1 ;;; mew-scan.el --- Scanning messages for Mew
3 ;; Author: Kazu Yamamoto <Kazu@Mew.org>
4 ;; Created: Oct 2, 1996
5 ;; Revised: Aug 31, 1999
9 (defconst mew-scan-version "mew-scan.el version 0.28")
13 (defvar mew-summary-inbox-position (make-marker))
15 (defun mew-summary-get (&optional arg)
16 "Get +inbox asynchronously."
18 (let ((inbox (mew-inbox-folder)))
19 (if (get-buffer inbox)
20 (switch-to-buffer inbox)
21 (mew-summary-folder-create inbox))
22 (if (and mew-summary-trace-directory (mew-folder-localp inbox))
23 (cd (mew-expand-folder inbox)))
24 (mew-summary-folder-cache-manage inbox)
25 (if (and mew-summary-cache-use (mew-summary-folder-dir-newp))
28 (or arg (goto-char (point-max)))
29 (mew-summary-scan-body mew-prog-imls
34 inbox mew-range-auto-alist mew-ask-range))
35 ;; wait for asynchronous process
37 (while mew-summary-buffer-process
38 (accept-process-output)
39 (sit-for 0.1));; to flush
40 (while mew-summary-buffer-process (sit-for 1)))))
41 (set-marker mew-summary-inbox-position (point) (current-buffer))
43 (or arg (goto-char (point-max)))
44 (mew-summary-scan-body mew-prog-imget
49 (defun mew-summary-exchange-point ()
50 "Exchange the current point and the marker."
53 (and (equal (buffer-name) (mew-inbox-folder)) ;; xxx
54 (marker-position mew-summary-inbox-position)
55 (goto-char (marker-position mew-summary-inbox-position)))))
57 (defun mew-summary-ls (&optional arg jump)
58 "List this folder asynchronously."
61 (let* ((folder (buffer-name))
63 (alist mew-range-auto-alist)
65 (mew-summary-folder-cache-manage folder)
66 ;; check scanp before (mew-mark-clean)
69 (setq alist mew-range-interactive-alist)
72 ((and mew-summary-cache-use mew-summary-imap-cache
73 (not (member folder mew-summary-imap-nocache-folders))
74 (mew-folder-imapp folder)
75 (file-exists-p (mew-expand-folder folder mew-summary-cache-file)))
77 ((mew-folder-remotep folder) ;; xxx
78 (setq alist mew-range-interactive-alist)
81 ((and mew-summary-cache-use (mew-summary-folder-dir-newp))
85 (set-buffer-modified-p nil)
86 (if (or jump (mew-folder-imapp folder)) (goto-char (point-max)))
87 (mew-buffers-setup folder)
89 (or arg (goto-char (point-max)))
90 (setq range (mew-input-range folder alist askp))
91 (or arg (goto-char (point-max)))
92 (if (equal (car range) "all")
93 (setq lines (mew-summary-mark-collect3 mew-mark-review)))
94 (mew-summary-scan-body mew-prog-imls
107 (defun mew-summary-scan-body (prog mode folder read &optional range folders grep reviews)
109 (set-buffer (get-buffer-create folder))
110 (if (not (mew-summary-exclusive-p))
113 (let ((process-connection-type mew-connection-type1))
114 (buffer-disable-undo (current-buffer))
115 (if (not (equal major-mode mode)) (funcall mode))
116 (mew-window-configure (current-buffer) 'summary)
117 (mew-current-set 'message nil)
118 (mew-current-set 'part nil)
119 (mew-current-set 'cache nil)
120 (setq mew-summary-buffer-direction 'down)
121 (mew-decode-syntax-delete)
123 ((string-match mew-prog-imget prog)
124 (if (string= mew-config-imget mew-config-default)
125 (message "Getting %s ..." folder)
126 (message "Getting %s (%s)..." folder mew-config-imget)))
127 ((string-match mew-prog-imls prog)
128 (message "Listing %s ..." folder)
129 (if (or (equal 'erase (car (cdr range)))
130 (equal mode 'mew-virtual-mode))
131 (mew-erase-buffer))))
132 (setq mew-summary-buffer-start-point (point))
133 (setq mew-summary-buffer-string nil) ;; just in case
134 (setq mew-summary-buffer-config mew-config-imget)
135 (setq mew-summary-buffer-error nil)
136 (setq mew-summary-buffer-wrong-pws nil)
138 read mew-cs-pick mew-cs-pick
139 (setq mew-summary-buffer-process
140 (apply (function start-process)
144 (format "--width=%d" (if mew-summary-scan-width
145 mew-summary-scan-width
146 (if (< (window-width) 80)
149 (format "--mimedecodequoted=%s" (if mew-decode-quoted
151 (append mew-prog-im-arg ;; xxx
153 ((string-match mew-prog-imget prog)
155 (list (concat "--config="
156 mew-summary-buffer-config)
157 "--scaninboxonly=yes")
158 mew-prog-imget-arg-list))
159 ((string-match mew-prog-imls prog)
161 ((equal mode 'mew-summary-mode)
163 (list (format "--thread=%s"
164 (if (mew-folder-newsp folder)
166 (list (concat "--src=" folder))
167 mew-prog-imls-arg-list
168 (if (listp (car range))
170 (list (car range)))))
171 ((equal mode 'mew-virtual-mode)
173 (concat "--src=" (mew-join "," folders))
174 (concat "--grep=" grep))))))))))
175 (mew-set-process-cs mew-summary-buffer-process read mew-cs-dummy)
176 (set-process-filter mew-summary-buffer-process
177 'mew-summary-scan-filter)
178 (set-process-sentinel mew-summary-buffer-process
179 'mew-summary-scan-sentinel)
180 (setq mew-summary-buffer-reviews reviews)
181 (process-kill-without-query mew-summary-buffer-process))
183 (set-process-sentinel mew-summary-buffer-process nil)
184 (setq mew-summary-buffer-start-point nil)
185 (setq mew-summary-buffer-process nil)
186 (setq mew-summary-buffer-string nil)
187 (setq mew-summary-buffer-reviews nil))))))
189 (defun mew-summary-scan-passwd (src)
190 (let ((prompt "Enter password"))
191 (if mew-use-imget-assoc
192 (setq prompt (format "%s (%s)" prompt src))
193 (if (not (equal mew-summary-buffer-config mew-config-default))
194 (setq prompt (format "%s (%s)" prompt mew-summary-buffer-config))))
195 (setq prompt (concat prompt " : "))
196 (if mew-use-cached-passwd
197 (mew-input-passwd prompt src)
198 (mew-input-passwd prompt))))
200 (defmacro mew-summary-scan-filter-skip ()
201 '(setq mew-summary-buffer-string
203 (substring mew-summary-buffer-string 0 (match-beginning 0))
204 (substring mew-summary-buffer-string (match-end 0)))))
206 (defun mew-summary-scan-filter (process string)
207 (let* ((after-change-function nil) ;; XEmacs - obsolete variable, ignore warnings.
208 (after-change-functions nil)
209 (obuf (current-buffer))
212 (prog (process-name process))
214 (format "^%s: ERROR: invalid password (\\([^\)]+\\))[^\n]*\n"
217 (format "^%s: ERROR: \\([^\n]*\\)\n" prog))
218 (regex-imget-greeting "^imget: Getting new messages[^\n]*\n")
219 (regex-passwd "^Password (\\([^\)]+\\))")
221 ;; save-excursion is not usefule because sometime we want to
222 ;; move the cursor forward.
223 (set-buffer (process-buffer process)) ;; necessary
224 (setq mew-summary-buffer-string (concat mew-summary-buffer-string string))
225 (if (string-match regex-wrong-pw mew-summary-buffer-string)
227 (setq wpw (mew-match 1 mew-summary-buffer-string))
228 (mew-passwd-set-passwd wpw nil)
229 (setq mew-summary-buffer-wrong-pws
230 (cons wpw mew-summary-buffer-wrong-pws))
231 (mew-summary-scan-filter-skip)))
232 (if (string-match regex-err mew-summary-buffer-string)
234 (setq mew-summary-buffer-error
235 (mew-match 1 mew-summary-buffer-string))
236 (mew-summary-scan-filter-skip)))
237 (if (string-match regex-passwd mew-summary-buffer-string)
241 (format "%s\n" (mew-summary-scan-passwd
242 (mew-match 1 mew-summary-buffer-string))))
243 (setq mew-summary-buffer-string "")))
244 (if (string-match regex-imget-greeting mew-summary-buffer-string)
245 (mew-summary-scan-filter-skip))
246 (while (string-match "^ *[0-9]+.*\n" mew-summary-buffer-string)
247 (goto-char (point-max))
248 ;; the cursor moves forward!
250 (insert (mew-match 0 mew-summary-buffer-string)))
251 (setq mew-summary-buffer-string
252 (substring mew-summary-buffer-string (match-end 0))))
253 (if (or (equal opos mew-summary-buffer-start-point)
254 (not (equal opos omax)))
255 ;; move the cursor to the original position.
259 (defun mew-summary-scan-sentinel (process event)
260 (let ((prog (process-name process))
263 (set-buffer (process-buffer process)) ;; necessary
264 (setq folder (buffer-name))
266 (mew-summary-buffer-wrong-pws
269 (message "Password is wrong (%s)!"
270 (mapconcat (function identity)
271 mew-summary-buffer-wrong-pws
273 ((not (equal mew-summary-buffer-config mew-config-default))
274 (message "Password is wrong (%s)!" mew-summary-buffer-config))
276 (message "Password is wrong!"))))
278 (mew-summary-buffer-error
279 (message "%s" mew-summary-buffer-error))
282 (let ((reviews mew-summary-buffer-reviews))
283 (goto-char (point-max))
284 (keep-lines (concat mew-summary-message-regex))
285 ;; save cache only when success
287 (goto-line (car reviews))
288 (mew-summary-mark-as mew-mark-review)
289 (setq reviews (cdr reviews)))
290 (mew-summary-folder-cache-save folder)
291 (mew-highlight-mark-region
292 mew-summary-buffer-start-point (point-max))
294 ((string-match mew-prog-imget prog)
295 ;; the last messages are examined. this is not friendly
296 ;; to imget's assoc. But imget's assoc itself is awkward.
298 ((string-match (format "^%s: no \\(new \\)?message" prog)
299 mew-summary-buffer-string)
300 (message "No new message"))
301 ((string-match (format "^%s: \\([0-9]+\\) message" prog)
302 mew-summary-buffer-string)
303 (message "%s message(s)"
304 (mew-match 1 mew-summary-buffer-string)))
306 (message "Getting %s ... done" folder))))
307 ((string-match mew-prog-imls prog)
308 (message "Listing %s ... done" folder)))))))
309 (set-buffer-modified-p nil)
310 (setq mew-summary-buffer-start-point nil)
311 (setq mew-summary-buffer-process nil)
312 (setq mew-summary-buffer-string nil)
313 (setq mew-summary-buffer-config nil)
314 (setq mew-summary-buffer-error nil)
315 (setq mew-summary-buffer-wrong-pws nil)
316 (setq mew-summary-buffer-reviews nil)
318 ((string-match mew-prog-imget prog)
319 ;; On PPP environment, executing "imget" lets the dial be up.
320 ;; So, it's a good idea to flush queue at this time
321 ;; if messages to be sent exist.
322 (if (and mew-auto-flush-queue (mew-flushable-p))
323 (let ((mew-ask-flush-queue nil))
325 (mew-summary-flush-queue)))))
327 ((string-match mew-prog-imget prog)
328 (run-hooks 'mew-summary-inc-sentinel-hook))
329 ((string-match mew-prog-imls prog)
330 (run-hooks 'mew-summary-scan-sentinel-hook))))))
332 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
335 ;;; mew-summary-buffer-process is a key to see if exclusive
338 (defun mew-summary-exclusive-p ()
340 ((eq mew-summary-buffer-process t)
341 (message "Try again later.")
342 nil) ;; not exclusive
343 ((processp mew-summary-buffer-process)
344 (message "%s is running. Try again later."
345 (process-name mew-summary-buffer-process))
346 nil) ;; not exclusive
349 (defun mew-summary-kill-subprocess ()
350 "\\<mew-summary-mode-map>
351 Kill a process in Summary mode such as 'imget' and 'imls'.
352 Sometime a process accidentally remains in Summary mode.
353 In this situation, you cannot execute '\\[mew-summary-get]', '\\[mew-summary-ls]', nor '\\[mew-summary-exec]'.
354 Use this command to solve this problem."
357 (if (null (processp mew-summary-buffer-process))
358 (message "No process to kill. This buffer is unlocked anyway.")
359 (message "%s was killed" (process-name mew-summary-buffer-process))
360 (kill-process mew-summary-buffer-process))
361 (setq mew-summary-buffer-process nil)))
363 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
365 ;;; Summary file cache
368 (defun mew-summary-compare-times (type)
369 (let* ((dir (file-chase-links (mew-expand-folder (buffer-name))))
370 (tdir (if mew-touch-folder-p
372 (expand-file-name mew-summary-touch-file
373 (mew-expand-folder dir)))
374 (mew-file-get-time dir)))
375 (cache (expand-file-name mew-summary-cache-file dir))
376 (tcache (mew-file-get-time cache))
377 (tbuf mew-summary-buffer-folder-cache-time)
380 ((eq type 'dir-cache)
383 ((eq type 'cache-buf)
388 ((null t2) t) ;; do update
389 ((> (nth 0 t1) (nth 0 t2)) t)
390 ((= (nth 0 t1) (nth 0 t2))
391 (if (> (nth 1 t1) (nth 1 t2)) t nil)) ;; nil if equal
394 (defmacro mew-summary-folder-dir-newp ()
395 '(mew-summary-compare-times 'dir-cache))
397 (defmacro mew-summary-folder-cache-newp ()
398 '(mew-summary-compare-times 'cache-buf))
400 (defmacro mew-summary-folder-cache-updatep (folder)
401 (` (and mew-summary-cache-use
402 (or (mew-folder-localp (, folder))
403 (and mew-use-imap mew-summary-imap-cache
404 (not (member (, folder) mew-summary-imap-nocache-folders))
405 (mew-folder-imapp (, folder)))))))
407 (defun mew-summary-folder-cache-manage (folder)
408 (switch-to-buffer folder)
409 (if (mew-summary-folder-cache-updatep folder)
410 (let ((cache (mew-expand-folder folder mew-summary-cache-file)))
411 (if (and (file-exists-p cache)
412 (or (mew-summary-folder-cache-newp) (mew-folder-imapp folder)))
416 mew-cs-scan mew-cs-dummy
417 (insert-file-contents cache))
418 (setq mew-summary-buffer-folder-cache-time
419 (mew-file-get-time cache))
420 (mew-summary-batch-unmark (list mew-mark-refile) nil)
421 (mew-highlight-mark-region (point-min) (point-max))
422 (set-buffer-modified-p nil)))))
423 (if (not (equal major-mode 'mew-summary-mode)) (mew-summary-mode)))
425 (defun mew-summary-folder-cache-save (folder)
426 (if (mew-summary-folder-cache-updatep folder)
427 (let ((cache (mew-expand-folder (buffer-name) mew-summary-cache-file)))
428 (if (file-writable-p cache)
431 (if (mew-decode-syntax-p)
432 (let ((cbuf (current-buffer))
435 (beg (mew-decode-syntax-begin))
436 (end (mew-decode-syntax-end)))
438 (insert-buffer-substring cbuf min beg)
439 (insert-buffer-substring cbuf end max)
441 mew-cs-dummy mew-cs-scan
442 (write-region (point-min) (point-max) cache nil 'no-msg))
445 mew-cs-dummy mew-cs-scan
446 (write-region (point-min) (point-max) cache nil 'no-msg)))
447 (setq mew-summary-buffer-folder-cache-time
448 (mew-file-get-time cache)))))))
456 (defun mew-summary-config-imget ()
457 "Set the config value for imget."
459 (setq mew-config-imget (mew-input-config mew-config-imget)))
461 ;;; Copyright Notice:
463 ;; Copyright (C) 1996, 1997, 1998, 1999 Mew developing team.
464 ;; All rights reserved.
466 ;; Redistribution and use in source and binary forms, with or without
467 ;; modification, are permitted provided that the following conditions
470 ;; 1. Redistributions of source code must retain the above copyright
471 ;; notice, this list of conditions and the following disclaimer.
472 ;; 2. Redistributions in binary form must reproduce the above copyright
473 ;; notice, this list of conditions and the following disclaimer in the
474 ;; documentation and/or other materials provided with the distribution.
475 ;; 3. Neither the name of the team nor the names of its contributors
476 ;; may be used to endorse or promote products derived from this software
477 ;; without specific prior written permission.
479 ;; THIS SOFTWARE IS PROVIDED BY THE TEAM AND CONTRIBUTORS ``AS IS'' AND
480 ;; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
481 ;; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
482 ;; PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE TEAM OR CONTRIBUTORS BE
483 ;; LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
484 ;; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
485 ;; SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
486 ;; BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
487 ;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
488 ;; OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
489 ;; IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
491 ;;; mew-scan.el ends here