summaryrefslogtreecommitdiff
path: root/lisp/gnus/sieve-manage.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/gnus/sieve-manage.el')
-rw-r--r--lisp/gnus/sieve-manage.el576
1 files changed, 0 insertions, 576 deletions
diff --git a/lisp/gnus/sieve-manage.el b/lisp/gnus/sieve-manage.el
deleted file mode 100644
index d0fad75afac..00000000000
--- a/lisp/gnus/sieve-manage.el
+++ /dev/null
@@ -1,576 +0,0 @@
-;;; sieve-manage.el --- Implementation of the managesieve protocol in elisp
-
-;; Copyright (C) 2001-2017 Free Software Foundation, Inc.
-
-;; Author: Simon Josefsson <simon@josefsson.org>
-;; Albert Krewinkel <tarleb@moltkeplatz.de>
-
-;; This file is part of GNU Emacs.
-
-;; GNU Emacs is free software: you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; GNU Emacs is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; This library provides an elisp API for the managesieve network
-;; protocol.
-;;
-;; It uses the SASL library for authentication, which means it
-;; supports DIGEST-MD5, CRAM-MD5, SCRAM-MD5, NTLM, PLAIN and LOGIN
-;; methods. STARTTLS is not well tested, but should be easy to get to
-;; work if someone wants.
-;;
-;; The API should be fairly obvious for anyone familiar with the
-;; managesieve protocol, interface functions include:
-;;
-;; `sieve-manage-open'
-;; open connection to managesieve server, returning a buffer to be
-;; used by all other API functions.
-;;
-;; `sieve-manage-opened'
-;; check if a server is open or not
-;;
-;; `sieve-manage-close'
-;; close a server connection.
-;;
-;; `sieve-manage-listscripts'
-;; `sieve-manage-deletescript'
-;; `sieve-manage-getscript'
-;; performs managesieve protocol actions
-;;
-;; and that's it. Example of a managesieve session in *scratch*:
-;;
-;; (with-current-buffer (sieve-manage-open "mail.example.com")
-;; (sieve-manage-authenticate)
-;; (sieve-manage-listscripts))
-;;
-;; => ((active . "main") "vacation")
-;;
-;; References:
-;;
-;; draft-martin-managesieve-02.txt,
-;; "A Protocol for Remotely Managing Sieve Scripts",
-;; by Tim Martin.
-;;
-;; Release history:
-;;
-;; 2001-10-31 Committed to Oort Gnus.
-;; 2002-07-27 Added DELETESCRIPT. Suggested by Ned Ludd.
-;; 2002-08-03 Use SASL library.
-;; 2013-06-05 Enabled STARTTLS support, fixed bit rot.
-
-;;; Code:
-
-(if (locate-library "password-cache")
- (require 'password-cache)
- (require 'password))
-
-(eval-when-compile
- (require 'cl) ; caddr
- (require 'sasl)
- (require 'starttls))
-(autoload 'sasl-find-mechanism "sasl")
-(autoload 'auth-source-search "auth-source")
-
-;; User customizable variables:
-
-(defgroup sieve-manage nil
- "Low-level Managesieve protocol issues."
- :group 'mail
- :prefix "sieve-")
-
-(defcustom sieve-manage-log "*sieve-manage-log*"
- "Name of buffer for managesieve session trace."
- :type 'string
- :group 'sieve-manage)
-
-(defcustom sieve-manage-server-eol "\r\n"
- "The EOL string sent from the server."
- :type 'string
- :group 'sieve-manage)
-
-(defcustom sieve-manage-client-eol "\r\n"
- "The EOL string we send to the server."
- :type 'string
- :group 'sieve-manage)
-
-(defcustom sieve-manage-authenticators '(digest-md5
- cram-md5
- scram-md5
- ntlm
- plain
- login)
- "Priority of authenticators to consider when authenticating to server."
- ;; FIXME Improve this. It's not `set'.
- ;; It's like (repeat (choice (const ...))), where each choice can
- ;; only appear once.
- :type '(repeat symbol)
- :group 'sieve-manage)
-
-(defcustom sieve-manage-authenticator-alist
- '((cram-md5 sieve-manage-cram-md5-p sieve-manage-cram-md5-auth)
- (digest-md5 sieve-manage-digest-md5-p sieve-manage-digest-md5-auth)
- (scram-md5 sieve-manage-scram-md5-p sieve-manage-scram-md5-auth)
- (ntlm sieve-manage-ntlm-p sieve-manage-ntlm-auth)
- (plain sieve-manage-plain-p sieve-manage-plain-auth)
- (login sieve-manage-login-p sieve-manage-login-auth))
- "Definition of authenticators.
-
-\(NAME CHECK AUTHENTICATE)
-
-NAME names the authenticator. CHECK is a function returning non-nil if
-the server support the authenticator and AUTHENTICATE is a function
-for doing the actual authentication."
- :type '(repeat (list (symbol :tag "Name") (function :tag "Check function")
- (function :tag "Authentication function")))
- :group 'sieve-manage)
-
-(defcustom sieve-manage-default-port "sieve"
- "Default port number or service name for managesieve protocol."
- :type '(choice integer string)
- :version "24.4"
- :group 'sieve-manage)
-
-(defcustom sieve-manage-default-stream 'network
- "Default stream type to use for `sieve-manage'."
- :version "24.1"
- :type 'symbol
- :group 'sieve-manage)
-
-;; Internal variables:
-
-(defconst sieve-manage-local-variables '(sieve-manage-server
- sieve-manage-port
- sieve-manage-auth
- sieve-manage-stream
- sieve-manage-process
- sieve-manage-client-eol
- sieve-manage-server-eol
- sieve-manage-capability))
-(defconst sieve-manage-coding-system-for-read 'binary)
-(defconst sieve-manage-coding-system-for-write 'binary)
-(defvar sieve-manage-stream nil)
-(defvar sieve-manage-auth nil)
-(defvar sieve-manage-server nil)
-(defvar sieve-manage-port nil)
-(defvar sieve-manage-state 'closed
- "Managesieve state.
-Valid states are `closed', `initial', `nonauth', and `auth'.")
-(defvar sieve-manage-process nil)
-(defvar sieve-manage-capability nil)
-
-;; Internal utility functions
-(autoload 'mm-enable-multibyte "mm-util")
-
-(defun sieve-manage-make-process-buffer ()
- (with-current-buffer
- (generate-new-buffer (format " *sieve %s:%s*"
- sieve-manage-server
- sieve-manage-port))
- (mapc 'make-local-variable sieve-manage-local-variables)
- (mm-enable-multibyte)
- (buffer-disable-undo)
- (current-buffer)))
-
-(defun sieve-manage-erase (&optional p buffer)
- (let ((buffer (or buffer (current-buffer))))
- (and sieve-manage-log
- (with-current-buffer (get-buffer-create sieve-manage-log)
- (mm-enable-multibyte)
- (buffer-disable-undo)
- (goto-char (point-max))
- (insert-buffer-substring buffer (with-current-buffer buffer
- (point-min))
- (or p (with-current-buffer buffer
- (point-max)))))))
- (delete-region (point-min) (or p (point-max))))
-
-(defun sieve-manage-open-server (server port &optional stream buffer)
- "Open network connection to SERVER on PORT.
-Return the buffer associated with the connection."
- (with-current-buffer buffer
- (sieve-manage-erase)
- (setq sieve-manage-state 'initial)
- (destructuring-bind (proc . props)
- (open-protocol-stream
- "SIEVE" buffer server port
- :type stream
- :capability-command "CAPABILITY\r\n"
- :end-of-command "^\\(OK\\|NO\\).*\n"
- :success "^OK.*\n"
- :return-list t
- :starttls-function
- (lambda (capabilities)
- (when (string-match "\\bSTARTTLS\\b" capabilities)
- "STARTTLS\r\n")))
- (setq sieve-manage-process proc)
- (setq sieve-manage-capability
- (sieve-manage-parse-capability (plist-get props :capabilities)))
- ;; Ignore new capabilities issues after successful STARTTLS
- (when (and (memq stream '(nil network starttls))
- (eq (plist-get props :type) 'tls))
- (sieve-manage-drop-next-answer))
- (current-buffer))))
-
-;; Authenticators
-(defun sieve-sasl-auth (buffer mech)
- "Login to server using the SASL MECH method."
- (message "sieve: Authenticating using %s..." mech)
- (with-current-buffer buffer
- (let* ((auth-info (auth-source-search :host sieve-manage-server
- :port "sieve"
- :max 1
- :create t))
- (user-name (or (plist-get (nth 0 auth-info) :user) ""))
- (user-password (or (plist-get (nth 0 auth-info) :secret) ""))
- (user-password (if (functionp user-password)
- (funcall user-password)
- user-password))
- (client (sasl-make-client (sasl-find-mechanism (list mech))
- user-name "sieve" sieve-manage-server))
- (sasl-read-passphrase
- ;; We *need* to copy the password, because sasl will modify it
- ;; somehow.
- `(lambda (prompt) ,(copy-sequence user-password)))
- (step (sasl-next-step client nil))
- (tag (sieve-manage-send
- (concat
- "AUTHENTICATE \""
- mech
- "\""
- (and (sasl-step-data step)
- (concat
- " \""
- (base64-encode-string
- (sasl-step-data step)
- 'no-line-break)
- "\"")))))
- data rsp)
- (catch 'done
- (while t
- (setq rsp nil)
- (goto-char (point-min))
- (while (null (or (progn
- (setq rsp (sieve-manage-is-string))
- (if (not (and rsp (looking-at
- sieve-manage-server-eol)))
- (setq rsp nil)
- (goto-char (match-end 0))
- rsp))
- (setq rsp (sieve-manage-is-okno))))
- (accept-process-output sieve-manage-process 1)
- (goto-char (point-min)))
- (sieve-manage-erase)
- (when (sieve-manage-ok-p rsp)
- (when (and (cadr rsp)
- (string-match "^SASL \"\\([^\"]+\\)\"" (cadr rsp)))
- (sasl-step-set-data
- step (base64-decode-string (match-string 1 (cadr rsp)))))
- (if (and (setq step (sasl-next-step client step))
- (setq data (sasl-step-data step)))
- ;; We got data for server but it's finished
- (error "Server not ready for SASL data: %s" data)
- ;; The authentication process is finished.
- (throw 'done t)))
- (unless (stringp rsp)
- (error "Server aborted SASL authentication: %s" (caddr rsp)))
- (sasl-step-set-data step (base64-decode-string rsp))
- (setq step (sasl-next-step client step))
- (sieve-manage-send
- (if (sasl-step-data step)
- (concat "\""
- (base64-encode-string (sasl-step-data step)
- 'no-line-break)
- "\"")
- ""))))
- (message "sieve: Login using %s...done" mech))))
-
-(defun sieve-manage-cram-md5-p (buffer)
- (sieve-manage-capability "SASL" "CRAM-MD5" buffer))
-
-(defun sieve-manage-cram-md5-auth (buffer)
- "Login to managesieve server using the CRAM-MD5 SASL method."
- (sieve-sasl-auth buffer "CRAM-MD5"))
-
-(defun sieve-manage-digest-md5-p (buffer)
- (sieve-manage-capability "SASL" "DIGEST-MD5" buffer))
-
-(defun sieve-manage-digest-md5-auth (buffer)
- "Login to managesieve server using the DIGEST-MD5 SASL method."
- (sieve-sasl-auth buffer "DIGEST-MD5"))
-
-(defun sieve-manage-scram-md5-p (buffer)
- (sieve-manage-capability "SASL" "SCRAM-MD5" buffer))
-
-(defun sieve-manage-scram-md5-auth (buffer)
- "Login to managesieve server using the SCRAM-MD5 SASL method."
- (sieve-sasl-auth buffer "SCRAM-MD5"))
-
-(defun sieve-manage-ntlm-p (buffer)
- (sieve-manage-capability "SASL" "NTLM" buffer))
-
-(defun sieve-manage-ntlm-auth (buffer)
- "Login to managesieve server using the NTLM SASL method."
- (sieve-sasl-auth buffer "NTLM"))
-
-(defun sieve-manage-plain-p (buffer)
- (sieve-manage-capability "SASL" "PLAIN" buffer))
-
-(defun sieve-manage-plain-auth (buffer)
- "Login to managesieve server using the PLAIN SASL method."
- (sieve-sasl-auth buffer "PLAIN"))
-
-(defun sieve-manage-login-p (buffer)
- (sieve-manage-capability "SASL" "LOGIN" buffer))
-
-(defun sieve-manage-login-auth (buffer)
- "Login to managesieve server using the LOGIN SASL method."
- (sieve-sasl-auth buffer "LOGIN"))
-
-;; Managesieve API
-
-(defun sieve-manage-open (server &optional port stream auth buffer)
- "Open a network connection to a managesieve SERVER (string).
-Optional argument PORT is port number (integer) on remote server.
-Optional argument STREAM is any of `sieve-manage-streams' (a symbol).
-Optional argument AUTH indicates authenticator to use, see
-`sieve-manage-authenticators' for available authenticators.
-If nil, chooses the best stream the server is capable of.
-Optional argument BUFFER is buffer (buffer, or string naming buffer)
-to work in."
- (setq sieve-manage-port (or port sieve-manage-default-port))
- (with-current-buffer (or buffer (sieve-manage-make-process-buffer))
- (setq sieve-manage-server (or server
- sieve-manage-server)
- sieve-manage-stream (or stream
- sieve-manage-stream
- sieve-manage-default-stream)
- sieve-manage-auth (or auth
- sieve-manage-auth))
- (message "sieve: Connecting to %s..." sieve-manage-server)
- (sieve-manage-open-server sieve-manage-server
- sieve-manage-port
- sieve-manage-stream
- (current-buffer))
- (when (sieve-manage-opened (current-buffer))
- ;; Choose authenticator
- (when (and (null sieve-manage-auth)
- (not (eq sieve-manage-state 'auth)))
- (dolist (auth sieve-manage-authenticators)
- (when (funcall (nth 1 (assq auth sieve-manage-authenticator-alist))
- buffer)
- (setq sieve-manage-auth auth)
- (return)))
- (unless sieve-manage-auth
- (error "Couldn't figure out authenticator for server")))
- (sieve-manage-erase)
- (current-buffer))))
-
-(defun sieve-manage-authenticate (&optional buffer)
- "Authenticate on server in BUFFER.
-Return `sieve-manage-state' value."
- (with-current-buffer (or buffer (current-buffer))
- (if (eq sieve-manage-state 'nonauth)
- (when (funcall (nth 2 (assq sieve-manage-auth
- sieve-manage-authenticator-alist))
- (current-buffer))
- (setq sieve-manage-state 'auth))
- sieve-manage-state)))
-
-(defun sieve-manage-opened (&optional buffer)
- "Return non-nil if connection to managesieve server in BUFFER is open.
-If BUFFER is nil then the current buffer is used."
- (and (setq buffer (get-buffer (or buffer (current-buffer))))
- (buffer-live-p buffer)
- (with-current-buffer buffer
- (and sieve-manage-process
- (memq (process-status sieve-manage-process) '(open run))))))
-
-(defun sieve-manage-close (&optional buffer)
- "Close connection to managesieve server in BUFFER.
-If BUFFER is nil, the current buffer is used."
- (with-current-buffer (or buffer (current-buffer))
- (when (sieve-manage-opened)
- (sieve-manage-send "LOGOUT")
- (sit-for 1))
- (when (and sieve-manage-process
- (memq (process-status sieve-manage-process) '(open run)))
- (delete-process sieve-manage-process))
- (setq sieve-manage-process nil)
- (sieve-manage-erase)
- t))
-
-(defun sieve-manage-capability (&optional name value buffer)
- "Check if capability NAME of server BUFFER match VALUE.
-If it does, return the server value of NAME. If not returns nil.
-If VALUE is nil, do not check VALUE and return server value.
-If NAME is nil, return the full server list of capabilities."
- (with-current-buffer (or buffer (current-buffer))
- (if (null name)
- sieve-manage-capability
- (let ((server-value (cadr (assoc name sieve-manage-capability))))
- (when (or (null value)
- (and server-value
- (string-match value server-value)))
- server-value)))))
-
-(defun sieve-manage-listscripts (&optional buffer)
- (with-current-buffer (or buffer (current-buffer))
- (sieve-manage-send "LISTSCRIPTS")
- (sieve-manage-parse-listscripts)))
-
-(defun sieve-manage-havespace (name size &optional buffer)
- (with-current-buffer (or buffer (current-buffer))
- (sieve-manage-send (format "HAVESPACE \"%s\" %s" name size))
- (sieve-manage-parse-okno)))
-
-(defun sieve-manage-putscript (name content &optional buffer)
- (with-current-buffer (or buffer (current-buffer))
- (sieve-manage-send (format "PUTSCRIPT \"%s\" {%d+}%s%s" name
- ;; Here we assume that the coding-system will
- ;; replace each char with a single byte.
- ;; This is always the case if `content' is
- ;; a unibyte string.
- (length content)
- sieve-manage-client-eol content))
- (sieve-manage-parse-okno)))
-
-(defun sieve-manage-deletescript (name &optional buffer)
- (with-current-buffer (or buffer (current-buffer))
- (sieve-manage-send (format "DELETESCRIPT \"%s\"" name))
- (sieve-manage-parse-okno)))
-
-(defun sieve-manage-getscript (name output-buffer &optional buffer)
- (with-current-buffer (or buffer (current-buffer))
- (sieve-manage-send (format "GETSCRIPT \"%s\"" name))
- (let ((script (sieve-manage-parse-string)))
- (sieve-manage-parse-crlf)
- (with-current-buffer output-buffer
- (insert script))
- (sieve-manage-parse-okno))))
-
-(defun sieve-manage-setactive (name &optional buffer)
- (with-current-buffer (or buffer (current-buffer))
- (sieve-manage-send (format "SETACTIVE \"%s\"" name))
- (sieve-manage-parse-okno)))
-
-;; Protocol parsing routines
-
-(defun sieve-manage-wait-for-answer ()
- (let ((pattern "^\\(OK\\|NO\\).*\n")
- pos)
- (while (not pos)
- (setq pos (search-forward-regexp pattern nil t))
- (goto-char (point-min))
- (sleep-for 0 50))
- pos))
-
-(defun sieve-manage-drop-next-answer ()
- (sieve-manage-wait-for-answer)
- (sieve-manage-erase))
-
-(defun sieve-manage-ok-p (rsp)
- (string= (downcase (or (car-safe rsp) "")) "ok"))
-
-(defun sieve-manage-is-okno ()
- (when (looking-at (concat
- "^\\(OK\\|NO\\)\\( (\\([^)]+\\))\\)?\\( \\(.*\\)\\)?"
- sieve-manage-server-eol))
- (let ((status (match-string 1))
- (resp-code (match-string 3))
- (response (match-string 5)))
- (when response
- (goto-char (match-beginning 5))
- (setq response (sieve-manage-is-string)))
- (list status resp-code response))))
-
-(defun sieve-manage-parse-okno ()
- (let (rsp)
- (while (null rsp)
- (accept-process-output (get-buffer-process (current-buffer)) 1)
- (goto-char (point-min))
- (setq rsp (sieve-manage-is-okno)))
- (sieve-manage-erase)
- rsp))
-
-(defun sieve-manage-parse-capability (str)
- "Parse managesieve capability string `STR'.
-Set variable `sieve-manage-capability' to "
- (let ((capas (delq nil
- (mapcar #'split-string-and-unquote
- (split-string str "\n")))))
- (when (string= "OK" (caar (last capas)))
- (setq sieve-manage-state 'nonauth))
- capas))
-
-(defun sieve-manage-is-string ()
- (cond ((looking-at "\"\\([^\"]+\\)\"")
- (prog1
- (match-string 1)
- (goto-char (match-end 0))))
- ((looking-at (concat "{\\([0-9]+\\+?\\)}" sieve-manage-server-eol))
- (let ((pos (match-end 0))
- (len (string-to-number (match-string 1))))
- (if (< (point-max) (+ pos len))
- nil
- (goto-char (+ pos len))
- (buffer-substring pos (+ pos len)))))))
-
-(defun sieve-manage-parse-string ()
- (let (rsp)
- (while (null rsp)
- (accept-process-output (get-buffer-process (current-buffer)) 1)
- (goto-char (point-min))
- (setq rsp (sieve-manage-is-string)))
- (sieve-manage-erase (point))
- rsp))
-
-(defun sieve-manage-parse-crlf ()
- (when (looking-at sieve-manage-server-eol)
- (sieve-manage-erase (match-end 0))))
-
-(defun sieve-manage-parse-listscripts ()
- (let (tmp rsp data)
- (while (null rsp)
- (while (null (or (setq rsp (sieve-manage-is-okno))
- (setq tmp (sieve-manage-is-string))))
- (accept-process-output (get-buffer-process (current-buffer)) 1)
- (goto-char (point-min)))
- (when tmp
- (while (not (looking-at (concat "\\( ACTIVE\\)?"
- sieve-manage-server-eol)))
- (accept-process-output (get-buffer-process (current-buffer)) 1)
- (goto-char (point-min)))
- (if (match-string 1)
- (push (cons 'active tmp) data)
- (push tmp data))
- (goto-char (match-end 0))
- (setq tmp nil)))
- (sieve-manage-erase)
- (if (sieve-manage-ok-p rsp)
- data
- rsp)))
-
-(defun sieve-manage-send (cmdstr)
- (setq cmdstr (concat cmdstr sieve-manage-client-eol))
- (and sieve-manage-log
- (with-current-buffer (get-buffer-create sieve-manage-log)
- (mm-enable-multibyte)
- (buffer-disable-undo)
- (goto-char (point-max))
- (insert cmdstr)))
- (process-send-string sieve-manage-process cmdstr))
-
-(provide 'sieve-manage)
-
-;; sieve-manage.el ends here