diff lisp/vm/vm-pop.el @ 24:4103f0995bd7 r19-15b95

Import from CVS: tag r19-15b95
author cvs
date Mon, 13 Aug 2007 08:51:03 +0200
parents 859a2309aef8
children 441bb1e64a06
line wrap: on
line diff
--- a/lisp/vm/vm-pop.el	Mon Aug 13 08:50:31 2007 +0200
+++ b/lisp/vm/vm-pop.el	Mon Aug 13 08:51:03 2007 +0200
@@ -24,19 +24,125 @@
   (let ((process nil)
 	(folder-type vm-folder-type)
 	(saved-password t)
+	(m-per-session vm-pop-messages-per-session)
+	(b-per-session vm-pop-bytes-per-session)
 	(handler (and (fboundp 'find-file-name-handler)
 		      (condition-case ()
 			  (find-file-name-handler source 'vm-pop-move-mail)
 			(wrong-number-of-arguments
 			  (find-file-name-handler source)))))
 	(popdrop (vm-safe-popdrop-string source))
-	greeting timestamp n message-count
-	host port auth user pass source-list process-buffer)
+	mailbox-count mailbox-size message-size response
+	n retrieved retrieved-bytes process-buffer)
     (unwind-protect
 	(catch 'done
 	  (if handler
 	      (throw 'done
 		     (funcall handler 'vm-pop-move-mail source destination)))
+	  (setq process (vm-pop-make-session source))
+	  (or process (throw 'done nil))
+	  (setq process-buffer (process-buffer process))
+	  (save-excursion
+	    (set-buffer process-buffer)
+	    (setq vm-folder-type (or folder-type vm-default-folder-type))
+	    ;; find out how many messages are in the box.
+	    (vm-pop-send-command process "STAT")
+	    (setq response (vm-pop-read-stat-response process)
+		  mailbox-count (nth 0 response)
+		  mailbox-size (nth 1 response))
+	    ;; forget it if the command fails
+	    ;; or if there are no messages present.
+	    (if (or (null mailbox-count)
+		    (< mailbox-count 1))
+		(throw 'done nil))
+	    ;; loop through the maildrop retrieving and deleting
+	    ;; messages as we go.
+	    (setq n 1 retrieved 0 retrieved-bytes 0)
+	    (while (and (<= n mailbox-count)
+			(or (not (natnump m-per-session))
+			    (< retrieved m-per-session))
+			(or (not (natnump b-per-session))
+			    (< retrieved-bytes b-per-session)))
+	      (if (or vm-pop-max-message-size
+		      b-per-session)
+		  (progn
+		    (vm-pop-send-command process (format "LIST %d" n))
+		    (setq message-size
+			  (vm-pop-read-list-response process))))
+	      (if (and (integerp vm-pop-max-message-size)
+		       (> message-size vm-pop-max-message-size)
+		       (progn
+			 (setq response
+			       (if vm-pop-ok-to-ask
+				   (vm-pop-ask-about-large-message process
+								   message-size
+								   n)
+				 'skip))
+			 (not (eq response 'retrieve))))
+		  (if (eq response 'delete)
+		      (progn
+			(message "Deleting message %d..." n)
+			(vm-pop-send-command process (format "DELE %d" n))
+			(and (null (vm-pop-read-response process))
+			     (throw 'done (not (equal retrieved 0)))))
+		    (if vm-pop-ok-to-ask
+			(message "Skipping message %d..." n)
+	     (message "Skipping message %d in %s, too large (%d > %d)..."
+		      n popdrop message-size vm-pop-max-message-size)))
+		(message "Retrieving message %d (of %d) from %s..."
+			 n mailbox-count popdrop)
+		(vm-pop-send-command process (format "RETR %d" n))
+		(and (null (vm-pop-read-response process))
+		     (throw 'done (not (equal retrieved 0))))
+		(and (null (vm-pop-retrieve-to-crashbox process destination))
+		     (throw 'done (not (equal retrieved 0))))
+		(vm-increment retrieved)
+		(and b-per-session
+		     (setq retrieved-bytes (+ retrieved-bytes message-size)))
+		(vm-pop-send-command process (format "DELE %d" n))
+		;; DELE can't fail but Emacs or this code might
+		;; blow a gasket and spew filth down the
+		;; connection, so...
+		(and (null (vm-pop-read-response process))
+		     (throw 'done (not (equal retrieved 0)))))
+	      (vm-increment n))
+	     (not (equal retrieved 0)) ))
+      (if process
+	  (vm-pop-end-session process)))))
+
+(defun vm-pop-check-mail (source)
+  (let ((process nil)
+	(handler (and (fboundp 'find-file-name-handler)
+		      (condition-case ()
+			  (find-file-name-handler source 'vm-pop-check-mail)
+			(wrong-number-of-arguments
+			 (find-file-name-handler source)))))
+	response)
+    (unwind-protect
+	(save-excursion
+	  (catch 'done
+	    (if handler
+		(throw 'done
+		       (funcall handler 'vm-pop-check-mail source)))
+	    (setq process (vm-pop-make-session source))
+	    (or process (throw 'done nil))
+	    (set-buffer (process-buffer process))
+	    (vm-pop-send-command process "STAT")
+	    (setq response (vm-pop-read-stat-response process))
+	    (if (null response)
+		nil
+	      (not (equal 0 (car response))))))
+      (and process (vm-pop-end-session process)))))
+
+(defun vm-pop-make-session (source)
+  (let ((process-to-shutdown nil)
+	process
+	(saved-password t)
+	(popdrop (vm-safe-popdrop-string source))
+	greeting timestamp
+	host port auth user pass source-list process-buffer)
+    (unwind-protect
+	(catch 'done
 	  ;; parse the maildrop
 	  (setq source-list (vm-parse source "\\([^:]+\\):?")
 		host (nth 0 source-list)
@@ -67,16 +173,22 @@
 	      (progn
 		(setq pass (car (cdr (assoc source vm-pop-passwords))))
 		(if (null pass)
-		    (setq pass
-			  (vm-read-password
-			   (format "POP password for %s: "
-				   popdrop))
-			  vm-pop-passwords (cons (list source pass)
-						 vm-pop-passwords)
-			  saved-password t))))
+		    (if (null vm-pop-ok-to-ask)
+			(progn (message "Need password for %s" popdrop)
+			       (throw 'done nil))
+		      (setq pass
+			    (vm-read-password
+			     (format "POP password for %s: "
+				     popdrop))
+			    vm-pop-passwords (cons (list source pass)
+						   vm-pop-passwords)
+			    saved-password t)))))
 	  ;; get the trace buffer
 	  (setq process-buffer
 		(get-buffer-create (format "trace of POP session to %s" host)))
+	  ;; Tell XEmacs/MULE not to mess with the text.
+	  (and (fboundp 'set-file-coding-system)
+	       (set-file-coding-system 'binary t))
 	  ;; clear the trace buffer of old output
 	  (save-excursion
 	    (set-buffer process-buffer)
@@ -84,14 +196,15 @@
 	  ;; open the connection to the server
 	  (setq process (open-network-stream "POP" process-buffer host port))
 	  (and (null process) (throw 'done nil))
-	  (set-process-filter process 'vm-pop-process-filter)
+	  (process-kill-without-query process)
 	  (save-excursion
 	    (set-buffer process-buffer)
 	    (make-local-variable 'vm-pop-read-point)
-	    (setq vm-pop-read-point (point-min)
-		  vm-folder-type (or folder-type vm-default-folder-type))
-	    (and (null (setq greeting (vm-pop-read-response process t)))
-		 (throw 'done nil))
+	    (setq vm-pop-read-point (point-min))
+	    (if (null (setq greeting (vm-pop-read-response process t)))
+		(progn (delete-process process)
+		       (throw 'done nil)))
+	    (setq process-to-shutdown process)
 	    ;; authentication
 	    (cond ((equal auth "pass")
 		   (vm-pop-send-command process (format "USER %s" user))
@@ -118,7 +231,7 @@
 		   (if (null timestamp)
 		       (progn
 			 (goto-char (point-max))
-		 (insert "<<< ooops, no timestamp found in greeting! >>>\n")
+   (insert-before-markers "<<< ooops, no timestamp found in greeting! >>>\n")
 			 (throw 'done nil)))
 		   (vm-pop-send-command
 		    process
@@ -128,51 +241,25 @@
 		   (and (null (vm-pop-read-response process))
 			(throw 'done nil)))
 		  (t (error "Don't know how to authenticate with %s" auth)))
-	    ;; find out how many messages are in the box.
-	    (vm-pop-send-command process "STAT")
-	    (setq message-count (vm-pop-read-stat-response process))
-	    ;; forget it if the command fails
-	    ;; or if there are no messages present.
-	    (if (or (null message-count)
-		    (< message-count 1))
-		(throw 'done nil))
-	    ;; loop through the maildrop retrieving and deleting
-	    ;; messages as we go.
-	    (setq n 1)
-	    (while (<= n message-count)
-	      (vm-unsaved-message "Retrieving message %d (of %d) from %s..."
-				  n message-count popdrop)
-	      (vm-pop-send-command process (format "RETR %d" n))
-	      (and (null (vm-pop-read-response process))
-		   (throw 'done (not (equal n 1))))
-	      (and (null (vm-pop-retrieve-to-crashbox process destination))
-		   (throw 'done (not (equal n 1))))
-	      (vm-pop-send-command process (format "DELE %d" n))
-	      ;; DELE can't fail but Emacs or this code might
-	      ;; blow a gasket and spew filth down the
-	      ;; connection, so...
-	      (and (null (vm-pop-read-response process))
-		   (throw 'done (not (equal n 1))))
-	      (vm-increment n))
-	     t ))
-      (if process
-	  (save-excursion
-	    (set-buffer (process-buffer process))
-	    (vm-pop-send-command process "QUIT")
-	    (vm-pop-read-response process)
-	    (delete-process process))))))
+	    (setq process-to-shutdown nil)
+	    process ))
+      (if process-to-shutdown
+	  (vm-pop-end-session process-to-shutdown)))))
 
-(defun vm-pop-process-filter (process output)
+(defun vm-pop-end-session (process)
   (save-excursion
     (set-buffer (process-buffer process))
-    (goto-char (point-max))
-    (insert output)))
+    (vm-pop-send-command process "QUIT")
+    (vm-pop-read-response process)
+    (if (fboundp 'add-async-timeout)
+	(add-async-timeout 2 'delete-process process)
+      (run-at-time 2 nil 'delete-process process))))
 
 (defun vm-pop-send-command (process command)
   (goto-char (point-max))
   (if (= (aref command 0) ?P)
-      (insert "PASS <omitted>\r\n")
-    (insert command "\r\n"))
+      (insert-before-markers "PASS <omitted>\r\n")
+    (insert-before-markers command "\r\n"))
   (setq vm-pop-read-point (point))
   (process-send-string process command)
   (process-send-string process "\r\n"))
@@ -193,16 +280,72 @@
 	  (buffer-substring (point) match-end)
 	t ))))
 
+(defun vm-pop-read-past-dot-sentinel-line (process)
+  (let ((case-fold-search nil))
+    (goto-char vm-pop-read-point)
+    (while (not (search-forward "^.\r\n" nil 0))
+      (beginning-of-line)
+      ;; save-excursion doesn't work right
+      (let ((opoint (point)))
+	(accept-process-output process)
+	(goto-char opoint)))
+    (setq vm-pop-read-point (point))))
+
 (defun vm-pop-read-stat-response (process)
+  (let ((response (vm-pop-read-response process t))
+	list)
+    (setq list (vm-parse response "\\([^ ]+\\) *"))
+    (list (string-to-int (nth 1 list)) (string-to-int (nth 2 list)))))
+
+(defun vm-pop-read-list-response (process)
   (let ((response (vm-pop-read-response process t)))
-    (string-to-int (nth 1 (vm-parse response "\\([^ ]+\\) *")))))
+    (string-to-int (nth 2 (vm-parse response "\\([^ ]+\\) *")))))
+
+(defun vm-pop-ask-about-large-message (process size n)
+  (let ((work-buffer nil)
+	(pop-buffer (current-buffer))
+	start end)
+    (unwind-protect
+	(save-excursion
+	  (save-window-excursion
+	    (vm-pop-send-command process (format "TOP %d %d" n 0))
+	    (if (vm-pop-read-response process)
+		(progn
+		  (setq start vm-pop-read-point)
+		  (vm-pop-read-past-dot-sentinel-line process)
+		  (setq end vm-pop-read-point)
+		  (setq work-buffer (generate-new-buffer "*pop-glop*"))
+		  (set-buffer work-buffer)
+		  (insert-buffer-substring pop-buffer start end)
+		  (forward-line -1)
+		  (delete-region (point) (point-max))
+		  (vm-pop-cleanup-region (point-min) (point-max))
+		  (vm-display-buffer work-buffer)
+		  (setq minibuffer-scroll-window (selected-window))
+		  (goto-char (point-min))
+		  (if (re-search-forward "^Received:" nil t)
+		      (progn
+			(goto-char (match-beginning 0))
+			(vm-reorder-message-headers
+			 nil vm-visible-headers
+			 vm-invisible-header-regexp)))
+		  (set-window-point (selected-window) (point))))
+	    (if (y-or-n-p (format "Message %d, size = %d, retrieve? " n size))
+		'retrieve
+	      (if (y-or-n-p (format "Delete message %d from popdrop? " n size))
+		  'delete
+		'skip))))
+      (and work-buffer (kill-buffer work-buffer)))))
 
 (defun vm-pop-retrieve-to-crashbox (process crash)
   (let ((start vm-pop-read-point) end)
     (goto-char start)
-    (while (not (re-search-forward "^\\.\r\n" nil t))
-      (accept-process-output process)
-      (goto-char start))
+    (while (not (re-search-forward "^\\.\r\n" nil 0))
+      (beginning-of-line)
+      ;; save-excursion doesn't work right
+      (let ((opoint (point)))
+	(accept-process-output process)
+	(goto-char opoint)))
     (setq vm-pop-read-point (point-marker))
     (goto-char (match-beginning 0))
     (setq end (point-marker))