stxt-viewpoint 1.0.0.beta.3

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 (89) hide show
  1. checksums.yaml +7 -0
  2. data/Changelog.txt +1004 -0
  3. data/README.md +201 -0
  4. data/TODO +17 -0
  5. data/lib/ews/calendar_accessors.rb +46 -0
  6. data/lib/ews/connection.rb +120 -0
  7. data/lib/ews/connection_helper.rb +35 -0
  8. data/lib/ews/convert_accessors.rb +56 -0
  9. data/lib/ews/errors.rb +56 -0
  10. data/lib/ews/ews_client.rb +101 -0
  11. data/lib/ews/exceptions/exceptions.rb +61 -0
  12. data/lib/ews/folder_accessors.rb +264 -0
  13. data/lib/ews/impersonation.rb +30 -0
  14. data/lib/ews/item_accessors.rb +231 -0
  15. data/lib/ews/mailbox_accessors.rb +92 -0
  16. data/lib/ews/message_accessors.rb +93 -0
  17. data/lib/ews/push_subscription_accessors.rb +33 -0
  18. data/lib/ews/room_accessors.rb +48 -0
  19. data/lib/ews/roomlist_accessors.rb +47 -0
  20. data/lib/ews/soap/builders/ews_builder.rb +1257 -0
  21. data/lib/ews/soap/ews_response.rb +84 -0
  22. data/lib/ews/soap/ews_soap_availability_response.rb +58 -0
  23. data/lib/ews/soap/ews_soap_free_busy_response.rb +119 -0
  24. data/lib/ews/soap/ews_soap_response.rb +103 -0
  25. data/lib/ews/soap/ews_soap_room_response.rb +53 -0
  26. data/lib/ews/soap/ews_soap_roomlist_response.rb +54 -0
  27. data/lib/ews/soap/exchange_availability.rb +61 -0
  28. data/lib/ews/soap/exchange_data_services.rb +780 -0
  29. data/lib/ews/soap/exchange_notification.rb +146 -0
  30. data/lib/ews/soap/exchange_synchronization.rb +93 -0
  31. data/lib/ews/soap/exchange_time_zones.rb +56 -0
  32. data/lib/ews/soap/exchange_user_configuration.rb +33 -0
  33. data/lib/ews/soap/exchange_web_service.rb +264 -0
  34. data/lib/ews/soap/parsers/ews_parser.rb +43 -0
  35. data/lib/ews/soap/parsers/ews_sax_document.rb +70 -0
  36. data/lib/ews/soap/response_message.rb +80 -0
  37. data/lib/ews/soap/responses/create_attachment_response_message.rb +47 -0
  38. data/lib/ews/soap/responses/create_item_response_message.rb +25 -0
  39. data/lib/ews/soap/responses/find_item_response_message.rb +80 -0
  40. data/lib/ews/soap/responses/get_events_response_message.rb +53 -0
  41. data/lib/ews/soap/responses/send_notification_response_message.rb +59 -0
  42. data/lib/ews/soap/responses/subscribe_response_message.rb +35 -0
  43. data/lib/ews/soap/responses/sync_folder_hierarchy_response_message.rb +36 -0
  44. data/lib/ews/soap/responses/sync_folder_items_response_message.rb +36 -0
  45. data/lib/ews/soap.rb +63 -0
  46. data/lib/ews/templates/calendar_item.rb +78 -0
  47. data/lib/ews/templates/forward_item.rb +24 -0
  48. data/lib/ews/templates/message.rb +73 -0
  49. data/lib/ews/templates/reply_to_item.rb +25 -0
  50. data/lib/ews/templates/task.rb +74 -0
  51. data/lib/ews/types/attachment.rb +77 -0
  52. data/lib/ews/types/attendee.rb +27 -0
  53. data/lib/ews/types/calendar_folder.rb +50 -0
  54. data/lib/ews/types/calendar_item.rb +122 -0
  55. data/lib/ews/types/contact.rb +7 -0
  56. data/lib/ews/types/contacts_folder.rb +8 -0
  57. data/lib/ews/types/copied_event.rb +51 -0
  58. data/lib/ews/types/created_event.rb +24 -0
  59. data/lib/ews/types/deleted_event.rb +24 -0
  60. data/lib/ews/types/distribution_list.rb +7 -0
  61. data/lib/ews/types/event.rb +62 -0
  62. data/lib/ews/types/export_items_response_message.rb +52 -0
  63. data/lib/ews/types/file_attachment.rb +65 -0
  64. data/lib/ews/types/folder.rb +60 -0
  65. data/lib/ews/types/free_busy_changed_event.rb +24 -0
  66. data/lib/ews/types/generic_folder.rb +420 -0
  67. data/lib/ews/types/item.rb +438 -0
  68. data/lib/ews/types/item_attachment.rb +84 -0
  69. data/lib/ews/types/item_field_uri_map.rb +224 -0
  70. data/lib/ews/types/mailbox_user.rb +156 -0
  71. data/lib/ews/types/meeting_cancellation.rb +7 -0
  72. data/lib/ews/types/meeting_message.rb +7 -0
  73. data/lib/ews/types/meeting_request.rb +7 -0
  74. data/lib/ews/types/meeting_response.rb +7 -0
  75. data/lib/ews/types/message.rb +7 -0
  76. data/lib/ews/types/modified_event.rb +48 -0
  77. data/lib/ews/types/moved_event.rb +51 -0
  78. data/lib/ews/types/new_mail_event.rb +24 -0
  79. data/lib/ews/types/out_of_office.rb +147 -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 +37 -0
  83. data/lib/ews/types/tasks_folder.rb +27 -0
  84. data/lib/ews/types.rb +191 -0
  85. data/lib/viewpoint/logging/config.rb +24 -0
  86. data/lib/viewpoint/logging.rb +27 -0
  87. data/lib/viewpoint/string_utils.rb +44 -0
  88. data/lib/viewpoint.rb +109 -0
  89. metadata +191 -0
@@ -0,0 +1,1257 @@
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
+ module Viewpoint::EWS::SOAP
19
+
20
+ # This class includes the element builders. The idea is that each element should
21
+ # know how to build themselves so each parent element can delegate creation of
22
+ # subelements to a method of the same name with a '!' after it.
23
+ class EwsBuilder
24
+ include Viewpoint::EWS
25
+ include Viewpoint::StringUtils
26
+
27
+ attr_reader :nbuild
28
+ def initialize
29
+ @nbuild = Nokogiri::XML::Builder.new
30
+ end
31
+
32
+ # Build the SOAP envelope and yield this object so subelements can be built. Once
33
+ # you have the EwsBuilder object you can use the nbuild object like shown in the
34
+ # example for the Header section. The nbuild object is the underlying
35
+ # Nokogiri::XML::Builder object.
36
+ # @param [Hash] opts
37
+ # @option opts [String] :server_version The version string that should get
38
+ # set in the Header. See ExchangeWebService#initialize
39
+ # @option opts [Hash] :time_zone_context TimeZoneDefinition. Format: !{id: time_zone_identifier}
40
+ # @example
41
+ # xb = EwsBuilder.new
42
+ # xb.build! do |part, b|
43
+ # if(part == :header)
44
+ # b.nbuild.MyVar('blablabla')
45
+ # else
46
+ # b.folder_shape!({:base_shape => 'Default'})
47
+ # end
48
+ # end
49
+ def build!(opts = {}, &block)
50
+ @nbuild.Envelope(NAMESPACES) do |node|
51
+ node.parent.namespace = parent_namespace(node)
52
+ node.Header {
53
+ set_version_header! opts[:server_version]
54
+ set_impersonation! opts[:impersonation_type], opts[:impersonation_mail]
55
+ set_time_zone_context_header! opts[:time_zone_context]
56
+ yield(:header, self) if block_given?
57
+ }
58
+ node.Body {
59
+ yield(:body, self) if block_given?
60
+ }
61
+ end
62
+ @nbuild.doc
63
+ end
64
+
65
+ # Build XML from a passed in Hash or Array in a specified format.
66
+ # @param [Array,Hash] elems The elements to add to the Builder. They must
67
+ # be specified like so:
68
+ #
69
+ # !{:top =>
70
+ # { :xmlns => 'http://stonesthrow/soap',
71
+ # :sub_elements => [
72
+ # {:elem1 => {:text => 'inside'}},
73
+ # {:elem2 => {:text => 'inside2'}}
74
+ # ],
75
+ # :id => '3232', :tx_dd => 23, :asdf => 'turkey'
76
+ # }
77
+ # }
78
+ # or
79
+ # [ {:first => {:text => 'hello'}},
80
+ # {:second => {:text => 'world'}}
81
+ # ]
82
+ #
83
+ # NOTE: there are specialized keys for text (:text), child elements
84
+ # (:sub_elements) and namespaces (:xmlns).
85
+ def build_xml!(elems)
86
+ case elems.class.name
87
+ when 'Hash'
88
+ keys = elems.keys
89
+ vals = elems.values
90
+ if(keys.length > 1 && !vals.is_a?(Hash))
91
+ raise "invalid input: #{elems}"
92
+ end
93
+ vals = vals.first.clone
94
+ se = vals.delete(:sub_elements)
95
+ txt = vals.delete(:text)
96
+ xmlns_attribute = vals.delete(:xmlns_attribute)
97
+
98
+ node = @nbuild.send(camel_case(keys.first), txt, vals) {|x|
99
+ build_xml!(se) if se
100
+ }
101
+
102
+ # Set node level namespace
103
+ node.xmlns = NAMESPACES["xmlns:#{xmlns_attribute}"] if xmlns_attribute
104
+ when 'Array'
105
+ elems.each do |e|
106
+ build_xml!(e)
107
+ end
108
+ else
109
+ raise "Unsupported type: #{elems.class.name}"
110
+ end
111
+ end
112
+
113
+ # Build the FolderShape element
114
+ # @see http://msdn.microsoft.com/en-us/library/aa494311.aspx
115
+ # @param [Hash] folder_shape The folder shape structure to build from
116
+ # @todo need fully support all options
117
+ def folder_shape!(folder_shape)
118
+ @nbuild.FolderShape {
119
+ @nbuild.parent.default_namespace = @default_ns
120
+ base_shape!(folder_shape[:base_shape])
121
+ if(folder_shape[:additional_properties])
122
+ additional_properties!(folder_shape[:additional_properties])
123
+ end
124
+ }
125
+ end
126
+
127
+ # Build the ItemShape element
128
+ # @see http://msdn.microsoft.com/en-us/library/aa565261.aspx
129
+ # @param [Hash] item_shape The item shape structure to build from
130
+ # @todo need fully support all options
131
+ def item_shape!(item_shape)
132
+ @nbuild[NS_EWS_MESSAGES].ItemShape {
133
+ @nbuild.parent.default_namespace = @default_ns
134
+ base_shape!(item_shape[:base_shape])
135
+ mime_content!(item_shape[:include_mime_content]) if item_shape.has_key?(:include_mime_content)
136
+ body_type!(item_shape[:body_type]) if item_shape[:body_type]
137
+ if(item_shape[:additional_properties])
138
+ additional_properties!(item_shape[:additional_properties])
139
+ end
140
+ }
141
+ end
142
+
143
+ # Build the IndexedPageItemView element
144
+ # @see http://msdn.microsoft.com/en-us/library/exchange/aa563549(v=exchg.150).aspx
145
+ # @todo needs peer check
146
+ def indexed_page_item_view!(indexed_page_item_view)
147
+ attribs = {}
148
+ indexed_page_item_view.each_pair {|k,v| attribs[camel_case(k)] = v.to_s}
149
+ @nbuild[NS_EWS_MESSAGES].IndexedPageItemView(attribs)
150
+ end
151
+
152
+ # Build the BaseShape element
153
+ # @see http://msdn.microsoft.com/en-us/library/aa580545.aspx
154
+ def base_shape!(base_shape)
155
+ @nbuild[NS_EWS_TYPES].BaseShape(camel_case(base_shape))
156
+ end
157
+
158
+ def mime_content!(include_mime_content)
159
+ @nbuild[NS_EWS_TYPES].IncludeMimeContent(include_mime_content.to_s.downcase)
160
+ end
161
+
162
+ def body_type!(body_type)
163
+ body_type = body_type.to_s
164
+ if body_type =~ /html/i
165
+ body_type = body_type.upcase
166
+ else
167
+ body_type = body_type.downcase.capitalize
168
+ end
169
+ nbuild[NS_EWS_TYPES].BodyType(body_type)
170
+ end
171
+
172
+ # Build the ParentFolderIds element
173
+ # @see http://msdn.microsoft.com/en-us/library/aa565998.aspx
174
+ def parent_folder_ids!(pfids)
175
+ @nbuild[NS_EWS_MESSAGES].ParentFolderIds {
176
+ pfids.each do |pfid|
177
+ dispatch_folder_id!(pfid)
178
+ end
179
+ }
180
+ end
181
+
182
+ # Build the ParentFolderId element
183
+ # @see http://msdn.microsoft.com/en-us/library/aa563268.aspx
184
+ def parent_folder_id!(pfid)
185
+ @nbuild.ParentFolderId {
186
+ dispatch_folder_id!(pfid)
187
+ }
188
+ end
189
+
190
+ # Build the FolderIds element
191
+ # @see http://msdn.microsoft.com/en-us/library/aa580509.aspx
192
+ def folder_ids!(fids, act_as=nil)
193
+ ns = @nbuild.parent.name.match(/subscription/i) ? NS_EWS_TYPES : NS_EWS_MESSAGES
194
+ @nbuild[ns].FolderIds {
195
+ fids.each do |fid|
196
+ fid[:act_as] = act_as if act_as != nil
197
+ dispatch_folder_id!(fid)
198
+ end
199
+ }
200
+ end
201
+
202
+ # Build the SyncFolderId element
203
+ # @see http://msdn.microsoft.com/en-us/library/aa580296.aspx
204
+ def sync_folder_id!(fid)
205
+ @nbuild.SyncFolderId {
206
+ dispatch_folder_id!(fid)
207
+ }
208
+ end
209
+
210
+ # Build the DistinguishedFolderId element
211
+ # @see http://msdn.microsoft.com/en-us/library/aa580808.aspx
212
+ # @todo add support for the Mailbox child object
213
+ def distinguished_folder_id!(dfid, change_key = nil, act_as = nil)
214
+ attribs = {'Id' => dfid.to_s}
215
+ attribs['ChangeKey'] = change_key if change_key
216
+ @nbuild[NS_EWS_TYPES].DistinguishedFolderId(attribs) {
217
+ if ! act_as.nil?
218
+ mailbox!({:email_address => act_as})
219
+ end
220
+ }
221
+ end
222
+
223
+ # Build the FolderId element
224
+ # @see http://msdn.microsoft.com/en-us/library/aa579461.aspx
225
+ def folder_id!(fid, change_key = nil)
226
+ attribs = {'Id' => fid}
227
+ attribs['ChangeKey'] = change_key if change_key
228
+ @nbuild[NS_EWS_TYPES].FolderId(attribs)
229
+ end
230
+
231
+ # @see http://msdn.microsoft.com/en-us/library/aa563525(v=EXCHG.140).aspx
232
+ def item_ids!(item_ids)
233
+ @nbuild.ItemIds {
234
+ item_ids.each do |iid|
235
+ dispatch_item_id!(iid)
236
+ end
237
+ }
238
+ end
239
+
240
+ def parent_item_id!(id)
241
+ nbuild.ParentItemId {|x|
242
+ x.parent['Id'] = id[:id]
243
+ x.parent['ChangeKey'] = id[:change_key] if id[:change_key]
244
+ }
245
+ end
246
+
247
+ # @see http://msdn.microsoft.com/en-us/library/aa580234(v=EXCHG.140).aspx
248
+ def item_id!(id)
249
+ nbuild[NS_EWS_TYPES].ItemId {|x|
250
+ x.parent['Id'] = id[:id]
251
+ x.parent['ChangeKey'] = id[:change_key] if id[:change_key]
252
+ }
253
+ end
254
+
255
+ # @see http://msdn.microsoft.com/en-us/library/ff709503(v=exchg.140).aspx
256
+ def export_item_ids!(item_ids)
257
+ ns = @nbuild.parent.name.match(/subscription/i) ? NS_EWS_TYPES : NS_EWS_MESSAGES
258
+ @nbuild[ns].ExportItems{
259
+ @nbuild.ItemIds {
260
+ item_ids.each do |iid|
261
+ dispatch_item_id!(iid)
262
+ end
263
+ }
264
+ }
265
+ end
266
+
267
+ # @see http://msdn.microsoft.com/en-us/library/aa580744(v=EXCHG.140).aspx
268
+ def occurrence_item_id!(id)
269
+ @nbuild[NS_EWS_TYPES].OccurrenceItemId {|x|
270
+ x.parent['RecurringMasterId'] = id[:recurring_master_id]
271
+ x.parent['ChangeKey'] = id[:change_key] if id[:change_key]
272
+ x.parent['InstanceIndex'] = id[:instance_index]
273
+ }
274
+ end
275
+
276
+ # @see http://msdn.microsoft.com/en-us/library/aa581019(v=EXCHG.140).aspx
277
+ def recurring_master_item_id!(id)
278
+ @nbuild[NS_EWS_TYPES].RecurringMasterItemId {|x|
279
+ x.parent['OccurrenceId'] = id[:occurrence_id]
280
+ x.parent['ChangeKey'] = id[:change_key] if id[:change_key]
281
+ }
282
+ end
283
+
284
+ # @see http://msdn.microsoft.com/en-us/library/aa565020(v=EXCHG.140).aspx
285
+ def to_folder_id!(to_fid)
286
+ @nbuild[NS_EWS_MESSAGES].ToFolderId {
287
+ dispatch_folder_id!(to_fid)
288
+ }
289
+ end
290
+
291
+ # @see http://msdn.microsoft.com/en-us/library/aa564009.aspx
292
+ def folders!(folders)
293
+ @nbuild.Folders {|x|
294
+ folders.each do |fold|
295
+ fold.each_pair do |ftype, vars| # convenience, should only be one pair
296
+ ftype = "#{ftype}!".to_sym
297
+ if self.respond_to? ftype
298
+ self.send ftype, vars
299
+ else
300
+ raise Viewpoint::EWS::EwsNotImplemented,
301
+ "#{ftype} not implemented as a builder."
302
+ end
303
+ end
304
+ end
305
+ }
306
+ end
307
+
308
+ def folder!(folder, type = :Folder)
309
+ nbuild[NS_EWS_TYPES].send(type) {|x|
310
+ folder.each_pair do |e,v|
311
+ ftype = "#{e}!".to_sym
312
+ if e == :folder_id
313
+ dispatch_folder_id!(v)
314
+ elsif self.respond_to?(ftype)
315
+ self.send ftype, v
316
+ else
317
+ raise Viewpoint::EWS::EwsNotImplemented,
318
+ "#{ftype} not implemented as a builder."
319
+ end
320
+ end
321
+ }
322
+ end
323
+
324
+ def calendar_folder!(folder)
325
+ folder! folder, :CalendarFolder
326
+ end
327
+
328
+ def contacts_folder!(folder)
329
+ folder! folder, :ContactsFolder
330
+ end
331
+
332
+ def search_folder!(folder)
333
+ folder! folder, :SearchFolder
334
+ end
335
+
336
+ def tasks_folder!(folder)
337
+ folder! folder, :TasksFolder
338
+ end
339
+
340
+ def display_name!(name)
341
+ nbuild[NS_EWS_TYPES].DisplayName(name)
342
+ end
343
+
344
+ # Build the AdditionalProperties element
345
+ # @see http://msdn.microsoft.com/en-us/library/aa563810.aspx
346
+ def additional_properties!(addprops)
347
+ @nbuild[NS_EWS_TYPES].AdditionalProperties {
348
+ addprops.each_pair {|k,v|
349
+ dispatch_field_uri!({k => v}, NS_EWS_TYPES)
350
+ }
351
+ }
352
+ end
353
+
354
+ # Build the Mailbox element.
355
+ # This element is commonly used for delegation. Typically passing an
356
+ # email_address is sufficient
357
+ # @see http://msdn.microsoft.com/en-us/library/aa565036.aspx
358
+ # @param [Hash] mailbox A well-formated hash
359
+ def mailbox!(mbox)
360
+ nbuild[NS_EWS_TYPES].Mailbox {
361
+ name!(mbox[:name]) if mbox[:name]
362
+ email_address!(mbox[:email_address]) if mbox[:email_address]
363
+ address!(mbox[:address]) if mbox[:address] # for Availability query
364
+ routing_type!(mbox[:routing_type]) if mbox[:routing_type]
365
+ mailbox_type!(mbox[:mailbox_type]) if mbox[:mailbox_type]
366
+ item_id!(mbox[:item_id]) if mbox[:item_id]
367
+ }
368
+ end
369
+
370
+ def name!(name)
371
+ nbuild[NS_EWS_TYPES].Name(name)
372
+ end
373
+
374
+ def email_address!(email)
375
+ nbuild[NS_EWS_TYPES].EmailAddress(email)
376
+ end
377
+
378
+ def address!(email)
379
+ nbuild[NS_EWS_TYPES].Address(email)
380
+ end
381
+
382
+ # This is stupid. The only valid value is "SMTP"
383
+ def routing_type!(type)
384
+ nbuild[NS_EWS_TYPES].RoutingType(type)
385
+ end
386
+
387
+ def mailbox_type!(type)Standard
388
+ nbuild[NS_EWS_TYPES].MailboxType(type)
389
+ end
390
+
391
+ def user_oof_settings!(opts)
392
+ nbuild[NS_EWS_TYPES].UserOofSettings {
393
+ nbuild.OofState(camel_case(opts[:oof_state]))
394
+ nbuild.ExternalAudience(camel_case(opts[:external_audience])) if opts[:external_audience]
395
+ duration!(opts[:duration]) if opts[:duration]
396
+ nbuild.InternalReply {
397
+ nbuild.Message(opts[:internal_reply])
398
+ } if opts[:external_reply]
399
+ nbuild.ExternalReply {
400
+ nbuild.Message(opts[:external_reply])
401
+ } if opts[:external_reply]
402
+ }
403
+ end
404
+
405
+ def duration!(opts)
406
+ nbuild.Duration {
407
+ nbuild.StartTime(format_time opts[:start_time])
408
+ nbuild.EndTime(format_time opts[:end_time])
409
+ }
410
+ end
411
+
412
+ def mailbox_data!(md)
413
+ nbuild[NS_EWS_TYPES].MailboxData {
414
+ nbuild[NS_EWS_TYPES].Email {
415
+ mbox = md[:email]
416
+ name!(mbox[:name]) if mbox[:name]
417
+ address!(mbox[:address]) if mbox[:address] # for Availability query
418
+ routing_type!(mbox[:routing_type]) if mbox[:routing_type]
419
+ }
420
+ nbuild[NS_EWS_TYPES].AttendeeType 'Required'
421
+ }
422
+ end
423
+
424
+ def free_busy_view_options!(opts)
425
+ nbuild[NS_EWS_TYPES].FreeBusyViewOptions {
426
+ nbuild[NS_EWS_TYPES].TimeWindow {
427
+ nbuild[NS_EWS_TYPES].StartTime(format_time opts[:time_window][:start_time])
428
+ nbuild[NS_EWS_TYPES].EndTime(format_time opts[:time_window][:end_time])
429
+ }
430
+ nbuild[NS_EWS_TYPES].RequestedView(camel_case(opts[:requested_view][:requested_free_busy_view]))
431
+ }
432
+ end
433
+
434
+ def suggestions_view_options!(opts)
435
+ end
436
+
437
+ def time_zone!(zone)
438
+ zone ||= {}
439
+ zone = {
440
+ bias: zone[:bias] || 480,
441
+ standard_time: {
442
+ bias: 0,
443
+ time: "02:00:00",
444
+ day_order: 5,
445
+ month: 10,
446
+ day_of_week: 'Sunday'
447
+ }.merge(zone[:standard_time] || {}),
448
+ daylight_time: {
449
+ bias: -60,
450
+ time: "02:00:00",
451
+ day_order: 1,
452
+ month: 4,
453
+ day_of_week: 'Sunday'
454
+ }.merge(zone[:daylight_time] || {})
455
+ }
456
+
457
+ nbuild[NS_EWS_TYPES].TimeZone {
458
+ nbuild[NS_EWS_TYPES].Bias(zone[:bias])
459
+ nbuild[NS_EWS_TYPES].StandardTime {
460
+ nbuild[NS_EWS_TYPES].Bias(zone[:standard_time][:bias])
461
+ nbuild[NS_EWS_TYPES].Time(zone[:standard_time][:time])
462
+ nbuild[NS_EWS_TYPES].DayOrder(zone[:standard_time][:day_order])
463
+ nbuild[NS_EWS_TYPES].Month(zone[:standard_time][:month])
464
+ nbuild[NS_EWS_TYPES].DayOfWeek(zone[:standard_time][:day_of_week])
465
+ }
466
+ nbuild[NS_EWS_TYPES].DaylightTime {
467
+ nbuild[NS_EWS_TYPES].Bias(zone[:daylight_time][:bias])
468
+ nbuild[NS_EWS_TYPES].Time(zone[:daylight_time][:time])
469
+ nbuild[NS_EWS_TYPES].DayOrder(zone[:daylight_time][:day_order])
470
+ nbuild[NS_EWS_TYPES].Month(zone[:daylight_time][:month])
471
+ nbuild[NS_EWS_TYPES].DayOfWeek(zone[:daylight_time][:day_of_week])
472
+ }
473
+ }
474
+ end
475
+
476
+ # Request all known time_zones from server
477
+ def get_server_time_zones!(get_time_zone_options)
478
+ nbuild[NS_EWS_MESSAGES].GetServerTimeZones('ReturnFullTimeZoneData' => get_time_zone_options[:full]) do
479
+ if get_time_zone_options[:ids] && get_time_zone_options[:ids].any?
480
+ nbuild[NS_EWS_MESSAGES].Ids do
481
+ get_time_zone_options[:ids].each do |id|
482
+ nbuild[NS_EWS_TYPES].Id id
483
+ end
484
+ end
485
+ end
486
+ end
487
+ end
488
+
489
+ # Specifies an optional time zone for the start time
490
+ # @param [Hash] attributes
491
+ # @option attributes :id [String] ID of the Microsoft well known time zone
492
+ # @option attributes :name [String] Optional name of the time zone
493
+ # @todo Implement sub elements Periods, TransitionsGroups and Transitions to override zone
494
+ # @see http://msdn.microsoft.com/en-us/library/exchange/dd899524.aspx
495
+ def start_time_zone!(zone)
496
+ attributes = {}
497
+ attributes['Id'] = zone[:id] if zone[:id]
498
+ attributes['Name'] = zone[:name] if zone[:name]
499
+ nbuild[NS_EWS_TYPES].StartTimeZone(attributes)
500
+ end
501
+
502
+ # Specifies an optional time zone for the end time
503
+ # @param [Hash] attributes
504
+ # @option attributes :id [String] ID of the Microsoft well known time zone
505
+ # @option attributes :name [String] Optional name of the time zone
506
+ # @todo Implement sub elements Periods, TransitionsGroups and Transitions to override zone
507
+ # @see http://msdn.microsoft.com/en-us/library/exchange/dd899434.aspx
508
+ def end_time_zone!(zone)
509
+ attributes = {}
510
+ attributes['Id'] = zone[:id] if zone[:id]
511
+ attributes['Name'] = zone[:name] if zone[:name]
512
+ nbuild[NS_EWS_TYPES].EndTimeZone(attributes)
513
+ end
514
+
515
+ # Specify a time zone
516
+ # @todo Implement subelements Periods, TransitionsGroups and Transitions to override zone
517
+ # @see http://msdn.microsoft.com/en-us/library/exchange/dd899488.aspx
518
+ def time_zone_definition!(zone)
519
+ attributes = {'Id' => zone[:id]}
520
+ attributes['Name'] = zone[:name] if zone[:name]
521
+ nbuild[NS_EWS_TYPES].TimeZoneDefinition(attributes)
522
+ end
523
+
524
+ # Build the Restriction element
525
+ # @see http://msdn.microsoft.com/en-us/library/aa563791.aspx
526
+ # @param [Hash] restriction a well-formatted Hash that can be fed to #build_xml!
527
+ def restriction!(restriction)
528
+ @nbuild[NS_EWS_MESSAGES].Restriction {
529
+ restriction.each_pair do |k,v|
530
+ self.send normalize_type(k), v
531
+ end
532
+ }
533
+ end
534
+
535
+ def and_r(expr)
536
+ and_or('And', expr)
537
+ end
538
+
539
+ def or_r(expr)
540
+ and_or('Or', expr)
541
+ end
542
+
543
+ def and_or(type, expr)
544
+ @nbuild[NS_EWS_TYPES].send(type) {
545
+ expr.each do |e|
546
+ type = e.keys.first
547
+ self.send normalize_type(type), e[type]
548
+ end
549
+ }
550
+ end
551
+
552
+ def not_r(expr)
553
+ @nbuild[NS_EWS_TYPES].Not {
554
+ type = expr.keys.first
555
+ self.send(type, expr[type])
556
+ }
557
+ end
558
+
559
+ def contains(expr)
560
+ @nbuild[NS_EWS_TYPES].Contains(
561
+ 'ContainmentMode' => expr.delete(:containment_mode),
562
+ 'ContainmentComparison' => expr.delete(:containment_comparison)) {
563
+ c = expr.delete(:constant) # remove constant 1st for ordering
564
+ type = expr.keys.first
565
+ self.send(type, expr[type])
566
+ constant(c)
567
+ }
568
+ end
569
+
570
+ def excludes(expr)
571
+ @nbuild[NS_EWS_TYPES].Excludes {
572
+ b = expr.delete(:bitmask) # remove bitmask 1st for ordering
573
+ type = expr.keys.first
574
+ self.send(type, expr[type])
575
+ bitmask(b)
576
+ }
577
+ end
578
+
579
+ def exists(expr)
580
+ @nbuild[NS_EWS_TYPES].Exists {
581
+ type = expr.keys.first
582
+ self.send(type, expr[type])
583
+ }
584
+ end
585
+
586
+ def bitmask(expr)
587
+ @nbuild[NS_EWS_TYPES].Bitmask('Value' => expr[:value])
588
+ end
589
+
590
+ def is_equal_to(expr)
591
+ restriction_compare('IsEqualTo',expr)
592
+ end
593
+
594
+ def is_greater_than(expr)
595
+ restriction_compare('IsGreaterThan',expr)
596
+ end
597
+
598
+ def is_greater_than_or_equal_to(expr)
599
+ restriction_compare('IsGreaterThanOrEqualTo',expr)
600
+ end
601
+
602
+ def is_less_than(expr)
603
+ restriction_compare('IsLessThan',expr)
604
+ end
605
+
606
+ def is_less_than_or_equal_to(expr)
607
+ restriction_compare('IsLessThanOrEqualTo',expr)
608
+ end
609
+
610
+ def is_not_equal_to(expr)
611
+ restriction_compare('IsNotEqualTo',expr)
612
+ end
613
+
614
+ def restriction_compare(type,expr)
615
+ nbuild[NS_EWS_TYPES].send(type) {
616
+ expr.each do |e|
617
+ e.each_pair do |k,v|
618
+ self.send(k, v)
619
+ end
620
+ end
621
+ }
622
+ end
623
+
624
+ def field_uRI(expr)
625
+ nbuild[NS_EWS_TYPES].FieldURI('FieldURI' => expr[:field_uRI])
626
+ end
627
+
628
+ alias_method :field_uri, :field_uRI
629
+
630
+ def indexed_field_uRI(expr)
631
+ nbuild[NS_EWS_TYPES].IndexedFieldURI(
632
+ 'FieldURI' => expr[:field_uRI],
633
+ 'FieldIndex' => expr[:field_index]
634
+ )
635
+ end
636
+
637
+ alias_method :indexed_field_uri, :indexed_field_uRI
638
+
639
+ def extended_field_uRI(expr)
640
+ nbuild[NS_EWS_TYPES].ExtendedFieldURI {
641
+ nbuild.parent['DistinguishedPropertySetId'] = expr[:distinguished_property_set_id] if expr[:distinguished_property_set_id]
642
+ nbuild.parent['PropertySetId'] = expr[:property_set_id] if expr[:property_set_id]
643
+ nbuild.parent['PropertyTag'] = expr[:property_tag] if expr[:property_tag]
644
+ nbuild.parent['PropertyName'] = expr[:property_name] if expr[:property_name]
645
+ nbuild.parent['PropertyId'] = expr[:property_id] if expr[:property_id]
646
+ nbuild.parent['PropertyType'] = expr[:property_type] if expr[:property_type]
647
+ }
648
+ end
649
+
650
+ alias_method :extended_field_uri, :extended_field_uRI
651
+
652
+ def extended_properties!(eprops)
653
+ eprops.each {|ep| extended_property!(ep)}
654
+ end
655
+
656
+ def extended_property!(eprop)
657
+ nbuild[NS_EWS_TYPES].ExtendedProperty {
658
+ key = eprop.keys.grep(/extended/i).first
659
+ dispatch_field_uri!({key => eprop[key]}, NS_EWS_TYPES)
660
+ if eprop[:values]
661
+ nbuild.Values {
662
+ eprop[:values].each do |v|
663
+ value! v
664
+ end
665
+ }
666
+ elsif eprop[:value]
667
+ value! eprop[:value]
668
+ end
669
+ }
670
+ end
671
+
672
+ def value!(val)
673
+ nbuild[NS_EWS_TYPES].Value(val)
674
+ end
675
+
676
+ def field_uRI_or_constant(expr)
677
+ nbuild[NS_EWS_TYPES].FieldURIOrConstant {
678
+ type = expr.keys.first
679
+ self.send(type, expr[type])
680
+ }
681
+ end
682
+
683
+ alias_method :field_uri_or_constant, :field_uRI_or_constant
684
+
685
+ def constant(expr)
686
+ nbuild[NS_EWS_TYPES].Constant('Value' => expr[:value])
687
+ end
688
+
689
+ # Build the CalendarView element
690
+ def calendar_view!(cal_view)
691
+ attribs = {}
692
+ cal_view.each_pair {|k,v| attribs[camel_case(k)] = v.to_s}
693
+ @nbuild[NS_EWS_MESSAGES].CalendarView(attribs)
694
+ end
695
+
696
+ # Build the ContactsView element
697
+ def contacts_view!(con_view)
698
+ attribs = {}
699
+ con_view.each_pair {|k,v| attribs[camel_case(k)] = v.to_s}
700
+ @nbuild[NS_EWS_MESSAGES].ContactsView(attribs)
701
+ end
702
+
703
+ # @see http://msdn.microsoft.com/en-us/library/aa579678(v=EXCHG.140).aspx
704
+ def event_types!(evtypes)
705
+ @nbuild[NS_EWS_TYPES].EventTypes {
706
+ evtypes.each do |et|
707
+ @nbuild[NS_EWS_TYPES].EventType(camel_case(et))
708
+ end
709
+ }
710
+ end
711
+
712
+ # @see http://msdn.microsoft.com/en-us/library/aa565886(v=EXCHG.140).aspx
713
+ def watermark!(wmark, ns = NS_EWS_TYPES)
714
+ @nbuild[ns].Watermark(wmark)
715
+ end
716
+
717
+ # @see http://msdn.microsoft.com/en-us/library/aa565201(v=EXCHG.140).aspx
718
+ def timeout!(tout)
719
+ @nbuild[NS_EWS_TYPES].Timeout(tout)
720
+ end
721
+
722
+ # @see http://msdn.microsoft.com/en-us/library/aa564048(v=EXCHG.140).aspx
723
+ def status_frequency!(freq)
724
+ @nbuild[NS_EWS_TYPES].StatusFrequency(freq)
725
+ end
726
+
727
+ # @see http://msdn.microsoft.com/en-us/library/aa566309(v=EXCHG.140).aspx
728
+ def uRL!(url)
729
+ @nbuild[NS_EWS_TYPES].URL(url)
730
+ end
731
+
732
+ # @see http://msdn.microsoft.com/en-us/library/aa563790(v=EXCHG.140).aspx
733
+ def subscription_id!(subid)
734
+ @nbuild.SubscriptionId(subid)
735
+ end
736
+
737
+ # @see http://msdn.microsoft.com/en-us/library/aa563455(v=EXCHG.140).aspx
738
+ def pull_subscription_request(subopts)
739
+ subscribe_all = subopts[:subscribe_to_all_folders] ? 'true' : 'false'
740
+ @nbuild.PullSubscriptionRequest('SubscribeToAllFolders' => subscribe_all) {
741
+ folder_ids!(subopts[:folder_ids]) if subopts[:folder_ids]
742
+ event_types!(subopts[:event_types]) if subopts[:event_types]
743
+ watermark!(subopts[:watermark]) if subopts[:watermark]
744
+ timeout!(subopts[:timeout]) if subopts[:timeout]
745
+ }
746
+ end
747
+
748
+ # @see http://msdn.microsoft.com/en-us/library/aa563599(v=EXCHG.140).aspx
749
+ def push_subscription_request(subopts)
750
+ subscribe_all = subopts[:subscribe_to_all_folders] ? 'true' : 'false'
751
+ @nbuild.PushSubscriptionRequest('SubscribeToAllFolders' => subscribe_all) {
752
+ folder_ids!(subopts[:folder_ids]) if subopts[:folder_ids]
753
+ event_types!(subopts[:event_types]) if subopts[:event_types]
754
+ watermark!(subopts[:watermark]) if subopts[:watermark]
755
+ status_frequency!(subopts[:status_frequency]) if subopts[:status_frequency]
756
+ uRL!(subopts[:uRL]) if subopts[:uRL]
757
+ }
758
+ end
759
+
760
+ # @see http://msdn.microsoft.com/en-us/library/ff406182(v=EXCHG.140).aspx
761
+ def streaming_subscription_request(subopts)
762
+ subscribe_all = subopts[:subscribe_to_all_folders] ? 'true' : 'false'
763
+ @nbuild.StreamingSubscriptionRequest('SubscribeToAllFolders' => subscribe_all) {
764
+ folder_ids!(subopts[:folder_ids]) if subopts[:folder_ids]
765
+ event_types!(subopts[:event_types]) if subopts[:event_types]
766
+ }
767
+ end
768
+
769
+ # @see http://msdn.microsoft.com/en-us/library/aa565970(v=EXCHG.140).aspx
770
+ def sync_state!(syncstate)
771
+ @nbuild.SyncState(syncstate)
772
+ end
773
+
774
+ # @see http://msdn.microsoft.com/en-us/library/aa563785(v=EXCHG.140).aspx
775
+ def ignore!(item_ids)
776
+ @nbuild.Ignore {
777
+ item_ids.each do |iid|
778
+ item_id!(iid)
779
+ end
780
+ }
781
+ end
782
+
783
+ # @see http://msdn.microsoft.com/en-us/library/aa566325(v=EXCHG.140).aspx
784
+ def max_changes_returned!(cnum)
785
+ @nbuild[NS_EWS_MESSAGES].MaxChangesReturned(cnum)
786
+ end
787
+
788
+ # @see http://msdn.microsoft.com/en-us/library/dd899531(v=EXCHG.140).aspx
789
+ def sync_scope!(scope)
790
+ @nbuild.SyncScope(scope)
791
+ end
792
+
793
+ # @see http://msdn.microsoft.com/en-us/library/aa580758(v=EXCHG.140).aspx
794
+ def saved_item_folder_id!(fid)
795
+ @nbuild.SavedItemFolderId {
796
+ dispatch_folder_id!(fid)
797
+ }
798
+ end
799
+
800
+ # @see http://msdn.microsoft.com/en-us/library/aa565652(v=exchg.140).aspx
801
+ def item!(item)
802
+ nbuild.Item {
803
+ item.each_pair {|k,v|
804
+ self.send("#{k}!", v)
805
+ }
806
+ }
807
+ end
808
+
809
+ def message!(item)
810
+ nbuild[NS_EWS_TYPES].Message {
811
+ if item[:extended_properties]
812
+ extended_properties! item.delete(:extended_properties)
813
+ end
814
+ item.each_pair {|k,v|
815
+ self.send("#{k}!", v)
816
+ }
817
+ }
818
+ end
819
+
820
+ def calendar_item!(item)
821
+ nbuild[NS_EWS_TYPES].CalendarItem {
822
+ item.each_pair {|k,v|
823
+ self.send("#{k}!", v)
824
+ }
825
+ }
826
+ end
827
+
828
+ def task!(item)
829
+ nbuild[NS_EWS_TYPES].Task {
830
+ item.each_pair {|k,v|
831
+ self.send("#{k}!", v)
832
+ }
833
+ }
834
+ end
835
+
836
+ def forward_item!(item)
837
+ nbuild[NS_EWS_TYPES].ForwardItem {
838
+ item.each_pair {|k,v|
839
+ self.send("#{k}!", v)
840
+ }
841
+ }
842
+ end
843
+
844
+ def reply_to_item!(item)
845
+ nbuild[NS_EWS_TYPES].ReplyToItem {
846
+ item.each_pair {|k,v|
847
+ self.send("#{k}!", v)
848
+ }
849
+ }
850
+ end
851
+
852
+ def reply_all_to_item!(item)
853
+ nbuild[NS_EWS_TYPES].ReplyAllToItem {
854
+ item.each_pair {|k,v|
855
+ self.send("#{k}!", v)
856
+ }
857
+ }
858
+ end
859
+
860
+ def reference_item_id!(id)
861
+ nbuild[NS_EWS_TYPES].ReferenceItemId {|x|
862
+ x.parent['Id'] = id[:id]
863
+ x.parent['ChangeKey'] = id[:change_key] if id[:change_key]
864
+ }
865
+ end
866
+
867
+ def subject!(sub)
868
+ nbuild[NS_EWS_TYPES].Subject(sub)
869
+ end
870
+
871
+ def importance!(sub)
872
+ nbuild[NS_EWS_TYPES].Importance(sub)
873
+ end
874
+
875
+ def body!(b)
876
+ nbuild[NS_EWS_TYPES].Body(b[:text]) {|x|
877
+ x.parent['BodyType'] = b[:body_type] if b[:body_type]
878
+ }
879
+ end
880
+
881
+ def new_body_content!(b)
882
+ nbuild[NS_EWS_TYPES].NewBodyContent(b[:text]) {|x|
883
+ x.parent['BodyType'] = b[:body_type] if b[:body_type]
884
+ }
885
+ end
886
+
887
+ # @see http://msdn.microsoft.com/en-us/library/aa563719(v=exchg.140).aspx
888
+ # @param [Array] r An array of Mailbox type hashes to send to #mailbox!
889
+ def to_recipients!(r)
890
+ nbuild[NS_EWS_TYPES].ToRecipients {
891
+ r.each {|mbox| mailbox!(mbox[:mailbox]) }
892
+ }
893
+ end
894
+
895
+ def cc_recipients!(r)
896
+ nbuild[NS_EWS_TYPES].CcRecipients {
897
+ r.each {|mbox| mailbox!(mbox[:mailbox]) }
898
+ }
899
+ end
900
+
901
+ def bcc_recipients!(r)
902
+ nbuild[NS_EWS_TYPES].BccRecipients {
903
+ r.each {|mbox| mailbox!(mbox[:mailbox]) }
904
+ }
905
+ end
906
+
907
+ def from!(f)
908
+ nbuild[NS_EWS_TYPES].From {
909
+ mailbox! f
910
+ }
911
+ end
912
+
913
+ def required_attendees!(attendees)
914
+ nbuild[NS_EWS_TYPES].RequiredAttendees {
915
+ attendees.each {|a| attendee!(a[:attendee])}
916
+ }
917
+ end
918
+
919
+ def optional_attendees!(attendees)
920
+ nbuild[NS_EWS_TYPES].OptionalAttendees {
921
+ attendees.each {|a| attendee!(a[:attendee])}
922
+ }
923
+ end
924
+
925
+ def resources!(attendees)
926
+ nbuild[NS_EWS_TYPES].Resources {
927
+ attendees.each {|a| attendee!(a[:attendee])}
928
+ }
929
+ end
930
+
931
+ # @todo support ResponseType, LastResponseTime: http://msdn.microsoft.com/en-us/library/aa580339.aspx
932
+ def attendee!(a)
933
+ nbuild[NS_EWS_TYPES].Attendee {
934
+ mailbox!(a[:mailbox])
935
+ }
936
+ end
937
+
938
+ def start!(st)
939
+ nbuild[NS_EWS_TYPES].Start(st[:text])
940
+ end
941
+
942
+ def end!(et)
943
+ nbuild[NS_EWS_TYPES].End(et[:text])
944
+ end
945
+
946
+ def start_date!(sd)
947
+ nbuild[NS_EWS_TYPES].StartDate format_time(sd[:text])
948
+ end
949
+
950
+ def due_date!(dd)
951
+ nbuild[NS_EWS_TYPES].DueDate format_time(dd[:text])
952
+ end
953
+
954
+ def location!(loc)
955
+ nbuild[NS_EWS_TYPES].Location(loc)
956
+ end
957
+
958
+ def is_all_day_event!(all_day)
959
+ nbuild[NS_EWS_TYPES].IsAllDayEvent(all_day)
960
+ end
961
+
962
+ def reminder_is_set!(reminder)
963
+ nbuild[NS_EWS_TYPES].ReminderIsSet reminder
964
+ end
965
+
966
+ def reminder_due_by!(date)
967
+ nbuild[NS_EWS_TYPES].ReminderDueBy format_time(date)
968
+ end
969
+
970
+ def reminder_minutes_before_start!(minutes)
971
+ nbuild[NS_EWS_TYPES].ReminderMinutesBeforeStart minutes
972
+ end
973
+
974
+ # @see http://msdn.microsoft.com/en-us/library/aa566143(v=exchg.150).aspx
975
+ # possible values Exchange Server 2010 = [Free, Tentative, Busy, OOF, NoData]
976
+ # Exchange Server 2013 = [Free, Tentative, Busy, OOF, WorkingElsewhere, NoData]
977
+ def legacy_free_busy_status!(state)
978
+ nbuild[NS_EWS_TYPES].LegacyFreeBusyStatus(state)
979
+ end
980
+
981
+ # @see http://msdn.microsoft.com/en-us/library/aa565428(v=exchg.140).aspx
982
+ def item_changes!(changes)
983
+ nbuild.ItemChanges {
984
+ changes.each do |chg|
985
+ item_change!(chg)
986
+ end
987
+ }
988
+ end
989
+
990
+ # @see http://msdn.microsoft.com/en-us/library/aa581081(v=exchg.140).aspx
991
+ def item_change!(change)
992
+ @nbuild[NS_EWS_TYPES].ItemChange {
993
+ updates = change.delete(:updates) # Remove updates so dispatch_item_id works correctly
994
+ dispatch_item_id!(change)
995
+ updates!(updates)
996
+ }
997
+ end
998
+
999
+ # @see http://msdn.microsoft.com/en-us/library/aa581074(v=exchg.140).aspx
1000
+ def updates!(updates)
1001
+ @nbuild[NS_EWS_TYPES].Updates {
1002
+ updates.each do |update|
1003
+ dispatch_update_type!(update)
1004
+ end
1005
+ }
1006
+ end
1007
+
1008
+ # @see http://msdn.microsoft.com/en-us/library/aa581317(v=exchg.140).aspx
1009
+ def append_to_item_field!(upd)
1010
+ uri = upd.select {|k,v| k =~ /_uri/i}
1011
+ raise EwsBadArgumentError, "Bad argument given for AppendToItemField." if uri.keys.length != 1
1012
+ upd.delete(uri.keys.first)
1013
+ @nbuild.AppendToItemField {
1014
+ dispatch_field_uri!(uri)
1015
+ dispatch_field_item!(upd)
1016
+ }
1017
+ end
1018
+
1019
+ # @see http://msdn.microsoft.com/en-us/library/aa581487(v=exchg.140).aspx
1020
+ def set_item_field!(upd)
1021
+ uri = upd.select {|k,v| k =~ /_uri/i}
1022
+ raise EwsBadArgumentError, "Bad argument given for SetItemField." if uri.keys.length != 1
1023
+ upd.delete(uri.keys.first)
1024
+ @nbuild[NS_EWS_TYPES].SetItemField {
1025
+ dispatch_field_uri!(uri, NS_EWS_TYPES)
1026
+ dispatch_field_item!(upd, NS_EWS_TYPES)
1027
+ }
1028
+ end
1029
+
1030
+ # @see http://msdn.microsoft.com/en-us/library/aa580330(v=exchg.140).aspx
1031
+ def delete_item_field!(upd)
1032
+ uri = upd.select {|k,v| k =~ /_uri/i}
1033
+ raise EwsBadArgumentError, "Bad argument given for SetItemField." if uri.keys.length != 1
1034
+ @nbuild[NS_EWS_TYPES].DeleteItemField {
1035
+ dispatch_field_uri!(uri, NS_EWS_TYPES)
1036
+ }
1037
+ end
1038
+
1039
+ # @see http://msdn.microsoft.com/en-us/library/ff709497(v=exchg.140).aspx
1040
+ def return_new_item_ids!(retval)
1041
+ @nbuild.ReturnNewItemIds(retval)
1042
+ end
1043
+
1044
+ def inline_attachment!(fa)
1045
+ @nbuild[NS_EWS_TYPES].FileAttachment {
1046
+ @nbuild[NS_EWS_TYPES].Name(fa.name)
1047
+ @nbuild[NS_EWS_TYPES].ContentId(fa.name)
1048
+ @nbuild[NS_EWS_TYPES].IsInline(true)
1049
+ @nbuild[NS_EWS_TYPES].Content(fa.content)
1050
+ }
1051
+ end
1052
+
1053
+ def file_attachment!(fa)
1054
+ @nbuild[NS_EWS_TYPES].FileAttachment {
1055
+ @nbuild[NS_EWS_TYPES].Name(fa.name)
1056
+ @nbuild[NS_EWS_TYPES].Content(fa.content)
1057
+ }
1058
+ end
1059
+
1060
+ def item_attachment!(ia)
1061
+ @nbuild[NS_EWS_TYPES].ItemAttachment {
1062
+ @nbuild[NS_EWS_TYPES].Name(ia.name)
1063
+ @nbuild[NS_EWS_TYPES].Item {
1064
+ item_id!(ia.item)
1065
+ }
1066
+ }
1067
+ end
1068
+
1069
+ # Build the AttachmentIds element
1070
+ # @see http://msdn.microsoft.com/en-us/library/aa580686.aspx
1071
+ def attachment_ids!(aids)
1072
+ @nbuild.AttachmentIds {
1073
+ @nbuild.parent.default_namespace = @default_ns
1074
+ aids.each do |aid|
1075
+ attachment_id!(aid)
1076
+ end
1077
+ }
1078
+ end
1079
+
1080
+ # Build the AttachmentId element
1081
+ # @see http://msdn.microsoft.com/en-us/library/aa580764.aspx
1082
+ def attachment_id!(aid)
1083
+ attribs = {'Id' => aid}
1084
+ @nbuild[NS_EWS_TYPES].AttachmentId(attribs)
1085
+ end
1086
+
1087
+ def user_configuration_name!(cfg_name)
1088
+ attribs = {'Name' => cfg_name.delete(:name)}
1089
+ @nbuild[NS_EWS_MESSAGES].UserConfigurationName(attribs) {
1090
+ fid = cfg_name.keys.first
1091
+ self.send "#{fid}!", cfg_name[fid][:id], cfg_name[fid][:change_key]
1092
+ }
1093
+ end
1094
+
1095
+ def user_configuration_properties!(cfg_prop)
1096
+ @nbuild[NS_EWS_MESSAGES].UserConfigurationProperties(cfg_prop)
1097
+ end
1098
+
1099
+ # ---------------------- Helpers -------------------- #
1100
+
1101
+ # A helper method to dispatch to a FolderId or DistinguishedFolderId correctly
1102
+ # @param [Hash] fid A folder_id
1103
+ # Ex: {:id => myid, :change_key => ck}
1104
+ def dispatch_folder_id!(fid)
1105
+ if(fid[:id].is_a?(String))
1106
+ folder_id!(fid[:id], fid[:change_key])
1107
+ elsif(fid[:id].is_a?(Symbol))
1108
+ distinguished_folder_id!(fid[:id], fid[:change_key], fid[:act_as])
1109
+ else
1110
+ raise EwsBadArgumentError, "Bad argument given for a FolderId. #{fid[:id].class}"
1111
+ end
1112
+ end
1113
+
1114
+ # A helper method to dispatch to an ItemId, OccurrenceItemId, or a RecurringMasterItemId
1115
+ # @param [Hash] iid The item id of some type
1116
+ def dispatch_item_id!(iid)
1117
+ type = iid.keys.first
1118
+ item = iid[type]
1119
+ case type
1120
+ when :item_id
1121
+ item_id!(item)
1122
+ when :occurrence_item_id
1123
+ occurrence_item_id!(
1124
+ item[:recurring_master_id], item[:change_key], item[:instance_index])
1125
+ when :recurring_master_item_id
1126
+ recurring_master_item_id!(item[:occurrence_id], item[:change_key])
1127
+ else
1128
+ raise EwsBadArgumentError, "Bad ItemId type. #{type}"
1129
+ end
1130
+ end
1131
+
1132
+ # A helper method to dispatch to a AppendToItemField, SetItemField, or
1133
+ # DeleteItemField
1134
+ # @param [Hash] update An update of some type
1135
+ def dispatch_update_type!(update)
1136
+ type = update.keys.first
1137
+ upd = update[type]
1138
+ case type
1139
+ when :append_to_item_field
1140
+ append_to_item_field!(upd)
1141
+ when :set_item_field
1142
+ set_item_field!(upd)
1143
+ when :delete_item_field
1144
+ delete_item_field!(upd)
1145
+ else
1146
+ raise EwsBadArgumentError, "Bad Update type. #{type}"
1147
+ end
1148
+ end
1149
+
1150
+ # A helper to dispatch to a FieldURI, IndexedFieldURI, or an ExtendedFieldURI
1151
+ # @todo Implement ExtendedFieldURI
1152
+ def dispatch_field_uri!(uri, ns=NS_EWS_MESSAGES)
1153
+ type = uri.keys.first
1154
+ vals = uri[type].is_a?(Array) ? uri[type] : [uri[type]]
1155
+ case type
1156
+ when :field_uRI, :field_uri
1157
+ vals.each do |val|
1158
+ nbuild[ns].FieldURI('FieldURI' => val[type])
1159
+ end
1160
+ when :indexed_field_uRI, :indexed_field_uri
1161
+ vals.each do |val|
1162
+ nbuild[ns].IndexedFieldURI('FieldURI' => val[:field_uRI], 'FieldIndex' => val[:field_index])
1163
+ end
1164
+ when :extended_field_uRI, :extended_field_uri
1165
+ vals.each do |val|
1166
+ nbuild[ns].ExtendedFieldURI {
1167
+ nbuild.parent['DistinguishedPropertySetId'] = val[:distinguished_property_set_id] if val[:distinguished_property_set_id]
1168
+ nbuild.parent['PropertySetId'] = val[:property_set_id] if val[:property_set_id]
1169
+ nbuild.parent['PropertyTag'] = val[:property_tag] if val[:property_tag]
1170
+ nbuild.parent['PropertyName'] = val[:property_name] if val[:property_name]
1171
+ nbuild.parent['PropertyId'] = val[:property_id] if val[:property_id]
1172
+ nbuild.parent['PropertyType'] = val[:property_type] if val[:property_type]
1173
+ }
1174
+ end
1175
+ else
1176
+ raise EwsBadArgumentError, "Bad URI type. #{type}"
1177
+ end
1178
+ end
1179
+
1180
+ # Insert item, enforce xmlns attribute if prefix is present
1181
+ def dispatch_field_item!(item, ns_prefix = nil)
1182
+ item.values.first[:xmlns_attribute] = ns_prefix if ns_prefix
1183
+ build_xml!(item)
1184
+ end
1185
+
1186
+ def room_list!(cfg_prop)
1187
+ @nbuild[NS_EWS_MESSAGES].RoomList {
1188
+ email_address!(cfg_prop)
1189
+ }
1190
+ end
1191
+
1192
+ def room_lists!
1193
+ @nbuild[NS_EWS_MESSAGES].GetRoomLists
1194
+ end
1195
+
1196
+
1197
+ private
1198
+
1199
+ def parent_namespace(node)
1200
+ node.parent.namespace_definitions.find {|ns| ns.prefix == NS_SOAP}
1201
+ end
1202
+
1203
+ def set_version_header!(version)
1204
+ if version && !(version == 'none')
1205
+ nbuild[NS_EWS_TYPES].RequestServerVersion {|x|
1206
+ x.parent['Version'] = version
1207
+ }
1208
+ end
1209
+ end
1210
+
1211
+ def set_impersonation!(type, address)
1212
+ if type && type != ""
1213
+ nbuild[NS_EWS_TYPES].ExchangeImpersonation {
1214
+ nbuild[NS_EWS_TYPES].ConnectingSID {
1215
+ nbuild[NS_EWS_TYPES].method_missing type, address
1216
+ }
1217
+ }
1218
+ end
1219
+ end
1220
+
1221
+ # Set TimeZoneContext Header
1222
+ # @param time_zone_def [Hash] !{id: time_zone_identifier, name: time_zone_name}
1223
+ def set_time_zone_context_header!(time_zone_def)
1224
+ if time_zone_def
1225
+ nbuild[NS_EWS_TYPES].TimeZoneContext do
1226
+ time_zone_definition! time_zone_def
1227
+ end
1228
+ end
1229
+ end
1230
+
1231
+ # some methods need special naming so they use the '_r' suffix like 'and'
1232
+ def normalize_type(type)
1233
+ case type
1234
+ when :and, :or, :not
1235
+ "#{type}_r".to_sym
1236
+ else
1237
+ type
1238
+ end
1239
+ end
1240
+
1241
+ def format_time(time)
1242
+ case time
1243
+ when Time, Date, DateTime
1244
+ time.to_datetime.new_offset(0).iso8601
1245
+ when String
1246
+ begin
1247
+ DateTime.parse(time).new_offset(0).iso8601
1248
+ rescue ArgumentError
1249
+ raise EwsBadArgumentError, "Invalid Time argument (#{time})"
1250
+ end
1251
+ else
1252
+ raise EwsBadArgumentError, "Invalid Time argument (#{time})"
1253
+ end
1254
+ end
1255
+
1256
+ end # EwsBuilder
1257
+ end # Viewpoint::EWS::SOAP