diff options
-rw-r--r-- | addressbook/ChangeLog | 28 | ||||
-rw-r--r-- | addressbook/backend/ebook/e-book-util.c | 13 | ||||
-rw-r--r-- | addressbook/backend/ebook/e-card-compare.c | 71 | ||||
-rw-r--r-- | addressbook/backend/ebook/e-card-compare.h | 2 | ||||
-rw-r--r-- | addressbook/backend/ebook/e-card.c | 144 | ||||
-rw-r--r-- | addressbook/backend/ebook/e-card.h | 1 | ||||
-rw-r--r-- | addressbook/backend/ebook/e-destination.c | 44 |
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, |