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,61 @@
1
+ module Viewpoint::EWS::SOAP
2
+
3
+ # Exchange Availability operations as listed in the EWS Documentation.
4
+ # @see http://msdn.microsoft.com/en-us/library/bb409286.aspx
5
+ module ExchangeAvailability
6
+ include Viewpoint::EWS::SOAP
7
+
8
+ # -------------- Availability Operations -------------
9
+
10
+ # Gets a mailbox user's Out of Office (OOF) settings and messages.
11
+ # @see http://msdn.microsoft.com/en-us/library/aa563465.aspx
12
+ # @param [Hash] opts
13
+ # @option opts [String] :address the email address of the user
14
+ # @option opts [String] :name the user display name (optional)
15
+ # @option opts [String] :routing_type the routing protocol (optional and stupid)
16
+ def get_user_oof_settings(opts)
17
+ opts = opts.clone
18
+ [:address].each do |k|
19
+ validate_param(opts, k, true)
20
+ end
21
+ req = build_soap! do |type, builder|
22
+ if(type == :header)
23
+ else
24
+ builder.nbuild.GetUserOofSettingsRequest {|x|
25
+ x.parent.default_namespace = @default_ns
26
+ builder.mailbox!(opts)
27
+ }
28
+ end
29
+ end
30
+ do_soap_request(req, response_class: EwsSoapAvailabilityResponse)
31
+ end
32
+
33
+ # Sets a mailbox user's Out of Office (OOF) settings and message.
34
+ # @see http://msdn.microsoft.com/en-us/library/aa580294.aspx
35
+ # @param [Hash] opts
36
+ # @option opts [Hash] :mailbox the mailbox hash for the use
37
+ # @option opts [String,Symbol] :oof_state :enabled, :disabled, :scheduled
38
+ # @option opts [Hash] :duration {start_time: DateTime, end_time: DateTime}
39
+ # @option opts [String] :internal_reply
40
+ # @option opts [String] :external_reply
41
+ # @option opts [String,Symbol] :external_audience :none, :known, :all
42
+ def set_user_oof_settings(opts)
43
+ opts = opts.clone
44
+ [:mailbox, :oof_state].each do |k|
45
+ validate_param(opts, k, true)
46
+ end
47
+ req = build_soap! do |type, builder|
48
+ if(type == :header)
49
+ else
50
+ builder.nbuild.SetUserOofSettingsRequest {|x|
51
+ x.parent.default_namespace = @default_ns
52
+ builder.mailbox! opts.delete(:mailbox)
53
+ builder.user_oof_settings!(opts)
54
+ }
55
+ end
56
+ end
57
+ do_soap_request(req, response_class: EwsSoapAvailabilityResponse)
58
+ end
59
+
60
+ end #ExchangeAvailability
61
+ end
@@ -0,0 +1,780 @@
1
+ module Viewpoint::EWS::SOAP
2
+
3
+ # Exchange Data Service operations as listed in the EWS Documentation.
4
+ # @see http://msdn.microsoft.com/en-us/library/bb409286.aspx
5
+ module ExchangeDataServices
6
+ include Viewpoint::EWS::SOAP
7
+
8
+ # -------------- Item Operations -------------
9
+
10
+ # Identifies items that are located in a specified folder
11
+ # @see http://msdn.microsoft.com/en-us/library/aa566107.aspx
12
+ #
13
+ # @param [Hash] opts
14
+ # @option opts [Array<Hash>] :parent_folder_ids An Array of folder id Hashes, either a
15
+ # DistinguishedFolderId (must me a Symbol) or a FolderId (String)
16
+ # [{:id => <myid>, :change_key => <ck>}, {:id => :root}]
17
+ # @option opts [String] :traversal Shallow/Deep/SoftDeleted
18
+ # @option opts [Hash] :item_shape defines the ItemShape node
19
+ # @option item_shape [String] :base_shape IdOnly/Default/AllProperties
20
+ # @option item_shape :additional_properties
21
+ # See: http://msdn.microsoft.com/en-us/library/aa563810.aspx
22
+ # @option opts [Hash] :calendar_view Limit FindItem by a start and end date
23
+ # {:calendar_view => {:max_entries_returned => 2, :start_date =>
24
+ # <DateTime Obj>, :end_date => <DateTime Obj>}}
25
+ # @option opts [Hash] :contacts_view Limit FindItem between contact names
26
+ # {:contacts_view => {:max_entries_returned => 2, :initial_name => 'Dan',
27
+ # :final_name => 'Wally'}}
28
+ # @example
29
+ # { :parent_folder_ids => [{:id => root}],
30
+ # :traversal => 'Shallow',
31
+ # :item_shape => {:base_shape => 'Default'} }
32
+ def find_item(opts)
33
+ opts = opts.clone
34
+ [:parent_folder_ids, :traversal, :item_shape].each do |k|
35
+ validate_param(opts, k, true)
36
+ end
37
+ req = build_soap! do |type, builder|
38
+ if(type == :header)
39
+ else
40
+ builder.nbuild.FindItem(:Traversal => camel_case(opts[:traversal])) {
41
+ builder.nbuild.parent.default_namespace = @default_ns
42
+ builder.item_shape!(opts[:item_shape])
43
+ builder.indexed_page_item_view!(opts[:indexed_page_item_view]) if opts[:indexed_page_item_view]
44
+ # @todo add FractionalPageFolderView
45
+ builder.calendar_view!(opts[:calendar_view]) if opts[:calendar_view]
46
+ builder.contacts_view!(opts[:contacts_view]) if opts[:contacts_view]
47
+ builder.restriction!(opts[:restriction]) if opts[:restriction]
48
+ builder.parent_folder_ids!(opts[:parent_folder_ids])
49
+ }
50
+ end
51
+ end
52
+ do_soap_request(req, response_class: EwsResponse)
53
+ end
54
+
55
+ # Gets items from the Exchange store
56
+ # @see http://msdn.microsoft.com/en-us/library/aa565934(v=EXCHG.140).aspx
57
+ #
58
+ # @param [Hash] opts
59
+ # @option opts [Hash] :item_shape The item shape properties
60
+ # Ex: {:base_shape => 'Default'}
61
+ # @option opts [Array<Hash>] :item_ids ItemIds Hash. The keys in these Hashes can be
62
+ # :item_id, :occurrence_item_id, or :recurring_master_item_id. Please see the
63
+ # Microsoft docs for more information.
64
+ # @example
65
+ # opts = {
66
+ # :item_shape => {:base_shape => 'Default'},
67
+ # :item_ids => [
68
+ # {:item_id => {:id => 'id1'}},
69
+ # {:occurrence_item_id => {:recurring_master_id => 'rid1', :change_key => 'ck', :instance_index => 1}},
70
+ # {:recurring_master_item_id => {:occurrence_id => 'oid1', :change_key => 'ck'}}
71
+ # ]}
72
+ def get_item(opts)
73
+ opts = opts.clone
74
+ [:item_shape, :item_ids].each do |k|
75
+ validate_param(opts, k, true)
76
+ end
77
+ req = build_soap! do |type, builder|
78
+ if(type == :header)
79
+ else
80
+ builder.nbuild.GetItem {
81
+ builder.nbuild.parent.default_namespace = @default_ns
82
+ builder.item_shape!(opts[:item_shape])
83
+ builder.item_ids!(opts[:item_ids])
84
+ }
85
+ end
86
+ end
87
+ do_soap_request(req, response_class: EwsResponse)
88
+ end
89
+
90
+ # Defines a request to create an item in the Exchange store.
91
+ # @see http://msdn.microsoft.com/en-us/library/aa565209(v=EXCHG.140).aspx
92
+ #
93
+ # @param [Hash] opts
94
+ # @option opts [String] :message_disposition How the item will be handled after it is created.
95
+ # Only applicable for to e-mail. Must be one of 'SaveOnly', 'SendOnly', or 'SendAndSaveCopy'
96
+ # @option opts [String] :send_meeting_invitations How meeting requests are handled after they
97
+ # are created. Required for calendar items. Must be one of 'SendToNone', 'SendOnlyToAll',
98
+ # 'SendToAllAndSaveCopy'
99
+ # @option opts [Hash] :saved_item_folder_id A well formatted folder_id Hash. Ex: {:id => :inbox}
100
+ # Will on work if 'SendOnly' is specified for :message_disposition
101
+ # @option opts [Array<Hash>] :items This is a complex Hash that conforms to various Item types.
102
+ # Please see the Microsoft documentation for this element.
103
+ # @example
104
+ # opts = {
105
+ # message_disposition: 'SendAndSaveCopy',
106
+ # items: [ {message:
107
+ # {subject: 'test2',
108
+ # body: {body_type: 'Text', text: 'this is a test'},
109
+ # to_recipients: [{mailbox: {email_address: 'dan.wanek@gmail.com'}}]
110
+ # }
111
+ # }]}
112
+ #
113
+ # opts = {
114
+ # send_meeting_invitations: 'SendToAllAndSaveCopy',
115
+ # items: [ {calendar_item:
116
+ # {subject: 'test cal item',
117
+ # body: {body_type: 'Text', text: 'this is a test cal item'},
118
+ # start: {text: Chronic.parse('tomorrow at 4pm').to_datetime.to_s},
119
+ # end: {text: Chronic.parse('tomorrow at 5pm').to_datetime.to_s},
120
+ # required_attendees: [
121
+ # {attendee: {mailbox: {email_address: 'dan.wanek@gmail.com'}}},
122
+ # ]
123
+ # }
124
+ # }]
125
+ def create_item(opts)
126
+ opts = opts.clone
127
+ [:items].each do |k|
128
+ validate_param(opts, k, true)
129
+ end
130
+ req = build_soap! do |type, builder|
131
+ attribs = {}
132
+ attribs['MessageDisposition'] = opts[:message_disposition] if opts[:message_disposition]
133
+ attribs['SendMeetingInvitations'] = opts[:send_meeting_invitations] if opts[:send_meeting_invitations]
134
+ if(type == :header)
135
+ else
136
+ builder.nbuild.CreateItem(attribs) {
137
+ builder.nbuild.parent.default_namespace = @default_ns
138
+ builder.saved_item_folder_id!(opts[:saved_item_folder_id]) if opts[:saved_item_folder_id]
139
+ builder.nbuild.Items {
140
+ opts[:items].each {|i|
141
+ # The key can be any number of item types like :message,
142
+ # :calendar, etc
143
+ ikey = i.keys.first
144
+ builder.send("#{ikey}!",i[ikey])
145
+ }
146
+ }
147
+ }
148
+ end
149
+ end
150
+ do_soap_request(req, response_class: EwsResponse)
151
+ end
152
+
153
+ # Used to modify the properties of an existing item in the Exchange store
154
+ # @see http://msdn.microsoft.com/en-us/library/aa581084(v=exchg.140).aspx
155
+ #
156
+ # @param [Hash] opts
157
+ # @option opts [String] :conflict_resolution Identifies the type of conflict resolution to
158
+ # try during an update. The default value is AutoResolve. Available options are
159
+ # 'NeverOverwrite', 'AutoResolve', 'AlwaysOverwrite'
160
+ # @option opts [String] :message_disposition How the item will be handled after it is updated.
161
+ # Only applicable for to e-mail. Must be one of 'SaveOnly', 'SendOnly', or 'SendAndSaveCopy'
162
+ # @option opts [String] :send_meeting_invitations_or_cancellations How meeting requests are
163
+ # handled after they are updated. Required for calendar items. Must be one of 'SendToNone',
164
+ # 'SendOnlyToAll', 'SendOnlyToChanged', 'SendToAllAndSaveCopy', 'SendToChangedAndSaveCopy'
165
+ # @option opts [Hash] :saved_item_folder_id A well formatted folder_id Hash. Ex: {:id => :sentitems}
166
+ # Will on work if 'SendOnly' is specified for :message_disposition
167
+ # @option opts [Array<Hash>] :item_changes an array of ItemChange elements that identify items
168
+ # and the updates to apply to the items. See the Microsoft docs for more information.
169
+ # @example
170
+ # opts = {
171
+ # :send_meeting_invitations_or_cancellations => 'SendOnlyToChangedAndSaveCopy',
172
+ # :item_changes => [
173
+ # { :item_id => {:id => 'id1'},
174
+ # :updates => [
175
+ # {:set_item_field => {
176
+ # :field_uRI => {:field_uRI => 'item:Subject'},
177
+ # # The following needs to conform to #build_xml! format for now
178
+ # :calendar_item => { :sub_elements => [{:subject => {:text => 'Test Subject'}}]}
179
+ # }}
180
+ # ]
181
+ # }
182
+ # ]
183
+ # }
184
+ def update_item(opts)
185
+ opts = opts.clone
186
+ [:item_changes].each do |k|
187
+ validate_param(opts, k, true)
188
+ end
189
+ req = build_soap! do |type, builder|
190
+ attribs = {}
191
+ attribs['MessageDisposition'] = opts[:message_disposition] if opts[:message_disposition]
192
+ attribs['ConflictResolution'] = opts[:conflict_resolution] if opts[:conflict_resolution]
193
+ attribs['SendMeetingInvitationsOrCancellations'] = opts[:send_meeting_invitations_or_cancellations] if opts[:send_meeting_invitations_or_cancellations]
194
+ if(type == :header)
195
+ else
196
+ builder.nbuild.UpdateItem(attribs) {
197
+ builder.nbuild.parent.default_namespace = @default_ns
198
+ builder.saved_item_folder_id!(opts[:saved_item_folder_id]) if opts[:saved_item_folder_id]
199
+ builder.item_changes!(opts[:item_changes])
200
+ }
201
+ end
202
+ end
203
+ do_soap_request(req, response_class: EwsResponse)
204
+ end
205
+
206
+ # Delete an item from a mailbox in the Exchange store
207
+ # @see http://msdn.microsoft.com/en-us/library/aa580484(v=exchg.140).aspx
208
+ #
209
+ # @param [Hash] opts
210
+ # @option opts [String] :delete_type Describes how an item is deleted. Must be one of
211
+ # 'HardDelete', 'SoftDelete', or 'MoveToDeletedItems'
212
+ # @option opts [String] :send_meeting_cancellations How meetings are handled after they
213
+ # are deleted. Required for calendar items. Must be one of 'SendToNone', 'SendOnlyToAll',
214
+ # 'SendToAllAndSaveCopy'
215
+ # @option opts [String] :affected_task_occurrences Describes whether a task instance or a
216
+ # task master is deleted by a DeleteItem Operation. This attribute is required when
217
+ # tasks are deleted. Must be one of 'AllOccurrences' or 'SpecifiedOccurrenceOnly'
218
+ # @option opts [Array<Hash>] :item_ids ItemIds Hash. The keys in these Hashes can be
219
+ # :item_id, :occurrence_item_id, or :recurring_master_item_id. Please see the
220
+ # Microsoft docs for more information.
221
+ # @example
222
+ # opts = {
223
+ # :delete_type => 'MoveToDeletedItems',
224
+ # :item_ids => [{:item_id => {:id => 'id1'}}]
225
+ # }
226
+ # inst.delete_item(opts)
227
+ def delete_item(opts)
228
+ opts = opts.clone
229
+ [:delete_type, :item_ids].each do |k|
230
+ validate_param(opts, k, true)
231
+ end
232
+ req = build_soap! do |type, builder|
233
+ attribs = {'DeleteType' => opts[:delete_type]}
234
+ attribs['SendMeetingCancellations'] = opts[:send_meeting_cancellations] if opts[:send_meeting_cancellations]
235
+ attribs['AffectedTaskOccurrences'] = opts[:affected_task_occurrences] if opts[:affected_task_occurrences]
236
+ if(type == :header)
237
+ else
238
+ builder.nbuild.DeleteItem(attribs) {
239
+ builder.nbuild.parent.default_namespace = @default_ns
240
+ builder.item_ids!(opts[:item_ids])
241
+ }
242
+ end
243
+ end
244
+ do_soap_request(req, response_class: EwsResponse)
245
+ end
246
+
247
+ # Used to move one or more items to a single destination folder.
248
+ # @see http://msdn.microsoft.com/en-us/library/aa565781(v=exchg.140).aspx
249
+ #
250
+ # @param [Hash] opts
251
+ # @option opts [Hash] :to_folder_id A well formatted folder_id Hash. Ex: {:id => :inbox}
252
+ # @option opts [Array<Hash>] :item_ids ItemIds Hash. The keys in these Hashes can be
253
+ # :item_id, :occurrence_item_id, or :recurring_master_item_id. Please see the
254
+ # Microsoft docs for more information.
255
+ # @option opts [Boolean] :return_new_item_ids Indicates whether the item identifiers of
256
+ # new items are returned in the response
257
+ # @example
258
+ # opts = {
259
+ # :to_folder_id => {:id => :inbox},
260
+ # :item_ids => [
261
+ # {:item_id => {:id => 'id1'}},
262
+ # {:item_id => {:id => 'id2'}},
263
+ # ],
264
+ # :return_new_item_ids => true
265
+ # }
266
+ # obj.move_item(opts)
267
+ def move_item(opts)
268
+ opts = opts.clone
269
+ [:to_folder_id, :item_ids].each do |k|
270
+ validate_param(opts, k, true)
271
+ end
272
+ return_new_ids = validate_param(opts, :return_new_item_ids, false, true)
273
+
274
+ req = build_soap! do |type, builder|
275
+ if(type == :header)
276
+ else
277
+ builder.nbuild.MoveItem {
278
+ builder.nbuild.parent.default_namespace = @default_ns
279
+ builder.to_folder_id!(opts[:to_folder_id])
280
+ builder.item_ids!(opts[:item_ids])
281
+ builder.return_new_item_ids!(return_new_ids)
282
+ }
283
+ end
284
+ end
285
+ do_soap_request(req, response_class: EwsResponse)
286
+ end
287
+
288
+ # Copies items and puts the items in a different folder
289
+ # @see http://msdn.microsoft.com/en-us/library/aa565012(v=exchg.140).aspx
290
+ #
291
+ # @param [Hash] opts
292
+ # @option opts [Hash] :to_folder_id A well formatted folder_id Hash. Ex: {:id => :inbox}
293
+ # @option opts [Array<Hash>] :item_ids ItemIds Hash. The keys in these Hashes can be
294
+ # :item_id, :occurrence_item_id, or :recurring_master_item_id. Please see the
295
+ # Microsoft docs for more information.
296
+ # @option opts [Boolean] :return_new_item_ids Indicates whether the item identifiers of
297
+ # new items are returned in the response
298
+ # @example
299
+ # opts = {
300
+ # :to_folder_id => {:id => :inbox},
301
+ # :item_ids => [
302
+ # {:item_id => {:id => 'id1'}},
303
+ # {:item_id => {:id => 'id2'}},
304
+ # ],
305
+ # :return_new_item_ids => true
306
+ # }
307
+ # obj.copy_item(opts)
308
+ def copy_item(opts)
309
+ opts = opts.clone
310
+ [:to_folder_id, :item_ids].each do |k|
311
+ validate_param(opts, k, true)
312
+ end
313
+ return_new_ids = validate_param(opts, :return_new_item_ids, false, true)
314
+
315
+ req = build_soap! do |type, builder|
316
+ if(type == :header)
317
+ else
318
+ builder.nbuild.CopyItem {
319
+ builder.nbuild.parent.default_namespace = @default_ns
320
+ builder.to_folder_id!(opts[:to_folder_id])
321
+ builder.item_ids!(opts[:item_ids])
322
+ builder.return_new_item_ids!(return_new_ids)
323
+ }
324
+ end
325
+ end
326
+ do_soap_request(req, response_class: EwsResponse)
327
+ end
328
+
329
+ # Used to send e-mail messages that are located in the Exchange store.
330
+ # @see http://msdn.microsoft.com/en-us/library/aa580238(v=exchg.140).aspx
331
+ #
332
+ # @param [Hash] opts
333
+ # @option opts [Boolean] :save_item_to_folder To save or not to save... save! :-)
334
+ # @option opts [Hash] :saved_item_folder_id A well formatted folder_id Hash. Ex: {:id => :sentitems}
335
+ # @option opts [Array<Hash>] :item_ids ItemIds Hash. The keys in these Hashes can be
336
+ # :item_id, :occurrence_item_id, or :recurring_master_item_id. Please see the
337
+ # Microsoft docs for more information.
338
+ # @example
339
+ # opts = {
340
+ # :save_item_to_folder => true,
341
+ # :saved_item_folder_id => {:id => :sentitems},
342
+ # :item_ids => [
343
+ # {:item_id => {:id => 'id1'}},
344
+ # {:item_id => {:id => 'id2'}},
345
+ # ]}
346
+ # obj.send_item(opts)
347
+ def send_item(opts)
348
+ opts = opts.clone
349
+ [:item_ids].each do |k|
350
+ validate_param(opts, k, true)
351
+ end
352
+
353
+ req = build_soap! do |type, builder|
354
+ attribs = {}
355
+ attribs['SaveItemToFolder'] = validate_param(opts, :save_item_to_folder, false, true)
356
+ if(type == :header)
357
+ else
358
+ builder.nbuild.SendItem(attribs) {
359
+ builder.nbuild.parent.default_namespace = @default_ns
360
+ builder.item_ids!(opts[:item_ids])
361
+ builder.saved_item_folder_id!(opts[:saved_item_folder_id]) if opts[:saved_item_folder_id]
362
+ }
363
+ end
364
+ end
365
+ do_soap_request(req, response_class: EwsResponse)
366
+ end
367
+
368
+ # Export items as a base64 string
369
+ # @see http://msdn.microsoft.com/en-us/library/ff709503(v=exchg.140).aspx
370
+ #
371
+ # (Requires Exchange version equal or newer than VERSION 2010 SP 1)
372
+ #
373
+ # @param ids [Array] array of item ids. Can also be a single id value
374
+ def export_items(ids)
375
+ validate_version(VERSION_2010_SP1)
376
+ ids = ids.clone
377
+ [:item_ids].each do |k|
378
+ validate_param(ids, k, true)
379
+ end
380
+ req = build_soap! do |type, builder|
381
+ if(type == :header)
382
+ else
383
+ builder.export_item_ids!(ids[:item_ids])
384
+ end
385
+ end
386
+ do_soap_request(req, response_class: EwsResponse)
387
+ end
388
+
389
+ # ------------- Folder Operations ------------
390
+
391
+ # Creates folders, calendar folders, contacts folders, tasks folders, and search folders.
392
+ # @see http://msdn.microsoft.com/en-us/library/aa563574.aspx CreateFolder
393
+ #
394
+ # @param [Hash] opts
395
+ # @option opts [Hash] :parent_folder_id A hash with either the name of a
396
+ # folder or it's numerical ID.
397
+ # See: http://msdn.microsoft.com/en-us/library/aa565998.aspx
398
+ # {:id => :root} or {:id => 'myfolderid#'}
399
+ # @option opts [Array<Hash>] :folders An array of hashes of folder types
400
+ # that conform to input for build_xml!
401
+ # @example [
402
+ # {:folder =>
403
+ # {:display_name => "New Folder"}},
404
+ # {:calendar_folder =>
405
+ # {:folder_id => {:id => 'blah', :change_key => 'blah'}}}
406
+ def create_folder(opts)
407
+ opts = opts.clone
408
+ req = build_soap! do |type, builder|
409
+ if(type == :header)
410
+ else
411
+ builder.nbuild.CreateFolder {|x|
412
+ x.parent.default_namespace = @default_ns
413
+ builder.parent_folder_id!(opts[:parent_folder_id])
414
+ builder.folders!(opts[:folders])
415
+ }
416
+ end
417
+ end
418
+ do_soap_request(req)
419
+ end
420
+
421
+ # Defines a request to copy folders in the Exchange store
422
+ # @see http://msdn.microsoft.com/en-us/library/aa563949.aspx
423
+ # @param [Hash] to_folder_id The target FolderId
424
+ # {:id => <myid>, :change_key => <optional ck>}
425
+ # @param [Array<Hash>] *sources The source Folders
426
+ # {:id => <myid>, :change_key => <optional_ck>},
427
+ # {:id => <myid2>, :change_key => <optional_ck>}
428
+ def copy_folder(to_folder_id, *sources)
429
+ req = build_soap! do |type, builder|
430
+ if(type == :header)
431
+ else
432
+ builder.nbuild.CopyFolder {
433
+ builder.nbuild.parent.default_namespace = @default_ns
434
+ builder.to_folder_id!(to_folder_id)
435
+ builder.folder_ids!(sources.flatten)
436
+ }
437
+ end
438
+ end
439
+ do_soap_request(req)
440
+ end
441
+
442
+ # Deletes folders from a mailbox.
443
+ # @see http://msdn.microsoft.com/en-us/library/aa564767.aspx DeleteFolder
444
+ #
445
+ # @param [Hash] opts
446
+ # @option opts [Array<Hash>] :folder_ids An array of folder_ids in the form:
447
+ # [ {:id => 'myfolderID##asdfs', :change_key => 'asdfasdf'},
448
+ # {:id => :msgfolderroot} ] # Don't do this for real
449
+ # @option opts [String,nil] :delete_type Type of delete to do:
450
+ # HardDelete/SoftDelete/MoveToDeletedItems
451
+ # @option opts [String,nil] :act_as User to act on behalf as. This user
452
+ # must have been given delegate access to this folder or else this
453
+ # operation will fail.
454
+ def delete_folder(opts)
455
+ req = build_soap! do |type, builder|
456
+ if(type == :header)
457
+ else
458
+ builder.nbuild.DeleteFolder('DeleteType' => opts[:delete_type]) {
459
+ builder.nbuild.parent.default_namespace = @default_ns
460
+ builder.folder_ids!(opts[:folder_ids], opts[:act_as])
461
+ }
462
+ end
463
+ end
464
+ do_soap_request(req)
465
+ end
466
+
467
+ # Find subfolders of an identified folder
468
+ # @see http://msdn.microsoft.com/en-us/library/aa563918.aspx
469
+ #
470
+ # @param [Hash] opts
471
+ # @option opts [Array<Hash>] :parent_folder_ids An Array of folder id Hashes,
472
+ # either a DistinguishedFolderId (must me a Symbol) or a FolderId (String)
473
+ # [{:id => <myid>, :change_key => <ck>}, {:id => :root}]
474
+ # @option opts [String] :traversal Shallow/Deep/SoftDeleted
475
+ # @option opts [Hash] :folder_shape defines the FolderShape node
476
+ # See: http://msdn.microsoft.com/en-us/library/aa494311.aspx
477
+ # @option folder_shape [String] :base_shape IdOnly/Default/AllProperties
478
+ # @option folder_shape :additional_properties
479
+ # See: http://msdn.microsoft.com/en-us/library/aa563810.aspx
480
+ # @option opts [Hash] :restriction A well formatted restriction Hash.
481
+ # @example
482
+ # { :parent_folder_ids => [{:id => root}],
483
+ # :traversal => 'Deep',
484
+ # :folder_shape => {:base_shape => 'Default'} }
485
+ # @todo add FractionalPageFolderView
486
+ def find_folder(opts)
487
+ opts = opts.clone
488
+ [:parent_folder_ids, :traversal, :folder_shape].each do |k|
489
+ validate_param(opts, k, true)
490
+ end
491
+
492
+ req = build_soap! do |type, builder|
493
+ if(type == :header)
494
+ else
495
+ builder.nbuild.FindFolder(:Traversal => camel_case(opts[:traversal])) {
496
+ builder.nbuild.parent.default_namespace = @default_ns
497
+ builder.folder_shape!(opts[:folder_shape])
498
+ builder.restriction!(opts[:restriction]) if opts[:restriction]
499
+ builder.parent_folder_ids!(opts[:parent_folder_ids])
500
+ }
501
+ end
502
+ end
503
+ do_soap_request(req)
504
+ end
505
+
506
+ # Gets folders from the Exchange store
507
+ # @see http://msdn.microsoft.com/en-us/library/aa580274.aspx
508
+ #
509
+ # @param [Hash] opts
510
+ # @option opts [Array<Hash>] :folder_ids An array of folder_ids in the form:
511
+ # [ {:id => 'myfolderID##asdfs', :change_key => 'asdfasdf'},
512
+ # {:id => :msgfolderroot} ]
513
+ # @option opts [Hash] :folder_shape defines the FolderShape node
514
+ # @option folder_shape [String] :base_shape IdOnly/Default/AllProperties
515
+ # @option folder_shape :additional_properties
516
+ # @option opts [String,nil] :act_as User to act on behalf as. This user must
517
+ # have been given delegate access to this folder or else this operation
518
+ # will fail.
519
+ # @example
520
+ # { :folder_ids => [{:id => :msgfolderroot}],
521
+ # :folder_shape => {:base_shape => 'Default'} }
522
+ def get_folder(opts)
523
+ opts = opts.clone
524
+ [:folder_ids, :folder_shape].each do |k|
525
+ validate_param(opts, k, true)
526
+ end
527
+ validate_param(opts[:folder_shape], :base_shape, true)
528
+ req = build_soap! do |type, builder|
529
+ if(type == :header)
530
+ else
531
+ builder.nbuild.GetFolder {
532
+ builder.nbuild.parent.default_namespace = @default_ns
533
+ builder.folder_shape!(opts[:folder_shape])
534
+ builder.folder_ids!(opts[:folder_ids], opts[:act_as])
535
+ }
536
+ end
537
+ end
538
+ do_soap_request(req)
539
+ end
540
+
541
+ # Defines a request to move folders in the Exchange store
542
+ # @see http://msdn.microsoft.com/en-us/library/aa566202.aspx
543
+ # @param [Hash] to_folder_id The target FolderId
544
+ # {:id => <myid>, :change_key => <optional ck>}
545
+ # @param [Array<Hash>] *sources The source Folders
546
+ # {:id => <myid>, :change_key => <optional_ck>},
547
+ # {:id => <myid2>, :change_key => <optional_ck>}
548
+ def move_folder(to_folder_id, *sources)
549
+ req = build_soap! do |type, builder|
550
+ if(type == :header)
551
+ else
552
+ builder.nbuild.MoveFolder {
553
+ builder.nbuild.parent.default_namespace = @default_ns
554
+ builder.to_folder_id!(to_folder_id)
555
+ builder.folder_ids!(sources.flatten)
556
+ }
557
+ end
558
+ end
559
+ do_soap_request(req)
560
+ end
561
+
562
+ # Update properties for a specified folder
563
+ # There is a lot more building in this method because most of the builders
564
+ # are only used for this operation so there was no need to externalize them
565
+ # for re-use.
566
+ # @see http://msdn.microsoft.com/en-us/library/aa580519(v=EXCHG.140).aspx
567
+ # @param [Array<Hash>] folder_changes an Array of well formatted Hashes
568
+ def update_folder(folder_changes)
569
+ req = build_soap! do |type, builder|
570
+ if(type == :header)
571
+ else
572
+ builder.nbuild.UpdateFolder {
573
+ builder.nbuild.parent.default_namespace = @default_ns
574
+ builder.nbuild.FolderChanges {
575
+ folder_changes.each do |fc|
576
+ builder[NS_EWS_TYPES].FolderChange {
577
+ builder.dispatch_folder_id!(fc)
578
+ builder[NS_EWS_TYPES].Updates {
579
+ # @todo finish implementation
580
+ }
581
+ }
582
+ end
583
+ }
584
+ }
585
+ end
586
+ end
587
+ do_soap_request(req)
588
+ end
589
+
590
+ # Empties folders in a mailbox.
591
+ # @see http://msdn.microsoft.com/en-us/library/ff709484.aspx
592
+ # @param [Hash] opts
593
+ # @option opts [String] :delete_type Must be one of
594
+ # ExchangeDataServices::HARD_DELETE, SOFT_DELETE, or MOVE_TO_DELETED_ITEMS
595
+ # @option opts [Boolean] :delete_sub_folders
596
+ # @option opts [Array<Hash>] :folder_ids An array of folder_ids in the form:
597
+ # [ {:id => 'myfolderID##asdfs', :change_key => 'asdfasdf'},
598
+ # {:id => 'blah'} ]
599
+ # @todo Finish
600
+ def empty_folder(opts)
601
+ validate_version(VERSION_2010_SP1)
602
+ ef_opts = {}
603
+ [:delete_type, :delete_sub_folders].each do |k|
604
+ ef_opts[camel_case(k)] = validate_param(opts, k, true)
605
+ end
606
+ fids = validate_param opts, :folder_ids, true
607
+
608
+ req = build_soap! do |type, builder|
609
+ if(type == :header)
610
+ else
611
+ builder.nbuild.EmptyFolder(ef_opts) {|x|
612
+ builder.nbuild.parent.default_namespace = @default_ns
613
+ builder.folder_ids!(fids)
614
+ }
615
+ end
616
+ end
617
+ do_soap_request(req)
618
+ end
619
+
620
+ # ----------- Attachment Operations ----------
621
+
622
+ # Used to retrieve existing attachments on items in the Exchange store
623
+ # @see http://msdn.microsoft.com/en-us/library/aa494316.aspx
624
+ # @param [Hash] opts
625
+ # @option opts [Array] :attachment_ids Attachment Ids to fetch
626
+ # @option opts [Hash] :attachment_shape Attachment shape
627
+ # include_mime_content: true or false (optional)
628
+ # body_type: "Best" | "HTML" | "Text" (optional)
629
+ # filter_html_content: true or false (optional)
630
+ # additional_properties: @todo finish implementation
631
+ def get_attachment(opts)
632
+ opts = opts.clone
633
+ [:attachment_ids].each do |k|
634
+ validate_param(opts, k, true)
635
+ end
636
+ req = build_soap! do |type, builder|
637
+ if(type == :header)
638
+ else
639
+ builder.nbuild.GetAttachment {|x|
640
+ builder.nbuild.parent.default_namespace = @default_ns
641
+ builder.attachment_ids!(opts[:attachment_ids])
642
+ }
643
+ end
644
+ end
645
+ do_soap_request(req)
646
+ end
647
+
648
+ # Creates either an item or file attachment and attaches it to the specified item.
649
+ # @see http://msdn.microsoft.com/en-us/library/aa565877.aspx
650
+ # @param [Hash] opts
651
+ # @option opts [Hash] :parent_id {id: <id>, change_key: <ck>}
652
+ # @option opts [Array<Hash>] :files An Array of Base64 encoded Strings with
653
+ # an associated name:
654
+ # {:name => <name>, :content => <Base64 encoded string>}
655
+ # @option opts [Array] :items Exchange Items to attach to this Item
656
+ # @todo Need to implement attachment of Item types
657
+ def create_attachment(opts)
658
+ opts = opts.clone
659
+ [:parent_id].each do |k|
660
+ validate_param(opts, k, true)
661
+ end
662
+ validate_param(opts, :files, false, [])
663
+ validate_param(opts, :items, false, [])
664
+
665
+ req = build_soap! do |type, builder|
666
+ if(type == :header)
667
+ else
668
+ builder.nbuild.CreateAttachment {|x|
669
+ builder.nbuild.parent.default_namespace = @default_ns
670
+ builder.parent_item_id!(opts[:parent_id])
671
+ x.Attachments {
672
+ opts[:files].each do |fa|
673
+ builder.file_attachment!(fa)
674
+ end
675
+ opts[:items].each do |ia|
676
+ builder.item_attachment!(ia)
677
+ end
678
+ opts[:inline_files].each do |fi|
679
+ builder.inline_attachment!(fi)
680
+ end
681
+ }
682
+ }
683
+ end
684
+ end
685
+ do_soap_request(req, response_class: EwsResponse)
686
+ end
687
+
688
+
689
+ # ------------ Utility Operations ------------
690
+
691
+ # Exposes the full membership of distribution lists.
692
+ # @see http://msdn.microsoft.com/en-us/library/aa494152.aspx ExpandDL
693
+ #
694
+ # @todo Fully support all of the ExpandDL operations. Today it just supports
695
+ # taking an e-mail address as an argument
696
+ # @param [Hash] opts
697
+ # @option opts [String] :email_address The e-mail address of the
698
+ # distribution to resolve
699
+ # @option opts [Hash] :item_id The ItemId of the private distribution to resolve.
700
+ # {:id => 'my id'}
701
+ def expand_dl(opts)
702
+ opts = opts.clone
703
+ req = build_soap! do |type, builder|
704
+ if(type == :header)
705
+ else
706
+ builder.nbuild.ExpandDL {|x|
707
+ x.parent.default_namespace = @default_ns
708
+ x.Mailbox {|mb|
709
+ key = :email_address
710
+ mb[NS_EWS_TYPES].EmailAddress(opts[key]) if opts[key]
711
+ builder.item_id! if opts[:item_id]
712
+ }
713
+ }
714
+ end
715
+ end
716
+ do_soap_request(req)
717
+ end
718
+
719
+ # Resolve ambiguous e-mail addresses and display names
720
+ # @see http://msdn.microsoft.com/en-us/library/aa565329.aspx ResolveNames
721
+ # @see http://msdn.microsoft.com/en-us/library/aa581054.aspx UnresolvedEntry
722
+ # @param [Hash] opts
723
+ # @option opts [String] :name the unresolved entry
724
+ # @option opts [Boolean] :full_contact_data (true) Whether or not to return
725
+ # the full contact details.
726
+ # @option opts [String] :search_scope where to seach for this entry, one of
727
+ # SOAP::Contacts, SOAP::ActiveDirectory, SOAP::ActiveDirectoryContacts
728
+ # (default), SOAP::ContactsActiveDirectory
729
+ # @option opts [String, FolderId] :parent_folder_id either the name of a
730
+ # folder or it's numerical ID.
731
+ # @see http://msdn.microsoft.com/en-us/library/aa565998.aspx
732
+ def resolve_names(opts)
733
+ opts = opts.clone
734
+ fcd = opts.has_key?(:full_contact_data) ? opts[:full_contact_data] : true
735
+ req = build_soap! do |type, builder|
736
+ if(type == :header)
737
+ else
738
+ builder.nbuild.ResolveNames {|x|
739
+ x.parent['ReturnFullContactData'] = fcd.to_s
740
+ x.parent['SearchScope'] = opts[:search_scope] if opts[:search_scope]
741
+ x.parent.default_namespace = @default_ns
742
+ # @todo builder.nbuild.ParentFolderIds
743
+ x.UnresolvedEntry(opts[:name])
744
+ }
745
+ end
746
+ end
747
+ do_soap_request(req)
748
+ end
749
+
750
+ # Converts item and folder identifiers between formats.
751
+ # @see http://msdn.microsoft.com/en-us/library/bb799665.aspx
752
+ # @todo Needs to be finished
753
+ def convert_id(opts)
754
+ opts = opts.clone
755
+
756
+ [:id, :format, :destination_format, :mailbox ].each do |k|
757
+ validate_param(opts, k, true)
758
+ end
759
+
760
+ req = build_soap! do |type, builder|
761
+ if(type == :header)
762
+ else
763
+ builder.nbuild.ConvertId {|x|
764
+ builder.nbuild.parent.default_namespace = @default_ns
765
+ x.parent['DestinationFormat'] = opts[:destination_format].to_s.camel_case
766
+ x.SourceIds { |x|
767
+ x[NS_EWS_TYPES].AlternateId { |x|
768
+ x.parent['Format'] = opts[:format].to_s.camel_case
769
+ x.parent['Id'] = opts[:id]
770
+ x.parent['Mailbox'] = opts[:mailbox]
771
+ }
772
+ }
773
+ }
774
+ end
775
+ end
776
+ do_soap_request(req, response_class: EwsResponse)
777
+ end
778
+
779
+ end #ExchangeDataServices
780
+ end