summaryrefslogtreecommitdiff
path: root/lisp
diff options
context:
space:
mode:
authorAlexander Adolf <alexander.adolf@condition-alpha.com>2022-11-08 13:39:19 -0500
committerThomas Fitzsimmons <fitzsim@fitzsim.org>2022-11-08 18:19:15 -0500
commit0e25a39e69acca0324c326ea8e46b1725594bff5 (patch)
tree6340e009978c52bd415ad9ff84888f3334c7d5e3 /lisp
parent1f53a5f1b389a2c4a8225cf37bbf68bebac735d7 (diff)
downloademacs-0e25a39e69acca0324c326ea8e46b1725594bff5.tar.gz
emacs-0e25a39e69acca0324c326ea8e46b1725594bff5.tar.bz2
emacs-0e25a39e69acca0324c326ea8e46b1725594bff5.zip
EUDC: Add ecomplete and mailabbrev backends
* doc/misc/eudc.texi (Overview): Add ecomplete and mailabbrev nodes. (ecomplete, mailabbrev): New nodes. (Installation): Add ecomplete and mailabbrev nodes. (LDAP Configuration): Use code formatting instead of quotes. (macOS Contacts Configuration): Likewise. (ecomplete Configuration): New node. (mailabbrev Configuration): Likewise. * etc/NEWS (EUDC): Mention ecomplete and mailabbrev backends, mention eudc-server-hotlist default change. * lisp/net/eudc-vars.el (eudc-known-protocols): Add ecomplete and mailabbrev. (eudc-server-hotlist): Add entries for ecomplete and mailabbrev. * lisp/net/eudcb-ecomplete.el: New EUDC backend file. * lisp/net/eudcb-mailabbrev.el: Likewise. * test/lisp/net/eudc-resources/ecompleterc, test/lisp/net/eudc-resources/mailrc: New eudc-tests resource files. * test/lisp/net/eudc-tests.el (eudc-test-rfc5322-quote-phrase) (eudc-test-make-address, eudcb-ecomplete, eudcb-mailabbrev): New test cases.
Diffstat (limited to 'lisp')
-rw-r--r--lisp/net/eudc-vars.el5
-rw-r--r--lisp/net/eudcb-ecomplete.el108
-rw-r--r--lisp/net/eudcb-mailabbrev.el127
3 files changed, 238 insertions, 2 deletions
diff --git a/lisp/net/eudc-vars.el b/lisp/net/eudc-vars.el
index 3ce363cf688..b44989d9061 100644
--- a/lisp/net/eudc-vars.el
+++ b/lisp/net/eudc-vars.el
@@ -51,9 +51,10 @@ instead."
;; Known protocols (used in completion)
;; Not to be mistaken with `eudc-supported-protocols'
-(defvar eudc-known-protocols '(bbdb ldap))
+(defvar eudc-known-protocols '(bbdb ldap ecomplete mailabbrev))
-(defcustom eudc-server-hotlist nil
+(defcustom eudc-server-hotlist '(("localhost" . ecomplete)
+ ("localhost" . mailabbrev))
"Directory servers to query.
This is an alist of the form (SERVER . PROTOCOL). SERVER is the
host name or URI of the server, PROTOCOL is a symbol representing
diff --git a/lisp/net/eudcb-ecomplete.el b/lisp/net/eudcb-ecomplete.el
new file mode 100644
index 00000000000..55011d29f6c
--- /dev/null
+++ b/lisp/net/eudcb-ecomplete.el
@@ -0,0 +1,108 @@
+;;; eudcb-ecomplete.el --- EUDC - ecomplete backend -*- lexical-binding: t -*-
+
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+;;
+;; Author: Alexander Adolf
+;;
+;; This file is part of GNU Emacs.
+;;
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;; This library provides an interface to the ecomplete package as
+;; an EUDC data source.
+
+;;; Usage:
+;; No setup is required, since there is an entry for this backend
+;; in `eudc-server-hotlist' by default.
+;;
+;; For example, if your `ecomplete-database-file' (typically
+;; ~/.emacs.d/ecompleterc) contains:
+;;
+;; ((mail ("larsi@gnus.org" 38154 1516109510 "Lars <larsi@ecomplete.org>")))
+;;
+;; Then:
+;;
+;; C-x m lars C-u M-x eudc-expand-try-all RET
+;;
+;; should expand the email address into the To: field of the new
+;; message.
+
+;;; Code:
+
+(require 'eudc)
+(require 'ecomplete)
+(require 'mail-parse)
+
+(defvar eudc-ecomplete-attributes-translation-alist
+ '((email . mail))
+ "See `eudc-protocol-attributes-translation-alist'.
+The back-end-specific attribute names are used as the \"type\" of
+entry when searching, and they must hence match the types you use
+in your ecompleterc database file.")
+
+;; hook ourselves into the EUDC framework
+(eudc-protocol-set 'eudc-query-function
+ 'eudc-ecomplete-query-internal
+ 'ecomplete)
+(eudc-protocol-set 'eudc-list-attributes-function
+ nil
+ 'ecomplete)
+(eudc-protocol-set 'eudc-protocol-attributes-translation-alist
+ 'eudc-ecomplete-attributes-translation-alist
+ 'ecomplete)
+(eudc-protocol-set 'eudc-protocol-has-default-query-attributes
+ nil
+ 'ecomplete)
+
+;;;###autoload
+(defun eudc-ecomplete-query-internal (query &optional _return-attrs)
+ "Query `ecomplete' with QUERY.
+QUERY is a list of cons cells (ATTR . VALUE). Since `ecomplete'
+does not provide attributes in the usual sense, the
+back-end-specific attribute names in
+`eudc-ecomplete-attributes-translation-alist' are used as the
+KEY (that is, the \"type\" of match) when looking for matches in
+`ecomplete-database'.
+
+RETURN-ATTRS is ignored." ; FIXME: why is this being ignored?
+ (ecomplete-setup)
+ (let ((email-attr (car (eudc-translate-attribute-list '(email))))
+ result)
+ (dolist (term query)
+ (let* ((attr (car term))
+ (value (cdr term))
+ (matches (ecomplete-get-matches attr value)))
+ (when matches
+ (dolist (match (split-string (string-trim (substring-no-properties
+ matches))
+ "[\n\r]"))
+ ;; Try to decompose the email address.
+ (let* ((decoded (mail-header-parse-address match t))
+ (name (cdr decoded))
+ (email (car decoded)))
+ (if (and decoded (eq attr email-attr))
+ ;; The email could be decomposed, push individual
+ ;; fields.
+ (push `((,attr . ,email)
+ ,@(when name (list (cons 'name name))))
+ result)
+ ;; Otherwise just forward the value as-is.
+ (push (list (cons attr match)) result)))))))
+ result))
+
+(eudc-register-protocol 'ecomplete)
+
+(provide 'eudcb-ecomplete)
+;;; eudcb-ecomplete.el ends here
diff --git a/lisp/net/eudcb-mailabbrev.el b/lisp/net/eudcb-mailabbrev.el
new file mode 100644
index 00000000000..64b50af09bc
--- /dev/null
+++ b/lisp/net/eudcb-mailabbrev.el
@@ -0,0 +1,127 @@
+;;; eudcb-mailabbrev.el --- EUDC - mailabbrev backend -*- lexical-binding: t -*-
+
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+;;
+;; Author: Alexander Adolf
+;;
+;; This file is part of GNU Emacs.
+;;
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;; This library provides an interface to the mailabbrev package as
+;; an EUDC data source.
+
+;;; Usage:
+;; No setup is required, since there is an entry for this backend
+;; in `eudc-server-hotlist' by default.
+;;
+;; For example, if your `mail-personal-alias-file' (typically
+;; ~/.mailrc) contains:
+;;
+;; alias lars "Lars <larsi@mail-abbrev.com>"
+;;
+;; Then:
+;;
+;; C-x m lars C-u M-x eudc-expand-try-all RET
+;;
+;; will expand the correct email address into the To: field of the
+;; new message.
+
+;;; Code:
+
+(require 'eudc)
+(require 'mailabbrev)
+(require 'mail-parse)
+
+;; hook ourselves into the EUDC framework
+(eudc-protocol-set 'eudc-query-function
+ 'eudc-mailabbrev-query-internal
+ 'mailabbrev)
+(eudc-protocol-set 'eudc-list-attributes-function
+ nil
+ 'mailabbrev)
+(eudc-protocol-set 'eudc-protocol-attributes-translation-alist
+ nil
+ 'mailabbrev)
+(eudc-protocol-set 'eudc-protocol-has-default-query-attributes
+ nil
+ 'mailabbrev)
+;;;###autoload
+(defun eudc-mailabbrev-query-internal (query &optional _return-attrs)
+ "Query `mailabbrev' with QUERY.
+QUERY is a list of cons cells (ATTR . VALUE). Since `mailabbrev'
+does not provide attributes in the usual sense, only the email,
+name, and firstname attributes in the QUERY are considered, and
+their values are matched against the alias names in the mailrc
+file. When a mailrc alias is a distribution list, that is it
+expands to more that one email address, the individual recipient
+specifications are formatted using `eudc-rfc5322-make-address',
+and returned as a comma-separated list in the email address
+attribute.
+
+RETURN-ATTRS is a list of attributes to return, defaulting to
+`eudc-default-return-attributes'."
+ (mail-abbrevs-setup)
+ (let (result)
+ (dolist (term query)
+ (let* ((attr (car term))
+ (value (cdr term))
+ (raw-matches (symbol-value (intern-soft value mail-abbrevs))))
+ (when (and raw-matches
+ (memq attr '(email firstname name)))
+ (let* ((matches (split-string raw-matches ", "))
+ (num-matches (length matches)))
+ (if (> num-matches 1)
+ ;; multiple matches: distribution list
+ (let ((distr-str (string)))
+ (dolist (recipient matches)
+ ;; try to decompose email construct
+ (let* ((decoded (mail-header-parse-address recipient t))
+ (name (cdr decoded))
+ (email (car decoded)))
+ (if decoded
+ ;; decoding worked, push rfc5322 rendered address
+ (setq distr-str
+ (copy-sequence
+ (concat distr-str ", "
+ (eudc-rfc5322-make-address email
+ nil
+ name))))
+ ;; else, just forward the value as-is
+ (setq distr-str
+ (copy-sequence
+ (concat distr-str ", " recipient))))))
+ ;; push result, removing the leading ", "
+ (push (list (cons 'email (substring distr-str 2 -1)))
+ result))
+ ;; simple case: single match
+ (let* ((match (car matches))
+ (decoded (mail-header-parse-address match t))
+ (name (cdr decoded))
+ (email (car decoded)))
+ (if decoded
+ ;; decoding worked, push individual fields
+ (push `((email . ,email)
+ ,@(when name (list (cons 'name name))))
+ result)
+ ;; else, just forward the value as-is
+ (push (list (cons 'email match)) result))))))))
+ result))
+
+(eudc-register-protocol 'mailabbrev)
+
+(provide 'eudcb-mailabbrev)
+
+;;; eudcb-mailabbrev.el ends here