viewpoint 0.1.27 → 1.0.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. data/README.md +196 -0
  2. data/lib/ews/calendar_accessors.rb +34 -0
  3. data/lib/ews/connection.rb +117 -0
  4. data/lib/ews/connection_helper.rb +35 -0
  5. data/lib/ews/ews_client.rb +71 -0
  6. data/lib/ews/exceptions/exceptions.rb +59 -0
  7. data/lib/ews/folder_accessors.rb +199 -0
  8. data/lib/ews/item_accessors.rb +157 -0
  9. data/lib/ews/mailbox_accessors.rb +87 -0
  10. data/lib/ews/message_accessors.rb +86 -0
  11. data/lib/ews/push_subscription_accessors.rb +33 -0
  12. data/lib/ews/soap.rb +63 -0
  13. data/lib/ews/soap/builders/ews_builder.rb +1011 -0
  14. data/lib/ews/soap/ews_response.rb +83 -0
  15. data/lib/ews/soap/ews_soap_availability_response.rb +58 -0
  16. data/lib/ews/soap/ews_soap_free_busy_response.rb +109 -0
  17. data/lib/ews/soap/ews_soap_response.rb +103 -0
  18. data/lib/ews/soap/exchange_availability.rb +61 -0
  19. data/lib/ews/soap/exchange_data_services.rb +742 -0
  20. data/lib/ews/soap/exchange_notification.rb +146 -0
  21. data/lib/ews/soap/exchange_user_configuration.rb +33 -0
  22. data/lib/ews/soap/exchange_web_service.rb +294 -0
  23. data/lib/{model/attendee.rb → ews/soap/parsers/ews_parser.rb} +20 -14
  24. data/lib/ews/soap/parsers/ews_sax_document.rb +66 -0
  25. data/lib/ews/soap/response_message.rb +78 -0
  26. data/lib/ews/soap/responses/create_attachment_response_message.rb +46 -0
  27. data/lib/{model/meeting_message.rb → ews/soap/responses/create_item_response_message.rb} +7 -10
  28. data/lib/ews/soap/responses/find_item_response_message.rb +80 -0
  29. data/lib/ews/soap/responses/get_events_response_message.rb +53 -0
  30. data/lib/ews/soap/responses/send_notification_response_message.rb +58 -0
  31. data/lib/{model/attachment.rb → ews/soap/responses/subscribe_response_message.rb} +17 -13
  32. data/lib/ews/templates/forward_item.rb +24 -0
  33. data/lib/ews/templates/message.rb +66 -0
  34. data/lib/ews/templates/reply_to_item.rb +25 -0
  35. data/lib/ews/types.rb +146 -0
  36. data/lib/ews/types/attachment.rb +77 -0
  37. data/lib/{model/meeting_cancellation.rb → ews/types/attendee.rb} +9 -8
  38. data/lib/ews/types/calendar_folder.rb +8 -0
  39. data/lib/ews/types/calendar_item.rb +37 -0
  40. data/lib/ews/types/contact.rb +7 -0
  41. data/lib/ews/types/contacts_folder.rb +8 -0
  42. data/lib/ews/types/copied_event.rb +51 -0
  43. data/lib/{soap/handsoap/builder.rb → ews/types/created_event.rb} +5 -2
  44. data/lib/{model/meeting_response.rb → ews/types/deleted_event.rb} +6 -6
  45. data/lib/ews/types/distribution_list.rb +7 -0
  46. data/lib/ews/types/event.rb +62 -0
  47. data/lib/ews/types/file_attachment.rb +65 -0
  48. data/lib/ews/types/folder.rb +60 -0
  49. data/lib/{model/distribution_list.rb → ews/types/free_busy_changed_event.rb} +6 -6
  50. data/lib/ews/types/generic_folder.rb +352 -0
  51. data/lib/ews/types/item.rb +381 -0
  52. data/lib/ews/types/item_attachment.rb +46 -0
  53. data/lib/{model → ews/types}/item_field_uri_map.rb +2 -2
  54. data/lib/ews/types/mailbox_user.rb +156 -0
  55. data/lib/ews/types/meeting_cancellation.rb +7 -0
  56. data/lib/ews/types/meeting_message.rb +7 -0
  57. data/lib/ews/types/meeting_request.rb +7 -0
  58. data/lib/ews/types/meeting_response.rb +7 -0
  59. data/lib/ews/types/message.rb +7 -0
  60. data/lib/ews/types/modified_event.rb +48 -0
  61. data/lib/{model/item_attachment.rb → ews/types/moved_event.rb} +33 -15
  62. data/lib/ews/types/new_mail_event.rb +24 -0
  63. data/lib/ews/types/out_of_office.rb +147 -0
  64. data/lib/ews/types/search_folder.rb +8 -0
  65. data/lib/ews/types/status_event.rb +39 -0
  66. data/lib/ews/types/task.rb +7 -0
  67. data/lib/ews/types/tasks_folder.rb +8 -0
  68. data/lib/viewpoint.rb +82 -106
  69. metadata +99 -67
  70. data/README +0 -114
  71. data/lib/exceptions/exceptions.rb +0 -46
  72. data/lib/model/calendar_folder.rb +0 -67
  73. data/lib/model/calendar_item.rb +0 -267
  74. data/lib/model/contact.rb +0 -238
  75. data/lib/model/contacts_folder.rb +0 -46
  76. data/lib/model/event.rb +0 -116
  77. data/lib/model/file_attachment.rb +0 -53
  78. data/lib/model/folder.rb +0 -47
  79. data/lib/model/generic_folder.rb +0 -471
  80. data/lib/model/item.rb +0 -313
  81. data/lib/model/mailbox_user.rb +0 -146
  82. data/lib/model/meeting_request.rb +0 -39
  83. data/lib/model/message.rb +0 -142
  84. data/lib/model/model.rb +0 -269
  85. data/lib/model/search_folder.rb +0 -48
  86. data/lib/model/task.rb +0 -121
  87. data/lib/model/tasks_folder.rb +0 -44
  88. data/lib/soap/handsoap/builders/ews_build_helpers.rb +0 -383
  89. data/lib/soap/handsoap/builders/ews_builder.rb +0 -146
  90. data/lib/soap/handsoap/ews_service.rb +0 -813
  91. data/lib/soap/handsoap/parser.rb +0 -104
  92. data/lib/soap/handsoap/parsers/ews_parser.rb +0 -246
  93. data/lib/soap/soap_provider.rb +0 -64
@@ -0,0 +1,86 @@
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::MessageAccessors
19
+ include Viewpoint::EWS
20
+
21
+ # Send an E-mail message
22
+ #
23
+ # @param [Hash] opts A Hash with message params
24
+ # @option opts [String] :subject The message subject
25
+ # @option opts [String] :body The message body
26
+ # @option opts [Array] :to_recipients An array of e-mail addresses to send to
27
+ # @option opts [Array] :cc_recipients An array of e-mail addresses to send to
28
+ # @option opts [Array] :bcc_recipients An array of e-mail addresses to send to
29
+ # @option opts [Boolean] :draft if true it will save to the draft folder
30
+ # without sending the message.
31
+ # @option opts [String,Symbol,Hash] saved_item_folder_id Either a
32
+ # FolderId(String) or a DistinguishedFolderId(Symbol). You can also pass a
33
+ # Hash in the form: {id: <fold_id>, change_key: <change_key>}
34
+ # @option opts [Array<File>] :file_attachments an Array of File objects
35
+ # @return [Message,Boolean] Returns true if the message is sent, false if
36
+ # nothing is returned from EWS or if draft is true it will return the
37
+ # Message object. Finally, if something goes wrong, it raises an error
38
+ # with a message stating why the e-mail could not be sent.
39
+ # @todo Finish ItemAttachments
40
+ def send_message(opts = {}, &block)
41
+ msg = Template::Message.new opts.clone
42
+ yield msg if block_given?
43
+ if msg.has_attachments?
44
+ draft = msg.draft
45
+ msg.draft = true
46
+ resp = parse_create_item(ews.create_item(msg.to_ews))
47
+ msg.file_attachments.each do |f|
48
+ next unless f.kind_of?(File)
49
+ resp.add_file_attachment(f)
50
+ end
51
+ if draft
52
+ resp.submit_attachments!
53
+ resp
54
+ else
55
+ resp.submit!
56
+ end
57
+ else
58
+ resp = ews.create_item(msg.to_ews)
59
+ resp.response_messages ? parse_create_item(resp) : false
60
+ end
61
+ end
62
+
63
+ # See #send_message for options
64
+ def draft_message(opts = {}, &block)
65
+ send_message opts.merge(draft: true), &block
66
+ end
67
+
68
+
69
+ private
70
+
71
+
72
+ def parse_create_item(resp)
73
+ rm = resp.response_messages[0]
74
+ if(rm.status == 'Success')
75
+ rm.items.empty? ? true : parse_message(rm.items.first)
76
+ else
77
+ raise EwsError, "Could not send message. #{rm.code}: #{rm.message_text}"
78
+ end
79
+ end
80
+
81
+ def parse_message(msg)
82
+ mtype = msg.keys.first
83
+ message = class_by_name(mtype).new(ews, msg[mtype])
84
+ end
85
+
86
+ end # Viewpoint::EWS::MessageAccessors
@@ -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,63 @@
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_NONE = 'none'
51
+
52
+ HARD_DELETE = 'HardDelete'
53
+ SOFT_DELETE = 'SoftDelete'
54
+ MOVE_TO_DELETED_ITEMS = 'MoveToDeletedItems'
55
+
56
+ def initialize
57
+ @log = Logging.logger[self.class.name.to_s.to_sym]
58
+ @default_ns = NAMESPACES["xmlns:#{NS_EWS_MESSAGES}"]
59
+ end
60
+
61
+ end # SOAP
62
+ end # EWS
63
+ end # Viewpoint
@@ -0,0 +1,1011 @@
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
+
25
+ attr_reader :nbuild
26
+ def initialize
27
+ @nbuild = Nokogiri::XML::Builder.new
28
+ end
29
+
30
+ # Build the SOAP envelope and yield this object so subelements can be built. Once
31
+ # you have the EwsBuilder object you can use the nbuild object like shown in the
32
+ # example for the Header section. The nbuild object is the underlying
33
+ # Nokogiri::XML::Builder object.
34
+ # @param [Hash] opts
35
+ # @option opts [String] :server_version The version string that should get
36
+ # set in the Header. See ExchangeWebService#initialize
37
+ # @example
38
+ # xb = EwsBuilder.new
39
+ # xb.build! do |part, b|
40
+ # if(part == :header)
41
+ # b.nbuild.MyVar('blablabla')
42
+ # else
43
+ # b.folder_shape!({:base_shape => 'Default'})
44
+ # end
45
+ # end
46
+ def build!(opts = {}, &block)
47
+ @nbuild.Envelope(NAMESPACES) do |node|
48
+ node.parent.namespace = parent_namespace(node)
49
+ node.Header {
50
+ set_version_header! opts[:server_version]
51
+ yield(:header, self) if block_given?
52
+ }
53
+ node.Body {
54
+ yield(:body, self) if block_given?
55
+ }
56
+ end
57
+ @nbuild.doc
58
+ end
59
+
60
+ # Build XML from a passed in Hash or Array in a specified format.
61
+ # @param [Array,Hash] elems The elements to add to the Builder. They must
62
+ # be specified like so:
63
+ # {:top =>
64
+ # { :xmlns => 'http://stonesthrow/soap',
65
+ # :sub_elements => [
66
+ # {:elem1 => {:text => 'inside'}},
67
+ # {:elem2 => {:text => 'inside2'}}
68
+ # ],
69
+ # :id => '3232', :tx_dd => 23, :asdf => 'turkey'
70
+ # }
71
+ # }
72
+ # or
73
+ # [ {:first => {:text => 'hello'}},
74
+ # {:second => {:text => 'world'}}
75
+ # ]
76
+ #
77
+ # NOTE: there are specialized keys for text (:text), child elements
78
+ # (:sub_elements) and namespaces (:xmlns).
79
+ def build_xml!(elems)
80
+ case elems.class.name
81
+ when 'Hash'
82
+ keys = elems.keys
83
+ vals = elems.values
84
+ if(keys.length > 1 && !vals.is_a?(Hash))
85
+ raise "invalid input: #{elems}"
86
+ end
87
+ vals = vals.first.clone
88
+ se = vals.delete(:sub_elements)
89
+ txt = vals.delete(:text)
90
+
91
+ @nbuild.send(keys.first.to_s.camel_case, txt, vals) {|x|
92
+ build_xml!(se) if se
93
+ }
94
+ when 'Array'
95
+ elems.each do |e|
96
+ build_xml!(e)
97
+ end
98
+ else
99
+ raise "Unsupported type: #{elems.class.name}"
100
+ end
101
+ end
102
+
103
+ # Build the FolderShape element
104
+ # @see http://msdn.microsoft.com/en-us/library/aa494311.aspx
105
+ # @param [Hash] folder_shape The folder shape structure to build from
106
+ # @todo need fully support all options
107
+ def folder_shape!(folder_shape)
108
+ @nbuild.FolderShape {
109
+ @nbuild.parent.default_namespace = @default_ns
110
+ base_shape!(folder_shape[:base_shape])
111
+ if(folder_shape[:additional_properties])
112
+ additional_properties!(folder_shape[:additional_properties])
113
+ end
114
+ }
115
+ end
116
+
117
+ # Build the ItemShape element
118
+ # @see http://msdn.microsoft.com/en-us/library/aa565261.aspx
119
+ # @param [Hash] item_shape The item shape structure to build from
120
+ # @todo need fully support all options
121
+ def item_shape!(item_shape)
122
+ @nbuild[NS_EWS_MESSAGES].ItemShape {
123
+ @nbuild.parent.default_namespace = @default_ns
124
+ base_shape!(item_shape[:base_shape])
125
+ body_type!(item_shape[:body_type]) if item_shape[:body_type]
126
+ if(item_shape[:additional_properties])
127
+ additional_properties!(item_shape[:additional_properties])
128
+ end
129
+ }
130
+ end
131
+
132
+ # Build the BaseShape element
133
+ # @see http://msdn.microsoft.com/en-us/library/aa580545.aspx
134
+ def base_shape!(base_shape)
135
+ @nbuild[NS_EWS_TYPES].BaseShape(base_shape.to_s.camel_case)
136
+ end
137
+
138
+ def body_type!(body_type)
139
+ body_type = body_type.to_s
140
+ if body_type =~ /html/i
141
+ body_type = body_type.upcase
142
+ else
143
+ body_type = body_type.downcase.capitalize
144
+ end
145
+ nbuild[NS_EWS_TYPES].BodyType(body_type)
146
+ end
147
+
148
+ # Build the ParentFolderIds element
149
+ # @see http://msdn.microsoft.com/en-us/library/aa565998.aspx
150
+ def parent_folder_ids!(pfids)
151
+ @nbuild[NS_EWS_MESSAGES].ParentFolderIds {
152
+ pfids.each do |pfid|
153
+ dispatch_folder_id!(pfid)
154
+ end
155
+ }
156
+ end
157
+
158
+ # Build the ParentFolderId element
159
+ # @see http://msdn.microsoft.com/en-us/library/aa563268.aspx
160
+ def parent_folder_id!(pfid)
161
+ @nbuild.ParentFolderId {
162
+ dispatch_folder_id!(pfid)
163
+ }
164
+ end
165
+
166
+ # Build the FolderIds element
167
+ # @see http://msdn.microsoft.com/en-us/library/aa580509.aspx
168
+ def folder_ids!(fids, act_as=nil)
169
+ ns = @nbuild.parent.name.match(/subscription/i) ? NS_EWS_TYPES : NS_EWS_MESSAGES
170
+ @nbuild[ns].FolderIds {
171
+ fids.each do |fid|
172
+ fid[:act_as] = act_as if act_as != nil
173
+ dispatch_folder_id!(fid)
174
+ end
175
+ }
176
+ end
177
+
178
+ # Build the SyncFolderId element
179
+ # @see http://msdn.microsoft.com/en-us/library/aa580296.aspx
180
+ def sync_folder_id!(fid)
181
+ @nbuild.SyncFolderId {
182
+ dispatch_folder_id!(fid)
183
+ }
184
+ end
185
+
186
+ # Build the DistinguishedFolderId element
187
+ # @see http://msdn.microsoft.com/en-us/library/aa580808.aspx
188
+ # @todo add support for the Mailbox child object
189
+ def distinguished_folder_id!(dfid, change_key = nil, act_as = nil)
190
+ attribs = {'Id' => dfid.to_s}
191
+ attribs['ChangeKey'] = change_key if change_key
192
+ @nbuild[NS_EWS_TYPES].DistinguishedFolderId(attribs) {
193
+ if ! act_as.nil?
194
+ mailbox!({:email_address => act_as})
195
+ end
196
+ }
197
+ end
198
+
199
+ # Build the FolderId element
200
+ # @see http://msdn.microsoft.com/en-us/library/aa579461.aspx
201
+ def folder_id!(fid, change_key = nil)
202
+ attribs = {'Id' => fid}
203
+ attribs['ChangeKey'] = change_key if change_key
204
+ @nbuild[NS_EWS_TYPES].FolderId(attribs)
205
+ end
206
+
207
+ # @see http://msdn.microsoft.com/en-us/library/aa563525(v=EXCHG.140).aspx
208
+ def item_ids!(item_ids)
209
+ @nbuild.ItemIds {
210
+ item_ids.each do |iid|
211
+ dispatch_item_id!(iid)
212
+ end
213
+ }
214
+ end
215
+
216
+ def parent_item_id!(id)
217
+ nbuild.ParentItemId {|x|
218
+ x.parent['Id'] = id[:id]
219
+ x.parent['ChangeKey'] = id[:change_key] if id[:change_key]
220
+ }
221
+ end
222
+
223
+ # @see http://msdn.microsoft.com/en-us/library/aa580234(v=EXCHG.140).aspx
224
+ def item_id!(id)
225
+ nbuild[NS_EWS_TYPES].ItemId {|x|
226
+ x.parent['Id'] = id[:id]
227
+ x.parent['ChangeKey'] = id[:change_key] if id[:change_key]
228
+ }
229
+ end
230
+
231
+ # @see http://msdn.microsoft.com/en-us/library/aa580744(v=EXCHG.140).aspx
232
+ def occurrence_item_id!(id)
233
+ @nbuild[NS_EWS_TYPES].OccurrenceItemId {|x|
234
+ x.parent['RecurringMasterId'] = id[:recurring_master_id]
235
+ x.parent['ChangeKey'] = id[:change_key] if id[:change_key]
236
+ x.parent['InstanceIndex'] = id[:instance_index]
237
+ }
238
+ end
239
+
240
+ # @see http://msdn.microsoft.com/en-us/library/aa581019(v=EXCHG.140).aspx
241
+ def recurring_master_item_id!(id)
242
+ @nbuild[NS_EWS_TYPES].RecurringMasterItemId {|x|
243
+ x.parent['OccurrenceId'] = id[:occurrence_id]
244
+ x.parent['ChangeKey'] = id[:change_key] if id[:change_key]
245
+ }
246
+ end
247
+
248
+ # @see http://msdn.microsoft.com/en-us/library/aa565020(v=EXCHG.140).aspx
249
+ def to_folder_id!(to_fid)
250
+ @nbuild[NS_EWS_MESSAGES].ToFolderId {
251
+ dispatch_folder_id!(to_fid)
252
+ }
253
+ end
254
+
255
+ # @see http://msdn.microsoft.com/en-us/library/aa564009.aspx
256
+ def folders!(folders)
257
+ @nbuild.Folders {|x|
258
+ folders.each do |fold|
259
+ fold.each_pair do |ftype, vars| # convenience, should only be one pair
260
+ ftype = "#{ftype}!".to_sym
261
+ if self.respond_to? ftype
262
+ self.send ftype, vars
263
+ else
264
+ raise Viewpoint::EWS::EwsNotImplemented,
265
+ "#{ftype} not implemented as a builder."
266
+ end
267
+ end
268
+ end
269
+ }
270
+ end
271
+
272
+ def folder!(folder, type = :Folder)
273
+ nbuild[NS_EWS_TYPES].send(type) {|x|
274
+ folder.each_pair do |e,v|
275
+ ftype = "#{e}!".to_sym
276
+ if e == :folder_id
277
+ dispatch_folder_id!(v)
278
+ elsif self.respond_to?(ftype)
279
+ self.send ftype, v
280
+ else
281
+ raise Viewpoint::EWS::EwsNotImplemented,
282
+ "#{ftype} not implemented as a builder."
283
+ end
284
+ end
285
+ }
286
+ end
287
+
288
+ def calendar_folder!(folder)
289
+ folder! folder, :CalendarFolder
290
+ end
291
+
292
+ def contacts_folder!(folder)
293
+ folder! folder, :ContactsFolder
294
+ end
295
+
296
+ def search_folder!(folder)
297
+ folder! folder, :SearchFolder
298
+ end
299
+
300
+ def tasks_folder!(folder)
301
+ folder! folder, :TasksFolder
302
+ end
303
+
304
+ def display_name!(name)
305
+ nbuild[NS_EWS_TYPES].DisplayName(name)
306
+ end
307
+
308
+ # Build the AdditionalProperties element
309
+ # @see http://msdn.microsoft.com/en-us/library/aa563810.aspx
310
+ def additional_properties!(addprops)
311
+ @nbuild[NS_EWS_TYPES].AdditionalProperties {
312
+ addprops.each_pair {|k,v|
313
+ dispatch_field_uri!({k => v})
314
+ }
315
+ }
316
+ end
317
+
318
+ # Build the Mailbox element.
319
+ # This element is commonly used for delegation. Typically passing an
320
+ # email_address is sufficient
321
+ # @see http://msdn.microsoft.com/en-us/library/aa565036.aspx
322
+ # @param [Hash] mailbox A well-formated hash
323
+ def mailbox!(mbox)
324
+ nbuild[NS_EWS_TYPES].Mailbox {
325
+ name!(mbox[:name]) if mbox[:name]
326
+ email_address!(mbox[:email_address]) if mbox[:email_address]
327
+ address!(mbox[:address]) if mbox[:address] # for Availability query
328
+ routing_type!(mbox[:routing_type]) if mbox[:routing_type]
329
+ mailbox_type!(mbox[:mailbox_type]) if mbox[:mailbox_type]
330
+ item_id!(mbox[:item_id]) if mbox[:item_id]
331
+ }
332
+ end
333
+
334
+ def name!(name)
335
+ nbuild[NS_EWS_TYPES].Name(name)
336
+ end
337
+
338
+ def email_address!(email)
339
+ nbuild[NS_EWS_TYPES].EmailAddress(email)
340
+ end
341
+
342
+ def address!(email)
343
+ nbuild[NS_EWS_TYPES].Address(email)
344
+ end
345
+
346
+ # This is stupid. The only valid value is "SMTP"
347
+ def routing_type!(type)
348
+ nbuild[NS_EWS_TYPES].RoutingType(type)
349
+ end
350
+
351
+ def mailbox_type!(type)Standard
352
+ nbuild[NS_EWS_TYPES].MailboxType(type)
353
+ end
354
+
355
+ def user_oof_settings!(opts)
356
+ nbuild[NS_EWS_TYPES].UserOofSettings {
357
+ nbuild.OofState(opts[:oof_state].to_s.camel_case)
358
+ nbuild.ExternalAudience(opts[:external_audience].to_s.camel_case) if opts[:external_audience]
359
+ duration!(opts[:duration]) if opts[:duration]
360
+ nbuild.InternalReply {
361
+ nbuild.Message(opts[:internal_reply])
362
+ } if opts[:external_reply]
363
+ nbuild.ExternalReply {
364
+ nbuild.Message(opts[:external_reply])
365
+ } if opts[:external_reply]
366
+ }
367
+ end
368
+
369
+ def duration!(opts)
370
+ nbuild.Duration {
371
+ nbuild.StartTime(opts[:start_time].new_offset(0).strftime('%FT%H:%M:%SZ'))
372
+ nbuild.EndTime(opts[:end_time].new_offset(0).strftime('%FT%H:%M:%SZ'))
373
+ }
374
+ end
375
+
376
+ def mailbox_data!(md)
377
+ nbuild[NS_EWS_TYPES].MailboxData {
378
+ nbuild.Email {
379
+ mbox = md[:email]
380
+ name!(mbox[:name]) if mbox[:name]
381
+ address!(mbox[:address]) if mbox[:address] # for Availability query
382
+ routing_type!(mbox[:routing_type]) if mbox[:routing_type]
383
+ }
384
+ nbuild.AttendeeType 'Required'
385
+ }
386
+ end
387
+
388
+ def free_busy_view_options!(opts)
389
+ nbuild[NS_EWS_TYPES].FreeBusyViewOptions {
390
+ nbuild.TimeWindow {
391
+ nbuild.StartTime(opts[:time_window][:start_time])
392
+ nbuild.EndTime(opts[:time_window][:end_time])
393
+ }
394
+ nbuild.RequestedView(opts[:requested_view][:requested_free_busy_view].to_s.camel_case)
395
+ }
396
+ end
397
+
398
+ def suggestions_view_options!(opts)
399
+ end
400
+
401
+ def time_zone!(zone)
402
+ nbuild[NS_EWS_TYPES].TimeZone {
403
+ nbuild.Bias(480)
404
+ nbuild.StandardTime {
405
+ nbuild.Bias(0)
406
+ nbuild.Time("02:00:00")
407
+ nbuild.DayOrder(5)
408
+ nbuild.Month(10)
409
+ nbuild.DayOfWeek('Sunday')
410
+ }
411
+ nbuild.DaylightTime {
412
+ nbuild.Bias(-60)
413
+ nbuild.Time("02:00:00")
414
+ nbuild.DayOrder(1)
415
+ nbuild.Month(4)
416
+ nbuild.DayOfWeek('Sunday')
417
+ }
418
+ }
419
+ end
420
+
421
+ # Build the Restriction element
422
+ # @see http://msdn.microsoft.com/en-us/library/aa563791.aspx
423
+ # @param [Hash] restriction a well-formatted Hash that can be fed to #build_xml!
424
+ def restriction!(restriction)
425
+ @nbuild[NS_EWS_MESSAGES].Restriction {
426
+ restriction.each_pair do |k,v|
427
+ self.send normalize_type(k), v
428
+ end
429
+ }
430
+ end
431
+
432
+ def and_r(expr)
433
+ and_or('And', expr)
434
+ end
435
+
436
+ def or_r(expr)
437
+ and_or('Or', expr)
438
+ end
439
+
440
+ def and_or(type, expr)
441
+ @nbuild[NS_EWS_TYPES].send(type) {
442
+ expr.each do |e|
443
+ type = e.keys.first
444
+ self.send normalize_type(type), e[type]
445
+ end
446
+ }
447
+ end
448
+
449
+ def not_r(expr)
450
+ @nbuild[NS_EWS_TYPES].Not {
451
+ type = expr.keys.first
452
+ self.send(type, expr[type])
453
+ }
454
+ end
455
+
456
+ def contains(expr)
457
+ @nbuild[NS_EWS_TYPES].Contains(
458
+ 'ContainmentMode' => expr.delete(:containment_mode),
459
+ 'ContainmentComparison' => expr.delete(:containment_comparison)) {
460
+ c = expr.delete(:constant) # remove constant 1st for ordering
461
+ type = expr.keys.first
462
+ self.send(type, expr[type])
463
+ constant(c)
464
+ }
465
+ end
466
+
467
+ def excludes(expr)
468
+ @nbuild[NS_EWS_TYPES].Excludes {
469
+ b = expr.delete(:bitmask) # remove bitmask 1st for ordering
470
+ type = expr.keys.first
471
+ self.send(type, expr[type])
472
+ bitmask(b)
473
+ }
474
+ end
475
+
476
+ def exists(expr)
477
+ @nbuild[NS_EWS_TYPES].Exists {
478
+ type = expr.keys.first
479
+ self.send(type, expr[type])
480
+ }
481
+ end
482
+
483
+ def bitmask(expr)
484
+ @nbuild[NS_EWS_TYPES].Bitmask('Value' => expr[:value])
485
+ end
486
+
487
+ def is_equal_to(expr)
488
+ restriction_compare('IsEqualTo',expr)
489
+ end
490
+
491
+ def is_greater_than(expr)
492
+ restriction_compare('IsGreaterThan',expr)
493
+ end
494
+
495
+ def is_greater_than_or_equal_to(expr)
496
+ restriction_compare('IsGreaterThanOrEqualTo',expr)
497
+ end
498
+
499
+ def is_less_than(expr)
500
+ restriction_compare('IsLessThan',expr)
501
+ end
502
+
503
+ def is_less_than_or_equal_to(expr)
504
+ restriction_compare('IsLessThanOrEqualTo',expr)
505
+ end
506
+
507
+ def is_not_equal_to(expr)
508
+ restriction_compare('IsNotEqualTo',expr)
509
+ end
510
+
511
+ def restriction_compare(type,expr)
512
+ nbuild[NS_EWS_TYPES].send(type) {
513
+ expr.each do |e|
514
+ e.each_pair do |k,v|
515
+ self.send(k, v)
516
+ end
517
+ end
518
+ }
519
+ end
520
+
521
+ def field_uRI(expr)
522
+ nbuild[NS_EWS_TYPES].FieldURI('FieldURI' => expr[:field_uRI])
523
+ end
524
+
525
+ def indexed_field_uRI(expr)
526
+ nbuild[NS_EWS_TYPES].IndexedFieldURI(
527
+ 'FieldURI' => expr[:field_uRI],
528
+ 'FieldIndex' => expr[:field_index]
529
+ )
530
+ end
531
+
532
+ def extended_field_uRI(expr)
533
+ nbuild[NS_EWS_TYPES].ExtendedFieldURI {
534
+ nbuild.parent['DistinguishedPropertySetId'] = expr[:distinguished_property_set_id] if expr[:distinguished_property_set_id]
535
+ nbuild.parent['PropertySetId'] = expr[:property_set_id] if expr[:property_set_id]
536
+ nbuild.parent['PropertyTag'] = expr[:property_tag] if expr[:property_tag]
537
+ nbuild.parent['PropertyName'] = expr[:property_name] if expr[:property_name]
538
+ nbuild.parent['PropertyId'] = expr[:property_id] if expr[:property_id]
539
+ nbuild.parent['PropertyType'] = expr[:property_type] if expr[:property_type]
540
+ }
541
+ end
542
+
543
+ def field_uRI_or_constant(expr)
544
+ nbuild[NS_EWS_TYPES].FieldURIOrConstant {
545
+ type = expr.keys.first
546
+ self.send(type, expr[type])
547
+ }
548
+ end
549
+
550
+ def constant(expr)
551
+ nbuild[NS_EWS_TYPES].Constant('Value' => expr[:value])
552
+ end
553
+
554
+ # Build the CalendarView element
555
+ def calendar_view!(cal_view)
556
+ attribs = {}
557
+ cal_view.each_pair {|k,v| attribs[k.to_s.camel_case] = v.to_s}
558
+ @nbuild[NS_EWS_MESSAGES].CalendarView(attribs)
559
+ end
560
+
561
+ # Build the ContactsView element
562
+ def contacts_view!(con_view)
563
+ attribs = {}
564
+ con_view.each_pair {|k,v| attribs[k.to_s.camel_case] = v.to_s}
565
+ @nbuild[NS_EWS_MESSAGES].ContactsView(attribs)
566
+ end
567
+
568
+ # @see http://msdn.microsoft.com/en-us/library/aa579678(v=EXCHG.140).aspx
569
+ def event_types!(evtypes)
570
+ @nbuild[NS_EWS_TYPES].EventTypes {
571
+ evtypes.each do |et|
572
+ @nbuild[NS_EWS_TYPES].EventType(et.to_s.camel_case)
573
+ end
574
+ }
575
+ end
576
+
577
+ # @see http://msdn.microsoft.com/en-us/library/aa565886(v=EXCHG.140).aspx
578
+ def watermark!(wmark, ns = NS_EWS_TYPES)
579
+ @nbuild[ns].Watermark(wmark)
580
+ end
581
+
582
+ # @see http://msdn.microsoft.com/en-us/library/aa565201(v=EXCHG.140).aspx
583
+ def timeout!(tout)
584
+ @nbuild[NS_EWS_TYPES].Timeout(tout)
585
+ end
586
+
587
+ # @see http://msdn.microsoft.com/en-us/library/aa564048(v=EXCHG.140).aspx
588
+ def status_frequency!(freq)
589
+ @nbuild[NS_EWS_TYPES].StatusFrequency(freq)
590
+ end
591
+
592
+ # @see http://msdn.microsoft.com/en-us/library/aa566309(v=EXCHG.140).aspx
593
+ def uRL!(url)
594
+ @nbuild[NS_EWS_TYPES].URL(url)
595
+ end
596
+
597
+ # @see http://msdn.microsoft.com/en-us/library/aa563790(v=EXCHG.140).aspx
598
+ def subscription_id!(subid)
599
+ @nbuild.SubscriptionId(subid)
600
+ end
601
+
602
+ # @see http://msdn.microsoft.com/en-us/library/aa563455(v=EXCHG.140).aspx
603
+ def pull_subscription_request(subopts)
604
+ subscribe_all = subopts[:subscribe_to_all_folders] ? 'true' : 'false'
605
+ @nbuild.PullSubscriptionRequest('SubscribeToAllFolders' => subscribe_all) {
606
+ folder_ids!(subopts[:folder_ids]) if subopts[:folder_ids]
607
+ event_types!(subopts[:event_types]) if subopts[:event_types]
608
+ watermark!(subopts[:watermark]) if subopts[:watermark]
609
+ timeout!(subopts[:timeout]) if subopts[:timeout]
610
+ }
611
+ end
612
+
613
+ # @see http://msdn.microsoft.com/en-us/library/aa563599(v=EXCHG.140).aspx
614
+ def push_subscription_request(subopts)
615
+ subscribe_all = subopts[:subscribe_to_all_folders] ? 'true' : 'false'
616
+ @nbuild.PushSubscriptionRequest('SubscribeToAllFolders' => subscribe_all) {
617
+ folder_ids!(subopts[:folder_ids]) if subopts[:folder_ids]
618
+ event_types!(subopts[:event_types]) if subopts[:event_types]
619
+ watermark!(subopts[:watermark]) if subopts[:watermark]
620
+ status_frequency!(subopts[:status_frequency]) if subopts[:status_frequency]
621
+ uRL!(subopts[:uRL]) if subopts[:uRL]
622
+ }
623
+ end
624
+
625
+ # @see http://msdn.microsoft.com/en-us/library/ff406182(v=EXCHG.140).aspx
626
+ def streaming_subscription_request(subopts)
627
+ subscribe_all = subopts[:subscribe_to_all_folders] ? 'true' : 'false'
628
+ @nbuild.StreamingSubscriptionRequest('SubscribeToAllFolders' => subscribe_all) {
629
+ folder_ids!(subopts[:folder_ids]) if subopts[:folder_ids]
630
+ event_types!(subopts[:event_types]) if subopts[:event_types]
631
+ }
632
+ end
633
+
634
+ # @see http://msdn.microsoft.com/en-us/library/aa565970(v=EXCHG.140).aspx
635
+ def sync_state!(syncstate)
636
+ @nbuild.SyncState(syncstate)
637
+ end
638
+
639
+ # @see http://msdn.microsoft.com/en-us/library/aa563785(v=EXCHG.140).aspx
640
+ def ignore!(item_ids)
641
+ @nbuild.Ignore {
642
+ item_ids.each do |iid|
643
+ item_id!(iid)
644
+ end
645
+ }
646
+ end
647
+
648
+ # @see http://msdn.microsoft.com/en-us/library/aa566325(v=EXCHG.140).aspx
649
+ def max_changes_returned!(cnum)
650
+ @nbuild[NS_EWS_MESSAGES].MaxChangesReturned(cnum)
651
+ end
652
+
653
+ # @see http://msdn.microsoft.com/en-us/library/dd899531(v=EXCHG.140).aspx
654
+ def sync_scope!(scope)
655
+ @nbuild.SyncScope(scope)
656
+ end
657
+
658
+ # @see http://msdn.microsoft.com/en-us/library/aa580758(v=EXCHG.140).aspx
659
+ def saved_item_folder_id!(fid)
660
+ @nbuild.SavedItemFolderId {
661
+ dispatch_folder_id!(fid)
662
+ }
663
+ end
664
+
665
+ # @see http://msdn.microsoft.com/en-us/library/aa565652(v=exchg.140).aspx
666
+ def item!(item)
667
+ nbuild.Item {
668
+ item.each_pair {|k,v|
669
+ self.send("#{k}!", v)
670
+ }
671
+ }
672
+ end
673
+
674
+ def message!(item)
675
+ nbuild[NS_EWS_TYPES].Message {
676
+ item.each_pair {|k,v|
677
+ self.send("#{k}!", v)
678
+ }
679
+ }
680
+ end
681
+
682
+ def calendar_item!(item)
683
+ nbuild[NS_EWS_TYPES].CalendarItem {
684
+ item.each_pair {|k,v|
685
+ self.send("#{k}!", v)
686
+ }
687
+ }
688
+ end
689
+
690
+ def forward_item!(item)
691
+ nbuild[NS_EWS_TYPES].ForwardItem {
692
+ item.each_pair {|k,v|
693
+ self.send("#{k}!", v)
694
+ }
695
+ }
696
+ end
697
+
698
+ def reply_to_item!(item)
699
+ nbuild[NS_EWS_TYPES].ReplyToItem {
700
+ item.each_pair {|k,v|
701
+ self.send("#{k}!", v)
702
+ }
703
+ }
704
+ end
705
+
706
+ def reply_all_to_item!(item)
707
+ nbuild[NS_EWS_TYPES].ReplyAllToItem {
708
+ item.each_pair {|k,v|
709
+ self.send("#{k}!", v)
710
+ }
711
+ }
712
+ end
713
+
714
+ def reference_item_id!(id)
715
+ nbuild[NS_EWS_TYPES].ReferenceItemId {|x|
716
+ x.parent['Id'] = id[:id]
717
+ x.parent['ChangeKey'] = id[:change_key] if id[:change_key]
718
+ }
719
+ end
720
+
721
+ def subject!(sub)
722
+ nbuild[NS_EWS_TYPES].Subject(sub)
723
+ end
724
+
725
+ def body!(b)
726
+ nbuild[NS_EWS_TYPES].Body(b[:text]) {|x|
727
+ x.parent['BodyType'] = b[:body_type] if b[:body_type]
728
+ }
729
+ end
730
+
731
+ def new_body_content!(b)
732
+ nbuild[NS_EWS_TYPES].NewBodyContent(b[:text]) {|x|
733
+ x.parent['BodyType'] = b[:body_type] if b[:body_type]
734
+ }
735
+ end
736
+
737
+ # @see http://msdn.microsoft.com/en-us/library/aa563719(v=exchg.140).aspx
738
+ # @param [Array] r An array of Mailbox type hashes to send to #mailbox!
739
+ def to_recipients!(r)
740
+ nbuild[NS_EWS_TYPES].ToRecipients {
741
+ r.each {|mbox| mailbox!(mbox[:mailbox]) }
742
+ }
743
+ end
744
+
745
+ def cc_recipients!(r)
746
+ nbuild[NS_EWS_TYPES].CcRecipients {
747
+ r.each {|mbox| mailbox!(mbox[:mailbox]) }
748
+ }
749
+ end
750
+
751
+ def bcc_recipients!(r)
752
+ nbuild[NS_EWS_TYPES].BccRecipients {
753
+ r.each {|mbox| mailbox!(mbox[:mailbox]) }
754
+ }
755
+ end
756
+
757
+ def required_attendees!(attendees)
758
+ nbuild[NS_EWS_TYPES].RequiredAttendees {
759
+ attendees.each {|a| attendee!(a[:attendee])}
760
+ }
761
+ end
762
+
763
+ def optional_attendees!(attendees)
764
+ nbuild[NS_EWS_TYPES].OptionalAttendees {
765
+ attendees.each {|a| attendee!(a[:attendee])}
766
+ }
767
+ end
768
+
769
+ def resources!(attendees)
770
+ nbuild[NS_EWS_TYPES].Resources {
771
+ attendees.each {|a| attendee!(a[:attendee])}
772
+ }
773
+ end
774
+
775
+ def attendee!(a)
776
+ nbuild[NS_EWS_TYPES].Attendee {
777
+ mailbox!(a[:mailbox])
778
+ #@todo support ResponseType, LastResponseTime: http://msdn.microsoft.com/en-us/library/aa580339.aspx
779
+ }
780
+ end
781
+
782
+ def start!(st)
783
+ nbuild[NS_EWS_TYPES].Start(st[:text])
784
+ end
785
+
786
+ def end!(et)
787
+ nbuild[NS_EWS_TYPES].End(et[:text])
788
+ end
789
+
790
+ # @see http://msdn.microsoft.com/en-us/library/aa565428(v=exchg.140).aspx
791
+ def item_changes!(changes)
792
+ nbuild.ItemChanges {
793
+ changes.each do |chg|
794
+ item_change!(chg)
795
+ end
796
+ }
797
+ end
798
+
799
+ # @see http://msdn.microsoft.com/en-us/library/aa581081(v=exchg.140).aspx
800
+ def item_change!(change)
801
+ @nbuild[NS_EWS_TYPES].ItemChange {
802
+ updates = change.delete(:updates) # Remove updates so dispatch_item_id works correctly
803
+ dispatch_item_id!(change)
804
+ updates!(updates)
805
+ }
806
+ end
807
+
808
+ # @see http://msdn.microsoft.com/en-us/library/aa581074(v=exchg.140).aspx
809
+ def updates!(updates)
810
+ @nbuild[NS_EWS_TYPES].Updates {
811
+ updates.each do |update|
812
+ dispatch_update_type!(update)
813
+ end
814
+ }
815
+ end
816
+
817
+ # @see http://msdn.microsoft.com/en-us/library/aa581317(v=exchg.140).aspx
818
+ def append_to_item_field!(upd)
819
+ uri = upd.select {|k,v| k =~ /_uri/i}
820
+ raise EwsBadArgumentError, "Bad argument given for AppendToItemField." if uri.keys.length != 1
821
+ upd.delete(uri.keys.first)
822
+ @nbuild.AppendToItemField {
823
+ dispatch_field_uri!(uri)
824
+ dispatch_field_item!(upd)
825
+ }
826
+ end
827
+
828
+ # @see http://msdn.microsoft.com/en-us/library/aa581487(v=exchg.140).aspx
829
+ def set_item_field!(upd)
830
+ uri = upd.select {|k,v| k =~ /_uri/i}
831
+ raise EwsBadArgumentError, "Bad argument given for SetItemField." if uri.keys.length != 1
832
+ upd.delete(uri.keys.first)
833
+ @nbuild.SetItemField {
834
+ dispatch_field_uri!(uri)
835
+ dispatch_field_item!(upd)
836
+ }
837
+ end
838
+
839
+ # @see http://msdn.microsoft.com/en-us/library/aa580330(v=exchg.140).aspx
840
+ def delete_item_field!(upd)
841
+ uri = upd.select {|k,v| k =~ /_uri/i}
842
+ raise EwsBadArgumentError, "Bad argument given for SetItemField." if uri.keys.length != 1
843
+ @nbuild.DeleteItemField {
844
+ dispatch_field_uri!(uri)
845
+ }
846
+ end
847
+
848
+ # @see http://msdn.microsoft.com/en-us/library/ff709497(v=exchg.140).aspx
849
+ def return_new_item_ids!(retval)
850
+ @nbuild.ReturnNewItemIds(retval)
851
+ end
852
+
853
+ def file_attachment!(fa)
854
+ @nbuild[NS_EWS_TYPES].FileAttachment {
855
+ @nbuild.Name(fa.name)
856
+ @nbuild.Content(fa.content)
857
+ }
858
+ end
859
+
860
+ def item_attachment!(ia)
861
+ @nbuild[NS_EWS_TYPES].ItemAttachment {
862
+ @nbuild.Name(ia.name)
863
+ @nbuild.Item {
864
+ item_id!(ia.item)
865
+ }
866
+ }
867
+ end
868
+
869
+ # Build the AttachmentIds element
870
+ # @see http://msdn.microsoft.com/en-us/library/aa580686.aspx
871
+ def attachment_ids!(aids)
872
+ @nbuild.AttachmentIds {
873
+ @nbuild.parent.default_namespace = @default_ns
874
+ aids.each do |aid|
875
+ attachment_id!(aid)
876
+ end
877
+ }
878
+ end
879
+
880
+ # Build the AttachmentId element
881
+ # @see http://msdn.microsoft.com/en-us/library/aa580764.aspx
882
+ def attachment_id!(aid)
883
+ attribs = {'Id' => aid}
884
+ @nbuild[NS_EWS_TYPES].AttachmentId(attribs)
885
+ end
886
+
887
+ def user_configuration_name!(cfg_name)
888
+ attribs = {'Name' => cfg_name.delete(:name)}
889
+ @nbuild[NS_EWS_MESSAGES].UserConfigurationName(attribs) {
890
+ fid = cfg_name.keys.first
891
+ self.send "#{fid}!", cfg_name[fid][:id], cfg_name[fid][:change_key]
892
+ }
893
+ end
894
+
895
+ def user_configuration_properties!(cfg_prop)
896
+ @nbuild[NS_EWS_MESSAGES].UserConfigurationProperties(cfg_prop)
897
+ end
898
+
899
+ # ---------------------- Helpers -------------------- #
900
+
901
+ # A helper method to dispatch to a FolderId or DistinguishedFolderId correctly
902
+ # @param [Hash] fid A folder_id
903
+ # Ex: {:id => myid, :change_key => ck}
904
+ def dispatch_folder_id!(fid)
905
+ if(fid[:id].is_a?(String))
906
+ folder_id!(fid[:id], fid[:change_key])
907
+ elsif(fid[:id].is_a?(Symbol))
908
+ distinguished_folder_id!(fid[:id], fid[:change_key], fid[:act_as])
909
+ else
910
+ raise EwsBadArgumentError, "Bad argument given for a FolderId. #{fid[:id].class}"
911
+ end
912
+ end
913
+
914
+ # A helper method to dispatch to an ItemId, OccurrenceItemId, or a RecurringMasterItemId
915
+ # @param [Hash] iid The item id of some type
916
+ def dispatch_item_id!(iid)
917
+ type = iid.keys.first
918
+ item = iid[type]
919
+ case type
920
+ when :item_id
921
+ item_id!(item)
922
+ when :occurrence_item_id
923
+ occurrence_item_id!(
924
+ item[:recurring_master_id], item[:change_key], item[:instance_index])
925
+ when :recurring_master_item_id
926
+ recurring_master_item_id!(item[:occurrence_id], item[:change_key])
927
+ else
928
+ raise EwsBadArgumentError, "Bad ItemId type. #{type}"
929
+ end
930
+ end
931
+
932
+ # A helper method to dispatch to a AppendToItemField, SetItemField, or
933
+ # DeleteItemField
934
+ # @param [Hash] update An update of some type
935
+ def dispatch_update_type!(update)
936
+ type = update.keys.first
937
+ upd = update[type]
938
+ case type
939
+ when :append_to_item_field
940
+ append_to_item_field!(upd)
941
+ when :set_item_field
942
+ set_item_field!(upd)
943
+ when :delete_item_field
944
+ delete_item_field!(upd)
945
+ else
946
+ raise EwsBadArgumentError, "Bad Update type. #{type}"
947
+ end
948
+ end
949
+
950
+ # A helper to dispatch to a FieldURI, IndexedFieldURI, or an ExtendedFieldURI
951
+ # @todo Implement ExtendedFieldURI
952
+ def dispatch_field_uri!(uri)
953
+ type = uri.keys.first
954
+ vals = uri[type].is_a?(Array) ? uri[type] : [uri[type]]
955
+ case type
956
+ when :field_uRI, :field_uri
957
+ vals.each do |val|
958
+ nbuild.FieldURI('FieldURI' => val[:field_uRI])
959
+ end
960
+ when :indexed_field_uRI, :indexed_field_uri
961
+ vals.each do |val|
962
+ nbuild.IndexedFieldURI('FieldURI' => val[:field_uRI], 'FieldIndex' => val[:field_index])
963
+ end
964
+ when :extended_field_uRI, :extended_field_uri
965
+ vals.each do |val|
966
+ nbuild.ExtendedFieldURI {
967
+ nbuild.parent['DistinguishedPropertySetId'] = val[:distinguished_property_set_id] if val[:distinguished_property_set_id]
968
+ nbuild.parent['PropertySetId'] = val[:property_set_id] if val[:property_set_id]
969
+ nbuild.parent['PropertyTag'] = val[:property_tag] if val[:property_tag]
970
+ nbuild.parent['PropertyName'] = val[:property_name] if val[:property_name]
971
+ nbuild.parent['PropertyId'] = val[:property_id] if val[:property_id]
972
+ nbuild.parent['PropertyType'] = val[:property_type] if val[:property_type]
973
+ }
974
+ end
975
+ else
976
+ raise EwsBadArgumentError, "Bad URI type. #{type}"
977
+ end
978
+
979
+ end
980
+
981
+ def dispatch_field_item!(item)
982
+ build_xml!(item)
983
+ end
984
+
985
+
986
+ private
987
+
988
+ def parent_namespace(node)
989
+ node.parent.namespace_definitions.find {|ns| ns.prefix == NS_SOAP}
990
+ end
991
+
992
+ def set_version_header!(version)
993
+ if version && !(version == 'none')
994
+ nbuild[NS_EWS_TYPES].RequestServerVersion {|x|
995
+ x.parent['Version'] = version
996
+ }
997
+ end
998
+ end
999
+
1000
+ # some methods need special naming so they use the '_r' suffix like 'and'
1001
+ def normalize_type(type)
1002
+ case type
1003
+ when :and, :or, :not
1004
+ "#{type}_r".to_sym
1005
+ else
1006
+ type
1007
+ end
1008
+ end
1009
+
1010
+ end # EwsBuilder
1011
+ end # Viewpoint::EWS::SOAP