rims 0.2.5 → 0.2.6

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.
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'