@@ -10,48 +10,83 @@ class Message < ApplicationRecord
1010 # https://blade.ruby-lang.org/ruby-talk/410000 is not.
1111 self . skip_time_zone_conversion_for_attributes = [ :published_at ]
1212
13+ has_many_attached :attachments
14+
1315 attr_accessor :children
1416
1517 class << self
1618 def from_mail ( mail , list , list_seq )
17- body = Kconv . toutf8 mail . body . raw_source
18- if ( ( list . name == 'ruby-dev' ) && list_seq . in? ( [ 13859 , 26229 , 39731 , 39734 ] ) ) || ( ( list . name == 'ruby-core' ) && list_seq . in? ( [ 5231 ] ) ) || ( ( list . name == 'ruby-list' ) && list_seq . in? ( [ 29637 , 29711 , 30148 ] ) ) || ( ( list . name == 'ruby-talk' ) && list_seq . in? ( [ 5198 , 61316 ] ) )
19- body . gsub! ( "\u0000 " , '' )
20- end
21- if ( list . name == 'ruby-list' ) && list_seq . in? ( [ 37565 , 38116 , 43106 ] )
22- mail . header [ :subject ] . value . chop!
23- end
24- if ( list . name == 'ruby-list' ) && ( list_seq . in? ( [ 41850 , 43710 ] ) )
25- mail . header [ :subject ] . value = Kconv . toutf8 mail . header [ :subject ] . value
26- end
27- subject = mail . subject
28- subject = Kconv . toutf8 subject if subject
29- from = Kconv . toutf8 mail . from_address &.raw
30- if !from && ( list . name == 'ruby-core' ) && ( list_seq == 161 )
31- from = mail . from . encode Encoding ::UTF_8 , Encoding ::KOI8_R
32- end
19+ new . from_mail ( mail , list , list_seq )
20+ end
21+ end
3322
34- message_id = mail . message_id &.encode Encoding ::UTF_8 , invalid : :replace , undef : :replace
23+ def from_mail ( mail , list , list_seq )
24+ self . list_id , self . list_seq , self . published_at = list . id , list_seq , mail . date
3525
36- # mail.in_reply_to returns strange Array object in some cases (?), so let's use the raw value
37- parent_message_id_header = extract_message_id_from_in_reply_to ( mail . header [ :in_reply_to ] &.value )
38- parent_message_id = Message . where ( list_id : list . id , message_id_header : parent_message_id_header ) . pick ( :id ) if parent_message_id_header
39- if !parent_message_id && ( String === mail . references )
40- parent_message_id = Message . where ( list_id : list . id , message_id_header : mail . references ) . pick ( :id )
41- end
42- if !parent_message_id && ( Array === mail . references )
43- mail . references . compact . each do |ref |
44- break if ( parent_message_id = Message . where ( list_id : list . id , message_id_header : ref ) . pick ( :id ) )
45- end
26+ if mail . multipart?
27+ mail . parts . each do |p |
28+ handle_multipart p
4629 end
30+ else
31+ self . body = Kconv . toutf8 mail . body . raw_source
32+ end
33+
34+ if ( ( list . name == 'ruby-dev' ) && list_seq . in? ( [ 13859 , 26229 , 39731 , 39734 ] ) ) || ( ( list . name == 'ruby-core' ) && list_seq . in? ( [ 5231 ] ) ) || ( ( list . name == 'ruby-list' ) && list_seq . in? ( [ 29637 , 29711 , 30148 ] ) ) || ( ( list . name == 'ruby-talk' ) && list_seq . in? ( [ 5198 , 61316 ] ) )
35+ self . body . gsub! ( "\u0000 " , '' )
36+ end
37+
38+ if ( list . name == 'ruby-list' ) && list_seq . in? ( [ 37565 , 38116 , 43106 ] )
39+ mail . header [ :subject ] . value . chop!
40+ end
41+ if ( list . name == 'ruby-list' ) && ( list_seq . in? ( [ 41850 , 43710 ] ) )
42+ mail . header [ :subject ] . value = Kconv . toutf8 mail . header [ :subject ] . value
43+ end
44+ self . subject = mail . subject
45+ self . subject = Kconv . toutf8 subject if self . subject
4746
48- new list_id : list . id , list_seq : list_seq , body : body , subject : subject , from : from , published_at : mail . date , message_id_header : message_id , parent_id : parent_message_id
47+ self . from = Kconv . toutf8 mail . from_address &.raw
48+ if !self . from && ( list . name == 'ruby-core' ) && ( list_seq == 161 )
49+ self . from = mail . from . encode Encoding ::UTF_8 , Encoding ::KOI8_R
4950 end
5051
51- private def extract_message_id_from_in_reply_to ( header )
52- header && header . strip . scan ( /<([^>]+)>/ ) . flatten . first
52+ self . message_id_header = mail . message_id &.encode Encoding ::UTF_8 , invalid : :replace , undef : :replace
53+
54+ # mail.in_reply_to returns strange Array object in some cases (?), so let's use the raw value
55+ parent_message_id_header = extract_message_id_from_in_reply_to ( mail . header [ :in_reply_to ] &.value )
56+ self . parent_id = Message . where ( list_id : list . id , message_id_header : parent_message_id_header ) . pick ( :id ) if parent_message_id_header
57+ if !self . parent_id && ( String === mail . references )
58+ self . parent_id = Message . where ( list_id : list . id , message_id_header : mail . references ) . pick ( :id )
59+ end
60+ if !self . parent_id && ( Array === mail . references )
61+ mail . references . compact . each do |ref |
62+ break if ( self . parent_id = Message . where ( list_id : list . id , message_id_header : ref ) . pick ( :id ) )
63+ end
5364 end
5465
66+ self
67+ end
68+
69+ private def handle_multipart ( part )
70+ if part . attachment?
71+ file = StringIO . new ( part . decoded )
72+ attachments . attach ( io : file , filename : part . filename , content_type : part . content_type )
73+ else
74+ case part . content_type . downcase
75+ when /^text\/ plain/
76+ ( self . body ||= '' ) << Kconv . toutf8 ( part . body . raw_source )
77+ when /^text\/ html;/
78+ ( self . html_body ||= '' ) << Kconv . toutf8 ( part . body . raw_source )
79+ else
80+ puts "Unknown content_type: #{ part . content_type } "
81+ end
82+ end
83+ end
84+
85+ private def extract_message_id_from_in_reply_to ( header )
86+ header && header . strip . scan ( /<([^>]+)>/ ) . flatten . first
87+ end
88+
89+ class << self
5590 def from_s3 ( list_name , list_seq , s3_client = Aws ::S3 ::Client . new ( region : BLADE_BUCKET_REGION ) )
5691 obj = s3_client . get_object ( bucket : BLADE_BUCKET_NAME , key : "#{ list_name } /#{ list_seq } " )
5792
0 commit comments