X-Git-Url: http://cgit.sxemacs.org/?p=gnus;a=blobdiff_plain;f=lisp%2Fnnmaildir.el;h=5b72b52079d4d874f4f9fb3287daf5fbcf64ae79;hp=827eafdc7ede490014bb5544c6223c5981c7c524;hb=5ceeed36bf0911861d47c8dce31b8737ae6a3902;hpb=c9a393eeb329a99695566342a9f03b8a30000898 diff --git a/lisp/nnmaildir.el b/lisp/nnmaildir.el index 827eafdc7..5b72b5207 100644 --- a/lisp/nnmaildir.el +++ b/lisp/nnmaildir.el @@ -59,24 +59,71 @@ ) ] -;; For Emacs < 22.2. -(eval-and-compile - (unless (fboundp 'declare-function) (defmacro declare-function (&rest r)))) - -(eval-and-compile - (require 'nnheader) - (require 'gnus) - (require 'gnus-util) - (require 'gnus-range) - (require 'gnus-start) - (require 'gnus-int) - (require 'message)) +(require 'nnheader) +(require 'gnus) +(require 'gnus-util) +(require 'gnus-range) +(require 'gnus-start) +(require 'gnus-int) +(require 'message) +(require 'nnmail) + (eval-when-compile - (require 'cl) - (require 'nnmail)) + (require 'cl)) (defconst nnmaildir-version "Gnus") +(defconst nnmaildir-flag-mark-mapping + '((?F . tick) + (?P . forward) + (?R . reply) + (?S . read)) + "Alist mapping Maildir filename flags to Gnus marks. +Maildir filenames are of the form \"unique-id:2,FLAGS\", +where FLAGS are a string of characters in ASCII order. +Some of the FLAGS correspond to Gnus marks.") + +(defsubst nnmaildir--mark-to-flag (mark) + "Find the Maildir flag that corresponds to MARK (an atom). +Return a character, or nil if not found. +See `nnmaildir-flag-mark-mapping'." + (car (rassq mark nnmaildir-flag-mark-mapping))) + +(defsubst nnmaildir--flag-to-mark (flag) + "Find the Gnus mark that corresponds to FLAG (a character). +Return an atom, or nil if not found. +See `nnmaildir-flag-mark-mapping'." + (cdr (assq flag nnmaildir-flag-mark-mapping))) + +(defun nnmaildir--ensure-suffix (filename) + "Ensure that FILENAME contains the suffix \":2,\"." + (if (gnus-string-match-p ":2," filename) + filename + (concat filename ":2,"))) + +(defun nnmaildir--add-flag (flag suffix) + "Return a copy of SUFFIX where FLAG is set. +SUFFIX should start with \":2,\"." + (unless (gnus-string-match-p "^:2," suffix) + (error "Invalid suffix `%s'" suffix)) + (let* ((flags (substring suffix 3)) + (flags-as-list (append flags nil)) + (new-flags + (concat (gnus-delete-duplicates + ;; maildir flags must be sorted + (sort (cons flag flags-as-list) '<))))) + (concat ":2," new-flags))) + +(defun nnmaildir--remove-flag (flag suffix) + "Return a copy of SUFFIX where FLAG is cleared. +SUFFIX should start with \":2,\"." + (unless (gnus-string-match-p "^:2," suffix) + (error "Invalid suffix `%s'" suffix)) + (let* ((flags (substring suffix 3)) + (flags-as-list (append flags nil)) + (new-flags (concat (delq flag flags-as-list)))) + (concat ":2," new-flags))) + (defvar nnmaildir-article-file-name nil "*The filename of the most recently requested article. This variable is set by nnmaildir-request-article.") @@ -152,6 +199,16 @@ by nnmaildir-request-article.") (gnm nil) ;; flag: split from mail-sources? (target-prefix nil :type string)) ;; symlink target prefix +(defun nnmaildir--article-set-flags (article new-suffix curdir) + (let* ((prefix (nnmaildir--art-prefix article)) + (suffix (nnmaildir--art-suffix article)) + (article-file (concat curdir prefix suffix)) + (new-name (concat curdir prefix new-suffix))) + (unless (file-exists-p article-file) + (error "Couldn't find article file %s" article-file)) + (rename-file article-file new-name 'replace) + (setf (nnmaildir--art-suffix article) new-suffix))) + (defun nnmaildir--expired-article (group article) (setf (nnmaildir--art-nov article) nil) (let ((flist (nnmaildir--grp-flist group)) @@ -208,33 +265,33 @@ by nnmaildir-request-article.") (eval param)) (defmacro nnmaildir--with-nntp-buffer (&rest body) - `(save-excursion - (set-buffer nntp-server-buffer) + (declare (debug (body))) + `(with-current-buffer nntp-server-buffer ,@body)) (defmacro nnmaildir--with-work-buffer (&rest body) - `(save-excursion - (set-buffer (get-buffer-create " *nnmaildir work*")) + (declare (debug (body))) + `(with-current-buffer (get-buffer-create " *nnmaildir work*") ,@body)) (defmacro nnmaildir--with-nov-buffer (&rest body) - `(save-excursion - (set-buffer (get-buffer-create " *nnmaildir nov*")) + (declare (debug (body))) + `(with-current-buffer (get-buffer-create " *nnmaildir nov*") ,@body)) (defmacro nnmaildir--with-move-buffer (&rest body) - `(save-excursion - (set-buffer (get-buffer-create " *nnmaildir move*")) + (declare (debug (body))) + `(with-current-buffer (get-buffer-create " *nnmaildir move*") ,@body)) -(defmacro nnmaildir--subdir (dir subdir) - `(file-name-as-directory (concat ,dir ,subdir))) -(defmacro nnmaildir--srvgrp-dir (srv-dir gname) - `(nnmaildir--subdir ,srv-dir ,gname)) -(defmacro nnmaildir--tmp (dir) `(nnmaildir--subdir ,dir "tmp")) -(defmacro nnmaildir--new (dir) `(nnmaildir--subdir ,dir "new")) -(defmacro nnmaildir--cur (dir) `(nnmaildir--subdir ,dir "cur")) -(defmacro nnmaildir--nndir (dir) `(nnmaildir--subdir ,dir ".nnmaildir")) -(defmacro nnmaildir--nov-dir (dir) `(nnmaildir--subdir ,dir "nov")) -(defmacro nnmaildir--marks-dir (dir) `(nnmaildir--subdir ,dir "marks")) -(defmacro nnmaildir--num-dir (dir) `(nnmaildir--subdir ,dir "num")) +(defsubst nnmaildir--subdir (dir subdir) + (file-name-as-directory (concat dir subdir))) +(defsubst nnmaildir--srvgrp-dir (srv-dir gname) + (nnmaildir--subdir srv-dir gname)) +(defsubst nnmaildir--tmp (dir) (nnmaildir--subdir dir "tmp")) +(defsubst nnmaildir--new (dir) (nnmaildir--subdir dir "new")) +(defsubst nnmaildir--cur (dir) (nnmaildir--subdir dir "cur")) +(defsubst nnmaildir--nndir (dir) (nnmaildir--subdir dir ".nnmaildir")) +(defsubst nnmaildir--nov-dir (dir) (nnmaildir--subdir dir "nov")) +(defsubst nnmaildir--marks-dir (dir) (nnmaildir--subdir dir "marks")) +(defsubst nnmaildir--num-dir (dir) (nnmaildir--subdir dir "num")) (defmacro nnmaildir--unlink (file-arg) `(let ((file ,file-arg)) @@ -277,29 +334,24 @@ by nnmaildir-request-article.") ;; given group, if non-nil, be the current group of the current server. Then ;; return the group object for the current group. (defun nnmaildir--prepare (server group) - (let (x groups) - (catch 'return - (if (null server) - (unless (setq server nnmaildir--cur-server) - (throw 'return nil)) - (unless (setq server (intern-soft server nnmaildir--servers)) + (catch 'return + (if (null server) + (unless (setq server nnmaildir--cur-server) (throw 'return nil)) - (setq server (symbol-value server) - nnmaildir--cur-server server)) - (unless (setq groups (nnmaildir--srv-groups server)) + (unless (setq server (intern-soft server nnmaildir--servers)) (throw 'return nil)) - (unless (nnmaildir--srv-method server) - (setq x (concat "nnmaildir:" (nnmaildir--srv-address server)) - x (gnus-server-to-method x)) - (unless x (throw 'return nil)) - (setf (nnmaildir--srv-method server) x)) - (if (null group) - (unless (setq group (nnmaildir--srv-curgrp server)) - (throw 'return nil)) - (unless (setq group (intern-soft group groups)) - (throw 'return nil)) - (setq group (symbol-value group))) - group))) + (setq server (symbol-value server) + nnmaildir--cur-server server)) + (let ((groups (nnmaildir--srv-groups server))) + (when groups + (unless (nnmaildir--srv-method server) + (setf (nnmaildir--srv-method server) + (or (gnus-server-to-method + (concat "nnmaildir:" (nnmaildir--srv-address server))) + (throw 'return nil)))) + (if (null group) + (nnmaildir--srv-curgrp server) + (symbol-value (intern-soft group groups))))))) (defun nnmaildir--tab-to-space (string) (let ((pos 0)) @@ -309,6 +361,7 @@ by nnmaildir-request-article.") string) (defmacro nnmaildir--condcase (errsym body &rest handler) + (declare (debug (sexp form body))) `(condition-case ,errsym (let ((system-messages-locale "C")) ,body) (error . ,handler))) @@ -371,7 +424,7 @@ by nnmaildir-request-article.") (srv-dir (nnmaildir--srv-dir server)) (storage-version 1) ;; [version article-number msgid [...nov...]] dir gname pgname msgdir prefix suffix file attr mtime novdir novfile - nov msgid nov-beg nov-mid nov-end field val old-extra num numdir + nov msgid nov-beg nov-mid nov-end field val old-extra num deactivate-mark) (catch 'return (setq gname (nnmaildir--grp-name group) @@ -611,7 +664,7 @@ by nnmaildir-request-article.") "/" "\\057" 'literal) ":" "\\072" 'literal)) -(defun nnmaildir-request-type (group &optional article) +(defun nnmaildir-request-type (_group &optional _article) 'mail) (defun nnmaildir-status-message (&optional server) @@ -711,7 +764,7 @@ by nnmaildir-request-article.") (if (> (aref a 1) (aref b 1)) (throw 'return nil)) (string-lessp (aref a 2) (aref b 2)))) -(defun nnmaildir--scan (gname scan-msgs groups method srv-dir srv-ls) +(defun nnmaildir--scan (gname scan-msgs groups _method srv-dir srv-ls) (catch 'return (let ((36h-ago (- (car (current-time)) 2)) absdir nndir tdir ndir cdir nattr cattr isnew pgname read-only ls @@ -763,7 +816,7 @@ by nnmaildir-request-article.") (dolist (file (funcall ls ndir nil "\\`[^.]" 'nosort)) (setq x (concat ndir file)) (and (time-less-p (nth 5 (file-attributes x)) (current-time)) - (rename-file x (concat cdir file ":2,")))) + (rename-file x (concat cdir (nnmaildir--ensure-suffix file))))) (setf (nnmaildir--grp-new group) nattr)) (setq cattr (nth 5 (file-attributes cdir))) (if (equal cattr (nnmaildir--grp-cur group)) @@ -788,11 +841,23 @@ by nnmaildir-request-article.") cdir (nnmaildir--marks-dir nndir) ndir (nnmaildir--subdir cdir "tick") cdir (nnmaildir--subdir cdir "read")) - (dolist (file files) - (setq file (car file)) - (if (or (not (file-exists-p (concat cdir file))) - (file-exists-p (concat ndir file))) - (setq num (1+ num))))) + (dolist (prefix-suffix files) + (let ((prefix (car prefix-suffix)) + (suffix (cdr prefix-suffix))) + ;; increase num for each unread or ticked article + (when (or + ;; first look for marks in suffix, if it's valid... + (when (and (stringp suffix) + (gnus-string-prefix-p ":2," suffix)) + (or + (not (gnus-string-match-p + (string (nnmaildir--mark-to-flag 'read)) suffix)) + (gnus-string-match-p + (string (nnmaildir--mark-to-flag 'tick)) suffix))) + ;; then look in marks directories + (not (file-exists-p (concat cdir prefix))) + (file-exists-p (concat ndir prefix))) + (incf num))))) (setf (nnmaildir--grp-cache group) (make-vector num nil)) (let ((inhibit-quit t)) (set (intern gname groups) group)) @@ -814,6 +879,10 @@ by nnmaildir-request-article.") (setf (nnmaildir--grp-cur group) cattr))) t)) +(defvar nnmaildir-get-new-mail) +(defvar nnmaildir-group-alist) +(defvar nnmaildir-active-file) + (defun nnmaildir-request-scan (&optional scan-group server) (let ((coding-system-for-write nnheader-file-coding-system) (buffer-file-coding-system nil) @@ -821,7 +890,7 @@ by nnmaildir-request-article.") (nnmaildir-get-new-mail t) (nnmaildir-group-alist nil) (nnmaildir-active-file nil) - x srv-ls srv-dir method groups target-prefix group dirs grp-dir seen + x srv-ls srv-dir method groups target-prefix dirs seen deactivate-mark) (nnmaildir--prepare server nil) (setq srv-ls (nnmaildir--srv-ls nnmaildir--cur-server) @@ -897,7 +966,7 @@ by nnmaildir-request-article.") (nnmaildir--srv-groups nnmaildir--cur-server)))) t) -(defun nnmaildir-request-newgroups (date &optional server) +(defun nnmaildir-request-newgroups (_date &optional server) (nnmaildir-request-list server)) (defun nnmaildir-retrieve-groups (groups &optional server) @@ -921,11 +990,14 @@ by nnmaildir-request-article.") 'group) (defun nnmaildir-request-update-info (gname info &optional server) - (let ((group (nnmaildir--prepare server gname)) - pgname flist always-marks never-marks old-marks dotfile num dir - markdirs marks mark ranges markdir article read end new-marks ls - old-mmth new-mmth mtime mark-sym existing missing deactivate-mark - article-list) + (let* ((group (nnmaildir--prepare server gname)) + (curdir (nnmaildir--cur + (nnmaildir--srvgrp-dir + (nnmaildir--srv-dir nnmaildir--cur-server) gname))) + (curdir-mtime (nth 5 (file-attributes curdir))) + pgname flist always-marks never-marks old-marks dir + all-marks marks ranges markdir read ls + old-mmth new-mmth mtime existing missing deactivate-mark) (catch 'return (unless group (setf (nnmaildir--srv-error nnmaildir--cur-server) @@ -954,40 +1026,77 @@ by nnmaildir-request-article.") dir (nnmaildir--nndir dir) dir (nnmaildir--marks-dir dir) ls (nnmaildir--group-ls nnmaildir--cur-server pgname) - markdirs (funcall ls dir nil "\\`[^.]" 'nosort) - new-mmth (nnmaildir--up2-1 (length markdirs)) + all-marks (gnus-delete-duplicates + ;; get mark names from mark dirs and from flag + ;; mappings + (append + (mapcar 'cdr nnmaildir-flag-mark-mapping) + (mapcar 'intern (funcall ls dir nil "\\`[^.]" 'nosort)))) + new-mmth (nnmaildir--up2-1 (length all-marks)) new-mmth (make-vector new-mmth 0) old-mmth (nnmaildir--grp-mmth group)) - (dolist (mark markdirs) - (setq markdir (nnmaildir--subdir dir mark) - mark-sym (intern mark) + (dolist (mark all-marks) + (setq markdir (nnmaildir--subdir dir (symbol-name mark)) ranges nil) (catch 'got-ranges - (if (memq mark-sym never-marks) (throw 'got-ranges nil)) - (when (memq mark-sym always-marks) + (if (memq mark never-marks) (throw 'got-ranges nil)) + (when (memq mark always-marks) (setq ranges existing) (throw 'got-ranges nil)) - (setq mtime (nth 5 (file-attributes markdir))) - (set (intern mark new-mmth) mtime) - (when (equal mtime (symbol-value (intern-soft mark old-mmth))) - (setq ranges (assq mark-sym old-marks)) + ;; Find the mtime for this mark. If this mark can be expressed as + ;; a filename flag, get the later of the mtimes for markdir and + ;; curdir, otherwise only the markdir counts. + (setq mtime + (let ((markdir-mtime (nth 5 (file-attributes markdir)))) + (cond + ((null (nnmaildir--mark-to-flag mark)) + markdir-mtime) + ((null markdir-mtime) + curdir-mtime) + ((null curdir-mtime) + ;; this should never happen... + markdir-mtime) + ((time-less-p markdir-mtime curdir-mtime) + curdir-mtime) + (t + markdir-mtime)))) + (set (intern (symbol-name mark) new-mmth) mtime) + (when (equal mtime (symbol-value (intern-soft (symbol-name mark) old-mmth))) + (setq ranges (assq mark old-marks)) (if ranges (setq ranges (cdr ranges))) (throw 'got-ranges nil)) - (setq article-list nil) - (dolist (prefix (funcall ls markdir nil "\\`[^.]" 'nosort)) - (setq article (nnmaildir--flist-art flist prefix)) - (if article - (setq article-list - (cons (nnmaildir--art-num article) article-list)))) - (setq ranges (gnus-add-to-range ranges (sort article-list '<)))) - (if (eq mark-sym 'read) (setq read ranges) - (if ranges (setq marks (cons (cons mark-sym ranges) marks))))) + (let ((article-list nil)) + ;; Consider the article marked if it either has the flag in the + ;; filename, or is in the markdir. As you'd rarely remove a + ;; flag/mark, this should avoid losing information in the most + ;; common usage pattern. + (or + (let ((flag (nnmaildir--mark-to-flag mark))) + ;; If this mark has a corresponding maildir flag... + (when flag + (let ((regexp + (concat "\\`[^.].*:2,[A-Z]*" (string flag)))) + ;; ...then find all files with that flag. + (dolist (filename (funcall ls curdir nil regexp 'nosort)) + (let* ((prefix (car (split-string filename ":2,"))) + (article (nnmaildir--flist-art flist prefix))) + (when article + (push (nnmaildir--art-num article) article-list))))))) + ;; Also check Gnus-specific mark directory, if it exists. + (when (file-directory-p markdir) + (dolist (prefix (funcall ls markdir nil "\\`[^.]" 'nosort)) + (let ((article (nnmaildir--flist-art flist prefix))) + (when article + (push (nnmaildir--art-num article) article-list)))))) + (setq ranges (gnus-add-to-range ranges (sort article-list '<))))) + (if (eq mark 'read) (setq read ranges) + (if ranges (setq marks (cons (cons mark ranges) marks))))) (gnus-info-set-read info (gnus-range-add read missing)) (gnus-info-set-marks info marks 'extend) (setf (nnmaildir--grp-mmth group) new-mmth) info))) -(defun nnmaildir-request-group (gname &optional server fast) +(defun nnmaildir-request-group (gname &optional server fast _info) (let ((group (nnmaildir--prepare server gname)) deactivate-mark) (catch 'return @@ -1010,7 +1119,7 @@ by nnmaildir-request-article.") (insert " " (gnus-replace-in-string gname " " "\\ " t) "\n") t)))) -(defun nnmaildir-request-create-group (gname &optional server args) +(defun nnmaildir-request-create-group (gname &optional server _args) (nnmaildir--prepare server nil) (catch 'return (let ((target-prefix (nnmaildir--srv-target-prefix nnmaildir--cur-server)) @@ -1156,7 +1265,7 @@ by nnmaildir-request-article.") (defun nnmaildir-retrieve-headers (articles &optional gname server fetch-old) (let ((group (nnmaildir--prepare server gname)) - srv-dir dir nlist mlist article num start stop nov nlist2 insert-nov + nlist mlist article num start stop nov insert-nov deactivate-mark) (setq insert-nov (lambda (article) @@ -1181,9 +1290,7 @@ by nnmaildir-request-article.") (erase-buffer) (setq mlist (nnmaildir--grp-mlist group) nlist (nnmaildir--grp-nlist group) - gname (nnmaildir--grp-name group) - srv-dir (nnmaildir--srv-dir nnmaildir--cur-server) - dir (nnmaildir--srvgrp-dir srv-dir gname)) + gname (nnmaildir--grp-name group)) (cond ((null nlist)) ((and fetch-old (not (numberp fetch-old))) @@ -1249,13 +1356,12 @@ by nnmaildir-request-article.") (setf (nnmaildir--srv-error nnmaildir--cur-server) "Article has expired") (throw 'return nil)) - (save-excursion - (set-buffer (or to-buffer nntp-server-buffer)) + (with-current-buffer (or to-buffer nntp-server-buffer) (erase-buffer) (nnheader-insert-file-contents nnmaildir-article-file-name)) (cons gname num-msgid)))) -(defun nnmaildir-request-post (&optional server) +(defun nnmaildir-request-post (&optional _server) (let (message-required-mail-headers) (funcall message-send-mail-function))) @@ -1289,8 +1395,7 @@ by nnmaildir-request-article.") (setf (nnmaildir--srv-error nnmaildir--cur-server) (concat "File exists: " tmpfile)) (throw 'return nil)) - (save-excursion - (set-buffer buffer) + (with-current-buffer buffer (gmm-write-region (point-min) (point-max) tmpfile nil 'no-message nil 'excl)) (unix-sync) ;; no fsync :( @@ -1298,7 +1403,7 @@ by nnmaildir-request-article.") t))) (defun nnmaildir-request-move-article (article gname server accept-form - &optional last move-is-internal) + &optional _last _move-is-internal) (let ((group (nnmaildir--prepare server gname)) pgname suffix result nnmaildir--file deactivate-mark) (catch 'return @@ -1335,7 +1440,7 @@ by nnmaildir-request-article.") (nnmaildir--expired-article group article)) result))) -(defun nnmaildir-request-accept-article (gname &optional server last) +(defun nnmaildir-request-accept-article (gname &optional server _last) (let ((group (nnmaildir--prepare server gname)) (coding-system-for-write nnheader-file-coding-system) (buffer-file-coding-system nil) @@ -1387,7 +1492,8 @@ by nnmaildir-request-article.") (error (gmm-write-region (point-min) (point-max) tmpfile nil 'no-message nil 'excl) - (unix-sync))) ;; no fsync :( + (when (fboundp 'unix-sync) + (unix-sync)))) ;; no fsync :( (nnheader-cancel-timer 24h) (condition-case err (add-name-to-file tmpfile curfile) @@ -1438,7 +1544,7 @@ by nnmaildir-request-article.") ga)) group-art))))) -(defun nnmaildir-active-number (gname) +(defun nnmaildir-active-number (_gname) 0) (declare-function gnus-group-mark-article-read "gnus-group" (group article)) @@ -1446,8 +1552,8 @@ by nnmaildir-request-article.") (defun nnmaildir-request-expire-articles (ranges &optional gname server force) (let ((no-force (not force)) (group (nnmaildir--prepare server gname)) - pgname time boundary bound-iter high low target dir nlist nlist2 - stop article didnt nnmaildir--file nnmaildir-article-file-name + pgname time boundary bound-iter high low target dir nlist + didnt nnmaildir--file nnmaildir-article-file-name deactivate-mark) (catch 'return (unless group @@ -1466,7 +1572,7 @@ by nnmaildir-request-article.") (if (eq time 'immediate) (setq time 0) (if (numberp time) - (setq time (* time 86400))))) + (setq time (round (* time 86400)))))) (when no-force (unless (integerp time) ;; handle 'never (throw 'return (gnus-uncompress-range ranges))) @@ -1529,47 +1635,77 @@ by nnmaildir-request-article.") (erase-buffer)) didnt))) +(defvar nnmaildir--article) + (defun nnmaildir-request-set-mark (gname actions &optional server) - (let ((group (nnmaildir--prepare server gname)) - (coding-system-for-write nnheader-file-coding-system) - (buffer-file-coding-system nil) - (file-coding-system-alist nil) - del-mark del-action add-action set-action marksdir nlist - ranges begin end article all-marks todo-marks mdir mfile - pgname ls permarkfile deactivate-mark) - (setq del-mark + (let* ((group (nnmaildir--prepare server gname)) + (curdir (nnmaildir--cur + (nnmaildir--srvgrp-dir + (nnmaildir--srv-dir nnmaildir--cur-server) + gname))) + (coding-system-for-write nnheader-file-coding-system) + (buffer-file-coding-system nil) + (file-coding-system-alist nil) + marksdir nlist + ranges all-marks todo-marks mdir mfile + pgname ls permarkfile deactivate-mark + (del-mark (lambda (mark) - (setq mfile (nnmaildir--subdir marksdir (symbol-name mark)) - mfile (concat mfile (nnmaildir--art-prefix article))) - (nnmaildir--unlink mfile)) - del-action (lambda (article) (mapcar del-mark todo-marks)) - add-action + (let ((prefix (nnmaildir--art-prefix nnmaildir--article)) + (suffix (nnmaildir--art-suffix nnmaildir--article)) + (flag (nnmaildir--mark-to-flag mark))) + (when flag + ;; If this mark corresponds to a flag, remove the flag from + ;; the file name. + (nnmaildir--article-set-flags + nnmaildir--article (nnmaildir--remove-flag flag suffix) + curdir)) + ;; We still want to delete the hardlink in the marks dir if + ;; present, regardless of whether this mark has a maildir flag or + ;; not, to avoid getting out of sync. + (setq mfile (nnmaildir--subdir marksdir (symbol-name mark)) + mfile (concat mfile prefix)) + (nnmaildir--unlink mfile)))) + (del-action (lambda (article) + (let ((nnmaildir--article article)) + (mapcar del-mark todo-marks)))) + (add-action (lambda (article) (mapcar (lambda (mark) - (setq mdir (nnmaildir--subdir marksdir (symbol-name mark)) - permarkfile (concat mdir ":") - mfile (concat mdir (nnmaildir--art-prefix article))) - (nnmaildir--condcase err (add-name-to-file permarkfile mfile) - (cond - ((nnmaildir--eexist-p err)) - ((nnmaildir--enoent-p err) - (nnmaildir--mkdir mdir) - (nnmaildir--mkfile permarkfile) - (add-name-to-file permarkfile mfile)) - ((nnmaildir--emlink-p err) - (let ((permarkfilenew (concat permarkfile "{new}"))) - (nnmaildir--mkfile permarkfilenew) - (rename-file permarkfilenew permarkfile 'replace) - (add-name-to-file permarkfile mfile))) - (t (signal (car err) (cdr err)))))) - todo-marks)) - set-action (lambda (article) - (funcall add-action) - (mapcar (lambda (mark) - (unless (memq mark todo-marks) - (funcall del-mark mark))) - all-marks))) + (let ((prefix (nnmaildir--art-prefix article)) + (suffix (nnmaildir--art-suffix article)) + (flag (nnmaildir--mark-to-flag mark))) + (if flag + ;; If there is a corresponding maildir flag, just rename + ;; the file. + (nnmaildir--article-set-flags + article (nnmaildir--add-flag flag suffix) curdir) + ;; Otherwise, use nnmaildir-specific marks dir. + (setq mdir (nnmaildir--subdir marksdir (symbol-name mark)) + permarkfile (concat mdir ":") + mfile (concat mdir prefix)) + (nnmaildir--condcase err (add-name-to-file permarkfile mfile) + (cond + ((nnmaildir--eexist-p err)) + ((nnmaildir--enoent-p err) + (nnmaildir--mkdir mdir) + (nnmaildir--mkfile permarkfile) + (add-name-to-file permarkfile mfile)) + ((nnmaildir--emlink-p err) + (let ((permarkfilenew (concat permarkfile "{new}"))) + (nnmaildir--mkfile permarkfilenew) + (rename-file permarkfilenew permarkfile 'replace) + (add-name-to-file permarkfile mfile))) + (t (signal (car err) (cdr err)))))))) + todo-marks))) + (set-action (lambda (article) + (funcall add-action article) + (let ((nnmaildir--article article)) + (mapcar (lambda (mark) + (unless (memq mark todo-marks) + (funcall del-mark mark))) + all-marks))))) (catch 'return (unless group (setf (nnmaildir--srv-error nnmaildir--cur-server) @@ -1586,17 +1722,22 @@ by nnmaildir-request-article.") pgname (nnmaildir--pgname nnmaildir--cur-server gname) ls (nnmaildir--group-ls nnmaildir--cur-server pgname) all-marks (funcall ls marksdir nil "\\`[^.]" 'nosort) - all-marks (mapcar 'intern all-marks)) + all-marks (gnus-delete-duplicates + ;; get mark names from mark dirs and from flag + ;; mappings + (append + (mapcar 'cdr nnmaildir-flag-mark-mapping) + (mapcar 'intern all-marks)))) (dolist (action actions) (setq ranges (car action) todo-marks (caddr action)) (dolist (mark todo-marks) - (add-to-list 'all-marks mark)) + (pushnew mark all-marks :test #'equal)) (if (numberp (cdr ranges)) (setq ranges (list ranges))) (nnmaildir--nlist-iterate nlist ranges (cond ((eq 'del (cadr action)) del-action) ((eq 'add (cadr action)) add-action) - (t set-action)))) + ((eq 'set (cadr action)) set-action)))) nil))) (defun nnmaildir-close-group (gname &optional server) @@ -1638,6 +1779,8 @@ by nnmaildir-request-article.") t))) (defun nnmaildir-close-server (&optional server) + (defvar flist) (defvar ls) (defvar dirs) (defvar dir) + (defvar files) (defvar file) (defvar x) (let (flist ls dirs dir files file x) (nnmaildir--prepare server nil) (when nnmaildir--cur-server