(windows-1250, windows-125[2-8])
[bpt/emacs.git] / lisp / mh-e / mh-pick.el
CommitLineData
bdcfe844 1;;; mh-pick.el --- make a search pattern and search for a message in MH-E
c26cf6c8 2
f0d73c14 3;; Copyright (C) 1993, 1995, 2001, 2003, 2004 Free Software Foundation, Inc.
a1b4049d
BW
4
5;; Author: Bill Wohler <wohler@newt.com>
6;; Maintainer: Bill Wohler <wohler@newt.com>
7;; Keywords: mail
8;; See: mh-e.el
c26cf6c8 9
60370d40 10;; This file is part of GNU Emacs.
c26cf6c8 11
9b7bc076 12;; GNU Emacs is free software; you can redistribute it and/or modify
c26cf6c8
RS
13;; it under the terms of the GNU General Public License as published by
14;; the Free Software Foundation; either version 2, or (at your option)
15;; any later version.
16
9b7bc076 17;; GNU Emacs is distributed in the hope that it will be useful,
c26cf6c8
RS
18;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20;; GNU General Public License for more details.
21
22;; You should have received a copy of the GNU General Public License
b578f267
EN
23;; along with GNU Emacs; see the file COPYING. If not, write to the
24;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25;; Boston, MA 02111-1307, USA.
c26cf6c8
RS
26
27;;; Commentary:
28
bdcfe844 29;; Internal support for MH-E package.
c26cf6c8 30
847b8219
KH
31;;; Change Log:
32
c26cf6c8
RS
33;;; Code:
34
f0d73c14
BW
35(eval-when-compile (require 'mh-acros))
36(mh-require-cl)
c26cf6c8 37(require 'mh-e)
a1b4049d
BW
38(require 'easymenu)
39(require 'gnus-util)
c26cf6c8 40
847b8219
KH
41;;; Internal variables:
42
43(defvar mh-pick-mode-map (make-sparse-keymap)
44 "Keymap for searching folder.")
45
c3d9274a 46(defvar mh-searching-folder nil) ;Folder this pick is searching.
3d7ca223 47(defvar mh-searching-function nil)
c26cf6c8 48
f0d73c14
BW
49(defconst mh-pick-single-dash '(cc date from subject to)
50 "Search components that are supported by single-dash option in pick.")
51
c3d9274a 52;;;###mh-autoload
3d7ca223 53(defun mh-search-folder (folder window-config)
847b8219 54 "Search FOLDER for messages matching a pattern.
bdcfe844 55This function uses the MH command `pick' to do the work.
3d7ca223
BW
56Add the messages found to the sequence named `search'.
57Argument WINDOW-CONFIG is the current window configuration and is used when
58the search folder is dismissed."
59 (interactive (list (mh-prompt-for-folder "Search" mh-current-folder nil nil t)
60 (current-window-configuration)))
61 (let ((pick-folder (if (equal folder "+") mh-current-folder folder)))
62 (switch-to-buffer-other-window "search-pattern")
63 (if (or (zerop (buffer-size))
64 (not (y-or-n-p "Reuse pattern? ")))
65 (mh-make-pick-template)
66 (message ""))
67 (setq mh-searching-function 'mh-pick-do-search
924df208
BW
68 mh-searching-folder pick-folder)
69 (mh-make-local-vars 'mh-current-folder folder
70 'mh-previous-window-config window-config)
3d7ca223
BW
71 (message "%s" (substitute-command-keys
72 (concat "Type \\[mh-do-search] to search messages, "
73 "\\[mh-help] for help.")))))
c26cf6c8
RS
74
75(defun mh-make-pick-template ()
bdcfe844 76 "Initialize the current buffer with a template for a pick pattern."
3d7ca223 77 (let ((inhibit-read-only t)) (erase-buffer))
c26cf6c8 78 (insert "From: \n"
c3d9274a
BW
79 "To: \n"
80 "Cc: \n"
81 "Date: \n"
82 "Subject: \n"
83 "---------\n")
c26cf6c8
RS
84 (mh-pick-mode)
85 (goto-char (point-min))
3d7ca223
BW
86 (dotimes (i 5)
87 (add-text-properties (point) (1+ (point)) '(front-sticky t))
88 (add-text-properties (- (line-end-position) 2) (1- (line-end-position))
89 '(rear-nonsticky t))
90 (add-text-properties (point) (1- (line-end-position)) '(read-only t))
91 (forward-line))
92 (add-text-properties (point) (1+ (point)) '(front-sticky t))
93 (add-text-properties (point) (1- (line-end-position)) '(read-only t))
94 (goto-char (point-max)))
c26cf6c8 95
bdcfe844
BW
96;;; Menu extracted from mh-menubar.el V1.1 (31 July 2001)
97(easy-menu-define
98 mh-pick-menu mh-pick-mode-map "Menu for MH-E pick-mode"
99 '("Pick"
3d7ca223 100 ["Execute the Search" mh-pick-do-search t]))
bdcfe844
BW
101
102
103;;; Help Messages
104;;; Group messages logically, more or less.
105(defvar mh-pick-mode-help-messages
106 '((nil
3d7ca223
BW
107 "Search messages using pick: \\[mh-pick-do-search]\n"
108 "Search messages using index: \\[mh-index-do-search]\n"
bdcfe844
BW
109 "Move to a field by typing C-c C-f C-<field>\n"
110 "where <field> is the first letter of the desired field."))
111 "Key binding cheat sheet.
112
113This is an associative array which is used to show the most common commands.
114The key is a prefix char. The value is one or more strings which are
115concatenated together and displayed in the minibuffer if ? is pressed after
116the prefix character. The special key nil is used to display the
117non-prefixed commands.
118
119The substitutions described in `substitute-command-keys' are performed as
120well.")
121
c26cf6c8
RS
122(put 'mh-pick-mode 'mode-class 'special)
123
a1b4049d 124(define-derived-mode mh-pick-mode fundamental-mode "MH-Pick"
bdcfe844 125 "Mode for creating search templates in MH-E.\\<mh-pick-mode-map>
a1b4049d 126
847b8219
KH
127After each field name, enter the pattern to search for. If a field's
128value does not matter for the search, leave it empty. To search the
129entire message, supply the pattern in the \"body\" of the template.
130Each non-empty field must be matched for a message to be selected.
131To effect a logical \"or\", use \\[mh-search-folder] multiple times.
3d7ca223 132When you have finished, type \\[mh-pick-do-search] to do the search.
a1b4049d 133
bdcfe844
BW
134The value of `mh-pick-mode-hook' is a list of functions to be called,
135with no arguments, upon entry to this mode.
a1b4049d
BW
136
137\\{mh-pick-mode-map}"
138
c26cf6c8 139 (make-local-variable 'mh-searching-folder)
3d7ca223 140 (make-local-variable 'mh-searching-function)
bdcfe844 141 (make-local-variable 'mh-help-messages)
3d7ca223 142 (easy-menu-add mh-pick-menu)
bdcfe844
BW
143 (setq mh-help-messages mh-pick-mode-help-messages)
144 (run-hooks 'mh-pick-mode-hook))
c26cf6c8 145
3d7ca223
BW
146;;;###mh-autoload
147(defun mh-pick-do-search ()
148 "Find messages that match the qualifications in the current pattern buffer.
149Messages are searched for in the folder named in `mh-searching-folder'.
847b8219 150Add the messages found to the sequence named `search'."
c26cf6c8 151 (interactive)
3d7ca223
BW
152 (let ((pattern-list (mh-pick-parse-search-buffer))
153 (folder mh-searching-folder)
154 (new-buffer-flag nil)
155 (window-config mh-previous-window-config)
156 range pick-args msgs)
157 (unless pattern-list
158 (error "No search pattern specified"))
c26cf6c8 159 (save-excursion
3d7ca223
BW
160 (cond ((get-buffer folder)
161 (set-buffer folder)
162 (setq range (if (and mh-first-msg-num mh-last-msg-num)
163 (format "%d-%d" mh-first-msg-num mh-last-msg-num)
164 "all")))
c3d9274a 165 (t
3d7ca223
BW
166 (mh-make-folder folder)
167 (setq range "all")
168 (setq new-buffer-flag t))))
169 (setq pick-args (mh-pick-regexp-builder pattern-list))
170 (when pick-args
171 (setq msgs (mh-seq-from-command folder 'search
172 `("pick" ,folder ,range ,@pick-args))))
c26cf6c8 173 (message "Searching...done")
3d7ca223
BW
174 (if (not new-buffer-flag)
175 (switch-to-buffer folder)
176 (mh-scan-folder folder msgs)
177 (setq mh-previous-window-config window-config))
847b8219
KH
178 (mh-add-msgs-to-seq msgs 'search)
179 (delete-other-windows)))
c26cf6c8 180
3d7ca223
BW
181;;;###mh-autoload
182(defun mh-do-search ()
183 "Use the default searching function.
184If \\[mh-search-folder] was used to create the search pattern then pick is used
185to search the folder. Otherwise if \\[mh-index-search] was used then the
186indexing program specified in `mh-index-program' is used."
187 (interactive)
188 (if (symbolp mh-searching-function)
189 (funcall mh-searching-function)
190 (error "No searching function defined")))
191
bdcfe844
BW
192(defun mh-seq-from-command (folder seq command)
193 "In FOLDER, make a sequence named SEQ by executing COMMAND.
194COMMAND is a list. The first element is a program name
195and the subsequent elements are its arguments, all strings."
c26cf6c8 196 (let ((msg)
c3d9274a
BW
197 (msgs ())
198 (case-fold-search t))
c26cf6c8
RS
199 (save-excursion
200 (save-window-excursion
c3d9274a
BW
201 (if (eq 0 (apply 'mh-exec-cmd-quiet nil command))
202 ;; "pick" outputs one number per line
203 (while (setq msg (car (mh-read-msg-list)))
204 (setq msgs (cons msg msgs))
205 (forward-line 1))))
c26cf6c8 206 (set-buffer folder)
c3d9274a 207 (setq msgs (nreverse msgs)) ;put in ascending order
c26cf6c8
RS
208 msgs)))
209
3d7ca223
BW
210(defun mh-pick-parse-search-buffer ()
211 "Parse the search buffer contents.
212The function returns a alist. The car of each element is either the header name
213to search in or nil to search the whole message. The cdr of the element is the
214pattern to search."
215 (save-excursion
216 (let ((pattern-list ())
217 (in-body-flag nil)
218 start begin)
219 (goto-char (point-min))
220 (while (not (eobp))
221 (if (search-forward "--------" (line-end-position) t)
222 (setq in-body-flag t)
223 (beginning-of-line)
224 (setq begin (point))
225 (setq start (if in-body-flag
226 (point)
227 (search-forward ":" (line-end-position) t)
228 (point)))
229 (push (cons (and (not in-body-flag)
230 (intern (downcase
231 (buffer-substring-no-properties
232 begin (1- start)))))
233 (mh-index-parse-search-regexp
234 (buffer-substring-no-properties
235 start (line-end-position))))
236 pattern-list))
237 (forward-line))
238 pattern-list)))
239
240\f
241
242;; Functions specific to how pick works...
243(defun mh-pick-construct-regexp (expr component)
244 "Construct pick compatible expression corresponding to EXPR.
245COMPONENT is the component to search."
246 (cond ((atom expr) (list component expr))
247 ((eq (car expr) 'and)
248 `("-lbrace" ,@(mh-pick-construct-regexp (cadr expr) component) "-and"
249 ,@(mh-pick-construct-regexp (caddr expr) component) "-rbrace"))
250 ((eq (car expr) 'or)
251 `("-lbrace" ,@(mh-pick-construct-regexp (cadr expr) component) "-or"
252 ,@(mh-pick-construct-regexp (caddr expr) component) "-rbrace"))
253 ((eq (car expr) 'not)
254 `("-lbrace" "-not" ,@(mh-pick-construct-regexp (cadr expr) component)
255 "-rbrace"))
256 (t (error "Unknown operator '%s' seen" (car expr)))))
257
f0d73c14
BW
258;; All implementations of pick have special options -cc, -date, -from and
259;; -subject that allow to search for corresponding components. Any other
260;; component is searched using option --COMPNAME, for example: `pick
261;; --x-mailer mh-e'. Mailutils `pick' supports this option using a certain
262;; kludge, but it prefers the following syntax for this purpose:
263;; `--component=COMPNAME --pattern=PATTERN'.
264;; -- Sergey Poznyakoff, Aug 2003
3d7ca223
BW
265(defun mh-pick-regexp-builder (pattern-list)
266 "Generate pick search expression from PATTERN-LIST."
267 (let ((result ()))
268 (dolist (pattern pattern-list)
269 (when (cdr pattern)
270 (setq result `(,@result "-and" "-lbrace"
271 ,@(mh-pick-construct-regexp
f0d73c14
BW
272 (if (and (mh-variant-p 'mu-mh) (car pattern))
273 (format "--pattern=%s" (cdr pattern))
274 (cdr pattern))
275 (if (car pattern)
276 (cond
277 ((mh-variant-p 'mu-mh)
278 (format "--component=%s" (car pattern)))
279 ((member (car pattern) mh-pick-single-dash)
280 (format "-%s" (car pattern)))
281 (t
282 (format "--%s" (car pattern))))
283 "-search"))
3d7ca223
BW
284 "-rbrace"))))
285 (cdr result)))
c26cf6c8 286
bdcfe844
BW
287\f
288
c26cf6c8 289;;; Build the pick-mode keymap:
bdcfe844 290;;; If this changes, modify mh-pick-mode-help-messages accordingly, above.
a1b4049d 291(gnus-define-keys mh-pick-mode-map
c3d9274a 292 "\C-c?" mh-help
3d7ca223
BW
293 "\C-c\C-i" mh-index-do-search
294 "\C-c\C-p" mh-pick-do-search
295 "\C-c\C-c" mh-do-search
c3d9274a
BW
296 "\C-c\C-f\C-b" mh-to-field
297 "\C-c\C-f\C-c" mh-to-field
298 "\C-c\C-f\C-d" mh-to-field
299 "\C-c\C-f\C-f" mh-to-field
300 "\C-c\C-f\C-r" mh-to-field
301 "\C-c\C-f\C-s" mh-to-field
302 "\C-c\C-f\C-t" mh-to-field
303 "\C-c\C-fb" mh-to-field
304 "\C-c\C-fc" mh-to-field
305 "\C-c\C-fd" mh-to-field
306 "\C-c\C-ff" mh-to-field
307 "\C-c\C-fr" mh-to-field
308 "\C-c\C-fs" mh-to-field
309 "\C-c\C-ft" mh-to-field)
a1b4049d 310
bdcfe844
BW
311(provide 'mh-pick)
312
313;;; Local Variables:
c3d9274a 314;;; indent-tabs-mode: nil
bdcfe844
BW
315;;; sentence-end-double-space: nil
316;;; End:
60370d40 317
ab5796a9 318;;; arch-tag: aef2b271-7768-42bd-a782-9a14ba9f83f7
60370d40 319;;; mh-pick.el ends here