summaryrefslogtreecommitdiff
path: root/lisp/bbdb-sc.el
blob: 6fe04ae48d6c297ae2943c95cde3f50744822770 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
;;; -*- Mode:Emacs-Lisp -*-

;;; This file is an addition to the Insidious Big Brother Database
;;; (aka BBDB), copyright (c) 1991, 1992 Jamie Zawinski
;;; <jwz@netscape.com>.
;;;
;;; The Insidious Big Brother Database is free software; you can redistribute
;;; it and/or modify it under the terms of the GNU General Public License as
;;; published by the Free Software Foundation; either version 1, or (at your
;;; option) any later version.
;;;
;;; BBDB is distributed in the hope that it will be useful, but WITHOUT ANY
;;; WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
;;; FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
;;; details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with GNU Emacs; see the file COPYING.  If not, write to
;;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.


;;; This file was written by Martin Sjolin <marsj@ida.liu.se>
;;; based the original code by Tom Tromey <tromey@busco.lanl.gov>.
;;;
;;; Thanks to Richard Stanton <stanton@haas.berkeley.edu> for ideas
;;; for improvements and to Michael D. Carney  <carney@ltx-tr.com>
;;; for testing and feedback.

;;; This file adds the ability to define attributions for Supercite in
;;; a BBDB, enables you to retrieve your standard attribution from
;;; BBDB. If the from header in the mail to which you are replying
;;; only contains the e-mail address, the personal name is lookup in
;;; BBDB. You need Supercite to make this code work. The attribution
;;; os is stored under the key `attribution' (unless you've changed
;;; bbdb/sc-attribution-field).

;;; To use enable this code you will have to the "sc-consult" to your
;;; sc-preferred-attribution-list. This file sets variable if it is not
;;; set and isues an warning message if "sc-consult" is not included.
;;;
;;;   (setq sc-preferred-attribution-list
;;;     '("sc-lastchoice" "x-attribution" "sc-consult"
;;;       "initials" "firstname" "lastname"))
;;;
;;;
;;; We also set the sc-attrib-selection-list below if is not bound, if
;;; you have your own special sc-attrib-selection-list, please add
;;; an expression as below:
;;;
;;;   (setq sc-attrib-selection-list
;;;        '(("sc-from-address" ((".*" . (bbdb/sc-consult-attr
;;;                    (sc-mail-field "sc-from-address")))))))
;;;
;;; And finally we set the sc-mail-glom-frame to enable the
;;; fetching of the name of person when there is only an e-mail
;;; address in the original mail:
;;;
;;;  (setq sc-mail-glom-frame
;;;    '((begin                        (setq sc-mail-headers-start (point)))
;;;      ("^x-attribution:[ \t]+.*$"   (sc-mail-fetch-field t) nil t)
;;;      ("^\\S +:.*$"                 (sc-mail-fetch-field) nil t)
;;;      ("^$"                         (progn (bbdb/sc-default)
;;;                      (list 'abort '(step . 0))))
;;;      ("^[ \t]+"                    (sc-mail-append-field))
;;;      (sc-mail-warn-if-non-rfc822-p (sc-mail-error-in-mail-field))
;;;      (end                          (setq sc-mail-headers-end (point)))))
;;;
;;;

;;;
;;;

;;; packages
(require 'bbdb)
(require 'supercite)

;;; User variable(s)
(defcustom bbdb/sc-replace-attr-p t
 "t if you like to create a new BBDB entry when
entering a non-default attribution, 'ask if the user
should be asked before creation and NIL if we never create a new entry."
 :group 'bbdb-utilities-supercite
 :type '(choice (const "Create a new BBDB entry" t)
        (const "Confirm new record creation" ask)
        (const "Don't create a new entry" nil)))

(defcustom bbdb/sc-attribution-field 'attribution
  "The BBDB field used for Supercite attribution information."
  :group 'bbdb-utilities-supercite
  :type '(symbol :tag "Field name"))

;;; Code starts
(defcustom bbdb/sc-last-attribution ""
 "Default attribution return by the SuperCite citation engine,
used to compare against citation selected by the user."
 :group 'bbdb-utilities-supercite
 :type '(string :tag "Default citation" ""))

(defun bbdb/sc-consult-attr (from)
  "Extract citing information from BBDB using sc-consult where
FROM is user e-mail address to look for in BBDB."
  ;; if logged in user sent this, use recipients.
  (let ((from (if (or (null from)
                      (string-match (bbdb-user-mail-names) from))
                  (car (cdr (mail-extract-address-components
                             (or (sc-mail-field "to") from))))
                from)))
    (if from
        (let ((record (bbdb-search-simple nil from)))
          (and record
               (bbdb-record-getprop record bbdb/sc-attribution-field))))))

(defun bbdb/sc-set-attr ()
  "Add attribute to BBDB."
  (let ((from (sc-mail-field "from"))
    (address (sc-mail-field "sc-from-address"))
    (attr (sc-mail-field "sc-attribution")))
    (if (and from attr bbdb/sc-replace-attr-p
        (not (string-equal attr bbdb/sc-last-attribution))
        (not (string-match (bbdb-user-mail-names) address)))
    (let* ((bbdb-notice-hook nil)
           ;; avoid noticing any headers in the reply message
           (record (bbdb-annotate-message-sender
               from t
               (bbdb-invoke-hook-for-value
            bbdb/mail-auto-create-p) t)))
      (if record
          (let ((old (bbdb-record-getprop record 'attribution)))
        ;; ignore if we have an value and same value
        (if (and (not (and old (string-equal old attr)))
             (or (not (eq bbdb/sc-replace-attr-p 'ask))
                 (y-or-n-p (concat "Change attribution " attr))))
            (progn (bbdb-record-putprop record
                        bbdb/sc-attribution-field attr)
               (bbdb-change-record record nil)))))))))

;;; this is marked as autoload since someone managed to trip up Gnus
;;; with it. I'm not clear this needs fixing, as you should be calling
;;; bbdb-insinuate-sc if you're using supercite/BBDB. However.
;;;###autoload
(defun bbdb/sc-default ()
  "If the current \"from\" field in `sc-mail-info' alist
contains only an e-mail address, lookup e-mail address in
BBDB, and prepend a new \"from\" field to `sc-mail-info'."
  (let* ((from   (sc-mail-field "from"))
     (pair   (and from (mail-extract-address-components from))))
    (if (and pair (not (car pair)))
    (let* ((record (bbdb-search-simple nil (car (cdr pair))))
           (name   (and record (bbdb-record-name record))))
      (if name
          (setq sc-mail-info
            (cons (cons "from"
                (format "%s (%s)" (car (cdr pair)) name))
              sc-mail-info)))))))

;;; setup the default setting of the variables
(defun bbdb/sc-setup-variables ()
  "Set up the various Supercite variables for the BBDB.
`sc-preferred-attribution-list', `sc-attrib-selection-list', and
`sc-mail-glom-frame' are set, but only if they have not previously
been defined.  It is strongly suggested that you not call this
function directly, but that you use this function (specifically the
settings contained herein) as an example.  In other words, set these
variables yourself, either in your Emacs configuration file or using
Custom."

  ;; check for sc-consult in sc-preferred-attribution-list
  (if (boundp 'sc-preferred-attribution-list)
      (or (member '"sc-consult" sc-preferred-attribution-list)
      (bbdb-warn (concat "\"sc-consult\" not included in "
                 "sc-preferred-attribution-list.  Attributions cannot"
                 "be gathered from the BBDB without \"sc-consult\""
                 "in sc-preferred-attribution-list")))
    (defvar sc-preferred-attribution-list
      '("sc-lastchoice" "x-attribution" "sc-consult"
        "initials" "firstname" "lastname")))

  ;; check sc-attrib-selection-list
  (defvar sc-attrib-selection-list
    '(("sc-from-address"
       ((".*" . (bbdb/sc-consult-attr
         (sc-mail-field "sc-from-address")))))))

  ;; set sc-mail-glom-frame
  (defvar sc-mail-glom-frame
    '((begin                        (setq sc-mail-headers-start (point)))
      ("^x-attribution:[ \t]+.*$"   (sc-mail-fetch-field t) nil t)
      ("^\\S +:.*$"                 (sc-mail-fetch-field) nil t)
      ("^$"                         (progn (bbdb/sc-default)
                       (list 'abort '(step . 0))))
      ("^[ \t]+"                    (sc-mail-append-field))
      (sc-mail-warn-if-non-rfc822-p (sc-mail-error-in-mail-field))
      (end                          (setq sc-mail-headers-end (point))))))

;; insert our hooks - call me from your Emacs initialization file
(defvar attribution) ;; dammit, supercite!
;;;###autoload
(defun bbdb-insinuate-sc ()
  "Call this function to hook BBDB into Supercite."

  (add-hook 'sc-post-hook 'bbdb/sc-set-attr)
  (add-hook 'sc-attribs-postselect-hook
         (function (lambda()
                 (setq bbdb/sc-last-attribution
                   (if sc-downcase-p
                       (downcase attribution) attribution))))))

(provide 'bbdb-sc)
;;; end of bbdb-sc.el