Fix last change.
[elisp/flim.git] / smtp.el
diff --git a/smtp.el b/smtp.el
index cf2e1c1..2462c43 100644 (file)
--- a/smtp.el
+++ b/smtp.el
 
 (eval-when-compile (require 'cl))      ; push
 
-(require 'net-trans)
+(require 'tram)
 
 (eval-and-compile
-  (luna-define-class smtp-transaction (net-transaction)
+  (luna-define-class smtp-stream (tram-stream)
                     (process
-                     extensions
-                     sender
-                     recipients
-                     buffer))
+                     extensions))
 
-  (luna-define-internal-accessors 'smtp-transaction))
+  (luna-define-internal-accessors 'smtp-stream))
 
 (defgroup smtp nil
   "SMTP protocol for sending mail."
@@ -80,29 +77,19 @@ don't define this value."
   :type '(choice (const nil) string)
   :group 'smtp)
 
-(defcustom smtp-debug-info nil
-  "*smtp debug info printout. messages and process buffer."
-  :type 'boolean
-  :group 'smtp)
-
 (defcustom smtp-notify-success nil
   "If non-nil, notification for successful mail delivery is returned 
  to user (RFC1891)."
   :type 'boolean
   :group 'smtp)
 
-(defvar smtp-open-connection-function (function open-network-stream))
-
-(defvar smtp-default-commands
-  '(&& smtp-greeting (|| smtp-ehlo smtp-helo)
-       smtp-mailfrom smtp-rcptto  smtp-data))
+(defvar smtp-transaction-compose-function
+  #'smtp-default-transaction-compose-function)
 
-(defvar smtp-commands smtp-default-commands)
+(defvar smtp-open-connection-function (function open-network-stream))
 
 (defvar smtp-read-point nil)
 
-(defvar smtp-transaction-function nil)
-
 (defun smtp-make-fqdn ()
   "Return user's fully qualified domain name."
   (let ((system-name (system-name)))
@@ -114,125 +101,127 @@ don't define this value."
      (t
       (error "Cannot generate valid FQDN. Set `smtp-local-domain' correctly.")))))
 
-(luna-define-generic smtp-greeting (trans))
-(luna-define-generic smtp-ehlo (trans))
-(luna-define-generic smtp-helo (trans))
-(luna-define-generic smtp-mailfrom (trans))
-(luna-define-generic smtp-rcptto (trans))
-(luna-define-generic smtp-data (trans))
-
-(luna-define-method smtp-greeting ((trans smtp-transaction))
+(defun smtp-greeting (trans)
   (let ((response
         (smtp-read-response
-         (smtp-transaction-process-internal trans))))
+         (smtp-stream-process-internal trans))))
     (or (smtp-check-response response)
-       (net-transaction-error trans 'greeting))
+       (tram-stream-error trans 'greeting))
     trans))
   
-(luna-define-method smtp-ehlo ((trans smtp-transaction))
+(defun smtp-ehlo (trans)
   (smtp-send-command
-   (smtp-transaction-process-internal trans)
+   (smtp-stream-process-internal trans)
    (format "EHLO %s" (smtp-make-fqdn)))
   (let ((response
         (smtp-read-response 
-         (smtp-transaction-process-internal trans))))
+         (smtp-stream-process-internal trans))))
     (or (smtp-check-response response)
-       (net-transaction-error trans 'ehlo))
-    (smtp-transaction-set-extensions-internal trans (cdr response))
+       (tram-stream-error trans 'ehlo))
+    (smtp-stream-set-extensions-internal
+     trans (mapcar
+           (lambda (extension)
+             (car (read-from-string (downcase extension))))
+           (cdr response)))
     trans))
 
-(luna-define-method smtp-helo ((trans smtp-transaction))
+(defun smtp-helo (trans)
   (smtp-send-command
-   (smtp-transaction-process-internal trans)
+   (smtp-stream-process-internal trans)
    (format "HELO %s" (smtp-make-fqdn)))
   (let ((response
         (smtp-read-response
-         (smtp-transaction-process-internal trans))))
+         (smtp-stream-process-internal trans))))
     (or (smtp-check-response response)
-       (net-transaction-error trans 'helo))
+       (tram-stream-error trans 'helo))
     trans))
 
-(luna-define-method smtp-mailfrom ((trans smtp-transaction))
+(defun smtp-mailfrom (sender trans)
   (smtp-send-command
-   (smtp-transaction-process-internal trans)
-   (format "MAIL FROM:<%s>%s%s"
-          (smtp-transaction-sender-internal trans)
+   (smtp-stream-process-internal trans)
+   (format "MAIL FROM:<%s>%s"
+          sender
           ;; SIZE --- Message Size Declaration (RFC1870)
-          (if (memq 'size
-                    (smtp-transaction-extensions-internal trans))
-              (format " SIZE=%d"
-                      (save-excursion
-                        (set-buffer
-                         (smtp-transaction-buffer-internal trans))
-                        (+ (- (point-max) (point-min))
-                           ;; Add one byte for each change-of-line
-                           ;; because or CR-LF representation:
-                           (count-lines (point-min) (point-max))
-                           ;; For some reason, an empty line is
-                           ;; added to the message.    Maybe this
-                           ;; is a bug, but it can't hurt to add
-                           ;; those two bytes anyway:
-                           2)))
-            "")
+;;;       (if (memq 'size
+;;;                 (smtp-stream-extensions-internal trans))
+;;;           (format " SIZE=%d"
+;;;                   (save-excursion
+;;;                     (set-buffer buffer)
+;;;                     (+ (- (point-max) (point-min))
+;;;                        ;; Add one byte for each change-of-line
+;;;                        ;; because or CR-LF representation:
+;;;                        (count-lines (point-min) (point-max))
+;;;                        ;; For some reason, an empty line is
+;;;                        ;; added to the message.    Maybe this
+;;;                        ;; is a bug, but it can't hurt to add
+;;;                        ;; those two bytes anyway:
+;;;                        2)))
+;;;         "")
           ;; 8BITMIME --- 8bit-MIMEtransport (RFC1652)
           (if (and (memq '8bitmime
-                         (smtp-transaction-extensions-internal trans))
+                         (smtp-stream-extensions-internal trans))
                    smtp-use-8bitmime)
               " BODY=8BITMIME"
             "")))
   (let ((response
         (smtp-read-response
-         (smtp-transaction-process-internal trans))))
+         (smtp-stream-process-internal trans))))
     (or (smtp-check-response response)
-       (net-transaction-error trans 'mailfrom))
+       (tram-stream-error trans 'mailfrom))
     trans))
 
-(luna-define-method smtp-rcptto ((trans smtp-transaction))
-  (let ((recipients
-        (smtp-transaction-recipients-internal trans))
-       response)
-    (while recipients
-      (smtp-send-command
-       (smtp-transaction-process-internal trans)
-       (format
-       (if smtp-notify-success
-           "RCPT TO:<%s> NOTIFY=SUCCESS"
-         "RCPT TO:<%s>")
-       (car recipients)))
-      (setq response
-           (smtp-read-response
-            (smtp-transaction-process-internal trans)))
-      (or (smtp-check-response response)
-         (net-transaction-error trans 'rcptto))
-      (setq recipients (cdr recipients)))
+(defun smtp-rcptto (recipient trans)
+  (let (response)
+    (smtp-send-command
+     (smtp-stream-process-internal trans)
+     (format
+      (if smtp-notify-success
+         "RCPT TO:<%s> NOTIFY=SUCCESS"
+       "RCPT TO:<%s>")
+      recipient))
+    (setq response
+         (smtp-read-response
+          (smtp-stream-process-internal trans)))
+    (or (smtp-check-response response)
+       (tram-stream-error trans 'rcptto))
     trans))
 
-(luna-define-method smtp-data ((trans smtp-transaction))
+(defun smtp-data (buffer trans)
   (smtp-send-command
-   (smtp-transaction-process-internal trans)
+   (smtp-stream-process-internal trans)
    "DATA")
   (let ((response
         (smtp-read-response
-         (smtp-transaction-process-internal trans))))
+         (smtp-stream-process-internal trans))))
     (or (smtp-check-response response)
-       (net-transaction-error trans 'data))
+       (tram-stream-error trans 'data))
 
     ;; Mail contents
     (smtp-send-data 
-     (smtp-transaction-process-internal trans)
-     (smtp-transaction-buffer-internal trans))
-
+     (smtp-stream-process-internal trans)
+     buffer)
     ;; DATA end "."
     (smtp-send-command
-     (smtp-transaction-process-internal trans)
+     (smtp-stream-process-internal trans)
      ".")
     (setq response
          (smtp-read-response
-          (smtp-transaction-process-internal trans)))
+          (smtp-stream-process-internal trans)))
     (or (smtp-check-response response)
-       (net-transaction-error trans 'data))
+       (tram-stream-error trans 'data))
     trans))
 
+(defun smtp-default-transaction-compose-function (sender recipients buffer)
+  (tram-compose-transaction
+   `(&& smtp-greeting
+       (|| smtp-ehlo smtp-helo)
+       ,(closure-partial-call #'smtp-mailfrom sender)
+       ,@(mapcar
+          (lambda (recipient)
+            (closure-partial-call #'smtp-rcptto recipient))
+          recipients)
+       ,(closure-partial-call #'smtp-data buffer))))
+
 (defun smtp-via-smtp (sender recipients smtp-text-buffer)
   (let ((server (if (functionp smtp-server)
                    (funcall smtp-server sender recipients)
@@ -246,14 +235,14 @@ don't define this value."
       (erase-buffer)
       (make-local-variable 'smtp-read-point)
       (setq smtp-read-point (point-min))
-      (make-local-variable 'smtp-transaction-function)
-      (or smtp-transaction-function
-         (let ((function (net-transaction-compose-commands smtp-commands)))
+      (unwind-protect
+         (let ((function
+                (funcall smtp-transaction-compose-function
+                         sender recipients smtp-text-buffer)))
            (or (functionp function)
                (error "Unable to compose SMTP commands"))
-           (setq smtp-transaction-function function)))
-      (unwind-protect
-         (progn
+           (if (eq (car-safe function) 'lambda)
+               (setq function (byte-compile function)))
            (as-binary-process
             (setq process
                   (funcall smtp-open-connection-function
@@ -261,14 +250,10 @@ don't define this value."
            (when process
              (set-process-filter process 'smtp-process-filter)
              (setq trans
-                   (luna-make-entity 'smtp-transaction
-                                     :process process
-                                     :sender sender
-                                     :recipients recipients
-                                     :buffer smtp-text-buffer)
+                   (luna-make-entity 'smtp-stream :process process)
                    error
-                   (catch (net-transaction-error-name trans)
-                     (funcall smtp-transaction-function trans)
+                   (catch (tram-stream-error-name trans)
+                     (funcall function trans)
                      nil))
              (not error)))
        (when (and process
@@ -285,55 +270,28 @@ don't define this value."
 
 (defun smtp-read-response (process)
   (let ((case-fold-search nil)
-       (response-strings nil)
+       response
        (response-continue t)
-       (return-value '(nil ()))
        match-end)
-
     (while response-continue
       (goto-char smtp-read-point)
       (while (not (search-forward "\r\n" nil t))
        (accept-process-output process)
        (goto-char smtp-read-point))
-
       (setq match-end (point))
-      (setq response-strings
-           (cons (buffer-substring smtp-read-point (- match-end 2))
-                 response-strings))
-       
+      (setq response
+           (nconc response
+                  (list (buffer-substring (+ 4 smtp-read-point)
+                                          (- match-end 2)))))
       (goto-char smtp-read-point)
-      (if (looking-at "[0-9]+ ")
-         (let ((begin (match-beginning 0))
-               (end (match-end 0)))
-           (if smtp-debug-info
-               (message "%s" (car response-strings)))
-
-           (setq smtp-read-point match-end)
-
-           ;; ignore lines that start with "0"
-           (if (looking-at "0[0-9]+ ")
-               nil
-             (setq response-continue nil)
-             (setq return-value
-                   (cons (string-to-int
-                          (buffer-substring begin end))
-                         (nreverse response-strings)))))
-       
-       (if (looking-at "[0-9]+-")
-           (progn (if smtp-debug-info
-                    (message "%s" (car response-strings)))
-                  (setq smtp-read-point match-end)
-                  (setq response-continue t))
-         (progn
-           (setq smtp-read-point match-end)
-           (setq response-continue nil)
-           (setq return-value
-                 (cons nil (nreverse response-strings)))))))
-    (setq smtp-read-point match-end)
-    return-value))
+      (when (looking-at "[1-5][0-9][0-9] ")
+       (setq response-continue nil)
+       (push (read (point-marker)) response))
+      (setq smtp-read-point match-end))
+    response))
 
 (defun smtp-check-response (response)
-  (> (car response) 200))
+  (memq (/ (car response) 100) '(2 3)));; XXX
 
 (defun smtp-send-command (process command)
   (goto-char (point-max))
@@ -344,8 +302,6 @@ don't define this value."
 
 (defun smtp-send-data-1 (process data)
   (goto-char (point-max))
-  (if smtp-debug-info
-      (insert data "\r\n"))
   (setq smtp-read-point (point))
   ;; Escape "." at start of a line.
   (if (eq (string-to-char data) ?.)