X-Git-Url: http://git.chise.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=elmo%2Felmo.el;h=b111675ce764a71e1bb6b5a9e15670a44324b275;hb=50a175807caa995602ccd01dc65698cdd603f013;hp=0dcfae05bbabd1b5e467a4d0a64356e7e5efd651;hpb=d6f0f1d102813e2bf503ab8f524363dbd501ede4;p=elisp%2Fwanderlust.git diff --git a/elmo/elmo.el b/elmo/elmo.el index 0dcfae0..b111675 100644 --- a/elmo/elmo.el +++ b/elmo/elmo.el @@ -46,7 +46,8 @@ (defcustom elmo-message-fetch-threshold 30000 "Fetch threshold." - :type 'integer + :type '(choice (integer :tag "Threshold (bytes)") + (const :tag "No limitation" nil)) :group 'elmo) (defcustom elmo-message-fetch-confirm t @@ -84,6 +85,7 @@ Otherwise, entire fetching of the message is aborted without confirmation." (autoload 'elmo-dop-queue-flush "elmo-dop") (autoload 'elmo-nntp-post "elmo-nntp") (autoload 'elmo-global-flag-p "elmo-flag") + (autoload 'elmo-local-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") @@ -117,6 +119,7 @@ If a folder name begins with PREFIX, use BACKEND." path ; directory path for msgdb. msgdb ; msgdb (may be nil). killed-list ; killed list. + flag-table ; flag table. persistent ; non-nil if persistent. process-duplicates ; read or hide biff ; folder for biff @@ -140,8 +143,8 @@ If optional argument NON-PERSISTENT is non-nil, the folder msgdb is not saved." (setq original (elmo-string name)) (if type (progn - (setq prefix (substring name 0 1)) - (setq name (substring name 1))) + (setq prefix (elmo-string (substring name 0 1))) + (setq name (elmo-string (substring name 1)))) (setq type (intern (car (setq split (split-string name ":"))))) (if (>= (length split) 2) (setq name (substring name (+ 1 (length (car split))))) @@ -232,10 +235,10 @@ If second optional IN-MSGDB is non-nil, only messages in the msgdb are listed.") (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) + (if (and in-msgdb killed-list) + (elmo-uniq-sorted-list + (sort (nconc (elmo-number-set-to-number-list killed-list) list) #'<) + #'eq) list)))) (luna-define-generic elmo-folder-list-messages-internal (folder &optional @@ -312,12 +315,18 @@ Otherwise, all descendent folders are returned.") "Rename FOLDER to NEW-NAME (string).") (luna-define-generic elmo-folder-delete-messages (folder numbers) - "Delete messages. + "Delete messages with msgdb entity. FOLDER is the ELMO folder structure. 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-delete-messages-internal (folder numbers) + "Delete messages, but no delete msgdb entity. +FOLDER is the ELMO folder structure. +NUMBERS is a list of message numbers to be deleted. +Override this method by each implement of `elmo-folder'.") + (luna-define-generic elmo-folder-search (folder condition &optional numbers) "Search and return list of message numbers. FOLDER is the ELMO folder structure. @@ -368,6 +377,9 @@ FLAG is a symbol which is one of the following: `all' (remove all flags) If optional IS-LOCAL is non-nil, update only local (not server) status.") +(luna-define-generic elmo-message-flag-available-p (folder number flag) + "Return non-nil when a message in the FOLDER with NUMBER treats FLAG.") + (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.") @@ -375,8 +387,10 @@ FOLDER is the ELMO folder structure.") (luna-define-generic elmo-folder-append-buffer (folder &optional flags number) "Append current buffer as a new message. -FOLDER is the destination folder(ELMO folder structure). -FLAGS is the status of appended message (list of symbols). +FOLDER is the destination folder (ELMO folder structure). +FLAGS is the flag list for the appended message (list of symbols). +If FLAGS contain `read', the message is appended as `not-unread'. +If it is nil, the appended message will be treated as `new'. If optional argument NUMBER is specified, the new message number is set \(if possible\). Return nil on failure.") @@ -393,7 +407,8 @@ Caller should make sure FOLDER is `writable'. SRC-FOLDER is the source ELMO folder structure. NUMBERS is the message numbers to be appended in the SRC-FOLDER. If second optional argument SAME-NUMBER is specified, -message number is preserved \(if possible\).") +message number is preserved \(if possible\). +Returns a list of message numbers successfully appended.") (luna-define-generic elmo-folder-pack-numbers (folder) "Pack message numbers of FOLDER.") @@ -456,6 +471,10 @@ Return newly created temporary directory name which contains temporary files.") FOLDER is a ELMO folder structure. NUMBER is a number of the message.") +(luna-define-method elmo-message-flag-available-p ((folder elmo-folder) number + flag) + (elmo-msgdb-flag-available-p (elmo-folder-msgdb folder) flag)) + (luna-define-method elmo-message-flags ((folder elmo-folder) number) (elmo-msgdb-flags (elmo-folder-msgdb folder) number)) @@ -683,16 +702,17 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-FLAG-ALIST).") (elmo-generic-folder-commit folder)) (defun elmo-generic-folder-commit (folder) - (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)))) + (when (elmo-folder-persistent-p folder) + (let ((msgdb (elmo-folder-msgdb-internal folder))) + (when msgdb + (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-save msgdb)))) + (elmo-msgdb-killed-list-save + (elmo-folder-msgdb-path folder) + (elmo-folder-killed-list-internal folder)))) (luna-define-method elmo-folder-close-internal ((folder elmo-folder)) ;; do nothing. @@ -743,6 +763,11 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-FLAG-ALIST).") (elmo-folder-send folder 'elmo-folder-rename-internal new-folder) (elmo-msgdb-rename-path folder new-folder))) +(luna-define-method elmo-folder-delete-messages ((folder elmo-folder) + numbers) + (and (elmo-folder-delete-messages-internal folder numbers) + (elmo-folder-detach-messages folder numbers))) + (luna-define-method elmo-folder-search ((folder elmo-folder) condition &optional numbers) @@ -789,7 +814,7 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-FLAG-ALIST).") cache-path)))) (when (and filename (file-readable-p filename)) (with-temp-buffer - (elmo-set-buffer-multibyte nil) + (set-buffer-multibyte nil) ;;(insert-file-contents-as-binary filename) (elmo-message-fetch folder number (elmo-make-fetch-strategy 'entire @@ -797,7 +822,7 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-FLAG-ALIST).") nil cache-path) nil (current-buffer) t) - (elmo-set-buffer-multibyte default-enable-multibyte-characters) + (set-buffer-multibyte default-enable-multibyte-characters) (decode-coding-region (point-min) (point-max) elmo-mime-display-as-is-coding-system) (elmo-buffer-field-condition-match condition number numbers))))) @@ -827,6 +852,39 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-FLAG-ALIST).") (luna-define-method elmo-folder-have-subfolder-p ((folder elmo-folder)) t) +;; Flag table +(luna-define-generic elmo-folder-flag-table (folder &optional if-exists) + "Return the flag-table of FOLDER. +If optional argument IF-EXISTS is nil, load on demand. +\(For internal use only.\)") + +(luna-define-generic elmo-folder-close-flag-table (folder) + "Close flag-table of FOLDER.") + +(luna-define-method elmo-folder-flag-table ((folder elmo-folder) + &optional if-exists) + (or (elmo-folder-flag-table-internal folder) + (unless if-exists + (elmo-folder-set-flag-table-internal + folder + (elmo-flag-table-load (elmo-folder-msgdb-path folder)))))) + +(luna-define-method elmo-folder-close-flag-table ((folder elmo-folder)) + (elmo-flag-table-save (elmo-folder-msgdb-path folder) + (elmo-folder-flag-table folder)) + (elmo-folder-set-flag-table-internal folder nil)) + +(defun elmo-folder-preserve-flags (folder msgid flags) + "Preserve FLAGS into FOLDER for a message that has MSGID." + (when (and msgid flags) + (let ((flag-table (elmo-folder-flag-table folder 'if-exists)) + load-now) + (when (setq load-now (null flag-table)) + (setq flag-table (elmo-folder-flag-table folder))) + (elmo-flag-table-set flag-table msgid flags) + (when load-now + (elmo-folder-close-flag-table folder))))) + ;;; Folder info ;; Folder info is a message number information cache (hashtable) (defsubst elmo-folder-get-info (folder &optional hashtb) @@ -897,8 +955,7 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-FLAG-ALIST).") (defsubst elmo-strict-folder-diff (folder) "Return folder diff information strictly from FOLDER." - (let ((in-db (sort (elmo-msgdb-list-messages (elmo-folder-msgdb folder)) - '<)) + (let ((in-db (sort (elmo-folder-list-messages folder nil 'in-msgdb) '<)) (in-folder (elmo-folder-list-messages folder)) append-list delete-list diff) (cons (if (equal in-folder in-db) @@ -973,17 +1030,16 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-FLAG-ALIST).") (defun elmo-generic-folder-append-messages (folder src-folder numbers same-number) (let ((src-msgdb-exists (not (zerop (elmo-folder-length src-folder)))) - unseen table flags + unseen table succeed-numbers failure cache id) - (setq table (elmo-flag-table-load (elmo-folder-msgdb-path folder))) + (setq table (elmo-folder-flag-table folder)) (with-temp-buffer (set-buffer-multibyte nil) (while numbers (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))) + 'message-id))) (condition-case nil (setq cache (elmo-file-cache-get id) failure @@ -1007,18 +1063,22 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-FLAG-ALIST).") (> (buffer-size) 0) (elmo-folder-append-buffer folder - (or flags '(read)) + (let ((this-id (elmo-message-field src-folder (car numbers) + 'message-id))) + (and this-id + (string= this-id + (elmo-msgdb-get-message-id-from-buffer)) + (or (elmo-message-flags src-folder (car numbers)) + '(read)))) (if same-number (car numbers)))))) (error (setq failure t))) ;; FETCH & APPEND finished (unless failure - (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))) (when (elmo-folder-persistent-p folder) - (elmo-flag-table-save (elmo-folder-msgdb-path folder) table)) + (elmo-folder-close-flag-table folder)) succeed-numbers))) ;; Arguments should be reduced. @@ -1048,8 +1108,7 @@ Return a cons cell of (NUMBER-CROSSPOSTS . NEW-FLAG-ALIST).") (elmo-folder-close dst-folder))) (if (and (not no-delete) succeeds) (progn - (if (and (elmo-folder-delete-messages src-folder succeeds) - (elmo-folder-detach-messages src-folder succeeds)) + (if (elmo-folder-delete-messages src-folder succeeds) (progn (elmo-global-flag-detach-messages src-folder succeeds (eq dst-folder 'null)) @@ -1104,6 +1163,12 @@ If CACHED is t, message is set as cached.") (elmo-msgdb-copy-message-entity (elmo-message-entity-handler entity) entity)) +(luna-define-generic elmo-message-number (folder message-id) + "Get message number from MSGDB which corresponds to MESSAGE-ID.") + +(luna-define-method elmo-message-number ((folder elmo-folder) message-id) + (elmo-msgdb-message-number (elmo-folder-msgdb folder) message-id)) + (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. @@ -1140,14 +1205,14 @@ ENTITY is the message-entity to get the parent.") (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')") +Return alist of flag and numbers. +Example: +\(\(new . 10\) + \(unread . 20\) + \(answered . 3\)\)") (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))) + (elmo-msgdb-flag-count (elmo-folder-msgdb folder))) (defun elmo-message-set-flag (folder number flag &optional is-local) "Set message flag. @@ -1186,7 +1251,7 @@ NUMBER is a number of the message. 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)) + (elmo-msgdb-message-field (elmo-folder-msgdb folder) number field)) (luna-define-generic elmo-message-set-field (folder number field value) "Set message field value in the msgdb. @@ -1283,11 +1348,11 @@ If Optional LOCAL is non-nil, don't update server flag." ;; 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)) + (elmo-folder-unset-flag folder duplicates 'unread)) ((eq (elmo-folder-process-duplicates-internal folder) 'read) ;; Flag as read duplicates. - (elmo-folder-set-flag folder duplicates 'read)) + (elmo-folder-unset-flag folder duplicates 'unread)) (t ;; Do nothing. (setq duplicates nil))) @@ -1406,7 +1471,8 @@ If Optional LOCAL is non-nil, don't update server flag." &optional disable-killed ignore-msgdb - no-check) + no-check + mask) "Synchronize the folder data to the newest status. FOLDER is the ELMO folder structure. @@ -1414,6 +1480,8 @@ 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 flag status. If NO-CHECK is non-nil, rechecking folder is skipped. +If optional argument MASK is specified and is a list of message numbers, +synchronize messages only which are contained the list. Return amount of cross-posted messages. If update process is interrupted, return nil.") @@ -1421,47 +1489,47 @@ If update process is interrupted, return nil.") &optional disable-killed ignore-msgdb - no-check) - (let ((killed-list (elmo-folder-killed-list-internal folder)) - (before-append t) - old-msgdb diff diff-2 delete-list new-list new-msgdb flag - flag-table crossed after-append) - (setq old-msgdb (elmo-folder-msgdb folder)) - (setq flag-table (elmo-flag-table-load (elmo-folder-msgdb-path folder))) + no-check + mask) + (let ((old-msgdb (elmo-folder-msgdb folder)) + (killed-list (elmo-folder-killed-list-internal folder)) + (flag-table (elmo-flag-table-load (elmo-folder-msgdb-path folder))) + (before-append t)) (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 + (let ((killed-list (elmo-folder-killed-list-internal folder)) + diff-new diff-del + delete-list new-list new-msgdb crossed) (message "Checking folder diff...") - (setq diff (elmo-list-diff (elmo-folder-list-messages - folder - (not disable-killed)) - (elmo-folder-list-messages - folder - (not disable-killed) - 'in-msgdb))) + (elmo-set-list + '(diff-new diff-del) + (elmo-list-diff (elmo-folder-list-messages folder) + (elmo-folder-list-messages folder nil 'in-msgdb))) + (when diff-new + (unless disable-killed + (setq diff-new (elmo-living-messages diff-new killed-list))) + (when mask + (setq diff-new (elmo-list-filter mask diff-new)))) (message "Checking folder diff...done") - (setq new-list (elmo-folder-confirm-appends (car diff))) - ;; 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-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) - (eq (length (cadr diff)) 0))) + (setq new-list (elmo-folder-confirm-appends diff-new)) + ;; Append to killed list as (MIN-OF-DISAPPEARED . MAX-OF-DISAPPEARED) + (when (not (eq (length diff-new) + (length new-list))) + (let* ((diff (elmo-list-diff diff-new new-list)) + (disappeared (car diff))) + (when disappeared + (elmo-folder-kill-messages-range folder + (car disappeared) + (elmo-last disappeared))))) + (setq delete-list diff-del) + (if (and (null diff-new) (null diff-del)) (progn (elmo-folder-update-number folder) (elmo-folder-process-crosspost folder) - 0 ; no updates. - ) + 0) ; `0' means no updates. (when delete-list (elmo-folder-detach-messages folder delete-list)) (when new-list @@ -1490,7 +1558,14 @@ If update process is interrupted, return nil.") (luna-define-method elmo-folder-detach-messages ((folder elmo-folder) numbers) - (elmo-msgdb-delete-messages (elmo-folder-msgdb folder) numbers)) + (when (elmo-msgdb-delete-messages (elmo-folder-msgdb folder) numbers) + ;; Remove NUMBERS from killed message list. + (elmo-folder-set-killed-list-internal + folder + (elmo-number-set-delete-list + (elmo-folder-killed-list-internal folder) + numbers)) + t)) (luna-define-generic elmo-folder-length (folder) "Return number of messages in the FOLDER.") @@ -1655,6 +1730,8 @@ Return a hashtable for newsgroups." 'elmo-cache-directory) (elmo-define-obsolete-variable 'elmo-msgdb-dir 'elmo-msgdb-directory) +(elmo-define-obsolete-variable 'elmo-global-flag-list + 'elmo-global-flags) ;; Obsolete functions. ;; 2001-12-11: *-dir -> *-directory