emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] /srv/bzr/emacs/trunk r109894: Merge changes made in Gnus m


From: Katsumi Yamaoka
Subject: [Emacs-diffs] /srv/bzr/emacs/trunk r109894: Merge changes made in Gnus master
Date: Wed, 05 Sep 2012 22:35:32 +0000
User-agent: Bazaar (2.5.0)

------------------------------------------------------------
revno: 109894
author: Gnus developers <address@hidden>
committer: Katsumi Yamaoka <address@hidden>
branch nick: trunk
timestamp: Wed 2012-09-05 22:35:32 +0000
message:
  Merge changes made in Gnus master
  
  2012-09-05 Julien Danjou <address@hidden>
  * gnus-srvr.el (gnus-server-open-server): Don't message on failure:
    this hide the real reason with a message giving absolutely no hint.
  
  2012-09-05 Lars Ingebrigtsen <address@hidden>
  * gnus-group.el (gnus-group-mark-article-read): Propagate the read mark
    to the backend (bug#11804).
  * message.el (message-insert-newsgroups): Don't insert newsgroup
    duplicates (bug#12275).
  
  2012-09-05 John Wiegley <address@hidden>
  * gnus.el (gnus-expand-group-parameters): Allow regexp substitutions in
    sieve rules.
  
  2012-09-05 Jan Tatarik <address@hidden>
  * gnus-score.el (gnus-score-decode-text-parts): Use #' for the local
    function.
  * gnus-logic.el (gnus-advanced-body): Allow scoring on decoded bodies.
  * gnus-score.el (gnus-score-decode-text-parts): Ditto.
  
  2012-09-05 Magnus Henoch <address@hidden>
  * nnmaildir.el: Make nnmaildir understand and write maildir flags.
    That is, rename files from "unique:2," to "unique:2,S" for "seen", etc.
    This should make nnmaildir more usable with offlineimap.
modified:
  lisp/gnus/ChangeLog
  lisp/gnus/gnus-group.el
  lisp/gnus/gnus-logic.el
  lisp/gnus/gnus-score.el
  lisp/gnus/gnus-srvr.el
  lisp/gnus/gnus.el
  lisp/gnus/message.el
  lisp/gnus/nnmaildir.el
=== modified file 'lisp/gnus/ChangeLog'
--- a/lisp/gnus/ChangeLog       2012-09-05 06:56:55 +0000
+++ b/lisp/gnus/ChangeLog       2012-09-05 22:35:32 +0000
@@ -1,3 +1,36 @@
+2012-09-05  Julien Danjou  <address@hidden>
+
+       * gnus-srvr.el (gnus-server-open-server): Don't message on failure:
+       this hide the real reason with a message giving absolutely no hint.
+
+2012-09-05  Lars Ingebrigtsen  <address@hidden>
+
+       * gnus-group.el (gnus-group-mark-article-read): Propagate the read mark
+       to the backend (bug#11804).
+
+       * message.el (message-insert-newsgroups): Don't insert newsgroup
+       duplicates (bug#12275).
+
+2012-09-05  John Wiegley  <address@hidden>
+
+       * gnus.el (gnus-expand-group-parameters): Allow regexp substitutions in
+       sieve rules.
+
+2012-09-05  Jan Tatarik  <address@hidden>
+
+       * gnus-score.el (gnus-score-decode-text-parts): Use #' for the local
+       function.
+
+       * gnus-logic.el (gnus-advanced-body): Allow scoring on decoded bodies.
+
+       * gnus-score.el (gnus-score-decode-text-parts): Ditto.
+
+2012-09-05  Magnus Henoch  <address@hidden>
+
+       * nnmaildir.el: Make nnmaildir understand and write maildir flags.
+       That is, rename files from "unique:2," to "unique:2,S" for "seen", etc.
+       This should make nnmaildir more usable with offlineimap.
+
 2012-09-03  Lars Ingebrigtsen  <address@hidden>
 
        * gnus-notifications.el (gnus-notifications-notify): Use it.

=== modified file 'lisp/gnus/gnus-group.el'
--- a/lisp/gnus/gnus-group.el   2012-07-24 22:17:17 +0000
+++ b/lisp/gnus/gnus-group.el   2012-09-05 22:35:32 +0000
@@ -4670,6 +4670,8 @@
              (setq mark gnus-expirable-mark))
            (setq mark (gnus-request-update-mark
                        group article mark))
+           (gnus-request-set-mark
+            group (list (list (list article) 'add '(read))))
            (gnus-mark-article-as-read article mark)
            (setq gnus-newsgroup-active (gnus-active group))
            (when active

=== modified file 'lisp/gnus/gnus-logic.el'
--- a/lisp/gnus/gnus-logic.el   2012-01-19 07:21:25 +0000
+++ b/lisp/gnus/gnus-logic.el   2012-09-05 22:35:32 +0000
@@ -180,46 +180,51 @@
     (setq header "article"))
   (with-current-buffer nntp-server-buffer
     (let* ((request-func (cond ((string= "head" header)
-                               'gnus-request-head)
-                              ((string= "body" header)
-                               'gnus-request-body)
-                              (t 'gnus-request-article)))
-          ofunc article)
+                                'gnus-request-head)
+                               ;; We need to peek at the headers to detect the
+                               ;; content encoding
+                               ((string= "body" header)
+                                'gnus-request-article)
+                               (t 'gnus-request-article)))
+           ofunc article handles)
       ;; Not all backends support partial fetching.  In that case, we
       ;; just fetch the entire article.
       (unless (gnus-check-backend-function
-              (intern (concat "request-" header))
-              gnus-newsgroup-name)
-       (setq ofunc request-func)
-       (setq request-func 'gnus-request-article))
+               (intern (concat "request-" header))
+               gnus-newsgroup-name)
+        (setq ofunc request-func)
+        (setq request-func 'gnus-request-article))
       (setq article (mail-header-number gnus-advanced-headers))
       (gnus-message 7 "Scoring article %s..." article)
       (when (funcall request-func article gnus-newsgroup-name)
-       (goto-char (point-min))
-       ;; If just parts of the article is to be searched and the
-       ;; backend didn't support partial fetching, we just narrow to
-       ;; the relevant parts.
-       (when ofunc
-         (if (eq ofunc 'gnus-request-head)
-             (narrow-to-region
-              (point)
-              (or (search-forward "\n\n" nil t) (point-max)))
-           (narrow-to-region
-            (or (search-forward "\n\n" nil t) (point))
-            (point-max))))
-       (let* ((case-fold-search (not (eq (downcase (symbol-name type))
-                                         (symbol-name type))))
-              (search-func
-               (cond ((memq type '(r R regexp Regexp))
-                      're-search-forward)
-                     ((memq type '(s S string String))
-                      'search-forward)
-                     (t
-                      (error "Invalid match type: %s" type)))))
-         (goto-char (point-min))
-         (prog1
-             (funcall search-func match nil t)
-           (widen)))))))
+        (when (string= "body" header)
+          (setq handles (gnus-score-decode-text-parts)))
+        (goto-char (point-min))
+        ;; If just parts of the article is to be searched and the
+        ;; backend didn't support partial fetching, we just narrow to
+        ;; the relevant parts.
+        (when ofunc
+          (if (eq ofunc 'gnus-request-head)
+              (narrow-to-region
+               (point)
+               (or (search-forward "\n\n" nil t) (point-max)))
+            (narrow-to-region
+             (or (search-forward "\n\n" nil t) (point))
+             (point-max))))
+        (let* ((case-fold-search (not (eq (downcase (symbol-name type))
+                                          (symbol-name type))))
+               (search-func
+                (cond ((memq type '(r R regexp Regexp))
+                       're-search-forward)
+                      ((memq type '(s S string String))
+                       'search-forward)
+                      (t
+                       (error "Invalid match type: %s" type)))))
+          (goto-char (point-min))
+          (prog1
+              (funcall search-func match nil t)
+            (widen)))
+        (when handles (mm-destroy-parts handles))))))
 
 (provide 'gnus-logic)
 

=== modified file 'lisp/gnus/gnus-score.el'
--- a/lisp/gnus/gnus-score.el   2012-07-24 22:17:17 +0000
+++ b/lisp/gnus/gnus-score.el   2012-09-05 22:35:32 +0000
@@ -1717,105 +1717,140 @@
          (setq entries rest)))))
   nil)
 
+(defun gnus-score-decode-text-parts ()
+  (labels ((mm-text-parts (handle)
+                        (cond ((stringp (car handle))
+                               (let ((parts (mapcan 'mm-text-parts (cdr 
handle))))
+                                 (if (equal "multipart/alternative" (car 
handle))
+                                     ;; pick the first supported alternative
+                                     (list (car parts))
+                                   parts)))
+
+                              ((bufferp (car handle))
+                               (when (string-match "^text/" 
(mm-handle-media-type handle))
+                                 (list handle)))
+
+                              (t (mapcan 'mm-text-parts handle))))
+           (my-mm-display-part (handle)
+                               (when handle
+                                 (save-restriction
+                                   (narrow-to-region (point) (point))
+                                   (mm-display-inline handle)
+                                   (goto-char (point-max))))))
+
+    (let (;(mm-text-html-renderer 'w3m-standalone)
+          (handles (mm-dissect-buffer t)))
+      (save-excursion
+        (article-goto-body)
+        (delete-region (point) (point-max))
+        (mapc #'my-mm-display-part (mm-text-parts handles))
+        handles))))
+
 (defun gnus-score-body (scores header now expire &optional trace)
-  (if gnus-agent-fetching
-      nil
-    (save-excursion
-      (setq gnus-scores-articles
-           (sort gnus-scores-articles
-                 (lambda (a1 a2)
-                   (< (mail-header-number (car a1))
-                      (mail-header-number (car a2))))))
-      (set-buffer nntp-server-buffer)
-      (save-restriction
-       (let* ((buffer-read-only nil)
-              (articles gnus-scores-articles)
-              (all-scores scores)
-              (request-func (cond ((string= "head" header)
-                                   'gnus-request-head)
-                                  ((string= "body" header)
-                                   'gnus-request-body)
-                                  (t 'gnus-request-article)))
-              entries alist ofunc article last)
-         (when articles
-           (setq last (mail-header-number (caar (last articles))))
-         ;; Not all backends support partial fetching.  In that case,
-           ;; we just fetch the entire article.
-           (unless (gnus-check-backend-function
-                    (and (string-match "^gnus-" (symbol-name request-func))
-                         (intern (substring (symbol-name request-func)
-                                            (match-end 0))))
-                    gnus-newsgroup-name)
-             (setq ofunc request-func)
-             (setq request-func 'gnus-request-article))
-           (while articles
-             (setq article (mail-header-number (caar articles)))
-             (gnus-message 7 "Scoring article %s of %s..." article last)
-             (widen)
-             (when (funcall request-func article gnus-newsgroup-name)
-               (goto-char (point-min))
-           ;; If just parts of the article is to be searched, but the
-           ;; backend didn't support partial fetching, we just narrow
-               ;; to the relevant parts.
-               (when ofunc
-                 (if (eq ofunc 'gnus-request-head)
-                     (narrow-to-region
-                      (point)
-                      (or (search-forward "\n\n" nil t) (point-max)))
-                   (narrow-to-region
-                    (or (search-forward "\n\n" nil t) (point))
-                    (point-max))))
-               (setq scores all-scores)
-               ;; Find matches.
-               (while scores
-                 (setq alist (pop scores)
-                       entries (assoc header alist))
-                 (while (cdr entries) ;First entry is the header index.
-                   (let* ((rest (cdr entries))
-                          (kill (car rest))
-                          (match (nth 0 kill))
-                          (type (or (nth 3 kill) 's))
-                          (score (or (nth 1 kill)
-                                     gnus-score-interactive-default-score))
-                          (date (nth 2 kill))
-                          (found nil)
-                          (case-fold-search
-                           (not (or (eq type 'R) (eq type 'S)
-                                    (eq type 'Regexp) (eq type 'String))))
-                          (search-func
-                           (cond ((or (eq type 'r) (eq type 'R)
-                                      (eq type 'regexp) (eq type 'Regexp))
-                                  're-search-forward)
-                                 ((or (eq type 's) (eq type 'S)
-                                      (eq type 'string) (eq type 'String))
-                                  'search-forward)
-                                 (t
-                                  (error "Invalid match type: %s" type)))))
-                     (goto-char (point-min))
-                     (when (funcall search-func match nil t)
-                       ;; Found a match, update scores.
-                       (setcdr (car articles) (+ score (cdar articles)))
-                       (setq found t)
-                       (when trace
-                         (push
-                          (cons (car-safe (rassq alist gnus-score-cache))
-                                kill)
-                          gnus-score-trace)))
-                     ;; Update expire date
-                     (unless trace
-                       (cond
-                        ((null date))  ;Permanent entry.
-                        ((and found gnus-update-score-entry-dates)
-                         ;; Match, update date.
-                         (gnus-score-set 'touched '(t) alist)
-                         (setcar (nthcdr 2 kill) now))
-                        ((and expire (< date expire)) ;Old entry, remove.
-                         (gnus-score-set 'touched '(t) alist)
-                         (setcdr entries (cdr rest))
-                         (setq rest entries))))
-                     (setq entries rest)))))
-             (setq articles (cdr articles)))))))
-    nil))
+    (if gnus-agent-fetching
+       nil
+     (save-excursion
+       (setq gnus-scores-articles
+             (sort gnus-scores-articles
+                   (lambda (a1 a2)
+                     (< (mail-header-number (car a1))
+                        (mail-header-number (car a2))))))
+       (set-buffer nntp-server-buffer)
+       (save-restriction
+         (let* ((buffer-read-only nil)
+                (articles gnus-scores-articles)
+                (all-scores scores)
+                (request-func (cond ((string= "head" header)
+                                     'gnus-request-head)
+                                    ;; We need to peek at the headers to detect
+                                    ;; the content encoding
+                                    ((string= "body" header)
+                                     'gnus-request-article)
+                                    (t 'gnus-request-article)))
+                entries alist ofunc article last)
+           (when articles
+             (setq last (mail-header-number (caar (last articles))))
+             ;; Not all backends support partial fetching.  In that case,
+             ;; we just fetch the entire article.
+             (unless (gnus-check-backend-function
+                      (and (string-match "^gnus-" (symbol-name request-func))
+                           (intern (substring (symbol-name request-func)
+                                              (match-end 0))))
+                      gnus-newsgroup-name)
+               (setq ofunc request-func)
+               (setq request-func 'gnus-request-article))
+             (while articles
+               (setq article (mail-header-number (caar articles)))
+               (gnus-message 7 "Scoring article %s of %s..." article last)
+               (widen)
+               (let (handles)
+                 (when (funcall request-func article gnus-newsgroup-name)
+                  (when (string= "body" header)
+                    (setq handles (gnus-score-decode-text-parts)))
+                  (goto-char (point-min))
+                  ;; If just parts of the article is to be searched, but the
+                  ;; backend didn't support partial fetching, we just narrow
+                  ;; to the relevant parts.
+                  (when ofunc
+                    (if (eq ofunc 'gnus-request-head)
+                        (narrow-to-region
+                         (point)
+                         (or (search-forward "\n\n" nil t) (point-max)))
+                      (narrow-to-region
+                       (or (search-forward "\n\n" nil t) (point))
+                       (point-max))))
+                  (setq scores all-scores)
+                  ;; Find matches.
+                  (while scores
+                    (setq alist (pop scores)
+                          entries (assoc header alist))
+                    (while (cdr entries) ;First entry is the header index.
+                      (let* ((rest (cdr entries))
+                             (kill (car rest))
+                             (match (nth 0 kill))
+                             (type (or (nth 3 kill) 's))
+                             (score (or (nth 1 kill)
+                                        gnus-score-interactive-default-score))
+                             (date (nth 2 kill))
+                             (found nil)
+                             (case-fold-search
+                              (not (or (eq type 'R) (eq type 'S)
+                                       (eq type 'Regexp) (eq type 'String))))
+                             (search-func
+                              (cond ((or (eq type 'r) (eq type 'R)
+                                         (eq type 'regexp) (eq type 'Regexp))
+                                     're-search-forward)
+                                    ((or (eq type 's) (eq type 'S)
+                                         (eq type 'string) (eq type 'String))
+                                     'search-forward)
+                                    (t
+                                     (error "Invalid match type: %s" type)))))
+                        (goto-char (point-min))
+                        (when (funcall search-func match nil t)
+                          ;; Found a match, update scores.
+                          (setcdr (car articles) (+ score (cdar articles)))
+                          (setq found t)
+                          (when trace
+                            (push
+                             (cons (car-safe (rassq alist gnus-score-cache))
+                                   kill)
+                             gnus-score-trace)))
+                        ;; Update expire date
+                        (unless trace
+                          (cond
+                           ((null date)) ;Permanent entry.
+                           ((and found gnus-update-score-entry-dates)
+                            ;; Match, update date.
+                            (gnus-score-set 'touched '(t) alist)
+                            (setcar (nthcdr 2 kill) now))
+                           ((and expire (< date expire)) ;Old entry, remove.
+                            (gnus-score-set 'touched '(t) alist)
+                            (setcdr entries (cdr rest))
+                            (setq rest entries))))
+                        (setq entries rest))))
+                  (when handles (mm-destroy-parts handles))))
+               (setq articles (cdr articles)))))))
+     nil))
 
 (defun gnus-score-thread (scores header now expire &optional trace)
   (gnus-score-followup scores header now expire trace t))

=== modified file 'lisp/gnus/gnus-srvr.el'
--- a/lisp/gnus/gnus-srvr.el    2012-01-26 23:03:28 +0000
+++ b/lisp/gnus/gnus-srvr.el    2012-09-05 22:35:32 +0000
@@ -490,8 +490,7 @@
       (error "No such server: %s" server))
     (gnus-server-set-status method 'ok)
     (prog1
-       (or (gnus-open-server method)
-           (progn (message "Couldn't open %s" server) nil))
+       (gnus-open-server method)
       (gnus-server-update-server server)
       (gnus-server-position-point))))
 

=== modified file 'lisp/gnus/gnus.el'
--- a/lisp/gnus/gnus.el 2012-07-31 01:39:58 +0000
+++ b/lisp/gnus/gnus.el 2012-09-05 22:35:32 +0000
@@ -3824,12 +3824,28 @@
   "Go through PARAMETERS and expand them according to the match data."
   (let (new)
     (dolist (elem parameters)
-      (if (and (stringp (cdr elem))
-              (string-match "\\\\[0-9&]" (cdr elem)))
-         (push (cons (car elem)
-                     (gnus-expand-group-parameter match (cdr elem) group))
-               new)
-       (push elem new)))
+      (cond
+       ((and (stringp (cdr elem))
+             (string-match "\\\\[0-9&]" (cdr elem)))
+        (push (cons (car elem)
+                    (gnus-expand-group-parameter match (cdr elem) group))
+              new))
+       ;; For `sieve' group parameters, perform substitutions for every
+       ;; string within the match rule.  This allows for parameters such
+       ;; as:
+       ;;  ("list\\.\\(.*\\)"
+       ;;   (sieve header :is "list-id" "<\\1.domain.org>"))
+       ((eq 'sieve (car elem))
+        (push (mapcar (lambda (sieve-elem)
+                        (if (and (stringp sieve-elem)
+                                 (string-match "\\\\[0-9&]" sieve-elem))
+                            (gnus-expand-group-parameter match sieve-elem
+                                                         group)
+                          sieve-elem))
+                      (cdr elem))
+              new))
+       (t
+       (push elem new))))
     new))
 
 (defun gnus-group-fast-parameter (group symbol &optional allow-list)
@@ -3861,9 +3877,20 @@
              (when this-result
                (setq result (car this-result))
                ;; Expand if necessary.
-               (if (and (stringp result) (string-match "\\\\[0-9&]" result))
-                   (setq result (gnus-expand-group-parameter
-                                 (car head) result group)))))))
+               (cond
+                 ((and (stringp result) (string-match "\\\\[0-9&]" result))
+                  (setq result (gnus-expand-group-parameter
+                                (car head) result group)))
+                 ;; For `sieve' group parameters, perform substitutions
+                 ;; for every string within the match rule (see above).
+                 ((eq symbol 'sieve)
+                  (setq result
+                        (mapcar (lambda (elem)
+                                  (if (stringp elem)
+                                      (gnus-expand-group-parameter (car head)
+                                                                   elem group)
+                                    elem))
+                                result))))))))
        ;; Done.
        result))))
 

=== modified file 'lisp/gnus/message.el'
--- a/lisp/gnus/message.el      2012-09-01 01:04:26 +0000
+++ b/lisp/gnus/message.el      2012-09-05 22:35:32 +0000
@@ -3292,11 +3292,33 @@
 (defun message-insert-newsgroups ()
   "Insert the Newsgroups header from the article being replied to."
   (interactive)
-  (when (and (message-position-on-field "Newsgroups")
-            (mail-fetch-field "newsgroups")
-            (not (string-match "\\` *\\'" (mail-fetch-field "newsgroups"))))
-    (insert ","))
-  (insert (or (message-fetch-reply-field "newsgroups") "")))
+  (let ((old-newsgroups (mail-fetch-field "newsgroups"))
+       (new-newsgroups (message-fetch-reply-field "newsgroups"))
+       (first t)
+       insert-newsgroups)
+    (message-position-on-field "Newsgroups")
+    (cond
+     ((not new-newsgroups)
+      (error "No Newsgroups to insert"))
+     ((not old-newsgroups)
+      (insert new-newsgroups))
+     (t
+      (setq new-newsgroups (split-string new-newsgroups "[, ]+")
+           old-newsgroups (split-string old-newsgroups "[, ]+"))
+      (dolist (group new-newsgroups)
+       (unless (member group old-newsgroups)
+         (push group insert-newsgroups)))
+      (if (null insert-newsgroups)
+         (error "Newgroup%s already in the header"
+                (if (> (length new-newsgroups) 1)
+                    "s" ""))
+       (when old-newsgroups
+         (setq first nil))
+       (dolist (group insert-newsgroups)
+         (unless first
+           (insert ","))
+         (setq first nil)
+         (insert group)))))))
 
 
 

=== modified file 'lisp/gnus/nnmaildir.el'
--- a/lisp/gnus/nnmaildir.el    2012-06-10 22:16:03 +0000
+++ b/lisp/gnus/nnmaildir.el    2012-09-05 22:35:32 +0000
@@ -77,6 +77,66 @@
 
 (defconst nnmaildir-version "Gnus")
 
+(defconst nnmaildir-flag-mark-mapping
+  '((?F . tick)
+    (?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 (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 (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 (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)))
+
+(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)))
+
 (defvar nnmaildir-article-file-name nil
   "*The filename of the most recently requested article.  This variable is set
 by nnmaildir-request-article.")
@@ -208,29 +268,33 @@
   (eval param))
 
 (defmacro nnmaildir--with-nntp-buffer (&rest body)
+  (declare (debug (body)))
   `(with-current-buffer nntp-server-buffer
      ,@body))
 (defmacro nnmaildir--with-work-buffer (&rest body)
+  (declare (debug (body)))
   `(with-current-buffer (get-buffer-create " *nnmaildir work*")
      ,@body))
 (defmacro nnmaildir--with-nov-buffer (&rest body)
+  (declare (debug (body)))
   `(with-current-buffer (get-buffer-create " *nnmaildir nov*")
      ,@body))
 (defmacro nnmaildir--with-move-buffer (&rest body)
+  (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))
@@ -305,6 +369,7 @@
   string)
 
 (defmacro nnmaildir--condcase (errsym body &rest handler)
+  (declare (debug (sexp form body)))
   `(condition-case ,errsym
        (let ((system-messages-locale "C")) ,body)
      (error . ,handler)))
@@ -759,7 +824,7 @@
          (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))
@@ -784,11 +849,23 @@
                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)
+                               (string-prefix-p ":2," suffix))
+                      (or
+                       (not (string-match-p
+                             (string (nnmaildir--mark-to-flag 'read)) suffix))
+                       (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))
@@ -916,12 +993,15 @@
                  "\n")))))
   'group)
 
-(defun nnmaildir-request-marks (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)
+(defun nnmaildir-request-update-info (gname info &optional server)
+  (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 dotfile num dir
+        all-marks marks mark ranges markdir read end new-marks ls
+        old-mmth new-mmth mtime mark-sym existing missing deactivate-mark)
     (catch 'return
       (unless group
        (setf (nnmaildir--srv-error nnmaildir--cur-server)
@@ -950,34 +1030,71 @@
            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)
@@ -1525,39 +1642,63 @@
       didnt)))
 
 (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)
+  (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)
+        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
          (lambda (mark)
-           (setq mfile (nnmaildir--subdir marksdir (symbol-name mark))
-                 mfile (concat mfile (nnmaildir--art-prefix article)))
-           (nnmaildir--unlink mfile))
+           (let ((prefix (nnmaildir--art-prefix article))
+                 (suffix (nnmaildir--art-suffix 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
+                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) (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))))))
+              (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)
@@ -1581,7 +1722,12 @@
             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))


reply via email to

[Prev in Thread] Current Thread [Next in Thread]