lib/sup/message.rb in sup-0.0.1 vs lib/sup/message.rb in sup-0.0.2

- old
+ new

@@ -25,28 +25,31 @@ def subj_is_reply? s; s =~ RE_PATTERN; end def reify_subj s; subj_is_reply?(s) ? s : "Re: " + s; end end class Attachment - attr_reader :content_type, :desc + attr_reader :content_type, :desc, :filename def initialize content_type, desc, part @content_type = content_type @desc = desc @part = part @file = nil + desc =~ /filename="(.*?)"/ && @filename = $1 end def view! unless @file @file = Tempfile.new "redwood.attachment" - @file.print @part.decode + @file.print self @file.close end ## TODO: handle unknown mime-types system "/usr/bin/run-mailcap --action=view #{@content_type}:#{@file.path}" end + + def to_s; @part.decode; end end class Text attr_reader :lines def initialize lines @@ -71,37 +74,51 @@ QUOTE_PATTERN = /^\s{0,4}[>|\}]/ BLOCK_QUOTE_PATTERN = /^-----\s*Original Message\s*----+$/ QUOTE_START_PATTERN = /(^\s*Excerpts from)|(^\s*In message )|(^\s*In article )|(^\s*Quoting )|((wrote|writes|said|says)\s*:\s*$)/ SIG_PATTERN = /(^-- ?$)|(^\s*----------+\s*$)|(^\s*_________+\s*$)/ - SIG_DISTANCE = 15 # lines from the end + MAX_SIG_DISTANCE = 15 # lines from the end DEFAULT_SUBJECT = "(missing subject)" DEFAULT_SENDER = "(missing sender)" attr_reader :id, :date, :from, :subj, :refs, :replytos, :to, :source, :cc, :bcc, :labels, :list_address, :recipient_email, :replyto, - :source_info, :mbox_status + :source_info, :status bool_reader :dirty - def initialize source, source_info, labels, snippet=nil - @source = source - @source_info = source_info + ## if index_entry is specified, will fill in values from that, + def initialize opts + if opts[:source] + @source = opts[:source] + @source_info = opts[:source_info] or raise ArgumentError, ":source but no :source_info" + @body = nil + else + @source = @source_info = nil + @body = opts[:body] or raise ArgumentError, "one of :body or :source must be specified" + end + @snippet = opts[:snippet] || "" + @labels = opts[:labels] || [] @dirty = false - @snippet = snippet - @labels = labels - header = @source.load_header @source_info - header.each { |k, v| header[k.downcase] = v } + header = + if opts[:header] + opts[:header] + else + header = @source.load_header @source_info + header.each { |k, v| header[k.downcase] = v } + header + end %w(message-id date).each do |f| raise MessageFormatError, "no #{f} field in header #{header.inspect} (source #@source offset #@source_info)" unless header.include? f raise MessageFormatError, "nil #{f} field in header #{header.inspect} (source #@source offset #@source_info)" unless header[f] end begin - @date = Time.parse header["date"] + date = header["date"] + @date = (Time === date ? date : Time.parse(header["date"])) rescue ArgumentError => e raise MessageFormatError, "unparsable date #{header['date']}: #{e.message}" end if(@subj = header["subject"]) @@ -123,18 +140,14 @@ else nil end @recipient_email = header["delivered-to"] - @mbox_status = header["status"] + @status = header["status"] end - def snippet - to_chunks unless @snippet - @snippet - end - + def snippet; @snippet || to_chunks && @snippet; end def is_list_message?; !@list_address.nil?; end def is_draft?; DraftLoader === @source; end def draft_filename raise "not a draft" unless is_draft? @source.fn_for_offset @source_info @@ -165,18 +178,25 @@ @labels = l @dirty = true end def to_chunks - m = @source.load_message @source_info - message_to_chunks m + if @body + [Text.new(@body.split("\n"))] + else + message_to_chunks @source.load_message(@source_info) + end end - def header_text - @source.load_header_text @source_info + def raw_header + @source.raw_header @source_info end + def raw_full_message + @source.raw_full_message @source_info + end + def content [ from && from.longname, to.map { |p| p.longname }, cc.map { |p| p.longname }, @@ -208,11 +228,11 @@ when "text/plain", nil raise MessageFormatError, "no message body before decode" unless m.body body = m.decode or raise MessageFormatError, "no message body" text_to_chunks body.gsub(/\t/, " ").gsub(/\r/, "").split("\n") - when "multipart/alternative", "multipart/mixed" + when /^multipart\// nil else disp = m.header["Content-Disposition"] || "" Attachment.new m.header.content_type, disp.gsub(/[\s\n]+/, " "), m end @@ -235,11 +255,11 @@ case state when :text newstate = nil if line =~ QUOTE_PATTERN || (line =~ QUOTE_START_PATTERN && (nextline =~ QUOTE_PATTERN || nextline =~ QUOTE_START_PATTERN)) newstate = :quote - elsif line =~ SIG_PATTERN && (lines.length - i) < SIG_DISTANCE + elsif line =~ SIG_PATTERN && (lines.length - i) < MAX_SIG_DISTANCE newstate = :sig elsif line =~ BLOCK_QUOTE_PATTERN newstate = :block_quote end if newstate @@ -251,10 +271,10 @@ end when :quote newstate = nil if line =~ QUOTE_PATTERN || line =~ QUOTE_START_PATTERN || line =~ /^\s*$/ chunk_lines << line - elsif line =~ SIG_PATTERN && (lines.length - i) < SIG_DISTANCE + elsif line =~ SIG_PATTERN && (lines.length - i) < MAX_SIG_DISTANCE newstate = :sig else newstate = :text end if newstate