tdiary 5.5.0 → 5.6.0

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 (175) hide show
  1. checksums.yaml +4 -4
  2. data/ChangeLog +2 -0
  3. data/Gemfile +2 -1
  4. data/Gemfile.lock +37 -37
  5. data/doc/UPGRADE.md +1 -1
  6. data/lib/tdiary/admin.rb +11 -13
  7. data/lib/tdiary/application.rb +2 -7
  8. data/lib/tdiary/author_only_base.rb +78 -9
  9. data/lib/tdiary/base.rb +2 -2
  10. data/lib/tdiary/cgi_adapter.rb +7 -5
  11. data/lib/tdiary/cgi_compat.rb +27 -95
  12. data/lib/tdiary/configuration.rb +4 -0
  13. data/lib/tdiary/core_ext.rb +146 -1
  14. data/lib/tdiary/dispatcher/index_main.rb +5 -23
  15. data/lib/tdiary/dispatcher/update_main.rb +2 -17
  16. data/lib/tdiary/dispatcher.rb +29 -15
  17. data/lib/tdiary/filter/default.rb +2 -2
  18. data/lib/tdiary/filter/spam.rb +2 -2
  19. data/lib/tdiary/filter.rb +1 -1
  20. data/lib/tdiary/plugin/00default.rb +18 -3
  21. data/lib/tdiary/plugin/en/00default.rb +15 -0
  22. data/lib/tdiary/plugin/ja/00default.rb +15 -0
  23. data/lib/tdiary/plugin.rb +1 -1
  24. data/lib/tdiary/rack/error_handler.rb +36 -0
  25. data/lib/tdiary/rack.rb +1 -0
  26. data/lib/tdiary/request.rb +12 -2
  27. data/lib/tdiary/server.rb +25 -3
  28. data/lib/tdiary/version.rb +1 -1
  29. data/lib/tdiary/view.rb +33 -28
  30. data/lib/tdiary/view_helper.rb +10 -2
  31. data/lib/tdiary.rb +6 -1
  32. data/misc/plugin/image.rb +1 -1
  33. data/misc/plugin/makerss.rb +3 -3
  34. data/tdiary.conf.sample +8 -0
  35. data/tdiary.conf.sample-en +8 -0
  36. data/vendor/bundle/ruby/3.4.0/cache/net-imap-0.6.6.gem +0 -0
  37. data/vendor/bundle/ruby/3.4.0/cache/net-protocol-0.3.0.gem +0 -0
  38. data/vendor/bundle/ruby/3.4.0/cache/rack-3.2.7.gem +0 -0
  39. data/vendor/bundle/ruby/3.4.0/extensions/x86_64-linux/3.4.0/cgi-0.5.2/gem_make.out +5 -5
  40. data/vendor/bundle/ruby/3.4.0/extensions/x86_64-linux/3.4.0/date-3.5.1/gem_make.out +5 -5
  41. data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/Gemfile +3 -4
  42. data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/README.md +1 -1
  43. data/vendor/bundle/ruby/3.4.0/gems/net-imap-0.6.6/Rakefile +24 -0
  44. data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/command_data.rb +62 -92
  45. data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/config/attr_accessors.rb +8 -9
  46. data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/config/attr_inheritance.rb +64 -1
  47. data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/config/attr_version_defaults.rb +1 -4
  48. data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/config.rb +209 -35
  49. data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/connection_state.rb +1 -1
  50. data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/data_encoding.rb +127 -27
  51. data/vendor/bundle/ruby/3.4.0/gems/net-imap-0.6.6/lib/net/imap/errors.rb +372 -0
  52. data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/esearch_result.rb +6 -0
  53. data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/response_data.rb +90 -11
  54. data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/response_parser/parser_utils.rb +14 -23
  55. data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/response_parser.rb +41 -26
  56. data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/response_reader.rb +16 -21
  57. data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/sasl/scram_authenticator.rb +3 -3
  58. data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/search_result.rb +11 -1
  59. data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/sequence_set.rb +620 -312
  60. data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/uidplus_data.rb +2 -63
  61. data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap.rb +279 -162
  62. data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/net-imap.gemspec +1 -1
  63. data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/rakelib/rdoc.rake +1 -18
  64. data/vendor/bundle/ruby/3.4.0/gems/{net-protocol-0.2.2/LICENSE.txt → net-protocol-0.3.0/BSDL} +3 -3
  65. data/vendor/bundle/ruby/3.4.0/gems/net-protocol-0.3.0/COPYING +56 -0
  66. data/vendor/bundle/ruby/3.4.0/gems/{net-protocol-0.2.2 → net-protocol-0.3.0}/lib/net/protocol.rb +58 -4
  67. data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/CHANGELOG.md +54 -1
  68. data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/utils.rb +3 -3
  69. data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/version.rb +1 -1
  70. data/vendor/bundle/ruby/3.4.0/specifications/{net-imap-0.5.15.gemspec → net-imap-0.6.6.gemspec} +4 -4
  71. data/vendor/bundle/ruby/3.4.0/specifications/{net-protocol-0.2.2.gemspec → net-protocol-0.3.0.gemspec} +5 -5
  72. data/vendor/bundle/ruby/3.4.0/specifications/{rack-3.2.6.gemspec → rack-3.2.7.gemspec} +3 -3
  73. data/views/tdiary.rconf +2 -0
  74. metadata +127 -131
  75. data/vendor/bundle/ruby/3.4.0/cache/net-imap-0.5.15.gem +0 -0
  76. data/vendor/bundle/ruby/3.4.0/cache/net-protocol-0.2.2.gem +0 -0
  77. data/vendor/bundle/ruby/3.4.0/cache/rack-3.2.6.gem +0 -0
  78. data/vendor/bundle/ruby/3.4.0/gems/net-imap-0.5.15/Rakefile +0 -13
  79. data/vendor/bundle/ruby/3.4.0/gems/net-imap-0.5.15/lib/net/imap/data_lite.rb +0 -226
  80. data/vendor/bundle/ruby/3.4.0/gems/net-imap-0.5.15/lib/net/imap/errors.rb +0 -118
  81. data/vendor/bundle/ruby/3.4.0/gems/net-protocol-0.2.2/Gemfile +0 -7
  82. data/vendor/bundle/ruby/3.4.0/gems/net-protocol-0.2.2/Rakefile +0 -10
  83. data/vendor/bundle/ruby/3.4.0/gems/net-protocol-0.2.2/bin/console +0 -14
  84. data/vendor/bundle/ruby/3.4.0/gems/net-protocol-0.2.2/bin/setup +0 -8
  85. data/vendor/bundle/ruby/3.4.0/gems/net-protocol-0.2.2/net-protocol.gemspec +0 -33
  86. /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/BSDL +0 -0
  87. /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/COPYING +0 -0
  88. /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/LICENSE.txt +0 -0
  89. /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/docs/styles.css +0 -0
  90. /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/authenticators.rb +0 -0
  91. /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/config/attr_type_coercion.rb +0 -0
  92. /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/deprecated_client_options.rb +0 -0
  93. /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/fetch_data.rb +0 -0
  94. /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/flags.rb +0 -0
  95. /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/sasl/anonymous_authenticator.rb +0 -0
  96. /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/sasl/authentication_exchange.rb +0 -0
  97. /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/sasl/authenticators.rb +0 -0
  98. /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/sasl/client_adapter.rb +0 -0
  99. /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/sasl/cram_md5_authenticator.rb +0 -0
  100. /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/sasl/digest_md5_authenticator.rb +0 -0
  101. /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/sasl/external_authenticator.rb +0 -0
  102. /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/sasl/gs2_header.rb +0 -0
  103. /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/sasl/login_authenticator.rb +0 -0
  104. /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/sasl/oauthbearer_authenticator.rb +0 -0
  105. /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/sasl/plain_authenticator.rb +0 -0
  106. /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/sasl/protocol_adapters.rb +0 -0
  107. /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/sasl/scram_algorithm.rb +0 -0
  108. /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/sasl/stringprep.rb +0 -0
  109. /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/sasl/xoauth2_authenticator.rb +0 -0
  110. /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/sasl.rb +0 -0
  111. /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/sasl_adapter.rb +0 -0
  112. /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/stringprep/nameprep.rb +0 -0
  113. /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/stringprep/saslprep.rb +0 -0
  114. /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/stringprep/saslprep_tables.rb +0 -0
  115. /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/stringprep/tables.rb +0 -0
  116. /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/stringprep/trace.rb +0 -0
  117. /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/stringprep.rb +0 -0
  118. /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/vanished_data.rb +0 -0
  119. /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/rakelib/benchmarks.rake +0 -0
  120. /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/rakelib/rfcs.rake +0 -0
  121. /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/rakelib/saslprep.rake +0 -0
  122. /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/rakelib/string_prep_tables_generator.rb +0 -0
  123. /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/sample/net-imap.rb +0 -0
  124. /data/vendor/bundle/ruby/3.4.0/gems/{net-protocol-0.2.2 → net-protocol-0.3.0}/README.md +0 -0
  125. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/CONTRIBUTING.md +0 -0
  126. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/MIT-LICENSE +0 -0
  127. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/README.md +0 -0
  128. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/SPEC.rdoc +0 -0
  129. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/auth/abstract/handler.rb +0 -0
  130. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/auth/abstract/request.rb +0 -0
  131. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/auth/basic.rb +0 -0
  132. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/bad_request.rb +0 -0
  133. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/body_proxy.rb +0 -0
  134. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/builder.rb +0 -0
  135. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/cascade.rb +0 -0
  136. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/common_logger.rb +0 -0
  137. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/conditional_get.rb +0 -0
  138. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/config.rb +0 -0
  139. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/constants.rb +0 -0
  140. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/content_length.rb +0 -0
  141. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/content_type.rb +0 -0
  142. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/deflater.rb +0 -0
  143. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/directory.rb +0 -0
  144. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/etag.rb +0 -0
  145. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/events.rb +0 -0
  146. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/files.rb +0 -0
  147. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/head.rb +0 -0
  148. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/headers.rb +0 -0
  149. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/lint.rb +0 -0
  150. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/lock.rb +0 -0
  151. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/media_type.rb +0 -0
  152. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/method_override.rb +0 -0
  153. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/mime.rb +0 -0
  154. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/mock.rb +0 -0
  155. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/mock_request.rb +0 -0
  156. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/mock_response.rb +0 -0
  157. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/multipart/generator.rb +0 -0
  158. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/multipart/parser.rb +0 -0
  159. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/multipart/uploaded_file.rb +0 -0
  160. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/multipart.rb +0 -0
  161. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/null_logger.rb +0 -0
  162. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/query_parser.rb +0 -0
  163. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/recursive.rb +0 -0
  164. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/reloader.rb +0 -0
  165. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/request.rb +0 -0
  166. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/response.rb +0 -0
  167. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/rewindable_input.rb +0 -0
  168. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/runtime.rb +0 -0
  169. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/sendfile.rb +0 -0
  170. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/show_exceptions.rb +0 -0
  171. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/show_status.rb +0 -0
  172. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/static.rb +0 -0
  173. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/tempfile_reaper.rb +0 -0
  174. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/urlmap.rb +0 -0
  175. /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack.rb +0 -0
@@ -326,6 +326,11 @@ module Net
326
326
  #
327
327
  # <em>In general, #capable? should be used rather than explicitly sending a
328
328
  # +CAPABILITY+ command to the server.</em>
329
+ # - #enable: Enables backwards incompatible server extensions.
330
+ # <em>Requires the +ENABLE+ or +IMAP4rev2+ capability.</em>
331
+ # - #enabled: Returns a set of enabled server extensions.
332
+ # - #enabled?: Returns whether a server extension has been enabled.
333
+ # - #utf8_enabled?: Returns whether UTF-8 string encoding has been enabled.
329
334
  #
330
335
  # === Handling server responses
331
336
  #
@@ -359,8 +364,8 @@ module Net
359
364
  #
360
365
  # - #capability: Returns the server's capabilities as an array of strings.
361
366
  #
362
- # <em>In general, #capable? should be used rather than explicitly sending a
363
- # +CAPABILITY+ command to the server.</em>
367
+ # <em>In general,</em> #capable? <em>should be used rather than explicitly
368
+ # sending a +CAPABILITY+ command to the server.</em>
364
369
  # - #noop: Allows the server to send unsolicited untagged #responses.
365
370
  # - #logout: Tells the server to end the session. Enters the +logout+ state.
366
371
  #
@@ -450,8 +455,8 @@ module Net
450
455
  #
451
456
  # Although IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051] is not supported
452
457
  # yet, Net::IMAP supports several extensions that have been folded into it:
453
- # +ENABLE+, +IDLE+, +MOVE+, +NAMESPACE+, +SASL-IR+, +UIDPLUS+, +UNSELECT+,
454
- # <tt>STATUS=SIZE</tt>, and the fetch side of +BINARY+.
458
+ # +ENABLE+, +IDLE+, +LITERAL-+, +MOVE+, +NAMESPACE+, +SASL-IR+, +UIDPLUS+,
459
+ # +UNSELECT+, <tt>STATUS=SIZE</tt>, and the fetch side of +BINARY+.
455
460
  # Commands for these extensions are listed with the {Core IMAP
456
461
  # commands}[rdoc-ref:Net::IMAP@Core+IMAP+commands], above.
457
462
  #
@@ -459,7 +464,7 @@ module Net
459
464
  # <em>The following are folded into +IMAP4rev2+ but are currently
460
465
  # unsupported or incompletely supported by</em> Net::IMAP<em>: RFC4466
461
466
  # extensions, +SEARCHRES+, +LIST-EXTENDED+, +LIST-STATUS+,
462
- # +LITERAL-+, and +SPECIAL-USE+.</em>
467
+ # and +SPECIAL-USE+.</em>
463
468
  #
464
469
  # ==== RFC2087: +QUOTA+
465
470
  # +NOTE:+ Only the +STORAGE+ quota resource type is currently supported.
@@ -489,9 +494,7 @@ module Net
489
494
  # IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051].
490
495
  # - Updates #fetch and #uid_fetch with the +BINARY+, +BINARY.PEEK+, and
491
496
  # +BINARY.SIZE+ items. See FetchData#binary and FetchData#binary_size.
492
- #
493
- # >>>
494
- # *NOTE:* The binary extension the #append command is _not_ supported yet.
497
+ # - Updates #append to allow binary messages containing +NULL+ bytes.
495
498
  #
496
499
  # ==== RFC3691: +UNSELECT+
497
500
  # Folded into IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051] and also included
@@ -554,6 +557,7 @@ module Net
554
557
  # ==== RFC6855: <tt>UTF8=ACCEPT</tt>, <tt>UTF8=ONLY</tt>
555
558
  #
556
559
  # - See #enable for information about support for UTF-8 string encoding.
560
+ # - #utf8_enabled?: Returns whether UTF-8 string encoding has been enabled.
557
561
  #
558
562
  # ==== RFC7162: +CONDSTORE+
559
563
  #
@@ -571,6 +575,15 @@ module Net
571
575
  # - Updates #store and #uid_store with the +unchangedsince+ modifier and adds
572
576
  # the +MODIFIED+ ResponseCode to the tagged response.
573
577
  #
578
+ # ==== RFC7888: <tt>LITERAL+</tt>
579
+ # - Literal strings smaller than Config#max_non_synchronizing_literal bytes
580
+ # are sent without waiting for the server's continuation request.
581
+ #
582
+ # ==== RFC7888: +LITERAL-+
583
+ # - Literal strings smaller than 4096 bytes or
584
+ # Config#max_non_synchronizing_literal (whichever is smaller)
585
+ # are sent without waiting for the server's continuation request.
586
+ #
574
587
  # ==== RFC8438: <tt>STATUS=SIZE</tt>
575
588
  # - Updates #status with the +SIZE+ status attribute.
576
589
  #
@@ -644,9 +657,9 @@ module Net
644
657
  # RFC 5322, DOI 10.17487/RFC5322, October 2008,
645
658
  # <https://www.rfc-editor.org/info/rfc5322>.
646
659
  #
647
- # <em>Note: obsoletes</em>
648
- # RFC-2822[https://www.rfc-editor.org/rfc/rfc2822]<em> (April 2001) and</em>
649
- # RFC-822[https://www.rfc-editor.org/rfc/rfc822]<em> (August 1982).</em>
660
+ # *NOTE*: obsoletes
661
+ # RFC-2822[https://www.rfc-editor.org/rfc/rfc2822] (April 2001) and
662
+ # RFC-822[https://www.rfc-editor.org/rfc/rfc822] (August 1982).
650
663
  #
651
664
  # [CHARSET[https://www.rfc-editor.org/rfc/rfc2978]]::
652
665
  # Freed, N. and J. Postel, "IANA Charset Registration Procedures", BCP 19,
@@ -753,8 +766,8 @@ module Net
753
766
  # Gulbrandsen, A. and N. Freed, Ed., "Internet Message Access Protocol
754
767
  # (\IMAP) - MOVE Extension", RFC 6851, DOI 10.17487/RFC6851, January 2013,
755
768
  # <https://www.rfc-editor.org/info/rfc6851>.
756
- # [UTF8=ACCEPT[https://www.rfc-editor.org/rfc/rfc6855]]::
757
- # [UTF8=ONLY[https://www.rfc-editor.org/rfc/rfc6855]]::
769
+ # [{UTF8=ACCEPT}[https://www.rfc-editor.org/rfc/rfc6855]]::
770
+ # [{UTF8=ONLY}[https://www.rfc-editor.org/rfc/rfc6855]]::
758
771
  # Resnick, P., Ed., Newman, C., Ed., and S. Shen, Ed.,
759
772
  # "IMAP Support for UTF-8", RFC 6855, DOI 10.17487/RFC6855, March 2013,
760
773
  # <https://www.rfc-editor.org/info/rfc6855>.
@@ -806,7 +819,7 @@ module Net
806
819
  # * {IMAP URLAUTH Authorization Mechanism Registry}[https://www.iana.org/assignments/urlauth-authorization-mechanism-registry/urlauth-authorization-mechanism-registry.xhtml]
807
820
  #
808
821
  class IMAP < Protocol
809
- VERSION = "0.5.15"
822
+ VERSION = "0.6.6"
810
823
 
811
824
  # Aliases for supported capabilities, to be used with the #enable command.
812
825
  ENABLE_ALIASES = {
@@ -814,6 +827,11 @@ module Net
814
827
  "UTF8=ONLY" => "UTF8=ACCEPT",
815
828
  }.freeze
816
829
 
830
+ # Aliases for supported capabilities, to be used with #enabled?.
831
+ ENABLED_ALIASES = {
832
+ utf8: Set.new(%w[UTF8=ACCEPT IMAP4REV2]).freeze,
833
+ }.freeze
834
+
817
835
  dir = File.expand_path("imap", __dir__)
818
836
  autoload :ConnectionState, "#{dir}/connection_state"
819
837
  autoload :ResponseReader, "#{dir}/response_reader"
@@ -823,10 +841,6 @@ module Net
823
841
  autoload :StringPrep, "#{dir}/stringprep"
824
842
 
825
843
  include MonitorMixin
826
- if defined?(OpenSSL::SSL)
827
- include OpenSSL
828
- include SSL
829
- end
830
844
 
831
845
  # :call-seq:
832
846
  # Net::IMAP::SequenceSet(set = nil) -> SequenceSet
@@ -1107,11 +1121,11 @@ module Net
1107
1121
  @ssl_ctx_params, @ssl_ctx = build_ssl_ctx(ssl)
1108
1122
 
1109
1123
  # Basic Client State
1110
- @utf8_strings = false
1111
1124
  @debug_output_bol = true
1112
1125
  @exception = nil
1113
1126
  @greeting = nil
1114
1127
  @capabilities = nil
1128
+ @enabled = Set.new
1115
1129
  @tls_verified = false
1116
1130
  @connection_state = ConnectionState::NotAuthenticated.new
1117
1131
 
@@ -1142,6 +1156,44 @@ module Net
1142
1156
  start_imap_connection
1143
1157
  end
1144
1158
 
1159
+ # Returns a string representation of +self+, showing basic client state
1160
+ # information.
1161
+ #
1162
+ # imap = Net::IMAP.new(hostname, ssl: true)
1163
+ # imap.inspect #=> "#<Net::IMAP imap.example.net:993 TLS not_authenticated>"
1164
+ #
1165
+ # imap.authenticate(:oauthbearer, "user", token)
1166
+ # imap.inspect #=> "#<Net::IMAP imap.example.net:993 TLS authenticated>"
1167
+ #
1168
+ # imap.select("INBOX")
1169
+ # imap.inspect #=> "#<Net::IMAP imap.example.net:993 TLS selected>"
1170
+ #
1171
+ # imap.logout
1172
+ # imap.inspect #=> "#<Net::IMAP imap.example.net:993 TLS logout>"
1173
+ #
1174
+ # imap = Net::IMAP.new(hostname, ssl: false)
1175
+ # imap.inspect #=> "#<Net::IMAP imap.example.net:143 PLAINTEXT not_authenticated>"
1176
+ #
1177
+ # imap.starttls verify_mode: OpenSSL::SSL::VERIFY_NONE
1178
+ # imap.inspect #=> "#<Net::IMAP imap.example.net:993 TLS (NOT VERIFIED) not_authenticated>"
1179
+ #
1180
+ def inspect
1181
+ conn_state = disconnected? ? "disconnected" : connection_state.to_sym
1182
+ "#<%s:0x%08x %s:%s %s %s>" % [
1183
+ self.class.name, __id__, host, port, inspect_tls_state, conn_state
1184
+ ]
1185
+ end
1186
+
1187
+ private def inspect_tls_state
1188
+ if tls_verified?
1189
+ "TLS"
1190
+ elsif ssl_ctx && @sock.kind_of?(OpenSSL::SSL::SSLSocket)
1191
+ "TLS (#{@sock.session ? "NOT VERIFIED" : "NOT ESTABLISHED"})"
1192
+ else
1193
+ "PLAINTEXT#{" (TLS NOT STARTED)" if ssl_ctx}"
1194
+ end
1195
+ end
1196
+
1145
1197
  # Returns true after the TLS negotiation has completed and the remote
1146
1198
  # hostname has been verified. Returns false when TLS has been established
1147
1199
  # but peer verification was disabled.
@@ -1152,9 +1204,10 @@ module Net
1152
1204
  # Waits for receiver thread to close before returning, except when called
1153
1205
  # from inside the connection mutex such as from a response handler. Slow or
1154
1206
  # stuck response handlers can cause #disconnect to hang until they complete.
1207
+ # Use +timeout+ to limit how long to wait for the receiver thread to exit.
1155
1208
  #
1156
1209
  # Related: #logout, #logout!
1157
- def disconnect
1210
+ def disconnect(timeout: nil)
1158
1211
  in_logout_state = try_state_logout?
1159
1212
  return if disconnected?
1160
1213
  in_receiver_thread = Thread.current == @receiver_thread
@@ -1166,7 +1219,7 @@ module Net
1166
1219
  @receiver_thread.raise(e) unless in_receiver_thread
1167
1220
  end
1168
1221
  @sock.close
1169
- @receiver_thread.join unless mon_owned? || in_receiver_thread
1222
+ @receiver_thread.join(timeout) unless mon_owned? || in_receiver_thread
1170
1223
  raise e if e
1171
1224
  ensure
1172
1225
  # Try again after shutting down the receiver thread. With no reciever
@@ -1428,7 +1481,7 @@ module Net
1428
1481
  end
1429
1482
  if error
1430
1483
  disconnect
1431
- raise error
1484
+ reraise error
1432
1485
  end
1433
1486
  unless handled
1434
1487
  disconnect
@@ -1551,6 +1604,7 @@ module Net
1551
1604
  # completes. If the TaggedResponse to #authenticate includes updated
1552
1605
  # capabilities, they will be cached.
1553
1606
  def authenticate(*args, sasl_ir: config.sasl_ir, **props, &callback)
1607
+ sasl_ir = may_depend_on_capabilities_cached?(sasl_ir)
1554
1608
  sasl_adapter.authenticate(*args, sasl_ir: sasl_ir, **props, &callback)
1555
1609
  .tap do state_authenticated! _1 end
1556
1610
  end
@@ -1602,7 +1656,7 @@ module Net
1602
1656
  # When the +condstore+ keyword argument is true, the server is told to
1603
1657
  # enable the extension. If +mailbox+ supports persistence of mod-sequences,
1604
1658
  # the +HIGHESTMODSEQ+ ResponseCode will be sent as an untagged response to
1605
- # #select and all `FETCH` responses will include FetchData#modseq.
1659
+ # #select and all +FETCH+ responses will include FetchData#modseq.
1606
1660
  # Otherwise, the +NOMODSEQ+ ResponseCode will be sent.
1607
1661
  #
1608
1662
  # A Net::IMAP::NoResponseError is raised if the mailbox does not
@@ -1930,7 +1984,7 @@ module Net
1930
1984
  if storage_limit.nil?
1931
1985
  list = []
1932
1986
  else
1933
- list = ["STORAGE", Integer(storage_limit)]
1987
+ list = ["STORAGE", NumValidator.coerce_number64(storage_limit)]
1934
1988
  end
1935
1989
  send_command("SETQUOTA", quota_root, list)
1936
1990
  end
@@ -2078,9 +2132,14 @@ module Net
2078
2132
  #
2079
2133
  # ==== Capabilities
2080
2134
  #
2135
+ # If +BINARY+ [RFC3516[https://www.rfc-editor.org/rfc/rfc3516.html]] is
2136
+ # supported by the server, +message+ may contain +NULL+ characters and
2137
+ # be sent as a binary literal. Otherwise, binary message parts must be
2138
+ # encoded appropriately (for example, +base64+).
2139
+ #
2081
2140
  # If +UIDPLUS+ [RFC4315[https://www.rfc-editor.org/rfc/rfc4315.html]] is
2082
2141
  # supported and the destination supports persistent UIDs, the server's
2083
- # response should include an +APPENDUID+ response code with UIDPlusData.
2142
+ # response should include an +APPENDUID+ response code with AppendUIDData.
2084
2143
  # This will report the UIDVALIDITY of the destination mailbox and the
2085
2144
  # assigned UID of the appended message.
2086
2145
  #
@@ -2088,12 +2147,11 @@ module Net
2088
2147
  # TODO: add MULTIAPPEND support
2089
2148
  #++
2090
2149
  def append(mailbox, message, flags = nil, date_time = nil)
2150
+ message = StringFormatter.literal_or_literal8(message, name: "message")
2091
2151
  args = []
2092
- if flags
2093
- args.push(flags)
2094
- end
2152
+ args.push(flags) if flags
2095
2153
  args.push(date_time) if date_time
2096
- args.push(Literal.new(message))
2154
+ args.push(message)
2097
2155
  send_command("APPEND", mailbox, *args)
2098
2156
  end
2099
2157
 
@@ -2847,7 +2905,7 @@ module Net
2847
2905
  #
2848
2906
  # If +UIDPLUS+ [RFC4315[https://www.rfc-editor.org/rfc/rfc4315.html]] is
2849
2907
  # supported, the server's response should include a +COPYUID+ response code
2850
- # with UIDPlusData. This will report the UIDVALIDITY of the destination
2908
+ # with CopyUIDData. This will report the UIDVALIDITY of the destination
2851
2909
  # mailbox, the UID set of the source messages, and the assigned UID set of
2852
2910
  # the moved messages.
2853
2911
  #
@@ -2888,7 +2946,7 @@ module Net
2888
2946
  #
2889
2947
  # If +UIDPLUS+ [RFC4315[https://www.rfc-editor.org/rfc/rfc4315.html]] is
2890
2948
  # supported, the server's response should include a +COPYUID+ response code
2891
- # with UIDPlusData. This will report the UIDVALIDITY of the destination
2949
+ # with CopyUIDData. This will report the UIDVALIDITY of the destination
2892
2950
  # mailbox, the UID set of the source messages, and the assigned UID set of
2893
2951
  # the moved messages.
2894
2952
  #
@@ -3114,12 +3172,48 @@ module Net
3114
3172
  synchronize do
3115
3173
  send_command("ENABLE", *capabilities)
3116
3174
  result = clear_responses("ENABLED").last || []
3117
- @utf8_strings ||= result.include? "UTF8=ACCEPT"
3118
- @utf8_strings ||= result.include? "IMAP4REV2"
3175
+ @enabled.merge(result.map(&:upcase))
3119
3176
  result
3120
3177
  end
3121
3178
  end
3122
3179
 
3180
+ # Returns whether UTF-8 string encoding has been enabled for the connection.
3181
+ #
3182
+ # This is currently identical to calling #enabled? with +:utf8+.
3183
+ #
3184
+ # See #enable and #enabled?.
3185
+ def utf8_enabled?; enabled?(:utf8) end
3186
+
3187
+ # Returns whether +capability+ is in the set of #enabled capabilities,
3188
+ # matched case-insensitively.
3189
+ #
3190
+ # When +capability+ is +:utf8+, it matches if _either_
3191
+ # <tt>"UTF8=ACCEPT"</tt> or <tt>"IMAP4REV2"</tt> is enabled.
3192
+ #
3193
+ # See #enable and #utf8_enabled?.
3194
+ def enabled?(capability)
3195
+ case capability
3196
+ in String
3197
+ capability = capability.upcase
3198
+ synchronize { @enabled.include?(capability) }
3199
+ in Symbol
3200
+ capabilities = ENABLED_ALIASES[capability] or
3201
+ raise ArgumentError, "unknown capability alias: #{capability}"
3202
+ synchronize { @enabled.intersect?(capabilities) }
3203
+ else
3204
+ raise TypeError, "expected capability to be String or Symbol, " \
3205
+ "got %s" % [capability.class]
3206
+ end
3207
+ end
3208
+
3209
+ # Returns a set of enabled capabilities for the connection, as upper-cased
3210
+ # strings.
3211
+ #
3212
+ # See #enable and #enabled?.
3213
+ def enabled
3214
+ synchronize { @enabled.dup }
3215
+ end
3216
+
3123
3217
  # Sends an {IDLE command [RFC2177 §3]}[https://www.rfc-editor.org/rfc/rfc6851#section-3]
3124
3218
  # {[IMAP4rev2 §6.3.13]}[https://www.rfc-editor.org/rfc/rfc9051#section-6.3.13]
3125
3219
  # that waits for notifications of new or expunged messages. Yields
@@ -3156,8 +3250,9 @@ module Net
3156
3250
 
3157
3251
  synchronize do
3158
3252
  tag = Thread.current[:net_imap_tag] = generate_tag
3159
- guard_against_tagged_response_skipping_handler!(tag, "IDLE")
3253
+ command = Command[tag:, name: "IDLE"]
3160
3254
  put_string("#{tag} IDLE#{CRLF}")
3255
+ finish_sending_command(command)
3161
3256
 
3162
3257
  begin
3163
3258
  add_response_handler(&response_handler)
@@ -3165,7 +3260,7 @@ module Net
3165
3260
  @idle_done_cond.wait(timeout)
3166
3261
  @idle_done_cond = nil
3167
3262
  if @receiver_thread_terminating
3168
- raise @exception || Net::IMAP::Error.new("connection closed")
3263
+ reraise @exception || Net::IMAP::Error.new("connection closed")
3169
3264
  end
3170
3265
  ensure
3171
3266
  remove_response_handler(response_handler)
@@ -3174,6 +3269,9 @@ module Net
3174
3269
  response = get_tagged_response(tag, "IDLE", idle_response_timeout)
3175
3270
  end
3176
3271
  end
3272
+ rescue InvalidResponseError
3273
+ disconnect
3274
+ raise
3177
3275
  end
3178
3276
 
3179
3277
  return response
@@ -3465,67 +3563,28 @@ module Net
3465
3563
  end
3466
3564
 
3467
3565
  def receive_responses
3468
- connection_closed = false
3469
- until connection_closed
3470
- synchronize do
3471
- @exception = nil
3472
- end
3473
- begin
3474
- resp = get_response
3475
- rescue Exception => e
3476
- synchronize do
3477
- state_logout!
3478
- @sock.close
3479
- @exception = e
3480
- end
3481
- break
3482
- end
3483
- unless resp
3484
- synchronize do
3485
- @exception = EOFError.new("end of file reached")
3486
- end
3487
- break
3488
- end
3489
- begin
3490
- synchronize do
3491
- case resp
3492
- when TaggedResponse
3493
- @tagged_responses[resp.tag] = resp
3494
- @tagged_response_arrival.broadcast
3495
- case resp.tag
3496
- when @logout_command_tag
3497
- state_logout!
3498
- return
3499
- when @continued_command_tag
3500
- @continuation_request_exception =
3501
- RESPONSE_ERRORS[resp.name].new(resp)
3502
- @continuation_request_arrival.signal
3503
- end
3504
- when UntaggedResponse
3505
- record_untagged_response(resp)
3506
- if resp.name == "BYE" && @logout_command_tag.nil?
3507
- state_logout!
3508
- @sock.close
3509
- @exception = ByeResponseError.new(resp)
3510
- connection_closed = true
3511
- end
3512
- when ContinuationRequest
3513
- @continuation_request_arrival.signal
3514
- end
3515
- state_unselected! if resp in {data: {code: {name: "CLOSED"}}}
3516
- @response_handlers.each do |handler|
3517
- handler.call(resp)
3518
- end
3519
- end
3520
- rescue Exception => e
3521
- @exception = e
3522
- synchronize do
3523
- @tagged_response_arrival.broadcast
3524
- @continuation_request_arrival.broadcast
3525
- end
3526
- end
3566
+ exception = nil
3567
+ loop do
3568
+ resp = get_response or raise EOFError, "end of file reached"
3569
+ handle_response(resp) or return
3527
3570
  end
3571
+ rescue Exception => exception
3572
+ # NOTE: this rescue clause is only capturing the exception for the ensure
3573
+ # clause. Using `$!` in the ensure clause seems to trigger a weird
3574
+ # TruffleRuby bug: https://github.com/truffleruby/truffleruby/issues/4308
3575
+ #
3576
+ # We don't assign @exception directly here, because we want that to be
3577
+ # atomically synchronized with all of the other changes in `ensure`.
3578
+ raise
3579
+ ensure
3528
3580
  synchronize do
3581
+ if exception
3582
+ # Handling exceptions here, not in a rescue clause, so the lock isn't
3583
+ # released and reacquired between rescue and ensure clauses.
3584
+ @exception ||= exception
3585
+ @sock.close
3586
+ end
3587
+ state_logout!
3529
3588
  @receiver_thread_terminating = true
3530
3589
  @tagged_response_arrival.broadcast
3531
3590
  @continuation_request_arrival.broadcast
@@ -3533,36 +3592,6 @@ module Net
3533
3592
  @idle_done_cond.signal
3534
3593
  end
3535
3594
  end
3536
- ensure
3537
- state_logout!
3538
- end
3539
-
3540
- def get_tagged_response(tag, cmd, timeout = nil)
3541
- if timeout
3542
- deadline = Time.now + timeout
3543
- end
3544
- until @tagged_responses.key?(tag)
3545
- raise @exception if @exception
3546
- if timeout
3547
- timeout = deadline - Time.now
3548
- if timeout <= 0
3549
- return nil
3550
- end
3551
- end
3552
- @tagged_response_arrival.wait(timeout)
3553
- end
3554
- resp = @tagged_responses.delete(tag)
3555
- case resp.name
3556
- when /\A(?:OK)\z/ni
3557
- return resp
3558
- when /\A(?:NO)\z/ni
3559
- raise NoResponseError, resp
3560
- when /\A(?:BAD)\z/ni
3561
- raise BadResponseError, resp
3562
- else
3563
- disconnect
3564
- raise InvalidResponseError, "invalid tagged resp: %p" % [resp.raw.chomp]
3565
- end
3566
3595
  end
3567
3596
 
3568
3597
  def get_response
@@ -3575,6 +3604,47 @@ module Net
3575
3604
  #############################
3576
3605
  # built-in response handlers
3577
3606
 
3607
+ def handle_response(resp)
3608
+ connection_closed = false
3609
+ synchronize do
3610
+ case resp
3611
+ when TaggedResponse
3612
+ @tagged_responses[resp.tag] = resp
3613
+ @tagged_response_arrival.broadcast
3614
+ case resp.tag
3615
+ when @logout_command_tag
3616
+ state_logout!
3617
+ return
3618
+ when @continued_command_tag
3619
+ @continuation_request_exception =
3620
+ RESPONSE_ERRORS[resp.name].new(resp)
3621
+ @continuation_request_arrival.signal
3622
+ end
3623
+ when UntaggedResponse
3624
+ record_untagged_response(resp)
3625
+ if resp.name == "BYE" && @logout_command_tag.nil?
3626
+ state_logout!
3627
+ @sock.close
3628
+ @exception = ByeResponseError.new(resp)
3629
+ connection_closed = true
3630
+ end
3631
+ when ContinuationRequest
3632
+ @continuation_request_arrival.signal
3633
+ end
3634
+ state_unselected! if resp in {data: {code: {name: "CLOSED"}}}
3635
+ @response_handlers.each do |handler|
3636
+ handler.call(resp)
3637
+ end
3638
+ rescue Exception => e
3639
+ @exception = e
3640
+ @tagged_response_arrival.broadcast
3641
+ @continuation_request_arrival.broadcast
3642
+ ensure
3643
+ @exception = nil unless connection_closed
3644
+ end
3645
+ !connection_closed
3646
+ end
3647
+
3578
3648
  # store name => [..., data]
3579
3649
  def record_untagged_response(resp)
3580
3650
  @responses[resp.name] << resp.data
@@ -3611,45 +3681,96 @@ module Net
3611
3681
  end
3612
3682
 
3613
3683
  def send_command(cmd, *args, &block)
3684
+ args.each do validate_data _1 end
3614
3685
  synchronize do
3615
- args.each do |i|
3616
- validate_data(i)
3617
- end
3618
3686
  tag = generate_tag
3687
+ command = Command[tag:, name: cmd]
3619
3688
  put_string(tag + " " + cmd)
3620
3689
  args.each do |i|
3621
3690
  put_string(" ")
3622
3691
  send_data(i, tag)
3623
3692
  end
3624
- guard_against_tagged_response_skipping_handler!(tag, cmd)
3625
- put_string(CRLF)
3626
- if cmd == "LOGOUT"
3627
- @logout_command_tag = tag
3628
- end
3629
- if block
3630
- add_response_handler(&block)
3631
- end
3693
+ @logout_command_tag = tag if cmd == "LOGOUT"
3694
+ finish_sending_command(command)
3695
+ add_response_handler(&block) if block
3632
3696
  begin
3633
- return get_tagged_response(tag, cmd)
3697
+ put_string(CRLF)
3698
+ get_tagged_response(tag, cmd)
3634
3699
  ensure
3635
- if block
3636
- remove_response_handler(block)
3700
+ remove_response_handler(block) if block
3701
+ end
3702
+ rescue InvalidResponseError
3703
+ disconnect
3704
+ raise
3705
+ end
3706
+ end
3707
+
3708
+ # NOTE: This must be synchronized with sending the command's final CRLF and
3709
+ # adding any command-related response handlers.
3710
+ def finish_sending_command(command)
3711
+ if (response = @tagged_responses[command.tag])&.name&.casecmp?("OK")
3712
+ raise InvalidTaggedResponseError.new(:incomplete, command:, response:)
3713
+ end
3714
+ end
3715
+
3716
+ def get_tagged_response(tag, cmd, timeout = nil)
3717
+ if timeout
3718
+ deadline = Time.now + timeout
3719
+ end
3720
+ until @tagged_responses.key?(tag)
3721
+ reraise @exception
3722
+ if timeout
3723
+ timeout = deadline - Time.now
3724
+ if timeout <= 0
3725
+ return nil
3637
3726
  end
3638
3727
  end
3728
+ @tagged_response_arrival.wait(timeout)
3729
+ end
3730
+ resp = @tagged_responses.delete(tag)
3731
+ case resp.name
3732
+ when /\A(?:OK)\z/ni
3733
+ return resp
3734
+ when /\A(?:NO)\z/ni
3735
+ raise NoResponseError, resp
3736
+ when /\A(?:BAD)\z/ni
3737
+ raise BadResponseError, resp
3738
+ else
3739
+ disconnect
3740
+ raise InvalidResponseError, "invalid tagged resp: %p" % [resp.raw_data.chomp]
3639
3741
  end
3640
- rescue InvalidResponseError
3641
- disconnect
3642
- raise
3643
3742
  end
3644
3743
 
3645
- def guard_against_tagged_response_skipping_handler!(tag, cmd)
3646
- return unless (resp = @tagged_responses[tag])&.name&.upcase == "OK"
3647
- raise InvalidResponseError, format(
3648
- "Received tagged 'OK' to incomplete %s command (tag=%s). " \
3649
- "This could indicate a malicious server, a man-in-the-middle, or " \
3650
- "client-side command injection. Disconnecting.",
3651
- cmd, tag
3652
- )
3744
+ # Raises a copy of +exception+ with an updated +backtrace+ and +cause+, or
3745
+ # returns +nil+ when +exception+ is falsey.
3746
+ #
3747
+ # +backtrace+ is set to reflect the current caller.
3748
+ #
3749
+ # +cause+ is set to the original exception, _if_ the original has its own
3750
+ # backtrace or cause. Otherwise, the original was never raised and the
3751
+ # default cause is used.
3752
+ #
3753
+ # This is meant for exceptions that may have been created by another thread.
3754
+ # Raising them directly gives a misleading backtrace, making it hard to
3755
+ # discover where the errors originate. Although it is sometimes more
3756
+ # appropriate to raise a wrapping exception, that changes the API and forces
3757
+ # updates to users' `rescue` pattern matching.
3758
+ def reraise(exception)
3759
+ return unless exception
3760
+ copy = exception.dup
3761
+ # NOTE: set_backtrace(caller_locations) doesn't work for CRuby <= 3.3.
3762
+ # and set_backtrace(nil) doesn't work for TruffleRuby 34.0.0:
3763
+ # https://github.com/truffleruby/truffleruby/issues/4296
3764
+ if RUBY_ENGINE == "truffleruby"
3765
+ copy.set_backtrace caller_locations
3766
+ else
3767
+ copy.set_backtrace nil
3768
+ end
3769
+ if exception.cause || exception.backtrace
3770
+ raise copy, cause: exception
3771
+ else
3772
+ raise copy
3773
+ end
3653
3774
  end
3654
3775
 
3655
3776
  def generate_tag
@@ -3673,11 +3794,11 @@ module Net
3673
3794
  end
3674
3795
 
3675
3796
  def enforce_logindisabled?
3676
- if config.enforce_logindisabled == :when_capabilities_cached
3677
- capabilities_cached?
3678
- else
3679
- config.enforce_logindisabled
3680
- end
3797
+ may_depend_on_capabilities_cached?(config.enforce_logindisabled)
3798
+ end
3799
+
3800
+ def may_depend_on_capabilities_cached?(value)
3801
+ value == :when_capabilities_cached ? capabilities_cached? : value
3681
3802
  end
3682
3803
 
3683
3804
  def expunge_internal(...)
@@ -3873,12 +3994,9 @@ module Net
3873
3994
  def build_ssl_ctx(ssl)
3874
3995
  if ssl
3875
3996
  params = (Hash.try_convert(ssl) || {}).freeze
3876
- context = SSLContext.new
3997
+ context = OpenSSL::SSL::SSLContext.new
3877
3998
  context.set_params(params)
3878
- if defined?(VerifyCallbackProc)
3879
- context.verify_callback = VerifyCallbackProc
3880
- end
3881
- context.freeze
3999
+ context.setup
3882
4000
  [params, context]
3883
4001
  else
3884
4002
  false
@@ -3889,12 +4007,12 @@ module Net
3889
4007
  raise "SSL extension not installed" unless defined?(OpenSSL::SSL)
3890
4008
  raise "already using SSL" if @sock.kind_of?(OpenSSL::SSL::SSLSocket)
3891
4009
  raise "cannot start TLS without SSLContext" unless ssl_ctx
3892
- @sock = SSLSocket.new(@sock, ssl_ctx)
4010
+ @sock = OpenSSL::SSL::SSLSocket.new(@sock, ssl_ctx)
3893
4011
  @reader = ResponseReader.new(self, @sock)
3894
4012
  @sock.sync_close = true
3895
4013
  @sock.hostname = @host if @sock.respond_to? :hostname=
3896
4014
  ssl_socket_connect(@sock, open_timeout)
3897
- if ssl_ctx.verify_mode != VERIFY_NONE
4015
+ if ssl_ctx.verify_mode != OpenSSL::SSL::VERIFY_NONE
3898
4016
  @sock.post_connection_check(@host)
3899
4017
  @tls_verified = true
3900
4018
  end
@@ -3958,7 +4076,6 @@ require_relative "imap/errors"
3958
4076
  require_relative "imap/config"
3959
4077
  require_relative "imap/command_data"
3960
4078
  require_relative "imap/data_encoding"
3961
- require_relative "imap/data_lite"
3962
4079
  require_relative "imap/flags"
3963
4080
  require_relative "imap/response_data"
3964
4081
  require_relative "imap/response_parser"