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