aboutsummaryrefslogtreecommitdiffstats
path: root/addressbook
diff options
context:
space:
mode:
authorJon Trowbridge <trow@ximian.com>2001-07-07 14:38:52 +0800
committerJon Trowbridge <trow@src.gnome.org>2001-07-07 14:38:52 +0800
commitda9c4d10641eed27263f12c7415100348991ef32 (patch)
tree50428b4e028ce83e81502b142920753bb61a2a31 /addressbook
parent5304dda169dd9778def88176572bb76eeaf0883b (diff)
downloadgsoc2013-evolution-da9c4d10641eed27263f12c7415100348991ef32.tar.gz
gsoc2013-evolution-da9c4d10641eed27263f12c7415100348991ef32.tar.zst
gsoc2013-evolution-da9c4d10641eed27263f12c7415100348991ef32.zip
Detect the embedded EDestination XML, and convert it to a nice-looking
2001-07-07 Jon Trowbridge <trow@ximian.com> * gui/widgets/e-minicard.c (add_field): Detect the embedded EDestination XML, and convert it to a nice-looking e-mail address. * gui/contact-list-editor/e-contact-list-editor.c: Adjusted to reflect changes to EContactListModel. (Yeah, this is vague, but the changes are _really_ obvious and boring.) * gui/contact-list-editor/e-contact-list-model.c: Revamped to make everything an EDestination, rather than storing either cards or strings. * gui/component/select-names/e-select-names-text-model.c (e_select_names_text_model_insert_length): Use e_destination_get_textrep. * gui/component/select-names/e-select-names-table-model.c (fill_in_info): Use e_destination_get_name and e_destination_get_email. * gui/component/select-names/e-select-names-popup.c (popup_menu_card): Use e_destination_get_name instead of e_card_name_to_string. (quick_add_cb): Use e_destination_get_address. (popup_menu_nocard): Use e_destination_get_name. * gui/component/select-names/e-select-names-model.c (e_select_names_model_changed): Removed obsolete debugging code. (e_select_names_model_get_textification): Use e_destination_get_textrep\. (e_select_names_model_get_address_text): Use e_destination_get_address. (e_select_names_model_get_string): Use e_destination_get_textrep. (e_select_names_model_replace): Use e_destination_get_textrep. (e_select_names_model_name_pos): Use e_destination_get_textrep. * gui/component/select-names/e-select-names-completion.c (emailify_match): Match only if this isn't a contact list. (match_email): Match only if this isn't a contact list. (match_name): Do the right thing in the case of a contact list. (book_query_process_card_list): Don't construct a match for each possible e-mail address if this is a contact list. * backend/ebook/e-destination.c: Major-league de-crufting and rationalization, combined with lots of hacks to make things work properly with contact lists. (e_destination_copy): Copy contact list info. (e_destination_clear_card): Clear contact list info. (e_destination_is_empty): If we contain a contact list, we aren't empty. (e_destination_set_card_uri): Added. Allows us to set a destination by card URI. (e_destination_set_name): Allows the contact's name only ("Jane Smith") to be set. (e_destination_set_email): Allows the contact's e-mail only ("jane@assbarn.com") to be set. (e_destination_set_string): Takes a free-form string containing a contact's name and/or e-mail, and tries to do the right thing with it. (e_destination_contains_card): Renamed. Used to be e_destination_has_card. (e_destination_from_card): Added. Returns TRUE if the EDestination comes from either a ECard (which we presently hold) or is specified by an ECard URI. (e_destination_use_card): Allows an EDestination's ECard to be accessed, via a callback. If we only are holding the URI, the card will be loaded and stored in the EDestination. (e_destination_get_name): Returns the name only ("Jane Smith"), or NULL. (e_destination_get_email): Returns the email only ("jane@assbarn.com"), or NULL. (e_destination_get_address): Added. Returns a "full address" if both the name & e-mail are available ("Jane Smith <jane@assbarn.com>"), or just the e-mail if the name is unknown ("jane@assbarn.com>"). If the destination is a contact list, returns a comma-separated list of addresses. (e_destination_get_textrep): Added. Returns a "text representation" of the EDestination. This is what is now displayed for completed, "cardified" destinations in addressbook entries. (e_destination_is_evolution_list): Check to see if this destination is for a contact list. (e_destination_xml_encode): Added. Build an XML data structure representing an EDestination. (e_destination_xml_decode): Added. Parse an XML data structure, constructing an EDestination. (e_destination_export): Added. Returns a null-terminated string containing an XML representation of the EDestination, with newlines and excess whitespace removed. (e_destination_import): Added. Parses a string containing an XML representation of an EDestination. (e_destination_exportv): Added. Returns a null-terminated string containing an XML representation of a collection of EDestinations, with newlines and excess whitespace removed. (e_destination_importv): Added. Takes an XML representation of a collection of destinations, parses it, and returns a vector of EDestinations. * backend/ebook/e-card.c (e_card_duplicate): Copy the ->book pointer. (e_card_get_id): Check that the argument is valid. (e_card_set_id): Check that the argument is valid. (e_card_get_book): Added. Return the EBook the ECard came from. (e_card_get_uri): Added. Tries to returns a URI for the ECard, which is of the form (EBook URI)/(ECard unique ID). Returns NULL if the EBook URI or the ID are unknown/not set. (e_card_get_vobject): If we have the URI, use it as the VCUniqueStringProp, rather than just the ID. This is a hack to make DnD work properly. (parse_id): Detect if the unique ID we've been passed is a URI or just a plain card ID, and do the right thing in either case. (e_card_uri_extract_book_uri): Added. Convenience function for parsing card URIs. (e_card_uri_extract_card_id): Added. Convenience function for parsing card URIs. (e_card_load_uri): Added. Allows an ECard to be loaded by its URI. * backend/ebook/e-book-view.c: Added a EBook * to the _EBookViewPrivate struct. This is meant to contain the EBook the EBookView is associated with. (add_book_iterator): Added. A convenience function for attaching the EBook to a GList of cards (if no EBook is already stored). (e_book_view_do_added_event): Record the EBook in the added ECards. (e_book_view_do_modified_event): Record the EBook in the modified ECards. (e_book_view_set_book): Added. Stores a pointer to the EBookView's "parent" EBook. (e_book_view_init): Init book_view->priv->book to NULL. (e_book_view_destroy): Unref book_view->priv->book. * backend/ebook/e-book.c: Added a uri field to _EBookPrivate. (e_book_unqueue_op): Removed debugging spew. (e_book_do_response_get_view): Attach the current EBook to the created EBookView. (e_book_do_response_get_changes): Attach the current EBook to the created EBookView. (e_book_load_uri): Save a copy of the uri in the EBook. (e_book_get_uri): Added. Just returns book->priv->uri. (e_book_get_card): Attach a pointer to the Ebook to the newly-loaded ECard. (e_book_add_card): Attach a pointer to the EBook to the newly-added ECard. (e_book_commit_card): Attach a pointer to the EBook to the committed ECard. (e_book_init): Initialize the uri to NULL. (e_book_destroy): Free the uri string on destruction. svn path=/trunk/; revision=10882
Diffstat (limited to 'addressbook')
-rw-r--r--addressbook/ChangeLog148
-rw-r--r--addressbook/backend/ebook/e-book-view.c37
-rw-r--r--addressbook/backend/ebook/e-book-view.h5
-rw-r--r--addressbook/backend/ebook/e-book.c37
-rw-r--r--addressbook/backend/ebook/e-book.h2
-rw-r--r--addressbook/backend/ebook/e-card-simple.c7
-rw-r--r--addressbook/backend/ebook/e-card.c144
-rw-r--r--addressbook/backend/ebook/e-card.h15
-rw-r--r--addressbook/backend/ebook/e-destination.c874
-rw-r--r--addressbook/backend/ebook/e-destination.h27
10 files changed, 922 insertions, 374 deletions
diff --git a/addressbook/ChangeLog b/addressbook/ChangeLog
index 9a2fcaf41e..e355eb6e52 100644
--- a/addressbook/ChangeLog
+++ b/addressbook/ChangeLog
@@ -1,3 +1,151 @@
+2001-07-07 Jon Trowbridge <trow@ximian.com>
+
+ * gui/widgets/e-minicard.c (add_field): Detect the embedded
+ EDestination XML, and convert it to a nice-looking e-mail address.
+
+ * gui/contact-list-editor/e-contact-list-editor.c: Adjusted to
+ reflect changes to EContactListModel. (Yeah, this is vague,
+ but the changes are _really_ obvious and boring.)
+
+ * gui/contact-list-editor/e-contact-list-model.c: Revamped
+ to make everything an EDestination, rather than storing either
+ cards or strings.
+
+ * gui/component/select-names/e-select-names-text-model.c
+ (e_select_names_text_model_insert_length): Use
+ e_destination_get_textrep.
+
+ * gui/component/select-names/e-select-names-table-model.c
+ (fill_in_info): Use e_destination_get_name and
+ e_destination_get_email.
+
+ * gui/component/select-names/e-select-names-popup.c
+ (popup_menu_card): Use e_destination_get_name instead of
+ e_card_name_to_string.
+ (quick_add_cb): Use e_destination_get_address.
+ (popup_menu_nocard): Use e_destination_get_name.
+
+ * gui/component/select-names/e-select-names-model.c
+ (e_select_names_model_changed): Removed obsolete debugging code.
+ (e_select_names_model_get_textification): Use e_destination_get_textrep.
+ (e_select_names_model_get_address_text): Use e_destination_get_address.
+ (e_select_names_model_get_string): Use e_destination_get_textrep.
+ (e_select_names_model_replace): Use e_destination_get_textrep.
+ (e_select_names_model_name_pos): Use e_destination_get_textrep.
+
+ * gui/component/select-names/e-select-names-completion.c
+ (emailify_match): Match only if this isn't a contact list.
+ (match_email): Match only if this isn't a contact list.
+ (match_name): Do the right thing in the case of a contact list.
+ (book_query_process_card_list): Don't construct a match for
+ each possible e-mail address if this is a contact list.
+
+ * backend/ebook/e-destination.c: Major-league de-crufting and
+ rationalization, combined with lots of hacks to make things work
+ properly with contact lists.
+ (e_destination_copy): Copy contact list info.
+ (e_destination_clear_card): Clear contact list info.
+ (e_destination_is_empty): If we contain a contact list, we aren't
+ empty.
+ (e_destination_set_card_uri): Added. Allows us to set a
+ destination by card URI.
+ (e_destination_set_name): Allows the contact's name only ("Jane
+ Smith") to be set.
+ (e_destination_set_email): Allows the contact's e-mail only
+ ("jane@assbarn.com") to be set.
+ (e_destination_set_string): Takes a free-form string containing a
+ contact's name and/or e-mail, and tries to do the right thing with
+ it.
+ (e_destination_contains_card): Renamed. Used to be
+ e_destination_has_card.
+ (e_destination_from_card): Added. Returns TRUE if the
+ EDestination comes from either a ECard (which we presently hold)
+ or is specified by an ECard URI.
+ (e_destination_use_card): Allows an EDestination's ECard to be
+ accessed, via a callback. If we only are holding the URI, the
+ card will be loaded and stored in the EDestination.
+ (e_destination_get_name): Returns the name only ("Jane Smith"), or
+ NULL.
+ (e_destination_get_email): Returns the email only
+ ("jane@assbarn.com"), or NULL.
+ (e_destination_get_address): Added. Returns a "full address" if
+ both the name & e-mail are available ("Jane Smith
+ <jane@assbarn.com>"), or just the e-mail if the name is unknown
+ ("jane@assbarn.com>"). If the destination is a contact list,
+ returns a comma-separated list of addresses.
+ (e_destination_get_textrep): Added. Returns a "text
+ representation" of the EDestination. This is what is now
+ displayed for completed, "cardified" destinations in addressbook
+ entries.
+ (e_destination_is_evolution_list): Check to see if this
+ destination is for a contact list.
+ (e_destination_xml_encode): Added. Build an XML data structure
+ representing an EDestination.
+ (e_destination_xml_decode): Added. Parse an XML data structure,
+ constructing an EDestination.
+ (e_destination_export): Added. Returns a null-terminated string
+ containing an XML representation of the EDestination, with
+ newlines and excess whitespace removed.
+ (e_destination_import): Added. Parses a string containing an XML
+ representation of an EDestination.
+ (e_destination_exportv): Added. Returns a null-terminated string
+ containing an XML representation of a collection of EDestinations,
+ with newlines and excess whitespace removed.
+ (e_destination_importv): Added. Takes an XML representation of a
+ collection of destinations, parses it, and returns a vector of
+ EDestinations.
+
+ * backend/ebook/e-card.c (e_card_duplicate): Copy the ->book
+ pointer.
+ (e_card_get_id): Check that the argument is valid.
+ (e_card_set_id): Check that the argument is valid.
+ (e_card_get_book): Added. Return the EBook the ECard came from.
+ (e_card_get_uri): Added. Tries to returns a URI for the ECard,
+ which is of the form (EBook URI)/(ECard unique ID). Returns NULL
+ if the EBook URI or the ID are unknown/not set.
+ (e_card_get_vobject): If we have the URI, use it as the
+ VCUniqueStringProp, rather than just the ID. This is a hack to
+ make DnD work properly.
+ (parse_id): Detect if the unique ID we've been passed is a URI or
+ just a plain card ID, and do the right thing in either case.
+ (e_card_uri_extract_book_uri): Added. Convenience function for
+ parsing card URIs.
+ (e_card_uri_extract_card_id): Added. Convenience function for
+ parsing card URIs.
+ (e_card_load_uri): Added. Allows an ECard to be loaded by its
+ URI.
+
+ * backend/ebook/e-book-view.c: Added a EBook * to the
+ _EBookViewPrivate struct. This is meant to contain the EBook the
+ EBookView is associated with.
+ (add_book_iterator): Added. A convenience function for attaching
+ the EBook to a GList of cards (if no EBook is already stored).
+ (e_book_view_do_added_event): Record the EBook in the added
+ ECards.
+ (e_book_view_do_modified_event): Record the EBook in the modified
+ ECards.
+ (e_book_view_set_book): Added. Stores a pointer to the
+ EBookView's "parent" EBook.
+ (e_book_view_init): Init book_view->priv->book to NULL.
+ (e_book_view_destroy): Unref book_view->priv->book.
+
+ * backend/ebook/e-book.c: Added a uri field to _EBookPrivate.
+ (e_book_unqueue_op): Removed debugging spew.
+ (e_book_do_response_get_view): Attach the current EBook to the
+ created EBookView.
+ (e_book_do_response_get_changes): Attach the current EBook to the
+ created EBookView.
+ (e_book_load_uri): Save a copy of the uri in the EBook.
+ (e_book_get_uri): Added. Just returns book->priv->uri.
+ (e_book_get_card): Attach a pointer to the Ebook to the
+ newly-loaded ECard.
+ (e_book_add_card): Attach a pointer to the EBook to the
+ newly-added ECard.
+ (e_book_commit_card): Attach a pointer to the EBook to the
+ committed ECard.
+ (e_book_init): Initialize the uri to NULL.
+ (e_book_destroy): Free the uri string on destruction.
+
2001-07-06 Ettore Perazzoli <ettore@ximian.com>
* gui/component/addressbook-component.c (populate_context_menu):
diff --git a/addressbook/backend/ebook/e-book-view.c b/addressbook/backend/ebook/e-book-view.c
index 2a9f3f2f53..7dbe7d46fb 100644
--- a/addressbook/backend/ebook/e-book-view.c
+++ b/addressbook/backend/ebook/e-book-view.c
@@ -16,11 +16,14 @@
#include "e-card-cursor.h"
#include "e-book-view-listener.h"
#include "e-book-view.h"
+#include "e-book.h"
GtkObjectClass *e_book_view_parent_class;
struct _EBookViewPrivate {
GNOME_Evolution_Addressbook_BookView corba_book_view;
+
+ EBook *book;
EBookViewListener *listener;
@@ -39,9 +42,24 @@ enum {
static guint e_book_view_signals [LAST_SIGNAL];
static void
+add_book_iterator (gpointer data, gpointer closure)
+{
+ ECard *card = E_CARD (data);
+ EBook *book = E_BOOK (closure);
+
+ if (card->book == NULL) {
+ card->book = book;
+ gtk_object_ref (GTK_OBJECT (book));
+ }
+}
+
+static void
e_book_view_do_added_event (EBookView *book_view,
EBookViewListenerResponse *resp)
{
+ if (book_view->priv->book)
+ g_list_foreach (resp->cards, add_book_iterator, book_view->priv->book);
+
gtk_signal_emit (GTK_OBJECT (book_view), e_book_view_signals [CARD_ADDED],
resp->cards);
@@ -53,6 +71,9 @@ static void
e_book_view_do_modified_event (EBookView *book_view,
EBookViewListenerResponse *resp)
{
+ if (book_view->priv->book)
+ g_list_foreach (resp->cards, add_book_iterator, book_view->priv->book);
+
gtk_signal_emit (GTK_OBJECT (book_view), e_book_view_signals [CARD_CHANGED],
resp->cards);
@@ -178,10 +199,22 @@ e_book_view_new (GNOME_Evolution_Addressbook_BookView corba_book_view, EBookView
return book_view;
}
+void
+e_book_view_set_book (EBookView *book_view, EBook *book)
+{
+ g_return_if_fail (book_view && E_IS_BOOK_VIEW (book_view));
+ g_return_if_fail (book && E_IS_BOOK (book));
+ g_return_if_fail (book_view->priv->book == NULL);
+
+ book_view->priv->book = book;
+ gtk_object_ref (GTK_OBJECT (book));
+}
+
static void
e_book_view_init (EBookView *book_view)
{
book_view->priv = g_new0 (EBookViewPrivate, 1);
+ book_view->priv->book = NULL;
book_view->priv->corba_book_view = CORBA_OBJECT_NIL;
book_view->priv->listener = NULL;
book_view->priv->responses_queued_id = 0;
@@ -193,6 +226,10 @@ e_book_view_destroy (GtkObject *object)
EBookView *book_view = E_BOOK_VIEW (object);
CORBA_Environment ev;
+ if (book_view->priv->book) {
+ gtk_object_unref (GTK_OBJECT (book_view->priv->book));
+ }
+
if (book_view->priv->corba_book_view) {
CORBA_exception_init (&ev);
diff --git a/addressbook/backend/ebook/e-book-view.h b/addressbook/backend/ebook/e-book-view.h
index 726920f13d..5e576d6642 100644
--- a/addressbook/backend/ebook/e-book-view.h
+++ b/addressbook/backend/ebook/e-book-view.h
@@ -22,6 +22,8 @@ typedef struct _EBookView EBookView;
typedef struct _EBookViewClass EBookViewClass;
typedef struct _EBookViewPrivate EBookViewPrivate;
+struct _EBook; /* Forward reference */
+
struct _EBookView {
GtkObject parent;
EBookViewPrivate *priv;
@@ -44,7 +46,8 @@ struct _EBookViewClass {
EBookView *e_book_view_new (GNOME_Evolution_Addressbook_BookView corba_book_view, EBookViewListener *listener);
GtkType e_book_view_get_type (void);
-void e_book_view_get_book_view_listener (EBookView *book_view);
+
+void e_book_view_set_book (EBookView *book_view, struct _EBook *book);
#define E_BOOK_VIEW_TYPE (e_book_view_get_type ())
#define E_BOOK_VIEW(o) (GTK_CHECK_CAST ((o), E_BOOK_VIEW_TYPE, EBookView))
diff --git a/addressbook/backend/ebook/e-book.c b/addressbook/backend/ebook/e-book.c
index 3078d1d948..5a78fbe595 100644
--- a/addressbook/backend/ebook/e-book.c
+++ b/addressbook/backend/ebook/e-book.c
@@ -45,6 +45,8 @@ struct _EBookPrivate {
GList *pending_ops;
guint op_tag;
+
+ gchar *uri;
};
enum {
@@ -97,8 +99,6 @@ e_book_unqueue_op (EBook *book)
EBookOp *op;
GList *removed;
- g_print ("Unqueue Op\n");
-
removed = g_list_last (book->priv->pending_ops);
if (removed) {
@@ -251,6 +251,7 @@ e_book_do_response_get_view (EBook *book,
}
book_view = e_book_view_new(resp->book_view, op->listener);
+ e_book_view_set_book (book_view, book);
/* Only execute the callback if the operation is still flagged as active (i.e. hasn't
been cancelled. This is mildly wasteful since we unnecessaryily create the
@@ -299,6 +300,7 @@ e_book_do_response_get_changes (EBook *book,
}
book_view = e_book_view_new (resp->book_view, op->listener);
+ e_book_view_set_book (book_view, book);
if (op->cb) {
if (op->active)
@@ -459,6 +461,7 @@ e_book_check_listener_queue (EBookListener *listener, EBook *book)
/**
* e_book_load_uri:
*/
+
gboolean
e_book_load_uri (EBook *book,
const char *uri,
@@ -478,6 +481,9 @@ e_book_load_uri (EBook *book,
return FALSE;
}
+ g_free (book->priv->uri);
+ book->priv->uri = g_strdup (uri);
+
/*
* Create our local BookListener interface.
*/
@@ -489,7 +495,7 @@ e_book_load_uri (EBook *book,
gtk_signal_connect (GTK_OBJECT (book->priv->listener), "responses_queued",
e_book_check_listener_queue, book);
-
+
/*
* Load the addressbook into the PAS.
*/
@@ -558,6 +564,14 @@ e_book_unload_uri (EBook *book)
book->priv->load_state = URINotLoaded;
}
+const char *
+e_book_get_uri (EBook *book)
+{
+ g_return_val_if_fail (book && E_IS_BOOK (book), NULL);
+
+ return book->priv->uri;
+}
+
char *
e_book_get_static_capabilities (EBook *book)
{
@@ -729,6 +743,8 @@ e_book_get_card (EBook *book,
g_free(vcard);
e_card_set_id(card, id);
+ card->book = book;
+ gtk_object_ref (GTK_OBJECT (card->book));
return card;
}
@@ -883,6 +899,11 @@ e_book_add_card (EBook *book,
g_free (vcard);
+ if (card->book && card->book != book)
+ gtk_object_unref (GTK_OBJECT (card->book));
+ card->book = book;
+ gtk_object_ref (GTK_OBJECT (card->book));
+
return retval;
}
@@ -961,6 +982,11 @@ e_book_commit_card (EBook *book,
g_free (vcard);
+ if (card->book && card->book != book)
+ gtk_object_unref (GTK_OBJECT (card->book));
+ card->book = book;
+ gtk_object_ref (GTK_OBJECT (card->book));
+
return retval;
}
@@ -1215,7 +1241,8 @@ e_book_init (EBook *book)
{
book->priv = g_new0 (EBookPrivate, 1);
book->priv->load_state = URINotLoaded;
- book->priv->op_tag = 1;
+ book->priv->op_tag = 1;
+ book->priv->uri = NULL;
}
static void
@@ -1237,6 +1264,8 @@ e_book_destroy (GtkObject *object)
CORBA_exception_init (&ev);
}
+ g_free (book->priv->uri);
+
g_free (book->priv);
GTK_OBJECT_CLASS (e_book_parent_class)->destroy (object);
diff --git a/addressbook/backend/ebook/e-book.h b/addressbook/backend/ebook/e-book.h
index 1deecdb1ed..1c9386cfa7 100644
--- a/addressbook/backend/ebook/e-book.h
+++ b/addressbook/backend/ebook/e-book.h
@@ -60,6 +60,8 @@ gboolean e_book_load_uri (EBook *book,
gpointer closure);
void e_book_unload_uri (EBook *book);
+const char *e_book_get_uri (EBook *book);
+
char *e_book_get_static_capabilities (EBook *book);
guint e_book_get_supported_fields (EBook *book,
diff --git a/addressbook/backend/ebook/e-card-simple.c b/addressbook/backend/ebook/e-card-simple.c
index 2eea743893..a9f33350d5 100644
--- a/addressbook/backend/ebook/e-card-simple.c
+++ b/addressbook/backend/ebook/e-card-simple.c
@@ -237,7 +237,8 @@ e_card_simple_new (ECard *card)
return simple;
}
-ECardSimple *e_card_simple_duplicate(ECardSimple *simple)
+ECardSimple *
+e_card_simple_duplicate(ECardSimple *simple)
{
char *vcard = e_card_simple_get_vcard(simple);
ECard *card = e_card_new(vcard);
@@ -283,8 +284,8 @@ e_card_simple_set_id (ECardSimple *simple, const char *id)
*
* Returns: a string in vcard format, which is wrapped by the @simple.
*/
-char
-*e_card_simple_get_vcard (ECardSimple *simple)
+char *
+e_card_simple_get_vcard (ECardSimple *simple)
{
if (simple->card)
return e_card_get_vcard(simple->card);
diff --git a/addressbook/backend/ebook/e-card.c b/addressbook/backend/ebook/e-card.c
index 044f27be3b..53ba425a48 100644
--- a/addressbook/backend/ebook/e-card.c
+++ b/addressbook/backend/ebook/e-card.c
@@ -28,6 +28,7 @@
#include <libversit/vcc.h>
#include "e-util/ename/e-name-western.h"
#include "e-util/ename/e-address-western.h"
+#include "e-book.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))
@@ -129,6 +130,9 @@ static void set_phone_flags (VObject *vobj, ECardPhoneFlags flags);
static ECardAddressFlags get_address_flags (VObject *vobj);
static void set_address_flags (VObject *vobj, ECardAddressFlags flags);
+static gchar *e_card_uri_extract_book_uri (const gchar *uri);
+static gchar *e_card_uri_extract_card_id (const gchar *uri);
+
typedef void (* ParsePropertyFunc) (ECard *card, VObject *object);
struct {
@@ -234,6 +238,12 @@ e_card_duplicate(ECard *card)
char *vcard = e_card_get_vcard(card);
ECard *new_card = e_card_new(vcard);
g_free (vcard);
+
+ if (card->book) {
+ new_card->book = card->book;
+ gtk_object_ref (GTK_OBJECT (new_card->book));
+ }
+
return new_card;
}
@@ -306,6 +316,8 @@ e_card_touch(ECard *card)
const char *
e_card_get_id (ECard *card)
{
+ g_return_val_if_fail (card && E_IS_CARD (card), NULL);
+
return card->id;
}
@@ -320,11 +332,34 @@ e_card_get_id (ECard *card)
void
e_card_set_id (ECard *card, const char *id)
{
+ g_return_if_fail (card && E_IS_CARD (card));
+
if ( card->id )
g_free(card->id);
card->id = g_strdup(id);
}
+EBook *
+e_card_get_book (ECard *card)
+{
+ g_return_val_if_fail (card && E_IS_CARD (card), NULL);
+
+ return card->book;
+}
+
+const gchar *
+e_card_get_uri (ECard *card)
+{
+ g_return_val_if_fail (card && E_IS_CARD (card), NULL);
+
+ if (card->uri == NULL && card->id && *card->id && card->book) {
+ const char *book_uri = e_book_get_uri (card->book);
+ if (book_uri)
+ card->uri = g_strdup_printf ("%s/%s", book_uri, card->id);
+ }
+ return card->uri;
+}
+
static gchar *
e_card_date_to_string (ECardDate *dt)
{
@@ -341,6 +376,7 @@ static VObject *
e_card_get_vobject (ECard *card)
{
VObject *vobj;
+ const char *tmp;
vobj = newVObject (VCCardProp);
@@ -571,8 +607,14 @@ e_card_get_vobject (ECard *card)
}
}
- if (card->id)
- addPropValue (vobj, VCUniqueStringProp, card->id);
+ tmp = e_card_get_uri (card);
+ if (tmp == NULL)
+ tmp = card->id;
+ if (tmp) {
+ g_message ("unique string = [%s]", tmp);
+ addPropValue (vobj, VCUniqueStringProp, tmp);
+ }
+
#if 0
@@ -1083,9 +1125,24 @@ parse_arbitrary(ECard *card, VObject *vobj)
static void
parse_id(ECard *card, VObject *vobj)
{
- if ( card->id )
- g_free(card->id);
- assign_string(vobj, &(card->id));
+ if ( vObjectValueType (vobj) ) {
+ gchar *str = fakeCString (vObjectUStringZValue (vobj));
+ gchar *id;
+ if ( card->id )
+ g_free(card->id);
+ if ( card->uri )
+ g_free(card->uri);
+
+ id = e_card_uri_extract_card_id (str);
+ if (id) {
+ card->id = id;
+ card->uri = g_strdup (str);
+ } else {
+ card->id = g_strdup (str);
+ card->uri = NULL;
+ }
+ free (str);
+ }
}
static void
@@ -1770,6 +1827,9 @@ e_card_destroy (GtkObject *object)
{
ECard *card = E_CARD(object);
g_free(card->id);
+ if (card->book)
+ gtk_object_unref (GTK_OBJECT (card->book));
+ g_free(card->uri);
g_free(card->file_as);
g_free(card->fname);
if ( card->name )
@@ -4047,3 +4107,77 @@ e_card_evolution_list_show_addresses (ECard *card)
g_return_val_if_fail (card && E_IS_CARD (card), FALSE);
return card->list_show_addresses;
}
+
+static gchar *
+e_card_uri_extract_book_uri (const gchar *uri)
+{
+ gchar *lastslash;
+
+ if (uri == NULL)
+ return NULL;
+
+ lastslash = strrchr (uri, '/');
+ if (lastslash == NULL)
+ return NULL;
+
+ return g_strndup (uri, lastslash - uri);
+}
+
+static gchar *
+e_card_uri_extract_card_id (const gchar *uri)
+{
+ gchar *lastslash;
+
+ if (uri == NULL)
+ return NULL;
+
+ lastslash = strrchr (uri, '/');
+ return lastslash ? g_strdup (lastslash+1) : NULL;
+}
+
+typedef struct _CardLoadData CardLoadData;
+struct _CardLoadData {
+ gchar *card_id;
+ ECardCallback cb;
+ gpointer closure;
+};
+
+static void
+card_load_cb (EBook *book, EBookStatus status, gpointer closure)
+{
+ CardLoadData *data = (CardLoadData *) closure;
+ ECard *card = NULL;
+
+ if (status == E_BOOK_STATUS_SUCCESS)
+ card = e_book_get_card (book, data->card_id);
+
+ if (data->cb != NULL)
+ data->cb (card, data->closure);
+
+ g_free (data->card_id);
+ g_free (data);
+}
+
+void
+e_card_load_uri (const gchar *uri, ECardCallback cb, gpointer closure)
+{
+ CardLoadData *data;
+ gchar *book_uri;
+ gchar *card_id;
+ EBook *book;
+
+ g_return_if_fail (uri != NULL);
+
+ book_uri = e_card_uri_extract_book_uri (uri);
+ card_id = e_card_uri_extract_card_id (uri);
+
+ data = g_new (CardLoadData, 1);
+ data->card_id = g_strdup (card_id);
+ data->cb = cb;
+ data->closure = closure;
+
+ book = e_book_new ();
+ e_book_load_uri (book, book_uri, card_load_cb, data);
+
+ g_free (book_uri);
+}
diff --git a/addressbook/backend/ebook/e-card.h b/addressbook/backend/ebook/e-card.h
index fa448704a5..3aaeddb813 100644
--- a/addressbook/backend/ebook/e-card.h
+++ b/addressbook/backend/ebook/e-card.h
@@ -27,10 +27,15 @@
typedef struct _ECard ECard;
typedef struct _ECardClass ECardClass;
+struct _EBook; /* Forward reference */
+
struct _ECard {
GtkObject object;
char *id;
+ struct _EBook *book; /* The EBook this card is from. */
+ gchar *uri; /* The card's uri (book uri + id) */
+
char *file_as; /* The File As field. */
char *fname; /* The full name. */
ECardName *name; /* The structured name. */
@@ -117,6 +122,10 @@ const char *e_card_get_id (ECard
void e_card_set_id (ECard *card,
const char *character);
+struct _EBook *e_card_get_book (ECard *card);
+const char *e_card_get_uri (ECard *card);
+
+
char *e_card_get_vcard (ECard *card);
char *e_card_list_get_vcard (GList *list);
ECard *e_card_duplicate (ECard *card);
@@ -126,7 +135,6 @@ void e_card_touch (ECard
/* Evolution List convenience functions */
/* used for encoding uids in email addresses */
-#define ECARD_UID_LINK_PREFIX "|X-EVOLUTION-UID="
gboolean e_card_evolution_list (ECard *card);
gboolean e_card_evolution_list_show_addresses(ECard *card);
@@ -182,6 +190,11 @@ void e_card_send (ECard
void e_card_list_send (GList *cards,
ECardDisposition disposition);
+/* Getting ECards via their URIs */
+typedef void (*ECardCallback) (ECard *card, gpointer closure);
+void e_card_load_uri (const gchar *uri, ECardCallback cb, gpointer closure);
+
+
/* Standard Gtk function */
GtkType e_card_get_type (void);
diff --git a/addressbook/backend/ebook/e-destination.c b/addressbook/backend/ebook/e-destination.c
index 4a1d2992cb..421b13cf07 100644
--- a/addressbook/backend/ebook/e-destination.c
+++ b/addressbook/backend/ebook/e-destination.c
@@ -28,28 +28,33 @@
#include <config.h>
#include "e-destination.h"
+#include <stdlib.h>
+#include <ctype.h>
#include <string.h>
#include <gtk/gtkobject.h>
#include <libgnome/gnome-defs.h>
#include <libgnome/gnome-i18n.h>
#include "e-book.h"
#include "e-book-util.h"
+#include <gal/widgets/e-unicode.h>
+#include <gnome-xml/parser.h>
+#include <gnome-xml/xmlmemory.h>
struct _EDestinationPrivate {
- gchar *pending_card_id;
-
+ gchar *card_uri;
ECard *card;
gint card_email_num;
gchar *name;
- gchar *string;
- gchar *string_email;
- gchar *string_email_verbose;
+ gchar *email;
+ gchar *addr;
gboolean html_mail_override;
gboolean wants_html_mail;
+
+ GList *list_dests;
};
static void e_destination_clear_card (EDestination *);
@@ -62,9 +67,7 @@ e_destination_destroy (GtkObject *obj)
{
EDestination *dest = E_DESTINATION (obj);
- e_destination_clear_card (dest);
- e_destination_clear_strings (dest);
-
+ e_destination_clear (dest);
g_free (dest->priv);
if (parent_class->destroy)
@@ -119,65 +122,85 @@ EDestination *
e_destination_copy (EDestination *dest)
{
EDestination *new_dest;
+ GList *iter;
g_return_val_if_fail (dest && E_IS_DESTINATION (dest), NULL);
new_dest = e_destination_new ();
- new_dest->priv->pending_card_id = g_strdup (new_dest->priv->pending_card_id);
+ new_dest->priv->card_uri = g_strdup (dest->priv->card_uri);
+ new_dest->priv->name = g_strdup (dest->priv->name);
+ new_dest->priv->email = g_strdup (dest->priv->email);
+ new_dest->priv->addr = g_strdup (dest->priv->addr);
+ new_dest->priv->card_email_num = dest->priv->card_email_num;
- new_dest->priv->card = dest->priv->card;
+ new_dest->priv->card = dest->priv->card;
if (new_dest->priv->card)
gtk_object_ref (GTK_OBJECT (new_dest->priv->card));
- new_dest->priv->card_email_num = dest->priv->card_email_num;
+ new_dest->priv->html_mail_override = dest->priv->html_mail_override;
+ new_dest->priv->wants_html_mail = dest->priv->wants_html_mail;
- new_dest->priv->string = g_strdup (dest->priv->string);
- new_dest->priv->string_email = g_strdup (dest->priv->string_email);
- new_dest->priv->string_email_verbose = g_strdup (dest->priv->string_email_verbose);
+ for (iter = dest->priv->list_dests; iter != NULL; iter = g_list_next (iter)) {
+ new_dest->priv->list_dests = g_list_append (new_dest->priv->list_dests,
+ e_destination_copy (E_DESTINATION (iter->data)));
+ }
return new_dest;
}
-gboolean
-e_destination_is_empty (EDestination *dest)
-{
- struct _EDestinationPrivate *p;
- g_return_val_if_fail (dest && E_IS_DESTINATION (dest), TRUE);
- p = dest->priv;
-
- return !(p->card
- || p->pending_card_id
- || (p->string && *p->string)
- || (p->name && *p->name)
- || (p->string_email && *p->string_email));
-}
-
static void
e_destination_clear_card (EDestination *dest)
{
- g_free (dest->priv->pending_card_id);
- dest->priv->pending_card_id = NULL;
+ g_free (dest->priv->card_uri);
+ dest->priv->card_uri = NULL;
if (dest->priv->card)
gtk_object_unref (GTK_OBJECT (dest->priv->card));
dest->priv->card = NULL;
dest->priv->card_email_num = -1;
+
+ g_list_foreach (dest->priv->list_dests, (GFunc) gtk_object_unref, NULL);
+ g_list_free (dest->priv->list_dests);
+ dest->priv->list_dests = NULL;
}
static void
e_destination_clear_strings (EDestination *dest)
{
g_free (dest->priv->name);
- g_free (dest->priv->string);
- g_free (dest->priv->string_email);
- g_free (dest->priv->string_email_verbose);
-
dest->priv->name = NULL;
- dest->priv->string = NULL;
- dest->priv->string_email = NULL;
- dest->priv->string_email_verbose = NULL;
+
+ g_free (dest->priv->email);
+ dest->priv->email = NULL;
+
+ g_free (dest->priv->addr);
+ dest->priv->addr = NULL;
+}
+
+void
+e_destination_clear (EDestination *dest)
+{
+ g_return_if_fail (dest && E_IS_DESTINATION (dest));
+
+ e_destination_clear_card (dest);
+ e_destination_clear_strings (dest);
+}
+
+gboolean
+e_destination_is_empty (EDestination *dest)
+{
+ struct _EDestinationPrivate *p;
+ g_return_val_if_fail (dest && E_IS_DESTINATION (dest), TRUE);
+ p = dest->priv;
+
+ return !(p->card != NULL
+ || (p->card_uri && *p->card_uri)
+ || (p->name && *p->name)
+ || (p->email && *p->email)
+ || (p->addr && *p->addr)
+ || (p->list_dests != NULL));
}
void
@@ -186,31 +209,103 @@ e_destination_set_card (EDestination *dest, ECard *card, gint email_num)
g_return_if_fail (dest && E_IS_DESTINATION (dest));
g_return_if_fail (card && E_IS_CARD (card));
- if (dest->priv->pending_card_id) {
- g_free (dest->priv->pending_card_id);
- dest->priv->pending_card_id = NULL;
- }
+ e_destination_clear (dest);
- if (dest->priv->card != card) {
- if (dest->priv->card)
- gtk_object_unref (GTK_OBJECT (dest->priv->card));
- dest->priv->card = card;
- gtk_object_ref (GTK_OBJECT (card));
- }
+ dest->priv->card = card;
+ gtk_object_ref (GTK_OBJECT (dest->priv->card));
dest->priv->card_email_num = email_num;
+}
- e_destination_clear_strings (dest);
+void
+e_destination_set_card_uri (EDestination *dest, const gchar *uri, gint email_num)
+{
+ g_return_if_fail (dest && E_IS_DESTINATION (dest));
+ g_return_if_fail (uri != NULL);
+
+ g_free (dest->priv->card_uri);
+ dest->priv->card_uri = g_strdup (uri);
+ dest->priv->card_email_num = email_num;
+
+ /* If we already have a card, remove it unless it's uri matches the one
+ we just set. */
+ if (dest->priv->card && strcmp (uri, e_card_get_uri (dest->priv->card))) {
+ gtk_object_unref (GTK_OBJECT (dest->priv->card));
+ dest->priv->card = NULL;
+ }
}
void
-e_destination_set_string (EDestination *dest, const gchar *string)
+e_destination_set_name (EDestination *dest, const gchar *name)
{
g_return_if_fail (dest && E_IS_DESTINATION (dest));
- g_return_if_fail (string != NULL);
+ g_return_if_fail (name != NULL);
- g_free (dest->priv->string);
- dest->priv->string = g_strdup (string);
+ g_free (dest->priv->name);
+ dest->priv->name = g_strdup (name);
+}
+
+void
+e_destination_set_email (EDestination *dest, const gchar *email)
+{
+ g_return_if_fail (dest && E_IS_DESTINATION (dest));
+ g_return_if_fail (email != NULL);
+
+ g_free (dest->priv->email);
+ dest->priv->email = g_strdup (email);
+}
+
+
+/* This function takes a free-form string and tries to do something
+ intelligent with it. */
+void
+e_destination_set_string (EDestination *dest, const gchar *str)
+{
+ gchar *name = NULL;
+ gchar *email = NULL;
+ gchar *lt, *gt;
+
+ g_return_if_fail (dest && E_IS_DESTINATION (dest));
+ g_return_if_fail (str != NULL);
+
+ /* Look for something of the form Jane Smith <jane@assbarn.com> */
+ if ( (lt = strrchr (str, '<')) && (gt = strrchr (str, '>')) && lt+1 < gt) {
+ name = g_strndup (str, lt-str);
+ email = g_strndup (lt+1, gt-lt-1);
+
+ /* I love using goto. It makes me feel so wicked. */
+ goto finished;
+ }
+
+ /* If it contains '@', assume it is an e-mail address. */
+ if (strchr (str, '@')) {
+ email = g_strdup (str);
+ goto finished;
+ }
+
+ /* If we contain whitespace, that is very suggestive of being a name. */
+ if (strchr (str, ' ')) {
+ name = g_strdup (str);
+ goto finished;
+ }
+
+ /* Default: Just treat it as an e-mail address. */
+ email = g_strdup (str);
+
+ finished:
+ if (name) {
+ g_strstrip (name);
+ if (*name)
+ e_destination_set_name (dest, name);
+ g_free (name);
+ }
+
+ if (email) {
+ g_strstrip (email);
+ if (*email)
+ e_destination_set_email (dest, email);
+ g_free (email);
+ }
}
void
@@ -223,17 +318,17 @@ e_destination_set_html_mail_pref (EDestination *dest, gboolean x)
}
gboolean
-e_destination_has_card (const EDestination *dest)
+e_destination_contains_card (const EDestination *dest)
{
g_return_val_if_fail (dest && E_IS_DESTINATION (dest), FALSE);
return dest->priv->card != NULL;
}
gboolean
-e_destination_has_pending_card (const EDestination *dest)
+e_destination_from_card (const EDestination *dest)
{
g_return_val_if_fail (dest && E_IS_DESTINATION (dest), FALSE);
- return dest->priv->pending_card_id != NULL;
+ return dest->priv->card != NULL || dest->priv->card_uri != NULL;
}
@@ -245,35 +340,22 @@ struct _UseCard {
};
static void
-use_card_cb (EBook *book, gpointer closure)
+use_card_cb (ECard *card, gpointer closure)
{
UseCard *uc = (UseCard *) closure;
- ECard *card;
-
- if (book != NULL && uc->dest->priv->card == NULL) {
-
- if (uc->dest->priv->pending_card_id) {
- card = e_book_get_card (book, uc->dest->priv->pending_card_id);
+ if (card != NULL && uc->dest->priv->card == NULL) {
- if (card) {
- ECard *old = uc->dest->priv->card;
- uc->dest->priv->card = card;
- gtk_object_ref (GTK_OBJECT (card));
- if (old)
- gtk_object_unref (GTK_OBJECT (old));
- }
-
- g_free (uc->dest->priv->pending_card_id);
- uc->dest->priv->pending_card_id = NULL;
-
- }
+ uc->dest->priv->card = card;
+ gtk_object_ref (GTK_OBJECT (uc->dest->priv->card));
}
- if (uc->cb)
+ if (uc->cb) {
uc->cb (uc->dest, uc->dest->priv->card, uc->closure);
+ }
+ /* We held a copy of the destination during the callback. */
gtk_object_unref (GTK_OBJECT (uc->dest));
g_free (uc);
}
@@ -289,13 +371,15 @@ e_destination_use_card (EDestination *dest, EDestinationCardCallback cb, gpointe
cb (dest, dest->priv->card, closure);
}
- } else {
+ } else if (dest->priv->card_uri) {
+
UseCard *uc = g_new (UseCard, 1);
uc->dest = dest;
+ /* Hold a reference to the destination during the callback. */
gtk_object_ref (GTK_OBJECT (uc->dest));
uc->cb = cb;
uc->closure = closure;
- e_book_use_local_address_book (use_card_cb, uc);
+ e_card_load_uri (dest->priv->card_uri, use_card_cb, uc);
}
}
@@ -307,62 +391,29 @@ e_destination_get_card (const EDestination *dest)
return dest->priv->card;
}
-gint
-e_destination_get_email_num (const EDestination *dest)
-{
- g_return_val_if_fail (dest && E_IS_DESTINATION (dest), -1);
-
- return dest->priv->card_email_num;
-}
-
const gchar *
-e_destination_get_string (const EDestination *dest)
+e_destination_get_card_uri (const EDestination *dest)
{
- struct _EDestinationPrivate *priv;
-
g_return_val_if_fail (dest && E_IS_DESTINATION (dest), NULL);
-
- priv = (struct _EDestinationPrivate *)dest->priv; /* cast out const */
- if (priv->string == NULL) {
-
- if (priv->card) {
-
- priv->string = e_card_name_to_string (priv->card->name);
- if (priv->string) {
- g_strstrip (priv->string);
- if (*(priv->string) == '\0') {
- g_free (priv->string);
- priv->string = NULL;
- }
- }
-
- if (priv->string == NULL)
- priv->string = g_strdup (e_destination_get_email (dest));
-
- if (priv->string == NULL)
- priv->string = g_strdup (_("???"));
-
- } else { /* If there is no card... */
-
- if (priv->name)
- return priv->name;
-
- }
- }
+ if (dest->priv->card_uri)
+ return dest->priv->card_uri;
- return priv->string;
+ if (dest->priv->card)
+ return e_card_get_uri (dest->priv->card);
+
+ return NULL;
}
gint
-e_destination_get_strlen (const EDestination *dest)
+e_destination_get_email_num (const EDestination *dest)
{
- const gchar *str;
+ g_return_val_if_fail (dest && E_IS_DESTINATION (dest), -1);
- g_return_val_if_fail (dest && E_IS_DESTINATION (dest), 0);
+ if (dest->priv->card == NULL && dest->priv->card_uri == NULL)
+ return -1;
- str = e_destination_get_string (dest);
- return str ? strlen (str) : 0;
+ return dest->priv->card_email_num;
}
const gchar *
@@ -373,15 +424,9 @@ e_destination_get_name (const EDestination *dest)
priv = (struct _EDestinationPrivate *)dest->priv; /* cast out const */
- if (priv->name == NULL) {
-
- if (priv->card) {
-
- priv->name = e_card_name_to_string (priv->card->name);
-
- }
- }
-
+ if (priv->name == NULL && priv->card != NULL)
+ priv->name = e_card_name_to_string (priv->card->name);
+
return priv->name;
}
@@ -395,7 +440,7 @@ e_destination_get_email (const EDestination *dest)
priv = (struct _EDestinationPrivate *)dest->priv; /* cast out const */
- if (priv->string_email == NULL) {
+ if (priv->email == NULL) {
if (priv->card) { /* Pull the address out of the card. */
@@ -410,46 +455,118 @@ e_destination_get_email (const EDestination *dest)
if (e_iterator_is_valid (iter)) {
gconstpointer ptr = e_iterator_get (iter);
- priv->string_email = g_strdup ((gchar *) ptr);
+ priv->email = g_strdup ((gchar *) ptr);
}
}
- } else if (priv->string) { /* Use the string as an e-mail address */
- return priv->string;
}
-
- /* else we just return NULL */
}
- return priv->string_email;
+ return priv->email;
}
const gchar *
-e_destination_get_email_verbose (const EDestination *dest)
+e_destination_get_address (const EDestination *dest)
{
struct _EDestinationPrivate *priv;
-
+
g_return_val_if_fail (dest && E_IS_DESTINATION (dest), NULL);
priv = (struct _EDestinationPrivate *)dest->priv; /* cast out const */
+
+ if (priv->addr == NULL) {
- if (priv->string_email_verbose == NULL) {
-
- const gchar *email = e_destination_get_email (dest);
- const gchar *name = e_destination_get_name (dest);
+ if (e_destination_is_evolution_list (dest)) {
+
+ gchar **strv = g_new0 (gchar *, g_list_length (priv->list_dests) + 1);
+ gint i = 0;
+ GList *iter = dest->priv->list_dests;
+
+ while (iter) {
+ EDestination *list_dest = E_DESTINATION (iter->data);
+ if (! e_destination_is_empty (list_dest)) {
+ strv[i] = (gchar *) e_destination_get_address (list_dest);
+ ++i;
+ }
+ iter = g_list_next (iter);
+ }
+
+ priv->addr = g_strjoinv (", ", strv);
- if (name) {
+ g_message ("List address is [%s]", priv->addr);
- priv->string_email_verbose = g_strdup_printf ("%s <%s>", name, email);
+ g_free (strv);
} else {
- return email;
+ const gchar *email = e_destination_get_email (dest);
+
+ if (email) { /* If this isn't set, we return NULL */
+
+ const gchar *name = e_destination_get_name (dest);
+
+ if (name) {
+
+ gboolean needs_quotes = (strchr (name, '.') != NULL);
+
+ priv->addr = g_strdup_printf ("%s%s%s <%s>",
+ needs_quotes ? "\"" : "",
+ name,
+ needs_quotes ? "\"" : "",
+ email);
+
+ } else {
+
+ priv->addr = g_strdup (email);
+
+ }
+ }
}
+ }
+
+ return priv->addr;
+}
+
+const gchar *
+e_destination_get_textrep (const EDestination *dest)
+{
+ const gchar *txt;
+
+ g_return_val_if_fail (dest && E_IS_DESTINATION (dest), NULL);
+
+ txt = e_destination_get_name (dest);
+ if (txt)
+ return txt;
+ txt = e_destination_get_email (dest);
+ if (txt)
+ return txt;
+
+ return NULL;
+}
+
+gboolean
+e_destination_is_evolution_list (const EDestination *dest)
+{
+ g_return_val_if_fail (dest && E_IS_DESTINATION (dest), FALSE);
+
+ if (dest->priv->list_dests == NULL
+ && dest->priv->card != NULL
+ && dest->priv->card->email != NULL
+ && e_card_evolution_list (dest->priv->card)) {
+
+ EIterator *iter = e_list_get_iterator (dest->priv->card->email);
+ e_iterator_reset (iter);
+ while (e_iterator_is_valid (iter)) {
+ const gchar *dest_xml = (const gchar *) e_iterator_get (iter);
+ EDestination *list_dest = e_destination_import (dest_xml);
+ if (list_dest)
+ dest->priv->list_dests = g_list_append (dest->priv->list_dests, list_dest);
+ e_iterator_next (iter);
+ }
}
- return priv->string_email_verbose;
+ return dest->priv->list_dests != NULL;
}
gboolean
@@ -480,7 +597,7 @@ e_destination_get_address_textv (EDestination **destv)
for (i = 0, j = 0; destv[i]; ++i) {
if (! e_destination_is_empty (destv[i])) {
- const gchar *addr = e_destination_get_email_verbose (destv[i]);
+ const gchar *addr = e_destination_get_address (destv[i]);
strv[j++] = addr ? (gchar *) addr : "";
}
}
@@ -492,289 +609,342 @@ e_destination_get_address_textv (EDestination **destv)
return str;
}
-/*
- *
- * Serialization code
- *
- */
+xmlNodePtr
+e_destination_xml_encode (const EDestination *dest)
+{
+ xmlNodePtr dest_node;
+ const gchar *str;
-#define DESTINATION_TAG "DEST"
+ g_return_val_if_fail (dest && E_IS_DESTINATION (dest), NULL);
-#define DESTINATION_SEPARATOR "|"
-#define DESTINATION_SEPARATOR_CHAR '|'
+ dest_node = xmlNewNode (NULL, "destination");
-#define VEC_SEPARATOR "\1"
-#define VEC_SEPARATOR_CHAR '\1'
+ str = e_destination_get_name (dest);
+ if (str)
+ xmlNewTextChild (dest_node, NULL, "name", str);
-static gchar *
-join_strings (gchar **strv)
-{
- /* FIXME: Should also quote any |'s that occur in any of the strings. */
- /* (We fake it by mapping | to _ when building our fields below) */
- return g_strjoinv (DESTINATION_SEPARATOR, strv);
-}
+ if (! e_destination_is_evolution_list (dest)) {
-static gchar **
-unjoin_string (const gchar *str)
-{
- /* FIXME: Should properly handle quoteded |'s in the string. */
- /* (We fake it by mapping | to _ when building our fields below) */
- return g_strsplit (str, DESTINATION_SEPARATOR, 0);
-}
+ str = e_destination_get_email (dest);
+ if (str)
+ xmlNewTextChild (dest_node, NULL, "email", str);
-static gchar *
-build_field (const gchar *key, const gchar *value)
-{
- gchar *field;
- gchar *c;
+ } else {
- g_return_val_if_fail (key != NULL, NULL);
- g_return_val_if_fail (value != NULL, NULL);
+ GList *iter = dest->priv->list_dests;
+ while (iter) {
+ EDestination *list_dest = E_DESTINATION (iter->data);
+ xmlNodePtr list_node = xmlNewNode (NULL, "list_entry");
+
+ str = e_destination_get_name (list_dest);
+ if (str)
+ xmlNewTextChild (list_node, NULL, "name", str);
+
+ str = e_destination_get_email (list_dest);
+ if (str)
+ xmlNewTextChild (list_node, NULL, "email", str);
- field = g_strdup_printf ("%s=%s", key, value);
+ xmlAddChild (dest_node, list_node);
+
+ iter = g_list_next (iter);
+ }
- /* Paranoia: Convert any '=' in the key to '_' */
- c = field;
- while (*key) {
- if (*c == '=')
- *c = '_';
- ++key;
- ++c;
+ xmlNewProp (dest_node, "is_list", "yes");
}
-
- /* Paranoia: Convert any '\1' or '|' in the key or value to '_' */
- for (c=field; *c; ++c) {
- if (*c == VEC_SEPARATOR_CHAR || *c == DESTINATION_SEPARATOR_CHAR)
- *c = '_';
+
+ str = e_destination_get_card_uri (dest);
+ if (str) {
+ gchar buf[16];
+ xmlNodePtr uri_node = xmlNewTextChild (dest_node, NULL, "card_uri", str);
+ g_snprintf (buf, 16, "%d", e_destination_get_email_num (dest));
+ xmlNewProp (uri_node, "email_num", buf);
}
- return field;
-}
+ xmlNewProp (dest_node, "html_mail", e_destination_get_html_mail_pref (dest) ? "yes" : "no");
-/* Modifies string in place, \0-terminates after the key, returns pointer to "value",
- or NULL if the field is malformed. */
-static gchar *
-extract_field (gchar *field)
-{
- gchar *s = strchr (field, '=');
- if (s == NULL)
- return NULL;
- *s = '\0';
- return s+1;
+ return dest_node;
}
-#define EXPORT_MAX_FIELDS 10
-gchar *
-e_destination_export (const EDestination *dest)
+gboolean
+e_destination_xml_decode (EDestination *dest, xmlNodePtr node)
{
- ECard *card;
- gchar **fields;
- gchar *str;
- gint i;
-
- g_return_val_if_fail (dest && E_IS_DESTINATION (dest), NULL);
+ gchar *name = NULL, *email = NULL, *card_uri = NULL;
+ gint email_num = -1;
+ gboolean html_mail = FALSE;
+ gboolean is_list = FALSE;
+ gchar *tmp;
+ GList *list_dests = NULL;
- fields = g_new (gchar *, EXPORT_MAX_FIELDS);
- fields[0] = g_strdup (DESTINATION_TAG);
- fields[1] = build_field ("addr", e_destination_get_email (dest));
+ g_return_val_if_fail (dest && E_IS_DESTINATION (dest), FALSE);
+ g_return_val_if_fail (node != NULL, FALSE);
- i = 2;
+ if (strcmp (node->name, "destination"))
+ return FALSE;
- if (e_destination_get_name (dest))
- fields[i++] = build_field ("name", e_destination_get_name (dest));
+ tmp = xmlGetProp (node, "html_mail");
+ if (tmp) {
+ html_mail = !strcmp (tmp, "yes");
+ xmlFree (tmp);
+ }
- fields[i++] = build_field ("html",
- e_destination_get_html_mail_pref (dest) ? "Y" : "N");
+ tmp = xmlGetProp (node, "is_list");
+ if (tmp) {
+ is_list = !strcmp (tmp, "yes");
+ xmlFree (tmp);
+ }
- card = e_destination_get_card (dest);
- if (card)
- fields[i++] = build_field ("card", e_card_get_id (card));
+ node = node->xmlChildrenNode;
+ while (node) {
- fields[i] = NULL;
-
+ if (!strcmp (node->name, "name")) {
+
+ tmp = xmlNodeGetContent (node);
+ g_free (name);
+ name = e_utf8_xml1_decode (tmp);
+ xmlFree (tmp);
- str = join_strings (fields);
- g_strfreev (fields);
-
- return str;
-}
+ } else if (!is_list && !strcmp (node->name, "email")) {
-EDestination *
-e_destination_import (const gchar *str)
-{
- EDestination *dest;
- gchar **fields;
- gint i;
+ tmp = xmlNodeGetContent (node);
+ g_free (email);
+ email = e_utf8_xml1_decode (tmp);
+ xmlFree (tmp);
- gchar *addr = NULL, *name = NULL, *card = NULL;
- gboolean want_html = FALSE;
-
- g_return_val_if_fail (str, NULL);
+ } else if (is_list && !strcmp (node->name, "list_entry")) {
- fields = unjoin_string (str);
- g_return_val_if_fail (fields && fields[0], NULL);
- g_return_val_if_fail (!strcmp (fields[0], DESTINATION_TAG), NULL);
-
- for (i = 1; fields[i]; ++i) {
- gchar *key = fields[i];
- gchar *value = extract_field (fields[i]);
-
- if (value) {
+ xmlNodePtr subnode = node->xmlChildrenNode;
+ gchar *list_name = NULL, *list_email = NULL;
- if (!strcmp ("addr", key)) {
+ while (subnode) {
- if (addr) {
- g_warning ("addr redefined: \"%s\" => \"%s\"", addr, value);
- }
+ if (!strcmp (subnode->name, "name")) {
- addr = g_strdup (value);
-
- } else if (!strcmp ("name", key)) {
+ tmp = xmlNodeGetContent (subnode);
+ g_free (list_name);
+ list_name = e_utf8_xml1_decode (tmp);
+ xmlFree (tmp);
- if (name) {
- g_warning ("name redefined: \"%s\" => \"%s\"", name, value);
- }
+ } else if (!strcmp (subnode->name, "email")) {
+
+ tmp = xmlNodeGetContent (subnode);
+ g_free (list_email);
+ list_email = e_utf8_xml1_decode (tmp);
+ xmlFree (tmp);
- name = g_strdup (value);
+ }
- } else if (!strcmp ("html", key)) {
+ subnode = subnode->next;
+ }
- want_html = (*value == 'Y');
+ if (list_name || list_email) {
+ EDestination *list_dest = e_destination_new ();
+ if (list_name)
+ e_destination_set_name (list_dest, list_name);
+ if (list_email)
+ e_destination_set_email (list_dest, list_email);
- } else if (!strcmp ("card", key)) {
+ list_dests = g_list_append (list_dests, list_dest);
+
+ }
- if (card) {
- g_warning ("card redefined: \"%s\" => \"%s\"", card, value);
- }
+ } else if (!strcmp (node->name, "card_uri")) {
- card = g_strdup (value);
+ tmp = xmlNodeGetContent (node);
+ g_free (card_uri);
+ card_uri = e_utf8_xml1_decode (tmp);
+ xmlFree (tmp);
- }
+ tmp = xmlGetProp (node, "email_num");
+ email_num = atoi (tmp);
+ xmlFree (tmp);
}
+ node = node->next;
}
- dest = e_destination_new ();
+ e_destination_clear (dest);
- /* We construct this part of the object in a rather abusive way. */
- dest->priv->string_email = addr;
- dest->priv->name = name;
- dest->priv->pending_card_id = card;
+ if (name)
+ e_destination_set_name (dest, name);
+ if (email)
+ e_destination_set_email (dest, email);
+ if (card_uri)
+ e_destination_set_card_uri (dest, card_uri, email_num);
+ if (list_dests)
+ dest->priv->list_dests = list_dests;
- e_destination_set_html_mail_pref (dest, want_html);
+ return TRUE;
+}
- g_strfreev (fields);
+/* FIXME: Make utf-8 safe */
+static gchar *
+null_terminate_and_remove_extra_whitespace (xmlChar *xml_in, gint size)
+{
+ gchar *xml;
+ gchar *r, *w;
+ gboolean skip_white = FALSE;
- return dest;
+ if (xml_in == NULL || size <= 0)
+ return NULL;
+
+ xml = g_strndup (xml_in, size);
+ r = w = xml;
+
+ while (*r) {
+ if (*r == '\n' || *r == '\r') {
+ skip_white = TRUE;
+ } else {
+ gboolean is_space = isspace (*r);
+
+ *w = *r;
+
+ if (! (skip_white && is_space))
+ ++w;
+ if (! is_space)
+ skip_white = FALSE;
+ }
+ ++r;
+ }
+
+ *w = '\0';
+
+ return xml;
}
gchar *
-e_destination_exportv (EDestination **destv)
+e_destination_export (const EDestination *dest)
{
- gint i, j, len = 0;
- gchar **strv;
- gchar *str;
+ xmlNodePtr dest_node;
+ xmlDocPtr dest_doc;
+ xmlChar *buffer = NULL;
+ gint size = -1;
+ gchar *str;
+
+ g_return_val_if_fail (dest && E_IS_DESTINATION (dest), NULL);
- g_return_val_if_fail (destv, NULL);
+ dest_node = e_destination_xml_encode (dest);
+ if (dest_node == NULL)
+ return NULL;
- while (destv[len]) {
- g_return_val_if_fail (E_IS_DESTINATION (destv[len]), NULL);
- ++len;
- }
+ dest_doc = xmlNewDoc (XML_DEFAULT_VERSION);
+ xmlDocSetRootElement (dest_doc, dest_node);
- strv = g_new0 (gchar *, len+1);
- for (i = 0, j = 0; i < len; ++i) {
- if (! e_destination_is_empty (destv[i]))
- strv[j++] = e_destination_export (destv[i]);
- }
+ xmlDocDumpMemory (dest_doc, &buffer, &size);
+ xmlFreeDoc (dest_doc);
+
+ str = null_terminate_and_remove_extra_whitespace (buffer, size);
+ xmlFree (buffer);
+
+ return str;
+}
- str = g_strjoinv (VEC_SEPARATOR, strv);
+EDestination *
+e_destination_import (const gchar *str)
+{
+ EDestination *dest = NULL;
+ xmlDocPtr dest_doc;
- for (i = 0; i < len; ++i) {
- if (strv[i]) {
- g_free (strv[i]);
+ if (! (str && *str))
+ return NULL;
+
+ dest_doc = xmlParseMemory ((gchar *) str, strlen (str));
+ if (dest_doc && dest_doc->xmlRootNode) {
+ dest = e_destination_new ();
+ if (! e_destination_xml_decode (dest, dest_doc->xmlRootNode)) {
+ gtk_object_unref (GTK_OBJECT (dest));
+ dest = NULL;
}
}
- g_free (strv);
+ xmlFreeDoc (dest_doc);
- return str;
+ return dest;
}
-EDestination **
-e_destination_importv (const gchar *str)
+gchar *
+e_destination_exportv (EDestination **destv)
{
- gchar** strv;
- EDestination **destv;
- gint i = 0, j = 0, len = 0;
-
- if (!(str && *str))
+ xmlDocPtr destv_doc;
+ xmlNodePtr destv_node;
+ xmlChar *buffer = NULL;
+ gint size = -1;
+ gchar *str;
+ gint i;
+
+ if (destv == NULL || *destv == NULL)
return NULL;
-
- strv = g_strsplit (str, VEC_SEPARATOR, 0);
- while (strv[len])
- ++len;
- destv = g_new0 (EDestination *, len+1);
+ destv_doc = xmlNewDoc (XML_DEFAULT_VERSION);
+ destv_node = xmlNewNode (NULL, "destinations");
+ xmlDocSetRootElement (destv_doc, destv_node);
- while (strv[i]) {
- EDestination *dest = e_destination_import (strv[i]);
- if (dest) {
- destv[j++] = dest;
+ for (i=0; destv[i]; ++i) {
+ if (! e_destination_is_empty (destv[i])) {
+ xmlNodePtr dest_node = e_destination_xml_encode (destv[i]);
+ if (dest_node)
+ xmlAddChild (destv_node, dest_node);
}
- ++i;
}
- g_strfreev (strv);
- return destv;
+ xmlDocDumpMemory (destv_doc, &buffer, &size);
+ xmlFreeDoc (destv_doc);
+
+ str = null_terminate_and_remove_extra_whitespace (buffer, size);
+ xmlFree (buffer);
+
+ return str;
}
EDestination **
-e_destination_importv_list (EBook *book, ECard *list)
+e_destination_importv (const gchar *str)
{
- EList *email_list;
- EIterator *email_iter;
- EDestination **destv;
- gint j = 0;
+ GList *dest_list = NULL, *iter;
+ xmlDocPtr destv_doc;
+ xmlNodePtr node;
+ EDestination **destv = NULL;
+ gint N;
- if (!e_card_evolution_list (list))
+ if (! (str && *str))
return NULL;
- gtk_object_get (GTK_OBJECT(list),
- "email", &email_list,
- NULL);
+ destv_doc = xmlParseMemory ((gchar *)str, strlen (str));
+ node = destv_doc->xmlRootNode;
- destv = g_new0 (EDestination *, e_list_length (email_list) +1);
+ if (strcmp (node->name, "destinations"))
+ goto finished;
- email_iter = e_list_get_iterator (email_list);
-
- while (e_iterator_is_valid (email_iter)) {
- const char *email = e_iterator_get (email_iter);
-
- if (!strncmp (email, ECARD_UID_LINK_PREFIX, strlen (ECARD_UID_LINK_PREFIX))) {
- /* it's a serialized uid */
- ECard *card;
- const char *uid;
- uid = email + strlen (ECARD_UID_LINK_PREFIX);
- card = e_book_get_card (book, uid);
- if (card) {
- EDestination *dest = e_destination_new ();
- e_destination_set_card (dest, card, 0);
- gtk_object_unref (GTK_OBJECT (card)); /* XXX ? */
- destv[j++] = dest;
- }
- }
- else {
- /* it's an email address */
- EDestination *dest = e_destination_new();
- dest->priv->string_email = g_strdup (email);
+ node = node->xmlChildrenNode;
+
+ while (node) {
+ EDestination *dest;
- if (dest) {
- destv[j++] = dest;
- }
+ dest = e_destination_new ();
+ if (e_destination_xml_decode (dest, node)) {
+ dest_list = g_list_prepend (dest_list, dest);
+ } else {
+ gtk_object_unref (GTK_OBJECT (dest));
}
+
+ node = node->next;
}
+ N = g_list_length (dest_list);
+ destv = g_new0 (EDestination *, N+1);
+
+ /* We write the EDestinations into the list from back to front, to
+ undo the reversal caused by using g_list_prepend instead of
+ g_list_append. */
+ iter = dest_list;
+ while (iter != NULL) {
+ destv[N-1] = E_DESTINATION (iter->data);
+ iter = g_list_next (iter);
+ --N;
+ }
+
+ finished:
+ xmlFreeDoc (destv_doc);
+ g_list_free (dest_list);
+
return destv;
}
diff --git a/addressbook/backend/ebook/e-destination.h b/addressbook/backend/ebook/e-destination.h
index 85edf594be..c4d742afbe 100644
--- a/addressbook/backend/ebook/e-destination.h
+++ b/addressbook/backend/ebook/e-destination.h
@@ -31,6 +31,7 @@
#include <gtk/gtkobject.h>
#include <addressbook/backend/ebook/e-card.h>
#include <addressbook/backend/ebook/e-book.h>
+#include <gnome-xml/tree.h>
#define E_TYPE_DESTINATION (e_destination_get_type ())
#define E_DESTINATION(o) (GTK_CHECK_CAST ((o), E_TYPE_DESTINATION, EDestination))
@@ -60,39 +61,49 @@ GtkType e_destination_get_type (void);
EDestination *e_destination_new (void);
EDestination *e_destination_copy (EDestination *);
+void e_destination_clear (EDestination *);
gboolean e_destination_is_empty (EDestination *);
void e_destination_set_card (EDestination *, ECard *card, gint email_num);
+void e_destination_set_card_uri (EDestination *, const gchar *uri, gint email_num);
+
+void e_destination_set_name (EDestination *, const gchar *name);
+void e_destination_set_email (EDestination *, const gchar *email);
+
void e_destination_set_string (EDestination *, const gchar *string);
void e_destination_set_html_mail_pref (EDestination *, gboolean);
-gboolean e_destination_has_card (const EDestination *);
-gboolean e_destination_has_pending_card (const EDestination *);
+gboolean e_destination_contains_card (const EDestination *);
+gboolean e_destination_from_card (const EDestination *);
void e_destination_use_card (EDestination *, EDestinationCardCallback cb, gpointer closure);
ECard *e_destination_get_card (const EDestination *);
+const gchar *e_destination_get_card_uri (const EDestination *);
gint e_destination_get_email_num (const EDestination *);
-const gchar *e_destination_get_string (const EDestination *);
-gint e_destination_get_strlen (const EDestination *); /* a convenience function... */
-const gchar *e_destination_get_name (const EDestination *);
+const gchar *e_destination_get_name (const EDestination *); /* "Jane Smith" */
+const gchar *e_destination_get_email (const EDestination *); /* "jane@assbarn.com" */
+const gchar *e_destination_get_address (const EDestination *); /* "Jane Smith <jane@assbarn.com>" (or a comma-sep set of such for a list) */
-const gchar *e_destination_get_email (const EDestination *);
-const gchar *e_destination_get_email_verbose (const EDestination *);
+const gchar *e_destination_get_textrep (const EDestination *); /* "Jane Smith" or "jane@assbarn.com" */
+
+gboolean e_destination_is_evolution_list (const EDestination *);
/* If true, they want HTML mail. */
gboolean e_destination_get_html_mail_pref (const EDestination *);
gchar *e_destination_get_address_textv (EDestination **);
+xmlNodePtr e_destination_xml_encode (const EDestination *dest);
+gboolean e_destination_xml_decode (EDestination *dest, xmlNodePtr node);
+
gchar *e_destination_export (const EDestination *);
EDestination *e_destination_import (const gchar *str);
gchar *e_destination_exportv (EDestination **);
EDestination **e_destination_importv (const gchar *str);
-EDestination **e_destination_importv_list (EBook *book, ECard *list);
void e_destination_touch (EDestination *);