rmailsum.el 67 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838
  1. ;;; rmailsum.el --- make summary buffers for the mail reader
  2. ;; Copyright (C) 1985, 1993-1996, 2000-2012 Free Software Foundation, Inc.
  3. ;; Maintainer: FSF
  4. ;; Keywords: mail
  5. ;; Package: rmail
  6. ;; This file is part of GNU Emacs.
  7. ;; GNU Emacs is free software: you can redistribute it and/or modify
  8. ;; it under the terms of the GNU General Public License as published by
  9. ;; the Free Software Foundation, either version 3 of the License, or
  10. ;; (at your option) any later version.
  11. ;; GNU Emacs is distributed in the hope that it will be useful,
  12. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. ;; GNU General Public License for more details.
  15. ;; You should have received a copy of the GNU General Public License
  16. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  17. ;;; Commentary:
  18. ;; Extended by Bob Weiner of Motorola
  19. ;; Provided all commands from rmail-mode in rmail-summary-mode and made key
  20. ;; bindings in both modes wholly compatible.
  21. ;;; Code:
  22. ;; For rmail-select-summary.
  23. (require 'rmail)
  24. (require 'rfc2047)
  25. (defcustom rmail-summary-scroll-between-messages t
  26. "Non-nil means Rmail summary scroll commands move between messages.
  27. That is, after `rmail-summary-scroll-msg-up' reaches the end of a
  28. message, it moves to the next message; and similarly for
  29. `rmail-summary-scroll-msg-down'."
  30. :type 'boolean
  31. :group 'rmail-summary)
  32. ;; FIXME could do with a :set function that regenerates the summary
  33. ;; and updates rmail-summary-vector.
  34. (defcustom rmail-summary-line-count-flag t
  35. "Non-nil means Rmail summary should show the number of lines in each message.
  36. Setting this option to nil might speed up the generation of summaries."
  37. :type 'boolean
  38. :group 'rmail-summary)
  39. (defvar rmail-summary-font-lock-keywords
  40. '(("^.....D.*" . font-lock-string-face) ; Deleted.
  41. ("^.....-.*" . font-lock-type-face) ; Unread.
  42. ;; Neither of the below will be highlighted if either of the above are:
  43. ("^.....[^D-] \\(......\\)" 1 font-lock-keyword-face) ; Date.
  44. ("{ \\([^\n}]+\\) }" 1 font-lock-comment-face)) ; Labels.
  45. "Additional expressions to highlight in Rmail Summary mode.")
  46. (defvar rmail-summary-redo nil
  47. "(FUNCTION . ARGS) to regenerate this Rmail summary buffer.")
  48. (defvar rmail-summary-overlay nil
  49. "Overlay used to highlight the current message in the Rmail summary.")
  50. (put 'rmail-summary-overlay 'permanent-local t)
  51. (defvar rmail-summary-mode-map
  52. (let ((map (make-keymap)))
  53. (suppress-keymap map)
  54. (define-key map [mouse-2] 'rmail-summary-mouse-goto-message)
  55. (define-key map "a" 'rmail-summary-add-label)
  56. (define-key map "b" 'rmail-summary-bury)
  57. (define-key map "c" 'rmail-summary-continue)
  58. (define-key map "d" 'rmail-summary-delete-forward)
  59. (define-key map "\C-d" 'rmail-summary-delete-backward)
  60. (define-key map "e" 'rmail-summary-edit-current-message)
  61. (define-key map "f" 'rmail-summary-forward)
  62. (define-key map "g" 'rmail-summary-get-new-mail)
  63. (define-key map "h" 'rmail-summary)
  64. (define-key map "i" 'rmail-summary-input)
  65. (define-key map "j" 'rmail-summary-goto-msg)
  66. (define-key map "\C-m" 'rmail-summary-goto-msg)
  67. (define-key map "k" 'rmail-summary-kill-label)
  68. (define-key map "l" 'rmail-summary-by-labels)
  69. (define-key map "\e\C-h" 'rmail-summary)
  70. (define-key map "\e\C-l" 'rmail-summary-by-labels)
  71. (define-key map "\e\C-r" 'rmail-summary-by-recipients)
  72. (define-key map "\e\C-s" 'rmail-summary-by-regexp)
  73. ;; `f' for "from".
  74. (define-key map "\e\C-f" 'rmail-summary-by-senders)
  75. (define-key map "\e\C-t" 'rmail-summary-by-topic)
  76. (define-key map "m" 'rmail-summary-mail)
  77. (define-key map "\M-m" 'rmail-summary-retry-failure)
  78. (define-key map "n" 'rmail-summary-next-msg)
  79. (define-key map "\en" 'rmail-summary-next-all)
  80. (define-key map "\e\C-n" 'rmail-summary-next-labeled-message)
  81. (define-key map "o" 'rmail-summary-output)
  82. (define-key map "\C-o" 'rmail-summary-output-as-seen)
  83. (define-key map "p" 'rmail-summary-previous-msg)
  84. (define-key map "\ep" 'rmail-summary-previous-all)
  85. (define-key map "\e\C-p" 'rmail-summary-previous-labeled-message)
  86. (define-key map "q" 'rmail-summary-quit)
  87. (define-key map "Q" 'rmail-summary-wipe)
  88. (define-key map "r" 'rmail-summary-reply)
  89. (define-key map "s" 'rmail-summary-expunge-and-save)
  90. ;; See rms's comment in rmail.el
  91. ;; (define-key map "\er" 'rmail-summary-search-backward)
  92. (define-key map "\es" 'rmail-summary-search)
  93. (define-key map "t" 'rmail-summary-toggle-header)
  94. (define-key map "u" 'rmail-summary-undelete)
  95. (define-key map "\M-u" 'rmail-summary-undelete-many)
  96. (define-key map "x" 'rmail-summary-expunge)
  97. (define-key map "w" 'rmail-summary-output-body)
  98. (define-key map "v" 'rmail-mime)
  99. (define-key map "." 'rmail-summary-beginning-of-message)
  100. (define-key map "/" 'rmail-summary-end-of-message)
  101. (define-key map "<" 'rmail-summary-first-message)
  102. (define-key map ">" 'rmail-summary-last-message)
  103. (define-key map " " 'rmail-summary-scroll-msg-up)
  104. (define-key map "\177" 'rmail-summary-scroll-msg-down)
  105. (define-key map "?" 'describe-mode)
  106. (define-key map "\C-c\C-n" 'rmail-summary-next-same-subject)
  107. (define-key map "\C-c\C-p" 'rmail-summary-previous-same-subject)
  108. (define-key map "\C-c\C-s\C-d" 'rmail-summary-sort-by-date)
  109. (define-key map "\C-c\C-s\C-s" 'rmail-summary-sort-by-subject)
  110. (define-key map "\C-c\C-s\C-a" 'rmail-summary-sort-by-author)
  111. (define-key map "\C-c\C-s\C-r" 'rmail-summary-sort-by-recipient)
  112. (define-key map "\C-c\C-s\C-c" 'rmail-summary-sort-by-correspondent)
  113. (define-key map "\C-c\C-s\C-l" 'rmail-summary-sort-by-lines)
  114. (define-key map "\C-c\C-s\C-k" 'rmail-summary-sort-by-labels)
  115. (define-key map "\C-x\C-s" 'rmail-summary-save-buffer)
  116. ;; Menu bar bindings.
  117. (define-key map [menu-bar] (make-sparse-keymap))
  118. (define-key map [menu-bar classify]
  119. (cons "Classify" (make-sparse-keymap "Classify")))
  120. (define-key map [menu-bar classify output-menu]
  121. '("Output (Rmail Menu)..." . rmail-summary-output-menu))
  122. (define-key map [menu-bar classify input-menu]
  123. '("Input Rmail File (menu)..." . rmail-input-menu))
  124. (define-key map [menu-bar classify input-menu]
  125. '(nil))
  126. (define-key map [menu-bar classify output-menu]
  127. '(nil))
  128. (define-key map [menu-bar classify output-body]
  129. '("Output body..." . rmail-summary-output-body))
  130. (define-key map [menu-bar classify output-inbox]
  131. '("Output..." . rmail-summary-output))
  132. (define-key map [menu-bar classify output]
  133. '("Output as seen..." . rmail-summary-output-as-seen))
  134. (define-key map [menu-bar classify kill-label]
  135. '("Kill Label..." . rmail-summary-kill-label))
  136. (define-key map [menu-bar classify add-label]
  137. '("Add Label..." . rmail-summary-add-label))
  138. (define-key map [menu-bar summary]
  139. (cons "Summary" (make-sparse-keymap "Summary")))
  140. (define-key map [menu-bar summary senders]
  141. '("By Senders..." . rmail-summary-by-senders))
  142. (define-key map [menu-bar summary labels]
  143. '("By Labels..." . rmail-summary-by-labels))
  144. (define-key map [menu-bar summary recipients]
  145. '("By Recipients..." . rmail-summary-by-recipients))
  146. (define-key map [menu-bar summary topic]
  147. '("By Topic..." . rmail-summary-by-topic))
  148. (define-key map [menu-bar summary regexp]
  149. '("By Regexp..." . rmail-summary-by-regexp))
  150. (define-key map [menu-bar summary all]
  151. '("All" . rmail-summary))
  152. (define-key map [menu-bar mail]
  153. (cons "Mail" (make-sparse-keymap "Mail")))
  154. (define-key map [menu-bar mail rmail-summary-get-new-mail]
  155. '("Get New Mail" . rmail-summary-get-new-mail))
  156. (define-key map [menu-bar mail lambda]
  157. '("----"))
  158. (define-key map [menu-bar mail continue]
  159. '("Continue" . rmail-summary-continue))
  160. (define-key map [menu-bar mail resend]
  161. '("Re-send..." . rmail-summary-resend))
  162. (define-key map [menu-bar mail forward]
  163. '("Forward" . rmail-summary-forward))
  164. (define-key map [menu-bar mail retry]
  165. '("Retry" . rmail-summary-retry-failure))
  166. (define-key map [menu-bar mail reply]
  167. '("Reply" . rmail-summary-reply))
  168. (define-key map [menu-bar mail mail]
  169. '("Mail" . rmail-summary-mail))
  170. (define-key map [menu-bar delete]
  171. (cons "Delete" (make-sparse-keymap "Delete")))
  172. (define-key map [menu-bar delete expunge/save]
  173. '("Expunge/Save" . rmail-summary-expunge-and-save))
  174. (define-key map [menu-bar delete expunge]
  175. '("Expunge" . rmail-summary-expunge))
  176. (define-key map [menu-bar delete undelete]
  177. '("Undelete" . rmail-summary-undelete))
  178. (define-key map [menu-bar delete delete]
  179. '("Delete" . rmail-summary-delete-forward))
  180. (define-key map [menu-bar move]
  181. (cons "Move" (make-sparse-keymap "Move")))
  182. (define-key map [menu-bar move search-back]
  183. '("Search Back..." . rmail-summary-search-backward))
  184. (define-key map [menu-bar move search]
  185. '("Search..." . rmail-summary-search))
  186. (define-key map [menu-bar move previous]
  187. '("Previous Nondeleted" . rmail-summary-previous-msg))
  188. (define-key map [menu-bar move next]
  189. '("Next Nondeleted" . rmail-summary-next-msg))
  190. (define-key map [menu-bar move last]
  191. '("Last" . rmail-summary-last-message))
  192. (define-key map [menu-bar move first]
  193. '("First" . rmail-summary-first-message))
  194. (define-key map [menu-bar move previous]
  195. '("Previous" . rmail-summary-previous-all))
  196. (define-key map [menu-bar move next]
  197. '("Next" . rmail-summary-next-all))
  198. map)
  199. "Keymap used in Rmail summary mode.")
  200. ;; Entry points for making a summary buffer.
  201. ;; Regenerate the contents of the summary
  202. ;; using the same selection criterion as last time.
  203. ;; M-x revert-buffer in a summary buffer calls this function.
  204. (defun rmail-update-summary (&rest ignore)
  205. (apply (car rmail-summary-redo) (cdr rmail-summary-redo)))
  206. ;;;###autoload
  207. (defun rmail-summary ()
  208. "Display a summary of all messages, one line per message."
  209. (interactive)
  210. (rmail-new-summary "All" '(rmail-summary) nil))
  211. ;;;###autoload
  212. (defun rmail-summary-by-labels (labels)
  213. "Display a summary of all messages with one or more LABELS.
  214. LABELS should be a string containing the desired labels, separated by commas."
  215. (interactive "sLabels to summarize by: ")
  216. (if (string= labels "")
  217. (setq labels (or rmail-last-multi-labels
  218. (error "No label specified"))))
  219. (setq rmail-last-multi-labels labels)
  220. (rmail-new-summary (concat "labels " labels)
  221. (list 'rmail-summary-by-labels labels)
  222. 'rmail-message-labels-p
  223. (concat " \\("
  224. (mail-comma-list-regexp labels)
  225. "\\)\\(,\\|\\'\\)")))
  226. ;; FIXME "a string of regexps separated by commas" makes no sense because:
  227. ;; i) it's pointless (you can just use \\|)
  228. ;; ii) it's broken (you can't specify a literal comma)
  229. ;; rmail-summary-by-topic and rmail-summary-by-senders have the same issue.
  230. ;;;###autoload
  231. (defun rmail-summary-by-recipients (recipients &optional primary-only)
  232. "Display a summary of all messages with the given RECIPIENTS.
  233. Normally checks the To, From and Cc fields of headers;
  234. but if PRIMARY-ONLY is non-nil (prefix arg given),
  235. only look in the To and From fields.
  236. RECIPIENTS is a string of regexps separated by commas."
  237. (interactive "sRecipients to summarize by: \nP")
  238. (rmail-new-summary
  239. (concat "recipients " recipients)
  240. (list 'rmail-summary-by-recipients recipients primary-only)
  241. 'rmail-message-recipients-p
  242. (mail-comma-list-regexp recipients) primary-only))
  243. (defun rmail-message-recipients-p (msg recipients &optional primary-only)
  244. (rmail-apply-in-message msg 'rmail-message-recipients-p-1
  245. recipients primary-only))
  246. (defun rmail-message-recipients-p-1 (recipients &optional primary-only)
  247. ;; mail-fetch-field does not care where it starts from.
  248. (narrow-to-region (point) (progn (search-forward "\n\n") (point)))
  249. (or (string-match recipients (or (mail-fetch-field "To") ""))
  250. (string-match recipients (or (mail-fetch-field "From") ""))
  251. (if (not primary-only)
  252. (string-match recipients (or (mail-fetch-field "Cc") "")))))
  253. ;; FIXME I find this a non-obvious name for what this function does.
  254. ;; Also, the optional WHOLE-MESSAGE argument of r-s-by-topic would
  255. ;; seem more natural here.
  256. ;;;###autoload
  257. (defun rmail-summary-by-regexp (regexp)
  258. "Display a summary of all messages according to regexp REGEXP.
  259. If the regular expression is found in the header of the message
  260. \(including in the date and other lines, as well as the subject line),
  261. Emacs will list the message in the summary."
  262. (interactive "sRegexp to summarize by: ")
  263. (if (string= regexp "")
  264. (setq regexp (or rmail-last-regexp
  265. (error "No regexp specified"))))
  266. (setq rmail-last-regexp regexp)
  267. (rmail-new-summary (concat "regexp " regexp)
  268. (list 'rmail-summary-by-regexp regexp)
  269. 'rmail-message-regexp-p
  270. regexp))
  271. (defun rmail-message-regexp-p (msg regexp)
  272. "Return t, if for message number MSG, regexp REGEXP matches in the header."
  273. (rmail-apply-in-message msg 'rmail-message-regexp-p-1 msg regexp))
  274. (defun rmail-message-regexp-p-1 (msg regexp)
  275. ;; Search functions can expect to start from the beginning.
  276. (narrow-to-region (point) (save-excursion (search-forward "\n\n") (point)))
  277. (if (and rmail-enable-mime
  278. rmail-search-mime-header-function)
  279. (funcall rmail-search-mime-header-function msg regexp (point))
  280. (re-search-forward regexp nil t)))
  281. ;;;###autoload
  282. (defun rmail-summary-by-topic (subject &optional whole-message)
  283. "Display a summary of all messages with the given SUBJECT.
  284. Normally checks just the Subject field of headers; but with prefix
  285. argument WHOLE-MESSAGE is non-nil, looks in the whole message.
  286. SUBJECT is a string of regexps separated by commas."
  287. (interactive
  288. ;; We quote the default subject, because if it contains regexp
  289. ;; special characters (eg "?"), it can fail to match itself. (Bug#2333)
  290. (let* ((subject (regexp-quote (rmail-simplified-subject)))
  291. (prompt (concat "Topics to summarize by (regexp"
  292. (if subject ", default current subject" "")
  293. "): ")))
  294. (list (read-string prompt nil nil subject) current-prefix-arg)))
  295. (rmail-new-summary
  296. (concat "about " subject)
  297. (list 'rmail-summary-by-topic subject whole-message)
  298. 'rmail-message-subject-p
  299. (mail-comma-list-regexp subject) whole-message))
  300. (defun rmail-message-subject-p (msg subject &optional whole-message)
  301. (if whole-message
  302. (rmail-apply-in-message msg 're-search-forward subject nil t)
  303. (string-match subject (rmail-simplified-subject msg))))
  304. ;;;###autoload
  305. (defun rmail-summary-by-senders (senders)
  306. "Display a summary of all messages whose \"From\" field matches SENDERS.
  307. SENDERS is a string of regexps separated by commas."
  308. (interactive "sSenders to summarize by: ")
  309. (rmail-new-summary
  310. (concat "senders " senders)
  311. (list 'rmail-summary-by-senders senders)
  312. 'rmail-message-senders-p
  313. (mail-comma-list-regexp senders)))
  314. (defun rmail-message-senders-p (msg senders)
  315. (string-match senders (or (rmail-get-header "From" msg) "")))
  316. ;; General making of a summary buffer.
  317. (defvar rmail-summary-symbol-number 0)
  318. (defvar rmail-new-summary-line-count)
  319. (defun rmail-new-summary (desc redo func &rest args)
  320. "Create a summary of selected messages.
  321. DESC makes part of the mode line of the summary buffer. REDO is form ...
  322. For each message, FUNC is applied to the message number and ARGS...
  323. and if the result is non-nil, that message is included.
  324. nil for FUNCTION means all messages."
  325. (message "Computing summary lines...")
  326. (unless rmail-buffer
  327. (error "No RMAIL buffer found"))
  328. (let (mesg was-in-summary sumbuf)
  329. (if (eq major-mode 'rmail-summary-mode)
  330. (setq was-in-summary t))
  331. (with-current-buffer rmail-buffer
  332. (setq rmail-summary-buffer (rmail-new-summary-1 desc redo func args)
  333. ;; r-s-b is buffer-local.
  334. sumbuf rmail-summary-buffer
  335. mesg rmail-current-message))
  336. ;; Now display the summary buffer and go to the right place in it.
  337. (unless was-in-summary
  338. (if (and (one-window-p)
  339. pop-up-windows
  340. (not pop-up-frames))
  341. ;; If there is just one window, put the summary on the top.
  342. (progn
  343. (split-window (selected-window) rmail-summary-window-size)
  344. (select-window (next-window (frame-first-window)))
  345. (rmail-pop-to-buffer sumbuf)
  346. ;; If pop-to-buffer did not use that window, delete that
  347. ;; window. (This can happen if it uses another frame.)
  348. (if (not (eq sumbuf (window-buffer (frame-first-window))))
  349. (delete-other-windows)))
  350. (rmail-pop-to-buffer sumbuf))
  351. (set-buffer rmail-buffer)
  352. ;; This is how rmail makes the summary buffer reappear.
  353. ;; We do this here to make the window the proper size.
  354. (rmail-select-summary nil)
  355. (set-buffer rmail-summary-buffer))
  356. (rmail-summary-goto-msg mesg t t)
  357. (rmail-summary-construct-io-menu)
  358. (message "Computing summary lines...done")))
  359. (defun rmail-new-summary-1 (description form function args)
  360. "Filter messages to obtain summary lines.
  361. DESCRIPTION is added to the mode line.
  362. Return the summary buffer by invoking FUNCTION on each message
  363. passing the message number and ARGS...
  364. REDO is a form ...
  365. The current buffer must be a Rmail buffer either containing a
  366. collection of mbox formatted messages or displaying a single
  367. message."
  368. (let ((summary-msgs ())
  369. (rmail-new-summary-line-count 0)
  370. (sumbuf (rmail-get-create-summary-buffer)))
  371. ;; Scan the messages, getting their summary strings
  372. ;; and putting the list of them in SUMMARY-MSGS.
  373. (let ((msgnum 1)
  374. (main-buffer (current-buffer))
  375. (total rmail-total-messages)
  376. (inhibit-read-only t))
  377. (save-excursion
  378. ;; Go where the mbox text is.
  379. (if (rmail-buffers-swapped-p)
  380. (set-buffer rmail-view-buffer))
  381. (let ((old-min (point-min-marker))
  382. (old-max (point-max-marker)))
  383. (unwind-protect
  384. ;; Can't use save-restriction here; that doesn't work if we
  385. ;; plan to modify text outside the original restriction.
  386. (save-excursion
  387. (widen)
  388. (goto-char (point-min))
  389. (while (>= total msgnum)
  390. ;; Go back to the Rmail buffer so
  391. ;; so FUNCTION and rmail-get-summary can see its local vars.
  392. (with-current-buffer main-buffer
  393. ;; First test whether to include this message.
  394. (if (or (null function)
  395. (apply function msgnum args))
  396. (setq summary-msgs
  397. (cons (cons msgnum (rmail-get-summary msgnum))
  398. summary-msgs))))
  399. (setq msgnum (1+ msgnum))
  400. ;; Provide a periodic User progress message.
  401. (if (and (not (zerop rmail-new-summary-line-count))
  402. (zerop (% rmail-new-summary-line-count 10)))
  403. (message "Computing summary lines...%d"
  404. rmail-new-summary-line-count)))
  405. (setq summary-msgs (nreverse summary-msgs)))
  406. (narrow-to-region old-min old-max)))))
  407. ;; Temporarily, while summary buffer is unfinished,
  408. ;; we "don't have" a summary.
  409. (setq rmail-summary-buffer nil)
  410. ;; I have not a clue what this clause is doing. If you read this
  411. ;; chunk of code and have a clue, then please email that clue to
  412. ;; pmr@pajato.com
  413. (if rmail-enable-mime
  414. (with-current-buffer rmail-buffer
  415. (setq rmail-summary-buffer nil)))
  416. (save-excursion
  417. (let ((rbuf (current-buffer))
  418. (total rmail-total-messages))
  419. (set-buffer sumbuf)
  420. ;; Set up the summary buffer's contents.
  421. (let ((buffer-read-only nil))
  422. (erase-buffer)
  423. (while summary-msgs
  424. (princ (cdr (car summary-msgs)) sumbuf)
  425. (setq summary-msgs (cdr summary-msgs)))
  426. (goto-char (point-min)))
  427. ;; Set up the rest of its state and local variables.
  428. (setq buffer-read-only t)
  429. (rmail-summary-mode)
  430. (make-local-variable 'minor-mode-alist)
  431. (setq minor-mode-alist (list (list t (concat ": " description))))
  432. (setq rmail-buffer rbuf
  433. rmail-summary-redo form
  434. rmail-total-messages total)))
  435. sumbuf))
  436. (defun rmail-get-create-summary-buffer ()
  437. "Return the Rmail summary buffer.
  438. If necessary, it is created and undo is disabled."
  439. (if (and rmail-summary-buffer (buffer-name rmail-summary-buffer))
  440. rmail-summary-buffer
  441. (let ((buff (generate-new-buffer (concat (buffer-name) "-summary"))))
  442. (with-current-buffer buff
  443. (setq buffer-undo-list t))
  444. buff)))
  445. ;; Low levels of generating a summary.
  446. (defun rmail-get-summary (msgnum)
  447. "Return the summary line for message MSGNUM.
  448. The mbox buffer must be current when you call this function
  449. even if its text is swapped.
  450. If the message has a summary line already, it will be stored in
  451. the message as a header and simply returned, otherwise the
  452. summary line is created, saved in the message header, cached and
  453. returned.
  454. The current buffer contains the unrestricted message collection."
  455. (let ((line (aref rmail-summary-vector (1- msgnum))))
  456. (unless line
  457. ;; Register a summary line for MSGNUM.
  458. (setq rmail-new-summary-line-count (1+ rmail-new-summary-line-count)
  459. line (rmail-create-summary-line msgnum))
  460. ;; Cache the summary line for use during this Rmail session.
  461. (aset rmail-summary-vector (1- msgnum) line))
  462. line))
  463. (defcustom rmail-summary-line-decoder (function rfc2047-decode-string)
  464. "Function to decode a Rmail summary line.
  465. It receives the summary line for one message as a string
  466. and should return the decoded string.
  467. By default, it is `rfc2047-decode-string', which decodes MIME-encoded
  468. subject."
  469. :type 'function
  470. :version "23.3"
  471. :group 'rmail-summary)
  472. (defun rmail-create-summary-line (msgnum)
  473. "Return the summary line for message MSGNUM.
  474. Obtain the message summary from the header if it is available
  475. otherwise create it and store it in the message header.
  476. The mbox buffer must be current when you call this function
  477. even if its text is swapped."
  478. (let ((beg (rmail-msgbeg msgnum))
  479. (end (rmail-msgend msgnum))
  480. (deleted (rmail-message-deleted-p msgnum))
  481. ;; Does not work (swapped?)
  482. ;;; (unseen (rmail-message-unseen-p msgnum))
  483. unseen lines)
  484. (save-excursion
  485. ;; Switch to the buffer that has the whole mbox text.
  486. (if (rmail-buffers-swapped-p)
  487. (set-buffer rmail-view-buffer))
  488. ;; Now we can compute the line count.
  489. (if rmail-summary-line-count-flag
  490. (setq lines (count-lines beg end)))
  491. ;; Narrow to the message header.
  492. (save-excursion
  493. (save-restriction
  494. (widen)
  495. (goto-char beg)
  496. (if (search-forward "\n\n" end t)
  497. (progn
  498. (narrow-to-region beg (point))
  499. ;; Replace rmail-message-unseen-p from above.
  500. (goto-char beg)
  501. (setq unseen (and (search-forward
  502. (concat rmail-attribute-header ": ") nil t)
  503. (looking-at "......U")))
  504. ;; Generate a status line from the message.
  505. (rmail-create-summary msgnum deleted unseen lines))
  506. (rmail-error-bad-format msgnum)))))))
  507. ;; FIXME this is now unused.
  508. ;; The intention was to display in the summary something like {E}
  509. ;; for an edited messaged, similarly for answered, etc.
  510. ;; But that conflicts with the previous rmail usage, where
  511. ;; any user-defined { labels } occupied this space.
  512. ;; So whilst it would be nice to have this information in the summary,
  513. ;; it would need to go somewhere else.
  514. (defun rmail-get-summary-status ()
  515. "Return a coded string wrapped in curly braces denoting the status.
  516. The current buffer must already be narrowed to the message headers for
  517. the message being processed."
  518. (let ((status (mail-fetch-field rmail-attribute-header))
  519. (index 0)
  520. (result "")
  521. char)
  522. ;; Strip off the read/unread and the deleted attribute which are
  523. ;; handled separately.
  524. (setq status
  525. (if status
  526. (concat (substring status 0 1) (substring status 2 6))
  527. ""))
  528. (while (< index (length status))
  529. (unless (string= "-" (setq char (substring status index (1+ index))))
  530. (setq result (concat result char)))
  531. (setq index (1+ index)))
  532. (when (> (length result) 0)
  533. (setq result (concat "{" result "}")))
  534. result))
  535. (autoload 'rmail-make-label "rmailkwd")
  536. (defun rmail-get-summary-labels ()
  537. "Return a string wrapped in curly braces with the current message labels.
  538. Returns nil if there are no labels. The current buffer must
  539. already be narrowed to the message headers for the message being
  540. processed."
  541. (let ((labels (mail-fetch-field rmail-keyword-header)))
  542. (and labels
  543. (not (string-equal labels ""))
  544. (progn
  545. ;; Intern so that rmail-read-label can offer completion.
  546. (mapc 'rmail-make-label (split-string labels ", "))
  547. (format "{ %s } " labels)))))
  548. (defun rmail-create-summary (msgnum deleted unseen lines)
  549. "Return the summary line for message MSGNUM.
  550. The current buffer should already be narrowed to the header for that message.
  551. It could be either buffer, so don't access Rmail local variables.
  552. DELETED is t if this message is marked deleted.
  553. UNSEEN is t if it is marked unseen.
  554. LINES is the number of lines in the message (if we should display that)
  555. or else nil."
  556. (goto-char (point-min))
  557. (let ((line (rmail-header-summary))
  558. (labels (rmail-get-summary-labels))
  559. pos status prefix basic-start basic-end linecount-string)
  560. (setq linecount-string
  561. (cond
  562. ((not lines) " ")
  563. ((<= lines 9) (format " [%d]" lines))
  564. ((<= lines 99) (format " [%d]" lines))
  565. ((<= lines 999) (format " [%d]" lines))
  566. ((<= lines 9999) (format " [%dk]" (/ lines 1000)))
  567. ((<= lines 99999) (format " [%dk]" (/ lines 1000)))
  568. (t (format "[%dk]" (/ lines 1000)))))
  569. (setq status (cond
  570. (deleted ?D)
  571. (unseen ?-)
  572. (t ? ))
  573. prefix (format "%5d%c " msgnum status)
  574. basic-start (car line)
  575. basic-end (cadr line))
  576. (funcall rmail-summary-line-decoder
  577. (concat prefix basic-start linecount-string " "
  578. labels basic-end))))
  579. (defun rmail-header-summary ()
  580. "Return a message summary based on the message headers.
  581. The value is a list of two strings, the first and second parts of the summary.
  582. The current buffer must already be narrowed to the message headers for
  583. the message being processed."
  584. (goto-char (point-min))
  585. (list
  586. (concat (save-excursion
  587. (if (not (re-search-forward "^Date:" nil t))
  588. " "
  589. ;; Match month names case-insensitively
  590. (cond ((let ((case-fold-search t))
  591. (re-search-forward "\\([^0-9:]\\)\\([0-3]?[0-9]\\)\\([- \t_]+\\)\\([adfjmnos][aceopu][bcglnprtvy]\\)"
  592. (line-end-position) t))
  593. (format "%2d-%3s"
  594. (string-to-number (buffer-substring
  595. (match-beginning 2)
  596. (match-end 2)))
  597. (buffer-substring
  598. (match-beginning 4) (match-end 4))))
  599. ((let ((case-fold-search t))
  600. (re-search-forward "\\([^a-z]\\)\\([adfjmnos][acepou][bcglnprtvy]\\)\\([-a-z \t_]*\\)\\([0-9][0-9]?\\)"
  601. (line-end-position) t))
  602. (format "%2d-%3s"
  603. (string-to-number (buffer-substring
  604. (match-beginning 4)
  605. (match-end 4)))
  606. (buffer-substring
  607. (match-beginning 2) (match-end 2))))
  608. ((re-search-forward "\\(19\\|20\\)\\([0-9][0-9]\\)-\\([01][0-9]\\)-\\([0-3][0-9]\\)"
  609. (line-end-position) t)
  610. (format "%2s%2s%2s"
  611. (buffer-substring
  612. (match-beginning 2) (match-end 2))
  613. (buffer-substring
  614. (match-beginning 3) (match-end 3))
  615. (buffer-substring
  616. (match-beginning 4) (match-end 4))))
  617. (t "??????"))))
  618. " "
  619. (save-excursion
  620. (let* ((from (and (re-search-forward "^From:[ \t]*" nil t)
  621. (mail-strip-quoted-names
  622. (buffer-substring
  623. (1- (point))
  624. ;; Get all the lines of the From field
  625. ;; so that we get a whole comment if there is one,
  626. ;; so that mail-strip-quoted-names can discard it.
  627. (let ((opoint (point)))
  628. (while (progn (forward-line 1)
  629. (looking-at "[ \t]")))
  630. ;; Back up over newline, then trailing spaces or tabs
  631. (forward-char -1)
  632. (skip-chars-backward " \t")
  633. (point))))))
  634. len mch lo)
  635. (if (or (null from)
  636. (string-match
  637. (or rmail-user-mail-address-regexp
  638. (concat "^\\("
  639. (regexp-quote (user-login-name))
  640. "\\($\\|@\\)\\|"
  641. (regexp-quote
  642. ;; Don't lose if run from init file
  643. ;; where user-mail-address is not
  644. ;; set yet.
  645. (or user-mail-address
  646. (concat (user-login-name) "@"
  647. (or mail-host-address
  648. (system-name)))))
  649. "\\>\\)"))
  650. from))
  651. ;; No From field, or it's this user.
  652. (save-excursion
  653. (goto-char (point-min))
  654. (if (not (re-search-forward "^To:[ \t]*" nil t))
  655. nil
  656. (setq from
  657. (concat "to: "
  658. (mail-strip-quoted-names
  659. (buffer-substring
  660. (point)
  661. (progn (end-of-line)
  662. (skip-chars-backward " \t")
  663. (point)))))))))
  664. (if (null from)
  665. " "
  666. ;; We are going to return only 25 characters of the
  667. ;; address, so make sure it is RFC2047 decoded before
  668. ;; taking its substring. This is important when the address is not on the same line as the name, e.g.:
  669. ;; To: =?UTF-8?Q?=C5=A0t=C4=9Bp=C3=A1n_?= =?UTF-8?Q?N=C4=9Bmec?=
  670. ;; <stepnem@gmail.com>
  671. (setq from (rfc2047-decode-string from))
  672. (setq len (length from))
  673. (setq mch (string-match "[@%]" from))
  674. (format "%25s"
  675. (if (or (not mch) (<= len 25))
  676. (substring from (max 0 (- len 25)))
  677. (substring from
  678. (setq lo (cond ((< (- mch 14) 0) 0)
  679. ((< len (+ mch 11))
  680. (- len 25))
  681. (t (- mch 14))))
  682. (min len (+ lo 25)))))))))
  683. (concat (if (re-search-forward "^Subject:" nil t)
  684. (let (pos str)
  685. (skip-chars-forward " \t")
  686. (setq pos (point))
  687. (forward-line 1)
  688. (setq str (buffer-substring pos (1- (point))))
  689. (while (looking-at "\\s ")
  690. (setq str (concat str " "
  691. (buffer-substring (match-end 0)
  692. (line-end-position))))
  693. (forward-line 1))
  694. str)
  695. (re-search-forward "[\n][\n]+" nil t)
  696. (buffer-substring (point) (progn (end-of-line) (point))))
  697. "\n")))
  698. ;; Simple motion in a summary buffer.
  699. (defun rmail-summary-next-all (&optional number)
  700. (interactive "p")
  701. (forward-line (if number number 1))
  702. ;; It doesn't look nice to move forward past the last message line.
  703. (and (eobp) (> number 0)
  704. (forward-line -1))
  705. (display-buffer rmail-buffer))
  706. (defun rmail-summary-previous-all (&optional number)
  707. (interactive "p")
  708. (forward-line (- (if number number 1)))
  709. ;; It doesn't look nice to move forward past the last message line.
  710. (and (eobp) (< number 0)
  711. (forward-line -1))
  712. (display-buffer rmail-buffer))
  713. (defun rmail-summary-next-msg (&optional number)
  714. "Display next non-deleted msg from rmail file.
  715. With optional prefix argument NUMBER, moves forward this number of non-deleted
  716. messages, or backward if NUMBER is negative."
  717. (interactive "p")
  718. (forward-line 0)
  719. (and (> number 0) (end-of-line))
  720. (let ((count (if (< number 0) (- number) number))
  721. (search (if (> number 0) 're-search-forward 're-search-backward))
  722. (non-del-msg-found nil))
  723. (while (and (> count 0) (setq non-del-msg-found
  724. (or (funcall search "^.....[^D]" nil t)
  725. non-del-msg-found)))
  726. (setq count (1- count))))
  727. (beginning-of-line)
  728. (display-buffer rmail-buffer))
  729. (defun rmail-summary-previous-msg (&optional number)
  730. "Display previous non-deleted msg from rmail file.
  731. With optional prefix argument NUMBER, moves backward this number of
  732. non-deleted messages."
  733. (interactive "p")
  734. (rmail-summary-next-msg (- (if number number 1))))
  735. (defun rmail-summary-next-labeled-message (n labels)
  736. "Show next message with LABELS. Defaults to last labels used.
  737. With prefix argument N moves forward N messages with these labels."
  738. (interactive "p\nsMove to next msg with labels: ")
  739. (let (msg)
  740. (with-current-buffer rmail-buffer
  741. (rmail-next-labeled-message n labels)
  742. (setq msg rmail-current-message))
  743. (rmail-summary-goto-msg msg)))
  744. (defun rmail-summary-previous-labeled-message (n labels)
  745. "Show previous message with LABELS. Defaults to last labels used.
  746. With prefix argument N moves backward N messages with these labels."
  747. (interactive "p\nsMove to previous msg with labels: ")
  748. (let (msg)
  749. (with-current-buffer rmail-buffer
  750. (rmail-previous-labeled-message n labels)
  751. (setq msg rmail-current-message))
  752. (rmail-summary-goto-msg msg)))
  753. (defun rmail-summary-next-same-subject (n)
  754. "Go to the next message in the summary having the same subject.
  755. With prefix argument N, do this N times.
  756. If N is negative, go backwards."
  757. (interactive "p")
  758. (let ((forward (> n 0))
  759. subject i found)
  760. (with-current-buffer rmail-buffer
  761. (setq subject (rmail-simplified-subject)
  762. i rmail-current-message))
  763. (save-excursion
  764. (while (and (/= n 0)
  765. (if forward
  766. (not (eobp))
  767. (not (bobp))))
  768. (let (done)
  769. (while (and (not done)
  770. (if forward
  771. (not (eobp))
  772. (not (bobp))))
  773. ;; Advance thru summary.
  774. (forward-line (if forward 1 -1))
  775. ;; Get msg number of this line.
  776. (setq i (string-to-number
  777. (buffer-substring (point)
  778. (min (point-max) (+ 6 (point))))))
  779. (setq done (string-equal subject (rmail-simplified-subject i))))
  780. (if done (setq found i)))
  781. (setq n (if forward (1- n) (1+ n)))))
  782. (if found
  783. (rmail-summary-goto-msg found)
  784. (error "No %s message with same subject"
  785. (if forward "following" "previous")))))
  786. (defun rmail-summary-previous-same-subject (n)
  787. "Go to the previous message in the summary having the same subject.
  788. With prefix argument N, do this N times.
  789. If N is negative, go forwards instead."
  790. (interactive "p")
  791. (rmail-summary-next-same-subject (- n)))
  792. ;; Delete and undelete summary commands.
  793. (defun rmail-summary-delete-forward (&optional count)
  794. "Delete this message and move to next nondeleted one.
  795. Deleted messages stay in the file until the \\[rmail-expunge] command is given.
  796. A prefix argument serves as a repeat count;
  797. a negative argument means to delete and move backward."
  798. (interactive "p")
  799. (unless (numberp count) (setq count 1))
  800. (let (end del-msg
  801. (backward (< count 0)))
  802. (while (/= count 0)
  803. (rmail-summary-goto-msg)
  804. (with-current-buffer rmail-buffer
  805. (rmail-delete-message)
  806. (setq del-msg rmail-current-message))
  807. (rmail-summary-mark-deleted del-msg)
  808. (while (and (not (if backward (bobp) (eobp)))
  809. (save-excursion (beginning-of-line)
  810. (looking-at " *[0-9]+D")))
  811. (forward-line (if backward -1 1)))
  812. ;; It looks ugly to move to the empty line at end of buffer.
  813. (and (eobp) (not backward)
  814. (forward-line -1))
  815. (setq count
  816. (if (> count 0) (1- count) (1+ count))))))
  817. (defun rmail-summary-delete-backward (&optional count)
  818. "Delete this message and move to previous nondeleted one.
  819. Deleted messages stay in the file until the \\[rmail-expunge] command is given.
  820. A prefix argument serves as a repeat count;
  821. a negative argument means to delete and move forward."
  822. (interactive "p")
  823. (rmail-summary-delete-forward (- count)))
  824. (defun rmail-summary-mark-deleted (&optional n undel)
  825. ;; Since third arg is t, this only alters the summary, not the Rmail buf.
  826. (and n (rmail-summary-goto-msg n t t))
  827. (or (eobp)
  828. (not (overlay-get rmail-summary-overlay 'face))
  829. (let ((buffer-read-only nil))
  830. (skip-chars-forward " ")
  831. (skip-chars-forward "0-9")
  832. (if undel
  833. (if (looking-at "D")
  834. (progn (delete-char 1) (insert " ")))
  835. (delete-char 1)
  836. (insert "D"))
  837. ;; Register a new summary line.
  838. (with-current-buffer rmail-buffer
  839. (aset rmail-summary-vector (1- n) (rmail-create-summary-line n)))))
  840. (beginning-of-line))
  841. (defun rmail-summary-update-line (n)
  842. "Update the summary line for message N."
  843. (when (rmail-summary-goto-msg n t t)
  844. (let* ((buffer-read-only nil)
  845. (start (line-beginning-position))
  846. (end (line-beginning-position 2))
  847. (overlays (overlays-in start end))
  848. high ov)
  849. (while (and (setq ov (car overlays))
  850. (not (setq high (overlay-get ov 'rmail-summary))))
  851. (setq overlays (cdr overlays)))
  852. (delete-region start end)
  853. (princ
  854. (with-current-buffer rmail-buffer
  855. (aset rmail-summary-vector (1- n) (rmail-create-summary-line n)))
  856. (current-buffer))
  857. (when high
  858. (forward-line -1)
  859. (rmail-summary-update-highlight nil)))))
  860. (defun rmail-summary-mark-undeleted (n)
  861. (rmail-summary-mark-deleted n t))
  862. (defun rmail-summary-deleted-p (&optional n)
  863. (save-excursion
  864. (and n (rmail-summary-goto-msg n nil t))
  865. (skip-chars-forward " ")
  866. (skip-chars-forward "0-9")
  867. (looking-at "D")))
  868. (defun rmail-summary-undelete (&optional arg)
  869. "Undelete current message.
  870. Optional prefix ARG means undelete ARG previous messages."
  871. (interactive "p")
  872. (if (/= arg 1)
  873. (rmail-summary-undelete-many arg)
  874. (let ((buffer-read-only nil)
  875. (opoint (point)))
  876. (end-of-line)
  877. (cond ((re-search-backward "\\(^ *[0-9]*\\)\\(D\\)" nil t)
  878. (replace-match "\\1 ")
  879. (rmail-summary-goto-msg)
  880. (if rmail-enable-mime
  881. (set-buffer rmail-buffer)
  882. (rmail-pop-to-buffer rmail-buffer))
  883. (and (rmail-message-deleted-p rmail-current-message)
  884. (rmail-undelete-previous-message))
  885. (if rmail-enable-mime
  886. (rmail-pop-to-buffer rmail-buffer))
  887. (rmail-pop-to-buffer rmail-summary-buffer))
  888. (t (goto-char opoint))))))
  889. (defun rmail-summary-undelete-many (&optional n)
  890. "Undelete all deleted msgs, optional prefix arg N means undelete N prev msgs."
  891. (interactive "P")
  892. (with-current-buffer rmail-buffer
  893. (let* ((init-msg (if n rmail-current-message rmail-total-messages))
  894. (rmail-current-message init-msg)
  895. (n (or n rmail-total-messages))
  896. (msgs-undeled 0))
  897. (while (and (> rmail-current-message 0)
  898. (< msgs-undeled n))
  899. (if (rmail-message-deleted-p rmail-current-message)
  900. (progn (rmail-set-attribute rmail-deleted-attr-index nil)
  901. (setq msgs-undeled (1+ msgs-undeled))))
  902. (setq rmail-current-message (1- rmail-current-message)))
  903. (set-buffer rmail-summary-buffer)
  904. (setq rmail-current-message init-msg msgs-undeled 0)
  905. (while (and (> rmail-current-message 0)
  906. (< msgs-undeled n))
  907. (if (rmail-summary-deleted-p rmail-current-message)
  908. (progn (rmail-summary-mark-undeleted rmail-current-message)
  909. (setq msgs-undeled (1+ msgs-undeled))))
  910. (setq rmail-current-message (1- rmail-current-message))))
  911. (rmail-summary-goto-msg)))
  912. ;; Rmail Summary mode is suitable only for specially formatted data.
  913. (put 'rmail-summary-mode 'mode-class 'special)
  914. (defun rmail-summary-mode ()
  915. "Rmail Summary Mode is invoked from Rmail Mode by using \\<rmail-mode-map>\\[rmail-summary].
  916. As commands are issued in the summary buffer, they are applied to the
  917. corresponding mail messages in the rmail buffer.
  918. All normal editing commands are turned off.
  919. Instead, nearly all the Rmail mode commands are available,
  920. though many of them move only among the messages in the summary.
  921. These additional commands exist:
  922. \\[rmail-summary-undelete-many] Undelete all or prefix arg deleted messages.
  923. \\[rmail-summary-wipe] Delete the summary and go to the Rmail buffer.
  924. Commands for sorting the summary:
  925. \\[rmail-summary-sort-by-date] Sort by date.
  926. \\[rmail-summary-sort-by-subject] Sort by subject.
  927. \\[rmail-summary-sort-by-author] Sort by author.
  928. \\[rmail-summary-sort-by-recipient] Sort by recipient.
  929. \\[rmail-summary-sort-by-correspondent] Sort by correspondent.
  930. \\[rmail-summary-sort-by-lines] Sort by lines.
  931. \\[rmail-summary-sort-by-labels] Sort by labels."
  932. (interactive)
  933. (kill-all-local-variables)
  934. (setq major-mode 'rmail-summary-mode)
  935. (setq mode-name "RMAIL Summary")
  936. (setq truncate-lines t)
  937. (setq buffer-read-only t)
  938. (set-syntax-table text-mode-syntax-table)
  939. (make-local-variable 'rmail-buffer)
  940. (make-local-variable 'rmail-total-messages)
  941. (make-local-variable 'rmail-current-message)
  942. (setq rmail-current-message nil)
  943. (make-local-variable 'rmail-summary-redo)
  944. (setq rmail-summary-redo nil)
  945. (make-local-variable 'revert-buffer-function)
  946. (make-local-variable 'font-lock-defaults)
  947. (setq font-lock-defaults '(rmail-summary-font-lock-keywords t))
  948. (rmail-summary-enable)
  949. (run-mode-hooks 'rmail-summary-mode-hook))
  950. ;; Summary features need to be disabled during edit mode.
  951. (defun rmail-summary-disable ()
  952. (use-local-map text-mode-map)
  953. (remove-hook 'post-command-hook 'rmail-summary-rmail-update t)
  954. (setq revert-buffer-function nil))
  955. (defun rmail-summary-enable ()
  956. (use-local-map rmail-summary-mode-map)
  957. (add-hook 'post-command-hook 'rmail-summary-rmail-update nil t)
  958. (setq revert-buffer-function 'rmail-update-summary))
  959. (defun rmail-summary-mark-seen (n &optional nomove unseen)
  960. "Remove the unseen mark from the current message, update the summary vector.
  961. N is the number of the current message. Optional argument NOMOVE
  962. non-nil means we are already at the right column. Optional argument
  963. UNSEEN non-nil means mark the message as unseen."
  964. (save-excursion
  965. (unless nomove
  966. (beginning-of-line)
  967. (skip-chars-forward " ")
  968. (skip-chars-forward "0-9"))
  969. (when (char-equal (following-char) (if unseen ?\s ?-))
  970. (let ((buffer-read-only nil))
  971. (delete-char 1)
  972. (insert (if unseen "-" " ")))
  973. (let ((line (buffer-substring-no-properties (line-beginning-position)
  974. (line-beginning-position 2))))
  975. (with-current-buffer rmail-buffer
  976. (aset rmail-summary-vector (1- n) line))))))
  977. (defvar rmail-summary-put-back-unseen nil
  978. "Used for communicating between calls to `rmail-summary-rmail-update'.
  979. If it moves to a message within an Incremental Search, and removes
  980. the `unseen' attribute from that message, it sets this flag
  981. so that if the next motion between messages is in the same Incremental
  982. Search, the `unseen' attribute is restored.")
  983. ;; Show in Rmail the message described by the summary line that point is on,
  984. ;; but only if the Rmail buffer is already visible.
  985. ;; This is a post-command-hook in summary buffers.
  986. (defun rmail-summary-rmail-update ()
  987. (let (buffer-read-only)
  988. (save-excursion
  989. ;; If at end of buffer, pretend we are on the last text line.
  990. (if (eobp)
  991. (forward-line -1))
  992. (beginning-of-line)
  993. (skip-chars-forward " ")
  994. (let ((msg-num (string-to-number (buffer-substring
  995. (point)
  996. (progn (skip-chars-forward "0-9")
  997. (point))))))
  998. ;; Always leave `unseen' removed
  999. ;; if we get out of isearch mode.
  1000. ;; Don't let a subsequent isearch restore that `unseen'.
  1001. (if (not isearch-mode)
  1002. (setq rmail-summary-put-back-unseen nil))
  1003. (or (eq rmail-current-message msg-num)
  1004. (let ((window (get-buffer-window rmail-buffer t))
  1005. (owin (selected-window)))
  1006. (if isearch-mode
  1007. (progn
  1008. ;; If we first saw the previous message in this search,
  1009. ;; and we have gone to a different message while searching,
  1010. ;; put back `unseen' on the former one.
  1011. (when rmail-summary-put-back-unseen
  1012. (rmail-set-attribute rmail-unseen-attr-index t
  1013. rmail-current-message)
  1014. (save-excursion
  1015. (goto-char rmail-summary-put-back-unseen)
  1016. (rmail-summary-mark-seen rmail-current-message t t)))
  1017. ;; Arrange to do that later, for the new current message,
  1018. ;; if it still has `unseen'.
  1019. (setq rmail-summary-put-back-unseen
  1020. (if (rmail-message-unseen-p msg-num)
  1021. (point))))
  1022. (setq rmail-summary-put-back-unseen nil))
  1023. ;; Go to the desired message.
  1024. (setq rmail-current-message msg-num)
  1025. ;; Update the summary to show the message has been seen.
  1026. (rmail-summary-mark-seen msg-num t)
  1027. (if window
  1028. ;; Using save-window-excursion would cause the new value
  1029. ;; of point to get lost.
  1030. (unwind-protect
  1031. (progn
  1032. (select-window window)
  1033. (rmail-show-message msg-num t))
  1034. (select-window owin))
  1035. (if (buffer-name rmail-buffer)
  1036. (with-current-buffer rmail-buffer
  1037. (rmail-show-message msg-num t))))
  1038. ;; In linum mode, the message buffer must be specially
  1039. ;; updated (Bug#4878).
  1040. (and (fboundp 'linum-update)
  1041. (buffer-name rmail-buffer)
  1042. (linum-update rmail-buffer))))
  1043. (rmail-summary-update-highlight nil)))))
  1044. (defun rmail-summary-save-buffer ()
  1045. "Save the buffer associated with this RMAIL summary."
  1046. (interactive)
  1047. (save-window-excursion
  1048. (save-excursion
  1049. (switch-to-buffer rmail-buffer)
  1050. (save-buffer))))
  1051. (defun rmail-summary-mouse-goto-message (event)
  1052. "Select the message whose summary line you click on."
  1053. (interactive "@e")
  1054. (goto-char (posn-point (event-end event)))
  1055. (rmail-summary-goto-msg))
  1056. (defun rmail-summary-goto-msg (&optional n nowarn skip-rmail)
  1057. "Go to message N in the summary buffer and the Rmail buffer.
  1058. If N is nil, use the message corresponding to point in the summary
  1059. and move to that message in the Rmail buffer.
  1060. If NOWARN, don't say anything if N is out of range.
  1061. If SKIP-RMAIL, don't do anything to the Rmail buffer.
  1062. Returns non-nil if message N was found."
  1063. (interactive "P")
  1064. (if (consp n) (setq n (prefix-numeric-value n)))
  1065. (if (eobp) (forward-line -1))
  1066. (beginning-of-line)
  1067. (let* ((obuf (current-buffer))
  1068. (buf rmail-buffer)
  1069. (cur (point))
  1070. message-not-found
  1071. (curmsg (string-to-number
  1072. (buffer-substring (point)
  1073. (min (point-max) (+ 6 (point))))))
  1074. (total (with-current-buffer buf rmail-total-messages)))
  1075. ;; If message number N was specified, find that message's line
  1076. ;; or set message-not-found.
  1077. ;; If N wasn't specified or that message can't be found.
  1078. ;; set N by default.
  1079. (if (not n)
  1080. (setq n curmsg)
  1081. (if (< n 1)
  1082. (progn (message "No preceding message")
  1083. (setq n 1)))
  1084. (if (and (> n total)
  1085. (> total 0))
  1086. (progn (message "No following message")
  1087. (goto-char (point-max))
  1088. (rmail-summary-goto-msg nil nowarn skip-rmail)))
  1089. (goto-char (point-min))
  1090. (if (not (re-search-forward (format "^%5d[^0-9]" n) nil t))
  1091. (progn (or nowarn (message "Message %d not found" n))
  1092. (setq n curmsg)
  1093. (setq message-not-found t)
  1094. (goto-char cur))))
  1095. (rmail-summary-mark-seen n)
  1096. (rmail-summary-update-highlight message-not-found)
  1097. (beginning-of-line)
  1098. (unless skip-rmail
  1099. (let ((selwin (selected-window)))
  1100. (unwind-protect
  1101. (progn (rmail-pop-to-buffer buf)
  1102. (rmail-show-message n))
  1103. (select-window selwin)
  1104. ;; The actions above can alter the current buffer. Preserve it.
  1105. (set-buffer obuf))))
  1106. (not message-not-found)))
  1107. ;; Update the highlighted line in an rmail summary buffer.
  1108. ;; That should be current. We highlight the line point is on.
  1109. ;; If NOT-FOUND is non-nil, we turn off highlighting.
  1110. (defun rmail-summary-update-highlight (not-found)
  1111. ;; Make sure we have an overlay to use.
  1112. (or rmail-summary-overlay
  1113. (progn
  1114. (make-local-variable 'rmail-summary-overlay)
  1115. (setq rmail-summary-overlay (make-overlay (point) (point)))
  1116. (overlay-put rmail-summary-overlay 'rmail-summary t)))
  1117. ;; If this message is in the summary, use the overlay to highlight it.
  1118. ;; Otherwise, don't highlight anything.
  1119. (if not-found
  1120. (overlay-put rmail-summary-overlay 'face nil)
  1121. (move-overlay rmail-summary-overlay
  1122. (save-excursion (beginning-of-line)
  1123. (skip-chars-forward " ")
  1124. (point))
  1125. (line-end-position))
  1126. (overlay-put rmail-summary-overlay 'face 'highlight)))
  1127. (defun rmail-summary-scroll-msg-up (&optional dist)
  1128. "Scroll the Rmail window forward.
  1129. If the Rmail window is displaying the end of a message,
  1130. advance to the next message."
  1131. (interactive "P")
  1132. (if (eq dist '-)
  1133. (rmail-summary-scroll-msg-down nil)
  1134. (let ((rmail-buffer-window (get-buffer-window rmail-buffer)))
  1135. (if rmail-buffer-window
  1136. (if (let ((rmail-summary-window (selected-window)))
  1137. (select-window rmail-buffer-window)
  1138. (prog1
  1139. ;; Is EOB visible in the buffer?
  1140. (save-excursion
  1141. (let ((ht (window-height (selected-window))))
  1142. (move-to-window-line (- ht 2))
  1143. (end-of-line)
  1144. (eobp)))
  1145. (select-window rmail-summary-window)))
  1146. (if (not rmail-summary-scroll-between-messages)
  1147. (error "End of buffer")
  1148. (rmail-summary-next-msg (or dist 1)))
  1149. (let ((other-window-scroll-buffer rmail-buffer))
  1150. (scroll-other-window dist)))
  1151. ;; If it isn't visible at all, show the beginning.
  1152. (rmail-summary-beginning-of-message)))))
  1153. (defun rmail-summary-scroll-msg-down (&optional dist)
  1154. "Scroll the Rmail window backward.
  1155. If the Rmail window is now displaying the beginning of a message,
  1156. move to the previous message."
  1157. (interactive "P")
  1158. (if (eq dist '-)
  1159. (rmail-summary-scroll-msg-up nil)
  1160. (let ((rmail-buffer-window (get-buffer-window rmail-buffer)))
  1161. (if rmail-buffer-window
  1162. (if (let ((rmail-summary-window (selected-window)))
  1163. (select-window rmail-buffer-window)
  1164. (prog1
  1165. ;; Is BOB visible in the buffer?
  1166. (save-excursion
  1167. (move-to-window-line 0)
  1168. (beginning-of-line)
  1169. (bobp))
  1170. (select-window rmail-summary-window)))
  1171. (if (not rmail-summary-scroll-between-messages)
  1172. (error "Beginning of buffer")
  1173. (rmail-summary-previous-msg (or dist 1)))
  1174. (let ((other-window-scroll-buffer rmail-buffer))
  1175. (scroll-other-window-down dist)))
  1176. ;; If it isn't visible at all, show the beginning.
  1177. (rmail-summary-beginning-of-message)))))
  1178. (defun rmail-summary-beginning-of-message ()
  1179. "Show current message from the beginning."
  1180. (interactive)
  1181. (rmail-summary-show-message 'BEG))
  1182. (defun rmail-summary-end-of-message ()
  1183. "Show bottom of current message."
  1184. (interactive)
  1185. (rmail-summary-show-message 'END))
  1186. (defun rmail-summary-show-message (where)
  1187. "Show current mail message.
  1188. Position it according to WHERE which can be BEG or END"
  1189. (if (and (one-window-p) (not pop-up-frames))
  1190. ;; If there is just one window, put the summary on the top.
  1191. (let ((buffer rmail-buffer))
  1192. (split-window (selected-window) rmail-summary-window-size)
  1193. (select-window (frame-first-window))
  1194. (rmail-pop-to-buffer rmail-buffer)
  1195. ;; If pop-to-buffer did not use that window, delete that
  1196. ;; window. (This can happen if it uses another frame.)
  1197. (or (eq buffer (window-buffer (next-window (frame-first-window))))
  1198. (delete-other-windows)))
  1199. (rmail-pop-to-buffer rmail-buffer))
  1200. (cond
  1201. ((eq where 'BEG)
  1202. (goto-char (point-min))
  1203. (search-forward "\n\n"))
  1204. ((eq where 'END)
  1205. (goto-char (point-max))
  1206. (recenter (1- (window-height))))
  1207. )
  1208. (rmail-pop-to-buffer rmail-summary-buffer))
  1209. (defun rmail-summary-bury ()
  1210. "Bury the Rmail buffer and the Rmail summary buffer."
  1211. (interactive)
  1212. (let ((buffer-to-bury (current-buffer)))
  1213. (let (window)
  1214. (while (setq window (get-buffer-window rmail-buffer))
  1215. (set-window-buffer window (other-buffer rmail-buffer)))
  1216. (bury-buffer rmail-buffer))
  1217. (switch-to-buffer (other-buffer buffer-to-bury))
  1218. (bury-buffer buffer-to-bury)))
  1219. (defun rmail-summary-quit ()
  1220. "Quit out of Rmail and Rmail summary."
  1221. (interactive)
  1222. (rmail-summary-wipe)
  1223. (rmail-quit))
  1224. (defun rmail-summary-wipe ()
  1225. "Kill and wipe away Rmail summary, remaining within Rmail."
  1226. (interactive)
  1227. (with-current-buffer rmail-buffer (setq rmail-summary-buffer nil))
  1228. (let ((local-rmail-buffer rmail-buffer))
  1229. (kill-buffer (current-buffer))
  1230. ;; Delete window if not only one.
  1231. (if (not (eq (selected-window) (next-window nil 'no-minibuf)))
  1232. (delete-window))
  1233. ;; Switch windows to the rmail buffer, or switch to it in this window.
  1234. (rmail-pop-to-buffer local-rmail-buffer)))
  1235. (defun rmail-summary-expunge ()
  1236. "Actually erase all deleted messages and recompute summary headers."
  1237. (interactive)
  1238. (with-current-buffer rmail-buffer
  1239. (when (rmail-expunge-confirmed)
  1240. (rmail-only-expunge)))
  1241. (rmail-update-summary))
  1242. (defun rmail-summary-expunge-and-save ()
  1243. "Expunge and save RMAIL file."
  1244. (interactive)
  1245. (save-excursion
  1246. (rmail-expunge-and-save))
  1247. (rmail-update-summary)
  1248. (set-buffer-modified-p nil))
  1249. (defun rmail-summary-get-new-mail (&optional file-name)
  1250. "Get new mail and recompute summary headers.
  1251. Optionally you can specify the file to get new mail from. In this case,
  1252. the file of new mail is not changed or deleted. Noninteractively, you can
  1253. pass the inbox file name as an argument. Interactively, a prefix
  1254. argument says to read a file name and use that file as the inbox."
  1255. (interactive
  1256. (list (if current-prefix-arg
  1257. (read-file-name "Get new mail from file: "))))
  1258. (let (msg)
  1259. (with-current-buffer rmail-buffer
  1260. (rmail-get-new-mail file-name)
  1261. ;; Get the proper new message number.
  1262. (setq msg rmail-current-message))
  1263. ;; Make sure that message is displayed.
  1264. (or (zerop msg)
  1265. (rmail-summary-goto-msg msg))))
  1266. (defun rmail-summary-input (filename)
  1267. "Run Rmail on file FILENAME."
  1268. (interactive "FRun rmail on RMAIL file: ")
  1269. ;; We switch windows here, then display the other Rmail file there.
  1270. (rmail-pop-to-buffer rmail-buffer)
  1271. (rmail filename))
  1272. (defun rmail-summary-first-message ()
  1273. "Show first message in Rmail file from summary buffer."
  1274. (interactive)
  1275. (with-no-warnings
  1276. (beginning-of-buffer)))
  1277. (defun rmail-summary-last-message ()
  1278. "Show last message in Rmail file from summary buffer."
  1279. (interactive)
  1280. (with-no-warnings
  1281. (end-of-buffer))
  1282. (forward-line -1))
  1283. (declare-function rmail-abort-edit "rmailedit" ())
  1284. (declare-function rmail-cease-edit "rmailedit"())
  1285. (declare-function rmail-set-label "rmailkwd" (l state &optional n))
  1286. (declare-function rmail-output-read-file-name "rmailout" ())
  1287. (declare-function mail-send-and-exit "sendmail" (&optional arg))
  1288. (defvar rmail-summary-edit-map nil)
  1289. (if rmail-summary-edit-map
  1290. nil
  1291. (setq rmail-summary-edit-map
  1292. (nconc (make-sparse-keymap) text-mode-map))
  1293. (define-key rmail-summary-edit-map "\C-c\C-c" 'rmail-cease-edit)
  1294. (define-key rmail-summary-edit-map "\C-c\C-]" 'rmail-abort-edit))
  1295. (defun rmail-summary-edit-current-message ()
  1296. "Edit the contents of this message."
  1297. (interactive)
  1298. (rmail-pop-to-buffer rmail-buffer)
  1299. (rmail-edit-current-message)
  1300. (use-local-map rmail-summary-edit-map))
  1301. (defun rmail-summary-cease-edit ()
  1302. "Finish editing message, then go back to Rmail summary buffer."
  1303. (interactive)
  1304. (rmail-cease-edit)
  1305. (rmail-pop-to-buffer rmail-summary-buffer))
  1306. (defun rmail-summary-abort-edit ()
  1307. "Abort edit of current message; restore original contents.
  1308. Go back to summary buffer."
  1309. (interactive)
  1310. (rmail-abort-edit)
  1311. (rmail-pop-to-buffer rmail-summary-buffer))
  1312. (defun rmail-summary-search-backward (regexp &optional n)
  1313. "Show message containing next match for REGEXP.
  1314. Prefix argument gives repeat count; negative argument means search
  1315. backwards (through earlier messages).
  1316. Interactively, empty argument means use same regexp used last time."
  1317. (interactive
  1318. (let* ((reversep (>= (prefix-numeric-value current-prefix-arg) 0))
  1319. (prompt
  1320. (concat (if reversep "Reverse " "") "Rmail search (regexp"))
  1321. regexp)
  1322. (setq prompt
  1323. (concat prompt
  1324. (if rmail-search-last-regexp
  1325. (concat ", default "
  1326. rmail-search-last-regexp "): ")
  1327. "): ")))
  1328. (setq regexp (read-string prompt))
  1329. (cond ((not (equal regexp ""))
  1330. (setq rmail-search-last-regexp regexp))
  1331. ((not rmail-search-last-regexp)
  1332. (error "No previous Rmail search string")))
  1333. (list rmail-search-last-regexp
  1334. (prefix-numeric-value current-prefix-arg))))
  1335. ;; Don't use save-excursion because that prevents point from moving
  1336. ;; properly in the summary buffer.
  1337. (with-current-buffer rmail-buffer
  1338. (rmail-search regexp (- n))))
  1339. (defun rmail-summary-search (regexp &optional n)
  1340. "Show message containing next match for REGEXP.
  1341. Prefix argument gives repeat count; negative argument means search
  1342. backwards (through earlier messages).
  1343. Interactively, empty argument means use same regexp used last time."
  1344. (interactive
  1345. (let* ((reversep (< (prefix-numeric-value current-prefix-arg) 0))
  1346. (prompt
  1347. (concat (if reversep "Reverse " "") "Rmail search (regexp"))
  1348. regexp)
  1349. (setq prompt
  1350. (concat prompt
  1351. (if rmail-search-last-regexp
  1352. (concat ", default "
  1353. rmail-search-last-regexp "): ")
  1354. "): ")))
  1355. (setq regexp (read-string prompt))
  1356. (cond ((not (equal regexp ""))
  1357. (setq rmail-search-last-regexp regexp))
  1358. ((not rmail-search-last-regexp)
  1359. (error "No previous Rmail search string")))
  1360. (list rmail-search-last-regexp
  1361. (prefix-numeric-value current-prefix-arg))))
  1362. ;; Don't use save-excursion because that prevents point from moving
  1363. ;; properly in the summary buffer.
  1364. (let ((buffer (current-buffer))
  1365. (selwin (selected-window)))
  1366. (unwind-protect
  1367. (progn
  1368. (rmail-pop-to-buffer rmail-buffer)
  1369. (rmail-search regexp n))
  1370. (select-window selwin)
  1371. (set-buffer buffer))))
  1372. (defun rmail-summary-toggle-header ()
  1373. "Show original message header if pruned header currently shown, or vice versa."
  1374. (interactive)
  1375. (save-window-excursion
  1376. (set-buffer rmail-buffer)
  1377. (rmail-toggle-header))
  1378. ;; Inside save-excursion, some changes to point in the RMAIL buffer are lost.
  1379. ;; Set point to point-min in the RMAIL buffer, if it is visible.
  1380. (let ((window (get-buffer-window rmail-buffer)))
  1381. (if window
  1382. ;; Using save-window-excursion would lose the new value of point.
  1383. (let ((owin (selected-window)))
  1384. (unwind-protect
  1385. (progn
  1386. (select-window window)
  1387. (goto-char (point-min)))
  1388. (select-window owin))))))
  1389. (defun rmail-summary-add-label (label)
  1390. "Add LABEL to labels associated with current Rmail message.
  1391. Completion is performed over known labels when reading."
  1392. (interactive (list (with-current-buffer rmail-buffer
  1393. (rmail-read-label "Add label"))))
  1394. (with-current-buffer rmail-buffer
  1395. (rmail-add-label label)))
  1396. (defun rmail-summary-kill-label (label)
  1397. "Remove LABEL from labels associated with current Rmail message.
  1398. Completion is performed over known labels when reading."
  1399. (interactive (list (with-current-buffer rmail-buffer
  1400. (rmail-read-label "Kill label"))))
  1401. (with-current-buffer rmail-buffer
  1402. (rmail-set-label label nil)))
  1403. ;;;; *** Rmail Summary Mailing Commands ***
  1404. (defun rmail-summary-override-mail-send-and-exit ()
  1405. "Replace bindings to `mail-send-and-exit' with `rmail-summary-send-and-exit'."
  1406. (use-local-map (copy-keymap (current-local-map)))
  1407. (dolist (key (where-is-internal 'mail-send-and-exit))
  1408. (define-key (current-local-map) key 'rmail-summary-send-and-exit)))
  1409. (defun rmail-summary-mail ()
  1410. "Send mail in another window.
  1411. While composing the message, use \\[mail-yank-original] to yank the
  1412. original message into it."
  1413. (interactive)
  1414. (let ((window (get-buffer-window rmail-buffer)))
  1415. (if window
  1416. (select-window window)
  1417. (set-buffer rmail-buffer)))
  1418. (rmail-start-mail nil nil nil nil nil (current-buffer))
  1419. (rmail-summary-override-mail-send-and-exit))
  1420. (defun rmail-summary-continue ()
  1421. "Continue composing outgoing message previously being composed."
  1422. (interactive)
  1423. (let ((window (get-buffer-window rmail-buffer)))
  1424. (if window
  1425. (select-window window)
  1426. (set-buffer rmail-buffer)))
  1427. (rmail-start-mail t))
  1428. (defun rmail-summary-reply (just-sender)
  1429. "Reply to the current message.
  1430. Normally include CC: to all other recipients of original message;
  1431. prefix argument means ignore them. While composing the reply,
  1432. use \\[mail-yank-original] to yank the original message into it."
  1433. (interactive "P")
  1434. (let ((window (get-buffer-window rmail-buffer)))
  1435. (if window
  1436. (select-window window)
  1437. (set-buffer rmail-buffer)))
  1438. (rmail-reply just-sender)
  1439. (rmail-summary-override-mail-send-and-exit))
  1440. (defun rmail-summary-retry-failure ()
  1441. "Edit a mail message which is based on the contents of the current message.
  1442. For a message rejected by the mail system, extract the interesting headers and
  1443. the body of the original message; otherwise copy the current message."
  1444. (interactive)
  1445. (let ((window (get-buffer-window rmail-buffer)))
  1446. (if window
  1447. (select-window window)
  1448. (set-buffer rmail-buffer)))
  1449. (rmail-retry-failure)
  1450. (rmail-summary-override-mail-send-and-exit))
  1451. (defun rmail-summary-send-and-exit ()
  1452. "Send mail reply and return to summary buffer."
  1453. (interactive)
  1454. (mail-send-and-exit t))
  1455. (defun rmail-summary-forward (resend)
  1456. "Forward the current message to another user.
  1457. With prefix argument, \"resend\" the message instead of forwarding it;
  1458. see the documentation of `rmail-resend'."
  1459. (interactive "P")
  1460. (save-excursion
  1461. (let ((window (get-buffer-window rmail-buffer)))
  1462. (if window
  1463. (select-window window)
  1464. (set-buffer rmail-buffer)))
  1465. (rmail-forward resend)
  1466. (rmail-summary-override-mail-send-and-exit)))
  1467. (defun rmail-summary-resend ()
  1468. "Resend current message using `rmail-resend'."
  1469. (interactive)
  1470. (save-excursion
  1471. (let ((window (get-buffer-window rmail-buffer)))
  1472. (if window
  1473. (select-window window)
  1474. (set-buffer rmail-buffer)))
  1475. (call-interactively 'rmail-resend)))
  1476. ;; Summary output commands.
  1477. (defun rmail-summary-output (&optional file-name n)
  1478. "Append this message to mail file FILE-NAME.
  1479. This works with both mbox format and Babyl format files,
  1480. outputting in the appropriate format for each.
  1481. The default file name comes from `rmail-default-file',
  1482. which is updated to the name you use in this command.
  1483. A prefix argument N says to output that many consecutive messages
  1484. from those in the summary, starting with the current one.
  1485. Deleted messages are skipped and don't count.
  1486. When called from Lisp code, N may be omitted and defaults to 1.
  1487. This command always outputs the complete message header,
  1488. even the header display is currently pruned."
  1489. (interactive
  1490. (progn (require 'rmailout)
  1491. (list (rmail-output-read-file-name)
  1492. (prefix-numeric-value current-prefix-arg))))
  1493. (let ((i 0) prev-msg)
  1494. (while
  1495. (and (< i n)
  1496. (progn (rmail-summary-goto-msg)
  1497. (not (eq prev-msg
  1498. (setq prev-msg
  1499. (with-current-buffer rmail-buffer
  1500. rmail-current-message))))))
  1501. (setq i (1+ i))
  1502. (with-current-buffer rmail-buffer
  1503. (let ((rmail-delete-after-output nil))
  1504. (rmail-output file-name 1)))
  1505. (if rmail-delete-after-output
  1506. (rmail-summary-delete-forward nil)
  1507. (if (< i n)
  1508. (rmail-summary-next-msg 1))))))
  1509. (defalias 'rmail-summary-output-to-rmail-file 'rmail-summary-output)
  1510. (declare-function rmail-output-as-seen "rmailout"
  1511. (file-name &optional count noattribute from-gnus))
  1512. (defun rmail-summary-output-as-seen (&optional file-name n)
  1513. "Append this message to mbox file named FILE-NAME.
  1514. A prefix argument N says to output that many consecutive messages,
  1515. from the summary, starting with the current one.
  1516. Deleted messages are skipped and don't count.
  1517. When called from Lisp code, N may be omitted and defaults to 1.
  1518. This outputs the message header as you see it (or would see it)
  1519. displayed in Rmail.
  1520. The default file name comes from `rmail-default-file',
  1521. which is updated to the name you use in this command."
  1522. (interactive
  1523. (progn (require 'rmailout)
  1524. (list (rmail-output-read-file-name)
  1525. (prefix-numeric-value current-prefix-arg))))
  1526. (require 'rmailout) ; for rmail-output-as-seen in non-interactive case
  1527. (let ((i 0) prev-msg)
  1528. (while
  1529. (and (< i n)
  1530. (progn (rmail-summary-goto-msg)
  1531. (not (eq prev-msg
  1532. (setq prev-msg
  1533. (with-current-buffer rmail-buffer
  1534. rmail-current-message))))))
  1535. (setq i (1+ i))
  1536. (with-current-buffer rmail-buffer
  1537. (let ((rmail-delete-after-output nil))
  1538. (rmail-output-as-seen file-name 1)))
  1539. (if rmail-delete-after-output
  1540. (rmail-summary-delete-forward nil)
  1541. (if (< i n)
  1542. (rmail-summary-next-msg 1))))))
  1543. (defun rmail-summary-output-menu ()
  1544. "Output current message to another Rmail file, chosen with a menu.
  1545. Also set the default for subsequent \\[rmail-output-to-babyl-file] commands.
  1546. The variables `rmail-secondary-file-directory' and
  1547. `rmail-secondary-file-regexp' control which files are offered in the menu."
  1548. (interactive)
  1549. (with-current-buffer rmail-buffer
  1550. (let ((rmail-delete-after-output nil))
  1551. (call-interactively 'rmail-output-menu)))
  1552. (if rmail-delete-after-output
  1553. (rmail-summary-delete-forward nil)))
  1554. (defun rmail-summary-construct-io-menu ()
  1555. (let ((files (rmail-find-all-files rmail-secondary-file-directory)))
  1556. (if files
  1557. (progn
  1558. (define-key rmail-summary-mode-map [menu-bar classify input-menu]
  1559. (cons "Input Rmail File"
  1560. (rmail-list-to-menu "Input Rmail File"
  1561. files
  1562. 'rmail-summary-input)))
  1563. (define-key rmail-summary-mode-map [menu-bar classify output-menu]
  1564. (cons "Output Rmail File"
  1565. (rmail-list-to-menu "Output Rmail File"
  1566. files
  1567. 'rmail-summary-output))))
  1568. (define-key rmail-summary-mode-map [menu-bar classify input-menu]
  1569. '("Input Rmail File" . rmail-disable-menu))
  1570. (define-key rmail-summary-mode-map [menu-bar classify output-menu]
  1571. '("Output Rmail File" . rmail-disable-menu)))))
  1572. (defun rmail-summary-output-body (&optional file-name)
  1573. "Write this message body to the file FILE-NAME.
  1574. FILE-NAME defaults, interactively, from the Subject field of the message."
  1575. (interactive)
  1576. (with-current-buffer rmail-buffer
  1577. (let ((rmail-delete-after-output nil))
  1578. (if file-name
  1579. (rmail-output-body-to-file file-name)
  1580. (call-interactively 'rmail-output-body-to-file))))
  1581. (if rmail-delete-after-output
  1582. (rmail-summary-delete-forward nil)))
  1583. ;; Sorting messages in Rmail Summary buffer.
  1584. (defun rmail-summary-sort-by-date (reverse)
  1585. "Sort messages of current Rmail summary by \"Date\" header.
  1586. If prefix argument REVERSE is non-nil, sorts in reverse order."
  1587. (interactive "P")
  1588. (rmail-sort-from-summary (function rmail-sort-by-date) reverse))
  1589. (defun rmail-summary-sort-by-subject (reverse)
  1590. "Sort messages of current Rmail summary by \"Subject\" header.
  1591. Ignores any \"Re: \" prefix. If prefix argument REVERSE is
  1592. non-nil, sorts in reverse order."
  1593. (interactive "P")
  1594. (rmail-sort-from-summary (function rmail-sort-by-subject) reverse))
  1595. (defun rmail-summary-sort-by-author (reverse)
  1596. "Sort messages of current Rmail summary by author.
  1597. This uses either the \"From\" or \"Sender\" header, downcased.
  1598. If prefix argument REVERSE is non-nil, sorts in reverse order."
  1599. (interactive "P")
  1600. (rmail-sort-from-summary (function rmail-sort-by-author) reverse))
  1601. (defun rmail-summary-sort-by-recipient (reverse)
  1602. "Sort messages of current Rmail summary by recipient.
  1603. This uses either the \"To\" or \"Apparently-To\" header, downcased.
  1604. If prefix argument REVERSE is non-nil, sorts in reverse order."
  1605. (interactive "P")
  1606. (rmail-sort-from-summary (function rmail-sort-by-recipient) reverse))
  1607. (defun rmail-summary-sort-by-correspondent (reverse)
  1608. "Sort messages of current Rmail summary by other correspondent.
  1609. This uses either the \"From\", \"Sender\", \"To\", or
  1610. \"Apparently-To\" header, downcased. Uses the first header not
  1611. excluded by `mail-dont-reply-to-names'. If prefix argument
  1612. REVERSE is non-nil, sorts in reverse order."
  1613. (interactive "P")
  1614. (rmail-sort-from-summary (function rmail-sort-by-correspondent) reverse))
  1615. (defun rmail-summary-sort-by-lines (reverse)
  1616. "Sort messages of current Rmail summary by the number of lines.
  1617. If prefix argument REVERSE is non-nil, sorts in reverse order."
  1618. (interactive "P")
  1619. (rmail-sort-from-summary (function rmail-sort-by-lines) reverse))
  1620. (defun rmail-summary-sort-by-labels (reverse labels)
  1621. "Sort messages of current Rmail summary by labels.
  1622. LABELS is a comma-separated list of labels.
  1623. If prefix argument REVERSE is non-nil, sorts in reverse order."
  1624. (interactive "P\nsSort by labels: ")
  1625. (rmail-sort-from-summary
  1626. (lambda (reverse) (rmail-sort-by-labels reverse labels))
  1627. reverse))
  1628. (defun rmail-sort-from-summary (sortfun reverse)
  1629. "Sort the Rmail buffer using sorting function SORTFUN.
  1630. Passes REVERSE to SORTFUN as its sole argument. Then regenerates
  1631. the summary. Note that the whole Rmail buffer is sorted, even if
  1632. the summary is only showing a subset of messages."
  1633. (require 'rmailsort)
  1634. (let ((selwin (selected-window)))
  1635. (unwind-protect
  1636. (progn (rmail-pop-to-buffer rmail-buffer)
  1637. (funcall sortfun reverse))
  1638. (select-window selwin))))
  1639. (provide 'rmailsum)
  1640. ;; Local Variables:
  1641. ;; generated-autoload-file: "rmail.el"
  1642. ;; End:
  1643. ;;; rmailsum.el ends here