net-imap 0.3.1 → 0.3.7
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.
Potentially problematic release.
This version of net-imap might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +8 -1
- data/.gitignore +1 -0
- data/Gemfile +3 -0
- data/Rakefile +3 -0
- data/benchmarks/stringprep.yml +65 -0
- data/benchmarks/table-regexps.yml +39 -0
- data/docs/styles.css +36 -0
- data/lib/net/imap/authenticators/digest_md5.rb +2 -2
- data/lib/net/imap/authenticators/xoauth2.rb +1 -1
- data/lib/net/imap/authenticators.rb +30 -10
- data/lib/net/imap/command_data.rb +8 -11
- data/lib/net/imap/data_encoding.rb +104 -8
- data/lib/net/imap/errors.rb +1 -1
- data/lib/net/imap/flags.rb +105 -77
- data/lib/net/imap/response_data.rb +1077 -317
- data/lib/net/imap/response_parser.rb +66 -1
- data/lib/net/imap/sasl/saslprep.rb +55 -0
- data/lib/net/imap/sasl/saslprep_tables.rb +98 -0
- data/lib/net/imap/sasl/stringprep.rb +72 -0
- data/lib/net/imap/sasl/stringprep_tables.rb +153 -0
- data/lib/net/imap/sasl.rb +78 -0
- data/lib/net/imap.rb +1209 -292
- data/net-imap.gemspec +3 -1
- data/rakelib/rdoc.rake +70 -0
- data/rakelib/rfcs.rake +168 -0
- data/rakelib/saslprep.rake +30 -0
- data/rakelib/string_prep_tables_generator.rb +423 -0
- metadata +29 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 30f6313663bc3f6e896e6166ad97a16296b52e59f9f2ef93f5b6ceb8a3031caa
|
4
|
+
data.tar.gz: e916c89df8b3d7bbf7c310c0299a6b7134caf71a0514091f4f87a171247750a2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f19ca9b2808b3d293b1a6ffef2c8b3287f1f69471c914bf775d51b3259d3dc837cee635d647c575dab70795b06b54c37214d2c51e9138a2093df5d3e20d5b478
|
7
|
+
data.tar.gz: d6c5b5c78de3f328486d4e107f1d6c336bb13be4738ad0d1b4e3b7b9b6af89f1a7bc77d09a7a27bd9f61160f38f4a5dc6c3a1ec5ae3f9f33705d6c52188e41f5
|
data/.github/workflows/test.yml
CHANGED
@@ -3,11 +3,18 @@ name: ubuntu
|
|
3
3
|
on: [push, pull_request]
|
4
4
|
|
5
5
|
jobs:
|
6
|
+
ruby-versions:
|
7
|
+
uses: ruby/actions/.github/workflows/ruby_versions.yml@master
|
8
|
+
with:
|
9
|
+
engine: cruby
|
10
|
+
min_version: 2.6
|
11
|
+
|
6
12
|
build:
|
13
|
+
needs: ruby-versions
|
7
14
|
name: build (${{ matrix.ruby }} / ${{ matrix.os }})
|
8
15
|
strategy:
|
9
16
|
matrix:
|
10
|
-
ruby:
|
17
|
+
ruby: ${{ fromJson(needs.ruby-versions.outputs.versions) }}
|
11
18
|
os: [ ubuntu-latest, macos-latest ]
|
12
19
|
experimental: [false]
|
13
20
|
include:
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/Rakefile
CHANGED
@@ -0,0 +1,65 @@
|
|
1
|
+
---
|
2
|
+
prelude: |
|
3
|
+
begin
|
4
|
+
require "mongo" # gem install mongo
|
5
|
+
require "idn" # gem install idn-ruby
|
6
|
+
rescue LoadError
|
7
|
+
warn "You must 'gem install mongo idn-ruby' for this benchmark."
|
8
|
+
raise
|
9
|
+
end
|
10
|
+
|
11
|
+
MStrPrep = Mongo::Auth::StringPrep
|
12
|
+
|
13
|
+
# this indirection will slow it down a little bit
|
14
|
+
def mongo_saslprep(string)
|
15
|
+
MStrPrep.prepare(string,
|
16
|
+
MStrPrep::Profiles::SASL::MAPPINGS,
|
17
|
+
MStrPrep::Profiles::SASL::PROHIBITED,
|
18
|
+
normalize: true,
|
19
|
+
bidi: true)
|
20
|
+
rescue Mongo::Error::FailedStringPrepValidation
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
|
24
|
+
$LOAD_PATH.unshift "./lib"
|
25
|
+
require "net/imap"
|
26
|
+
def net_imap_saslprep(string)
|
27
|
+
Net::IMAP::SASL::SASLprep.saslprep string, exception: false
|
28
|
+
end
|
29
|
+
|
30
|
+
def libidn_saslprep(string)
|
31
|
+
IDN::Stringprep.with_profile(string, "SASLprep")
|
32
|
+
rescue IDN::Stringprep::StringprepError
|
33
|
+
nil
|
34
|
+
end
|
35
|
+
|
36
|
+
benchmark:
|
37
|
+
- net_imap_saslprep "I\u00ADX" # RFC example 1. IX
|
38
|
+
- net_imap_saslprep "user" # RFC example 2. user
|
39
|
+
- net_imap_saslprep "USER" # RFC example 3. user
|
40
|
+
- net_imap_saslprep "\u00aa" # RFC example 4. a
|
41
|
+
- net_imap_saslprep "\u2168" # RFC example 5. IX
|
42
|
+
- net_imap_saslprep "\u0007" # RFC example 6. Error - prohibited character
|
43
|
+
- net_imap_saslprep "\u0627\u0031" # RFC example 7. Error - bidirectional check
|
44
|
+
- net_imap_saslprep "I\u2000X" # map to space: I X
|
45
|
+
- net_imap_saslprep "a longer string, e.g. a password"
|
46
|
+
|
47
|
+
- libidn_saslprep "I\u00ADX" # RFC example 1. IX
|
48
|
+
- libidn_saslprep "user" # RFC example 2. user
|
49
|
+
- libidn_saslprep "USER" # RFC example 3. user
|
50
|
+
- libidn_saslprep "\u00aa" # RFC example 4. a
|
51
|
+
- libidn_saslprep "\u2168" # RFC example 5. IX
|
52
|
+
- libidn_saslprep "\u0007" # RFC example 6. Error - prohibited character
|
53
|
+
- libidn_saslprep "\u0627\u0031" # RFC example 7. Error - bidirectional check
|
54
|
+
- libidn_saslprep "I\u2000X" # map to space: I X
|
55
|
+
- libidn_saslprep "a longer string, e.g. a password"
|
56
|
+
|
57
|
+
- mongo_saslprep "I\u00ADX" # RFC example 1. IX
|
58
|
+
- mongo_saslprep "user" # RFC example 2. user
|
59
|
+
- mongo_saslprep "USER" # RFC example 3. user
|
60
|
+
- mongo_saslprep "\u00aa" # RFC example 4. a
|
61
|
+
- mongo_saslprep "\u2168" # RFC example 5. IX
|
62
|
+
- mongo_saslprep "\u0007" # RFC example 6. Error - prohibited character
|
63
|
+
- mongo_saslprep "\u0627\u0031" # RFC example 7. Error - bidirectional check
|
64
|
+
- mongo_saslprep "I\u2000X" # map to space: I X
|
65
|
+
- mongo_saslprep "a longer string, e.g. a password"
|
@@ -0,0 +1,39 @@
|
|
1
|
+
prelude: |
|
2
|
+
require "json"
|
3
|
+
require "set"
|
4
|
+
|
5
|
+
all_codepoints = (0..0x10ffff).map{_1.chr("UTF-8") rescue nil}.compact
|
6
|
+
|
7
|
+
rfc3454_tables = Dir["rfcs/rfc3454*.json"]
|
8
|
+
.first
|
9
|
+
.then{File.read _1}
|
10
|
+
.then{JSON.parse _1}
|
11
|
+
titles = rfc3454_tables.delete("titles")
|
12
|
+
|
13
|
+
sets = rfc3454_tables
|
14
|
+
.transform_values{|t|t.keys rescue t}
|
15
|
+
.transform_values{|table|
|
16
|
+
table
|
17
|
+
.map{_1.split(?-).map{|i|Integer i, 16}}
|
18
|
+
.flat_map{_2 ? (_1.._2).to_a : _1}
|
19
|
+
.to_set
|
20
|
+
}
|
21
|
+
|
22
|
+
TABLE_A1_SET = sets.fetch "A.1"
|
23
|
+
ASSIGNED_3_2 = /\p{AGE=3.2}/
|
24
|
+
UNASSIGNED_3_2 = /\P{AGE=3.2}/
|
25
|
+
TABLE_A1_REGEX = /(?-mix:[\u{0000}-\u{001f}\u{007f}-\u{00a0}\u{0340}-\u{0341}\u{06dd}\u{070f}\u{1680}\u{180e}\u{2000}-\u{200f}\u{2028}-\u{202f}\u{205f}-\u{2063}\u{206a}-\u{206f}\u{2ff0}-\u{2ffb}\u{3000}\u{e000}-\u{f8ff}\u{fdd0}-\u{fdef}\u{feff}\u{fff9}-\u{ffff}\u{1d173}-\u{1d17a}\u{1fffe}-\u{1ffff}\u{2fffe}-\u{2ffff}\u{3fffe}-\u{3ffff}\u{4fffe}-\u{4ffff}\u{5fffe}-\u{5ffff}\u{6fffe}-\u{6ffff}\u{7fffe}-\u{7ffff}\u{8fffe}-\u{8ffff}\u{9fffe}-\u{9ffff}\u{afffe}-\u{affff}\u{bfffe}-\u{bffff}\u{cfffe}-\u{cffff}\u{dfffe}-\u{dffff}\u{e0001}\u{e0020}-\u{e007f}\u{efffe}-\u{10ffff}])|(?-mix:\p{Cs})/.freeze
|
26
|
+
|
27
|
+
benchmark:
|
28
|
+
|
29
|
+
# matches A.1
|
30
|
+
- script: "all_codepoints.grep(TABLE_A1_SET)"
|
31
|
+
- script: "all_codepoints.grep(TABLE_A1_REGEX)"
|
32
|
+
- script: "all_codepoints.grep(UNASSIGNED_3_2)"
|
33
|
+
- script: "all_codepoints.grep_v(ASSIGNED_3_2)"
|
34
|
+
|
35
|
+
# doesn't match A.1
|
36
|
+
- script: "all_codepoints.grep_v(TABLE_A1_SET)"
|
37
|
+
- script: "all_codepoints.grep_v(TABLE_A1_REGEX)"
|
38
|
+
- script: "all_codepoints.grep_v(UNASSIGNED_3_2)"
|
39
|
+
- script: "all_codepoints.grep(ASSIGNED_3_2)"
|
data/docs/styles.css
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
/* this is a work in progress. :) */
|
2
|
+
|
3
|
+
main .method-header {
|
4
|
+
background: rgba(27,31,35,0.05);
|
5
|
+
border: 1px solid #6C8C22;
|
6
|
+
padding: 0.5em;
|
7
|
+
border-radius: 4px;
|
8
|
+
/* padding: 0 0.5em; */
|
9
|
+
/* border-width: 0 1px; */
|
10
|
+
/* border-color: #6C8C22; */
|
11
|
+
/* border-style: solid; */
|
12
|
+
}
|
13
|
+
|
14
|
+
main .method-description, main .aliases {
|
15
|
+
padding-left: 1em;
|
16
|
+
}
|
17
|
+
|
18
|
+
body {
|
19
|
+
/*
|
20
|
+
* The default (300) can be too low contrast. Also, many fonts don't
|
21
|
+
* distinguish between 300->400, so <em>...</em> had no effect.
|
22
|
+
*/
|
23
|
+
font-weight: 400;
|
24
|
+
}
|
25
|
+
|
26
|
+
@media only screen and (min-width: 600px) {
|
27
|
+
nav {
|
28
|
+
height: 100%;
|
29
|
+
position: fixed;
|
30
|
+
overflow-y: scroll;
|
31
|
+
}
|
32
|
+
|
33
|
+
nav #class-metadata {
|
34
|
+
margin-bottom: 5em;
|
35
|
+
}
|
36
|
+
}
|
@@ -15,7 +15,7 @@ class Net::IMAP::DigestMD5Authenticator
|
|
15
15
|
@stage = STAGE_TWO
|
16
16
|
sparams = {}
|
17
17
|
c = StringScanner.new(challenge)
|
18
|
-
while c.scan(/(?:\s*,)?\s*(\w+)=("(?:[^\\"]
|
18
|
+
while c.scan(/(?:\s*,)?\s*(\w+)=("(?:[^\\"]|\\.)*"|[^,]+)\s*/)
|
19
19
|
k, v = c[1], c[2]
|
20
20
|
if v =~ /^"(.*)"$/
|
21
21
|
v = $1
|
@@ -26,7 +26,7 @@ class Net::IMAP::DigestMD5Authenticator
|
|
26
26
|
sparams[k] = v
|
27
27
|
end
|
28
28
|
|
29
|
-
raise Net::IMAP::DataFormatError, "Bad Challenge: '#{challenge}'" unless c.eos?
|
29
|
+
raise Net::IMAP::DataFormatError, "Bad Challenge: '#{challenge}'" unless c.eos? and sparams['qop']
|
30
30
|
raise Net::IMAP::Error, "Server does not support auth (qop = #{sparams['qop'].join(',')})" unless sparams['qop'].include?("auth")
|
31
31
|
|
32
32
|
response = {
|
@@ -3,22 +3,42 @@
|
|
3
3
|
# Registry for SASL authenticators used by Net::IMAP.
|
4
4
|
module Net::IMAP::Authenticators
|
5
5
|
|
6
|
-
# Adds an authenticator for
|
6
|
+
# Adds an authenticator for Net::IMAP#authenticate to use. +mechanism+ is the
|
7
7
|
# {SASL mechanism}[https://www.iana.org/assignments/sasl-mechanisms/sasl-mechanisms.xhtml]
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
8
|
+
# implemented by +authenticator+ (for instance, <tt>"PLAIN"</tt>).
|
9
|
+
#
|
10
|
+
# The +authenticator+ must respond to +#new+ (or #call), receiving the
|
11
|
+
# authenticator configuration and return a configured authentication session.
|
12
|
+
# The authenticator session must respond to +#process+, receiving the server's
|
13
|
+
# challenge and returning the client's response.
|
13
14
|
#
|
14
|
-
#
|
15
|
-
#
|
15
|
+
# See PlainAuthenticator, XOauth2Authenticator, and DigestMD5Authenticator for
|
16
|
+
# examples.
|
16
17
|
def add_authenticator(auth_type, authenticator)
|
17
18
|
authenticators[auth_type] = authenticator
|
18
19
|
end
|
19
20
|
|
20
|
-
#
|
21
|
-
#
|
21
|
+
# :call-seq:
|
22
|
+
# authenticator(mechanism, ...) -> authenticator
|
23
|
+
# authenticator(mech, *creds, **props) {|prop, auth| val } -> authenticator
|
24
|
+
# authenticator(mechanism, authnid, creds, authzid=nil) -> authenticator
|
25
|
+
# authenticator(mechanism, **properties) -> authenticator
|
26
|
+
# authenticator(mechanism) {|propname, authctx| value } -> authenticator
|
27
|
+
#
|
28
|
+
# Builds a new authentication session context for +mechanism+.
|
29
|
+
#
|
30
|
+
# [Note]
|
31
|
+
# This method is intended for internal use by connection protocol code only.
|
32
|
+
# Protocol client users should see refer to their client's documentation,
|
33
|
+
# e.g. Net::IMAP#authenticate for Net::IMAP.
|
34
|
+
#
|
35
|
+
# The call signatures documented for this method are recommendations for
|
36
|
+
# authenticator implementors. All arguments (other than +mechanism+) are
|
37
|
+
# forwarded to the registered authenticator's +#new+ (or +#call+) method, and
|
38
|
+
# each authenticator must document its own arguments.
|
39
|
+
#
|
40
|
+
# The returned object represents a single authentication exchange and <em>must
|
41
|
+
# not</em> be reused for multiple authentication attempts.
|
22
42
|
def authenticator(mechanism, *authargs, **properties, &callback)
|
23
43
|
authenticator = authenticators.fetch(mechanism.upcase) do
|
24
44
|
raise ArgumentError, 'unknown auth type - "%s"' % mechanism
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "date"
|
4
|
+
|
3
5
|
require_relative "errors"
|
4
6
|
|
5
7
|
module Net
|
@@ -21,7 +23,7 @@ module Net
|
|
21
23
|
validate_data(i)
|
22
24
|
end
|
23
25
|
end
|
24
|
-
when Time
|
26
|
+
when Time, Date, DateTime
|
25
27
|
when Symbol
|
26
28
|
else
|
27
29
|
data.validate
|
@@ -38,7 +40,9 @@ module Net
|
|
38
40
|
send_number_data(data)
|
39
41
|
when Array
|
40
42
|
send_list_data(data, tag)
|
41
|
-
when
|
43
|
+
when Date
|
44
|
+
send_date_data(data)
|
45
|
+
when Time, DateTime
|
42
46
|
send_time_data(data)
|
43
47
|
when Symbol
|
44
48
|
send_symbol_data(data)
|
@@ -101,15 +105,8 @@ module Net
|
|
101
105
|
put_string(")")
|
102
106
|
end
|
103
107
|
|
104
|
-
|
105
|
-
|
106
|
-
def send_time_data(time)
|
107
|
-
t = time.dup.gmtime
|
108
|
-
s = format('"%2d-%3s-%4d %02d:%02d:%02d +0000"',
|
109
|
-
t.day, DATE_MONTH[t.month - 1], t.year,
|
110
|
-
t.hour, t.min, t.sec)
|
111
|
-
put_string(s)
|
112
|
-
end
|
108
|
+
def send_date_data(date) put_string Net::IMAP.encode_date(date) end
|
109
|
+
def send_time_data(time) put_string Net::IMAP.encode_time(time) end
|
113
110
|
|
114
111
|
def send_symbol_data(symbol)
|
115
112
|
put_string("\\" + symbol.to_s)
|
@@ -1,10 +1,50 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "date"
|
4
|
+
|
3
5
|
require_relative "errors"
|
4
6
|
|
5
7
|
module Net
|
6
8
|
class IMAP < Protocol
|
7
9
|
|
10
|
+
# strftime/strptime format for an IMAP4 +date+, excluding optional dquotes.
|
11
|
+
# Use via the encode_date and decode_date methods.
|
12
|
+
#
|
13
|
+
# date = date-text / DQUOTE date-text DQUOTE
|
14
|
+
# date-text = date-day "-" date-month "-" date-year
|
15
|
+
#
|
16
|
+
# date-day = 1*2DIGIT
|
17
|
+
# ; Day of month
|
18
|
+
# date-month = "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" /
|
19
|
+
# "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec"
|
20
|
+
# date-year = 4DIGIT
|
21
|
+
STRFDATE = "%d-%b-%Y"
|
22
|
+
|
23
|
+
# strftime/strptime format for an IMAP4 +date-time+, including dquotes.
|
24
|
+
# See the encode_datetime and decode_datetime methods.
|
25
|
+
#
|
26
|
+
# date-time = DQUOTE date-day-fixed "-" date-month "-" date-year
|
27
|
+
# SP time SP zone DQUOTE
|
28
|
+
#
|
29
|
+
# date-day-fixed = (SP DIGIT) / 2DIGIT
|
30
|
+
# ; Fixed-format version of date-day
|
31
|
+
# date-month = "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" /
|
32
|
+
# "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec"
|
33
|
+
# date-year = 4DIGIT
|
34
|
+
# time = 2DIGIT ":" 2DIGIT ":" 2DIGIT
|
35
|
+
# ; Hours minutes seconds
|
36
|
+
# zone = ("+" / "-") 4DIGIT
|
37
|
+
# ; Signed four-digit value of hhmm representing
|
38
|
+
# ; hours and minutes east of Greenwich (that is,
|
39
|
+
# ; the amount that the given time differs from
|
40
|
+
# ; Universal Time). Subtracting the timezone
|
41
|
+
# ; from the given time will give the UT form.
|
42
|
+
# ; The Universal Time zone is "+0000".
|
43
|
+
#
|
44
|
+
# Note that Time.strptime <tt>"%d"</tt> flexibly parses either space or zero
|
45
|
+
# padding. However, the DQUOTEs are *not* optional.
|
46
|
+
STRFTIME = '"%d-%b-%Y %H:%M:%S %z"'
|
47
|
+
|
8
48
|
# Decode a string from modified UTF-7 format to UTF-8.
|
9
49
|
#
|
10
50
|
# UTF-7 is a 7-bit encoding of Unicode [UTF7]. IMAP uses a
|
@@ -14,9 +54,9 @@ module Net
|
|
14
54
|
# Net::IMAP does _not_ automatically encode and decode
|
15
55
|
# mailbox names to and from UTF-7.
|
16
56
|
def self.decode_utf7(s)
|
17
|
-
return s.gsub(/&([
|
18
|
-
if $1
|
19
|
-
(
|
57
|
+
return s.gsub(/&([A-Za-z0-9+,]+)?-/n) {
|
58
|
+
if base64 = $1
|
59
|
+
(base64.tr(",", "/") + "===").unpack1("m").encode(Encoding::UTF_8, Encoding::UTF_16BE)
|
20
60
|
else
|
21
61
|
"&"
|
22
62
|
end
|
@@ -35,14 +75,70 @@ module Net
|
|
35
75
|
}.force_encoding("ASCII-8BIT")
|
36
76
|
end
|
37
77
|
|
38
|
-
# Formats +time+ as an
|
39
|
-
def self.
|
40
|
-
|
78
|
+
# Formats +time+ as an IMAP4 date.
|
79
|
+
def self.encode_date(date)
|
80
|
+
date.to_date.strftime STRFDATE
|
41
81
|
end
|
42
82
|
|
43
|
-
#
|
83
|
+
# :call-seq: decode_date(string) -> Date
|
84
|
+
#
|
85
|
+
# Decodes +string+ as an IMAP formatted "date".
|
86
|
+
#
|
87
|
+
# Double quotes are optional. Day of month may be padded with zero or
|
88
|
+
# space. See STRFDATE.
|
89
|
+
def self.decode_date(string)
|
90
|
+
string = string.delete_prefix('"').delete_suffix('"')
|
91
|
+
Date.strptime(string, STRFDATE)
|
92
|
+
end
|
93
|
+
|
94
|
+
# :call-seq: encode_datetime(time) -> string
|
95
|
+
#
|
96
|
+
# Formats +time+ as an IMAP4 date-time.
|
97
|
+
def self.encode_datetime(time)
|
98
|
+
time.to_datetime.strftime STRFTIME
|
99
|
+
end
|
100
|
+
|
101
|
+
# :call-seq: decode_datetime(string) -> DateTime
|
102
|
+
#
|
103
|
+
# Decodes +string+ as an IMAP4 formatted "date-time".
|
104
|
+
#
|
105
|
+
# Note that double quotes are not optional. See STRFTIME.
|
106
|
+
def self.decode_datetime(string)
|
107
|
+
DateTime.strptime(string, STRFTIME)
|
108
|
+
end
|
109
|
+
|
110
|
+
# :call-seq: decode_time(string) -> Time
|
111
|
+
#
|
112
|
+
# Decodes +string+ as an IMAP4 formatted "date-time".
|
113
|
+
#
|
114
|
+
# Same as +decode_datetime+, but returning a Time instead.
|
115
|
+
def self.decode_time(string)
|
116
|
+
decode_datetime(string).to_time
|
117
|
+
end
|
118
|
+
|
119
|
+
class << self
|
120
|
+
alias encode_time encode_datetime
|
121
|
+
alias format_date encode_date
|
122
|
+
alias format_time encode_time
|
123
|
+
alias parse_date decode_date
|
124
|
+
alias parse_datetime decode_datetime
|
125
|
+
alias parse_time decode_time
|
126
|
+
|
127
|
+
# alias format_datetime encode_datetime # n.b. this is overridden below...
|
128
|
+
end
|
129
|
+
|
130
|
+
# DEPRECATED:: The original version returned incorrectly formatted strings.
|
131
|
+
# Strings returned by encode_datetime or format_time use the
|
132
|
+
# correct IMAP4rev1 syntax for "date-time".
|
133
|
+
#
|
134
|
+
# This invalid format has been temporarily retained for backward
|
135
|
+
# compatibility. A future release will change this method to return the
|
136
|
+
# correct format.
|
44
137
|
def self.format_datetime(time)
|
45
|
-
|
138
|
+
warn("#{self}.format_datetime incorrectly formats IMAP date-time. " \
|
139
|
+
"Convert to #{self}.encode_datetime or #{self}.format_time instead.",
|
140
|
+
uplevel: 1, category: :deprecated)
|
141
|
+
time.strftime("%d-%b-%Y %H:%M %z")
|
46
142
|
end
|
47
143
|
|
48
144
|
# Common validators of number and nz_number types
|
data/lib/net/imap/errors.rb
CHANGED