diff options
Diffstat (limited to 'vendor/ruby-msg/lib/mapi/convert/note-tmail.rb')
-rw-r--r-- | vendor/ruby-msg/lib/mapi/convert/note-tmail.rb | 287 |
1 files changed, 0 insertions, 287 deletions
diff --git a/vendor/ruby-msg/lib/mapi/convert/note-tmail.rb b/vendor/ruby-msg/lib/mapi/convert/note-tmail.rb deleted file mode 100644 index 9ccc9e0b3..000000000 --- a/vendor/ruby-msg/lib/mapi/convert/note-tmail.rb +++ /dev/null @@ -1,287 +0,0 @@ -require 'rubygems' -require 'tmail' - -# these will be removed later -require 'time' -require 'mime' - -# there is some Msg specific stuff in here. - -class TMail::Mail - def quoted_body= str - body_port.wopen { |f| f.write str } - str - end -end - -module Mapi - class Message - def mime - return @mime if @mime - # if these headers exist at all, they can be helpful. we may however get a - # application/ms-tnef mime root, which means there will be little other than - # headers. we may get nothing. - # and other times, when received from external, we get the full cigar, boundaries - # etc and all. - # sometimes its multipart, with no boundaries. that throws an error. so we'll be more - # forgiving here - @mime = Mime.new props.transport_message_headers.to_s, true - populate_headers - @mime - end - - def headers - mime.headers - end - - # copy data from msg properties storage to standard mime. headers - # i've now seen it where the existing headers had heaps on stuff, and the msg#props had - # practically nothing. think it was because it was a tnef - msg conversion done by exchange. - def populate_headers - # construct a From value - # should this kind of thing only be done when headers don't exist already? maybe not. if its - # sent, then modified and saved, the headers could be wrong? - # hmmm. i just had an example where a mail is sent, from an internal user, but it has transport - # headers, i think because one recipient was external. the only place the senders email address - # exists is in the transport headers. so its maybe not good to overwrite from. - # recipients however usually have smtp address available. - # maybe we'll do it for all addresses that are smtp? (is that equivalent to - # sender_email_address !~ /^\// - name, email = props.sender_name, props.sender_email_address - if props.sender_addrtype == 'SMTP' - headers['From'] = if name and email and name != email - [%{"#{name}" <#{email}>}] - else - [email || name] - end - elsif !headers.has_key?('From') - # some messages were never sent, so that sender stuff isn't filled out. need to find another - # way to get something - # what about marking whether we thing the email was sent or not? or draft? - # for partition into an eventual Inbox, Sent, Draft mbox set? - # i've now seen cases where this stuff is missing, but exists in transport message headers, - # so maybe i should inhibit this in that case. - if email - # disabling this warning for now - #Log.warn "* no smtp sender email address available (only X.400). creating fake one" - # this is crap. though i've specially picked the logic so that it generates the correct - # email addresses in my case (for my organisation). - # this user stuff will give valid email i think, based on alias. - user = name ? name.sub(/(.*), (.*)/, "\\2.\\1") : email[/\w+$/].downcase - domain = (email[%r{^/O=([^/]+)}i, 1].downcase + '.com' rescue email) - headers['From'] = [name ? %{"#{name}" <#{user}@#{domain}>} : "<#{user}@#{domain}>" ] - elsif name - # we only have a name? thats screwed up. - # disabling this warning for now - #Log.warn "* no smtp sender email address available (only name). creating fake one" - headers['From'] = [%{"#{name}"}] - else - # disabling this warning for now - #Log.warn "* no sender email address available at all. FIXME" - end - # else we leave the transport message header version - end - - # for all of this stuff, i'm assigning in utf8 strings. - # thats ok i suppose, maybe i can say its the job of the mime class to handle that. - # but a lot of the headers are overloaded in different ways. plain string, many strings - # other stuff. what happens to a person who has a " in their name etc etc. encoded words - # i suppose. but that then happens before assignment. and can't be automatically undone - # until the header is decomposed into recipients. - recips_by_type = recipients.group_by { |r| r.type } - # i want to the the types in a specific order. - [:to, :cc, :bcc].each do |type| - # don't know why i bother, but if we can, we try to sort recipients by the numerical part - # of the ole name, or just leave it if we can't - recips = recips_by_type[type] - recips = (recips.sort_by { |r| r.obj.name[/\d{8}$/].hex } rescue recips) - # switched to using , for separation, not ;. see issue #4 - # recips.empty? is strange. i wouldn't have thought it possible, but it was right? - headers[type.to_s.sub(/^(.)/) { $1.upcase }] = [recips.join(', ')] unless recips.empty? - end - headers['Subject'] = [props.subject] if props.subject - - # fill in a date value. by default, we won't mess with existing value hear - if !headers.has_key?('Date') - # we want to get a received date, as i understand it. - # use this preference order, or pull the most recent? - keys = %w[message_delivery_time client_submit_time last_modification_time creation_time] - time = keys.each { |key| break time if time = props.send(key) } - time = nil unless Date === time - - # now convert and store - # this is a little funky. not sure about time zone stuff either? - # actually seems ok. maybe its always UTC and interpreted anyway. or can be timezoneless. - # i have no timezone info anyway. - # in gmail, i see stuff like 15 Jan 2007 00:48:19 -0000, and it displays as 11:48. - # can also add .localtime here if desired. but that feels wrong. - headers['Date'] = [Time.iso8601(time.to_s).rfc2822] if time - end - - # some very simplistic mapping between internet message headers and the - # mapi properties - # any of these could be causing duplicates due to case issues. the hack in #to_mime - # just stops re-duplication at that point. need to move some smarts into the mime - # code to handle it. - mapi_header_map = [ - [:internet_message_id, 'Message-ID'], - [:in_reply_to_id, 'In-Reply-To'], - # don't set these values if they're equal to the defaults anyway - [:importance, 'Importance', proc { |val| val.to_s == '1' ? nil : val }], - [:priority, 'Priority', proc { |val| val.to_s == '1' ? nil : val }], - [:sensitivity, 'Sensitivity', proc { |val| val.to_s == '0' ? nil : val }], - # yeah? - [:conversation_topic, 'Thread-Topic'], - # not sure of the distinction here - # :originator_delivery_report_requested ?? - [:read_receipt_requested, 'Disposition-Notification-To', proc { |val| from }] - ] - mapi_header_map.each do |mapi, mime, *f| - next unless q = val = props.send(mapi) or headers.has_key?(mime) - next if f[0] and !(val = f[0].call(val)) - headers[mime] = [val.to_s] - end - end - - # redundant? - def type - props.message_class[/IPM\.(.*)/, 1].downcase rescue nil - end - - # shortcuts to some things from the headers - %w[From To Cc Bcc Subject].each do |key| - define_method(key.downcase) { headers[key].join(' ') if headers.has_key?(key) } - end - - def body_to_tmail - # to create the body - # should have some options about serializing rtf. and possibly options to check the rtf - # for rtf2html conversion, stripping those html tags or other similar stuff. maybe want to - # ignore it in the cases where it is generated from incoming html. but keep it if it was the - # source for html and plaintext. - if props.body_rtf or props.body_html - # should plain come first? - part = TMail::Mail.new - # its actually possible for plain body to be empty, but the others not. - # if i can get an html version, then maybe a callout to lynx can be made... - part.parts << TMail::Mail.parse("Content-Type: text/plain\r\n\r\n" + props.body) if props.body - # this may be automatically unwrapped from the rtf if the rtf includes the html - part.parts << TMail::Mail.parse("Content-Type: text/html\r\n\r\n" + props.body_html) if props.body_html - # temporarily disabled the rtf. its just showing up as an attachment anyway. - #mime.parts << Mime.new("Content-Type: text/rtf\r\n\r\n" + props.body_rtf) if props.body_rtf - # its thus currently possible to get no body at all if the only body is rtf. that is not - # really acceptable FIXME - part['Content-Type'] = 'multipart/alternative' - part - else - # check no header case. content type? etc?. not sure if my Mime class will accept - Log.debug "taking that other path" - # body can be nil, hence the to_s - TMail::Mail.parse "Content-Type: text/plain\r\n\r\n" + props.body.to_s - end - end - - def to_tmail - # intended to be used for IPM.note, which is the email type. can use it for others if desired, - # YMMV - Log.warn "to_mime used on a #{props.message_class}" unless props.message_class == 'IPM.Note' - # we always have a body - mail = body = body_to_tmail - - # If we have attachments, we take the current mime root (body), and make it the first child - # of a new tree that will contain body and attachments. - unless attachments.empty? - raise NotImplementedError - mime = Mime.new "Content-Type: multipart/mixed\r\n\r\n" - mime.parts << body - # i don't know any better way to do this. need multipart/related for inline images - # referenced by cid: urls to work, but don't want to use it otherwise... - related = false - attachments.each do |attach| - part = attach.to_mime - related = true if part.headers.has_key?('Content-ID') or part.headers.has_key?('Content-Location') - mime.parts << part - end - mime.headers['Content-Type'] = ['multipart/related'] if related - end - - # at this point, mime is either - # - a single text/plain, consisting of the body ('taking that other path' above. rare) - # - a multipart/alternative, consiting of a few bodies (plain and html body. common) - # - a multipart/mixed, consisting of 1 of the above 2 types of bodies, and attachments. - # we add this standard preamble if its multipart - # FIXME preamble.replace, and body.replace both suck. - # preamble= is doable. body= wasn't being done because body will get rewritten from parts - # if multipart, and is only there readonly. can do that, or do a reparse... - # The way i do this means that only the first preamble will say it, not preambles of nested - # multipart chunks. - mail.quoted_body = "This is a multi-part message in MIME format.\r\n" if mail.multipart? - - # now that we have a root, we can mix in all our headers - headers.each do |key, vals| - # don't overwrite the content-type, encoding style stuff - next if mail[key] - # some new temporary hacks - next if key =~ /content-type/i and vals[0] =~ /base64/ - #next if mime.headers.keys.map(&:downcase).include? key.downcase - mail[key] = vals.first - end - # just a stupid hack to make the content-type header last, when using OrderedHash - #mime.headers['Content-Type'] = mime.headers.delete 'Content-Type' - - mail - end - end - - class Attachment - def to_tmail - # TODO: smarter mime typing. - mimetype = props.attach_mime_tag || 'application/octet-stream' - part = TMail::Mail.parse "Content-Type: #{mimetype}\r\n\r\n" - part['Content-Disposition'] = %{attachment; filename="#{filename}"} - part['Content-Transfer-Encoding'] = 'base64' - part['Content-Location'] = props.attach_content_location if props.attach_content_location - part['Content-ID'] = props.attach_content_id if props.attach_content_id - # data.to_s for now. data was nil for some reason. - # perhaps it was a data object not correctly handled? - # hmmm, have to use read here. that assumes that the data isa stream. - # but if the attachment data is a string, then it won't work. possible? - data_str = if @embedded_msg - raise NotImplementedError - mime.headers['Content-Type'] = 'message/rfc822' - # lets try making it not base64 for now - mime.headers.delete 'Content-Transfer-Encoding' - # not filename. rather name, or something else right? - # maybe it should be inline?? i forget attach_method / access meaning - mime.headers['Content-Disposition'] = [%{attachment; filename="#{@embedded_msg.subject}"}] - @embedded_msg.to_mime.to_s - elsif @embedded_ole - raise NotImplementedError - # kind of hacky - io = StringIO.new - Ole::Storage.new io do |ole| - ole.root.type = :dir - Ole::Storage::Dirent.copy @embedded_ole, ole.root - end - io.string - else - data.read.to_s - end - part.body = @embedded_msg ? data_str : Base64.encode64(data_str).gsub(/\n/, "\r\n") - part - end - end - - class Msg < Message - def populate_headers - super - if !headers.has_key?('Date') - # can employ other methods for getting a time. heres one in a similar vein to msgconvert.pl, - # ie taking the time from an ole object - time = @root.ole.dirents.map { |dirent| dirent.modify_time || dirent.create_time }.compact.sort.last - headers['Date'] = [Time.iso8601(time.to_s).rfc2822] if time - end - end - end -end - |