aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--addressbook/ChangeLog28
-rw-r--r--addressbook/backend/ebook/e-book-util.c13
-rw-r--r--addressbook/backend/ebook/e-card-compare.c71
-rw-r--r--addressbook/backend/ebook/e-card-compare.h2
-rw-r--r--addressbook/backend/ebook/e-card.c144
-rw-r--r--addressbook/backend/ebook/e-card.h1
-rw-r--r--addressbook/backend/ebook/e-destination.c44
7 files changed, 136 insertions, 167 deletions
diff --git a/addressbook/ChangeLog b/addressbook/ChangeLog
index 1c3dbb6a46..9e45da5e5c 100644
--- a/addressbook/ChangeLog
+++ b/addressbook/ChangeLog
@@ -1,3 +1,31 @@
+2001-09-19 Jon Trowbridge <trow@ximian.com>
+
+ * backend/ebook/e-destination.c (name_and_email_simple_query_cb):
+ Use the default e-mail address if we have nothing else to go on.
+ Previously we just failed, which basically meant that name-only
+ searches would never work properly.
+ (nickname_simple_query_cb): The logic was a bit tangled here; if
+ our query status isn't SUCCESS, always give up but don't leak the
+ destination. And if our nickname query fails and we try the
+ name-and-email query, use the textrep for a name-only search. The
+ only reason we are doing a nickname query in the first place is if
+ we have an obviously invalid e-mail.
+ (launch_cardify_query): Use e_destination_is_valid to determine
+ if we should try a nickname query first.
+ These changes basically fix bug 7728, and generally make the
+ auto-cardification of addresses a lot more clever and robust.
+
+ * backend/ebook/e-book-util.c (name_and_email_cb): Use
+ e_card_compare_name_to_string instead of e_card_name_match_string.
+ (e_book_name_and_email_query): The arguments to g_strsplit were
+ in the wrong order. Doh!
+
+ * backend/ebook/e-card-compare.c (e_card_compare_name_to_string):
+ Added. Replaces e_card_name_match_string, and actually works.
+
+ * backend/ebook/e-card.c: Removed e_card_name_match_string
+ function, which didn't work particularly well.
+
2001-09-19 JP Rosevear <jpr@ximian.com>
* conduit/address-conduit.c (cursor_cb): don't add to the complete
diff --git a/addressbook/backend/ebook/e-book-util.c b/addressbook/backend/ebook/e-book-util.c
index 7811629571..1468274230 100644
--- a/addressbook/backend/ebook/e-book-util.c
+++ b/addressbook/backend/ebook/e-book-util.c
@@ -26,11 +26,13 @@
*/
#include <config.h>
+#include "e-book-util.h"
+
#include <gtk/gtkobject.h>
#include <gtk/gtksignal.h>
#include <libgnome/gnome-defs.h>
#include <libgnome/gnome-util.h>
-#include "e-book-util.h"
+#include "e-card-compare.h"
gboolean
e_book_load_local_address_book (EBook *book, EBookCallback open_response, gpointer closure)
@@ -351,9 +353,10 @@ name_and_email_cb (EBook *book, EBookSimpleQueryStatus status, const GList *card
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)))
+ if ((info->name == NULL || e_card_compare_name_to_string (card, info->name) >= E_CARD_MATCH_VAGUE)
+ && (info->email == NULL || e_card_email_match_string (card, info->email))) {
filtered_cards = g_list_append (filtered_cards, card);
+ }
cards = g_list_next (cards);
}
@@ -392,7 +395,7 @@ e_book_name_and_email_query (EBook *book,
* in the usernames of everyone out there, it shouldn't be that bad. (Famous last words.)
*/
if (email) {
- const gchar *t=email;
+ const gchar *t = email;
while (*t && *t != '@')
++t;
if (*t == '@') {
@@ -414,7 +417,7 @@ e_book_name_and_email_query (EBook *book,
gint i, count=0;
g_strstrip (name_cpy);
- namev = g_strsplit (" ", name_cpy, 0);
+ namev = g_strsplit (name_cpy, " ", 0);
for (i=0; namev[i]; ++i) {
if (*namev[i]) {
char *str = namev[i];
diff --git a/addressbook/backend/ebook/e-card-compare.c b/addressbook/backend/ebook/e-card-compare.c
index d8acbda48e..7ccfae0aa7 100644
--- a/addressbook/backend/ebook/e-card-compare.c
+++ b/addressbook/backend/ebook/e-card-compare.c
@@ -62,6 +62,8 @@ static gchar *name_synonyms[][2] = {
{ "elizabeth", "liz" },
{ "jeff", "geoff" },
{ "jeff", "geoffrey" },
+ { "tom", "thomas" },
+ { "dave", "david" },
{ "jim", "james" },
{ "abigal", "abby" },
{ "amanda", "amy" },
@@ -101,14 +103,79 @@ name_fragment_match (const gchar *a, const gchar *b)
}
ECardMatchType
+e_card_compare_name_to_string (ECard *card, const gchar *str)
+{
+ gchar **namev;
+ gboolean matched_given = FALSE, matched_additional = FALSE, matched_family = FALSE, mismatch = FALSE;
+ ECardMatchType match_type;
+ gint i;
+
+ g_return_val_if_fail (E_IS_CARD (card), E_CARD_MATCH_NOT_APPLICABLE);
+ g_return_val_if_fail (card->name != NULL, E_CARD_MATCH_NOT_APPLICABLE);
+ g_return_val_if_fail (str != NULL, E_CARD_MATCH_NOT_APPLICABLE);
+
+ namev = g_strsplit (str, " ", 0);
+
+ for (i = 0; namev[i] && !mismatch; ++i) {
+
+ if (card->name->given
+ && !matched_given
+ && name_fragment_match (card->name->given, namev[i])) {
+
+ matched_given = TRUE;
+
+ } else if (card->name->additional
+ && !matched_additional
+ && name_fragment_match (card->name->additional, namev[i])) {
+
+ matched_additional = TRUE;
+
+ } else if (card->name->family
+ && !matched_family
+ && !g_utf8_strcasecmp (card->name->family, namev[i])) {
+
+ matched_family = TRUE;
+
+ } else {
+
+ mismatch = TRUE;
+
+ }
+ }
+
+
+ match_type = E_CARD_MATCH_NONE;
+ if (! mismatch) {
+
+ switch ( (matched_family ? 1 : 0) + (matched_additional ? 1 : 0) + (matched_given ? 1 : 0)) {
+
+ case 0:
+ match_type = E_CARD_MATCH_NONE;
+ break;
+ case 1:
+ match_type = E_CARD_MATCH_VAGUE;
+ break;
+ case 2:
+ case 3:
+ match_type = E_CARD_MATCH_PARTIAL;
+ break;
+ }
+ }
+
+ g_strfreev (namev);
+
+ return match_type;
+}
+
+ECardMatchType
e_card_compare_name (ECard *card1, ECard *card2)
{
ECardName *a, *b;
gint matches=0, possible=0;
gboolean given_match = FALSE, additional_match = FALSE, family_match = FALSE;
- g_return_val_if_fail (card1 && E_IS_CARD (card1), E_CARD_MATCH_NOT_APPLICABLE);
- g_return_val_if_fail (card2 && E_IS_CARD (card2), E_CARD_MATCH_NOT_APPLICABLE);
+ g_return_val_if_fail (E_IS_CARD (card1), E_CARD_MATCH_NOT_APPLICABLE);
+ g_return_val_if_fail (E_IS_CARD (card2), E_CARD_MATCH_NOT_APPLICABLE);
a = card1->name;
b = card2->name;
diff --git a/addressbook/backend/ebook/e-card-compare.h b/addressbook/backend/ebook/e-card-compare.h
index e5f034600b..56d7b6e1f5 100644
--- a/addressbook/backend/ebook/e-card-compare.h
+++ b/addressbook/backend/ebook/e-card-compare.h
@@ -41,6 +41,8 @@ typedef enum {
typedef void (*ECardMatchQueryCallback) (ECard *card, ECard *match, ECardMatchType type, gpointer closure);
+ECardMatchType e_card_compare_name_to_string (ECard *card, const gchar *str);
+
ECardMatchType e_card_compare_name (ECard *card1, ECard *card2);
ECardMatchType e_card_compare_nickname (ECard *card1, ECard *card2);
ECardMatchType e_card_compare_email (ECard *card1, ECard *card2);
diff --git a/addressbook/backend/ebook/e-card.c b/addressbook/backend/ebook/e-card.c
index 835cc8195a..1b3ef694b6 100644
--- a/addressbook/backend/ebook/e-card.c
+++ b/addressbook/backend/ebook/e-card.c
@@ -1621,150 +1621,6 @@ 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 *name_str;
- gchar **strv, **namev;
- gint i, j, match_count;
-
- g_return_val_if_fail (name != NULL, FALSE);
- g_return_val_if_fail (str != NULL, FALSE);
-
- strv = g_strsplit (str, " ", 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 k;
- gboolean first_match = FALSE, second_match = FALSE;
-
- for (k=0; strv[i + k]; ++k) {
- if (name_fragment_match (strv[i + k], namev[j])) {
- first_match = TRUE;
- break;
- }
- }
-
- if (!first_match) {
- for (k=0; namev[j + k]; ++k) {
- if (name_fragment_match (strv[i], namev[j + k])) {
- second_match = TRUE;
- break;
- }
- }
- }
-
- if (! (first_match || second_match))
- break;
-
- ++match_count;
-
- if (first_match) {
- i += k + 1;
- ++j;
- } else {
- ++i;
- j += k + 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. */
-
- g_strfreev (strv);
- g_strfreev (namev);
- g_free (name_str);
-
- return match_count >= 2;
-}
-
ECardArbitrary *
e_card_arbitrary_new(void)
{
diff --git a/addressbook/backend/ebook/e-card.h b/addressbook/backend/ebook/e-card.h
index f1e35ce0a8..c45a73b6fd 100644
--- a/addressbook/backend/ebook/e-card.h
+++ b/addressbook/backend/ebook/e-card.h
@@ -164,7 +164,6 @@ ECardName *e_card_name_copy (const
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 */
diff --git a/addressbook/backend/ebook/e-destination.c b/addressbook/backend/ebook/e-destination.c
index f5564f37ae..c5287e5e6d 100644
--- a/addressbook/backend/ebook/e-destination.c
+++ b/addressbook/backend/ebook/e-destination.c
@@ -908,10 +908,15 @@ static void
name_and_email_simple_query_cb (EBook *book, EBookSimpleQueryStatus status, const GList *cards, gpointer closure)
{
EDestination *dest = E_DESTINATION (closure);
-
+
if (status == E_BOOK_SIMPLE_QUERY_STATUS_SUCCESS && g_list_length ((GList *) cards) == 1) {
ECard *card = E_CARD (cards->data);
- gint email_num = e_card_email_find_number (card, e_destination_get_email (dest));
+ const gchar *email = e_destination_get_email (dest);
+ gint email_num = 0;
+
+ if (e_destination_is_valid (dest) && email && *email) {
+ email_num = e_card_email_find_number (card, e_destination_get_email (dest));
+ }
if (email_num >= 0) {
dest->priv->has_been_cardified = TRUE;
@@ -933,27 +938,36 @@ nickname_simple_query_cb (EBook *book, EBookSimpleQueryStatus status, const GLis
{
EDestination *dest = E_DESTINATION (closure);
- if (status == E_BOOK_SIMPLE_QUERY_STATUS_SUCCESS && g_list_length ((GList *) cards) == 1) {
- dest->priv->has_been_cardified = TRUE;
- e_destination_set_card (dest, E_CARD (cards->data), 0); /* Uses primary e-mail by default. */
- gtk_signal_emit (GTK_OBJECT (dest), e_destination_signals[CARDIFIED]);
-
- gtk_object_unref (GTK_OBJECT (dest)); /* drop the reference held by the query */
+ if (status == E_BOOK_SIMPLE_QUERY_STATUS_SUCCESS) {
+ if (g_list_length ((GList *) cards) == 1) {
+ dest->priv->has_been_cardified = TRUE;
+ e_destination_set_card (dest, E_CARD (cards->data), 0); /* Uses primary e-mail by default. */
+ gtk_signal_emit (GTK_OBJECT (dest), e_destination_signals[CARDIFIED]);
+
+ gtk_object_unref (GTK_OBJECT (dest)); /* drop the reference held by the query */
+
+ } else {
+
+ /* We can only end up here if we don't look at all like an e-mail address, so
+ we do a name-only query on the textrep */
+
+ e_book_name_and_email_query (book,
+ e_destination_get_textrep (dest),
+ NULL,
+ name_and_email_simple_query_cb,
+ dest);
+ }
} else {
-
- e_book_name_and_email_query (book,
- e_destination_get_name (dest),
- e_destination_get_email (dest),
- name_and_email_simple_query_cb,
- dest);
+ /* Something went wrong with the query: drop our ref to the destination and return. */
+ gtk_object_unref (GTK_OBJECT (dest));
}
}
static void
launch_cardify_query (EDestination *dest)
{
- if (strchr (e_destination_get_textrep (dest), '@') == NULL) {
+ if (! e_destination_is_valid (dest)) {
/* If it doesn't look like an e-mail address, see if it is a nickname. */
e_book_nickname_query (dest->priv->cardify_book,