asyncssh 2.15.0__tar.gz → 2.17.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. {asyncssh-2.15.0 → asyncssh-2.17.0}/CONTRIBUTING.rst +9 -10
  2. {asyncssh-2.15.0/asyncssh.egg-info → asyncssh-2.17.0}/PKG-INFO +5 -12
  3. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/channel.py +5 -1
  4. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/client.py +9 -1
  5. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/config.py +7 -5
  6. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/connection.py +217 -26
  7. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/crypto/cipher.py +48 -30
  8. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/crypto/x509.py +2 -1
  9. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/gss.py +7 -3
  10. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/gss_unix.py +9 -5
  11. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/gss_win32.py +10 -2
  12. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/listener.py +12 -2
  13. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/logging.py +22 -12
  14. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/misc.py +14 -0
  15. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/public_key.py +2 -5
  16. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/saslprep.py +4 -2
  17. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/server.py +8 -0
  18. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/sftp.py +11 -13
  19. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/version.py +1 -1
  20. {asyncssh-2.15.0 → asyncssh-2.17.0/asyncssh.egg-info}/PKG-INFO +5 -12
  21. {asyncssh-2.15.0 → asyncssh-2.17.0}/docs/changes.rst +63 -0
  22. {asyncssh-2.15.0 → asyncssh-2.17.0}/examples/callback_client.py +3 -3
  23. {asyncssh-2.15.0 → asyncssh-2.17.0}/examples/callback_client2.py +3 -3
  24. {asyncssh-2.15.0 → asyncssh-2.17.0}/examples/callback_client3.py +3 -3
  25. {asyncssh-2.15.0 → asyncssh-2.17.0}/examples/callback_math_server.py +6 -3
  26. {asyncssh-2.15.0 → asyncssh-2.17.0}/examples/chat_server.py +3 -3
  27. {asyncssh-2.15.0 → asyncssh-2.17.0}/examples/check_exit_status.py +3 -3
  28. {asyncssh-2.15.0 → asyncssh-2.17.0}/examples/chroot_sftp_server.py +3 -3
  29. {asyncssh-2.15.0 → asyncssh-2.17.0}/examples/direct_client.py +3 -3
  30. {asyncssh-2.15.0 → asyncssh-2.17.0}/examples/direct_server.py +3 -3
  31. {asyncssh-2.15.0 → asyncssh-2.17.0}/examples/editor.py +3 -3
  32. {asyncssh-2.15.0 → asyncssh-2.17.0}/examples/gather_results.py +3 -3
  33. {asyncssh-2.15.0 → asyncssh-2.17.0}/examples/listening_client.py +3 -3
  34. {asyncssh-2.15.0 → asyncssh-2.17.0}/examples/local_forwarding_client.py +3 -3
  35. {asyncssh-2.15.0 → asyncssh-2.17.0}/examples/local_forwarding_client2.py +3 -3
  36. {asyncssh-2.15.0 → asyncssh-2.17.0}/examples/local_forwarding_server.py +3 -3
  37. {asyncssh-2.15.0 → asyncssh-2.17.0}/examples/math_client.py +3 -3
  38. {asyncssh-2.15.0 → asyncssh-2.17.0}/examples/math_server.py +3 -3
  39. {asyncssh-2.15.0 → asyncssh-2.17.0}/examples/redirect_input.py +3 -3
  40. {asyncssh-2.15.0 → asyncssh-2.17.0}/examples/redirect_local_pipe.py +3 -3
  41. {asyncssh-2.15.0 → asyncssh-2.17.0}/examples/redirect_remote_pipe.py +3 -3
  42. {asyncssh-2.15.0 → asyncssh-2.17.0}/examples/redirect_server.py +3 -3
  43. {asyncssh-2.15.0 → asyncssh-2.17.0}/examples/remote_forwarding_client.py +3 -3
  44. {asyncssh-2.15.0 → asyncssh-2.17.0}/examples/remote_forwarding_client2.py +3 -3
  45. {asyncssh-2.15.0 → asyncssh-2.17.0}/examples/remote_forwarding_server.py +3 -3
  46. {asyncssh-2.15.0 → asyncssh-2.17.0}/examples/reverse_client.py +3 -3
  47. {asyncssh-2.15.0 → asyncssh-2.17.0}/examples/reverse_server.py +3 -3
  48. {asyncssh-2.15.0 → asyncssh-2.17.0}/examples/scp_client.py +3 -3
  49. {asyncssh-2.15.0 → asyncssh-2.17.0}/examples/set_environment.py +3 -3
  50. {asyncssh-2.15.0 → asyncssh-2.17.0}/examples/set_terminal.py +3 -3
  51. {asyncssh-2.15.0 → asyncssh-2.17.0}/examples/sftp_client.py +3 -3
  52. {asyncssh-2.15.0 → asyncssh-2.17.0}/examples/show_environment.py +3 -3
  53. {asyncssh-2.15.0 → asyncssh-2.17.0}/examples/show_terminal.py +3 -3
  54. {asyncssh-2.15.0 → asyncssh-2.17.0}/examples/simple_cert_server.py +3 -3
  55. {asyncssh-2.15.0 → asyncssh-2.17.0}/examples/simple_client.py +11 -5
  56. {asyncssh-2.15.0 → asyncssh-2.17.0}/examples/simple_keyed_server.py +3 -3
  57. {asyncssh-2.15.0 → asyncssh-2.17.0}/examples/simple_scp_server.py +3 -3
  58. {asyncssh-2.15.0 → asyncssh-2.17.0}/examples/simple_server.py +3 -3
  59. {asyncssh-2.15.0 → asyncssh-2.17.0}/examples/simple_sftp_server.py +3 -3
  60. {asyncssh-2.15.0 → asyncssh-2.17.0}/examples/stream_direct_client.py +3 -3
  61. {asyncssh-2.15.0 → asyncssh-2.17.0}/examples/stream_direct_server.py +3 -3
  62. {asyncssh-2.15.0 → asyncssh-2.17.0}/examples/stream_listening_client.py +3 -3
  63. {asyncssh-2.15.0 → asyncssh-2.17.0}/tests/gssapi_stub.py +3 -1
  64. {asyncssh-2.15.0 → asyncssh-2.17.0}/tests/test_auth.py +2 -2
  65. {asyncssh-2.15.0 → asyncssh-2.17.0}/tests/test_config.py +7 -1
  66. {asyncssh-2.15.0 → asyncssh-2.17.0}/tests/test_connection.py +131 -1
  67. {asyncssh-2.15.0 → asyncssh-2.17.0}/tests/test_connection_auth.py +13 -1
  68. {asyncssh-2.15.0 → asyncssh-2.17.0}/tests/test_kex.py +2 -2
  69. {asyncssh-2.15.0 → asyncssh-2.17.0}/.coveragerc +0 -0
  70. {asyncssh-2.15.0 → asyncssh-2.17.0}/.github/workflows/run_tests.yml +0 -0
  71. {asyncssh-2.15.0 → asyncssh-2.17.0}/.gitignore +0 -0
  72. {asyncssh-2.15.0 → asyncssh-2.17.0}/.readthedocs.yaml +0 -0
  73. {asyncssh-2.15.0 → asyncssh-2.17.0}/COPYRIGHT +0 -0
  74. {asyncssh-2.15.0 → asyncssh-2.17.0}/LICENSE +0 -0
  75. {asyncssh-2.15.0 → asyncssh-2.17.0}/MANIFEST.in +0 -0
  76. {asyncssh-2.15.0 → asyncssh-2.17.0}/README.rst +0 -0
  77. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/__init__.py +0 -0
  78. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/agent.py +0 -0
  79. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/agent_unix.py +0 -0
  80. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/agent_win32.py +0 -0
  81. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/asn1.py +0 -0
  82. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/auth.py +0 -0
  83. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/auth_keys.py +0 -0
  84. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/compression.py +0 -0
  85. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/constants.py +0 -0
  86. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/crypto/__init__.py +0 -0
  87. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/crypto/chacha.py +0 -0
  88. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/crypto/dh.py +0 -0
  89. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/crypto/dsa.py +0 -0
  90. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/crypto/ec.py +0 -0
  91. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/crypto/ec_params.py +0 -0
  92. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/crypto/ed.py +0 -0
  93. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/crypto/kdf.py +0 -0
  94. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/crypto/misc.py +0 -0
  95. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/crypto/rsa.py +0 -0
  96. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/crypto/sntrup.py +0 -0
  97. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/crypto/umac.py +0 -0
  98. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/dsa.py +0 -0
  99. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/ecdsa.py +0 -0
  100. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/eddsa.py +0 -0
  101. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/editor.py +0 -0
  102. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/encryption.py +0 -0
  103. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/forward.py +0 -0
  104. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/kex.py +0 -0
  105. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/kex_dh.py +0 -0
  106. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/kex_rsa.py +0 -0
  107. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/keysign.py +0 -0
  108. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/known_hosts.py +0 -0
  109. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/mac.py +0 -0
  110. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/packet.py +0 -0
  111. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/pattern.py +0 -0
  112. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/pbe.py +0 -0
  113. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/pkcs11.py +0 -0
  114. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/process.py +0 -0
  115. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/py.typed +0 -0
  116. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/rsa.py +0 -0
  117. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/scp.py +0 -0
  118. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/session.py +0 -0
  119. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/sk.py +0 -0
  120. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/sk_ecdsa.py +0 -0
  121. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/sk_eddsa.py +0 -0
  122. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/socks.py +0 -0
  123. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/stream.py +0 -0
  124. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/subprocess.py +0 -0
  125. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/tuntap.py +0 -0
  126. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh/x11.py +0 -0
  127. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh.egg-info/SOURCES.txt +0 -0
  128. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh.egg-info/dependency_links.txt +0 -0
  129. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh.egg-info/requires.txt +0 -0
  130. {asyncssh-2.15.0 → asyncssh-2.17.0}/asyncssh.egg-info/top_level.txt +0 -0
  131. {asyncssh-2.15.0 → asyncssh-2.17.0}/docs/_templates/sidebarbottom.html +0 -0
  132. {asyncssh-2.15.0 → asyncssh-2.17.0}/docs/_templates/sidebartop.html +0 -0
  133. {asyncssh-2.15.0 → asyncssh-2.17.0}/docs/api.rst +0 -0
  134. {asyncssh-2.15.0 → asyncssh-2.17.0}/docs/conf.py +0 -0
  135. {asyncssh-2.15.0 → asyncssh-2.17.0}/docs/contributing.rst +0 -0
  136. {asyncssh-2.15.0 → asyncssh-2.17.0}/docs/index.rst +0 -0
  137. {asyncssh-2.15.0 → asyncssh-2.17.0}/docs/requirements.txt +0 -0
  138. {asyncssh-2.15.0 → asyncssh-2.17.0}/docs/rftheme/layout.html +0 -0
  139. {asyncssh-2.15.0 → asyncssh-2.17.0}/docs/rftheme/static/rftheme.css_t +0 -0
  140. {asyncssh-2.15.0 → asyncssh-2.17.0}/docs/rftheme/theme.conf +0 -0
  141. {asyncssh-2.15.0 → asyncssh-2.17.0}/docs/rtd-req.txt +0 -0
  142. {asyncssh-2.15.0 → asyncssh-2.17.0}/mypy.ini +0 -0
  143. {asyncssh-2.15.0 → asyncssh-2.17.0}/pylintrc +0 -0
  144. {asyncssh-2.15.0 → asyncssh-2.17.0}/setup.cfg +0 -0
  145. {asyncssh-2.15.0 → asyncssh-2.17.0}/setup.py +0 -0
  146. {asyncssh-2.15.0 → asyncssh-2.17.0}/tests/__init__.py +0 -0
  147. {asyncssh-2.15.0 → asyncssh-2.17.0}/tests/gss_stub.py +0 -0
  148. {asyncssh-2.15.0 → asyncssh-2.17.0}/tests/keysign_stub.py +0 -0
  149. {asyncssh-2.15.0 → asyncssh-2.17.0}/tests/pkcs11_stub.py +0 -0
  150. {asyncssh-2.15.0 → asyncssh-2.17.0}/tests/server.py +0 -0
  151. {asyncssh-2.15.0 → asyncssh-2.17.0}/tests/sk_stub.py +0 -0
  152. {asyncssh-2.15.0 → asyncssh-2.17.0}/tests/sspi_stub.py +0 -0
  153. {asyncssh-2.15.0 → asyncssh-2.17.0}/tests/test_agent.py +0 -0
  154. {asyncssh-2.15.0 → asyncssh-2.17.0}/tests/test_asn1.py +0 -0
  155. {asyncssh-2.15.0 → asyncssh-2.17.0}/tests/test_auth_keys.py +0 -0
  156. {asyncssh-2.15.0 → asyncssh-2.17.0}/tests/test_channel.py +0 -0
  157. {asyncssh-2.15.0 → asyncssh-2.17.0}/tests/test_compression.py +0 -0
  158. {asyncssh-2.15.0 → asyncssh-2.17.0}/tests/test_editor.py +0 -0
  159. {asyncssh-2.15.0 → asyncssh-2.17.0}/tests/test_encryption.py +0 -0
  160. {asyncssh-2.15.0 → asyncssh-2.17.0}/tests/test_forward.py +0 -0
  161. {asyncssh-2.15.0 → asyncssh-2.17.0}/tests/test_known_hosts.py +0 -0
  162. {asyncssh-2.15.0 → asyncssh-2.17.0}/tests/test_logging.py +0 -0
  163. {asyncssh-2.15.0 → asyncssh-2.17.0}/tests/test_mac.py +0 -0
  164. {asyncssh-2.15.0 → asyncssh-2.17.0}/tests/test_packet.py +0 -0
  165. {asyncssh-2.15.0 → asyncssh-2.17.0}/tests/test_pkcs11.py +0 -0
  166. {asyncssh-2.15.0 → asyncssh-2.17.0}/tests/test_process.py +0 -0
  167. {asyncssh-2.15.0 → asyncssh-2.17.0}/tests/test_public_key.py +0 -0
  168. {asyncssh-2.15.0 → asyncssh-2.17.0}/tests/test_saslprep.py +0 -0
  169. {asyncssh-2.15.0 → asyncssh-2.17.0}/tests/test_sftp.py +0 -0
  170. {asyncssh-2.15.0 → asyncssh-2.17.0}/tests/test_sk.py +0 -0
  171. {asyncssh-2.15.0 → asyncssh-2.17.0}/tests/test_stream.py +0 -0
  172. {asyncssh-2.15.0 → asyncssh-2.17.0}/tests/test_subprocess.py +0 -0
  173. {asyncssh-2.15.0 → asyncssh-2.17.0}/tests/test_tuntap.py +0 -0
  174. {asyncssh-2.15.0 → asyncssh-2.17.0}/tests/test_x11.py +0 -0
  175. {asyncssh-2.15.0 → asyncssh-2.17.0}/tests/test_x509.py +0 -0
  176. {asyncssh-2.15.0 → asyncssh-2.17.0}/tests/util.py +0 -0
  177. {asyncssh-2.15.0 → asyncssh-2.17.0}/tox.ini +0 -0
@@ -68,19 +68,18 @@ contributors list.
68
68
  Branches
69
69
  --------
70
70
 
71
- There are two long-lived branches in AsyncSSH at the moment:
71
+ There are two long-lived branches in AsyncSSH:
72
72
 
73
73
  * The master branch is intended to contain the latest stable version
74
74
  of the code. All official versions of AsyncSSH are released from
75
75
  this branch, and each release has a corresponding tag added
76
- matching its release number. Bug fixes and simple improvements
77
- may be checked directly into this branch, but most new features
78
- will be added to the develop branch first.
79
-
80
- * The develop branch is intended to contain features for developers
81
- to test before they are ready to be added to an official release.
82
- APIs in the develop branch may be subject to change until they
83
- are migrated back to master, and there's no guarantee of backward
76
+ matching its release number.
77
+
78
+ * The develop branch is intended to contain new features and bug fixes
79
+ ready to be tested before being added to an official release. APIs
80
+ in the develop branch may be subject to change until they are
81
+ migrated back to master, and there's no guarantee of backward
84
82
  compatibility in this branch. However, pulling from this branch
85
83
  will provide early access to new functionality and a chance to
86
- influence this functionality before it is released.
84
+ influence this functionality before it is released. Also, all
85
+ pull requests should be submitted against this branch.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: asyncssh
3
- Version: 2.15.0
3
+ Version: 2.17.0
4
4
  Summary: AsyncSSH: Asynchronous SSHv2 client and server library
5
5
  Home-page: http://asyncssh.timeheart.net
6
6
  Author: Ron Frederick
@@ -27,23 +27,14 @@ Classifier: Topic :: Security :: Cryptography
27
27
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
28
28
  Classifier: Topic :: System :: Networking
29
29
  Requires-Python: >= 3.6
30
- License-File: LICENSE
31
- Requires-Dist: cryptography>=39.0
32
- Requires-Dist: typing_extensions>=4.0.0
33
30
  Provides-Extra: bcrypt
34
- Requires-Dist: bcrypt>=3.1.3; extra == "bcrypt"
35
31
  Provides-Extra: fido2
36
- Requires-Dist: fido2>=0.9.2; extra == "fido2"
37
32
  Provides-Extra: gssapi
38
- Requires-Dist: gssapi>=1.2.0; extra == "gssapi"
39
33
  Provides-Extra: libnacl
40
- Requires-Dist: libnacl>=1.4.2; extra == "libnacl"
41
34
  Provides-Extra: pkcs11
42
- Requires-Dist: python-pkcs11>=0.7.0; extra == "pkcs11"
43
- Provides-Extra: pyopenssl
44
- Requires-Dist: pyOpenSSL>=23.0.0; extra == "pyopenssl"
35
+ Provides-Extra: pyOpenSSL
45
36
  Provides-Extra: pywin32
46
- Requires-Dist: pywin32>=227; extra == "pywin32"
37
+ License-File: LICENSE
47
38
 
48
39
  .. image:: https://readthedocs.org/projects/asyncssh/badge/?version=latest
49
40
  :target: https://asyncssh.readthedocs.io/en/latest/?badge=latest
@@ -276,3 +267,5 @@ Three mailing lists are available for AsyncSSH:
276
267
  __ http://groups.google.com/d/forum/asyncssh-announce
277
268
  __ http://groups.google.com/d/forum/asyncssh-dev
278
269
  __ http://groups.google.com/d/forum/asyncssh-users
270
+
271
+
@@ -413,7 +413,11 @@ class SSHChannel(Generic[AnyStr], SSHPacketHandler):
413
413
  handler = cast(_RequestHandler, getattr(self, name, None))
414
414
 
415
415
  if handler:
416
- result = cast(Optional[bool], handler(packet))
416
+ if self._session:
417
+ result = cast(Optional[bool], handler(packet))
418
+ else:
419
+ # Ignore requests received after application closes the channel
420
+ result = True
417
421
  else:
418
422
  self.logger.debug1('Received unknown channel request: %s', request)
419
423
  result = False
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2013-2023 by Ron Frederick <ronf@timeheart.net> and others.
1
+ # Copyright (c) 2013-2024 by Ron Frederick <ronf@timeheart.net> and others.
2
2
  #
3
3
  # This program and the accompanying materials are made available under
4
4
  # the terms of the Eclipse Public License v2.0 which accompanies this
@@ -39,6 +39,14 @@ class SSHClient:
39
39
  to receive callbacks when certain events occur on the SSH
40
40
  connection.
41
41
 
42
+ Whenever a new SSH client connection is opened, a corresponding
43
+ SSHClient object is created and the method :meth:`connection_made`
44
+ is called, passing in the :class:`SSHClientConnection` object.
45
+
46
+ When the connection is closed, the method :meth:`connection_lost`
47
+ is called with an exception representing the reason for the
48
+ disconnect, or `None` if the connection was closed cleanly.
49
+
42
50
  For simple password or public key based authentication, nothing
43
51
  needs to be defined here if the password or client keys are passed
44
52
  in when the connection is created. However, to prompt interactively
@@ -321,11 +321,15 @@ class SSHConfig:
321
321
 
322
322
  args = []
323
323
  loption = ''
324
+ allow_equal = True
324
325
 
325
326
  for i, arg in enumerate(split_args, 1):
326
327
  if arg.startswith('='):
327
328
  if len(arg) > 1:
328
329
  args.append(arg[1:])
330
+ elif not allow_equal:
331
+ args.extend(split_args[i-1:])
332
+ break
329
333
  elif arg.endswith('='):
330
334
  args.append(arg[:-1])
331
335
  elif '=' in arg:
@@ -337,9 +341,7 @@ class SSHConfig:
337
341
 
338
342
  if i == 1:
339
343
  loption = args.pop(0).lower()
340
- elif i > 1 and loption not in self._conditionals:
341
- args.extend(split_args[i:])
342
- break
344
+ allow_equal = loption in self._conditionals
343
345
 
344
346
  if loption in self._no_split:
345
347
  args = [line.lstrip()[len(loption):].strip()]
@@ -423,7 +425,7 @@ class SSHClientConfig(SSHConfig):
423
425
  """Settings from an OpenSSH client config file"""
424
426
 
425
427
  _conditionals = {'host', 'match'}
426
- _no_split = {'remotecommand'}
428
+ _no_split = {'proxycommand', 'remotecommand'}
427
429
  _percent_expand = {'CertificateFile', 'IdentityAgent',
428
430
  'IdentityFile', 'ProxyCommand', 'RemoteCommand'}
429
431
 
@@ -557,7 +559,7 @@ class SSHClientConfig(SSHConfig):
557
559
  ('PKCS11Provider', SSHConfig._set_string),
558
560
  ('PreferredAuthentications', SSHConfig._set_string),
559
561
  ('Port', SSHConfig._set_int),
560
- ('ProxyCommand', SSHConfig._set_string_list),
562
+ ('ProxyCommand', SSHConfig._set_string),
561
563
  ('ProxyJump', SSHConfig._set_string),
562
564
  ('PubkeyAuthentication', SSHConfig._set_bool),
563
565
  ('RekeyLimit', SSHConfig._set_rekey_limits),