rims 0.2.5 → 0.2.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: 7acc91008294ca9589a19ecb657d5a04cc9d21c17e6349e059dd371bba0f4dbb
4
- data.tar.gz: f750c5ef8ea6064033d1b6e1e0329964db61e56f1e9e1535883a19fcb1738aa3
3
+ metadata.gz: 5f51adf08f317981cdec3bb1067edd7a6c4befcf2f3e3e9c3ab4ac97702dad80
4
+ data.tar.gz: d0089e4150ad0768b0267c3c34980fad6a5251f0953997bd75a8c00e590120bb
5
5
  SHA512:
6
- metadata.gz: 003c20745f575ba8801f6b72956b42b3329f45fc84f70fe68146767fae15a657f9a3cb1767f759877e8cf442738873a05182c835d697c702e4fad7a575b560d3
7
- data.tar.gz: 449554fe7059796dd4fbbce1c433b7abc2a411ad5ee24acccc0618bb1043e2fb6b9a006dc0e93eb5c32813409a80b2bb677c37e39437e819153c38233cbaa194
6
+ metadata.gz: 4be9394ccaa4e2081dcc4040f197f375444b04953706c050aad5b1e255121cfec2d49753f31160f0dc458dcac139296b37c5efe0685f749904e5a0d74c705b24
7
+ data.tar.gz: a1a1a3f16b3069b2fd0e2ee9016349fbb2bb43401220ed9d00beec44914b4ef0206582c41a2bfb94c895d91ea6eb62ba76dcdd342338aa5becb8670777a3343a
data/ChangeLog CHANGED
@@ -1,3 +1,63 @@
1
+ 2019-07-08 TOKI Yoshinori <toki@freedom.ne.jp>
2
+
3
+ * lib/rims/cmd.rb: disable plug-in name list on plug-in command
4
+ options.
5
+
6
+ * lib/rims/cmd.rb: environment command is defined.
7
+
8
+ 2019-07-02 TOKI Yoshinori <toki@freedom.ne.jp>
9
+
10
+ * lib/rims/protocol/decoder.rb: ALERT message notified to client
11
+ immediately.
12
+
13
+ 2019-07-01 TOKI Yoshinori <toki@freedom.ne.jp>
14
+
15
+ * lib/rims/protocol/decoder.rb, lib/rims/protocol/parser.rb: skip
16
+ encoding error on SEARCH command.
17
+
18
+ * lib/rims/protocol/decoder.rb: BADCHARSET response code for
19
+ unknown charset on SERCH command.
20
+
21
+ See RFC 3501 / 6.4.4. SEARCH Command
22
+ <https://tools.ietf.org/html/rfc3501#section-6.4.4>
23
+
24
+ If the server does not support the specified [CHARSET], it MUST
25
+ return a tagged NO response (not a BAD). This response SHOULD
26
+ contain the BADCHARSET response code, which MAY list the
27
+ [CHARSET]s supported by the server.
28
+
29
+ 2019-06-29 TOKI Yoshinori <toki@freedom.ne.jp>
30
+
31
+ * lib/rims/protocol/decoder.rb: line break before error response
32
+ interrupting search command.
33
+
34
+ 2019-06-25 TOKI Yoshinori <toki@freedom.ne.jp>
35
+
36
+ * lib/rims/protocol/parser.rb: delete unnecessary private methods.
37
+
38
+ 2019-06-23 TOKI Yoshinori <toki@freedom.ne.jp>
39
+
40
+ * lib/rims/protocol/parser.rb: add extension data to
41
+ bodystructure.
42
+
43
+ 2019-06-21 TOKI Yoshinori <toki@freedom.ne.jp>
44
+
45
+ * lib/rims/rfc822.rb, rims.gemspec, test/test_rfc822.rb: repladced
46
+ `RIMS::RFC822' to a external rubygem.
47
+
48
+ 2019-06-15 TOKI Yoshinori <toki@freedom.ne.jp>
49
+
50
+ * lib/rims/protocol/parser.rb: not allowed empty body field
51
+ parameters at attribute parser.
52
+
53
+ when body field parameters are empty, a command to fetch
54
+ `bodystructure' should response `NIL' instead of `()'.
55
+
56
+ see RFC 3501 / 9. Formal Syntax:
57
+ <https://tools.ietf.org/html/rfc3501#section-9>
58
+
59
+ body-fld-param = "(" string SP string *(SP string SP string) ")" / nil
60
+
1
61
  2019-06-10 TOKI Yoshinori <toki@freedom.ne.jp>
2
62
 
3
63
  * RIMS version 0.2.5 is released.
@@ -1,13 +1,10 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
3
  require 'json'
4
- require 'logger'
5
4
  require 'net/imap'
6
5
  require 'optparse'
7
6
  require 'pp'if $DEBUG
8
7
  require 'riser'
9
- require 'syslog'
10
- require 'syslog/logger'
11
8
  require 'yaml'
12
9
 
13
10
  OptionParser.accept(JSON) do |json_data, *_|
@@ -61,7 +58,7 @@ module RIMS
61
58
  puts "commands:"
62
59
  w = CMDs.keys.map{|k| k.length }.max + 4
63
60
  fmt = " %- #{w}s%s"
64
- CMDs.each do |cmd_name, cmd_entry|
61
+ CMDs.sort_by{|cmd_name, _| cmd_name }.each do |cmd_name, cmd_entry|
65
62
  if ((! show_debug_command) && (cmd_name =~ /\A debug/x)) then
66
63
  next
67
64
  end
@@ -519,13 +516,7 @@ module RIMS
519
516
  end
520
517
  options.on('--meta-kvs-type=TYPE',
521
518
  KeyValueStore::FactoryBuilder.plug_in_names,
522
- "Choose key-value store type of mailbox meta-data database" +
523
- if (KeyValueStore::FactoryBuilder.plug_in_names.length > 1) then
524
- ' (' + KeyValueStore::FactoryBuilder.plug_in_names.join(' ') + ')'
525
- else
526
- ''
527
- end +
528
- ". default is `" +
519
+ "Choose key-value store type of mailbox meta-data database. default is `" +
529
520
  KeyValueStore::FactoryBuilder.plug_in_names[0] +
530
521
  "'."
531
522
  ) do |kvs_type|
@@ -568,13 +559,7 @@ module RIMS
568
559
  end
569
560
  options.on('--text-kvs-type=TYPE',
570
561
  KeyValueStore::FactoryBuilder.plug_in_names,
571
- "Choose key-value store type of mailbox text-data database" +
572
- if (KeyValueStore::FactoryBuilder.plug_in_names.length > 1) then
573
- ' (' + KeyValueStore::FactoryBuilder.plug_in_names.join(' ') + ')'
574
- else
575
- ''
576
- end +
577
- ". default is `" +
562
+ "Choose key-value store type of mailbox text-data database. default is `" +
578
563
  KeyValueStore::FactoryBuilder.plug_in_names[0] +
579
564
  "'."
580
565
  ) do |kvs_type|
@@ -627,7 +612,7 @@ module RIMS
627
612
  end
628
613
  options.on('--passwd-config=TYPE_JSONDATA',
629
614
  /([^:]+)(?::(.*))?/,
630
- "Password source type (#{Authentication.plug_in_names.join(',')}) and configuration. format is `[type]:[json_data]'."
615
+ "Password source type and configuration. format is `[type]:[json_data]'."
631
616
  ) do |_, type, json_data|
632
617
  build.chain{|c|
633
618
  c.load(authentication: {
@@ -641,7 +626,7 @@ module RIMS
641
626
  end
642
627
  options.on('--passwd-file=TYPE_FILE',
643
628
  /([^:]+):(.+)/,
644
- "Password source type (#{Authentication.plug_in_names.join(',')}) and configuration file. format is `[type]:[file]'."
629
+ "Password source type and configuration file. format is `[type]:[file]'."
645
630
  ) do |_, type, path|
646
631
  build.chain{|c|
647
632
  c.load(authentication: {
@@ -907,14 +892,7 @@ module RIMS
907
892
  def key_value_store_option
908
893
  @conf[:key_value_store_type] = GDBM_KeyValueStore
909
894
  @options.on('--kvs-type=TYPE',
910
- KeyValueStore::FactoryBuilder.plug_in_names,
911
- "Choose key-value store type of mailbox database" +
912
- if (KeyValueStore::FactoryBuilder.plug_in_names.length > 1) then
913
- ' (' + KeyValueStore::FactoryBuilder.plug_in_names.join(' ') + ')'
914
- else
915
- ''
916
- end +
917
- ". default is `" +
895
+ "Choose key-value store type of mailbox database. default is `" +
918
896
  KeyValueStore::FactoryBuilder.plug_in_names[0] +
919
897
  "'."
920
898
  ) do |kvs_type|
@@ -1145,6 +1123,44 @@ module RIMS
1145
1123
  end
1146
1124
  command_function :cmd_daemon, "Daemon start/stop/status tool."
1147
1125
 
1126
+ def cmd_environment(options, args)
1127
+ format = {
1128
+ yaml: lambda{|env|
1129
+ YAML.dump(env)
1130
+ },
1131
+ json: lambda{|env|
1132
+ JSON.pretty_generate(env)
1133
+ }
1134
+ }
1135
+
1136
+ conf = Config.new(options,
1137
+ [ [ :format_type,
1138
+ format.keys.first,
1139
+ '--format=FORMAT',
1140
+ format.keys,
1141
+ "Choose display format (#{format.keys.join(' ')})."
1142
+ ]
1143
+ ])
1144
+ conf.required_feature_option
1145
+ conf.setup_option_list
1146
+ conf.parse_options!(args)
1147
+
1148
+ env = {
1149
+ 'RIMS Environment' => [
1150
+ { 'RUBY VERSION' => RUBY_DESCRIPTION },
1151
+ { 'RIMS VERSION' => RIMS::VERSION },
1152
+ { 'AUTHENTICATION PLUG-IN' => Authentication.plug_in_names },
1153
+ { 'KEY-VALUE STORE PLUG-IN' => KeyValueStore::FactoryBuilder.plug_in_names }
1154
+ ]
1155
+ }
1156
+
1157
+ formatter = format[conf[:format_type]]
1158
+ puts formatter.call(env)
1159
+
1160
+ 0
1161
+ end
1162
+ command_function :cmd_environment, 'Show rims environment.'
1163
+
1148
1164
  def imap_append(imap, mailbox, message, store_flags: [], date_time: nil, verbose: false)
1149
1165
  puts "message date: #{date_time}" if (verbose && date_time)
1150
1166
  store_flags = nil if store_flags.empty?
@@ -26,9 +26,13 @@ module RIMS
26
26
  output_write = lambda{|res|
27
27
  last_line = nil
28
28
  for data in res
29
- logger.debug("response data: #{Protocol.io_data_log(data)}") if logger.debug?
30
- output << data
31
- last_line = data
29
+ if (data == :flush) then
30
+ output.flush
31
+ else
32
+ logger.debug("response data: #{Protocol.io_data_log(data)}") if logger.debug?
33
+ output << data
34
+ last_line = data
35
+ end
32
36
  end
33
37
  output.flush
34
38
 
@@ -252,13 +256,13 @@ module RIMS
252
256
  end
253
257
  private :imap_command
254
258
 
255
- def make_engine_and_recovery_if_needed(services, username,
259
+ def make_engine_and_recovery_if_needed(drb_services, username,
256
260
  logger: Logger.new(STDOUT))
257
261
  unique_user_id = Authentication.unique_user_id(username)
258
262
  logger.debug("unique user ID: #{username} -> #{unique_user_id}") if logger.debug?
259
263
 
260
264
  logger.info("open mail store: #{unique_user_id} [ #{username} ]")
261
- engine = services[:engine, unique_user_id]
265
+ engine = drb_services[:engine, unique_user_id]
262
266
 
263
267
  begin
264
268
  engine.recovery_if_needed(username) {|msg| yield(msg) }
@@ -321,10 +325,10 @@ module RIMS
321
325
  private :imap_command
322
326
  end
323
327
 
324
- def initialize(services, auth, logger,
328
+ def initialize(drb_services, auth, logger,
325
329
  mail_delivery_user: Service::DEFAULT_CONFIG.mail_delivery_user)
326
330
  super(auth, logger)
327
- @services = services
331
+ @drb_services = drb_services
328
332
  @mail_delivery_user = mail_delivery_user
329
333
  end
330
334
 
@@ -360,9 +364,9 @@ module RIMS
360
364
  case (username)
361
365
  when @mail_delivery_user
362
366
  @logger.info("mail delivery user: #{username}")
363
- MailDeliveryDecoder.new(self, @services, @auth, @logger)
367
+ MailDeliveryDecoder.new(self, @drb_services, @auth, @logger)
364
368
  else
365
- engine = self.class.make_engine_and_recovery_if_needed(@services, username, logger: @logger) {|msg| yield(msg) }
369
+ engine = self.class.make_engine_and_recovery_if_needed(@drb_services, username, logger: @logger) {|msg| yield(msg) }
366
370
  UserMailboxDecoder.new(self, engine, @auth, @logger)
367
371
  end
368
372
  end
@@ -375,7 +379,7 @@ module RIMS
375
379
  if (username != :*) then
376
380
  yield response_stream(tag) {|res|
377
381
  @logger.info("authentication OK: #{username}")
378
- @next_decoder = accept_authentication(username) {|msg| res << msg }
382
+ @next_decoder = accept_authentication(username) {|msg| res << msg << :flush }
379
383
  res << "#{tag} OK AUTHENTICATE #{auth_type} success\r\n"
380
384
  }
381
385
  else
@@ -392,7 +396,7 @@ module RIMS
392
396
  if (@auth.authenticate_login(username, password)) then
393
397
  yield response_stream(tag) {|res|
394
398
  @logger.info("login authentication OK: #{username}")
395
- @next_decoder = accept_authentication(username) {|msg| res << msg }
399
+ @next_decoder = accept_authentication(username) {|msg| res << msg << :flush }
396
400
  res << "#{tag} OK LOGIN completed\r\n"
397
401
  }
398
402
  else
@@ -1242,7 +1246,12 @@ module RIMS
1242
1246
  cond_args.shift
1243
1247
  charset_string = cond_args.shift or raise SyntaxError, 'need for a charset string of CHARSET'
1244
1248
  charset_string.is_a? String or raise SyntaxError, "CHARSET charset string expected as <String> but was <#{charset_string.class}>."
1245
- parser.charset = charset_string
1249
+ begin
1250
+ parser.charset = charset_string
1251
+ rescue ArgumentError
1252
+ @logger.warn("unknown charset: #{charset_string}")
1253
+ return yield([ "#{tag} NO [BADCHARSET (#{Encoding.list.map(&:to_s).join(' ')})] unknown charset\r\n" ])
1254
+ end
1246
1255
  end
1247
1256
 
1248
1257
  if (cond_args.empty?) then
@@ -1278,21 +1287,36 @@ module RIMS
1278
1287
  }
1279
1288
 
1280
1289
  res << '* SEARCH'
1281
- for msg in msg_src
1282
- if (cond.call(msg)) then
1283
- if (uid) then
1284
- res << " #{msg.uid}"
1285
- else
1286
- res << " #{msg.num}"
1287
- end
1288
- if (res.length >= @bulk_response_count) then
1289
- yield(res)
1290
- res = []
1290
+ begin
1291
+ begin
1292
+ for msg in msg_src
1293
+ begin
1294
+ if (cond.call(msg)) then
1295
+ if (uid) then
1296
+ res << " #{msg.uid}"
1297
+ else
1298
+ res << " #{msg.num}"
1299
+ end
1300
+ if (res.length >= @bulk_response_count) then
1301
+ yield(res)
1302
+ res = []
1303
+ end
1304
+ end
1305
+ rescue EncodingError
1306
+ @logger.warn("encoding error at the message: uidvalidity(#{folder.mbox_id}) uid(#{msg.uid})")
1307
+ @logger.warn("#{$!} (#{$!.class})")
1308
+ end
1291
1309
  end
1310
+ ensure
1311
+ res << "\r\n"
1292
1312
  end
1313
+ rescue
1314
+ # flush bulk response
1315
+ yield(res)
1316
+ res = []
1317
+ raise
1293
1318
  end
1294
1319
 
1295
- res << "\r\n"
1296
1320
  res << "#{tag} OK SEARCH completed\r\n"
1297
1321
  yield(res)
1298
1322
  end
@@ -1756,10 +1780,10 @@ module RIMS
1756
1780
  end
1757
1781
 
1758
1782
  class MailDeliveryDecoder < AuthenticatedDecoder
1759
- def initialize(parent_decoder, services, auth, logger)
1783
+ def initialize(parent_decoder, drb_services, auth, logger)
1760
1784
  super(auth, logger)
1761
1785
  @parent_decoder = parent_decoder
1762
- @services = services
1786
+ @drb_services = drb_services
1763
1787
  @auth = auth
1764
1788
  @last_user_cache_key_username = nil
1765
1789
  @last_user_cache_value_engine = nil
@@ -1802,7 +1826,7 @@ module RIMS
1802
1826
  private :release_engine_cache
1803
1827
 
1804
1828
  def auth?
1805
- @services != nil
1829
+ @drb_services != nil
1806
1830
  end
1807
1831
 
1808
1832
  def selected?
@@ -1811,7 +1835,7 @@ module RIMS
1811
1835
 
1812
1836
  def cleanup
1813
1837
  release_engine_cache
1814
- @services = nil unless @services.nil?
1838
+ @drb_services = nil unless @drb_services.nil?
1815
1839
  @auth = nil unless @auth.nil?
1816
1840
 
1817
1841
  unless (@parent_decoder.nil?) then
@@ -1924,9 +1948,9 @@ module RIMS
1924
1948
  engine = engine_cache(username)
1925
1949
  deliver_to_user(tag, username, mbox_name, opt_args, msg_text, engine, res)
1926
1950
  else
1927
- res = Enumerator.new{|stream_res|
1951
+ res = response_stream(tag) {|stream_res|
1928
1952
  engine = store_engine_cache(username) {
1929
- self.class.make_engine_and_recovery_if_needed(@services, username, logger: @logger) {|msg| stream_res << msg }
1953
+ self.class.make_engine_and_recovery_if_needed(@drb_services, username, logger: @logger) {|msg| stream_res << msg << :flush }
1930
1954
  }
1931
1955
  deliver_to_user(tag, username, mbox_name, opt_args, msg_text, engine, stream_res)
1932
1956
  }
@@ -244,8 +244,21 @@ module RIMS
244
244
  end
245
245
  private :get_mail
246
246
 
247
- attr_accessor :charset
247
+ attr_reader :charset
248
248
 
249
+ def charset=(new_charset)
250
+ @charset = Encoding.find(new_charset)
251
+ end
252
+
253
+ def force_string_charset(string)
254
+ string = string.dup
255
+ string.force_encoding(@charset)
256
+ string.valid_encoding? or raise SyntaxError, "invalid #{@charset} string: #{string.inspect}"
257
+ string
258
+ end
259
+ private :force_string_charset
260
+
261
+ # should set `search_string' encoding to `@charset'
249
262
  def string_include?(search_string, text)
250
263
  if (search_string.ascii_only?) then
251
264
  unless (text.encoding.ascii_compatible?) then
@@ -253,7 +266,6 @@ module RIMS
253
266
  end
254
267
  else
255
268
  if (@charset) then
256
- search_string = search_string.dup.force_encoding(@charset)
257
269
  text = text.encode(@charset)
258
270
  end
259
271
  end
@@ -266,7 +278,7 @@ module RIMS
266
278
  if (mail.text? || mail.message?) then
267
279
  body_txt = mail.body.raw_source
268
280
  if (charset = mail.charset) then
269
- if (body_txt.encoding != Encoding.find(charset)) then
281
+ if (body_txt.encoding != charset) then
270
282
  body_txt = body_txt.dup.force_encoding(charset)
271
283
  end
272
284
  end
@@ -310,6 +322,7 @@ module RIMS
310
322
  private :parse_msg_flag_enabled
311
323
 
312
324
  def parse_search_header(field_name, search_string)
325
+ search_string = force_string_charset(search_string) if @charset
313
326
  proc{|next_cond|
314
327
  proc{|msg|
315
328
  mail = get_mail(msg)
@@ -359,6 +372,7 @@ module RIMS
359
372
  private :parse_mail_bytesize
360
373
 
361
374
  def parse_body(search_string)
375
+ search_string = force_string_charset(search_string) if @charset
362
376
  proc{|next_cond|
363
377
  proc{|msg|
364
378
  if (text = mail_body_text(get_mail(msg))) then
@@ -421,6 +435,7 @@ module RIMS
421
435
  private :parse_or
422
436
 
423
437
  def parse_text(search_string)
438
+ search_string = force_string_charset(search_string) if @charset
424
439
  search_text = proc{|message_text| string_include?(search_string, message_text) }
425
440
  search_mail = proc{|mail|
426
441
  if (mail.multipart?) then
@@ -690,14 +705,10 @@ module RIMS
690
705
  if ((array.length > 0) && (array.first.is_a? Array)) then
691
706
  s = '('.b
692
707
  array = array.dup
693
- while (object = array.shift)
694
- case (object)
695
- when Array
696
- s << encode_bodystructure(object)
697
- else
698
- s << ' '.b << encode_value(object)
699
- end
700
- end
708
+ begin
709
+ s << encode_bodystructure(array.shift)
710
+ end while ((array.length > 0) && (array.first.is_a? Array))
711
+ s << ' '.b << array.map{|i| encode_value(i) }.join(' '.b)
701
712
  s << ')'.b
702
713
  elsif ((array.length > 0) && (array.first.upcase == 'MESSAGE')) then
703
714
  msg_body_list = array[0..7].map{|v| encode_value(v) }
@@ -760,7 +771,6 @@ module RIMS
760
771
  def initialize(mail_store, folder)
761
772
  @mail_store = mail_store
762
773
  @folder = folder
763
- @charset = nil
764
774
  @mail_cache = Hash.new{|hash, uid|
765
775
  if (msg_txt = @mail_store.msg_text(@folder.mbox_id, uid)) then
766
776
  hash[uid] = RFC822::Message.new(msg_txt)
@@ -773,29 +783,6 @@ module RIMS
773
783
  end
774
784
  private :get_mail
775
785
 
776
- def make_array(value)
777
- if (value) then
778
- if (value.is_a? Array) then
779
- list = value
780
- else
781
- list = [ value ]
782
- end
783
-
784
- if (block_given?) then
785
- yield(list)
786
- else
787
- list
788
- end
789
- end
790
- end
791
- private :make_array
792
-
793
- def make_address_list(email_address)
794
- mailbox, host = email_address.split(/@/, 2)
795
- [ nil, nil, mailbox, host ]
796
- end
797
- private :make_address_list
798
-
799
786
  def expand_macro(cmd_list)
800
787
  func_list = cmd_list.map{|name| parse_cached(name) }
801
788
  proc{|msg|
@@ -804,76 +791,116 @@ module RIMS
804
791
  end
805
792
  private :expand_macro
806
793
 
807
- def get_header_field(mail, name, default=nil)
808
- if (field = mail[name]) then
809
- if (block_given?) then
810
- yield(field)
811
- else
812
- field
813
- end
794
+ def make_body_params(name_value_pair_list)
795
+ if (name_value_pair_list && ! name_value_pair_list.empty?) then
796
+ name_value_pair_list.flatten
797
+ else
798
+ # not allowed empty body field parameters.
799
+ # RFC 3501 / 9. Formal Syntax:
800
+ # body-fld-param = "(" string SP string *(SP string SP string) ")" / nil
801
+ nil
802
+ end
803
+ end
804
+ private :make_body_params
805
+
806
+ def get_body_disposition(mail)
807
+ if (disposition_type = mail.content_disposition_upcase) then
808
+ [ disposition_type,
809
+ make_body_params(mail.content_disposition_parameter_list)
810
+ ]
814
811
  else
815
- default
812
+ # not allowed empty body field disposition.
813
+ # RFC 3501 / 9. Formal Syntax:
814
+ # body-fld-dsp = "(" string SP body-fld-param ")" / nil
815
+ nil
816
816
  end
817
817
  end
818
- private :get_header_field
818
+ private :get_body_disposition
819
819
 
820
- def get_bodystructure_data(mail)
820
+ def get_body_lang(mail)
821
+ if (tag_list = mail.content_language_upcase) then
822
+ unless (tag_list.empty?) then
823
+ if (tag_list.length == 1) then
824
+ tag_list[0]
825
+ else
826
+ tag_list
827
+ end
828
+ end
829
+ end
830
+ end
831
+ private :get_body_lang
832
+
833
+ def get_bodystructure_data(mail, extension: false)
834
+ body_data = []
821
835
  if (mail.multipart?) then # body_type_mpart
822
- mpart_data = []
823
- mpart_data.concat(mail.parts.map{|part_msg| get_bodystructure_data(part_msg) })
824
- mpart_data << mail.media_sub_type_upcase
825
- elsif (mail.text?) then # body_type_text
826
- text_data = []
827
-
828
- # media_text
829
- text_data << mail.media_main_type_upcase
830
- text_data << mail.media_sub_type_upcase
831
-
832
- # body_fields
833
- text_data << mail.content_type_parameters.flatten
834
- text_data << mail.header['Content-Id']
835
- text_data << mail.header['Content-Description']
836
- text_data << mail.header.fetch_upcase('Content-Transfer-Encoding')
837
- text_data << mail.raw_source.bytesize
838
-
839
- # body_fld_lines
840
- text_data << mail.raw_source.each_line.count
841
- elsif (mail.message?) then # body_type_msg
842
- msg_data = []
843
-
844
- # message_media
845
- msg_data << mail.media_main_type_upcase
846
- msg_data << mail.media_sub_type_upcase
847
-
848
- # body_fields
849
- msg_data << mail.content_type_parameters.flatten
850
- msg_data << mail.header['Content-Id']
851
- msg_data << mail.header['Content-Description']
852
- msg_data << mail.header.fetch_upcase('Content-Transfer-Encoding')
853
- msg_data << mail.raw_source.bytesize
854
-
855
- # envelope
856
- msg_data << get_envelope_data(mail.message)
857
-
858
- # body
859
- msg_data << get_bodystructure_data(mail.message)
860
-
861
- # body_fld_lines
862
- msg_data << mail.raw_source.each_line.count
863
- else # body_type_basic
864
- basic_data = []
865
-
866
- # media_basic
867
- basic_data << mail.media_main_type_upcase
868
- basic_data << mail.media_sub_type_upcase
869
-
870
- # body_fields
871
- basic_data << mail.content_type_parameters.flatten
872
- basic_data << mail.header['Content-Id']
873
- basic_data << mail.header['Content-Description']
874
- basic_data << mail.header.fetch_upcase('Content-Transfer-Encoding')
875
- basic_data << mail.raw_source.bytesize
836
+ body_data.concat(mail.parts.map{|part_msg| get_bodystructure_data(part_msg, extension: extension) })
837
+ body_data << mail.media_sub_type_upcase
838
+
839
+ # body_ext_mpart
840
+ if (extension) then
841
+ body_data << make_body_params(mail.content_type_parameter_list)
842
+ body_data << get_body_disposition(mail)
843
+ body_data << get_body_lang(mail)
844
+ body_data << mail.header['Content-Location']
845
+ end
846
+ else
847
+ if (mail.text?) then # body_type_text
848
+ # media_text
849
+ body_data << mail.media_main_type_upcase
850
+ body_data << mail.media_sub_type_upcase
851
+
852
+ # body_fields
853
+ body_data << make_body_params(mail.content_type_parameter_list)
854
+ body_data << mail.header['Content-Id']
855
+ body_data << mail.header['Content-Description']
856
+ body_data << mail.header.fetch_upcase('Content-Transfer-Encoding')
857
+ body_data << mail.raw_source.bytesize
858
+
859
+ # body_fld_lines
860
+ body_data << mail.raw_source.each_line.count
861
+ elsif (mail.message?) then # body_type_msg
862
+ # message_media
863
+ body_data << mail.media_main_type_upcase
864
+ body_data << mail.media_sub_type_upcase
865
+
866
+ # body_fields
867
+ body_data << make_body_params(mail.content_type_parameter_list)
868
+ body_data << mail.header['Content-Id']
869
+ body_data << mail.header['Content-Description']
870
+ body_data << mail.header.fetch_upcase('Content-Transfer-Encoding')
871
+ body_data << mail.raw_source.bytesize
872
+
873
+ # envelope
874
+ body_data << get_envelope_data(mail.message)
875
+
876
+ # body
877
+ body_data << get_bodystructure_data(mail.message, extension: extension)
878
+
879
+ # body_fld_lines
880
+ body_data << mail.raw_source.each_line.count
881
+ else # body_type_basic
882
+ # media_basic
883
+ body_data << mail.media_main_type_upcase
884
+ body_data << mail.media_sub_type_upcase
885
+
886
+ # body_fields
887
+ body_data << make_body_params(mail.content_type_parameter_list)
888
+ body_data << mail.header['Content-Id']
889
+ body_data << mail.header['Content-Description']
890
+ body_data << mail.header.fetch_upcase('Content-Transfer-Encoding')
891
+ body_data << mail.raw_source.bytesize
892
+ end
893
+
894
+ # body_ext_1part
895
+ if (extension) then
896
+ body_data << mail.header['Content-MD5']
897
+ body_data << get_body_disposition(mail)
898
+ body_data << get_body_lang(mail)
899
+ body_data << mail.header['Content-Location']
900
+ end
876
901
  end
902
+
903
+ body_data
877
904
  end
878
905
  private :get_bodystructure_data
879
906
 
@@ -881,12 +908,12 @@ module RIMS
881
908
  env_data = []
882
909
  env_data << mail.header['Date']
883
910
  env_data << mail.header['Subject']
884
- env_data << mail.from
885
- env_data << mail.sender
886
- env_data << mail.reply_to
887
- env_data << mail.to
888
- env_data << mail.cc
889
- env_data << mail.bcc
911
+ env_data << mail.from&.map(&:to_a)
912
+ env_data << mail.sender&.map(&:to_a)
913
+ env_data << mail.reply_to&.map(&:to_a)
914
+ env_data << mail.to&.map(&:to_a)
915
+ env_data << mail.cc&.map(&:to_a)
916
+ env_data << mail.bcc&.map(&:to_a)
890
917
  env_data << mail.header['In-Reply-To']
891
918
  env_data << mail.header['Message-Id']
892
919
  end
@@ -1034,9 +1061,9 @@ module RIMS
1034
1061
  end
1035
1062
  private :parse_body
1036
1063
 
1037
- def parse_bodystructure(msg_att_name)
1064
+ def parse_bodystructure(msg_att_name, extension: false)
1038
1065
  proc{|msg|
1039
- ''.b << msg_att_name << ' '.b << encode_bodystructure(get_bodystructure_data(get_mail(msg)))
1066
+ ''.b << msg_att_name << ' '.b << encode_bodystructure(get_bodystructure_data(get_mail(msg), extension: extension))
1040
1067
  }
1041
1068
  end
1042
1069
  private :parse_bodystructure
@@ -1095,9 +1122,9 @@ module RIMS
1095
1122
  when 'ALL'
1096
1123
  fetch = expand_macro(%w[ FLAGS INTERNALDATE RFC822.SIZE ENVELOPE ])
1097
1124
  when 'BODY'
1098
- fetch = parse_bodystructure(fetch_att)
1125
+ fetch = parse_bodystructure(fetch_att, extension: false)
1099
1126
  when 'BODYSTRUCTURE'
1100
- fetch = parse_bodystructure(fetch_att)
1127
+ fetch = parse_bodystructure(fetch_att, extension: true)
1101
1128
  when 'ENVELOPE'
1102
1129
  fetch = parse_envelope(fetch_att)
1103
1130
  when 'FAST'