aboutsummaryrefslogtreecommitdiffstats
path: root/addressbook/backend/ebook
diff options
context:
space:
mode:
Diffstat (limited to 'addressbook/backend/ebook')
-rw-r--r--addressbook/backend/ebook/Makefile.am29
-rw-r--r--addressbook/backend/ebook/TODO2
-rw-r--r--addressbook/backend/ebook/e-book-listener.c432
-rw-r--r--addressbook/backend/ebook/e-book-listener.h83
-rw-r--r--addressbook/backend/ebook/e-book.c821
-rw-r--r--addressbook/backend/ebook/e-book.h89
-rw-r--r--addressbook/backend/ebook/e-card-pairs.h139
-rw-r--r--addressbook/backend/ebook/e-card-types.h246
-rw-r--r--addressbook/backend/ebook/e-card.c1856
-rw-r--r--addressbook/backend/ebook/e-card.h92
10 files changed, 3457 insertions, 332 deletions
diff --git a/addressbook/backend/ebook/Makefile.am b/addressbook/backend/ebook/Makefile.am
index e9e974b704..35cf59d537 100644
--- a/addressbook/backend/ebook/Makefile.am
+++ b/addressbook/backend/ebook/Makefile.am
@@ -1,3 +1,5 @@
+bin_PROGRAMS = test-card test-client
+
corbadir = $(sysconfdir)/CORBA/servers
CORBA_SOURCE = \
@@ -39,7 +41,8 @@ lib_LTLIBRARIES = libebook.la
libebook_la_SOURCES = \
$(CORBA_SOURCE) \
e-book-listener.c \
- e-book.c
+ e-book.c \
+ e-card.c
libebookincludedir = $(includedir)/backend
@@ -48,5 +51,29 @@ libebookinclude_HEADERS = \
e-book-listener.h \
e-card.h
+test_client_SOURCES = \
+ test-client.c
+
+test_client_LDADD = \
+ $(GTK_LIBS) \
+ $(GNOME_LIBDIR) \
+ $(GNOMEGNORBA_LIBS) \
+ $(INTLLIBS) \
+ -lbonobo \
+ $(ebook_libs) \
+ ../libversit/libversit.la
+
+test_card_SOURCES = \
+ test-card.c
+
+test_card_LDADD = \
+ $(GTK_LIBS) \
+ $(GNOME_LIBDIR) \
+ $(GNOMEGNORBA_LIBS) \
+ $(INTLLIBS) \
+ -lbonobo \
+ $(ebook_libs) \
+ ../libversit/libversit.la
+
BUILT_SOURCES = $(CORBA_SOURCE)
CLEANFILES += $(BUILT_SOURCES)
diff --git a/addressbook/backend/ebook/TODO b/addressbook/backend/ebook/TODO
new file mode 100644
index 0000000000..a69703cd92
--- /dev/null
+++ b/addressbook/backend/ebook/TODO
@@ -0,0 +1,2 @@
+* Make sure open_book_progress does not use the EBook op queue; make
+ sure it works.
diff --git a/addressbook/backend/ebook/e-book-listener.c b/addressbook/backend/ebook/e-book-listener.c
index b0e10fc90c..e1182981fe 100644
--- a/addressbook/backend/ebook/e-book-listener.c
+++ b/addressbook/backend/ebook/e-book-listener.c
@@ -1,20 +1,313 @@
/*
+ * Exports the BookListener interface. Maintains a queue of messages
+ * which come in on the interface.
+ *
* Author:
* Nat Friedman (nat@helixcode.com)
*
* Copyright 2000, Helix Code, Inc.
*/
-#include <e-book-listener.h>
+#include <gtk/gtksignal.h>
+ #include <e-book-listener.h>
+
+static EBookStatus e_book_listener_convert_status (Evolution_BookListener_CallStatus status);
+
+enum {
+ RESPONSES_QUEUED,
+ LAST_SIGNAL
+};
+
+static guint e_book_listener_signals [LAST_SIGNAL];
static GnomeObjectClass *e_book_listener_parent_class;
POA_Evolution_BookListener__vepv e_book_listener_vepv;
+struct _EBookListenerPrivate {
+ EBook *book;
+ GList *response_queue;
+ gint idle_id;
+};
+
+static gboolean
+e_book_listener_check_queue (EBookListener *listener)
+{
+ if (listener->priv->response_queue != NULL) {
+ gtk_signal_emit (GTK_OBJECT (listener),
+ e_book_listener_signals [RESPONSES_QUEUED]);
+ }
+
+ if (listener->priv->response_queue == NULL) {
+ listener->priv->idle_id = 0;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+e_book_listener_queue_response (EBookListener *listener,
+ EBookListenerResponse *response)
+{
+ listener->priv->response_queue =
+ g_list_append (listener->priv->response_queue,
+ response);
+
+ if (listener->priv->idle_id == 0) {
+ listener->priv->idle_id = g_idle_add (
+ (GSourceFunc) e_book_listener_check_queue, listener);
+ }
+}
+
+/* Add, Remove, Modify */
+static void
+e_book_listener_queue_generic_response (EBookListener *listener,
+ EBookListenerOperation op,
+ EBookStatus status)
+{
+ EBookListenerResponse *resp;
+
+ resp = g_new0 (EBookListenerResponse, 1);
+
+ resp->op = op;
+ resp->status = status;
+
+ e_book_listener_queue_response (listener, resp);
+}
+
+static void
+e_book_listener_queue_open_response (EBookListener *listener,
+ EBookStatus status,
+ Evolution_Book book)
+{
+ EBookListenerResponse *resp;
+
+ resp = g_new0 (EBookListenerResponse, 1);
+
+ resp->op = OpenBookResponse;
+ resp->status = status;
+ resp->book = book;
+
+ e_book_listener_queue_response (listener, resp);
+}
+
+static void
+e_book_listener_queue_open_progress (EBookListener *listener,
+ const char *msg,
+ short percent)
+{
+ EBookListenerResponse *resp;
+
+ resp = g_new0 (EBookListenerResponse, 1);
+
+ resp->op = OpenProgressEvent;
+ resp->msg = g_strdup (msg);
+ resp->percent = percent;
+
+ e_book_listener_queue_response (listener, resp);
+}
+
+
+static void
+e_book_listener_queue_link_status (EBookListener *listener,
+ gboolean connected)
+{
+ EBookListenerResponse *resp;
+
+ resp = g_new0 (EBookListenerResponse, 1);
+
+ resp->op = LinkStatusEvent;
+ resp->connected = connected;
+
+ e_book_listener_queue_response (listener, resp);
+}
+
+static void
+e_book_listener_queue_generic_event (EBookListener *listener,
+ EBookStatus status,
+ const char *id)
+{
+ EBookListenerResponse *resp;
+
+ resp = g_new0 (EBookListenerResponse, 1);
+
+ resp->op = LinkStatusEvent;
+ resp->status = status;
+ resp->id = g_strdup (id);
+
+ e_book_listener_queue_response (listener, resp);
+}
+
+static void
+impl_BookListener_respond_create_card (PortableServer_Servant servant,
+ const Evolution_BookListener_CallStatus status,
+ CORBA_Environment *ev)
+{
+ EBookListener *listener = E_BOOK_LISTENER (gnome_object_from_servant (servant));
+
+ e_book_listener_queue_generic_response (
+ listener, CreateCardResponse,
+ e_book_listener_convert_status (status));
+}
+
+static void
+impl_BookListener_respond_remove_card (PortableServer_Servant servant,
+ const Evolution_BookListener_CallStatus status,
+ CORBA_Environment *ev)
+{
+ EBookListener *listener = E_BOOK_LISTENER (gnome_object_from_servant (servant));
+
+ e_book_listener_queue_generic_response (
+ listener, RemoveCardResponse,
+ e_book_listener_convert_status (status));
+}
+
+static void
+impl_BookListener_respond_modify_card (PortableServer_Servant servant,
+ const Evolution_BookListener_CallStatus status,
+ CORBA_Environment *ev)
+{
+ EBookListener *listener = E_BOOK_LISTENER (gnome_object_from_servant (servant));
+
+ e_book_listener_queue_generic_response (
+ listener, ModifyCardResponse,
+ e_book_listener_convert_status (status));
+}
+
+static void
+impl_BookListener_respond_open_book (PortableServer_Servant servant,
+ const Evolution_BookListener_CallStatus status,
+ const Evolution_Book book,
+ CORBA_Environment *ev)
+{
+ EBookListener *listener = E_BOOK_LISTENER (gnome_object_from_servant (servant));
+ Evolution_Book book_copy;
+
+ book_copy = CORBA_Object_duplicate (book, ev);
+
+ if (ev->_major != CORBA_NO_EXCEPTION) {
+ g_warning ("EBookListener: Exception while duplicating Book!\n");
+ return;
+ }
+
+ e_book_listener_queue_open_response (
+ listener,
+ e_book_listener_convert_status (status),
+ book_copy);
+}
+
+static void
+impl_BookListener_report_open_book_progress (PortableServer_Servant servant,
+ const CORBA_char *status_message,
+ const CORBA_short percent,
+ CORBA_Environment *ev)
+{
+ EBookListener *listener = E_BOOK_LISTENER (gnome_object_from_servant (servant));
+
+ e_book_listener_queue_open_progress (
+ listener, status_message, percent);
+}
+
+static void
+impl_BookListener_report_connection_status (PortableServer_Servant servant,
+ const CORBA_boolean connected,
+ CORBA_Environment *ev)
+{
+ EBookListener *listener = E_BOOK_LISTENER (gnome_object_from_servant (servant));
+
+ e_book_listener_queue_link_status (
+ listener, connected);
+}
+
+static void
+impl_BookListener_signal_card_added (PortableServer_Servant servant,
+ const Evolution_CardId id,
+ CORBA_Environment *ev)
+{
+ EBookListener *listener = E_BOOK_LISTENER (gnome_object_from_servant (servant));
+
+ e_book_listener_queue_generic_event (
+ listener, CardAddedEvent, (const char *) id);
+}
+
+static void
+impl_BookListener_signal_card_removed (PortableServer_Servant servant,
+ const Evolution_CardId id,
+ CORBA_Environment *ev)
+{
+ EBookListener *listener = E_BOOK_LISTENER (gnome_object_from_servant (servant));
+
+ e_book_listener_queue_generic_event (
+ listener, CardRemovedEvent, (const char *) id);
+}
+
+static void
+impl_BookListener_signal_card_changed (PortableServer_Servant servant,
+ const Evolution_CardId id,
+ CORBA_Environment *ev)
+{
+ EBookListener *listener = E_BOOK_LISTENER (gnome_object_from_servant (servant));
+
+ e_book_listener_queue_generic_event (
+ listener, CardModifiedEvent, (const char *) id);
+}
+
+/**
+ * e_book_listener_get_book:
+ */
+EBook *
+e_book_listener_get_book (EBookListener *listener)
+{
+ g_return_val_if_fail (listener != NULL, NULL);
+ g_return_val_if_fail (E_IS_BOOK_LISTENER (listener), NULL);
+
+ return listener->priv->book;
+}
+
+/**
+ * e_book_listener_check_pending:
+ */
+int
+e_book_listener_check_pending (EBookListener *listener)
+{
+ g_return_val_if_fail (listener != NULL, -1);
+ g_return_val_if_fail (E_IS_BOOK_LISTENER (listener), -1);
+
+ return g_list_length (listener->priv->response_queue);
+}
+
+/**
+ * e_book_listener_pop_response:
+ */
+EBookListenerResponse *
+e_book_listener_pop_response (EBookListener *listener)
+{
+ EBookListenerResponse *resp;
+ GList *popped;
+
+ g_return_val_if_fail (listener != NULL, NULL);
+ g_return_val_if_fail (E_IS_BOOK_LISTENER (listener), NULL);
+
+ if (listener->priv->response_queue == NULL)
+ return NULL;
+
+ resp = listener->priv->response_queue->data;
+
+ popped = listener->priv->response_queue;
+ listener->priv->response_queue =
+ g_list_remove_link (listener->priv->response_queue,
+ listener->priv->response_queue);
+ g_list_free_1 (popped);
+
+ return resp;
+}
+
static EBookStatus
e_book_listener_convert_status (const Evolution_BookListener_CallStatus status)
{
switch (status) {
-
+ case Evolution_BookListener_Success:
+ return E_BOOK_STATUS_SUCCESS;
case Evolution_BookListener_RepositoryOffline:
return E_BOOK_STATUS_REPOSITORY_OFFLINE;
case Evolution_BookListener_PermissionDenied:
@@ -41,7 +334,7 @@ e_book_listener_construct (EBookListener *listener, EBook *book)
g_assert (book != NULL);
g_assert (E_IS_BOOK (book));
- listener->book = book;
+ listener->priv->book = book;
servant = (POA_Evolution_BookListener *) g_new0 (GnomeObjectServant, 1);
servant->vepv = &e_book_listener_vepv;
@@ -97,112 +390,45 @@ e_book_listener_new (EBook *book)
}
static void
-impl_BookListener_respond_create_card (PortableServer_Servant servant,
- const Evolution_BookListener_CallStatus status,
- CORBA_Environment *ev)
+e_book_listener_init (EBookListener *listener)
{
- EBookListener *listener = E_BOOK_LISTENER (gnome_object_from_servant (servant));
-
- if (listener->create_response == NULL)
- return;
-
- (listener->create_response) (listener->book,
- e_book_listener_convert_status (status),
- listener->closure);
+ listener->priv = g_new0 (EBookListenerPrivate, 1);
}
static void
-impl_BookListener_respond_remove_card (PortableServer_Servant servant,
- const Evolution_BookListener_CallStatus status,
- CORBA_Environment *ev)
-{
- EBookListener *listener = E_BOOK_LISTENER (gnome_object_from_servant (servant));
-
- if (listener->remove_response == NULL)
- return;
-
- (listener->remove_response) (listener->book,
- e_book_listener_convert_status (status),
- listener->closure);
-}
-
-static void
-impl_BookListener_respond_modify_card (PortableServer_Servant servant,
- const Evolution_BookListener_CallStatus status,
- CORBA_Environment *ev)
-{
- EBookListener *listener = E_BOOK_LISTENER (gnome_object_from_servant (servant));
-
- if (listener->modify_response == NULL)
- return;
-
- (listener->modify_response) (listener->book,
- e_book_listener_convert_status (status),
- listener->closure);
-}
-
-static void
-impl_BookListener_report_open_book_progress (PortableServer_Servant servant,
- const CORBA_char *status_message,
- const CORBA_short percent,
- CORBA_Environment *ev)
-{
- EBookListener *listener = E_BOOK_LISTENER (gnome_object_from_servant (servant));
-
- if (listener->open_progress == NULL)
- return;
-
- (listener->open_progress) (listener->book,
- status_message,
- percent,
- listener->closure);
-}
-
-static void
-impl_BookListener_respond_open_book (PortableServer_Servant servant,
- const Evolution_BookListener_CallStatus status,
- const Evolution_Book book,
- CORBA_Environment *ev)
+e_book_listener_destroy (GtkObject *object)
{
- EBookListener *listener = E_BOOK_LISTENER (gnome_object_from_servant (servant));
-
- if (listener->open_response == NULL)
- return;
-
- (listener->open_response) (listener->book,
- e_book_listener_convert_status (status),
- book,
- listener->closure);
-}
-
+ EBookListener *listener = E_BOOK_LISTENER (object);
+ GList *l;
-static void
-impl_BookListener_report_connection_status (PortableServer_Servant servant,
- const CORBA_boolean connected,
- CORBA_Environment *ev)
-{
- EBookListener *listener = E_BOOK_LISTENER (gnome_object_from_servant (servant));
+ for (l = listener->priv->response_queue; l != NULL; l = l->next) {
+ EBookListenerResponse *resp = l->data;
- if (listener->connect_status == NULL)
- return;
+ g_free (resp->msg);
+ g_free (resp->id);
- (listener->connect_status) (listener->book, connected, listener->closure);
-}
+ if (resp->book != CORBA_OBJECT_NIL) {
+ CORBA_Environment ev;
+ CORBA_exception_init (&ev);
-static void
-e_book_listener_init (EBook *listener)
-{
-}
+ CORBA_Object_release (resp->book, &ev);
-static void
-e_book_listener_destroy (GtkObject *object)
-{
- EBookListener *listener = E_BOOK_LISTENER (object);
- CORBA_Environment ev;
+ if (ev._major != CORBA_NO_EXCEPTION) {
+ g_warning ("e_book_listener_destroy: "
+ "Exception destroying book "
+ "in response queue!\n");
+ }
+
+ CORBA_exception_free (&ev);
+ }
- CORBA_exception_init (&ev);
+ g_free (resp);
+ }
+ g_list_free (listener->priv->response_queue);
+ g_free (listener->priv);
+
GTK_OBJECT_CLASS (e_book_listener_parent_class)->destroy (object);
}
@@ -222,6 +448,10 @@ e_book_listener_get_epv (void)
epv->report_connection_status = impl_BookListener_report_connection_status;
+ epv->signal_card_changed = impl_BookListener_signal_card_changed;
+ epv->signal_card_removed = impl_BookListener_signal_card_removed;
+ epv->signal_card_added = impl_BookListener_signal_card_added;
+
return epv;
}
@@ -239,6 +469,16 @@ e_book_listener_class_init (EBookListenerClass *klass)
e_book_listener_parent_class = gtk_type_class (gnome_object_get_type ());
+ e_book_listener_signals [RESPONSES_QUEUED] =
+ gtk_signal_new ("responses_queued",
+ GTK_RUN_LAST,
+ object_class->type,
+ GTK_SIGNAL_OFFSET (EBookListenerClass, responses_queued),
+ gtk_marshal_NONE__NONE,
+ GTK_TYPE_NONE, 0);
+
+ gtk_object_class_add_signals (object_class, e_book_listener_signals, LAST_SIGNAL);
+
object_class->destroy = e_book_listener_destroy;
e_book_listener_corba_class_init ();
diff --git a/addressbook/backend/ebook/e-book-listener.h b/addressbook/backend/ebook/e-book-listener.h
index 71004a966a..9873edc58c 100644
--- a/addressbook/backend/ebook/e-book-listener.h
+++ b/addressbook/backend/ebook/e-book-listener.h
@@ -12,47 +12,70 @@
#define __E_BOOK_LISTENER_H__
#include <libgnome/gnome-defs.h>
-
#include <bonobo/gnome-object.h>
#include <e-book.h>
-
#include <addressbook.h>
BEGIN_GNOME_DECLS
-typedef struct _EBookListener EBookListener;
-
-typedef void (*EBookListenerRespondOpenBookCallback) (EBook *book,
- EBookStatus status,
- Evolution_Book corba_book,
- gpointer closure);
-
-typedef void (*EBookListenerConnectionStatusCallback) (EBook *book,
- gboolean connected,
- gpointer closure);
-
-struct _EBookListener {
- GnomeObject parent;
-
- EBook *book;
-
- gpointer closure;
-
- EBookCallback create_response;
- EBookCallback remove_response;
- EBookCallback modify_response;
-
- EBookOpenProgressCallback open_progress;
- EBookListenerRespondOpenBookCallback open_response;
- EBookListenerConnectionStatusCallback connect_status;
-};
+typedef struct _EBookListenerPrivate EBookListenerPrivate;
+
+typedef struct {
+ GnomeObject parent;
+ EBookListenerPrivate *priv;
+} EBookListener;
typedef struct {
GnomeObjectClass parent;
+
+ /*
+ * Signals
+ */
+ void (*responses_queued) (void);
} EBookListenerClass;
-EBookListener *e_book_listener_new (EBook *book);
-GtkType e_book_listener_get_type (void);
+typedef enum {
+ /* Async responses */
+ OpenBookResponse,
+ CreateCardResponse,
+ RemoveCardResponse,
+ ModifyCardResponse,
+
+ /* Async events */
+ CardAddedEvent,
+ CardRemovedEvent,
+ CardModifiedEvent,
+ LinkStatusEvent,
+ OpenProgressEvent,
+} EBookListenerOperation;
+
+typedef struct {
+ EBookListenerOperation op;
+
+ /* For most Response notifications */
+ EBookStatus status;
+
+ /* For OpenBookResponse */
+ Evolution_Book book;
+
+ /* For OpenProgressEvent */
+ char *msg;
+ short percent;
+
+ /* For LinkStatusEvent */
+ gboolean connected;
+
+ /* For Card[Added|Removed|Modified]Event */
+ char *id;
+} EBookListenerResponse;
+
+EBookListener *e_book_listener_new (EBook *book);
+EBook *e_book_listener_get_book (EBookListener *listener);
+int e_book_listener_check_pending (EBookListener *listener);
+EBookListenerResponse *e_book_listener_pop_response (EBookListener *listener);
+GtkType e_book_listener_get_type (void);
+
+POA_Evolution_BookListener__epv *e_book_listener_get_epv (void);
#define E_BOOK_LISTENER_TYPE (e_book_listener_get_type ())
#define E_BOOK_LISTENER(o) (GTK_CHECK_CAST ((o), E_BOOK_LISTENER_TYPE, EBookListener))
diff --git a/addressbook/backend/ebook/e-book.c b/addressbook/backend/ebook/e-book.c
index 80d5173231..460f73b56e 100644
--- a/addressbook/backend/ebook/e-book.c
+++ b/addressbook/backend/ebook/e-book.c
@@ -8,28 +8,41 @@
*/
#include <addressbook.h>
+#include <libgnorba/gnorba.h>
+#include <gtk/gtksignal.h>
+#include <gtk/gtkmarshal.h>
#include <e-card-cursor.h>
#include <e-book-listener.h>
#include <e-book.h>
-#include <gtk/gtksignal.h>
-#include <gtk/gtkmarshal.h>
+GtkObjectClass *e_book_parent_class;
-GnomeObjectClass *e_book_parent_class;
+#define CARDSERVER_GOAD_ID "evolution:card-server"
-#define CARDSERVER_GOAD_ID "FIXME"
+typedef enum {
+ URINotLoaded,
+ URILoading,
+ URILoaded
+} EBookLoadState;
struct _EBookPrivate {
Evolution_BookFactory book_factory;
EBookListener *listener;
- gboolean operation_pending;
+ Evolution_Book corba_book;
- EBookCallback open_response;
- gpointer closure;
+ EBookLoadState load_state;
+
+ /*
+ * The operation queue. New operations are appended to the
+ * end of the queue. When responses come back from the PAS,
+ * the op structures are popped off the front of the queue.
+ */
+ GList *pending_ops;
};
enum {
+ OPEN_PROGRESS,
CARD_CHANGED,
CARD_REMOVED,
CARD_ADDED,
@@ -39,17 +52,292 @@ enum {
static guint e_book_signals [LAST_SIGNAL];
-static EBook *
-e_book_construct (EBook *book,
- const char *uri,
- EBookOpenProgressCallback progress_cb,
- EBookCallback open_response,
- gpointer closure)
+typedef struct {
+ gpointer cb;
+ gpointer closure;
+} EBookOp;
+
+/*
+ * Local response queue management.
+ */
+static void
+e_book_queue_op (EBook *book,
+ gpointer cb,
+ gpointer closure)
+{
+ EBookOp *op;
+
+ op = g_new0 (EBookOp, 1);
+ op->cb = cb;
+ op->closure = closure;
+
+ book->priv->pending_ops =
+ g_list_append (book->priv->pending_ops, op);
+}
+
+static EBookOp *
+e_book_pop_op (EBook *book)
+{
+ GList *popped;
+ EBookOp *op;
+
+ if (book->priv->pending_ops == NULL)
+ return NULL;
+
+ op = book->priv->pending_ops->data;
+
+ popped = book->priv->pending_ops;
+ book->priv->pending_ops =
+ g_list_remove_link (book->priv->pending_ops, (gpointer) op);
+
+ g_list_free_1 (popped);
+
+ return op;
+}
+
+static void
+e_book_do_response_generic (EBook *book,
+ EBookListenerResponse *resp)
+{
+ EBookOp *op;
+
+ op = e_book_pop_op (book);
+
+ if (op == NULL) {
+ g_warning ("e_book_do_response_generic: Cannot find operation "
+ "in local op queue!\n");
+ }
+
+ ((EBookCallback) op->cb) (book, resp->status, op->closure);
+
+ g_free (op);
+}
+
+static void
+e_book_do_response_open (EBook *book,
+ EBookListenerResponse *resp)
+{
+ EBookOp *op;
+
+ if (resp->status == E_BOOK_STATUS_SUCCESS) {
+ book->priv->corba_book = resp->book;
+ book->priv->load_state = URILoaded;
+ }
+
+ op = e_book_pop_op (book);
+
+ if (op == NULL) {
+ g_warning ("e_book_do_response_open: Cannot find operation "
+ "in local op queue!\n");
+ return;
+ }
+
+ ((EBookCallback) op->cb) (book, resp->status, op->closure);
+ g_free (op);
+}
+
+static void
+e_book_do_progress_event (EBook *book,
+ EBookListenerResponse *resp)
+{
+ gtk_signal_emit (GTK_OBJECT (book), e_book_signals [OPEN_PROGRESS],
+ resp->msg, resp->percent);
+
+ g_free (resp->msg);
+}
+
+static void
+e_book_do_link_event (EBook *book,
+ EBookListenerResponse *resp)
+{
+ gtk_signal_emit (GTK_OBJECT (book), e_book_signals [LINK_STATUS],
+ resp->connected);
+}
+
+static void
+e_book_do_added_event (EBook *book,
+ EBookListenerResponse *resp)
+{
+ gtk_signal_emit (GTK_OBJECT (book), e_book_signals [CARD_ADDED],
+ resp->id);
+
+ g_free (resp->id);
+}
+
+static void
+e_book_do_modified_event (EBook *book,
+ EBookListenerResponse *resp)
+{
+ gtk_signal_emit (GTK_OBJECT (book), e_book_signals [CARD_CHANGED],
+ resp->id);
+
+ g_free (resp->id);
+}
+
+static void
+e_book_do_removed_event (EBook *book,
+ EBookListenerResponse *resp)
+{
+ gtk_signal_emit (GTK_OBJECT (book), e_book_signals [CARD_REMOVED],
+ resp->id);
+
+ g_free (resp->id);
+}
+
+
+/*
+ * Reading notices out of the EBookListener's queue.
+ */
+static void
+e_book_check_listener_queue (EBookListener *listener)
+{
+ EBook *book;
+ EBookListenerResponse *resp;
+
+ book = e_book_listener_get_book (listener);
+ g_assert (book != NULL);
+
+ resp = e_book_listener_pop_response (listener);
+
+ if (resp == NULL)
+ return;
+
+ switch (resp->op) {
+ case CreateCardResponse:
+ case RemoveCardResponse:
+ case ModifyCardResponse:
+ e_book_do_response_generic (book, resp);
+ break;
+ case OpenBookResponse:
+ e_book_do_response_open (book, resp);
+ break;
+
+ case OpenProgressEvent:
+ e_book_do_progress_event (book, resp);
+ break;
+ case LinkStatusEvent:
+ e_book_do_link_event (book, resp);
+ break;
+ case CardAddedEvent:
+ e_book_do_added_event (book, resp);
+ break;
+ case CardModifiedEvent:
+ e_book_do_modified_event (book, resp);
+ break;
+ case CardRemovedEvent:
+ e_book_do_removed_event (book, resp);
+ break;
+ default:
+ g_error ("EBook: Unknown operation %d in listener queue!\n",
+ resp->op);
+ }
+
+ g_free (resp);
+}
+
+/**
+ * e_book_load_uri:
+ */
+gboolean
+e_book_load_uri (EBook *book,
+ const char *uri,
+ EBookCallback open_response,
+ gpointer closure)
{
CORBA_Environment ev;
- g_return_val_if_fail (book != NULL, NULL);
- g_assert (uri != NULL);
+ g_return_val_if_fail (book != NULL, FALSE);
+ g_return_val_if_fail (E_IS_BOOK (book), FALSE);
+ g_return_val_if_fail (uri != NULL, FALSE);
+ g_return_val_if_fail (open_response != NULL, FALSE);
+
+ if (book->priv->load_state != URINotLoaded) {
+ g_warning ("e_book_load_uri: Attempted to load a URI "
+ "on a book which already has a URI loaded!\n");
+ return FALSE;
+ }
+
+ /*
+ * Load the addressbook into the PAS.
+ */
+ CORBA_exception_init (&ev);
+
+ Evolution_BookFactory_open_book (
+ book->priv->book_factory, uri,
+ gnome_object_corba_objref (GNOME_OBJECT (book->priv->listener)),
+ &ev);
+
+ if (ev._major != CORBA_NO_EXCEPTION) {
+ g_warning ("e_book_load_uri: CORBA exception while opening addressbook!\n");
+ CORBA_exception_free (&ev);
+ return FALSE;
+ }
+
+ CORBA_exception_free (&ev);
+
+ book->priv->load_state = URILoading;
+
+ e_book_queue_op (book, open_response, closure);
+
+ /* Now we play the waiting game. */
+
+ return TRUE;
+}
+
+/**
+ * e_book_unload_uri:
+ */
+void
+e_book_unload_uri (EBook *book)
+{
+ CORBA_Environment ev;
+
+ g_return_if_fail (book != NULL);
+ g_return_if_fail (E_IS_BOOK (book));
+
+ /*
+ * FIXME: Make sure this works if the URI is still being
+ * loaded.
+ */
+ if (book->priv->load_state == URINotLoaded) {
+ g_warning ("e_book_unload_uri: No URI is loaded!\n");
+ return;
+ }
+
+ /*
+ * Release the remote Evolution_Book in the PAS.
+ */
+ CORBA_exception_init (&ev);
+
+ GNOME_Unknown_unref (book->priv->corba_book, &ev);
+
+ if (ev._major != CORBA_NO_EXCEPTION) {
+ g_warning ("e_book_unload_uri: Exception unref'ing "
+ "remote Evolution_Book interface!\n");
+ CORBA_exception_free (&ev);
+ CORBA_exception_init (&ev);
+ }
+
+ CORBA_Object_release (book->priv->corba_book, &ev);
+
+ if (ev._major != CORBA_NO_EXCEPTION) {
+ g_warning ("e_book_unload_uri: Exception releasing "
+ "remote book interface!\n");
+ }
+
+ CORBA_exception_free (&ev);
+
+ gtk_object_unref (GTK_OBJECT (book->priv->listener));
+
+ book->priv->listener = NULL;
+ book->priv->load_state = URINotLoaded;
+}
+
+static gboolean
+e_book_construct (EBook *book)
+{
+ g_return_val_if_fail (book != NULL, FALSE);
+ g_return_val_if_fail (E_IS_BOOK (book), FALSE);
/*
* Connect to the Personal Addressbook Server.
@@ -60,7 +348,7 @@ e_book_construct (EBook *book,
if (book->priv->book_factory == CORBA_OBJECT_NIL) {
g_warning ("e_book_construct: Could not obtain a handle "
"to the Personal Addressbook Server!\n");
- return NULL;
+ return FALSE;
}
/*
@@ -69,71 +357,418 @@ e_book_construct (EBook *book,
book->priv->listener = e_book_listener_new (book);
if (book->priv->listener == NULL) {
g_warning ("e_book_construct: Could not create EBookListener!\n");
+ return FALSE;
+ }
+
+ gtk_signal_connect (GTK_OBJECT (book->priv->listener), "responses_queued",
+ e_book_check_listener_queue, NULL);
+
+ return TRUE;
+}
+
+/**
+ * e_book_new:
+ */
+EBook *
+e_book_new (void)
+{
+ EBook *book;
+
+ book = gtk_type_new (E_BOOK_TYPE);
+
+ if (! e_book_construct (book)) {
+ gtk_object_unref (GTK_OBJECT (book));
return NULL;
}
- /*
- * Setup the callback for getting book-opening progress
- * notifications.
- */
- book->priv->listener->open_progress = progress_cb;
- book->priv->listener->closure = closure;
- book->priv->open_response = open_response;
- book->priv->closure = closure;
- book->priv->operation_pending = TRUE;
+ return book;
+}
+
+/* Fetching cards */
+
+/**
+ * e_book_get_card:
+ */
+ECard *
+e_book_get_card (EBook *book,
+ const char *id)
+{
+ char *vcard;
+ ECard *card;
+
+ g_return_val_if_fail (book != NULL, NULL);
+ g_return_val_if_fail (E_IS_BOOK (book), NULL);
+
+ if (! book->priv->load_state != URILoaded) {
+ g_warning ("e_book_get_card: No URI loaded!\n");
+ return NULL;
+ }
+
+ vcard = e_book_get_vcard (book, id);
+
+ if (vcard == NULL) {
+ g_warning ("e_book_get_card: Got bogus VCard from PAS!\n");
+ return NULL;
+ }
+
+ card = e_card_new (vcard);
+ g_strdup (vcard);
+
+ return card;
+}
+
+/**
+ * e_book_get_vcard:
+ */
+char *
+e_book_get_vcard (EBook *book,
+ const char *id)
+{
+ CORBA_Environment ev;
+ char *retval;
+ char *vcard;
+
+ g_return_val_if_fail (book != NULL, NULL);
+ g_return_val_if_fail (E_IS_BOOK (book), NULL);
+
+ if (book->priv->load_state != URILoaded) {
+ g_warning ("e_book_get_vcard: No URI loaded!\n");
+ return NULL;
+ }
- /*
- * Load the addressbook into the PAS.
- */
CORBA_exception_init (&ev);
- Evolution_BookFactory_open_book (
- book->priv->book_factory, uri,
- gnome_object_corba_objref (GNOME_OBJECT (book->priv->listener)),
- &ev);
+ vcard = Evolution_Book_get_vcard (book->priv->corba_book,
+ (Evolution_CardId) id,
+ &ev);
if (ev._major != CORBA_NO_EXCEPTION) {
- g_warning ("e_book_construct: CORBA exception while opening addressbook!\n");
+ g_warning ("e_book_get_vcard: Exception getting VCard from PAS!\n");
CORBA_exception_free (&ev);
return NULL;
}
CORBA_exception_free (&ev);
+
+ if (vcard == NULL || strlen (vcard) == 0) {
+ g_warning ("e_book_get_vcard: Got NULL VCard from PAS!\n");
+ return NULL;
+ }
+
+ retval = g_strdup (vcard);
+ CORBA_free (vcard);
+
+ return retval;
}
+/* Deleting cards. */
+
/**
- * e_book_new:
+ * e_book_remove_card:
*/
-EBook *
-e_book_new (const char *uri,
- EBookOpenProgressCallback progress_cb,
- EBookCallback open_response,
- gpointer closure)
+gboolean
+e_book_remove_card (EBook *book,
+ ECard *card,
+ EBookCallback cb,
+ gpointer closure)
{
- EBook *book;
- EBook *retval;
+ const char *id;
- g_return_val_if_fail (uri != NULL, NULL);
+ g_return_val_if_fail (book != NULL, FALSE);
+ g_return_val_if_fail (E_IS_BOOK (book), FALSE);
+ g_return_val_if_fail (card != NULL, FALSE);
+ g_return_val_if_fail (E_IS_CARD (card), FALSE);
+ g_return_val_if_fail (cb != NULL, FALSE);
- book = gtk_type_new (E_BOOK_TYPE);
+ if (book->priv->load_state != URILoaded) {
+ g_warning ("e_book_remove_card: No URI loaded!\n");
+ return FALSE;
+ }
- retval = e_book_construct (book, uri, progress_cb,
- open_response, closure);
+ id = e_card_get_id (card);
+ g_assert (id != NULL);
- if (retval == NULL) {
- g_warning ("e_book_new: Could not construct EBook!\n");
- gtk_object_unref (GTK_OBJECT (book));
+ return e_book_remove_card_by_id (book, id, cb, closure);
+}
+/**
+ * e_book_remove_card_by_id:
+ */
+gboolean
+e_book_remove_card_by_id (EBook *book,
+ const char *id,
+ EBookCallback cb,
+ gpointer closure)
+
+{
+ CORBA_Environment ev;
+
+ g_return_val_if_fail (book != NULL, FALSE);
+ g_return_val_if_fail (E_IS_BOOK (book), FALSE);
+ g_return_val_if_fail (id != NULL, FALSE);
+ g_return_val_if_fail (cb != NULL, FALSE);
+
+ if (book->priv->load_state != URILoaded) {
+ g_warning ("e_book_remove_card_by_id: No URI loaded!\n");
+ return FALSE;
+ }
+
+ CORBA_exception_init (&ev);
+
+ Evolution_Book_remove_card (
+ book->priv->corba_book, (const Evolution_CardId) id, &ev);
+
+ if (ev._major != CORBA_NO_EXCEPTION) {
+ g_warning ("e_book_remove_card_by_id: CORBA exception "
+ "talking to PAS!\n");
+ CORBA_exception_free (&ev);
+ return FALSE;
+ }
+
+ CORBA_exception_free (&ev);
+
+ e_book_queue_op (book, cb, closure);
+
+ return TRUE;
+}
+
+/* Adding cards. */
+
+/**
+ * e_book_add_card:
+ */
+gboolean
+e_book_add_card (EBook *book,
+ ECard *card,
+ EBookCallback cb,
+ gpointer closure)
+
+{
+ char *vcard;
+ gboolean retval;
+
+ g_return_val_if_fail (book != NULL, FALSE);
+ g_return_val_if_fail (E_IS_BOOK (book), FALSE);
+ g_return_val_if_fail (card != NULL, FALSE);
+ g_return_val_if_fail (E_IS_CARD (card), FALSE);
+ g_return_val_if_fail (cb != NULL, FALSE);
+
+ if (book->priv->load_state != URILoaded) {
+ g_warning ("e_book_add_card: No URI loaded!\n");
+ return FALSE;
+ }
+
+ vcard = e_card_get_vcard (card);
+
+ if (vcard == NULL) {
+ g_warning ("e_book_add_card: Cannot convert card to VCard string!\n");
+ return FALSE;
+ }
+
+ retval = e_book_add_vcard (book, vcard, cb, closure);
+
+ g_free (vcard);
+
+ return retval;
+}
+
+/**
+ * e_book_add_vcard:
+ */
+gboolean
+e_book_add_vcard (EBook *book,
+ const char *vcard,
+ EBookCallback cb,
+ gpointer closure)
+{
+ CORBA_Environment ev;
+
+ g_return_val_if_fail (book != NULL, FALSE);
+ g_return_val_if_fail (E_IS_BOOK (book), FALSE);
+ g_return_val_if_fail (vcard != NULL, FALSE);
+ g_return_val_if_fail (cb != NULL, FALSE);
+
+ if (book->priv->load_state != URILoaded) {
+ g_warning ("e_book_add_vcard: No URI loaded!\n");
+ return FALSE;
+ }
+
+ CORBA_exception_init (&ev);
+
+ Evolution_Book_create_card (
+ book->priv->corba_book, vcard, &ev);
+
+ if (ev._major != CORBA_NO_EXCEPTION) {
+ g_warning ("e_book_add_vcard: Exception adding card to PAS!\n");
+ CORBA_exception_free (&ev);
+ return FALSE;
+ }
+
+ CORBA_exception_free (&ev);
+
+ e_book_queue_op (book, cb, closure);
+
+ return TRUE;
+}
+
+/* Modifying cards. */
+
+/**
+ * e_book_commit_card:
+ */
+gboolean
+e_book_commit_card (EBook *book,
+ ECard *card,
+ EBookCallback cb,
+ gpointer closure)
+{
+ char *vcard;
+ gboolean retval;
+
+ g_return_val_if_fail (book != NULL, FALSE);
+ g_return_val_if_fail (E_IS_BOOK (book), FALSE);
+ g_return_val_if_fail (card != NULL, FALSE);
+ g_return_val_if_fail (E_IS_CARD (card), FALSE);
+ g_return_val_if_fail (cb != NULL, FALSE);
+
+ if (book->priv->load_state != URILoaded) {
+ g_warning ("e_book_commit_card: No URI loaded!\n");
+ return FALSE;
+ }
+
+ vcard = e_card_get_vcard (card);
+
+ if (vcard == NULL) {
+ g_warning ("e_book_commit_card: Error "
+ "getting VCard for card!\n");
+ return FALSE;
+ }
+
+ retval = e_book_commit_vcard (book, vcard, cb, closure);
+
+ g_free (vcard);
+
+ return retval;
+}
+
+/**
+ * e_book_commit_vcard:
+ */
+gboolean
+e_book_commit_vcard (EBook *book,
+ const char *vcard,
+ EBookCallback cb,
+ gpointer closure)
+{
+ CORBA_Environment ev;
+
+ g_return_val_if_fail (book != NULL, FALSE);
+ g_return_val_if_fail (E_IS_BOOK (book), FALSE);
+ g_return_val_if_fail (vcard != NULL, FALSE);
+ g_return_val_if_fail (cb != NULL, FALSE);
+
+ if (book->priv->load_state != URILoaded) {
+ g_warning ("e_book_commit_vcard: No URI loaded!\n");
+ return FALSE;
+ }
+
+ CORBA_exception_init (&ev);
+
+ Evolution_Book_modify_card (
+ book->priv->corba_book, vcard, &ev);
+
+ if (ev._major != CORBA_NO_EXCEPTION) {
+ g_warning ("e_book_commit_vcard: Exception "
+ "modifying card in PAS!\n");
+ CORBA_exception_free (&ev);
+ return FALSE;
+ }
+
+ CORBA_exception_free (&ev);
+
+ e_book_queue_op (book, cb, closure);
+
+ return TRUE;
+}
+
+/**
+ * e_book_check_connection:
+ */
+gboolean
+e_book_check_connection (EBook *book)
+{
+ CORBA_Environment ev;
+
+ g_return_val_if_fail (book != NULL, FALSE);
+ g_return_val_if_fail (E_IS_BOOK (book), FALSE);
+
+ if (book->priv->load_state != URILoaded) {
+ g_warning ("e_book_check_connection: No URI loaded!\n");
+ return FALSE;
+ }
+
+ CORBA_exception_init (&ev);
+
+ Evolution_Book_check_connection (book->priv->corba_book, &ev);
+
+ if (ev._major != CORBA_NO_EXCEPTION) {
+ g_warning ("e_book_check_connection: Exception "
+ "querying the PAS!\n");
+ CORBA_exception_free (&ev);
+ return FALSE;
+ }
+
+ CORBA_exception_free (&ev);
+
+ return TRUE;
+}
+
+/**
+ * e_book_get_name:
+ */
+char *
+e_book_get_name (EBook *book)
+{
+ CORBA_Environment ev;
+ char *retval;
+ char *name;
+
+ g_return_val_if_fail (book != NULL, NULL);
+ g_return_val_if_fail (E_IS_BOOK (book), NULL);
+
+ if (book->priv->load_state != URILoaded) {
+ g_warning ("e_book_get_name: No URI loaded!\n");
return NULL;
}
+ CORBA_exception_init (&ev);
+
+ name = Evolution_Book_get_name (book->priv->corba_book, &ev);
+
+ if (ev._major != CORBA_NO_EXCEPTION) {
+ g_warning ("e_book_get_name: Exception getting name from PAS!\n");
+ CORBA_exception_free (&ev);
+ return NULL;
+ }
+
+ CORBA_exception_free (&ev);
+
+ if (name == NULL) {
+ g_warning ("e_book_get_name: Got NULL name from PAS!\n");
+ return NULL;
+ }
+
+ retval = g_strdup (name);
+ CORBA_free (name);
+
return retval;
}
static void
e_book_init (EBook *book)
{
- book->priv = g_new0 (EBookPrivate, 1);
+ book->priv = g_new0 (EBookPrivate, 1);
+ book->priv->load_state = URINotLoaded;
}
static void
@@ -142,7 +777,8 @@ e_book_destroy (GtkObject *object)
EBook *book = E_BOOK (object);
CORBA_Environment ev;
- gtk_object_unref (GTK_OBJECT (book->priv->listener));
+ if (book->priv->load_state != URINotLoaded)
+ e_book_unload_uri (book);
CORBA_exception_init (&ev);
@@ -179,7 +815,7 @@ e_book_class_init (EBookClass *klass)
gtk_signal_new ("card_added",
GTK_RUN_LAST,
object_class->type,
- GTK_SIGNAL_OFFSET (EBookClass, card_changed),
+ GTK_SIGNAL_OFFSET (EBookClass, card_added),
gtk_marshal_NONE__POINTER,
GTK_TYPE_NONE, 1,
GTK_TYPE_POINTER);
@@ -188,7 +824,7 @@ e_book_class_init (EBookClass *klass)
gtk_signal_new ("card_removed",
GTK_RUN_LAST,
object_class->type,
- GTK_SIGNAL_OFFSET (EBookClass, card_changed),
+ GTK_SIGNAL_OFFSET (EBookClass, card_removed),
gtk_marshal_NONE__POINTER,
GTK_TYPE_NONE, 1,
GTK_TYPE_POINTER);
@@ -208,87 +844,6 @@ e_book_class_init (EBookClass *klass)
object_class->destroy = e_book_destroy;
}
-/* Fetching cards */
-ECard *
-e_book_get_card (EBook *book,
- char *id)
-{
- g_return_val_if_fail (book != NULL, NULL);
- g_return_val_if_fail (E_IS_BOOK (book), NULL);
-
- if (book->priv->operation_pending) {
- g_warning ("EBook: Operation attempted on busy EBook!\n");
- return;
- }
-}
-
-char *
-e_book_get_vcard (EBook *book,
- char *id)
-{
-}
-
-ECardCursor *
-e_book_query (EBook *book,
- char *query)
-{
-}
-
-/* Deleting cards. */
-void
-e_book_remove_card (EBook *book,
- ECard *card,
- EBookCallback cb,
- gpointer closure)
-{
-}
-
-void
-e_book_remove_card_by_id (EBook *book,
- char *id,
- EBookCallback cb,
- gpointer closure)
-
-{
-}
-
-/* Adding cards. */
-void
-e_book_add_card (EBook *book,
- ECard *card,
- EBookCallback cb,
- gpointer closure)
-{
-}
-
-void
-e_book_add_vcard (EBook *book,
- char *vcard,
- char *id,
- EBookCallback cb,
- gpointer closure)
-{
-}
-
-
-/* Modifying cards. */
-void
-e_book_commit_card (EBook *book,
- ECard *card,
- EBookCallback cb,
- gpointer closure)
-{
-}
-
-void
-e_book_commit_vcard (EBook *book,
- char *vcard,
- EBookCallback cb,
- gpointer closure)
-{
-}
-
-
/**
* e_book_get_type:
*/
diff --git a/addressbook/backend/ebook/e-book.h b/addressbook/backend/ebook/e-book.h
index 892f99fb53..8a3fb311c1 100644
--- a/addressbook/backend/ebook/e-book.h
+++ b/addressbook/backend/ebook/e-book.h
@@ -37,10 +37,11 @@ typedef struct {
/*
* Signals.
*/
- void (* card_changed) (const char *id);
- void (* card_removed) (const char *id);
- void (* card_added) (const char *id);
- void (* link_status) (gboolean connected);
+ void (* open_progress) (const char *msg, short percent);
+ void (* link_status) (gboolean connected);
+ void (* card_changed) (const char *id);
+ void (* card_removed) (const char *id);
+ void (* card_added) (const char *id);
} EBookClass;
/* Callbacks for asynchronous functions. */
@@ -49,51 +50,59 @@ typedef void (*EBookOpenProgressCallback) (EBook *book,
const char *status_message,
short percent,
gpointer closure);
-
-
+
+
/* Creating a new addressbook. */
-EBook *e_book_new (const char *uri,
- EBookOpenProgressCallback progress_cb,
- EBookCallback open_response,
- gpointer closure);
-GtkType e_book_get_type (void);
+EBook *e_book_new (void);
+gboolean e_book_load_uri (EBook *book,
+ const char *uri,
+ EBookCallback open_response,
+ gpointer closure);
+void e_book_unload_uri (EBook *book);
/* Fetching cards. */
-ECard *e_book_get_card (EBook *book,
- char *id);
-char *e_book_get_vcard (EBook *book,
- char *id);
+ECard *e_book_get_card (EBook *book,
+ const char *id);
+char *e_book_get_vcard (EBook *book,
+ const char *id);
/* Deleting cards. */
-void e_book_remove_card (EBook *book,
- ECard *card,
- EBookCallback cb,
- gpointer closure);
-void e_book_remove_card_by_id (EBook *book,
- char *id,
- EBookCallback cb,
- gpointer closure);
+gboolean e_book_remove_card (EBook *book,
+ ECard *card,
+ EBookCallback cb,
+ gpointer closure);
+gboolean e_book_remove_card_by_id (EBook *book,
+ const char *id,
+ EBookCallback cb,
+ gpointer closure);
/* Adding cards. */
-void e_book_add_card (EBook *book,
- ECard *card,
- EBookCallback cb,
- gpointer closure);
-void e_book_add_vcard (EBook *book,
- char *vcard,
- char *id,
- EBookCallback cb,
- gpointer closure);
+gboolean e_book_add_card (EBook *book,
+ ECard *card,
+ EBookCallback cb,
+ gpointer closure);
+gboolean e_book_add_vcard (EBook *book,
+ const char *vcard,
+ EBookCallback cb,
+ gpointer closure);
/* Modifying cards. */
-void e_book_commit_card (EBook *book,
- ECard *card,
- EBookCallback cb,
- gpointer closure);
-void e_book_commit_vcard (EBook *book,
- char *vcard,
- EBookCallback cb,
- gpointer closure);
+gboolean e_book_commit_card (EBook *book,
+ ECard *card,
+ EBookCallback cb,
+ gpointer closure);
+gboolean e_book_commit_vcard (EBook *book,
+ const char *vcard,
+ EBookCallback cb,
+ gpointer closure);
+
+/* Checking to see if we're connected to the card repository. */
+gboolean e_book_check_connection (EBook *book);
+
+/* Getting the name of the repository. */
+char *e_book_get_name (EBook *book);
+
+GtkType e_book_get_type (void);
#define E_BOOK_TYPE (e_book_get_type ())
#define E_BOOK(o) (GTK_CHECK_CAST ((o), E_BOOK_TYPE, EBook))
diff --git a/addressbook/backend/ebook/e-card-pairs.h b/addressbook/backend/ebook/e-card-pairs.h
new file mode 100644
index 0000000000..d79d1171c6
--- /dev/null
+++ b/addressbook/backend/ebook/e-card-pairs.h
@@ -0,0 +1,139 @@
+/* GnomeCard - a graphical contact manager.
+ *
+ * pairs.h: This file is part of GnomeCard.
+ *
+ * Copyright (C) 1999 The Free Software Foundation
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __E_CARD_PAIRS_H__
+#define __E_CARD_PAIRS_H__
+
+#include "../libversit/vcc.h"
+#include <e-card.h>
+
+struct pair
+{
+ char *str;
+ enum PropertyType id;
+};
+
+struct pair prop_lookup[] = {
+ { VCFullNameProp, PROP_FNAME },
+ { VCNameProp, PROP_NAME },
+ { VCPhotoProp, PROP_PHOTO },
+ { VCBirthDateProp, PROP_BDAY },
+ { VCAdrProp, PROP_DELADDR },
+ { VCDeliveryLabelProp, PROP_DELLABEL },
+ { VCTelephoneProp, PROP_PHONE },
+ { VCEmailAddressProp, PROP_EMAIL },
+ { VCMailerProp, PROP_MAILER },
+ { VCTimeZoneProp, PROP_TIMEZN },
+ { VCGeoProp, PROP_GEOPOS },
+ { VCTitleProp, PROP_TITLE },
+ { VCBusinessRoleProp, PROP_ROLE },
+ { VCLogoProp, PROP_LOGO },
+ { VCAgentProp, PROP_AGENT },
+ { VCOrgProp, PROP_ORG },
+ { VCCategoriesProp, PROP_CATEGORIES },
+ { VCCommentProp, PROP_COMMENT },
+ { VCLastRevisedProp, PROP_REV },
+ { VCPronunciationProp, PROP_SOUND },
+ { VCURLProp, PROP_URL },
+ { VCUniqueStringProp, PROP_UID },
+ { VCVersionProp, PROP_VERSION },
+ { VCPublicKeyProp, PROP_KEY },
+ { VCValueProp, PROP_VALUE },
+ { VCEncodingProp, PROP_ENCODING },
+ { VCQuotedPrintableProp, PROP_QUOTED_PRINTABLE },
+ { VC8bitProp, PROP_8BIT },
+ { VCBase64Prop, PROP_BASE64 },
+ { VCLanguageProp, PROP_LANG },
+ { VCCharSetProp, PROP_CHARSET },
+ { NULL, PROP_NONE} };
+
+struct pair addr_pairs[] = {
+ { VCDomesticProp, ADDR_DOM },
+ { VCInternationalProp, ADDR_INTL },
+ { VCPostalProp, ADDR_POSTAL },
+ { VCParcelProp, ADDR_PARCEL },
+ { VCHomeProp, ADDR_HOME },
+ { VCWorkProp, ADDR_WORK },
+ { NULL, 0} };
+
+struct pair photo_pairs[] = {
+ { VCGIFProp, PHOTO_GIF },
+ { VCCGMProp, PHOTO_CGM },
+ { VCWMFProp, PHOTO_WMF },
+ { VCBMPProp, PHOTO_BMP },
+ { VCMETProp, PHOTO_MET },
+ { VCPMBProp, PHOTO_PMB },
+ { VCDIBProp, PHOTO_DIB },
+ { VCPICTProp, PHOTO_PICT },
+ { VCTIFFProp, PHOTO_TIFF },
+ { VCPDFProp, PHOTO_PDF },
+ { VCPSProp, PHOTO_PS },
+ { VCJPEGProp, PHOTO_JPEG },
+ { VCMPEGProp, PHOTO_MPEG },
+ { VCMPEG2Prop, PHOTO_MPEG2 },
+ { VCAVIProp, PHOTO_AVI },
+ { VCQuickTimeProp, PHOTO_QTIME },
+ { NULL, 0 } };
+
+struct pair phone_pairs[] = {
+ { VCPreferredProp, PHONE_PREF },
+ { VCWorkProp, PHONE_WORK },
+ { VCHomeProp, PHONE_HOME },
+ { VCVoiceProp, PHONE_VOICE },
+ { VCFaxProp, PHONE_FAX },
+ { VCMessageProp, PHONE_MSG },
+ { VCCellularProp, PHONE_CELL },
+ { VCPagerProp, PHONE_PAGER },
+ { VCBBSProp, PHONE_BBS },
+ { VCModemProp, PHONE_MODEM },
+ { VCCarProp, PHONE_CAR },
+ { VCISDNProp, PHONE_ISDN },
+ { VCVideoProp, PHONE_VIDEO },
+ { NULL, 0 } };
+
+struct pair email_pairs[] = {
+ { VCAOLProp, EMAIL_AOL },
+ { VCAppleLinkProp, EMAIL_APPLE_LINK },
+ { VCATTMailProp, EMAIL_ATT },
+ { VCCISProp, EMAIL_CIS },
+ { VCEWorldProp, EMAIL_EWORLD },
+ { VCInternetProp, EMAIL_INET },
+ { VCIBMMailProp, EMAIL_IBM },
+ { VCMCIMailProp, EMAIL_MCI },
+ { VCPowerShareProp, EMAIL_POWERSHARE },
+ { VCProdigyProp, EMAIL_PRODIGY },
+ { VCTLXProp, EMAIL_TLX },
+ { VCX400Prop, EMAIL_X400 },
+ { NULL, 0 } };
+
+struct pair sound_pairs[] = {
+ { VCAIFFProp, SOUND_AIFF },
+ { VCPCMProp, SOUND_PCM },
+ { VCWAVEProp, SOUND_WAVE },
+ { NULL, 0 } };
+
+struct pair key_pairs[] = {
+ { VCX509Prop, KEY_X509 },
+ { VCPGPProp, KEY_PGP },
+ { NULL, 0 } };
+
+
+#endif /* ! __E_CARD_PAIRS_H__ */
diff --git a/addressbook/backend/ebook/e-card-types.h b/addressbook/backend/ebook/e-card-types.h
new file mode 100644
index 0000000000..c148423b21
--- /dev/null
+++ b/addressbook/backend/ebook/e-card-types.h
@@ -0,0 +1,246 @@
+/*
+ * Authors:
+ * Arturo Espinosa
+ * Nat Friedman (nat@helixcode.com)
+ *
+ * Copyright (C) 2000 Helix Code, Inc.
+ * Copyright (C) 1999 The Free Software Foundation
+ */
+
+#ifndef __E_CARD_TYPES_H__
+#define __E_CARD_TYPES_H__
+
+typedef enum
+{
+ PROP_NONE = 0, /* Must always be the first, with value = 0. */
+ PROP_CARD = 1,
+ PROP_FNAME = 2,
+ PROP_NAME = 3,
+ PROP_PHOTO = 4,
+ PROP_BDAY = 5,
+ PROP_DELADDR_LIST = 6,
+ PROP_DELADDR = 7,
+ PROP_DELLABEL_LIST = 8,
+ PROP_DELLABEL = 9,
+ PROP_PHONE_LIST = 10,
+ PROP_PHONE = 11,
+ PROP_EMAIL_LIST = 12,
+ PROP_EMAIL = 13,
+ PROP_MAILER = 14,
+ PROP_TIMEZN = 15,
+ PROP_GEOPOS = 16,
+ PROP_TITLE = 17,
+ PROP_ROLE = 18,
+ PROP_LOGO = 19,
+ PROP_AGENT = 20,
+ PROP_ORG = 21,
+ PROP_COMMENT = 22,
+ PROP_REV = 23,
+ PROP_SOUND = 24,
+ PROP_URL = 25,
+ PROP_UID = 26,
+ PROP_VERSION = 27,
+ PROP_KEY = 28,
+ PROP_CATEGORIES = 29,
+ PROP_XTENSION_LIST = 30,
+ PROP_VALUE = 31,
+ PROP_ENCODING = 32,
+ PROP_QUOTED_PRINTABLE = 33,
+ PROP_8BIT = 34,
+ PROP_BASE64 = 35,
+ PROP_LANG = 36,
+ PROP_CHARSET = 37,
+ PROP_LAST = 38 /* Must always be the last, with the gratest value. */
+} ECardPropertyType;
+
+typedef enum
+{
+ ENC_NONE = 0,
+ ENC_BASE64 = 1,
+ ENC_QUOTED_PRINTABLE = 2,
+ ENC_8BIT = 3,
+ ENC_7BIT = 4,
+ ENC_LAST = 5
+} ECardEncodeType;
+
+typedef enum
+{
+ VAL_NONE = 0,
+ VAL_INLINE = 1,
+ VAL_CID = 2,
+ VAL_URL = 3,
+ VAL_LAST = 4
+} ECardValueType;
+
+typedef struct {
+ gboolean used;
+ ECardPropertyType type;
+ ECardEncodeType encode;
+ ECardValueType value;
+ char *charset;
+ char *lang;
+ GList *xtension;
+
+ void *user_data;
+} CardProperty;
+
+typedef struct {
+ char *name;
+ char *data;
+} CardXAttribute;
+
+typedef struct {
+ CardProperty prop;
+
+ char *name;
+ char *data;
+} ECardXProperty;
+
+typedef struct {
+ CardProperty prop;
+
+ GList *l;
+} ECardList;
+
+/* IDENTIFICATION PROPERTIES */
+
+
+typedef struct {
+ char *prefix; /* Mr. */
+ char *given; /* John */
+ char *additional; /* Quinlan */
+ char *family; /* Public */
+ char *suffix; /* Esq. */
+} ECardName;
+
+typedef struct {
+ CardProperty prop;
+
+ enum ECardPhotoType type;
+ guint size;
+ char *data;
+
+} ECardPhoto;
+
+typedef struct {
+ int year;
+ int month;
+ int day;
+} ECardDate;
+
+
+/* TELECOMMUNICATIONS ADDRESSING PROPERTIES */
+
+typedef enum {
+ PHONE_PREF = 1 << 0,
+ PHONE_WORK = 1 << 1,
+ PHONE_HOME = 1 << 2,
+ PHONE_VOICE = 1 << 3,
+ PHONE_FAX = 1 << 4,
+ PHONE_MSG = 1 << 5,
+ PHONE_CELL = 1 << 6,
+ PHONE_PAGER = 1 << 7,
+ PHONE_BBS = 1 << 8,
+ PHONE_MODEM = 1 << 9,
+ PHONE_CAR = 1 << 10,
+ PHONE_ISDN = 1 << 11,
+ PHONE_VIDEO = 1 << 12
+} ECardPhoneFlags;
+
+typedef struct {
+ ECardPhoneFlags flags;
+ char *data;
+} ECardPhone;
+
+typedef struct {
+ int sign; /* 1 or -1 */
+ int hours; /* Mexico General is at -6:00 UTC */
+ int mins; /* sign -1, hours 6, mins 0 */
+} ECardTimeZone;
+
+typedef struct {
+ CardProperty prop;
+
+ float lon;
+ float lat;
+} ECardGeoPos;
+
+
+typedef enum {
+ PHOTO_GIF, PHOTO_CGM, PHOTO_WMF, PHOTO_BMP, PHOTO_MET, PHOTO_PMB,
+ PHOTO_DIB, PHOTO_PICT, PHOTO_TIFF, PHOTO_PS, PHOTO_PDF, PHOTO_JPEG,
+ PHOTO_MPEG, PHOTO_MPEG2, PHOTO_AVI, PHOTO_QTIME
+} ECardPhotoType;
+
+/* DELIVERY ADDRESSING PROPERTIES */
+
+typedef enum {
+ ADDR_HOME = 1 << 0,
+ ADDR_WORK = 1 << 1,
+ ADDR_POSTAL = 1 << 2,
+ ADDR_PARCEL = 1 << 3,
+ ADDR_DOM = 1 << 4,
+ ADDR_INTL = 1 << 5
+} ECardAddrFlags;
+
+typedef struct {
+ ECardAddrFlags flags;
+
+ char *pobox;
+ char *ext;
+ char *street;
+ char *city;
+ char *region;
+ char *code;
+ char *country;
+} ECardAddr;
+
+
+typedef struct
+{
+ ECardAddrFlags flags;
+ char *data;
+} ECardAddrLabel;
+
+/* ORGANIZATIONAL PROPERTIES */
+
+typedef struct {
+ char *name;
+ char *unit1;
+ char *unit2;
+ char *unit3;
+ char *unit4;
+} ECardOrg;
+
+typedef enum {
+ SOUND_AIFF,
+ SOUND_PCM,
+ SOUND_WAVE,
+ SOUND_PHONETIC
+} ECardSoundType;
+
+typedef enum {
+ KEY_X509,
+ KEY_PGP
+} ECardKeyType;
+
+typedef struct {
+ int utc;
+ struct tm tm;
+} ECardRev;
+
+
+typedef struct {
+ enum SoundType type;
+ unsigned int size;
+ char *data;
+} ECardSound;
+
+typedef struct {
+ CardProperty prop;
+
+ enum KeyType type;
+ char *data;
+} ECardKey;
+
+#endif /* __E_CARD_TYPES_H__ */
diff --git a/addressbook/backend/ebook/e-card.c b/addressbook/backend/ebook/e-card.c
new file mode 100644
index 0000000000..bc5b13deae
--- /dev/null
+++ b/addressbook/backend/ebook/e-card.c
@@ -0,0 +1,1856 @@
+/*
+ * Authors:
+ * Arturo Espinosa (arturo@nuclecu.unam.mx)
+ * Nat Friedman (nat@helixcode.com)
+ *
+ * Copyright (C) 2000 Helix Code, Inc.
+ * Copyright (C) 1999 The Free Software Foundation
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+
+#include "../libversit/vcc.h"
+#include <e-card-pairs.h>
+#include <e-card.h>
+
+#define is_a_prop_of(obj,prop) isAPropertyOf (obj,prop)
+#define str_val(obj) the_str = (vObjectValueType (obj))? fakeCString (vObjectUStringZValue (obj)) : calloc (1, 1)
+#define has(obj,prop) (vo = isAPropertyOf (obj, prop))
+
+static VObject *card_convert_to_vobject (Card *crd);
+
+/*
+ * ECard lifecycle management and vCard loading/saving.
+ */
+
+/**
+ * e_card_new:
+ */
+ECard *
+e_card_new (void)
+{
+ ECard *c;
+
+ c = g_new0 (ECard, 1);
+
+ c->fname =
+ c->mailer =
+ c->title =
+ c->role =
+ c->comment =
+ c->categories =
+ c->url =
+ c->uid = e_card_prop_str_empty ();
+
+ c->photo.type = PHOTO_JPEG;
+ c->logo.type = PHOTO_JPEG;
+ c->rev.utc = -1;
+ c->sound.type = SOUND_PHONETIC;
+ c->key.type = KEY_PGP;
+
+ c->categories.prop.encod = ENC_QUOTED_PRINTABLE;
+ c->comment.prop.encod = ENC_QUOTED_PRINTABLE;
+
+ c->name.prop = c->photo.prop = c->bday.prop = c->timezn.prop =
+ c->geopos.prop = c->logo.prop = c->org.prop = c->rev.prop =
+ c->sound.prop = c->key.prop = c->deladdr.prop = c->dellabel.prop =
+ c->phone.prop = c->email.prop = c->xtension.prop = c->prop = e_card_prop_empty ();
+
+ c->prop.type = PROP_CARD;
+ c->fname.prop.type = PROP_FNAME;
+ c->name.prop.type = PROP_NAME;
+ c->photo.prop.type = PROP_PHOTO;
+ c->bday.prop.type = PROP_BDAY;
+
+ c->deladdr.prop.type = PROP_DELADDR_LIST;
+ c->dellabel.prop.type = PROP_DELLABEL_LIST;
+ c->phone.prop.type = PROP_PHONE_LIST;
+ c->email.prop.type = PROP_EMAIL_LIST;
+ c->xtension.prop.type = PROP_XTENSION_LIST;
+ c->mailer.prop.type = PROP_MAILER;
+ c->timezn.prop.type = PROP_TIMEZN;
+ c->geopos.prop.type = PROP_GEOPOS;
+ c->title.prop.type = PROP_TITLE;
+ c->role.prop.type = PROP_ROLE;
+ c->logo.prop.type = PROP_LOGO;
+ c->org.prop.type = PROP_ORG;
+ c->categories.prop.type = PROP_CATEGORIES;
+ c->comment.prop.type = PROP_COMMENT;
+ c->rev.prop.type = PROP_REV;
+ c->sound.prop.type = PROP_SOUND;
+ c->url.prop.type = PROP_URL;
+ c->uid.prop.type = PROP_UID;
+ c->key.prop.type = PROP_KEY;
+
+ return c;
+}
+
+static void
+e_card_str_free (CardStrProperty *sp)
+{
+ g_free (sp->str);
+
+ e_card_prop_free (sp->prop);
+}
+
+static void
+e_card_name_free (CardName *name)
+{
+ g_free (name->family);
+ g_free (name->given);
+ g_free (name->additional);
+ g_free (name->prefix);
+ g_free (name->suffix);
+
+ e_card_prop_free (name->prop);
+}
+
+static void
+e_card_photo_free (CardPhoto *photo)
+{
+ g_free (photo->data);
+
+ e_card_prop_free (photo->prop);
+}
+
+/**
+ * e_card_free:
+ */
+void
+e_card_free (ECard *card)
+{
+ GList *l;
+
+ g_return_if_fail (card != NULL);
+
+ e_card_name_free (& card->name);
+ e_card_str_free (& card->fname);
+
+ e_card_photo_free (card->photo);
+
+ e_card_logo_free (card->logo);
+ e_card_org_free (card->org);
+ e_card_key_free (card->key);
+ e_card_sound_free (card->sound);
+
+ e_card_prop_str_free (& card->mailer);
+ e_card_prop_str_free (& card->title);
+ e_card_prop_str_free (& card->role);
+ e_card_prop_str_free (& card->categories);
+ e_card_prop_str_free (& card->comment);
+ e_card_prop_str_free (& card->url);
+ e_card_prop_str_free (& card->uid);
+
+ /* address is a little more complicated */
+ card_prop_free (card->deladdr.prop);
+ while ((l = card->deladdr.l)) {
+
+ e_card_deladdr_free ((CardDelAddr *) l->data);
+
+ card->deladdr.l = g_list_remove_link (card->deladdr.l, l);
+ g_list_free (l);
+ }
+
+ g_free (card);
+}
+
+typedef struct
+{
+ char c;
+ int id;
+
+ GList *sons;
+} tree;
+
+extern CardProperty
+e_card_prop_empty (void)
+{
+ CardProperty prop;
+
+ prop.used = FALSE;
+
+ prop.type = PROP_NONE;
+ prop.encod = ENC_7BIT;
+ prop.value = VAL_INLINE;
+ prop.charset = NULL;
+ prop.lang = NULL;
+ prop.grp = NULL;
+ prop.xtension = NULL;
+
+ prop.user_data = NULL;
+
+ return prop;
+}
+
+static CardStrProperty
+e_card_prop_str_empty (void)
+{
+ CardStrProperty strprop;
+
+ strprop.prop = card_prop_empty ();
+ strprop.str = NULL;
+
+ return strprop;
+}
+
+/* Intended to check asserts. */
+extern int card_check_prop (CardProperty prop)
+{
+ if (((prop.used == FALSE) || (prop.used == TRUE)) &&
+ ((prop.type >= PROP_NONE) && (prop.type <= PROP_LAST)) &&
+ ((prop.encod >= ENC_NONE) && (prop.encod <= ENC_LAST)) &&
+ ((prop.value >= VAL_NONE) && (prop.value <= VAL_LAST)))
+ return TRUE;
+
+ return FALSE;
+}
+
+extern void
+card_prop_free (CardProperty prop)
+{
+ GList *l;
+
+ g_free (prop.charset);
+ g_free (prop.lang);
+
+ for (l = prop.xtension; l; l = l->next) {
+ CardXAttribute *xa = (CardXAttribute *) l->data;
+ g_free (xa->name);
+ g_free (xa->data);
+ }
+
+ g_list_free (l);
+
+ prop.used = FALSE;
+}
+
+e_card_deladdr_free (ECardDelAddr *c)
+{
+ card_prop_free (c->prop);
+
+ g_free (p->pobox);
+ g_free (p->ext);
+ g_free (p->street);
+ g_free (p->city);
+ g_free (p->region);
+ g_free (p->code);
+ g_free (p->country);
+}
+
+void
+card_free (Card *crd)
+{
+}
+
+static tree *
+new_tree (char c, int id)
+{
+ tree *t;
+
+ t = malloc (sizeof (tree));
+ t->c = c;
+ t->id = id;
+ t->sons = NULL;
+
+ return t;
+}
+
+static void
+add_branch (tree *t, char *str, int id)
+{
+ tree *tmp;
+ char *end;
+
+ end = str + strlen (str) + 1;
+
+ while (str != end) {
+ tmp = new_tree (*str, id);
+ t->sons = g_list_append (t->sons, (gpointer) tmp);
+ t = tmp;
+
+ str ++;
+ }
+}
+
+static tree *
+add_to_tree (tree *t, struct pair p)
+{
+ GList *node;
+ char *c, *end;
+ tree *tmp;
+
+ c = p.str;
+ end = c + strlen (c) + 1;
+ tmp = t;
+
+ while (c != end) {
+ for (node = tmp->sons; node; node = node->next)
+ if (((tree *) node->data)->c == *c) {
+ break;
+ }
+
+ if (node) {
+ tmp = (tree *) node->data;
+ tmp->id = 0;
+ c++;
+ }
+ else {
+ add_branch (tmp, c, p.id);
+ break;
+ }
+ }
+
+ return t;
+}
+
+static tree *
+create_search_tree (void)
+{
+ tree *t;
+ int i;
+
+ t = new_tree (0, 0);
+ for (i = 0; prop_lookup[i].str; i++)
+ t = add_to_tree (t, prop_lookup[i]);
+
+ return t;
+}
+
+static int
+card_lookup_name (const char *c)
+{
+ static tree *search_tree = NULL;
+ GList *node;
+ tree *tmp;
+ const char *end;
+
+ if (!search_tree)
+ search_tree = create_search_tree ();
+
+ tmp = search_tree;
+ end = c + strlen (c) + 1;
+
+ while (tmp->id == 0 && c != end) {
+ for (node = tmp->sons; node; node = node->next)
+ if (((tree *) node->data)->c == *c) {
+ break;
+ }
+
+ if (node) {
+ tmp = (tree *) node->data;
+ c++;
+ }
+ else
+ return 0;
+ }
+
+ return tmp->id;
+}
+
+static enum PhotoType
+get_photo_type (VObject *o)
+{
+ VObject *vo;
+ int i;
+
+ for (i = 0; photo_pairs[i].str; i++)
+ if (has (o, photo_pairs[i].str))
+ return photo_pairs[i].id;
+
+ g_warning ("? < No PhotoType for Photo property. Falling back to JPEG.");
+ return PHOTO_JPEG;
+}
+
+static int
+get_addr_type (VObject *o)
+{
+ VObject *vo;
+ int ret = 0;
+ int i;
+
+ for (i = 0; addr_pairs[i].str; i++)
+ if (has (o, addr_pairs[i].str))
+ ret |= addr_pairs[i].id;
+
+ return ret;
+}
+
+static int
+get_phone_type (VObject *o)
+{
+ VObject *vo;
+ int ret = 0;
+ int i;
+
+ for (i = 0; phone_pairs[i].str; i++)
+ if (has (o, phone_pairs[i].str))
+ ret |= phone_pairs[i].id;
+
+ return ret;
+}
+
+static enum EMailType
+get_email_type (VObject *o)
+{
+ VObject *vo;
+ int i;
+
+ for (i = 0; email_pairs[i].str; i++)
+ if (has (o, email_pairs[i].str))
+ return email_pairs[i].id;
+
+ g_warning ("? < No EMailType for EMail property. Falling back to INET.");
+ return EMAIL_INET;
+}
+
+static CardProperty
+get_CardProperty (VObject *o)
+{
+ VObjectIterator i;
+ CardProperty prop;
+
+ prop = card_prop_empty ();
+ prop.used = TRUE;
+
+ initPropIterator (&i, o);
+ while (moreIteration (&i)) {
+ VObject *vo = nextVObject (&i);
+ const char *n = vObjectName (vo);
+ int propid;
+
+ propid = card_lookup_name (n);
+
+ switch (propid) {
+
+ case PROP_VALUE:
+
+ if (has (vo, VCContentIDProp))
+ prop.value = VAL_CID;
+ else if (has (vo, VCURLValueProp))
+ prop.value = VAL_URL;
+ break;
+
+ case PROP_ENCODING:
+ if (has (vo, VCQuotedPrintableProp))
+ prop.encod = ENC_QUOTED_PRINTABLE;
+ else if (has (vo, VC8bitProp))
+ prop.encod = ENC_8BIT;
+ else if (has (vo, VCBase64Prop))
+ prop.encod = ENC_BASE64;
+ break;
+
+ case PROP_QUOTED_PRINTABLE:
+ prop.encod = ENC_QUOTED_PRINTABLE;
+ break;
+
+ case PROP_8BIT:
+ prop.encod = ENC_8BIT;
+ break;
+
+ case PROP_BASE64:
+ prop.encod = ENC_BASE64;
+ break;
+
+ case PROP_LANG:
+ if (vObjectValueType (vo)) {
+ prop.lang =
+ g_strdup (vObjectStringZValue (vo));
+ } else
+ g_warning ("? < No value for LANG attribute.");
+ break;
+
+ case PROP_CHARSET:
+ if (vObjectValueType (vo)) {
+ prop.charset =
+ g_strdup (vObjectStringZValue (vo));
+ g_warning (prop.charset);
+ } else
+ g_warning ("? < No value for CHARSET attribute.");
+ break;
+ default:
+ {
+ CardXAttribute *c;
+
+ c = malloc (sizeof (CardXAttribute));
+ c->name = g_strdup (n);
+
+ if (vObjectValueType (vo))
+ c->data =
+ g_strdup (vObjectStringZValue (vo));
+ else
+ c->data = NULL;
+
+ prop.xtension =
+ g_list_append (prop.xtension, c);
+ }
+ }
+ }
+
+ return prop;
+}
+
+static gboolean
+e_card_prop_has (VObject *o,
+ const char *id)
+{
+ g_assert (o != NULL);
+ g_assert (id != NULL);
+
+ if (isAPropertyOf (o, id) == NULL)
+ return FALSE;
+
+ return TRUE;
+}
+
+static const char *
+e_card_prop_get_str (VObject *o,
+ const char *id)
+{
+ VObject *strobj;
+
+ g_assert (o != NULL);
+ g_assert (id != NULL);
+
+ strobj = isAPropertyOf (o, id);
+
+ if (strobj == NULL)
+ return g_strdup ("");
+
+ if (vObjectValueType (strobj) != NULL) {
+ char *str;
+ char *g_str;
+
+ str = fakeCString (vObjectStringZValue (strobj));
+ g_str = g_strdup (str);
+ free (str);
+
+ return g_str;
+ }
+
+ return g_strdup ("");
+}
+
+static ECardName *
+e_card_get_name (VObject *o)
+{
+ CardName *name;
+ VObject *vo;
+ char *the_str;
+
+ name = g_new0 (ECardName, 1);
+
+ name->family = e_card_prop_get_substr (o, VCFamilyNameProp);
+ name->given = e_card_prop_get_substr (o, VCGivenNameProp);
+ name->additional = e_card_prop_get_substr (o, VCAdditionalNamesProp);
+ name->prefix = e_card_prop_get_substr (o, VCNamePrefixesProp);
+ name->suffix = e_card_prop_get_substr (o, VCNameSuffixesProp);
+
+ return name;
+}
+
+static CardBDay
+strtoCardBDay (char *str)
+{
+ char *s;
+ int i;
+ CardBDay bday;
+
+ bday.year = 0;
+ bday.month = 0;
+ bday.day = 0;
+
+ if (strchr (str, '-')) {
+ for (s = strtok (str, "-"), i = 0; s;
+ s = strtok (NULL, "-"), i++)
+ switch (i) {
+ case 0:
+ bday.year = atoi (s);
+ break;
+ case 1:
+ bday.month = atoi (s);
+ break;
+ case 2:
+ bday.day = atoi (s);
+ break;
+ default:
+ g_warning ("? < Too many values for BDay property.");
+ }
+
+ if (i < 2)
+ g_warning ("? < Too few values for BDay property.");
+ } else {
+ if (strlen (str) >= 8) {
+ bday.day = atoi (str + 6);
+ str[6] = 0;
+ bday.month = atoi (str + 4);
+ str[4] = 0;
+ bday.year = atoi (str);
+ } else
+ g_warning ("? < Bad format for BDay property.");
+ }
+
+ return bday;
+}
+
+static ECardDelAddr *
+e_card_get_del_addr (VObject *o)
+{
+ ECardDelAddr *addr;
+
+ addr = g_new0 (ECardDelAddr, 1);
+
+ addr->type = get_addr_type (o);
+ addr->po = e_card_prop_get_substr (o, VCPostalBoxProp);
+ addr->ext = e_card_prop_get_substr (o, VCExtAddressProp);
+ addr->street = e_card_prop_get_substr (o, VCStreetAddressProp);
+ addr->city = e_card_prop_get_substr (o, VCCityProp);
+ addr->region = e_card_prop_get_substr (o, VCRegionProp);
+ addr->code = e_card_prop_get_substr (o, VCPostalBoxProp);
+ addr->country = e_card_prop_get_substr (o, VCCountryNameProp);
+
+ return addr;
+}
+
+static CardDelLabel *
+get_CardDelLabel (VObject *o)
+{
+ CardDelLabel *dellabel;
+ char *the_str;
+
+ dellabel = malloc (sizeof (CardDelLabel));
+
+ dellabel->type = get_addr_type (o);
+ dellabel->data = g_strdup (str_val (o));
+
+ free (the_str);
+ return dellabel;
+}
+
+static CardPhone *
+get_CardPhone (VObject *o)
+{
+ CardPhone *ret;
+ char *the_str;
+
+ ret = malloc (sizeof (CardPhone));
+ ret->type = get_phone_type (o);
+ ret->data = g_strdup (str_val (o));
+
+ free (the_str);
+
+ return ret;
+}
+
+static CardEMail *
+get_CardEMail (VObject *o)
+{
+ CardEMail *ret;
+ char *the_str;
+
+ ret = malloc (sizeof (CardEMail));
+ ret->type = get_email_type (o);
+ ret->data = g_strdup (str_val (o));
+
+ free (the_str);
+
+ return ret;
+}
+
+static CardTimeZone
+strtoCardTimeZone (char *str)
+{
+ char s[3];
+ CardTimeZone tz;
+
+ if (*str == '-') {
+ tz.sign = -1;
+ str++;
+ } else
+ tz.sign = 1;
+
+ tz.hours = 0;
+ tz.mins = 0;
+
+ s[2] = 0;
+ if (strlen (str) > 2) {
+ s[0] = str[0];
+ s[1] = str[1];
+ tz.hours = atoi (s);
+ } else {
+ g_warning ("? < TimeZone value is too short.");
+ return tz;
+ }
+
+ str += 2;
+ if (*str == ':')
+ str++;
+
+ if (strlen (str) >= 2) {
+ s[0] = str[0];
+ s[1] = str[1];
+ tz.mins = atoi (s);
+ } else {
+ g_warning ("? < TimeZone value is too short.");
+ return tz;
+ }
+
+ if (strlen (str) > 3)
+ g_warning ("? < TimeZone value is too long.");
+
+ return tz;
+}
+
+static CardGeoPos
+strtoCardGeoPos (char *str)
+{
+ CardGeoPos gp;
+ char *s;
+
+ gp.lon = 0;
+ gp.lat = 0;
+
+ s = strchr (str, ',');
+
+ if (! s) {
+ g_warning ("? < Bad format for GeoPos property.");
+ return gp;
+ }
+
+ *s = 0;
+ s++;
+
+ gp.lon = atof (str);
+ gp.lat = atof (s);
+
+ return gp;
+}
+
+static CardOrg *
+e_card_vobject_to_org (VObject *o)
+{
+ VObject *vo;
+ char *the_str;
+ CardOrg *org;
+
+ org = g_new0 (CardOrg, 1);
+
+ if (has (o, VCOrgNameProp)) {
+ org.name = g_strdup (str_val (vo));
+ free (the_str);
+ }
+ if (has (o, VCOrgUnitProp)) {
+ org.unit1 = g_strdup (str_val (vo));
+ free (the_str);
+ }
+ if (has (o, VCOrgUnit2Prop)) {
+ org.unit2 = g_strdup (str_val (vo));
+ free (the_str);
+ }
+ if (has (o, VCOrgUnit3Prop)) {
+ org.unit3 = g_strdup (str_val (vo));
+ free (the_str);
+ }
+ if (has (o, VCOrgUnit4Prop)) {
+ org.unit4 = g_strdup (str_val (vo));
+ free (the_str);
+ }
+
+ return org;
+}
+
+static CardXProperty *
+get_XProp (VObject *o)
+{
+ char *the_str;
+ CardXProperty *ret;
+
+ ret = malloc (sizeof (CardXProperty));
+ ret->name = g_strdup (vObjectName (o));
+ ret->data = g_strdup (str_val (o));
+ free (the_str);
+
+ return ret;
+}
+
+static CardRev
+strtoCardRev (char *str)
+{
+ char s[3], *t, *ss;
+ int len, i;
+ CardRev rev;
+
+ rev.utc = 0;
+ len = strlen (str);
+
+ if (str[len] == 'Z') { /* Is it UTC? */
+ rev.utc = 1;
+ str[len] = 0;
+ }
+
+ s[2] = 0;
+ t = strchr (str, 'T');
+ if (t) { /* Take the Time */
+ *t = 0;
+ t++;
+ if (strlen (t) > 2) {
+ s[0] = t[0];
+ s[1] = t[1];
+ rev.tm.tm_hour = atoi (s);
+ } else {
+ g_warning ("? < Rev value is too short.");
+ return rev;
+ }
+
+ t += 2;
+ if (*t == ':') /* Ignore ':' separator */
+ t++;
+
+ if (strlen (t) > 2) {
+ s[0] = t[0];
+ s[1] = t[1];
+ rev.tm.tm_min = atoi (s);
+ } else {
+ g_warning ("? < Rev value is too short.");
+ return rev;
+ }
+
+ t += 2;
+ if (*t == ':')
+ t++;
+
+ if (strlen (t) > 2) {
+ s[0] = t[0];
+ s[1] = t[1];
+ rev.tm.tm_sec = atoi (s);
+ } else {
+ g_warning ("? < Rev value is too short.");
+ return rev;
+ }
+
+ if (strlen (str) > 3)
+ g_warning ("? < Rev value is too long.");
+
+ } else {
+ g_warning ("? < No time value for Rev property.");
+ }
+
+ /* Now the date (the part before the T) */
+
+ if (strchr (str, '-')) { /* extended iso 8601 */
+ for (ss = strtok (str, "-"), i = 0; ss;
+ ss = strtok (NULL, "-"), i++)
+ switch (i) {
+ case 0:
+ rev.tm.tm_year = atoi (ss);
+ break;
+ case 1:
+ rev.tm.tm_mon = atoi (ss);
+ break;
+ case 2:
+ rev.tm.tm_mday = atoi (ss);
+ break;
+ default:
+ g_warning ("? < Too many values for Rev property.");
+ }
+
+ if (i < 2)
+ g_warning ("? < Too few values for Rev property.");
+ } else {
+ if (strlen (str) >= 8) { /* short representation */
+ rev.tm.tm_mday = atoi (str + 6);
+ str[6] = 0;
+ rev.tm.tm_mon = atoi (str + 4);
+ str[4] = 0;
+ rev.tm.tm_year = atoi (str);
+ } else
+ g_warning ("? < Bad format for Rev property.");
+ }
+
+ return rev;
+}
+
+static enum KeyType
+get_key_type (VObject *o)
+{
+ VObject *vo;
+ int i;
+
+ for (i = 0; key_pairs[i].str; i++)
+ if (has (o, key_pairs[i].str))
+ return key_pairs[i].id;
+
+ g_warning ("? < No KeyType for Key property. Falling back to PGP.");
+ return KEY_PGP;
+}
+
+static CardPhoto
+get_CardPhoto (VObject *o)
+{
+ VObject *vo;
+ char *the_str;
+ CardPhoto photo;
+
+ photo.type = get_photo_type (o);
+
+ if (has (o, VCDataSizeProp)) {
+ photo.size = vObjectIntegerValue (vo);
+ photo.data = malloc (photo.size);
+ memcpy (photo.data, vObjectAnyValue (o), photo.size);
+ } else {
+ photo.size = strlen (str_val (o)) + 1;
+ photo.data = g_strdup (the_str);
+ free (the_str);
+ }
+
+ return photo;
+}
+
+static enum SoundType
+get_sound_type (VObject *o)
+{
+ VObject *vo;
+ int i;
+
+ for (i = 0; sound_pairs[i].str; i++)
+ if (has (o, sound_pairs[i].str))
+ return sound_pairs[i].id;
+
+ return SOUND_PHONETIC;
+}
+
+static CardSound
+get_CardSound (VObject *o)
+{
+ VObject *vo;
+ char *the_str;
+ CardSound sound;
+
+ sound.type = get_sound_type (o);
+
+ if (has (o, VCDataSizeProp)) {
+ sound.size = vObjectIntegerValue (vo);
+ sound.data = malloc (sound.size);
+ memcpy (sound.data, vObjectAnyValue (o), sound.size);
+ } else {
+ sound.size = strlen (str_val (o));
+ sound.data = g_strdup (the_str);
+ free (the_str);
+ }
+
+ return sound;
+}
+
+/* Loads our card contents from a VObject */
+static ECard *
+e_card_construct_from_vobject (ECard *card,
+ VObject *vcrd)
+{
+ VObjectIterator i;
+ Card *crd;
+ char *the_str;
+
+ initPropIterator (&i, vcrd);
+ crd = card_new ();
+
+ while (moreIteration (&i)) {
+ VObject *o = nextVObject (&i);
+ const char *n = vObjectName (o);
+ int propid;
+ CardProperty *prop = NULL;
+
+ propid = card_lookup_name (n);
+
+ switch (propid) {
+ case PROP_FNAME:
+ prop = &crd->fname.prop;
+ crd->fname.str = g_strdup (str_val (o));
+ free (the_str);
+ break;
+ case PROP_NAME:
+ prop = &crd->name.prop;
+ crd->name = e_card_get_name (o);
+ break;
+ case PROP_PHOTO:
+ prop = &crd->photo.prop;
+ crd->photo = get_CardPhoto (o);
+ break;
+ case PROP_BDAY:
+ prop = &crd->bday.prop;
+ crd->bday = strtoCardBDay (str_val (o));
+ free (the_str);
+ break;
+ case PROP_DELADDR:
+ {
+ CardDelAddr *c;
+ c = get_CardDelAddr (o);
+ prop = &c->prop;
+ crd->deladdr.l = g_list_append (crd->deladdr.l, c);
+ }
+ break;
+ case PROP_DELLABEL:
+ {
+ CardDelLabel *c;
+ c = get_CardDelLabel (o);
+ prop = &c->prop;
+ crd->dellabel.l = g_list_append (crd->dellabel.l, c);
+ }
+ break;
+ case PROP_PHONE:
+ {
+ CardPhone *c;
+
+ c = get_CardPhone (o);
+ prop = &c->prop;
+ crd->phone.l = g_list_append (crd->phone.l, c);
+ }
+ break;
+ case PROP_EMAIL:
+ {
+ CardEMail *c;
+
+ c = get_CardEMail (o);
+ prop = &c->prop;
+ crd->email.l = g_list_append (crd->email.l, c);
+ }
+ break;
+ case PROP_MAILER:
+ prop = &crd->mailer.prop;
+ crd->mailer.str = g_strdup (str_val (o));
+ free (the_str);
+ break;
+ case PROP_TIMEZN:
+ prop = &crd->timezn.prop;
+ crd->timezn = strtoCardTimeZone (str_val (o));
+ free (the_str);
+ break;
+ case PROP_GEOPOS:
+ prop = &crd->geopos.prop;
+ crd->geopos = strtoCardGeoPos (str_val (o));
+ break;
+ case PROP_TITLE:
+ prop = &crd->title.prop;
+ crd->title.str = g_strdup (str_val (o));
+ free (the_str);
+ break;
+ case PROP_ROLE:
+ prop = &crd->role.prop;
+ crd->role.str = g_strdup (str_val (o));
+ free (the_str);
+ break;
+ case PROP_LOGO:
+ prop = &crd->logo.prop;
+ crd->logo = get_CardPhoto (o);
+ break;
+ case PROP_AGENT:
+ crd->agent = card_create_from_vobject (o);
+ break;
+ case PROP_ORG:
+ prop = &crd->org.prop;
+ crd->org = get_CardOrg (o);
+ break;
+ case PROP_CATEGORIES:
+ prop = &crd->categories.prop;
+ crd->categories.str = g_strdup (str_val (o));
+ crd->categories.prop.encod = ENC_QUOTED_PRINTABLE;
+ free (the_str);
+ break;
+ case PROP_COMMENT:
+ prop = &crd->comment.prop;
+ crd->comment.str = g_strdup (str_val (o));
+ crd->comment.prop.encod = ENC_QUOTED_PRINTABLE;
+ free (the_str);
+ break;
+ case PROP_REV:
+ prop = &crd->rev.prop;
+ crd->rev = strtoCardRev (str_val (o));
+ free (the_str);
+ break;
+ case PROP_SOUND:
+ prop = &crd->sound.prop;
+ crd->sound = get_CardSound (o);
+ break;
+ case PROP_URL:
+ prop = &crd->url.prop;
+ crd->url.str = g_strdup (str_val (o));
+ free (the_str);
+ break;
+ case PROP_UID:
+ prop = &crd->uid.prop;
+ crd->uid.str = g_strdup (str_val (o));
+ free (the_str);
+ break;
+ case PROP_VERSION:
+ {
+ char *str;
+ str = str_val (o);
+ if (strcmp (str, "2.1"))
+ g_warning ("? < Version doesn't match.");
+ free (the_str);
+ }
+ break;
+ case PROP_KEY:
+ prop = &crd->key.prop;
+ crd->key.type = get_key_type (o);
+ crd->key.data = g_strdup (str_val (o));
+ free (the_str);
+ break;
+ default:
+ {
+ CardXProperty *c;
+
+ c = get_XProp (o);
+ prop = &c->prop;
+ crd->xtension.l = g_list_append (crd->xtension.l, c);
+ }
+ break;
+ }
+
+ if (prop) {
+ *prop = get_CardProperty (o);
+ prop->type = propid;
+ }
+ }
+
+ return crd;
+}
+
+/* Loads a card from a file */
+GList *
+card_load (GList *crdlist, char *fname)
+{
+ VObject *vobj, *tmp;
+
+ vobj = Parse_MIME_FromFileName (fname);
+ if (!vobj) {
+ g_warning ("Could not load the cardfile");
+ return NULL;
+ }
+
+ while (vobj) {
+ const char *n = vObjectName (vobj);
+
+ if (strcmp (n, VCCardProp) == 0) {
+ crdlist = g_list_append (crdlist, (gpointer)
+ card_create_from_vobject (vobj));
+ }
+ tmp = vobj;
+ vobj = nextVObjectInList (vobj);
+ cleanVObject (tmp);
+ }
+
+ cleanVObject (vobj);
+ cleanStrTbl ();
+ return crdlist;
+}
+
+static VObject *
+add_strProp (VObject *o, const char *id, char *val)
+{
+ VObject *vo = NULL;
+
+ if (val)
+ vo = addPropValue (o, id, val);
+
+ return vo;
+}
+
+static VObject *
+add_CardProperty (VObject *o, CardProperty *prop)
+{
+ GList *node;
+
+ switch (prop->encod) {
+ case ENC_BASE64:
+ addProp (o, VCBase64Prop);
+ break;
+ case ENC_QUOTED_PRINTABLE:
+ addProp (o, VCQuotedPrintableProp);
+ break;
+ case ENC_8BIT:
+ addProp (o, VC8bitProp);
+ break;
+ case ENC_7BIT:
+ /* Do nothing: 7BIT is the default. Avoids file clutter. */
+ break;
+ default:
+ g_warning ("? < Card had invalid encoding type.");
+ }
+
+ switch (prop->value) {
+ case VAL_CID:
+ addProp (o, VCContentIDProp);
+ break;
+ case VAL_URL:
+ addProp (o, VCURLValueProp);
+ break;
+ case VAL_INLINE:
+ /* Do nothing: INLINE is the default. Avoids file clutter. */
+ break;
+ default:
+ g_warning ("? < Card had invalid value type.");
+ }
+
+ for (node = prop->xtension; node; node = node->next) {
+ CardXAttribute *xa = (CardXAttribute *) node->data;
+ if (xa->data)
+ addPropValue (o, xa->name, xa->data);
+ else
+ addProp (o, xa->name);
+ }
+
+ add_strProp (o, VCCharSetProp, prop->charset);
+ add_strProp (o, VCLanguageProp, prop->lang);
+
+ return o;
+}
+
+static VObject *
+add_CardStrProperty (VObject *vobj, const char *id, CardStrProperty *strprop)
+{
+ VObject *vprop;
+
+ if (strprop->prop.used) {
+ vprop = add_strProp (vobj, id, strprop->str);
+ add_CardProperty (vprop, &strprop->prop);
+ }
+
+ return vobj;
+}
+
+static VObject *
+add_PhotoType (VObject *o, enum PhotoType photo_type)
+{
+ int i;
+
+ for (i = 0; photo_pairs[i].str; i++)
+ if (photo_type == photo_pairs[i].id) {
+ addProp (o, photo_pairs[i].str);
+ return o;
+ }
+
+ g_warning ("? > No PhotoType for Photo property. Falling back to JPEG.");
+ addProp (o, VCJPEGProp);
+
+ return o;
+}
+
+static VObject *
+add_AddrType (VObject *o, int addr_type)
+{
+ int i;
+
+ for (i = 0; addr_pairs[i].str; i++)
+ if (addr_type & addr_pairs[i].id)
+ addProp (o, addr_pairs[i].str);
+
+ return o;
+}
+
+static void
+add_strAddrType (GString *string, int addr_type)
+{
+ int i, first = 1;
+ char *str;
+
+ if (addr_type) {
+ g_string_append (string, " (");
+
+ for (i = 0; addr_pairs[i].str; i++)
+ if (addr_type & addr_pairs[i].id) {
+ if (!first)
+ g_string_append (string, ", ");
+ first = 0;
+ str = my_cap (addr_pairs[i].str);
+ g_string_append (string, str);
+ g_free (str);
+ }
+
+ g_string_append_c (string, ')');
+ }
+}
+
+static VObject *
+add_PhoneType (VObject *o, int phone_type)
+{
+ int i;
+
+ for (i = 0; phone_pairs[i].str; i++)
+ if (phone_type & phone_pairs[i].id)
+ addProp (o, phone_pairs[i].str);
+
+ return o;
+}
+
+static void
+add_strPhoneType (GString *string, int phone_type)
+{
+ int i, first = 1;
+ char *str;
+
+ if (phone_type) {
+ g_string_append (string, " (");
+
+ for (i = 0; phone_pairs[i].str; i++)
+ if (phone_type & phone_pairs[i].id) {
+ if (!first)
+ g_string_append (string, ", ");
+ first = 0;
+ str = my_cap (phone_pairs[i].str);
+ g_string_append (string, str);
+ g_free (str);
+ }
+
+ g_string_append_c (string, ')');
+ }
+}
+
+static VObject *
+add_EMailType (VObject *o, enum EMailType email_type)
+{
+ int i;
+
+ for (i = 0; email_pairs[i].str; i++)
+ if (email_type == email_pairs[i].id) {
+ addProp (o, email_pairs[i].str);
+ return o;
+ }
+
+ g_warning ("? > No EMailType for EMail property. Falling back to INET.");
+ addProp (o, VCInternetProp);
+
+ return o;
+}
+
+static void
+add_strEMailType (GString *string, int email_type)
+{
+ int i;
+ char *str;
+
+ if (email_type) {
+ g_string_append (string, " (");
+
+ for (i = 0; email_pairs[i].str; i++)
+ if (email_type == email_pairs[i].id) {
+ str = my_cap (email_pairs[i].str);
+ g_string_append (string, str);
+ g_free (str);
+ break;
+ }
+
+ g_string_append_c (string, ')');
+ }
+}
+
+static VObject *
+add_KeyType (VObject *o, enum KeyType key_type)
+{
+ int i;
+
+ for (i = 0; key_pairs[i].str; i++)
+ if (key_type == key_pairs[i].id) {
+ addProp (o, key_pairs[i].str);
+ return o;
+ }
+
+ g_warning ("? > No KeyType for Key property. Falling back to PGP.");
+ addProp (o, VCPGPProp);
+
+ return o;
+}
+
+static void
+add_strKeyType (GString *string, int key_type)
+{
+ int i;
+ char *str;
+
+ if (key_type) {
+ g_string_append (string, " (");
+
+ for (i = 0; key_pairs[i].str; i++)
+ if (key_type == key_pairs[i].id) {
+ str = my_cap (key_pairs[i].str);
+ g_string_append (string, str);
+ g_free (str);
+ break;
+ }
+
+ g_string_append_c (string, ')');
+ }
+}
+
+static VObject *
+add_SoundType (VObject *o, enum SoundType sound_type)
+{
+ int i;
+
+ for (i = 0; sound_pairs[i].str; i++)
+ if (sound_type == sound_pairs[i].id) {
+ addProp (o, sound_pairs[i].str);
+ return o;
+ }
+
+ return o;
+}
+
+char *card_bday_str (CardBDay bday)
+{
+ char *str;
+
+ str = malloc (12);
+ snprintf (str, 12, "%04d-%02d-%02d", bday.year, bday.month, bday.day);
+
+ return str;
+}
+
+char *card_timezn_str (CardTimeZone timezn)
+{
+ char *str;
+
+ str = malloc (7);
+ snprintf (str, 7, (timezn.sign == -1)? "-%02d:%02d" : "%02d:%02d",
+ timezn.hours, timezn.mins);
+ return str;
+}
+
+char *card_geopos_str (CardGeoPos geopos)
+{
+ char *str;
+
+ str = malloc (15);
+ snprintf (str, 15, "%03.02f,%03.02f", geopos.lon, geopos.lat);
+ return str;
+}
+
+
+static VObject *
+card_convert_to_vobject (Card *crd)
+{
+ VObject *vobj, *vprop;
+
+ vobj = newVObject (VCCardProp);
+
+ add_CardStrProperty (vobj, VCFullNameProp, &crd->fname);
+ if (crd->name.prop.used) {
+ vprop = addProp (vobj, VCNameProp);
+ add_strProp (vprop, VCFamilyNameProp, crd->name.family);
+ add_strProp (vprop, VCGivenNameProp, crd->name.given);
+ add_strProp (vprop, VCAdditionalNamesProp, crd->name.additional);
+ add_strProp (vprop, VCNamePrefixesProp, crd->name.prefix);
+ add_strProp (vprop, VCNameSuffixesProp, crd->name.suffix);
+ add_CardProperty (vprop, &crd->name.prop);
+ }
+
+ if (crd->photo.prop.used) {
+ vprop = addPropSizedValue (vobj, VCPhotoProp,
+ crd->photo.data, crd->photo.size);
+ add_PhotoType (vprop, crd->photo.type);
+ add_CardProperty (vprop, &crd->photo.prop);
+ }
+
+ if (crd->bday.prop.used) {
+ char *date_str;
+
+ date_str = card_bday_str (crd->bday);
+ vprop = addPropValue (vobj, VCBirthDateProp, date_str);
+ free (date_str);
+ add_CardProperty (vprop, &crd->bday.prop);
+ }
+
+ if (crd->xtension.l) {
+ GList *node;
+
+ for (node = crd->xtension.l; node; node = node->next) {
+ CardXProperty *xp = (CardXProperty *) node->data;
+ addPropValue (vobj, xp->name, xp->data);
+ add_CardProperty (vobj, &xp->prop);
+ }
+ }
+
+
+ if (crd->deladdr.l) {
+ GList *node;
+
+ for (node = crd->deladdr.l; node; node = node->next) {
+ CardDelAddr *deladdr = (CardDelAddr *) node->data;
+
+ if (deladdr->prop.used) {
+ vprop = addProp (vobj, VCAdrProp);
+ add_AddrType (vprop, deladdr->type);
+ add_strProp (vprop, VCPostalBoxProp, deladdr->po);
+ add_strProp (vprop, VCExtAddressProp,deladdr->ext);
+ add_strProp (vprop, VCStreetAddressProp,deladdr->street);
+ add_strProp (vprop, VCCityProp, deladdr->city);
+ add_strProp (vprop, VCRegionProp, deladdr->region);
+ add_strProp (vprop, VCPostalCodeProp, deladdr->code);
+ add_strProp (vprop, VCCountryNameProp, deladdr->country);
+ add_CardProperty (vprop, &deladdr->prop);
+ }
+ }
+ }
+
+ if (crd->dellabel.l) {
+ GList *node;
+
+ for (node = crd->dellabel.l; node; node = node->next) {
+ CardDelLabel *dellabel = (CardDelLabel *) node->data;
+
+ vprop = add_strProp (vobj, VCDeliveryLabelProp,
+ dellabel->data);
+ add_AddrType (vprop, dellabel->type);
+ add_CardProperty (vprop, &dellabel->prop);
+ }
+ }
+
+ if (crd->phone.l) {
+ GList *node;
+
+ for (node = crd->phone.l; node; node = node->next) {
+ CardPhone *phone = (CardPhone *) node->data;
+
+ if (phone->prop.used) {
+ vprop = add_strProp (vobj, VCTelephoneProp,
+ (phone->data)?
+ phone->data: "");
+ add_PhoneType (vprop, phone->type);
+ add_CardProperty (vprop, &phone->prop);
+ }
+ }
+ }
+
+ if (crd->email.l) {
+ GList *node;
+
+ for (node = crd->email.l; node; node = node->next) {
+ CardEMail *email = (CardEMail *) node->data;
+
+ if (email->prop.used) {
+ vprop = add_strProp (vobj, VCEmailAddressProp,
+ email->data);
+ add_EMailType (vprop, email->type);
+ add_CardProperty (vprop, &email->prop);
+ }
+ }
+ }
+
+ add_CardStrProperty (vobj, VCMailerProp, &crd->mailer);
+
+ if (crd->timezn.prop.used) {
+ char *str;
+
+ str = card_timezn_str (crd->timezn);
+ vprop = addPropValue (vobj, VCTimeZoneProp, str);
+ free (str);
+ add_CardProperty (vprop, &crd->timezn.prop);
+ }
+
+ if (crd->geopos.prop.used) {
+ char *str;
+
+ str = card_geopos_str (crd->geopos);
+ vprop = addPropValue (vobj, VCGeoLocationProp, str);
+ free (str);
+ add_CardProperty (vprop, &crd->geopos.prop);
+ }
+
+ add_CardStrProperty (vobj, VCTitleProp, &crd->title);
+ add_CardStrProperty (vobj, VCBusinessRoleProp, &crd->role);
+
+ if (crd->logo.prop.used) {
+ vprop = addPropSizedValue (vobj, VCLogoProp,
+ crd->logo.data, crd->logo.size);
+ add_PhotoType (vprop, crd->logo.type);
+ add_CardProperty (vprop, &crd->logo.prop);
+ }
+
+ if (crd->agent)
+ addVObjectProp (vobj, card_convert_to_vobject (crd->agent));
+
+ if (crd->org.prop.used) {
+ vprop = addProp (vobj, VCOrgProp);
+ add_strProp (vprop, VCOrgNameProp, crd->org.name);
+ add_strProp (vprop, VCOrgUnitProp, crd->org.unit1);
+ add_strProp (vprop, VCOrgUnit2Prop, crd->org.unit2);
+ add_strProp (vprop, VCOrgUnit3Prop, crd->org.unit3);
+ add_strProp (vprop, VCOrgUnit4Prop, crd->org.unit4);
+ add_CardProperty (vprop, &crd->org.prop);
+ }
+
+ add_CardStrProperty (vobj, VCCategoriesProp, &crd->categories);
+ add_CardStrProperty (vobj, VCCommentProp, &crd->comment);
+
+ if (crd->sound.prop.used) {
+ if (crd->sound.type != SOUND_PHONETIC)
+ vprop = addPropSizedValue (vobj, VCPronunciationProp,
+ crd->sound.data, crd->sound.size);
+ else
+ vprop = addPropValue (vobj, VCPronunciationProp,
+ crd->sound.data);
+
+ add_SoundType (vprop, crd->sound.type);
+ add_CardProperty (vprop, &crd->sound.prop);
+ }
+
+ add_CardStrProperty (vobj, VCURLProp, &crd->url);
+ add_CardStrProperty (vobj, VCUniqueStringProp, &crd->uid);
+
+ if (crd->key.prop.used) {
+ vprop = addPropValue (vobj, VCPublicKeyProp, crd->key.data);
+ add_KeyType (vprop, crd->key.type);
+ add_CardProperty (vprop, &crd->key.prop);
+ }
+
+ return vobj;
+}
+
+static void add_CardStrProperty_to_string (GString *string, char *prop_name,
+ CardStrProperty *strprop)
+{
+ if (strprop->prop.used) {
+ if (prop_name)
+ g_string_append (string, prop_name);
+
+ g_string_append (string, strprop->str);
+ }
+}
+
+static void add_strProp_to_string (GString *string, char *prop_name, char *val)
+{
+ if (val) {
+ if (prop_name)
+ g_string_append (string, prop_name);
+
+ g_string_append (string, val);
+ }
+}
+
+static void addProp_to_string (GString *string, char *prop_name)
+{
+ if (prop_name)
+ g_string_append (string, prop_name);
+}
+
+char *
+card_to_string (Card *crd)
+{
+ GString *string;
+ char *ret;
+
+ string = g_string_new ("");
+
+ add_CardStrProperty_to_string (string, _ ("Card: "), &crd->fname);
+ if (crd->name.prop.used) {
+ addProp_to_string (string, _ ("\nName: "));
+ add_strProp_to_string (string, _ ("\n Prefix: "), crd->name.prefix);
+ add_strProp_to_string (string, _ ("\n Given: "), crd->name.given);
+ add_strProp_to_string (string, _ ("\n Additional: "), crd->name.additional);
+ add_strProp_to_string (string, _ ("\n Family: "), crd->name.family);
+ add_strProp_to_string (string, _ ("\n Suffix: "), crd->name.suffix);
+ g_string_append_c (string, '\n');
+ }
+
+/* if (crd->photo.prop.used) {
+ addPropSizedValue (string, _ ("\nPhoto: "),
+ crd->photo.data, crd->photo.size);
+ add_PhotoType (string, crd->photo.type);
+ }*/
+
+ if (crd->bday.prop.used) {
+ char *date_str;
+
+ date_str = card_bday_str (crd->bday);
+ add_strProp_to_string (string, _ ("\nBirth Date: "), date_str);
+ free (date_str);
+ }
+
+ if (crd->deladdr.l) {
+ GList *node;
+
+ for (node = crd->deladdr.l; node; node = node->next) {
+ CardDelAddr *deladdr = (CardDelAddr *) node->data;
+
+ if (deladdr->prop.used) {
+ addProp_to_string (string, _ ("\nAddress:"));
+ add_strAddrType (string, deladdr->type);
+ add_strProp_to_string (string, _ ("\n Postal Box: "), deladdr->po);
+ add_strProp_to_string (string, _ ("\n Ext: "),deladdr->ext);
+ add_strProp_to_string (string, _ ("\n Street: "),deladdr->street);
+ add_strProp_to_string (string, _ ("\n City: "), deladdr->city);
+ add_strProp_to_string (string, _ ("\n Region: "), deladdr->region);
+ add_strProp_to_string (string, _ ("\n Postal Code: "), deladdr->code);
+ add_strProp_to_string (string, _ ("\n Country: "), deladdr->country);
+ }
+ }
+
+ g_string_append_c (string, '\n');
+ }
+
+ if (crd->dellabel.l) {
+ GList *node;
+
+ for (node = crd->dellabel.l; node; node = node->next) {
+ CardDelLabel *dellabel = (CardDelLabel *) node->data;
+
+ add_strProp_to_string (string, _ ("\nDelivery Label: "),
+ dellabel->data);
+ add_strAddrType (string, dellabel->type);
+ }
+ }
+
+ if (crd->phone.l) {
+ GList *node;
+ char *sep;
+
+ if (crd->phone.l->next) {
+ sep = " ";
+ g_string_append (string, _ ("\nTelephones:\n"));
+ } else {
+ sep = " ";
+ g_string_append (string, _ ("\nTelephone:"));
+ }
+
+ for (node = crd->phone.l; node; node = node->next) {
+ CardPhone *phone = (CardPhone *) node->data;
+
+ if (phone->prop.used) {
+ g_string_append (string, sep);
+ g_string_append (string, phone->data);
+ add_strPhoneType (string, phone->type);
+ g_string_append_c (string, '\n');
+ }
+ }
+
+ if (crd->phone.l->next)
+ g_string_append_c (string, '\n');
+ }
+
+ if (crd->email.l) {
+ GList *node;
+ char *sep;
+
+ if (crd->email.l->next) {
+ sep = " ";
+ g_string_append (string, _ ("\nE-mail:\n"));
+ } else {
+ sep = " ";
+ g_string_append (string, _ ("\nE-mail:"));
+ }
+
+
+ for (node = crd->email.l; node; node = node->next) {
+ CardEMail *email = (CardEMail *) node->data;
+
+ if (email->prop.used) {
+ g_string_append (string, sep);
+ g_string_append (string, email->data);
+ add_strEMailType (string, email->type);
+ g_string_append_c (string, '\n');
+ }
+ }
+
+ if (crd->email.l->next)
+ g_string_append_c (string, '\n');
+ }
+
+ add_CardStrProperty_to_string (string, _ ("\nMailer: "), &crd->mailer);
+
+ if (crd->timezn.prop.used) {
+ char *str;
+
+ str = card_timezn_str (crd->timezn);
+ add_strProp_to_string (string, _ ("\nTime Zone: "), str);
+ free (str);
+ }
+
+ if (crd->geopos.prop.used) {
+ char *str;
+
+ str = card_geopos_str (crd->geopos);
+ add_strProp_to_string (string, _ ("\nGeo Location: "), str);
+ free (str);
+ }
+
+ add_CardStrProperty_to_string (string, _ ("\nTitle: "), &crd->title);
+ add_CardStrProperty_to_string (string, _ ("\nBusiness Role: "), &crd->role);
+
+/* if (crd->logo.prop.used) {
+ addPropSizedValue (string, _ ("\nLogo: "),
+ crd->logo.data, crd->logo.size);
+ add_PhotoType (string, crd->logo.type);
+ }*/
+
+/* if (crd->agent)
+ addstringectProp (string, card_convert_to_stringect (crd->agent));*/
+
+ if (crd->org.prop.used) {
+ addProp_to_string (string, _ ("\nOrg: "));
+ add_strProp_to_string (string, _ ("\n Name: "), crd->org.name);
+ add_strProp_to_string (string, _ ("\n Unit: "), crd->org.unit1);
+ add_strProp_to_string (string, _ ("\n Unit2: "), crd->org.unit2);
+ add_strProp_to_string (string, _ ("\n Unit3: "), crd->org.unit3);
+ add_strProp_to_string (string, _ ("\n Unit4: "), crd->org.unit4);
+ g_string_append_c (string, '\n');
+ }
+
+ add_CardStrProperty_to_string (string, _ ("\nCategories: "), &crd->categories);
+ add_CardStrProperty_to_string (string, _ ("\nComment: "), &crd->comment);
+
+/* if (crd->sound.prop.used) {
+ if (crd->sound.type != SOUND_PHONETIC)
+ addPropSizedValue (string, _ ("\nPronunciation: "),
+ crd->sound.data, crd->sound.size);
+ else
+ add_strProp_to_string (string, _ ("\nPronunciation: "),
+ crd->sound.data);
+
+ add_SoundType (string, crd->sound.type);
+ }*/
+
+ add_CardStrProperty_to_string (string, _ ("\nURL: "), &crd->url);
+ add_CardStrProperty_to_string (string, _ ("\nUnique String: "), &crd->uid);
+
+ if (crd->key.prop.used) {
+ add_strProp_to_string (string, _ ("\nPublic Key: "), crd->key.data);
+ add_strKeyType (string, crd->key.type);
+ }
+
+ ret = g_strdup (string->str);
+ g_string_free (string, TRUE);
+
+ return ret;
+}
+
+char *
+card_to_vobj_string (Card *crd)
+{
+ VObject *object;
+ char *data, *ret_val;
+
+ g_assert (crd != NULL);
+
+ object = card_convert_to_vobject (crd);
+ data = writeMemVObject (0, 0, object);
+ ret_val = g_strdup (data);
+ free (data);
+
+ cleanVObject (object);
+
+ return ret_val;
+}
+
+void
+card_save (Card *crd, FILE *fp)
+{
+ VObject *object;
+
+ g_return_if_fail (crd != NULL);
+
+ object = card_convert_to_vobject (crd);
+ writeVObject (fp, object);
+ cleanVObject (object);
+}
diff --git a/addressbook/backend/ebook/e-card.h b/addressbook/backend/ebook/e-card.h
index 7959377695..516cb85017 100644
--- a/addressbook/backend/ebook/e-card.h
+++ b/addressbook/backend/ebook/e-card.h
@@ -1,51 +1,79 @@
/*
- * Author:
+ * Authors:
+ * Arturo Espinosa
* Nat Friedman (nat@helixcode.com)
*
- * Copyright 1999, Helix Code, Inc.
+ * Copyright (C) 2000 Helix Code, Inc.
+ * Copyright (C) 1999 The Free Software Foundation
*/
#ifndef __E_CARD_H__
#define __E_CARD_H__
-#include <gtk/gtkobject.h>
-#include <libgnome/gnome-defs.h>
-#include <ebook/e-card-fields.h>
+#include <time.h>
+#include <glib.h>
+#include <stdio.h>
+#include <e-card-types.h>
-BEGIN_GNOME_DECLS
+typedef struct _ECard ECard;
-typedef struct _ECardPrivate ECardPrivate;
+struct _ECard {
-typedef struct {
- GtkObject parent;
- ECardPrivate *priv;
-} ECard;
+ char *fname; /* The full name. */
+ ECardName *name; /* The structured name. */
-typedef struct {
- GtkObjectClass parent;
-} ECardClass;
+ GList *del_addrs; /* Delivery addresses (ECardAddr *) */
+ GList *del_labels; /* Delivery address labels
+ * (ECardAddrLabel *) */
+ GList *phone; /* Phone numbers (ECardPhone *) */
+ GList *email; /* Email addresses (char *) */
+ char *url; /* The person's web page. */
+
+ ECardDate *bday; /* The person's birthday. */
-ECard *e_card_new (void);
-GtkType e_card_get_type (void);
+ ECardOrg *org; /* The person's organization. */
+ char *title; /* The person's title w/in his org */
+ char *role; /* The person's role w/in his org */
+ ECardPhoto *logo; /* This person's org's logo. */
-char *e_card_get_string (ECard *card,
- char *field);
-void e_card_set_string (ECard *card,
- char *field,
- char *value);
+ ECardPhoto *photo; /* A photo of the person. */
+
+ ECard *agent; /* A person who sereves as this
+ guy's agent/secretary/etc. */
+
-gboolean e_card_get_boolean (ECard *card,
- char *field);
-void e_card_set_boolean (ECard *card,
- char *field,
- gboolean value);
+ char *categories; /* A list of the categories to which
+ this card belongs. */
+
+ char *comment; /* An unstructured comment string. */
-#define E_CARD_TYPE (e_card_get_type ())
-#define E_CARD(o) (GTK_CHECK_CAST ((o), E_CARD_TYPE, ECard))
-#define E_CARD_CLASS(k) (GTK_CHECK_CLASS_CAST((k), E_CARD_TYPE, ECardClass))
-#define E_IS_CARD(o) (GTK_CHECK_TYPE ((o), E_CARD_TYPE))
-#define E_IS_CARD_CLASS(k) (GTK_CHECK_CLASS_TYPE ((k), E_CARD_TYPE))
+ ECardSound *sound;
+
+ ECardKey *key; /* The person's public key. */
+ ECardTimeZone *timezn; /* The person's time zone. */
+ ECardGeoPos *geopos; /* The person's long/lat. */
-END_GNOME_DECLS
+ char *mailer; /* The user's mailer. */
+
+ char *uid; /* This card's unique identifier. */
+ ECardRev *rev; /* The time this card was last
+ modified. */
+
+ CardList xtension;
+};
+
+Card *card_new (void);
+void card_free (Card *crd);
+void card_prop_free (CardProperty prop);
+CardProperty card_prop_empty (void);
+int card_check_prop (CardProperty prop);
+GList *card_load (GList *crdlist, char *fname);
+void card_save (Card *crd, FILE *fp);
+char *card_to_vobj_string (Card *card);
+char *card_to_string (Card *card);
+
+char *card_bday_str (CardBDay bday);
+char *card_timezn_str (CardTimeZone timezn);
+char *card_geopos_str (CardGeoPos geopos);
#endif /* ! __E_CARD_H__ */