1require "net/imap"
2require "test/unit"
3
4class IMAPResponseParserTest < Test::Unit::TestCase
5  def setup
6    @do_not_reverse_lookup = Socket.do_not_reverse_lookup
7    Socket.do_not_reverse_lookup = true
8    if Net::IMAP.respond_to?(:max_flag_count)
9      @max_flag_count = Net::IMAP.max_flag_count
10      Net::IMAP.max_flag_count = 3
11    end
12  end
13
14  def teardown
15    Socket.do_not_reverse_lookup = @do_not_reverse_lookup
16    if Net::IMAP.respond_to?(:max_flag_count)
17      Net::IMAP.max_flag_count = @max_flag_count
18    end
19  end
20
21  def test_flag_list_safe
22    parser = Net::IMAP::ResponseParser.new
23    response = lambda {
24      $SAFE = 1
25      parser.parse(<<EOF.gsub(/\n/, "\r\n").taint)
26* LIST (\\HasChildren) "." "INBOX"
27EOF
28    }.call
29    assert_equal [:Haschildren], response.data.attr
30  end
31
32  def test_flag_list_too_many_flags
33    parser = Net::IMAP::ResponseParser.new
34    assert_nothing_raised do
35      3.times do |i|
36      parser.parse(<<EOF.gsub(/\n/, "\r\n").taint)
37* LIST (\\Foo#{i}) "." "INBOX"
38EOF
39      end
40    end
41    assert_raise(Net::IMAP::FlagCountError) do
42      parser.parse(<<EOF.gsub(/\n/, "\r\n").taint)
43* LIST (\\Foo3) "." "INBOX"
44EOF
45    end
46  end
47
48  def test_flag_list_many_same_flags
49    parser = Net::IMAP::ResponseParser.new
50    assert_nothing_raised do
51      100.times do
52      parser.parse(<<EOF.gsub(/\n/, "\r\n").taint)
53* LIST (\\Foo) "." "INBOX"
54EOF
55      end
56    end
57  end
58
59  def test_flag_xlist_inbox
60    parser = Net::IMAP::ResponseParser.new
61	response = parser.parse(<<EOF.gsub(/\n/, "\r\n").taint)
62* XLIST (\\Inbox) "." "INBOX"
63EOF
64    assert_equal [:Inbox], response.data.attr
65  end
66
67  def test_resp_text_code
68    parser = Net::IMAP::ResponseParser.new
69    response = parser.parse(<<EOF.gsub(/\n/, "\r\n").taint)
70* OK [CLOSED] Previous mailbox closed.
71EOF
72    assert_equal "CLOSED", response.data.code.name
73  end
74
75  def test_search_response
76    parser = Net::IMAP::ResponseParser.new
77    response = parser.parse(<<EOF.gsub(/\n/, "\r\n").taint)
78* SEARCH
79EOF
80    assert_equal [], response.data
81    response = parser.parse(<<EOF.gsub(/\n/, "\r\n").taint)
82* SEARCH 1
83EOF
84    assert_equal [1], response.data
85    response = parser.parse(<<EOF.gsub(/\n/, "\r\n").taint)
86* SEARCH 1 2 3
87EOF
88    assert_equal [1, 2, 3], response.data
89  end
90
91  def test_search_response_of_yahoo
92    parser = Net::IMAP::ResponseParser.new
93    response = parser.parse(<<EOF.gsub(/\n/, "\r\n").taint)
94* SEARCH 1\s
95EOF
96    assert_equal [1], response.data
97    response = parser.parse(<<EOF.gsub(/\n/, "\r\n").taint)
98* SEARCH 1 2 3\s
99EOF
100    assert_equal [1, 2, 3], response.data
101  end
102
103  def test_msg_att_extra_space
104    parser = Net::IMAP::ResponseParser.new
105    response = parser.parse(<<EOF.gsub(/\n/, "\r\n").taint)
106* 1 FETCH (UID 92285)
107EOF
108    assert_equal 92285, response.data.attr["UID"]
109
110    response = parser.parse(<<EOF.gsub(/\n/, "\r\n").taint)
111* 1 FETCH (UID 92285 )
112EOF
113    assert_equal 92285, response.data.attr["UID"]
114
115    response = parser.parse(<<EOF.gsub(/\n/, "\r\n").taint)
116* 1 FETCH (UID 92285  )
117EOF
118  end
119
120  def test_msg_att_parse_error
121    parser = Net::IMAP::ResponseParser.new
122    e = assert_raise(Net::IMAP::ResponseParseError) {
123      response = parser.parse(<<EOF.gsub(/\n/, "\r\n").taint)
124* 123 FETCH (UNKNOWN 92285)
125EOF
126    }
127    assert_match(/ for \{123\}/, e.message)
128  end
129
130  def test_msg_att_rfc822_text
131    parser = Net::IMAP::ResponseParser.new
132    response = parser.parse(<<EOF.gsub(/\n/, "\r\n").taint)
133* 123 FETCH (RFC822 {5}
134foo
135)
136EOF
137    assert_equal("foo\r\n", response.data.attr["RFC822"])
138    response = parser.parse(<<EOF.gsub(/\n/, "\r\n").taint)
139* 123 FETCH (RFC822[] {5}
140foo
141)
142EOF
143    assert_equal("foo\r\n", response.data.attr["RFC822"])
144  end
145
146  # [Bug #6397] [ruby-core:44849]
147  def test_body_type_attachment
148    parser = Net::IMAP::ResponseParser.new
149    response = parser.parse(<<EOF.gsub(/\n/, "\r\n").taint)
150* 980 FETCH (UID 2862 BODYSTRUCTURE ((("TEXT" "PLAIN" ("CHARSET" "iso-8859-1") NIL NIL "7BIT" 416 21 NIL NIL NIL)("TEXT" "HTML" ("CHARSET" "iso-8859-1") NIL NIL "7BIT" 1493 32 NIL NIL NIL) "ALTERNATIVE" ("BOUNDARY" "Boundary_(ID_IaecgfnXwG5bn3x8lIeGIQ)") NIL NIL)("MESSAGE" "RFC822" ("NAME" "Fw_ ____ _____ ____.eml") NIL NIL "7BIT" 1980088 NIL ("ATTACHMENT" ("FILENAME" "Fw_ ____ _____ ____.eml")) NIL) "MIXED" ("BOUNDARY" "Boundary_(ID_eDdLc/j0mBIzIlR191pHjA)") NIL NIL))
151EOF
152    assert_equal("Fw_ ____ _____ ____.eml",
153      response.data.attr["BODYSTRUCTURE"].parts[1].body.param["FILENAME"])
154  end
155
156  def assert_parseable(s)
157    parser = Net::IMAP::ResponseParser.new
158    parser.parse(s.gsub(/\n/, "\r\n").taint)
159  end
160
161  # [Bug #7146]
162  def test_msg_delivery_status
163    # This was part of a larger response that caused crashes, but this was the
164    # minimal test case to demonstrate it
165    assert_parseable <<EOF
166* 4902 FETCH (BODY (("MESSAGE" "DELIVERY-STATUS" NIL NIL NIL "7BIT" 324) "REPORT"))
167EOF
168  end
169
170  # [Bug #7147]
171  def test_msg_with_message_rfc822_attachment
172    assert_parseable <<EOF
173* 5441 FETCH (BODY ((("TEXT" "PLAIN" ("CHARSET" "iso-8859-1") NIL NIL "QUOTED-PRINTABLE" 69 1)("TEXT" "HTML" ("CHARSET" "iso-8859-1") NIL NIL "QUOTED-PRINTABLE" 455 12) "ALTERNATIVE")("MESSAGE" "RFC822" ("NAME" "ATT00026.eml") NIL NIL "7BIT" 4079755) "MIXED"))
174EOF
175  end
176
177  # [Bug #7153]
178  def test_msg_body_mixed
179    assert_parseable <<EOF
180* 1038 FETCH (BODY ("MIXED"))
181EOF
182  end
183
184  # [Bug #8281]
185  def test_acl
186    parser = Net::IMAP::ResponseParser.new
187    response = parser.parse(<<EOF.gsub(/\n/, "\r\n").taint)
188* ACL "INBOX/share" "imshare2copy1366146467@xxxxxxxxxxxxxxxxxx.com" lrswickxteda
189EOF
190    assert_equal("ACL", response.name)
191    assert_equal(1, response.data.length)
192    assert_equal("INBOX/share", response.data[0].mailbox)
193    assert_equal("imshare2copy1366146467@xxxxxxxxxxxxxxxxxx.com",
194                 response.data[0].user)
195    assert_equal("lrswickxteda", response.data[0].rights)
196  end
197
198  # [Bug #8415]
199  def test_capability
200    parser = Net::IMAP::ResponseParser.new
201    response = parser.parse("* CAPABILITY st11p00mm-iscream009 1Q49 XAPPLEPUSHSERVICE IMAP4 IMAP4rev1 SASL-IR AUTH=ATOKEN AUTH=PLAIN\r\n")
202    assert_equal("CAPABILITY", response.name)
203    assert_equal("AUTH=PLAIN", response.data.last)
204    response = parser.parse("* CAPABILITY st11p00mm-iscream009 1Q49 XAPPLEPUSHSERVICE IMAP4 IMAP4rev1 SASL-IR AUTH=ATOKEN AUTH=PLAIN \r\n")
205    assert_equal("CAPABILITY", response.name)
206    assert_equal("AUTH=PLAIN", response.data.last)
207  end
208end
209