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

nnimap 0.99 -> 0.100 patches



Index: nnimap/ChangeLog
diff -c nnimap/ChangeLog:1.199 nnimap/ChangeLog:1.202
*** nnimap/ChangeLog:1.199	Sun May  9 09:56:46 1999
--- nnimap/ChangeLog	Fri May 14 08:07:27 1999
***************
*** 1,3 ****
--- 1,52 ----
+ 1999-05-14  Simon Josefsson  <jas@pdc.kth.se>
+ 
+ 	* nnimap.el: 0.100 released.
+ 	
+ 	* nnimap.el (nnimap-group-list-speed): Removed.
+ 	(nnimap-replace-tabs):
+ 	(nnimap-remove-delimiter): New functions.
+ 	(nnimap-retrieve-headers-progress): Insert NOV line of fetched
+ 	article.
+ 	(nnimap-retrieve-headers): Rewrite, fetch attributes suitable for
+ 	NOV lines.
+ 	(nnimap-request-list): Rewrite.
+ 	(nnimap-split-articles): Don't delete articles destined for the
+ 	inbox.
+ 	(nnimap-destructive-plist-to-alist): Removed.
+ 	(nnimap-request-list-mapper): Fast/medium methods removed.
+ 
+ 	* imap.el (imap-forward): New function.
+ 	(imap-parse-*): Use it.
+ 	(imap-parse-fetch): Handle complex BODY fetches.
+ 
+ 	* nnimap.texi (split-rule): Empty regexp not needed.
+ 
+ 1999-05-13  Simon Josefsson  <jas@pdc.kth.se>
+ 
+ 	* imap.el (imap-mailbox-expunge): New function.
+ 	(imap-message-fetch): New argument nouidfetch.
+ 
+ 	* nnimap.el (gnus-group-nnimap-expunge): Use it.
+ 
+ 	* nnimap.el (nnimap-replace-tabs): New function.
+ 	(nnimap-retrieve-headers-progress): Insert nov line of message.
+ 	(nnimap-retrieve-headers): Rewrite.
+ 
+ 	* imap.el (imap-body-lines): New function, moved from
+ 	nnimap-body-lines.
+ 	(imap-envelope-from): New function.
+ 	(imap-parse-astring): Don't use read.
+ 	(imap-parse-response): Signal error when receiving BAD.
+ 
+ 	* nnimap.el (nnimap-demule): Don't check string.
+ 	(nnimap-request-article-part): Protect null strings early.
+ 
+ 	* nnimap.texi: Update.
+ 
+ 1999-05-09  Simon Josefsson  <jas@pdc.kth.se>
+ 
+ 	* imap.el (imap-parse-mailbox): No need to check symbolp.
+ 
  1999-05-09  Simon Josefsson  <jas@pdc.kth.se>
  
  	* nnimap 0.99 released.
Index: nnimap/imap.el
diff -c nnimap/imap.el:1.127 nnimap/imap.el:1.130
*** nnimap/imap.el:1.127	Sun May  9 09:53:36 1999
--- nnimap/imap.el	Fri May 14 07:53:21 1999
***************
*** 717,722 ****
--- 717,728 ----
  	    imap-state 'auth)
        t)))
  
+ (defun imap-mailbox-expunge (&optional buffer)
+   "Expunge articles in current folder in BUFFER. If BUFFER is
+ nil the current buffer is assumed."
+   (with-current-buffer (or buffer (current-buffer))
+     (imap-ok-p (imap-send-command-wait "EXPUNGE"))))
+ 
  (defun imap-mailbox-close (&optional buffer)
    "Expunge articles and close current folder in BUFFER. If BUFFER is
  nil the current buffer is assumed."
***************
*** 852,858 ****
  	       (list list))
  	     ","))
  
! (defun imap-message-fetch (uids props &optional receive buffer)
    "Fetch properties PROPS from message set UIDS from server in
  BUFFER. UIDS is a list of articles. If RECEIVE is non-nil return
  theese properties."
--- 858,864 ----
  	       (list list))
  	     ","))
  
! (defun imap-message-fetch (uids props &optional receive nouidfetch buffer)
    "Fetch properties PROPS from message set UIDS from server in
  BUFFER. UIDS is a list of articles. If RECEIVE is non-nil return
  theese properties."
***************
*** 860,869 ****
      (let ((uids (if (or (stringp uids) (listp uids)) uids (list uids)))
  	  (props (if (or (stringp props) (listp props)) props (list props))))
        (when (imap-ok-p (imap-send-command-wait 
! 			(format "UID FETCH %s %s"
  				(if (listp uids)
  				    (imap-list-to-message-set uids)
  				  uids)
  				props)))
  	(if (not (and receive (listp uids)))
  	    t
--- 866,878 ----
      (let ((uids (if (or (stringp uids) (listp uids)) uids (list uids)))
  	  (props (if (or (stringp props) (listp props)) props (list props))))
        (when (imap-ok-p (imap-send-command-wait 
! 			(concat (or nouidfetch
! 				    "UID ")
! 				"FETCH "
  				(if (listp uids)
  				    (imap-list-to-message-set uids)
  				  uids)
+ 				" "
  				props)))
  	(if (not (and receive (listp uids)))
  	    t
***************
*** 1038,1043 ****
--- 1047,1077 ----
  	(list "APPEND " (imap-encode-string mailbox) " "  article))))
      (imap-message-appenduid mailbox)))
    
+ (defun imap-body-lines (body)
+   "Return number of lines in article by looking at the mime bodystructure
+ BODY."
+   (if (listp body)
+       (if (stringp (car body))
+ 	  (cond ((and (string= (car body) "TEXT")
+ 		      (numberp (nth 7 body)))
+ 		 (nth 7 body))
+ 		((and (string= (car body) "MESSAGE")
+ 		      (numberp (nth 9 body)))
+ 		 (nth 9 body))
+ 		(t 0))
+ 	(apply '+ (mapcar 'imap-body-lines body)))
+     0))
+ 
+ (defun imap-envelope-from (from)
+   "Return a from string line."
+   (and from
+        (concat (aref from 0)
+ 	       (if (aref from 0) " <")
+ 	       (aref from 2) 
+ 	       "@" 
+ 	       (aref from 3)
+ 	       (if (aref from 0) ">"))))
+ 
  
  ;; Internal functions.
  
***************
*** 1076,1082 ****
  			   (when (eq stream 'kerberos4)
  			     ;; XXX modifies buffer!
  			     (goto-char (point-min))
! 			     (while (re-search-forward "\r\n" nil t)
  			       (replace-match "\n")))
  			   (and imap-log
  				(with-current-buffer (get-buffer-create
--- 1110,1116 ----
  			   (when (eq stream 'kerberos4)
  			     ;; XXX modifies buffer!
  			     (goto-char (point-min))
! 			     (while (search-forward "\r\n" nil t)
  			       (replace-match "\n")))
  			   (and imap-log
  				(with-current-buffer (get-buffer-create
***************
*** 1166,1171 ****
--- 1200,1208 ----
  
  ;; Imap parser.
  
+ (defsubst imap-forward ()
+   (or (eobp) (forward-char)))
+ 
  ;;   number          = 1*DIGIT
  ;;                       ; Unsigned 32-bit integer
  ;;                       ; (0 <= n < 4,294,967,296)
***************
*** 1236,1242 ****
  
  (defsubst imap-parse-astring ()
    (or (imap-parse-string)
!       (symbol-name (read (current-buffer)))))
  
  ;;   address         = "(" addr-name SP addr-adl SP addr-mailbox SP
  ;;                      addr-host ")"
--- 1273,1281 ----
  
  (defsubst imap-parse-astring ()
    (or (imap-parse-string)
!       (buffer-substring (point) 
! 			(or (search-forward " " (line-end-position) t)
! 			    (line-end-position)))))
  
  ;;   address         = "(" addr-name SP addr-adl SP addr-mailbox SP
  ;;                      addr-host ")"
***************
*** 1264,1279 ****
  (defsubst imap-parse-address ()
    (let (address)
      (when (eq (char-after) ?\()
!       (or (eobp) (forward-char))
        (setq address (vector (prog1 (imap-parse-nstring)
! 			      (or (eobp) (forward-char)))
  			    (prog1 (imap-parse-nstring)
! 			      (or (eobp) (forward-char)))
  			    (prog1 (imap-parse-nstring)
! 			      (or (eobp) (forward-char)))
  			    (imap-parse-nstring)))
        (when (eq (char-after) ?\))
! 	(or (eobp) (forward-char))
  	address))))
  
  ;;   address-list    = "(" 1*address ")" / nil
--- 1303,1318 ----
  (defsubst imap-parse-address ()
    (let (address)
      (when (eq (char-after) ?\()
!       (imap-forward)
        (setq address (vector (prog1 (imap-parse-nstring)
! 			      (imap-forward))
  			    (prog1 (imap-parse-nstring)
! 			      (imap-forward))
  			    (prog1 (imap-parse-nstring)
! 			      (imap-forward))
  			    (imap-parse-nstring)))
        (when (eq (char-after) ?\))
! 	(imap-forward)
  	address))))
  
  ;;   address-list    = "(" 1*address ")" / nil
***************
*** 1283,1294 ****
  (defsubst imap-parse-address-list ()
    (if (eq (char-after) ?\()
        (let (address addresses)
! 	(or (eobp) (forward-char))
  	(while (and (not (eq (char-after) ?\)))
  		    (setq address (imap-parse-address)))
  	  (setq addresses (cons address addresses)))
  	(when (eq (char-after) ?\))
! 	  (or (eobp) (forward-char))
  	  (nreverse addresses)))
      (assert (imap-parse-nil))))
  
--- 1322,1333 ----
  (defsubst imap-parse-address-list ()
    (if (eq (char-after) ?\()
        (let (address addresses)
! 	(imap-forward)
  	(while (and (not (eq (char-after) ?\)))
  		    (setq address (imap-parse-address)))
  	  (setq addresses (cons address addresses)))
  	(when (eq (char-after) ?\))
! 	  (imap-forward)
  	  (nreverse addresses)))
      (assert (imap-parse-nil))))
  
***************
*** 1303,1310 ****
  
  (defsubst imap-parse-mailbox ()
    (let ((mailbox (imap-parse-astring)))
-     (and (symbolp mailbox)
- 	 (setq mailbox (symbol-name mailbox)))
      (if (string-equal "INBOX" (upcase mailbox))
  	"INBOX"
        mailbox)))
--- 1342,1347 ----
***************
*** 1370,1376 ****
  				     (point-max))
  		   t)))
        (* (case (prog1 (setq token (read (current-buffer)))
! 		 (or (eobp) (forward-char)))
  	   (OK         (imap-parse-resp-text))
  	   (NO         (imap-parse-resp-text))
  	   (BAD        (imap-parse-resp-text))
--- 1407,1413 ----
  				     (point-max))
  		   t)))
        (* (case (prog1 (setq token (read (current-buffer)))
! 		 (imap-forward))
  	   (OK         (imap-parse-resp-text))
  	   (NO         (imap-parse-resp-text))
  	   (BAD        (imap-parse-resp-text))
***************
*** 1387,1393 ****
  					   ")"))))
  	   (ACL        (imap-parse-acl))
  	   (t       (case (prog1 (read (current-buffer))
! 			    (or (eobp) (forward-char)))
  		      (EXISTS  (imap-mailbox-put 'exists token))
  		      (RECENT  (imap-mailbox-put 'recent token))
  		      (EXPUNGE t)
--- 1424,1430 ----
  					   ")"))))
  	   (ACL        (imap-parse-acl))
  	   (t       (case (prog1 (read (current-buffer))
! 			    (imap-forward))
  		      (EXISTS  (imap-mailbox-put 'exists token))
  		      (RECENT  (imap-mailbox-put 'recent token))
  		      (EXPUNGE t)
***************
*** 1397,1403 ****
  	   (if (not (integerp token))
  	       (message "Garbage: %s" (buffer-string))
  	     (case (prog1 (setq status (read (current-buffer)))
! 		     (or (eobp) (forward-char)))
  	       (OK  (progn
  		      (setq imap-reached-tag (max imap-reached-tag token))
  		      (imap-parse-resp-text)))
--- 1434,1440 ----
  	   (if (not (integerp token))
  	       (message "Garbage: %s" (buffer-string))
  	     (case (prog1 (setq status (read (current-buffer)))
! 		     (imap-forward))
  	       (OK  (progn
  		      (setq imap-reached-tag (max imap-reached-tag token))
  		      (imap-parse-resp-text)))
***************
*** 1409,1415 ****
  			(when (eq (char-after) ?\[)
  			  (setq code (buffer-substring (point)
  						       (search-forward "]")))
! 			  (or (eobp) (forward-char)))
  			(setq text (buffer-substring (point) (point-max)))
  			(push (list token status code text) 
  			      imap-failed-tags))))
--- 1446,1452 ----
  			(when (eq (char-after) ?\[)
  			  (setq code (buffer-substring (point)
  						       (search-forward "]")))
! 			  (imap-forward))
  			(setq text (buffer-substring (point) (point-max)))
  			(push (list token status code text) 
  			      imap-failed-tags))))
***************
*** 1421,1431 ****
  			(when (eq (char-after) ?\[)
  			  (setq code (buffer-substring (point)
  						       (search-forward "]")))
! 			  (or (eobp) (forward-char)))
  			(setq text (buffer-substring (point) (point-max)))
  			(push (list token status code text) imap-failed-tags)
! 			(message "Internal error, tag %s status %s code %s text %s"
! 				 token status code text))))
  	       (t   (message "Garbage: %s" (buffer-string))))))))))
  
  ;;   resp-text       = ["[" resp-text-code "]" SP] text
--- 1458,1468 ----
  			(when (eq (char-after) ?\[)
  			  (setq code (buffer-substring (point)
  						       (search-forward "]")))
! 			  (imap-forward))
  			(setq text (buffer-substring (point) (point-max)))
  			(push (list token status code text) imap-failed-tags)
! 			(error "Internal error, tag %s status %s code %s text %s"
! 			       token status code text))))
  	       (t   (message "Garbage: %s" (buffer-string))))))))))
  
  ;;   resp-text       = ["[" resp-text-code "]" SP] text
***************
*** 1493,1499 ****
  
  (defun imap-parse-resp-text-code ()
    (when (eq (char-after) ?\[)
!     (or (eobp) (forward-char))
      (cond ((search-forward "PERMANENTFLAGS " nil t)
  	   (imap-mailbox-put 'permanentflags (imap-parse-flag-list)))
  	  ((search-forward "UIDNEXT " nil t)
--- 1530,1536 ----
  
  (defun imap-parse-resp-text-code ()
    (when (eq (char-after) ?\[)
!     (imap-forward)
      (cond ((search-forward "PERMANENTFLAGS " nil t)
  	   (imap-mailbox-put 'permanentflags (imap-parse-flag-list)))
  	  ((search-forward "UIDNEXT " nil t)
***************
*** 1507,1513 ****
  	  ((search-forward "NEWNAME " nil t)
  	   (let (oldname newname)
  	     (setq oldname (imap-parse-string))
! 	     (or (eobp) (forward-char))
  	     (setq newname (imap-parse-string))
  	     (imap-mailbox-put 'newname newname oldname)))
  	  ((search-forward "TRYCREATE" nil t)
--- 1544,1550 ----
  	  ((search-forward "NEWNAME " nil t)
  	   (let (oldname newname)
  	     (setq oldname (imap-parse-string))
! 	     (imap-forward)
  	     (setq newname (imap-parse-string))
  	     (imap-mailbox-put 'newname newname oldname)))
  	  ((search-forward "TRYCREATE" nil t)
***************
*** 1555,1619 ****
  	(imap-mailbox-put 'list-flags flags mailbox)
  	(imap-mailbox-put 'delimiter delimiter mailbox)))))
  
! ;;   msg-att         = "(" (msg-att-dynamic / msg-att-static)
! ;;                      *(SP (msg-att-dynamic / msg-att-static)) ")"
! ;;
! ;;   msg-att-dynamic = "FLAGS" SP "(" [flag-fetch *(SP flag-fetch)] ")"
! ;;                       ; MAY change for a message
! ;;
! ;;   flag-fetch      = flag / "\Recent"
! ;;
! ;;   flag            = "\Answered" / "\Flagged" / "\Deleted" /
! ;;                     "\Seen" / "\Draft" / flag-keyword / flag-extension
! ;;                       ; Does not include "\Recent"
! ;;
! ;;   flag-keyword    = atom
! ;;
! ;;   flag-extension  = "\" atom
! ;;                       ; Future expansion.  Client implementations
! ;;                       ; MUST accept flag-extension flags.  Server
! ;;                       ; implementations MUST NOT generate
! ;;                       ; flag-extension flags except as defined by
! ;;                       ; future standard or standards-track
! ;;                       ; revisions of this specification.
! ;;
! ;;   msg-att-static  = "ENVELOPE" SP envelope / 
! ;;                     "INTERNALDATE" SP date-time /
! ;;                     "RFC822" [".HEADER" / ".TEXT"] SP nstring /
! ;;                     "RFC822.SIZE" SP number /
! ;;                     "BODY" ["STRUCTURE"] SP body /
! ;;                     "BODY" section ["<" number ">"] SP nstring /
! ;;                     "UID" SP uniqueid
! ;;                       ; MUST NOT change for a message
! ;;
! ;;   section         = "[" [section-spec] "]"
! ;;
! ;;   section-msgtext = "HEADER" / "HEADER.FIELDS" [".NOT"] SP header-list /
! ;;                     "TEXT"
! ;;                       ; top-level or MESSAGE/RFC822 part
! ;;
! ;;   section-part    = nz-number *("." nz-number)
! ;;                       ; body part nesting
! ;;
! ;;   section-spec    = section-msgtext / (section-part ["." section-text])
! ;;
! ;;   section-text    = section-msgtext / "MIME"
! ;;                       ; text other than actual body part (headers, etc.)
! ;;
! ;;   date-time       = DQUOTE date-day-fixed "-" date-month "-" date-year
! ;;                     SP time SP zone DQUOTE
! ;;
! ;;   uniqueid        = nz-number
! ;;                       ; Strictly ascending
  
  (defun imap-parse-fetch (response)
    (when (eq (char-after) ?\()
      (let (uid flags envelope internaldate rfc822 rfc822header rfc822text 
! 	      rfc822size body bodystructure)
        (while (not (eq (char-after) ?\)))
! 	(or (eobp) (forward-char))
  	(let ((token (read (current-buffer))))
! 	  (or (eobp) (forward-char))
  	  (cond ((eq token 'UID)
  		 (setq uid (read (current-buffer))))
  		((eq token 'FLAGS)
--- 1592,1627 ----
  	(imap-mailbox-put 'list-flags flags mailbox)
  	(imap-mailbox-put 'delimiter delimiter mailbox)))))
  
! ;;  msg_att         ::= "(" 1#("ENVELOPE" SPACE envelope /
! ;;                      "FLAGS" SPACE "(" #(flag / "\Recent") ")" /
! ;;                      "INTERNALDATE" SPACE date_time /
! ;;                      "RFC822" [".HEADER" / ".TEXT"] SPACE nstring /
! ;;                      "RFC822.SIZE" SPACE number /
! ;;                      "BODY" ["STRUCTURE"] SPACE body /
! ;;                      "BODY" section ["<" number ">"] SPACE nstring /
! ;;                      "UID" SPACE uniqueid) ")"
! ;;  
! ;;  date_time       ::= <"> date_day_fixed "-" date_month "-" date_year
! ;;                      SPACE time SPACE zone <">
! ;;  
! ;;  section         ::= "[" [section_text / (nz_number *["." nz_number]
! ;;                      ["." (section_text / "MIME")])] "]"
! ;;  
! ;;  section_text    ::= "HEADER" / "HEADER.FIELDS" [".NOT"]
! ;;                      SPACE header_list / "TEXT"
! ;;  
! ;;  header_fld_name ::= astring
! ;;  
! ;;  header_list     ::= "(" 1#header_fld_name ")"
  
  (defun imap-parse-fetch (response)
    (when (eq (char-after) ?\()
      (let (uid flags envelope internaldate rfc822 rfc822header rfc822text 
! 	      rfc822size body bodydetail bodystructure)
        (while (not (eq (char-after) ?\)))
! 	(imap-forward)
  	(let ((token (read (current-buffer))))
! 	  (imap-forward)
  	  (cond ((eq token 'UID)
  		 (setq uid (read (current-buffer))))
  		((eq token 'FLAGS)
***************
*** 1631,1637 ****
  		((eq token 'RFC822.SIZE)
  		 (setq rfc822size (read (current-buffer))))
  		((eq token 'BODY)
! 		 (setq body (imap-parse-body)))
  		((eq token 'BODYSTRUCTURE)
  		 (setq bodystructure (imap-parse-body))))))
        (if (not uid)
--- 1639,1655 ----
  		((eq token 'RFC822.SIZE)
  		 (setq rfc822size (read (current-buffer))))
  		((eq token 'BODY)
! 		 (if (eq (char-before) ?\[)
! 		     (push (list
! 			    (buffer-substring (point)
! 					      (1- (search-forward "]" nil t)))
! 			    (and (eq (char-after) ?<)
! 				 (buffer-substring (1+ (point))
! 						   (search-forward ">" nil t)))
! 			    (progn (imap-forward)
! 				   (imap-parse-nstring)))
! 			   bodydetail)
! 		   (setq body (imap-parse-body))))
  		((eq token 'BODYSTRUCTURE)
  		 (setq bodystructure (imap-parse-body))))))
        (if (not uid)
***************
*** 1646,1651 ****
--- 1664,1670 ----
  	(and rfc822text (imap-message-put uid 'RFC822.TEXT rfc822text))
  	(and rfc822size (imap-message-put uid 'RFC822.SIZE rfc822size))
  	(and body (imap-message-put uid 'BODY body))
+ 	(and bodydetail (imap-message-put uid 'BODYDETAIL bodydetail))
  	(and bodystructure (imap-message-put uid 'BODYSTRUCTURE bodystructure))
  	(run-hooks 'imap-fetch-data-hook)))))
  
***************
*** 1748,1784 ****
  
  (defun imap-parse-envelope ()
    (when (eq (char-after) ?\()
!     (or (eobp) (forward-char))
      (vector (prog1 (imap-parse-nstring)      ;; date
! 	      (or (eobp) (forward-char)))
  	    (prog1 (imap-parse-nstring)      ;; subject
! 	      (or (eobp) (forward-char)))
  	    (prog1 (imap-parse-address-list) ;; from
! 	      (or (eobp) (forward-char)))
  	    (prog1 (imap-parse-address-list) ;; sender
! 	      (or (eobp) (forward-char)))
  	    (prog1 (imap-parse-address-list) ;; reply-to
! 	      (or (eobp) (forward-char)))
  	    (prog1 (imap-parse-address-list) ;; to
! 	      (or (eobp) (forward-char)))
  	    (prog1 (imap-parse-address-list) ;; cc
! 	      (or (eobp) (forward-char)))
  	    (prog1 (imap-parse-address-list) ;; bcc
! 	      (or (eobp) (forward-char)))
  	    (prog1 (imap-parse-nstring)      ;; in-reply-to
! 	      (or (eobp) (forward-char)))
  	    (prog1 (imap-parse-nstring)      ;; message-id
! 	      (or (eobp) (forward-char))))))
  
  ;;   body-fld-param  = "(" string SP string *(SP string SP string) ")" / nil
  
  (defsubst imap-parse-string-list ()
    (cond ((eq (char-after) ?\()                      ;; body-fld-param
  	 (let (strlist str)
! 	   (or (eobp) (forward-char))
  	   (while (setq str (imap-parse-string))
  	     (push str strlist)
! 	     (or (eobp) (forward-char)))
  	   (nreverse strlist)))
  	((imap-parse-nil)
  	 nil)))
--- 1767,1803 ----
  
  (defun imap-parse-envelope ()
    (when (eq (char-after) ?\()
!     (imap-forward)
      (vector (prog1 (imap-parse-nstring)      ;; date
! 	      (imap-forward))
  	    (prog1 (imap-parse-nstring)      ;; subject
! 	      (imap-forward))
  	    (prog1 (imap-parse-address-list) ;; from
! 	      (imap-forward))
  	    (prog1 (imap-parse-address-list) ;; sender
! 	      (imap-forward))
  	    (prog1 (imap-parse-address-list) ;; reply-to
! 	      (imap-forward))
  	    (prog1 (imap-parse-address-list) ;; to
! 	      (imap-forward))
  	    (prog1 (imap-parse-address-list) ;; cc
! 	      (imap-forward))
  	    (prog1 (imap-parse-address-list) ;; bcc
! 	      (imap-forward))
  	    (prog1 (imap-parse-nstring)      ;; in-reply-to
! 	      (imap-forward))
  	    (prog1 (imap-parse-nstring)      ;; message-id
! 	      (imap-forward)))))
  
  ;;   body-fld-param  = "(" string SP string *(SP string SP string) ")" / nil
  
  (defsubst imap-parse-string-list ()
    (cond ((eq (char-after) ?\()                      ;; body-fld-param
  	 (let (strlist str)
! 	   (imap-forward)
  	   (while (setq str (imap-parse-string))
  	     (push str strlist)
! 	     (imap-forward))
  	   (nreverse strlist)))
  	((imap-parse-nil)
  	 nil)))
***************
*** 1795,1807 ****
  (defun imap-parse-body-extension ()
    (if (eq (char-after) ?\()
        (let (b-e)
! 	(or (eobp) (forward-char))
  	(push (imap-parse-body-extension) b-e)
  	(while (eq (char-after) ?\ )
! 	  (or (eobp) (forward-char))
  	  (push (imap-parse-body-extension) b-e))
  	(assert (eq (char-after) ?\)))
! 	(or (eobp) (forward-char))
  	(nreverse b-e))
      (or (imap-parse-number)
  	(imap-parse-nstring))))
--- 1814,1826 ----
  (defun imap-parse-body-extension ()
    (if (eq (char-after) ?\()
        (let (b-e)
! 	(imap-forward)
  	(push (imap-parse-body-extension) b-e)
  	(while (eq (char-after) ?\ )
! 	  (imap-forward)
  	  (push (imap-parse-body-extension) b-e))
  	(assert (eq (char-after) ?\)))
! 	(imap-forward)
  	(nreverse b-e))
      (or (imap-parse-number)
  	(imap-parse-nstring))))
***************
*** 1819,1842 ****
  (defsubst imap-parse-body-ext ()
    (let (ext)
      (when (eq (char-after) ?\ )                   ;; body-fld-dsp
!       (or (eobp) (forward-char))
        (let (dsp)
  	(if (eq (char-after) ?\()
  	    (progn
! 	      (or (eobp) (forward-char))
  	      (push (imap-parse-string) dsp)
! 	      (or (eobp) (forward-char))
  	      (push (imap-parse-string-list) dsp)
! 	      (or (eobp) (forward-char)))
  	  (assert (imap-parse-nil)))
  	(push (nreverse dsp) ext))
        (when (eq (char-after) ?\ )                ;; body-fld-lang
! 	(or (eobp) (forward-char))
  	(if (eq (char-after) ?\()
  	    (push (imap-parse-string-list) ext)
  	  (push (imap-parse-nstring) ext))
  	(while (eq (char-after) ?\ )             ;; body-extension
! 	  (or (eobp) (forward-char))
  	  (setq ext (append (imap-parse-body-extension) ext)))))
      ext))
  
--- 1838,1861 ----
  (defsubst imap-parse-body-ext ()
    (let (ext)
      (when (eq (char-after) ?\ )                   ;; body-fld-dsp
!       (imap-forward)
        (let (dsp)
  	(if (eq (char-after) ?\()
  	    (progn
! 	      (imap-forward)
  	      (push (imap-parse-string) dsp)
! 	      (imap-forward)
  	      (push (imap-parse-string-list) dsp)
! 	      (imap-forward))
  	  (assert (imap-parse-nil)))
  	(push (nreverse dsp) ext))
        (when (eq (char-after) ?\ )                ;; body-fld-lang
! 	(imap-forward)
  	(if (eq (char-after) ?\()
  	    (push (imap-parse-string-list) ext)
  	  (push (imap-parse-nstring) ext))
  	(while (eq (char-after) ?\ )             ;; body-extension
! 	  (imap-forward)
  	  (setq ext (append (imap-parse-body-extension) ext)))))
      ext))
  
***************
*** 1904,1942 ****
  (defun imap-parse-body ()
    (let (body)
      (when (eq (char-after) ?\()
!       (or (eobp) (forward-char))
        (if (eq (char-after) ?\()
  	  (let (subbody)
  	    (while (and (eq (char-after) ?\()
  			(setq subbody (imap-parse-body)))
  	      (push subbody body))
! 	    (or (eobp) (forward-char))
  	    (push (imap-parse-string) body)               ;; media-subtype
  	    (when (eq (char-after) ?\ )                   ;; body-ext-mpart:
! 	      (or (eobp) (forward-char))
  	      (if (eq (char-after) ?\()                   ;; body-fld-param
  		  (push (imap-parse-string-list) body)
  		(push (and (imap-parse-nil) nil) body))
  	      (setq body
  		    (append (imap-parse-body-ext) body))) ;; body-ext-...
  	    (assert (eq (char-after) ?\)))
! 	    (or (eobp) (forward-char))
  	    (nreverse body))
  
  	(push (imap-parse-string) body)                   ;; media-type
! 	(or (eobp) (forward-char))
  	(push (imap-parse-string) body)                   ;; media-subtype
! 	(or (eobp) (forward-char))
  	(if (eq (char-after) ?\()                         ;; body-fld-param
  	    (push (imap-parse-string-list) body)
  	  (push (and (imap-parse-nil) nil) body))
! 	(or (eobp) (forward-char))
  	(push (imap-parse-nstring) body)                  ;; body-fld-id
! 	(or (eobp) (forward-char))
  	(push (imap-parse-nstring) body)                  ;; body-fld-desc
! 	(or (eobp) (forward-char))
  	(push (imap-parse-string) body)                   ;; body-fld-enc
! 	(or (eobp) (forward-char))
  	(push (imap-parse-number) body)                   ;; body-fld-octets
  
  	;; ok, we're done parsing the required parts, what comes now is one
--- 1923,1961 ----
  (defun imap-parse-body ()
    (let (body)
      (when (eq (char-after) ?\()
!       (imap-forward)
        (if (eq (char-after) ?\()
  	  (let (subbody)
  	    (while (and (eq (char-after) ?\()
  			(setq subbody (imap-parse-body)))
  	      (push subbody body))
! 	    (imap-forward)
  	    (push (imap-parse-string) body)               ;; media-subtype
  	    (when (eq (char-after) ?\ )                   ;; body-ext-mpart:
! 	      (imap-forward)
  	      (if (eq (char-after) ?\()                   ;; body-fld-param
  		  (push (imap-parse-string-list) body)
  		(push (and (imap-parse-nil) nil) body))
  	      (setq body
  		    (append (imap-parse-body-ext) body))) ;; body-ext-...
  	    (assert (eq (char-after) ?\)))
! 	    (imap-forward)
  	    (nreverse body))
  
  	(push (imap-parse-string) body)                   ;; media-type
! 	(imap-forward)
  	(push (imap-parse-string) body)                   ;; media-subtype
! 	(imap-forward)
  	(if (eq (char-after) ?\()                         ;; body-fld-param
  	    (push (imap-parse-string-list) body)
  	  (push (and (imap-parse-nil) nil) body))
! 	(imap-forward)
  	(push (imap-parse-nstring) body)                  ;; body-fld-id
! 	(imap-forward)
  	(push (imap-parse-nstring) body)                  ;; body-fld-desc
! 	(imap-forward)
  	(push (imap-parse-string) body)                   ;; body-fld-enc
! 	(imap-forward)
  	(push (imap-parse-number) body)                   ;; body-fld-octets
  
  	;; ok, we're done parsing the required parts, what comes now is one
***************
*** 1950,1962 ****
  	;; by the third. So we parse the first two here (if there are any)...
  
  	(when (eq (char-after) ?\ )
! 	  (or (eobp) (forward-char))
  	  (let (lines)
  	    (cond ((eq (char-after) ?\()                  ;; body-type-msg:
  		   (push (imap-parse-envelope) body)      ;; envelope
! 		   (or (eobp) (forward-char))
  		   (push (imap-parse-body) body)          ;; body
! 		   (or (eobp) (forward-char))
  		   (push (imap-parse-number) body))       ;; body-fld-lines
  		  ((setq lines (imap-parse-number))       ;; body-type-text:
  		   (push lines body))                     ;; body-fld-lines
--- 1969,1981 ----
  	;; by the third. So we parse the first two here (if there are any)...
  
  	(when (eq (char-after) ?\ )
! 	  (imap-forward)
  	  (let (lines)
  	    (cond ((eq (char-after) ?\()                  ;; body-type-msg:
  		   (push (imap-parse-envelope) body)      ;; envelope
! 		   (imap-forward)
  		   (push (imap-parse-body) body)          ;; body
! 		   (imap-forward)
  		   (push (imap-parse-number) body))       ;; body-fld-lines
  		  ((setq lines (imap-parse-number))       ;; body-type-text:
  		   (push lines body))                     ;; body-fld-lines
***************
*** 1966,1977 ****
  	;; ...and then parse the third one here...
  
  	(when (eq (char-after) ?\ )                       ;; body-ext-1part:
! 	  (or (eobp) (forward-char))
  	  (push (imap-parse-nstring) body)                ;; body-fld-md5
  	  (setq body (append (imap-parse-body-ext) body)));; body-ext-1part..
      
  	(assert (eq (char-after) ?\)))
! 	(or (eobp) (forward-char))
  	(nreverse body)))))
  
  (when imap-debug ; (untrace-all)
--- 1985,1996 ----
  	;; ...and then parse the third one here...
  
  	(when (eq (char-after) ?\ )                       ;; body-ext-1part:
! 	  (imap-forward)
  	  (push (imap-parse-nstring) body)                ;; body-fld-md5
  	  (setq body (append (imap-parse-body-ext) body)));; body-ext-1part..
      
  	(assert (eq (char-after) ?\)))
! 	(imap-forward)
  	(nreverse body)))))
  
  (when imap-debug ; (untrace-all)
Index: nnimap/nnimap.el
diff -c nnimap/nnimap.el:1.146 nnimap/nnimap.el:1.149
*** nnimap/nnimap.el:1.146	Sun May  9 09:56:19 1999
--- nnimap/nnimap.el	Fri May 14 08:06:57 1999
***************
*** 93,100 ****
  
  (nnoo-declare nnimap)
  
! (defconst nnimap-version "nnimap 0.99")
  
  ;; Splitting variables
  
  (defvar nnimap-split-crosspost t
--- 93,107 ----
  
  (nnoo-declare nnimap)
  
! (defconst nnimap-version "nnimap 0.100")
  
+ (defvoo nnimap-address nil
+   "Address of physical IMAP server.  If nil, use the virtual server's name.")
+ 
+ (defvoo nnimap-server-port nil
+   "Port number on physical IMAP server.  If nil, defaults to 993 for
+ SSL connections and 143 otherwise.")
+ 
  ;; Splitting variables
  
  (defvar nnimap-split-crosspost t
***************
*** 169,174 ****
--- 176,189 ----
  
  Possible choices: kerberos4, cram-md5, login, anonymous.")
  
+ (defvoo nnimap-directory message-directory
+   "Data directory for the nnimap backend.")
+ 
+ (defvoo nnimap-active-file
+   (concat (file-name-as-directory nnimap-directory) "active.nnimap.")
+   "Mail active file for the nnimap backend. The virtual server name
+ will be appended")
+ 
  (defcustom nnimap-authinfo-file "~/.authinfo"
    "Authorization information for IMAP servers. In .netrc format."
    :type
***************
*** 204,216 ****
  
  ;; Various server variables.
  
- (defvoo nnimap-directory message-directory
-   "Data directory for the nnimap backend.")
- 
- (defvoo nnimap-active-file
-   (concat (file-name-as-directory nnimap-directory) "active")
-   "Mail active file for the nnimap backend.")
- 
  (defvoo nnimap-list-pattern "*" 
  "*PATTERN or list of PATTERNS use to limit available groups.  
  
--- 219,224 ----
***************
*** 242,256 ****
  \"LIST\". LSUB means only retrieve groups marked on the server as
  subscribed.  LIST means every matching group should be retrieved.")
  
- (defvoo nnimap-address nil
-   "*The name of the IMAP server.  If nil, uses the virtual server's name.")
- 
  (defvoo nnimap-server-address nil
    "Obsolete. Use `nnimap-address'.")
  
- (defvoo nnimap-server-port nil
-   "*The port of the IMAP server.  If nil, uses the default port. (143).")
- 
  (defvoo nnimap-imap-defs nil
    "*Definitions of variables to set up in the IMAP buffer.")
  
--- 250,258 ----
***************
*** 266,276 ****
  When setting this variable to `never', you can only expunge articles
  by using `G x' (gnus-group-nnimap-expunge) from the Group buffer.")
  
- (defvoo nnimap-group-list-speed 'slow ; 'fast, 'medium
-   "*If fast, do not show number of articles in the group list.
- If medium, guess number of articles by using the UIDNEXT attribute.
- If slow, fetch the UID of lowest/highest article.")
- 
  
  ;; Internal variables.
  (defvoo nnimap-need-expunge nil)
--- 268,273 ----
***************
*** 298,303 ****
--- 295,358 ----
  
  (nnoo-define-basics nnimap)
  
+ (defsubst nnimap-replace-tabs (string)
+   "Translate TAB characters into SPACE characters in STRING."
+   (subst-char-in-string ?\t ?  string t))
+ 
+ (defsubst nnimap-remove-delimiter (string)
+   "Remove trailing \r\n\r\n (rfc822 head/body delimiter) from string"
+   (and (> (length string) 4)
+        (substring string 0 -4)))
+ 
+ (defun nnimap-retrieve-headers-progress ()
+   (when (and (> nnimap-length 25) (eq (mod nnimap-counter 5) 0))
+     (setq nnimap-counter (1+ nnimap-counter))
+     (message "Fetching headers...  %-3d%%" 
+ 	     (* 100.0 (/ (float nnimap-counter) nnimap-length))))
+   (with-current-buffer nntp-server-buffer
+     (nnheader-insert-nov
+      (vector imap-current-message
+ 	     (nnimap-replace-tabs (imap-message-envelope-subject
+ 				   imap-current-message))
+ 	     (nnimap-replace-tabs (imap-envelope-from 
+ 				   (car-safe (imap-message-envelope-from
+ 					      imap-current-message))))
+ 	     (nnimap-replace-tabs (imap-message-envelope-date 
+ 				   imap-current-message))
+ 	     (nnimap-replace-tabs (imap-message-envelope-message-id
+ 				   imap-current-message))
+ 	     (nnimap-replace-tabs
+ 	      (nnimap-remove-delimiter
+ 	       (nth 2 (assoc "HEADER.FIELDS (References)"
+ 			     (imap-message-get imap-current-message 
+ 					       'BODYDETAIL)))))
+ 	     (imap-message-get imap-current-message 'RFC822.SIZE)
+ 	     (imap-body-lines (imap-message-body imap-current-message))
+ 	     nil ;; xref
+ 	     nil))) ;; extra-headers
+   )
+ 
+ (deffoo nnimap-retrieve-headers (articles &optional group server fetch-old)
+   (when (nnimap-possibly-change-group group server)
+     (with-current-buffer nntp-server-buffer
+       (erase-buffer))
+     (let* ((articles (if (numberp (car articles))
+ 			 articles
+ 		       (mapcar (lambda (msgid)
+ 				 (imap-search 
+ 				  (format "HEADER Message-Id %s" msgid
+ 					  nnimap-server-buffer)))
+ 			       articles)))
+            (compressed (gnus-compress-sequence articles t))
+ 	   (imap-fetch-data-hook '(nnimap-retrieve-headers-progress))
+ 	   (nnimap-length (length articles))
+ 	   (nnimap-counter 0))
+       (imap-message-fetch (if (and fetch-old (not (numberp fetch-old)))
+ 			      "1:*" (nnimap-range-to-string compressed))
+ 			  "(UID RFC822.SIZE ENVELOPE BODY BODY.PEEK[HEADER.FIELDS (References)])"
+ 			  nil nil nnimap-server-buffer))
+     'nov))
+ 
  (defun nnimap-open-connection (server)
    (if (not (imap-open nnimap-address nnimap-server-port nnimap-stream
  		      nnimap-authenticator nnimap-server-buffer))
***************
*** 382,401 ****
      (nnoo-status-message 'nnimap server)))
  
  (defun nnimap-demule (string)
!   (funcall (if (and string
! 		    (fboundp 'string-as-multibyte)
  		    (subrp (symbol-function 'string-as-multibyte)))
  	       'string-as-multibyte
  	     'identity)
  	   string))
  
  (defun nnimap-request-article-part (article part prop
! 					 &optional group server to-buffer)
    (when (nnimap-possibly-change-group group server)
      (with-current-buffer (or to-buffer nntp-server-buffer)
        (erase-buffer)
!       (insert (or (nnimap-demule
! 		   (car-safe
  		    (car-safe
  		     (imap-message-fetch 
  		      (if (stringp article)
--- 437,455 ----
      (nnoo-status-message 'nnimap server)))
  
  (defun nnimap-demule (string)
!   (funcall (if (and (fboundp 'string-as-multibyte)
  		    (subrp (symbol-function 'string-as-multibyte)))
  	       'string-as-multibyte
  	     'identity)
  	   string))
  
  (defun nnimap-request-article-part (article part prop
! 					    &optional group server to-buffer)
    (when (nnimap-possibly-change-group group server)
      (with-current-buffer (or to-buffer nntp-server-buffer)
        (erase-buffer)
!       (insert (nnimap-demule
! 	       (or (car-safe
  		    (car-safe
  		     (imap-message-fetch 
  		      (if (stringp article)
***************
*** 403,410 ****
  				     (format "HEADER Message-Id %s" article
  					     nnimap-server-buffer)))
  			article)
! 		      part prop nnimap-server-buffer))))
! 		  ""))
        (nnheader-ms-strip-cr)
        (if (bobp)
  	  (nnheader-report 'nnimap "No such article")
--- 457,464 ----
  				     (format "HEADER Message-Id %s" article
  					     nnimap-server-buffer)))
  			article)
! 		      part prop nil nnimap-server-buffer)))
! 		   "")))
        (nnheader-ms-strip-cr)
        (if (bobp)
  	  (nnheader-report 'nnimap "No such article")
***************
*** 422,430 ****
--- 476,512 ----
    (nnimap-request-article-part
     article "RFC822.TEXT.PEEK" 'RFC822.TEXT group server to-buffer))
  
+ (defun nnimap-pattern-to-list-arguments (pattern)
+   (mapcar (lambda (p)
+ 	    (cons (car-safe p) (or (cdr-safe p) p)))
+ 	  (if (and (listp pattern)
+ 		   (listp (cdr pattern)))
+ 	      pattern
+ 	    (list pattern))))
+ 
+ (deffoo nnimap-request-list (&optional server)
+   (when (nnimap-possibly-change-server server)
+     (with-current-buffer nntp-server-buffer
+       (gnus-message 5 "Generating active list for %s..." server)
+       (erase-buffer)
+       (dolist (pattern (nnimap-pattern-to-list-arguments 
+ 			nnimap-list-pattern))
+ 	(dolist (mbx (imap-mailbox-list 
+ 		      nnimap-server-buffer (cdr pattern) t (car pattern)))
+ 	  (or (member "\\NoSelect" 
+ 		      (imap-mailbox-get 'list-flags mbx nnimap-server-buffer))
+ 	      ;; We ignore groups with spaces (Gnus can't handle them)
+ 	      (string-match " " mbx)
+ 	      ;; We lie about high/low article number
+ 	      (insert (format "%s 0 1 y\n" mbx)))))
+       (gnus-message 5 "Generating active list for %s...done" server))
+     t))
+ 
  (deffoo nnimap-request-post (&optional server)
    (nnheader-report 'nnimap "Nnimap doesn't support posting"))
  
+ ;; Optional backend functions
+ 
  (defun nnimap-body-lines (body)
    "Return number of lines in article by looking at the mime bodystructure
  BODY."
***************
*** 532,546 ****
  	    (dolist (article (imap-search "UNSEEN UNDELETED"))
  	      (when (nnimap-request-head article)
  		;; copy article to right group(s)
! 		(setq removeorig t)
  		(dolist (to-group (nnimap-split-to-groups rule))
  		  (if (imap-message-copy article to-group nil nil t)
! 		      (message "IMAP split moved %s:%s:%d to %s" server inbox
! 			       article to-group)
  		    (message "IMAP split failed to move %s:%s:%d to %s" server
! 			     inbox article to-group)
! 		    (setq removeorig nil)))
! 		;; remove article on success
  		(when removeorig
  		  (setq nnimap-need-expunge t)
  		  (imap-message-flags-add (format "%d" article)
--- 614,629 ----
  	    (dolist (article (imap-search "UNSEEN UNDELETED"))
  	      (when (nnimap-request-head article)
  		;; copy article to right group(s)
! 		(setq removeorig nil)
  		(dolist (to-group (nnimap-split-to-groups rule))
  		  (if (imap-message-copy article to-group nil nil t)
! 		      (progn
! 			(message "IMAP split moved %s:%s:%d to %s" server inbox
! 				 article to-group)
! 			(setq removeorig t))
  		    (message "IMAP split failed to move %s:%s:%d to %s" server
! 			     inbox article to-group)))
! 		;; remove article if it was successfully copied somewhere
  		(when removeorig
  		  (setq nnimap-need-expunge t)
  		  (imap-message-flags-add (format "%d" article)
***************
*** 625,630 ****
--- 708,733 ----
  	     (nnimap-request-expire-articles (list article) group server t))
  	result))))
    
+ (deffoo nnimap-request-accept-article (group &optional server last)
+   (when (nnimap-possibly-change-server server)
+     (let (uid)
+       (and (setq uid
+ 		 (if (string= nnimap-current-server nnimap-current-move-server)
+ 		     ;; moving article within same server, speed it up...
+ 		     (and (nnimap-possibly-change-group
+ 			   nnimap-current-move-group)
+ 			  (imap-message-copy (number-to-string
+ 					      nnimap-current-move-article)
+ 					     group nnimap-server-buffer))
+ 		   ;; turn into rfc822 format (\r\n eol's)
+ 		   (with-current-buffer (current-buffer)
+ 		     (goto-char (point-min))
+ 		     (while (search-forward "\n" nil t)
+ 		       (replace-match "\r\n")))
+ 		   (imap-message-append group (current-buffer)
+ 					nnimap-server-buffer)))
+ 	   (cons group (nth 1 uid))))))
+ 
  (deffoo nnimap-request-delete-group (group force &optional server)
    (when (and (nnimap-possibly-change-server server) force)
      (imap-mailbox-delete group nnimap-server-buffer)))
***************
*** 647,653 ****
      (unless (eq 'nnimap (car (setq method (gnus-find-method-for-group group))))
        (error "Expunging only available for nnimap groups"))
      (when (nnimap-possibly-change-group mailbox (cadr method))
!       (nnimap-send-command-wait "EXPUNGE" nnimap-server-buffer))))
  
  (defun gnus-group-nnimap-edit-acl (group)
    "Edit the Access Control List of current nnimap GROUP."
--- 750,756 ----
      (unless (eq 'nnimap (car (setq method (gnus-find-method-for-group group))))
        (error "Expunging only available for nnimap groups"))
      (when (nnimap-possibly-change-group mailbox (cadr method))
!       (imap-mailbox-expunge nnimap-server-buffer))))
  
  (defun gnus-group-nnimap-edit-acl (group)
    "Edit the Access Control List of current nnimap GROUP."
***************
*** 730,787 ****
  
  ;;; Interface functions, required backend functions
  
- (defun nnimap-retrieve-headers-progress ()
-   (when (> nnimap-length 25)
-     (setq nnimap-counter (1+ nnimap-counter))
-     (message "Fetching headers...  %-3d%%" 
- 	     (* 100.0 (/ (float nnimap-counter) 
- 			 nnimap-length)))))
- 
- ;; todo:
- ;; use NOV lines instead? A fetch like
- ;;   (UID RFC822.SIZE BODY BODY[HEADER.FIELDS (References)]) would do it
- ;; remove redundant lines:/chars:
- (deffoo nnimap-retrieve-headers (articles &optional group server fetch-old)
-   (when (nnimap-possibly-change-group group server)
-     (with-current-buffer nntp-server-buffer (erase-buffer))
-     (let* ((uncompressed (gnus-uncompress-sequence articles))
-           (compressed (gnus-compress-sequence uncompressed t)))
-       (with-current-buffer nnimap-server-buffer
- 	;; Reset message info, this makes sure we return 423 on
- 	;; articles that were removed by another client while we
- 	;; had the mailbox SELECTed. This isn't really necessery (the user
- 	;; will find out when he selects the article anyway).
- 	;(imap-message-reset)
- 	(let ((imap-fetch-data-hook '(nnimap-retrieve-headers-progress))
- 	      (nnimap-length (length uncompressed))
- 	      (nnimap-counter 0))
- 	  (nnimap-ok-p (nnimap-send-command-wait
- 			(concat "UID FETCH "
- 				(if (and fetch-old (not (numberp fetch-old)))
- 				    "1:*"
- 				  (nnimap-range-to-string compressed))
- 				" (UID RFC822.HEADER RFC822.SIZE BODYSTRUCTURE)"))))
- 	(mapc (lambda (num)
- 		(let* ((header (imap-message-get num 'RFC822.HEADER))
- 		       (size   (imap-message-get num 'RFC822.SIZE))
- 		       (body   (imap-message-get num 'BODYSTRUCTURE))
- 		       (lines  (nnimap-body-lines body)))
- 		  (with-current-buffer nntp-server-buffer
- 		    (if (not header)
- 			(insert "423 Bad article number.\n")
- 		      (insert (format "221 %d Article retrieved.\n" num))
- 		      (insert (format "Chars: %d\n" size))
- 		      (insert (format "Lines: %d\n" lines))
- 		      (insert header)
- 		      (delete-char -2)
- 		      (insert ".\n")))))
- 	      uncompressed)
- 	(with-current-buffer nntp-server-buffer
- 	  (goto-char (point-min))
- 	  (while (re-search-forward "\r$" nil t)
- 	    (delete-backward-char 1)))	
- 	'headers))))
- 
  ;;; Select GROUP and unless FAST return 211 EXISTS LOWEST HIGHEST GROUP
  ;;; The active info returned goes into the `gnus-active-hashtb'.
  ;;; Don't call this directly, call `gnus-activate-group'.
--- 833,838 ----
***************
*** 824,886 ****
    (unless (or (member "\\NoSelect" (imap-mailbox-get 'list-flags group))
  	      ;; We ignore groups with spaces (Gnus can't handle them)
  	      (string-match " " group))
!     (let (high)
!       (gnus-message 7 "Generating active list for nnimap group %s" group)
!       (cond 
!        ((eq nnimap-group-list-speed 'slow)
! 	(when (imap-mailbox-select group)
! 	  (let ((exists (imap-mailbox-get 'exists))
! 		articles)
! 	    (if (eq 0 exists)
! 		(with-current-buffer nntp-server-buffer
! 		  (insert (format "%s 0 1 y\n" group)))
! 	      (when (nnimap-ok-p (nnimap-send-command-wait "FETCH 1,* (UID)"))
! 		(imap-message-map (lambda (uid Uid)
! 				    (push uid articles)) 'UID)
! 		(with-current-buffer nntp-server-buffer
! 		  (insert (format "%s %d %d y\n" group
! 				  (apply 'max articles)
! 				  (apply 'min articles))))))
! 	    t)))
!        ((eq nnimap-group-list-speed 'medium)
! 	(when (nnimap-ok-p (nnimap-send-command-wait
! 			    (concat "STATUS " group 
! 				    " (UIDNEXT)")))
! 	  (setq high (1- (imap-mailbox-get 'uidnext group)))
! 	  (with-current-buffer nntp-server-buffer
! 	    (insert (format "%s %d 1 y\n" group high))
! 	    t)))
!        ((eq nnimap-group-list-speed 'fast)
! 	(with-current-buffer nntp-server-buffer
! 	  (insert (format "%s 0 1 y\n" group))
! 	  t))
!        (t
! 	(error "Unknown nnimap-group-list-speed: %s"
! 	       nnimap-group-list-speed))))))
! 
! (defun nnimap-pattern-to-list-arguments (pattern)
!   (mapcar (lambda (p) (if (consp p)
! 			  (cons (car p)
! 				(cdr p))
! 			(cons nil p)))
! 	  (if (and (listp pattern)
! 		   (listp (cdr pattern)))
! 	      pattern
! 	    (list pattern))))
! 
! ;;; Returns: GROUP HIGHEST LOWEST [ynmxj=]
! (deffoo nnimap-request-list (&optional server)
!   (when (nnimap-possibly-change-server server)
!     (with-current-buffer nntp-server-buffer (erase-buffer))
!     (with-current-buffer nnimap-server-buffer
!       (let* ((patterns (nnimap-pattern-to-list-arguments nnimap-list-pattern))
! 	     pattern)
! 	(gnus-message 5 "Generating active list for %s" server)
! 	(while (setq pattern (pop patterns))
! 	  (imap-mailbox-list nil (cdr pattern) t (car pattern))
! 	  (let ((nnimap-group-list-speed 'fast))
! 	    (imap-mailbox-map 'nnimap-request-list-mapper))))
!       t)))
  
  
  ;;; Interface functions, optional backend functions
--- 875,895 ----
    (unless (or (member "\\NoSelect" (imap-mailbox-get 'list-flags group))
  	      ;; We ignore groups with spaces (Gnus can't handle them)
  	      (string-match " " group))
!     (gnus-message 7 "Generating active list for nnimap group %s" group)
!     (when (imap-mailbox-select group)
!       (let ((exists (imap-mailbox-get 'exists))
! 	    articles)
! 	(if (eq 0 exists)
! 	    (with-current-buffer nntp-server-buffer
! 	      (insert (format "%s 0 1 y\n" group)))
! 	  (when (nnimap-ok-p (nnimap-send-command-wait "FETCH 1,* (UID)"))
! 	    (imap-message-map (lambda (uid Uid)
! 				(push uid articles)) 'UID)
! 	    (with-current-buffer nntp-server-buffer
! 	      (insert (format "%s %d %d y\n" group
! 			      (apply 'max articles)
! 			      (apply 'min articles))))))
! 	t))))
  
  
  ;;; Interface functions, optional backend functions
***************
*** 1026,1052 ****
    ;; return articles not deleted
    articles)
  
- (deffoo nnimap-request-accept-article (group &optional server last)
-   (when (nnimap-possibly-change-server server)
-     (let (uid)
-       (if (string= nnimap-current-server nnimap-current-move-server)
- 	  ;; moving article within same server, speed it up...
- 	  (when (nnimap-possibly-change-group nnimap-current-move-group)
- 	    (setq uid (imap-message-copy 
- 		       (number-to-string nnimap-current-move-article)
- 		       group nnimap-server-buffer)))
- 	;; turn into rfc822 format (\r\n eol's)
- 	(with-current-buffer (current-buffer)
- 	  (goto-char (point-min))
- 	  (while (re-search-forward "\n" nil t)
- 	    (replace-match "\r\n")))
- 	(setq uid (imap-message-append group (current-buffer)
- 				       nnimap-server-buffer)))
-       (and uid
- 	   (cons group (nth 1 uid))))))
- 
- ;; (deffoo nnimap-request-replace-article -- IMAP does not support replacing
- 
  
  ;;; Internal functions
  
--- 1035,1040 ----
***************
*** 1216,1249 ****
  		    (imap-mailbox-unselect))))))))
        imap-current-mailbox)))
  
- (eval-and-compile  
-   (if (not (fboundp 'destructive-plist-to-alist)) ;; From XEmacs subr.el 
-       (defun destructive-plist-to-alist (plist)
- 	"Convert property list PLIST into the equivalent
- association-list form.  The alist is returned.  This converts from
- 
- \(a 1 b 2 c 3)
- 
- into
- 
- \((a . 1) (b . 2) (c . 3))
- 
- The original plist is destroyed in the process of constructing the
- alist.  See also `plist-to-alist'."
- 	(let ((head plist)
- 	      next)
- 	  (while plist
- 	    ;; remember the next plist pair.
- 	    (setq next (cddr plist))
- 	    ;; make the cons holding the property value into the alist element.
- 	    (setcdr (cdr plist) (cadr plist))
- 	    (setcar (cdr plist) (car plist))
- 	    ;; reattach into alist form.
- 	    (setcar plist (cdr plist))
- 	    (setcdr plist next)
- 	    (setq plist next))
- 	  head))))
- 
  (when nnimap-debug
    (require 'trace)
    (buffer-disable-undo (get-buffer-create nnimap-debug))
--- 1204,1209 ----
***************
*** 1265,1271 ****
  gnus-group-nnimap-edit-acl
  gnus-group-nnimap-edit-acl-done
  nnimap-group-mode-hook
! nnimap-retrieve-headers-progress
  nnimap-retrieve-headers
  nnimap-open-server
  nnimap-close-server
--- 1225,1231 ----
  gnus-group-nnimap-edit-acl
  gnus-group-nnimap-edit-acl-done
  nnimap-group-mode-hook
! ;nnimap-retrieve-headers-progress
  nnimap-retrieve-headers
  nnimap-open-server
  nnimap-close-server
Index: nnimap/nnimap.texi
diff -c nnimap/nnimap.texi:1.20 nnimap/nnimap.texi:1.24
*** nnimap/nnimap.texi:1.20	Thu Jan 28 15:00:52 1999
--- nnimap/nnimap.texi	Fri May 14 08:03:07 1999
***************
*** 7,14 ****
  @setchapternewpage odd
  @paragraphindent 0
  
! @set VERSION $Revision: 1.1 $
! @set NNIMAP-VERSION 0.84
  
  @ifinfo
       This file documents nnimap, an Emacs Lisp package for accessing
--- 7,14 ----
  @setchapternewpage odd
  @paragraphindent 0
  
! @set VERSION $Revision: 1.1 $
! @set NNIMAP-VERSION 0.100
  
  @ifinfo
       This file documents nnimap, an Emacs Lisp package for accessing
***************
*** 62,67 ****
--- 62,71 ----
  Please note that nnimap require that you use the latest Gnus series,
  called Pterodactyl Gnus.
  
+ Also note that nnimap isn't so much different from other backends in
+ Gnus, so this documentation sort of assumes that you're familiar with
+ basic concepts in Gnus.
+ 
  To use nnimap, you should
  @enumerate
  @item
***************
*** 86,91 ****
--- 90,96 ----
  * config:: Configuring nnimap
  * using:: Using nnimap
  * trix:: Neat tricks
+ * bugreporting:: Reporting bugs
  * contributors:: Contributors
  * concepts:: Concept Index
  * variables:: Variable and Function Index
***************
*** 177,199 ****
        '((nnfolder "")
          (nnimap "dada"
                  (nnimap-address "cyrus.andrew.cmu.edu")
                  (nnimap-list-pattern ("INBOX" "archive.*")))
          (nnimap "yoyo"
                  (nnimap-stream ssl)
                  (nnimap-address "your.mail.server"))))
  @end lisp
  
! The nnimap server variables used above are described below:
! @itemize @bullet
! @item
! @ref{config-address}.
! @item
! @ref{config-list-pattern}.
! @item
! @ref{config-stream}.
! @item
! @ref{config-authenticator}.
! @end itemize
  
  Now when Gnus starts, it will ask you for a username/password for each
  IMAP server.
--- 182,195 ----
        '((nnfolder "")
          (nnimap "dada"
                  (nnimap-address "cyrus.andrew.cmu.edu")
+                 (nnimap-authenticator anonymous)
                  (nnimap-list-pattern ("INBOX" "archive.*")))
          (nnimap "yoyo"
                  (nnimap-stream ssl)
                  (nnimap-address "your.mail.server"))))
  @end lisp
  
! The server variables used above are explained later on.
  
  Now when Gnus starts, it will ask you for a username/password for each
  IMAP server.
***************
*** 208,213 ****
--- 204,210 ----
  * config-expiring:: Expiring Mail
  * config-krb:: Required programs for kerberos
  * config-ssl:: Required programs for ssl
+ * debug:: Debugging
  @end menu
  
  @node config-authinfo, config-server, , config
***************
*** 238,243 ****
--- 235,243 ----
  default login anonymous password arne@@domain.org
  @end example
  
+ Unfortunely there is no known way to have a login/password containing
+ space.
+ 
  @node config-server, config-splitting, config-authinfo, config
  @section Server variables
  @cindex Server variables
***************
*** 528,542 ****
  containing the headers of the article. It should return a non-nil value
  if it thinks that the mail belongs in that group.
  
! The last of these groups should always be a general one, and the regular
! expression should always be `' so that it matches any mails that haven't
! been matched by any of the other regexps.
  
  These rules are processed from the beginning of the alist toward the
  end. The first rule to make a match will "win", unless you have
  crossposting enabled. In that case, all matching rules will "win".
  
! The splitting code tries to create mailboxes if it has too.
  
  Nnmail equivalent: @code{nnmail-split-methods}.
  
--- 528,545 ----
  containing the headers of the article. It should return a non-nil value
  if it thinks that the mail belongs in that group.
  
! Nnmail users might recollect that the last regexp had to be empty to
! match all articles (like in the example above). This is not required in
! nnimap. Articles not matching any of the regexps will not be moved out
! of your inbox. (This might might affect performance if you keep lots of
! unread articles in your inbox, since the splitting code would go over
! them every time you fetch new mail.)
  
  These rules are processed from the beginning of the alist toward the
  end. The first rule to make a match will "win", unless you have
  crossposting enabled. In that case, all matching rules will "win".
  
! The splitting code tries to create mailboxes if it need too.
  
  Nnmail equivalent: @code{nnmail-split-methods}.
  
***************
*** 565,573 ****
  or set the @code{auto-expire}, @code{total-expire} group parameters on
  nnimap folders to enable expiring.
  
! (The reasoning behind the decision to use nnmail variables is that these
! variables are set by Gnus when you set the @code{expiry-wait} group
! parameter.)
  
  @node config-krb, config-ssl, config-expiring, config
  @section Required programs for kerberos
--- 568,576 ----
  or set the @code{auto-expire}, @code{total-expire} group parameters on
  nnimap folders to enable expiring.
  
! (The reasoning behind the decision to use nnmail variables instead of
! defining `nnimap-expiry-wait' is that `nnmail-expiry-wait' are set by
! Gnus when you customize the @code{expiry-wait} group parameter.)
  
  @node config-krb, config-ssl, config-expiring, config
  @section Required programs for kerberos
***************
*** 580,586 ****
  program @code{imtest} which comes with Cyrus IMAPD
  (@url{http://andrew2.andrew.cmu.edu/cyrus/}) in your path.
  
! @node config-ssl, , config-krb, config
  @section Required programs for ssl
  @cindex ssl
  @cindex using ssl
--- 583,589 ----
  program @code{imtest} which comes with Cyrus IMAPD
  (@url{http://andrew2.andrew.cmu.edu/cyrus/}) in your path.
  
! @node config-ssl, debug, config-krb, config
  @section Required programs for ssl
  @cindex ssl
  @cindex using ssl
***************
*** 590,595 ****
--- 593,622 ----
  For SSL encryption you need to have the external program @code{s_client},
  which comes with SSLeay (@url{http://www.ssleay.org/},) in your path.
  
+ @node debug, , config-ssl, config
+ @section Debugging
+ @vindex imap-debug
+ @vindex imap-log
+ @vindex nnimap-debug
+ 
+ Nnimap has a detailed logging/debugging capability, most are by default
+ turned on. These are controlled by three variables. If you set the
+ variable to nil you're disabling it (things will go faster but you'll be
+ unable to make good bug reports).
+ 
+ @table @code
+ 
+ @item imap-log
+ Contains name of buffer to hold the log of IMAP conversation between
+ nnimap and the IMAP server. It defaults to @code{*imap-log*}.
+ @item imap-debug
+ Contains name of buffer to hold elisp tracing of the imap
+ library. Defaults to nil.
+ @item nnimap-debug
+ Contains name of buffer to hold elisp tracing of nnimap. Defaults to
+ @code{*nnimap-debug*}.
+ @end table
+ 
  @node using, trix, config, Top
  @chapter Using nnimap
  @cindex using nnimap
***************
*** 685,691 ****
  
  Currently there is no way of showing deleted articles.
  
! @node trix, contributors, using, Top
  @chapter Neat tricks
  @ifinfo
  @menu
--- 712,718 ----
  
  Currently there is no way of showing deleted articles.
  
! @node trix, bugreporting, using, Top
  @chapter Neat tricks
  @ifinfo
  @menu
***************
*** 741,752 ****
  Are you using nnimap from home, over a dialup connection?  Then maybe
  "Article Caching", another Gnus feature, is for you.
  
! You should really read the
! Gnus manual on
! Article Caching to get the whole picture,
! (at @url{"http://www.gnus.org/manual/gnus_3.html#SEC76},)
! but here is a simple setup
! for your convenience:
  
  @lisp
  (setq gnus-use-cache t)
--- 768,775 ----
  Are you using nnimap from home, over a dialup connection?  Then maybe
  "Article Caching", another Gnus feature, is for you.
  
! You should really read the Gnus manual on Article Caching to get the
! whole picture, but here is a simple setup for your convenience:
  
  @lisp
  (setq gnus-use-cache t)
***************
*** 819,833 ****
  Now you should be able to connect to your IMAP server securely to read
  your mail, which, by the way, has been sent in clear-text through the
  entire internet.
  
! @node contributors, concepts, trix, Top
  @chapter Contributors
  
  Numerous people have helped the nnimap project, here I list people who
  have written code, sent bug reports and other things. Apologies to
  everybody I've forgotten.
  
! John Prevost, Jim Radford, Simon Josefsson, Marty Fouts, Jake Colman.
  
  @node concepts, variables, contributors, Top
  @unnumbered Concept Index
--- 842,869 ----
  Now you should be able to connect to your IMAP server securely to read
  your mail, which, by the way, has been sent in clear-text through the
  entire internet.
+ 
+ @node bugreporting, contributors, trix, Top
+ @chapter Reporting bugs
+ 
+ Bug reports are highly appreciated of course. When debugging a problem
+ it's very useful to be able to see the content of your @code{*imap-log*}
+ and @code{*nnimap-debug*} buffers.
+ 
+ A good way to generate debug buffers containing relevant information is
+ to start your gnus, kill your debug buffers and perform whatever tasks
+ to trigger the bug. Save your buffers and mail'em of to the nnimap
+ mailing list.
  
! @node contributors, concepts, bugreporting, Top
  @chapter Contributors
  
  Numerous people have helped the nnimap project, here I list people who
  have written code, sent bug reports and other things. Apologies to
  everybody I've forgotten.
  
! John Prevost, Jim Radford, Marty Fouts, Jake Colman, Jeff Senn, Trung
! Tran-Duc, Matt Armstrong, Keisuke Mori.
  
  @node concepts, variables, contributors, Top
  @unnumbered Concept Index