viewpoint2 1.3.0

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