Add new functions for lax mail address splitting

* 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.
This commit is contained in:
Lars Ingebrigtsen 2021-08-14 15:20:59 +02:00
parent a8a3fd8f8e
commit e91b574bf8
5 changed files with 107 additions and 1 deletions

View file

@ -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 "###".

View 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

View 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)

View file

@ -71,6 +71,45 @@
(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

View file

@ -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