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,52 @@
1
+ module Viewpoint::EWS::Types
2
+
3
+ class ExportItemsResponseMessage
4
+ include Viewpoint::EWS
5
+ include Viewpoint::EWS::Types
6
+ include Viewpoint::EWS::Types::Item
7
+
8
+ BULK_KEY_PATHS = {
9
+ :id => [:item_id, :attribs, :id],
10
+ :change_key => [:item_id, :attribs, :change_key],
11
+ :data => [:data, :text]
12
+ }
13
+
14
+ BULK_KEY_TYPES = { }
15
+
16
+ BULK_KEY_ALIAS = { }
17
+
18
+ def initialize(ews, bulk_item)
19
+ super(ews, bulk_item)
20
+ @item = bulk_item
21
+ @ews = ews
22
+ end
23
+
24
+ def id
25
+ @item[:item_id][:attribs][:id]
26
+ end
27
+
28
+ def change_key
29
+ @item[:item_id][:attribs][:change_key]
30
+ end
31
+
32
+ def data
33
+ @item[:data][:text]
34
+ end
35
+
36
+
37
+ private
38
+
39
+ def key_paths
40
+ @key_paths ||= BULK_KEY_PATHS
41
+ end
42
+
43
+ def key_types
44
+ @key_types ||= BULK_KEY_TYPES
45
+ end
46
+
47
+ def key_alias
48
+ @key_alias ||= BULK_KEY_ALIAS
49
+ end
50
+
51
+ end
52
+ end
@@ -0,0 +1,65 @@
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::Types
20
+ class FileAttachment < Attachment
21
+
22
+ FILE_ATTACH_KEY_PATHS = {
23
+ :is_contact_photo? => [:is_contact_photo, :text],
24
+ :content => [:content, :text],
25
+ }
26
+
27
+ FILE_ATTACH_KEY_TYPES = {
28
+ is_contact_photo?: ->(str){str.downcase == 'true'},
29
+ }
30
+
31
+ FILE_ATTACH_KEY_ALIAS = {
32
+ :file_name => :name,
33
+ }
34
+
35
+ def get_all_properties!
36
+ resp = ews.get_attachment attachment_ids: [self.id]
37
+ @ews_item.merge!(parse_response(resp))
38
+ end
39
+
40
+ private
41
+
42
+
43
+ def key_paths
44
+ super.merge(FILE_ATTACH_KEY_PATHS)
45
+ end
46
+
47
+ def key_types
48
+ super.merge(FILE_ATTACH_KEY_TYPES)
49
+ end
50
+
51
+ def key_alias
52
+ super.merge(FILE_ATTACH_KEY_ALIAS)
53
+ end
54
+
55
+ def parse_response(resp)
56
+ if(resp.status == 'Success')
57
+ resp.response_message[:elems][:attachments][:elems][0][:file_attachment][:elems].inject(&:merge)
58
+ else
59
+ raise EwsError, "Could not retrieve #{self.class}. #{resp.code}: #{resp.message}"
60
+ end
61
+ end
62
+
63
+ end
64
+ end
65
+
@@ -0,0 +1,60 @@
1
+ module Viewpoint::EWS::Types
2
+ class Folder
3
+ include Viewpoint::EWS
4
+ include Viewpoint::EWS::Types
5
+ include Viewpoint::EWS::Types::GenericFolder
6
+
7
+ FOLDER_KEY_PATHS = {
8
+ :unread_count => [:unread_count, :text],
9
+ }
10
+ FOLDER_KEY_TYPES = {
11
+ :unread_count => ->(str){str.to_i},
12
+ }
13
+ FOLDER_KEY_ALIAS = {}
14
+
15
+ alias :messages :items
16
+
17
+ def unread_messages
18
+ self.items read_unread_restriction
19
+ end
20
+
21
+ def read_messages
22
+ self.items read_unread_restriction(true)
23
+ end
24
+
25
+ def messages_with_attachments
26
+ opts = {:restriction =>
27
+ {:is_equal_to => [
28
+ {:field_uRI => {:field_uRI=>'item:HasAttachments'}},
29
+ {:field_uRI_or_constant => {:constant => {:value=> true}}}
30
+ ]}
31
+ }
32
+ self.items opts
33
+ end
34
+
35
+ private
36
+
37
+
38
+ def read_unread_restriction(read = false)
39
+ {:restriction =>
40
+ {:is_equal_to => [
41
+ {:field_uRI => {:field_uRI=>'message:IsRead'}},
42
+ {:field_uRI_or_constant => {:constant => {:value=> read}}}
43
+ ]}
44
+ }
45
+ end
46
+
47
+ def key_paths
48
+ @key_paths ||= super.merge(FOLDER_KEY_PATHS)
49
+ end
50
+
51
+ def key_types
52
+ @key_types ||= super.merge(FOLDER_KEY_TYPES)
53
+ end
54
+
55
+ def key_alias
56
+ @key_alias ||= super.merge(FOLDER_KEY_ALIAS)
57
+ end
58
+
59
+ end
60
+ end
@@ -0,0 +1,24 @@
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::Types
20
+
21
+ class FreeBusyChangedEvent < Event
22
+
23
+ end
24
+ end
@@ -0,0 +1,418 @@
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
+ require 'ews/item_accessors'
20
+
21
+ module Viewpoint::EWS::Types
22
+ module GenericFolder
23
+ include Viewpoint::EWS
24
+ include Viewpoint::EWS::Types
25
+ include Viewpoint::EWS::ItemAccessors
26
+ include Viewpoint::StringUtils
27
+
28
+ GFOLDER_KEY_PATHS = {
29
+ :folder_id => [:folder_id, :attribs],
30
+ :id => [:folder_id, :attribs, :id],
31
+ :change_key => [:folder_id, :attribs, :change_key],
32
+ :parent_folder_id => [:parent_folder_id, :attribs, :id],
33
+ :parent_folder_change_key => [:parent_folder_id, :attribs, :change_key],
34
+ :folder_class => [:folder_class, :text],
35
+ :total_count => [:total_count, :text],
36
+ :child_folder_count => [:child_folder_count, :text],
37
+ :display_name => [:display_name, :text],
38
+ }
39
+
40
+ GFOLDER_KEY_TYPES = {
41
+ :total_count => ->(str){str.to_i},
42
+ :child_folder_count => ->(str){str.to_i},
43
+ }
44
+
45
+ GFOLDER_KEY_ALIAS = {
46
+ :name => :display_name,
47
+ :ckey => :change_key,
48
+ }
49
+
50
+ attr_accessor :subscription_id, :watermark, :sync_state
51
+
52
+ # @param [SOAP::ExchangeWebService] ews the EWS reference
53
+ # @param [Hash] ews_item the EWS parsed response document
54
+ def initialize(ews, ews_item)
55
+ super
56
+ simplify!
57
+ @sync_state = nil
58
+ @synced = false
59
+ end
60
+
61
+ def delete!
62
+ opts = {
63
+ :folder_ids => [:id => id],
64
+ :delete_type => 'HardDelete'
65
+ }
66
+ resp = @ews.delete_folder(opts)
67
+ if resp.success?
68
+ true
69
+ else
70
+ raise EwsError, "Could not delete folder. #{resp.code}: #{resp.message}"
71
+ end
72
+ end
73
+
74
+ def items(opts = {})
75
+ args = items_args(opts.clone)
76
+ obj = OpenStruct.new(opts: args, restriction: {})
77
+ yield obj if block_given?
78
+ merge_restrictions! obj
79
+ resp = ews.find_item(args)
80
+ items_parser resp
81
+ end
82
+
83
+ # Fetch items since a give DateTime
84
+ # @param [DateTime] date_time the time to fetch Items since.
85
+ def items_since(date_time, opts = {})
86
+ opts = opts.clone
87
+ unless date_time.kind_of?(Date)
88
+ raise EwsBadArgumentError, "First argument must be a Date or DateTime"
89
+ end
90
+ restr = {:restriction =>
91
+ {:is_greater_than_or_equal_to =>
92
+ [{:field_uRI => {:field_uRI=>'item:DateTimeReceived'}},
93
+ {:field_uRI_or_constant =>{:constant => {:value=>date_time.to_datetime}}}]
94
+ }}
95
+ items(opts.merge(restr))
96
+ end
97
+
98
+ # Fetch only items from today (since midnight)
99
+ def todays_items(opts = {})
100
+ items_since(Date.today)
101
+ end
102
+
103
+ # Fetch items between a given time period
104
+ # @param [DateTime] start_date the time to start fetching Items from
105
+ # @param [DateTime] end_date the time to stop fetching Items from
106
+ def items_between(start_date, end_date, opts={})
107
+ items do |obj|
108
+ obj.restriction = { :and =>
109
+ [
110
+ {:is_greater_than_or_equal_to =>
111
+ [
112
+ {:field_uRI => {:field_uRI=>'item:DateTimeReceived'}},
113
+ {:field_uRI_or_constant=>{:constant => {:value =>start_date}}}
114
+ ]
115
+ },
116
+ {:is_less_than_or_equal_to =>
117
+ [
118
+ {:field_uRI => {:field_uRI=>'item:DateTimeReceived'}},
119
+ {:field_uRI_or_constant=>{:constant => {:value =>end_date}}}
120
+ ]
121
+ }
122
+ ]
123
+ }
124
+ end
125
+ end
126
+
127
+ # Search on the item subject
128
+ # @param [String] match_str A simple string paramater to match against the
129
+ # subject. The search ignores case and does not accept regexes... only strings.
130
+ # @param [String,nil] exclude_str A string to exclude from matches against
131
+ # the subject. This is optional.
132
+ def search_by_subject(match_str, exclude_str = nil)
133
+ items do |obj|
134
+ match = {:contains => {
135
+ :containment_mode => 'Substring',
136
+ :containment_comparison => 'IgnoreCase',
137
+ :field_uRI => {:field_uRI=>'item:Subject'},
138
+ :constant => {:value =>match_str}
139
+ }}
140
+ unless exclude_str.nil?
141
+ excl = {:not =>
142
+ {:contains => {
143
+ :containment_mode => 'Substring',
144
+ :containment_comparison => 'IgnoreCase',
145
+ :field_uRI => {:field_uRI=>'item:Subject'},
146
+ :constant => {:value =>exclude_str}
147
+ }}
148
+ }
149
+
150
+ match[:and] = [{:contains => match.delete(:contains)}, excl]
151
+ end
152
+ obj.restriction = match
153
+ end
154
+ end
155
+
156
+ def get_all_properties!
157
+ @ews_item = get_folder(:base_shape => 'AllProperties')
158
+ simplify!
159
+ end
160
+
161
+ def available_categories
162
+ opts = {
163
+ user_config_name: {
164
+ name: 'CategoryList',
165
+ distinguished_folder_id: {id: :calendar}
166
+ },
167
+ user_config_props: 'XmlData'
168
+ }
169
+ resp = ews.get_user_configuration(opts)
170
+ #txt = resp.response_message[:elems][:get_user_configuration_response_message][:elems][1][:user_configuration][:elems][1][:xml_data][:text]
171
+ #Base64.decode64 txt
172
+ end
173
+
174
+ # Syncronize Items in this folder. If this method is issued multiple
175
+ # times it will continue where the last sync completed.
176
+ # @param [Integer] sync_amount The number of items to synchronize per sync
177
+ # @param [Boolean] sync_all Whether to sync all the data by looping through.
178
+ # The default is to just sync the first set. You can manually loop through
179
+ # with multiple calls to #sync_items!
180
+ # @return [Hash] Returns a hash with keys for each change type that ocurred.
181
+ # Possible key values are:
182
+ # (:create/:udpate/:delete/:read_flag_change).
183
+ # For :deleted and :read_flag_change items a simple hash with :id and
184
+ # :change_key is returned.
185
+ # See: http://msdn.microsoft.com/en-us/library/aa565609.aspx
186
+ def sync_items!(sync_state = nil, sync_amount = 256, sync_all = false, opts = {})
187
+ item_shape = opts.has_key?(:item_shape) ? opts.delete(:item_shape) : {:base_shape => :default}
188
+ sync_state ||= @sync_state
189
+
190
+ resp = ews.sync_folder_items item_shape: item_shape,
191
+ sync_folder_id: self.folder_id, max_changes_returned: sync_amount, sync_state: sync_state
192
+ rmsg = resp.response_messages[0]
193
+
194
+ if rmsg.success?
195
+ @synced = rmsg.includes_last_item_in_range?
196
+ @sync_state = rmsg.sync_state
197
+ rhash = {}
198
+ rmsg.changes.each do |c|
199
+ ctype = c.keys.first
200
+ rhash[ctype] = [] unless rhash.has_key?(ctype)
201
+ if ctype == :delete || ctype == :read_flag_change
202
+ rhash[ctype] << c[ctype][:elems][0][:item_id][:attribs]
203
+ else
204
+ type = c[ctype][:elems][0].keys.first
205
+ item = class_by_name(type).new(ews, c[ctype][:elems][0][type])
206
+ rhash[ctype] << item
207
+ end
208
+ end
209
+ rhash
210
+ else
211
+ raise EwsError, "Could not synchronize: #{rmsg.code}: #{rmsg.message_text}"
212
+ end
213
+ end
214
+
215
+ def synced?
216
+ @synced
217
+ end
218
+
219
+ # Subscribe this folder to events. This method initiates an Exchange pull
220
+ # type subscription.
221
+ #
222
+ # @param event_types [Array] Which event types to subscribe to. By default
223
+ # we subscribe to all Exchange event types: :all, :copied, :created,
224
+ # :deleted, :modified, :moved, :new_mail, :free_busy_changed
225
+ # @param watermark [String] pass a watermark if you wish to start the
226
+ # subscription at a specific point.
227
+ # @param timeout [Fixnum] the time in minutes that the subscription can
228
+ # remain idle between calls to #get_events. default: 240 minutes
229
+ # @return [Boolean] Did the subscription happen successfully?
230
+ def subscribe(evtypes = [:all], watermark = nil, timeout = 240)
231
+ # Refresh the subscription if already subscribed
232
+ unsubscribe if subscribed?
233
+
234
+ event_types = normalize_event_names(evtypes)
235
+ folder = {id: self.id, change_key: self.change_key}
236
+ resp = ews.pull_subscribe_folder(folder, event_types, timeout, watermark)
237
+ rmsg = resp.response_messages.first
238
+ if rmsg.success?
239
+ @subscription_id = rmsg.subscription_id
240
+ @watermark = rmsg.watermark
241
+ true
242
+ else
243
+ raise EwsSubscriptionError, "Could not subscribe: #{rmsg.code}: #{rmsg.message_text}"
244
+ end
245
+ end
246
+
247
+ def push_subscribe(url, evtypes = [:all], watermark = nil, status_frequency = nil)
248
+
249
+ event_types = normalize_event_names(evtypes)
250
+ folder = {id: self.id, change_key: self.change_key}
251
+ resp = ews.push_subscribe_folder(folder, event_types, url, status_frequency, watermark)
252
+ rmsg = resp.response_messages.first
253
+ if rmsg.success?
254
+ @subscription_id = rmsg.subscription_id
255
+ @watermark = rmsg.watermark
256
+ true
257
+ else
258
+ raise EwsSubscriptionError, "Could not subscribe: #{rmsg.code}: #{rmsg.message_text}"
259
+ end
260
+ end
261
+
262
+ # Check if there is a subscription for this folder.
263
+ # @return [Boolean] Are we subscribed to this folder?
264
+ def subscribed?
265
+ ( @subscription_id.nil? or @watermark.nil? )? false : true
266
+ end
267
+
268
+ # Unsubscribe this folder from further Exchange events.
269
+ # @return [Boolean] Did we unsubscribe successfully?
270
+ def unsubscribe
271
+ return true if @subscription_id.nil?
272
+
273
+ resp = ews.unsubscribe(@subscription_id)
274
+ rmsg = resp.response_messages.first
275
+ if rmsg.success?
276
+ @subscription_id, @watermark = nil, nil
277
+ true
278
+ else
279
+ raise EwsSubscriptionError, "Could not unsubscribe: #{rmsg.code}: #{rmsg.message_text}"
280
+ end
281
+ end
282
+
283
+ # Checks a subscribed folder for events
284
+ # @return [Array] An array of Event items
285
+ def get_events
286
+ begin
287
+ if subscribed?
288
+ resp = ews.get_events(@subscription_id, @watermark)
289
+ rmsg = resp.response_messages[0]
290
+ @watermark = rmsg.new_watermark
291
+ # @todo if parms[:more_events] # get more events
292
+ rmsg.events.collect{|ev|
293
+ type = ev.keys.first
294
+ class_by_name(type).new(ews, ev[type])
295
+ }
296
+ else
297
+ raise EwsSubscriptionError, "Folder <#{self.display_name}> not subscribed to. Issue a Folder#subscribe before checking events."
298
+ end
299
+ rescue EwsSubscriptionTimeout => e
300
+ @subscription_id, @watermark = nil, nil
301
+ raise e
302
+ end
303
+ end
304
+
305
+
306
+ private
307
+
308
+
309
+ def key_paths
310
+ @key_paths ||= super.merge(GFOLDER_KEY_PATHS)
311
+ end
312
+
313
+ def key_types
314
+ @key_types ||= super.merge(GFOLDER_KEY_TYPES)
315
+ end
316
+
317
+ def key_alias
318
+ @key_alias ||= super.merge(GFOLDER_KEY_ALIAS)
319
+ end
320
+
321
+ def simplify!
322
+ @ews_item = @ews_item[:elems].inject({}) do |o,i|
323
+ key = i.keys.first
324
+ if o.has_key?(key)
325
+ if o[key].is_a?(Array)
326
+ o[key] << i[key]
327
+ else
328
+ o[key] = [o.delete(key), i[key]]
329
+ end
330
+ else
331
+ o[key] = i[key]
332
+ end
333
+ o
334
+ end
335
+ end
336
+
337
+ # Get a specific folder by its ID.
338
+ # @param [Hash] opts Misc options to control request
339
+ # @option opts [String] :base_shape IdOnly/Default/AllProperties
340
+ # @raise [EwsError] raised when the backend SOAP method returns an error.
341
+ def get_folder(opts = {})
342
+ args = get_folder_args(opts)
343
+ resp = ews.get_folder(args)
344
+ get_folder_parser(resp)
345
+ end
346
+
347
+ # Build up the arguements for #get_folder
348
+ # @todo: should we really pass the ChangeKey or do we want the freshest obj?
349
+ def get_folder_args(opts)
350
+ opts[:base_shape] ||= 'Default'
351
+ default_args = {
352
+ :folder_ids => [{:id => self.id, :change_key => self.change_key}],
353
+ :folder_shape => {:base_shape => opts[:base_shape]}
354
+ }
355
+ default_args.merge(opts)
356
+ end
357
+
358
+ def get_folder_parser(resp)
359
+ if(resp.status == 'Success')
360
+ f = resp.response_message[:elems][:folders][:elems][0]
361
+ f.values.first
362
+ else
363
+ raise EwsError, "Could not retrieve folder. #{resp.code}: #{resp.message}"
364
+ end
365
+ end
366
+
367
+ def items_args(opts)
368
+ default_args = {
369
+ :parent_folder_ids => [{:id => self.id}],
370
+ :traversal => 'Shallow',
371
+ :item_shape => {:base_shape => 'Default'}
372
+ }.merge(opts)
373
+ end
374
+
375
+ def items_parser(resp)
376
+ rm = resp.response_messages[0]
377
+ if(rm.status == 'Success')
378
+ items = []
379
+ rm.root_folder.items.each do |i|
380
+ type = i.keys.first
381
+ items << class_by_name(type).new(ews, i[type], self)
382
+ end
383
+ items
384
+ else
385
+ raise EwsError, "Could not retrieve folder. #{rm.code}: #{rm.message_text}"
386
+ end
387
+ end
388
+
389
+ def merge_restrictions!(obj, merge_type = :and)
390
+ if obj.opts[:restriction] && !obj.opts[:restriction].empty? && !obj.restriction.empty?
391
+ obj.opts[:restriction] = {
392
+ merge_type => [
393
+ obj.opts.delete(:restriction),
394
+ obj.restriction
395
+ ]
396
+ }
397
+ elsif !obj.restriction.empty?
398
+ obj.opts[:restriction] = obj.restriction
399
+ end
400
+ end
401
+
402
+ def normalize_event_names(events)
403
+ if events.include?(:all)
404
+ events = [:copied, :created, :deleted, :modified, :moved, :new_mail, :free_busy_changed]
405
+ end
406
+
407
+ events.collect do |ev|
408
+ nev = ruby_case(ev)
409
+ if nev.end_with?('_event')
410
+ nev.to_sym
411
+ else
412
+ "#{nev}_event".to_sym
413
+ end
414
+ end
415
+ end
416
+
417
+ end
418
+ end