* elmo-nntp.el (elmo-nntp-list-folders): Remove progress gauge
[elisp/wanderlust.git] / elmo / elmo-pop3.el
1 ;;; elmo-pop3.el -- POP3 Interface for ELMO.
2
3 ;; Copyright 1998,1999,2000 Yuuichi Teranishi <teranisi@gohome.org>
4
5 ;; Author: Yuuichi Teranishi <teranisi@gohome.org>
6 ;; Keywords: mail, net news
7 ;; Time-stamp: <00/04/28 10:28:08 teranisi>
8
9 ;; This file is part of ELMO (Elisp Library for Message Orchestration).
10
11 ;; This program is free software; you can redistribute it and/or modify
12 ;; it under the terms of the GNU General Public License as published by
13 ;; the Free Software Foundation; either version 2, or (at your option)
14 ;; any later version.
15 ;;
16 ;; This program is distributed in the hope that it will be useful,
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 ;; GNU General Public License for more details.
20 ;;
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
23 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24 ;; Boston, MA 02111-1307, USA.
25 ;;
26
27 ;;; Commentary:
28 ;; 
29
30 ;;; Code:
31 ;; 
32
33 (require 'elmo-msgdb)
34 (eval-when-compile
35   (require 'elmo-util)
36   (condition-case nil
37       (progn
38         (require 'starttls)
39         (require 'sasl))
40     (error))
41   (defun-maybe md5 (a))
42   (defun-maybe sasl-digest-md5-digest-response 
43     (digest-challenge username passwd serv-type host &optional realm))  
44   (defun-maybe sasl-scram-md5-client-msg-1
45     (authenticate-id &optional authorize-id))
46   (defun-maybe sasl-scram-md5-client-msg-2
47     (server-msg-1 client-msg-1 salted-pass))
48   (defun-maybe sasl-scram-md5-make-salted-pass
49     (server-msg-1 passphrase))
50   (defun-maybe sasl-scram-md5-authenticate-server
51     (server-msg-1 server-msg-2 client-msg-1 salted-pass))
52   (defun-maybe starttls-negotiate (a)))
53 (condition-case nil
54     (progn
55       (require 'sasl))
56   (error))
57
58 (defvar elmo-pop3-exists-exactly t)
59 (defvar elmo-pop3-read-point nil)
60 (defvar elmo-pop3-connection-cache nil
61   "Cache of pop3 connection.")
62
63 (defun elmo-pop3-close-connection (connection &optional process buffer)
64   (save-excursion
65     (let* ((buffer  (or buffer (nth 0 connection)))
66            (process (or process (nth 1 connection))))
67       (elmo-pop3-send-command buffer process "quit")
68       (when (null (elmo-pop3-read-response buffer process t))
69         (error "POP error: QUIT failed")))))
70
71 (defun elmo-pop3-flush-connection ()
72   (interactive)
73   (let ((cache elmo-pop3-connection-cache)
74         buffer process proc-stat)
75     (while cache
76       (setq buffer (car (cdr (car cache))))
77       (setq process (car (cdr (cdr (car cache)))))
78       (if (and process
79                (not (or (eq (setq proc-stat 
80                                   (process-status process)) 
81                             'closed)
82                         (eq proc-stat 'exit))))
83           (condition-case ()
84               (elmo-pop3-close-connection nil process buffer)
85             (error)))
86       (if buffer (kill-buffer buffer))
87       ;;(setq process (car (cdr (cdr (car cache)))))
88       (if process (delete-process process))
89       (setq cache (cdr cache)))
90     (setq elmo-pop3-connection-cache nil)))
91
92 (defun elmo-pop3-get-connection (spec)
93   (let* ((user   (elmo-pop3-spec-username spec))
94          (server (elmo-pop3-spec-hostname spec))
95          (port   (elmo-pop3-spec-port spec))
96          (auth   (elmo-pop3-spec-auth spec))
97          (ssl    (elmo-pop3-spec-ssl spec))
98          (user-at-host (format "%s@%s" user server))
99          ret-val result buffer process errmsg proc-stat
100          user-at-host-on-port)
101     (if (not (elmo-plugged-p server port))
102         (error "Unplugged"))
103     (setq user-at-host-on-port 
104           (concat user-at-host ":" (int-to-string port)
105                   (if (eq ssl 'starttls) "!!" (if ssl "!"))))
106     (setq ret-val (assoc user-at-host-on-port elmo-pop3-connection-cache))
107     (if (and ret-val 
108              (or (eq (setq proc-stat 
109                            (process-status (cadr (cdr ret-val)))) 
110                      'closed)
111                  (eq proc-stat 'exit)))
112         ;; connection is closed...
113         (progn
114           (kill-buffer (car (cdr ret-val)))
115           (setq elmo-pop3-connection-cache 
116                 (delete ret-val elmo-pop3-connection-cache))
117           (setq ret-val nil)
118           ))
119     (if ret-val
120         (cdr ret-val)
121       (setq result
122             (elmo-pop3-open-connection 
123              server user port auth
124              (elmo-get-passwd user-at-host) ssl))
125       (if (null result)
126           (error "Connection failed"))
127       (setq buffer (car result))
128       (setq process (cdr result))
129       (when (and process (null buffer))
130         (elmo-remove-passwd user-at-host)
131         (delete-process process)
132         (error "Login failed")
133         )
134       (setq elmo-pop3-connection-cache 
135             (append elmo-pop3-connection-cache 
136                     (list 
137                      (cons user-at-host-on-port
138                            (setq ret-val (list buffer process))))))
139       ret-val)))
140
141 (defun elmo-pop3-send-command (buffer process command)
142   (save-excursion
143     (set-buffer buffer)
144     (erase-buffer)
145     (goto-char (point-min))
146     (setq elmo-pop3-read-point (point))
147     (process-send-string process command)
148     (process-send-string process "\r\n")))
149
150 (defun elmo-pop3-send-command-no-erase (buffer process command)
151   (save-excursion
152     (set-buffer buffer)
153     ;(erase-buffer)
154     (goto-char (point-min))
155     (setq elmo-pop3-read-point (point))
156     (process-send-string process command)
157     (process-send-string process "\r\n")))
158
159 (defun elmo-pop3-read-response (buffer process &optional not-command)
160   (save-excursion
161     (set-buffer buffer)
162     (let ((case-fold-search nil)
163           (response-string nil)
164           (response-continue t)
165           (return-value nil)
166           match-end)
167       (while response-continue
168         (goto-char elmo-pop3-read-point)
169         (while (not (re-search-forward "\r?\n" nil t))
170           (accept-process-output process)
171           (goto-char elmo-pop3-read-point))
172         (setq match-end (point))
173         (setq response-string
174               (buffer-substring elmo-pop3-read-point (- match-end 2)))
175         (goto-char elmo-pop3-read-point)
176         (if (looking-at "\\+.*$")
177             (progn 
178               (setq response-continue nil)
179               (setq elmo-pop3-read-point match-end)
180               (setq return-value 
181                     (if return-value 
182                         (concat return-value "\n" response-string)
183                       response-string
184                       )))
185           (if (looking-at "\\-.*$")
186               (progn 
187                 (setq response-continue nil)
188                 (setq elmo-pop3-read-point match-end)
189                 (setq return-value nil))
190             (setq elmo-pop3-read-point match-end)
191             (if not-command
192                 (setq response-continue nil))
193             (setq return-value 
194                   (if return-value 
195                       (concat return-value "\n" response-string)
196                     response-string)))
197           (setq elmo-pop3-read-point match-end)))
198       return-value)))
199
200 (defun elmo-pop3-process-filter (process output)
201   (save-excursion
202     (set-buffer (process-buffer process))
203     (goto-char (point-max))
204     (insert output)))
205
206 (defun elmo-pop3-open-connection (server user port auth passphrase ssl)
207   (let ((process nil)
208         (host server)
209         process-buffer ret-val response capability)
210     (catch 'done
211       (as-binary-process
212        (setq process-buffer
213              (get-buffer-create (format " *POP session to %s:%d" host port)))
214        (save-excursion
215          (set-buffer process-buffer)
216          (elmo-set-buffer-multibyte nil)         
217          (erase-buffer))
218        (setq process
219              (elmo-open-network-stream "POP" process-buffer host port ssl))
220        (and (null process) (throw 'done nil))
221        (set-process-filter process 'elmo-pop3-process-filter)
222        ;; flush connections when exiting...
223        (save-excursion
224          (set-buffer process-buffer)
225          (make-local-variable 'elmo-pop3-read-point)
226          (setq elmo-pop3-read-point (point-min))
227          (when (null (setq response
228                            (elmo-pop3-read-response process-buffer process t)))
229            (setq ret-val (cons nil process))
230            (throw 'done nil))
231          (when (eq ssl 'starttls)
232            (elmo-pop3-send-command process-buffer process "stls")
233            (string-match "^\+OK" 
234                          (elmo-pop3-read-response 
235                           process-buffer process))
236            (starttls-negotiate process))
237          (cond ((string= auth "apop")
238                 ;; try only APOP
239                 (if (string-match "^\+OK .*\\(<[^\>]+>\\)" response)
240                     ;; good, APOP ready server
241                     (progn
242                       (require 'md5)
243                       (elmo-pop3-send-command  
244                        process-buffer process 
245                        (format "apop %s %s" 
246                                user
247                                (md5 
248                                 (concat (match-string 1 response)
249                                             passphrase)))))
250                   ;; otherwise, fail (only APOP authentication)
251                   (setq ret-val (cons nil process))
252                   (throw 'done nil)))
253                ((string= auth "cram-md5")
254                 (elmo-pop3-send-command  
255                  process-buffer process "auth cram-md5")
256                 (when (null (setq response
257                                   (elmo-pop3-read-response
258                                    process-buffer process t)))
259                   (setq ret-val (cons nil process))
260                   (throw 'done nil))
261                 (elmo-pop3-send-command
262                  process-buffer process
263                  (elmo-base64-encode-string
264                   (sasl-cram-md5 user passphrase 
265                                  (elmo-base64-decode-string
266                                   (cadr (split-string response " ")))))))
267                ((string= auth "digest-md5")
268                 (elmo-pop3-send-command  
269                  process-buffer process "auth digest-md5")
270                 (when (null (setq response
271                                   (elmo-pop3-read-response
272                                    process-buffer process t)))
273                   (setq ret-val (cons nil process))
274                   (throw 'done nil))
275                 (elmo-pop3-send-command
276                  process-buffer process
277                  (elmo-base64-encode-string
278                   (sasl-digest-md5-digest-response
279                    (elmo-base64-decode-string
280                     (cadr (split-string response " ")))
281                    user passphrase "pop" host)
282                   'no-line-break))
283                 (when (null (setq response
284                                   (elmo-pop3-read-response
285                                    process-buffer process t)))
286                   (setq ret-val (cons nil process))
287                   (throw 'done nil))
288                 (elmo-pop3-send-command process-buffer process ""))
289                ((string= auth "scram-md5")
290                 (let (server-msg-1 server-msg-2 client-msg-1 client-msg-2
291                                    salted-pass)
292                   (elmo-pop3-send-command
293                    process-buffer process
294                    (format "auth scram-md5 %s"
295                            (elmo-base64-encode-string
296                             (setq client-msg-1
297                                   (sasl-scram-md5-client-msg-1 user)))))
298                   (when (null (setq response
299                                     (elmo-pop3-read-response
300                                      process-buffer process t)))
301                     (setq ret-val (cons nil process))
302                     (throw 'done nil))
303                   (setq server-msg-1
304                         (elmo-base64-decode-string
305                          (cadr (split-string response " "))))
306                   (elmo-pop3-send-command
307                    process-buffer process
308                    (elmo-base64-encode-string
309                     (sasl-scram-md5-client-msg-2
310                      server-msg-1
311                      client-msg-1
312                      (setq salted-pass
313                            (sasl-scram-md5-make-salted-pass 
314                             server-msg-1 passphrase)))))
315                   (when (null (setq response
316                                     (elmo-pop3-read-response
317                                      process-buffer process t)))
318                     (setq ret-val (cons nil process))
319                     (throw 'done nil))
320                   (setq server-msg-2
321                         (elmo-base64-decode-string
322                          (cadr (split-string response " "))))
323                   (if (null (sasl-scram-md5-authenticate-server
324                              server-msg-1
325                              server-msg-2
326                              client-msg-1
327                              salted-pass))
328                       (throw 'done nil))
329                   (elmo-pop3-send-command
330                    process-buffer process "") ))
331                (t
332                 ;; try USER/PASS
333                 (elmo-pop3-send-command  process-buffer process 
334                                          (format "user %s" user))
335                 (when (null (elmo-pop3-read-response process-buffer process t))
336                   (setq ret-val (cons nil process))
337                   (throw 'done nil))
338                 (elmo-pop3-send-command  process-buffer process 
339                                          (format "pass %s" passphrase))))
340          ;; read PASS or APOP response
341          (when (null (elmo-pop3-read-response process-buffer process t))
342            (setq ret-val (cons nil process))
343            (throw 'done nil))
344          (setq ret-val (cons process-buffer process)))))
345     ret-val))
346
347 (defun elmo-pop3-read-contents (buffer process)
348   (save-excursion
349     (set-buffer buffer)
350     (let ((case-fold-search nil)
351           match-end)
352       (goto-char elmo-pop3-read-point)
353       (while (not (re-search-forward "^\\.\r\n" nil t))
354         (accept-process-output process)
355         (goto-char elmo-pop3-read-point))
356       (setq match-end (point))
357       (elmo-delete-cr
358        (buffer-substring elmo-pop3-read-point 
359                          (- match-end 3))))))
360
361 ;; dummy functions
362 (defun elmo-pop3-list-folders (spec &optional hierarchy) nil)
363 (defun elmo-pop3-append-msg (spec string) nil nil)
364 (defun elmo-pop3-folder-creatable-p (spec) nil)
365 (defun elmo-pop3-create-folder (spec) nil)
366
367 (defun elmo-pop3-folder-exists-p (spec)
368   (if (and elmo-pop3-exists-exactly
369            (elmo-pop3-plugged-p spec))
370       (save-excursion
371         (let (elmo-auto-change-plugged) ;;don't change plug status.
372           (condition-case nil
373               (prog1
374                   (elmo-pop3-get-connection spec)
375                 (elmo-pop3-flush-connection))
376             (error nil))))
377     t))
378
379 (defun elmo-pop3-parse-list-response (string)
380   (save-excursion
381     (let ((tmp-buffer (get-buffer-create " *ELMO PARSE TMP*"))
382           ret-val)
383       (set-buffer tmp-buffer)
384       (let ((case-fold-search t))
385         (erase-buffer)
386         (insert string)
387         (goto-char (point-min))
388         (while (re-search-forward "^\\([0-9]*\\)[\t ].*$" nil t)
389           (setq ret-val
390                 (cons
391                  (string-to-int
392                   (elmo-match-buffer 1))
393                  ret-val)))
394         (kill-buffer tmp-buffer)
395         (nreverse ret-val)))))
396
397 (defun elmo-pop3-list-folder (spec)
398   (save-excursion
399     (elmo-pop3-flush-connection)
400     (let* ((connection (elmo-pop3-get-connection spec))
401            (buffer  (nth 0 connection))
402            (process (nth 1 connection))
403            response errmsg ret-val)
404       (elmo-pop3-send-command buffer process "list")
405       (if (null (elmo-pop3-read-response buffer process))
406           (error "POP List folder failed"))
407       (if (null (setq response (elmo-pop3-read-contents buffer process)))
408           (error "POP List folder failed"))
409       ;; POP server always returns a sequence of serial numbers.
410       (elmo-pop3-parse-list-response response))))
411
412 (defun elmo-pop3-max-of-folder (spec)
413   (save-excursion
414     (elmo-pop3-flush-connection)
415     (let* ((connection (elmo-pop3-get-connection spec))
416            (buffer  (nth 0 connection))
417            (process (nth 1 connection))
418            (total 0)
419            response)
420       (elmo-pop3-send-command buffer process "STAT")
421       (setq response (elmo-pop3-read-response buffer process))
422       ;; response: "^\+OK 2 7570$"
423       (if (not (string-match "^\+OK[ \t]*\\([0-9]*\\)" response))
424           (error "POP STAT command failed")
425         (setq total
426               (string-to-int
427                (substring response (match-beginning 1)(match-end 1 ))))
428         (cons total total)))))
429
430 (defvar elmo-pop3-header-fetch-chop-length 200)
431
432 (defsubst elmo-pop3-next-result-arrived-p ()
433   (cond
434    ((eq (following-char) ?+)
435     (if (re-search-forward "\n\\.\r?\n" nil t)
436         t
437       nil))
438    ((looking-at "-")
439     (if (search-forward "\n" nil t)
440         t
441       nil))
442    (t
443     nil)))
444      
445 (defun elmo-pop3-retrieve-headers (buffer tobuffer process articles)
446   (save-excursion
447     (set-buffer buffer)
448     (erase-buffer)
449     (let ((number (length articles))
450           (count 0)
451           (received 0)
452           (last-point (point-min)))
453       ;; Send HEAD commands.
454       (while articles
455         (elmo-pop3-send-command-no-erase
456          buffer
457          process
458          (format "top %s 0" (car articles))
459          )
460         ; (accept-process-output process 1)
461         (setq articles (cdr articles))
462         (setq count (1+ count))
463         ;; Every 200 requests we have to read the stream in
464         ;; order to avoid deadlocks.
465         (when (or elmo-pop3-send-command-synchronously
466                   (null articles)       ;All requests have been sent.
467                   (zerop (% count elmo-pop3-header-fetch-chop-length)))
468           (unless elmo-pop3-send-command-synchronously
469             (accept-process-output process 1))
470           (discard-input)
471           (while (progn
472                    (set-buffer buffer)
473                    (goto-char last-point)
474                    ;; Count replies.
475                    (while (elmo-pop3-next-result-arrived-p)
476                      (setq last-point (point))
477                      (setq received (1+ received)))
478                    (< received count))
479             (and (zerop (% received 20))
480                  (elmo-display-progress
481                   'elmo-pop3-retrieve-headers "Getting headers..."
482                   (/ (* received 100) number)))
483             (accept-process-output process 1)
484             ;(accept-process-output process)
485             (discard-input)
486             )))
487       (elmo-display-progress
488        'elmo-pop3-retrieve-headers "Getting headers..." 100)
489       ;; Remove all "\r"'s.
490       (goto-char (point-min))
491       (while (search-forward "\r\n" nil t)
492         (replace-match "\n"))
493       (copy-to-buffer tobuffer (point-min) (point-max))
494       ;(elmo-pop3-close-connection nil process buffer) ; close connection
495       )))
496
497 (defalias 'elmo-pop3-msgdb-create 'elmo-pop3-msgdb-create-as-numlist)
498 (defun elmo-pop3-msgdb-create-as-numlist (spec numlist new-mark
499                                                already-mark seen-mark
500                                                important-mark seen-list)
501   (when numlist
502     (let* ((connection (elmo-pop3-get-connection spec))
503            (buffer (nth 0 connection))
504            (process (nth 1 connection))
505            response errmsg ret-val)
506       (elmo-pop3-msgdb-create-by-header buffer process numlist
507                                         new-mark already-mark 
508                                         seen-mark seen-list))))
509
510 (defun elmo-pop3-msgdb-create-by-header (buffer process numlist
511                                                 new-mark already-mark 
512                                                 seen-mark
513                                                 seen-list)
514   (let ((tmp-buffer (get-buffer-create " *ELMO Overview TMP*"))
515         ret-val)
516     (elmo-pop3-retrieve-headers
517      buffer tmp-buffer process numlist)
518     (setq ret-val
519           (elmo-pop3-msgdb-create-message
520            tmp-buffer 
521            (length numlist)
522            numlist
523            new-mark already-mark seen-mark seen-list))
524     (kill-buffer tmp-buffer)
525     ret-val))
526
527 (defun elmo-pop3-msgdb-create-message (buffer 
528                                        num numlist new-mark already-mark 
529                                        seen-mark
530                                        seen-list)
531   (save-excursion
532     (let (beg
533           overview number-alist mark-alist
534           entity i number message-id gmark seen)
535       (set-buffer buffer)
536       (elmo-set-buffer-multibyte default-enable-multibyte-characters)
537       (goto-char (point-min))
538       (setq i 0)
539       (message "Creating msgdb...")
540       (while (not (eobp))
541         (setq beg (save-excursion (forward-line 1) (point)))
542         (elmo-pop3-next-result-arrived-p)
543         (save-excursion
544           (forward-line -1)
545           (save-restriction
546             (narrow-to-region beg (point))
547             (setq entity
548                   (elmo-msgdb-create-overview-from-buffer 
549                    (car numlist)))
550             (setq numlist (cdr numlist))
551             (when entity
552               (setq overview 
553                     (elmo-msgdb-append-element
554                      overview entity))
555               (setq number-alist
556                     (elmo-msgdb-number-add number-alist
557                                            (elmo-msgdb-overview-entity-get-number entity)
558                                            (car entity)))
559               (setq message-id (car entity))
560               (setq seen (member message-id seen-list))
561               (if (setq gmark (or (elmo-msgdb-global-mark-get message-id)
562                                   (if (elmo-cache-exists-p 
563                                        message-id) ; XXX
564                                       (if seen
565                                           nil
566                                         already-mark)
567                                     (if seen
568                                         (if elmo-pop3-use-cache
569                                             seen-mark)
570                                       new-mark))))
571                   (setq mark-alist
572                         (elmo-msgdb-mark-append 
573                          mark-alist
574                          (elmo-msgdb-overview-entity-get-number entity)
575                          gmark)))
576               )))
577         (setq i (1+ i))
578         (and (zerop (% i 20))
579              (elmo-display-progress
580               'elmo-pop3-msgdb-create-message "Creating msgdb..."
581               (/ (* i 100) num)))
582         )
583       (elmo-display-progress
584        'elmo-pop3-msgdb-create-message "Creating msgdb..." 100)
585       (list overview number-alist mark-alist))))
586
587 (defun elmo-pop3-read-body (buffer process outbuf)
588   (with-current-buffer buffer
589     (let ((start elmo-pop3-read-point)
590           end)
591       (goto-char start)
592       (while (not (re-search-forward "^\\.\r?\n" nil t))
593         (accept-process-output process)
594         (goto-char start))
595       (setq end (point))
596       (with-current-buffer outbuf
597         (erase-buffer)
598         (insert-buffer-substring buffer start (- end 3))
599         (elmo-delete-cr-get-content-type)))))
600
601 (defun elmo-pop3-read-msg (spec number outbuf)
602   (save-excursion
603     (let* ((connection (elmo-pop3-get-connection spec))
604            (buffer  (car connection))
605            (process (cadr connection))
606            (cwf     (caddr connection))  
607            response errmsg msg)
608       (elmo-pop3-send-command buffer process 
609                               (format "retr %s" number))
610       (when (null (setq response (elmo-pop3-read-response
611                                   buffer process t)))
612         (error "Fetching message failed"))
613       (setq response (elmo-pop3-read-body buffer process outbuf))
614       (set-buffer outbuf)
615       (goto-char (point-min))
616       (while (re-search-forward "^\\." nil t)
617         (replace-match "")
618         (forward-line))
619       response)))
620
621 (defun elmo-pop3-delete-msg (buffer process number)
622   (let (response errmsg msg)
623     (elmo-pop3-send-command buffer process 
624                             (format "dele %s" number))
625     (when (null (setq response (elmo-pop3-read-response
626                                 buffer process t)))
627       (error "Deleting message failed"))))
628
629 (defun elmo-pop3-delete-msgs (spec msgs)
630   (save-excursion
631     (let* ((connection (elmo-pop3-get-connection spec))
632            (buffer  (car connection))
633            (process (cadr connection)))
634       (mapcar '(lambda (msg) (elmo-pop3-delete-msg 
635                               buffer process msg))
636               msgs))))
637
638 (defun elmo-pop3-search (spec condition &optional numlist)
639   (error "Searching in pop3 folder is not implemented yet"))
640
641 (defun elmo-pop3-use-cache-p (spec number)
642   elmo-pop3-use-cache)
643
644 (defun elmo-pop3-local-file-p (spec number)
645   nil)
646
647 (defun elmo-pop3-port-label (spec)
648   (concat "pop3"
649           (if (elmo-pop3-spec-ssl spec) "!ssl" "")))
650
651 (defsubst elmo-pop3-portinfo (spec)
652   (list (elmo-pop3-spec-hostname spec) 
653         (elmo-pop3-spec-port spec)))
654
655 (defun elmo-pop3-plugged-p (spec)
656   (apply 'elmo-plugged-p
657          (append (elmo-pop3-portinfo spec)
658                  (list nil (quote (elmo-pop3-port-label spec))))))
659
660 (defun elmo-pop3-set-plugged (spec plugged add)
661   (apply 'elmo-set-plugged plugged
662          (append (elmo-pop3-portinfo spec)
663                  (list nil nil (quote (elmo-pop3-port-label spec)) add))))
664
665 (defalias 'elmo-pop3-sync-number-alist 
666   'elmo-generic-sync-number-alist)
667 (defalias 'elmo-pop3-list-folder-unread 
668   'elmo-generic-list-folder-unread)
669 (defalias 'elmo-pop3-list-folder-important
670   'elmo-generic-list-folder-important)
671 (defalias 'elmo-pop3-commit 'elmo-generic-commit)
672
673 (provide 'elmo-pop3)
674
675 ;;; elmo-pop3.el ends here