diff options
Diffstat (limited to 'addressbook/backend/ebook')
-rw-r--r-- | addressbook/backend/ebook/Makefile.am | 29 | ||||
-rw-r--r-- | addressbook/backend/ebook/TODO | 2 | ||||
-rw-r--r-- | addressbook/backend/ebook/e-book-listener.c | 432 | ||||
-rw-r--r-- | addressbook/backend/ebook/e-book-listener.h | 83 | ||||
-rw-r--r-- | addressbook/backend/ebook/e-book.c | 821 | ||||
-rw-r--r-- | addressbook/backend/ebook/e-book.h | 89 | ||||
-rw-r--r-- | addressbook/backend/ebook/e-card-pairs.h | 139 | ||||
-rw-r--r-- | addressbook/backend/ebook/e-card-types.h | 246 | ||||
-rw-r--r-- | addressbook/backend/ebook/e-card.c | 1856 | ||||
-rw-r--r-- | addressbook/backend/ebook/e-card.h | 92 |
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__ */ |