aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/ruby-msg/bin
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/ruby-msg/bin')
-rwxr-xr-xvendor/ruby-msg/bin/mapitool195
1 files changed, 195 insertions, 0 deletions
diff --git a/vendor/ruby-msg/bin/mapitool b/vendor/ruby-msg/bin/mapitool
new file mode 100755
index 000000000..79824daa4
--- /dev/null
+++ b/vendor/ruby-msg/bin/mapitool
@@ -0,0 +1,195 @@
+#! /usr/bin/ruby
+
+$:.unshift File.dirname(__FILE__) + '/../lib'
+
+require 'optparse'
+require 'rubygems'
+require 'mapi/msg'
+require 'mapi/pst'
+require 'mapi/convert'
+require 'time'
+
+class Mapitool
+ attr_reader :files, :opts
+ def initialize files, opts
+ @files, @opts = files, opts
+ seen_pst = false
+ raise ArgumentError, 'Must specify 1 or more input files.' if files.empty?
+ files.map! do |f|
+ ext = File.extname(f.downcase)[1..-1]
+ raise ArgumentError, 'Unsupported file type - %s' % f unless ext =~ /^(msg|pst)$/
+ raise ArgumentError, 'Expermiental pst support not enabled' if ext == 'pst' and !opts[:enable_pst]
+ [ext.to_sym, f]
+ end
+ if dir = opts[:output_dir]
+ Dir.mkdir(dir) unless File.directory?(dir)
+ end
+ end
+
+ def each_message(&block)
+ files.each do |format, filename|
+ if format == :pst
+ if filter_path = opts[:filter_path]
+ filter_path = filter_path.tr("\\", '/').gsub(/\/+/, '/').sub(/^\//, '').sub(/\/$/, '')
+ end
+ open filename do |io|
+ pst = Mapi::Pst.new io
+ pst.each do |message|
+ next unless message.type == :message
+ if filter_path
+ next unless message.path =~ /^#{Regexp.quote filter_path}(\/|$)/i
+ end
+ yield message
+ end
+ end
+ else
+ Mapi::Msg.open filename, &block
+ end
+ end
+ end
+
+ def run
+ each_message(&method(:process_message))
+ end
+
+ def make_unique filename
+ @map ||= {}
+ return @map[filename] if !opts[:individual] and @map[filename]
+ try = filename
+ i = 1
+ try = filename.gsub(/(\.[^.]+)$/, ".#{i += 1}\\1") while File.exist?(try)
+ @map[filename] = try
+ try
+ end
+
+ def process_message message
+ # TODO make this more informative
+ mime_type = message.mime_type
+ return unless pair = Mapi::Message::CONVERSION_MAP[mime_type]
+
+ combined_map = {
+ 'eml' => 'Mail.mbox',
+ 'vcf' => 'Contacts.vcf',
+ 'txt' => 'Posts.txt'
+ }
+
+ # TODO handle merged mode, pst, etc etc...
+ case message
+ when Mapi::Msg
+ if opts[:individual]
+ filename = message.root.ole.io.path.gsub(/msg$/i, pair.last)
+ else
+ filename = combined_map[pair.last] or raise NotImplementedError
+ end
+ when Mapi::Pst::Item
+ if opts[:individual]
+ filename = "#{message.subject.tr ' ', '_'}.#{pair.last}".gsub(/[^A-Za-z0-9.()\[\]{}-]/, '_')
+ else
+ filename = combined_map[pair.last] or raise NotImplementedError
+ filename = (message.path.tr(' /', '_.').gsub(/[^A-Za-z0-9.()\[\]{}-]/, '_') + '.' + File.extname(filename)).squeeze('.')
+ end
+ dir = File.dirname(message.instance_variable_get(:@desc).pst.io.path)
+ filename = File.join dir, filename
+ else
+ raise
+ end
+
+ if dir = opts[:output_dir]
+ filename = File.join dir, File.basename(filename)
+ end
+
+ filename = make_unique filename
+
+ write_message = proc do |f|
+ data = message.send(pair.first).to_s
+ if !opts[:individual] and pair.last == 'eml'
+ # we do the append > style mbox quoting (mboxrd i think its called), as it
+ # is the only one that can be robuslty un-quoted. evolution doesn't use this!
+ f.puts "From mapitool@localhost #{Time.now.rfc2822}"
+ #munge_headers mime, opts
+ data.each do |line|
+ if line =~ /^>*From /o
+ f.print '>' + line
+ else
+ f.print line
+ end
+ end
+ else
+ f.write data
+ end
+ end
+
+ if opts[:stdout]
+ write_message[STDOUT]
+ else
+ open filename, 'a', &write_message
+ end
+ end
+
+ def munge_headers mime, opts
+ opts[:header_defaults].each do |s|
+ key, val = s.match(/(.*?):\s+(.*)/)[1..-1]
+ mime.headers[key] = [val] if mime.headers[key].empty?
+ end
+ end
+end
+
+def mapitool
+ opts = {:verbose => false, :action => :convert, :header_defaults => []}
+ op = OptionParser.new do |op|
+ op.banner = "Usage: mapitool [options] [files]"
+ #op.separator ''
+ #op.on('-c', '--convert', 'Convert input files (default)') { opts[:action] = :convert }
+ op.separator ''
+ op.on('-o', '--output-dir DIR', 'Put all output files in DIR') { |d| opts[:output_dir] = d }
+ op.on('-i', '--[no-]individual', 'Do not combine converted files') { |i| opts[:individual] = i }
+ op.on('-s', '--stdout', 'Write all data to stdout') { opts[:stdout] = true }
+ op.on('-f', '--filter-path PATH', 'Only process pst items in PATH') { |path| opts[:filter_path] = path }
+ op.on( '--enable-pst', 'Turn on experimental PST support') { opts[:enable_pst] = true }
+ #op.on('-d', '--header-default STR', 'Provide a default value for top level mail header') { |hd| opts[:header_defaults] << hd }
+ # --enable-pst
+ op.separator ''
+ op.on('-v', '--[no-]verbose', 'Run verbosely') { |v| opts[:verbose] = v }
+ op.on_tail('-h', '--help', 'Show this message') { puts op; exit }
+ end
+
+ files = op.parse ARGV
+
+ # for windows. see issue #2
+ STDOUT.binmode
+
+ Mapi::Log.level = Ole::Log.level = opts[:verbose] ? Logger::WARN : Logger::FATAL
+
+ tool = begin
+ Mapitool.new(files, opts)
+ rescue ArgumentError
+ puts $!
+ puts op
+ exit 1
+ end
+
+ tool.run
+end
+
+mapitool
+
+__END__
+
+mapitool [options] [files]
+
+files is a list of *.msg & *.pst files.
+
+one of the options should be some sort of path filter to apply to pst items.
+
+--filter-path=
+--filter-type=eml,vcf
+
+with that out of the way, the entire list of files can be converted into a
+list of items (with meta data about the source).
+
+--convert
+--[no-]separate one output file per item or combined output
+--stdout
+--output-dir=.
+
+