diff options
| author | Chong Yidong | 2011-03-26 19:18:42 -0400 |
|---|---|---|
| committer | Chong Yidong | 2011-03-26 19:18:42 -0400 |
| commit | f2eefd24778eb8d577ea09a5c2d28b4df1471b8b (patch) | |
| tree | 6561d7cb137444cc28deda72405a5dbd6bb91893 | |
| parent | 181855e600437c16fe4137d316c1337ad5d5d791 (diff) | |
| download | emacs-f2eefd24778eb8d577ea09a5c2d28b4df1471b8b.tar.gz emacs-f2eefd24778eb8d577ea09a5c2d28b4df1471b8b.zip | |
Changes to open-protocol-stream, preparing for merging it with open-network-stream.
* lisp/gnus/proto-stream.el: Changes preparatory to merging open-protocol-stream
with open-network-stream.
(proto-stream-always-use-starttls): Option removed.
(open-protocol-stream): Return a process object by default. Provide a
new parameter :return-list specifying a list-type return value, which
now has the form (PROP . PLIST) instead of a fixed-length list. Change
:type `network' to `try-starttls', and `network-only' to `default'.
Make `default' the default, for compatibility with open-network-stream.
Handle the no-parameter case exactly as open-network-stream, with no
additional stream processing. Search plists using plist-get.
Explicitly add :end-of-commend parameter if it is missing.
(proto-stream-open-default): Renamed from
proto-stream-open-network-only. Return 'default as the type.
(proto-stream-open-starttls): Rename from proto-stream-open-network.
Use plist-get. Don't return `tls' as the type if STARTTLS negotiation
failed. Always return a list with a (possibly dead) process as the
first element, for compatibility with open-network-stream.
(proto-stream-open-tls): Use plist-get. Always return a list.
(proto-stream-open-shell): Return `default' as connection type.
(proto-stream-capability-open): Use plist-get.
(proto-stream-eoc): Function deleted.
* lisp/gnus/nnimap.el (nnimap-stream, nnimap-open-connection)
(nnimap-open-connection-1): Handle renaming of :type parameter for
open-protocol-stream.
(nnimap-open-connection-1): Pass a :return-list parameter
open-protocol-stream to obtain a list return value. Parse this list
using plist-get.
* lisp/gnus/nntp.el (nntp-open-connection): Handle renaming of :type parameter
for open-protocol-stream. Accept open-protocol-stream return value
that is a subprocess object instead of a list. Handle the case of a
dead returned process.
| -rw-r--r-- | lisp/gnus/ChangeLog | 36 | ||||
| -rw-r--r-- | lisp/gnus/nnimap.el | 41 | ||||
| -rw-r--r-- | lisp/gnus/nntp.el | 33 | ||||
| -rw-r--r-- | lisp/gnus/proto-stream.el | 321 |
4 files changed, 232 insertions, 199 deletions
diff --git a/lisp/gnus/ChangeLog b/lisp/gnus/ChangeLog index ddc946383b6..f257ff51f3d 100644 --- a/lisp/gnus/ChangeLog +++ b/lisp/gnus/ChangeLog | |||
| @@ -1,3 +1,39 @@ | |||
| 1 | 2011-03-26 Chong Yidong <cyd@stupidchicken.com> | ||
| 2 | |||
| 3 | * proto-stream.el: Changes preparatory to merging open-protocol-stream | ||
| 4 | with open-network-stream. | ||
| 5 | (proto-stream-always-use-starttls): Option removed. | ||
| 6 | (open-protocol-stream): Return a process object by default. Provide a | ||
| 7 | new parameter :return-list specifying a list-type return value, which | ||
| 8 | now has the form (PROP . PLIST) instead of a fixed-length list. Change | ||
| 9 | :type `network' to `try-starttls', and `network-only' to `default'. | ||
| 10 | Make `default' the default, for compatibility with open-network-stream. | ||
| 11 | Handle the no-parameter case exactly as open-network-stream, with no | ||
| 12 | additional stream processing. Search plists using plist-get. | ||
| 13 | Explicitly add :end-of-commend parameter if it is missing. | ||
| 14 | (proto-stream-open-default): Renamed from | ||
| 15 | proto-stream-open-network-only. Return 'default as the type. | ||
| 16 | (proto-stream-open-starttls): Rename from proto-stream-open-network. | ||
| 17 | Use plist-get. Don't return `tls' as the type if STARTTLS negotiation | ||
| 18 | failed. Always return a list with a (possibly dead) process as the | ||
| 19 | first element, for compatibility with open-network-stream. | ||
| 20 | (proto-stream-open-tls): Use plist-get. Always return a list. | ||
| 21 | (proto-stream-open-shell): Return `default' as connection type. | ||
| 22 | (proto-stream-capability-open): Use plist-get. | ||
| 23 | (proto-stream-eoc): Function deleted. | ||
| 24 | |||
| 25 | * nnimap.el (nnimap-stream, nnimap-open-connection) | ||
| 26 | (nnimap-open-connection-1): Handle renaming of :type parameter for | ||
| 27 | open-protocol-stream. | ||
| 28 | (nnimap-open-connection-1): Pass a :return-list parameter | ||
| 29 | open-protocol-stream to obtain a list return value. Parse this list | ||
| 30 | using plist-get. | ||
| 31 | |||
| 32 | * nntp.el (nntp-open-connection): Handle renaming of :type parameter | ||
| 33 | for open-protocol-stream. Accept open-protocol-stream return value | ||
| 34 | that is a subprocess object instead of a list. Handle the case of a | ||
| 35 | dead returned process. | ||
| 36 | |||
| 1 | 2011-03-25 Teodor Zlatanov <tzz@lifelogs.com> | 37 | 2011-03-25 Teodor Zlatanov <tzz@lifelogs.com> |
| 2 | 38 | ||
| 3 | * mm-util.el (mm-handle-filename): Move to mm-decode.el (bug#8330). | 39 | * mm-util.el (mm-handle-filename): Move to mm-decode.el (bug#8330). |
diff --git a/lisp/gnus/nnimap.el b/lisp/gnus/nnimap.el index bcbe7b678d5..15d7f463d41 100644 --- a/lisp/gnus/nnimap.el +++ b/lisp/gnus/nnimap.el | |||
| @@ -62,9 +62,9 @@ it will default to `imap'.") | |||
| 62 | 62 | ||
| 63 | (defvoo nnimap-stream 'undecided | 63 | (defvoo nnimap-stream 'undecided |
| 64 | "How nnimap will talk to the IMAP server. | 64 | "How nnimap will talk to the IMAP server. |
| 65 | Values are `ssl', `network', `network-only, `starttls' or | 65 | Values are `ssl', `default', `try-starttls', `starttls' or |
| 66 | `shell'. The default is to try `ssl' first, and then | 66 | `shell'. The default is to try `ssl' first, and then |
| 67 | `network'.") | 67 | `try-starttls'.") |
| 68 | 68 | ||
| 69 | (defvoo nnimap-shell-program (if (boundp 'imap-shell-program) | 69 | (defvoo nnimap-shell-program (if (boundp 'imap-shell-program) |
| 70 | (if (listp imap-shell-program) | 70 | (if (listp imap-shell-program) |
| @@ -319,7 +319,7 @@ textual parts.") | |||
| 319 | (setq nnimap-stream 'ssl)) | 319 | (setq nnimap-stream 'ssl)) |
| 320 | (let ((stream | 320 | (let ((stream |
| 321 | (if (eq nnimap-stream 'undecided) | 321 | (if (eq nnimap-stream 'undecided) |
| 322 | (loop for type in '(ssl network) | 322 | (loop for type in '(ssl try-starttls) |
| 323 | for stream = (let ((nnimap-stream type)) | 323 | for stream = (let ((nnimap-stream type)) |
| 324 | (nnimap-open-connection-1 buffer)) | 324 | (nnimap-open-connection-1 buffer)) |
| 325 | while (eq stream 'no-connect) | 325 | while (eq stream 'no-connect) |
| @@ -339,9 +339,7 @@ textual parts.") | |||
| 339 | (port nil) | 339 | (port nil) |
| 340 | (ports | 340 | (ports |
| 341 | (cond | 341 | (cond |
| 342 | ((or (eq nnimap-stream 'network) | 342 | ((memq nnimap-stream '(try-starttls default starttls)) |
| 343 | (eq nnimap-stream 'network-only) | ||
| 344 | (eq nnimap-stream 'starttls)) | ||
| 345 | (nnheader-message 7 "Opening connection to %s..." | 343 | (nnheader-message 7 "Opening connection to %s..." |
| 346 | nnimap-address) | 344 | nnimap-address) |
| 347 | '("imap" "143")) | 345 | '("imap" "143")) |
| @@ -355,21 +353,28 @@ textual parts.") | |||
| 355 | '("imaps" "imap" "993" "143")) | 353 | '("imaps" "imap" "993" "143")) |
| 356 | (t | 354 | (t |
| 357 | (error "Unknown stream type: %s" nnimap-stream)))) | 355 | (error "Unknown stream type: %s" nnimap-stream)))) |
| 358 | (proto-stream-always-use-starttls t) | ||
| 359 | login-result credentials) | 356 | login-result credentials) |
| 360 | (when nnimap-server-port | 357 | (when nnimap-server-port |
| 361 | (push nnimap-server-port ports)) | 358 | (push nnimap-server-port ports)) |
| 362 | (destructuring-bind (stream greeting capabilities stream-type) | 359 | (let* ((stream-list |
| 363 | (open-protocol-stream | 360 | (open-protocol-stream |
| 364 | "*nnimap*" (current-buffer) nnimap-address (car ports) | 361 | "*nnimap*" (current-buffer) nnimap-address (car ports) |
| 365 | :type nnimap-stream | 362 | :type nnimap-stream |
| 366 | :shell-command nnimap-shell-program | 363 | :return-list t |
| 367 | :capability-command "1 CAPABILITY\r\n" | 364 | :shell-command nnimap-shell-program |
| 368 | :success " OK " | 365 | :capability-command "1 CAPABILITY\r\n" |
| 369 | :starttls-function | 366 | :success " OK " |
| 370 | (lambda (capabilities) | 367 | :starttls-function |
| 371 | (when (gnus-string-match-p "STARTTLS" capabilities) | 368 | (lambda (capabilities) |
| 372 | "1 STARTTLS\r\n"))) | 369 | (when (gnus-string-match-p "STARTTLS" capabilities) |
| 370 | "1 STARTTLS\r\n")))) | ||
| 371 | (stream (car stream-list)) | ||
| 372 | (props (cdr stream-list)) | ||
| 373 | (greeting (plist-get props :greeting)) | ||
| 374 | (capabilities (plist-get props :capabilities)) | ||
| 375 | (stream-type (plist-get props :type))) | ||
| 376 | (when (and stream (not (memq (process-status stream) '(open run)))) | ||
| 377 | (setq stream nil)) | ||
| 373 | (setf (nnimap-process nnimap-object) stream) | 378 | (setf (nnimap-process nnimap-object) stream) |
| 374 | (setf (nnimap-stream-type nnimap-object) stream-type) | 379 | (setf (nnimap-stream-type nnimap-object) stream-type) |
| 375 | (if (not stream) | 380 | (if (not stream) |
diff --git a/lisp/gnus/nntp.el b/lisp/gnus/nntp.el index 66a6365cb3b..9065027d34f 100644 --- a/lisp/gnus/nntp.el +++ b/lisp/gnus/nntp.el | |||
| @@ -1339,26 +1339,26 @@ password contained in '~/.nntp-authinfo'." | |||
| 1339 | (condition-case err | 1339 | (condition-case err |
| 1340 | (let ((coding-system-for-read nntp-coding-system-for-read) | 1340 | (let ((coding-system-for-read nntp-coding-system-for-read) |
| 1341 | (coding-system-for-write nntp-coding-system-for-write) | 1341 | (coding-system-for-write nntp-coding-system-for-write) |
| 1342 | (map '((nntp-open-network-stream network) | 1342 | (map '((nntp-open-network-stream try-starttls) |
| 1343 | (network-only network-only) | 1343 | (network-only default) |
| 1344 | (nntp-open-ssl-stream tls) | 1344 | (nntp-open-ssl-stream tls) |
| 1345 | (nntp-open-tls-stream tls)))) | 1345 | (nntp-open-tls-stream tls)))) |
| 1346 | (if (assoc nntp-open-connection-function map) | 1346 | (if (assoc nntp-open-connection-function map) |
| 1347 | (car (open-protocol-stream | 1347 | (open-protocol-stream |
| 1348 | "nntpd" pbuffer nntp-address nntp-port-number | 1348 | "nntpd" pbuffer nntp-address nntp-port-number |
| 1349 | :type (cadr | 1349 | :type (or (cadr (assoc nntp-open-connection-function map)) |
| 1350 | (assoc nntp-open-connection-function map)) | 1350 | 'try-starttls) |
| 1351 | :end-of-command "^\\([2345]\\|[.]\\).*\n" | 1351 | :end-of-command "^\\([2345]\\|[.]\\).*\n" |
| 1352 | :capability-command "CAPABILITIES\r\n" | 1352 | :capability-command "CAPABILITIES\r\n" |
| 1353 | :success "^3" | 1353 | :success "^3" |
| 1354 | :starttls-function | 1354 | :starttls-function |
| 1355 | (lambda (capabilities) | 1355 | (lambda (capabilities) |
| 1356 | (if (not (string-match "STARTTLS" capabilities)) | 1356 | (if (not (string-match "STARTTLS" capabilities)) |
| 1357 | nil | 1357 | nil |
| 1358 | "STARTTLS\r\n")))) | 1358 | "STARTTLS\r\n"))) |
| 1359 | (funcall nntp-open-connection-function pbuffer))) | 1359 | (funcall nntp-open-connection-function pbuffer))) |
| 1360 | (error | 1360 | (error |
| 1361 | (nnheader-report 'nntp "%s" err)) | 1361 | (nnheader-report 'nntp ">>> %s" err)) |
| 1362 | (quit | 1362 | (quit |
| 1363 | (message "Quit opening connection to %s" nntp-address) | 1363 | (message "Quit opening connection to %s" nntp-address) |
| 1364 | (nntp-kill-buffer pbuffer) | 1364 | (nntp-kill-buffer pbuffer) |
| @@ -1366,6 +1366,9 @@ password contained in '~/.nntp-authinfo'." | |||
| 1366 | nil)))) | 1366 | nil)))) |
| 1367 | (when timer | 1367 | (when timer |
| 1368 | (nnheader-cancel-timer timer)) | 1368 | (nnheader-cancel-timer timer)) |
| 1369 | (when (and process | ||
| 1370 | (not (memq (process-status process) '(open run)))) | ||
| 1371 | (setq process nil)) | ||
| 1369 | (unless process | 1372 | (unless process |
| 1370 | (nntp-kill-buffer pbuffer)) | 1373 | (nntp-kill-buffer pbuffer)) |
| 1371 | (when (and (buffer-name pbuffer) | 1374 | (when (and (buffer-name pbuffer) |
diff --git a/lisp/gnus/proto-stream.el b/lisp/gnus/proto-stream.el index fdf2abfea05..5e92cb40264 100644 --- a/lisp/gnus/proto-stream.el +++ b/lisp/gnus/proto-stream.el | |||
| @@ -37,7 +37,7 @@ | |||
| 37 | 37 | ||
| 38 | ;; (open-protocol-stream | 38 | ;; (open-protocol-stream |
| 39 | ;; "*nnimap*" buffer address port | 39 | ;; "*nnimap*" buffer address port |
| 40 | ;; :type 'network | 40 | ;; :type 'try-starttls |
| 41 | ;; :capability-command "1 CAPABILITY\r\n" | 41 | ;; :capability-command "1 CAPABILITY\r\n" |
| 42 | ;; :success " OK " | 42 | ;; :success " OK " |
| 43 | ;; :starttls-function | 43 | ;; :starttls-function |
| @@ -48,171 +48,164 @@ | |||
| 48 | 48 | ||
| 49 | ;;; Code: | 49 | ;;; Code: |
| 50 | 50 | ||
| 51 | (eval-when-compile | ||
| 52 | (require 'cl)) | ||
| 53 | (require 'tls) | 51 | (require 'tls) |
| 54 | (require 'starttls) | 52 | (require 'starttls) |
| 55 | (require 'format-spec) | ||
| 56 | |||
| 57 | (defcustom proto-stream-always-use-starttls (fboundp 'open-gnutls-stream) | ||
| 58 | "If non-nil, always try to upgrade network connections with STARTTLS." | ||
| 59 | :version "24.1" | ||
| 60 | :type 'boolean | ||
| 61 | :group 'comm) | ||
| 62 | 53 | ||
| 63 | (declare-function gnutls-negotiate "gnutls" | 54 | (declare-function gnutls-negotiate "gnutls" |
| 64 | (proc type &optional priority-string trustfiles keyfiles)) | 55 | (proc type &optional priority-string trustfiles keyfiles)) |
| 65 | 56 | ||
| 66 | ;;;###autoload | 57 | ;;;###autoload |
| 67 | (defun open-protocol-stream (name buffer host service &rest parameters) | 58 | (defun open-protocol-stream (name buffer host service &rest parameters) |
| 68 | "Open a network stream to HOST, upgrading to STARTTLS if possible. | 59 | "Open a network stream to HOST, possibly with encryption. |
| 69 | The first four parameters have the same meaning as in | 60 | Normally, return a network process object; with a non-nil |
| 70 | `open-network-stream'. The function returns a list where the | 61 | :return-list parameter, return a list instead (see below). |
| 71 | first element is the stream, the second element is the greeting | 62 | |
| 72 | the server replied with after connecting, and the third element | 63 | The first four parameters, NAME, BUFFER, HOST, and SERVICE, have |
| 73 | is a string representing the capabilities of the server (if any). | 64 | the same meanings as in `open-network-stream'. The remaining |
| 74 | 65 | PARAMETERS should be a sequence of keywords and values: | |
| 75 | The PARAMETERS is a keyword list that can have the following | 66 | |
| 76 | values: | 67 | :type specifies the connection type, one of the following: |
| 77 | 68 | `default' -- An ordinary network connection. | |
| 78 | :type -- either `network', `network-only, `tls', `shell' or | 69 | `try-starttls' |
| 79 | `starttls'. If omitted, the default is `network'. `network' | 70 | -- Begin an ordinary network connection, and try |
| 80 | will be opportunistically upgraded to STARTTLS if both the server | 71 | upgrading it to an encrypted connection via |
| 81 | and Emacs supports it. If you don't want STARTTLS upgrades, use | 72 | STARTTLS if both HOST and Emacs support TLS. If |
| 82 | `network-only'. | 73 | that fails, keep the unencrypted connection. |
| 83 | 74 | `starttls' -- Begin an ordinary connection, and try upgrading | |
| 84 | :end-of-command -- a regexp saying what the end of a command is. | 75 | it via STARTTLS. If that fails for any reason, |
| 85 | This defaults to \"\\n\". | 76 | drop the connection; in this case, the returned |
| 86 | 77 | process object is a killed process. | |
| 87 | :success -- a regexp saying whether the STARTTLS command was | 78 | `tls' or `ssl' -- A TLS connection. |
| 88 | successful or not. For instance, for NNTP this is \"^3\". | 79 | `shell' -- A shell connection. |
| 89 | 80 | ||
| 90 | :capability-command -- a string representing the command used to | 81 | :return-list specifies this function's return value. |
| 91 | query server for capabilities. For instance, for IMAP this is | 82 | If omitted or nil, return a process object. A non-nil means to |
| 92 | \"1 CAPABILITY\\r\\n\". | 83 | return (PROC . PROPS), where PROC is a process object and PROPS |
| 93 | 84 | is a plist of connection properties, with these keywords: | |
| 94 | :starttls-function -- a function that takes one parameter, which | 85 | :greeting -- the greeting returned by HOST (a string), or nil. |
| 95 | is the response to the capaibility command. It should return nil | 86 | :capabilities -- a string representing HOST's capabilities, |
| 96 | if it turns out that the server doesn't support STARTTLS, or the | 87 | or nil if none could be found. |
| 97 | command to switch on STARTTLS otherwise. | 88 | :type -- the actual connection type; either `default' for an |
| 98 | 89 | unencrypted connection, or `tls'. | |
| 99 | The return value from this function is a four-element list, where | 90 | |
| 100 | the first element is the stream (if connection was successful); | 91 | :end-of-command specifies a regexp matching the end of a command. |
| 101 | the second element is the \"greeting\", i. e., the string the | 92 | If non-nil, it defaults to \"\\n\". |
| 102 | server sent over on initial contact; the third element is the | 93 | |
| 103 | capability string; and the fourth element is either `network' or | 94 | :success specifies a regexp matching a message indicating a |
| 104 | `tls', depending on whether the connection ended up being | 95 | successful STARTTLS negotiation. For instance, the default |
| 105 | encrypted or not." | 96 | should be \"^3\" for an NNTP connection. If this is not |
| 106 | (let ((type (or (cadr (memq :type parameters)) 'network))) | 97 | supplied, STARTTLS will always fail. |
| 107 | (cond | 98 | |
| 108 | ((eq type 'starttls) | 99 | :capability-command specifies a command used to query the HOST |
| 109 | (setq type 'network)) | 100 | for its capabilities. For instance, for IMAP this should be |
| 110 | ((eq type 'ssl) | 101 | \"1 CAPABILITY\\r\\n\". |
| 111 | (setq type 'tls))) | 102 | |
| 112 | (let ((open-result | 103 | :starttls-function specifies a function for handling STARTTLS. |
| 113 | (funcall (intern (format "proto-stream-open-%s" type) obarray) | 104 | This function should take one parameter, the response to the |
| 114 | name buffer host service parameters))) | 105 | capability command, and should return the command to switch on |
| 115 | (if (null open-result) | 106 | STARTTLS if the server supports STARTTLS, and nil otherwise." |
| 116 | (list nil nil nil type) | 107 | (let ((type (plist-get parameters :type)) |
| 117 | (let ((stream (car open-result))) | 108 | (return-list (plist-get parameters :return-list))) |
| 118 | (list (and stream | 109 | (if (and (null return-list) (memq type '(nil default))) |
| 119 | (memq (process-status stream) | 110 | ;; The simplest case---no encryption, and no need to report |
| 120 | '(open run)) | 111 | ;; connection properties. Like `open-network-stream', this |
| 121 | stream) | 112 | ;; doesn't read anything into BUFFER yet. |
| 122 | (nth 1 open-result) | 113 | (open-network-stream name buffer host service) |
| 123 | (nth 2 open-result) | 114 | ;; For everything else, refer to proto-stream-open-*. |
| 124 | (nth 3 open-result))))))) | 115 | (unless (plist-get parameters :end-of-command) |
| 125 | 116 | (setq parameters | |
| 126 | (defun proto-stream-open-network-only (name buffer host service parameters) | 117 | (append '(:end-of-command "\r\n") parameters))) |
| 118 | (let* ((connection-function | ||
| 119 | (cond | ||
| 120 | ((memq type '(nil default)) | ||
| 121 | 'proto-stream-open-default) | ||
| 122 | ((memq type '(try-starttls starttls)) | ||
| 123 | 'proto-stream-open-starttls) | ||
| 124 | ((memq type '(tls ssl)) | ||
| 125 | 'proto-stream-open-tls) | ||
| 126 | ((eq type 'shell) | ||
| 127 | 'proto-stream-open-shell) | ||
| 128 | (t | ||
| 129 | (error "Invalid connection type %s" type)))) | ||
| 130 | (result (funcall connection-function | ||
| 131 | name buffer host service parameters))) | ||
| 132 | (if return-list | ||
| 133 | (list (car result) | ||
| 134 | :greeting (nth 1 result) | ||
| 135 | :capabilities (nth 2 result) | ||
| 136 | :type (nth 3 result)) | ||
| 137 | (car result)))))) | ||
| 138 | |||
| 139 | (defun proto-stream-open-default (name buffer host service parameters) | ||
| 127 | (let ((start (with-current-buffer buffer (point))) | 140 | (let ((start (with-current-buffer buffer (point))) |
| 128 | (stream (open-network-stream name buffer host service))) | 141 | (stream (open-network-stream name buffer host service))) |
| 129 | (list stream | 142 | (list stream |
| 130 | (proto-stream-get-response | 143 | (proto-stream-get-response stream start |
| 131 | stream start (proto-stream-eoc parameters)) | 144 | (plist-get parameters :end-of-command)) |
| 132 | nil | 145 | nil |
| 133 | 'network))) | 146 | 'default))) |
| 134 | 147 | ||
| 135 | (defun proto-stream-open-network (name buffer host service parameters) | 148 | (defun proto-stream-open-starttls (name buffer host service parameters) |
| 136 | (let* ((start (with-current-buffer buffer (point))) | 149 | (let* ((start (with-current-buffer buffer (point))) |
| 150 | ;; This should be `starttls' or `try-starttls'. | ||
| 151 | (type (plist-get parameters :type)) | ||
| 152 | (starttls-function (plist-get parameters :starttls-function)) | ||
| 153 | (success-string (plist-get parameters :success)) | ||
| 154 | (capability-command (plist-get parameters :capability-command)) | ||
| 155 | (eoc (plist-get parameters :end-of-command)) | ||
| 156 | ;; Return (STREAM GREETING CAPABILITIES RESULTING-TYPE) | ||
| 137 | (stream (open-network-stream name buffer host service)) | 157 | (stream (open-network-stream name buffer host service)) |
| 138 | (capability-command (cadr (memq :capability-command parameters))) | ||
| 139 | (eoc (proto-stream-eoc parameters)) | ||
| 140 | (type (cadr (memq :type parameters))) | ||
| 141 | (greeting (proto-stream-get-response stream start eoc)) | 158 | (greeting (proto-stream-get-response stream start eoc)) |
| 142 | success) | 159 | (capabilities (when capability-command |
| 143 | (if (not capability-command) | 160 | (proto-stream-command stream |
| 144 | (list stream greeting nil 'network) | 161 | capability-command eoc))) |
| 145 | (let* ((capabilities | 162 | (resulting-type 'default) |
| 146 | (proto-stream-command stream capability-command eoc)) | 163 | starttls-command) |
| 147 | (starttls-command | 164 | |
| 148 | (funcall (cadr (memq :starttls-function parameters)) | 165 | ;; If we have STARTTLS support, try to upgrade the connection. |
| 149 | capabilities))) | 166 | (when (and (or (fboundp 'open-gnutls-stream) |
| 150 | (cond | 167 | (executable-find "gnutls-cli")) |
| 151 | ;; If this server doesn't support STARTTLS, but we have | 168 | capabilities success-string starttls-function |
| 152 | ;; requested it explicitly, then close the connection and | 169 | (setq starttls-command |
| 153 | ;; return nil. | 170 | (funcall starttls-function capabilities))) |
| 154 | ((or (not starttls-command) | 171 | ;; If using external STARTTLS, drop this connection and start |
| 155 | (and (not (eq type 'starttls)) | 172 | ;; anew with `starttls-open-stream'. |
| 156 | (not proto-stream-always-use-starttls))) | 173 | (unless (fboundp 'open-gnutls-stream) |
| 157 | (if (eq type 'starttls) | 174 | (delete-process stream) |
| 158 | (progn | 175 | (setq start (with-current-buffer buffer (point-max))) |
| 159 | (delete-process stream) | 176 | (let* ((starttls-use-gnutls t) |
| 160 | nil) | 177 | (starttls-extra-arguments |
| 161 | ;; Otherwise, just return this plain network connection. | 178 | (if (not (eq type 'starttls)) |
| 162 | (list stream greeting capabilities 'network))) | 179 | ;; For opportunistic TLS upgrades, we don't |
| 163 | ;; We have some kind of STARTTLS support, so we try to | 180 | ;; really care about the identity of the peer. |
| 164 | ;; upgrade the connection opportunistically. | 181 | (cons "--insecure" starttls-extra-arguments) |
| 165 | ((or (fboundp 'open-gnutls-stream) | 182 | starttls-extra-arguments))) |
| 166 | (executable-find "gnutls-cli")) | 183 | (setq stream (starttls-open-stream name buffer host service))) |
| 167 | (unless (fboundp 'open-gnutls-stream) | 184 | (proto-stream-get-response stream start eoc)) |
| 168 | (delete-process stream) | 185 | (when (string-match success-string |
| 169 | (setq start (with-current-buffer buffer (point-max))) | 186 | (proto-stream-command stream starttls-command eoc)) |
| 170 | (let* ((starttls-use-gnutls t) | 187 | ;; The server said it was OK to begin STARTTLS negotiations. |
| 171 | (starttls-extra-arguments | 188 | (if (fboundp 'open-gnutls-stream) |
| 172 | (if (not (eq type 'starttls)) | 189 | (gnutls-negotiate stream nil) |
| 173 | ;; When doing opportunistic TLS upgrades we | 190 | (unless (starttls-negotiate stream) |
| 174 | ;; don't really care about the identity of the | 191 | (delete-process stream))) |
| 175 | ;; peer. | 192 | (if (memq (process-status stream) '(open run)) |
| 176 | (cons "--insecure" starttls-extra-arguments) | 193 | (setq resulting-type 'tls) |
| 177 | starttls-extra-arguments))) | 194 | ;; We didn't successfully negotiate STARTTLS; if TLS |
| 178 | (setq stream (starttls-open-stream name buffer host service))) | 195 | ;; isn't demanded, reopen an unencrypted connection. |
| 179 | (proto-stream-get-response stream start eoc)) | 196 | (when (eq type 'try-starttls) |
| 180 | (if (not | 197 | (setq stream (open-network-stream name buffer host service)) |
| 181 | (string-match | 198 | (proto-stream-get-response stream start eoc))) |
| 182 | (cadr (memq :success parameters)) | 199 | ;; Re-get the capabilities, which may have now changed. |
| 183 | (proto-stream-command stream starttls-command eoc))) | 200 | (setq capabilities |
| 184 | ;; We got an error back from the STARTTLS command. | 201 | (proto-stream-command stream capability-command eoc)))) |
| 185 | (progn | 202 | |
| 186 | (if (eq type 'starttls) | 203 | ;; If TLS is mandatory, close the connection if it's unencrypted. |
| 187 | (progn | 204 | (and (eq type 'starttls) |
| 188 | (delete-process stream) | 205 | (eq resulting-type 'default) |
| 189 | nil) | 206 | (delete-process stream)) |
| 190 | (list stream greeting capabilities 'network))) | 207 | ;; Return value: |
| 191 | ;; The server said it was OK to start doing STARTTLS negotiations. | 208 | (list stream greeting capabilities resulting-type))) |
| 192 | (if (fboundp 'open-gnutls-stream) | ||
| 193 | (gnutls-negotiate stream nil) | ||
| 194 | (unless (starttls-negotiate stream) | ||
| 195 | (delete-process stream) | ||
| 196 | (setq stream nil))) | ||
| 197 | (when (or (null stream) | ||
| 198 | (not (memq (process-status stream) | ||
| 199 | '(open run)))) | ||
| 200 | ;; It didn't successfully negotiate STARTTLS, so we reopen | ||
| 201 | ;; the connection. | ||
| 202 | (setq stream (open-network-stream name buffer host service)) | ||
| 203 | (proto-stream-get-response stream start eoc)) | ||
| 204 | ;; Re-get the capabilities, since they may have changed | ||
| 205 | ;; after switching to TLS. | ||
| 206 | (list stream greeting | ||
| 207 | (proto-stream-command stream capability-command eoc) 'tls))) | ||
| 208 | ;; We don't have STARTTLS support available, but the caller | ||
| 209 | ;; requested a STARTTLS connection, so we give up. | ||
| 210 | ((eq (cadr (memq :type parameters)) 'starttls) | ||
| 211 | (delete-process stream) | ||
| 212 | nil) | ||
| 213 | ;; Fall back on using a plain network stream. | ||
| 214 | (t | ||
| 215 | (list stream greeting capabilities 'network))))))) | ||
| 216 | 209 | ||
| 217 | (defun proto-stream-command (stream command eoc) | 210 | (defun proto-stream-command (stream command eoc) |
| 218 | (let ((start (with-current-buffer (process-buffer stream) (point-max)))) | 211 | (let ((start (with-current-buffer (process-buffer stream) (point-max)))) |
| @@ -241,47 +234,43 @@ encrypted or not." | |||
| 241 | (funcall (if (fboundp 'open-gnutls-stream) | 234 | (funcall (if (fboundp 'open-gnutls-stream) |
| 242 | 'open-gnutls-stream | 235 | 'open-gnutls-stream |
| 243 | 'open-tls-stream) | 236 | 'open-tls-stream) |
| 244 | name buffer host service))) | 237 | name buffer host service)) |
| 238 | (eoc (plist-get parameters :end-of-command))) | ||
| 245 | (if (null stream) | 239 | (if (null stream) |
| 246 | nil | 240 | (list nil nil nil 'default) |
| 247 | ;; If we're using tls.el, we have to delete the output from | 241 | ;; If we're using tls.el, we have to delete the output from |
| 248 | ;; openssl/gnutls-cli. | 242 | ;; openssl/gnutls-cli. |
| 249 | (unless (fboundp 'open-gnutls-stream) | 243 | (unless (fboundp 'open-gnutls-stream) |
| 250 | (proto-stream-get-response | 244 | (proto-stream-get-response stream start eoc) |
| 251 | stream start (proto-stream-eoc parameters)) | ||
| 252 | (goto-char (point-min)) | 245 | (goto-char (point-min)) |
| 253 | (when (re-search-forward (proto-stream-eoc parameters) nil t) | 246 | (when (re-search-forward eoc nil t) |
| 254 | (goto-char (match-beginning 0)) | 247 | (goto-char (match-beginning 0)) |
| 255 | (delete-region (point-min) (line-beginning-position)))) | 248 | (delete-region (point-min) (line-beginning-position)))) |
| 256 | (proto-stream-capability-open start stream parameters 'tls))))) | 249 | (proto-stream-capability-open start stream parameters 'tls))))) |
| 257 | 250 | ||
| 258 | (defun proto-stream-open-shell (name buffer host service parameters) | 251 | (defun proto-stream-open-shell (name buffer host service parameters) |
| 252 | (require 'format-spec) | ||
| 259 | (proto-stream-capability-open | 253 | (proto-stream-capability-open |
| 260 | (with-current-buffer buffer (point)) | 254 | (with-current-buffer buffer (point)) |
| 261 | (let ((process-connection-type nil)) | 255 | (let ((process-connection-type nil)) |
| 262 | (start-process name buffer shell-file-name | 256 | (start-process name buffer shell-file-name |
| 263 | shell-command-switch | 257 | shell-command-switch |
| 264 | (format-spec | 258 | (format-spec |
| 265 | (cadr (memq :shell-command parameters)) | 259 | (plist-get parameters :shell-command) |
| 266 | (format-spec-make | 260 | (format-spec-make |
| 267 | ?s host | 261 | ?s host |
| 268 | ?p service)))) | 262 | ?p service)))) |
| 269 | parameters 'network)) | 263 | parameters 'default)) |
| 270 | 264 | ||
| 271 | (defun proto-stream-capability-open (start stream parameters stream-type) | 265 | (defun proto-stream-capability-open (start stream parameters stream-type) |
| 272 | (let ((capability-command (cadr (memq :capability-command parameters))) | 266 | (let* ((capability-command (plist-get parameters :capability-command)) |
| 273 | (greeting (proto-stream-get-response | 267 | (eoc (plist-get parameters :end-of-command)) |
| 274 | stream start (proto-stream-eoc parameters)))) | 268 | (greeting (proto-stream-get-response stream start eoc))) |
| 275 | (list stream greeting | 269 | (list stream greeting |
| 276 | (and capability-command | 270 | (and capability-command |
| 277 | (proto-stream-command | 271 | (proto-stream-command stream capability-command eoc)) |
| 278 | stream capability-command (proto-stream-eoc parameters))) | ||
| 279 | stream-type))) | 272 | stream-type))) |
| 280 | 273 | ||
| 281 | (defun proto-stream-eoc (parameters) | ||
| 282 | (or (cadr (memq :end-of-command parameters)) | ||
| 283 | "\r\n")) | ||
| 284 | |||
| 285 | (provide 'proto-stream) | 274 | (provide 'proto-stream) |
| 286 | 275 | ||
| 287 | ;;; proto-stream.el ends here | 276 | ;;; proto-stream.el ends here |