(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-29 Yuuichi Teranishi <teranisi@gohome.org>
+
+ * 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 <teranisi@gohome.org>
* elmo-nntp.el (elmo-nntp-list-folder): Set current group after
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; 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))
(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))
(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)))
;; 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)
(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))
(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)))
(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))
(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
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")))
(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))
(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
"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
(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
(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))
(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))
(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))
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)
(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))
(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)
(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))
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
",")))))
(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)
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 ::= <elisp string expression>
+;; 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 ::= <ascii space character, 0x20>
+;; ATOM_CHARS ::= <any character except specials>
+;; 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))
(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)
(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)
"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)
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
(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