rims 0.2.5 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -446,6 +446,14 @@ module RIMS::Test
446
446
  assert_equal(expected_value, @c.daemon_debug?)
447
447
  end
448
448
 
449
+ data('default' => [ 0037, {} ],
450
+ 'umask' => [ 0022, { daemon: { umask: 0022 } } ])
451
+ def test_daemon_umask(data)
452
+ expected_value, config = data
453
+ @c.load(config)
454
+ assert_equal(expected_value, @c.daemon_umask)
455
+ end
456
+
449
457
  data('default' => [ File.join(BASE_DIR, 'rims.pid'), {} ],
450
458
  'rel_path' => [ File.join(BASE_DIR, 'status'), { daemon: { status_file: 'status' } } ],
451
459
  'abs_path' => [ '/var/run/rims.pid', { daemon: { status_file: '/var/run/rims.pid' } } ])
@@ -709,6 +717,133 @@ module RIMS::Test
709
717
  assert_equal(expected_values, limits.to_h)
710
718
  end
711
719
 
720
+ data('default' => [ 1024 * 8, {} ],
721
+ 'config' => [ 1024 * 16, { protocol: { line_length_limit: 1024 * 16 } } ])
722
+ def test_protocol_line_length_limit(data)
723
+ expected_value, config = data
724
+ @c.load(config)
725
+ assert_equal(expected_value, @c.protocol_line_length_limit)
726
+ end
727
+
728
+ data('default' => [ 1024**2 * 10, {} ],
729
+ 'config' => [ 1024**2 * 16, { protocol: { literal_size_limit: 1024**2 * 16 } } ])
730
+ def test_protocol_literal_size_limit(data)
731
+ expected_value, config = data
732
+ @c.load(config)
733
+ assert_equal(expected_value, @c.protocol_literal_size_limit)
734
+ end
735
+
736
+ data('default' => [ 1024**2 * 10, {} ],
737
+ 'config' => [ 1024**2 * 16, { protocol: { command_size_limit: 1024**2 * 16 } } ])
738
+ def test_protocol_command_size_limit(data)
739
+ expected_value, config = data
740
+ @c.load(config)
741
+ assert_equal(expected_value, @c.protocol_command_size_limit)
742
+ end
743
+
744
+ data('default' => [ [ [ 'EUC-JP', Encoding::EUCJP_MS ],
745
+ [ 'ISO-2022-JP', Encoding::CP50221 ],
746
+ [ 'SHIFT_JIS', Encoding::WINDOWS_31J ]
747
+ ],
748
+ {}
749
+ ],
750
+ 'use_default_aliases:yes' => [ [ [ 'EUC-JP', Encoding::EUCJP_MS ],
751
+ [ 'ISO-2022-JP', Encoding::CP50221 ],
752
+ [ 'SHIFT_JIS', Encoding::WINDOWS_31J ]
753
+ ],
754
+ { charset: {
755
+ use_default_aliases: true
756
+ }
757
+ }
758
+ ],
759
+ 'use_default_aliases:no' => [ [],
760
+ { charset: {
761
+ use_default_aliases: false
762
+ }
763
+ }
764
+ ],
765
+ 'aliases' => [ [ [ 'EUC-JP', Encoding::EUCJP_MS ],
766
+ [ 'SHIFT_JIS', Encoding::WINDOWS_31J ]
767
+ ],
768
+ { charset: {
769
+ use_default_aliases: false,
770
+ aliases: [
771
+ { name: 'euc-jp', encoding: 'eucJP-ms' },
772
+ { name: 'Shift_JIS', encoding: 'Windows-31J' }
773
+ ]
774
+ }
775
+ }
776
+ ])
777
+ def test_charset_aliases(data)
778
+ expected_aliases, config = data
779
+ @c.load(config)
780
+ assert_equal(expected_aliases, @c.charset_aliases.to_a)
781
+ end
782
+
783
+ data('default' => [ { undef: :replace }, {} ],
784
+ 'replace_invalid_byte_sequence: true' => [ { invalid: :replace,
785
+ undef: :replace
786
+ },
787
+ { charset: {
788
+ convert_options: {
789
+ replace_invalid_byte_sequence: true
790
+ }
791
+ }
792
+ }
793
+ ],
794
+ 'replace_invalid_byte_sequence: false' => [ { undef: :replace },
795
+ { charset: {
796
+ convert_options: {
797
+ replace_invalid_byte_sequence: false
798
+ }
799
+ }
800
+ }
801
+ ],
802
+ 'replace_undefined_character: true' => [ { undef: :replace },
803
+ { charset: {
804
+ convert_options: {
805
+ replace_undefined_character: true
806
+ }
807
+ }
808
+ }
809
+ ],
810
+ 'replace_undefined_character: false' => [ {},
811
+ { charset: {
812
+ convert_options: {
813
+ replace_undefined_character: false
814
+ }
815
+ }
816
+ }
817
+ ],
818
+ 'replaced_mark' => [ { undef: :replace,
819
+ replace: "\uFFFD"
820
+ },
821
+ { charset: {
822
+ convert_options: {
823
+ replaced_mark: "\uFFFD"
824
+ }
825
+ }
826
+ }
827
+ ],
828
+ 'all' => [ { invalid: :replace,
829
+ undef: :replace,
830
+ replace: "\uFFFD"
831
+ },
832
+ { charset: {
833
+ convert_options: {
834
+ replace_invalid_byte_sequence: true,
835
+ replace_undefined_character: true,
836
+ replaced_mark: "\uFFFD"
837
+ }
838
+ }
839
+ }
840
+ ])
841
+ def test_charset_convert_options(data)
842
+ expected_options, config = data
843
+ @c.load(config)
844
+ assert_equal(expected_options, @c.charset_convert_options)
845
+ end
846
+
712
847
  data('default' => [ 0, {} ],
713
848
  'config' => [ 4,
714
849
  { drb_services: {
@@ -722,6 +857,21 @@ module RIMS::Test
722
857
  assert_equal(expected_value, @c.drb_process_num)
723
858
  end
724
859
 
860
+ data('default' => [ {}, {}, {} ],
861
+ 'load_limit' => [ { load_limit: 134217728 },
862
+ { load_limit: 134217728 },
863
+ { drb_services: {
864
+ load_limit: 134217728
865
+ }
866
+ }
867
+ ])
868
+ def test_drb_server_client_config(data)
869
+ expected_server_config, expected_client_config, config = data
870
+ @c.load(config)
871
+ assert_equal(expected_server_config, @c.drb_server_config)
872
+ assert_equal(expected_client_config, @c.drb_client_config)
873
+ end
874
+
725
875
  data('default' => [ 100, {} ],
726
876
  'config' => [ 1024,
727
877
  { drb_services: {
@@ -737,6 +887,21 @@ module RIMS::Test
737
887
  assert_equal(expected_value, @c.bulk_response_count)
738
888
  end
739
889
 
890
+ data('default' => [ 1024**2 * 10, {} ],
891
+ 'config' => [ 33554432,
892
+ { drb_services: {
893
+ engine: {
894
+ bulk_response_size: 33554432
895
+ }
896
+ }
897
+ }
898
+ ])
899
+ def test_bulk_response_size(data)
900
+ expected_value, config = data
901
+ @c.load(config)
902
+ assert_equal(expected_value, @c.bulk_response_size)
903
+ end
904
+
740
905
  data('default' => [ 30, {} ],
741
906
  'config' => [ 15,
742
907
  { drb_services: {
metadata CHANGED
@@ -1,29 +1,43 @@
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.3.0
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: 2020-08-28 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.2
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.2
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: riser
15
29
  requirement: !ruby/object:Gem::Requirement
16
30
  requirements:
17
31
  - - ">="
18
32
  - !ruby/object:Gem::Version
19
- version: 0.1.8
33
+ version: 0.2.0
20
34
  type: :runtime
21
35
  prerelease: false
22
36
  version_requirements: !ruby/object:Gem::Requirement
23
37
  requirements:
24
38
  - - ">="
25
39
  - !ruby/object:Gem::Version
26
- version: 0.1.8
40
+ version: 0.2.0
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: logger-joint
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -94,6 +108,20 @@ dependencies:
94
108
  - - ">="
95
109
  - !ruby/object:Gem::Version
96
110
  version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: irb
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
97
125
  description: |2
98
126
  RIMS is Ruby IMap Server.
99
127
  This gem provides a complete IMAP server by itself. The IMAP
@@ -107,6 +135,7 @@ extensions: []
107
135
  extra_rdoc_files: []
108
136
  files:
109
137
  - ".gitignore"
138
+ - CHANGELOG.md
110
139
  - ChangeLog
111
140
  - Gemfile
112
141
  - LICENSE.txt
@@ -130,7 +159,6 @@ files:
130
159
  - lib/rims/protocol/connection.rb
131
160
  - lib/rims/protocol/decoder.rb
132
161
  - lib/rims/protocol/parser.rb
133
- - lib/rims/rfc822.rb
134
162
  - lib/rims/service.rb
135
163
  - lib/rims/test.rb
136
164
  - lib/rims/version.rb
@@ -156,7 +184,6 @@ files:
156
184
  - test/test_protocol_fetch.rb
157
185
  - test/test_protocol_request.rb
158
186
  - test/test_protocol_search.rb
159
- - test/test_rfc822.rb
160
187
  - test/test_service.rb
161
188
  homepage: https://github.com/y10k/rims
162
189
  licenses:
@@ -177,7 +204,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
177
204
  - !ruby/object:Gem::Version
178
205
  version: '0'
179
206
  requirements: []
180
- rubygems_version: 3.0.3
207
+ rubygems_version: 3.1.2
181
208
  signing_key:
182
209
  specification_version: 4
183
210
  summary: RIMS is Ruby IMap Server
@@ -202,5 +229,4 @@ test_files:
202
229
  - test/test_protocol_fetch.rb
203
230
  - test/test_protocol_request.rb
204
231
  - test/test_protocol_search.rb
205
- - test/test_rfc822.rb
206
232
  - 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: