~ubuntu-branches/ubuntu/karmic/emacs-snapshot/karmic

« back to all changes in this revision

Viewing changes to lisp/mail/rmailsum.el

  • Committer: Bazaar Package Importer
  • Author(s): Reinhard Tartler
  • Date: 2009-04-05 09:14:30 UTC
  • mto: This revision was merged to the branch mainline in revision 34.
  • Revision ID: james.westby@ubuntu.com-20090405091430-nw07lynn2arotjbe
Tags: upstream-20090320
ImportĀ upstreamĀ versionĀ 20090320

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
;;; rmailsum.el --- make summary buffers for the mail reader
2
2
 
3
3
;; Copyright (C) 1985, 1993, 1994, 1995, 1996, 2000, 2001, 2002, 2003,
4
 
;;   2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
 
4
;;   2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
5
5
 
6
6
;; Maintainer: FSF
7
7
;; Keywords: mail
29
29
 
30
30
;;; Code:
31
31
 
32
 
(defvar msgnum)
33
 
 
34
 
;; For rmail-select-summary
 
32
;; For rmail-select-summary.
35
33
(require 'rmail)
36
34
 
37
 
;;;###autoload
38
35
(defcustom rmail-summary-scroll-between-messages t
39
 
  "*Non-nil means Rmail summary scroll commands move between messages."
 
36
  "Non-nil means Rmail summary scroll commands move between messages.
 
37
That is, after `rmail-summary-scroll-msg-up' reaches the end of a
 
38
message, it moves to the next message; and similarly for
 
39
`rmail-summary-scroll-msg-down'."
40
40
  :type 'boolean
41
41
  :group 'rmail-summary)
42
42
 
43
 
;;;###autoload
 
43
;; FIXME could do with a :set function that regenerates the summary
 
44
;; and updates rmail-summary-vector.
44
45
(defcustom rmail-summary-line-count-flag t
45
 
  "*Non-nil means Rmail summary should show the number of lines in each message."
 
46
  "Non-nil means Rmail summary should show the number of lines in each message.
 
47
Setting this option to nil might speed up the generation of summaries."
46
48
  :type 'boolean
47
49
  :group 'rmail-summary)
48
50
 
54
56
    ("{ \\([^\n}]+\\) }" 1 font-lock-comment-face))             ; Labels.
55
57
  "Additional expressions to highlight in Rmail Summary mode.")
56
58
 
57
 
(defvar rmail-summary-redo
 
59
(defvar rmail-summary-redo nil
58
60
  "(FUNCTION . ARGS) to regenerate this Rmail summary buffer.")
59
61
 
60
 
(defvar rmail-summary-overlay nil)
 
62
(defvar rmail-summary-overlay nil
 
63
  "Overlay used to highlight the current message in the Rmail summary.")
61
64
(put 'rmail-summary-overlay 'permanent-local t)
62
65
 
63
 
(defvar rmail-summary-mode-map nil)
 
66
(defvar rmail-summary-mode-map nil
 
67
  "Keymap used in Rmail summary mode.")
64
68
 
65
69
;; Entry points for making a summary buffer.
66
70
 
74
78
(defun rmail-summary ()
75
79
  "Display a summary of all messages, one line per message."
76
80
  (interactive)
77
 
  (rmail-new-summary "All" '(rmail-summary) nil))
 
81
  (rmail-new-summary "All" '(rmail-summary) nil)
 
82
  (unless (get-buffer-window rmail-buffer)
 
83
    (rmail-summary-beginning-of-message)))
78
84
 
79
85
;;;###autoload
80
86
(defun rmail-summary-by-labels (labels)
88
94
  (rmail-new-summary (concat "labels " labels)
89
95
                     (list 'rmail-summary-by-labels labels)
90
96
                     'rmail-message-labels-p
91
 
                     (concat ", \\(" (mail-comma-list-regexp labels) "\\),")))
 
97
                     (concat " \\("
 
98
                             (mail-comma-list-regexp labels)
 
99
                             "\\)\\(,\\|\\'\\)")))
92
100
 
 
101
;; FIXME "a string of regexps separated by commas" makes no sense because:
 
102
;;  i) it's pointless (you can just use \\|)
 
103
;; ii) it's broken (you can't specify a literal comma)
 
104
;; rmail-summary-by-topic and rmail-summary-by-senders have the same issue.
93
105
;;;###autoload
94
106
(defun rmail-summary-by-recipients (recipients &optional primary-only)
95
107
  "Display a summary of all messages with the given RECIPIENTS.
104
116
   'rmail-message-recipients-p
105
117
   (mail-comma-list-regexp recipients) primary-only))
106
118
 
 
119
(defun rmail-message-recipients-p (msg recipients &optional primary-only)
 
120
  (rmail-apply-in-message msg 'rmail-message-recipients-p-1
 
121
                          recipients primary-only))
 
122
 
 
123
(defun rmail-message-recipients-p-1 (recipients &optional primary-only)
 
124
  ;; mail-fetch-field does not care where it starts from.
 
125
  (narrow-to-region (point) (progn (search-forward "\n\n") (point)))
 
126
  (or (string-match recipients (or (mail-fetch-field "To") ""))
 
127
      (string-match recipients (or (mail-fetch-field "From") ""))
 
128
      (if (not primary-only)
 
129
          (string-match recipients (or (mail-fetch-field "Cc") "")))))
 
130
 
 
131
;; FIXME I find this a non-obvious name for what this function does.
 
132
;; Also, the optional WHOLE-MESSAGE argument of r-s-by-topic would
 
133
;; seem more natural here.
107
134
;;;###autoload
108
135
(defun rmail-summary-by-regexp (regexp)
109
136
  "Display a summary of all messages according to regexp REGEXP.
110
137
If the regular expression is found in the header of the message
111
138
\(including in the date and other lines, as well as the subject line),
112
 
Emacs will list the header line in the RMAIL-summary."
 
139
Emacs will list the message in the summary."
113
140
  (interactive "sRegexp to summarize by: ")
114
141
  (if (string= regexp "")
115
142
      (setq regexp (or rmail-last-regexp
120
147
                     'rmail-message-regexp-p
121
148
                     regexp))
122
149
 
123
 
;; rmail-summary-by-topic
124
 
;; 1989 R.A. Schnitzler
 
150
(defun rmail-message-regexp-p (msg regexp)
 
151
  "Return t, if for message number MSG, regexp REGEXP matches in the header."
 
152
  (rmail-apply-in-message msg 'rmail-message-regexp-p-1 msg regexp))
 
153
 
 
154
(defun rmail-message-regexp-p-1 (msg regexp)
 
155
  ;; Search functions can expect to start from the beginning.
 
156
  (narrow-to-region (point) (save-excursion (search-forward "\n\n") (point)))
 
157
  (if rmail-enable-mime
 
158
      (if rmail-search-mime-header-function
 
159
          (funcall rmail-search-mime-header-function msg regexp (point))
 
160
        (error "You must set `rmail-search-mime-header-function'"))
 
161
    (re-search-forward regexp nil t)))
125
162
 
126
163
;;;###autoload
127
164
(defun rmail-summary-by-topic (subject &optional whole-message)
128
165
  "Display a summary of all messages with the given SUBJECT.
129
 
Normally checks the Subject field of headers;
130
 
but if WHOLE-MESSAGE is non-nil (prefix arg given),
131
 
 look in the whole message.
 
166
Normally checks just the Subject field of headers; but with prefix
 
167
argument WHOLE-MESSAGE is non-nil, looks in the whole message.
132
168
SUBJECT is a string of regexps separated by commas."
133
169
  (interactive
134
 
   (let* ((subject (with-current-buffer rmail-buffer
135
 
                     (rmail-current-subject)))
136
 
          (subject-re (with-current-buffer rmail-buffer
137
 
                        (rmail-current-subject-regexp)))
 
170
   ;; We quote the default subject, because if it contains regexp
 
171
   ;; special characters (eg "?"), it can fail to match itself.  (Bug#2333)
 
172
   (let* ((subject (regexp-quote (rmail-simplified-subject)))
138
173
          (prompt (concat "Topics to summarize by (regexp"
139
174
                          (if subject ", default current subject" "")
140
175
                          "): ")))
146
181
   (mail-comma-list-regexp subject) whole-message))
147
182
 
148
183
(defun rmail-message-subject-p (msg subject &optional whole-message)
149
 
  (save-restriction
150
 
    (goto-char (rmail-msgbeg msg))
151
 
    (search-forward "\n*** EOOH ***\n" (rmail-msgend msg) 'move)
152
 
    (narrow-to-region
153
 
     (point)
154
 
     (progn (search-forward (if whole-message "\^_" "\n\n")) (point)))
155
 
    (goto-char (point-min))
156
 
    (if whole-message (re-search-forward subject nil t)
157
 
      (string-match subject (let ((subj (mail-fetch-field "Subject")))
158
 
                              (if subj
159
 
                                  (funcall rmail-summary-line-decoder subj)
160
 
                                ""))))))
 
184
  (if whole-message
 
185
      (rmail-apply-in-message msg 're-search-forward subject nil t)
 
186
    (string-match subject (rmail-simplified-subject msg))))
161
187
 
162
188
;;;###autoload
163
189
(defun rmail-summary-by-senders (senders)
164
 
  "Display a summary of all messages with the given SENDERS.
165
 
SENDERS is a string of names separated by commas."
 
190
  "Display a summary of all messages whose \"From\" field matches SENDERS.
 
191
SENDERS is a string of regexps separated by commas."
166
192
  (interactive "sSenders to summarize by: ")
167
193
  (rmail-new-summary
168
194
   (concat "senders " senders)
171
197
   (mail-comma-list-regexp senders)))
172
198
 
173
199
(defun rmail-message-senders-p (msg senders)
174
 
  (save-restriction
175
 
    (goto-char (rmail-msgbeg msg))
176
 
    (search-forward "\n*** EOOH ***\n")
177
 
    (narrow-to-region (point) (progn (search-forward "\n\n") (point)))
178
 
    (string-match senders (or (mail-fetch-field "From") ""))))
 
200
  (string-match senders (or (rmail-get-header "From" msg) "")))
179
201
 
180
202
;; General making of a summary buffer.
181
203
 
183
205
 
184
206
(defvar rmail-new-summary-line-count)
185
207
 
186
 
(defun rmail-new-summary (description redo-form function &rest args)
 
208
(defun rmail-new-summary (desc redo func &rest args)
187
209
  "Create a summary of selected messages.
188
 
DESCRIPTION makes part of the mode line of the summary buffer.
189
 
For each message, FUNCTION is applied to the message number and ARGS...
 
210
DESC makes part of the mode line of the summary buffer. REDO is form ...
 
211
For each message, FUNC is applied to the message number and ARGS...
190
212
and if the result is non-nil, that message is included.
191
213
nil for FUNCTION means all messages."
192
214
  (message "Computing summary lines...")
193
 
  (let (sumbuf mesg was-in-summary)
194
 
    (save-excursion
195
 
      ;; Go to the Rmail buffer.
196
 
      (if (eq major-mode 'rmail-summary-mode)
197
 
          (setq was-in-summary t))
198
 
      (set-buffer rmail-buffer)
199
 
      ;; Find its summary buffer, or make one.
200
 
      (setq sumbuf
201
 
            (if (and rmail-summary-buffer
202
 
                     (buffer-name rmail-summary-buffer))
203
 
                rmail-summary-buffer
204
 
              (generate-new-buffer (concat (buffer-name) "-summary"))))
205
 
      (setq mesg rmail-current-message)
206
 
      ;; Filter the messages; make or get their summary lines.
207
 
      (let ((summary-msgs ())
208
 
            (rmail-new-summary-line-count 0))
209
 
        (let ((msgnum 1)
210
 
              (buffer-read-only nil)
211
 
              (old-min (point-min-marker))
212
 
              (old-max (point-max-marker)))
213
 
          ;; Can't use save-restriction here; that doesn't work if we
214
 
          ;; plan to modify text outside the original restriction.
215
 
          (save-excursion
216
 
            (widen)
217
 
            (goto-char (point-min))
218
 
            (while (>= rmail-total-messages msgnum)
219
 
              (if (or (null function)
220
 
                      (apply function (cons msgnum args)))
221
 
                  (setq summary-msgs
222
 
                        (cons (cons msgnum (rmail-make-summary-line msgnum))
223
 
                              summary-msgs)))
224
 
              (setq msgnum (1+ msgnum)))
225
 
            (setq summary-msgs (nreverse summary-msgs)))
226
 
          (narrow-to-region old-min old-max))
227
 
        ;; Temporarily, while summary buffer is unfinished,
228
 
        ;; we "don't have" a summary.
229
 
        (setq rmail-summary-buffer nil)
230
 
        (if rmail-enable-mime
231
 
            (with-current-buffer rmail-view-buffer
232
 
              (setq rmail-summary-buffer nil)))
233
 
        (save-excursion
234
 
          (let ((rbuf (current-buffer))
235
 
                (vbuf rmail-view-buffer)
236
 
                (total rmail-total-messages))
237
 
            (set-buffer sumbuf)
238
 
            ;; Set up the summary buffer's contents.
239
 
            (let ((buffer-read-only nil))
240
 
              (erase-buffer)
241
 
              (while summary-msgs
242
 
                (princ (cdr (car summary-msgs)) sumbuf)
243
 
                (setq summary-msgs (cdr summary-msgs)))
244
 
              (goto-char (point-min)))
245
 
            ;; Set up the rest of its state and local variables.
246
 
            (setq buffer-read-only t)
247
 
            (rmail-summary-mode)
248
 
            (make-local-variable 'minor-mode-alist)
249
 
            (setq minor-mode-alist (list (list t (concat ": " description))))
250
 
            (setq rmail-buffer rbuf
251
 
                  rmail-view-buffer vbuf
252
 
                  rmail-summary-redo redo-form
253
 
                  rmail-total-messages total))))
254
 
      (setq rmail-summary-buffer sumbuf))
 
215
  (unless rmail-buffer
 
216
    (error "No RMAIL buffer found"))
 
217
  (let (mesg was-in-summary)
 
218
    (if (eq major-mode 'rmail-summary-mode)
 
219
        (setq was-in-summary t))
 
220
    (with-current-buffer rmail-buffer
 
221
      (if (zerop (setq mesg rmail-current-message))
 
222
          (error "No messages to summarize"))
 
223
      (setq rmail-summary-buffer (rmail-new-summary-1 desc redo func args)))
255
224
    ;; Now display the summary buffer and go to the right place in it.
256
 
    (or was-in-summary
257
 
        (progn
258
 
          (if (and (one-window-p)
259
 
                   pop-up-windows (not pop-up-frames))
260
 
              ;; If there is just one window, put the summary on the top.
261
 
              (progn
262
 
                (split-window (selected-window) rmail-summary-window-size)
263
 
                (select-window (next-window (frame-first-window)))
264
 
                (pop-to-buffer sumbuf)
265
 
                ;; If pop-to-buffer did not use that window, delete that
266
 
                ;; window.  (This can happen if it uses another frame.)
267
 
                (if (not (eq sumbuf (window-buffer (frame-first-window))))
268
 
                    (delete-other-windows)))
269
 
            (pop-to-buffer sumbuf))
270
 
          (set-buffer rmail-buffer)
271
 
          ;; This is how rmail makes the summary buffer reappear.
272
 
          ;; We do this here to make the window the proper size.
273
 
          (rmail-select-summary nil)
274
 
          (set-buffer rmail-summary-buffer)))
 
225
    (unless was-in-summary
 
226
      (if (and (one-window-p)
 
227
               pop-up-windows
 
228
               (not pop-up-frames))
 
229
          ;; If there is just one window, put the summary on the top.
 
230
          (progn
 
231
            (split-window (selected-window) rmail-summary-window-size)
 
232
            (select-window (next-window (frame-first-window)))
 
233
            (pop-to-buffer rmail-summary-buffer)
 
234
            ;; If pop-to-buffer did not use that window, delete that
 
235
            ;; window.  (This can happen if it uses another frame.)
 
236
            (if (not (eq rmail-summary-buffer
 
237
                         (window-buffer (frame-first-window))))
 
238
                (delete-other-windows)))
 
239
        (pop-to-buffer rmail-summary-buffer))
 
240
      (set-buffer rmail-buffer)
 
241
      ;; This is how rmail makes the summary buffer reappear.
 
242
      ;; We do this here to make the window the proper size.
 
243
      (rmail-select-summary nil)
 
244
      (set-buffer rmail-summary-buffer))
275
245
    (rmail-summary-goto-msg mesg t t)
276
246
    (rmail-summary-construct-io-menu)
277
247
    (message "Computing summary lines...done")))
 
248
 
 
249
(defun rmail-new-summary-1 (description form function args)
 
250
  "Filter messages to obtain summary lines.
 
251
DESCRIPTION is added to the mode line.
 
252
 
 
253
Return the summary buffer by invoking FUNCTION on each message
 
254
passing the message number and ARGS...
 
255
 
 
256
REDO is a form ...
 
257
 
 
258
The current buffer must be a Rmail buffer either containing a
 
259
collection of mbox formatted messages or displaying a single
 
260
message."
 
261
  (let ((summary-msgs ())
 
262
        (rmail-new-summary-line-count 0)
 
263
        (sumbuf (rmail-get-create-summary-buffer)))
 
264
    ;; Scan the messages, getting their summary strings
 
265
    ;; and putting the list of them in SUMMARY-MSGS.
 
266
    (let ((msgnum 1)
 
267
          (main-buffer (current-buffer))
 
268
          (total rmail-total-messages)
 
269
          (inhibit-read-only t))
 
270
      (save-excursion
 
271
        ;; Go where the mbox text is.
 
272
        (if (rmail-buffers-swapped-p)
 
273
            (set-buffer rmail-view-buffer))
 
274
        (let ((old-min (point-min-marker))
 
275
              (old-max (point-max-marker)))
 
276
          (unwind-protect
 
277
              ;; Can't use save-restriction here; that doesn't work if we
 
278
              ;; plan to modify text outside the original restriction.
 
279
              (save-excursion
 
280
                (widen)
 
281
                (goto-char (point-min))
 
282
                (while (>= total msgnum)
 
283
                  ;; Go back to the Rmail buffer so
 
284
                  ;; so FUNCTION and rmail-get-summary can see its local vars.
 
285
                  (with-current-buffer main-buffer
 
286
                    ;; First test whether to include this message.
 
287
                    (if (or (null function)
 
288
                            (apply function msgnum args))
 
289
                        (setq summary-msgs
 
290
                              (cons (cons msgnum (rmail-get-summary msgnum))
 
291
                                    summary-msgs))))
 
292
                  (setq msgnum (1+ msgnum))
 
293
                  ;; Provide a periodic User progress message.
 
294
                  (if (zerop (% rmail-new-summary-line-count 10))
 
295
                      (message "Computing summary lines...%d"
 
296
                               rmail-new-summary-line-count)))
 
297
                (setq summary-msgs (nreverse summary-msgs)))
 
298
            (narrow-to-region old-min old-max)))))
 
299
    ;; Temporarily, while summary buffer is unfinished,
 
300
    ;; we "don't have" a summary.
 
301
    (setq rmail-summary-buffer nil)
 
302
    (unless summary-msgs
 
303
      (kill-buffer sumbuf)
 
304
      (error "Nothing to summarize"))
 
305
    ;; I have not a clue what this clause is doing.  If you read this
 
306
    ;; chunk of code and have a clue, then please email that clue to
 
307
    ;; pmr@pajato.com
 
308
    (if rmail-enable-mime
 
309
        (with-current-buffer rmail-buffer
 
310
          (setq rmail-summary-buffer nil)))
 
311
    (save-excursion
 
312
      (let ((rbuf (current-buffer))
 
313
            (total rmail-total-messages))
 
314
        (set-buffer sumbuf)
 
315
        ;; Set up the summary buffer's contents.
 
316
        (let ((buffer-read-only nil))
 
317
          (erase-buffer)
 
318
          (while summary-msgs
 
319
            (princ (cdr (car summary-msgs)) sumbuf)
 
320
            (setq summary-msgs (cdr summary-msgs)))
 
321
          (goto-char (point-min)))
 
322
        ;; Set up the rest of its state and local variables.
 
323
        (setq buffer-read-only t)
 
324
        (rmail-summary-mode)
 
325
        (make-local-variable 'minor-mode-alist)
 
326
        (setq minor-mode-alist (list (list t (concat ": " description))))
 
327
        (setq rmail-buffer rbuf
 
328
              rmail-summary-redo form
 
329
              rmail-total-messages total)))
 
330
    sumbuf))
 
331
 
 
332
(defun rmail-get-create-summary-buffer ()
 
333
  "Return the Rmail summary buffer.
 
334
If necessary, it is created and undo is disabled."
 
335
  (if (and rmail-summary-buffer (buffer-name rmail-summary-buffer))
 
336
      rmail-summary-buffer
 
337
    (let ((buff (generate-new-buffer (concat (buffer-name) "-summary"))))
 
338
      (with-current-buffer buff
 
339
        (setq buffer-undo-list t))
 
340
      buff)))
 
341
 
278
342
 
279
343
;; Low levels of generating a summary.
280
344
 
281
 
(defun rmail-make-summary-line (msg)
282
 
  (let ((line (or (aref rmail-summary-vector (1- msg))
283
 
                  (progn
284
 
                    (setq rmail-new-summary-line-count
285
 
                          (1+ rmail-new-summary-line-count))
286
 
                    (if (zerop (% rmail-new-summary-line-count 10))
287
 
                        (message "Computing summary lines...%d"
288
 
                                 rmail-new-summary-line-count))
289
 
                    (rmail-make-summary-line-1 msg))))
290
 
        delpos)
291
 
    ;; Fix up the part of the summary that says "deleted" or "unseen".
292
 
    (string-match "[0-9]+" line)
293
 
    (aset line (match-end 0)
294
 
          (if (rmail-message-deleted-p msg) ?D
295
 
            (if (= ?0 (char-after (+ 3 (rmail-msgbeg msg))))
296
 
                ?- ?\s)))
 
345
(defun rmail-get-summary (msgnum)
 
346
  "Return the summary line for message MSGNUM.
 
347
The mbox buffer must be current when you call this function
 
348
even if its text is swapped.
 
349
 
 
350
If the message has a summary line already, it will be stored in
 
351
the message as a header and simply returned, otherwise the
 
352
summary line is created, saved in the message header, cached and
 
353
returned.
 
354
 
 
355
The current buffer contains the unrestricted message collection."
 
356
  (let ((line (aref rmail-summary-vector (1- msgnum))))
 
357
    (unless line
 
358
      ;; Register a summary line for MSGNUM.
 
359
      (setq rmail-new-summary-line-count (1+ rmail-new-summary-line-count)
 
360
            line (rmail-create-summary-line msgnum))
 
361
      ;; Cache the summary line for use during this Rmail session.
 
362
      (aset rmail-summary-vector (1- msgnum) line))
297
363
    line))
298
364
 
299
 
;;;###autoload
300
365
(defcustom rmail-summary-line-decoder (function identity)
301
 
  "*Function to decode summary-line.
 
366
  "Function to decode a Rmail summary line.
 
367
It receives the summary line for one message as a string
 
368
and should return the decoded string.
302
369
 
303
 
By default, `identity' is set."
 
370
By default, it is `identity', which returns the string unaltered."
304
371
  :type 'function
305
372
  :group 'rmail-summary)
306
373
 
307
 
(defun rmail-make-summary-line-1 (msg)
308
 
  (goto-char (rmail-msgbeg msg))
309
 
  (let* ((lim (save-excursion (forward-line 2) (point)))
310
 
         pos
311
 
         (labels
312
 
          (progn
313
 
            (forward-char 3)
314
 
            (concat
315
 
;            (if (save-excursion (re-search-forward ",answered," lim t))
316
 
;                "*" "")
317
 
;            (if (save-excursion (re-search-forward ",filed," lim t))
318
 
;                "!" "")
319
 
             (if (progn (search-forward ",,") (eolp))
320
 
                 ""
321
 
               (concat "{"
322
 
                       (buffer-substring (point)
323
 
                                         (progn (end-of-line)
324
 
                                                (backward-char)
325
 
                                                (if (looking-at ",")
326
 
                                                    (point)
327
 
                                                  (1+ (point)))))
328
 
                       " } ")))))
329
 
         (line
330
 
          (progn
331
 
            (forward-line 1)
332
 
            (if (looking-at "Summary-line: ")
333
 
                (progn
334
 
                  (goto-char (match-end 0))
335
 
                  (buffer-substring (point)
336
 
                                    (progn (forward-line 1) (point))))))))
337
 
    ;; Obsolete status lines lacking a # should be flushed.
338
 
    (and line
339
 
         (not (string-match "#" line))
 
374
(defun rmail-create-summary-line (msgnum)
 
375
  "Return the summary line for message MSGNUM.
 
376
Obtain the message summary from the header if it is available
 
377
otherwise create it and store it in the message header.
 
378
 
 
379
The mbox buffer must be current when you call this function
 
380
even if its text is swapped."
 
381
  (let ((beg (rmail-msgbeg msgnum))
 
382
        (end (rmail-msgend msgnum))
 
383
        (deleted (rmail-message-deleted-p msgnum))
 
384
        ;; Does not work (swapped?)
 
385
;;;     (unseen (rmail-message-unseen-p msgnum))
 
386
        unseen lines)
 
387
    (save-excursion
 
388
      ;; Switch to the buffer that has the whole mbox text.
 
389
      (if (rmail-buffers-swapped-p)
 
390
          (set-buffer rmail-view-buffer))
 
391
      ;; Now we can compute the line count.
 
392
      (if rmail-summary-line-count-flag
 
393
          (setq lines (count-lines beg end)))
 
394
      ;; Narrow to the message header.
 
395
      (save-excursion
 
396
        (save-restriction
 
397
          (widen)
 
398
          (goto-char beg)
 
399
          (if (search-forward "\n\n" end t)
 
400
              (progn
 
401
                (narrow-to-region beg (point))
 
402
                ;; Replace rmail-message-unseen-p from above.
 
403
                (goto-char beg)
 
404
                (setq unseen (and (search-forward
 
405
                                   (concat rmail-attribute-header ": ") nil t)
 
406
                                  (looking-at "......U")))
 
407
                ;; Generate a status line from the message.
 
408
                (rmail-create-summary msgnum deleted unseen lines))
 
409
            (rmail-error-bad-format msgnum)))))))
 
410
 
 
411
;; FIXME this is now unused.
 
412
;; The intention was to display in the summary something like {E}
 
413
;; for an edited messaged, similarly for answered, etc.
 
414
;; But that conflicts with the previous rmail usage, where
 
415
;; any user-defined { labels } occupied this space.
 
416
;; So whilst it would be nice to have this information in the summary,
 
417
;; it would need to go somewhere else.
 
418
(defun rmail-get-summary-status ()
 
419
  "Return a coded string wrapped in curly braces denoting the status.
 
420
 
 
421
The current buffer must already be narrowed to the message headers for
 
422
the message being processed."
 
423
  (let ((status (mail-fetch-field rmail-attribute-header))
 
424
        (index 0)
 
425
        (result "")
 
426
        char)
 
427
    ;; Strip off the read/unread and the deleted attribute which are
 
428
    ;; handled separately.
 
429
    (setq status
 
430
          (if status
 
431
              (concat (substring status 0 1) (substring status 2 6))
 
432
            ""))
 
433
    (while (< index (length status))
 
434
      (unless (string= "-" (setq char (substring status index (1+ index))))
 
435
        (setq result (concat result char)))
 
436
      (setq index (1+ index)))
 
437
    (when (> (length result) 0)
 
438
      (setq result (concat "{" result "}")))
 
439
    result))
 
440
 
 
441
(autoload 'rmail-make-label "rmailkwd")
 
442
 
 
443
(defun rmail-get-summary-labels ()
 
444
  "Return a string wrapped in curly braces with the current message labels.
 
445
Returns nil if there are no labels.  The current buffer must
 
446
already be narrowed to the message headers for the message being
 
447
processed."
 
448
  (let ((labels (mail-fetch-field rmail-keyword-header)))
 
449
    (and labels
 
450
         (not (string-equal labels ""))
340
451
         (progn
341
 
           (delete-region (point)
342
 
                          (progn (forward-line -1) (point)))
343
 
           (setq line nil)))
344
 
    ;; If we didn't get a valid status line from the message,
345
 
    ;; make a new one and put it in the message.
346
 
    (or line
347
 
        (let* ((case-fold-search t)
348
 
               (next (rmail-msgend msg))
349
 
               (beg (if (progn (goto-char (rmail-msgbeg msg))
350
 
                               (search-forward "\n*** EOOH ***\n" next t))
351
 
                        (point)
352
 
                      (forward-line 1)
353
 
                      (point)))
354
 
               (end (progn (search-forward "\n\n" nil t) (point))))
355
 
          (save-restriction
356
 
            (narrow-to-region beg end)
357
 
            (goto-char beg)
358
 
            (setq line (rmail-make-basic-summary-line)))
359
 
          (goto-char (rmail-msgbeg msg))
360
 
          (forward-line 2)
361
 
          (insert "Summary-line: " line)))
362
 
    (setq pos (string-match "#" line))
363
 
    (aset rmail-summary-vector (1- msg)
364
 
          (funcall rmail-summary-line-decoder
365
 
                   (concat (format "%5d  " msg)
366
 
                           (substring line 0 pos)
367
 
                           labels
368
 
                           (substring line (1+ pos)))))
369
 
    ))
370
 
 
 
452
           ;; Intern so that rmail-read-label can offer completion.
 
453
           (mapc 'rmail-make-label (split-string labels ", "))
 
454
           (format "{ %s } " labels)))))
 
455
 
 
456
(defun rmail-create-summary (msgnum deleted unseen lines)
 
457
  "Return the summary line for message MSGNUM.
 
458
The current buffer should already be narrowed to the header for that message.
 
459
It could be either buffer, so don't access Rmail local variables.
 
460
DELETED is t if this message is marked deleted.
 
461
UNSEEN is t if it is marked unseen.
 
462
LINES is the number of lines in the message (if we should display that)
 
463
 or else nil."
 
464
  (goto-char (point-min))
 
465
  (let ((line (rmail-header-summary))
 
466
        (labels (rmail-get-summary-labels))
 
467
        pos status prefix basic-start basic-end linecount-string)
 
468
 
 
469
    (setq linecount-string
 
470
          (cond
 
471
           ((not lines)       " ")
 
472
           ((<= lines      9) (format "   [%d]" lines))
 
473
           ((<= lines     99) (format "  [%d]" lines))
 
474
           ((<= lines    999) (format " [%d]" lines))
 
475
           ((<= lines   9999) (format "  [%dk]" (/ lines 1000)))
 
476
           ((<= lines  99999) (format " [%dk]" (/ lines 1000)))
 
477
           (t                 (format "[%dk]" (/ lines 1000)))))
 
478
 
 
479
    (setq status (cond
 
480
                  (deleted ?D)
 
481
                  (unseen ?-)
 
482
                  (t ? ))
 
483
          prefix (format "%5d%c " msgnum status)
 
484
          basic-start (car line)
 
485
          basic-end (cadr line))
 
486
    (funcall rmail-summary-line-decoder
 
487
             (concat prefix basic-start linecount-string " "
 
488
                     labels basic-end))))
 
489
 
 
490
;; FIXME move to rmail.el?
371
491
;;;###autoload
372
492
(defcustom rmail-user-mail-address-regexp nil
373
 
  "*Regexp matching user mail addresses.
 
493
  "Regexp matching user mail addresses.
374
494
If non-nil, this variable is used to identify the correspondent
375
495
when receiving new mail.  If it matches the address of the sender,
376
496
the recipient is taken as correspondent of a mail.
386
506
  :group 'rmail-retrieve
387
507
  :version "21.1")
388
508
 
389
 
(defun rmail-make-basic-summary-line ()
 
509
(defun rmail-header-summary ()
 
510
  "Return a message summary based on the message headers.
 
511
The value is a list of two strings, the first and second parts of the summary.
 
512
 
 
513
The current buffer must already be narrowed to the message headers for
 
514
the message being processed."
390
515
  (goto-char (point-min))
391
 
  (concat (save-excursion
392
 
            (if (not (re-search-forward "^Date:" nil t))
393
 
                "      "
394
 
              (cond ((re-search-forward "\\([^0-9:]\\)\\([0-3]?[0-9]\\)\\([- \t_]+\\)\\([adfjmnos][aceopu][bcglnprtvy]\\)"
395
 
                      (save-excursion (end-of-line) (point)) t)
396
 
                     (format "%2d-%3s"
397
 
                             (string-to-number (buffer-substring
398
 
                                                (match-beginning 2)
399
 
                                                (match-end 2)))
400
 
                             (buffer-substring
401
 
                              (match-beginning 4) (match-end 4))))
402
 
                    ((re-search-forward "\\([^a-z]\\)\\([adfjmnos][acepou][bcglnprtvy]\\)\\([-a-z \t_]*\\)\\([0-9][0-9]?\\)"
403
 
                      (save-excursion (end-of-line) (point)) t)
404
 
                     (format "%2d-%3s"
405
 
                             (string-to-number (buffer-substring
406
 
                                                (match-beginning 4)
407
 
                                                (match-end 4)))
408
 
                             (buffer-substring
409
 
                              (match-beginning 2) (match-end 2))))
410
 
                    ((re-search-forward "\\(19\\|20\\)\\([0-9][0-9]\\)-\\([01][0-9]\\)-\\([0-3][0-9]\\)"
411
 
                      (save-excursion (end-of-line) (point)) t)
412
 
                     (format "%2s%2s%2s"
413
 
                             (buffer-substring
414
 
                              (match-beginning 2) (match-end 2))
415
 
                             (buffer-substring
416
 
                              (match-beginning 3) (match-end 3))
417
 
                             (buffer-substring
418
 
                              (match-beginning 4) (match-end 4))))
419
 
                    (t "??????"))))
420
 
          "  "
421
 
          (save-excursion
422
 
            (let* ((from (and (re-search-forward "^From:[ \t]*" nil t)
423
 
                              (mail-strip-quoted-names
424
 
                               (buffer-substring
425
 
                                (1- (point))
426
 
                                ;; Get all the lines of the From field
427
 
                                ;; so that we get a whole comment if there is one,
428
 
                                ;; so that mail-strip-quoted-names can discard it.
429
 
                                (let ((opoint (point)))
430
 
                                  (while (progn (forward-line 1)
431
 
                                                (looking-at "[ \t]")))
432
 
                                  ;; Back up over newline, then trailing spaces or tabs
433
 
                                  (forward-char -1)
434
 
                                  (skip-chars-backward " \t")
435
 
                                  (point))))))
436
 
                   len mch lo)
437
 
              (if (or (null from)
438
 
                      (string-match
439
 
                       (or rmail-user-mail-address-regexp
440
 
                           (concat "^\\("
441
 
                                   (regexp-quote (user-login-name))
442
 
                                   "\\($\\|@\\)\\|"
443
 
                                   (regexp-quote
444
 
                                    ;; Don't lose if run from init file
445
 
                                    ;; where user-mail-address is not
446
 
                                    ;; set yet.
447
 
                                    (or user-mail-address
448
 
                                        (concat (user-login-name) "@"
449
 
                                                (or mail-host-address
450
 
                                                    (system-name)))))
451
 
                                   "\\>\\)"))
452
 
                       from))
453
 
                  ;; No From field, or it's this user.
454
 
                  (save-excursion
455
 
                    (goto-char (point-min))
456
 
                    (if (not (re-search-forward "^To:[ \t]*" nil t))
457
 
                        nil
458
 
                      (setq from
459
 
                            (concat "to: "
460
 
                                    (mail-strip-quoted-names
461
 
                                     (buffer-substring
462
 
                                      (point)
463
 
                                      (progn (end-of-line)
464
 
                                             (skip-chars-backward " \t")
465
 
                                             (point)))))))))
466
 
              (if (null from)
467
 
                  "                         "
468
 
                (setq len (length from))
469
 
                (setq mch (string-match "[@%]" from))
470
 
                (format "%25s"
471
 
                        (if (or (not mch) (<= len 25))
472
 
                            (substring from (max 0 (- len 25)))
473
 
                          (substring from
474
 
                                     (setq lo (cond ((< (- mch 14) 0) 0)
475
 
                                                    ((< len (+ mch 11))
476
 
                                                     (- len 25))
477
 
                                                    (t (- mch 14))))
478
 
                                     (min len (+ lo 25))))))))
479
 
          (if rmail-summary-line-count-flag
480
 
              (save-excursion
481
 
                (save-restriction
482
 
                  (widen)
483
 
                  (let ((beg (rmail-msgbeg msgnum))
484
 
                        (end (rmail-msgend msgnum))
485
 
                        lines)
486
 
                    (save-excursion
487
 
                      (goto-char beg)
488
 
                      ;; Count only lines in the reformatted header,
489
 
                      ;; if we have reformatted it.
490
 
                      (search-forward "\n*** EOOH ***\n" end t)
491
 
                      (setq lines (count-lines (point) end)))
492
 
                    (format (cond
493
 
                             ((<= lines     9) "   [%d]")
494
 
                             ((<= lines    99) "  [%d]")
495
 
                             ((<= lines   999) " [%3d]")
496
 
                             (t             "[%d]"))
497
 
                            lines))))
498
 
            " ")
499
 
          " #"                          ;The # is part of the format.
500
 
          (if (re-search-forward "^Subject:" nil t)
501
 
              (progn (skip-chars-forward " \t")
502
 
                     (buffer-substring (point)
 
516
  (list
 
517
   (concat (save-excursion
 
518
             (if (not (re-search-forward "^Date:" nil t))
 
519
                 "      "
 
520
               (cond ((re-search-forward "\\([^0-9:]\\)\\([0-3]?[0-9]\\)\\([- \t_]+\\)\\([adfjmnos][aceopu][bcglnprtvy]\\)"
 
521
                       (line-end-position) t)
 
522
                      (format "%2d-%3s"
 
523
                              (string-to-number (buffer-substring
 
524
                                                 (match-beginning 2)
 
525
                                                 (match-end 2)))
 
526
                              (buffer-substring
 
527
                               (match-beginning 4) (match-end 4))))
 
528
                     ((re-search-forward "\\([^a-z]\\)\\([adfjmnos][acepou][bcglnprtvy]\\)\\([-a-z \t_]*\\)\\([0-9][0-9]?\\)"
 
529
                       (line-end-position) t)
 
530
                      (format "%2d-%3s"
 
531
                              (string-to-number (buffer-substring
 
532
                                                 (match-beginning 4)
 
533
                                                 (match-end 4)))
 
534
                              (buffer-substring
 
535
                               (match-beginning 2) (match-end 2))))
 
536
                     ((re-search-forward "\\(19\\|20\\)\\([0-9][0-9]\\)-\\([01][0-9]\\)-\\([0-3][0-9]\\)"
 
537
                       (line-end-position) t)
 
538
                      (format "%2s%2s%2s"
 
539
                              (buffer-substring
 
540
                               (match-beginning 2) (match-end 2))
 
541
                              (buffer-substring
 
542
                               (match-beginning 3) (match-end 3))
 
543
                              (buffer-substring
 
544
                               (match-beginning 4) (match-end 4))))
 
545
                     (t "??????"))))
 
546
           "  "
 
547
           (save-excursion
 
548
             (let* ((from (and (re-search-forward "^From:[ \t]*" nil t)
 
549
                               (mail-strip-quoted-names
 
550
                                (buffer-substring
 
551
                                 (1- (point))
 
552
                                 ;; Get all the lines of the From field
 
553
                                 ;; so that we get a whole comment if there is one,
 
554
                                 ;; so that mail-strip-quoted-names can discard it.
 
555
                                 (let ((opoint (point)))
 
556
                                   (while (progn (forward-line 1)
 
557
                                                 (looking-at "[ \t]")))
 
558
                                   ;; Back up over newline, then trailing spaces or tabs
 
559
                                   (forward-char -1)
 
560
                                   (skip-chars-backward " \t")
 
561
                                   (point))))))
 
562
                    len mch lo)
 
563
               (if (or (null from)
 
564
                       (string-match
 
565
                        (or rmail-user-mail-address-regexp
 
566
                            (concat "^\\("
 
567
                                    (regexp-quote (user-login-name))
 
568
                                    "\\($\\|@\\)\\|"
 
569
                                    (regexp-quote
 
570
                                     ;; Don't lose if run from init file
 
571
                                     ;; where user-mail-address is not
 
572
                                     ;; set yet.
 
573
                                     (or user-mail-address
 
574
                                         (concat (user-login-name) "@"
 
575
                                                 (or mail-host-address
 
576
                                                     (system-name)))))
 
577
                                    "\\>\\)"))
 
578
                        from))
 
579
                   ;; No From field, or it's this user.
 
580
                   (save-excursion
 
581
                     (goto-char (point-min))
 
582
                     (if (not (re-search-forward "^To:[ \t]*" nil t))
 
583
                         nil
 
584
                       (setq from
 
585
                             (concat "to: "
 
586
                                     (mail-strip-quoted-names
 
587
                                      (buffer-substring
 
588
                                       (point)
503
589
                                       (progn (end-of-line)
504
 
                                              (point))))
505
 
            (re-search-forward "[\n][\n]+" nil t)
506
 
            (buffer-substring (point) (progn (end-of-line) (point))))
507
 
          "\n"))
 
590
                                              (skip-chars-backward " \t")
 
591
                                              (point)))))))))
 
592
               (if (null from)
 
593
                   "                         "
 
594
                 (setq len (length from))
 
595
                 (setq mch (string-match "[@%]" from))
 
596
                 (format "%25s"
 
597
                         (if (or (not mch) (<= len 25))
 
598
                             (substring from (max 0 (- len 25)))
 
599
                           (substring from
 
600
                                      (setq lo (cond ((< (- mch 14) 0) 0)
 
601
                                                     ((< len (+ mch 11))
 
602
                                                      (- len 25))
 
603
                                                     (t (- mch 14))))
 
604
                                      (min len (+ lo 25)))))))))
 
605
   (concat (if (re-search-forward "^Subject:" nil t)
 
606
               (progn (skip-chars-forward " \t")
 
607
                      (buffer-substring (point)
 
608
                                        (progn (end-of-line)
 
609
                                               (point))))
 
610
             (re-search-forward "[\n][\n]+" nil t)
 
611
             (buffer-substring (point) (progn (end-of-line) (point))))
 
612
           "\n")))
508
613
 
509
614
;; Simple motion in a summary buffer.
510
615
 
539
644
                                      non-del-msg-found)))
540
645
      (setq count (1- count))))
541
646
  (beginning-of-line)
542
 
  (display-buffer rmail-view-buffer))
 
647
  (display-buffer rmail-buffer))
543
648
 
544
649
(defun rmail-summary-previous-msg (&optional number)
545
650
  "Display previous non-deleted msg from rmail file.
576
681
If N is negative, go backwards."
577
682
  (interactive "p")
578
683
  (let ((forward (> n 0))
579
 
        search-regexp i found)
 
684
        subject i found)
580
685
    (with-current-buffer rmail-buffer
581
 
      (setq search-regexp (rmail-current-subject-regexp)
 
686
      (setq subject (rmail-simplified-subject)
582
687
            i rmail-current-message))
583
688
    (save-excursion
584
689
      (while (and (/= n 0)
596
701
            (setq i (string-to-number
597
702
                     (buffer-substring (point)
598
703
                                       (min (point-max) (+ 6 (point))))))
599
 
            ;; See if that msg has desired subject.
600
 
            (save-excursion
601
 
              (set-buffer rmail-buffer)
602
 
              (save-restriction
603
 
                (widen)
604
 
                (goto-char (rmail-msgbeg i))
605
 
                (search-forward "\n*** EOOH ***\n")
606
 
                (let ((beg (point)) end)
607
 
                  (search-forward "\n\n")
608
 
                  (setq end (point))
609
 
                  (goto-char beg)
610
 
                  (setq done (re-search-forward search-regexp end t))))))
 
704
            (setq done (string-equal subject (rmail-simplified-subject i))))
611
705
          (if done (setq found i)))
612
706
        (setq n (if forward (1- n) (1+ n)))))
613
707
    (if found
664
758
      (not (overlay-get rmail-summary-overlay 'face))
665
759
      (let ((buffer-read-only nil))
666
760
        (skip-chars-forward " ")
667
 
        (skip-chars-forward "[0-9]")
 
761
        (skip-chars-forward "0-9")
668
762
        (if undel
669
763
            (if (looking-at "D")
670
764
                (progn (delete-char 1) (insert " ")))
671
765
          (delete-char 1)
672
 
          (insert "D"))))
 
766
          (insert "D"))
 
767
        ;; Register a new summary line.
 
768
        (with-current-buffer rmail-buffer
 
769
          (aset rmail-summary-vector (1- n) (rmail-create-summary-line n)))))
673
770
  (beginning-of-line))
674
771
 
 
772
(defun rmail-summary-update-line (n)
 
773
  "Update the summary line for message N."
 
774
  (when (rmail-summary-goto-msg n t t)
 
775
    (let* ((buffer-read-only nil)
 
776
           (start (line-beginning-position))
 
777
           (end (line-beginning-position 2))
 
778
           (overlays (overlays-in start end))
 
779
           high ov)
 
780
      (while (and (setq ov (car overlays))
 
781
                  (not (setq high (overlay-get ov 'rmail-summary))))
 
782
        (setq overlays (cdr overlays)))
 
783
      (delete-region start end)
 
784
      (princ
 
785
       (with-current-buffer rmail-buffer
 
786
         (aset rmail-summary-vector (1- n) (rmail-create-summary-line n)))
 
787
       (current-buffer))
 
788
      (when high
 
789
        (forward-line -1)
 
790
        (rmail-summary-update-highlight nil)))))
 
791
 
675
792
(defun rmail-summary-mark-undeleted (n)
676
793
  (rmail-summary-mark-deleted n t))
677
794
 
679
796
  (save-excursion
680
797
    (and n (rmail-summary-goto-msg n nil t))
681
798
    (skip-chars-forward " ")
682
 
    (skip-chars-forward "[0-9]")
 
799
    (skip-chars-forward "0-9")
683
800
    (looking-at "D")))
684
801
 
685
802
(defun rmail-summary-undelete (&optional arg)
700
817
             (and (rmail-message-deleted-p rmail-current-message)
701
818
                  (rmail-undelete-previous-message))
702
819
             (if rmail-enable-mime
703
 
                 (pop-to-buffer rmail-view-buffer))
 
820
                 (pop-to-buffer rmail-buffer))
704
821
             (pop-to-buffer rmail-summary-buffer))
705
822
            (t (goto-char opoint))))))
706
823
 
716
833
      (while (and (> rmail-current-message 0)
717
834
                  (< msgs-undeled n))
718
835
        (if (rmail-message-deleted-p rmail-current-message)
719
 
            (progn (rmail-set-attribute "deleted" nil)
 
836
            (progn (rmail-set-attribute rmail-deleted-attr-index nil)
720
837
                   (setq msgs-undeled (1+ msgs-undeled))))
721
838
        (setq rmail-current-message (1- rmail-current-message)))
722
839
      (set-buffer rmail-summary-buffer)
763
880
  (setq buffer-read-only t)
764
881
  (set-syntax-table text-mode-syntax-table)
765
882
  (make-local-variable 'rmail-buffer)
766
 
  (make-local-variable 'rmail-view-buffer)
767
883
  (make-local-variable 'rmail-total-messages)
768
884
  (make-local-variable 'rmail-current-message)
769
885
  (setq rmail-current-message nil)
786
902
  (add-hook 'post-command-hook 'rmail-summary-rmail-update nil t)
787
903
  (setq revert-buffer-function 'rmail-update-summary))
788
904
 
 
905
(defun rmail-summary-mark-seen (n &optional nomove unseen)
 
906
  "Remove the unseen mark from the current message, update the summary vector.
 
907
N is the number of the current message.  Optional argument NOMOVE
 
908
non-nil means we are already at the right column.  Optional argument
 
909
UNSEEN non-nil means mark the message as unseen."
 
910
  (save-excursion
 
911
    (unless nomove
 
912
      (beginning-of-line)
 
913
      (skip-chars-forward " ")
 
914
      (skip-chars-forward "0-9"))
 
915
    (when (char-equal (following-char) (if unseen ?\s ?-))
 
916
      (let ((buffer-read-only nil))
 
917
        (delete-char 1)
 
918
        (insert (if unseen "-" " ")))
 
919
      (let ((line (buffer-substring-no-properties (line-beginning-position)
 
920
                                                  (line-beginning-position 2))))
 
921
      (with-current-buffer rmail-buffer
 
922
        (aset rmail-summary-vector (1- n) line))))))
 
923
 
789
924
(defvar rmail-summary-put-back-unseen nil
790
925
  "Used for communicating between calls to `rmail-summary-rmail-update'.
791
926
If it moves to a message within an Incremental Search, and removes
815
950
            (setq rmail-summary-put-back-unseen nil))
816
951
 
817
952
        (or (eq rmail-current-message msg-num)
818
 
            (let ((window (get-buffer-window rmail-view-buffer t))
 
953
            (let ((window (get-buffer-window rmail-buffer t))
819
954
                  (owin (selected-window)))
820
955
              (if isearch-mode
821
 
                  (save-excursion
822
 
                    (set-buffer rmail-buffer)
 
956
                  (progn
823
957
                    ;; If we first saw the previous message in this search,
824
958
                    ;; and we have gone to a different message while searching,
825
959
                    ;; put back `unseen' on the former one.
826
 
                    (if rmail-summary-put-back-unseen
827
 
                        (rmail-set-attribute "unseen" t
828
 
                                             rmail-current-message))
 
960
                    (when rmail-summary-put-back-unseen
 
961
                      (rmail-set-attribute rmail-unseen-attr-index t
 
962
                                           rmail-current-message)
 
963
                      (save-excursion
 
964
                        (goto-char rmail-summary-put-back-unseen)
 
965
                        (rmail-summary-mark-seen rmail-current-message t t)))
829
966
                    ;; Arrange to do that later, for the new current message,
830
967
                    ;; if it still has `unseen'.
831
968
                    (setq rmail-summary-put-back-unseen
832
 
                          (rmail-message-labels-p msg-num ", ?\\(unseen\\),")))
 
969
                          (if (rmail-message-unseen-p msg-num)
 
970
                              (point))))
833
971
                (setq rmail-summary-put-back-unseen nil))
834
 
 
835
972
              ;; Go to the desired message.
836
973
              (setq rmail-current-message msg-num)
837
 
 
838
974
              ;; Update the summary to show the message has been seen.
839
 
              (if (= (following-char) ?-)
840
 
                  (progn
841
 
                    (delete-char 1)
842
 
                    (insert " ")))
843
 
 
 
975
              (rmail-summary-mark-seen msg-num t)
844
976
              (if window
845
977
                  ;; Using save-window-excursion would cause the new value
846
978
                  ;; of point to get lost.
888
1020
  (define-key rmail-summary-mode-map "\e\C-l" 'rmail-summary-by-labels)
889
1021
  (define-key rmail-summary-mode-map "\e\C-r" 'rmail-summary-by-recipients)
890
1022
  (define-key rmail-summary-mode-map "\e\C-s" 'rmail-summary-by-regexp)
 
1023
  ;; `f' for "from".
 
1024
  (define-key rmail-summary-mode-map "\e\C-f" 'rmail-summary-by-senders)
891
1025
  (define-key rmail-summary-mode-map "\e\C-t" 'rmail-summary-by-topic)
892
1026
  (define-key rmail-summary-mode-map "m"      'rmail-summary-mail)
893
1027
  (define-key rmail-summary-mode-map "\M-m"   'rmail-summary-retry-failure)
894
1028
  (define-key rmail-summary-mode-map "n"      'rmail-summary-next-msg)
895
1029
  (define-key rmail-summary-mode-map "\en"    'rmail-summary-next-all)
896
1030
  (define-key rmail-summary-mode-map "\e\C-n" 'rmail-summary-next-labeled-message)
897
 
  (define-key rmail-summary-mode-map "o"      'rmail-summary-output-to-rmail-file)
898
 
  (define-key rmail-summary-mode-map "\C-o"   'rmail-summary-output)
 
1031
  (define-key rmail-summary-mode-map "o"      'rmail-summary-output)
 
1032
  (define-key rmail-summary-mode-map "\C-o"   'rmail-summary-output-as-seen)
899
1033
  (define-key rmail-summary-mode-map "p"      'rmail-summary-previous-msg)
900
1034
  (define-key rmail-summary-mode-map "\ep"    'rmail-summary-previous-all)
901
1035
  (define-key rmail-summary-mode-map "\e\C-p" 'rmail-summary-previous-labeled-message)
903
1037
  (define-key rmail-summary-mode-map "Q"      'rmail-summary-wipe)
904
1038
  (define-key rmail-summary-mode-map "r"      'rmail-summary-reply)
905
1039
  (define-key rmail-summary-mode-map "s"      'rmail-summary-expunge-and-save)
 
1040
  ;; See rms's comment in rmail.el
 
1041
;;;  (define-key rmail-summary-mode-map "\er"    'rmail-summary-search-backward)
906
1042
  (define-key rmail-summary-mode-map "\es"    'rmail-summary-search)
907
1043
  (define-key rmail-summary-mode-map "t"      'rmail-summary-toggle-header)
908
1044
  (define-key rmail-summary-mode-map "u"      'rmail-summary-undelete)
909
1045
  (define-key rmail-summary-mode-map "\M-u"   'rmail-summary-undelete-many)
910
1046
  (define-key rmail-summary-mode-map "x"      'rmail-summary-expunge)
911
1047
  (define-key rmail-summary-mode-map "w"      'rmail-summary-output-body)
 
1048
  (define-key rmail-summary-mode-map "v"      'rmail-mime)
912
1049
  (define-key rmail-summary-mode-map "."      'rmail-summary-beginning-of-message)
913
1050
  (define-key rmail-summary-mode-map "/"      'rmail-summary-end-of-message)
914
1051
  (define-key rmail-summary-mode-map "<"      'rmail-summary-first-message)
955
1092
  '(nil))
956
1093
 
957
1094
(define-key rmail-summary-mode-map [menu-bar classify output-body]
958
 
  '("Output (body)..." . rmail-summary-output-body))
 
1095
  '("Output body..." . rmail-summary-output-body))
959
1096
 
960
1097
(define-key rmail-summary-mode-map [menu-bar classify output-inbox]
961
 
  '("Output (inbox)..." . rmail-summary-output))
 
1098
  '("Output..." . rmail-summary-output))
962
1099
 
963
1100
(define-key rmail-summary-mode-map [menu-bar classify output]
964
 
  '("Output (Rmail)..." . rmail-summary-output-to-rmail-file))
 
1101
  '("Output as seen..." . rmail-summary-output-as-seen))
965
1102
 
966
1103
(define-key rmail-summary-mode-map [menu-bar classify kill-label]
967
1104
  '("Kill Label..." . rmail-summary-kill-label))
1071
1208
and move to that message in the Rmail buffer.
1072
1209
 
1073
1210
If NOWARN, don't say anything if N is out of range.
1074
 
If SKIP-RMAIL, don't do anything to the Rmail buffer."
 
1211
If SKIP-RMAIL, don't do anything to the Rmail buffer.
 
1212
Returns non-nil if message N was found."
1075
1213
  (interactive "P")
1076
1214
  (if (consp n) (setq n (prefix-numeric-value n)))
1077
1215
  (if (eobp) (forward-line -1))
1104
1242
                 (setq n curmsg)
1105
1243
                 (setq message-not-found t)
1106
1244
                 (goto-char cur))))
1107
 
    (beginning-of-line)
1108
 
    (skip-chars-forward " ")
1109
 
    (skip-chars-forward "0-9")
1110
 
    (save-excursion (if (= (following-char) ?-)
1111
 
                        (let ((buffer-read-only nil))
1112
 
                          (delete-char 1)
1113
 
                          (insert " "))))
 
1245
    (rmail-summary-mark-seen n)
1114
1246
    (rmail-summary-update-highlight message-not-found)
1115
1247
    (beginning-of-line)
1116
 
    (if skip-rmail
1117
 
        nil
 
1248
    (unless skip-rmail
1118
1249
      (let ((selwin (selected-window)))
1119
1250
        (unwind-protect
1120
1251
            (progn (pop-to-buffer buf)
1121
1252
                   (rmail-show-message n))
1122
1253
          (select-window selwin)
1123
1254
          ;; The actions above can alter the current buffer.  Preserve it.
1124
 
          (set-buffer obuf))))))
 
1255
          (set-buffer obuf))))
 
1256
    (not message-not-found)))
1125
1257
 
1126
1258
;; Update the highlighted line in an rmail summary buffer.
1127
1259
;; That should be current.  We highlight the line point is on.
1131
1263
  (or rmail-summary-overlay
1132
1264
      (progn
1133
1265
        (make-local-variable 'rmail-summary-overlay)
1134
 
        (setq rmail-summary-overlay (make-overlay (point) (point)))))
 
1266
        (setq rmail-summary-overlay (make-overlay (point) (point)))
 
1267
        (overlay-put rmail-summary-overlay 'rmail-summary t)))
1135
1268
  ;; If this message is in the summary, use the overlay to highlight it.
1136
1269
  ;; Otherwise, don't highlight anything.
1137
1270
  (if not-found
1140
1273
                  (save-excursion (beginning-of-line)
1141
1274
                                  (skip-chars-forward " ")
1142
1275
                                  (point))
1143
 
                  (save-excursion (end-of-line) (point)))
 
1276
                  (line-end-position))
1144
1277
    (overlay-put rmail-summary-overlay 'face 'highlight)))
1145
1278
 
1146
1279
(defun rmail-summary-scroll-msg-up (&optional dist)
1150
1283
  (interactive "P")
1151
1284
  (if (eq dist '-)
1152
1285
      (rmail-summary-scroll-msg-down nil)
1153
 
    (let ((rmail-buffer-window (get-buffer-window rmail-view-buffer)))
 
1286
    (let ((rmail-buffer-window (get-buffer-window rmail-buffer)))
1154
1287
      (if rmail-buffer-window
1155
1288
          (if (let ((rmail-summary-window (selected-window)))
1156
1289
                (select-window rmail-buffer-window)
1165
1298
              (if (not rmail-summary-scroll-between-messages)
1166
1299
                  (error "End of buffer")
1167
1300
                (rmail-summary-next-msg (or dist 1)))
1168
 
            (let ((other-window-scroll-buffer rmail-view-buffer))
 
1301
            (let ((other-window-scroll-buffer rmail-buffer))
1169
1302
              (scroll-other-window dist)))
1170
1303
        ;; If it isn't visible at all, show the beginning.
1171
1304
        (rmail-summary-beginning-of-message)))))
1177
1310
  (interactive "P")
1178
1311
  (if (eq dist '-)
1179
1312
      (rmail-summary-scroll-msg-up nil)
1180
 
    (let ((rmail-buffer-window (get-buffer-window rmail-view-buffer)))
 
1313
    (let ((rmail-buffer-window (get-buffer-window rmail-buffer)))
1181
1314
      (if rmail-buffer-window
1182
1315
          (if (let ((rmail-summary-window (selected-window)))
1183
1316
                (select-window rmail-buffer-window)
1191
1324
              (if (not rmail-summary-scroll-between-messages)
1192
1325
                  (error "Beginning of buffer")
1193
1326
                (rmail-summary-previous-msg (or dist 1)))
1194
 
            (let ((other-window-scroll-buffer rmail-view-buffer))
 
1327
            (let ((other-window-scroll-buffer rmail-buffer))
1195
1328
              (scroll-other-window-down dist)))
1196
1329
        ;; If it isn't visible at all, show the beginning.
1197
1330
        (rmail-summary-beginning-of-message)))))
1211
1344
Position it according to WHERE which can be BEG or END"
1212
1345
  (if (and (one-window-p) (not pop-up-frames))
1213
1346
      ;; If there is just one window, put the summary on the top.
1214
 
      (let ((buffer rmail-view-buffer))
 
1347
      (let ((buffer rmail-buffer))
1215
1348
        (split-window (selected-window) rmail-summary-window-size)
1216
1349
        (select-window (frame-first-window))
1217
 
        (pop-to-buffer rmail-view-buffer)
 
1350
        (pop-to-buffer rmail-buffer)
1218
1351
        ;; If pop-to-buffer did not use that window, delete that
1219
1352
        ;; window.  (This can happen if it uses another frame.)
1220
1353
        (or (eq buffer (window-buffer (next-window (frame-first-window))))
1221
1354
            (delete-other-windows)))
1222
 
    (pop-to-buffer rmail-view-buffer))
 
1355
    (pop-to-buffer rmail-buffer))
1223
1356
  (cond
1224
1357
   ((eq where 'BEG)
1225
1358
        (goto-char (point-min))
1251
1384
  "Kill and wipe away Rmail summary, remaining within Rmail."
1252
1385
  (interactive)
1253
1386
  (save-excursion (set-buffer rmail-buffer) (setq rmail-summary-buffer nil))
1254
 
  (let ((local-rmail-buffer rmail-view-buffer))
 
1387
  (let ((local-rmail-buffer rmail-buffer))
1255
1388
    (kill-buffer (current-buffer))
1256
1389
    ;; Delete window if not only one.
1257
1390
    (if (not (eq (selected-window) (next-window nil 'no-minibuf)))
1272
1405
  "Expunge and save RMAIL file."
1273
1406
  (interactive)
1274
1407
  (save-excursion
1275
 
    (set-buffer rmail-buffer)
1276
 
    (when (rmail-expunge-confirmed)
1277
 
      (rmail-only-expunge)))
 
1408
    (rmail-expunge-and-save))
1278
1409
  (rmail-update-summary)
1279
 
  (save-excursion
1280
 
    (set-buffer rmail-buffer)
1281
 
    (save-buffer))
1282
1410
  (set-buffer-modified-p nil))
1283
1411
 
1284
1412
(defun rmail-summary-get-new-mail (&optional file-name)
1325
1453
(declare-function rmail-cease-edit "rmailedit"())
1326
1454
(declare-function rmail-set-label "rmailkwd" (l state &optional n))
1327
1455
(declare-function rmail-output-read-file-name "rmailout" ())
1328
 
(declare-function rmail-output-read-rmail-file-name  "rmailout" ())
1329
1456
(declare-function mail-send-and-exit "sendmail" (&optional arg))
1330
1457
 
1331
1458
(defvar rmail-summary-edit-map nil)
1413
1540
            (prefix-numeric-value current-prefix-arg))))
1414
1541
  ;; Don't use save-excursion because that prevents point from moving
1415
1542
  ;; properly in the summary buffer.
1416
 
  (let ((buffer (current-buffer)))
 
1543
  (let ((buffer (current-buffer))
 
1544
        (selwin (selected-window)))
1417
1545
    (unwind-protect
1418
1546
        (progn
1419
 
          (set-buffer rmail-buffer)
 
1547
          (pop-to-buffer rmail-buffer)
1420
1548
          (rmail-search regexp n))
 
1549
      (select-window selwin)
1421
1550
      (set-buffer buffer))))
1422
1551
 
1423
1552
(defun rmail-summary-toggle-header ()
1428
1557
    (rmail-toggle-header))
1429
1558
  ;; Inside save-excursion, some changes to point in the RMAIL buffer are lost.
1430
1559
  ;; Set point to point-min in the RMAIL buffer, if it is visible.
1431
 
  (let ((window (get-buffer-window rmail-view-buffer)))
 
1560
  (let ((window (get-buffer-window rmail-buffer)))
1432
1561
    (if window
1433
1562
        ;; Using save-window-excursion would lose the new value of point.
1434
1563
        (let ((owin (selected-window)))
1494
1623
prefix argument means ignore them.  While composing the reply,
1495
1624
use \\[mail-yank-original] to yank the original message into it."
1496
1625
  (interactive "P")
1497
 
  (let ((window (get-buffer-window rmail-view-buffer)))
 
1626
  (let ((window (get-buffer-window rmail-buffer)))
1498
1627
    (if window
1499
1628
        (select-window window)
1500
 
      (set-buffer rmail-view-buffer)))
 
1629
      (set-buffer rmail-buffer)))
1501
1630
  (rmail-reply just-sender)
1502
1631
  (rmail-summary-override-mail-send-and-exit))
1503
1632
 
1543
1672
 
1544
1673
;; Summary output commands.
1545
1674
 
1546
 
(defun rmail-summary-output-to-rmail-file (&optional file-name n)
1547
 
  "Append the current message to an Rmail file named FILE-NAME.
1548
 
If the file does not exist, ask if it should be created.
1549
 
If file is being visited, the message is appended to the Emacs
1550
 
buffer visiting that file.
1551
 
 
1552
 
A prefix argument N says to output N consecutive messages
1553
 
starting with the current one.  Deleted messages are skipped and don't count."
1554
 
  (interactive
1555
 
   (progn (require 'rmailout)
1556
 
          (list (rmail-output-read-rmail-file-name)
1557
 
                (prefix-numeric-value current-prefix-arg))))
1558
 
  (let ((i 0) prev-msg)
1559
 
    (while
1560
 
        (and (< i n)
1561
 
             (progn (rmail-summary-goto-msg)
1562
 
                    (not (eq prev-msg
1563
 
                             (setq prev-msg
1564
 
                                   (with-current-buffer rmail-buffer
1565
 
                                     rmail-current-message))))))
1566
 
      (setq i (1+ i))
1567
 
      (with-current-buffer rmail-buffer
1568
 
        (let ((rmail-delete-after-output nil))
1569
 
          (rmail-output-to-rmail-file file-name 1)))
1570
 
      (if rmail-delete-after-output
1571
 
          (rmail-summary-delete-forward nil)
1572
 
        (if (< i n)
1573
 
            (rmail-summary-next-msg 1))))))
1574
 
 
1575
1675
(defun rmail-summary-output (&optional file-name n)
1576
 
  "Append this message to Unix mail file named FILE-NAME.
1577
 
 
1578
 
A prefix argument N says to output N consecutive messages
1579
 
starting with the current one.  Deleted messages are skipped and don't count."
 
1676
  "Append this message to mail file FILE-NAME.
 
1677
This works with both mbox format and Babyl format files,
 
1678
outputting in the appropriate format for each.
 
1679
The default file name comes from `rmail-default-file',
 
1680
which is updated to the name you use in this command.
 
1681
 
 
1682
A prefix argument N says to output that many consecutive messages
 
1683
from those in the summary, starting with the current one.
 
1684
Deleted messages are skipped and don't count.
 
1685
When called from Lisp code, N may be omitted and defaults to 1.
 
1686
 
 
1687
This command always outputs the complete message header,
 
1688
even the header display is currently pruned."
1580
1689
  (interactive
1581
1690
   (progn (require 'rmailout)
1582
1691
          (list (rmail-output-read-file-name)
1598
1707
        (if (< i n)
1599
1708
            (rmail-summary-next-msg 1))))))
1600
1709
 
 
1710
(defalias 'rmail-summary-output-to-rmail-file 'rmail-summary-output)
 
1711
 
 
1712
(declare-function rmail-output-as-seen "rmailout"
 
1713
                  (file-name &optional count noattribute from-gnus))
 
1714
 
 
1715
(defun rmail-summary-output-as-seen (&optional file-name n)
 
1716
  "Append this message to mbox file named FILE-NAME.
 
1717
A prefix argument N says to output that many consecutive messages,
 
1718
from the summary, starting with the current one.
 
1719
Deleted messages are skipped and don't count.
 
1720
When called from Lisp code, N may be omitted and defaults to 1.
 
1721
 
 
1722
This outputs the message header as you see it (or would see it)
 
1723
displayed in Rmail.
 
1724
 
 
1725
The default file name comes from `rmail-default-file',
 
1726
which is updated to the name you use in this command."
 
1727
  (interactive
 
1728
   (progn (require 'rmailout)
 
1729
          (list (rmail-output-read-file-name)
 
1730
                (prefix-numeric-value current-prefix-arg))))
 
1731
  (require 'rmailout) ; for rmail-output-as-seen in non-interactive case
 
1732
  (let ((i 0) prev-msg)
 
1733
    (while
 
1734
        (and (< i n)
 
1735
             (progn (rmail-summary-goto-msg)
 
1736
                    (not (eq prev-msg
 
1737
                             (setq prev-msg
 
1738
                                   (with-current-buffer rmail-buffer
 
1739
                                     rmail-current-message))))))
 
1740
      (setq i (1+ i))
 
1741
      (with-current-buffer rmail-buffer
 
1742
        (let ((rmail-delete-after-output nil))
 
1743
          (rmail-output-as-seen file-name 1)))
 
1744
      (if rmail-delete-after-output
 
1745
          (rmail-summary-delete-forward nil)
 
1746
        (if (< i n)
 
1747
            (rmail-summary-next-msg 1))))))
 
1748
 
1601
1749
(defun rmail-summary-output-menu ()
1602
1750
  "Output current message to another Rmail file, chosen with a menu.
1603
 
Also set the default for subsequent \\[rmail-output-to-rmail-file] commands.
 
1751
Also set the default for subsequent \\[rmail-output-to-babyl-file] commands.
1604
1752
The variables `rmail-secondary-file-directory' and
1605
1753
`rmail-secondary-file-regexp' control which files are offered in the menu."
1606
1754
  (interactive)
1624
1772
            (cons "Output Rmail File"
1625
1773
                  (rmail-list-to-menu "Output Rmail File"
1626
1774
                                      files
1627
 
                                      'rmail-summary-output-to-rmail-file))))
 
1775
                                      'rmail-summary-output))))
1628
1776
      (define-key rmail-summary-mode-map [menu-bar classify input-menu]
1629
1777
        '("Input Rmail File" . rmail-disable-menu))
1630
1778
      (define-key rmail-summary-mode-map [menu-bar classify output-menu]
1646
1794
;; Sorting messages in Rmail Summary buffer.
1647
1795
 
1648
1796
(defun rmail-summary-sort-by-date (reverse)
1649
 
  "Sort messages of current Rmail summary by date.
1650
 
If prefix argument REVERSE is non-nil, sort them in reverse order."
 
1797
  "Sort messages of current Rmail summary by \"Date\" header.
 
1798
If prefix argument REVERSE is non-nil, sorts in reverse order."
1651
1799
  (interactive "P")
1652
1800
  (rmail-sort-from-summary (function rmail-sort-by-date) reverse))
1653
1801
 
1654
1802
(defun rmail-summary-sort-by-subject (reverse)
1655
 
  "Sort messages of current Rmail summary by subject.
1656
 
If prefix argument REVERSE is non-nil, sort them in reverse order."
 
1803
  "Sort messages of current Rmail summary by \"Subject\" header.
 
1804
Ignores any \"Re: \" prefix.  If prefix argument REVERSE is
 
1805
non-nil, sorts in reverse order."
1657
1806
  (interactive "P")
1658
1807
  (rmail-sort-from-summary (function rmail-sort-by-subject) reverse))
1659
1808
 
1660
1809
(defun rmail-summary-sort-by-author (reverse)
1661
1810
  "Sort messages of current Rmail summary by author.
1662
 
If prefix argument REVERSE is non-nil, sort them in reverse order."
 
1811
This uses either the \"From\" or \"Sender\" header, downcased.
 
1812
If prefix argument REVERSE is non-nil, sorts in reverse order."
1663
1813
  (interactive "P")
1664
1814
  (rmail-sort-from-summary (function rmail-sort-by-author) reverse))
1665
1815
 
1666
1816
(defun rmail-summary-sort-by-recipient (reverse)
1667
1817
  "Sort messages of current Rmail summary by recipient.
1668
 
If prefix argument REVERSE is non-nil, sort them in reverse order."
 
1818
This uses either the \"To\" or \"Apparently-To\" header, downcased.
 
1819
If prefix argument REVERSE is non-nil, sorts in reverse order."
1669
1820
  (interactive "P")
1670
1821
  (rmail-sort-from-summary (function rmail-sort-by-recipient) reverse))
1671
1822
 
1672
1823
(defun rmail-summary-sort-by-correspondent (reverse)
1673
1824
  "Sort messages of current Rmail summary by other correspondent.
1674
 
If prefix argument REVERSE is non-nil, sort them in reverse order."
 
1825
This uses either the \"From\", \"Sender\", \"To\", or
 
1826
\"Apparently-To\" header, downcased.  Uses the first header not
 
1827
excluded by `rmail-dont-reply-to-names'.  If prefix argument
 
1828
REVERSE is non-nil, sorts in reverse order."
1675
1829
  (interactive "P")
1676
1830
  (rmail-sort-from-summary (function rmail-sort-by-correspondent) reverse))
1677
1831
 
1678
1832
(defun rmail-summary-sort-by-lines (reverse)
1679
 
  "Sort messages of current Rmail summary by lines of the message.
1680
 
If prefix argument REVERSE is non-nil, sort them in reverse order."
 
1833
  "Sort messages of current Rmail summary by the number of lines.
 
1834
If prefix argument REVERSE is non-nil, sorts in reverse order."
1681
1835
  (interactive "P")
1682
1836
  (rmail-sort-from-summary (function rmail-sort-by-lines) reverse))
1683
1837
 
1684
1838
(defun rmail-summary-sort-by-labels (reverse labels)
1685
1839
  "Sort messages of current Rmail summary by labels.
1686
 
If prefix argument REVERSE is non-nil, sort them in reverse order.
1687
 
KEYWORDS is a comma-separated list of labels."
 
1840
LABELS is a comma-separated list of labels.
 
1841
If prefix argument REVERSE is non-nil, sorts in reverse order."
1688
1842
  (interactive "P\nsSort by labels: ")
1689
1843
  (rmail-sort-from-summary
1690
 
   (function (lambda (reverse)
1691
 
               (rmail-sort-by-labels reverse labels)))
 
1844
   (lambda (reverse) (rmail-sort-by-labels reverse labels))
1692
1845
   reverse))
1693
1846
 
1694
1847
(defun rmail-sort-from-summary (sortfun reverse)
1695
 
  "Sort Rmail messages from Summary buffer and update it after sorting."
 
1848
  "Sort the Rmail buffer using sorting function SORTFUN.
 
1849
Passes REVERSE to SORTFUN as its sole argument.  Then regenerates
 
1850
the summary.  Note that the whole Rmail buffer is sorted, even if
 
1851
the summary is only showing a subset of messages."
1696
1852
  (require 'rmailsort)
1697
1853
  (let ((selwin (selected-window)))
1698
1854
    (unwind-protect
1702
1858
 
1703
1859
(provide 'rmailsum)
1704
1860
 
1705
 
;; arch-tag: 556079ee-75c1-47f5-9884-2e0a0bc6c5a1
 
1861
;; arch-tag: 80b0a27a-a50d-4f37-9466-83d32d1e0ca8
1706
1862
;;; rmailsum.el ends here