T-gnus 6.14.2.
[elisp/gnus.git-] / lisp / pop3.el
1 ;;; pop3.el --- Post Office Protocol (RFC 1460) interface
2
3 ;; Copyright (C) 1996, 97, 98, 1999 Free Software Foundation, Inc.
4
5 ;; Author: Richard L. Pieri <ratinox@peorth.gweep.net>
6 ;;      Daiki Ueno  <ueno@ueda.info.waseda.ac.jp>
7 ;; Maintainer: FSF
8 ;; Keywords: mail
9 ;; Version: 1.3s
10
11 ;; This file is part of GNU Emacs.
12
13 ;; GNU Emacs is free software; you can redistribute it and/or modify
14 ;; it under the terms of the GNU General Public License as published by
15 ;; the Free Software Foundation; either version 2, or (at your option)
16 ;; any later version.
17
18 ;; GNU Emacs is distributed in the hope that it will be useful,
19 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 ;; GNU General Public License for more details.
22
23 ;; You should have received a copy of the GNU General Public License
24 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
25 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
26 ;; Boston, MA 02111-1307, USA.
27
28 ;;; Commentary:
29
30 ;; Most of the standard Post Office Protocol version 3 (RFC 1460) commands
31 ;; are implemented.  The LIST command has not been implemented due to lack
32 ;; of actual usefulness.
33 ;; The optional POP3 command TOP has not been implemented.
34
35 ;; This program was inspired by Kyle E. Jones's vm-pop program.
36
37 ;;; Code:
38
39 (eval-when-compile (require 'cl))
40 (eval-when-compile (require 'static))
41
42 (require 'mail-utils)
43
44 (defconst pop3-version "1.3s")
45
46 (defvar pop3-maildrop (or (user-login-name) (getenv "LOGNAME") (getenv "USER") nil)
47   "*POP3 maildrop.")
48 (defvar pop3-mailhost (or (getenv "MAILHOST") nil)
49   "*POP3 mailhost.")
50 (defvar pop3-port 110
51   "*POP3 port.")
52 (defvar pop3-connection-type nil
53   "*POP3 connection type.")
54
55 (defvar pop3-password-required t
56   "*Non-nil if a password is required when connecting to POP server.")
57 (defvar pop3-password nil
58   "*Password to use when connecting to POP server.")
59
60 (defvar pop3-authentication-scheme 'pass
61   "*POP3 authentication scheme.
62 Defaults to 'pass, for the standard USER/PASS authentication.  Other valid
63 values are 'apop.")
64
65 (defvar pop3-timestamp nil
66   "Timestamp returned when initially connected to the POP server.
67 Used for APOP authentication.")
68
69 (defvar pop3-leave-mail-on-server nil
70   "Non-nil if mail is to be left on the server and UIDL used for message retrieval.")
71
72 (defvar pop3-maximum-message-size nil
73   "If non-nil only download messages smaller than this.")
74
75 (defvar pop3-except-header-regexp nil
76   "If non-nil we do not retrieve messages whose headers are matching this regexp.")
77
78 (defvar pop3-uidl-file-name "~/.uidls"
79   "File in which to store the UIDL of processed messages.")
80
81 (defvar pop3-uidl-support 'dont-know
82   "Whether the server supports UIDL.
83 Nil means no, t means yes, not-nil-or-t means yet to be determined.")
84
85 (defvar pop3-uidl-obarray (make-vector 31 0)
86   "Uidl hash table.")
87
88 (defvar pop3-read-point nil)
89 (defvar pop3-debug nil)
90
91 (eval-and-compile
92   (autoload 'open-ssl-stream "ssl")
93   (autoload 'starttls-open-stream "starttls")
94   (autoload 'starttls-negotiate "starttls"))
95
96 (defvar pop3-ssl-program-arguments
97   '("s_client" "-quiet")
98   "Arguments to be passed to the program `pop3-ssl-program-name'.")
99
100 (defun pop3-progress-message (format percent &rest args)
101   (apply (function message) format args))
102
103 (defun pop3-movemail (&optional crashbox)
104   "Transfer contents of a maildrop to the specified CRASHBOX."
105   (or crashbox (setq crashbox (expand-file-name "~/.crashbox")))
106   (let* ((process (pop3-open-server pop3-mailhost pop3-port))
107          (crashbuf (get-buffer-create " *pop3-retr*"))
108          (n 1)
109          message-count
110          (pop3-password pop3-password)
111          (pop3-uidl-file-name (convert-standard-filename
112                                (concat pop3-uidl-file-name "-"
113                                        pop3-mailhost)))
114          retrieved-messages messages)
115     ;; for debugging only
116     (if pop3-debug (switch-to-buffer (process-buffer process)))
117     ;; query for password
118     (if (and pop3-password-required (not pop3-password))
119         (setq pop3-password
120               (pop3-read-passwd (format "Password for %s: " pop3-maildrop))))
121     (cond ((equal 'apop pop3-authentication-scheme)
122            (pop3-apop process pop3-maildrop))
123           ((equal 'pass pop3-authentication-scheme)
124            (pop3-user process pop3-maildrop)
125            (pop3-pass process))
126           (t (error "Invalid POP3 authentication scheme")))
127     ;; get messages that are suitable for download
128     (message "Retrieving message list...")
129     (setq messages (pop3-get-message-numbers process)
130           message-count (length (cdr messages)))
131     (message "Retrieving message list...%d of %d unread"
132              message-count (pop messages))
133     (unwind-protect
134         (unless (not (stringp crashbox))
135           (while messages
136             (pop3-progress-message
137              "Retrieving message %d of %d (%d octets) from %s..."
138              (floor (* (/ (float n) message-count) 100))
139              n message-count (cdar messages) pop3-mailhost)
140             (pop3-retr process (caar messages) crashbuf)
141             (push (caar messages) retrieved-messages)
142             (setq messages (cdr messages)
143                   n (1+ n)))
144           (with-current-buffer crashbuf
145             (write-region-as-binary (point-min) (point-max)
146                                     crashbox 'append 'nomesg))
147           ;; mark messages as read
148           (when pop3-leave-mail-on-server
149             (pop3-save-uidls))
150           ;; now delete the messages we have retrieved
151           (unless pop3-leave-mail-on-server
152             (dolist (n retrieved-messages)
153               (message "Deleting message %d of %d from %s..."
154                        n message-count pop3-mailhost)
155               (pop3-dele process n)))
156           )
157       (pop3-quit process))
158     (kill-buffer crashbuf)
159     message-count))
160
161 (defun pop3-open-server (mailhost port)
162   "Open TCP connection to MAILHOST on PORT.
163 Returns the process associated with the connection.
164 Argument PORT specifies connecting port."
165   (let (process)
166     (save-excursion
167       (set-buffer (get-buffer-create (concat " trace of POP session to %s"
168                                              mailhost)))
169       (erase-buffer)
170       (setq pop3-read-point (point-min))
171       (setq
172        process
173        (cond
174         ((eq pop3-connection-type 'ssl)
175          (pop3-open-ssl-stream "POP" (current-buffer) mailhost port))
176         ((eq pop3-connection-type 'tls)
177          (pop3-open-tls-stream "POP" (current-buffer) mailhost port))
178         (t
179          (open-network-stream-as-binary "POP" (current-buffer)
180                                         mailhost port))))
181       (let ((response (pop3-read-response process t)))
182         (setq pop3-timestamp
183               (substring response (or (string-match "<" response) 0)
184                          (+ 1 (or (string-match ">" response) -1)))))
185       process)))
186
187 (defun pop3-open-ssl-stream-1 (name buffer host service extra-arg)
188   (require 'path-util)
189   (let* ((ssl-program-name
190           (cond ((exec-installed-p "openssl")
191                  "openssl")
192                 (t
193                  "ssleay")))
194          (ssl-program-arguments
195           `(,@pop3-ssl-program-arguments ,extra-arg
196             "-connect" ,(format "%s:%d" host service)))
197          (process (open-ssl-stream name buffer host service)))
198     (when process
199       (with-current-buffer buffer
200         (goto-char (point-min))
201         (while (and (memq (process-status process) '(open run))
202                     (goto-char (point-max))
203                     (forward-line -1)
204                     (not (looking-at "+OK")))
205           (accept-process-output process 1)
206           (sit-for 1))
207         (delete-region (point-min) (point)))
208       (and process (memq (process-status process) '(open run))
209            process))))
210
211 (defun pop3-open-ssl-stream (name buffer host service)
212   "Open a SSL connection for a service to a host.
213 Returns a subprocess-object to represent the connection.
214 Args are NAME BUFFER HOST SERVICE."
215   (cond ((eq system-type 'windows-nt)
216          (let (selective-display
217                (coding-system-for-write 'binary)
218                (coding-system-for-read 'raw-text-dos))
219            (or (pop3-open-ssl-stream-1 name buffer host service "-ssl3")
220                (pop3-open-ssl-stream-1 name buffer host service "-ssl2"))))
221         (t
222          (as-binary-process
223            (or (pop3-open-ssl-stream-1 name buffer host service "-ssl3")
224                (pop3-open-ssl-stream-1 name buffer host service "-ssl2"))))))
225
226 (defun pop3-open-tls-stream (name buffer host service)
227   "Open a TLSv1 connection for a service to a host.
228 Returns a subprocess-object to represent the connection.
229 Args are NAME BUFFER HOST SERVICE."
230   (let ((process
231          (as-binary-process (starttls-open-stream
232                              name buffer host service))))
233     (pop3-stls process)
234     (starttls-negotiate process)
235     process))
236
237 ;; Support functions
238
239 (defun pop3-process-filter (process output)
240   (save-excursion
241     (set-buffer (process-buffer process))
242     (goto-char (point-max))
243     (insert output)))
244
245 (defun pop3-send-command (process command)
246     (set-buffer (process-buffer process))
247     (goto-char (point-max))
248 ;;    (if (= (aref command 0) ?P)
249 ;;      (insert "PASS <omitted>\r\n")
250 ;;      (insert command "\r\n"))
251     (setq pop3-read-point (point))
252     (goto-char (point-max))
253     (process-send-string process (concat command "\r\n"))
254     )
255
256 (defun pop3-read-response (process &optional return)
257   "Read the response from the server PROCESS.
258 Return the response string if optional second argument RETURN is non-nil."
259   (let ((case-fold-search nil)
260         match-end)
261     (save-excursion
262       (set-buffer (process-buffer process))
263       (goto-char pop3-read-point)
264       (while (not (search-forward "\r\n" nil t))
265         (accept-process-output process 3)
266         (goto-char pop3-read-point))
267       (setq match-end (point))
268       (goto-char pop3-read-point)
269       (if (looking-at "-ERR")
270           (error (buffer-substring (point) (- match-end 2)))
271         (if (not (looking-at "+OK"))
272             (progn (setq pop3-read-point match-end) nil)
273           (setq pop3-read-point match-end)
274           (if return
275               (buffer-substring (point) match-end)
276             t)
277           )))))
278
279 (defvar pop3-read-passwd nil)
280 (defun pop3-read-passwd (prompt)
281   (if (not pop3-read-passwd)
282       (if (fboundp 'read-passwd)
283           (setq pop3-read-passwd 'read-passwd)
284         (if (load "passwd" t)
285             (setq pop3-read-passwd 'read-passwd)
286           (autoload 'ange-ftp-read-passwd "ange-ftp")
287           (setq pop3-read-passwd 'ange-ftp-read-passwd))))
288   (funcall pop3-read-passwd prompt))
289
290 (defun pop3-clean-region (start end)
291   (setq end (set-marker (make-marker) end))
292   (save-excursion
293     (goto-char start)
294     (while (and (< (point) end) (search-forward "\r\n" end t))
295       (replace-match "\n" t t))
296     (goto-char start)
297     (while (re-search-forward "\n\n\\(From \\)" end t)
298       (replace-match "\n\n>\\1" t nil))
299     (goto-char start)
300     (while (and (< (point) end) (re-search-forward "^\\." end t))
301       (replace-match "" t t)
302       (forward-char)))
303   (set-marker end nil))
304
305 (defun pop3-munge-message-separator (start end)
306   "Check to see if a message separator exists.  If not, generate one."
307   (if (not (fboundp 'parse-time-string))
308       (autoload 'parse-time-string "parse-time"))
309   (save-excursion
310     (save-restriction
311       (narrow-to-region start end)
312       (goto-char (point-min))
313       (if (not (or (looking-at "From .?") ; Unix mail
314                    (looking-at "\001\001\001\001\n") ; MMDF
315                    (looking-at "BABYL OPTIONS:") ; Babyl
316                    ))
317           (let ((from (mail-strip-quoted-names (mail-fetch-field "From")))
318                 (date (mail-fetch-field "Date"))
319                 (From_))
320             ;; sample date formats I have seen
321             ;; Date: Tue, 9 Jul 1996 09:04:21 -0400 (EDT)
322             ;; Date: 08 Jul 1996 23:22:24 -0400
323             ;; should be
324             ;; Tue Jul 9 09:04:21 1996
325             (setq date (format-time-string
326                         "%a %b %e %T %Y"
327                         (if date
328                             (condition-case nil
329                                 (apply 'encode-time (parse-time-string date))
330                               (error (current-time)))
331                           (current-time))))
332             (setq From_ (format "\nFrom %s  %s\n" from date))
333             (while (string-match "," From_)
334               (setq From_ (concat (substring From_ 0 (match-beginning 0))
335                                   (substring From_ (match-end 0)))))
336             (goto-char (point-min))
337             (insert From_))))))
338
339 ;; UIDL support
340
341 (defun pop3-get-message-numbers (process)
342   "Get the list of message numbers and lengths to retrieve via PROCESS."
343   ;; we use the LIST comand first anyway to get the message lengths.
344   ;; then if we're leaving mail on the server, see if the UIDL command
345   ;; is implemented. if so, we use it to get the message number list.
346   (let* ((messages (pop3-list process))
347          (total (or (pop messages) 0))
348          (uidl (if pop3-leave-mail-on-server
349                    (pop3-get-uidl process)))
350          out)
351     (while messages
352       ;; only retrieve messages matching our regexp or in the uidl list
353       (when (and
354              ;; remove elements not in the uidl, this assumes the uidl is short
355              (or (not (eq pop3-uidl-support t))
356                  (memq (caar messages) uidl))
357              (caar messages)
358              ;; don't download messages that are too large
359              (not (and pop3-maximum-message-size
360                        (> (cdar messages) pop3-maximum-message-size)))
361              (not (and pop3-except-header-regexp
362                        (string-match pop3-except-header-regexp
363                                      (pop3-top process (caar messages) 0)))))
364         (push (car messages) out))
365       (setq messages (cdr messages)))
366     (cons total (reverse out))))
367
368 (defun pop3-get-uidl (process)
369   "Use PROCESS to get a list of unread message numbers."
370   (let ((messages (pop3-uidl process)) uidl)
371     (if (or (null messages) (null pop3-uidl-support))
372         (setq pop3-uidl-support nil)
373       (setq pop3-uidl-support t)
374       (save-excursion
375         (with-temp-buffer
376           (when (file-readable-p pop3-uidl-file-name)
377             (insert-file-contents pop3-uidl-file-name))
378           (goto-char (point-min))
379           (while (looking-at "\\([^ \n\t]+\\)")
380             (set (intern (match-string 1) pop3-uidl-obarray)
381                  (cons nil t))
382             (forward-line 1))
383           ))
384       (dolist (message (cdr messages))
385         (if (setq uidl (intern-soft (cdr message) pop3-uidl-obarray))
386             (setcar (symbol-value uidl) (car message))
387           (set (intern (cdr message) pop3-uidl-obarray)
388                (cons (car message) nil))))
389       (pop3-get-unread-message-numbers))
390     ))
391
392 (defun pop3-get-unread-message-numbers ()
393   "Return a sorted list of unread msg numbers to retrieve."
394   (let (nums)
395     (mapatoms (lambda (atom)
396                 (if (not (cdr (symbol-value atom)))
397                     (push (car (symbol-value atom)) nums)))
398               pop3-uidl-obarray)
399     (sort nums '<)))
400
401 (defun pop3-save-uidls ()
402   "Save the updated UIDLs to disk for use next time."
403   (when (and pop3-leave-mail-on-server
404              ;; UIDL hash table is non-empty
405              (let ((len (length pop3-uidl-obarray)))
406                (while (< 0 len)
407                  (setq len (if (symbolp (aref pop3-uidl-obarray (1- len)))
408                                -1 (1- len))))
409                (minusp len)))
410     (when (file-readable-p pop3-uidl-file-name)
411       (copy-file pop3-uidl-file-name
412                  (concat pop3-uidl-file-name ".old")
413                  'overwrite 'keeptime))
414     (save-excursion
415       (with-temp-file pop3-uidl-file-name
416         (mapatoms
417          (lambda (atom)
418            (when (car (symbol-value atom))
419              (insert (format "%s\n" atom))))
420          pop3-uidl-obarray)))))
421     
422
423 ;; The Command Set
424
425 ;; AUTHORIZATION STATE
426
427 (defun pop3-user (process user)
428   "Send USER information to POP3 server."
429   (pop3-send-command process (format "USER %s" user))
430   (let ((response (pop3-read-response process t)))
431     (if (not (and response (string-match "+OK" response)))
432         (error (format "USER %s not valid." user)))))
433
434 (defun pop3-pass (process)
435   "Send authentication information to the server."
436   (pop3-send-command process (format "PASS %s" pop3-password))
437   (let ((response (pop3-read-response process t)))
438     (if (not (and response (string-match "+OK" response)))
439         (pop3-quit process))))
440
441 (static-unless (and (fboundp 'md5) (subrp (symbol-function 'md5)))
442   (eval-and-compile
443     (require 'path-util)
444     (if (module-installed-p 'md5)
445         (progn
446           (autoload 'md5 "md5")
447           (fset 'pop3-md5 'md5))
448
449       (defvar pop3-md5-program "md5"
450         "*Program to encode its input in MD5.")
451
452       (defun pop3-md5 (string)
453         (with-temp-buffer
454           (insert string)
455           (call-process-region (point-min) (point-max)
456                                (or shell-file-name "/bin/sh")
457                                t (current-buffer) nil
458                                "-c" pop3-md5-program)
459           ;; The meaningful output is the first 32 characters.
460           ;; Don't return the newline that follows them!
461           (buffer-substring (point-min) (+ (point-min) 32))))
462       )))
463
464 (defun pop3-apop (process user)
465   "Send alternate authentication information to the server."
466   (let ((pass pop3-password))
467     (if (and pop3-password-required (not pass))
468         (setq pass
469               (pop3-read-passwd (format "Password for %s: " pop3-maildrop))))
470     (if pass
471         (let ((hash (static-if (and (fboundp 'md5)
472                                     (subrp (symbol-function 'md5)))
473                         (md5 (concat pop3-timestamp pass))
474                       (pop3-md5 (concat pop3-timestamp pass)))))
475           (pop3-send-command process (format "APOP %s %s" user hash))
476           (let ((response (pop3-read-response process t)))
477             (if (not (and response (string-match "+OK" response)))
478                 (pop3-quit process)))))
479     ))
480
481 (defun pop3-stls (process)
482   "Query whether TLS extension is supported"
483   (pop3-send-command process "STLS")
484   (let ((response (pop3-read-response process t)))
485     (if (not (and response (string-match "+OK" response)))
486         (pop3-quit process))))
487
488 ;; TRANSACTION STATE
489
490 (defun pop3-stat (process)
491   "Return the number of messages in the maildrop and the maildrop's size."
492   (pop3-send-command process "STAT")
493   (let ((response (pop3-read-response process t)))
494     (list (string-to-int (nth 1 (split-string response " ")))
495           (string-to-int (nth 2 (split-string response " "))))
496     ))
497
498 (defun pop3-retr (process msg crashbuf)
499   "Retrieve message-id MSG to buffer CRASHBUF."
500   (pop3-send-command process (format "RETR %s" msg))
501   (pop3-read-response process)
502   (save-excursion
503     (let ((region (pop3-get-extended-response process)))
504       (pop3-munge-message-separator (car region) (cadr region))
505       (append-to-buffer crashbuf (car region) (cadr region))
506       (delete-region (car region) (cadr region))
507       )))
508
509 (defun pop3-dele (process msg)
510   "Mark message-id MSG as deleted."
511   (pop3-send-command process (format "DELE %s" msg))
512   (pop3-read-response process))
513
514 (defun pop3-noop (process msg)
515   "No-operation."
516   (pop3-send-command process "NOOP")
517   (pop3-read-response process))
518
519 (defun pop3-last (process)
520   "Return highest accessed message-id number for the session."
521   (pop3-send-command process "LAST")
522   (let ((response (pop3-read-response process t)))
523     (string-to-int (nth 1 (split-string response " ")))
524     ))
525
526 (defun pop3-rset (process)
527   "Remove all delete marks from current maildrop."
528   (pop3-send-command process "RSET")
529   (pop3-read-response process))
530
531 ;; UPDATE
532
533 (defun pop3-quit (process)
534   "Close connection to POP3 server.
535 Tell server to remove all messages marked as deleted, unlock the maildrop,
536 and close the connection."
537   (pop3-send-command process "QUIT")
538   (pop3-read-response process t)
539   (when process
540     (save-excursion
541       (set-buffer (process-buffer process))
542       (goto-char (point-max))
543       (delete-process process)
544       ))
545   (when pop3-leave-mail-on-server
546     (mapatoms
547      (lambda (atom)
548        (when (car (symbol-value atom))
549          (unintern atom pop3-uidl-obarray)))
550      pop3-uidl-obarray)))
551
552 (defun pop3-uidl (process &optional msgno)
553   "Return the results of a UIDL command in PROCESS for optional MSGNO.
554 If UIDL is unsupported on this mail server or if msgno is invalid, return nil.
555 Otherwise, return a list in the form
556
557    (N (1 UIDL-1) (2 UIDL-2) ... (N UIDL-N))
558
559 where
560
561    N is an integer for the number of UIDLs returned (could be 0)
562    UIDL-n is a string."
563
564   (if msgno
565       (pop3-send-command process (format "UIDL %d" msgno))
566     (pop3-send-command process "UIDL"))
567   
568   (if (null (pop3-read-response process t))
569       nil ;; UIDL is not supported on this server
570     (let (pairs uidl)
571       (save-excursion
572         (save-restriction
573           (apply 'narrow-to-region (pop3-get-extended-response process))
574           (goto-char (point-min))
575           (while (looking-at "\\([^ \n\t]*\\) \\([^ \n\t]*\\)")
576             (setq msgno (string-to-int (match-string 1))
577                   uidl (match-string 2))
578             (push (cons msgno uidl) pairs)
579             (beginning-of-line 2))
580           (cons (length pairs) (nreverse pairs))
581           )))))
582
583 (defun pop3-list (process &optional msgno)
584   "Return the results of a LIST command for PROCESS and optional MSGNO.
585 If (optional) msgno is invalid, return nil.  Otherwise, return a list
586 in the form
587
588    (N (1 LEN-1) (2 LEN-2) ... (N LEN-N))
589
590 where
591
592    N is an integer for the number of msg/len pairs (could be 0)
593    LEN-n is an integer."
594   (if msgno
595       (pop3-send-command process (format "LIST %d" msgno))
596     (pop3-send-command process "LIST"))
597
598   (if (null (pop3-read-response process t))
599       nil ;; MSGNO is not valid number
600     (let (pairs len)
601       (save-excursion
602         (save-restriction
603           (apply 'narrow-to-region (pop3-get-extended-response process))
604           (goto-char (point-min))
605           (while (looking-at "\\([^ \n\t]*\\) \\([^ \n\t]*\\)")
606             (setq msgno (string-to-int (match-string 1))
607                   len (string-to-int (match-string 2)))
608             (push (cons msgno len) pairs)
609             (beginning-of-line 2))
610           (cons (length pairs) (nreverse pairs))
611           )))))
612
613 (defun pop3-top (process msgno &optional lines)
614   "Return the top LINES of messages for PROCESS and MSGNO.
615 If msgno is invalid, return nil.  Otherwise, return a string."
616   (pop3-send-command process (format "TOP %d %d" msgno (or lines 1)))
617   (if (pop3-read-response process t)
618       nil ;; MSGNO is not valid number
619     (save-excursion
620       (apply 'buffer-substring (pop3-get-extended-response process)))
621     ))
622
623 ;;; Utility code
624
625 (defun pop3-get-extended-response (process)
626   "Get the extended pop3 response in the PROCESS buffer."
627   (let ((start pop3-read-point) end)
628     (set-buffer (process-buffer process))
629     (goto-char start)
630     (while (not (re-search-forward "^\\.\r\n" nil t))
631       (accept-process-output process 3)
632       (goto-char start))
633     (setq pop3-read-point (point-marker))
634     (goto-char (match-beginning 0))
635     (setq end (point-marker))
636     (pop3-clean-region start end)
637     (list start end)))
638
639 \f
640 ;; Summary of POP3 (Post Office Protocol version 3) commands and responses
641
642 ;;; AUTHORIZATION STATE
643
644 ;; Initial TCP connection
645 ;; Arguments: none
646 ;; Restrictions: none
647 ;; Possible responses:
648 ;;  +OK [POP3 server ready]
649
650 ;; USER name
651 ;; Arguments: a server specific user-id (required)
652 ;; Restrictions: authorization state [after unsuccessful USER or PASS
653 ;; Possible responses:
654 ;;  +OK [valid user-id]
655 ;;  -ERR [invalid user-id]
656
657 ;; PASS string
658 ;; Arguments: a server/user-id specific password (required)
659 ;; Restrictions: authorization state, after successful USER
660 ;; Possible responses:
661 ;;  +OK [maildrop locked and ready]
662 ;;  -ERR [invalid password]
663 ;;  -ERR [unable to lock maildrop]
664
665 ;; STLS
666 ;; Arguments: none
667 ;; Restrictions: authorization state
668 ;; Possible responses:
669 ;;  +OK [negotiation is ready]
670 ;;  -ERR [security layer is already active]
671
672 ;;; TRANSACTION STATE
673
674 ;; STAT
675 ;; Arguments: none
676 ;; Restrictions: transaction state
677 ;; Possible responses:
678 ;;  +OK nn mm [# of messages, size of maildrop]
679
680 ;; LIST [msg]
681 ;; Arguments: a message-id (optional)
682 ;; Restrictions: transaction state; msg must not be deleted
683 ;; Possible responses:
684 ;;  +OK [scan listing follows]
685 ;;  -ERR [no such message]
686
687 ;; TOP msg [lines]
688 ;; Arguments: a message-id (required), number of lines (optional)
689 ;; Restrictions: transaction state; msg must not be deleted
690 ;; Possible responses:
691 ;;  +OK [partial message listing follows]
692 ;;  -ERR [no such message]
693
694 ;; UIDL [msg]
695 ;; Arguments: a message-id (optional)
696 ;; Restrictions: transaction state; msg must not be deleted
697 ;; Possible responses:
698 ;;  +OK [uidl listing follows]
699 ;;  -ERR [no such message]
700
701 ;; RETR msg
702 ;; Arguments: a message-id (required)
703 ;; Restrictions: transaction state; msg must not be deleted
704 ;; Possible responses:
705 ;;  +OK [message contents follow]
706 ;;  -ERR [no such message]
707
708 ;; DELE msg
709 ;; Arguments: a message-id (required)
710 ;; Restrictions: transaction state; msg must not be deleted
711 ;; Possible responses:
712 ;;  +OK [message deleted]
713 ;;  -ERR [no such message]
714
715 ;; NOOP
716 ;; Arguments: none
717 ;; Restrictions: transaction state
718 ;; Possible responses:
719 ;;  +OK
720
721 ;; LAST
722 ;; Arguments: none
723 ;; Restrictions: transaction state
724 ;; Possible responses:
725 ;;  +OK nn [highest numbered message accessed]
726
727 ;; RSET
728 ;; Arguments: none
729 ;; Restrictions: transaction state
730 ;; Possible responses:
731 ;;  +OK [all delete marks removed]
732
733 ;;; UPDATE STATE
734
735 ;; QUIT
736 ;; Arguments: none
737 ;; Restrictions: none
738 ;; Possible responses:
739 ;;  +OK [TCP connection closed]
740
741 (provide 'pop3)
742
743 ;;; pop3.el ends here