diff options
Diffstat (limited to 'addressbook/backend')
-rw-r--r-- | addressbook/backend/ebook/e-card-compare.c | 34 | ||||
-rw-r--r-- | addressbook/backend/ebook/e-card.c | 161 | ||||
-rw-r--r-- | addressbook/backend/ebook/e-card.h | 23 | ||||
-rw-r--r-- | addressbook/backend/ebook/e-destination.c | 176 | ||||
-rw-r--r-- | addressbook/backend/ebook/e-destination.h | 13 |
5 files changed, 361 insertions, 46 deletions
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__ */ |