sfdcvp 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. checksums.yaml +15 -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 +126 -0
  7. data/lib/ews/connection_helper.rb +35 -0
  8. data/lib/ews/convert_accessors.rb +56 -0
  9. data/lib/ews/errors.rb +56 -0
  10. data/lib/ews/ews_client.rb +101 -0
  11. data/lib/ews/exceptions/exceptions.rb +61 -0
  12. data/lib/ews/folder_accessors.rb +264 -0
  13. data/lib/ews/impersonation.rb +30 -0
  14. data/lib/ews/item_accessors.rb +231 -0
  15. data/lib/ews/mailbox_accessors.rb +92 -0
  16. data/lib/ews/message_accessors.rb +93 -0
  17. data/lib/ews/push_subscription_accessors.rb +33 -0
  18. data/lib/ews/room_accessors.rb +48 -0
  19. data/lib/ews/roomlist_accessors.rb +47 -0
  20. data/lib/ews/soap.rb +64 -0
  21. data/lib/ews/soap/builders/ews_builder.rb +1361 -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 +78 -0
  47. data/lib/ews/templates/forward_item.rb +24 -0
  48. data/lib/ews/templates/message.rb +73 -0
  49. data/lib/ews/templates/reply_to_item.rb +25 -0
  50. data/lib/ews/templates/task.rb +74 -0
  51. data/lib/ews/types.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 +129 -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 +420 -0
  68. data/lib/ews/types/item.rb +442 -0
  69. data/lib/ews/types/item_attachment.rb +84 -0
  70. data/lib/ews/types/item_field_uri_map.rb +224 -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 +37 -0
  84. data/lib/ews/types/tasks_folder.rb +27 -0
  85. data/lib/sfdcvp.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 +190 -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
data/lib/ews/soap.rb ADDED
@@ -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,1361 @@
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 response_type!(response)
944
+ # nbuild[NS_EWS_TYPES].ResponseType(reponse)
945
+ # end
946
+
947
+ def start!(st)
948
+ nbuild[NS_EWS_TYPES].Start(st[:text])
949
+ end
950
+
951
+ def end!(et)
952
+ nbuild[NS_EWS_TYPES].End(et[:text])
953
+ end
954
+
955
+ def start_date!(sd)
956
+ nbuild[NS_EWS_TYPES].StartDate format_time(sd[:text])
957
+ end
958
+
959
+ def end_date_r!(ed)
960
+ nbuild[NS_EWS_TYPES].EndDate(ed)
961
+ end
962
+
963
+ def start_date_r!(sd)
964
+ nbuild[NS_EWS_TYPES].StartDate(sd)
965
+ end
966
+
967
+ def due_date!(dd)
968
+ nbuild[NS_EWS_TYPES].DueDate format_time(dd[:text])
969
+ end
970
+
971
+ # Recurrence Methods
972
+
973
+ def calendar_item_type!(it)
974
+ nbuild[NS_EWS_TYPES].CalendarItemType(it)
975
+ end
976
+
977
+ def recurrence!(rr)
978
+ nbuild[NS_EWS_TYPES].Recurrence {
979
+ # How often the event should occur
980
+ daily_recurrence!(rr[:daily_recurrence]) if rr[:daily_recurrence]
981
+ weekly_recurrence!(rr[:weekly_recurrence]) if rr[:weekly_recurrence]
982
+ absolute_monthly_recurrence!(rr[:absolute_monthly_recurrence]) if rr[:absolute_monthly_recurrence]
983
+ # How to repeat the recurring series
984
+ no_end_recurrence!(rr[:no_end_recurrence]) if rr[:no_end_recurrence]
985
+ end_date_recurrence!(rr[:end_date_recurrence]) if rr[:end_date_recurrence]
986
+ numbered_recurrence!(rr[:numbered_recurrence]) if rr[:numbered_recurrence]
987
+ }
988
+ # puts nbuild[NS_EWS_TYPES].to_xml
989
+ end
990
+
991
+ def daily_recurrence!(dr)
992
+ nbuild[NS_EWS_TYPES].DailyRecurrence {
993
+ interval!(dr[:interval])
994
+ }
995
+ end
996
+
997
+ def weekly_recurrence!(wr)
998
+ nbuild[NS_EWS_TYPES].WeeklyRecurrence {
999
+ interval!(wr[:interval])
1000
+ days_of_week!(wr[:days_of_week])
1001
+ # first_day_of_week!(wr[:first_day_of_week])
1002
+ }
1003
+ end
1004
+
1005
+ def absolute_monthly_recurrence!(amr)
1006
+ nbuild[NS_EWS_TYPES].AbsoluteMonthlyRecurrence {
1007
+ interval!(amr[:interval])
1008
+ day_of_month!(amr[:day_of_month])
1009
+ }
1010
+ end
1011
+
1012
+ def end_date_recurrence!(edr)
1013
+ nbuild[NS_EWS_TYPES].EndDateRecurrence {
1014
+ start_date_r!(edr[:start_date])
1015
+ end_date_r!(edr[:end_date])
1016
+ }
1017
+ end
1018
+
1019
+ def no_end_recurrence!(ner)
1020
+ nbuild[NS_EWS_TYPES].NoEndRecurrence {
1021
+ start_date_r!(ner[:start_date])
1022
+ }
1023
+ end
1024
+
1025
+ def numbered_recurrence!(nr)
1026
+ nbuild[NS_EWS_TYPES].NumberedRecurrence {
1027
+ start_date_r!(nr[:start_date])
1028
+ number_of_occurrences!(nr[:number_of_occurrences])
1029
+ }
1030
+ end
1031
+
1032
+ def interval!(iv)
1033
+ nbuild[NS_EWS_TYPES].Interval(iv)
1034
+ end
1035
+
1036
+ def number_of_occurrences!(noc)
1037
+ nbuild[NS_EWS_TYPES].NumberOfOccurrences(noc)
1038
+ end
1039
+
1040
+ def days_of_week!(dow)
1041
+ nbuild[NS_EWS_TYPES].DaysOfWeek(dow)
1042
+ end
1043
+
1044
+ def day_of_month!(dom)
1045
+ nbuild[NS_EWS_TYPES].DayOfMonth(dom)
1046
+ end
1047
+
1048
+ # def first_day_of_week!(fdow)
1049
+ # nbuild[NS_EWS_TYPES].FirstDayOfWeek(fdow)
1050
+ # end
1051
+
1052
+ def location!(loc)
1053
+ nbuild[NS_EWS_TYPES].Location(loc)
1054
+ end
1055
+
1056
+ # ==============================================
1057
+
1058
+ def is_all_day_event!(all_day)
1059
+ nbuild[NS_EWS_TYPES].IsAllDayEvent(all_day)
1060
+ end
1061
+
1062
+ def reminder_is_set!(reminder)
1063
+ nbuild[NS_EWS_TYPES].ReminderIsSet reminder
1064
+ end
1065
+
1066
+ def reminder_due_by!(date)
1067
+ nbuild[NS_EWS_TYPES].ReminderDueBy format_time(date)
1068
+ end
1069
+
1070
+ def reminder_minutes_before_start!(minutes)
1071
+ nbuild[NS_EWS_TYPES].ReminderMinutesBeforeStart minutes
1072
+ end
1073
+
1074
+ # @see http://msdn.microsoft.com/en-us/library/aa566143(v=exchg.150).aspx
1075
+ # possible values Exchange Server 2010 = [Free, Tentative, Busy, OOF, NoData]
1076
+ # Exchange Server 2013 = [Free, Tentative, Busy, OOF, WorkingElsewhere, NoData]
1077
+ def legacy_free_busy_status!(state)
1078
+ nbuild[NS_EWS_TYPES].LegacyFreeBusyStatus(state)
1079
+ end
1080
+
1081
+ # @see http://msdn.microsoft.com/en-us/library/aa565428(v=exchg.140).aspx
1082
+ def item_changes!(changes)
1083
+ nbuild.ItemChanges {
1084
+ changes.each do |chg|
1085
+ item_change!(chg)
1086
+ end
1087
+ }
1088
+ end
1089
+
1090
+ # @see http://msdn.microsoft.com/en-us/library/aa581081(v=exchg.140).aspx
1091
+ def item_change!(change)
1092
+ @nbuild[NS_EWS_TYPES].ItemChange {
1093
+ updates = change.delete(:updates) # Remove updates so dispatch_item_id works correctly
1094
+ dispatch_item_id!(change)
1095
+ updates!(updates)
1096
+ }
1097
+ end
1098
+
1099
+ # @see http://msdn.microsoft.com/en-us/library/aa581074(v=exchg.140).aspx
1100
+ def updates!(updates)
1101
+ @nbuild[NS_EWS_TYPES].Updates {
1102
+ updates.each do |update|
1103
+ dispatch_update_type!(update)
1104
+ end
1105
+ }
1106
+ end
1107
+
1108
+ # @see http://msdn.microsoft.com/en-us/library/aa581317(v=exchg.140).aspx
1109
+ def append_to_item_field!(upd)
1110
+ uri = upd.select {|k,v| k =~ /_uri/i}
1111
+ raise EwsBadArgumentError, "Bad argument given for AppendToItemField." if uri.keys.length != 1
1112
+ upd.delete(uri.keys.first)
1113
+ @nbuild.AppendToItemField {
1114
+ dispatch_field_uri!(uri)
1115
+ dispatch_field_item!(upd)
1116
+ }
1117
+ end
1118
+
1119
+ # @see http://msdn.microsoft.com/en-us/library/aa581487(v=exchg.140).aspx
1120
+ def set_item_field!(upd)
1121
+ uri = upd.select {|k,v| k =~ /_uri/i}
1122
+ raise EwsBadArgumentError, "Bad argument given for SetItemField." if uri.keys.length != 1
1123
+ upd.delete(uri.keys.first)
1124
+ @nbuild[NS_EWS_TYPES].SetItemField {
1125
+ dispatch_field_uri!(uri, NS_EWS_TYPES)
1126
+ dispatch_field_item!(upd, NS_EWS_TYPES)
1127
+ }
1128
+ end
1129
+
1130
+ # @see http://msdn.microsoft.com/en-us/library/aa580330(v=exchg.140).aspx
1131
+ def delete_item_field!(upd)
1132
+ uri = upd.select {|k,v| k =~ /_uri/i}
1133
+ raise EwsBadArgumentError, "Bad argument given for SetItemField." if uri.keys.length != 1
1134
+ @nbuild[NS_EWS_TYPES].DeleteItemField {
1135
+ dispatch_field_uri!(uri, NS_EWS_TYPES)
1136
+ }
1137
+ end
1138
+
1139
+ # @see http://msdn.microsoft.com/en-us/library/ff709497(v=exchg.140).aspx
1140
+ def return_new_item_ids!(retval)
1141
+ @nbuild.ReturnNewItemIds(retval)
1142
+ end
1143
+
1144
+ def inline_attachment!(fa)
1145
+ @nbuild[NS_EWS_TYPES].FileAttachment {
1146
+ @nbuild[NS_EWS_TYPES].Name(fa.name)
1147
+ @nbuild[NS_EWS_TYPES].ContentId(fa.name)
1148
+ @nbuild[NS_EWS_TYPES].IsInline(true)
1149
+ @nbuild[NS_EWS_TYPES].Content(fa.content)
1150
+ }
1151
+ end
1152
+
1153
+ def file_attachment!(fa)
1154
+ @nbuild[NS_EWS_TYPES].FileAttachment {
1155
+ @nbuild[NS_EWS_TYPES].Name(fa.name)
1156
+ @nbuild[NS_EWS_TYPES].Content(fa.content)
1157
+ }
1158
+ end
1159
+
1160
+ def item_attachment!(ia)
1161
+ @nbuild[NS_EWS_TYPES].ItemAttachment {
1162
+ @nbuild[NS_EWS_TYPES].Name(ia.name)
1163
+ @nbuild[NS_EWS_TYPES].Item {
1164
+ item_id!(ia.item)
1165
+ }
1166
+ }
1167
+ end
1168
+
1169
+ # Build the AttachmentIds element
1170
+ # @see http://msdn.microsoft.com/en-us/library/aa580686.aspx
1171
+ def attachment_ids!(aids)
1172
+ @nbuild.AttachmentIds {
1173
+ @nbuild.parent.default_namespace = @default_ns
1174
+ aids.each do |aid|
1175
+ attachment_id!(aid)
1176
+ end
1177
+ }
1178
+ end
1179
+
1180
+ # Build the AttachmentId element
1181
+ # @see http://msdn.microsoft.com/en-us/library/aa580764.aspx
1182
+ def attachment_id!(aid)
1183
+ attribs = {'Id' => aid}
1184
+ @nbuild[NS_EWS_TYPES].AttachmentId(attribs)
1185
+ end
1186
+
1187
+ def user_configuration_name!(cfg_name)
1188
+ attribs = {'Name' => cfg_name.delete(:name)}
1189
+ @nbuild[NS_EWS_MESSAGES].UserConfigurationName(attribs) {
1190
+ fid = cfg_name.keys.first
1191
+ self.send "#{fid}!", cfg_name[fid][:id], cfg_name[fid][:change_key]
1192
+ }
1193
+ end
1194
+
1195
+ def user_configuration_properties!(cfg_prop)
1196
+ @nbuild[NS_EWS_MESSAGES].UserConfigurationProperties(cfg_prop)
1197
+ end
1198
+
1199
+ # ---------------------- Helpers -------------------- #
1200
+
1201
+ # A helper method to dispatch to a FolderId or DistinguishedFolderId correctly
1202
+ # @param [Hash] fid A folder_id
1203
+ # Ex: {:id => myid, :change_key => ck}
1204
+ def dispatch_folder_id!(fid)
1205
+ if(fid[:id].is_a?(String))
1206
+ folder_id!(fid[:id], fid[:change_key])
1207
+ elsif(fid[:id].is_a?(Symbol))
1208
+ distinguished_folder_id!(fid[:id], fid[:change_key], fid[:act_as])
1209
+ else
1210
+ raise EwsBadArgumentError, "Bad argument given for a FolderId. #{fid[:id].class}"
1211
+ end
1212
+ end
1213
+
1214
+ # A helper method to dispatch to an ItemId, OccurrenceItemId, or a RecurringMasterItemId
1215
+ # @param [Hash] iid The item id of some type
1216
+ def dispatch_item_id!(iid)
1217
+ type = iid.keys.first
1218
+ item = iid[type]
1219
+ case type
1220
+ when :item_id
1221
+ item_id!(item)
1222
+ when :occurrence_item_id
1223
+ occurrence_item_id!(
1224
+ item[:recurring_master_id], item[:change_key], item[:instance_index])
1225
+ when :recurring_master_item_id
1226
+ recurring_master_item_id!(item[:occurrence_id], item[:change_key])
1227
+ else
1228
+ raise EwsBadArgumentError, "Bad ItemId type. #{type}"
1229
+ end
1230
+ end
1231
+
1232
+ # A helper method to dispatch to a AppendToItemField, SetItemField, or
1233
+ # DeleteItemField
1234
+ # @param [Hash] update An update of some type
1235
+ def dispatch_update_type!(update)
1236
+ type = update.keys.first
1237
+ upd = update[type]
1238
+ case type
1239
+ when :append_to_item_field
1240
+ append_to_item_field!(upd)
1241
+ when :set_item_field
1242
+ set_item_field!(upd)
1243
+ when :delete_item_field
1244
+ delete_item_field!(upd)
1245
+ else
1246
+ raise EwsBadArgumentError, "Bad Update type. #{type}"
1247
+ end
1248
+ end
1249
+
1250
+ # A helper to dispatch to a FieldURI, IndexedFieldURI, or an ExtendedFieldURI
1251
+ # @todo Implement ExtendedFieldURI
1252
+ def dispatch_field_uri!(uri, ns=NS_EWS_MESSAGES)
1253
+ type = uri.keys.first
1254
+ vals = uri[type].is_a?(Array) ? uri[type] : [uri[type]]
1255
+ case type
1256
+ when :field_uRI, :field_uri
1257
+ vals.each do |val|
1258
+ value = val.is_a?(Hash) ? val[type] : val
1259
+ nbuild[ns].FieldURI('FieldURI' => value)
1260
+ end
1261
+ when :indexed_field_uRI, :indexed_field_uri
1262
+ vals.each do |val|
1263
+ nbuild[ns].IndexedFieldURI(
1264
+ 'FieldURI' => (val[:field_uRI] || val[:field_uri]),
1265
+ 'FieldIndex' => val[:field_index]
1266
+ )
1267
+ end
1268
+ when :extended_field_uRI, :extended_field_uri
1269
+ vals.each do |val|
1270
+ nbuild[ns].ExtendedFieldURI {
1271
+ nbuild.parent['DistinguishedPropertySetId'] = val[:distinguished_property_set_id] if val[:distinguished_property_set_id]
1272
+ nbuild.parent['PropertySetId'] = val[:property_set_id] if val[:property_set_id]
1273
+ nbuild.parent['PropertyTag'] = val[:property_tag] if val[:property_tag]
1274
+ nbuild.parent['PropertyName'] = val[:property_name] if val[:property_name]
1275
+ nbuild.parent['PropertyId'] = val[:property_id] if val[:property_id]
1276
+ nbuild.parent['PropertyType'] = val[:property_type] if val[:property_type]
1277
+ }
1278
+ end
1279
+ else
1280
+ raise EwsBadArgumentError, "Bad URI type. #{type}"
1281
+ end
1282
+ end
1283
+
1284
+ # Insert item, enforce xmlns attribute if prefix is present
1285
+ def dispatch_field_item!(item, ns_prefix = nil)
1286
+ item.values.first[:xmlns_attribute] = ns_prefix if ns_prefix
1287
+ build_xml!(item)
1288
+ end
1289
+
1290
+ def room_list!(cfg_prop)
1291
+ @nbuild[NS_EWS_MESSAGES].RoomList {
1292
+ email_address!(cfg_prop)
1293
+ }
1294
+ end
1295
+
1296
+ def room_lists!
1297
+ @nbuild[NS_EWS_MESSAGES].GetRoomLists
1298
+ end
1299
+
1300
+
1301
+ private
1302
+
1303
+ def parent_namespace(node)
1304
+ node.parent.namespace_definitions.find {|ns| ns.prefix == NS_SOAP}
1305
+ end
1306
+
1307
+ def set_version_header!(version)
1308
+ if version && !(version == 'none')
1309
+ nbuild[NS_EWS_TYPES].RequestServerVersion {|x|
1310
+ x.parent['Version'] = version
1311
+ }
1312
+ end
1313
+ end
1314
+
1315
+ def set_impersonation!(type, address)
1316
+ if type && type != ""
1317
+ nbuild[NS_EWS_TYPES].ExchangeImpersonation {
1318
+ nbuild[NS_EWS_TYPES].ConnectingSID {
1319
+ nbuild[NS_EWS_TYPES].method_missing type, address
1320
+ }
1321
+ }
1322
+ end
1323
+ end
1324
+
1325
+ # Set TimeZoneContext Header
1326
+ # @param time_zone_def [Hash] !{id: time_zone_identifier, name: time_zone_name}
1327
+ def set_time_zone_context_header!(time_zone_def)
1328
+ if time_zone_def
1329
+ nbuild[NS_EWS_TYPES].TimeZoneContext do
1330
+ time_zone_definition! time_zone_def
1331
+ end
1332
+ end
1333
+ end
1334
+
1335
+ # some methods need special naming so they use the '_r' suffix like 'and'
1336
+ def normalize_type(type)
1337
+ case type
1338
+ when :and, :or, :not
1339
+ "#{type}_r".to_sym
1340
+ else
1341
+ type
1342
+ end
1343
+ end
1344
+
1345
+ def format_time(time)
1346
+ case time
1347
+ when Time, Date, DateTime
1348
+ time.to_datetime.new_offset(0).iso8601
1349
+ when String
1350
+ begin
1351
+ DateTime.parse(time).new_offset(0).iso8601
1352
+ rescue ArgumentError
1353
+ raise EwsBadArgumentError, "Invalid Time argument (#{time})"
1354
+ end
1355
+ else
1356
+ raise EwsBadArgumentError, "Invalid Time argument (#{time})"
1357
+ end
1358
+ end
1359
+
1360
+ end # EwsBuilder
1361
+ end # Viewpoint::EWS::SOAP