This is an autogenerated patch header for a single-debian-patch file. The
delta against upstream is either kept as a single patch, or maintained
in some VCS, and exported as a single patch instead of more manageable
atomic patches.

--- bbdb3-3.2.orig/ChangeLog
+++ bbdb3-3.2/ChangeLog
@@ -1,3 +1,110 @@
+2021-01-07  Roland Winkler  <winkler@gnu.org>
+	* lisp/bbdb-sc.el: Add third arg to define-obsolete-variable-alias
+	and define-obsolete-function-alias.
+
+2020-09-28  Roland Winkler  <winkler@gnu.org>
+	* lisp/bbdb-sc.el (bbdb-sc-attribution-field): Quieten compiler.
+
+2020-09-28  Stefan Monnier <monnier@iro.umontreal.ca>
+	* lisp/bbdb.el, lisp/bbdb-tex.el, lisp/bbdb-migrate.el: Require
+	cl-lib.
+
+2020-08-29  David Maus <dmause@dmaus.name>
+	Use wl sticky buffer name if necessary.
+	* lisp/bbdb-wl.el (bbdb/wl-header): Use wl sticky buffer name if
+	necessary.
+
+2020-08-29  Stefan Monnier <monnier@iro.umontreal.ca>
+	Use cl-defstruct to define BBDB record type.
+	* lisp/bbdb-com.el: Use cl-defstruct to define BBDB record type.
+	* lisp/bbdb-com.el, lisp/bbdb-com.el, lisp/bbdb-snarf.el:
+	* lisp/bbdb-migrate.el: Use setf to set records.
+
+2020-01-01  Roland Winkler  <winkler@gnu.org>
+	* lisp/bbdb-com.el (bbdb-search): New keywords :invert and
+	:case-fold.  Allow arbitrary functions for keyword :bool.
+
+2020-01-01  Roland Winkler  <winkler@gnu.org>
+	* lisp/bbdb.el (bbdb-mode): Bind buffer-undo-list to t.
+
+2020-01-01  Roland Winkler  <winkler@gnu.org>
+	* lisp/bbdb.el: Declare functions used for insinuation.
+	(bbdb-init-functions): Renamed from bbdb-init-forms.
+
+2019-09-27  Roland Winkler  <winkler@gnu.org>
+	* lisp/bbdb-mua.el (bbdb-mua-auto-update-init): Use
+	wl-summary-redisplay-hook for wanderlust.
+
+2019-06-08  Roland Winkler  <winkler@gnu.org>
+	* bbdb-com.el (bbdb-search-read): When region is active make it
+	the default string to match.
+
+2019-03-09  Stefan Monnier <monnier@iro.umontreal.ca>
+	* bbdb-com.el, bbdb.el: Fix some warnings; plus cosmetic changes
+
+	* bbdb-com.el, bbdb.el: Use #' to quote functions.
+	* bbdb-com.el (bbdb-dial): Clarify backslash escaping in regexp.
+	(bbdb-mail-aliases): η-reduce.
+	(bbdb-mail-aliases): Use abbrev-symbol.
+	(bbdb-dial-number): Use bbdb--dial-default.
+
+	* bbdb.el: Move variable aliases before their target's definition.
+	(bbdb-merge-records-function, bbdb-dial-function):
+	(bbdb-canonicalize-mail-function): Use a non-nil default.
+	(bbdb--dial-default): New function.
+	(bbdb-init-forms): Use functions rather than "forms".
+	(bbdb-initialize): Adjust accordingly.
+
+2018-09-06  Roland Winkler  <winkler@gnu.org>
+	Fix support for Wanderlust.
+	* lisp/bbdb-mua.el (bbdb-mua-mode-alist): Include mime-view-mode.
+	* lisp/bbdb-wl.el (bbdb/wl-header): Use with-current-buffer.
+
+2018-05-02  Roland Winkler  <winkler@gnu.org>
+	* lisp/bbdb-mua.el (bbdb-message-header): Use rmail-get-header.
+	* lisp/bbdb-rmail.el (bbdb/rmail-header): Remove.
+
+2018-03-30  Roland Winkler  <winkler@gnu.org>
+	Unify the handling of new records, new fields and modified fields.
+
+	* bbdb.el (bbdb-check-name): Handle both names and akas.  New
+	optional arg warn.
+	(bbdb-check-mail): New function.
+	(bbdb-register-record): Use bbdb-check-name and bbdb-check-mail.
+	New optional arg warn.
+	(bbdb-change-record): Fix docstring.
+
+	* bbdb.el (bbdb-record-set-field):
+	* bbdb-com.el (bbdb-read-record, bbdb-create-internal):
+	Use bbdb-check-name and bbdb-check-mail.
+
+	* bbdb-com.el (bbdb-record-edit-address): Allow arg address be nil
+	for new addresses.
+	(bbdb-record-edit-phone): Operate only on the phone number that we
+	change.
+	(bbdb-read-record, bbdb-read-field): Use bbdb-record-edit-phone.
+	Always use bbdb-record-set-field.
+
+2018-03-26  Roland Winkler  <winkler@gnu.org>
+	* bbdb.el (bbdb-register-record): Don't be fooled by existing
+	records.
+
+2018-03-17  Vincent Belaïche  <vincentb1@users.sourceforge.net>
+	* lisp/Makefile.am (abs_target): Make absolute path for
+	bbdb-loaddefs.el MSWindows aware.
+
+2018-03-17  Roland Winkler  <winkler@gnu.org>
+	* bbdb.el (bbdb-register-record): New function renamed from
+	bbdb-hash-record.
+	(bbdb-parse-records, bbdb-change-record): Use it.
+
+2018-03-17  Roland Winkler  <winkler@gnu.org>
+	* bbdb-com.el (bbdb-create-internal): Bug fix.  Support old
+	calling sequence with warning.
+
+2018-03-02  Stefan Monnier <monnier@iro.umontreal.ca>
+	* bbdb.el: Add missing "Maintainer:" header
+
 2018-01-06  Roland Winkler  <winkler@gnu.org>
 	* configure.ac: Increase version number to 3.2.
 
@@ -2358,7 +2465,7 @@
 ;; coding: utf-8
 ;; End:
 
-  Copyright (C) 2010-2017 Free Software Foundation, Inc.
+  Copyright (C) 2010-2021 Free Software Foundation, Inc.
 
   This file is part of the Insidious Big Brother Database (aka BBDB),
 
--- bbdb3-3.2.orig/Makefile.am
+++ bbdb3-3.2/Makefile.am
@@ -18,7 +18,11 @@
 # You should have received a copy of the GNU General Public License
 # along with BBDB.  If not, see <http://www.gnu.org/licenses/>.
 
-SUBDIRS = lisp doc tex
+SUBDIRS = lisp tex
+
+if DOCS
+SUBDIRS += doc
+endif
 
 doc_DATA = COPYING ChangeLog AUTHORS NEWS README TODO
 
--- bbdb3-3.2.orig/configure.ac
+++ bbdb3-3.2/configure.ac
@@ -31,6 +31,14 @@ AM_INIT_AUTOMAKE([1.13 -Wall gnu])
 
 AC_PACKAGE_DATE
 
+# Process options
+AC_MSG_CHECKING([enable_docs])
+AC_ARG_ENABLE([docs],
+       [AS_HELP_STRING([--enable-docs],[build and install LaTeX-format documentation (default=yes)])],,
+       [enable_docs=yes])
+AC_MSG_RESULT([$enable_docs])
+AM_CONDITIONAL([DOCS], [test x${enable_docs} = xyes])
+
 # Checks for programs.
 AC_PROG_INSTALL
 
--- bbdb3-3.2.orig/lisp/Makefile.am
+++ bbdb3-3.2/lisp/Makefile.am
@@ -87,9 +87,14 @@ bbdb-loaddefs.el: $(dist_lisp_LISP)
 	@echo "" >> $@;
 #	Generated autoload-file must have an absolute path,
 #	$srcdir can be relative.
+#
+#       The equivalent command line with bash $(...) construct is:
+#       abs_target=$$($(CYGPATH_W) $(abs_builddir)/$@ | sed 's/\\/\\\\/g');
+#       See http://lists.nongnu.org/archive/html/bbdb-user/2018-02/msg00000.html
+	abs_target=`$(CYGPATH_W) $(abs_builddir)/$@ | sed 's/\\\\/\\\\\\\\/g'`; \
 	$(EMACS) --batch $(AM_ELCFLAGS) $(ELCFLAGS) \
 		--load autoload \
-		--eval '(setq generated-autoload-file "'$(abs_builddir)/$@'")' \
+		--eval '(setq generated-autoload-file "'"$$abs_target"'")' \
 		--eval '(setq make-backup-files nil)' \
 		--funcall batch-update-autoloads $(srcdir)
 
--- bbdb3-3.2.orig/lisp/bbdb-com.el
+++ bbdb3-3.2/lisp/bbdb-com.el
@@ -1,6 +1,6 @@
 ;;; bbdb-com.el --- user-level commands of BBDB -*- lexical-binding: t -*-
 
-;; Copyright (C) 2010-2017  Free Software Foundation, Inc.
+;; Copyright (C) 2010-2020  Free Software Foundation, Inc.
 
 ;; This file is part of the Insidious Big Brother Database (aka BBDB),
 
@@ -59,8 +59,8 @@ If RECORDS is a single record turn it in
 If FULL is non-nil, assume that RECORDS include display information."
   (if records
       (if full
-          (if (vectorp (car records)) (list records) records)
-        (if (vectorp records) (list records) records))))
+          (if (bbdb-record-p (car records)) (list records) records)
+        (if (bbdb-record-p records) (list records) records))))
 
 ;; Note about BBDB prefix commands:
 ;; `bbdb-do-all-records', `bbdb-append-display' and `bbdb-search-invert'
@@ -103,7 +103,7 @@ If FULL is non-nil, the list of records
         (setq bbdb-do-all-records nil)
         (aset bbdb-modeline-info 4 nil)
         (aset bbdb-modeline-info 5 nil)
-        (if full bbdb-records (mapcar 'car bbdb-records)))
+        (if full bbdb-records (mapcar #'car bbdb-records)))
     (list (bbdb-current-record full))))
 
 ;;;###autoload
@@ -181,6 +181,8 @@ With prefix ARG a negative number, do no
   (bbdb-prefix-message))
 
 (defmacro bbdb-search (records &rest spec)
+  ;; FIXME: Provide a functional interface so client code can be compiled
+  ;; without having BBDB around!
   "Search RECORDS for fields matching SPEC.
 The following keywords are supported in SPEC to search fields in RECORDS
 matching the regexps RE:
@@ -202,11 +204,16 @@ matching the regexps RE:
 Each of these keywords may appear multiple times.
 Other keywords:
 
-:bool BOOL        Combine the search for multiple fields using BOOL.
-                  BOOL may be either `or' (match either field)
-                  or `and' (match all fields) with default `or'.
+:bool FUN         Combine the search for multiple fields using FUN.
+                  FUN must be a function that takes as many arguments
+                  as there are search keywords in SPEC, for example
+                  `or' (match either field, the default)
+                  or `and' (match all fields).
+:invert VAL       Invert the search if VAL is non-nil.
+                  The default is the return value of `bbdb-search-invert-p'.
+:case-fold VAL    Searches ignore case if VAL is non-nil.
+                  The default is the value of `bbdb-case-fold-search'.
 
-To reverse the search, bind `bbdb-search-invert' to t.
 See also `bbdb-message-search' for fast searches using `bbdb-hashtable'
 but not allowing for regexps.
 
@@ -226,18 +233,20 @@ This usage is discouraged."
       (dolist (key '(:all-names :organization :mail :xfield :phone :address))
         (if (setq val (pop spec))
             (push (list key val) newspec)))
-      (setq spec (apply 'append newspec))))
+      (setq spec (apply #'append newspec))))
 
-  (let* ((count 0)
-         (sym-list (mapcar (lambda (_)
-                             (make-symbol
-                              (format "bbdb-re-%d" (setq count (1+ count)))))
-                           spec))
-         (bool (make-symbol "bool"))
-         (not-invert (make-symbol "not-invert"))
-         (matches (make-symbol "matches"))
-         keyw re-list clauses)
-    (set bool ''or) ; default
+  ;; The following defaults are motivated historically by the use
+  ;; of `bbdb-search' in interactive commands.
+  ;; Non-interactively these defaults may not always be useful.
+  (let ((bool 'or) ; default
+        (case-fold 'bbdb-case-fold-search) ; default
+        (invert '(bbdb-search-invert-p)) ; default
+        (sym-list (let ((count 0))
+                    (mapcar (lambda (_)
+                              (make-symbol
+                               (format "bbdb-re-%d" (setq count (1+ count)))))
+                            spec)))
+        keyw re-list clauses)
 
     ;; Check keys.
     (while (keywordp (setq keyw (car spec)))
@@ -336,7 +345,7 @@ This usage is discouraged."
          (let ((sym (pop sym-list)))
            (push `(,sym ,(pop spec)) re-list)
            (push `(let ((mails (bbdb-record-mail record))
-                        (bbdb-case-fold-search t) ; there is no case for mails
+                        (case-fold-search t) ; there is no case for mails
                         m done)
                     (if mails
                         (while (and (setq m (pop mails)) (not done))
@@ -383,37 +392,51 @@ This usage is discouraged."
                  clauses)))
 
         (`:bool
-         (set bool (pop spec)))
+         (setq bool (pop spec)))
+
+        (`:invert
+         (setq invert (pop spec)))
+
+        (`:case-fold
+         (setq case-fold (pop spec)))
 
         ;; Do we need other keywords?
 
-        (_ (error "Keyword `%s' undefines" keyw))))
+        (_ (error "Keyword `%s' undefined" keyw))))
 
-    `(let ((case-fold-search bbdb-case-fold-search)
-           (,not-invert (not (bbdb-search-invert-p)))
-           ,@re-list ,matches)
-       ;; Are there any use cases for `bbdb-search' where BOOL is only
-       ;; known at run time?  A smart byte compiler will hopefully
-       ;; simplify the code below if we know BOOL already at compile time.
-       ;; Alternatively, BOOL could also be a user function that
-       ;; defines more complicated boolian expressions.  Yet then we loose
-       ;; the efficiency of `and' and `or' that evaluate its arguments
-       ;; as needed.  We would need instead boolian macros that the compiler
-       ;; can analyze at compile time.
-       (if (eq 'and ,(symbol-value bool))
-           (dolist (record ,records)
-             (unless (eq ,not-invert (not (and ,@clauses)))
-                 (push record ,matches)))
+    ;; The clauses have the same order as the keywords.
+    (setq clauses (nreverse clauses))
+
+    ;; Silly me!  For the keyword :bool, we used to use double-quoted
+    ;; arguments like ":bool 'or".  Strip off one quote to preserve
+    ;; backward compatibility.
+    (if (eq 'quote (car-safe bool))
+        (setq bool (cadr bool)))
+
+    (let ((not-invert (make-symbol "not-invert"))
+          (matches (make-symbol "matches")))
+      `(let ((case-fold-search ,case-fold)
+             (,not-invert (not ,invert))
+             ,@re-list ,matches)
          (dolist (record ,records)
-           (unless (eq ,not-invert (not (or ,@clauses)))
-               (push record ,matches))))
-       (nreverse ,matches))))
+           (unless (eq ,not-invert (not (,bool ,@clauses)))
+             (push record ,matches)))
+         (nreverse ,matches)))))
 
 (defun bbdb-search-read (&optional field)
-  "Read regexp to search FIELD values of records."
-  (read-string (format "Search records%s %smatching regexp: "
-                       (if field (concat " with " field) "")
-                       (if bbdb-search-invert "not " ""))))
+  "Read regexp to search FIELD values of records.
+When region is active make it the default string to match."
+  (let ((default (if (and (region-active-p)
+                          (< (region-beginning) (region-end)))
+                     (regexp-quote
+                      (buffer-substring-no-properties
+                       (region-beginning) (region-end))))))
+    (prog1 (read-string (format "Search records%s %smatching regexp: %s"
+                                (if field (concat " with " field) "")
+                                (if bbdb-search-invert "not " "")
+                                (if default (format "(default %s) " default) ""))
+                        nil nil default)
+      (if default (deactivate-mark)))))
 
 ;;;###autoload
 (defun bbdb (regexp &optional layout)
@@ -423,7 +446,7 @@ in either the name(s), organization, add
   (let ((records (bbdb-search (bbdb-records) :all-names regexp
                               :organization regexp :mail regexp
                               :xfield (cons '* regexp)
-                              :phone regexp :address regexp :bool 'or)))
+                              :phone regexp :address regexp :bool or)))
     (if records
         (bbdb-display-records records layout nil t)
       (message "No records matching '%s'" regexp))))
@@ -467,7 +490,7 @@ in either the name(s), organization, add
   "Display all BBDB records for which xfield FIELD matches REGEXP."
   (interactive
    (let ((field (completing-read "Xfield to search (RET for all): "
-                                 (mapcar 'list bbdb-xfield-label-list) nil t)))
+                                 (mapcar #'list bbdb-xfield-label-list) nil t)))
      (list (if (string= field "") '* (intern field))
            (bbdb-search-read (if (string= field "")
                                    "any xfield"
@@ -475,7 +498,7 @@ in either the name(s), organization, add
            (bbdb-layout-prefix))))
   (bbdb-display-records (bbdb-search (bbdb-records) :xfield (cons field regexp))
                         layout))
-(define-obsolete-function-alias 'bbdb-search-notes 'bbdb-search-xfields "3.0")
+(define-obsolete-function-alias 'bbdb-search-notes #'bbdb-search-xfields "3.0")
 
 ;;;###autoload
 (defun bbdb-search-changed (&optional layout)
@@ -543,11 +566,11 @@ which is probably more suited for your n
         (if (assoc-string mail mails t) ; duplicate mail address
             (push mail redundant)
           (push mail mails)))
-      (let ((mail-re (delq nil (mapcar 'bbdb-mail-redundant-re mails)))
+      (let ((mail-re (delq nil (mapcar #'bbdb-mail-redundant-re mails)))
             (case-fold-search t))
         (if (not (cdr mail-re)) ; at most one mail-re address to consider
             (setq okay (nreverse mails))
-          (setq mail-re (concat "\\`\\(?:" (mapconcat 'identity mail-re "\\|")
+          (setq mail-re (concat "\\`\\(?:" (mapconcat #'identity mail-re "\\|")
                                 "\\)\\'"))
           (dolist (mail mails)
             (if (string-match mail-re mail) ; redundant mail address
@@ -564,13 +587,15 @@ which is probably more suited for your n
           (when update
             (bbdb-change-record record)))))))
 (define-obsolete-function-alias 'bbdb-delete-duplicate-mails
-  'bbdb-delete-redundant-mails "3.0")
+  #'bbdb-delete-redundant-mails "3.0")
 
 (defun bbdb-search-duplicates (&optional fields)
   "Search all records that have duplicate entries for FIELDS.
 The list FIELDS may contain the symbols `name', `mail', and `aka'.
 If FIELDS is nil use all these fields.  With prefix, query for FIELDS.
-The search results are displayed in the BBDB buffer."
+The search results are displayed in the BBDB buffer.
+The command `bbdb-merge-records' may come handy for merging duplicate
+records."
   (interactive (list (if current-prefix-arg
                          (list (intern (completing-read "Field: "
                                                         '("name" "mail" "aka")
@@ -738,7 +763,7 @@ Return a list containing four numbers or
   ;; Is this always correct?  What about an extension zero?
   ;; Should we use nil instead of zeros?
   (unless style (setq style bbdb-phone-style))
-  (let ((area-regexp (concat "(?[ \t]*\\+?1?[ \t]*[-\(]?[ \t]*[-\(]?[ \t]*"
+  (let ((area-regexp (concat "(?[ \t]*\\+?1?[ \t]*[-(]?[ \t]*[-(]?[ \t]*"
                              "\\([2-9][0-9][0-9]\\)[ \t]*)?[-./ \t]*"))
         (main-regexp (concat "\\([1-9][0-9][0-9]\\)[ \t]*[-.]?[ \t]*"
                              "\\([0-9][0-9][0-9][0-9]\\)[ \t]*"))
@@ -803,51 +828,46 @@ but does ensure that there will not be n
     (let (name)
       (bbdb-error-retry
        (setq name (bbdb-read-name first-and-last))
-       (bbdb-check-name (car name) (cdr name)))
-      (bbdb-record-set-firstname record (car name))
-      (bbdb-record-set-lastname record (cdr name)))
+       (bbdb-check-name name))
+      (setf (bbdb-record-firstname record) (car name))
+      (setf (bbdb-record-lastname record) (cdr name)))
 
     ;; organization
-    (bbdb-record-set-organization record (bbdb-read-organization))
+    (setf (bbdb-record-organization record) (bbdb-read-organization))
 
     ;; mail
-    (bbdb-record-set-mail
-     record (bbdb-split 'mail (bbdb-read-string "E-Mail Addresses: ")))
+    (let (mail)
+      (bbdb-error-retry
+       (setq mail (bbdb-split 'mail (bbdb-read-string "E-Mail Addresses: ")))
+       (bbdb-check-mail mail))
+      (setf (bbdb-record-mail record) mail))
+
     ;; address
-    (let (addresses label address)
+    (let (addresses label)
       (while (not (string= ""
                            (setq label
                                  (bbdb-read-string
                                   "Snail Mail Address Label [RET when done]: "
-                                  nil
-                                  bbdb-address-label-list))))
-        (setq address (make-vector bbdb-address-length nil))
-        (bbdb-record-edit-address address label t)
-        (push address addresses))
-      (bbdb-record-set-address record (nreverse addresses)))
+                                  nil bbdb-address-label-list))))
+        ;; Here we could also already update the completion lists.  Bother?
+        (push (bbdb-record-edit-address nil label) addresses))
+      (setf (bbdb-record-address record) (nreverse addresses)))
 
     ;; phones
-    (let (phones phone-list label)
+    (let (phones label)
       (while (not (string= ""
                            (setq label
                                  (bbdb-read-string
-                                  "Phone Label [RET when done]: " nil
-                                  bbdb-phone-label-list))))
-        (setq phone-list
-              (bbdb-error-retry
-               (bbdb-parse-phone
-                (read-string "Phone: "
-                             (and (integerp bbdb-default-area-code)
-                                  (format "(%03d) "
-                                          bbdb-default-area-code))))))
-        (push (apply 'vector label phone-list) phones))
-      (bbdb-record-set-phone record (nreverse phones)))
+                                  "Phone Label [RET when done]: "
+                                  nil bbdb-phone-label-list))))
+        (push (bbdb-record-edit-phone nil label) phones))
+      (setf (bbdb-record-phone record) (nreverse phones)))
 
     ;; `bbdb-default-xfield'
     (let ((xfield (bbdb-read-xfield bbdb-default-xfield)))
       (unless (string= "" xfield)
-        (bbdb-record-set-xfields
-         record (list (cons bbdb-default-xfield xfield)))))
+        (setf (bbdb-record-xfields record)
+              (list (cons bbdb-default-xfield xfield)))))
 
     record))
 
@@ -912,13 +932,15 @@ The following keywords are supported in
                    and `bbdb-allow-duplicates' is nil.
 :affix VAL         List of strings.
 :aka VAL           List of strings.
+                   An error is thrown if an aka in VAL is already in use
+                   and `bbdb-allow-duplicates' is nil.
 :organization VAL  List of strings.
 :mail VAL          String with comma-separated mail address
                    or a list of strings.
-                   An error is thrown if a mail address in MAIL is already
+                   An error is thrown if a mail address in VAL is already
                    in use and `bbdb-allow-duplicates' is nil.
 :phone VAL         List of phone-number objects.  A phone-number is a vector
-                   [\"label\" areacode prefix suffix extension-or-nil]
+                   [\"label\" area-code prefix suffix extension-or-nil]
                    or [\"label\" \"phone-number\"]
 :address VAL       List of addresses.  An address is a vector of the form
                    \[\"label\" (\"line1\" \"line2\" ... ) \"City\"
@@ -929,8 +951,25 @@ The following keywords are supported in
 :check             If present, throw an error if a field value is not
                    syntactically correct."
   (bbdb-editable)
+
+  (when (not (keywordp (car spec)))
+    ;; Old format for backward compatibility (BBDB version < 3.2)
+    (unless (get 'bbdb-create-internal 'bbdb-outdated)
+      (put 'bbdb-create-internal 'bbdb-outdated t)
+      (message "Outdated usage of `bbdb-create-internal'")
+      (sit-for 2))
+    (let (newspec val)
+      (dolist (key '(:name :affix :aka :organization :mail :phone :address
+                           :xfields))
+        (if (setq val (pop spec))
+            (push (list key val) newspec)))
+      (if (setq val (pop spec))
+          (push (list :check) newspec))
+      (setq spec (apply #'append newspec))))
+
   (let ((record (bbdb-empty-record))
-        (record-type (cdr bbdb-record-type))
+        ;; FIXME: Use something like `bbdb-record--make' i.s.o `vector'.
+        (record-type (apply #'vector (cdr bbdb-record-type)))
         (check (prog1 (memq :check spec)
                  (setq spec (delq :check spec))))
         keyw)
@@ -946,62 +985,58 @@ The following keywords are supported in
                  (check (bbdb-check-type name '(or (const nil)
                                                    (cons string string))
                                          t)))
-           (let ((firstname (car name))
-                 (lastname (cdr name)))
-             (bbdb-check-name firstname lastname) ; check for duplicates
-             (bbdb-record-set-firstname record firstname)
-             (bbdb-record-set-lastname record lastname))))
+           (bbdb-check-name name) ; check for duplicates
+           (setf (bbdb-record-firstname record) (car name))
+           (setf (bbdb-record-lastname record) (cdr name))))
 
         (`:affix
          (let ((affix (bbdb-split-maybe 'affix (pop spec))))
            (if check (bbdb-check-type affix (bbdb-record-affix record-type) t))
-           (bbdb-record-set-affix record affix)))
+           (setf (bbdb-record-affix record) affix)))
 
         (`:organization
          (let ((organization (bbdb-split-maybe 'organization (pop spec))))
            (if check (bbdb-check-type
                       organization (bbdb-record-organization record-type) t))
-           (bbdb-record-set-organization record organization)))
+           (setf (bbdb-record-organization record) organization)))
 
         (`:aka
          (let ((aka (bbdb-split-maybe 'aka (pop spec))))
            (if check (bbdb-check-type aka (bbdb-record-aka record-type) t))
-           (bbdb-record-set-aka record aka)))
+           (bbdb-check-name aka)
+           (setf (bbdb-record-aka record) aka)))
 
         (`:mail
          (let ((mail (bbdb-split-maybe 'mail (pop spec))))
            (if check (bbdb-check-type mail (bbdb-record-mail record-type) t))
-           (unless bbdb-allow-duplicates
-             (dolist (elt mail)
-               (if (bbdb-gethash elt '(mail))
-                   (error "%s is already in the database" elt))))
-           (bbdb-record-set-mail record mail)))
+           (bbdb-check-mail mail)
+           (setf (bbdb-record-mail record) mail)))
 
         (`:phone
          (let ((phone (pop spec)))
            (if check (bbdb-check-type phone (bbdb-record-phone record-type) t))
-           (bbdb-record-set-phone phone record)))
+           (setf (bbdb-record-phone record) phone)))
 
         (`:address
          (let ((address (pop spec)))
            (if check (bbdb-check-type address (bbdb-record-address record-type) t))
-           (bbdb-record-set-address record address)))
+           (setf (bbdb-record-address record) address)))
 
         (`:xfields
          (let ((xfields (pop spec)))
            (if check (bbdb-check-type xfields (bbdb-record-xfields record-type) t))
-           (bbdb-record-set-xfields record xfields)))
+           (setf (bbdb-record-xfields record) xfields)))
 
         (`:uuid
          (let ((uuid (pop spec)))
            (if check (bbdb-check-type uuid (bbdb-record-uuid record-type) t))
-           (bbdb-record-set-uuid record uuid)))
+           (setf (bbdb-record-uuid record) uuid)))
 
         (`:creation-date
          (let ((creation-date (pop spec)))
            (if check (bbdb-check-type
                       creation-date (bbdb-record-creation-date record-type) t))
-           (bbdb-record-set-creation-date record creation-date)))
+           (setf (bbdb-record-creation-date record) creation-date)))
 
         (_ (error "Keyword `%s' undefined" keyw))))
 
@@ -1020,14 +1055,14 @@ A non-nil prefix arg is passed on to `bb
                         '(affix organization aka phone address mail)))
           (field "")
           (completion-ignore-case t)
-          (present (mapcar 'car (bbdb-record-xfields record))))
+          (present (mapcar #'car (bbdb-record-xfields record))))
      (if (bbdb-record-affix record) (push 'affix present))
      (if (bbdb-record-organization record) (push 'organization present))
      (if (bbdb-record-mail record) (push 'mail present))
      (if (bbdb-record-aka record) (push 'aka present))
      (dolist (field present)
        (setq list (remq field list)))
-     (setq list (mapcar 'symbol-name list))
+     (setq list (mapcar #'symbol-name list))
      (while (string= field "")
        (setq field (downcase (completing-read "Insert Field: " list))))
      (setq field (intern field))
@@ -1112,19 +1147,10 @@ A non-nil prefix arg is passed on to `bb
            (let ((bbdb-phone-style
                   (if flag (if (eq bbdb-phone-style 'nanp) nil 'nanp)
                     bbdb-phone-style)))
-             (apply 'vector
-                    (bbdb-read-string "Label: " nil bbdb-phone-label-list)
-                    (bbdb-error-retry
-                     (bbdb-parse-phone
-                      (read-string "Phone: "
-                                   (and (integerp bbdb-default-area-code)
-                                        (format "(%03d) "
-                                                bbdb-default-area-code))))))))
+             (bbdb-record-edit-phone)))
           ;; Address
           ((eq field 'address)
-           (let ((address (make-vector bbdb-address-length nil)))
-             (bbdb-record-edit-address address nil t)
-             address))
+           (bbdb-record-edit-address))
           ;; xfield
           ((or (memq field bbdb-xfield-label-list)
                ;; New xfield
@@ -1181,10 +1207,17 @@ a phone number or address with VALUE bei
 
           ((eq field 'phone)
            (unless value (error "No phone specified"))
-           (bbdb-record-edit-phone (bbdb-record-phone record) value))
+           (bbdb-record-set-field
+            record field
+            ;; Splice new phone value into list of phones.
+            (let ((phones (bbdb-record-phone record)))
+              (setcar (memq value phones)
+                      (bbdb-record-edit-phone value))
+              phones)))
           ((eq field 'address)
            (unless value (error "No address specified"))
-           (bbdb-record-edit-address value nil flag))
+           (bbdb-record-edit-address value nil flag)
+           (bbdb-record-set-field record field (bbdb-record-address record)))
           ((eq field 'organization)
            (bbdb-record-set-field
             record field
@@ -1202,8 +1235,9 @@ a phone number or address with VALUE bei
            (bbdb-record-set-field
             record 'uuid (bbdb-read-string "uuid (edit at your own risk): " (bbdb-record-uuid record))))
           ((eq field 'creation-date)
-           (bbdb-record-set-creation-date
-            record (bbdb-read-string "creation-date: " (bbdb-record-creation-date record))))
+           (bbdb-record-set-field
+            record 'creation-date
+            (bbdb-read-string "creation-date: " (bbdb-record-creation-date record))))
           ;; The timestamp is set automatically whenever we save a modified record.
           ;; So any editing gets overwritten.
           ((eq field 'timestamp)) ; do nothing
@@ -1234,17 +1268,18 @@ to select the field."
           (field (if (memq tmp '(current-fields all-fields))
                      ;; Do not require match so that we can define new xfields.
                      (intern (completing-read
-                              "Edit field: " (mapcar 'list (if (eq tmp 'all-fields)
-                                                               (append '(name affix organization aka mail phone address uuid creation-date)
-                                                                       bbdb-xfield-label-list)
-                                                             (append (if (bbdb-record-affix record) '(affix))
-                                                                     (if (bbdb-record-organization record) '(organization))
-                                                                     (if (bbdb-record-aka record) '(aka))
-                                                                     (if (bbdb-record-mail record) '(mail))
-                                                                     (if (bbdb-record-phone record) '(phone))
-                                                                     (if (bbdb-record-address record) '(address))
-                                                                     (mapcar 'car (bbdb-record-xfields record))
-                                                                     '(name uuid creation-date))))))
+                              "Edit field: "
+                              (mapcar #'list (if (eq tmp 'all-fields)
+                                                 (append '(name affix organization aka mail phone address uuid creation-date)
+                                                         bbdb-xfield-label-list)
+                                               (append (if (bbdb-record-affix record) '(affix))
+                                                       (if (bbdb-record-organization record) '(organization))
+                                                       (if (bbdb-record-aka record) '(aka))
+                                                       (if (bbdb-record-mail record) '(mail))
+                                                       (if (bbdb-record-phone record) '(phone))
+                                                       (if (bbdb-record-address record) '(address))
+                                                       (mapcar #'car (bbdb-record-xfields record))
+                                                       '(name uuid creation-date))))))
                    tmp))
           ;; Multiple phone and address fields may use the same label.
           ;; So we cannot use these labels to uniquely identify
@@ -1322,12 +1357,15 @@ This calls bbdb-read-xfield-FIELD if it
                                   nil nil init))
     (bbdb-split 'organization (bbdb-read-string "Organizations: " init))))
 
-(defun bbdb-record-edit-address (address &optional label ignore-country)
-  "Edit ADDRESS.
+;; The name `bbdb-read-address' might fit better.
+(defun bbdb-record-edit-address (&optional address label ignore-country)
+  "Edit and return ADDRESS.
 If LABEL is nil, edit the label sub-field of the address as well.
 If the country field of ADDRESS is nonempty and IGNORE-COUNTRY is nil,
 use the rule from `bbdb-address-format-list' matching this country.
 Otherwise, use the default rule according to `bbdb-address-format-list'."
+  (unless address
+    (setq address (bbdb-address--make)))
   (unless label
     (setq label (bbdb-read-string "Label: "
                                   (bbdb-address-label address)
@@ -1375,19 +1413,21 @@ Otherwise, use the default rule accordin
                       "Country: " (or (bbdb-address-country address)
                                       bbdb-default-country)
                       bbdb-country-list))))))
-    (bbdb-address-set-label address label)
-    (bbdb-address-set-streets address (elt new-addr 0))
-    (bbdb-address-set-city address (elt new-addr 1))
-    (bbdb-address-set-state address (elt new-addr 2))
-    (bbdb-address-set-postcode address (elt new-addr 3))
-    (if (string= "" (bbdb-concat "" (elt new-addr 0) (elt new-addr 1)
-                                 (elt new-addr 2) (elt new-addr 3)
-                                 (elt new-addr 4)))
-        ;; User did not enter anything. this causes a display bug.
-        ;; The following is a temporary fix.  Ideally, we would simply discard
-        ;; the entire address, but that requires bigger hacking.
-        (bbdb-address-set-country address "Emacs")
-      (bbdb-address-set-country address (elt new-addr 4)))))
+    (setf (bbdb-address-label address) label)
+    (setf (bbdb-address-streets address) (elt new-addr 0))
+    (setf (bbdb-address-city address) (elt new-addr 1))
+    (setf (bbdb-address-state address) (elt new-addr 2))
+    (setf (bbdb-address-postcode address) (elt new-addr 3))
+    (setf (bbdb-address-country address)
+          (if (string= "" (bbdb-concat "" (elt new-addr 0) (elt new-addr 1)
+                                       (elt new-addr 2) (elt new-addr 3)
+                                       (elt new-addr 4)))
+              ;; User did not enter anything. this causes a display bug.
+              ;; The following is a temporary fix.  Ideally, we would simply discard
+              ;; the entire address, but that requires bigger hacking.
+              "Emacs"
+            (elt new-addr 4)))
+    address))
 
 (defun bbdb-edit-address-street (streets)
   "Edit list STREETS."
@@ -1400,10 +1440,13 @@ Otherwise, use the default rule accordin
       (setq n (1+ n)))
     (reverse list)))
 
-;; This function can provide some guidance for writing
-;; your own address editing function
+;; This function can provide some guidance for writing your own
+;; address editing function for `bbdb-address-format-list'.
+;; Such a function should return a list or vector with five elements,
+;; a list of streets, city, state, postcode, country.
+;; These elements should be strings or nil.
 (defun bbdb-edit-address-default (address)
-  "Function to use for address editing.
+  "Function for editing ADDRESS to be used by `bbdb-address-format-list'.
 The sub-fields and the prompts used are:
 Street, line n:  (nth n street)
 City:            city
@@ -1422,21 +1465,26 @@ Country:         country"
                                           bbdb-default-country)
                           bbdb-country-list)))
 
-(defun bbdb-record-edit-phone (phones phone)
-  "For list PHONES edit PHONE number."
+;; The name `bbdb-read-phone' might fit better.
+(defun bbdb-record-edit-phone (&optional phone label)
+  "Edit and return PHONE.
+If LABEL is nil, edit the label sub-field of PHONE as well."
   ;; Phone numbers are special.  They are vectors with either
   ;; two or four elements.  We do not know whether after editing PHONE
   ;; we still have a number requiring the same format as PHONE.
-  ;; So we take all numbers PHONES of the record so that we can
-  ;; replace the element PHONE in PHONES.
-  (setcar (memq phone phones)
-          (apply 'vector
-                 (bbdb-read-string "Label: "
-                                   (bbdb-phone-label phone)
-                                   bbdb-phone-label-list)
-                 (bbdb-error-retry
-                  (bbdb-parse-phone
-                   (read-string "Phone: " (bbdb-phone-string phone)))))))
+  ;; So we throw away the argument PHONE and return a new vector.
+  (apply #'bbdb-phone--make
+         (or label
+             (bbdb-read-string "Label: "
+                               (and phone (bbdb-phone-label phone))
+                               bbdb-phone-label-list))
+         (bbdb-error-retry
+          (bbdb-parse-phone
+           (read-string "Phone: "
+                        (or (and phone (bbdb-phone-string phone))
+                            (and (integerp bbdb-default-area-code)
+                                 (format "(%03d) "
+                                         bbdb-default-area-code))))))))
 
 ;; (bbdb-list-transpose '(a b c d) 1 3)
 (defun bbdb-list-transpose (list i j)
@@ -1480,7 +1528,7 @@ If any of these terms is not defined at
              ;; can be anything.  (xfields are unique within a record.)
              (if (eq 'xfields (car field))
                  (setq val (car val)
-                       fields (mapcar 'car fields)))
+                       fields (mapcar #'car fields)))
              (while (and (not done) (setq elt (pop fields)))
                (if (eq val elt)
                    (setq done t)
@@ -1813,9 +1861,11 @@ in `bbdb-change-hook')."
   (interactive (list (bbdb-do-records) t))
   (bbdb-editable)
   (dolist (record (bbdb-record-list records))
-    (bbdb-record-set-address
-     record (sort (bbdb-record-address record)
-                  (lambda (xx yy) (string< (aref xx 0) (aref yy 0)))))
+    (setf (bbdb-record-address record)
+          (sort (bbdb-record-address record)
+                ;; FIXME: Should these `aref's be replaced by
+                ;; `bbdb-address-label'?
+                (lambda (xx yy) (string< (aref xx 0) (aref yy 0)))))
     (if update
         (bbdb-change-record record))))
 
@@ -1830,9 +1880,11 @@ in `bbdb-change-hook')."
   (interactive (list (bbdb-do-records) t))
   (bbdb-editable)
   (dolist (record (bbdb-record-list records))
-    (bbdb-record-set-phone
-     record (sort (bbdb-record-phone record)
-                  (lambda (xx yy) (string< (aref xx 0) (aref yy 0)))))
+    (setf (bbdb-record-phone record)
+          (sort (bbdb-record-phone record)
+                ;; FIXME: Should these `aref's be replaced by
+                ;; `bbdb-phone-label'?
+                (lambda (xx yy) (string< (aref xx 0) (aref yy 0)))))
     (if update
         (bbdb-change-record record))))
 
@@ -1847,14 +1899,14 @@ in `bbdb-change-hook')."
   (interactive (list (bbdb-do-records) t))
   (bbdb-editable)
   (dolist (record (bbdb-record-list records))
-    (bbdb-record-set-xfields
-     record (sort (bbdb-record-xfields record)
-                  (lambda (a b)
-                    (< (or (cdr (assq (car a) bbdb-xfields-sort-order)) 100)
-                       (or (cdr (assq (car b) bbdb-xfields-sort-order)) 100)))))
+    (setf (bbdb-record-xfields record)
+          (sort (bbdb-record-xfields record)
+                (lambda (a b)
+                  (< (or (cdr (assq (car a) bbdb-xfields-sort-order)) 100)
+                     (or (cdr (assq (car b) bbdb-xfields-sort-order)) 100)))))
     (if update
         (bbdb-change-record record))))
-(define-obsolete-function-alias 'bbdb-sort-notes 'bbdb-sort-xfields "3.0")
+(define-obsolete-function-alias 'bbdb-sort-notes #'bbdb-sort-xfields "3.0")
 
 ;;; Send-Mail interface
 
@@ -1935,7 +1987,7 @@ If MAIL is nil use the first mail addres
 Use `bbdb-mail-user-agent' or (if nil) use `mail-user-agent'.
 ARGS are passed to `compose-mail'."
   (let ((mail-user-agent (or bbdb-mail-user-agent mail-user-agent)))
-    (apply 'compose-mail args)))
+    (apply #'compose-mail args)))
 
 ;;;###autoload
 (defun bbdb-mail (records &optional subject n verbose)
@@ -1991,7 +2043,7 @@ to kill ring.  If VERBOSE is non-nil (as
                                                        (car mails)))))))))
       (when (and bad verbose)
         (message "No mail addresses for %s."
-                 (mapconcat 'bbdb-record-name (nreverse bad) ", "))
+                 (mapconcat #'bbdb-record-name (nreverse bad) ", "))
         (unless (string= "" good) (sit-for 2)))
       (when (and kill-ring-save (not (string= good "")))
         (kill-new good)
@@ -2040,7 +2092,7 @@ The primary mail of each of the records
       (insert (car addresses))
       (when (cdr addresses) (insert ",\n") (indent-relative))
       (setq addresses (cdr addresses)))))
-(define-obsolete-function-alias 'bbdb-yank-addresses 'bbdb-mail-yank "3.0")
+(define-obsolete-function-alias 'bbdb-yank-addresses #'bbdb-mail-yank "3.0")
 
 ;;; completion
 
@@ -2064,7 +2116,7 @@ Completion is done according to `bbdb-co
 just hits return, nil is returned.  Otherwise, a valid response is forced."
   (let* ((completion-ignore-case t)
          (string (completing-read prompt bbdb-hashtable
-                                  'bbdb-completion-predicate t)))
+                                  #'bbdb-completion-predicate t)))
     (unless (string= "" string)
       (let (records)
         (dolist (record (gethash string bbdb-hashtable))
@@ -2086,7 +2138,7 @@ completion with."
            (let* ((count (length records))
                   (result (completing-read
                            (format "Which record (1-%s): " count)
-                           (mapcar 'number-to-string (number-sequence 1 count))
+                           (mapcar #'number-to-string (number-sequence 1 count))
                            nil t)))
              (nth (1- (string-to-number result)) records))))))
 
@@ -2180,7 +2232,7 @@ as part of the MUA insinuation."
          (completion-ignore-case t)
          (completion (and orig
                           (try-completion orig bbdb-hashtable
-                                          'bbdb-completion-predicate)))
+                                          #'bbdb-completion-predicate)))
          all-completions dwim-completions one-record)
 
     (unless done
@@ -2199,13 +2251,13 @@ as part of the MUA insinuation."
           (setq completion (substring completion 0 (match-beginning 0))))
 
       (setq all-completions (all-completions orig bbdb-hashtable
-                                             'bbdb-completion-predicate))
+                                             #'bbdb-completion-predicate))
       ;; Resolve the records matching ORIG:
       ;; Multiple completions may match the same record
       (let ((records (delete-dups
-                      (apply 'append (mapcar (lambda (compl)
-                                               (gethash compl bbdb-hashtable))
-                                             all-completions)))))
+                      (apply #'append (mapcar (lambda (compl)
+                                                (gethash compl bbdb-hashtable))
+                                              all-completions)))))
         ;; Is there only one matching record?
         (setq one-record (and (not (cdr records))
                               (car records))))
@@ -2397,6 +2449,7 @@ as part of the MUA insinuation."
             ;; `completion-list-insert-choice-function'
             ;; before performing our own stuff.
             (completion-list-insert-choice-function
+             ;; FIXME: Use closure instead of backquoted lambda!
              `(lambda (beg end text)
                 ,(if (boundp 'completion-list-insert-choice-function)
                      `(funcall ',completion-list-insert-choice-function
@@ -2413,7 +2466,7 @@ as part of the MUA insinuation."
       done)))
 
 ;;;###autoload
-(define-obsolete-function-alias 'bbdb-complete-name 'bbdb-complete-mail "3.0")
+(define-obsolete-function-alias 'bbdb-complete-name #'bbdb-complete-mail "3.0")
 
 (defun bbdb-complete-mail-cleanup (mail beg)
   "Clean up after inserting MAIL at position BEG.
@@ -2437,6 +2490,8 @@ If we are past `fill-column', wrap at th
               ;; FIXME: This pops up *BBDB* before removing *Completions*
               (bbdb-display-records records nil t)))
         ;; `bbdb-complete-mail-hook' may access MAIL, ADDRESS, and RECORDS.
+        ;; FIXME: Now that we use lexical-binding, these vars can't be accessed
+        ;; any more.  Maybe we should just change the doc!?
         (run-hooks 'bbdb-complete-mail-hook))))
 
 ;;; interface to mail-abbrevs.el.
@@ -2496,7 +2551,7 @@ Rebuilding the aliases is enforced if pr
                 (if (cddr result)
                     ;; for group aliases we just take all the primary mails
                     ;; and define only one expansion!
-                    (list (mapconcat (lambda (record) (bbdb-dwim-mail record))
+                    (list (mapconcat #'bbdb-dwim-mail
                                      (cdr result) mail-alias-separator-string))
                   ;; this is an alias for a single person so deal with it
                   ;; according to `bbdb-mail-alias'
@@ -2536,13 +2591,15 @@ Rebuilding the aliases is enforced if pr
             (bbdb-pushnew (cons alias expansion) mail-aliases)
 
             (define-mail-abbrev alias expansion)
-            (unless (setq f-alias (intern-soft (downcase alias) mail-abbrevs))
+            
+            (unless (setq f-alias (abbrev-symbol alias mail-abbrevs))
               (error "Cannot find the alias"))
 
             ;; `define-mail-abbrev' initializes f-alias to be
             ;; `mail-abbrev-expand-hook'. We replace this by
             ;; `bbdb-mail-abbrev-expand-hook'
-            (unless (eq (symbol-function f-alias) 'mail-abbrev-expand-hook)
+            ;; FIXME: Use proper accessor instead of `symbol-function'.
+            (unless (eq (symbol-function f-alias) #'mail-abbrev-expand-hook)
               (error "mail-aliases contains unexpected hook %s"
                      (symbol-function f-alias)))
             ;; `bbdb-mail-abbrev-hook' is called with mail addresses instead of
@@ -2562,6 +2619,7 @@ Rebuilding the aliases is enforced if pr
             ;; EXPANSION to the mail addresses it contains (which is tricky
             ;; because mail addresses in the database can be shortcuts for
             ;; the addresses in EXPANSION).
+            ;; FIXME: Use a closure rather than a backquoted lambda!
             (fset f-alias `(lambda ()
                              (bbdb-mail-abbrev-expand-hook
                               ,alias
@@ -2576,7 +2634,7 @@ Rebuilding the aliases is enforced if pr
   (when bbdb-completion-display-record
     (let ((bbdb-silent-internal t))
       (bbdb-display-records
-       (apply 'append
+       (apply #'append
               (mapcar (lambda (mail) (bbdb-message-search nil mail)) mails))
        nil t))))
 
@@ -2653,9 +2711,7 @@ one arg RECORD to define the default val
 This uses the tel URI syntax passed to `browse-url' to make the call.
 If `bbdb-dial-function' is non-nil then that is called to make the phone call."
   (interactive "sDial number: ")
-  (if bbdb-dial-function
-      (funcall bbdb-dial-function phone-string)
-    (browse-url (concat "tel:" phone-string))))
+  (funcall (or bbdb-dial-function #'bbdb--dial-default) phone-string))
 
 ;;;###autoload
 (defun bbdb-dial (phone force-area-code)
@@ -2668,7 +2724,7 @@ is non-nil.  Do not dial the extension."
       (setq phone (car (bbdb-record-phone (bbdb-current-record)))))
   (if (eq (car-safe phone) 'phone)
       (setq phone (car (cdr phone))))
-  (or (vectorp phone) (error "Not on a phone field"))
+  (or (bbdb-phone-p phone) (error "Not on a phone field"))
 
   (let ((number (bbdb-phone-string phone))
         shortnumber)
@@ -2680,7 +2736,7 @@ is non-nil.  Do not dial the extension."
     (unless force-area-code
       (let ((alist bbdb-dial-local-prefix-alist) prefix)
         (while (setq prefix (pop alist))
-          (if (string-match (concat "^" (eval (car prefix))) number)
+          (if (string-match (concat "^" (eval (car prefix) t)) number)
               (setq shortnumber (concat (cdr prefix)
                                         (substring number (match-end 0)))
                     alist nil)))))
@@ -2696,7 +2752,7 @@ is non-nil.  Do not dial the extension."
 
       ;; Leading + => long distance/international number
       (if (and bbdb-dial-long-distance-prefix
-               (string-match "^\+" number))
+               (string-match "^\\+" number))
           (setq number (concat bbdb-dial-long-distance-prefix " "
                                (substring number 1)))))
 
@@ -2752,7 +2808,7 @@ Interactively, use BBDB prefix \
             drec))
     (kill-new (replace-regexp-in-string
                "[ \t\n]*\\'" "\n"
-               (mapconcat 'identity (nreverse drec) "")))))
+               (mapconcat #'identity (nreverse drec) "")))))
 
 ;;;###autoload
 (defun bbdb-copy-fields-as-kill (records field &optional num)
--- bbdb3-3.2.orig/lisp/bbdb-migrate.el
+++ bbdb3-3.2/lisp/bbdb-migrate.el
@@ -1,6 +1,6 @@
-;;; bbdb-migrate.el --- migration functions for BBDB -*- lexical-binding: t -*-
+;;; bbdb-migrate.el --- migration functions for BBDB -*- lexical-binding:t -*-
 
-;; Copyright (C) 2010-2017  Free Software Foundation, Inc.
+;; Copyright (C) 2010-2020  Free Software Foundation, Inc.
 
 ;; This file is part of the Insidious Big Brother Database (aka BBDB),
 
@@ -37,6 +37,7 @@
 
 ;;; Code:
 
+(require 'cl-lib)
 (require 'bbdb)
 
 ;;; Migrating the BBDB
@@ -97,22 +98,16 @@
   records)
 
 (defconst bbdb-migrate-alist
-  '((3 (bbdb-record-xfields bbdb-record-set-xfields
-        bbdb-migrate-dates))
-    (4 (bbdb-record-address bbdb-record-set-address
-        bbdb-migrate-add-country))
-    (5 (bbdb-record-address bbdb-record-set-address
-        bbdb-migrate-streets-to-list))
-    (6 (bbdb-record-address bbdb-record-set-address
-        bbdb-migrate-postcode-to-string))
-    (7 (bbdb-record-xfields bbdb-record-set-xfields
-        bbdb-migrate-xfields-to-list)
-       (bbdb-record-organization bbdb-record-set-organization
-        bbdb-migrate-organization-to-list)))
+  '((3 (bbdb-record-xfields bbdb-migrate-dates))
+    (4 (bbdb-record-address bbdb-migrate-add-country))
+    (5 (bbdb-record-address bbdb-migrate-streets-to-list))
+    (6 (bbdb-record-address bbdb-migrate-postcode-to-string))
+    (7 (bbdb-record-xfields bbdb-migrate-xfields-to-list)
+       (bbdb-record-organization bbdb-migrate-organization-to-list)))
   ;; Formats 8 and 9: do nothing
   "Alist (VERSION . CHANGES).
-CHANGES is a list with elements (GET SET FUNCTION) that expands
-to action (SET record (FUNCTION (GET record))).")
+CHANGES is a list with elements (GETTER FUNCTION) that expands
+to action (setf (GETTER record) (FUNCTION (GETTER record))).")
 
 (defun bbdb-migrate-lambda (old)
   "Return the function to migrate from OLD to `bbdb-file-format'.
@@ -121,60 +116,61 @@ The manipulations are defined by `bbdb-m
     (while (<= old bbdb-file-format)
       (setq spec (append spec (cdr (assoc old bbdb-migrate-alist)))
             old (1+ old)))
-    `(lambda (record)
-       ,@(mapcar (lambda (change)
-                   ;; (SET record (FUNCTION (GET record)))
-                   `(,(nth 1 change) record ; SET
-                     (,(nth 2 change) ; FUNCTION
-                      (,(nth 0 change) record)))) ; GET
-                 spec)
-       record)))
+    (eval
+     `(lambda (record)
+        ,@(mapcar (lambda (change)
+                    (pcase-let ((`(,getter ,migrate-function) change))
+                      ;; (SET record (FUNCTION (GET record)))
+                      `(cl-callf ,migrate-function (,getter record))))
+                  spec)
+        record)
+     'lexical)))
 
 (defun bbdb-migrate-postcode-to-string (addresses)
   "Make all postcodes plain strings.
 This uses the code that used to be in `bbdb-address-postcode'."
   ;; apply the function to all addresses in the list and return a
   ;; modified list of addresses
-  (mapcar (lambda (address)
-            (let ((postcode (bbdb-address-postcode address)))
-              (bbdb-address-set-postcode
-               address
-               (cond ((stringp postcode)
-                      postcode)
-                     ;; nil or zero
-                     ((or (zerop postcode)
-                          (null postcode))
-                      "")
-                     ;; a number
-                     ((numberp postcode)
-                      (format "%d" postcode))
-                     ;; list with two strings
-                     ((and (stringp (nth 0 postcode))
-                           (stringp (nth 1 postcode)))
-                      ;; the second string starts with 4 digits
-                      (if (string-match "^[0-9][0-9][0-9][0-9]"
-                                        (nth 1 postcode))
-                          (format "%s-%s" (nth 0 postcode) (nth 1 postcode))
-                        ;; ("abc" "efg")
-                        (format "%s %s" (nth 0 postcode) (nth 1 postcode))))
-                     ;; list with two numbers
-                     ((and (integerp (nth 0 postcode))
-                           (integerp (nth 1 postcode)))
-                      (format "%05d-%04d" (nth 0 postcode) (nth 1 postcode)))
-                     ;; list with a string and a number
-                     ((and (stringp (nth 0 postcode))
-                           (integerp (nth 1 postcode)))
-                      (format "%s-%d" (nth 0 postcode) (nth 1 postcode)))
-                     ;; ("SE" (123 45))
-                     ((and (stringp (nth 0 postcode))
-                           (integerp (nth 0 (nth 1 postcode)))
-                           (integerp (nth 1 (nth 1 postcode))))
-                      (format "%s-%d %d" (nth 0 postcode) (nth 0 (nth 1 postcode))
-                              (nth 1 (nth 1 postcode))))
-                     ;; last possibility
-                     (t (format "%s" postcode)))))
-            address)
-          addresses))
+  (mapcar
+   (lambda (address)
+     (let ((postcode (bbdb-address-postcode address)))
+       (setf (bbdb-address-postcode address)
+             (cond ((stringp postcode)
+                    postcode)
+                   ;; nil or zero
+                   ((or (zerop postcode)
+                        (null postcode))
+                    "")
+                   ;; a number
+                   ((numberp postcode)
+                    (format "%d" postcode))
+                   ;; list with two strings
+                   ((and (stringp (nth 0 postcode))
+                         (stringp (nth 1 postcode)))
+                    ;; the second string starts with 4 digits
+                    (if (string-match "^[0-9][0-9][0-9][0-9]"
+                                      (nth 1 postcode))
+                        (format "%s-%s" (nth 0 postcode) (nth 1 postcode))
+                      ;; ("abc" "efg")
+                      (format "%s %s" (nth 0 postcode) (nth 1 postcode))))
+                   ;; list with two numbers
+                   ((and (integerp (nth 0 postcode))
+                         (integerp (nth 1 postcode)))
+                    (format "%05d-%04d" (nth 0 postcode) (nth 1 postcode)))
+                   ;; list with a string and a number
+                   ((and (stringp (nth 0 postcode))
+                         (integerp (nth 1 postcode)))
+                    (format "%s-%d" (nth 0 postcode) (nth 1 postcode)))
+                   ;; ("SE" (123 45))
+                   ((and (stringp (nth 0 postcode))
+                         (integerp (nth 0 (nth 1 postcode)))
+                         (integerp (nth 1 (nth 1 postcode))))
+                    (format "%s-%d %d" (nth 0 postcode) (nth 0 (nth 1 postcode))
+                            (nth 1 (nth 1 postcode))))
+                   ;; last possibility
+                   (t (format "%s" postcode)))))
+     address)
+   addresses))
 
 (defun bbdb-migrate-dates (xfields)
   "Change date formats.
--- bbdb3-3.2.orig/lisp/bbdb-mua.el
+++ bbdb3-3.2/lisp/bbdb-mua.el
@@ -1,6 +1,6 @@
 ;;; bbdb-mua.el --- various MUA functionality for BBDB -*- lexical-binding: t -*-
 
-;; Copyright (C) 2010-2017  Free Software Foundation, Inc.
+;; Copyright (C) 2010-2020  Free Software Foundation, Inc.
 
 ;; This file is part of the Insidious Big Brother Database (aka BBDB),
 
@@ -48,7 +48,7 @@
   (autoload 'vm-check-for-killed-summary "vm-misc")
   (autoload 'vm-error-if-folder-empty "vm-misc")
 
-  (autoload 'bbdb/rmail-header "bbdb-rmail")
+  (autoload 'rmail-get-header "rmail")
   (defvar rmail-buffer)
 
   (autoload 'bbdb/mh-header "bbdb-mhe")
@@ -68,7 +68,7 @@
     (rmail rmail-mode rmail-summary-mode)
     (mh mhe-mode mhe-summary-mode mh-folder-mode)
     (mu4e mu4e-view-mode)  ; Tackle `mu4e-headers-mode' later
-    (wl wl-summary-mode wl-draft-mode)
+    (wl wl-summary-mode wl-draft-mode mime-view-mode)
     (message message-mode mu4e-compose-mode notmuch-message-mode)
     (mail mail-mode))
   "Alist of MUA modes supported by BBDB.
@@ -115,7 +115,9 @@ MIME encoded headers are decoded.  Retur
                      ;; See http://permalink.gmane.org/gmane.emacs.gnus.general/78741
                      (eq mua 'gnus) (gnus-fetch-original-field header))
                     ((eq mua 'vm) (bbdb/vm-header header))
-                    ((eq mua 'rmail) (bbdb/rmail-header header))
+                    ((eq mua 'rmail)
+                     (with-current-buffer rmail-buffer
+                       (rmail-get-header header)))
                     ((eq mua 'mh) (bbdb/mh-header header))
                     ((eq mua 'mu4e) (message-field-value header))
                     ((eq mua 'wl) (bbdb/wl-header header))
@@ -238,7 +240,7 @@ Usually this function is called by the w
   ;; with the chain `bbdb-mua-auto-update-p' -> `bbdb-select-message'
   ;; -> `bbdb-update-records-p'.
   (while (and (functionp update-p)
-              ;; Bad! `search' is a function in `cl-seq.el'.
+              ;; Bad! `search' is a function in `cl.el'.
               (not (eq update-p 'search)))
     (setq update-p (funcall update-p)))
   (cond ((eq t update-p)
@@ -906,7 +908,7 @@ See `bbdb-mua-auto-update' for details a
                  (gnus . gnus-article-prepare-hook)
                  (mh . mh-show-hook)
                  (vm . vm-select-message-hook)
-                 (wl . wl-message-redisplay-hook)))
+                 (wl . wl-summary-redisplay-hook)))
     (if (memq (car mua) muas)
         (add-hook (cdr mua) 'bbdb-mua-auto-update)
       (remove-hook (cdr mua) 'bbdb-mua-auto-update))))
--- bbdb3-3.2.orig/lisp/bbdb-rmail.el
+++ bbdb3-3.2/lisp/bbdb-rmail.el
@@ -1,6 +1,6 @@
 ;;; bbdb-rmail.el --- BBDB interface to Rmail -*- lexical-binding: t -*-
 
-;; Copyright (C) 2010-2017  Free Software Foundation, Inc.
+;; Copyright (C) 2010-2018  Free Software Foundation, Inc.
 
 ;; This file is part of the Insidious Big Brother Database (aka BBDB),
 
@@ -26,18 +26,7 @@
 (require 'bbdb)
 (require 'bbdb-com)
 (require 'bbdb-mua)
-(require 'rmail)
 (require 'rmailsum)
-(require 'mailheader)
-
-;;;###autoload
-(defun bbdb/rmail-header (header)
-  "Pull HEADER out of Rmail header."
-  (with-current-buffer rmail-buffer
-    (save-restriction
-      (with-no-warnings (rmail-narrow-to-non-pruned-header))
-      (mail-header (intern-soft (downcase header))
-                   (mail-header-extract)))))
 
 ;;;###autoload
 (defun bbdb-insinuate-rmail ()
--- bbdb3-3.2.orig/lisp/bbdb-sc.el
+++ bbdb3-3.2/lisp/bbdb-sc.el
@@ -1,7 +1,7 @@
 ;;; bbdb-sc.el --- BBDB interface to Supercite -*- lexical-binding: t -*-
 
 ;; Copyright (C) 1991, 1992 Jamie Zawinski <jwz@netscape.com>.
-;; Copyright (C) 2010-2017 Roland Winkler <winkler@gnu.org>
+;; Copyright (C) 2010-2021 Roland Winkler <winkler@gnu.org>
 
 ;; This file is part of the Insidious Big Brother Database (aka BBDB),
 
@@ -71,12 +71,12 @@
 (require 'bbdb-mua)
 (require 'supercite)
 
+(define-obsolete-variable-alias 'bbdb/sc-attribution-field
+  'bbdb-sc-attribution-field "3.0")
 (defcustom bbdb-sc-attribution-field 'attribution
   "The BBDB xfield used for Supercite attribution."
   :group 'bbdb-utilities-sc
   :type '(symbol :tag "Field name"))
-(define-obsolete-variable-alias 'bbdb/sc-attribution-field
-  'bbdb-sc-attribution-field)
 
 (defcustom bbdb-sc-update-records-p 'search
   "How `bbdb-sc-set-attrib' updates BBDB records automatically.
@@ -105,6 +105,7 @@ Allowed values include
  "Last attribution used by Supercite.
 Used to compare against citation selected by the user.")
 
+(define-obsolete-function-alias 'bbdb/sc-consult-attr 'bbdb-sc-get-attrib "3.0")
 (defun bbdb-sc-get-attrib (mail)
   "Get the Supercite attribution from BBDB.
 MAIL is the mail address to look for in BBDB."
@@ -120,8 +121,8 @@ MAIL is the mail address to look for in
       (sit-for 1))
     (if record
         (bbdb-record-field (car record) bbdb-sc-attribution-field))))
-(define-obsolete-function-alias 'bbdb/sc-consult-attr 'bbdb-sc-get-attrib)
 
+(define-obsolete-function-alias 'bbdb/sc-set-attr 'bbdb-sc-set-attrib "3.0")
 (defun bbdb-sc-set-attrib ()
   "Store attribution in BBDB."
   (let ((from (bbdb-extract-address-components (sc-mail-field "from")))
@@ -147,8 +148,8 @@ MAIL is the mail address to look for in
                                          (bbdb-record-name record) attrib))))
           (bbdb-record-set-field record bbdb-sc-attribution-field attrib)
           (bbdb-change-record record))))))
-(define-obsolete-function-alias 'bbdb/sc-set-attr 'bbdb-sc-set-attrib)
 
+(define-obsolete-function-alias 'bbdb/sc-default 'bbdb-sc-update-from "3.0")
 ;;;###autoload
 (defun bbdb-sc-update-from ()
   "Update the \"from\" field in `sc-mail-info'.
@@ -169,7 +170,6 @@ complement the \"from\" field in `sc-mai
     (if name
         (setcdr (assoc-string "from" sc-mail-info t)
                 (format "%s <%s>" name (cadr address))))))
-(define-obsolete-function-alias 'bbdb/sc-default 'bbdb-sc-update-from)
 
 ;; Insert our hooks
 
--- bbdb3-3.2.orig/lisp/bbdb-snarf.el
+++ bbdb3-3.2/lisp/bbdb-snarf.el
@@ -1,6 +1,6 @@
 ;;; bbdb-snarf.el --- convert free-form text to BBDB records -*- lexical-binding: t -*-
 
-;; Copyright (C) 2010-2017  Free Software Foundation, Inc.
+;; Copyright (C) 2010-2020  Free Software Foundation, Inc.
 
 ;; This file is part of the Insidious Big Brother Database (aka BBDB),
 
@@ -189,8 +189,8 @@ The first subexpression becomes the URL.
       (let ((name (match-string 1)))
         (replace-match "")
         (setq name (bbdb-divide-name name))
-        (bbdb-record-set-firstname record (car name))
-        (bbdb-record-set-lastname record (cdr name)))))
+        (setf (bbdb-record-firstname record) (car name))
+        (setf (bbdb-record-lastname record) (cdr name)))))
 
 (defun bbdb-snarf-name-mail (record)
   "Snarf name from mail address for RECORD."
@@ -202,8 +202,8 @@ The first subexpression becomes the URL.
                (setq name (car (bbdb-extract-address-components
                                 (car (bbdb-record-mail record)))))
                (setq name (bbdb-divide-name name)))
-      (bbdb-record-set-firstname record (car name))
-      (bbdb-record-set-lastname record (cadr name)))))
+      (setf (bbdb-record-firstname record) (car name))
+      (setf (bbdb-record-lastname record) (cadr name)))))
 
 (defun bbdb-snarf-mail-address (record)
   "Snarf name and mail address for RECORD."
@@ -212,9 +212,9 @@ The first subexpression becomes the URL.
   ;; a more complex rule, the buffer should be narrowed appropriately.
   (let* ((data (bbdb-extract-address-components (buffer-string)))
          (name (and (car data) (bbdb-divide-name (car data)))))
-    (bbdb-record-set-firstname record (car name))
-    (bbdb-record-set-lastname  record (cdr name))
-    (bbdb-record-set-mail record (list (cadr data)))
+    (setf (bbdb-record-firstname record) (car name))
+    (setf (bbdb-record-lastname  record) (cdr name))
+    (setf (bbdb-record-mail record) (list (cadr data)))
     (delete-region (point-min) (point-max))))
 
 (defun bbdb-snarf-mail (record)
@@ -224,7 +224,7 @@ This uses the first subexpresion of `bbd
     (while (re-search-forward bbdb-snarf-mail-regexp nil t)
       (push (match-string 1) mails)
       (replace-match ""))
-    (bbdb-record-set-mail record (nconc (bbdb-record-mail record) mails))))
+    (setf (bbdb-record-mail record) (nconc (bbdb-record-mail record) mails))))
 
 (defun bbdb-snarf-label (field)
   "Extract the label before point, or return default label for FIELD."
@@ -250,8 +250,8 @@ This uses the first subexpresion of `bbd
                          (bbdb-parse-phone (match-string 1))))
               phones)
         (replace-match "")))
-    (bbdb-record-set-phone record (nconc (bbdb-record-phone record)
-                                         (nreverse phones)))))
+    (setf (bbdb-record-phone record) (nconc (bbdb-record-phone record)
+                                            (nreverse phones)))))
 
 (defun bbdb-snarf-phone-eu (record &optional phone-regexp)
   "Snarf European phone numbers for RECORD.
@@ -259,41 +259,44 @@ PHONE-REGEXP is the regexp to match a ph
 It defaults to `bbdb-snarf-phone-eu-regexp'."
   (let ((case-fold-search t) phones)
     (while (re-search-forward (or phone-regexp
-                                  bbdb-snarf-phone-eu-regexp) nil t)
+                                  bbdb-snarf-phone-eu-regexp)
+                              nil t)
       (goto-char (match-beginning 0))
       (push (vector (bbdb-snarf-label 'phone)
                     (match-string 1))
             phones)
       (replace-match ""))
-    (bbdb-record-set-phone record (nconc (bbdb-record-phone record)
-                                         (nreverse phones)))))
+    (setf (bbdb-record-phone record) (nconc (bbdb-record-phone record)
+                                            (nreverse phones)))))
 
 (defun bbdb-snarf-streets (address)
   "Snarf streets for ADDRESS.  This assumes a narrowed region."
-  (bbdb-address-set-streets address (bbdb-split "\n" (buffer-string)))
+  (setf (bbdb-address-streets address) (bbdb-split "\n" (buffer-string)))
   (delete-region (point-min) (point-max)))
 
 (defun bbdb-snarf-address-us (record)
   "Snarf a US address for RECORD."
-  (let ((address (make-vector bbdb-address-length nil)))
+  (let ((address (bbdb-address--make)))
     (cond ((re-search-forward bbdb-snarf-postcode-us-regexp nil t)
            ;; Streets, City, State Postcode
            (save-restriction
              (narrow-to-region (point-min) (match-end 0))
              ;; Postcode
              (goto-char (match-beginning 0))
-             (bbdb-address-set-postcode address
-              (bbdb-parse-postcode (match-string 1)))
+             (setf (bbdb-address-postcode address)
+                   (bbdb-parse-postcode (match-string 1)))
              ;; State
              (skip-chars-backward " \t")
              (let ((pos (point)))
                (skip-chars-backward "^ \t,")
-               (bbdb-address-set-state address (buffer-substring (point) pos)))
+               (setf (bbdb-address-state address)
+                     (buffer-substring (point) pos)))
              ;; City
              (skip-chars-backward " \t,")
              (let ((pos (point)))
                (beginning-of-line)
-               (bbdb-address-set-city address (buffer-substring (point) pos)))
+               (setf (bbdb-address-city address)
+                     (buffer-substring (point) pos)))
              ;; Toss it
              (forward-char -1)
              (delete-region (point) (point-max))
@@ -303,8 +306,8 @@ It defaults to `bbdb-snarf-phone-eu-rege
           ;; Try for just Streets, City, State
           ((let (case-fold-search)
              (re-search-forward "^\\(.*\\), \\([A-Z][A-Za-z]\\)$" nil t))
-           (bbdb-address-set-city address (match-string 1))
-           (bbdb-address-set-state address (match-string 2))
+           (setf (bbdb-address-city address) (match-string 1))
+           (setf (bbdb-address-state address) (match-string 2))
            (replace-match "")
            (save-restriction
              (narrow-to-region (point-min) (match-beginning 0))
@@ -312,13 +315,13 @@ It defaults to `bbdb-snarf-phone-eu-rege
              (bbdb-snarf-streets address))))
     (when (bbdb-address-city address)
       (if bbdb-snarf-address-us-country
-          (bbdb-address-set-country address bbdb-snarf-address-us-country))
+          (setf (bbdb-address-country address) bbdb-snarf-address-us-country))
       ;; Fixme: There are no labels anymore.  `bbdb-snarf-streets' snarfed
       ;; everything that was left!
-      (bbdb-address-set-label address (bbdb-snarf-label 'address))
-      (bbdb-record-set-address record
-                               (nconc (bbdb-record-address record)
-                                      (list address))))))
+      (setf (bbdb-address-label address) (bbdb-snarf-label 'address))
+      (setf (bbdb-record-address record)
+            (nconc (bbdb-record-address record)
+                   (list address))))))
 
 (defun bbdb-snarf-address-eu (record &optional postcode-regexp country)
   "Snarf a European address for RECORD.
@@ -328,27 +331,29 @@ is used in many continental European cou
 POSTCODE-REGEXP defaults to `bbdb-snarf-postcode-eu-regexp'.
 COUNTRY is the country to use.  It defaults to `bbdb-snarf-address-eu-country'."
   (when (re-search-forward (or postcode-regexp
-                               bbdb-snarf-postcode-eu-regexp) nil t)
-    (let ((address (make-vector bbdb-address-length nil)))
+                               bbdb-snarf-postcode-eu-regexp)
+                           nil t)
+    (let ((address (bbdb-address--make)))
       (save-restriction
         (goto-char (match-end 0))
         (narrow-to-region (point-min) (line-end-position))
         ;; Postcode
-        (bbdb-address-set-postcode address (match-string 1))
+        (setf (bbdb-address-postcode address) (match-string 1))
         ;; City
         (skip-chars-forward " \t")
-        (bbdb-address-set-city address (buffer-substring (point) (point-max)))
+        (setf (bbdb-address-city address)
+              (buffer-substring (point) (point-max)))
         ;; Toss it
         (delete-region (match-beginning 0) (point-max))
         ;; Streets
         (goto-char (point-min))
         (bbdb-snarf-streets address))
       (unless country (setq country bbdb-snarf-address-eu-country))
-      (if country (bbdb-address-set-country address country))
-      (bbdb-address-set-label address (bbdb-snarf-label 'address))
-      (bbdb-record-set-address record
-                               (nconc (bbdb-record-address record)
-                                      (list address))))))
+      (if country (setf (bbdb-address-country address) country))
+      (setf (bbdb-address-label address) (bbdb-snarf-label 'address))
+      (setf (bbdb-record-address record)
+            (nconc (bbdb-record-address record)
+                   (list address))))))
 
 (defun bbdb-snarf-url (record)
   "Snarf URL for RECORD.
@@ -356,19 +361,17 @@ This uses the first subexpresion of `bbd
   (when (and bbdb-snarf-url
              (let ((case-fold-search t))
                (re-search-forward bbdb-snarf-url-regexp nil t)))
-    (bbdb-record-set-xfields
-     record
-     (nconc (bbdb-record-xfields record)
-            (list (cons bbdb-snarf-url (match-string 1)))))
+    (setf (bbdb-record-xfields record)
+          (nconc (bbdb-record-xfields record)
+                 (list (cons bbdb-snarf-url (match-string 1)))))
     (replace-match "")))
 
 (defun bbdb-snarf-notes (record)
   "Snarf notes for RECORD."
   (when (/= (point-min) (point-max))
-    (bbdb-record-set-xfields
-     record
-     (nconc (bbdb-record-xfields record)
-            (list (cons bbdb-default-xfield (buffer-string)))))
+    (setf (bbdb-record-xfields record)
+          (nconc (bbdb-record-xfields record)
+                 (list (cons bbdb-default-xfield (buffer-string)))))
     (erase-buffer)))
 
 (defsubst bbdb-snarf-rule-interactive ()
--- bbdb3-3.2.orig/lisp/bbdb-tex.el
+++ bbdb3-3.2/lisp/bbdb-tex.el
@@ -1,6 +1,6 @@
 ;;; bbdb-tex.el --- feed BBDB into LaTeX  -*- lexical-binding: t -*-
 
-;; Copyright (C) 2010-2017  Free Software Foundation, Inc.
+;; Copyright (C) 2010-2020  Free Software Foundation, Inc.
 
 ;; Authors: Boris Goldowsky <boris@cs.rochester.edu>
 ;;          Dirk Grunwald <grunwald@cs.colorado.edu>
@@ -103,6 +103,7 @@
 
 ;;; Code:
 
+(eval-when-compile (require 'cl-lib))
 (require 'bbdb)
 (require 'bbdb-com)
 
--- bbdb3-3.2.orig/lisp/bbdb-wl.el
+++ bbdb3-3.2/lisp/bbdb-wl.el
@@ -1,6 +1,6 @@
 ;;; bbdb-wl.el --- BBDB interface to Wanderlust -*- lexical-binding: t -*-
 
-;; Copyright (C) 2015-2017  Free Software Foundation, Inc.
+;; Copyright (C) 2015-2020  Free Software Foundation, Inc.
 
 ;; This file is part of the Insidious Big Brother Database (aka BBDB),
 
@@ -28,18 +28,28 @@
 
 (defvar wl-summary-mode-map)
 (defvar wl-draft-mode-map)
+(defvar wl-summary-buffer-name)
 (defvar wl-summary-buffer-elmo-folder)
 (eval-and-compile
   (autoload 'wl-summary-message-number "wl-summary")
+  (autoload 'wl-summary-sticky-p "wl-summary")
+  (autoload 'wl-summary-sticky-buffer-name "wl-summary")
   (autoload 'elmo-message-entity "elmo-msgdb")
-  (autoload 'elmo-message-entity-field "elmo-msgdb"))
+  (autoload 'elmo-message-entity-field "elmo-msgdb")
+  (autoload 'elmo-folder-name-internal "elmo"))
 
 ;;;###autoload
 (defun bbdb/wl-header (header)
-  (elmo-message-entity-field
-   (elmo-message-entity wl-summary-buffer-elmo-folder
-                        (wl-summary-message-number))
-   (intern (downcase header)) 'string))
+  (with-current-buffer
+      (if (wl-summary-sticky-p)
+          (wl-summary-sticky-buffer-name
+           (elmo-folder-name-internal wl-summary-buffer-elmo-folder))
+        wl-summary-buffer-name)
+    (elmo-message-entity-field
+     (elmo-message-entity wl-summary-buffer-elmo-folder
+                          (wl-summary-message-number))
+     (intern (downcase header))
+     'string)))
 
 ;;;###autoload
 (defun bbdb-insinuate-wl ()
--- bbdb3-3.2.orig/lisp/bbdb.el
+++ bbdb3-3.2/lisp/bbdb.el
@@ -1,9 +1,10 @@
 ;;; bbdb.el --- core of BBDB -*- lexical-binding: t -*-
 
-;; Copyright (C) 2010-2017  Free Software Foundation, Inc.
+;; Copyright (C) 2010-2020  Free Software Foundation, Inc.
 
+;; Maintainer: Roland Winkler <winkler@gnu.org>
 ;; Version: 3.2
-;; Package-Requires: ((emacs "24"))
+;; Package-Requires: ((emacs "24") (cl-lib "0.5"))
 
 ;; This file is part of the Insidious Big Brother Database (aka BBDB),
 
@@ -36,6 +37,7 @@
 
 ;;; Code:
 
+(eval-when-compile (require 'cl-lib))
 (require 'timezone)
 (require 'bbdb-site)
 
@@ -228,10 +230,10 @@ first, followed by a call of this hook."
   :group 'bbdb
   :type 'hook)
 
-(defcustom bbdb-merge-records-function nil
+(defcustom bbdb-merge-records-function #'bbdb-merge-records
   "If non-nil, a function for merging two records.
 This function is called when loading a record into BBDB that has the same uuid
-as an exisiting record.  If nil use `bbdb-merge-records'.
+as an exisiting record.
 This function should take two arguments RECORD1 and RECORD2, with RECORD2
 being the already existing record.  It should merge RECORD1 into RECORD2,
 and return RECORD2."
@@ -1050,7 +1052,7 @@ See also `bbdb-add-mails'."
                  (function :tag "Function for analyzing primary handling")
                  (regexp :tag "If the new mail address matches this regexp put it at the end.")))
 
-(defcustom bbdb-canonicalize-mail-function nil
+(defcustom bbdb-canonicalize-mail-function #'bbdb-string-trim
   "If non-nil, it should be a function of one arg: a mail address string.
 When BBDB \"notices\" a message, the corresponding mail addresses are passed
 to this function first.  It acts as a kind of \"filter\" to transform
@@ -1062,6 +1064,8 @@ See also `bbdb-ignore-redundant-mails'."
   :group 'bbdb-mua
   :type 'function)
 
+(define-obsolete-variable-alias 'bbdb-canonicalize-redundant-mails
+  'bbdb-ignore-redundant-mails "3.0")
 (defcustom bbdb-ignore-redundant-mails 'query
   "How to handle redundant mail addresses for existing BBDB records.
 For example, \"foo@bar.baz.com\" is redundant w.r.t. \"foo@baz.com\".
@@ -1087,10 +1091,8 @@ See also `bbdb-add-mails' and `bbdb-cano
                  (number :tag "Number of seconds to display redundant addresses")
                  (function :tag "Function for handling redundant mail addresses")
                  (regexp :tag "If the new address matches this regexp never ignore it.")))
-(define-obsolete-variable-alias 'bbdb-canonicalize-redundant-mails
-  'bbdb-ignore-redundant-mails "3.0")
 
-(defcustom bbdb-message-clean-name-function 'bbdb-message-clean-name-default
+(defcustom bbdb-message-clean-name-function #'bbdb-message-clean-name-default
   "Function to clean up the name in the header of a message.
 It takes one argument, the name as extracted by
 `mail-extract-address-components'."
@@ -1285,6 +1287,7 @@ See also `bbdb-auto-notes-ignore-message
                   (string :tag "Header name")
                   (regexp :tag "Regexp to match on header value"))))
 
+(define-obsolete-variable-alias 'bbdb-message-pop-up 'bbdb-mua-pop-up "3.0")
 (defcustom bbdb-mua-pop-up t
   "If non-nil, display an auto-updated BBDB window while using a MUA.
 If 'horiz, stack the window horizontally if there is room.
@@ -1295,7 +1298,6 @@ See also `bbdb-mua-pop-up-window-size' a
   :type '(choice (const :tag "MUA BBDB window stacked vertically" t)
                  (const :tag "MUA BBDB window stacked horizontally" horiz)
                  (const :tag "No MUA BBDB window" nil)))
-(define-obsolete-variable-alias 'bbdb-message-pop-up 'bbdb-mua-pop-up "3.0")
 
 (defcustom bbdb-mua-pop-up-window-size bbdb-pop-up-window-size
   "Vertical size of MUA pop-up BBDB window (vertical split).
@@ -1322,6 +1324,7 @@ window width that BBDB will take over."
 
 
 ;;; xfields processing
+(define-obsolete-variable-alias 'bbdb-notes-sort-order 'bbdb-xfields-sort-order "3.0")
 (defcustom bbdb-xfields-sort-order
   '((notes . 0) (url . 1) (ftp . 2) (gopher . 3) (telnet . 4) (mail-alias . 5)
     (mail-folder . 6) (lpr . 7))
@@ -1333,8 +1336,9 @@ weights more than 100 will be in the end
   :type '(repeat (cons
                   (symbol :tag "xfield")
                   (number :tag "Weight"))))
-(define-obsolete-variable-alias 'bbdb-notes-sort-order 'bbdb-xfields-sort-order "3.0")
 
+(define-obsolete-variable-alias 'bbdb-merge-notes-function-alist
+  'bbdb-merge-xfield-function-alist "3.0")
 (defcustom bbdb-merge-xfield-function-alist nil
   "Alist defining merging functions for particular xfields.
 Each element is of the form (LABEL . MERGE-FUN).
@@ -1343,8 +1347,6 @@ For merging xfield LABEL, this will use
   :type '(repeat (cons
                   (symbol :tag "xfield")
                   (function :tag "merge function"))))
-(define-obsolete-variable-alias 'bbdb-merge-notes-function-alist
-  'bbdb-merge-xfield-function-alist "3.0")
 
 (defcustom bbdb-mua-summary-unification-list
   '(name mail message-name message-mail message-address)
@@ -1566,7 +1568,7 @@ when dialling (international dialing pre
   :type '(choice (const :tag "No digits required" nil)
                  (string :tag "Dial this first" "1")))
 
-(defcustom bbdb-dial-function nil
+(defcustom bbdb-dial-function #'bbdb--dial-default
   "If non-nil this should be a function used for dialing phone numbers.
 This function is used by `bbdb-dial-number'.  It requires one
 argument which is a string for the number that is dialed.
@@ -1575,6 +1577,8 @@ to make the call."
   :group 'bbdb-utilities-dialing
   :type 'function)
 
+(defun bbdb--dial-default (phone-string)
+  (browse-url (concat "tel:" phone-string)))
 
 ;; Faces for font-lock
 (defgroup bbdb-faces nil
@@ -1651,36 +1655,50 @@ You really should not disable debugging.
   "Bind this to t to quiet things down - do not set it.
 See also `bbdb-silent'.")
 
-(defvar bbdb-init-forms
-  '((gnus                       ; gnus 3.15 or newer
-     (add-hook 'gnus-startup-hook 'bbdb-insinuate-gnus))
+(declare-function bbdb-insinuate-gnus "bbdb-gnus" ())
+(declare-function bbdb-insinuate-mh "bbdb-mhe" ())
+(declare-function bbdb-insinuate-rmail "bbdb-rmail" ())
+(declare-function bbdb-insinuate-vm "bbdb-vm" ())
+(declare-function bbdb-insinuate-mail "bbdb-message" ())
+(declare-function bbdb-insinuate-message "bbdb-message" ())
+(declare-function bbdb-insinuate-mu4e "bbdb-m4e" ())
+(declare-function bbdb-insinuate-sc "bbdb-sc" ())
+(declare-function bbdb-pgp "bbdb-pgp" ())
+(declare-function bbdb-insinuate-wl "bbdb-wl" ())
+(declare-function bbdb-anniv-diary-entries "bbdb-anniv" ())
+
+(define-obsolete-variable-alias 'bbdb-init-forms
+  'bbdb-init-functions "3.0")
+(defvar bbdb-init-functions
+  `((gnus                       ; gnus 3.15 or newer
+     ,(lambda () (add-hook 'gnus-startup-hook #'bbdb-insinuate-gnus)))
     (mh-e                       ; MH-E
-     (add-hook 'mh-folder-mode-hook 'bbdb-insinuate-mh))
+     ,(lambda () (add-hook 'mh-folder-mode-hook #'bbdb-insinuate-mh)))
     (rmail                      ; RMAIL
-     (add-hook 'rmail-mode-hook 'bbdb-insinuate-rmail))
+     ,(lambda () (add-hook 'rmail-mode-hook #'bbdb-insinuate-rmail)))
     (vm                        ; newer versions of vm do not have `vm-load-hook'
-     (eval-after-load "vm" '(bbdb-insinuate-vm)))
+     ,(lambda () (eval-after-load "vm" '(bbdb-insinuate-vm))))
     (mail                       ; the standard mail user agent
-     (add-hook 'mail-setup-hook 'bbdb-insinuate-mail))
+     ,(lambda () (add-hook 'mail-setup-hook #'bbdb-insinuate-mail)))
     (sendmail
-     (progn (message "BBDB: sendmail insinuation deprecated. Use mail.")
-            (add-hook 'mail-setup-hook 'bbdb-insinuate-mail)))
+     ,(lambda () (message "BBDB: sendmail insinuation deprecated.  Use mail.")
+            (add-hook 'mail-setup-hook #'bbdb-insinuate-mail)))
     (message                    ; the gnus mail user agent
-     (add-hook 'message-setup-hook 'bbdb-insinuate-message))
+     ,(lambda () (add-hook 'message-setup-hook #'bbdb-insinuate-message)))
     (mu4e                       ; the mu4e user agent
-     (add-hook 'mu4e-main-mode-hook 'bbdb-insinuate-mu4e))
+     ,(lambda () (add-hook 'mu4e-main-mode-hook #'bbdb-insinuate-mu4e)))
 
     (sc                         ; supercite
-     (add-hook 'sc-load-hook 'bbdb-insinuate-sc))
+     ,(lambda () (add-hook 'sc-load-hook #'bbdb-insinuate-sc)))
     (anniv                      ; anniversaries
-     (add-hook 'diary-list-entries-hook 'bbdb-anniv-diary-entries))
+     ,(lambda () (add-hook 'diary-list-entries-hook #'bbdb-anniv-diary-entries)))
     (pgp                        ; pgp-mail
-     (progn
-       (add-hook 'message-send-hook 'bbdb-pgp)
-       (add-hook 'mail-send-hook 'bbdb-pgp)))
+     ,(lambda ()
+        (add-hook 'message-send-hook #'bbdb-pgp)
+        (add-hook 'mail-send-hook #'bbdb-pgp)))
     (wl
-     (add-hook 'wl-init-hook 'bbdb-insinuate-wl)))
-  "Alist mapping features to insinuation forms.")
+     ,(lambda () (add-hook 'wl-init-hook #'bbdb-insinuate-wl))))
+  "Alist mapping features to insinuation functions.")
 
 (defvar bbdb-search-invert nil
   "Bind this variable to t in order to invert the result of `bbdb-search'.")
@@ -1915,7 +1933,7 @@ This is a child of `special-mode-map'.")
   "Display a message at the bottom of the screen.
 ARGS are passed to `message'."
   (ding t)
-  (apply 'message args))
+  (apply #'message args))
 
 (defun bbdb-string-trim (string &optional null)
   "Remove leading and trailing whitespace and all properties from STRING.
@@ -1964,10 +1982,11 @@ The inverse function of `bbdb-split'."
   (if (symbolp separator)
       (setq separator (nth 1 (or (cdr (assq separator bbdb-separator-alist))
                                  bbdb-default-separator))))
-  (mapconcat 'identity
-             (delete "" (apply 'append (mapcar (lambda (x) (if (stringp x)
-                                                               (list x) x))
-                                               strings))) separator))
+  (mapconcat #'identity
+             (delete "" (apply #'append (mapcar (lambda (x) (if (stringp x)
+                                                                (list x) x))
+                                                strings)))
+             separator))
 
 (defun bbdb-list-strings (list)
   "Remove all elements from LIST which are not non-empty strings."
@@ -1996,6 +2015,7 @@ COLLECTION and REQUIRE-MATCH have the sa
        ;; Hack: In `minibuffer-local-completion-map' remove
        ;; the binding of SPC to `minibuffer-complete-word'
        ;; and of ? to `minibuffer-completion-help'.
+       ;; FIXME: Explain why we don't want to use the bindings of SPC and ?
        (minibuffer-with-setup-hook
            (lambda ()
              (use-local-map
@@ -2164,14 +2184,11 @@ by `mail-extract-address-components'.
 Pass FULL-NAME through `bbdb-message-clean-name-function'
 and CANONICAL-ADDRESS through `bbdb-canonicalize-mail-function'."
   (list (if (car components)
-            (if bbdb-message-clean-name-function
-                (funcall bbdb-message-clean-name-function (car components))
-              (car components)))
+            (funcall (or bbdb-message-clean-name-function #'identity)
+                     (car components)))
         (if (cadr components)
-            (if bbdb-canonicalize-mail-function
-                (funcall bbdb-canonicalize-mail-function (cadr components))
-              ;; Minimalistic clean-up
-              (bbdb-string-trim (cadr components))))))
+            (funcall (or bbdb-canonicalize-mail-function #'bbdb-string-trim)
+                     (cadr components)))))
 
 (defun bbdb-extract-address-components (address &optional all)
   "Given an RFC-822 address ADDRESS, extract full name and canonical address.
@@ -2179,7 +2196,7 @@ This function behaves like `mail-extract
 its return value through `bbdb-clean-address-components'.
 See also `bbdb-decompose-bbdb-address'."
   (if all
-      (mapcar 'bbdb-clean-address-components
+      (mapcar #'bbdb-clean-address-components
               (mail-extract-address-components address t))
     (bbdb-clean-address-components (mail-extract-address-components address))))
 
@@ -2328,53 +2345,68 @@ This strips garbage from the user full N
   (substring-no-properties name))
 
 ;; BBDB data structure
-(defmacro bbdb-defstruct (name &rest elts)
-  "Define two functions to operate on vector NAME for each symbol ELT in ELTS.
-The function bbdb-NAME-ELT returns the element ELT in vector NAME.
-The function bbdb-NAME-set-ELT sets ELT.
-Also define a constant bbdb-NAME-length that holds the number of ELTS
-in vector NAME."
+
+(defmacro bbdb--defun-obsolete-setters (type &optional fields)
+  "Define obsolete setters that used to be defined by the old `bbdb-defstruct'."
   (declare (indent 1))
-  (let* ((count 0)
-         (sname (symbol-name name))
-         (uname (upcase sname))
-         (cname (concat "bbdb-" sname "-"))
-         body)
-    (dolist (elt elts)
-      (let* ((selt (symbol-name elt))
-             (setname  (intern (concat cname "set-" selt))))
-        (push (list 'defsubst (intern (concat cname selt)) `(,name)
-                    (format "For BBDB %s read element %i `%s'."
-                            uname count selt)
-                    ;; Use `elt' instead of `aref' so that these functions
-                    ;; also work for the `bbdb-record-type' pseudo-code.
-                    `(elt ,name ,count)) body)
-        (push (list 'defsubst setname `(,name value)
-                    (format "For BBDB %s set element %i `%s' to VALUE.  \
-Return VALUE.
-Do not call this function directly.  Call instead `bbdb-record-set-field'
-which ensures the integrity of the database.  Also, this makes your code
-more robust with respect to possible future changes of BBDB's innermost
-internals."
-                            uname count selt)
-                    `(aset ,name ,count value)) body))
-      (setq count (1+ count)))
-    (push (list 'defconst (intern (concat cname "length")) count
-                (concat "Length of BBDB `" sname "'.")) body)
-    (cons 'progn body)))
+  (unless fields
+    ;; This only works in Emacs≥25!
+    (let* ((class (cl-find-class type))
+           (slots (cl--class-slots class)))
+      (setq fields (mapcar #'cl--slot-descriptor-name slots))))
+  `(progn
+     ,@(mapcar (lambda (field)
+                 (let ((accessor (intern (format "%s-%s" type field))))
+                   `(defun ,(intern (format "%s-set-%s" type field)) (obj val)
+                      (declare (obsolete
+                                ,(format "use (setf (%s OBJ) VAL)) instead"
+                                         accessor)
+                                "BBDB-3.3"))
+                      (setf (,accessor obj) val))))
+               fields)))
 
 ;; Define RECORD:
-(bbdb-defstruct record
+(defalias 'bbdb-record-p #'vectorp)
+(cl-defstruct (bbdb-record
+               (:type vector)
+               (:constructor nil)
+               (:constructor bbdb-record--make ()))
   firstname lastname affix aka organization phone address mail xfields
   uuid creation-date timestamp cache)
+(bbdb--defun-obsolete-setters bbdb-record
+  (firstname lastname affix aka organization phone address mail xfields
+   uuid creation-date timestamp cache))
 
 ;; Define PHONE:
-(bbdb-defstruct phone
+;; FIXME: Currently, the PHONE structure can have two internal formats.
+;; - It can be a vector with elements (LABEL AREA EXCHANGE SUFFIX EXTENSION),
+;;   where LABEL is a string and the remaining elements are integer numbers.
+;;   This scheme refers to the North American Numbering Plan (NANP).
+;; - It can be a vector with elements (LABEL STRING) both of which are strings.
+;; Does the NANP format have any real benefits for NANP numbers?
+;; There should be only one internal format for all phone numbers.  Likely,
+;; this scheme should represent all phone numbers as strings.
+;; Also, it should allow comments as a separate string.
+;; Inspired by RFC3966, it could be something like
+;;   [country code [area code [local number]]] [extension} [comment]
+;; However, this will often require sophisticated parsing.  Is it
+;; worth the effort compared with using a single string?
+(defalias 'bbdb-phone-p #'vectorp)
+(defalias 'bbdb-phone--make #'vector)
+(cl-defstruct (bbdb-phone
+               (:type vector)
+               (:constructor nil))
   label area exchange suffix extension)
+(bbdb--defun-obsolete-setters bbdb-phone (label area exchange suffix extension))
 
 ;; Define ADDRESS:
-(bbdb-defstruct address
+(cl-defstruct (bbdb-address
+               (:type vector)
+               (:constructor nil)
+               (:constructor bbdb-address--make ()))
   label streets city state postcode country)
+(bbdb--defun-obsolete-setters bbdb-address
+  (label streets city state postcode country))
 
 ;; Define record CACHE:
 ;; - fl-name (first and last name of the person referred to by the record),
@@ -2383,7 +2415,10 @@ internals."
 ;; - mail-canon (list of canonical mail addresses)
 ;; - sortkey (the concatenation of the elements used for sorting the record),
 ;; - marker  (position of beginning of record in `bbdb-file')
-(bbdb-defstruct cache
+(cl-defstruct (bbdb-cache
+               (:type vector)
+               (:constructor nil)
+               (:constructor bbdb-cache--make ()))
   fl-name lf-name mail-aka mail-canon sortkey marker)
 
 (defsubst bbdb-record-mail-aka (record)
@@ -2397,15 +2432,15 @@ internals."
 (defun bbdb-empty-record ()
   "Return a new empty record structure with a cache.
 It is the caller's responsibility to make the new record known to BBDB."
-  (let ((record (make-vector bbdb-record-length nil)))
-    (bbdb-record-set-cache record (make-vector bbdb-cache-length nil))
+  (let ((record (bbdb-record--make)))
+    (setf (bbdb-record-cache record) (bbdb-cache--make))
     record))
 
 ;; `bbdb-hashtable' associates with each KEY a list of matching records.
 ;; KEY includes fl-name, lf-name, organizations, AKAs and email addresses.
 ;; When loading the database the hash table is initialized by calling
-;; `bbdb-hash-record' for each record.  This function is also called
-;; when new records are added to the database.
+;; `bbdb-register-record' for each record.  This function is also called
+;; when adding new records to the database.
 ;; `bbdb-delete-record-internal' with arg REMHASH non-nil removes a record
 ;; from the hash table (besides deleting the record from the database).
 ;; When an existing record is modified, the code that modifies the record
@@ -2480,19 +2515,6 @@ KEY must be a string or nil.  Empty stri
               (puthash key records bbdb-hashtable)
             (remhash key bbdb-hashtable))))))
 
-(defun bbdb-hash-record (record)
-  "Insert RECORD in `bbdb-hashtable'.
-This performs all initializations required for a new record.
-Do not call this for existing records that require updating."
-  (bbdb-puthash (bbdb-record-name record) record)
-  (bbdb-puthash (bbdb-record-name-lf record) record)
-  (dolist (organization (bbdb-record-organization record))
-    (bbdb-puthash organization record))
-  (dolist (aka (bbdb-record-aka record))
-    (bbdb-puthash aka record))
-  (bbdb-puthash-mail record)
-  (puthash (bbdb-record-uuid record) record bbdb-uuid-table))
-
 (defun bbdb-puthash-mail (record)
   "For RECORD put mail into `bbdb-hashtable'."
   (let (mail-aka mail-canon address)
@@ -2503,10 +2525,10 @@ Do not call this for existing records th
         (bbdb-puthash (car address) record))
       (push (nth 1 address) mail-canon)
       (bbdb-puthash (nth 1 address) record))
-    (bbdb-cache-set-mail-aka (bbdb-record-cache record)
-                             (nreverse mail-aka))
-    (bbdb-cache-set-mail-canon (bbdb-record-cache record)
-                               (nreverse mail-canon))))
+    (setf (bbdb-cache-mail-aka (bbdb-record-cache record))
+          (nreverse mail-aka))
+    (setf (bbdb-cache-mail-canon (bbdb-record-cache record))
+          (nreverse mail-canon))))
 
 (defun bbdb-hash-update (record old new)
   "Update hash for RECORD.  Remove OLD, insert NEW.
@@ -2516,18 +2538,54 @@ Both OLD and NEW are lists of values."
   (dolist (elt new)
     (bbdb-puthash elt record)))
 
-(defun bbdb-check-name (first last &optional record)
-  "Check whether the name FIRST LAST is a valid name.
-This throws an error if the name is already used by another record
-and `bbdb-allow-duplicates' is nil.  If RECORD is non-nil, FIRST and LAST
-may correspond to RECORD without raising an error."
-  ;; Are there more useful checks for names beyond checking for duplicates?
+(defun bbdb-check-name (name &optional record warn)
+  "Check whether NAME is a valid name.
+This throws an error if NAME is already used by another record
+and `bbdb-allow-duplicates' is nil.
+NAME may be a string, a cons (FIRST . LAST) or a list of name strings.
+If RECORD is non-nil, NAME may correspond to RECORD without raising an error.
+If WARN is non-nil, issue a warning instead of raising an error."
+  ;; Are there other useful checks for names beyond checking for duplicates?
   (unless bbdb-allow-duplicates
-    (let* ((name (bbdb-concat 'name-first-last first last))
-           (records (bbdb-gethash name '(fl-name lf-name aka))))
-      (if (or (and (not record) records)
-              (remq record records))
-          (error "%s is already in BBDB" name)))))
+    (cl-flet ((fun (name)
+                   (let* ((tmp (bbdb-gethash name '(fl-name lf-name aka)))
+                          (records (if record (remq record tmp) tmp)))
+                     (if records
+                         ;; Be verbose as the duplicates may be AKAs.
+                         (let ((msg (format "Name `%s' is already in BBDB: %s"
+                                            name (mapconcat #'bbdb-record-name
+                                                            records ", "))))
+                           (if (not warn)
+                               (error msg)
+                             (message msg)
+                             (sit-for 1)))))))
+      (cond ((stringp name)
+             (fun name))
+            ((and (consp name) (stringp (cdr name)))
+             (fun (bbdb-concat 'name-first-last (car name) (cdr name))))
+            (t (mapc #'fun name))))))
+
+(defun bbdb-check-mail (mail &optional record warn)
+  "Check whether MAIL is a valid mail address.
+This throws an error if MAIL is already used by another record
+and `bbdb-allow-duplicates' is nil.
+MAIL may be a mail string or a list of mail strings.
+If RECORD is non-nil, MAIL may appear in RECORD without raising an error.
+If WARN is non-nil, issue a warning instead of raising an error."
+  ;; Are there other useful checks for mail addresses beyond checking
+  ;; for duplicates?
+  (unless bbdb-allow-duplicates
+    (dolist (m (if (listp mail) mail (list mail)))
+      (let* ((tmp (bbdb-gethash (nth 1 (bbdb-decompose-bbdb-address m))
+                                '(mail)))
+             (records (if record (remq record tmp) tmp)))
+        (if records
+            (let ((msg (format "Mail `%s' is already in BBDB: %s" m
+                               (mapconcat #'bbdb-record-name records ", "))))
+              (if (not warn)
+                  (error msg)
+                (message msg)
+                (sit-for 1))))))))
 
 (defun bbdb-record-name (record)
   "Record cache function: Return the full name FIRST_LAST of RECORD.
@@ -2558,16 +2616,16 @@ Set full name in cache and hash.  Return
     (if lf-name (bbdb-remhash lf-name record)))
   (if (eq t first)
       (setq first (bbdb-record-firstname record))
-    (bbdb-record-set-firstname record first))
+    (setf (bbdb-record-firstname record) first))
   (if (eq t last)
       (setq last (bbdb-record-lastname record))
-    (bbdb-record-set-lastname record last))
+    (setf (bbdb-record-lastname record) last))
   (let ((fl-name (bbdb-concat 'name-first-last first last))
         (lf-name (bbdb-concat 'name-last-first last first))
         (cache (bbdb-record-cache record)))
     ;; Set cache of RECORD
-    (bbdb-cache-set-fl-name cache fl-name)
-    (bbdb-cache-set-lf-name cache lf-name)
+    (setf (bbdb-cache-fl-name cache) fl-name)
+    (setf (bbdb-cache-lf-name cache) lf-name)
     ;; Set hash.  For convenience, the hash contains the full name
     ;; as first-last and last-fist.
     (bbdb-puthash fl-name record)
@@ -2582,12 +2640,11 @@ Set and store it if necessary."
 
 (defun bbdb-record-set-sortkey (record)
   "Record cache function: Set and return RECORD's sortkey."
-  (bbdb-cache-set-sortkey
-   (bbdb-record-cache record)
-   (downcase
-    (bbdb-concat "" (bbdb-record-lastname record)
-                 (bbdb-record-firstname record)
-                 (bbdb-record-organization record)))))
+  (setf (bbdb-cache-sortkey (bbdb-record-cache record))
+        (downcase
+         (bbdb-concat "" (bbdb-record-lastname record)
+                      (bbdb-record-firstname record)
+                      (bbdb-record-organization record)))))
 
 (defsubst bbdb-record-marker (record)
   "Record cache function: Return the marker for RECORD."
@@ -2595,7 +2652,7 @@ Set and store it if necessary."
 
 (defsubst bbdb-record-set-marker (record marker)
   "Record cache function: Set and return RECORD's MARKER."
-  (bbdb-cache-set-marker (bbdb-record-cache record) marker))
+  (setf (bbdb-cache-marker (bbdb-record-cache record)) marker))
 
 (defsubst bbdb-record-xfield (record label)
   "For RECORD return value of xfield LABEL.
@@ -2645,16 +2702,17 @@ Return VALUE."
            (setcdr old-xfield value))
           (value ; new xfield
            (bbdb-pushnewq label bbdb-xfield-label-list)
-           (bbdb-record-set-xfields record
-                                    (append (bbdb-record-xfields record)
-                                            (list (cons label value)))))
+           (setf (bbdb-record-xfields record)
+                 (append (bbdb-record-xfields record)
+                         (list (cons label value)))))
           (old-xfield ; remove
-           (bbdb-record-set-xfields record
-                                    (delq old-xfield
-                                          (bbdb-record-xfields record))))))
+           (setf (bbdb-record-xfields record)
+                 (delq old-xfield
+                       (bbdb-record-xfields record))))))
   value)
 
 (defun bbdb-check-type (object type &optional abort extended)
+  ;; FIXME: Use `cl-typep'?
   "Return non-nil if OBJECT is of type TYPE.
 TYPE is a pseudo-code as in `bbdb-record-type'.
 If ABORT is non-nil, abort with error message if type checking fails.
@@ -2679,7 +2737,8 @@ symbols, numbers, markers, and strings."
                            (setq tmp (= type object)) t)
                           ((stringp type)
                            (setq tmp (and (stringp object)
-                                          (string= type object))) t)))
+                                          (string= type object)))
+                           t)))
                tmp)
               ((not (consp type))
                (error "Atomic type `%s' undefined" type))
@@ -2792,9 +2851,10 @@ See also `bbdb-record-set-field'."
         ;; Return xfield FIELD (e.g., `notes') or nil if FIELD is not defined.
         ((symbolp field) (bbdb-record-xfield record field))
         (t (error "Unknown field type `%s'" field))))
-(define-obsolete-function-alias 'bbdb-record-get-field 'bbdb-record-field "3.0")
+(define-obsolete-function-alias 'bbdb-record-get-field #'bbdb-record-field "3.0")
 
 (defun bbdb-record-set-field (record field value &optional merge check)
+  ;; FIXME: No caller passes the `check' argument!
   "For RECORD set FIELD to VALUE.  Return VALUE.
 If MERGE is non-nil, merge VALUE with the current value of FIELD.
 If CHECK is non-nil, check syntactically whether FIELD may take VALUE.
@@ -2824,18 +2884,19 @@ See also `bbdb-record-field'."
   (bbdb-editable)
   (if (memq field '(name-lf mail-aka mail-canon aka-all))
       (error "`%s' is not allowed as the name of a field" field))
-  (let ((record-type (cdr bbdb-record-type)))
+  ;; FIXME: Use something like `bbdb-record--make' i.s.o `vector'.
+  (let ((record-type (apply #'vector (cdr bbdb-record-type))))
     (cond ((eq field 'firstname) ; First name
            (if merge (error "Does not merge names"))
            (if check (bbdb-check-type value (bbdb-record-firstname record-type) t))
-           (bbdb-check-name value (bbdb-record-lastname record) record)
+           (bbdb-check-name (cons value (bbdb-record-lastname record)) record)
            (bbdb-record-set-name record value t))
 
           ;; Last name
           ((eq field 'lastname)
            (if merge (error "Does not merge names"))
            (if check (bbdb-check-type value (bbdb-record-lastname record-type) t))
-           (bbdb-check-name (bbdb-record-firstname record) value record)
+           (bbdb-check-name (cons (bbdb-record-firstname record) value) record)
            (bbdb-record-set-name record t value))
 
           ;; Name
@@ -2844,9 +2905,8 @@ See also `bbdb-record-field'."
            (if (stringp value)
                (setq value (bbdb-divide-name value))
              (if check (bbdb-check-type value '(cons string string) t)))
-           (let ((fn (car value)) (ln (cdr value)))
-             (bbdb-check-name fn ln record)
-             (bbdb-record-set-name record fn ln)))
+           (bbdb-check-name value record)
+           (bbdb-record-set-name record (car value) (cdr value)))
 
           ;; Affix
           ((eq field 'affix)
@@ -2854,7 +2914,7 @@ See also `bbdb-record-field'."
                                                    value 'bbdb-string=)))
            (if check (bbdb-check-type value (bbdb-record-affix record-type) t))
            (setq value (bbdb-list-strings value))
-           (bbdb-record-set-affix record value))
+           (setf (bbdb-record-affix record) value))
 
           ;; Organization
           ((eq field 'organization)
@@ -2865,7 +2925,7 @@ See also `bbdb-record-field'."
            (bbdb-hash-update record (bbdb-record-organization record) value)
            (dolist (organization value)
              (bbdb-pushnew organization bbdb-organization-list))
-           (bbdb-record-set-organization record value))
+           (setf (bbdb-record-organization record) value))
 
           ;; AKA
           ((eq field 'aka)
@@ -2873,13 +2933,9 @@ See also `bbdb-record-field'."
                                                    value 'bbdb-string=)))
            (if check (bbdb-check-type value (bbdb-record-aka record-type) t))
            (setq value (bbdb-list-strings value))
-           (unless bbdb-allow-duplicates
-             (dolist (aka value)
-               (let ((old (remq record (bbdb-gethash aka '(fl-name lf-name aka)))))
-                 (if old (error "Alternate name address \"%s\" is used by \"%s\""
-                                aka (mapconcat 'bbdb-record-name old ", "))))))
+           (bbdb-check-name value record)
            (bbdb-hash-update record (bbdb-record-aka record) value)
-           (bbdb-record-set-aka record value))
+           (setf (bbdb-record-aka record) value))
 
           ;; Mail
           ((eq field 'mail)
@@ -2887,16 +2943,12 @@ See also `bbdb-record-field'."
                                                    value 'bbdb-string=)))
            (if check (bbdb-check-type value (bbdb-record-mail record-type) t))
            (setq value (bbdb-list-strings value))
-           (unless bbdb-allow-duplicates
-             (dolist (mail value)
-               (let ((old (remq record (bbdb-gethash mail '(mail)))))
-                 (if old (error "Mail address \"%s\" is used by \"%s\""
-                                mail (mapconcat 'bbdb-record-name old ", "))))))
+           (bbdb-check-mail value record)
            (dolist (aka (bbdb-record-mail-aka record))
              (bbdb-remhash aka record))
            (dolist (mail (bbdb-record-mail-canon record))
              (bbdb-remhash mail record))
-           (bbdb-record-set-mail record value)
+           (setf (bbdb-record-mail record) value)
            (bbdb-puthash-mail record))
 
           ;; Phone
@@ -2906,7 +2958,7 @@ See also `bbdb-record-field'."
            (if check (bbdb-check-type value (bbdb-record-phone record-type) t))
            (dolist (phone value)
              (bbdb-pushnew (bbdb-phone-label phone) bbdb-phone-label-list))
-           (bbdb-record-set-phone record value))
+           (setf (bbdb-record-phone record) value))
 
           ;; Address
           ((eq field 'address)
@@ -2921,7 +2973,7 @@ See also `bbdb-record-field'."
              (bbdb-pushnewt (bbdb-address-state address) bbdb-state-list)
              (bbdb-pushnewt (bbdb-address-postcode address) bbdb-postcode-list)
              (bbdb-pushnewt (bbdb-address-country address) bbdb-country-list))
-           (bbdb-record-set-address record value))
+           (setf (bbdb-record-address record) value))
 
           ;; uuid
           ((eq field 'uuid)
@@ -2930,20 +2982,20 @@ See also `bbdb-record-field'."
            (let ((old-uuid (bbdb-record-uuid record)))
              (unless (string= old-uuid value)
                (remhash old-uuid bbdb-uuid-table)
-               (bbdb-record-set-uuid record value)
+               (setf (bbdb-record-uuid record) value)
                (puthash value record bbdb-uuid-table))))
 
           ;; creation-date
           ((eq field 'creation-date)
            ;; MERGE not meaningful
            (if check (bbdb-check-type value (bbdb-record-creation-date record-type) t))
-           (bbdb-record-set-creation-date record value))
+           (setf (bbdb-record-creation-date record) value))
 
           ;; timestamp
           ((eq field 'timestamp)
            ;; MERGE not meaningful
            (if check (bbdb-check-type value (bbdb-record-timestamp record-type) t))
-           (bbdb-record-set-timestamp record value))
+           (setf (bbdb-record-timestamp record) value))
 
           ;; all xfields
           ((eq field 'xfields)
@@ -2963,7 +3015,7 @@ See also `bbdb-record-field'."
                (when (and (cdr xfield) (not (equal "" (cdr xfield))))
                  (push xfield new-xfields)
                  (bbdb-pushnewq (car xfield) bbdb-xfield-label-list)))
-             (bbdb-record-set-xfields record (nreverse new-xfields))))
+             (setf (bbdb-record-xfields record) (nreverse new-xfields))))
 
           ;; Single xfield
           ((symbolp field)
@@ -3073,7 +3125,7 @@ Do this only if `bbdb-check-postcode' is
     string))
 
 (defun bbdb-phone-string (phone)
-  "Massage string PHONE into a standard format."
+  "Massage vector PHONE into a standard format."
   ;; Phone numbers should come in two forms:
   (if (= 2 (length phone))
       ;; (1) ["where" "the number"]
@@ -3161,7 +3213,7 @@ copy it to `bbdb-file'."
     (unless (assq 'bbdb-records (buffer-local-variables))
       ;; We are reading / reverting `bbdb-buffer'.
       (set (make-local-variable 'revert-buffer-function)
-           'bbdb-revert-buffer)
+           #'bbdb-revert-buffer)
 
       (setq buffer-file-coding-system bbdb-file-coding-system
             buffer-read-only bbdb-read-only
@@ -3171,10 +3223,10 @@ copy it to `bbdb-file'."
       ;; `bbdb-before-save-hook' and `bbdb-after-save-hook' are user variables.
       ;; To avoid confusion, we hide the hook functions `bbdb-before-save'
       ;; and `bbdb-after-save' from the user as these are essential for BBDB.
-      (dolist (hook (cons 'bbdb-before-save bbdb-before-save-hook))
-        (add-hook 'before-save-hook hook nil t))
-      (dolist (hook (cons 'bbdb-after-save bbdb-after-save-hook))
-        (add-hook 'after-save-hook hook nil t))
+      (dolist (fun (cons #'bbdb-before-save bbdb-before-save-hook))
+        (add-hook 'before-save-hook fun nil t))
+      (dolist (fun (cons #'bbdb-after-save bbdb-after-save-hook))
+        (add-hook 'after-save-hook fun nil t))
 
       (clrhash bbdb-hashtable)
       (clrhash bbdb-uuid-table)
@@ -3234,7 +3286,10 @@ BBDB is not editable if it is read-only.
   t)
 
 ;;;###autoload
-(defsubst bbdb-records ()
+(defun bbdb-records ()
+  ;; We used to define it as a `defsubst' but those are treated differently
+  ;; by the ;;;###autoload machinery: calling the function didn't load
+  ;; bbdb.el, so the call to bbdb-buffer then failed :-(
   "Return a list of all BBDB records; read in and parse the db if necessary.
 This function also notices if the corresponding file on disk has been modified."
   (with-current-buffer (bbdb-buffer)
@@ -3371,9 +3426,9 @@ If `bbdb-file' uses an outdated format,
               (unless (looking-at "\\[")
                 (error "BBDB corrupted: junk between records at %s" (point))))
 
-            (bbdb-cache-set-marker
-             (bbdb-record-set-cache record (make-vector bbdb-cache-length nil))
-             (point-marker))
+            (setf (bbdb-cache-marker
+                   (setf (bbdb-record-cache record) (bbdb-cache--make)))
+                  (point-marker))
             (forward-line 1)
 
             ;; Every record must have a unique uuid in `bbdb-uuid-table'.
@@ -3382,46 +3437,10 @@ If `bbdb-file' uses an outdated format,
                 ;; We are just loading BBDB, so we are not yet ready
                 ;; for sophisticated solutions.
                 (error "Duplicate UUID %s" (bbdb-record-uuid record)))
-
-            ;; Set the completion lists
-            (dolist (phone (bbdb-record-phone record))
-              (bbdb-pushnew (bbdb-phone-label phone) bbdb-phone-label-list))
-            (dolist (address (bbdb-record-address record))
-              (bbdb-pushnew (bbdb-address-label address) bbdb-address-label-list)
-              (mapc (lambda (street) (bbdb-pushnewt street bbdb-street-list))
-                    (bbdb-address-streets address))
-              (bbdb-pushnewt (bbdb-address-city address) bbdb-city-list)
-              (bbdb-pushnewt (bbdb-address-state address) bbdb-state-list)
-              (bbdb-pushnewt (bbdb-address-postcode address) bbdb-postcode-list)
-              (bbdb-pushnewt (bbdb-address-country address) bbdb-country-list))
-            (dolist (xfield (bbdb-record-xfields record))
-              (bbdb-pushnewq (car xfield) bbdb-xfield-label-list))
-            (dolist (organization (bbdb-record-organization record))
-              (bbdb-pushnew organization bbdb-organization-list))
-
-            (let ((name (bbdb-concat 'name-first-last
-                                     (bbdb-record-firstname record)
-                                     (bbdb-record-lastname record))))
-              (when (and (not bbdb-allow-duplicates)
-                         (bbdb-gethash name '(fl-name aka)))
-                ;; This does not check for duplicate mail fields.
-                ;; Yet under normal circumstances, this should really
-                ;; not be necessary each time BBDB is loaded as BBDB checks
-                ;; whether creating a new record or modifying an existing one
-                ;; results in duplicates.
-                ;; Alternatively, you can use `bbdb-search-duplicates'.
-                (message "Duplicate BBDB record encountered: %s" name)
-                (sit-for 1)))
-
-            ;; If `bbdb-allow-duplicates' is non-nil, we allow that two records
-            ;; (with different uuids) refer to the same person (same name etc.).
-            ;; Such duplicate records are always hashed.
-            ;; Otherwise, an unhashed record would not be available for things
-            ;; like completion (and we would not know which record to keeep
-            ;; and which one to hide).  We trust the user she knows what
-            ;; she wants if she keeps duplicate records in the database though
-            ;; `bbdb-allow-duplicates' is nil.
-            (bbdb-hash-record record))
+            ;; With `bbdb-allow-duplicates' nil, BBDB would become unusable
+            ;; if duplicates threw an error upon loading BBDB.  Thus we only
+            ;; issue a message.
+            (bbdb-register-record record t))
 
           ;; Note that `bbdb-xfield-label-list' serves two purposes:
           ;;  - check whether an xfield is new to BBDB
@@ -3450,6 +3469,52 @@ If `bbdb-file' uses an outdated format,
           (unless bbdb-silent (message "Parsing BBDB file `%s'...done" file))
           bbdb-records)))))
 
+(defun bbdb-register-record (record &optional warn)
+  "Register RECORD with BBDB.
+This performs the registration (including hash tables and cache) required both
+for records that are loaded from the database and for new records added to BBDB.
+If `bbdb-allow-duplicates' is nil, this throws an error if the name,
+an aka or mail address of RECORD is already in BBDB.  If WARN is non-nil,
+issue a warning instead.
+Do not call this function directly.  Call instead `bbdb-change-record'."
+  (bbdb-check-name (cons (bbdb-record-firstname record)
+                         (bbdb-record-lastname record))
+                   record warn)
+  (bbdb-check-mail (bbdb-record-mail record) record warn)
+
+  ;; If `bbdb-allow-duplicates' is non-nil, we allow that two records
+  ;; (with different uuids) refer to the same person (same name etc.).
+  ;; Such duplicate records are always hashed.
+  ;; Otherwise, an unhashed record would not be available for things
+  ;; like completion (and we would not know which record to keeep
+  ;; and which one to hide).  We trust the user she knows what
+  ;; she wants if she keeps duplicate records in the database though
+  ;; `bbdb-allow-duplicates' is nil.
+  (bbdb-puthash (bbdb-record-name record) record)
+  (bbdb-puthash (bbdb-record-name-lf record) record)
+  (dolist (organization (bbdb-record-organization record))
+    (bbdb-puthash organization record))
+  (dolist (aka (bbdb-record-aka record))
+    (bbdb-puthash aka record))
+  (bbdb-puthash-mail record)
+  (puthash (bbdb-record-uuid record) record bbdb-uuid-table)
+
+  ;; Update the completion lists
+  (dolist (phone (bbdb-record-phone record))
+    (bbdb-pushnew (bbdb-phone-label phone) bbdb-phone-label-list))
+  (dolist (address (bbdb-record-address record))
+    (bbdb-pushnew (bbdb-address-label address) bbdb-address-label-list)
+    (mapc (lambda (street) (bbdb-pushnewt street bbdb-street-list))
+          (bbdb-address-streets address))
+    (bbdb-pushnewt (bbdb-address-city address) bbdb-city-list)
+    (bbdb-pushnewt (bbdb-address-state address) bbdb-state-list)
+    (bbdb-pushnewt (bbdb-address-postcode address) bbdb-postcode-list)
+    (bbdb-pushnewt (bbdb-address-country address) bbdb-country-list))
+  (dolist (xfield (bbdb-record-xfields record))
+    (bbdb-pushnewq (car xfield) bbdb-xfield-label-list))
+  (dolist (organization (bbdb-record-organization record))
+    (bbdb-pushnew organization bbdb-organization-list)))
+
 (defun bbdb-before-save ()
   "Run before saving `bbdb-file' as buffer-local part of `before-save-hook'."
   (when (and bbdb-file-remote
@@ -3472,9 +3537,9 @@ If `bbdb-file' uses an outdated format,
   "Update the database after a change of RECORD.
 Return RECORD if RECORD got changed compared with the database,
 return nil otherwise.
-Hash RECORD if it is new.  If RECORD is not new, it is the the caller's
-responsibility to update the hashtables for RECORD.  (Up-to-date hashtables are
-ensured if the fields are modified by calling `bbdb-record-set-field'.)
+Register RECORD if it is new.  If RECORD is not new, it is the caller's
+responsibility to update this information for RECORD.  (This is ensured
+if the fields of RECORD are modified by calling `bbdb-record-set-field'.)
 Redisplay RECORD if it is not new.
 
 Args IGNORED are ignored and their use is discouraged.
@@ -3508,12 +3573,12 @@ They are present only for backward compa
                                          bbdb-end-marker))))
                                 (let ((cache (bbdb-record-cache record))
                                       (inhibit-quit t))
-                                  (bbdb-record-set-cache record nil)
+                                  (setf (bbdb-record-cache record) nil)
                                   (prog1 (bbdb-with-print-loadably
                                            (prin1-to-string record))
-                                    (bbdb-record-set-cache record cache))))))
-          (bbdb-record-set-timestamp
-           record (format-time-string bbdb-time-stamp-format nil t))
+                                    (setf (bbdb-record-cache record) cache))))))
+          (setf (bbdb-record-timestamp record)
+                (format-time-string bbdb-time-stamp-format nil t))
           (run-hook-with-args 'bbdb-change-hook record)
           (let ((sort (not (equal (bbdb-cache-sortkey (bbdb-record-cache record))
                                   (bbdb-record-set-sortkey record)))))
@@ -3531,27 +3596,26 @@ They are present only for backward compa
 
       ;; Record is new and not yet in BBDB.
       (unless (bbdb-record-cache record)
-        (bbdb-record-set-cache record (make-vector bbdb-cache-length nil)))
+        (setf (bbdb-record-cache record) (bbdb-cache--make)))
       (unless (bbdb-record-uuid record)
-        (bbdb-record-set-uuid record (bbdb-uuid)))
+        (setf (bbdb-record-uuid record) (bbdb-uuid)))
       (unless (bbdb-record-creation-date record)
-        (bbdb-record-set-creation-date
-         record (format-time-string bbdb-time-stamp-format nil t))
+        (setf (bbdb-record-creation-date record)
+              (format-time-string bbdb-time-stamp-format nil t))
         (run-hook-with-args 'bbdb-create-hook record))
 
       (let ((old-record (gethash (bbdb-record-uuid record) bbdb-uuid-table)))
         (if old-record
             ;; RECORD is really OLD-RECORD.  Merge and return OLD-RECORD.
-            (if bbdb-merge-records-function
-                (funcall bbdb-merge-records-function record old-record)
-              (bbdb-merge-records record old-record))
+            (funcall (or bbdb-merge-records-function #'bbdb-merge-records)
+                     record old-record)
 
           ;; RECORD is really new.
-          (bbdb-record-set-timestamp
-           record (format-time-string bbdb-time-stamp-format nil t))
+          (setf (bbdb-record-timestamp record)
+                (format-time-string bbdb-time-stamp-format nil t))
           (run-hook-with-args 'bbdb-change-hook record)
+          (bbdb-register-record record) ; Call this earlier?
           (bbdb-insert-record-internal record)
-          (bbdb-hash-record record)
           (bbdb-pushnewq record bbdb-changed-records)
           (run-hook-with-args 'bbdb-after-change-hook record)
           record)))))
@@ -3618,11 +3682,11 @@ that calls the hooks, too."
         (if (and (/= point bbdb-end-marker)
                  (not (looking-at "^\\[")))
             (error "Not inserting before a record (%s)" point)))
-      (bbdb-record-set-cache record nil)
+      (setf (bbdb-record-cache record) nil)
       (insert-before-markers
        (bbdb-with-print-loadably (prin1-to-string record)) "\n")
       (set-marker (bbdb-cache-marker cache) point)
-      (bbdb-record-set-cache record cache))
+      (setf (bbdb-record-cache record) cache))
     record))
 
 (defun bbdb-overwrite-record-internal (record)
@@ -3644,13 +3708,13 @@ that calls the hooks, too."
                  (not (looking-at "\\[")))
             (error "Not inserting before a record (%s)" (point))))
 
-      (bbdb-record-set-cache record nil)
+      (setf (bbdb-record-cache record) nil)
       (insert (bbdb-with-print-loadably (prin1-to-string record)) "\n")
       (delete-region (point)
                      (if (cdr tail)
                          (bbdb-record-marker (car (cdr tail)))
                        bbdb-end-marker))
-      (bbdb-record-set-cache record cache)
+      (setf (bbdb-record-cache record) cache)
 
       (bbdb-debug
         (if (<= (if (cdr tail)
@@ -3701,7 +3765,7 @@ This function is a possible formatting f
   (let ((country (bbdb-address-country address))
         (streets (bbdb-address-streets address)))
     (concat (if streets
-                (concat (mapconcat 'identity streets "\n") "\n"))
+                (concat (mapconcat #'identity streets "\n") "\n"))
             (bbdb-concat ", " (bbdb-address-city address)
                          (bbdb-concat " " (bbdb-address-state address)
                                       (bbdb-address-postcode address)))
@@ -4043,7 +4107,7 @@ Move point to the end of the inserted re
         (omit-list  (bbdb-layout-get-option layout 'omit)) ; omitted fields
         (order-list (bbdb-layout-get-option layout 'order)); requested field order
         (all-fields (append '(phone address mail aka) ; default field order
-                            (mapcar 'car (bbdb-record-xfields record))
+                            (mapcar #'car (bbdb-record-xfields record))
                             '(uuid creation-date timestamp)))
         (beg (point))
         format-function field-list)
@@ -4123,7 +4187,7 @@ SELECT and HORIZ-P have the same meaning
       ;; If we are appending RECORDS to the ones already displayed,
       ;; then first remove any duplicates, and then sort them.
       (if append
-          (let ((old-rec (mapcar 'car bbdb-records)))
+          (let ((old-rec (mapcar #'car bbdb-records)))
             (dolist (record records)
               (unless (memq (car record) old-rec)
                 (push record bbdb-records)))
@@ -4239,14 +4303,14 @@ If DELETE-P is non-nil RECORD is removed
   (dolist (buffer (buffer-list))
     (with-current-buffer buffer
       (if (and (eq major-mode 'bbdb-mode)
-               (memq record (mapcar 'car bbdb-records)))
+               (memq record (mapcar #'car bbdb-records)))
           (let ((window (get-buffer-window bbdb-buffer-name)))
             (if window
                 (with-selected-window window
                   (bbdb-redisplay-record record sort delete-p))
               (bbdb-redisplay-record record sort delete-p)))))))
 (define-obsolete-function-alias 'bbdb-maybe-update-display
-  'bbdb-redisplay-record-globally "3.0")
+  #'bbdb-redisplay-record-globally "3.0")
 
 
 ;;; window configuration hackery
@@ -4419,13 +4483,15 @@ Important variables:
 There are numerous hooks.  M-x apropos ^bbdb.*hook RET
 
 \\{bbdb-mode-map}"
-  (setq truncate-lines t
+  (setq buffer-undo-list t ;; No need to keep an undo list in *BBDB* buffer
+        truncate-lines t
         default-directory (file-name-directory bbdb-file)
         mode-line-buffer-identification
         (list 24 (buffer-name) "  "
               '(:eval (format "%d/%d/%d"
                               (1+ (or (get-text-property
-                                       (point) 'bbdb-record-number) -1))
+                                       (point) 'bbdb-record-number)
+                                      -1))
                               (length bbdb-records)
                               ;; This code gets called a lot.
                               ;; So we keep it as simple as possible.
@@ -4444,8 +4510,9 @@ There are numerous hooks.  M-x apropos ^
   ;; `bbdb-revert-buffer' acts on `bbdb-buffer'.  Yet this command is usually
   ;; called from the *BBDB* buffer.
   (set (make-local-variable 'revert-buffer-function)
-       'bbdb-revert-buffer)
-  (add-hook 'post-command-hook 'force-mode-line-update nil t))
+       #'bbdb-revert-buffer)
+  ;; FIXME: Really?  Why?
+  (add-hook 'post-command-hook #'force-mode-line-update nil t))
 
 
 
@@ -4675,9 +4742,9 @@ however, after having used other program
             ;; and update the cache's marker.
             (setq cache (bbdb-record-cache record))
             (set-marker (bbdb-cache-marker cache) (point))
-            (bbdb-record-set-cache record nil)
+            (setf (bbdb-record-cache record) nil)
             (bbdb-with-print-loadably (prin1 record buf))
-            (bbdb-record-set-cache record cache)
+            (setf (bbdb-record-cache record) cache)
             (insert ?\n)))
         (dolist (buffer (buffer-list))
           (with-current-buffer buffer
@@ -4720,11 +4787,13 @@ See also `bbdb-mua-auto-update-init'.  T
 as this allows one to initialize the auto update feature for some MUAs only,
 for example only for outgoing messages."
   (dolist (mua muas)
-    (let ((init (assq mua bbdb-init-forms)))
-      (if init
-          ;; Should we make sure that each insinuation happens only once?
-          (eval (cadr init))
-        (bbdb-warn "Do not know how to insinuate `%s'" mua))))
+    (let ((init (cadr (assq mua bbdb-init-functions))))
+      ;; Should we make sure that each insinuation happens only once?
+      (cond
+       ((functionp init) (funcall init))
+       (init (eval init t))             ;Old-style "form".
+       (t
+        (bbdb-warn "Do not know how to insinuate `%s'" mua)))))
   (run-hooks 'bbdb-initialize-hook))
 
 
