From 02620af4c2a27d6c34a2c34c739d266b22fed381 Mon Sep 17 00:00:00 2001 From: djcb Date: Wed, 30 Dec 2015 15:33:27 +0200 Subject: [PATCH] mu/mu4e: improve in contacts completion mu: cleanup server side; make sure not to loose 'personal' flag when seeing same contact in non-personal context mu4e: tweak the sorting algorithm a bit to take the personal flag into account --- lib/mu-contacts.c | 13 ++++++++---- mu/mu-cmd-server.c | 23 ++++++++++----------- mu4e/mu4e-utils.el | 50 ++++++++++++++++++++++++++++++---------------- 3 files changed, 53 insertions(+), 33 deletions(-) diff --git a/lib/mu-contacts.c b/lib/mu-contacts.c index 64792732..b0d8e8b9 100644 --- a/lib/mu-contacts.c +++ b/lib/mu-contacts.c @@ -286,14 +286,14 @@ gboolean mu_contacts_add (MuContacts *self, const char *addr, const char *name, gboolean personal, time_t tstamp) { - ContactInfo *cinfo; - const char *group; + ContactInfo *cinfo; + const char *group; g_return_val_if_fail (self, FALSE); g_return_val_if_fail (addr, FALSE); - group = encode_email_address (addr); - + group = encode_email_address (addr); + cinfo = (ContactInfo*) g_hash_table_lookup (self->_hash, group); if (!cinfo) { char *addr_dc; @@ -304,6 +304,11 @@ mu_contacts_add (MuContacts *self, const char *addr, const char *name, tstamp, 1); g_hash_table_insert (self->_hash, g_strdup(group), cinfo); } else { + /* if the contact is ever user in a personal way, it's + * personal */ + if (personal) + cinfo->_personal = TRUE; + if (cinfo->_tstamp < tstamp) { if (!mu_str_is_empty(name)) { /* update the name to the last one used, unless it's diff --git a/mu/mu-cmd-server.c b/mu/mu-cmd-server.c index cb1b00cf..5f0ef898 100644 --- a/mu/mu-cmd-server.c +++ b/mu/mu-cmd-server.c @@ -578,7 +578,7 @@ static void each_contact_sexp (const char *email, const char *name, gboolean personal, time_t tstamp, unsigned freq, SexpData *sdata) { - char *escmail; + char *escmail, *escname; /* (maybe) only include 'personal' contacts */ if (sdata->personal && !personal) @@ -594,19 +594,18 @@ each_contact_sexp (const char *email, const char *name, gboolean personal, return; escmail = mu_str_escape_c_literal (email, TRUE); + escname = name ? mu_str_escape_c_literal (name, TRUE) : NULL; - if (name) { - char *escname; - escname = mu_str_escape_c_literal (name, TRUE); - g_string_append_printf (sdata->gstr, - "(:name %s :mail %s :tstamp %u :freq %u)\n", - escname, escmail, (unsigned)tstamp, freq); - g_free (escname); - } else - g_string_append_printf (sdata->gstr, - "(:mail %s :tstamp %u :freq %u)\n", - escmail, (unsigned)tstamp, freq); + g_string_append_printf ( + sdata->gstr, + "(:mail %s :name %s :tstamp %u :freq %u :personal %s)\n", + escmail, + escname ? escname : "nil", + (unsigned)tstamp, + freq, + sdata->personal ? "t" : "nil"); + g_free (escname); g_free (escmail); } diff --git a/mu4e/mu4e-utils.el b/mu4e/mu4e-utils.el index cc9c0547..633769b9 100644 --- a/mu4e/mu4e-utils.el +++ b/mu4e/mu4e-utils.el @@ -645,24 +645,37 @@ or (rfc822-string . CONTACT) otherwise." (when contact (let ((name (plist-get contact :name)) (mail (plist-get contact :mail))) - (unless (and mail (string-match mu4e-compose-complete-ignore-address-regexp mail)) + (unless (and mail + (string-match mu4e-compose-complete-ignore-address-regexp mail)) (cons (if name (format "%s <%s>" (mu4e~rfc822-quoteit name) mail) mail) contact))))) -(defun mu4e~sort-contacts (contacts) - "Sort the contacts (only for cycling). Sort by last-use when -that is at most 10 days old. Otherwise, sort by frequency." - (let ((recent (- (float-time) (* 10 24 3600)))) - (sort contacts +(defsubst mu4e~sort-contacts (contacts) + "Destructively sort contacts (only for cycling). Sort by +last-use when that is at most 10 days old. Otherwise, sort by +frequency." + (let* ((now (+ (float-time) 3600)) ;; allow for clock diffs + (recent (- (float-time) (* 30 24 3600)))) + (sort* contacts (lambda (c1 c2) - (let* ((freq1 (plist-get c1 :freq)) + (let* ( (c1 (cdr c1)) (c2 (cdr c2)) + (personal1 (plist-get c1 :personal)) + (personal2 (plist-get c2 :personal)) + (freq1 (plist-get c1 :freq)) (freq2 (plist-get c2 :freq)) (tstamp1 (plist-get c1 :tstamp)) (tstamp2 (plist-get c2 :tstamp))) - (if (or (> tstamp1 recent) (> tstamp2 recent)) - (< tstamp1 tstamp2) - (< freq1 freq2))))))) + ;; personal contacts come first + (if (or personal1 personal2) + (if personal1 t nil) + ;; then come recently seen ones; but only if they're not in + ;; the future (as seen in spams) + (if (and (<= tstamp1 now) (<= tstamp2 now) + (or (> tstamp1 recent) (> tstamp2 recent))) + (> tstamp1 tstamp2) + ;; otherwise, use the frequency + (> freq1 freq2)))))))) ;; start and stopping (defun mu4e~fill-contacts (contacts) @@ -672,13 +685,16 @@ and fill the list `mu4e~contacts-for-completion' with it, with each element looking like name This is used by the completion function in mu4e-compose." - (let ((contacts (mu4e~sort-contacts contacts))) - (setq mu4e~contacts-for-completion nil) - (dolist (contact contacts) - (let ((contact (mu4e~process-contact contact))) - (when contact (push contact mu4e~contacts-for-completion)))) - (mu4e-index-message "Contacts received: %d" - (length mu4e~contacts-for-completion)))) + (setq mu4e~contacts-for-completion nil) + (dolist (contact contacts) + (let ((contact (mu4e~process-contact contact))) + ;; note, this gives cells (rfc822-address . contact) + (when contact (push contact mu4e~contacts-for-completion)))) + (setq mu4e~contacts-for-completion + (mapcar 'car ;; strip off the other stuff again + (mu4e~sort-contacts mu4e~contacts-for-completion))) + (mu4e-index-message "Contacts received: %d" + (length mu4e~contacts-for-completion))) (defun mu4e~check-requirements ()