* elmo.el: Moved obsolete variable definitions from
[elisp/wanderlust.git] / elmo / elmo-net.el
1 ;;; elmo-net.el -- Network module for ELMO.
2
3 ;; Copyright (C) 1998,1999,2000 Yuuichi Teranishi <teranisi@gohome.org>
4
5 ;; Author: Yuuichi Teranishi <teranisi@gohome.org>
6 ;; Keywords: mail, net news
7
8 ;; This file is part of ELMO (Elisp Library for Message Orchestration).
9
10 ;; This program is free software; you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation; either version 2, or (at your option)
13 ;; any later version.
14 ;;
15 ;; This program is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 ;; GNU General Public License for more details.
19 ;;
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
22 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 ;; Boston, MA 02111-1307, USA.
24 ;;
25
26 ;;; Commentary:
27 ;; 
28
29 (eval-when-compile (require 'cl))
30
31 (require 'elmo-util)
32 (require 'elmo-dop)
33 (require 'elmo-vars)
34 (require 'elmo-cache)
35 (require 'elmo)
36
37 ;;; Code:
38 ;;
39
40 ;;; ELMO net folder
41 (eval-and-compile
42   (luna-define-class elmo-net-folder
43                      (elmo-folder)
44                      (user auth server port stream-type))
45   (luna-define-internal-accessors 'elmo-net-folder))
46
47 ;;; Session
48 (eval-and-compile
49   (autoload 'starttls-negotiate "starttls")
50   (autoload 'sasl-find-mechanism "sasl")
51   (autoload 'sasl-make-client "sasl")
52   (autoload 'sasl-mechanism-name "sasl")
53   (autoload 'sasl-next-step "sasl")
54   (autoload 'sasl-step-data "sasl")
55   (autoload 'sasl-step-set-data "sasl"))
56
57 (defvar sasl-mechanisms)
58
59 ;;; Code:
60 ;;
61 (eval-and-compile
62   (luna-define-class elmo-network-session () (name
63                                               server
64                                               port
65                                               user
66                                               auth
67                                               stream-type
68                                               process
69                                               greeting))
70   (luna-define-internal-accessors 'elmo-network-session))
71
72 (luna-define-generic elmo-network-initialize-session (session)
73   "Initialize SESSION (Called before authentication).")
74
75 (luna-define-generic elmo-network-initialize-session-buffer (session buffer)
76   "Initialize SESSION's BUFFER.")
77
78 (luna-define-generic elmo-network-authenticate-session (session)
79   "Authenticate SESSION.")
80
81 (luna-define-generic elmo-network-setup-session (session)
82   "Setup SESSION. (Called after authentication).")
83
84 (luna-define-generic elmo-network-close-session (session)
85   "Close SESSION.")
86
87 (luna-define-method
88   elmo-network-initialize-session-buffer ((session
89                                            elmo-network-session) buffer)
90   (with-current-buffer buffer
91     (elmo-set-buffer-multibyte nil)
92     (buffer-disable-undo (current-buffer))))
93
94 (luna-define-method elmo-network-close-session ((session elmo-network-session))
95   (when (elmo-network-session-process-internal session)
96 ;;; (memq (process-status (elmo-network-session-process-internal session))
97 ;;;       '(open run))
98     (kill-buffer (process-buffer
99                   (elmo-network-session-process-internal session)))
100     (delete-process (elmo-network-session-process-internal session))))
101
102 (defmacro elmo-network-stream-type-spec-string (stream-type)
103   (` (nth 0 (, stream-type))))
104
105 (defmacro elmo-network-stream-type-symbol (stream-type)
106   (` (nth 1 (, stream-type))))
107
108 (defmacro elmo-network-stream-type-feature (stream-type)
109   (` (nth 2 (, stream-type))))
110
111 (defmacro elmo-network-stream-type-function (stream-type)
112   (` (nth 3 (, stream-type))))
113
114 (defsubst elmo-network-session-password-key (session)
115   (format "%s:%s/%s@%s:%d"
116           (elmo-network-session-name-internal session)
117           (elmo-network-session-user-internal session)
118           (elmo-network-session-auth-internal session)
119           (elmo-network-session-server-internal session)
120           (elmo-network-session-port-internal session)))
121
122 (defvar elmo-network-session-cache nil)
123 (defvar elmo-network-session-name-prefix nil)
124
125 (defsubst elmo-network-session-cache-key (name folder)
126   "Returns session cache key for NAME and FOLDER."
127   (format "%s:%s/%s@%s:%d%s"
128           (concat elmo-network-session-name-prefix name)
129           (elmo-net-folder-user-internal folder)
130           (elmo-net-folder-auth-internal folder)
131           (elmo-net-folder-server-internal folder)
132           (elmo-net-folder-port-internal folder)
133           (or
134            (elmo-network-stream-type-spec-string
135             (elmo-net-folder-stream-type-internal folder)) "")))
136
137 (defun elmo-network-clear-session-cache ()
138   "Clear session cache."
139   (interactive)
140   (dolist (pair elmo-network-session-cache)
141     (elmo-network-close-session (cdr pair)))
142   (setq elmo-network-session-cache nil))
143
144 (defmacro elmo-network-session-buffer (session)
145   "Get buffer for SESSION."
146   (` (process-buffer (elmo-network-session-process-internal
147                       (, session)))))
148
149 (defun elmo-network-get-session (class name folder &optional if-exists)
150   "Get network session from session cache or a new network session.
151 CLASS is the class name of the session.
152 NAME is the name of the process.
153 FOLDER is the ELMO folder structure.
154 Returns a `elmo-network-session' instance.
155 If optional argument IF-EXISTS is non-nil, it does not return session
156 if there is no session cache.
157 if making session failed, returns nil."
158   (let (pair session key)
159     (if (not (elmo-plugged-p
160               (elmo-net-folder-server-internal folder)
161               (elmo-net-folder-port-internal folder)))
162         (error "Unplugged"))
163     (setq pair (assoc (setq key (elmo-network-session-cache-key name folder))
164                       elmo-network-session-cache))
165     (when (and pair
166                (not (memq (process-status
167                            (elmo-network-session-process-internal
168                             (cdr pair)))
169                           '(open run))))
170       (setq elmo-network-session-cache
171             (delq pair elmo-network-session-cache))
172       (elmo-network-close-session (cdr pair))
173       (setq pair nil))
174     (if pair
175         (cdr pair)                      ; connection cache exists.
176       (unless if-exists
177         (setq session
178               (elmo-network-open-session
179                class
180                name
181                (elmo-net-folder-server-internal folder)
182                (elmo-net-folder-port-internal folder)
183                (elmo-net-folder-user-internal folder)
184                (elmo-net-folder-auth-internal folder)
185                (elmo-net-folder-stream-type-internal folder)))
186         (setq elmo-network-session-cache
187               (cons (cons key session)
188                     elmo-network-session-cache))
189         session))))
190
191 (defun elmo-network-open-session (class name server port user auth
192                                         stream-type)
193   "Open an authenticated network session.
194 CLASS is the class name of the session.
195 NAME is the name of the process.
196 SERVER is the name of the server server.
197 PORT is the port number of the service.
198 USER is the user-id for the authenticate.
199 AUTH is the authenticate method name (symbol).
200 STREAM-TYPE is the stream type (See also `elmo-network-stream-type-alist').
201 Returns a process object.  if making session failed, returns nil."
202   (let ((session
203          (luna-make-entity class
204                            :name name
205                            :server server
206                            :port port
207                            :user user
208                            :auth auth
209                            :stream-type stream-type
210                            :process nil
211                            :greeting nil))
212         (buffer (format " *%s session for %s@%s:%d%s"
213                         (concat elmo-network-session-name-prefix name)
214                         user
215                         server
216                         port
217                         (or (elmo-network-stream-type-spec-string stream-type)
218                             "")))
219         process)
220     (condition-case error
221         (progn
222           (if (get-buffer buffer) (kill-buffer buffer))
223           (setq buffer (get-buffer-create buffer))
224           (elmo-network-initialize-session-buffer session buffer)
225           (elmo-network-session-set-process-internal
226            session
227            (setq process (elmo-open-network-stream
228                           (elmo-network-session-name-internal session)
229                           buffer server port stream-type)))
230           (when process
231             (elmo-network-initialize-session session)
232             (elmo-network-authenticate-session session)
233             (elmo-network-setup-session session)))
234       (error
235        (when (eq (car error) 'elmo-authenticate-error)
236          (elmo-remove-passwd (elmo-network-session-password-key session)))
237        (elmo-network-close-session session)
238        (signal (car error)(cdr error))))
239     session))
240
241 (defun elmo-open-network-stream (name buffer server service stream-type)
242   (let ((auto-plugged (and elmo-auto-change-plugged
243                            (> elmo-auto-change-plugged 0)))
244         process)
245     (if (and stream-type
246              (elmo-network-stream-type-feature stream-type))
247         (require (elmo-network-stream-type-feature stream-type)))
248     (condition-case err
249         (let (process-connection-type)
250           (as-binary-process
251            (setq process
252                  (if stream-type
253                      (funcall (elmo-network-stream-type-function stream-type)
254                               name buffer server service)
255                    (open-network-stream name buffer server service)))))
256       (error
257        (when auto-plugged
258          (elmo-set-plugged nil server service stream-type (current-time))
259          (message "Auto plugged off at %s:%d" server service)
260          (sit-for 1))
261        (signal (car err) (cdr err))))
262     (when process
263       (process-kill-without-query process)
264       (when auto-plugged
265         (elmo-set-plugged t server service stream-type))
266       process)))
267
268 (luna-define-method elmo-folder-initialize ((folder
269                                              elmo-net-folder)
270                                             name)
271   ;; user and auth should be set in subclass.
272   (when (string-match "\\(@[^@:/!]+\\)?\\(:[0-9]+\\)?\\(!.*\\)?$" name)
273     (if (match-beginning 1)
274         (elmo-net-folder-set-server-internal
275          folder
276          (elmo-match-substring 1 name 1)))
277     (if (match-beginning 2)
278         (elmo-net-folder-set-port-internal
279          folder
280          (string-to-int (elmo-match-substring 2 name 1))))
281     (if (match-beginning 3)
282         (elmo-net-folder-set-stream-type-internal 
283          folder
284          (assoc (elmo-match-string 3 name)
285                 elmo-network-stream-type-alist)))
286     (substring name 0 (match-beginning 0))))
287
288 (defun elmo-net-port-info (folder)
289   (list (elmo-net-folder-server-internal folder)
290         (elmo-net-folder-port-internal folder)
291         (elmo-network-stream-type-symbol
292          (elmo-net-folder-stream-type-internal folder))))
293
294 (defun elmo-net-port-label (folder)
295   (concat
296    (symbol-name (elmo-folder-type-internal folder))
297    (if (elmo-net-folder-stream-type-internal folder)
298        (concat "!" (symbol-name
299                     (elmo-network-stream-type-symbol
300                      (elmo-net-folder-stream-type-internal
301                       folder)))))))
302
303 (luna-define-method elmo-folder-plugged-p ((folder elmo-net-folder))
304   (apply 'elmo-plugged-p
305          (append (elmo-net-port-info folder)
306                  (list nil (quote (elmo-net-port-label folder))))))
307                             
308 (luna-define-method elmo-folder-set-plugged ((folder elmo-net-folder)
309                                              plugged &optional add)
310   (apply 'elmo-set-plugged plugged
311          (append (elmo-net-port-info folder)
312                  (list nil nil (quote (elmo-net-port-label folder)) add))))
313
314 (luna-define-method elmo-folder-exists-p ((folder elmo-net-folder))
315   (if (elmo-folder-plugged-p folder)
316       (elmo-folder-send folder 'elmo-folder-exists-p-plugged)
317     t)) ; If unplugged, assume the folder exists.
318
319 (luna-define-method elmo-folder-status ((folder elmo-net-folder))
320   (if (elmo-folder-plugged-p folder)
321       (elmo-folder-send folder 'elmo-folder-status-plugged)
322     (elmo-folder-send folder 'elmo-folder-status-unplugged)))
323
324 (luna-define-method elmo-folder-status-unplugged
325   ((folder elmo-net-folder))
326   (if elmo-enable-disconnected-operation
327       () ; XXX FIXME. (elmo-folder-status-dop folder) 
328     (error "Unplugged")))
329
330 (luna-define-method elmo-folder-list-messages-internal
331   ((folder elmo-net-folder) &optional nohide)
332   (elmo-net-folder-list-messages-internal folder nohide))
333
334 (defun elmo-net-folder-list-messages-internal (folder nohide)
335   (if (elmo-folder-plugged-p folder)
336       (elmo-folder-send folder 'elmo-folder-list-messages-plugged nohide)
337     (elmo-folder-send folder 'elmo-folder-list-messages-unplugged)))
338
339 (luna-define-method elmo-folder-list-messages-plugged
340   ((folder elmo-net-folder))
341   t)
342
343 ;; XXX
344 ;; Should consider offline append and removal.
345 (luna-define-method elmo-folder-list-messages-unplugged
346   ((folder elmo-net-folder))
347   (if elmo-enable-disconnected-operation
348       t 
349     (error "Unplugged")))
350
351 (luna-define-method elmo-folder-list-unreads-internal
352   ((folder elmo-net-folder) unread-marks &optional mark-alist)
353   (if (and (elmo-folder-plugged-p folder)
354            (elmo-folder-use-flag-p folder))
355       (elmo-folder-send folder 'elmo-folder-list-unreads-plugged)
356     t))
357
358 (luna-define-method elmo-folder-list-importants-internal
359   ((folder elmo-net-folder) important-mark)
360   (if (and (elmo-folder-plugged-p folder)
361            (elmo-folder-use-flag-p folder))
362       (elmo-folder-send folder 'elmo-folder-list-importants-plugged)
363     t))
364
365 (luna-define-method elmo-folder-list-unreads-plugged
366   ((folder elmo-net-folder))
367   t)
368
369 (luna-define-method elmo-folder-list-importants-plugged
370   ((folder elmo-net-folder))
371   t)
372
373 (luna-define-method elmo-folder-delete-messages ((folder elmo-net-folder)
374                                                  numbers)
375   (if (elmo-folder-plugged-p folder)
376       (elmo-folder-send folder 'elmo-folder-delete-messages-plugged numbers)
377     (elmo-folder-send folder 'elmo-folder-delete-messages-unplugged numbers)))
378
379 (luna-define-method elmo-folder-unmark-important ((folder elmo-net-folder)
380                                                   numbers)
381   (if (elmo-folder-use-flag-p folder)
382       (if (elmo-folder-plugged-p folder)
383           (elmo-folder-send folder 'elmo-folder-unmark-important-plugged
384                             numbers)
385         (elmo-folder-send folder
386                           'elmo-folder-unmark-important-unplugged numbers))
387     t))
388
389 (luna-define-method elmo-folder-mark-as-important ((folder elmo-net-folder)
390                                                    numbers)
391   (if (elmo-folder-use-flag-p folder)
392       (if (elmo-folder-plugged-p folder)
393           (elmo-folder-send folder 'elmo-folder-mark-as-important-plugged
394                             numbers)
395         (elmo-folder-send folder 'elmo-folder-mark-as-important-unplugged
396                           numbers))
397     t))
398
399 (luna-define-method elmo-folder-unmark-read ((folder elmo-net-folder)
400                                              numbers)
401   (if (elmo-folder-use-flag-p folder)
402       (if (elmo-folder-plugged-p folder)
403           (elmo-folder-send folder 'elmo-folder-unmark-read-plugged numbers)
404         (elmo-folder-send folder 'elmo-folder-unmark-read-unplugged numbers))
405     t))
406
407 (luna-define-method elmo-folder-mark-as-read ((folder elmo-net-folder)
408                                               numbers)
409   (if (elmo-folder-use-flag-p folder)
410       (if (elmo-folder-plugged-p folder)
411           (elmo-folder-send folder 'elmo-folder-mark-as-read-plugged numbers)
412         (elmo-folder-send
413          folder 'elmo-folder-mark-as-read-unplugged numbers))
414     t))
415
416 (luna-define-method elmo-message-fetch ((folder elmo-net-folder)
417                                         number strategy
418                                         &optional section
419                                         outbuf
420                                         unseen)
421   (if (elmo-folder-plugged-p folder)
422       (let ((cache-file (elmo-file-cache-expand-path
423                          (elmo-fetch-strategy-cache-path strategy)
424                          section)))
425         (if (and (elmo-fetch-strategy-use-cache strategy)
426                  (file-exists-p cache-file))
427             (if outbuf
428                 (with-current-buffer outbuf
429                   (insert-file-contents-as-binary cache-file)
430                   t)
431               (with-temp-buffer
432                 (insert-file-contents-as-binary cache-file)
433                 (buffer-string)))
434           (if outbuf
435               (with-current-buffer outbuf
436                 (elmo-folder-send folder 'elmo-message-fetch-plugged
437                                   number strategy section
438                                   (current-buffer) unseen)
439                 (elmo-delete-cr-buffer)
440                 (when (and (> (buffer-size) 0)
441                            (elmo-fetch-strategy-save-cache strategy))
442                   (elmo-file-cache-save
443                    (elmo-fetch-strategy-cache-path strategy)
444                    section))
445                 t)
446             (with-temp-buffer
447               (elmo-folder-send folder 'elmo-message-fetch-plugged
448                                 number strategy section
449                                 (current-buffer) unseen)
450               (elmo-delete-cr-buffer)
451               (when (and (> (buffer-size) 0)
452                          (elmo-fetch-strategy-save-cache strategy)
453                          (elmo-fetch-strategy-cache-path strategy))
454                 (elmo-file-cache-save
455                  (elmo-fetch-strategy-cache-path strategy)
456                  section))
457               (buffer-string)))))
458     (elmo-folder-send folder 'elmo-message-fetch-unplugged
459                       number strategy section outbuf unseen)))
460
461 (luna-define-method elmo-message-fetch-unplugged
462   ((folder elmo-net-folder) number strategy  &optional section outbuf unseen)
463   (if (elmo-fetch-strategy-use-cache strategy)
464       (if outbuf
465           (with-current-buffer outbuf
466             (insert-file-contents-as-binary
467              (elmo-file-cache-expand-path
468               (elmo-fetch-strategy-cache-path strategy)
469               section))
470             t)
471         (with-temp-buffer
472           (insert-file-contents-as-binary
473            (elmo-file-cache-expand-path
474             (elmo-fetch-strategy-cache-path strategy)
475             section))
476           (buffer-string)))
477     (error "Unplugged")))
478
479 (luna-define-method elmo-folder-check ((folder elmo-net-folder))
480   (if (elmo-folder-plugged-p folder)
481       (elmo-folder-send folder 'elmo-folder-check-plugged)))
482
483 (luna-define-method elmo-folder-close :after ((folder elmo-net-folder))
484   (if (elmo-folder-plugged-p folder)
485       (elmo-folder-send folder 'elmo-folder-check-plugged)))
486
487 (luna-define-method elmo-folder-diff :around ((folder elmo-net-folder)
488                                               &optional numbers)
489   (if (and (elmo-folder-use-flag-p folder)
490            (elmo-folder-plugged-p folder))
491       (elmo-folder-send folder 'elmo-folder-diff-plugged)
492     (luna-call-next-method)))
493
494 (luna-define-method elmo-folder-local-p ((folder elmo-net-folder))
495   nil)
496
497 (luna-define-method elmo-quit ((folder elmo-net-folder))
498   (elmo-network-clear-session-cache))
499
500 (require 'product)
501 (product-provide (provide 'elmo-net) (require 'elmo-version))
502
503 ;;; elmo-net.el ends here