viewpoint2 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +216 -0
  3. data/lib/ews/calendar_accessors.rb +34 -0
  4. data/lib/ews/connection.rb +130 -0
  5. data/lib/ews/connection_helper.rb +35 -0
  6. data/lib/ews/convert_accessors.rb +56 -0
  7. data/lib/ews/errors.rb +56 -0
  8. data/lib/ews/ews_client.rb +103 -0
  9. data/lib/ews/exceptions/exceptions.rb +61 -0
  10. data/lib/ews/folder_accessors.rb +264 -0
  11. data/lib/ews/impersonation.rb +30 -0
  12. data/lib/ews/item_accessors.rb +231 -0
  13. data/lib/ews/mailbox_accessors.rb +99 -0
  14. data/lib/ews/message_accessors.rb +93 -0
  15. data/lib/ews/push_subscription_accessors.rb +33 -0
  16. data/lib/ews/room_accessors.rb +48 -0
  17. data/lib/ews/roomlist_accessors.rb +47 -0
  18. data/lib/ews/soap.rb +64 -0
  19. data/lib/ews/soap/builders/ews_builder.rb +1351 -0
  20. data/lib/ews/soap/ews_response.rb +84 -0
  21. data/lib/ews/soap/ews_soap_availability_response.rb +58 -0
  22. data/lib/ews/soap/ews_soap_free_busy_response.rb +119 -0
  23. data/lib/ews/soap/ews_soap_response.rb +103 -0
  24. data/lib/ews/soap/ews_soap_room_response.rb +53 -0
  25. data/lib/ews/soap/ews_soap_roomlist_response.rb +54 -0
  26. data/lib/ews/soap/exchange_availability.rb +61 -0
  27. data/lib/ews/soap/exchange_data_services.rb +780 -0
  28. data/lib/ews/soap/exchange_notification.rb +146 -0
  29. data/lib/ews/soap/exchange_synchronization.rb +93 -0
  30. data/lib/ews/soap/exchange_time_zones.rb +56 -0
  31. data/lib/ews/soap/exchange_user_configuration.rb +33 -0
  32. data/lib/ews/soap/exchange_web_service.rb +264 -0
  33. data/lib/ews/soap/parsers/ews_parser.rb +43 -0
  34. data/lib/ews/soap/parsers/ews_sax_document.rb +70 -0
  35. data/lib/ews/soap/response_message.rb +80 -0
  36. data/lib/ews/soap/responses/create_attachment_response_message.rb +47 -0
  37. data/lib/ews/soap/responses/create_item_response_message.rb +25 -0
  38. data/lib/ews/soap/responses/find_item_response_message.rb +80 -0
  39. data/lib/ews/soap/responses/get_events_response_message.rb +53 -0
  40. data/lib/ews/soap/responses/send_notification_response_message.rb +59 -0
  41. data/lib/ews/soap/responses/subscribe_response_message.rb +35 -0
  42. data/lib/ews/soap/responses/sync_folder_hierarchy_response_message.rb +36 -0
  43. data/lib/ews/soap/responses/sync_folder_items_response_message.rb +36 -0
  44. data/lib/ews/templates/calendar_item.rb +79 -0
  45. data/lib/ews/templates/forward_item.rb +24 -0
  46. data/lib/ews/templates/message.rb +76 -0
  47. data/lib/ews/templates/reply_to_item.rb +25 -0
  48. data/lib/ews/templates/task.rb +74 -0
  49. data/lib/ews/types.rb +194 -0
  50. data/lib/ews/types/attachment.rb +77 -0
  51. data/lib/ews/types/attendee.rb +41 -0
  52. data/lib/ews/types/calendar_folder.rb +50 -0
  53. data/lib/ews/types/calendar_item.rb +133 -0
  54. data/lib/ews/types/contact.rb +7 -0
  55. data/lib/ews/types/contacts_folder.rb +8 -0
  56. data/lib/ews/types/copied_event.rb +51 -0
  57. data/lib/ews/types/created_event.rb +24 -0
  58. data/lib/ews/types/deleted_event.rb +24 -0
  59. data/lib/ews/types/distribution_list.rb +7 -0
  60. data/lib/ews/types/event.rb +62 -0
  61. data/lib/ews/types/export_items_response_message.rb +52 -0
  62. data/lib/ews/types/file_attachment.rb +65 -0
  63. data/lib/ews/types/folder.rb +60 -0
  64. data/lib/ews/types/free_busy_changed_event.rb +24 -0
  65. data/lib/ews/types/generic_folder.rb +418 -0
  66. data/lib/ews/types/item.rb +450 -0
  67. data/lib/ews/types/item_attachment.rb +84 -0
  68. data/lib/ews/types/item_field_uri_map.rb +208 -0
  69. data/lib/ews/types/mailbox_user.rb +156 -0
  70. data/lib/ews/types/meeting_cancellation.rb +7 -0
  71. data/lib/ews/types/meeting_message.rb +7 -0
  72. data/lib/ews/types/meeting_request.rb +7 -0
  73. data/lib/ews/types/meeting_response.rb +7 -0
  74. data/lib/ews/types/message.rb +7 -0
  75. data/lib/ews/types/modified_event.rb +48 -0
  76. data/lib/ews/types/moved_event.rb +51 -0
  77. data/lib/ews/types/new_mail_event.rb +24 -0
  78. data/lib/ews/types/out_of_office.rb +147 -0
  79. data/lib/ews/types/post_item.rb +7 -0
  80. data/lib/ews/types/search_folder.rb +8 -0
  81. data/lib/ews/types/status_event.rb +39 -0
  82. data/lib/ews/types/task.rb +104 -0
  83. data/lib/ews/types/tasks_folder.rb +27 -0
  84. data/lib/viewpoint/logging.rb +27 -0
  85. data/lib/viewpoint/logging/config.rb +24 -0
  86. data/lib/viewpoint/string_utils.rb +76 -0
  87. data/lib/viewpoint2.rb +111 -0
  88. metadata +191 -0
@@ -0,0 +1,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