Synch with Oort Gnus.
authoryamaoka <yamaoka>
Fri, 21 Dec 2001 01:57:51 +0000 (01:57 +0000)
committeryamaoka <yamaoka>
Fri, 21 Dec 2001 01:57:51 +0000 (01:57 +0000)
lisp/ChangeLog
lisp/nnimap.el
lisp/nnmaildir.el [new file with mode: 0644]

index e058581..7a60ad9 100644 (file)
@@ -1,3 +1,19 @@
+2001-12-20 15:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnmaildir.el: Copyright changes. Require cl only at compile time.
+
+2001-12-20  Simon Josefsson  <jas@extundo.com>
+
+       * nnimap.el (top-level): Don't require cl.  Suggested by ShengHuo
+       ZHU <zsh@cs.rochester.edu>.
+       (nnimap-close-group): Don't quote KEYLIST items.  Suggested by
+       Brian P Templeton <bpt@tunes.org>.
+
+2001-12-19 17:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
+
+       * nnmaildir.el: New.
+       From Paul Jarc <prj@po.cwru.edu>.
+
 2001-12-19 16:00:00  ShengHuo ZHU  <zsh@cs.rochester.edu>
 
        * nndoc.el (nndoc-type-alist): Move forward to the end.
index 48b43e1..9ff83b4 100644 (file)
@@ -60,7 +60,7 @@
 
 (eval-when-compile (require 'cl))
 (eval-when-compile (require 'gnus-clfns))
-(eval-and-compile (require 'imap))
+(require 'imap)
 
 (require 'nnoo)
 (require 'nnmail)
@@ -846,9 +846,9 @@ function is generally only called when Gnus is shutting down."
     (when (and (imap-opened)
               (nnimap-possibly-change-group group server))
       (case nnimap-expunge-on-close
-       ('always (imap-mailbox-expunge nnimap-close-asynchronous)
+       (always (imap-mailbox-expunge nnimap-close-asynchronous)
                 (imap-mailbox-close nnimap-close-asynchronous))
-       ('ask (if (and (imap-search "DELETED")
+       (ask (if (and (imap-search "DELETED")
                       (gnus-y-or-n-p (format
                                       "Expunge articles in group `%s'? "
                                       imap-current-mailbox)))
diff --git a/lisp/nnmaildir.el b/lisp/nnmaildir.el
new file mode 100644 (file)
index 0000000..b4c0a8f
--- /dev/null
@@ -0,0 +1,1664 @@
+;;; nnmaildir.el --- maildir backend for Gnus
+;; Copyright (c) 2001 Free Software Foundation, Inc.
+;; Copyright (c) 2000, 2001 Paul Jarc <prj@po.cwru.edu>
+
+;; Author: Paul Jarc <prj@po.cwru.edu>
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;;; <URL:http://multivac.cwru.edu./nnmaildir/>
+
+;;; Code:
+
+(eval-and-compile
+  (require 'nnheader)
+  (require 'gnus)
+  (require 'gnus-util)
+  (require 'gnus-range)
+  (require 'gnus-start)
+  (require 'gnus-int)
+  (require 'message))
+(eval-when-compile
+  (require 'cl)
+  (require 'nnmail))
+
+(gnus-declare-backend "nnmaildir" 'mail 'respool 'address)
+(defconst nnmaildir-version "2001.12.19")
+
+(defvar nnmaildir-article-file-name nil
+  "*The filename of the most recently requested article.  This variable is set
+by nnmaildir-request-article.")
+
+;; The filename of the article being moved/copied:
+(defvar nnmaildir--file nil)
+
+;; Variables to generate filenames of messages being delivered:
+(defvar   nnmaildir--delivery-time "")
+(defconst nnmaildir--delivery-pid  (number-to-string (emacs-pid)))
+(defvar   nnmaildir--delivery-ct   nil)
+
+;; An obarry containing symbols whose names are server names and whose values
+;; are servers:
+(defvar nnmaildir--servers (make-vector 3 0))
+;; A server which has not necessarily been added to nnmaildir--servers, or nil:
+(defvar nnmaildir--tmp-server nil)
+;; The current server:
+(defvar nnmaildir--cur-server nil)
+
+;; A server is a vector:
+["server-name"
+ select-method
+ "/expanded/path/to/directory/containing/symlinks/to/maildirs/"
+ directory-files-function
+ group-name-transformation-function
+ ;; An obarray containing symbols whose names are group names and whose values
+ ;; are groups:
+ group-hash
+ ;; A group which has not necessarily been added to the group hash, or nil:
+ tmp-group
+ current-group ;; or nil
+ "Last error message, or nil"
+ directory-modtime
+ get-new-mail-p ;; Should we split mail from mail-sources?
+ "new/group/creation/directory"]
+
+;; A group is a vector:
+["group.name"
+ "prefixed:group.name"
+ ;; Modification times of the "new", and "cur" directories:
+ new-modtime
+ cur-modtime
+ ;; A vector containing lists of articles:
+ [;; A list of articles, with article numbers in descending order, ending with
+  ;; article 1:
+  article-list
+  ;; An obarray containing symbols whose names are filename prefixes and whose
+  ;; values are articles:
+  file-hash
+  ;; Same as above, but keyed on Message-ID:
+  msgid-hash
+  ;; An article which has not necessarily been added to the file and msgid
+  ;; hashes, or nil:
+  tmp-article]
+ ;; A vector containing nil, or articles with NOV data:
+ nov-cache
+ ;; The index of the next nov-cache entry to be replaced:
+ nov-cache-index
+ ;; An obarray containing symbols whose names are mark names and whose values
+ ;; are modtimes of mark directories:
+ mark-modtime-hash]
+
+;; An article is a vector:
+["file.name.prefix"
+ ":2,suffix" ;; or 'expire if expired
+ number
+ "msgid"
+ ;; A NOV data vector, or nil:
+ ["subject\tfrom\tdate"
+  "references\tchars\lines"
+  "extra"
+  article-file-modtime]]
+
+(defmacro nnmaildir--srv-new () '(make-vector 11 nil))
+(defmacro nnmaildir--srv-get-name       (server) `(aref ,server  0))
+(defmacro nnmaildir--srv-get-method     (server) `(aref ,server  1))
+(defmacro nnmaildir--srv-get-dir        (server) `(aref ,server  2))
+(defmacro nnmaildir--srv-get-ls         (server) `(aref ,server  3))
+(defmacro nnmaildir--srv-get-groups     (server) `(aref ,server  4))
+(defmacro nnmaildir--srv-get-tmpgrp     (server) `(aref ,server  5))
+(defmacro nnmaildir--srv-get-curgrp     (server) `(aref ,server  6))
+(defmacro nnmaildir--srv-get-error      (server) `(aref ,server  7))
+(defmacro nnmaildir--srv-get-mtime      (server) `(aref ,server  8))
+(defmacro nnmaildir--srv-get-gnm        (server) `(aref ,server  9))
+(defmacro nnmaildir--srv-get-create-dir (server) `(aref ,server 10))
+(defmacro nnmaildir--srv-set-name       (server val) `(aset ,server  0 ,val))
+(defmacro nnmaildir--srv-set-method     (server val) `(aset ,server  1 ,val))
+(defmacro nnmaildir--srv-set-dir        (server val) `(aset ,server  2 ,val))
+(defmacro nnmaildir--srv-set-ls         (server val) `(aset ,server  3 ,val))
+(defmacro nnmaildir--srv-set-groups     (server val) `(aset ,server  4 ,val))
+(defmacro nnmaildir--srv-set-tmpgrp     (server val) `(aset ,server  5 ,val))
+(defmacro nnmaildir--srv-set-curgrp     (server val) `(aset ,server  6 ,val))
+(defmacro nnmaildir--srv-set-error      (server val) `(aset ,server  7 ,val))
+(defmacro nnmaildir--srv-set-mtime      (server val) `(aset ,server  8 ,val))
+(defmacro nnmaildir--srv-set-gnm        (server val) `(aset ,server  9 ,val))
+(defmacro nnmaildir--srv-set-create-dir (server val) `(aset ,server 10 ,val))
+
+(defmacro nnmaildir--grp-new () '(make-vector 8 nil))
+(defmacro nnmaildir--grp-get-name   (group) `(aref ,group 0))
+(defmacro nnmaildir--grp-get-pname  (group) `(aref ,group 1))
+(defmacro nnmaildir--grp-get-new    (group) `(aref ,group 2))
+(defmacro nnmaildir--grp-get-cur    (group) `(aref ,group 3))
+(defmacro nnmaildir--grp-get-lists  (group) `(aref ,group 4))
+(defmacro nnmaildir--grp-get-cache  (group) `(aref ,group 5))
+(defmacro nnmaildir--grp-get-index  (group) `(aref ,group 6))
+(defmacro nnmaildir--grp-get-mmth   (group) `(aref ,group 7))
+(defmacro nnmaildir--grp-set-name   (group val) `(aset ,group 0 ,val))
+(defmacro nnmaildir--grp-set-pname  (group val) `(aset ,group 1 ,val))
+(defmacro nnmaildir--grp-set-new    (group val) `(aset ,group 2 ,val))
+(defmacro nnmaildir--grp-set-cur    (group val) `(aset ,group 3 ,val))
+(defmacro nnmaildir--grp-set-lists  (group val) `(aset ,group 4 ,val))
+(defmacro nnmaildir--grp-set-cache  (group val) `(aset ,group 5 ,val))
+(defmacro nnmaildir--grp-set-index  (group val) `(aset ,group 6 ,val))
+(defmacro nnmaildir--grp-set-mmth   (group val) `(aset ,group 7 ,val))
+
+(defmacro nnmaildir--lists-new () '(make-vector 4 nil))
+(defmacro nnmaildir--lists-get-nlist  (lists) `(aref ,lists 0))
+(defmacro nnmaildir--lists-get-flist  (lists) `(aref ,lists 1))
+(defmacro nnmaildir--lists-get-mlist  (lists) `(aref ,lists 2))
+(defmacro nnmaildir--lists-get-tmpart (lists) `(aref ,lists 3))
+(defmacro nnmaildir--lists-set-nlist  (lists val) `(aset ,lists 0 ,val))
+(defmacro nnmaildir--lists-set-flist  (lists val) `(aset ,lists 1 ,val))
+(defmacro nnmaildir--lists-set-mlist  (lists val) `(aset ,lists 2 ,val))
+(defmacro nnmaildir--lists-set-tmpart (lists val) `(aset ,lists 3 ,val))
+
+(defmacro nnmaildir--nlist-last-num (list)
+  `(if ,list (nnmaildir--art-get-num (car ,list)) 0))
+(defmacro nnmaildir--nlist-art (list num)
+  `(and ,list
+        (>= (nnmaildir--art-get-num (car ,list)) ,num)
+        (nth (- (nnmaildir--art-get-num (car ,list)) ,num) ,list)))
+(defmacro nnmaildir--flist-art (list file)
+  `(symbol-value (intern-soft ,file ,list)))
+(defmacro nnmaildir--mlist-art (list msgid)
+  `(symbol-value (intern-soft ,msgid ,list)))
+
+(defmacro nnmaildir--art-new () '(make-vector 5 nil))
+(defmacro nnmaildir--art-get-prefix (article) `(aref ,article 0))
+(defmacro nnmaildir--art-get-suffix (article) `(aref ,article 1))
+(defmacro nnmaildir--art-get-num    (article) `(aref ,article 2))
+(defmacro nnmaildir--art-get-msgid  (article) `(aref ,article 3))
+(defmacro nnmaildir--art-get-nov    (article) `(aref ,article 4))
+(defmacro nnmaildir--art-set-prefix (article val) `(aset ,article 0 ,val))
+(defmacro nnmaildir--art-set-suffix (article val) `(aset ,article 1 ,val))
+(defmacro nnmaildir--art-set-num    (article val) `(aset ,article 2 ,val))
+(defmacro nnmaildir--art-set-msgid  (article val) `(aset ,article 3 ,val))
+(defmacro nnmaildir--art-set-nov    (article val) `(aset ,article 4 ,val))
+
+(defmacro nnmaildir--nov-new () '(make-vector 4 nil))
+(defmacro nnmaildir--nov-get-beg   (nov) `(aref ,nov 0))
+(defmacro nnmaildir--nov-get-mid   (nov) `(aref ,nov 1))
+(defmacro nnmaildir--nov-get-end   (nov) `(aref ,nov 2))
+(defmacro nnmaildir--nov-get-mtime (nov) `(aref ,nov 3))
+(defmacro nnmaildir--nov-set-beg   (nov val) `(aset ,nov 0 ,val))
+(defmacro nnmaildir--nov-set-mid   (nov val) `(aset ,nov 1 ,val))
+(defmacro nnmaildir--nov-set-end   (nov val) `(aset ,nov 2 ,val))
+(defmacro nnmaildir--nov-set-mtime (nov val) `(aset ,nov 3 ,val))
+
+(defmacro nnmaildir--srv-grp-dir (srv-dir gname)
+  `(file-name-as-directory (concat ,srv-dir ,gname)))
+
+(defun nnmaildir--param (prefixed-group-name param)
+  (setq param
+        (gnus-group-find-parameter prefixed-group-name param 'allow-list)
+        param (if (vectorp param) (aref param 0) param))
+  (eval param))
+
+(defmacro nnmaildir--unlink (file)
+  `(if (file-attributes ,file) (delete-file ,file)))
+
+(defmacro nnmaildir--tmp (dir) `(file-name-as-directory (concat ,dir "tmp")))
+(defmacro nnmaildir--new (dir) `(file-name-as-directory (concat ,dir "new")))
+(defmacro nnmaildir--cur (dir) `(file-name-as-directory (concat ,dir "cur")))
+(defmacro nnmaildir--nndir (dir)
+  `(file-name-as-directory (concat ,dir ".nnmaildir")))
+
+(defun nnmaildir--lists-fix (lists)
+  (let ((tmp (nnmaildir--lists-get-tmpart lists)))
+    (when tmp
+      (set (intern (nnmaildir--art-get-prefix tmp)
+                   (nnmaildir--lists-get-flist lists))
+           tmp)
+      (set (intern (nnmaildir--art-get-msgid tmp)
+                   (nnmaildir--lists-get-mlist lists))
+           tmp)
+      (nnmaildir--lists-set-tmpart lists nil))))
+
+(defun nnmaildir--prepare (server group)
+  (let (x groups)
+    (catch 'return
+      (setq x nnmaildir--tmp-server)
+      (when x
+        (set (intern (nnmaildir--srv-get-name x) nnmaildir--servers) x)
+        (setq nnmaildir--tmp-server nil))
+      (if (null server)
+          (or (setq server nnmaildir--cur-server)
+              (throw 'return nil))
+        (or (setq server (intern-soft server nnmaildir--servers))
+            (throw 'return nil))
+        (setq server (symbol-value server)
+              nnmaildir--cur-server server))
+      (setq groups (nnmaildir--srv-get-groups server))
+      (if groups nil (throw 'return nil))
+      (if (nnmaildir--srv-get-method server) nil
+        (setq x (concat "nnmaildir:" (nnmaildir--srv-get-name server))
+              x (gnus-server-to-method x))
+        (if x nil (throw 'return nil))
+        (nnmaildir--srv-set-method server x))
+      (setq x (nnmaildir--srv-get-tmpgrp server))
+      (when x
+        (set (intern (nnmaildir--grp-get-name x) groups) x)
+        (nnmaildir--srv-set-tmpgrp server nil))
+      (if (null group)
+          (or (setq group (nnmaildir--srv-get-curgrp server))
+              (throw 'return nil))
+        (setq group (intern-soft group groups))
+        (if group nil (throw 'return nil))
+        (setq group (symbol-value group)))
+      (nnmaildir--lists-fix (nnmaildir--grp-get-lists group))
+      group)))
+
+(defun nnmaildir--update-nov (srv-dir group article)
+  (let ((nnheader-file-coding-system 'binary)
+        dir gname pgname msgdir prefix suffix file attr mtime novdir novfile
+        nov msgid nov-beg nov-mid nov-end field pos extra val deactivate-mark)
+    (catch 'return
+      (setq suffix (nnmaildir--art-get-suffix article))
+      (if (stringp suffix) nil
+        (nnmaildir--art-set-nov article nil)
+        (throw 'return nil))
+      (setq gname (nnmaildir--grp-get-name group)
+            pgname (nnmaildir--grp-get-pname group)
+            dir (nnmaildir--srv-grp-dir srv-dir gname)
+            msgdir (if (nnmaildir--param pgname 'read-only)
+                       (nnmaildir--new dir) (nnmaildir--cur dir))
+            prefix (nnmaildir--art-get-prefix article)
+            file (concat msgdir prefix suffix)
+            attr (file-attributes file))
+      (if attr nil
+        (nnmaildir--art-set-suffix article 'expire)
+        (nnmaildir--art-set-nov article nil)
+        (throw 'return nil))
+      (setq mtime (nth 5 attr)
+            attr (nth 7 attr)
+            nov (nnmaildir--art-get-nov article)
+            novdir (concat (nnmaildir--nndir dir) "nov")
+            novdir (file-name-as-directory novdir)
+            novfile (concat novdir prefix))
+      (save-excursion
+        (set-buffer (get-buffer-create " *nnmaildir nov*"))
+        (when (file-exists-p novfile)
+          (and nov
+               (equal mtime (nnmaildir--nov-get-mtime nov))
+               (throw 'return nov))
+          (erase-buffer)
+          (nnheader-insert-file-contents novfile)
+          (setq nov (read (current-buffer)))
+          (nnmaildir--art-set-msgid article (car nov))
+          (setq nov (cadr nov))
+          (and (equal mtime (nnmaildir--nov-get-mtime nov))
+               (throw 'return nov)))
+        (erase-buffer)
+        (nnheader-insert-file-contents file)
+        (insert "\n")
+        (goto-char (point-min))
+        (save-restriction
+          (if (search-forward "\n\n" nil 'noerror)
+              (progn
+                (setq nov-mid (count-lines (point) (point-max)))
+                (narrow-to-region (point-min) (1- (point))))
+            (setq nov-mid 0))
+          (goto-char (point-min))
+          (delete-char 1)
+          (nnheader-fold-continuation-lines)
+          (setq nov (nnheader-parse-head 'naked)
+                field (or (mail-header-lines nov) 0)))
+        (if (or (zerop field) (nnmaildir--param pgname 'distrust-Lines:)) nil
+          (setq nov-mid field))
+        (setq nov-mid (number-to-string nov-mid)
+              nov-mid (concat (number-to-string attr) "\t" nov-mid)
+              field (or (mail-header-references nov) "")
+              pos 0)
+        (save-match-data
+          (while (string-match "\t" field pos)
+            (aset field (match-beginning 0) ? )
+            (setq pos (match-end 0)))
+          (setq nov-mid (concat field "\t" nov-mid)
+                extra (mail-header-extra nov)
+                nov-end "")
+          (while extra
+            (setq field (car extra) extra (cdr extra)
+                  val (cdr field) field (symbol-name (car field))
+                  pos 0)
+            (while (string-match "\t" field pos)
+              (aset field (match-beginning 0) ? )
+              (setq pos (match-end 0)))
+            (setq pos 0)
+            (while (string-match "\t" val pos)
+              (aset val (match-beginning 0) ? )
+              (setq pos (match-end 0)))
+            (setq nov-end (concat nov-end "\t" field ": " val)))
+          (setq nov-end (if (zerop (length nov-end)) "" (substring nov-end 1))
+                field (or (mail-header-subject nov) "")
+                pos 0)
+          (while (string-match "\t" field pos)
+            (aset field (match-beginning 0) ? )
+            (setq pos (match-end 0)))
+          (setq nov-beg field
+                field (or (mail-header-from nov) "")
+                pos 0)
+          (while (string-match "\t" field pos)
+            (aset field (match-beginning 0) ? )
+            (setq pos (match-end 0)))
+          (setq nov-beg (concat nov-beg "\t" field)
+                field (or (mail-header-date nov) "")
+                pos 0)
+          (while (string-match "\t" field pos)
+            (aset field (match-beginning 0) ? )
+            (setq pos (match-end 0)))
+          (setq nov-beg (concat nov-beg "\t" field)
+                field (mail-header-id nov)
+                pos 0)
+          (while (string-match "\t" field pos)
+            (aset field (match-beginning 0) ? )
+            (setq pos (match-end 0)))
+          (setq msgid field))
+        (if (or (null msgid) (nnheader-fake-message-id-p msgid))
+            (setq msgid (concat "<" prefix "@nnmaildir>")))
+        (erase-buffer)
+        (setq nov (nnmaildir--nov-new))
+        (nnmaildir--nov-set-beg nov nov-beg)
+        (nnmaildir--nov-set-mid nov nov-mid)
+        (nnmaildir--nov-set-end nov nov-end)
+        (nnmaildir--nov-set-mtime nov mtime)
+        (prin1 (list msgid nov) (current-buffer))
+        (setq file (concat novdir ":"))
+        (nnmaildir--unlink file)
+        (write-region (point-min) (point-max) file nil 'no-message))
+      (rename-file file novfile 'replace)
+      (nnmaildir--art-set-msgid article msgid)
+      nov)))
+
+(defun nnmaildir--cache-nov (group article nov)
+  (let ((cache (nnmaildir--grp-get-cache group))
+        (index (nnmaildir--grp-get-index group))
+        goner)
+    (if (nnmaildir--art-get-nov article) nil
+      (setq goner (aref cache index))
+      (if goner (nnmaildir--art-set-nov goner nil))
+      (aset cache index article)
+      (nnmaildir--grp-set-index group (% (1+ index) (length cache))))
+    (nnmaildir--art-set-nov article nov)))
+
+(defun nnmaildir--grp-add-art (srv-dir group article)
+  (let ((nov (nnmaildir--update-nov srv-dir group article))
+        old-lists new-lists)
+    (when nov
+      (setq old-lists (nnmaildir--grp-get-lists group)
+            new-lists (nnmaildir--lists-new))
+      (nnmaildir--lists-set-nlist
+        new-lists (cons article (nnmaildir--lists-get-nlist old-lists)))
+      (nnmaildir--lists-set-flist new-lists
+                                  (nnmaildir--lists-get-flist old-lists))
+      (nnmaildir--lists-set-mlist new-lists
+                                  (nnmaildir--lists-get-mlist old-lists))
+      (nnmaildir--lists-set-tmpart new-lists article)
+      (nnmaildir--grp-set-lists group new-lists)
+      (nnmaildir--lists-fix new-lists)
+      (nnmaildir--cache-nov group article nov)
+      t)))
+
+(defun nnmaildir--mkdir (dir)
+  (or (file-exists-p (file-name-as-directory dir))
+      (make-directory-internal (directory-file-name dir))))
+
+(defun nnmaildir--article-count (group)
+  (let ((ct 0)
+        (min 0))
+    (setq group (nnmaildir--grp-get-lists group)
+          group (nnmaildir--lists-get-nlist group))
+    (while group
+      (if (stringp (nnmaildir--art-get-suffix (car group)))
+          (setq ct (1+ ct)
+                min (nnmaildir--art-get-num (car group))))
+      (setq group (cdr group)))
+    (cons ct min)))
+
+(defun nnmaildir-article-number-to-file-name
+       (number group-name server-address-string)
+  (let ((group (nnmaildir--prepare server-address-string group-name))
+        list article suffix dir filename)
+    (catch 'return
+      (if (null group)
+          ;; The given group or server does not exist.
+          (throw 'return nil))
+      (setq list (nnmaildir--grp-get-lists group)
+            list (nnmaildir--lists-get-nlist list)
+            article (nnmaildir--nlist-art list number))
+      (if (null article)
+          ;; The given article number does not exist in this group.
+          (throw 'return nil))
+      (setq suffix (nnmaildir--art-get-suffix article))
+      (if (not (stringp suffix))
+          ;; The article has expired.
+          (throw 'return nil))
+      (setq dir (nnmaildir--srv-get-dir nnmaildir--cur-server)
+            dir (nnmaildir--srv-grp-dir dir group-name)
+            group (if (nnmaildir--param (nnmaildir--grp-get-pname group)
+                                        'read-only)
+                      (nnmaildir--new dir) (nnmaildir--cur dir))
+            filename (concat group (nnmaildir--art-get-prefix article) suffix))
+      (if (file-exists-p filename)
+          filename
+        ;; The article disappeared out from under us.
+        (nnmaildir--art-set-suffix article 'expire)
+        (nnmaildir--art-set-nov article nil)
+        nil))))
+
+(defun nnmaildir-request-type (group &optional article)
+  'mail)
+
+(defun nnmaildir-status-message (&optional server)
+  (nnmaildir--prepare server nil)
+  (nnmaildir--srv-get-error nnmaildir--cur-server))
+
+(defun nnmaildir-server-opened (&optional server)
+  (and nnmaildir--cur-server
+       (if server
+           (string-equal server
+                         (nnmaildir--srv-get-name nnmaildir--cur-server))
+         t)
+       (nnmaildir--srv-get-groups nnmaildir--cur-server)
+       t))
+
+(defun nnmaildir-open-server (server &optional defs)
+  (let ((x server)
+        dir size)
+    (catch 'return
+      (setq server (intern-soft x nnmaildir--servers))
+      (if server
+          (and (setq server (symbol-value server))
+               (nnmaildir--srv-get-groups server)
+               (setq nnmaildir--cur-server server)
+               (throw 'return t))
+        (setq server (nnmaildir--srv-new))
+        (nnmaildir--srv-set-name server x)
+        (setq nnmaildir--tmp-server server)
+        (set (intern x nnmaildir--servers) server)
+        (setq nnmaildir--tmp-server nil))
+      (setq dir (assq 'directory defs))
+      (if dir nil
+        (nnmaildir--srv-set-error
+          server "You must set \"directory\" in the select method")
+        (throw 'return nil))
+      (setq dir (cadr dir)
+            dir (eval dir)
+            dir (expand-file-name dir)
+            dir (file-name-as-directory dir))
+      (if (file-exists-p dir) nil
+        (nnmaildir--srv-set-error server (concat "No such directory: " dir))
+        (throw 'return nil))
+      (nnmaildir--srv-set-dir server dir)
+      (setq x (assq 'directory-files defs))
+      (if (null x)
+          (setq x (symbol-function (if nnheader-directory-files-is-safe
+                                       'directory-files
+                                     'nnheader-directory-files-safe)))
+        (setq x (cadr x))
+        (if (functionp x) nil
+          (nnmaildir--srv-set-error
+            server (concat "Not a function: " (prin1-to-string x)))
+          (throw 'return nil)))
+      (nnmaildir--srv-set-ls server x)
+      (setq x (funcall x dir nil "\\`[^.]" 'nosort)
+            x (length x)
+            size 1)
+      (while (<= size x) (setq size (* 2 size)))
+      (if (/= size 1) (setq size (1- size)))
+      (and (setq x (assq 'get-new-mail defs))
+           (setq x (cdr x))
+           (car x)
+           (nnmaildir--srv-set-gnm server t)
+           (require 'nnmail))
+      (setq x (assq 'create-directory defs))
+      (when x
+        (setq x (cadr x)
+              x (eval x))
+        (nnmaildir--srv-set-create-dir server x))
+      (nnmaildir--srv-set-groups server (make-vector size 0))
+      (setq nnmaildir--cur-server server)
+      t)))
+
+(defun nnmaildir--parse-filename (file)
+  (let ((prefix (car file))
+        timestamp len)
+    (if (string-match
+          "\\`\\([0-9]+\\)\\.\\([0-9]+\\)\\(_\\([0-9]+\\)\\)?\\(\\..*\\)\\'"
+          prefix)
+        (progn
+          (setq timestamp (concat "0000" (match-string 1 prefix))
+                len (- (length timestamp) 4))
+          (vector (string-to-number (substring timestamp 0 len))
+                  (string-to-number (substring timestamp len))
+                  (string-to-number (match-string 2 prefix))
+                  (string-to-number (or (match-string 4 prefix) "-1"))
+                  (match-string 5 prefix)
+                  file))
+      file)))
+
+(defun nnmaildir--sort-files (a b)
+  (catch 'return
+    (if (consp a)
+        (throw 'return (and (consp b) (string-lessp (car a) (car b)))))
+    (if (consp b) (throw 'return t))
+    (if (< (aref a 0) (aref b 0)) (throw 'return t))
+    (if (> (aref a 0) (aref b 0)) (throw 'return nil))
+    (if (< (aref a 1) (aref b 1)) (throw 'return t))
+    (if (> (aref a 1) (aref b 1)) (throw 'return nil))
+    (if (< (aref a 2) (aref b 2)) (throw 'return t))
+    (if (> (aref a 2) (aref b 2)) (throw 'return nil))
+    (if (< (aref a 3) (aref b 3)) (throw 'return t))
+    (if (> (aref a 3) (aref b 3)) (throw 'return nil))
+    (string-lessp (aref a 4) (aref b 4))))
+
+(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
+          files file num dir flist group x)
+      (setq absdir (file-name-as-directory (concat srv-dir gname))
+            nndir (nnmaildir--nndir absdir))
+      (if (file-attributes absdir) nil
+        (nnmaildir--srv-set-error nnmaildir--cur-server
+                                  (concat "No such directory: " absdir))
+        (throw 'return nil))
+      (setq tdir (nnmaildir--tmp absdir)
+            ndir (nnmaildir--new absdir)
+            cdir (nnmaildir--cur absdir)
+            nattr (file-attributes ndir)
+            cattr (file-attributes cdir))
+      (if (and (file-exists-p tdir) nattr cattr) nil
+        (nnmaildir--srv-set-error nnmaildir--cur-server
+                                  (concat "Not a maildir: " absdir))
+        (throw 'return nil))
+      (setq group (nnmaildir--prepare nil gname))
+      (if group
+          (setq isnew nil
+                pgname (nnmaildir--grp-get-pname group))
+        (setq isnew t
+              group (nnmaildir--grp-new)
+              pgname (gnus-group-prefixed-name gname method))
+        (nnmaildir--grp-set-name group gname)
+        (nnmaildir--grp-set-pname group pgname)
+        (nnmaildir--grp-set-lists group (nnmaildir--lists-new))
+        (nnmaildir--grp-set-index group 0)
+        (nnmaildir--mkdir nndir)
+        (nnmaildir--mkdir (concat nndir "nov"))
+        (nnmaildir--mkdir (concat nndir "marks"))
+        (write-region "" nil (concat nndir "markfile") nil 'no-message))
+      (setq read-only (nnmaildir--param pgname 'read-only)
+            ls (or (nnmaildir--param pgname 'directory-files) srv-ls))
+      (if read-only nil
+        (setq x (nth 11 (file-attributes tdir)))
+        (if (and (= x (nth 11 nattr)) (= x (nth 11 cattr))) nil
+          (nnmaildir--srv-set-error nnmaildir--cur-server
+                                    (concat "Maildir spans filesystems: "
+                                            absdir))
+          (throw 'return nil))
+        (setq files (funcall ls tdir 'full "\\`[^.]" 'nosort))
+        (while files
+          (setq file (car files) files (cdr files)
+                x (file-attributes file))
+          (if (or (< 1 (cadr x)) (> 36h-ago (car (nth 4 x))))
+              (delete-file file))))
+      (or scan-msgs
+          isnew
+          (throw 'return t))
+      (setq nattr (nth 5 nattr))
+      (if (equal nattr (nnmaildir--grp-get-new group))
+          (setq nattr nil))
+      (if read-only (setq dir (and (or isnew nattr) ndir))
+        (when (or isnew nattr)
+          (setq files (funcall ls ndir nil "\\`[^.]" 'nosort))
+          (while files
+            (setq file (car files) files (cdr files))
+            (rename-file (concat ndir file) (concat cdir file ":2,")))
+          (nnmaildir--grp-set-new group nattr))
+        (setq cattr (file-attributes cdir)
+              cattr (nth 5 cattr))
+        (if (equal cattr (nnmaildir--grp-get-cur group))
+            (setq cattr nil))
+        (setq dir (and (or isnew cattr) cdir)))
+      (if dir nil (throw 'return t))
+      (setq files (funcall ls dir nil "\\`[^.]" 'nosort))
+      (when isnew
+        (setq x (length files)
+              num 1)
+        (while (<= num x) (setq num (* 2 num)))
+        (if (/= num 1) (setq num (1- num)))
+        (setq x (nnmaildir--grp-get-lists group))
+        (nnmaildir--lists-set-flist x (make-vector num 0))
+        (nnmaildir--lists-set-mlist x (make-vector num 0))
+        (nnmaildir--grp-set-mmth group (make-vector 1 0))
+        (setq num (nnmaildir--param pgname 'nov-cache-size))
+        (if (numberp num) (if (< num 1) (setq num 1))
+          (setq x files
+                num 16
+                cdir (file-name-as-directory (concat nndir "marks"))
+                ndir (file-name-as-directory (concat cdir "tick"))
+                cdir (file-name-as-directory (concat cdir "read")))
+          (while x
+            (setq file (car x) x (cdr x))
+            (string-match "\\`\\([^:]*\\)\\(\\(:.*\\)?\\)\\'" file)
+            (setq file (match-string 1 file))
+            (if (or (not (file-exists-p (concat cdir file)))
+                    (file-exists-p (concat ndir file)))
+                (setq num (1+ num)))))
+        (nnmaildir--grp-set-cache group (make-vector num nil))
+        (nnmaildir--srv-set-tmpgrp nnmaildir--cur-server group)
+        (set (intern gname groups) group)
+        (nnmaildir--srv-set-tmpgrp nnmaildir--cur-server nil)
+        (or scan-msgs (throw 'return t)))
+      (setq flist (nnmaildir--grp-get-lists group)
+            num (nnmaildir--lists-get-nlist flist)
+            flist (nnmaildir--lists-get-flist flist)
+            num (nnmaildir--nlist-last-num num)
+            x files
+            files nil)
+      (while x
+        (setq file (car x) x (cdr x))
+        (string-match "\\`\\([^:]*\\)\\(\\(:.*\\)?\\)\\'" file)
+        (setq file (cons (match-string 1 file) (match-string 2 file)))
+        (if (nnmaildir--flist-art flist (car file)) nil
+          (setq files (cons file files))))
+      (setq files (mapcar 'nnmaildir--parse-filename files)
+            files (sort files 'nnmaildir--sort-files))
+      (while files
+        (setq file (car files) files (cdr files)
+              file (if (consp file) file (aref file 5))
+              x (nnmaildir--art-new))
+        (nnmaildir--art-set-prefix x (car file))
+        (nnmaildir--art-set-suffix x (cdr file))
+        (nnmaildir--art-set-num x (1+ num))
+        (if (nnmaildir--grp-add-art srv-dir group x)
+            (setq num (1+ num))))
+      (if read-only (nnmaildir--grp-set-new group nattr)
+        (nnmaildir--grp-set-cur group cattr)))
+    t))
+
+(defun nnmaildir-request-scan (&optional scan-group server)
+  (let ((coding-system-for-write nnheader-file-coding-system)
+        (buffer-file-coding-system nil)
+        (file-coding-system-alist nil)
+        (nnmaildir-get-new-mail t)
+        (nnmaildir-group-alist nil)
+        (nnmaildir-active-file nil)
+        x srv-ls srv-dir method groups group dirs grp-dir seen deactivate-mark)
+    (nnmaildir--prepare server nil)
+    (setq srv-ls (nnmaildir--srv-get-ls nnmaildir--cur-server)
+          srv-dir (nnmaildir--srv-get-dir nnmaildir--cur-server)
+          method (nnmaildir--srv-get-method nnmaildir--cur-server)
+          groups (nnmaildir--srv-get-groups nnmaildir--cur-server))
+    (save-excursion
+      (set-buffer (get-buffer-create " *nnmaildir work*"))
+      (save-match-data
+        (if (stringp scan-group)
+            (if (nnmaildir--scan scan-group t groups method srv-dir srv-ls)
+                (if (nnmaildir--srv-get-gnm nnmaildir--cur-server)
+                    (nnmail-get-new-mail 'nnmaildir nil nil scan-group))
+              (unintern scan-group groups))
+          (setq x (nth 5 (file-attributes srv-dir)))
+          (if (equal x (nnmaildir--srv-get-mtime nnmaildir--cur-server))
+              (if scan-group nil
+                (mapatoms (lambda (sym)
+                            (nnmaildir--scan (symbol-name sym) t groups
+                                             method srv-dir srv-ls))
+                          groups))
+            (setq dirs (funcall srv-ls srv-dir nil "\\`[^.]" 'nosort)
+                  x (length dirs)
+                  seen 1)
+            (while (<= seen x) (setq seen (* 2 seen)))
+            (if (/= seen 1) (setq seen (1- seen)))
+            (setq seen (make-vector seen 0)
+                  scan-group (null scan-group))
+            (while dirs
+              (setq grp-dir (car dirs) dirs (cdr dirs))
+              (if (nnmaildir--scan grp-dir scan-group groups method srv-dir
+                                   srv-ls)
+                  (intern grp-dir seen)))
+            (setq x nil)
+            (mapatoms (lambda (group)
+                        (setq group (symbol-name group))
+                        (if (intern-soft group seen) nil
+                          (setq x (cons group x))))
+                      groups)
+            (while x
+              (unintern (car x) groups)
+              (setq x (cdr x)))
+            (nnmaildir--srv-set-mtime nnmaildir--cur-server
+                                      (nth 5 (file-attributes srv-dir))))
+          (if (nnmaildir--srv-get-gnm nnmaildir--cur-server)
+              (nnmail-get-new-mail 'nnmaildir nil nil))))))
+  t)
+
+(defun nnmaildir-request-list (&optional server)
+  (nnmaildir-request-scan 'find-new-groups server)
+  (let (pgname ro ct-min deactivate-mark)
+    (nnmaildir--prepare server nil)
+    (save-excursion
+      (set-buffer nntp-server-buffer)
+      (erase-buffer)
+      (mapatoms (lambda (group)
+                  (setq group (symbol-value group)
+                        ro (nnmaildir--param (nnmaildir--grp-get-pname group)
+                                             'read-only)
+                        ct-min (nnmaildir--article-count group))
+                  (insert (nnmaildir--grp-get-name group) " ")
+                  (princ (car ct-min) nntp-server-buffer)
+                  (insert " ")
+                  (princ (cdr ct-min) nntp-server-buffer)
+                  (insert " " (if ro "n" "y") "\n"))
+                (nnmaildir--srv-get-groups nnmaildir--cur-server))))
+  t)
+
+(defun nnmaildir-request-newgroups (date &optional server)
+  (nnmaildir-request-list server))
+
+(defun nnmaildir-retrieve-groups (groups &optional server)
+  (let (gname group ct-min deactivate-mark)
+    (nnmaildir--prepare server nil)
+    (save-excursion
+      (set-buffer nntp-server-buffer)
+      (erase-buffer)
+      (while groups
+        (setq gname (car groups) groups (cdr groups))
+        (nnmaildir-request-scan gname server)
+        (setq group (nnmaildir--prepare nil gname))
+        (if (null group) (insert "411 no such news group\n")
+          (setq ct-min (nnmaildir--article-count group))
+          (insert "211 ")
+          (princ (car ct-min) nntp-server-buffer)
+          (insert " ")
+          (princ (cdr ct-min) nntp-server-buffer)
+          (insert " ")
+          (princ (nnmaildir--nlist-last-num
+                   (nnmaildir--lists-get-nlist
+                     (nnmaildir--grp-get-lists group)))
+                 nntp-server-buffer)
+          (insert " " gname "\n")))))
+  'group)
+
+(defun nnmaildir-request-update-info (gname info &optional server)
+  (nnmaildir-request-scan gname server)
+  (let ((group (nnmaildir--prepare server gname))
+        srv-ls pgname nlist flist last always-marks never-marks old-marks
+        dotfile num dir markdirs marks mark ranges articles article read end
+        new-marks ls old-mmth new-mmth mtime mark-sym deactivate-mark)
+    (catch 'return
+      (if group nil
+        (nnmaildir--srv-set-error nnmaildir--cur-server
+                                  (concat "No such group: " gname))
+        (throw 'return nil))
+      (setq srv-ls (nnmaildir--srv-get-ls nnmaildir--cur-server)
+            gname (nnmaildir--grp-get-name group)
+            pgname (nnmaildir--grp-get-pname group)
+            nlist (nnmaildir--grp-get-lists group)
+            flist (nnmaildir--lists-get-flist nlist)
+            nlist (nnmaildir--lists-get-nlist nlist))
+      (if nlist nil
+        (gnus-info-set-read info nil)
+        (gnus-info-set-marks info nil 'extend)
+        (throw 'return info))
+      (setq old-marks (cons 'read (gnus-info-read info))
+            old-marks (cons old-marks (gnus-info-marks info))
+            last (nnmaildir--nlist-last-num nlist)
+            always-marks (nnmaildir--param pgname 'always-marks)
+            never-marks (nnmaildir--param pgname 'never-marks)
+            dir (nnmaildir--srv-get-dir nnmaildir--cur-server)
+            dir (nnmaildir--srv-grp-dir dir gname)
+            dir (nnmaildir--nndir dir)
+            dir (concat dir "marks")
+            dir (file-name-as-directory dir)
+            ls (nnmaildir--param pgname 'directory-files)
+            ls (or ls srv-ls)
+            markdirs (funcall ls dir nil "\\`[^.]" 'nosort)
+            num (length markdirs)
+            new-mmth 1)
+      (while (<= new-mmth num) (setq new-mmth (* 2 new-mmth)))
+      (if (/= new-mmth 1) (setq new-mmth (1- new-mmth)))
+      (setq new-mmth (make-vector new-mmth 0)
+            old-mmth (nnmaildir--grp-get-mmth group))
+      (while markdirs
+        (setq mark (car markdirs) markdirs (cdr markdirs)
+              articles (concat dir mark)
+              articles (file-name-as-directory articles)
+              mark-sym (intern mark)
+              ranges nil)
+        (catch 'got-ranges
+          (if (memq mark-sym never-marks) (throw 'got-ranges nil))
+          (when (memq mark-sym always-marks)
+            (setq ranges (list (cons 1 last)))
+            (throw 'got-ranges nil))
+          (setq mtime (file-attributes articles)
+                mtime (nth 5 mtime))
+          (set (intern mark new-mmth) mtime)
+          (when (equal mtime (symbol-value (intern-soft mark old-mmth)))
+            (setq ranges (assq mark-sym old-marks))
+            (if ranges (setq ranges (cdr ranges)))
+            (throw 'got-ranges nil))
+          (setq articles (funcall ls articles nil "\\`[^.]" 'nosort))
+          (while articles
+            (setq article (car articles) articles (cdr articles)
+                  article (nnmaildir--flist-art flist article))
+            (if article
+                (setq num (nnmaildir--art-get-num article)
+                      ranges (gnus-add-to-range ranges (list num))))))
+        (if (eq mark-sym 'read) (setq read ranges)
+          (if ranges (setq marks (cons (cons mark-sym ranges) marks)))))
+      (gnus-info-set-read info read)
+      (gnus-info-set-marks info marks 'extend)
+      (nnmaildir--grp-set-mmth group new-mmth)
+      info)))
+
+(defun nnmaildir-request-group (gname &optional server fast)
+  (nnmaildir-request-scan gname server)
+  (let ((group (nnmaildir--prepare server gname))
+        ct-min deactivate-mark)
+    (save-excursion
+      (set-buffer nntp-server-buffer)
+      (erase-buffer)
+      (catch 'return
+        (if group nil
+          (insert "411 no such news group\n")
+          (nnmaildir--srv-set-error nnmaildir--cur-server
+                                    (concat "No such group: " gname))
+          (throw 'return nil))
+        (nnmaildir--srv-set-curgrp nnmaildir--cur-server group)
+        (if fast (throw 'return t))
+        (setq ct-min (nnmaildir--article-count group))
+        (insert "211 ")
+        (princ (car ct-min) nntp-server-buffer)
+        (insert " ")
+        (princ (cdr ct-min) nntp-server-buffer)
+        (insert " ")
+        (princ (nnmaildir--nlist-last-num
+                 (nnmaildir--lists-get-nlist
+                  (nnmaildir--grp-get-lists group)))
+               nntp-server-buffer)
+        (insert " " gname "\n")
+        t))))
+
+(defun nnmaildir-request-create-group (gname &optional server args)
+  (nnmaildir--prepare server nil)
+  (catch 'return
+    (let ((create-dir (nnmaildir--srv-get-create-dir nnmaildir--cur-server))
+          srv-dir dir groups)
+      (when (zerop (length gname))
+        (nnmaildir--srv-set-error nnmaildir--cur-server
+                                  "Invalid (empty) group name")
+        (throw 'return nil))
+      (when (eq (aref "." 0) (aref gname 0))
+        (nnmaildir--srv-set-error nnmaildir--cur-server
+                                  "Group names may not start with \".\"")
+        (throw 'return nil))
+      (when (save-match-data (string-match "[\0/\t]" gname))
+        (nnmaildir--srv-set-error nnmaildir--cur-server
+          (concat "Illegal characters (null, tab, or /) in group name: "
+                  gname))
+        (throw 'return nil))
+      (setq groups (nnmaildir--srv-get-groups nnmaildir--cur-server))
+      (when (intern-soft gname groups)
+        (nnmaildir--srv-set-error nnmaildir--cur-server
+                                  (concat "Group already exists: " gname))
+        (throw 'return nil))
+      (setq srv-dir (nnmaildir--srv-get-dir nnmaildir--cur-server))
+      (if (file-name-absolute-p create-dir)
+          (setq dir (expand-file-name create-dir))
+        (setq dir srv-dir
+              dir (file-truename dir)
+              dir (concat dir create-dir)))
+      (setq dir (file-name-as-directory dir)
+            dir (concat dir gname))
+      (nnmaildir--mkdir dir)
+      (setq dir (file-name-as-directory dir))
+      (nnmaildir--mkdir (concat dir "tmp"))
+      (nnmaildir--mkdir (concat dir "new"))
+      (nnmaildir--mkdir (concat dir "cur"))
+      (setq create-dir (file-name-as-directory create-dir))
+      (make-symbolic-link (concat create-dir gname) (concat srv-dir gname))
+      (nnmaildir-request-scan 'find-new-groups))))
+
+(defun nnmaildir-request-rename-group (gname new-name &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)
+        srv-dir x groups)
+    (catch 'return
+      (if group nil
+        (nnmaildir--srv-set-error nnmaildir--cur-server
+                                  (concat "No such group: " gname))
+        (throw 'return nil))
+      (when (zerop (length new-name))
+        (nnmaildir--srv-set-error nnmaildir--cur-server
+                                  "Invalid (empty) group name")
+        (throw 'return nil))
+      (when (eq (aref "." 0) (aref new-name 0))
+        (nnmaildir--srv-set-error nnmaildir--cur-server
+                                  "Group names may not start with \".\"")
+        (throw 'return nil))
+      (when (save-match-data (string-match "[\0/\t]" new-name))
+        (nnmaildir--srv-set-error nnmaildir--cur-server
+          (concat "Illegal characters (null, tab, or /) in group name: "
+                  new-name))
+        (throw 'return nil))
+      (if (string-equal gname new-name) (throw 'return t))
+      (when (intern-soft new-name
+                         (nnmaildir--srv-get-groups nnmaildir--cur-server))
+        (nnmaildir--srv-set-error nnmaildir--cur-server
+                                  (concat "Group already exists: " new-name))
+        (throw 'return nil))
+      (setq srv-dir (nnmaildir--srv-get-dir nnmaildir--cur-server))
+      (condition-case err
+          (rename-file (concat srv-dir gname)
+                       (concat srv-dir new-name))
+        (error
+         (nnmaildir--srv-set-error nnmaildir--cur-server
+                                   (concat "Error renaming link: "
+                                           (prin1-to-string err)))
+         (throw 'return nil)))
+      (setq x (nnmaildir--srv-get-groups nnmaildir--cur-server)
+            groups (make-vector (length x) 0))
+      (mapatoms (lambda (sym)
+                  (if (eq (symbol-value sym) group) nil
+                    (set (intern (symbol-name sym) groups)
+                         (symbol-value sym))))
+                x)
+      (setq group (copy-sequence group))
+      (nnmaildir--grp-set-name group new-name)
+      (set (intern new-name groups) group)
+      (nnmaildir--srv-set-groups nnmaildir--cur-server groups)
+      t)))
+
+(defun nnmaildir-request-delete-group (gname force &optional server)
+  (let ((group (nnmaildir--prepare server gname))
+        pgname grp-dir dir dirs files ls deactivate-mark)
+    (catch 'return
+      (if group nil
+        (nnmaildir--srv-set-error nnmaildir--cur-server
+                                  (concat "No such group: " gname))
+        (throw 'return nil))
+      (if (eq group (nnmaildir--srv-get-curgrp nnmaildir--cur-server))
+          (nnmaildir--srv-set-curgrp nnmaildir--cur-server nil))
+      (setq gname (nnmaildir--grp-get-name group)
+            pgname (nnmaildir--grp-get-pname group))
+      (unintern gname (nnmaildir--srv-get-groups nnmaildir--cur-server))
+      (setq grp-dir (nnmaildir--srv-get-dir nnmaildir--cur-server)
+            grp-dir (nnmaildir--srv-grp-dir grp-dir gname))
+      (if (not force) (setq grp-dir (directory-file-name grp-dir))
+        (if (nnmaildir--param pgname 'read-only)
+            (progn (delete-directory  (nnmaildir--tmp grp-dir))
+                   (nnmaildir--unlink (nnmaildir--new grp-dir))
+                   (delete-directory  (nnmaildir--cur grp-dir)))
+          (save-excursion
+            (set-buffer (get-buffer-create " *nnmaildir work*"))
+            (erase-buffer)
+            (setq ls (or (nnmaildir--param pgname 'directory-files)
+                         (nnmaildir--srv-get-ls nnmaildir--cur-server))
+                  files (funcall ls (nnmaildir--tmp grp-dir) 'full "\\`[^.]"
+                                 'nosort))
+            (while files
+              (delete-file (car files))
+              (setq files (cdr files)))
+            (delete-directory (concat grp-dir "tmp"))
+            (setq files (funcall ls (nnmaildir--new grp-dir) 'full "\\`[^.]"
+                                 'nosort))
+            (while files
+              (delete-file (car files))
+              (setq files (cdr files)))
+            (delete-directory (concat grp-dir "new"))
+            (setq files (funcall ls (nnmaildir--cur grp-dir) 'full "\\`[^.]"
+                                 'nosort))
+            (while files
+              (delete-file (car files))
+              (setq files (cdr files)))
+            (delete-directory (concat grp-dir "cur"))))
+        (setq dir (nnmaildir--nndir grp-dir)
+              dirs (cons (concat dir "nov")
+                         (funcall ls (concat dir "marks") 'full "\\`[^.]"
+                                  'nosort)))
+        (while dirs
+          (setq dir (car dirs) dirs (cdr dirs)
+                files (funcall ls dir 'full "\\`[^.]" 'nosort))
+          (while files
+            (delete-file (car files))
+            (setq files (cdr files)))
+          (delete-directory dir))
+        (setq dir (nnmaildir--nndir grp-dir)
+              files (concat dir "markfile"))
+        (nnmaildir--unlink files)
+        (delete-directory (concat dir "marks"))
+        (delete-directory dir)
+        (setq grp-dir (directory-file-name grp-dir)
+              dir (car (file-attributes grp-dir)))
+        (if (eq (aref "/" 0) (aref dir 0)) nil
+          (setq dir (concat (file-truename
+                              (nnmaildir--srv-get-dir nnmaildir--cur-server))
+                            dir)))
+        (delete-directory dir))
+      (nnmaildir--unlink grp-dir)
+      t)))
+
+(defun nnmaildir-retrieve-headers (articles &optional gname server fetch-old)
+  (let ((group (nnmaildir--prepare server gname))
+        srv-dir dir nlist mlist article num stop nov nlist2 deactivate-mark)
+    (catch 'return
+      (if group nil
+        (nnmaildir--srv-set-error nnmaildir--cur-server
+                                  (if gname (concat "No such group: " gname)
+                                    "No current group"))
+        (throw 'return nil))
+      (save-excursion
+        (set-buffer nntp-server-buffer)
+        (erase-buffer)
+        (setq nlist (nnmaildir--grp-get-lists group)
+              mlist (nnmaildir--lists-get-mlist nlist)
+              nlist (nnmaildir--lists-get-nlist nlist)
+              gname (nnmaildir--grp-get-name group)
+              srv-dir (nnmaildir--srv-get-dir nnmaildir--cur-server)
+              dir (nnmaildir--srv-grp-dir srv-dir gname))
+        (cond
+         ((null nlist))
+         ((and fetch-old (not (numberp fetch-old)))
+          (while nlist
+            (setq article (car nlist) nlist (cdr nlist)
+                  nov (nnmaildir--update-nov srv-dir group article))
+            (when nov
+              (nnmaildir--cache-nov group article nov)
+              (setq num (nnmaildir--art-get-num article))
+              (princ num nntp-server-buffer)
+              (insert "\t" (nnmaildir--nov-get-beg nov) "\t"
+                      (nnmaildir--art-get-msgid article) "\t"
+                      (nnmaildir--nov-get-mid nov) "\tXref: nnmaildir " gname
+                      ":")
+              (princ num nntp-server-buffer)
+              (insert "\t" (nnmaildir--nov-get-end nov) "\n")
+              (goto-char (point-min)))))
+         ((null articles))
+         ((stringp (car articles))
+          (while articles
+            (setq article (car articles) articles (cdr articles)
+                  article (nnmaildir--mlist-art mlist article))
+            (when (and article
+                       (setq nov (nnmaildir--update-nov srv-dir group
+                                                        article)))
+              (nnmaildir--cache-nov group article nov)
+              (setq num (nnmaildir--art-get-num article))
+              (princ num nntp-server-buffer)
+              (insert "\t" (nnmaildir--nov-get-beg nov) "\t"
+                      (nnmaildir--art-get-msgid article) "\t"
+                      (nnmaildir--nov-get-mid nov) "\tXref: nnmaildir " gname
+                      ":")
+              (princ num nntp-server-buffer)
+              (insert "\t" (nnmaildir--nov-get-end nov) "\n"))))
+         (t
+          (if fetch-old
+              ;; Assume the article range is sorted ascending
+              (setq stop (car articles)
+                    num  (car (last articles))
+                    stop (if (numberp stop) stop (car stop))
+                    num  (if (numberp num)  num  (cdr num))
+                    stop (- stop fetch-old)
+                    stop (if (< stop 1) 1 stop)
+                    articles (list (cons stop num))))
+          (while articles
+            (setq stop (car articles) articles (cdr articles))
+            (while (eq stop (car articles))
+              (setq articles (cdr articles)))
+            (if (numberp stop) (setq num stop)
+              (setq num (cdr stop) stop (car stop)))
+            (setq nlist2 (nthcdr (- (nnmaildir--art-get-num (car nlist)) num)
+                                 nlist))
+            (while (and nlist2
+                        (setq article (car nlist2)
+                              num (nnmaildir--art-get-num article))
+                        (>= num stop))
+              (setq nlist2 (cdr nlist2)
+                    nov (nnmaildir--update-nov srv-dir group article))
+              (when nov
+                (nnmaildir--cache-nov group article nov)
+                (princ num nntp-server-buffer)
+                (insert "\t" (nnmaildir--nov-get-beg nov) "\t"
+                        (nnmaildir--art-get-msgid article) "\t"
+                        (nnmaildir--nov-get-mid nov) "\tXref: nnmaildir " gname
+                        ":")
+                (princ num nntp-server-buffer)
+                (insert "\t" (nnmaildir--nov-get-end nov) "\n")
+                (goto-char (point-min)))))))
+        (sort-numeric-fields 1 (point-min) (point-max))
+        'nov))))
+
+(defun nnmaildir-request-article (num-msgid &optional gname server to-buffer)
+  (let ((group (nnmaildir--prepare server gname))
+        (case-fold-search t)
+        list article suffix dir deactivate-mark)
+    (catch 'return
+      (if group nil
+        (nnmaildir--srv-set-error nnmaildir--cur-server
+                                  (if gname (concat "No such group: " gname)
+                                    "No current group"))
+        (throw 'return nil))
+      (setq list (nnmaildir--grp-get-lists group))
+      (if (numberp num-msgid)
+          (setq list (nnmaildir--lists-get-nlist list)
+                article (nnmaildir--nlist-art list num-msgid))
+        (setq list (nnmaildir--lists-get-mlist list)
+              article (nnmaildir--mlist-art list num-msgid))
+        (if article (setq num-msgid (nnmaildir--art-get-num article))
+          (catch 'found
+            (mapatoms
+              (lambda (grp)
+                (setq group (symbol-value grp)
+                      list (nnmaildir--grp-get-lists group)
+                      list (nnmaildir--lists-get-mlist list)
+                      article (nnmaildir--mlist-art list num-msgid))
+                (when article
+                  (setq num-msgid (nnmaildir--art-get-num article))
+                  (throw 'found nil)))
+              (nnmaildir--srv-get-groups nnmaildir--cur-server)))))
+      (if article nil
+        (nnmaildir--srv-set-error nnmaildir--cur-server "No such article")
+        (throw 'return nil))
+      (if (stringp (setq suffix (nnmaildir--art-get-suffix article))) nil
+        (nnmaildir--srv-set-error nnmaildir--cur-server "Article has expired")
+        (throw 'return nil))
+      (setq gname (nnmaildir--grp-get-name group)
+            dir (nnmaildir--srv-get-dir nnmaildir--cur-server)
+            dir (nnmaildir--srv-grp-dir dir gname)
+            group (if (nnmaildir--param (nnmaildir--grp-get-pname group)
+                                        'read-only)
+                      (nnmaildir--new dir) (nnmaildir--cur dir))
+            nnmaildir-article-file-name (concat group
+                                                (nnmaildir--art-get-prefix
+                                                  article)
+                                                suffix))
+      (if (file-exists-p nnmaildir-article-file-name) nil
+        (nnmaildir--art-set-suffix article 'expire)
+        (nnmaildir--art-set-nov article nil)
+        (nnmaildir--srv-set-error nnmaildir--cur-server "Article has expired")
+        (throw 'return nil))
+      (save-excursion
+        (set-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)
+  (let (message-required-mail-headers)
+    (funcall message-send-mail-function)))
+
+(defun nnmaildir-request-replace-article (article gname buffer)
+  (let ((group (nnmaildir--prepare nil gname))
+        (coding-system-for-write nnheader-file-coding-system)
+        (buffer-file-coding-system nil)
+        (file-coding-system-alist nil)
+        file dir suffix tmpfile deactivate-mark)
+    (catch 'return
+      (if group nil
+        (nnmaildir--srv-set-error nnmaildir--cur-server
+                                  (concat "No such group: " gname))
+        (throw 'return nil))
+      (when (nnmaildir--param (nnmaildir--grp-get-pname group) 'read-only)
+        (nnmaildir--srv-set-error nnmaildir--cur-server
+                                  (concat "Read-only group: " group))
+        (throw 'return nil))
+      (setq dir (nnmaildir--srv-get-dir nnmaildir--cur-server)
+            dir (nnmaildir--srv-grp-dir dir gname)
+            file (nnmaildir--grp-get-lists group)
+            file (nnmaildir--lists-get-nlist file)
+            file (nnmaildir--nlist-art file article))
+      (if (and file (stringp (setq suffix (nnmaildir--art-get-suffix file))))
+          nil
+        (nnmaildir--srv-set-error nnmaildir--cur-server
+                                  (format "No such article: %d" article))
+        (throw 'return nil))
+      (save-excursion
+        (set-buffer buffer)
+        (setq article file
+              file (nnmaildir--art-get-prefix article)
+              tmpfile (concat (nnmaildir--tmp dir) file))
+        (when (file-exists-p tmpfile)
+          (nnmaildir--srv-set-error nnmaildir--cur-server
+                                    (concat "File exists: " tmpfile))
+          (throw 'return nil))
+        (write-region (point-min) (point-max) tmpfile nil 'no-message nil
+                      'confirm-overwrite)) ;; error would be preferred :(
+      (unix-sync) ;; no fsync :(
+      (rename-file tmpfile (concat (nnmaildir--cur dir) file suffix) 'replace)
+      t)))
+
+(defun nnmaildir-request-move-article (article gname server accept-form
+                                       &optional last)
+  (let ((group (nnmaildir--prepare server gname))
+        pgname list suffix result nnmaildir--file deactivate-mark)
+    (catch 'return
+      (if group nil
+        (nnmaildir--srv-set-error nnmaildir--cur-server
+                                  (concat "No such group: " gname))
+        (throw 'return nil))
+      (setq gname (nnmaildir--grp-get-name group)
+            pgname (nnmaildir--grp-get-pname group)
+            list (nnmaildir--grp-get-lists group)
+            list (nnmaildir--lists-get-nlist list)
+            article (nnmaildir--nlist-art list article))
+      (if article nil
+        (nnmaildir--srv-set-error nnmaildir--cur-server "No such article")
+        (throw 'return nil))
+      (if (stringp (setq suffix (nnmaildir--art-get-suffix article))) nil
+        (nnmaildir--srv-set-error nnmaildir--cur-server "Article has expired")
+        (throw 'return nil))
+      (setq nnmaildir--file (nnmaildir--srv-get-dir nnmaildir--cur-server)
+            nnmaildir--file (nnmaildir--srv-grp-dir nnmaildir--file gname)
+            nnmaildir--file (if (nnmaildir--param pgname 'read-only)
+                                (nnmaildir--new nnmaildir--file)
+                              (nnmaildir--cur nnmaildir--file))
+            nnmaildir--file (concat nnmaildir--file
+                                    (nnmaildir--art-get-prefix article)
+                                    suffix))
+      (if (file-exists-p nnmaildir--file) nil
+        (nnmaildir--art-set-suffix article 'expire)
+        (nnmaildir--art-set-nov article nil)
+        (nnmaildir--srv-set-error nnmaildir--cur-server "Article has expired")
+        (throw 'return nil))
+      (save-excursion
+        (set-buffer (get-buffer-create " *nnmaildir move*"))
+        (erase-buffer)
+        (nnheader-insert-file-contents nnmaildir--file)
+        (setq result (eval accept-form)))
+      (if (or (null result) (nnmaildir--param pgname 'read-only)) nil
+        (nnmaildir--unlink nnmaildir--file)
+        (nnmaildir--art-set-suffix article 'expire)
+        (nnmaildir--art-set-nov article nil))
+      result)))
+
+(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)
+        (file-coding-system-alist nil)
+        srv-dir dir file tmpfile curfile 24h num article)
+    (catch 'return
+      (if group nil
+        (nnmaildir--srv-set-error nnmaildir--cur-server
+                                  (concat "No such group: " gname))
+        (throw 'return nil))
+      (setq gname (nnmaildir--grp-get-name group))
+      (when (nnmaildir--param (nnmaildir--grp-get-pname group) 'read-only)
+        (nnmaildir--srv-set-error nnmaildir--cur-server
+                                  (concat "Read-only group: " gname))
+        (throw 'return nil))
+      (setq srv-dir (nnmaildir--srv-get-dir nnmaildir--cur-server)
+            dir (nnmaildir--srv-grp-dir srv-dir gname)
+            file (format-time-string "%s" nil))
+      (if (string= nnmaildir--delivery-time file) nil
+        (setq nnmaildir--delivery-time file
+              nnmaildir--delivery-ct 0))
+      (setq file (concat file "." nnmaildir--delivery-pid))
+      (if (zerop nnmaildir--delivery-ct) nil
+        (setq file (concat file "_"
+                           (number-to-string nnmaildir--delivery-ct))))
+      (setq file (concat file "." (system-name))
+            tmpfile (concat (nnmaildir--tmp dir) file)
+            curfile (concat (nnmaildir--cur dir) file ":2,"))
+      (when (file-exists-p tmpfile)
+        (nnmaildir--srv-set-error nnmaildir--cur-server
+                                  (concat "File exists: " tmpfile))
+        (throw 'return nil))
+      (when (file-exists-p curfile)
+        (nnmaildir--srv-set-error nnmaildir--cur-server
+                                  (concat "File exists: " curfile))
+        (throw 'return nil))
+      (setq nnmaildir--delivery-ct (1+ nnmaildir--delivery-ct)
+            24h (run-with-timer 86400 nil
+                                (lambda ()
+                                  (nnmaildir--unlink tmpfile)
+                                  (nnmaildir--srv-set-error
+                                    nnmaildir--cur-server
+                                    "24-hour timer expired")
+                                  (throw 'return nil))))
+      (condition-case nil
+          (add-name-to-file nnmaildir--file tmpfile)
+        (error
+         (write-region (point-min) (point-max) tmpfile nil 'no-message nil
+                       'confirm-overwrite) ;; error would be preferred :(
+         (unix-sync))) ;; no fsync :(
+      (cancel-timer 24h)
+      (condition-case err
+          (add-name-to-file tmpfile curfile)
+        (error
+         (nnmaildir--srv-set-error nnmaildir--cur-server
+                                   (concat "Error linking: "
+                                           (prin1-to-string err)))
+         (nnmaildir--unlink tmpfile)
+         (throw 'return nil)))
+      (nnmaildir--unlink tmpfile)
+      (setq article (nnmaildir--art-new)
+            num (nnmaildir--grp-get-lists group)
+            num (nnmaildir--lists-get-nlist num)
+            num (1+ (nnmaildir--nlist-last-num num)))
+      (nnmaildir--art-set-prefix article file)
+      (nnmaildir--art-set-suffix article ":2,")
+      (nnmaildir--art-set-num article num)
+      (if (nnmaildir--grp-add-art srv-dir group article) (cons gname num)))))
+
+(defun nnmaildir-save-mail (group-art)
+  (catch 'return
+    (if group-art nil
+      (throw 'return nil))
+    (let ((group-art group-art)
+          x nnmaildir--file deactivate-mark)
+      (save-excursion
+        (goto-char (point-min))
+        (save-match-data
+          (while (looking-at "From ")
+            (replace-match "X-From-Line: ")
+            (forward-line 1))))
+      (setq x (caar group-art) group-art (cdr group-art))
+      (if (nnmaildir-request-accept-article x) nil
+        (throw 'return nil)) ; not that nnmail bothers to check
+      (setq x (nnmaildir--prepare nil x)
+            nnmaildir--file (nnmaildir--srv-get-dir nnmaildir--cur-server)
+            nnmaildir--file (concat nnmaildir--file
+                                    (nnmaildir--grp-get-name x))
+            nnmaildir--file (file-name-as-directory nnmaildir--file)
+            x (nnmaildir--grp-get-lists x)
+            x (nnmaildir--lists-get-nlist x)
+            x (car x)
+            nnmaildir--file (concat nnmaildir--file
+                                    (nnmaildir--art-get-prefix x)
+                                    (nnmaildir--art-get-suffix x)))
+      (while group-art
+        (setq x (caar group-art) group-art (cdr group-art))
+        (if (nnmaildir-request-accept-article x) nil
+          (throw 'return nil))))
+    group-art))
+
+(defun nnmaildir-active-number (group)
+  (let ((x (nnmaildir--prepare nil group)))
+    (catch 'return
+      (if x nil
+        (nnmaildir--srv-set-error nnmaildir--cur-server
+                                  (concat "No such group: " group))
+        (throw 'return nil))
+      (setq x (nnmaildir--grp-get-lists x)
+            x (nnmaildir--lists-get-nlist x))
+      (if x
+          (setq x (car x)
+                x (nnmaildir--art-get-num x)
+                x (1+ x))
+        1))))
+
+(defun nnmaildir-request-expire-articles (ranges &optional gname server force)
+  (let ((no-force (not force))
+        (group (nnmaildir--prepare server gname))
+        pgname time boundary time-iter bound-iter high low target dir nlist
+        stop num article didnt suffix nnmaildir--file deactivate-mark)
+    (catch 'return
+      (if group nil
+        (nnmaildir--srv-set-error nnmaildir--cur-server
+                                  (if gname (concat "No such group: " gname)
+                                    "No current group"))
+        (throw 'return (gnus-uncompress-range ranges)))
+      (setq gname (nnmaildir--grp-get-name group)
+            pgname (nnmaildir--grp-get-pname group))
+      (if (nnmaildir--param pgname 'read-only)
+          (throw 'return (gnus-uncompress-range ranges)))
+      (setq time (or (nnmaildir--param pgname 'expire-age) 604800))
+      (if (or force (integerp time)) nil
+        (throw 'return (gnus-uncompress-range ranges)))
+      (setq boundary (current-time)
+            high (- (car boundary) (/ time 65536))
+            low (- (cadr boundary) (% time 65536)))
+      (if (< low 0)
+          (setq low (+ low 65536)
+                high (1- high)))
+      (setcar (cdr boundary) low)
+      (setcar boundary high)
+      (setq target (nnmaildir--param pgname 'expire-group)
+            target (and (stringp target)
+                        (not (string-equal target pgname))
+                        target)
+            dir (nnmaildir--srv-get-dir nnmaildir--cur-server)
+            dir (nnmaildir--srv-grp-dir dir gname)
+            dir (nnmaildir--cur dir)
+            nlist (nnmaildir--grp-get-lists group)
+            nlist (nnmaildir--lists-get-nlist nlist)
+            ranges (reverse ranges))
+      (save-excursion
+        (set-buffer (get-buffer-create " *nnmaildir move*"))
+        (while ranges
+          (setq num (car ranges) ranges (cdr ranges))
+          (while (eq num (car ranges))
+            (setq ranges (cdr ranges)))
+          (if (numberp num) (setq stop num)
+            (setq stop (car num) num (cdr num)))
+          (setq nlist (nthcdr (- (nnmaildir--art-get-num (car nlist)) num)
+                              nlist))
+          (while (and nlist
+                      (setq article (car nlist)
+                            num (nnmaildir--art-get-num article))
+                      (>= num stop))
+            (setq nlist (cdr nlist)
+                  suffix (nnmaildir--art-get-suffix article))
+            (catch 'continue
+              (if (stringp suffix) nil
+                (nnmaildir--art-set-suffix article 'expire)
+                (nnmaildir--art-set-nov article nil)
+                (throw 'continue nil))
+              (setq nnmaildir--file (nnmaildir--art-get-prefix article)
+                    nnmaildir--file (concat dir nnmaildir--file suffix)
+                    time (file-attributes nnmaildir--file))
+              (if time nil
+                (nnmaildir--art-set-suffix article 'expire)
+                (nnmaildir--art-set-nov article nil)
+                (throw 'continue nil))
+              (setq time (nth 5 time)
+                    time-iter time
+                    bound-iter boundary)
+              (if (and no-force
+                       (progn
+                         (while (and bound-iter time-iter
+                                     (= (car bound-iter) (car time-iter)))
+                           (setq bound-iter (cdr bound-iter)
+                                 time-iter (cdr time-iter)))
+                         (and bound-iter time-iter
+                              (car-less-than-car bound-iter time-iter))))
+                  (setq didnt (cons (nnmaildir--art-get-num article) didnt))
+                (when target
+                  (erase-buffer)
+                  (nnheader-insert-file-contents nnmaildir--file)
+                  (gnus-request-accept-article target nil nil 'no-encode))
+                (nnmaildir--unlink nnmaildir--file)
+                (nnmaildir--art-set-suffix article 'expire)
+                (nnmaildir--art-set-nov article nil)))))
+        (erase-buffer))
+      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 add-marks marksdir markfile action group-nlist nlist ranges
+        begin end article all-marks todo-marks did-marks marks form mdir mfile
+        deactivate-mark)
+    (setq del-mark
+          (lambda ()
+            (setq mfile (car marks)
+                  mfile (symbol-name mfile)
+                  mfile (concat marksdir mfile)
+                  mfile (file-name-as-directory mfile)
+                  mfile (concat mfile (nnmaildir--art-get-prefix article)))
+            (nnmaildir--unlink mfile))
+          add-marks
+          (lambda ()
+            (while marks
+              (setq mdir (concat marksdir (symbol-name (car marks)))
+                    mfile (concat (file-name-as-directory mdir)
+                                  (nnmaildir--art-get-prefix article)))
+              (if (memq (car marks) did-marks) nil
+                (nnmaildir--mkdir mdir)
+                (setq did-marks (cons (car marks) did-marks)))
+              (if (file-exists-p mfile) nil
+                (condition-case nil
+                    (add-name-to-file markfile mfile)
+                  (file-error ;; too many links, probably
+                   (if (file-exists-p mfile) nil
+                     (nnmaildir--unlink markfile)
+                     (write-region "" nil markfile nil 'no-message)
+                     (add-name-to-file markfile mfile
+                                       'ok-if-already-exists)))))
+              (setq marks (cdr marks)))))
+    (catch 'return
+      (if group nil
+        (nnmaildir--srv-set-error nnmaildir--cur-server
+                                  (concat "No such group: " gname))
+        (while actions
+          (setq ranges (gnus-range-add ranges (caar actions))
+                actions (cdr actions)))
+        (throw 'return ranges))
+      (setq group-nlist (nnmaildir--grp-get-lists group)
+            group-nlist (nnmaildir--lists-get-nlist group-nlist)
+            marksdir (nnmaildir--srv-get-dir nnmaildir--cur-server)
+            marksdir (nnmaildir--srv-grp-dir marksdir gname)
+            marksdir (nnmaildir--nndir marksdir)
+            markfile (concat marksdir "markfile")
+            marksdir (concat marksdir "marks")
+            marksdir (file-name-as-directory marksdir)
+            gname (nnmaildir--grp-get-name group)
+            all-marks (nnmaildir--grp-get-pname group)
+            all-marks (or (nnmaildir--param all-marks 'directory-files)
+                          (nnmaildir--srv-get-ls nnmaildir--cur-server))
+            all-marks (funcall all-marks marksdir nil "\\`[^.]" 'nosort)
+            marks all-marks)
+      (while marks
+        (setcar marks (intern (car marks)))
+        (setq marks (cdr marks)))
+      (while actions
+        (setq action (car actions) actions (cdr actions)
+              nlist group-nlist
+              ranges (car action)
+              todo-marks (caddr action)
+              marks todo-marks)
+        (while marks
+          (if (memq (car marks) all-marks) nil
+            (setq all-marks (cons (car marks) all-marks)))
+          (setq marks (cdr marks)))
+        (setq form
+              (cond
+               ((eq 'del (cadr action))
+                '(while marks
+                   (funcall del-mark)
+                   (setq marks (cdr marks))))
+               ((eq 'add (cadr action)) '(funcall add-marks))
+               (t
+                '(progn
+                   (funcall add-marks)
+                   (setq marks all-marks)
+                   (while marks
+                     (if (memq (car marks) todo-marks) nil
+                       (funcall del-mark))
+                     (setq marks (cdr marks)))))))
+        (if (numberp (cdr ranges)) (setq ranges (list ranges))
+          (setq ranges (reverse ranges)))
+        (while ranges
+          (setq begin (car ranges) ranges (cdr ranges))
+          (while (eq begin (car ranges))
+            (setq ranges (cdr ranges)))
+          (if (numberp begin) (setq end begin)
+            (setq end (cdr begin) begin (car begin)))
+          (setq nlist (nthcdr (- (nnmaildir--art-get-num (car nlist)) end)
+                              nlist))
+          (while (and nlist
+                      (setq article (car nlist))
+                      (>= (nnmaildir--art-get-num article) begin))
+            (setq nlist (cdr nlist))
+            (when (stringp (nnmaildir--art-get-suffix article))
+              (setq marks todo-marks)
+              (eval form)))))
+      nil)))
+
+(defun nnmaildir-close-group (group &optional server)
+  t)
+
+(defun nnmaildir-close-server (&optional server)
+  (let (srv-ls flist ls dirs dir files file x)
+    (nnmaildir--prepare server nil)
+    (setq server nnmaildir--cur-server)
+    (when server
+      (setq nnmaildir--cur-server nil
+            srv-ls (nnmaildir--srv-get-ls server))
+      (save-match-data
+        (mapatoms
+          (lambda (group)
+            (setq group (symbol-value group)
+                  x (nnmaildir--grp-get-pname group)
+                  ls (nnmaildir--param x 'directory-files)
+                  ls (or ls srv-ls)
+                  dir (nnmaildir--srv-get-dir server)
+                  dir (nnmaildir--srv-grp-dir
+                        dir (nnmaildir--grp-get-name group))
+                  x (nnmaildir--param x 'read-only)
+                  x (if x (nnmaildir--new dir) (nnmaildir--cur dir))
+                  files (funcall ls x nil "\\`[^.]" 'nosort)
+                  x (length files)
+                  flist 1)
+            (while (<= flist x) (setq flist (* 2 flist)))
+            (if (/= flist 1) (setq flist (1- flist)))
+            (setq flist (make-vector flist 0))
+            (while files
+              (setq file (car files) files (cdr files))
+              (string-match "\\`\\([^:]*\\)\\(:.*\\)?\\'" file)
+              (intern (match-string 1 file) flist))
+            (setq dir (nnmaildir--nndir dir)
+                  dirs (cons (concat dir "nov")
+                             (funcall ls (concat dir "marks") 'full "\\`[^.]"
+                                      'nosort)))
+            (while dirs
+              (setq dir (car dirs) dirs (cdr dirs)
+                    files (funcall ls dir nil "\\`[^.]" 'nosort)
+                    dir (file-name-as-directory dir))
+              (while files
+                (setq file (car files) files (cdr files))
+                (if (intern-soft file flist) nil
+                  (setq file (concat dir file))
+                  (delete-file file)))))
+          (nnmaildir--srv-get-groups server)))
+      (unintern (nnmaildir--srv-get-name server) nnmaildir--servers)))
+  t)
+
+(defun nnmaildir-request-close ()
+  (let (servers buffer)
+    (mapatoms (lambda (server)
+                (setq servers (cons (symbol-name server) servers)))
+              nnmaildir--servers)
+    (while servers
+      (nnmaildir-close-server (car servers))
+      (setq servers (cdr servers)))
+    (setq buffer (get-buffer " *nnmaildir work*"))
+    (if buffer (kill-buffer buffer))
+    (setq buffer (get-buffer " *nnmaildir nov*"))
+    (if buffer (kill-buffer buffer))
+    (setq buffer (get-buffer " *nnmaildir move*"))
+    (if buffer (kill-buffer buffer)))
+  t)
+
+(provide 'nnmaildir)
+
+;;; nnmaildir.el ends here