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 +4 -4
- data/ChangeLog +60 -0
- data/lib/rims/cmd.rb +44 -28
- data/lib/rims/protocol/decoder.rb +53 -29
- data/lib/rims/protocol/parser.rb +136 -109
- data/lib/rims/service.rb +21 -21
- data/lib/rims/test.rb +21 -3
- data/lib/rims/version.rb +1 -1
- data/rims.gemspec +1 -0
- data/test/cmd/test_command.rb +114 -22
- data/test/test_protocol_decoder.rb +190 -46
- data/test/test_protocol_fetch.rb +380 -189
- data/test/test_protocol_search.rb +1 -0
- metadata +16 -5
- data/lib/rims/rfc822.rb +0 -463
- data/test/test_rfc822.rb +0 -696
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5f51adf08f317981cdec3bb1067edd7a6c4befcf2f3e3e9c3ab4ac97702dad80
|
4
|
+
data.tar.gz: d0089e4150ad0768b0267c3c34980fad6a5251f0953997bd75a8c00e590120bb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
data/lib/rims/cmd.rb
CHANGED
@@ -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
|
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
|
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
|
-
|
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
|
-
|
30
|
-
|
31
|
-
|
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(
|
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 =
|
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(
|
328
|
+
def initialize(drb_services, auth, logger,
|
325
329
|
mail_delivery_user: Service::DEFAULT_CONFIG.mail_delivery_user)
|
326
330
|
super(auth, logger)
|
327
|
-
@
|
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, @
|
367
|
+
MailDeliveryDecoder.new(self, @drb_services, @auth, @logger)
|
364
368
|
else
|
365
|
-
engine = self.class.make_engine_and_recovery_if_needed(@
|
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
|
-
|
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
|
-
|
1282
|
-
|
1283
|
-
|
1284
|
-
|
1285
|
-
|
1286
|
-
|
1287
|
-
|
1288
|
-
|
1289
|
-
|
1290
|
-
|
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,
|
1783
|
+
def initialize(parent_decoder, drb_services, auth, logger)
|
1760
1784
|
super(auth, logger)
|
1761
1785
|
@parent_decoder = parent_decoder
|
1762
|
-
@
|
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
|
-
@
|
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
|
-
@
|
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 =
|
1951
|
+
res = response_stream(tag) {|stream_res|
|
1928
1952
|
engine = store_engine_cache(username) {
|
1929
|
-
self.class.make_engine_and_recovery_if_needed(@
|
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
|
}
|
data/lib/rims/protocol/parser.rb
CHANGED
@@ -244,8 +244,21 @@ module RIMS
|
|
244
244
|
end
|
245
245
|
private :get_mail
|
246
246
|
|
247
|
-
|
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 !=
|
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
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
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
|
808
|
-
if (
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
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
|
-
|
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 :
|
818
|
+
private :get_body_disposition
|
819
819
|
|
820
|
-
def
|
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
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
|
873
|
-
|
874
|
-
|
875
|
-
|
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'
|