Revert last commit (I'm sorry it was my mistake).
[elisp/wanderlust.git] / elmo / elmo-net.el
index f283b2a..009dcae 100644 (file)
@@ -1,4 +1,4 @@
-;;; elmo-net.el -- Network module for ELMO.
+;;; elmo-net.el --- Network module for ELMO.
 
 ;; Copyright (C) 1998,1999,2000 Yuuichi Teranishi <teranisi@gohome.org>
 
 ;;
 
 ;;; Commentary:
-;; 
+;;
+
+(eval-when-compile (require 'cl))
 
-(require 'luna)
 (require 'elmo-util)
+(require 'elmo-dop)
 (require 'elmo-vars)
+(require 'elmo-cache)
+(require 'elmo)
+
+;;; Code:
+;;
+
+;;; ELMO net folder
+(eval-and-compile
+  (luna-define-class elmo-net-folder
+                    (elmo-folder)
+                    (user auth server port stream-type))
+  (luna-define-internal-accessors 'elmo-net-folder))
+
+;;; Session
+(eval-and-compile
+  (autoload 'starttls-negotiate "starttls")
+  (autoload 'sasl-find-mechanism "sasl")
+  (autoload 'sasl-make-client "sasl")
+  (autoload 'sasl-mechanism-name "sasl")
+  (autoload 'sasl-next-step "sasl")
+  (autoload 'sasl-step-data "sasl")
+  (autoload 'sasl-step-set-data "sasl"))
+
+(defvar sasl-mechanisms)
 
 ;;; Code:
 ;;
 (eval-and-compile
   (luna-define-class elmo-network-session () (name
-                                             host
+                                             server
                                              port
                                              user
                                              auth
 
 (defsubst elmo-network-session-password-key (session)
   (format "%s:%s/%s@%s:%d"
-         (elmo-network-session-name-internal session)
+         (upcase
+          (nth 1 (split-string (symbol-name
+                                (luna-class-name session)) "[4-]")))
          (elmo-network-session-user-internal session)
-         (symbol-name (or (elmo-network-session-auth-internal session)
-                          'plain))
-         (elmo-network-session-host-internal session)
+         (elmo-network-session-auth-internal session)
+         (elmo-network-session-server-internal session)
          (elmo-network-session-port-internal session)))
 
 (defvar elmo-network-session-cache nil)
-(defvar elmo-network-session-name-prefix nil)
 
-(defsubst elmo-network-session-cache-key (name host port user auth stream-type)
-  "Returns session cache key."
+(defsubst elmo-network-session-cache-key (name folder)
+  "Returns session cache key for NAME and FOLDER."
   (format "%s:%s/%s@%s:%d%s"
-         (concat elmo-network-session-name-prefix name)
-         user auth host port (or stream-type "")))
+         name
+         (elmo-net-folder-user-internal folder)
+         (elmo-net-folder-auth-internal folder)
+         (elmo-net-folder-server-internal folder)
+         (elmo-net-folder-port-internal folder)
+         (or
+          (elmo-network-stream-type-spec-string
+           (elmo-net-folder-stream-type-internal folder)) "")))
 
 (defun elmo-network-clear-session-cache ()
   "Clear session cache."
   (interactive)
-  (mapcar (lambda (pair)
-           (elmo-network-close-session (cdr pair)))
-         elmo-network-session-cache)
+  (dolist (pair elmo-network-session-cache)
+    (elmo-network-close-session (cdr pair)))
   (setq elmo-network-session-cache nil))
 
 (defmacro elmo-network-session-buffer (session)
   (` (process-buffer (elmo-network-session-process-internal
                      (, session)))))
 
-(defun elmo-network-get-session (class name host port user auth stream-type
-                                      &optional if-exists)
+(defun elmo-network-get-session (class name folder &optional if-exists)
   "Get network session from session cache or a new network session.
 CLASS is the class name of the session.
 NAME is the name of the process.
-HOST is the name of the server host.
-PORT is the port number of the service.
-USER is the user-id for the authenticate.
-AUTH is the authenticate method name (symbol).
-STREAM-TYPE is the stream type (See also `elmo-network-stream-type-alist').
+FOLDER is the ELMO folder structure.
 Returns a `elmo-network-session' instance.
 If optional argument IF-EXISTS is non-nil, it does not return session
 if there is no session cache.
 if making session failed, returns nil."
   (let (pair session key)
-    (if (not (elmo-plugged-p host port))
+    (if (not (elmo-plugged-p
+             (elmo-net-folder-server-internal folder)
+             (elmo-net-folder-port-internal folder)
+             (elmo-network-stream-type-symbol
+              (elmo-net-folder-stream-type-internal folder))))
        (error "Unplugged"))
-    (setq pair (assoc (setq key (elmo-network-session-cache-key
-                                name host port user auth stream-type))
+    (setq pair (assoc (setq key (elmo-network-session-cache-key name folder))
                      elmo-network-session-cache))
     (when (and pair
               (not (memq (process-status
@@ -149,19 +178,25 @@ if making session failed, returns nil."
        (cdr pair)                      ; connection cache exists.
       (unless if-exists
        (setq session
-             (elmo-network-open-session class name
-                                        host port user auth stream-type))
+             (elmo-network-open-session
+              class
+              name
+              (elmo-net-folder-server-internal folder)
+              (elmo-net-folder-port-internal folder)
+              (elmo-net-folder-user-internal folder)
+              (elmo-net-folder-auth-internal folder)
+              (elmo-net-folder-stream-type-internal folder)))
        (setq elmo-network-session-cache
              (cons (cons key session)
                    elmo-network-session-cache))
        session))))
 
-(defun elmo-network-open-session (class name host port user auth
+(defun elmo-network-open-session (class name server port user auth
                                        stream-type)
   "Open an authenticated network session.
 CLASS is the class name of the session.
 NAME is the name of the process.
-HOST is the name of the server host.
+SERVER is the name of the server server.
 PORT is the port number of the service.
 USER is the user-id for the authenticate.
 AUTH is the authenticate method name (symbol).
@@ -170,7 +205,7 @@ Returns a process object.  if making session failed, returns nil."
   (let ((session
         (luna-make-entity class
                           :name name
-                          :host host
+                          :server server
                           :port port
                           :user user
                           :auth auth
@@ -178,9 +213,9 @@ Returns a process object.  if making session failed, returns nil."
                           :process nil
                           :greeting nil))
        (buffer (format " *%s session for %s@%s:%d%s"
-                       (concat elmo-network-session-name-prefix name)
+                       name
                        user
-                       host
+                       server
                        port
                        (or (elmo-network-stream-type-spec-string stream-type)
                            "")))
@@ -194,19 +229,25 @@ Returns a process object.  if making session failed, returns nil."
           session
           (setq process (elmo-open-network-stream
                          (elmo-network-session-name-internal session)
-                         buffer host port stream-type)))
+                         buffer server port stream-type)))
          (when process
            (elmo-network-initialize-session session)
            (elmo-network-authenticate-session session)
            (elmo-network-setup-session session)))
       (error
+       (when (eq (car error) 'elmo-open-error)
+        (elmo-set-plugged nil server port
+                          (elmo-network-stream-type-symbol stream-type)
+                          (current-time))
+        (message "Auto plugged off at %s:%d :%s" server port (cadr error))
+        (sit-for 1))
        (when (eq (car error) 'elmo-authenticate-error)
         (elmo-remove-passwd (elmo-network-session-password-key session)))
        (elmo-network-close-session session)
        (signal (car error)(cdr error))))
     session))
 
-(defun elmo-open-network-stream (name buffer host service stream-type)
+(defun elmo-open-network-stream (name buffer server service stream-type)
   (let ((auto-plugged (and elmo-auto-change-plugged
                           (> elmo-auto-change-plugged 0)))
        process)
@@ -214,25 +255,327 @@ Returns a process object.  if making session failed, returns nil."
             (elmo-network-stream-type-feature stream-type))
        (require (elmo-network-stream-type-feature stream-type)))
     (condition-case err
-       (let (process-connection-type)
+       (let (process-connection-type)
          (as-binary-process
           (setq process
                 (if stream-type
                     (funcall (elmo-network-stream-type-function stream-type)
-                             name buffer host service)
-                  (open-network-stream name buffer host service)))))
+                             name buffer server service)
+                  (open-network-stream name buffer server service)))))
       (error
        (when auto-plugged
-        (elmo-set-plugged nil host service (current-time))
-        (message "Auto plugged off at %s:%d" host service)
+        (elmo-set-plugged nil server service
+                          (elmo-network-stream-type-symbol stream-type)
+                          (current-time))
+        (message "Auto plugged off at %s:%d" server service)
         (sit-for 1))
        (signal (car err) (cdr err))))
     (when process
       (process-kill-without-query process)
       (when auto-plugged
-       (elmo-set-plugged t host service))
+       (elmo-set-plugged t server service
+                         (elmo-network-stream-type-symbol stream-type)))
       process)))
 
+(defun elmo-get-network-stream-type (symbol)
+  "Return network stream type corresponding to SYMBOL.
+Returned value is searched from `elmo-network-stream-type-alist'."
+  (let ((alist elmo-network-stream-type-alist)
+       spec)
+    (while alist
+      (when (eq (nth 1 (car alist)) symbol)
+       (setq spec (car alist))
+       (setq alist nil))
+      (setq alist (cdr alist)))
+    spec))
+
+(luna-define-method elmo-folder-initialize ((folder
+                                            elmo-net-folder)
+                                           name)
+  ;; user and auth should be set in subclass.
+  (when (string-match "\\(@[^@:/!]+\\)?\\(:[0-9]+\\)?\\(!.*\\)?$" name)
+    (if (match-beginning 1)
+       (elmo-net-folder-set-server-internal
+        folder
+        (elmo-match-substring 1 name 1)))
+    (if (match-beginning 2)
+       (elmo-net-folder-set-port-internal
+        folder
+        (string-to-int (elmo-match-substring 2 name 1))))
+    (if (match-beginning 3)
+       (elmo-net-folder-set-stream-type-internal
+        folder
+        (assoc (elmo-match-string 3 name)
+               elmo-network-stream-type-alist)))
+    (substring name 0 (match-beginning 0))))
+
+(luna-define-method elmo-net-port-info ((folder elmo-net-folder))
+  (list (elmo-net-folder-server-internal folder)
+       (elmo-net-folder-port-internal folder)
+       (elmo-network-stream-type-symbol
+        (elmo-net-folder-stream-type-internal folder))))
+
+(defun elmo-net-port-label (folder)
+  (concat
+   (symbol-name (elmo-folder-type-internal folder))
+   (if (elmo-net-folder-stream-type-internal folder)
+       (concat "!" (symbol-name
+                   (elmo-network-stream-type-symbol
+                    (elmo-net-folder-stream-type-internal
+                     folder)))))))
+
+(luna-define-method elmo-folder-plugged-p ((folder elmo-net-folder))
+  (apply 'elmo-plugged-p
+        (append (elmo-net-port-info folder)
+                (list nil (quote (elmo-net-port-label folder))))))
+
+(luna-define-method elmo-folder-set-plugged ((folder elmo-net-folder)
+                                            plugged &optional add)
+  (apply 'elmo-set-plugged plugged
+        (append (elmo-net-port-info folder)
+                (list nil nil (quote (elmo-net-port-label folder)) add))))
+
+(luna-define-method elmo-folder-create ((folder elmo-net-folder))
+  (if (elmo-folder-plugged-p folder)
+      (elmo-folder-send folder 'elmo-folder-create-plugged)
+    (elmo-folder-send folder 'elmo-folder-create-unplugged)))
+
+(luna-define-method elmo-folder-create-unplugged ((folder elmo-net-folder))
+  (if elmo-enable-disconnected-operation
+      (elmo-folder-create-dop folder)
+    (error "Unplugged")))
+
+(luna-define-method elmo-folder-exists-p ((folder elmo-net-folder))
+  (if (elmo-folder-plugged-p folder)
+      (elmo-folder-send folder 'elmo-folder-exists-p-plugged)
+    ;; If unplugged, guess by msgdb.
+    (file-directory-p (elmo-folder-msgdb-path folder))))
+
+(luna-define-method elmo-folder-status ((folder elmo-net-folder))
+  (if (elmo-folder-plugged-p folder)
+      (elmo-folder-send folder 'elmo-folder-status-plugged)
+    (elmo-folder-send folder 'elmo-folder-status-unplugged)))
+
+(luna-define-method elmo-folder-status-unplugged
+  ((folder elmo-net-folder))
+  (if elmo-enable-disconnected-operation
+      (elmo-folder-status-dop folder)
+    (error "Unplugged")))
+
+(luna-define-method elmo-folder-list-messages-internal
+  ((folder elmo-net-folder) &optional nohide)
+  (elmo-net-folder-list-messages-internal folder nohide))
+
+(defun elmo-net-folder-list-messages-internal (folder nohide)
+  (if (elmo-folder-plugged-p folder)
+      (elmo-folder-send folder 'elmo-folder-list-messages-plugged nohide)
+    (elmo-folder-send folder 'elmo-folder-list-messages-unplugged)))
+
+(luna-define-method elmo-folder-list-messages-plugged
+  ((folder elmo-net-folder))
+  nil)
+
+;; Should consider offline append and removal.
+(luna-define-method elmo-folder-list-messages-unplugged ((folder
+                                                         elmo-net-folder))
+  (if elmo-enable-disconnected-operation
+      (let ((deleting (elmo-dop-list-deleting-messages folder)))
+       (nconc
+        ;; delete deleting messages
+        (elmo-delete-if
+         (lambda (number) (memq number deleting))
+         ;; current number-list.
+         (mapcar
+          'car
+          (elmo-msgdb-get-number-alist (elmo-folder-msgdb folder))))
+        ;; append appending messages
+        (mapcar (lambda (x) (* -1 x))
+                (elmo-dop-spool-folder-list-messages folder))))
+    t))
+
+(luna-define-method elmo-folder-list-unreads-internal
+  ((folder elmo-net-folder) unread-marks &optional mark-alist)
+  (if (and (elmo-folder-plugged-p folder)
+          (elmo-folder-use-flag-p folder))
+      (elmo-folder-send folder 'elmo-folder-list-unreads-plugged)
+    t))
+
+(luna-define-method elmo-folder-list-importants-internal
+  ((folder elmo-net-folder) important-mark)
+  (if (and (elmo-folder-plugged-p folder)
+          (elmo-folder-use-flag-p folder))
+      (elmo-folder-send folder 'elmo-folder-list-importants-plugged)
+    t))
+
+(luna-define-method elmo-folder-list-unreads-plugged
+  ((folder elmo-net-folder))
+  t)
+
+(luna-define-method elmo-folder-list-importants-plugged
+  ((folder elmo-net-folder))
+  t)
+
+(luna-define-method elmo-folder-delete-messages ((folder elmo-net-folder)
+                                                numbers)
+  (if (elmo-folder-plugged-p folder)
+      (elmo-folder-send folder 'elmo-folder-delete-messages-plugged numbers)
+    (elmo-folder-send folder 'elmo-folder-delete-messages-unplugged numbers)))
+
+(luna-define-method elmo-folder-delete-messages-unplugged ((folder
+                                                           elmo-net-folder)
+                                                          numbers)
+  (elmo-folder-delete-messages-dop folder numbers))
+
+(luna-define-method elmo-folder-msgdb-create ((folder elmo-net-folder)
+                                             numbers new-mark
+                                             already-mark seen-mark
+                                             important-mark seen-list)
+  (if (elmo-folder-plugged-p folder)
+      (elmo-folder-send folder 'elmo-folder-msgdb-create-plugged
+                       numbers
+                       new-mark
+                       already-mark seen-mark
+                       important-mark seen-list)
+    (elmo-folder-send folder 'elmo-folder-msgdb-create-unplugged
+                     numbers
+                     new-mark already-mark seen-mark
+                     important-mark seen-list)))
+
+(luna-define-method elmo-folder-msgdb-create-unplugged ((folder
+                                                        elmo-net-folder)
+                                                       numbers
+                                                       new-mark already-mark
+                                                       seen-mark
+                                                       important-mark
+                                                       seen-list)
+  ;; XXXX should be appended to already existing msgdb.
+  (elmo-dop-msgdb
+   (elmo-folder-msgdb-create (elmo-dop-spool-folder folder)
+                            (mapcar 'abs numbers)
+                            new-mark already-mark
+                            seen-mark
+                            important-mark
+                            seen-list)))
+
+(luna-define-method elmo-folder-unmark-important ((folder elmo-net-folder)
+                                                 numbers)
+  (if (elmo-folder-use-flag-p folder)
+      (if (elmo-folder-plugged-p folder)
+         (elmo-folder-send folder 'elmo-folder-unmark-important-plugged
+                           numbers)
+       (elmo-folder-send folder
+                         'elmo-folder-unmark-important-unplugged numbers))
+    t))
+
+(luna-define-method elmo-folder-mark-as-important ((folder elmo-net-folder)
+                                                  numbers)
+  (if (elmo-folder-use-flag-p folder)
+      (if (elmo-folder-plugged-p folder)
+         (elmo-folder-send folder 'elmo-folder-mark-as-important-plugged
+                           numbers)
+       (elmo-folder-send folder 'elmo-folder-mark-as-important-unplugged
+                         numbers))
+    t))
+
+(luna-define-method elmo-folder-unmark-read ((folder elmo-net-folder)
+                                            numbers)
+  (if (elmo-folder-use-flag-p folder)
+      (if (elmo-folder-plugged-p folder)
+         (elmo-folder-send folder 'elmo-folder-unmark-read-plugged numbers)
+       (elmo-folder-send folder 'elmo-folder-unmark-read-unplugged numbers))
+    t))
+
+(luna-define-method elmo-folder-mark-as-read ((folder elmo-net-folder)
+                                             numbers)
+  (if (elmo-folder-use-flag-p folder)
+      (if (elmo-folder-plugged-p folder)
+         (elmo-folder-send folder 'elmo-folder-mark-as-read-plugged numbers)
+       (elmo-folder-send
+        folder 'elmo-folder-mark-as-read-unplugged numbers))
+    t))
+
+(luna-define-method elmo-folder-mark-as-read-unplugged ((folder
+                                                        elmo-net-folder)
+                                                       numbers)
+  (elmo-folder-mark-as-read-dop folder numbers))
+
+(luna-define-method elmo-folder-unmark-read-unplugged ((folder elmo-net-folder)
+                                                    numbers)
+  (elmo-folder-unmark-read-dop folder numbers))
+
+(luna-define-method elmo-folder-mark-as-important-unplugged ((folder
+                                                             elmo-net-folder)
+                                                            numbers)
+  (elmo-folder-mark-as-important-dop folder numbers))
+
+(luna-define-method elmo-folder-unmark-important-unplugged ((folder
+                                                            elmo-net-folder)
+                                                           numbers)
+  (elmo-folder-unmark-important-dop folder numbers))
+
+(luna-define-method elmo-message-encache :around ((folder elmo-net-folder)
+                                                 number &optional read)
+  (if (elmo-folder-plugged-p folder)
+      (luna-call-next-method)
+    (if elmo-enable-disconnected-operation
+       (elmo-message-encache-dop folder number read)
+      (error "Unplugged"))))
+
+(luna-define-generic elmo-message-fetch-plugged (folder number strategy
+                                                       &optional
+                                                       section
+                                                       outbuf
+                                                       unseen)
+  "")
+
+(luna-define-generic elmo-message-fetch-unplugged (folder number strategy
+                                                         &optional
+                                                         section
+                                                         outbuf
+                                                         unseen)
+  "")
+
+(luna-define-method elmo-message-fetch-internal ((folder elmo-net-folder)
+                                                number strategy
+                                                &optional section unseen)
+  (if (elmo-folder-plugged-p folder)
+      (elmo-message-fetch-plugged folder number
+                                 strategy section
+                                 (current-buffer) unseen)
+    (elmo-message-fetch-unplugged folder number
+                                 strategy section
+                                 (current-buffer) unseen)))
+
+(luna-define-method elmo-message-fetch-unplugged
+  ((folder elmo-net-folder) number strategy  &optional section outbuf unseen)
+  (if (and elmo-enable-disconnected-operation
+          (< number 0))
+      (elmo-message-fetch-internal
+       (elmo-dop-spool-folder folder) (abs number) strategy
+       section unseen)
+    (error "Unplugged")))
+
+(luna-define-method elmo-folder-check ((folder elmo-net-folder))
+  (if (elmo-folder-plugged-p folder)
+      (elmo-folder-send folder 'elmo-folder-check-plugged)))
+
+(luna-define-method elmo-folder-close :after ((folder elmo-net-folder))
+  (if (elmo-folder-plugged-p folder)
+      (elmo-folder-send folder 'elmo-folder-check-plugged)))
+
+(luna-define-method elmo-folder-diff :around ((folder elmo-net-folder)
+                                             &optional numbers)
+  (if (and (elmo-folder-use-flag-p folder)
+          (elmo-folder-plugged-p folder))
+      (elmo-folder-send folder 'elmo-folder-diff-plugged)
+    (luna-call-next-method)))
+
+(luna-define-method elmo-folder-local-p ((folder elmo-net-folder))
+  nil)
+
+(luna-define-method elmo-quit ((folder elmo-net-folder))
+  (elmo-network-clear-session-cache))
+
 (require 'product)
 (product-provide (provide 'elmo-net) (require 'elmo-version))