net-imap 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5ce3f04b1c49832a6e2b36c2b9b9a7a79223c297896aa7daeb7bf7fd0b54a7f6
4
- data.tar.gz: 2ce12d9e40a529f638a4314f6c61ebf343a5341225fa4c2442800be339a32dea
3
+ metadata.gz: a91d908ae16db12c507a6cf5c0e5eef57e18c97473b2a13a0ab14cf655e9bcb7
4
+ data.tar.gz: 1bdab36cf0779d14e2f414e00aee90d95d2584bfc8d591c11d5104b4071bebb8
5
5
  SHA512:
6
- metadata.gz: 8933d844581528c0b969e4e5256821a41cf7838f1fed493205c2447e3fd5578df6f9f1eb75f24cb14c8a227b3908218224c161da3a61a26dab2b66d819738d03
7
- data.tar.gz: 9b37cf6d107aa5e4a5bd650faac5f4fb4f2a4d2283068bd1b39793db2a5a3b1e6dcc86e5b850efc4e008ddbe0a0632d367ad0fb473e1e7158633c09726dc7f25
6
+ metadata.gz: 65133026b0746efbdc55a64bd1091da0524e5b922672767f334cec1d0357b31b973380bc8e787ff2430b831375f52050004d718b6308fa9203c9f6710ac2444b
7
+ data.tar.gz: 7e5e9fcac352549585e38b5a86b0198cc1c5996ad129cf9e53ca92f2ef63ea4b37d26ab8c5efd641b19711b2ea04e42622ead203c3afcaa8d420ceaaaa9893c8
@@ -0,0 +1,6 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: 'github-actions'
4
+ directory: '/'
5
+ schedule:
6
+ interval: 'weekly'
@@ -7,7 +7,7 @@ jobs:
7
7
  name: build (${{ matrix.ruby }} / ${{ matrix.os }})
8
8
  strategy:
9
9
  matrix:
10
- ruby: [ '3.0', 2.7, 2.5, head ]
10
+ ruby: [ head, '3.1', '3.0', '2.7' ]
11
11
  os: [ ubuntu-latest, macos-latest ]
12
12
  experimental: [false]
13
13
  include:
@@ -20,7 +20,7 @@ jobs:
20
20
  runs-on: ${{ matrix.os }}
21
21
  continue-on-error: ${{ matrix.experimental }}
22
22
  steps:
23
- - uses: actions/checkout@v2
23
+ - uses: actions/checkout@v3
24
24
  - name: Set up Ruby
25
25
  uses: ruby/setup-ruby@v1
26
26
  with:
data/LICENSE.txt CHANGED
@@ -20,3 +20,65 @@ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
20
20
  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
21
21
  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
22
22
  SUCH DAMAGE.
23
+
24
+ -------------------------------------------------------------------------
25
+
26
+ This software includes documentation which has been copied from the relevant
27
+ RFCs. The copied documentation is covered by the following licenses:
28
+
29
+ RFC 3501 (Editor: M. Crispin)
30
+ Full Copyright Statement
31
+
32
+ Copyright (C) The Internet Society (2003). All Rights Reserved.
33
+
34
+ This document and translations of it may be copied and furnished to
35
+ others, and derivative works that comment on or otherwise explain it
36
+ or assist in its implementation may be prepared, copied, published
37
+ and distributed, in whole or in part, without restriction of any
38
+ kind, provided that the above copyright notice and this paragraph are
39
+ included on all such copies and derivative works. However, this
40
+ document itself may not be modified in any way, such as by removing
41
+ the copyright notice or references to the Internet Society or other
42
+ Internet organizations, except as needed for the purpose of
43
+ developing Internet standards in which case the procedures for
44
+ copyrights defined in the Internet Standards process must be
45
+ followed, or as required to translate it into languages other than
46
+ English.
47
+
48
+ The limited permissions granted above are perpetual and will not be
49
+ revoked by the Internet Society or its successors or assigns. v This
50
+ document and the information contained herein is provided on an "AS
51
+ IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK
52
+ FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT
53
+ LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL
54
+ NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY
55
+ OR FITNESS FOR A PARTICULAR PURPOSE.
56
+
57
+
58
+ RFC9051 (Editors: A. Melnikov, B. Leiba)
59
+ Copyright Notice
60
+
61
+ Copyright (c) 2021 IETF Trust and the persons identified as the
62
+ document authors. All rights reserved.
63
+
64
+ This document is subject to BCP 78 and the IETF Trust's Legal
65
+ Provisions Relating to IETF Documents
66
+ (https://trustee.ietf.org/license-info) in effect on the date of
67
+ publication of this document. Please review these documents
68
+ carefully, as they describe your rights and restrictions with respect
69
+ to this document. Code Components extracted from this document must
70
+ include Simplified BSD License text as described in Section 4.e of
71
+ the Trust Legal Provisions and are provided without warranty as
72
+ described in the Simplified BSD License.
73
+
74
+ This document may contain material from IETF Documents or IETF
75
+ Contributions published or made publicly available before November
76
+ 10, 2008. The person(s) controlling the copyright in some of this
77
+ material may not have granted the IETF Trust the right to allow
78
+ modifications of such material outside the IETF Standards Process.
79
+ Without obtaining an adequate license from the person(s) controlling
80
+ the copyright in such materials, this document may not be modified
81
+ outside the IETF Standards Process, and derivative works of it may
82
+ not be created outside the IETF Standards Process, except to format
83
+ it for publication as an RFC or to translate it into languages other
84
+ than English.
data/Rakefile CHANGED
@@ -7,4 +7,11 @@ Rake::TestTask.new(:test) do |t|
7
7
  t.test_files = FileList["test/**/test_*.rb"]
8
8
  end
9
9
 
10
+ task :sync_tool do
11
+ require 'fileutils'
12
+ FileUtils.cp "../ruby/tool/lib/core_assertions.rb", "./test/lib"
13
+ FileUtils.cp "../ruby/tool/lib/envutil.rb", "./test/lib"
14
+ FileUtils.cp "../ruby/tool/lib/find_executable.rb", "./test/lib"
15
+ end
16
+
10
17
  task :default => :test
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "digest/md5"
4
-
5
3
  # Authenticator for the "+CRAM-MD5+" SASL mechanism, specified in
6
4
  # RFC2195[https://tools.ietf.org/html/rfc2195]. See Net::IMAP#authenticate.
7
5
  #
@@ -23,7 +21,11 @@ class Net::IMAP::CramMD5Authenticator
23
21
 
24
22
  private
25
23
 
26
- def initialize(user, password)
24
+ def initialize(user, password, warn_deprecation: true, **_ignored)
25
+ if warn_deprecation
26
+ warn "WARNING: CRAM-MD5 mechanism is deprecated." # TODO: recommend SCRAM
27
+ end
28
+ require "digest/md5"
27
29
  @user = user
28
30
  @password = password
29
31
  end
@@ -45,5 +47,5 @@ class Net::IMAP::CramMD5Authenticator
45
47
  return Digest::MD5.hexdigest(k_opad + digest)
46
48
  end
47
49
 
48
- Net::IMAP.add_authenticator "PLAIN", self
50
+ Net::IMAP.add_authenticator "CRAM-MD5", self
49
51
  end
@@ -1,8 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "digest/md5"
4
- require "strscan"
5
-
6
3
  # Net::IMAP authenticator for the "`DIGEST-MD5`" SASL mechanism type, specified
7
4
  # in RFC2831(https://tools.ietf.org/html/rfc2831). See Net::IMAP#authenticate.
8
5
  #
@@ -29,8 +26,8 @@ class Net::IMAP::DigestMD5Authenticator
29
26
  sparams[k] = v
30
27
  end
31
28
 
32
- raise DataFormatError, "Bad Challenge: '#{challenge}'" unless c.rest.size == 0
33
- raise Error, "Server does not support auth (qop = #{sparams['qop'].join(',')})" unless sparams['qop'].include?("auth")
29
+ raise Net::IMAP::DataFormatError, "Bad Challenge: '#{challenge}'" unless c.eos?
30
+ raise Net::IMAP::Error, "Server does not support auth (qop = #{sparams['qop'].join(',')})" unless sparams['qop'].include?("auth")
34
31
 
35
32
  response = {
36
33
  :nonce => sparams['nonce'],
@@ -77,11 +74,18 @@ class Net::IMAP::DigestMD5Authenticator
77
74
  end
78
75
  end
79
76
 
80
- def initialize(user, password, authname = nil)
77
+ def initialize(user, password, authname = nil, warn_deprecation: true)
78
+ if warn_deprecation
79
+ warn "WARNING: DIGEST-MD5 SASL mechanism was deprecated by RFC6331."
80
+ # TODO: recommend SCRAM instead.
81
+ end
82
+ require "digest/md5"
83
+ require "strscan"
81
84
  @user, @password, @authname = user, password, authname
82
85
  @nc, @stage = {}, STAGE_ONE
83
86
  end
84
87
 
88
+
85
89
  private
86
90
 
87
91
  STAGE_ONE = :stage_one
@@ -100,7 +104,7 @@ class Net::IMAP::DigestMD5Authenticator
100
104
  def qdval(k, v)
101
105
  return if k.nil? or v.nil?
102
106
  if %w"username authzid realm nonce cnonce digest-uri qop".include? k
103
- v.gsub!(/([\\"])/, "\\\1")
107
+ v = v.gsub(/([\\"])/, "\\\1")
104
108
  return '%s="%s"' % [k, v]
105
109
  else
106
110
  return '%s=%s' % [k, v]
@@ -33,7 +33,10 @@ class Net::IMAP::LoginAuthenticator
33
33
  STATE_USER = :USER
34
34
  STATE_PASSWORD = :PASSWORD
35
35
 
36
- def initialize(user, password)
36
+ def initialize(user, password, warn_deprecation: true, **_ignored)
37
+ if warn_deprecation
38
+ warn "WARNING: LOGIN SASL mechanism is deprecated. Use PLAIN instead."
39
+ end
37
40
  @user = user
38
41
  @password = password
39
42
  @state = STATE_USER
@@ -19,13 +19,15 @@ module Net::IMAP::Authenticators
19
19
 
20
20
  # Builds an authenticator for Net::IMAP#authenticate. +args+ will be passed
21
21
  # directly to the chosen authenticator's +#initialize+.
22
- def authenticator(auth_type, *args)
23
- auth_type = auth_type.upcase
24
- unless authenticators.has_key?(auth_type)
25
- raise ArgumentError,
26
- format('unknown auth type - "%s"', auth_type)
22
+ def authenticator(mechanism, *authargs, **properties, &callback)
23
+ authenticator = authenticators.fetch(mechanism.upcase) do
24
+ raise ArgumentError, 'unknown auth type - "%s"' % mechanism
25
+ end
26
+ if authenticator.respond_to?(:new)
27
+ authenticator.new(*authargs, **properties, &callback)
28
+ else
29
+ authenticator.call(*authargs, **properties, &callback)
27
30
  end
28
- authenticators[auth_type].new(*args)
29
31
  end
30
32
 
31
33
  private
@@ -38,7 +40,8 @@ end
38
40
 
39
41
  Net::IMAP.extend Net::IMAP::Authenticators
40
42
 
41
- require_relative "authenticators/login"
42
43
  require_relative "authenticators/plain"
44
+
45
+ require_relative "authenticators/login"
43
46
  require_relative "authenticators/cram_md5"
44
47
  require_relative "authenticators/digest_md5"
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "errors"
4
+
3
5
  module Net
4
6
  class IMAP < Protocol
5
7
 
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "errors"
4
+
3
5
  module Net
4
6
  class IMAP < Protocol
5
7
 
@@ -43,5 +45,62 @@ module Net
43
45
  return time.strftime('%d-%b-%Y %H:%M %z')
44
46
  end
45
47
 
48
+ # Common validators of number and nz_number types
49
+ module NumValidator # :nodoc
50
+ module_function
51
+
52
+ # Check is passed argument valid 'number' in RFC 3501 terminology
53
+ def valid_number?(num)
54
+ # [RFC 3501]
55
+ # number = 1*DIGIT
56
+ # ; Unsigned 32-bit integer
57
+ # ; (0 <= n < 4,294,967,296)
58
+ num >= 0 && num < 4294967296
59
+ end
60
+
61
+ # Check is passed argument valid 'nz_number' in RFC 3501 terminology
62
+ def valid_nz_number?(num)
63
+ # [RFC 3501]
64
+ # nz-number = digit-nz *DIGIT
65
+ # ; Non-zero unsigned 32-bit integer
66
+ # ; (0 < n < 4,294,967,296)
67
+ num != 0 && valid_number?(num)
68
+ end
69
+
70
+ # Check is passed argument valid 'mod_sequence_value' in RFC 4551 terminology
71
+ def valid_mod_sequence_value?(num)
72
+ # mod-sequence-value = 1*DIGIT
73
+ # ; Positive unsigned 64-bit integer
74
+ # ; (mod-sequence)
75
+ # ; (1 <= n < 18,446,744,073,709,551,615)
76
+ num >= 1 && num < 18446744073709551615
77
+ end
78
+
79
+ # Ensure argument is 'number' or raise DataFormatError
80
+ def ensure_number(num)
81
+ return if valid_number?(num)
82
+
83
+ msg = "number must be unsigned 32-bit integer: #{num}"
84
+ raise DataFormatError, msg
85
+ end
86
+
87
+ # Ensure argument is 'nz_number' or raise DataFormatError
88
+ def ensure_nz_number(num)
89
+ return if valid_nz_number?(num)
90
+
91
+ msg = "nz_number must be non-zero unsigned 32-bit integer: #{num}"
92
+ raise DataFormatError, msg
93
+ end
94
+
95
+ # Ensure argument is 'mod_sequence_value' or raise DataFormatError
96
+ def ensure_mod_sequence_value(num)
97
+ return if valid_mod_sequence_value?(num)
98
+
99
+ msg = "mod_sequence_value must be unsigned 64-bit integer: #{num}"
100
+ raise DataFormatError, msg
101
+ end
102
+
103
+ end
104
+
46
105
  end
47
106
  end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Net
4
+ class IMAP < Protocol
5
+
6
+ # Superclass of IMAP errors.
7
+ class Error < StandardError
8
+ end
9
+
10
+ # Error raised when data is in the incorrect format.
11
+ class DataFormatError < Error
12
+ end
13
+
14
+ # Error raised when a response from the server is non-parseable.
15
+ class ResponseParseError < Error
16
+ end
17
+
18
+ # Superclass of all errors used to encapsulate "fail" responses
19
+ # from the server.
20
+ class ResponseError < Error
21
+
22
+ # The response that caused this error
23
+ attr_accessor :response
24
+
25
+ def initialize(response)
26
+ @response = response
27
+
28
+ super @response.data.text
29
+ end
30
+
31
+ end
32
+
33
+ # Error raised upon a "NO" response from the server, indicating
34
+ # that the client command could not be completed successfully.
35
+ class NoResponseError < ResponseError
36
+ end
37
+
38
+ # Error raised upon a "BAD" response from the server, indicating
39
+ # that the client command violated the IMAP protocol, or an internal
40
+ # server failure has occurred.
41
+ class BadResponseError < ResponseError
42
+ end
43
+
44
+ # Error raised upon a "BYE" response from the server, indicating
45
+ # that the client is not being allowed to login, or has been timed
46
+ # out due to inactivity.
47
+ class ByeResponseError < ResponseError
48
+ end
49
+
50
+ # Error raised upon an unknown response from the server.
51
+ class UnknownResponseError < ResponseError
52
+ end
53
+
54
+ RESPONSE_ERRORS = Hash.new(ResponseError)
55
+ RESPONSE_ERRORS["NO"] = NoResponseError
56
+ RESPONSE_ERRORS["BAD"] = BadResponseError
57
+
58
+ end
59
+ end
@@ -3,74 +3,232 @@
3
3
  module Net
4
4
  class IMAP < Protocol
5
5
 
6
- # :category: Message Flags
6
+ # -------------------------------------------------------------------------
7
+ # :section: Message Flags: system flags
7
8
  #
8
- # Flag indicating a message has been seen.
9
+ # A message has a list of zero or more named tokens, known as "flags",
10
+ # associated with it. A flag is set by its addition to this list and is
11
+ # cleared by its removal. There are two types of flags in IMAP4rev2: system
12
+ # flags and keywords. A flag of either type can be permanent or
13
+ # session-only.
14
+ #
15
+ # A "system flag" is a message flag name that is predefined in the IMAP
16
+ # specification and begins with "\". +Net::IMAP+ returns all system flags
17
+ # as symbols, without the "\" prefix.
18
+ #
19
+ # The descriptions here were copied from the IMAP4rev2 specification:
20
+ # [RFC-9051 § 2.3.2](https://www.rfc-editor.org/rfc/rfc9051.html#section-2.3.2)
21
+ #
22
+ # See [RFC-3501 § 2.3.2](https://www.rfc-editor.org/rfc/rfc3501.html#section-2.3.2)
23
+ # for a description of the flags message attribute and system flag semantics
24
+ # in IMAP4rev1.
25
+ # -------------------------------------------------------------------------
26
+
27
+ # Flag indicating a message has been read.
9
28
  SEEN = :Seen
10
29
 
11
- # :category: Message Flags
12
- #
13
30
  # Flag indicating a message has been answered.
14
31
  ANSWERED = :Answered
15
32
 
16
- # :category: Message Flags
17
- #
18
- # Flag indicating a message has been flagged for special or urgent
33
+ # A message flag indicating a message has been flagged for special or urgent
19
34
  # attention.
35
+ #
36
+ # Also a mailbox special use attribute, which indicates that this mailbox
37
+ # presents all messages marked in some way as "important". When this
38
+ # special use is supported, it is likely to represent a virtual mailbox
39
+ # collecting messages (from other mailboxes) that are marked with the
40
+ # "\Flagged" message flag.
20
41
  FLAGGED = :Flagged
21
42
 
22
- # :category: Message Flags
23
- #
24
43
  # Flag indicating a message has been marked for deletion. This
25
44
  # will occur when the mailbox is closed or expunged.
26
45
  DELETED = :Deleted
27
46
 
28
- # :category: Message Flags
29
- #
30
47
  # Flag indicating a message is only a draft or work-in-progress version.
31
48
  DRAFT = :Draft
32
49
 
33
- # :category: Message Flags
34
- #
35
50
  # Flag indicating that the message is "recent," meaning that this
36
51
  # session is the first session in which the client has been notified
37
52
  # of this message.
53
+ #
54
+ # This flag was defined by
55
+ # IMAP4rev1 [RFC-3501](https://www.rfc-editor.org/rfc/rfc3501.html),
56
+ # and has been deprecated by
57
+ # IMAP4rev2 [RFC-9051](https://www.rfc-editor.org/rfc/rfc9051.html).
38
58
  RECENT = :Recent
39
59
 
40
- # :category: Mailbox Flags
60
+ # -------------------------------------------------------------------------
61
+ # :section: Mailbox Name Attributes, Base attributes
62
+ # Mailbox name attributes will be returned in LIST responses. Base
63
+ # attributes must be returned according to the server's capabilities.
41
64
  #
42
- # Flag indicating that a mailbox context name cannot contain
43
- # children.
44
- NOINFERIORS = :Noinferiors
65
+ # IMAP4 specifies that all mailbox name attributes, including future
66
+ # extensions, begin with "\". +Net::IMAP+ returns all mailbox attributes as
67
+ # symbols, without the "\" prefix.
68
+ #
69
+ # The descriptions here were copied from the IMAP4rev2 specification:
70
+ # [RFC9051 § 7.3.1](https://www.rfc-editor.org/rfc/rfc9051.html#section-7.3.1).
71
+ #
72
+ # Other mailbox name attributes can be found in the [IANA IMAP Mailbox Name
73
+ # Attributes registry](https://www.iana.org/assignments/imap-mailbox-name-attributes/imap-mailbox-name-attributes.xhtml)].
74
+ # -------------------------------------------------------------------------
75
+
76
+ # The "\NonExistent" attribute indicates that a mailbox name does not refer
77
+ # to an existing mailbox. Note that this attribute is not meaningful by
78
+ # itself, as mailbox names that match the canonical LIST pattern but don't
79
+ # exist must not be returned unless one of the two conditions listed below
80
+ # is also satisfied:
81
+ #
82
+ # 1. The mailbox name also satisfies the selection criteria (for example,
83
+ # it is subscribed and the "SUBSCRIBED" selection option has been
84
+ # specified).
85
+ #
86
+ # 2. "RECURSIVEMATCH" has been specified, and the mailbox name has at least
87
+ # one descendant mailbox name that does not match the LIST pattern and
88
+ # does match the selection criteria.
89
+ #
90
+ # In practice, this means that the "\NonExistent" attribute is usually
91
+ # returned with one or more of "\Subscribed", "\Remote", "\HasChildren", or
92
+ # the CHILDINFO extended data item.
93
+ #
94
+ # The client must treat the presence of the \NonExistent attribute as if the
95
+ # \NoSelect attribute was also sent by the server
96
+ NONEXISTENT = :NonExistent
45
97
 
46
- # :category: Mailbox Flags
98
+ # Mailbox attribute indicating it is not possible for any child levels of
99
+ # hierarchy to exist under this name; no child levels exist now and none can
100
+ # be created in the future children.
47
101
  #
48
- # Flag indicating that a mailbox is not selected.
102
+ # The client must treat the presence of the \NoInferiors attribute as if the
103
+ # \HasNoChildren attribute was also sent by the server
104
+ NOINFERIORS = :Noinferiors
105
+
106
+ # Mailbox attribute indicating it is not possible to use this name as a
107
+ # selectable mailbox.
49
108
  NOSELECT = :Noselect
50
109
 
51
- # :category: Mailbox Flags
110
+ # The presence of this attribute indicates that the mailbox has child
111
+ # mailboxes. A server SHOULD NOT set this attribute if there are child
112
+ # mailboxes and the user does not have permission to access any of them. In
113
+ # this case, \HasNoChildren SHOULD be used. In many cases, however, a server
114
+ # may not be able to efficiently compute whether a user has access to any
115
+ # child mailboxes. Note that even though the \HasChildren attribute for a
116
+ # mailbox must be correct at the time of processing the mailbox, a client
117
+ # must be prepared to deal with a situation when a mailbox is marked with
118
+ # the \HasChildren attribute, but no child mailbox appears in the response
119
+ # to the LIST command. This might happen, for example, due to child
120
+ # mailboxes being deleted or made inaccessible to the user (using access
121
+ # control) by another client before the server is able to list them.
122
+ #
123
+ # It is an error for the server to return both a \HasChildren and a
124
+ # \HasNoChildren attribute in the same LIST response. A client that
125
+ # encounters a LIST response with both \HasChildren and \HasNoChildren
126
+ # attributes present should act as if both are absent in the LIST response.
127
+ HAS_CHILDREN = :HasChildren
128
+
129
+ # The presence of this attribute indicates that the mailbox has NO child
130
+ # mailboxes that are accessible to the currently authenticated user.
52
131
  #
53
- # Flag indicating that a mailbox has been marked "interesting" by
54
- # the server; this commonly indicates that the mailbox contains
55
- # new messages.
132
+ # It is an error for the server to return both a \HasChildren and a
133
+ # \HasNoChildren attribute in the same LIST response. A client that
134
+ # encounters a LIST response with both \HasChildren and \HasNoChildren
135
+ # attributes present should act as if both are absent in the LIST response.
136
+ #
137
+ # Note: the \HasNoChildren attribute should not be confused with the
138
+ # \NoInferiors attribute, which indicates that no child mailboxes exist now
139
+ # and none can be created in the future.
140
+ HAS_NO_CHILDREN = :HasNoChildren
141
+
142
+ # The mailbox has been marked "interesting" by the server; the mailbox
143
+ # probably contains messages that have been added since the last time the
144
+ # mailbox was selected.
145
+ #
146
+ # If it is not feasible for the server to determine whether or not the
147
+ # mailbox is "interesting", the server SHOULD NOT send either \Marked or
148
+ # \Unmarked. The server MUST NOT send more than one of \Marked, \Unmarked,
149
+ # and \Noselect for a single mailbox, and it MAY send none of these.
56
150
  MARKED = :Marked
57
151
 
58
- # :category: Mailbox Flags
152
+ # The mailbox does not contain any additional messages since the last time
153
+ # the mailbox was selected.
59
154
  #
60
- # Flag indicating that the mailbox does not contains new messages.
155
+ # If it is not feasible for the server to determine whether or not the
156
+ # mailbox is "interesting", the server SHOULD NOT send either \Marked or
157
+ # \Unmarked. The server MUST NOT send more than one of \Marked, \Unmarked,
158
+ # and \Noselect for a single mailbox, and it MAY send none of these.
61
159
  UNMARKED = :Unmarked
62
160
 
63
- @@max_flag_count = 10000
161
+ # The mailbox name was subscribed to using the SUBSCRIBE command.
162
+ SUBSCRIBED = :Subscribed
163
+
164
+ # The mailbox is a remote mailbox.
165
+ REMOTE = :Remove
166
+
167
+ # -------------------------------------------------------------------------
168
+ # :section: Mailbox Name Attributes, Special Use
169
+ # Mailbox name attributes will be returned in LIST responses. In addition
170
+ # to the base mailbox name attributes defined above, an IMAP server MAY also
171
+ # include any or all of the following attributes that denote "role" (or
172
+ # "special-use") of a mailbox. These attributes are included along with base
173
+ # attributes defined above. A given mailbox may have none, one, or more than
174
+ # one of these attributes. In some cases, a special use is advice to a
175
+ # client about what to put in that mailbox. In other cases, it's advice to a
176
+ # client about what to expect to find there.
177
+ #
178
+ # IMAP4 specifies that all mailbox name attributes, including future
179
+ # extensions, begin with "\". +Net::IMAP+ returns all mailbox attributes as
180
+ # symbols, without the "\" prefix.
181
+ #
182
+ # The descriptions here were copied from the IMAP4rev2 specification:
183
+ # [RFC-9051 § 7.3.1](https://www.rfc-editor.org/rfc/rfc9051.html#section-7.3.1).
184
+ #
185
+ # Other mailbox name attributes can be found in the [IANA IMAP Mailbox Name
186
+ # Attributes registry](https://www.iana.org/assignments/imap-mailbox-name-attributes/imap-mailbox-name-attributes.xhtml)].
187
+ # -------------------------------------------------------------------------
188
+
189
+ # Mailbox attribute indicating that this mailbox presents all messages in
190
+ # the user's message store. Implementations MAY omit some messages, such as,
191
+ # perhaps, those in \Trash and \Junk. When this special use is supported, it
192
+ # is almost certain to represent a virtual mailbox
193
+ ALL = :All
194
+
195
+ # Mailbox attribute indicating that this mailbox is used to archive
196
+ # messages. The meaning of an "archival" mailbox is server dependent;
197
+ # typically, it will be used to get messages out of the inbox, or otherwise
198
+ # keep them out of the user's way, while still making them accessible
199
+ ARCHIVE = :Archive
200
+
201
+ # Mailbox attribute indicating that this mailbox is used to hold draft
202
+ # messages -- typically, messages that are being composed but have not yet
203
+ # been sent. In some server implementations, this might be a virtual
204
+ # mailbox, containing messages from other mailboxes that are marked with the
205
+ # "\Draft" message flag. Alternatively, this might just be advice that a
206
+ # client put drafts here
207
+ DRAFTS = :Drafts
208
+
209
+ # FLAGGED is defined with the system flags section.
210
+
211
+ # Mailbox attribute indicating that this mailbox is where messages deemed to
212
+ # be junk mail are held. Some server implementations might put messages here
213
+ # automatically. Alternatively, this might just be advice to a client-side
214
+ # spam filter.
215
+ JUNK = :Junk
64
216
 
65
- # Returns the max number of flags interned to symbols.
66
- def self.max_flag_count
67
- return @@max_flag_count
68
- end
217
+ # Mailbox attribute indicating that this mailbox is used to hold copies of
218
+ # messages that have been sent. Some server implementations might put
219
+ # messages here automatically. Alternatively, this might just be advice that
220
+ # a client save sent messages here.
221
+ SENT = :Sent
69
222
 
70
- # Sets the max number of flags interned to symbols.
71
- def self.max_flag_count=(count)
72
- @@max_flag_count = count
73
- end
223
+ # Mailbox attribute indicating that this mailbox is used to hold messages
224
+ # that have been deleted or marked for deletion. In some server
225
+ # implementations, this might be a virtual mailbox, containing messages from
226
+ # other mailboxes that are marked with the "\Deleted" message flag.
227
+ # Alternatively, this might just be advice that a client that chooses not to
228
+ # use the IMAP "\Deleted" model should use as its trash location. In server
229
+ # implementations that strictly expect the IMAP "\Deleted" model, this
230
+ # special use is likely not to be supported.
231
+ TRASH = :Trash
74
232
 
75
233
  end
76
234
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "errors"
4
+
3
5
  module Net
4
6
  class IMAP < Protocol
5
7
 
@@ -9,7 +11,6 @@ module Net
9
11
  @pos = nil
10
12
  @lex_state = nil
11
13
  @token = nil
12
- @flag_symbols = {}
13
14
  end
14
15
 
15
16
  def parse(str)
@@ -1212,12 +1213,7 @@ module Net
1212
1213
  if atom
1213
1214
  atom
1214
1215
  else
1215
- symbol = flag.capitalize.intern
1216
- @flag_symbols[symbol] = true
1217
- if @flag_symbols.length > IMAP.max_flag_count
1218
- raise FlagCountError, "number of flag symbols exceeded"
1219
- end
1220
- symbol
1216
+ flag.capitalize.intern
1221
1217
  end
1222
1218
  }
1223
1219
  else
data/lib/net/imap.rb CHANGED
@@ -13,7 +13,6 @@
13
13
  # See Net::IMAP for documentation.
14
14
  #
15
15
 
16
-
17
16
  require "socket"
18
17
  require "monitor"
19
18
  require 'net/protocol'
@@ -22,12 +21,6 @@ begin
22
21
  rescue LoadError
23
22
  end
24
23
 
25
- require_relative "imap/command_data"
26
- require_relative "imap/data_encoding"
27
- require_relative "imap/flags"
28
- require_relative "imap/response_data"
29
- require_relative "imap/response_parser"
30
-
31
24
  module Net
32
25
 
33
26
  #
@@ -227,7 +220,7 @@ module Net
227
220
  # Unicode", RFC-2152[https://tools.ietf.org/html/rfc2152], May 1997.
228
221
  #
229
222
  class IMAP < Protocol
230
- VERSION = "0.2.2"
223
+ VERSION = "0.3.0"
231
224
 
232
225
  include MonitorMixin
233
226
  if defined?(OpenSSL::SSL)
@@ -385,28 +378,37 @@ module Net
385
378
  # Sends an AUTHENTICATE command to authenticate the client.
386
379
  # The +auth_type+ parameter is a string that represents
387
380
  # the authentication mechanism to be used. Currently Net::IMAP
388
- # supports the authentication mechanisms:
389
- #
390
- # LOGIN:: login using cleartext user and password.
391
- # CRAM-MD5:: login with cleartext user and encrypted password
392
- # (see [RFC-2195] for a full description). This
393
- # mechanism requires that the server have the user's
394
- # password stored in clear-text password.
395
- #
396
- # For both of these mechanisms, there should be two +args+: username
397
- # and (cleartext) password. A server may not support one or the other
398
- # of these mechanisms; check #capability for a capability of
399
- # the form "AUTH=LOGIN" or "AUTH=CRAM-MD5".
400
- #
401
- # Authentication is done using the appropriate authenticator object:
402
- # see +add_authenticator+ for more information on plugging in your own
403
- # authenticator.
381
+ # supports the following mechanisms:
382
+ #
383
+ # PLAIN:: Login using cleartext user and password. Secure with TLS.
384
+ # See Net::IMAP::PlainAuthenticator.
385
+ # CRAM-MD5:: DEPRECATED: Use PLAIN (or DIGEST-MD5) with TLS.
386
+ # DIGEST-MD5:: DEPRECATED by RFC6331. Must be secured using TLS.
387
+ # See Net::IMAP::DigestMD5Authenticator.
388
+ # LOGIN:: DEPRECATED: Use PLAIN.
389
+ #
390
+ # Most mechanisms require two args: authentication identity (e.g. username)
391
+ # and credentials (e.g. a password). But each mechanism requires and allows
392
+ # different arguments; please consult the documentation for the specific
393
+ # mechanisms you are using. <em>Several obsolete mechanisms are available
394
+ # for backwards compatibility. Using deprecated mechanisms will issue
395
+ # warnings.</em>
396
+ #
397
+ # Servers do not support all mechanisms and clients must not attempt to use
398
+ # a mechanism unless "AUTH=#{mechanism}" is listed as a #capability.
399
+ # Clients must not attempt to authenticate or #login when +LOGINDISABLED+ is
400
+ # listed with the capabilities. Server capabilities, especially auth
401
+ # mechanisms, do change after calling #starttls so they need to be checked
402
+ # again.
404
403
  #
405
404
  # For example:
406
405
  #
407
- # imap.authenticate('LOGIN', user, password)
406
+ # imap.authenticate('PLAIN', user, password)
408
407
  #
409
408
  # A Net::IMAP::NoResponseError is raised if authentication fails.
409
+ #
410
+ # See +Net::IMAP::Authenticators+ for more information on plugging in your
411
+ # own authenticator.
410
412
  def authenticate(auth_type, *args)
411
413
  authenticator = self.class.authenticator(auth_type, *args)
412
414
  send_command("AUTHENTICATE", auth_type) do |resp|
@@ -1462,118 +1464,13 @@ module Net
1462
1464
  end
1463
1465
  end
1464
1466
 
1465
- # Common validators of number and nz_number types
1466
- module NumValidator # :nodoc
1467
- class << self
1468
- # Check is passed argument valid 'number' in RFC 3501 terminology
1469
- def valid_number?(num)
1470
- # [RFC 3501]
1471
- # number = 1*DIGIT
1472
- # ; Unsigned 32-bit integer
1473
- # ; (0 <= n < 4,294,967,296)
1474
- num >= 0 && num < 4294967296
1475
- end
1476
-
1477
- # Check is passed argument valid 'nz_number' in RFC 3501 terminology
1478
- def valid_nz_number?(num)
1479
- # [RFC 3501]
1480
- # nz-number = digit-nz *DIGIT
1481
- # ; Non-zero unsigned 32-bit integer
1482
- # ; (0 < n < 4,294,967,296)
1483
- num != 0 && valid_number?(num)
1484
- end
1485
-
1486
- # Check is passed argument valid 'mod_sequence_value' in RFC 4551 terminology
1487
- def valid_mod_sequence_value?(num)
1488
- # mod-sequence-value = 1*DIGIT
1489
- # ; Positive unsigned 64-bit integer
1490
- # ; (mod-sequence)
1491
- # ; (1 <= n < 18,446,744,073,709,551,615)
1492
- num >= 1 && num < 18446744073709551615
1493
- end
1494
-
1495
- # Ensure argument is 'number' or raise DataFormatError
1496
- def ensure_number(num)
1497
- return if valid_number?(num)
1498
-
1499
- msg = "number must be unsigned 32-bit integer: #{num}"
1500
- raise DataFormatError, msg
1501
- end
1502
-
1503
- # Ensure argument is 'nz_number' or raise DataFormatError
1504
- def ensure_nz_number(num)
1505
- return if valid_nz_number?(num)
1506
-
1507
- msg = "nz_number must be non-zero unsigned 32-bit integer: #{num}"
1508
- raise DataFormatError, msg
1509
- end
1510
-
1511
- # Ensure argument is 'mod_sequence_value' or raise DataFormatError
1512
- def ensure_mod_sequence_value(num)
1513
- return if valid_mod_sequence_value?(num)
1514
-
1515
- msg = "mod_sequence_value must be unsigned 64-bit integer: #{num}"
1516
- raise DataFormatError, msg
1517
- end
1518
- end
1519
- end
1520
-
1521
- # Superclass of IMAP errors.
1522
- class Error < StandardError
1523
- end
1524
-
1525
- # Error raised when data is in the incorrect format.
1526
- class DataFormatError < Error
1527
- end
1528
-
1529
- # Error raised when a response from the server is non-parseable.
1530
- class ResponseParseError < Error
1531
- end
1532
-
1533
- # Superclass of all errors used to encapsulate "fail" responses
1534
- # from the server.
1535
- class ResponseError < Error
1536
-
1537
- # The response that caused this error
1538
- attr_accessor :response
1539
-
1540
- def initialize(response)
1541
- @response = response
1542
-
1543
- super @response.data.text
1544
- end
1545
-
1546
- end
1547
-
1548
- # Error raised upon a "NO" response from the server, indicating
1549
- # that the client command could not be completed successfully.
1550
- class NoResponseError < ResponseError
1551
- end
1552
-
1553
- # Error raised upon a "BAD" response from the server, indicating
1554
- # that the client command violated the IMAP protocol, or an internal
1555
- # server failure has occurred.
1556
- class BadResponseError < ResponseError
1557
- end
1558
-
1559
- # Error raised upon a "BYE" response from the server, indicating
1560
- # that the client is not being allowed to login, or has been timed
1561
- # out due to inactivity.
1562
- class ByeResponseError < ResponseError
1563
- end
1564
-
1565
- # Error raised upon an unknown response from the server.
1566
- class UnknownResponseError < ResponseError
1567
- end
1568
-
1569
- RESPONSE_ERRORS = Hash.new(ResponseError)
1570
- RESPONSE_ERRORS["NO"] = NoResponseError
1571
- RESPONSE_ERRORS["BAD"] = BadResponseError
1572
-
1573
- # Error raised when too many flags are interned to symbols.
1574
- class FlagCountError < Error
1575
- end
1576
1467
  end
1577
1468
  end
1578
1469
 
1470
+ require_relative "imap/errors"
1471
+ require_relative "imap/command_data"
1472
+ require_relative "imap/data_encoding"
1473
+ require_relative "imap/flags"
1474
+ require_relative "imap/response_data"
1475
+ require_relative "imap/response_parser"
1579
1476
  require_relative "imap/authenticators"
data/net-imap.gemspec CHANGED
@@ -10,13 +10,13 @@ end
10
10
  Gem::Specification.new do |spec|
11
11
  spec.name = name
12
12
  spec.version = version
13
- spec.authors = ["Shugo Maeda"]
14
- spec.email = ["shugo@ruby-lang.org"]
13
+ spec.authors = ["Shugo Maeda", "nicholas a. evans"]
14
+ spec.email = ["shugo@ruby-lang.org", "nick@ekenosen.net"]
15
15
 
16
16
  spec.summary = %q{Ruby client api for Internet Message Access Protocol}
17
17
  spec.description = %q{Ruby client api for Internet Message Access Protocol}
18
18
  spec.homepage = "https://github.com/ruby/net-imap"
19
- spec.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
19
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.6.0")
20
20
  spec.licenses = ["Ruby", "BSD-2-Clause"]
21
21
 
22
22
  spec.metadata["homepage_uri"] = spec.homepage
@@ -25,13 +25,13 @@ Gem::Specification.new do |spec|
25
25
  # Specify which files should be added to the gem when it is released.
26
26
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
27
27
  spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
28
- `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
28
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(bin|test|spec|features)/}) }
29
29
  end
30
30
  spec.bindir = "exe"
31
31
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
32
32
  spec.require_paths = ["lib"]
33
33
 
34
34
  spec.add_dependency "net-protocol"
35
- spec.add_dependency "digest"
36
- spec.add_dependency "strscan"
35
+ spec.add_development_dependency "digest"
36
+ spec.add_development_dependency "strscan"
37
37
  end
metadata CHANGED
@@ -1,14 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: net-imap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shugo Maeda
8
+ - nicholas a. evans
8
9
  autorequire:
9
10
  bindir: exe
10
11
  cert_chain: []
11
- date: 2021-07-07 00:00:00.000000000 Z
12
+ date: 2022-09-28 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: net-protocol
@@ -31,7 +32,7 @@ dependencies:
31
32
  - - ">="
32
33
  - !ruby/object:Gem::Version
33
34
  version: '0'
34
- type: :runtime
35
+ type: :development
35
36
  prerelease: false
36
37
  version_requirements: !ruby/object:Gem::Requirement
37
38
  requirements:
@@ -45,7 +46,7 @@ dependencies:
45
46
  - - ">="
46
47
  - !ruby/object:Gem::Version
47
48
  version: '0'
48
- type: :runtime
49
+ type: :development
49
50
  prerelease: false
50
51
  version_requirements: !ruby/object:Gem::Requirement
51
52
  requirements:
@@ -55,18 +56,18 @@ dependencies:
55
56
  description: Ruby client api for Internet Message Access Protocol
56
57
  email:
57
58
  - shugo@ruby-lang.org
59
+ - nick@ekenosen.net
58
60
  executables: []
59
61
  extensions: []
60
62
  extra_rdoc_files: []
61
63
  files:
64
+ - ".github/dependabot.yml"
62
65
  - ".github/workflows/test.yml"
63
66
  - ".gitignore"
64
67
  - Gemfile
65
68
  - LICENSE.txt
66
69
  - README.md
67
70
  - Rakefile
68
- - bin/console
69
- - bin/setup
70
71
  - lib/net/imap.rb
71
72
  - lib/net/imap/authenticators.rb
72
73
  - lib/net/imap/authenticators/cram_md5.rb
@@ -75,6 +76,7 @@ files:
75
76
  - lib/net/imap/authenticators/plain.rb
76
77
  - lib/net/imap/command_data.rb
77
78
  - lib/net/imap/data_encoding.rb
79
+ - lib/net/imap/errors.rb
78
80
  - lib/net/imap/flags.rb
79
81
  - lib/net/imap/response_data.rb
80
82
  - lib/net/imap/response_parser.rb
@@ -94,14 +96,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
94
96
  requirements:
95
97
  - - ">="
96
98
  - !ruby/object:Gem::Version
97
- version: 2.5.0
99
+ version: 2.6.0
98
100
  required_rubygems_version: !ruby/object:Gem::Requirement
99
101
  requirements:
100
102
  - - ">="
101
103
  - !ruby/object:Gem::Version
102
104
  version: '0'
103
105
  requirements: []
104
- rubygems_version: 3.3.0.dev
106
+ rubygems_version: 3.4.0.dev
105
107
  signing_key:
106
108
  specification_version: 4
107
109
  summary: Ruby client api for Internet Message Access Protocol
data/bin/console DELETED
@@ -1,14 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require "bundler/setup"
4
- require "net/imap"
5
-
6
- # You can add fixtures and/or initialization code here to make experimenting
7
- # with your gem easier. You can also use a different console, if you like.
8
-
9
- # (If you use this, don't forget to add pry to your Gemfile!)
10
- # require "pry"
11
- # Pry.start
12
-
13
- require "irb"
14
- IRB.start(__FILE__)
data/bin/setup DELETED
@@ -1,8 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
- IFS=$'\n\t'
4
- set -vx
5
-
6
- bundle install
7
-
8
- # Do any other automated setup that you need to do here