[Evolution-hackers] ebook api plans for 1.6



As part of the work for 1.6 I'm going over all the ebook and pas apis to
try and make them a easier to use from outside evolution (in the ebook
case) and a easier to implement (in the pas case).  I've been focusing
most of my energy on the ebook front, since this will end up creating
the most work for me (rewriting all of the addressbook UI code to use
the new ebook api.)  All the work I've been doing is on the
"toshok_syncapi_branch" branch in addressbook/backend.

The plan is to keep the existing async object/listener architecture, but
present an api (e-book.h attached) that wraps it all up in a
synchronous, cancelable interface.  An async alternative similar to
what's there now will be present for people that really want to use that
style, but hopefully all of evolution-addressbook will switch over to
the synchronous api. hmm, actually do we even need/want the async
interface?

We're going to drop the libversit dependency altogether, in favor of the
rather simple (and extremely forgiving) vcard parser in e-vcard.[ch] 
We'll get vCard 3.0, and all of the niggling interop bugs should go
away.

The EBook api is pretty simple, and although I'm sure it'll take some
tweaking it's probably not too far from what it'll be in the end.  One
area that's causing me a little grief is the ECard/ECardSimple code.  I
want all of it gone, replaced with something simpler (probably leaning
more toward the ECardSimple api), and maybe something that makes
EDestination obsolete too.  I've written the beginnings of EContact
(I've attached e-contact.h and e-vcard.h, it's parent class) just to get
things going, but I'm having a hard time coming up with a way to address
lists of structured attributes (like ADR), and also a sane way to handle
attribute parameters.

Right now since EContact subclasses from EVCard you can step along all
the attributes of the vcard and then iterate over the parameters/values,
but I'd really rather not force people to do that.  At the same time I
don't really want make EContact use ECard's way of representing
parameters (integer constants OR'ed together), since that's not
extensible, and the idea is that not only evolution will be using this
api.

The test-ebook.c file I've attached gives a small example of using the
new synchronous api.  It iterates over the list of email addresses,
which are at present just a list of EVCardAttribute's.  Is this way of
doing things satisfactory?  Maybe add convenience functions to return
the first value of an attribute, so the "v && v->data ?..." stuff would
go away.  But then how to handle parameters?  We can already get a list
of the EVCardAttributeParam's from the EVCardAttribute, but I don't
really want to make people write glist code to iterate over them all.. 
maybe e_contact_get_labeled_attribute (EContact *, EContactField, const
char *label) will return the EVCardAttribute with "TYPE= label"?

any thoughts?  I'm less concerned about getting this right for
evolution, since we've already proven we're willing to work with rather
broken apis :)  I'm more concerned with it being useful for others.

Chris
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
 * The Evolution addressbook client object.
 *
 * Author:
 *   Chris Toshok (toshok ximian com)
 *
 * Copyright (C) 1999-2003, Ximian, Inc.
 */

#ifndef __E_BOOK_H__
#define __E_BOOK_H__

#include <glib.h>
#include <glib-object.h>

#include <ebook/e-contact.h>
#include <ebook/e-book-query.h>
#include <ebook/e-book-view.h>
#include <ebook/e-book-types.h>

#define E_TYPE_BOOK        (e_book_get_type ())
#define E_BOOK(o)          (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_BOOK, EBook))
#define E_BOOK_CLASS(k)    (G_TYPE_CHECK_CLASS_CAST ((k), E_TYPE_BOOK, EBookClass))
#define E_IS_BOOK(o)       (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_BOOK))
#define E_IS_BOOK_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_BOOK))
#define E_BOOK_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_BOOK, EBookClass))

G_BEGIN_DECLS

typedef struct _EBook        EBook;
typedef struct _EBookClass   EBookClass;
typedef struct _EBookPrivate EBookPrivate;

struct _EBook {
	GObject       parent;
	EBookPrivate *priv;
};

struct _EBookClass {
	GObjectClass parent;

	/*
	 * Signals.
	 */
	void (* writable_status) (EBook *book, gboolean writable);
	void (* backend_died)    (EBook *book);
};

/* Creating a new addressbook. */
EBook      *e_book_new                   (void);

/* loading arbitrary addressbooks */
EBookStatus e_book_load_uri              (EBook       *book,
					  const char  *uri);

EBookStatus e_book_unload_uri            (EBook       *book);

/* convenience function for loading the "local" contact folder */
EBookStatus e_book_load_local_addressbook (EBook *book);

EBookStatus e_book_get_supported_fields  (EBook       *book,
					  GList      **fields);

EBookStatus e_book_get_supported_auth_methods (EBook       *book,
					       GList      **auth_methods);

/* User authentication. */
EBookStatus e_book_authenticate_user     (EBook       *book,
					  const char  *user,
					  const char  *passwd,
					  const char  *auth_method);

/* Fetching contacts. */
EBookStatus e_book_get_contact           (EBook       *book,
					  const char  *id,
					  EContact   **contact);

/* Deleting contacts. */
EBookStatus e_book_remove_contact        (EBook       *book,
					  const char  *id);

EBookStatus e_book_remove_contacts       (EBook       *book,
					  GList       *id_list);

/* Adding contacts. */
EBookStatus e_book_add_contact           (EBook       *book,
					  EContact    *contact);

/* Modifying contacts. */
EBookStatus e_book_commit_contact        (EBook       *book,
					  EContact       *contact);

EBookStatus e_book_get_book_view         (EBook       *book,
					  EBookQuery  *query,
					  GList       *requested_fields,
					  int          max_results,
					  EBookView  **book_view);

EBookStatus e_book_get_contacts          (EBook       *book,
					  EBookQuery  *query,
					  GList       **contacts);

EBookStatus e_book_get_changes           (EBook       *book,
					  char        *changeid,
					  EBookView  **book_view);

const char *e_book_get_uri               (EBook       *book);

const char *e_book_get_static_capabilities (EBook       *book);
gboolean    e_book_check_static_capability (EBook       *book,
					    const char  *cap);

/* Cancel a pending operation. */
EBookStatus e_book_cancel                  (EBook *book);

GType     e_book_get_type                (void);

G_END_DECLS

#endif /* ! __E_BOOK_H__ */
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
 * Authors:
 *   Chris Toshok <toshok ximian com>
 *
 * Copyright (C) 2003 Ximian, Inc.
 */

#ifndef __E_CONTACT_H__
#define __E_CONTACT_H__

#include <time.h>
#include <glib-object.h>
#include <stdio.h>
#include <e-vcard.h>
#include <e-util/e-list.h>

#define E_TYPE_CONTACT            (e_contact_get_type ())
#define E_CONTACT(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_CONTACT, EContact))
#define E_CONTACT_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_CONTACT, EContactClass))
#define E_IS_CONTACT(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_CONTACT))
#define E_IS_CONTACT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), E_TYPE_CONTACT))
#define E_CONTACT_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_CONTACT, EContactClass))

typedef struct _EContact EContact;
typedef struct _EContactClass EContactClass;
typedef struct _EContactPrivate EContactPrivate;

typedef enum {
	E_CONTACT_UID = 1,    /* string field */

	E_CONTACT_FILE_AS,    /* string field */

	E_CONTACT_FULL_NAME,  /* string field */
	E_CONTACT_NAME,       /* structured field (EContactName) */
	E_CONTACT_GIVEN_NAME,  /* synthetic field */
	E_CONTACT_FAMILY_NAME, /* synthetic field */

	E_CONTACT_EMAIL,      /* Multi-valued */
	E_CONTACT_EMAIL_1,    /* synthetic field */
	E_CONTACT_EMAIL_2,    /* synthetic field */
	E_CONTACT_EMAIL_3,    /* synthetic field */

	E_CONTACT_ADDRESS,       /* Multi-valued */
	E_CONTACT_ADDRESS_HOME,  /* synthetic field */
	E_CONTACT_ADDRESS_WORK,  /* synthetic field */
	E_CONTACT_ADDRESS_OTHER, /* synthetic field */

	E_CONTACT_IM_AIM,     /* Multi-valued */
	E_CONTACT_IM_JABBER,  /* Multi-valued */
	E_CONTACT_IM_YAHOO,   /* Multi-valued */
	E_CONTACT_IM_MSN,     /* Multi-valued */

	E_CONTACT_FIELD_LAST
} EContactField;

typedef struct {
	char *family;
	char *given;
	char *additional;
	char *prefixes;
	char *suffixes;
} EContactName;

struct _EContact {
	EVCard parent;

	EContactPrivate *priv;
};

struct _EContactClass {
	EVCardClass parent_class;
};

GType                   e_contact_get_type (void);

EContact*               e_contact_new             (void);
EContact*               e_contact_new_from_vcard  (const char *vcard);

gpointer                e_contact_get             (EContact *contact, EContactField field_id);
void                    e_contact_set             (EContact *contact, EContactField field_id, gpointer value);

/* destructors for structured values */
void                    e_contact_name_free       (EContactName *name);


const char*             e_contact_field_name      (EContactField field_id);
const char*             e_contact_pretty_name     (EContactField field_id);


#endif /* __E_CONTACT_H__ */
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/* e-vcard.h
 *
 * Copyright (C) 2003 Ximian, Inc.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of version 2 of the GNU General Public
 * License as published by the Free Software Foundation.
 *
 * 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.
 *
 * Author: Chris Toshok (toshok ximian com)
 */

#ifndef _EVCARD_H
#define _EVCARD_H

#include <glib.h>
#include <glib-object.h>

#define EVC_UID     "UID"
#define EVC_FN      "FN"
#define EVC_N       "N"
#define EVC_ORG     "ORG"
#define EVC_URL     "URL"
#define EVC_VERSION "VERSION"
#define EVC_REV     "REV"
#define EVC_PRODID  "PRODID"
#define EVC_TYPE    "TYPE"
#define EVC_ADR     "ADR"
#define EVC_TEL     "TEL"
#define EVC_EMAIL   "EMAIL"

#define EVC_ENCODING "ENCODING"
#define EVC_QUOTEDPRINTABLE "QUOTED-PRINTABLE"

#define EVC_X_FILE_AS "X-EVOLUTION-FILE-AS"
#define EVC_X_AIM     "X-AIM"
#define EVC_X_JABBER  "X-JABBER"
#define EVC_X_YAHOO   "X-YAHOO"
#define EVC_X_MSN     "X-MSN"

#define E_TYPE_VCARD            (e_vcard_get_type ())
#define E_VCARD(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_VCARD, EVCard))
#define E_VCARD_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_VCARD, EVCardClass))
#define E_IS_VCARD(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_VCARD))
#define E_IS_VCARD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), E_TYPE_VCARD))
#define E_VCARD_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_VCARD, EVCardClass))

typedef struct _EVCard EVCard;
typedef struct _EVCardClass EVCardClass;
typedef struct _EVCardPrivate EVCardPrivate;
typedef struct _EVCardAttribute EVCardAttribute;
typedef struct _EVCardAttributeParam EVCardAttributeParam;

struct _EVCard {
	GObject parent;

	EVCardPrivate *priv;
};

struct _EVCardClass {
	GObjectClass parent_class;
};

GType   e_vcard_get_type                     (void);

void    e_vcard_construct                    (EVCard *evc, const char *str);
EVCard* e_vcard_new                          (void);
EVCard* e_vcard_new_from_string              (const char *str);

char*   e_vcard_to_string                    (EVCard *evc);
/* mostly for debugging */
void    e_vcard_dump_structure               (EVCard *evc);


/* attributes */
EVCardAttribute *e_vcard_attribute_new             (const char *attr_group, const char *attr_name);
void             e_vcard_attribute_free            (EVCardAttribute *attr);
EVCardAttribute *e_vcard_attribute_copy            (EVCardAttribute *attr);
void             e_vcard_remove_attribute          (EVCard *evcard, const char *attr_group, const char *attr_name);
void             e_vcard_add_attribute             (EVCard *evcard, EVCardAttribute *attr);
void             e_vcard_add_attribute_with_value  (EVCard *evcard, EVCardAttribute *attr, const char *value);
void             e_vcard_add_attribute_with_values (EVCard *evcard, EVCardAttribute *attr, ...);
void             e_vcard_attribute_add_value       (EVCardAttribute *attr, const char *value);
void             e_vcard_attribute_add_values      (EVCardAttribute *attr, ...);

/* attribute parameters */
EVCardAttributeParam* e_vcard_attribute_param_new             (const char *param_name);
void                  e_vcard_attribute_param_free            (EVCardAttributeParam *param);
EVCardAttributeParam* e_vcard_attribute_param_copy            (EVCardAttributeParam *param);
void                  e_vcard_attribute_add_param             (EVCardAttribute *attr, EVCardAttributeParam *param);
void                  e_vcard_attribute_add_param_with_value  (EVCardAttribute *attr,
							       EVCardAttributeParam *param, const char *value);
void                  e_vcard_attribute_add_param_with_values (EVCardAttribute *attr,
							       EVCardAttributeParam *param, ...);

void                  e_vcard_attribute_param_add_value       (EVCardAttributeParam *param,
							       const char *value);
void                  e_vcard_attribute_param_add_values      (EVCardAttributeParam *param,
							       ...);

/* EVCard* accessors.  nothing returned from these functions should be
   freed by the caller. */
GList*           e_vcard_get_attributes       (EVCard *evcard);
const char*      e_vcard_attribute_get_group  (EVCardAttribute *attr);
const char*      e_vcard_attribute_get_name   (EVCardAttribute *attr);
GList*           e_vcard_attribute_get_values (EVCardAttribute *attr);

GList*           e_vcard_attribute_get_params       (EVCardAttribute *attr);
const char*      e_vcard_attribute_param_get_name   (EVCardAttributeParam *param);
GList*           e_vcard_attribute_param_get_values (EVCardAttributeParam *param);


#endif /* _EVCARD_H */
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */

#include "e-book.h"
#include "e-card-simple.h"
#include <libgnome/gnome-init.h>
#include <bonobo/bonobo-main.h>
#include <pthread.h>
#include <stdlib.h>

static pthread_t mainloop_thread;

static void*
run_mainloop (void *data)
{
	bonobo_main();
}

static void
print_all_emails (EBook *book)
{
	EBookQuery *query;
	EBookStatus status;
	GList *cards, *c;


	/*
	  this should be:
	    query = e_book_query_field_exists (E_CARD_SIMPLE_FIELD_FULL_NAME);
	  but backends don't handle "exists" yet.
	*/
	query = e_book_query_field_test (E_CONTACT_FULL_NAME,
					 E_BOOK_QUERY_CONTAINS, "");

	status = e_book_get_contacts (book, query, &cards);

	e_book_query_unref (query);

	if (status != E_BOOK_STATUS_OK) {
		printf ("error getting card list\n");
		exit(0);
	}

	for (c = cards; c; c = c->next) {
		EContact *contact = E_CONTACT (c->data);
		char *file_as = e_contact_get (contact, E_CONTACT_FILE_AS);
		GList *emails, *e;

		printf ("Contact: %s\n", file_as);
		printf ("Email addresses:\n");
		emails = e_contact_get (contact, E_CONTACT_EMAIL);
		for (e = emails; e; e = e->next) {
			EVCardAttribute *attr = e->data;
			GList *values = e_vcard_attribute_get_values (attr);
			printf ("\t%s\n",  values && values->data ? (char*)values->data : "");
			e_vcard_attribute_free (attr);
		}
		g_list_free (emails);

		g_free (file_as);

		g_object_unref (contact);

		printf ("\n");
	}
	g_list_free (cards);
}

int
main (int argc, char **argv)
{
	EBook *book;
	EBookStatus status;

	gnome_program_init("test-ebook", "0.0", LIBGNOME_MODULE, argc, argv, NULL);

	if (bonobo_init (&argc, argv) == FALSE)
		g_error ("Could not initialize Bonobo");

	pthread_create(&mainloop_thread, NULL, run_mainloop, NULL);


	/*
	** the actual ebook foo
	*/

	book = e_book_new ();

	status = e_book_load_local_addressbook (book);
	if (status != E_BOOK_STATUS_OK) {
		printf ("failed to open local addressbook\n");
		exit(0);
	}

	print_all_emails (book);


	g_object_unref (book);

	bonobo_main_quit();

	return 0;
}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]