diff options
Diffstat (limited to 'vendor/ruby-msg')
25 files changed, 0 insertions, 9486 deletions
diff --git a/vendor/ruby-msg/ChangeLog b/vendor/ruby-msg/ChangeLog deleted file mode 100644 index fb502127a..000000000 --- a/vendor/ruby-msg/ChangeLog +++ /dev/null @@ -1,82 +0,0 @@ -== 1.4.0 / 2008-10-12 - -- Initial simple msg test case. -- Update TODO, stripping out all the redundant ole stuff. -- Fix property set guids to use the new Ole::Types::Clsid type. -- Add block form of Msg.open -- Fix file requires for running tests individually. -- Update pst RangesIO subclasses for changes in ruby-ole. -- Merge initial pst reading code (converted from libpst). -- Pretty big pst refactoring, adding initial outlook 2003 pst support. -- Flesh out move to mapi to clean up the way pst hijacks the msg - classes currently. -- Add a ChangeLog :). -- Update README, by converting Home.wiki with wiki2rdoc converter. -- Separate out generic mapi object code from msg code, and separate out - conversion code. -- Add decent set of Mapi and Msg unit tests, approaching ~55% code coverage, - not including pst. -- Add TMail note conversion alternative, to eventually allow removal of - custom Mime class. -- Expose experimental pst support through renamed mapitool program. - -== 1.3.1 / 2007-08-21 - -- Add fix for issue #2, and #4. -- Move ole code to ruby-ole project, and depend on it. - -== 1.2.17 / 2007-05-13 - -(This was last release before splitting out ruby-ole. subsequent bug fix -point releases 1-3 were made directly on the gem, not reflected in the -repository, though the fixes were also forward-ported.) - -- Update Ole::Storage backend, finalising api for split to separate - library. - -== 1.2.16 / 2007-04-28 - -- Some minor fixes to msg parser. -- Extending RTF and body conversion support. -- Initial look at possible wmf conversion for embedded images. -- Add initial cli converter tool -- Add rdoc to ole/storage, and msg/properties -- Add streaming IO support to Ole::Storage, and use it in Msg::Properties -- Updates to test cases -- Add README, and update TODO -- Convert rtf support tools in c to small ruby class. -- Merge preliminary write support for Ole::Storage, as well as preliminary - filesystem api. - -== 1.2.13 / 2007-01-22 - -- Nested msg support - -== 1.2.10 / 2007-01-21 - -- Add initial vcard support. -- Implement a named properties map, for vcard conversion. -- Add orderedhash to Mime for keeping header order -- Fix line endings in lib/mime -- First released version - -== <= 1.2.9 / 2007-01-11..2007-01-19 - -(Haven't bothered to note exact versions and dates - nothing here was released. -can look at history of lib/msg.rb to see exact VERSION at each commit.) - -- Merged most of the named property work. -- Added some test files. -- Update svn:ignore, to exclude test messages and ole files which I can't - release. Need to get some clean files for use in test cases. - Also excluding source to the mapitags files for the moment. - A lot of it is not redistributable -- Added a converter to extract embedded html in rtf. Downloaded somewhere, - source unknown. -- Minor fix to ole/storage.rb, after new OleDir#type behaviour -- Imported support.rb, replacing previously required std.rb -- Added initial support for parsing times in Msg::Properties. -- Imported some rtf decompression code and minor updates. -- Cleaned up the ole class a bit -- Fixed OleDir#data method using sb_blocks map (see POLE). - diff --git a/vendor/ruby-msg/FIXES b/vendor/ruby-msg/FIXES deleted file mode 100644 index 7a094b437..000000000 --- a/vendor/ruby-msg/FIXES +++ /dev/null @@ -1,56 +0,0 @@ -FIXES - -recent fixes based on importing results into evolution - -1. was running into some issue with base64 encoded message/rfc822 attachments displaying - as empty. encoding them as plain solved the issue (odd). - -2. problem with a large percentage of emails, not displaying as mime. turned out to be - all received from blackberry. further, turned out there was 2 content-type headers, - "Content-Type", which I add, and "Content-type". normally my override works, but I - need to handle it case insensitvely it would appear. more tricky, whats the story - with these. fixing that will probably fix that whole class of issues there. - evolution was renaming my second content type as X-Invalid-Content-Type or something. - -3. another interesting one. had content-transfer-encoding set in the transport message - headers. it was set to base64. i didn't override that, so evolution "decoded" my - plaintext message into complete garbage. - fix - delete content-transfer-encoding. - -4. added content-location and content-id output in the mime handling of attachments - to get some inline html/image mails to work properly. - further, the containing mime content-type must be multipart/related, not multipart/mixed, - at least for evolution, in order for the images to appear inline. - could still improve in this area. if someone drags and drops in an image, it may - be inline in the rtf version, but exchanges generates crappy html such that the image - doesn't display inline. maybe i should correct the html output in these cases as i'm - throwing away the rtf version. - -5. note you may need wingdings installed. i had a lot of L and J appear in messages from - outlook users. turns out its smilies in wingdings. i think its only if word is used - as email editor and has autotext messing things up. - -6. still unsure about how to do my "\r" handling. - -7. need to join addresses with , instead of ; i think. evolution only shows the - first one otherwise it appears, but all when they are , separated. - -8. need to solve ole storage issues with the very large file using extra bat - stuff. - -9. retest a bit on evolution and thunderbird, and release. tested on a corups - of >1000 msg files, so should be starting to get pretty good quality. - -10. longer term, things fall into a few basic categories: - -- non mail conversions (look further into vcard, ical et al support for other - types of msg) -- further tests and robustness for what i handle now. ie, look into corner - cases covered so far, and work on the mime code. fix random charset encoding - issues, in the various weird mime ways, do header wrapping etc etc. - check fidelity of conversions, and capture some more properties as headers, - such as importance which i don't do yet. -- fix that named property bug. tidy up warnings, exceptions. -- extend conversion to make better html. - this is longer term. as i don't use the rtf, i need to make my html better. - emulating some rtf things. harder, not important atm. diff --git a/vendor/ruby-msg/README b/vendor/ruby-msg/README deleted file mode 100644 index bd16dfcc4..000000000 --- a/vendor/ruby-msg/README +++ /dev/null @@ -1,128 +0,0 @@ -= Introduction - -Generally, the goal of the project is to enable the conversion of -msg and pst files into standards based formats, without reliance on -outlook, or any platform dependencies. In fact its currently <em>pure -ruby</em>, so it should be easy to get running. - -It is targeted at people who want to migrate their PIM data from outlook, -converting msg and pst files into rfc2822 emails, vCard contacts, -iCalendar appointments etc. However, it also aims to be a fairly complete -mapi message store manipulation library, providing a sane model for -(currently read-only) access to msg and pst files (message stores). - -I am happy to accept patches, give commit bits etc. - -Please let me know how it works for you, any feedback would be welcomed. - -= Features - -Broad features of the project: - -* Can be used as a general mapi library, where conversion to and working - on a standard format doesn't make sense. - -* Supports conversion of messages to standard formats, like rfc2822 - emails, vCard, etc. - -* Well commented, and easily extended. - -* Basic RTF converter, for providing a readable body when only RTF - exists (needs work) - -* RTF decompression support included, as well as HTML extraction from - RTF where appropriate (both in pure ruby, see <tt>lib/mapi/rtf.rb</tt>) - -* Support for mapping property codes to symbolic names, with many - included. - -Features of the msg format message store: - -* Most key .msg structures are understood, and the only the parsing - code should require minor tweaks. Most of remaining work is in achieving - high-fidelity conversion to standards formats (see [TODO]). - -* Supports both types of property storage (large ones in +substg+ - files, and small ones in the +properties+ file. - -* Complete support for named properties in different GUID namespaces. - -* Initial support for handling embedded ole files, converting nested - .msg files to message/rfc822 attachments, and serializing others - as ole file attachments (allows you to view embedded excel for example). - -Features of the pst format message store: - -* Handles both Outlook 1997 & 2003 format pst files, both with no- - and "compressible-" encryption. - -* Understanding of the file format is still very superficial. - -= Usage - -At the command line, it is simple to convert individual msg or pst -files to .eml, or to convert a batch to an mbox format file. See mapitool -help for details: - - mapitool -si some_email.msg > some_email.eml - mapitool -s *.msg > mbox - -There is also a fairly complete and easy to use high level library -access: - - require 'mapi/msg' - - msg = Mapi::Msg.open filename - - # access to the 3 main data stores, if you want to poke with the msg - # internals - msg.recipients - # => [#<Recipient:'\'Marley, Bob\' <bob.marley@gmail.com>'>] - msg.attachments - # => [#<Attachment filename='blah1.tif'>, #<Attachment filename='blah2.tif'>] - msg.properties - # => #<Properties ... normalized_subject='Testing' ... - # creation_time=#<DateTime: 2454042.45074714,0,2299161> ...> - -To completely abstract away all msg peculiarities, convert the msg -to a mime object. The message as a whole, and some of its main parts -support conversion to mime objects. - - msg.attachments.first.to_mime - # => #<Mime content_type='application/octet-stream'> - mime = msg.to_mime - puts mime.to_tree - # => - - #<Mime content_type='multipart/mixed'> - |- #<Mime content_type='multipart/alternative'> - | |- #<Mime content_type='text/plain'> - | \- #<Mime content_type='text/html'> - |- #<Mime content_type='application/octet-stream'> - \- #<Mime content_type='application/octet-stream'> - - # convert mime object to serialised form, - # inclusive of attachments etc. (not ideal in memory, but its wip). - puts mime.to_s - -= Thanks - -* The initial implementation of parsing msg files was based primarily - on msgconvert.pl[http://www.matijs.net/software/msgconv/]. - -* The basis for the outlook 97 pst file was the source to +libpst+. - -* The code for rtf decompression was implemented by inspecting the - algorithm used in the +JTNEF+ project. - -= Other - -For more information, see - -* TODO - -* MsgDetails[http://code.google.com/p/ruby-msg/wiki/MsgDetails] - -* PstDetails[http://code.google.com/p/ruby-msg/wiki/PstDetails] - -* OleDetails[http://code.google.com/p/ruby-ole/wiki/OleDetails] - diff --git a/vendor/ruby-msg/Rakefile b/vendor/ruby-msg/Rakefile deleted file mode 100644 index 066ca3741..000000000 --- a/vendor/ruby-msg/Rakefile +++ /dev/null @@ -1,77 +0,0 @@ -require 'rake/rdoctask' -require 'rake/testtask' -require 'rake/packagetask' -require 'rake/gempackagetask' - -require 'rbconfig' -require 'fileutils' - -$:.unshift 'lib' - -require 'mapi/msg' - -PKG_NAME = 'ruby-msg' -PKG_VERSION = Mapi::VERSION - -task :default => [:test] - -Rake::TestTask.new(:test) do |t| - t.test_files = FileList["test/test_*.rb"] - ['test/test_pst.rb'] - t.warning = false - t.verbose = true -end - -begin - require 'rcov/rcovtask' - # NOTE: this will not do anything until you add some tests - desc "Create a cross-referenced code coverage report" - Rcov::RcovTask.new do |t| - t.test_files = FileList['test/test*.rb'] - t.ruby_opts << "-Ilib" # in order to use this rcov - t.rcov_opts << "--xrefs" # comment to disable cross-references - t.rcov_opts << "--exclude /usr/local/lib/site_ruby" - t.verbose = true - end -rescue LoadError - # Rcov not available -end - -Rake::RDocTask.new do |t| - t.rdoc_dir = 'doc' - t.title = "#{PKG_NAME} documentation" - t.options += %w[--main README --line-numbers --inline-source --tab-width 2] - t.rdoc_files.include 'lib/**/*.rb' - t.rdoc_files.include 'README' -end - -spec = Gem::Specification.new do |s| - s.name = PKG_NAME - s.version = PKG_VERSION - s.summary = %q{Ruby Msg library.} - s.description = %q{A library for reading and converting Outlook msg and pst files (mapi message stores).} - s.authors = ["Charles Lowe"] - s.email = %q{aquasync@gmail.com} - s.homepage = %q{http://code.google.com/p/ruby-msg} - s.rubyforge_project = %q{ruby-msg} - - s.executables = ['mapitool'] - s.files = FileList['data/*.yaml', 'Rakefile', 'README', 'FIXES'] - s.files += FileList['lib/**/*.rb', 'test/test_*.rb', 'bin/*'] - - s.has_rdoc = true - s.extra_rdoc_files = ['README'] - s.rdoc_options += ['--main', 'README', - '--title', "#{PKG_NAME} documentation", - '--tab-width', '2'] - - s.add_dependency 'ruby-ole', '>=1.2.8' - s.add_dependency 'vpim', '>=0.360' -end - -Rake::GemPackageTask.new(spec) do |p| - p.gem_spec = spec - p.need_tar = false #true - p.need_zip = false - p.package_dir = 'build' -end - diff --git a/vendor/ruby-msg/TODO b/vendor/ruby-msg/TODO deleted file mode 100644 index 2e4309c21..000000000 --- a/vendor/ruby-msg/TODO +++ /dev/null @@ -1,184 +0,0 @@ -= Newer Msg - -* a lot of the doc is out of sync given the Mapi:: changes lately. need to - fix. - -* extend msgtool with support for the other kinds of msg files. things like, - - dump properties to yaml / xml (with option on how the keys should be dumped). - should be fairly easy to implement. hash, with array of attach & recips. - - just write out the mime type - - convert to the automatically guessed output type, also allowing an override - of some sort. have a batch mode that converts all arguments, using automatic - extensions, eg .vcf, .eml etc. - - options regarding preferring rtf / html / txt output for things. like, eg - the output for note conversion, will be one of them i guess. - -* fix nameid handling for sub Properties objects. needs to inherit top-level @nameid. - -* better handling for "Untitled Attachments", or attachments with no filename at all. - maybe better handling in general for attached messages. maybe re-write filename with - subject. - -* do the above 2, then go for a new release. - for this release, i want it to be pretty robust, and have better packaging. - have the gem install 2 tools - oletool (--tree, --read, --write, --repack) - and msgtool (--convert, --dump-attachments etc) - fix docs, add option parsing etc etc. - submit to the usual gem repositories etc, announce project as usable. - -* better handling for other types of embedded ole attachments. try to recognise .wmf to - start with. etc. 2 goals, form .eml, and for .rtf output. - -* rtf to text support, initially. just simple strip all the crap out approach. maybe html - later on. sometimes the only body is rtf, which is problematic. is rtf an allowed body - type? - -* better encoding support (i'm thinking, check some things like m-dash in the non-wide - string type. is it windows codepage?. how to know code page in general? change - ENCODER[] to convert these to utf8 i think). I'm trying to just move everything to utf8. - then i need to make sure the mime side of that holds up. - -* certain parsing still not correct, especially small properties directory, - things like bools, multiavlue shorts etc. - -* test cases for msg/properties.rb msg/rtf.rb and mime.rb -* regarding the mime fix ups. check out: - -- http://rubyforge.org/projects/rubymail/, and -- http://rubyforge.org/projects/mime-alt-lite/ - -both haven't been touched in 2 years though. - -* get some sort of working From: header - there doesn't appear to be a way to get an smtp address for the sender in an - internal mail. you need to query the exchanger server, using the sender_entryid - as far as i can tell. - you may also get these so called "X.400" addresses for external recipients - that are on the GAL (Global Address List), as custom recipients. - (mostly complete. better way?) -* check lots of little details: encoding issues with code pages etc other - than ascii stuff. consider Msg, Mime, Vcard etc, to check its clean. check - timezones, inaccuracies in date handling. -* http://msdn2.microsoft.com/en-us/library/ms526761.aspx - import guids for these? -PS_ROUTING_EMAIL_ADDRESSES -PS_ROUTING_ADDRTYPE -PS_ROUTING_SEARCH_KEY -PS_ROUTING_DISPLAY_NAME -PS_ROUTING_ENTRYID -* check this thing i wrote: - creating ones in ps_mapi works strangely, as ps_mapi is the top levels ones. - don't get entries in nameid. as should match the definitions. - however still get allocated an 8 number. that number becomes permanent... -* do something about the message class-specific range, 0x6800 through 0x7FFF. -* multivalue encoding may explain some of the unknown data in properties objs -* get some clean test msgs from somewhere -* tackle other types of msgs, such as appointments, contacts etc, converting - to their appropriate standard types too. - would like to look at this next. see about the content specific range - http://en.wikipedia.org/wiki/ICalendar - is it better/easier to go through micro formats? there are libraries for ruby - already i think. check this out. although using IMC standards seem to make - more sense. encoding issues? - try contact => vcf, - note => ?? icalendar. VTODO? / VJOURNAL? - appointment => VEVENT? - (initial try done. really basic vcard output supported. not difficult) -* ole code is suppopsed to be able to return guids for something too. supporting - all this probably means creating a new file for ole/types.rb, containing all - the various classes, and binary conversion code. -* some dubiously useful info about some unknown codes i wrote: -unknown property 5ff6 - * appears to be equal to display_name, and transmitable_display_name -unknown property 5ff7 - * recipient.properties[0x5ff7].upcase == recipient.properties.entryid - is equivalent, but not all uppercase. - everything else is upper though. maybe a displayname kind of thing. -* common relationship - CGI.escape(msg.properties.subject.strip).tr('+', ' ') + '.EML' == msg.properties.url_comp_name - -(28 bytes binary data and msg.properties.sender_email_address and "\000") -entryids are a strange format. for internal or from exchange whatever, they have that -EX:/O=XXXXXX/... -otherwise, they may have SMTP in them. - such as msg.properties.sent_representing_search_key - == "SMTP:SOMEGUY@XXX.COM\000" - but Ole::UTF16_TO_UTF8[msg2.properties.sender_entryid[/.*\000\000(.+)\000/, 1][0..-2]] - == "SomeGuy@XXX.COM" - for external people, entry ids have displayname and address. - -longer term, i want to investigate the overlap with PST stuff, like libpst, -which seems to be another kind of mapi tag property storage, and try to -understand the relationship with existing TNEF work also. - -hmmmm for future work: -http://blogs.msdn.com/stephen_griffin/archive/2005/10/25/484656.aspx - - -= Older - -- set 'From' in Msg#populate_headers. - Notes: - # ways to get the sender of a mail. - # if external, you can do this (different for internal). - name, protocol, email = Ole::UTF16_TO_UTF8[msg.props.sender_entryid[24..-1]].split(/\x00/) - # here is an excerpt from a yaml dump. - # need to consider how to get it. also when its a draft, and other stuff. - creator_name: - sent_representing_name: - last_modifier_name: - sender_email_address: - sent_representing_email_address: - sender_name: -- fill out some of the tag holes. mostly done -- properly integrate rtf decompression, and the html conversion from rtf -- figure out some things, like entryids, and the properties directories, - and the ntsecurity data 0e27. - http://peach.ease.lsoft.com/scripts/wa.exe?A2=ind0207&L=mapi-l&P=24515 - "In case anybody is interested, Exchange stores PR_NT_SECURITY_DESCRIPTOR as a header plus the regular self=-relative SECURITY_DESCRIPTOR structure. The first two bytes of the header (WORD) is the length of the header; Read these two bytes to find out how many bytes you must skip to get to the real data. Many thanks to Stephen Griffin for this info." - using outlook spy gives an actual dump. for example: - << - Control: SE_DACL_AUTO_INHERITED | SE_DACL_DEFAULTED | SE_DACL_PRESENT | SE_GROUP_DEFAULTED | SE_OWNER_DEFAULTED | SE_SACL_AUTO_INHERITED | SE_SACL_DEFAULTED | SE_SELF_RELATIVE - Owner: - SID: S-1-5-21-1004336348-602609370-725345543-44726 - Name: lowecha - DomainName: XXX - Group: - SID: S-1-5-21-1004336348-602609370-725345543-513 - Name: Domain Users - DomainName: XXX - Dacl: - Header: - AceType: ACCESS_DENIED_ACE_TYPE - AceFlags: INHERITED_ACE - Mask: fsdrightReadBody (fsdrightListContents) | fsdrightWriteBody (fsdrightCreateItem) | fsdrightAppendMsg (fsdrightCreateContainer) | fsdrightReadProperty | fsdrightWriteProperty | fsdrightExecute | fsdrightReadAttributes | fsdrightWriteAttributes | fsdrightWriteOwnProperty | fsdrightDeleteOwnItem | fsdrightViewItem | fsdrightWriteSD | fsdrightDelete | fsdrightWriteOwner | fsdrightReadControl | fsdrightSynchronize - Sid: - SID: S-1-5-7 - Name: ANONYMOUS LOGON - DomainName: NT AUTHORITY - >> - Not something i care about at the moment. - -- conversion of inline images. - Content-Location, cid: urls etc etc. - what would be cool, is conversion of outlooks text/rtf's only real "feature" over - text/html - convert inline attachments to be <a href> links, using cid: urls to the - actual content data, and using an <img with cid: url to a converted image from the - attach_rendering property (image data), along with the text itself. (although i think - the rendering may actually include the text ??. that would explain why its always clipped. - can these be used for contact pictures too? -- entryid format cf. entry_id.h. another serialized structure. - entryids are for the addressbook connection. EMS (exchange message something), AB - address book. MUIDEMSAB. makes sense. - -mapidefs.h: - - 174 /* Types of message receivers */ - 175 #ifndef MAPI_ORIG - 176 #define MAPI_ORIG 0 /* The original author */ - 177 #define MAPI_TO 1 /* The primary message receiver */ - 178 #define MAPI_CC 2 /* A carbon copy receiver */ - 179 #define MAPI_BCC 3 /* A blind carbon copy receiver */ - 180 #define MAPI_P1 0x10000000 /* A message resend */ - 181 #define MAPI_SUBMITTED 0x80000000 /* This message has already been sent */ - 182 #endif diff --git a/vendor/ruby-msg/bin/mapitool b/vendor/ruby-msg/bin/mapitool deleted file mode 100755 index 79824daa4..000000000 --- a/vendor/ruby-msg/bin/mapitool +++ /dev/null @@ -1,195 +0,0 @@ -#! /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=. - - diff --git a/vendor/ruby-msg/contrib/rtf2html.c b/vendor/ruby-msg/contrib/rtf2html.c deleted file mode 100644 index 937e22ff1..000000000 --- a/vendor/ruby-msg/contrib/rtf2html.c +++ /dev/null @@ -1,155 +0,0 @@ -#include <stdio.h> -#define bool int -#define false 0 -#define true 1 - -// RTF/HTML functions -// -------------------- -// -// Sometimes in MAPI, the PR_BODY_HTML property contains the HTML of a message. -// But more usually, the HTML is encoded inside the RTF body (which you get in the -// PR_RTF_COMPRESSED property). These routines concern the decoding of the HTML -// from this RTF body. -// -// An encoded htmlrtf file is a valid RTF document, but which contains additional -// html markup information in its comments, and sometimes contains the equivalent -// rtf markup outside the comments. Therefore, when it is displayed by a plain -// simple RTF reader, the html comments are ignored and only the rtf markup has -// effect. Typically, this rtf markup is not as rich as the html markup would have been. -// But for an html-aware reader (such as the code below), we can ignore all the -// rtf markup, and extract the html markup out of the comments, and get a valid -// html document. -// -// There are actually two kinds of html markup in comments. Most of them are -// prefixed by "\*\htmltagNNN", for some number NNN. But sometimes there's one -// prefixed by "\*\mhtmltagNNN" followed by "\*\htmltagNNN". In this case, -// the two are equivalent, but the m-tag is for a MIME Multipart/Mixed Message -// and contains tags that refer to content-ids (e.g. img src="cid:072344a7") -// while the normal tag just refers to a name (e.g. img src="fred.jpg") -// The code below keeps the m-tag and discards the normal tag. -// If there are any m-tags like this, then the message also contains an -// attachment with a PR_CONTENT_ID property e.g. "072344a7". Actually, -// sometimes the m-tag is e.g. img src="http://outlook/welcome.html" and the -// attachment has a PR_CONTENT_LOCATION "http://outlook/welcome.html" instead -// of a PR_CONTENT_ID. -// -// This code is experimental. It works on my own message archive, of about -// a thousand html-encoded messages, received in Outlook97 and Outlook2000 -// and OutlookXP. But I can't guarantee that it will work on all rtf-encoded -// messages. Indeed, it used to be the case that people would simply stick -// {\fromhtml at the start of an html document, and } at the end, and send -// this as RTF. If someone did this, then it will almost work in my function -// but not quite. (Because I ignore \r and \n, and respect only \par. Thus, -// any linefeeds in the erroneous encoded-html will be ignored.) - - - - - -// ISRTFHTML -- Given an uncompressed RTF body of the message, this -// function tells you whether it encodes some html. -// [in] (buf,*len) indicate the start and length of the uncompressed RTF body. -// [return-value] true or false, for whether it really does encode some html -bool isrtfhtml(const char *buf,unsigned int len) -{ // We look for the words "\fromhtml" somewhere in the file. - // If the rtf encodes text rather than html, then instead - // it will only find "\fromtext". - const char *c; - for (c=buf; c<buf+len; c++) - { if (strncmp(c,"\\from",5)==0) return strncmp(c,"\\fromhtml",9)==0; - } - return false; -} - - - - -// DECODERTFHTML -- Given an uncompressed RTF body of the message, -// and assuming that it contains encoded-html, this function -// turns it onto regular html. -// [in] (buf,*len) indicate the start and length of the uncompressed RTF body. -// [out] the buffer is overwritten with the HTML version, null-terminated, -// and *len indicates the length of this HTML. -// -// Notes: (1) because of how the encoding works, the HTML version is necessarily -// shorter than the encoded version. That's why it's safe for the function to -// place the decoded html in the same buffer that formerly held the encoded stuff. -// (2) Some messages include characters \'XX, where XX is a hexedecimal number. -// This function simply converts this into ASCII. The conversion will only make -// sense if the right code-page is being used. I don't know how rtf specifies which -// code page it wants. -// (3) By experiment, I discovered that \pntext{..} and \liN and \fi-N are RTF -// markup that should be removed. There might be other RTF markup that should -// also be removed. But I don't know what else. -// -void decodertfhtml(char *buf,unsigned int *len) -{ // c -- pointer to where we're reading from - // d -- pointer to where we're writing to. Invariant: d<c - // max -- how far we can read from (i.e. to the end of the original rtf) - // ignore_tag -- stores 'N': after \mhtmlN, we will ignore the subsequent \htmlN. - char *c=buf, *max=buf+*len, *d=buf; int ignore_tag=-1; - // First, we skip forwards to the first \htmltag. - while (c<max && strncmp(c,"{\\*\\htmltag",11)!=0) c++; - // - // Now work through the document. Our plan is as follows: - // * Ignore { and }. These are part of RTF markup. - // * Ignore \htmlrtf...\htmlrtf0. This is how RTF keeps its equivalent markup separate from the html. - // * Ignore \r and \n. The real carriage returns are stored in \par tags. - // * Ignore \pntext{..} and \liN and \fi-N. These are RTF junk. - // * Convert \par and \tab into \r\n and \t - // * Convert \'XX into the ascii character indicated by the hex number XX - // * Convert \{ and \} into { and }. This is how RTF escapes its curly braces. - // * When we get \*\mhtmltagN, keep the tag, but ignore the subsequent \*\htmltagN - // * When we get \*\htmltagN, keep the tag as long as it isn't subsequent to a \*\mhtmltagN - // * All other text should be kept as it is. - while (c<max) - { if (*c=='{') c++; - else if (*c=='}') c++; - else if (strncmp(c,"\\*\\htmltag",10)==0) - { c+=10; int tag=0; while (*c>='0' && *c<='9') {tag=tag*10+*c-'0'; c++;} - if (*c==' ') c++; - if (tag==ignore_tag) {while (c<max && *c!='}') c++; if (*c=='}') c++;} - ignore_tag=-1; - } - else if (strncmp(c,"\\*\\mhtmltag",11)==0) - { c+=11; int tag=0; while (*c>='0' && *c<='9') {tag=tag*10+*c-'0'; c++;} - if (*c==' ') c++; - ignore_tag=tag; - } - else if (strncmp(c,"\\par",4)==0) {strcpy(d,"\r\n"); d+=2; c+=4; if (*c==' ') c++;} - else if (strncmp(c,"\\tab",4)==0) {strcpy(d," "); d+=3; c+=4; if (*c==' ') c++;} - else if (strncmp(c,"\\li",3)==0) - { c+=3; while (*c>='0' && *c<='9') c++; if (*c==' ') c++; - } - else if (strncmp(c,"\\fi-",4)==0) - { c+=4; while (*c>='0' && *c<='9') c++; if (*c==' ') c++; - } - else if (strncmp(c,"\\'",2)==0) - { unsigned int hi=c[2], lo=c[3]; - if (hi>='0' && hi<='9') hi-='0'; else if (hi>='A' && hi<='Z') hi-='A'; else if (hi>='a' && hi<='z') hi-='a'; - if (lo>='0' && lo<='9') lo-='0'; else if (lo>='A' && lo<='Z') lo-='A'; else if (lo>='a' && lo<='z') lo-='a'; - *((unsigned char*)d) = (unsigned char)(hi*16+lo); - c+=4; d++; - } - else if (strncmp(c,"\\pntext",7)==0) {c+=7; while (c<max && *c!='}') c++;} - else if (strncmp(c,"\\htmlrtf",8)==0) - { c++; while (c<max && strncmp(c,"\\htmlrtf0",9)!=0) c++; - if (c<max) c+=9; if (*c==' ') c++; - } - else if (*c=='\r' || *c=='\n') c++; - else if (strncmp(c,"\\{",2)==0) {*d='{'; d++; c+=2;} - else if (strncmp(c,"\\}",2)==0) {*d='}'; d++; c+=2;} - else {*d=*c; c++; d++;} - } - *d=0; d++; - *len = d-buf; -} - - -void main() -{ - unsigned char buf[1024*1024]; - int len = fread(buf, 1, 1024*1024, stdin); - decodertfhtml(buf, &len); - fwrite(buf, 1, len, stdout); -} diff --git a/vendor/ruby-msg/contrib/rtfdecompr.c b/vendor/ruby-msg/contrib/rtfdecompr.c deleted file mode 100644 index 633d50286..000000000 --- a/vendor/ruby-msg/contrib/rtfdecompr.c +++ /dev/null @@ -1,105 +0,0 @@ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -void decompress_rtf(FILE *srcf) -{ -// #define prebuf_len (sizeof(prebuf)) -// static unsigned char prebuf[] = - - // the window of decompressed bytes that can be referenced for copies. - // moved to this rather than indexing directly into output for streaming. - // circular buffer. - // because we use single-function call approach, no need for copy. - // if using libstream-3, i would have a few options. i would be part of - // the filter interface, which doesn't care if it is reading or writing, - // all it knows about is its input and output buffers. we can't just - // flush some data to the output buffer in that scenario, so we would need - // to keep the window around. we also can't guarantee availability of that - // buffer. so, we would probably have a instance member which would be - // this -> - unsigned char buf[4096] = - "{\\rtf1\\ansi\\mac\\deff0\\deftab720{\\fonttbl;}" - "{\\f0\\fnil \\froman \\fswiss \\fmodern \\fscript " - "\\fdecor MS Sans SerifSymbolArialTimes New RomanCourier" - "{\\colortbl\\red0\\green0\\blue0\n\r\\par " - "\\pard\\plain\\f0\\fs20\\b\\i\\u\\tab\\tx"; - - #define BUF_MASK 4095 - - int wp = strlen((char *)buf); - - unsigned char *dst; // destination for uncompressed bytes - int in = 0; // current position in src array - int out = 0; // current position in dst array - - unsigned char hdr[16]; - int got; - // get header fields (as defined in RTFLIB.H) - got = fread(hdr, 1, 16, srcf); - if (got != 16) { - printf("Invalid compressed-RTF header\n"); - exit(1); - } - - int compr_size = *(unsigned int *)(hdr); - int uncompr_size = *(unsigned int *)(hdr + 4); - int magic = *(unsigned int *)(hdr + 8); - long crc32 = *(unsigned int *)(hdr + 12); - - unsigned char *x, *y;; - unsigned char *src = malloc(compr_size - 12); // includes the 3 header fields - y = src; - x = src + compr_size - 12; - got = fread(src, 1, compr_size - 12, srcf); - if (got != compr_size - 12) { - printf("compressed-RTF data size mismatch (%d != %d)\n", got, compr_size - 12); - exit(1); - } - // shouldn't be any more than that - got = fread(dst, 1, 16, srcf); - if (got > 0) { - printf("warning: data after the size\n"); - } - - // process the data - if (magic == 0x414c454d) { // magic number that identifies the stream as a uncompressed stream - dst = malloc(uncompr_size); - memcpy(dst, src, uncompr_size); - } - else if (magic == 0x75465a4c) { // magic number that identifies the stream as a compressed stream - out = 0; //strlen(prebuf); - int dst_len; - dst = malloc(dst_len = uncompr_size); - - int flagCount = 0; - int flags = 0; - while (out < dst_len && src < x) { - // each flag byte flags 8 literals/references, 1 per bit - flags = (flagCount++ % 8 == 0) ? *src++ : flags >> 1; - if (flags & 1) { // each flag bit is 1 for reference, 0 for literal - int rp = *src++; - int l = *src++; - //offset is a 12 byte number. 2^12 is 4096, so thats fine - rp = (rp << 4) | (l >> 4); // the offset relative to block start - l = (l & 0xf) + 2; // the number of bytes to copy - int e = rp + l; - while (rp < e) - putchar(buf[wp++ & BUF_MASK] = buf[rp++ & BUF_MASK]); - } - else putchar(buf[wp++ & BUF_MASK] = *src++); - } - } - else { // unknown magic number - printf("Unknown compression type (magic number %04x)", magic); - } - - free(y); -} - -int main(int argc, char *argv[]) -{ - FILE *file = fopen(argv[1], "rb"); - decompress_rtf(file); - fclose(file); -} diff --git a/vendor/ruby-msg/contrib/wmf.rb b/vendor/ruby-msg/contrib/wmf.rb deleted file mode 100644 index 531e5fc99..000000000 --- a/vendor/ruby-msg/contrib/wmf.rb +++ /dev/null @@ -1,107 +0,0 @@ - -# this file will be used later to enhance the msg conversion. - -# doesn't really work very well.... - -def wmf_getdimensions wmf_data - # check if we have a placeable metafile - if wmf_data.unpack('L')[0] == 0x9ac6cdd7 - # do check sum test - shorts = wmf_data.unpack 'S11' - warn 'bad wmf header checksum' unless shorts.pop == shorts.inject(0) { |a, b| a ^ b } - # determine dimensions - left, top, right, bottom, twips_per_inch = wmf_data[6, 10].unpack 'S5' - p [left, top, right, bottom, twips_per_inch] - [right - left, bottom - top].map { |i| (i * 96.0 / twips_per_inch).round } - else - [nil, nil] - end -end - -=begin - -some attachment stuff -rendering_position -object_type -attach_num -attach_method - -rendering_position is around (1 << 32) - 1 if its inline - -attach_method 1 for plain data? -attach_method 6 for embedded ole - -display_name instead of reading the embedded ole type. - - -PR_RTF_IN_SYNC property is missing or set to FALSE. - - -Before reading from the uncompressed RTF stream, sort the message's attachment -table on the value of the PR_RENDERING_POSITION property. The attachments will -now be in order by how they appear in the message. - -As your client scans through the RTF stream, check for the token "\objattph". -The character following the token is the place to put the next attachment from -the sorted table. Handle attachments that have set their PR_RENDERING_POSITION -property to -1 separately. - -eg from rtf. - -\b\f2\fs20{\object\objemb{\*\objclass PBrush}\objw1320\objh1274{\*\objdata -01050000 <- looks like standard header -02000000 <- not sure -07000000 <- this means length of following is 7. -50427275736800 <- Pbrush\000 in hex -00000000 <- ? -00000000 <- ? -e0570000 <- this is 22496. length of the following in hex -this is the bitmap data, starting with BM.... -424dde57000000000000360000002800000058000000550000000100180000000000a857000000 -000000000000000000000000000000c8d0d4c8d0d4c8d0d4c8d0d4c8d0d4c8d0d4c8d0d4c8d0d4 - ---------------- - -tested 3 different embedded files: - -1. excel embedded - - "\002OlePres000"[40..-1] can be saved to '.wmf' and opened. - - "\002OlePres001" similarly. - much better looking image. strange - - For the rtf serialization, it has the file contents as an - ole, "d0cf11e" serialization, which i can't do yet. this can - be extracted as a working .xls - followed by a METAFILEPICT chunk, correspoding to one of the - ole pres chunks. - then the very same metafile chunk in the result bit. - -2. pbrush embedded image - - "\002OlePres000" wmf as above. - - "\001Ole10Native" is a long followed by a plain old .bmp - - Serialization: - Basic header as before, then bitmap data follows, then the - metafile chunk follows, though labeled PBrush again this time. - the result chunk was corrupted - -3. metafile embedded image - - no presentation section, just a - - "CONTENTS" section, which can be saved directly as a wmf. - different header to the other 2 metafiles. it starts with - 9AC6CDD7, which is the Aldus placeable metafile header. - (http://wvware.sourceforge.net/caolan/ora-wmf.html) - you can decode the left, top, right, bottom, and then - multiply by 96, and divide by the metafile unit converter thing - to get pixel values. - -the above ones were always the plain metafiles -word filetype (0 = memory, 1 = disk) -word headersize (always 9) -word version -thus leading to the -0100 -0900 -0003 -pattern i usually see. - -=end - diff --git a/vendor/ruby-msg/data/mapitags.yaml b/vendor/ruby-msg/data/mapitags.yaml deleted file mode 100644 index d6c5d5756..000000000 --- a/vendor/ruby-msg/data/mapitags.yaml +++ /dev/null @@ -1,4168 +0,0 @@ ---- -66b0: -- PR_RECIPIENT_ON_ASSOC_MSG_COUNT -- PT_LONG -3a01: -- PR_ALTERNATE_RECIPIENT -- PT_BINARY -"6628": -- PR_GW_MTSIN_ENTRYID -- PT_BINARY -"0061": -- PR_END_DATE -- PT_SYSTIME -66b1: -- PR_ATTACH_ON_NORMAL_MSG_COUNT -- PT_LONG -"1006": -- PR_RTF_SYNC_BODY_CRC -- PT_LONG -3a02: -- PR_CALLBACK_TELEPHONE_NUMBER -- PT_TSTRING -67aa: -- PR_ASSOCIATED -- PT_BOOLEAN -"6629": -- PR_GW_MTSOUT_ENTRYID -- PT_BINARY -"0062": -- PR_OWNER_APPT_ID -- PT_LONG -fffa: -- PR_EMS_AB_OBJECT_OID -- PT_BINARY -66b2: -- PR_ATTACH_ON_ASSOC_MSG_COUNT -- PT_LONG -36e0: -- PR_FOLDER_XVIEWINFO_E -- PT_BINARY -"1007": -- PR_RTF_SYNC_BODY_COUNT -- PT_LONG -3a03: -- PR_CONVERSION_PROHIBITED -- PT_BOOLEAN -"0063": -- PR_RESPONSE_REQUESTED -- PT_BOOLEAN -fffb: -- PR_EMS_AB_IS_MASTER -- PT_BOOLEAN -002a: -- PR_RECEIPT_TIME -- PT_SYSTIME -66b3: -- PR_NORMAL_MESSAGE_SIZE -- PT_LONG|PT_I8 -36e1: -- PR_FOLDER_VIEWS_ONLY -- PT_LONG -"1008": -- PR_RTF_SYNC_BODY_TAG -- PT_TSTRING -3a04: -- PR_DISCLOSE_RECIPIENTS -- PT_BOOLEAN -"0064": -- PR_SENT_REPRESENTING_ADDRTYPE -- PT_TSTRING -fffc: -- PR_EMS_AB_PARENT_ENTRYID -- PT_BINARY -002b: -- PR_RECIPIENT_REASSIGNMENT_PROHIBITED -- PT_BOOLEAN -66b4: -- PR_ASSOC_MESSAGE_SIZE -- PT_LONG|PT_I8 -"1009": -- PR_RTF_COMPRESSED -- PT_BINARY -3a05: -- PR_GENERATION -- PT_TSTRING -"0065": -- PR_SENT_REPRESENTING_EMAIL_ADDRESS -- PT_TSTRING -002c: -- PR_REDIRECTION_HISTORY -- PT_BINARY -66b5: -- PR_FOLDER_PATHNAME -- PT_TSTRING -3a06: -- PR_GIVEN_NAME -- PT_TSTRING -fffe: -- PR_EMS_AB_SERVER -- PT_TSTRING -002d: -- PR_RELATED_IPMS -- PT_BINARY -66b6: -- PR_OWNER_COUNT -- PT_LONG -36e4: -- PR_FREEBUSY_ENTRYIDS -- PT_MV_BINARY -3a07: -- PR_GOVERNMENT_ID_NUMBER -- PT_TSTRING -"0066": -- PR_ORIGINAL_SENDER_ADDRTYPE -- PT_TSTRING -002e: -- PR_ORIGINAL_SENSITIVITY -- PT_LONG -"1010": -- PR_RTF_SYNC_PREFIX_COUNT -- PT_LONG -66b7: -- PR_CONTACT_COUNT -- PT_LONG -36e5: -- PR_DEF_MSG_CLASS -- PT_UNICODE -3a08: -- PR_BUSINESS_TELEPHONE_NUMBER -- PT_TSTRING -"0067": -- PR_ORIGINAL_SENDER_EMAIL_ADDRESS -- PT_TSTRING -002f: -- PR_LANGUAGES -- PT_TSTRING -"1011": -- PR_RTF_SYNC_TRAILING_COUNT -- PT_LONG -"6634": -- PR_CHANGE_ADVISOR -- PT_OBJECT -36e6: -- PR_DEF_FORM_NAME -- PT_UNICODE -3a09: -- PR_HOME_TELEPHONE_NUMBER -- PT_TSTRING -0068: -- PR_ORIGINAL_SENT_REPRESENTING_ADDRTYPE -- PT_TSTRING -"6635": -- PR_FAVORITES_DEFAULT_NAME -- PT_TSTRING -0069: -- PR_ORIGINAL_SENT_REPRESENTING_EMAIL_ADDRESS -- PT_TSTRING -"1012": -- PR_ORIGINALLY_INTENDED_RECIP_ENTRYID -- PT_BINARY -0e96: -- PR_ATTACH_VIRUS_SCAN_INFO -- PT_BINARY -"6636": -- PR_SYS_CONFIG_FOLDER_ENTRYID -- PT_BINARY -67f0: -- PR_PROFILE_SECURE_MAILBOX -- PT_BINARY -"1013": -- PR_BODY_HTML -- PT_TSTRING -"3400": -- PR_DEFAULT_STORE -- PT_BOOLEAN -"6637": -- PR_CHANGE_NOTIFICATION_GUID -- PT_CLSID -36e9: -- PR_GENERATE_EXCHANGE_VIEWS -- PT_BOOLEAN -"0070": -- PR_CONVERSATION_TOPIC -- PT_TSTRING -0e5e: -- PR_MIME_HANDLER_CLASSIDS -- PT_CLSID -3a10: -- PR_ORGANIZATIONAL_ID_NUMBER -- PT_TSTRING -"6638": -- PR_FOLDER_CHILD_COUNT -- PT_LONG -"0071": -- PR_CONVERSATION_INDEX -- PT_BINARY -3a11: -- PR_SURNAME -- PT_TSTRING -"0072": -- PR_ORIGINAL_DISPLAY_BCC -- PT_TSTRING -"7001": -- PR_VD_BINARY -- PT_BINARY -3a12: -- PR_ORIGINAL_ENTRYID -- PT_BINARY -"0073": -- PR_ORIGINAL_DISPLAY_CC -- PT_TSTRING -003a: -- PR_REPORT_NAME -- PT_TSTRING -"7002": -- PR_VD_STRINGS -- PT_UNICODE -3a13: -- PR_ORIGINAL_DISPLAY_NAME -- PT_TSTRING -"0074": -- PR_ORIGINAL_DISPLAY_TO -- PT_TSTRING -686b: -- PR_DELEGATES_SEE_PRIVATE -- PT_MV_LONG -003b: -- PR_SENT_REPRESENTING_SEARCH_KEY -- PT_BINARY -66c3: -- PR_CODE_PAGE_ID -- PT_LONG -"7003": -- PR_VD_FLAGS -- PT_LONG -3a14: -- PR_ORIGINAL_SEARCH_KEY -- PT_BINARY -"0075": -- PR_RECEIVED_BY_ADDRTYPE -- PT_TSTRING -686c: -- PR_PERSONAL_FREEBUSY -- PT_BINARY -003c: -- PR_X400_CONTENT_TYPE -- PT_BINARY -66c4: -- PR_RETENTION_AGE_LIMIT -- PT_LONG -"7004": -- PR_VD_LINK_TO -- PT_BINARY -3a15: -- PR_POSTAL_ADDRESS -- PT_TSTRING -"0076": -- PR_RECEIVED_BY_EMAIL_ADDRESS -- PT_TSTRING -686d: -- PR_PROCESS_MEETING_REQUESTS -- PT_BOOLEAN -003d: -- PR_SUBJECT_PREFIX -- PT_TSTRING -66c5: -- PR_DISABLE_PERUSER_READ -- PT_BOOLEAN -"7005": -- PR_VD_VIEW_FOLDER -- PT_BINARY -3a16: -- PR_COMPANY_NAME -- PT_TSTRING -686e: -- PR_DECLINE_RECURRING_MEETING_REQUESTS -- PT_BOOLEAN -003e: -- PR_NON_RECEIPT_REASON -- PT_LONG -66c6: -- PR_INTERNET_PARSE_STATE -- PT_BINARY -"7006": -- PR_VD_NAME -- PT_UNICODE -3a17: -- PR_TITLE -- PT_TSTRING -660a: -- PR_PROFILE_TYPE -- PT_LONG -"0077": -- PR_RCVD_REPRESENTING_ADDRTYPE -- PT_TSTRING -686f: -- PR_DECLINE_CONFLICTING_MEETING_REQUESTS -- PT_BOOLEAN -003f: -- PR_RECEIVED_BY_ENTRYID -- PT_BINARY -66c7: -- PR_INTERNET_MESSAGE_INFO -- PT_BINARY -3a18: -- PR_DEPARTMENT_NAME -- PT_TSTRING -660b: -- PR_PROFILE_MAILBOX -- PT_TSTRING -0078: -- PR_RCVD_REPRESENTING_EMAIL_ADDRESS -- PT_TSTRING -7d01: -- PR_FAV_AUTOSUBFOLDERS -- PT_LONG -"7007": -- PR_VD_VERSION -- PT_LONG -3a19: -- PR_OFFICE_LOCATION -- PT_TSTRING -660c: -- PR_PROFILE_SERVER -- PT_TSTRING -0079: -- PR_ORIGINAL_AUTHOR_ADDRTYPE -- PT_TSTRING -7d02: -- PR_FAV_PARENT_SOURCE_KEY -- PT_BINARY -660d: -- PR_PROFILE_MAX_RESTRICT -- PT_LONG -7d03: -- PR_FAV_LEVEL_MASK -- PT_LONG -"3410": -- PR_IPM_SUBTREE_SEARCH_KEY -- PT_BINARY -660e: -- PR_PROFILE_AB_FILES_PATH -- PT_TSTRING -3a20: -- PR_TRANSMITTABLE_DISPLAY_NAME -- PT_TSTRING -"3411": -- PR_IPM_OUTBOX_SEARCH_KEY -- PT_BINARY -"6779": -- PR_PF_QUOTA_STYLE -- PT_LONG -0c0a: -- PR_PHYSICAL_DELIVERY_BUREAU_FAX_DELIVERY -- PT_BOOLEAN -660f: -- PR_PROFILE_FAVFLD_DISPLAY_NAME -- PT_TSTRING -3a21: -- PR_PAGER_TELEPHONE_NUMBER -- PT_TSTRING -"3412": -- PR_IPM_WASTEBASKET_SEARCH_KEY -- PT_BINARY -0c0b: -- PR_PHYSICAL_DELIVERY_MODE -- PT_LONG -3a22: -- PR_USER_CERTIFICATE -- PT_BINARY -"3413": -- PR_IPM_SENTMAIL_SEARCH_KEY -- PT_BINARY -0c0c: -- PR_PHYSICAL_DELIVERY_REPORT_REQUEST -- PT_LONG -7d07: -- PR_FAV_INHERIT_AUTO -- PT_LONG -65a0: -- PR_RULE_SERVER_RULE_ID -- PT_I8 -3a23: -- PR_PRIMARY_FAX_NUMBER -- PT_TSTRING -"3414": -- PR_MDB_PROVIDER -- PT_BINARY -0c0d: -- PR_PHYSICAL_FORWARDING_ADDRESS -- PT_BINARY -004a: -- PR_DISC_VAL -- PT_BOOLEAN -7d08: -- PR_FAV_DEL_SUBS -- PT_BINARY -"6650": -- PR_RULE_ACTION_NUMBER -- PT_LONG -3a24: -- PR_BUSINESS_FAX_NUMBER -- PT_TSTRING -"3415": -- PR_RECEIVE_FOLDER_SETTINGS -- PT_OBJECT -0c0e: -- PR_PHYSICAL_FORWARDING_ADDRESS_REQUESTED -- PT_BOOLEAN -004b: -- PR_ORIG_MESSAGE_CLASS -- PT_TSTRING -"6651": -- PR_RULE_FOLDER_ENTRYID -- PT_BINARY -"6783": -- PR_SEARCH_FLAGS -- PT_LONG -3a25: -- PR_HOME_FAX_NUMBER -- PT_TSTRING -674a: -- PR_MID -- PT_I8 -0c0f: -- PR_PHYSICAL_FORWARDING_PROHIBITED -- PT_BOOLEAN -004c: -- PR_ORIGINAL_AUTHOR_ENTRYID -- PT_BINARY -"6652": -- PR_ACTIVE_USER_ENTRYID -- PT_BINARY -3a26: -- PR_COUNTRY -- PT_TSTRING -674b: -- PR_CATEG_ID -- PT_I8 -004d: -- PR_ORIGINAL_AUTHOR_NAME -- PT_TSTRING -"1030": -- PR_INTERNET_APPROVED -- PT_TSTRING -"6653": -- PR_X400_ENVELOPE_TYPE -- PT_LONG -3a27: -- PR_LOCALITY -- PT_TSTRING -661a: -- PR_USER_NAME -- PT_TSTRING -674c: -- PR_PARENT_CATEG_ID -- PT_I8 -004e: -- PR_ORIGINAL_SUBMIT_TIME -- PT_SYSTIME -"1031": -- PR_INTERNET_CONTROL -- PT_TSTRING -"6654": -- PR_MSG_FOLD_TIME -- PT_SYSTIME -3a28: -- PR_STATE_OR_PROVINCE -- PT_TSTRING -661b: -- PR_MAILBOX_OWNER_ENTRYID -- PT_BINARY -674d: -- PR_INST_ID -- PT_I8 -004f: -- PR_REPLY_RECIPIENT_ENTRIES -- PT_BINARY -"1032": -- PR_INTERNET_DISTRIBUTION -- PT_TSTRING -3a29: -- PR_STREET_ADDRESS -- PT_TSTRING -661c: -- PR_MAILBOX_OWNER_NAME -- PT_TSTRING -674e: -- PR_INSTANCE_NUM -- PT_LONG -"1033": -- PR_INTERNET_FOLLOWUP_TO -- PT_TSTRING -"6655": -- PR_ICS_CHANGE_KEY -- PT_BINARY -661d: -- PR_OOF_STATE -- PT_BOOLEAN -674f: -- PR_ADDRBOOK_MID -- PT_I8 -661e: -- PR_SCHEDULE_FOLDER_ENTRYID -- PT_BINARY -"1034": -- PR_INTERNET_LINES -- PT_LONG -3a30: -- PR_ASSISTANT -- PT_TSTRING -0c1a: -- PR_SENDER_NAME -- PT_TSTRING -661f: -- PR_IPM_DAF_ENTRYID -- PT_BINARY -"1035": -- PR_INTERNET_MESSAGE_ID -- PT_TSTRING -"6658": -- PR_GW_ADMIN_OPERATIONS -- PT_LONG -0c1b: -- PR_SUPPLEMENTARY_INFO -- PT_TSTRING -"1036": -- PR_INTERNET_NEWSGROUPS -- PT_TSTRING -"6659": -- PR_INTERNET_CONTENT -- PT_BINARY -0c1c: -- PR_TYPE_OF_MTS_USER -- PT_LONG -0c1d: -- PR_SENDER_SEARCH_KEY -- PT_BINARY -005a: -- PR_ORIGINAL_SENDER_NAME -- PT_TSTRING -"1037": -- PR_INTERNET_ORGANIZATION -- PT_TSTRING -66aa: -- PR_RESTRICTION_COUNT -- PT_LONG -0c1e: -- PR_SENDER_ADDRTYPE -- PT_TSTRING -005b: -- PR_ORIGINAL_SENDER_ENTRYID -- PT_BINARY -10c0: -- PR_SMTP_TEMP_TBL_DATA -- PT_BINARY -"6660": -- PR_TRACE_INFO -- PT_BINARY -"1038": -- PR_INTERNET_NNTP_PATH -- PT_TSTRING -66ab: -- PR_CATEG_COUNT -- PT_LONG -675a: -- PR_PCL_EXPORT -- PT_BINARY -0c1f: -- PR_SENDER_EMAIL_ADDRESS -- PT_TSTRING -005c: -- PR_ORIGINAL_SENDER_SEARCH_KEY -- PT_BINARY -10c1: -- PR_SMTP_TEMP_TBL_DATA_2 -- PT_LONG -35e0: -- PR_IPM_SUBTREE_ENTRYID -- PT_BINARY -"6661": -- PR_SUBJECT_TRACE_INFO -- PT_BINARY -"1039": -- PR_INTERNET_REFERENCES -- PT_TSTRING -66ac: -- PR_CACHED_COLUMN_COUNT -- PT_LONG -675b: -- PR_CN_MV_EXPORT -- PT_MV_BINARY -"8100": -- PR_EMS_AB_OPEN_RETRY_INTERVAL -- PT_LONG -005d: -- PR_ORIGINAL_SENT_REPRESENTING_NAME -- PT_TSTRING -10c2: -- PR_SMTP_TEMP_TBL_DATA_3 -- PT_BINARY -"6662": -- PR_RECIPIENT_NUMBER -- PT_LONG -66ad: -- PR_NORMAL_MSG_W_ATTACH_COUNT -- PT_LONG -662a: -- PR_TRANSFER_ENABLED -- PT_BOOLEAN -"8101": -- PR_EMS_AB_ORGANIZATION_NAME -- PT_MV_TSTRING -005e: -- PR_ORIGINAL_SENT_REPRESENTING_ENTRYID -- PT_BINARY -10c3: -- PR_CAL_START_TIME -- PT_SYSTIME -"1040": -- PR_NNTP_XREF -- PT_TSTRING -35e2: -- PR_IPM_OUTBOX_ENTRYID -- PT_BINARY -"6663": -- PR_MTS_SUBJECT_ID -- PT_BINARY -66ae: -- PR_ASSOC_MSG_W_ATTACH_COUNT -- PT_LONG -662b: -- PR_TEST_LINE_SPEED -- PT_BINARY -"8102": -- PR_EMS_AB_ORGANIZATIONAL_UNIT_NAME -- PT_MV_TSTRING -005f: -- PR_ORIGINAL_SENT_REPRESENTING_SEARCH_KEY -- PT_BINARY -10c4: -- PR_CAL_END_TIME -- PT_SYSTIME -"1041": -- PR_INTERNET_PRECEDENCE -- PT_TSTRING -35e3: -- PR_IPM_WASTEBASKET_ENTRYID -- PT_BINARY -"6664": -- PR_REPORT_DESTINATION_NAME -- PT_TSTRING -66af: -- PR_RECIPIENT_ON_NORMAL_MSG_COUNT -- PT_LONG -662c: -- PR_HIERARCHY_SYNCHRONIZER -- PT_OBJECT -"8103": -- PR_EMS_AB_ORIGINAL_DISPLAY_TABLE -- PT_BINARY -10c5: -- PR_CAL_RECURRING_ID -- PT_SYSTIME -"1042": -- PR_IN_REPLY_TO_ID -- PT_UNICODE -35e4: -- PR_IPM_SENTMAIL_ENTRYID -- PT_BINARY -"6665": -- PR_REPORT_DESTINATION_ENTRYID -- PT_BINARY -662d: -- PR_CONTENTS_SYNCHRONIZER -- PT_OBJECT -"8104": -- PR_EMS_AB_ORIGINAL_DISPLAY_TABLE_MSDOS -- PT_BINARY -10c6: -- PR_DAV_SUBMIT_DATA -- PT_UNICODE -"1043": -- PR_LIST_HELP -- PT_UNICODE -35e5: -- PR_VIEWS_ENTRYID -- PT_BINARY -662e: -- PR_COLLECTOR -- PT_OBJECT -36df: -- PR_FOLDER_WEBVIEWINFO -- PT_BINARY -"8105": -- PR_EMS_AB_OUTBOUND_SITES -- PT_OBJECT|PT_MV_TSTRING -10c7: -- PR_CDO_EXPANSION_INDEX -- PT_LONG -"1044": -- PR_LIST_SUBSCRIBE -- PT_UNICODE -35e6: -- PR_COMMON_VIEWS_ENTRYID -- PT_BINARY -"6666": -- PR_CONTENT_SEARCH_KEY -- PT_BINARY -662f: -- PR_FAST_TRANSFER -- PT_OBJECT -"8106": -- PR_EMS_AB_P_SELECTOR -- PT_BINARY -10c8: -- PR_IFS_INTERNAL_DATA -- PT_BINARY -3a40: -- PR_SEND_RICH_INFO -- PT_BOOLEAN -35e7: -- PR_FINDER_ENTRYID -- PT_BINARY -"6667": -- PR_FOREIGN_ID -- PT_BINARY -"1045": -- PR_LIST_UNSUBSCRIBE -- PT_UNICODE -3a41: -- PR_WEDDING_ANNIVERSARY -- PT_SYSTIME -"6668": -- PR_FOREIGN_REPORT_ID -- PT_BINARY -"8107": -- PR_EMS_AB_P_SELECTOR_INBOUND -- PT_BINARY -"3301": -- PR_FORM_VERSION -- PT_TSTRING -3a42: -- PR_BIRTHDAY -- PT_SYSTIME -"6669": -- PR_FOREIGN_SUBJECT_ID -- PT_BINARY -3a0a: -- PR_INITIALS -- PT_TSTRING -"8108": -- PR_EMS_AB_PER_MSG_DIALOG_DISPLAY_TABLE -- PT_BINARY -"3302": -- PR_FORM_CLSID -- PT_CLSID -3a43: -- PR_HOBBIES -- PT_TSTRING -"8109": -- PR_EMS_AB_PER_RECIP_DIALOG_DISPLAY_TABLE -- PT_BINARY -"6670": -- PR_LONGTERM_ENTRYID_FROM_TABLE -- PT_BINARY -"3303": -- PR_FORM_CONTACT_NAME -- PT_TSTRING -3a44: -- PR_MIDDLE_NAME -- PT_TSTRING -3a0b: -- PR_KEYWORD -- PT_TSTRING -65c2: -- PR_REPLY_TEMPLATE_ID -- PT_BINARY -"6671": -- PR_MEMBER_ID -- PT_I8 -"3304": -- PR_FORM_CATEGORY -- PT_TSTRING -3a45: -- PR_DISPLAY_NAME_PREFIX -- PT_TSTRING -3a0c: -- PR_LANGUAGE -- PT_TSTRING -"6672": -- PR_MEMBER_NAME -- PT_TSTRING -"3305": -- PR_FORM_CATEGORY_SUB -- PT_TSTRING -3a46: -- PR_PROFESSION -- PT_TSTRING -"8110": -- PR_EMS_AB_PUBLIC_DELEGATES_BL -- PT_OBJECT|PT_MV_TSTRING -3a0d: -- PR_LOCATION -- PT_TSTRING -"6673": -- PR_MEMBER_RIGHTS -- PT_LONG -"3306": -- PR_FORM_HOST_MAP -- PT_MV_LONG -3a47: -- PR_PREFERRED_BY_NAME -- PT_TSTRING -663a: -- PR_HAS_RULES -- PT_BOOLEAN -"8111": -- PR_EMS_AB_QUOTA_NOTIFICATION_SCHEDULE -- PT_BINARY -3a0e: -- PR_MAIL_PERMISSION -- PT_BOOLEAN -"6674": -- PR_RULE_ID -- PT_I8 -"3307": -- PR_FORM_HIDDEN -- PT_BOOLEAN -3a48: -- PR_SPOUSE_NAME -- PT_TSTRING -663b: -- PR_ADDRESS_BOOK_ENTRYID -- PT_BINARY -36ec: -- PR_AGING_PERIOD -- PT_LONG -"8112": -- PR_EMS_AB_QUOTA_NOTIFICATION_STYLE -- PT_LONG -3a0f: -- PR_MHS_COMMON_NAME -- PT_TSTRING -"6675": -- PR_RULE_IDS -- PT_BINARY -"3308": -- PR_FORM_DESIGNER_NAME -- PT_TSTRING -3a49: -- PR_COMPUTER_NETWORK_NAME -- PT_TSTRING -663c: -- PR_PUBLIC_FOLDER_ENTRYID -- PT_BINARY -"8113": -- PR_EMS_AB_RANGE_LOWER -- PT_LONG -"6676": -- PR_RULE_SEQUENCE -- PT_LONG -"3309": -- PR_FORM_DESIGNER_GUID -- PT_CLSID -663d: -- PR_OFFLINE_FLAGS -- PT_LONG -36ee: -- PR_AGING_GRANULARITY -- PT_LONG -7c00: -- PR_FAV_DISPLAY_NAME -- PT_TSTRING -"8114": -- PR_EMS_AB_RANGE_UPPER -- PT_LONG -663e: -- PR_HIERARCHY_CHANGE_NUM -- PT_LONG -"8115": -- PR_EMS_AB_RAS_CALLBACK_NUMBER -- PT_TSTRING -3a50: -- PR_PERSONAL_HOME_PAGE -- PT_TSTRING -"6677": -- PR_RULE_STATE -- PT_LONG -663f: -- PR_HAS_MODERATOR_RULES -- PT_BOOLEAN -7c02: -- PR_FAV_PUBLIC_SOURCE_KEY -- PT_BINARY -"8116": -- PR_EMS_AB_RAS_PHONE_NUMBER -- PT_TSTRING -3a51: -- PR_BUSINESS_HOME_PAGE -- PT_TSTRING -"6678": -- PR_RULE_USER_FLAGS -- PT_LONG -"8117": -- PR_EMS_AB_RAS_PHONEBOOK_ENTRY_NAME -- PT_TSTRING -3a52: -- PR_CONTACT_VERSION -- PT_CLSID -"6679": -- PR_RULE_CONDITION -- PT_SRESTRICTION -3a1a: -- PR_PRIMARY_TELEPHONE_NUMBER -- PT_TSTRING -7c04: -- PR_OST_OSTID -- PT_BINARY -"4000": -- PR_NEW_ATTACH -- PT_LONG -3a53: -- PR_CONTACT_ENTRYIDS -- PT_MV_BINARY -3a1b: -- PR_BUSINESS2_TELEPHONE_NUMBER -- PT_TSTRING -007a: -- PR_ORIGINAL_AUTHOR_EMAIL_ADDRESS -- PT_TSTRING -"8118": -- PR_EMS_AB_RAS_REMOTE_SRVR_NAME -- PT_TSTRING -"4001": -- PR_START_EMBED -- PT_LONG -3a54: -- PR_CONTACT_ADDRTYPES -- PT_MV_TSTRING -81a1: -- PR_EMS_AB_X500_RDN -- PT_TSTRING -340d: -- PR_STORE_SUPPORT_MASK -- PT_LONG -007b: -- PR_ORIGINALLY_INTENDED_RECIP_ADDRTYPE -- PT_TSTRING -"8119": -- PR_EMS_AB_REGISTERED_ADDRESS -- PT_MV_BINARY -"4002": -- PR_END_EMBED -- PT_LONG -"6681": -- PR_RULE_PROVIDER -- PT_TSTRING -3a55: -- PR_CONTACT_DEFAULT_ADDRESS_INDEX -- PT_LONG -81a2: -- PR_EMS_AB_X500_NC -- PT_TSTRING -3a1c: -- PR_MOBILE_TELEPHONE_NUMBER -- PT_TSTRING -340e: -- PR_STORE_STATE -- PT_LONG -007c: -- PR_ORIGINALLY_INTENDED_RECIP_EMAIL_ADDRESS -- PT_TSTRING -"4003": -- PR_START_RECIP -- PT_LONG -"6682": -- PR_RULE_NAME -- PT_TSTRING -3a56: -- PR_CONTACT_EMAIL_ADDRESSES -- PT_MV_TSTRING -677b: -- PR_PF_STORAGE_QUOTA -- PT_LONG -81a3: -- PR_EMS_AB_REFERRAL_LIST -- PT_MV_TSTRING -"8120": -- PR_EMS_AB_REPORT_TO_ORIGINATOR -- PT_BOOLEAN -3a1d: -- PR_RADIO_TELEPHONE_NUMBER -- PT_TSTRING -007d: -- PR_TRANSPORT_MESSAGE_HEADERS -- PT_TSTRING -"6683": -- PR_RULE_LEVEL -- PT_LONG -3a57: -- PR_COMPANY_MAIN_PHONE_NUMBER -- PT_TSTRING -664a: -- PR_HAS_NAMED_PROPERTIES -- PT_BOOLEAN -81a4: -- PR_EMS_AB_NNTP_DISTRIBUTIONS_FLAG -- PT_BOOLEAN -"8121": -- PR_EMS_AB_REPORT_TO_OWNER -- PT_BOOLEAN -3a1e: -- PR_CAR_TELEPHONE_NUMBER -- PT_TSTRING -007e: -- PR_DELEGATION -- PT_BINARY -"4004": -- PR_END_RECIP -- PT_LONG -"6684": -- PR_RULE_PROVIDER_DATA -- PT_BINARY -3a58: -- PR_CHILDRENS_NAMES -- PT_MV_TSTRING -664b: -- PR_REPLICA_VERSION -- PT_I8 -81a5: -- PR_EMS_AB_ASSOC_PROTOCOL_CFG_NNTP -- PT_OBJECT|PT_MV_TSTRING -"8122": -- PR_EMS_AB_REQ_SEQ -- PT_LONG -3a1f: -- PR_OTHER_TELEPHONE_NUMBER -- PT_TSTRING -007f: -- PR_TNEF_CORRELATION_KEY -- PT_BINARY -"4005": -- PR_END_CC_RECIP -- PT_LONG -"6685": -- PR_LAST_FULL_BACKUP -- PT_SYSTIME -3a59: -- PR_HOME_ADDRESS_CITY -- PT_TSTRING -81a6: -- PR_EMS_AB_NNTP_NEWSFEEDS -- PT_OBJECT|PT_MV_TSTRING -"8123": -- PR_EMS_AB_RESPONSIBLE_LOCAL_DXA -- PT_OBJECT|PT_MV_TSTRING -"4006": -- PR_END_BCC_RECIP -- PT_LONG -"8124": -- PR_EMS_AB_RID_SERVER -- PT_OBJECT|PT_MV_TSTRING -"4007": -- PR_END_P1_RECIP -- PT_LONG -"6687": -- PR_PROFILE_ADDR_INFO -- PT_BINARY -81a8: -- PR_EMS_AB_ENABLED_PROTOCOL_CFG -- PT_BOOLEAN -"8125": -- PR_EMS_AB_ROLE_OCCUPANT -- PT_OBJECT|PT_MV_TSTRING -81a9: -- PR_EMS_AB_HTTP_PUB_AB_ATTRIBUTES -- PT_MV_TSTRING -"8126": -- PR_EMS_AB_ROUTING_LIST -- PT_MV_TSTRING -"4009": -- PR_START_TOP_FLD -- PT_LONG -3a60: -- PR_OTHER_ADDRESS_COUNTRY -- PT_TSTRING -"8127": -- PR_EMS_AB_RTS_CHECKPOINT_SIZE -- PT_LONG -"5902": -- PR_INET_MAIL_OVERRIDE_FORMAT -- PT_LONG -3a61: -- PR_OTHER_ADDRESS_POSTAL_CODE -- PT_TSTRING -"6689": -- PR_PROFILE_OPTIONS_DATA -- PT_BINARY -3a2a: -- PR_POSTAL_CODE -- PT_TSTRING -"8128": -- PR_EMS_AB_RTS_RECOVERY_TIMEOUT -- PT_LONG -"4010": -- PR_START_FAI_MSG -- PT_LONG -3a62: -- PR_OTHER_ADDRESS_STATE_OR_PROVINCE -- PT_TSTRING -81b0: -- PR_EMS_AB_OUTBOUND_HOST_TYPE -- PT_BOOLEAN -3a2b: -- PR_POST_BOX -- PT_TSTRING -"4011": -- PR_NEW_FX_FOLDER -- PT_BINARY -7ffa: -- PR_ATTACHMENT_LINKID -- PT_LONG -65e0: -- PR_SOURCE_KEY -- PT_BINARY -3a63: -- PR_OTHER_ADDRESS_STREET -- PT_TSTRING -81b1: -- PR_EMS_AB_PROXY_GENERATION_ENABLED -- PT_BOOLEAN -3a2c: -- PR_TELEX_NUMBER -- PT_TSTRING -"8129": -- PR_EMS_AB_RTS_WINDOW_SIZE -- PT_LONG -"4012": -- PR_INCR_SYNC_CHG -- PT_LONG -7ffb: -- PR_EXCEPTION_STARTTIME -- PT_SYSTIME -65e1: -- PR_PARENT_SOURCE_KEY -- PT_BINARY -"6690": -- PR_REPLICATION_STYLE -- PT_LONG -3a64: -- PR_OTHER_ADDRESS_POST_OFFICE_BOX -- PT_TSTRING -81b2: -- PR_EMS_AB_ROOT_NEWSGROUPS_FOLDER_ID -- PT_BINARY -10f1: -- PR_OWA_URL -- PT_TSTRING -"4013": -- PR_INCR_SYNC_DEL -- PT_LONG -7ffc: -- PR_EXCEPTION_ENDTIME -- PT_SYSTIME -65e2: -- PR_CHANGE_KEY -- PT_BINARY -"6691": -- PR_REPLICATION_SCHEDULE -- PT_BINARY -81b3: -- PR_EMS_AB_CONNECTION_TYPE -- PT_BOOLEAN -3a2d: -- PR_ISDN_NUMBER -- PT_TSTRING -"8130": -- PR_EMS_AB_SERIAL_NUMBER -- PT_MV_TSTRING -10f2: -- PR_DISABLE_FULL_FIDELITY -- PT_BOOLEAN -"4014": -- PR_INCR_SYNC_END -- PT_LONG -7ffd: -- PR_ATTACHMENT_FLAGS -- PT_LONG -65e3: -- PR_PREDECESSOR_CHANGE_LIST -- PT_BINARY -"6692": -- PR_REPLICATION_MESSAGE_PRIORITY -- PT_LONG -81b4: -- PR_EMS_AB_CONNECTION_LIST_FILTER_TYPE -- PT_LONG -"8131": -- PR_EMS_AB_SERVICE_ACTION_FIRST -- PT_LONG -3a2e: -- PR_ASSISTANT_TELEPHONE_NUMBER -- PT_TSTRING -10f3: -- PR_URL_COMP_NAME -- PT_UNICODE -7ffe: -- PR_ATTACHMENT_HIDDEN -- PT_BOOLEAN -65e4: -- PR_SYNCHRONIZE_FLAGS -- PT_LONG -"6693": -- PR_OVERALL_MSG_AGE_LIMIT -- PT_LONG -665a: -- PR_HAS_ATTACH_FROM_IMAIL -- PT_BOOLEAN -81b5: -- PR_EMS_AB_PORT_NUMBER -- PT_LONG -"8132": -- PR_EMS_AB_SERVICE_ACTION_OTHER -- PT_LONG -3a2f: -- PR_HOME2_TELEPHONE_NUMBER -- PT_TSTRING -10f4: -- PR_ATTR_HIDDEN -- PT_BOOLEAN -"4015": -- PR_INCR_SYNC_MSG -- PT_LONG -65e5: -- PR_AUTO_ADD_NEW_SUBS -- PT_BOOLEAN -"6694": -- PR_REPLICATION_ALWAYS_INTERVAL -- PT_LONG -"5909": -- PR_MSG_EDITOR_FORMAT -- PT_LONG -665b: -- PR_ORIGINATOR_NAME -- PT_TSTRING -"8001": -- PR_EMS_AB_DISPLAY_NAME_OVERRIDE -- PT_BOOLEAN -81b6: -- PR_EMS_AB_PROTOCOL_SETTINGS -- PT_MV_TSTRING -"8133": -- PR_EMS_AB_SERVICE_ACTION_SECOND -- PT_LONG -10f5: -- PR_ATTR_SYSTEM -- PT_BOOLEAN -"4016": -- PR_FX_DEL_PROP -- PT_LONG -65e6: -- PR_NEW_SUBS_GET_AUTO_ADD -- PT_BOOLEAN -"6695": -- PR_REPLICATION_MSG_SIZE -- PT_LONG -665c: -- PR_ORIGINATOR_ADDR -- PT_TSTRING -81b7: -- PR_EMS_AB_GROUP_BY_ATTR_1 -- PT_TSTRING -"8134": -- PR_EMS_AB_SERVICE_RESTART_DELAY -- PT_LONG -10f6: -- PR_ATTR_READONLY -- PT_BOOLEAN -"4017": -- PR_IDSET_GIVEN -- PT_LONG -65e7: -- PR_MESSAGE_SITE_NAME -- PT_TSTRING -"6696": -- PR_IS_NEWSGROUP_ANCHOR -- PT_BOOLEAN -103a: -- PR_SUPERSEDES -- PT_TSTRING -665d: -- PR_ORIGINATOR_ADDRTYPE -- PT_TSTRING -"8003": -- PR_EMS_AB_CA_CERTIFICATE -- PT_MV_BINARY -81b8: -- PR_EMS_AB_GROUP_BY_ATTR_2 -- PT_TSTRING -"8135": -- PR_EMS_AB_SERVICE_RESTART_MESSAGE -- PT_TSTRING -65e8: -- PR_MESSAGE_PROCESSED -- PT_BOOLEAN -"6697": -- PR_IS_NEWSGROUP -- PT_BOOLEAN -103b: -- PR_POST_FOLDER_ENTRIES -- PT_BINARY -665e: -- PR_ORIGINATOR_ENTRYID -- PT_BINARY -"8004": -- PR_EMS_AB_FOLDER_PATHNAME -- PT_TSTRING -81b9: -- PR_EMS_AB_GROUP_BY_ATTR_3 -- PT_TSTRING -"8136": -- PR_EMS_AB_SESSION_DISCONNECT_TIMER -- PT_LONG -"4019": -- PR_SENDER_FLAGS -- PT_LONG -65e9: -- PR_RULE_MSG_STATE -- PT_LONG -3a70: -- PR_USER_X509_CERTIFICATE -- PT_MV_BINARY -"6698": -- PR_REPLICA_LIST -- PT_BINARY -103c: -- PR_POST_FOLDER_NAMES -- PT_TSTRING -665f: -- PR_ARRIVAL_TIME -- PT_SYSTIME -"8005": -- PR_EMS_AB_MANAGER -- PT_OBJECT|PT_MV_TSTRING -"8137": -- PR_EMS_AB_SITE_AFFINITY -- PT_MV_TSTRING -3a71: -- PR_SEND_INTERNET_ENCODING -- PT_LONG -103d: -- PR_POST_REPLY_FOLDER_ENTRIES -- PT_BINARY -35df: -- PR_VALID_FOLDER_MASK -- PT_LONG -"8006": -- PR_EMS_AB_HOME_MDB -- PT_OBJECT|PT_MV_TSTRING -"8138": -- PR_EMS_AB_SITE_PROXY_SPACE -- PT_MV_TSTRING -"4020": -- PR_READ_RECEIPT_FLAGS -- PT_LONG -"6699": -- PR_OVERALL_AGE_LIMIT -- PT_LONG -103e: -- PR_POST_REPLY_FOLDER_NAMES -- PT_TSTRING -"8007": -- PR_EMS_AB_HOME_MTA -- PT_OBJECT|PT_MV_TSTRING -"8139": -- PR_EMS_AB_SPACE_LAST_COMPUTED -- PT_SYSTIME -"4021": -- PR_SOFT_DELETES -- PT_BOOLEAN -65f0: -- PR_RULE_MSG_CONDITION -- PT_BINARY -103f: -- PR_POST_REPLY_DENIED -- PT_BINARY -81c0: -- PR_EMS_AB_VIEW_CONTAINER_2 -- PT_TSTRING -65f1: -- PR_RULE_MSG_CONDITION_LCID -- PT_LONG -81c1: -- PR_EMS_AB_VIEW_CONTAINER_3 -- PT_TSTRING -65f2: -- PR_RULE_MSG_VERSION -- PT_SHORT -81c2: -- PR_EMS_AB_PROMO_EXPIRATION -- PT_SYSTIME -"8008": -- PR_EMS_AB_IS_MEMBER_OF_DL -- PT_OBJECT|PT_MV_TSTRING -65f3: -- PR_RULE_MSG_SEQUENCE -- PT_LONG -10ca: -- PR_CAL_REMINDER_NEXT_TIME -- PT_SYSTIME -81c3: -- PR_EMS_AB_DISABLED_GATEWAY_PROXY -- PT_MV_TSTRING -"8140": -- PR_EMS_AB_T_SELECTOR -- PT_BINARY -"8009": -- PR_EMS_AB_MEMBER -- PT_OBJECT|PT_MV_TSTRING -"1080": -- PR_ACTION -- PT_LONG -65f4: -- PR_PREVENT_MSG_CREATE -- PT_BOOLEAN -81c4: -- PR_EMS_AB_COMPROMISED_KEY_LIST -- PT_BINARY -"8141": -- PR_EMS_AB_T_SELECTOR_INBOUND -- PT_BINARY -"1081": -- PR_ACTION_FLAG -- PT_LONG -65f5: -- PR_IMAP_INTERNAL_DATE -- PT_SYSTIME -"8010": -- PR_EMS_AB_HELP_DATA32 -- PT_BINARY -81c5: -- PR_EMS_AB_INSADMIN -- PT_OBJECT|PT_MV_TSTRING -"8142": -- PR_EMS_AB_TARGET_MTAS -- PT_MV_TSTRING -"1082": -- PR_ACTION_DATE -- PT_SYSTIME -666c: -- PR_IN_CONFLICT -- PT_BOOLEAN -"8011": -- PR_EMS_AB_TARGET_ADDRESS -- PT_TSTRING -81c6: -- PR_EMS_AB_OVERRIDE_NNTP_CONTENT_FORMAT -- PT_BOOLEAN -"8143": -- PR_EMS_AB_TELETEX_TERMINAL_IDENTIFIER -- PT_MV_BINARY -3f00: -- PR_CONTROL_FLAGS -- PT_LONG -810a: -- PR_EMS_AB_PERIOD_REP_SYNC_TIMES -- PT_BINARY -"8012": -- PR_EMS_AB_TELEPHONE_NUMBER -- PT_MV_TSTRING -81c7: -- PR_EMS_AB_OBJ_VIEW_CONTAINERS -- PT_OBJECT|PT_MV_TSTRING -"8144": -- PR_EMS_AB_TEMP_ASSOC_THRESHOLD -- PT_LONG -3f01: -- PR_CONTROL_STRUCTURE -- PT_BINARY -810b: -- PR_EMS_AB_PERIOD_REPL_STAGGER -- PT_LONG -"8013": -- PR_EMS_AB_NT_SECURITY_DESCRIPTOR -- PT_BINARY -"8145": -- PR_EMS_AB_TOMBSTONE_LIFETIME -- PT_LONG -3f02: -- PR_CONTROL_TYPE -- PT_LONG -810c: -- PR_EMS_AB_POSTAL_ADDRESS -- PT_MV_BINARY -"8014": -- PR_EMS_AB_HOME_MDB_BL -- PT_OBJECT|PT_MV_TSTRING -"8146": -- PR_EMS_AB_TRACKING_LOG_PATH_NAME -- PT_TSTRING -3f03: -- PR_DELTAX -- PT_LONG -810d: -- PR_EMS_AB_PREFERRED_DELIVERY_METHOD -- PT_MV_LONG -"8015": -- PR_EMS_AB_PUBLIC_DELEGATES -- PT_OBJECT|PT_MV_TSTRING -"8147": -- PR_EMS_AB_TRANS_RETRY_MINS -- PT_LONG -3f04: -- PR_DELTAY -- PT_LONG -810e: -- PR_EMS_AB_PRMD -- PT_TSTRING -3a4a: -- PR_CUSTOMER_ID -- PT_TSTRING -"8016": -- PR_EMS_AB_CERTIFICATE_REVOCATION_LIST -- PT_BINARY -"8148": -- PR_EMS_AB_TRANS_TIMEOUT_MINS -- PT_LONG -"4030": -- PR_SENDER_SIMPLE_DISP_NAME -- PT_UNICODE -3f05: -- PR_XPOS -- PT_LONG -810f: -- PR_EMS_AB_PROXY_GENERATOR_DLL -- PT_TSTRING -330a: -- PR_FORM_MESSAGE_BEHAVIOR -- PT_LONG -3a4b: -- PR_TTYTDD_PHONE_NUMBER -- PT_TSTRING -"8017": -- PR_EMS_AB_ADDRESS_ENTRY_DISPLAY_TABLE -- PT_BINARY -"8149": -- PR_EMS_AB_TRANSFER_RETRY_INTERVAL -- PT_LONG -"4031": -- PR_SENT_REPRESENTING_SIMPLE_DISP_NAME -- PT_UNICODE -3f06: -- PR_YPOS -- PT_LONG -3a4c: -- PR_FTP_SITE -- PT_TSTRING -"8018": -- PR_EMS_AB_ADDRESS_SYNTAX -- PT_BINARY -3f07: -- PR_CONTROL_ID -- PT_BINARY -80a0: -- PR_EMS_AB_DXA_TYPES -- PT_LONG -3a4d: -- PR_GENDER -- PT_SHORT -3f08: -- PR_INITIAL_DETAILS_PANE -- PT_LONG -80a1: -- PR_EMS_AB_DXA_UNCONF_CONTAINER_LIST -- PT_OBJECT|PT_MV_TSTRING -"8150": -- PR_EMS_AB_TURN_REQUEST_THRESHOLD -- PT_LONG -3a4e: -- PR_MANAGER_NAME -- PT_TSTRING -66fe: -- PR_OWNER_NAME -- PT_STRING8 -80a2: -- PR_EMS_AB_ENCAPSULATION_METHOD -- PT_LONG -"8151": -- PR_EMS_AB_TWO_WAY_ALTERNATE_FACILITY -- PT_BOOLEAN -"1090": -- PR_FLAG_STATUS -- PT_LONG -667b: -- PR_PROFILE_MOAB -- PT_TSTRING -80a3: -- PR_EMS_AB_ENCRYPT -- PT_BOOLEAN -"8152": -- PR_EMS_AB_UNAUTH_ORIG_BL -- PT_OBJECT|PT_MV_TSTRING -3a4f: -- PR_NICKNAME -- PT_TSTRING -"3900": -- PR_DISPLAY_TYPE -- PT_LONG -"1091": -- PR_FLAG_COMPLETE -- PT_SYSTIME -66ff: -- PR_ASSIGNED_ACCESS -- PT_LONG -667c: -- PR_PROFILE_MOAB_GUID -- PT_TSTRING -80a4: -- PR_EMS_AB_EXPAND_DLS_LOCALLY -- PT_BOOLEAN -"8153": -- PR_EMS_AB_USER_PASSWORD -- PT_MV_BINARY -811a: -- PR_EMS_AB_REMOTE_BRIDGE_HEAD -- PT_TSTRING -667d: -- PR_PROFILE_MOAB_SEQ -- PT_LONG -80a5: -- PR_EMS_AB_EXPORT_CONTAINERS -- PT_OBJECT|PT_MV_TSTRING -"8154": -- PR_EMS_AB_USN_CREATED -- PT_LONG -"3902": -- PR_TEMPLATEID -- PT_BINARY -811b: -- PR_EMS_AB_REMOTE_BRIDGE_HEAD_ADDRESS -- PT_TSTRING -80a6: -- PR_EMS_AB_EXPORT_CUSTOM_RECIPIENTS -- PT_BOOLEAN -"8023": -- PR_EMS_AB_BUSINESS_ROLES -- PT_BINARY -"8155": -- PR_EMS_AB_USN_DSA_LAST_OBJ_REMOVED -- PT_LONG -811c: -- PR_EMS_AB_REMOTE_OUT_BH_SERVER -- PT_OBJECT|PT_MV_TSTRING -"4038": -- PR_CREATOR_SIMPLE_DISP_NAME -- PT_UNICODE -667f: -- PR_IMPLIED_RESTRICTIONS -- PT_MV_BINARY -80a7: -- PR_EMS_AB_EXTENDED_CHARS_ALLOWED -- PT_BOOLEAN -"8024": -- PR_EMS_AB_OWNER_BL -- PT_OBJECT|PT_MV_TSTRING -"8156": -- PR_EMS_AB_USN_LAST_OBJ_REM -- PT_LONG -"3904": -- PR_PRIMARY_CAPABILITY -- PT_BINARY -7c0a: -- PR_STORE_SLOWLINK -- PT_BOOLEAN -811d: -- PR_EMS_AB_REMOTE_SITE -- PT_OBJECT|PT_MV_TSTRING -80a8: -- PR_EMS_AB_EXTENSION_DATA -- PT_MV_BINARY -"8025": -- PR_EMS_AB_CROSS_CERTIFICATE_PAIR -- PT_MV_BINARY -"8157": -- PR_EMS_AB_USN_SOURCE -- PT_LONG -811e: -- PR_EMS_AB_REPLICATION_SENSITIVITY -- PT_LONG -80a9: -- PR_EMS_AB_EXTENSION_NAME -- PT_MV_TSTRING -"8026": -- PR_EMS_AB_AUTHORITY_REVOCATION_LIST -- PT_MV_BINARY -"8158": -- PR_EMS_AB_X121_ADDRESS -- PT_MV_TSTRING -811f: -- PR_EMS_AB_REPLICATION_STAGGER -- PT_LONG -3a5a: -- PR_HOME_ADDRESS_COUNTRY -- PT_TSTRING -"8027": -- PR_EMS_AB_ASSOC_NT_ACCOUNT -- PT_BINARY -"8159": -- PR_EMS_AB_X25_CALL_USER_DATA_INCOMING -- PT_BINARY -3a5b: -- PR_HOME_ADDRESS_POSTAL_CODE -- PT_TSTRING -"8028": -- PR_EMS_AB_EXPIRATION_TIME -- PT_SYSTIME -3a5c: -- PR_HOME_ADDRESS_STATE_OR_PROVINCE -- PT_TSTRING -"8029": -- PR_EMS_AB_USN_CHANGED -- PT_LONG -400a: -- PR_START_SUB_FLD -- PT_LONG -80b0: -- PR_EMS_AB_GATEWAY_LOCAL_CRED -- PT_TSTRING -3a5d: -- PR_HOME_ADDRESS_STREET -- PT_TSTRING -81ab: -- PR_EMS_AB_HTTP_SERVERS -- PT_MV_TSTRING -400b: -- PR_END_FOLDER -- PT_LONG -80b1: -- PR_EMS_AB_GATEWAY_LOCAL_DESIG -- PT_TSTRING -"8160": -- PR_EMS_AB_X400_ATTACHMENT_TYPE -- PT_BINARY -3a5e: -- PR_HOME_ADDRESS_POST_OFFICE_BOX -- PT_TSTRING -81ac: -- PR_EMS_AB_MODERATED -- PT_BOOLEAN -400c: -- PR_START_MESSAGE -- PT_LONG -80b2: -- PR_EMS_AB_GATEWAY_PROXY -- PT_MV_TSTRING -"8161": -- PR_EMS_AB_X400_SELECTOR_SYNTAX -- PT_LONG -3a5f: -- PR_OTHER_ADDRESS_CITY -- PT_TSTRING -81ad: -- PR_EMS_AB_RAS_ACCOUNT -- PT_TSTRING -400d: -- PR_END_MESSAGE -- PT_LONG -668b: -- PR_NNTP_CONTROL_FOLDER_ENTRYID -- PT_BINARY -80b3: -- PR_EMS_AB_GATEWAY_ROUTING_TREE -- PT_BINARY -"8030": -- PR_EMS_AB_EXTENSION_ATTRIBUTE_4 -- PT_TSTRING -"8162": -- PR_EMS_AB_X500_ACCESS_CONTROL_LIST -- PT_BINARY -81ae: -- PR_EMS_AB_RAS_PASSWORD -- PT_BINARY -812a: -- PR_EMS_AB_RUNS_ON -- PT_OBJECT|PT_MV_TSTRING -400e: -- PR_END_ATTACH -- PT_LONG -668c: -- PR_NEWSGROUP_ROOT_FOLDER_ENTRYID -- PT_BINARY -80b4: -- PR_EMS_AB_GWART_LAST_MODIFIED -- PT_SYSTIME -"8031": -- PR_EMS_AB_EXTENSION_ATTRIBUTE_5 -- PT_TSTRING -"8163": -- PR_EMS_AB_XMIT_TIMEOUT_NON_URGENT -- PT_LONG -81af: -- PR_EMS_AB_INCOMING_PASSWORD -- PT_BINARY -812b: -- PR_EMS_AB_S_SELECTOR -- PT_BINARY -400f: -- PR_EC_WARNING -- PT_LONG -668d: -- PR_INBOUND_NEWSFEED_DN -- PT_TSTRING -80b5: -- PR_EMS_AB_HAS_FULL_REPLICA_NCS -- PT_OBJECT|PT_MV_TSTRING -"8032": -- PR_EMS_AB_EXTENSION_ATTRIBUTE_6 -- PT_TSTRING -"8164": -- PR_EMS_AB_XMIT_TIMEOUT_NORMAL -- PT_LONG -812c: -- PR_EMS_AB_S_SELECTOR_INBOUND -- PT_BINARY -668e: -- PR_OUTBOUND_NEWSFEED_DN -- PT_TSTRING -80b6: -- PR_EMS_AB_HAS_MASTER_NCS -- PT_OBJECT|PT_MV_TSTRING -"8033": -- PR_EMS_AB_EXTENSION_ATTRIBUTE_7 -- PT_TSTRING -"8165": -- PR_EMS_AB_XMIT_TIMEOUT_URGENT -- PT_LONG -812d: -- PR_EMS_AB_SEARCH_FLAGS -- PT_LONG -668f: -- PR_DELETED_ON -- PT_SYSTIME -80b7: -- PR_EMS_AB_HEURISTICS -- PT_LONG -"8034": -- PR_EMS_AB_EXTENSION_ATTRIBUTE_8 -- PT_TSTRING -"8166": -- PR_EMS_AB_SITE_FOLDER_GUID -- PT_BINARY -812e: -- PR_EMS_AB_SEARCH_GUIDE -- PT_MV_BINARY -80b8: -- PR_EMS_AB_HIDE_DL_MEMBERSHIP -- PT_BOOLEAN -"8035": -- PR_EMS_AB_EXTENSION_ATTRIBUTE_9 -- PT_TSTRING -"8167": -- PR_EMS_AB_SITE_FOLDER_SERVER -- PT_OBJECT|PT_MV_TSTRING -812f: -- PR_EMS_AB_SEE_ALSO -- PT_OBJECT|PT_MV_TSTRING -80b9: -- PR_EMS_AB_HIDE_FROM_ADDRESS_BOOK -- PT_BOOLEAN -"8036": -- PR_EMS_AB_EXTENSION_ATTRIBUTE_10 -- PT_TSTRING -"8168": -- PR_EMS_AB_REPLICATION_MAIL_MSG_SIZE -- PT_LONG -"8037": -- PR_EMS_AB_SECURITY_PROTOCOL -- PT_MV_BINARY -"8169": -- PR_EMS_AB_MAXIMUM_OBJECT_ID -- PT_BINARY -"8038": -- PR_EMS_AB_PF_CONTACTS -- PT_OBJECT|PT_MV_TSTRING -401a: -- PR_SENT_REPRESENTING_FLAGS -- PT_LONG -65ea: -- PR_RULE_MSG_USER_FLAGS -- PT_LONG -80c0: -- PR_EMS_AB_IS_DELETED -- PT_BOOLEAN -81ba: -- PR_EMS_AB_GROUP_BY_ATTR_4 -- PT_TSTRING -401b: -- PR_RCVD_BY_FLAGS -- PT_LONG -65eb: -- PR_RULE_MSG_PROVIDER -- PT_UNICODE -80c1: -- PR_EMS_AB_IS_SINGLE_VALUED -- PT_BOOLEAN -"8170": -- PR_EMS_AB_NETWORK_ADDRESS -- PT_MV_TSTRING -401c: -- PR_RCVD_REPRESENTING_FLAGS -- PT_LONG -65ec: -- PR_RULE_MSG_NAME -- PT_UNICODE -669a: -- PR_INTERNET_CHARSET -- PT_TSTRING -80c2: -- PR_EMS_AB_KCC_STATUS -- PT_MV_BINARY -"8171": -- PR_EMS_AB_LDAP_DISPLAY_NAME -- PT_MV_TSTRING -401d: -- PR_ORIGINAL_SENDER_FLAGS -- PT_LONG -65ed: -- PR_RULE_MSG_LEVEL -- PT_LONG -669b: -- PR_DELETED_MESSAGE_SIZE -- PT_I8 -80c3: -- PR_EMS_AB_KNOWLEDGE_INFORMATION -- PT_MV_TSTRING -"8040": -- PR_EMS_AB_ENCRYPT_ALG_LIST_NA -- PT_MV_TSTRING -401e: -- PR_ORIGINAL_SENT_REPRESENTING_FLAGS -- PT_LONG -65ee: -- PR_RULE_MSG_PROVIDER_DATA -- PT_BINARY -669c: -- PR_DELETED_NORMAL_MESSAGE_SIZE -- PT_I8 -80c4: -- PR_EMS_AB_LINE_WRAP -- PT_LONG -"8041": -- PR_EMS_AB_ENCRYPT_ALG_LIST_OTHER -- PT_MV_TSTRING -"8173": -- PR_EMS_AB_SCHEMA_FLAGS -- PT_LONG -81be: -- PR_EMS_AB_VIEW_SITE -- PT_TSTRING -813a: -- PR_EMS_AB_STREET_ADDRESS -- PT_TSTRING -401f: -- PR_REPORT_FLAGS -- PT_LONG -669d: -- PR_DELETED_ASSOC_MESSAGE_SIZE -- PT_I8 -80c5: -- PR_EMS_AB_LINK_ID -- PT_LONG -"8042": -- PR_EMS_AB_IMPORTED_FROM -- PT_TSTRING -"8174": -- PR_EMS_AB_BRIDGEHEAD_SERVERS -- PT_OBJECT|PT_MV_TSTRING -81bf: -- PR_EMS_AB_VIEW_CONTAINER_1 -- PT_TSTRING -813b: -- PR_EMS_AB_SUB_REFS -- PT_OBJECT|PT_MV_TSTRING -65ef: -- PR_RULE_MSG_ACTIONS -- PT_BINARY -669e: -- PR_SECURE_IN_SITE -- PT_BOOLEAN -80c6: -- PR_EMS_AB_LOCAL_BRIDGE_HEAD -- PT_TSTRING -"8043": -- PR_EMS_AB_ENCRYPT_ALG_SELECTED_NA -- PT_TSTRING -"8175": -- PR_EMS_AB_WWW_HOME_PAGE -- PT_TSTRING -3e00: -- PR_IDENTITY_DISPLAY -- PT_TSTRING -800a: -- PR_EMS_AB_AUTOREPLY_MESSAGE -- PT_TSTRING -813c: -- PR_EMS_AB_SUBMISSION_CONT_LENGTH -- PT_LONG -80c7: -- PR_EMS_AB_LOCAL_BRIDGE_HEAD_ADDRESS -- PT_TSTRING -"8044": -- PR_EMS_AB_ACCESS_CATEGORY -- PT_LONG -"8176": -- PR_EMS_AB_NNTP_CONTENT_FORMAT -- PT_TSTRING -3e01: -- PR_IDENTITY_ENTRYID -- PT_BINARY -800b: -- PR_EMS_AB_AUTOREPLY -- PT_BOOLEAN -813d: -- PR_EMS_AB_SUPPORTED_APPLICATION_CONTEXT -- PT_MV_BINARY -"4059": -- PR_CREATOR_FLAGS -- PT_LONG -80c8: -- PR_EMS_AB_LOCAL_INITIAL_TURN -- PT_BOOLEAN -"8045": -- PR_EMS_AB_ACTIVATION_SCHEDULE -- PT_BINARY -"8177": -- PR_EMS_AB_POP_CONTENT_FORMAT -- PT_TSTRING -3e02: -- PR_RESOURCE_METHODS -- PT_LONG -800c: -- PR_EMS_AB_OWNER -- PT_OBJECT|PT_MV_TSTRING -813e: -- PR_EMS_AB_SUPPORTING_STACK -- PT_OBJECT|PT_MV_TSTRING -80c9: -- PR_EMS_AB_LOCAL_SCOPE -- PT_OBJECT|PT_MV_TSTRING -"8046": -- PR_EMS_AB_ACTIVATION_STYLE -- PT_LONG -"8178": -- PR_EMS_AB_LANGUAGE -- PT_LONG -3e03: -- PR_RESOURCE_TYPE -- PT_LONG -800d: -- PR_EMS_AB_KM_SERVER -- PT_OBJECT|PT_MV_TSTRING -813f: -- PR_EMS_AB_SUPPORTING_STACK_BL -- PT_OBJECT|PT_MV_TSTRING -"8047": -- PR_EMS_AB_ADDRESS_ENTRY_DISPLAY_TABLE_MSDOS -- PT_BINARY -"8179": -- PR_EMS_AB_POP_CHARACTER_SET -- PT_TSTRING -"4061": -- PR_ORIGINATOR_SEARCH_KEY -- PT_BINARY -3e04: -- PR_STATUS_CODE -- PT_LONG -800e: -- PR_EMS_AB_REPORTS -- PT_OBJECT -"8048": -- PR_EMS_AB_ADDRESS_TYPE -- PT_TSTRING -3e05: -- PR_IDENTITY_SEARCH_KEY -- PT_BINARY -800f: -- PR_EMS_AB_PROXY_ADDRESSES -- PT_MV_TSTRING -80d0: -- PR_EMS_AB_MDB_MSG_TIME_OUT_PERIOD -- PT_LONG -"8049": -- PR_EMS_AB_ADMD -- PT_TSTRING -3e06: -- PR_OWN_STORE_ENTRYID -- PT_BINARY -80d1: -- PR_EMS_AB_MDB_OVER_QUOTA_LIMIT -- PT_LONG -"8180": -- PR_EMS_AB_CONNECTION_LIST_FILTER -- PT_BINARY -"4064": -- PR_REPORT_DESTINATION_SEARCH_KEY -- PT_BINARY -3e07: -- PR_RESOURCE_PATH -- PT_TSTRING -80d2: -- PR_EMS_AB_MDB_STORAGE_QUOTA -- PT_LONG -"8181": -- PR_EMS_AB_AVAILABLE_AUTHORIZATION_PACKAGES -- PT_MV_TSTRING -"4065": -- PR_ER_FLAG -- PT_LONG -3e08: -- PR_STATUS_STRING -- PT_TSTRING -402c: -- PR_MESSAGE_SUBMISSION_ID_FROM_CLIENT -- PT_BINARY -80d3: -- PR_EMS_AB_MDB_UNREAD_LIMIT -- PT_LONG -"8050": -- PR_EMS_AB_ANCESTOR_ID -- PT_BINARY -"8182": -- PR_EMS_AB_CHARACTER_SET_LIST -- PT_MV_TSTRING -3e09: -- PR_X400_DEFERRED_DELIVERY_CANCEL -- PT_BOOLEAN -"8051": -- PR_EMS_AB_ASSOC_REMOTE_DXA -- PT_OBJECT|PT_MV_TSTRING -"8183": -- PR_EMS_AB_USE_SITE_VALUES -- PT_BOOLEAN -814a: -- PR_EMS_AB_TRANSFER_TIMEOUT_NON_URGENT -- PT_LONG -80d4: -- PR_EMS_AB_MDB_USE_DEFAULTS -- PT_BOOLEAN -"8052": -- PR_EMS_AB_ASSOCIATION_LIFETIME -- PT_LONG -"8184": -- PR_EMS_AB_ENABLED_AUTHORIZATION_PACKAGES -- PT_MV_TSTRING -814b: -- PR_EMS_AB_TRANSFER_TIMEOUT_NORMAL -- PT_LONG -"4068": -- PR_INTERNET_SUBJECT -- PT_BINARY -80d5: -- PR_EMS_AB_MESSAGE_TRACKING_ENABLED -- PT_BOOLEAN -"8053": -- PR_EMS_AB_AUTH_ORIG_BL -- PT_OBJECT|PT_MV_TSTRING -"8185": -- PR_EMS_AB_CHARACTER_SET -- PT_TSTRING -814c: -- PR_EMS_AB_TRANSFER_TIMEOUT_URGENT -- PT_LONG -"4069": -- PR_INTERNET_SENT_REPRESENTING_NAME -- PT_BINARY -80d6: -- PR_EMS_AB_MONITOR_CLOCK -- PT_BOOLEAN -"8054": -- PR_EMS_AB_AUTHORIZED_DOMAIN -- PT_TSTRING -"8186": -- PR_EMS_AB_CONTENT_TYPE -- PT_LONG -814d: -- PR_EMS_AB_TRANSLATION_TABLE_USED -- PT_LONG -80d7: -- PR_EMS_AB_MONITOR_SERVERS -- PT_BOOLEAN -"8187": -- PR_EMS_AB_ANONYMOUS_ACCESS -- PT_BOOLEAN -814e: -- PR_EMS_AB_TRANSPORT_EXPEDITED_DATA -- PT_BOOLEAN -8c18: -- PR_EMS_AB_VIEW_FLAGS -- PT_LONG -80d8: -- PR_EMS_AB_MONITOR_SERVICES -- PT_BOOLEAN -"8055": -- PR_EMS_AB_AUTHORIZED_PASSWORD -- PT_BINARY -"8188": -- PR_EMS_AB_CONTROL_MSG_FOLDER_ID -- PT_BINARY -814f: -- PR_EMS_AB_TRUST_LEVEL -- PT_LONG -8c19: -- PR_EMS_AB_GROUP_BY_ATTR_VALUE_STR -- PT_TSTRING -80d9: -- PR_EMS_AB_MONITORED_CONFIGURATIONS -- PT_OBJECT|PT_MV_TSTRING -"8056": -- PR_EMS_AB_AUTHORIZED_USER -- PT_TSTRING -"8189": -- PR_EMS_AB_USENET_SITE_NAME -- PT_TSTRING -3fc9: -- PR_LAST_CONFLICT -- PT_BINARY -"8057": -- PR_EMS_AB_BUSINESS_CATEGORY -- PT_MV_TSTRING -"8058": -- PR_EMS_AB_CAN_CREATE_PF -- PT_OBJECT|PT_MV_TSTRING -8c20: -- PR_EMS_AB_INBOUND_ACCEPT_ALL -- PT_BOOLEAN -80e0: -- PR_EMS_AB_MONITORING_CACHED_VIA_MAIL -- PT_OBJECT|PT_MV_TSTRING -3fd0: -- PR_REPL_HEADER -- PT_BINARY -"8059": -- PR_EMS_AB_CAN_CREATE_PF_BL -- PT_OBJECT|PT_MV_TSTRING -8c21: -- PR_EMS_AB_ENABLED -- PT_BOOLEAN -80e1: -- PR_EMS_AB_MONITORING_CACHED_VIA_RPC -- PT_OBJECT|PT_MV_TSTRING -"8190": -- PR_EMS_AB_INCOMING_MSG_SIZE_LIMIT -- PT_LONG -8c22: -- PR_EMS_AB_PRESERVE_INTERNET_CONTENT -- PT_BOOLEAN -80e2: -- PR_EMS_AB_MONITORING_ESCALATION_PROCEDURE -- PT_MV_BINARY -"8191": -- PR_EMS_AB_SEND_TNEF -- PT_BOOLEAN -3fd1: -- PR_REPL_STATUS -- PT_BINARY -80aa: -- PR_EMS_AB_EXTENSION_NAME_INHERITED -- PT_MV_TSTRING -403d: -- PR_ORG_ADDR_TYPE -- PT_UNICODE -8c23: -- PR_EMS_AB_DISABLE_DEFERRED_COMMIT -- PT_BOOLEAN -80e3: -- PR_EMS_AB_MONITORING_HOTSITE_POLL_INTERVAL -- PT_LONG -"8060": -- PR_EMS_AB_CAN_PRESERVE_DNS -- PT_BOOLEAN -"8192": -- PR_EMS_AB_AUTHORIZED_PASSWORD_CONFIRM -- PT_BINARY -3fd2: -- PR_REPL_CHANGES -- PT_BINARY -80ab: -- PR_EMS_AB_FACSIMILE_TELEPHONE_NUMBER -- PT_MV_BINARY -403e: -- PR_ORG_EMAIL_ADDR -- PT_UNICODE -8c24: -- PR_EMS_AB_CLIENT_ACCESS_ENABLED -- PT_BOOLEAN -80e4: -- PR_EMS_AB_MONITORING_HOTSITE_POLL_UNITS -- PT_LONG -"8061": -- PR_EMS_AB_CLOCK_ALERT_OFFSET -- PT_LONG -"8193": -- PR_EMS_AB_INBOUND_NEWSFEED -- PT_TSTRING -3fd3: -- PR_REPL_RGM -- PT_BINARY -80ac: -- PR_EMS_AB_FILE_VERSION -- PT_BINARY -815a: -- PR_EMS_AB_X25_CALL_USER_DATA_OUTGOING -- PT_BINARY -8c25: -- PR_EMS_AB_REQUIRE_SSL -- PT_BOOLEAN -80e5: -- PR_EMS_AB_MONITORING_MAIL_UPDATE_INTERVAL -- PT_LONG -"8062": -- PR_EMS_AB_CLOCK_ALERT_REPAIR -- PT_BOOLEAN -"8194": -- PR_EMS_AB_NEWSFEED_TYPE -- PT_LONG -3fd4: -- PR_RMI -- PT_BINARY -80ad: -- PR_EMS_AB_FILTER_LOCAL_ADDRESSES -- PT_BOOLEAN -815b: -- PR_EMS_AB_X25_FACILITIES_DATA_INCOMING -- PT_BINARY -"8063": -- PR_EMS_AB_CLOCK_WARNING_OFFSET -- PT_LONG -80ae: -- PR_EMS_AB_FOLDERS_CONTAINER -- PT_OBJECT|PT_MV_TSTRING -80e6: -- PR_EMS_AB_MONITORING_MAIL_UPDATE_UNITS -- PT_LONG -815c: -- PR_EMS_AB_X25_FACILITIES_DATA_OUTGOING -- PT_BINARY -"8195": -- PR_EMS_AB_OUTBOUND_NEWSFEED -- PT_TSTRING -8c26: -- PR_EMS_AB_ANONYMOUS_ACCOUNT -- PT_TSTRING -3fd5: -- PR_INTERNAL_POST_REPLY -- PT_BINARY -"8064": -- PR_EMS_AB_CLOCK_WARNING_REPAIR -- PT_BOOLEAN -80af: -- PR_EMS_AB_GARBAGE_COLL_PERIOD -- PT_LONG -80e7: -- PR_EMS_AB_MONITORING_NORMAL_POLL_INTERVAL -- PT_LONG -815d: -- PR_EMS_AB_X25_LEASED_LINE_PORT -- PT_BINARY -"8196": -- PR_EMS_AB_NEWSGROUP_LIST -- PT_BINARY -8c27: -- PR_EMS_AB_CERTIFICATE_CHAIN_V3 -- PT_BINARY -3fd6: -- PR_NTSD_MODIFICATION_TIME -- PT_SYSTIME -"8065": -- PR_EMS_AB_COMPUTER_NAME -- PT_TSTRING -80e8: -- PR_EMS_AB_MONITORING_NORMAL_POLL_UNITS -- PT_LONG -815e: -- PR_EMS_AB_X25_LEASED_OR_SWITCHED -- PT_BOOLEAN -"8197": -- PR_EMS_AB_NNTP_DISTRIBUTIONS -- PT_MV_TSTRING -8c28: -- PR_EMS_AB_CERTIFICATE_REVOCATION_LIST_V3 -- PT_BINARY -802d: -- PR_EMS_AB_EXTENSION_ATTRIBUTE_1 -- PT_TSTRING -3fd8: -- PR_PREVIEW_UNREAD -- PT_TSTRING -"8066": -- PR_EMS_AB_CONNECTED_DOMAINS -- PT_MV_TSTRING -80e9: -- PR_EMS_AB_MONITORING_RECIPIENTS -- PT_OBJECT|PT_MV_TSTRING -815f: -- PR_EMS_AB_X25_REMOTE_MTA_PHONE -- PT_TSTRING -"8198": -- PR_EMS_AB_NEWSGROUP -- PT_TSTRING -8c29: -- PR_EMS_AB_CERTIFICATE_REVOCATION_LIST_V1 -- PT_BINARY -802e: -- PR_EMS_AB_EXTENSION_ATTRIBUTE_2 -- PT_TSTRING -3fd9: -- PR_PREVIEW -- PT_TSTRING -"8067": -- PR_EMS_AB_CONTAINER_INFO -- PT_LONG -"8199": -- PR_EMS_AB_MODERATOR -- PT_TSTRING -802f: -- PR_EMS_AB_EXTENSION_ATTRIBUTE_3 -- PT_TSTRING -"8068": -- PR_EMS_AB_COST -- PT_LONG -"8069": -- PR_EMS_AB_COUNTRY_NAME -- PT_TSTRING -80f0: -- PR_EMS_AB_MTA_LOCAL_DESIG -- PT_TSTRING -8c30: -- PR_EMS_AB_CROSS_CERTIFICATE_CRL -- PT_MV_BINARY -"3000": -- PR_ROWID -- PT_LONG -80f1: -- PR_EMS_AB_N_ADDRESS -- PT_BINARY -8c31: -- PR_EMS_AB_SEND_EMAIL_MESSAGE -- PT_BOOLEAN -"3001": -- PR_DISPLAY_NAME -- PT_TSTRING -80ba: -- PR_EMS_AB_IMPORT_CONTAINER -- PT_OBJECT|PT_MV_TSTRING -80f2: -- PR_EMS_AB_N_ADDRESS_TYPE -- PT_LONG -8c32: -- PR_EMS_AB_ENABLE_COMPATIBILITY -- PT_BOOLEAN -"3002": -- PR_ADDRTYPE -- PT_TSTRING -3fe2: -- PR_FOLDER_DESIGN_FLAGS -- PT_LONG -"8070": -- PR_EMS_AB_DESTINATION_INDICATOR -- PT_MV_TSTRING -80bb: -- PR_EMS_AB_IMPORT_SENSITIVITY -- PT_LONG -80f3: -- PR_EMS_AB_NT_MACHINE_NAME -- PT_TSTRING -8c33: -- PR_EMS_AB_SMIME_ALG_LIST_NA -- PT_MV_TSTRING -3fe3: -- PR_DELEGATED_BY_RULE -- PT_BOOLEAN -"8071": -- PR_EMS_AB_DIAGNOSTIC_REG_KEY -- PT_TSTRING -80bc: -- PR_EMS_AB_INBOUND_SITES -- PT_OBJECT|PT_MV_TSTRING -80f4: -- PR_EMS_AB_NUM_OF_OPEN_RETRIES -- PT_LONG -8c34: -- PR_EMS_AB_SMIME_ALG_LIST_OTHER -- PT_MV_TSTRING -"3003": -- PR_EMAIL_ADDRESS -- PT_TSTRING -3fe4: -- PR_DESIGN_IN_PROGRESS -- PT_BOOLEAN -"8072": -- PR_EMS_AB_DL_MEM_REJECT_PERMS_BL -- PT_OBJECT|PT_MV_TSTRING -80bd: -- PR_EMS_AB_INSTANCE_TYPE -- PT_LONG -80f5: -- PR_EMS_AB_NUM_OF_TRANSFER_RETRIES -- PT_LONG -8c35: -- PR_EMS_AB_SMIME_ALG_SELECTED_NA -- PT_TSTRING -"3004": -- PR_COMMENT -- PT_TSTRING -803a: -- PR_EMS_AB_HELP_DATA16 -- PT_BINARY -3fe5: -- PR_SECURE_ORIGINATION -- PT_BOOLEAN -"8073": -- PR_EMS_AB_DL_MEM_SUBMIT_PERMS_BL -- PT_OBJECT|PT_MV_TSTRING -80be: -- PR_EMS_AB_INTERNATIONAL_ISDN_NUMBER -- PT_MV_TSTRING -80f6: -- PR_EMS_AB_OBJECT_CLASS_CATEGORY -- PT_LONG -8c36: -- PR_EMS_AB_SMIME_ALG_SELECTED_OTHER -- PT_TSTRING -"3005": -- PR_DEPTH -- PT_LONG -803b: -- PR_EMS_AB_HELP_FILE_NAME -- PT_TSTRING -3fe6: -- PR_PUBLISH_IN_ADDRESS_BOOK -- PT_BOOLEAN -"8074": -- PR_EMS_AB_DL_MEMBER_RULE -- PT_MV_BINARY -80bf: -- PR_EMS_AB_INVOCATION_ID -- PT_BINARY -80f7: -- PR_EMS_AB_OBJECT_VERSION -- PT_LONG -8c37: -- PR_EMS_AB_DEFAULT_MESSAGE_FORMAT -- PT_BOOLEAN -"3006": -- PR_PROVIDER_DISPLAY -- PT_TSTRING -803c: -- PR_EMS_AB_OBJ_DIST_NAME -- PT_OBJECT|PT_MV_TSTRING -3fe7: -- PR_RESOLVE_METHOD -- PT_LONG -3d00: -- PR_STORE_PROVIDERS -- PT_BINARY -"8075": -- PR_EMS_AB_DOMAIN_DEF_ALT_RECIP -- PT_OBJECT|PT_MV_TSTRING -80f8: -- PR_EMS_AB_OFF_LINE_AB_CONTAINERS -- PT_OBJECT|PT_MV_TSTRING -8c38: -- PR_EMS_AB_TYPE -- PT_TSTRING -"3007": -- PR_CREATION_TIME -- PT_SYSTIME -803d: -- PR_EMS_AB_ENCRYPT_ALG_SELECTED_OTHER -- PT_TSTRING -3fe8: -- PR_ADDRESS_BOOK_DISPLAY_NAME -- PT_TSTRING -3d01: -- PR_AB_PROVIDERS -- PT_BINARY -"8076": -- PR_EMS_AB_DOMAIN_NAME -- PT_TSTRING -80f9: -- PR_EMS_AB_OFF_LINE_AB_SCHEDULE -- PT_BINARY -"3008": -- PR_LAST_MODIFICATION_TIME -- PT_SYSTIME -803e: -- PR_EMS_AB_AUTOREPLY_SUBJECT -- PT_TSTRING -3fe9: -- PR_EFORMS_LOCALE_ID -- PT_LONG -3d02: -- PR_TRANSPORT_PROVIDERS -- PT_BINARY -"8077": -- PR_EMS_AB_DSA_SIGNATURE -- PT_BINARY -"3009": -- PR_RESOURCE_FLAGS -- PT_LONG -803f: -- PR_EMS_AB_HOME_PUBLIC_SERVER -- PT_OBJECT|PT_MV_TSTRING -"8078": -- PR_EMS_AB_DXA_ADMIN_COPY -- PT_BOOLEAN -3d04: -- PR_DEFAULT_PROFILE -- PT_BOOLEAN -"8079": -- PR_EMS_AB_DXA_ADMIN_FORWARD -- PT_BOOLEAN -3ff0: -- PR_CONFLICT_ENTRYID -- PT_BINARY -8c40: -- PR_EMS_AB_VOICE_MAIL_FLAGS -- PT_MV_BINARY -405a: -- PR_MODIFIER_FLAGS -- PT_LONG -3d05: -- PR_AB_SEARCH_PATH -- PT_MV_BINARY -3ff1: -- PR_MESSAGE_LOCALE_ID -- PT_LONG -8c41: -- PR_EMS_AB_VOICE_MAIL_VOLUME -- PT_LONG -405b: -- PR_ORIGINATOR_FLAGS -- PT_LONG -3d06: -- PR_AB_DEFAULT_DIR -- PT_BINARY -3ff2: -- PR_RULE_TRIGGER_HISTORY -- PT_BINARY -80ca: -- PR_EMS_AB_LOG_FILENAME -- PT_TSTRING -8c42: -- PR_EMS_AB_VOICE_MAIL_SPEED -- PT_LONG -405c: -- PR_REPORT_DESTINATION_FLAGS -- PT_LONG -"8080": -- PR_EMS_AB_DXA_EXCHANGE_OPTIONS -- PT_LONG -3d07: -- PR_AB_DEFAULT_PAB -- PT_BINARY -80cb: -- PR_EMS_AB_LOG_ROLLOVER_INTERVAL -- PT_LONG -8c43: -- PR_EMS_AB_VOICE_MAIL_RECORDING_LENGTH -- PT_MV_LONG -405d: -- PR_ORIGINAL_AUTHOR_FLAGS -- PT_LONG -"6800": -- PR_MAILBEAT_BOUNCE_SERVER -- PT_UNICODE -3ff3: -- PR_MOVE_TO_STORE_ENTRYID -- PT_BINARY -"8081": -- PR_EMS_AB_DXA_EXPORT_NOW -- PT_BOOLEAN -3d08: -- PR_FILTERING_HOOKS -- PT_BINARY -80cc: -- PR_EMS_AB_MAINTAIN_AUTOREPLY_HISTORY -- PT_BOOLEAN -817a: -- PR_EMS_AB_USN_INTERSITE -- PT_LONG -8c44: -- PR_EMS_AB_DISPLAY_NAME_SUFFIX -- PT_TSTRING -"6801": -- PR_MAILBEAT_REQUEST_SENT -- PT_SYSTIME -3ff4: -- PR_MOVE_TO_FOLDER_ENTRYID -- PT_BINARY -"8082": -- PR_EMS_AB_DXA_FLAGS -- PT_LONG -3d09: -- PR_SERVICE_NAME -- PT_TSTRING -80cd: -- PR_EMS_AB_MAPI_DISPLAY_TYPE -- PT_LONG -817b: -- PR_EMS_AB_SUB_SITE -- PT_TSTRING -8c45: -- PR_EMS_AB_ATTRIBUTE_CERTIFICATE -- PT_MV_BINARY -"6802": -- PR_USENET_SITE_NAME -- PT_UNICODE -3ff5: -- PR_STORAGE_QUOTA_LIMIT -- PT_LONG -"8083": -- PR_EMS_AB_DXA_IMP_SEQ -- PT_TSTRING -804a: -- PR_EMS_AB_ADMIN_DESCRIPTION -- PT_TSTRING -80ce: -- PR_EMS_AB_MAPI_ID -- PT_LONG -817c: -- PR_EMS_AB_SCHEMA_VERSION -- PT_MV_LONG -8c46: -- PR_EMS_AB_DELTA_REVOCATION_LIST -- PT_MV_BINARY -"6803": -- PR_MAILBEAT_REQUEST_RECEIVED -- PT_SYSTIME -3ff6: -- PR_EXCESS_STORAGE_USED -- PT_LONG -"3700": -- PR_ATTACHMENT_X400_PARAMETERS -- PT_BINARY -"8084": -- PR_EMS_AB_DXA_IMP_SEQ_TIME -- PT_SYSTIME -0e00: -- PR_CURRENT_VERSION -- PT_I8 -804b: -- PR_EMS_AB_ADMIN_DISPLAY_NAME -- PT_TSTRING -80cf: -- PR_EMS_AB_MDB_BACKOFF_INTERVAL -- PT_LONG -817d: -- PR_EMS_AB_NNTP_CHARACTER_SET -- PT_TSTRING -8c47: -- PR_EMS_AB_SECURITY_POLICY -- PT_MV_BINARY -"6804": -- PR_MAILBEAT_REQUEST_PROCESSED -- PT_SYSTIME -3ff7: -- PR_SVR_GENERATING_QUOTA_MSG -- PT_TSTRING -3d10: -- PR_SERVICE_DELETE_FILES -- PT_MV_TSTRING -"8085": -- PR_EMS_AB_DXA_IMP_SEQ_USN -- PT_LONG -0e01: -- PR_DELETE_AFTER_SUBMIT -- PT_BOOLEAN -804c: -- PR_EMS_AB_ADMIN_EXTENSION_DLL -- PT_TSTRING -817e: -- PR_EMS_AB_USE_SERVER_VALUES -- PT_BOOLEAN -8c48: -- PR_EMS_AB_SUPPORT_SMIME_SIGNATURES -- PT_BOOLEAN -"3701": -- PR_ATTACH_DATA -- PT_OBJECT|PT_BINARY -3ff8: -- PR_CREATOR_NAME -- PT_TSTRING -"3702": -- PR_ATTACH_ENCODING -- PT_BINARY -3d11: -- PR_AB_SEARCH_PATH_UPDATE -- PT_BINARY -"8086": -- PR_EMS_AB_DXA_IMPORT_NOW -- PT_BOOLEAN -0e02: -- PR_DISPLAY_BCC -- PT_TSTRING -3e0a: -- PR_HEADER_FOLDER_ENTRYID -- PT_BINARY -804d: -- PR_EMS_AB_ALIASED_OBJECT_NAME -- PT_OBJECT|PT_MV_TSTRING -817f: -- PR_EMS_AB_ENABLED_PROTOCOLS -- PT_LONG -8c49: -- PR_EMS_AB_DELEGATE_USER -- PT_BOOLEAN -"6806": -- PR_MAILBEAT_REPLY_SENT -- PT_SYSTIME -3ff9: -- PR_CREATOR_ENTRYID -- PT_BINARY -"3703": -- PR_ATTACH_EXTENSION -- PT_TSTRING -3d12: -- PR_PROFILE_NAME -- PT_TSTRING -"8087": -- PR_EMS_AB_DXA_IN_TEMPLATE_MAP -- PT_MV_TSTRING -0e03: -- PR_DISPLAY_CC -- PT_TSTRING -3e0b: -- PR_REMOTE_PROGRESS -- PT_LONG -804e: -- PR_EMS_AB_ALT_RECIPIENT -- PT_OBJECT|PT_MV_TSTRING -"6807": -- PR_MAILBEAT_REPLY_SUBMIT -- PT_SYSTIME -"3704": -- PR_ATTACH_FILENAME -- PT_TSTRING -"8088": -- PR_EMS_AB_DXA_LOCAL_ADMIN -- PT_OBJECT|PT_MV_TSTRING -0e04: -- PR_DISPLAY_TO -- PT_TSTRING -3e0c: -- PR_REMOTE_PROGRESS_TEXT -- PT_TSTRING -804f: -- PR_EMS_AB_ALT_RECIPIENT_BL -- PT_OBJECT|PT_MV_TSTRING -"6808": -- PR_MAILBEAT_REPLY_RECEIVED -- PT_SYSTIME -"3705": -- PR_ATTACH_METHOD -- PT_LONG -"8089": -- PR_EMS_AB_DXA_LOGGING_LEVEL -- PT_LONG -0e05: -- PR_PARENT_DISPLAY -- PT_TSTRING -3e0d: -- PR_REMOTE_VALIDATE_OK -- PT_BOOLEAN -8c50: -- PR_EMS_AB_LIST_PUBLIC_FOLDERS -- PT_BOOLEAN -"6809": -- PR_MAILBEAT_REPLY_PROCESSED -- PT_SYSTIME -0e06: -- PR_MESSAGE_DELIVERY_TIME -- PT_SYSTIME -8c51: -- PR_EMS_AB_LABELEDURI -- PT_TSTRING -"3707": -- PR_ATTACH_LONG_FILENAME -- PT_TSTRING -0e07: -- PR_MESSAGE_FLAGS -- PT_LONG -80da: -- PR_EMS_AB_MONITORED_SERVERS -- PT_OBJECT|PT_MV_TSTRING -8c1a: -- PR_EMS_AB_GROUP_BY_ATTR_VALUE_DN -- PT_OBJECT|PT_MV_TSTRING -8c52: -- PR_EMS_AB_RETURN_EXACT_MSG_SIZE -- PT_BOOLEAN -"3708": -- PR_ATTACH_PATHNAME -- PT_TSTRING -"8090": -- PR_EMS_AB_DXA_PREV_REMOTE_ENTRIES -- PT_OBJECT|PT_MV_TSTRING -80db: -- PR_EMS_AB_MONITORED_SERVICES -- PT_MV_TSTRING -8c1b: -- PR_EMS_AB_VIEW_DEFINITION -- PT_MV_BINARY -8c53: -- PR_EMS_AB_GENERATION_QUALIFIER -- PT_TSTRING -3fca: -- PR_CONFLICT_MSG_KEY -- PT_BINARY -0e08: -- PR_MESSAGE_SIZE -- PT_LONG|PT_I8 -"3709": -- PR_ATTACH_RENDERING -- PT_BINARY -0e09: -- PR_PARENT_ENTRYID -- PT_BINARY -"8091": -- PR_EMS_AB_DXA_PREV_REPLICATION_SENSITIVITY -- PT_LONG -80dc: -- PR_EMS_AB_MONITORING_ALERT_DELAY -- PT_LONG -818a: -- PR_EMS_AB_CONTROL_MSG_RULES -- PT_BINARY -8c1c: -- PR_EMS_AB_MIME_TYPES -- PT_BINARY -8c54: -- PR_EMS_AB_HOUSE_IDENTIFIER -- PT_TSTRING -3f80: -- PR_DID -- PT_I8 -"8092": -- PR_EMS_AB_DXA_PREV_TEMPLATE_OPTIONS -- PT_LONG -80dd: -- PR_EMS_AB_MONITORING_ALERT_UNITS -- PT_LONG -818b: -- PR_EMS_AB_AVAILABLE_DISTRIBUTIONS -- PT_TSTRING -8c1d: -- PR_EMS_AB_LDAP_SEARCH_CFG -- PT_LONG -8c55: -- PR_EMS_AB_SUPPORTED_ALGORITHMS -- PT_BINARY -3f81: -- PR_SEQID -- PT_I8 -805a: -- PR_EMS_AB_CAN_CREATE_PF_DL -- PT_OBJECT|PT_MV_TSTRING -"8093": -- PR_EMS_AB_DXA_PREV_TYPES -- PT_LONG -80de: -- PR_EMS_AB_MONITORING_AVAILABILITY_STYLE -- PT_LONG -8c1e: -- PR_EMS_AB_INBOUND_DN -- PT_OBJECT|PT_MV_TSTRING -8c56: -- PR_EMS_AB_DMD_NAME -- PT_TSTRING -3f82: -- PR_DRAFTID -- PT_I8 -805b: -- PR_EMS_AB_CAN_CREATE_PF_DL_BL -- PT_OBJECT|PT_MV_TSTRING -"3710": -- PR_ATTACH_MIME_SEQUENCE -- PT_LONG -0e10: -- PR_SPOOLER_STATUS -- PT_LONG -"8094": -- PR_EMS_AB_DXA_RECIPIENT_CP -- PT_TSTRING -80df: -- PR_EMS_AB_MONITORING_AVAILABILITY_WINDOW -- PT_BINARY -818d: -- PR_EMS_AB_OUTBOUND_HOST -- PT_BINARY -8c57: -- PR_EMS_AB_EXTENSION_ATTRIBUTE_11 -- PT_TSTRING -3f83: -- PR_CHECK_IN_TIME -- PT_SYSTIME -805c: -- PR_EMS_AB_CAN_NOT_CREATE_PF -- PT_OBJECT|PT_MV_TSTRING -0e11: -- PR_TRANSPORT_STATUS -- PT_LONG -"8095": -- PR_EMS_AB_DXA_REMOTE_CLIENT -- PT_OBJECT|PT_MV_TSTRING -818e: -- PR_EMS_AB_INBOUND_HOST -- PT_MV_TSTRING -8c1f: -- PR_EMS_AB_INBOUND_NEWSFEED_TYPE -- PT_BOOLEAN -8c58: -- PR_EMS_AB_EXTENSION_ATTRIBUTE_12 -- PT_TSTRING -3f84: -- PR_CHECK_IN_COMMENT -- PT_UNICODE -805d: -- PR_EMS_AB_CAN_NOT_CREATE_PF_BL -- PT_OBJECT|PT_MV_TSTRING -"3712": -- PR_ATTACH_CONTENT_ID -- PT_TSTRING -0e12: -- PR_MESSAGE_RECIPIENTS -- PT_OBJECT -"8096": -- PR_EMS_AB_DXA_REQ_SEQ -- PT_TSTRING -818f: -- PR_EMS_AB_OUTGOING_MSG_SIZE_LIMIT -- PT_LONG -8c59: -- PR_EMS_AB_EXTENSION_ATTRIBUTE_13 -- PT_TSTRING -3d21: -- PR_ADMIN_SECURITY_DESCRIPTOR -- PT_BINARY -3f85: -- PR_VERSION_OP_CODE -- PT_LONG -805e: -- PR_EMS_AB_CAN_NOT_CREATE_PF_DL -- PT_OBJECT|PT_MV_TSTRING -"3713": -- PR_ATTACH_CONTENT_LOCATION -- PT_TSTRING -0e13: -- PR_MESSAGE_ATTACHMENTS -- PT_OBJECT -"8097": -- PR_EMS_AB_DXA_REQ_SEQ_TIME -- PT_SYSTIME -3f86: -- PR_VERSION_OP_DATA -- PT_BINARY -805f: -- PR_EMS_AB_CAN_NOT_CREATE_PF_DL_BL -- PT_OBJECT|PT_MV_TSTRING -"3714": -- PR_ATTACH_FLAGS -- PT_LONG -0e14: -- PR_SUBMIT_FLAGS -- PT_LONG -"8098": -- PR_EMS_AB_DXA_REQ_SEQ_USN -- PT_LONG -3f87: -- PR_VERSION_SEQUENCE_NUMBER -- PT_LONG -0e15: -- PR_RECIPIENT_STATUS -- PT_LONG -"8099": -- PR_EMS_AB_DXA_REQNAME -- PT_TSTRING -8c60: -- PR_EMS_AB_EXTENSION_ATTRIBUTE_14 -- PT_TSTRING -3f88: -- PR_ATTACH_ID -- PT_I8 -"6001": -- PR_DOTSTUFF_STATE -- PT_LONG -0e16: -- PR_TRANSPORT_KEY -- PT_LONG -8c61: -- PR_EMS_AB_EXTENSION_ATTRIBUTE_15 -- PT_TSTRING -"3716": -- PR_ATTACH_CONTENT_DISPOSITION -- PT_UNICODE -0e17: -- PR_MSG_STATUS -- PT_LONG -80ea: -- PR_EMS_AB_MONITORING_RECIPIENTS_NDR -- PT_OBJECT|PT_MV_TSTRING -8c62: -- PR_EMS_AB_REPLICATED_OBJECT_VERSION -- PT_LONG -3fda: -- PR_ABSTRACT -- PT_TSTRING -0e18: -- PR_MESSAGE_DOWNLOAD_TIME -- PT_LONG -80eb: -- PR_EMS_AB_MONITORING_RPC_UPDATE_INTERVAL -- PT_LONG -8c63: -- PR_EMS_AB_MAIL_DROP -- PT_TSTRING -3fdb: -- PR_DL_REPORT_FLAGS -- PT_LONG -0e19: -- PR_CREATION_VERSION -- PT_I8 -80ec: -- PR_EMS_AB_MONITORING_RPC_UPDATE_UNITS -- PT_LONG -819a: -- PR_EMS_AB_AUTHENTICATION_TO_USE -- PT_TSTRING -8c64: -- PR_EMS_AB_FORWARDING_ADDRESS -- PT_TSTRING -3f90: -- PR_VERSIONING_FLAGS -- PT_SHORT -3fdc: -- PR_BILATERAL_INFO -- PT_BINARY -80ed: -- PR_EMS_AB_MONITORING_WARNING_DELAY -- PT_LONG -819b: -- PR_EMS_AB_HTTP_PUB_GAL -- PT_BOOLEAN -8c65: -- PR_EMS_AB_FORM_DATA -- PT_BINARY -3f91: -- PR_PKM_LAST_UNAPPROVED_VID -- PT_BINARY -3fdd: -- PR_MSG_BODY_ID -- PT_LONG -806a: -- PR_EMS_AB_DELIV_CONT_LENGTH -- PT_LONG -80ee: -- PR_EMS_AB_MONITORING_WARNING_UNITS -- PT_LONG -819c: -- PR_EMS_AB_HTTP_PUB_GAL_LIMIT -- PT_LONG -8c66: -- PR_EMS_AB_OWA_SERVER -- PT_TSTRING -3f92: -- PR_MV_PKM_VERSION_LABELS -- PT_MV_UNICODE -0e20: -- PR_ATTACH_SIZE -- PT_LONG -3fde: -- PR_INTERNET_CPID -- PT_LONG -806b: -- PR_EMS_AB_DELIV_EITS -- PT_MV_BINARY -80ef: -- PR_EMS_AB_MTA_LOCAL_CRED -- PT_TSTRING -8c67: -- PR_EMS_AB_EMPLOYEE_NUMBER -- PT_TSTRING -3f93: -- PR_MV_PKM_VERSION_STATUS -- PT_MV_UNICODE -0e21: -- PR_ATTACH_NUM -- PT_LONG -3fdf: -- PR_AUTO_RESPONSE_SUPPRESS -- PT_LONG -806c: -- PR_EMS_AB_DELIV_EXT_CONT_TYPES -- PT_MV_BINARY -819e: -- PR_EMS_AB_HTTP_PUB_PF -- PT_MV_BINARY -8c68: -- PR_EMS_AB_TELEPHONE_PERSONAL_PAGER -- PT_TSTRING -3f94: -- PR_PKM_INTERNAL_DATA -- PT_BINARY -0e22: -- PR_PREPROCESS -- PT_BOOLEAN -806d: -- PR_EMS_AB_DELIVER_AND_REDIRECT -- PT_BOOLEAN -8c69: -- PR_EMS_AB_EMPLOYEE_TYPE -- PT_TSTRING -806e: -- PR_EMS_AB_DELIVERY_MECHANISM -- PT_LONG -0e23: -- PR_INTERNET_ARTICLE_NUMBER -- PT_LONG -806f: -- PR_EMS_AB_DESCRIPTION -- PT_MV_TSTRING -0e24: -- PR_NEWSGROUP_NAME -- PT_TSTRING -0e25: -- PR_ORIGINATING_MTA_CERTIFICATE -- PT_BINARY -0e26: -- PR_PROOF_OF_SUBMISSION -- PT_BINARY -80fa: -- PR_EMS_AB_OFF_LINE_AB_SERVER -- PT_OBJECT|PT_MV_TSTRING -8c3a: -- PR_EMS_AB_DO_OAB_VERSION -- PT_LONG -0e27: -- PR_NT_SECURITY_DESCRIPTOR -- PT_BINARY -3fea: -- PR_HAS_DAMS -- PT_BOOLEAN -80fb: -- PR_EMS_AB_OFF_LINE_AB_STYLE -- PT_LONG -8c3b: -- PR_EMS_AB_VOICE_MAIL_SYSTEM_GUID -- PT_BINARY -"0001": -- PR_ACKNOWLEDGEMENT_MODE -- PT_LONG -300a: -- PR_PROVIDER_DLL_NAME -- PT_TSTRING -3feb: -- PR_DEFERRED_SEND_NUMBER -- PT_LONG -80fc: -- PR_EMS_AB_OID_TYPE -- PT_LONG -8c3c: -- PR_EMS_AB_VOICE_MAIL_USER_ID -- PT_TSTRING -"0002": -- PR_ALTERNATE_RECIPIENT_ALLOWED -- PT_BOOLEAN -300b: -- PR_SEARCH_KEY -- PT_BINARY -3fec: -- PR_DEFERRED_SEND_UNITS -- PT_LONG -80fd: -- PR_EMS_AB_OM_OBJECT_CLASS -- PT_BINARY -8c3d: -- PR_EMS_AB_VOICE_MAIL_PASSWORD -- PT_TSTRING -"0003": -- PR_AUTHORIZING_USERS -- PT_BINARY -807a: -- PR_EMS_AB_DXA_ADMIN_UPDATE -- PT_LONG -"6701": -- PR_PST_REMEMBER_PW -- PT_BOOLEAN -300c: -- PR_PROVIDER_UID -- PT_BINARY -3fed: -- PR_EXPIRY_NUMBER -- PT_LONG -80fe: -- PR_EMS_AB_OM_SYNTAX -- PT_LONG -8c3e: -- PR_EMS_AB_VOICE_MAIL_RECORDED_NAME -- PT_BINARY -"0004": -- PR_AUTO_FORWARD_COMMENT -- PT_TSTRING -807b: -- PR_EMS_AB_DXA_APPEND_REQCN -- PT_BOOLEAN -300d: -- PR_PROVIDER_ORDINAL -- PT_LONG -3fee: -- PR_EXPIRY_UNITS -- PT_LONG -80ff: -- PR_EMS_AB_OOF_REPLY_TO_ORIGINATOR -- PT_BOOLEAN -8c3f: -- PR_EMS_AB_VOICE_MAIL_GREETINGS -- PT_MV_TSTRING -"6702": -- PR_OST_ENCRYPTION -- PT_LONG -3fef: -- PR_DEFERRED_SEND_TIME -- PT_SYSTIME -"0005": -- PR_AUTO_FORWARDED -- PT_BOOLEAN -807c: -- PR_EMS_AB_DXA_CONF_CONTAINER_LIST -- PT_OBJECT|PT_MV_TSTRING -"6703": -- PR_PST_PW_SZ_OLD -- PT_TSTRING -"0006": -- PR_CONTENT_CONFIDENTIALITY_ALGORITHM_ID -- PT_BINARY -807d: -- PR_EMS_AB_DXA_CONF_REQ_TIME -- PT_SYSTIME -"6704": -- PR_PST_PW_SZ_NEW -- PT_TSTRING -"3600": -- PR_CONTAINER_FLAGS -- PT_LONG -"0007": -- PR_CONTENT_CORRELATOR -- PT_BINARY -807e: -- PR_EMS_AB_DXA_CONF_SEQ -- PT_TSTRING -"6705": -- PR_SORT_LOCALE_ID -- PT_LONG -"3601": -- PR_FOLDER_TYPE -- PT_LONG -0008: -- PR_CONTENT_IDENTIFIER -- PT_TSTRING -3d0a: -- PR_SERVICE_DLL_NAME -- PT_TSTRING -807f: -- PR_EMS_AB_DXA_CONF_SEQ_USN -- PT_LONG -"3602": -- PR_CONTENT_COUNT -- PT_LONG -0009: -- PR_CONTENT_LENGTH -- PT_LONG -3d0b: -- PR_SERVICE_ENTRY_NAME -- PT_TSTRING -"3603": -- PR_CONTENT_UNREAD -- PT_LONG -"6707": -- PR_URL_NAME -- PT_UNICODE -3d0c: -- PR_SERVICE_UID -- PT_BINARY -"3604": -- PR_CREATE_TEMPLATES -- PT_OBJECT -3d0d: -- PR_SERVICE_EXTRA_UIDS -- PT_BINARY -"0010": -- PR_DELIVER_TIME -- PT_SYSTIME -"3605": -- PR_DETAILS_TABLE -- PT_OBJECT -"6709": -- PR_LOCAL_COMMIT_TIME -- PT_SYSTIME -3d0e: -- PR_SERVICES -- PT_BINARY -3ffa: -- PR_LAST_MODIFIER_NAME -- PT_TSTRING -f000: -- PR_EMS_AB_OTHER_RECIPS -- PT_OBJECT -3d0f: -- PR_SERVICE_SUPPORT_FILES -- PT_MV_TSTRING -3ffb: -- PR_LAST_MODIFIER_ENTRYID -- PT_BINARY -"0011": -- PR_DISCARD_REASON -- PT_LONG -"3607": -- PR_SEARCH -- PT_OBJECT -3ffc: -- PR_REPLY_RECIPIENT_SMTP_PROXIES -- PT_TSTRING -"0012": -- PR_DISCLOSURE_OF_RECIPIENTS -- PT_BOOLEAN -"6710": -- PR_URL_COMP_NAME_HASH -- PT_LONG -3ffd: -- PR_MESSAGE_CODEPAGE -- PT_LONG -"0013": -- PR_DL_EXPANSION_HISTORY -- PT_BINARY -"3609": -- PR_SELECTABLE -- PT_BOOLEAN -808a: -- PR_EMS_AB_DXA_NATIVE_ADDRESS_TYPE -- PT_TSTRING -0ff4: -- PR_ACCESS -- PT_LONG -"6711": -- PR_MSG_FOLDER_TEMPLATE_RES_2 -- PT_LONG -3ffe: -- PR_EXTENDED_ACL_DATA -- PT_BINARY -"0014": -- PR_DL_EXPANSION_PROHIBITED -- PT_BOOLEAN -808b: -- PR_EMS_AB_DXA_OUT_TEMPLATE_MAP -- PT_MV_TSTRING -0ff5: -- PR_ROW_TYPE -- PT_LONG -"6712": -- PR_RANK -- PT_LONG -"6844": -- PR_DELEGATES_DISPLAY_NAMES -- PT_MV_UNICODE -"0015": -- PR_EXPIRY_TIME -- PT_SYSTIME -808c: -- PR_EMS_AB_DXA_PASSWORD -- PT_TSTRING -0ff6: -- PR_INSTANCE_KEY -- PT_BINARY -3fff: -- PR_FROM_I_HAVE -- PT_BOOLEAN -"6713": -- PR_MSG_FOLDER_TEMPLATE_RES_4 -- PT_BOOLEAN -"6845": -- PR_DELEGATES_ENTRYIDS -- PT_MV_BINARY -"0016": -- PR_IMPLICIT_CONVERSION_PROHIBITED -- PT_BOOLEAN -370a: -- PR_ATTACH_TAG -- PT_BINARY -808d: -- PR_EMS_AB_DXA_PREV_EXCHANGE_OPTIONS -- PT_LONG -"3610": -- PR_FOLDER_ASSOCIATED_CONTENTS -- PT_OBJECT -0ff7: -- PR_ACCESS_LEVEL -- PT_LONG -"6714": -- PR_MSG_FOLDER_TEMPLATE_RES_5 -- PT_BOOLEAN -"0017": -- PR_IMPORTANCE -- PT_LONG -370b: -- PR_RENDERING_POSITION -- PT_LONG -808e: -- PR_EMS_AB_DXA_PREV_EXPORT_NATIVE_ONLY -- PT_BOOLEAN -0e0a: -- PR_SENTMAIL_ENTRYID -- PT_BINARY -"3611": -- PR_DEF_CREATE_DL -- PT_BINARY -0ff8: -- PR_MAPPING_SIGNATURE -- PT_BINARY -"6715": -- PR_MSG_FOLDER_TEMPLATE_RES_6 -- PT_BOOLEAN -"6847": -- PR_FREEBUSY_START_RANGE -- PT_LONG -0018: -- PR_IPM_ID -- PT_BINARY -370c: -- PR_ATTACH_TRANSPORT_NAME -- PT_TSTRING -808f: -- PR_EMS_AB_DXA_PREV_IN_EXCHANGE_SENSITIVITY -- PT_LONG -"3612": -- PR_DEF_CREATE_MAILUSER -- PT_BINARY -0ff9: -- PR_RECORD_KEY -- PT_BINARY -"6716": -- PR_MSG_FOLDER_TEMPLATE_RES_7 -- PT_BINARY -"6848": -- PR_FREEBUSY_END_RANGE -- PT_LONG -0019: -- PR_LATEST_DELIVERY_TIME -- PT_SYSTIME -370d: -- PR_ATTACH_LONG_PATHNAME -- PT_TSTRING -0e0c: -- PR_CORRELATE -- PT_BOOLEAN -"3613": -- PR_CONTAINER_CLASS -- PT_TSTRING -"6717": -- PR_MSG_FOLDER_TEMPLATE_RES_8 -- PT_BINARY -"6849": -- PR_FREEBUSY_EMAIL_ADDRESS -- PT_UNICODE -370e: -- PR_ATTACH_MIME_TAG -- PT_TSTRING -0e0d: -- PR_CORRELATE_MTSID -- PT_BINARY -"3614": -- PR_CONTAINER_MODIFY_VERSION -- PT_I8 -"6718": -- PR_MSG_FOLDER_TEMPLATE_RES_9 -- PT_BINARY -370f: -- PR_ATTACH_ADDITIONAL_INFO -- PT_BINARY -0e0e: -- PR_DISCRETE_VALUES -- PT_BOOLEAN -"0020": -- PR_ORIGINALLY_INTENDED_RECIPIENT_NAME -- PT_BINARY -"3615": -- PR_AB_PROVIDER_ID -- PT_BINARY -"6719": -- PR_MSG_FOLDER_TEMPLATE_RES_10 -- PT_UNICODE -"6850": -- PR_FREEBUSY_ALL_EVENTS -- PT_MV_BINARY -0e0f: -- PR_RESPONSIBILITY -- PT_BOOLEAN -"0021": -- PR_ORIGINAL_EITS -- PT_BINARY -"3616": -- PR_DEFAULT_VIEW_ENTRYID -- PT_BINARY -"6851": -- PR_FREEBUSY_TENTATIVE_MONTHS -- PT_MV_LONG -"3617": -- PR_ASSOC_CONTENT_COUNT -- PT_LONG -"3880": -- PR_SYNCEVENT_SUPPRESS_GUID -- PT_BINARY -"6720": -- PR_INTERNET_FREE_DOC_INFO -- PT_BINARY -"6852": -- PR_FREEBUSY_TENTATIVE_EVENTS -- PT_MV_BINARY -"0022": -- PR_ORIGINATOR_CERTIFICATE -- PT_BINARY -"0023": -- PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED -- PT_BOOLEAN -809a: -- PR_EMS_AB_DXA_SVR_SEQ -- PT_TSTRING -39fe: -- PR_SMTP_ADDRESS -- PT_UNICODE -"6721": -- PR_PF_OVER_HARD_QUOTA_LIMIT -- PT_LONG -"6853": -- PR_FREEBUSY_BUSY_MONTHS -- PT_MV_LONG -"0024": -- PR_ORIGINATOR_RETURN_ADDRESS -- PT_BINARY -809b: -- PR_EMS_AB_DXA_SVR_SEQ_TIME -- PT_SYSTIME -"6722": -- PR_PF_MSG_SIZE_LIMIT -- PT_LONG -"6854": -- PR_FREEBUSY_BUSY_EVENTS -- PT_MV_BINARY -39ff: -- PR_7BIT_DISPLAY_NAME -- PT_TSTRING -"0025": -- PR_PARENT_KEY -- PT_BINARY -809c: -- PR_EMS_AB_DXA_SVR_SEQ_USN -- PT_LONG -"6855": -- PR_FREEBUSY_OOF_MONTHS -- PT_MV_LONG -"0026": -- PR_PRIORITY -- PT_LONG -809d: -- PR_EMS_AB_DXA_TASK -- PT_LONG -3f8d: -- PR_PKM_DOC_STATUS -- PT_UNICODE -"6856": -- PR_FREEBUSY_OOF_EVENTS -- PT_MV_BINARY -0e1a: -- PR_MODIFY_VERSION -- PT_I8 -"0027": -- PR_ORIGIN_CHECK -- PT_BINARY -809e: -- PR_EMS_AB_DXA_TEMPLATE_OPTIONS -- PT_LONG -fff8: -- PR_EMS_AB_CHILD_RDNS -- PT_MV_TSTRING -0e1b: -- PR_HASATTACH -- PT_BOOLEAN -0028: -- PR_PROOF_OF_SUBMISSION_REQUESTED -- PT_BOOLEAN -809f: -- PR_EMS_AB_DXA_TEMPLATE_TIMESTAMP -- PT_SYSTIME -fff9: -- PR_EMS_AB_HIERARCHY_PATH -- PT_TSTRING -3f8e: -- PR_MV_PKM_OPERATION_REQ -- PT_MV_UNICODE -0e1c: -- PR_BODY_CRC -- PT_LONG -0029: -- PR_READ_RECEIPT_REQUESTED -- PT_BOOLEAN -3f8f: -- PR_PKM_DOC_INTERNAL_STATE -- PT_UNICODE -0e1d: -- PR_NORMALIZED_SUBJECT -- PT_TSTRING -"0030": -- PR_REPLY_TIME -- PT_SYSTIME -8c6a: -- PR_EMS_AB_TAGGED_X509_CERT -- PT_MV_BINARY -0e1f: -- PR_RTF_IN_SYNC -- PT_BOOLEAN -"0031": -- PR_REPORT_TAG -- PT_BINARY -8c6b: -- PR_EMS_AB_PERSONAL_TITLE -- PT_TSTRING -0e58: -- PR_CREATOR_SID -- PT_BINARY -"0032": -- PR_REPORT_TIME -- PT_SYSTIME -8c6c: -- PR_EMS_AB_LANGUAGE_ISO639 -- PT_TSTRING -0e59: -- PR_LAST_MODIFIER_SID -- PT_BINARY -"0033": -- PR_RETURNED_IPM -- PT_BOOLEAN -"0034": -- PR_SECURITY -- PT_LONG -"0035": -- PR_INCOMPLETE_COPY -- PT_BOOLEAN -0e61: -- PR_URL_COMP_NAME_POSTFIX -- PT_LONG -"0036": -- PR_SENSITIVITY -- PT_LONG -"6602": -- PR_PROFILE_HOME_SERVER -- PT_TSTRING -0e62: -- PR_URL_COMP_NAME_SET -- PT_BOOLEAN -"0037": -- PR_SUBJECT -- PT_TSTRING -0e63: -- PR_SUBFOLDER_CT -- PT_LONG -0038: -- PR_SUBJECT_IPM -- PT_BINARY -0c00: -- PR_CONTENT_INTEGRITY_CHECK -- PT_BINARY -0e64: -- PR_DELETED_SUBFOLDER_CT -- PT_LONG -"6868": -- PR_FREEBUSY_LAST_MODIFIED -- PT_SYSTIME -0039: -- PR_CLIENT_SUBMIT_TIME -- PT_SYSTIME -0c01: -- PR_EXPLICIT_CONVERSION -- PT_LONG -"6869": -- PR_FREEBUSY_NUM_MONTHS -- PT_LONG -0c02: -- PR_IPM_RETURN_REQUESTED -- PT_BOOLEAN -0e66: -- PR_DELETE_TIME -- PT_SYSTIME -"0040": -- PR_RECEIVED_BY_NAME -- PT_TSTRING -"6607": -- PR_PROFILE_UNRESOLVED_NAME -- PT_TSTRING -0c03: -- PR_MESSAGE_TOKEN -- PT_BINARY -0e67: -- PR_AGE_LIMIT -- PT_BINARY -"0041": -- PR_SENT_REPRESENTING_ENTRYID -- PT_BINARY -"6608": -- PR_PROFILE_UNRESOLVED_SERVER -- PT_TSTRING -0c04: -- PR_NDR_REASON_CODE -- PT_LONG -"0042": -- PR_SENT_REPRESENTING_NAME -- PT_TSTRING -0c05: -- PR_NDR_DIAG_CODE -- PT_LONG -000a: -- PR_CONTENT_RETURN_REQUESTED -- PT_BOOLEAN -"0043": -- PR_RCVD_REPRESENTING_ENTRYID -- PT_BINARY -0c06: -- PR_NON_RECEIPT_NOTIFICATION_REQUESTED -- PT_BOOLEAN -"6610": -- PR_PROFILE_OFFLINE_STORE_PATH -- PT_TSTRING -000b: -- PR_CONVERSATION_KEY -- PT_BINARY -0c07: -- PR_DELIVERY_POINT -- PT_LONG -000c: -- PR_CONVERSION_EITS -- PT_BINARY -"0044": -- PR_RCVD_REPRESENTING_NAME -- PT_TSTRING -0c08: -- PR_ORIGINATOR_NON_DELIVERY_REPORT_REQUESTED -- PT_BOOLEAN -670a: -- PR_LOCAL_COMMIT_TIME_MAX -- PT_SYSTIME -"6611": -- PR_PROFILE_OFFLINE_INFO -- PT_BINARY -000d: -- PR_CONVERSION_WITH_LOSS_PROHIBITED -- PT_BOOLEAN -"0045": -- PR_REPORT_ENTRYID -- PT_BINARY -0c09: -- PR_ORIGINATOR_REQUESTED_ALTERNATE_RECIPIENT -- PT_BINARY -670b: -- PR_DELETED_COUNT_TOTAL -- PT_LONG -"6743": -- PR_CONNECTION_MODULUS -- PT_LONG -"6612": -- PR_PROFILE_HOME_SERVER_DN -- PT_TSTRING -000e: -- PR_CONVERTED_EITS -- PT_BINARY -"0046": -- PR_READ_RECEIPT_ENTRYID -- PT_BINARY -670c: -- PR_AUTO_RESET -- PT_CLSID -"6744": -- PR_DELIVER_TO_DN -- PT_UNICODE -"6613": -- PR_PROFILE_HOME_SERVER_ADDRS -- PT_MV_TSTRING -000f: -- PR_DEFERRED_DELIVERY_TIME -- PT_SYSTIME -"0047": -- PR_MESSAGE_SUBMISSION_ID -- PT_BINARY -"6614": -- PR_PROFILE_SERVER_DN -- PT_TSTRING -0c10: -- PR_PHYSICAL_RENDITION_ATTRIBUTES -- PT_BINARY -0048: -- PR_PROVIDER_SUBMIT_TIME -- PT_SYSTIME -360a: -- PR_SUBFOLDERS -- PT_BOOLEAN -"6746": -- PR_MIME_SIZE -- PT_LONG -"6615": -- PR_PROFILE_FAVFLD_COMMENT -- PT_TSTRING -0c11: -- PR_PROOF_OF_DELIVERY -- PT_BINARY -0049: -- PR_ORIGINAL_SUBJECT -- PT_TSTRING -360b: -- PR_STATUS -- PT_LONG -"6747": -- PR_FILE_SIZE -- PT_I8 -"6616": -- PR_PROFILE_ALLPUB_DISPLAY_NAME -- PT_TSTRING -0c12: -- PR_PROOF_OF_DELIVERY_REQUESTED -- PT_BOOLEAN -360c: -- PR_ANR -- PT_TSTRING -"6748": -- PR_FID -- PT_I8 -"0050": -- PR_REPLY_RECIPIENT_NAMES -- PT_TSTRING -"6617": -- PR_PROFILE_ALLPUB_COMMENT -- PT_TSTRING -0c13: -- PR_RECIPIENT_CERTIFICATE -- PT_BINARY -360d: -- PR_CONTENTS_SORT_ORDER -- PT_MV_LONG -"6749": -- PR_PARENT_FID -- PT_I8 -"0051": -- PR_RECEIVED_BY_SEARCH_KEY -- PT_BINARY -0c14: -- PR_RECIPIENT_NUMBER_FOR_ADVICE -- PT_TSTRING -66a0: -- PR_NT_USER_NAME -- PT_TSTRING -360e: -- PR_CONTAINER_HIERARCHY -- PT_OBJECT -"0052": -- PR_RCVD_REPRESENTING_SEARCH_KEY -- PT_BINARY -0ffa: -- PR_STORE_RECORD_KEY -- PT_BINARY -0c15: -- PR_RECIPIENT_TYPE -- PT_LONG -66a1: -- PR_LOCALE_ID -- PT_LONG -360f: -- PR_CONTAINER_CONTENTS -- PT_OBJECT -0e79: -- PR_TRUST_SENDER -- PT_LONG -"6750": -- PR_ICS_NOTIF -- PT_LONG -"0053": -- PR_READ_RECEIPT_SEARCH_KEY -- PT_BINARY -0ffb: -- PR_STORE_ENTRYID -- PT_BINARY -0c16: -- PR_REGISTERED_MAIL_TYPE -- PT_LONG -66a2: -- PR_LAST_LOGON_TIME -- PT_SYSTIME -"1100": -- PR_P1_CONTENT -- PT_BINARY -001a: -- PR_MESSAGE_CLASS -- PT_TSTRING -36d0: -- PR_IPM_APPOINTMENT_ENTRYID -- PT_BINARY -"6751": -- PR_ARTICLE_NUM_NEXT -- PT_LONG -"0054": -- PR_REPORT_SEARCH_KEY -- PT_BINARY -0ffc: -- PR_MINI_ICON -- PT_BINARY -0c17: -- PR_REPLY_REQUESTED -- PT_BOOLEAN -66a3: -- PR_LAST_LOGOFF_TIME -- PT_SYSTIME -"1101": -- PR_P1_CONTENT_TYPE -- PT_BINARY -001b: -- PR_MESSAGE_DELIVERY_ID -- PT_BINARY -36d1: -- PR_IPM_CONTACT_ENTRYID -- PT_BINARY -"6752": -- PR_IMAP_LAST_ARTICLE_ID -- PT_LONG -0ffd: -- PR_ICON -- PT_BINARY -0c18: -- PR_REQUESTED_DELIVERY_METHOD -- PT_LONG -66a4: -- PR_STORAGE_LIMIT_INFORMATION -- PT_LONG -36d2: -- PR_IPM_JOURNAL_ENTRYID -- PT_BINARY -671a: -- PR_MSG_FOLDER_TEMPLATE_RES_11 -- PT_UNICODE -"6753": -- PR_NOT_822_RENDERABLE -- PT_BOOLEAN -"0055": -- PR_ORIGINAL_DELIVERY_TIME -- PT_SYSTIME -0ffe: -- PR_OBJECT_TYPE -- PT_LONG -0c19: -- PR_SENDER_ENTRYID -- PT_BINARY -66a5: -- PR_NEWSGROUP_COMPONENT -- PT_TSTRING -36d3: -- PR_IPM_NOTE_ENTRYID -- PT_BINARY -671b: -- PR_MSG_FOLDER_TEMPLATE_RES_12 -- PT_UNICODE -"0056": -- PR_ORIGINAL_AUTHOR_SEARCH_KEY -- PT_BINARY -66a6: -- PR_NEWSFEED_INFO -- PT_BINARY -"1000": -- PR_BODY -- PT_TSTRING -001e: -- PR_MESSAGE_SECURITY_LABEL -- PT_BINARY -36d4: -- PR_IPM_TASK_ENTRYID -- PT_BINARY -0fff: -- PR_ENTRYID -- PT_BINARY -"0057": -- PR_MESSAGE_TO_ME -- PT_BOOLEAN -66a7: -- PR_INTERNET_NEWSGROUP_NAME -- PT_TSTRING -001f: -- PR_OBSOLETED_IPMS -- PT_BINARY -36d5: -- PR_REMINDERS_ONLINE_ENTRYID -- PT_BINARY -684f: -- PR_FREEBUSY_ALL_MONTHS -- PT_MV_LONG -0058: -- PR_MESSAGE_CC_ME -- PT_BOOLEAN -66a8: -- PR_FOLDER_FLAGS -- PT_LONG -"1001": -- PR_REPORT_TEXT -- PT_TSTRING -36d6: -- PR_REMINDERS_OFFLINE_ENTRYID -- PT_BINARY -671e: -- PR_PF_PLATINUM_HOME_MDB -- PT_BOOLEAN -0059: -- PR_MESSAGE_RECIP_ME -- PT_BOOLEAN -66a9: -- PR_LAST_ACCESS_TIME -- PT_SYSTIME -"1002": -- PR_ORIGINATOR_AND_DL_EXPANSION_HISTORY -- PT_BINARY -36d7: -- PR_IPM_DRAFTS_ENTRYID -- PT_BINARY -671f: -- PR_PF_PROXY_REQUIRED -- PT_BOOLEAN -"6626": -- PR_ADDRBOOK_FOR_LOCAL_SITE_ENTRYID -- PT_BINARY -"1003": -- PR_REPORTING_DL_NAME -- PT_BINARY -361c: -- PR_PACKED_NAME_PROPS -- PT_BINARY -36d8: -- PR_OUTLOOK_2003_ENTRYIDS -- PT_MV_BINARY -"6758": -- PR_LTID -- PT_BINARY -"0060": -- PR_START_DATE -- PT_SYSTIME -"6627": -- PR_OFFLINE_MESSAGE_ENTRYID -- PT_BINARY -3a00: -- PR_ACCOUNT -- PT_TSTRING -"1004": -- PR_REPORTING_MTA_CERTIFICATE -- PT_BINARY -"6759": -- PR_CN_EXPORT -- PT_BINARY diff --git a/vendor/ruby-msg/data/named_map.yaml b/vendor/ruby-msg/data/named_map.yaml deleted file mode 100644 index 8de27d13f..000000000 --- a/vendor/ruby-msg/data/named_map.yaml +++ /dev/null @@ -1,114 +0,0 @@ -# this file provides for the mapping of the keys of named properties -# to symbolic names (as opposed to mapitags.yaml, which is currently -# in a different format, has a different source, and is only fixed -# code properties) -# -# essentially the symbols are slightly munged versions of the names -# given to these properties by CDO, or Outlook's object model. -# it was parsed out of cdo10.htm, and neatened up a bit. -# -# interestingly, despite having separate guids, the codes are picked not to -# clash. further the names themselves have only 3 clashes in all the below. -{ -[0x8005, PSETID_Address]: file_under, -[0x8017, PSETID_Address]: last_name_and_first_name, -[0x8018, PSETID_Address]: company_and_full_name, -[0x8019, PSETID_Address]: full_name_and_company, -[0x801a, PSETID_Address]: home_address, -[0x801b, PSETID_Address]: business_address, -[0x801c, PSETID_Address]: other_address, -[0x8022, PSETID_Address]: selected_address, -[0x802b, PSETID_Address]: web_page, -[0x802c, PSETID_Address]: yomi_first_name, -[0x802d, PSETID_Address]: yomi_last_name, -[0x802e, PSETID_Address]: yomi_company_name, -[0x8030, PSETID_Address]: last_first_no_space, -[0x8031, PSETID_Address]: last_first_space_only, -[0x8032, PSETID_Address]: company_last_first_no_space, -[0x8033, PSETID_Address]: company_last_first_space_only, -[0x8034, PSETID_Address]: last_first_no_space_company, -[0x8035, PSETID_Address]: last_first_space_only_company, -[0x8036, PSETID_Address]: last_first_and_suffix, -[0x8045, PSETID_Address]: business_address_street, -[0x8046, PSETID_Address]: business_address_city, -[0x8047, PSETID_Address]: business_address_state, -[0x8048, PSETID_Address]: business_address_postal_code, -[0x8049, PSETID_Address]: business_address_country, -[0x804a, PSETID_Address]: business_address_post_office_box, -[0x804f, PSETID_Address]: user_field1, -[0x8050, PSETID_Address]: user_field2, -[0x8051, PSETID_Address]: user_field3, -[0x8052, PSETID_Address]: user_field4, -[0x8062, PSETID_Address]: imaddress, -[0x8082, PSETID_Address]: email_addr_type, -[0x8083, PSETID_Address]: email_email_address, -[0x8084, PSETID_Address]: email_original_display_name, -[0x8085, PSETID_Address]: email_original_entry_id, -[0x8092, PSETID_Address]: email2_addr_type, -[0x8093, PSETID_Address]: email2_email_address, -[0x8094, PSETID_Address]: email2_original_display_name, -[0x8095, PSETID_Address]: email2_original_entry_id, -[0x80a2, PSETID_Address]: email3_addr_type, -[0x80a3, PSETID_Address]: email3_email_address, -[0x80a4, PSETID_Address]: email3_original_display_name, -[0x80a5, PSETID_Address]: email3_original_entry_id, -[0x80d8, PSETID_Address]: internet_free_busy_address, -[0x8101, PSETID_Task]: status, -[0x8102, PSETID_Task]: percent_complete, -[0x8103, PSETID_Task]: team_task, -[0x8104, PSETID_Task]: start_date, -[0x8105, PSETID_Task]: due_date, -[0x8106, PSETID_Task]: duration, -[0x810f, PSETID_Task]: date_completed, -[0x8110, PSETID_Task]: actual_work, -[0x8111, PSETID_Task]: total_work, -[0x811c, PSETID_Task]: complete, -[0x811f, PSETID_Task]: owner, -[0x8126, PSETID_Task]: is_recurring, -[0x8205, PSETID_Appointment]: busy_status, -[0x8208, PSETID_Appointment]: location, -[0x820d, PSETID_Appointment]: start_date, -[0x820e, PSETID_Appointment]: end_date, -[0x8213, PSETID_Appointment]: duration, -[0x8214, PSETID_Appointment]: colors, -[0x8216, PSETID_Appointment]: recurrence_state, -[0x8218, PSETID_Appointment]: response_status, -[0x8222, PSETID_Appointment]: reply_time, -[0x8223, PSETID_Appointment]: is_recurring, -[0x822e, PSETID_Appointment]: organizer, -[0x8231, PSETID_Appointment]: recurrence_type, -[0x8232, PSETID_Appointment]: recurrence_pattern, -# also had CdoPR_FLAG_DUE_BY, when applied to messages. i don't currently -# use message class specific names -[0x8502, PSETID_Common]: reminder_time, -[0x8503, PSETID_Common]: reminder_set, -[0x8516, PSETID_Common]: common_start, -[0x8517, PSETID_Common]: common_end, -[0x851c, PSETID_Common]: reminder_override, -[0x851e, PSETID_Common]: reminder_sound, -[0x851f, PSETID_Common]: reminder_file, -# this one only listed as CdoPR_FLAG_TEXT. maybe should be -# reminder_text -[0x8530, PSETID_Common]: flag_text, -[0x8534, PSETID_Common]: mileage, -[0x8535, PSETID_Common]: billing_information, -[0x8539, PSETID_Common]: companies, -[0x853a, PSETID_Common]: contact_names, -# had CdoPR_FLAG_DUE_BY_NEXT for this one also -[0x8560, PSETID_Common]: reminder_next_time, -[0x8700, PSETID_Log]: entry, -[0x8704, PSETID_Log]: start_date, -[0x8705, PSETID_Log]: start_time, -[0x8706, PSETID_Log]: start, -[0x8707, PSETID_Log]: duration, -[0x8708, PSETID_Log]: end, -[0x870e, PSETID_Log]: doc_printed, -[0x870f, PSETID_Log]: doc_saved, -[0x8710, PSETID_Log]: doc_routed, -[0x8711, PSETID_Log]: doc_posted, -[0x8712, PSETID_Log]: entry_type, -[0x8b00, PSETID_Note]: color, -[0x8b02, PSETID_Note]: width, -[0x8b03, PSETID_Note]: height, -["Keywords", PS_PUBLIC_STRINGS]: categories -} diff --git a/vendor/ruby-msg/data/types.yaml b/vendor/ruby-msg/data/types.yaml deleted file mode 100644 index b2c9024b8..000000000 --- a/vendor/ruby-msg/data/types.yaml +++ /dev/null @@ -1,15 +0,0 @@ ---- -# grep ' PT_' mapitags.yaml | sort -u > types.yaml -- PT_BINARY -- PT_BOOLEAN -- PT_CLSID -- PT_I8 -- PT_LONG -- PT_MV_BINARY -- PT_MV_LONG -- PT_MV_TSTRING -- PT_OBJECT -- PT_SHORT -- PT_STRING8 -- PT_SYSTIME -- PT_TSTRING diff --git a/vendor/ruby-msg/lib/mapi.rb b/vendor/ruby-msg/lib/mapi.rb deleted file mode 100644 index b9d3413f7..000000000 --- a/vendor/ruby-msg/lib/mapi.rb +++ /dev/null @@ -1,109 +0,0 @@ -require 'mapi/types' -require 'mapi/property_set' - -module Mapi - VERSION = '1.4.0' - - # - # 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 - diff --git a/vendor/ruby-msg/lib/mapi/convert.rb b/vendor/ruby-msg/lib/mapi/convert.rb deleted file mode 100644 index 4c7a0d298..000000000 --- a/vendor/ruby-msg/lib/mapi/convert.rb +++ /dev/null @@ -1,61 +0,0 @@ -# we have two different "backends" for note conversion. we're sticking with -# the current (home grown) mime one until the tmail version is suitably -# polished. -require 'mapi/convert/note-mime' -require 'mapi/convert/contact' - -module Mapi - class Message - CONVERSION_MAP = { - 'text/x-vcard' => [:to_vcard, 'vcf'], - 'message/rfc822' => [:to_mime, 'eml'], - 'text/plain' => [:to_post, 'txt'] - # ... - } - - # get the mime type of the message. - def mime_type - case props.message_class #.downcase <- have a feeling i saw other cased versions - when 'IPM.Contact' - # apparently "text/directory; profile=vcard" is what you're supposed to use - 'text/x-vcard' - when 'IPM.Note' - 'message/rfc822' - when 'IPM.Post' - 'text/plain' - when 'IPM.StickyNote' - 'text/plain' # hmmm.... - else - Mapi::Log.warn 'unknown message_class - %p' % props.message_class - nil - end - end - - def convert - type = mime_type - unless pair = CONVERSION_MAP[type] - raise 'unable to convert message with mime type - %p' % type - end - send pair.first - end - - # should probably be moved to mapi/convert/post - class Post - # not really sure what the pertinent properties are. we just do nothing for now... - def initialize message - @message = message - end - - def to_s - # should maybe handle other types, like html body. need a better format for post - # probably anyway, cause a lot of meta data is getting chucked. - @message.props.body - end - end - - def to_post - Post.new self - end - end -end - diff --git a/vendor/ruby-msg/lib/mapi/convert/contact.rb b/vendor/ruby-msg/lib/mapi/convert/contact.rb deleted file mode 100644 index 838ae6498..000000000 --- a/vendor/ruby-msg/lib/mapi/convert/contact.rb +++ /dev/null @@ -1,142 +0,0 @@ -require 'rubygems' -require 'vpim/vcard' - -# patch Vpim. TODO - fix upstream, or verify old behaviour was ok -def Vpim.encode_text v - # think the regexp was wrong - v.to_str.gsub(/(.)/m) do - case $1 - when "\n" - "\\n" - when "\\", ",", ";" - "\\#{$1}" - else - $1 - end - end -end - -module Mapi - class Message - class VcardConverter - include Vpim - - # a very incomplete mapping, but its a start... - # can't find where to set a lot of stuff, like zipcode, jobtitle etc - VCARD_MAP = { - # these are all standard mapi properties - :name => [ - { - :given => :given_name, - :family => :surname, - :fullname => :subject - } - ], - # outlook seems to eschew the mapi properties this time, - # like postal_address, street_address, home_address_city - # so we use the named properties - :addr => [ - { - :location => 'work', - :street => :business_address_street, - :locality => proc do |props| - [props.business_address_city, props.business_address_state].compact * ', ' - end - } - ], - - # right type? maybe date - :birthday => :birthday, - :nickname => :nickname - - # photo available? - # FIXME finish, emails, telephones etc - } - - attr_reader :msg - def initialize msg - @msg = msg - end - - def field name, *args - DirectoryInfo::Field.create name, Vpim.encode_text_list(args) - end - - def get_property key - if String === key - return key - elsif key.respond_to? :call - value = key.call msg.props - else - value = msg.props[key] - end - if String === value and value.empty? - nil - else - value - end - end - - def get_properties hash - constants = {} - others = {} - hash.each do |to, from| - if String === from - constants[to] = from - else - value = get_property from - others[to] = value if value - end - end - return nil if others.empty? - others.merge constants - end - - def convert - Vpim::Vcard::Maker.make2 do |m| - # handle name - [:name, :addr].each do |type| - VCARD_MAP[type].each do |hash| - next unless props = get_properties(hash) - m.send "add_#{type}" do |n| - props.each { |key, value| n.send "#{key}=", value } - end - end - end - - (VCARD_MAP.keys - [:name, :addr]).each do |key| - value = get_property VCARD_MAP[key] - m.send "#{key}=", value if value - end - - # the rest of the stuff is custom - - url = get_property(:webpage) || get_property(:business_home_page) - m.add_field field('URL', url) if url - m.add_field field('X-EVOLUTION-FILE-AS', get_property(:file_under)) if get_property(:file_under) - - addr = get_property(:email_email_address) || get_property(:email_original_display_name) - if addr - m.add_email addr do |e| - e.format ='x400' unless msg.props.email_addr_type == 'SMTP' - end - end - - if org = get_property(:company_name) - m.add_field field('ORG', get_property(:company_name)) - end - - # TODO: imaddress - end - end - end - - def to_vcard - #p props.raw.reject { |key, value| key.guid.inspect !~ /00062004-0000-0000-c000-000000000046/ }. - # map { |key, value| [key.to_sym, value] }.reject { |a, b| b.respond_to? :read } - #y props.to_h.reject { |a, b| b.respond_to? :read } - VcardConverter.new(self).convert - end - end -end - diff --git a/vendor/ruby-msg/lib/mapi/convert/note-mime.rb b/vendor/ruby-msg/lib/mapi/convert/note-mime.rb deleted file mode 100644 index deb035f2c..000000000 --- a/vendor/ruby-msg/lib/mapi/convert/note-mime.rb +++ /dev/null @@ -1,274 +0,0 @@ -require 'base64' -require 'mime' -require 'time' - -# there is still some Msg specific stuff in here. - -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 = SimpleMime.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(', ')] if recips and !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_mime - # 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? - mime = SimpleMime.new "Content-Type: multipart/alternative\r\n\r\n" - # 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... - mime.parts << SimpleMime.new("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 - mime.parts << SimpleMime.new("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 << SimpleMime.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 - mime - else - # check no header case. content type? etc?. not sure if my SimpleMime class will accept - Log.debug "taking that other path" - # body can be nil, hence the to_s - SimpleMime.new "Content-Type: text/plain\r\n\r\n" + props.body.to_s - end - end - - def to_mime - # 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 - mime = body = body_to_mime - - # 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? - mime = SimpleMime.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. - mime.preamble.replace "This is a multi-part message in MIME format.\r\n" if mime.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 mime.headers.has_key? 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 - mime.headers[key] += vals - end - # just a stupid hack to make the content-type header last, when using OrderedHash - mime.headers['Content-Type'] = mime.headers.delete 'Content-Type' - - mime - end - end - - class Attachment - def to_mime - # TODO: smarter mime typing. - mimetype = props.attach_mime_tag || 'application/octet-stream' - mime = SimpleMime.new "Content-Type: #{mimetype}\r\n\r\n" - mime.headers['Content-Disposition'] = [%{attachment; filename="#{filename}"}] - mime.headers['Content-Transfer-Encoding'] = ['base64'] - mime.headers['Content-Location'] = [props.attach_content_location] if props.attach_content_location - mime.headers['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 - 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 - # 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 - # FIXME: shouldn't be required - data.read.to_s rescue '' - end - mime.body.replace @embedded_msg ? data_str : Base64.encode64(data_str).gsub(/\n/, "\r\n") - mime - 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 - 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 - diff --git a/vendor/ruby-msg/lib/mapi/msg.rb b/vendor/ruby-msg/lib/mapi/msg.rb deleted file mode 100644 index fc30a9170..000000000 --- a/vendor/ruby-msg/lib/mapi/msg.rb +++ /dev/null @@ -1,440 +0,0 @@ -require 'rubygems' -require 'ole/storage' -require 'mapi' -require 'mapi/rtf' - -module Mapi - # - # = Introduction - # - # Primary class interface to the vagaries of .msg files. - # - # The core of the work is done by the <tt>Msg::PropertyStore</tt> class. - # - class Msg < Message - # - # = Introduction - # - # A big compononent of +Msg+ files is the property store, which holds - # all the key/value pairs of properties. The message itself, and all - # its <tt>Attachment</tt>s and <tt>Recipient</tt>s have an instance of - # this class. - # - # = Storage model - # - # Property keys (tags?) can be either simple hex numbers, in the - # range 0x0000 - 0xffff, or they can be named properties. In fact, - # properties in the range 0x0000 to 0x7fff are supposed to be the non- - # named properties, and can be considered to be in the +PS_MAPI+ - # namespace. (correct?) - # - # Named properties are serialized in the 0x8000 to 0xffff range, - # and are referenced as a guid and long/string pair. - # - # There are key ranges, which can be used to imply things generally - # about keys. - # - # Further, we can give symbolic names to most keys, coming from - # constants in various places. Eg: - # - # 0x0037 => subject - # {00062002-0000-0000-C000-000000000046}/0x8218 => response_status - # # displayed as categories in outlook - # {00020329-0000-0000-C000-000000000046}/"Keywords" => categories - # - # Futher, there are completely different names, coming from other - # object models that get mapped to these things (CDO's model, - # Outlook's model etc). Eg "urn:schemas:httpmail:subject" - # I think these can be ignored though, as they aren't defined clearly - # in terms of mapi properties, and i'm really just trying to make - # a mapi property store. (It should also be relatively easy to - # support them later.) - # - # = Usage - # - # The api is driven by a desire to have the simple stuff "just work", ie - # - # properties.subject - # properties.display_name - # - # There also needs to be a way to look up properties more specifically: - # - # properties[0x0037] # => gets the subject - # properties[0x0037, PS_MAPI] # => still gets the subject - # properties['Keywords', PS_PUBLIC_STRINGS] # => gets outlook's categories array - # - # The abbreviated versions work by "resolving" the symbols to full keys: - # - # # the guid here is just PS_PUBLIC_STRINGS - # properties.resolve :keywords # => #<Key {00020329-0000-0000-c000-000000000046}/"Keywords"> - # # the result here is actually also a key - # k = properties.resolve :subject # => 0x0037 - # # it has a guid - # k.guid == Msg::Properties::PS_MAPI # => true - # - # = Parsing - # - # There are three objects that need to be parsed to load a +Msg+ property store: - # - # 1. The +nameid+ directory (<tt>Properties.parse_nameid</tt>) - # 2. The many +substg+ objects, whose names should match <tt>Properties::SUBSTG_RX</tt> - # (<tt>Properties#parse_substg</tt>) - # 3. The +properties+ file (<tt>Properties#parse_properties</tt>) - # - # Understanding of the formats is by no means perfect. - # - # = TODO - # - # * While the key objects are sufficient, the value objects are just plain - # ruby types. It currently isn't possible to write to the values, or to know - # which encoding the value had. - # * Update this doc. - # * Perhaps change from eager loading, to be load-on-demand. - # - class PropertyStore - include PropertySet::Constants - Key = PropertySet::Key - - # note that binary and default both use obj.open. not the block form. this means we should - # #close it later, which we don't. as we're only reading though, it shouldn't matter right? - # not really good though FIXME - # change these to use mapi symbolic const names - ENCODINGS = { - 0x000d => proc { |obj| obj }, # seems to be used when its going to be a directory instead of a file. eg nested ole. 3701 usually. in which case we shouldn't get here right? - 0x001f => proc { |obj| Ole::Types::FROM_UTF16.iconv obj.read }, # unicode - # ascii - # FIXME hack did a[0..-2] before, seems right sometimes, but for some others it chopped the text. chomp - 0x001e => proc { |obj| obj.read.chomp 0.chr }, - 0x0102 => proc { |obj| obj.open }, # binary? - :default => proc { |obj| obj.open } - } - - SUBSTG_RX = /^__substg1\.0_([0-9A-F]{4})([0-9A-F]{4})(?:-([0-9A-F]{8}))?$/ - PROPERTIES_RX = /^__properties_version1\.0$/ - NAMEID_RX = /^__nameid_version1\.0$/ - VALID_RX = /#{SUBSTG_RX}|#{PROPERTIES_RX}|#{NAMEID_RX}/ - - attr_reader :nameid - - def initialize - @nameid = nil - # not exactly a cache currently - @cache = {} - end - - #-- - # The parsing methods - #++ - - def self.load obj - prop = new - prop.load obj - prop - end - - # Parse properties from the +Dirent+ obj - def load obj - # we need to do the nameid first, as it provides the map for later user defined properties - if nameid_obj = obj.children.find { |child| child.name =~ NAMEID_RX } - @nameid = PropertyStore.parse_nameid nameid_obj - # hack to make it available to all msg files from the same ole storage object - # FIXME - come up with a neater way - class << obj.ole - attr_accessor :msg_nameid - end - obj.ole.msg_nameid = @nameid - elsif obj.ole - @nameid = obj.ole.msg_nameid rescue nil - end - # now parse the actual properties. i think dirs that match the substg should be decoded - # as properties to. 0x000d is just another encoding, the dir encoding. it should match - # whether the object is file / dir. currently only example is embedded msgs anyway - obj.children.each do |child| - next unless child.file? - case child.name - when PROPERTIES_RX - parse_properties child - when SUBSTG_RX - parse_substg(*($~[1..-1].map { |num| num.hex rescue nil } + [child])) - end - end - end - - # Read nameid from the +Dirent+ obj, which is used for mapping of named properties keys to - # proxy keys in the 0x8000 - 0xffff range. - # Returns a hash of integer -> Key. - def self.parse_nameid obj - remaining = obj.children.dup - guids_obj, props_obj, names_obj = - %w[__substg1.0_00020102 __substg1.0_00030102 __substg1.0_00040102].map do |name| - remaining.delete obj/name - end - - # parse guids - # this is the guids for named properities (other than builtin ones) - # i think PS_PUBLIC_STRINGS, and PS_MAPI are builtin. - guids = [PS_PUBLIC_STRINGS] + guids_obj.read.scan(/.{16}/mn).map do |str| - Ole::Types.load_guid str - end - - # parse names. - # the string ids for named properties - # they are no longer parsed, as they're referred to by offset not - # index. they are simply sequentially packed, as a long, giving - # the string length, then padding to 4 byte multiple, and repeat. - names_data = names_obj.read - - # parse actual props. - # not sure about any of this stuff really. - # should flip a few bits in the real msg, to get a better understanding of how this works. - props = props_obj.read.scan(/.{8}/mn).map do |str| - flags, offset = str[4..-1].unpack 'v2' - # the property will be serialised as this pseudo property, mapping it to this named property - pseudo_prop = 0x8000 + offset - named = flags & 1 == 1 - prop = if named - str_off = *str.unpack('V') - len = *names_data[str_off, 4].unpack('V') - Ole::Types::FROM_UTF16.iconv names_data[str_off + 4, len] - else - a, b = str.unpack('v2') - Log.debug "b not 0" if b != 0 - a - end - # a bit sus - guid_off = flags >> 1 - # missing a few builtin PS_* - Log.debug "guid off < 2 (#{guid_off})" if guid_off < 2 - guid = guids[guid_off - 2] - [pseudo_prop, Key.new(prop, guid)] - end - - #Log.warn "* ignoring #{remaining.length} objects in nameid" unless remaining.empty? - # this leaves a bunch of other unknown chunks of data with completely unknown meaning. - # pp [:unknown, child.name, child.data.unpack('H*')[0].scan(/.{16}/m)] - Hash[*props.flatten] - end - - # Parse an +Dirent+, as per <tt>msgconvert.pl</tt>. This is how larger properties, such - # as strings, binary blobs, and other ole sub-directories (eg nested Msg) are stored. - def parse_substg key, encoding, offset, obj - if (encoding & 0x1000) != 0 - if !offset - # there is typically one with no offset first, whose data is a series of numbers - # equal to the lengths of all the sub parts. gives an implied array size i suppose. - # maybe you can initialize the array at this time. the sizes are the same as all the - # ole object sizes anyway, its to pre-allocate i suppose. - #p obj.data.unpack('V*') - # ignore this one - return - else - # remove multivalue flag for individual pieces - encoding &= ~0x1000 - end - else - Log.warn "offset specified for non-multivalue encoding #{obj.name}" if offset - offset = nil - end - # offset is for multivalue encodings. - unless encoder = ENCODINGS[encoding] - Log.warn "unknown encoding #{encoding}" - #encoder = proc { |obj| obj.io } #.read }. maybe not a good idea - encoder = ENCODINGS[:default] - end - add_property key, encoder[obj], offset - end - - # For parsing the +properties+ file. Smaller properties are serialized in one chunk, - # such as longs, bools, times etc. The parsing has problems. - def parse_properties obj - data = obj.read - # don't really understand this that well... - pad = data.length % 16 - unless (pad == 0 || pad == 8) and data[0...pad] == "\000" * pad - Log.warn "padding was not as expected #{pad} (#{data.length}) -> #{data[0...pad].inspect}" - end - data[pad..-1].scan(/.{16}/mn).each do |data| - property, encoding = ('%08x' % data.unpack('V')).scan /.{4}/ - key = property.hex - # doesn't make any sense to me. probably because its a serialization of some internal - # outlook structure... - next if property == '0000' - case encoding - when '0102', '001e', '001f', '101e', '101f', '000d' - # ignore on purpose. not sure what its for - # multivalue versions ignored also - when '0003' # long - # don't know what all the other data is for - add_property key, *data[8, 4].unpack('V') - when '000b' # boolean - # again, heaps more data than needed. and its not always 0 or 1. - # they are in fact quite big numbers. this is wrong. -# p [property, data[4..-1].unpack('H*')[0]] - add_property key, data[8, 4].unpack('V')[0] != 0 - when '0040' # systime - # seems to work: - add_property key, Ole::Types.load_time(data[8..-1]) - else - #Log.warn "ignoring data in __properties section, encoding: #{encoding}" - #Log << data.unpack('H*').inspect + "\n" - end - end - end - - def add_property key, value, pos=nil - # map keys in the named property range through nameid - if Integer === key and key >= 0x8000 - if !@nameid - Log.warn "no nameid section yet named properties used" - key = Key.new key - elsif real_key = @nameid[key] - key = real_key - else - # i think i hit these when i have a named property, in the PS_MAPI - # guid - Log.warn "property in named range not in nameid #{key.inspect}" - key = Key.new key - end - else - key = Key.new key - end - if pos - @cache[key] ||= [] - Log.warn "duplicate property" unless Array === @cache[key] - # ^ this is actually a trickier problem. the issue is more that they must all be of - # the same type. - @cache[key][pos] = value - else - # take the last. - Log.warn "duplicate property #{key.inspect}" if @cache[key] - @cache[key] = value - end - end - - # delegate to cache - def method_missing name, *args, &block - @cache.send name, *args, &block - end - end - - # these 2 will actually be of the form - # 1\.0_#([0-9A-Z]{8}), where $1 is the 0 based index number in hex - # should i parse that and use it as an index, or just return in - # file order? probably should use it later... - ATTACH_RX = /^__attach_version1\.0_.*/ - RECIP_RX = /^__recip_version1\.0_.*/ - VALID_RX = /#{PropertyStore::VALID_RX}|#{ATTACH_RX}|#{RECIP_RX}/ - - attr_reader :root - attr_accessor :close_parent - - # Alternate constructor, to create an +Msg+ directly from +arg+ and +mode+, passed - # directly to Ole::Storage (ie either filename or seekable IO object). - def self.open arg, mode=nil - msg = new Ole::Storage.open(arg, mode).root - # we will close the ole when we are #closed - msg.close_parent = true - if block_given? - begin yield msg - ensure; msg.close - end - else msg - end - end - - # Create an Msg from +root+, an <tt>Ole::Storage::Dirent</tt> object - def initialize root - @root = root - @close_parent = false - super PropertySet.new(PropertyStore.load(@root)) - Msg.warn_unknown @root - end - - def self.warn_unknown obj - # bit of validation. not important if there is extra stuff, though would be - # interested to know what it is. doesn't check dir/file stuff. - unknown = obj.children.reject { |child| child.name =~ VALID_RX } - Log.warn "skipped #{unknown.length} unknown msg object(s)" unless unknown.empty? - end - - def close - @root.ole.close if @close_parent - end - - def attachments - @attachments ||= @root.children. - select { |child| child.dir? and child.name =~ ATTACH_RX }. - map { |child| Attachment.new child }. - select { |attach| attach.valid? } - end - - def recipients - @recipients ||= @root.children. - select { |child| child.dir? and child.name =~ RECIP_RX }. - map { |child| Recipient.new child } - end - - class Attachment < Mapi::Attachment - attr_reader :obj, :properties - alias props :properties - - def initialize obj - @obj = obj - @embedded_ole = nil - @embedded_msg = nil - - super PropertySet.new(PropertyStore.load(@obj)) - Msg.warn_unknown @obj - - @obj.children.each do |child| - # temp hack. PropertyStore doesn't do directory properties atm - FIXME - if child.dir? and child.name =~ PropertyStore::SUBSTG_RX and - $1 == '3701' and $2.downcase == '000d' - @embedded_ole = child - class << @embedded_ole - def compobj - return nil unless compobj = self["\001CompObj"] - compobj.read[/^.{32}([^\x00]+)/m, 1] - end - - def embedded_type - temp = compobj and return temp - # try to guess more - if children.select { |child| child.name =~ /__(substg|properties|recip|attach|nameid)/ }.length > 2 - return 'Microsoft Office Outlook Message' - end - nil - end - end - if @embedded_ole.embedded_type == 'Microsoft Office Outlook Message' - @embedded_msg = Msg.new @embedded_ole - end - end - end - end - - def valid? - # something i started to notice when handling embedded ole object attachments is - # the particularly strange case where there are empty attachments - not props.raw.keys.empty? - end - end - - # - # +Recipient+ serves as a container for the +recip+ directories in the .msg. - # It has things like office_location, business_telephone_number, but I don't - # think enough to make a vCard out of? - # - class Recipient < Mapi::Recipient - attr_reader :obj, :properties - alias props :properties - - def initialize obj - @obj = obj - super PropertySet.new(PropertyStore.load(@obj)) - Msg.warn_unknown @obj - end - end - end -end - diff --git a/vendor/ruby-msg/lib/mapi/property_set.rb b/vendor/ruby-msg/lib/mapi/property_set.rb deleted file mode 100644 index 199bca525..000000000 --- a/vendor/ruby-msg/lib/mapi/property_set.rb +++ /dev/null @@ -1,269 +0,0 @@ -require 'yaml' -require 'mapi/types' -require 'mapi/rtf' -require 'rtf' - -module Mapi - # - # The Mapi::PropertySet class is used to wrap the lower level Msg or Pst property stores, - # and provide a consistent and more friendly interface. It allows you to just say: - # - # properties.subject - # - # instead of: - # - # properites.raw[0x0037, PS_MAPI] - # - # The underlying store can be just a hash, or lazily loading directly from the file. A good - # compromise is to cache all the available keys, and just return the values on demand, rather - # than load up many possibly unwanted values. - # - class PropertySet - # the property set guid constants - # these guids are all defined with the macro DEFINE_OLEGUID in mapiguid.h. - # see http://doc.ddart.net/msdn/header/include/mapiguid.h.html - oleguid = proc do |prefix| - Ole::Types::Clsid.parse "{#{prefix}-0000-0000-c000-000000000046}" - end - - NAMES = { - oleguid['00020328'] => 'PS_MAPI', - oleguid['00020329'] => 'PS_PUBLIC_STRINGS', - oleguid['00020380'] => 'PS_ROUTING_EMAIL_ADDRESSES', - oleguid['00020381'] => 'PS_ROUTING_ADDRTYPE', - oleguid['00020382'] => 'PS_ROUTING_DISPLAY_NAME', - oleguid['00020383'] => 'PS_ROUTING_ENTRYID', - oleguid['00020384'] => 'PS_ROUTING_SEARCH_KEY', - # string properties in this namespace automatically get added to the internet headers - oleguid['00020386'] => 'PS_INTERNET_HEADERS', - # theres are bunch of outlook ones i think - # http://blogs.msdn.com/stephen_griffin/archive/2006/05/10/outlook-2007-beta-documentation-notification-based-indexing-support.aspx - # IPM.Appointment - oleguid['00062002'] => 'PSETID_Appointment', - # IPM.Task - oleguid['00062003'] => 'PSETID_Task', - # used for IPM.Contact - oleguid['00062004'] => 'PSETID_Address', - oleguid['00062008'] => 'PSETID_Common', - # didn't find a source for this name. it is for IPM.StickyNote - oleguid['0006200e'] => 'PSETID_Note', - # for IPM.Activity. also called the journal? - oleguid['0006200a'] => 'PSETID_Log', - } - - module Constants - NAMES.each { |guid, name| const_set name, guid } - end - - include Constants - - # +Properties+ are accessed by <tt>Key</tt>s, which are coerced to this class. - # Includes a bunch of methods (hash, ==, eql?) to allow it to work as a key in - # a +Hash+. - # - # Also contains the code that maps keys to symbolic names. - class Key - include Constants - - attr_reader :code, :guid - def initialize code, guid=PS_MAPI - @code, @guid = code, guid - end - - def to_sym - # hmmm, for some stuff, like, eg, the message class specific range, sym-ification - # of the key depends on knowing our message class. i don't want to store anything else - # here though, so if that kind of thing is needed, it can be passed to this function. - # worry about that when some examples arise. - case code - when Integer - if guid == PS_MAPI # and < 0x8000 ? - # the hash should be updated now that i've changed the process - TAGS['%04x' % code].first[/_(.*)/, 1].downcase.to_sym rescue code - else - # handle other guids here, like mapping names to outlook properties, based on the - # outlook object model. - NAMED_MAP[self].to_sym rescue code - end - when String - # return something like - # note that named properties don't go through the map at the moment. so #categories - # doesn't work yet - code.downcase.to_sym - end - end - - def to_s - to_sym.to_s - end - - # FIXME implement these - def transmittable? - # etc, can go here too - end - - # this stuff is to allow it to be a useful key - def hash - [code, guid].hash - end - - def == other - hash == other.hash - end - - alias eql? :== - - def inspect - # maybe the way to do this, would be to be able to register guids - # in a global lookup, which are used by Clsid#inspect itself, to - # provide symbolic names... - guid_str = NAMES[guid] || "{#{guid.format}}" rescue "nil" - if Integer === code - hex = '0x%04x' % code - if guid == PS_MAPI - # just display as plain hex number - hex - else - "#<Key #{guid_str}/#{hex}>" - end - else - # display full guid and code - "#<Key #{guid_str}/#{code.inspect}>" - end - end - end - - # duplicated here for now - SUPPORT_DIR = File.dirname(__FILE__) + '/../..' - - # data files that provide for the code to symbolic name mapping - # guids in named_map are really constant references to the above - TAGS = YAML.load_file "#{SUPPORT_DIR}/data/mapitags.yaml" - NAMED_MAP = YAML.load_file("#{SUPPORT_DIR}/data/named_map.yaml").inject({}) do |hash, (key, value)| - hash.update Key.new(key[0], const_get(key[1])) => value - end - - attr_reader :raw - - # +raw+ should be an hash-like object that maps <tt>Key</tt>s to values. Should respond_to? - # [], keys, values, each, and optionally []=, and delete. - def initialize raw - @raw = raw - end - - # resolve +arg+ (could be key, code, string, or symbol), and possible +guid+ to a key. - # returns nil on failure - def resolve arg, guid=nil - if guid; Key.new arg, guid - else - case arg - when Key; arg - when Integer; Key.new arg - else sym_to_key[arg.to_sym] - end - end - end - - # this is the function that creates a symbol to key mapping. currently this works by making a - # pass through the raw properties, but conceivably you could map symbols to keys using the - # mapitags directly. problem with that would be that named properties wouldn't map automatically, - # but maybe thats not too important. - def sym_to_key - return @sym_to_key if @sym_to_key - @sym_to_key = {} - raw.keys.each do |key| - sym = key.to_sym - unless Symbol === sym - Log.debug "couldn't find symbolic name for key #{key.inspect}" - next - end - if @sym_to_key[sym] - Log.warn "duplicate key #{key.inspect}" - # we give preference to PS_MAPI keys - @sym_to_key[sym] = key if key.guid == PS_MAPI - else - # just assign - @sym_to_key[sym] = key - end - end - @sym_to_key - end - - def keys - sym_to_key.keys - end - - def values - sym_to_key.values.map { |key| raw[key] } - end - - def [] arg, guid=nil - raw[resolve(arg, guid)] - end - - def []= arg, *args - args.unshift nil if args.length == 1 - guid, value = args - # FIXME this won't really work properly. it would need to go - # to TAGS to resolve, as it often won't be there already... - raw[resolve(arg, guid)] = value - end - - def method_missing name, *args - if name.to_s !~ /\=$/ and args.empty? - self[name] - elsif name.to_s =~ /(.*)\=$/ and args.length == 1 - self[$1] = args[0] - else - super - end - end - - def to_h - sym_to_key.inject({}) { |hash, (sym, key)| hash.update sym => raw[key] } - end - - def inspect - "#<#{self.class} " + to_h.sort_by { |k, v| k.to_s }.map do |k, v| - v = v.inspect - "#{k}=#{v.length > 32 ? v[0..29] + '..."' : v}" - end.join(' ') + '>' - end - - # ----- - - # temporary pseudo tags - - # for providing rtf to plain text conversion. later, html to text too. - def body - return @body if defined?(@body) - @body = (self[:body] rescue nil) - # last resort - if !@body or @body.strip.empty? - Log.warn 'creating text body from rtf' - @body = (::RTF::Converter.rtf2text body_rtf rescue nil) - end - @body - end - - # for providing rtf decompression - def body_rtf - return @body_rtf if defined?(@body_rtf) - @body_rtf = (RTF.rtfdecompr rtf_compressed.read rescue nil) - end - - # for providing rtf to html conversion - def body_html - return @body_html if defined?(@body_html) - @body_html = (self[:body_html].read rescue nil) - @body_html = (RTF.rtf2html body_rtf rescue nil) if !@body_html or @body_html.strip.empty? - # last resort - if !@body_html or @body_html.strip.empty? - Log.warn 'creating html body from rtf' - @body_html = (::RTF::Converter.rtf2text body_rtf, :html rescue nil) - end - @body_html - end - end -end - diff --git a/vendor/ruby-msg/lib/mapi/pst.rb b/vendor/ruby-msg/lib/mapi/pst.rb deleted file mode 100644 index 9ac64b097..000000000 --- a/vendor/ruby-msg/lib/mapi/pst.rb +++ /dev/null @@ -1,1806 +0,0 @@ -# -# = Introduction -# -# This file is mostly an attempt to port libpst to ruby, and simplify it in the process. It -# will leverage much of the existing MAPI => MIME conversion developed for Msg files, and as -# such is purely concerned with the file structure details. -# -# = TODO -# -# 1. solve recipient table problem (test4). -# this is done. turns out it was due to id2 clashes. find better solution -# 2. check parse consistency. an initial conversion of a 30M file to pst, shows -# a number of messages conveting badly. compare with libpst too. -# 3. xattribs -# 4. generalise the Mapi stuff better -# 5. refactor index load -# 6. msg serialization? -# - -=begin - -quick plan for cleanup. - -have working tests for 97 and 03 file formats, so safe. - -want to fix up: - -64 bit unpacks scattered around. its ugly. not sure how best to handle it, but am slightly tempted -to override String#unpack to support a 64 bit little endian unpack (like L vs N/V, for Q). one way or -another need to fix it. Could really slow everything else down if its parsing the unpack strings twice, -once in ruby, for every single unpack i do :/ - -the index loading process, and the lack of shared code between normal vs 64 bit variants, and Index vs Desc. -should be able to reduce code by factor of 4. also think I should move load code into the class too. then -maybe have something like: - -class Header - def index_class - version_2003 ? Index64 : Index - end -end - -def load_idx - header.index_class.load_index -end - -OR - -def initialize - @header = ... - extend @header.index_class::Load - load_idx -end - -need to think about the role of the mapi code, and Pst::Item etc, but that layer can come later. - -=end - -require 'mapi' -require 'enumerator' -require 'ostruct' -require 'ole/ranges_io' - -module Mapi -class Pst - class FormatError < StandardError - end - - # unfortunately there is no Q analogue which is little endian only. - # this translates T as an unsigned quad word, little endian byte order, to - # not pollute the rest of the code. - # - # didn't want to override String#unpack, cause its too hacky, and incomplete. - def self.unpack str, unpack_spec - return str.unpack(unpack_spec) unless unpack_spec['T'] - @unpack_cache ||= {} - t_offsets, new_spec = @unpack_cache[unpack_spec] - unless t_offsets - t_offsets = [] - offset = 0 - new_spec = '' - unpack_spec.scan(/([^\d])_?(\*|\d+)?/o) do - num_elems = $1.downcase == 'a' ? 1 : ($2 || 1).to_i - if $1 == 'T' - num_elems.times { |i| t_offsets << offset + i } - new_spec << "V#{num_elems * 2}" - else - new_spec << $~[0] - end - offset += num_elems - end - @unpack_cache[unpack_spec] = [t_offsets, new_spec] - end - a = str.unpack(new_spec) - t_offsets.each do |offset| - low, high = a[offset, 2] - a[offset, 2] = low && high ? low + (high << 32) : nil - end - a - end - - # - # this is the header and encryption encapsulation code - # ---------------------------------------------------------------------------- - # - - # class which encapsulates the pst header - class Header - SIZE = 512 - MAGIC = 0x2142444e - - # these are the constants defined in libpst.c, that - # are referenced in pst_open() - INDEX_TYPE_OFFSET = 0x0A - FILE_SIZE_POINTER = 0xA8 - FILE_SIZE_POINTER_64 = 0xB8 - SECOND_POINTER = 0xBC - INDEX_POINTER = 0xC4 - SECOND_POINTER_64 = 0xE0 - INDEX_POINTER_64 = 0xF0 - ENC_OFFSET = 0x1CD - - attr_reader :magic, :index_type, :encrypt_type, :size - attr_reader :index1_count, :index1, :index2_count, :index2 - attr_reader :version - def initialize data - @magic = data.unpack('N')[0] - @index_type = data[INDEX_TYPE_OFFSET] - @version = {0x0e => 1997, 0x17 => 2003}[@index_type] - - if version_2003? - # don't know? - # >> data1.unpack('V*').zip(data2.unpack('V*')).enum_with_index.select { |(c, d), i| c != d and not [46, 56, 60].include?(i) }.select { |(a, b), i| b == 0 }.map { |(a, b), i| [a / 256, i] } - # [8, 76], [32768, 84], [128, 89] - # >> data1.unpack('C*').zip(data2.unpack('C*')).enum_with_index.select { |(c, d), i| c != d and not [184..187, 224..227, 240..243].any? { |r| r === i } }.select { |(a, b), i| b == 0 and ((Math.log(a) / Math.log(2)) % 1) < 0.0001 } - # [[[2, 0], 61], [[2, 0], 76], [[2, 0], 195], [[2, 0], 257], [[8, 0], 305], [[128, 0], 338], [[128, 0], 357]] - # i have only 2 psts to base this guess on, so i can't really come up with anything that looks reasonable yet. not sure what the offset is. unfortunately there is so much in the header - # that isn't understood... - @encrypt_type = 1 - - @index2_count, @index2 = data[SECOND_POINTER_64 - 4, 8].unpack('V2') - @index1_count, @index1 = data[INDEX_POINTER_64 - 4, 8].unpack('V2') - - @size = data[FILE_SIZE_POINTER_64, 4].unpack('V')[0] - else - @encrypt_type = data[ENC_OFFSET] - - @index2_count, @index2 = data[SECOND_POINTER - 4, 8].unpack('V2') - @index1_count, @index1 = data[INDEX_POINTER - 4, 8].unpack('V2') - - @size = data[FILE_SIZE_POINTER, 4].unpack('V')[0] - end - - validate! - end - - def version_2003? - version == 2003 - end - - def encrypted? - encrypt_type != 0 - end - - def validate! - raise FormatError, "bad signature on pst file (#{'0x%x' % magic})" unless magic == MAGIC - raise FormatError, "only index types 0x0e and 0x17 are handled (#{'0x%x' % index_type})" unless [0x0e, 0x17].include?(index_type) - raise FormatError, "only encrytion types 0 and 1 are handled (#{encrypt_type.inspect})" unless [0, 1].include?(encrypt_type) - end - end - - # compressible encryption! :D - # - # simple substitution. see libpst.c - # maybe test switch to using a String#tr! - class CompressibleEncryption - DECRYPT_TABLE = [ - 0x47, 0xf1, 0xb4, 0xe6, 0x0b, 0x6a, 0x72, 0x48, - 0x85, 0x4e, 0x9e, 0xeb, 0xe2, 0xf8, 0x94, 0x53, # 0x0f - 0xe0, 0xbb, 0xa0, 0x02, 0xe8, 0x5a, 0x09, 0xab, - 0xdb, 0xe3, 0xba, 0xc6, 0x7c, 0xc3, 0x10, 0xdd, # 0x1f - 0x39, 0x05, 0x96, 0x30, 0xf5, 0x37, 0x60, 0x82, - 0x8c, 0xc9, 0x13, 0x4a, 0x6b, 0x1d, 0xf3, 0xfb, # 0x2f - 0x8f, 0x26, 0x97, 0xca, 0x91, 0x17, 0x01, 0xc4, - 0x32, 0x2d, 0x6e, 0x31, 0x95, 0xff, 0xd9, 0x23, # 0x3f - 0xd1, 0x00, 0x5e, 0x79, 0xdc, 0x44, 0x3b, 0x1a, - 0x28, 0xc5, 0x61, 0x57, 0x20, 0x90, 0x3d, 0x83, # 0x4f - 0xb9, 0x43, 0xbe, 0x67, 0xd2, 0x46, 0x42, 0x76, - 0xc0, 0x6d, 0x5b, 0x7e, 0xb2, 0x0f, 0x16, 0x29, # 0x5f - 0x3c, 0xa9, 0x03, 0x54, 0x0d, 0xda, 0x5d, 0xdf, - 0xf6, 0xb7, 0xc7, 0x62, 0xcd, 0x8d, 0x06, 0xd3, # 0x6f - 0x69, 0x5c, 0x86, 0xd6, 0x14, 0xf7, 0xa5, 0x66, - 0x75, 0xac, 0xb1, 0xe9, 0x45, 0x21, 0x70, 0x0c, # 0x7f - 0x87, 0x9f, 0x74, 0xa4, 0x22, 0x4c, 0x6f, 0xbf, - 0x1f, 0x56, 0xaa, 0x2e, 0xb3, 0x78, 0x33, 0x50, # 0x8f - 0xb0, 0xa3, 0x92, 0xbc, 0xcf, 0x19, 0x1c, 0xa7, - 0x63, 0xcb, 0x1e, 0x4d, 0x3e, 0x4b, 0x1b, 0x9b, # 0x9f - 0x4f, 0xe7, 0xf0, 0xee, 0xad, 0x3a, 0xb5, 0x59, - 0x04, 0xea, 0x40, 0x55, 0x25, 0x51, 0xe5, 0x7a, # 0xaf - 0x89, 0x38, 0x68, 0x52, 0x7b, 0xfc, 0x27, 0xae, - 0xd7, 0xbd, 0xfa, 0x07, 0xf4, 0xcc, 0x8e, 0x5f, # 0xbf - 0xef, 0x35, 0x9c, 0x84, 0x2b, 0x15, 0xd5, 0x77, - 0x34, 0x49, 0xb6, 0x12, 0x0a, 0x7f, 0x71, 0x88, # 0xcf - 0xfd, 0x9d, 0x18, 0x41, 0x7d, 0x93, 0xd8, 0x58, - 0x2c, 0xce, 0xfe, 0x24, 0xaf, 0xde, 0xb8, 0x36, # 0xdf - 0xc8, 0xa1, 0x80, 0xa6, 0x99, 0x98, 0xa8, 0x2f, - 0x0e, 0x81, 0x65, 0x73, 0xe4, 0xc2, 0xa2, 0x8a, # 0xef - 0xd4, 0xe1, 0x11, 0xd0, 0x08, 0x8b, 0x2a, 0xf2, - 0xed, 0x9a, 0x64, 0x3f, 0xc1, 0x6c, 0xf9, 0xec # 0xff - ] - - ENCRYPT_TABLE = [nil] * 256 - DECRYPT_TABLE.each_with_index { |i, j| ENCRYPT_TABLE[i] = j } - - def self.decrypt_alt encrypted - decrypted = '' - encrypted.length.times { |i| decrypted << DECRYPT_TABLE[encrypted[i]] } - decrypted - end - - def self.encrypt_alt decrypted - encrypted = '' - decrypted.length.times { |i| encrypted << ENCRYPT_TABLE[decrypted[i]] } - encrypted - end - - # an alternate implementation that is possibly faster.... - # TODO - bench - DECRYPT_STR, ENCRYPT_STR = [DECRYPT_TABLE, (0...256)].map do |values| - values.map { |i| i.chr }.join.gsub(/([\^\-\\])/, "\\\\\\1") - end - - def self.decrypt encrypted - encrypted.tr ENCRYPT_STR, DECRYPT_STR - end - - def self.encrypt decrypted - decrypted.tr DECRYPT_STR, ENCRYPT_STR - end - end - - class RangesIOEncryptable < RangesIO - def initialize io, mode='r', params={} - mode, params = 'r', mode if Hash === mode - @decrypt = !!params[:decrypt] - super - end - - def encrypted? - @decrypt - end - - def read limit=nil - buf = super - buf = CompressibleEncryption.decrypt(buf) if encrypted? - buf - end - end - - attr_reader :io, :header, :idx, :desc, :special_folder_ids - - # corresponds to - # * pst_open - # * pst_load_index - def initialize io - @io = io - io.pos = 0 - @header = Header.new io.read(Header::SIZE) - - # would prefer this to be in Header#validate, but it doesn't have the io size. - # should perhaps downgrade this to just be a warning... - raise FormatError, "header size field invalid (#{header.size} != #{io.size}}" unless header.size == io.size - - load_idx - load_desc - load_xattrib - - @special_folder_ids = {} - end - - def encrypted? - @header.encrypted? - end - - # until i properly fix logging... - def warn s - Mapi::Log.warn s - end - - # - # this is the index and desc record loading code - # ---------------------------------------------------------------------------- - # - - ToTree = Module.new - - module Index2 - BLOCK_SIZE = 512 - module RecursiveLoad - def load_chain - #... - end - end - - module Base - def read - #... - end - end - - class Version1997 < Struct.new(:a)#...) - SIZE = 12 - - include RecursiveLoad - include Base - end - - class Version2003 < Struct.new(:a)#...) - SIZE = 24 - - include RecursiveLoad - include Base - end - end - - module Desc2 - module Base - def desc - #... - end - end - - class Version1997 < Struct.new(:a)#...) - #include Index::RecursiveLoad - include Base - end - - class Version2003 < Struct.new(:a)#...) - #include Index::RecursiveLoad - include Base - end - end - - # more constants from libpst.c - # these relate to the index block - ITEM_COUNT_OFFSET = 0x1f0 # count byte - LEVEL_INDICATOR_OFFSET = 0x1f3 # node or leaf - BACKLINK_OFFSET = 0x1f8 # backlink u1 value - - # these 3 classes are used to hold various file records - - # pst_index - class Index < Struct.new(:id, :offset, :size, :u1) - UNPACK_STR = 'VVvv' - SIZE = 12 - BLOCK_SIZE = 512 # index blocks was 516 but bogus - COUNT_MAX = 41 # max active items (ITEM_COUNT_OFFSET / Index::SIZE = 41) - - attr_accessor :pst - def initialize data - data = Pst.unpack data, UNPACK_STR if String === data - super(*data) - end - - def type - @type ||= begin - if id & 0x2 == 0 - :data - else - first_byte, second_byte = read.unpack('CC') - if first_byte == 1 - raise second_byte unless second_byte == 1 - :data_chain_header - elsif first_byte == 2 - raise second_byte unless second_byte == 0 - :id2_assoc - else - raise FormatError, 'unknown first byte for block - %p' % first_byte - end - end - end - end - - def data? - (id & 0x2) == 0 - end - - def read decrypt=true - # only data blocks are every encrypted - decrypt = false unless data? - pst.pst_read_block_size offset, size, decrypt - end - - # show all numbers in hex - def inspect - super.gsub(/=(\d+)/) { '=0x%x' % $1.to_i }.sub(/Index /, "Index type=#{type.inspect}, ") - end - end - - # mostly guesses. - ITEM_COUNT_OFFSET_64 = 0x1e8 - LEVEL_INDICATOR_OFFSET_64 = 0x1eb # diff of 3 between these 2 as above... - - # will maybe inherit from Index64, in order to get the same #type function. - class Index64 < Index - UNPACK_STR = 'TTvvV' - SIZE = 24 - BLOCK_SIZE = 512 - COUNT_MAX = 20 # bit of a guess really. 512 / 24 = 21, but doesn't leave enough header room - - # this is the extra item on the end of the UNPACK_STR above - attr_accessor :u2 - - def initialize data - data = Pst.unpack data, UNPACK_STR if String === data - @u2 = data.pop - super data - end - - def inspect - super.sub(/>$/, ', u2=%p>' % u2) - end - - def self.load_chain io, header - load_idx_rec io, header.index1, 0, 0 - end - - # almost identical to load code for Index, just different offsets and unpack strings. - # can probably merge them, or write a generic load_tree function or something. - def self.load_idx_rec io, offset, linku1, start_val - io.seek offset - buf = io.read BLOCK_SIZE - idxs = [] - - item_count = buf[ITEM_COUNT_OFFSET_64] - raise "have too many active items in index (#{item_count})" if item_count > COUNT_MAX - - #idx = Index.new buf[BACKLINK_OFFSET, Index::SIZE] - #raise 'blah 1' unless idx.id == linku1 - - if buf[LEVEL_INDICATOR_OFFSET_64] == 0 - # leaf pointers - # split the data into item_count index objects - buf[0, SIZE * item_count].scan(/.{#{SIZE}}/mo).each_with_index do |data, i| - idx = new data - # first entry - raise 'blah 3' if i == 0 and start_val != 0 and idx.id != start_val - #idx.pst = self - break if idx.id == 0 - idxs << idx - end - else - # node pointers - # split the data into item_count table pointers - buf[0, SIZE * item_count].scan(/.{#{SIZE}}/mo).each_with_index do |data, i| - start, u1, offset = Pst.unpack data, 'T3' - # for the first value, we expect the start to be equal - raise 'blah 3' if i == 0 and start_val != 0 and start != start_val - break if start == 0 - idxs += load_idx_rec io, offset, u1, start - end - end - - idxs - end - end - - # pst_desc - class Desc64 < Struct.new(:desc_id, :idx_id, :idx2_id, :parent_desc_id, :u2) - UNPACK_STR = 'T3VV' - SIZE = 32 - BLOCK_SIZE = 512 # descriptor blocks was 520 but bogus - COUNT_MAX = 15 # guess as per Index64 - - include RecursivelyEnumerable - - attr_accessor :pst - attr_reader :children - def initialize data - super(*Pst.unpack(data, UNPACK_STR)) - @children = [] - end - - def desc - pst.idx_from_id idx_id - end - - def list_index - pst.idx_from_id idx2_id - end - - def self.load_chain io, header - load_desc_rec io, header.index2, 0, 0x21 - end - - def self.load_desc_rec io, offset, linku1, start_val - io.seek offset - buf = io.read BLOCK_SIZE - descs = [] - item_count = buf[ITEM_COUNT_OFFSET_64] - - # not real desc - #desc = Desc.new buf[BACKLINK_OFFSET, 4] - #raise 'blah 1' unless desc.desc_id == linku1 - - if buf[LEVEL_INDICATOR_OFFSET_64] == 0 - # leaf pointers - raise "have too many active items in index (#{item_count})" if item_count > COUNT_MAX - # split the data into item_count desc objects - buf[0, SIZE * item_count].scan(/.{#{SIZE}}/mo).each_with_index do |data, i| - desc = new data - # first entry - raise 'blah 3' if i == 0 and start_val != 0 and desc.desc_id != start_val - break if desc.desc_id == 0 - descs << desc - end - else - # node pointers - raise "have too many active items in index (#{item_count})" if item_count > Index64::COUNT_MAX - # split the data into item_count table pointers - buf[0, Index64::SIZE * item_count].scan(/.{#{Index64::SIZE}}/mo).each_with_index do |data, i| - start, u1, offset = Pst.unpack data, 'T3' - # for the first value, we expect the start to be equal note that ids -1, so even for the - # first we expect it to be equal. thats the 0x21 (dec 33) desc record. this means we assert - # that the first desc record is always 33... - # thats because 0x21 is the pst root itself... - raise 'blah 3' if i == 0 and start_val != -1 and start != start_val - # this shouldn't really happen i'd imagine - break if start == 0 - descs += load_desc_rec io, offset, u1, start - end - end - - descs - end - - def each_child(&block) - @children.each(&block) - end - end - - # _pst_table_ptr_struct - class TablePtr < Struct.new(:start, :u1, :offset) - UNPACK_STR = 'V3' - SIZE = 12 - - def initialize data - data = data.unpack(UNPACK_STR) if String === data - super(*data) - end - end - - # pst_desc - # idx_id is a pointer to an idx record which gets the primary data stream for the Desc record. - # idx2_id gets you an idx record, that when read gives you an ID2 association list, which just maps - # another set of ids to index values - class Desc < Struct.new(:desc_id, :idx_id, :idx2_id, :parent_desc_id) - UNPACK_STR = 'V4' - SIZE = 16 - BLOCK_SIZE = 512 # descriptor blocks was 520 but bogus - COUNT_MAX = 31 # max active desc records (ITEM_COUNT_OFFSET / Desc::SIZE = 31) - - include ToTree - - attr_accessor :pst - attr_reader :children - def initialize data - super(*data.unpack(UNPACK_STR)) - @children = [] - end - - def desc - pst.idx_from_id idx_id - end - - def list_index - pst.idx_from_id idx2_id - end - - # show all numbers in hex - def inspect - super.gsub(/=(\d+)/) { '=0x%x' % $1.to_i } - end - end - - # corresponds to - # * _pst_build_id_ptr - def load_idx - @idx = [] - @idx_offsets = [] - if header.version_2003? - @idx = Index64.load_chain io, header - @idx.each { |idx| idx.pst = self } - else - load_idx_rec header.index1, header.index1_count, 0 - end - - # we'll typically be accessing by id, so create a hash as a lookup cache - @idx_from_id = {} - @idx.each do |idx| - warn "there are duplicate idx records with id #{idx.id}" if @idx_from_id[idx.id] - @idx_from_id[idx.id] = idx - end - end - - # load the flat idx table, which maps ids to file ranges. this is the recursive helper - # - # corresponds to - # * _pst_build_id_ptr - def load_idx_rec offset, linku1, start_val - @idx_offsets << offset - - #_pst_read_block_size(pf, offset, BLOCK_SIZE, &buf, 0, 0) < BLOCK_SIZE) - buf = pst_read_block_size offset, Index::BLOCK_SIZE, false - - item_count = buf[ITEM_COUNT_OFFSET] - raise "have too many active items in index (#{item_count})" if item_count > Index::COUNT_MAX - - idx = Index.new buf[BACKLINK_OFFSET, Index::SIZE] - raise 'blah 1' unless idx.id == linku1 - - if buf[LEVEL_INDICATOR_OFFSET] == 0 - # leaf pointers - # split the data into item_count index objects - buf[0, Index::SIZE * item_count].scan(/.{#{Index::SIZE}}/mo).each_with_index do |data, i| - idx = Index.new data - # first entry - raise 'blah 3' if i == 0 and start_val != 0 and idx.id != start_val - idx.pst = self - # this shouldn't really happen i'd imagine - break if idx.id == 0 - @idx << idx - end - else - # node pointers - # split the data into item_count table pointers - buf[0, TablePtr::SIZE * item_count].scan(/.{#{TablePtr::SIZE}}/mo).each_with_index do |data, i| - table = TablePtr.new data - # for the first value, we expect the start to be equal - raise 'blah 3' if i == 0 and start_val != 0 and table.start != start_val - # this shouldn't really happen i'd imagine - break if table.start == 0 - load_idx_rec table.offset, table.u1, table.start - end - end - end - - # most access to idx objects will use this function - # - # corresponds to - # * _pst_getID - def idx_from_id id - @idx_from_id[id] - end - - # corresponds to - # * _pst_build_desc_ptr - # * record_descriptor - def load_desc - @desc = [] - @desc_offsets = [] - if header.version_2003? - @desc = Desc64.load_chain io, header - @desc.each { |desc| desc.pst = self } - else - load_desc_rec header.index2, header.index2_count, 0x21 - end - - # first create a lookup cache - @desc_from_id = {} - @desc.each do |desc| - desc.pst = self - warn "there are duplicate desc records with id #{desc.desc_id}" if @desc_from_id[desc.desc_id] - @desc_from_id[desc.desc_id] = desc - end - - # now turn the flat list of loaded desc records into a tree - - # well, they have no parent, so they're more like, the toplevel descs. - @orphans = [] - # now assign each node to the parents child array, putting the orphans in the above - @desc.each do |desc| - parent = @desc_from_id[desc.parent_desc_id] - # note, besides this, its possible to create other circular structures. - if parent == desc - # this actually happens usually, for the root_item it appears. - #warn "desc record's parent is itself (#{desc.inspect})" - # maybe add some more checks in here for circular structures - elsif parent - parent.children << desc - next - end - @orphans << desc - end - - # maybe change this to some sort of sane-ness check. orphans are expected -# warn "have #{@orphans.length} orphan desc record(s)." unless @orphans.empty? - end - - # load the flat list of desc records recursively - # - # corresponds to - # * _pst_build_desc_ptr - # * record_descriptor - def load_desc_rec offset, linku1, start_val - @desc_offsets << offset - - buf = pst_read_block_size offset, Desc::BLOCK_SIZE, false - item_count = buf[ITEM_COUNT_OFFSET] - - # not real desc - desc = Desc.new buf[BACKLINK_OFFSET, 4] - raise 'blah 1' unless desc.desc_id == linku1 - - if buf[LEVEL_INDICATOR_OFFSET] == 0 - # leaf pointers - raise "have too many active items in index (#{item_count})" if item_count > Desc::COUNT_MAX - # split the data into item_count desc objects - buf[0, Desc::SIZE * item_count].scan(/.{#{Desc::SIZE}}/mo).each_with_index do |data, i| - desc = Desc.new data - # first entry - raise 'blah 3' if i == 0 and start_val != 0 and desc.desc_id != start_val - # this shouldn't really happen i'd imagine - break if desc.desc_id == 0 - @desc << desc - end - else - # node pointers - raise "have too many active items in index (#{item_count})" if item_count > Index::COUNT_MAX - # split the data into item_count table pointers - buf[0, TablePtr::SIZE * item_count].scan(/.{#{TablePtr::SIZE}}/mo).each_with_index do |data, i| - table = TablePtr.new data - # for the first value, we expect the start to be equal note that ids -1, so even for the - # first we expect it to be equal. thats the 0x21 (dec 33) desc record. this means we assert - # that the first desc record is always 33... - raise 'blah 3' if i == 0 and start_val != -1 and table.start != start_val - # this shouldn't really happen i'd imagine - break if table.start == 0 - load_desc_rec table.offset, table.u1, table.start - end - end - end - - # as for idx - # - # corresponds to: - # * _pst_getDptr - def desc_from_id id - @desc_from_id[id] - end - - # corresponds to - # * pst_load_extended_attributes - def load_xattrib - unless desc = desc_from_id(0x61) - warn "no extended attributes desc record found" - return - end - unless desc.desc - warn "no desc idx for extended attributes" - return - end - if desc.list_index - end - #warn "skipping loading xattribs" - # FIXME implement loading xattribs - end - - # corresponds to: - # * _pst_read_block_size - # * _pst_read_block ?? - # * _pst_ff_getIDblock_dec ?? - # * _pst_ff_getIDblock ?? - def pst_read_block_size offset, size, decrypt=true - io.seek offset - buf = io.read size - warn "tried to read #{size} bytes but only got #{buf.length}" if buf.length != size - encrypted? && decrypt ? CompressibleEncryption.decrypt(buf) : buf - end - - # - # id2 - # ---------------------------------------------------------------------------- - # - - class ID2Assoc < Struct.new(:id2, :id, :table2) - UNPACK_STR = 'V3' - SIZE = 12 - - def initialize data - data = data.unpack(UNPACK_STR) if String === data - super(*data) - end - end - - class ID2Assoc64 < Struct.new(:id2, :u1, :id, :table2) - UNPACK_STR = 'VVT2' - SIZE = 24 - - def initialize data - if String === data - data = Pst.unpack data, UNPACK_STR - end - super(*data) - end - - def self.load_chain idx - buf = idx.read - type, count = buf.unpack 'v2' - unless type == 0x0002 - raise 'unknown id2 type 0x%04x' % type - #return - end - id2 = [] - count.times do |i| - assoc = new buf[8 + SIZE * i, SIZE] - id2 << assoc - if assoc.table2 != 0 - id2 += load_chain idx.pst.idx_from_id(assoc.table2) - end - end - id2 - end - end - - class ID2Mapping - attr_reader :list - def initialize pst, list - @pst = pst - @list = list - # create a lookup. - @id_from_id2 = {} - @list.each do |id2| - # NOTE we take the last value seen value if there are duplicates. this "fixes" - # test4-o1997.pst for the time being. - warn "there are duplicate id2 records with id #{id2.id2}" if @id_from_id2[id2.id2] - next if @id_from_id2[id2.id2] - @id_from_id2[id2.id2] = id2.id - end - end - - # TODO: fix logging - def warn s - Mapi::Log.warn s - end - - # corresponds to: - # * _pst_getID2 - def [] id - #id2 = @list.find { |x| x.id2 == id } - id = @id_from_id2[id] - id and @pst.idx_from_id(id) - end - end - - def load_idx2 idx - if header.version_2003? - id2 = ID2Assoc64.load_chain idx - else - id2 = load_idx2_rec idx - end - ID2Mapping.new self, id2 - end - - # corresponds to - # * _pst_build_id2 - def load_idx2_rec idx - # i should perhaps use a idx chain style read here? - buf = pst_read_block_size idx.offset, idx.size, false - type, count = buf.unpack 'v2' - unless type == 0x0002 - raise 'unknown id2 type 0x%04x' % type - #return - end - id2 = [] - count.times do |i| - assoc = ID2Assoc.new buf[4 + ID2Assoc::SIZE * i, ID2Assoc::SIZE] - id2 << assoc - if assoc.table2 != 0 - id2 += load_idx2_rec idx_from_id(assoc.table2) - end - end - id2 - end - - class RangesIOIdxChain < RangesIOEncryptable - def initialize pst, idx_head - @idxs = pst.id2_block_idx_chain idx_head - # whether or not a given idx needs encrypting - decrypts = @idxs.map do |idx| - decrypt = (idx.id & 2) != 0 ? false : pst.encrypted? - end.uniq - raise NotImplementedError, 'partial encryption in RangesIOID2' if decrypts.length > 1 - decrypt = decrypts.first - # convert idxs to ranges - ranges = @idxs.map { |idx| [idx.offset, idx.size] } - super pst.io, :ranges => ranges, :decrypt => decrypt - end - end - - class RangesIOID2 < RangesIOIdxChain - def self.new pst, id2, idx2 - RangesIOIdxChain.new pst, idx2[id2] - end - end - - # corresponds to: - # * _pst_ff_getID2block - # * _pst_ff_getID2data - # * _pst_ff_compile_ID - def id2_block_idx_chain idx - if (idx.id & 0x2) == 0 - [idx] - else - buf = idx.read - type, fdepth, count = buf[0, 4].unpack 'CCv' - unless type == 1 # libpst.c:3958 - warn 'Error in idx_chain - %p, %p, %p - attempting to ignore' % [type, fdepth, count] - return [idx] - end - # there are 4 unaccounted for bytes here, 4...8 - if header.version_2003? - ids = buf[8, count * 8].unpack("T#{count}") - else - ids = buf[8, count * 4].unpack('V*') - end - if fdepth == 1 - ids.map { |id| idx_from_id id } - else - ids.map { |id| id2_block_idx_chain idx_from_id(id) }.flatten - end - end - end - - # - # main block parsing code. gets raw properties - # ---------------------------------------------------------------------------- - # - - # the job of this class, is to take a desc record, and be able to enumerate through the - # mapi properties of the associated thing. - # - # corresponds to - # * _pst_parse_block - # * _pst_process (in some ways. although perhaps thats more the Item::Properties#add_property) - class BlockParser - include Mapi::Types::Constants - - TYPES = { - 0xbcec => 1, - 0x7cec => 2, - # type 3 is removed. an artifact of not handling the indirect blocks properly in libpst. - } - - PR_SUBJECT = PropertySet::TAGS.find { |num, (name, type)| name == 'PR_SUBJECT' }.first.hex - PR_BODY_HTML = PropertySet::TAGS.find { |num, (name, type)| name == 'PR_BODY_HTML' }.first.hex - - # this stuff could maybe be moved to Ole::Types? or leverage it somehow? - # whether or not a type is immeidate is more a property of the pst encoding though i expect. - # what i probably can add is a generic concept of whether a type is of variadic length or not. - - # these lists are very incomplete. think they are largely copied from libpst - - IMMEDIATE_TYPES = [ - PT_SHORT, PT_LONG, PT_BOOLEAN - ] - - INDIRECT_TYPES = [ - PT_DOUBLE, PT_OBJECT, - 0x0014, # whats this? probably something like PT_LONGLONG, given the correspondence with the - # ole variant types. (= VT_I8) - PT_STRING8, PT_UNICODE, # unicode isn't in libpst, but added here for outlook 2003 down the track - PT_SYSTIME, - 0x0048, # another unknown - 0x0102, # this is PT_BINARY vs PT_CLSID - #0x1003, # these are vector types, but they're commented out for now because i'd expect that - #0x1014, # there's extra decoding needed that i'm not doing. (probably just need a simple - # # PT_* => unpack string mapping for the immediate types, and just do unpack('V*') etc - #0x101e, - #0x1102 - ] - - # the attachment and recipient arrays appear to be always stored with these fixed - # id2 values. seems strange. are there other extra streams? can find out by making higher - # level IO wrapper, which has the id2 value, and doing the diff of available id2 values versus - # used id2 values in properties of an item. - ID2_ATTACHMENTS = 0x671 - ID2_RECIPIENTS = 0x692 - - attr_reader :desc, :data, :data_chunks, :offset_tables - def initialize desc - raise FormatError, "unable to get associated index record for #{desc.inspect}" unless desc.desc - @desc = desc - #@data = desc.desc.read - if Pst::Index === desc.desc - #@data = RangesIOIdxChain.new(desc.pst, desc.desc).read - idxs = desc.pst.id2_block_idx_chain desc.desc - # this gets me the plain index chain. - else - # fake desc - #@data = desc.desc.read - idxs = [desc.desc] - end - - @data_chunks = idxs.map { |idx| idx.read } - @data = @data_chunks.first - - load_header - - @index_offsets = [@index_offset] + @data_chunks[1..-1].map { |chunk| chunk.unpack('v')[0] } - @offset_tables = [] - @ignored = [] - @data_chunks.zip(@index_offsets).each do |chunk, offset| - ignore = chunk[offset, 2].unpack('v')[0] - @ignored << ignore -# p ignore - @offset_tables.push offset_table = [] - # maybe its ok if there aren't to be any values ? - raise FormatError if offset == 0 - offsets = chunk[offset + 2..-1].unpack('v*') - #p offsets - offsets[0, ignore + 2].each_cons 2 do |from, to| - #next if to == 0 - raise FormatError, [from, to].inspect if from > to - offset_table << [from, to] - end - end - - @offset_table = @offset_tables.first - @idxs = idxs - - # now, we may have multiple different blocks - end - - # a given desc record may or may not have associated idx2 data. we lazily load it here, so it will never - # actually be requested unless get_data_indirect actually needs to use it. - def idx2 - return @idx2 if @idx2 - raise FormatError, 'idx2 requested but no idx2 available' unless desc.list_index - # should check this can't return nil - @idx2 = desc.pst.load_idx2 desc.list_index - end - - def load_header - @index_offset, type, @offset1 = data.unpack 'vvV' - raise FormatError, 'unknown block type signature 0x%04x' % type unless TYPES[type] - @type = TYPES[type] - end - - # based on the value of offset, return either some data from buf, or some data from the - # id2 chain id2, where offset is some key into a lookup table that is stored as the id2 - # chain. i think i may need to create a BlockParser class that wraps up all this mess. - # - # corresponds to: - # * _pst_getBlockOffsetPointer - # * _pst_getBlockOffset - def get_data_indirect offset - return get_data_indirect_io(offset).read - - if offset == 0 - nil - elsif (offset & 0xf) == 0xf - RangesIOID2.new(desc.pst, offset, idx2).read - else - low, high = offset & 0xf, offset >> 4 - raise FormatError if low != 0 or (high & 0x1) != 0 or (high / 2) > @offset_table.length - from, to = @offset_table[high / 2] - data[from...to] - end - end - - def get_data_indirect_io offset - if offset == 0 - nil - elsif (offset & 0xf) == 0xf - if idx2[offset] - RangesIOID2.new desc.pst, offset, idx2 - else - warn "tried to get idx2 record for #{offset} but failed" - return StringIO.new('') - end - else - low, high = offset & 0xf, offset >> 4 - if low != 0 or (high & 0x1) != 0 -# raise FormatError, - warn "bad - #{low} #{high} (1)" - return StringIO.new('') - end - # lets see which block it should come from. - block_idx, i = high.divmod 4096 - unless block_idx < @data_chunks.length - warn "bad - block_idx to high (not #{block_idx} < #{@data_chunks.length})" - return StringIO.new('') - end - data_chunk, offset_table = @data_chunks[block_idx], @offset_tables[block_idx] - if i / 2 >= offset_table.length - warn "bad - #{low} #{high} - #{i / 2} >= #{offset_table.length} (2)" - return StringIO.new('') - end - #warn "ok - #{low} #{high} #{offset_table.length}" - from, to = offset_table[i / 2] - StringIO.new data_chunk[from...to] - end - end - - def handle_indirect_values key, type, value - case type - when PT_BOOLEAN - value = value != 0 - when *IMMEDIATE_TYPES # not including PT_BOOLEAN which we just did above - # no processing current applied (needed?). - when *INDIRECT_TYPES - # the value is a pointer - if String === value # ie, value size > 4 above - value = StringIO.new value - else - value = get_data_indirect_io(value) - end - # keep strings as immediate values for now, for compatability with how i set up - # Msg::Properties::ENCODINGS - if value - if type == PT_STRING8 - value = value.read - elsif type == PT_UNICODE - value = Ole::Types::FROM_UTF16.iconv value.read - end - end - # special subject handling - if key == PR_BODY_HTML and value - # to keep the msg code happy, which thinks body_html will be an io - # although, in 2003 version, they are 0102 already - value = StringIO.new value unless value.respond_to?(:read) - end - if key == PR_SUBJECT and value - ignore, offset = value.unpack 'C2' - offset = (offset == 1 ? nil : offset - 3) - value = value[2..-1] -=begin - index = value =~ /^[A-Z]*:/ ? $~[0].length - 1 : nil - unless ignore == 1 and offset == index - warn 'something wrong with subject hack' - $x = [ignore, offset, value] - require 'irb' - IRB.start - exit - end -=end -=begin -new idea: - -making sense of the \001\00[156] i've seen prefixing subject. i think its to do with the placement -of the ':', or the ' '. And perhaps an optimization to do with thread topic, and ignoring the prefixes -added by mailers. thread topic is equal to subject with all that crap removed. - -can test by creating some mails with bizarre subjects. - -subject="\001\005RE: blah blah" -subject="\001\001blah blah" -subject="\001\032Out of Office AutoReply: blah blah" -subject="\001\020Undeliverable: blah blah" - -looks like it - -=end - - # now what i think, is that perhaps, value[offset..-1] ... - # or something like that should be stored as a special tag. ie, do a double yield - # for this case. probably PR_CONVERSATION_TOPIC, in which case i'd write instead: - # yield [PR_SUBJECT, ref_type, value] - # yield [PR_CONVERSATION_TOPIC, ref_type, value[offset..-1] - # next # to skip the yield. - end - - # special handling for embedded objects - # used for attach_data for attached messages. in which case attach_method should == 5, - # for embedded object. - if type == PT_OBJECT and value - value = value.read if value.respond_to?(:read) - id2, unknown = value.unpack 'V2' - io = RangesIOID2.new desc.pst, id2, idx2 - - # hacky - desc2 = OpenStruct.new(:desc => io, :pst => desc.pst, :list_index => desc.list_index, :children => []) - # put nil instead of desc.list_index, otherwise the attachment is attached to itself ad infinitum. - # should try and fix that FIXME - # this shouldn't be done always. for an attached message, yes, but for an attached - # meta file, for example, it shouldn't. difference between embedded_ole vs embedded_msg - # really. - # note that in the case where its a embedded ole, you actually get a regular serialized ole - # object, so i need to create an ole storage object on a rangesioidxchain! - # eg: -=begin -att.props.display_name # => "Picture (Metafile)" -io = att.props.attach_data -io.read(32).unpack('H*') # => ["d0cf11e0a1b11ae100000.... note the docfile signature. -# plug some missing rangesio holes: -def io.rewind; seek 0; end -def io.flush; raise IOError; end -ole = Ole::Storage.open io -puts ole.root.to_tree - -- #<Dirent:"Root Entry"> - |- #<Dirent:"\001Ole" size=20 data="\001\000\000\002\000..."> - |- #<Dirent:"CONTENTS" size=65696 data="\327\315\306\232\000..."> - \- #<Dirent:"\003MailStream" size=12 data="\001\000\000\000[..."> -=end - # until properly fixed, i have disabled this code here, so this will break - # nested messages temporarily. - #value = Item.new desc2, RawPropertyStore.new(desc2).to_a - #desc2.list_index = nil - value = io - end - # this is PT_MV_STRING8, i guess. - # should probably have the 0x1000 flag, and do the or-ring. - # example of 0x1102 is PR_OUTLOOK_2003_ENTRYIDS. less sure about that one. - when 0x101e, 0x1102 - # example data: - # 0x802b "\003\000\000\000\020\000\000\000\030\000\000\000#\000\000\000BusinessCompetitionFavorites" - # this 0x802b would be an extended attribute for categories / keywords. - value = get_data_indirect_io(value).read unless String === value - num = value.unpack('V')[0] - offsets = value[4, 4 * num].unpack("V#{num}") - value = (offsets + [value.length]).to_enum(:each_cons, 2).map { |from, to| value[from...to] } - value.map! { |str| StringIO.new str } if type == 0x1102 - else - name = Mapi::Types::DATA[type].first rescue nil - warn '0x%04x %p' % [key, get_data_indirect_io(value).read] - raise NotImplementedError, 'unsupported mapi property type - 0x%04x (%p)' % [type, name] - end - [key, type, value] - end - end - -=begin -* recipients: - - affects: ["0x200764", "0x2011c4", "0x201b24", "0x201b44", "0x201ba4", "0x201c24", "0x201cc4", "0x202504"] - -after adding the rawpropertystoretable fix, all except the second parse properly, and satisfy: - - item.props.display_to == item.recipients.map { |r| r.props.display_name if r.props.recipient_type == 1 }.compact * '; ' - -only the second still has a problem - -#[#<struct Pst::Desc desc_id=0x2011c4, idx_id=0x397c, idx2_id=0x398a, parent_desc_id=0x8082>] - -think this is related to a multi block #data3. ie, when you use @x * rec_size, and it -goes > 8190, or there abouts, then it stuffs up. probably there is header gunk, or something, -similar to when #data is multi block. - -same problem affects the attachment table in test4. - -fixed that issue. round data3 ranges to rec_size. - -fix other issue with attached objects. - -all recipients and attachments in test2 are fine. - -only remaining issue is test4 recipients of 200044. strange. - -=end - - # RawPropertyStore is used to iterate through the properties of an item, or the auxiliary - # data for an attachment. its just a parser for the way the properties are serialized, when the - # properties don't have to conform to a column structure. - # - # structure of this chunk of data is often - # header, property keys, data values, and then indexes. - # the property keys has value in it. value can be the actual value if its a short type, - # otherwise you lookup the value in the indicies, where you get the offsets to use in the - # main data body. due to the indirect thing though, any of these parts could actually come - # from a separate stream. - class RawPropertyStore < BlockParser - include Enumerable - - attr_reader :length - def initialize desc - super - raise FormatError, "expected type 1 - got #{@type}" unless @type == 1 - - # the way that offset works, data1 may be a subset of buf, or something from id2. if its from buf, - # it will be offset based on index_offset and offset. so it could be some random chunk of data anywhere - # in the thing. - header_data = get_data_indirect @offset1 - raise FormatError if header_data.length < 8 - signature, offset2 = header_data.unpack 'V2' - #p [@type, signature] - raise FormatError, 'unhandled block signature 0x%08x' % @type if signature != 0x000602b5 - # this is actually a big chunk of tag tuples. - @index_data = get_data_indirect offset2 - @length = @index_data.length / 8 - end - - # iterate through the property tuples - def each - length.times do |i| - key, type, value = handle_indirect_values(*@index_data[8 * i, 8].unpack('vvV')) - yield key, type, value - end - end - end - - # RawPropertyStoreTable is kind of like a database table. - # it has a fixed set of columns. - # #[] is kind of like getting a row from the table. - # those rows are currently encapsulated by Row, which has #each like - # RawPropertyStore. - # only used for the recipients array, and the attachments array. completely lazy, doesn't - # load any of the properties upon creation. - class RawPropertyStoreTable < BlockParser - class Column < Struct.new(:ref_type, :type, :ind2_off, :size, :slot) - def initialize data - super(*data.unpack('v3CC')) - end - - def nice_type_name - Mapi::Types::DATA[ref_type].first[/_(.*)/, 1].downcase rescue '0x%04x' % ref_type - end - - def nice_prop_name - Mapi::PropertyStore::TAGS['%04x' % type].first[/_(.*)/, 1].downcase rescue '0x%04x' % type - end - - def inspect - "#<#{self.class} name=#{nice_prop_name.inspect}, type=#{nice_type_name.inspect}>" - end - end - - include Enumerable - - attr_reader :length, :index_data, :data2, :data3, :rec_size - def initialize desc - super - raise FormatError, "expected type 2 - got #{@type}" unless @type == 2 - - header_data = get_data_indirect @offset1 - # seven_c_blk - # often: u1 == u2 and u3 == u2 + 2, then rec_size == u3 + 4. wtf - seven_c, @num_list, u1, u2, u3, @rec_size, b_five_offset, - ind2_offset, u7, u8 = header_data[0, 22].unpack('CCv4V2v2') - @index_data = header_data[22..-1] - - raise FormatError if @num_list != schema.length or seven_c != 0x7c - # another check - min_size = schema.inject(0) { |total, col| total + col.size } - # seem to have at max, 8 padding bytes on the end of the record. not sure if it means - # anything. maybe its just space that hasn't been reclaimed due to columns being - # removed or something. probably should just check lower bound. - range = (min_size..min_size + 8) - warn "rec_size seems wrong (#{range} !=== #{rec_size})" unless range === rec_size - - header_data2 = get_data_indirect b_five_offset - raise FormatError if header_data2.length < 8 - signature, offset2 = header_data2.unpack 'V2' - # ??? seems a bit iffy - # there's probably more to the differences than this, and the data2 difference below - expect = desc.pst.header.version_2003? ? 0x000404b5 : 0x000204b5 - raise FormatError, 'unhandled block signature 0x%08x' % signature if signature != expect - - # this holds all the row data - # handle multiple block issue. - @data3_io = get_data_indirect_io ind2_offset - if RangesIOIdxChain === @data3_io - @data3_idxs = - # modify ranges - ranges = @data3_io.ranges.map { |offset, size| [offset, size / @rec_size * @rec_size] } - @data3_io.instance_variable_set :@ranges, ranges - end - @data3 = @data3_io.read - - # there must be something to the data in data2. i think data2 is the array of objects essentially. - # currently its only used to imply a length - # actually, at size 6, its just some auxiliary data. i'm thinking either Vv/vV, for 97, and something - # wider for 03. the second value is just the index (0...length), and the first value is - # some kind of offset i expect. actually, they were all id2 values, in another case. - # so maybe they're get_data_indirect values too? - # actually, it turned out they were identical to the PR_ATTACHMENT_ID2 values... - # id2_values = ie, data2.unpack('v*').to_enum(:each_slice, 3).transpose[0] - # table[i].assoc(PR_ATTACHMENT_ID2).last == id2_values[i], for all i. - @data2 = get_data_indirect(offset2) rescue nil - #if data2 - # @length = (data2.length / 6.0).ceil - #else - # the above / 6, may have been ok for 97 files, but the new 0x0004 style block must have - # different size records... just use this instead: - # hmmm, actually, we can still figure it out: - @length = @data3.length / @rec_size - #end - - # lets try and at least use data2 for a warning for now - if data2 - data2_rec_size = desc.pst.header.version_2003? ? 8 : 6 - warn 'somthing seems wrong with data3' unless @length == (data2.length / data2_rec_size) - end - end - - def schema - @schema ||= index_data.scan(/.{8}/m).map { |data| Column.new data } - end - - def [] idx - # handle funky rounding - Row.new self, idx * @rec_size - end - - def each - length.times { |i| yield self[i] } - end - - class Row - include Enumerable - - def initialize array_parser, x - @array_parser, @x = array_parser, x - end - - # iterate through the property tuples - def each - (@array_parser.index_data.length / 8).times do |i| - ref_type, type, ind2_off, size, slot = @array_parser.index_data[8 * i, 8].unpack 'v3CC' - # check this rescue too - value = @array_parser.data3[@x + ind2_off, size] -# if INDIRECT_TYPES.include? ref_type - if size <= 4 - value = value.unpack('V')[0] - end - #p ['0x%04x' % ref_type, '0x%04x' % type, (Msg::Properties::MAPITAGS['%04x' % type].first[/^.._(.*)/, 1].downcase rescue nil), - # value_orig, value, (get_data_indirect(value_orig.unpack('V')[0]) rescue nil), size, ind2_off, slot] - key, type, value = @array_parser.handle_indirect_values type, ref_type, value - yield key, type, value - end - end - end - end - - class AttachmentTable < BlockParser - # a "fake" MAPI property name for this constant. if you get a mapi property with - # this value, it is the id2 value to use to get attachment data. - PR_ATTACHMENT_ID2 = 0x67f2 - - attr_reader :desc, :table - def initialize desc - @desc = desc - # no super, we only actually want BlockParser2#idx2 - @table = nil - return unless desc.list_index - return unless idx = idx2[ID2_ATTACHMENTS] - # FIXME make a fake desc. - @desc2 = OpenStruct.new :desc => idx, :pst => desc.pst, :list_index => desc.list_index - @table = RawPropertyStoreTable.new @desc2 - end - - def to_a - return [] if !table - table.map do |attachment| - attachment = attachment.to_a - #p attachment - # potentially merge with yet more properties - # this still seems pretty broken - especially the property overlap - if attachment_id2 = attachment.assoc(PR_ATTACHMENT_ID2) - #p attachment_id2.last - #p idx2[attachment_id2.last] - @desc2.desc = idx2[attachment_id2.last] - RawPropertyStore.new(@desc2).each do |a, b, c| - record = attachment.assoc a - attachment << record = [] unless record - record.replace [a, b, c] - end - end - attachment - end - end - end - - # there is no equivalent to this in libpst. ID2_RECIPIENTS was just guessed given the above - # AttachmentTable. - class RecipientTable < BlockParser - attr_reader :desc, :table - def initialize desc - @desc = desc - # no super, we only actually want BlockParser2#idx2 - @table = nil - return unless desc.list_index - return unless idx = idx2[ID2_RECIPIENTS] - # FIXME make a fake desc. - desc2 = OpenStruct.new :desc => idx, :pst => desc.pst, :list_index => desc.list_index - @table = RawPropertyStoreTable.new desc2 - end - - def to_a - return [] if !table - table.map { |x| x.to_a } - end - end - - # - # higher level item code. wraps up the raw properties above, and gives nice - # objects to work with. handles item relationships too. - # ---------------------------------------------------------------------------- - # - - def self.make_property_set property_list - hash = property_list.inject({}) do |hash, (key, type, value)| - hash.update PropertySet::Key.new(key) => value - end - PropertySet.new hash - end - - class Attachment < Mapi::Attachment - def initialize list - super Pst.make_property_set(list) - - @embedded_msg = props.attach_data if Item === props.attach_data - end - end - - class Recipient < Mapi::Recipient - def initialize list - super Pst.make_property_set(list) - end - end - - class Item < Mapi::Message - class EntryID < Struct.new(:u1, :entry_id, :id) - UNPACK_STR = 'VA16V' - - def initialize data - data = data.unpack(UNPACK_STR) if String === data - super(*data) - end - end - - include RecursivelyEnumerable - - attr_accessor :type, :parent - - def initialize desc, list, type=nil - @desc = desc - super Pst.make_property_set(list) - - # this is kind of weird, but the ids of the special folders are stored in a hash - # when the root item is loaded - if ipm_wastebasket_entryid - desc.pst.special_folder_ids[ipm_wastebasket_entryid] = :wastebasket - end - - if finder_entryid - desc.pst.special_folder_ids[finder_entryid] = :finder - end - - # and then here, those are used, along with a crappy heuristic to determine if we are an - # item -=begin -i think the low bits of the desc_id can give some info on the type. - -it seems that 0x4 is for regular messages (and maybe contacts etc) -0x2 is for folders, and 0x8 is for special things like rules etc, that aren't visible. -=end - unless type - type = props.valid_folder_mask || ipm_subtree_entryid || props.content_count || props.subfolders ? :folder : :message - if type == :folder - type = desc.pst.special_folder_ids[desc.desc_id] || type - end - end - - @type = type - end - - def each_child - id = ipm_subtree_entryid - if id - root = @desc.pst.desc_from_id id - raise "couldn't find root" unless root - raise 'both kinds of children' unless @desc.children.empty? - children = root.children - # lets look up the other ids we have. - # typically the wastebasket one "deleted items" is in the children already, but - # the search folder isn't. - extras = [ipm_wastebasket_entryid, finder_entryid].compact.map do |id| - root = @desc.pst.desc_from_id id - warn "couldn't find root for id #{id}" unless root - root - end.compact - # i do this instead of union, so as not to mess with the order of the - # existing children. - children += (extras - children) - children - else - @desc.children - end.each do |desc| - item = @desc.pst.pst_parse_item(desc) - item.parent = self - yield item - end - end - - def path - parents, item = [], self - parents.unshift item while item = item.parent - # remove root - parents.shift - parents.map { |item| item.props.display_name or raise 'unable to construct path' } * '/' - end - - def children - to_enum(:each_child).to_a - end - - # these are still around because they do different stuff - - # Top of Personal Folder Record - def ipm_subtree_entryid - @ipm_subtree_entryid ||= EntryID.new(props.ipm_subtree_entryid.read).id rescue nil - end - - # Deleted Items Folder Record - def ipm_wastebasket_entryid - @ipm_wastebasket_entryid ||= EntryID.new(props.ipm_wastebasket_entryid.read).id rescue nil - end - - # Search Root Record - def finder_entryid - @finder_entryid ||= EntryID.new(props.finder_entryid.read).id rescue nil - end - - # all these have been replaced with the method_missing below -=begin - # States which folders are valid for this message store - #def valid_folder_mask - # props[0x35df] - #end - - # Number of emails stored in a folder - def content_count - props[0x3602] - end - - # Has children - def subfolders - props[0x360a] - end -=end - - # i think i will change these, so they can inherit the lazyness from RawPropertyStoreTable. - # so if you want the last attachment, you can get it without creating the others perhaps. - # it just has to handle the no table at all case a bit more gracefully. - - def attachments - @attachments ||= AttachmentTable.new(@desc).to_a.map { |list| Attachment.new list } - end - - def recipients - #[] - @recipients ||= RecipientTable.new(@desc).to_a.map { |list| Recipient.new list } - end - - def each_recursive(&block) - #p :self => self - children.each do |child| - #p :child => child - block[child] - child.each_recursive(&block) - end - end - - def inspect - attrs = %w[display_name subject sender_name subfolders] -# attrs = %w[display_name valid_folder_mask ipm_wastebasket_entryid finder_entryid content_count subfolders] - str = attrs.map { |a| b = props.send a; " #{a}=#{b.inspect}" if b }.compact * ',' - - type_s = type == :message ? 'Message' : type == :folder ? 'Folder' : type.to_s.capitalize + 'Folder' - str2 = 'desc_id=0x%x' % @desc.desc_id - - !str.empty? ? "#<Pst::#{type_s} #{str2}#{str}>" : "#<Pst::#{type_s} #{str2} props=#{props.inspect}>" #\n" + props.transport_message_headers + ">" - end - end - - # corresponds to - # * _pst_parse_item - def pst_parse_item desc - Item.new desc, RawPropertyStore.new(desc).to_a - end - - # - # other random code - # ---------------------------------------------------------------------------- - # - - def dump_debug_info - puts "* pst header" - p header - -=begin -Looking at the output of this, for blank-o1997.pst, i see this part: -... -- (26624,516) desc block data (overlap of 4 bytes) -- (27136,516) desc block data (gap of 508 bytes) -- (28160,516) desc block data (gap of 2620 bytes) -... - -which confirms my belief that the block size for idx and desc is more likely 512 -=end - if 0 + 0 == 0 - puts '* file range usage' - file_ranges = - # these 3 things, should account for most of the data in the file. - [[0, Header::SIZE, 'pst file header']] + - @idx_offsets.map { |offset| [offset, Index::BLOCK_SIZE, 'idx block data'] } + - @desc_offsets.map { |offset| [offset, Desc::BLOCK_SIZE, 'desc block data'] } + - @idx.map { |idx| [idx.offset, idx.size, 'idx id=0x%x (%s)' % [idx.id, idx.type]] } - (file_ranges.sort_by { |idx| idx.first } + [nil]).to_enum(:each_cons, 2).each do |(offset, size, name), next_record| - # i think there is a padding of the size out to 64 bytes - # which is equivalent to padding out the final offset, because i think the offset is - # similarly oriented - pad_amount = 64 - warn 'i am wrong about the offset padding' if offset % pad_amount != 0 - # so, assuming i'm not wrong about that, then we can calculate how much padding is needed. - pad = pad_amount - (size % pad_amount) - pad = 0 if pad == pad_amount - gap = next_record ? next_record.first - (offset + size + pad) : 0 - extra = case gap <=> 0 - when -1; ["overlap of #{gap.abs} bytes)"] - when 0; [] - when +1; ["gap of #{gap} bytes"] - end - # how about we check that padding - @io.pos = offset + size - pad_bytes = @io.read(pad) - extra += ["padding not all zero"] unless pad_bytes == 0.chr * pad - puts "- #{offset}:#{size}+#{pad} #{name.inspect}" + (extra.empty? ? '' : ' [' + extra * ', ' + ']') - end - end - - # i think the idea of the idx, and indeed the idx2, is just to be able to - # refer to data indirectly, which means it can get moved around, and you just update - # the idx table. it is simply a list of file offsets and sizes. - # not sure i get how id2 plays into it though.... - # the sizes seem to be all even. is that a co-incidence? and the ids are all even. that - # seems to be related to something else (see the (id & 2) == 1 stuff) - puts '* idx entries' - @idx.each { |idx| puts "- #{idx.inspect}" } - - # if you look at the desc tree, you notice a few things: - # 1. there is a desc that seems to be the parent of all the folders, messages etc. - # it is the one whose parent is itself. - # one of its children is referenced as the subtree_entryid of the first desc item, - # the root. - # 2. typically only 2 types of desc records have idx2_id != 0. messages themselves, - # and the desc with id = 0x61 - the xattrib container. everything else uses the - # regular ids to find its data. i think it should be reframed as small blocks and - # big blocks, but i'll look into it more. - # - # idx_id and idx2_id are for getting to the data. desc_id and parent_desc_id just define - # the parent <-> child relationship, and the desc_ids are how the items are referred to in - # entryids. - # note that these aren't unique! eg for 0, 4 etc. i expect these'd never change, as the ids - # are stored in entryids. whereas the idx and idx2 could be a bit more volatile. - puts '* desc tree' - # make a dummy root hold everything just for convenience - root = Desc.new '' - def root.inspect; "#<Pst::Root>"; end - root.children.replace @orphans - # this still loads the whole thing as a string for gsub. should use directo output io - # version. - puts root.to_tree.gsub(/, (parent_desc_id|idx2_id)=0x0(?!\d)/, '') - - # this is fairly easy to understand, its just an attempt to display the pst items in a tree form - # which resembles what you'd see in outlook. - puts '* item tree' - # now streams directly - root_item.to_tree STDOUT - end - - def root_desc - @desc.first - end - - def root_item - item = pst_parse_item root_desc - item.type = :root - item - end - - def root - root_item - end - - # depth first search of all items - include Enumerable - - def each(&block) - root = self.root - block[root] - root.each_recursive(&block) - end - - def name - @name ||= root_item.props.display_name - end - - def inspect - "#<Pst name=#{name.inspect} io=#{io.inspect}>" - end -end -end - diff --git a/vendor/ruby-msg/lib/mapi/rtf.rb b/vendor/ruby-msg/lib/mapi/rtf.rb deleted file mode 100644 index 9fa133fac..000000000 --- a/vendor/ruby-msg/lib/mapi/rtf.rb +++ /dev/null @@ -1,169 +0,0 @@ -require 'stringio' -require 'strscan' -require 'rtf' - -module Mapi - # - # = Introduction - # - # The +RTF+ module contains a few helper functions for dealing with rtf - # in mapi messages: +rtfdecompr+, and <tt>rtf2html</tt>. - # - # Both were ported from their original C versions for simplicity's sake. - # - module RTF - RTF_PREBUF = - "{\\rtf1\\ansi\\mac\\deff0\\deftab720{\\fonttbl;}" \ - "{\\f0\\fnil \\froman \\fswiss \\fmodern \\fscript " \ - "\\fdecor MS Sans SerifSymbolArialTimes New RomanCourier" \ - "{\\colortbl\\red0\\green0\\blue0\n\r\\par " \ - "\\pard\\plain\\f0\\fs20\\b\\i\\u\\tab\\tx" - - # Decompresses compressed rtf +data+, as found in the mapi property - # +PR_RTF_COMPRESSED+. Code converted from my C version, which in turn - # I wrote from a Java source, in JTNEF I believe. - # - # C version was modified to use circular buffer for back references, - # instead of the optimization of the Java version to index directly into - # output buffer. This was in preparation to support streaming in a - # read/write neutral fashion. - def rtfdecompr data - io = StringIO.new data - buf = RTF_PREBUF + "\x00" * (4096 - RTF_PREBUF.length) - wp = RTF_PREBUF.length - rtf = '' - - # get header fields (as defined in RTFLIB.H) - compr_size, uncompr_size, magic, crc32 = io.read(16).unpack 'V*' - #warn "compressed-RTF data size mismatch" unless io.size == data.compr_size + 4 - - # process the data - case magic - when 0x414c454d # "MELA" magic number that identifies the stream as a uncompressed stream - rtf = io.read uncompr_size - when 0x75465a4c # "LZFu" magic number that identifies the stream as a compressed stream - flag_count = -1 - flags = nil - while rtf.length < uncompr_size and !io.eof? - # each flag byte flags 8 literals/references, 1 per bit - flags = ((flag_count += 1) % 8 == 0) ? io.getc : flags >> 1 - if 1 == (flags & 1) # each flag bit is 1 for reference, 0 for literal - rp, l = io.getc, io.getc - # offset is a 12 byte number. 2^12 is 4096, so thats fine - rp = (rp << 4) | (l >> 4) # the offset relative to block start - l = (l & 0xf) + 2 # the number of bytes to copy - l.times do - rtf << buf[wp] = buf[rp] - wp = (wp + 1) % 4096 - rp = (rp + 1) % 4096 - end - else - rtf << buf[wp] = io.getc - wp = (wp + 1) % 4096 - end - end - else # unknown magic number - raise "Unknown compression type (magic number 0x%08x)" % magic - end - - # not sure if its due to a bug in the above code. doesn't seem to be - # in my tests, but sometimes there's a trailing null. we chomp it here, - # which actually makes the resultant rtf smaller than its advertised - # size (+uncompr_size+). - rtf.chomp! 0.chr - rtf - end - - # Note, this is a conversion of the original C code. Not great - needs tests and - # some refactoring, and an attempt to correct some inaccuracies. Hacky but works. - # - # Returns +nil+ if it doesn't look like an rtf encapsulated rtf. - # - # Some cases that the original didn't deal with have been patched up, eg from - # this chunk, where there are tags outside of the htmlrtf ignore block. - # - # "{\\*\\htmltag116 <br />}\\htmlrtf \\line \\htmlrtf0 \\line {\\*\\htmltag84 <a href..." - # - # We take the approach of ignoring all rtf tags not explicitly handled. A proper - # parse tree would be nicer to work with. will need to look for ruby rtf library - # - # Some of the original comment to the c code is excerpted here: - # - # Sometimes in MAPI, the PR_BODY_HTML property contains the HTML of a message. - # But more usually, the HTML is encoded inside the RTF body (which you get in the - # PR_RTF_COMPRESSED property). These routines concern the decoding of the HTML - # from this RTF body. - # - # An encoded htmlrtf file is a valid RTF document, but which contains additional - # html markup information in its comments, and sometimes contains the equivalent - # rtf markup outside the comments. Therefore, when it is displayed by a plain - # simple RTF reader, the html comments are ignored and only the rtf markup has - # effect. Typically, this rtf markup is not as rich as the html markup would have been. - # But for an html-aware reader (such as the code below), we can ignore all the - # rtf markup, and extract the html markup out of the comments, and get a valid - # html document. - # - # There are actually two kinds of html markup in comments. Most of them are - # prefixed by "\*\htmltagNNN", for some number NNN. But sometimes there's one - # prefixed by "\*\mhtmltagNNN" followed by "\*\htmltagNNN". In this case, - # the two are equivalent, but the m-tag is for a MIME Multipart/Mixed Message - # and contains tags that refer to content-ids (e.g. img src="cid:072344a7") - # while the normal tag just refers to a name (e.g. img src="fred.jpg") - # The code below keeps the m-tag and discards the normal tag. - # If there are any m-tags like this, then the message also contains an - # attachment with a PR_CONTENT_ID property e.g. "072344a7". Actually, - # sometimes the m-tag is e.g. img src="http://outlook/welcome.html" and the - # attachment has a PR_CONTENT_LOCATION "http://outlook/welcome.html" instead - # of a PR_CONTENT_ID. - # - def rtf2html rtf - scan = StringScanner.new rtf - # require \fromhtml. is this worth keeping? apparently you see \\fromtext if it - # was converted from plain text. - return nil unless rtf["\\fromhtml"] - html = '' - ignore_tag = nil - # skip up to the first htmltag. return nil if we don't ever find one - return nil unless scan.scan_until /(?=\{\\\*\\htmltag)/ - until scan.empty? - if scan.scan /\{/ - elsif scan.scan /\}/ - elsif scan.scan /\\\*\\htmltag(\d+) ?/ - #p scan[1] - if ignore_tag == scan[1] - scan.scan_until /\}/ - ignore_tag = nil - end - elsif scan.scan /\\\*\\mhtmltag(\d+) ?/ - ignore_tag = scan[1] - elsif scan.scan /\\par ?/ - html << "\r\n" - elsif scan.scan /\\tab ?/ - html << "\t" - elsif scan.scan /\\'([0-9A-Za-z]{2})/ - html << scan[1].hex.chr - elsif scan.scan /\\pntext/ - scan.scan_until /\}/ - elsif scan.scan /\\htmlrtf/ - scan.scan_until /\\htmlrtf0 ?/ - # a generic throw away unknown tags thing. - # the above 2 however, are handled specially - elsif scan.scan /\\[a-z-]+(\d+)? ?/ - #elsif scan.scan /\\li(\d+) ?/ - #elsif scan.scan /\\fi-(\d+) ?/ - elsif scan.scan /[\r\n]/ - elsif scan.scan /\\([{}\\])/ - html << scan[1] - elsif scan.scan /(.)/ - html << scan[1] - else - p :wtf - end - end - html.strip.empty? ? nil : html - end - - module_function :rtf2html, :rtfdecompr - end -end - diff --git a/vendor/ruby-msg/lib/mapi/types.rb b/vendor/ruby-msg/lib/mapi/types.rb deleted file mode 100644 index 71416afd5..000000000 --- a/vendor/ruby-msg/lib/mapi/types.rb +++ /dev/null @@ -1,51 +0,0 @@ -require 'rubygems' -require 'ole/types' - -module Mapi - Log = Logger.new_with_callstack - - module Types - # - # Mapi property types, taken from http://msdn2.microsoft.com/en-us/library/bb147591.aspx. - # - # The fields are [mapi name, variant name, description]. Maybe I should just make it a - # struct. - # - # seen some synonyms here, like PT_I8 vs PT_LONG. seen stuff like PT_SRESTRICTION, not - # sure what that is. look at `grep ' PT_' data/mapitags.yaml | sort -u` - # also, it has stuff like PT_MV_BINARY, where _MV_ probably means multi value, and is - # likely just defined to | in 0x1000. - # - # Note that the last 2 are the only ones where the Mapi value differs from the Variant value - # for the corresponding variant type. Odd. Also, the last 2 are currently commented out here - # because of the clash. - # - # Note 2 - the strings here say VT_BSTR, but I don't have that defined in Ole::Types. Should - # maybe change them to match. I've also seen reference to PT_TSTRING, which is defined as some - # sort of get unicode first, and fallback to ansii or something. - # - DATA = { - 0x0001 => ['PT_NULL', 'VT_NULL', 'Null (no valid data)'], - 0x0002 => ['PT_SHORT', 'VT_I2', '2-byte integer (signed)'], - 0x0003 => ['PT_LONG', 'VT_I4', '4-byte integer (signed)'], - 0x0004 => ['PT_FLOAT', 'VT_R4', '4-byte real (floating point)'], - 0x0005 => ['PT_DOUBLE', 'VT_R8', '8-byte real (floating point)'], - 0x0006 => ['PT_CURRENCY', 'VT_CY', '8-byte integer (scaled by 10,000)'], - 0x000a => ['PT_ERROR', 'VT_ERROR', 'SCODE value; 32-bit unsigned integer'], - 0x000b => ['PT_BOOLEAN', 'VT_BOOL', 'Boolean'], - 0x000d => ['PT_OBJECT', 'VT_UNKNOWN', 'Data object'], - 0x001e => ['PT_STRING8', 'VT_BSTR', 'String'], - 0x001f => ['PT_UNICODE', 'VT_BSTR', 'String'], - 0x0040 => ['PT_SYSTIME', 'VT_DATE', '8-byte real (date in integer, time in fraction)'], - #0x0102 => ['PT_BINARY', 'VT_BLOB', 'Binary (unknown format)'], - #0x0102 => ['PT_CLSID', 'VT_CLSID', 'OLE GUID'] - } - - module Constants - DATA.each { |num, (mapi_name, variant_name, desc)| const_set mapi_name, num } - end - - include Constants - end -end - diff --git a/vendor/ruby-msg/lib/mime.rb b/vendor/ruby-msg/lib/mime.rb deleted file mode 100644 index 4340e4901..000000000 --- a/vendor/ruby-msg/lib/mime.rb +++ /dev/null @@ -1,165 +0,0 @@ -# -# = Introduction -# -# A *basic* mime class for _really_ _basic_ and probably non-standard parsing -# and construction of MIME messages. -# -# Intended for two main purposes in this project: -# 1. As the container that is used to build up the message for eventual -# serialization as an eml. -# 2. For assistance in parsing the +transport_message_headers+ provided in .msg files, -# which are then kept through to the final eml. -# -# = TODO -# -# * Better streaming support, rather than an all-in-string approach. -# * Add +OrderedHash+ optionally, to not lose ordering in headers. -# * A fair bit remains to be done for this class, its fairly immature. But generally I'd like -# to see it be more generally useful. -# * All sorts of correctness issues, encoding particular. -# * Duplication of work in net/http.rb's +HTTPHeader+? Don't know if the overlap is sufficient. -# I don't want to lower case things, just for starters. -# * Mime was the original place I wrote #to_tree, intended as a quick debug hack. -# -class SimpleMime - Hash = begin - require 'orderedhash' - OrderedHash - rescue LoadError - Hash - end - - attr_reader :headers, :body, :parts, :content_type, :preamble, :epilogue - - # Create a SimpleMime object using +str+ as an initial serialization, which must contain headers - # and a body (even if empty). Needs work. - def initialize str, ignore_body=false - headers, @body = $~[1..-1] if str[/(.*?\r?\n)(?:\r?\n(.*))?\Z/m] - - @headers = Hash.new { |hash, key| hash[key] = [] } - @body ||= '' - headers.to_s.scan(/^\S+:\s*.*(?:\n\t.*)*/).each do |header| - @headers[header[/(\S+):/, 1]] << header[/\S+:\s*(.*)/m, 1].gsub(/\s+/m, ' ').strip # this is kind of wrong - end - - # don't have to have content type i suppose - @content_type, attrs = nil, {} - if content_type = @headers['Content-Type'][0] - @content_type, attrs = SimpleMime.split_header content_type - end - - return if ignore_body - - if multipart? - if body.empty? - @preamble = '' - @epilogue = '' - @parts = [] - else - # we need to split the message at the boundary - boundary = attrs['boundary'] or raise "no boundary for multipart message" - - # splitting the body: - parts = body.split(/--#{Regexp.quote boundary}/m) - unless parts[-1] =~ /^--/; warn "bad multipart boundary (missing trailing --)" - else parts[-1][0..1] = '' - end - parts.each_with_index do |part, i| - part =~ /^(\r?\n)?(.*?)(\r?\n)?\Z/m - part.replace $2 - warn "bad multipart boundary" if (1...parts.length-1) === i and !($1 && $3) - end - @preamble = parts.shift - @epilogue = parts.pop - @parts = parts.map { |part| SimpleMime.new part } - end - end - end - - def multipart? - @content_type && @content_type =~ /^multipart/ ? true : false - end - - def inspect - # add some extra here. - "#<SimpleMime content_type=#{@content_type.inspect}>" - end - - def to_tree - if multipart? - str = "- #{inspect}\n" - parts.each_with_index do |part, i| - last = i == parts.length - 1 - part.to_tree.split(/\n/).each_with_index do |line, j| - str << " #{last ? (j == 0 ? "\\" : ' ') : '|'}" + line + "\n" - end - end - str - else - "- #{inspect}\n" - end - end - - def to_s opts={} - opts = {:boundary_counter => 0}.merge opts - if multipart? - boundary = SimpleMime.make_boundary opts[:boundary_counter] += 1, self - @body = [preamble, parts.map { |part| "\r\n" + part.to_s(opts) + "\r\n" }, "--\r\n" + epilogue]. - flatten.join("\r\n--" + boundary) - content_type, attrs = SimpleMime.split_header @headers['Content-Type'][0] - attrs['boundary'] = boundary - @headers['Content-Type'] = [([content_type] + attrs.map { |key, val| %{#{key}="#{val}"} }).join('; ')] - end - - str = '' - @headers.each do |key, vals| - vals.each { |val| str << "#{key}: #{val}\r\n" } - end - str << "\r\n" + @body - end - - def self.split_header header - # FIXME: haven't read standard. not sure what its supposed to do with " in the name, or if other - # escapes are allowed. can't test on windows as " isn't allowed anyway. can be fixed with more - # accurate parser later. - # maybe move to some sort of Header class. but not all headers should be of it i suppose. - # at least add a join_header then, taking name and {}. for use in SimpleMime#to_s (for boundary - # rewrite), and Attachment#to_mime, among others... - attrs = {} - header.scan(/;\s*([^\s=]+)\s*=\s*("[^"]*"|[^\s;]*)\s*/m).each do |key, value| - if attrs[key]; warn "ignoring duplicate header attribute #{key.inspect}" - else attrs[key] = value[/^"/] ? value[1..-2] : value - end - end - - [header[/^[^;]+/].strip, attrs] - end - - # +i+ is some value that should be unique for all multipart boundaries for a given message - def self.make_boundary i, extra_obj = SimpleMime - "----_=_NextPart_#{'%03d' % i}_#{'%08x' % extra_obj.object_id}.#{'%08x' % Time.now}" - end -end - -=begin -things to consider for header work. -encoded words: -Subject: =?iso-8859-1?q?p=F6stal?= - -and other mime funkyness: -Content-Disposition: attachment; - filename*0*=UTF-8''09%20%D7%90%D7%A5; - filename*1*=%20%D7%A1%D7%91-; - filename*2*=%D7%A7%95%A5.wma -Content-Transfer-Encoding: base64 - -and another, doing a test with an embedded newline in an attachment name, I -get this output from evolution. I get the feeling that this is probably a bug -with their implementation though, they weren't expecting new lines in filenames. -Content-Disposition: attachment; filename="asdf'b\"c -d efgh=i: ;\\j" -d efgh=i: ;\\j"; charset=us-ascii -Content-Type: text/plain; name="asdf'b\"c"; charset=us-ascii - -=end - diff --git a/vendor/ruby-msg/lib/orderedhash.rb b/vendor/ruby-msg/lib/orderedhash.rb deleted file mode 100644 index 16a4f5860..000000000 --- a/vendor/ruby-msg/lib/orderedhash.rb +++ /dev/null @@ -1,218 +0,0 @@ -# = OrderedHash -# -# == Version -# 1.2006.07.13 (change of the first number means Big Change) -# -# == Description -# Hash which preserves order of added items (like PHP array). -# -# == Usage -# -# (see examples directory under the ruby gems root directory) -# -# require 'rubygems' -# require 'ordered_hash' -# -# hsh = OrderedHash.new -# hsh['z'] = 1 -# hsh['a'] = 2 -# hsh['c'] = 3 -# p hsh.keys # ['z','a','c'] -# -# == Source -# http://simplypowerful.1984.cz/goodlibs/1.2006.07.13 -# -# == Author -# jan molic (/mig/at_sign/1984/dot/cz/) -# -# == Thanks to -# Andrew Johnson for his suggestions and fixes of Hash[], merge, to_a, inspect and shift -# Desmond Dsouza for == fixes -# -# == Licence -# You can redistribute it and/or modify it under the same terms of Ruby's license; -# either the dual license version in 2003, or any later version. -# - -class OrderedHash < Hash - - attr_accessor :order - - class << self - - def [] *args - hsh = OrderedHash.new - if Hash === args[0] - hsh.replace args[0] - elsif (args.size % 2) != 0 - raise ArgumentError, "odd number of elements for Hash" - else - hsh[args.shift] = args.shift while args.size > 0 - end - hsh - end - - end - - def initialize(*a, &b) - super - @order = [] - end - - def store_only a,b - store a,b - end - - alias orig_store store - - def store a,b - @order.push a unless has_key? a - super a,b - end - - alias []= store - - def == hsh2 - return hsh2==self if !hsh2.is_a?(OrderedHash) - return false if @order != hsh2.order - super hsh2 - end - - def clear - @order = [] - super - end - - def delete key - @order.delete key - super - end - - def each_key - @order.each { |k| yield k } - self - end - - def each_value - @order.each { |k| yield self[k] } - self - end - - def each - @order.each { |k| yield k,self[k] } - self - end - - alias each_pair each - - def delete_if - @order.clone.each { |k| - delete k if yield - } - self - end - - def values - ary = [] - @order.each { |k| ary.push self[k] } - ary - end - - def keys - @order - end - - def invert - hsh2 = Hash.new - @order.each { |k| hsh2[self[k]] = k } - hsh2 - end - - def reject &block - self.dup.delete_if( &block ) - end - - def reject! &block - hsh2 = reject( &block ) - self == hsh2 ? nil : hsh2 - end - - def replace hsh2 - @order = hsh2.keys - super hsh2 - end - - def shift - key = @order.first - key ? [key,delete(key)] : super - end - - def unshift k,v - unless self.include? k - @order.unshift k - orig_store(k,v) - true - else - false - end - end - - def push k,v - unless self.include? k - @order.push k - orig_store(k,v) - true - else - false - end - end - - def pop - key = @order.last - key ? [key,delete(key)] : nil - end - - def first - self[@order.first] - end - - def last - self[@order.last] - end - - def to_a - ary = [] - each { |k,v| ary << [k,v] } - ary - end - - def to_s - self.to_a.to_s - end - - def inspect - ary = [] - each {|k,v| ary << k.inspect + "=>" + v.inspect} - '{' + ary.join(", ") + '}' - end - - def update hsh2 - hsh2.each { |k,v| self[k] = v } - self - end - - alias :merge! update - - def merge hsh2 - self.dup update(hsh2) - end - - def select - ary = [] - each { |k,v| ary << [k,v] if yield k,v } - ary - end - -end - -#=end diff --git a/vendor/ruby-msg/lib/rtf.rb b/vendor/ruby-msg/lib/rtf.rb deleted file mode 100755 index 3afac68a8..000000000 --- a/vendor/ruby-msg/lib/rtf.rb +++ /dev/null @@ -1,109 +0,0 @@ -require 'stringio' - -# this file is pretty crap, its just to ensure there is always something readable if -# there is an rtf only body, with no html encapsulation. - -module RTF - class Tokenizer - def self.process io - while true do - case c = io.getc - when ?{; yield :open_group - when ?}; yield :close_group - when ?\\ - case c = io.getc - when ?{, ?}, ?\\; yield :text, c.chr - when ?'; yield :text, [io.read(2)].pack('H*') - when ?a..?z, ?A..?Z - # read control word - str = c.chr - str << c while c = io.read(1) and c =~ /[a-zA-Z]/ - neg = 1 - neg = -1 and c = io.read(1) if c == '-' - num = if c =~ /[0-9]/ - num = c - num << c while c = io.read(1) and c =~ /[0-9]/ - num.to_i * neg - end - raise "invalid rtf stream" if neg == -1 and !num # ???? \blahblah- some text - io.seek(-1, IO::SEEK_CUR) if c != ' ' - yield :control_word, str, num - when nil - raise "invalid rtf stream" # \EOF - else - # other kind of control symbol - yield :control_symbol, c.chr - end - when nil - return - when ?\r, ?\n - # ignore - else yield :text, c.chr - end - end - end - end - - class Converter - # crappy - def self.rtf2text str, format=:text - group = 0 - text = '' - text << "<html>\n<body>" if format == :html - group_type = [] - group_tags = [] - RTF::Tokenizer.process(StringIO.new(str)) do |a, b, c| - add_text = '' - case a - when :open_group; group += 1; group_type[group] = nil; group_tags[group] = [] - when :close_group; group_tags[group].reverse.each { |t| text << "</#{t}>" }; group -= 1; - when :control_word; # ignore - group_type[group] ||= b - # maybe change this to use utf8 where possible - add_text = if b == 'par' || b == 'line' || b == 'page'; "\n" - elsif b == 'tab' || b == 'cell'; "\t" - elsif b == 'endash' || b == 'emdash'; "-" - elsif b == 'emspace' || b == 'enspace' || b == 'qmspace'; " " - elsif b == 'ldblquote'; '"' - else '' - end - if b == 'b' || b == 'i' and format == :html - close = c == 0 ? '/' : '' - text << "<#{close}#{b}>" - if c == 0 - group_tags[group].delete b - else - group_tags[group] << b - end - end - # lot of other ones belong in here.\ -=begin -\bullet Bullet character. -\lquote Left single quotation mark. -\rquote Right single quotation mark. -\ldblquote Left double quotation mark. -\rdblquote -=end - when :control_symbol; # ignore - group_type[group] ||= b - add_text = ' ' if b == '~' # non-breakable space - add_text = '-' if b == '_' # non-breakable hypen - when :text - add_text = b if group <= 1 or group_type[group] == 'rtlch' && !group_type[0...group].include?('*') - end - if format == :html - text << add_text.gsub(/([<>&"'])/) do - ent = { '<' => 'lt', '>' => 'gt', '&' => 'amp', '"' => 'quot', "'" => 'apos' }[$1] - "&#{ent};" - end - text << '<br>' if add_text == "\n" - else - text << add_text - end - end - text << "</body>\n</html>\n" if format == :html - text - end - end -end - |