net-imap 0.4.5 → 0.4.6

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: e4e6a6afb6888a5be474a97195f41e06a2e1706d9f65a0700f17bce7f6dd82af
4
- data.tar.gz: 3dd62a4e251d29e9e72e5538f548623662ed2ff16da46deadf8843585f8db658
3
+ metadata.gz: e9a3148dcf057ea22dbb67a976576ca59060038a8352fc1a71f3ec4cd928289b
4
+ data.tar.gz: 38e9bbc72d9d90bad28b24f47305d6376c6b17e41233af747bfd3cae27cdfc2e
5
5
  SHA512:
6
- metadata.gz: bc73faf474cb22965f3ec95bdae48d13514505d4072f0fe3ca47f1dbccc8b04aad404e90ecd2b04afa7dc401dc2f66d087fea316b26e46edf1403945e7e3c305
7
- data.tar.gz: 9c10a3b062c88f6145deb1adbbe3e8a2574e9f4dac39c2b7706fbc84643ee031891dae270197f910ceda3e5d0513f0929d574889e506c53a6f5048cb9be36dfa
6
+ metadata.gz: f5f9f4ade6c25741a402ea78c81928ab455c9b8c6bff5998ae884d567257cb823a16195aa148abc7d9215aa9d0bdce3632904e0f921f061174b04ccdfd4abf9c
7
+ data.tar.gz: 683fe61b95035387e6f651565174f6499a0f68e712287e904318f05e23fc24f195035a4c29eaeedbeb42a24401e7f2884f8e75af359d623daf098da402f8aaea
@@ -198,6 +198,7 @@ module Net
198
198
  # ; revisions of this specification.
199
199
  # flag-keyword = "$MDNSent" / "$Forwarded" / "$Junk" /
200
200
  # "$NotJunk" / "$Phishing" / atom
201
+ #
201
202
  # flag-perm = flag / "\*"
202
203
  #
203
204
  # Not checking for max one mbx-list-sflag in the parser.
@@ -220,19 +221,15 @@ module Net
220
221
  MBX_FLAG = FLAG_EXTENSION
221
222
 
222
223
  # flag-list = "(" [flag *(SP flag)] ")"
223
- #
224
- # part of resp-text-code:
225
- # >>>
226
- # "PERMANENTFLAGS" SP "(" [flag-perm *(SP flag-perm)] ")"
227
- #
228
- # parens from mailbox-list are included in the regexp:
229
- # >>>
230
- # mbx-list-flags = *(mbx-list-oflag SP) mbx-list-sflag
231
- # *(SP mbx-list-oflag) /
232
- # mbx-list-oflag *(SP mbx-list-oflag)
233
- FLAG_LIST = /\G\((#{FLAG }(?:#{SP}#{FLAG })*|)\)/ni
234
- FLAG_PERM_LIST = /\G\((#{FLAG_PERM}(?:#{SP}#{FLAG_PERM})*|)\)/ni
235
- MBX_LIST_FLAGS = /\G\((#{MBX_FLAG }(?:#{SP}#{MBX_FLAG })*|)\)/ni
224
+ # resp-text-code =/ "PERMANENTFLAGS" SP
225
+ # "(" [flag-perm *(SP flag-perm)] ")"
226
+ # mbx-list-flags = *(mbx-list-oflag SP) mbx-list-sflag
227
+ # *(SP mbx-list-oflag) /
228
+ # mbx-list-oflag *(SP mbx-list-oflag)
229
+ # (Not checking for max one mbx-list-sflag in the parser.)
230
+ FLAG_LIST = /\G\((#{FLAG }(?:#{SP}#{FLAG })*|)\)/ni
231
+ FLAG_PERM_LIST = /\G\((#{FLAG_PERM}(?:#{SP}#{FLAG_PERM})*|)\)/ni
232
+ MBX_LIST_FLAGS = /\G (#{MBX_FLAG }(?:#{SP}#{MBX_FLAG })*) /nix
236
233
 
237
234
  # RFC3501:
238
235
  # QUOTED-CHAR = <any TEXT-CHAR except quoted-specials> /
@@ -777,34 +774,47 @@ module Net
777
774
 
778
775
  # RFC3501 & RFC9051:
779
776
  # response-tagged = tag SP resp-cond-state CRLF
780
- #
781
- # resp-cond-state = ("OK" / "NO" / "BAD") SP resp-text
782
- # ; Status condition
783
- #
784
- # tag = 1*<any ASTRING-CHAR except "+">
785
777
  def response_tagged
786
- tag = tag(); SP!
787
- name = resp_cond_state__name; SP!
788
- TaggedResponse.new(tag, name, resp_text, @str)
778
+ TaggedResponse.new(tag, *(SP!; resp_cond_state), @str)
789
779
  end
790
780
 
791
781
  # RFC3501 & RFC9051:
792
782
  # resp-cond-state = ("OK" / "NO" / "BAD") SP resp-text
783
+ #
784
+ # NOTE: In the spirit of RFC9051 Appx E 23 (and to workaround existing
785
+ # servers), we don't require a final SP and instead parse this as:
786
+ #
787
+ # resp-cond-state = ("OK" / "NO" / "BAD") [SP resp-text]
788
+ def resp_cond_state
789
+ [resp_cond_state__name, SP? ? resp_text : ResponseText::EMPTY]
790
+ end
791
+
793
792
  def resp_cond_state__untagged
794
- name = resp_cond_state__name; SP!
795
- UntaggedResponse.new(name, resp_text, @str)
793
+ UntaggedResponse.new(*resp_cond_state, @str)
796
794
  end
797
795
 
798
796
  # resp-cond-auth = ("OK" / "PREAUTH") SP resp-text
797
+ #
798
+ # NOTE: In the spirit of RFC9051 Appx E 23 (and to workaround existing
799
+ # servers), we don't require a final SP and instead parse this as:
800
+ #
801
+ # resp-cond-auth = ("OK" / "PREAUTH") [SP resp-text]
799
802
  def resp_cond_auth
800
- name = resp_cond_auth__name; SP!
801
- UntaggedResponse.new(name, resp_text, @str)
803
+ UntaggedResponse.new(resp_cond_auth__name,
804
+ SP? ? resp_text : ResponseText::EMPTY,
805
+ @str)
802
806
  end
803
807
 
804
808
  # resp-cond-bye = "BYE" SP resp-text
809
+ #
810
+ # NOTE: In the spirit of RFC9051 Appx E 23 (and to workaround existing
811
+ # servers), we don't require a final SP and instead parse this as:
812
+ #
813
+ # resp-cond-bye = "BYE" [SP resp-text]
805
814
  def resp_cond_bye
806
- name = label(BYE); SP!
807
- UntaggedResponse.new(name, resp_text, @str)
815
+ UntaggedResponse.new(label(BYE),
816
+ SP? ? resp_text : ResponseText::EMPTY,
817
+ @str)
808
818
  end
809
819
 
810
820
  # message-data = nz-number SP ("EXPUNGE" / ("FETCH" SP msg-att))
@@ -928,41 +938,57 @@ module Net
928
938
  # this represents the partial size for BODY or BINARY
929
939
  alias gt__number__lt atom
930
940
 
941
+ # RFC3501 & RFC9051:
942
+ # envelope = "(" env-date SP env-subject SP env-from SP
943
+ # env-sender SP env-reply-to SP env-to SP env-cc SP
944
+ # env-bcc SP env-in-reply-to SP env-message-id ")"
931
945
  def envelope
932
946
  @lex_state = EXPR_DATA
933
- token = lookahead
934
- if token.symbol == T_NIL
935
- shift_token
936
- result = nil
937
- else
938
- match(T_LPAR)
939
- date = nstring
940
- match(T_SPACE)
941
- subject = nstring
942
- match(T_SPACE)
943
- from = address_list
944
- match(T_SPACE)
945
- sender = address_list
946
- match(T_SPACE)
947
- reply_to = address_list
948
- match(T_SPACE)
949
- to = address_list
950
- match(T_SPACE)
951
- cc = address_list
952
- match(T_SPACE)
953
- bcc = address_list
954
- match(T_SPACE)
955
- in_reply_to = nstring
956
- match(T_SPACE)
957
- message_id = nstring
958
- match(T_RPAR)
959
- result = Envelope.new(date, subject, from, sender, reply_to,
960
- to, cc, bcc, in_reply_to, message_id)
961
- end
947
+ lpar; date = env_date
948
+ SP!; subject = env_subject
949
+ SP!; from = env_from
950
+ SP!; sender = env_sender
951
+ SP!; reply_to = env_reply_to
952
+ SP!; to = env_to
953
+ SP!; cc = env_cc
954
+ SP!; bcc = env_bcc
955
+ SP!; in_reply_to = env_in_reply_to
956
+ SP!; message_id = env_message_id
957
+ rpar
958
+ Envelope.new(date, subject, from, sender, reply_to,
959
+ to, cc, bcc, in_reply_to, message_id)
960
+ ensure
962
961
  @lex_state = EXPR_BEG
963
- return result
964
962
  end
965
963
 
964
+ # env-date = nstring
965
+ # env-subject = nstring
966
+ # env-in-reply-to = nstring
967
+ # env-message-id = nstring
968
+ alias env_date nstring
969
+ alias env_subject nstring
970
+ alias env_in_reply_to nstring
971
+ alias env_message_id nstring
972
+
973
+ # env-from = "(" 1*address ")" / nil
974
+ # env-sender = "(" 1*address ")" / nil
975
+ # env-reply-to = "(" 1*address ")" / nil
976
+ # env-to = "(" 1*address ")" / nil
977
+ # env-cc = "(" 1*address ")" / nil
978
+ # env-bcc = "(" 1*address ")" / nil
979
+ def nlist__address
980
+ return if NIL?
981
+ lpar; list = [address]; list << address until rpar?
982
+ list
983
+ end
984
+
985
+ alias env_from nlist__address
986
+ alias env_sender nlist__address
987
+ alias env_reply_to nlist__address
988
+ alias env_to nlist__address
989
+ alias env_cc nlist__address
990
+ alias env_bcc nlist__address
991
+
966
992
  # date-time = DQUOTE date-day-fixed "-" date-month "-" date-year
967
993
  # SP time SP zone DQUOTE
968
994
  alias date_time quoted
@@ -1321,18 +1347,17 @@ module Net
1321
1347
  alias mailbox_data__lsub mailbox_data__list
1322
1348
  alias mailbox_data__xlist mailbox_data__list
1323
1349
 
1350
+ # mailbox-list = "(" [mbx-list-flags] ")" SP
1351
+ # (DQUOTE QUOTED-CHAR DQUOTE / nil) SP mailbox
1352
+ # [SP mbox-list-extended]
1353
+ # ; This is the list information pointed to by the ABNF
1354
+ # ; item "mailbox-data", which is defined above
1324
1355
  def mailbox_list
1325
- attr = flag_list
1326
- match(T_SPACE)
1327
- token = match(T_QUOTED, T_NIL)
1328
- if token.symbol == T_NIL
1329
- delim = nil
1330
- else
1331
- delim = token.value
1332
- end
1333
- match(T_SPACE)
1334
- name = astring
1335
- return MailboxList.new(attr, delim, name)
1356
+ lpar; attr = peek_rpar? ? [] : mbx_list_flags; rpar
1357
+ SP!; delim = nquoted
1358
+ SP!; name = mailbox
1359
+ # TODO: mbox-list-extended
1360
+ MailboxList.new(attr, delim, name)
1336
1361
  end
1337
1362
 
1338
1363
  def getquota_response
@@ -1458,66 +1483,55 @@ module Net
1458
1483
  end
1459
1484
  alias sort_data mailbox_data__search
1460
1485
 
1486
+ # RFC5256: THREAD
1487
+ # thread-data = "THREAD" [SP 1*thread-list]
1461
1488
  def thread_data
1462
- token = match(T_ATOM)
1463
- name = token.value.upcase
1464
- token = lookahead
1465
-
1466
- if token.symbol == T_SPACE
1467
- threads = []
1468
-
1469
- while true
1470
- shift_token
1471
- token = lookahead
1472
-
1473
- case token.symbol
1474
- when T_LPAR
1475
- threads << thread_branch(token)
1476
- when T_CRLF
1477
- break
1478
- end
1479
- end
1480
- else
1481
- # no member
1482
- threads = []
1489
+ name = label("THREAD")
1490
+ threads = []
1491
+ if SP?
1492
+ threads << thread_list while lookahead_thread_list?
1483
1493
  end
1484
-
1485
- return UntaggedResponse.new(name, threads, @str)
1494
+ UntaggedResponse.new(name, threads, @str)
1486
1495
  end
1487
1496
 
1488
- def thread_branch(token)
1489
- rootmember = nil
1490
- lastmember = nil
1491
-
1492
- while true
1493
- shift_token # ignore first T_LPAR
1494
- token = lookahead
1497
+ alias lookahead_thread_list? lookahead_lpar?
1498
+ alias lookahead_thread_nested? lookahead_thread_list?
1495
1499
 
1496
- case token.symbol
1497
- when T_NUMBER
1498
- # new member
1499
- newmember = ThreadMember.new(number, [])
1500
- if rootmember.nil?
1501
- rootmember = newmember
1502
- else
1503
- lastmember.children << newmember
1504
- end
1505
- lastmember = newmember
1506
- when T_SPACE
1507
- # do nothing
1508
- when T_LPAR
1509
- if rootmember.nil?
1510
- # dummy member
1511
- lastmember = rootmember = ThreadMember.new(nil, [])
1512
- end
1500
+ # RFC5256: THREAD
1501
+ # thread-list = "(" (thread-members / thread-nested) ")"
1502
+ def thread_list
1503
+ lpar
1504
+ thread = if lookahead_thread_nested?
1505
+ ThreadMember.new(nil, thread_nested)
1506
+ else
1507
+ thread_members
1508
+ end
1509
+ rpar
1510
+ thread
1511
+ end
1513
1512
 
1514
- lastmember.children << thread_branch(token)
1515
- when T_RPAR
1516
- break
1513
+ # RFC5256: THREAD
1514
+ # thread-members = nz-number *(SP nz-number) [SP thread-nested]
1515
+ def thread_members
1516
+ members = []
1517
+ members << nz_number # thread root
1518
+ while SP?
1519
+ case lookahead!(T_NUMBER, T_LPAR).symbol
1520
+ when T_NUMBER then members << nz_number
1521
+ else nested = thread_nested; break
1517
1522
  end
1518
1523
  end
1524
+ members.reverse.inject(nested || []) {|subthreads, number|
1525
+ [ThreadMember.new(number, subthreads)]
1526
+ }.first
1527
+ end
1519
1528
 
1520
- return rootmember
1529
+ # RFC5256: THREAD
1530
+ # thread-nested = 2*thread-list
1531
+ def thread_nested
1532
+ nested = [thread_list, thread_list]
1533
+ while lookahead_thread_list? do nested << thread_list end
1534
+ nested
1521
1535
  end
1522
1536
 
1523
1537
  # mailbox-data =/ "STATUS" SP mailbox SP "(" [status-att-list] ")"
@@ -1864,61 +1878,40 @@ module Net
1864
1878
  UIDPlusData.new(validity, src_uids, dst_uids)
1865
1879
  end
1866
1880
 
1867
- def address_list
1868
- token = lookahead
1869
- if token.symbol == T_NIL
1870
- shift_token
1871
- return nil
1872
- else
1873
- result = []
1874
- match(T_LPAR)
1875
- while true
1876
- token = lookahead
1877
- case token.symbol
1878
- when T_RPAR
1879
- shift_token
1880
- break
1881
- when T_SPACE
1882
- shift_token
1883
- end
1884
- result.push(address)
1885
- end
1886
- return result
1887
- end
1888
- end
1889
-
1890
- ADDRESS_REGEXP = /\G\
1891
- (?# 1: NAME )(?:NIL|"((?:[^\x80-\xff\x00\r\n"\\]|\\["\\])*)") \
1892
- (?# 2: ROUTE )(?:NIL|"((?:[^\x80-\xff\x00\r\n"\\]|\\["\\])*)") \
1893
- (?# 3: MAILBOX )(?:NIL|"((?:[^\x80-\xff\x00\r\n"\\]|\\["\\])*)") \
1894
- (?# 4: HOST )(?:NIL|"((?:[^\x80-\xff\x00\r\n"\\]|\\["\\])*)")\
1895
- \)/ni
1896
-
1881
+ ADDRESS_REGEXP = /\G
1882
+ \( (?: NIL | #{Patterns::QUOTED_rev2} ) # 1: NAME
1883
+ \s (?: NIL | #{Patterns::QUOTED_rev2} ) # 2: ROUTE
1884
+ \s (?: NIL | #{Patterns::QUOTED_rev2} ) # 3: MAILBOX
1885
+ \s (?: NIL | #{Patterns::QUOTED_rev2} ) # 4: HOST
1886
+ \)
1887
+ /nix
1888
+
1889
+ # address = "(" addr-name SP addr-adl SP addr-mailbox SP
1890
+ # addr-host ")"
1891
+ # addr-adl = nstring
1892
+ # addr-host = nstring
1893
+ # addr-mailbox = nstring
1894
+ # addr-name = nstring
1897
1895
  def address
1898
- match(T_LPAR)
1899
- if @str.index(ADDRESS_REGEXP, @pos)
1900
- # address does not include literal.
1901
- @pos = $~.end(0)
1902
- name = $1
1903
- route = $2
1904
- mailbox = $3
1905
- host = $4
1906
- for s in [name, route, mailbox, host]
1907
- Patterns.unescape_quoted! s
1908
- end
1909
- else
1910
- name = nstring
1911
- match(T_SPACE)
1912
- route = nstring
1913
- match(T_SPACE)
1914
- mailbox = nstring
1915
- match(T_SPACE)
1916
- host = nstring
1917
- match(T_RPAR)
1896
+ if (match = accept_re(ADDRESS_REGEXP))
1897
+ # note that "NIL" isn't captured by the regexp
1898
+ name, route, mailbox, host = match.captures
1899
+ .map { Patterns.unescape_quoted _1 }
1900
+ else # address may include literals
1901
+ lpar; name = addr_name
1902
+ SP!; route = addr_adl
1903
+ SP!; mailbox = addr_mailbox
1904
+ SP!; host = addr_host
1905
+ rpar
1918
1906
  end
1919
- return Address.new(name, route, mailbox, host)
1907
+ Address.new(name, route, mailbox, host)
1920
1908
  end
1921
1909
 
1910
+ alias addr_adl nstring
1911
+ alias addr_host nstring
1912
+ alias addr_mailbox nstring
1913
+ alias addr_name nstring
1914
+
1922
1915
  # flag-list = "(" [flag *(SP flag)] ")"
1923
1916
  def flag_list
1924
1917
  match_re(Patterns::FLAG_LIST, "flag-list")[1]
@@ -1933,22 +1926,10 @@ module Net
1933
1926
  .map! { _1.start_with?("\\") ? _1[1..].capitalize.to_sym : _1 }
1934
1927
  end
1935
1928
 
1936
- # Not checking for max one mbx-list-sflag in the parser.
1937
- # >>>
1938
- # mbx-list-flags = *(mbx-list-oflag SP) mbx-list-sflag
1939
- # *(SP mbx-list-oflag) /
1940
- # mbx-list-oflag *(SP mbx-list-oflag)
1941
- # mbx-list-oflag = "\Noinferiors" / child-mbox-flag /
1942
- # "\Subscribed" / "\Remote" / flag-extension
1943
- # ; Other flags; multiple from this list are
1944
- # ; possible per LIST response, but each flag
1945
- # ; can only appear once per LIST response
1946
- # mbx-list-sflag = "\NonExistent" / "\Noselect" / "\Marked" /
1947
- # "\Unmarked"
1948
- # ; Selectability flags; only one per LIST response
1949
- def parens__mbx_list_flags
1929
+ # See Patterns::MBX_LIST_FLAGS
1930
+ def mbx_list_flags
1950
1931
  match_re(Patterns::MBX_LIST_FLAGS, "mbx-list-flags")[1]
1951
- .split(nil).map! { _1.capitalize.to_sym }
1932
+ .split(nil).map! { _1[1..].capitalize.to_sym }
1952
1933
  end
1953
1934
 
1954
1935
  # See https://developers.google.com/gmail/imap/imap-extensions
data/lib/net/imap.rb CHANGED
@@ -690,7 +690,7 @@ module Net
690
690
  # * {IMAP URLAUTH Authorization Mechanism Registry}[https://www.iana.org/assignments/urlauth-authorization-mechanism-registry/urlauth-authorization-mechanism-registry.xhtml]
691
691
  #
692
692
  class IMAP < Protocol
693
- VERSION = "0.4.5"
693
+ VERSION = "0.4.6"
694
694
 
695
695
  # Aliases for supported capabilities, to be used with the #enable command.
696
696
  ENABLE_ALIASES = {
@@ -1692,13 +1692,14 @@ module Net
1692
1692
  # and returns the status of the indicated +mailbox+. +attr+ is a list of one
1693
1693
  # or more attributes whose statuses are to be requested.
1694
1694
  #
1695
- # The return value is a hash of attributes.
1695
+ # The return value is a hash of attributes. Most status attributes return
1696
+ # integer values, but some return other value types (documented below).
1696
1697
  #
1697
1698
  # A Net::IMAP::NoResponseError is raised if status values
1698
1699
  # for +mailbox+ cannot be returned; for instance, because it
1699
1700
  # does not exist.
1700
1701
  #
1701
- # ===== Supported attributes:
1702
+ # ===== Supported attributes
1702
1703
  #
1703
1704
  # +MESSAGES+:: The number of messages in the mailbox.
1704
1705
  #
@@ -1715,7 +1716,7 @@ module Net
1715
1716
  # the sum of all messages' +RFC822.SIZE+ fetch item values.
1716
1717
  #
1717
1718
  # +MAILBOXID+::
1718
- # A server-allocated unique identifier for the mailbox.
1719
+ # A server-allocated unique _string_ identifier for the mailbox.
1719
1720
  # See +OBJECTID+
1720
1721
  # {[RFC8474]}[https://www.rfc-editor.org/rfc/rfc8474.html#section-4].
1721
1722
  #
@@ -1723,6 +1724,9 @@ module Net
1723
1724
  # The number of messages with the <tt>\Recent</tt> flag.
1724
1725
  # _NOTE:_ +RECENT+ was removed from IMAP4rev2.
1725
1726
  #
1727
+ # Unsupported attributes may be requested. The attribute value will be
1728
+ # either an Integer or an ExtensionData object.
1729
+ #
1726
1730
  # ===== For example:
1727
1731
  #
1728
1732
  # p imap.status("inbox", ["MESSAGES", "RECENT"])
@@ -1734,6 +1738,8 @@ module Net
1734
1738
  # <tt>STATUS=SIZE</tt>
1735
1739
  # {[RFC8483]}[https://www.rfc-editor.org/rfc/rfc8483.html].
1736
1740
  #
1741
+ # +DELETED+ requires the server's capabilities to include +IMAP4rev2+.
1742
+ #
1737
1743
  # +MAILBOXID+ requires the server's capabilities to include +OBJECTID+
1738
1744
  # {[RFC8474]}[https://www.rfc-editor.org/rfc/rfc8474.html].
1739
1745
  def status(mailbox, attr)
@@ -42,7 +42,7 @@ file "benchmarks/parser.yml" => PARSER_TEST_FIXTURES do |t|
42
42
 
43
43
  benchmarks = tests.map {|fixture_name, response|
44
44
  {"name" => fixture_name.delete_prefix("test_"),
45
- "prelude" => "response = %s" % [response.dump],
45
+ "prelude" => "response = -%s.b" % [response.dump],
46
46
  "script" => "parser.parse(response)"}
47
47
  }
48
48
  .sort_by { _1["name"] }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: net-imap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.5
4
+ version: 0.4.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shugo Maeda
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2023-11-13 00:00:00.000000000 Z
12
+ date: 2023-11-21 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: net-protocol
@@ -148,7 +148,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
148
148
  - !ruby/object:Gem::Version
149
149
  version: '0'
150
150
  requirements: []
151
- rubygems_version: 3.4.10
151
+ rubygems_version: 3.4.22
152
152
  signing_key:
153
153
  specification_version: 4
154
154
  summary: Ruby client api for Internet Message Access Protocol