exchange-offline-address-book 0.0.1 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +54 -0
- data/Rakefile +13 -0
- data/exchange-offline-address-book.gemspec +32 -0
- data/lib/exchange-offline-address-book.rb +114 -0
- data/lib/exchange-offline-address-book/mspack.rb +18 -0
- data/lib/exchange-offline-address-book/parser.rb +741 -0
- data/lib/exchange-offline-address-book/version.rb +3 -0
- data/test/test_exchange-offline-address-book.rb +11 -0
- metadata +78 -25
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 36482b6cf832cab6b56979b4f9632c010b3fa645
|
4
|
+
data.tar.gz: ca6a463ea3983aa043505fbbc842ebf0f2b9174b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3950eaaeaabcb130cfc2c632d242937279c52e42b735cd493e4d4df4e8cf0db8370e368f3ac2fb8541439f4d64ad5353f471735439f62c3d01f86aebfbad1f7f
|
7
|
+
data.tar.gz: 4a47c4aec5d94119ae97364103d0d515fd6c382145448c57c6d5b817c92568de7a9bc0f6800cc1302c045d2456bbe5caa5fc89fa767f8fdad3e97d139a20e9f9
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
exchange-offline-address-book (0.0.5)
|
5
|
+
autodiscover (~> 1)
|
6
|
+
curb (~> 0.9)
|
7
|
+
libmspack (~> 0.1)
|
8
|
+
nokogiri (~> 1.8)
|
9
|
+
|
10
|
+
GEM
|
11
|
+
remote: https://rubygems.org/
|
12
|
+
specs:
|
13
|
+
autodiscover (1.0.2)
|
14
|
+
httpclient
|
15
|
+
logging
|
16
|
+
nokogiri
|
17
|
+
nori
|
18
|
+
bump (0.5.3)
|
19
|
+
curb (0.9.3)
|
20
|
+
dotenv (2.2.1)
|
21
|
+
ffi (1.9.18)
|
22
|
+
ffi-compiler2 (2.0.0)
|
23
|
+
ffi (>= 1.0.0)
|
24
|
+
rake
|
25
|
+
gem-release (1.0.0)
|
26
|
+
httpclient (2.8.3)
|
27
|
+
libmspack (0.1.0)
|
28
|
+
ffi
|
29
|
+
ffi-compiler2 (>= 2.0.0)
|
30
|
+
little-plugger (1.1.4)
|
31
|
+
logging (2.2.2)
|
32
|
+
little-plugger (~> 1.1)
|
33
|
+
multi_json (~> 1.10)
|
34
|
+
mini_portile2 (2.2.0)
|
35
|
+
minitest (5.10.2)
|
36
|
+
multi_json (1.12.1)
|
37
|
+
nokogiri (1.8.0)
|
38
|
+
mini_portile2 (~> 2.2.0)
|
39
|
+
nori (2.6.0)
|
40
|
+
rake (12.0.0)
|
41
|
+
|
42
|
+
PLATFORMS
|
43
|
+
ruby
|
44
|
+
|
45
|
+
DEPENDENCIES
|
46
|
+
bump (~> 0.5)
|
47
|
+
bundler (~> 1.3)
|
48
|
+
dotenv (~> 2)
|
49
|
+
exchange-offline-address-book!
|
50
|
+
gem-release (~> 1)
|
51
|
+
minitest (~> 5)
|
52
|
+
|
53
|
+
BUNDLED WITH
|
54
|
+
1.15.1
|
data/Rakefile
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "exchange-offline-address-book/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "exchange-offline-address-book"
|
8
|
+
spec.version = OfflineAddressBook::VERSION
|
9
|
+
spec.authors = ["Emiliano Heyns"]
|
10
|
+
spec.email = ["Emiliano.Heyns@iris-advies.com"]
|
11
|
+
spec.description = %q{Get Exchange Offline Address Book}
|
12
|
+
spec.summary = %q{Get Exchange Offline Address Book}
|
13
|
+
spec.homepage = "http://github.io"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
spec.required_ruby_version = '>= 2.3'
|
21
|
+
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
23
|
+
spec.add_development_dependency "dotenv", '~> 2'
|
24
|
+
spec.add_development_dependency "minitest", '~> 5'
|
25
|
+
spec.add_development_dependency "gem-release", '~> 1'
|
26
|
+
spec.add_development_dependency "bump", '~> 0.5'
|
27
|
+
|
28
|
+
spec.add_runtime_dependency 'nokogiri', '~> 1.8'
|
29
|
+
spec.add_runtime_dependency 'autodiscover', '~> 1'
|
30
|
+
spec.add_runtime_dependency 'libmspack', '~> 0.1'
|
31
|
+
spec.add_runtime_dependency 'curb', '~> 0.9'
|
32
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'dotenv/load'
|
4
|
+
|
5
|
+
require 'autodiscover'
|
6
|
+
#require "autodiscover/debug"
|
7
|
+
|
8
|
+
require 'yaml'
|
9
|
+
require 'nokogiri'
|
10
|
+
require 'tempfile'
|
11
|
+
require 'json'
|
12
|
+
require 'ostruct'
|
13
|
+
|
14
|
+
require 'curb'
|
15
|
+
require_relative 'exchange-offline-address-book/parser'
|
16
|
+
require_relative 'exchange-offline-address-book/mspack'
|
17
|
+
|
18
|
+
class OfflineAddressBook
|
19
|
+
def initialize(email: nil, password: nil, username: nil, cachedir: nil, update: true)
|
20
|
+
@email = email
|
21
|
+
@username = username || email
|
22
|
+
@password = password
|
23
|
+
@cachedir = cachedir
|
24
|
+
@update = update
|
25
|
+
end
|
26
|
+
|
27
|
+
def download(file, target = nil)
|
28
|
+
client = Curl::Easy.new(baseurl + file)
|
29
|
+
client.http_auth_types = :ntlm
|
30
|
+
client.username = @username
|
31
|
+
client.password = @password
|
32
|
+
client.perform
|
33
|
+
|
34
|
+
return client.body_str if target.nil?
|
35
|
+
|
36
|
+
open(target, 'wb'){|f| f.write(client.body_str) }
|
37
|
+
end
|
38
|
+
|
39
|
+
def baseurl
|
40
|
+
@baseurl ||= begin
|
41
|
+
client = Autodiscover::Client.new(email: @email, password: @password, username: @username)
|
42
|
+
data = client.autodiscover(ignore_ssl_errors: true)
|
43
|
+
raise "No data" unless data
|
44
|
+
data.response['Account']['Protocol'].detect{|p| p['OABUrl'] && p['Type'] == 'EXPR'}['OABUrl']
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def addressbook
|
49
|
+
@addressbook ||= begin
|
50
|
+
lzx = nil
|
51
|
+
if !@update & @cachedir
|
52
|
+
oab = Dir[File.join(@cachedir, '*.oab')][0]
|
53
|
+
lzx = File.basename(oab, File.extname(oab)) + '.lzx' if oab
|
54
|
+
end
|
55
|
+
|
56
|
+
lzx ||= Nokogiri::XML(download('oab.xml')).at('//Full').inner_text
|
57
|
+
oab = File.basename(lzx, File.extname(lzx)) + '.oab'
|
58
|
+
|
59
|
+
if @cachedir && File.file?(File.join(@cachedir, oab))
|
60
|
+
oab = File.join(@cachedir, oab)
|
61
|
+
else
|
62
|
+
if @cachedir
|
63
|
+
%w{*.oab *.lzx *.yml *.json}.each{|ext|
|
64
|
+
Dir[File.join(@cachedir, ext)].each{|f| File.unlink(f) }
|
65
|
+
}
|
66
|
+
download(lzx, File.join(@cachedir, lzx))
|
67
|
+
lzx = File.join(@cachedir, lzx)
|
68
|
+
@oab = File.join(@cachedir, oab)
|
69
|
+
else
|
70
|
+
_lzx = Tempfile.new('lzx')
|
71
|
+
download(lzx, _lzx.path)
|
72
|
+
lzx = _lzx.path
|
73
|
+
oab = Tempfile.new('oab').path
|
74
|
+
end
|
75
|
+
|
76
|
+
puts 'decompressing'
|
77
|
+
LibMsPack.oab_decompress(lzx, oab)
|
78
|
+
puts 'done'
|
79
|
+
end
|
80
|
+
|
81
|
+
oab
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def cache
|
86
|
+
@cache ||= File.join(File.dirname(addressbook), File.basename(addressbook, File.extname(addressbook)) + '.json')
|
87
|
+
end
|
88
|
+
|
89
|
+
def header
|
90
|
+
@parsed ||= Parser.new(addressbook)
|
91
|
+
@parsed.header
|
92
|
+
end
|
93
|
+
|
94
|
+
def records
|
95
|
+
@records ||= begin
|
96
|
+
if File.file?(cache)
|
97
|
+
parsed = JSON.parse(open(cache).read).collect{|record| OpenStruct.new(record) }
|
98
|
+
else
|
99
|
+
@parsed ||= Parser.new(addressbook)
|
100
|
+
parsed = @parsed.records.collect{|record|
|
101
|
+
record.to_h.each_pair{|k, v|
|
102
|
+
record[k] = v[0] if v.length == 1
|
103
|
+
}
|
104
|
+
# no idea what's going on here
|
105
|
+
record.AddressBookObjectGuid = record.AddressBookObjectGuid.inspect if record.AddressBookObjectGuid
|
106
|
+
record
|
107
|
+
}
|
108
|
+
open(cache, 'w'){|f| f.write(JSON.pretty_generate(parsed.collect{|r| r.to_h}))} if @cachedir
|
109
|
+
end
|
110
|
+
|
111
|
+
parsed
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'libmspack'
|
2
|
+
|
3
|
+
module LibMsPack
|
4
|
+
attach_function :mspack_create_oab_decompressor, [ :pointer ], :pointer
|
5
|
+
attach_function :mspack_destroy_oab_decompressor, [ :pointer ], :void
|
6
|
+
|
7
|
+
class OABDecompressor < FFI::Struct
|
8
|
+
layout :decompress, callback([:pointer, :string, :string], :int),
|
9
|
+
:decompress_incremental, callback([:pointer, :string, :string, :string], :int)
|
10
|
+
end
|
11
|
+
|
12
|
+
def LibMsPack.oab_decompress(source, target)
|
13
|
+
dec = LibMsPack.mspack_create_oab_decompressor(nil)
|
14
|
+
msoab = LibMsPack::OABDecompressor.new(dec)
|
15
|
+
msoab[:decompress].call(dec, source, target)
|
16
|
+
LibMsPack.mspack_destroy_oab_decompressor(dec)
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,741 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'ostruct'
|
4
|
+
|
5
|
+
MapiPropertyDataType = OpenStruct.new({
|
6
|
+
Unspecified: 0,
|
7
|
+
Null: 1,
|
8
|
+
Short: 2,
|
9
|
+
Long: 3,
|
10
|
+
Float: 4,
|
11
|
+
Double: 5,
|
12
|
+
Currency: 6,
|
13
|
+
ApplicationTime: 7,
|
14
|
+
Error: 10,
|
15
|
+
Boolean: 11,
|
16
|
+
Object: 13,
|
17
|
+
LongLong: 20,
|
18
|
+
AnsiString: 30,
|
19
|
+
UnicodeString: 31,
|
20
|
+
SystemTime: 64,
|
21
|
+
Clsid: 72,
|
22
|
+
Binary: 258,
|
23
|
+
Mv: 0x1000 # Multi-value (aka array) flag
|
24
|
+
})
|
25
|
+
MapiPropertyDataType.MvShort = MapiPropertyDataType.Short | MapiPropertyDataType.Mv
|
26
|
+
MapiPropertyDataType.MvLong = MapiPropertyDataType.Long | MapiPropertyDataType.Mv
|
27
|
+
MapiPropertyDataType.MvFloat = MapiPropertyDataType.Float | MapiPropertyDataType.Mv
|
28
|
+
MapiPropertyDataType.MvDouble = MapiPropertyDataType.Double | MapiPropertyDataType.Mv
|
29
|
+
MapiPropertyDataType.MvCurrency = MapiPropertyDataType.Currency | MapiPropertyDataType.Mv
|
30
|
+
MapiPropertyDataType.MvApplicationTime = MapiPropertyDataType.ApplicationTime | MapiPropertyDataType.Mv
|
31
|
+
MapiPropertyDataType.MvLongLong = MapiPropertyDataType.LongLong | MapiPropertyDataType.Mv
|
32
|
+
MapiPropertyDataType.MvAnsiString = MapiPropertyDataType.AnsiString | MapiPropertyDataType.Mv
|
33
|
+
MapiPropertyDataType.MvUnicodeString = MapiPropertyDataType.UnicodeString | MapiPropertyDataType.Mv
|
34
|
+
MapiPropertyDataType.MvSystemTime = MapiPropertyDataType.SystemTime | MapiPropertyDataType.Mv
|
35
|
+
MapiPropertyDataType.MvClsid = MapiPropertyDataType.Clsid | MapiPropertyDataType.Mv
|
36
|
+
MapiPropertyDataType.MvBinary = MapiPropertyDataType.Binary | MapiPropertyDataType.Mv
|
37
|
+
MapiPropertyDataType.to_h.each_pair{|k, v| MapiPropertyDataType[v.to_s.to_sym] = k }
|
38
|
+
|
39
|
+
MapiPropertyName = {
|
40
|
+
'0001' => :TemplateData,
|
41
|
+
'0002' => :AlternateRecipientAllowed,
|
42
|
+
'0004' => :AutoForwardComment,
|
43
|
+
# '0004' => :ScriptData,
|
44
|
+
'0005' => :AutoForwarded,
|
45
|
+
'000F' => :DeferredDeliveryTime,
|
46
|
+
'0015' => :ExpiryTime,
|
47
|
+
'0017' => :Importance,
|
48
|
+
'001A' => :MessageClass,
|
49
|
+
'0023' => :OriginatorDeliveryReportRequested,
|
50
|
+
'0025' => :ParentKey,
|
51
|
+
'0026' => :Priority,
|
52
|
+
'0029' => :ReadReceiptRequested,
|
53
|
+
'002B' => :RecipientReassignmentProhibited,
|
54
|
+
'002E' => :OriginalSensitivity,
|
55
|
+
'0030' => :ReplyTime,
|
56
|
+
'0031' => :ReportTag,
|
57
|
+
'0032' => :ReportTime,
|
58
|
+
'0036' => :Sensitivity,
|
59
|
+
'0037' => :Subject,
|
60
|
+
'0039' => :ClientSubmitTime,
|
61
|
+
'003A' => :ReportName,
|
62
|
+
'003B' => :SentRepresentingSearchKey,
|
63
|
+
'003D' => :SubjectPrefix,
|
64
|
+
'003F' => :ReceivedByEntryId,
|
65
|
+
'0040' => :ReceivedByName,
|
66
|
+
'0041' => :SentRepresentingEntryId,
|
67
|
+
'0042' => :SentRepresentingName,
|
68
|
+
'0043' => :ReceivedRepresentingEntryId,
|
69
|
+
'0044' => :ReceivedRepresentingName,
|
70
|
+
'0045' => :ReportEntryId,
|
71
|
+
'0046' => :ReadReceiptEntryId,
|
72
|
+
'0047' => :MessageSubmissionId,
|
73
|
+
'0048' => :ProviderSubmitTime,
|
74
|
+
'0049' => :OriginalSubject,
|
75
|
+
'004B' => :OriginalMessageClass,
|
76
|
+
'004C' => :OriginalAuthorEntryId,
|
77
|
+
'004D' => :OriginalAuthorName,
|
78
|
+
'004E' => :OriginalSubmitTime,
|
79
|
+
'004F' => :ReplyRecipientEntries,
|
80
|
+
'0050' => :ReplyRecipientNames,
|
81
|
+
'0051' => :ReceivedBySearchKey,
|
82
|
+
'0052' => :ReceivedRepresentingSearchKey,
|
83
|
+
'0053' => :ReadReceiptSearchKey,
|
84
|
+
'0054' => :ReportSearchKey,
|
85
|
+
'0055' => :OriginalDeliveryTime,
|
86
|
+
'0057' => :MessageToMe,
|
87
|
+
'0058' => :MessageCcMe,
|
88
|
+
'0059' => :MessageRecipientMe,
|
89
|
+
'005A' => :OriginalSenderName,
|
90
|
+
'005B' => :OriginalSenderEntryId,
|
91
|
+
'005C' => :OriginalSenderSearchKey,
|
92
|
+
'005D' => :OriginalSentRepresentingName,
|
93
|
+
'005E' => :OriginalSentRepresentingEntryId,
|
94
|
+
'005F' => :OriginalSentRepresentingSearchKey,
|
95
|
+
'0060' => :StartDate,
|
96
|
+
'0061' => :EndDate,
|
97
|
+
'0062' => :OwnerAppointmentId,
|
98
|
+
'0063' => :ResponseRequested,
|
99
|
+
'0064' => :SentRepresentingAddressType,
|
100
|
+
'0065' => :SentRepresentingEmailAddress,
|
101
|
+
'0066' => :OriginalSenderAddressType,
|
102
|
+
'0067' => :OriginalSenderEmailAddress,
|
103
|
+
'0068' => :OriginalSentRepresentingAddressType,
|
104
|
+
'0069' => :OriginalSentRepresentingEmailAddress,
|
105
|
+
'0070' => :ConversationTopic,
|
106
|
+
'0071' => :ConversationIndex,
|
107
|
+
'0072' => :OriginalDisplayBcc,
|
108
|
+
'0073' => :OriginalDisplayCc,
|
109
|
+
'0074' => :OriginalDisplayTo,
|
110
|
+
'0075' => :ReceivedByAddressType,
|
111
|
+
'0076' => :ReceivedByEmailAddress,
|
112
|
+
'0077' => :ReceivedRepresentingAddressType,
|
113
|
+
'0078' => :ReceivedRepresentingEmailAddress,
|
114
|
+
'007D' => :TransportMessageHeaders,
|
115
|
+
'007F' => :TnefCorrelationKey,
|
116
|
+
'0080' => :ReportDisposition,
|
117
|
+
'0081' => :ReportDispositionMode,
|
118
|
+
'0807' => :AddressBookRoomCapacity,
|
119
|
+
'0809' => :AddressBookRoomDescription,
|
120
|
+
'0C06' => :NonReceiptNotificationRequested,
|
121
|
+
'0C08' => :OriginatorNonDeliveryReportRequested,
|
122
|
+
'0C15' => :RecipientType,
|
123
|
+
'0C17' => :ReplyRequested,
|
124
|
+
'0C19' => :SenderEntryId,
|
125
|
+
'0C1A' => :SenderName,
|
126
|
+
'0C1D' => :SenderSearchKey,
|
127
|
+
'0C1E' => :SenderAddressType,
|
128
|
+
'0C1F' => :SenderEmailAddress,
|
129
|
+
'0E01' => :DeleteAfterSubmit,
|
130
|
+
'0E02' => :DisplayBcc,
|
131
|
+
'0E03' => :DisplayCc,
|
132
|
+
'0E04' => :DisplayTo,
|
133
|
+
'0E06' => :MessageDeliveryTime,
|
134
|
+
'0E07' => :MessageFlags,
|
135
|
+
'0E08' => :MessageSize,
|
136
|
+
# '0E08' => :MessageSizeExtended,
|
137
|
+
'0E09' => :ParentEntryId,
|
138
|
+
'0E0F' => :Responsibility,
|
139
|
+
'0E12' => :MessageRecipients,
|
140
|
+
'0E13' => :MessageAttachments,
|
141
|
+
'0E17' => :MessageStatus,
|
142
|
+
'0E1B' => :HasAttachments,
|
143
|
+
'0E1D' => :NormalizedSubject,
|
144
|
+
'0E1F' => :RtfInSync,
|
145
|
+
'0E20' => :AttachSize,
|
146
|
+
'0E21' => :AttachNumber,
|
147
|
+
'0E23' => :InternetArticleNumber,
|
148
|
+
'0E28' => :PrimarySendAccount,
|
149
|
+
'0E29' => :NextSendAcct,
|
150
|
+
'0E2B' => :ToDoItemFlags,
|
151
|
+
'0E2C' => :SwappedToDoStore,
|
152
|
+
'0E2D' => :SwappedToDoData,
|
153
|
+
'0E69' => :Read,
|
154
|
+
'0E6A' => :SecurityDescriptorAsXml,
|
155
|
+
'0E79' => :TrustSender,
|
156
|
+
'0E84' => :ExchangeNTSecurityDescriptor,
|
157
|
+
'0E99' => :ExtendedRuleMessageActions,
|
158
|
+
'0E9A' => :ExtendedRuleMessageCondition,
|
159
|
+
'0E9B' => :ExtendedRuleSizeLimit,
|
160
|
+
'0FF4' => :Access,
|
161
|
+
'0FF5' => :RowType,
|
162
|
+
'0FF6' => :InstanceKey,
|
163
|
+
'0FF7' => :AccessLevel,
|
164
|
+
'0FF8' => :MappingSignature,
|
165
|
+
'0FF9' => :RecordKey,
|
166
|
+
'0FFB' => :StoreEntryId,
|
167
|
+
'0FFE' => :ObjectType,
|
168
|
+
'0FFF' => :EntryId,
|
169
|
+
'1000' => :Body,
|
170
|
+
'1001' => :ReportText,
|
171
|
+
'1009' => :RtfCompressed,
|
172
|
+
'1013' => :BodyHtml,
|
173
|
+
# '1013' => :Html,
|
174
|
+
'1014' => :BodyContentLocation,
|
175
|
+
'1015' => :BodyContentId,
|
176
|
+
'1016' => :NativeBody,
|
177
|
+
'1035' => :InternetMessageId,
|
178
|
+
'1039' => :InternetReferences,
|
179
|
+
'1042' => :InReplyToId,
|
180
|
+
'1043' => :ListHelp,
|
181
|
+
'1044' => :ListSubscribe,
|
182
|
+
'1045' => :ListUnsubscribe,
|
183
|
+
'1046' => :OriginalMessageId,
|
184
|
+
'1080' => :IconIndex,
|
185
|
+
'1081' => :LastVerbExecuted,
|
186
|
+
'1082' => :LastVerbExecutionTime,
|
187
|
+
'1090' => :FlagStatus,
|
188
|
+
'1091' => :FlagCompleteTime,
|
189
|
+
'1095' => :FollowupIcon,
|
190
|
+
'1096' => :BlockStatus,
|
191
|
+
'10C3' => :ICalendarStartTime,
|
192
|
+
'10C4' => :ICalendarEndTime,
|
193
|
+
'10C5' => :CdoRecurrenceid,
|
194
|
+
'10CA' => :ICalendarReminderNextTime,
|
195
|
+
'10F3' => :UrlCompName,
|
196
|
+
'10F4' => :AttributeHidden,
|
197
|
+
'10F6' => :AttributeReadOnly,
|
198
|
+
'3000' => :Rowid,
|
199
|
+
'3001' => :DisplayName,
|
200
|
+
'3002' => :AddressType,
|
201
|
+
'3003' => :EmailAddress,
|
202
|
+
'3004' => :Comment,
|
203
|
+
'3005' => :Depth,
|
204
|
+
'3007' => :CreationTime,
|
205
|
+
'3008' => :LastModificationTime,
|
206
|
+
'300B' => :SearchKey,
|
207
|
+
'3010' => :TargetEntryId,
|
208
|
+
'3013' => :ConversationId,
|
209
|
+
'3016' => :ConversationIndexTracking,
|
210
|
+
'3018' => :ArchiveTag,
|
211
|
+
'3019' => :PolicyTag,
|
212
|
+
'301A' => :RetentionPeriod,
|
213
|
+
'301B' => :StartDateEtc,
|
214
|
+
'301C' => :RetentionDate,
|
215
|
+
'301D' => :RetentionFlags,
|
216
|
+
'301E' => :ArchivePeriod,
|
217
|
+
'301F' => :ArchiveDate,
|
218
|
+
'340D' => :StoreSupportMask,
|
219
|
+
'340E' => :StoreState,
|
220
|
+
'3600' => :ContainerFlags,
|
221
|
+
'3601' => :FolderType,
|
222
|
+
'3602' => :ContentCount,
|
223
|
+
'3603' => :ContentUnreadCount,
|
224
|
+
'3609' => :Selectable,
|
225
|
+
'360A' => :Subfolders,
|
226
|
+
'360C' => :Anr,
|
227
|
+
'360E' => :ContainerHierarchy,
|
228
|
+
'360F' => :ContainerContents,
|
229
|
+
'3610' => :FolderAssociatedContents,
|
230
|
+
'3613' => :ContainerClass,
|
231
|
+
'36D0' => :IpmAppointmentEntryId,
|
232
|
+
'36D1' => :IpmContactEntryId,
|
233
|
+
'36D2' => :IpmJournalEntryId,
|
234
|
+
'36D3' => :IpmNoteEntryId,
|
235
|
+
'36D4' => :IpmTaskEntryId,
|
236
|
+
'36D5' => :RemindersOnlineEntryId,
|
237
|
+
'36D7' => :IpmDraftsEntryId,
|
238
|
+
'36D8' => :AdditionalRenEntryIds,
|
239
|
+
'36D9' => :AdditionalRenEntryIdsEx,
|
240
|
+
'36DA' => :ExtendedFolderFlags,
|
241
|
+
'36E2' => :OrdinalMost,
|
242
|
+
'36E4' => :FreeBusyEntryIds,
|
243
|
+
'36E5' => :DefaultPostMessageClass,
|
244
|
+
'3701' => :AttachDataObject,
|
245
|
+
# '3701' => :AttachDataBinary,
|
246
|
+
'3702' => :AttachEncoding,
|
247
|
+
'3703' => :AttachExtension,
|
248
|
+
'3704' => :AttachFilename,
|
249
|
+
'3705' => :AttachMethod,
|
250
|
+
'3707' => :AttachLongFilename,
|
251
|
+
'3708' => :AttachPathname,
|
252
|
+
'3709' => :AttachRendering,
|
253
|
+
'370A' => :AttachTag,
|
254
|
+
'370B' => :RenderingPosition,
|
255
|
+
'370C' => :AttachTransportName,
|
256
|
+
'370D' => :AttachLongPathname,
|
257
|
+
'370E' => :AttachMimeTag,
|
258
|
+
'370F' => :AttachAdditionalInformation,
|
259
|
+
'3711' => :AttachContentBase,
|
260
|
+
'3712' => :CID,
|
261
|
+
'3713' => :AttachContentLocation,
|
262
|
+
'3714' => :AttachFlags,
|
263
|
+
'3719' => :AttachPayloadProviderGuidString,
|
264
|
+
'371A' => :AttachPayloadClass,
|
265
|
+
'371B' => :TextAttachmentCharset,
|
266
|
+
'3900' => :DisplayType,
|
267
|
+
'3902' => :Templateid,
|
268
|
+
'3905' => :DisplayTypeEx,
|
269
|
+
'39FE' => :SmtpAddress,
|
270
|
+
'39FF' => :AddressBookDisplayNamePrintable,
|
271
|
+
'3A00' => :Account,
|
272
|
+
'3A02' => :CallbackTelephoneNumber,
|
273
|
+
'3A05' => :Generation,
|
274
|
+
'3A06' => :GivenName,
|
275
|
+
'3A07' => :GovernmentIdNumber,
|
276
|
+
'3A08' => :BusinessTelephoneNumber,
|
277
|
+
'3A09' => :HomeTelephoneNumber,
|
278
|
+
'3A0A' => :Initials,
|
279
|
+
'3A0B' => :Keyword,
|
280
|
+
'3A0C' => :Language,
|
281
|
+
'3A0D' => :Location,
|
282
|
+
'3A0F' => :MessageHandlingSystemCommonName,
|
283
|
+
'3A10' => :OrganizationalIdNumber,
|
284
|
+
'3A11' => :Surname,
|
285
|
+
'3A12' => :OriginalEntryId,
|
286
|
+
'3A15' => :PostalAddress,
|
287
|
+
'3A16' => :CompanyName,
|
288
|
+
'3A17' => :Title,
|
289
|
+
'3A18' => :DepartmentName,
|
290
|
+
'3A19' => :OfficeLocation,
|
291
|
+
'3A1A' => :PrimaryTelephoneNumber,
|
292
|
+
'3A1B' => :Business2TelephoneNumber,
|
293
|
+
# '3A1B' => :Business2TelephoneNumbers,
|
294
|
+
'3A1C' => :MobileTelephoneNumber,
|
295
|
+
'3A1D' => :RadioTelephoneNumber,
|
296
|
+
'3A1E' => :CarTelephoneNumber,
|
297
|
+
'3A1F' => :OtherTelephoneNumber,
|
298
|
+
'3A20' => :TransmittableDisplayName,
|
299
|
+
'3A21' => :PagerTelephoneNumber,
|
300
|
+
'3A22' => :UserCertificate,
|
301
|
+
'3A23' => :PrimaryFaxNumber,
|
302
|
+
'3A24' => :BusinessFaxNumber,
|
303
|
+
'3A25' => :HomeFaxNumber,
|
304
|
+
'3A26' => :Country,
|
305
|
+
'3A27' => :Locality,
|
306
|
+
'3A28' => :StateOrProvince,
|
307
|
+
'3A29' => :StreetAddress,
|
308
|
+
'3A2A' => :PostalCode,
|
309
|
+
'3A2B' => :PostOfficeBox,
|
310
|
+
'3A2C' => :TelexNumber,
|
311
|
+
'3A2D' => :IsdnNumber,
|
312
|
+
'3A2E' => :AssistantTelephoneNumber,
|
313
|
+
'3A2F' => :Home2TelephoneNumber,
|
314
|
+
# '3A2F' => :Home2TelephoneNumbers,
|
315
|
+
'3A30' => :Assistant,
|
316
|
+
'3A40' => :SendRichInfo,
|
317
|
+
'3A41' => :WeddingAnniversary,
|
318
|
+
'3A42' => :Birthday,
|
319
|
+
'3A43' => :Hobbies,
|
320
|
+
'3A44' => :MiddleName,
|
321
|
+
'3A45' => :DisplayNamePrefix,
|
322
|
+
'3A46' => :Profession,
|
323
|
+
'3A47' => :ReferredByName,
|
324
|
+
'3A48' => :SpouseName,
|
325
|
+
'3A49' => :ComputerNetworkName,
|
326
|
+
'3A4A' => :CustomerId,
|
327
|
+
'3A4B' => :TelecommunicationsDeviceForDeafTelephoneNumber,
|
328
|
+
'3A4C' => :FtpSite,
|
329
|
+
'3A4D' => :Gender,
|
330
|
+
'3A4E' => :ManagerName,
|
331
|
+
'3A4F' => :Nickname,
|
332
|
+
'3A50' => :PersonalHomePage,
|
333
|
+
'3A51' => :BusinessHomePage,
|
334
|
+
'3A57' => :CompanyMainTelephoneNumber,
|
335
|
+
'3A58' => :ChildrensNames,
|
336
|
+
'3A59' => :HomeAddressCity,
|
337
|
+
'3A5A' => :HomeAddressCountry,
|
338
|
+
'3A5B' => :HomeAddressPostalCode,
|
339
|
+
'3A5C' => :HomeAddressStateOrProvince,
|
340
|
+
'3A5D' => :HomeAddressStreet,
|
341
|
+
'3A5E' => :HomeAddressPostOfficeBox,
|
342
|
+
'3A5F' => :OtherAddressCity,
|
343
|
+
'3A60' => :OtherAddressCountry,
|
344
|
+
'3A61' => :OtherAddressPostalCode,
|
345
|
+
'3A62' => :OtherAddressStateOrProvince,
|
346
|
+
'3A63' => :OtherAddressStreet,
|
347
|
+
'3A64' => :OtherAddressPostOfficeBox,
|
348
|
+
'3A70' => :UserX509Certificate,
|
349
|
+
'3A71' => :SendInternetEncoding,
|
350
|
+
'3F08' => :InitialDetailsPane,
|
351
|
+
'3F20' => :TemporaryDefaultDocument,
|
352
|
+
'3FDE' => :InternetCodepage,
|
353
|
+
'3FDF' => :AutoResponseSuppress,
|
354
|
+
'3FE0' => :AccessControlListData,
|
355
|
+
'3FE3' => :DelegatedByRule,
|
356
|
+
'3FE7' => :ResolveMethod,
|
357
|
+
'3FEA' => :HasDeferredActionMessages,
|
358
|
+
'3FEB' => :DeferredSendNumber,
|
359
|
+
'3FEC' => :DeferredSendUnits,
|
360
|
+
'3FED' => :ExpiryNumber,
|
361
|
+
'3FEE' => :ExpiryUnits,
|
362
|
+
'3FEF' => :DeferredSendTime,
|
363
|
+
'3FF0' => :ConflictEntryId,
|
364
|
+
'3FF1' => :MessageLocaleId,
|
365
|
+
'3FF8' => :CreatorName,
|
366
|
+
'3FF9' => :CreatorEntryId,
|
367
|
+
'3FFA' => :LastModifierName,
|
368
|
+
'3FFB' => :LastModifierEntryId,
|
369
|
+
'3FFD' => :MessageCodepage,
|
370
|
+
'401A' => :SentRepresentingFlags,
|
371
|
+
'4029' => :ReadReceiptAddressType,
|
372
|
+
'402A' => :ReadReceiptEmailAddress,
|
373
|
+
'402B' => :ReadReceiptName,
|
374
|
+
'4076' => :ContentFilterSpamConfidenceLevel,
|
375
|
+
'4079' => :SenderIdStatus,
|
376
|
+
'4083' => :PurportedSenderDomain,
|
377
|
+
'5902' => :InternetMailOverrideFormat,
|
378
|
+
'5909' => :MessageEditorFormat,
|
379
|
+
'5D01' => :SenderSmtpAddress,
|
380
|
+
'5FDE' => :RecipientResourceState,
|
381
|
+
'5FDF' => :RecipientOrder,
|
382
|
+
'5FE1' => :RecipientProposed,
|
383
|
+
'5FE3' => :RecipientProposedStartTime,
|
384
|
+
'5FE4' => :RecipientProposedEndTime,
|
385
|
+
'5FF6' => :RecipientDisplayName,
|
386
|
+
'5FF7' => :RecipientEntryId,
|
387
|
+
'5FFB' => :RecipientTrackStatusTime,
|
388
|
+
'5FFD' => :RecipientFlags,
|
389
|
+
'5FFF' => :RecipientTrackStatus,
|
390
|
+
'6100' => :JunkIncludeContacts,
|
391
|
+
'6101' => :JunkThreshold,
|
392
|
+
'6102' => :JunkPermanentlyDelete,
|
393
|
+
'6103' => :JunkAddRecipientsToSafeSendersList,
|
394
|
+
'6107' => :JunkPhishingEnableLinks,
|
395
|
+
'64F0' => :MimeSkeleton,
|
396
|
+
'65C2' => :ReplyTemplateId,
|
397
|
+
'65E0' => :SourceKey,
|
398
|
+
'65E1' => :ParentSourceKey,
|
399
|
+
'65E2' => :ChangeKey,
|
400
|
+
'65E3' => :PredecessorChangeList,
|
401
|
+
'65E9' => :RuleMessageState,
|
402
|
+
'65EA' => :RuleMessageUserFlags,
|
403
|
+
'65EB' => :RuleMessageProvider,
|
404
|
+
'65EC' => :RuleMessageName,
|
405
|
+
'65ED' => :RuleMessageLevel,
|
406
|
+
'65EE' => :RuleMessageProviderData,
|
407
|
+
'65F3' => :RuleMessageSequence,
|
408
|
+
'6619' => :UserEntryId,
|
409
|
+
'661B' => :MailboxOwnerEntryId,
|
410
|
+
'661C' => :MailboxOwnerName,
|
411
|
+
'661D' => :OutOfOfficeState,
|
412
|
+
'6622' => :ScheduleFreeBusy,
|
413
|
+
'6639' => :Rights,
|
414
|
+
'663A' => :HasRules,
|
415
|
+
'663B' => :AddressBookEntryId,
|
416
|
+
'663E' => :HierarchyChangeNumber,
|
417
|
+
'6645' => :ClientActions,
|
418
|
+
'6646' => :DamOriginalEntryId,
|
419
|
+
'6647' => :DamBackPatched,
|
420
|
+
'6648' => :RuleError,
|
421
|
+
'6649' => :RuleActionType,
|
422
|
+
'664A' => :HasNamedProperties,
|
423
|
+
'6650' => :RuleActionNumber,
|
424
|
+
'6651' => :RuleFolderEntryId,
|
425
|
+
'666A' => :ProhibitReceiveQuota,
|
426
|
+
'666C' => :InConflict,
|
427
|
+
'666D' => :MaximumSubmitMessageSize,
|
428
|
+
'666E' => :ProhibitSendQuota,
|
429
|
+
'6671' => :MemberId,
|
430
|
+
'6672' => :MemberName,
|
431
|
+
'6673' => :MemberRights,
|
432
|
+
'6674' => :RuleId,
|
433
|
+
'6675' => :RuleIds,
|
434
|
+
'6676' => :RuleSequence,
|
435
|
+
'6677' => :RuleState,
|
436
|
+
'6678' => :RuleUserFlags,
|
437
|
+
'6679' => :RuleCondition,
|
438
|
+
'6680' => :RuleActions,
|
439
|
+
'6681' => :RuleProvider,
|
440
|
+
'6682' => :RuleName,
|
441
|
+
'6683' => :RuleLevel,
|
442
|
+
'6684' => :RuleProviderData,
|
443
|
+
'668F' => :DeletedOn,
|
444
|
+
'66A1' => :LocaleId,
|
445
|
+
'66B3' => :NormalMessageSize,
|
446
|
+
'66C3' => :CodePageId,
|
447
|
+
'6704' => :AddressBookManageDistributionList,
|
448
|
+
'6705' => :SortLocaleId,
|
449
|
+
'6707' => :UrlName,
|
450
|
+
'6708' => :Subfolder,
|
451
|
+
'6709' => :LocalCommitTime,
|
452
|
+
'670A' => :LocalCommitTimeMax,
|
453
|
+
'670B' => :DeletedCountTotal,
|
454
|
+
'670E' => :FlatUrlName,
|
455
|
+
'671C' => :PublicFolderAdministrativeDescription,
|
456
|
+
'671D' => :PublicFolderProxy,
|
457
|
+
'6740' => :SentMailSvrEID,
|
458
|
+
'6741' => :DeferredActionMessageOriginalEntryId,
|
459
|
+
'6748' => :FolderId,
|
460
|
+
'6749' => :ParentFolderId,
|
461
|
+
'674A' => :Mid,
|
462
|
+
'674D' => :InstID,
|
463
|
+
'674E' => :InstanceNum,
|
464
|
+
'674F' => :AddressBookMessageId,
|
465
|
+
'67A4' => :ChangeNumber,
|
466
|
+
'67AA' => :Associated,
|
467
|
+
'6800' => :OfflineAddressBookName,
|
468
|
+
'6801' => :OfflineAddressBookSequence,
|
469
|
+
# '6801' => :VoiceMessageDuration,
|
470
|
+
'6802' => :OfflineAddressBookContainerGuid,
|
471
|
+
# '6802' => :SenderTelephoneNumber,
|
472
|
+
# '6802' => :RwRulesStream,
|
473
|
+
'6803' => :OfflineAddressBookMessageClass,
|
474
|
+
# '6803' => :VoiceMessageSenderName,
|
475
|
+
'6804' => :FaxNumberOfPages,
|
476
|
+
# '6804' => :OfflineAddressBookDistinguishedName,
|
477
|
+
'6805' => :VoiceMessageAttachmentOrder,
|
478
|
+
# '6805' => :OfflineAddressBookTruncatedProperties,
|
479
|
+
'6806' => :CallId,
|
480
|
+
'6834' => :SearchFolderLastUsed,
|
481
|
+
'683A' => :SearchFolderExpiration,
|
482
|
+
'6841' => :ScheduleInfoResourceType,
|
483
|
+
# '6841' => :SearchFolderTemplateId,
|
484
|
+
'6842' => :ScheduleInfoDelegatorWantsCopy,
|
485
|
+
# '6842' => :SearchFolderId,
|
486
|
+
# '6842' => :WlinkGroupHeaderID,
|
487
|
+
'6843' => :ScheduleInfoDontMailDelegates,
|
488
|
+
'6844' => :SearchFolderRecreateInfo,
|
489
|
+
# '6844' => :ScheduleInfoDelegateNames,
|
490
|
+
'6845' => :SearchFolderDefinition,
|
491
|
+
# '6845' => :ScheduleInfoDelegateEntryIds,
|
492
|
+
'6846' => :SearchFolderStorageType,
|
493
|
+
# '6846' => :GatewayNeedsToRefresh,
|
494
|
+
'6847' => :FreeBusyPublishStart,
|
495
|
+
# '6847' => :SearchFolderTag,
|
496
|
+
# '6847' => :WlinkSaveStamp,
|
497
|
+
'6848' => :FreeBusyPublishEnd,
|
498
|
+
# '6848' => :SearchFolderEfpFlags,
|
499
|
+
'6849' => :WlinkType,
|
500
|
+
# '6849' => :FreeBusyMessageEmailAddress,
|
501
|
+
'684A' => :WlinkFlags,
|
502
|
+
# '684A' => :ScheduleInfoDelegateNamesW,
|
503
|
+
'684B' => :ScheduleInfoDelegatorWantsInfo,
|
504
|
+
# '684B' => :WlinkOrdinal,
|
505
|
+
'684C' => :WlinkEntryId,
|
506
|
+
'684D' => :WlinkRecordKey,
|
507
|
+
'684E' => :WlinkStoreEntryId,
|
508
|
+
'684F' => :WlinkFolderType,
|
509
|
+
# '684F' => :ScheduleInfoMonthsMerged,
|
510
|
+
'6850' => :WlinkGroupClsid,
|
511
|
+
# '6850' => :ScheduleInfoFreeBusyMerged,
|
512
|
+
'6851' => :WlinkGroupName,
|
513
|
+
# '6851' => :ScheduleInfoMonthsTentative,
|
514
|
+
'6852' => :WlinkSection,
|
515
|
+
# '6852' => :ScheduleInfoFreeBusyTentative,
|
516
|
+
'6853' => :WlinkCalendarColor,
|
517
|
+
# '6853' => :ScheduleInfoMonthsBusy,
|
518
|
+
'6854' => :WlinkAddressBookEID,
|
519
|
+
# '6854' => :ScheduleInfoFreeBusyBusy,
|
520
|
+
'6855' => :ScheduleInfoMonthsAway,
|
521
|
+
'6856' => :ScheduleInfoFreeBusyAway,
|
522
|
+
'6868' => :FreeBusyRangeTimestamp,
|
523
|
+
'6869' => :FreeBusyCountMonths,
|
524
|
+
'686A' => :ScheduleInfoAppointmentTombstone,
|
525
|
+
'686B' => :DelegateFlags,
|
526
|
+
'686C' => :ScheduleInfoFreeBusy,
|
527
|
+
'686D' => :ScheduleInfoAutoAcceptAppointments,
|
528
|
+
'686F' => :ScheduleInfoDisallowOverlappingAppts,
|
529
|
+
'6890' => :WlinkClientID,
|
530
|
+
'6891' => :WlinkAddressBookStoreEID,
|
531
|
+
'6892' => :WlinkROGroupType,
|
532
|
+
'7001' => :ViewDescriptorBinary,
|
533
|
+
'7002' => :ViewDescriptorStrings,
|
534
|
+
'7006' => :ViewDescriptorName,
|
535
|
+
'7007' => :ViewDescriptorVersion,
|
536
|
+
'7C06' => :RoamingDatatypes,
|
537
|
+
'7C07' => :RoamingDictionary,
|
538
|
+
'7C08' => :RoamingXmlStream,
|
539
|
+
'7C24' => :OscSyncEnabled,
|
540
|
+
'7D01' => :Processed,
|
541
|
+
'7FF9' => :ExceptionReplaceTime,
|
542
|
+
'7FFA' => :AttachmentLinkId,
|
543
|
+
'7FFB' => :ExceptionStartTime,
|
544
|
+
'7FFC' => :ExceptionEndTime,
|
545
|
+
'7FFD' => :AttachmentFlags,
|
546
|
+
'7FFE' => :AttachmentHidden,
|
547
|
+
'7FFF' => :AttachmentContactPhoto,
|
548
|
+
'8004' => :AddressBookFolderPathname,
|
549
|
+
'8005' => :AddressBookManager,
|
550
|
+
# '8005' => :AddressBookManagerDistinguishedName,
|
551
|
+
'8006' => :AddressBookHomeMessageDatabase,
|
552
|
+
'8008' => :AddressBookIsMemberOfDistributionList,
|
553
|
+
'8009' => :AddressBookMember,
|
554
|
+
'800C' => :AddressBookOwner,
|
555
|
+
'800E' => :AddressBookReports,
|
556
|
+
'800F' => :AddressBookProxyAddresses,
|
557
|
+
'8011' => :AddressBookTargetAddress,
|
558
|
+
'8015' => :AddressBookPublicDelegates,
|
559
|
+
'8024' => :AddressBookOwnerBackLink,
|
560
|
+
'802D' => :AddressBookExtensionAttribute1,
|
561
|
+
'802E' => :AddressBookExtensionAttribute2,
|
562
|
+
'802F' => :AddressBookExtensionAttribute3,
|
563
|
+
'8030' => :AddressBookExtensionAttribute4,
|
564
|
+
'8031' => :AddressBookExtensionAttribute5,
|
565
|
+
'8032' => :AddressBookExtensionAttribute6,
|
566
|
+
'8033' => :AddressBookExtensionAttribute7,
|
567
|
+
'8034' => :AddressBookExtensionAttribute8,
|
568
|
+
'8035' => :AddressBookExtensionAttribute9,
|
569
|
+
'8036' => :AddressBookExtensionAttribute10,
|
570
|
+
'803C' => :AddressBookObjectDistinguishedName,
|
571
|
+
'806A' => :AddressBookDeliveryContentLength,
|
572
|
+
'8073' => :AddressBookDistributionListMemberSubmitAccepted,
|
573
|
+
'8170' => :AddressBookNetworkAddress,
|
574
|
+
'8C57' => :AddressBookExtensionAttribute11,
|
575
|
+
'8C58' => :AddressBookExtensionAttribute12,
|
576
|
+
'8C59' => :AddressBookExtensionAttribute13,
|
577
|
+
'8C60' => :AddressBookExtensionAttribute14,
|
578
|
+
'8C61' => :AddressBookExtensionAttribute15,
|
579
|
+
'8C6A' => :AddressBookX509Certificate,
|
580
|
+
'8C6D' => :AddressBookObjectGuid,
|
581
|
+
'8C8E' => :AddressBookPhoneticGivenName,
|
582
|
+
'8C8F' => :AddressBookPhoneticSurname,
|
583
|
+
'8C90' => :AddressBookPhoneticDepartmentName,
|
584
|
+
'8C91' => :AddressBookPhoneticCompanyName,
|
585
|
+
'8C92' => :AddressBookPhoneticDisplayName,
|
586
|
+
'8C93' => :AddressBookDisplayTypeExtended,
|
587
|
+
'8C94' => :AddressBookHierarchicalShowInDepartments,
|
588
|
+
'8C96' => :AddressBookRoomContainers,
|
589
|
+
'8C97' => :AddressBookHierarchicalDepartmentMembers,
|
590
|
+
'8C98' => :AddressBookHierarchicalRootDepartment,
|
591
|
+
'8C99' => :AddressBookHierarchicalParentDepartment,
|
592
|
+
'8C9A' => :AddressBookHierarchicalChildDepartments,
|
593
|
+
'8C9E' => :ThumbnailPhoto,
|
594
|
+
'8CA0' => :AddressBookSeniorityIndex,
|
595
|
+
'8CA8' => :AddressBookOrganizationalUnitRootDistinguishedName,
|
596
|
+
'8CAC' => :AddressBookSenderHintTranslations,
|
597
|
+
'8CB5' => :AddressBookModerationEnabled,
|
598
|
+
'8CC2' => :SpokenName,
|
599
|
+
'8CD8' => :AddressBookAuthorizedSenders,
|
600
|
+
'8CD9' => :AddressBookUnauthorizedSenders,
|
601
|
+
'8CDA' => :AddressBookDistributionListMemberSubmitRejected,
|
602
|
+
'8CDB' => :AddressBookDistributionListRejectMessagesFromDLMembers,
|
603
|
+
'8CDD' => :AddressBookHierarchicalIsHierarchicalGroup,
|
604
|
+
'8CE2' => :AddressBookDistributionListMemberCount,
|
605
|
+
'8CE3' => :AddressBookDistributionListExternalMemberCount,
|
606
|
+
'FFFB' => :AddressBookIsMaster,
|
607
|
+
'FFFC' => :AddressBookParentEntryId,
|
608
|
+
'FFFD' => :AddressBookContainerId,
|
609
|
+
}
|
610
|
+
|
611
|
+
class OfflineAddressBook
|
612
|
+
class Parser
|
613
|
+
def initialize(oab)
|
614
|
+
@oab = open(oab)
|
615
|
+
@header = _header
|
616
|
+
end
|
617
|
+
|
618
|
+
def pos
|
619
|
+
return sprintf('%08o', @oab.pos)
|
620
|
+
end
|
621
|
+
def typeof(type)
|
622
|
+
return MapiPropertyDataType[type.to_s.to_sym]
|
623
|
+
end
|
624
|
+
|
625
|
+
attr_reader :serialNumber, :totalRecords, :header
|
626
|
+
|
627
|
+
def _uint32
|
628
|
+
return @oab.read(4).unpack('V*')[0]
|
629
|
+
end
|
630
|
+
def _ubyte
|
631
|
+
return @oab.read(1).unpack('C*')[0]
|
632
|
+
end
|
633
|
+
|
634
|
+
def _integer
|
635
|
+
firstByte = _ubyte
|
636
|
+
|
637
|
+
return firstByte if firstByte < 0x80
|
638
|
+
|
639
|
+
case firstByte
|
640
|
+
when 0x81 then return _ubyte
|
641
|
+
when 0x82 then return _ubyte + (_ubyte << 8)
|
642
|
+
when 0x83 then return _ubyte + (_ubyte << 8) + (_ubyte << 16)
|
643
|
+
when 0x84 then return _ubyte + (_ubyte << 8) + (_ubyte << 16) + (_ubyte << 24)
|
644
|
+
end
|
645
|
+
raise "Unexpected first byte #{sprintf('%x', firstByte)} of integer"
|
646
|
+
end
|
647
|
+
|
648
|
+
def _propertyTypes
|
649
|
+
n = _uint32
|
650
|
+
return 1.upto(n).collect{|i|
|
651
|
+
prop = OpenStruct.new
|
652
|
+
prop.pos = pos
|
653
|
+
|
654
|
+
id = _uint32
|
655
|
+
prop._id = id.to_s(16)
|
656
|
+
prop.id = sprintf('%04x', id >> 16).upcase
|
657
|
+
prop.name = MapiPropertyName[prop.id]
|
658
|
+
throw prop.id unless prop.name && prop.name != ''
|
659
|
+
type = id & 0xffff
|
660
|
+
prop.type = typeof(type & ~MapiPropertyDataType.Mv)
|
661
|
+
prop._type = sprintf('%04x', (type & ~MapiPropertyDataType.Mv))
|
662
|
+
prop.array = ((type & MapiPropertyDataType.Mv) != 0)
|
663
|
+
prop.flags = _uint32
|
664
|
+
prop
|
665
|
+
}
|
666
|
+
end
|
667
|
+
|
668
|
+
def _header
|
669
|
+
# Read OAB_HDR
|
670
|
+
version = _uint32
|
671
|
+
raise "Version not found, got #{version.inspect}" unless version == 0x20 # version
|
672
|
+
@serialNumber = _uint32
|
673
|
+
@totalRecords = _uint32
|
674
|
+
# Read OAB_META_DATA
|
675
|
+
metadataSize = _uint32
|
676
|
+
|
677
|
+
@headerProperties = _propertyTypes
|
678
|
+
@oabProperties = _propertyTypes
|
679
|
+
return _record(true)
|
680
|
+
end
|
681
|
+
|
682
|
+
def _property(prop)
|
683
|
+
if prop.array
|
684
|
+
valueCount = _integer
|
685
|
+
value = []
|
686
|
+
valueCount.times{
|
687
|
+
value << _scalar(prop.type)
|
688
|
+
}
|
689
|
+
else
|
690
|
+
value = _scalar(prop.type)
|
691
|
+
end
|
692
|
+
p = OpenStruct.new(type: prop.type, id: prop.id, name: prop.name, value: value)
|
693
|
+
return p
|
694
|
+
end
|
695
|
+
|
696
|
+
def _scalar(type)
|
697
|
+
case type
|
698
|
+
when :Long then return _integer
|
699
|
+
when :Boolean then return (_ubyte > 0)
|
700
|
+
when :Binary then return @oab.read(_integer)
|
701
|
+
when :AnsiString, :UnicodeString
|
702
|
+
string = ''
|
703
|
+
while (byte = @oab.read(1)) != "\x00"
|
704
|
+
string << byte
|
705
|
+
end
|
706
|
+
# TODO: string.force_encoding(MapiPropertyDataType.UnicodeString ? 'UTF-8' : 'ASCII')
|
707
|
+
string.force_encoding(type == :UnicodeString ? 'UTF-8' : 'ASCII')
|
708
|
+
return string
|
709
|
+
end
|
710
|
+
raise "Unknown scalar type #{type}"
|
711
|
+
end
|
712
|
+
|
713
|
+
def _record(headerRecord = false)
|
714
|
+
initialPosition = @oab.pos
|
715
|
+
recordSize = 0
|
716
|
+
record = OpenStruct.new
|
717
|
+
begin
|
718
|
+
properties = headerRecord ? @headerProperties : @oabProperties
|
719
|
+
recordSize = _uint32
|
720
|
+
recordPresence = @oab.read((properties.length + 7) / 8).unpack("b*").join.split('').collect{|bit| bit.to_i != 0 }
|
721
|
+
properties.each_with_index{|prop, i|
|
722
|
+
next unless recordPresence[i + 7 - 2 * (i % 8)]
|
723
|
+
p = _property(prop)
|
724
|
+
pn = p.name.to_s
|
725
|
+
record[pn] ||= []
|
726
|
+
record[pn] << p.value
|
727
|
+
}
|
728
|
+
ensure
|
729
|
+
@oab.pos = initialPosition + recordSize
|
730
|
+
end
|
731
|
+
return record
|
732
|
+
end
|
733
|
+
|
734
|
+
def records
|
735
|
+
@records = Enumerator.new(@totalRecords) do |y|
|
736
|
+
@totalRecords.times { y.yield _record }
|
737
|
+
end
|
738
|
+
return @records
|
739
|
+
end
|
740
|
+
end
|
741
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'dotenv/load'
|
2
|
+
|
3
|
+
require 'minitest/autorun'
|
4
|
+
require 'exchange-offline-address-book'
|
5
|
+
|
6
|
+
class EOABTest < Minitest::Test
|
7
|
+
def test_downlod
|
8
|
+
oab = OfflineAddressBook.new(username: ENV['USERNAME'], password: ENV['PASSWORD'], email: ENV['EMAIL'])
|
9
|
+
puts oab.addressbook
|
10
|
+
end
|
11
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: exchange-offline-address-book
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Emiliano Heyns
|
@@ -25,75 +25,117 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.3'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: dotenv
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
34
|
-
type: :
|
33
|
+
version: '2'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '5'
|
48
|
+
type: :development
|
35
49
|
prerelease: false
|
36
50
|
version_requirements: !ruby/object:Gem::Requirement
|
37
51
|
requirements:
|
38
|
-
- - "
|
52
|
+
- - "~>"
|
39
53
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
54
|
+
version: '5'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
56
|
+
name: gem-release
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
44
58
|
requirements:
|
45
|
-
- - "
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
46
67
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
68
|
+
version: '1'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: bump
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0.5'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0.5'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: nokogiri
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '1.8'
|
48
90
|
type: :runtime
|
49
91
|
prerelease: false
|
50
92
|
version_requirements: !ruby/object:Gem::Requirement
|
51
93
|
requirements:
|
52
|
-
- - "
|
94
|
+
- - "~>"
|
53
95
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
96
|
+
version: '1.8'
|
55
97
|
- !ruby/object:Gem::Dependency
|
56
98
|
name: autodiscover
|
57
99
|
requirement: !ruby/object:Gem::Requirement
|
58
100
|
requirements:
|
59
|
-
- - "
|
101
|
+
- - "~>"
|
60
102
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
103
|
+
version: '1'
|
62
104
|
type: :runtime
|
63
105
|
prerelease: false
|
64
106
|
version_requirements: !ruby/object:Gem::Requirement
|
65
107
|
requirements:
|
66
|
-
- - "
|
108
|
+
- - "~>"
|
67
109
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
110
|
+
version: '1'
|
69
111
|
- !ruby/object:Gem::Dependency
|
70
112
|
name: libmspack
|
71
113
|
requirement: !ruby/object:Gem::Requirement
|
72
114
|
requirements:
|
73
|
-
- - "
|
115
|
+
- - "~>"
|
74
116
|
- !ruby/object:Gem::Version
|
75
|
-
version: '0'
|
117
|
+
version: '0.1'
|
76
118
|
type: :runtime
|
77
119
|
prerelease: false
|
78
120
|
version_requirements: !ruby/object:Gem::Requirement
|
79
121
|
requirements:
|
80
|
-
- - "
|
122
|
+
- - "~>"
|
81
123
|
- !ruby/object:Gem::Version
|
82
|
-
version: '0'
|
124
|
+
version: '0.1'
|
83
125
|
- !ruby/object:Gem::Dependency
|
84
126
|
name: curb
|
85
127
|
requirement: !ruby/object:Gem::Requirement
|
86
128
|
requirements:
|
87
|
-
- - "
|
129
|
+
- - "~>"
|
88
130
|
- !ruby/object:Gem::Version
|
89
|
-
version: '0'
|
131
|
+
version: '0.9'
|
90
132
|
type: :runtime
|
91
133
|
prerelease: false
|
92
134
|
version_requirements: !ruby/object:Gem::Requirement
|
93
135
|
requirements:
|
94
|
-
- - "
|
136
|
+
- - "~>"
|
95
137
|
- !ruby/object:Gem::Version
|
96
|
-
version: '0'
|
138
|
+
version: '0.9'
|
97
139
|
description: Get Exchange Offline Address Book
|
98
140
|
email:
|
99
141
|
- Emiliano.Heyns@iris-advies.com
|
@@ -101,7 +143,17 @@ executables: []
|
|
101
143
|
extensions: []
|
102
144
|
extra_rdoc_files: []
|
103
145
|
files:
|
146
|
+
- ".gitignore"
|
147
|
+
- Gemfile
|
148
|
+
- Gemfile.lock
|
104
149
|
- README.md
|
150
|
+
- Rakefile
|
151
|
+
- exchange-offline-address-book.gemspec
|
152
|
+
- lib/exchange-offline-address-book.rb
|
153
|
+
- lib/exchange-offline-address-book/mspack.rb
|
154
|
+
- lib/exchange-offline-address-book/parser.rb
|
155
|
+
- lib/exchange-offline-address-book/version.rb
|
156
|
+
- test/test_exchange-offline-address-book.rb
|
105
157
|
homepage: http://github.io
|
106
158
|
licenses:
|
107
159
|
- MIT
|
@@ -126,4 +178,5 @@ rubygems_version: 2.6.12
|
|
126
178
|
signing_key:
|
127
179
|
specification_version: 4
|
128
180
|
summary: Get Exchange Offline Address Book
|
129
|
-
test_files:
|
181
|
+
test_files:
|
182
|
+
- test/test_exchange-offline-address-book.rb
|