1 ;;; elmo-pop3.el -- POP3 Interface for ELMO.
3 ;; Copyright (C) 1998,1999,2000 Yuuichi Teranishi <teranisi@gohome.org>
4 ;; Copyright (C) 1999,2000 Kenichi OKADA <okada@opaopa.org>
6 ;; Author: Yuuichi Teranishi <teranisi@gohome.org>
7 ;; Kenichi OKADA <okada@opaopa.org>
8 ;; Keywords: mail, net news
10 ;; This file is part of ELMO (Elisp Library for Message Orchestration).
12 ;; This program is free software; you can redistribute it and/or modify
13 ;; it under the terms of the GNU General Public License as published by
14 ;; the Free Software Foundation; either version 2, or (at your option)
17 ;; This program is distributed in the hope that it will be useful,
18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 ;; GNU General Public License for more details.
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with GNU Emacs; see the file COPYING. If not, write to the
24 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25 ;; Boston, MA 02111-1307, USA.
44 (defun-maybe starttls-negotiate (a)))
50 (defvar elmo-pop3-use-uidl t
51 "*If non-nil, use UIDL.")
53 (defvar elmo-pop3-exists-exactly t)
56 (luna-define-class elmo-pop3-session (elmo-network-session) ()))
59 (defvar elmo-pop3-read-point nil)
60 (defvar elmo-pop3-number-uidl-hash nil) ; number -> uidl
61 (defvar elmo-pop3-uidl-number-hash nil) ; uidl -> number
62 (defvar elmo-pop3-size-hash nil) ; number -> size
63 (defvar elmo-pop3-uidl-done nil)
64 (defvar elmo-pop3-list-done nil)
66 (defvar elmo-pop3-local-variables '(elmo-pop3-read-point
67 elmo-pop3-uidl-number-hash
68 elmo-pop3-number-uidl-hash
73 (luna-define-method elmo-network-close-session ((session elmo-pop3-session))
74 (unless (memq (process-status
75 (elmo-network-session-process-internal session))
77 (elmo-pop3-send-command (elmo-network-session-process-internal session)
79 (or (elmo-pop3-read-response
80 (elmo-network-session-process-internal session) t)
81 (error "POP error: QUIT failed")))
82 (kill-buffer (process-buffer
83 (elmo-network-session-process-internal session)))
84 (delete-process (elmo-network-session-process-internal session)))
86 (defun elmo-pop3-get-session (spec &optional if-exists)
87 (elmo-network-get-session
90 (elmo-pop3-spec-hostname spec)
91 (elmo-pop3-spec-port spec)
92 (elmo-pop3-spec-username spec)
93 (elmo-pop3-spec-auth spec)
94 (elmo-pop3-spec-stream-type spec)
97 (defun elmo-pop3-send-command (process command &optional no-erase)
98 (with-current-buffer (process-buffer process)
101 (goto-char (point-min))
102 (setq elmo-pop3-read-point (point))
103 (process-send-string process command)
104 (process-send-string process "\r\n")))
106 (defun elmo-pop3-read-response (process &optional not-command)
107 (with-current-buffer (process-buffer process)
108 (let ((case-fold-search nil)
109 (response-string nil)
110 (response-continue t)
113 (while response-continue
114 (goto-char elmo-pop3-read-point)
115 (while (not (re-search-forward "\r?\n" nil t))
116 (accept-process-output process)
117 (goto-char elmo-pop3-read-point))
118 (setq match-end (point))
119 (setq response-string
120 (buffer-substring elmo-pop3-read-point (- match-end 2)))
121 (goto-char elmo-pop3-read-point)
122 (if (looking-at "\\+.*$")
124 (setq response-continue nil)
125 (setq elmo-pop3-read-point match-end)
128 (concat return-value "\n" response-string)
130 (if (looking-at "\\-.*$")
132 (setq response-continue nil)
133 (setq elmo-pop3-read-point match-end)
134 (setq return-value nil))
135 (setq elmo-pop3-read-point match-end)
137 (setq response-continue nil))
140 (concat return-value "\n" response-string)
142 (setq elmo-pop3-read-point match-end)))
145 (defun elmo-pop3-process-filter (process output)
147 (set-buffer (process-buffer process))
148 (goto-char (point-max))
151 (defun elmo-pop3-auth-user (session)
152 (let ((process (elmo-network-session-process-internal session)))
154 (elmo-pop3-send-command
156 (format "user %s" (elmo-network-session-user-internal session)))
157 (or (elmo-pop3-read-response process t)
158 (signal 'elmo-authenticate-error
159 '(elmo-pop-auth-user)))
160 (elmo-pop3-send-command process
164 (elmo-network-session-password-key session))))
165 (or (elmo-pop3-read-response process t)
166 (signal 'elmo-authenticate-error
167 '(elmo-pop-auth-user)))))
169 (defun elmo-pop3-auth-apop (session)
170 (if (string-match "^\+OK .*\\(<[^\>]+>\\)"
171 (elmo-network-session-greeting-internal session))
172 ;; good, APOP ready server
175 (elmo-pop3-send-command
176 (elmo-network-session-process-internal session)
178 (elmo-network-session-user-internal session)
180 (concat (match-string
182 (elmo-network-session-greeting-internal session))
184 (elmo-network-session-password-key session))))))
185 (or (elmo-pop3-read-response
186 (elmo-network-session-process-internal session)
188 (signal 'elmo-authenticate-error
189 '(elmo-pop3-auth-apop))))
190 (signal 'elmo-open-error '(elmo-pop-auth-user))))
192 (defun elmo-pop3-auth-cram-md5 (session)
193 (let ((process (elmo-network-session-process-internal session))
195 (elmo-pop3-send-command process "auth cram-md5")
197 (elmo-pop3-read-response process t))
198 (signal 'elmo-open-error '(elmo-pop-auth-cram-md5)))
199 (elmo-pop3-send-command
201 (elmo-base64-encode-string
202 (sasl-cram-md5 (elmo-network-session-user-internal session)
204 (elmo-network-session-password-key session))
205 (elmo-base64-decode-string
206 (cadr (split-string response " "))))))
207 (or (elmo-pop3-read-response process t)
208 (signal 'elmo-authenticate-error
209 '(elmo-pop-auth-cram-md5)))))
211 (defun elmo-pop3-auth-scram-md5 (session)
212 (let ((process (elmo-network-session-process-internal session))
213 server-msg-1 server-msg-2 client-msg-1 client-msg-2
214 salted-pass response)
215 (elmo-pop3-send-command
217 (format "auth scram-md5 %s"
218 (elmo-base64-encode-string
220 (sasl-scram-md5-client-msg-1
221 (elmo-network-session-user-internal session))))))
222 (or (elmo-pop3-read-response process t)
223 (signal 'elmo-open-error '(elmo-pop-auth-scram-md5)))
225 (elmo-base64-decode-string (cadr (split-string response " "))))
226 (elmo-pop3-send-command
228 (elmo-base64-encode-string
229 (sasl-scram-md5-client-msg-2
233 (sasl-scram-md5-make-salted-pass
236 (elmo-network-session-password-key session)))))))
237 (or (setq response (elmo-pop3-read-response process t))
238 (signal 'elmo-authenticate-error
239 '(elmo-pop-auth-scram-md5)))
240 (setq server-msg-2 (elmo-base64-decode-string
241 (cadr (split-string response " "))))
242 (or (sasl-scram-md5-authenticate-server server-msg-1
246 (signal 'elmo-authenticate-error
247 '(elmo-pop-auth-scram-md5)))
248 (elmo-pop3-send-command process "")
249 (or (setq response (elmo-pop3-read-response process t))
250 (signal 'elmo-authenticate-error
251 '(elmo-pop-auth-scram-md5)))))
253 (defun elmo-pop3-auth-digest-md5 (session)
254 (let ((process (elmo-network-session-process-internal session))
256 (elmo-pop3-send-command process "auth digest-md5")
258 (elmo-pop3-read-response process t))
259 (signal 'elmo-open-error
260 '(elmo-pop-auth-digest-md5)))
261 (elmo-pop3-send-command
263 (elmo-base64-encode-string
264 (sasl-digest-md5-digest-response
265 (elmo-base64-decode-string
266 (cadr (split-string response " ")))
267 (elmo-network-session-user-internal session)
269 (elmo-network-session-password-key session))
271 (elmo-network-session-host-internal session))
273 (or (elmo-pop3-read-response process t)
274 (signal 'elmo-authenticate-error
275 '(elmo-pop-auth-digest-md5)))
276 (elmo-pop3-send-command process "")
277 (or (elmo-pop3-read-response process t)
278 (signal 'elmo-open-error
279 '(elmo-pop-auth-digest-md5)))))
282 (defconst sasl-pop3-user-steps
283 '(sasl-pop3-user-response-1
284 sasl-pop3-user-response-2))
286 (defun sasl-pop3-user-response-1 (client step)
287 (sasl-client-name client))
289 (defun sasl-pop3-user-response-2 (client step)
291 (sasl-read-passphrase
292 (format "LOGIN passphrase for %s: "
293 (sasl-client-name client)))))
295 (put 'sasl-pop3-user 'sasl-mechanism
296 (sasl-make-mechanism "USER" sasl-pop3-user-steps))
298 (provide 'sasl-pop3-user)
300 (defconst sasl-pop3-apop-steps
301 '(sasl-pop3-apop-response))
303 (defun sasl-pop3-apop-response (client step)
306 (sasl-client-name client)
308 (concat (match-string
310 (elmo-network-session-greeting-internal session))
311 (sasl-read-passphrase
312 (format "LOGIN passphrase for %s: "
313 (sasl-client-name client)))))))
315 (put 'sasl-pop3-apop 'sasl-mechanism
316 (sasl-make-mechanism "APOP" sasl-pop3-apop-steps))
318 (provide 'sasl-pop3-apop)
320 (luna-define-method elmo-network-initialize-session-buffer :after
321 ((session elmo-pop3-session) buffer)
322 (with-current-buffer buffer
323 (mapcar 'make-variable-buffer-local elmo-pop3-local-variables)))
325 (luna-define-method elmo-network-initialize-session ((session
327 (let ((process (elmo-network-session-process-internal session))
329 (with-current-buffer (process-buffer process)
330 (set-process-filter process 'elmo-pop3-process-filter)
331 (setq elmo-pop3-read-point (point-min))
332 (or (elmo-network-session-set-greeting-internal
334 (elmo-pop3-read-response process t))
335 (signal 'elmo-open-error
336 '(elmo-network-intialize-session)))
337 (when (eq (elmo-network-stream-type-symbol
338 (elmo-network-session-stream-type-internal session))
340 (elmo-pop3-send-command process "stls")
341 (if (string-match "^\+OK"
342 (elmo-pop3-read-response process))
343 (starttls-negotiate process)
344 (signal 'elmo-open-error
345 '(elmo-pop3-starttls-error)))))))
347 (luna-define-method elmo-network-authenticate-session ((session
349 (let* ((process (elmo-network-session-process-internal session))
350 (auth (elmo-network-session-auth-internal session))
351 (auth (mapcar '(lambda (mechanism) (upcase (symbol-name mechanism)))
352 (if (listp auth) auth (list auth))))
353 (sasl-mechanism-alist
356 (list '("USER" sasl-pop3-user)
357 '("APOP" sasl-pop3-apop))))
360 (sasl-find-mechanism sasl-mechanisms)
361 (sasl-find-mechanism auth)))
362 client name step response
363 sasl-read-passphrase)
365 (if (or elmo-pop3-force-login
368 "There's no %s capability in server. continue?"
370 (elmo-network-session-auth-internal session)))))
371 (setq mechanism (sasl-find-mechanism
373 (signal 'elmo-authenticate-error '(elmo-pop3-auth-no-mechanisms))))
377 (elmo-network-session-user-internal session)
379 (elmo-network-session-host-internal session)))
380 ;;; (if elmo-pop3-auth-user-realm
381 ;;; (sasl-client-set-property client 'realm elmo-pop3-auth-user-realm))
382 (setq name (sasl-mechanism-name mechanism)
383 step (sasl-next-step client nil))
384 (elmo-network-session-set-auth-internal session
385 (intern (downcase name)))
386 (setq sasl-read-passphrase
390 (elmo-network-session-password-key session)))))
391 (if (or (string= name "USER")
392 (string= name "APOP"))
393 (elmo-pop3-send-command
396 (sasl-step-data step)))
397 (elmo-pop3-send-command
400 (and (sasl-step-data step)
403 (elmo-base64-encode-string
404 (sasl-step-data step) 'no-line-break))))))
407 (setq response (elmo-pop3-read-response process t))
408 (if (string-match "^\+OK" response)
409 (if (sasl-next-step client step)
410 (signal 'elmo-authenticate-error
412 (concat "elmo-pop3-auth-"
417 (elmo-base64-decode-string response))
418 (setq step (sasl-next-step client step))
419 (elmo-pop3-send-string
421 (if (sasl-step-data step)
422 (elmo-base64-encode-string (sasl-step-data step)
426 (luna-define-method elmo-network-setup-session ((session
428 (let ((process (elmo-network-session-process-internal session))
430 (with-current-buffer (process-buffer process)
431 (setq elmo-pop3-size-hash (make-vector 31 0))
432 ;; To get obarray of uidl and size
433 (elmo-pop3-send-command process "list")
434 (if (null (elmo-pop3-read-response process))
435 (error "POP List folder failed"))
436 (if (null (setq response
437 (elmo-pop3-read-contents
438 (current-buffer) process)))
439 (error "POP List folder failed"))
440 ;; POP server always returns a sequence of serial numbers.
441 (elmo-pop3-parse-list-response response)
443 (when elmo-pop3-use-uidl
444 (setq elmo-pop3-uidl-number-hash (make-vector 31 0))
445 (setq elmo-pop3-number-uidl-hash (make-vector 31 0))
447 (elmo-pop3-send-command process "uidl")
448 (unless (elmo-pop3-read-response process)
449 (error "UIDL failed"))
450 (unless (setq response (elmo-pop3-read-contents
451 (current-buffer) process))
452 (error "UIDL failed"))
453 (elmo-pop3-parse-uidl-response response)))))
455 (defun elmo-pop3-read-contents (buffer process)
458 (let ((case-fold-search nil)
460 (goto-char elmo-pop3-read-point)
461 (while (not (re-search-forward "^\\.\r\n" nil t))
462 (accept-process-output process)
463 (goto-char elmo-pop3-read-point))
464 (setq match-end (point))
466 (buffer-substring elmo-pop3-read-point
470 (defun elmo-pop3-list-folders (spec &optional hierarchy) nil)
471 (defun elmo-pop3-append-msg (spec string) nil nil)
472 (defun elmo-pop3-folder-creatable-p (spec) nil)
473 (defun elmo-pop3-create-folder (spec) nil)
475 (defun elmo-pop3-folder-exists-p (spec)
476 (if (and elmo-pop3-exists-exactly
477 (elmo-pop3-plugged-p spec))
479 (let (elmo-auto-change-plugged ; don't change plug status.
480 elmo-pop3-use-uidl ; No need to use uidl.
483 (setq session (elmo-pop3-get-session spec))
485 (elmo-network-close-session session)))))
488 (defun elmo-pop3-parse-uidl-response (string)
489 (let ((buffer (current-buffer))
492 (let (number uid list)
494 (goto-char (point-min))
495 (while (re-search-forward "^\\([0-9]+\\)[\t ]\\([^ \n]+\\)$" nil t)
496 (setq number (elmo-match-buffer 1))
497 (setq uid (elmo-match-buffer 2))
498 (with-current-buffer buffer
499 (elmo-set-hash-val uid number elmo-pop3-uidl-number-hash)
500 (elmo-set-hash-val (concat "#" number) uid
501 elmo-pop3-number-uidl-hash))
502 (setq list (cons uid list)))
503 (with-current-buffer buffer (setq elmo-pop3-uidl-done t))
506 (defun elmo-pop3-parse-list-response (string)
507 (let ((buffer (current-buffer))
511 (goto-char (point-min))
512 (while (re-search-forward "^\\([0-9]+\\)[\t ]\\([0-9]+\\)$" nil t)
515 (string-to-int (setq number (elmo-match-buffer 1)))
517 (setq size (elmo-match-buffer 2))
518 (with-current-buffer buffer
519 (elmo-set-hash-val (concat "#" number)
521 elmo-pop3-size-hash)))
522 (with-current-buffer buffer (setq elmo-pop3-list-done t))
525 (defun elmo-pop3-list-location (spec)
526 (with-current-buffer (process-buffer
527 (elmo-network-session-process-internal
528 (elmo-pop3-get-session spec)))
530 (if elmo-pop3-uidl-done
534 (setq list (cons (symbol-name atom) list)))
535 elmo-pop3-uidl-number-hash)
537 (error "POP3: Error in UIDL")))))
539 (defun elmo-pop3-list-by-uidl-subr (spec &optional nonsort)
540 (let ((flist (elmo-list-folder-by-location
542 (elmo-pop3-list-location spec))))
544 (cons (elmo-max-of-list flist) (length flist))
547 (defun elmo-pop3-list-by-list (spec)
548 (with-current-buffer (process-buffer
549 (elmo-network-session-process-internal
550 (elmo-pop3-get-session spec)))
552 (if elmo-pop3-list-done
554 (mapatoms (lambda (atom)
555 (setq list (cons (string-to-int
556 (substring (symbol-name atom) 1))
560 (error "POP3: Error in list")))))
562 (defun elmo-pop3-list-folder (spec)
563 (let ((killed (and elmo-use-killed-list
564 (elmo-msgdb-killed-list-load
565 (elmo-msgdb-expand-path spec))))
567 (elmo-pop3-commit spec)
568 (setq numbers (if elmo-pop3-use-uidl
570 (elmo-pop3-list-by-uidl-subr spec))
571 (elmo-pop3-list-by-list spec)))
572 (elmo-living-messages numbers killed)))
574 (defun elmo-pop3-max-of-folder (spec)
575 (elmo-pop3-commit spec)
576 (if elmo-pop3-use-uidl
577 (elmo-pop3-list-by-uidl-subr spec 'nonsort)
579 (elmo-network-session-process-internal
580 (elmo-pop3-get-session spec)))
583 (with-current-buffer (process-buffer process)
584 (elmo-pop3-send-command process "STAT")
585 (setq response (elmo-pop3-read-response process))
586 ;; response: "^\+OK 2 7570$"
587 (if (not (string-match "^\+OK[ \t]*\\([0-9]*\\)" response))
588 (error "POP STAT command failed")
591 (substring response (match-beginning 1)(match-end 1 ))))
592 (cons total total))))))
594 (defvar elmo-pop3-header-fetch-chop-length 200)
596 (defsubst elmo-pop3-next-result-arrived-p ()
598 ((eq (following-char) ?+)
599 (if (re-search-forward "\n\\.\r?\n" nil t)
603 (if (search-forward "\n" nil t)
609 (defun elmo-pop3-retrieve-headers (buffer tobuffer process articles)
613 (let ((number (length articles))
616 (last-point (point-min)))
617 ;; Send HEAD commands.
619 (elmo-pop3-send-command process (format
620 "top %s 0" (car articles))
622 ;;; (accept-process-output process 1)
623 (setq articles (cdr articles))
624 (setq count (1+ count))
625 ;; Every 200 requests we have to read the stream in
626 ;; order to avoid deadlocks.
627 (when (or elmo-pop3-send-command-synchronously
628 (null articles) ;All requests have been sent.
629 (zerop (% count elmo-pop3-header-fetch-chop-length)))
630 (unless elmo-pop3-send-command-synchronously
631 (accept-process-output process 1))
635 (goto-char last-point)
637 (while (elmo-pop3-next-result-arrived-p)
638 (setq last-point (point))
639 (setq received (1+ received)))
641 (when (> number elmo-display-progress-threshold)
642 (if (or (zerop (% received 5)) (= received number))
643 (elmo-display-progress
644 'elmo-pop3-retrieve-headers "Getting headers..."
645 (/ (* received 100) number))))
646 (accept-process-output process 1)
647 ;;; (accept-process-output process)
649 ;; Remove all "\r"'s.
650 (goto-char (point-min))
651 (while (search-forward "\r\n" nil t)
652 (replace-match "\n"))
653 (copy-to-buffer tobuffer (point-min) (point-max)))))
655 (defalias 'elmo-pop3-msgdb-create 'elmo-pop3-msgdb-create-as-numlist)
657 (defun elmo-pop3-msgdb-create-as-numlist (spec numlist new-mark
658 already-mark seen-mark
659 important-mark seen-list
662 (let ((process (elmo-network-session-process-internal
663 (elmo-pop3-get-session spec)))
665 (if elmo-pop3-use-uidl
666 (setq loc-alist (if msgdb (elmo-msgdb-get-location msgdb)
667 (elmo-msgdb-location-load
668 (elmo-msgdb-expand-path spec)))))
669 (elmo-pop3-msgdb-create-by-header process numlist
670 new-mark already-mark
674 (defun elmo-pop3-uidl-to-number (uidl)
675 (string-to-number (elmo-get-hash-val uidl
676 elmo-pop3-uidl-number-hash)))
678 (defun elmo-pop3-number-to-uidl (number)
679 (elmo-get-hash-val (format "#%d" number)
680 elmo-pop3-number-uidl-hash))
682 (defun elmo-pop3-number-to-size (number)
683 (elmo-get-hash-val (format "#%d" number)
684 elmo-pop3-size-hash))
686 (defun elmo-pop3-msgdb-create-by-header (process numlist
687 new-mark already-mark
691 (let ((tmp-buffer (get-buffer-create " *ELMO Overview TMP*")))
692 (with-current-buffer (process-buffer process)
693 (if loc-alist ; use uidl.
699 (elmo-pop3-uidl-to-number (cdr (assq number loc-alist))))
701 (elmo-pop3-retrieve-headers (process-buffer process)
702 tmp-buffer process numlist)
704 (elmo-pop3-msgdb-create-message
709 new-mark already-mark seen-mark seen-list loc-alist)
710 (kill-buffer tmp-buffer)))))
712 (defun elmo-pop3-msgdb-create-message (buffer
715 numlist new-mark already-mark
720 (let (beg overview number-alist mark-alist
721 entity i number message-id gmark seen size)
723 (elmo-set-buffer-multibyte default-enable-multibyte-characters)
724 (goto-char (point-min))
726 (message "Creating msgdb...")
728 (setq beg (save-excursion (forward-line 1) (point)))
729 (elmo-pop3-next-result-arrived-p)
733 (narrow-to-region beg (point))
735 (elmo-msgdb-create-overview-from-buffer
737 (setq numlist (cdr numlist))
740 (elmo-msgdb-append-element
742 (with-current-buffer (process-buffer process)
743 (elmo-msgdb-overview-entity-set-size
746 (elmo-pop3-number-to-size
747 (elmo-msgdb-overview-entity-get-number entity))))
751 (elmo-pop3-number-to-uidl
752 (elmo-msgdb-overview-entity-get-number entity))
754 (elmo-msgdb-overview-entity-set-number entity number)))
756 (elmo-msgdb-number-add
758 (elmo-msgdb-overview-entity-get-number entity)
760 (setq message-id (car entity))
761 (setq seen (member message-id seen-list))
762 (if (setq gmark (or (elmo-msgdb-global-mark-get message-id)
763 (if (elmo-cache-exists-p
769 (if elmo-pop3-use-cache
773 (elmo-msgdb-mark-append
775 (elmo-msgdb-overview-entity-get-number entity)
777 (when (> num elmo-display-progress-threshold)
779 (if (or (zerop (% i 5)) (= i num))
780 (elmo-display-progress
781 'elmo-pop3-msgdb-create-message "Creating msgdb..."
782 (/ (* i 100) num)))))
783 (list overview number-alist mark-alist loc-alist))))
785 (defun elmo-pop3-read-body (process outbuf)
786 (with-current-buffer (process-buffer process)
787 (let ((start elmo-pop3-read-point)
790 (while (not (re-search-forward "^\\.\r?\n" nil t))
791 (accept-process-output process)
794 (with-current-buffer outbuf
796 (insert-buffer-substring (process-buffer process) start (- end 3))
797 (elmo-delete-cr-get-content-type)))))
799 (defun elmo-pop3-read-msg (spec number outbuf &optional msgdb)
800 (let* ((loc-alist (if elmo-pop3-use-uidl
802 (elmo-msgdb-get-location msgdb)
803 (elmo-msgdb-location-load
804 (elmo-msgdb-expand-path spec)))))
805 (process (elmo-network-session-process-internal
806 (elmo-pop3-get-session spec)))
808 (with-current-buffer (process-buffer process)
810 (setq number (elmo-pop3-uidl-to-number
811 (cdr (assq number loc-alist)))))
813 (elmo-pop3-send-command process
814 (format "retr %s" number))
815 (when (null (setq response (elmo-pop3-read-response
817 (error "Fetching message failed"))
818 (setq response (elmo-pop3-read-body process outbuf))
820 (goto-char (point-min))
821 (while (re-search-forward "^\\." nil t)
826 (defun elmo-pop3-delete-msg (process number loc-alist)
827 (with-current-buffer (process-buffer process)
828 (let (response errmsg msg)
830 (setq number (elmo-pop3-uidl-to-number
831 (cdr (assq number loc-alist)))))
834 (elmo-pop3-send-command process
835 (format "dele %s" number))
836 (when (null (setq response (elmo-pop3-read-response
838 (error "Deleting message failed")))
839 (error "Deleting message failed")))))
841 (defun elmo-pop3-delete-msgs (spec msgs &optional msgdb)
842 (let ((loc-alist (if elmo-pop3-use-uidl
844 (elmo-msgdb-get-location msgdb)
845 (elmo-msgdb-location-load
846 (elmo-msgdb-expand-path spec)))))
847 (process (elmo-network-session-process-internal
848 (elmo-pop3-get-session spec))))
849 (mapcar '(lambda (msg) (elmo-pop3-delete-msg
850 process msg loc-alist))
853 (defun elmo-pop3-search (spec condition &optional numlist)
854 (error "Searching in pop3 folder is not implemented yet"))
856 (defun elmo-pop3-use-cache-p (spec number)
859 (defun elmo-pop3-local-file-p (spec number)
862 (defun elmo-pop3-port-label (spec)
864 (if (elmo-pop3-spec-stream-type spec)
865 (concat "!" (symbol-name
866 (elmo-network-stream-type-symbol
867 (elmo-pop3-spec-stream-type spec)))))))
869 (defsubst elmo-pop3-portinfo (spec)
870 (list (elmo-pop3-spec-hostname spec)
871 (elmo-pop3-spec-port spec)))
873 (defun elmo-pop3-plugged-p (spec)
874 (apply 'elmo-plugged-p
875 (append (elmo-pop3-portinfo spec)
876 (list nil (quote (elmo-pop3-port-label spec))))))
878 (defun elmo-pop3-set-plugged (spec plugged add)
879 (apply 'elmo-set-plugged plugged
880 (append (elmo-pop3-portinfo spec)
881 (list nil nil (quote (elmo-pop3-port-label spec)) add))))
883 (defalias 'elmo-pop3-sync-number-alist
884 'elmo-generic-sync-number-alist)
885 (defalias 'elmo-pop3-list-folder-unread
886 'elmo-generic-list-folder-unread)
887 (defalias 'elmo-pop3-list-folder-important
888 'elmo-generic-list-folder-important)
889 (defalias 'elmo-pop3-folder-diff 'elmo-generic-folder-diff)
891 (defun elmo-pop3-commit (spec)
892 (if (elmo-pop3-plugged-p spec)
893 (let ((session (elmo-pop3-get-session spec 'if-exists)))
895 (elmo-network-close-session session)))))
899 (product-provide (provide 'elmo-pop3) (require 'elmo-version))
901 ;;; elmo-pop3.el ends here