2036 lines
56 KiB
C
2036 lines
56 KiB
C
/*
|
|
* 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 book files.
|
|
*/
|
|
|
|
#include <glib.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <dirent.h>
|
|
#include <sys/stat.h>
|
|
#include <math.h>
|
|
#include <setjmp.h>
|
|
|
|
#include "xml.h"
|
|
#include "mgutils.h"
|
|
#include "addritem.h"
|
|
#include "addrcache.h"
|
|
#include "addrbook.h"
|
|
#include "adbookbase.h"
|
|
|
|
#ifndef DEV_STANDALONE
|
|
#include "prefs.h"
|
|
#include "codeconv.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;
|
|
|
|
book = g_new0( AddressBookFile, 1 );
|
|
book->type = ADBOOKTYPE_BOOK;
|
|
book->addressCache = addrcache_create();
|
|
book->retVal = MGU_SUCCESS;
|
|
book->path = NULL;
|
|
book->fileName = NULL;
|
|
book->maxValue = 0;
|
|
book->tempList = NULL;
|
|
book->tempHash = NULL;
|
|
book->addressCache->modified = TRUE;
|
|
return book;
|
|
}
|
|
|
|
/*
|
|
* Specify name to be used.
|
|
*/
|
|
void addrbook_set_name( AddressBookFile *book, const gchar *value ) {
|
|
g_return_if_fail( book != NULL );
|
|
addrcache_set_name( book->addressCache, value );
|
|
}
|
|
gchar *addrbook_get_name( AddressBookFile *book ) {
|
|
g_return_val_if_fail( book != NULL, NULL );
|
|
return addrcache_get_name( book->addressCache );
|
|
}
|
|
void addrbook_set_path( AddressBookFile *book, const gchar *value ) {
|
|
g_return_if_fail( book != NULL );
|
|
book->path = mgu_replace_string( book->path, value );
|
|
addrcache_set_dirty( book->addressCache, TRUE );
|
|
}
|
|
void addrbook_set_file( AddressBookFile *book, const gchar *value ) {
|
|
g_return_if_fail( book != NULL );
|
|
book->fileName = mgu_replace_string( book->fileName, value );
|
|
addrcache_set_dirty( book->addressCache, TRUE );
|
|
}
|
|
gboolean addrbook_get_modified( AddressBookFile *book ) {
|
|
g_return_val_if_fail( book != NULL, FALSE );
|
|
return book->addressCache->modified;
|
|
}
|
|
void addrbook_set_modified( AddressBookFile *book, const gboolean value ) {
|
|
g_return_if_fail( book != NULL );
|
|
book->addressCache->modified = value;
|
|
}
|
|
gboolean addrbook_get_accessed( AddressBookFile *book ) {
|
|
g_return_val_if_fail( book != NULL, FALSE );
|
|
return book->addressCache->accessFlag;
|
|
}
|
|
void addrbook_set_accessed( AddressBookFile *book, const gboolean value ) {
|
|
g_return_if_fail( book != NULL );
|
|
book->addressCache->accessFlag = value;
|
|
}
|
|
gboolean addrbook_get_read_flag( AddressBookFile *book ) {
|
|
g_return_val_if_fail( book != NULL, FALSE );
|
|
return book->addressCache->dataRead;
|
|
}
|
|
void addrbook_set_read_flag( AddressBookFile *book, const gboolean value ) {
|
|
g_return_if_fail( book != NULL );
|
|
book->addressCache->dataRead = value;
|
|
}
|
|
gint addrbook_get_status( AddressBookFile *book ) {
|
|
g_return_val_if_fail( book != NULL, -1 );
|
|
return book->retVal;
|
|
}
|
|
ItemFolder *addrbook_get_root_folder( AddressBookFile *book ) {
|
|
g_return_val_if_fail( book != NULL, NULL );
|
|
return addrcache_get_root_folder( book->addressCache );
|
|
}
|
|
GList *addrbook_get_list_folder( AddressBookFile *book ) {
|
|
g_return_val_if_fail( book != NULL, NULL );
|
|
return addrcache_get_list_folder( book->addressCache );
|
|
}
|
|
GList *addrbook_get_list_person( AddressBookFile *book ) {
|
|
g_return_val_if_fail( book != NULL, NULL );
|
|
return addrcache_get_list_person( book->addressCache );
|
|
}
|
|
gboolean addrbook_get_dirty( AddressBookFile *book ) {
|
|
g_return_val_if_fail( book != NULL, FALSE );
|
|
return addrcache_get_dirty( book->addressCache );
|
|
}
|
|
void addrbook_set_dirty( AddressBookFile *book, const gboolean value ) {
|
|
g_return_if_fail( book != NULL );
|
|
addrcache_set_dirty( book->addressCache, value );
|
|
}
|
|
|
|
/*
|
|
* Empty address book.
|
|
*/
|
|
void addrbook_empty_book( AddressBookFile *book ) {
|
|
g_return_if_fail( book != NULL );
|
|
|
|
/* Free up internal objects */
|
|
addrcache_clear( book->addressCache );
|
|
addrcache_set_dirty( book->addressCache, FALSE );
|
|
g_list_free( book->tempList );
|
|
|
|
/* Reset to initial state */
|
|
book->tempList = NULL;
|
|
book->tempHash = NULL;
|
|
book->addressCache->dataRead = FALSE;
|
|
book->addressCache->modified = FALSE;
|
|
book->addressCache->accessFlag = FALSE;
|
|
book->retVal = MGU_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Free address book.
|
|
*/
|
|
void addrbook_free_book( AddressBookFile *book ) {
|
|
g_return_if_fail( book != NULL );
|
|
|
|
/* Clear cache */
|
|
addrcache_clear( book->addressCache );
|
|
addrcache_free( book->addressCache );
|
|
|
|
/* Free up internal objects */
|
|
g_free( book->path );
|
|
g_free( book->fileName );
|
|
g_list_free( book->tempList );
|
|
|
|
book->path = NULL;
|
|
book->fileName = NULL;
|
|
book->maxValue = 0;
|
|
book->tempList = NULL;
|
|
book->tempHash = NULL;
|
|
|
|
book->type = ADBOOKTYPE_NONE;
|
|
book->addressCache = NULL;
|
|
book->retVal = MGU_SUCCESS;
|
|
|
|
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, "\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 ) {
|
|
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 ) {
|
|
g_return_val_if_fail( book != NULL, NULL );
|
|
return addrcache_remove_group( book->addressCache, group );
|
|
}
|
|
|
|
/*
|
|
* 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 ) {
|
|
g_return_val_if_fail( book != NULL, NULL );
|
|
return addrcache_remove_person( book->addressCache, person );
|
|
}
|
|
|
|
/*
|
|
* 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 ) {
|
|
g_return_val_if_fail( book != NULL, NULL );
|
|
return addrcache_person_remove_email( book->addressCache, person, email );
|
|
}
|
|
|
|
/* **********************************************************************
|
|
* 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 ); */
|
|
email = addrcache_get_email( book->addressCache, 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;
|
|
|
|
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;
|
|
|
|
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_val_if_fail( book != NULL, -1 );
|
|
|
|
/*
|
|
printf( "...addrbook_read_data :%s:\t:%s:\n", book->fileName,
|
|
addrcache_get_name( book->addressCache ) );
|
|
*/
|
|
|
|
fileSpec = g_strconcat( book->path, G_DIR_SEPARATOR_S, book->fileName, NULL );
|
|
book->retVal = MGU_OPEN_FILE;
|
|
addrcache_clear( book->addressCache );
|
|
book->addressCache->modified = FALSE;
|
|
book->addressCache->accessFlag = 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->addressCache->modified = FALSE;
|
|
book->addressCache->dataRead = TRUE;
|
|
addrcache_set_dirty( book->addressCache, 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( "</", fp );
|
|
fputs( name, 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 );
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 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 );
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 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_val_if_fail( book != NULL, -1 );
|
|
g_return_val_if_fail( newFile != NULL, -1 );
|
|
|
|
fileSpec = g_strconcat( book->path, G_DIR_SEPARATOR_S, newFile, NULL );
|
|
|
|
book->retVal = MGU_OPEN_FILE;
|
|
#ifdef DEV_STANDALONE
|
|
fp = fopen( fileSpec, "wb" );
|
|
g_free( fileSpec );
|
|
if( fp ) {
|
|
fputs( "<?xml version=\"1.0\" ?>\n", fp );
|
|
#else
|
|
pfile = prefs_write_open( fileSpec );
|
|
g_free( fileSpec );
|
|
if( pfile ) {
|
|
fp = pfile->fp;
|
|
fprintf( fp, "<?xml version=\"1.0\" encoding=\"%s\" ?>\n",
|
|
conv_get_current_charset_str() );
|
|
#endif
|
|
addrbook_write_elem_s( fp, 0, AB_ELTAG_ADDRESS_BOOK );
|
|
addrbook_write_attr( fp, AB_ATTAG_NAME, addrcache_get_name( book->addressCache ) );
|
|
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 );
|
|
|
|
/* Output all folders */
|
|
g_hash_table_foreach( book->addressCache->itemHash, addrbook_write_item_folder_vis, 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_val_if_fail( book != NULL, -1 );
|
|
|
|
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 ) {
|
|
addrcache_set_dirty( book->addressCache, 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_val_if_fail( book != NULL, NULL );
|
|
|
|
email = addritem_move_email_before( person, itemMove, itemTarget );
|
|
if( email ) {
|
|
addrcache_set_dirty( book->addressCache, 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_val_if_fail( book != NULL, NULL );
|
|
|
|
email = addritem_move_email_after( person, itemMove, itemTarget );
|
|
if( email ) {
|
|
addrcache_set_dirty( book->addressCache, TRUE );
|
|
}
|
|
return email;
|
|
}
|
|
|
|
/*
|
|
* Hash table visitor function for deletion of hashtable entries.
|
|
*/
|
|
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 List of new 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 *listDelete;
|
|
GList *listGroup;
|
|
|
|
g_return_if_fail( book != NULL );
|
|
g_return_if_fail( person != NULL );
|
|
|
|
/* Get groups where person's existing email addresses are 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 );
|
|
}
|
|
|
|
g_list_free( listRemove );
|
|
|
|
/* 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;
|
|
}
|
|
|
|
/* Remove old addresses from person and cache */
|
|
listDelete = NULL;
|
|
node = person->listEMail;
|
|
while( node ) {
|
|
ItemEMail *email = node->data;
|
|
|
|
if( addrcache_person_remove_email( book->addressCache, person, email ) ) {
|
|
addrcache_remove_email( book->addressCache, email );
|
|
}
|
|
listDelete = g_list_append( listDelete, email );
|
|
node = person->listEMail;
|
|
}
|
|
|
|
/* Add new address entries */
|
|
node = listEMail;
|
|
while( node ) {
|
|
ItemEMail *email = node->data;
|
|
|
|
if( ADDRITEM_ID(email) == NULL ) {
|
|
/* Allocate an ID for new address */
|
|
addrcache_id_email( book->addressCache, email );
|
|
}
|
|
addrcache_person_add_email( book->addressCache, person, email );
|
|
node = g_list_next( node );
|
|
}
|
|
|
|
addrcache_set_dirty( book->addressCache, TRUE );
|
|
|
|
/* Free up memory */
|
|
g_list_free( listEMail );
|
|
listEMail = NULL;
|
|
|
|
node = listDelete;
|
|
while( node ) {
|
|
ItemEMail *email = node->data;
|
|
|
|
addritem_free_item_email( email );
|
|
node = g_list_next( node );
|
|
}
|
|
g_list_free( listDelete );
|
|
listDelete = NULL;
|
|
|
|
}
|
|
|
|
/*
|
|
* 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_val_if_fail( book != NULL, 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 );
|
|
}
|
|
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 );
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 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_val_if_fail( book != NULL, 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 );
|
|
|
|
addrcache_set_dirty( book->addressCache, TRUE );
|
|
|
|
/* Remember old list */
|
|
oldData = group->listEMail;
|
|
group->listEMail = listEMail;
|
|
mgu_clear_list( oldData );
|
|
oldData = NULL;
|
|
}
|
|
|
|
/*
|
|
* 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_val_if_fail( book != NULL, 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;
|
|
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_val_if_fail( book != NULL, 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);
|
|
addrcache_set_dirty( book->addressCache, 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;
|
|
addrcache_set_dirty( book->addressCache, TRUE );
|
|
|
|
/* Free up old data */
|
|
addritem_free_list_attribute( oldData );
|
|
oldData = NULL;
|
|
|
|
}
|
|
|
|
/*
|
|
* 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 );
|
|
}
|
|
addrcache_set_dirty( book->addressCache, 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_val_if_fail( book != NULL, NULL );
|
|
|
|
f = addrcache_remove_folder( book->addressCache, folder );
|
|
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_val_if_fail( book != NULL, NULL );
|
|
|
|
f = addrcache_remove_folder_delete( book->addressCache, folder );
|
|
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_val_if_fail( book != NULL, 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 );
|
|
numbuf[ FILE_NUMDIGITS ] = '\0';
|
|
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;
|
|
g_snprintf( fmt, sizeof(fmt), "%%s%%0%dd%%s", FILE_NUMDIGITS );
|
|
g_snprintf( buf, sizeof(buf), fmt, ADDRBOOK_PREFIX, n, ADDRBOOK_SUFFIX );
|
|
return g_strdup( buf );
|
|
}
|
|
|
|
/* **********************************************************************
|
|
* Address book test functions...
|
|
* ***********************************************************************
|
|
*/
|
|
|
|
/*
|
|
* 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;
|
|
|
|
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;
|
|
|
|
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;
|
|
|
|
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;
|
|
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_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 );
|
|
}
|
|
}
|
|
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_val_if_fail( book != NULL, -1 );
|
|
|
|
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_val_if_fail( book != NULL, 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 )
|
|
{
|
|
g_return_val_if_fail( book != NULL, NULL );
|
|
return addrcache_add_contact( book->addressCache, folder, name, address, remarks );
|
|
}
|
|
|
|
/*
|
|
* Return file name for next address book file.
|
|
* Enter: book Address book.
|
|
* Return: File name, or NULL if could not create. This should be g_free()
|
|
* when done.
|
|
*/
|
|
gchar *addrbook_guess_next_file( AddressBookFile *book ) {
|
|
gchar *newFile = NULL;
|
|
GList *fileList = NULL;
|
|
gint fileNum = 1;
|
|
fileList = addrbook_get_bookfile_list( book );
|
|
if( fileList ) {
|
|
fileNum = 1 + book->maxValue;
|
|
}
|
|
newFile = addrbook_gen_new_file_name( fileNum );
|
|
g_list_free( fileList );
|
|
fileList = NULL;
|
|
return newFile;
|
|
}
|
|
|
|
/*
|
|
* End of Source.
|
|
*/
|
|
|
|
|