diff lisp/nndoc.el @ 15511:530d0d516a42

New version.
author Lars Magne Ingebrigtsen <larsi@gnus.org>
date Tue, 25 Jun 1996 22:21:39 +0000
parents 83f275dcd93a
children b131fbcf8530
line wrap: on
line diff
--- a/lisp/nndoc.el	Tue Jun 25 18:19:09 1996 +0000
+++ b/lisp/nndoc.el	Tue Jun 25 22:21:39 1996 +0000
@@ -1,6 +1,5 @@
 ;;; nndoc.el --- single file access for Gnus
-
-;; Copyright (C) 1995 Free Software Foundation, Inc.
+;; Copyright (C) 1995,96 Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@ifi.uio.no>
 ;; 	Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
@@ -28,239 +27,203 @@
 ;;; Code:
 
 (require 'nnheader)
-(require 'rmail)
+(require 'message)
 (require 'nnmail)
+(require 'nnoo)
+(eval-when-compile (require 'cl))
 
-(defvar nndoc-article-type 'mbox
-  "*Type of the file - one of `mbox', `babyl' or `digest'.")
+(nnoo-declare nndoc)
 
-(defvar nndoc-digest-type 'traditional
-  "Type of the last digest.  Auto-detected from the article header.
-Possible values:
-  `traditional' -- the \"lots of dashes\" (30+) rules used;
-                   we currently also do unconditional RFC 934 unquoting.
-  `rfc1341' -- RFC 1341 digest (MIME, unique boundary, no quoting).")
+(defvoo nndoc-article-type 'guess
+  "*Type of the file.
+One of `mbox', `babyl', `digest', `news', `rnews', `mmdf', `forward',
+`mime-digest', `standard-digest', `slack-digest', `clari-briefs' or
+`guess'.")
+
+(defvoo nndoc-post-type 'mail
+  "*Whether the nndoc group is `mail' or `post'.")
 
-(defconst nndoc-type-to-regexp
-  (list (list 'mbox 
-	      (concat "^" rmail-unix-mail-delimiter)
-	      (concat "^" rmail-unix-mail-delimiter)
-	      nil "^$" nil nil nil)
-	(list 'babyl "\^_\^L *\n" "\^_" "^[0-9].*\n" "^$" nil nil
-	      "\\*\\*\\* EOOH \\*\\*\\*\n\\(^.+\n\\)*")
-	(list 'digest
-	      "^------------------------------*[\n \t]+"
-	      "^------------------------------*[\n \t]+"
-	      nil "^ ?$"   
-	      "^------------------------------*[\n \t]+"
-	      "^End of" nil))
-  "Regular expressions for articles of the various types.")
+(defvar nndoc-type-alist 
+  `((mmdf 
+     (article-begin .  "^\^A\^A\^A\^A\n")
+     (body-end .  "^\^A\^A\^A\^A\n"))
+    (news
+     (article-begin . "^Path:"))
+    (rnews
+     (article-begin . "^#! *rnews +\\([0-9]+\\) *\n")
+     (body-end-function . nndoc-rnews-body-end))
+    (mbox 
+     (article-begin . 
+		    ,(let ((delim (concat "^" message-unix-mail-delimiter)))
+		       (if (string-match "\n\\'" delim)
+			   (substring delim 0 (match-beginning 0))
+			 delim)))
+     (body-end-function . nndoc-mbox-body-end))
+    (babyl 
+     (article-begin . "\^_\^L *\n")
+     (body-end . "\^_")
+     (body-begin-function . nndoc-babyl-body-begin)
+     (head-begin-function . nndoc-babyl-head-begin))
+    (forward
+     (article-begin . "^-+ Start of forwarded message -+\n+")
+     (body-end . "^-+ End of forwarded message -+$")
+     (prepare-body . nndoc-unquote-dashes))
+    (clari-briefs
+     (article-begin . "^ \\*")
+     (body-end . "^\t------*[ \t]^*\n^ \\*")
+     (body-begin . "^\t")
+     (head-end . "^\t")
+     (generate-head . nndoc-generate-clari-briefs-head)
+     (article-transform . nndoc-transform-clari-briefs))
+    (slack-digest
+     (article-begin . "^------------------------------*[\n \t]+")
+     (head-end . "^ ?$")
+     (body-end-function . nndoc-digest-body-end)
+     (body-begin . "^ ?$")
+     (file-end . "^End of")
+     (prepare-body . nndoc-unquote-dashes))
+    (mime-digest
+     (article-begin . "")
+     (head-end . "^ ?$")
+     (body-end . "")
+     (file-end . ""))
+    (standard-digest
+     (first-article . ,(concat "^" (make-string 70 ?-) "\n\n+"))
+     (article-begin . ,(concat "\n\n" (make-string 30 ?-) "\n\n+"))
+     (prepare-body . nndoc-unquote-dashes)
+     (body-end-function . nndoc-digest-body-end)
+     (head-end . "^ ?$")
+     (body-begin . "^ ?\n")
+     (file-end . "^End of .*digest.*[0-9].*\n\\*\\*\\|^End of.*Digest *$"))
+    (guess 
+     (guess . nndoc-guess-type))
+    (digest
+     (guess . nndoc-guess-digest-type))
+    ))
 
 
 
-(defvar nndoc-article-begin nil)
-(defvar nndoc-article-end nil)
-(defvar nndoc-head-begin nil)
-(defvar nndoc-head-end nil)
-(defvar nndoc-first-article nil)
-(defvar nndoc-end-of-file nil)
-(defvar nndoc-body-begin nil)
+(defvoo nndoc-file-begin nil)
+(defvoo nndoc-first-article nil)
+(defvoo nndoc-article-end nil)
+(defvoo nndoc-article-begin nil)
+(defvoo nndoc-head-begin nil)
+(defvoo nndoc-head-end nil)
+(defvoo nndoc-file-end nil)
+(defvoo nndoc-body-begin nil)
+(defvoo nndoc-body-end-function nil)
+(defvoo nndoc-body-begin-function nil)
+(defvoo nndoc-head-begin-function nil)
+(defvoo nndoc-body-end nil)
+(defvoo nndoc-dissection-alist nil)
+(defvoo nndoc-prepare-body nil)
+(defvoo nndoc-generate-head nil)
+(defvoo nndoc-article-transform nil)
 
-(defvar nndoc-current-server nil)
-(defvar nndoc-server-alist nil)
-(defvar nndoc-server-variables
-  (list
-   (list 'nndoc-article-type nndoc-article-type)
-   '(nndoc-article-begin nil)
-   '(nndoc-article-end nil)
-   '(nndoc-head-begin nil)
-   '(nndoc-head-end nil)
-   '(nndoc-first-article nil)
-   '(nndoc-current-buffer nil)
-   '(nndoc-group-alist nil)
-   '(nndoc-end-of-file nil)
-   '(nndoc-body-begin nil)
-   '(nndoc-address nil)))
+(defvoo nndoc-status-string "")
+(defvoo nndoc-group-alist nil)
+(defvoo nndoc-current-buffer nil
+  "Current nndoc news buffer.")
+(defvoo nndoc-address nil)
 
 (defconst nndoc-version "nndoc 1.0"
   "nndoc version.")
 
-(defvar nndoc-current-buffer nil
-  "Current nndoc news buffer.")
-
-(defvar nndoc-address nil)
-
 
 
-(defvar nndoc-status-string "")
-
-(defvar nndoc-group-alist nil)
-
 ;;; Interface functions
 
-(defun nndoc-retrieve-headers (sequence &optional newsgroup server)
-  (save-excursion
-    (set-buffer nntp-server-buffer)
-    (erase-buffer)
-    (let ((prev 2)
-	  article p beg lines)
-      (nndoc-possibly-change-buffer newsgroup server)
-      (if (stringp (car sequence))
-	  'headers
-	(set-buffer nndoc-current-buffer)
-	(widen)
-	(goto-char (point-min))
-	(re-search-forward (or nndoc-first-article 
-			       nndoc-article-begin) nil t)
-	(or (not nndoc-head-begin)
-	    (re-search-forward nndoc-head-begin nil t))
-	(re-search-forward nndoc-head-end nil t)
-	(while sequence
-	  (setq article (car sequence))
-	  (set-buffer nndoc-current-buffer)
-	  (if (not (nndoc-forward-article (max 0 (- article prev))))
-	      ()
-	    (setq p (point))
-	    (setq beg (or (and
-			   (re-search-backward nndoc-article-begin nil t)
-			   (match-end 0))
-			  (point-min)))
-	    (goto-char p)
-	    (setq lines (count-lines 
-			 (point)
-			 (or
-			  (and (re-search-forward nndoc-article-end nil t)
-			       (goto-char (match-beginning 0)))
-			  (goto-char (point-max)))))
-
-	    (set-buffer nntp-server-buffer)
-	    (insert (format "221 %d Article retrieved.\n" article))
-	    (insert-buffer-substring nndoc-current-buffer beg p)
-	    (goto-char (point-max))
-	    (or (= (char-after (1- (point))) ?\n) (insert "\n"))
-	    (insert (format "Lines: %d\n" lines))
-	    (insert ".\n"))
-
-	  (setq prev article
-		sequence (cdr sequence)))
+(nnoo-define-basics nndoc)
 
-	;; Fold continuation lines.
-	(set-buffer nntp-server-buffer)
-	(goto-char (point-min))
-	(while (re-search-forward "\\(\r?\n[ \t]+\\)+" nil t)
-	  (replace-match " " t t))
-	'headers))))
+(deffoo nndoc-retrieve-headers (articles &optional newsgroup server fetch-old)
+  (when (nndoc-possibly-change-buffer newsgroup server)
+    (save-excursion
+      (set-buffer nntp-server-buffer)
+      (erase-buffer)
+      (let (article entry)
+	(if (stringp (car articles))
+	    'headers
+	  (while articles
+	    (when (setq entry (cdr (assq (setq article (pop articles))
+					 nndoc-dissection-alist)))
+	      (insert (format "221 %d Article retrieved.\n" article))
+	      (if nndoc-generate-head
+		  (funcall nndoc-generate-head article)
+		(insert-buffer-substring
+		 nndoc-current-buffer (car entry) (nth 1 entry)))
+	      (goto-char (point-max))
+	      (or (= (char-after (1- (point))) ?\n) (insert "\n"))
+	      (insert (format "Lines: %d\n" (nth 4 entry)))
+	      (insert ".\n")))
 
-(defun nndoc-open-server (server &optional defs)
-  (nnheader-init-server-buffer)
-  (if (equal server nndoc-current-server)
-      t
-    (if nndoc-current-server
-	(setq nndoc-server-alist 
-	      (cons (list nndoc-current-server
-			  (nnheader-save-variables nndoc-server-variables))
-		    nndoc-server-alist)))
-    (let ((state (assoc server nndoc-server-alist)))
-      (if state 
-	  (progn
-	    (nnheader-restore-variables (nth 1 state))
-	    (setq nndoc-server-alist (delq state nndoc-server-alist)))
-	(nnheader-set-init-variables nndoc-server-variables defs)))
-    (setq nndoc-current-server server)
-    (let ((defs (cdr (assq nndoc-article-type nndoc-type-to-regexp))))
-      (setq nndoc-article-begin (nth 0 defs))
-      (setq nndoc-article-end (nth 1 defs))
-      (setq nndoc-head-begin (nth 2 defs))
-      (setq nndoc-head-end (nth 3 defs))
-      (setq nndoc-first-article (nth 4 defs))
-      (setq nndoc-end-of-file (nth 5 defs))
-      (setq nndoc-body-begin (nth 6 defs)))
-    t))
+	  (nnheader-fold-continuation-lines)
+	  'headers)))))
 
-(defun nndoc-close-server (&optional server)
-  t)
-
-(defun nndoc-server-opened (&optional server)
-  (and (equal server nndoc-current-server)
-       nntp-server-buffer
-       (buffer-name nntp-server-buffer)))
-
-(defun nndoc-status-message (&optional server)
-  nndoc-status-string)
-
-(defun nndoc-request-article (article &optional newsgroup server buffer)
+(deffoo nndoc-request-article (article &optional newsgroup server buffer)
   (nndoc-possibly-change-buffer newsgroup server)
   (save-excursion
-    (let ((buffer (or buffer nntp-server-buffer)))
+    (let ((buffer (or buffer nntp-server-buffer))
+	  (entry (cdr (assq article nndoc-dissection-alist)))
+	  beg)
       (set-buffer buffer)
       (erase-buffer)
       (if (stringp article)
 	  nil
-	(nndoc-insert-article article)
-	;; Unquote quoted non-separators in digests.
-	(if (and (eq nndoc-article-type 'digest)
-		 (eq nndoc-digest-type 'traditional))
-	    (progn
-	      (goto-char (point-min))
-	      (while (re-search-forward "^- -"nil t)
-		(replace-match "-" t t))))
-	;; Some assholish digests do not have a blank line after the
-	;; headers. Aargh!
-	(goto-char (point-min))
-	(if (search-forward "\n\n" nil t)
-	    ()				; We let this one pass.
-	  (if (re-search-forward "^[ \t]+$" nil t)
-	      (replace-match "" t t)	; We nix out a line of blanks.
-	    (while (and (looking-at "[^ ]+:")
-			(zerop (forward-line 1))))
-	    ;; We just insert a couple of lines. If you read digests
-	    ;; that are so badly formatted, you don't deserve any
-	    ;; better. Blphphpht!
-	    (insert "\n\n")))
+	(insert-buffer-substring 
+	 nndoc-current-buffer (car entry) (nth 1 entry))
+	(insert "\n")
+	(setq beg (point))
+	(insert-buffer-substring 
+	 nndoc-current-buffer (nth 2 entry) (nth 3 entry))
+	(goto-char beg)
+	(when nndoc-prepare-body
+	  (funcall nndoc-prepare-body))
+	(when nndoc-article-transform
+	  (funcall nndoc-article-transform article))
 	t))))
 
-(defun nndoc-request-group (group &optional server dont-check)
+(deffoo nndoc-request-group (group &optional server dont-check)
   "Select news GROUP."
-  (save-excursion
-    (if (not (nndoc-possibly-change-buffer group server))
-	(progn
-	  (setq nndoc-status-string "No such file or buffer")
-	  nil)
-      (nndoc-set-header-dependent-regexps) ; hack for MIME digests
-      (if dont-check
-	  t
-	(save-excursion
-	  (set-buffer nntp-server-buffer)
-	  (erase-buffer)
-	  (let ((number (nndoc-number-of-articles)))
-	    (if (zerop number)
-		(progn
-		  (nndoc-close-group group)
-		  nil)
-	      (insert (format "211 %d %d %d %s\n" number 1 number group))
-	      t)))))))
+  (let (number)
+    (cond 
+     ((not (nndoc-possibly-change-buffer group server))
+      (nnheader-report 'nndoc "No such file or buffer: %s"
+		       nndoc-address))
+     (dont-check
+      (nnheader-report 'nndoc "Selected group %s" group)
+      t)
+     ((zerop (setq number (length nndoc-dissection-alist)))
+      (nndoc-close-group group)
+      (nnheader-report 'nndoc "No articles in group %s" group))
+     (t
+      (nnheader-insert "211 %d %d %d %s\n" number 1 number group)))))
 
-(defun nndoc-close-group (group &optional server)
+(deffoo nndoc-request-type (group &optional article)
+  (cond ((not article) 'unknown)
+        (nndoc-post-type nndoc-post-type)
+        (t 'unknown)))
+
+(deffoo nndoc-close-group (group &optional server)
   (nndoc-possibly-change-buffer group server)
-  (kill-buffer nndoc-current-buffer)
+  (and nndoc-current-buffer
+       (buffer-name nndoc-current-buffer)
+       (kill-buffer nndoc-current-buffer))
   (setq nndoc-group-alist (delq (assoc group nndoc-group-alist)
 				nndoc-group-alist))
   (setq nndoc-current-buffer nil)
-  (setq nndoc-current-server nil)
+  (nnoo-close-server 'nndoc server)
+  (setq nndoc-dissection-alist nil)
   t)
 
-(defun nndoc-request-list (&optional server)
+(deffoo nndoc-request-list (&optional server)
   nil)
 
-(defun nndoc-request-newgroups (date &optional server)
+(deffoo nndoc-request-newgroups (date &optional server)
   nil)
 
-(defun nndoc-request-list-newsgroups (&optional server)
+(deffoo nndoc-request-list-newsgroups (&optional server)
   nil)
 
-(defalias 'nndoc-request-post 'nnmail-request-post)
-(defalias 'nndoc-request-post-buffer 'nnmail-request-post-buffer)
-
 
 ;;; Internal functions.
 
@@ -269,6 +232,7 @@
     (cond 
      ;; The current buffer is this group's buffer.
      ((and nndoc-current-buffer
+	   (buffer-name nndoc-current-buffer)
 	   (eq nndoc-current-buffer 
 	       (setq buf (cdr (assoc group nndoc-group-alist))))))
      ;; We change buffers by taking an old from the group alist.
@@ -281,121 +245,231 @@
 	  (and (stringp nndoc-address)
 	       (file-exists-p nndoc-address)
 	       (not (file-directory-p nndoc-address))))
-      (setq nndoc-group-alist 
-	    (cons (cons group (setq nndoc-current-buffer 
-				    (get-buffer-create 
-				     (concat " *nndoc " group "*"))))
-		  nndoc-group-alist))
+      (push (cons group (setq nndoc-current-buffer 
+			      (get-buffer-create 
+			       (concat " *nndoc " group "*"))))
+	    nndoc-group-alist)
+      (setq nndoc-dissection-alist nil)
       (save-excursion
 	(set-buffer nndoc-current-buffer)
 	(buffer-disable-undo (current-buffer))
 	(erase-buffer)
 	(if (stringp nndoc-address)
 	    (insert-file-contents nndoc-address)
-	  (save-excursion
-	    (set-buffer nndoc-address)
-	    (widen))
-	  (insert-buffer-substring nndoc-address))
-	t)))))
-
-;; MIME (RFC 1341) digest hack by Ulrik Dickow <dickow@nbi.dk>.
-(defun nndoc-set-header-dependent-regexps ()
-  (if (not (eq nndoc-article-type 'digest))
-      ()
-    (let ((case-fold-search t)		; We match a bit too much, keep it simple.
-	  (boundary-id) (b-delimiter))
+	  (insert-buffer-substring nndoc-address)))))
+    ;; Initialize the nndoc structures according to this new document.
+    (when (and nndoc-current-buffer
+	       (not nndoc-dissection-alist))
       (save-excursion
 	(set-buffer nndoc-current-buffer)
-	(goto-char (point-min))
-	(if (and
-	     (re-search-forward
-	      (concat "\n\n\\|^Content-Type: *multipart/digest;[ \t\n]*[ \t]"
-		      "boundary=\"\\([^\"\n]*[^\" \t\n]\\)\"")
-	      nil t)
-	     (match-beginning 1))
-	    (setq nndoc-digest-type 'rfc1341
-		  boundary-id (format "%s"
-				      (buffer-substring
-				       (match-beginning 1) (match-end 1)))
-		  b-delimiter       (concat "\n--" boundary-id "[\n \t]+")
-		  nndoc-article-begin b-delimiter ; Too strict: "[ \t]*$"
-		  nndoc-article-end (concat "\n--" boundary-id
-					    "\\(--\\)?[\n \t]+")
-		  nndoc-first-article b-delimiter ; ^eof ends article too.
-		  nndoc-end-of-file (concat "\n--" boundary-id "--[ \t]*$"))
-	  (setq nndoc-digest-type 'traditional))))))
+	(nndoc-set-delims)
+	(nndoc-dissect-buffer)))
+    (unless nndoc-current-buffer
+      (nndoc-close-server))
+    ;; Return whether we managed to select a file.
+    nndoc-current-buffer))
 
-(defun nndoc-forward-article (n)
-  (while (and (> n 0)
-	      (re-search-forward nndoc-article-begin nil t)
-	      (or (not nndoc-head-begin)
-		  (re-search-forward nndoc-head-begin nil t))
-	      (re-search-forward nndoc-head-end nil t))
-    (setq n (1- n)))
-  (zerop n))
-
-(defun nndoc-number-of-articles ()
-  (save-excursion
-    (set-buffer nndoc-current-buffer)
-    (widen)
+;; MIME (RFC 1341) digest hack by Ulrik Dickow <dickow@nbi.dk>.
+(defun nndoc-guess-digest-type ()
+  "Guess what digest type the current document is."
+  (let ((case-fold-search t)		; We match a bit too much, keep it simple.
+	boundary-id b-delimiter entry)
     (goto-char (point-min))
-    (let ((num 0))
-      (if (re-search-forward (or nndoc-first-article
-				 nndoc-article-begin) nil t)
-	  (progn
-	    (setq num 1)
-	    (while (and (re-search-forward nndoc-article-begin nil t)
-			(or (not nndoc-end-of-file)
-			    (not (looking-at nndoc-end-of-file)))
-			(or (not nndoc-head-begin)
-			    (re-search-forward nndoc-head-begin nil t))
-			(re-search-forward nndoc-head-end nil t))
-	      (setq num (1+ num)))))
-      num)))
+    (cond 
+     ;; MIME digest.
+     ((and
+       (re-search-forward
+	(concat "^Content-Type: *multipart/digest;[ \t\n]*[ \t]"
+		"boundary=\"\\([^\"\n]*[^\" \t\n]\\)\"")
+	nil t)
+       (match-beginning 1))
+      (setq boundary-id (match-string 1)
+	    b-delimiter (concat "\n--" boundary-id "[\n \t]+"))
+      (setq entry (assq 'mime-digest nndoc-type-alist))
+      (setcdr entry
+	      (list
+	       (cons 'head-end "^ ?$")
+	       (cons 'body-begin "^ ?\n")
+	       (cons 'article-begin b-delimiter)
+	       (cons 'body-end-function 'nndoc-digest-body-end)
+;	       (cons 'body-end 
+;		     (concat "\n--" boundary-id "\\(--\\)?[\n \t]+"))
+	       (cons 'file-end (concat "\n--" boundary-id "--[ \t]*$"))))
+      'mime-digest)
+     ;; Standard digest.
+     ((and (re-search-forward (concat "^" (make-string 70 ?-) "\n\n") nil t)
+	   (re-search-forward 
+	    (concat "\n\n" (make-string 30 ?-) "\n\n") nil t))
+      'standard-digest)
+     ;; Stupid digest.
+     (t
+      'slack-digest))))
 
-(defun nndoc-narrow-to-article (article)
-  (save-excursion
-    (set-buffer nndoc-current-buffer)
-    (widen)
-    (goto-char (point-min))
-    (while (and (re-search-forward nndoc-article-begin nil t)
-		(not (zerop (setq article (1- article))))))
-    (if (not (zerop article))
-	()
-      (narrow-to-region 
-       (match-end 0)
-       (or (and (re-search-forward nndoc-article-end nil t)
-		(match-beginning 0))
-	   (point-max)))
-      t)))
+(defun nndoc-guess-type ()
+  "Guess what document type is in the current buffer."
+  (goto-char (point-min))
+  (cond 
+   ((looking-at message-unix-mail-delimiter)
+    'mbox)
+   ((looking-at "\^A\^A\^A\^A$")
+    'mmdf)
+   ((looking-at "^Path:.*\n")
+    'news)
+   ((looking-at "#! *rnews")
+    'rnews)
+   ((re-search-forward "\^_\^L *\n" nil t)
+    'babyl)
+   ((save-excursion
+      (and (re-search-forward "^-+ Start of forwarded message -+\n+" nil t)
+	   (not (re-search-forward "^Subject:.*digest" nil t))))
+    'forward)
+   ((let ((case-fold-search nil))
+      (re-search-forward "^\t[^a-z]+ ([^a-z]+) --" nil t))
+    'clari-briefs)
+   (t 
+    'digest)))
 
-;; Insert article ARTICLE in the current buffer.
-(defun nndoc-insert-article (article)
-  (let ((ibuf (current-buffer)))
+(defun nndoc-set-delims ()
+  "Set the nndoc delimiter variables according to the type of the document."
+  (let ((vars '(nndoc-file-begin 
+		nndoc-first-article 
+		nndoc-article-end nndoc-head-begin nndoc-head-end
+		nndoc-file-end nndoc-article-begin
+		nndoc-body-begin nndoc-body-end-function nndoc-body-end
+		nndoc-prepare-body nndoc-article-transform
+		nndoc-generate-head nndoc-body-begin-function
+		nndoc-head-begin-function)))
+    (while vars
+      (set (pop vars) nil)))
+  (let* (defs guess)
+    ;; Guess away until we find the real file type.
+    (while (setq defs (cdr (assq nndoc-article-type nndoc-type-alist))
+		 guess (assq 'guess defs))
+      (setq nndoc-article-type (funcall (cdr guess))))
+    ;; Set the nndoc variables.
+    (while defs
+      (set (intern (format "nndoc-%s" (caar defs)))
+	   (cdr (pop defs))))))
+
+(defun nndoc-search (regexp)
+  (prog1
+      (re-search-forward regexp nil t)
+    (beginning-of-line)))
+
+(defun nndoc-dissect-buffer ()
+  "Go through the document and partition it into heads/bodies/articles."
+  (let ((i 0)
+	(first t)
+	head-begin head-end body-begin body-end)
+    (setq nndoc-dissection-alist nil)
     (save-excursion
       (set-buffer nndoc-current-buffer)
-      (widen)
       (goto-char (point-min))
-      (while (and (re-search-forward nndoc-article-begin nil t)
-		  (not (zerop (setq article (1- article))))))
-      (if (not (zerop article))
-	  ()
-	(narrow-to-region 
-	 (match-end 0)
-	 (or (and (re-search-forward nndoc-article-end nil t)
-		  (match-beginning 0))
-	     (point-max)))
+      ;; Find the beginning of the file.
+      (when nndoc-file-begin
+	(nndoc-search nndoc-file-begin))
+      ;; Go through the file.
+      (while (if (and first nndoc-first-article)
+		 (nndoc-search nndoc-first-article)
+	       (nndoc-search nndoc-article-begin))
+	(setq first nil)
+	(cond (nndoc-head-begin-function
+	       (funcall nndoc-head-begin-function))
+	      (nndoc-head-begin 
+	       (nndoc-search nndoc-head-begin)))
+ 	(if (and nndoc-file-end
+		 (looking-at nndoc-file-end))
+	    (goto-char (point-max))
+	  (setq head-begin (point))
+	  (nndoc-search (or nndoc-head-end "^$"))
+	  (setq head-end (point))
+	  (if nndoc-body-begin-function
+	      (funcall nndoc-body-begin-function)
+	    (nndoc-search (or nndoc-body-begin "^\n")))
+	  (setq body-begin (point))
+	  (or (and nndoc-body-end-function
+		   (funcall nndoc-body-end-function))
+	      (and nndoc-body-end
+		   (nndoc-search nndoc-body-end))
+	      (nndoc-search nndoc-article-begin)
+	      (progn
+		(goto-char (point-max))
+		(when nndoc-file-end
+		  (and (re-search-backward nndoc-file-end nil t)
+		       (beginning-of-line)))))
+	  (setq body-end (point))
+	  (push (list (incf i) head-begin head-end body-begin body-end
+		      (count-lines body-begin body-end))
+		nndoc-dissection-alist))))))
+
+(defun nndoc-unquote-dashes ()
+  "Unquote quoted non-separators in digests."
+  (while (re-search-forward "^- -"nil t)
+    (replace-match "-" t t)))
+
+(defun nndoc-digest-body-end ()
+  (and (re-search-forward nndoc-article-begin nil t)
+       (goto-char (match-beginning 0))))
+
+(defun nndoc-mbox-body-end ()
+  (let ((beg (point))
+	len end)
+    (when
+	(save-excursion
+	  (and (re-search-backward nndoc-article-begin nil t)
+	       (setq end (point))
+	       (search-forward "\n\n" beg t)
+	       (re-search-backward
+		"^Content-Length:[ \t]*\\([0-9]+\\) *$" end t)
+	       (setq len (string-to-int (match-string 1)))
+	       (search-forward "\n\n" beg t)
+	       (or (= (setq len (+ (point) len)) (point-max))
+		   (and (< len (point-max))
+			(goto-char len)
+			(looking-at nndoc-article-begin)))))
+      (goto-char len))))
+
+(defun nndoc-rnews-body-end ()
+  (and (re-search-backward nndoc-article-begin nil t)
+       (forward-line 1)
+       (goto-char (+ (point) (string-to-int (match-string 1))))))
+
+(defun nndoc-transform-clari-briefs (article)
+  (goto-char (point-min))
+  (when (looking-at " *\\*\\(.*\\)\n")
+    (replace-match "" t t))
+  (nndoc-generate-clari-briefs-head article))
+
+(defun nndoc-generate-clari-briefs-head (article)
+  (let ((entry (cdr (assq article nndoc-dissection-alist)))
+	subject from)
+    (save-excursion
+      (set-buffer nndoc-current-buffer)
+      (save-restriction
+	(narrow-to-region (car entry) (nth 3 entry))
 	(goto-char (point-min))
-	(and nndoc-head-begin
-	     (re-search-forward nndoc-head-begin nil t)
-	     (narrow-to-region (point) (point-max)))
-	(or (re-search-forward nndoc-head-end nil t)
-	    (goto-char (point-max)))
-	(append-to-buffer ibuf (point-min) (point))
-	(and nndoc-body-begin 
-	     (re-search-forward nndoc-body-begin nil t))
-	(append-to-buffer ibuf (point) (point-max))
-	t))))
+	(when (looking-at " *\\*\\(.*\\)$")
+	  (setq subject (match-string 1))
+	  (when (string-match "[ \t]+$" subject)
+	    (setq subject (substring subject 0 (match-beginning 0)))))
+	(when
+	    (let ((case-fold-search nil))
+	      (re-search-forward
+	       "^\t\\([^a-z]+\\(,[^(]+\\)? ([^a-z]+)\\) --" nil t))
+	  (setq from (match-string 1)))))
+    (insert "From: " "clari@clari.net (" (or from "unknown") ")"
+	    "\nSubject: " (or subject "(no subject)") "\n")))
+
+(defun nndoc-babyl-body-begin ()
+  (re-search-forward "^\n" nil t)
+  (when (looking-at "\*\*\* EOOH \*\*\*")
+    (re-search-forward "^\n" nil t)))
+
+(defun nndoc-babyl-head-begin ()
+  (when (re-search-forward "^[0-9].*\n" nil t)
+    (when (looking-at "\*\*\* EOOH \*\*\*")
+      (forward-line 1))
+    t))
 
 (provide 'nndoc)