aboutsummaryrefslogtreecommitdiffstats
path: root/addressbook/backend/ebook
diff options
context:
space:
mode:
authorJon Trowbridge <trow@ximian.com>2001-03-16 16:16:29 +0800
committerJon Trowbridge <trow@src.gnome.org>2001-03-16 16:16:29 +0800
commit57de6972c845dbae49717a4520aeed75f88f0078 (patch)
treef58e45cdbb09793d8a09506af00c70b1ca63a389 /addressbook/backend/ebook
parent403205b15e9f14472711ee115cae17031eb4ce7b (diff)
downloadgsoc2013-evolution-57de6972c845dbae49717a4520aeed75f88f0078.tar.gz
gsoc2013-evolution-57de6972c845dbae49717a4520aeed75f88f0078.tar.zst
gsoc2013-evolution-57de6972c845dbae49717a4520aeed75f88f0078.zip
Added addressbook querying and "cardification" functions, which are turned
2001-03-15 Jon Trowbridge <trow@ximian.com> * gui/component/e-address-widget.c: Added addressbook querying and "cardification" functions, which are turned off by default for now because of addressbook bugs. Added a popup menu option to turn queries on, so that others can enjoy the thrill of massive flaming death. * gui/component/addressbook-factory.c (main): Made warnings always be fatal. * backend/pas/pas-book-view.c: Added some debugging spew. * backend/pas/pas-backend-file.c (pas_backend_file_search): Added a little experimental code to try to make file searches scale better. #if 0/#endif-ed out for now. * contact-editor/e-contact-quick-add.c: #included e-book-util.h. * backend/ebook/e-card.c (e_card_name_match_string): Added. Looser name-matching function. (e_card_email_match_string): Added. Loose e-mail matching. * backend/ebook/e-book-view-listener.c (e_book_view_listener_check_queue): Added code to cause us to abort rather than get trapped in a 100%-CPU-consuming loop in certain situations. Now we just need to figure out how to avoid these situations altogether. * backend/ebook/e-book-util.c: Added. Now contains the simple query stuff and the open local addressbook functions. * backend/ebook/e-book.c: Moved simple query stuff and open local addressbook functions into e-book-util.c. 2001-03-15 Jon Trowbridge <trow@ximian.com> * wombat.c (main): If we can't initialize a service on startup, tell us which one before terminating. svn path=/trunk/; revision=8754
Diffstat (limited to 'addressbook/backend/ebook')
-rw-r--r--addressbook/backend/ebook/Makefile.am2
-rw-r--r--addressbook/backend/ebook/e-book-util.c444
-rw-r--r--addressbook/backend/ebook/e-book-util.h64
-rw-r--r--addressbook/backend/ebook/e-book-view-listener.c19
-rw-r--r--addressbook/backend/ebook/e-book.c174
-rw-r--r--addressbook/backend/ebook/e-book.h16
-rw-r--r--addressbook/backend/ebook/e-card.c202
-rw-r--r--addressbook/backend/ebook/e-card.h6
8 files changed, 737 insertions, 190 deletions
diff --git a/addressbook/backend/ebook/Makefile.am b/addressbook/backend/ebook/Makefile.am
index 7abee848e9..a46d94ac87 100644
--- a/addressbook/backend/ebook/Makefile.am
+++ b/addressbook/backend/ebook/Makefile.am
@@ -43,6 +43,7 @@ libebook_la_SOURCES = \
e-book-view-listener.c \
e-book-view.c \
e-book.c \
+ e-book-util.c \
e-card-cursor.c \
e-card-simple.c \
e-card.c \
@@ -56,6 +57,7 @@ libebookinclude_HEADERS = \
e-book-view-listener.h \
e-book-view.h \
e-book.h \
+ e-book-util.h \
e-card-cursor.h \
e-card-pairs.h \
e-card-simple.h \
diff --git a/addressbook/backend/ebook/e-book-util.c b/addressbook/backend/ebook/e-book-util.c
new file mode 100644
index 0000000000..1d1106e8f2
--- /dev/null
+++ b/addressbook/backend/ebook/e-book-util.c
@@ -0,0 +1,444 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * e-book-util.c
+ *
+ * Copyright (C) 2001 Ximian, Inc.
+ *
+ * Developed by Jon Trowbridge <trow@ximian.com>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA.
+ */
+
+#include <config.h>
+#include <gtk/gtk.h>
+#include <libgnome/gnome-defs.h>
+#include <libgnome/gnome-util.h>
+#include "e-book-util.h"
+
+gboolean
+e_book_load_local_address_book (EBook *book, EBookCallback open_response, gpointer closure)
+{
+ gchar *filename;
+ gchar *uri;
+ gboolean rv;
+
+ g_return_val_if_fail (book != NULL, FALSE);
+ g_return_val_if_fail (E_IS_BOOK (book), FALSE);
+ g_return_val_if_fail (open_response != NULL, FALSE);
+
+ filename = gnome_util_prepend_user_home ("evolution/local/Contacts/addressbook.db");
+ uri = g_strdup_printf ("file://%s", filename);
+
+ rv = e_book_load_uri (book, uri, open_response, closure);
+
+ g_free (filename);
+ g_free (uri);
+
+ return rv;
+}
+
+/*
+ *
+ * Simple Query Stuff
+ *
+ */
+
+typedef struct _SimpleQueryInfo SimpleQueryInfo;
+struct _SimpleQueryInfo {
+ guint tag;
+ EBook *book;
+ gchar *query;
+ EBookSimpleQueryCallback cb;
+ gpointer closure;
+ EBookView *view;
+ guint add_tag;
+ guint seq_complete_tag;
+ GList *cards;
+};
+
+static void
+book_add_simple_query (EBook *book, SimpleQueryInfo *info)
+{
+ GList *pending = gtk_object_get_data (GTK_OBJECT (book), "sq_pending");
+ pending = g_list_prepend (pending, info);
+ gtk_object_set_data (GTK_OBJECT (book), "sq_pending", pending);
+}
+
+static SimpleQueryInfo *
+book_lookup_simple_query (EBook *book, guint tag)
+{
+ GList *pending = gtk_object_get_data (GTK_OBJECT (book), "sq_pending");
+ while (pending) {
+ SimpleQueryInfo *sq = pending->data;
+ if (sq->tag == tag)
+ return sq;
+ pending = g_list_next (pending);
+ }
+ return NULL;
+}
+
+static void
+book_remove_simple_query (EBook *book, SimpleQueryInfo *info)
+{
+ GList *pending = gtk_object_get_data (GTK_OBJECT (book), "sq_pending");
+ GList *i;
+
+ for (i=pending; i != NULL; i = g_list_next (i)) {
+ if (i->data == info) {
+ pending = g_list_remove_link (pending, i);
+ g_list_free_1 (i);
+ break;
+ }
+ }
+ gtk_object_set_data (GTK_OBJECT (book), "sq_pending", pending);
+}
+
+static guint
+book_issue_tag (EBook *book)
+{
+ gpointer ptr = gtk_object_get_data (GTK_OBJECT (book), "sq_tag");
+ guint tag = GPOINTER_TO_UINT (ptr);
+ if (tag == 0)
+ tag = 1;
+ gtk_object_set_data (GTK_OBJECT (book), "sq_tag", GUINT_TO_POINTER (tag+1));
+ return tag;
+}
+
+#ifdef USE_WORKAROUND
+static GList *WORKAROUND_sq_queue = NULL;
+static gboolean WORKAROUND_running_query = FALSE;
+#endif
+
+static SimpleQueryInfo *
+simple_query_new (EBook *book, const char *query, EBookSimpleQueryCallback cb, gpointer closure)
+{
+ SimpleQueryInfo *sq = g_new0 (SimpleQueryInfo, 1);
+
+ sq->tag = book_issue_tag (book);
+ sq->book = book;
+ gtk_object_ref (GTK_OBJECT (book));
+ sq->query = g_strdup_printf (query);
+ sq->cb = cb;
+ sq->closure = closure;
+
+ /* Automatically add ourselves to the EBook's pending list. */
+ book_add_simple_query (book, sq);
+
+#ifdef USE_WORKAROUND
+ /* Add ourselves to the queue. */
+ WORKAROUND_sq_queue = g_list_append (WORKAROUND_sq_queue, sq);
+#endif
+
+ return sq;
+}
+
+static void
+simple_query_free (SimpleQueryInfo *sq)
+{
+ GList *i;
+
+ /* Remove ourselves from the EBook's pending list. */
+ book_remove_simple_query (sq->book, sq);
+
+#ifdef USE_WORKAROUND
+ /* If we are still in the queue, remove ourselves. */
+ for (i = WORKAROUND_sq_queue; i != NULL; i = g_list_next (i)) {
+ if (i->data == sq) {
+ WORKAROUND_sq_queue = g_list_remove_link (WORKAROUND_sq_queue, i);
+ g_list_free_1 (i);
+ break;
+ }
+ }
+#endif
+
+ g_free (sq->query);
+
+ if (sq->add_tag)
+ gtk_signal_disconnect (GTK_OBJECT (sq->view), sq->add_tag);
+ if (sq->seq_complete_tag)
+ gtk_signal_disconnect (GTK_OBJECT (sq->view), sq->seq_complete_tag);
+
+#ifdef USE_WORKAROUND
+ if (sq->view)
+ WORKAROUND_running_query = FALSE;
+#endif
+
+ if (sq->view)
+ gtk_object_unref (GTK_OBJECT (sq->view));
+
+ if (sq->book)
+ gtk_object_unref (GTK_OBJECT (sq->book));
+
+ g_list_foreach (sq->cards, (GFunc) gtk_object_unref, NULL);
+ g_list_free (sq->cards);
+
+ g_free (sq);
+}
+
+static void
+simple_query_card_added_cb (EBookView *view, const GList *cards, gpointer closure)
+{
+ SimpleQueryInfo *sq = closure;
+
+ sq->cards = g_list_concat (sq->cards, g_list_copy ((GList *) cards));
+ g_list_foreach ((GList *) cards, (GFunc) gtk_object_ref, NULL);
+}
+
+static void
+simple_query_sequence_complete_cb (EBookView *view, gpointer closure)
+{
+ SimpleQueryInfo *sq = closure;
+
+ sq->cb (sq->book, E_BOOK_SIMPLE_QUERY_STATUS_SUCCESS, sq->cards, sq->closure);
+ simple_query_free (sq);
+}
+
+static void
+simple_query_book_view_cb (EBook *book, EBookStatus status, EBookView *book_view, gpointer closure)
+{
+ SimpleQueryInfo *sq = closure;
+
+ if (status != E_BOOK_STATUS_SUCCESS) {
+ sq->cb (sq->book, E_BOOK_SIMPLE_QUERY_STATUS_OTHER_ERROR, NULL, sq->closure);
+ simple_query_free (sq);
+ return;
+ }
+
+ sq->view = book_view;
+ gtk_object_ref (GTK_OBJECT (book_view));
+
+ sq->add_tag = gtk_signal_connect (GTK_OBJECT (sq->view),
+ "card_added",
+ GTK_SIGNAL_FUNC (simple_query_card_added_cb),
+ sq);
+ sq->seq_complete_tag = gtk_signal_connect (GTK_OBJECT (sq->view),
+ "sequence_complete",
+ GTK_SIGNAL_FUNC (simple_query_sequence_complete_cb),
+ sq);
+}
+
+#ifdef USE_WORKAROUND
+static gint
+WORKAROUND_try_queue (gpointer foo)
+{
+ if (WORKAROUND_sq_queue) {
+ SimpleQueryInfo *sq;
+ GList *i;
+
+ if (WORKAROUND_running_query)
+ return TRUE;
+
+ WORKAROUND_running_query = TRUE;
+ sq = WORKAROUND_sq_queue->data;
+
+ i = WORKAROUND_sq_queue;
+ WORKAROUND_sq_queue = g_list_remove_link (WORKAROUND_sq_queue, WORKAROUND_sq_queue);
+ g_list_free_1 (i);
+
+ e_book_get_book_view (sq->book, sq->query, simple_query_book_view_cb, sq);
+ }
+
+ return FALSE;
+}
+#endif
+
+guint
+e_book_simple_query (EBook *book, const char *query, EBookSimpleQueryCallback cb, gpointer closure)
+{
+ SimpleQueryInfo *sq;
+
+ g_return_val_if_fail (book && E_IS_BOOK (book), 0);
+ g_return_val_if_fail (query, 0);
+ g_return_val_if_fail (cb, 0);
+
+ sq = simple_query_new (book, query, cb, closure);
+#ifdef USE_WORKAROUND
+ gtk_timeout_add (50, WORKAROUND_try_queue, NULL);
+#else
+ e_book_get_book_view (book, query, simple_query_book_view_cb, sq);
+#endif
+
+ return sq->tag;
+}
+
+void
+e_book_simple_query_cancel (EBook *book, guint tag)
+{
+ SimpleQueryInfo *sq;
+
+ g_return_if_fail (book && E_IS_BOOK (book));
+
+ sq = book_lookup_simple_query (book, tag);
+
+ if (sq) {
+ sq->cb (sq->book, E_BOOK_SIMPLE_QUERY_STATUS_CANCELLED, NULL, sq->closure);
+ simple_query_free (sq);
+ } else {
+ g_warning ("Simple query tag %d is unknown", tag);
+ }
+}
+
+/*
+ *
+ * Specialized Queries
+ *
+ */
+
+typedef struct _NameEmailQueryInfo NameEmailQueryInfo;
+struct _NameEmailQueryInfo {
+ gchar *name;
+ gchar *email;
+ EBookSimpleQueryCallback cb;
+ gpointer closure;
+};
+
+static void
+name_email_query_info_free (NameEmailQueryInfo *info)
+{
+ if (info) {
+ g_free (info->name);
+ g_free (info->email);
+ g_free (info);
+ }
+}
+
+static void
+name_and_email_cb (EBook *book, EBookSimpleQueryStatus status, const GList *cards, gpointer closure)
+{
+ NameEmailQueryInfo *info = closure;
+ GList *filtered_cards = NULL;
+
+ while (cards) {
+ ECard *card = E_CARD (cards->data);
+ if ((info->name == NULL || e_card_name_match_string (card->name, info->name))
+ && (info->email == NULL || e_card_email_match_string (card, info->email)))
+ filtered_cards = g_list_append (filtered_cards, card);
+ cards = g_list_next (cards);
+ }
+
+ info->cb (book, status, filtered_cards, info->closure);
+
+ g_list_free (filtered_cards);
+
+ name_email_query_info_free (info);
+}
+
+guint
+e_book_name_and_email_query (EBook *book,
+ const gchar *name,
+ const gchar *email,
+ EBookSimpleQueryCallback cb,
+ gpointer closure)
+{
+ NameEmailQueryInfo *info;
+ gchar *email_query=NULL, *name_query=NULL, *query;
+ guint tag;
+
+ g_return_val_if_fail (book && E_IS_BOOK (book), 0);
+ g_return_val_if_fail (cb != NULL, 0);
+
+ if (name && !*name)
+ name = NULL;
+ if (email && !*email)
+ email = NULL;
+
+ if (name == NULL && email == NULL)
+ return 0;
+
+ /* Build our e-mail query.
+ * We only query against the username part of the address, to avoid not matching
+ * fred@foo.com and fred@mail.foo.com. While their may be namespace collisions
+ * in the usernames of everyone out there, it shouldn't be that bad. (Famous last words.)
+ */
+ if (email) {
+ const gchar *t=email;
+ while (*t && *t != '@')
+ ++t;
+ if (*t == '@') {
+ email_query = g_strdup_printf ("(beginswith \"email\" \"%.*s@\")", t-email, email);
+
+ } else {
+ email_query = g_strdup_printf ("(beginswith \"email\" \"%s\")", email);
+ }
+ }
+
+ /* Build our name query.
+ * We only do name-query stuff if we don't have an e-mail address. Our basic assumption
+ * is that the username part of the email is good enough to keep the amount of stuff returned
+ * in the query relatively small.
+ */
+ if (name && !email) {
+ gchar *name_cpy = g_strdup (name), *qjoined;
+ gchar **namev;
+ gint i, count=0;
+
+ g_strstrip (name_cpy);
+ namev = g_strsplit (" ", name_cpy, 0);
+ for (i=0; namev[i]; ++i) {
+ if (*namev[i]) {
+ namev[i] = g_strdup_printf ("(contains \"file_as\" \"%s\")", namev[i]);
+ ++count;
+ }
+ }
+
+ qjoined = g_strjoinv (" ", namev);
+ if (count > 1) {
+ name_query = g_strdup_printf ("(or %s)", qjoined);
+ } else {
+ name_query = qjoined;
+ qjoined = NULL;
+ }
+
+
+ g_free (name_cpy);
+ for (i=0; namev[i]; ++i)
+ if (*namev[i])
+ g_free (namev[i]);
+ g_free (namev);
+ g_free (qjoined);
+ }
+
+ /* Assemble our e-mail & name queries */
+ if (email_query && name_query) {
+ query = g_strdup_printf ("(and %s %s)", email_query, name_query);
+ } else if (email_query) {
+ query = email_query;
+ email_query = NULL;
+ } else if (name_query) {
+ query = name_query;
+ name_query = NULL;
+ } else
+ return 0;
+
+ g_message ("query: %s", query);
+
+ info = g_new0 (NameEmailQueryInfo, 1);
+ info->name = g_strdup (name);
+ info->email = g_strdup (email);
+ info->cb = cb;
+ info->closure = closure;
+
+ tag = e_book_simple_query (book, query, name_and_email_cb, info);
+
+ g_free (email_query);
+ g_free (name_query);
+ g_free (query);
+
+ return tag;
+}
diff --git a/addressbook/backend/ebook/e-book-util.h b/addressbook/backend/ebook/e-book-util.h
new file mode 100644
index 0000000000..cf0103bfea
--- /dev/null
+++ b/addressbook/backend/ebook/e-book-util.h
@@ -0,0 +1,64 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * e-book-util.h
+ *
+ * Copyright (C) 2001 Ximian, Inc.
+ *
+ * Developed by Jon Trowbridge <trow@ximian.com>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA.
+ */
+
+#ifndef __E_BOOK_UTIL_H__
+#define __E_BOOK_UTIL_H__
+
+#include <libgnome/gnome-defs.h>
+#include "e-book.h"
+
+BEGIN_GNOME_DECLS
+
+/* Callbacks for asynchronous functions. */
+typedef void (*EBookSimpleQueryCallback) (EBook *book, EBookSimpleQueryStatus status, const GList *cards, gpointer closure);
+
+gboolean e_book_load_local_address_book (EBook *book,
+ EBookCallback open_response,
+ gpointer closure);
+
+/* Simple Query Interface. */
+
+guint e_book_simple_query (EBook *book,
+ const char *query,
+ EBookSimpleQueryCallback cb,
+ gpointer closure);
+void e_book_simple_query_cancel (EBook *book,
+ guint tag);
+
+/* Specialized Name/Email Queries */
+
+guint e_book_name_and_email_query (EBook *book,
+ const char *name,
+ const char *email,
+ EBookSimpleQueryCallback cb,
+ gpointer closure);
+
+END_GNOME_DECLS
+
+
+#endif /* __E_BOOK_UTIL_H__ */
+
diff --git a/addressbook/backend/ebook/e-book-view-listener.c b/addressbook/backend/ebook/e-book-view-listener.c
index 4ad674ccd8..8433d1cc29 100644
--- a/addressbook/backend/ebook/e-book-view-listener.c
+++ b/addressbook/backend/ebook/e-book-view-listener.c
@@ -33,12 +33,31 @@ struct _EBookViewListenerPrivate {
static gboolean
e_book_view_listener_check_queue (EBookViewListener *listener)
{
+ static gint thrash = 0;
+ gint queue_len;
+
+ queue_len = g_list_length (listener->priv->response_queue);
+
bonobo_object_ref (BONOBO_OBJECT (listener));
if (listener->priv->response_queue != NULL) {
gtk_signal_emit (GTK_OBJECT (listener),
e_book_view_listener_signals [RESPONSES_QUEUED]);
}
+ /* This means we didn't make any progress in dealing with what is on our
+ response queue. */
+ if (queue_len == g_list_length (listener->priv->response_queue))
+ ++thrash;
+ else
+ thrash = 0;
+
+ if (thrash > 20) {
+ g_error ("e_book_view_listener_check_queue thrashing!");
+ thrash = 0;
+ listener->priv->idle_id = 0;
+ return FALSE;
+ }
+
if (listener->priv->response_queue == NULL) {
listener->priv->idle_id = 0;
bonobo_object_unref (BONOBO_OBJECT (listener));
diff --git a/addressbook/backend/ebook/e-book.c b/addressbook/backend/ebook/e-book.c
index e0b62c48d1..2a02b78fbf 100644
--- a/addressbook/backend/ebook/e-book.c
+++ b/addressbook/backend/ebook/e-book.c
@@ -12,7 +12,6 @@
#include <gtk/gtksignal.h>
#include <gtk/gtkmarshal.h>
#include <libgnome/gnome-defs.h>
-#include <libgnome/gnome-util.h>
#include <liboaf/liboaf.h>
#include "addressbook.h"
@@ -517,28 +516,6 @@ e_book_unload_uri (EBook *book)
book->priv->load_state = URINotLoaded;
}
-gboolean
-e_book_load_local_address_book (EBook *book, EBookCallback open_response, gpointer closure)
-{
- gchar *filename;
- gchar *uri;
- gboolean rv;
-
- g_return_val_if_fail (book != NULL, FALSE);
- g_return_val_if_fail (E_IS_BOOK (book), FALSE);
- g_return_val_if_fail (open_response != NULL, FALSE);
-
- filename = gnome_util_prepend_user_home ("evolution/local/Contacts/addressbook.db");
- uri = g_strdup_printf ("file://%s", filename);
-
- rv = e_book_load_uri (book, uri, open_response, closure);
-
- g_free (filename);
- g_free (uri);
-
- return rv;
-}
-
char *
e_book_get_static_capabilities (EBook *book)
{
@@ -1119,157 +1096,6 @@ e_book_get_changes (EBook *book,
return TRUE;
}
-/*
- *
- * Simple Query Stuff
- *
- */
-
-typedef struct _SimpleQueryInfo SimpleQueryInfo;
-struct _SimpleQueryInfo {
- guint tag;
- EBook *book;
- gchar *query;
- EBookSimpleQueryCallback cb;
- gpointer closure;
- EBookView *view;
- guint add_tag;
- guint seq_complete_tag;
- GList *cards;
-};
-
-static SimpleQueryInfo *
-simple_query_new (EBook *book, char *query, EBookSimpleQueryCallback cb, gpointer closure)
-{
- SimpleQueryInfo *sq = g_new0 (SimpleQueryInfo, 1);
-
- sq->tag = ++book->priv->sq_tag;
- sq->book = book;
- gtk_object_ref (GTK_OBJECT (book));
- sq->query = g_strdup_printf (query);
- sq->cb = cb;
- sq->closure = closure;
-
- /* Automatically add ourselves to the EBook's pending list. */
- book->priv->sq_pending = g_list_prepend (book->priv->sq_pending, sq);
-
- return sq;
-}
-
-static void
-simple_query_free (SimpleQueryInfo *sq)
-{
- GList *i;
- gboolean found = FALSE;
-
- /* Find & remove ourselves from the EBook's pending list. */
- for (i = sq->book->priv->sq_pending; i != NULL; i = g_list_next (i)) {
- if (i->data == sq) {
- sq->book->priv->sq_pending = g_list_remove_link (sq->book->priv->sq_pending, i);
- g_list_free_1 (i);
- i = NULL;
- found = TRUE;
- } else
- i = g_list_next (i);
- }
-
- g_assert (found);
-
- g_free (sq->query);
-
- if (sq->add_tag)
- gtk_signal_disconnect (GTK_OBJECT (sq->view), sq->add_tag);
- if (sq->seq_complete_tag)
- gtk_signal_disconnect (GTK_OBJECT (sq->view), sq->seq_complete_tag);
-
- if (sq->view)
- gtk_object_unref (GTK_OBJECT (sq->view));
-
- if (sq->book)
- gtk_object_unref (GTK_OBJECT (sq->book));
-
- g_list_foreach (sq->cards, (GFunc) gtk_object_unref, NULL);
- g_list_free (sq->cards);
-
- g_free (sq);
-}
-
-static void
-simple_query_card_added_cb (EBookView *view, const GList *cards, gpointer closure)
-{
- SimpleQueryInfo *sq = closure;
-
- sq->cards = g_list_concat (sq->cards, g_list_copy ((GList *) cards));
- g_list_foreach ((GList *) cards, (GFunc) gtk_object_ref, NULL);
-}
-
-static void
-simple_query_sequence_complete_cb (EBookView *view, gpointer closure)
-{
- SimpleQueryInfo *sq = closure;
-
- sq->cb (sq->book, E_BOOK_SIMPLE_QUERY_STATUS_SUCCESS, sq->cards, sq->closure);
- simple_query_free (sq);
-}
-
-static void
-simple_query_book_view_cb (EBook *book, EBookStatus status, EBookView *book_view, gpointer closure)
-{
- SimpleQueryInfo *sq = closure;
-
- if (status != E_BOOK_STATUS_SUCCESS) {
- sq->cb (sq->book, E_BOOK_SIMPLE_QUERY_STATUS_OTHER_ERROR, NULL, sq->closure);
- simple_query_free (sq);
- return;
- }
-
- sq->view = book_view;
- gtk_object_ref (GTK_OBJECT (book_view));
-
- sq->add_tag = gtk_signal_connect (GTK_OBJECT (sq->view),
- "card_added",
- GTK_SIGNAL_FUNC (simple_query_card_added_cb),
- sq);
- sq->seq_complete_tag = gtk_signal_connect (GTK_OBJECT (sq->view),
- "sequence_complete",
- GTK_SIGNAL_FUNC (simple_query_sequence_complete_cb),
- sq);
-}
-
-guint
-e_book_simple_query (EBook *book, char *query, EBookSimpleQueryCallback cb, gpointer closure)
-{
- SimpleQueryInfo *sq;
-
- g_return_val_if_fail (book && E_IS_BOOK (book), 0);
- g_return_val_if_fail (query, 0);
- g_return_val_if_fail (cb, 0);
-
- sq = simple_query_new (book, query, cb, closure);
- e_book_get_book_view (book, query, simple_query_book_view_cb, sq);
-
- return sq->tag;
-}
-
-void
-e_book_simple_query_cancel (EBook *book, guint tag)
-{
- GList *i;
-
- g_return_if_fail (book && E_IS_BOOK (book));
-
- for (i=book->priv->sq_pending; i != NULL; i=g_list_next (i)) {
- SimpleQueryInfo *sq = i->data;
-
- if (sq->tag == tag) {
- sq->cb (sq->book, E_BOOK_SIMPLE_QUERY_STATUS_CANCELLED, NULL, sq->closure);
- simple_query_free (sq);
- return;
- }
- }
- g_warning ("Simple query tag %d is unknown", tag);
-}
-
/**
* e_book_get_name:
*/
diff --git a/addressbook/backend/ebook/e-book.h b/addressbook/backend/ebook/e-book.h
index 2521edb24f..0713bc6bdb 100644
--- a/addressbook/backend/ebook/e-book.h
+++ b/addressbook/backend/ebook/e-book.h
@@ -50,9 +50,6 @@ typedef void (*EBookCursorCallback) (EBook *book, EBookStatus status, ECardCurso
typedef void (*EBookBookViewCallback) (EBook *book, EBookStatus status, EBookView *book_view, gpointer closure);
typedef void (*EBookFieldsCallback) (EBook *book, EBookStatus status, EList *fields, gpointer closure);
-typedef void (*EBookSimpleQueryCallback) (EBook *book, EBookSimpleQueryStatus status, const GList *cards, gpointer closure);
-
-
/* Creating a new addressbook. */
EBook *e_book_new (void);
@@ -62,10 +59,6 @@ gboolean e_book_load_uri (EBook *book,
gpointer closure);
void e_book_unload_uri (EBook *book);
-gboolean e_book_load_local_address_book (EBook *book,
- EBookCallback open_response,
- gpointer closure);
-
char *e_book_get_static_capabilities (EBook *book);
gboolean e_book_get_supported_fields (EBook *book,
@@ -133,15 +126,6 @@ gboolean e_book_get_changes (EBook *book,
EBookBookViewCallback cb,
gpointer closure);
-/* Simple Query Interface. */
-
-guint e_book_simple_query (EBook *book,
- char *query,
- EBookSimpleQueryCallback cb,
- gpointer closure);
-void e_book_simple_query_cancel (EBook *book,
- guint tag);
-
/* Getting the name of the repository. */
char *e_book_get_name (EBook *book);
diff --git a/addressbook/backend/ebook/e-card.c b/addressbook/backend/ebook/e-card.c
index 12877d3646..8c1f7b1905 100644
--- a/addressbook/backend/ebook/e-card.c
+++ b/addressbook/backend/ebook/e-card.c
@@ -9,6 +9,7 @@
*/
#include <config.h>
+#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -1348,6 +1349,154 @@ e_card_name_from_string(const char *full_name)
return name;
}
+
+/* This *so* doesn't belong here... at least not implemented in a
+ sucky way like this. But by getting it in here now, I can fix it
+ up w/o adding a new feature when we are in feature freeze. :-) */
+
+/* This is very Anglocentric. Maybe it should be by locale? */
+static gchar *name_synonyms[][2] = {
+ { "Jon", "John" }, /* Ah, the hacker's perogative */
+ { "Jon", "Jonathan" },
+ { "Daniel", "Dan" },
+ { "Joseph", "Joe" },
+ { "Robert", "Rob" },
+ { "Robert", "Bob" },
+ { "Richard", "Rich" },
+ { "Richard", "Dick" },
+ { "William", "Will" },
+ { "William", "Bill" },
+ { "Anthony", "Tony" },
+ { "Steven", "Steve" },
+ { "Michael", "Mike" },
+ { "Douglas", "Doug" },
+ { "Sidney", "Sid" },
+ { "Eric", "Erik" },
+ { "Chris", "Christopher" },
+ { "Chris", "Christine" },
+ { "Chris", "Christy" },
+ { "Elizabeth", "Liz" },
+ { "Jeff", "Geoff" },
+ { "Jeff", "Jeffrey" },
+ { "Jeff", "Geoffrey" },
+ { "Jim", "James" },
+ { "Abigal", "Abby" },
+ { "Amanda", "Amy" },
+ { "Amanda", "Manda" },
+ { "Di", "Diana" },
+ { "Di", "Diane" },
+ { "Maxine", "Max" },
+ { "Rebecca", "Becca" },
+ { "Rebecca", "Becky" },
+ { "Jennifer", "Jen" },
+ { "Jennifer", "Jenny" },
+ /* We could go on and on... */
+ { NULL, NULL }
+};
+
+static gboolean
+name_fragment_match (const gchar *a, const gchar *b)
+{
+ gint i;
+ gboolean nickname_match = FALSE;
+
+ if (!g_strcasecmp (a, b))
+ return TRUE;
+
+ /* Check for nicknames. Yes, the linear search blows. */
+ for (i=0; name_synonyms[i][0]; ++i) {
+ if (!g_strcasecmp (name_synonyms[i][1], a)) {
+ a = name_synonyms[i][0];
+ nickname_match = TRUE;
+ break;
+ }
+ }
+
+ for (i=0; name_synonyms[i][0]; ++i) {
+ if (!g_strcasecmp (name_synonyms[i][1], b)) {
+ b = name_synonyms[i][0];
+ nickname_match = TRUE;
+ break;
+ }
+ }
+
+ return nickname_match && !g_strcasecmp (a, b);
+}
+
+gboolean
+e_card_name_match_string (const ECardName *name, const gchar *str)
+{
+ gchar *cpy, *name_str;
+ gchar **strv, **namev;
+ gint i, j, match_count;
+ gboolean matched = FALSE;
+
+ g_return_val_if_fail (name != NULL, FALSE);
+ g_return_val_if_fail (str != NULL, FALSE);
+
+ cpy = g_strdup (str);
+ strv = g_strsplit (cpy, " ", 0);
+ for (i=0; strv[i]; ++i)
+ g_strstrip (strv[i]);
+
+ name_str = e_card_name_to_string (name);
+ namev = g_strsplit (name_str, " ", 0);
+ for (i=0; namev[i]; ++i)
+ g_strstrip (namev[i]);
+
+ match_count = 0;
+ i = j = 0;
+ while (strv[i] && namev[j]) {
+ gint k1, k2;
+
+ for (k1=0; strv[i+k1]; ++k1) {
+ if (name_fragment_match (strv[i+k1], namev[j]))
+ break;
+ }
+
+ for (k2=0; namev[j+k2]; ++k2) {
+ if (name_fragment_match (strv[i], namev[j+k2]))
+ break;
+ }
+
+ if (strv[i+k1] == NULL && namev[j+k2] == NULL) {
+ matched = FALSE;
+ goto cleanup_and_return;
+ }
+
+ ++match_count;
+
+ if (k1 < k2) {
+ i += k1+1;
+ ++j;
+ } else if (k2 < k1) {
+ ++i;
+ j += k2+1;
+ } else if (k1 == k2) {
+ i += k1+1;
+ j += k2+1;
+ }
+ }
+
+ /* This rule could be made more precise.
+ As it is, it will say that "Joe Smith" will match the name
+ "Joe Allen Smith" (which is good), but "de Icaza" will match
+ either "Miguel de Icaza" as well as Miguel's shiftless
+ brother "Roger de Icaza". In this sort of a case, the match
+ threshold should go up to 3. */
+ if (match_count >= 2)
+ matched = TRUE;
+
+
+ cleanup_and_return:
+ g_free (strv);
+ g_free (cpy);
+ g_free (namev);
+ g_free (name_str);
+
+ return matched;
+}
+
ECardArbitrary *
e_card_arbitrary_new(void)
{
@@ -1382,6 +1531,59 @@ e_card_arbitrary_free(ECardArbitrary *arbitrary)
g_free(arbitrary);
}
+/* EMail matching */
+static gboolean
+e_card_email_match_single_string (const gchar *a, const gchar *b)
+{
+ const gchar *xa = NULL, *xb = NULL;
+ gboolean match = TRUE;
+
+ for (xa=a; *xa && *xa != '@'; ++xa);
+ for (xb=b; *xb && *xb != '@'; ++xb);
+
+ if (xa-a != xb-b || *xa != *xb || g_strncasecmp (a, b, xa-a))
+ return FALSE;
+
+ if (*xa == '\0')
+ return TRUE;
+
+ /* Find the end of the string, then walk through backwards comparing.
+ This is so that we'll match joe@foobar.com and joe@mail.foobar.com.
+ */
+ while (*xa)
+ ++xa;
+ while (*xb)
+ ++xb;
+
+ while (match && *xa != '@' && *xb != '@') {
+ match = (*xa == *xb);
+ --xa;
+ --xb;
+ }
+
+ match = match && ((*xa == *xb) || (*xa == '.') || (*xb == '.'));
+
+ return match;
+}
+
+gboolean
+e_card_email_match_string (const ECard *card, const gchar *str)
+{
+ EIterator *iter;
+
+ g_return_val_if_fail (card && E_IS_CARD (card), FALSE);
+ g_return_val_if_fail (str != NULL, FALSE);
+
+ iter = e_list_get_iterator (card->email);
+ for (e_iterator_reset (iter); e_iterator_is_valid (iter); e_iterator_next (iter)) {
+ if (e_card_email_match_single_string (e_iterator_get (iter), str))
+ return TRUE;
+ }
+ gtk_object_unref (GTK_OBJECT (iter));
+
+ return FALSE;
+}
+
/*
* ECard lifecycle management and vCard loading/saving.
*/
diff --git a/addressbook/backend/ebook/e-card.h b/addressbook/backend/ebook/e-card.h
index 81473a28ed..eba8c07140 100644
--- a/addressbook/backend/ebook/e-card.h
+++ b/addressbook/backend/ebook/e-card.h
@@ -140,12 +140,18 @@ ECardName *e_card_name_copy (const ECardName
void e_card_name_free (ECardName *name);
char *e_card_name_to_string (const ECardName *name);
ECardName *e_card_name_from_string (const char *full_name);
+gboolean e_card_name_match_string (const ECardName *name,
+ const gchar *str);
/* ECardArbitrary manipulation */
ECardArbitrary *e_card_arbitrary_new (void);
ECardArbitrary *e_card_arbitrary_copy (const ECardArbitrary *arbitrary);
void e_card_arbitrary_free (ECardArbitrary *arbitrary);
+/* ECard email manipulation */
+gboolean e_card_email_match_string (const ECard *card,
+ const gchar *str);
+
/* Specialized functionality */
GList *e_card_load_cards_from_file (const char *filename);