exchange-offline-address-book 0.0.1 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 55f6145921765406c06e60039b1e9a8ca0a22649
4
- data.tar.gz: 7c33e19b2ac23809b6790a053d38f7e981e797c1
3
+ metadata.gz: 36482b6cf832cab6b56979b4f9632c010b3fa645
4
+ data.tar.gz: ca6a463ea3983aa043505fbbc842ebf0f2b9174b
5
5
  SHA512:
6
- metadata.gz: c129660484fa8e0ec44b1d1d1099661e9c9ad10119f696040969c4b163e7b7c8005f299964fadfb5816466b52ce79bb029aa6e1e90906fbce439609ea74496aa
7
- data.tar.gz: 1f96026d119a43e392f9332dd3aeb31dcf00a35d0683505585507502647a95a7ffb65aa2c6f93983584b06eb5cfcdba1150c1d136a3fb453b330056b446b4ad5
6
+ metadata.gz: 3950eaaeaabcb130cfc2c632d242937279c52e42b735cd493e4d4df4e8cf0db8370e368f3ac2fb8541439f4d64ad5353f471735439f62c3d01f86aebfbad1f7f
7
+ data.tar.gz: 4a47c4aec5d94119ae97364103d0d515fd6c382145448c57c6d5b817c92568de7a9bc0f6800cc1302c045d2456bbe5caa5fc89fa767f8fdad3e97d139a20e9f9
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ .env
2
+ *.gem
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ #ruby=2.3
2
+ #ruby-gemset=oab
3
+
4
+ source 'https://rubygems.org'
5
+
6
+ # Specify your gem's dependencies in gemspec
7
+ gemspec
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,13 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rake/testtask'
4
+ require 'bump/tasks'
5
+ #Bump.tag_by_default = true
6
+
7
+ Rake::TestTask.new do |t|
8
+ t.libs << 'test'
9
+ end
10
+
11
+ desc 'Run tests'
12
+ task :default => :test
13
+
@@ -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,3 @@
1
+ class OfflineAddressBook
2
+ VERSION = '0.0.5'
3
+ 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.1
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: nokogiri
28
+ name: dotenv
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ">="
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
34
- type: :runtime
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: '0'
54
+ version: '5'
41
55
  - !ruby/object:Gem::Dependency
42
- name: logging
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: '0'
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: '0'
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: '0'
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: '0'
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