;;; pop3.el --- Post Office Protocol (RFC 1460) interface
-;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002
-;; Free Software Foundation, Inc.
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
+;; 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
;; Author: Richard L. Pieri <ratinox@peorth.gweep.net>
;; Maintainer: FSF
;; This file is part of GNU Emacs.
-;; GNU Emacs is free software; you can redistribute it and/or modify
+;; GNU Emacs is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 2, or (at your option)
-;; any later version.
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING. If not, write to the
-;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;;; Code:
+(eval-when-compile (require 'cl))
(require 'mail-utils)
-
-(defvar pop3-maildrop (or (user-login-name) (getenv "LOGNAME") (getenv "USER") nil)
- "*POP3 maildrop.")
-(defvar pop3-mailhost (or (getenv "MAILHOST") nil)
- "*POP3 mailhost.")
-(defvar pop3-port 110
- "*POP3 port.")
-
-(defvar pop3-password-required t
- "*Non-nil if a password is required when connecting to POP server.")
+(defvar parse-time-months)
+
+(defgroup pop3 nil
+ "Post Office Protocol."
+ :group 'mail
+ :group 'mail-source)
+
+(defcustom pop3-maildrop (or (user-login-name)
+ (getenv "LOGNAME")
+ (getenv "USER"))
+ "*POP3 maildrop."
+ :version "22.1" ;; Oort Gnus
+ :type 'string
+ :group 'pop3)
+
+(defcustom pop3-mailhost (or (getenv "MAILHOST") ;; nil -> mismatch
+ "pop3")
+ "*POP3 mailhost."
+ :version "22.1" ;; Oort Gnus
+ :type 'string
+ :group 'pop3)
+
+(defcustom pop3-port 110
+ "*POP3 port."
+ :version "22.1" ;; Oort Gnus
+ :type 'number
+ :group 'pop3)
+
+(defcustom pop3-password-required t
+ "*Non-nil if a password is required when connecting to POP server."
+ :version "22.1" ;; Oort Gnus
+ :type 'boolean
+ :group 'pop3)
+
+;; Should this be customizable?
(defvar pop3-password nil
"*Password to use when connecting to POP server.")
-(defvar pop3-authentication-scheme 'pass
+(defcustom pop3-authentication-scheme 'pass
"*POP3 authentication scheme.
-Defaults to 'pass, for the standard USER/PASS authentication. Other valid
-values are 'apop.")
+Defaults to `pass', for the standard USER/PASS authentication. The other
+valid value is 'apop'."
+ :type '(choice (const :tag "Normal user/password" pass)
+ (const :tag "APOP" apop))
+ :version "22.1" ;; Oort Gnus
+ :group 'pop3)
+
+(defcustom pop3-stream-length 100
+ "How many messages should be requested at one time.
+The lower the number, the more latency-sensitive the fetching
+will be. If your pop3 server doesn't support streaming at all,
+set this to 1."
+ :type 'number
+ :version "24.1"
+ :group 'pop3)
+
+(defcustom pop3-leave-mail-on-server nil
+ "*Non-nil if the mail is to be left on the POP server after fetching.
+
+If `pop3-leave-mail-on-server' is non-nil the mail is to be left
+on the POP server after fetching. Note that POP servers maintain
+no state information between sessions, so what the client
+believes is there and what is actually there may not match up.
+If they do not, then you may get duplicate mails or the whole
+thing can fall apart and leave you with a corrupt mailbox."
+ ;; We can't use the UILD support from XEmacs mail-lib or cvs.m17n.org:
+ ;; http://thread.gmane.org/v9lld8fml4.fsf@marauder.physik.uni-ulm.de
+ ;; http://thread.gmane.org/b9yy8hzy9ej.fsf@jpl.org
+ ;; Any volunteer to re-implement this?
+ :version "22.1" ;; Oort Gnus
+ :type 'boolean
+ :group 'pop3)
(defvar pop3-timestamp nil
"Timestamp returned when initially connected to the POP server.
(defvar pop3-read-point nil)
(defvar pop3-debug nil)
-(defun pop3-movemail (&optional crashbox)
- "Transfer contents of a maildrop to the specified CRASHBOX."
- (or crashbox (setq crashbox (expand-file-name "~/.crashbox")))
+;; Borrowed from nnheader-accept-process-output in nnheader.el. See the
+;; comments there for explanations about the values.
+
+(eval-and-compile
+ (if (and (fboundp 'nnheader-accept-process-output)
+ (boundp 'nnheader-read-timeout))
+ (defalias 'pop3-accept-process-output 'nnheader-accept-process-output)
+ ;; Borrowed from `nnheader.el':
+ (defvar pop3-read-timeout
+ (if (string-match "windows-nt\\|os/2\\|cygwin"
+ (symbol-name system-type))
+ 1.0
+ 0.01)
+ "How long pop3 should wait between checking for the end of output.
+Shorter values mean quicker response, but are more CPU intensive.")
+ (defun pop3-accept-process-output (process)
+ (accept-process-output
+ process
+ (truncate pop3-read-timeout)
+ (truncate (* (- pop3-read-timeout
+ (truncate pop3-read-timeout))
+ 1000))))))
+
+;;;###autoload
+(defun pop3-movemail (file)
+ "Transfer contents of a maildrop to the specified FILE.
+Use streaming commands."
(let* ((process (pop3-open-server pop3-mailhost pop3-port))
- (crashbuf (get-buffer-create " *pop3-retr*"))
- (n 1)
- message-count
- (pop3-password pop3-password)
- )
+ message-count message-total-size)
+ (pop3-logon process)
+ (with-current-buffer (process-buffer process)
+ (let ((size (pop3-stat process)))
+ (setq message-count (car size)
+ message-total-size (cadr size)))
+ (when (> message-count 0)
+ (pop3-send-streaming-command
+ process "RETR" message-count message-total-size)
+ (pop3-write-to-file file)
+ (unless pop3-leave-mail-on-server
+ (pop3-send-streaming-command
+ process "DELE" message-count nil))))
+ (pop3-quit process)
+ t))
+
+(defun pop3-send-streaming-command (process command count total-size)
+ (erase-buffer)
+ (let ((i 1))
+ (while (>= count i)
+ (process-send-string process (format "%s %d\r\n" command i))
+ ;; Only do 100 messages at a time to avoid pipe stalls.
+ (when (zerop (% i pop3-stream-length))
+ (pop3-wait-for-messages process i total-size))
+ (incf i)))
+ (pop3-wait-for-messages process count total-size))
+
+(defun pop3-wait-for-messages (process count total-size)
+ (while (< (pop3-number-of-responses total-size) count)
+ (when total-size
+ (message "pop3 retrieved %dKB (%d%%)"
+ (truncate (/ (