Merge remote-tracking branch 'sourceforge/master'
[emacs-jabber.git] / jabber-socks5.el
blobee64033c3c856918ef5fecf263d532435af03b14
1 ;; jabber-socks5.el - SOCKS5 bytestreams by JEP-0065
3 ;; Copyright (C) 2003, 2004, 2007 - Magnus Henoch - mange@freemail.hu
4 ;; Copyright (C) 2002, 2003, 2004 - tom berger - object@intelectronica.net
6 ;; This file is a part of jabber.el.
8 ;; This program is free software; you can redistribute it and/or modify
9 ;; it under the terms of the GNU General Public License as published by
10 ;; the Free Software Foundation; either version 2 of the License, or
11 ;; (at your option) any later version.
13 ;; This program is distributed in the hope that it will be useful,
14 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ;; GNU General Public License for more details.
18 ;; You should have received a copy of the GNU General Public License
19 ;; along with this program; if not, write to the Free Software
20 ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 (require 'jabber-iq)
23 (require 'jabber-disco)
24 (require 'jabber-si-server)
25 (require 'jabber-si-client)
26 (require 'jabber-newdisco)
28 (require 'fsm)
29 (eval-when-compile (require 'cl))
31 (defvar jabber-socks5-pending-sessions nil
32 "List of pending sessions.
34 Each entry is a list, containing:
35 * Stream ID
36 * Full JID of initiator
37 * State machine managing the session")
39 (defvar jabber-socks5-active-sessions nil
40 "List of active sessions.
42 Each entry is a list, containing:
43 * Network connection
44 * Stream ID
45 * Full JID of initiator
46 * Profile data function")
48 (defcustom jabber-socks5-proxies nil
49 "JIDs of JEP-0065 proxies to use for file transfer.
50 Put preferred ones first."
51 :type '(repeat string)
52 :group 'jabber
53 ; :set 'jabber-socks5-set-proxies)
56 (defvar jabber-socks5-proxies-data nil
57 "Alist containing information about proxies.
58 Keys of the alist are strings, the JIDs of the proxies.
59 Values are \"streamhost\" XML nodes.")
61 (add-to-list 'jabber-advertised-features "http://jabber.org/protocol/bytestreams")
63 (add-to-list 'jabber-si-stream-methods
64 (list "http://jabber.org/protocol/bytestreams"
65 'jabber-socks5-client-1
66 'jabber-socks5-accept))
68 (defun jabber-socks5-set-proxies (symbol value)
69 "Set `jabber-socks5-proxies' and query proxies.
70 This is the set function of `jabber-socks5-proxies-data'."
71 (set-default symbol value)
72 (when *jabber-connected*
73 (jabber-socks5-query-all-proxies)))
75 (defun jabber-socks5-query-all-proxies (jc &optional callback)
76 "Ask all proxies in `jabber-socks5-proxies' for connection information.
77 If CALLBACK is non-nil, call it with no arguments when all
78 proxies have answered."
79 (interactive (list (jabber-read-account)))
80 (setq jabber-socks5-proxies-data nil)
81 (dolist (proxy jabber-socks5-proxies)
82 (jabber-socks5-query-proxy jc proxy callback)))
84 (defun jabber-socks5-query-proxy (jc jid &optional callback)
85 "Query the SOCKS5 proxy specified by JID for IP and port number."
86 (jabber-send-iq jc jid "get"
87 '(query ((xmlns . "http://jabber.org/protocol/bytestreams")))
88 #'jabber-socks5-process-proxy-response (list callback t)
89 #'jabber-socks5-process-proxy-response (list callback nil)))
91 (defun jabber-socks5-process-proxy-response (jc xml-data closure-data)
92 "Process response from proxy query."
93 (let* ((query (jabber-iq-query xml-data))
94 (from (jabber-xml-get-attribute xml-data 'from))
95 (streamhosts (jabber-xml-get-children query 'streamhost)))
97 (let ((existing-entry (assoc from jabber-socks5-proxies-data)))
98 (when existing-entry
99 (setq jabber-socks5-proxies-data
100 (delq existing-entry jabber-socks5-proxies-data))))
102 (destructuring-bind (callback successp) closure-data
103 (when successp
104 (setq jabber-socks5-proxies-data
105 (cons (cons from streamhosts)
106 jabber-socks5-proxies-data)))
107 (message "%s from %s. %d of %d proxies have answered."
108 (if successp "Response" "Error") from
109 (length jabber-socks5-proxies-data) (length jabber-socks5-proxies))
110 (when (and callback (= (length jabber-socks5-proxies-data) (length jabber-socks5-proxies)))
111 (funcall callback)))))
113 (define-state-machine jabber-socks5
114 :start ((jc jid sid profile-function role)
115 "Start JEP-0065 bytestream with JID.
116 SID is the session ID used.
117 PROFILE-FUNCTION is the function to call upon success. See `jabber-si-stream-methods'.
118 ROLE is either :initiator or :target. The initiator sends an IQ
119 set; the target waits for one."
120 (let ((new-state-data (list :jc jc
121 :jid jid
122 :sid sid
123 :profile-function profile-function
124 :role role))
125 (new-state
126 ;; We want information about proxies; it might be needed in
127 ;; various situations.
128 (cond
129 ((null jabber-socks5-proxies)
130 ;; We know no proxy addresses. Try to find them by disco.
131 'seek-proxies)
132 ((null jabber-socks5-proxies-data)
133 ;; We need to query the proxies for addresses.
134 'query-proxies)
135 ;; So, we have our proxies.
137 'initiate))))
138 (list new-state new-state-data nil))))
140 (defun jabber-socks5-accept (jc jid sid profile-function)
141 "Remember that we are waiting for connection from JID, with stream id SID"
142 ;; asking the user for permission is done in the profile
143 (add-to-list 'jabber-socks5-pending-sessions
144 (list sid jid (start-jabber-socks5 jc jid sid profile-function :target))))
146 (define-enter-state jabber-socks5 seek-proxies (fsm state-data)
147 ;; Look for items at the server.
148 (let* ((jc (plist-get state-data :jc))
149 (server (jabber-jid-server (jabber-connection-jid jc))))
150 (jabber-disco-get-items jc
151 server
153 (lambda (jc fsm result)
154 (fsm-send-sync fsm (cons :items result)))
155 fsm))
156 ;; Spend no more than five seconds looking for a proxy.
157 (list state-data 5))
159 (define-state jabber-socks5 seek-proxies (fsm state-data event callback)
160 "Collect disco results, looking for a bytestreams proxy."
161 ;; We put the number of outstanding requests as :remaining-info in
162 ;; the state-data plist.
163 (cond
164 ;; We're not ready to handle the IQ stanza yet
165 ((eq (car-safe event) :iq)
166 :defer)
168 ;; Got list of items at the server.
169 ((eq (car-safe event) :items)
170 (dolist (entry (cdr event))
171 ;; Each entry is ["name" "jid" "node"]. We send a disco info
172 ;; request to everything without a node.
173 (when (null (aref entry 2))
174 (lexical-let ((jid (aref entry 1)))
175 (jabber-disco-get-info
176 (plist-get state-data :jc)
177 jid nil
178 (lambda (jc fsm result)
179 (fsm-send-sync fsm (list :info jid result)))
180 fsm))))
181 ;; Remember number of requests sent. But if none, we just go on.
182 (if (cdr event)
183 (list 'seek-proxies (plist-put state-data :remaining-info (length (cdr event))) :keep)
184 (list 'initiate state-data nil)))
186 ;; Got disco info from an item at the server.
187 ((eq (car-safe event) :info)
188 (fsm-debug-output "got disco event")
189 ;; Count the response.
190 (plist-put state-data :remaining-info (1- (plist-get state-data :remaining-info)))
191 (unless (eq (first (third event)) 'error)
192 (let ((identities (first (third event))))
193 ;; Is it a bytestream proxy?
194 (when (dolist (identity identities)
195 (when (and (string= (aref identity 1) "proxy")
196 (string= (aref identity 2) "bytestreams"))
197 (return t)))
198 ;; Yes, it is. Add it to the list.
199 (push (second event) jabber-socks5-proxies))))
201 ;; Wait for more responses, if any are to be expected.
202 (if (zerop (plist-get state-data :remaining-info))
203 ;; No more... go on to querying the proxies.
204 (list 'query-proxies state-data nil)
205 ;; We expect more responses...
206 (list 'seek-proxies state-data :keep)))
208 ((eq event :timeout)
209 ;; We can't wait anymore...
210 (list 'query-proxies state-data nil))))
212 (define-enter-state jabber-socks5 query-proxies (fsm state-data)
213 (jabber-socks5-query-all-proxies
214 (plist-get state-data :jc)
215 (lexical-let ((fsm fsm))
216 (lambda () (fsm-send-sync fsm :proxies))))
217 (list state-data 5))
219 (define-state jabber-socks5 query-proxies (fsm state-data event callback)
220 "Query proxies in `jabber-socks5-proxies'."
221 (cond
222 ;; Can't handle the iq stanza yet...
223 ((eq (car-safe event) :iq)
224 :defer)
226 ((eq (car-safe event) :info)
227 ;; stray event... do nothing
228 (list 'query-proxies state-data :keep))
230 ;; Got response/error from all proxies, or timeout
231 ((memq event '(:proxies :timeout))
232 (list 'initiate state-data nil))))
234 (define-enter-state jabber-socks5 initiate (fsm state-data)
235 ;; Sort the alist jabber-socks5-proxies-data such that the
236 ;; keys are in the same order as in jabber-socks5-proxies.
237 (setq jabber-socks5-proxies-data
238 (sort jabber-socks5-proxies-data
239 #'(lambda (a b)
240 (> (length (member (car a) jabber-socks5-proxies))
241 (length (member (car b) jabber-socks5-proxies))))))
243 ;; If we're the initiator, send initiation stanza.
244 (when (eq (plist-get state-data :role) :initiator)
245 ;; This is where initiation of server sockets would go
247 (jabber-send-iq
248 (plist-get state-data :jc)
249 (plist-get state-data :jid) "set"
250 `(query ((xmlns . "http://jabber.org/protocol/bytestreams")
251 (sid . ,(plist-get state-data :sid)))
252 ,@(mapcar
253 #'(lambda (proxy)
254 (mapcar
255 #'(lambda (streamhost)
256 (list 'streamhost
257 (list (cons 'jid (jabber-xml-get-attribute streamhost 'jid))
258 (cons 'host (jabber-xml-get-attribute streamhost 'host))
259 (cons 'port (jabber-xml-get-attribute streamhost 'port)))
260 ;; (proxy ((xmlns . "http://affinix.com/jabber/stream")))
262 (cdr proxy)))
263 jabber-socks5-proxies-data)
264 ;; (fast ((xmlns . "http://affinix.com/jabber/stream")))
266 (lexical-let ((fsm fsm))
267 (lambda (jc xml-data closure-data)
268 (fsm-send-sync fsm (list :iq xml-data))))
270 ;; TODO: error handling
271 #'jabber-report-success "SOCKS5 negotiation"))
273 ;; If we're the target, we just wait for an incoming stanza.
274 (list state-data nil))
276 (add-to-list 'jabber-iq-set-xmlns-alist
277 (cons "http://jabber.org/protocol/bytestreams" 'jabber-socks5-process))
278 (defun jabber-socks5-process (jc xml-data)
279 "Accept IQ get for SOCKS5 bytestream"
280 (let* ((jid (jabber-xml-get-attribute xml-data 'from))
281 (id (jabber-xml-get-attribute xml-data 'id))
282 (query (jabber-iq-query xml-data))
283 (sid (jabber-xml-get-attribute query 'sid))
284 (session (dolist (pending-session jabber-socks5-pending-sessions)
285 (when (and (equal sid (nth 0 pending-session))
286 (equal jid (nth 1 pending-session)))
287 (return pending-session)))))
288 ;; check that we really are expecting this session
289 (unless session
290 (jabber-signal-error "auth" 'not-acceptable))
292 (setq jabber-socks5-pending-sessions (delq session jabber-socks5-pending-sessions))
293 (fsm-send-sync (nth 2 session) (list :iq xml-data))
295 ;; find streamhost to connect to
296 ;; (let* ((streamhosts (jabber-xml-get-children query 'streamhost))
297 ;; (streamhost (dolist (streamhost streamhosts)
298 ;; (let ((connection (jabber-socks5-connect streamhost sid jid (concat jabber-username "@" jabber-server "/" jabber-resource))))
299 ;; (when connection
300 ;; ;; We select the first streamhost that we are able to connect to.
301 ;; (push (list connection sid jid profile-data-function)
302 ;; jabber-socks5-active-sessions)
303 ;; ;; Now set the filter, for the rest of the output
304 ;; (set-process-filter connection #'jabber-socks5-filter)
305 ;; (set-process-sentinel connection #'jabber-socks5-sentinel)
306 ;; (return streamhost))))))
307 ;; (unless streamhost
308 ;; (jabber-signal-error "cancel" 'item-not-found))
310 ;; ;; tell initiator which streamhost we use
311 ;; (jabber-send-iq jid "result"
312 ;; `(query ((xmlns . "http://jabber.org/protocol/bytestreams"))
313 ;; (streamhost-used ((jid . ,(jabber-xml-get-attribute streamhost 'jid)))))
314 ;; nil nil nil nil id)
315 ;; ;; now, as data is sent, it will be passed to the profile.
316 ;; )
319 (define-state jabber-socks5 initiate (fsm state-data event callback)
320 (let* ((jc (plist-get state-data :jc))
321 (jc-data (fsm-get-state-data jc))
322 (our-jid (concat (plist-get jc-data :username) "@"
323 (plist-get jc-data :server) "/"
324 (plist-get jc-data :resource)))
325 (their-jid (plist-get state-data :jid))
326 (initiator-jid (if (eq (plist-get state-data :role) :initiator) our-jid their-jid))
327 (target-jid (if (eq (plist-get state-data :role) :initiator) their-jid our-jid)))
328 (cond
329 ;; Stray event...
330 ((memq (car-safe event) '(:proxy :info))
331 (list 'initiate state-data :keep))
333 ;; Incoming IQ
334 ((eq (car-safe event) :iq)
335 (let ((xml-data (second event)))
336 ;; This is either type "set" (with a list of streamhosts to
337 ;; use), or a "result" (indicating the streamhost finally used
338 ;; by the other party).
339 (cond
340 ((string= (jabber-xml-get-attribute xml-data 'type) "set")
341 ;; A "set" makes sense if we're the initiator and offered
342 ;; Psi's "fast mode". We don't yet, though, so this is only
343 ;; for target.
344 (dolist (streamhost (jabber-xml-get-children (jabber-iq-query xml-data) 'streamhost))
345 (jabber-xml-let-attributes
346 (jid host port) streamhost
347 ;; This is where we would attempt to support zeroconf
348 (when (and jid host port)
349 (start-jabber-socks5-connection
350 jc initiator-jid target-jid jid
351 (plist-get state-data :sid) host port fsm))))
353 (list 'wait-for-connection (plist-put state-data :iq-id (jabber-xml-get-attribute xml-data 'id)) 30))
355 ((string= (jabber-xml-get-attribute xml-data 'type) "result")
356 ;; The other party has decided what streamhost to use.
357 (let* ((proxy-used (jabber-xml-get-attribute (jabber-xml-path xml-data '(query streamhost-used)) 'jid))
358 ;; If JID is our own JID, we have probably already detected
359 ;; what connection to use. But that is a later problem...
360 (streamhosts (cdr (assoc proxy-used jabber-socks5-proxies-data))))
361 ;; Try to connect to all addresses of this proxy...
362 (dolist (streamhost streamhosts)
363 (jabber-xml-let-attributes
364 (jid host port) streamhost
365 (when (and jid host port)
366 (start-jabber-socks5-connection
367 jc initiator-jid target-jid jid
368 (plist-get state-data :sid) host port fsm)))))
370 (list 'wait-for-connection state-data 30))))))))
372 (define-state-machine jabber-socks5-connection
373 :start
374 ((jc initiator-jid target-jid streamhost-jid sid host port socks5-fsm)
375 "Connect to a single JEP-0065 streamhost."
376 (let ((coding-system-for-read 'binary)
377 (coding-system-for-write 'binary))
378 ;; make-network-process, which we really want, for asynchronous
379 ;; connection and such, was introduced in Emacs 22.
380 (if (fboundp 'make-network-process)
381 (let ((connection
382 (make-network-process
383 :name "socks5"
384 :buffer nil
385 :host host
386 :service (string-to-number port)
387 :nowait t
388 :filter (fsm-make-filter fsm)
389 :sentinel (fsm-make-sentinel fsm))))
390 (list 'wait-for-connection
391 (list :jc jc
392 :connection connection
393 :initiator-jid initiator-jid
394 :target-jid target-jid
395 :streamhost-jid streamhost-jid
396 :sid sid
397 :socks5-fsm socks5-fsm)
398 30))
399 ;; So we open a stream, and wait for the connection to succeed.
400 (condition-case nil
401 (let ((connection
402 (open-network-stream "socks5" nil
403 host (string-to-number port))))
404 (set-process-filter connection (fsm-make-filter fsm))
405 (set-process-sentinel connection (fsm-make-sentinel fsm))
406 (list 'authenticate
407 (list :jc jc
408 :connection connection
409 :initiator-jid initiator-jid
410 :target-jid target-jid
411 :streamhost-jid streamhost-jid
412 :sid sid
413 :socks5-fsm socks5-fsm)
414 nil))
415 (error (list 'fail '() nil)))))))
417 (define-state jabber-socks5-connection wait-for-connection
418 (fsm state-data event callback)
419 (cond
420 ((eq (car-safe event) :sentinel)
421 (let ((string (third event)))
422 (cond
423 ;; Connection succeeded
424 ((string= (substring string 0 4) "open")
425 (list 'authenticate state-data nil))
426 ;; Connection failed
428 (list 'fail state-data nil)))))))
430 (define-enter-state jabber-socks5-connection authenticate
431 (fsm state-data)
432 "Send authenticate command."
433 ;; version: 5. number of auth methods supported: 1.
434 ;; which one: no authentication.
435 (process-send-string (plist-get state-data :connection) (string 5 1 0))
436 (list state-data 30))
438 (define-state jabber-socks5-connection authenticate
439 (fsm state-data event callback)
440 "Receive response to authenticate command."
441 (cond
442 ((eq (car-safe event) :filter)
443 (let ((string (third event)))
444 ;; should return:
445 ;; version: 5. auth method to use: none
446 (if (string= string (string 5 0))
447 ;; Authenticated. Send connect command.
448 (list 'connect state-data nil)
449 ;; Authentication failed...
450 (delete-process (second event))
451 (list 'fail state-data nil))))
453 ((eq (car-safe event) :sentinel)
454 (list 'fail state-data nil))))
456 (define-enter-state jabber-socks5-connection connect (fsm state-data)
457 "Send connect command."
458 (let* ((sid (plist-get state-data :sid))
459 (initiator (plist-get state-data :initiator-jid))
460 (target (plist-get state-data :target-jid))
461 (hash (sha1-string (concat sid initiator target))))
462 (process-send-string
463 (plist-get state-data :connection)
464 (concat (string 5 1 0 3 (length hash))
465 hash
466 (string 0 0)))
467 (list state-data 30)))
469 (define-state jabber-socks5-connection connect
470 (fsm state-data event callback)
471 "Receive response to connect command."
472 (cond
473 ((eq (car-safe event) :filter)
474 (let ((string (third event)))
475 (if (string= (substring string 0 2) (string 5 0))
476 ;; connection established
477 (progn
478 (fsm-send (plist-get state-data :socks5-fsm)
479 (list :connected
480 (plist-get state-data :connection)
481 (plist-get state-data :streamhost-jid)))
482 ;; Our work is done
483 (list 'done nil))
484 (list 'fail state-data nil))))
485 ((eq (car-safe event) :sentinel)
486 (list 'fail state-data nil))))
488 (define-state jabber-socks5-connection done
489 (fsm state-data event callback)
490 ;; ignore all events
491 (list 'done nil nil))
493 (define-enter-state jabber-socks5-connection fail (fsm state-data)
494 ;; Notify parent fsm about failure
495 (fsm-send (plist-get state-data :socks5-fsm)
496 :not-connected)
497 (list nil nil))
499 (define-state jabber-socks5-connection fail
500 (fsm state-data event callback)
501 ;; ignore all events
502 (list 'fail nil nil))
504 (define-state jabber-socks5 wait-for-connection
505 (fsm state-data event callback)
506 (cond
507 ((eq (car-safe event) :connected)
508 (destructuring-bind (ignored connection streamhost-jid) event
509 (setq state-data (plist-put state-data :connection connection))
510 ;; If we are expected to tell which streamhost we chose, do so.
511 (let ((iq-id (plist-get state-data :iq-id)))
512 (when iq-id
513 (jabber-send-iq
514 (plist-get state-data :jc)
515 (plist-get state-data :jid) "result"
516 `(query ((xmlns . "http://jabber.org/protocol/bytestreams"))
517 (streamhost-used ((jid . ,streamhost-jid))))
518 nil nil nil nil
519 iq-id)))
521 ;; If we are the initiator, we should activate the bytestream.
522 (if (eq (plist-get state-data :role) :initiator)
523 (progn
524 (jabber-send-iq
525 (plist-get state-data :jc)
526 streamhost-jid "set"
527 `(query ((xmlns . "http://jabber.org/protocol/bytestreams")
528 (sid . ,(plist-get state-data :sid)))
529 (activate nil ,(plist-get state-data :jid)))
530 (lambda (jc xml-data fsm) (fsm-send-sync fsm :activated)) fsm
531 (lambda (jc xml-data fsm) (fsm-send-sync fsm :activation-failed)) fsm)
532 (list 'wait-for-activation state-data 10))
533 ;; Otherwise, we just let the data flow.
534 (list 'stream-activated state-data nil))))
536 ((eq event :not-connected)
537 ;; If we were counting the streamhosts, we would know when there
538 ;; are no more chances left.
539 (list 'wait-for-connection state-data :keep))
541 ((eq event :timeout)
542 (list 'fail (plist-put state-data :error "Timeout when connecting to streamhosts") nil))))
544 (define-state jabber-socks5 wait-for-activation
545 (fsm state-data event callback)
546 (cond
547 ((eq event :activated)
548 (list 'stream-activated state-data nil))
549 ((eq event :activation-failed)
550 (list 'fail (plist-put state-data :error "Proxy activation failed") nil))
552 ;; Stray events from earlier state
553 ((eq (car-safe event) :connected)
554 ;; We just close the connection
555 (delete-process (second event))
556 (list 'wait-for-activation state-data :keep))
557 ((eq event :not-connected)
558 (list 'wait-for-activation state-data :keep))))
560 (define-enter-state jabber-socks5 stream-activated
561 (fsm state-data)
562 (let ((connection (plist-get state-data :connection))
563 (jc (plist-get state-data :jc))
564 (jid (plist-get state-data :jid))
565 (sid (plist-get state-data :sid))
566 (profile-function (plist-get state-data :profile-function)))
567 (set-process-filter connection (fsm-make-filter fsm))
568 (set-process-sentinel connection (fsm-make-sentinel fsm))
569 ;; Call the profile function, passing the data send function, and
570 ;; receiving the data receiving function. Put the data receiving
571 ;; function in the plist.
572 (list (plist-put state-data
573 :profile-data-function
574 (funcall profile-function
575 jc jid sid
576 (lexical-let ((fsm fsm))
577 (lambda (data)
578 (fsm-send fsm (list :send data))))))
579 nil)))
582 (define-state jabber-socks5 stream-activated
583 (fsm state-data event callback)
584 (let ((jc (plist-get state-data :jc))
585 (connection (plist-get state-data :connection))
586 (profile-data-function (plist-get state-data :profile-data-function))
587 (sid (plist-get state-data :sid))
588 (jid (plist-get state-data :jid)))
589 (cond
590 ((eq (car-safe event) :send)
591 (process-send-string connection (second event))
592 (list 'stream-activated state-data nil))
594 ((eq (car-safe event) :filter)
595 ;; Pass data from connection to profile data function
596 ;; If the data function requests it, tear down the connection.
597 (unless (funcall profile-data-function jc jid sid (third event))
598 (fsm-send fsm (list :sentinel (second event) "shutdown")))
600 (list 'stream-activated state-data nil))
602 ((eq (car-safe event) :sentinel)
603 ;; Connection terminated. Shuffle together the remaining data,
604 ;; and kill the buffer.
605 (delete-process (second event))
606 (funcall profile-data-function jc jid sid nil)
607 (list 'closed nil nil))
609 ;; Stray events from earlier state
610 ((eq (car-safe event) :connected)
611 ;; We just close the connection
612 (delete-process (second event))
613 (list 'stream-activated state-data nil))
614 ((eq event :not-connected)
615 (list 'stream-activated state-data nil)))))
617 (define-enter-state jabber-socks5 fail (fsm state-data)
618 "Tell our caller that we failed."
619 (let ((jc (plist-get state-data :jc))
620 (jid (plist-get state-data :jid))
621 (sid (plist-get state-data :sid))
622 (profile-function (plist-get state-data :profile-function))
623 (iq-id (plist-get state-data :iq-id)))
624 (funcall profile-function jc jid sid (plist-get state-data :error))
626 (when iq-id
627 (jabber-send-iq-error jc jid iq-id nil "cancel"
628 'remote-server-not-found)))
629 (list nil nil))
631 (defun jabber-socks5-client-1 (jc jid sid profile-function)
632 "Negotiate a SOCKS5 connection with JID.
633 This function simply starts a state machine."
634 (add-to-list 'jabber-socks5-pending-sessions
635 (list sid jid (start-jabber-socks5 jc jid sid profile-function :initiator))))
637 ;; (defun jabber-socks5-client-2 (xml-data jid sid profile-function)
638 ;; "Contact has selected a streamhost to use. Connect to the proxy."
639 ;; (let* ((query (jabber-iq-query xml-data))
640 ;; (streamhost-used (car (jabber-xml-get-children query 'streamhost-used)))
641 ;; (proxy-used (jabber-xml-get-attribute streamhost-used 'jid))
642 ;; connection)
643 ;; (let ((streamhosts-left (cdr (assoc proxy-used jabber-socks5-proxies-data))))
644 ;; (while (and streamhosts-left (not connection))
645 ;; (setq connection
646 ;; (jabber-socks5-connect (car streamhosts-left)
647 ;; sid
648 ;; (concat jabber-username "@" jabber-server "/" jabber-resource)
649 ;; jid))
650 ;; (setq streamhosts-left (cdr streamhosts-left))))
651 ;; (unless connection
652 ;; (error "Couldn't connect to proxy %s" proxy-used))
654 ;; ;; Activation is only needed for proxies.
655 ;; (jabber-send-iq proxy-used "set"
656 ;; `(query ((xmlns . "http://jabber.org/protocol/bytestreams")
657 ;; (sid . ,sid))
658 ;; (activate () ,jid))
659 ;; (lexical-let ((jid jid) (sid sid) (profile-function profile-function)
660 ;; (connection connection))
661 ;; (lambda (xml-data closure-data)
662 ;; (jabber-socks5-client-3 xml-data jid sid profile-function connection))) nil
663 ;; ;; TODO: report error to contact?
664 ;; #'jabber-report-success "Proxy activation")))
666 ;; (defun jabber-socks5-client-3 (xml-data jid sid profile-function proxy-connection)
667 ;; "Proxy is activated. Start the transfer."
668 ;; ;; The response from the proxy does not contain any interesting
669 ;; ;; information, beyond success confirmation.
671 ;; (funcall profile-function jid sid
672 ;; (lexical-let ((proxy-connection proxy-connection))
673 ;; (lambda (data)
674 ;; (process-send-string proxy-connection data)))))
676 (provide 'jabber-socks5)
678 ;;; arch-tag: 9e70dfea-2522-40c6-a79f-302c8fb82ac5