diff --git a/bin/mapitool b/bin/mapitool index ff8f582..7f68271 100755 --- a/bin/mapitool +++ b/bin/mapitool @@ -6,7 +6,6 @@ require 'optparse' require 'rubygems' require 'mapi/msg' require 'mapi/pst' -require 'mapi/convert' require 'time' class Mapitool diff --git a/lib/mapi.rb b/lib/mapi.rb index 64e0daf..df9d422 100644 --- a/lib/mapi.rb +++ b/lib/mapi.rb @@ -1,108 +1,5 @@ require 'mapi/version' +require 'mapi/base' require 'mapi/types' require 'mapi/property_set' - -module Mapi - # - # Mapi::Item is the base class used for all mapi objects, and is purely a - # property set container - # - class Item - attr_reader :properties - alias props properties - - # +properties+ should be a PropertySet instance. - def initialize properties - @properties = properties - end - end - - # a general attachment class. is subclassed by Msg and Pst attachment classes - class Attachment < Item - def filename - props.attach_long_filename || props.attach_filename - end - - def data - @embedded_msg || @embedded_ole || props.attach_data - end - - # with new stream work, its possible to not have the whole thing in memory at one time, - # just to save an attachment - # - # a = msg.attachments.first - # a.save open(File.basename(a.filename || 'attachment'), 'wb') - def save io - raise "can only save binary data blobs, not ole dirs" if @embedded_ole - data.each_read { |chunk| io << chunk } - end - - def inspect - "#<#{self.class.to_s[/\w+$/]}" + - (filename ? " filename=#{filename.inspect}" : '') + - (@embedded_ole ? " embedded_type=#{@embedded_ole.embedded_type.inspect}" : '') + ">" - end - end - - class Recipient < Item - # some kind of best effort guess for converting to standard mime style format. - # there are some rules for encoding non 7bit stuff in mail headers. should obey - # that here, as these strings could be unicode - # email_address will be an EX:/ address (X.400?), unless external recipient. the - # other two we try first. - # consider using entry id for this too. - def name - name = props.transmittable_display_name || props.display_name - # dequote - name[/^'(.*)'/, 1] or name rescue nil - end - - def email - props.smtp_address || props.org_email_addr || props.email_address - end - - RECIPIENT_TYPES = { 0 => :orig, 1 => :to, 2 => :cc, 3 => :bcc } - def type - RECIPIENT_TYPES[props.recipient_type] - end - - def to_s - if name = self.name and !name.empty? and email && name != email - %{"#{name}" <#{email}>} - else - email || name - end - end - - def inspect - "#<#{self.class.to_s[/\w+$/]}:#{self.to_s.inspect}>" - end - end - - # i refer to it as a message (as does mapi), although perhaps Item is better, as its a more general - # concept than a message, as used in Pst files. though maybe i'll switch to using - # Mapi::Object as the base class there. - # - # IMessage essentially, but there's also stuff like IMAPIFolder etc. so, for this to form - # basis for PST Item, it'd need to be more general. - class Message < Item - # these 2 collections should be provided by our subclasses - def attachments - raise NotImplementedError - end - - def recipients - raise NotImplementedError - end - - def inspect - str = %w[message_class from to subject].map do |key| - " #{key}=#{props.send(key).inspect}" - end.compact.join - str << " recipients=#{recipients.inspect}" - str << " attachments=#{attachments.inspect}" - "#<#{self.class.to_s[/\w+$/]}#{str}>" - end - end -end - +require 'mapi/convert' diff --git a/lib/mapi/base.rb b/lib/mapi/base.rb new file mode 100644 index 0000000..f5410bd --- /dev/null +++ b/lib/mapi/base.rb @@ -0,0 +1,103 @@ +module Mapi + # + # Mapi::Item is the base class used for all mapi objects, and is purely a + # property set container + # + class Item + attr_reader :properties + alias props properties + + # +properties+ should be a PropertySet instance. + def initialize properties + @properties = properties + end + end + + # a general attachment class. is subclassed by Msg and Pst attachment classes + class Attachment < Item + def filename + props.attach_long_filename || props.attach_filename + end + + def data + @embedded_msg || @embedded_ole || props.attach_data + end + + # with new stream work, its possible to not have the whole thing in memory at one time, + # just to save an attachment + # + # a = msg.attachments.first + # a.save open(File.basename(a.filename || 'attachment'), 'wb') + def save io + raise "can only save binary data blobs, not ole dirs" if @embedded_ole + data.each_read { |chunk| io << chunk } + end + + def inspect + "#<#{self.class.to_s[/\w+$/]}" + + (filename ? " filename=#{filename.inspect}" : '') + + (@embedded_ole ? " embedded_type=#{@embedded_ole.embedded_type.inspect}" : '') + ">" + end + end + + class Recipient < Item + # some kind of best effort guess for converting to standard mime style format. + # there are some rules for encoding non 7bit stuff in mail headers. should obey + # that here, as these strings could be unicode + # email_address will be an EX:/ address (X.400?), unless external recipient. the + # other two we try first. + # consider using entry id for this too. + def name + name = props.transmittable_display_name || props.display_name + # dequote + name[/^'(.*)'/, 1] or name rescue nil + end + + def email + props.smtp_address || props.org_email_addr || props.email_address + end + + RECIPIENT_TYPES = { 0 => :orig, 1 => :to, 2 => :cc, 3 => :bcc } + def type + RECIPIENT_TYPES[props.recipient_type] + end + + def to_s + if name = self.name and !name.empty? and email && name != email + %{"#{name}" <#{email}>} + else + email || name + end + end + + def inspect + "#<#{self.class.to_s[/\w+$/]}:#{self.to_s.inspect}>" + end + end + + # i refer to it as a message (as does mapi), although perhaps Item is better, as its a more general + # concept than a message, as used in Pst files. though maybe i'll switch to using + # Mapi::Object as the base class there. + # + # IMessage essentially, but there's also stuff like IMAPIFolder etc. so, for this to form + # basis for PST Item, it'd need to be more general. + class Message < Item + # these 2 collections should be provided by our subclasses + def attachments + raise NotImplementedError + end + + def recipients + raise NotImplementedError + end + + def inspect + str = %w[message_class from to subject].map do |key| + " #{key}=#{props.send(key).inspect}" + end.compact.join + str << " recipients=#{recipients.inspect}" + str << " attachments=#{attachments.inspect}" + "#<#{self.class.to_s[/\w+$/]}#{str}>" + end + end +end