From: teranisi Date: Fri, 29 Sep 2000 02:25:00 +0000 (+0000) Subject: * elmo2.el (elmo-generic-list-folder-unread): Rewrite. X-Git-Url: http://git.chise.org/gitweb/?a=commitdiff_plain;h=f59a2d0563078493d529e76c2b9833c24607a28c;p=elisp%2Fwanderlust.git * elmo2.el (elmo-generic-list-folder-unread): Rewrite. (elmo-list-folder-unread): Rewrite. (elmo-list-folder-important): Ditto. * elmo-util.el (elmo-filter-get-spec): Rewrite. (elmo-condition-parse-error): New inline function. (elmo-read-search-condition): New function. (elmo-read-search-condition-internal): Ditto. (elmo-parse-search-condition): Rewrite. (elmo-condition-parse): New function. (elmo-condition-parse-or-expr): Ditto. (elmo-condition-parse-and-expr): Ditto. (elmo-condition-parse-primitive): Ditto. (elmo-condition-parse-search-value): Ditto. (elmo-buffer-field-primitive-condition-match): Ditto. (elmo-buffer-field-condition-match): Rewrite. (elmo-file-field-condition-match): Ditto. * elmo-msgdb.el (elmo-msgdb-expand-path): Use `elmo-replace-msgid-as-filename' instead of `elmo-safe-filename'. * elmo-internal.el (elmo-internal-search): Set `number' and `number-list' argument of `elmo-file-field-condition-match'. * elmo-maildir.el (elmo-maildir-search): Ditto. * elmo-imap4.el (elmo-imap4-list-folder-unread): Use `msgdb' as argument instead of `mark-alist'. (elmo-imap4-list-folder-important): Use `msgdb' as argument instead of `overview'. * elmo-multi.el: Likewise. * elmo-pipe.el: Likewise. * elmo-imap4.el (elmo-imap4-search-internal-primitive): New function. (elmo-imap4-search-internal): Rewrite. (elmo-imap4-search): Ditto. * elmo-filter.el (elmo-filter-list-folder): Rewrite. (elmo-filter-list-folder-unread): Ditto. (elmo-filter-list-folder-important): Ditto. (elmo-filter-search): Rewrite. * elmo-cache.el (elmo-cache-search-all): Set `number' and `number-list' argument of `elmo-file-field-condition-match'. (elmo-cache-search): Ditto. * elmo-localdir.el: Likewise. * elmo-archive.el (elmo-archive-field-condition-match): Added argument number-list and pass it to `elmo-buffer-field-condition-match'. (elmo-archive-field-condition-match): Pass `number-list' to `elmo-archive-field-condition-match' --- diff --git a/elmo/ChangeLog b/elmo/ChangeLog index 9da5e25..6a74f79 100644 --- a/elmo/ChangeLog +++ b/elmo/ChangeLog @@ -1,3 +1,60 @@ +2000-09-29 Yuuichi Teranishi + + * elmo2.el (elmo-generic-list-folder-unread): Rewrite. + (elmo-list-folder-unread): Rewrite. + (elmo-list-folder-important): Ditto. + + * elmo-util.el (elmo-filter-get-spec): Rewrite. + (elmo-condition-parse-error): New inline function. + (elmo-read-search-condition): New function. + (elmo-read-search-condition-internal): Ditto. + (elmo-parse-search-condition): Rewrite. + (elmo-condition-parse): New function. + (elmo-condition-parse-or-expr): Ditto. + (elmo-condition-parse-and-expr): Ditto. + (elmo-condition-parse-primitive): Ditto. + (elmo-condition-parse-search-value): Ditto. + (elmo-buffer-field-primitive-condition-match): Ditto. + (elmo-buffer-field-condition-match): Rewrite. + (elmo-file-field-condition-match): Ditto. + + * elmo-msgdb.el (elmo-msgdb-expand-path): Use + `elmo-replace-msgid-as-filename' instead of `elmo-safe-filename'. + + * elmo-internal.el (elmo-internal-search): Set `number' and + `number-list' argument of `elmo-file-field-condition-match'. + + * elmo-maildir.el (elmo-maildir-search): Ditto. + + * elmo-imap4.el (elmo-imap4-list-folder-unread): Use + `msgdb' as argument instead of `mark-alist'. + (elmo-imap4-list-folder-important): Use `msgdb' as argument instead of + `overview'. + + * elmo-multi.el: Likewise. + + * elmo-pipe.el: Likewise. + + * elmo-imap4.el (elmo-imap4-search-internal-primitive): New function. + (elmo-imap4-search-internal): Rewrite. + (elmo-imap4-search): Ditto. + + * elmo-filter.el (elmo-filter-list-folder): Rewrite. + (elmo-filter-list-folder-unread): Ditto. + (elmo-filter-list-folder-important): Ditto. + (elmo-filter-search): Rewrite. + + * elmo-cache.el (elmo-cache-search-all): Set `number' and + `number-list' argument of `elmo-file-field-condition-match'. + (elmo-cache-search): Ditto. + + * elmo-localdir.el: Likewise. + + * elmo-archive.el (elmo-archive-field-condition-match): Added argument + number-list and pass it to `elmo-buffer-field-condition-match'. + (elmo-archive-field-condition-match): Pass `number-list' to + `elmo-archive-field-condition-match' + 2000-09-25 Yuuichi Teranishi * elmo-nntp.el (elmo-nntp-list-folder): Set current group after diff --git a/elmo/elmo-archive.el b/elmo/elmo-archive.el index dab0504..c96b003 100644 --- a/elmo/elmo-archive.el +++ b/elmo/elmo-archive.el @@ -971,7 +971,8 @@ TYPE specifies the archiver's symbol." ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Search functions -(defsubst elmo-archive-field-condition-match (spec number condition prefix) +(defsubst elmo-archive-field-condition-match (spec number number-list + condition prefix) (save-excursion (let* ((type (nth 2 spec)) (arc (elmo-archive-get-archive-name (nth 1 spec) type spec)) @@ -983,7 +984,7 @@ TYPE specifies the archiver's symbol." (elmo-archive-call-method method args t)) (elmo-set-buffer-multibyte default-enable-multibyte-characters) (decode-mime-charset-region (point-min)(point-max) elmo-mime-charset) - (elmo-buffer-field-condition-match condition)))))) + (elmo-buffer-field-condition-match condition number number-list)))))) (defun elmo-archive-search (spec condition &optional from-msgs) (let* (;;(args (elmo-string-to-list key)) @@ -996,7 +997,7 @@ TYPE specifies the archiver's symbol." (case-fold-search nil) ret-val) (while msgs - (if (elmo-archive-field-condition-match spec (car msgs) + (if (elmo-archive-field-condition-match spec (car msgs) msgs condition (nth 3 spec)) (setq ret-val (cons (car msgs) ret-val))) diff --git a/elmo/elmo-cache.el b/elmo/elmo-cache.el index 53b7823..4f81749 100644 --- a/elmo/elmo-cache.el +++ b/elmo/elmo-cache.el @@ -280,29 +280,33 @@ If KBYTES is kilo bytes (This value must be float)." ;; not directory. path)))))) -(defun elmo-cache-search-all (folder condition from-msgs) +(defun elmo-cache-search-all (folder condition) (let* ((number-alist (elmo-msgdb-number-load (elmo-msgdb-expand-path folder))) - (nalist number-alist) + (number-list (mapcar 'car number-alist)) (num (length number-alist)) cache-file ret-val case-fold-search msg percent i) (setq i 0) - (while nalist - (if (and (setq cache-file (elmo-cache-exists-p (cdr (car nalist)) + (while number-alist + (if (and (setq cache-file (elmo-cache-exists-p (cdr (car + number-alist)) folder - (car (car nalist)))) - (elmo-file-field-condition-match cache-file condition)) - (setq ret-val (append ret-val (list (caar nalist))))) + (car (car + number-alist)))) + (elmo-file-field-condition-match cache-file condition + (car (car number-alist)) + number-list)) + (setq ret-val (append ret-val (list (caar number-alist))))) (when (> num elmo-display-progress-threshold) (setq i (1+ i)) (setq percent (/ (* i 100) num)) (elmo-display-progress 'elmo-cache-search-all "Searching..." percent)) - (setq nalist (cdr nalist))) + (setq number-alist (cdr number-alist))) ret-val)) (defun elmo-cache-collect-sub-directories (init dir &optional recursively) @@ -696,7 +700,9 @@ Returning its cache buffer." (elmo-msgid-to-cache (cdr (assq (car msgs) number-alist))) (elmo-cache-get-folder-directory spec)) - condition) + condition + (car msgs) + msgs) (setq ret-val (cons (car msgs) ret-val))) (when (> num elmo-display-progress-threshold) (setq i (1+ i)) diff --git a/elmo/elmo-filter.el b/elmo/elmo-filter.el index 14b2731..2490bc6 100644 --- a/elmo/elmo-filter.el +++ b/elmo/elmo-filter.el @@ -66,85 +66,20 @@ (elmo-call-func (nth 2 spec) "delete-msgs" msgs)) (defun elmo-filter-list-folder (spec) - (let ((filter (nth 1 spec)) - (folder (nth 2 spec)) - numbers) - (cond - ((vectorp filter) - (cond ((string= (elmo-filter-key filter) - "last") - (setq numbers (elmo-list-folder folder)) - (nthcdr (max (- (length numbers) - (string-to-int (elmo-filter-value filter))) - 0) - numbers)) - ((string= (elmo-filter-key filter) - "first") - (setq numbers (elmo-list-folder folder)) - (let ((rest (nthcdr (string-to-int (elmo-filter-value filter) ) - numbers))) - (mapcar '(lambda (x) - (delete x numbers)) rest)) - numbers))) - ((listp filter) - (elmo-search folder filter))))) - -(defun elmo-filter-list-folder-unread (spec mark-alist unread-marks) - (let ((filter (nth 1 spec)) - (folder (nth 2 spec)) - msgs pair) - (cond - ((vectorp filter) - (cond ((string= (elmo-filter-key filter) - "last") - (setq msgs (elmo-list-folder-unread folder mark-alist - unread-marks)) - (nthcdr (max (- (length msgs) - (string-to-int (elmo-filter-value filter))) - 0) - msgs)) - ((string= (elmo-filter-key filter) - "first") - (setq msgs (elmo-list-folder-unread folder - mark-alist - unread-marks)) - (let ((rest (nthcdr (string-to-int (elmo-filter-value filter) ) - msgs))) - (mapcar '(lambda (x) - (delete x msgs)) rest)) - msgs))) - ((listp filter) - (elmo-list-filter - (elmo-search folder filter) - (elmo-list-folder-unread folder mark-alist unread-marks)))))) - -(defun elmo-filter-list-folder-important (spec overview) - (let ((filter (nth 1 spec)) - (folder (nth 2 spec)) - msgs pair) - (cond - ((vectorp filter) - (cond ((string= (elmo-filter-key filter) - "last") - (setq msgs (elmo-list-folder-important folder overview)) - (nthcdr (max (- (length msgs) - (string-to-int (elmo-filter-value filter))) - 0) - msgs)) - ((string= (elmo-filter-key filter) - "first") - (setq msgs (elmo-list-folder-important folder overview)) - (let ((rest (nthcdr (string-to-int (elmo-filter-value filter) ) - msgs))) - (mapcar '(lambda (x) - (delete x msgs)) rest)) - msgs))) - ((listp filter) - (elmo-list-filter - (mapcar - '(lambda (x) (elmo-msgdb-overview-entity-get-number x)) - overview) - (elmo-list-folder-important folder overview)))))) + (elmo-search (nth 2 spec) (nth 1 spec))) + +(defun elmo-filter-list-folder-unread (spec msgdb unread-marks) + (elmo-list-filter + (mapcar 'car (elmo-msgdb-get-number-alist msgdb)) + (elmo-list-folder-unread + (nth 2 spec) msgdb unread-marks))) + +(defun elmo-filter-list-folder-important (spec msgdb) + (elmo-list-filter + (mapcar 'car (elmo-msgdb-get-number-alist msgdb)) + (elmo-list-folder-important + (nth 2 spec) + msgdb))) (defun elmo-filter-max-of-folder (spec) (elmo-max-of-folder (nth 2 spec))) @@ -158,12 +93,12 @@ (defun elmo-filter-create-folder (spec) (elmo-create-folder (nth 2 spec))) -(defun elmo-filter-search (spec condition &optional numlist) +(defun elmo-filter-search (spec condition &optional from-msgs) ;; search from messages in this folder (elmo-list-filter - numlist - (elmo-call-func (nth 2 spec) "search" condition - (elmo-filter-list-folder spec)))) + from-msgs + (elmo-search (nth 2 spec) condition + (elmo-filter-list-folder spec)))) (defun elmo-filter-use-cache-p (spec number) (elmo-call-func (nth 2 spec) "use-cache-p" number)) diff --git a/elmo/elmo-imap4.el b/elmo/elmo-imap4.el index 4f9e9b8..66b8dc1 100644 --- a/elmo/elmo-imap4.el +++ b/elmo/elmo-imap4.el @@ -57,7 +57,7 @@ (defun-maybe sasl-digest-md5-digest-response (digest-challenge username passwd serv-type host &optional realm)) (defun-maybe starttls-negotiate (a)) - (defun-maybe elmo-generic-list-folder-unread (spec mark-alist unread-marks)) + (defun-maybe elmo-generic-list-folder-unread (spec msgdb unread-marks)) (defsubst-maybe utf7-decode-string (string &optional imap) string)) (defvar elmo-imap4-use-lock t @@ -730,12 +730,12 @@ BUFFER must be a single-byte buffer." numbers)) numbers))) -(defun elmo-imap4-list-folder-unread (spec mark-alist unread-marks) +(defun elmo-imap4-list-folder-unread (spec msgdb unread-marks) (if (elmo-imap4-use-flag-p spec) (elmo-imap4-list spec "unseen") - (elmo-generic-list-folder-unread spec mark-alist unread-marks))) + (elmo-generic-list-folder-unread spec msgdb unread-marks))) -(defun elmo-imap4-list-folder-important (spec overview) +(defun elmo-imap4-list-folder-important (spec msgdb) (and (elmo-imap4-use-flag-p spec) (elmo-imap4-list spec "flagged"))) @@ -744,10 +744,23 @@ BUFFER must be a single-byte buffer." (insert (, string)) (detect-mime-charset-region (point-min) (point-max))))) -(defun elmo-imap4-search-internal (session filter) +(defun elmo-imap4-search-internal-primitive (spec session filter from-msgs) (let ((search-key (elmo-filter-key filter)) + (imap-search-keys '("bcc" "body" "cc" "from" "subject" "to")) charset) (cond + ((string= "last" search-key) + (let ((numbers (or from-msgs (elmo-imap4-list-folder spec)))) + (nthcdr (max (- (length numbers) + (string-to-int (elmo-filter-value filter))) + 0) + numbers))) + ((string= "first" search-key) + (let* ((numbers (or from-msgs (elmo-imap4-list-folder spec))) + (rest (nthcdr (string-to-int (elmo-filter-value filter) ) + numbers))) + (mapcar '(lambda (x) (delete x numbers)) rest) + numbers)) ((or (string= "since" search-key) (string= "before" search-key)) (setq search-key (concat "sent" search-key)) @@ -755,16 +768,29 @@ BUFFER must be a single-byte buffer." (elmo-imap4-send-command-wait session (format (if elmo-imap4-use-uid - "uid search %s %s" - " search %s %s") + "uid search %s %s %s %s" + " search %s %s %s %s") + (if from-msgs + (concat + (unless elmo-imap4-use-uid "uid ") + (cdr + (elmo-imap4-make-number-set-list + from-msgs))) + "") + (if (eq (elmo-filter-type filter) + 'unmatch) + "not" "") search-key (elmo-date-get-description (elmo-date-get-datevec (elmo-filter-value filter))))) 'search)) (t - (setq charset (elmo-imap4-detect-search-charset - (elmo-filter-value filter))) + (setq charset + (if (eq (length (elmo-filter-value filter)) 0) + (setq charset 'us-ascii) + (elmo-imap4-detect-search-charset + (elmo-filter-value filter)))) (elmo-imap4-response-value (elmo-imap4-send-command-wait session (list @@ -773,33 +799,58 @@ BUFFER must be a single-byte buffer." "search CHARSET ") (elmo-imap4-astring (symbol-name charset)) + (if from-msgs + (concat + (unless elmo-imap4-use-uid "uid ") + (cdr + (elmo-imap4-make-number-set-list + from-msgs))) + "") (if (eq (elmo-filter-type filter) 'unmatch) " not " " ") - (format "%s " + (format "%s%s " + (if (member + (elmo-filter-key filter) + imap-search-keys) + "" + "header ") (elmo-filter-key filter)) (elmo-imap4-astring (encode-mime-charset-string (elmo-filter-value filter) charset)))) 'search))))) +(defun elmo-imap4-search-internal (spec session condition from-msgs) + (let (result) + (cond + ((vectorp condition) + (setq result (elmo-imap4-search-internal-primitive + spec session condition from-msgs))) + ((eq (car condition) 'and) + (setq result (elmo-imap4-search-internal spec session (nth 1 condition) + from-msgs) + result (elmo-list-filter result + (elmo-imap4-search-internal + spec session (nth 2 condition) + from-msgs)))) + ((eq (car condition) 'or) + (setq result (elmo-imap4-search-internal + spec session (nth 1 condition) from-msgs) + result (elmo-uniq-list + (nconc result + (elmo-imap4-search-internal + spec session (nth 2 condition) from-msgs))) + result (sort result '<)))))) + + (defun elmo-imap4-search (spec condition &optional from-msgs) (save-excursion - (let* ((session (elmo-imap4-get-session spec)) - response matched) + (let ((session (elmo-imap4-get-session spec))) (elmo-imap4-session-select-mailbox session (elmo-imap4-spec-mailbox spec)) - (while condition - (setq response (elmo-imap4-search-internal session - (car condition))) - (setq matched (nconc matched response)) - (setq condition (cdr condition))) - (if from-msgs - (elmo-list-filter - from-msgs - (elmo-uniq-list (sort matched '<))) - (elmo-uniq-list (sort matched '<)))))) + (elmo-imap4-search-internal spec session condition from-msgs)))) (defun elmo-imap4-use-flag-p (spec) (not (string-match elmo-imap4-disuse-server-flag-mailbox-regexp diff --git a/elmo/elmo-internal.el b/elmo/elmo-internal.el index aa297bf..1d69b68 100644 --- a/elmo/elmo-internal.el +++ b/elmo/elmo-internal.el @@ -237,6 +237,7 @@ (loc-alist (if msgdb (elmo-msgdb-get-location msgdb) (elmo-msgdb-location-load (elmo-msgdb-expand-path nil spec)))) + (number-list (mapcar 'car loc-alist)) cache-file ret-val case-fold-search msg @@ -246,7 +247,9 @@ (while loc-alist (if (and (setq cache-file (elmo-cache-exists-p (cdr (car loc-alist)))) (elmo-file-field-condition-match cache-file - condition)) + condition + (car (car loc-alist)) + number-list)) (setq ret-val (append ret-val (list (car (car loc-alist)))))) (setq i (1+ i)) (setq percent (/ (* i 100) num)) diff --git a/elmo/elmo-localdir.el b/elmo/elmo-localdir.el index af33d0e..c7865e2 100644 --- a/elmo/elmo-localdir.el +++ b/elmo/elmo-localdir.el @@ -357,19 +357,21 @@ (rename-file old new) t)))) -(defsubst elmo-localdir-field-condition-match (spec number condition) +(defsubst elmo-localdir-field-condition-match (spec condition + number number-list) (elmo-file-field-condition-match (expand-file-name (int-to-string number) (elmo-localdir-get-folder-directory spec)) - condition)) + condition + number number-list)) (defun elmo-localdir-search (spec condition &optional from-msgs) (let* ((msgs (or from-msgs (elmo-localdir-list-folder spec))) (num (length msgs)) (i 0) case-fold-search ret-val) (while msgs - (if (elmo-localdir-field-condition-match spec (car msgs) - condition) + (if (elmo-localdir-field-condition-match spec condition + (car msgs) msgs) (setq ret-val (cons (car msgs) ret-val))) (when (> num elmo-display-progress-threshold) (setq i (1+ i)) diff --git a/elmo/elmo-maildir.el b/elmo/elmo-maildir.el index 4ca4610..10a61a6 100644 --- a/elmo/elmo-maildir.el +++ b/elmo/elmo-maildir.el @@ -440,7 +440,7 @@ file name for maildir directories." (if (elmo-file-field-condition-match (elmo-maildir-number-to-filename dir (car msgs) loc-alist) - condition) + condition (car msgs) msgs) (setq ret-val (append ret-val (list msg-num)))) (setq i (1+ i)) (setq percent (/ (* i 100) num)) diff --git a/elmo/elmo-msgdb.el b/elmo/elmo-msgdb.el index 0e43a2f..c012ce0 100644 --- a/elmo/elmo-msgdb.el +++ b/elmo/elmo-msgdb.el @@ -78,7 +78,7 @@ elmo-msgdb-dir))) ((eq type 'filter) (expand-file-name - (elmo-safe-filename folder) + (elmo-replace-msgid-as-filename folder) (expand-file-name "filter" elmo-msgdb-dir))) ((eq type 'archive) diff --git a/elmo/elmo-multi.el b/elmo/elmo-multi.el index 0fb6397..06bf4fe 100644 --- a/elmo/elmo-multi.el +++ b/elmo/elmo-multi.el @@ -182,9 +182,10 @@ (setq result (nconc result (list one-alist)))) result)) -(defun elmo-multi-list-folder-unread (spec mark-alist unread-marks) +(defun elmo-multi-list-folder-unread (spec msgdb unread-marks) (let* ((flds (cdr spec)) (cur-number 0) + (mark-alist (elmo-msgdb-get-mark-alist msgdb)) mark-alist-list ret-val) (setq mark-alist-list (elmo-multi-mark-alist-list mark-alist)) @@ -204,7 +205,7 @@ (setq flds (cdr flds))) ret-val)) -(defun elmo-multi-list-folder-important (spec overview) +(defun elmo-multi-list-folder-important (spec msgdb) (let* ((flds (cdr spec)) (cur-number 0) ret-val) @@ -217,7 +218,8 @@ (lambda (x) (+ (* elmo-multi-divide-number cur-number) x))) - (elmo-list-folder-important (car flds) overview)))) + (elmo-list-folder-important (car flds) + msgdb)))) (setq flds (cdr flds))) ret-val)) diff --git a/elmo/elmo-pipe.el b/elmo/elmo-pipe.el index eb07743..fce64b7 100644 --- a/elmo/elmo-pipe.el +++ b/elmo/elmo-pipe.el @@ -89,11 +89,12 @@ numbers)) numbers))) -(defun elmo-pipe-list-folder-unread (spec mark-alist unread-marks) - (elmo-list-folder-unread (elmo-pipe-spec-dst spec) mark-alist unread-marks)) +(defun elmo-pipe-list-folder-unread (spec msgdb unread-marks) + (elmo-list-folder-unread (elmo-pipe-spec-dst spec) + msgdb unread-marks)) -(defun elmo-pipe-list-folder-important (spec overview) - (elmo-list-folder-important (elmo-pipe-spec-dst spec) overview)) +(defun elmo-pipe-list-folder-important (spec msgdb) + (elmo-list-folder-important (elmo-pipe-spec-dst spec) msgdb)) (defun elmo-pipe-max-of-folder (spec) (let* (elmo-pop3-use-uidl diff --git a/elmo/elmo-util.el b/elmo/elmo-util.el index 9af7aa9..174198a 100644 --- a/elmo/elmo-util.el +++ b/elmo/elmo-util.el @@ -446,23 +446,13 @@ File content is encoded with MIME-CHARSET." ","))))) (defun elmo-filter-get-spec (folder) - (save-match-data - (when (string-match - "^\\(/\\)\\(.*\\)$" - folder) - (let ((spec (elmo-match-string 2 folder)) - filter) - (when (string-match "\\([^/]+\\)/" spec) - (setq filter (elmo-match-string 1 spec)) - (setq spec (substring spec (match-end 0)))) - (cond - ((string-match "^\\(last\\|first\\):\\(.*\\)$" filter) ; partial - (setq filter (vector 'partial - (elmo-match-string 1 filter) - (elmo-match-string 2 filter)))) - (t - (setq filter (elmo-parse-search-condition filter)))) - (list 'filter filter spec))))) + (when (string-match "^\\(/\\)\\(.*\\)$" folder) + (let ((folder (elmo-match-string 2 folder)) + pair) + (setq pair (elmo-parse-search-condition folder)) + (if (string-match "^ */\\(.*\\)$" (cdr pair)) + (list 'filter (car pair) (elmo-match-string 1 (cdr pair))) + (error "Folder syntax error `%s'" folder))))) (defun elmo-pipe-get-spec (folder) (when (string-match "^\\(|\\)\\([^|]*\\)|\\(.*\\)$" folder) @@ -478,46 +468,145 @@ File content is encoded with MIME-CHARSET." folder) (error "%s is not supported folder type" folder)))) +;;; Search Condition +(defun elmo-read-search-condition (default) + "Read search condition string interactively" + (elmo-read-search-condition-internal "Search by" default)) + +(defun elmo-read-search-condition-internal (prompt default) + (let* ((completion-ignore-case t) + (field (completing-read + (format "%s (%s): " prompt default) + (mapcar 'list + (append '("AND" "OR" + "Last" "First" + "From" "Subject" "To" "Cc" "Body" + "Since" "Before" "ToCc" + "!From" "!Subject" "!To" "!Cc" "!Body" + "!Since" "!Before" "!ToCc") + elmo-msgdb-extra-fields))))) + (setq field (if (string= field "") + (setq field default) + field)) + (cond + ((or (string= field "AND") (string= field "OR")) + (concat "(" + (elmo-read-search-condition-internal + (concat field "(1) Search by") default) + (if (string= field "AND") "&" "|") + (elmo-read-search-condition-internal + (concat field "(2) Search by") default) + ")")) + ((string-match "Since\\|Before" field) + (concat + (downcase field) ":" + (completing-read (format "Value for '%s': " field) + (mapcar (function + (lambda (x) + (list (format "%s" (car x))))) + elmo-date-descriptions)))) + (t + (concat + (downcase field) ":" + (prin1-to-string + (read-from-minibuffer + (format "Value for '%s': " field)))))))) + +(defsubst elmo-condition-parse-error () + (error "Syntax error in '%s'" (buffer-string))) + (defun elmo-parse-search-condition (condition) - (let ((terms (split-string condition "|")) ; split by OR - term ret-val) - (while terms - (setq term (car terms)) - (cond - ((string-match "^\\([a-zA-Z\\-]+\\)=\\(.*\\)$" term) - (if (save-match-data - (string-match "tocc" (elmo-match-string 1 term))) ;; syntax sugar - (setq ret-val (nconc - ret-val - (list (vector 'match "to" - (elmo-match-string 2 term)) - (vector 'match "cc" - (elmo-match-string 2 term))))) - (setq ret-val (cons (vector 'match - (elmo-match-string 1 term) - (elmo-match-string 2 term)) - ret-val)))) - ((string-match "^\\([a-zA-Z\\-]+\\)!=\\(.*\\)$" term) - (if (save-match-data - (string-match "tocc" (elmo-match-string 1 term))) ;; syntax sugar - (setq ret-val (nconc - ret-val - (list (vector 'unmatch "to" - (elmo-match-string 2 term)) - (vector 'unmatch "cc" - (elmo-match-string 2 term))))) - (setq ret-val (cons (vector 'unmatch - (elmo-match-string 1 term) - (elmo-match-string 2 term)) - ret-val)))) - ((string-match "^\\(since\\|before\\):\\(.*\\)$" term) - (setq ret-val (cons (vector 'date - (elmo-match-string 1 term) - (elmo-match-string 2 term)) - ret-val)))) - (setq terms (cdr terms))) - ret-val)) + "Parse CONDITION. +Return value is a cons cell of (STRUCTURE . REST)" + (with-temp-buffer + (insert condition) + (goto-char (point-min)) + (cons (elmo-condition-parse) (buffer-substring (point) (point-max))))) + +;; condition ::= or-expr +(defun elmo-condition-parse () + (or (elmo-condition-parse-or-expr) + (elmo-condition-parse-error))) + +;; or-expr ::= and-expr / +;; and-expr "|" or-expr +(defun elmo-condition-parse-or-expr () + (let ((left (elmo-condition-parse-and-expr))) + (if (looking-at "| *") + (progn + (goto-char (match-end 0)) + (list 'or left (elmo-condition-parse-or-expr))) + left))) + +;; and-expr ::= primitive / +;; primitive "&" and-expr +(defun elmo-condition-parse-and-expr () + (let ((left (elmo-condition-parse-primitive))) + (if (looking-at "& *") + (progn + (goto-char (match-end 0)) + (list 'and left (elmo-condition-parse-and-expr))) + left))) + +;; primitive ::= "(" expr ")" / +;; ["!"] search-key SPACE* ":" SPACE* search-value +(defun elmo-condition-parse-primitive () + (cond + ((looking-at "( *") + (goto-char (match-end 0)) + (prog1 (elmo-condition-parse) + (unless (looking-at ") *") + (elmo-condition-parse-error)) + (goto-char (match-end 0)))) +;; search-key ::= [A-Za-z-]+ +;; ;; "since" / "before" / "last" / "first" / +;; ;; "body" / field-name + ((looking-at "\\(!\\)? *\\([A-Za-z-]+\\) *: *") + (goto-char (match-end 0)) + (let ((search-key (vector + (if (match-beginning 1) 'unmatch 'match) + (elmo-match-buffer 2) + (elmo-condition-parse-search-value)))) + ;; syntax sugar. + (if (string= (aref search-key 1) "tocc") + (if (eq (aref search-key 0) 'match) + (list 'or + (vector 'match "to" (aref search-key 2)) + (vector 'match "cc" (aref search-key 2))) + (list 'and + (vector 'unmatch "to" (aref search-key 2)) + (vector 'unmatch "cc" (aref search-key 2)))) + search-key))))) + +;; search-value ::= quoted / time / number / atom +;; quoted ::= +;; time ::= "yesterday" / "lastweek" / "lastmonth" / "lastyear" / +;; number SPACE* "daysago" / +;; number "-" month "-" number ; ex. 10-May-2000 +;; number ::= [0-9]+ +;; month ::= "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" / +;; "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec" +;; atom ::= ATOM_CHARS* +;; SPACE ::= +;; ATOM_CHARS ::= +;; specials ::= SPACE / <"> / / <)> / <|> / <&> +;; ;; These characters should be quoted. +(defun elmo-condition-parse-search-value () + (cond + ((looking-at "\"") + (read (current-buffer))) + ((or (looking-at "yesterday") (looking-at "lastweek") + (looking-at "lastmonth") (looking-at "lastyear") + (looking-at "[0-9]+ *daysago") + (looking-at "[0-9]+") + (looking-at "[0-9]+-[A-Za-z]+-[0-9]+") + (looking-at "[^/ \")|&]*") ; atom* (except quoted specials). + ) + (prog1 (elmo-match-buffer 0) + (goto-char (match-end 0)))) + (t (error "Syntax error '%s'" (buffer-string))))) +;;; (defun elmo-multi-get-real-folder-number (folder number) (let* ((spec (elmo-folder-get-spec folder)) (flds (cdr spec)) @@ -1120,73 +1209,80 @@ Otherwise treat \\ in NEWTEXT string as special: (defmacro elmo-filter-value (filter) (` (aref (, filter) 2))) -(defsubst elmo-buffer-field-condition-match (condition) - (let (term) - (catch 'done - (while condition - (goto-char (point-min)) - (setq term (car condition)) - (cond - ((and (eq (elmo-filter-type term) 'date) - (string= (elmo-filter-key term) "since")) - (let ((date (elmo-date-get-datevec (elmo-filter-value term)))) - (if (string< - (timezone-make-sortable-date (aref date 0) - (aref date 1) - (aref date 2) - (timezone-make-time-string - (aref date 3) - (aref date 4) - (aref date 5))) - (timezone-make-date-sortable (std11-field-body "date"))) - (throw 'done t)))) - ((and (eq (elmo-filter-type term) 'date) - (string= (elmo-filter-key term) "before")) - (let ((date (elmo-date-get-datevec (elmo-filter-value term)))) - (if (string< - (timezone-make-date-sortable (std11-field-body "date")) - (timezone-make-sortable-date (aref date 0) - (aref date 1) - (aref date 2) - (timezone-make-time-string - (aref date 3) - (aref date 4) - (aref date 5)))) - (throw 'done t)))) - ((eq (elmo-filter-type term) 'match) - (if (string= "body" (elmo-filter-key term)) - (progn - (re-search-forward "^$" nil t) ; goto body - (if (search-forward (elmo-filter-value term) nil t) - (throw 'done t))) - (let ((fval (eword-decode-string - (or (std11-field-body (elmo-filter-key term)) "")))) - (if (and fval (string-match (elmo-filter-value term) - fval)) - (throw 'done t))))) - ((eq (elmo-filter-type term) 'unmatch) - (if (string= "body" (elmo-filter-key term)) - (progn - (re-search-forward "^$" nil t) ; goto body - (if (not (search-forward (elmo-filter-value term) nil t)) - (throw 'done t))) - (let ((fval (eword-decode-string - (or (std11-field-body (elmo-filter-key term)) "")))) - (if fval - (if (not (string-match (elmo-filter-value term) - fval)) - (throw 'done t)) - (throw 'done t)))))) ; OK? - (setq condition (cdr condition))) - (throw 'done nil)))) - -(defsubst elmo-file-field-condition-match (file condition) +(defsubst elmo-buffer-field-primitive-condition-match (condition + number + number-list) + (let (result) + (goto-char (point-min)) + (cond + ((string= (elmo-filter-key condition) "last") + (setq result (> (length (memq number number-list)) + (string-to-int (elmo-filter-value condition))))) + ((string= (elmo-filter-key condition) "first") + (setq result (< (- (length number-list) + (length (memq number number-list))) + (string-to-int (elmo-filter-value condition))))) + ((string= (elmo-filter-key condition) "since") + (let ((date (elmo-date-get-datevec (elmo-filter-value condition)))) + (setq result + (string< + (timezone-make-sortable-date (aref date 0) + (aref date 1) + (aref date 2) + (timezone-make-time-string + (aref date 3) + (aref date 4) + (aref date 5))) + (timezone-make-date-sortable (std11-field-body "date")))))) + ((string= (elmo-filter-key condition) "before") + (let ((date (elmo-date-get-datevec (elmo-filter-value condition)))) + (setq result + (string< + (timezone-make-date-sortable (std11-field-body "date")) + (timezone-make-sortable-date (aref date 0) + (aref date 1) + (aref date 2) + (timezone-make-time-string + (aref date 3) + (aref date 4) + (aref date 5))))))) + ((string= (elmo-filter-key condition) "body") + (and (re-search-forward "^$" nil t) ; goto body + (setq result (search-forward (elmo-filter-value condition) + nil t)))) + (t + (let ((fval (std11-field-body (elmo-filter-key condition)))) + (if (eq (length fval) 0) (setq fval nil)) + (if fval (setq fval (eword-decode-string fval))) + (setq result (and fval (string-match + (elmo-filter-value condition) fval)))))) + (if (eq (elmo-filter-type condition) 'unmatch) + (setq result (not result))) + result)) + +(defun elmo-buffer-field-condition-match (condition number number-list) + (cond + ((vectorp condition) + (elmo-buffer-field-primitive-condition-match + condition number number-list)) + ((eq (car condition) 'and) + (and (elmo-buffer-field-condition-match + (nth 1 condition) number number-list) + (elmo-buffer-field-condition-match + (nth 2 condition) number number-list))) + ((eq (car condition) 'or) + (or (elmo-buffer-field-condition-match + (nth 1 condition) number number-list) + (elmo-buffer-field-condition-match + (nth 2 condition) number number-list))))) + +(defsubst elmo-file-field-condition-match (file condition number number-list) (elmo-set-work-buf - (as-binary-input-file - (insert-file-contents file)) + (as-binary-input-file (insert-file-contents file)) (elmo-set-buffer-multibyte default-enable-multibyte-characters) + ;; Should consider charset? (decode-mime-charset-region (point-min)(point-max) elmo-mime-charset) - (elmo-buffer-field-condition-match condition))) + (elmo-buffer-field-condition-match condition number number-list))) (defun elmo-cross-device-link-error-p (err) (let ((errobj err) diff --git a/elmo/elmo2.el b/elmo/elmo2.el index 17abb1e..ff71a73 100644 --- a/elmo/elmo2.el +++ b/elmo/elmo2.el @@ -386,14 +386,10 @@ without cacheing." (elmo-call-func folder "delete-msgs" msgs) (elmo-dop-delete-msgs folder msgs msgdb))) -;; -;; Server side search. -;; (defun elmo-search (folder condition &optional from-msgs) - (let ((type (elmo-folder-get-type folder))) - (if (elmo-folder-plugged-p folder) - (elmo-call-func folder "search" condition from-msgs) - (elmo-cache-search-all folder condition from-msgs)))) + (if (elmo-folder-plugged-p folder) + (elmo-call-func folder "search" condition from-msgs) + (elmo-cache-search-all folder condition from-msgs))) (defun elmo-msgdb-create (folder numlist new-mark already-mark seen-mark important-mark seen-list) @@ -578,16 +574,17 @@ without cacheing." "Just return number-alist." number-alist) -(defun elmo-generic-list-folder-unread (spec mark-alist unread-marks) - (elmo-delete-if - 'null - (mapcar - (function (lambda (x) - (if (member (cadr (assq (car x) mark-alist)) unread-marks) - (car x)))) - mark-alist))) - -(defun elmo-generic-list-folder-important (spec overview) +(defun elmo-generic-list-folder-unread (spec msgdb unread-marks) + (let ((mark-alist (elmo-msgdb-get-mark-alist msgdb))) + (elmo-delete-if + 'null + (mapcar + (function (lambda (x) + (if (member (cadr (assq (car x) mark-alist)) unread-marks) + (car x)))) + mark-alist)))) + +(defun elmo-generic-list-folder-important (spec msgdb) nil) (defun elmo-update-number (folder msgdb) @@ -632,22 +629,22 @@ without cacheing." 0))) (length in-folder)))) -(defun elmo-list-folder-unread (folder mark-alist unread-marks) - (elmo-call-func folder "list-folder-unread" mark-alist unread-marks)) +(defun elmo-list-folder-unread (folder msgdb unread-marks) + (elmo-call-func folder "list-folder-unread" msgdb unread-marks)) -(defun elmo-list-folder-important (folder overview) - (let (importants) +(defun elmo-list-folder-important (folder msgdb) + (let (importants + (overview (elmo-msgdb-get-overview msgdb))) ;; server side importants...(append only.) (if (elmo-folder-plugged-p folder) (setq importants (elmo-call-func folder "list-folder-important" - overview))) + msgdb))) (or elmo-msgdb-global-mark-alist (setq elmo-msgdb-global-mark-alist (elmo-object-load (expand-file-name elmo-msgdb-global-mark-filename elmo-msgdb-dir)))) (while overview - (car overview) (if (assoc (elmo-msgdb-overview-entity-get-id (car overview)) elmo-msgdb-global-mark-alist) (setq importants (cons @@ -695,8 +692,11 @@ Currently works on IMAP4 folder only." (elmo-multi-folder-diff fld)) ((and (eq type 'filter) (or (elmo-multi-p fld) - (not - (vectorp (nth 1 (elmo-folder-get-spec fld))))) + (not (and (vectorp (nth 1 (elmo-folder-get-spec fld))) + (string-match + "^first$\\|^last$" + (elmo-filter-key + (nth 1 (elmo-folder-get-spec fld))))))) ;; not partial...unsync number is unknown. (cons nil (cdr (elmo-folder-diff