viewpoint2 1.3.0

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.
Files changed (88) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +216 -0
  3. data/lib/ews/calendar_accessors.rb +34 -0
  4. data/lib/ews/connection.rb +130 -0
  5. data/lib/ews/connection_helper.rb +35 -0
  6. data/lib/ews/convert_accessors.rb +56 -0
  7. data/lib/ews/errors.rb +56 -0
  8. data/lib/ews/ews_client.rb +103 -0
  9. data/lib/ews/exceptions/exceptions.rb +61 -0
  10. data/lib/ews/folder_accessors.rb +264 -0
  11. data/lib/ews/impersonation.rb +30 -0
  12. data/lib/ews/item_accessors.rb +231 -0
  13. data/lib/ews/mailbox_accessors.rb +99 -0
  14. data/lib/ews/message_accessors.rb +93 -0
  15. data/lib/ews/push_subscription_accessors.rb +33 -0
  16. data/lib/ews/room_accessors.rb +48 -0
  17. data/lib/ews/roomlist_accessors.rb +47 -0
  18. data/lib/ews/soap.rb +64 -0
  19. data/lib/ews/soap/builders/ews_builder.rb +1351 -0
  20. data/lib/ews/soap/ews_response.rb +84 -0
  21. data/lib/ews/soap/ews_soap_availability_response.rb +58 -0
  22. data/lib/ews/soap/ews_soap_free_busy_response.rb +119 -0
  23. data/lib/ews/soap/ews_soap_response.rb +103 -0
  24. data/lib/ews/soap/ews_soap_room_response.rb +53 -0
  25. data/lib/ews/soap/ews_soap_roomlist_response.rb +54 -0
  26. data/lib/ews/soap/exchange_availability.rb +61 -0
  27. data/lib/ews/soap/exchange_data_services.rb +780 -0
  28. data/lib/ews/soap/exchange_notification.rb +146 -0
  29. data/lib/ews/soap/exchange_synchronization.rb +93 -0
  30. data/lib/ews/soap/exchange_time_zones.rb +56 -0
  31. data/lib/ews/soap/exchange_user_configuration.rb +33 -0
  32. data/lib/ews/soap/exchange_web_service.rb +264 -0
  33. data/lib/ews/soap/parsers/ews_parser.rb +43 -0
  34. data/lib/ews/soap/parsers/ews_sax_document.rb +70 -0
  35. data/lib/ews/soap/response_message.rb +80 -0
  36. data/lib/ews/soap/responses/create_attachment_response_message.rb +47 -0
  37. data/lib/ews/soap/responses/create_item_response_message.rb +25 -0
  38. data/lib/ews/soap/responses/find_item_response_message.rb +80 -0
  39. data/lib/ews/soap/responses/get_events_response_message.rb +53 -0
  40. data/lib/ews/soap/responses/send_notification_response_message.rb +59 -0
  41. data/lib/ews/soap/responses/subscribe_response_message.rb +35 -0
  42. data/lib/ews/soap/responses/sync_folder_hierarchy_response_message.rb +36 -0
  43. data/lib/ews/soap/responses/sync_folder_items_response_message.rb +36 -0
  44. data/lib/ews/templates/calendar_item.rb +79 -0
  45. data/lib/ews/templates/forward_item.rb +24 -0
  46. data/lib/ews/templates/message.rb +76 -0
  47. data/lib/ews/templates/reply_to_item.rb +25 -0
  48. data/lib/ews/templates/task.rb +74 -0
  49. data/lib/ews/types.rb +194 -0
  50. data/lib/ews/types/attachment.rb +77 -0
  51. data/lib/ews/types/attendee.rb +41 -0
  52. data/lib/ews/types/calendar_folder.rb +50 -0
  53. data/lib/ews/types/calendar_item.rb +133 -0
  54. data/lib/ews/types/contact.rb +7 -0
  55. data/lib/ews/types/contacts_folder.rb +8 -0
  56. data/lib/ews/types/copied_event.rb +51 -0
  57. data/lib/ews/types/created_event.rb +24 -0
  58. data/lib/ews/types/deleted_event.rb +24 -0
  59. data/lib/ews/types/distribution_list.rb +7 -0
  60. data/lib/ews/types/event.rb +62 -0
  61. data/lib/ews/types/export_items_response_message.rb +52 -0
  62. data/lib/ews/types/file_attachment.rb +65 -0
  63. data/lib/ews/types/folder.rb +60 -0
  64. data/lib/ews/types/free_busy_changed_event.rb +24 -0
  65. data/lib/ews/types/generic_folder.rb +418 -0
  66. data/lib/ews/types/item.rb +450 -0
  67. data/lib/ews/types/item_attachment.rb +84 -0
  68. data/lib/ews/types/item_field_uri_map.rb +208 -0
  69. data/lib/ews/types/mailbox_user.rb +156 -0
  70. data/lib/ews/types/meeting_cancellation.rb +7 -0
  71. data/lib/ews/types/meeting_message.rb +7 -0
  72. data/lib/ews/types/meeting_request.rb +7 -0
  73. data/lib/ews/types/meeting_response.rb +7 -0
  74. data/lib/ews/types/message.rb +7 -0
  75. data/lib/ews/types/modified_event.rb +48 -0
  76. data/lib/ews/types/moved_event.rb +51 -0
  77. data/lib/ews/types/new_mail_event.rb +24 -0
  78. data/lib/ews/types/out_of_office.rb +147 -0
  79. data/lib/ews/types/post_item.rb +7 -0
  80. data/lib/ews/types/search_folder.rb +8 -0
  81. data/lib/ews/types/status_event.rb +39 -0
  82. data/lib/ews/types/task.rb +104 -0
  83. data/lib/ews/types/tasks_folder.rb +27 -0
  84. data/lib/viewpoint/logging.rb +27 -0
  85. data/lib/viewpoint/logging/config.rb +24 -0
  86. data/lib/viewpoint/string_utils.rb +76 -0
  87. data/lib/viewpoint2.rb +111 -0
  88. metadata +191 -0
@@ -0,0 +1,450 @@
1
+ module Viewpoint::EWS::Types
2
+ module Item
3
+ include Viewpoint::EWS
4
+ include Viewpoint::EWS::Types
5
+ include ItemFieldUriMap
6
+
7
+ def self.included(klass)
8
+ klass.extend ClassMethods
9
+ end
10
+
11
+ module ClassMethods
12
+ def init_simple_item(ews, id, change_key = nil, parent = nil)
13
+ ews_item = {item_id: {attribs: {id: id, change_key: change_key}}}
14
+ self.new ews, ews_item, parent
15
+ end
16
+ end
17
+
18
+ ITEM_KEY_PATHS = {
19
+ item_id: [:item_id, :attribs],
20
+ id: [:item_id, :attribs, :id],
21
+ change_key: [:item_id, :attribs, :change_key],
22
+ subject: [:subject, :text],
23
+ sensitivity: [:sensitivity, :text],
24
+ size: [:size, :text],
25
+ date_time_sent: [:date_time_sent, :text],
26
+ date_time_created: [:date_time_created, :text],
27
+ last_modified_time: [:last_modified_time, :text],
28
+ mime_content: [:mime_content, :text],
29
+ has_attachments?:[:has_attachments, :text],
30
+ is_associated?: [:is_associated, :text],
31
+ is_read?: [:is_read, :text],
32
+ is_draft?: [:is_draft, :text],
33
+ is_submitted?: [:is_submitted, :text],
34
+ conversation_id:[:conversation_id, :attribs, :id],
35
+ categories: [:categories, :elems],
36
+ internet_message_id:[:internet_message_id, :text],
37
+ internet_message_headers:[:internet_message_headers, :elems],
38
+ sender: [:sender, :elems, 0, :mailbox, :elems],
39
+ from: [:from, :elems, 0, :mailbox, :elems],
40
+ to_recipients: [:to_recipients, :elems],
41
+ cc_recipients: [:cc_recipients, :elems],
42
+ attachments: [:attachments, :elems],
43
+ importance: [:importance, :text],
44
+ conversation_index: [:conversation_index, :text],
45
+ conversation_topic: [:conversation_topic, :text],
46
+ body_type: [:body, :attribs, :body_type],
47
+ body: [:body, :text]
48
+ }
49
+
50
+ ITEM_KEY_TYPES = {
51
+ size: ->(str){str.to_i},
52
+ date_time_sent: ->(str){DateTime.parse(str)},
53
+ date_time_created: ->(str){DateTime.parse(str)},
54
+ last_modified_time: ->(str){DateTime.parse(str)},
55
+ has_attachments?: ->(str){str.downcase == 'true'},
56
+ is_associated?: ->(str){str.downcase == 'true'},
57
+ is_read?: ->(str){str.downcase == 'true'},
58
+ is_draft?: ->(str){str.downcase == 'true'},
59
+ is_submitted?: ->(str){str.downcase == 'true'},
60
+ categories: ->(obj){obj.collect{|s| s[:string][:text]}},
61
+ internet_message_headers: ->(obj){obj.collect{|h|
62
+ {h[:internet_message_header][:attribs][:header_name] =>
63
+ h[:internet_message_header][:text]} } },
64
+ sender: :build_mailbox_user,
65
+ from: :build_mailbox_user,
66
+ to_recipients: :build_mailbox_users,
67
+ cc_recipients: :build_mailbox_users,
68
+ attachments: :build_attachments,
69
+ }
70
+
71
+ ITEM_KEY_ALIAS = {
72
+ :read? => :is_read?,
73
+ :draft? => :is_draft?,
74
+ :submitted? => :is_submitted?,
75
+ :associated? => :is_associated?,
76
+ }
77
+
78
+ attr_reader :ews_item, :parent
79
+
80
+ # @param ews [SOAP::ExchangeWebService] the EWS reference
81
+ # @param ews_item [Hash] the EWS parsed response document
82
+ # @param parent [GenericFolder] an optional parent object
83
+ def initialize(ews, ews_item, parent = nil)
84
+ super(ews, ews_item)
85
+ @parent = parent
86
+ @body_type = false
87
+ simplify!
88
+ @new_file_attachments = []
89
+ @new_item_attachments = []
90
+ @new_inline_attachments = []
91
+ end
92
+
93
+ # Specify a body_type to fetch this item with if it hasn't already been fetched.
94
+ # @param body_type [String, Symbol, FalseClass] must be :best, :text, or
95
+ # :html. You can also set it to false to make it use the default.
96
+ def default_body_type=(body_type)
97
+ @body_type = body_type
98
+ end
99
+
100
+ def delete!(deltype = :hard, opts = {})
101
+ opts = {
102
+ :delete_type => delete_type(deltype),
103
+ :item_ids => [{:item_id => {:id => id}}]
104
+ }.merge(opts)
105
+
106
+ resp = @ews.delete_item(opts)
107
+ rmsg = resp.response_messages[0]
108
+ unless rmsg.success?
109
+ raise EwsError, "Could not delete #{self.class}. #{rmsg.response_code}: #{rmsg.message_text}"
110
+ end
111
+ true
112
+ end
113
+
114
+ def recycle!
115
+ delete! :recycle
116
+ end
117
+
118
+ def get_all_properties!
119
+ @ews_item = get_item(base_shape: 'AllProperties')
120
+ simplify!
121
+ end
122
+
123
+ # Mark an item as read
124
+ def mark_read!
125
+ update_is_read_status true
126
+ end
127
+
128
+ # Mark an item as unread
129
+ def mark_unread!
130
+ update_is_read_status false
131
+ end
132
+
133
+ # Move this item to a new folder
134
+ # @param [String,Symbol,GenericFolder] new_folder The new folder to move it to. This should
135
+ # be a subclass of GenericFolder, a DistinguishedFolderId (must me a Symbol) or a FolderId (String)
136
+ # @return [String] the new Id of the moved item
137
+ def move!(new_folder)
138
+ new_folder = new_folder.id if new_folder.kind_of?(GenericFolder)
139
+ move_opts = {
140
+ :to_folder_id => {:id => new_folder},
141
+ :item_ids => [{:item_id => {:id => self.id}}]
142
+ }
143
+ resp = @ews.move_item(move_opts)
144
+ rmsg = resp.response_messages[0]
145
+
146
+ if rmsg.success?
147
+ obj = rmsg.items.first
148
+ itype = obj.keys.first
149
+ obj[itype][:elems][0][:item_id][:attribs][:id]
150
+ else
151
+ raise EwsError, "Could not move item. #{resp.code}: #{resp.message}"
152
+ end
153
+ end
154
+
155
+ # Copy this item to a new folder
156
+ # @param [String,Symbol,GenericFolder] new_folder The new folder to move it to. This should
157
+ # be a subclass of GenericFolder, a DistinguishedFolderId (must me a Symbol) or a FolderId (String)
158
+ # @return [String] the new Id of the copied item
159
+ def copy(new_folder)
160
+ new_folder = new_folder.id if new_folder.kind_of?(GenericFolder)
161
+ copy_opts = {
162
+ :to_folder_id => {:id => new_folder},
163
+ :item_ids => [{:item_id => {:id => self.id}}]
164
+ }
165
+ resp = @ews.copy_item(copy_opts)
166
+ rmsg = resp.response_messages[0]
167
+
168
+ if rmsg.success?
169
+ obj = rmsg.items.first
170
+ itype = obj.keys.first
171
+ obj[itype][:elems][0][:item_id][:attribs][:id]
172
+ else
173
+ raise EwsError, "Could not copy item. #{rmsg.response_code}: #{rmsg.message_text}"
174
+ end
175
+ end
176
+
177
+ def add_file_attachment(file)
178
+ fa = OpenStruct.new
179
+ fa.name = File.basename(file.path)
180
+ fa.content = Base64.encode64(file.read)
181
+ @new_file_attachments << fa
182
+ end
183
+
184
+ def add_item_attachment(other_item, name = nil)
185
+ ia = OpenStruct.new
186
+ ia.name = (name ? name : other_item.subject)
187
+ ia.item = {id: other_item.id, change_key: other_item.change_key}
188
+ @new_item_attachments << ia
189
+ end
190
+
191
+ def add_inline_attachment(file)
192
+ fi = OpenStruct.new
193
+ fi.name = File.basename(file.path)
194
+ fi.content = Base64.encode64(file.read)
195
+ @new_inline_attachments << fi
196
+ end
197
+
198
+ def submit!
199
+ if draft?
200
+ submit_attachments!
201
+ resp = ews.send_item(item_ids: [{item_id: {id: self.id, change_key: self.change_key}}])
202
+ rm = resp.response_messages[0]
203
+ if rm.success?
204
+ true
205
+ else
206
+ raise EwsSendItemError, "#{rm.code}: #{rm.message_text}"
207
+ end
208
+ else
209
+ false
210
+ end
211
+ end
212
+
213
+ def submit_attachments!
214
+ return false unless draft? && !(@new_file_attachments.empty? && @new_item_attachments.empty? && @new_inline_attachments.empty?)
215
+
216
+ opts = {
217
+ parent_id: {id: self.id, change_key: self.change_key},
218
+ files: @new_file_attachments,
219
+ items: @new_item_attachments,
220
+ inline_files: @new_inline_attachments
221
+ }
222
+ resp = ews.create_attachment(opts)
223
+ set_change_key resp.response_messages[0].attachments[0].parent_change_key
224
+ @new_file_attachments = []
225
+ @new_item_attachments = []
226
+ @new_inline_attachments = []
227
+ end
228
+
229
+ # If you want to add to the body set #new_body_content. If you set #body
230
+ # it will override the body that is there.
231
+ # @see MessageAccessors#send_message for options
232
+ # additional options:
233
+ # :new_body_content, :new_body_type
234
+ # @example
235
+ # item.forward do |i|
236
+ # i.new_body_content = "Add this to the top"
237
+ # i.to_recipients << 'test@example.com'
238
+ # end
239
+ def forward(opts = {})
240
+ msg = Template::ForwardItem.new opts.clone
241
+ yield msg if block_given?
242
+ msg.reference_item_id = {id: self.id, change_key: self.change_key}
243
+ dispatch_create_item! msg
244
+ end
245
+
246
+ def reply_to(opts = {})
247
+ msg = Template::ReplyToItem.new opts.clone
248
+ yield msg if block_given?
249
+ msg.reference_item_id = {id: self.id, change_key: self.change_key}
250
+ dispatch_create_item! msg
251
+ end
252
+
253
+ def reply_to_all(opts = {})
254
+ msg = Template::ReplyToItem.new opts.clone
255
+ yield msg if block_given?
256
+ msg.reference_item_id = {id: self.id, change_key: self.change_key}
257
+ msg.ews_type = :reply_all_to_item
258
+ dispatch_create_item! msg
259
+ end
260
+
261
+
262
+ private
263
+
264
+ def key_paths
265
+ super.merge(ITEM_KEY_PATHS)
266
+ end
267
+
268
+ def key_types
269
+ super.merge(ITEM_KEY_TYPES)
270
+ end
271
+
272
+ def key_alias
273
+ super.merge(ITEM_KEY_ALIAS)
274
+ end
275
+
276
+ def update_is_read_status(read)
277
+ field = :is_read
278
+ opts = {item_changes:
279
+ [
280
+ { item_id: {id: id, change_key: change_key},
281
+ updates: [
282
+ {set_item_field: {field_uRI: {field_uRI: FIELD_URIS[field][:text]},
283
+ message: {sub_elements: [{field => {text: read}}]}}}
284
+ ]
285
+ }
286
+ ]
287
+ }
288
+ resp = ews.update_item({conflict_resolution: 'AutoResolve'}.merge(opts))
289
+ rmsg = resp.response_messages[0]
290
+ unless rmsg.success?
291
+ raise EwsError, "#{rmsg.response_code}: #{rmsg.message_text}"
292
+ end
293
+ true
294
+ end
295
+
296
+ def simplify!
297
+ return unless @ews_item.has_key?(:elems)
298
+ @ews_item = @ews_item[:elems].inject({}) do |o,i|
299
+ key = i.keys.first
300
+ if o.has_key?(key)
301
+ if o[key].is_a?(Array)
302
+ o[key] << i[key]
303
+ else
304
+ o[key] = [o.delete(key), i[key]]
305
+ end
306
+ else
307
+ o[key] = i[key]
308
+ end
309
+ o
310
+ end
311
+ end
312
+
313
+ # Get a specific item by its ID.
314
+ # @param [Hash] opts Misc options to control request
315
+ # @option opts [String] :base_shape IdOnly/Default/AllProperties
316
+ # @raise [EwsError] raised when the backend SOAP method returns an error.
317
+ def get_item(opts = {})
318
+ args = get_item_args(opts)
319
+ resp = ews.get_item(args)
320
+ get_item_parser(resp)
321
+ end
322
+
323
+ # Build up the arguements for #get_item
324
+ # @todo: should we really pass the ChangeKey or do we want the freshest obj?
325
+ def get_item_args(opts)
326
+ opts[:base_shape] ||= 'Default'
327
+ default_args = {
328
+ item_shape: {base_shape: opts[:base_shape]},
329
+ item_ids: [{item_id:{id: id, change_key: change_key}}]
330
+ }
331
+ default_args[:item_shape][:body_type] = @body_type if @body_type
332
+ default_args
333
+ end
334
+
335
+ def get_item_parser(resp)
336
+ rm = resp.response_messages[0]
337
+ if(rm.status == 'Success')
338
+ rm.items[0].values.first
339
+ else
340
+ raise EwsError, "Could not retrieve #{self.class}. #{rm.code}: #{rm.message_text}"
341
+ end
342
+ end
343
+
344
+ # Map a delete type to what EWS expects
345
+ # @param [Symbol] type. Must be :hard, :soft, or :recycle
346
+ def delete_type(type)
347
+ case type
348
+ when :hard then 'HardDelete'
349
+ when :soft then 'SoftDelete'
350
+ when :recycle then 'MoveToDeletedItems'
351
+ else 'MoveToDeletedItems'
352
+ end
353
+ end
354
+
355
+ def build_deleted_occurrences(occurrences)
356
+ occurrences.collect{|a| DateTime.parse a[:deleted_occurrence][:elems][0][:start][:text]}
357
+ end
358
+
359
+ def build_modified_occurrences(occurrences)
360
+ {}.tap do |h|
361
+ occurrences.collect do |a|
362
+ elems = a[:occurrence][:elems]
363
+
364
+ h[DateTime.parse(elems.find{|e| e[:original_start]}[:original_start][:text])] = {
365
+ start: elems.find{|e| e[:start]}[:start][:text],
366
+ end: elems.find{|e| e[:end]}[:end][:text]
367
+ }
368
+ end
369
+ end
370
+ end
371
+
372
+ def build_mailbox_user(mbox_ews)
373
+ MailboxUser.new(ews, mbox_ews)
374
+ end
375
+
376
+ def build_mailbox_users(users)
377
+ return [] if users.nil?
378
+ users.collect{|u| build_mailbox_user(u[:mailbox][:elems])}
379
+ end
380
+
381
+ def build_attendees_users(ews_users)
382
+ attendees = []
383
+ ews_users.each do |attendee|
384
+ attendee[:attendee][:elems].each do |element|
385
+ if element[:mailbox]
386
+ attendees << Attendee.new(ews, attendee)
387
+ end
388
+ end
389
+ end
390
+ attendees
391
+ end
392
+
393
+ def build_attachments(attachments)
394
+ return [] if attachments.nil?
395
+ attachments.collect do |att|
396
+ key = att.keys.first
397
+ class_by_name(key).new(self, att[key])
398
+ end
399
+ end
400
+
401
+ def set_change_key(ck)
402
+ p = resolve_key_path(ews_item, key_paths[:change_key][0..-2])
403
+ p[:change_key] = ck
404
+ end
405
+
406
+ # Handles the CreateItem call for Forward, ReplyTo, and ReplyAllTo
407
+ # It will handle the neccessary actions for adding attachments.
408
+ def dispatch_create_item!(msg)
409
+ if msg.has_attachments?
410
+ draft = msg.draft
411
+ msg.draft = true
412
+ resp = validate_created_item(ews.create_item(msg.to_ews))
413
+ msg.file_attachments.each do |f|
414
+ next unless f.kind_of?(File)
415
+ resp.add_file_attachment(f)
416
+ end
417
+ if draft
418
+ resp.submit_attachments!
419
+ resp
420
+ else
421
+ resp.submit!
422
+ end
423
+ else
424
+ resp = ews.create_item(msg.to_ews)
425
+ validate_created_item resp
426
+ end
427
+ end
428
+
429
+ # validate the CreateItem response.
430
+ # @return [Boolean, Item] returns true if items is empty and status is
431
+ # "Success" if items is not empty it will return the first Item since
432
+ # we are only dealing with single items here.
433
+ # @raise EwsCreateItemError on failure
434
+ def validate_created_item(response)
435
+ msg = response.response_messages[0]
436
+
437
+ if(msg.status == 'Success')
438
+ msg.items.empty? ? true : parse_created_item(msg.items.first)
439
+ else
440
+ raise EwsCreateItemError, "#{msg.code}: #{msg.message_text}"
441
+ end
442
+ end
443
+
444
+ def parse_created_item(msg)
445
+ mtype = msg.keys.first
446
+ message = class_by_name(mtype).new(ews, msg[mtype])
447
+ end
448
+
449
+ end
450
+ end
@@ -0,0 +1,84 @@
1
+ =begin
2
+ This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services.
3
+
4
+ Copyright © 2011 Dan Wanek <dan.wanek@gmail.com>
5
+
6
+ Licensed under the Apache License, Version 2.0 (the "License");
7
+ you may not use this file except in compliance with the License.
8
+ You may obtain a copy of the License at
9
+
10
+ http://www.apache.org/licenses/LICENSE-2.0
11
+
12
+ Unless required by applicable law or agreed to in writing, software
13
+ distributed under the License is distributed on an "AS IS" BASIS,
14
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ See the License for the specific language governing permissions and
16
+ limitations under the License.
17
+ =end
18
+
19
+ module Viewpoint::EWS::Types
20
+ class ItemAttachment < Attachment
21
+
22
+ ITEM_ATTACH_KEY_PATHS = {
23
+ item: [:item],
24
+ message: [:message],
25
+ calendar_item: [:calendar_item],
26
+ contact: [:contact],
27
+ task: [:task],
28
+ meeting_message: [:meeting_message],
29
+ meeting_request: [:meeting_request],
30
+ meeting_response: [:meeting_response],
31
+ meeting_cancellation: [:meeting_cancellation]
32
+ }
33
+
34
+ ITEM_ATTACH_KEY_TYPES = {
35
+ message: :build_message,
36
+ calendar_item: :build_calendar_item,
37
+ contact: :build_contact,
38
+ task: :build_task,
39
+ meeting_message: :build_meeting_message,
40
+ meeting_request: :build_meeting_request,
41
+ meeting_response: :build_meeting_response,
42
+ meeting_cancellation: :build_meeting_cancellation
43
+ }
44
+
45
+ ITEM_ATTACH_KEY_ALIAS = { }
46
+
47
+ def get_all_properties!
48
+ resp = ews.get_attachment attachment_ids: [self.id]
49
+ @ews_item.merge!(parse_response(resp))
50
+ end
51
+
52
+ private
53
+
54
+ def self.method_missing(method, *args, &block)
55
+ if method.to_s =~ /^build_(.+)$/
56
+ class_by_name($1).new(ews, args[0])
57
+ else
58
+ super
59
+ end
60
+ end
61
+
62
+ def key_paths
63
+ super.merge(ITEM_ATTACH_KEY_PATHS)
64
+ end
65
+
66
+ def key_types
67
+ super.merge(ITEM_ATTACH_KEY_TYPES)
68
+ end
69
+
70
+ def key_alias
71
+ super.merge(ITEM_ATTACH_KEY_ALIAS)
72
+ end
73
+
74
+ def parse_response(resp)
75
+ if(resp.status == 'Success')
76
+ resp.response_message[:elems][:attachments][:elems][0][:item_attachment][:elems].inject(&:merge)
77
+ else
78
+ raise EwsError, "Could not retrieve #{self.class}. #{resp.code}: #{resp.message}"
79
+ end
80
+ end
81
+
82
+ end
83
+ end
84
+