;;; mew-scan.el --- Scanning messages for Mew ;; Author: Kazu Yamamoto ;; Created: Oct 2, 1996 ;; Revised: Aug 31, 1999 ;;; Code: (defconst mew-scan-version "mew-scan.el version 0.28") (require 'mew) (defvar mew-summary-inbox-position (make-marker)) (defun mew-summary-get (&optional arg) "Get +inbox asynchronously." (interactive "P") (let ((inbox (mew-inbox-folder))) (if (get-buffer inbox) (switch-to-buffer inbox) (mew-summary-folder-create inbox)) (if (and mew-summary-trace-directory (mew-folder-localp inbox)) (cd (mew-expand-folder inbox))) (mew-summary-folder-cache-manage inbox) (if (and mew-summary-cache-use (mew-summary-folder-dir-newp)) (progn ;; scan the gap (or arg (goto-char (point-max))) (mew-summary-scan-body mew-prog-imls 'mew-summary-mode inbox mew-cs-scan (mew-input-range inbox mew-range-auto-alist mew-ask-range)) ;; wait for asynchronous process (if mew-xemacs-p (while mew-summary-buffer-process (accept-process-output) (sit-for 0.1));; to flush (while mew-summary-buffer-process (sit-for 1))))) (set-marker mew-summary-inbox-position (point) (current-buffer)) ;; for C-xC-x (or arg (goto-char (point-max))) (mew-summary-scan-body mew-prog-imget 'mew-summary-mode inbox mew-cs-scan))) (defun mew-summary-exchange-point () "Exchange the current point and the marker." (interactive) (mew-summary-only (and (equal (buffer-name) (mew-inbox-folder)) ;; xxx (marker-position mew-summary-inbox-position) (goto-char (marker-position mew-summary-inbox-position))))) (defun mew-summary-ls (&optional arg jump) "List this folder asynchronously." (interactive "P") (mew-summary-only (let* ((folder (buffer-name)) (askp mew-ask-range) (alist mew-range-auto-alist) scanp range lines) (mew-summary-folder-cache-manage folder) ;; check scanp before (mew-mark-clean) (cond ((interactive-p) (setq alist mew-range-interactive-alist) (setq askp t) (setq scanp t)) ((and mew-summary-cache-use mew-summary-imap-cache (not (member folder mew-summary-imap-nocache-folders)) (mew-folder-imapp folder) (file-exists-p (mew-expand-folder folder mew-summary-cache-file))) (setq scanp t)) ((mew-folder-remotep folder) ;; xxx (setq alist mew-range-interactive-alist) (setq askp t) (setq scanp t)) ((and mew-summary-cache-use (mew-summary-folder-dir-newp)) (setq scanp t))) ;; (mew-mark-clean) (set-buffer-modified-p nil) (if (or jump (mew-folder-imapp folder)) (goto-char (point-max))) (mew-buffers-setup folder) (if (not scanp) (or arg (goto-char (point-max))) (setq range (mew-input-range folder alist askp)) (or arg (goto-char (point-max))) (if (equal (car range) "all") (setq lines (mew-summary-mark-collect3 mew-mark-review))) (mew-summary-scan-body mew-prog-imls 'mew-summary-mode folder mew-cs-scan range nil nil lines))))) ;; ;; Scan ;; (defun mew-summary-scan-body (prog mode folder read &optional range folders grep reviews) (save-excursion (set-buffer (get-buffer-create folder)) (if (not (mew-summary-exclusive-p)) () (condition-case nil (let ((process-connection-type mew-connection-type1)) (buffer-disable-undo (current-buffer)) (if (not (equal major-mode mode)) (funcall mode)) (mew-window-configure (current-buffer) 'summary) (mew-current-set 'message nil) (mew-current-set 'part nil) (mew-current-set 'cache nil) (setq mew-summary-buffer-direction 'down) (mew-decode-syntax-delete) (cond ((string-match mew-prog-imget prog) (if (string= mew-config-imget mew-config-default) (message "Getting %s ..." folder) (message "Getting %s (%s)..." folder mew-config-imget))) ((string-match mew-prog-imls prog) (message "Listing %s ..." folder) (if (or (equal 'erase (car (cdr range))) (equal mode 'mew-virtual-mode)) (mew-erase-buffer)))) (setq mew-summary-buffer-start-point (point)) (setq mew-summary-buffer-string nil) ;; just in case (setq mew-summary-buffer-config mew-config-imget) (setq mew-summary-buffer-error nil) (setq mew-summary-buffer-wrong-pws nil) (mew-pioalet read mew-cs-pick mew-cs-pick (setq mew-summary-buffer-process (apply (function start-process) prog;; name (current-buffer) prog;; program (format "--width=%d" (if mew-summary-scan-width mew-summary-scan-width (if (< (window-width) 80) 80 (window-width)))) (format "--mimedecodequoted=%s" (if mew-decode-quoted "yes" "no")) (append mew-prog-im-arg ;; xxx (cond ((string-match mew-prog-imget prog) (append (list (concat "--config=" mew-summary-buffer-config) "--scaninboxonly=yes") mew-prog-imget-arg-list)) ((string-match mew-prog-imls prog) (cond ((equal mode 'mew-summary-mode) (append (list (format "--thread=%s" (if (mew-folder-newsp folder) "yes" "no"))) (list (concat "--src=" folder)) mew-prog-imls-arg-list (if (listp (car range)) (car range) (list (car range))))) ((equal mode 'mew-virtual-mode) (list (concat "--src=" (mew-join "," folders)) (concat "--grep=" grep)))))))))) (mew-set-process-cs mew-summary-buffer-process read mew-cs-dummy) (set-process-filter mew-summary-buffer-process 'mew-summary-scan-filter) (set-process-sentinel mew-summary-buffer-process 'mew-summary-scan-sentinel) (setq mew-summary-buffer-reviews reviews) (process-kill-without-query mew-summary-buffer-process)) (quit (set-process-sentinel mew-summary-buffer-process nil) (setq mew-summary-buffer-start-point nil) (setq mew-summary-buffer-process nil) (setq mew-summary-buffer-string nil) (setq mew-summary-buffer-reviews nil)))))) (defun mew-summary-scan-passwd (src) (let ((prompt "Enter password")) (if mew-use-imget-assoc (setq prompt (format "%s (%s)" prompt src)) (if (not (equal mew-summary-buffer-config mew-config-default)) (setq prompt (format "%s (%s)" prompt mew-summary-buffer-config)))) (setq prompt (concat prompt " : ")) (if mew-use-cached-passwd (mew-input-passwd prompt src) (mew-input-passwd prompt)))) (defmacro mew-summary-scan-filter-skip () '(setq mew-summary-buffer-string (concat (substring mew-summary-buffer-string 0 (match-beginning 0)) (substring mew-summary-buffer-string (match-end 0))))) (defun mew-summary-scan-filter (process string) (let* ((after-change-function nil) ;; XEmacs - obsolete variable, ignore warnings. (after-change-functions nil) (obuf (current-buffer)) (opos (point)) (omax (point-max)) (prog (process-name process)) (regex-wrong-pw (format "^%s: ERROR: invalid password (\\([^\)]+\\))[^\n]*\n" prog)) (regex-err (format "^%s: ERROR: \\([^\n]*\\)\n" prog)) (regex-imget-greeting "^imget: Getting new messages[^\n]*\n") (regex-passwd "^Password (\\([^\)]+\\))") wpw) ;; save-excursion is not usefule because sometime we want to ;; move the cursor forward. (set-buffer (process-buffer process)) ;; necessary (setq mew-summary-buffer-string (concat mew-summary-buffer-string string)) (if (string-match regex-wrong-pw mew-summary-buffer-string) (progn (setq wpw (mew-match 1 mew-summary-buffer-string)) (mew-passwd-set-passwd wpw nil) (setq mew-summary-buffer-wrong-pws (cons wpw mew-summary-buffer-wrong-pws)) (mew-summary-scan-filter-skip))) (if (string-match regex-err mew-summary-buffer-string) (progn (setq mew-summary-buffer-error (mew-match 1 mew-summary-buffer-string)) (mew-summary-scan-filter-skip))) (if (string-match regex-passwd mew-summary-buffer-string) (progn (process-send-string process (format "%s\n" (mew-summary-scan-passwd (mew-match 1 mew-summary-buffer-string)))) (setq mew-summary-buffer-string ""))) (if (string-match regex-imget-greeting mew-summary-buffer-string) (mew-summary-scan-filter-skip)) (while (string-match "^ *[0-9]+.*\n" mew-summary-buffer-string) (goto-char (point-max)) ;; the cursor moves forward! (mew-elet (insert (mew-match 0 mew-summary-buffer-string))) (setq mew-summary-buffer-string (substring mew-summary-buffer-string (match-end 0)))) (if (or (equal opos mew-summary-buffer-start-point) (not (equal opos omax))) ;; move the cursor to the original position. (goto-char opos)) (set-buffer obuf))) (defun mew-summary-scan-sentinel (process event) (let ((prog (process-name process)) folder) (save-excursion (set-buffer (process-buffer process)) ;; necessary (setq folder (buffer-name)) (cond (mew-summary-buffer-wrong-pws (cond (mew-use-imget-assoc (message "Password is wrong (%s)!" (mapconcat (function identity) mew-summary-buffer-wrong-pws ","))) ((not (equal mew-summary-buffer-config mew-config-default)) (message "Password is wrong (%s)!" mew-summary-buffer-config)) (t (message "Password is wrong!")))) ;; must be here (mew-summary-buffer-error (message "%s" mew-summary-buffer-error)) (t (mew-elet (let ((reviews mew-summary-buffer-reviews)) (goto-char (point-max)) (keep-lines (concat mew-summary-message-regex)) ;; save cache only when success (while reviews (goto-line (car reviews)) (mew-summary-mark-as mew-mark-review) (setq reviews (cdr reviews))) (mew-summary-folder-cache-save folder) (mew-highlight-mark-region mew-summary-buffer-start-point (point-max)) (cond ((string-match mew-prog-imget prog) ;; the last messages are examined. this is not friendly ;; to imget's assoc. But imget's assoc itself is awkward. (cond ((string-match (format "^%s: no \\(new \\)?message" prog) mew-summary-buffer-string) (message "No new message")) ((string-match (format "^%s: \\([0-9]+\\) message" prog) mew-summary-buffer-string) (message "%s message(s)" (mew-match 1 mew-summary-buffer-string))) (t (message "Getting %s ... done" folder)))) ((string-match mew-prog-imls prog) (message "Listing %s ... done" folder))))))) (set-buffer-modified-p nil) (setq mew-summary-buffer-start-point nil) (setq mew-summary-buffer-process nil) (setq mew-summary-buffer-string nil) (setq mew-summary-buffer-config nil) (setq mew-summary-buffer-error nil) (setq mew-summary-buffer-wrong-pws nil) (setq mew-summary-buffer-reviews nil) (cond ((string-match mew-prog-imget prog) ;; On PPP environment, executing "imget" lets the dial be up. ;; So, it's a good idea to flush queue at this time ;; if messages to be sent exist. (if (and mew-auto-flush-queue (mew-flushable-p)) (let ((mew-ask-flush-queue nil)) (sit-for 1) ; wait (mew-summary-flush-queue))))) (cond ((string-match mew-prog-imget prog) (run-hooks 'mew-summary-inc-sentinel-hook)) ((string-match mew-prog-imls prog) (run-hooks 'mew-summary-scan-sentinel-hook)))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; process control ;;; mew-summary-buffer-process is a key to see if exclusive ;; (defun mew-summary-exclusive-p () (cond ((eq mew-summary-buffer-process t) (message "Try again later.") nil) ;; not exclusive ((processp mew-summary-buffer-process) (message "%s is running. Try again later." (process-name mew-summary-buffer-process)) nil) ;; not exclusive (t t))) ;; exclusive (defun mew-summary-kill-subprocess () "\\ Kill a process in Summary mode such as 'imget' and 'imls'. Sometime a process accidentally remains in Summary mode. In this situation, you cannot execute '\\[mew-summary-get]', '\\[mew-summary-ls]', nor '\\[mew-summary-exec]'. Use this command to solve this problem." (interactive) (unwind-protect (if (null (processp mew-summary-buffer-process)) (message "No process to kill. This buffer is unlocked anyway.") (message "%s was killed" (process-name mew-summary-buffer-process)) (kill-process mew-summary-buffer-process)) (setq mew-summary-buffer-process nil))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; Summary file cache ;;; (defun mew-summary-compare-times (type) (let* ((dir (file-chase-links (mew-expand-folder (buffer-name)))) (tdir (if mew-touch-folder-p (mew-file-get-time (expand-file-name mew-summary-touch-file (mew-expand-folder dir))) (mew-file-get-time dir))) (cache (expand-file-name mew-summary-cache-file dir)) (tcache (mew-file-get-time cache)) (tbuf mew-summary-buffer-folder-cache-time) t1 t2) (cond ((eq type 'dir-cache) (setq t1 tdir) (setq t2 tcache)) ((eq type 'cache-buf) (setq t1 tcache) (setq t2 tbuf))) (cond ((null t1) nil) ((null t2) t) ;; do update ((> (nth 0 t1) (nth 0 t2)) t) ((= (nth 0 t1) (nth 0 t2)) (if (> (nth 1 t1) (nth 1 t2)) t nil)) ;; nil if equal (t nil)))) (defmacro mew-summary-folder-dir-newp () '(mew-summary-compare-times 'dir-cache)) (defmacro mew-summary-folder-cache-newp () '(mew-summary-compare-times 'cache-buf)) (defmacro mew-summary-folder-cache-updatep (folder) (` (and mew-summary-cache-use (or (mew-folder-localp (, folder)) (and mew-use-imap mew-summary-imap-cache (not (member (, folder) mew-summary-imap-nocache-folders)) (mew-folder-imapp (, folder))))))) (defun mew-summary-folder-cache-manage (folder) (switch-to-buffer folder) (if (mew-summary-folder-cache-updatep folder) (let ((cache (mew-expand-folder folder mew-summary-cache-file))) (if (and (file-exists-p cache) (or (mew-summary-folder-cache-newp) (mew-folder-imapp folder))) (mew-elet (mew-erase-buffer) (mew-frwlet mew-cs-scan mew-cs-dummy (insert-file-contents cache)) (setq mew-summary-buffer-folder-cache-time (mew-file-get-time cache)) (mew-summary-batch-unmark (list mew-mark-refile) nil) (mew-highlight-mark-region (point-min) (point-max)) (set-buffer-modified-p nil))))) (if (not (equal major-mode 'mew-summary-mode)) (mew-summary-mode))) (defun mew-summary-folder-cache-save (folder) (if (mew-summary-folder-cache-updatep folder) (let ((cache (mew-expand-folder (buffer-name) mew-summary-cache-file))) (if (file-writable-p cache) (save-restriction (widen) (if (mew-decode-syntax-p) (let ((cbuf (current-buffer)) (min (point-min)) (max (point-max)) (beg (mew-decode-syntax-begin)) (end (mew-decode-syntax-end))) (mew-set-buffer-tmp) (insert-buffer-substring cbuf min beg) (insert-buffer-substring cbuf end max) (mew-frwlet mew-cs-dummy mew-cs-scan (write-region (point-min) (point-max) cache nil 'no-msg)) (set-buffer cbuf)) (mew-frwlet mew-cs-dummy mew-cs-scan (write-region (point-min) (point-max) cache nil 'no-msg))) (setq mew-summary-buffer-folder-cache-time (mew-file-get-time cache))))))) (provide 'mew-scan) ;; ;; Config for imget ;; (defun mew-summary-config-imget () "Set the config value for imget." (interactive) (setq mew-config-imget (mew-input-config mew-config-imget))) ;;; Copyright Notice: ;; Copyright (C) 1996, 1997, 1998, 1999 Mew developing team. ;; All rights reserved. ;; Redistribution and use in source and binary forms, with or without ;; modification, are permitted provided that the following conditions ;; are met: ;; ;; 1. Redistributions of source code must retain the above copyright ;; notice, this list of conditions and the following disclaimer. ;; 2. Redistributions in binary form must reproduce the above copyright ;; notice, this list of conditions and the following disclaimer in the ;; documentation and/or other materials provided with the distribution. ;; 3. Neither the name of the team nor the names of its contributors ;; may be used to endorse or promote products derived from this software ;; without specific prior written permission. ;; ;; THIS SOFTWARE IS PROVIDED BY THE TEAM AND CONTRIBUTORS ``AS IS'' AND ;; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ;; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR ;; PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE TEAM OR CONTRIBUTORS BE ;; LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ;; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ;; SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ;; BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE ;; OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN ;; IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ;;; mew-scan.el ends here