X-Git-Url: http://git.chise.org/gitweb/?a=blobdiff_plain;f=elmo%2Felmo.el;h=7a8b7815648cf6cc4e0724674d4e38bcdd129f74;hb=298179ef92e7400bdab05f509725ebfb9672b038;hp=d974213c5d090141520f064fbb10ba5f8b8a2fe8;hpb=88d92346ec94d9f4c094659671c0c591c00d3bbd;p=elisp%2Fwanderlust.git diff --git a/elmo/elmo.el b/elmo/elmo.el index d974213..7a8b781 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") @@ -121,6 +123,7 @@ If a folder name begins with PREFIX, use BACKEND." persistent ; non-nil if persistent. process-duplicates ; read or hide biff ; folder for biff + handlers ; list of event handler. )) (luna-define-internal-accessors 'elmo-folder)) @@ -141,8 +144,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))))) @@ -313,12 +316,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. @@ -369,6 +378,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.") @@ -377,8 +389,9 @@ FOLDER is the ELMO folder structure.") 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). -If it is nil, it is not that there is no flag and what is not defined is meant. +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.") @@ -395,7 +408,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.") @@ -453,22 +467,17 @@ Return newly created temporary directory name which contains temporary files.") (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 &optional msgid) +(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. -If optional argument MSGID is specified, -the message with NUMBER checks whether it has MSGID.") - -(luna-define-method elmo-message-flags ((folder elmo-folder) number - &optional msgid) - (if msgid - (let ((this-id (elmo-message-field folder number 'message-id))) - (and this-id - (string= this-id msgid) - (or (elmo-msgdb-flags (elmo-folder-msgdb folder) number) - '(read)))) - (elmo-msgdb-flags (elmo-folder-msgdb folder) number))) +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)) (defsubst elmo-message-flagged-p (folder number flag) "Return non-nil if the message is set FLAG. @@ -694,16 +703,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. @@ -754,6 +764,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) @@ -800,7 +815,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 @@ -808,7 +823,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))))) @@ -941,8 +956,7 @@ If optional argument IF-EXISTS is nil, load on demand. (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) @@ -1050,10 +1064,13 @@ If optional argument IF-EXISTS is nil, load on demand. (> (buffer-size) 0) (elmo-folder-append-buffer folder - (elmo-message-flags - src-folder - (car numbers) - (elmo-msgdb-get-message-id-from-buffer)) + (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 @@ -1092,8 +1109,7 @@ If optional argument IF-EXISTS is nil, load on demand. (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)) @@ -1148,6 +1164,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. @@ -1184,14 +1206,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. @@ -1230,7 +1252,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. @@ -1261,7 +1283,8 @@ VALUE is a value to set.") (elmo-global-flag-set flag folder number message-id))) (elmo-msgdb-set-flag (elmo-folder-msgdb folder) number - flag)))) + flag)) + (elmo-folder-notify-event folder 'flag-changed numbers))) (defun elmo-message-has-global-flag-p (folder number) "Return non-nil when the message in the FOLDER with NUMBER has global flag." @@ -1299,7 +1322,8 @@ If Optional LOCAL is non-nil, don't update server flag." (elmo-global-flag-detach flag folder number 'always)) (elmo-msgdb-unset-flag (elmo-folder-msgdb folder) number - flag)))) + flag)) + (elmo-folder-notify-event folder 'flag-changed numbers))) (luna-define-method elmo-folder-process-crosspost ((folder elmo-folder)) ;; Do nothing. @@ -1327,11 +1351,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))) @@ -1450,7 +1474,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. @@ -1458,6 +1483,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.") @@ -1465,47 +1492,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 @@ -1534,7 +1561,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.") @@ -1619,6 +1653,31 @@ Return a hashtable for newsgroups." (elmo-make-directory temp-dir) temp-dir)) +;; Event notification/observer framework +(eval-and-compile + (luna-define-class elmo-event-handler ())) + +(luna-define-generic elmo-event-handler-flag-changed (handler numbers) + "Notify flag of the messages with NUMBERS is changed.") + +(defun elmo-folder-add-handler (folder handler) + (unless (memq handler (elmo-folder-handlers-internal folder)) + (elmo-folder-set-handlers-internal + folder + (cons handler (elmo-folder-handlers-internal folder))))) + +(defun elmo-folder-remove-handler (folder handler) + (elmo-folder-set-handlers-internal + folder + (delq handler (elmo-folder-handlers-internal folder)))) + +(defun elmo-folder-notify-event (folder event &rest args) + (when (elmo-folder-handlers-internal folder) + (let ((message (format "elmo-event-handler-%s" event))) + (dolist (handler (elmo-folder-handlers-internal folder)) + (apply #'luna-send handler message handler args))))) + +;;; (defun elmo-init () "Initialize ELMO module." (elmo-crosspost-message-alist-load) @@ -1699,6 +1758,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