viewpoint_reloaded 1.0.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 (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 +34 -0
  6. data/lib/ews/connection.rb +130 -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 +103 -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.rb +64 -0
  21. data/lib/ews/soap/builders/ews_builder.rb +1266 -0
  22. data/lib/ews/soap/ews_response.rb +84 -0
  23. data/lib/ews/soap/ews_soap_availability_response.rb +58 -0
  24. data/lib/ews/soap/ews_soap_free_busy_response.rb +119 -0
  25. data/lib/ews/soap/ews_soap_response.rb +103 -0
  26. data/lib/ews/soap/ews_soap_room_response.rb +53 -0
  27. data/lib/ews/soap/ews_soap_roomlist_response.rb +54 -0
  28. data/lib/ews/soap/exchange_availability.rb +61 -0
  29. data/lib/ews/soap/exchange_data_services.rb +780 -0
  30. data/lib/ews/soap/exchange_notification.rb +146 -0
  31. data/lib/ews/soap/exchange_synchronization.rb +93 -0
  32. data/lib/ews/soap/exchange_time_zones.rb +56 -0
  33. data/lib/ews/soap/exchange_user_configuration.rb +33 -0
  34. data/lib/ews/soap/exchange_web_service.rb +264 -0
  35. data/lib/ews/soap/parsers/ews_parser.rb +43 -0
  36. data/lib/ews/soap/parsers/ews_sax_document.rb +70 -0
  37. data/lib/ews/soap/response_message.rb +80 -0
  38. data/lib/ews/soap/responses/create_attachment_response_message.rb +47 -0
  39. data/lib/ews/soap/responses/create_item_response_message.rb +25 -0
  40. data/lib/ews/soap/responses/find_item_response_message.rb +80 -0
  41. data/lib/ews/soap/responses/get_events_response_message.rb +53 -0
  42. data/lib/ews/soap/responses/send_notification_response_message.rb +59 -0
  43. data/lib/ews/soap/responses/subscribe_response_message.rb +35 -0
  44. data/lib/ews/soap/responses/sync_folder_hierarchy_response_message.rb +36 -0
  45. data/lib/ews/soap/responses/sync_folder_items_response_message.rb +36 -0
  46. data/lib/ews/templates/calendar_item.rb +79 -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.rb +194 -0
  52. data/lib/ews/types/attachment.rb +77 -0
  53. data/lib/ews/types/attendee.rb +27 -0
  54. data/lib/ews/types/calendar_folder.rb +50 -0
  55. data/lib/ews/types/calendar_item.rb +130 -0
  56. data/lib/ews/types/contact.rb +7 -0
  57. data/lib/ews/types/contacts_folder.rb +8 -0
  58. data/lib/ews/types/copied_event.rb +51 -0
  59. data/lib/ews/types/created_event.rb +24 -0
  60. data/lib/ews/types/deleted_event.rb +24 -0
  61. data/lib/ews/types/distribution_list.rb +7 -0
  62. data/lib/ews/types/event.rb +62 -0
  63. data/lib/ews/types/export_items_response_message.rb +52 -0
  64. data/lib/ews/types/file_attachment.rb +65 -0
  65. data/lib/ews/types/folder.rb +60 -0
  66. data/lib/ews/types/free_busy_changed_event.rb +24 -0
  67. data/lib/ews/types/generic_folder.rb +418 -0
  68. data/lib/ews/types/item.rb +441 -0
  69. data/lib/ews/types/item_attachment.rb +84 -0
  70. data/lib/ews/types/item_field_uri_map.rb +208 -0
  71. data/lib/ews/types/mailbox_user.rb +156 -0
  72. data/lib/ews/types/meeting_cancellation.rb +7 -0
  73. data/lib/ews/types/meeting_message.rb +7 -0
  74. data/lib/ews/types/meeting_request.rb +7 -0
  75. data/lib/ews/types/meeting_response.rb +7 -0
  76. data/lib/ews/types/message.rb +7 -0
  77. data/lib/ews/types/modified_event.rb +48 -0
  78. data/lib/ews/types/moved_event.rb +51 -0
  79. data/lib/ews/types/new_mail_event.rb +24 -0
  80. data/lib/ews/types/out_of_office.rb +147 -0
  81. data/lib/ews/types/search_folder.rb +8 -0
  82. data/lib/ews/types/status_event.rb +39 -0
  83. data/lib/ews/types/task.rb +41 -0
  84. data/lib/ews/types/tasks_folder.rb +27 -0
  85. data/lib/viewpoint.rb +109 -0
  86. data/lib/viewpoint/logging.rb +27 -0
  87. data/lib/viewpoint/logging/config.rb +24 -0
  88. data/lib/viewpoint/string_utils.rb +76 -0
  89. metadata +192 -0
@@ -0,0 +1,48 @@
1
+ =begin
2
+ This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services.
3
+
4
+ Copyright © 2013 Camille Baldock <viewpoint@camillebaldock.co.uk>
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::RoomAccessors
20
+ include Viewpoint::EWS
21
+
22
+ # Gets the rooms that are available within the specified room distribution list
23
+ # @see http://msdn.microsoft.com/en-us/library/dd899415.aspx
24
+ # @param [String] roomDistributionList
25
+ def get_rooms(roomDistributionList)
26
+ resp = ews.get_rooms(roomDistributionList)
27
+ get_rooms_parser(resp)
28
+ end
29
+
30
+ def room_name( room )
31
+ room[:room][:elems][:id][:elems][0][:name][:text]
32
+ end
33
+
34
+ def room_email( room )
35
+ room[:room][:elems][:id][:elems][1][:email_address][:text]
36
+ end
37
+
38
+ private
39
+
40
+ def get_rooms_parser(resp)
41
+ if resp.success?
42
+ resp
43
+ else
44
+ raise EwsError, "GetRooms produced an error: #{resp.code}: #{resp.message}"
45
+ end
46
+ end
47
+
48
+ end # Viewpoint::EWS::RoomAccessors
@@ -0,0 +1,47 @@
1
+ =begin
2
+ This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services.
3
+
4
+ Copyright © 2013 Camille Baldock <viewpoint@camillebaldock.co.uk>
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::RoomlistAccessors
20
+ include Viewpoint::EWS
21
+
22
+ # Gets the room lists that are available within the Exchange organization.
23
+ # @see http://msdn.microsoft.com/en-us/library/dd899416.aspx
24
+ def get_room_lists
25
+ resp = ews.get_room_lists
26
+ get_room_lists_parser(resp)
27
+ end
28
+
29
+ def roomlist_name( roomlist )
30
+ roomlist[:address][:elems][:name][:text]
31
+ end
32
+
33
+ def roomlist_email( roomlist )
34
+ roomlist[:address][:elems][:email_address][:text]
35
+ end
36
+
37
+ private
38
+
39
+ def get_room_lists_parser(resp)
40
+ if resp.success?
41
+ resp
42
+ else
43
+ raise EwsError, "GetRoomLists produced an error: #{resp.code}: #{resp.message}"
44
+ end
45
+ end
46
+
47
+ end # Viewpoint::EWS::RoomlistAccessors
@@ -0,0 +1,64 @@
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
+ # This module defines some constants and other niceties to make available to
20
+ # the underlying SOAP classes and modules that do the actual work.
21
+ module Viewpoint
22
+ module EWS
23
+ module SOAP
24
+
25
+ # CONSTANTS
26
+
27
+ NS_SOAP = 'soap'.freeze
28
+ NS_EWS_TYPES = 't'.freeze
29
+ NS_EWS_MESSAGES = 'm'.freeze
30
+ NAMESPACES = {
31
+ "xmlns:#{NS_SOAP}" => 'http://schemas.xmlsoap.org/soap/envelope/',
32
+ "xmlns:#{NS_EWS_TYPES}" => 'http://schemas.microsoft.com/exchange/services/2006/types',
33
+ "xmlns:#{NS_EWS_MESSAGES}" => 'http://schemas.microsoft.com/exchange/services/2006/messages',
34
+ }.freeze
35
+
36
+ # used in ResolveNames to determine where names are resolved
37
+ ActiveDirectory = 'ActiveDirectory'
38
+ ActiveDirectoryContacts = 'ActiveDirectoryContacts'
39
+ Contacts = 'Contacts'
40
+ ContactsActiveDirectory = 'ContactsActiveDirectory'
41
+
42
+ # Target specific Exchange Server versions
43
+ # @see http://msdn.microsoft.com/en-us/library/bb891876(v=exchg.140).aspx
44
+ VERSION_2007 = 'Exchange2007'
45
+ VERSION_2007_SP1 = 'Exchange2007_SP1'
46
+ VERSION_2010 = 'Exchange2010'
47
+ VERSION_2010_SP1 = 'Exchange2010_SP1'
48
+ VERSION_2010_SP2 = 'Exchange2010_SP2'
49
+ VERSION_2013 = 'Exchange2013'
50
+ VERSION_2013_SP1 = 'Exchange2013_SP1'
51
+ VERSION_NONE = 'none'
52
+
53
+ HARD_DELETE = 'HardDelete'
54
+ SOFT_DELETE = 'SoftDelete'
55
+ MOVE_TO_DELETED_ITEMS = 'MoveToDeletedItems'
56
+
57
+ def initialize
58
+ @log = Logging.logger[self.class.name.to_s.to_sym]
59
+ @default_ns = NAMESPACES["xmlns:#{NS_EWS_MESSAGES}"]
60
+ end
61
+
62
+ end # SOAP
63
+ end # EWS
64
+ end # Viewpoint
@@ -0,0 +1,1266 @@
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 ews_types_builder
625
+ nbuild[NS_EWS_TYPES]
626
+ end
627
+
628
+ def field_uRI(expr)
629
+ value = expr.is_a?(Hash) ? (expr[:field_uRI] || expr[:field_uri]) : expr
630
+ ews_types_builder.FieldURI('FieldURI' => value)
631
+ end
632
+
633
+ alias_method :field_uri, :field_uRI
634
+
635
+ def indexed_field_uRI(expr)
636
+ nbuild[NS_EWS_TYPES].IndexedFieldURI(
637
+ 'FieldURI' => (expr[:field_uRI] || expr[:field_uri]),
638
+ 'FieldIndex' => expr[:field_index]
639
+ )
640
+ end
641
+
642
+ alias_method :indexed_field_uri, :indexed_field_uRI
643
+
644
+ def extended_field_uRI(expr)
645
+ nbuild[NS_EWS_TYPES].ExtendedFieldURI {
646
+ nbuild.parent['DistinguishedPropertySetId'] = expr[:distinguished_property_set_id] if expr[:distinguished_property_set_id]
647
+ nbuild.parent['PropertySetId'] = expr[:property_set_id] if expr[:property_set_id]
648
+ nbuild.parent['PropertyTag'] = expr[:property_tag] if expr[:property_tag]
649
+ nbuild.parent['PropertyName'] = expr[:property_name] if expr[:property_name]
650
+ nbuild.parent['PropertyId'] = expr[:property_id] if expr[:property_id]
651
+ nbuild.parent['PropertyType'] = expr[:property_type] if expr[:property_type]
652
+ }
653
+ end
654
+
655
+ alias_method :extended_field_uri, :extended_field_uRI
656
+
657
+ def extended_properties!(eprops)
658
+ eprops.each {|ep| extended_property!(ep)}
659
+ end
660
+
661
+ def extended_property!(eprop)
662
+ nbuild[NS_EWS_TYPES].ExtendedProperty {
663
+ key = eprop.keys.grep(/extended/i).first
664
+ dispatch_field_uri!({key => eprop[key]}, NS_EWS_TYPES)
665
+ if eprop[:values]
666
+ nbuild.Values {
667
+ eprop[:values].each do |v|
668
+ value! v
669
+ end
670
+ }
671
+ elsif eprop[:value]
672
+ value! eprop[:value]
673
+ end
674
+ }
675
+ end
676
+
677
+ def value!(val)
678
+ nbuild[NS_EWS_TYPES].Value(val)
679
+ end
680
+
681
+ def field_uRI_or_constant(expr)
682
+ nbuild[NS_EWS_TYPES].FieldURIOrConstant {
683
+ type = expr.keys.first
684
+ self.send(type, expr[type])
685
+ }
686
+ end
687
+
688
+ alias_method :field_uri_or_constant, :field_uRI_or_constant
689
+
690
+ def constant(expr)
691
+ nbuild[NS_EWS_TYPES].Constant('Value' => expr[:value])
692
+ end
693
+
694
+ # Build the CalendarView element
695
+ def calendar_view!(cal_view)
696
+ attribs = {}
697
+ cal_view.each_pair {|k,v| attribs[camel_case(k)] = v.to_s}
698
+ @nbuild[NS_EWS_MESSAGES].CalendarView(attribs)
699
+ end
700
+
701
+ # Build the ContactsView element
702
+ def contacts_view!(con_view)
703
+ attribs = {}
704
+ con_view.each_pair {|k,v| attribs[camel_case(k)] = v.to_s}
705
+ @nbuild[NS_EWS_MESSAGES].ContactsView(attribs)
706
+ end
707
+
708
+ # @see http://msdn.microsoft.com/en-us/library/aa579678(v=EXCHG.140).aspx
709
+ def event_types!(evtypes)
710
+ @nbuild[NS_EWS_TYPES].EventTypes {
711
+ evtypes.each do |et|
712
+ @nbuild[NS_EWS_TYPES].EventType(camel_case(et))
713
+ end
714
+ }
715
+ end
716
+
717
+ # @see http://msdn.microsoft.com/en-us/library/aa565886(v=EXCHG.140).aspx
718
+ def watermark!(wmark, ns = NS_EWS_TYPES)
719
+ @nbuild[ns].Watermark(wmark)
720
+ end
721
+
722
+ # @see http://msdn.microsoft.com/en-us/library/aa565201(v=EXCHG.140).aspx
723
+ def timeout!(tout)
724
+ @nbuild[NS_EWS_TYPES].Timeout(tout)
725
+ end
726
+
727
+ # @see http://msdn.microsoft.com/en-us/library/aa564048(v=EXCHG.140).aspx
728
+ def status_frequency!(freq)
729
+ @nbuild[NS_EWS_TYPES].StatusFrequency(freq)
730
+ end
731
+
732
+ # @see http://msdn.microsoft.com/en-us/library/aa566309(v=EXCHG.140).aspx
733
+ def uRL!(url)
734
+ @nbuild[NS_EWS_TYPES].URL(url)
735
+ end
736
+
737
+ # @see http://msdn.microsoft.com/en-us/library/aa563790(v=EXCHG.140).aspx
738
+ def subscription_id!(subid)
739
+ @nbuild.SubscriptionId(subid)
740
+ end
741
+
742
+ # @see http://msdn.microsoft.com/en-us/library/aa563455(v=EXCHG.140).aspx
743
+ def pull_subscription_request(subopts)
744
+ subscribe_all = subopts[:subscribe_to_all_folders] ? 'true' : 'false'
745
+ @nbuild.PullSubscriptionRequest('SubscribeToAllFolders' => subscribe_all) {
746
+ folder_ids!(subopts[:folder_ids]) if subopts[:folder_ids]
747
+ event_types!(subopts[:event_types]) if subopts[:event_types]
748
+ watermark!(subopts[:watermark]) if subopts[:watermark]
749
+ timeout!(subopts[:timeout]) if subopts[:timeout]
750
+ }
751
+ end
752
+
753
+ # @see http://msdn.microsoft.com/en-us/library/aa563599(v=EXCHG.140).aspx
754
+ def push_subscription_request(subopts)
755
+ subscribe_all = subopts[:subscribe_to_all_folders] ? 'true' : 'false'
756
+ @nbuild.PushSubscriptionRequest('SubscribeToAllFolders' => subscribe_all) {
757
+ folder_ids!(subopts[:folder_ids]) if subopts[:folder_ids]
758
+ event_types!(subopts[:event_types]) if subopts[:event_types]
759
+ watermark!(subopts[:watermark]) if subopts[:watermark]
760
+ status_frequency!(subopts[:status_frequency]) if subopts[:status_frequency]
761
+ uRL!(subopts[:uRL]) if subopts[:uRL]
762
+ }
763
+ end
764
+
765
+ # @see http://msdn.microsoft.com/en-us/library/ff406182(v=EXCHG.140).aspx
766
+ def streaming_subscription_request(subopts)
767
+ subscribe_all = subopts[:subscribe_to_all_folders] ? 'true' : 'false'
768
+ @nbuild.StreamingSubscriptionRequest('SubscribeToAllFolders' => subscribe_all) {
769
+ folder_ids!(subopts[:folder_ids]) if subopts[:folder_ids]
770
+ event_types!(subopts[:event_types]) if subopts[:event_types]
771
+ }
772
+ end
773
+
774
+ # @see http://msdn.microsoft.com/en-us/library/aa565970(v=EXCHG.140).aspx
775
+ def sync_state!(syncstate)
776
+ @nbuild.SyncState(syncstate)
777
+ end
778
+
779
+ # @see http://msdn.microsoft.com/en-us/library/aa563785(v=EXCHG.140).aspx
780
+ def ignore!(item_ids)
781
+ @nbuild.Ignore {
782
+ item_ids.each do |iid|
783
+ item_id!(iid)
784
+ end
785
+ }
786
+ end
787
+
788
+ # @see http://msdn.microsoft.com/en-us/library/aa566325(v=EXCHG.140).aspx
789
+ def max_changes_returned!(cnum)
790
+ @nbuild[NS_EWS_MESSAGES].MaxChangesReturned(cnum)
791
+ end
792
+
793
+ # @see http://msdn.microsoft.com/en-us/library/dd899531(v=EXCHG.140).aspx
794
+ def sync_scope!(scope)
795
+ @nbuild.SyncScope(scope)
796
+ end
797
+
798
+ # @see http://msdn.microsoft.com/en-us/library/aa580758(v=EXCHG.140).aspx
799
+ def saved_item_folder_id!(fid)
800
+ @nbuild.SavedItemFolderId {
801
+ dispatch_folder_id!(fid)
802
+ }
803
+ end
804
+
805
+ # @see http://msdn.microsoft.com/en-us/library/aa565652(v=exchg.140).aspx
806
+ def item!(item)
807
+ nbuild.Item {
808
+ item.each_pair {|k,v|
809
+ self.send("#{k}!", v)
810
+ }
811
+ }
812
+ end
813
+
814
+ def message!(item)
815
+ nbuild[NS_EWS_TYPES].Message {
816
+ if item[:extended_properties]
817
+ extended_properties! item.delete(:extended_properties)
818
+ end
819
+ item.each_pair {|k,v|
820
+ self.send("#{k}!", v)
821
+ }
822
+ }
823
+ end
824
+
825
+ def calendar_item!(item)
826
+ nbuild[NS_EWS_TYPES].CalendarItem {
827
+ item.each_pair {|k,v|
828
+ self.send("#{k}!", v)
829
+ }
830
+ }
831
+ end
832
+
833
+ def task!(item)
834
+ nbuild[NS_EWS_TYPES].Task {
835
+ item.each_pair {|k,v|
836
+ self.send("#{k}!", v)
837
+ }
838
+ }
839
+ end
840
+
841
+ def forward_item!(item)
842
+ nbuild[NS_EWS_TYPES].ForwardItem {
843
+ item.each_pair {|k,v|
844
+ self.send("#{k}!", v)
845
+ }
846
+ }
847
+ end
848
+
849
+ def reply_to_item!(item)
850
+ nbuild[NS_EWS_TYPES].ReplyToItem {
851
+ item.each_pair {|k,v|
852
+ self.send("#{k}!", v)
853
+ }
854
+ }
855
+ end
856
+
857
+ def reply_all_to_item!(item)
858
+ nbuild[NS_EWS_TYPES].ReplyAllToItem {
859
+ item.each_pair {|k,v|
860
+ self.send("#{k}!", v)
861
+ }
862
+ }
863
+ end
864
+
865
+ def reference_item_id!(id)
866
+ nbuild[NS_EWS_TYPES].ReferenceItemId {|x|
867
+ x.parent['Id'] = id[:id]
868
+ x.parent['ChangeKey'] = id[:change_key] if id[:change_key]
869
+ }
870
+ end
871
+
872
+ def subject!(sub)
873
+ nbuild[NS_EWS_TYPES].Subject(sub)
874
+ end
875
+
876
+ def importance!(sub)
877
+ nbuild[NS_EWS_TYPES].Importance(sub)
878
+ end
879
+
880
+ def body!(b)
881
+ nbuild[NS_EWS_TYPES].Body(b[:text]) {|x|
882
+ x.parent['BodyType'] = b[:body_type] if b[:body_type]
883
+ }
884
+ end
885
+
886
+ def new_body_content!(b)
887
+ nbuild[NS_EWS_TYPES].NewBodyContent(b[:text]) {|x|
888
+ x.parent['BodyType'] = b[:body_type] if b[:body_type]
889
+ }
890
+ end
891
+
892
+ # @see http://msdn.microsoft.com/en-us/library/aa563719(v=exchg.140).aspx
893
+ # @param [Array] r An array of Mailbox type hashes to send to #mailbox!
894
+ def to_recipients!(r)
895
+ nbuild[NS_EWS_TYPES].ToRecipients {
896
+ r.each {|mbox| mailbox!(mbox[:mailbox]) }
897
+ }
898
+ end
899
+
900
+ def cc_recipients!(r)
901
+ nbuild[NS_EWS_TYPES].CcRecipients {
902
+ r.each {|mbox| mailbox!(mbox[:mailbox]) }
903
+ }
904
+ end
905
+
906
+ def bcc_recipients!(r)
907
+ nbuild[NS_EWS_TYPES].BccRecipients {
908
+ r.each {|mbox| mailbox!(mbox[:mailbox]) }
909
+ }
910
+ end
911
+
912
+ def from!(f)
913
+ nbuild[NS_EWS_TYPES].From {
914
+ mailbox! f
915
+ }
916
+ end
917
+
918
+ def required_attendees!(attendees)
919
+ nbuild[NS_EWS_TYPES].RequiredAttendees {
920
+ attendees.each {|a| attendee!(a[:attendee])}
921
+ }
922
+ end
923
+
924
+ def optional_attendees!(attendees)
925
+ nbuild[NS_EWS_TYPES].OptionalAttendees {
926
+ attendees.each {|a| attendee!(a[:attendee])}
927
+ }
928
+ end
929
+
930
+ def resources!(attendees)
931
+ nbuild[NS_EWS_TYPES].Resources {
932
+ attendees.each {|a| attendee!(a[:attendee])}
933
+ }
934
+ end
935
+
936
+ # @todo support ResponseType, LastResponseTime: http://msdn.microsoft.com/en-us/library/aa580339.aspx
937
+ def attendee!(a)
938
+ nbuild[NS_EWS_TYPES].Attendee {
939
+ mailbox!(a[:mailbox])
940
+ }
941
+ end
942
+
943
+ def start!(st)
944
+ nbuild[NS_EWS_TYPES].Start(st[:text])
945
+ end
946
+
947
+ def end!(et)
948
+ nbuild[NS_EWS_TYPES].End(et[:text])
949
+ end
950
+
951
+ def start_date!(sd)
952
+ nbuild[NS_EWS_TYPES].StartDate format_time(sd[:text])
953
+ end
954
+
955
+ def due_date!(dd)
956
+ nbuild[NS_EWS_TYPES].DueDate format_time(dd[:text])
957
+ end
958
+
959
+ def location!(loc)
960
+ nbuild[NS_EWS_TYPES].Location(loc)
961
+ end
962
+
963
+ def is_all_day_event!(all_day)
964
+ nbuild[NS_EWS_TYPES].IsAllDayEvent(all_day)
965
+ end
966
+
967
+ def reminder_is_set!(reminder)
968
+ nbuild[NS_EWS_TYPES].ReminderIsSet reminder
969
+ end
970
+
971
+ def reminder_due_by!(date)
972
+ nbuild[NS_EWS_TYPES].ReminderDueBy format_time(date)
973
+ end
974
+
975
+ def reminder_minutes_before_start!(minutes)
976
+ nbuild[NS_EWS_TYPES].ReminderMinutesBeforeStart minutes
977
+ end
978
+
979
+ # @see http://msdn.microsoft.com/en-us/library/aa566143(v=exchg.150).aspx
980
+ # possible values Exchange Server 2010 = [Free, Tentative, Busy, OOF, NoData]
981
+ # Exchange Server 2013 = [Free, Tentative, Busy, OOF, WorkingElsewhere, NoData]
982
+ def legacy_free_busy_status!(state)
983
+ nbuild[NS_EWS_TYPES].LegacyFreeBusyStatus(state)
984
+ end
985
+
986
+ # @see http://msdn.microsoft.com/en-us/library/aa565428(v=exchg.140).aspx
987
+ def item_changes!(changes)
988
+ nbuild.ItemChanges {
989
+ changes.each do |chg|
990
+ item_change!(chg)
991
+ end
992
+ }
993
+ end
994
+
995
+ # @see http://msdn.microsoft.com/en-us/library/aa581081(v=exchg.140).aspx
996
+ def item_change!(change)
997
+ @nbuild[NS_EWS_TYPES].ItemChange {
998
+ updates = change.delete(:updates) # Remove updates so dispatch_item_id works correctly
999
+ dispatch_item_id!(change)
1000
+ updates!(updates)
1001
+ }
1002
+ end
1003
+
1004
+ # @see http://msdn.microsoft.com/en-us/library/aa581074(v=exchg.140).aspx
1005
+ def updates!(updates)
1006
+ @nbuild[NS_EWS_TYPES].Updates {
1007
+ updates.each do |update|
1008
+ dispatch_update_type!(update)
1009
+ end
1010
+ }
1011
+ end
1012
+
1013
+ # @see http://msdn.microsoft.com/en-us/library/aa581317(v=exchg.140).aspx
1014
+ def append_to_item_field!(upd)
1015
+ uri = upd.select {|k,v| k =~ /_uri/i}
1016
+ raise EwsBadArgumentError, "Bad argument given for AppendToItemField." if uri.keys.length != 1
1017
+ upd.delete(uri.keys.first)
1018
+ @nbuild.AppendToItemField {
1019
+ dispatch_field_uri!(uri)
1020
+ dispatch_field_item!(upd)
1021
+ }
1022
+ end
1023
+
1024
+ # @see http://msdn.microsoft.com/en-us/library/aa581487(v=exchg.140).aspx
1025
+ def set_item_field!(upd)
1026
+ uri = upd.select {|k,v| k =~ /_uri/i}
1027
+ raise EwsBadArgumentError, "Bad argument given for SetItemField." if uri.keys.length != 1
1028
+ upd.delete(uri.keys.first)
1029
+ @nbuild[NS_EWS_TYPES].SetItemField {
1030
+ dispatch_field_uri!(uri, NS_EWS_TYPES)
1031
+ dispatch_field_item!(upd, NS_EWS_TYPES)
1032
+ }
1033
+ end
1034
+
1035
+ # @see http://msdn.microsoft.com/en-us/library/aa580330(v=exchg.140).aspx
1036
+ def delete_item_field!(upd)
1037
+ uri = upd.select {|k,v| k =~ /_uri/i}
1038
+ raise EwsBadArgumentError, "Bad argument given for SetItemField." if uri.keys.length != 1
1039
+ @nbuild[NS_EWS_TYPES].DeleteItemField {
1040
+ dispatch_field_uri!(uri, NS_EWS_TYPES)
1041
+ }
1042
+ end
1043
+
1044
+ # @see http://msdn.microsoft.com/en-us/library/ff709497(v=exchg.140).aspx
1045
+ def return_new_item_ids!(retval)
1046
+ @nbuild.ReturnNewItemIds(retval)
1047
+ end
1048
+
1049
+ def inline_attachment!(fa)
1050
+ @nbuild[NS_EWS_TYPES].FileAttachment {
1051
+ @nbuild[NS_EWS_TYPES].Name(fa.name)
1052
+ @nbuild[NS_EWS_TYPES].ContentId(fa.name)
1053
+ @nbuild[NS_EWS_TYPES].IsInline(true)
1054
+ @nbuild[NS_EWS_TYPES].Content(fa.content)
1055
+ }
1056
+ end
1057
+
1058
+ def file_attachment!(fa)
1059
+ @nbuild[NS_EWS_TYPES].FileAttachment {
1060
+ @nbuild[NS_EWS_TYPES].Name(fa.name)
1061
+ @nbuild[NS_EWS_TYPES].Content(fa.content)
1062
+ }
1063
+ end
1064
+
1065
+ def item_attachment!(ia)
1066
+ @nbuild[NS_EWS_TYPES].ItemAttachment {
1067
+ @nbuild[NS_EWS_TYPES].Name(ia.name)
1068
+ @nbuild[NS_EWS_TYPES].Item {
1069
+ item_id!(ia.item)
1070
+ }
1071
+ }
1072
+ end
1073
+
1074
+ # Build the AttachmentIds element
1075
+ # @see http://msdn.microsoft.com/en-us/library/aa580686.aspx
1076
+ def attachment_ids!(aids)
1077
+ @nbuild.AttachmentIds {
1078
+ @nbuild.parent.default_namespace = @default_ns
1079
+ aids.each do |aid|
1080
+ attachment_id!(aid)
1081
+ end
1082
+ }
1083
+ end
1084
+
1085
+ # Build the AttachmentId element
1086
+ # @see http://msdn.microsoft.com/en-us/library/aa580764.aspx
1087
+ def attachment_id!(aid)
1088
+ attribs = {'Id' => aid}
1089
+ @nbuild[NS_EWS_TYPES].AttachmentId(attribs)
1090
+ end
1091
+
1092
+ def user_configuration_name!(cfg_name)
1093
+ attribs = {'Name' => cfg_name.delete(:name)}
1094
+ @nbuild[NS_EWS_MESSAGES].UserConfigurationName(attribs) {
1095
+ fid = cfg_name.keys.first
1096
+ self.send "#{fid}!", cfg_name[fid][:id], cfg_name[fid][:change_key]
1097
+ }
1098
+ end
1099
+
1100
+ def user_configuration_properties!(cfg_prop)
1101
+ @nbuild[NS_EWS_MESSAGES].UserConfigurationProperties(cfg_prop)
1102
+ end
1103
+
1104
+ # ---------------------- Helpers -------------------- #
1105
+
1106
+ # A helper method to dispatch to a FolderId or DistinguishedFolderId correctly
1107
+ # @param [Hash] fid A folder_id
1108
+ # Ex: {:id => myid, :change_key => ck}
1109
+ def dispatch_folder_id!(fid)
1110
+ if(fid[:id].is_a?(String))
1111
+ folder_id!(fid[:id], fid[:change_key])
1112
+ elsif(fid[:id].is_a?(Symbol))
1113
+ distinguished_folder_id!(fid[:id], fid[:change_key], fid[:act_as])
1114
+ else
1115
+ raise EwsBadArgumentError, "Bad argument given for a FolderId. #{fid[:id].class}"
1116
+ end
1117
+ end
1118
+
1119
+ # A helper method to dispatch to an ItemId, OccurrenceItemId, or a RecurringMasterItemId
1120
+ # @param [Hash] iid The item id of some type
1121
+ def dispatch_item_id!(iid)
1122
+ type = iid.keys.first
1123
+ item = iid[type]
1124
+ case type
1125
+ when :item_id
1126
+ item_id!(item)
1127
+ when :occurrence_item_id
1128
+ occurrence_item_id!(
1129
+ item[:recurring_master_id], item[:change_key], item[:instance_index])
1130
+ when :recurring_master_item_id
1131
+ recurring_master_item_id!(item[:occurrence_id], item[:change_key])
1132
+ else
1133
+ raise EwsBadArgumentError, "Bad ItemId type. #{type}"
1134
+ end
1135
+ end
1136
+
1137
+ # A helper method to dispatch to a AppendToItemField, SetItemField, or
1138
+ # DeleteItemField
1139
+ # @param [Hash] update An update of some type
1140
+ def dispatch_update_type!(update)
1141
+ type = update.keys.first
1142
+ upd = update[type]
1143
+ case type
1144
+ when :append_to_item_field
1145
+ append_to_item_field!(upd)
1146
+ when :set_item_field
1147
+ set_item_field!(upd)
1148
+ when :delete_item_field
1149
+ delete_item_field!(upd)
1150
+ else
1151
+ raise EwsBadArgumentError, "Bad Update type. #{type}"
1152
+ end
1153
+ end
1154
+
1155
+ # A helper to dispatch to a FieldURI, IndexedFieldURI, or an ExtendedFieldURI
1156
+ # @todo Implement ExtendedFieldURI
1157
+ def dispatch_field_uri!(uri, ns=NS_EWS_MESSAGES)
1158
+ type = uri.keys.first
1159
+ vals = uri[type].is_a?(Array) ? uri[type] : [uri[type]]
1160
+ case type
1161
+ when :field_uRI, :field_uri
1162
+ vals.each do |val|
1163
+ value = val.is_a?(Hash) ? val[type] : val
1164
+ nbuild[ns].FieldURI('FieldURI' => value)
1165
+ end
1166
+ when :indexed_field_uRI, :indexed_field_uri
1167
+ vals.each do |val|
1168
+ nbuild[ns].IndexedFieldURI(
1169
+ 'FieldURI' => (val[:field_uRI] || val[:field_uri]),
1170
+ 'FieldIndex' => val[:field_index]
1171
+ )
1172
+ end
1173
+ when :extended_field_uRI, :extended_field_uri
1174
+ vals.each do |val|
1175
+ nbuild[ns].ExtendedFieldURI {
1176
+ nbuild.parent['DistinguishedPropertySetId'] = val[:distinguished_property_set_id] if val[:distinguished_property_set_id]
1177
+ nbuild.parent['PropertySetId'] = val[:property_set_id] if val[:property_set_id]
1178
+ nbuild.parent['PropertyTag'] = val[:property_tag] if val[:property_tag]
1179
+ nbuild.parent['PropertyName'] = val[:property_name] if val[:property_name]
1180
+ nbuild.parent['PropertyId'] = val[:property_id] if val[:property_id]
1181
+ nbuild.parent['PropertyType'] = val[:property_type] if val[:property_type]
1182
+ }
1183
+ end
1184
+ else
1185
+ raise EwsBadArgumentError, "Bad URI type. #{type}"
1186
+ end
1187
+ end
1188
+
1189
+ # Insert item, enforce xmlns attribute if prefix is present
1190
+ def dispatch_field_item!(item, ns_prefix = nil)
1191
+ item.values.first[:xmlns_attribute] = ns_prefix if ns_prefix
1192
+ build_xml!(item)
1193
+ end
1194
+
1195
+ def room_list!(cfg_prop)
1196
+ @nbuild[NS_EWS_MESSAGES].RoomList {
1197
+ email_address!(cfg_prop)
1198
+ }
1199
+ end
1200
+
1201
+ def room_lists!
1202
+ @nbuild[NS_EWS_MESSAGES].GetRoomLists
1203
+ end
1204
+
1205
+
1206
+ private
1207
+
1208
+ def parent_namespace(node)
1209
+ node.parent.namespace_definitions.find {|ns| ns.prefix == NS_SOAP}
1210
+ end
1211
+
1212
+ def set_version_header!(version)
1213
+ if version && !(version == 'none')
1214
+ nbuild[NS_EWS_TYPES].RequestServerVersion {|x|
1215
+ x.parent['Version'] = version
1216
+ }
1217
+ end
1218
+ end
1219
+
1220
+ def set_impersonation!(type, address)
1221
+ if type && type != ""
1222
+ nbuild[NS_EWS_TYPES].ExchangeImpersonation {
1223
+ nbuild[NS_EWS_TYPES].ConnectingSID {
1224
+ nbuild[NS_EWS_TYPES].method_missing type, address
1225
+ }
1226
+ }
1227
+ end
1228
+ end
1229
+
1230
+ # Set TimeZoneContext Header
1231
+ # @param time_zone_def [Hash] !{id: time_zone_identifier, name: time_zone_name}
1232
+ def set_time_zone_context_header!(time_zone_def)
1233
+ if time_zone_def
1234
+ nbuild[NS_EWS_TYPES].TimeZoneContext do
1235
+ time_zone_definition! time_zone_def
1236
+ end
1237
+ end
1238
+ end
1239
+
1240
+ # some methods need special naming so they use the '_r' suffix like 'and'
1241
+ def normalize_type(type)
1242
+ case type
1243
+ when :and, :or, :not
1244
+ "#{type}_r".to_sym
1245
+ else
1246
+ type
1247
+ end
1248
+ end
1249
+
1250
+ def format_time(time)
1251
+ case time
1252
+ when Time, Date, DateTime
1253
+ time.to_datetime.new_offset(0).iso8601
1254
+ when String
1255
+ begin
1256
+ DateTime.parse(time).new_offset(0).iso8601
1257
+ rescue ArgumentError
1258
+ raise EwsBadArgumentError, "Invalid Time argument (#{time})"
1259
+ end
1260
+ else
1261
+ raise EwsBadArgumentError, "Invalid Time argument (#{time})"
1262
+ end
1263
+ end
1264
+
1265
+ end # EwsBuilder
1266
+ end # Viewpoint::EWS::SOAP