(elmo-define-error 'elmo-authenticate-error "Login failed" 'elmo-open-error)
(elmo-define-error 'elmo-imap4-bye-error "IMAP4 session was terminated" 'elmo-open-error)
+;; autoloads
+(eval-and-compile
+ (autoload 'elmo-dop-queue-flush "elmo-dop")
+ (autoload 'elmo-nntp-post "elmo-nntp")
+ (autoload 'elmo-global-flag-p "elmo-flag")
+ (autoload 'elmo-global-flag-detach "elmo-flag")
+ (autoload 'elmo-global-flag-detach-messages "elmo-flag")
+ (autoload 'elmo-global-flag-set "elmo-flag")
+ (autoload 'elmo-get-global-flags "elmo-flag")
+ (autoload 'elmo-global-mark-migrate "elmo-flag")
+ (autoload 'elmo-folder-list-global-flag-messages "elmo-flag"))
+
(defun elmo-define-folder (prefix backend)
"Define a folder.
If a folder name begins with PREFIX, use BACKEND."
(defmacro elmo-folder-type (name)
"Get folder type from NAME string."
- (` (and (stringp (, name))
- (cdr (assoc (string-to-char (, name)) elmo-folder-type-alist)))))
+ `(and (stringp ,name)
+ (or (cdr (assoc (string-to-char ,name) elmo-folder-type-alist))
+ (when (string-match "\\([^:]*\\):" ,name)
+ (intern (match-string 1 ,name))))))
;;; ELMO folder
;; A elmo folder provides uniformed (orchestrated) access
msgdb ; msgdb (may be nil).
killed-list ; killed list.
persistent ; non-nil if persistent.
- message-modified ; message is modified.
- mark-modified ; mark is modified.
process-duplicates ; read or hide
+ biff ; folder for biff
))
(luna-define-internal-accessors 'elmo-folder))
;;;###autoload
(defun elmo-make-folder (name &optional non-persistent)
"Make an ELMO folder structure specified by NAME.
-If optional argument NON-PERSISTENT is non-nil, folder is treated as
- non-persistent."
+If optional argument NON-PERSISTENT is non-nil, the folder msgdb is not saved."
(let ((type (elmo-folder-type name))
prefix split class folder original)
(setq original (elmo-string name))
(setq prefix (substring name 0 1))
(setq name (substring name 1)))
(setq type (intern (car (setq split (split-string name ":")))))
- (if (> (length split) 2)
+ (if (>= (length split) 2)
(setq name (substring name (+ 1 (length (car split)))))
(error "Error in folder name `%s'" original))
(setq prefix (concat (car split) ":")))
(setq class (format "elmo-%s" (symbol-name type)))
(require (intern class))
(setq folder (luna-make-entity (intern (concat class "-folder"))
- :type type
+ :type type
:prefix prefix
:name original
:persistent (not non-persistent)))
(save-match-data
(elmo-folder-send folder 'elmo-folder-initialize name))))
-(defmacro elmo-folder-msgdb (folder)
- "Return the msgdb of FOLDER (on-demand loading)."
- (` (or (elmo-folder-msgdb-internal (, folder))
- (elmo-folder-set-msgdb-internal (, folder)
- (elmo-msgdb-load (, folder))))))
+;; Note that this function is for internal use only.
+(luna-define-generic elmo-folder-msgdb (folder)
+ "Return the msgdb of FOLDER (on-demand loading).
+\(For internal use only.\)")
+
+(luna-define-method elmo-folder-msgdb ((folder elmo-folder))
+ (or (elmo-folder-msgdb-internal folder)
+ (elmo-folder-set-msgdb-internal folder
+ (elmo-folder-msgdb-load folder))))
(luna-define-generic elmo-folder-open (folder &optional load-msgdb)
"Open and setup (load saved status) FOLDER.
If optional LOAD-MSGDB is non-nil, msgdb is loaded.
-(otherwise, msgdb is loaded on-demand)")
+\(otherwise, msgdb is loaded on-demand)")
(luna-define-generic elmo-folder-open-internal (folder)
"Open FOLDER (without loading saved folder status).")
(luna-define-generic elmo-folder-use-flag-p (folder)
"Returns t if FOLDER treats unread/important flag itself.")
-(luna-define-generic elmo-folder-diff (folder &optional numbers)
+(luna-define-generic elmo-folder-diff (folder)
"Get diff of FOLDER.
-If optional NUMBERS is set, it is used as current NUMBERS.
-Otherwise, saved status for folder is used for comparison.
Return value is cons cell or list:
- - a cons cell (NEWS . MESSAGES)
- - a list (RECENT UNSEEN MESSAGES) ; RECENT means NEWS, UNSEEN means UNREAD.")
+ - a cons cell (new . all)
+ - a list (new unread all)")
(luna-define-generic elmo-folder-status (folder)
"Returns a cons cell of (MAX-NUMBER . MESSAGES) in the FOLDER.")
(luna-define-generic elmo-folder-reserve-status-p (folder)
"If non-nil, the folder should not close folder after `elmo-folder-status'.")
-(defun elmo-folder-list-messages (folder &optional visible-only)
+(luna-define-generic elmo-folder-list-messages (folder &optional visible-only
+ in-msgdb)
"Return a list of message numbers contained in FOLDER.
-If optional VISIBLE-ONLY is non-nil, killed messages are not listed."
- (let ((list (elmo-folder-list-messages-internal folder visible-only))
- (killed (elmo-folder-killed-list-internal folder))
- numbers)
- (setq numbers
- (if (listp list)
- list
- ;; Not available, use current list.
- (mapcar
- 'car
- (elmo-msgdb-get-number-alist (elmo-folder-msgdb folder)))))
- (elmo-living-messages numbers killed)))
-
-(defun elmo-folder-list-unreads (folder unread-marks)
- "Return a list of unread message numbers contained in FOLDER.
-UNREAD-MARKS is the unread marks."
- (let ((list (elmo-folder-list-unreads-internal folder
- unread-marks)))
- (if (listp list)
- list
- ;; Not available, use current mark.
- (delq nil
- (mapcar
- (function
- (lambda (x)
- (if (member (cadr x) unread-marks)
- (car x))))
- (elmo-msgdb-get-mark-alist (elmo-folder-msgdb folder)))))))
-
-(defun elmo-folder-list-importants (folder important-mark)
- "Returns a list of important message numbers contained in FOLDER.
-IMPORTANT-MARK is the important mark."
- (let ((importants (elmo-folder-list-importants-internal folder important-mark))
- (number-alist (elmo-msgdb-get-number-alist
- (elmo-folder-msgdb folder)))
- num-pair result)
- (dolist (mark-pair (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)))))
- (if (and (string= important-mark (cdr mark-pair))
- (setq num-pair (rassoc (car mark-pair) number-alist)))
- (setq result (cons (car num-pair) result))))
- (if (listp importants)
- (elmo-uniq-list (nconc result importants))
- result)))
+If optional VISIBLE-ONLY is non-nil, killed messages are not listed.
+If second optional IN-MSGDB is non-nil, only messages in the msgdb are listed.")
+
+(luna-define-method elmo-folder-list-messages ((folder elmo-folder)
+ &optional visible-only in-msgdb)
+ (let ((list (if in-msgdb
+ t
+ (elmo-folder-list-messages-internal folder visible-only)))
+ (killed-list (elmo-folder-killed-list-internal folder)))
+ (unless (listp list)
+ ;; Use current list.
+ (setq list (elmo-msgdb-list-messages (elmo-folder-msgdb folder))))
+ (if visible-only
+ (elmo-living-messages list killed-list)
+ (if in-msgdb
+ (elmo-uniq-list
+ (nconc (elmo-number-set-to-number-list killed-list) list)
+ #'delq)
+ list))))
(luna-define-generic elmo-folder-list-messages-internal (folder &optional
visible-only)
;; Return t if the message list is not available.
)
-(luna-define-generic elmo-folder-list-unreads-internal (folder
- unread-marks
- &optional mark-alist)
- ;; Return a list of unread message numbers contained in FOLDER.
- ;; If optional MARK-ALIST is set, it is used as mark-alist.
- ;; Return t if this feature is not available.
- )
-
-(luna-define-generic elmo-folder-list-importants-internal (folder
- important-mark)
- ;; Return a list of important message numbers contained in FOLDER.
- ;; Return t if this feature is not available.
- )
+(luna-define-generic elmo-folder-list-flagged (folder flag &optional in-msgdb)
+ "List messages in the FOLDER with FLAG.
+FLAG is a symbol which is one of the following:
+ `new' (new messages)
+ `unread' (unread messages (new messages are included))
+ `answered' (answered or forwarded)
+ `important' (marked as important)
+'sugar' flags:
+ `read' (not unread)
+ `digest' (unread + important + other flags)
+ `any' (digest + answered + other flags)
+If optional IN-MSGDB is non-nil, retrieve flag information from msgdb.")
+
+(luna-define-method elmo-folder-list-flagged ((folder elmo-folder) flag
+ &optional in-msgdb)
+ (let ((msgs (if in-msgdb
+ t
+ (elmo-folder-list-flagged-internal folder flag))))
+ (unless (listp msgs)
+ (setq msgs (elmo-msgdb-list-flagged (elmo-folder-msgdb folder) flag)))
+ (if in-msgdb
+ msgs
+ (elmo-uniq-list
+ (nconc (elmo-folder-list-global-flag-messages folder flag) msgs)
+ #'delq))))
+
+(luna-define-generic elmo-folder-list-flagged-internal (folder flag)
+ "Return a list of message in the FOLDER with FLAG.
+Return t if the message list is not available.")
+
+(luna-define-method elmo-folder-list-flagged-internal ((folder elmo-folder)
+ flag)
+ t)
(luna-define-generic elmo-folder-list-subfolders (folder &optional one-level)
"Returns a list of subfolders contained in FOLDER.
If optional argument ONE-LEVEL is non-nil, only children of FOLDER is returned.
-(a folder which have children is returned as a list)
+\(a folder which have children is returned as a list\)
Otherwise, all descendent folders are returned.")
(luna-define-generic elmo-folder-have-subfolder-p (folder)
(luna-define-generic elmo-folder-delete-messages (folder numbers)
"Delete messages.
FOLDER is the ELMO folder structure.
-NUMBERS is a list of message numbers to be deleted.")
+NUMBERS is a list of message numbers to be deleted.
+It is not recommended to use this function other than internal use.
+Use `elmo-folder-move-messages' with dst-folder 'null instead.")
(luna-define-generic elmo-folder-search (folder condition &optional numbers)
"Search and return list of message numbers.
FOLDER is the ELMO folder structure.
-CONDITION is a condition string for searching.
+CONDITION is a condition structure for searching.
If optional argument NUMBERS is specified and is a list of message numbers,
messages are searched from the list.")
-(luna-define-generic elmo-folder-msgdb-create
- (folder numbers new-mark already-mark seen-mark important-mark seen-list)
+(luna-define-generic elmo-message-match-condition (folder number
+ condition
+ numbers)
+ "Return non-nil when the message in the FOLDER with NUMBER is matched.
+CONDITION is a condition structure for testing.
+NUMBERS is a list of message numbers,
+use to be test for \"last\" and \"first\" predicates.")
+
+(luna-define-generic elmo-folder-msgdb-create (folder numbers flag-table)
"Create a message database (implemented in each backends).
FOLDER is the ELMO folder structure.
NUMBERS is a list of message numbers to create msgdb.
-NEW-MARK, ALREADY-MARK, SEEN-MARK, and IMPORTANT-MARK are mark string for
-new message, unread but cached message, read message and important message.
-SEEN-LIST is a list of message-id string which should be treated as read.")
-
-(luna-define-generic elmo-folder-unmark-important (folder numbers)
- "Un-mark messages as important.
-FOLDER is the ELMO folder structure.
-NUMBERS is a list of message numbers to be processed.")
-
-(luna-define-generic elmo-folder-mark-as-important (folder numbers)
- "Mark messages as important.
-FOLDER is the ELMO folder structure.
-NUMBERS is a list of message numbers to be processed.")
-
-(luna-define-generic elmo-folder-unmark-read (folder numbers)
- "Un-mark messages as read.
-FOLDER is the ELMO folder structure.
-NUMBERS is a list of message numbers to be processed.")
-
-(luna-define-generic elmo-folder-mark-as-read (folder numbers)
- "Mark messages as read.
-FOLDER is the ELMO folder structure.
-NUMBERS is a list of message numbers to be processed.")
-
-(luna-define-generic elmo-folder-append-buffer (folder unread &optional number)
+FLAG-TABLE is a hashtable of message-id and flag.")
+
+(luna-define-generic elmo-folder-set-flag (folder numbers flag
+ &optional is-local)
+ "Set messages flag.
+FOLDER is a ELMO folder structure.
+NUMBERS is a list of message number to set flag.
+
+FLAG is a symbol which is one of the following:
+ `unread' (set the message as unread)
+ `answered' (set the message as answered)
+ `important' (set the message as important)
+'sugar' flag:
+ `read' (remove new and unread flags)
+If optional IS-LOCAL is non-nil, update only local (not server) status.")
+
+(luna-define-generic elmo-folder-unset-flag (folder numbers flag
+ &optional is-local)
+ "Unset messages flag.
+FOLDER is a ELMO folder structure.
+NUMBERS is a list of message number to unset flag.
+
+FLAG is a symbol which is one of the following:
+ `unread' (remove unread and new flag)
+ `answered' (remove answered flag)
+ `important' (remove important flag)
+'sugar' flag:
+ `read' (set unread flag)
+If optional IS-LOCAL is non-nil, update only local (not server) status.")
+
+(luna-define-generic elmo-folder-next-message-number (folder)
+ "The next message number that will be assigned to a new message.
+FOLDER is the ELMO folder structure.")
+
+(luna-define-generic elmo-folder-append-buffer (folder &optional flag
+ number)
"Append current buffer as a new message.
FOLDER is the destination folder(ELMO folder structure).
-If UNREAD is non-nil, message is appended as unread.
+FLAG is the status of appended message.
If optional argument NUMBER is specified, the new message number is set
-(if possible).")
+\(if possible\).")
(luna-define-generic elmo-folder-append-messages (folder
src-folder
numbers
- unread-marks
&optional
same-number)
"Append messages from folder.
FOLDER is the ELMO folder structure.
Caller should make sure FOLDER is `writable'.
-(Can be checked with `elmo-folder-writable-p').
+\(Can be checked with `elmo-folder-writable-p'\).
SRC-FOLDER is the source ELMO folder structure.
NUMBERS is the message numbers to be appended in the SRC-FOLDER.
-UNREAD-MARKS is a list of unread mark string.
If second optional argument SAME-NUMBER is specified,
-message number is preserved (if possible).")
+message number is preserved \(if possible\).")
(luna-define-generic elmo-folder-pack-numbers (folder)
"Pack message numbers of FOLDER.")
(luna-define-generic elmo-message-file-p (folder number)
"Return t if message in the FOLDER with NUMBER is a file.")
+(luna-define-generic elmo-message-flags (folder number)
+ "Return a list of flags.
+FOLDER is a ELMO folder structure.
+NUMBER is a number of the message.")
+
+(luna-define-method elmo-message-flags ((folder elmo-folder) number)
+ (elmo-msgdb-flags (elmo-folder-msgdb folder) number))
+
+(defsubst elmo-message-flagged-p (folder number flag)
+ "Return non-nil if the message is set FLAG.
+FOLDER is a ELMO folder structure.
+NUMBER is a message number to test."
+ (let ((cur-flags (elmo-message-flags folder number)))
+ (case flag
+ (read
+ (not (memq 'unread cur-flags)))
+ (t
+ (memq flag cur-flags)))))
+
(luna-define-generic elmo-find-fetch-strategy
(folder entity &optional ignore-cache)
;; Returns the message fetching strategy suitable for the message.
(luna-define-method elmo-find-fetch-strategy
((folder elmo-folder) entity &optional ignore-cache)
(let (cache-file size message-id number)
- (setq size (elmo-msgdb-overview-entity-get-size entity))
- (setq message-id (elmo-msgdb-overview-entity-get-id entity))
- (setq number (elmo-msgdb-overview-entity-get-number entity))
+ (setq size (elmo-message-entity-field entity 'size))
+ (setq message-id (elmo-message-entity-field entity 'message-id))
+ (setq number (elmo-message-entity-number entity))
(setq cache-file (elmo-file-cache-get message-id))
+ (setq ignore-cache (or ignore-cache
+ (null (elmo-message-use-cache-p folder number))))
(if (or ignore-cache
(null (elmo-file-cache-status cache-file)))
;; No cache or ignore-cache.
((folder elmo-folder) &optional visible-only)
t)
-(luna-define-method elmo-folder-list-unreads-internal
- ((folder elmo-folder) unread-marks &optional mark-alist)
- t)
-
-(luna-define-method elmo-folder-list-importants-internal
- ((folder elmo-folder) important-mark)
- t)
-
(defun elmo-folder-encache (folder numbers &optional unread)
"Encache messages in the FOLDER with NUMBERS.
-If UNREAD is non-nil, messages are not marked as read."
+If UNREAD is non-nil, messages are not flaged as read."
(dolist (number numbers)
(elmo-message-encache folder number unread)))
(luna-define-generic elmo-message-encache (folder number &optional read)
"Encache message in the FOLDER with NUMBER.
-If READ is non-nil, message is marked as read.")
+If READ is non-nil, message is flaged as read.")
(luna-define-method elmo-message-encache ((folder elmo-folder) number
&optional read)
- (elmo-message-fetch
- folder number
- (elmo-make-fetch-strategy 'entire
- nil ;use-cache
- t ;save-cache
- (elmo-file-cache-get-path
- (elmo-message-field
- folder number 'message-id)))
- nil nil (not read)))
+ (let (path)
+ (elmo-message-fetch
+ folder number
+ (elmo-make-fetch-strategy 'entire
+ nil ;use-cache
+ t ;save-cache
+ (setq path (elmo-file-cache-get-path
+ (elmo-message-field
+ folder number 'message-id))))
+ nil nil (not read))
+ path))
(luna-define-generic elmo-message-fetch (folder number strategy
&optional
is fetched (if possible).
If second optional argument OUTBUF is specified, fetched message is
inserted to the buffer and returns t if fetch was ended successfully.
-If third optional argument UNREAD is non-nil, message is not marked as read.
+If third optional argument UNREAD is non-nil, message is not flaged as read.
Returns non-nil if fetching was succeed.")
(luna-define-generic elmo-message-fetch-with-cache-process (folder
STRATEGY is the message fetching strategy.
If optional argument SECTION is specified, only the SECTION of the message
is fetched (if possible).
-If second optional argument UNREAD is non-nil, message is not marked as read.
+If second optional argument UNREAD is non-nil, message is not flaged as read.
Returns non-nil if fetching was succeed.")
(luna-define-generic elmo-message-fetch-internal (folder number strategy
STRATEGY is the message fetching strategy.
If optional argument SECTION is specified, only the SECTION of the message
is fetched (if possible).
-If second optional argument UNREAD is non-nil, message is not marked as read.
+If second optional argument UNREAD is non-nil, message is not flaged as read.
Returns non-nil if fetching was succeed.")
(luna-define-generic elmo-message-fetch-field (folder number field)
(luna-define-generic elmo-message-folder (folder number)
"Get primitive folder of the message.")
-(luna-define-generic elmo-folder-process-crosspost (folder
- &optional
- number-alist)
+(luna-define-generic elmo-folder-process-crosspost (folder)
"Process crosspost for FOLDER.
-If NUMBER-ALIST is set, it is used as number-alist.
-Return a cons cell of (NUMBER-CROSSPOSTS . NEW-MARK-ALIST).")
-
-(luna-define-generic elmo-folder-append-msgdb (folder append-msgdb)
- "Append APPEND-MSGDB to the current msgdb of the folder.")
+Return a cons cell of (NUMBER-CROSSPOSTS . NEW-FLAG-ALIST).")
(luna-define-generic elmo-folder-newsgroups (folder)
"Return list of newsgroup name of FOLDER.")
+(luna-define-generic elmo-folder-search-requires-msgdb-p (folder condition)
+ "Return non-nil if searching in FOLDER by CONDITION requires msgdb fetch.")
+
+(defun elmo-folder-search-requires-msgdb-p-internal (folder condition)
+ (if (listp condition)
+ (or (elmo-folder-search-requires-msgdb-p-internal
+ folder (nth 1 condition))
+ (elmo-folder-search-requires-msgdb-p-internal
+ folder (nth 2 condition)))
+ (and (not (string= (elmo-filter-key condition) "last"))
+ (not (string= (elmo-filter-key condition) "first")))))
+
+(luna-define-method elmo-folder-search-requires-msgdb-p ((folder elmo-folder)
+ condition)
+ (elmo-folder-search-requires-msgdb-p-internal folder condition))
+
(luna-define-method elmo-folder-newsgroups ((folder elmo-folder))
nil)
(defun elmo-generic-folder-open (folder load-msgdb)
(let ((inhibit-quit t))
- (if load-msgdb
- (elmo-folder-set-msgdb-internal folder (elmo-msgdb-load folder)))
+ (if load-msgdb (elmo-folder-msgdb folder))
(elmo-folder-set-killed-list-internal
folder
(elmo-msgdb-killed-list-load (elmo-folder-msgdb-path folder))))
(elmo-generic-folder-commit folder))
(defun elmo-generic-folder-commit (folder)
- (when (elmo-folder-persistent-p folder)
- (when (elmo-folder-message-modified-internal folder)
- (elmo-msgdb-overview-save
- (elmo-folder-msgdb-path folder)
- (elmo-msgdb-get-overview (elmo-folder-msgdb folder)))
- (elmo-msgdb-number-save
- (elmo-folder-msgdb-path folder)
- (elmo-msgdb-get-number-alist (elmo-folder-msgdb folder)))
- (elmo-folder-set-info-max-by-numdb
- folder
- (elmo-msgdb-get-number-alist
- (elmo-folder-msgdb folder)))
- (elmo-folder-set-message-modified-internal folder nil)
- (elmo-msgdb-killed-list-save
- (elmo-folder-msgdb-path folder)
- (elmo-folder-killed-list-internal folder)))
- (when (elmo-folder-mark-modified-internal folder)
- (elmo-msgdb-mark-save
- (elmo-folder-msgdb-path folder)
- (elmo-msgdb-get-mark-alist (elmo-folder-msgdb folder)))
- (elmo-folder-set-mark-modified-internal folder nil))))
+ (let ((msgdb (elmo-folder-msgdb-internal folder)))
+ (when (and msgdb (elmo-folder-persistent-p folder))
+ (when (elmo-msgdb-message-modified-p msgdb)
+ (elmo-folder-set-info-max-by-numdb
+ folder
+ (elmo-folder-list-messages folder nil 'in-msgdb))
+ (elmo-msgdb-killed-list-save
+ (elmo-folder-msgdb-path folder)
+ (elmo-folder-killed-list-internal folder)))
+ (elmo-msgdb-save msgdb))))
(luna-define-method elmo-folder-close-internal ((folder elmo-folder))
;; do nothing.
(elmo-folder-persistent-internal folder))
(luna-define-method elmo-folder-creatable-p ((folder elmo-folder))
- t) ; default is creatable.
+ nil) ; default is not creatable.
(luna-define-method elmo-folder-writable-p ((folder elmo-folder))
nil) ; default is not writable.
+(luna-define-method elmo-folder-delete ((folder elmo-folder))
+ (when (yes-or-no-p (format "Delete msgdb of \"%s\"? "
+ (elmo-folder-name-internal folder)))
+ (elmo-msgdb-delete-path folder)
+ t))
+
(luna-define-method elmo-folder-rename ((folder elmo-folder) new-name)
(let* ((new-folder (elmo-make-folder new-name)))
(unless (eq (elmo-folder-type-internal folder)
(elmo-folder-send folder 'elmo-folder-rename-internal new-folder)
(elmo-msgdb-rename-path folder new-folder)))
+(luna-define-method elmo-folder-search ((folder elmo-folder)
+ condition
+ &optional numbers)
+ (let ((numbers (or numbers (elmo-folder-list-messages folder)))
+ (msgdb (elmo-folder-msgdb folder))
+ results)
+ (setq results (elmo-msgdb-search msgdb condition numbers))
+ (if (listp results)
+ results
+ (let ((len (length numbers))
+ matched)
+ (elmo-with-progress-display (> len elmo-display-progress-threshold)
+ (elmo-folder-search len "Searching...")
+ (dolist (number numbers)
+ (let (result)
+ (setq result (elmo-msgdb-match-condition msgdb
+ condition
+ number
+ numbers))
+ (when (elmo-filter-condition-p result)
+ (setq result (elmo-message-match-condition folder
+ number
+ condition
+ numbers)))
+ (when result
+ (setq matched (cons number matched))))
+ (elmo-progress-notify 'elmo-folder-search)))
+ (message "Searching...done")
+ (nreverse matched)))))
+
+(luna-define-method elmo-message-match-condition ((folder elmo-folder)
+ number condition
+ numbers)
+ (let ((filename (cond
+ ((elmo-message-file-name folder number))
+ ((let* ((cache (elmo-file-cache-get
+ (elmo-message-field folder number
+ 'message-id)))
+ (cache-path (elmo-file-cache-path cache)))
+ (when (and cache-path
+ (not (elmo-cache-path-section-p cache-path)))
+ cache-path))))))
+ (when (and filename
+ (file-readable-p filename))
+ (with-temp-buffer
+ (insert-file-contents-as-binary filename)
+ (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 number numbers)))))
+
(luna-define-method elmo-folder-pack-numbers ((folder elmo-folder))
nil) ; default is noop.
(list new unread numbers max)
elmo-folder-info-hashtb)))
-(defun elmo-folder-set-info-max-by-numdb (folder msgdb-number)
+(defun elmo-folder-set-info-max-by-numdb (folder numbers)
"Set FOLDER info by MSGDB-NUMBER in msgdb."
- (let ((num-db (sort (mapcar 'car msgdb-number) '<)))
- (elmo-folder-set-info-hashtb
- folder
- (or (nth (max 0 (1- (length num-db))) num-db) 0)
- nil ;;(length num-db)
- )))
+ (elmo-folder-set-info-hashtb
+ folder
+ (if numbers (apply #'max numbers) 0)
+ nil ;;(length num-db)
+ ))
(defun elmo-folder-get-info-max (folder)
"Return max number of FODLER from folder info."
(setq elmo-folder-info-hashtb hashtb)))
(defsubst elmo-diff-new (diff)
- (when (consp (cdr diff))
- (car diff)))
+ (car diff))
(defsubst elmo-diff-unread (diff)
- (if (consp (cdr diff))
- (nth 1 diff)
- (car diff)))
+ (when (consp (cdr diff))
+ (nth 1 diff)))
(defsubst elmo-diff-all (diff)
(if (consp (cdr diff))
(defsubst elmo-strict-folder-diff (folder)
"Return folder diff information strictly from FOLDER."
- (let* ((dir (elmo-folder-msgdb-path folder))
- (nalist (elmo-msgdb-get-number-alist (elmo-folder-msgdb folder)))
- (in-db (sort (mapcar 'car nalist) '<))
- (in-folder (elmo-folder-list-messages folder))
- append-list delete-list diff)
+ (let ((in-db (sort (elmo-msgdb-list-messages (elmo-folder-msgdb folder))
+ '<))
+ (in-folder (elmo-folder-list-messages folder))
+ append-list delete-list diff)
(cons (if (equal in-folder in-db)
0
- (setq diff (elmo-list-diff
- in-folder in-db
- nil
- ))
+ (setq diff (elmo-list-diff in-folder in-db nil))
(setq append-list (car diff))
(setq delete-list (cadr diff))
(if append-list
0)))
(length in-folder))))
-(luna-define-method elmo-folder-diff ((folder elmo-folder)
- &optional numbers)
- (elmo-generic-folder-diff folder numbers))
+(luna-define-method elmo-folder-diff ((folder elmo-folder))
+ (elmo-generic-folder-diff folder))
-(defun elmo-generic-folder-diff (folder numbers)
+(defun elmo-generic-folder-diff (folder)
(if (elmo-string-match-member (elmo-folder-name-internal folder)
elmo-strict-diff-folder-list)
(elmo-strict-folder-diff folder)
(in-db t)
unsync messages
in-db-max)
- (if numbers
- (setq in-db-max (or (nth (max 0 (1- (length numbers))) numbers)
- 0))
- (if (not cached-in-db-max)
- (let ((number-list (mapcar 'car
- (elmo-msgdb-number-load
- (elmo-folder-msgdb-path folder)))))
- ;; No info-cache.
- (setq in-db (sort number-list '<))
- (setq in-db-max (or (nth (max 0 (1- (length in-db))) in-db)
- 0))
- (elmo-folder-set-info-hashtb folder in-db-max nil))
- (setq in-db-max cached-in-db-max)))
- (setq unsync (if (and in-db
- (car in-folder))
+ (if (not cached-in-db-max)
+ (let ((number-list (elmo-folder-list-messages folder
+ nil 'in-msgdb)))
+ ;; No info-cache.
+ (setq in-db number-list)
+ (setq in-db-max (if in-db (apply #'max in-db) 0))
+ (elmo-folder-set-info-hashtb folder in-db-max nil))
+ (setq in-db-max cached-in-db-max))
+ (setq unsync (if (and in-db (car in-folder))
(- (car in-folder) in-db-max)
- (if (and in-folder
- (null in-db))
+ (if (and in-folder (null in-db))
(cdr in-folder)
- (if (null (car in-folder))
- nil))))
+ (car in-folder))))
(setq messages (cdr in-folder))
(if (and unsync messages (> unsync messages))
(setq unsync messages))
(luna-define-method elmo-folder-contains-type ((folder elmo-folder) type)
(eq (elmo-folder-type-internal folder) type))
+(luna-define-method elmo-folder-next-message-number ((folder elmo-folder))
+ (+ 1 (elmo-max-of-list (or (elmo-folder-list-messages folder)
+ '(0)))))
+
(luna-define-method elmo-folder-append-messages ((folder elmo-folder)
src-folder
numbers
- unread-marks
&optional
same-number)
(elmo-generic-folder-append-messages folder src-folder numbers
- unread-marks same-number))
+ same-number))
(defun elmo-generic-folder-append-messages (folder src-folder numbers
- unread-marks same-number)
- (let (unseen seen-list succeed-numbers failure cache)
+ same-number)
+ (let ((src-msgdb-exists (not (zerop (elmo-folder-length src-folder))))
+ unseen table flags
+ succeed-numbers failure cache id)
+ (setq table (elmo-flag-table-load (elmo-folder-msgdb-path folder)))
(with-temp-buffer
+ (set-buffer-multibyte nil)
(while numbers
- (setq failure nil)
+ (setq failure nil
+ id (and src-msgdb-exists
+ (elmo-message-field src-folder (car numbers)
+ 'message-id))
+ flags (elmo-message-flags src-folder (car numbers)))
(condition-case nil
- (progn
- (elmo-message-fetch
- src-folder (car numbers)
- (if (and (not (elmo-folder-plugged-p src-folder))
- elmo-enable-disconnected-operation
- (setq cache (elmo-file-cache-get
- (elmo-message-field
- src-folder (car numbers)
- 'message-id)))
- (eq (elmo-file-cache-status cache) 'entire))
- (elmo-make-fetch-strategy
- 'entire t nil (elmo-file-cache-path cache))
- (elmo-make-fetch-strategy 'entire t))
- nil (current-buffer)
- 'unread)
- (unless (eq (buffer-size) 0)
- (setq failure (not
- (elmo-folder-append-buffer
- folder
- (setq unseen (member (elmo-message-mark
- src-folder (car numbers))
- unread-marks))
- (if same-number (car numbers)))))))
+ (setq cache (elmo-file-cache-get id)
+ failure
+ (not
+ (and
+ (elmo-message-fetch
+ src-folder (car numbers)
+ (if (elmo-folder-plugged-p src-folder)
+ (elmo-make-fetch-strategy
+ 'entire 'maybe nil
+ (and cache (elmo-file-cache-path cache)))
+ (or (and elmo-enable-disconnected-operation
+ cache
+ (eq (elmo-file-cache-status cache) 'entire)
+ (elmo-make-fetch-strategy
+ 'entire t nil
+ (elmo-file-cache-path cache)))
+ (error "Unplugged")))
+ nil (current-buffer)
+ 'unread)
+ (> (buffer-size) 0)
+ (elmo-folder-append-buffer
+ folder
+ (or flags '(read))
+ (if same-number (car numbers))))))
(error (setq failure t)))
;; FETCH & APPEND finished
(unless failure
- (unless unseen
- (setq seen-list (cons (elmo-message-field
- src-folder (car numbers)
- 'message-id)
- seen-list)))
+ (when id
+ (elmo-flag-table-set table id flags))
(setq succeed-numbers (cons (car numbers) succeed-numbers)))
(elmo-progress-notify 'elmo-folder-move-messages)
(setq numbers (cdr numbers)))
- (if (and seen-list (elmo-folder-persistent-p folder))
- (elmo-msgdb-seen-save (elmo-folder-msgdb-path folder)
- (nconc (elmo-msgdb-seen-load
- (elmo-folder-msgdb-path folder))
- seen-list)))
+ (when (elmo-folder-persistent-p folder)
+ (elmo-flag-table-save (elmo-folder-msgdb-path folder) table))
succeed-numbers)))
;; Arguments should be reduced.
(defun elmo-folder-move-messages (src-folder msgs dst-folder
- &optional msgdb
- no-delete-info
+ &optional
no-delete
- same-number
- unread-marks
- save-unread)
+ same-number)
(save-excursion
(let* ((messages msgs)
(elmo-inhibit-display-retrieval-progress t)
(unless (setq succeeds (elmo-folder-append-messages dst-folder
src-folder
messages
- unread-marks
same-number))
(error "move: append message to %s failed"
(elmo-folder-name-internal dst-folder)))
- (elmo-folder-close dst-folder))
- (when (and (elmo-folder-persistent-p dst-folder)
- save-unread)
- ;; Save to seen list.
- (let* ((dir (elmo-folder-msgdb-path dst-folder))
- (seen-list (elmo-msgdb-seen-load dir)))
- (setq seen-list
- (elmo-msgdb-add-msgs-to-seen-list
- msgs (elmo-folder-msgdb src-folder)
- unread-marks seen-list))
- (elmo-msgdb-seen-save dir seen-list))))
+ (elmo-folder-close dst-folder)))
(if (and (not no-delete) succeeds)
(progn
- (if (not no-delete-info)
- (message "Cleaning up src folder..."))
(if (and (elmo-folder-delete-messages src-folder succeeds)
- (elmo-msgdb-delete-msgs
- (elmo-folder-msgdb src-folder) succeeds))
- (setq result t)
+ (elmo-folder-detach-messages src-folder succeeds))
+ (progn
+ (elmo-global-flag-detach-messages
+ src-folder succeeds (eq dst-folder 'null))
+ (setq result t))
(message "move: delete messages from %s failed."
(elmo-folder-name-internal src-folder))
(setq result nil))
- (if (and result
- (not no-delete-info))
- (message "Cleaning up src folder...done"))
result)
(if no-delete
(progn
- (message "Copying messages...done")
+ ;; (message "Copying messages...done")
t)
(if (eq len 0)
(message "No message was moved.")
folder
(elmo-folder-expand-msgdb-path folder))))
-(defun elmo-message-mark (folder number)
- "Get mark of the message.
+(luna-define-generic elmo-message-cached-p (folder number)
+ "Return non-nil if the message is cached.")
+
+(luna-define-method elmo-message-cached-p ((folder elmo-folder) number)
+ (elmo-message-flagged-p folder number 'cached))
+
+(defun elmo-message-accessible-p (folder number)
+ "Get accessibility of the message.
+Return non-nil when message is accessible."
+ (or (elmo-folder-plugged-p folder)
+ (elmo-folder-local-p folder)
+ (elmo-message-cached-p folder number)))
+
+(luna-define-generic elmo-message-set-cached (folder number cached)
+ "Set cache status of the message in the msgdb.
FOLDER is the ELMO folder structure.
-NUMBER is a number of the message."
- (cadr (assq number (elmo-msgdb-get-mark-alist (elmo-folder-msgdb folder)))))
-
-(defun elmo-folder-list-messages-mark-match (folder mark-regexp)
- "List messages in the FOLDER which have a mark that matches MARK-REGEXP"
- (let ((case-fold-search nil)
- matched)
- (if mark-regexp
- (dolist (elem (elmo-msgdb-get-mark-alist (elmo-folder-msgdb folder)))
- (if (string-match mark-regexp (cadr elem))
- (setq matched (cons (car elem) matched)))))
- matched))
-
-(defun elmo-message-field (folder number field)
+NUMBER is a number of the message.
+If CACHED is t, message is set as cached.")
+
+(luna-define-method elmo-message-set-cached ((folder elmo-folder)
+ number cached)
+ (if cached
+ (elmo-msgdb-set-flag (elmo-folder-msgdb folder) number 'cached)
+ (elmo-msgdb-unset-flag (elmo-folder-msgdb folder) number 'cached)))
+
+(defun elmo-message-copy-entity (entity)
+ (elmo-msgdb-copy-message-entity (elmo-message-entity-handler entity)
+ entity))
+
+(luna-define-generic elmo-message-entity (folder key)
+ "Return the message-entity structure which matches to the KEY.
+KEY is a number or a string.
+A number is for message number in the FOLDER.
+A string is for message-id of the message.")
+
+(luna-define-method elmo-message-entity ((folder elmo-folder) key)
+ (elmo-msgdb-message-entity (elmo-folder-msgdb folder) key))
+
+(luna-define-generic elmo-message-entity-parent (folder entity)
+ "Return the parent message-entity structure in the FOLDER.
+ENTITY is the message-entity to get the parent.")
+
+(luna-define-method elmo-message-entity-parent ((folder elmo-folder) entity)
+ (elmo-msgdb-get-parent-entity entity (elmo-folder-msgdb folder)))
+
+(put 'elmo-folder-do-each-message-entity 'lisp-indent-function '1)
+(def-edebug-spec elmo-folder-do-each-message-entity
+ ((symbolp form &rest form) &rest form))
+
+(defsubst elmo-folder-list-message-entities (folder)
+ ;; List all message entities in the FOLDER.
+ (mapcar
+ (lambda (number) (elmo-message-entity folder number))
+ (elmo-folder-list-messages folder nil t))) ; XXX killed-list is not used.
+
+(defmacro elmo-folder-do-each-message-entity (spec &rest form)
+ "Iterator for message entity in the folder.
+\(elmo-folder-do-each-message-entity \(entity folder\)
+ ... do the process using entity...
+\)"
+ `(dolist (,(car spec) (elmo-folder-list-message-entities ,(car (cdr spec))))
+ ,@form))
+
+(luna-define-generic elmo-folder-count-flags (folder)
+ "Count flagged message number in the msgdb of the FOLDER.
+Return a list of numbers (`new' `unread' `answered')")
+
+(luna-define-method elmo-folder-count-flags ((folder elmo-folder))
+ (let* ((flag-count (elmo-msgdb-flag-count (elmo-folder-msgdb folder)))
+ (new (or (cdr (assq 'new flag-count)) 0))
+ (unread (or (cdr (assq 'unread flag-count)) 0))
+ (answered(or (cdr (assq 'answered flag-count)) 0)))
+ (list new (- unread new) answered)))
+
+(defun elmo-message-set-flag (folder number flag &optional is-local)
+ "Set message flag.
+FOLDER is a ELMO folder structure.
+NUMBER is a message number to set flag.
+
+FLAG is a symbol which is one of the following:
+ `unread' (set the message as unread)
+ `answered' (set the message as answered)
+ `important' (set the message as important)
+'sugar' flag:
+ `read' (remove new and unread flags)
+If optional IS-LOCAL is non-nil, update only local (not server) status."
+ ;; XXX Transitional implementation.
+ (elmo-folder-set-flag folder (list number) flag is-local))
+
+(defun elmo-message-unset-flag (folder number flag &optional is-local)
+ "Unset message flag.
+FOLDER is a ELMO folder structure.
+NUMBER is a message number to set flag.
+
+FLAG is a symbol which is one of the following:
+ `unread' (remove unread and new flag)
+ `answered' (remove answered flag)
+ `important' (remove important flag)
+'sugar' flag:
+ `read' (set unread flag)
+If optional IS-LOCAL is non-nil, update only local (not server) status."
+ ;; XXX Transitional implementation.
+ (elmo-folder-unset-flag folder (list number) flag is-local))
+
+(luna-define-generic elmo-message-field (folder number field)
"Get message field value in the msgdb.
FOLDER is the ELMO folder structure.
NUMBER is a number of the message.
-FIELD is a symbol of the field."
- (case field
- (message-id (elmo-msgdb-overview-entity-get-id
- (elmo-msgdb-overview-get-entity
- number (elmo-folder-msgdb folder))))
- (subject (elmo-msgdb-overview-entity-get-subject
- (elmo-msgdb-overview-get-entity
- number (elmo-folder-msgdb folder))))
- (size (elmo-msgdb-overview-entity-get-size
- (elmo-msgdb-overview-get-entity
- number (elmo-folder-msgdb folder))))
- (date (elmo-msgdb-overview-entity-get-date
- (elmo-msgdb-overview-get-entity
- number (elmo-folder-msgdb folder))))
- (to (elmo-msgdb-overview-entity-get-to
- (elmo-msgdb-overview-get-entity
- number (elmo-folder-msgdb folder))))
- (cc (elmo-msgdb-overview-entity-get-cc
- (elmo-msgdb-overview-get-entity
- number (elmo-folder-msgdb folder))))))
-
-(defun elmo-message-set-mark (folder number mark)
- "Set mark for the message in the FOLDER with NUMBER as MARK."
- (elmo-msgdb-set-mark-alist
- (elmo-folder-msgdb folder)
- (elmo-msgdb-mark-set
- (elmo-msgdb-get-mark-alist (elmo-folder-msgdb folder))
- number mark)))
+FIELD is a symbol of the field.")
+
+(luna-define-method elmo-message-field ((folder elmo-folder) number field)
+ (elmo-message-entity-field (elmo-message-entity folder number) field))
(luna-define-method elmo-message-use-cache-p ((folder elmo-folder) number)
nil) ; default is not use cache.
(luna-define-method elmo-message-folder ((folder elmo-folder) number)
folder) ; default is folder
-(luna-define-method elmo-folder-unmark-important ((folder elmo-folder) numbers)
- t)
-
-(luna-define-method elmo-folder-mark-as-important ((folder elmo-folder)
- numbers)
- t)
-
-(luna-define-method elmo-folder-unmark-read ((folder elmo-folder) numbers)
- t)
-
-(luna-define-method elmo-folder-mark-as-read ((folder elmo-folder) numbers)
- t)
-
-(luna-define-method elmo-folder-process-crosspost ((folder elmo-folder)
- &optional
- number-alist)
+(luna-define-method elmo-folder-set-flag ((folder elmo-folder)
+ numbers
+ flag
+ &optional is-local)
+ (when (elmo-folder-msgdb-internal folder)
+ (dolist (number numbers)
+ (when (elmo-global-flag-p flag)
+ (let ((message-id (elmo-message-field folder number 'message-id)))
+ (elmo-global-flag-set flag folder number message-id)))
+ (elmo-msgdb-set-flag (elmo-folder-msgdb folder)
+ number
+ flag))))
+
+(defun elmo-message-has-global-flag-p (folder number)
+ "Return non-nil when the message in the FOLDER with NUMBER has global flag."
+ (let ((flags (elmo-message-flags folder number))
+ result)
+ (while flags
+ (when (and (elmo-global-flag-p (car flags))
+ (not (memq (car flags) '(answered unread cached))))
+ (setq result t
+ flags nil))
+ (setq flags (cdr flags)))
+ result))
+
+(defun elmo-message-set-global-flags (folder number flags &optional local)
+ "Set global flags of the message in the FOLDER with NUMBER as FLAGS.
+If Optional LOCAL is non-nil, don't update server flag."
+ (dolist (flag flags)
+ (unless (elmo-global-flag-p flag)
+ (error "Not a global flag")))
+ (let ((old-flags (elmo-get-global-flags (elmo-message-flags folder number))))
+ (dolist (flag flags)
+ (unless (memq flag old-flags)
+ (elmo-message-set-flag folder number flag local)))
+ (dolist (flag old-flags)
+ (unless (memq flag flags)
+ (elmo-message-unset-flag folder number flag local)))))
+
+(luna-define-method elmo-folder-unset-flag ((folder elmo-folder)
+ numbers
+ flag
+ &optional is-local)
+ (when (elmo-folder-msgdb-internal folder)
+ (dolist (number numbers)
+ (when (elmo-global-flag-p flag)
+ (elmo-global-flag-detach flag folder number 'always))
+ (elmo-msgdb-unset-flag (elmo-folder-msgdb folder)
+ number
+ flag))))
+
+(luna-define-method elmo-folder-process-crosspost ((folder elmo-folder))
;; Do nothing.
)
-(defun elmo-generic-folder-append-msgdb (folder append-msgdb)
+;;(luna-define-generic elmo-folder-append-message-entity (folder entity
+;; &optional
+;; flag-table)
+;; "Append ENTITY to the folder.")
+
+(defun elmo-msgdb-merge (folder msgdb-merge)
+ "Return a list of messages which have duplicated message-id."
+ (let (msgdb duplicates)
+ (setq msgdb (or (elmo-folder-msgdb-internal folder)
+ (elmo-make-msgdb (elmo-folder-msgdb-path folder))))
+ (setq duplicates (elmo-msgdb-append msgdb msgdb-merge))
+ (elmo-folder-set-msgdb-internal folder msgdb)
+ duplicates))
+
+(defsubst elmo-folder-append-msgdb (folder append-msgdb)
(if append-msgdb
- (let* ((number-alist (elmo-msgdb-get-number-alist append-msgdb))
- (all-alist (copy-sequence (append
- (elmo-msgdb-get-number-alist
- (elmo-folder-msgdb folder))
- number-alist)))
- (cur number-alist)
- pair overview
- to-be-deleted
- mark-alist)
- (while cur
- (setq all-alist (delq (car cur) all-alist))
- ;; same message id exists.
- (if (setq pair (rassoc (cdr (car cur)) all-alist))
- (setq to-be-deleted (nconc to-be-deleted (list (car pair)))))
- (setq cur (cdr cur)))
+ (let ((duplicates (elmo-msgdb-merge folder append-msgdb)))
(cond ((eq (elmo-folder-process-duplicates-internal folder)
'hide)
- ;; Hide duplicates.
- (setq overview (elmo-delete-if
- (lambda (x)
- (memq (elmo-msgdb-overview-entity-get-number
- x)
- to-be-deleted))
- (elmo-msgdb-get-overview append-msgdb)))
- ;; Should be mark as read.
- (elmo-folder-mark-as-read folder to-be-deleted)
- (elmo-msgdb-set-overview append-msgdb overview))
+ ;; Let duplicates be a temporary killed message.
+ (elmo-folder-kill-messages folder duplicates)
+ ;; Should be flag as read.
+ (elmo-folder-set-flag folder duplicates 'read))
((eq (elmo-folder-process-duplicates-internal folder)
'read)
- ;; Mark as read duplicates.
- (elmo-folder-mark-as-read folder to-be-deleted))
+ ;; Flag as read duplicates.
+ (elmo-folder-set-flag folder duplicates 'read))
(t
;; Do nothing.
- (setq to-be-deleted nil)))
- (elmo-folder-set-msgdb-internal folder
- (elmo-msgdb-append
- (elmo-folder-msgdb folder)
- append-msgdb t))
- (length to-be-deleted))
+ (setq duplicates nil)))
+ (length duplicates))
0))
-(luna-define-method elmo-folder-append-msgdb ((folder elmo-folder)
- append-msgdb)
- (elmo-generic-folder-append-msgdb folder append-msgdb))
-
(defun elmo-folder-confirm-appends (appends)
(let ((len (length appends))
in)
(if (and elmo-folder-update-threshold
(> len elmo-folder-update-threshold)
elmo-folder-update-confirm)
- (if (y-or-n-p (format "Too many messages(%d). Continue? " len))
+ (if (y-or-n-p (format "Too many messages(%d). Update all? " len))
appends
(setq in elmo-folder-update-threshold)
(catch 'end
in (string-to-int in))
(if (< len in)
(throw 'end len))
- (if (y-or-n-p (format "%d messages are not appeared. OK? "
- (max (- len in) 0)))
+ (if (y-or-n-p (format
+ "%d messages are killed (not appeared). OK? "
+ (max (- len in) 0)))
(throw 'end in))))
(nthcdr (max (- len in) 0) appends))
(if (and elmo-folder-update-threshold
(with-current-buffer outbuf
(erase-buffer)
(elmo-message-fetch-with-cache-process folder number
- strategy section unread)
- t)
+ strategy section unread))
(with-temp-buffer
(elmo-message-fetch-with-cache-process folder number
strategy section unread)
number strategy
&optional
section unread)
- (let (cache-path cache-file)
- (if (and (elmo-fetch-strategy-use-cache strategy)
- (setq cache-path (elmo-fetch-strategy-cache-path strategy))
- (setq cache-file (elmo-file-cache-expand-path
- cache-path
- section))
- (file-exists-p cache-file)
- (or (not (elmo-cache-path-section-p cache-file))
- (not (eq (elmo-fetch-strategy-entireness strategy) 'entire))))
- (insert-file-contents-as-binary cache-file)
- (elmo-message-fetch-internal folder number strategy section unread)
- (elmo-delete-cr-buffer)
- (when (and (> (buffer-size) 0)
- (elmo-fetch-strategy-save-cache strategy)
- (elmo-fetch-strategy-cache-path strategy))
- (elmo-file-cache-save
- (elmo-fetch-strategy-cache-path strategy)
- section)))))
+ (let ((cache-path (elmo-fetch-strategy-cache-path strategy))
+ (method-priorities
+ (cond ((eq (elmo-fetch-strategy-use-cache strategy) 'maybe)
+ '(entity cache))
+ ((elmo-fetch-strategy-use-cache strategy)
+ '(cache entity))
+ (t
+ '(entity))))
+ result err)
+ (while (and method-priorities
+ (null result))
+ (setq result
+ (case (car method-priorities)
+ (cache
+ (elmo-file-cache-load cache-path section))
+ (entity
+ (when (and (condition-case error
+ (elmo-message-fetch-internal folder number
+ strategy
+ section
+ unread)
+ (error (setq err error) nil))
+ (> (buffer-size) 0))
+ (elmo-delete-cr-buffer)
+ (when (and (elmo-fetch-strategy-save-cache strategy)
+ cache-path)
+ (elmo-file-cache-save cache-path section))
+ t)))
+ method-priorities (cdr method-priorities)))
+ (or result
+ (and err (signal (car err) (cdr err))))))
+
+(defun elmo-folder-kill-messages-range (folder beg end)
+ (elmo-folder-set-killed-list-internal
+ folder
+ (nconc
+ (elmo-folder-killed-list-internal folder)
+ (list (cons beg end)))))
+
+(defun elmo-folder-kill-messages (folder numbers)
+ "Kill(hide) messages in the FOLDER with NUMBERS."
+ (let ((msgdb (elmo-folder-msgdb folder))
+ (killed (elmo-folder-killed-list-internal folder)))
+ (dolist (number numbers)
+ (elmo-number-set-append killed number)
+ (elmo-msgdb-unset-flag msgdb number 'all))
+ (elmo-folder-set-killed-list-internal folder killed)))
+
(luna-define-method elmo-folder-clear ((folder elmo-folder)
&optional keep-killed)
(unless keep-killed
(elmo-folder-set-killed-list-internal folder nil))
- (elmo-folder-set-msgdb-internal folder (elmo-msgdb-clear)))
-
-(defun elmo-folder-synchronize (folder
- new-mark ;"N"
- unread-uncached-mark ;"U"
- unread-cached-mark ;"!"
- read-uncached-mark ;"u"
- important-mark ;"$"
- &optional ignore-msgdb
- no-check)
+ (if (eq elmo-msgdb-convert-type 'sync)
+ (elmo-folder-set-msgdb-internal
+ folder
+ (elmo-make-msgdb (elmo-folder-msgdb-path folder)))
+ (elmo-msgdb-clear (elmo-folder-msgdb folder))))
+
+(luna-define-generic elmo-folder-synchronize (folder
+ &optional
+ disable-killed
+ ignore-msgdb
+ no-check)
"Synchronize the folder data to the newest status.
FOLDER is the ELMO folder structure.
-NEW-MARK, UNREAD-CACHED-MARK, READ-UNCACHED-MARK, and IMPORTANT-MARK
-are mark strings for new messages, unread but cached messages,
-read but not cached messages, and important messages.
+
+If optional DISABLE-KILLED is non-nil, killed messages are also synchronized.
If optional IGNORE-MSGDB is non-nil, current msgdb is thrown away except
-read mark status. If IGNORE-MSGDB is 'visible-only, only visible messages
-\(the messages which are not in the killed-list\) are thrown away and
-synchronized.
+flag status.
If NO-CHECK is non-nil, rechecking folder is skipped.
-
-Return a list of
-\(NEW-MSGDB DELETE-LIST CROSSED\)
-NEW-MSGDB is the newly appended msgdb.
-DELETE-LIST is a list of deleted message number.
-CROSSED is cross-posted message number.
-If update process is interrupted, return nil."
+Return a list of a cross-posted message number.
+If update process is interrupted, return nil.")
+
+(luna-define-method elmo-folder-synchronize ((folder elmo-folder)
+ &optional
+ disable-killed
+ ignore-msgdb
+ no-check)
(let ((killed-list (elmo-folder-killed-list-internal folder))
(before-append t)
- number-alist mark-alist
- old-msgdb diff diff-2 delete-list new-list new-msgdb mark
- seen-list crossed after-append)
+ old-msgdb diff diff-2 delete-list new-list new-msgdb flag
+ flag-table crossed after-append)
(setq old-msgdb (elmo-folder-msgdb folder))
- ;; Load seen-list.
- (setq seen-list (elmo-msgdb-seen-load (elmo-folder-msgdb-path folder)))
- (setq number-alist (elmo-msgdb-get-number-alist
- (elmo-folder-msgdb folder)))
- (setq mark-alist (elmo-msgdb-get-mark-alist
- (elmo-folder-msgdb folder)))
- (if ignore-msgdb
- (progn
- (setq seen-list (nconc
- (elmo-msgdb-mark-alist-to-seen-list
- number-alist mark-alist
- (concat important-mark read-uncached-mark))
- seen-list))
- (elmo-folder-clear folder (eq ignore-msgdb 'visible-only))))
+ (setq flag-table (elmo-flag-table-load (elmo-folder-msgdb-path folder)))
+ (when ignore-msgdb
+ (elmo-msgdb-flag-table (elmo-folder-msgdb folder) flag-table)
+ (elmo-folder-clear folder (not disable-killed)))
(unless no-check (elmo-folder-check folder))
(condition-case nil
(progn
(message "Checking folder diff...")
- ;; TODO: killed list is loaded in elmo-folder-open and
- ;; list-messages use internal killed-list-folder.
(setq diff (elmo-list-diff (elmo-folder-list-messages
folder
- (eq 'visible-only ignore-msgdb))
- (unless ignore-msgdb
- (sort (mapcar
- 'car
- number-alist)
- '<))))
+ (not disable-killed))
+ (elmo-folder-list-messages
+ folder
+ (not disable-killed)
+ 'in-msgdb)))
(message "Checking folder diff...done")
(setq new-list (elmo-folder-confirm-appends (car diff)))
- ;; Set killed list.
+ ;; Set killed list as ((1 . MAX-OF-DISAPPEARED))
(when (and (not (eq (length (car diff))
(length new-list)))
(setq diff-2 (elmo-list-diff (car diff) new-list)))
- (elmo-msgdb-append-to-killed-list folder (car diff-2)))
- ;; Don't delete important marked messages.
- (setq delete-list
- (if (eq (elmo-folder-type-internal folder) 'mark)
- (cadr diff)
- (elmo-delete-if
- (lambda (x)
- (and (setq mark (cadr (assq x mark-alist)))
- (string= mark important-mark)))
- ;; delete message list
- (cadr diff))))
+ (elmo-folder-kill-messages-range
+ folder
+ (car (car diff-2))
+ (nth (- (length (car diff-2)) 1) (car diff-2))))
+ (setq delete-list (cadr diff))
(if (or (equal diff '(nil nil))
(equal diff '(nil))
(and (eq (length (car diff)) 0)
(progn
(elmo-folder-update-number folder)
(elmo-folder-process-crosspost folder)
- (list nil nil nil) ; no updates.
+ 0 ; no updates.
)
- (if delete-list (elmo-msgdb-delete-msgs
- (elmo-folder-msgdb folder) delete-list))
+ (when delete-list
+ (elmo-folder-detach-messages folder delete-list))
(when new-list
+ (elmo-msgdb-out-of-date-messages (elmo-folder-msgdb folder))
(setq new-msgdb (elmo-folder-msgdb-create
- folder
- new-list
- new-mark unread-cached-mark
- read-uncached-mark important-mark
- seen-list))
- (elmo-msgdb-change-mark (elmo-folder-msgdb folder)
- new-mark unread-uncached-mark)
- ;; Clear seen-list.
+ folder new-list flag-table))
+ ;; Clear flag-table
(if (elmo-folder-persistent-p folder)
- (setq seen-list (elmo-msgdb-seen-save
- (elmo-folder-msgdb-path folder) nil)))
+ (elmo-flag-table-save (elmo-folder-msgdb-path folder)
+ nil))
(setq before-append nil)
(setq crossed (elmo-folder-append-msgdb folder new-msgdb))
;; process crosspost.
- ;; Return a cons cell of (NUMBER-CROSSPOSTS . NEW-MARK-ALIST).
- (elmo-folder-process-crosspost folder)
- (elmo-folder-set-message-modified-internal folder t)
- (elmo-folder-set-mark-modified-internal folder t))
+ ;; Return a cons cell of (NUMBER-CROSSPOSTS . NEW-FLAG-ALIST).
+ (elmo-folder-process-crosspost folder))
;; return value.
- (list new-msgdb delete-list crossed)))
+ (or crossed 0)))
(quit
;; Resume to the original status.
- (if before-append
- (elmo-folder-set-msgdb-internal folder old-msgdb))
+ (if before-append (elmo-folder-set-msgdb-internal folder old-msgdb))
(elmo-folder-set-killed-list-internal folder killed-list)
nil))))
-(defun elmo-folder-messages (folder)
- "Return number of messages in the FOLDER."
- (length
- (elmo-msgdb-get-number-alist
- (elmo-folder-msgdb folder))))
-
-;;;
-(defun elmo-msgdb-search (folder condition msgdb)
- "Search messages which satisfy CONDITION from FOLDER with MSGDB."
- (let* ((condition (car (elmo-parse-search-condition condition)))
- (overview (elmo-msgdb-get-overview msgdb))
- (number-alist (elmo-msgdb-get-number-alist msgdb))
- (number-list (mapcar 'car number-alist))
- (length (length overview))
- (i 0)
- result)
- (if (not (elmo-condition-in-msgdb-p condition))
- (elmo-folder-search folder condition number-list)
- (while overview
- (if (elmo-msgdb-search-internal condition (car overview)
- number-list)
- (setq result
- (cons
- (elmo-msgdb-overview-entity-get-number (car overview))
- result)))
- (setq i (1+ i))
- (elmo-display-progress
- 'elmo-msgdb-search "Searching..." (/ (* i 100) length))
- (setq overview (cdr overview)))
- (nreverse result))))
-
-(defun elmo-msgdb-load (folder)
- (message "Loading msgdb for %s..." (elmo-folder-name-internal folder))
- (let* ((path (elmo-folder-msgdb-path folder))
- (overview (elmo-msgdb-overview-load path))
- (msgdb (list overview
- (elmo-msgdb-number-load path)
- (elmo-msgdb-mark-load path)
- (elmo-msgdb-make-overview-hashtb overview))))
- (message "Loading msgdb for %s...done" (elmo-folder-name-internal folder))
- (elmo-folder-set-info-max-by-numdb folder
- (elmo-msgdb-get-number-alist msgdb))
+(luna-define-generic elmo-folder-detach-messages (folder numbers)
+ "Remove messages with NUMBERS from MSGDB.")
+
+(luna-define-method elmo-folder-detach-messages ((folder elmo-folder)
+ numbers)
+ (elmo-msgdb-delete-messages (elmo-folder-msgdb folder) numbers))
+
+(luna-define-generic elmo-folder-length (folder)
+ "Return number of messages in the FOLDER.")
+
+(luna-define-method elmo-folder-length ((folder elmo-folder))
+ (if (elmo-folder-msgdb-internal folder)
+ (elmo-msgdb-length (elmo-folder-msgdb folder))
+ 0))
+
+(defun elmo-folder-msgdb-load (folder &optional silent)
+ (unless silent
+ (message "Loading msgdb for %s..." (elmo-folder-name-internal folder)))
+ (let ((msgdb (elmo-load-msgdb (elmo-folder-msgdb-path folder))))
+ (elmo-folder-set-info-max-by-numdb
+ folder
+ (elmo-msgdb-list-messages msgdb))
+ (unless silent
+ (message "Loading msgdb for %s...done"
+ (elmo-folder-name-internal folder)))
msgdb))
(defun elmo-msgdb-delete-path (folder)
(elmo-crosspost-alist-save elmo-crosspost-message-alist)
(setq elmo-crosspost-message-alist-modified nil))))
-(defun elmo-folder-make-temp-dir (folder)
+(defun elmo-folder-make-temporary-directory (folder)
;; Make a temporary directory for FOLDER.
(let ((temp-dir (make-temp-name
(concat
"Initialize ELMO module."
(elmo-crosspost-message-alist-load)
(elmo-resque-obsolete-variables)
- (elmo-dop-queue-load))
+ (elmo-dop-queue-load)
+ (run-hooks 'elmo-init-hook))
(defun elmo-quit ()
"Quit and cleanup ELMO."
(while types
(setq class
(luna-find-class
- (intern (format "elmo-%s-folder" (symbol-name (cdr (car types)))))))
+ (intern (format "elmo-%s-folder"
+ (symbol-name (cdr (car types)))))))
;; Call all folder's `elmo-quit' method.
(if class
(dolist (func (luna-class-find-functions class 'elmo-quit))
(funcall func nil)))
(setq types (cdr types)))))
+(luna-define-method elmo-folder-rename-internal ((folder elmo-folder)
+ new-folder)
+ (error "Cannot rename %s folder"
+ (symbol-name (elmo-folder-type-internal folder))))
;;; Define folders.
(elmo-define-folder ?% 'imap4)
'elmo-imap4-default-user)
(elmo-define-obsolete-variable 'elmo-default-imap4-port
'elmo-imap4-default-port)
+(elmo-define-obsolete-variable 'elmo-default-imap4-stream-type
+ 'elmo-imap4-default-stream-type)
(elmo-define-obsolete-variable 'elmo-default-nntp-server
'elmo-nntp-default-server)
(elmo-define-obsolete-variable 'elmo-default-nntp-user
'elmo-nntp-default-user)
(elmo-define-obsolete-variable 'elmo-default-nntp-port
'elmo-nntp-default-port)
+(elmo-define-obsolete-variable 'elmo-default-nntp-stream-type
+ 'elmo-nntp-default-stream-type)
(elmo-define-obsolete-variable 'elmo-default-pop3-server
'elmo-pop3-default-server)
(elmo-define-obsolete-variable 'elmo-default-pop3-user
'elmo-pop3-default-authenticate-type)
(elmo-define-obsolete-variable 'elmo-default-pop3-port
'elmo-pop3-default-port)
-
-;; autoloads
-(autoload 'elmo-dop-queue-flush "elmo-dop")
+(elmo-define-obsolete-variable 'elmo-default-pop3-stream-type
+ 'elmo-pop3-default-stream-type)
+(elmo-define-obsolete-variable 'elmo-cache-dirname
+ 'elmo-cache-directory)
+(elmo-define-obsolete-variable 'elmo-msgdb-dir
+ 'elmo-msgdb-directory)
+
+;; Obsolete functions.
+;; 2001-12-11: *-dir -> *-directory
+(defalias 'elmo-folder-make-temp-dir 'elmo-folder-make-temporary-directory)
+(make-obsolete 'elmo-folder-make-temp-dir
+ 'elmo-folder-make-temporary-directory)
(require 'product)
(product-provide (provide 'elmo) (require 'elmo-version))