net-imap 0.3.1 → 0.3.7
Sign up to get free protection for your applications and to get access to all the features.
- 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