The RMail::StreamParser is a low level message parsing API. It is useful when you are interested in serially examining all message content but are not interested in a full object representation of the object. See ::parse.
Parse a message from an input source. This method returns nothing.
Instead, the supplied handler
is expected to implement the
same methods as RMail::StreamHandler. The
message structure can be inferred from the methods called on the
handler
. The input
can be any Ruby IO source or
a String.
This is a low level parsing API. For a message parser that returns an RMail::Message object, see the RMail::Parser class. RMail::Parser is implemented using RMail::StreamParser.
# File lib/rmail/parser.rb, line 169 def parse(input, handler) RMail::StreamParser.new(input, handler).parse end
# File lib/rmail/parser.rb, line 202 def parse_header(input, depth) data = nil header = nil pushback = nil boundary = nil while chunk = input.read data ||= '' data << chunk if data[0] == \n # A leading newline in the message is seen when parsing the # parts of a multipart message. It means there are no # headers. The body part starts directly after this # newline. rest = data[1..-1] else header, rest = data.split(/\n\n/, 2) end break if rest end input.pushback(rest) if header mime = false fields = header.split(/\n(?!\s)/) if fields.first =~ /^From / @handler.mbox_from(fields.first) fields.shift end fields.each { |field| if field =~ /^From / @handler.mbox_from(field) else name, value = RMail::Header::Field.parse(field) case name.downcase when 'mime-version' if value =~ /\b1\.0\b/ mime = true end when 'content-type' # FIXME: would be nice to have a procedural equivalent # to RMail::Header#param. header = RMail::Header.new header['content-type'] = value boundary = header.param('content-type', 'boundary') end @handler.header_field(field, name, value) end } unless mime or depth > 0 boundary = nil end end return boundary end
# File lib/rmail/parser.rb, line 193 def parse_low(input, depth) multipart_boundary = parse_header(input, depth) if multipart_boundary parse_multipart_body(input, depth, multipart_boundary) else parse_singlepart_body(input, depth) end end
# File lib/rmail/parser.rb, line 256 def parse_multipart_body(input, depth, boundary) input = RMail::Parser::MultipartReader.new(input, boundary) input.chunk_size = @chunk_size if @chunk_size @handler.multipart_body_begin # Reach each part, adding it to this entity as appropriate. delimiters = [] while input.next_part if input.preamble? while chunk = input.read @handler.preamble_chunk(chunk) end elsif input.epilogue? while chunk = input.read @handler.epilogue_chunk(chunk) end else @handler.part_begin parse_low(input, depth + 1) @handler.part_end end delimiters << (input.delimiter || "") unless input.epilogue? end @handler.multipart_body_end(delimiters, boundary) end
# File lib/rmail/parser.rb, line 283 def parse_singlepart_body(input, depth) @handler.body_begin while chunk = input.read @handler.body_chunk(chunk) end @handler.body_end end