]> git.eshelyaron.com Git - emacs.git/commitdiff
Add new functions for lax mail address splitting
authorLars Ingebrigtsen <larsi@gnus.org>
Sat, 14 Aug 2021 13:20:59 +0000 (15:20 +0200)
committerLars Ingebrigtsen <larsi@gnus.org>
Sat, 14 Aug 2021 13:20:59 +0000 (15:20 +0200)
* lisp/emacs-lisp/subr-x.el (string-clean-whitespace): Autoload.
* lisp/mail/mail-parse.el (mail-header-parse-addresses-lax)
(mail-header-parse-address-lax): New functions.

etc/NEWS
lisp/emacs-lisp/subr-x.el
lisp/mail/mail-extr.el
lisp/mail/mail-parse.el
test/lisp/mail/mail-parse-tests.el [new file with mode: 0644]

index a321ffd81f1e494bfa38f135c2f8724f11c61e8b..a3a25436289acffef2ea0d2ec962fc08f95e1f75 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -2443,6 +2443,15 @@ images are marked.
 
 ** Miscellaneous
 
+---
+*** New function 'mail-header-parse-addresses-lax'.
+This takes a comma-separated string and returns a list of mail/name
+pairs.
+
+---
+*** New function 'mail-header-parse-address-lax'.
+Parse a string as a mail address-like string.
+
 ---
 *** 'shell-script-mode' now supports 'outline-minor-mode'.
 The outline headings have lines that start with "###".
index 468d124c0e292823a3d4bffa92ae29110ce4791d..4204d20249d045c25c84fa03e1f2c18d8a765ec6 100644 (file)
@@ -240,6 +240,7 @@ carriage return."
       (substring string 0 (- (length string) (length suffix)))
     string))
 
+;;;###autoload
 (defun string-clean-whitespace (string)
   "Clean up whitespace in STRING.
 All sequences of whitespaces in STRING are collapsed into a
index 88fb08668567d330da4df804a7d0e41149ed8fcd..24d8311f641c79864bf1a66fa65a941ed1f37035 100644 (file)
@@ -707,7 +707,10 @@ This function is primarily meant for when you're displaying the
 result to the user: Many prettifications are applied to the
 result returned.  If you want to decode an address for further
 non-display use, you should probably use
-`mail-header-parse-address' instead."
+`mail-header-parse-address' instead.  Also see
+`mail-header-parse-address-lax' for a function that's less strict
+than `mail-header-parse-address', but does less post-processing
+to the results."
   (let ((canonicalization-buffer (get-buffer-create " *canonical address*"))
        (extraction-buffer (get-buffer-create " *extract address components*"))
        value-list)
index e72ed828494e266002213827210c268a63178e58..212fadf382337912c42723a61f697229c861671c 100644 (file)
 (defalias 'mail-decode-encoded-address-region 'rfc2047-decode-address-region)
 (defalias 'mail-decode-encoded-address-string 'rfc2047-decode-address-string)
 
+(defun mail-header-parse-addresses-lax (string)
+  "Parse STRING as a comma-separated list of mail addresses.
+The return value is a list with mail/name pairs."
+  (delq nil
+        (mapcar (lambda (elem)
+                  (or (mail-header-parse-address elem)
+                      (mail-header-parse-address-lax elem)))
+                (mail-header-parse-addresses string t))))
+
+(defun mail-header-parse-address-lax (string)
+  "Parse STRING as a mail address.
+Returns a mail/name pair.
+
+This function will first try to parse STRING as a
+standards-compliant address string, and if that fails, try to use
+heuristics to determine the email address and the name in the
+string."
+  (with-temp-buffer
+    (insert (string-clean-whitespace string))
+    ;; Find the bit with the @ and guess that that's the mail.
+    (goto-char (point-max))
+    (when (search-backward "@" nil t)
+      (if (re-search-backward " " nil t)
+          (forward-char 1)
+        (goto-char (point-min)))
+      (let* ((start (point))
+             (mail (buffer-substring
+                    start (or (re-search-forward " " nil t)
+                              (goto-char (point-max))))))
+        (delete-region start (point))
+        ;; We've now removed the email bit, so the rest of the stuff
+        ;; has to be the name.
+        (cons (string-trim mail "[<]+" "[>]+")
+              (let ((name (string-trim (buffer-string)
+                                       "[ \t\n\r(]+" "[ \t\n\r)]+")))
+                (if (length= name 0)
+                    nil
+                  name)))))))
+
 (provide 'mail-parse)
 
 ;;; mail-parse.el ends here
diff --git a/test/lisp/mail/mail-parse-tests.el b/test/lisp/mail/mail-parse-tests.el
new file mode 100644 (file)
index 0000000..70de92d
--- /dev/null
@@ -0,0 +1,54 @@
+;;; mail-parse-tests.el --- tests for mail-parse.el  -*- lexical-binding: t -*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+
+;; 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:
+
+;;; Code:
+
+(require 'ert)
+(require 'mail-parse)
+(require 'subr-x)
+
+(ert-deftest test-mail-header-parse-address-lax ()
+  (should (equal (mail-header-parse-address-lax
+                  "Lars Ingebrigtsen <larsi@gnus.org>")
+                 '("larsi@gnus.org" . "Lars Ingebrigtsen")))
+  (should (equal (mail-header-parse-address-lax
+                  "Lars Ingebrigtsen larsi@gnus.org>")
+                 '("larsi@gnus.org" . "Lars Ingebrigtsen")))
+  (should (equal (mail-header-parse-address-lax
+                  "Lars Ingebrigtsen larsi@gnus.org")
+                 '("larsi@gnus.org" . "Lars Ingebrigtsen")))
+  (should (equal (mail-header-parse-address-lax
+                  "larsi@gnus.org (Lars Ingebrigtsen)")
+                 '("larsi@gnus.org " . "Lars Ingebrigtsen")))
+  (should (equal (mail-header-parse-address-lax "larsi@gnus.org")
+                 '("larsi@gnus.org")))
+  (should (equal (mail-header-parse-address-lax "foo")
+                 nil)))
+
+(ert-deftest test-mail-header-parse-addresses-lax ()
+  (should (equal (mail-header-parse-addresses-lax
+                  "Bob Weiner <rsw@gnu.org>, Mats Lidell <matsl@gnu.org>")
+                 '(("rsw@gnu.org" . "Bob Weiner")
+                   ("matsl@gnu.org" . "Mats Lidell")))))
+
+(provide 'mail-parse-tests)
+
+;;; mail-parse-tests.el ends here