viewpoint_reloaded 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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