From fbb47e2d533585188124588b1fbb3be8ba7d8812 Mon Sep 17 00:00:00 2001 From: Match Grun Date: Sat, 1 Sep 2001 23:48:06 +0000 Subject: [PATCH] New address book. --- src/Makefile.am | 11 + src/addrbook.c | 2114 ++++++++++++++++++ src/addrbook.h | 116 + src/addrcache.c | 1164 ++++++++++ src/addrcache.h | 125 ++ src/addressadd.c | 401 ++++ src/addressadd.h | 37 + src/addressbook.c | 4870 +++++++++++++++++++---------------------- src/addressbook.h | 160 +- src/addressitem.h | 141 +- src/addrindex.c | 1845 ++++++++++++++++ src/addrindex.h | 130 ++ src/addritem.c | 966 ++++++++ src/addritem.h | 175 ++ src/editaddress.c | 1166 ++++++++++ src/editaddress.h | 34 + src/editbook.c | 347 +++ src/editbook.h | 35 + src/editgroup.c | 527 +++++ src/editgroup.h | 36 + src/editjpilot.c | 29 +- src/editjpilot.h | 2 +- src/editldap.c | 25 +- src/editldap.h | 2 +- src/editldap_basedn.c | 4 +- src/editvcard.c | 25 +- src/editvcard.h | 2 +- src/jpilot.c | 627 +++--- src/jpilot.h | 167 +- src/main.c | 1 + src/mgutils.c | 310 +-- src/mgutils.h | 47 +- src/procmime.c | 8 +- src/summaryview.c | 56 +- src/syldap.c | 218 +- src/syldap.h | 98 +- src/textview.c | 3 +- src/vcard.c | 239 +- src/vcard.h | 44 +- 39 files changed, 12557 insertions(+), 3750 deletions(-) create mode 100644 src/addrbook.c create mode 100644 src/addrbook.h create mode 100644 src/addrcache.c create mode 100644 src/addrcache.h create mode 100644 src/addressadd.c create mode 100644 src/addressadd.h create mode 100644 src/addrindex.c create mode 100644 src/addrindex.h create mode 100644 src/addritem.c create mode 100644 src/addritem.h create mode 100644 src/editaddress.c create mode 100644 src/editaddress.h create mode 100644 src/editbook.c create mode 100644 src/editbook.h create mode 100644 src/editgroup.c create mode 100644 src/editgroup.h diff --git a/src/Makefile.am b/src/Makefile.am index 413637a2e..823f87fec 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -93,14 +93,22 @@ sylpheed_SOURCES = \ quote_fmt_lex.l quote_fmt_lex.h \ quote_fmt_parse.y quote_fmt.h \ addressitem.h \ + addritem.c addritem.h \ + addrcache.c addrcache.h \ + addrbook.c addrbook.h \ + addrindex.c addrindex.h \ mgutils.c mgutils.h \ vcard.c vcard.h \ jpilot.c jpilot.h \ syldap.c syldap.h \ + editbook.c editbook.h \ + editgroup.c editgroup.h \ + editaddress.c editaddress.h \ editvcard.c editvcard.h \ editjpilot.c editjpilot.h \ editldap.c editldap.h \ editldap_basedn.c editldap_basedn.h \ + addressadd.c addressadd.h \ gtkspell.c gtkspell.h gtkxtext.h \ template.c template.h \ prefs_templates.c prefs_templates.h \ @@ -151,6 +159,9 @@ EXTRA_DIST = \ pixmaps/stock_paste.xpm \ pixmaps/tb_address_book.xpm \ pixmaps/sylpheed-logo.xpm \ + pixmaps/interface.xpm \ + pixmaps/book.xpm \ + pixmaps/address.xpm \ pixmaps/vcard.xpm \ pixmaps/jpilot.xpm \ pixmaps/category.xpm \ diff --git a/src/addrbook.c b/src/addrbook.c new file mode 100644 index 000000000..8e9098e35 --- /dev/null +++ b/src/addrbook.c @@ -0,0 +1,2114 @@ +/* + * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client + * Copyright (C) 2001 Match Grun + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ + +/* + * General functions for accessing external address book files. + */ + +#include +#include +#include +#include +#include +#include + +#include "xml.h" +#include "mgutils.h" +#include "addritem.h" +#include "addrcache.h" +#include "addrbook.h" + +#ifndef DEV_STANDALONE +#include "prefs.h" +#endif + +#define ADDRBOOK_MAX_SEARCH_COUNT 1000 +#define ADDRBOOK_PREFIX "addrbook-" +#define ADDRBOOK_SUFFIX ".xml" +#define FILE_NUMDIGITS 6 + +#define ID_TIME_OFFSET 998000000 +/* +* Create new address book. +*/ +AddressBookFile *addrbook_create_book() { + AddressBookFile *book; + gint t; + book = g_new0( AddressBookFile, 1 ); + book->name = NULL; + book->path = NULL; + book->fileName = NULL; + book->retVal = MGU_SUCCESS; + book->addressCache = addrcache_create(); + + book->tempList = NULL; + book->readFlag = FALSE; + book->dirtyFlag = FALSE; + book->modifyFlag = TRUE; + book->accessFlag = FALSE; + book->tempHash = NULL; + return book; +} + +/* +* Specify name to be used. +*/ +void addrbook_set_name( AddressBookFile *book, const gchar *value ) { + g_return_if_fail( book != NULL ); + book->name = mgu_replace_string( book->name, value ); +} +void addrbook_set_path( AddressBookFile *book, const gchar *value ) { + g_return_if_fail( book != NULL ); + book->path = mgu_replace_string( book->path, value ); + book->dirtyFlag = TRUE; +} +void addrbook_set_file( AddressBookFile *book, const gchar *value ) { + g_return_if_fail( book != NULL ); + book->fileName = mgu_replace_string( book->fileName, value ); + book->dirtyFlag = TRUE; +} +void addrbook_set_accessed( AddressBookFile *book, const gboolean value ) { + g_return_if_fail( book != NULL ); + book->accessFlag = value; +} +gboolean addrbook_get_modified( AddressBookFile *book ) { + g_return_if_fail( book != NULL ); + return book->modifyFlag; +} +gboolean addrbook_get_accessed( AddressBookFile *book ) { + g_return_if_fail( book != NULL ); + return book->accessFlag; +} +gboolean addrbook_get_read_flag( AddressBookFile *book ) { + g_return_if_fail( book != NULL ); + return book->readFlag; +} +gint addrbook_get_status( AddressBookFile *book ) { + g_return_if_fail( book != NULL ); + return book->retVal; +} +ItemFolder *addrbook_get_root_folder( AddressBookFile *book ) { + g_return_if_fail( book != NULL ); + return addrcache_get_root_folder( book->addressCache ); +} +GList *addrbook_get_list_folder( AddressBookFile *book ) { + g_return_if_fail( book != NULL ); + return addrcache_get_list_folder( book->addressCache ); +} +GList *addrbook_get_list_person( AddressBookFile *book ) { + g_return_if_fail( book != NULL ); + return addrcache_get_list_person( book->addressCache ); +} +gchar *addrbook_get_name( AddressBookFile *book ) { + g_return_if_fail( book != NULL ); + return book->name; +} + +static gint addrcache_free_item_vis( gpointer key, gpointer value, gpointer data ) { + AddrItemObject *obj = ( AddrItemObject * ) value; + if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) { + addritem_free_item_person( ( ItemPerson * ) obj ); + } + else if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) { + addritem_free_item_group( ( ItemGroup * ) obj ); + } + else if( ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER ) { + addritem_free_item_folder( ( ItemFolder * ) obj ); + } + key = NULL; + value = NULL; + return 0; +} + +/* +* Free hash table of address book items. +*/ +static void addrcache_free_item_hash( GHashTable *table ) { + g_return_if_fail( table != NULL ); + g_hash_table_freeze( table ); + g_hash_table_foreach_remove( table, addrcache_free_item_vis, NULL ); + g_hash_table_thaw( table ); + g_hash_table_destroy( table ); +} + +/* +* Empty address book. +*/ +void addrbook_empty_book( AddressBookFile *book ) { + g_return_if_fail( book != NULL ); + + // Free up folders and hash table + addrcache_clear( book->addressCache ); + + g_list_free( book->tempList ); + book->tempList = NULL; + + // Reset to initial state + book->retVal = MGU_SUCCESS; + book->tempHash = NULL; + book->readFlag = FALSE; + book->dirtyFlag = FALSE; + book->modifyFlag = FALSE; + book->accessFlag = FALSE; +} + +/* +* Free address book. +*/ +void addrbook_free_book( AddressBookFile *book ) { + g_return_if_fail( book != NULL ); + + g_free( book->name ); + g_free( book->path ); + g_free( book->fileName ); + book->name = NULL; + book->path = NULL; + book->fileName = NULL; + + // Free up folders and hash table + addrcache_free( book->addressCache ); + book->addressCache = NULL; + + g_list_free( book->tempList ); + book->tempList = NULL; + + book->retVal = MGU_SUCCESS; + book->tempHash = NULL; + book->readFlag = FALSE; + book->dirtyFlag = FALSE; + book->modifyFlag = FALSE; + book->accessFlag = FALSE; + + g_free( book ); +} + +/* +* Print list of items. +*/ +void addrbook_print_item_list( GList *list, FILE *stream ) { + GList *node = list; + while( node ) { + AddrItemObject *obj = node->data; + if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) { + addritem_print_item_person( ( ItemPerson * ) obj, stream ); + } + else if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) { + addritem_print_item_group( ( ItemGroup * ) obj, stream ); + } + else if( ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER ) { + addritem_print_item_folder( ( ItemFolder * ) obj, stream ); + } + node = g_list_next( node ); + } + fprintf( stream, "\t---\n" ); +} + +/* +* Print address book. +*/ +void addrbook_print_book( AddressBookFile *book, FILE *stream ) { + g_return_if_fail( book != NULL ); + fprintf( stream, "AddressBook:\n" ); + fprintf( stream, "\tname : '%s'\n", book->name ); + fprintf( stream, "\tpath : '%s'\n", book->path ); + fprintf( stream, "\tfile : '%s'\n", book->fileName ); + fprintf( stream, "\tstatus: %d : '%s'\n", book->retVal, mgu_error2string( book->retVal ) ); + addrcache_print( book->addressCache, stream ); +} + +/* +* Dump entire address book traversing folders. +*/ +void addrbook_dump_book( AddressBookFile *book, FILE *stream ) { + GList *node; + ItemFolder *folder; + g_return_if_fail( book != NULL ); + addrbook_print_book( book, stream ); + folder = book->addressCache->rootFolder; + addritem_print_item_folder( folder, stream ); +} + +/* +* Remove group from address book. +* param: group Group to remove. +* return: Group, or NULL if not found. Note that object should still be freed. +*/ +ItemGroup *addrbook_remove_group( AddressBookFile *book, ItemGroup *group ) { + ItemGroup *item; + g_return_if_fail( book != NULL ); + item = addrcache_remove_group( book->addressCache, group ); + if( item ) book->dirtyFlag = TRUE; + return item; +} + +/* +* Remove specified person from address book. +* param: person Person to remove. +* return: Person, or NULL if not found. Note that object should still be freed. +*/ +ItemPerson *addrbook_remove_person( AddressBookFile *book, ItemPerson *person ) { + ItemPerson *item; + g_return_if_fail( book != NULL ); + item = addrcache_remove_person( book->addressCache, person ); + if( item ) book->dirtyFlag = TRUE; + return item; +} + +/* +* Remove email address in address book for specified person. +* param: person Person. +* email EMail to remove. +* return: EMail object, or NULL if not found. Note that object should still be freed. +*/ +ItemEMail *addrbook_person_remove_email( AddressBookFile *book, ItemPerson *person, ItemEMail *email ) { + ItemEMail *item; + g_return_if_fail( book != NULL ); + item = addrcache_person_remove_email( book->addressCache, person, email ); + if( item ); book->dirtyFlag = TRUE; + return item; +} + +/* ********************************************************************** +* Read/Write XML data file... +* =========================== +* Notes: +* 1) The address book is structured as follows: +* +* address-book +* person +* address-list +* address +* attribute-list +* attribute +* group +* member-list +* member +* folder +* item-list +* item +* +* 2) This sequence of elements was chosen so that the most important +* elements (person and their email addresses) appear first. +* +* 3) Groups then appear. When groups are loaded, person's email +* addresses have already been loaded and can be found. +* +* 4) Finally folders are loaded. Any forward and backward references +* to folders, groups and persons in the folders are resolved after +* loading. +* +* *********************************************************************** +*/ + +// Element tag names +#define AB_ELTAG_ADDRESS "address" +#define AB_ELTAG_ATTRIBUTE "attribute" +#define AB_ELTAG_ATTRIBUTE_LIST "attribute-list" +#define AB_ELTAG_ADDRESS_LIST "address-list" +#define AB_ELTAG_MEMBER "member" +#define AB_ELTAG_MEMBER_LIST "member-list" +#define AB_ELTAG_ITEM "item" +#define AB_ELTAG_ITEM_LIST "item-list" +#define AB_ELTAG_ADDRESS_BOOK "address-book" +#define AB_ELTAG_PERSON "person" +#define AB_ELTAG_GROUP "group" +#define AB_ELTAG_FOLDER "folder" + +// Attribute tag names +#define AB_ATTAG_TYPE "type" +#define AB_ATTAG_UID "uid" +#define AB_ATTAG_NAME "name" +#define AB_ATTAG_REMARKS "remarks" +#define AB_ATTAG_FIRST_NAME "first-name" +#define AB_ATTAG_LAST_NAME "last-name" +#define AB_ATTAG_NICK_NAME "nick-name" +#define AB_ATTAG_COMMON_NAME "cn" +#define AB_ATTAG_ALIAS "alias" +#define AB_ATTAG_EMAIL "email" +#define AB_ATTAG_EID "eid" +#define AB_ATTAG_PID "pid" + +// Attribute values +#define AB_ATTAG_VAL_PERSON "person" +#define AB_ATTAG_VAL_GROUP "group" +#define AB_ATTAG_VAL_FOLDER "folder" + +/* +* Parse address item for person. +*/ +static void addrbook_parse_address( AddressBookFile *book, XMLFile *file, ItemPerson *person ) { + GList *attr; + gchar *name, *value; + ItemEMail *email = NULL; + + attr = xml_get_current_tag_attr(file); + while( attr ) { + name = ((XMLAttr *)attr->data)->name; + value = ((XMLAttr *)attr->data)->value; + if( ! email ) email = addritem_create_item_email(); + if( strcmp( name, AB_ATTAG_UID ) == 0 ) { + ADDRITEM_ID(email) = g_strdup( value ); + } + else if( strcmp( name, AB_ATTAG_ALIAS ) == 0 ) { + ADDRITEM_NAME(email) = g_strdup( value ); + } + else if( strcmp( name, AB_ATTAG_EMAIL ) == 0 ) { + email->address = g_strdup( value ); + } + else if( strcmp( name, AB_ATTAG_REMARKS ) == 0 ) { + email->remarks = g_strdup( value ); + } + attr = g_list_next( attr ); + } + if( email ) { + if( person ) { + addrcache_person_add_email( book->addressCache, person, email ); + } + else { + addritem_free_item_email( email ); + email = NULL; + } + } +} + +/* +* Parse email address list. +*/ +static void addrbook_parse_addr_list( AddressBookFile *book, XMLFile *file, ItemPerson *person ){ + GList *attr; + guint prev_level; + + for (;;) { + prev_level = file->level; + if( xml_parse_next_tag( file ) ) { + longjmp( book->jumper, 1 ); + } + if (file->level < prev_level) return; + if( xml_compare_tag( file, AB_ELTAG_ADDRESS ) ) { + attr = xml_get_current_tag_attr(file); + addrbook_parse_address( book, file, person ); + addrbook_parse_addr_list( book, file, person ); + } + } +} + +/* +* Parse attibute for person. +*/ +static void addrbook_parse_attribute( XMLFile *file, ItemPerson *person ) { + GList *attr; + gchar *name, *value; + gchar *element; + UserAttribute *uAttr = NULL; + + attr = xml_get_current_tag_attr(file); + while( attr ) { + name = ((XMLAttr *)attr->data)->name; + value = ((XMLAttr *)attr->data)->value; + if( ! uAttr ) uAttr = addritem_create_attribute(); + if( strcmp( name, AB_ATTAG_UID ) == 0 ) { + addritem_attrib_set_id( uAttr, value ); + } + else if( strcmp( name, AB_ATTAG_NAME ) == 0 ) { + addritem_attrib_set_name( uAttr, value ); + } + attr = g_list_next( attr ); + } + + element = xml_get_element( file ); + addritem_attrib_set_value( uAttr, element ); + + if( uAttr ) { + if( person ) { + addritem_person_add_attribute( person, uAttr ); + } + else { + addritem_free_attribute( uAttr ); + uAttr = NULL; + } + } +} + +/* +* Parse attribute list. +*/ +static void addrbook_parse_attr_list( AddressBookFile *book, XMLFile *file, ItemPerson *person ){ + GList *attr; + guint prev_level; + + for (;;) { + prev_level = file->level; + if( xml_parse_next_tag( file ) ) { + longjmp( book->jumper, 1 ); + } + if (file->level < prev_level) return; + if( xml_compare_tag( file, AB_ELTAG_ATTRIBUTE ) ) { + attr = xml_get_current_tag_attr(file); + addrbook_parse_attribute( file, person ); + addrbook_parse_attr_list( book, file, person ); + } + } +} + +/* +* Parse person. +*/ +static void addrbook_parse_person( AddressBookFile *book, XMLFile *file ) { + GList *attr; + gchar *name, *value; + ItemPerson *person = NULL; + + attr = xml_get_current_tag_attr(file); + while( attr ) { + name = ((XMLAttr *)attr->data)->name; + value = ((XMLAttr *)attr->data)->value; + if( ! person ) person = addritem_create_item_person(); + if( strcmp( name, AB_ATTAG_UID ) == 0 ) { + ADDRITEM_ID(person) = g_strdup( value ); + } + else if( strcmp( name, AB_ATTAG_FIRST_NAME ) == 0 ) { + person->firstName = g_strdup( value ); + } + else if( strcmp( name, AB_ATTAG_LAST_NAME ) == 0 ) { + person->lastName = g_strdup( value ); + } + else if( strcmp( name, AB_ATTAG_NICK_NAME ) == 0 ) { + person->nickName = g_strdup( value ); + } + else if( strcmp( name, AB_ATTAG_COMMON_NAME ) == 0 ) { + ADDRITEM_NAME(person) = g_strdup( value ); + } + attr = g_list_next( attr ); + } + if( xml_parse_next_tag( file ) ) { // Consume closing tag + longjmp( book->jumper, 1 ); + } + if( xml_compare_tag( file, AB_ELTAG_ADDRESS_LIST ) ) { + addrbook_parse_addr_list( book, file, person ); + if( person ) { + addrcache_hash_add_person( book->addressCache, person ); + } + } + if( xml_parse_next_tag( file ) ) { // Consume closing tag + longjmp( book->jumper, 1 ); + } + if( xml_compare_tag( file, AB_ELTAG_ATTRIBUTE_LIST ) ) { + addrbook_parse_attr_list( book, file, person ); + } +} + +/* +* Parse group member. +*/ +static void addrbook_parse_member( AddressBookFile *book, XMLFile *file, ItemGroup *group ) { + GList *attr; + gchar *name, *value; + gchar *pid = NULL, *eid = NULL; + ItemEMail *email = NULL; + + attr = xml_get_current_tag_attr(file); + while( attr ) { + name = ((XMLAttr *)attr->data)->name; + value = ((XMLAttr *)attr->data)->value; + if( strcmp( name, AB_ATTAG_PID ) == 0 ) { + pid = g_strdup( value ); + } + else if( strcmp( name, AB_ATTAG_EID ) == 0 ) { + eid = g_strdup( value ); + } + attr = g_list_next( attr ); + } + email = addrcache_get_email( book->addressCache, pid, eid ); + if( email ) { + if( group ) { + addrcache_group_add_email( book->addressCache, group, email ); + } + else { + addritem_free_item_email( email ); + email = NULL; + } + } +} + +/* +* Parse group member list. +*/ +static void addrbook_parse_member_list( AddressBookFile *book, XMLFile *file, ItemGroup *group ){ + GList *attr; + guint prev_level; + gchar *element; + + for (;;) { + prev_level = file->level; + if( xml_parse_next_tag( file ) ) { + longjmp( book->jumper, 1 ); + } + if (file->level < prev_level) return; + if( xml_compare_tag( file, AB_ELTAG_MEMBER ) ) { + attr = xml_get_current_tag_attr(file); + addrbook_parse_member( book, file, group ); + addrbook_parse_member_list( book, file, group ); + } + else { + attr = xml_get_current_tag_attr( file ); + } + } +} + +/* +* Parse group. +*/ +static void addrbook_parse_group( AddressBookFile *book, XMLFile *file ) { + GList *attr; + gchar *name, *value; + ItemGroup *group = NULL; + + attr = xml_get_current_tag_attr(file); + while( attr ) { + name = ((XMLAttr *)attr->data)->name; + value = ((XMLAttr *)attr->data)->value; + if( ! group ) group = addritem_create_item_group(); + if( strcmp( name, AB_ATTAG_UID ) == 0 ) { + ADDRITEM_ID(group) = g_strdup( value ); + } + else if( strcmp( name, AB_ATTAG_NAME ) == 0 ) { + ADDRITEM_NAME(group) = g_strdup( value ); + } + else if( strcmp( name, AB_ATTAG_REMARKS ) == 0 ) { + group->remarks = g_strdup( value ); + } + attr = g_list_next( attr ); + } + if( xml_parse_next_tag( file ) ) { // Consume closing tag + longjmp( book->jumper, 1 ); + } + if( xml_compare_tag( file, AB_ELTAG_MEMBER_LIST ) ) { + if( group ) { + addrcache_hash_add_group( book->addressCache, group ); + } + addrbook_parse_member_list( book, file, group ); + } +} + +/* +* Parse folder item. +*/ +static void addrbook_parse_folder_item( AddressBookFile *book, XMLFile *file, ItemFolder *folder ) { + GList *attr; + gchar *name, *value; + gchar *uid = NULL; + + attr = xml_get_current_tag_attr(file); + while( attr ) { + name = ((XMLAttr *)attr->data)->name; + value = ((XMLAttr *)attr->data)->value; + if( strcmp( name, AB_ATTAG_UID ) == 0 ) { + uid = g_strdup( value ); + } + attr = g_list_next( attr ); + } + if( folder ) { + if( uid ) { + folder->listItems = g_list_append( folder->listItems, uid ); + } + } +} + +/* +* Parse folder item list. +*/ +static void addrbook_parse_folder_list( AddressBookFile *book, XMLFile *file, ItemFolder *folder ){ + GList *attr; + guint prev_level; + gchar *element; + + for (;;) { + prev_level = file->level; + if( xml_parse_next_tag( file ) ) { + longjmp( book->jumper, 1 ); + } + if (file->level < prev_level) return; + if( xml_compare_tag( file, AB_ELTAG_ITEM ) ) { + attr = xml_get_current_tag_attr(file); + addrbook_parse_folder_item( book, file, folder ); + addrbook_parse_folder_list( book, file, folder ); + } + else { + attr = xml_get_current_tag_attr( file ); + } + } +} + +/* +* Parse folder. +*/ +static void addrbook_parse_folder( AddressBookFile *book, XMLFile *file ) { + GList *attr; + gchar *name, *value; + ItemFolder *folder = NULL; + + attr = xml_get_current_tag_attr(file); + while( attr ) { + name = ((XMLAttr *)attr->data)->name; + value = ((XMLAttr *)attr->data)->value; + if( ! folder ) { + folder = addritem_create_item_folder(); + } + if( strcmp( name, AB_ATTAG_UID ) == 0 ) { + ADDRITEM_ID(folder) = g_strdup( value ); + } + else if( strcmp( name, AB_ATTAG_NAME ) == 0 ) { + ADDRITEM_NAME(folder) = g_strdup( value ); + } + else if( strcmp( name, AB_ATTAG_REMARKS ) == 0 ) { + folder->remarks = g_strdup( value ); + } + attr = g_list_next( attr ); + } + if( xml_parse_next_tag( file ) ) { // Consume closing tag + longjmp( book->jumper, 1 ); + } + if( xml_compare_tag( file, AB_ELTAG_ITEM_LIST ) ) { + if( folder ) { + if( addrcache_hash_add_folder( book->addressCache, folder ) ) { + book->tempList = g_list_append( book->tempList, folder ); + ADDRITEM_PARENT(folder) = NULL; // We will resolve folder later + } + } + addrbook_parse_folder_list( book, file, folder ); + } +} + +/* +* Parse address book. +* Return: TRUE if data read successfully, FALSE if error reading data. +*/ +static gboolean addrbook_read_tree( AddressBookFile *book, XMLFile *file ) { + gboolean retVal; + GList *attr; + gchar *name, *value; + + book->retVal = MGU_BAD_FORMAT; + if( xml_get_dtd( file ) ) { + return FALSE; + } + if( xml_parse_next_tag( file ) ) { + longjmp( book->jumper, 1 ); + } + if( ! xml_compare_tag( file, AB_ELTAG_ADDRESS_BOOK ) ) { + return FALSE; + } + + attr = xml_get_current_tag_attr(file); + while( attr ) { + name = ((XMLAttr *)attr->data)->name; + value = ((XMLAttr *)attr->data)->value; + if( strcmp( name, AB_ATTAG_NAME ) == 0 ) { + addrbook_set_name( book, value ); + } + attr = g_list_next( attr ); + } + + retVal = TRUE; + for (;;) { + if (! file->level ) break; + // Get next item tag (person, group or folder) + if( xml_parse_next_tag( file ) ) { + longjmp( book->jumper, 1 ); + } + if( xml_compare_tag( file, AB_ELTAG_PERSON ) ) { + addrbook_parse_person( book, file ); + } + else if( xml_compare_tag( file, AB_ELTAG_GROUP ) ) { + addrbook_parse_group( book, file ); + } + else if( xml_compare_tag( file, AB_ELTAG_FOLDER ) ) { + addrbook_parse_folder( book, file ); + } + } + if( retVal ) book->retVal = MGU_SUCCESS; + return retVal; +} + +/* +* Resolve folder items visitor function. +*/ +static void addrbook_res_items_vis( gpointer key, gpointer value, gpointer data ) { + AddressBookFile *book = data; + AddrItemObject *obj = ( AddrItemObject * ) value; + ItemFolder *rootFolder = book->addressCache->rootFolder; + if( obj->parent == NULL ) { + if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) { + rootFolder->listPerson = g_list_append( rootFolder->listPerson, obj ); + ADDRITEM_PARENT(obj) = ADDRITEM_OBJECT(rootFolder); + } + else if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) { + rootFolder->listGroup = g_list_append( rootFolder->listGroup, obj ); + ADDRITEM_PARENT(obj) = ADDRITEM_OBJECT(rootFolder); + } + } +} + +/* +* Resolve folder items. Lists of UID's are replaced with pointers to data items. +*/ +static void addrbook_resolve_folder_items( AddressBookFile *book ) { + GList *nodeFolder = NULL; + GList *listRemove = NULL; + GList *node = NULL; + ItemFolder *rootFolder = book->addressCache->rootFolder; + nodeFolder = book->tempList; + while( nodeFolder ) { + ItemFolder *folder = nodeFolder->data; + listRemove = NULL; + node = folder->listItems; + while( node ) { + gchar *uid = node->data; + AddrItemObject *aio = addrcache_get_object( book->addressCache, uid ); + if( aio ) { + if( aio->type == ITEMTYPE_FOLDER ) { + ItemFolder *item = ( ItemFolder * ) aio; + folder->listFolder = g_list_append( folder->listFolder, item ); + ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder); + addrcache_hash_add_folder( book->addressCache, folder ); + } + else if( aio->type == ITEMTYPE_PERSON ) { + ItemPerson *item = ( ItemPerson * ) aio; + folder->listPerson = g_list_append( folder->listPerson, item ); + ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder); + } + else if( aio->type == ITEMTYPE_GROUP ) { + ItemGroup *item = ( ItemGroup * ) aio; + folder->listGroup = g_list_append( folder->listGroup, item ); + ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder); + } + // Replace data with pointer to item + g_free( uid ); + node->data = aio; + } + else { + // Not found, append to remove list. + listRemove = g_list_append( listRemove, uid ); + } + node = g_list_next( node ); + } + rootFolder->listFolder = g_list_append( rootFolder->listFolder, folder ); + + // Process remove list + node = listRemove; + while( node ) { + gchar *uid = node->data; + folder->listItems = g_list_remove( folder->listItems, uid ); + g_free( uid ); + node = g_list_next( node ); + } + g_list_free( listRemove ); + nodeFolder = g_list_next( nodeFolder ); + } + + // Remove folders with parents. + listRemove = NULL; + node = rootFolder->listFolder; + while( node ) { + ItemFolder *folder = ( ItemFolder * ) node->data; + if( ADDRITEM_PARENT(folder) ) { + // Remove folders with parents + listRemove = g_list_append( listRemove, folder ); + } + else { + // Add to root folder + ADDRITEM_PARENT(folder) = ADDRITEM_OBJECT(book->addressCache->rootFolder); + } + node = g_list_next( node ); + } + + // Process remove list + node = listRemove; + while( node ) { + rootFolder->listFolder = g_list_remove( rootFolder->listFolder, node->data ); + node = g_list_next( node ); + } + g_list_free( listRemove ); + + // Move all unparented persons and groups into root folder + g_hash_table_foreach( book->addressCache->itemHash, addrbook_res_items_vis, book ); + + // Free up some more + nodeFolder = book->tempList; + while( nodeFolder ) { + ItemFolder *folder = nodeFolder->data; + g_list_free( folder->listItems ); + folder->listItems = NULL; + nodeFolder = g_list_next( nodeFolder ); + } + g_list_free( book->tempList ); + book->tempList = NULL; + +} + +/* +* Read address book file. +*/ +gint addrbook_read_data( AddressBookFile *book ) { + XMLFile *file = NULL; + gchar *fileSpec = NULL; + g_return_if_fail( book != NULL ); + + fileSpec = g_strconcat( book->path, G_DIR_SEPARATOR_S, book->fileName, NULL ); + book->retVal = MGU_OPEN_FILE; + book->accessFlag = FALSE; + book->modifyFlag = FALSE; + file = xml_open_file( fileSpec ); + g_free( fileSpec ); + if( file ) { + book->tempList = NULL; + + // Trap for parsing errors. + if( setjmp( book->jumper ) ) { + xml_close_file( file ); + return book->retVal; + } + addrbook_read_tree( book, file ); + xml_close_file( file ); + + // Resolve folder items + addrbook_resolve_folder_items( book ); + book->tempList = NULL; + book->readFlag = TRUE; + book->dirtyFlag = FALSE; + } + return book->retVal; +} + +static void addrbook_write_elem_s( FILE *fp, gint lvl, gchar *name ) { + gint i; + for( i = 0; i < lvl; i++ ) fputs( " ", fp ); + fputs( "<", fp ); + fputs( name, fp ); +} + +static void addrbook_write_elem_e( FILE *fp, gint lvl, gchar *name ) { + gint i; + for( i = 0; i < lvl; i++ ) fputs( " ", fp ); + fputs( "\n", fp ); +} + +static void addrbook_write_attr( FILE *fp, gchar *name, gchar *value ) { + fputs( " ", fp ); + fputs( name, fp ); + fputs( "=\"", fp ); + xml_file_put_escape_str( fp, value ); + fputs( "\"", fp ); +} + +/* +* Write file hash table visitor function. +*/ +static void addrbook_write_item_person_vis( gpointer key, gpointer value, gpointer data ) { + AddrItemObject *obj = ( AddrItemObject * ) value; + FILE *fp = ( FILE * ) data; + GList *node; + if( ! obj ) return; + if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) { + ItemPerson *person = ( ItemPerson * ) value; + if( person ) { + addrbook_write_elem_s( fp, 1, AB_ELTAG_PERSON ); + addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(person) ); + addrbook_write_attr( fp, AB_ATTAG_FIRST_NAME, person->firstName ); + addrbook_write_attr( fp, AB_ATTAG_LAST_NAME, person->lastName ); + addrbook_write_attr( fp, AB_ATTAG_NICK_NAME, person->nickName ); + addrbook_write_attr( fp, AB_ATTAG_COMMON_NAME, ADDRITEM_NAME(person) ); + fputs( " >\n", fp); + + // Output email addresses + addrbook_write_elem_s( fp, 2, AB_ELTAG_ADDRESS_LIST ); + fputs( ">\n", fp ); + node = person->listEMail; + while ( node ) { + ItemEMail *email = node->data; + addrbook_write_elem_s( fp, 3, AB_ELTAG_ADDRESS ); + addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(email) ); + addrbook_write_attr( fp, AB_ATTAG_ALIAS, ADDRITEM_NAME(email) ); + addrbook_write_attr( fp, AB_ATTAG_EMAIL, email->address ); + addrbook_write_attr( fp, AB_ATTAG_REMARKS, email->remarks ); + fputs( " />\n", fp); + node = g_list_next( node ); + } + addrbook_write_elem_e( fp, 2, AB_ELTAG_ADDRESS_LIST ); + + // Output user attributes + addrbook_write_elem_s( fp, 2, AB_ELTAG_ATTRIBUTE_LIST ); + fputs( ">\n", fp ); + node = person->listAttrib; + while ( node ) { + UserAttribute *attrib = node->data; + addrbook_write_elem_s( fp, 3, AB_ELTAG_ATTRIBUTE ); + addrbook_write_attr( fp, AB_ATTAG_UID, attrib->uid ); + addrbook_write_attr( fp, AB_ATTAG_NAME, attrib->name ); + fputs( " >", fp); + xml_file_put_escape_str( fp, attrib->value ); + addrbook_write_elem_e( fp, 0, AB_ELTAG_ATTRIBUTE ); + node = g_list_next( node ); + } + addrbook_write_elem_e( fp, 2, AB_ELTAG_ATTRIBUTE_LIST ); + addrbook_write_elem_e( fp, 1, AB_ELTAG_PERSON ); + } + } +} + +/* +* Output all groups in folder. +*/ +static void addrbook_write_folder_group( ItemFolder *parent, FILE *fp ) { + GList *nodeGrp = parent->listGroup; + GList *node; + while( nodeGrp ) { + ItemGroup *group = nodeGrp->data; + if( group ) { + addrbook_write_elem_s( fp, 1, AB_ELTAG_GROUP ); + addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(group) ); + addrbook_write_attr( fp, AB_ATTAG_NAME, ADDRITEM_NAME(group) ); + addrbook_write_attr( fp, AB_ATTAG_REMARKS, group->remarks ); + fputs( " >\n", fp ); + + // Output email address links + addrbook_write_elem_s( fp, 2, AB_ELTAG_MEMBER_LIST ); + fputs( ">\n", fp ); + node = group->listEMail; + while ( node ) { + ItemEMail *email = node->data; + ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(email); + addrbook_write_elem_s( fp, 3, AB_ELTAG_MEMBER ); + addrbook_write_attr( fp, AB_ATTAG_PID, ADDRITEM_ID(person) ); + addrbook_write_attr( fp, AB_ATTAG_EID, ADDRITEM_ID(email) ); + fputs( " />\n", fp ); + node = g_list_next( node ); + } + addrbook_write_elem_e( fp, 2, AB_ELTAG_MEMBER_LIST ); + addrbook_write_elem_e( fp, 1, AB_ELTAG_GROUP ); + } + nodeGrp = g_list_next( nodeGrp ); + } + node = parent->listFolder; + while( node ) { + ItemFolder *folder = node->data; + addrbook_write_folder_group( folder, fp ); + node = g_list_next( node ); + } +} + +/* +* Write file hash table visitor function. +*/ +static void addrbook_write_item_group_vis( gpointer key, gpointer value, gpointer data ) { + AddrItemObject *obj = ( AddrItemObject * ) value; + FILE *fp = ( FILE * ) data; + GList *node; + if( ! obj ) return; + if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) { + ItemGroup *group = ( ItemGroup * ) value; + if( group ) { + addrbook_write_elem_s( fp, 1, AB_ELTAG_GROUP ); + addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(group) ); + addrbook_write_attr( fp, AB_ATTAG_NAME, ADDRITEM_NAME(group) ); + addrbook_write_attr( fp, AB_ATTAG_REMARKS, group->remarks ); + fputs( " >\n", fp ); + + // Output email address links + addrbook_write_elem_s( fp, 2, AB_ELTAG_MEMBER_LIST ); + fputs( ">\n", fp ); + node = group->listEMail; + while ( node ) { + ItemEMail *email = node->data; + ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(email); + addrbook_write_elem_s( fp, 3, AB_ELTAG_MEMBER ); + addrbook_write_attr( fp, AB_ATTAG_PID, ADDRITEM_ID(person) ); + addrbook_write_attr( fp, AB_ATTAG_EID, ADDRITEM_ID(email) ); + fputs( " />\n", fp ); + node = g_list_next( node ); + } + addrbook_write_elem_e( fp, 2, AB_ELTAG_MEMBER_LIST ); + addrbook_write_elem_e( fp, 1, AB_ELTAG_GROUP ); + } + } +} + +/* +* Output all folders in folder. +*/ +static void addrbook_write_folder_folder( ItemFolder *parent, FILE *fp ) { + GList *nodeFold = parent->listFolder; + GList *node; + while( nodeFold ) { + ItemFolder *folder = nodeFold->data; + addrbook_write_folder_folder( folder, fp ); + if( folder ) { + addrbook_write_elem_s( fp, 1, AB_ELTAG_FOLDER ); + addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(folder) ); + addrbook_write_attr( fp, AB_ATTAG_NAME, ADDRITEM_NAME(folder) ); + addrbook_write_attr( fp, AB_ATTAG_REMARKS, folder->remarks ); + fputs( " >\n", fp ); + addrbook_write_elem_s( fp, 2, AB_ELTAG_ITEM_LIST ); + fputs( ">\n", fp ); + + // Output persons + node = folder->listPerson; + while ( node ) { + ItemPerson *item = node->data; + addrbook_write_elem_s( fp, 2, AB_ELTAG_ITEM ); + addrbook_write_attr( fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_PERSON ); + addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(item ) ); + fputs( " />\n", fp ); + node = g_list_next( node ); + } + + // Output groups + node = folder->listGroup; + while ( node ) { + ItemGroup *item = node->data; + addrbook_write_elem_s( fp, 2, AB_ELTAG_ITEM ); + addrbook_write_attr( fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_GROUP ); + addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(item ) ); + fputs( " />\n", fp ); + node = g_list_next( node ); + } + + // Output folders + node = folder->listFolder; + while ( node ) { + ItemFolder *item = node->data; + addrbook_write_elem_s( fp, 2, AB_ELTAG_ITEM ); + addrbook_write_attr( fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_FOLDER ); + addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(item ) ); + fputs( " />\n", fp ); + node = g_list_next( node ); + } + addrbook_write_elem_e( fp, 2, AB_ELTAG_ITEM_LIST ); + addrbook_write_elem_e( fp, 1, AB_ELTAG_FOLDER ); + } + nodeFold = g_list_next( nodeFold ); + } +} + +/* +* Write file hash table visitor function. +*/ +static void addrbook_write_item_folder_vis( gpointer key, gpointer value, gpointer data ) { + AddrItemObject *obj = ( AddrItemObject * ) value; + FILE *fp = ( FILE * ) data; + GList *node; + if( ! obj ) return; + if( ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER ) { + ItemFolder *folder = ( ItemFolder * ) value; + if( folder ) { + addrbook_write_elem_s( fp, 1, AB_ELTAG_FOLDER ); + addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(folder) ); + addrbook_write_attr( fp, AB_ATTAG_NAME, ADDRITEM_NAME(folder) ); + addrbook_write_attr( fp, AB_ATTAG_REMARKS, folder->remarks ); + fputs( " >\n", fp ); + addrbook_write_elem_s( fp, 2, AB_ELTAG_ITEM_LIST ); + fputs( ">\n", fp ); + + // Output persons + node = folder->listPerson; + while ( node ) { + ItemPerson *item = node->data; + addrbook_write_elem_s( fp, 3, AB_ELTAG_ITEM ); + addrbook_write_attr( fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_PERSON ); + addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(item ) ); + fputs( " />\n", fp ); + node = g_list_next( node ); + } + + // Output groups + node = folder->listGroup; + while ( node ) { + ItemGroup *item = node->data; + addrbook_write_elem_s( fp, 3, AB_ELTAG_ITEM ); + addrbook_write_attr( fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_GROUP ); + addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(item ) ); + fputs( " />\n", fp ); + node = g_list_next( node ); + } + + // Output folders + node = folder->listFolder; + while ( node ) { + ItemFolder *item = node->data; + addrbook_write_elem_s( fp, 3, AB_ELTAG_ITEM ); + addrbook_write_attr( fp, AB_ATTAG_TYPE, AB_ATTAG_VAL_FOLDER ); + addrbook_write_attr( fp, AB_ATTAG_UID, ADDRITEM_ID(item ) ); + fputs( " />\n", fp ); + node = g_list_next( node ); + } + addrbook_write_elem_e( fp, 2, AB_ELTAG_ITEM_LIST ); + addrbook_write_elem_e( fp, 1, AB_ELTAG_FOLDER ); + } + } +} + +/* +* Output address book data to specified file. +* return: Status code. +*/ +gint addrbook_write_to( AddressBookFile *book, gchar *newFile ) { + FILE *fp; + gchar *fileSpec; +#ifndef DEV_STANDALONE + PrefFile *pfile; +#endif + + g_return_if_fail( book != NULL ); + g_return_if_fail( newFile != NULL ); + + fileSpec = g_strconcat( book->path, G_DIR_SEPARATOR_S, newFile, NULL ); + + book->retVal = MGU_OPEN_FILE; +#ifdef DEV_STANDALONE + fp = fopen( fileSpec, "w" ); + g_free( fileSpec ); + if( fp ) { + fputs( "\n", fp ); +#else + pfile = prefs_write_open( fileSpec ); + g_free( fileSpec ); + if( pfile ) { + fp = pfile->fp; + fprintf( fp, "\n", + conv_get_current_charset_str() ); +#endif + addrbook_write_elem_s( fp, 0, AB_ELTAG_ADDRESS_BOOK ); + addrbook_write_attr( fp, AB_ATTAG_NAME, book->name ); + fputs( " >\n", fp ); + + // Output all persons + g_hash_table_foreach( book->addressCache->itemHash, addrbook_write_item_person_vis, fp ); + + // Output all groups + g_hash_table_foreach( book->addressCache->itemHash, addrbook_write_item_group_vis, fp ); + // addrbook_write_folder_group( book->rootFolder, fp ); + + // Output all folders + g_hash_table_foreach( book->addressCache->itemHash, addrbook_write_item_folder_vis, fp ); + // addrbook_write_folder_folder( book->rootFolder, fp ); + + addrbook_write_elem_e( fp, 0, AB_ELTAG_ADDRESS_BOOK ); + book->retVal = MGU_SUCCESS; +#ifdef DEV_STANDALONE + fclose( fp ); +#else + if( prefs_write_close( pfile ) < 0 ) { + book->retVal = MGU_ERROR_WRITE; + } +#endif + } + + fileSpec = NULL; + return book->retVal; +} + +/* +* Output address book data to original file. +* return: Status code. +*/ +gint addrbook_save_data( AddressBookFile *book ) { + g_return_if_fail( book != NULL ); + + book->retVal = MGU_NO_FILE; + if( book->fileName == NULL || *book->fileName == '\0' ) return book->retVal; + if( book->path == NULL || *book->path == '\0' ) return book->retVal; + + addrbook_write_to( book, book->fileName ); + if( book->retVal == MGU_SUCCESS ) { + book->dirtyFlag = FALSE; + } + return book->retVal; +} + +/* ********************************************************************** +* Address book edit interface functions... +* *********************************************************************** +*/ + +/* +* Move person's email item. +* param: book Address book. +* person Person. +* itemMove Item to move. +* itemTarget Target item before which to move item. +*/ +ItemEMail *addrbook_move_email_before( AddressBookFile *book, ItemPerson *person, + ItemEMail *itemMove, ItemEMail *itemTarget ) +{ + ItemEMail *email = NULL; + g_return_if_fail( book != NULL ); + email = addritem_move_email_before( person, itemMove, itemTarget ); + if( email ) { + book->dirtyFlag = TRUE; + } + return email; +} + +/* +* Move person's email item. +* param: book Address book. +* person Person. +* itemMove Item to move. +* itemTarget Target item after which to move item. +*/ +ItemEMail *addrbook_move_email_after( AddressBookFile *book, ItemPerson *person, + ItemEMail *itemMove, ItemEMail *itemTarget ) +{ + ItemEMail *email = NULL; + g_return_if_fail( book != NULL ); + email = addritem_move_email_after( person, itemMove, itemTarget ); + if( email ) { + book->dirtyFlag = TRUE; + } + return email; +} + +/* +* Hash table visitor function. +*/ +static gboolean addrbook_free_simple_hash_vis( gpointer *key, gpointer *value, gpointer *data ) { + g_free( key ); + key = NULL; + value = NULL; + return TRUE; +} + +/* +* Update address book email list for specified person. +* Enter: book Address book. +* person Person to update. +* listEMail New list of email addresses. +* Note: The existing email addresses are replaced with the new addresses. Any references +* to old addresses in the groups are re-linked to the new addresses. All old addresses +* linked to the person are removed. +*/ +void addrbook_update_address_list( AddressBookFile *book, ItemPerson *person, GList *listEMail ) { + GList *node; + GList *oldData; + GList *listGroup; + + g_return_if_fail( book != NULL ); + g_return_if_fail( person != NULL ); + + // Remember old list + oldData = person->listEMail; + + // Attach new address list to person. + node = listEMail; + while( node ) { + ItemEMail *email = node->data; + if( ADDRITEM_ID(email) == NULL ) { + // Allocate an ID + addrcache_id_email( book->addressCache, email ); + } + ADDRITEM_PARENT(email) = ADDRITEM_OBJECT(person); + node = g_list_next( node ); + } + person->listEMail = listEMail; + + // Get groups where person's email is listed + listGroup = addrcache_get_group_for_person( book->addressCache, person ); + if( listGroup ) { + GHashTable *hashEMail; + GList *nodeGrp; + + // Load hash table with new address entries + hashEMail = g_hash_table_new( g_str_hash, g_str_equal ); + node = listEMail; + while( node ) { + ItemEMail *email = node->data; + gchar *addr = g_strdup( email->address ); + g_strdown( addr ); + if( ! g_hash_table_lookup( hashEMail, addr ) ) { + g_hash_table_insert( hashEMail, addr, email ); + } + node = g_list_next( node ); + } + + // Re-parent new addresses to existing groups, where email address match. + nodeGrp = listGroup; + while( nodeGrp ) { + ItemGroup *group = ( ItemGroup * ) nodeGrp->data; + GList *groupEMail = group->listEMail; + GList *nodeGrpEM; + GList *listRemove = NULL; + + // Process each email item linked to group + nodeGrpEM = groupEMail; + while( nodeGrpEM ) { + ItemEMail *emailGrp = ( ItemEMail * ) nodeGrpEM->data; + if( ADDRITEM_PARENT(emailGrp) == ADDRITEM_OBJECT(person) ) { + // Found an email address for this person + ItemEMail *emailNew = NULL; + gchar *addr = g_strdup( emailGrp->address ); + g_strdown( addr ); + emailNew = ( ItemEMail * ) g_hash_table_lookup( hashEMail, addr ); + g_free( addr ); + if( emailNew ) { + // Point to this entry + nodeGrpEM->data = emailNew; + } + else { + // Mark for removal + listRemove = g_list_append( listRemove, emailGrp ); + } + } + // Move on to next email link + nodeGrpEM = g_list_next( nodeGrpEM ); + } + + // Process all removed links in current group + nodeGrpEM = listRemove; + while( nodeGrpEM ) { + ItemEMail *emailGrp = nodeGrpEM->data; + groupEMail = g_list_remove( groupEMail, emailGrp ); + nodeGrpEM = g_list_next( nodeGrpEM ); + } + + // Move on to next group + nodeGrp = g_list_next( nodeGrp ); + + } + + // Clear hash table + g_hash_table_foreach_remove( hashEMail, ( GHRFunc ) addrbook_free_simple_hash_vis, NULL ); + g_hash_table_destroy( hashEMail ); + hashEMail = NULL; + g_list_free( listGroup ); + listGroup = NULL; + } + + // Free up old data + addritem_free_list_email( oldData ); + oldData = NULL; + book->dirtyFlag = TRUE; + +} + +/* +* Add person and address data to address book. +* Enter: book Address book. +* folder Folder where to add person, or NULL for root folder. +* listEMail New list of email addresses. +* Return: Person added. +* Note: A new person is created with specified list of email addresses. All objects inserted +* into address book. +*/ +ItemPerson *addrbook_add_address_list( AddressBookFile *book, ItemFolder *folder, GList *listEMail ) { + ItemPerson *person; + ItemFolder *f = folder; + GList *node; + + g_return_if_fail( book != NULL ); + + if( ! f ) f = book->addressCache->rootFolder; + person = addritem_create_item_person(); + addrcache_id_person( book->addressCache, person ); + addrcache_folder_add_person( book->addressCache, f, person ); + + node = listEMail; + while( node ) { + ItemEMail *email = node->data; + if( ADDRITEM_ID(email) == NULL ) { + addrcache_id_email( book->addressCache, email ); + } + addrcache_person_add_email( book->addressCache, person, email ); + node = g_list_next( node ); + } + book->dirtyFlag = TRUE; + return person; +} + +/* +* Load hash table visitor function. +*/ +static void addrbook_load_hash_table_email_vis( gpointer key, gpointer value, gpointer data ) { + AddrItemObject *obj = ( AddrItemObject * ) value; + if( ADDRITEM_TYPE(obj) == ITEMTYPE_EMAIL ) { + GHashTable *table = ( GHashTable * ) data; + gchar *newKey = g_strdup( key ); + ItemEMail *email = ( ItemEMail * ) obj; + if( ! g_hash_table_lookup( table, newKey ) ) { + g_hash_table_insert( table, newKey, email ); + } + } +} + +/* +* Load hash table with links to email addresses. +*/ +static void addrbook_load_hash_table_email( AddressBookFile *book, GHashTable *table ) { + g_return_if_fail( book != NULL ); + g_return_if_fail( table != NULL ); + g_hash_table_foreach( book->addressCache->itemHash, addrbook_load_hash_table_email_vis, table ); +} + +/* +* Build available email list visitor function. +*/ +static void addrbook_build_avail_email_vis( gpointer key, gpointer value, gpointer data ) { + AddrItemObject *obj = ( AddrItemObject * ) value; + if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) { + AddressBookFile *book = data; + ItemPerson *person = ( ItemPerson * ) obj; + GList *node = person->listEMail; + while( node ) { + ItemEMail *email = node->data; + gchar *newKey = g_strdup( ADDRITEM_ID(email) ); + if( ! g_hash_table_lookup( book->tempHash, ADDRITEM_ID(email) ) ) { + book->tempList = g_list_append( book->tempList, email ); + } + node = g_list_next( node ); + } + } +} + +/* +* Return link list of available email items (which have not already been linked to +* groups). Note that the list contains references to items and should be g_free() +* when done. Do *NOT* attempt to used the addrbook_free_xxx() functions... this will +* destroy the addressbook data! +* Return: List of items, or NULL if none. +*/ +GList *addrbook_get_available_email_list( AddressBookFile *book, ItemGroup *group ) { + GList *list = NULL; + GHashTable *table; + + g_return_if_fail( book != NULL ); + + // Load hash table with group email entries + table = g_hash_table_new( g_str_hash, g_str_equal ); + if( group ) { + list = group->listEMail; + while( list ) { + ItemEMail *email = list->data; + g_hash_table_insert( table, ADDRITEM_ID(email), email ); + list = g_list_next( list ); + } + } + + // Build list of available email addresses which exclude those already in groups + book->tempList = NULL; + book->tempHash = table; + g_hash_table_foreach( book->addressCache->itemHash, addrbook_build_avail_email_vis, book ); + list = book->tempList; + book->tempList = NULL; + book->tempHash = NULL; + + // Clear hash table + g_hash_table_destroy( table ); + table = NULL; + + return list; +} + +/* +* Update address book email list for specified group. +* Enter: book Address book. +* group group to update. +* listEMail New list of email addresses. This should *NOT* be g_free() when done. +* Note: The existing email addresses are replaced with the new addresses. Any references +* to old addresses in the groups are re-linked to the new addresses. All old addresses +* linked to the person are removed. +*/ +void addrbook_update_group_list( AddressBookFile *book, ItemGroup *group, GList *listEMail ) { + GList *oldData; + + g_return_if_fail( book != NULL ); + g_return_if_fail( group != NULL ); + + // Remember old list + oldData = group->listEMail; + group->listEMail = listEMail; + mgu_clear_list( oldData ); + oldData = NULL; + book->dirtyFlag = TRUE; +} + +/* +* Add group and email list to address book. +* Enter: book Address book. +* folder Parent folder, or NULL for root folder. +* listEMail New list of email addresses. This should *NOT* be g_free() when done. +* Return: Group object. +* Note: The existing email addresses are replaced with the new addresses. Any references +* to old addresses in the groups are re-linked to the new addresses. All old addresses +* linked to the person are removed. +*/ +ItemGroup *addrbook_add_group_list( AddressBookFile *book, ItemFolder *folder, GList *listEMail ) { + ItemGroup *group = NULL; + ItemFolder *f = folder; + g_return_if_fail( book != NULL ); + + if( ! f ) f = book->addressCache->rootFolder; + group = addritem_create_item_group(); + addrcache_id_group( book->addressCache, group ); + addrcache_folder_add_group( book->addressCache, f, group ); + group->listEMail = listEMail; + book->dirtyFlag = TRUE; + return group; +} + +/* +* Add new folder to address book. +* Enter: book Address book. +* parent Parent folder. +* Return: Folder that was added. This should *NOT* be g_free() when done. +*/ +ItemFolder *addrbook_add_new_folder( AddressBookFile *book, ItemFolder *parent ) { + ItemFolder *folder = NULL; + ItemFolder *p = parent; + g_return_if_fail( book != NULL ); + + if( ! p ) p = book->addressCache->rootFolder; + folder = addritem_create_item_folder(); + addrcache_id_folder( book->addressCache, folder ); + if( addrcache_hash_add_folder( book->addressCache, folder ) ) { + p->listFolder = g_list_append( p->listFolder, folder ); + ADDRITEM_PARENT(folder) = ADDRITEM_OBJECT(p); + book->dirtyFlag = TRUE; + } + else { + addritem_free_item_folder( folder ); + folder = NULL; + } + return folder; +} + +/* +* Update address book attribute list for specified person. +* Enter: book Address book. +* person Person to update. +* listAttrib New list of attributes. +* Note: The existing email addresses are replaced with the new addresses. All old attributes +* linked to the person are removed. +*/ +void addrbook_update_attrib_list( AddressBookFile *book, ItemPerson *person, GList *listAttrib ) { + GList *node; + GList *oldData; + + g_return_if_fail( book != NULL ); + g_return_if_fail( person != NULL ); + + // Remember old list + oldData = person->listAttrib; + + // Attach new address list to person. + node = listAttrib; + while( node ) { + UserAttribute *attrib = node->data; + if( attrib->uid == NULL ) { + // Allocate an ID + addrcache_id_attribute( book->addressCache, attrib ); + } + node = g_list_next( node ); + } + person->listAttrib = listAttrib; + + // Free up old data + addritem_free_list_attribute( oldData ); + oldData = NULL; + book->dirtyFlag = TRUE; + +} + +/* +* Add attribute data for person to address book. +* Enter: book Address book. +* person New person object. +* listAttrib New list of attributes. +* Note: Only attributes are inserted into address book. +*/ +void addrbook_add_attrib_list( AddressBookFile *book, ItemPerson *person, GList *listAttrib ) { + GList *node; + g_return_if_fail( book != NULL ); + g_return_if_fail( person != NULL ); + + node = listAttrib; + while( node ) { + UserAttribute *attrib = node->data; + if( attrib->uid == NULL ) { + addrcache_id_attribute( book->addressCache, attrib ); + } + addritem_person_add_attribute( person, attrib ); + node = g_list_next( node ); + } + book->dirtyFlag = TRUE; +} + +/* +* Return address book file for specified object. +* Enter: aio Book item object. +* Return: Address book, or NULL if not found. +*/ +AddressBookFile *addrbook_item_get_bookfile( AddrItemObject *aio ) { + AddressBookFile *book = NULL; + if( aio ) { + ItemFolder *parent = NULL; + ItemFolder *root = NULL; + if( aio->type == ITEMTYPE_EMAIL ) { + ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(aio); + if( person ) { + parent = ( ItemFolder * ) ADDRITEM_PARENT(person); + } + } + else { + parent = ( ItemFolder * ) ADDRITEM_PARENT(aio); + } + if( parent ) { + root = addrcache_find_root_folder( parent ); + } + if( root ) { + book = ( AddressBookFile * ) ADDRITEM_PARENT(root); + } + } + return book; +} + +/* +* Remove folder from address book. Children are re-parented to parent folder. +* param: folder Folder to remove. +* return: Folder, or NULL if not found. Note that object should still be freed. +*/ +ItemFolder *addrbook_remove_folder( AddressBookFile *book, ItemFolder *folder ) { + ItemFolder *f; + g_return_if_fail( book != NULL ); + f = addrcache_remove_folder( book->addressCache, folder ); + if( f ) book->dirtyFlag = TRUE; + return f; +} + +/* +* Remove folder from address book. Children are deleted. +* param: folder Folder to remove. +* return: Folder, or NULL if not found. Note that object should still be freed. +*/ +ItemFolder *addrbook_remove_folder_delete( AddressBookFile *book, ItemFolder *folder ) { + ItemFolder *f; + g_return_if_fail( book != NULL ); + f = addrcache_remove_folder_delete( book->addressCache, folder ); + if( f ) book->dirtyFlag = TRUE; + return f; +} + +#define WORK_BUFLEN 1024 +#define ADDRBOOK_DIGITS "0123456789" + +/* +* Return list of existing address book files. +* Enter: book Address book file. +* Return: File list. +*/ +GList *addrbook_get_bookfile_list( AddressBookFile *book ) { + gchar *adbookdir; + DIR *dp; + struct dirent *entry; + struct stat statbuf; + gchar buf[ WORK_BUFLEN ]; + gchar numbuf[ WORK_BUFLEN ]; + gint len, lenpre, lensuf, lennum; + long int val, maxval; + GList *fileList = NULL; + + g_return_if_fail( book != NULL ); + + if( book->path == NULL || *book->path == '\0' ) { + book->retVal = MGU_NO_PATH; + return NULL; + } + + strcpy( buf, book->path ); + len = strlen( buf ); + if( len > 0 ) { + if( buf[ len-1 ] != G_DIR_SEPARATOR ) { + buf[ len ] = G_DIR_SEPARATOR; + buf[ ++len ] = '\0'; + } + } + + adbookdir = g_strdup( buf ); + strcat( buf, ADDRBOOK_PREFIX ); + + if( ( dp = opendir( adbookdir ) ) == NULL ) { + book->retVal = MGU_OPEN_DIRECTORY; + g_free( adbookdir ); + return NULL; + } + + lenpre = strlen( ADDRBOOK_PREFIX ); + lensuf = strlen( ADDRBOOK_SUFFIX ); + lennum = FILE_NUMDIGITS + lenpre; + maxval = -1; + + while( ( entry = readdir( dp ) ) != NULL ) { + gchar **endptr = NULL; + gint i; + gboolean flg; + + strcpy( buf, adbookdir ); + strcat( buf, entry->d_name ); + stat( buf, &statbuf ); + if( S_IFREG & statbuf.st_mode ) { + if( strncmp( entry->d_name, ADDRBOOK_PREFIX, lenpre ) == 0 ) { + if( strncmp( (entry->d_name) + lennum, ADDRBOOK_SUFFIX, lensuf ) == 0 ) { + strncpy( numbuf, (entry->d_name) + lenpre, FILE_NUMDIGITS ); + flg = TRUE; + for( i = 0; i < FILE_NUMDIGITS; i++ ) { + if( ! strchr( ADDRBOOK_DIGITS, numbuf[i] ) ) { + flg = FALSE; + break; + } + } + if( flg ) { + // Get value + val = strtol( numbuf, &endptr, 10 ); + if( endptr && val > -1 ) { + if( val > maxval ) maxval = val; + fileList = g_list_append( fileList, g_strdup( entry->d_name ) ); + } + } + } + } + } + } + closedir( dp ); + g_free( adbookdir ); + + book->maxValue = maxval; + book->retVal = MGU_SUCCESS; + return fileList; +} + +/* +* Return file name for specified file number. +* Enter: fileNum File number. +* Return: File name, or NULL if file number too large. Should be g_free() when done. +*/ +gchar *addrbook_gen_new_file_name( gint fileNum ) { + gchar fmt[ 30 ]; + gchar buf[ WORK_BUFLEN ]; + gint n = fileNum; + long int nmax; + + if( n < 1 ) n = 1; + nmax = -1 + (long int) pow( 10, FILE_NUMDIGITS ); + if( fileNum > nmax ) return NULL; + sprintf( fmt, "%%s%%0%dd%%s", FILE_NUMDIGITS ); + sprintf( buf, fmt, ADDRBOOK_PREFIX, n, ADDRBOOK_SUFFIX ); + return g_strdup( buf ); +} + +/* ********************************************************************** +* Address book test functions... +* *********************************************************************** +*/ + +static void addrbook_show_attribs( GList *attr ) { + while( attr ) { + gchar *name = ((XMLAttr *)attr->data)->name; + gchar *value = ((XMLAttr *)attr->data)->value; + printf( "\tn/v = %s : %s\n", name, value ); + attr = g_list_next( attr ); + } + printf( "\t---\n" ); +} + +/* +* Test email address list. +*/ +static void addrbook_chkparse_addr_list( AddressBookFile *book, XMLFile *file ){ + guint prev_level; + GList *attr; + + for (;;) { + prev_level = file->level; + if( xml_parse_next_tag( file ) ) { + longjmp( book->jumper, 1 ); + } + if (file->level < prev_level) return; + attr = xml_get_current_tag_attr(file); + // addrbook_show_attribs( attr ); + if( xml_compare_tag( file, AB_ELTAG_ADDRESS ) ) { + addrbook_chkparse_addr_list( book, file ); + } + } +} + +/* +* Test user attributes for person. +*/ +static void addrbook_chkparse_attribute( AddressBookFile *book, XMLFile *file ) { + GList *attr; + gchar *element; + + attr = xml_get_current_tag_attr(file); + // addrbook_show_attribs( attr ); + element = xml_get_element( file ); + // printf( "\t\tattrib value : %s\n", element ); +} + +/* +* Test attribute list. +*/ +static void addrbook_chkparse_attr_list( AddressBookFile *book, XMLFile *file ){ + guint prev_level; + + for (;;) { + prev_level = file->level; + if( xml_parse_next_tag( file ) ) { + longjmp( book->jumper, 1 ); + } + if (file->level < prev_level) return; + if( xml_compare_tag( file, AB_ELTAG_ATTRIBUTE ) ) { + addrbook_chkparse_attribute( book, file ); + addrbook_chkparse_attr_list( book, file ); + } + } +} + +/* +* Test person. +*/ +static void addrbook_chkparse_person( AddressBookFile *book, XMLFile *file ) { + GList *attr; + gchar *name, *value; + + attr = xml_get_current_tag_attr(file); + // addrbook_show_attribs( attr ); + if( xml_parse_next_tag( file ) ) { // Consume closing tag + longjmp( book->jumper, 1 ); + } + if( xml_compare_tag( file, AB_ELTAG_ADDRESS_LIST ) ) { + addrbook_chkparse_addr_list( book, file ); + } + if( xml_parse_next_tag( file ) ) { // Consume closing tag + longjmp( book->jumper, 1 ); + } + if( xml_compare_tag( file, AB_ELTAG_ATTRIBUTE_LIST ) ) { + addrbook_chkparse_attr_list( book, file ); + } +} + +/* +* Test group member list. +*/ +static void addrbook_chkparse_member_list( AddressBookFile *book, XMLFile *file ){ + GList *attr; + guint prev_level; + + for (;;) { + prev_level = file->level; + if( xml_parse_next_tag( file ) ) { + longjmp( book->jumper, 1 ); + } + if (file->level < prev_level) return; + if( xml_compare_tag( file, AB_ELTAG_MEMBER ) ) { + attr = xml_get_current_tag_attr(file); + // addrbook_show_attribs( attr ); + addrbook_chkparse_member_list( book, file ); + } + else { + attr = xml_get_current_tag_attr( file ); + // addrbook_show_attribs( attr ); + } + } +} + +/* +* Test group. +*/ +static void addrbook_chkparse_group( AddressBookFile *book, XMLFile *file ) { + GList *attr; + gchar *name, *value; + + attr = xml_get_current_tag_attr(file); + // addrbook_show_attribs( attr ); + if( xml_parse_next_tag( file ) ) { // Consume closing tag + longjmp( book->jumper, 1 ); + } + if( xml_compare_tag( file, AB_ELTAG_MEMBER_LIST ) ) { + addrbook_chkparse_member_list( book, file ); + } +} + +/* +* Test folder item list. +*/ +static void addrbook_chkparse_folder_list( AddressBookFile *book, XMLFile *file ){ + GList *attr; + guint prev_level; + + for (;;) { + prev_level = file->level; + if( xml_parse_next_tag( file ) ) { + longjmp( book->jumper, 1 ); + } + if (file->level < prev_level) return; + if( xml_compare_tag( file, AB_ELTAG_ITEM ) ) { + attr = xml_get_current_tag_attr(file); + // addrbook_show_attribs( attr ); + addrbook_chkparse_folder_list( book, file ); + } + else { + attr = xml_get_current_tag_attr( file ); + // addrbook_show_attribs( attr ); + } + } +} + +/* +* Test folder. +*/ +static void addrbook_chkparse_folder( AddressBookFile *book, XMLFile *file ) { + GList *attr; + gchar *name, *value; + + attr = xml_get_current_tag_attr(file); + // addrbook_show_attribs( attr ); + if( xml_parse_next_tag( file ) ) { // Consume closing tag + longjmp( book->jumper, 1 ); + } + if( xml_compare_tag( file, AB_ELTAG_ITEM_LIST ) ) { + addrbook_chkparse_folder_list( book, file ); + } +} + +/* +* Test address book. +*/ +static gboolean addrbook_chkread_tree( AddressBookFile *book, XMLFile *file ) { + GList *attr; + gchar *name, *value; + gboolean retVal; + + if( xml_get_dtd( file ) ) { + return FALSE; + } + if( xml_parse_next_tag( file ) ) { + return FALSE; + } + + if( ! xml_compare_tag( file, AB_ELTAG_ADDRESS_BOOK ) ) { + return FALSE; + } + + attr = xml_get_current_tag_attr(file); + // addrbook_show_attribs( attr ); + + retVal = TRUE; + for (;;) { + if (! file->level ) break; + // Get item tag + if( xml_parse_next_tag( file ) ) { + longjmp( book->jumper, 1 ); + } + // Get next tag (person, group or folder) + if( xml_parse_next_tag( file ) ) { + longjmp( book->jumper, 1 ); + } + if( xml_compare_tag( file, AB_ELTAG_PERSON ) ) { + addrbook_chkparse_person( book, file ); + } + else if( xml_compare_tag( file, AB_ELTAG_GROUP ) ) { + addrbook_chkparse_group( book, file ); + } + else if( xml_compare_tag( file, AB_ELTAG_FOLDER ) ) { + addrbook_chkparse_folder( book, file ); + } + else { + // Item not recognized + retVal = FALSE; + } + } + return retVal; +} + +/* +* Test address book file by parsing contents. +* Enter: book Address book file to check. +* fileName File name to check. +* Return: MGU_SUCCESS if file appears to be valid format. +*/ +gint addrbook_test_read_file( AddressBookFile *book, gchar *fileName ) { + XMLFile *file = NULL; + gchar *fileSpec = NULL; + + g_return_if_fail( book != NULL ); + + fileSpec = g_strconcat( book->path, G_DIR_SEPARATOR_S, fileName, NULL ); + book->retVal = MGU_OPEN_FILE; + file = xml_open_file( fileSpec ); + g_free( fileSpec ); + if( file ) { + book->retVal = MGU_BAD_FORMAT; + if( setjmp( book->jumper ) ) { + // printf( "Caught Ya!!!\n" ); + xml_close_file( file ); + return book->retVal; + } + if( addrbook_chkread_tree( book, file ) ) { + book->retVal = MGU_SUCCESS; + } + xml_close_file( file ); + } + return book->retVal; +} + +/* +* Return link list of all persons in address book. Note that the list contains +* references to items. Do *NOT* attempt to use the addrbook_free_xxx() functions... +* this will destroy the addressbook data! +* Return: List of items, or NULL if none. +*/ +GList *addrbook_get_all_persons( AddressBookFile *book ) { + g_return_if_fail( book != NULL ); + return addrcache_get_all_persons( book->addressCache ); +} + +/* +* Add person and address data to address book. +* Enter: book Address book. +* folder Folder where to add person, or NULL for root folder. +* name Common name. +* address EMail address. +* remarks Remarks. +* Return: Person added. Do not *NOT* to use the addrbook_free_xxx() functions... +* this will destroy the address book data. +*/ +ItemPerson *addrbook_add_contact( AddressBookFile *book, ItemFolder *folder, const gchar *name, + const gchar *address, const gchar *remarks ) +{ + ItemPerson *person = NULL; + g_return_if_fail( book != NULL ); + person = addrcache_add_contact( book->addressCache, folder, name, address, remarks ); + if( person ) book->dirtyFlag = TRUE; + return person; +} + +/* +* End of Source. +*/ + diff --git a/src/addrbook.h b/src/addrbook.h new file mode 100644 index 000000000..3f6002ed2 --- /dev/null +++ b/src/addrbook.h @@ -0,0 +1,116 @@ +/* + * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client + * Copyright (C) 2001 Match Grun + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ + +/* + * Definitions necessary to access external address book files. + */ + +#ifndef __ADDRBOOK_H__ +#define __ADDRBOOK_H__ + +#include +#include +#include + +#include "addritem.h" +#include "addrcache.h" + +// Address book file. +typedef struct _AddressBookFile AddressBookFile; +struct _AddressBookFile { + gchar *name; + gchar *path; + gchar *fileName; + AddressCache *addressCache; + gint retVal; + gint maxValue; + GList *tempList; + GHashTable *tempHash; + gboolean readFlag; + gboolean dirtyFlag; + gboolean modifyFlag; + gboolean accessFlag; + jmp_buf jumper; +}; + +// Function prototypes + +AddressBookFile *addrbook_create_book ( void ); +void addrbook_empty_book ( AddressBookFile *book ); +void addrbook_free_book ( AddressBookFile *book ); +void addrbook_print_book ( AddressBookFile *book, FILE *stream ); +void addrbook_dump_hash ( AddressBookFile *book, FILE *stream ); +void addrbook_dump_book ( AddressBookFile *book, FILE *stream ); +void addrbook_set_name ( AddressBookFile *book, const gchar *value ); +void addrbook_set_path ( AddressBookFile *book, const gchar *value ); +void addrbook_set_file ( AddressBookFile *book, const gchar *value ); +void addrbook_set_accessed ( AddressBookFile *book, const gboolean value ); +gboolean addrbook_get_modified ( AddressBookFile *book ); +gboolean addrbook_get_accessed ( AddressBookFile *book ); +gboolean addrbook_get_read_flag ( AddressBookFile *book ); +gint addrbook_get_status ( AddressBookFile *book ); +ItemFolder *addrbook_get_root_folder ( AddressBookFile *book ); +GList *addrbook_get_list_folder ( AddressBookFile *book ); +GList *addrbook_get_list_person ( AddressBookFile *book ); +gchar *addrbook_get_name ( AddressBookFile *book ); + +ItemPerson *addrbook_remove_person ( AddressBookFile *book, ItemPerson *person ); +ItemGroup *addrbook_remove_group ( AddressBookFile *book, ItemGroup *group ); +ItemEMail *addrbook_person_remove_email ( AddressBookFile *book, ItemPerson *person, + ItemEMail *email ); + +gint addrbook_read_data ( AddressBookFile *book ); +gint addrbook_save_data ( AddressBookFile *book ); + +ItemEMail *addrbook_move_email_before ( AddressBookFile *book, ItemPerson *person, + ItemEMail *itemMove, ItemEMail *itemTarget ); +ItemEMail *addrbook_move_email_after ( AddressBookFile *book, ItemPerson *person, + ItemEMail *itemMove, ItemEMail *itemTarget ); + +void addrbook_update_address_list ( AddressBookFile *book, ItemPerson *person, + GList *listEMail ); +ItemPerson *addrbook_add_address_list ( AddressBookFile *book, ItemFolder *folder, + GList *listEMail ); +GList *addrbook_get_available_email_list( AddressBookFile *book, ItemGroup *group ); +void addrbook_update_group_list ( AddressBookFile *book, ItemGroup *group, + GList *listEMail ); +ItemGroup *addrbook_add_group_list ( AddressBookFile *book, ItemFolder *folder, + GList *listEMail ); +ItemFolder *addrbook_add_new_folder ( AddressBookFile *book, ItemFolder *parent ); + +ItemFolder *addrbook_remove_folder ( AddressBookFile *book, ItemFolder *folder ); +ItemFolder *addrbook_remove_folder_delete( AddressBookFile *book, ItemFolder *folder ); + +GList *addrbook_get_bookfile_list ( AddressBookFile *book ); +gchar *addrbook_gen_new_file_name ( gint fileNum ); +gint addrbook_test_read_file ( AddressBookFile *book, gchar *fileName ); + +GList *addrbook_get_all_persons ( AddressBookFile *book ); + +ItemPerson *addrbook_add_contact ( AddressBookFile *book, ItemFolder *folder, + const gchar *name, const gchar *address, + const gchar *remarks ); + +#endif /* __ADDRBOOK_H__ */ + +/* +* End of Source. +*/ + + diff --git a/src/addrcache.c b/src/addrcache.c new file mode 100644 index 000000000..c9bc33b84 --- /dev/null +++ b/src/addrcache.c @@ -0,0 +1,1164 @@ +/* + * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client + * Copyright (C) 2001 Match Grun + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ + +/* + * Functions to maintain address cache. + */ + +#include +#include +#include + +// #include "mgutils.h" +#include "addritem.h" +#include "addrcache.h" + +#define ID_TIME_OFFSET 998000000 +#define ADDRCACHE_MAX_SEARCH_COUNT 1000 + +/* +* Create new address cache. +*/ +AddressCache *addrcache_create() { + AddressCache *cache; + gint t; + + cache = g_new0( AddressCache, 1 ); + cache->itemHash = g_hash_table_new( g_str_hash, g_str_equal ); + + cache->dataRead = FALSE; + cache->modified = FALSE; + cache->modifyTime = 0; + + // Generate the next ID using system time + cache->nextID = 1; + t = time( NULL ); + if( t > 0 ) { + cache->nextID = t - ID_TIME_OFFSET; + } + + cache->tempList = NULL; + cache->rootFolder = addritem_create_item_folder(); + cache->rootFolder->isRoot = TRUE; + ADDRITEM_PARENT(cache->rootFolder) = NULL; + return cache; +} + +/* +* Properties. +*/ +ItemFolder *addrcache_get_root_folder( AddressCache *cache ) { + g_return_if_fail( cache != NULL ); + return cache->rootFolder; +} +GList *addrcache_get_list_folder( AddressCache *cache ) { + g_return_if_fail( cache != NULL ); + return cache->rootFolder->listFolder; +} +GList *addrcache_get_list_person( AddressCache *cache ) { + g_return_if_fail( cache != NULL ); + return cache->rootFolder->listPerson; +} + +/* +* Generate next ID. +*/ +void addrcache_next_id( AddressCache *cache ) { + g_return_if_fail( cache != NULL ); + cache->nextID++; +} + +/* +* Refresh internal variables. This can be used force a reload. +*/ +void addrcache_refresh( AddressCache *cache ) { + cache->dataRead = FALSE; + cache->modified = TRUE; + cache->modifyTime = 0; +} + +/* +* Free hash table visitor function. +*/ +static gint addrcache_free_item_vis( gpointer key, gpointer value, gpointer data ) { + AddrItemObject *obj = ( AddrItemObject * ) value; + if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) { + addritem_free_item_person( ( ItemPerson * ) obj ); + } + else if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) { + addritem_free_item_group( ( ItemGroup * ) obj ); + } + else if( ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER ) { + addritem_free_item_folder( ( ItemFolder * ) obj ); + } + key = NULL; + value = NULL; + return 0; +} + +/* +* Free hash table of address cache items. +*/ +static void addrcache_free_item_hash( GHashTable *table ) { + g_return_if_fail( table != NULL ); + g_hash_table_freeze( table ); + g_hash_table_foreach_remove( table, addrcache_free_item_vis, NULL ); + g_hash_table_thaw( table ); + g_hash_table_destroy( table ); +} + +/* +* Free up folders and groups. +*/ +static void addrcache_free_all_folders( ItemFolder *parent ) { + GList *node = parent->listFolder; + while( node ) { + ItemFolder *folder = node->data; + addrcache_free_all_folders( folder ); + node = g_list_next( node ); + } + g_list_free( parent->listPerson ); + g_list_free( parent->listGroup ); + g_list_free( parent->listFolder ); + parent->listPerson = NULL; + parent->listGroup = NULL; + parent->listFolder = NULL; +} + +/* +* Clear the address cache. +*/ +void addrcache_clear( AddressCache *cache ) { + g_return_if_fail( cache != NULL ); + + // Free up folders and hash table + addrcache_free_all_folders( cache->rootFolder ); + addrcache_free_item_hash( cache->itemHash ); + cache->itemHash = NULL; + ADDRITEM_PARENT(cache->rootFolder) = NULL; + addritem_free_item_folder( cache->rootFolder ); + cache->rootFolder = NULL; + g_list_free( cache->tempList ); + cache->tempList = NULL; + + // Reset to initial state + cache->itemHash = g_hash_table_new( g_str_hash, g_str_equal ); + cache->rootFolder = addritem_create_item_folder(); + cache->rootFolder->isRoot = TRUE; + ADDRITEM_PARENT(cache->rootFolder) = NULL; + + addrcache_refresh( cache ); + +} + +/* +* Free address cache. +*/ +void addrcache_free( AddressCache *cache ) { + g_return_if_fail( cache != NULL ); + + addrcache_free_all_folders( cache->rootFolder ); + addrcache_free_item_hash( cache->itemHash ); + cache->itemHash = NULL; + ADDRITEM_PARENT(cache->rootFolder) = NULL; + addritem_free_item_folder( cache->rootFolder ); + cache->rootFolder = NULL; + g_list_free( cache->tempList ); + cache->tempList = NULL; + g_free( cache ); +} + +/* +* Check whether file has changed by comparing with cache. +* return: TRUE if file has changed. +*/ +gboolean addrcache_check_file( AddressCache *cache, gchar *path ) { + gboolean retVal; + struct stat filestat; + retVal = TRUE; + if( path ) { + if( 0 == lstat( path, &filestat ) ) { + if( filestat.st_mtime == cache->modifyTime ) retVal = FALSE; + } + } + return retVal; +} + +/* +* Save file time to cache. +* return: TRUE if time marked. +*/ +gboolean addrcache_mark_file( AddressCache *cache, gchar *path ) { + gboolean retVal = FALSE; + struct stat filestat; + if( path ) { + if( 0 == lstat( path, &filestat ) ) { + cache->modifyTime = filestat.st_mtime; + retVal = TRUE; + } + } + return retVal; +} + +/* +* Print list of items. +*/ +void addrcache_print_item_list( GList *list, FILE *stream ) { + GList *node = list; + while( node ) { + AddrItemObject *obj = node->data; + if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) { + addritem_print_item_person( ( ItemPerson * ) obj, stream ); + } + else if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) { + addritem_print_item_group( ( ItemGroup * ) obj, stream ); + } + else if( ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER ) { + addritem_print_item_folder( ( ItemFolder * ) obj, stream ); + } + node = g_list_next( node ); + } + fprintf( stream, "\t---\n" ); +} + +/* +* Print item hash table visitor function. +*/ +static void addrcache_print_item_vis( gpointer key, gpointer value, gpointer data ) { + AddrItemObject *obj = ( AddrItemObject * ) value; + FILE *stream = ( FILE * ) data; + if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) { + addritem_print_item_person( ( ItemPerson * ) obj, stream ); + } + else if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) { + addritem_print_item_group( ( ItemGroup * ) obj, stream ); + } + else if( ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER ) { + addritem_print_item_folder( ( ItemFolder * ) obj, stream ); + } +} + +/* +* Dump entire address cache hash table contents. +*/ +void addrcache_print( AddressCache *cache, FILE *stream ) { + g_return_if_fail( cache != NULL ); + fprintf( stream, "AddressCache:\n" ); + fprintf( stream, "next id : %d\n", cache->nextID ); + fprintf( stream, "mod time : %d\n", cache->modifyTime ); + fprintf( stream, "modified : %s\n", cache->modified ? "yes" : "no" ); + fprintf( stream, "data read: %s\n", cache->dataRead ? "yes" : "no" ); +} + +/* +* Dump entire address cache hash table contents. +*/ +void addrcache_dump_hash( AddressCache *cache, FILE *stream ) { + g_return_if_fail( cache != NULL ); + addrcache_print( cache, stream ); + g_hash_table_foreach( cache->itemHash, addrcache_print_item_vis, stream ); +} + +/* + * Allocate ID for person. + */ +void addrcache_id_person( AddressCache *cache, ItemPerson *person ) { + g_return_if_fail( cache != NULL ); + g_return_if_fail( person != NULL ); + if( ADDRITEM_ID(person) ) return; + addrcache_next_id( cache ); + ADDRITEM_ID(person) = g_strdup_printf( "%d", cache->nextID ); +} + +/* + * Allocate ID for group. + */ +void addrcache_id_group( AddressCache *cache, ItemGroup *group ) { + g_return_if_fail( cache != NULL ); + g_return_if_fail( group != NULL ); + if( ADDRITEM_ID(group) ) return; + addrcache_next_id( cache ); + ADDRITEM_ID(group) = g_strdup_printf( "%d", cache->nextID ); +} + +/* + * Allocate ID for folder. + */ +void addrcache_id_folder( AddressCache *cache, ItemFolder *folder ) { + g_return_if_fail( cache != NULL ); + g_return_if_fail( folder != NULL ); + if( ADDRITEM_ID(folder) ) return; + addrcache_next_id( cache ); + ADDRITEM_ID(folder) = g_strdup_printf( "%d", cache->nextID ); +} + +/* + * Allocate ID for email address. + */ +void addrcache_id_email( AddressCache *cache, ItemEMail *email ) { + g_return_if_fail( cache != NULL ); + g_return_if_fail( email != NULL ); + if( ADDRITEM_ID(email) ) return; + addrcache_next_id( cache ); + ADDRITEM_ID(email) = g_strdup_printf( "%d", cache->nextID ); +} + +/* + * Allocate ID for user attribute. + */ +void addrcache_id_attribute( AddressCache *cache, UserAttribute *attrib ) { + g_return_if_fail( cache != NULL ); + g_return_if_fail( attrib != NULL ); + if( attrib->uid ) return; + addrcache_next_id( cache ); + attrib->uid = g_strdup_printf( "%d", cache->nextID ); +} + +/* +* Add person to hash table. +* return: TRUE if item added. +*/ +gboolean addrcache_hash_add_person( AddressCache *cache, ItemPerson *person ) { + if( g_hash_table_lookup( cache->itemHash, ADDRITEM_ID(person) ) ) { + return FALSE; + } + g_hash_table_insert( cache->itemHash, ADDRITEM_ID(person), person ); + return TRUE; +} + +/* +* Add group to hash table. +* return: TRUE if item added. +*/ +gboolean addrcache_hash_add_group( AddressCache *cache, ItemGroup *group ) { + g_return_if_fail( cache != NULL ); + g_return_if_fail( group != NULL ); + if( g_hash_table_lookup( cache->itemHash, ADDRITEM_ID(group) ) ) { + return FALSE; + } + g_hash_table_insert( cache->itemHash, ADDRITEM_ID(group), group ); + return TRUE; +} + +/* +* Add folder to hash table. +* return: TRUE if item added. +*/ +gboolean addrcache_hash_add_folder( AddressCache *cache, ItemFolder *folder ) { + g_return_if_fail( cache != NULL ); + g_return_if_fail( folder != NULL ); + if( g_hash_table_lookup( cache->itemHash, ADDRITEM_ID(folder) ) ) { + return FALSE; + } + g_hash_table_insert( cache->itemHash, ADDRITEM_ID(folder), folder ); + return TRUE; +} + +/* +* Add person to specified folder in cache. +*/ +gboolean addrcache_folder_add_person( AddressCache *cache, ItemFolder *folder, ItemPerson *item ) { + gboolean retVal = FALSE; + g_return_if_fail( cache != NULL ); + g_return_if_fail( folder != NULL ); + g_return_if_fail( item != NULL ); + retVal = addrcache_hash_add_person( cache, item ); + if( retVal ) { + addritem_folder_add_person( folder, item ); + } + return retVal; +} + +/* +* Add folder to specified folder in cache. +*/ +gboolean addrcache_folder_add_folder( AddressCache *cache, ItemFolder *folder, ItemFolder *item ) { + gboolean retVal = FALSE; + g_return_if_fail( cache != NULL ); + g_return_if_fail( folder != NULL ); + g_return_if_fail( item != NULL ); + retVal = addrcache_hash_add_folder( cache, item ); + if( retVal ) { + addritem_folder_add_folder( folder, item ); + } + return TRUE; +} + +/* +* Add folder to specified folder in cache. +*/ +gboolean addrcache_folder_add_group( AddressCache *cache, ItemFolder *folder, ItemGroup *item ) { + gboolean retVal = FALSE; + g_return_if_fail( cache != NULL ); + g_return_if_fail( folder != NULL ); + g_return_if_fail( item != NULL ); + retVal = addrcache_hash_add_group( cache, item ); + if( retVal ) { + addritem_folder_add_group( folder, item ); + } + return retVal; +} + +/* +* Add person to address cache. +* return: TRUE if item added. +*/ +gboolean addrcache_add_person( AddressCache *cache, ItemPerson *person ) { + gboolean retVal = FALSE; + g_return_if_fail( cache != NULL ); + g_return_if_fail( person != NULL ); + retVal = addrcache_hash_add_person( cache, person ); + if( retVal ) { + addritem_folder_add_person( cache->rootFolder, person ); + } + return retVal; +} + +/* +* Add EMail address to person. +* return: TRUE if item added. +*/ +gboolean addrcache_person_add_email( AddressCache *cache, ItemPerson *person, ItemEMail *email ) { + g_return_if_fail( cache != NULL ); + g_return_if_fail( person != NULL ); + g_return_if_fail( email != NULL ); + addritem_person_add_email( person, email ); + return TRUE; +} + +/* +* Add group to address cache. +* return: TRUE if item added. +*/ +gboolean addrcache_add_group( AddressCache *cache, ItemGroup *group ) { + gboolean retVal = FALSE; + g_return_if_fail( cache != NULL ); + g_return_if_fail( group != NULL ); + retVal = addrcache_hash_add_group( cache, group ); + if( retVal ) { + addritem_folder_add_group( cache->rootFolder, group ); + } + return retVal; +} + +/* +* Add EMail address to person. +* return: TRUE if item added. +*/ +gboolean addrcache_group_add_email( AddressCache *cache, ItemGroup *group, ItemEMail *email ) { + g_return_if_fail( cache != NULL ); + g_return_if_fail( group != NULL ); + g_return_if_fail( email != NULL ); + addritem_group_add_email( group, email ); + return TRUE; +} + +/* +* Add folder to address cache. +* return: TRUE if item added. +*/ +gboolean addrcache_add_folder( AddressCache *cache, ItemFolder *folder ) { + gboolean retVal = FALSE; + g_return_if_fail( cache != NULL ); + g_return_if_fail( folder != NULL ); + retVal = addrcache_hash_add_folder( cache, folder ); + if( retVal ) { + addritem_folder_add_folder( cache->rootFolder, folder ); + } + return retVal; +} + +/* +* Return pointer to object (either person or group) for specified ID. +* param: uid Object ID. +* return: Object, or NULL if not found. +*/ +AddrItemObject *addrcache_get_object( AddressCache *cache, const gchar *uid ) { + AddrItemObject *obj = NULL; + gchar *uidH; + + g_return_if_fail( cache != NULL ); + if( uid == NULL || *uid == '\0' ) return NULL; + obj = ( AddrItemObject * ) g_hash_table_lookup( cache->itemHash, uid ); + if( obj ) { + // Check for matching UID + uidH = ADDRITEM_ID(obj); + if( uidH ) { + if( strcmp( uidH, uid ) == 0 ) return obj; + } + } + return NULL; +} + +/* +* Return pointer for specified object ID. +* param: uid Object ID. +* return: Person object, or NULL if not found. +*/ +ItemPerson *addrcache_get_person( AddressCache *cache, const gchar *uid ) { + ItemPerson *person = NULL; + AddrItemObject *obj = addrcache_get_object( cache, uid ); + if( obj ) { + if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) { + person = ( ItemPerson * ) obj; + } + } + return person; +} + +/* +* Return pointer for specified object ID. +* param: uid group ID. +* return: Group object, or NULL if not found. +*/ +ItemGroup *addrcache_get_group( AddressCache *cache, const gchar *uid ) { + ItemGroup *group = NULL; + AddrItemObject *obj = addrcache_get_object( cache, uid ); + if( obj ) { + if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) { + group = ( ItemGroup * ) obj; + } + } + return group; +} + +/* +* Find email address in address cache. +* param: uid Object ID for person. +* eid EMail ID. +* return: email object for specified object ID and email ID, or NULL if not found. +*/ +ItemEMail *addrcache_get_email( AddressCache *cache, const gchar *uid, const gchar *eid ) { + AddrItemObject *objP; + if( eid == NULL || *eid == '\0' ) return NULL; + + objP = addrcache_get_object( cache, uid ); + if( objP ) { + if( ADDRITEM_TYPE(objP) == ITEMTYPE_PERSON ) { + // Sequential search through email addresses + ItemPerson *person = ( ItemPerson * ) objP; + GList *nodeMail = person->listEMail; + while( nodeMail ) { + AddrItemObject *objE = nodeMail->data; + gchar *ide = ADDRITEM_ID(objE); + if( ide ) { + if( strcmp( ide, eid ) == 0 ) { + return ( ItemEMail * ) objE; + } + } + nodeMail = g_list_next( nodeMail ); + } + } + } + return NULL; +} + +/* +* Remove attribute from person. +* param: uid Object ID for person. +* aid Attribute ID. +* return: UserAttribute object, or NULL if not found. Note that object should still be freed. +*/ +UserAttribute *addrcache_person_remove_attrib_id( AddressCache *cache, const gchar *uid, const gchar *aid ) { + UserAttribute *attrib = NULL; + ItemPerson *person; + if( aid == NULL || *aid == '\0' ) return NULL; + + person = addrcache_get_person( cache, uid ); + if( person ) { + attrib = addritem_person_remove_attrib_id( person, aid ); + } + return attrib; +} + +/* +* Remove attribute from person. +* param: person Person. +* attrib Attribute to remove. +* return: UserAttribute object. Note that object should still be freed. +*/ +UserAttribute *addrcache_person_remove_attribute( AddressCache *cache, ItemPerson *person, UserAttribute *attrib ) { + UserAttribute *found = NULL; + g_return_if_fail( cache != NULL ); + if( person && attrib ) { + found = addritem_person_remove_attribute( person, attrib ); + } + return found; +} + +/* +* Remove group from address cache for specified ID. +* param: uid Object ID. +* return: Group, or NULL if not found. Note that object should still be freed. +*/ +ItemGroup *addrcache_remove_group_id( AddressCache *cache, const gchar *uid ) { + AddrItemObject *obj = NULL; + + g_return_if_fail( cache != NULL ); + if( uid == NULL || *uid == '\0' ) return NULL; + obj = ( AddrItemObject * ) g_hash_table_lookup( cache->itemHash, uid ); + if( obj ) { + if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) { + ItemGroup *group = ( ItemGroup * ) obj; + ItemFolder *parent = ( ItemFolder * ) ADDRITEM_PARENT(group); + if( ! parent ) parent = cache->rootFolder; + // Remove group from parent's list and hash table + parent->listGroup = g_list_remove( parent->listGroup, group ); + g_hash_table_remove( cache->itemHash, uid ); + return ( ItemGroup * ) obj; + } + } + return NULL; +} + +/* +* Remove group from address cache. +* param: group Group to remove. +* return: Group, or NULL if not found. Note that object should still be freed. +*/ +ItemGroup *addrcache_remove_group( AddressCache *cache, ItemGroup *group ) { + AddrItemObject *obj = NULL; + + g_return_if_fail( cache != NULL ); + if( group ) { + gchar *uid = ADDRITEM_ID(group); + if( uid == NULL || *uid == '\0' ) return NULL; + obj = ( AddrItemObject * ) g_hash_table_lookup( cache->itemHash, uid ); + if( obj ) { + ItemGroup *item = ( ItemGroup * ) obj; + ItemFolder *parent = ( ItemFolder * ) ADDRITEM_PARENT(group); + if( ! parent ) parent = cache->rootFolder; + + // Remove group from parent's list and hash table + parent->listGroup = g_list_remove( parent->listGroup, obj ); + g_hash_table_remove( cache->itemHash, uid ); + return group; + } + } + return NULL; +} + +/* +* Remove person's email address from all groups in folder. +*/ +static void addrcache_foldergrp_rem_person( ItemFolder *folder, ItemPerson *person ) { + GList *nodeGrp = folder->listGroup; + while( nodeGrp ) { + ItemGroup *group = nodeGrp->data; + if( group ) { + // Remove each email address that belongs to the person from the list + GList *node = person->listEMail; + while( node ) { + group->listEMail = g_list_remove( group->listEMail, node->data ); + node = g_list_next( node ); + } + } + nodeGrp = g_list_next( nodeGrp ); + } +} + +/* +* Remove person from address cache for specified ID. Note that person still retains +* their EMail addresses. Also, links to these email addresses will be severed from +* the group. +* param: uid Object ID. +* return: Person, or NULL if not found. Note that object should still be freed. +*/ +ItemPerson *addrcache_remove_person_id( AddressCache *cache, const gchar *uid ) { + AddrItemObject *obj = NULL; + + g_return_if_fail( cache != NULL ); + if( uid == NULL || *uid == '\0' ) return NULL; + obj = ( AddrItemObject * ) g_hash_table_lookup( cache->itemHash, uid ); + if( obj ) { + if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) { + // Remove person's email addresses from all groups where + // referenced and from hash table. + ItemPerson *person = ( ItemPerson * ) obj; + ItemFolder *parent = ( ItemFolder * ) ADDRITEM_PARENT(person); + if( ! parent ) parent = cache->rootFolder; + // Remove emails from groups, remove from parent's list + // and hash table + addrcache_foldergrp_rem_person( parent, person ); + parent->listPerson = g_list_remove( parent->listPerson, person ); + g_hash_table_remove( cache->itemHash, uid ); + return person; + } + } + return NULL; +} + +/* +* Remove specified person from address cache. +* param: person Person to remove. +* return: Person, or NULL if not found. Note that object should still be freed. +*/ +ItemPerson *addrcache_remove_person( AddressCache *cache, ItemPerson *person ) { + AddrItemObject *obj = NULL; + + g_return_if_fail( cache != NULL ); + if( person ) { + gchar *uid = ADDRITEM_ID(person); + if( uid == NULL || *uid == '\0' ) return NULL; + obj = ( AddrItemObject * ) g_hash_table_lookup( cache->itemHash, uid ); + if( obj ) { + if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) { + // Remove person's email addresses from all groups where + // referenced and from hash table. + ItemFolder *parent = ( ItemFolder * ) ADDRITEM_PARENT(person); + if( ! parent ) parent = cache->rootFolder; + addrcache_foldergrp_rem_person( parent, person ); + parent->listPerson = g_list_remove( parent->listPerson, person ); + g_hash_table_remove( cache->itemHash, uid ); + return person; + } + } + } + return NULL; +} + +/* +* Remove email from group item hash table visitor function. +*/ +static void addrcache_allgrp_rem_email_vis( gpointer key, gpointer value, gpointer data ) { + AddrItemObject *obj = ( AddrItemObject * ) value; + ItemEMail *email = ( ItemEMail * ) data; + if( ! email ) return; + if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) { + ItemGroup *group = ( ItemGroup * ) value; + if( group ) { + // Remove each email address that belongs to the person from the list + group->listEMail = g_list_remove( group->listEMail, email ); + } + } +} + +/* +* Remove email address in address cache for specified ID. +* param: uid Object ID for person. +* eid EMail ID. +* return: EMail object, or NULL if not found. Note that object should still be freed. +*/ +ItemEMail *addrcache_person_remove_email_id( AddressCache *cache, const gchar *uid, const gchar *eid ) { + ItemEMail *email = NULL; + ItemPerson *person; + if( eid == NULL || *eid == '\0' ) return NULL; + + person = addrcache_get_person( cache, uid ); + if( person ) { + email = addritem_person_remove_email_id( person, eid ); + if( email ) { + // Remove email from all groups. + g_hash_table_foreach( cache->itemHash, addrcache_allgrp_rem_email_vis, email ); + + // Remove email from person's address list + if( person->listEMail ) { + person->listEMail = g_list_remove( person->listEMail, email ); + } + // Unlink reference to person. + ADDRITEM_PARENT(email) = NULL; + } + } + return email; +} + +/* +* Remove email address in address cache for specified person. +* param: person Person. +* email EMail to remove. +* return: EMail object, or NULL if not found. Note that object should still be freed. +*/ +ItemEMail *addrcache_person_remove_email( AddressCache *cache, ItemPerson *person, ItemEMail *email ) { + ItemEMail *found = NULL; + g_return_if_fail( cache != NULL ); + if( person && email ) { + found = addritem_person_remove_email( person, email ); + if( found ) { + // Remove email from all groups. + g_hash_table_foreach( cache->itemHash, addrcache_allgrp_rem_email_vis, email ); + + // Remove email from person's address list + if( person->listEMail ) { + person->listEMail = g_list_remove( person->listEMail, email ); + } + // Unlink reference to person. + ADDRITEM_PARENT(email) = NULL; + } + } + return found; +} + +/* +* Return link list of address items for root level folder. Note that the list contains +* references to items and should be g_free() when done. Do *NOT* attempt to use the +* addrcache_free_xxx() functions... this will destroy the address cache data! +* Return: List of items, or NULL if none. +*/ +GList *addrcache_folder_get_address_list( AddressCache *cache, ItemFolder *folder ) { + GList *list = NULL; + GList *node = NULL; + ItemFolder *f = folder; + g_return_if_fail( cache != NULL ); + + if( ! f ) f = cache->rootFolder; + node = f->listPerson; + while( node ) { + list = g_list_append( list, node->data ); + node = g_list_next( node ); + } + node = f->listGroup; + while( node ) { + list = g_list_append( list, node->data ); + node = g_list_next( node ); + } + return list; +} + +/* +* Return link list of persons for specified folder. Note that the list contains +* references to items and should be g_free() when done. Do *NOT* attempt to use the +* addrcache_free_xxx() functions... this will destroy the address cache data! +* Return: List of items, or NULL if none. +*/ +GList *addrcache_folder_get_person_list( AddressCache *cache, ItemFolder *folder ) { + GList *list = NULL; + GList *node = NULL; + ItemFolder *f = folder; + g_return_if_fail( cache != NULL ); + + if( ! f ) f = cache->rootFolder; + return addritem_folder_get_person_list( f ); +} + +/* +* Return link list of group items for specified folder. Note that the list contains +* references to items and should be g_free() when done. Do *NOT* attempt to use the +* addrcache_free_xxx() functions... this will destroy the address cache data! +* Return: List of items, or NULL if none. +*/ +GList *addrcache_folder_get_group_list( AddressCache *cache, ItemFolder *folder ) { + GList *node = NULL; + GList *list = NULL; + ItemFolder *f = folder; + g_return_if_fail( cache != NULL ); + if( ! f ) f = cache->rootFolder; + return addritem_folder_get_group_list( f ); +} + +/* +* Return link list of folder items for specified folder. Note that the list contains +* references to items and should be g_free() when done. Do *NOT* attempt to used the +* addrcache_free_xxx() functions... this will destroy the address cache data! +* Return: List of items, or NULL if none. +*/ +GList *addrcache_folder_get_folder_list( AddressCache *cache, ItemFolder *folder ) { + GList *node = NULL; + GList *list = NULL; + ItemFolder *f = folder; + g_return_if_fail( cache != NULL ); + if( ! f ) f = cache->rootFolder; + node = f->listFolder; + while( node ) { + list = g_list_append( list, node->data ); + node = g_list_next( node ); + } + return list; +} + +/* +* Return link list of address items for root level folder. Note that the list contains +* references to items and should be g_free() when done. Do *NOT* attempt to used the +* addrcache_free_xxx() functions... this will destroy the address cache data! +* Return: List of items, or NULL if none. +*/ +GList *addrcache_get_address_list( AddressCache *cache ) { + GList *list = NULL; + g_return_if_fail( cache != NULL ); + return addrcache_folder_get_address_list( cache, cache->rootFolder ); +} + +/* +* Return link list of persons for root level folder. Note that the list contains +* references to items and should be g_free() when done. Do *NOT* attempt to used the +* addrcache_free_xxx() functions... this will destroy the address cache data! +* Return: List of items, or NULL if none. +*/ +GList *addrcache_get_person_list( AddressCache *cache ) { + g_return_if_fail( cache != NULL ); + return addritem_folder_get_person_list( cache->rootFolder ); +} + +/* +* Return link list of group items in root level folder. Note that the list contains +* references to items and should be g_free() when done. Do *NOT* attempt to used the +* addrcache_free_xxx() functions... this will destroy the address cache data! +* Return: List of items, or NULL if none. +*/ +GList *addrcache_get_group_list( AddressCache *cache ) { + g_return_if_fail( cache != NULL ); + return cache->rootFolder->listGroup; +} + +/* +* Return link list of folder items in root level folder. Note that the list contains +* references to items and should be g_free() when done. Do *NOT* attempt to used the +* addrcache_free_xxx() functions... this will destroy the address cache data! +* Return: List of items, or NULL if none. +*/ +GList *addrcache_get_folder_list( AddressCache *cache ) { + g_return_if_fail( cache != NULL ); + return cache->rootFolder->listFolder; +} + +/* +* Group visitor function. +*/ +static void addrcache_get_grp_person_vis( gpointer key, gpointer value, gpointer data ) { + AddrItemObject *obj = ( AddrItemObject * ) value; + if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) { + AddressCache *cache = data; + ItemGroup *group = ( ItemGroup * ) obj; + ItemPerson *person = ( ItemPerson * ) cache->tempList->data; + GList *node = group->listEMail; + while( node ) { + ItemEMail *email = ( ItemEMail * ) node->data; + if( ADDRITEM_PARENT(email) == ADDRITEM_OBJECT(person) ) { + if( ! g_list_find( cache->tempList, group ) ) { + cache->tempList = g_list_append( cache->tempList, group ); + } + } + node = g_list_next( node ); + } + } +} + +/* +* Return link list of groups which contain a reference to specified person's email +* address. +*/ +GList *addrcache_get_group_for_person( AddressCache *cache, ItemPerson *person ) { + GList *list = NULL; + g_return_if_fail( cache != NULL ); + cache->tempList = NULL; + cache->tempList = g_list_append( cache->tempList, person ); + g_hash_table_foreach( cache->itemHash, addrcache_get_grp_person_vis, cache ); + cache->tempList = g_list_remove( cache->tempList, person ); + list = cache->tempList; + cache->tempList = NULL; + return list; +} + +/* +* Find root folder for specified folder. +* Enter: folder Folder to search. +* Return: root folder, or NULL if not found. +*/ +ItemFolder *addrcache_find_root_folder( ItemFolder *folder ) { + ItemFolder *item = folder; + gint count = 0; + while( item ) { + if( item->isRoot ) break; + if( ++count > ADDRCACHE_MAX_SEARCH_COUNT ) { + item = NULL; + break; + } + item = ( ItemFolder * ) ADDRITEM_PARENT(folder); + } + return item; +} + +/* +* Get all person visitor function. +*/ +static void addrcache_get_all_persons_vis( gpointer key, gpointer value, gpointer data ) { + AddrItemObject *obj = ( AddrItemObject * ) value; + if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) { + AddressCache *cache = data; + cache->tempList = g_list_append( cache->tempList, obj ); + } +} + +/* +* Return link list of all persons in address cache. Note that the list contains +* references to items. Do *NOT* attempt to use the addrcache_free_xxx() functions... +* this will destroy the address cache data! +* Return: List of items, or NULL if none. +*/ +GList *addrcache_get_all_persons( AddressCache *cache ) { + GList *list = NULL; + g_return_if_fail( cache != NULL ); + + cache->tempList = NULL; + g_hash_table_foreach( cache->itemHash, addrcache_get_all_persons_vis, cache ); + list = cache->tempList; + cache->tempList = NULL; + return list; +} + +/* +* Remove folder from cache. Children are re-parented to parent folder. +* param: folder Folder to remove. +* return: Folder, or NULL if not found. Note that object should still be freed. +*/ +ItemFolder *addrcache_remove_folder( AddressCache *cache, ItemFolder *folder ) { + AddrItemObject *obj = NULL; + + g_return_if_fail( cache != NULL ); + if( folder ) { + gchar *uid = ADDRITEM_ID(folder); + if( uid == NULL || *uid == '\0' ) return NULL; + obj = ( AddrItemObject * ) g_hash_table_lookup( cache->itemHash, uid ); + if( obj ) { + ItemFolder *parent = ( ItemFolder * ) ADDRITEM_PARENT(folder); + GList *node; + AddrItemObject *aio; + if( ! parent ) parent = cache->rootFolder; + + // Re-parent children in folder + node = folder->listFolder; + while( node ) { + aio = ( AddrItemObject * ) node->data; + parent->listFolder = g_list_append( parent->listFolder, aio ); + aio->parent = ADDRITEM_OBJECT(parent); + node = g_list_next( node ); + } + node = folder->listPerson; + while( node ) { + aio = ( AddrItemObject * ) node->data; + parent->listPerson = g_list_append( parent->listPerson, aio ); + aio->parent = ADDRITEM_OBJECT(parent); + node = g_list_next( node ); + } + node = folder->listGroup; + while( node ) { + aio = ( AddrItemObject * ) node->data; + parent->listGroup = g_list_append( parent->listGroup, aio ); + aio->parent = ADDRITEM_OBJECT(parent); + node = g_list_next( node ); + } + + // Remove folder from parent's list and hash table + parent->listFolder = g_list_remove( parent->listFolder, folder ); + ADDRITEM_PARENT(folder) = NULL; + g_hash_table_remove( cache->itemHash, uid ); + return folder; + } + } + return NULL; +} + +/* +* Remove folder from cache. Children are deleted. +* param: folder Folder to remove. +* return: Folder, or NULL if not found. Note that object should still be freed. +*/ +ItemFolder *addrcache_remove_folder_delete( AddressCache *cache, ItemFolder *folder ) { + AddrItemObject *obj = NULL; + + g_return_if_fail( cache != NULL ); + if( folder ) { + gchar *uid = ADDRITEM_ID(folder); + if( uid == NULL || *uid == '\0' ) return NULL; + obj = ( AddrItemObject * ) g_hash_table_lookup( cache->itemHash, uid ); + if( obj ) { + ItemFolder *parent = ( ItemFolder * ) ADDRITEM_PARENT(folder); + GList *node; + AddrItemObject *aio; + if( ! parent ) parent = cache->rootFolder; + + // Remove groups + while( folder->listGroup ) { + ItemGroup *item = ( ItemGroup * ) folder->listGroup->data; + item = addrcache_remove_group( cache, item ); + if( item ) { + addritem_free_item_group( item ); + item = NULL; + } + } + + while( folder->listPerson ) { + ItemPerson *item = ( ItemPerson * ) folder->listPerson->data; + item = addrcache_remove_person( cache, item ); + if( item ) { + addritem_free_item_person( item ); + item = NULL; + } + } + + // Recursive deletion of folder + while( folder->listFolder ) { + ItemFolder *item = ( ItemFolder * ) folder->listFolder->data; + item = addrcache_remove_folder_delete( cache, item ); + if( item ) { + addritem_free_item_folder( item ); + item = NULL; + } + } + + // Remove folder from parent's list and hash table + parent->listFolder = g_list_remove( parent->listFolder, folder ); + ADDRITEM_PARENT(folder) = NULL; + g_hash_table_remove( cache->itemHash, uid ); + return folder; + } + } + return NULL; +} + +/* +* Add person and address data to cache. +* Enter: cache Cache. +* folder Folder where to add person, or NULL for root folder. +* name Common name. +* address EMail address. +* remarks Remarks. +* Return: Person added. Do not *NOT* to use the addrbook_free_xxx() functions... +* this will destroy the address book data. +*/ +ItemPerson *addrcache_add_contact( AddressCache *cache, ItemFolder *folder, const gchar *name, + const gchar *address, const gchar *remarks ) +{ + ItemPerson *person = NULL; + ItemEMail *email = NULL; + ItemFolder *f = folder; + + g_return_if_fail( cache != NULL ); + + if( ! f ) f = cache->rootFolder; + + // Create person object + person = addritem_create_item_person(); + addritem_person_set_common_name( person, name ); + addrcache_id_person( cache, person ); + addrcache_folder_add_person( cache, f, person ); + + // Create email object + email = addritem_create_item_email(); + addritem_email_set_address( email, address ); + addritem_email_set_remarks( email, remarks ); + addrcache_id_email( cache, email ); + addritem_person_add_email( person, email ); + + return person; +} + +/* +* End of Source. +*/ + diff --git a/src/addrcache.h b/src/addrcache.h new file mode 100644 index 000000000..2dce5f1a4 --- /dev/null +++ b/src/addrcache.h @@ -0,0 +1,125 @@ +/* + * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client + * Copyright (C) 2001 Match Grun + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ + +/* + * Definitions for address cache. + */ + +#ifndef __ADDRCACHE_H__ +#define __ADDRCACHE_H__ + +#include +#include +#include +#include "addritem.h" + +// Address book file. +typedef struct _AddressCache AddressCache; +struct _AddressCache { + gint nextID; + gboolean dataRead; + gboolean modified; + time_t modifyTime; + GHashTable *itemHash; + GList *tempList; + ItemFolder *rootFolder; +}; + +// Function prototypes +AddressCache *addrcache_create(); +ItemFolder *addrcache_get_root_folder ( AddressCache *cache ); +GList *addrcache_get_list_folder ( AddressCache *cache ); +GList *addrcache_get_list_person ( AddressCache *cache ); + +void addrcache_refresh ( AddressCache *cache ); +void addrcache_empty ( AddressCache *cache ); +void addrcache_free ( AddressCache *cache ); +gboolean addrcache_check_file ( AddressCache *cache, gchar *path ); +gboolean addrcache_mark_file ( AddressCache *cache, gchar *path ); + +void addrcache_print_item_list ( GList *list, FILE *stream ); +void addrcache_print ( AddressCache *cache, FILE *stream ); +void addrcache_dump_hash ( AddressCache *cache, FILE *stream ); + +void addrcache_id_person ( AddressCache *cache, ItemPerson *person ); +void addrcache_id_group ( AddressCache *cache, ItemGroup *group ); +void addrcache_id_folder ( AddressCache *cache, ItemFolder *folder ); +void addrcache_id_email ( AddressCache *cache, ItemEMail *email ); +void addrcache_id_attribute ( AddressCache *cache, UserAttribute *attrib ); + +gboolean addrcache_hash_add_person ( AddressCache *cache, ItemPerson *person ); +gboolean addrcache_hash_add_group ( AddressCache *cache, ItemGroup *group ); +gboolean addrcache_hash_add_folder ( AddressCache *cache, ItemFolder *folder ); + +gboolean addrcache_folder_add_person ( AddressCache *cache, ItemFolder *folder, ItemPerson *item ); +gboolean addrcache_folder_add_folder ( AddressCache *cache, ItemFolder *folder, ItemFolder *item ); +gboolean addrcache_folder_add_group ( AddressCache *cache, ItemFolder *folder, ItemGroup *item ); + +gboolean addrcache_add_person ( AddressCache *cache, ItemPerson *person ); +gboolean addrcache_add_group ( AddressCache *cache, ItemGroup *group ); +gboolean addrcache_person_add_email ( AddressCache *cache, ItemPerson *person, ItemEMail *email ); +gboolean addrcache_group_add_email ( AddressCache *cache, ItemGroup *group, ItemEMail *email ); +gboolean addrcache_add_folder ( AddressCache *cache, ItemFolder *folder ); + +AddrItemObject *addrcache_get_object ( AddressCache *cache, const gchar *uid ); +ItemPerson *addrcache_get_person ( AddressCache *cache, const gchar *uid ); +ItemGroup *addrcache_get_group ( AddressCache *cache, const gchar *uid ); +ItemEMail *addrcache_get_email ( AddressCache *cache, const gchar *uid, const gchar *eid ); + +UserAttribute *addrcache_person_remove_attrib_id ( AddressCache *cache, const gchar *uid, + const gchar *aid ); +UserAttribute *addrcache_person_remove_attribute ( AddressCache *cache, ItemPerson *person, + UserAttribute *attrib ); + +ItemGroup *addrcache_remove_group_id ( AddressCache *cache, const gchar *uid ); +ItemGroup *addrcache_remove_group ( AddressCache *cache, ItemGroup *group ); + +ItemPerson *addrcache_remove_person_id ( AddressCache *cache, const gchar *uid ); +ItemPerson *addrcache_remove_person ( AddressCache *cache, ItemPerson *person ); +ItemEMail *addrcache_person_remove_email_id ( AddressCache *cache, const gchar *uid, const gchar *eid ); +ItemEMail *addrcache_person_remove_email ( AddressCache *cache, ItemPerson *person, ItemEMail *email ); + +GList *addrcache_folder_get_address_list ( AddressCache *cache, ItemFolder *folder ); +GList *addrcache_folder_get_person_list ( AddressCache *cache, ItemFolder *folder ); +GList *addrcache_folder_get_group_list ( AddressCache *cache, ItemFolder *folder ); +GList *addrcache_folder_get_folder_list ( AddressCache *cache, ItemFolder *folder ); + +GList *addrcache_get_address_list ( AddressCache *cache ); +GList *addrcache_get_person_list ( AddressCache *cache ); +GList *addrcache_get_group_list ( AddressCache *cache ); +GList *addrcache_get_folder_list ( AddressCache *cache ); + +GList *addrcache_get_group_for_person ( AddressCache *cache, ItemPerson *person ); + +ItemFolder *addrcache_find_root_folder ( ItemFolder *folder ); +GList *addrcache_get_all_persons ( AddressCache *cache ); + +ItemFolder *addrcache_remove_folder ( AddressCache *cache, ItemFolder *folder ); +ItemFolder *addrcache_remove_folder_delete ( AddressCache *cache, ItemFolder *folder ); + +ItemPerson *addrcache_add_contact ( AddressCache *cache, ItemFolder *folder, + const gchar *name, const gchar *address, + const gchar *remarks ); + +#endif /* __ADDRCACHE_H__ */ + +/* +* End of Source. +*/ + diff --git a/src/addressadd.c b/src/addressadd.c new file mode 100644 index 000000000..dfeaf0d35 --- /dev/null +++ b/src/addressadd.c @@ -0,0 +1,401 @@ +/* + * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client + * Copyright (C) 2001 Match Grun + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ + +/* + * Add address to address book dialog. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "defs.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "intl.h" +#include "gtkutils.h" +#include "prefs_common.h" +#include "addressadd.h" +#include "addritem.h" +#include "addrbook.h" +#include "addrindex.h" + +#include "pixmaps/book.xpm" +#include "pixmaps/dir-open.xpm" + +typedef struct { + AddressBookFile *book; + ItemFolder *folder; +} FolderInfo; + +static struct _AddressAdd_dlg { + GtkWidget *window; + GtkWidget *label_name; + GtkWidget *label_address; + GtkWidget *label_remarks; + GtkWidget *tree_folder; + GtkWidget *ok_btn; + GtkWidget *cancel_btn; + GtkWidget *statusbar; + gint status_cid; + FolderInfo *fiSelected; +} addressadd_dlg; + +static GdkPixmap *folderXpm; +static GdkBitmap *folderXpmMask; +static GdkPixmap *bookXpm; +static GdkBitmap *bookXpmMask; + +static gboolean addressadd_cancelled; + +static FolderInfo *addressadd_create_folderinfo( AddressBookFile *abf, ItemFolder *folder ) +{ + FolderInfo *fi = g_new0( FolderInfo, 1 ); + fi->book = abf; + fi->folder = folder; + return fi; +} + +static void addressadd_free_folderinfo( FolderInfo *fi ) { + fi->book = NULL; + fi->folder = NULL; + g_free( fi ); +} + +/* +* Edit functions. +*/ +static void addressadd_status_show( gchar *msg ) { + if( addressadd_dlg.statusbar != NULL ) { + gtk_statusbar_pop( GTK_STATUSBAR(addressadd_dlg.statusbar), addressadd_dlg.status_cid ); + if( msg ) { + gtk_statusbar_push( GTK_STATUSBAR(addressadd_dlg.statusbar), addressadd_dlg.status_cid, msg ); + } + } +} + +static gint addressadd_delete_event( GtkWidget *widget, GdkEventAny *event, gboolean *cancelled ) { + addressadd_cancelled = TRUE; + gtk_main_quit(); + return TRUE; +} + +static void addressadd_key_pressed( GtkWidget *widget, GdkEventKey *event, gboolean *cancelled ) { + if (event && event->keyval == GDK_Escape) { + addressadd_cancelled = TRUE; + gtk_main_quit(); + } +} + +static void addressadd_ok( GtkWidget *widget, gboolean *cancelled ) { + addressadd_cancelled = FALSE; + gtk_main_quit(); +} + +static void addressadd_cancel( GtkWidget *widget, gboolean *cancelled ) { + addressadd_cancelled = TRUE; + gtk_main_quit(); +} + +static void addressadd_folder_select( GtkCTree *ctree, gint row, gint column, + GdkEvent *event, gpointer data ) +{ + addressadd_dlg.fiSelected = gtk_clist_get_row_data( GTK_CLIST(ctree), row ); +} + +static void addressadd_tree_button( GtkCTree *ctree, GdkEventButton *event, gpointer data ) { + if( ! event ) return; + if( event->button == 1 ) { + // Handle double click + if( event->type == GDK_2BUTTON_PRESS ) { + addressadd_cancelled = FALSE; + gtk_main_quit(); + } + } +} + +static void addressadd_create( void ) { + GtkWidget *window; + GtkWidget *vbox; + GtkWidget *table; + GtkWidget *label; + GtkWidget *label_name; + GtkWidget *label_addr; + GtkWidget *label_rems; + GtkWidget *tree_folder; + GtkWidget *vlbox; + GtkWidget *tree_win; + GtkWidget *hlbox; + GtkWidget *hbbox; + GtkWidget *hsep; + GtkWidget *ok_btn; + GtkWidget *cancel_btn; + GtkWidget *check_btn; + GtkWidget *file_btn; + GtkWidget *hsbox; + GtkWidget *statusbar; + gint top; + + window = gtk_window_new(GTK_WINDOW_DIALOG); + gtk_widget_set_usize( window, 300, 400 ); + gtk_container_set_border_width( GTK_CONTAINER(window), 0 ); + gtk_window_set_title( GTK_WINDOW(window), _("Add Address to Book") ); + gtk_window_set_position( GTK_WINDOW(window), GTK_WIN_POS_MOUSE ); + gtk_window_set_modal( GTK_WINDOW(window), TRUE ); + gtk_signal_connect( GTK_OBJECT(window), "delete_event", + GTK_SIGNAL_FUNC(addressadd_delete_event), NULL ); + gtk_signal_connect( GTK_OBJECT(window), "key_press_event", + GTK_SIGNAL_FUNC(addressadd_key_pressed), NULL ); + + vbox = gtk_vbox_new(FALSE, 8); + gtk_container_add(GTK_CONTAINER(window), vbox); + gtk_container_set_border_width( GTK_CONTAINER(vbox), 0 ); + + table = gtk_table_new(3, 2, FALSE); + gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0); + gtk_container_set_border_width( GTK_CONTAINER(table), 8 ); + gtk_table_set_row_spacings(GTK_TABLE(table), 8); + gtk_table_set_col_spacings(GTK_TABLE(table), 8); + + // First row + top = 0; + label = gtk_label_new(_("Name")); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); + + label_name = gtk_label_new(""); + gtk_table_attach(GTK_TABLE(table), label_name, 1, 2, top, (top + 1), GTK_FILL, 0, 0, 0); + gtk_misc_set_alignment(GTK_MISC(label_name), 0, 0.5); + + // Second row + top = 1; + label = gtk_label_new(_("Address")); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0); + + label_addr = gtk_label_new(""); + gtk_table_attach(GTK_TABLE(table), label_addr, 1, 2, top, (top + 1), GTK_FILL, 0, 0, 0); + gtk_misc_set_alignment(GTK_MISC(label_addr), 0, 0.5); + + // Third row + top = 2; + label = gtk_label_new(_("Remarks")); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); + + label_rems = gtk_label_new(""); + gtk_table_attach(GTK_TABLE(table), label_rems, 1, 2, top, (top + 1), GTK_FILL, 0, 0, 0); + gtk_misc_set_alignment(GTK_MISC(label_rems), 0, 0.5); + + // Address book/folder tree + vlbox = gtk_vbox_new(FALSE, 8); + gtk_box_pack_start(GTK_BOX(vbox), vlbox, TRUE, TRUE, 0); + gtk_container_set_border_width( GTK_CONTAINER(vlbox), 8 ); + + tree_win = gtk_scrolled_window_new( NULL, NULL ); + gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(tree_win), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_ALWAYS ); + gtk_box_pack_start( GTK_BOX(vlbox), tree_win, TRUE, TRUE, 0 ); + + tree_folder = gtk_ctree_new( 1, 0 ); + gtk_container_add( GTK_CONTAINER(tree_win), tree_folder ); + gtk_clist_column_titles_show( GTK_CLIST(tree_folder) ); + gtk_clist_set_column_title( GTK_CLIST(tree_folder), 0, _( "Select Address Book Folder" ) ); + gtk_ctree_set_line_style( GTK_CTREE(tree_folder), GTK_CTREE_LINES_DOTTED ); + gtk_clist_set_selection_mode( GTK_CLIST(tree_folder), GTK_SELECTION_BROWSE ); + gtk_ctree_set_expander_style( GTK_CTREE(tree_folder), GTK_CTREE_EXPANDER_SQUARE ); + gtk_ctree_set_indent( GTK_CTREE(tree_folder), CTREE_INDENT ); + gtk_clist_set_auto_sort( GTK_CLIST(tree_folder), TRUE ); + + // Status line + hsbox = gtk_hbox_new(FALSE, 0); + gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH); + statusbar = gtk_statusbar_new(); + gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH); + + // Button panel + gtkut_button_set_create(&hbbox, &ok_btn, _("OK"), + &cancel_btn, _("Cancel"), NULL, NULL); + gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0); + gtk_container_set_border_width( GTK_CONTAINER(hbbox), 0 ); + gtk_widget_grab_default(ok_btn); + + hsep = gtk_hseparator_new(); + gtk_box_pack_end(GTK_BOX(vbox), hsep, FALSE, FALSE, 0); + + gtk_signal_connect(GTK_OBJECT(ok_btn), "clicked", + GTK_SIGNAL_FUNC(addressadd_ok), NULL); + gtk_signal_connect(GTK_OBJECT(cancel_btn), "clicked", + GTK_SIGNAL_FUNC(addressadd_cancel), NULL); + gtk_signal_connect(GTK_OBJECT(tree_folder), "select_row", + GTK_SIGNAL_FUNC(addressadd_folder_select), NULL); + gtk_signal_connect(GTK_OBJECT(tree_folder), "button_press_event", + GTK_SIGNAL_FUNC(addressadd_tree_button), NULL); + + gtk_widget_show_all(vbox); + + addressadd_dlg.window = window; + addressadd_dlg.label_name = label_name; + addressadd_dlg.label_address = label_addr; + addressadd_dlg.label_remarks = label_rems; + addressadd_dlg.tree_folder = tree_folder; + addressadd_dlg.ok_btn = ok_btn; + addressadd_dlg.cancel_btn = cancel_btn; + addressadd_dlg.statusbar = statusbar; + addressadd_dlg.status_cid = gtk_statusbar_get_context_id( GTK_STATUSBAR(statusbar), "Address Add" ); + + gtk_widget_show_all( window ); + + PIXMAP_CREATE( window, bookXpm, bookXpmMask, book_xpm ); + PIXMAP_CREATE( window, folderXpm, folderXpmMask, DIRECTORY_OPEN_XPM ); +} + +static void addressadd_load_folder( GtkCTreeNode *parentNode, ItemFolder *parentFolder, + FolderInfo *fiParent ) +{ + GtkCTree *tree = GTK_CTREE( addressadd_dlg.tree_folder ); + GList *list; + ItemFolder *folder; + gchar *fName; + gchar **name; + GtkCTreeNode *node; + FolderInfo *fi; + + list = parentFolder->listFolder; + while( list ) { + folder = list->data; + fName = g_strdup( ADDRITEM_NAME(folder) ); + name = &fName; + node = gtk_ctree_insert_node( tree, parentNode, NULL, name, FOLDER_SPACING, + folderXpm, folderXpmMask, folderXpm, folderXpmMask, + FALSE, TRUE ); + g_free( fName ); + fi = addressadd_create_folderinfo( fiParent->book, folder ); + gtk_ctree_node_set_row_data_full( tree, node, fi, + ( GtkDestroyNotify ) addressadd_free_folderinfo ); + addressadd_load_folder( node, folder, fi ); + list = g_list_next( list ); + } +} + +static void addressadd_load_data( AddressIndex *addrIndex ) { + AddressDataSource *ds; + GList *list, *nodeDS; + gchar **name; + gchar *dsName; + ItemFolder *rootFolder; + AddressBookFile *abf; + FolderInfo *fi; + GtkCTree *tree = GTK_CTREE( addressadd_dlg.tree_folder ); + GtkCTreeNode *node; + + gtk_clist_clear( GTK_CLIST( tree ) ); + list = addrindex_get_interface_list( addrIndex ); + while( list ) { + AddressInterface *interface = list->data; + if( interface->type == ADDR_IF_BOOK ) { + nodeDS = interface->listSource; + while( nodeDS ) { + ds = nodeDS->data; + dsName = g_strdup( addrindex_ds_get_name( ds ) ); + + // Read address book + if( ! addrindex_ds_get_read_flag( ds ) ) { + addrindex_ds_read_data( ds ); + } + + // Add node for address book + abf = ds->rawDataSource; + name = &dsName; + node = gtk_ctree_insert_node( tree, NULL, NULL, + name, FOLDER_SPACING, bookXpm, + bookXpmMask, bookXpm, bookXpmMask, + FALSE, TRUE ); + g_free( dsName ); + + fi = addressadd_create_folderinfo( abf, NULL ); + gtk_ctree_node_set_row_data_full( tree, node, fi, + ( GtkDestroyNotify ) addressadd_free_folderinfo ); + + rootFolder = addrindex_ds_get_root_folder( ds ); + addressadd_load_folder( node, rootFolder, fi ); + + nodeDS = g_list_next( nodeDS ); + } + } + list = g_list_next( list ); + } +} + +gboolean addressadd_selection( AddressIndex *addrIndex, const gchar *name, const gchar *address, const gchar *remarks ) { + gboolean retVal = FALSE; + ItemPerson *person = NULL; + + addressadd_cancelled = FALSE; + if( ! addressadd_dlg.window ) addressadd_create(); + gtk_widget_grab_focus(addressadd_dlg.ok_btn); + gtk_widget_show(addressadd_dlg.window); + manage_window_set_transient(GTK_WINDOW(addressadd_dlg.window)); + + addressadd_dlg.fiSelected = NULL; + addressadd_status_show( "" ); + addressadd_load_data( addrIndex ); + gtk_clist_select_row( GTK_CLIST( addressadd_dlg.tree_folder ), 0, 0 ); + gtk_widget_show(addressadd_dlg.window); + + gtk_label_set_text( GTK_LABEL(addressadd_dlg.label_name ), "" ); + gtk_label_set_text( GTK_LABEL(addressadd_dlg.label_address ), "" ); + gtk_label_set_text( GTK_LABEL(addressadd_dlg.label_remarks ), "" ); + if( name ) + gtk_label_set_text( GTK_LABEL(addressadd_dlg.label_name ), name ); + if( address ) + gtk_label_set_text( GTK_LABEL(addressadd_dlg.label_address ), address ); + if( remarks ) + gtk_label_set_text( GTK_LABEL(addressadd_dlg.label_remarks ), remarks ); + + gtk_main(); + gtk_widget_hide( addressadd_dlg.window ); + + if( ! addressadd_cancelled ) { + if( addressadd_dlg.fiSelected ) { + FolderInfo *fi = addressadd_dlg.fiSelected; + person = addrbook_add_contact( fi->book, fi->folder, name, address, remarks ); + if( person ) retVal = TRUE; + } + } + + gtk_clist_clear( GTK_CLIST( addressadd_dlg.tree_folder ) ); + + return retVal; +} + +/* +* End of Source. +*/ + diff --git a/src/addressadd.h b/src/addressadd.h new file mode 100644 index 000000000..20e90fc72 --- /dev/null +++ b/src/addressadd.h @@ -0,0 +1,37 @@ +/* + * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client + * Copyright (C) 2001 Match Grun + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ + +/* + * Add address to address book dialog. + */ + +#ifndef __ADDRESS_ADD_H__ +#define __ADDRESS_ADD_H__ + +#include "addrindex.h" + +// Function prototypes +gboolean addressadd_selection( AddressIndex *addrIndex, const gchar *name, const gchar *address, const gchar *remarks ); + +#endif /* __ADDRESS_ADD_H__ */ + +/* +* End of Source. +*/ + diff --git a/src/addressbook.c b/src/addressbook.c index 53ee29965..becf2ecfa 100644 --- a/src/addressbook.c +++ b/src/addressbook.c @@ -61,9 +61,17 @@ #include "about.h" #include "addr_compl.h" +#include "mgutils.h" #include "addressitem.h" +#include "addritem.h" +#include "addrcache.h" +#include "addrbook.h" +#include "addrindex.h" #include "vcard.h" #include "editvcard.h" +#include "editgroup.h" +#include "editaddress.h" +#include "editbook.h" #ifdef USE_JPILOT #include "jpilot.h" @@ -75,34 +83,19 @@ #include "syldap.h" #include "editldap.h" -// Interval to check for LDAP search results -// #define ADDRESSBOOK_LDAP_TIMER_INTERVAL 100 -#define ADDRESSBOOK_LDAP_BUSYMSG "Busy" - +#define ADDRESSBOOK_LDAP_BUSYMSG "Busy" #endif #include "pixmaps/dir-close.xpm" #include "pixmaps/dir-open.xpm" #include "pixmaps/group.xpm" +#include "pixmaps/interface.xpm" +#include "pixmaps/book.xpm" +#include "pixmaps/address.xpm" #include "pixmaps/vcard.xpm" -#ifdef USE_JPILOT #include "pixmaps/jpilot.xpm" #include "pixmaps/category.xpm" -#endif -#ifdef USE_LDAP #include "pixmaps/ldap.xpm" -#endif - -// XML tag names for top level folders -#define ADDRESS_TAG_COMMON "common_address" -#define ADDRESS_TAG_PERSONAL "personal_address" -#define ADDRESS_TAG_VCARD "vcard_list" -#ifdef USE_JPILOT -#define ADDRESS_TAG_JPILOT "jpilot_list" -#endif -#ifdef USE_LDAP -#define ADDRESS_TAG_LDAP "ldap_list" -#endif typedef enum { @@ -112,7 +105,7 @@ typedef enum } AddressBookColumnPos; #define N_COLS 3 -#define COL_NAME_WIDTH 144 +#define COL_NAME_WIDTH 164 #define COL_ADDRESS_WIDTH 156 #define COL_FOLDER_WIDTH 170 @@ -127,6 +120,12 @@ static GdkPixmap *folderopenxpm; static GdkBitmap *folderopenxpmmask; static GdkPixmap *groupxpm; static GdkBitmap *groupxpmmask; +static GdkPixmap *interfacexpm; +static GdkBitmap *interfacexpmmask; +static GdkPixmap *bookxpm; +static GdkBitmap *bookxpmmask; +static GdkPixmap *addressxpm; +static GdkBitmap *addressxpmmask; static GdkPixmap *vcardxpm; static GdkBitmap *vcardxpmmask; #ifdef USE_JPILOT @@ -140,28 +139,24 @@ static GdkPixmap *ldapxpm; static GdkBitmap *ldapxpmmask; #endif -// Pilot library indicator (set at run-time) -static _have_pilot_library_; - -// LDAP library indicator (set at run-time) -static _have_ldap_library_; - // Message buffer static gchar addressbook_msgbuf[ ADDRESSBOOK_MSGBUF_SIZE ]; -static AddressBook addrbook; +// Address list selection +static GList *_addressListSelection_ = NULL; -static struct _AddressEdit -{ - GtkWidget *window; - GtkWidget *name_entry; - GtkWidget *addr_entry; - GtkWidget *rem_entry; - GtkWidget *ok_btn; - GtkWidget *cancel_btn; -} addredit; - -static void addressbook_create (gboolean show); +// Address index file and interfaces +static AddressIndex *_addressIndex_ = NULL; +static GList *_addressInterfaceList_ = NULL; +static GList *_addressIFaceSelection_ = NULL; +#define ADDRESSBOOK_IFACE_SELECTION "1/y,3/y,4/y,2/n" + +static AddressBook_win addrbook; + +static GHashTable *_addressBookTypeHash_ = NULL; +static GList *_addressBookTypeList_ = NULL; + +static void addressbook_create ( void ); static gint addressbook_close (void); static void addressbook_button_set_sensitive (void); @@ -184,6 +179,20 @@ static void addressbook_list_selected (GtkCList *clist, gint column, GdkEvent *event, gpointer data); +static void addressbook_list_row_selected (GtkCTree *clist, + GtkCTreeNode *node, + gint column, + gpointer data); +static void addressbook_list_row_unselected (GtkCTree *clist, + GtkCTreeNode *node, + gint column, + gpointer data); +static void addressbook_person_expand_node (GtkCTree *ctree, + GList *node, + gpointer *data ); +static void addressbook_person_collapse_node (GtkCTree *ctree, + GList *node, + gpointer *data ); static void addressbook_entry_gotfocus (GtkWidget *widget); #if 0 @@ -211,29 +220,15 @@ static void addressbook_new_folder_cb (gpointer data, static void addressbook_new_group_cb (gpointer data, guint action, GtkWidget *widget); -static void addressbook_edit_folder_cb (gpointer data, +static void addressbook_treenode_edit_cb (gpointer data, guint action, GtkWidget *widget); -static void addressbook_delete_folder_cb (gpointer data, +static void addressbook_treenode_delete_cb (gpointer data, guint action, GtkWidget *widget); static void addressbook_change_node_name (GtkCTreeNode *node, const gchar *name); -static void addressbook_edit_group (GtkCTreeNode *group_node); - -static void addressbook_edit_address_create (gboolean *cancelled); -static void edit_address_ok (GtkWidget *widget, - gboolean *cancelled); -static void edit_address_cancel (GtkWidget *widget, - gboolean *cancelled); -static gint edit_address_delete_event (GtkWidget *widget, - GdkEventAny *event, - gboolean *cancelled); -static void edit_address_key_pressed (GtkWidget *widget, - GdkEventKey *event, - gboolean *cancelled); -static AddressItem *addressbook_edit_address (AddressItem *item); static void addressbook_new_address_cb (gpointer data, guint action, @@ -248,58 +243,62 @@ static void addressbook_delete_address_cb (gpointer data, static void close_cb (gpointer data, guint action, GtkWidget *widget); +static void addressbook_file_save_cb (gpointer data, + guint action, + GtkWidget *widget); -// VCard edit stuff +// Data source edit stuff +static void addressbook_new_book_cb ( gpointer data, + guint action, + GtkWidget *widget ); static void addressbook_new_vcard_cb ( gpointer data, guint action, GtkWidget *widget ); #ifdef USE_JPILOT -// JPilot edit stuff static void addressbook_new_jpilot_cb ( gpointer data, guint action, GtkWidget *widget ); #endif #ifdef USE_LDAP -// LDAP edit stuff static void addressbook_new_ldap_cb ( gpointer data, guint action, GtkWidget *widget ); #endif -static AddressItem *addressbook_parse_address (const gchar *str); -static void addressbook_append_to_compose_entry (AddressItem *item, - ComposeEntryType type); - static void addressbook_set_clist (AddressObject *obj); -static void addressbook_read_file (void); -static void addressbook_get_tree (XMLFile *file, - GtkCTreeNode *node, - const gchar *folder_tag); -static void addressbook_add_objs (XMLFile *file, - GtkCTreeNode *node); +static void addressbook_load_tree (void); +void addressbook_read_file (void); static GtkCTreeNode *addressbook_add_object (GtkCTreeNode *node, AddressObject *obj); -static void addressbook_delete_object (AddressObject *obj); -static AddressObject *addressbook_find_object_by_name +static AddressDataSource *addressbook_find_datasource + (GtkCTreeNode *node ); + +static AddressBookFile *addressbook_get_book_file(); + +static GtkCTreeNode *addressbook_node_add_folder (GtkCTreeNode *node, - const gchar *name); + AddressDataSource *ds, + ItemFolder *itemFolder, + AddressObjectType otype ); +static GtkCTreeNode *addressbook_node_add_group (GtkCTreeNode *node, + AddressDataSource *ds, + ItemGroup *itemGroup ); +static GtkCTreeNode *addressbook_node_add_category + (GtkCTreeNode *node, + AddressDataSource *ds, + ItemFolder *itemFolder ); +static void addressbook_tree_remove_children (GtkCTree *ctree, + GtkCTreeNode *parent ); +static void addressbook_move_nodes_up (GtkCTree *ctree, + GtkCTreeNode *node ); +static GtkCTreeNode *addressbook_find_group_node (GtkCTreeNode *parent, + ItemGroup *group ); -static AddressItem *addressbook_parse_item (XMLFile *file); -static void addressbook_xml_recursive_write (GtkCTreeNode *node, - FILE *fp); -static void addressbook_node_write_begin (GtkCTreeNode *node, - FILE *fp); -static void addressbook_node_write_end (GtkCTreeNode *node, - FILE *fp); -static void addressbook_write_items (FILE *fp, - GList *items, - guint level); -static void tab_indent_out (FILE *fp, - guint level); +static void addressbook_delete_object (AddressObject *obj); static void key_pressed (GtkWidget *widget, GdkEventKey *event, @@ -307,67 +306,89 @@ static void key_pressed (GtkWidget *widget, static gint addressbook_list_compare_func (GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2); -static gint addressbook_obj_name_compare (gconstpointer a, - gconstpointer b); +//static gint addressbook_obj_name_compare (gconstpointer a, +// gconstpointer b); -static AddressVCard *addressbook_parse_vcard ( XMLFile *file ); -static void addressbook_write_vcard ( FILE *fp, - AddressVCard *vcard, - guint level ); +static void addressbook_book_show_message ( AddressBookFile *book ); static void addressbook_vcard_show_message ( VCardFile *vcf ); - #ifdef USE_JPILOT -static AddressJPilot *addressbook_parse_jpilot ( XMLFile *file ); -static void addressbook_write_jpilot ( FILE *fp, - AddressJPilot *jpilot, - guint level ); static void addressbook_jpilot_show_message ( JPilotFile *jpf ); #endif #ifdef USE_LDAP -static AddressLDAP *addressbook_parse_ldap ( XMLFile *file ); -static void addressbook_write_ldap ( FILE *fp, - AddressLDAP *ldapi, - guint level ); static void addressbook_ldap_show_message ( SyldapServer *server ); #endif +// LUT's and IF stuff +static void addressbook_free_adapter ( GtkCTreeNode *node ); +static void addressbook_free_child_adapters ( GtkCTreeNode *node ); +AddressTypeControlItem *addrbookctl_lookup ( gint ot ); +AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ); + +void addrbookctl_build_map ( GtkWidget *window ); +void addrbookctl_build_iflist ( void ); +AdapterInterface *addrbookctl_find_interface ( AddressIfType ifType ); +void addrbookctl_build_ifselect(); + +static void addrbookctl_free_interface ( AdapterInterface *adapter ); +static void addrbookctl_free_datasource ( AdapterDSource *adapter ); +static void addrbookctl_free_folder ( AdapterFolder *adapter ); +static void addrbookctl_free_group ( AdapterGroup *adapter ); + +static void addressbook_list_select_clear ( void ); +static void addressbook_list_select_add ( AddressObject *obj ); +static void addressbook_list_select_remove ( AddressObject *obj ); + static GtkItemFactoryEntry addressbook_entries[] = { - {N_("/_File"), NULL, NULL, 0, ""}, - {N_("/_File/New _Address"), "N", addressbook_new_address_cb, 0, NULL}, - {N_("/_File/New _Group"), "G", addressbook_new_group_cb, 0, NULL}, - {N_("/_File/New _Folder"), "R", addressbook_new_folder_cb, 0, NULL}, - {N_("/_File/New _V-Card"), "D", addressbook_new_vcard_cb, 0, NULL}, + {N_("/_File"), NULL, NULL, 0, ""}, + {N_("/_File/New _Book"), "B", addressbook_new_book_cb, 0, NULL}, + {N_("/_File/New _V-Card"), "D", addressbook_new_vcard_cb, 0, NULL}, #ifdef USE_JPILOT - {N_("/_File/New _J-Pilot"), "J", addressbook_new_jpilot_cb, 0, NULL}, + {N_("/_File/New _J-Pilot"), "J", addressbook_new_jpilot_cb, 0, NULL}, #endif #ifdef USE_LDAP - {N_("/_File/New _Server"), "S", addressbook_new_ldap_cb, 0, NULL}, -#endif - {N_("/_File/---"), NULL, NULL, 0, ""}, - {N_("/_File/_Edit"), "Return", addressbook_edit_address_cb, 0, NULL}, - {N_("/_File/_Delete"), NULL, addressbook_delete_address_cb, 0, NULL}, - {N_("/_File/---"), NULL, NULL, 0, ""}, - {N_("/_File/_Close"), "W", close_cb, 0, NULL}, - {N_("/_Help"), NULL, NULL, 0, ""}, - {N_("/_Help/_About"), NULL, about_show, 0, NULL} + {N_("/_File/New _Server"), "S", addressbook_new_ldap_cb, 0, NULL}, +#endif + {N_("/_File/---"), NULL, NULL, 0, ""}, + {N_("/_File/_Edit"), NULL, addressbook_treenode_edit_cb, 0, NULL}, + {N_("/_File/_Delete"), NULL, addressbook_treenode_delete_cb, 0, NULL}, + {N_("/_File/---"), NULL, NULL, 0, ""}, + {N_("/_File/_Save"), "V", addressbook_file_save_cb, 0, NULL}, + {N_("/_File/_Close"), "W", close_cb, 0, NULL}, + {N_("/_Address"), NULL, NULL, 0, ""}, + {N_("/_Address/New _Address"), "N", addressbook_new_address_cb, 0, NULL}, + {N_("/_Address/New _Group"), "G", addressbook_new_group_cb, 0, NULL}, + {N_("/_Address/New _Folder"), "R", addressbook_new_folder_cb, 0, NULL}, + {N_("/_Address/---"), NULL, NULL, 0, ""}, + {N_("/_Address/_Edit"), "Return", addressbook_edit_address_cb, 0, NULL}, + {N_("/_Address/_Delete"), NULL, addressbook_delete_address_cb, 0, NULL}, + {N_("/_Help"), NULL, NULL, 0, ""}, + {N_("/_Help/_About"), NULL, about_show, 0, NULL} }; +// New options to be added. +/* + {N_("/_Edit"), NULL, NULL, 0, ""}, + {N_("/_Edit/C_ut"), "X", NULL, 0, NULL}, + {N_("/_Edit/_Copy"), "C", NULL, 0, NULL}, + {N_("/_Edit/_Paste"), "V", NULL, 0, NULL}, + {N_("/_Tools"), NULL, NULL, 0, ""}, + {N_("/_Tools/Import _Mozilla"), NULL, NULL, 0, NULL}, + {N_("/_Tools/Import _LDIF"), NULL, NULL, 0, NULL}, + {N_("/_Tools/Import _V-Card"), NULL, NULL, 0, NULL}, + {N_("/_Tools/---"), NULL, NULL, 0, ""}, + {N_("/_Tools/Export _LDIF"), NULL, NULL, 0, NULL}, + {N_("/_Tools/Export V-_Card"), NULL, NULL, 0, NULL}, +*/ + static GtkItemFactoryEntry addressbook_tree_popup_entries[] = { {N_("/New _Address"), NULL, addressbook_new_address_cb, 0, NULL}, {N_("/New _Group"), NULL, addressbook_new_group_cb, 0, NULL}, {N_("/New _Folder"), NULL, addressbook_new_folder_cb, 0, NULL}, - {N_("/New _V-Card"), NULL, addressbook_new_vcard_cb, 0, NULL}, -#ifdef USE_JPILOT - {N_("/New _J-Pilot"), NULL, addressbook_new_jpilot_cb, 0, NULL}, -#endif -#ifdef USE_LDAP - {N_("/New _Server"), NULL, addressbook_new_ldap_cb, 0, NULL}, -#endif {N_("/---"), NULL, NULL, 0, ""}, - {N_("/_Edit"), NULL, addressbook_edit_folder_cb, 0, NULL}, - {N_("/_Delete"), NULL, addressbook_delete_folder_cb, 0, NULL} + {N_("/_Edit"), NULL, addressbook_treenode_edit_cb, 0, NULL}, + {N_("/_Delete"), NULL, addressbook_treenode_delete_cb, 0, NULL} }; static GtkItemFactoryEntry addressbook_list_popup_entries[] = @@ -383,12 +404,13 @@ static GtkItemFactoryEntry addressbook_list_popup_entries[] = void addressbook_open(Compose *target) { if (!addrbook.window) { - addressbook_create(TRUE); addressbook_read_file(); - addrbook.open_folder = TRUE; + addressbook_create(); + addressbook_load_tree(); gtk_ctree_select(GTK_CTREE(addrbook.ctree), GTK_CTREE_NODE(GTK_CLIST(addrbook.ctree)->row_list)); - } else + } + gtk_widget_hide(addrbook.window); gtk_widget_show_all(addrbook.window); @@ -408,8 +430,31 @@ Compose *addressbook_get_target_compose(void) return addrbook.target_compose; } -static void addressbook_create(gboolean show) -{ +void addressbook_refresh( void ) { + if( addrbook.window ) { + if( addrbook.treeSelected ) { + gtk_ctree_select( GTK_CTREE(addrbook.ctree), addrbook.treeSelected ); + } + } + addressbook_export_to_file(); +} + +/* +* Create the address book widgets. The address book contains two CTree widgets: the +* address index tree on the left and the address list on the right. +* +* The address index tree displays a hierarchy of interfaces and groups. Each node in +* this tree is linked to an address Adapter. Adapters have been created for interfaces, +* data sources and folder objects. +* +* The address list displays group, person and email objects. These items are linked +* directly to ItemGroup, ItemPerson and ItemEMail objects inside the address book data +* sources. +* +* In the tradition of MVC architecture, the data stores have been separated from the +* GUI components. The addrindex.c file provides the interface to all data stores. +*/ +static void addressbook_create( void ) { GtkWidget *window; GtkWidget *vbox; GtkWidget *menubar; @@ -439,6 +484,9 @@ static void addressbook_create(gboolean show) GtkItemFactory *list_factory; GtkItemFactory *menu_factory; gint n_entries; + GList *nodeIf; + AdapterInterface *adapter; + AddressTypeControlItem *atci; gchar *titles[N_COLS] = {_("Name"), _("E-Mail address"), _("Remarks")}; gchar *text; @@ -446,14 +494,10 @@ static void addressbook_create(gboolean show) debug_print("Creating addressbook window...\n"); - // Global flag if we have library installed (at run-time) - _have_pilot_library_ = FALSE; - _have_ldap_library_ = FALSE; - window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(window), _("Address book")); gtk_widget_set_usize(window, ADDRESSBOOK_WIDTH, ADDRESSBOOK_HEIGHT); - //gtk_container_set_border_width(GTK_CONTAINER(window), BORDER_WIDTH); + gtk_container_set_border_width(GTK_CONTAINER(window), BORDER_WIDTH); gtk_window_set_policy(GTK_WINDOW(window), TRUE, TRUE, TRUE); gtk_widget_realize(window); @@ -486,6 +530,7 @@ static void addressbook_create(gboolean show) GTK_POLICY_ALWAYS); gtk_widget_set_usize(ctree_swin, COL_FOLDER_WIDTH + 40, -1); + // Address index ctree = gtk_ctree_new(1, 0); gtk_container_add(GTK_CONTAINER(ctree_swin), ctree); gtk_clist_set_selection_mode(GTK_CLIST(ctree), GTK_SELECTION_BROWSE); @@ -514,9 +559,13 @@ static void addressbook_create(gboolean show) GTK_POLICY_ALWAYS); gtk_box_pack_start(GTK_BOX(clist_vbox), clist_swin, TRUE, TRUE, 0); - clist = gtk_clist_new_with_titles(N_COLS, titles); + // Address list + clist = gtk_ctree_new_with_titles(N_COLS, 0, titles); gtk_container_add(GTK_CONTAINER(clist_swin), clist); gtk_clist_set_selection_mode(GTK_CLIST(clist), GTK_SELECTION_EXTENDED); + gtk_ctree_set_line_style(GTK_CTREE(clist), GTK_CTREE_LINES_DOTTED); + gtk_ctree_set_expander_style(GTK_CTREE(clist), GTK_CTREE_EXPANDER_SQUARE); + gtk_ctree_set_indent(GTK_CTREE(clist), CTREE_INDENT); gtk_clist_set_column_width(GTK_CLIST(clist), COL_NAME, COL_NAME_WIDTH); gtk_clist_set_column_width(GTK_CLIST(clist), COL_ADDRESS, @@ -528,14 +577,22 @@ static void addressbook_create(gboolean show) GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(clist)->column[i].button, GTK_CAN_FOCUS); - gtk_signal_connect(GTK_OBJECT(clist), "select_row", - GTK_SIGNAL_FUNC(addressbook_list_selected), NULL); + gtk_signal_connect(GTK_OBJECT(clist), "tree_select_row", + GTK_SIGNAL_FUNC(addressbook_list_row_selected), NULL); + gtk_signal_connect(GTK_OBJECT(clist), "tree_unselect_row", + GTK_SIGNAL_FUNC(addressbook_list_row_unselected), NULL); gtk_signal_connect(GTK_OBJECT(clist), "button_press_event", GTK_SIGNAL_FUNC(addressbook_list_button_pressed), NULL); gtk_signal_connect(GTK_OBJECT(clist), "button_release_event", GTK_SIGNAL_FUNC(addressbook_list_button_released), NULL); + gtk_signal_connect(GTK_OBJECT(clist), "select_row", + GTK_SIGNAL_FUNC(addressbook_list_selected), NULL); + gtk_signal_connect(GTK_OBJECT(clist), "tree_expand", + GTK_SIGNAL_FUNC(addressbook_person_expand_node), NULL ); + gtk_signal_connect(GTK_OBJECT(clist), "tree_collapse", + GTK_SIGNAL_FUNC(addressbook_person_collapse_node), NULL ); hbox = gtk_hbox_new(FALSE, 4); gtk_box_pack_start(GTK_BOX(clist_vbox), hbox, FALSE, FALSE, 0); @@ -612,77 +669,32 @@ static void addressbook_create(gboolean show) GTK_SIGNAL_FUNC(addressbook_to_clicked), GINT_TO_POINTER(COMPOSE_BCC)); - PIXMAP_CREATE(window, folderxpm, folderxpmmask, DIRECTORY_CLOSE_XPM); - PIXMAP_CREATE(window, folderopenxpm, folderopenxpmmask, - DIRECTORY_OPEN_XPM); - PIXMAP_CREATE(window, groupxpm, groupxpmmask, group_xpm); - PIXMAP_CREATE(window, vcardxpm, vcardxpmmask, vcard_xpm); -#ifdef USE_JPILOT - PIXMAP_CREATE(window, jpilotxpm, jpilotxpmmask, jpilot_xpm); - PIXMAP_CREATE(window, categoryxpm, categoryxpmmask, category_xpm); -#endif -#ifdef USE_LDAP - PIXMAP_CREATE(window, ldapxpm, ldapxpmmask, ldap_xpm); -#endif - - text = _("Common address"); - addrbook.common = - gtk_ctree_insert_node(GTK_CTREE(ctree), - NULL, NULL, &text, FOLDER_SPACING, - folderxpm, folderxpmmask, - folderopenxpm, folderopenxpmmask, - FALSE, FALSE); - text = _("Personal address"); - addrbook.personal = - gtk_ctree_insert_node(GTK_CTREE(ctree), - NULL, NULL, &text, FOLDER_SPACING, - folderxpm, folderxpmmask, - folderopenxpm, folderopenxpmmask, - FALSE, FALSE); - - text = _("V-Card"); - addrbook.vcard = - gtk_ctree_insert_node(GTK_CTREE(ctree), - NULL, NULL, &text, FOLDER_SPACING, - folderxpm, folderxpmmask, - folderopenxpm, folderopenxpmmask, - FALSE, FALSE); - -#ifdef USE_JPILOT - text = _("J-Pllot"); - addrbook.jpilot = - gtk_ctree_insert_node(GTK_CTREE(ctree), - NULL, NULL, &text, FOLDER_SPACING, - folderxpm, folderxpmmask, - folderopenxpm, folderopenxpmmask, - FALSE, FALSE); - if( jpilot_test_pilot_lib() ) { - _have_pilot_library_ = TRUE; - menu_set_sensitive( menu_factory, "/File/New J-Pilot", TRUE ); - } - else { - menu_set_sensitive( menu_factory, "/File/New J-Pilot", FALSE ); - } -#endif - -#ifdef USE_LDAP - text = _("Directory"); - addrbook.ldap = - gtk_ctree_insert_node(GTK_CTREE(ctree), - NULL, NULL, &text, FOLDER_SPACING, - folderxpm, folderxpmmask, - folderopenxpm, folderopenxpmmask, - FALSE, FALSE); - if( syldap_test_ldap_lib() ) { - _have_ldap_library_ = TRUE; - menu_set_sensitive( menu_factory, "/File/New Server", TRUE ); - } - else { - menu_set_sensitive( menu_factory, "/File/New Server", FALSE ); - } -#endif - - /* popup menu */ + // Build icons for interface + PIXMAP_CREATE( window, interfacexpm, interfacexpmmask, interface_xpm ); + + // Build control tables + addrbookctl_build_map( window ); + addrbookctl_build_iflist(); + addrbookctl_build_ifselect(); + + // Add each interface into the tree as a root level folder + nodeIf = _addressInterfaceList_; + while( nodeIf ) { + adapter = nodeIf->data; + nodeIf = g_list_next( nodeIf ); + atci = adapter->atci; + text = atci->displayName; + adapter->treeNode = + gtk_ctree_insert_node( GTK_CTREE(ctree), + NULL, NULL, &text, FOLDER_SPACING, + interfacexpm, interfacexpmmask, + interfacexpm, interfacexpmmask, + FALSE, FALSE ); + menu_set_sensitive( menu_factory, atci->menuCommand, adapter->haveLibrary ); + gtk_ctree_node_set_row_data( GTK_CTREE(ctree), adapter->treeNode, adapter ); + } + + // Popup menu n_entries = sizeof(addressbook_tree_popup_entries) / sizeof(addressbook_tree_popup_entries[0]); tree_popup = menu_create_items(addressbook_tree_popup_entries, @@ -719,18 +731,16 @@ static void addressbook_create(gboolean show) addrbook.list_factory = list_factory; addrbook.menu_factory = menu_factory; + addrbook.listSelected = NULL; address_completion_start(window); + gtk_widget_show_all(window); - if (show) - gtk_widget_show_all(window); } static gint addressbook_close(void) { gtk_widget_hide(addrbook.window); addressbook_export_to_file(); - /* tell addr_compl that there's a new addressbook file */ - invalidate_address_completion(); return TRUE; } @@ -743,6 +753,30 @@ static void addressbook_status_show( gchar *msg ) { } } +static void addressbook_ds_show_message( AddressDataSource *ds ) { + gint retVal; + gchar *name; + *addressbook_msgbuf = '\0'; + if( ds ) { + name = addrindex_ds_get_name( ds ); + retVal = addrindex_ds_get_status_code( ds ); + if( retVal == MGU_SUCCESS ) { + if( ds ) { + sprintf( addressbook_msgbuf, "%s", name ); + } + } + else { + if( ds == NULL ) { + sprintf( addressbook_msgbuf, "%s", mgu_error2string( retVal ) ); + } + else { + sprintf( addressbook_msgbuf, "%s: %s", name, mgu_error2string( retVal ) ); + } + } + } + addressbook_status_show( addressbook_msgbuf ); +} + static void addressbook_button_set_sensitive(void) { gboolean to_sens = FALSE; @@ -763,217 +797,206 @@ static void addressbook_button_set_sensitive(void) gtk_widget_set_sensitive(addrbook.bcc_btn, bcc_sens); } +/* +* Delete one or more objects from address list. +*/ static void addressbook_del_clicked(GtkButton *button, gpointer data) { - GtkCList *clist = GTK_CLIST(addrbook.clist); + GtkCTree *clist = GTK_CTREE(addrbook.clist); GtkCTree *ctree = GTK_CTREE(addrbook.ctree); AddressObject *pobj, *obj; - GList *cur, *next; - gint row; - gboolean remFlag; - - if (!clist->selection) { - addressbook_delete_folder_cb(NULL, 0, NULL); - return; - } + AdapterDSource *ads = NULL; + GtkCTreeNode *nodeList; + gboolean remFlag, procFlag; + AlertValue aval; + AddressBookFile *abf = NULL; + AddressDataSource *ds = NULL; - pobj = gtk_ctree_node_get_row_data(ctree, addrbook.opened); + pobj = gtk_ctree_node_get_row_data(ctree, addrbook.opened ); g_return_if_fail(pobj != NULL); - if (alertpanel(_("Delete address(es)"), - _("Really delete the address(es)?"), - _("Yes"), _("No"), NULL) != G_ALERTDEFAULT) - return; + nodeList = addrbook.listSelected; + obj = gtk_ctree_node_get_row_data( clist, nodeList ); + if( obj == NULL) return; + ds = addressbook_find_datasource( addrbook.treeSelected ); + if( ds == NULL ) return; - for (cur = clist->selection; cur != NULL; cur = next) { - next = cur->next; - row = GPOINTER_TO_INT(cur->data); - remFlag = FALSE; + procFlag = FALSE; + if( pobj->type == ADDR_DATASOURCE ) { + ads = ADAPTER_DSOURCE(pobj); + if( ads->subType == ADDR_BOOK ) procFlag = TRUE; + } + else if( pobj->type == ADDR_ITEM_FOLDER ) { + procFlag = TRUE; + } + else if( pobj->type == ADDR_ITEM_GROUP ) { + procFlag = TRUE; + } + if( ! procFlag ) return; + abf = ds->rawDataSource; + if( abf == NULL ) return; - obj = gtk_clist_get_row_data(clist, row); - if (!obj) continue; + // Confirm deletion + aval = alertpanel( _("Delete address(es)"), + _("Really delete the address(es)?"), + _("Yes"), _("No"), NULL ); + if( aval != G_ALERTDEFAULT ) return; - if (pobj->type == ADDR_GROUP) { - AddressGroup *group = ADDRESS_GROUP(pobj); - group->items = g_list_remove(group->items, obj); - } else if (pobj->type == ADDR_FOLDER) { - AddressFolder *folder = ADDRESS_FOLDER(pobj); + // Process deletions + if( pobj->type == ADDR_DATASOURCE || pobj->type == ADDR_ITEM_FOLDER ) { + // Items inside folders + GList *node; + node = _addressListSelection_; + while( node ) { + AddrItemObject *aio = node->data; + node = g_list_next( node ); + if( aio->type == ADDR_ITEM_GROUP ) { + ItemGroup *item = ( ItemGroup * ) aio; + GtkCTreeNode *nd = NULL; - folder->items = g_list_remove(folder->items, obj); - if (obj->type == ADDR_GROUP) { - remFlag = TRUE; - } - else if (obj->type == ADDR_VCARD) { - remFlag = TRUE; + nd = addressbook_find_group_node( addrbook.opened, item ); + item = addrbook_remove_group( abf, item ); + if( item ) { + addritem_free_item_group( item ); + item = NULL; + } + // Remove group from parent node + gtk_ctree_remove_node( ctree, nd ); } - else if (obj->type == ADDR_JPILOT) { - remFlag = TRUE; + else if( aio->type == ADDR_ITEM_PERSON ) { + ItemPerson *item = ( ItemPerson * ) aio; + item = addrbook_remove_person( abf, item ); + if( item ) { + addritem_free_item_person( item ); + item = NULL; + } } - else if (obj->type == ADDR_LDAP) { - remFlag = TRUE; + else if( aio->type == ADDR_ITEM_EMAIL ) { + ItemEMail *item = ( ItemEMail * ) aio; + ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item); + item = addrbook_person_remove_email( abf, person, item ); + if( item ) { + addritem_free_item_email( item ); + item = NULL; + } } - - if( remFlag ) { - GtkCTreeNode *node; - node = gtk_ctree_find_by_row_data - (ctree, addrbook.opened, obj); - if (node) gtk_ctree_remove_node(ctree, node); + } + addressbook_list_select_clear(); + gtk_ctree_select( ctree, addrbook.opened); + return; + } + else if( pobj->type == ADDR_ITEM_GROUP ) { + // Items inside groups + GList *node; + node = _addressListSelection_; + while( node ) { + AddrItemObject *aio = node->data; + node = g_list_next( node ); + if( aio->type == ADDR_ITEM_EMAIL ) { + ItemEMail *item = ( ItemEMail * ) aio; + ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item); + item = addrbook_person_remove_email( abf, person, item ); + if( item ) { + addritem_print_item_email( item, stdout ); + addritem_free_item_email( item ); + item = NULL; + } } - } else - continue; + } + addressbook_list_select_clear(); + gtk_ctree_select( ctree, addrbook.opened); + return; + } - addressbook_delete_object(obj); + gtk_ctree_node_set_row_data( clist, nodeList, NULL ); + gtk_ctree_remove_node( clist, nodeList ); + addressbook_list_select_remove( obj ); - gtk_clist_remove(clist, row); - } } static void addressbook_reg_clicked(GtkButton *button, gpointer data) { - GtkCTree *ctree = GTK_CTREE(addrbook.ctree); - GtkEntry *entry = GTK_ENTRY(addrbook.entry); - AddressObject *obj; - AddressItem *item; - gchar *str; - - if (*gtk_entry_get_text(entry) == '\0') { - addressbook_new_address_cb(NULL, 0, NULL); - return; - } - if (!addrbook.opened) return; - - obj = gtk_ctree_node_get_row_data(ctree, addrbook.opened); - if (!obj) return; + addressbook_new_address_cb( NULL, 0, NULL ); +} - g_return_if_fail(obj->type == ADDR_GROUP || obj->type == ADDR_FOLDER); +gchar *addressbook_format_address( AddressObject * obj ) { + gchar *buf = NULL; + gchar *name = NULL; + gchar *address = NULL; - str = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1); + if( obj->type == ADDR_ITEM_EMAIL ) { + ItemPerson *person = NULL; + ItemEMail *email = ( ItemEMail * ) obj; - item = addressbook_parse_address(str); - g_free(str); - if (item) { - if (addressbook_find_object_by_name - (addrbook.opened, item->name) != NULL) { - addressbook_delete_object(ADDRESS_OBJECT(item)); - item = NULL; - } else if (addressbook_edit_address(item) == NULL) { - addressbook_delete_object(ADDRESS_OBJECT(item)); - return; + person = ( ItemPerson * ) ADDRITEM_PARENT(email); + if( email->address ) { + if( ADDRITEM_NAME(email) ) { + name = ADDRITEM_NAME(email); + if( *name == '\0' ) { + name = ADDRITEM_NAME(person); + } + } + else if( ADDRITEM_NAME(person) ) { + name = ADDRITEM_NAME(person); + } + else { + buf = g_strdup( email->address ); + } + address = email->address; } } + else if( obj->type == ADDR_ITEM_PERSON ) { + ItemPerson *person = ( ItemPerson * ) obj; + GList *node = person->listEMail; - if (!item) { - item = addressbook_edit_address(NULL); - if (!item) return; - } - - if (addressbook_find_object_by_name(addrbook.opened, item->name)) { - addressbook_delete_object(ADDRESS_OBJECT(item)); - return; + name = ADDRITEM_NAME(person); + if( node ) { + ItemEMail *email = ( ItemEMail * ) node->data; + address = email->address; + } } - - addressbook_add_object(addrbook.opened, ADDRESS_OBJECT(item)); - addrbook.open_folder = TRUE; - gtk_ctree_select(GTK_CTREE(addrbook.ctree), addrbook.opened); -} - -static AddressItem *addressbook_parse_address(const gchar *str) -{ - gchar *name = NULL; - gchar *address = NULL; - AddressItem *item; - gchar *buf; - gchar *start, *end; - - Xalloca(buf, strlen(str) + 1, return NULL); - - strcpy(buf, str); - g_strstrip(buf); - if (*buf == '\0') return NULL; - - if ((start = strchr(buf, '<'))) { - if (start > buf) { - *start = '\0'; - g_strstrip(buf); - if (*buf != '\0') - name = g_strdup(buf); + if( address ) { + if( name ) { + buf = g_strdup_printf( "%s <%s>", name, address ); } - start++; - if ((end = strchr(start, '>'))) { - *end = '\0'; - g_strstrip(start); - if (*start != '\0') - address = g_strdup(start); + else { + buf = g_strdup( address ); } - } else - name = g_strdup(buf); - - if (!name && !address) return NULL; - - item = mgu_create_address(); - ADDRESS_OBJECT_TYPE(item) = ADDR_ITEM; - item->name = name; - item->address = address; - item->remarks = NULL; + } - return item; + return buf; } static void addressbook_to_clicked(GtkButton *button, gpointer data) { - GtkCList *clist = GTK_CLIST(addrbook.clist); - GList *cur; - + GList *node = _addressListSelection_; if (!addrbook.target_compose) return; - - for (cur = clist->selection; cur != NULL; cur = cur->next) { - AddressObject *obj; - - obj = gtk_clist_get_row_data(clist, - GPOINTER_TO_INT(cur->data)); - if (!obj) return; - - if (obj->type == ADDR_ITEM) { - addressbook_append_to_compose_entry - (ADDRESS_ITEM(obj), (ComposeEntryType)data); - } else if (obj->type == ADDR_GROUP) { - AddressGroup *group; - GList *cur_item; - - group = ADDRESS_GROUP(obj); - for (cur_item = group->items; cur_item != NULL; - cur_item = cur_item->next) { - if (ADDRESS_OBJECT(cur_item->data)->type - != ADDR_ITEM) - continue; - addressbook_append_to_compose_entry - (ADDRESS_ITEM(cur_item->data), - (ComposeEntryType)data); + while( node ) { + AddressObject *obj = node->data; + Compose *compose = addrbook.target_compose; + node = g_list_next( node ); + if( obj->type == ADDR_ITEM_PERSON || obj->type == ADDR_ITEM_EMAIL ) { + gchar *addr = addressbook_format_address( obj ); + compose_entry_append( compose, addr, (ComposeEntryType) data ); + g_free( addr ); + addr = NULL; + } + else if( obj->type == ADDR_ITEM_GROUP ) { + ItemGroup *group = ( ItemGroup * ) obj; + GList *nodeMail = group->listEMail; + while( nodeMail ) { + ItemEMail *email = nodeMail->data; + gchar *addr = addressbook_format_address( ( AddressObject * ) email ); + compose_entry_append( compose, addr, (ComposeEntryType) data ); + g_free( addr ); + nodeMail = g_list_next( nodeMail ); } } } } -static void addressbook_append_to_compose_entry(AddressItem *item, - ComposeEntryType type) -{ - Compose *compose = addrbook.target_compose; - - if (item->name && item->address) { - gchar *buf; - - buf = g_strdup_printf - ("%s <%s>", item->name, item->address); - compose_entry_append(compose, buf, type); - g_free(buf); - } else if (item->address) - compose_entry_append(compose, item->address, type); -} - static void addressbook_menubar_set_sensitive( gboolean sensitive ) { - menu_set_sensitive( addrbook.menu_factory, "/File/New Address", sensitive ); - menu_set_sensitive( addrbook.menu_factory, "/File/New Group", sensitive ); - menu_set_sensitive( addrbook.menu_factory, "/File/New Folder", sensitive ); + menu_set_sensitive( addrbook.menu_factory, "/File/New Book", sensitive ); menu_set_sensitive( addrbook.menu_factory, "/File/New V-Card", sensitive ); #ifdef USE_JPILOT menu_set_sensitive( addrbook.menu_factory, "/File/New J-Pilot", sensitive ); @@ -981,356 +1004,320 @@ static void addressbook_menubar_set_sensitive( gboolean sensitive ) { #ifdef USE_LDAP menu_set_sensitive( addrbook.menu_factory, "/File/New Server", sensitive ); #endif + menu_set_sensitive( addrbook.menu_factory, "/File/Edit", sensitive ); + menu_set_sensitive( addrbook.menu_factory, "/File/Delete", sensitive ); + + menu_set_sensitive( addrbook.menu_factory, "/Address/New Address", sensitive ); + menu_set_sensitive( addrbook.menu_factory, "/Address/New Group", sensitive ); + menu_set_sensitive( addrbook.menu_factory, "/Address/New Folder", sensitive ); gtk_widget_set_sensitive( addrbook.reg_btn, sensitive ); gtk_widget_set_sensitive( addrbook.del_btn, sensitive ); } static void addressbook_menuitem_set_sensitive( AddressObject *obj, GtkCTreeNode *node ) { - gboolean canEdit = TRUE; - if( obj->type == ADDR_FOLDER ) { - if( node == addrbook.common ) { - canEdit = FALSE; + gboolean canEdit = FALSE; + gboolean canAdd = FALSE; + gboolean canEditTr = TRUE; + gboolean editAddress = FALSE; + AddressTypeControlItem *atci = NULL; + AddressDataSource *ds = NULL; + AddressInterface *iface = NULL; + + if( obj == NULL ) return; + if( obj->type == ADDR_INTERFACE ) { + AdapterInterface *adapter = ADAPTER_INTERFACE(obj); + iface = adapter->interface; + if( iface ) { + if( iface->haveLibrary ) { + // Enable appropriate File / New command + atci = adapter->atci; + menu_set_sensitive( addrbook.menu_factory, atci->menuCommand, TRUE ); + } } - if( node == addrbook.personal ) { - canEdit = FALSE; + canEditTr = FALSE; + } + else if( obj->type == ADDR_DATASOURCE ) { + AdapterDSource *ads = ADAPTER_DSOURCE(obj); + ds = ads->dataSource; + iface = ds->interface; + if( ! iface->readOnly ) { + canAdd = canEdit = editAddress = TRUE; } - if( node == addrbook.vcard ) { - canEdit = FALSE; - menu_set_sensitive( addrbook.menu_factory, "/File/New V-Card", TRUE ); + if( ! iface->haveLibrary ) { + canAdd = canEdit = editAddress = FALSE; } -#ifdef USE_JPILOT - else if( node == addrbook.jpilot ) { - canEdit = FALSE; - if( _have_pilot_library_ ) { - menu_set_sensitive( addrbook.menu_factory, "/File/New J-Pilot", TRUE ); + } + else if( obj->type == ADDR_ITEM_FOLDER ) { + ds = addressbook_find_datasource( addrbook.treeSelected ); + if( ds ) { + iface = ds->interface; + if( ! iface->readOnly ) { + canAdd = editAddress = TRUE; } } -#endif -#ifdef USE_LDAP - else if( node == addrbook.ldap ) { - canEdit = FALSE; - if( _have_ldap_library_ ) { - menu_set_sensitive( addrbook.menu_factory, "/File/New Server", TRUE ); + } + else if( obj->type == ADDR_ITEM_GROUP ) { + ds = addressbook_find_datasource( addrbook.treeSelected ); + if( ds ) { + iface = ds->interface; + if( ! iface->readOnly ) { + editAddress = TRUE; } } -#endif - else { - menu_set_sensitive( addrbook.menu_factory, "/File/New Address", TRUE ); - menu_set_sensitive( addrbook.menu_factory, "/File/New Group", TRUE ); - menu_set_sensitive( addrbook.menu_factory, "/File/New Folder", TRUE ); - gtk_widget_set_sensitive( addrbook.reg_btn, TRUE ); - gtk_widget_set_sensitive( addrbook.del_btn, TRUE ); - } - } - else if( obj->type == ADDR_GROUP ) { - menu_set_sensitive( addrbook.menu_factory, "/File/New Address", TRUE ); - gtk_widget_set_sensitive( addrbook.reg_btn, TRUE ); - gtk_widget_set_sensitive( addrbook.del_btn, TRUE ); - } -#ifdef USE_JPILOT - else if( obj->type == ADDR_JPILOT ) { - if( ! _have_pilot_library_ ) canEdit = FALSE; - } - else if( obj->type == ADDR_CATEGORY ) { - canEdit = FALSE; - } -#endif -#ifdef USE_LDAP - else if( obj->type == ADDR_LDAP ) { - if( ! _have_ldap_library_ ) canEdit = FALSE; } -#endif - menu_set_sensitive( addrbook.menu_factory, "/File/Edit", canEdit ); - menu_set_sensitive( addrbook.menu_factory, "/File/Delete", canEdit ); + + if( addrbook.listSelected == NULL ) canEdit = FALSE; + + // Enable add + menu_set_sensitive( addrbook.menu_factory, "/Address/New Address", editAddress ); + menu_set_sensitive( addrbook.menu_factory, "/Address/New Group", canAdd ); + menu_set_sensitive( addrbook.menu_factory, "/Address/New Folder", canAdd ); + gtk_widget_set_sensitive( addrbook.reg_btn, editAddress ); + + // Enable edit + menu_set_sensitive( addrbook.menu_factory, "/Address/Edit", canEdit ); + menu_set_sensitive( addrbook.menu_factory, "/Address/Delete", canEdit ); + gtk_widget_set_sensitive( addrbook.del_btn, canEdit ); + + menu_set_sensitive( addrbook.menu_factory, "/File/Edit", canEditTr ); + menu_set_sensitive( addrbook.menu_factory, "/File/Delete", canEditTr ); } static void addressbook_tree_selected(GtkCTree *ctree, GtkCTreeNode *node, gint column, gpointer data) { - AddressObject *obj; + AddressObject *obj = NULL; + AdapterDSource *ads = NULL; + AddressDataSource *ds = NULL; + ItemFolder *rootFolder = NULL; - addrbook.selected = node; - addrbook.open_folder = FALSE; + addrbook.treeSelected = node; + addrbook.listSelected = NULL; addressbook_status_show( "" ); - if( addrbook.entry != NULL ) { - gtk_entry_set_text(GTK_ENTRY(addrbook.entry), ""); - } + if( addrbook.entry != NULL ) gtk_entry_set_text(GTK_ENTRY(addrbook.entry), ""); - obj = gtk_ctree_node_get_row_data(ctree, node); + if( addrbook.clist ) gtk_clist_clear( GTK_CLIST(addrbook.clist) ); + if( node ) obj = gtk_ctree_node_get_row_data( ctree, node ); if( obj == NULL ) return; addrbook.opened = node; - if( obj->type == ADDR_GROUP || obj->type == ADDR_FOLDER || - obj->type == ADDR_VCARD || obj->type == ADDR_JPILOT || - obj->type == ADDR_CATEGORY || obj->type == ADDR_LDAP ) { - addressbook_set_clist(obj); - } - - if( obj->type == ADDR_VCARD ) { + if( obj->type == ADDR_DATASOURCE ) { // Read from file - VCardFile *vcf; - vcf = ADDRESS_VCARD(obj)->cardFile; - vcard_read_data( vcf ); - addressbook_vcard_show_message( vcf ); - ADDRESS_VCARD(obj)->items = vcard_get_address_list( vcf ); - addressbook_set_clist( obj ); - } -#ifdef USE_JPILOT - else if( obj->type == ADDR_JPILOT ) { - if( _have_pilot_library_ ) { - // Read from file - JPilotFile *jpf; - GList *catList, *catNode; - AddressCategory *acat; - GtkCTreeNode *childNode, *nextNode; - GtkCTreeRow *currRow; - - jpf = ADDRESS_JPILOT(obj)->pilotFile; - addressbook_jpilot_show_message( jpf ); - if( jpilot_get_modified( jpf ) ) { - jpilot_read_data( jpf ); - catList = jpilot_get_category_items( jpf ); - - // Remove existing categories - currRow = GTK_CTREE_ROW( node ); - if( currRow ) { - while( nextNode = currRow->children ) { - gtk_ctree_remove_node( ctree, nextNode ); - } - } + static gboolean tVal = TRUE; - // Load new categories into the tree. - catNode = catList; - while( catNode ) { - AddressItem *item = catNode->data; - acat = g_new(AddressCategory, 1); - ADDRESS_OBJECT_TYPE(acat) = ADDR_CATEGORY; - acat->name = g_strdup( item->name ); - acat->items = NULL; - acat->pilotFile = jpf; - acat->category = item; - catNode = g_list_next( catNode ); - addressbook_add_object(node, ADDRESS_OBJECT(acat)); - } + ads = ADAPTER_DSOURCE(obj); + if( ads == NULL ) return; + ds = ads->dataSource; + if( ds == NULL ) return; - ADDRESS_JPILOT(obj)->items = catList; - } - addressbook_set_clist( obj ); + if( addrindex_ds_get_modify_flag( ds ) ) { + addrindex_ds_read_data( ds ); } - } - else if( obj->type == ADDR_CATEGORY ) { - if( _have_pilot_library_ ) { - // Read from file - JPilotFile *jpf; - jpf = ADDRESS_JPILOT(obj)->pilotFile; - if( jpilot_get_modified( jpf ) ) { - // Force parent to be reloaded - gtk_ctree_select( GTK_CTREE(addrbook.ctree), GTK_CTREE_ROW(node)->parent); - gtk_ctree_expand( GTK_CTREE(addrbook.ctree), GTK_CTREE_ROW(node)->parent); + if( ! addrindex_ds_get_read_flag( ds ) ) { + addrindex_ds_read_data( ds ); + } + addressbook_ds_show_message( ds ); + + if( ! addrindex_ds_get_access_flag( ds ) ) { + // Remove existing folders and groups + gtk_clist_freeze( GTK_CLIST(ctree) ); + addressbook_tree_remove_children( ctree, node ); + gtk_clist_thaw( GTK_CLIST(ctree) ); + + // Load folders into the tree + rootFolder = addrindex_ds_get_root_folder( ds ); + if( ds->type == ADDR_IF_JPILOT ) { + addressbook_node_add_folder( node, ds, rootFolder, ADDR_CATEGORY ); } else { - AddressItem *item = NULL; - AddressCategory *acat = ADDRESS_CATEGORY(obj); - if( acat ) item = acat->category; - if( item ) { - ADDRESS_CATEGORY(obj)->items = - jpilot_get_address_list_cat( jpf, item->categoryID ); - } - addressbook_set_clist( obj ); - } - } - } -#endif -#ifdef USE_LDAP - else if( obj->type == ADDR_LDAP ) { - if( _have_ldap_library_ ) { - // Read from cache - SyldapServer *server; - server = ADDRESS_LDAP(obj)->ldapServer; - addressbook_ldap_show_message( server ); - if( ! server->busyFlag ) { - ADDRESS_LDAP(obj)->items = syldap_get_address_list( server ); - addressbook_set_clist( obj ); + addressbook_node_add_folder( node, ds, rootFolder, ADDR_ITEM_FOLDER ); } + addrindex_ds_set_access_flag( ds, &tVal ); + gtk_ctree_expand( ctree, node ); } } -#endif + + // Update address list + addressbook_set_clist( obj ); // Setup main menu selections addressbook_menubar_set_sensitive( FALSE ); addressbook_menuitem_set_sensitive( obj, node ); + + addressbook_list_select_clear(); + } static void addressbook_list_selected(GtkCList *clist, gint row, gint column, GdkEvent *event, gpointer data) { - GtkEntry *entry = GTK_ENTRY(addrbook.entry); - AddressObject *obj; - GList *cur; - if (event && event->type == GDK_2BUTTON_PRESS) { + // Handle double click if (prefs_common.add_address_by_click && addrbook.target_compose) addressbook_to_clicked(NULL, NULL); else addressbook_edit_address_cb(NULL, 0, NULL); - return; } +} -#if 0 - gtk_signal_handler_block_by_func - (GTK_OBJECT(entry), - GTK_SIGNAL_FUNC(addressbook_entry_changed), NULL); -#endif - - gtk_entry_set_text(entry, ""); - - for (cur = clist->selection; cur != NULL; cur = cur->next) { - obj = gtk_clist_get_row_data(clist, - GPOINTER_TO_INT(cur->data)); - g_return_if_fail(obj != NULL); - - if (obj->type == ADDR_ITEM) { - AddressItem *item; - - item = ADDRESS_ITEM(obj); - if (item->name && item->address) { - gchar *buf; - - buf = g_strdup_printf - ("%s <%s>", item->name, item->address); - if (*gtk_entry_get_text(entry) != '\0') - gtk_entry_append_text(entry, ", "); - gtk_entry_append_text(entry, buf); - g_free(buf); - } else if (item->address) { - if (*gtk_entry_get_text(entry) != '\0') - gtk_entry_append_text(entry, ", "); - gtk_entry_append_text(entry, item->address); +static void addressbook_list_select_show() { + GList *node = _addressListSelection_; + gchar *addr = NULL; + printf( "show selection...>>>\n" ); + while( node != NULL ) { + AddressObject *obj = ( AddressObject * ) node->data; + if( obj ) { + printf( "- %d : '%s'\n", obj->type, obj->name ); + if( obj->type == ADDR_ITEM_GROUP ) { + ItemGroup *group = ( ItemGroup * ) obj; + GList *node = group->listEMail; + while( node ) { + ItemEMail *email = node->data; + addr = addressbook_format_address( ( AddressObject * ) email ); + if( addr ) { + printf( "\tgrp >%s<\n", addr ); + g_free( addr ); + } + node = g_list_next( node ); + } + } + else { + addr = addressbook_format_address( obj ); + if( addr ) { + printf( "\t>%s<\n", addr ); + g_free( addr ); + } } } + else { + printf( "- NULL" ); + } + node = g_list_next( node ); } - -#if 0 - gtk_signal_handler_unblock_by_func - (GTK_OBJECT(entry), - GTK_SIGNAL_FUNC(addressbook_entry_changed), NULL); -#endif + printf( "show selection...<<<\n" ); } -#if 0 -static void addressbook_entry_changed(GtkWidget *widget) -{ - GtkCList *clist = GTK_CLIST(addrbook.clist); - GtkEntry *entry = GTK_ENTRY(addrbook.entry); - const gchar *str; - gint len; - gint row; - - //if (clist->selection && clist->selection->next) return; - - str = gtk_entry_get_text(entry); - if (*str == '\0') { - gtk_clist_unselect_all(clist); - return; +static void addressbook_list_select_clear() { + if( _addressListSelection_ ) { + g_list_free( _addressListSelection_ ); } - len = strlen(str); - - for (row = 0; row < clist->rows; row++) { - AddressObject *obj; - const gchar *name; - - obj = ADDRESS_OBJECT(gtk_clist_get_row_data(clist, row)); - if (!obj) continue; - if (obj->type == ADDR_ITEM) - name = ADDRESS_ITEM(obj)->name; - else if (obj->type == ADDR_GROUP) - name = ADDRESS_GROUP(obj)->name; - else - continue; + _addressListSelection_ = NULL; +} - if (name && !strncasecmp(name, str, len)) { - gtk_clist_unselect_all(clist); - gtk_clist_select_row(clist, row, -1); - return; +static void addressbook_list_select_add( AddressObject *obj ) { + GList *node; + if( obj ) { + if( obj->type == ADDR_ITEM_PERSON || + obj->type == ADDR_ITEM_EMAIL || + obj->type == ADDR_ITEM_GROUP ) { + if( ! g_list_find( _addressListSelection_, obj ) ) { + _addressListSelection_ = g_list_append( _addressListSelection_, obj ); + } } } - - gtk_clist_unselect_all(clist); + // addressbook_list_select_show(); } -#endif -static void addressbook_entry_gotfocus( GtkWidget *widget ) { - gtk_editable_select_region( GTK_EDITABLE(addrbook.entry), 0, -1 ); +static void addressbook_list_select_remove( AddressObject *obj ) { + if( obj == NULL ) return; + if( _addressListSelection_ ) { + _addressListSelection_ = g_list_remove( _addressListSelection_, obj ); + } + // addressbook_list_select_show(); } -static void addressbook_list_button_pressed(GtkWidget *widget, - GdkEventButton *event, - gpointer data) -{ - GtkCList *clist = GTK_CLIST(widget); - gint row, column; - gint tRow, tCol; - AddressObject *obj, *pobj; - - if (!event) return; - - obj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), - addrbook.opened); - g_return_if_fail(obj != NULL); - - pobj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), addrbook.selected); - if( pobj ) { - if( pobj->type == ADDR_VCARD || - pobj->type == ADDR_JPILOT || - pobj->type == ADDR_CATEGORY || - pobj->type == ADDR_LDAP ) { - menu_set_sensitive(addrbook.menu_factory, "/File/Edit", FALSE); - menu_set_sensitive(addrbook.menu_factory, "/File/Delete", FALSE); +static void addressbook_list_row_selected( GtkCTree *clist, GtkCTreeNode *node, gint column, gpointer data ) { + GtkEntry *entry = GTK_ENTRY(addrbook.entry); + AddressObject *obj = NULL; + AddressObject *pobj = NULL; + AdapterDSource *ads = NULL; + AddressInterface *iface = NULL; + AddressDataSource *ds = NULL; + gboolean canEdit = FALSE; + gboolean canDelete = FALSE; + + gtk_entry_set_text( entry, "" ); + addrbook.listSelected = node; + obj = gtk_ctree_node_get_row_data( clist, node ); + if( obj != NULL ) { + // printf( "list select: %d : '%s'\n", obj->type, obj->name ); + addressbook_list_select_add( obj ); + } + + pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected ); + if( pobj == NULL ) return; + + menu_set_insensitive_all( GTK_MENU_SHELL(addrbook.list_popup) ); + + if( pobj->type == ADDR_DATASOURCE ) { + ads = ADAPTER_DSOURCE(pobj); + ds = ads->dataSource; + iface = ds->interface; + if( ! iface->readOnly ) { + canEdit = TRUE; + menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE ); + menu_set_sensitive( addrbook.list_factory, "/New Folder", TRUE ); + menu_set_sensitive( addrbook.list_factory, "/New Group", TRUE ); + gtk_widget_set_sensitive( addrbook.reg_btn, TRUE ); + } + } + else if( pobj->type != ADDR_INTERFACE ) { + ds = addressbook_find_datasource( addrbook.treeSelected ); + iface = ds->interface; + if( ! iface->readOnly ) { + if( pobj->type == ADDR_ITEM_FOLDER || pobj->type == ADDR_ITEM_GROUP ) { + canEdit = TRUE; + menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE ); + gtk_widget_set_sensitive( addrbook.reg_btn, TRUE ); + } + if( pobj->type == ADDR_ITEM_FOLDER ) { + canEdit = TRUE; + menu_set_sensitive( addrbook.list_factory, "/New Folder", TRUE ); + menu_set_sensitive( addrbook.list_factory, "/New Group", TRUE ); + } } } + if( obj == NULL ) canEdit = FALSE; + canDelete = canEdit; + if( GTK_CLIST(clist)->selection && GTK_CLIST(clist)->selection->next ) canEdit = FALSE; - if (event->button != 3) return; - menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.list_popup)); + menu_set_sensitive( addrbook.list_factory, "/Edit", canEdit ); + menu_set_sensitive( addrbook.list_factory, "/Delete", canDelete ); - if (gtk_clist_get_selection_info - (clist, event->x, event->y, &row, &column)) { - GtkCListRow *clist_row; + menu_set_sensitive( addrbook.menu_factory, "/Address/Edit", canEdit ); + menu_set_sensitive( addrbook.menu_factory, "/Address/Delete", canDelete ); - clist_row = g_list_nth(clist->row_list, row)->data; - if (clist_row->state != GTK_STATE_SELECTED) { - gtk_clist_unselect_all(clist); - gtk_clist_select_row(clist, row, column); - } - gtkut_clist_set_focus_row(clist, row); + gtk_widget_set_sensitive( addrbook.del_btn, canDelete ); - if( obj->type != ADDR_VCARD && - obj->type != ADDR_JPILOT && - obj->type != ADDR_CATEGORY && - obj->type != ADDR_LDAP ) { - menu_set_sensitive(addrbook.list_factory, "/Edit", TRUE); - menu_set_sensitive(addrbook.list_factory, "/Delete", TRUE); - } +} + +static void addressbook_list_row_unselected( GtkCTree *clist, GtkCTreeNode *node, gint column, gpointer data ) { + GtkEntry *entry = GTK_ENTRY(addrbook.entry); + AddressObject *obj; + + obj = gtk_ctree_node_get_row_data( clist, node ); + if( obj != NULL ) { + // printf( "list unselect: %d : '%s'\n", obj->type, obj->name ); + addressbook_list_select_remove( obj ); } +} - if( !( addrbook.opened == addrbook.vcard || - addrbook.opened == addrbook.jpilot || - addrbook.opened == addrbook.ldap ) ) { +static void addressbook_entry_gotfocus( GtkWidget *widget ) { + gtk_editable_select_region( GTK_EDITABLE(addrbook.entry), 0, -1 ); +} - if( obj->type == ADDR_FOLDER || obj->type == ADDR_GROUP ) { - menu_set_sensitive(addrbook.list_factory, "/New Address", TRUE); - gtk_widget_set_sensitive( addrbook.reg_btn, TRUE ); - gtk_widget_set_sensitive( addrbook.del_btn, TRUE ); - } - if (obj->type == ADDR_FOLDER) { - menu_set_sensitive(addrbook.list_factory, "/New Folder", TRUE); - menu_set_sensitive(addrbook.list_factory, "/New Group", TRUE); - } +static void addressbook_list_button_pressed(GtkWidget *widget, + GdkEventButton *event, + gpointer data) +{ + if( ! event ) return; + if( event->button == 3 ) { + gtk_menu_popup( GTK_MENU(addrbook.list_popup), NULL, NULL, NULL, NULL, + event->button, event->time ); } - gtk_menu_popup(GTK_MENU(addrbook.list_popup), NULL, NULL, NULL, NULL, - event->button, event->time); } static void addressbook_list_button_released(GtkWidget *widget, @@ -1345,94 +1332,70 @@ static void addressbook_tree_button_pressed(GtkWidget *ctree, { GtkCList *clist = GTK_CLIST(ctree); gint row, column; - AddressObject *obj; + AddressObject *obj = NULL; GtkCTreeNode *node; + AdapterDSource *ads = NULL; + AddressInterface *iface = NULL; + AddressDataSource *ds = NULL; + AddressTypeControlItem *atci = NULL; + gboolean canEdit = FALSE; - if (!event) return; - if (event->button == 1) { - addrbook.open_folder = TRUE; - return; + if( ! event ) return; + addressbook_menubar_set_sensitive( FALSE ); +/* */ + if( gtk_clist_get_selection_info( clist, event->x, event->y, &row, &column ) ) { + gtk_clist_select_row( clist, row, column ); + gtkut_clist_set_focus_row(clist, row); + obj = gtk_clist_get_row_data( clist, row ); } - if (event->button != 3) return; - - if (!gtk_clist_get_selection_info - (clist, event->x, event->y, &row, &column)) return; - gtk_clist_select_row(clist, row, column); - - obj = gtk_clist_get_row_data(clist, row); - g_return_if_fail(obj != NULL); - +/* */ menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup)); - if (obj->type == ADDR_FOLDER) { - node = gtk_ctree_node_nth(GTK_CTREE(ctree), row); - if( node == addrbook.vcard ) { - menu_set_sensitive(addrbook.tree_factory, "/New V-Card", TRUE); - } -#ifdef USE_JPILOT - else if( node == addrbook.jpilot ) { - if( _have_pilot_library_ ) { - menu_set_sensitive(addrbook.tree_factory, "/New J-Pilot", TRUE); - } - } -#endif -#ifdef USE_LDAP - else if( node == addrbook.ldap ) { - if( _have_ldap_library_ ) { - menu_set_sensitive(addrbook.tree_factory, "/New Server", TRUE); - } - } -#endif - else { - menu_set_sensitive(addrbook.tree_factory, "/New Address", TRUE); - menu_set_sensitive(addrbook.tree_factory, "/New Folder", TRUE); - menu_set_sensitive(addrbook.tree_factory, "/New Group", TRUE); - if (node && GTK_CTREE_ROW(node)->level >= 2) { - menu_set_sensitive(addrbook.tree_factory, "/Edit", TRUE); - menu_set_sensitive(addrbook.tree_factory, "/Delete", TRUE); - } + if( obj == NULL ) return; + if (obj->type == ADDR_DATASOURCE) { + ads = ADAPTER_DSOURCE(obj); + ds = ads->dataSource; + iface = ds->interface; + canEdit = TRUE; + if( ! iface->readOnly ) { + menu_set_sensitive( addrbook.tree_factory, "/New Address", TRUE ); + menu_set_sensitive( addrbook.tree_factory, "/New Folder", TRUE ); + menu_set_sensitive( addrbook.tree_factory, "/New Group", TRUE ); gtk_widget_set_sensitive( addrbook.reg_btn, TRUE ); - gtk_widget_set_sensitive( addrbook.del_btn, TRUE ); - } - } - else if (obj->type == ADDR_GROUP) { - menu_set_sensitive(addrbook.tree_factory, "/New Address", TRUE); - menu_set_sensitive(addrbook.tree_factory, "/Edit", TRUE); - menu_set_sensitive(addrbook.tree_factory, "/Delete", TRUE); - gtk_widget_set_sensitive( addrbook.reg_btn, TRUE ); - gtk_widget_set_sensitive( addrbook.del_btn, TRUE ); - } - else if (obj->type == ADDR_VCARD) { - menu_set_sensitive(addrbook.tree_factory, "/Edit", TRUE); - menu_set_sensitive(addrbook.tree_factory, "/Delete", TRUE); - } -#ifdef USE_JPILOT - else if (obj->type == ADDR_JPILOT) { - if( _have_pilot_library_ ) { - menu_set_sensitive(addrbook.tree_factory, "/Edit", TRUE); - menu_set_sensitive(addrbook.tree_factory, "/Delete", TRUE); } } - else if (obj->type == ADDR_CATEGORY) { - if( _have_pilot_library_ ) { - menu_set_sensitive(addrbook.tree_factory, "/Edit", FALSE); - menu_set_sensitive(addrbook.tree_factory, "/Delete", FALSE); + else if (obj->type == ADDR_ITEM_FOLDER) { + ds = addressbook_find_datasource( addrbook.treeSelected ); + iface = ds->interface; + if( ! iface->readOnly ) { + canEdit = TRUE; + menu_set_sensitive( addrbook.tree_factory, "/New Address", TRUE ); + menu_set_sensitive( addrbook.tree_factory, "/New Folder", TRUE ); + menu_set_sensitive( addrbook.tree_factory, "/New Group", TRUE ); + gtk_widget_set_sensitive( addrbook.reg_btn, TRUE ); } } -#endif -#ifdef USE_LDAP - else if (obj->type == ADDR_LDAP) { - if( _have_ldap_library_ ) { - menu_set_sensitive(addrbook.tree_factory, "/Edit", TRUE); - menu_set_sensitive(addrbook.tree_factory, "/Delete", TRUE); + else if (obj->type == ADDR_ITEM_GROUP) { + ds = addressbook_find_datasource( addrbook.treeSelected ); + iface = ds->interface; + if( ! iface->readOnly ) { + canEdit = TRUE; + menu_set_sensitive( addrbook.tree_factory, "/New Address", TRUE ); + gtk_widget_set_sensitive( addrbook.reg_btn, TRUE ); } } -#endif - else { - return; + + // Enable edit + menu_set_sensitive( addrbook.tree_factory, "/Edit", canEdit ); + menu_set_sensitive( addrbook.tree_factory, "/Delete", canEdit ); + menu_set_sensitive( addrbook.menu_factory, "/File/Edit", canEdit ); + menu_set_sensitive( addrbook.menu_factory, "/File/Delete", canEdit ); + + if( event->button == 3 ) { + gtk_menu_popup(GTK_MENU(addrbook.tree_popup), NULL, NULL, NULL, NULL, + event->button, event->time); } - gtk_menu_popup(GTK_MENU(addrbook.tree_popup), NULL, NULL, NULL, NULL, - event->button, event->time); + } static void addressbook_tree_button_released(GtkWidget *ctree, @@ -1456,90 +1419,76 @@ static void addressbook_new_folder_cb(gpointer data, guint action, GtkWidget *widget) { GtkCTree *ctree = GTK_CTREE(addrbook.ctree); - AddressObject *obj; - AddressFolder *folder; - gchar *new_folder; - - if (!addrbook.selected) return; + AddressObject *obj = NULL; + AddressDataSource *ds = NULL; + AddressBookFile *abf = NULL; + ItemFolder *parentFolder = NULL; + ItemFolder *folder = NULL; + + if( ! addrbook.treeSelected ) return; + obj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected ); + if( obj == NULL ) return; + ds = addressbook_find_datasource( addrbook.treeSelected ); + if( ds == NULL ) return; - obj = gtk_ctree_node_get_row_data(ctree, addrbook.selected); - g_return_if_fail(obj != NULL); - if (obj->type != ADDR_FOLDER) return; - - new_folder = input_dialog(_("New folder"), - _("Input the name of new folder:"), - _("NewFolder")); - if (!new_folder) return; - g_strstrip(new_folder); - if (*new_folder == '\0') { - g_free(new_folder); - return; + if( obj->type == ADDR_DATASOURCE ) { + if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return; } - - if (gtk_ctree_find_by_row_data_custom(ctree, addrbook.selected, - new_folder, - addressbook_obj_name_compare)) { - alertpanel_error(_("The name already exists.")); - g_free(new_folder); + else if( obj->type == ADDR_ITEM_FOLDER ) { + parentFolder = ADAPTER_FOLDER(obj)->itemFolder; + } + else { return; } - folder = g_new(AddressFolder, 1); - ADDRESS_OBJECT_TYPE(folder) = ADDR_FOLDER; - folder->name = g_strdup(new_folder); - folder->items = NULL; - - addressbook_add_object(addrbook.selected, ADDRESS_OBJECT(folder)); - - g_free(new_folder); + abf = ds->rawDataSource; + if( abf == NULL ) return; + folder = addressbook_edit_folder( abf, parentFolder, NULL ); + if( folder ) { + GtkCTreeNode *nn; + nn = addressbook_node_add_folder( addrbook.treeSelected, ds, folder, ADDR_ITEM_FOLDER ); + gtk_ctree_expand( ctree, addrbook.treeSelected ); + if( addrbook.treeSelected == addrbook.opened ) addressbook_set_clist(obj); + } - if (addrbook.selected == addrbook.opened) - addressbook_set_clist(obj); } static void addressbook_new_group_cb(gpointer data, guint action, GtkWidget *widget) { GtkCTree *ctree = GTK_CTREE(addrbook.ctree); - AddressObject *obj; - AddressGroup *group; - gchar *new_group; - - if (!addrbook.selected) return; + AddressObject *obj = NULL; + AddressDataSource *ds = NULL; + AddressBookFile *abf = NULL; + ItemFolder *parentFolder = NULL; + ItemGroup *group = NULL; + + if( ! addrbook.treeSelected ) return; + obj = gtk_ctree_node_get_row_data(ctree, addrbook.treeSelected); + if( obj == NULL ) return; + ds = addressbook_find_datasource( addrbook.treeSelected ); + if( ds == NULL ) return; - obj = gtk_ctree_node_get_row_data(ctree, addrbook.selected); - g_return_if_fail(obj != NULL); - if (obj->type != ADDR_FOLDER) return; - - new_group = input_dialog(_("New group"), - _("Input the name of new group:"), - _("NewGroup")); - if (!new_group) return; - g_strstrip(new_group); - if (*new_group == '\0') { - g_free(new_group); - return; + if( obj->type == ADDR_DATASOURCE ) { + if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return; } - - if (gtk_ctree_find_by_row_data_custom(ctree, addrbook.selected, - new_group, - addressbook_obj_name_compare)) { - alertpanel_error(_("The name already exists.")); - g_free(new_group); + else if( obj->type == ADDR_ITEM_FOLDER ) { + parentFolder = ADAPTER_FOLDER(obj)->itemFolder; + } + else { return; } - group = g_new(AddressGroup, 1); - ADDRESS_OBJECT_TYPE(group) = ADDR_GROUP; - group->name = g_strdup(new_group); - group->items = NULL; - - addressbook_add_object(addrbook.selected, ADDRESS_OBJECT(group)); - - g_free(new_group); + abf = ds->rawDataSource; + if( abf == NULL ) return; + group = addressbook_edit_group( abf, parentFolder, NULL ); + if( group ) { + GtkCTreeNode *nn; + nn = addressbook_node_add_group( addrbook.treeSelected, ds, group ); + gtk_ctree_expand( ctree, addrbook.treeSelected ); + if( addrbook.treeSelected == addrbook.opened ) addressbook_set_clist(obj); + } - if (addrbook.selected == addrbook.opened) - addressbook_set_clist(obj); } static void addressbook_change_node_name(GtkCTreeNode *node, const gchar *name) @@ -1559,460 +1508,388 @@ static void addressbook_change_node_name(GtkCTreeNode *node, const gchar *name) is_leaf, expanded); } -static void addressbook_edit_group(GtkCTreeNode *group_node) -{ - GtkCTree *ctree = GTK_CTREE(addrbook.ctree); - GtkCList *clist = GTK_CLIST(addrbook.clist); - AddressObject *obj; - AddressGroup *group; - gchar *new_name; - GtkCTreeNode *node; - - if (!group_node && clist->selection) { - obj = gtk_clist_get_row_data(clist, - GPOINTER_TO_INT(clist->selection->data)); - g_return_if_fail(obj != NULL); - if (obj->type != ADDR_GROUP) return; - node = gtk_ctree_find_by_row_data - (ctree, addrbook.selected, obj); - if (!node) return; - } else { - if (group_node) - node = group_node; - else - node = addrbook.selected; - obj = gtk_ctree_node_get_row_data(ctree, node); - g_return_if_fail(obj != NULL); - if (obj->type != ADDR_GROUP) return; - } +/* +* Edit data source. +* Enter: obj Address object to edit. +* node Node in tree. +* Return: New name of data source. +*/ +static gchar *addressbook_edit_datasource( AddressObject *obj, GtkCTreeNode *node ) { + gchar *newName = NULL; + AddressDataSource *ds = NULL; + AddressInterface *iface = NULL; + AdapterDSource *ads = NULL; - group = ADDRESS_GROUP(obj); + ds = addressbook_find_datasource( node ); + if( ds == NULL ) return NULL; + iface = ds->interface; + if( ! iface->haveLibrary ) return NULL; - new_name = input_dialog(_("Edit group"), - _("Input the new name of group:"), - group->name); - if (!new_name) return; - g_strstrip(new_name); - if (*new_name == '\0') { - g_free(new_name); - return; + // Read data from data source + if( ! addrindex_ds_get_read_flag( ds ) ) { + addrindex_ds_read_data( ds ); } - if (gtk_ctree_find_by_row_data_custom(ctree, addrbook.selected, - new_name, - addressbook_obj_name_compare)) { - alertpanel_error(_("The name already exists.")); - g_free(new_name); - return; + // Handle edit + ads = ADAPTER_DSOURCE(obj); + if( ads->subType == ADDR_BOOK ) { + if( addressbook_edit_book( _addressIndex_, ads ) == NULL ) return NULL; } - - g_free(group->name); - group->name = g_strdup(new_name); - - addressbook_change_node_name(node, new_name); - gtk_ctree_sort_node(ctree, GTK_CTREE_ROW(node)->parent); - - g_free(new_name); - - addrbook.open_folder = TRUE; - gtk_ctree_select(ctree, addrbook.opened); + else if( ads->subType == ADDR_VCARD ) { + if( addressbook_edit_vcard( _addressIndex_, ads ) == NULL ) return NULL; + } +#ifdef USE_JPILOT + else if( ads->subType == ADDR_JPILOT ) { + if( addressbook_edit_jpilot( _addressIndex_, ads ) == NULL ) return NULL; + } +#endif +#ifdef USE_LDAP + else if( ads->subType == ADDR_LDAP ) { + if( addressbook_edit_ldap( _addressIndex_, ads ) == NULL ) return NULL; + } +#endif + else { + return NULL; + } + newName = obj->name; + return newName; } -static void addressbook_edit_folder_cb(gpointer data, guint action, +/* +* Edit an object that is in the address tree area. +*/ +static void addressbook_treenode_edit_cb(gpointer data, guint action, GtkWidget *widget) { GtkCTree *ctree = GTK_CTREE(addrbook.ctree); AddressObject *obj; - AddressFolder *folder; - gchar *new_name = NULL; + AddressDataSource *ds = NULL; + AddressBookFile *abf = NULL; GtkCTreeNode *node = NULL, *parentNode = NULL; + gchar *name = NULL; - if (!addrbook.selected) return; - if (GTK_CTREE_ROW(addrbook.selected)->level == 1) return; - - obj = gtk_ctree_node_get_row_data(ctree, addrbook.selected); - g_return_if_fail(obj != NULL); - g_return_if_fail(obj->type == ADDR_FOLDER || obj->type == ADDR_GROUP || - obj->type == ADDR_VCARD || obj->type == ADDR_JPILOT || - obj->type == ADDR_CATEGORY || obj->type == ADDR_LDAP ); + if( ! addrbook.treeSelected ) return; + node = addrbook.treeSelected; + if( GTK_CTREE_ROW(node)->level == 1 ) return; + obj = gtk_ctree_node_get_row_data( ctree, node ); + if( obj == NULL ) return; + parentNode = GTK_CTREE_ROW(node)->parent; - if (obj->type == ADDR_GROUP) { - addressbook_edit_group(addrbook.selected); - return; - } + ds = addressbook_find_datasource( node ); + if( ds == NULL ) return; - if( obj->type == ADDR_VCARD ) { - AddressVCard *vcard = ADDRESS_VCARD(obj); - if( addressbook_edit_vcard( vcard ) == NULL ) return; - new_name = vcard->name; - parentNode = addrbook.vcard; - } -#ifdef USE_JPILOT - else if( obj->type == ADDR_JPILOT ) { - AddressJPilot *jpilot = ADDRESS_JPILOT(obj); - if( ! _have_pilot_library_ ) return; - if( addressbook_edit_jpilot( jpilot ) == NULL ) return; - new_name = jpilot->name; - parentNode = addrbook.jpilot; - } -#endif -#ifdef USE_LDAP - else if( obj->type == ADDR_LDAP ) { - AddressLDAP *ldapi = ADDRESS_LDAP(obj); - if( ! _have_ldap_library_ ) return; - if( addressbook_edit_ldap( ldapi ) == NULL ) return; - new_name = ldapi->name; - parentNode = addrbook.ldap; + if( obj->type == ADDR_DATASOURCE ) { + name = addressbook_edit_datasource( obj, node ); + if( name == NULL ) return; } -#endif - - if( new_name && parentNode) { + else { + abf = ds->rawDataSource; + if( abf == NULL ) return; + if( obj->type == ADDR_ITEM_FOLDER ) { + AdapterFolder *adapter = ADAPTER_FOLDER(obj); + ItemFolder *item = adapter->itemFolder; + ItemFolder *parentFolder = NULL; + parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item); + if( addressbook_edit_folder( abf, parentFolder, item ) == NULL ) return; + name = ADDRITEM_NAME(item); + } + else if( obj->type == ADDR_ITEM_GROUP ) { + AdapterGroup *adapter = ADAPTER_GROUP(obj); + ItemGroup *item = adapter->itemGroup; + ItemFolder *parentFolder = NULL; + parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item); + if( addressbook_edit_group( abf, parentFolder, item ) == NULL ) return; + name = ADDRITEM_NAME(item); + } + } + if( name && parentNode ) { // Update node in tree view - node = gtk_ctree_find_by_row_data( ctree, addrbook.selected, obj ); - if( ! node ) return; - addressbook_change_node_name( node, new_name ); + addressbook_change_node_name( node, name ); gtk_ctree_sort_node(ctree, parentNode); - addrbook.open_folder = TRUE; - gtk_ctree_select( GTK_CTREE(addrbook.ctree), node ); - return; + gtk_ctree_expand( ctree, node ); + gtk_ctree_select( ctree, node ); } - - folder = ADDRESS_FOLDER(obj); - new_name = input_dialog(_("Edit folder"), - _("Input the new name of folder:"), - folder->name); - - if (!new_name) return; - g_strstrip(new_name); - if (*new_name == '\0') { - g_free(new_name); - return; - } - - if (gtk_ctree_find_by_row_data_custom(ctree, addrbook.selected, - new_name, - addressbook_obj_name_compare)) { - alertpanel_error(_("The name already exists.")); - g_free(new_name); - return; - } - - g_free(folder->name); - folder->name = g_strdup(new_name); - - addressbook_change_node_name(addrbook.selected, new_name); - gtk_ctree_sort_node(ctree, GTK_CTREE_ROW(addrbook.selected)->parent); - - g_free(new_name); } -static void addressbook_delete_folder_cb(gpointer data, guint action, +/* +* Delete an item from the tree widget. +*/ +static void addressbook_treenode_delete_cb(gpointer data, guint action, GtkWidget *widget) { GtkCTree *ctree = GTK_CTREE(addrbook.ctree); - AddressObject *obj, *pobj; - gchar *name; + GtkCTreeNode *node = NULL; + AddressObject *obj; gchar *message; AlertValue aval; + AddressBookFile *abf = NULL; + AdapterDSource *ads = NULL; + AddressInterface *iface = NULL; + AddressDataSource *ds = NULL; + gboolean remFlag = FALSE; - if (!addrbook.selected) return; - if (GTK_CTREE_ROW(addrbook.selected)->level == 1) return; + if( ! addrbook.treeSelected ) return; + node = addrbook.treeSelected; + if( GTK_CTREE_ROW(node)->level == 1 ) return; - obj = gtk_ctree_node_get_row_data(ctree, addrbook.selected); + obj = gtk_ctree_node_get_row_data( ctree, node ); g_return_if_fail(obj != NULL); - if (obj->type == ADDR_GROUP) - name = ADDRESS_GROUP(obj)->name; - else if (obj->type == ADDR_FOLDER) - name = ADDRESS_FOLDER(obj)->name; - else if (obj->type == ADDR_VCARD) - name = ADDRESS_VCARD(obj)->name; -#ifdef USE_JPILOT - else if (obj->type == ADDR_JPILOT) { - if( ! _have_pilot_library_ ) return; - name = ADDRESS_JPILOT(obj)->name; - } -#endif -#ifdef USE_LDAP - else if (obj->type == ADDR_LDAP) { - if( ! _have_ldap_library_ ) return; - name = ADDRESS_LDAP(obj)->name; + if( obj->type == ADDR_DATASOURCE ) { + ads = ADAPTER_DSOURCE(obj); + if( ads == NULL ) return; + ds = ads->dataSource; + if( ds == NULL ) return; } -#endif - else - return; - - message = g_strdup_printf(_("Really delete `%s' ?"), name); - aval = alertpanel(_("Delete"), message, _("Yes"), _("No"), NULL); - g_free(message); - if (aval != G_ALERTDEFAULT) return; - - pobj = gtk_ctree_node_get_row_data - (ctree, GTK_CTREE_ROW(addrbook.selected)->parent); - if (!pobj) return; - g_return_if_fail(pobj->type == ADDR_FOLDER); - ADDRESS_FOLDER(pobj)->items = - g_list_remove(ADDRESS_FOLDER(pobj)->items, obj); - - addressbook_delete_object(obj); - addrbook.open_folder = TRUE; - gtk_ctree_remove_node(ctree, addrbook.selected); - addrbook.open_folder = FALSE; -} - -#define SET_LABEL_AND_ENTRY(str, entry, top) \ -{ \ - label = gtk_label_new(str); \ - gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), \ - GTK_FILL, 0, 0, 0); \ - gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); \ - \ - entry = gtk_entry_new(); \ - gtk_table_attach(GTK_TABLE(table), entry, 1, 2, top, (top + 1), \ - GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0); \ -} - -static void addressbook_edit_address_create(gboolean *cancelled) -{ - GtkWidget *window; - GtkWidget *vbox; - GtkWidget *table; - GtkWidget *label; - GtkWidget *name_entry; - GtkWidget *addr_entry; - GtkWidget *rem_entry; - GtkWidget *hbbox; - GtkWidget *ok_btn; - GtkWidget *cancel_btn; - - debug_print("Creating edit_address window...\n"); - - window = gtk_window_new(GTK_WINDOW_DIALOG); - gtk_widget_set_usize(window, 400, -1); - gtk_container_set_border_width(GTK_CONTAINER(window), 8); - gtk_window_set_title(GTK_WINDOW(window), _("Edit address")); - gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); - gtk_window_set_modal(GTK_WINDOW(window), TRUE); - gtk_signal_connect(GTK_OBJECT(window), "delete_event", - GTK_SIGNAL_FUNC(edit_address_delete_event), - cancelled); - gtk_signal_connect(GTK_OBJECT(window), "key_press_event", - GTK_SIGNAL_FUNC(edit_address_key_pressed), - cancelled); - - vbox = gtk_vbox_new(FALSE, 8); - gtk_container_add(GTK_CONTAINER(window), vbox); - - table = gtk_table_new(3, 2, FALSE); - gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0); - gtk_table_set_row_spacings(GTK_TABLE(table), 8); - gtk_table_set_col_spacings(GTK_TABLE(table), 8); - - SET_LABEL_AND_ENTRY(_("Name"), name_entry, 0); - SET_LABEL_AND_ENTRY(_("Address"), addr_entry, 1); - SET_LABEL_AND_ENTRY(_("Remarks"), rem_entry, 2); + else { + // Must be folder or something else + ds = addressbook_find_datasource( node ); + if( ds == NULL ) return; - gtkut_button_set_create(&hbbox, &ok_btn, _("OK"), - &cancel_btn, _("Cancel"), NULL, NULL); - gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0); - gtk_widget_grab_default(ok_btn); + // Only allow deletion from non-readOnly data sources + iface = ds->interface; + if( iface->readOnly ) return; + } - gtk_signal_connect(GTK_OBJECT(ok_btn), "clicked", - GTK_SIGNAL_FUNC(edit_address_ok), cancelled); - gtk_signal_connect(GTK_OBJECT(cancel_btn), "clicked", - GTK_SIGNAL_FUNC(edit_address_cancel), cancelled); + // Confirm deletion + if( obj->type == ADDR_ITEM_FOLDER ) { + message = g_strdup_printf( _( + "Do you want to delete the folder AND all addresses in `%s' ? \n" \ + "If deleting the folder only, addresses will be moved into parent folder." ), + obj->name ); + aval = alertpanel( _("Delete"), message, _("Folder only"), _("Folder and Addresses"), _("Cancel") ); + g_free(message); + if( aval == G_ALERTOTHER ) return; + } + else { + message = g_strdup_printf(_("Really delete `%s' ?"), obj->name); + aval = alertpanel(_("Delete"), message, _("Yes"), _("No"), NULL); + g_free(message); + if (aval != G_ALERTDEFAULT) return; + } - gtk_widget_show_all(vbox); + // Proceed with deletion + if( obj->type == ADDR_DATASOURCE ) { + // Remove data source. + if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) { + addressbook_free_child_adapters( node ); + remFlag = TRUE; + } + } + else { + abf = addressbook_get_book_file(); + if( abf == NULL ) return; + } + + if( obj->type == ADDR_ITEM_FOLDER ) { + AdapterFolder *adapter = ADAPTER_FOLDER(obj); + ItemFolder *item = adapter->itemFolder; + if( aval == G_ALERTDEFAULT ) { + // Remove folder only + item = addrbook_remove_folder( abf, item ); + if( item ) { + addritem_free_item_folder( item ); + addressbook_move_nodes_up( ctree, node ); + remFlag = TRUE; + } + } + else if( aval == G_ALERTALTERNATE ) { + // Remove folder and addresses + item = addrbook_remove_folder_delete( abf, item ); + if( item ) { + addritem_free_item_folder( item ); + addressbook_free_child_adapters( node ); + remFlag = TRUE; + } + } + } + else if( obj->type == ADDR_ITEM_GROUP ) { + AdapterGroup *adapter = ADAPTER_GROUP(obj); + ItemGroup *item = adapter->itemGroup; - addredit.window = window; - addredit.name_entry = name_entry; - addredit.addr_entry = addr_entry; - addredit.rem_entry = rem_entry; - addredit.ok_btn = ok_btn; - addredit.cancel_btn = cancel_btn; -} + item = addrbook_remove_group( abf, item ); + if( item ) { + addritem_free_item_group( item ); + remFlag = TRUE; + } + } -static void edit_address_ok(GtkWidget *widget, gboolean *cancelled) -{ - *cancelled = FALSE; - gtk_main_quit(); + if( remFlag ) { + // Free up adapter and remove node. + addressbook_free_adapter( node ); + gtk_ctree_remove_node(ctree, node ); + } } -static void edit_address_cancel(GtkWidget *widget, gboolean *cancelled) -{ - *cancelled = TRUE; - gtk_main_quit(); -} +static void addressbook_new_address_cb( gpointer data, guint action, GtkWidget *widget ) { + AddressObject *pobj = NULL; + AddressDataSource *ds = NULL; + AddressBookFile *abf = NULL; -static gint edit_address_delete_event(GtkWidget *widget, GdkEventAny *event, - gboolean *cancelled) -{ - *cancelled = TRUE; - gtk_main_quit(); + pobj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), addrbook.treeSelected); + if( pobj == NULL ) return; + ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) ); + if( ds == NULL ) return; - return TRUE; -} + abf = ds->rawDataSource; + if( abf == NULL ) return; -static void edit_address_key_pressed(GtkWidget *widget, GdkEventKey *event, - gboolean *cancelled) -{ - if (event && event->keyval == GDK_Escape) { - *cancelled = TRUE; - gtk_main_quit(); + if( pobj->type == ADDR_DATASOURCE ) { + if( ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK ) { + // New address + ItemPerson *person = addressbook_edit_person( abf, NULL, NULL, FALSE ); + if( person ) { + if( addrbook.treeSelected == addrbook.opened ) { + gtk_ctree_select( GTK_CTREE(addrbook.ctree), addrbook.opened ); + } + } + } + } + else if( pobj->type == ADDR_ITEM_FOLDER ) { + // New address + ItemFolder *folder = ADAPTER_FOLDER(pobj)->itemFolder; + ItemPerson *person = addressbook_edit_person( abf, folder, NULL, FALSE ); + if( person ) { + if (addrbook.treeSelected == addrbook.opened) { + gtk_ctree_select( GTK_CTREE(addrbook.ctree), addrbook.opened ); + } + } + } + else if( pobj->type == ADDR_ITEM_GROUP ) { + // New address in group + ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup; + if( addressbook_edit_group( abf, NULL, group ) == NULL ) return; + if (addrbook.treeSelected == addrbook.opened) { + // Change node name in tree. + addressbook_change_node_name( addrbook.treeSelected, ADDRITEM_NAME(group) ); + gtk_ctree_select( GTK_CTREE(addrbook.ctree), addrbook.opened ); + } } } -static AddressItem *addressbook_edit_address(AddressItem *item) -{ - static gboolean cancelled; - const gchar *str; - - if (!addredit.window) - addressbook_edit_address_create(&cancelled); - gtk_widget_grab_focus(addredit.ok_btn); - gtk_widget_grab_focus(addredit.name_entry); - gtk_widget_show(addredit.window); - manage_window_set_transient(GTK_WINDOW(addredit.window)); - - gtk_entry_set_text(GTK_ENTRY(addredit.name_entry), ""); - gtk_entry_set_text(GTK_ENTRY(addredit.addr_entry), ""); - gtk_entry_set_text(GTK_ENTRY(addredit.rem_entry), ""); +/* +* Search for specified group in address index tree. +*/ +static GtkCTreeNode *addressbook_find_group_node( GtkCTreeNode *parent, ItemGroup *group ) { + GtkCTreeNode *node = NULL; + GtkCTreeRow *currRow; - if (item) { - if (item->name) - gtk_entry_set_text(GTK_ENTRY(addredit.name_entry), - item->name); - if (item->address) - gtk_entry_set_text(GTK_ENTRY(addredit.addr_entry), - item->address); - if (item->remarks) - gtk_entry_set_text(GTK_ENTRY(addredit.rem_entry), - item->remarks); + currRow = GTK_CTREE_ROW( parent ); + if( currRow ) { + node = currRow->children; + while( node ) { + AddressObject *obj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), node ); + if( obj->type == ADDR_ITEM_GROUP ) { + ItemGroup *g = ADAPTER_GROUP(obj)->itemGroup; + if( g == group ) return node; + } + currRow = GTK_CTREE_ROW(node); + node = currRow->sibling; + } } + return NULL; +} - gtk_main(); - gtk_widget_hide(addredit.window); - if (cancelled == TRUE) return NULL; +static AddressBookFile *addressbook_get_book_file() { + AddressBookFile *abf = NULL; + AddressDataSource *ds = NULL; + ds = addressbook_find_datasource( addrbook.treeSelected ); + if( ds == NULL ) return; + if( ds->type == ADDR_IF_BOOK ) abf = ds->rawDataSource; + return abf; +} - str = gtk_entry_get_text(GTK_ENTRY(addredit.name_entry)); - if (*str == '\0') return NULL; +static void addressbook_tree_remove_children( GtkCTree *ctree, GtkCTreeNode *parent ) { + GtkCTreeNode *node; + GtkCTreeRow *row; - if (!item) { - item = mgu_create_address(); - ADDRESS_OBJECT_TYPE(item) = ADDR_ITEM; + // Remove existing folders and groups + row = GTK_CTREE_ROW( parent ); + if( row ) { + while( node = row->children ) { + gtk_ctree_remove_node( ctree, node ); + } } - - g_free(item->name); - item->name = g_strdup(str); - - str = gtk_entry_get_text(GTK_ENTRY(addredit.addr_entry)); - g_free(item->address); - if (*str == '\0') - item->address = NULL; - else - item->address = g_strdup(str); - - str = gtk_entry_get_text(GTK_ENTRY(addredit.rem_entry)); - g_free(item->remarks); - if (*str == '\0') - item->remarks = NULL; - else - item->remarks = g_strdup(str); - - return item; } -static void addressbook_new_address_cb(gpointer data, guint action, - GtkWidget *widget) -{ - AddressItem *item; - - item = addressbook_edit_address(NULL); - - if (item) { - addressbook_add_object(addrbook.selected, - ADDRESS_OBJECT(item)); - if (addrbook.selected == addrbook.opened) { - addrbook.open_folder = TRUE; - gtk_ctree_select(GTK_CTREE(addrbook.ctree), - addrbook.opened); +static void addressbook_move_nodes_up( GtkCTree *ctree, GtkCTreeNode *node ) { + GtkCTreeNode *parent, *child; + GtkCTreeRow *currRow; + currRow = GTK_CTREE_ROW( node ); + if( currRow ) { + parent = currRow->parent; + while( child = currRow->children ) { + gtk_ctree_move( ctree, child, parent, node ); } + gtk_ctree_sort_node( ctree, parent ); } } -static void addressbook_edit_address_cb(gpointer data, guint action, - GtkWidget *widget) -{ - GtkCList *clist = GTK_CLIST(addrbook.clist); +static void addressbook_edit_address_cb( gpointer data, guint action, GtkWidget *widget ) { + GtkCTree *clist = GTK_CTREE(addrbook.clist); GtkCTree *ctree; - AddressObject *obj, *pobj; + AddressObject *obj = NULL, *pobj = NULL; + AddressDataSource *ds = NULL; GtkCTreeNode *node = NULL, *parentNode = NULL; - gchar *nodeName; - - if (!clist->selection) { - addressbook_edit_folder_cb(NULL, 0, NULL); - return; - } + gchar *name = NULL; + AddressBookFile *abf = NULL; - obj = gtk_clist_get_row_data(clist, GPOINTER_TO_INT(clist->selection->data)); + if( addrbook.listSelected == NULL ) return; + obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected ); g_return_if_fail(obj != NULL); - pobj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), addrbook.selected); - - if (obj->type == ADDR_ITEM) { - AddressItem *item = ADDRESS_ITEM(obj); - - if( pobj ) { - // Prevent edit of readonly items - if( pobj->type == ADDR_VCARD || - pobj->type == ADDR_JPILOT || - pobj->type == ADDR_CATEGORY || - pobj->type == ADDR_LDAP ) return; + ctree = GTK_CTREE( addrbook.ctree ); + pobj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected ); + node = gtk_ctree_find_by_row_data( ctree, addrbook.treeSelected, obj ); + + ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) ); + if( ds == NULL ) return; + + abf = addressbook_get_book_file(); + if( abf == NULL ) return; + if( obj->type == ADDR_ITEM_EMAIL ) { + ItemEMail *email = ( ItemEMail * ) obj; + ItemPerson *person; + if( email == NULL ) return; + if( pobj && pobj->type == ADDR_ITEM_GROUP ) { + // Edit parent group + AdapterGroup *adapter = ADAPTER_GROUP(pobj); + ItemGroup *itemGrp = adapter->itemGroup; + if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return; + name = ADDRITEM_NAME(itemGrp); + node = addrbook.treeSelected; + parentNode = GTK_CTREE_ROW(node)->parent; + } + else { + // Edit person - email page + person = ( ItemPerson * ) ADDRITEM_PARENT(email); + if( addressbook_edit_person( abf, NULL, person, TRUE ) == NULL ) return; + gtk_ctree_select( ctree, addrbook.opened ); + return; } - - if (addressbook_edit_address(item) == NULL) return; - - addrbook.open_folder = TRUE; - gtk_ctree_select(GTK_CTREE(addrbook.ctree), addrbook.opened); - return; - } - else if (obj->type == ADDR_GROUP) { - addressbook_edit_group(NULL); - return; - } - else if( obj->type == ADDR_VCARD ) { - AddressVCard *vcard = ADDRESS_VCARD(obj); - if( addressbook_edit_vcard( vcard ) == NULL ) return; - nodeName = vcard->name; - parentNode = addrbook.vcard; } -#ifdef USE_JPILOT - else if( obj->type == ADDR_JPILOT ) { - AddressJPilot *jpilot = ADDRESS_JPILOT(obj); - if( addressbook_edit_jpilot( jpilot ) == NULL ) return; - nodeName = jpilot->name; - parentNode = addrbook.jpilot; + else if( obj->type == ADDR_ITEM_PERSON ) { + // Edit person - basic page + ItemPerson *person = ( ItemPerson * ) obj; + if( addressbook_edit_person( abf, NULL, person, FALSE ) == NULL ) return; + gtk_ctree_select( ctree, addrbook.opened); + return; } -#endif -#ifdef USE_LDAP - else if( obj->type == ADDR_LDAP ) { - AddressLDAP *ldapi = ADDRESS_LDAP(obj); - if( addressbook_edit_ldap( ldapi ) == NULL ) return; - nodeName = ldapi->name; - parentNode = addrbook.ldap; + else if( obj->type == ADDR_ITEM_GROUP ) { + ItemGroup *itemGrp = ( ItemGroup * ) obj; + if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return; + parentNode = addrbook.treeSelected; + node = addressbook_find_group_node( parentNode, itemGrp ); + name = ADDRITEM_NAME(itemGrp); } -#endif else { return; } // Update tree node with node name - ctree = GTK_CTREE( addrbook.ctree ); - node = gtk_ctree_find_by_row_data( ctree, addrbook.selected, obj ); - if( ! node ) return; - addressbook_change_node_name( node, nodeName ); - gtk_ctree_sort_node(ctree, parentNode ); - addrbook.open_folder = TRUE; + if( node == NULL ) return; + addressbook_change_node_name( node, name ); + gtk_ctree_sort_node( ctree, parentNode ); gtk_ctree_select( ctree, addrbook.opened ); } @@ -2027,707 +1904,828 @@ static void close_cb(gpointer data, guint action, GtkWidget *widget) addressbook_close(); } -static void addressbook_set_clist(AddressObject *obj) -{ - GtkCList *clist = GTK_CLIST(addrbook.clist); - GList *items; - gchar *text[N_COLS]; +static void addressbook_file_save_cb( gpointer data, guint action, GtkWidget *widget ) { + addressbook_export_to_file(); +} - if (!obj) { - gtk_clist_clear(clist); - return; +static void addressbook_person_expand_node( GtkCTree *ctree, GList *node, gpointer *data ) { + if( node ) { + ItemPerson *person = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) ); + if( person ) addritem_person_set_opened( person, TRUE ); } +} - gtk_clist_freeze(clist); - gtk_clist_clear(clist); - - if (obj->type == ADDR_GROUP) - items = ADDRESS_GROUP(obj)->items; - else if (obj->type == ADDR_FOLDER) { - items = ADDRESS_FOLDER(obj)->items; - } - else if (obj->type == ADDR_VCARD) { - items = ADDRESS_VCARD(obj)->items; - } -#ifdef USE_JPILOT - else if (obj->type == ADDR_JPILOT) { - items = ADDRESS_JPILOT(obj)->items; - } - else if (obj->type == ADDR_CATEGORY) { - items = ADDRESS_CATEGORY(obj)->items; +static void addressbook_person_collapse_node( GtkCTree *ctree, GList *node, gpointer *data ) { + if( node ) { + ItemPerson *person = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) ); + if( person ) addritem_person_set_opened( person, FALSE ); } -#endif -#ifdef USE_LDAP - else if (obj->type == ADDR_LDAP) { - items = ADDRESS_LDAP(obj)->items; +} + +static gchar *addressbook_format_item_clist( ItemPerson *person, ItemEMail *email ) { + gchar *str = NULL; + gchar *eMailAlias = ADDRITEM_NAME(email); + if( eMailAlias && *eMailAlias != '\0' ) { + if( person ) { + str = g_strdup_printf( "%s - %s", ADDRITEM_NAME(person), eMailAlias ); + } + else { + str = g_strdup( eMailAlias ); + } } -#endif - else { - gtk_clist_thaw(clist); - return; + return str; +} + +static void addressbook_load_group( GtkCTree *clist, ItemGroup *itemGroup ) { + GList *items = itemGroup->listEMail; + AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_EMAIL ); + for( ; items != NULL; items = g_list_next( items ) ) { + GtkCTreeNode *nodeEMail = NULL; + gchar *text[N_COLS]; + ItemEMail *email = items->data; + ItemPerson *person; + gchar *str = NULL; + + if( ! email ) continue; + + person = ( ItemPerson * ) ADDRITEM_PARENT(email); + str = addressbook_format_item_clist( person, email ); + if( str ) { + text[COL_NAME] = str; + } + else { + text[COL_NAME] = ADDRITEM_NAME(person); + } + text[COL_ADDRESS] = email->address; + text[COL_REMARKS] = email->remarks; + nodeEMail = gtk_ctree_insert_node( + clist, NULL, NULL, + text, FOLDER_SPACING, + atci->iconXpm, atci->maskXpm, + atci->iconXpmOpen, atci->maskXpmOpen, + FALSE, FALSE ); + gtk_ctree_node_set_row_data( clist, nodeEMail, email ); + g_free( str ); + str = NULL; } +} - for (; items != NULL; items = items->next) { - AddressObject *iobj; +static void addressbook_folder_load_person( GtkCTree *clist, ItemFolder *itemFolder ) { + GList *items; + AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON ); + AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL ); + + if( atci == NULL ) return; + if( atciMail == NULL ) return; + + // Load email addresses + items = addritem_folder_get_person_list( itemFolder ); + for( ; items != NULL; items = g_list_next( items ) ) { + GtkCTreeNode *nodePerson = NULL; + GtkCTreeNode *nodeEMail = NULL; + gchar *text[N_COLS]; + gboolean flgFirst = TRUE, haveAddr = FALSE; gint row; - iobj = ADDRESS_OBJECT(items->data); - if( iobj == NULL ) continue; + ItemPerson *person; + GList *node; - if (iobj->type == ADDR_GROUP) { - AddressGroup *group; + person = ( ItemPerson * ) items->data; + if( person == NULL ) continue; - group = ADDRESS_GROUP(iobj); - text[COL_NAME] = group->name; - text[COL_ADDRESS] = NULL; - text[COL_REMARKS] = NULL; - row = gtk_clist_append(clist, text); - gtk_clist_set_pixtext(clist, row, COL_NAME, - group->name, 4, - groupxpm, groupxpmmask); - gtk_clist_set_row_data(clist, row, iobj); - } if (iobj->type == ADDR_VCARD) { - AddressVCard *vcard; - - vcard = ADDRESS_VCARD(iobj); - text[COL_NAME] = vcard->name; - text[COL_ADDRESS] = NULL; - text[COL_REMARKS] = NULL; - row = gtk_clist_append(clist, text); - gtk_clist_set_pixtext(clist, row, COL_NAME, - vcard->name, 4, - vcardxpm, vcardxpmmask); - gtk_clist_set_row_data(clist, row, iobj); -#ifdef USE_JPILOT - } if (iobj->type == ADDR_JPILOT) { - AddressJPilot *jpilot; + text[COL_NAME] = NULL; + node = person->listEMail; + while( node ) { + ItemEMail *email = node->data; + gchar *eMailAddr = NULL; + node = g_list_next( node ); - jpilot = ADDRESS_JPILOT(iobj); - text[COL_NAME] = jpilot->name; - text[COL_ADDRESS] = NULL; - text[COL_REMARKS] = NULL; - row = gtk_clist_append(clist, text); - gtk_clist_set_pixtext(clist, row, COL_NAME, - jpilot->name, 4, - jpilotxpm, jpilotxpmmask); - gtk_clist_set_row_data(clist, row, iobj); - } if (iobj->type == ADDR_CATEGORY) { - AddressCategory *category; - - category = ADDRESS_CATEGORY(iobj); - text[COL_NAME] = category->name; + text[COL_ADDRESS] = email->address; + text[COL_REMARKS] = email->remarks; + eMailAddr = ADDRITEM_NAME(email); + if( *eMailAddr == '\0' ) eMailAddr = NULL; + if( flgFirst ) { + // First email belongs with person + gchar *str = addressbook_format_item_clist( person, email ); + if( str ) { + text[COL_NAME] = str; + } + else { + text[COL_NAME] = ADDRITEM_NAME(person); + } + nodePerson = gtk_ctree_insert_node( + clist, NULL, NULL, + text, FOLDER_SPACING, + atci->iconXpm, atci->maskXpm, + atci->iconXpmOpen, atci->maskXpmOpen, + FALSE, person->isOpened ); + g_free( str ); + str = NULL; + gtk_ctree_node_set_row_data(clist, nodePerson, person ); + } + else { + // Subsequent email is a child node of person + text[COL_NAME] = ADDRITEM_NAME(email); + nodeEMail = gtk_ctree_insert_node( + clist, nodePerson, NULL, + text, FOLDER_SPACING, + atciMail->iconXpm, atciMail->maskXpm, + atciMail->iconXpmOpen, atciMail->maskXpmOpen, + FALSE, TRUE ); + gtk_ctree_node_set_row_data(clist, nodeEMail, email ); + } + flgFirst = FALSE; + haveAddr = TRUE; + } + if( ! haveAddr ) { + // Have name without EMail + text[COL_NAME] = ADDRITEM_NAME(person); text[COL_ADDRESS] = NULL; text[COL_REMARKS] = NULL; - row = gtk_clist_append(clist, text); - gtk_clist_set_pixtext(clist, row, COL_NAME, - category->name, 4, - categoryxpm, categoryxpmmask); - gtk_clist_set_row_data(clist, row, iobj); -#endif -#ifdef USE_LDAP - } if (iobj->type == ADDR_LDAP) { - AddressLDAP *ldapi; + nodePerson = gtk_ctree_insert_node( + clist, NULL, NULL, + text, FOLDER_SPACING, + atci->iconXpm, atci->maskXpm, + atci->iconXpmOpen, atci->maskXpmOpen, + FALSE, person->isOpened ); + gtk_ctree_node_set_row_data(clist, nodePerson, person ); + } + gtk_ctree_sort_node(GTK_CTREE(clist), NULL); + } + // Free up the list + mgu_clear_list( items ); + g_list_free( items ); +} + +static void addressbook_folder_load_group( GtkCTree *clist, ItemFolder *itemFolder ) { + GList *items; + AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_GROUP ); + + // Load any groups + if( ! atci ) return; + items = addritem_folder_get_group_list( itemFolder ); + for( ; items != NULL; items = g_list_next( items ) ) { + GtkCTreeNode *nodeGroup = NULL; + gchar *text[N_COLS]; + ItemGroup *group = items->data; + if( group == NULL ) continue; + text[COL_NAME] = ADDRITEM_NAME(group); + text[COL_ADDRESS] = NULL; + text[COL_REMARKS] = NULL; + nodeGroup = gtk_ctree_insert_node(clist, NULL, NULL, + text, FOLDER_SPACING, + atci->iconXpm, atci->maskXpm, + atci->iconXpmOpen, atci->maskXpmOpen, + FALSE, FALSE); + gtk_ctree_node_set_row_data(clist, nodeGroup, group ); + gtk_ctree_sort_node(clist, NULL); + } + // Free up the list + mgu_clear_list( items ); + g_list_free( items ); +} + +/* + * Load data sources into list. + */ +static void addressbook_node_load_datasource( GtkCTree *clist, AddressObject *obj ) { + AdapterInterface *adapter; + AddressInterface *iface; + AddressTypeControlItem *atci = NULL; + AddressDataSource *ds; + GtkCTreeNode *newNode, *node; + GtkCTreeRow *row; + GtkCell *cell = NULL; + gchar *text[N_COLS]; + + adapter = ADAPTER_INTERFACE(obj); + if( adapter == NULL ) return; + iface = adapter->interface; + atci = adapter->atci; + if( atci == NULL ) return; - ldapi = ADDRESS_LDAP(iobj); - text[COL_NAME] = ldapi->name; + // Create nodes in list copying values for data sources in tree + row = GTK_CTREE_ROW( adapter->treeNode ); + if( row ) { + node = row->children; + while( node ) { + gpointer data = gtk_ctree_node_get_row_data( clist, node ); + row = GTK_CTREE_ROW( node ); + cell = ( ( GtkCListRow * )row )->cell; + text[COL_NAME] = cell->u.text; text[COL_ADDRESS] = NULL; text[COL_REMARKS] = NULL; - row = gtk_clist_append(clist, text); - gtk_clist_set_pixtext(clist, row, COL_NAME, - ldapi->name, 4, - ldapxpm, ldapxpmmask); - gtk_clist_set_row_data(clist, row, iobj); -#endif - } else if (iobj->type == ADDR_ITEM) { - AddressItem *item; + newNode = gtk_ctree_insert_node( clist, NULL, NULL, + text, FOLDER_SPACING, + atci->iconXpm, atci->maskXpm, + atci->iconXpmOpen, atci->maskXpmOpen, + FALSE, FALSE); + gtk_ctree_node_set_row_data( clist, newNode, data ); + node = row->sibling; - item = ADDRESS_ITEM(iobj); - text[COL_NAME] = item->name; - text[COL_ADDRESS] = item->address; - text[COL_REMARKS] = item->remarks; - row = gtk_clist_append(clist, text); - gtk_clist_set_row_data(clist, row, iobj); } } - - gtk_clist_sort(clist); - gtk_clist_thaw(clist); + gtk_ctree_sort_node( clist, NULL ); } -static void addressbook_read_file(void) -{ - XMLFile *file; - gchar *path; - - debug_print(_("Reading addressbook file...")); - - path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ADDRESS_BOOK, NULL); - if ((file = xml_open_file(path)) == NULL) { - debug_print(_("%s doesn't exist.\n"), path); - g_free(path); - addressbook_get_tree(NULL, addrbook.common, ADDRESS_TAG_COMMON); - addressbook_get_tree(NULL, addrbook.personal, ADDRESS_TAG_PERSONAL); - addressbook_get_tree(NULL, addrbook.vcard, ADDRESS_TAG_VCARD); -#ifdef USE_JPILOT - addressbook_get_tree(NULL, addrbook.jpilot, ADDRESS_TAG_JPILOT); -#endif -#ifdef USE_LDAP - addressbook_get_tree(NULL, addrbook.ldap, ADDRESS_TAG_LDAP); -#endif - return; +static AddressDataSource *addressbook_find_datasource( GtkCTreeNode *node ) { + AddressDataSource *ds = NULL; + AddressObject *ao; + + g_return_if_fail(addrbook.ctree != NULL); + + while( node ) { + if( GTK_CTREE_ROW(node)->level < 2 ) return NULL; + ao = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), node ); + if( ao ) { +// printf( "ao->type = %d\n", ao->type ); + if( ao->type == ADDR_DATASOURCE ) { + AdapterDSource *ads = ADAPTER_DSOURCE(ao); +// printf( "found it\n" ); + ds = ads->dataSource; + break; + } + } + node = GTK_CTREE_ROW(node)->parent; } - g_free(path); + return ds; +} - xml_get_dtd(file); +/* +* Load address list widget with children of specified object. +* Enter: obj Parent object to be loaded. +*/ +static void addressbook_set_clist( AddressObject *obj ) { + GtkCTree *ctreelist = GTK_CTREE(addrbook.clist); + GtkCList *clist = GTK_CLIST(addrbook.clist); + AddressDataSource *ds = NULL; + AdapterDSource *ads = NULL; - if (xml_parse_next_tag(file) < 0 || - xml_compare_tag(file, "addressbook") == FALSE) { - g_warning("Invalid addressbook data\n"); - xml_close_file(file); + if( obj == NULL ) { + gtk_clist_clear(clist); return; } - addressbook_get_tree(file, addrbook.common, ADDRESS_TAG_COMMON); - addressbook_get_tree(file, addrbook.personal, ADDRESS_TAG_PERSONAL); - addressbook_get_tree(file, addrbook.vcard, ADDRESS_TAG_VCARD); -#ifdef USE_JPILOT - addressbook_get_tree(file, addrbook.jpilot, ADDRESS_TAG_JPILOT); -#endif -#ifdef USE_LDAP - addressbook_get_tree(file, addrbook.ldap, ADDRESS_TAG_LDAP); -#endif - - xml_close_file(file); - - debug_print(_("done.\n")); -} - -static void addressbook_get_tree(XMLFile *file, GtkCTreeNode *node, - const gchar *folder_tag) -{ - AddressFolder *folder; - - g_return_if_fail(node != NULL); + if( obj->type == ADDR_INTERFACE ) { + // printf( "set_clist: loading datasource...\n" ); + // addressbook_node_load_datasource( clist, obj ); + return; + } - folder = g_new(AddressFolder, 1); - ADDRESS_OBJECT(folder)->type = ADDR_FOLDER; - folder->name = g_strdup(folder_tag); - folder->items = NULL; - gtk_ctree_node_set_row_data(GTK_CTREE(addrbook.ctree), node, folder); + gtk_clist_freeze(clist); + gtk_clist_clear(clist); - if (file) { - if (xml_parse_next_tag(file) < 0 || - xml_compare_tag(file, folder_tag) == FALSE) { - g_warning("Invalid addressbook data\n"); - return; + if( obj->type == ADDR_DATASOURCE ) { + ads = ADAPTER_DSOURCE(obj); + ds = ADAPTER_DSOURCE(obj)->dataSource; + if( ds ) { + // Load root folder + ItemFolder *rootFolder = NULL; + rootFolder = addrindex_ds_get_root_folder( ds ); + addressbook_folder_load_person( ctreelist, addrindex_ds_get_root_folder( ds ) ); + addressbook_folder_load_group( ctreelist, addrindex_ds_get_root_folder( ds ) ); + } + } + else { + if( obj->type == ADDR_ITEM_GROUP ) { + // Load groups + ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup; + addressbook_load_group( ctreelist, itemGroup ); + } + else if( obj->type == ADDR_ITEM_FOLDER ) { + // Load folders + ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder; + addressbook_folder_load_person( ctreelist, itemFolder ); + addressbook_folder_load_group( ctreelist, itemFolder ); } } - if (file) addressbook_add_objs(file, node); + gtk_clist_sort(clist); + gtk_clist_thaw(clist); } -static void addressbook_add_objs(XMLFile *file, GtkCTreeNode *node) -{ - GList *attr; - guint prev_level; - GtkCTreeNode *new_node; - - for (;;) { - prev_level = file->level; - if (xml_parse_next_tag(file) < 0) return; - if (file->level < prev_level) return; - - if (xml_compare_tag(file, "group")) { - AddressGroup *group; - - group = g_new(AddressGroup, 1); - ADDRESS_OBJECT_TYPE(group) = ADDR_GROUP; - attr = xml_get_current_tag_attr(file); - if (attr) - group->name = g_strdup(((XMLAttr *)attr->data)->value); - else - group->name = NULL; - group->items = NULL; - - new_node = addressbook_add_object - (node, ADDRESS_OBJECT(group)); - - addressbook_add_objs(file, new_node); - } else if (xml_compare_tag(file, "folder")) { - AddressFolder *folder; - - folder = g_new(AddressFolder, 1); - ADDRESS_OBJECT_TYPE(folder) = ADDR_FOLDER; - attr = xml_get_current_tag_attr(file); - if (attr) - folder->name = g_strdup(((XMLAttr *)attr->data)->value); - else - folder->name = NULL; - folder->items = NULL; - - new_node = addressbook_add_object - (node, ADDRESS_OBJECT(folder)); - - addressbook_add_objs(file, new_node); - } - else if( xml_compare_tag( file, "vcard" ) ) { - AddressVCard *vcard; - vcard = addressbook_parse_vcard( file ); - if( ! vcard ) return; - new_node = addressbook_add_object - (node, ADDRESS_OBJECT(vcard)); +/* +* Free adaptor for specified node. +*/ +static void addressbook_free_adapter( GtkCTreeNode *node ) { + AddressObject *ao; + + g_return_if_fail(addrbook.ctree != NULL); + + if( node ) { + if( GTK_CTREE_ROW(node)->level < 2 ) return; + ao = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), node ); + if( ao == NULL ) return; + if( ao->type == ADDR_INTERFACE ) { + AdapterInterface *ai = ADAPTER_INTERFACE(ao); + addrbookctl_free_interface( ai ); } -#ifdef USE_JPILOT - else if( xml_compare_tag( file, "jpilot" ) ) { - AddressJPilot *jpilot; - jpilot = addressbook_parse_jpilot( file ); - if( ! jpilot ) return; - new_node = addressbook_add_object - (node, ADDRESS_OBJECT(jpilot)); + else if( ao->type == ADDR_DATASOURCE ) { + AdapterDSource *ads = ADAPTER_DSOURCE(ao); + addrbookctl_free_datasource( ads ); } -#endif -#ifdef USE_LDAP - else if( xml_compare_tag( file, "server" ) ) { - AddressLDAP *ldapi; - ldapi = addressbook_parse_ldap( file ); - if( ! ldapi ) return; - new_node = addressbook_add_object - (node, ADDRESS_OBJECT(ldapi)); + else if( ao->type == ADDR_ITEM_FOLDER ) { + AdapterFolder *af = ADAPTER_FOLDER(ao); + addrbookctl_free_folder( af ); } -#endif - else if (xml_compare_tag(file, "item")) { - AddressItem *item; - - item = addressbook_parse_item(file); - if (!item) return; - new_node = addressbook_add_object - (node, ADDRESS_OBJECT(item)); - } else { - g_warning("Invalid tag\n"); - return; + else if( ao->type == ADDR_ITEM_GROUP ) { + AdapterGroup *ag = ADAPTER_GROUP(ao); + addrbookctl_free_group( ag ); } + gtk_ctree_node_set_row_data( GTK_CTREE(addrbook.ctree), node, NULL ); } } -static GtkCTreeNode *addressbook_add_object(GtkCTreeNode *node, - AddressObject *obj) -{ - GtkCTree *ctree = GTK_CTREE(addrbook.ctree); - GtkCTreeNode *added; - AddressObject *pobj; - - g_return_val_if_fail(node != NULL, NULL); - g_return_val_if_fail(obj != NULL, NULL); - - pobj = gtk_ctree_node_get_row_data(ctree, node); - g_return_val_if_fail(pobj != NULL, NULL); +/* +* Free all children adapters. +*/ +static void addressbook_free_child_adapters( GtkCTreeNode *node ) { + GtkCTreeNode *parent, *child; + GtkCTreeRow *currRow; - if (pobj->type == ADDR_ITEM) { - g_warning("Parent object mustn't be an item.\n"); - return NULL; + if( node == NULL ) return; + currRow = GTK_CTREE_ROW( node ); + if( currRow ) { + parent = currRow->parent; + child = currRow->children; + while( child ) { + addressbook_free_child_adapters( child ); + addressbook_free_adapter( child ); + currRow = GTK_CTREE_ROW( child ); + child = currRow->sibling; + } } - if (pobj->type == ADDR_FOLDER && - (obj->type == ADDR_GROUP || obj->type == ADDR_FOLDER)) - gtk_ctree_expand(ctree, node); - - if (pobj->type == ADDR_FOLDER && obj->type == ADDR_VCARD ) - gtk_ctree_expand(ctree, node); +} - if (pobj->type == ADDR_FOLDER && obj->type == ADDR_JPILOT ) - gtk_ctree_expand(ctree, node); +AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds, + AddressObjectType otype, gchar *name ) +{ + AdapterDSource *adapter = g_new0( AdapterDSource, 1 ); + ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE; + ADDRESS_OBJECT_NAME(adapter) = g_strdup( name ); + adapter->dataSource = ds; + adapter->subType = otype; + return adapter; +} - if (pobj->type == ADDR_FOLDER && obj->type == ADDR_LDAP ) - gtk_ctree_expand(ctree, node); +void addressbook_ads_set_name( AdapterDSource *adapter, gchar *value ) { + ADDRESS_OBJECT_NAME(adapter) = mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value ); +} - if (obj->type == ADDR_GROUP) { - AddressGroup *group = ADDRESS_GROUP(obj); +/* + * Load tree from address index with the initial data. + */ +static void addressbook_load_tree( void ) { + GtkCTree *ctree = GTK_CTREE( addrbook.ctree ); + GList *nodeIf, *nodeDS; + AdapterInterface *adapter; + AddressInterface *iface; + AddressTypeControlItem *atci; + AddressDataSource *ds; + AdapterDSource *ads; + GtkCTreeNode *node, *newNode; + gchar *name; - if (pobj->type != ADDR_FOLDER) { - g_warning("Group can't be added in another group.\n"); - return NULL; + nodeIf = _addressInterfaceList_; + while( nodeIf ) { + adapter = nodeIf->data; + node = adapter->treeNode; + iface = adapter->interface; + atci = adapter->atci; + if( iface ) { + // Load data sources below interface node + nodeDS = iface->listSource; + while( nodeDS ) { + ds = nodeDS->data; + newNode = NULL; + name = addrindex_ds_get_name( ds ); + ads = addressbook_create_ds_adapter( ds, atci->objectType, name ); + newNode = addressbook_add_object( node, ADDRESS_OBJECT(ads) ); + nodeDS = g_list_next( nodeDS ); + } } + gtk_ctree_expand( ctree, node ); + nodeIf = g_list_next( nodeIf ); + } +} - added = gtk_ctree_insert_node(ctree, node, NULL, - &group->name, FOLDER_SPACING, - groupxpm, groupxpmmask, - groupxpm, groupxpmmask, - TRUE, FALSE); - gtk_ctree_node_set_row_data(ctree, added, obj); - } else if (obj->type == ADDR_FOLDER) { - AddressFolder *folder = ADDRESS_FOLDER(obj); - - if (pobj->type != ADDR_FOLDER) { - g_warning("Group can't contain folder.\n"); - return NULL; +/* + * Convert the old address book to new format. + */ +static gboolean addressbook_convert( AddressIndex *addrIndex ) { + gboolean retVal = FALSE; + gboolean errFlag = TRUE; + gchar *msg = NULL; + + // Read old address book, performing conversion + debug_print( "Reading and converting old address book...\n" ); + addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE ); + addrindex_read_data( addrIndex ); + if( addrIndex->retVal == MGU_NO_FILE ) { + // We do not have a file - new user + debug_print( "New user... create new books...\n" ); + addrindex_create_new_books( addrIndex ); + if( addrIndex->retVal == MGU_SUCCESS ) { + // Save index file + addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE ); + addrindex_save_data( addrIndex ); + if( addrIndex->retVal == MGU_SUCCESS ) { + retVal = TRUE; + errFlag = FALSE; + } + else { + msg = g_strdup( _( "New user, could not save index file." ) ); + } + } + else { + msg = g_strdup( _( "New user, could not save address book files." ) ); } - - added = gtk_ctree_insert_node(ctree, node, NULL, - &folder->name, FOLDER_SPACING, - folderxpm, folderxpmmask, - folderopenxpm, folderopenxpmmask, - FALSE, FALSE); - gtk_ctree_node_set_row_data(ctree, added, obj); - - } - else if (obj->type == ADDR_VCARD) { - AddressVCard *vcard = ADDRESS_VCARD(obj); - added = gtk_ctree_insert_node(ctree, node, NULL, - &vcard->name, FOLDER_SPACING, - vcardxpm, vcardxpmmask, - vcardxpm, vcardxpmmask, - TRUE, FALSE); - gtk_ctree_node_set_row_data(ctree, added, obj); - } -#ifdef USE_JPILOT - else if (obj->type == ADDR_JPILOT) { - AddressJPilot *jpilot = ADDRESS_JPILOT(obj); - added = gtk_ctree_insert_node(ctree, node, NULL, - &jpilot->name, FOLDER_SPACING, - jpilotxpm, jpilotxpmmask, - jpilotxpm, jpilotxpmmask, - FALSE, FALSE); - gtk_ctree_node_set_row_data(ctree, added, obj); - } - else if (obj->type == ADDR_CATEGORY) { - AddressCategory *category = ADDRESS_CATEGORY(obj); - added = gtk_ctree_insert_node(ctree, node, NULL, - &category->name, FOLDER_SPACING, - categoryxpm, categoryxpmmask, - categoryxpm, categoryxpmmask, - TRUE, FALSE); - gtk_ctree_node_set_row_data(ctree, added, obj); - } -#endif -#ifdef USE_LDAP - else if (obj->type == ADDR_LDAP) { - AddressLDAP *server = ADDRESS_LDAP(obj); - added = gtk_ctree_insert_node(ctree, node, NULL, - &server->name, FOLDER_SPACING, - ldapxpm, ldapxpmmask, - ldapxpm, ldapxpmmask, - TRUE, FALSE); - gtk_ctree_node_set_row_data(ctree, added, obj); - } -#endif - else { - added = node; } - - if (obj->type == ADDR_GROUP || obj->type == ADDR_ITEM) { - if (pobj->type == ADDR_GROUP) { - AddressGroup *group = ADDRESS_GROUP(pobj); - - group->items = g_list_append(group->items, obj); - } else if (pobj->type == ADDR_FOLDER) { - AddressFolder *folder = ADDRESS_FOLDER(pobj); - - folder->items = g_list_append(folder->items, obj); + else { + // We have an old file + if( addrIndex->wasConverted ) { + // Converted successfully - save address index + addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE ); + addrindex_save_data( addrIndex ); + if( addrIndex->retVal == MGU_SUCCESS ) { + msg = g_strdup( _( "Old address book converted successfully." ) ); + retVal = TRUE; + errFlag = FALSE; + } + else { + msg = g_strdup( _( + "Old address book converted, " \ + "could not save new address index file" ) ); + } + } + else { + // File conversion failed - just create new books + debug_print( "File conversion failed... just create new books...\n" ); + addrindex_create_new_books( addrIndex ); + if( addrIndex->retVal == MGU_SUCCESS ) { + // Save index + addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE ); + addrindex_save_data( addrIndex ); + if( addrIndex->retVal == MGU_SUCCESS ) { + msg = g_strdup( _( + "Could not convert address book, " \ + "but created empty new address book files." ) ); + retVal = TRUE; + errFlag = FALSE; + } + else { + msg = g_strdup( _( + "Could not convert address book, " \ + "could not create new address book files." ) ); + } + } + else { + msg = g_strdup( _( + "Could not convert address book " \ + "and could not create new address book files." ) ); + } } } - - if (pobj->type == ADDR_FOLDER) { - if (obj->type == ADDR_VCARD || obj->type == ADDR_JPILOT || obj->type == ADDR_LDAP) { - AddressFolder *folder = ADDRESS_FOLDER(pobj); - folder->items = g_list_append(folder->items, obj); + if( errFlag ) { + debug_print( "Error\n%s\n", msg ); + alertpanel( _( "Sylpheed Addressbook Conversion Error" ), msg, _( "Close" ), NULL, NULL ); + } + else { + if( msg ) { + debug_print( "Warning\n%s\n", msg ); + alertpanel( _( "Sylpheed Addressbook Conversion" ), msg, _( "Close" ), NULL, NULL ); } } + if( msg ) g_free( msg ); + return retVal; +} - gtk_ctree_sort_node(ctree, node); +void addressbook_read_file( void ) { + AddressIndex *addrIndex = NULL; - return added; -} + debug_print( "Reading address index...\n" ); + if( _addressIndex_ ) { + debug_print( "address book already read!!!\n" ); + return; + } -static void addressbook_delete_object(AddressObject *obj) -{ - if (!obj) return; + addrIndex = addrindex_create_index(); - if (obj->type == ADDR_ITEM) { - AddressItem *item = ADDRESS_ITEM(obj); - - mgu_free_address( item ); - } else if (obj->type == ADDR_GROUP) { - AddressGroup *group = ADDRESS_GROUP(obj); - - g_free(group->name); - while (group->items != NULL) { - addressbook_delete_object - (ADDRESS_OBJECT(group->items->data)); - group->items = g_list_remove(group->items, - group->items->data); - } - g_free(group); - } else if (obj->type == ADDR_FOLDER) { - AddressFolder *folder = ADDRESS_FOLDER(obj); - - g_free(folder->name); - while (folder->items != NULL) { - addressbook_delete_object - (ADDRESS_OBJECT(folder->items->data)); - folder->items = g_list_remove(folder->items, - folder->items->data); - } - g_free(folder); - } - else if( obj->type == ADDR_VCARD ) { - AddressVCard *vcard = ADDRESS_VCARD(obj); - g_free( vcard->name ); - vcard_free( vcard->cardFile ); - vcard->cardFile = NULL; - vcard->items = NULL; - g_free( vcard ); + // Use new address book index. + addrindex_set_file_path( addrIndex, get_rc_dir() ); + addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE ); + addrindex_read_data( addrIndex ); + if( addrIndex->retVal == MGU_NO_FILE ) { + // Conversion required + printf( "Converting...\n" ); + if( addressbook_convert( addrIndex ) ) { + _addressIndex_ = addrIndex; + } } -#ifdef USE_JPILOT - else if( obj->type == ADDR_JPILOT ) { - AddressJPilot *jpilot = ADDRESS_JPILOT(obj); - g_free( jpilot->name ); - jpilot_free( jpilot->pilotFile ); - jpilot->pilotFile = NULL; - jpilot->items = NULL; - g_free( jpilot ); + else if( addrIndex->retVal == MGU_SUCCESS ) { + _addressIndex_ = addrIndex; } -#endif -#ifdef USE_LDAP - else if( obj->type == ADDR_LDAP ) { - AddressLDAP *ldapi = ADDRESS_LDAP(obj); - g_free( ldapi->name ); - syldap_free( ldapi->ldapServer ); - ldapi->ldapServer = NULL; - ldapi->items = NULL; - g_free( ldapi ); + else { + // Error reading address book + gchar *msg = NULL; + debug_print( "Could not read address index.\n" ); + addrindex_print_index( addrIndex, stdout ); + msg = g_strdup( _( "Could not read address index" ) ); + alertpanel( _( "Sylpheed Addressbook Error" ), msg, _( "Close" ), NULL, NULL ); + g_free( msg ); } -#endif + debug_print( "done.\n" ); } -static AddressObject *addressbook_find_object_by_name(GtkCTreeNode *node, - const gchar *name) -{ - GtkCTree *ctree = GTK_CTREE(addrbook.ctree); - AddressObject *obj; - GList *found; - - g_return_val_if_fail(node != NULL, NULL); - - obj = gtk_ctree_node_get_row_data(ctree, node); - g_return_val_if_fail(obj != NULL, NULL); - - if (obj->type == ADDR_GROUP) { - AddressGroup *group = ADDRESS_GROUP(obj); +void addressbook_read_file_old( void ) { + AddressIndex *addrIndex = NULL; + gboolean errFlag = TRUE; + gchar *msg = NULL; - found = g_list_find_custom(group->items, (gpointer)name, - addressbook_obj_name_compare); - if (found) return ADDRESS_OBJECT(found->data); - } else if (obj->type == ADDR_FOLDER) { - AddressFolder *folder = ADDRESS_FOLDER(obj); - - found = g_list_find_custom(folder->items, (gpointer)name, - addressbook_obj_name_compare); - if (found) return ADDRESS_OBJECT(found->data); - } else if (obj->type == ADDR_ITEM) { - if (!addressbook_obj_name_compare(obj, name)) return obj; + if( _addressIndex_ ) { + debug_print( "address book already read!!!\n" ); + return; } - return NULL; -} - -static AddressItem *addressbook_parse_item(XMLFile *file) -{ - gchar *element; - AddressItem *item; - guint level; - - item = mgu_create_address(); - ADDRESS_OBJECT(item)->type = ADDR_ITEM; - - level = file->level; - - while (xml_parse_next_tag(file) == 0) { - if (file->level < level) return item; - if (file->level == level) break; - - element = xml_get_element(file); - - if (xml_compare_tag(file, "name")) { - item->name = element; - } else if (xml_compare_tag(file, "address")) { - item->address = element; - } else if (xml_compare_tag(file, "remarks")) { - item->remarks = element; + addrIndex = addrindex_create_index(); + + // Use use new address book. + // addrindex_set_file_path( addrIndex, "/home/match/tmp/empty-dir" ); + addrindex_set_file_path( addrIndex, get_rc_dir() ); + addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE ); + + debug_print( "Reading address index...\n" ); + addrindex_read_data( addrIndex ); + if( addrIndex->retVal == MGU_NO_FILE ) { + // Read old address book, performing conversion + debug_print( "Reading and converting old address book...\n" ); + addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE ); + addrindex_read_data( addrIndex ); + if( addrIndex->retVal == MGU_NO_FILE ) { + // We do not have a file - new user + debug_print( "New user... create new books...\n" ); + addrindex_create_new_books( addrIndex ); + if( addrIndex->retVal == MGU_SUCCESS ) { + // Save index file + addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE ); + addrindex_save_data( addrIndex ); + if( addrIndex->retVal == MGU_SUCCESS ) { + errFlag = FALSE; + } + else { + msg = g_strdup( _( "New user, could not save index file." ) ); + } + } + else { + msg = g_strdup( _( "New user, could not save address book files." ) ); + } + } + else { + // We have an old file + if( addrIndex->wasConverted ) { + // Converted successfully - save address index + addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE ); + addrindex_save_data( addrIndex ); + if( addrIndex->retVal == MGU_SUCCESS ) { + msg = g_strdup( _( "Old address book converted successfully." ) ); + errFlag = FALSE; + } + else { + msg = g_strdup( _( + "Old address book converted, " \ + "could not save new address index file" ) ); + } + } + else { + // File conversion failed - just create new books + debug_print( "File conversion failed... just create new books...\n" ); + addrindex_create_new_books( addrIndex ); + if( addrIndex->retVal == MGU_SUCCESS ) { + // Save index + addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE ); + addrindex_save_data( addrIndex ); + if( addrIndex->retVal == MGU_SUCCESS ) { + msg = g_strdup( _( + "Could not convert address book, " \ + "but created empty new address book files." ) ); + errFlag = FALSE; + } + else { + msg = g_strdup( _( + "Could not convert address book, " \ + "could not create new address book files." ) ); + } + } + else { + msg = g_strdup( _( + "Could not convert address book " \ + "and could not create new address book files." ) ); + } + } } - - if (xml_parse_next_tag(file) < 0) break; - if (file->level != level) break; } + else if( addrIndex->retVal == MGU_SUCCESS ) { + errFlag = FALSE; + } + else { + debug_print( "Could not read address index.\n" ); + addrindex_print_index( addrIndex, stdout ); + msg = g_strdup( _( "Could not read address index" ) ); + } + _addressIndex_ = addrIndex; - g_warning("addressbook_parse_item(): Parse error\n"); - mgu_free_address( item ); + if( errFlag ) { + debug_print( "Error\n%s\n", msg ); + alertpanel( _( "Sylpheed Addressbook Conversion Error" ), msg, _( "Close" ), NULL, NULL ); + } + else { + if( msg ) { + debug_print( "Warning\n%s\n", msg ); + alertpanel( _( "Sylpheed Addressbook Conversion" ), msg, _( "Close" ), NULL, NULL ); + } + } + if( msg ) g_free( msg ); + debug_print( "done.\n" ); } -void addressbook_export_to_file(void) +/* +* Add object into the address index tree widget. +* Enter: node Parent node. +* obj Object to add. +* Return: Node that was added, or NULL if object not added. +*/ +static GtkCTreeNode *addressbook_add_object(GtkCTreeNode *node, + AddressObject *obj) { - PrefFile *pfile; - gchar *path; + GtkCTree *ctree = GTK_CTREE(addrbook.ctree); + GtkCTreeNode *added; + AddressObject *pobj; + AddressObjectType otype; + AddressTypeControlItem *atci = NULL; - if (!addrbook.ctree) return; + g_return_val_if_fail(node != NULL, NULL); + g_return_val_if_fail(obj != NULL, NULL); - debug_print(_("Exporting addressbook to file...")); + pobj = gtk_ctree_node_get_row_data(ctree, node); + g_return_val_if_fail(pobj != NULL, NULL); - path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ADDRESS_BOOK, NULL); - if ((pfile = prefs_write_open(path)) == NULL) { - g_free(path); - return; + // Determine object type to be displayed + if( obj->type == ADDR_DATASOURCE ) { + otype = ADAPTER_DSOURCE(obj)->subType; } - g_free(path); - - fprintf(pfile->fp, "\n", - conv_get_current_charset_str()); - fputs("\n\n", pfile->fp); - - addressbook_xml_recursive_write(NULL, pfile->fp); - - fputs("\n", pfile->fp); - - if (prefs_write_close(pfile) < 0) { - g_warning(_("failed to write addressbook data.\n")); - return; + else { + otype = obj->type; } - debug_print(_("done.\n")); -} - -/* Most part of this function was taken from gtk_ctree_pre_recursive() and - gtk_ctree_post_recursive(). */ -static void addressbook_xml_recursive_write(GtkCTreeNode *node, FILE *fp) -{ - GtkCTreeNode *work; - GtkCTreeNode *tmp; - - if (node) { - work = GTK_CTREE_ROW(node)->children; - addressbook_node_write_begin(node, fp); - } else - work = GTK_CTREE_NODE(GTK_CLIST(addrbook.ctree)->row_list); - - while (work) { - tmp = GTK_CTREE_ROW(work)->sibling; - addressbook_xml_recursive_write(work, fp); - work = tmp; + // Handle any special conditions. + added = node; + atci = addrbookctl_lookup( otype ); + if( atci ) { + if( atci->showInTree ) { + // Add object to tree + gchar **name; + name = &obj->name; + added = gtk_ctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING, + atci->iconXpm, atci->maskXpm, atci->iconXpmOpen, atci->maskXpmOpen, + atci->treeLeaf, atci->treeExpand ); + gtk_ctree_node_set_row_data(ctree, added, obj); + } } - if (node) - addressbook_node_write_end(node, fp); + gtk_ctree_sort_node(ctree, node); + + return added; } -static void addressbook_node_write_begin(GtkCTreeNode *node, FILE *fp) -{ - AddressObject *obj; +/* +* Add group into the address index tree. +* Enter: node Parent node. +* ds Data source. +* itemGroup Group to add. +* Return: Inserted node. +*/ +static GtkCTreeNode *addressbook_node_add_group( GtkCTreeNode *node, AddressDataSource *ds, ItemGroup *itemGroup ) { + GtkCTree *ctree = GTK_CTREE(addrbook.ctree); + GtkCTreeNode *newNode; + AdapterGroup *adapter; + AddressTypeControlItem *atci = NULL; + gchar **name; - obj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), node); - g_return_if_fail(obj != NULL); + if( ds == NULL ) return; + if( node == NULL || itemGroup == NULL ) return; - if (obj->type == ADDR_FOLDER) { - AddressFolder *folder = ADDRESS_FOLDER(obj); + name = &itemGroup->obj.name; - if (GTK_CTREE_ROW(node)->level == 1) { - fprintf(fp, "<%s>\n", folder->name); - } else { - tab_indent_out(fp, GTK_CTREE_ROW(node)->level - 1); - fputs("name); - fputs("\">\n", fp); - } - } else if (obj->type == ADDR_GROUP) { - AddressGroup *group = ADDRESS_GROUP(obj); + atci = addrbookctl_lookup( ADDR_ITEM_GROUP ); - tab_indent_out(fp, GTK_CTREE_ROW(node)->level - 1); - fputs("name); - fputs("\">\n", fp); - } + adapter = g_new0( AdapterGroup, 1 ); + ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP; + ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemGroup) ); + adapter->itemGroup = itemGroup; + + newNode = gtk_ctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING, + atci->iconXpm, atci->maskXpm, atci->iconXpm, atci->maskXpm, + atci->treeLeaf, atci->treeExpand ); + gtk_ctree_node_set_row_data( ctree, newNode, adapter ); + gtk_ctree_sort_node( ctree, node ); + return newNode; } -static void addressbook_node_write_end(GtkCTreeNode *node, FILE *fp) +/* +* Add folder into the address index tree. +* Enter: node Parent node. +* ds Data source. +* itemFolder Folder to add. +* otype Object type to display. +* Return: Inserted node. +*/ +static GtkCTreeNode *addressbook_node_add_folder( + GtkCTreeNode *node, AddressDataSource *ds, ItemFolder *itemFolder, AddressObjectType otype ) { - AddressObject *obj; - - obj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), node); - g_return_if_fail(obj != NULL); - - if (obj->type == ADDR_FOLDER) { - AddressFolder *folder = ADDRESS_FOLDER(obj); - - addressbook_write_items(fp, folder->items, - GTK_CTREE_ROW(node)->level); - - if (GTK_CTREE_ROW(node)->level == 1) { - fprintf(fp, "\n\n", folder->name); - } else { - tab_indent_out(fp, GTK_CTREE_ROW(node)->level - 1); - fputs("\n", fp); - } - } else if (obj->type == ADDR_GROUP) { - AddressGroup *group = ADDRESS_GROUP(obj); + GtkCTree *ctree = GTK_CTREE(addrbook.ctree); + GtkCTreeNode *newNode = NULL; + AdapterFolder *adapter; + AddressTypeControlItem *atci = NULL; + GList *listItems = NULL; + gchar **name; + ItemFolder *rootFolder; - addressbook_write_items(fp, group->items, - GTK_CTREE_ROW(node)->level); + if( ds == NULL ) return NULL; + if( node == NULL || itemFolder == NULL ) return NULL; - tab_indent_out(fp, GTK_CTREE_ROW(node)->level - 1); - fputs("\n", fp); - } - else if (obj->type == ADDR_VCARD) { - AddressVCard *vcard = ADDRESS_VCARD(obj); - addressbook_write_vcard( fp, vcard, GTK_CTREE_ROW(node)->level); - } -#ifdef USE_JPILOT - else if (obj->type == ADDR_JPILOT) { - AddressJPilot *jpilot = ADDRESS_JPILOT(obj); - addressbook_write_jpilot( fp, jpilot, GTK_CTREE_ROW(node)->level); - } -#endif -#ifdef USE_LDAP - else if (obj->type == ADDR_LDAP) { - AddressLDAP *ldap = ADDRESS_LDAP(obj); - addressbook_write_ldap( fp, ldap, GTK_CTREE_ROW(node)->level); + // Determine object type + atci = addrbookctl_lookup( otype ); + if( atci == NULL ) return NULL; + + rootFolder = addrindex_ds_get_root_folder( ds ); + if( itemFolder == rootFolder ) { + newNode = node; } -#endif -} + else { + name = &itemFolder->obj.name; -static void addressbook_write_items(FILE *fp, GList *items, guint level) -{ - AddressItem *item; + adapter = g_new0( AdapterFolder, 1 ); + ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER; + ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemFolder) ); + adapter->itemFolder = itemFolder; - for (; items != NULL; items = items->next) { - if (ADDRESS_OBJECT_TYPE(items->data) == ADDR_ITEM) { - item = ADDRESS_ITEM(items->data); + newNode = gtk_ctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING, + atci->iconXpm, atci->maskXpm, atci->iconXpm, atci->maskXpm, + atci->treeLeaf, atci->treeExpand ); + gtk_ctree_node_set_row_data( ctree, newNode, adapter ); + } - tab_indent_out(fp, level); - fputs("\n", fp); + listItems = itemFolder->listFolder; + while( listItems ) { + ItemFolder *item = listItems->data; + addressbook_node_add_folder( newNode, ds, item, otype ); + listItems = g_list_next( listItems ); + } + listItems = itemFolder->listGroup; + while( listItems ) { + ItemGroup *item = listItems->data; + addressbook_node_add_group( newNode, ds, item ); + listItems = g_list_next( listItems ); + } + gtk_ctree_sort_node( ctree, node ); + return newNode; +} - tab_indent_out(fp, level + 1); - fputs("", fp); - xml_file_put_escape_str(fp, item->name); - fputs("\n", fp); +static void addressbook_delete_object(AddressObject *obj) { + AdapterDSource *ads = NULL; + AddressDataSource *ds = NULL; + if (!obj) return; - tab_indent_out(fp, level + 1); - fputs("
", fp); - xml_file_put_escape_str(fp, item->address); - fputs("
\n", fp); + // Remove data source. + printf( "Delete obj type : %d\n", obj->type ); - tab_indent_out(fp, level + 1); - fputs("", fp); - xml_file_put_escape_str(fp, item->remarks); - fputs("\n", fp); + ads = ADAPTER_DSOURCE(obj); + if( ads == NULL ) return; + ds = ads->dataSource; + if( ds == NULL ) return; - tab_indent_out(fp, level); - fputs("
\n", fp); - } + // Remove data source + if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) { + addrindex_free_datasource( _addressIndex_, ds ); } + // Free up Adapter object + g_free( ADAPTER_DSOURCE(obj) ); } -static void tab_indent_out(FILE *fp, guint level) -{ - gint i; +void addressbook_export_to_file( void ) { + if( _addressIndex_ ) { + // Save all new address book data + debug_print( "Saving address books...\n" ); + addrindex_save_all_books( _addressIndex_ ); + + debug_print( "Exporting addressbook to file...\n" ); + addrindex_save_data( _addressIndex_ ); + if( _addressIndex_->retVal != MGU_SUCCESS ) { + addrindex_print_index( _addressIndex_, stdout ); + } - for (i = 0; i < level; i++) - fputs(" ", fp); + // Notify address completion of new data + invalidate_address_completion(); + } } static void key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data) @@ -2736,277 +2734,95 @@ static void key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data) addressbook_close(); } +/* +* Comparsion using names of AddressItem objects. +*/ +/* static gint addressbook_list_compare_func(GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2) { AddressObject *obj1 = ((GtkCListRow *)ptr1)->data; AddressObject *obj2 = ((GtkCListRow *)ptr2)->data; - gchar *name1, *name2; - - if (obj1) { - if (obj1->type == ADDR_ITEM) - name1 = ADDRESS_ITEM(obj1)->name; - else if (obj1->type == ADDR_GROUP) - name1 = ADDRESS_GROUP(obj1)->name; - else if (obj1->type == ADDR_FOLDER) - name1 = ADDRESS_FOLDER(obj1)->name; - else if (obj1->type == ADDR_VCARD) - name1 = ADDRESS_VCARD(obj1)->name; -#ifdef USE_JPILOT - else if (obj1->type == ADDR_JPILOT) - name1 = ADDRESS_JPILOT(obj1)->name; - else if (obj1->type == ADDR_CATEGORY) - name1 = ADDRESS_CATEGORY(obj1)->name; -#endif -#ifdef USE_LDAP - else if (obj1->type == ADDR_LDAP) - name1 = ADDRESS_LDAP(obj1)->name; -#endif - else - name1 = NULL; - } else - name1 = NULL; - - if (obj2) { - if (obj2->type == ADDR_ITEM) - name2 = ADDRESS_ITEM(obj2)->name; - else if (obj2->type == ADDR_GROUP) - name2 = ADDRESS_GROUP(obj2)->name; - else if (obj2->type == ADDR_FOLDER) - name2 = ADDRESS_FOLDER(obj2)->name; - else if (obj2->type == ADDR_VCARD) - name2 = ADDRESS_VCARD(obj2)->name; -#ifdef USE_JPILOT - else if (obj2->type == ADDR_JPILOT) - name2 = ADDRESS_JPILOT(obj2)->name; - else if (obj2->type == ADDR_CATEGORY) - name2 = ADDRESS_CATEGORY(obj2)->name; -#endif -#ifdef USE_LDAP - else if (obj2->type == ADDR_LDAP) - name2 = ADDRESS_LDAP(obj2)->name; -#endif - else - name2 = NULL; - } else - name2 = NULL; - - if (!name1) - return (name2 != NULL); - if (!name2) - return -1; - + gchar *name1 = NULL, *name2 = NULL; + if( obj1 ) name1 = obj1->name; + if( obj2 ) name2 = obj2->name; + if( ! name1 ) return ( name2 != NULL ); + if( ! name2 ) return -1; return strcasecmp(name1, name2); } +*/ + +/* +* Comparison using cell contents (text in first column). +*/ +static gint addressbook_list_compare_func( GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2 ) { + GtkCell *cell1 = ((GtkCListRow *)ptr1)->cell; + GtkCell *cell2 = ((GtkCListRow *)ptr2)->cell; + gchar *name1 = NULL, *name2 = NULL; + if( cell1 ) name1 = cell1->u.text; + if( cell2 ) name2 = cell2->u.text; + if( ! name1 ) return ( name2 != NULL ); + if( ! name2 ) return -1; + return strcasecmp( name1, name2 ); +} -static gint addressbook_obj_name_compare(gconstpointer a, gconstpointer b) +/* static */ +gint addressbook_obj_name_compare(gconstpointer a, gconstpointer b) { const AddressObject *obj = a; const gchar *name = b; + AddressTypeControlItem *atci = NULL; if (!obj || !name) return -1; - if (obj->type == ADDR_GROUP) { - AddressGroup *group = ADDRESS_GROUP(obj); - if (!group->name) - return -1; - else - return strcasecmp(group->name, name); - } else if (obj->type == ADDR_FOLDER) { - AddressFolder *folder = ADDRESS_FOLDER(obj); - if (!folder->name) - return -1; - else - return strcasecmp(folder->name, name); - } - else if (obj->type == ADDR_VCARD) { - AddressVCard *vcard = ADDRESS_VCARD(obj); - if (!vcard->name) - return -1; - else - return strcasecmp(vcard->name, name); - } -#ifdef USE_JPILOT - else if (obj->type == ADDR_JPILOT) { - AddressJPilot *jpilot = ADDRESS_JPILOT(obj); - if (!jpilot->name) - return -1; - else - return strcasecmp(jpilot->name, name); - } - else if (obj->type == ADDR_CATEGORY) { - AddressCategory *category = ADDRESS_CATEGORY(obj); - if (!category->name) - return -1; - else - return strcasecmp(category->name, name); - } -#endif -#ifdef USE_LDAP - else if (obj->type == ADDR_LDAP) { - AddressLDAP *server = ADDRESS_LDAP(obj); - if (!server->name) - return -1; - else - return strcasecmp(server->name, name); - } -#endif - else if (obj->type == ADDR_ITEM) { - AddressItem *item = ADDRESS_ITEM(obj); - if (!item->name) - return -1; - else - return strcasecmp(item->name, name); - } else - return -1; + atci = addrbookctl_lookup( obj->type ); + if( ! atci ) return -1; + if( ! obj->name ) return -1; + return strcasecmp(obj->name, name); } -static AddressVCard *addressbook_parse_vcard(XMLFile *file) { - AddressVCard *item = NULL; - VCardFile *vcf; - GList *attr; - gchar *name, *value; - - vcf = vcard_create(); - attr = xml_get_current_tag_attr( file ); - while( attr ) { - name = ((XMLAttr *)attr->data)->name; - value = ((XMLAttr *)attr->data)->value; - if( strcmp( name, "name" ) == 0 ) { - vcard_set_name( vcf, value ); - } - else if( strcmp( name, "file" ) == 0) { - vcard_set_file( vcf, value ); +static void addressbook_book_show_message( AddressBookFile *abf ) { + *addressbook_msgbuf = '\0'; + if( abf ) { + if( abf->retVal == MGU_SUCCESS ) { + sprintf( addressbook_msgbuf, "%s", abf->name ); } - attr = g_list_next( attr ); - } - - // Move to next tag - if( xml_parse_next_tag( file ) >= 0 ) { - if( vcard_validate( vcf ) ) { - item = g_new( AddressVCard, 1 ); - ADDRESS_OBJECT(item)->type = ADDR_VCARD; - item->name = g_strdup( vcf->name ); - item->cardFile = vcf; - item->items = NULL; - return item; + else { + sprintf( addressbook_msgbuf, "%s: %s", abf->name, mgu_error2string( abf->retVal ) ); } } - - // Must be an invalid tag or data. - g_warning( "addressbook_parse_vcard(): Parse error\n"); - vcard_free( vcf ); - vcf = NULL; - item = NULL; - return NULL; -} - -static void addressbook_write_vcard( FILE *fp, AddressVCard *vcard, guint level ) { - VCardFile *cardFile = vcard->cardFile; - if( cardFile ) { - tab_indent_out(fp, 1); - fputs("name); - fputs("\"", fp); - fputs(" file=\"", fp); - xml_file_put_escape_str(fp, cardFile->path); - fputs("\"", fp); - fputs(" />\n", fp); - } + addressbook_status_show( addressbook_msgbuf ); } -#ifdef USE_JPILOT -static AddressJPilot *addressbook_parse_jpilot(XMLFile *file) { - AddressJPilot *item = NULL; - JPilotFile *jpf; - GList *attr; - gchar *name, *value; - - jpf = jpilot_create(); - attr = xml_get_current_tag_attr( file ); - while( attr ) { - name = ((XMLAttr *)attr->data)->name; - value = ((XMLAttr *)attr->data)->value; - if( strcmp( name, "name" ) == 0 ) { - jpilot_set_name( jpf, value ); - } - else if( strcmp( name, "file" ) == 0 ) { - jpilot_set_file( jpf, value ); - } - else if( strcmp( name, "custom-1" ) == 0 ) { - jpilot_add_custom_label( jpf, value ); - } - else if( strcmp( name, "custom-2" ) == 0 ) { - jpilot_add_custom_label( jpf, value ); - } - else if( strcmp( name, "custom-3" ) == 0 ) { - jpilot_add_custom_label( jpf, value ); - } - else if( strcmp( name, "custom-4" ) == 0 ) { - jpilot_add_custom_label( jpf, value ); - } - attr = g_list_next( attr ); - } - - // Move to next tag - if( xml_parse_next_tag( file ) >= 0 ) { - if( jpilot_validate( jpf ) ) { - item = g_new( AddressJPilot, 1 ); - ADDRESS_OBJECT(item)->type = ADDR_JPILOT; - item->name = g_strdup( jpf->name ); - item->pilotFile = jpf; - item->items = NULL; - return item; - } - } +static void addressbook_new_book_cb( gpointer data, guint action, GtkWidget *widget ) { + AdapterDSource *ads; + AdapterInterface *adapter; - // Must be an invalid tag or data. - g_warning( "addressbook_parse_jpilot(): Parse error\n"); - jpilot_free( jpf ); - jpf = NULL; - item = NULL; - return NULL; -} - -static void addressbook_write_jpilot( FILE *fp, AddressJPilot *jpilot, guint level ) { - JPilotFile *pilotFile = jpilot->pilotFile; - if( pilotFile ) { - gint ind; - GList *node; - GList *customLbl = jpilot_get_custom_labels( pilotFile ); - tab_indent_out(fp, 1); - fputs("name); - fputs("\" file=\"", fp); - xml_file_put_escape_str(fp, pilotFile->path); - - fputs( "\" ", fp ); - node = customLbl; - ind = 1; - while( node ) { - fprintf( fp, "custom-%d=\"", ind ); - xml_file_put_escape_str( fp, node->data ); - fputs( "\" ", fp ); - ind++; - node = g_list_next( node ); + adapter = addrbookctl_find_interface( ADDR_IF_BOOK ); + if( adapter == NULL ) return; + if( addrbook.treeSelected == NULL ) return; + if( addrbook.treeSelected != adapter->treeNode ) return; + ads = addressbook_edit_book( _addressIndex_, NULL ); + if( ads ) { + addressbook_add_object( addrbook.treeSelected, ADDRESS_OBJECT(ads) ); + if( addrbook.treeSelected == addrbook.opened ) { + gtk_ctree_select( GTK_CTREE(addrbook.ctree), addrbook.opened ); } - fputs("/>\n", fp); } } -#endif static void addressbook_new_vcard_cb( gpointer data, guint action, GtkWidget *widget ) { - AddressVCard *vcard; - - if( addrbook.selected != addrbook.vcard ) return; - vcard = addressbook_edit_vcard( NULL ); - if( vcard ) { - addressbook_add_object( addrbook.selected, ADDRESS_OBJECT(vcard) ); - if( addrbook.selected == addrbook.opened ) { - addrbook.open_folder = TRUE; + AdapterDSource *ads; + AdapterInterface *adapter; + + adapter = addrbookctl_find_interface( ADDR_IF_VCARD ); + if( adapter == NULL ) return; + if( addrbook.treeSelected != adapter->treeNode ) return; + ads = addressbook_edit_vcard( _addressIndex_, NULL ); + if( ads ) { + addressbook_add_object( addrbook.treeSelected, ADDRESS_OBJECT(ads) ); + if( addrbook.treeSelected == addrbook.opened ) { gtk_ctree_select( GTK_CTREE(addrbook.ctree), addrbook.opened ); } } @@ -3027,15 +2843,19 @@ static void addressbook_vcard_show_message( VCardFile *vcf ) { #ifdef USE_JPILOT static void addressbook_new_jpilot_cb( gpointer data, guint action, GtkWidget *widget ) { - AddressJPilot *jpilot; - - if( addrbook.selected != addrbook.jpilot ) return; - if( ! _have_pilot_library_ ) return; - jpilot = addressbook_edit_jpilot( NULL ); - if( jpilot ) { - addressbook_add_object( addrbook.selected, ADDRESS_OBJECT(jpilot) ); - if( addrbook.selected == addrbook.opened ) { - addrbook.open_folder = TRUE; + AdapterDSource *ads; + AdapterInterface *adapter; + AddressInterface *iface; + + adapter = addrbookctl_find_interface( ADDR_IF_JPILOT ); + if( adapter == NULL ) return; + if( addrbook.treeSelected != adapter->treeNode ) return; + iface = adapter->interface; + if( ! iface->haveLibrary ) return; + ads = addressbook_edit_jpilot( _addressIndex_, NULL ); + if( ads ) { + addressbook_add_object( addrbook.treeSelected, ADDRESS_OBJECT(ads) ); + if( addrbook.treeSelected == addrbook.opened ) { gtk_ctree_select( GTK_CTREE(addrbook.ctree), addrbook.opened ); } } @@ -3058,105 +2878,24 @@ static void addressbook_jpilot_show_message( JPilotFile *jpf ) { #ifdef USE_LDAP static void addressbook_new_ldap_cb( gpointer data, guint action, GtkWidget *widget ) { - AddressLDAP *ldapi; - - if( addrbook.selected != addrbook.ldap ) return; - if( ! _have_ldap_library_ ) return; - ldapi = addressbook_edit_ldap( NULL ); - if( ldapi ) { - addressbook_add_object( addrbook.selected, ADDRESS_OBJECT(ldapi) ); - if( addrbook.selected == addrbook.opened ) { - addrbook.open_folder = TRUE; + AdapterDSource *ads; + AdapterInterface *adapter; + AddressInterface *iface; + + adapter = addrbookctl_find_interface( ADDR_IF_LDAP ); + if( adapter == NULL ) return; + if( addrbook.treeSelected != adapter->treeNode ) return; + iface = adapter->interface; + if( ! iface->haveLibrary ) return; + ads = addressbook_edit_ldap( _addressIndex_, NULL ); + if( ads ) { + addressbook_add_object( addrbook.treeSelected, ADDRESS_OBJECT(ads) ); + if( addrbook.treeSelected == addrbook.opened ) { gtk_ctree_select( GTK_CTREE(addrbook.ctree), addrbook.opened ); } } } -static AddressLDAP *addressbook_parse_ldap(XMLFile *file) { - AddressLDAP *item = NULL; - SyldapServer *server; - GList *attr; - gchar *name, *value; - gint ivalue; - - server = syldap_create(); - attr = xml_get_current_tag_attr( file ); - while( attr ) { - name = ((XMLAttr *)attr->data)->name; - value = ((XMLAttr *)attr->data)->value; - ivalue = atoi( value ); - if( strcmp( name, "name" ) == 0 ) { - syldap_set_name( server, value ); - } - else if( strcmp( name, "host" ) == 0 ) { - syldap_set_host( server, value ); - } - else if( strcmp( name, "port" ) == 0 ) { - syldap_set_port( server, ivalue ); - } - else if( strcmp( name, "base-dn" ) == 0 ) { - syldap_set_base_dn( server, value ); - } - else if( strcmp( name, "bind-dn" ) == 0 ) { - syldap_set_bind_dn( server, value ); - } - else if( strcmp( name, "bind-pass" ) == 0 ) { - syldap_set_bind_password( server, value ); - } - else if( strcmp( name, "criteria" ) == 0 ) { - syldap_set_search_criteria( server, value ); - } - else if( strcmp( name, "max-entry" ) == 0 ) { - syldap_set_max_entries( server, ivalue ); - } - else if( strcmp( name, "timeout" ) == 0 ) { - syldap_set_timeout( server, ivalue ); - } - attr = g_list_next( attr ); - } - - // Move to next tag - if( xml_parse_next_tag( file ) >= 0 ) { - item = g_new( AddressLDAP, 1 ); - ADDRESS_OBJECT(item)->type = ADDR_LDAP; - item->name = g_strdup( server->name ); - item->ldapServer = server; - item->items = NULL; - return item; - } - - // Must be an invalid tag or data. - g_warning( "addressbook_parse_ldap(): Parse error\n"); - syldap_free( server ); - server = NULL; - item = NULL; - return NULL; -} - -static void addressbook_write_ldap( FILE *fp, AddressLDAP *ldapi, guint level ) { - SyldapServer *server = ldapi->ldapServer; - if( server ) { - tab_indent_out(fp, 1); - fputs("name); - fputs("\" host=\"", fp); - xml_file_put_escape_str(fp, server->hostName); - fprintf( fp, "\" port=\"%d", server->port); - fputs("\" base-dn=\"", fp); - xml_file_put_escape_str(fp, server->baseDN); - fputs("\" bind-dn=\"", fp); - xml_file_put_escape_str(fp, server->bindDN); - fputs("\" bind-pass=\"", fp); - xml_file_put_escape_str(fp, server->bindPass); - fputs("\" criteria=\"", fp); - xml_file_put_escape_str(fp, server->searchCriteria); - fprintf( fp, "\" max-entry=\"%d", server->maxEntries); - fprintf( fp, "\" timeout=\"%d", server->timeOut); - fputs("\" />\n", fp); - } -} - static void addressbook_ldap_show_message( SyldapServer *svr ) { *addressbook_msgbuf = '\0'; if( svr ) { @@ -3175,27 +2914,37 @@ static void addressbook_ldap_show_message( SyldapServer *svr ) { addressbook_status_show( addressbook_msgbuf ); } -static gint ldapsearch_callback( SyldapServer *sls ) { +static void ldapsearch_callback( SyldapServer *sls ) { GtkCTree *ctree = GTK_CTREE(addrbook.ctree); AddressObject *obj; + AdapterDSource *ads = NULL; + AddressDataSource *ds = NULL; + AddressInterface *iface = NULL; if( sls == NULL ) return; - if( ! addrbook.selected ) return; - if( GTK_CTREE_ROW( addrbook.selected )->level == 1 ) return; + if( ! addrbook.treeSelected ) return; + if( GTK_CTREE_ROW( addrbook.treeSelected )->level == 1 ) return; - obj = gtk_ctree_node_get_row_data( ctree, addrbook.selected ); + obj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected ); if( obj == NULL ) return; - if( obj->type == ADDR_LDAP ) { - AddressLDAP *ldapi = ADDRESS_LDAP(obj); - SyldapServer *server = ldapi->ldapServer; - if( server == sls ) { - if( ! _have_ldap_library_ ) return; - // Read from cache - gtk_widget_show_all(addrbook.window); - ADDRESS_LDAP(obj)->items = syldap_get_address_list( sls ); - addressbook_set_clist( obj ); - addressbook_ldap_show_message( sls ); - gtk_widget_show_all(addrbook.window); + if( obj->type == ADDR_DATASOURCE ) { + ads = ADAPTER_DSOURCE(obj); + if( ads->subType == ADDR_LDAP ) { + SyldapServer *server; + + ds = ads->dataSource; + if( ds == NULL ) return; + iface = ds->interface; + if( ! iface->haveLibrary ) return; + server = ds->rawDataSource; + if( server == sls ) { + // Read from cache + gtk_widget_show_all(addrbook.window); + addressbook_set_clist( obj ); + addressbook_ldap_show_message( sls ); + gtk_widget_show_all(addrbook.window); + gtk_entry_set_text( GTK_ENTRY(addrbook.entry), "" ); + } } } } @@ -3207,497 +2956,488 @@ static gint ldapsearch_callback( SyldapServer *sls ) { static void addressbook_lup_clicked( GtkButton *button, gpointer data ) { GtkCTree *ctree = GTK_CTREE(addrbook.ctree); AddressObject *obj; + AdapterDSource *ads = NULL; + AddressDataSource *ds = NULL; + AddressInterface *iface = NULL; gchar *sLookup; -#ifdef USE_LDAP - AddressLDAP *ldapi; - SyldapServer *server; -#endif sLookup = gtk_editable_get_chars( GTK_EDITABLE(addrbook.entry), 0, -1 ); g_strchomp( sLookup ); - if( ! addrbook.selected ) return; - if( GTK_CTREE_ROW( addrbook.selected )->level == 1 ) return; + if( ! addrbook.treeSelected ) return; + if( GTK_CTREE_ROW( addrbook.treeSelected )->level == 1 ) return; - obj = gtk_ctree_node_get_row_data( ctree, addrbook.selected ); + obj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected ); if( obj == NULL ) return; #ifdef USE_LDAP - if( obj->type == ADDR_LDAP ) { - ldapi = ADDRESS_LDAP(obj); - server = ldapi->ldapServer; - if( server ) { - if( ! _have_ldap_library_ ) return; - syldap_cancel_read( server ); - if( *sLookup == '\0' || strlen( sLookup ) < 1 ) return; - syldap_set_search_value( server, sLookup ); - syldap_set_callback( server, ldapsearch_callback ); - syldap_read_data_th( server ); - addressbook_ldap_show_message( server ); - } - } -#endif - -} - -/***/ - -typedef struct { - gboolean init; /* if FALSE should init jump buffer */ - GtkCTreeNode *node_found; /* match (can be used to backtrack folders) */ - AddressObject *addr_found; /* match */ - int level; /* current recursion level (0 is root level) */ - jmp_buf jumper; /* jump buffer */ -} FindObject; - -typedef struct { - FindObject ancestor; - const gchar *groupname; -} FindGroup; - -typedef struct { - FindObject ancestor; - const gchar *name; - const gchar *address; -} FindAddress; - -typedef struct { - FindObject ancestor; - GList *grouplist; -} FindAllGroups; - -typedef gboolean (*ADDRESSBOOK_TRAVERSE_FUNC)(AddressObject *node, gpointer data); - -/***/ - -static gboolean traverse_find_group_by_name(AddressObject *ao, FindGroup *find) -{ - AddressFolder *folder; - AddressGroup *group; + if( obj->type == ADDR_DATASOURCE ) { + ads = ADAPTER_DSOURCE(obj); + if( ads->subType == ADDR_LDAP ) { + SyldapServer *server; - /* a group or folder: both are groups */ - if (ADDRESS_OBJECT_TYPE(ao) == ADDR_GROUP) { - group = ADDRESS_GROUP(ao); - if (0 == g_strcasecmp(group->name, find->groupname)) { - return TRUE; - } - } - else if (ADDRESS_OBJECT_TYPE(ao) == ADDR_FOLDER) { - folder = ADDRESS_FOLDER(ao); - if (0 == g_strcasecmp(folder->name, find->groupname)) { - return TRUE; + ds = ads->dataSource; + if( ds == NULL ) return; + iface = ds->interface; + if( ! iface->haveLibrary ) return; + server = ds->rawDataSource; + if( server ) { + syldap_cancel_read( server ); + if( *sLookup == '\0' || strlen( sLookup ) < 1 ) return; + syldap_set_search_value( server, sLookup ); + syldap_set_callback( server, ldapsearch_callback ); + syldap_read_data_th( server ); + addressbook_ldap_show_message( server ); + } } } - return FALSE; -} +#endif -static gboolean traverse_find_name_email(AddressObject *ao, FindAddress *find) -{ - AddressItem *item; - if (ADDRESS_OBJECT_TYPE(ao) == ADDR_ITEM) { - gboolean nmatch = FALSE, amatch = FALSE; - item = ADDRESS_ITEM(ao); - /* conditions: - * o only match at the first characters in item strings - * o match either name or address */ - if (find->name && item->name) { - nmatch = item->name == strcasestr(item->name, find->name); - } - if (find->address && item->address) { - amatch = item->address == strcasestr(item->address, find->address); - } - return nmatch || amatch; - } - return FALSE; } -static gboolean traverse_find_all_groups(AddressObject *ao, FindAllGroups *find) -{ - /* NOTE: added strings come from the address book. should perhaps - * strdup() them, especially if the address book is invalidated */ - if (ADDRESS_OBJECT_TYPE(ao) == ADDR_FOLDER) { - AddressFolder *folder = ADDRESS_FOLDER(ao); - find->grouplist = g_list_insert_sorted(find->grouplist, (gpointer) folder->name, (GCompareFunc) g_strcasecmp); - } - else if (ADDRESS_OBJECT_TYPE(ao) == ADDR_GROUP) { - AddressGroup *group = ADDRESS_GROUP(ao); - find->grouplist = g_list_insert_sorted(find->grouplist, (gpointer) group->name, (GCompareFunc) g_strcasecmp); - } - return FALSE; -} +/* ********************************************************************** +* Build lookup tables. +* *********************************************************************** +*/ -/* addressbook_traverse() - traverses all address objects stored in the address book. - * for some reason gtkctree's recursive tree functions don't allow a premature return, - * which is what we need if we need to enumerate the tree and check for a condition - * and then skipping other nodes. */ -static AddressObject *addressbook_traverse(GtkCTreeNode *node, ADDRESSBOOK_TRAVERSE_FUNC func, FindObject *data, int level) -{ - GtkCTreeNode *current, *tmp; - AddressObject *ao; +/* +* Build table that controls the rendering of object types. +*/ +void addrbookctl_build_map( GtkWidget *window ) { + AddressTypeControlItem *atci; - if (data->init == FALSE) { - /* initialize non-local exit */ - data->init = TRUE; - data->level = 0; - /* HANDLE NON-LOCAL EXIT */ - if (setjmp(data->jumper)) { - return data->addr_found; - } - } + // Build icons + PIXMAP_CREATE(window, folderxpm, folderxpmmask, DIRECTORY_CLOSE_XPM); + PIXMAP_CREATE(window, folderopenxpm, folderopenxpmmask, DIRECTORY_OPEN_XPM); + PIXMAP_CREATE(window, groupxpm, groupxpmmask, group_xpm); + PIXMAP_CREATE(window, vcardxpm, vcardxpmmask, vcard_xpm); + PIXMAP_CREATE(window, bookxpm, bookxpmmask, book_xpm); + PIXMAP_CREATE(window, addressxpm, addressxpmmask, address_xpm); + PIXMAP_CREATE(window, jpilotxpm, jpilotxpmmask, jpilot_xpm); + PIXMAP_CREATE(window, categoryxpm, categoryxpmmask, category_xpm); + PIXMAP_CREATE(window, ldapxpm, ldapxpmmask, ldap_xpm); - /* actual recursive code */ - if (!node) { - current = GTK_CTREE_NODE(GTK_CLIST(addrbook.ctree)->row_list); - } - else { - current = node; - } - - while (current) { - tmp = GTK_CTREE_ROW(current)->sibling; - ao = (AddressObject *) gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), current); - if (ao) { - GList *next; - - next = (ADDRESS_OBJECT_TYPE(ao) == ADDR_FOLDER) ? - g_list_first(((ADDRESS_FOLDER(ao))->items)) : - (ADDRESS_OBJECT_TYPE(ao) == ADDR_GROUP) ? - g_list_first(((ADDRESS_GROUP(ao))->items)) : NULL; - - while (ao) { - /* NOTE: first iteration of the root calls callback for the tree - * node, other iterations call callback for the address book items */ - if (func(ao, data)) { - /* unwind */ - data->node_found = current; - data->addr_found = ao; - longjmp(data->jumper, 1); - } - /* ctree node only stores folders and groups. now descend into - * address object data, searching for address items. */ - for ( ; next && ADDRESS_OBJECT_TYPE((next->data)) != ADDR_ITEM - ; next = g_list_next(next)) - ; - ao = next ? (AddressObject *) next->data : NULL; - next = next ? g_list_next(next) : NULL; - } - } - /* check the children (if level permits) */ - if (level == -1 || data->level < level) { - current = GTK_CTREE_ROW(current)->children; - if (current) { - data->level++; - addressbook_traverse(current, func, data, level); - data->level--; - } - } - /* check the siblings */ - current = tmp; - } - return NULL; -} + _addressBookTypeHash_ = g_hash_table_new( g_int_hash, g_int_equal ); + _addressBookTypeList_ = NULL; + + // Interface + atci = g_new0( AddressTypeControlItem, 1 ); + atci->objectType = ADDR_INTERFACE; + atci->interfaceType = ADDR_IF_NONE; + atci->showInTree = TRUE; + atci->treeExpand = TRUE; + atci->treeLeaf = FALSE; + atci->displayName = _( "Interface" ); + atci->iconXpm = folderxpm; + atci->maskXpm = folderxpmmask; + atci->iconXpmOpen = folderopenxpm; + atci->maskXpmOpen = folderopenxpmmask; + atci->menuCommand = NULL; + g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci ); + _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci ); + + // Address book + atci = g_new0( AddressTypeControlItem, 1 ); + atci->objectType = ADDR_BOOK; + atci->interfaceType = ADDR_IF_BOOK; + atci->showInTree = TRUE; + atci->treeExpand = TRUE; + atci->treeLeaf = FALSE; + atci->displayName = _( "Address Book" ); + atci->iconXpm = bookxpm; + atci->maskXpm = bookxpmmask; + atci->iconXpmOpen = bookxpm; + atci->maskXpmOpen = bookxpmmask; + atci->menuCommand = "/File/New Book"; + g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci ); + _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci ); + + // Item person + atci = g_new0( AddressTypeControlItem, 1 ); + atci->objectType = ADDR_ITEM_PERSON; + atci->interfaceType = ADDR_IF_NONE; + atci->showInTree = FALSE; + atci->treeExpand = FALSE; + atci->treeLeaf = FALSE; + atci->displayName = _( "Person" ); + atci->iconXpm = NULL; + atci->maskXpm = NULL; + atci->iconXpmOpen = NULL; + atci->maskXpmOpen = NULL; + atci->menuCommand = NULL; + g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci ); + _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci ); + + // Item email + atci = g_new0( AddressTypeControlItem, 1 ); + atci->objectType = ADDR_ITEM_EMAIL; + atci->interfaceType = ADDR_IF_NONE; + atci->showInTree = FALSE; + atci->treeExpand = FALSE; + atci->treeLeaf = TRUE; + atci->displayName = _( "EMail Address" ); + atci->iconXpm = addressxpm; + atci->maskXpm = addressxpmmask; + atci->iconXpmOpen = addressxpm; + atci->maskXpmOpen = addressxpmmask; + atci->menuCommand = NULL; + g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci ); + _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci ); + + // Item group + atci = g_new0( AddressTypeControlItem, 1 ); + atci->objectType = ADDR_ITEM_GROUP; + atci->interfaceType = ADDR_IF_BOOK; + atci->showInTree = TRUE; + atci->treeExpand = FALSE; + atci->treeLeaf = FALSE; + atci->displayName = _( "Group" ); + atci->iconXpm = groupxpm; + atci->maskXpm = groupxpmmask; + atci->iconXpmOpen = groupxpm; + atci->maskXpmOpen = groupxpmmask; + atci->menuCommand = NULL; + g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci ); + _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci ); + + // Item folder + atci = g_new0( AddressTypeControlItem, 1 ); + atci->objectType = ADDR_ITEM_FOLDER; + atci->interfaceType = ADDR_IF_BOOK; + atci->showInTree = TRUE; + atci->treeExpand = FALSE; + atci->treeLeaf = FALSE; + atci->displayName = _( "Folder" ); + atci->iconXpm = folderxpm; + atci->maskXpm = folderxpmmask; + atci->iconXpmOpen = folderopenxpm; + atci->maskXpmOpen = folderopenxpmmask; + atci->menuCommand = NULL; + g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci ); + _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci ); + + // V-Card + atci = g_new0( AddressTypeControlItem, 1 ); + atci->objectType = ADDR_VCARD; + atci->interfaceType = ADDR_IF_VCARD; + atci->showInTree = TRUE; + atci->treeExpand = TRUE; + atci->treeLeaf = TRUE; + atci->displayName = _( "V-Card" ); + atci->iconXpm = vcardxpm; + atci->maskXpm = vcardxpmmask; + atci->iconXpmOpen = vcardxpm; + atci->maskXpmOpen = vcardxpmmask; + atci->menuCommand = "/File/New V-Card"; + g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci ); + _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci ); + + // J-Pilot + atci = g_new0( AddressTypeControlItem, 1 ); + atci->objectType = ADDR_JPILOT; + atci->interfaceType = ADDR_IF_JPILOT; + atci->showInTree = TRUE; + atci->treeExpand = TRUE; + atci->treeLeaf = FALSE; + atci->displayName = _( "J-Pilot" ); + atci->iconXpm = jpilotxpm; + atci->maskXpm = jpilotxpmmask; + atci->iconXpmOpen = jpilotxpm; + atci->maskXpmOpen = jpilotxpmmask; + atci->menuCommand = "/File/New J-Pilot"; + g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci ); + _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci ); + + // Category + atci = g_new0( AddressTypeControlItem, 1 ); + atci->objectType = ADDR_CATEGORY; + atci->interfaceType = ADDR_IF_JPILOT; + atci->showInTree = TRUE; + atci->treeExpand = TRUE; + atci->treeLeaf = TRUE; + atci->displayName = _( "J-Pilot" ); + atci->iconXpm = categoryxpm; + atci->maskXpm = categoryxpmmask; + atci->iconXpmOpen = categoryxpm; + atci->maskXpmOpen = categoryxpmmask; + atci->menuCommand = NULL; + g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci ); + _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci ); + + // LDAP Server + atci = g_new0( AddressTypeControlItem, 1 ); + atci->objectType = ADDR_LDAP; + atci->interfaceType = ADDR_IF_LDAP; + atci->showInTree = TRUE; + atci->treeExpand = TRUE; + atci->treeLeaf = TRUE; + atci->displayName = _( "LDAP Server" ); + atci->iconXpm = ldapxpm; + atci->maskXpm = ldapxpmmask; + atci->iconXpmOpen = ldapxpm; + atci->maskXpmOpen = ldapxpmmask; + atci->menuCommand = "/File/New Server"; + g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci ); + _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci ); -static GtkCTreeNode *addressbook_get_group_node(const gchar *name) -{ - FindGroup fg = { { FALSE, NULL, NULL }, NULL }; - fg.groupname = name; - addressbook_traverse(NULL, (void *)traverse_find_group_by_name, (FindObject *)&fg, -1); - return fg.ancestor.node_found; } -static void addressbook_free_item(AddressItem *item) -{ - if (item) { - if (item->name) g_free(item->name); - if (item->address) g_free(item->address); - if (item->remarks) g_free(item->remarks); - g_free(item); - } +/* +* Search for specified object type. +*/ +AddressTypeControlItem *addrbookctl_lookup( gint ot ) { + gint objType = ot; + return ( AddressTypeControlItem * ) g_hash_table_lookup( _addressBookTypeHash_, &objType ); } -static AddressItem *addressbook_alloc_item(const gchar *name, const gchar *address, const gchar *remarks) -{ - AddressItem *item = g_new0(AddressItem, 1); - - if (item) { - item->obj.type = ADDR_ITEM; - if (item->name = g_strdup(name)) - if (item->address = g_strdup(address)) { - if (remarks) { - item->remarks = g_strdup(remarks); - } - return item; - } +/* +* Search for specified interface type. +*/ +AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ) { + GList *node = _addressBookTypeList_; + while( node ) { + AddressTypeControlItem *atci = node->data; + if( atci->interfaceType == ifType ) return atci; + node = g_list_next( node ); } - addressbook_free_item(item); return NULL; } -/***/ - -/* public provisional API */ - -/* addressbook_access() - should be called before using any of the following apis. it - * reloads the address book. */ -void addressbook_access(void) -{ - log_message("accessing address book\n"); - if (!addrbook.window) { - addressbook_create(FALSE); - addressbook_read_file(); - addrbook.open_folder = TRUE; - gtk_ctree_select(GTK_CTREE(addrbook.ctree), GTK_CTREE_NODE(GTK_CLIST(addrbook.ctree)->row_list)); - } -} - -/* addressbook_unaccess() - should only be called after changing the address book's - * contents */ -void addressbook_unaccess(void) -{ - log_message("unaccessing address book\n"); - addressbook_export_to_file(); - invalidate_address_completion(); -} - -const gchar *addressbook_get_personal_folder_name(void) -{ - return _("Personal addresses"); /* human readable */ +static void addrbookctl_free_address( AddressObject *obj ) { + g_free( obj->name ); + obj->type = ADDR_NONE; + obj->name = NULL; } -const gchar *addressbook_get_common_folder_name(void) -{ - return _("Common addresses"); /* human readable */ +static void addrbookctl_free_interface( AdapterInterface *adapter ) { + addrbookctl_free_address( ADDRESS_OBJECT(adapter) ); + adapter->interface = NULL; + adapter->interfaceType = ADDR_IF_NONE; + adapter->atci = NULL; + adapter->enabled = FALSE; + adapter->haveLibrary = FALSE; + adapter->treeNode = NULL; + g_free( adapter ); } -/* addressbook_find_group_by_name() - finds a group (folder or group) by - * its name */ -AddressObject *addressbook_find_group_by_name(const gchar *name) -{ - FindGroup fg = { { FALSE, NULL, NULL } }; - AddressObject *ao; - - /* initialize obj members */ - fg.groupname = name; - ao = addressbook_traverse(NULL, - (ADDRESSBOOK_TRAVERSE_FUNC)traverse_find_group_by_name, - (FindObject *)&fg, -1); - return ao; +static void addrbookctl_free_datasource( AdapterDSource *adapter ) { + addrbookctl_free_address( ADDRESS_OBJECT(adapter) ); + adapter->dataSource = NULL; + adapter->subType = ADDR_NONE; + g_free( adapter ); } -/* addressbook_find_contact() - finds an address item by either name or address - * or both. the comparison is done on the first few characters of the strings */ -AddressObject *addressbook_find_contact(const gchar *name, const gchar *address) -{ - FindAddress fa = { { FALSE, NULL, NULL } }; - AddressObject *ao; - - fa.name = name; - fa.address = address; - ao = addressbook_traverse(NULL, (ADDRESSBOOK_TRAVERSE_FUNC)traverse_find_name_email, - (FindObject *)&fa, -1); - return ao; +static void addrbookctl_free_folder( AdapterFolder *adapter ) { + addrbookctl_free_address( ADDRESS_OBJECT(adapter) ); + adapter->itemFolder = NULL; + g_free( adapter ); } -/* addressbook_get_group_list() - returns a list of strings with group names (both - * groups and folders). free the list using g_list_free(). note that another - * call may invalidate the returned list */ -GList *addressbook_get_group_list(void) -{ - FindAllGroups fag = { { FALSE, NULL, NULL }, NULL }; - addressbook_traverse(NULL, (ADDRESSBOOK_TRAVERSE_FUNC)traverse_find_all_groups, - (FindObject *)&fag, -1); - return fag.grouplist; +static void addrbookctl_free_group( AdapterGroup *adapter ) { + addrbookctl_free_address( ADDRESS_OBJECT(adapter) ); + adapter->itemGroup = NULL; + g_free( adapter ); } -/* addressbook_add_contact() - adds a contact to the address book. returns 1 - * if succesful else error */ -gint addressbook_add_contact(const gchar *group, const gchar *name, const gchar *address, - const gchar *remarks) -{ - GtkCTreeNode *node; - AddressItem *item; - FindAddress fa = { { FALSE, NULL, NULL } }; - - /* a healthy mix of hiro's and my code */ - if (name == NULL || strlen(name) == 0 - || address == NULL || strlen(address) == 0 - || group == NULL || strlen(group) == 0) { - return __LINE__; - } - node = addressbook_get_group_node(group); - if (!node) { - return __LINE__; - } - - /* check if it's already in this group */ - fa.name = name; - fa.address = address; +/* + * Build GUI interface list. + */ +void addrbookctl_build_iflist() { + AddressTypeControlItem *atci; + AdapterInterface *adapter; + GList *list = NULL; - if (addressbook_traverse(node, (gpointer)traverse_find_name_email, (gpointer)&fa, 0)) { - log_message("address <%s> already in %s\n", address, group); - return __LINE__; + if( _addressIndex_ == NULL ) { + _addressIndex_ = addrindex_create_index(); } - - item = addressbook_alloc_item(name, address, remarks); - if (!item) { - return __LINE__; + _addressInterfaceList_ = NULL; + list = addrindex_get_interface_list( _addressIndex_ ); + while( list ) { + AddressInterface *interface = list->data; + atci = addrbookctl_lookup_iface( interface->type ); + if( atci ) { + adapter = g_new0( AdapterInterface, 1 ); + adapter->interfaceType = interface->type; + adapter->atci = atci; + adapter->interface = interface; + adapter->treeNode = NULL; + adapter->enabled = TRUE; + adapter->haveLibrary = interface->haveLibrary; + ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE; + ADDRESS_OBJECT_NAME(adapter) = g_strdup( atci->displayName ); + _addressInterfaceList_ = g_list_append( _addressInterfaceList_, adapter ); + } + list = g_list_next( list ); } +} - if (!addressbook_add_object(node, (AddressObject *)item)) { - addressbook_free_item(item); - return __LINE__; +void addrbookctl_free_selection( GList *list ) { + GList *node = list; + while( node ) { + AdapterInterface *adapter = node->data; + adapter = NULL; + node = g_list_next( node ); } - - /* make sure it's updated if selected */ - log_message("updating addressbook widgets\n"); - addrbook.open_folder = TRUE; - gtk_ctree_select(GTK_CTREE(addrbook.ctree), addrbook.opened); - - /* not saved yet. only after unaccessing the address book */ - return 0; + g_list_free( list ); } -static void group_object_data_destroy(gchar *group) -{ - if (group) { - g_free(group); - } +/* +* Find GUI interface type specified interface type. +* Return: Interface item, or NULL if not found. +*/ +AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) { + GList *node = _addressInterfaceList_; + while( node ) { + AdapterInterface *adapter = node->data; + if( adapter->interfaceType == ifType ) return adapter; + node = g_list_next( node ); + } + return NULL; } -/***/ +/* +* Build interface list selection. +*/ +void addrbookctl_build_ifselect() { + GList *newList = NULL; + gchar *selectStr; + gchar **splitStr; + gint ifType; + gint i; + gchar *endptr = NULL; + gboolean enabled; + AdapterInterface *adapter; + GList *node; + + selectStr = g_strdup( ADDRESSBOOK_IFACE_SELECTION ); + + // Parse string + splitStr = g_strsplit( selectStr, ",", -1 ); + for( i = 0; i < ADDRESSBOOK_MAX_IFACE; i++ ) { + if( splitStr[i] ) { + // printf( "%d : %s\n", i, splitStr[i] ); + ifType = strtol( splitStr[i], &endptr, 10 ); + enabled = TRUE; + if( *endptr ) { + if( strcmp( endptr, "/n" ) == 0 ) { + enabled = FALSE; + } + } + // printf( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); + adapter = addrbookctl_find_interface( ifType ); + if( adapter ) { + newList = g_list_append( newList, adapter ); + } + } + else { + break; + } + } + // printf( "i=%d\n", i ); + g_strfreev( splitStr ); + g_free( selectStr ); -typedef struct { - gchar *name; - gchar *address; - gchar *remarks; -} ContactInfo; + // Replace existing list + mgu_clear_list( _addressIFaceSelection_ ); + g_list_free( _addressIFaceSelection_ ); + _addressIFaceSelection_ = newList; + newList = NULL; -static void addressbook_destroy_contact(ContactInfo *ci) -{ - g_return_if_fail(ci != NULL); - if (ci->name) g_free(ci->name); - if (ci->address) g_free(ci->address); - if (ci->remarks) g_free(ci->remarks); - g_free(ci); } -static ContactInfo *addressbook_new_contact(const gchar *name, const gchar *address, const gchar *remarks) -{ - ContactInfo *ci = g_new0(ContactInfo, 1); - - g_return_val_if_fail(ci != NULL, NULL); - g_return_val_if_fail(address != NULL, NULL); /* address should be valid */ - ci->name = name ? g_strdup(name) : NULL; - ci->address = g_strdup(address); - ci->remarks = remarks ? g_strdup(remarks) : NULL; - if (NULL == ci->address) { - addressbook_destroy_contact(ci); - ci = NULL; - } - return ci; -} +/* ********************************************************************** +* Add sender to address book. +* *********************************************************************** +*/ -static void addressbook_group_menu_selected(GtkMenuItem *menuitem, - ContactInfo *data) -{ - const gchar *group_name = (const gchar *) gtk_object_get_data(GTK_OBJECT(menuitem), - "group_name"); - - if (!group_name) { - g_warning("%s(%d) - invalid group name\n", __FILE__, __LINE__); - return ; +/* + * This function is used by the Add sender to address book function. + */ +gboolean addressbook_add_contact( const gchar *name, const gchar *address, const gchar *remarks ) { + debug_print( "addressbook_add_contact: name/address: %s - %s\n", name, address ); + if( addressadd_selection( _addressIndex_, name, address, remarks ) ) { + debug_print( "addressbook_add_contact - added\n" ); + addressbook_refresh(); } - g_return_if_fail(group_name != NULL); - - g_message("selected group %s from menu\n", group_name); - g_message("selected %s <%s>\n", data->name ? data->name : data->address, data->address); - - addressbook_access(); - addressbook_add_contact(group_name, data->name ? data->name : data->address, - data->address, data->remarks ? data->remarks : data->address); - addressbook_unaccess(); - - g_free(data); + return TRUE; } -/* addressbook_add_contact_by_meny() - launches menu with group items. submenu may be - * the menu item in the parent menu, or NULL for a normal right-click context menu */ -gboolean addressbook_add_submenu(GtkWidget *submenu, - const gchar *name, - const gchar *address, - const gchar *remarks) -{ - GtkWidget *menu, *menuitem; - GList *groups, *tmp; - ContactInfo *ci; +/* ********************************************************************** +* Address completion support. +* *********************************************************************** +*/ - ci = addressbook_new_contact(name, address, remarks); - g_return_val_if_fail(ci != NULL, FALSE); +/* +* This function is used by the address completion function to load +* addresses. +* Enter: callBackFunc Function to be called when an address is +* to be loaded. +* Return: TRUE if data loaded, FALSE if address index not loaded. +*/ +gboolean addressbook_load_completion( gint (*callBackFunc) ( const gchar *, const gchar * ) ) { + AddressInterface *interface; + AddressDataSource *ds; + GList *nodeIf, *nodeDS; + GList *listP, *nodeP; + GList *nodeM; + gchar *sName, *sAddress, *sAlias, *sFriendly; + + debug_print( "addressbook_load_completion\n" ); + + if( _addressIndex_ == NULL ) return FALSE; + + nodeIf = addrindex_get_interface_list( _addressIndex_ ); + while( nodeIf ) { + AddressInterface *interface = nodeIf->data; + nodeDS = interface->listSource; + while( nodeDS ) { + ds = nodeDS->data; + + // Read address book + if( ! addrindex_ds_get_read_flag( ds ) ) { + addrindex_ds_read_data( ds ); + } - addressbook_access(); - groups = addressbook_get_group_list(); - g_return_val_if_fail(groups != NULL, (addressbook_destroy_contact(ci), FALSE)); - - menu = gtk_menu_new(); - g_return_val_if_fail(menu != NULL, (g_list_free(groups), addressbook_destroy_contact(ci), FALSE)); + // Get all persons + listP = addrindex_ds_get_all_persons( ds ); + nodeP = listP; + while( nodeP ) { + ItemPerson *person = nodeP->data; + nodeM = person->listEMail; + + // Figure out name to use + sName = person->nickName; + if( sName == NULL || *sName == '\0' ) { + sName = ADDRITEM_NAME(person); + } - /* add groups to menu */ - for (tmp = g_list_first(groups); tmp != NULL; tmp = g_list_next(tmp)) { - const gchar *display_name; - gchar *original_name = (gchar *) tmp->data; - gboolean addItem = TRUE; + // Process each E-Mail address + while( nodeM ) { + ItemEMail *email = nodeM->data; + // Have mail + sFriendly = sName; + sAddress = email->address; + if( sAddress || *sAddress != '\0' ) { + sAlias = ADDRITEM_NAME(email); + if( sAlias && *sAlias != '\0' ) { + sFriendly = sAlias; + } + ( callBackFunc ) ( sFriendly, sAddress ); + } - if (!g_strcasecmp(original_name, ADDRESS_TAG_PERSONAL)) { - display_name = addressbook_get_personal_folder_name(); - } - else if (!g_strcasecmp(original_name, ADDRESS_TAG_COMMON)) { - display_name = addressbook_get_common_folder_name(); - } - else if( ! g_strcasecmp( original_name, ADDRESS_TAG_VCARD ) ) { - addItem = FALSE; - } -#ifdef USE_JPILOT - else if( ! g_strcasecmp( original_name, ADDRESS_TAG_JPILOT ) ) { - addItem = FALSE; - } -#endif -#ifdef USE_LDAP - else if( ! g_strcasecmp( original_name, ADDRESS_TAG_LDAP ) ) { - addItem = FALSE; - } -#endif - else { - display_name = original_name; - } + nodeM = g_list_next( nodeM ); + } + nodeP = g_list_next( nodeP ); + } + // Free up the list + g_list_free( listP ); - if( addItem ) { - original_name = g_strdup(original_name); - menuitem = gtk_menu_item_new_with_label(display_name); - /* register the duplicated string pointer as object data, - * so we get the opportunity to free it */ - gtk_object_set_data_full(GTK_OBJECT(menuitem), "group_name", - original_name, - (GtkDestroyNotify) group_object_data_destroy); - gtk_signal_connect(GTK_OBJECT(menuitem), "activate", - GTK_SIGNAL_FUNC(addressbook_group_menu_selected), - (gpointer)(ci)); - gtk_menu_append(GTK_MENU(menu), menuitem); - gtk_widget_show(menuitem); + nodeDS = g_list_next( nodeDS ); } + nodeIf = g_list_next( nodeIf ); } + debug_print( "addressbook_load_completion... done\n" ); - gtk_widget_show(menu); - - if (submenu) { - gtk_menu_item_set_submenu(GTK_MENU_ITEM(submenu), menu); - gtk_widget_set_sensitive(GTK_WIDGET(submenu), TRUE); - } - else { - gtk_widget_grab_focus(GTK_WIDGET(menu)); - gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 1, GDK_CURRENT_TIME); - } - - if (groups) g_list_free(groups); return TRUE; } diff --git a/src/addressbook.h b/src/addressbook.h index d459510df..7a0d5ad23 100644 --- a/src/addressbook.h +++ b/src/addressbook.h @@ -22,171 +22,27 @@ #include #include -#include -#include - -#include "addressitem.h" -#include "vcard.h" - -#ifdef USE_JPILOT -#include "jpilot.h" -#endif - -#ifdef USE_LDAP -#include "syldap.h" -#endif - -#define ADDRESS_GROUP(obj) ((AddressGroup *)obj) -#define ADDRESS_FOLDER(obj) ((AddressFolder *)obj) -#define ADDRESS_VCARD(obj) ((AddressVCard *)obj) -#define ADDRESS_JPILOT(obj) ((AddressJPilot *)obj) -#define ADDRESS_CATEGORY(obj) ((AddressCategory *)obj) -#define ADDRESS_LDAP(obj) ((AddressLDAP *)obj) - #include "compose.h" -typedef struct _AddressBook AddressBook; -struct _AddressBook -{ - GtkWidget *window; - GtkWidget *menubar; - GtkWidget *ctree; - GtkWidget *clist; - GtkWidget *entry; - GtkWidget *statusbar; - - GtkWidget *del_btn; - GtkWidget *reg_btn; - GtkWidget *lup_btn; - GtkWidget *to_btn; - GtkWidget *cc_btn; - GtkWidget *bcc_btn; - - GtkWidget *tree_popup; - GtkWidget *list_popup; - GtkItemFactory *tree_factory; - GtkItemFactory *list_factory; - GtkItemFactory *menu_factory; - - GtkCTreeNode *common; - GtkCTreeNode *personal; - GtkCTreeNode *vcard; - GtkCTreeNode *jpilot; - GtkCTreeNode *ldap; - GtkCTreeNode *selected; - GtkCTreeNode *opened; - - gboolean open_folder; - - Compose *target_compose; - gint status_cid; -}; - -typedef struct _AddressGroup AddressGroup; -struct _AddressGroup -{ - AddressObject obj; - - gchar *name; - - /* Group contains only Items */ - GList *items; -}; - -typedef struct _AddressFolder AddressFolder; -struct _AddressFolder -{ - AddressObject obj; - - gchar *name; - - /* Folder contains Groups and Items */ - GList *items; -}; - -typedef struct _AddressVCard AddressVCard; -struct _AddressVCard -{ - AddressObject obj; - - gchar *name; - VCardFile *cardFile; - - /* Folder contains only VCards */ - GList *items; -}; - -#ifdef USE_JPILOT -typedef struct _AddressJPilot AddressJPilot; -struct _AddressJPilot -{ - AddressObject obj; - - gchar *name; - JPilotFile *pilotFile; - - /* Folder contains only JPilotFiles */ - /* Folder contains only Items for each category */ - GList *items; -}; - -typedef struct _AddressCategory AddressCategory; -struct _AddressCategory -{ - AddressObject obj; - - gchar *name; - JPilotFile *pilotFile; - AddressItem *category; - - /* Category contains only Items */ - GList *items; -}; -#endif - -#ifdef USE_LDAP -typedef struct _AddressLDAP AddressLDAP; -struct _AddressLDAP -{ - AddressObject obj; - - gchar *name; - SyldapServer *ldapServer; - - /* Folder contains only SyldapServers */ - GList *items; -}; -#endif - -struct _AddressFileSelection { - GtkWidget *fileSelector; - gboolean cancelled; -}; -typedef struct _AddressFileSelection AddressFileSelection; - void addressbook_open (Compose *target); void addressbook_set_target_compose (Compose *target); Compose *addressbook_get_target_compose (void); void addressbook_export_to_file (void); +gint addressbook_obj_name_compare (gconstpointer a, + gconstpointer b); +// static gint addressbook_obj_name_compare(gconstpointer a, +// gconstpointer b); /* provisional API for accessing the address book */ void addressbook_access (void); void addressbook_unaccess (void); -const gchar *addressbook_get_personal_folder_name (void); -const gchar *addressbook_get_common_folder_name (void); - -AddressObject *addressbook_find_group_by_name (const gchar *name); -AddressObject *addressbook_find_contact (const gchar *name, const gchar *address); -GList *addressbook_get_group_list (void); -gint addressbook_add_contact (const gchar *group, const gchar *name, - const gchar *address, const gchar *remarks); +gboolean addressbook_add_contact ( const gchar *name, + const gchar *address, + const gchar *remarks ); -gboolean addressbook_add_submenu(GtkWidget *submenu, - const gchar *name, - const gchar *address, - const gchar *remarks); +gboolean addressbook_load_completion ( gint (*callBackFunc) ( const gchar *, const gchar * ) ); #endif /* __ADDRESSBOOK_H__ */ diff --git a/src/addressitem.h b/src/addressitem.h index 0886a9d87..80ceb9209 100644 --- a/src/addressitem.h +++ b/src/addressitem.h @@ -18,46 +18,141 @@ */ /* - * Address item data. + * Address item data. Shared among GUI components only. */ #ifndef __ADDRESSITEM_H__ #define __ADDRESSITEM_H__ +#include +#include +#include + +#include "compose.h" +#include "addrindex.h" + #define ADDRESS_OBJECT(obj) ((AddressObject *)obj) #define ADDRESS_OBJECT_TYPE(obj) (ADDRESS_OBJECT(obj)->type) -#define ADDRESS_ITEM(obj) ((AddressItem *)obj) +#define ADDRESS_OBJECT_NAME(obj) (ADDRESS_OBJECT(obj)->name) -#define ADDRESS_ITEM_CAT_UNKNOWN -1 - -typedef struct _AddressObject AddressObject; -typedef struct _AddressItem AddressItem; +#define ADAPTER_INTERFACE(obj) ((AdapterInterface *)obj) +#define ADAPTER_FOLDER(obj) ((AdapterFolder *)obj) +#define ADAPTER_GROUP(obj) ((AdapterGroup *)obj) +#define ADAPTER_DSOURCE(obj) ((AdapterDSource *)obj) -typedef enum -{ - ADDR_ITEM, - ADDR_GROUP, - ADDR_FOLDER, - ADDR_VCARD, - ADDR_JPILOT, - ADDR_CATEGORY, - ADDR_LDAP +typedef enum { + ADDR_NONE, + ADDR_ITEM_PERSON, + ADDR_ITEM_EMAIL, + ADDR_ITEM_FOLDER, + ADDR_ITEM_GROUP, + ADDR_INTERFACE, + ADDR_DATASOURCE, + ADDR_BOOK, // Sub-type + ADDR_VCARD, // Sub-type + ADDR_JPILOT, // Sub-type + ADDR_CATEGORY, // Sub-type + ADDR_LDAP // Sub-type } AddressObjectType; -struct _AddressObject +typedef struct _AddressBook_win AddressBook_win; +struct _AddressBook_win { + GtkWidget *window; + GtkWidget *menubar; + GtkWidget *ctree; + GtkWidget *clist; + GtkWidget *entry; + GtkWidget *statusbar; + + GtkWidget *del_btn; + GtkWidget *reg_btn; + GtkWidget *lup_btn; + GtkWidget *to_btn; + GtkWidget *cc_btn; + GtkWidget *bcc_btn; + + GtkWidget *tree_popup; + GtkWidget *list_popup; + GtkItemFactory *tree_factory; + GtkItemFactory *list_factory; + GtkItemFactory *menu_factory; + + GtkCTreeNode *treeSelected; + GtkCTreeNode *opened; + GtkCTreeNode *listSelected; + + Compose *target_compose; + gint status_cid; +}; + +typedef struct _AddressTypeControlItem AddressTypeControlItem; +struct _AddressTypeControlItem { + AddressObjectType objectType; + AddressIfType interfaceType; + gchar *displayName; + gboolean showInTree; + gboolean treeExpand; + gboolean treeLeaf; + gchar *menuCommand; + GdkPixmap *iconXpm; + GdkBitmap *maskXpm; + GdkPixmap *iconXpmOpen; + GdkBitmap *maskXpmOpen; +}; + +typedef struct _AddressObject AddressObject; +struct _AddressObject { AddressObjectType type; + gchar *name; }; -struct _AddressItem -{ +typedef struct _AdapterInterface AdapterInterface; +struct _AdapterInterface { AddressObject obj; + AddressInterface *interface; + AddressIfType interfaceType; + AddressTypeControlItem *atci; + gboolean enabled; + gboolean haveLibrary; + GtkCTreeNode *treeNode; +}; - gchar *name; - gchar *address; - gchar *remarks; - gchar *externalID; - gint categoryID; +typedef struct _AdapterDSource AdapterDSource; +struct _AdapterDSource { + AddressObject obj; + AddressDataSource *dataSource; + AddressObjectType subType; +}; + +typedef struct _AdapterFolder AdapterFolder; +struct _AdapterFolder { + AddressObject obj; + ItemFolder *itemFolder; +}; + +typedef struct _AdapterGroup AdapterGroup; +struct _AdapterGroup { + AddressObject obj; + ItemGroup *itemGroup; +}; + +typedef struct _AddressFileSelection AddressFileSelection; +struct _AddressFileSelection { + GtkWidget *fileSelector; + gboolean cancelled; }; +AdapterDSource *addressbook_create_ds_adapter ( AddressDataSource *ds, + AddressObjectType otype, + gchar *name ); + +void addressbook_ads_set_name ( AdapterDSource *adapter, + gchar *value ); + #endif /* __ADDRESSITEM_H__ */ + +/* +* End of Source. +*/ + diff --git a/src/addrindex.c b/src/addrindex.c new file mode 100644 index 000000000..7e1e0d89c --- /dev/null +++ b/src/addrindex.c @@ -0,0 +1,1845 @@ +/* + * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client + * Copyright (C) 2001 Match Grun + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ + +/* + * General functions for accessing address index file. + */ + +#include + +#include "mgutils.h" +#include "addritem.h" +#include "addrcache.h" +#include "addrbook.h" +#include "addrindex.h" +#include "xml.h" + +#ifndef DEV_STANDALONE +#include "prefs.h" +#endif + +#include "vcard.h" + +#ifdef USE_JPILOT +#include "jpilot.h" +#endif + +#ifdef USE_LDAP +#include "syldap.h" +#endif + +#define TAG_ADDRESS_INDEX "addressbook" + +#define TAG_IF_ADDRESS_BOOK "book_list" +#define TAG_IF_VCARD "vcard_list" +#define TAG_IF_JPILOT "jpilot_list" +#define TAG_IF_LDAP "ldap_list" + +#define TAG_DS_ADDRESS_BOOK "book" +#define TAG_DS_VCARD "vcard" +#define TAG_DS_JPILOT "jpilot" +#define TAG_DS_LDAP "server" + +// XML Attribute names +#define ATTAG_BOOK_NAME "name" +#define ATTAG_BOOK_FILE "file" + +#define ATTAG_VCARD_NAME "name" +#define ATTAG_VCARD_FILE "file" + +#define ATTAG_JPILOT_NAME "name" +#define ATTAG_JPILOT_FILE "file" +#define ATTAG_JPILOT_CUSTOM_1 "custom-1" +#define ATTAG_JPILOT_CUSTOM_2 "custom-2" +#define ATTAG_JPILOT_CUSTOM_3 "custom-3" +#define ATTAG_JPILOT_CUSTOM_4 "custom-4" +#define ATTAG_JPILOT_CUSTOM "custom-" + +#define ATTAG_LDAP_NAME "name" +#define ATTAG_LDAP_HOST "host" +#define ATTAG_LDAP_PORT "port" +#define ATTAG_LDAP_BASE_DN "base-dn" +#define ATTAG_LDAP_BIND_DN "bind-dn" +#define ATTAG_LDAP_BIND_PASS "bind-pass" +#define ATTAG_LDAP_CRITERIA "criteria" +#define ATTAG_LDAP_MAX_ENTRY "max-entry" +#define ATTAG_LDAP_TIMEOUT "timeout" + +#define DISP_NEW_COMMON "Common Address" +#define DISP_NEW_PERSONAL "Personal Address" + +// Old address book +#define TAG_IF_OLD_COMMON "common_address" +#define TAG_IF_OLD_PERSONAL "personal_address" + +#define DISP_OLD_COMMON "Common Address" +#define DISP_OLD_PERSONAL "Personal Address" + +typedef struct _AddressIfAttr AddressIfAttrib; +struct _AddressIfAttr { + gchar *name; + gchar *value; +}; + +/* +* Build interface with default values. +*/ +static AddressInterface *addrindex_create_interface( gint type, gchar *name, gchar *tagIf, gchar *tagDS ) { + AddressInterface *iface = g_new0( AddressInterface, 1 ); + ADDRITEM_TYPE(iface) = ITEMTYPE_INTERFACE; + ADDRITEM_ID(iface) = NULL; + ADDRITEM_NAME(iface) = g_strdup( name ); + ADDRITEM_PARENT(iface) = NULL; + ADDRITEM_SUBTYPE(iface) = type; + iface->type = type; + iface->name = g_strdup( name ); + iface->listTag = g_strdup( tagIf ); + iface->itemTag = g_strdup( tagDS ); + iface->legacyFlag = FALSE; + iface->haveLibrary = TRUE; + iface->useInterface = TRUE; + iface->readOnly = TRUE; + iface->getAccessFlag = NULL; + iface->getModifyFlag = NULL; + iface->getReadFlag = NULL; + iface->getStatusCode = NULL; + iface->getReadData = NULL; + iface->getRootFolder = NULL; + iface->getListFolder = NULL; + iface->getListPerson = NULL; + iface->getAllPersons = NULL; + iface->getName = NULL; + iface->listSource = NULL; + return iface; +} + +/* +* Build table of interfaces. +*/ +static void addrindex_build_if_list( AddressIndex *addrIndex ) { + AddressInterface *iface; + gint seq = 0; + + iface = addrindex_create_interface( ADDR_IF_BOOK, "Address Book", TAG_IF_ADDRESS_BOOK, TAG_DS_ADDRESS_BOOK ); + iface->readOnly = FALSE; + iface->getModifyFlag = ( void * ) addrbook_get_modified; + iface->getAccessFlag = ( void * ) addrbook_get_accessed; + iface->getReadFlag = ( void * ) addrbook_get_read_flag; + iface->getStatusCode = ( void * ) addrbook_get_status; + iface->getReadData = ( void * ) addrbook_read_data; + iface->getRootFolder = ( void * ) addrbook_get_root_folder; + iface->getListFolder = ( void * ) addrbook_get_list_folder; + iface->getListPerson = ( void * ) addrbook_get_list_person; + iface->getAllPersons = ( void * ) addrbook_get_all_persons; + iface->getName = ( void * ) addrbook_get_name; + iface->setAccessFlag = ( void * ) addrbook_set_accessed; + addrIndex->interfaceList = g_list_append( addrIndex->interfaceList, iface ); + ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex); + + iface = addrindex_create_interface( ADDR_IF_VCARD, "V-Card", TAG_IF_VCARD, TAG_DS_VCARD ); + iface->getModifyFlag = ( void * ) vcard_get_modified; + iface->getAccessFlag = ( void * ) vcard_get_accessed; + iface->getReadFlag = ( void * ) vcard_get_read_flag; + iface->getStatusCode = ( void * ) vcard_get_status; + iface->getReadData = ( void * ) vcard_read_data; + iface->getRootFolder = ( void * ) vcard_get_root_folder; + iface->getListFolder = ( void * ) vcard_get_list_folder; + iface->getListPerson = ( void * ) vcard_get_list_person; + iface->getAllPersons = ( void * ) vcard_get_all_persons; + iface->getName = ( void * ) vcard_get_name; + iface->setAccessFlag = ( void * ) vcard_set_accessed; + addrIndex->interfaceList = g_list_append( addrIndex->interfaceList, iface ); + ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex); + + iface = addrindex_create_interface( ADDR_IF_JPILOT, "J-Pilot", TAG_IF_JPILOT, TAG_DS_JPILOT ); +#ifdef USE_JPILOT + iface->useInterface = TRUE; + iface->haveLibrary = jpilot_test_pilot_lib(); + iface->getModifyFlag = ( void * ) jpilot_get_modified; + iface->getAccessFlag = ( void * ) jpilot_get_accessed; + iface->getReadFlag = ( void * ) jpilot_get_read_flag; + iface->getStatusCode = ( void * ) jpilot_get_status; + iface->getReadData = ( void * ) jpilot_read_data; + iface->getRootFolder = ( void * ) jpilot_get_root_folder; + iface->getListFolder = ( void * ) jpilot_get_list_folder; + iface->getListPerson = ( void * ) jpilot_get_list_person; + iface->getAllPersons = ( void * ) jpilot_get_all_persons; + iface->getName = ( void * ) jpilot_get_name; + iface->setAccessFlag = ( void * ) jpilot_set_accessed; +#else + iface->useInterface = FALSE; + iface->haveLibrary = FALSE; +#endif + addrIndex->interfaceList = g_list_append( addrIndex->interfaceList, iface ); + ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex); + + iface = addrindex_create_interface( ADDR_IF_LDAP, "LDAP", TAG_IF_LDAP, TAG_DS_LDAP ); +#ifdef USE_LDAP + iface->haveLibrary = syldap_test_ldap_lib(); + iface->getAccessFlag = ( void * ) syldap_get_accessed; + // iface->getModifyFlag = ( void * ) syldap_get_modified; + // iface->getReadFlag = ( void * ) syldap_get_read_flag; + iface->getStatusCode = ( void * ) syldap_get_status; + iface->getReadData = ( void * ) syldap_read_data; + iface->getRootFolder = ( void * ) syldap_get_root_folder; + iface->getListFolder = ( void * ) syldap_get_list_folder; + iface->getListPerson = ( void * ) syldap_get_list_person; + iface->getName = ( void * ) syldap_get_name; + iface->setAccessFlag = ( void * ) syldap_set_accessed; +#else + iface->useInterface = FALSE; + iface->haveLibrary = FALSE; +#endif + addrIndex->interfaceList = g_list_append( addrIndex->interfaceList, iface ); + ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex); + + // Two old legacy data sources + iface = addrindex_create_interface( ADDR_IF_COMMON, "Old Address - common", TAG_IF_OLD_COMMON, NULL ); + iface->legacyFlag = TRUE; + addrIndex->interfaceList = g_list_append( addrIndex->interfaceList, iface ); + ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex); + + iface = addrindex_create_interface( ADDR_IF_COMMON, "Old Address - personal", TAG_IF_OLD_PERSONAL, NULL ); + iface->legacyFlag = TRUE; + addrIndex->interfaceList = g_list_append( addrIndex->interfaceList, iface ); + ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex); + +} + +/* +* Free name-value pairs. +*/ +static void addrindex_free_attributes( GList *list ) { + GList *node = list; + while( node ) { + AddressIfAttrib *nv = node->data; + g_free( nv->name ); nv->name = NULL; + g_free( nv->value ); nv->value = NULL; + g_free( nv ); + node->data = NULL; + node = g_list_next( node ); + } + g_list_free( list ); +} + +/* +* Free up data source. +*/ +void addrindex_free_datasource( AddressIndex *addrIndex, AddressDataSource *ds ) { + AddressInterface *iface = NULL; + g_return_if_fail( addrIndex != NULL ); + g_return_if_fail( ds != NULL ); + + if( ds->interface == NULL ) { + iface = addrindex_get_interface( addrIndex, ds->type ); + } + if( iface == NULL ) return; + + if( iface->useInterface ) { + if( iface->type == ADDR_IF_BOOK ) { + AddressBookFile *abf = ds->rawDataSource; + if( abf ) { + addrbook_free_book( abf ); + } + } + else if( iface->type == ADDR_IF_VCARD ) { + VCardFile *vcf = ds->rawDataSource; + if( vcf ) { + vcard_free( vcf ); + } + } +#ifdef USE_JPILOT + else if( iface->type == ADDR_IF_JPILOT ) { + JPilotFile *jpf = ds->rawDataSource; + if( jpf ) { + jpilot_free( jpf ); + } + } +#endif +#ifdef USE_LDAP + else if( iface->type == ADDR_IF_LDAP ) { + SyldapServer *server = ds->rawDataSource; + if( server ) { + syldap_free( server ); + } + } +#endif + } + else { + GList *list = ds->rawDataSource; + addrindex_free_attributes( list ); + } + + g_free( ADDRITEM_ID(addrIndex) ); + g_free( ADDRITEM_NAME(addrIndex) ); + + ADDRITEM_TYPE(addrIndex) = ITEMTYPE_NONE; + ADDRITEM_ID(addrIndex) = NULL; + ADDRITEM_NAME(addrIndex) = NULL; + ADDRITEM_PARENT(addrIndex) = NULL; + ADDRITEM_SUBTYPE(addrIndex) = 0; + ds->type = ADDR_IF_NONE; + ds->rawDataSource = NULL; + ds->interface = NULL; + + ds->type = ADDR_IF_NONE; + ds->rawDataSource = NULL; + ds->interface = NULL; + g_free( ds ); +} + +static void addrindex_free_all_datasources( AddressInterface *iface ) { + GList *node = iface->listSource; + while( node ) { + AddressDataSource *ds = node->data; + if( iface->useInterface ) { + if( iface->type == ADDR_IF_BOOK ) { + AddressBookFile *abf = ds->rawDataSource; + if( abf ) { + addrbook_free_book( abf ); + } + } + else if( iface->type == ADDR_IF_VCARD ) { + VCardFile *vcf = ds->rawDataSource; + if( vcf ) { + vcard_free( vcf ); + } + } +#ifdef USE_JPILOT + else if( iface->type == ADDR_IF_JPILOT ) { + JPilotFile *jpf = ds->rawDataSource; + if( jpf ) { + jpilot_free( jpf ); + } + } +#endif +#ifdef USE_LDAP + else if( iface->type == ADDR_IF_LDAP ) { + SyldapServer *server = ds->rawDataSource; + if( server ) { + syldap_free( server ); + } + } +#endif + } + else { + GList *list = ds->rawDataSource; + addrindex_free_attributes( list ); + } + + ds->type = ADDR_IF_NONE; + ds->rawDataSource = NULL; + ds->interface = NULL; + g_free( ds ); + node->data = NULL; + node = g_list_next( node ); + } +} + +static addrindex_free_interface( AddressInterface *iface ) { + addrindex_free_all_datasources( iface ); + + g_free( ADDRITEM_ID(iface) ); + g_free( ADDRITEM_NAME(iface) ); + g_free( iface->name ); + g_free( iface->listTag ); + g_free( iface->itemTag ); + + ADDRITEM_TYPE(iface) = ITEMTYPE_NONE; + ADDRITEM_ID(iface) = NULL; + ADDRITEM_NAME(iface) = NULL; + ADDRITEM_PARENT(iface) = NULL; + ADDRITEM_SUBTYPE(iface) = 0; + iface->type = ADDR_IF_NONE; + iface->name = NULL; + iface->listTag = NULL; + iface->itemTag = NULL; + iface->legacyFlag = FALSE; + iface->useInterface = FALSE; + iface->haveLibrary = FALSE; + + g_list_free( iface->listSource ); + iface->listSource = NULL; +} + +/* +* Create new object. +*/ +AddressIndex *addrindex_create_index() { + AddressIndex *addrIndex = g_new0( AddressIndex, 1 ); + ADDRITEM_TYPE(addrIndex) = ITEMTYPE_INDEX; + ADDRITEM_ID(addrIndex) = NULL; + ADDRITEM_NAME(addrIndex) = g_strdup( "Address Index" ); + ADDRITEM_PARENT(addrIndex) = NULL; + ADDRITEM_SUBTYPE(addrIndex) = 0; + addrIndex->filePath = NULL; + addrIndex->fileName = NULL; + addrIndex->retVal = MGU_SUCCESS; + addrIndex->needsConversion = FALSE; + addrIndex->wasConverted = FALSE; + addrIndex->conversionError = FALSE; + addrIndex->interfaceList = NULL; + addrIndex->lastType = ADDR_IF_NONE; + addrIndex->dirtyFlag = FALSE; + addrindex_build_if_list( addrIndex ); + return addrIndex; +} + +/* +* Specify file to be used. +*/ +void addrindex_set_file_path( AddressIndex *addrIndex, const gchar *value ) { + g_return_if_fail( addrIndex != NULL ); + addrIndex->filePath = mgu_replace_string( addrIndex->filePath, value ); +} +void addrindex_set_file_name( AddressIndex *addrIndex, const gchar *value ) { + g_return_if_fail( addrIndex != NULL ); + addrIndex->fileName = mgu_replace_string( addrIndex->fileName, value ); +} +void addrindex_set_dirty( AddressIndex *addrIndex, const gboolean value ) { + g_return_if_fail( addrIndex != NULL ); + addrIndex->dirtyFlag = value; +} + +/* +* Return list of interfaces. +*/ +GList *addrindex_get_interface_list( AddressIndex *addrIndex ) { + g_return_if_fail( addrIndex != NULL ); + return addrIndex->interfaceList; +} + +/* +* Free up object. +*/ +void addrindex_free_index( AddressIndex *addrIndex ) { + GList *node; + g_return_if_fail( addrIndex != NULL ); + + g_free( ADDRITEM_ID(addrIndex) ); + g_free( ADDRITEM_NAME(addrIndex) ); + g_free( addrIndex->filePath ); + g_free( addrIndex->fileName ); + ADDRITEM_TYPE(addrIndex) = ITEMTYPE_NONE; + ADDRITEM_ID(addrIndex) = NULL; + ADDRITEM_NAME(addrIndex) = NULL; + ADDRITEM_PARENT(addrIndex) = NULL; + ADDRITEM_SUBTYPE(addrIndex) = 0; + addrIndex->filePath = NULL; + addrIndex->fileName = NULL; + addrIndex->retVal = MGU_SUCCESS; + addrIndex->needsConversion = FALSE; + addrIndex->wasConverted = FALSE; + addrIndex->conversionError = FALSE; + addrIndex->lastType = ADDR_IF_NONE; + addrIndex->dirtyFlag = FALSE; + node = addrIndex->interfaceList; + while( node ) { + AddressInterface *iface = node->data; + addrindex_free_interface( iface ); + node = g_list_next( node ); + } + g_list_free( addrIndex->interfaceList ); + addrIndex->interfaceList = NULL; + g_free( addrIndex ); +} + +/* +* Print address index. +*/ +void addrindex_print_index( AddressIndex *addrIndex, FILE *stream ) { + g_return_if_fail( addrIndex != NULL ); + fprintf( stream, "AddressIndex:\n" ); + fprintf( stream, "\tfile path: '%s'\n", addrIndex->filePath ); + fprintf( stream, "\tfile name: '%s'\n", addrIndex->fileName ); + fprintf( stream, "\t status: %d : '%s'\n", addrIndex->retVal, mgu_error2string( addrIndex->retVal ) ); + fprintf( stream, "\tconverted: '%s'\n", addrIndex->wasConverted ? "yes" : "no" ); + fprintf( stream, "\tcvt error: '%s'\n", addrIndex->conversionError ? "yes" : "no" ); + fprintf( stream, "\t---\n" ); +} + +/* +* Retrieve specified interface from index. +*/ +AddressInterface *addrindex_get_interface( AddressIndex *addrIndex, AddressIfType ifType ) { + AddressInterface *retVal = NULL; + GList *node; + g_return_if_fail( addrIndex != NULL ); + node = addrIndex->interfaceList; + while( node ) { + AddressInterface *iface = node->data; + node = g_list_next( node ); + if( iface->type == ifType ) { + retVal = iface; + break; + } + } + return retVal; +} + +AddressDataSource *addrindex_create_datasource() { + AddressDataSource *ds = NULL; + ds = g_new0( AddressDataSource, 1 ); + ADDRITEM_TYPE(ds) = ITEMTYPE_DATASOURCE; + ADDRITEM_ID(ds) = NULL; + ADDRITEM_NAME(ds) = NULL; + ADDRITEM_PARENT(ds) = NULL; + ADDRITEM_SUBTYPE(ds) = 0; + ds->type = ADDR_IF_NONE; + ds->rawDataSource = NULL; + ds->interface = NULL; + return ds; +} + +/* +* Add data source to index. +* Enter: addrIndex Address index object. +* ifType Interface type to add. +* dataSource Actual data source to add. +* Return: TRUE if data source was added. +* Note: The raw data object (for example, AddressBookFile or VCardFile object) should be +* supplied as the dataSource argument. +*/ +AddressDataSource *addrindex_index_add_datasource( AddressIndex *addrIndex, AddressIfType ifType, gpointer dataSource ) { + AddressInterface *iface; + AddressDataSource *ds = NULL; + g_return_if_fail( addrIndex != NULL ); + g_return_if_fail( dataSource != NULL ); + + iface = addrindex_get_interface( addrIndex, ifType ); + if( iface ) { + ds = addrindex_create_datasource(); + ADDRITEM_PARENT(ds) = ADDRITEM_OBJECT(iface); + ds->type = ifType; + ds->rawDataSource = dataSource; + ds->interface = iface; + iface->listSource = g_list_append( iface->listSource, ds ); + addrIndex->dirtyFlag = TRUE; + } + return ds; +} + +/* +* Remove data source from index. +* Enter: addrIndex Address index object. +* dataSource Data source to remove. +* Return: Data source if removed, or NULL if data source was not found in +* index. Note the this object must still be freed. +*/ +AddressDataSource *addrindex_index_remove_datasource( AddressIndex *addrIndex, AddressDataSource *dataSource ) { + AddressDataSource *retVal = FALSE; + AddressInterface *iface; + g_return_if_fail( addrIndex != NULL ); + g_return_if_fail( dataSource != NULL ); + + iface = addrindex_get_interface( addrIndex, dataSource->type ); + if( iface ) { + iface->listSource = g_list_remove( iface->listSource, dataSource ); + addrIndex->dirtyFlag = TRUE; + dataSource->interface = NULL; + retVal = dataSource; + } + return retVal; +} + +static AddressInterface *addrindex_tag_get_interface( AddressIndex *addrIndex, gchar *tag, AddressIfType ifType ) { + AddressInterface *retVal = NULL; + GList *node = addrIndex->interfaceList; + while( node ) { + AddressInterface *iface = node->data; + node = g_list_next( node ); + if( tag ) { + if( strcmp( iface->listTag, tag ) == 0 ) { + retVal = iface; + break; + } + } + else { + if( iface->type == ifType ) { + retVal = iface; + break; + } + } + } + return retVal; +} + +static AddressInterface *addrindex_tag_get_datasource( AddressIndex *addrIndex, AddressIfType ifType, gchar *tag ) { + AddressInterface *retVal = NULL; + GList *node = addrIndex->interfaceList; + while( node ) { + AddressInterface *iface = node->data; + node = g_list_next( node ); + if( iface->type == ifType && iface->itemTag ) { + if( strcmp( iface->itemTag, tag ) == 0 ) { + retVal = iface; + break; + } + } + } + return retVal; +} + +/* ********************************************************************** +* Interface XML parsing functions. +* *********************************************************************** +*/ +static void show_attribs( GList *attr ) { + while( attr ) { + gchar *name = ((XMLAttr *)attr->data)->name; + gchar *value = ((XMLAttr *)attr->data)->value; + printf( "\tattr value : %s :%s:\n", name, value ); + attr = g_list_next( attr ); + } + printf( "\t---\n" ); +} + +static void addrindex_write_elem_s( FILE *fp, gint lvl, gchar *name ) { + gint i; + for( i = 0; i < lvl; i++ ) fputs( " ", fp ); + fputs( "<", fp ); + fputs( name, fp ); +} + +static void addrindex_write_elem_e( FILE *fp, gint lvl, gchar *name ) { + gint i; + for( i = 0; i < lvl; i++ ) fputs( " ", fp ); + fputs( "\n", fp ); +} + +static void addrindex_write_attr( FILE *fp, gchar *name, gchar *value ) { + fputs( " ", fp ); + fputs( name, fp ); + fputs( "=\"", fp ); + xml_file_put_escape_str( fp, value ); + fputs( "\"", fp ); +} + +/* +* Return list of name-value pairs. +*/ +static GList *addrindex_read_attributes( XMLFile *file ) { + GList *list = NULL; + AddressIfAttrib *nv; + GList *attr; + gchar *name; + gchar *value; + + attr = xml_get_current_tag_attr( file ); + while( attr ) { + name = ((XMLAttr *)attr->data)->name; + value = ((XMLAttr *)attr->data)->value; + nv = g_new0( AddressIfAttrib, 1 ); + nv->name = g_strdup( name ); + nv->value = g_strdup( value ); + list = g_list_append( list, nv ); + attr = g_list_next( attr ); + } + return list; +} + +/* +* Output name-value pairs. +*/ +static void addrindex_write_attributes( FILE *fp, gchar *tag, GList *list, gint lvl ) { + GList *node; + AddressIfAttrib *nv; + if( list ) { + addrindex_write_elem_s( fp, lvl, tag ); + node = list; + while( node ) { + nv = node->data; + addrindex_write_attr( fp, nv->name, nv->value ); + node = g_list_next( node ); + } + fputs(" />\n", fp); + } +} + +static void addrindex_print_attributes( GList *list, FILE *stream ) { + GList *node = list; + while( node ) { + AddressIfAttrib *nv = node->data; + fprintf( stream, "%s : %s\n", nv->name, nv->value ); + node = g_list_next( node ); + } +} + +static AddressDataSource *addrindex_parse_book( XMLFile *file ) { + AddressDataSource *ds = g_new0( AddressDataSource, 1 ); + AddressBookFile *abf; + GList *attr; + + abf = addrbook_create_book(); + attr = xml_get_current_tag_attr( file ); + while( attr ) { + gchar *name = ((XMLAttr *)attr->data)->name; + gchar *value = ((XMLAttr *)attr->data)->value; + if( strcmp( name, ATTAG_BOOK_NAME ) == 0 ) { + addrbook_set_name( abf, value ); + } + else if( strcmp( name, ATTAG_BOOK_FILE ) == 0) { + addrbook_set_file( abf, value ); + } + attr = g_list_next( attr ); + } + ds->rawDataSource = abf; + return ds; +} + +static void addrindex_write_book( FILE *fp, AddressDataSource *ds, gint lvl ) { + AddressBookFile *abf = ds->rawDataSource; + if( abf ) { + addrindex_write_elem_s( fp, lvl, TAG_DS_ADDRESS_BOOK ); + addrindex_write_attr( fp, ATTAG_BOOK_NAME, abf->name ); + addrindex_write_attr( fp, ATTAG_BOOK_FILE, abf->fileName ); + fputs( " />\n", fp ); + } +} + +static AddressDataSource *addrindex_parse_vcard( XMLFile *file ) { + AddressDataSource *ds = g_new0( AddressDataSource, 1 ); + VCardFile *vcf; + GList *attr; + + vcf = vcard_create(); + attr = xml_get_current_tag_attr( file ); + while( attr ) { + gchar *name = ((XMLAttr *)attr->data)->name; + gchar *value = ((XMLAttr *)attr->data)->value; + if( strcmp( name, ATTAG_VCARD_NAME ) == 0 ) { + vcard_set_name( vcf, value ); + } + else if( strcmp( name, ATTAG_VCARD_FILE ) == 0) { + vcard_set_file( vcf, value ); + } + attr = g_list_next( attr ); + } + ds->rawDataSource = vcf; + return ds; +} + +static void addrindex_write_vcard( FILE *fp, AddressDataSource *ds, gint lvl ) { + VCardFile *vcf = ds->rawDataSource; + if( vcf ) { + addrindex_write_elem_s( fp, lvl, TAG_DS_VCARD ); + addrindex_write_attr( fp, ATTAG_VCARD_NAME, vcf->name ); + addrindex_write_attr( fp, ATTAG_VCARD_FILE, vcf->path ); + fputs( " />\n", fp ); + } +} + +#ifdef USE_JPILOT +static AddressDataSource *addrindex_parse_jpilot( XMLFile *file ) { + AddressDataSource *ds = g_new0( AddressDataSource, 1 ); + JPilotFile *jpf; + GList *attr; + + jpf = jpilot_create(); + attr = xml_get_current_tag_attr( file ); + while( attr ) { + gchar *name = ((XMLAttr *)attr->data)->name; + gchar *value = ((XMLAttr *)attr->data)->value; + if( strcmp( name, ATTAG_JPILOT_NAME ) == 0 ) { + jpilot_set_name( jpf, value ); + } + else if( strcmp( name, ATTAG_JPILOT_FILE ) == 0 ) { + jpilot_set_file( jpf, value ); + } + else if( strcmp( name, ATTAG_JPILOT_CUSTOM_1 ) == 0 ) { + jpilot_add_custom_label( jpf, value ); + } + else if( strcmp( name, ATTAG_JPILOT_CUSTOM_2 ) == 0 ) { + jpilot_add_custom_label( jpf, value ); + } + else if( strcmp( name, ATTAG_JPILOT_CUSTOM_3 ) == 0 ) { + jpilot_add_custom_label( jpf, value ); + } + else if( strcmp( name, ATTAG_JPILOT_CUSTOM_4 ) == 0 ) { + jpilot_add_custom_label( jpf, value ); + } + attr = g_list_next( attr ); + } + ds->rawDataSource = jpf; + return ds; +} + +static void addrindex_write_jpilot( FILE *fp,AddressDataSource *ds, gint lvl ) { + JPilotFile *jpf = ds->rawDataSource; + if( jpf ) { + gint ind; + GList *node; + GList *customLbl = jpilot_get_custom_labels( jpf ); + addrindex_write_elem_s( fp, lvl, TAG_DS_JPILOT ); + addrindex_write_attr( fp, ATTAG_JPILOT_NAME, jpf->name ); + addrindex_write_attr( fp, ATTAG_JPILOT_FILE, jpf->path ); + node = customLbl; + ind = 1; + while( node ) { + gchar name[256]; + sprintf( name, "%s%d", ATTAG_JPILOT_CUSTOM, ind ); + addrindex_write_attr( fp, name, node->data ); + ind++; + node = g_list_next( node ); + } + fputs( " />\n", fp ); + } +} +#else +// Just read/write name-value pairs +static AddressDataSource *addrindex_parse_jpilot( XMLFile *file ) { + AddressDataSource *ds = g_new0( AddressDataSource, 1 ); + GList *list = addrindex_read_attributes( file ); + ds->rawDataSource = list; + return ds; +} + +static void addrindex_write_jpilot( FILE *fp, AddressDataSource *ds, gint lvl ) { + GList *list = ds->rawDataSource; + if( list ) { + addrindex_write_attributes( fp, TAG_DS_JPILOT, list, lvl ); + } +} +#endif + +#ifdef USE_LDAP +static AddressDataSource *addrindex_parse_ldap( XMLFile *file ) { + AddressDataSource *ds = g_new0( AddressDataSource, 1 ); + SyldapServer *server; + GList *attr; + + server = syldap_create(); + attr = xml_get_current_tag_attr( file ); + while( attr ) { + gchar *name = ((XMLAttr *)attr->data)->name; + gchar *value = ((XMLAttr *)attr->data)->value; + gint ivalue = atoi( value ); + if( strcmp( name, ATTAG_LDAP_NAME ) == 0 ) { + syldap_set_name( server, value ); + } + else if( strcmp( name, ATTAG_LDAP_HOST ) == 0 ) { + syldap_set_host( server, value ); + } + else if( strcmp( name, ATTAG_LDAP_PORT ) == 0 ) { + syldap_set_port( server, ivalue ); + } + else if( strcmp( name, ATTAG_LDAP_BASE_DN ) == 0 ) { + syldap_set_base_dn( server, value ); + } + else if( strcmp( name, ATTAG_LDAP_BIND_DN ) == 0 ) { + syldap_set_bind_dn( server, value ); + } + else if( strcmp( name, ATTAG_LDAP_BIND_PASS ) == 0 ) { + syldap_set_bind_password( server, value ); + } + else if( strcmp( name, ATTAG_LDAP_CRITERIA ) == 0 ) { + syldap_set_search_criteria( server, value ); + } + else if( strcmp( name, ATTAG_LDAP_MAX_ENTRY ) == 0 ) { + syldap_set_max_entries( server, ivalue ); + } + else if( strcmp( name, ATTAG_LDAP_TIMEOUT ) == 0 ) { + syldap_set_timeout( server, ivalue ); + } + attr = g_list_next( attr ); + } + + ds->rawDataSource = server; + return ds; +} + +static void addrindex_write_ldap( FILE *fp, AddressDataSource *ds, gint lvl ) { + SyldapServer *server = ds->rawDataSource; + if( server ) { + gchar value[256]; + + addrindex_write_elem_s( fp, lvl, TAG_DS_LDAP ); + addrindex_write_attr( fp, ATTAG_LDAP_NAME, server->name ); + addrindex_write_attr( fp, ATTAG_LDAP_HOST, server->hostName ); + + sprintf( value, "%d", server->port ); + addrindex_write_attr( fp, ATTAG_LDAP_PORT, value ); + + addrindex_write_attr( fp, ATTAG_LDAP_BASE_DN, server->baseDN ); + addrindex_write_attr( fp, ATTAG_LDAP_BIND_DN, server->bindDN ); + addrindex_write_attr( fp, ATTAG_LDAP_BIND_PASS, server->bindPass ); + addrindex_write_attr( fp, ATTAG_LDAP_CRITERIA, server->searchCriteria ); + + sprintf( value, "%d", server->maxEntries ); + addrindex_write_attr( fp, ATTAG_LDAP_MAX_ENTRY, value ); + sprintf( value, "%d", server->timeOut ); + addrindex_write_attr( fp, ATTAG_LDAP_TIMEOUT, value ); + + fputs(" />\n", fp); + } +} +#else +// Just read/write name-value pairs +static AddressDataSource *addrindex_parse_ldap( XMLFile *file ) { + AddressDataSource *ds = g_new0( AddressDataSource, 1 ); + GList *list = addrindex_read_attributes( file ); + ds->data = list; + return ds; +} + +static void addrindex_write_ldap( FILE *fp, AddressDataSource *ds, gint lvl ) { + GList *list = ds->rawDataSource; + if( list ) { + addrindex_write_attributes( fp, TAG_DS_LDAP, list, lvl ); + } +} +#endif + +/* ********************************************************************** +* Address index I/O functions. +* *********************************************************************** +*/ +static void addrindex_read_index( AddressIndex *addrIndex, XMLFile *file ) { + guint prev_level; + gchar *element; + GList *attr; + XMLTag *xtag; + AddressInterface *iface = NULL, *dsIFace = NULL; + AddressDataSource *ds; + + for (;;) { + prev_level = file->level; + xml_parse_next_tag( file ); + if( file->level < prev_level ) return; + + xtag = xml_get_current_tag( file ); + // printf( "tag : %s\n", xtag->tag ); + + iface = addrindex_tag_get_interface( addrIndex, xtag->tag, ADDR_IF_NONE ); + if( iface ) { + addrIndex->lastType = iface->type; + if( iface->legacyFlag ) addrIndex->needsConversion = TRUE; + // printf( "found : %s\n", iface->name ); + } + else { + dsIFace = addrindex_tag_get_datasource( addrIndex, addrIndex->lastType, xtag->tag ); + if( dsIFace ) { + // Add data source to list + // printf( "\tdata source: %s\n", dsIFace->name ); + ds = NULL; + if( addrIndex->lastType == ADDR_IF_BOOK ) { + ds = addrindex_parse_book( file ); + if( ds->rawDataSource ) { + addrbook_set_path( ds->rawDataSource, addrIndex->filePath ); + // addrbook_print_book( ds->rawDataSource, stdout ); + } + } + else if( addrIndex->lastType == ADDR_IF_VCARD ) { + ds = addrindex_parse_vcard( file ); + // if( ds->rawDataSource ) { + // vcard_print_file( ds->rawDataSource, stdout ); + // } + } + else if( addrIndex->lastType == ADDR_IF_JPILOT ) { + ds = addrindex_parse_jpilot( file ); + /* + if( ds->rawDataSource ) { + jpilot_print_file( ds->rawDataSource, stdout ); + // addrindex_print_attributes( ds->rawDataSource, stdout ); + } + */ + } + else if( addrIndex->lastType == ADDR_IF_LDAP ) { + ds = addrindex_parse_ldap( file ); + /* + if( ds->rawDataSource ) { + syldap_print_data( ds->rawDataSource, stdout ); + // addrindex_print_attributes( ds->rawDataSource, stdout ); + } + */ + } + if( ds ) { + ds->type = addrIndex->lastType; + ds->interface = dsIFace; + dsIFace->listSource = g_list_append( dsIFace->listSource, ds ); + } + // printf( "=============================\n\n" ); + } + } + /* + element = xml_get_element( file ); + attr = xml_get_current_tag_attr( file ); + if( _interfaceLast_ && ! _interfaceLast_->legacyFlag ) { + show_attribs( attr ); + printf( "\ttag value : %s :\n", element ); + } + */ + addrindex_read_index( addrIndex, file ); + } +} + +static gint addrindex_read_file( AddressIndex *addrIndex ) { + XMLFile *file = NULL; + gchar *fileSpec = NULL; + g_return_if_fail( addrIndex != NULL ); + + fileSpec = g_strconcat( addrIndex->filePath, G_DIR_SEPARATOR_S, addrIndex->fileName, NULL ); + addrIndex->retVal = MGU_NO_FILE; + file = xml_open_file( fileSpec ); + g_free( fileSpec ); + + if( file == NULL ) { + // fprintf( stdout, " file '%s' does not exist.\n", addrIndex->fileName ); + return addrIndex->retVal; + } + + addrIndex->retVal = MGU_BAD_FORMAT; + if( xml_get_dtd( file ) == 0 ) { + if( xml_parse_next_tag( file ) == 0 ) { + if( xml_compare_tag( file, TAG_ADDRESS_INDEX ) ) { + addrindex_read_index( addrIndex, file ); + addrIndex->retVal = MGU_SUCCESS; + } + } + } + xml_close_file( file ); + + return addrIndex->retVal; +} + +static void addrindex_write_index( AddressIndex *addrIndex, FILE *fp ) { + GList *nodeIF, *nodeDS; + gint lvlList = 1; + gint lvlItem = 1 + lvlList; + + nodeIF = addrIndex->interfaceList; + while( nodeIF ) { + AddressInterface *iface = nodeIF->data; + if( ! iface->legacyFlag ) { + nodeDS = iface->listSource; + addrindex_write_elem_s( fp, lvlList, iface->listTag ); + fputs( ">\n", fp ); + while( nodeDS ) { + AddressDataSource *ds = nodeDS->data; + if( ds ) { + if( iface->type == ADDR_IF_BOOK ) { + addrindex_write_book( fp, ds, lvlItem ); + } + if( iface->type == ADDR_IF_VCARD ) { + addrindex_write_vcard( fp, ds, lvlItem ); + } + if( iface->type == ADDR_IF_JPILOT ) { + addrindex_write_jpilot( fp, ds, lvlItem ); + } + if( iface->type == ADDR_IF_LDAP ) { + addrindex_write_ldap( fp, ds, lvlItem ); + } + } + nodeDS = g_list_next( nodeDS ); + } + addrindex_write_elem_e( fp, lvlList, iface->listTag ); + } + nodeIF = g_list_next( nodeIF ); + } +} + +/* +* Write data to specified file. +* Enter: addrIndex Address index object. +* newFile New file name. +* return: Status code, from addrIndex->retVal. +* Note: File will be created in directory specified by addrIndex. +*/ +gint addrindex_write_to( AddressIndex *addrIndex, const gchar *newFile ) { + FILE *fp; + gchar *fileSpec; +#ifndef DEV_STANDALONE + PrefFile *pfile; +#endif + + g_return_if_fail( addrIndex != NULL ); + + fileSpec = g_strconcat( addrIndex->filePath, G_DIR_SEPARATOR_S, newFile, NULL ); + addrIndex->retVal = MGU_OPEN_FILE; +#ifdef DEV_STANDALONE + fp = fopen( fileSpec, "w" ); + g_free( fileSpec ); + if( fp ) { + fputs( "\n", fp ); +#else + pfile = prefs_write_open( fileSpec ); + g_free( fileSpec ); + if( pfile ) { + fp = pfile->fp; + fprintf( fp, "\n", + conv_get_current_charset_str() ); +#endif + addrindex_write_elem_s( fp, 0, TAG_ADDRESS_INDEX ); + fputs( ">\n", fp ); + + addrindex_write_index( addrIndex, fp ); + addrindex_write_elem_e( fp, 0, TAG_ADDRESS_INDEX ); + + addrIndex->retVal = MGU_SUCCESS; +#ifdef DEV_STANDALONE + fclose( fp ); +#else + if( prefs_write_close( pfile ) < 0 ) { + addrIndex->retVal = MGU_ERROR_WRITE; + } +#endif + } + + fileSpec = NULL; + return addrIndex->retVal; +} + +/* +* Save address index data to original file. +* return: Status code, from addrIndex->retVal. +*/ +gint addrindex_save_data( AddressIndex *addrIndex ) { + g_return_if_fail( addrIndex != NULL ); + + addrIndex->retVal = MGU_NO_FILE; + if( addrIndex->fileName == NULL || *addrIndex->fileName == '\0' ) return addrIndex->retVal; + if( addrIndex->filePath == NULL || *addrIndex->filePath == '\0' ) return addrIndex->retVal; + + addrindex_write_to( addrIndex, addrIndex->fileName ); + if( addrIndex->retVal == MGU_SUCCESS ) { + addrIndex->dirtyFlag = FALSE; + } + return addrIndex->retVal; +} + +/* +* Save all address book files which may have changed. +* Return: Status code, set if there was a problem saving data. +*/ +gint addrindex_save_all_books( AddressIndex *addrIndex ) { + gint retVal = MGU_SUCCESS; + GList *nodeIf, *nodeDS; + nodeIf = addrIndex->interfaceList; + while( nodeIf ) { + AddressInterface *iface = nodeIf->data; + if( iface->type == ADDR_IF_BOOK ) { + nodeDS = iface->listSource; + while( nodeDS ) { + AddressDataSource *ds = nodeDS->data; + AddressBookFile *abf = ds->rawDataSource; + if( abf->dirtyFlag ) { + if( abf->readFlag ) { + addrbook_save_data( abf ); + if( abf->retVal != MGU_SUCCESS ) { + retVal = abf->retVal; + } + } + } + nodeDS = g_list_next( nodeDS ); + } + break; + } + nodeIf = g_list_next( nodeIf ); + } + return retVal; +} + + +/* ********************************************************************** +* Address book conversion to new format. +* *********************************************************************** +*/ + +#define ELTAG_IF_OLD_FOLDER "folder" +#define ELTAG_IF_OLD_GROUP "group" +#define ELTAG_IF_OLD_ITEM "item" +#define ELTAG_IF_OLD_NAME "name" +#define ELTAG_IF_OLD_ADDRESS "address" +#define ELTAG_IF_OLD_REMARKS "remarks" +#define ATTAG_IF_OLD_NAME "name" + +#define TEMPNODE_ROOT 0 +#define TEMPNODE_FOLDER 1 +#define TEMPNODE_GROUP 2 +#define TEMPNODE_ADDRESS 3 + +typedef struct _AddressCvt_Node AddressCvtNode; +struct _AddressCvt_Node { + gint type; + gchar *name; + gchar *address; + gchar *remarks; + GList *list; +}; + +/* +* Parse current address item. +*/ +static AddressCvtNode *addrindex_parse_item( XMLFile *file ) { + gchar *element; + guint level; + AddressCvtNode *nn; + + nn = g_new0( AddressCvtNode, 1 ); + nn->type = TEMPNODE_ADDRESS; + nn->list = NULL; + + level = file->level; + + for (;;) { + xml_parse_next_tag(file); + if (file->level < level) return nn; + + element = xml_get_element( file ); + if( xml_compare_tag( file, ELTAG_IF_OLD_NAME ) ) { + nn->name = g_strdup( element ); + } + if( xml_compare_tag( file, ELTAG_IF_OLD_ADDRESS ) ) { + nn->address = g_strdup( element ); + } + if( xml_compare_tag( file, ELTAG_IF_OLD_REMARKS ) ) { + nn->remarks = g_strdup( element ); + } + xml_parse_next_tag(file); + } +} + +/* +* Create a temporary node below specified node. +*/ +static AddressCvtNode *addrindex_add_object( AddressCvtNode *node, gint type, gchar *name, gchar *addr, char *rem ) { + AddressCvtNode *nn; + nn = g_new0( AddressCvtNode, 1 ); + nn->type = type; + nn->name = g_strdup( name ); + nn->remarks = g_strdup( rem ); + node->list = g_list_append( node->list, nn ); + return nn; +} + +/* +* Process current temporary node. +*/ +static void addrindex_add_obj( XMLFile *file, AddressCvtNode *node ) { + GList *attr; + guint prev_level; + AddressCvtNode *newNode = NULL; + gchar *name; + gchar *value; + + for (;;) { + prev_level = file->level; + xml_parse_next_tag( file ); + if (file->level < prev_level) return; + name = NULL; + value = NULL; + + if( xml_compare_tag( file, ELTAG_IF_OLD_GROUP ) ) { + attr = xml_get_current_tag_attr(file); + if (attr) { + name = ((XMLAttr *)attr->data)->name; + if( strcmp( name, ATTAG_IF_OLD_NAME ) == 0 ) { + value = ((XMLAttr *)attr->data)->value; + } + } + newNode = addrindex_add_object( node, TEMPNODE_GROUP, value, "", "" ); + addrindex_add_obj( file, newNode ); + + } + else if( xml_compare_tag( file, ELTAG_IF_OLD_FOLDER ) ) { + attr = xml_get_current_tag_attr(file); + if (attr) { + name = ((XMLAttr *)attr->data)->name; + if( strcmp( name, ATTAG_IF_OLD_NAME ) == 0 ) { + value = ((XMLAttr *)attr->data)->value; + } + } + newNode = addrindex_add_object( node, TEMPNODE_FOLDER, value, "", "" ); + addrindex_add_obj( file, newNode ); + } + else if( xml_compare_tag( file, ELTAG_IF_OLD_ITEM ) ) { + newNode = addrindex_parse_item( file ); + node->list = g_list_append( node->list, newNode ); + } + else { + // printf( "invalid: !!! \n" ); + attr = xml_get_current_tag_attr( file ); + } + } +} + +/* +* Consume all nodes below current tag. +*/ +static void addrindex_consume_tree( XMLFile *file ) { + guint prev_level; + gchar *element; + GList *attr; + XMLTag *xtag; + + for (;;) { + prev_level = file->level; + xml_parse_next_tag( file ); + if (file->level < prev_level) return; + + xtag = xml_get_current_tag( file ); + // printf( "tag : %s\n", xtag->tag ); + element = xml_get_element( file ); + attr = xml_get_current_tag_attr( file ); + // show_attribs( attr ); + // printf( "\ttag value : %s :\n", element ); + addrindex_consume_tree( file ); + } +} + +/* +* Print temporary tree. +*/ +static void addrindex_print_node( AddressCvtNode *node, FILE *stream ) { + GList *list; + fprintf( stream, "Node:\ttype :%d:\n", node->type ); + fprintf( stream, "\tname :%s:\n", node->name ); + fprintf( stream, "\taddr :%s:\n", node->address ); + fprintf( stream, "\trems :%s:\n", node->remarks ); + if( node->list ) { + fprintf( stream, "\t--list----\n" ); + } + list = node->list; + while( list ) { + AddressCvtNode *lNode = list->data; + list = g_list_next( list ); + addrindex_print_node( lNode, stream ); + } + fprintf( stream, "\t==list-%d==\n", node->type ); +} + +/* +* Free up temporary tree. +*/ +static void addrindex_free_node( AddressCvtNode *node ) { + GList *list = node->list; + while( list ) { + AddressCvtNode *lNode = list->data; + list = g_list_next( list ); + addrindex_free_node( lNode ); + } + node->type = TEMPNODE_ROOT; + g_free( node->name ); + g_free( node->address ); + g_free( node->remarks ); + g_list_free( node->list ); + g_free( node ); +} + +/* +* Process address book for specified node. +*/ +static void addrindex_process_node( + AddressBookFile *abf, AddressCvtNode *node, ItemFolder *parent, + ItemGroup *parentGrp, ItemFolder *folderGrp ) +{ + GList *list; + ItemFolder *itemFolder; + ItemGroup *itemGParent = parentGrp; + ItemFolder *itemGFolder = folderGrp; + AddressCache *cache = abf->addressCache; + + if( node->type == TEMPNODE_ROOT ) { + itemFolder = parent; + } + else if( node->type == TEMPNODE_FOLDER ) { + itemFolder = addritem_create_item_folder(); + addritem_folder_set_name( itemFolder, node->name ); + addrcache_id_folder( cache, itemFolder ); + addrcache_folder_add_folder( cache, parent, itemFolder ); + itemGFolder = NULL; + } + else if( node->type == TEMPNODE_GROUP ) { + ItemGroup *itemGroup; + gchar *fName; + + // Create a folder for group + fName = g_strdup_printf( "Cvt - %s", node->name ); + itemGFolder = addritem_create_item_folder(); + addritem_folder_set_name( itemGFolder, fName ); + addrcache_id_folder( cache, itemGFolder ); + addrcache_folder_add_folder( cache, parent, itemGFolder ); + g_free( fName ); + + // Add group into folder + itemGroup = addritem_create_item_group(); + addritem_group_set_name( itemGroup, node->name ); + addrcache_id_group( cache, itemGroup ); + addrcache_folder_add_group( cache, itemGFolder, itemGroup ); + itemGParent = itemGroup; + } + else if( node->type == TEMPNODE_ADDRESS ) { + ItemPerson *itemPerson; + ItemEMail *itemEMail; + + // Create person and email objects + itemPerson = addritem_create_item_person(); + addritem_person_set_common_name( itemPerson, node->name ); + addrcache_id_person( cache, itemPerson ); + itemEMail = addritem_create_item_email(); + addritem_email_set_address( itemEMail, node->address ); + addritem_email_set_remarks( itemEMail, node->remarks ); + addrcache_id_email( cache, itemEMail ); + addrcache_person_add_email( cache, itemPerson, itemEMail ); + + // Add person into appropriate folder + if( itemGFolder ) { + addrcache_folder_add_person( cache, itemGFolder, itemPerson ); + } + else { + addrcache_folder_add_person( cache, parent, itemPerson ); + } + + // Add email address only into group + if( parentGrp ) { + addrcache_group_add_email( cache, parentGrp, itemEMail ); + } + } + + list = node->list; + while( list ) { + AddressCvtNode *lNode = list->data; + list = g_list_next( list ); + addrindex_process_node( abf, lNode, itemFolder, itemGParent, itemGFolder ); + } +} + +/* +* Process address book to specified file number. +*/ +static gboolean addrindex_process_book( AddressIndex *addrIndex, XMLFile *file, gchar *displayName ) { + gboolean retVal = FALSE; + AddressBookFile *abf = NULL; + AddressCvtNode *rootNode = NULL; + gchar *newFile = NULL; + GList *fileList = NULL; + gint fileNum = 0; + + // Setup root node + rootNode = g_new0( AddressCvtNode, 1 ); + rootNode->type = TEMPNODE_ROOT; + rootNode->name = g_strdup( "root" ); + rootNode->list = NULL; + addrindex_add_obj( file, rootNode ); + // addrindex_print_node( rootNode, stdout ); + + // Create new address book + abf = addrbook_create_book(); + addrbook_set_name( abf, displayName ); + addrbook_set_path( abf, addrIndex->filePath ); + + // Determine next available file number + fileList = addrbook_get_bookfile_list( abf ); + if( fileList ) { + fileNum = 1 + abf->maxValue; + } + g_list_free( fileList ); + fileList = NULL; + + newFile = addrbook_gen_new_file_name( fileNum ); + if( newFile ) { + addrbook_set_file( abf, newFile ); + } + + addrindex_process_node( abf, rootNode, abf->addressCache->rootFolder, NULL, NULL ); + + // addrbook_dump_book( abf, stdout ); + addrbook_save_data( abf ); + addrIndex->retVal = abf->retVal; + if( abf->retVal == MGU_SUCCESS ) retVal = TRUE; + + addrbook_free_book( abf ); + abf = NULL; + addrindex_free_node( rootNode ); + rootNode = NULL; + + // Create entries in address index + if( retVal ) { + abf = addrbook_create_book(); + addrbook_set_name( abf, displayName ); + addrbook_set_path( abf, addrIndex->filePath ); + addrbook_set_file( abf, newFile ); + addrindex_index_add_datasource( addrIndex, ADDR_IF_BOOK, abf ); + } + + return retVal; +} + +/* +* Process tree converting data. +*/ +static void addrindex_convert_tree( AddressIndex *addrIndex, XMLFile *file ) { + guint prev_level; + gchar *element; + GList *attr; + XMLTag *xtag; + + // Process file + for (;;) { + prev_level = file->level; + xml_parse_next_tag( file ); + if (file->level < prev_level) return; + + xtag = xml_get_current_tag( file ); + // printf( "tag : %d : %s\n", prev_level, xtag->tag ); + if( strcmp( xtag->tag, TAG_IF_OLD_COMMON ) == 0 ) { + if( addrindex_process_book( addrIndex, file, DISP_OLD_COMMON ) ) { + addrIndex->needsConversion = FALSE; + addrIndex->wasConverted = TRUE; + continue; + } + return; + } + if( strcmp( xtag->tag, TAG_IF_OLD_PERSONAL ) == 0 ) { + if( addrindex_process_book( addrIndex, file, DISP_OLD_PERSONAL ) ) { + addrIndex->needsConversion = FALSE; + addrIndex->wasConverted = TRUE; + continue; + } + return; + } + element = xml_get_element( file ); + attr = xml_get_current_tag_attr( file ); + // show_attribs( attr ); + // printf( "\ttag value : %s :\n", element ); + addrindex_consume_tree( file ); + } +} + +static gint addrindex_convert_data( AddressIndex *addrIndex ) { + XMLFile *file = NULL; + gchar *fileSpec; + + fileSpec = g_strconcat( addrIndex->filePath, G_DIR_SEPARATOR_S, addrIndex->fileName, NULL ); + addrIndex->retVal = MGU_NO_FILE; + file = xml_open_file( fileSpec ); + g_free( fileSpec ); + + if( file == NULL ) { + // fprintf( stdout, " file '%s' does not exist.\n", addrIndex->fileName ); + return addrIndex->retVal; + } + + addrIndex->retVal = MGU_BAD_FORMAT; + if( xml_get_dtd( file ) == 0 ) { + if( xml_parse_next_tag( file ) == 0 ) { + if( xml_compare_tag( file, TAG_ADDRESS_INDEX ) ) { + addrindex_convert_tree( addrIndex, file ); + } + } + } + xml_close_file( file ); + return addrIndex->retVal; +} + +/* +* Create a new address book file. +*/ +static gboolean addrindex_create_new_book( AddressIndex *addrIndex, gchar *displayName ) { + gboolean retVal = FALSE; + AddressBookFile *abf = NULL; + gchar *newFile = NULL; + GList *fileList = NULL; + gint fileNum = 0; + + // Create new address book + abf = addrbook_create_book(); + addrbook_set_name( abf, displayName ); + addrbook_set_path( abf, addrIndex->filePath ); + + // Determine next available file number + fileList = addrbook_get_bookfile_list( abf ); + if( fileList ) { + fileNum = 1 + abf->maxValue; + } + g_list_free( fileList ); + fileList = NULL; + + newFile = addrbook_gen_new_file_name( fileNum ); + if( newFile ) { + addrbook_set_file( abf, newFile ); + } + + addrbook_save_data( abf ); + addrIndex->retVal = abf->retVal; + if( abf->retVal == MGU_SUCCESS ) retVal = TRUE; + addrbook_free_book( abf ); + abf = NULL; + + // Create entries in address index + if( retVal ) { + abf = addrbook_create_book(); + addrbook_set_name( abf, displayName ); + addrbook_set_path( abf, addrIndex->filePath ); + addrbook_set_file( abf, newFile ); + addrindex_index_add_datasource( addrIndex, ADDR_IF_BOOK, abf ); + } + + return retVal; +} + +/* +* Read data for address index performing a conversion if necesary. +* Enter: addrIndex Address index object. +* return: Status code, from addrIndex->retVal. +* Note: New address book files will be created in directory specified by +* addrIndex. Three files will be created, for the following: +* "Common addresses" +* "Personal addresses" +* "Gathered addresses" - a new address book. +*/ +gint addrindex_read_data( AddressIndex *addrIndex ) { + g_return_if_fail( addrIndex != NULL ); + + addrIndex->conversionError = FALSE; + addrindex_read_file( addrIndex ); + if( addrIndex->retVal == MGU_SUCCESS ) { + if( addrIndex->needsConversion ) { + if( addrindex_convert_data( addrIndex ) == MGU_SUCCESS ) { + addrIndex->conversionError = TRUE; + } + else { + addrIndex->conversionError = TRUE; + } + } + addrIndex->dirtyFlag = TRUE; + } + return addrIndex->retVal; +} + +/* +* Create new address books for a new address index. +* Enter: addrIndex Address index object. +* return: Status code, from addrIndex->retVal. +* Note: New address book files will be created in directory specified by +* addrIndex. Three files will be created, for the following: +* "Common addresses" +* "Personal addresses" +* "Gathered addresses" - a new address book. +*/ +gint addrindex_create_new_books( AddressIndex *addrIndex ) { + gboolean flg; + + g_return_if_fail( addrIndex != NULL ); + + flg = addrindex_create_new_book( addrIndex, DISP_NEW_COMMON ); + if( flg ) { + flg = addrindex_create_new_book( addrIndex, DISP_NEW_PERSONAL ); + addrIndex->dirtyFlag = TRUE; + } + return addrIndex->retVal; +} + +/* ********************************************************************** +* New interface stuff. +* *********************************************************************** +*/ + +/* + * Return modified flag for specified data source. + */ +gboolean addrindex_ds_get_modify_flag( AddressDataSource *ds ) { + gboolean retVal = FALSE; + AddressInterface *iface; + + if( ds == NULL ) return retVal; + iface = ds->interface; + if( iface == NULL ) return retVal; + if( iface->getModifyFlag ) { + retVal = ( iface->getModifyFlag ) ( ds->rawDataSource ); + } + return retVal; +} + +/* + * Return accessed flag for specified data source. + */ +gboolean addrindex_ds_get_access_flag( AddressDataSource *ds ) { + gboolean retVal = FALSE; + AddressInterface *iface; + + if( ds == NULL ) return retVal; + iface = ds->interface; + if( iface == NULL ) return retVal; + if( iface->getAccessFlag ) { + retVal = ( iface->getAccessFlag ) ( ds->rawDataSource ); + } + return retVal; +} + +/* + * Return data read flag for specified data source. + */ +gboolean addrindex_ds_get_read_flag( AddressDataSource *ds ) { + gboolean retVal = TRUE; + AddressInterface *iface; + + if( ds == NULL ) return retVal; + iface = ds->interface; + if( iface == NULL ) return retVal; + if( iface->getReadFlag ) { + retVal = ( iface->getReadFlag ) ( ds->rawDataSource ); + } + return retVal; +} + +/* + * Return status code for specified data source. + */ +gint addrindex_ds_get_status_code( AddressDataSource *ds ) { + gint retVal = MGU_SUCCESS; + AddressInterface *iface; + + if( ds == NULL ) return retVal; + iface = ds->interface; + if( iface == NULL ) return retVal; + if( iface->getStatusCode ) { + retVal = ( iface->getStatusCode ) ( ds->rawDataSource ); + } + return retVal; +} + +/* + * Return data read flag for specified data source. + */ +gint addrindex_ds_read_data( AddressDataSource *ds ) { + gint retVal = MGU_SUCCESS; + AddressInterface *iface; + + if( ds == NULL ) return retVal; + iface = ds->interface; + if( iface == NULL ) return retVal; + if( iface->getReadData ) { + retVal = ( iface->getReadData ) ( ds->rawDataSource ); + } + return retVal; +} + +/* + * Return data read flag for specified data source. + */ +ItemFolder *addrindex_ds_get_root_folder( AddressDataSource *ds ) { + ItemFolder *retVal = NULL; + AddressInterface *iface; + + if( ds == NULL ) return retVal; + iface = ds->interface; + if( iface == NULL ) return retVal; + if( iface->getRootFolder ) { + retVal = ( iface->getRootFolder ) ( ds->rawDataSource ); + } + return retVal; +} + +/* + * Return list of folders for specified data source. + */ +GList *addrindex_ds_get_list_folder( AddressDataSource *ds ) { + GList *retVal = FALSE; + AddressInterface *iface; + + if( ds == NULL ) return retVal; + iface = ds->interface; + if( iface == NULL ) return retVal; + if( iface->getListFolder ) { + retVal = ( iface->getListFolder ) ( ds->rawDataSource ); + } + return retVal; +} + +/* + * Return list of persons in root folder for specified data source. + */ +GList *addrindex_ds_get_list_person( AddressDataSource *ds ) { + GList *retVal = FALSE; + AddressInterface *iface; + + if( ds == NULL ) return retVal; + iface = ds->interface; + if( iface == NULL ) return retVal; + if( iface->getListPerson ) { + retVal = ( iface->getListPerson ) ( ds->rawDataSource ); + } + return retVal; +} + +/* + * Return name for specified data source. + */ +gchar *addrindex_ds_get_name( AddressDataSource *ds ) { + gchar *retVal = FALSE; + AddressInterface *iface; + + if( ds == NULL ) return retVal; + iface = ds->interface; + if( iface == NULL ) return retVal; + if( iface->getName ) { + retVal = ( iface->getName ) ( ds->rawDataSource ); + } + return retVal; +} + +/* + * Set the access flag inside the data source. + */ +void addrindex_ds_set_access_flag( AddressDataSource *ds, gboolean *value ) { + AddressInterface *iface; + + if( ds == NULL ) return; + iface = ds->interface; + if( iface == NULL ) return; + if( iface->setAccessFlag ) { + ( iface->setAccessFlag ) ( ds->rawDataSource, value ); + } +} + +/* + * Return read only flag for specified data source. + */ +gboolean addrindex_ds_get_readonly( AddressDataSource *ds ) { + AddressInterface *iface; + if( ds == NULL ) return TRUE; + iface = ds->interface; + if( iface == NULL ) return TRUE; + return iface->readOnly; +} + +/* + * Return list of all persons for specified data source. + */ +GList *addrindex_ds_get_all_persons( AddressDataSource *ds ) { + GList *retVal = NULL; + AddressInterface *iface; + + if( ds == NULL ) return retVal; + iface = ds->interface; + if( iface == NULL ) return retVal; + if( iface->getAllPersons ) { + retVal = ( iface->getAllPersons ) ( ds->rawDataSource ); + } + return retVal; +} + +/* +* End of Source. +*/ + + diff --git a/src/addrindex.h b/src/addrindex.h new file mode 100644 index 000000000..e2cc4b4d2 --- /dev/null +++ b/src/addrindex.h @@ -0,0 +1,130 @@ +/* + * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client + * Copyright (C) 2001 Match Grun + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ + +/* + * General functions for accessing address index file. + */ + +#ifndef __ADDRINDEX_H__ +#define __ADDRINDEX_H__ + +#include +#include +#include "addritem.h" + +#define ADDRESSBOOK_MAX_IFACE 4 +#define ADDRESSBOOK_INDEX_FILE "addrbook--index.xml" +#define ADDRESSBOOK_OLD_FILE "addressbook.xml" + +typedef enum { + ADDR_IF_NONE, + ADDR_IF_BOOK, + ADDR_IF_VCARD, + ADDR_IF_JPILOT, + ADDR_IF_LDAP, + ADDR_IF_COMMON, + ADDR_IF_PERSONAL +} AddressIfType; + +typedef struct _AddressIndex AddressIndex; +struct _AddressIndex { + AddrItemObject obj; + gchar *filePath; + gchar *fileName; + gint retVal; + gboolean needsConversion; + gboolean wasConverted; + gboolean conversionError; + AddressIfType lastType; + gboolean dirtyFlag; + GList *interfaceList; +}; + +typedef struct _AddressInterface AddressInterface; +struct _AddressInterface { + AddrItemObject obj; + AddressIfType type; + gchar *name; + gchar *listTag; + gchar *itemTag; + gboolean legacyFlag; + gboolean useInterface; + gboolean haveLibrary; + gboolean readOnly; + GList *listSource; + gboolean (*getModifyFlag)( void * ); + gboolean (*getAccessFlag)( void * ); + gboolean (*getReadFlag)( void * ); + gint (*getStatusCode)( void * ); + gint (*getReadData)( void * ); + ItemFolder *(*getRootFolder)( void * ); + GList *(*getListFolder)( void * ); + GList *(*getListPerson)( void * ); + GList *(*getAllPersons)( void * ); + gchar *(*getName) ( void * ); + void (*setAccessFlag)( void *, void * ); +}; + +typedef struct _AddressDataSource AddressDataSource; +struct _AddressDataSource { + AddrItemObject obj; + AddressIfType type; + AddressInterface *interface; + gpointer rawDataSource; +}; + +AddressIndex *addrindex_create_index(); +void addrindex_set_file_path( AddressIndex *addrIndex, const gchar *value ); +void addrindex_set_file_name( AddressIndex *addrIndex, const gchar *value ); +void addrindex_set_dirty( AddressIndex *addrIndex, const gboolean value ); +GList *addrindex_get_interface_list( AddressIndex *addrIndex ); +void addrindex_free_index( AddressIndex *addrIndex ); +void addrindex_print_index( AddressIndex *addrIndex, FILE *stream ); + +AddressInterface *addrindex_get_interface( AddressIndex *addrIndex, AddressIfType ifType ); +AddressDataSource *addrindex_index_add_datasource( AddressIndex *addrIndex, AddressIfType ifType, gpointer dataSource ); +AddressDataSource *addrindex_index_remove_datasource( AddressIndex *addrIndex, AddressDataSource *dataSource ); +void addrindex_free_datasource( AddressIndex *addrIndex, AddressDataSource *ds ); + +gint addrindex_read_data( AddressIndex *addrIndex ); +gint addrindex_write_to( AddressIndex *addrIndex, const gchar *newFile ); +gint addrindex_save_data( AddressIndex *addrIndex ); +gint addrindex_create_new_books( AddressIndex *addrIndex ); +gint addrindex_save_all_books( AddressIndex *addrIndex ); + +gboolean addrindex_ds_get_modify_flag( AddressDataSource *ds ); +gboolean addrindex_ds_get_access_flag( AddressDataSource *ds ); +gboolean addrindex_ds_get_read_flag( AddressDataSource *ds ); +gint addrindex_ds_get_status_code( AddressDataSource *ds ); +gint addrindex_ds_read_data( AddressDataSource *ds ); +ItemFolder *addrindex_ds_get_root_folder( AddressDataSource *ds ); +GList *addrindex_ds_get_list_folder( AddressDataSource *ds ); +GList *addrindex_ds_get_list_person( AddressDataSource *ds ); +gchar *addrindex_ds_get_name( AddressDataSource *ds ); +void addrindex_ds_set_access_flag( AddressDataSource *ds, gboolean *value ); +gboolean addrindex_ds_get_readonly( AddressDataSource *ds ); +GList *addrindex_ds_get_all_persons( AddressDataSource *ds ); + +#endif /* __ADDRINDEX_H__ */ + +/* +* End of Source. +*/ + + diff --git a/src/addritem.c b/src/addritem.c new file mode 100644 index 000000000..5517745ef --- /dev/null +++ b/src/addritem.c @@ -0,0 +1,966 @@ +/* + * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client + * Copyright (C) 2001 Match Grun + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ + +/* + * General primitive address item objects. + */ + +#include +#include + +#include "addritem.h" +#include "mgutils.h" + +/* +* Create new email address item. +*/ +ItemEMail *addritem_create_item_email( void ) { + ItemEMail *item; + item = g_new0( ItemEMail, 1 ); + ADDRITEM_TYPE(item) = ITEMTYPE_EMAIL; + ADDRITEM_ID(item) = NULL; + ADDRITEM_NAME(item) = NULL; + ADDRITEM_PARENT(item) = NULL; + ADDRITEM_SUBTYPE(item) = 0; + item->address = NULL; + item->remarks = NULL; + return item; +} + +/* +* Create copy of specified email address item. +*/ +ItemEMail *addritem_copy_item_email( ItemEMail *item ) { + ItemEMail *itemNew = NULL; + if( item ) { + itemNew = addritem_create_item_email(); + ADDRITEM_TYPE(itemNew) = ADDRITEM_TYPE(item); + ADDRITEM_ID(itemNew) = g_strdup( ADDRITEM_ID(item) ); + ADDRITEM_NAME(itemNew) = g_strdup( ADDRITEM_NAME(item) ); + ADDRITEM_PARENT(itemNew) = ADDRITEM_PARENT(item); + itemNew->address = g_strdup( item->address ); + itemNew->remarks = g_strdup( item->remarks ); + } + return itemNew; +} + +void addritem_email_set_id( ItemEMail *email, const gchar *value ) { + ADDRITEM_ID(email) = mgu_replace_string( ADDRITEM_ID(email), value ); +} +void addritem_email_set_alias( ItemEMail *email, const gchar *value ) { + ADDRITEM_NAME(email) = mgu_replace_string( ADDRITEM_NAME(email), value ); +} +void addritem_email_set_address( ItemEMail *email, const gchar *value ) { + email->address = mgu_replace_string( email->address, value ); +} +void addritem_email_set_remarks( ItemEMail *email, const gchar *value ) { + email->remarks = mgu_replace_string( email->remarks, value ); +} + +/* +* Free address item email. +*/ +void addritem_free_item_email( ItemEMail *item ) { + g_return_if_fail( item != NULL ); + + /* Free internal stuff */ + g_free( ADDRITEM_ID(item) ); + g_free( ADDRITEM_NAME(item) ); + g_free( item->address ); + g_free( item->remarks ); + + ADDRITEM_OBJECT(item)->type = ITEMTYPE_NONE; + ADDRITEM_ID(item) = NULL; + ADDRITEM_NAME(item) = NULL; + ADDRITEM_PARENT(item) = NULL; + ADDRITEM_SUBTYPE(item) = 0; + item->address = NULL; + item->remarks = NULL; + g_free( item ); +} + +/* +* Create new attribute. +*/ +UserAttribute *addritem_create_attribute( void ) { + UserAttribute *item; + item = g_new0( UserAttribute, 1 ); + item->uid = NULL; + item->name = NULL; + item->value = NULL; + return item; +} + +/* +* Create copy of specified attribute. +*/ +UserAttribute *addritem_copy_attribute( UserAttribute *item ) { + UserAttribute *itemNew = NULL; + if( item ) { + itemNew = addritem_create_attribute(); + itemNew->uid = g_strdup( item->uid ); + itemNew->name = g_strdup( item->name ); + itemNew->value = g_strdup( item->value ); + } + return itemNew; +} + +void addritem_attrib_set_id( UserAttribute *item, const gchar *value ) { + g_return_if_fail( item != NULL ); + item->uid = mgu_replace_string( item->uid, value ); +} +void addritem_attrib_set_name( UserAttribute *item, const gchar *value ) { + g_return_if_fail( item != NULL ); + item->name = mgu_replace_string( item->name, value ); +} +void addritem_attrib_set_value( UserAttribute *item, const gchar *value ) { + g_return_if_fail( item != NULL ); + item->value = mgu_replace_string( item->value, value ); +} + +/* +* Free user attribute. +*/ +void addritem_free_attribute( UserAttribute *item ) { + g_return_if_fail( item != NULL ); + g_free( item->uid ); + g_free( item->name ); + g_free( item->value ); + item->uid = NULL; + item->name = NULL; + item->value = NULL; + g_free( item ); +} + +/* +* Create new address book person. +*/ +ItemPerson *addritem_create_item_person( void ) { + ItemPerson *person; + person = g_new0( ItemPerson, 1 ); + ADDRITEM_TYPE(person) = ITEMTYPE_PERSON; + ADDRITEM_ID(person) = NULL; + ADDRITEM_NAME(person) = NULL; + ADDRITEM_PARENT(person) = NULL; + ADDRITEM_SUBTYPE(person) = 0; + person->firstName = NULL; + person->lastName = NULL; + person->nickName = NULL; + person->listEMail = NULL; + person->listAttrib = NULL; + person->externalID = NULL; + person->isOpened = FALSE; + return person; +} + +void addritem_person_set_id( ItemPerson *person, const gchar *value ) { + ADDRITEM_ID(person) = mgu_replace_string( ADDRITEM_ID(person), value ); +} +void addritem_person_set_first_name( ItemPerson *person, const gchar *value ) { + person->firstName = mgu_replace_string( person->firstName, value ); +} +void addritem_person_set_last_name( ItemPerson *person, const gchar *value ) { + person->lastName = mgu_replace_string( person->lastName, value ); +} +void addritem_person_set_nick_name( ItemPerson *person, const gchar *value ) { + person->nickName = mgu_replace_string( person->nickName, value ); +} +void addritem_person_set_common_name( ItemPerson *person, const gchar *value ) { + ADDRITEM_NAME(person) = mgu_replace_string( ADDRITEM_NAME(person), value ); +} +void addritem_person_set_external_id( ItemPerson *person, const gchar *value ) { + person->externalID = mgu_replace_string( person->externalID, value ); +} +void addritem_person_set_opened( ItemPerson *person, const gboolean value ) { + person->isOpened = value; +} + +/* +* Free linked list of item addresses. +*/ +void addritem_free_list_email( GList *list ) { + GList *node = list; + while( node ) { + addritem_free_item_email( node->data ); + node->data = NULL; + node = g_list_next( node ); + } + g_list_free( list ); +} + +/* +* Free linked list of attributes. +*/ +void addritem_free_list_attribute( GList *list ) { + GList *node = list; + while( node ) { + addritem_free_attribute( node->data ); + node->data = NULL; + node = g_list_next( node ); + } + g_list_free( list ); +} + +/* +* Free address person. +*/ +void addritem_free_item_person( ItemPerson *person ) { + g_return_if_fail( person != NULL ); + + /* Free internal stuff */ + g_free( ADDRITEM_ID(person) ); + g_free( ADDRITEM_NAME(person) ); + g_free( person->firstName ); + g_free( person->lastName ); + g_free( person->nickName ); + g_free( person->externalID ); + addritem_free_list_email( person->listEMail ); + addritem_free_list_attribute( person->listAttrib ); + + ADDRITEM_OBJECT(person)->type = ITEMTYPE_NONE; + ADDRITEM_ID(person) = NULL; + ADDRITEM_NAME(person) = NULL; + ADDRITEM_PARENT(person) = NULL; + ADDRITEM_SUBTYPE(person) = 0; + person->firstName = NULL; + person->lastName = NULL; + person->nickName = NULL; + person->externalID = NULL; + person->listEMail = NULL; + person->listAttrib = NULL; + + g_free( person ); +} + +/* +* Print address item. +*/ +void addritem_print_item_email( ItemEMail *item, FILE *stream ) { + g_return_if_fail( item != NULL ); + fprintf( stream, "\t\tt/id: %d : '%s'\n", ADDRITEM_TYPE(item), ADDRITEM_ID(item) ); + fprintf( stream, "\t\tsubty: %d\n", ADDRITEM_SUBTYPE(item) ); + fprintf( stream, "\t\talis: '%s'\n", ADDRITEM_NAME(item) ); + fprintf( stream, "\t\taddr: '%s'\n", item->address ); + fprintf( stream, "\t\trems: '%s'\n", item->remarks ); + fprintf( stream, "\t\t---\n" ); +} + +/* +* Print user attribute. +*/ +void addritem_print_attribute( UserAttribute *item, FILE *stream ) { + g_return_if_fail( item != NULL ); + fprintf( stream, "\t\tuid : '%s'\n", item->uid ); + fprintf( stream, "\t\tname : '%s'\n", item->name ); + fprintf( stream, "\t\tvalue: '%s'\n", item->value ); + fprintf( stream, "\t\t---\n" ); +} + +/* +* Print person item. +*/ +void addritem_print_item_person( ItemPerson *person, FILE *stream ) { + GList *node; + g_return_if_fail( person != NULL ); + fprintf( stream, "Person:\n" ); + fprintf( stream, "\tt/uid: %d : '%s'\n", ADDRITEM_TYPE(person), ADDRITEM_ID(person) ); + fprintf( stream, "\tsubty: %d\n", ADDRITEM_SUBTYPE(person) ); + fprintf( stream, "\tcommn: '%s'\n", ADDRITEM_NAME(person) ); + fprintf( stream, "\tfirst: '%s'\n", person->firstName ); + fprintf( stream, "\tlast : '%s'\n", person->lastName ); + fprintf( stream, "\tnick : '%s'\n", person->nickName ); + fprintf( stream, "\textID: '%s'\n", person->externalID ); + fprintf( stream, "\teMail:\n" ); + fprintf( stream, "\t---\n" ); + node = person->listEMail; + while( node ) { + addritem_print_item_email( node->data, stream ); + node = g_list_next( node ); + } + fprintf( stream, "\tuAttr:\n" ); + fprintf( stream, "\t---\n" ); + node = person->listAttrib; + while( node ) { + addritem_print_attribute( node->data, stream ); + node = g_list_next( node ); + } + fprintf( stream, "\t===\n" ); +} + +/* +* Add EMail address to person. +* return: TRUE if item added. +*/ +gboolean addritem_person_add_email( ItemPerson *person, ItemEMail *email ) { + GList *node; + g_return_if_fail( person != NULL ); + g_return_if_fail( email != NULL ); + node = person->listEMail; + while( node ) { + if( node->data == email ) return FALSE; + node = g_list_next( node ); + } + person->listEMail = g_list_append( person->listEMail, email ); + ADDRITEM_PARENT(email) = ADDRITEM_OBJECT(person); + return TRUE; +} + +/* +* Return email object with specified ID. +* param: person Person object. +* eid EMail ID. +* return: EMail object, or NULL if not found. +*/ +ItemEMail *addritem_person_get_email( ItemPerson *person, const gchar *eid ) { + ItemEMail *email = NULL; + GList *node; + g_return_if_fail( person != NULL ); + if( eid == NULL || *eid == '\0' ) return NULL; + + // Look for email + node = person->listEMail; + while( node ) { + AddrItemObject *objE = node->data; + gchar *ide = ADDRITEM_ID(objE); + if( ide ) { + if( strcmp( ide, eid ) == 0 ) { + email = ( ItemEMail * ) objE; + } + } + node = g_list_next( node ); + } + return email; +} + +/* +* Remove email address for specified person. +* param: person Person object. +* eid EMail ID. +* return: EMail object, or NULL if not found. Note that object should still be freed. +*/ +ItemEMail *addritem_person_remove_email_id( ItemPerson *person, const gchar *eid ) { + ItemEMail *email = NULL; + GList *node; + g_return_if_fail( person != NULL ); + if( eid == NULL || *eid == '\0' ) return NULL; + + // Look for email + node = person->listEMail; + while( node ) { + AddrItemObject *objE = node->data; + gchar *ide = ADDRITEM_ID(objE); + if( ide ) { + if( strcmp( ide, eid ) == 0 ) { + email = ( ItemEMail * ) objE; + } + } + node = g_list_next( node ); + } + + if( email ) { + // Remove email from person's address list + if( person->listEMail ) { + person->listEMail = g_list_remove( person->listEMail, email ); + } + // Unlink reference to person. + ADDRITEM_PARENT(email) = NULL; + } + return email; +} + +/* +* Remove email address for specified. +* param: person Person. +* email EMail to remove. +* return: EMail object, or NULL if not found. Note that object should still be freed. +*/ +ItemEMail *addritem_person_remove_email( ItemPerson *person, ItemEMail *email ) { + gboolean found = FALSE; + GList *node; + g_return_if_fail( person != NULL ); + if( email == NULL ) return NULL; + + // Look for email + node = person->listEMail; + while( node ) { + if( node-> data == email ) { + found = TRUE; + break; + } + node = g_list_next( node ); + } + + if( found ) { + // Remove email from person's address list + if( person->listEMail ) { + person->listEMail = g_list_remove( person->listEMail, email ); + } + // Unlink reference to person. + ADDRITEM_PARENT(email) = NULL; + return email; + } + return NULL; +} + +/* +* Add user attribute to person. +* return: TRUE if item added. +*/ +void addritem_person_add_attribute( ItemPerson *person, UserAttribute *attrib ) { + g_return_if_fail( person != NULL ); + person->listAttrib = g_list_append( person->listAttrib, attrib ); +} + +/* +* Return attribute with specified ID. +* param: person Person object. +* aid Attribute ID. +* return: UserAttribute object, or NULL if not found. Note that object should still be freed. +*/ +UserAttribute *addritem_person_get_attribute( ItemPerson *person, const gchar *aid ) { + UserAttribute *attrib = NULL; + GList *node; + g_return_if_fail( person != NULL ); + if( aid == NULL || *aid == '\0' ) return NULL; + + // Look for attribute + node = person->listAttrib; + while( node ) { + UserAttribute *attr = node->data; + gchar *ida = attr->uid; + if( ida ) { + if( strcmp( ida, aid ) == 0 ) { + attrib = attr; + } + } + node = g_list_next( node ); + } + return attrib; +} + +/* +* Remove attribute from person. +* param: person Person object. +* aid Attribute ID. +* return: UserAttribute object, or NULL if not found. Note that object should still be freed. +*/ +UserAttribute *addritem_person_remove_attrib_id( ItemPerson *person, const gchar *aid ) { + UserAttribute *attrib = NULL; + GList *node; + g_return_if_fail( person != NULL ); + if( aid == NULL || *aid == '\0' ) return NULL; + + // Look for attribute + node = person->listAttrib; + while( node ) { + UserAttribute *attr = node->data; + gchar *ida = attr->uid; + if( ida ) { + if( strcmp( ida, aid ) == 0 ) { + attrib = attr; + } + } + node = g_list_next( node ); + } + + // Remove email from person's address list + if( person->listAttrib ) { + person->listAttrib = g_list_remove( person->listAttrib, attrib ); + } + return attrib; +} + +/* +* Remove attribute from person. +* param: person Person. +* attrib Attribute to remove. +* return: UserAttribute object. Note that object should still be freed. +*/ +UserAttribute *addritem_person_remove_attribute( ItemPerson *person, UserAttribute *attrib ) { + gboolean found = FALSE; + GList *node; + g_return_if_fail( person != NULL ); + if( attrib == NULL ) return NULL; + + // Look for attribute + node = person->listAttrib; + while( node ) { + if( node-> data == attrib ) { + found = TRUE; + break; + } + node = g_list_next( node ); + } + + if( found ) { + // Remove attribute + if( person->listAttrib ) { + person->listAttrib = g_list_remove( person->listAttrib, attrib ); + } + } + return attrib; +} + +/* +* Create new address book group. +*/ +ItemGroup *addritem_create_item_group( void ) { + ItemGroup *group; + group = g_new0( ItemGroup, 1 ); + ADDRITEM_TYPE(group) = ITEMTYPE_GROUP; + ADDRITEM_ID(group) = NULL; + ADDRITEM_NAME(group) = NULL; + ADDRITEM_PARENT(group) = NULL; + ADDRITEM_SUBTYPE(group) = 0; + group->remarks = NULL; + group->listEMail = NULL; + return group; +} + +/* +* Specify name to be used. +*/ +void addritem_group_set_id( ItemGroup *group, const gchar *value ) { + ADDRITEM_ID(group) = mgu_replace_string( ADDRITEM_ID(group), value ); +} +void addritem_group_set_name( ItemGroup *group, const gchar *value ) { + ADDRITEM_NAME(group) = mgu_replace_string( ADDRITEM_NAME(group), value ); +} +void addritem_group_set_remarks( ItemGroup *group, const gchar *value ) { + group->remarks = mgu_replace_string( group->remarks, value ); +} + +/* +* Free address group. +*/ +void addritem_free_item_group( ItemGroup *group ) { + g_return_if_fail( group != NULL ); + + /* Free internal stuff */ + g_free( ADDRITEM_ID(group) ); + g_free( ADDRITEM_NAME(group) ); + g_free( group->remarks ); + mgu_clear_list( group->listEMail ); + g_list_free( group->listEMail ); + + ADDRITEM_TYPE(group) = ITEMTYPE_NONE; + ADDRITEM_ID(group) = NULL; + ADDRITEM_NAME(group) = NULL; + ADDRITEM_PARENT(group) = NULL; + ADDRITEM_SUBTYPE(group) = 0; + group->remarks = NULL; + group->listEMail = NULL; + + g_free( group ); +} + +/* +* Add EMail address to group. +* return: TRUE if item added. +*/ +gboolean addritem_group_add_email( ItemGroup *group, ItemEMail *email ) { + GList *node; + g_return_if_fail( group != NULL ); + g_return_if_fail( email != NULL ); + node = group->listEMail; + while( node ) { + if( node->data == email ) return FALSE; + node = g_list_next( node ); + } + group->listEMail = g_list_append( group->listEMail, email ); + return TRUE; +} + +/* +* Remove email address for specified group. +* param: group Group from which to remove address. +* email EMail to remove +* return: EMail object, or NULL if email not found in group. Note that this object is +* referenced (linked) to a group and should *NOT* be freed. This object should only be +* freed after removing from a person. +*/ +ItemEMail *addritem_group_remove_email( ItemGroup *group, ItemEMail *email ) { + if( group && email ) { + GList *node = group->listEMail; + while( node ) { + if( node->data == email ) { + group->listEMail = g_list_remove( group->listEMail, email ); + return email; + } + node = g_list_next( node ); + } + } + return NULL; +} + +/* +* Remove email address for specified group and ID. +* param: group Group from which to remove address. +* eid EMail ID. +* return: EMail object, or NULL if email not found in group. Note that this object is +* referenced (linked) to a group and should *NOT* be freed. This object should only be +* freed after removing from a person. +*/ +ItemEMail *addritem_group_remove_email_id( ItemGroup *group, const gchar *eid ) { + if( group ) { + GList *node = group->listEMail; + while( node ) { + ItemEMail *email = ( ItemEMail * ) node->data; + if( strcmp( ADDRITEM_ID( email ), eid ) == 0 ) { + group->listEMail = g_list_remove( group->listEMail, email ); + return email; + } + node = g_list_next( node ); + } + } + return NULL; +} + +/* +* Print address group item. +*/ +void addritem_print_item_group( ItemGroup *group, FILE *stream ) { + GList *node; + ItemPerson *person; + ItemEMail *item; + g_return_if_fail( group != NULL ); + fprintf( stream, "Group:\n" ); + fprintf( stream, "\tt/u: %d : '%s'\n", ADDRITEM_TYPE(group), ADDRITEM_ID(group) ); + fprintf( stream, "\tsub: %d\n", ADDRITEM_SUBTYPE(group) ); + fprintf( stream, "\tgrp: '%s'\n", ADDRITEM_NAME(group) ); + fprintf( stream, "\trem: '%s'\n", group->remarks ); + fprintf( stream, "\t---\n" ); + node = group->listEMail; + while( node ) { + item = node->data; + person = ( ItemPerson * ) ADDRITEM_PARENT(item); + if( person ) { + fprintf( stream, "\t\tpid : '%s'\n", ADDRITEM_ID(person) ); + fprintf( stream, "\t\tcomn: '%s'\n", ADDRITEM_NAME(person) ); + } + else { + fprintf( stream, "\t\tpid : ???\n" ); + fprintf( stream, "\t\tcomn: ???\n" ); + } + addritem_print_item_email( item, stream ); + node = g_list_next( node ); + } + fprintf( stream, "\t***\n" ); +} + +/* +* Create new address folder. +*/ +ItemFolder *addritem_create_item_folder( void ) { + ItemFolder *folder; + folder = g_new0( ItemFolder, 1 ); + ADDRITEM_TYPE(folder) = ITEMTYPE_FOLDER; + ADDRITEM_ID(folder) = NULL; + ADDRITEM_NAME(folder) = NULL; + ADDRITEM_PARENT(folder) = NULL; + ADDRITEM_SUBTYPE(folder) = 0; + folder->remarks = NULL; + folder->isRoot = FALSE; + folder->listItems = NULL; + folder->listFolder = NULL; + folder->listPerson = NULL; + folder->listGroup = NULL; + folder->userData = NULL; + return folder; +} + +/* +* Specify name to be used. +*/ +void addritem_folder_set_id( ItemFolder *folder, const gchar *value ) { + ADDRITEM_ID(folder) = mgu_replace_string( ADDRITEM_ID(folder), value ); +} +void addritem_folder_set_name( ItemFolder *folder, const gchar *value ) { + ADDRITEM_NAME(folder) = mgu_replace_string( ADDRITEM_NAME(folder), value ); +} +void addritem_folder_set_remarks( ItemFolder *folder, const gchar *value ) { + folder->remarks = mgu_replace_string( folder->remarks, value ); +} + +/* +* Free address folder. Note: this does not free up the lists of children +* (folders, groups and person). This should be done prior to calling this +* function. +*/ +void addritem_free_item_folder( ItemFolder *folder ) { + g_return_if_fail( folder != NULL ); + + // Free internal stuff + g_free( ADDRITEM_ID(folder) ); + g_free( ADDRITEM_NAME(folder) ); + g_free( folder->remarks ); + mgu_clear_list( folder->listItems ); + g_list_free( folder->listItems ); + + ADDRITEM_TYPE(folder) = ITEMTYPE_NONE; + ADDRITEM_ID(folder) = NULL; + ADDRITEM_NAME(folder) = NULL; + ADDRITEM_PARENT(folder) = NULL; + ADDRITEM_SUBTYPE(folder) = 0; + folder->isRoot = FALSE; + folder->remarks = NULL; + folder->listItems = NULL; + folder->listFolder = NULL; + folder->listGroup = NULL; + folder->listPerson = NULL; + + g_free( folder->userData ); + folder->userData = NULL; + + g_free( folder ); +} + +/* +* Free up folders recursively. Note: this does not free up the lists of children +* (folders, groups and person). This should be done prior to calling this +* function. +*/ +void addritem_free_item_folder_recurse( ItemFolder *parent ) { + GList *node = parent->listFolder; + while( node ) { + ItemFolder *folder = node->data; + addritem_free_item_folder_recurse( folder ); + node = g_list_next( node ); + } + g_list_free( parent->listPerson ); + g_list_free( parent->listGroup ); + g_list_free( parent->listFolder ); + parent->listPerson = NULL; + parent->listGroup = NULL; + parent->listFolder = NULL; +} + +/* +* Free up list of person in specified folder. +*/ +void addritem_folder_free_person( ItemFolder *folder ) { + GList *node; + g_return_if_fail( folder != NULL ); + + // Free up folder of persons. + node = folder->listPerson; + while( node ) { + ItemPerson *person = node->data; + addritem_free_item_person( person ); + person = NULL; + node = g_list_next( node ); + } +} + +/* +* Add person into folder. +* return: TRUE if person added. +*/ +gboolean addritem_folder_add_person( ItemFolder *folder, ItemPerson *item ) { + gboolean retVal = FALSE; + g_return_if_fail( folder != NULL ); + g_return_if_fail( item != NULL ); + folder->listPerson = g_list_append( folder->listPerson, item ); + ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder); + return TRUE; +} + +/* +* Add folder into folder. +* return: TRUE if folder added. +*/ +gboolean addritem_folder_add_folder( ItemFolder *folder, ItemFolder *item ) { + gboolean retVal = FALSE; + g_return_if_fail( folder != NULL ); + g_return_if_fail( item != NULL ); + folder->listFolder = g_list_append( folder->listFolder, item ); + ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder); + return TRUE; +} + +/* +* Add group into folder. +* return: TRUE if folder added. +*/ +gboolean addritem_folder_add_group( ItemFolder *folder, ItemGroup *item ) { + gboolean retVal = FALSE; + g_return_if_fail( folder != NULL ); + g_return_if_fail( item != NULL ); + folder->listGroup = g_list_append( folder->listGroup, item ); + ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder); + return TRUE; +} + +/* +* Print address folder item. +*/ +void addritem_print_item_folder( ItemFolder *folder, FILE *stream ) { + GList *node; + ItemPerson *person; + ItemFolder *parent; + g_return_if_fail( folder != NULL ); + fprintf( stream, "Folder:\n" ); + fprintf( stream, "\tt/u: %d : '%s'\n", ADDRITEM_TYPE(folder), ADDRITEM_ID(folder) ); + fprintf( stream, "\tsub: %d\n", ADDRITEM_SUBTYPE(folder) ); + fprintf( stream, "\tnam: '%s'\n", ADDRITEM_NAME(folder) ); + fprintf( stream, "\trem: '%s'\n", folder->remarks ); + fprintf( stream, "\t---\n" ); + parent = ( ItemFolder * ) ADDRITEM_PARENT(folder); + if( parent ) { + fprintf( stream, "\tpar: %s : %s\n", ADDRITEM_ID(parent), ADDRITEM_NAME(parent) ); + } + else { + fprintf( stream, "\tpar: NULL\n" ); + } + node = folder->listFolder; + while( node ) { + AddrItemObject *aio = node->data; + if( aio ) { + if( aio->type == ITEMTYPE_FOLDER ) { + ItemFolder *item = ( ItemFolder * ) aio; + addritem_print_item_folder( item, stream ); + } + } + else { + fprintf( stream, "\t\tpid : ???\n" ); + } + + node = g_list_next( node ); + } + + node = folder->listPerson; + while( node ) { + AddrItemObject *aio = node->data; + if( aio ) { + if( aio->type == ITEMTYPE_PERSON ) { + ItemPerson *item = ( ItemPerson * ) aio; + addritem_print_item_person( item, stream ); + } + } + else { + fprintf( stream, "\t\tpid : ???\n" ); + } + + node = g_list_next( node ); + } + + node = folder->listGroup; + while( node ) { + AddrItemObject *aio = node->data; + if( aio ) { + if( aio->type == ITEMTYPE_GROUP ) { + ItemGroup *item = ( ItemGroup * ) aio; + addritem_print_item_group( item, stream ); + } + } + else { + fprintf( stream, "\t\tpid : ???\n" ); + } + node = g_list_next( node ); + } + fprintf( stream, "\t###\n" ); +} + +/* +* Return link list of persons for specified folder. Note that the list contains +* references to items and should be g_free() when done. Do *NOT* attempt to use the +* addritem_free_xxx() functions... this will destroy the addressbook data! +* Return: List of items, or NULL if none. +*/ +GList *addritem_folder_get_person_list( ItemFolder *folder ) { + GList *list = NULL; + GList *node = NULL; + g_return_if_fail( folder != NULL ); + + node = folder->listPerson; + while( node ) { + ItemPerson *person = node->data; + list = g_list_append( list, node->data ); + node = g_list_next( node ); + } + return list; +} + +/* +* Return link list of groups for specified folder. Note that the list contains +* references to items and should be g_free() when done. Do *NOT* attempt to use the +* addritem_free_xxx() functions... this will destroy the addressbook data! +* Return: List of items, or NULL if none. +*/ +GList *addritem_folder_get_group_list( ItemFolder *folder ) { + GList *list = NULL; + GList *node = NULL; + g_return_if_fail( folder != NULL ); + + node = folder->listGroup; + while( node ) { + ItemGroup *group = node->data; + list = g_list_append( list, node->data ); + node = g_list_next( node ); + } + return list; +} + +/* +* Move person's email item. +* param: person Person. +* itemMove Item to move. +* itemTarget Target item before which to move item. +*/ + +ItemEMail *addritem_move_email_before( ItemPerson *person, ItemEMail *itemMove, ItemEMail *itemTarget ) { + gint posT, posM; + g_return_if_fail( person != NULL ); + if( itemTarget == NULL ) return NULL; + if( itemMove == NULL ) return NULL; + if( itemMove == itemTarget ) return itemMove; + posT = g_list_index( person->listEMail, itemTarget ); + if( posT < 0 ) return NULL; + posM = g_list_index( person->listEMail, itemMove ); + if( posM < 0 ) return NULL; + person->listEMail = g_list_remove( person->listEMail, itemMove ); + person->listEMail = g_list_insert( person->listEMail, itemMove, posT ); + return itemMove; +} + +/* +* Move person's email item. +* param: person Person. +* itemMove Item to move. +* itemTarget Target item after which to move item. +*/ +ItemEMail *addritem_move_email_after( ItemPerson *person, ItemEMail *itemMove, ItemEMail *itemTarget ) { + gint posT, posM; + g_return_if_fail( person != NULL ); + if( itemTarget == NULL ) return NULL; + if( itemMove == NULL ) return NULL; + if( itemMove == itemTarget ) return itemMove; + posT = g_list_index( person->listEMail, itemTarget ); + if( posT < 0 ) return NULL; + posM = g_list_index( person->listEMail, itemMove ); + if( posM < 0 ) return NULL; + person->listEMail = g_list_remove( person->listEMail, itemMove ); + person->listEMail = g_list_insert( person->listEMail, itemMove, 1+posT ); + return itemMove; +} + +/* +* End of Source. +*/ + diff --git a/src/addritem.h b/src/addritem.h new file mode 100644 index 000000000..66dca4833 --- /dev/null +++ b/src/addritem.h @@ -0,0 +1,175 @@ +/* + * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client + * Copyright (C) 1999,2000 Hiroyuki Yamamoto + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ + +/* + * Address item data. + */ + +#ifndef __ADDRITEM_H__ +#define __ADDRITEM_H__ + +#include +#include + +#define ADDRITEM_OBJECT(obj) ((AddrItemObject *)obj) +#define ADDRITEM_TYPE(obj) (ADDRITEM_OBJECT(obj)->type) +#define ADDRITEM_NAME(obj) (ADDRITEM_OBJECT(obj)->name) +#define ADDRITEM_ID(obj) (ADDRITEM_OBJECT(obj)->uid) +#define ADDRITEM_PARENT(obj) (ADDRITEM_OBJECT(obj)->parent) +#define ADDRITEM_SUBTYPE(obj) (ADDRITEM_OBJECT(obj)->subType) + +typedef enum { + ITEMTYPE_NONE, + ITEMTYPE_PERSON, + ITEMTYPE_EMAIL, + ITEMTYPE_FOLDER, + ITEMTYPE_GROUP, + ITEMTYPE_INDEX, + ITEMTYPE_INTERFACE, + ITEMTYPE_DATASOURCE +} ItemObjectType; + +typedef struct _AddrItemObject AddrItemObject; +struct _AddrItemObject { + ItemObjectType type; + gchar *name; + gchar *uid; + AddrItemObject *parent; + gint subType; +}; + +typedef struct _ItemPerson ItemPerson; +struct _ItemPerson { + AddrItemObject obj; + gchar *firstName; + gchar *lastName; + gchar *nickName; + gchar *externalID; + GList *listEMail; + GList *listAttrib; + gboolean isOpened; +}; + +typedef struct _ItemEMail ItemEMail; +struct _ItemEMail { + AddrItemObject obj; + gchar *address; + gchar *remarks; +}; + +typedef struct _UserAttribute UserAttribute; +struct _UserAttribute { + gchar *uid; + gchar *name; + gchar *value; +}; + +typedef struct _ItemFolder ItemFolder; +struct _ItemFolder { + AddrItemObject obj; + gchar *remarks; + gboolean isRoot; + GList *listItems; + GList *listFolder; + GList *listPerson; + GList *listGroup; + gpointer userData; +}; + +typedef struct _ItemGroup ItemGroup; +struct _ItemGroup { + AddrItemObject obj; + gchar *remarks; + GList *listEMail; +}; + +/* Function prototypes */ +ItemEMail *addritem_create_item_email ( void ); +ItemEMail *addritem_copy_item_email ( ItemEMail *item ); +void addritem_email_set_id ( ItemEMail *email, const gchar *value ); +void addritem_email_set_alias ( ItemEMail *email, const gchar *value ); +void addritem_email_set_address ( ItemEMail *email, const gchar *value ); +void addritem_email_set_remarks ( ItemEMail *email, const gchar *value ); +void addritem_free_item_email ( ItemEMail *item ); + +UserAttribute *addritem_create_attribute( void ); +UserAttribute *addritem_copy_attribute ( UserAttribute *item ); +void addritem_attrib_set_id ( UserAttribute *item, const gchar *value ); +void addritem_attrib_set_name ( UserAttribute *item, const gchar *value ); +void addritem_attrib_set_value ( UserAttribute *item, const gchar *value ); +void addritem_free_attribute ( UserAttribute *item ); + +ItemPerson *addritem_create_item_person ( void ); +void addritem_person_set_id ( ItemPerson *person, const gchar *value ); +void addritem_person_set_first_name ( ItemPerson *person, const gchar *value ); +void addritem_person_set_last_name ( ItemPerson *person, const gchar *value ); +void addritem_person_set_nick_name ( ItemPerson *person, const gchar *value ); +void addritem_person_set_common_name ( ItemPerson *person, const gchar *value ); +void addritem_person_set_opened ( ItemPerson *person, const gboolean value ); +void addritem_free_item_person ( ItemPerson *person ); +void addritem_free_list_email ( GList *list ); +void addritem_free_list_attribute ( GList *list ); + +ItemGroup *addritem_create_item_group ( void ); +void addritem_free_item_group ( ItemGroup *group ); +void addritem_print ( ItemGroup *group, FILE *stream ); +void addritem_group_set_id ( ItemGroup *group, const gchar *value ); +void addritem_group_set_name ( ItemGroup *group, const gchar *value ); +void addritem_group_set_remarks ( ItemGroup *group, const gchar *value ); + +void addritem_print_item_email ( ItemEMail *item, FILE *stream ); +void addritem_print_attribute ( UserAttribute *item, FILE *stream ); +void addritem_print_item_person ( ItemPerson *person, FILE *stream ); +void addritem_print_item_group ( ItemGroup *group, FILE *stream ); +void addritem_print_item_folder ( ItemFolder *folder, FILE *stream ); + +gboolean addritem_person_add_email ( ItemPerson *person, ItemEMail *email ); +ItemEMail *addritem_person_get_email ( ItemPerson *person, const gchar *eid ); +ItemEMail *addritem_person_remove_email_id ( ItemPerson *person, const gchar *eid ); +ItemEMail *addritem_person_remove_email ( ItemPerson *person, ItemEMail *email ); + +void addritem_person_add_attribute ( ItemPerson *person, UserAttribute *attrib ); +UserAttribute *addritem_person_get_attribute ( ItemPerson *person, const gchar *aid ); +UserAttribute *addritem_person_remove_attrib_id ( ItemPerson *person, const gchar *aid ); +UserAttribute *addritem_person_remove_attribute ( ItemPerson *person, UserAttribute *attrib ); + +ItemFolder *addritem_create_item_folder ( void ); +void addritem_folder_set_id ( ItemFolder *folder, const gchar *value ); +void addritem_folder_set_name ( ItemFolder *folder, const gchar *value ); +void addritem_folder_set_remarks ( ItemFolder *folder, const gchar *value ); +void addritem_free_item_folder ( ItemFolder *folder ); +void addritem_free_item_folder_recurse ( ItemFolder *parent ); + +gboolean addritem_group_add_email ( ItemGroup *group, ItemEMail *email ); +ItemEMail *addritem_group_remove_email ( ItemGroup *group, ItemEMail *email ); +ItemEMail *addritem_group_remove_email_id ( ItemGroup *group, const gchar *eid ); + +gboolean addritem_folder_add_person ( ItemFolder *folder, ItemPerson *item ); +gboolean addritem_folder_add_folder ( ItemFolder *folder, ItemFolder *item ); +gboolean addritem_folder_add_group ( ItemFolder *folder, ItemGroup *item ); +void addritem_folder_free_person ( ItemFolder *folder ); +GList *addritem_folder_get_person_list ( ItemFolder *folder ); +GList *addritem_folder_get_group_list ( ItemFolder *folder ); + +ItemEMail *addritem_move_email_before ( ItemPerson *person, ItemEMail *itemMove, ItemEMail *itemTarget ); +ItemEMail *addritem_move_email_after ( ItemPerson *person, ItemEMail *itemMove, ItemEMail *itemTarget ); + +#endif /* __ADDRITEM_H__ */ + + diff --git a/src/editaddress.c b/src/editaddress.c new file mode 100644 index 000000000..eea5c8c9f --- /dev/null +++ b/src/editaddress.c @@ -0,0 +1,1166 @@ +/* + * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client + * Copyright (C) 1999,2000 Hiroyuki Yamamoto + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "defs.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "intl.h" +#include "mgutils.h" +#include "addressbook.h" +#include "addressitem.h" +#include "addritem.h" +#include "addrbook.h" + +#include "prefs_common.h" + +/* +static struct _AddressEdit_dlg { + GtkWidget *window; + GtkWidget *name_entry; + GtkWidget *addr_entry; + GtkWidget *rem_entry; + GtkWidget *ok_btn; + GtkWidget *cancel_btn; +} addredit; +*/ + +static struct _PersonEdit_dlg { + GtkWidget *window; + GtkWidget *notebook; + GtkWidget *ok_btn; + GtkWidget *cancel_btn; + GtkWidget *statusbar; + gint status_cid; + + // Basic data tab + GtkWidget *entry_name; + GtkWidget *entry_first; + GtkWidget *entry_last; + GtkWidget *entry_nick; + + // EMail data tab + GtkWidget *entry_email; + GtkWidget *entry_alias; + GtkWidget *entry_remarks; + GtkWidget *clist_email; + + // Attribute data tab + GtkWidget *entry_atname; + GtkWidget *entry_atvalue; + GtkWidget *clist_attrib; + + gint rowIndEMail; + gint rowIndAttrib; + gboolean editNew; + +} personeditdlg; + +typedef enum { + EMAIL_COL_EMAIL = 0, + EMAIL_COL_ALIAS = 1, + EMAIL_COL_REMARKS = 2 +} PersonEditEMailColumnPos; + +typedef enum { + ATTRIB_COL_NAME = 0, + ATTRIB_COL_VALUE = 1 +} PersonEditAttribColumnPos; + +#define EDITPERSON_WIDTH 520 +#define EDITPERSON_HEIGHT 340 + +#define EMAIL_N_COLS 3 +#define EMAIL_COL_WIDTH_EMAIL 180 +#define EMAIL_COL_WIDTH_ALIAS 80 + +#define ATTRIB_N_COLS 2 +#define ATTRIB_COL_WIDTH_NAME 120 +#define ATTRIB_COL_WIDTH_VALUE 180 + +#define PAGE_BASIC 0 +#define PAGE_EMAIL 1 +#define PAGE_ATTRIBUTES 2 + +/* +#define SET_LABEL_AND_ENTRY(str, entry, top) \ +{ \ + label = gtk_label_new(str); \ + gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), \ + GTK_FILL, 0, 0, 0); \ + gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); \ + \ + entry = gtk_entry_new(); \ + gtk_table_attach(GTK_TABLE(table), entry, 1, 2, top, (top + 1), \ + GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0); \ +} + +static void edit_address_ok(GtkWidget *widget, gboolean *cancelled) +{ + *cancelled = FALSE; + gtk_main_quit(); +} + +static void edit_address_cancel(GtkWidget *widget, gboolean *cancelled) +{ + *cancelled = TRUE; + gtk_main_quit(); +} + +static gint edit_address_delete_event(GtkWidget *widget, GdkEventAny *event, + gboolean *cancelled) +{ + *cancelled = TRUE; + gtk_main_quit(); + + return TRUE; +} + +static void edit_address_key_pressed(GtkWidget *widget, GdkEventKey *event, + gboolean *cancelled) +{ + if (event && event->keyval == GDK_Escape) { + *cancelled = TRUE; + gtk_main_quit(); + } +} + +static void addressbook_edit_address_create(gboolean *cancelled) +{ + GtkWidget *window; + GtkWidget *vbox; + GtkWidget *table; + GtkWidget *label; + GtkWidget *name_entry; + GtkWidget *addr_entry; + GtkWidget *rem_entry; + GtkWidget *hbbox; + GtkWidget *ok_btn; + GtkWidget *cancel_btn; + + debug_print("Creating edit_address window...\n"); + + window = gtk_window_new(GTK_WINDOW_DIALOG); + gtk_widget_set_usize(window, 400, -1); + gtk_container_set_border_width(GTK_CONTAINER(window), 8); + gtk_window_set_title(GTK_WINDOW(window), _("Edit address")); + gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); + gtk_window_set_modal(GTK_WINDOW(window), TRUE); + gtk_signal_connect(GTK_OBJECT(window), "delete_event", + GTK_SIGNAL_FUNC(edit_address_delete_event), + cancelled); + gtk_signal_connect(GTK_OBJECT(window), "key_press_event", + GTK_SIGNAL_FUNC(edit_address_key_pressed), + cancelled); + + vbox = gtk_vbox_new(FALSE, 8); + gtk_container_add(GTK_CONTAINER(window), vbox); + + table = gtk_table_new(3, 2, FALSE); + gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0); + gtk_table_set_row_spacings(GTK_TABLE(table), 8); + gtk_table_set_col_spacings(GTK_TABLE(table), 8); + + SET_LABEL_AND_ENTRY(_("Name"), name_entry, 0); + SET_LABEL_AND_ENTRY(_("Address"), addr_entry, 1); + SET_LABEL_AND_ENTRY(_("Remarks"), rem_entry, 2); + + gtkut_button_set_create(&hbbox, &ok_btn, _("OK"), + &cancel_btn, _("Cancel"), NULL, NULL); + gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0); + gtk_widget_grab_default(ok_btn); + + gtk_signal_connect(GTK_OBJECT(ok_btn), "clicked", + GTK_SIGNAL_FUNC(edit_address_ok), cancelled); + gtk_signal_connect(GTK_OBJECT(cancel_btn), "clicked", + GTK_SIGNAL_FUNC(edit_address_cancel), cancelled); + + gtk_widget_show_all(vbox); + + addredit.window = window; + addredit.name_entry = name_entry; + addredit.addr_entry = addr_entry; + addredit.rem_entry = rem_entry; + addredit.ok_btn = ok_btn; + addredit.cancel_btn = cancel_btn; +} + +AddressItem *addressbook_edit_address(AddressItem *item) +{ + static gboolean cancelled; + const gchar *str; + + if (!addredit.window) + addressbook_edit_address_create(&cancelled); + gtk_widget_grab_focus(addredit.ok_btn); + gtk_widget_grab_focus(addredit.name_entry); + gtk_widget_show(addredit.window); + manage_window_set_transient(GTK_WINDOW(addredit.window)); + + gtk_entry_set_text(GTK_ENTRY(addredit.name_entry), ""); + gtk_entry_set_text(GTK_ENTRY(addredit.addr_entry), ""); + gtk_entry_set_text(GTK_ENTRY(addredit.rem_entry), ""); + + if (item) { + if (ADDRESS_OBJECT_NAME(item)) + gtk_entry_set_text(GTK_ENTRY(addredit.name_entry), + ADDRESS_OBJECT_NAME(item)); + if (item->address) + gtk_entry_set_text(GTK_ENTRY(addredit.addr_entry), + item->address); + if (item->remarks) + gtk_entry_set_text(GTK_ENTRY(addredit.rem_entry), + item->remarks); + } + + gtk_main(); + gtk_widget_hide(addredit.window); + if (cancelled == TRUE) return NULL; + + str = gtk_entry_get_text(GTK_ENTRY(addredit.name_entry)); + if (*str == '\0') return NULL; + + if (!item) { + item = mgu_create_address(); + ADDRESS_OBJECT_TYPE(item) = ADDR_ITEM; + } + + g_free(ADDRESS_OBJECT_NAME(item)); + ADDRESS_OBJECT_NAME(item) = g_strdup(str); + + str = gtk_entry_get_text(GTK_ENTRY(addredit.addr_entry)); + g_free(item->address); + if (*str == '\0') + item->address = NULL; + else + item->address = g_strdup(str); + + str = gtk_entry_get_text(GTK_ENTRY(addredit.rem_entry)); + g_free(item->remarks); + if (*str == '\0') + item->remarks = NULL; + else + item->remarks = g_strdup(str); + + return item; +} +*/ + +static void edit_person_status_show( gchar *msg ) { + if( personeditdlg.statusbar != NULL ) { + gtk_statusbar_pop( GTK_STATUSBAR(personeditdlg.statusbar), personeditdlg.status_cid ); + if( msg ) { + gtk_statusbar_push( GTK_STATUSBAR(personeditdlg.statusbar), personeditdlg.status_cid, msg ); + } + } +} + +static void edit_person_ok(GtkWidget *widget, gboolean *cancelled) { + *cancelled = FALSE; + gtk_main_quit(); +} + +static void edit_person_cancel(GtkWidget *widget, gboolean *cancelled) { + *cancelled = TRUE; + gtk_main_quit(); +} + +static gint edit_person_delete_event(GtkWidget *widget, GdkEventAny *event, gboolean *cancelled) { + *cancelled = TRUE; + gtk_main_quit(); + return TRUE; +} + +static void edit_person_key_pressed(GtkWidget *widget, GdkEventKey *event, gboolean *cancelled) { + if (event && event->keyval == GDK_Escape) { + *cancelled = TRUE; + gtk_main_quit(); + } +} + +static gchar *_title_new_ = NULL; +static gchar *_title_edit_ = NULL; + +static void edit_person_set_window_title( gint pageNum ) { + gchar *sTitle; + + if( _title_new_ == NULL ) { + _title_new_ = g_strdup( _("Add New Person") ); + _title_edit_ = g_strdup( _("Edit Person Details") ); + } + + if( pageNum == PAGE_BASIC ) { + if( personeditdlg.editNew ) { + gtk_window_set_title( GTK_WINDOW(personeditdlg.window), _title_new_ ); + } + else { + gtk_window_set_title( GTK_WINDOW(personeditdlg.window), _title_edit_ ); + } + } + else { + if( personeditdlg.entry_name == NULL ) { + sTitle = g_strdup( _title_edit_ ); + } + else { + sTitle = g_strdup_printf( "%s - %s", _title_edit_, + gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_name), 0, -1 ) ); + } + gtk_window_set_title( GTK_WINDOW(personeditdlg.window), sTitle ); + g_free( sTitle ); + } +} + +static void edit_person_email_clear( gpointer data ) { + gtk_entry_set_text( GTK_ENTRY(personeditdlg.entry_email), "" ); + gtk_entry_set_text( GTK_ENTRY(personeditdlg.entry_alias), "" ); + gtk_entry_set_text( GTK_ENTRY(personeditdlg.entry_remarks), "" ); +} + +static void edit_person_attrib_clear( gpointer data ) { + gtk_entry_set_text( GTK_ENTRY(personeditdlg.entry_atname), "" ); + gtk_entry_set_text( GTK_ENTRY(personeditdlg.entry_atvalue), "" ); +} + +static void edit_person_switch_page( GtkNotebook *notebook, GtkNotebookPage *page, + gint pageNum, gpointer user_data) +{ + edit_person_set_window_title( pageNum ); + edit_person_status_show( "" ); +} + +/* +* Load clist with a copy of person's email addresses. +*/ +void edit_person_load_email( ItemPerson *person ) { + GList *node = person->listEMail; + GtkCList *clist = GTK_CLIST(personeditdlg.clist_email); + gchar *text[ EMAIL_N_COLS ]; + while( node ) { + ItemEMail *emorig = ( ItemEMail * ) node->data; + ItemEMail *email = addritem_copy_item_email( emorig ); + gint row; + text[ EMAIL_COL_EMAIL ] = email->address; + text[ EMAIL_COL_ALIAS ] = email->obj.name; + text[ EMAIL_COL_REMARKS ] = email->remarks; + + row = gtk_clist_append( clist, text ); + gtk_clist_set_row_data( clist, row, email ); + node = g_list_next( node ); + } +} + +static void edit_person_email_list_selected( GtkCList *clist, gint row, gint column, GdkEvent *event, gpointer data ) { + ItemEMail *email = gtk_clist_get_row_data( clist, row ); + if( email ) { + if( email->address ) + gtk_entry_set_text( GTK_ENTRY(personeditdlg.entry_email), email->address ); + if( ADDRITEM_NAME(email) ) + gtk_entry_set_text( GTK_ENTRY(personeditdlg.entry_alias), ADDRITEM_NAME(email) ); + if( email->remarks ) + gtk_entry_set_text( GTK_ENTRY(personeditdlg.entry_remarks), email->remarks ); + } + personeditdlg.rowIndEMail = row; + edit_person_status_show( NULL ); +} + +static void edit_person_email_move( gint dir ) { + GtkCList *clist = GTK_CLIST(personeditdlg.clist_email); + gint row = personeditdlg.rowIndEMail + dir; + ItemEMail *email = gtk_clist_get_row_data( clist, row ); + if( email ) { + gtk_clist_row_move( clist, personeditdlg.rowIndEMail, row ); + personeditdlg.rowIndEMail = row; + } + edit_person_email_clear( NULL ); + edit_person_status_show( NULL ); +} + +static void edit_person_email_move_up( gpointer data ) { + edit_person_email_move( -1 ); +} + +static void edit_person_email_move_down( gpointer data ) { + edit_person_email_move( +1 ); +} + +static void edit_person_email_delete( gpointer data ) { + GtkCList *clist = GTK_CLIST(personeditdlg.clist_email); + gint row = personeditdlg.rowIndEMail; + ItemEMail *email = gtk_clist_get_row_data( clist, row ); + edit_person_email_clear( NULL ); + if( email ) { + // Remove list entry + gtk_clist_remove( clist, row ); + addritem_free_item_email( email ); + email = NULL; + } + + // Position hilite bar + email = gtk_clist_get_row_data( clist, row ); + if( ! email ) { + personeditdlg.rowIndEMail = -1 + row; + } + edit_person_status_show( NULL ); +} + +static ItemEMail *edit_person_email_edit( gboolean *error, ItemEMail *email ) { + ItemEMail *retVal = NULL; + gchar *sEmail, *sAlias, *sRemarks; + *error = TRUE; + sEmail = gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_email), 0, -1 ); + sAlias = gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_alias), 0, -1 ); + sRemarks = gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_remarks), 0, -1 ); + sEmail = mgu_email_check_empty( sEmail ); + if( sEmail ) { + if( email == NULL ) { + email = addritem_create_item_email(); + } + addritem_email_set_address( email, sEmail ); + addritem_email_set_alias( email, sAlias ); + addritem_email_set_remarks( email, sRemarks ); + retVal = email; + *error = FALSE; + } + else { + edit_person_status_show( _( "An E-Mail address must be supplied." ) ); + } + return retVal; +} + +static void edit_person_email_modify( gpointer data ) { + gboolean errFlg = FALSE; + GtkCList *clist = GTK_CLIST(personeditdlg.clist_email); + gint row = personeditdlg.rowIndEMail; + ItemEMail *email = gtk_clist_get_row_data( clist, row ); + if( email ) { + edit_person_email_edit( &errFlg, email ); + if( ! errFlg ) { + gtk_clist_set_text( clist, row, EMAIL_COL_EMAIL, email->address ); + gtk_clist_set_text( clist, row, EMAIL_COL_ALIAS, email->obj.name ); + gtk_clist_set_text( clist, row, EMAIL_COL_REMARKS, email->remarks ); + edit_person_email_clear( NULL ); + } + } +} + +static void edit_person_email_add( gpointer data ) { + GtkCList *clist = GTK_CLIST(personeditdlg.clist_email); + gboolean errFlg = FALSE; + ItemEMail *email = NULL; + gint row = personeditdlg.rowIndEMail; + if( gtk_clist_get_row_data( clist, row ) == NULL ) row = 0; + + email = edit_person_email_edit( &errFlg, NULL ); + if( ! errFlg ) { + gchar *text[ EMAIL_N_COLS ]; + text[ EMAIL_COL_EMAIL ] = email->address; + text[ EMAIL_COL_ALIAS ] = email->obj.name; + text[ EMAIL_COL_REMARKS ] = email->remarks; + + row = gtk_clist_insert( clist, 1 + row, text ); + gtk_clist_set_row_data( clist, row, email ); + gtk_clist_select_row( clist, row, 0 ); + edit_person_email_clear( NULL ); + } +} + +/* +* Load clist with a copy of person's email addresses. +*/ +void edit_person_load_attrib( ItemPerson *person ) { + GList *node = person->listAttrib; + GtkCList *clist = GTK_CLIST(personeditdlg.clist_attrib); + gchar *text[ ATTRIB_N_COLS ]; + while( node ) { + UserAttribute *atorig = ( UserAttribute * ) node->data; + UserAttribute *attrib = addritem_copy_attribute( atorig ); + gint row; + text[ ATTRIB_COL_NAME ] = attrib->name; + text[ ATTRIB_COL_VALUE ] = attrib->value; + + row = gtk_clist_append( clist, text ); + gtk_clist_set_row_data( clist, row, attrib ); + node = g_list_next( node ); + } +} + +static void edit_person_attrib_list_selected( GtkCList *clist, gint row, gint column, GdkEvent *event, gpointer data ) { + UserAttribute *attrib = gtk_clist_get_row_data( clist, row ); + if( attrib ) { + gtk_entry_set_text( GTK_ENTRY(personeditdlg.entry_atname), attrib->name ); + gtk_entry_set_text( GTK_ENTRY(personeditdlg.entry_atvalue), attrib->value ); + } + personeditdlg.rowIndAttrib = row; + edit_person_status_show( NULL ); +} + +static void edit_person_attrib_delete( gpointer data ) { + GtkCList *clist = GTK_CLIST(personeditdlg.clist_attrib); + gint row = personeditdlg.rowIndAttrib; + UserAttribute *attrib = gtk_clist_get_row_data( clist, row ); + edit_person_attrib_clear( NULL ); + if( attrib ) { + // Remove list entry + gtk_clist_remove( clist, row ); + addritem_free_attribute( attrib ); + attrib = NULL; + } + + // Position hilite bar + attrib = gtk_clist_get_row_data( clist, row ); + if( ! attrib ) { + personeditdlg.rowIndAttrib = -1 + row; + } + edit_person_status_show( NULL ); +} + +static UserAttribute *edit_person_attrib_edit( gboolean *error, UserAttribute *attrib ) { + UserAttribute *retVal = NULL; + gchar *sName, *sValue; + *error = TRUE; + sName = gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_atname), 0, -1 ); + sValue = gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_atvalue), 0, -1 ); + sName = mgu_email_check_empty( sName ); + sValue = mgu_email_check_empty( sValue ); + if( sName && sValue ) { + if( attrib == NULL ) { + attrib = addritem_create_attribute(); + } + addritem_attrib_set_name( attrib, sName ); + addritem_attrib_set_value( attrib, sValue ); + retVal = attrib; + *error = FALSE; + } + else { + edit_person_status_show( _( "A Name and Value must be supplied." ) ); + } + return retVal; +} + +static void edit_person_attrib_modify( gpointer data ) { + gboolean errFlg = FALSE; + GtkCList *clist = GTK_CLIST(personeditdlg.clist_attrib); + gint row = personeditdlg.rowIndAttrib; + UserAttribute *attrib = gtk_clist_get_row_data( clist, row ); + if( attrib ) { + edit_person_attrib_edit( &errFlg, attrib ); + if( ! errFlg ) { + gtk_clist_set_text( clist, row, ATTRIB_COL_NAME, attrib->name ); + gtk_clist_set_text( clist, row, ATTRIB_COL_VALUE, attrib->value ); + edit_person_attrib_clear( NULL ); + } + } +} + +static void edit_person_attrib_add( gpointer data ) { + GtkCList *clist = GTK_CLIST(personeditdlg.clist_attrib); + gboolean errFlg = FALSE; + UserAttribute *attrib = NULL; + gint row = personeditdlg.rowIndAttrib; + if( gtk_clist_get_row_data( clist, row ) == NULL ) row = 0; + + attrib = edit_person_attrib_edit( &errFlg, NULL ); + if( ! errFlg ) { + gchar *text[ EMAIL_N_COLS ]; + text[ ATTRIB_COL_NAME ] = attrib->name; + text[ ATTRIB_COL_VALUE ] = attrib->value; + + row = gtk_clist_insert( clist, 1 + row, text ); + gtk_clist_set_row_data( clist, row, attrib ); + gtk_clist_select_row( clist, row, 0 ); + edit_person_attrib_clear( NULL ); + } +} + +static void addressbook_edit_person_dialog_create( gboolean *cancelled ) { + GtkWidget *window; + GtkWidget *vbox; + GtkWidget *notebook; + GtkWidget *hbbox; + GtkWidget *ok_btn; + GtkWidget *cancel_btn; + GtkWidget *hsbox; + GtkWidget *statusbar; + + window = gtk_window_new(GTK_WINDOW_DIALOG); + gtk_widget_set_usize(window, EDITPERSON_WIDTH, EDITPERSON_HEIGHT ); + gtk_container_set_border_width(GTK_CONTAINER(window), 0); + gtk_window_set_title(GTK_WINDOW(window), _("Edit Person Data")); + gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); + gtk_window_set_modal(GTK_WINDOW(window), TRUE); + gtk_signal_connect(GTK_OBJECT(window), "delete_event", + GTK_SIGNAL_FUNC(edit_person_delete_event), + cancelled); + gtk_signal_connect(GTK_OBJECT(window), "key_press_event", + GTK_SIGNAL_FUNC(edit_person_key_pressed), + cancelled); + + vbox = gtk_vbox_new( FALSE, 6 ); + gtk_container_set_border_width(GTK_CONTAINER(vbox), BORDER_WIDTH); + gtk_widget_show( vbox ); + gtk_container_add( GTK_CONTAINER( window ), vbox ); + + // Notebook + notebook = gtk_notebook_new(); + gtk_widget_show( notebook ); + gtk_box_pack_start( GTK_BOX( vbox ), notebook, TRUE, TRUE, 0 ); + gtk_container_set_border_width( GTK_CONTAINER( notebook ), 6 ); + + // Status line + hsbox = gtk_hbox_new(FALSE, 0); + gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH); + statusbar = gtk_statusbar_new(); + gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH); + + // Button panel + gtkut_button_set_create(&hbbox, &ok_btn, _("OK"), + &cancel_btn, _("Cancel"), NULL, NULL); + gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0); + gtk_widget_grab_default(ok_btn); + + gtk_signal_connect(GTK_OBJECT(ok_btn), "clicked", + GTK_SIGNAL_FUNC(edit_person_ok), cancelled); + gtk_signal_connect(GTK_OBJECT(cancel_btn), "clicked", + GTK_SIGNAL_FUNC(edit_person_cancel), cancelled); + gtk_signal_connect(GTK_OBJECT(notebook), "switch_page", + GTK_SIGNAL_FUNC(edit_person_switch_page), NULL ); + + gtk_widget_show_all(vbox); + + personeditdlg.window = window; + personeditdlg.notebook = notebook; + personeditdlg.ok_btn = ok_btn; + personeditdlg.cancel_btn = cancel_btn; + personeditdlg.statusbar = statusbar; + personeditdlg.status_cid = gtk_statusbar_get_context_id( GTK_STATUSBAR(statusbar), "Edit Person Dialog" ); + +} + +void addressbook_edit_person_page_basic( gint pageNum, gchar *pageLbl ) { + GtkWidget *vbox; + GtkWidget *table; + GtkWidget *label; + GtkWidget *entry_name; + GtkWidget *entry_fn; + GtkWidget *entry_ln; + GtkWidget *entry_nn; + gint top; + + vbox = gtk_vbox_new( FALSE, 8 ); + gtk_widget_show( vbox ); + gtk_container_add( GTK_CONTAINER( personeditdlg.notebook ), vbox ); + gtk_container_set_border_width( GTK_CONTAINER (vbox), BORDER_WIDTH ); + + label = gtk_label_new( pageLbl ); + gtk_widget_show( label ); + gtk_notebook_set_tab_label( + GTK_NOTEBOOK( personeditdlg.notebook ), + gtk_notebook_get_nth_page( GTK_NOTEBOOK( personeditdlg.notebook ), pageNum ), label ); + + table = gtk_table_new( 4, 3, FALSE); + gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0); + gtk_container_set_border_width( GTK_CONTAINER(table), 8 ); + gtk_table_set_row_spacings(GTK_TABLE(table), 8); + gtk_table_set_col_spacings(GTK_TABLE(table), 8); + + // First row + top = 0; + label = gtk_label_new(_("Display Name")); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); + + entry_name = gtk_entry_new(); + gtk_table_attach(GTK_TABLE(table), entry_name, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0); + + // Next row + ++top; + label = gtk_label_new(_("First Name")); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); + + entry_fn = gtk_entry_new(); + gtk_table_attach(GTK_TABLE(table), entry_fn, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0); + + // Next row + ++top; + label = gtk_label_new(_("Last Name")); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); + + entry_ln = gtk_entry_new(); + gtk_table_attach(GTK_TABLE(table), entry_ln, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0); + + // Next row + ++top; + label = gtk_label_new(_("Nick Name")); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); + + entry_nn = gtk_entry_new(); + gtk_table_attach(GTK_TABLE(table), entry_nn, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0); + + gtk_widget_show_all(vbox); + + personeditdlg.entry_name = entry_name; + personeditdlg.entry_first = entry_fn; + personeditdlg.entry_last = entry_ln; + personeditdlg.entry_nick = entry_nn; +} + +void addressbook_edit_person_page_email( gint pageNum, gchar *pageLbl ) { + GtkWidget *vbox; + GtkWidget *hbox; + GtkWidget *vboxl; + GtkWidget *vboxb; + GtkWidget *vbuttonbox; + GtkWidget *buttonUp; + GtkWidget *buttonDown; + GtkWidget *buttonDel; + GtkWidget *buttonMod; + GtkWidget *buttonAdd; + GtkWidget *buttonClr; + + GtkWidget *table; + GtkWidget *label; + GtkWidget *clist_swin; + GtkWidget *clist; + GtkWidget *entry_email; + GtkWidget *entry_alias; + GtkWidget *entry_remarks; + gint top; + + gchar *titles[ EMAIL_N_COLS ] = { _("E-Mail Address"), _("Alias"), _("Remarks") }; + gchar *text; + gint i; + + vbox = gtk_vbox_new( FALSE, 8 ); + gtk_widget_show( vbox ); + gtk_container_add( GTK_CONTAINER( personeditdlg.notebook ), vbox ); + gtk_container_set_border_width( GTK_CONTAINER (vbox), BORDER_WIDTH ); + + label = gtk_label_new( pageLbl ); + gtk_widget_show( label ); + gtk_notebook_set_tab_label( + GTK_NOTEBOOK( personeditdlg.notebook ), + gtk_notebook_get_nth_page( GTK_NOTEBOOK( personeditdlg.notebook ), pageNum ), label ); + + // Split into two areas + hbox = gtk_hbox_new( FALSE, 0 ); + gtk_container_add( GTK_CONTAINER( vbox ), hbox ); + + // EMail list + vboxl = gtk_vbox_new( FALSE, 4 ); + gtk_container_add( GTK_CONTAINER( hbox ), vboxl ); + gtk_container_set_border_width( GTK_CONTAINER(vboxl), 4 ); + + // Address list + clist_swin = gtk_scrolled_window_new( NULL, NULL ); + gtk_container_add( GTK_CONTAINER(vboxl), clist_swin ); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_ALWAYS); + + clist = gtk_clist_new_with_titles( EMAIL_N_COLS, titles ); + gtk_container_add( GTK_CONTAINER(clist_swin), clist ); + gtk_clist_set_selection_mode( GTK_CLIST(clist), GTK_SELECTION_BROWSE ); + gtk_clist_set_column_width( GTK_CLIST(clist), EMAIL_COL_EMAIL, EMAIL_COL_WIDTH_EMAIL ); + gtk_clist_set_column_width( GTK_CLIST(clist), EMAIL_COL_ALIAS, EMAIL_COL_WIDTH_ALIAS ); + + for( i = 0; i < EMAIL_N_COLS; i++ ) + GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(clist)->column[i].button, GTK_CAN_FOCUS); + + // Data entry area + table = gtk_table_new( 4, 2, FALSE); + gtk_box_pack_start(GTK_BOX(vboxl), table, FALSE, FALSE, 0); + gtk_container_set_border_width( GTK_CONTAINER(table), 4 ); + gtk_table_set_row_spacings(GTK_TABLE(table), 4); + gtk_table_set_col_spacings(GTK_TABLE(table), 4); + + // First row + top = 0; + label = gtk_label_new(_("E-Mail Address")); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); + + entry_email = gtk_entry_new(); + gtk_table_attach(GTK_TABLE(table), entry_email, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0); + + // Next row + ++top; + label = gtk_label_new(_("Alias")); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); + + entry_alias = gtk_entry_new(); + gtk_table_attach(GTK_TABLE(table), entry_alias, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0); + + // Next row + ++top; + label = gtk_label_new(_("Remarks")); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); + + entry_remarks = gtk_entry_new(); + gtk_table_attach(GTK_TABLE(table), entry_remarks, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0); + + // Button box + vboxb = gtk_vbox_new( FALSE, 4 ); + gtk_box_pack_start(GTK_BOX(hbox), vboxb, FALSE, FALSE, 2); + + vbuttonbox = gtk_vbutton_box_new(); + gtk_button_box_set_layout( GTK_BUTTON_BOX(vbuttonbox), GTK_BUTTONBOX_START ); + gtk_button_box_set_spacing( GTK_BUTTON_BOX(vbuttonbox), 8 ); + gtk_container_set_border_width( GTK_CONTAINER(vbuttonbox), 4 ); + gtk_container_add( GTK_CONTAINER(vboxb), vbuttonbox ); + + // Buttons + buttonUp = gtk_button_new_with_label( _( "Move Up" ) ); + gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonUp ); + + buttonDown = gtk_button_new_with_label( _( "Move Down" ) ); + gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonDown ); + + buttonDel = gtk_button_new_with_label( _( "Delete" ) ); + gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonDel ); + + buttonMod = gtk_button_new_with_label( _( "Modify" ) ); + gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonMod ); + + buttonAdd = gtk_button_new_with_label( _( "Add" ) ); + gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonAdd ); + + buttonClr = gtk_button_new_with_label( _( "Clear" ) ); + gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonClr ); + + gtk_widget_show_all(vbox); + + // Event handlers + gtk_signal_connect( GTK_OBJECT(clist), "select_row", + GTK_SIGNAL_FUNC( edit_person_email_list_selected), NULL ); + gtk_signal_connect( GTK_OBJECT(buttonUp), "clicked", + GTK_SIGNAL_FUNC( edit_person_email_move_up ), NULL ); + gtk_signal_connect( GTK_OBJECT(buttonDown), "clicked", + GTK_SIGNAL_FUNC( edit_person_email_move_down ), NULL ); + gtk_signal_connect( GTK_OBJECT(buttonDel), "clicked", + GTK_SIGNAL_FUNC( edit_person_email_delete ), NULL ); + gtk_signal_connect( GTK_OBJECT(buttonMod), "clicked", + GTK_SIGNAL_FUNC( edit_person_email_modify ), NULL ); + gtk_signal_connect( GTK_OBJECT(buttonAdd), "clicked", + GTK_SIGNAL_FUNC( edit_person_email_add ), NULL ); + gtk_signal_connect( GTK_OBJECT(buttonClr), "clicked", + GTK_SIGNAL_FUNC( edit_person_email_clear ), NULL ); + + personeditdlg.clist_email = clist; + personeditdlg.entry_email = entry_email; + personeditdlg.entry_alias = entry_alias; + personeditdlg.entry_remarks = entry_remarks; +} + +void addressbook_edit_person_page_attrib( gint pageNum, gchar *pageLbl ) { + GtkWidget *vbox; + GtkWidget *hbox; + GtkWidget *vboxl; + GtkWidget *vboxb; + GtkWidget *vbuttonbox; + GtkWidget *buttonDel; + GtkWidget *buttonMod; + GtkWidget *buttonAdd; + GtkWidget *buttonClr; + + GtkWidget *table; + GtkWidget *label; + GtkWidget *clist_swin; + GtkWidget *clist; + GtkWidget *entry_name; + GtkWidget *entry_value; + gint top; + + gchar *titles[ ATTRIB_N_COLS ] = { _("Name"), _("Value") }; + gchar *text; + gint i; + + vbox = gtk_vbox_new( FALSE, 8 ); + gtk_widget_show( vbox ); + gtk_container_add( GTK_CONTAINER( personeditdlg.notebook ), vbox ); + gtk_container_set_border_width( GTK_CONTAINER (vbox), BORDER_WIDTH ); + + label = gtk_label_new( pageLbl ); + gtk_widget_show( label ); + gtk_notebook_set_tab_label( + GTK_NOTEBOOK( personeditdlg.notebook ), + gtk_notebook_get_nth_page( GTK_NOTEBOOK( personeditdlg.notebook ), pageNum ), label ); + + // Split into two areas + hbox = gtk_hbox_new( FALSE, 0 ); + gtk_container_add( GTK_CONTAINER( vbox ), hbox ); + + // Attribute list + vboxl = gtk_vbox_new( FALSE, 4 ); + gtk_container_add( GTK_CONTAINER( hbox ), vboxl ); + gtk_container_set_border_width( GTK_CONTAINER(vboxl), 4 ); + + // Address list + clist_swin = gtk_scrolled_window_new( NULL, NULL ); + gtk_container_add( GTK_CONTAINER(vboxl), clist_swin ); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_ALWAYS); + + clist = gtk_clist_new_with_titles( ATTRIB_N_COLS, titles ); + gtk_container_add( GTK_CONTAINER(clist_swin), clist ); + gtk_clist_set_selection_mode( GTK_CLIST(clist), GTK_SELECTION_BROWSE ); + gtk_clist_set_column_width( GTK_CLIST(clist), ATTRIB_COL_NAME, ATTRIB_COL_WIDTH_NAME ); + gtk_clist_set_column_width( GTK_CLIST(clist), ATTRIB_COL_VALUE, ATTRIB_COL_WIDTH_VALUE ); + + for( i = 0; i < ATTRIB_N_COLS; i++ ) + GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(clist)->column[i].button, GTK_CAN_FOCUS); + + // Data entry area + table = gtk_table_new( 4, 2, FALSE); + gtk_box_pack_start(GTK_BOX(vboxl), table, FALSE, FALSE, 0); + gtk_container_set_border_width( GTK_CONTAINER(table), 4 ); + gtk_table_set_row_spacings(GTK_TABLE(table), 4); + gtk_table_set_col_spacings(GTK_TABLE(table), 4); + + // First row + top = 0; + label = gtk_label_new(_("Name")); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); + + entry_name = gtk_entry_new(); + gtk_table_attach(GTK_TABLE(table), entry_name, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0); + + // Next row + ++top; + label = gtk_label_new(_("Value")); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); + + entry_value = gtk_entry_new(); + gtk_table_attach(GTK_TABLE(table), entry_value, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0); + + // Button box + vboxb = gtk_vbox_new( FALSE, 4 ); + gtk_box_pack_start(GTK_BOX(hbox), vboxb, FALSE, FALSE, 2); + + vbuttonbox = gtk_vbutton_box_new(); + gtk_button_box_set_layout( GTK_BUTTON_BOX(vbuttonbox), GTK_BUTTONBOX_START ); + gtk_button_box_set_spacing( GTK_BUTTON_BOX(vbuttonbox), 8 ); + gtk_container_set_border_width( GTK_CONTAINER(vbuttonbox), 4 ); + gtk_container_add( GTK_CONTAINER(vboxb), vbuttonbox ); + + // Buttons + buttonDel = gtk_button_new_with_label( _( "Delete" ) ); + gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonDel ); + + buttonMod = gtk_button_new_with_label( _( "Modify" ) ); + gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonMod ); + + buttonAdd = gtk_button_new_with_label( _( "Add" ) ); + gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonAdd ); + + buttonClr = gtk_button_new_with_label( _( "Clear" ) ); + gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonClr ); + + gtk_widget_show_all(vbox); + + // Event handlers + gtk_signal_connect( GTK_OBJECT(clist), "select_row", + GTK_SIGNAL_FUNC( edit_person_attrib_list_selected), NULL ); + gtk_signal_connect( GTK_OBJECT(buttonDel), "clicked", + GTK_SIGNAL_FUNC( edit_person_attrib_delete ), NULL ); + gtk_signal_connect( GTK_OBJECT(buttonMod), "clicked", + GTK_SIGNAL_FUNC( edit_person_attrib_modify ), NULL ); + gtk_signal_connect( GTK_OBJECT(buttonAdd), "clicked", + GTK_SIGNAL_FUNC( edit_person_attrib_add ), NULL ); + gtk_signal_connect( GTK_OBJECT(buttonClr), "clicked", + GTK_SIGNAL_FUNC( edit_person_attrib_clear ), NULL ); + + personeditdlg.clist_attrib = clist; + personeditdlg.entry_atname = entry_name; + personeditdlg.entry_atvalue = entry_value; +} + +static void addressbook_edit_person_create( gboolean *cancelled ) { + addressbook_edit_person_dialog_create( cancelled ); + addressbook_edit_person_page_basic( PAGE_BASIC, _( "Basic Data" ) ); + addressbook_edit_person_page_email( PAGE_EMAIL, _( "E-Mail Address" ) ); + addressbook_edit_person_page_attrib( PAGE_ATTRIBUTES, _( "User Attributes" ) ); + gtk_widget_show_all( personeditdlg.window ); +} + +/* +* Return list of email items. +*/ +static GList *edit_person_build_email_list() { + GtkCList *clist = GTK_CLIST(personeditdlg.clist_email); + GList *listEMail = NULL; + ItemEMail *email; + gint row = 0; + while( email = gtk_clist_get_row_data( clist, row ) ) { + listEMail = g_list_append( listEMail, email ); + row++; + } + return listEMail; +} + +/* +* Return list of attributes. +*/ +static GList *edit_person_build_attrib_list() { + GtkCList *clist = GTK_CLIST(personeditdlg.clist_attrib); + GList *listAttrib = NULL; + UserAttribute *attrib; + gint row = 0; + while( attrib = gtk_clist_get_row_data( clist, row ) ) { + listAttrib = g_list_append( listAttrib, attrib ); + row++; + } + return listAttrib; +} + +/* +* Edit person. +* Enter: abf Address book. +* parent Parent folder for person (or NULL if adding to root folder). Argument is +* only required for new objects). +* person Person to edit, or NULL for a new person object. +* pgMail If TRUE, E-Mail page will be activated. +* Return: Edited object, or NULL if cancelled. +*/ +ItemPerson *addressbook_edit_person( AddressBookFile *abf, ItemFolder *parent, ItemPerson *person, gboolean pgMail ) { + static gboolean cancelled; + GList *listEMail = NULL; + GList *listAttrib = NULL; + gchar *cn = NULL; + + if (!personeditdlg.window) + addressbook_edit_person_create(&cancelled); + gtk_widget_grab_focus(personeditdlg.ok_btn); + gtk_widget_grab_focus(personeditdlg.entry_name); + gtk_widget_show(personeditdlg.window); + manage_window_set_transient(GTK_WINDOW(personeditdlg.window)); + + // Clear all fields + personeditdlg.rowIndEMail = -1; + personeditdlg.rowIndAttrib = -1; + edit_person_status_show( "" ); + gtk_clist_clear( GTK_CLIST(personeditdlg.clist_email) ); + gtk_clist_clear( GTK_CLIST(personeditdlg.clist_attrib) ); + gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_name), "" ); + gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_first), "" ); + gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_last), "" ); + gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_nick), "" ); + + personeditdlg.editNew = FALSE; + if( person ) { + if( ADDRITEM_NAME(person) ) + gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_name), ADDRITEM_NAME(person) ); + if( person->firstName ) + gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_first), person->firstName ); + if( person->lastName ) + gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_last), person->lastName ); + if( person->nickName ) + gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_nick), person->nickName ); + edit_person_load_email( person ); + edit_person_load_attrib( person ); + } + else { + personeditdlg.editNew = TRUE; + } + + // Select appropriate start page + if( pgMail ) { + gtk_notebook_set_page( GTK_NOTEBOOK(personeditdlg.notebook), PAGE_EMAIL ); + } + else { + gtk_notebook_set_page( GTK_NOTEBOOK(personeditdlg.notebook), PAGE_BASIC ); + } + + gtk_clist_select_row( GTK_CLIST(personeditdlg.clist_email), 0, 0 ); + gtk_clist_select_row( GTK_CLIST(personeditdlg.clist_attrib), 0, 0 ); + edit_person_email_clear( NULL ); + edit_person_attrib_clear( NULL ); + + gtk_main(); + gtk_widget_hide( personeditdlg.window ); + + listEMail = edit_person_build_email_list(); + listAttrib = edit_person_build_attrib_list(); + if( cancelled ) { + addritem_free_list_email( listEMail ); + gtk_clist_clear( GTK_CLIST(personeditdlg.clist_email) ); + gtk_clist_clear( GTK_CLIST(personeditdlg.clist_attrib) ); + return NULL; + } + + cn = g_strdup( gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_name), 0, -1 ) ); + if( person ) { + // Update email/attribute list + addrbook_update_address_list( abf, person, listEMail ); + addrbook_update_attrib_list( abf, person, listAttrib ); + } + else { + // Create new person and email/attribute list + if( cn == NULL || *cn == '\0' ) { + // Wasting our time + if( listEMail == NULL && listAttrib == NULL ) cancelled = TRUE; + } + if( ! cancelled ) { + person = addrbook_add_address_list( abf, parent, listEMail ); + addrbook_add_attrib_list( abf, person, listAttrib ); + } + } + + if( ! cancelled ) { + // Set person stuff + addritem_person_set_common_name( person, cn ); + addritem_person_set_first_name( person, + gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_first), 0, -1 ) ); + addritem_person_set_last_name( person, + gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_last), 0, -1 ) ); + addritem_person_set_nick_name( person, + gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_nick), 0, -1 ) ); + } + g_free( cn ); + + listEMail = NULL; + + gtk_clist_clear( GTK_CLIST(personeditdlg.clist_email) ); + gtk_clist_clear( GTK_CLIST(personeditdlg.clist_attrib) ); + + return person; +} + +/* +* End of Source. +*/ + diff --git a/src/editaddress.h b/src/editaddress.h new file mode 100644 index 000000000..d5e9068bb --- /dev/null +++ b/src/editaddress.h @@ -0,0 +1,34 @@ +/* + * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client + * Copyright (C) 1999,2000 Hiroyuki Yamamoto + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ + +/* + * Edit address item data. + */ + +#ifndef __EDITADDRESS_H__ +#define __EDITADDRESS_H__ + +// Function prototypes +ItemPerson *addressbook_edit_person( AddressBookFile *abf, ItemFolder *parent, ItemPerson *person, gboolean pgMail ); + +#endif /* __EDITADDRESS_H__ */ + +/* +* End of Source. +*/ diff --git a/src/editbook.c b/src/editbook.c new file mode 100644 index 000000000..8e219f292 --- /dev/null +++ b/src/editbook.c @@ -0,0 +1,347 @@ +/* + * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client + * Copyright (C) 2001 Match Grun + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ + +/* + * Edit new address book entry. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "defs.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "intl.h" +#include "utils.h" +#include "prefs_common.h" +#include "mgutils.h" +#include "addressbook.h" +#include "addressitem.h" +#include "addrindex.h" +#include "addrbook.h" + +#define ADDRESSBOOK_GUESS_BOOK "MyAddressBook" + +static struct _AddrBookEdit_Dlg { + GtkWidget *window; + GtkWidget *name_entry; + GtkWidget *file_label; + GtkWidget *ok_btn; + GtkWidget *cancel_btn; + GtkWidget *check_btn; + // GtkWidget *file_btn; + GtkWidget *statusbar; + gint status_cid; + AddressBookFile *bookFile; +} addrbookedit_dlg; + +static struct _AddressFileSelection vcard_file_selector; + +/* +* Edit functions. +*/ +void edit_book_status_show( gchar *msg ) { + if( addrbookedit_dlg.statusbar != NULL ) { + gtk_statusbar_pop( GTK_STATUSBAR(addrbookedit_dlg.statusbar), addrbookedit_dlg.status_cid ); + if( msg ) { + gtk_statusbar_push( + GTK_STATUSBAR(addrbookedit_dlg.statusbar), addrbookedit_dlg.status_cid, msg ); + } + else { + gtk_statusbar_push( + GTK_STATUSBAR(addrbookedit_dlg.statusbar), addrbookedit_dlg.status_cid, "" ); + } + } +} + +static void edit_book_ok( GtkWidget *widget, gboolean *cancelled ) { + *cancelled = FALSE; + gtk_main_quit(); +} + +static void edit_book_cancel( GtkWidget *widget, gboolean *cancelled ) { + *cancelled = TRUE; + gtk_main_quit(); +} + +static gint edit_book_delete_event( GtkWidget *widget, GdkEventAny *event, gboolean *cancelled ) { + *cancelled = TRUE; + gtk_main_quit(); + return TRUE; +} + +static void edit_book_key_pressed( GtkWidget *widget, GdkEventKey *event, gboolean *cancelled ) { + if (event && event->keyval == GDK_Escape) { + *cancelled = TRUE; + gtk_main_quit(); + } +} + +static void edit_book_file_check( void ) { + gint t; + gchar *sMsg; + AddressBookFile *abf = addrbookedit_dlg.bookFile; + + t = addrbook_test_read_file( abf, abf->fileName ); + if( t == MGU_SUCCESS ) { + sMsg = _("File appears to be Ok."); + } + else if( t == MGU_BAD_FORMAT ) { + sMsg = _("File does not appear to be a valid address book format."); + } + else { + sMsg = _("Could not read file."); + } + edit_book_status_show( sMsg ); +} + +static void edit_book_enable_buttons( gboolean enable ) { + gtk_widget_set_sensitive( addrbookedit_dlg.check_btn, enable ); + // gtk_widget_set_sensitive( addrbookedit_dlg.file_btn, enable ); +} + +static void edit_book_name_focus( GtkWidget *widget, GdkEventFocus *event, gpointer data) { + edit_book_status_show( "" ); +} + +static gchar *edit_book_guess_file( AddressBookFile *abf ) { + gchar *newFile = NULL; + GList *fileList = NULL; + gint fileNum = 1; + fileList = addrbook_get_bookfile_list( abf ); + if( fileList ) { + fileNum = 1 + abf->maxValue; + } + newFile = addrbook_gen_new_file_name( fileNum ); + g_list_free( fileList ); + fileList = NULL; + return newFile; +} + +static void addressbook_edit_book_create( gboolean *cancelled ) { + GtkWidget *window; + GtkWidget *vbox; + GtkWidget *table; + GtkWidget *label; + GtkWidget *name_entry; + GtkWidget *file_label; + GtkWidget *hbbox; + GtkWidget *hsep; + GtkWidget *ok_btn; + GtkWidget *cancel_btn; + GtkWidget *check_btn; + // GtkWidget *file_btn; + GtkWidget *statusbar; + GtkWidget *hsbox; + gint top; + + window = gtk_window_new(GTK_WINDOW_DIALOG); + gtk_widget_set_usize(window, 450, -1); + gtk_container_set_border_width( GTK_CONTAINER(window), 0 ); + gtk_window_set_title(GTK_WINDOW(window), _("Edit Addressbook")); + gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); + gtk_window_set_modal(GTK_WINDOW(window), TRUE); + gtk_signal_connect(GTK_OBJECT(window), "delete_event", + GTK_SIGNAL_FUNC(edit_book_delete_event), + cancelled); + gtk_signal_connect(GTK_OBJECT(window), "key_press_event", + GTK_SIGNAL_FUNC(edit_book_key_pressed), + cancelled); + + vbox = gtk_vbox_new(FALSE, 8); + gtk_container_add(GTK_CONTAINER(window), vbox); + gtk_container_set_border_width( GTK_CONTAINER(vbox), 0 ); + + table = gtk_table_new(2, 3, FALSE); + gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0); + gtk_container_set_border_width( GTK_CONTAINER(table), 8 ); + gtk_table_set_row_spacings(GTK_TABLE(table), 8); + gtk_table_set_col_spacings(GTK_TABLE(table), 8 ); + + // First row + top = 0; + label = gtk_label_new(_("Name")); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); + + name_entry = gtk_entry_new(); + gtk_table_attach(GTK_TABLE(table), name_entry, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0); + + check_btn = gtk_button_new_with_label( _(" Check File ")); + gtk_table_attach(GTK_TABLE(table), check_btn, 2, 3, top, (top + 1), GTK_FILL, 0, 3, 0); + + // Second row + top = 1; + label = gtk_label_new(_("File")); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); + + file_label = gtk_label_new( "" ); + gtk_misc_set_alignment(GTK_MISC(file_label), 0, 0.5); + gtk_table_attach(GTK_TABLE(table), file_label, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0); + + // file_btn = gtk_button_new_with_label( _(" ... ")); + // gtk_table_attach(GTK_TABLE(table), file_btn, 2, 3, top, (top + 1), GTK_FILL, 0, 3, 0); + + // Status line + hsbox = gtk_hbox_new(FALSE, 0); + gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH); + statusbar = gtk_statusbar_new(); + gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH); + + // Button panel + gtkut_button_set_create(&hbbox, &ok_btn, _("OK"), + &cancel_btn, _("Cancel"), NULL, NULL); + gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0); + gtk_container_set_border_width( GTK_CONTAINER(hbbox), 0 ); + gtk_widget_grab_default(ok_btn); + + hsep = gtk_hseparator_new(); + gtk_box_pack_end(GTK_BOX(vbox), hsep, FALSE, FALSE, 0); + + gtk_signal_connect(GTK_OBJECT(name_entry), "focus_in_event", + GTK_SIGNAL_FUNC(edit_book_name_focus), NULL ); + gtk_signal_connect(GTK_OBJECT(ok_btn), "clicked", + GTK_SIGNAL_FUNC(edit_book_ok), cancelled); + gtk_signal_connect(GTK_OBJECT(cancel_btn), "clicked", + GTK_SIGNAL_FUNC(edit_book_cancel), cancelled); +// gtk_signal_connect(GTK_OBJECT(file_btn), "clicked", +// GTK_SIGNAL_FUNC(edit_book_file_select), NULL); + gtk_signal_connect(GTK_OBJECT(check_btn), "clicked", + GTK_SIGNAL_FUNC(edit_book_file_check), NULL); + + gtk_widget_show_all(vbox); + + addrbookedit_dlg.window = window; + addrbookedit_dlg.name_entry = name_entry; + addrbookedit_dlg.file_label = file_label; + addrbookedit_dlg.ok_btn = ok_btn; + addrbookedit_dlg.cancel_btn = cancel_btn; + addrbookedit_dlg.check_btn = check_btn; + // addrbookedit_dlg.file_btn = file_btn; + addrbookedit_dlg.statusbar = statusbar; + addrbookedit_dlg.status_cid = gtk_statusbar_get_context_id( GTK_STATUSBAR(statusbar), "Edit Addressbook Dialog" ); +} + +AdapterDSource *addressbook_edit_book( AddressIndex *addrIndex, AdapterDSource *ads ) { + static gboolean cancelled; + gchar *sName; + AddressDataSource *ds = NULL; + AddressBookFile *abf; + gboolean fin; + gboolean newBook = FALSE; + gchar *newFile = NULL; + gint rc; + + if (!addrbookedit_dlg.window) + addressbook_edit_book_create(&cancelled); + gtk_widget_grab_focus(addrbookedit_dlg.ok_btn); + gtk_widget_grab_focus(addrbookedit_dlg.name_entry); + gtk_widget_show(addrbookedit_dlg.window); + manage_window_set_transient(GTK_WINDOW(addrbookedit_dlg.window)); + + edit_book_status_show( "" ); + gtk_label_set_text( GTK_LABEL(addrbookedit_dlg.file_label), "" ); + if( ads ) { + ds = ads->dataSource; + abf = ds->rawDataSource; + if (abf->name) + gtk_entry_set_text(GTK_ENTRY(addrbookedit_dlg.name_entry), abf->name); + if( abf->fileName ) + gtk_label_set_text(GTK_LABEL(addrbookedit_dlg.file_label), abf->fileName); + gtk_window_set_title( GTK_WINDOW(addrbookedit_dlg.window), _("Edit Addressbook")); + edit_book_enable_buttons( TRUE ); + } + else { + gchar *tmp = NULL; + newBook = TRUE; + abf = addrbook_create_book(); + addrbook_set_path( abf, addrIndex->filePath ); + + // Take initial guess at file name + newFile = edit_book_guess_file( abf ); + if( newFile ) { + tmp = g_strdup_printf( "<%s>", newFile ); + gtk_label_set_text(GTK_LABEL(addrbookedit_dlg.file_label), tmp ); + g_free( tmp ); + } + g_free( newFile ); + + gtk_entry_set_text( GTK_ENTRY(addrbookedit_dlg.name_entry), ADDRESSBOOK_GUESS_BOOK ); + gtk_window_set_title( GTK_WINDOW(addrbookedit_dlg.window), _("Add New Addressbook") ); + edit_book_enable_buttons( FALSE ); + } + + addrbookedit_dlg.bookFile = abf; + + gtk_main(); + gtk_widget_hide(addrbookedit_dlg.window); + + if( cancelled == TRUE ) { + if( newBook ) { + addrbook_free_book( abf ); + abf = NULL; + } + return NULL; + } + + fin = FALSE; + sName = gtk_editable_get_chars( GTK_EDITABLE(addrbookedit_dlg.name_entry), 0, -1 ); + if( *sName == '\0' ) fin = TRUE; + + if( fin ) { + if( newBook ) { + addrbook_free_book( abf ); + abf = NULL; + } + } + else { + if( newBook ) { + // Get final file name in case it changed + newFile = edit_book_guess_file( abf ); + addrbook_set_file( abf, newFile ); + g_free( newFile ); + ds = addrindex_index_add_datasource( addrIndex, ADDR_IF_BOOK, abf ); + ads = addressbook_create_ds_adapter( ds, ADDR_BOOK, NULL ); + } + addressbook_ads_set_name( ads, sName ); + addrbook_set_name( abf, sName ); + abf->dirtyFlag = TRUE; + } + g_free( sName ); + + // Save data + if( abf ) addrbook_save_data( abf ); + + return ads; +} + +/* +* End of Source. +*/ + diff --git a/src/editbook.h b/src/editbook.h new file mode 100644 index 000000000..9968dc41a --- /dev/null +++ b/src/editbook.h @@ -0,0 +1,35 @@ +/* + * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client + * Copyright (C) 2001 Match Grun + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ + +/* + * Edit new address book data. + */ + +#ifndef __EDITBOOK_H__ +#define __EDITBOOK_H__ + +// Function prototypes +AdapterDSource *addressbook_edit_book( AddressIndex *addrIndex, AdapterDSource *ads ); + +#endif /* __EDITBOOK_H__ */ + +/* +* End of Source. +*/ + diff --git a/src/editgroup.c b/src/editgroup.c new file mode 100644 index 000000000..e6cf99f90 --- /dev/null +++ b/src/editgroup.c @@ -0,0 +1,527 @@ +/* + * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client + * Copyright (C) 1999,2000 Hiroyuki Yamamoto + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "defs.h" + +#include +#include + +#include "intl.h" +#include "addressbook.h" +#include "addressitem.h" +#include "addrbook.h" +#include "addritem.h" + +#include "prefs_common.h" + +#include "alertpanel.h" +#include "inputdialog.h" + +#define ADDRESSBOOK_GUESS_FOLDER_NAME "NewFolder" +#define ADDRESSBOOK_GUESS_GROUP_NAME "NewGroup" + +#define EDITGROUP_WIDTH 580 +#define EDITGROUP_HEIGHT 340 + +typedef enum { + GROUP_COL_NAME = 0, + GROUP_COL_EMAIL = 1, + GROUP_COL_REMARKS = 2 +} GroupEditEMailColumnPos; + +#define GROUP_N_COLS 3 +#define GROUP_COL_WIDTH_NAME 140 +#define GROUP_COL_WIDTH_EMAIL 120 + +static struct _GroupEdit_dlg { + GtkWidget *window; + GtkWidget *ok_btn; + GtkWidget *cancel_btn; + GtkWidget *statusbar; + gint status_cid; + + // Basic data tab + GtkWidget *entry_name; + GtkCList *clist_group; + GtkCList *clist_avail; + + GHashTable *hashEMail; + gint rowIndGroup; + gint rowIndAvail; + +} groupeditdlg; + + +static gchar *_edit_group_dfl_message_ = NULL; + +static void edit_group_status_show( gchar *msg ) { + if( groupeditdlg.statusbar != NULL ) { + gtk_statusbar_pop( GTK_STATUSBAR(groupeditdlg.statusbar), groupeditdlg.status_cid ); + if( msg ) { + gtk_statusbar_push( GTK_STATUSBAR(groupeditdlg.statusbar), groupeditdlg.status_cid, msg ); + } + } +} + +static void edit_group_ok(GtkWidget *widget, gboolean *cancelled) { + gchar *sName = g_strdup( gtk_editable_get_chars( GTK_EDITABLE(groupeditdlg.entry_name), 0, -1 ) ); + gboolean errFlag = TRUE; + if( sName ) { + g_strstrip( sName ); + if( *sName != '\0' ) { + gtk_entry_set_text(GTK_ENTRY(groupeditdlg.entry_name), sName ); + *cancelled = FALSE; + gtk_main_quit(); + errFlag = FALSE; + } + } + if( errFlag ) { + edit_group_status_show( _( "A Group Name must be supplied." ) ); + } + g_free( sName ); +} + +static void edit_group_cancel(GtkWidget *widget, gboolean *cancelled) { + *cancelled = TRUE; + gtk_main_quit(); +} + +static gint edit_group_delete_event(GtkWidget *widget, GdkEventAny *event, gboolean *cancelled) { + *cancelled = TRUE; + gtk_main_quit(); + return TRUE; +} + +static void edit_group_key_pressed(GtkWidget *widget, GdkEventKey *event, gboolean *cancelled) { + if (event && event->keyval == GDK_Escape) { + *cancelled = TRUE; + gtk_main_quit(); + } +} + +static gchar *edit_group_format_item_clist( ItemPerson *person, ItemEMail *email ) { + gchar *str = NULL; + gchar *aName = ADDRITEM_NAME(email); + if( aName == NULL || *aName == '\0' ) return str; + if( person ) { + str = g_strdup_printf( "%s - %s", ADDRITEM_NAME(person), aName ); + } + else { + str = g_strdup( aName ); + } + return str; +} + +static gint edit_group_clist_add_email( GtkCList *clist, ItemEMail *email ) { + ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(email); + gchar *str = edit_group_format_item_clist( person, email ); + gchar *text[ GROUP_N_COLS ]; + gint row; + if( str ) { + text[ GROUP_COL_NAME ] = str; + } + else { + text[ GROUP_COL_NAME ] = ADDRITEM_NAME(person); + } + text[ GROUP_COL_EMAIL ] = email->address; + text[ GROUP_COL_REMARKS ] = email->remarks; + row = gtk_clist_append( clist, text ); + gtk_clist_set_row_data( clist, row, email ); + return row; +} + +static void edit_group_load_clist( GtkCList *clist, GList *listEMail ) { + GList *node = listEMail; + while( node ) { + ItemEMail *email = node->data; + edit_group_clist_add_email( clist, email ); + node = g_list_next( node ); + } +} + +static void edit_group_group_selected( GtkCList *clist, gint row, gint column, GdkEvent *event, gpointer data ) { + groupeditdlg.rowIndGroup = row; +} + +static void edit_group_avail_selected( GtkCList *clist, gint row, gint column, GdkEvent *event, gpointer data ) { + groupeditdlg.rowIndAvail = row; +} + +static gint edit_group_move_email( GtkCList *clist_from, GtkCList *clist_to, gint row ) { + ItemEMail *email = gtk_clist_get_row_data( clist_from, row ); + gint rrow = -1; + if( email ) { + gtk_clist_remove( clist_from, row ); + rrow = edit_group_clist_add_email( clist_to, email ); + gtk_clist_select_row( clist_to, rrow, 0 ); + } + return rrow; +} + +static void edit_group_to_group( GtkWidget *widget, gpointer data ) { + groupeditdlg.rowIndGroup = edit_group_move_email( groupeditdlg.clist_avail, + groupeditdlg.clist_group, groupeditdlg.rowIndAvail ); +} + +static void edit_group_to_avail( GtkWidget *widget, gpointer data ) { + groupeditdlg.rowIndAvail = edit_group_move_email( groupeditdlg.clist_group, + groupeditdlg.clist_avail, groupeditdlg.rowIndGroup ); +} + +static void edit_group_list_group_button( GtkCList *clist, GdkEventButton *event, gpointer data ) { + if( ! event ) return; + if( event->button == 1 ) { + if( event->type == GDK_2BUTTON_PRESS ) { + edit_group_to_avail( NULL, NULL ); + } + } +} + +static void edit_group_list_avail_button( GtkCList *clist, GdkEventButton *event, gpointer data ) { + if( ! event ) return; + if( event->button == 1 ) { + if( event->type == GDK_2BUTTON_PRESS ) { + edit_group_to_group( NULL, NULL ); + } + } +} + +static gint edit_group_list_compare_func( GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2 ) { + GtkCell *cell1 = ((GtkCListRow *)ptr1)->cell; + GtkCell *cell2 = ((GtkCListRow *)ptr2)->cell; + gchar *name1 = NULL, *name2 = NULL; + if( cell1 ) name1 = cell1->u.text; + if( cell2 ) name2 = cell2->u.text; + if( ! name1 ) return ( name2 != NULL ); + if( ! name2 ) return -1; + return strcasecmp( name1, name2 ); +} + +static void addressbook_edit_group_create( gboolean *cancelled ) { + GtkWidget *window; + GtkWidget *vbox; + GtkWidget *hbbox; + GtkWidget *ok_btn; + GtkWidget *cancel_btn; + GtkWidget *hsbox; + GtkWidget *statusbar; + + GtkWidget *hboxg; + GtkWidget *table; + GtkWidget *label; + GtkWidget *entry_name; + GtkWidget *hboxl; + GtkWidget *vboxl; + GtkWidget *hboxh; + + GtkWidget *clist_swin; + GtkWidget *clist_group; + GtkWidget *clist_avail; + + GtkWidget *vboxb; + GtkWidget *vbuttonbox; + GtkWidget *buttonGroup; + GtkWidget *buttonAvail; + gint top; + + gchar *titles[ GROUP_N_COLS ] = { _( "Name" ), _("E-Mail Address"), _("Remarks") }; + gchar *text; + gint i; + + window = gtk_window_new(GTK_WINDOW_DIALOG); + gtk_widget_set_usize(window, EDITGROUP_WIDTH, EDITGROUP_HEIGHT ); + gtk_container_set_border_width(GTK_CONTAINER(window), 0); + gtk_window_set_title(GTK_WINDOW(window), _("Edit Group Data")); + gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); + gtk_window_set_modal(GTK_WINDOW(window), TRUE); + gtk_signal_connect(GTK_OBJECT(window), "delete_event", + GTK_SIGNAL_FUNC(edit_group_delete_event), + cancelled); + gtk_signal_connect(GTK_OBJECT(window), "key_press_event", + GTK_SIGNAL_FUNC(edit_group_key_pressed), + cancelled); + + vbox = gtk_vbox_new( FALSE, 6 ); + gtk_container_set_border_width(GTK_CONTAINER(vbox), BORDER_WIDTH); + gtk_widget_show( vbox ); + gtk_container_add( GTK_CONTAINER( window ), vbox ); + + // Group area + hboxg = gtk_hbox_new( FALSE, 0 ); + gtk_box_pack_start(GTK_BOX(vbox), hboxg, FALSE, FALSE, 0); + + // Data entry area + table = gtk_table_new( 1, 3, FALSE); + gtk_box_pack_start(GTK_BOX(hboxg), table, TRUE, TRUE, 0); + gtk_container_set_border_width( GTK_CONTAINER(table), 4 ); + gtk_table_set_row_spacings(GTK_TABLE(table), 0); + gtk_table_set_col_spacings(GTK_TABLE(table), 4); + + // First row + top = 0; + label = gtk_label_new(_("Group Name")); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); + + entry_name = gtk_entry_new(); + gtk_table_attach(GTK_TABLE(table), entry_name, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0); + + // List area + hboxl = gtk_hbox_new( FALSE, 6 ); + gtk_container_set_border_width( GTK_CONTAINER(hboxl), 8 ); + gtk_box_pack_start(GTK_BOX(vbox), hboxl, TRUE, TRUE, 0); + + // Group list + vboxl = gtk_vbox_new( FALSE, 0 ); + gtk_box_pack_start(GTK_BOX(hboxl), vboxl, TRUE, TRUE, 0); + + hboxh = gtk_hbox_new( FALSE, 0 ); + gtk_container_set_border_width( GTK_CONTAINER(hboxh), 4 ); + gtk_box_pack_start(GTK_BOX(vboxl), hboxh, FALSE, FALSE, 0); + label = gtk_label_new(_("Addresses in Group")); + gtk_box_pack_start(GTK_BOX(hboxh), label, TRUE, TRUE, 0); + buttonAvail = gtk_button_new_with_label( _( " -> " ) ); + gtk_box_pack_end(GTK_BOX(hboxh), buttonAvail, FALSE, FALSE, 0); + + clist_swin = gtk_scrolled_window_new( NULL, NULL ); + gtk_box_pack_start(GTK_BOX(vboxl), clist_swin, TRUE, TRUE, 0); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_ALWAYS); + + clist_group = gtk_clist_new_with_titles( GROUP_N_COLS, titles ); + gtk_container_add( GTK_CONTAINER(clist_swin), clist_group ); + gtk_clist_set_selection_mode( GTK_CLIST(clist_group), GTK_SELECTION_BROWSE ); + gtk_clist_set_column_width( GTK_CLIST(clist_group), GROUP_COL_NAME, GROUP_COL_WIDTH_NAME ); + gtk_clist_set_column_width( GTK_CLIST(clist_group), GROUP_COL_EMAIL, GROUP_COL_WIDTH_EMAIL ); + gtk_clist_set_compare_func( GTK_CLIST(clist_group), edit_group_list_compare_func ); + gtk_clist_set_auto_sort( GTK_CLIST(clist_group), TRUE ); + + for( i = 0; i < GROUP_N_COLS; i++ ) + GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(clist_group)->column[i].button, GTK_CAN_FOCUS); + + // Available list + vboxl = gtk_vbox_new( FALSE, 0 ); + gtk_box_pack_start(GTK_BOX(hboxl), vboxl, TRUE, TRUE, 0); + + hboxh = gtk_hbox_new( FALSE, 0 ); + gtk_container_set_border_width( GTK_CONTAINER(hboxh), 4 ); + gtk_box_pack_start(GTK_BOX(vboxl), hboxh, FALSE, FALSE, 0); + buttonGroup = gtk_button_new_with_label( _( " <- " ) ); + gtk_box_pack_start(GTK_BOX(hboxh), buttonGroup, FALSE, FALSE, 0); + label = gtk_label_new(_("Available Addresses")); + gtk_box_pack_end(GTK_BOX(hboxh), label, TRUE, TRUE, 0); + + clist_swin = gtk_scrolled_window_new( NULL, NULL ); + gtk_box_pack_start(GTK_BOX(vboxl), clist_swin, TRUE, TRUE, 0); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_ALWAYS); + + clist_avail = gtk_clist_new_with_titles( GROUP_N_COLS, titles ); + gtk_container_add( GTK_CONTAINER(clist_swin), clist_avail ); + gtk_clist_set_selection_mode( GTK_CLIST(clist_avail), GTK_SELECTION_BROWSE ); + gtk_clist_set_column_width( GTK_CLIST(clist_avail), GROUP_COL_NAME, GROUP_COL_WIDTH_NAME ); + gtk_clist_set_column_width( GTK_CLIST(clist_avail), GROUP_COL_EMAIL, GROUP_COL_WIDTH_EMAIL ); + gtk_clist_set_compare_func( GTK_CLIST(clist_avail), edit_group_list_compare_func ); + gtk_clist_set_auto_sort( GTK_CLIST(clist_avail), TRUE ); + + for( i = 0; i < GROUP_N_COLS; i++ ) + GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(clist_avail)->column[i].button, GTK_CAN_FOCUS); + + // Status line + hsbox = gtk_hbox_new(FALSE, 0); + gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH); + statusbar = gtk_statusbar_new(); + gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH); + + // Button panel + gtkut_button_set_create(&hbbox, &ok_btn, _("OK"), + &cancel_btn, _("Cancel"), NULL, NULL); + gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0); + gtk_widget_grab_default(ok_btn); + + gtk_signal_connect(GTK_OBJECT(ok_btn), "clicked", + GTK_SIGNAL_FUNC(edit_group_ok), cancelled); + gtk_signal_connect(GTK_OBJECT(cancel_btn), "clicked", + GTK_SIGNAL_FUNC(edit_group_cancel), cancelled); + + gtk_widget_show_all(vbox); + + // Event handlers + gtk_signal_connect( GTK_OBJECT(clist_group), "select_row", + GTK_SIGNAL_FUNC( edit_group_group_selected), NULL ); + gtk_signal_connect( GTK_OBJECT(clist_avail), "select_row", + GTK_SIGNAL_FUNC( edit_group_avail_selected), NULL ); + gtk_signal_connect( GTK_OBJECT(buttonGroup), "clicked", + GTK_SIGNAL_FUNC( edit_group_to_group ), NULL ); + gtk_signal_connect( GTK_OBJECT(buttonAvail), "clicked", + GTK_SIGNAL_FUNC( edit_group_to_avail ), NULL ); + gtk_signal_connect(GTK_OBJECT(clist_avail), "button_press_event", + GTK_SIGNAL_FUNC(edit_group_list_avail_button), NULL); + gtk_signal_connect(GTK_OBJECT(clist_group), "button_press_event", + GTK_SIGNAL_FUNC(edit_group_list_group_button), NULL); + + groupeditdlg.window = window; + groupeditdlg.ok_btn = ok_btn; + groupeditdlg.cancel_btn = cancel_btn; + groupeditdlg.statusbar = statusbar; + groupeditdlg.status_cid = gtk_statusbar_get_context_id( GTK_STATUSBAR(statusbar), "Edit Group Dialog" ); + + groupeditdlg.entry_name = entry_name; + groupeditdlg.clist_group = GTK_CLIST( clist_group ); + groupeditdlg.clist_avail = GTK_CLIST( clist_avail ); + + if( ! _edit_group_dfl_message_ ) { + _edit_group_dfl_message_ = _( "Move E-Mail Addresses to or from Group with arrow buttons" ); + } +} + +/* +* Return list of email items. +*/ +static GList *edit_group_build_email_list() { + GtkCList *clist = GTK_CLIST(groupeditdlg.clist_group); + GList *listEMail = NULL; + ItemEMail *email; + gint row = 0; + while( email = gtk_clist_get_row_data( clist, row ) ) { + listEMail = g_list_append( listEMail, email ); + row++; + } + return listEMail; +} + +/* +* Edit group. +* Enter: abf Address book. +* folder Parent folder for group (or NULL if adding to root folder). Argument is +* only required for new objects). +* group Group to edit, or NULL for a new group object. +* Return: Edited object, or NULL if cancelled. +*/ +ItemGroup *addressbook_edit_group( AddressBookFile *abf, ItemFolder *parent, ItemGroup *group ) { + static gboolean cancelled; + GList *listEMail = NULL; + + if (!groupeditdlg.window) + addressbook_edit_group_create(&cancelled); + gtk_widget_grab_focus(groupeditdlg.ok_btn); + gtk_widget_grab_focus(groupeditdlg.entry_name); + gtk_widget_show(groupeditdlg.window); + manage_window_set_transient(GTK_WINDOW(groupeditdlg.window)); + + // Clear all fields + groupeditdlg.rowIndGroup = -1; + groupeditdlg.rowIndAvail = -1; + edit_group_status_show( "" ); + gtk_clist_clear( GTK_CLIST(groupeditdlg.clist_group) ); + gtk_clist_clear( GTK_CLIST(groupeditdlg.clist_avail) ); + + if( group ) { + if( ADDRITEM_NAME(group) ) + gtk_entry_set_text(GTK_ENTRY(groupeditdlg.entry_name), ADDRITEM_NAME(group) ); + edit_group_load_clist( groupeditdlg.clist_group, group->listEMail ); + gtk_window_set_title( GTK_WINDOW(groupeditdlg.window), _("Edit Group Details")); + } + else { + gtk_window_set_title( GTK_WINDOW(groupeditdlg.window), _("Add New Group")); + gtk_entry_set_text(GTK_ENTRY(groupeditdlg.entry_name), ADDRESSBOOK_GUESS_GROUP_NAME ); + } + + listEMail = addrbook_get_available_email_list( abf, group ); + edit_group_load_clist( groupeditdlg.clist_avail, listEMail ); + mgu_clear_list( listEMail ); + listEMail = NULL; + gtk_clist_select_row( groupeditdlg.clist_group, 0, 0 ); + gtk_clist_select_row( groupeditdlg.clist_avail, 0, 0 ); + + edit_group_status_show( _edit_group_dfl_message_ ); + + gtk_main(); + gtk_widget_hide( groupeditdlg.window ); + + if( cancelled ) { + return NULL; + } + + listEMail = edit_group_build_email_list(); + if( group ) { + // Update email list + addrbook_update_group_list( abf, group, listEMail ); + } + else { + // Create new person and email list + group = addrbook_add_group_list( abf, parent, listEMail ); + } + addritem_group_set_name( group, gtk_editable_get_chars( GTK_EDITABLE(groupeditdlg.entry_name), 0, -1 ) ); + + listEMail = NULL; + return group; +} + +/* +* Edit folder. +* Enter: abf Address book. +* parent Parent folder for folder (or NULL if adding to root folder). Argument is +* only required for new objects). +* folder Folder to edit, or NULL for a new folder object. +* Return: Edited object, or NULL if cancelled. +*/ +ItemFolder *addressbook_edit_folder( AddressBookFile *abf, ItemFolder *parent, ItemFolder *folder ) { + gchar *name = NULL; + + if( folder ) { + name = g_strdup( ADDRITEM_NAME(folder) ); + name = input_dialog( _("Edit folder"), _("Input the new name of folder:"), name ); + } + else { + name = input_dialog( _("New folder"), + _("Input the name of new folder:"), + _(ADDRESSBOOK_GUESS_FOLDER_NAME) ); + } + if( ! name ) return NULL; + g_strstrip( name ); + if( *name == '\0' ) { + g_free( name ); + return NULL; + } + if( folder ) { + if( strcasecmp( name, ADDRITEM_NAME(folder) ) == 0 ) { + g_free( name ); + return NULL; + } + } + + if( ! folder ) { + folder = addrbook_add_new_folder( abf, parent ); + } + addritem_folder_set_name( folder, name ); + g_free( name ); + return folder; +} + +/* +* End of Source. +*/ + diff --git a/src/editgroup.h b/src/editgroup.h new file mode 100644 index 000000000..2d7ee0256 --- /dev/null +++ b/src/editgroup.h @@ -0,0 +1,36 @@ +/* + * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client + * Copyright (C) 2001 Match Grun + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ + +/* + * Edit VCard address book data. + */ + +#ifndef __EDITGROUP_H__ +#define __EDITGROUP_H__ + +// Function prototypes +ItemGroup *addressbook_edit_group( AddressBookFile *abf, ItemFolder *folder, ItemGroup *group ); +ItemFolder *addressbook_edit_folder( AddressBookFile *abf, ItemFolder *parent, ItemFolder *folder ); + +#endif /* __EDITGROUP_H__ */ + +/* +* End of Source. +*/ + diff --git a/src/editjpilot.c b/src/editjpilot.c index d98a4cc98..94a272ffc 100644 --- a/src/editjpilot.c +++ b/src/editjpilot.c @@ -44,6 +44,7 @@ #include "prefs_common.h" #include "addressitem.h" #include "jpilot.h" +#include "mgutils.h" #define ADDRESSBOOK_GUESS_JPILOT "MyJPilot" #define JPILOT_NUM_CUSTOM_LABEL 4 @@ -143,7 +144,7 @@ static void edit_jpilot_read_check_box( JPilotFile *pilotFile ) { jpilot_clear_custom_labels( pilotFile ); for( i = 0; i < JPILOT_NUM_CUSTOM_LABEL; i++ ) { if( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(jpilotedit.custom_check[i]) ) ) { - labelName = g_strdup( GTK_LABEL(jpilotedit.custom_label[i])->label ); + labelName = GTK_LABEL(jpilotedit.custom_label[i])->label; jpilot_add_custom_label( pilotFile, labelName ); } } @@ -169,6 +170,7 @@ static void edit_jpilot_file_check( void ) { flg = TRUE; } jpilot_free( jpf ); + jpf = NULL; } } if( ! flg ) { @@ -370,14 +372,15 @@ static void addressbook_edit_jpilot_create( gboolean *cancelled ) { } } -AddressJPilot *addressbook_edit_jpilot( AddressJPilot *jpilot ) { +AdapterDSource *addressbook_edit_jpilot( AddressIndex *addrIndex, AdapterDSource *ads ) { static gboolean cancelled; gchar *sName; gchar *sFile; - JPilotFile *jpf; + AddressDataSource *ds = NULL; + JPilotFile *jpf = NULL; gboolean fin; - if (!jpilotedit.window) + if( ! jpilotedit.window ) addressbook_edit_jpilot_create(&cancelled); gtk_widget_grab_focus(jpilotedit.ok_btn); gtk_widget_grab_focus(jpilotedit.name_entry); @@ -385,8 +388,9 @@ AddressJPilot *addressbook_edit_jpilot( AddressJPilot *jpilot ) { manage_window_set_transient(GTK_WINDOW(jpilotedit.window)); edit_jpilot_status_show( "" ); - if( jpilot ) { - jpf = jpilot->pilotFile; + if( ads ) { + ds = ads->dataSource; + jpf = ds->rawDataSource; if (jpf->name) gtk_entry_set_text(GTK_ENTRY(jpilotedit.name_entry), jpf->name); if (jpf->path) @@ -400,7 +404,6 @@ AddressJPilot *addressbook_edit_jpilot( AddressJPilot *jpilot ) { gtk_entry_set_text(GTK_ENTRY(jpilotedit.file_entry), guessFile ); gtk_window_set_title( GTK_WINDOW(jpilotedit.window), _("Add New JPilot Entry")); edit_jpilot_fill_check_box_new(); - // Attempt to load labels if( *guessFile != '\0' ) { edit_jpilot_file_check(); } @@ -417,14 +420,12 @@ AddressJPilot *addressbook_edit_jpilot( AddressJPilot *jpilot ) { if( *sFile == '\0' ) fin = TRUE; if( ! fin ) { - if( ! jpilot ) { - jpilot = g_new0(AddressJPilot, 1); - ADDRESS_OBJECT_TYPE(jpilot) = ADDR_JPILOT; + if( ! ads ) { jpf = jpilot_create(); - jpilot->pilotFile = jpf; + ds = addrindex_index_add_datasource( addrIndex, ADDR_IF_JPILOT, jpf ); + ads = addressbook_create_ds_adapter( ds, ADDR_JPILOT, NULL ); } - g_free( jpilot->name ); - jpilot->name = g_strdup( sName ); + addressbook_ads_set_name( ads, sName ); jpilot_set_name( jpf, sName ); jpilot_set_file( jpf, sFile ); edit_jpilot_read_check_box( jpf ); @@ -432,7 +433,7 @@ AddressJPilot *addressbook_edit_jpilot( AddressJPilot *jpilot ) { g_free( sName ); g_free( sFile ); - return jpilot; + return ads; } #endif /* USE_JPILOT */ diff --git a/src/editjpilot.h b/src/editjpilot.h index 795d8c91d..6931c973d 100644 --- a/src/editjpilot.h +++ b/src/editjpilot.h @@ -27,7 +27,7 @@ #ifdef USE_JPILOT // Function prototypes -AddressJPilot *addressbook_edit_jpilot( AddressJPilot *jpilot ); +AdapterDSource *addressbook_edit_jpilot( AddressIndex *addrIndex, AdapterDSource *ads ); #endif /* USE_JPILOT */ diff --git a/src/editldap.c b/src/editldap.c index 010a45d06..38d6b3e05 100644 --- a/src/editldap.c +++ b/src/editldap.c @@ -41,7 +41,6 @@ #include "intl.h" #include "addressbook.h" #include "prefs_common.h" -#include "menu.h" #include "addressitem.h" #include "syldap.h" #include "editldap_basedn.h" @@ -73,7 +72,7 @@ static struct _LDAPEdit { /* * Edit functions. */ -void edit_ldap_status_show( gchar *msg ) { +static void edit_ldap_status_show( gchar *msg ) { if( ldapedit.statusbar != NULL ) { gtk_statusbar_pop( GTK_STATUSBAR(ldapedit.statusbar), ldapedit.status_cid ); if( msg ) { @@ -492,11 +491,12 @@ gint edit_ldap_get_optmenu( GtkOptionMenu *optmenu ) { return GPOINTER_TO_INT(gtk_object_get_user_data(GTK_OBJECT(menuitem))); } -AddressLDAP *addressbook_edit_ldap( AddressLDAP *ldapi ) { +AdapterDSource *addressbook_edit_ldap( AddressIndex *addrIndex, AdapterDSource *ads ) { static gboolean cancelled; gchar *sName, *sHost, *sBase, *sBind, *sPass, *sCrit; gint iPort, iMaxE, iTime, iMail, iName; - SyldapServer *server; + AddressDataSource *ds = NULL; + SyldapServer *server = NULL; gboolean fin; if (!ldapedit.window) @@ -508,8 +508,9 @@ AddressLDAP *addressbook_edit_ldap( AddressLDAP *ldapi ) { manage_window_set_transient(GTK_WINDOW(ldapedit.window)); edit_ldap_status_show( "" ); - if( ldapi ) { - server = ldapi->ldapServer; + if( ads ) { + ds = ads->dataSource; + server = ds->rawDataSource; if (server->name) gtk_entry_set_text(GTK_ENTRY(ldapedit.entry_name), server->name); if (server->hostName) @@ -560,14 +561,12 @@ AddressLDAP *addressbook_edit_ldap( AddressLDAP *ldapi ) { if( *sBase == '\0' ) fin = TRUE; if( ! fin ) { - if( ! ldapi ) { - ldapi = g_new0(AddressLDAP, 1); - ADDRESS_OBJECT_TYPE(ldapi) = ADDR_LDAP; + if( ! ads ) { server = syldap_create(); - ldapi->ldapServer = server; + ds = addrindex_index_add_datasource( addrIndex, ADDR_IF_LDAP, server ); + ads = addressbook_create_ds_adapter( ds, ADDR_LDAP, NULL ); } - g_free( ldapi->name ); - ldapi->name = g_strdup( sName ); + addressbook_ads_set_name( ads, sName ); syldap_set_name( server, sName ); syldap_set_host( server, sHost ); syldap_set_port( server, iPort ); @@ -585,7 +584,7 @@ AddressLDAP *addressbook_edit_ldap( AddressLDAP *ldapi ) { g_free( sPass ); g_free( sCrit ); - return ldapi; + return ads; } #endif /* USE_LDAP */ diff --git a/src/editldap.h b/src/editldap.h index 68fafb5ca..a644e5d32 100644 --- a/src/editldap.h +++ b/src/editldap.h @@ -27,7 +27,7 @@ #ifdef USE_LDAP // Function prototypes -AddressLDAP *addressbook_edit_ldap( AddressLDAP *ldapi ); +AdapterDSource *addressbook_edit_ldap( AddressIndex *addrIndex, AdapterDSource *ads ); #endif /* USE_LDAP */ diff --git a/src/editldap_basedn.c b/src/editldap_basedn.c index aabb27fcd..f836fc9ba 100644 --- a/src/editldap_basedn.c +++ b/src/editldap_basedn.c @@ -61,7 +61,7 @@ static gboolean ldapedit_basedn_bad_server; /* * Edit functions. */ -void edit_ldap_bdn_status_show( gchar *msg ) { +static void edit_ldap_bdn_status_show( gchar *msg ) { if( ldapedit_basedn.statusbar != NULL ) { gtk_statusbar_pop( GTK_STATUSBAR(ldapedit_basedn.statusbar), ldapedit_basedn.status_cid ); if( msg ) { @@ -248,7 +248,7 @@ void edit_ldap_bdn_load_data( const gchar *hostName, const gint iPort, const gin gboolean flgConn; gboolean flgDN; - edit_ldap_status_show( "" ); + edit_ldap_bdn_status_show( "" ); gtk_clist_clear(GTK_CLIST(ldapedit_basedn.basedn_list)); ldapedit_basedn_bad_server = TRUE; flgConn = flgDN = FALSE; diff --git a/src/editvcard.c b/src/editvcard.c index 4420b8435..aa2a1b67f 100644 --- a/src/editvcard.c +++ b/src/editvcard.c @@ -41,6 +41,7 @@ #include "prefs_common.h" #include "addressitem.h" #include "vcard.h" +#include "mgutils.h" #define ADDRESSBOOK_GUESS_VCARD "MyGnomeCard" @@ -262,14 +263,15 @@ static void addressbook_edit_vcard_create( gboolean *cancelled ) { vcardedit.status_cid = gtk_statusbar_get_context_id( GTK_STATUSBAR(statusbar), "Edit VCard Dialog" ); } -AddressVCard *addressbook_edit_vcard( AddressVCard *vcard ) { +AdapterDSource *addressbook_edit_vcard( AddressIndex *addrIndex, AdapterDSource *ads ) { static gboolean cancelled; gchar *sName; gchar *sFile; - VCardFile *vcf; + AddressDataSource *ds = NULL; + VCardFile *vcf = NULL; gboolean fin; - if (!vcardedit.window) + if( ! vcardedit.window ) addressbook_edit_vcard_create(&cancelled); gtk_widget_grab_focus(vcardedit.ok_btn); gtk_widget_grab_focus(vcardedit.name_entry); @@ -277,8 +279,9 @@ AddressVCard *addressbook_edit_vcard( AddressVCard *vcard ) { manage_window_set_transient(GTK_WINDOW(vcardedit.window)); edit_vcard_status_show( "" ); - if( vcard ) { - vcf = vcard->cardFile; + if( ads ) { + ds = ads->dataSource; + vcf = ds->rawDataSource; if (vcf->name) gtk_entry_set_text(GTK_ENTRY(vcardedit.name_entry), vcf->name); if (vcf->path) @@ -302,21 +305,19 @@ AddressVCard *addressbook_edit_vcard( AddressVCard *vcard ) { if( *sFile == '\0' ) fin = TRUE; if( ! fin ) { - if( ! vcard ) { - vcard = g_new0(AddressVCard, 1); - ADDRESS_OBJECT_TYPE(vcard) = ADDR_VCARD; + if( ! ads ) { vcf = vcard_create(); - vcard->cardFile = vcf; + ds = addrindex_index_add_datasource( addrIndex, ADDR_IF_VCARD, vcf ); + ads = addressbook_create_ds_adapter( ds, ADDR_VCARD, NULL ); } - g_free( vcard->name ); - vcard->name = g_strdup( sName ); + addressbook_ads_set_name( ads, sName ); vcard_set_name( vcf, sName ); vcard_set_file( vcf, sFile ); } g_free( sName ); g_free( sFile ); - return vcard; + return ads; } /* diff --git a/src/editvcard.h b/src/editvcard.h index 26b9471c4..8be859a8f 100644 --- a/src/editvcard.h +++ b/src/editvcard.h @@ -25,7 +25,7 @@ #define __EDITVCARD_H__ // Function prototypes -AddressVCard *addressbook_edit_vcard( AddressVCard *vcard ); +AdapterDSource *addressbook_edit_vcard( AddressIndex *addrIndex, AdapterDSource *ads ); #endif /* __EDITVCARD_H__ */ diff --git a/src/jpilot.c b/src/jpilot.c index 27d08967d..9b4d4b130 100644 --- a/src/jpilot.c +++ b/src/jpilot.c @@ -39,6 +39,8 @@ #include #include "mgutils.h" +#include "addritem.h" +#include "addrcache.h" #include "jpilot.h" #define JPILOT_DBHOME_DIR ".jpilot" @@ -52,50 +54,94 @@ #define IND_CUSTOM_LABEL 14 // Offset to custom label names #define NUM_CUSTOM_LABEL 4 // Number of custom labels -typedef struct _JPilotCategory JPilotCategory; -struct _JPilotCategory { - AddressItem *category; - GList *addressList; - gint count; -}; - -/* -* Specify name to be used. -*/ -void jpilot_set_name( JPilotFile* pilotFile, const gchar *name ) { - if( pilotFile->name ) g_free( pilotFile->name ); - if( name ) pilotFile->name = g_strdup( name ); -} - -/* -* Specify file to be used. -*/ -void jpilot_set_file( JPilotFile* pilotFile, const gchar *path ) { - g_return_if_fail( pilotFile != NULL ); - mgu_refresh_cache( pilotFile->addressCache ); - pilotFile->readMetadata = FALSE; +// Shamelessly copied from JPilot (libplugin.h) +typedef struct { + unsigned char db_name[32]; + unsigned char flags[2]; + unsigned char version[2]; + unsigned char creation_time[4]; + unsigned char modification_time[4]; + unsigned char backup_time[4]; + unsigned char modification_number[4]; + unsigned char app_info_offset[4]; + unsigned char sort_info_offset[4]; + unsigned char type[4];/*Database ID */ + unsigned char creator_id[4];/*Application ID */ + unsigned char unique_id_seed[4]; + unsigned char next_record_list_id[4]; + unsigned char number_of_records[2]; +} RawDBHeader; + +// Shamelessly copied from JPilot (libplugin.h) +typedef struct { + char db_name[32]; + unsigned int flags; + unsigned int version; + time_t creation_time; + time_t modification_time; + time_t backup_time; + unsigned int modification_number; + unsigned int app_info_offset; + unsigned int sort_info_offset; + char type[5];/*Database ID */ + char creator_id[5];/*Application ID */ + char unique_id_seed[5]; + unsigned int next_record_list_id; + unsigned int number_of_records; +} DBHeader; + +// Shamelessly copied from JPilot (libplugin.h) +typedef struct { + unsigned char Offset[4]; /*4 bytes offset from BOF to record */ + unsigned char attrib; + unsigned char unique_ID[3]; +} record_header; - /* Copy file path */ - if( pilotFile->path ) g_free( pilotFile->path ); - if( path ) pilotFile->path = g_strdup( path ); -} +// Shamelessly copied from JPilot (libplugin.h) +typedef struct mem_rec_header_s { + unsigned int rec_num; + unsigned int offset; + unsigned int unique_id; + unsigned char attrib; + struct mem_rec_header_s *next; +} mem_rec_header; + +// Shamelessly copied from JPilot (libplugin.h) +#define SPENT_PC_RECORD_BIT 256 + +typedef enum { + PALM_REC = 100L, + MODIFIED_PALM_REC = 101L, + DELETED_PALM_REC = 102L, + NEW_PC_REC = 103L, + DELETED_PC_REC = SPENT_PC_RECORD_BIT + 104L, + DELETED_DELETED_PALM_REC = SPENT_PC_RECORD_BIT + 105L +} PCRecType; + +// Shamelessly copied from JPilot (libplugin.h) +typedef struct { + PCRecType rt; + unsigned int unique_id; + unsigned char attrib; + void *buf; + int size; +} buf_rec; /* * Create new pilot file object. */ JPilotFile *jpilot_create() { JPilotFile *pilotFile; - pilotFile = g_new( JPilotFile, 1 ); + pilotFile = g_new0( JPilotFile, 1 ); pilotFile->name = NULL; - pilotFile->path = NULL; pilotFile->file = NULL; - pilotFile->addressCache = mgu_create_cache(); + pilotFile->path = NULL; + pilotFile->addressCache = addrcache_create(); pilotFile->readMetadata = FALSE; pilotFile->customLabels = NULL; pilotFile->labelInd = NULL; pilotFile->retVal = MGU_SUCCESS; - pilotFile->categoryList = NULL; - pilotFile->catAddrList = NULL; + pilotFile->accessFlag = FALSE; return pilotFile; } @@ -109,37 +155,81 @@ JPilotFile *jpilot_create_path( const gchar *path ) { return pilotFile; } +/* +* Properties... +*/ +void jpilot_set_name( JPilotFile* pilotFile, const gchar *value ) { + g_return_if_fail( pilotFile != NULL ); + pilotFile->name = mgu_replace_string( pilotFile->name, value ); +} +void jpilot_set_file( JPilotFile* pilotFile, const gchar *value ) { + g_return_if_fail( pilotFile != NULL ); + addrcache_refresh( pilotFile->addressCache ); + pilotFile->readMetadata = FALSE; + pilotFile->path = mgu_replace_string( pilotFile->path, value ); +} +void jpilot_set_accessed( JPilotFile *pilotFile, const gboolean value ) { + g_return_if_fail( pilotFile != NULL ); + pilotFile->accessFlag = value; +} + +gint jpilot_get_status( JPilotFile *pilotFile ) { + g_return_if_fail( pilotFile != NULL ); + return pilotFile->retVal; +} +ItemFolder *jpilot_get_root_folder( JPilotFile *pilotFile ) { + g_return_if_fail( pilotFile != NULL ); + return addrcache_get_root_folder( pilotFile->addressCache ); +} +gchar *jpilot_get_name( JPilotFile *pilotFile ) { + g_return_if_fail( pilotFile != NULL ); + return pilotFile->name; +} + /* * Test whether file was modified since last access. * Return: TRUE if file was modified. */ gboolean jpilot_get_modified( JPilotFile *pilotFile ) { g_return_if_fail( pilotFile != NULL ); - return mgu_check_file( pilotFile->addressCache, pilotFile->path ); + return addrcache_check_file( pilotFile->addressCache, pilotFile->path ); +} +gboolean jpilot_get_accessed( JPilotFile *pilotFile ) { + g_return_if_fail( pilotFile != NULL ); + return pilotFile->accessFlag; +} + +/* +* Test whether file was read. +* Return: TRUE if file was read. +*/ +gboolean jpilot_get_read_flag( JPilotFile *pilotFile ) { + g_return_if_fail( pilotFile != NULL ); + return pilotFile->addressCache->dataRead; } /* * Free up custom label list. */ void jpilot_clear_custom_labels( JPilotFile *pilotFile ) { - GSList *node; + GList *node; g_return_if_fail( pilotFile != NULL ); // Release custom labels - mgu_free_list( pilotFile->customLabels ); + mgu_free_dlist( pilotFile->customLabels ); pilotFile->customLabels = NULL; // Release indexes node = pilotFile->labelInd; while( node ) { node->data = NULL; - node = g_slist_next( node ); + node = g_list_next( node ); } - g_slist_free( pilotFile->labelInd ); + g_list_free( pilotFile->labelInd ); pilotFile->labelInd = NULL; // Force a fresh read - mgu_refresh_cache( pilotFile->addressCache ); + addrcache_refresh( pilotFile->addressCache ); } /* @@ -156,9 +246,9 @@ void jpilot_add_custom_label( JPilotFile *pilotFile, const gchar *labelName ) { g_free( labelCopy ); } else { - pilotFile->customLabels = g_slist_append( pilotFile->customLabels, labelCopy ); + pilotFile->customLabels = g_list_append( pilotFile->customLabels, labelCopy ); // Force a fresh read - mgu_refresh_cache( pilotFile->addressCache ); + addrcache_refresh( pilotFile->addressCache ); } } } @@ -169,12 +259,12 @@ void jpilot_add_custom_label( JPilotFile *pilotFile, const gchar *labelName ) { */ GList *jpilot_get_custom_labels( JPilotFile *pilotFile ) { GList *retVal = NULL; - GSList *node; + GList *node; g_return_if_fail( pilotFile != NULL ); node = pilotFile->customLabels; while( node ) { retVal = g_list_append( retVal, g_strdup( node->data ) ); - node = g_slist_next( node ); + node = g_list_next( node ); } return retVal; } @@ -192,13 +282,11 @@ void jpilot_free( JPilotFile *pilotFile ) { jpilot_clear_custom_labels( pilotFile ); /* Clear cache */ - mgu_clear_cache( pilotFile->addressCache ); - mgu_free_cache( pilotFile->addressCache ); - mgu_free_dlist( pilotFile->categoryList ); + addrcache_clear( pilotFile->addressCache ); + addrcache_free( pilotFile->addressCache ); pilotFile->addressCache = NULL; pilotFile->readMetadata = FALSE; - pilotFile->categoryList = NULL; - pilotFile->catAddrList = NULL; + pilotFile->accessFlag = FALSE; /* Now release file object */ g_free( pilotFile ); @@ -208,42 +296,41 @@ void jpilot_free( JPilotFile *pilotFile ) { * Refresh internal variables to force a file read. */ void jpilot_force_refresh( JPilotFile *pilotFile ) { - mgu_refresh_cache( pilotFile->addressCache ); + addrcache_refresh( pilotFile->addressCache ); } /* -* Print category address list for specified category. +* Print object to specified stream. */ -void jpilot_print_category( JPilotCategory *jpcat, FILE *stream ) { - fprintf( stream, "category: %s : count: %d\n", jpcat->category->name, jpcat->count ); - if( jpcat->addressList ) { - mgu_print_address_list( jpcat->addressList, stream ); +void jpilot_print_file( JPilotFile *pilotFile, FILE *stream ) { + GList *node; + g_return_if_fail( pilotFile != NULL ); + fprintf( stream, "JPilotFile:\n" ); + fprintf( stream, "file spec: '%s'\n", pilotFile->path ); + fprintf( stream, " metadata: %s\n", pilotFile->readMetadata ? "yes" : "no" ); + fprintf( stream, " ret val: %d\n", pilotFile->retVal ); + + node = pilotFile->customLabels; + while( node ) { + fprintf( stream, " c label: %s\n", node->data ); + node = g_list_next( node ); } - fprintf( stream, "=========================================\n" ); -} -/* -* Print address list for all categories. -*/ -void jpilot_print_category_list( GList *catAddrList, FILE *stream ) { - GList *node; - JPilotCategory *jpcat; - if( catAddrList == NULL ) return; - - fprintf( stream, "Address list by category\n" ); - node = catAddrList; + node = pilotFile->labelInd; while( node ) { - jpcat = node->data; - jpilot_print_category( jpcat, stream ); + fprintf( stream, " labelind: %d\n", GPOINTER_TO_INT(node->data) ); node = g_list_next( node ); } + + addrcache_print( pilotFile->addressCache, stream ); + addritem_print_item_folder( pilotFile->addressCache->rootFolder, stream ); } /* -* Print object to specified stream. +* Print summary of object to specified stream. */ -void jpilot_print_file( JPilotFile *pilotFile, FILE *stream ) { - GSList *node; +void jpilot_print_short( JPilotFile *pilotFile, FILE *stream ) { + GList *node; g_return_if_fail( pilotFile != NULL ); fprintf( stream, "JPilotFile:\n" ); fprintf( stream, "file spec: '%s'\n", pilotFile->path ); @@ -253,27 +340,25 @@ void jpilot_print_file( JPilotFile *pilotFile, FILE *stream ) { node = pilotFile->customLabels; while( node ) { fprintf( stream, " c label: %s\n", node->data ); - node = g_slist_next( node ); + node = g_list_next( node ); } node = pilotFile->labelInd; while( node ) { fprintf( stream, " labelind: %d\n", GPOINTER_TO_INT(node->data) ); - node = g_slist_next( node ); + node = g_list_next( node ); } - - mgu_print_cache( pilotFile->addressCache, stream ); - jpilot_print_category_list( pilotFile->catAddrList, stream ); + addrcache_print( pilotFile->addressCache, stream ); } // Shamelessly copied from JPilot (libplugin.c) static unsigned int bytes_to_bin(unsigned char *bytes, unsigned int num_bytes) { - unsigned int i, n; - n=0; - for (i=0;idb_name, rdbh->db_name, 31); - dbh->db_name[31] = '\0'; - dbh->flags = bytes_to_bin(rdbh->flags, 2); - dbh->version = bytes_to_bin(rdbh->version, 2); - temp = bytes_to_bin(rdbh->creation_time, 4); - dbh->creation_time = pilot_time_to_unix_time(temp); - temp = bytes_to_bin(rdbh->modification_time, 4); - dbh->modification_time = pilot_time_to_unix_time(temp); - temp = bytes_to_bin(rdbh->backup_time, 4); - dbh->backup_time = pilot_time_to_unix_time(temp); - dbh->modification_number = bytes_to_bin(rdbh->modification_number, 4); - dbh->app_info_offset = bytes_to_bin(rdbh->app_info_offset, 4); - dbh->sort_info_offset = bytes_to_bin(rdbh->sort_info_offset, 4); - strncpy(dbh->type, rdbh->type, 4); - dbh->type[4] = '\0'; - strncpy(dbh->creator_id, rdbh->creator_id, 4); - dbh->creator_id[4] = '\0'; - strncpy(dbh->unique_id_seed, rdbh->unique_id_seed, 4); - dbh->unique_id_seed[4] = '\0'; - dbh->next_record_list_id = bytes_to_bin(rdbh->next_record_list_id, 4); - dbh->number_of_records = bytes_to_bin(rdbh->number_of_records, 2); - return 0; + unsigned long temp; + strncpy(dbh->db_name, rdbh->db_name, 31); + dbh->db_name[31] = '\0'; + dbh->flags = bytes_to_bin(rdbh->flags, 2); + dbh->version = bytes_to_bin(rdbh->version, 2); + temp = bytes_to_bin(rdbh->creation_time, 4); + dbh->creation_time = pilot_time_to_unix_time(temp); + temp = bytes_to_bin(rdbh->modification_time, 4); + dbh->modification_time = pilot_time_to_unix_time(temp); + temp = bytes_to_bin(rdbh->backup_time, 4); + dbh->backup_time = pilot_time_to_unix_time(temp); + dbh->modification_number = bytes_to_bin(rdbh->modification_number, 4); + dbh->app_info_offset = bytes_to_bin(rdbh->app_info_offset, 4); + dbh->sort_info_offset = bytes_to_bin(rdbh->sort_info_offset, 4); + strncpy(dbh->type, rdbh->type, 4); + dbh->type[4] = '\0'; + strncpy(dbh->creator_id, rdbh->creator_id, 4); + dbh->creator_id[4] = '\0'; + strncpy(dbh->unique_id_seed, rdbh->unique_id_seed, 4); + dbh->unique_id_seed[4] = '\0'; + dbh->next_record_list_id = bytes_to_bin(rdbh->next_record_list_id, 4); + dbh->number_of_records = bytes_to_bin(rdbh->number_of_records, 2); + return 0; } // Shamelessly copied from JPilot (libplugin.c) @@ -350,7 +435,7 @@ static void free_mem_rec_header(mem_rec_header **mem_rh) { } // Shamelessly copied from JPilot (libplugin.c) -int jpilot_free_db_list( GList **br_list ) { +static int jpilot_free_db_list( GList **br_list ) { GList *temp_list, *first; buf_rec *br; @@ -376,7 +461,7 @@ int jpilot_free_db_list( GList **br_list ) { // Shamelessly copied from JPilot (libplugin.c) // Read file size. -int jpilot_get_info_size( FILE *in, int *size ) { +static int jpilot_get_info_size( FILE *in, int *size ) { RawDBHeader rdbh; DBHeader dbh; unsigned int offset; @@ -413,7 +498,7 @@ int jpilot_get_info_size( FILE *in, int *size ) { // Read address file into address list. Based on JPilot's // libplugin.c (jp_get_app_info) -gint jpilot_get_file_info( JPilotFile *pilotFile, unsigned char **buf, int *buf_size ) { +static gint jpilot_get_file_info( JPilotFile *pilotFile, unsigned char **buf, int *buf_size ) { FILE *in; int num; unsigned int rec_size; @@ -488,7 +573,7 @@ gint jpilot_get_file_info( JPilotFile *pilotFile, unsigned char **buf, int *buf_ #define EMAIL_BUFSIZE 256 // Read address file into address cache. Based on JPilot's // jp_read_DB_files (from libplugin.c) -gint jpilot_read_cache( JPilotFile *pilotFile ) { +static gint jpilot_read_file( JPilotFile *pilotFile ) { FILE *in; char *buf; int num_records, recs_returned, i, num, r; @@ -510,10 +595,12 @@ gint jpilot_read_cache( JPilotFile *pilotFile ) { gchar fullName[ FULLNAME_BUFSIZE ]; gchar bufEMail[ EMAIL_BUFSIZE ]; gchar* extID; - AddressItem *addrItem = NULL; + ItemPerson *person; + ItemEMail *email; int *indPhoneLbl; char *labelEntry; - GSList *node; + GList *node; + ItemFolder *folderInd[ JPILOT_NUM_CATEG ]; retVal = MGU_SUCCESS; mem_rh = last_mem_rh = NULL; @@ -613,6 +700,17 @@ gint jpilot_read_cache( JPilotFile *pilotFile ) { } fseek(in, next_offset, SEEK_SET); + // Build array of pointers to categories; + i = 0; + node = addrcache_get_list_folder( pilotFile->addressCache ); + while( node ) { + if( i < JPILOT_NUM_CATEG ) { + folderInd[i] = node->data; + } + node = g_list_next( node ); + i++; + } + // Now go load all records while(!feof(in)) { struct CategoryAppInfo *cat = & ai->category; @@ -662,14 +760,27 @@ gint jpilot_read_cache( JPilotFile *pilotFile ) { } g_strchug( fullName ); g_strchomp( fullName ); + + person = addritem_create_item_person(); + addritem_person_set_common_name( person, fullName ); + addritem_person_set_first_name( person, addrEnt[ IND_LABEL_FIRSTNAME ] ); + addritem_person_set_last_name( person, addrEnt[ IND_LABEL_LASTNAME ] ); + addrcache_id_person( pilotFile->addressCache, person ); + extID = g_strdup_printf( "%d", unique_id ); + addritem_person_set_external_id( person, extID ); + g_free( extID ); + extID = NULL; // Add entry for each email address listed under phone labels. indPhoneLbl = addr.phoneLabel; for( k = 0; k < JPILOT_NUM_ADDR_PHONE; k++ ) { int ind; ind = indPhoneLbl[k]; - // fprintf( stdout, "%d : %d : %20s : %s\n", k, ind, ai->phoneLabels[ind], addrEnt[3+k] ); + /* + fprintf( stdout, "%d : %d : %20s : %s\n", k, ind, + ai->phoneLabels[ind], addrEnt[3+k] ); + */ if( indPhoneLbl[k] == IND_PHONE_EMAIL ) { labelEntry = addrEnt[ OFFSET_PHONE_LABEL + k ]; if( labelEntry ) { @@ -677,13 +788,11 @@ gint jpilot_read_cache( JPilotFile *pilotFile ) { g_strchug( bufEMail ); g_strchomp( bufEMail ); - addrItem = mgu_create_address(); - addrItem->name = g_strdup( fullName ); - addrItem->address = g_strdup( bufEMail ); - addrItem->remarks = g_strdup( "" ); - addrItem->externalID = g_strdup( extID ); - addrItem->categoryID = cat_id; - mgu_add_cache( pilotFile->addressCache, addrItem ); + email = addritem_create_item_email(); + addritem_email_set_address( email, bufEMail ); + addrcache_id_email( pilotFile->addressCache, email ); + addrcache_person_add_email( + pilotFile->addressCache, person, email ); } } } @@ -694,29 +803,45 @@ gint jpilot_read_cache( JPilotFile *pilotFile ) { gint ind; ind = GPOINTER_TO_INT( node->data ); if( ind > -1 ) { - // fprintf( stdout, "%d : %20s : %s\n", ind, ai->labels[ind], addrEnt[ind] ); + /* + fprintf( stdout, "%d : %20s : %s\n", ind, ai->labels[ind], + addrEnt[ind] ); + */ labelEntry = addrEnt[ind]; if( labelEntry ) { strcpy( bufEMail, labelEntry ); g_strchug( bufEMail ); g_strchomp( bufEMail ); - addrItem = mgu_create_address(); - addrItem->name = g_strdup( fullName ); - addrItem->address = g_strdup( bufEMail ); - addrItem->remarks = g_strdup( ai->labels[ind] ); - addrItem->externalID = g_strdup( extID ); - addrItem->categoryID = cat_id; - mgu_add_cache( pilotFile->addressCache, addrItem ); + email = addritem_create_item_email(); + addritem_email_set_address( email, bufEMail ); + addritem_email_set_remarks( email, ai->labels[ind] ); + addrcache_id_email( pilotFile->addressCache, email ); + addrcache_person_add_email( + pilotFile->addressCache, person, email ); } } - node = g_slist_next( node ); + node = g_list_next( node ); + } + + if( person->listEMail ) { + if( cat_id > -1 && cat_id < JPILOT_NUM_CATEG ) { + // Add to specified category + addrcache_folder_add_person( + pilotFile->addressCache, folderInd[cat_id], person ); + } + else { + // Add to root folder + addrcache_add_person( pilotFile->addressCache, person ); + } + } + else { + addritem_free_item_person( person ); + person = NULL; } - g_free( extID ); - extID = NULL; } recs_returned++; } @@ -729,7 +854,7 @@ gint jpilot_read_cache( JPilotFile *pilotFile ) { /* * Read metadata from file. */ -gint jpilot_read_metadata( JPilotFile *pilotFile ) { +static gint jpilot_read_metadata( JPilotFile *pilotFile ) { gint retVal; unsigned int rec_size; unsigned char *buf; @@ -738,6 +863,7 @@ gint jpilot_read_metadata( JPilotFile *pilotFile ) { g_return_if_fail( pilotFile != NULL ); pilotFile->readMetadata = FALSE; + addrcache_clear( pilotFile->addressCache ); // Read file info retVal = jpilot_get_file_info( pilotFile, &buf, &rec_size); @@ -765,10 +891,10 @@ gint jpilot_read_metadata( JPilotFile *pilotFile ) { * Setup labels and indexes from metadata. * Return: TRUE is setup successfully. */ -gboolean jpilot_setup_labels( JPilotFile *pilotFile ) { +static gboolean jpilot_setup_labels( JPilotFile *pilotFile ) { gboolean retVal = FALSE; struct AddressAppInfo *ai; - GSList *node; + GList *node; g_return_if_fail( pilotFile != NULL ); @@ -776,7 +902,7 @@ gboolean jpilot_setup_labels( JPilotFile *pilotFile ) { node = pilotFile->labelInd; while( node ) { node->data = NULL; - node = g_slist_next( node ); + node = g_list_next( node ); } pilotFile->labelInd = NULL; @@ -784,20 +910,18 @@ gboolean jpilot_setup_labels( JPilotFile *pilotFile ) { ai = & pilotFile->addrInfo; node = pilotFile->customLabels; while( node ) { - gchar *lbl, *labelName; - int i; - gint ind; - ind = -1; - lbl = node->data; + gchar *lbl = node->data; + gint ind = -1; + gint i; for( i = 0; i < JPILOT_NUM_LABELS; i++ ) { - labelName = ai->labels[i]; + gchar *labelName = ai->labels[i]; if( g_strcasecmp( labelName, lbl ) == 0 ) { ind = i; break; } } - pilotFile->labelInd = g_slist_append( pilotFile->labelInd, GINT_TO_POINTER(ind) ); - node = g_slist_next( node ); + pilotFile->labelInd = g_list_append( pilotFile->labelInd, GINT_TO_POINTER(ind) ); + node = g_list_next( node ); } retVal = TRUE; } @@ -807,7 +931,7 @@ gboolean jpilot_setup_labels( JPilotFile *pilotFile ) { /* * Load list with character strings of label names. */ -GSList *jpilot_load_label( JPilotFile *pilotFile, GSList *labelList ) { +GList *jpilot_load_label( JPilotFile *pilotFile, GList *labelList ) { int i; g_return_if_fail( pilotFile != NULL ); if( pilotFile->readMetadata ) { @@ -815,10 +939,10 @@ GSList *jpilot_load_label( JPilotFile *pilotFile, GSList *labelList ) { for( i = 0; i < JPILOT_NUM_LABELS; i++ ) { gchar *labelName = ai->labels[i]; if( labelName ) { - labelList = g_slist_append( labelList, g_strdup( labelName ) ); + labelList = g_list_append( labelList, g_strdup( labelName ) ); } else { - labelList = g_slist_append( labelList, g_strdup( "" ) ); + labelList = g_list_append( labelList, g_strdup( "" ) ); } } } @@ -849,7 +973,7 @@ gchar *jpilot_get_category_name( JPilotFile *pilotFile, gint catID ) { /* * Load list with character strings of phone label names. */ -GSList *jpilot_load_phone_label( JPilotFile *pilotFile, GSList *labelList ) { +GList *jpilot_load_phone_label( JPilotFile *pilotFile, GList *labelList ) { int i; g_return_if_fail( pilotFile != NULL ); if( pilotFile->readMetadata ) { @@ -857,10 +981,10 @@ GSList *jpilot_load_phone_label( JPilotFile *pilotFile, GSList *labelList ) { for( i = 0; i < JPILOT_NUM_PHONELABELS; i++ ) { gchar *labelName = ai->phoneLabels[i]; if( labelName ) { - labelList = g_slist_append( labelList, g_strdup( labelName ) ); + labelList = g_list_append( labelList, g_strdup( labelName ) ); } else { - labelList = g_slist_append( labelList, g_strdup( "" ) ); + labelList = g_list_append( labelList, g_strdup( "" ) ); } } } @@ -894,8 +1018,8 @@ GList *jpilot_load_custom_label( JPilotFile *pilotFile, GList *labelList ) { /* * Load list with character strings of category names. */ -GSList *jpilot_get_category_list( JPilotFile *pilotFile ) { - GSList *catList = NULL; +GList *jpilot_get_category_list( JPilotFile *pilotFile ) { + GList *catList = NULL; int i; g_return_if_fail( pilotFile != NULL ); if( pilotFile->readMetadata ) { @@ -904,10 +1028,10 @@ GSList *jpilot_get_category_list( JPilotFile *pilotFile ) { for( i = 0; i < JPILOT_NUM_CATEG; i++ ) { gchar *catName = cat->name[i]; if( catName ) { - catList = g_slist_append( catList, g_strdup( catName ) ); + catList = g_list_append( catList, g_strdup( catName ) ); } else { - catList = g_slist_append( catList, g_strdup( "" ) ); + catList = g_list_append( catList, g_strdup( "" ) ); } } } @@ -915,131 +1039,56 @@ GSList *jpilot_get_category_list( JPilotFile *pilotFile ) { } /* -* Free category address list. +* Build folder for each category. */ -void jpilot_free_address_list( JPilotFile *pilotFile ) { - GList *addrList; - g_return_if_fail( pilotFile != NULL ); - - addrList = pilotFile->catAddrList; - while( addrList ) { - JPilotCategory *jpcat = addrList->data; - mgu_free_address( jpcat->category ); - mgu_free_address_list( jpcat->addressList ); - jpcat->category = NULL; - jpcat->addressList = NULL; - jpcat->count = 0; - g_free( jpcat ); - jpcat = NULL; - addrList->data = NULL; - addrList = g_list_next( addrList ); - } - pilotFile->catAddrList = NULL; -} - -/* -* Move data from address list and group into category address list. -*/ -void jpilot_load_category_items( JPilotFile *pilotFile ) { - JPilotCategory *jpcat[ 1 + JPILOT_NUM_CATEG ]; +static void jpilot_build_category_list( JPilotFile *pilotFile ) { struct AddressAppInfo *ai = & pilotFile->addrInfo; struct CategoryAppInfo *cat = & ai->category; - AddressItem *itemCat; - GList *addrList; - int i; - - // Create array for data by category - for( i = 0; i < 1 + JPILOT_NUM_CATEG; i++ ) { - itemCat = mgu_create_address_item( ADDR_CATEGORY ); - itemCat->categoryID = i; - jpcat[i] = g_new( JPilotCategory, 1 ); - jpcat[i]->category = itemCat; - jpcat[i]->addressList = NULL; - jpcat[i]->count = 0; - if( i < JPILOT_NUM_CATEG ) { - gchar *catName = cat->name[i]; - if( catName && strlen( catName ) > 0 ) { - itemCat->name = g_strdup( catName ); - } - } + gint i; + for( i = 0; i < JPILOT_NUM_CATEG; i++ ) { + ItemFolder *folder = addritem_create_item_folder(); + addritem_folder_set_name( folder, cat->name[i] ); + addrcache_id_folder( pilotFile->addressCache, folder ); + addrcache_add_folder( pilotFile->addressCache, folder ); } - - // Process address list moving data to category - addrList = pilotFile->addressCache->addressList; - while( addrList ) { - GList *addrLink; - AddressItem *item; - item = addrList->data; - i = item->categoryID; - if( i < 0 || i > JPILOT_NUM_CATEG ) i = JPILOT_NUM_CATEG; // Position at end of array - - // Add item to category list - addrLink = jpcat[i]->addressList; - addrLink = g_list_append( addrLink, item ); - jpcat[i]->addressList = addrLink; - jpcat[i]->count++; - - // Clear from cache list - addrList->data = NULL; - addrList = g_list_next( addrList ); - } - - // Remove entries from address cache - mgu_clear_cache_null( pilotFile->addressCache ); - -/* - printf( "dump jpcArray[]...\n" ); - for( i = 0; i < 1 + JPILOT_NUM_CATEG; i++ ) { - jpilot_print_category( jpcat[i], stdout ); - } -*/ - - // Free up existing category address list - jpilot_free_address_list( pilotFile ); - - // Move categories from array to category address list - addrList = NULL; - for( i = 0; i < 1 + JPILOT_NUM_CATEG; i++ ) { - if( jpcat[i]->count > 0 ) { - itemCat = jpcat[i]->category; - if( ! itemCat->name ) { - // Create a category name - itemCat->name = g_strdup_printf( "? %d", itemCat->categoryID ); - } - } - addrList = g_list_append( addrList, jpcat[i] ); - jpcat[i] = NULL; - } - pilotFile->catAddrList = addrList; - - // jpilot_print_category_list( pilotFile->catAddrList, stdout ); - } /* -* Build linked list of address items for each category. +* Remove empty folders (categories). */ -GList *jpilot_build_category_list( JPilotFile *pilotFile ) { - GList *catList = NULL; +static void jpilot_remove_empty( JPilotFile *pilotFile ) { + GList *listFolder; + GList *remList; GList *node; - node = pilotFile->catAddrList; + gint i = 0; + + listFolder = addrcache_get_list_folder( pilotFile->addressCache ); + node = listFolder; + remList = NULL; while( node ) { - JPilotCategory *jpcat = node->data; - AddressItem *catItem = jpcat->category; - - catItem = jpcat->category; - if( jpcat->count > 0 || catItem->name ) { - AddressItem *itemNew = mgu_copy_address_item( catItem ); - if( itemNew ) { - catList = g_list_append( catList, itemNew ); + ItemFolder *folder = node->data; + if( ADDRITEM_NAME(folder) == NULL || *ADDRITEM_NAME(folder) == '\0' ) { + if( folder->listPerson ) { + // Give name to folder + gchar name[20]; + sprintf( name, "? %d", i ); + addritem_folder_set_name( folder, name ); + } + else { + // Mark for removal + remList = g_list_append( remList, folder ); } } node = g_list_next( node ); + i++; } - mgu_free_address_list( pilotFile->categoryList ); - pilotFile->categoryList = catList; - // mgu_print_address_list( catList, stdout ); - return catList; + node = remList; + while( node ) { + ItemFolder *folder = node->data; + addrcache_remove_folder( pilotFile->addressCache, folder ); + node = g_list_next( node ); + } + g_list_free( remList ); } // ============================================================================================ @@ -1051,58 +1100,52 @@ GList *jpilot_build_category_list( JPilotFile *pilotFile ) { gint jpilot_read_data( JPilotFile *pilotFile ) { g_return_if_fail( pilotFile != NULL ); pilotFile->retVal = MGU_SUCCESS; - if( mgu_check_file( pilotFile->addressCache, pilotFile->path ) ) { - mgu_clear_cache( pilotFile->addressCache ); + pilotFile->accessFlag = FALSE; + if( addrcache_check_file( pilotFile->addressCache, pilotFile->path ) ) { + addrcache_clear( pilotFile->addressCache ); jpilot_read_metadata( pilotFile ); if( pilotFile->retVal == MGU_SUCCESS ) { jpilot_setup_labels( pilotFile ); - pilotFile->retVal = jpilot_read_cache( pilotFile ); + jpilot_build_category_list( pilotFile ); + pilotFile->retVal = jpilot_read_file( pilotFile ); if( pilotFile->retVal == MGU_SUCCESS ) { - mgu_mark_cache( pilotFile->addressCache, pilotFile->path ); + jpilot_remove_empty( pilotFile ); + addrcache_mark_file( pilotFile->addressCache, pilotFile->path ); pilotFile->addressCache->modified = FALSE; pilotFile->addressCache->dataRead = TRUE; } - jpilot_load_category_items( pilotFile ); - jpilot_build_category_list( pilotFile ); } } return pilotFile->retVal; } /* -* Return linked list of address items for loaded category names. +* Return link list of persons. */ -GList *jpilot_get_category_items( JPilotFile *pilotFile ) { +GList *jpilot_get_list_person( JPilotFile *pilotFile ) { g_return_if_fail( pilotFile != NULL ); - return pilotFile->categoryList; + return addrcache_get_list_person( pilotFile->addressCache ); } /* -* Return address list for specified category. +* Return link list of folders. This is always NULL since there are +* no folders in GnomeCard. +* Return: NULL. */ -GList *jpilot_get_address_list_cat( JPilotFile *pilotFile, const gint catID ) { - GList *addrList = NULL, *node; +GList *jpilot_get_list_folder( JPilotFile *pilotFile ) { g_return_if_fail( pilotFile != NULL ); - - node = pilotFile->catAddrList; - while( node ) { - JPilotCategory *jpcat = node->data; - AddressItem *catItem = jpcat->category; - if( catItem->categoryID == catID ) { - addrList = jpcat->addressList; - break; - } - node = g_list_next( node ); - } - return addrList; + return addrcache_get_list_folder( pilotFile->addressCache ); } /* -* Return linked list of address items. +* Return link list of all persons. Note that the list contains references +* to items. Do *NOT* attempt to use the addrbook_free_xxx() functions... +* this will destroy the addressbook data! +* Return: List of items, or NULL if none. */ -GList *jpilot_get_address_list( JPilotFile *pilotFile ) { +GList *jpilot_get_all_persons( JPilotFile *pilotFile ) { g_return_if_fail( pilotFile != NULL ); - return pilotFile->addressCache->addressList; + return addrcache_get_all_persons( pilotFile->addressCache ); } /* @@ -1176,7 +1219,7 @@ gchar *jpilot_find_pilotdb( void ) { strcat( str, G_DIR_SEPARATOR_S ); strcat( str, JPILOT_DBHOME_FILE ); - // Attempt to open + // Attempt to open if( ( fp = fopen( str, "r" ) ) != NULL ) { fclose( fp ); } @@ -1212,7 +1255,7 @@ gint jpilot_test_read_file( const gchar *fileSpec ) { */ gboolean jpilot_test_custom_label( JPilotFile *pilotFile, const gchar *labelName ) { gboolean retVal; - GSList *node; + GList *node; g_return_if_fail( pilotFile != NULL ); retVal = FALSE; @@ -1223,7 +1266,7 @@ gboolean jpilot_test_custom_label( JPilotFile *pilotFile, const gchar *labelName retVal = TRUE; break; } - node = g_slist_next( node ); + node = g_list_next( node ); } } return retVal; @@ -1262,3 +1305,5 @@ gboolean jpilot_test_pilot_lib() { /* * End of Source. */ + + diff --git a/src/jpilot.h b/src/jpilot.h index dd28795ab..a3b725458 100644 --- a/src/jpilot.h +++ b/src/jpilot.h @@ -28,28 +28,27 @@ #ifdef USE_JPILOT -#include - -#include #include #include +#include -#include "mgutils.h" +#include "addritem.h" +#include "addrcache.h" typedef struct _JPilotFile JPilotFile; struct _JPilotFile { - gchar *name; - FILE *file; - gchar *path; - AddressCache *addressCache; + gchar *name; + FILE *file; + gchar *path; + AddressCache *addressCache; struct AddressAppInfo addrInfo; - gboolean readMetadata; - GSList *customLabels; - GSList *labelInd; - gint retVal; - GList *categoryList; - GList *catAddrList; + gboolean readMetadata; + GList *customLabels; + GList *labelInd; + gint retVal; + // ItemFolder *rootFolder; + gboolean accessFlag; }; // Limits @@ -60,110 +59,44 @@ struct _JPilotFile { #define JPILOT_LEN_CATEG 15 // Max length of category #define JPILOT_NUM_ADDR_PHONE 5 // Number of phone entries a person can have -// Shamelessly copied from JPilot (libplugin.h) -typedef struct { - unsigned char db_name[32]; - unsigned char flags[2]; - unsigned char version[2]; - unsigned char creation_time[4]; - unsigned char modification_time[4]; - unsigned char backup_time[4]; - unsigned char modification_number[4]; - unsigned char app_info_offset[4]; - unsigned char sort_info_offset[4]; - unsigned char type[4];/*Database ID */ - unsigned char creator_id[4];/*Application ID */ - unsigned char unique_id_seed[4]; - unsigned char next_record_list_id[4]; - unsigned char number_of_records[2]; -} RawDBHeader; - -// Shamelessly copied from JPilot (libplugin.h) -typedef struct { - char db_name[32]; - unsigned int flags; - unsigned int version; - time_t creation_time; - time_t modification_time; - time_t backup_time; - unsigned int modification_number; - unsigned int app_info_offset; - unsigned int sort_info_offset; - char type[5];/*Database ID */ - char creator_id[5];/*Application ID */ - char unique_id_seed[5]; - unsigned int next_record_list_id; - unsigned int number_of_records; -} DBHeader; - -// Shamelessly copied from JPilot (libplugin.h) -typedef struct { - unsigned char Offset[4]; /*4 bytes offset from BOF to record */ - unsigned char attrib; - unsigned char unique_ID[3]; -} record_header; - -// Shamelessly copied from JPilot (libplugin.h) -typedef struct mem_rec_header_s { - unsigned int rec_num; - unsigned int offset; - unsigned int unique_id; - unsigned char attrib; - struct mem_rec_header_s *next; -} mem_rec_header; - -// Shamelessly copied from JPilot (libplugin.h) -#define SPENT_PC_RECORD_BIT 256 - -typedef enum { - PALM_REC = 100L, - MODIFIED_PALM_REC = 101L, - DELETED_PALM_REC = 102L, - NEW_PC_REC = 103L, - DELETED_PC_REC = SPENT_PC_RECORD_BIT + 104L, - DELETED_DELETED_PALM_REC = SPENT_PC_RECORD_BIT + 105L -} PCRecType; - -// Shamelessly copied from JPilot (libplugin.h) -typedef struct { - PCRecType rt; - unsigned int unique_id; - unsigned char attrib; - void *buf; - int size; -} buf_rec; - /* Function prototypes */ -JPilotFile *jpilot_create(); -JPilotFile *jpilot_create_path( const gchar *path ); -void jpilot_free( JPilotFile *pilotFile ); -void jpilot_force_refresh( JPilotFile *pilotFile ); -gboolean jpilot_get_modified( JPilotFile *pilotFile ); -void jpilot_print_file( JPilotFile *jpilotFile, FILE *stream ); -void jpilot_print_list( GSList *list, FILE *stream ); -gint jpilot_read_file( JPilotFile *pilotFile ); - -GList *jpilot_get_address_list( JPilotFile *pilotFile ); -GSList *jpilot_load_label( JPilotFile *pilotFile, GSList *labelList ); -GSList *jpilot_get_category_list( JPilotFile *pilotFile ); -gchar *jpilot_get_category_name( JPilotFile *pilotFile, gint catID ); -GSList *jpilot_load_phone_label( JPilotFile *pilotFile, GSList *labelList ); -GList *jpilot_load_custom_label( JPilotFile *pilotFile, GList *labelList ); - -GList *jpilot_get_category_items( JPilotFile *pilotFile ); -GList *jpilot_get_address_list_cat( JPilotFile *pilotFile, const gint catID ); - -void jpilot_set_file( JPilotFile* pilotFile, const gchar *path ); -gboolean jpilot_validate( const JPilotFile *pilotFile ); -gchar *jpilot_find_pilotdb( void ); -gint jpilot_test_read_data( const gchar *fileSpec ); - -void jpilot_clear_custom_labels( JPilotFile *pilotFile ); -void jpilot_add_custom_label( JPilotFile *pilotFile, const gchar *labelName ); -GList *jpilot_get_custom_labels( JPilotFile *pilotFile ); -gboolean jpilot_test_custom_label( JPilotFile *pilotFile, const gchar *labelName ); -gboolean jpilot_setup_labels( JPilotFile *pilotFile ); -gboolean jpilot_test_pilot_lib(); +JPilotFile *jpilot_create ( void ); +JPilotFile *jpilot_create_path ( const gchar *path ); +void jpilot_set_name ( JPilotFile* pilotFile, const gchar *value ); +void jpilot_set_file ( JPilotFile* pilotFile, const gchar *value ); +void jpilot_free ( JPilotFile *pilotFile ); +gint jpilot_get_status ( JPilotFile *pilotFile ); +gboolean jpilot_get_modified ( JPilotFile *pilotFile ); +gboolean jpilot_get_accessed ( JPilotFile *pilotFile ); +void jpilot_set_accessed ( JPilotFile *pilotFile, const gboolean value ); +gboolean jpilot_get_read_flag ( JPilotFile *pilotFile ); +ItemFolder *jpilot_get_root_folder ( JPilotFile *pilotFile ); +gchar *jpilot_get_name ( JPilotFile *pilotFile ); + +void jpilot_force_refresh ( JPilotFile *pilotFile ); +void jpilot_print_file ( JPilotFile *jpilotFile, FILE *stream ); +void jpilot_print_short ( JPilotFile *pilotFile, FILE *stream ); +gint jpilot_read_data ( JPilotFile *pilotFile ); +GList *jpilot_get_list_person ( JPilotFile *pilotFile ); +GList *jpilot_get_list_folder ( JPilotFile *pilotFile ); +GList *jpilot_get_all_persons ( JPilotFile *pilotFile ); + +GList *jpilot_load_label ( JPilotFile *pilotFile, GList *labelList ); +GList *jpilot_get_category_list ( JPilotFile *pilotFile ); +gchar *jpilot_get_category_name ( JPilotFile *pilotFile, gint catID ); +GList *jpilot_load_phone_label ( JPilotFile *pilotFile, GList *labelList ); +GList *jpilot_load_custom_label ( JPilotFile *pilotFile, GList *labelList ); + +gboolean jpilot_validate ( const JPilotFile *pilotFile ); +gchar *jpilot_find_pilotdb ( void ); + +gint jpilot_test_read_file ( const gchar *fileSpec ); + +void jpilot_clear_custom_labels ( JPilotFile *pilotFile ); +void jpilot_add_custom_label ( JPilotFile *pilotFile, const gchar *labelName ); +GList *jpilot_get_custom_labels ( JPilotFile *pilotFile ); +gboolean jpilot_test_custom_label ( JPilotFile *pilotFile, const gchar *labelName ); +gboolean jpilot_test_pilot_lib ( void ); #endif /* USE_JPILOT */ diff --git a/src/main.c b/src/main.c index 04367abab..90bc4e11b 100644 --- a/src/main.c +++ b/src/main.c @@ -246,6 +246,7 @@ int main(int argc, char *argv[]) prefs_display_header_read_config(); prefs_display_header_write_config(); prefs_filtering_read_config(); + addressbook_read_file(); gtkut_widget_init(); diff --git a/src/mgutils.c b/src/mgutils.c index 68595ddc2..ea6146060 100644 --- a/src/mgutils.c +++ b/src/mgutils.c @@ -21,217 +21,11 @@ * General functions for create common address book entries. */ -#include #include #include -#include "addressitem.h" #include "mgutils.h" -/* -* Create new address item. -*/ -AddressItem *mgu_create_address_item( AddressObjectType type ) { - AddressItem *item; - item = g_new( AddressItem, 1 ); - ADDRESS_OBJECT(item)->type = type; - item->name = NULL; - item->address = NULL; - item->remarks = NULL; - item->externalID = NULL; - item->categoryID = ADDRESS_ITEM_CAT_UNKNOWN; - return item; -} - -/* -* Create new address item. -*/ -AddressItem *mgu_create_address( void ) { - AddressItem *item; - item = g_new( AddressItem, 1 ); - ADDRESS_OBJECT(item)->type = ADDR_ITEM; - item->name = NULL; - item->address = NULL; - item->remarks = NULL; - item->externalID = NULL; - item->categoryID = ADDRESS_ITEM_CAT_UNKNOWN; - return item; -} - -/* -* Create copy of specified address item. -*/ -AddressItem *mgu_copy_address_item( AddressItem *item ) { - AddressItem *itemNew = NULL; - if( item ) { - itemNew = mgu_create_address_item( ADDRESS_OBJECT(item)->type ); - itemNew->name = g_strdup( item->name ); - itemNew->address = g_strdup( item->address ); - itemNew->remarks = g_strdup( item->remarks ); - itemNew->externalID = g_strdup( item->externalID ); - itemNew->categoryID = item->categoryID; - } - return itemNew; -} - -/* -* Free address item. -*/ -void mgu_free_address( AddressItem *item ) { - g_return_if_fail( item != NULL ); - - /* Free internal stuff */ - g_free( item->name ); - g_free( item->address ); - g_free( item->remarks ); - g_free( item->externalID ); - item->name = NULL; - item->address = NULL; - item->remarks = NULL; - item->externalID = NULL; - item->categoryID = ADDRESS_ITEM_CAT_UNKNOWN; - - /* Now release item */ - g_free( item ); -} - -/* -* Refresh internal variables to force a reload. -*/ -void mgu_refresh_cache( AddressCache *cache ) { - cache->dataRead = FALSE; - cache->modified = TRUE; - cache->modifyTime = 0; -} - -/* -* Free up address list. -*/ -void mgu_free_address_list( GList *addrList ) { - AddressItem *item; - GList *node; - - /* Free data in the list */ - node = addrList; - while( node ) { - item = node->data; - mgu_free_address( item ); - node->data = NULL; - node = g_list_next( node ); - } - - /* Now release linked list object */ - g_list_free( addrList ); -} - -/* -* Clear the cache. -*/ -void mgu_clear_cache( AddressCache *cache ) { - AddressItem *item; - GList *node; - g_return_if_fail( cache != NULL ); - - /* Free data in the list */ - mgu_free_address_list( cache->addressList ); - cache->addressList = NULL; - mgu_refresh_cache( cache ); -} - -/* -* Clear the cache by setting pointers to NULL and free list. -* Note that individual items are not free'd. -*/ -void mgu_clear_cache_null( AddressCache *cache ) { - GList *node; - g_return_if_fail( cache != NULL ); - - /* Free data in the list */ - node = cache->addressList; - while( node ) { - node->data = NULL; - node = g_list_next( node ); - } - - /* Now release linked list object */ - g_list_free( cache->addressList ); - cache->addressList = NULL; -} - -/* -* Create new cache. -*/ -AddressCache *mgu_create_cache( void ) { - AddressCache *cache; - cache = g_new( AddressCache, 1 ); - cache->addressList = NULL; - cache->dataRead = FALSE; - cache->modified = FALSE; - cache->modifyTime = 0; - return cache; -} - -/* -* Create new address item. -*/ -void mgu_free_cache( AddressCache *cache ) { - mgu_clear_cache( cache ); - cache->addressList = NULL; -} - -/* -* Print address item. -*/ -void mgu_print_address( AddressItem *item, FILE *stream ) { - g_return_if_fail( item != NULL ); - fprintf( stream, "addr item:\n" ); - fprintf( stream, "\tname: '%s'\n", item->name ); - fprintf( stream, "\taddr: '%s'\n", item->address ); - fprintf( stream, "\trems: '%s'\n", item->remarks ); - fprintf( stream, "\tid : '%s'\n", item->externalID ); - fprintf( stream, "\tcatg: '%d'\n", item->categoryID ); - fprintf( stream, "---\n" ); -} - -/* -* Print linked list containing address item(s). -*/ -void mgu_print_address_list( GList *addrList, FILE *stream ) { - GList *node; - g_return_if_fail( addrList != NULL ); - - /* Now process the list */ - node = addrList; - while( node ) { - gpointer *gptr = node->data; - AddressItem *item = ( AddressItem * ) gptr; - mgu_print_address( item, stream ); - node = g_list_next( node ); - } -} - -/* -* Print address cache. -*/ -void mgu_print_cache( AddressCache *cache, FILE *stream ) { - GList *node; - g_return_if_fail( cache != NULL ); - fprintf( stream, "AddressCache:\n" ); - fprintf( stream, "modified : %s\n", cache->modified ? "yes" : "no" ); - fprintf( stream, "data read: %s\n", cache->dataRead ? "yes" : "no" ); - - /* Now process the list */ - node = cache->addressList; - while( node ) { - gpointer *gptr; - AddressItem *item; - gptr = node->data; - item = ( AddressItem * ) gptr; - mgu_print_address( item, stream ); - node = g_list_next( node ); - } -} - /* * Dump linked list of character strings (for debug). */ @@ -254,38 +48,6 @@ void mgu_print_dlist( GList *list, FILE *stream ) { } } -/* -* Check whether file has changed by comparing with cache. -* return: TRUE if file has changed. -*/ -gboolean mgu_check_file( AddressCache *cache, gchar *path ) { - gboolean retVal; - struct stat filestat; - retVal = TRUE; - if( path ) { - if( 0 == lstat( path, &filestat ) ) { - if( filestat.st_mtime == cache->modifyTime ) retVal = FALSE; - } - } - return retVal; -} - -/* -* Save file time to cache. -* return: TRUE if time marked. -*/ -gboolean mgu_mark_cache( AddressCache *cache, gchar *path ) { - gboolean retVal = FALSE; - struct stat filestat; - if( path ) { - if( 0 == lstat( path, &filestat ) ) { - cache->modifyTime = filestat.st_mtime; - retVal = TRUE; - } - } - return retVal; -} - /* * Free linked list of character strings. */ @@ -334,7 +96,7 @@ gchar *mgu_list_coalesce( GSList *list ) { } // Create new buffer. - buf = g_new( gchar, len+1 ); + buf = g_new0( gchar, len+1 ); start = buf; node = list; while( node ) { @@ -347,14 +109,6 @@ gchar *mgu_list_coalesce( GSList *list ) { return buf; } -/* -* Add address item to cache. -*/ -void mgu_add_cache( AddressCache *cache, AddressItem *addrItem ) { - cache->addressList = g_list_append( cache->addressList, addrItem ); - cache->modified = TRUE; -} - struct mgu_error_entry { gint e_code; gchar *e_reason; @@ -377,6 +131,9 @@ static const struct mgu_error_entry mgu_error_list[] = { { MGU_LDAP_CRITERIA, "Error in LDAP search criteria" }, { MGU_LDAP_CRITERIA, "Error in LDAP search criteria" }, { MGU_LDAP_NOENTRIES, "No LDAP entries found for search criteria" }, + { MGU_ERROR_WRITE, "Error writing to file" }, + { MGU_OPEN_DIRECTORY, "Error opening directory" }, + { MGU_NO_PATH, "No path specified" }, { -999, NULL } }; @@ -398,6 +155,65 @@ gchar *mgu_error2string( gint err ) { return ( e != NULL ) ? e->e_reason : "Unknown error"; } +/* +* Replace existing string with new string. +*/ +gchar *mgu_replace_string( gchar *str, const gchar *value ) { + if( str ) g_free( str ); + if( value ) { + str = g_strdup( value ); + g_strstrip( str ); + } + else { + str = NULL; + } + return str; +} + +/* +* Clear a linked list by setting node data pointers to NULL. Note that +* items are not freed. +*/ +void mgu_clear_slist( GSList *list ) { + GSList *node = list; + while( node ) { + node->data = NULL; + node = g_slist_next( node ); + } +} + +/* +* Clear a linked list by setting node data pointers to NULL. Note that +* items are not freed. +*/ +void mgu_clear_list( GList *list ) { + GList *node = list; + while( node ) { + node->data = NULL; + node = g_list_next( node ); + } +} + +/* +* Test and reformat an email address. +* Enter: address. +* Return: Address, or NULL if address is empty. +* Note: Leading and trailing white space is removed. +*/ +gchar *mgu_email_check_empty( gchar *address ) { + gchar *retVal = NULL; + if( address ) { + retVal = g_strdup( address ); + retVal = g_strchug( retVal ); + retVal = g_strchomp( retVal ); + if( *retVal == '\0' ) { + g_free( retVal ); + retVal = NULL; + } + } + return retVal; +} + /* * End of Source. */ diff --git a/src/mgutils.h b/src/mgutils.h index 04ea7c172..1d6f25bf7 100644 --- a/src/mgutils.h +++ b/src/mgutils.h @@ -24,12 +24,9 @@ #ifndef __MGUTILS_H__ #define __MGUTILS_H__ -#include #include #include -#include "addressitem.h" - // Error codes #define MGU_SUCCESS 0 #define MGU_BAD_ARGS -1 @@ -46,38 +43,20 @@ #define MGU_LDAP_TIMEOUT -12 #define MGU_LDAP_CRITERIA -13 #define MGU_LDAP_NOENTRIES -14 - -// Address cache -typedef struct _AddressCache AddressCache; -struct _AddressCache { - GList *addressList; - gboolean dataRead; - gboolean modified; - time_t modifyTime; -}; +#define MGU_ERROR_WRITE -15 +#define MGU_OPEN_DIRECTORY -16 +#define MGU_NO_PATH -17 // Function prototypes -AddressItem *mgu_create_address_item( AddressObjectType type ); -AddressItem *mgu_create_address( void ); -AddressItem *mgu_copy_address_item( AddressItem *item ); -void mgu_free_address( AddressItem *item ); -void mgu_free_address_list( GList *addrList ); -void mgu_refresh_cache( AddressCache *cache ); -void mgu_clear_cache( AddressCache *cache ); -void mgu_clear_cache_null( AddressCache *cache ); -AddressCache *mgu_create_cache( void ); -void mgu_free_cache( AddressCache *cache ); -void mgu_print_address( AddressItem *item, FILE *stream ); -void mgu_print_address_list( GList *addrList, FILE *stream ); -void mgu_print_cache( AddressCache *cache, FILE *stream ); -void mgu_print_list( GSList *list, FILE *stream ); -void mgu_print_dlist( GList *list, FILE *stream ); -gboolean mgu_check_file( AddressCache *cache, gchar *path ); -gboolean mgu_mark_cache( AddressCache *cache, gchar *path ); -void mgu_free_list( GSList *list ); -void mgu_free_dlist( GList *list ); -gchar *mgu_list_coalesce( GSList *list ); -void mgu_add_cache( AddressCache *cache, AddressItem *addrItem ); -gchar *mgu_error2string( gint err ); +void mgu_print_list ( GSList *list, FILE *stream ); +void mgu_print_dlist ( GList *list, FILE *stream ); +void mgu_free_list ( GSList *list ); +void mgu_free_dlist ( GList *list ); +gchar *mgu_list_coalesce ( GSList *list ); +gchar *mgu_error2string ( gint err ); +gchar *mgu_replace_string ( gchar *str, const gchar *value ); +void mgu_clear_slist ( GSList *list ); +void mgu_clear_list ( GList *list ); +gchar *mgu_email_check_empty ( gchar *address ); #endif /* __MGUTILS_H__ */ diff --git a/src/procmime.c b/src/procmime.c index db91d83e6..c2b47ee25 100644 --- a/src/procmime.c +++ b/src/procmime.c @@ -842,9 +842,11 @@ GList *procmime_get_mime_type_list(void) if (mime_type_list) return mime_type_list; - if ((fp = fopen(SYSCONFDIR "/mime.types", "r")) == NULL) { - FILE_OP_ERROR(SYSCONFDIR "/mime.types", "fopen"); - return NULL; + if ((fp = fopen("/etc/mime.types", "r")) == NULL) { + if ((fp = fopen(SYSCONFDIR "/mime.types", "r")) == NULL) { + FILE_OP_ERROR(SYSCONFDIR "/mime.types", "fopen"); + return NULL; + } } while (fgets(buf, sizeof(buf), fp) != NULL) { diff --git a/src/summaryview.c b/src/summaryview.c index e73fa76cb..d6c768418 100644 --- a/src/summaryview.c +++ b/src/summaryview.c @@ -148,7 +148,6 @@ static void summary_write_cache_func (GtkCTree *ctree, gpointer data); static void summary_set_menu_sensitive (SummaryView *summaryview); -static void summary_set_add_sender_menu (SummaryView *summaryview); static void summary_select_node (SummaryView *summaryview, GtkCTreeNode *node, @@ -313,6 +312,10 @@ static void summary_drag_data_get (GtkWidget *widget, guint time, SummaryView *summaryview); +static void summary_add_address_cb (SummaryView *summaryview, + guint action, + GtkWidget *widget); + /* custom compare functions for sorting */ static gint summary_cmp_by_num (GtkCList *clist, @@ -375,7 +378,7 @@ static GtkItemFactoryEntry summary_popup_entries[] = NULL, summary_reply_cb, COMPOSE_FORWARD_AS_ATTACH, NULL}, {N_("/---"), NULL, NULL, 0, ""}, {N_("/Add sender to address _book"), - NULL, NULL, 0, NULL}, + NULL, summary_add_address_cb, 0, NULL}, {N_("/---"), NULL, NULL, 0, ""}, {N_("/Open in new _window"), NULL, summary_open_msg, 0, NULL}, {N_("/View so_urce"), NULL, summary_view_source, 0, NULL}, @@ -1067,6 +1070,7 @@ static void summary_set_menu_sensitive(SummaryView *summaryview) menu_set_sensitive(ifactory, "/Reply to all", sens); menu_set_sensitive(ifactory, "/Forward", TRUE); menu_set_sensitive(ifactory, "/Forward as attachment", TRUE); + menu_set_sensitive(ifactory, "/Add sender to address book", sens); menu_set_sensitive(ifactory, "/Open in new window", sens); menu_set_sensitive(ifactory, "/View source", sens); @@ -1089,32 +1093,6 @@ static void summary_set_menu_sensitive(SummaryView *summaryview) menu_set_sensitive(ifactory, "/Follow-up and reply to", sens); } -static void summary_set_add_sender_menu(SummaryView *summaryview) -{ - GtkWidget *menu; - GtkWidget *submenu; - MsgInfo *msginfo; - gchar *from; - - menu = gtk_item_factory_get_item(summaryview->popupfactory, - "/Add sender to address book"); - msginfo = gtk_ctree_node_get_row_data(GTK_CTREE(summaryview->ctree), - summaryview->selected); - if (!msginfo || !msginfo->from) { - gtk_widget_set_sensitive(menu, FALSE); - submenu = gtk_menu_new(); - gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu), submenu); - return; - } - - gtk_widget_set_sensitive(menu, TRUE); - Xstrdup_a(from, msginfo->from, return); - eliminate_address_comment(from); - extract_address(from); - addressbook_add_submenu(menu, msginfo->fromname, from, NULL); - -} - void summary_select_next_unread(SummaryView *summaryview) { GtkCTreeNode *node; @@ -3643,8 +3621,8 @@ static void summary_button_pressed(GtkWidget *ctree, GdkEventButton *event, if (!event) return; if (event->button == 3) { - /* right clicked */ - summary_set_add_sender_menu(summaryview); + // Right button clicked + // summary_set_add_sender_menu(summaryview); gtk_menu_popup(GTK_MENU(summaryview->popupmenu), NULL, NULL, NULL, NULL, event->button, event->time); } else if (event->button == 2) { @@ -4305,3 +4283,21 @@ static void summary_unignore_thread(SummaryView *summaryview) summary_status_show(summaryview); } +static void summary_add_address_cb( SummaryView *summaryview, guint action, GtkWidget *widget ) { + MsgInfo *msginfo; + gchar *from; + + msginfo = gtk_ctree_node_get_row_data(GTK_CTREE(summaryview->ctree), + summaryview->selected); + if (!msginfo) return; + + Xstrdup_a(from, msginfo->from, return); + eliminate_address_comment(from); + extract_address(from); + addressbook_add_contact( msginfo->fromname, from, NULL ); +} + +/* + * End of Source. + */ + diff --git a/src/syldap.c b/src/syldap.c index 188f8c48e..be394161b 100644 --- a/src/syldap.c +++ b/src/syldap.c @@ -35,14 +35,42 @@ #include #include "mgutils.h" +#include "addritem.h" +#include "addrcache.h" #include "syldap.h" +/* +* Create new LDAP server interface object. +*/ +SyldapServer *syldap_create() { + SyldapServer *ldapServer; + ldapServer = g_new0( SyldapServer, 1 ); + ldapServer->name = NULL; + ldapServer->hostName = NULL; + ldapServer->port = SYLDAP_DFL_PORT; + ldapServer->baseDN = NULL; + ldapServer->bindDN = NULL; + ldapServer->bindPass = NULL; + ldapServer->searchCriteria = NULL; + ldapServer->searchValue = NULL; + ldapServer->entriesRead = 0; + ldapServer->maxEntries = SYLDAP_MAX_ENTRIES; + ldapServer->timeOut = SYLDAP_DFL_TIMEOUT; + ldapServer->newSearch = TRUE; + ldapServer->addressCache = addrcache_create(); + ldapServer->thread = NULL; + ldapServer->busyFlag = FALSE; + ldapServer->retVal = MGU_SUCCESS; + ldapServer->callBack = NULL; + ldapServer->accessFlag = FALSE; + return ldapServer; +} + /* * Specify name to be used. */ void syldap_set_name( SyldapServer* ldapServer, const gchar *value ) { - if( ldapServer->name ) g_free( ldapServer->name ); - if( value ) ldapServer->name = g_strdup( value ); + ldapServer->name = mgu_replace_string( ldapServer->name, value ); g_strstrip( ldapServer->name ); } @@ -50,10 +78,8 @@ void syldap_set_name( SyldapServer* ldapServer, const gchar *value ) { * Specify hostname to be used. */ void syldap_set_host( SyldapServer* ldapServer, const gchar *value ) { - mgu_refresh_cache( ldapServer->addressCache ); - - if( ldapServer->hostName ) g_free( ldapServer->hostName ); - if( value ) ldapServer->hostName = g_strdup( value ); + addrcache_refresh( ldapServer->addressCache ); + ldapServer->hostName = mgu_replace_string( ldapServer->hostName, value ); g_strstrip( ldapServer->hostName ); } @@ -61,8 +87,7 @@ void syldap_set_host( SyldapServer* ldapServer, const gchar *value ) { * Specify port to be used. */ void syldap_set_port( SyldapServer* ldapServer, const gint value ) { - mgu_refresh_cache( ldapServer->addressCache ); - + addrcache_refresh( ldapServer->addressCache ); if( value > 0 ) { ldapServer->port = value; } @@ -75,10 +100,8 @@ void syldap_set_port( SyldapServer* ldapServer, const gint value ) { * Specify base DN to be used. */ void syldap_set_base_dn( SyldapServer* ldapServer, const gchar *value ) { - mgu_refresh_cache( ldapServer->addressCache ); - - if( ldapServer->baseDN ) g_free( ldapServer->baseDN ); - if( value ) ldapServer->baseDN = g_strdup( value ); + addrcache_refresh( ldapServer->addressCache ); + ldapServer->baseDN = mgu_replace_string( ldapServer->baseDN, value ); g_strstrip( ldapServer->baseDN ); } @@ -86,10 +109,8 @@ void syldap_set_base_dn( SyldapServer* ldapServer, const gchar *value ) { * Specify bind DN to be used. */ void syldap_set_bind_dn( SyldapServer* ldapServer, const gchar *value ) { - mgu_refresh_cache( ldapServer->addressCache ); - - if( ldapServer->bindDN ) g_free( ldapServer->bindDN ); - if( value ) ldapServer->bindDN = g_strdup( value ); + addrcache_refresh( ldapServer->addressCache ); + ldapServer->bindDN = mgu_replace_string( ldapServer->bindDN, value ); g_strstrip( ldapServer->bindDN ); } @@ -97,10 +118,8 @@ void syldap_set_bind_dn( SyldapServer* ldapServer, const gchar *value ) { * Specify bind password to be used. */ void syldap_set_bind_password( SyldapServer* ldapServer, const gchar *value ) { - mgu_refresh_cache( ldapServer->addressCache ); - - if( ldapServer->bindPass ) g_free( ldapServer->bindPass ); - if( value ) ldapServer->bindPass = g_strdup( value ); + addrcache_refresh( ldapServer->addressCache ); + ldapServer->bindPass = mgu_replace_string( ldapServer->bindPass, value ); g_strstrip( ldapServer->bindPass ); } @@ -108,10 +127,8 @@ void syldap_set_bind_password( SyldapServer* ldapServer, const gchar *value ) { * Specify search criteria to be used. */ void syldap_set_search_criteria( SyldapServer* ldapServer, const gchar *value ) { - mgu_refresh_cache( ldapServer->addressCache ); - - if( ldapServer->searchCriteria ) g_free( ldapServer->searchCriteria ); - if( value ) ldapServer->searchCriteria = g_strdup( value ); + addrcache_refresh( ldapServer->addressCache ); + ldapServer->searchCriteria = mgu_replace_string( ldapServer->searchCriteria, value ); g_strstrip( ldapServer->searchCriteria ); ldapServer->newSearch = TRUE; } @@ -120,10 +137,8 @@ void syldap_set_search_criteria( SyldapServer* ldapServer, const gchar *value ) * Specify search value to be searched for. */ void syldap_set_search_value( SyldapServer* ldapServer, const gchar *value ) { - mgu_refresh_cache( ldapServer->addressCache ); - - if( ldapServer->searchValue ) g_free( ldapServer->searchValue ); - if( value ) ldapServer->searchValue = g_strdup( value ); + addrcache_refresh( ldapServer->addressCache ); + ldapServer->searchValue = mgu_replace_string( ldapServer->searchValue, value ); g_strstrip( ldapServer->searchValue ); ldapServer->newSearch = TRUE; } @@ -132,7 +147,7 @@ void syldap_set_search_value( SyldapServer* ldapServer, const gchar *value ) { * Specify maximum number of entries to retrieve. */ void syldap_set_max_entries( SyldapServer* ldapServer, const gint value ) { - mgu_refresh_cache( ldapServer->addressCache ); + addrcache_refresh( ldapServer->addressCache ); if( value > 0 ) { ldapServer->maxEntries = value; } @@ -145,7 +160,7 @@ void syldap_set_max_entries( SyldapServer* ldapServer, const gint value ) { * Specify timeout value for LDAP operation (in seconds). */ void syldap_set_timeout( SyldapServer* ldapServer, const gint value ) { - mgu_refresh_cache( ldapServer->addressCache ); + addrcache_refresh( ldapServer->addressCache ); if( value > 0 ) { ldapServer->timeOut = value; } @@ -162,40 +177,36 @@ void syldap_set_callback( SyldapServer *ldapServer, void *func ) { ldapServer->callBack = func; } -/* -* Create new LDAP server interface object. -*/ -SyldapServer *syldap_create() { - SyldapServer *ldapServer; - ldapServer = g_new( SyldapServer, 1 ); - ldapServer->name = NULL; - ldapServer->hostName = NULL; - ldapServer->port = SYLDAP_DFL_PORT; - ldapServer->baseDN = NULL; - ldapServer->bindDN = NULL; - ldapServer->bindPass = NULL; - ldapServer->searchCriteria = NULL; - ldapServer->searchValue = NULL; - ldapServer->entriesRead = 0; - ldapServer->maxEntries = SYLDAP_MAX_ENTRIES; - ldapServer->timeOut = SYLDAP_DFL_TIMEOUT; - ldapServer->newSearch = TRUE; - ldapServer->addressCache = mgu_create_cache(); - ldapServer->thread = NULL; - ldapServer->busyFlag = FALSE; - ldapServer->retVal = MGU_SUCCESS; - ldapServer->callBack = NULL; - return ldapServer; +void syldap_set_accessed( SyldapServer *ldapServer, const gboolean value ) { + g_return_if_fail( ldapServer != NULL ); + ldapServer->accessFlag = value; } /* * Refresh internal variables to force a file read. */ void syldap_force_refresh( SyldapServer *ldapServer ) { - mgu_refresh_cache( ldapServer->addressCache ); + addrcache_refresh( ldapServer->addressCache ); ldapServer->newSearch = TRUE; } +gint syldap_get_status( SyldapServer *ldapServer ) { + g_return_if_fail( ldapServer != NULL ); + return ldapServer->retVal; +} +ItemFolder *syldap_get_root_folder( SyldapServer *ldapServer ) { + g_return_if_fail( ldapServer != NULL ); + return addrcache_get_root_folder( ldapServer->addressCache ); +} +gchar *syldap_get_name( SyldapServer *ldapServer ) { + g_return_if_fail( ldapServer != NULL ); + return ldapServer->name; +} +gboolean syldap_get_accessed( SyldapServer *ldapServer ) { + g_return_if_fail( ldapServer != NULL ); + return ldapServer->accessFlag; +} + /* * Free up LDAP server interface object by releasing internal memory. */ @@ -203,9 +214,8 @@ void syldap_free( SyldapServer *ldapServer ) { g_return_if_fail( ldapServer != NULL ); ldapServer->callBack = NULL; - // fprintf( stdout, "freeing... SyldapServer\n" ); - /* Free internal stuff */ + // Free internal stuff g_free( ldapServer->name ); g_free( ldapServer->hostName ); g_free( ldapServer->baseDN ); @@ -219,9 +229,9 @@ void syldap_free( SyldapServer *ldapServer ) { ldapServer->maxEntries = 0; ldapServer->newSearch = FALSE; - /* Clear cache */ - mgu_clear_cache( ldapServer->addressCache ); - mgu_free_cache( ldapServer->addressCache ); + // Clear cache + addrcache_clear( ldapServer->addressCache ); + addrcache_free( ldapServer->addressCache ); // Clear pointers ldapServer->name = NULL; @@ -235,12 +245,11 @@ void syldap_free( SyldapServer *ldapServer ) { ldapServer->thread = NULL; ldapServer->busyFlag = FALSE; ldapServer->retVal = MGU_SUCCESS; + ldapServer->accessFlag = FALSE; - /* Now release file object */ + // Now release LDAP object g_free( ldapServer ); - // fprintf( stdout, "freeing... SyldapServer done\n" ); - } /* @@ -261,7 +270,8 @@ void syldap_print_data( SyldapServer *ldapServer, FILE *stream ) { fprintf( stream, "max entry: %d\n", ldapServer->maxEntries ); fprintf( stream, " num read: %d\n", ldapServer->entriesRead ); fprintf( stream, " ret val: %d\n", ldapServer->retVal ); - mgu_print_cache( ldapServer->addressCache, stream ); + addrcache_print( ldapServer->addressCache, stream ); + addritem_print_item_folder( ldapServer->addressCache->rootFolder, stream ); } /* @@ -288,35 +298,40 @@ void syldap_print_short( SyldapServer *ldapServer, FILE *stream ) { * Build an address list entry and append to list of address items. Name is formatted * as it appears in the common name (cn) attribute. */ -void syldap_build_items_cn( SyldapServer *ldapServer, GSList *listName, GSList *listAddr ) { - AddressItem *addrItem = NULL; +static void syldap_build_items_cn( SyldapServer *ldapServer, GSList *listName, GSList *listAddr ) { + ItemPerson *person; + ItemEMail *email; GSList *nodeName = listName; while( nodeName ) { GSList *nodeAddress = listAddr; + person = addritem_create_item_person(); + addritem_person_set_common_name( person, nodeName->data ); + addrcache_id_person( ldapServer->addressCache, person ); + addrcache_add_person( ldapServer->addressCache, person ); + while( nodeAddress ) { - addrItem = mgu_create_address(); - addrItem->name = g_strdup( nodeName->data ); - addrItem->address = g_strdup( nodeAddress->data ); - addrItem->remarks = g_strdup( "" ); - mgu_add_cache( ldapServer->addressCache, addrItem ); + email = addritem_create_item_email(); + addritem_email_set_address( email, nodeAddress->data ); + addrcache_id_email( ldapServer->addressCache, email ); + addrcache_person_add_email( ldapServer->addressCache, person, email ); nodeAddress = g_slist_next( nodeAddress ); ldapServer->entriesRead++; } nodeName = g_slist_next( nodeName ); } - addrItem = NULL; } /* * Build an address list entry and append to list of address items. Name is formatted * as " ". */ -void syldap_build_items_fl( SyldapServer *ldapServer, GSList *listAddr, GSList *listFirst, GSList *listLast ) { - AddressItem *addrItem = NULL; +static void syldap_build_items_fl( SyldapServer *ldapServer, GSList *listAddr, GSList *listFirst, GSList *listLast ) { GSList *nodeFirst = listFirst; GSList *nodeAddress = listAddr; gchar *firstName = NULL, *lastName = NULL, *fullName = NULL; gint iLen = 0, iLenT = 0; + ItemPerson *person; + ItemEMail *email; // Find longest first name in list while( nodeFirst ) { @@ -355,31 +370,33 @@ void syldap_build_items_fl( SyldapServer *ldapServer, GSList *listAddr, GSList * g_strchug( fullName ); g_strchomp( fullName ); } + if( nodeAddress ) { + person = addritem_create_item_person(); + addritem_person_set_common_name( person, fullName ); + addritem_person_set_first_name( person, firstName ); + addritem_person_set_last_name( person, lastName ); + addrcache_id_person( ldapServer->addressCache, person ); + addrcache_add_person( ldapServer->addressCache, person ); + } + // Add address item while( nodeAddress ) { - addrItem = mgu_create_address(); - if( fullName ) { - addrItem->name = g_strdup( fullName ); - } - else { - addrItem->name = g_strdup( "" ); - } - addrItem->address = g_strdup( nodeAddress->data ); - addrItem->remarks = g_strdup( "" ); - mgu_add_cache( ldapServer->addressCache, addrItem ); - + email = addritem_create_item_email(); + addritem_email_set_address( email, nodeAddress->data ); + addrcache_id_email( ldapServer->addressCache, email ); + addrcache_person_add_email( ldapServer->addressCache, person, email ); nodeAddress = g_slist_next( nodeAddress ); ldapServer->entriesRead++; } g_free( fullName ); fullName = firstName = lastName = NULL; - addrItem = NULL; + } /* * Add all attribute values to a list. */ -GSList *syldap_add_list_values( LDAP *ld, LDAPMessage *entry, char *attr ) { +static GSList *syldap_add_list_values( LDAP *ld, LDAPMessage *entry, char *attr ) { GSList *list = NULL; gint i; char **vals; @@ -396,7 +413,7 @@ GSList *syldap_add_list_values( LDAP *ld, LDAPMessage *entry, char *attr ) { /* * Add a single attribute value to a list. */ -GSList *syldap_add_single_value( LDAP *ld, LDAPMessage *entry, char *attr ) { +static GSList *syldap_add_single_value( LDAP *ld, LDAPMessage *entry, char *attr ) { GSList *list = NULL; char **vals; if( ( vals = ldap_get_values( ld, entry, attr ) ) != NULL ) { @@ -412,7 +429,7 @@ GSList *syldap_add_single_value( LDAP *ld, LDAPMessage *entry, char *attr ) { /* * Free linked lists of character strings. */ -void syldap_free_lists( GSList *listName, GSList *listAddr, GSList *listID, GSList *listDN, GSList *listFirst, GSList *listLast ) { +static void syldap_free_lists( GSList *listName, GSList *listAddr, GSList *listID, GSList *listDN, GSList *listFirst, GSList *listLast ) { mgu_free_list( listName ); mgu_free_list( listAddr ); mgu_free_list( listID ); @@ -534,7 +551,7 @@ gint syldap_search( SyldapServer *ldapServer ) { // Clear the cache if we have new entries, otherwise leave untouched. if( ldap_count_entries( ld, result ) > 0 ) { - mgu_clear_cache( ldapServer->addressCache ); + addrcache_clear( ldapServer->addressCache ); } // Process results @@ -607,6 +624,7 @@ gint syldap_search( SyldapServer *ldapServer ) { gint syldap_read_data( SyldapServer *ldapServer ) { g_return_if_fail( ldapServer != NULL ); + ldapServer->accessFlag = FALSE; pthread_detach( pthread_self() ); if( ldapServer->newSearch ) { // Read data into the list @@ -615,6 +633,7 @@ gint syldap_read_data( SyldapServer *ldapServer ) { // Mark cache ldapServer->addressCache->modified = FALSE; ldapServer->addressCache->dataRead = TRUE; + ldapServer->accessFlag = FALSE; } // Callback @@ -636,7 +655,7 @@ gint syldap_read_data( SyldapServer *ldapServer ) { void syldap_cancel_read( SyldapServer *ldapServer ) { g_return_if_fail( ldapServer != NULL ); if( ldapServer->thread ) { -printf( "thread cancelled\n" ); + // printf( "thread cancelled\n" ); pthread_cancel( *ldapServer->thread ); } ldapServer->thread = NULL; @@ -665,12 +684,21 @@ gint syldap_read_data_th( SyldapServer *ldapServer ) { } /* -* Return link list of address items. -* Return: TRUE if file read successfully. +* Return link list of persons. +*/ +GList *syldap_get_list_person( SyldapServer *ldapServer ) { + g_return_if_fail( ldapServer != NULL ); + return addrcache_get_list_person( ldapServer->addressCache ); +} + +/* +* Return link list of folders. This is always NULL since there are +* no folders in GnomeCard. +* Return: NULL. */ -GList *syldap_get_address_list( const SyldapServer *ldapServer ) { +GList *syldap_get_list_folder( SyldapServer *ldapServer ) { g_return_if_fail( ldapServer != NULL ); - return ldapServer->addressCache->addressList; + return NULL; } #define SYLDAP_TEST_FILTER "(objectclass=*)" diff --git a/src/syldap.h b/src/syldap.h index c9151d458..6396e9cf0 100644 --- a/src/syldap.h +++ b/src/syldap.h @@ -29,7 +29,8 @@ #include #include -#include "mgutils.h" +#include "addritem.h" +#include "addrcache.h" #define SYLDAP_DFL_PORT 389 #define SYLDAP_MAX_ENTRIES 20 @@ -46,51 +47,64 @@ // VCard object typedef struct _SyldapServer SyldapServer; struct _SyldapServer { - gchar *name; - gchar *hostName; - gint port; - gchar *baseDN; - gchar *bindDN; - gchar *bindPass; - gchar *searchCriteria; - gchar *searchValue; - gint entriesRead; - gint maxEntries; - gint timeOut; - gboolean newSearch; + gchar *name; + gchar *hostName; + gint port; + gchar *baseDN; + gchar *bindDN; + gchar *bindPass; + gchar *searchCriteria; + gchar *searchValue; + gint entriesRead; + gint maxEntries; + gint timeOut; + gboolean newSearch; AddressCache *addressCache; - gint retVal; - pthread_t *thread; - gboolean busyFlag; - void (*callBack)( void * ); + // ItemFolder *rootFolder; + gboolean accessFlag; + gint retVal; + pthread_t *thread; + gboolean busyFlag; + void (*callBack)( void * ); }; /* Function prototypes */ -void syldap_set_name( SyldapServer* ldapServer, const gchar *value ); -void syldap_set_host( SyldapServer* ldapServer, const gchar *value ); -void syldap_set_port( SyldapServer* ldapServer, const gint value ); -void syldap_set_base_dn( SyldapServer* ldapServer, const gchar *value ); -void syldap_set_bind_dn( SyldapServer* ldapServer, const gchar *value ); -void syldap_set_bind_password( SyldapServer* ldapServer, const gchar *value ); -void syldap_set_search_criteria( SyldapServer* ldapServer, const gchar *value ); -void syldap_set_search_value( SyldapServer* ldapServer, const gchar *value ); -void syldap_set_max_entries( SyldapServer* ldapServer, const gint value ); -void syldap_set_timeout( SyldapServer* ldapServer, const gint value ); -void syldap_set_callback( SyldapServer *ldapServer, void *func ); -void syldap_force_refresh( SyldapServer *ldapServer ); -SyldapServer *syldap_create(); -void syldap_free( SyldapServer *ldapServer ); -void syldap_print_data( SyldapServer *ldapServer, FILE *stream ); -gboolean syldap_check_search( SyldapServer *ldapServer ); -gint syldap_read_data( SyldapServer *ldapServer ); -gint syldap_read_data_th( SyldapServer *ldapServer ); -void syldap_cancel_read( SyldapServer *ldapServer ); -GList *syldap_get_address_list( const SyldapServer *ldapServer ); -GList *syldap_read_basedn_s( const gchar *host, const gint port, const gchar *bindDN, const gchar *bindPW, const gint tov ); -GList *syldap_read_basedn( SyldapServer *ldapServer ); -gboolean syldap_test_connect_s( const gchar *host, const gint port ); -gboolean syldap_test_connect( SyldapServer *ldapServer ); -gboolean syldap_test_ldap_lib(); +SyldapServer *syldap_create ( void ); +void syldap_set_name ( SyldapServer* ldapServer, const gchar *value ); +void syldap_set_host ( SyldapServer* ldapServer, const gchar *value ); +void syldap_set_port ( SyldapServer* ldapServer, const gint value ); +void syldap_set_base_dn ( SyldapServer* ldapServer, const gchar *value ); +void syldap_set_bind_dn ( SyldapServer* ldapServer, const gchar *value ); +void syldap_set_bind_password ( SyldapServer* ldapServer, const gchar *value ); +void syldap_set_search_criteria ( SyldapServer* ldapServer, const gchar *value ); +void syldap_set_search_value ( SyldapServer* ldapServer, const gchar *value ); +void syldap_set_max_entries ( SyldapServer* ldapServer, const gint value ); +void syldap_set_timeout ( SyldapServer* ldapServer, const gint value ); +void syldap_set_callback ( SyldapServer *ldapServer, void *func ); +void syldap_set_accessed ( SyldapServer *ldapServer, const gboolean value ); +void syldap_force_refresh ( SyldapServer *ldapServer ); +void syldap_free ( SyldapServer *ldapServer ); +gint syldap_get_status ( SyldapServer *ldapServer ); +gboolean syldap_get_accessed ( SyldapServer *ldapServer ); +gchar *syldap_get_name ( SyldapServer *ldapServer ); + +void syldap_print_data ( SyldapServer *ldapServer, FILE *stream ); +gboolean syldap_check_search ( SyldapServer *ldapServer ); +gint syldap_read_data ( SyldapServer *ldapServer ); +gint syldap_read_data_th ( SyldapServer *ldapServer ); +void syldap_cancel_read ( SyldapServer *ldapServer ); + +// GList *syldap_get_address_list ( const SyldapServer *ldapServer ); +ItemFolder *syldap_get_root_folder ( SyldapServer *ldapServer ); +GList *syldap_get_list_person ( SyldapServer *ldapServer ); +GList *syldap_get_list_folder ( SyldapServer *ldapServer ); + +GList *syldap_read_basedn_s ( const gchar *host, const gint port, const gchar *bindDN, + const gchar *bindPW, const gint tov ); +GList *syldap_read_basedn ( SyldapServer *ldapServer ); +gboolean syldap_test_connect_s ( const gchar *host, const gint port ); +gboolean syldap_test_connect ( SyldapServer *ldapServer ); +gboolean syldap_test_ldap_lib ( void ); #endif /* USE_LDAP */ diff --git a/src/textview.c b/src/textview.c index dbed263f1..1ab32234f 100644 --- a/src/textview.c +++ b/src/textview.c @@ -1271,7 +1271,8 @@ static void textview_button_pressed(GtkWidget *widget, GdkEventButton *event, fromname = procheader_get_fromname(fromaddress); extract_address(fromaddress); g_message("adding from textview %s <%s>", fromname, fromaddress); - addressbook_add_submenu(NULL, fromname, fromaddress, NULL); + // Add to address book - Match + addressbook_add_contact( fromname, fromaddress, NULL ); g_free(fromaddress); g_free(fromname); } else { diff --git a/src/vcard.c b/src/vcard.c index d9cf5230d..9f42c5808 100644 --- a/src/vcard.c +++ b/src/vcard.c @@ -28,6 +28,8 @@ #include "mgutils.h" #include "vcard.h" +#include "addritem.h" +#include "addrcache.h" #define GNOMECARD_DIR ".gnome" #define GNOMECARD_FILE "GnomeCard" @@ -37,47 +39,85 @@ #define VCARD_TEST_LINES 200 /* -* Specify name to be used. +* Create new cardfile object. */ -void vcard_set_name( VCardFile* cardFile, const gchar *name ) { - /* Copy file name */ - if( cardFile->name ) g_free( cardFile->name ); - if( name ) cardFile->name = g_strdup( name ); +VCardFile *vcard_create() { + VCardFile *cardFile; + cardFile = g_new0( VCardFile, 1 ); + cardFile->name = NULL; + cardFile->path = NULL; + cardFile->file = NULL; + cardFile->bufptr = cardFile->buffer; + cardFile->addressCache = addrcache_create(); + cardFile->retVal = MGU_SUCCESS; + cardFile->accessFlag = FALSE; + return cardFile; +} + +/* +* Properties... +*/ +void vcard_set_name( VCardFile* cardFile, const gchar *value ) { + g_return_if_fail( cardFile != NULL ); + cardFile->name = mgu_replace_string( cardFile->name, value ); g_strstrip( cardFile->name ); } +void vcard_set_file( VCardFile* cardFile, const gchar *value ) { + g_return_if_fail( cardFile != NULL ); + addrcache_refresh( cardFile->addressCache ); + cardFile->path = mgu_replace_string( cardFile->path, value ); + g_strstrip( cardFile->path ); +} +void vcard_set_accessed( VCardFile *cardFile, const gboolean value ) { + g_return_if_fail( cardFile != NULL ); + cardFile->accessFlag = value; +} /* -* Specify file to be used. +* Test whether file was modified since last access. +* Return: TRUE if file was modified. */ -void vcard_set_file( VCardFile* cardFile, const gchar *path ) { - mgu_refresh_cache( cardFile->addressCache ); +gboolean vcard_get_modified( VCardFile *vcardFile ) { + g_return_if_fail( vcardFile != NULL ); + return addrcache_check_file( vcardFile->addressCache, vcardFile->path ); +} +gboolean vcard_get_accessed( VCardFile *vcardFile ) { + g_return_if_fail( vcardFile != NULL ); + return addrcache_check_file( vcardFile->addressCache, vcardFile->path ); +} - /* Copy file path */ - if( cardFile->path ) g_free( cardFile->path ); - if( path ) cardFile->path = g_strdup( path ); - g_strstrip( cardFile->path ); +/* +* Test whether file was read. +* Return: TRUE if file was read. +*/ +gboolean vcard_get_read_flag( VCardFile *vcardFile ) { + g_return_if_fail( vcardFile != NULL ); + return vcardFile->addressCache->dataRead; } /* -* Create new cardfile object. +* Return status code from last file operation. +* Return: Status code. */ -VCardFile *vcard_create() { - VCardFile *cardFile; - cardFile = g_new( VCardFile, 1 ); - cardFile->name = NULL; - cardFile->path = NULL; - cardFile->file = NULL; - cardFile->bufptr = cardFile->buffer; - cardFile->addressCache = mgu_create_cache(); - cardFile->retVal = MGU_SUCCESS; - return cardFile; +gint vcard_get_status( VCardFile *cardFile ) { + g_return_if_fail( cardFile != NULL ); + return cardFile->retVal; +} + +ItemFolder *vcard_get_root_folder( VCardFile *cardFile ) { + g_return_if_fail( cardFile != NULL ); + return addrcache_get_root_folder( cardFile->addressCache ); +} +gchar *vcard_get_name( VCardFile *cardFile ) { + g_return_if_fail( cardFile != NULL ); + return cardFile->name; } /* * Refresh internal variables to force a file read. */ void vcard_force_refresh( VCardFile *cardFile ) { - mgu_refresh_cache( cardFile->addressCache ); + addrcache_refresh( cardFile->addressCache ); } /* @@ -96,8 +136,6 @@ VCardFile *vcard_create_path( const gchar *path ) { void vcard_free( VCardFile *cardFile ) { g_return_if_fail( cardFile != NULL ); - // fprintf( stdout, "freeing... VCardFile\n" ); - /* Close file */ if( cardFile->file ) fclose( cardFile->file ); @@ -106,8 +144,8 @@ void vcard_free( VCardFile *cardFile ) { g_free( cardFile->path ); /* Clear cache */ - mgu_clear_cache( cardFile->addressCache ); - mgu_free_cache( cardFile->addressCache ); + addrcache_clear( cardFile->addressCache ); + addrcache_free( cardFile->addressCache ); // Clear pointers cardFile->file = NULL; @@ -115,12 +153,11 @@ void vcard_free( VCardFile *cardFile ) { cardFile->path = NULL; cardFile->addressCache = NULL; cardFile->retVal = MGU_SUCCESS; + cardFile->accessFlag = FALSE; /* Now release file object */ g_free( cardFile ); - // fprintf( stdout, "freeing... VCardFile done\n" ); - } /* @@ -133,14 +170,15 @@ void vcard_print_file( VCardFile *cardFile, FILE *stream ) { fprintf( stream, " name: '%s'\n", cardFile->name ); fprintf( stream, "file spec: '%s'\n", cardFile->path ); fprintf( stream, " ret val: %d\n", cardFile->retVal ); - mgu_print_cache( cardFile->addressCache, stream ); + addrcache_print( cardFile->addressCache, stream ); + addritem_print_item_folder( cardFile->addressCache->rootFolder, stream ); } /* * Open file for read. * return: TRUE if file opened successfully. */ -gint vcard_open_file( VCardFile* cardFile ) { +static gint vcard_open_file( VCardFile* cardFile ) { g_return_if_fail( cardFile != NULL ); // fprintf( stdout, "Opening file\n" ); @@ -169,7 +207,7 @@ gint vcard_open_file( VCardFile* cardFile ) { /* * Close file. */ -void vcard_close_file( VCardFile *cardFile ) { +static void vcard_close_file( VCardFile *cardFile ) { g_return_if_fail( cardFile != NULL ); if( cardFile->file ) fclose( cardFile->file ); cardFile->file = NULL; @@ -179,7 +217,7 @@ void vcard_close_file( VCardFile *cardFile ) { * Read line of text from file. * Return: ptr to buffer where line starts. */ -gchar *vcard_read_line( VCardFile *cardFile ) { +static gchar *vcard_read_line( VCardFile *cardFile ) { while( *cardFile->bufptr == '\n' || *cardFile->bufptr == '\0' ) { if( fgets( cardFile->buffer, VCARDBUFSIZE, cardFile->file ) == NULL ) return NULL; @@ -193,7 +231,7 @@ gchar *vcard_read_line( VCardFile *cardFile ) { * Read line of text from file. * Return: ptr to buffer where line starts. */ -gchar *vcard_get_line( VCardFile *cardFile ) { +static gchar *vcard_get_line( VCardFile *cardFile ) { gchar buf[ VCARDBUFSIZE ]; gchar *start, *end; gint len; @@ -219,7 +257,7 @@ gchar *vcard_get_line( VCardFile *cardFile ) { /* * Free linked lists of character strings. */ -void vcard_free_lists( GSList *listName, GSList *listAddr, GSList *listRem, GSList* listID ) { +static void vcard_free_lists( GSList *listName, GSList *listAddr, GSList *listRem, GSList* listID ) { mgu_free_list( listName ); mgu_free_list( listAddr ); mgu_free_list( listRem ); @@ -231,7 +269,7 @@ void vcard_free_lists( GSList *listName, GSList *listAddr, GSList *listRem, GSLi * Param: cardFile - object. * Param: tagvalue - will be placed into the linked list. */ -gchar *vcard_read_qp( VCardFile *cardFile, char *tagvalue ) { +static gchar *vcard_read_qp( VCardFile *cardFile, char *tagvalue ) { GSList *listQP = NULL; gint len = 0; gchar *line = tagvalue; @@ -258,7 +296,7 @@ gchar *vcard_read_qp( VCardFile *cardFile, char *tagvalue ) { * Parse tag name from line buffer. * Return: Buffer containing the tag name, or NULL if no delimiter char found. */ -gchar *vcard_get_tagname( char* line, gchar dlm ) { +static gchar *vcard_get_tagname( char* line, gchar dlm ) { gint len = 0; gchar *tag = NULL; gchar *lptr = line; @@ -279,7 +317,7 @@ gchar *vcard_get_tagname( char* line, gchar dlm ) { * Return: Buffer containing the tag value. Empty string is returned if * no delimiter char found. */ -gchar *vcard_get_tagvalue( gchar* line, gchar dlm ) { +static gchar *vcard_get_tagvalue( gchar* line, gchar dlm ) { gchar *value = NULL; gchar *start = NULL; gchar *lptr; @@ -306,7 +344,7 @@ gchar *vcard_get_tagvalue( gchar* line, gchar dlm ) { /* * Dump linked lists of character strings (for debug). */ -void vcard_dump_lists( GSList *listName, GSList *listAddr, GSList *listRem, GSList *listID, FILE *stream ) { +static void vcard_dump_lists( GSList *listName, GSList *listAddr, GSList *listRem, GSList *listID, FILE *stream ) { fprintf( stream, "dump name\n" ); fprintf( stream, "------------\n" ); mgu_print_list( listName, stdout ); @@ -324,60 +362,54 @@ void vcard_dump_lists( GSList *listName, GSList *listAddr, GSList *listRem, GSLi /* * Build an address list entry and append to list of address items. */ -void vcard_build_items( VCardFile *cardFile, GSList *listName, GSList *listAddr, GSList *listRem, GSList *listID ) { - AddressItem *addrItem = NULL; +static void vcard_build_items( VCardFile *cardFile, GSList *listName, GSList *listAddr, GSList *listRem, + GSList *listID ) +{ GSList *nodeName = listName; GSList *nodeID = listID; + gchar *str; while( nodeName ) { GSList *nodeAddress = listAddr; GSList *nodeRemarks = listRem; + ItemPerson *person = addritem_create_item_person(); + addritem_person_set_common_name( person, nodeName->data ); while( nodeAddress ) { - addrItem = mgu_create_address(); - addrItem->name = g_strdup( nodeName->data ); - addrItem->address = g_strdup( nodeAddress->data ); - if( nodeRemarks ) { - if( nodeRemarks->data ) { - if( g_strcasecmp( nodeRemarks->data, "internet" ) == 0 ) { - // Trivially exclude this one (appears for most records) - addrItem->remarks = g_strdup( "" ); - } - else { - addrItem->remarks = g_strdup( nodeRemarks->data ); + str = nodeAddress->data; + if( *str != '\0' ) { + ItemEMail *email = addritem_create_item_email(); + addritem_email_set_address( email, str ); + str = nodeRemarks->data; + if( nodeRemarks ) { + if( str ) { + if( g_strcasecmp( str, "internet" ) != 0 ) { + if( *str != '\0' ) addritem_email_set_remarks( email, str ); + } } } - else { - addrItem->remarks = g_strdup( "" ); - } - } - else { - addrItem->remarks = g_strdup( "" ); - } -/* - if( nodeID ) { - if( nodeID->data ) { - addrItem->externalID = g_strdup( nodeID->data ); - } - else { - addrItem->externalID = g_strdup( "" ); - } + addrcache_id_email( cardFile->addressCache, email ); + addrcache_person_add_email( cardFile->addressCache, person, email ); } - else { - addrItem->externalID = g_strdup( "" ); - } -*/ - mgu_add_cache( cardFile->addressCache, addrItem ); - nodeAddress = g_slist_next( nodeAddress ); nodeRemarks = g_slist_next( nodeRemarks ); } + if( person->listEMail ) { + addrcache_id_person( cardFile->addressCache, person ); + addrcache_add_person( cardFile->addressCache, person ); + } + else { + addritem_free_item_person( person ); + } + if( nodeID ) { + str = nodeID->data; + addritem_person_set_external_id( person, str ); + } nodeName = g_slist_next( nodeName ); nodeID = g_slist_next( nodeID ); } - addrItem = NULL; } // Unescape characters in quoted-printable string. -void vcard_unescape_qp( gchar *value ) { +static void vcard_unescape_qp( gchar *value ) { gchar *ptr, *src, *dest; int d, v; char ch; @@ -419,7 +451,7 @@ void vcard_unescape_qp( gchar *value ) { } /* -* Read file into cache. +* Read file data into root folder. * Note that one VCard can have multiple E-Mail addresses (MAIL tags); * these are broken out into separate address items. An address item * is generated for the person identified by FN tag and each EMAIL tag. @@ -428,7 +460,7 @@ void vcard_unescape_qp( gchar *value ) { * entry to have multiple FN tags; this might not make sense. However, * it will generate duplicate address entries for each person listed. */ -void vcard_read_cache( VCardFile *cardFile ) { +static void vcard_read_file( VCardFile *cardFile ) { gchar *tagtemp = NULL, *tagname = NULL, *tagvalue = NULL, *tagtype = NULL, *tagrest = NULL; GSList *listName = NULL, *listAddress = NULL, *listRemarks = NULL, *listID = NULL; GSList *listQP = NULL; @@ -463,7 +495,8 @@ void vcard_read_cache( VCardFile *cardFile ) { // fprintf( stdout, "QUOTED-PRINTABLE !!! final\n>%s<\n", tagvalue ); } - if( g_strcasecmp( tagname, VCARD_TAG_START ) == 0 && g_strcasecmp( tagvalue, VCARD_NAME ) == 0 ) { + if( g_strcasecmp( tagname, VCARD_TAG_START ) == 0 && + g_strcasecmp( tagvalue, VCARD_NAME ) == 0 ) { // fprintf( stdout, "start card\n" ); vcard_free_lists( listName, listAddress, listRemarks, listID ); listName = listAddress = listRemarks = listID = NULL; @@ -481,7 +514,8 @@ void vcard_read_cache( VCardFile *cardFile ) { // fprintf( stdout, "- id: %s\n", tagvalue ); listID = g_slist_append( listID, g_strdup( tagvalue ) ); } - if( g_strcasecmp( tagname, VCARD_TAG_END ) == 0 && g_strcasecmp( tagvalue, VCARD_NAME ) == 0 ) { + if( g_strcasecmp( tagname, VCARD_TAG_END ) == 0 && + g_strcasecmp( tagvalue, VCARD_NAME ) == 0 ) { // VCard is complete // fprintf( stdout, "end card\n--\n" ); // vcard_dump_lists( listName, listAddress, listRemarks, listID, stdout ); @@ -510,16 +544,17 @@ void vcard_read_cache( VCardFile *cardFile ) { gint vcard_read_data( VCardFile *cardFile ) { g_return_if_fail( cardFile != NULL ); cardFile->retVal = MGU_SUCCESS; - if( mgu_check_file( cardFile->addressCache, cardFile->path ) ) { - mgu_clear_cache( cardFile->addressCache ); + cardFile->accessFlag = FALSE; + if( addrcache_check_file( cardFile->addressCache, cardFile->path ) ) { + addrcache_clear( cardFile->addressCache ); vcard_open_file( cardFile ); if( cardFile->retVal == MGU_SUCCESS ) { // Read data into the list - vcard_read_cache( cardFile ); + vcard_read_file( cardFile ); vcard_close_file( cardFile ); // Mark cache - mgu_mark_cache( cardFile->addressCache, cardFile->path ); + addrcache_mark_file( cardFile->addressCache, cardFile->path ); cardFile->addressCache->modified = FALSE; cardFile->addressCache->dataRead = TRUE; } @@ -528,12 +563,32 @@ gint vcard_read_data( VCardFile *cardFile ) { } /* -* Return link list of address items. -* Return: TRUE if file read successfully. +* Return link list of persons. */ -GList *vcard_get_address_list( VCardFile *cardFile ) { +GList *vcard_get_list_person( VCardFile *cardFile ) { g_return_if_fail( cardFile != NULL ); - return cardFile->addressCache->addressList; + return addrcache_get_list_person( cardFile->addressCache ); +} + +/* +* Return link list of folders. This is always NULL since there are +* no folders in GnomeCard. +* Return: NULL. +*/ +GList *vcard_get_list_folder( VCardFile *cardFile ) { + g_return_if_fail( cardFile != NULL ); + return NULL; +} + +/* +* Return link list of all persons. Note that the list contains references +* to items. Do *NOT* attempt to use the addrbook_free_xxx() functions... +* this will destroy the addressbook data! +* Return: List of items, or NULL if none. +*/ +GList *vcard_get_all_persons( VCardFile *cardFile ) { + g_return_if_fail( cardFile != NULL ); + return addrcache_get_all_persons( cardFile->addressCache ); } /* @@ -664,11 +719,12 @@ gint vcard_test_read_file( const gchar *fileSpec ) { tagvalue = vcard_read_qp( cardFile, tagvalue ); vcard_unescape_qp( tagvalue ); } - - if( g_strcasecmp( tagname, VCARD_TAG_START ) == 0 && g_strcasecmp( tagvalue, VCARD_NAME ) == 0 ) { + if( g_strcasecmp( tagname, VCARD_TAG_START ) == 0 && + g_strcasecmp( tagvalue, VCARD_NAME ) == 0 ) { haveStart = TRUE; } - if( g_strcasecmp( tagname, VCARD_TAG_END ) == 0 && g_strcasecmp( tagvalue, VCARD_NAME ) == 0 ) { + if( g_strcasecmp( tagname, VCARD_TAG_END ) == 0 && + g_strcasecmp( tagvalue, VCARD_NAME ) == 0 ) { // VCard is complete if( haveStart ) cardFile->retVal = MGU_SUCCESS; } @@ -689,3 +745,4 @@ gint vcard_test_read_file( const gchar *fileSpec ) { /* * End of Source. */ + diff --git a/src/vcard.h b/src/vcard.h index dd5e420d9..ced8c7cb1 100644 --- a/src/vcard.h +++ b/src/vcard.h @@ -26,11 +26,11 @@ #ifndef __VCARD_H__ #define __VCARD_H__ -#include #include #include -#include "mgutils.h" +#include "addritem.h" +#include "addrcache.h" #define VCARDBUFSIZE 1024 @@ -45,8 +45,8 @@ #define VCARD_TYPE_QP "quoted-printable" -#define VCARD_SEP_TAG ':' -#define VCARD_SEP_TYPE ';' +#define VCARD_SEP_TAG ':' +#define VCARD_SEP_TYPE ';' /* // Typical VCard entry: @@ -72,21 +72,35 @@ struct _VCardFile { gchar *name; FILE *file; gchar *path; - AddressCache *addressCache; gchar buffer[ VCARDBUFSIZE ]; gchar *bufptr; + AddressCache *addressCache; gint retVal; + gboolean accessFlag; }; -/* Function prototypes */ -VCardFile *vcard_create(); -VCardFile *vcard_create_path( const gchar *path ); -void vcard_force_refresh( VCardFile *cardFile ); -void vcard_free( VCardFile *cardFile ); -gint vcard_read_data( VCardFile *cardFile ); -GList *vcard_get_address_list( VCardFile *cardFile ); -gboolean vcard_validate( const VCardFile *cardFile ); -gchar *vcard_find_gnomecard( void ); -gint vcard_test_read_file( const gchar *fileSpec ); +// Function prototypes +VCardFile *vcard_create ( void ); +VCardFile *vcard_create_path ( const gchar *path ); +void vcard_set_name ( VCardFile* cardFile, const gchar *value ); +void vcard_set_file ( VCardFile* cardFile, const gchar *value ); +void vcard_set_modified ( VCardFile *vcardFile, const gboolean value ); +void vcard_set_accessed ( VCardFile *vcardFile, const gboolean value ); +gboolean vcard_get_modified ( VCardFile *vcardFile ); +gboolean vcard_get_accessed ( VCardFile *vcardFile ); +gboolean vcard_get_read_flag ( VCardFile *vcardFile ); +gint vcard_get_status ( VCardFile *cardFile ); +ItemFolder *vcard_get_root_folder ( VCardFile *cardFile ); +gchar *vcard_get_name ( VCardFile *cardFile ); +void vcard_free ( VCardFile *cardFile ); +void vcard_force_refresh ( VCardFile *cardFile ); +gint vcard_read_data ( VCardFile *cardFile ); +GList *vcard_get_list_person ( VCardFile *cardFile ); +GList *vcard_get_list_folder ( VCardFile *cardFile ); +GList *vcard_get_all_persons ( VCardFile *cardFile ); +gboolean vcard_validate ( const VCardFile *cardFile ); +gchar *vcard_find_gnomecard ( void ); +gint vcard_test_read_file ( const gchar *fileSpec ); #endif /* __VCARD_H__ */ + -- 2.25.1