class RIMS::Protocol::FetchParser
Public Class Methods
new(mail_store, folder, charset_aliases: RFC822::DEFAULT_CHARSET_ALIASES)
click to toggle source
# File lib/rims/protocol/parser.rb, line 878 def initialize(mail_store, folder, charset_aliases: RFC822::DEFAULT_CHARSET_ALIASES) @mail_store = mail_store @folder = folder @mail_cache = Hash.new{|hash, uid| if (msg_txt = @mail_store.msg_text(@folder.mbox_id, uid)) then hash[uid] = RFC822::Message.new(msg_txt, charset_aliases: charset_aliases) end } end
Public Instance Methods
parse(fetch_att)
click to toggle source
# File lib/rims/protocol/parser.rb, line 1273 def parse(fetch_att) fetch = parse_cached(fetch_att) proc{|msg| res = fetch.call(msg) @mail_cache.clear res } end
Private Instance Methods
expand_macro(cmd_list)
click to toggle source
# File lib/rims/protocol/parser.rb, line 893 def expand_macro(cmd_list) func_list = cmd_list.map{|name| parse_cached(name) } proc{|msg| func_list.map{|f| f.call(msg) }.join(' '.b) } end
get_body_disposition(mail)
click to toggle source
# File lib/rims/protocol/parser.rb, line 913 def get_body_disposition(mail) if (disposition_type = mail.content_disposition_upcase) then [ disposition_type, make_body_params(mail.content_disposition_parameter_list) ] else # not allowed empty body field disposition. # RFC 3501 / 9. Formal Syntax: # body-fld-dsp = "(" string SP body-fld-param ")" / nil nil end end
get_body_lang(mail)
click to toggle source
# File lib/rims/protocol/parser.rb, line 927 def get_body_lang(mail) if (tag_list = mail.content_language_upcase) then unless (tag_list.empty?) then if (tag_list.length == 1) then tag_list[0] else tag_list end end end end
get_bodystructure_data(mail, extension: false)
click to toggle source
# File lib/rims/protocol/parser.rb, line 940 def get_bodystructure_data(mail, extension: false) body_data = [] if (mail.multipart?) then # body_type_mpart body_data.concat(mail.parts.map{|part_msg| get_bodystructure_data(part_msg, extension: extension) }) body_data << mail.media_sub_type_upcase # body_ext_mpart if (extension) then body_data << make_body_params(mail.content_type_parameter_list) body_data << get_body_disposition(mail) body_data << get_body_lang(mail) body_data << mail.header['Content-Location'] end else if (mail.text?) then # body_type_text # media_text body_data << mail.media_main_type_upcase body_data << mail.media_sub_type_upcase # body_fields body_data << make_body_params(mail.content_type_parameter_list) body_data << mail.header['Content-Id'] body_data << mail.header['Content-Description'] body_data << mail.header.fetch_upcase('Content-Transfer-Encoding') body_data << mail.raw_source.bytesize # body_fld_lines body_data << mail.raw_source.each_line.count elsif (mail.message?) then # body_type_msg # message_media body_data << mail.media_main_type_upcase body_data << mail.media_sub_type_upcase # body_fields body_data << make_body_params(mail.content_type_parameter_list) body_data << mail.header['Content-Id'] body_data << mail.header['Content-Description'] body_data << mail.header.fetch_upcase('Content-Transfer-Encoding') body_data << mail.raw_source.bytesize # envelope body_data << get_envelope_data(mail.message) # body body_data << get_bodystructure_data(mail.message, extension: extension) # body_fld_lines body_data << mail.raw_source.each_line.count else # body_type_basic # media_basic body_data << mail.media_main_type_upcase body_data << mail.media_sub_type_upcase # body_fields body_data << make_body_params(mail.content_type_parameter_list) body_data << mail.header['Content-Id'] body_data << mail.header['Content-Description'] body_data << mail.header.fetch_upcase('Content-Transfer-Encoding') body_data << mail.raw_source.bytesize end # body_ext_1part if (extension) then body_data << mail.header['Content-MD5'] body_data << get_body_disposition(mail) body_data << get_body_lang(mail) body_data << mail.header['Content-Location'] end end body_data end
get_envelope_data(mail)
click to toggle source
# File lib/rims/protocol/parser.rb, line 1014 def get_envelope_data(mail) env_data = [] env_data << mail.header['Date'] env_data << mail.header['Subject'] env_data << mail.from&.map(&:to_a) env_data << mail.sender&.map(&:to_a) env_data << mail.reply_to&.map(&:to_a) env_data << mail.to&.map(&:to_a) env_data << mail.cc&.map(&:to_a) env_data << mail.bcc&.map(&:to_a) env_data << mail.header['In-Reply-To'] env_data << mail.header['Message-Id'] end
get_mail(msg)
click to toggle source
# File lib/rims/protocol/parser.rb, line 888 def get_mail(msg) @mail_cache[msg.uid] or raise "not found a mail: #{msg.uid}" end
make_body_params(name_value_pair_list)
click to toggle source
# File lib/rims/protocol/parser.rb, line 901 def make_body_params(name_value_pair_list) if (name_value_pair_list && ! name_value_pair_list.empty?) then name_value_pair_list.flatten else # not allowed empty body field parameters. # RFC 3501 / 9. Formal Syntax: # body-fld-param = "(" string SP string *(SP string SP string) ")" / nil nil end end
parse_body(body, msg_att_name)
click to toggle source
# File lib/rims/protocol/parser.rb, line 1029 def parse_body(body, msg_att_name) enable_seen = true if (body.option) then case (body.option.upcase) when 'PEEK' enable_seen = false else raise SyntaxError, "unknown fetch body option: #{option}" end end if (@folder.read_only?) then enable_seen = false end if (enable_seen) then fetch_flags = parse_flags('FLAGS') fetch_flags_changed = proc{|msg| unless (@mail_store.msg_flag(@folder.mbox_id, msg.uid, 'seen')) then @mail_store.set_msg_flag(@folder.mbox_id, msg.uid, 'seen', true) fetch_flags.call(msg) + ' '.b else ''.b end } else fetch_flags_changed = proc{|msg| ''.b } end if (body.section_list.empty?) then section_text = nil section_index_list = [] else if (body.section_list[0] =~ /\A (?<index>\d+(?:\.\d+)*) (?:\.(?<text>.+))? \z/x) then section_text = $~[:text] section_index_list = $~[:index].split(/\./).map{|i| i.to_i } else section_text = body.section_list[0] section_index_list = [] end end is_root = section_index_list.empty? unless (section_text) then if (is_root) then fetch_body_content = proc{|mail| mail.raw_source } else fetch_body_content = proc{|mail| mail.body.raw_source } end else section_text = section_text.upcase case (section_text) when 'MIME' if (section_index_list.empty?) then raise SyntaxError, "need for section index at #{section_text}." else fetch_body_content = proc{|mail| if (header = get_body_content(mail, :header)) then header.raw_source end } end when 'HEADER' fetch_body_content = proc{|mail| if (header = get_body_content(mail, :header, nest_mail: ! is_root)) then header.raw_source end } when 'HEADER.FIELDS', 'HEADER.FIELDS.NOT' if (body.section_list.length != 2) then raise SyntaxError, "need for argument of #{section_text}." end field_name_list = body.section_list[1] unless ((field_name_list.is_a? Array) && (field_name_list[0] == :group)) then raise SyntaxError, "invalid argument of #{section_text}: #{field_name_list}" end field_name_list = field_name_list[1..-1] case (section_text) when 'HEADER.FIELDS' fetch_body_content = proc{|mail| if (header = get_body_content(mail, :header, nest_mail: ! is_root)) then field_name_set = field_name_list.map{|n| n.downcase }.to_set name_value_pair_list = header.select{|n, v| field_name_set.include? n.downcase } encode_header(name_value_pair_list) end } when 'HEADER.FIELDS.NOT' fetch_body_content = proc{|mail| if (header = get_body_content(mail, :header, nest_mail: ! is_root)) then field_name_set = field_name_list.map{|n| n.downcase }.to_set name_value_pair_list = header.reject{|n, v| field_name_set.include? n.downcase } encode_header(name_value_pair_list) end } else raise 'internal error.' end when 'TEXT' fetch_body_content = proc{|mail| if (mail_body = get_body_content(mail, :body, nest_mail: ! is_root)) then mail_body.raw_source end } else raise SyntaxError, "unknown fetch body section text: #{section_text}" end end proc{|msg| res = ''.b res << fetch_flags_changed.call(msg) res << msg_att_name res << ' '.b mail = get_body_section(get_mail(msg), section_index_list) content = fetch_body_content.call(mail) if mail if (content) then if (body.partial_origin) then if (content.bytesize > body.partial_origin) then partial_content = content.byteslice((body.partial_origin)..-1) if (partial_content.bytesize > body.partial_size) then # because bignum byteslice is failed. partial_content = partial_content.byteslice(0, body.partial_size) end res << Protocol.quote(partial_content) else res << 'NIL'.b end else res << Protocol.quote(content) end else res << 'NIL'.b end } end
parse_bodystructure(msg_att_name, extension: false)
click to toggle source
# File lib/rims/protocol/parser.rb, line 1171 def parse_bodystructure(msg_att_name, extension: false) proc{|msg| ''.b << msg_att_name << ' '.b << encode_bodystructure(get_bodystructure_data(get_mail(msg), extension: extension)) } end
parse_cached(fetch_att)
click to toggle source
# File lib/rims/protocol/parser.rb, line 1226 def parse_cached(fetch_att) fetch_att = fetch_att.upcase if (fetch_att.is_a? String) case (fetch_att) when 'ALL' fetch = expand_macro(%w[ FLAGS INTERNALDATE RFC822.SIZE ENVELOPE ]) when 'BODY' fetch = parse_bodystructure(fetch_att, extension: false) when 'BODYSTRUCTURE' fetch = parse_bodystructure(fetch_att, extension: true) when 'ENVELOPE' fetch = parse_envelope(fetch_att) when 'FAST' fetch = expand_macro(%w[ FLAGS INTERNALDATE RFC822.SIZE ]) when 'FLAGS' fetch = parse_flags(fetch_att) when 'FULL' fetch = expand_macro(%w[ FLAGS INTERNALDATE RFC822.SIZE ENVELOPE BODY ]) when 'INTERNALDATE' fetch = parse_internaldate(fetch_att) when 'RFC822' fetch = parse_body(Protocol.body(section_list: []), fetch_att) when 'RFC822.HEADER' fetch = parse_body(Protocol.body(option: 'PEEK', section_list: %w[ HEADER ]), fetch_att) when 'RFC822.SIZE' fetch = parse_rfc822_size(fetch_att) when 'RFC822.TEXT' fetch = parse_body(Protocol.body(section_list: %w[ TEXT ]), fetch_att) when 'UID' fetch = parse_uid(fetch_att) when Array case (fetch_att[0]) when :group fetch = parse_group(fetch_att[1..-1]) when :body body = fetch_att[1] fetch = parse_body(body, body.msg_att_name) else raise SyntaxError, "unknown fetch attribute: #{fetch_att[0]}" end else raise SyntaxError, "unknown fetch attribute: #{fetch_att}" end fetch end
parse_envelope(msg_att_name)
click to toggle source
# File lib/rims/protocol/parser.rb, line 1178 def parse_envelope(msg_att_name) proc{|msg| ''.b << msg_att_name << ' '.b << encode_list(get_envelope_data(get_mail(msg))) } end
parse_flags(msg_att_name)
click to toggle source
# File lib/rims/protocol/parser.rb, line 1185 def parse_flags(msg_att_name) proc{|msg| flag_list = MailStore::MSG_FLAG_NAMES.find_all{|flag_name| @mail_store.msg_flag(@folder.mbox_id, msg.uid, flag_name) }.map{|flag_name| "\\".b << flag_name.capitalize }.join(' ') ''.b << msg_att_name << ' (' << flag_list << ')' } end
parse_group(fetch_attrs)
click to toggle source
# File lib/rims/protocol/parser.rb, line 1218 def parse_group(fetch_attrs) group_fetch_list = fetch_attrs.map{|fetch_att| parse_cached(fetch_att) } proc{|msg| '('.b << group_fetch_list.map{|fetch| fetch.call(msg) }.join(' '.b) << ')'.b } end
parse_internaldate(msg_att_name)
click to toggle source
# File lib/rims/protocol/parser.rb, line 1197 def parse_internaldate(msg_att_name) proc{|msg| ''.b << msg_att_name << @mail_store.msg_date(@folder.mbox_id, msg.uid).strftime(' "%d-%b-%Y %H:%M:%S %z"'.b) } end
parse_rfc822_size(msg_att_name)
click to toggle source
# File lib/rims/protocol/parser.rb, line 1204 def parse_rfc822_size(msg_att_name) proc{|msg| ''.b << msg_att_name << ' '.b << get_mail(msg).raw_source.bytesize.to_s } end
parse_uid(msg_att_name)
click to toggle source
# File lib/rims/protocol/parser.rb, line 1211 def parse_uid(msg_att_name) proc{|msg| ''.b << msg_att_name << ' '.b << msg.uid.to_s } end