aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChong Yidong2011-03-26 19:18:42 -0400
committerChong Yidong2011-03-26 19:18:42 -0400
commitf2eefd24778eb8d577ea09a5c2d28b4df1471b8b (patch)
tree6561d7cb137444cc28deda72405a5dbd6bb91893
parent181855e600437c16fe4137d316c1337ad5d5d791 (diff)
downloademacs-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/ChangeLog36
-rw-r--r--lisp/gnus/nnimap.el41
-rw-r--r--lisp/gnus/nntp.el33
-rw-r--r--lisp/gnus/proto-stream.el321
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 @@
12011-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
12011-03-25 Teodor Zlatanov <tzz@lifelogs.com> 372011-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.
65Values are `ssl', `network', `network-only, `starttls' or 65Values 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.
69The first four parameters have the same meaning as in 60Normally, 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).
71first element is the stream, the second element is the greeting 62
72the server replied with after connecting, and the third element 63The first four parameters, NAME, BUFFER, HOST, and SERVICE, have
73is a string representing the capabilities of the server (if any). 64the same meanings as in `open-network-stream'. The remaining
74 65PARAMETERS should be a sequence of keywords and values:
75The PARAMETERS is a keyword list that can have the following 66
76values: 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
80will be opportunistically upgraded to STARTTLS if both the server 71 upgrading it to an encrypted connection via
81and 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,
85This 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.
88successful 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.
91query 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.
95is the response to the capaibility command. It should return nil 86 :capabilities -- a string representing HOST's capabilities,
96if it turns out that the server doesn't support STARTTLS, or the 87 or nil if none could be found.
97command to switch on STARTTLS otherwise. 88 :type -- the actual connection type; either `default' for an
98 89 unencrypted connection, or `tls'.
99The return value from this function is a four-element list, where 90
100the first element is the stream (if connection was successful); 91:end-of-command specifies a regexp matching the end of a command.
101the second element is the \"greeting\", i. e., the string the 92 If non-nil, it defaults to \"\\n\".
102server sent over on initial contact; the third element is the 93
103capability 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
105encrypted 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