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.
- checksums.yaml +4 -4
- data/ChangeLog +2 -0
- data/Gemfile +2 -1
- data/Gemfile.lock +37 -37
- data/doc/UPGRADE.md +1 -1
- data/lib/tdiary/admin.rb +11 -13
- data/lib/tdiary/application.rb +2 -7
- data/lib/tdiary/author_only_base.rb +78 -9
- data/lib/tdiary/base.rb +2 -2
- data/lib/tdiary/cgi_adapter.rb +7 -5
- data/lib/tdiary/cgi_compat.rb +27 -95
- data/lib/tdiary/configuration.rb +4 -0
- data/lib/tdiary/core_ext.rb +146 -1
- data/lib/tdiary/dispatcher/index_main.rb +5 -23
- data/lib/tdiary/dispatcher/update_main.rb +2 -17
- data/lib/tdiary/dispatcher.rb +29 -15
- data/lib/tdiary/filter/default.rb +2 -2
- data/lib/tdiary/filter/spam.rb +2 -2
- data/lib/tdiary/filter.rb +1 -1
- data/lib/tdiary/plugin/00default.rb +18 -3
- data/lib/tdiary/plugin/en/00default.rb +15 -0
- data/lib/tdiary/plugin/ja/00default.rb +15 -0
- data/lib/tdiary/plugin.rb +1 -1
- data/lib/tdiary/rack/error_handler.rb +36 -0
- data/lib/tdiary/rack.rb +1 -0
- data/lib/tdiary/request.rb +12 -2
- data/lib/tdiary/server.rb +25 -3
- data/lib/tdiary/version.rb +1 -1
- data/lib/tdiary/view.rb +33 -28
- data/lib/tdiary/view_helper.rb +10 -2
- data/lib/tdiary.rb +6 -1
- data/misc/plugin/image.rb +1 -1
- data/misc/plugin/makerss.rb +3 -3
- data/tdiary.conf.sample +8 -0
- data/tdiary.conf.sample-en +8 -0
- data/vendor/bundle/ruby/3.4.0/cache/net-imap-0.6.6.gem +0 -0
- data/vendor/bundle/ruby/3.4.0/cache/net-protocol-0.3.0.gem +0 -0
- data/vendor/bundle/ruby/3.4.0/cache/rack-3.2.7.gem +0 -0
- data/vendor/bundle/ruby/3.4.0/extensions/x86_64-linux/3.4.0/cgi-0.5.2/gem_make.out +5 -5
- data/vendor/bundle/ruby/3.4.0/extensions/x86_64-linux/3.4.0/date-3.5.1/gem_make.out +5 -5
- data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/Gemfile +3 -4
- data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/README.md +1 -1
- data/vendor/bundle/ruby/3.4.0/gems/net-imap-0.6.6/Rakefile +24 -0
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- data/vendor/bundle/ruby/3.4.0/gems/net-imap-0.6.6/lib/net/imap/errors.rb +372 -0
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap.rb +279 -162
- data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/net-imap.gemspec +1 -1
- data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/rakelib/rdoc.rake +1 -18
- data/vendor/bundle/ruby/3.4.0/gems/{net-protocol-0.2.2/LICENSE.txt → net-protocol-0.3.0/BSDL} +3 -3
- data/vendor/bundle/ruby/3.4.0/gems/net-protocol-0.3.0/COPYING +56 -0
- data/vendor/bundle/ruby/3.4.0/gems/{net-protocol-0.2.2 → net-protocol-0.3.0}/lib/net/protocol.rb +58 -4
- data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/CHANGELOG.md +54 -1
- data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/utils.rb +3 -3
- data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/version.rb +1 -1
- data/vendor/bundle/ruby/3.4.0/specifications/{net-imap-0.5.15.gemspec → net-imap-0.6.6.gemspec} +4 -4
- data/vendor/bundle/ruby/3.4.0/specifications/{net-protocol-0.2.2.gemspec → net-protocol-0.3.0.gemspec} +5 -5
- data/vendor/bundle/ruby/3.4.0/specifications/{rack-3.2.6.gemspec → rack-3.2.7.gemspec} +3 -3
- data/views/tdiary.rconf +2 -0
- metadata +127 -131
- data/vendor/bundle/ruby/3.4.0/cache/net-imap-0.5.15.gem +0 -0
- data/vendor/bundle/ruby/3.4.0/cache/net-protocol-0.2.2.gem +0 -0
- data/vendor/bundle/ruby/3.4.0/cache/rack-3.2.6.gem +0 -0
- data/vendor/bundle/ruby/3.4.0/gems/net-imap-0.5.15/Rakefile +0 -13
- data/vendor/bundle/ruby/3.4.0/gems/net-imap-0.5.15/lib/net/imap/data_lite.rb +0 -226
- data/vendor/bundle/ruby/3.4.0/gems/net-imap-0.5.15/lib/net/imap/errors.rb +0 -118
- data/vendor/bundle/ruby/3.4.0/gems/net-protocol-0.2.2/Gemfile +0 -7
- data/vendor/bundle/ruby/3.4.0/gems/net-protocol-0.2.2/Rakefile +0 -10
- data/vendor/bundle/ruby/3.4.0/gems/net-protocol-0.2.2/bin/console +0 -14
- data/vendor/bundle/ruby/3.4.0/gems/net-protocol-0.2.2/bin/setup +0 -8
- data/vendor/bundle/ruby/3.4.0/gems/net-protocol-0.2.2/net-protocol.gemspec +0 -33
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/BSDL +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/COPYING +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/LICENSE.txt +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/docs/styles.css +0 -0
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/rakelib/benchmarks.rake +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/rakelib/rfcs.rake +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/rakelib/saslprep.rake +0 -0
- /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
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/sample/net-imap.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{net-protocol-0.2.2 → net-protocol-0.3.0}/README.md +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/CONTRIBUTING.md +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/MIT-LICENSE +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/README.md +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/SPEC.rdoc +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/auth/abstract/handler.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/auth/abstract/request.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/auth/basic.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/bad_request.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/body_proxy.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/builder.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/cascade.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/common_logger.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/conditional_get.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/config.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/constants.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/content_length.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/content_type.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/deflater.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/directory.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/etag.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/events.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/files.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/head.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/headers.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/lint.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/lock.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/media_type.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/method_override.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/mime.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/mock.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/mock_request.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/mock_response.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/multipart/generator.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/multipart/parser.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/multipart/uploaded_file.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/multipart.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/null_logger.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/query_parser.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/recursive.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/reloader.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/request.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/response.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/rewindable_input.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/runtime.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/sendfile.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/show_exceptions.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/show_status.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/static.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/tempfile_reaper.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/urlmap.rb +0 -0
- /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
|
|
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+,
|
|
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
|
-
#
|
|
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
|
-
#
|
|
648
|
-
# RFC-2822[https://www.rfc-editor.org/rfc/rfc2822]
|
|
649
|
-
# RFC-822[https://www.rfc-editor.org/rfc/rfc822]
|
|
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.
|
|
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
|
-
|
|
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
|
|
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",
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
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
|
-
@
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
|
|
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
|
-
|
|
3625
|
-
|
|
3626
|
-
if
|
|
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
|
-
|
|
3697
|
+
put_string(CRLF)
|
|
3698
|
+
get_tagged_response(tag, cmd)
|
|
3634
3699
|
ensure
|
|
3635
|
-
if block
|
|
3636
|
-
|
|
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
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
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
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
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
|
-
|
|
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"
|