aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJon Trowbridge <trow@ximian.com>2001-06-30 13:23:09 +0800
committerJon Trowbridge <trow@src.gnome.org>2001-06-30 13:23:09 +0800
commit7c5dd95cd7aefa8243edac3c67bf1910fc905c4e (patch)
tree5c8dc3c28a6bac7d3e1643e9cdcfb0b75f28ebbc
parentc187a911c8926429946cc385fd5f7c8f0932d3e3 (diff)
downloadgsoc2013-evolution-7c5dd95cd7aefa8243edac3c67bf1910fc905c4e.tar
gsoc2013-evolution-7c5dd95cd7aefa8243edac3c67bf1910fc905c4e.tar.gz
gsoc2013-evolution-7c5dd95cd7aefa8243edac3c67bf1910fc905c4e.tar.bz2
gsoc2013-evolution-7c5dd95cd7aefa8243edac3c67bf1910fc905c4e.tar.lz
gsoc2013-evolution-7c5dd95cd7aefa8243edac3c67bf1910fc905c4e.tar.xz
gsoc2013-evolution-7c5dd95cd7aefa8243edac3c67bf1910fc905c4e.tar.zst
gsoc2013-evolution-7c5dd95cd7aefa8243edac3c67bf1910fc905c4e.zip
Make the standard for considering two cards to be match stricter.
2001-06-30 Jon Trowbridge <trow@ximian.com> * gui/merging/e-card-merging.c (match_query_callback): Make the standard for considering two cards to be match stricter. * gui/component/select-names/e-select-names-completion.c (make_match): Use the card's use-score to set the match's sort_major value. (match_name): Removed obsolete code. (e_select_names_completion_begin): Added (double) cast to make match->score calculation come out properly. * backend/ebook/e-card.c: Added X-EVOLUTION-LAST-USE and X-EVOLUTION-USE-SCORE to attribute_jump_array. (e_card_get_today): Added. A convenience routine for getting today's date and putting it in a GDate. (e_card_get_use_score): Added. Compute the current, time-decayed, use-score for the card. (e_card_touch): Increment the use-score by one; update the last used date. (e_card_date_to_string): Added as a convenience routine, getting rid of some code duplication. (e_card_get_vobject): Add handlers for X-EVOLUTION-USE-SCORE and X-EVOLUTION-LAST-USE. (parse_last_use): Added. (parse_use_score): Added. (e_card_class_init): Added args for last-use and use-score. (e_card_get_arg): Added handlers for last-use and use-score. o (e_card_set_arg): Added handlers for last-use and use-score. * backend/ebook/e-destination.c: Added pending_card_id to EDestinationPrivate struct. (e_destination_copy): Copy the pending_card_id. (e_destination_is_empty): Check for a pending_card_id. We are non-empty if we have one. (e_destination_clear_card): Clear pending_card_id. (e_destination_set_card): Clear pending_card_id. (e_destination_has_pending_card): Added. (e_destination_use_card): Added. An asynchronous way to load a pending card and then apply a callback to it. (build_field): Be paranoid, map our special characters to '_'. (e_destination_export): Use EXPORT_MAX_FIELDS symbol rather than a hard-wired array size. Added the "card" entry. (e_destination_import): Fix bug in handling of the "name" field. Process the "card" field. (e_destination_touch): "Touch" and commit the ECard corresponding to the e-mail address in the destination. (A query against the local addressbook is actually performed, in case the destination isn't cardified. * backend/ebook/e-card-compare.c (e_card_compare_name): Revamp the way E_CARD_MATCH_FOO results are mapped to comparison results. Report better matches when the family name is matched. svn path=/trunk/; revision=10626
-rw-r--r--addressbook/ChangeLog55
-rw-r--r--addressbook/backend/ebook/e-card-compare.c34
-rw-r--r--addressbook/backend/ebook/e-card.c161
-rw-r--r--addressbook/backend/ebook/e-card.h23
-rw-r--r--addressbook/backend/ebook/e-destination.c176
-rw-r--r--addressbook/backend/ebook/e-destination.h13
-rw-r--r--addressbook/gui/component/select-names/e-select-names-completion.c24
-rw-r--r--addressbook/gui/component/select-names/e-select-names-model.c5
-rw-r--r--addressbook/gui/merging/e-card-merging.c2
9 files changed, 429 insertions, 64 deletions
diff --git a/addressbook/ChangeLog b/addressbook/ChangeLog
index 6736d53b7c..06db0e7239 100644
--- a/addressbook/ChangeLog
+++ b/addressbook/ChangeLog
@@ -1,3 +1,58 @@
+2001-06-30 Jon Trowbridge <trow@ximian.com>
+
+ * gui/merging/e-card-merging.c (match_query_callback): Make the
+ standard for considering two cards to be match stricter.
+
+ * gui/component/select-names/e-select-names-completion.c
+ (make_match): Use the card's use-score to set the match's
+ sort_major value.
+ (match_name): Removed obsolete code.
+ (e_select_names_completion_begin): Added (double) cast to make
+ match->score calculation come out properly.
+
+ * backend/ebook/e-card.c: Added X-EVOLUTION-LAST-USE and
+ X-EVOLUTION-USE-SCORE to attribute_jump_array.
+ (e_card_get_today): Added. A convenience routine for getting
+ today's date and putting it in a GDate.
+ (e_card_get_use_score): Added. Compute the current, time-decayed,
+ use-score for the card.
+ (e_card_touch): Increment the use-score by one; update the last
+ used date.
+ (e_card_date_to_string): Added as a convenience routine, getting
+ rid of some code duplication.
+ (e_card_get_vobject): Add handlers for X-EVOLUTION-USE-SCORE and
+ X-EVOLUTION-LAST-USE.
+ (parse_last_use): Added.
+ (parse_use_score): Added.
+ (e_card_class_init): Added args for last-use and use-score.
+ (e_card_get_arg): Added handlers for last-use and use-score.
+ o
+ (e_card_set_arg): Added handlers for last-use and use-score.
+
+ * backend/ebook/e-destination.c: Added pending_card_id to
+ EDestinationPrivate struct.
+ (e_destination_copy): Copy the pending_card_id.
+ (e_destination_is_empty): Check for a pending_card_id. We are
+ non-empty if we have one.
+ (e_destination_clear_card): Clear pending_card_id.
+ (e_destination_set_card): Clear pending_card_id.
+ (e_destination_has_pending_card): Added.
+ (e_destination_use_card): Added. An asynchronous way to load a
+ pending card and then apply a callback to it.
+ (build_field): Be paranoid, map our special characters to '_'.
+ (e_destination_export): Use EXPORT_MAX_FIELDS symbol rather than a
+ hard-wired array size. Added the "card" entry.
+ (e_destination_import): Fix bug in handling of the "name" field.
+ Process the "card" field.
+ (e_destination_touch): "Touch" and commit the ECard corresponding
+ to the e-mail address in the destination. (A query against the
+ local addressbook is actually performed, in case the destination
+ isn't cardified.
+
+ * backend/ebook/e-card-compare.c (e_card_compare_name): Revamp the
+ way E_CARD_MATCH_FOO results are mapped to comparison results.
+ Report better matches when the family name is matched.
+
2001-06-29 Christopher James Lahey <clahey@ximian.com>
* gui/component/select-names/e-select-names.c (update_query):
diff --git a/addressbook/backend/ebook/e-card-compare.c b/addressbook/backend/ebook/e-card-compare.c
index 92f1cc9099..05be64d560 100644
--- a/addressbook/backend/ebook/e-card-compare.c
+++ b/addressbook/backend/ebook/e-card-compare.c
@@ -105,6 +105,7 @@ 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);
@@ -117,36 +118,45 @@ e_card_compare_name (ECard *card1, ECard *card2)
if (a->given && b->given) {
++possible;
- if (name_fragment_match (a->given, b->given))
+ if (name_fragment_match (a->given, b->given)) {
++matches;
+ given_match = TRUE;
+ }
}
if (a->additional && b->additional) {
++possible;
- if (name_fragment_match (a->additional, b->additional))
+ if (name_fragment_match (a->additional, b->additional)) {
++matches;
+ additional_match = TRUE;
+ }
}
if (a->family && b->family) {
++possible;
- if (name_fragment_match (a->family, b->family))
+ if (name_fragment_match (a->family, b->family)) {
++matches;
+ family_match = TRUE;
+ }
}
/* Now look at the # of matches and try to intelligently map
- an E_CARD_MATCH_* type to it. */
+ an E_CARD_MATCH_* type to it. Special consideration is given
+ to family-name matches. */
if (possible == 0)
return E_CARD_MATCH_NOT_APPLICABLE;
- if (matches == 0)
- return E_CARD_MATCH_NONE;
- if (matches == possible) {
- return possible > 1 ? E_CARD_MATCH_EXACT : E_CARD_MATCH_PARTIAL;
- } else if (matches == possible-1)
- return E_CARD_MATCH_PARTIAL;
- else
- return E_CARD_MATCH_VAGUE;
+ if (possible == 1)
+ return family_match ? E_CARD_MATCH_VAGUE : E_CARD_MATCH_NONE;
+
+ if (possible == matches)
+ return family_match ? E_CARD_MATCH_EXACT : E_CARD_MATCH_PARTIAL;
+
+ if (possible == matches+1)
+ return family_match ? E_CARD_MATCH_PARTIAL : E_CARD_MATCH_VAGUE;
+
+ return E_CARD_MATCH_NONE;
}
diff --git a/addressbook/backend/ebook/e-card.c b/addressbook/backend/ebook/e-card.c
index d80cd63369..a1698aaa4e 100644
--- a/addressbook/backend/ebook/e-card.c
+++ b/addressbook/backend/ebook/e-card.c
@@ -18,6 +18,8 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <time.h>
+#include <math.h>
#include <gtk/gtkobject.h>
#include <bonobo/bonobo-object-client.h>
@@ -69,6 +71,8 @@ enum {
ARG_EVOLUTION_LIST_SHOW_ADDRESSES,
ARG_ARBITRARY,
ARG_ID,
+ ARG_LAST_USE,
+ ARG_USE_SCORE,
};
#if 0
@@ -114,6 +118,8 @@ static void parse_list(ECard *card, VObject *object);
static void parse_list_show_addresses(ECard *card, VObject *object);
static void parse_arbitrary(ECard *card, VObject *object);
static void parse_id(ECard *card, VObject *object);
+static void parse_last_use(ECard *card, VObject *object);
+static void parse_use_score(ECard *card, VObject *object);
static ECardPhoneFlags get_phone_flags (VObject *vobj);
static void set_phone_flags (VObject *vobj, ECardPhoneFlags flags);
@@ -151,6 +157,9 @@ struct {
{ "CATEGORIES", parse_categories },
{ XEV_WANTS_HTML, parse_wants_html },
{ XEV_ARBITRARY, parse_arbitrary },
+ { VCUniqueStringProp, parse_id },
+ { "X-EVOLUTION-LAST-USE", parse_last_use },
+ { "X-EVOLUTION-USE-SCORE", parse_use_score },
{ XEV_LIST, parse_list },
{ XEV_LIST_SHOW_ADDRESSES, parse_list_show_addresses },
{ VCUniqueStringProp, parse_id }
@@ -215,7 +224,8 @@ e_card_new (char *vcard)
return card;
}
-ECard *e_card_duplicate(ECard *card)
+ECard *
+e_card_duplicate(ECard *card)
{
char *vcard = e_card_get_vcard(card);
ECard *new_card = e_card_new(vcard);
@@ -223,6 +233,65 @@ ECard *e_card_duplicate(ECard *card)
return new_card;
}
+static void
+e_card_get_today (GDate *dt)
+{
+ time_t now;
+ struct tm *now_tm;
+ if (dt == NULL)
+ return;
+
+ time (&now);
+ now_tm = localtime (&now);
+
+ g_date_set_dmy (dt, now_tm->tm_mday, now_tm->tm_mon + 1, now_tm->tm_year + 1900);
+}
+
+float
+e_card_get_use_score(ECard *card)
+{
+ GDate today, last_use;
+ gint days_since_last_use;
+
+ g_return_val_if_fail (card != NULL && E_IS_CARD (card), 0);
+
+ if (card->last_use == NULL)
+ return 0.0;
+
+ e_card_get_today (&today);
+ g_date_set_dmy (&last_use, card->last_use->day, card->last_use->month, card->last_use->year);
+
+ days_since_last_use = g_date_julian (&today) - g_date_julian (&last_use);
+
+ /* Apply a seven-day "grace period" to the use score decay. */
+ days_since_last_use -= 7;
+ if (days_since_last_use < 0)
+ days_since_last_use = 0;
+
+ return MAX (card->raw_use_score, 0) * exp (- days_since_last_use / 30.0);
+}
+
+void
+e_card_touch(ECard *card)
+{
+ GDate today;
+ double use_score;
+
+ g_return_if_fail (card != NULL && E_IS_CARD (card));
+
+ e_card_get_today (&today);
+ use_score = e_card_get_use_score (card);
+
+ if (card->last_use == NULL)
+ card->last_use = g_new (ECardDate, 1);
+
+ card->last_use->day = g_date_day (&today);
+ card->last_use->month = g_date_month (&today);
+ card->last_use->year = g_date_year (&today);
+
+ card->raw_use_score = use_score + 1.0;
+}
+
/**
* e_card_get_id:
* @card: an #ECard
@@ -252,6 +321,18 @@ e_card_set_id (ECard *card, const char *id)
card->id = g_strdup(id);
}
+static gchar *
+e_card_date_to_string (ECardDate *dt)
+{
+ if (dt)
+ return g_strdup_printf ("%04d-%02d-%02d",
+ CLAMP(dt->year, 1000, 9999),
+ CLAMP(dt->month, 1, 12),
+ CLAMP(dt->day, 1, 31));
+ else
+ return NULL;
+}
+
static VObject *
e_card_get_vobject (ECard *card)
{
@@ -353,13 +434,8 @@ e_card_get_vobject (ECard *card)
}
if ( card->bday ) {
- ECardDate date;
char *value;
- date = *card->bday;
- date.year = MIN(date.year, 9999);
- date.month = MIN(date.month, 12);
- date.day = MIN(date.day, 31);
- value = g_strdup_printf("%04d-%02d-%02d", date.year, date.month, date.day);
+ value = e_card_date_to_string (card->bday);
addPropValue(vobj, VCBirthDateProp, value);
g_free(value);
}
@@ -399,13 +475,8 @@ e_card_get_vobject (ECard *card)
addPropValue(vobj, "X-EVOLUTION-SPOUSE", card->spouse);
if ( card->anniversary ) {
- ECardDate date;
char *value;
- date = *card->anniversary;
- date.year = MIN(date.year, 9999);
- date.month = MIN(date.month, 12);
- date.day = MIN(date.day, 31);
- value = g_strdup_printf("%04d-%02d-%02d", date.year, date.month, date.day);
+ value = e_card_date_to_string (card->anniversary);
addPropValue(vobj, "X-EVOLUTION-ANNIVERSARY", value);
g_free(value);
}
@@ -424,6 +495,20 @@ e_card_get_vobject (ECard *card)
addProp(noteprop, VCQuotedPrintableProp);
}
+ if (card->last_use) {
+ char *value;
+ value = e_card_date_to_string (card->last_use);
+ addPropValue (vobj, "X-EVOLUTION-LAST-USE", value);
+ g_free (value);
+ }
+
+ if (card->raw_use_score > 0) {
+ char *value;
+ value = g_strdup_printf ("%f", card->raw_use_score);
+ addPropValue (vobj, "X-EVOLUTION-USE-SCORE", value);
+ g_free (value);
+ }
+
if (card->categories) {
EIterator *iterator;
int length = 0;
@@ -989,6 +1074,31 @@ parse_id(ECard *card, VObject *vobj)
}
static void
+parse_last_use(ECard *card, VObject *vobj)
+{
+ if ( vObjectValueType (vobj) ) {
+ char *str = fakeCString (vObjectUStringZValue (vobj));
+ if ( card->last_use )
+ g_free(card->last_use);
+ card->last_use = g_new(ECardDate, 1);
+ *(card->last_use) = e_card_date_from_string(str);
+ free(str);
+ }
+}
+
+static void
+parse_use_score(ECard *card, VObject *vobj)
+{
+ card->raw_use_score = 0;
+
+ if ( vObjectValueType (vobj) ) {
+ char *str = fakeCString (vObjectUStringZValue (vobj));
+ card->raw_use_score = MAX(0, atof (str));
+ free (str);
+ }
+}
+
+static void
parse_attribute(ECard *card, VObject *vobj)
{
ParsePropertyFunc function = g_hash_table_lookup(E_CARD_CLASS(GTK_OBJECT(card)->klass)->attribute_jump_table, vObjectName(vobj));
@@ -1099,6 +1209,10 @@ e_card_class_init (ECardClass *klass)
GTK_TYPE_OBJECT, GTK_ARG_READWRITE, ARG_ARBITRARY);
gtk_object_add_arg_type ("ECard::id",
GTK_TYPE_STRING, GTK_ARG_READWRITE, ARG_ID);
+ gtk_object_add_arg_type ("ECard::last_use",
+ GTK_TYPE_POINTER, GTK_ARG_READWRITE, ARG_LAST_USE);
+ gtk_object_add_arg_type ("ECard::use_score",
+ GTK_TYPE_FLOAT, GTK_ARG_READWRITE, ARG_USE_SCORE);
object_class->destroy = e_card_destroy;
@@ -1818,6 +1932,18 @@ e_card_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
g_free(card->id);
card->id = g_strdup(GTK_VALUE_STRING(*arg));
break;
+ case ARG_LAST_USE:
+ g_free(card->last_use);
+ if (GTK_VALUE_POINTER (*arg)) {
+ card->last_use = g_new (ECardDate, 1);
+ memcpy (card->last_use, GTK_VALUE_POINTER (*arg), sizeof (ECardDate));
+ } else {
+ card->last_use = NULL;
+ }
+ break;
+ case ARG_USE_SCORE:
+ card->raw_use_score = GTK_VALUE_FLOAT(*arg);
+ break;
case ARG_EVOLUTION_LIST:
card->list = GTK_VALUE_BOOL(*arg);
break;
@@ -1964,6 +2090,13 @@ e_card_get_arg (GtkObject *object, GtkArg *arg, guint arg_id)
case ARG_ID:
GTK_VALUE_STRING(*arg) = card->id;
break;
+ case ARG_LAST_USE:
+ GTK_VALUE_POINTER(*arg) = card->last_use;
+ break;
+
+ case ARG_USE_SCORE:
+ GTK_VALUE_FLOAT(*arg) = e_card_get_use_score (card);
+ break;
case ARG_EVOLUTION_LIST:
GTK_VALUE_BOOL(*arg) = card->list;
break;
@@ -2013,6 +2146,8 @@ e_card_init (ECard *card)
card->list = FALSE;
card->list_show_addresses = FALSE;
card->arbitrary = NULL;
+ card->last_use = NULL;
+ card->raw_use_score = 0;
#if 0
c = g_new0 (ECard, 1);
diff --git a/addressbook/backend/ebook/e-card.h b/addressbook/backend/ebook/e-card.h
index 78c6f3d661..d43f0666c2 100644
--- a/addressbook/backend/ebook/e-card.h
+++ b/addressbook/backend/ebook/e-card.h
@@ -34,12 +34,12 @@ struct _ECard {
char *file_as; /* The File As field. */
char *fname; /* The full name. */
ECardName *name; /* The structured name. */
- EList *address; /* Delivery addresses (ECardDeliveryAddress *) */
- EList *address_label; /* Delivery address labels
+ EList *address; /* Delivery addresses (ECardDeliveryAddress *) */
+ EList *address_label; /* Delivery address labels
* (ECardAddrLabel *) */
- EList *phone; /* Phone numbers (ECardPhone *) */
- EList *email; /* Email addresses (char *) */
+ EList *phone; /* Phone numbers (ECardPhone *) */
+ EList *email; /* Email addresses (char *) */
char *url; /* The person's web page. */
ECardDate *bday; /* The person's birthday. */
@@ -67,13 +67,17 @@ struct _ECard {
gint timezone; /* number of minutes from UTC as an int */
- EList *categories; /* Categories. */
+ ECardDate *last_use;
+ float raw_use_score;
- EList *arbitrary; /* Arbitrary fields. */
+ EList *categories; /* Categories. */
- guint32 wants_html : 1; /* Wants html mail. */
- guint32 wants_html_set : 1; /* Wants html mail. */
+ EList *arbitrary; /* Arbitrary fields. */
+
+
+ guint32 wants_html : 1; /* Wants html mail. */
+ guint32 wants_html_set : 1; /* Wants html mail. */
guint32 list : 1; /* If the card corresponds to a contact list */
guint32 list_show_addresses : 1; /* Whether to show the addresses
in the To: or Bcc: field */
@@ -119,6 +123,9 @@ char *e_card_get_vcard (ECard
char *e_card_list_get_vcard (GList *list);
ECard *e_card_duplicate (ECard *card);
+float e_card_get_use_score (ECard *card);
+void e_card_touch (ECard *card);
+
/* Evolution List convenience functions */
gboolean e_card_evolution_list (ECard *card);
gboolean e_card_evolution_list_show_addresses(ECard *card);
diff --git a/addressbook/backend/ebook/e-destination.c b/addressbook/backend/ebook/e-destination.c
index 83bd96a7d1..513f934cdf 100644
--- a/addressbook/backend/ebook/e-destination.c
+++ b/addressbook/backend/ebook/e-destination.c
@@ -26,13 +26,20 @@
*/
#include <config.h>
+#include "e-destination.h"
+
#include <string.h>
#include <gtk/gtkobject.h>
#include <libgnome/gnome-defs.h>
#include <libgnome/gnome-i18n.h>
-#include "e-destination.h"
+#include "e-book.h"
+#include "e-book-util.h"
+
struct _EDestinationPrivate {
+
+ gchar *pending_card_id;
+
ECard *card;
gint card_email_num;
@@ -117,6 +124,8 @@ e_destination_copy (EDestination *dest)
new_dest = e_destination_new ();
+ new_dest->priv->pending_card_id = g_strdup (new_dest->priv->pending_card_id);
+
new_dest->priv->card = dest->priv->card;
if (new_dest->priv->card)
gtk_object_ref (GTK_OBJECT (new_dest->priv->card));
@@ -135,12 +144,15 @@ e_destination_is_empty (EDestination *dest)
{
g_return_val_if_fail (dest && E_IS_DESTINATION (dest), TRUE);
- return !(dest->priv->card || (dest->priv->string && *dest->priv->string));
+ return !(dest->priv->card || dest->priv->pending_card_id || (dest->priv->string && *dest->priv->string));
}
static void
e_destination_clear_card (EDestination *dest)
{
+ g_free (dest->priv->pending_card_id);
+ dest->priv->pending_card_id = NULL;
+
if (dest->priv->card)
gtk_object_unref (GTK_OBJECT (dest->priv->card));
dest->priv->card = NULL;
@@ -168,6 +180,11 @@ 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;
+ }
+
if (dest->priv->card != card) {
if (dest->priv->card)
gtk_object_unref (GTK_OBJECT (dest->priv->card));
@@ -199,6 +216,83 @@ e_destination_set_html_mail_pref (EDestination *dest, gboolean x)
dest->priv->wants_html_mail = x;
}
+gboolean
+e_destination_has_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)
+{
+ g_return_val_if_fail (dest && E_IS_DESTINATION (dest), FALSE);
+ return dest->priv->pending_card_id != NULL;
+}
+
+
+typedef struct _UseCard UseCard;
+struct _UseCard {
+ EDestination *dest;
+ EDestinationCardCallback cb;
+ gpointer closure;
+};
+
+static void
+use_card_cb (EBook *book, 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) {
+ 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;
+
+ }
+
+ }
+
+ if (uc->cb)
+ uc->cb (uc->dest, uc->dest->priv->card, uc->closure);
+
+ gtk_object_unref (GTK_OBJECT (uc->dest));
+ g_free (uc);
+}
+
+void
+e_destination_use_card (EDestination *dest, EDestinationCardCallback cb, gpointer closure)
+{
+ g_return_if_fail (dest && E_IS_DESTINATION (dest));
+
+ if (dest->priv->card) {
+
+ if (cb) {
+ cb (dest, dest->priv->card, closure);
+ }
+
+ } else {
+ UseCard *uc = g_new (UseCard, 1);
+ uc->dest = dest;
+ gtk_object_ref (GTK_OBJECT (uc->dest));
+ uc->cb = cb;
+ uc->closure = closure;
+ e_book_use_local_address_book (use_card_cb, uc);
+ }
+}
+
ECard *
e_destination_get_card (const EDestination *dest)
{
@@ -393,11 +487,13 @@ e_destination_get_address_textv (EDestination **destv)
#define DESTINATION_TAG "DEST"
#define DESTINATION_SEPARATOR "|"
+#define VEC_SEPARATOR "\1"
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);
}
@@ -405,13 +501,37 @@ 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);
}
static gchar *
build_field (const gchar *key, const gchar *value)
{
- return g_strdup_printf ("%s=%s", key, value);
+ gchar *field;
+ gchar *c;
+
+ g_return_val_if_fail (key != NULL, NULL);
+ g_return_val_if_fail (value != NULL, NULL);
+
+ field = g_strdup_printf ("%s=%s", key, value);
+
+ /* Paranoia: Convert any '=' in the key to '_' */
+ c = field;
+ while (*key) {
+ if (*c == '=')
+ *c = '_';
+ ++key;
+ ++c;
+ }
+
+ /* Paranoia: Convert any '\1' or '|' in the key or value to '_' */
+ for (c=field; *c; ++c) {
+ if (*c == VEC_SEPARATOR || *c == DESTINATION_SEPARATOR)
+ *c = '_';
+ }
+
+ return field;
}
/* Modifies string in place, \0-terminates after the key, returns pointer to "value",
@@ -426,17 +546,18 @@ extract_field (gchar *field)
return s+1;
}
-
+#define EXPORT_MAX_FIELDS 10
gchar *
e_destination_export (const EDestination *dest)
{
+ ECard *card;
gchar **fields;
gchar *str;
gint i;
g_return_val_if_fail (dest && E_IS_DESTINATION (dest), NULL);
- fields = g_new (gchar *, 5);
+ fields = g_new (gchar *, EXPORT_MAX_FIELDS);
fields[0] = g_strdup (DESTINATION_TAG);
fields[1] = build_field ("addr", e_destination_get_email (dest));
@@ -448,6 +569,10 @@ e_destination_export (const EDestination *dest)
fields[i++] = build_field ("html",
e_destination_get_html_mail_pref (dest) ? "Y" : "N");
+ card = e_destination_get_card (dest);
+ if (card)
+ fields[i++] = build_field ("card", e_card_get_id (card));
+
fields[i] = NULL;
@@ -464,7 +589,7 @@ e_destination_import (const gchar *str)
gchar **fields;
gint i;
- gchar *addr = NULL, *name = NULL;
+ gchar *addr = NULL, *name = NULL, *card = NULL;
gboolean want_html = FALSE;
g_return_val_if_fail (str, NULL);
@@ -493,12 +618,20 @@ e_destination_import (const gchar *str)
g_warning ("name redefined: \"%s\" => \"%s\"", name, value);
}
- name = g_strdup (name);
+ name = g_strdup (value);
} else if (!strcmp ("html", key)) {
want_html = (*value == 'Y');
+ } else if (!strcmp ("card", key)) {
+
+ if (card) {
+ g_warning ("card redefined: \"%s\" => \"%s\"", card, value);
+ }
+
+ card = g_strdup (value);
+
}
}
@@ -510,6 +643,9 @@ e_destination_import (const gchar *str)
/* 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;
+
+ g_message ("name:[%s] addr:[%s]", name, addr);
e_destination_set_html_mail_pref (dest, want_html);
@@ -518,8 +654,6 @@ e_destination_import (const gchar *str)
return dest;
}
-#define VEC_SEPARATOR "\1"
-
gchar *
e_destination_exportv (EDestination **destv)
{
@@ -574,3 +708,27 @@ e_destination_importv (const gchar *str)
g_strfreev (strv);
return destv;
}
+
+static void
+touch_cb (EBook *book, const gchar *addr, ECard *card, gpointer closure)
+{
+ if (book != NULL && card != NULL) {
+ e_card_touch (card);
+ g_message ("Use score for \"%s\" is now %f", addr, e_card_get_use_score (card));
+ e_book_commit_card (book, card, NULL, NULL);
+ }
+}
+
+void
+e_destination_touch (EDestination *dest)
+{
+ const gchar *email;
+
+ g_return_if_fail (dest && E_IS_DESTINATION (dest));
+
+ email = e_destination_get_email (dest);
+
+ if (email) {
+ e_book_query_address_locally (email, touch_cb, NULL);
+ }
+}
diff --git a/addressbook/backend/ebook/e-destination.h b/addressbook/backend/ebook/e-destination.h
index bb3c77d475..bacd9dd428 100644
--- a/addressbook/backend/ebook/e-destination.h
+++ b/addressbook/backend/ebook/e-destination.h
@@ -30,6 +30,7 @@
#include <gtk/gtkobject.h>
#include <addressbook/backend/ebook/e-card.h>
+#include <addressbook/backend/ebook/e-book.h>
#define E_TYPE_DESTINATION (e_destination_get_type ())
#define E_DESTINATION(o) (GTK_CHECK_CAST ((o), E_TYPE_DESTINATION, EDestination))
@@ -40,6 +41,8 @@
typedef struct _EDestination EDestination;
typedef struct _EDestinationClass EDestinationClass;
+typedef void (*EDestinationCardCallback) (EDestination *dest, ECard *card, gpointer closure);
+
struct _EDestinationPrivate;
struct _EDestination {
@@ -64,6 +67,11 @@ void e_destination_set_card (EDestination *, ECard *card, gi
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 *);
+
+void e_destination_use_card (EDestination *, EDestinationCardCallback cb, gpointer closure);
+
ECard *e_destination_get_card (const EDestination *);
gint e_destination_get_email_num (const EDestination *);
const gchar *e_destination_get_string (const EDestination *);
@@ -79,16 +87,13 @@ gboolean e_destination_get_html_mail_pref (const EDestination *);
gchar *e_destination_get_address_textv (EDestination **);
-
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);
-
-
-
+void e_destination_touch (EDestination *);
#endif /* __E_DESTINATION_H__ */
diff --git a/addressbook/gui/component/select-names/e-select-names-completion.c b/addressbook/gui/component/select-names/e-select-names-completion.c
index b4fb73cc9e..27cc598f5d 100644
--- a/addressbook/gui/component/select-names/e-select-names-completion.c
+++ b/addressbook/gui/component/select-names/e-select-names-completion.c
@@ -26,9 +26,12 @@
*/
#include <config.h>
+#include "e-select-names-completion.h"
+
#include <ctype.h>
#include <stdio.h>
#include <string.h>
+#include <math.h>
#include <gtk/gtksignal.h>
#include <libgnome/gnome-defs.h>
@@ -39,7 +42,7 @@
#include <addressbook/backend/ebook/e-book-util.h>
#include <addressbook/backend/ebook/e-destination.h>
#include <addressbook/backend/ebook/e-card-simple.h>
-#include "e-select-names-completion.h"
+
struct _ESelectNamesCompletionPrivate {
@@ -99,9 +102,12 @@ static ECompletionMatch *
make_match (EDestination *dest, const gchar *menu_form, double score)
{
ECompletionMatch *match = g_new0 (ECompletionMatch, 1);
+ ECard *card = e_destination_get_card (dest);
+
e_completion_match_construct (match);
e_completion_match_set_text (match, e_destination_get_name (dest), menu_form);
+ match->sort_major = card ? floor (e_card_get_use_score (card)) : 0;
match->score = score;
match->sort_minor = e_destination_get_email_num (dest);
@@ -357,20 +363,6 @@ match_name (ESelectNamesCompletion *comp, EDestination *dest)
score *= 100;
}
-#if 0
- /* This leads to some pretty counter-intuitive results, so I'm disabling it. */
- email = e_destination_get_email (dest);
- if (email) {
- /* Do the same for the email address. */
- gchar *at = strchr (email, '@');
- len = at ? at-email : strlen (email);
- if ((card->name->given && !g_utf8_strncasecmp (card->name->given, email, MIN (strlen (card->name->given), len)))
- || (card->name->family && !g_utf8_strncasecmp (card->name->family, email, MIN (strlen (card->name->family), len)))
- || (card->name->additional && !g_utf8_strncasecmp (card->name->additional, email, MIN (strlen (card->name->additional), len))))
- score *= 100;
- }
-#endif
-
have_given = card->name->given && *card->name->given;
have_additional = card->name->additional && *card->name->additional;
have_family = card->name->family && *card->name->family;
@@ -1048,7 +1040,7 @@ e_select_names_completion_begin (ECompletion *comp, const gchar *text, gint pos,
ECompletionMatch *match = g_new (ECompletionMatch, 1);
e_completion_match_construct (match);
e_completion_match_set_text (match, text, override[j].text[k]);
- match->score = 1 / (k + 1);
+ match->score = 1 / (double) (k + 1);
e_completion_found_match (comp, match);
}
diff --git a/addressbook/gui/component/select-names/e-select-names-model.c b/addressbook/gui/component/select-names/e-select-names-model.c
index 74dfcb8158..d562b40a64 100644
--- a/addressbook/gui/component/select-names/e-select-names-model.c
+++ b/addressbook/gui/component/select-names/e-select-names-model.c
@@ -330,7 +330,10 @@ e_select_names_model_export_destinationv (ESelectNamesModel *model)
destv = g_new0 (EDestination *, len+1);
for (i=0, j = model->priv->data; j != NULL; j = g_list_next (j)) {
- destv[i++] = E_DESTINATION (j->data);
+ EDestination *dest = E_DESTINATION (j->data);
+
+ if (dest)
+ destv[i++] = dest;
}
str = e_destination_exportv (destv);
diff --git a/addressbook/gui/merging/e-card-merging.c b/addressbook/gui/merging/e-card-merging.c
index dd8c317990..d18c14f5bf 100644
--- a/addressbook/gui/merging/e-card-merging.c
+++ b/addressbook/gui/merging/e-card-merging.c
@@ -71,7 +71,7 @@ static void
match_query_callback (ECard *card, ECard *match, ECardMatchType type, gpointer closure)
{
ECardMergingLookup *lookup = closure;
- if (type == E_CARD_MATCH_NONE) {
+ if ((gint) type <= (gint) E_CARD_MATCH_VAGUE) {
doit (lookup);
g_free (lookup);
} else {