rims 0.2.5 → 0.2.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -952,6 +952,7 @@ Content-Type: text/html
952
952
  def test_parse_charset_text
953
953
  make_search_parser(charset: 'utf-8') {
954
954
  add_msg("Content-Type: text/plain\r\n" +
955
+ "\r\n" +
955
956
  "foo")
956
957
  add_msg("Content-Type: text/plain; charset=utf-8\r\n" +
957
958
  "X-foo: dummy\r\n" +
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rims
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.5
4
+ version: 0.2.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - TOKI Yoshinori
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-06-10 00:00:00.000000000 Z
11
+ date: 2019-07-08 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rims-rfc822
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 0.2.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 0.2.0
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: riser
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -130,7 +144,6 @@ files:
130
144
  - lib/rims/protocol/connection.rb
131
145
  - lib/rims/protocol/decoder.rb
132
146
  - lib/rims/protocol/parser.rb
133
- - lib/rims/rfc822.rb
134
147
  - lib/rims/service.rb
135
148
  - lib/rims/test.rb
136
149
  - lib/rims/version.rb
@@ -156,7 +169,6 @@ files:
156
169
  - test/test_protocol_fetch.rb
157
170
  - test/test_protocol_request.rb
158
171
  - test/test_protocol_search.rb
159
- - test/test_rfc822.rb
160
172
  - test/test_service.rb
161
173
  homepage: https://github.com/y10k/rims
162
174
  licenses:
@@ -202,5 +214,4 @@ test_files:
202
214
  - test/test_protocol_fetch.rb
203
215
  - test/test_protocol_request.rb
204
216
  - test/test_protocol_search.rb
205
- - test/test_rfc822.rb
206
217
  - test/test_service.rb
@@ -1,463 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
-
3
- require 'time'
4
-
5
- module RIMS
6
- module RFC822
7
- def split_message(msg_txt)
8
- header_txt, body_txt = msg_txt.lstrip.split(/\r?\n\r?\n/, 2)
9
- header_txt << $& if $&
10
- [ header_txt, body_txt ]
11
- end
12
- module_function :split_message
13
-
14
- def parse_header(header_txt)
15
- field_pair_list = header_txt.scan(%r{
16
- ^
17
- ((?#name) \S+? )
18
- \s* : \s*
19
- (
20
- (?#value)
21
- .*? (?: \n|\z)
22
- (?: ^\s .*? (?: \n|\z) )*
23
- )
24
- }x)
25
-
26
- for _name, value in field_pair_list
27
- value.strip!
28
- name.freeze
29
- value.freeze
30
- end
31
-
32
- field_pair_list.freeze
33
- end
34
- module_function :parse_header
35
-
36
- def parse_content_type(content_type_txt)
37
- src_txt = content_type_txt.dup
38
- if (src_txt.sub!(%r"\A \s* (?<main_type>\S+?) \s* / \s* (?<sub_type>\S+?) \s* (?:;|\Z)"x, '')) then
39
- main_type = $~[:main_type]
40
- sub_type = $~[:sub_type]
41
-
42
- params = {}
43
- src_txt.scan(%r'(?<name>\S+?) \s* = \s* (?: (?<quoted_string>".*?") | (?<token>\S+?) ) \s* (?:;|\Z)'x) do
44
- name = $~[:name]
45
- if ($~[:quoted_string]) then
46
- quoted_value = $~[:quoted_string]
47
- value = unquote_phrase(quoted_value)
48
- else
49
- value = $~[:token]
50
- end
51
- params[name.downcase] = [ name.freeze, value.freeze ].freeze
52
- end
53
-
54
- [ main_type.freeze, sub_type.freeze, params.freeze ].freeze
55
- else
56
- [ 'application'.freeze, 'octet-stream'.freeze, {}.freeze ].freeze
57
- end
58
- end
59
- module_function :parse_content_type
60
-
61
- def parse_multipart_body(boundary, body_txt)
62
- delim = '--' + boundary
63
- term = delim + '--'
64
- body_txt2, _body_epilogue_txt = body_txt.split(term, 2)
65
- if (body_txt2) then
66
- _body_preamble_txt, body_parts_txt = body_txt2.split(delim, 2)
67
- if (body_parts_txt) then
68
- part_list = body_parts_txt.split(delim, -1)
69
- for part_txt in part_list
70
- part_txt.lstrip!
71
- part_txt.chomp!("\n")
72
- part_txt.chomp!("\r")
73
- part_txt.freeze
74
- end
75
- return part_list.freeze
76
- end
77
- end
78
-
79
- [].freeze
80
- end
81
- module_function :parse_multipart_body
82
-
83
- def unquote_phrase(phrase_txt)
84
- state = :raw
85
- src_txt = phrase_txt.dup
86
- dst_txt = ''.encode(phrase_txt.encoding)
87
-
88
- while (src_txt.sub!(/\A(:? " | \( | \) | \\ | [^"\(\)\\]+ )/x, ''))
89
- match_txt = $&
90
- case (state)
91
- when :raw
92
- case (match_txt)
93
- when '"'
94
- state = :quote
95
- when '('
96
- state = :comment
97
- when "\\"
98
- src_txt.sub!(/\A./, '') and dst_txt << $&
99
- else
100
- dst_txt << match_txt
101
- end
102
- when :quote
103
- case (match_txt)
104
- when '"'
105
- state = :raw
106
- when "\\"
107
- src_txt.sub!(/\A./, '') && dst_txt << $&
108
- else
109
- dst_txt << match_txt
110
- end
111
- when :comment
112
- case (match_txt)
113
- when ')'
114
- state = :raw
115
- when "\\"
116
- src_txt.sub!(/\A./, '')
117
- else
118
- # ignore comment text.
119
- end
120
- else
121
- raise "internal error: unknown state #{state}"
122
- end
123
- end
124
-
125
- dst_txt.freeze
126
- end
127
- module_function :unquote_phrase
128
-
129
- def parse_mail_address_list(address_list_txt)
130
- addr_list = []
131
- src_txt = address_list_txt.dup
132
-
133
- while (true)
134
- if (src_txt.sub!(%r{
135
- \A
136
- \s*
137
- (?<display_name>\S.*?) \s* : (?<group_list>.*?) ;
138
- \s*
139
- ,?
140
- }x, ''))
141
- then
142
- display_name = $~[:display_name]
143
- group_list = $~[:group_list]
144
- addr_list << [ nil, nil, unquote_phrase(display_name), nil ].freeze
145
- addr_list.concat(parse_mail_address_list(group_list))
146
- addr_list << [ nil, nil, nil, nil ].freeze
147
- elsif (src_txt.sub!(%r{
148
- \A
149
- \s*
150
- (?<local_part>[^<>@",\s]+) \s* @ \s* (?<domain>[^<>@",\s]+)
151
- \s*
152
- ,?
153
- }x, ''))
154
- then
155
- addr_list << [ nil, nil, $~[:local_part].freeze, $~[:domain].freeze ].freeze
156
- elsif (src_txt.sub!(%r{
157
- \A
158
- \s*
159
- (?<display_name>\S.*?)
160
- \s*
161
- <
162
- \s*
163
- (?:
164
- (?<route>@[^<>@",]* (?:, \s* @[^<>@",]*)*)
165
- \s*
166
- :
167
- )?
168
- \s*
169
- (?<local_part>[^<>@",\s]+) \s* @ \s* (?<domain>[^<>@",\s]+)
170
- \s*
171
- >
172
- \s*
173
- ,?
174
- }x, ''))
175
- then
176
- display_name = $~[:display_name]
177
- route = $~[:route]
178
- local_part = $~[:local_part]
179
- domain = $~[:domain]
180
- addr_list << [ unquote_phrase(display_name), route.freeze, local_part.freeze, domain.freeze ].freeze
181
- else
182
- break
183
- end
184
- end
185
-
186
- addr_list.freeze
187
- end
188
- module_function :parse_mail_address_list
189
-
190
- class Header
191
- include Enumerable
192
-
193
- def initialize(header_txt)
194
- @raw_source = header_txt.freeze
195
- @field_list = nil
196
- @field_map = nil
197
- end
198
-
199
- attr_reader :raw_source
200
-
201
- def setup_header
202
- if (@field_list.nil? || @field_map.nil?) then
203
- @field_list = RFC822.parse_header(@raw_source)
204
- @field_map = {}
205
- for name, value in @field_list
206
- key = name.downcase
207
- @field_map[key] = [] unless (@field_map.key? key)
208
- @field_map[key] << value
209
- end
210
- @field_map.each_value do |value_list|
211
- value_list.freeze
212
- end
213
- @field_map.freeze
214
- self
215
- end
216
- end
217
- private :setup_header
218
-
219
- def each
220
- setup_header
221
- return enum_for(:each) unless block_given?
222
- for name, value in @field_list
223
- yield(name, value)
224
- end
225
- self
226
- end
227
-
228
- def key?(name)
229
- setup_header
230
- @field_map.key? name.downcase
231
- end
232
-
233
- def [](name)
234
- setup_header
235
- if (value_list = @field_map[name.downcase]) then
236
- value_list[0]
237
- end
238
- end
239
-
240
- def fetch_upcase(name)
241
- setup_header
242
- if (value_list = @field_map[name.downcase]) then
243
- if (value = value_list[0]) then
244
- value.upcase
245
- end
246
- end
247
- end
248
-
249
- def field_value_list(name)
250
- setup_header
251
- @field_map[name.downcase]
252
- end
253
- end
254
-
255
- class Body
256
- def initialize(body_txt)
257
- @raw_source = body_txt.freeze
258
- end
259
-
260
- attr_reader :raw_source
261
- end
262
-
263
- class Message
264
- def initialize(msg_txt)
265
- @raw_source = msg_txt.freeze
266
- @header = nil
267
- @body = nil
268
- @content_type = nil
269
- @is_multipart = nil
270
- @parts = nil
271
- @is_message = nil
272
- @message = nil
273
- @date = nil
274
- @from = nil
275
- @sender = nil
276
- @reply_to = nil
277
- @to = nil
278
- @cc = nil
279
- @bcc = nil
280
- end
281
-
282
- attr_reader :raw_source
283
-
284
- def setup_message
285
- if (@header.nil? || @body.nil?) then
286
- header_txt, body_txt = RFC822.split_message(@raw_source)
287
- @header = Header.new(header_txt || '')
288
- @body = Body.new(body_txt || '')
289
- self
290
- end
291
- end
292
- private :setup_message
293
-
294
- def header
295
- setup_message
296
- @header
297
- end
298
-
299
- def body
300
- setup_message
301
- @body
302
- end
303
-
304
- def setup_content_type
305
- if (@content_type.nil?) then
306
- @content_type = RFC822.parse_content_type(header['content-type'] || '')
307
- self
308
- end
309
- end
310
- private :setup_content_type
311
-
312
- def to_upper(text_or_nil)
313
- text_or_nil.upcase if text_or_nil
314
- end
315
- private :to_upper
316
-
317
- def media_main_type
318
- setup_content_type
319
- @content_type[0]
320
- end
321
-
322
- def media_main_type_upcase
323
- setup_content_type
324
- to_upper(@content_type[0])
325
- end
326
-
327
- def media_sub_type
328
- setup_content_type
329
- @content_type[1]
330
- end
331
-
332
- def media_sub_type_upcase
333
- setup_content_type
334
- to_upper(@content_type[1])
335
- end
336
-
337
- def content_type
338
- "#{media_main_type}/#{media_sub_type}"
339
- end
340
-
341
- def content_type_upcase
342
- to_upper("#{media_main_type}/#{media_sub_type}")
343
- end
344
-
345
- def content_type_parameters
346
- setup_content_type
347
- @content_type[2].each_value.map{|name, value| [ name, value ] }
348
- end
349
-
350
- def charset
351
- setup_content_type
352
- if (name_value_pair = @content_type[2]['charset']) then
353
- name_value_pair[1]
354
- end
355
- end
356
-
357
- def boundary
358
- setup_content_type
359
- if (name_value_pair = @content_type[2]['boundary']) then
360
- name_value_pair[1]
361
- end
362
- end
363
-
364
- def text?
365
- media_main_type_upcase == 'TEXT'
366
- end
367
-
368
- def multipart?
369
- if (@is_multipart.nil?) then
370
- @is_multipart = (media_main_type_upcase == 'MULTIPART')
371
- end
372
- @is_multipart
373
- end
374
-
375
- def parts
376
- if (multipart?) then
377
- if (@parts.nil?) then
378
- if (boundary = self.boundary) then
379
- part_list = RFC822.parse_multipart_body(boundary, body.raw_source)
380
- @parts = part_list.map{|msg_txt| Message.new(msg_txt) }.freeze
381
- else
382
- @parts = [].freeze
383
- end
384
- end
385
- @parts
386
- end
387
- end
388
-
389
- def message?
390
- if (@is_message.nil?) then
391
- @is_message = (media_main_type_upcase == 'MESSAGE')
392
- end
393
- @is_message
394
- end
395
-
396
- def message
397
- if (message?) then
398
- if (@message.nil?) then
399
- @message = Message.new(body.raw_source)
400
- end
401
- @message
402
- end
403
- end
404
-
405
- def date
406
- if (header.key? 'Date') then
407
- if (@date.nil?) then
408
- begin
409
- @date = Time.parse(header['Date'])
410
- rescue ArgumentError
411
- @date = Time.at(0)
412
- end
413
- end
414
-
415
- @date.freeze
416
- end
417
- end
418
-
419
- def mail_address_header_field(field_name)
420
- if (header.key? field_name) then
421
- ivar_name = '@' + field_name.downcase.gsub('-', '_')
422
- addr_list = instance_variable_get(ivar_name)
423
- if (addr_list.nil?) then
424
- addr_list = header.field_value_list(field_name).map{|addr_list_str| RFC822.parse_mail_address_list(addr_list_str) }.inject(:+)
425
- addr_list.freeze
426
- instance_variable_set(ivar_name, addr_list)
427
- end
428
- addr_list
429
- end
430
- end
431
- private :mail_address_header_field
432
-
433
- def from
434
- mail_address_header_field('from')
435
- end
436
-
437
- def sender
438
- mail_address_header_field('sender')
439
- end
440
-
441
- def reply_to
442
- mail_address_header_field('reply-to')
443
- end
444
-
445
- def to
446
- mail_address_header_field('to')
447
- end
448
-
449
- def cc
450
- mail_address_header_field('cc')
451
- end
452
-
453
- def bcc
454
- mail_address_header_field('bcc')
455
- end
456
- end
457
- end
458
- end
459
-
460
- # Local Variables:
461
- # mode: Ruby
462
- # indent-tabs-mode: nil
463
- # End: