From 7c5dd95cd7aefa8243edac3c67bf1910fc905c4e Mon Sep 17 00:00:00 2001 From: Jon Trowbridge Date: Sat, 30 Jun 2001 05:23:09 +0000 Subject: Make the standard for considering two cards to be match stricter. 2001-06-30 Jon Trowbridge * 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 --- addressbook/backend/ebook/e-card.c | 161 ++++++++++++++++++++++++++++++++++--- 1 file changed, 148 insertions(+), 13 deletions(-) (limited to 'addressbook/backend/ebook/e-card.c') 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 #include #include +#include +#include #include #include @@ -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; @@ -988,6 +1073,31 @@ parse_id(ECard *card, VObject *vobj) assign_string(vobj, &(card->id)); } +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) { @@ -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); -- cgit v1.2.3