class RMail::StreamParser
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 StreamParser.parse
.
Public Class Methods
parse(input, handler)
click to toggle source
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
Private Instance Methods
parse_header(input, depth)
click to toggle source
# File lib/rmail/parser.rb, line 202 def parse_header(input, depth) data = nil header = 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] elsif data[0] == ?\r && data[1] == ?\n rest = data[2..-1] else header, rest = data.split(/\r?\n\r?\n/, 2) end break if rest end input.pushback(rest) if header mime = false fields = header.split(/\r?\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
parse_low(input, depth)
click to toggle source
# 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
parse_multipart_body(input, depth, boundary)
click to toggle source
# File lib/rmail/parser.rb, line 257 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
parse_singlepart_body(input, depth)
click to toggle source
# File lib/rmail/parser.rb, line 284 def parse_singlepart_body(input, depth) @handler.body_begin while chunk = input.read @handler.body_chunk(chunk) end @handler.body_end end