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,30 @@
1
+ module Viewpoint::EWS
2
+
3
+ ConnectingSID = {
4
+ :UPN => 'PrincipalName',
5
+ :SID => 'SID',
6
+ :PSMTP => 'PrimarySmtpAddress',
7
+ :SMTP => 'SmtpAddress'
8
+ }
9
+
10
+ # @param connecting_type [String] should be one of the ConnectingSID variables
11
+ # ConnectingSID[:UPN] - use User Principal Name method
12
+ # ConnectingSID[:SID] - use Security Identifier method
13
+ # ConnectingSID[:PSMTP] - use primary Simple Mail Transfer Protocol method
14
+ # ConnectingSID[:SMTP] - use Simple Mail Transfer Protocol method
15
+ # you can add any other string, it will be converted into xml tag on soap request
16
+ # @param address [String] an address to include to requests for impersonation
17
+ def set_impersonation(connecting_type, address)
18
+ if ConnectingSID.has_value? connecting_type or connecting_type.is_a? String then
19
+ ews.impersonation_type = connecting_type
20
+ ews.impersonation_address = address
21
+ else
22
+ raise EwsBadArgumentError, "Not a proper connecting method: #{connecting_type.class}"
23
+ end
24
+ end
25
+
26
+ def remove_impersonation
27
+ ews.impersonation_type = ""
28
+ ews.impersonation_address = ""
29
+ end
30
+ end
@@ -0,0 +1,231 @@
1
+ =begin
2
+ This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services.
3
+
4
+ Copyright © 2011 Dan Wanek <dan.wanek@gmail.com>
5
+
6
+ Licensed under the Apache License, Version 2.0 (the "License");
7
+ you may not use this file except in compliance with the License.
8
+ You may obtain a copy of the License at
9
+
10
+ http://www.apache.org/licenses/LICENSE-2.0
11
+
12
+ Unless required by applicable law or agreed to in writing, software
13
+ distributed under the License is distributed on an "AS IS" BASIS,
14
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ See the License for the specific language governing permissions and
16
+ limitations under the License.
17
+ =end
18
+ module Viewpoint::EWS::ItemAccessors
19
+ include Viewpoint::EWS
20
+
21
+ # This is a class method that fetches an existing Item from the
22
+ # Exchange Store.
23
+ # @param [String] item_id The id of the item. You can also pass a Hash in the
24
+ # form: {id: <fold_id>, change_key: <change_key>}
25
+ # @param [Hash] opts Misc options to control request
26
+ # @option opts [Symbol] :shape :id_only/:default/:all_properties
27
+ # @return [Item] Returns an Item or subclass of Item
28
+ # @todo Add support to fetch an item with a ChangeKey
29
+ def get_item(item_id, opts = {})
30
+ args = get_item_args(item_id, opts.clone)
31
+ obj = OpenStruct.new(opts: args)
32
+ yield obj if block_given?
33
+ resp = ews.get_item(args)
34
+ get_item_parser(resp)
35
+ end
36
+
37
+ # @param [Hash] opts Misc options to control request
38
+ # @option opts [Symbol] :folder_id
39
+ # @see GenericFolder#items
40
+ def find_items(opts = {})
41
+ args = find_items_args(opts.clone)
42
+ obj = OpenStruct.new(opts: args, restriction: {})
43
+ yield obj if block_given?
44
+ merge_restrictions! obj
45
+ resp = ews.find_item(args)
46
+ find_items_parser resp
47
+ end
48
+
49
+ # This is a class method that fetches an existing Item from the
50
+ # Exchange Store.
51
+ # @param [String] item_id The id of the item. You can also pass a Hash in the
52
+ # form: {id: <fold_id>, change_key: <change_key>}
53
+ # @param [Hash] opts Misc options to control request
54
+ # @option opts [Symbol] :shape :id_only/:default/:all_properties
55
+ # @return [Item] Returns an Item or subclass of Item
56
+ # @todo Add support to fetch an item with a ChangeKey
57
+ def get_items(item_ids, opts = {})
58
+ args = get_item_args(item_ids, opts.clone)
59
+ obj = OpenStruct.new(opts: args)
60
+ yield obj if block_given?
61
+ resp = ews.get_item(args)
62
+ get_items_parser(resp)
63
+ end
64
+
65
+ # Copy an array of items to the specified folder
66
+ # @param items [Array] an array of EWS Items that you want to copy
67
+ # @param folder [String,Symbol,GenericFolder] The folder to copy to. This must
68
+ # be a subclass of GenericFolder, a DistinguishedFolderId (must me a Symbol)
69
+ # or a FolderId (String)
70
+ # @return [Array<Hash>] returns a Hash for each item passed
71
+ # on success:
72
+ # {:success => true, :item_id => <new_item_id>}
73
+ # on failure:
74
+ # {:success => false, :error_message => <the message>}
75
+ def copy_items(items, folder)
76
+ folder = folder.id if folder.kind_of?(Types::GenericFolder)
77
+ item_ids = items.collect{|i| {item_id: {id: i.id, change_key: i.change_key}}}
78
+ copy_opts = {
79
+ :to_folder_id => {:id => folder},
80
+ :item_ids => item_ids
81
+ }
82
+ resp = ews.copy_item(copy_opts)
83
+ copy_move_items_parser(resp)
84
+ end
85
+
86
+ # Move an array of items to the specified folder
87
+ # @see #copy_items for parameter info
88
+ def move_items(items, folder)
89
+ folder = folder.id if folder.kind_of?(Types::GenericFolder)
90
+ item_ids = items.collect{|i| {item_id: {id: i.id, change_key: i.change_key}}}
91
+ move_opts = {
92
+ :to_folder_id => {:id => folder},
93
+ :item_ids => item_ids
94
+ }
95
+ resp = ews.move_item(move_opts)
96
+ copy_move_items_parser(resp, :move_item_response_message)
97
+ end
98
+
99
+ # Exports an entire item into base64 string
100
+ # @param item_ids [Array] array of item ids. Can also be a single id value
101
+ # return [Array] array of bulk items
102
+ def export_items(item_ids)
103
+ args = export_items_args(item_ids)
104
+
105
+ resp = ews.export_items(args)
106
+ export_items_parser(resp)
107
+ end
108
+
109
+ private
110
+
111
+ def get_item_args(item_id, opts)
112
+ opts[:shape] ||= :default
113
+ default_args = {
114
+ :item_shape => {:base_shape => opts[:shape]}
115
+ }
116
+ default_args[:item_ids] = case item_id
117
+ when Hash
118
+ [{:item_id => item_id}]
119
+ when Array
120
+ item_id.map{|i| {:item_id => {:id => i}}}
121
+ else
122
+ [{:item_id => {:id => item_id}}]
123
+ end
124
+ default_args.merge opts
125
+ end
126
+
127
+ def get_item_parser(resp)
128
+ rm = resp.response_messages[0]
129
+
130
+ if(rm && rm.status == 'Success')
131
+ i = rm.items.first
132
+ itype = i.keys.first
133
+ class_by_name(itype).new(ews, i[itype])
134
+ else
135
+ code = rm.respond_to?(:code) ? rm.code : "Unknown"
136
+ text = rm.respond_to?(:message_text) ? rm.message_text : "Unknown"
137
+ raise EwsItemNotFound, "Could not retrieve item. #{rm.code}: #{rm.message_text}"
138
+ end
139
+ end
140
+
141
+ def get_items_parser(resp)
142
+ items = []
143
+
144
+ resp.response_messages.each do |rm|
145
+ if(rm && rm.status == 'Success')
146
+ rm.items.each do |i|
147
+ type = i.keys.first
148
+ items << class_by_name(type).new(ews, i[type])
149
+ end
150
+ end
151
+ end
152
+
153
+ items
154
+ end
155
+
156
+ def find_items_args(opts)
157
+ default_args = {
158
+ :traversal => 'Shallow',
159
+ :item_shape => {:base_shape => 'Default'}
160
+ }
161
+
162
+ if opts[:folder_id].is_a?(Hash)
163
+ default_args[:parent_folder_ids] = [opts.delete(:folder_id)]
164
+ else
165
+ default_args[:parent_folder_ids] = [{:id => opts.delete(:folder_id)}]
166
+ end
167
+ default_args.merge(opts)
168
+ end
169
+
170
+ def find_items_parser(resp)
171
+ rm = resp.response_messages[0]
172
+ if rm.success?
173
+ items = []
174
+ rm.root_folder.items.each do |i|
175
+ type = i.keys.first
176
+ items << class_by_name(type).new(ews, i[type])
177
+ end
178
+ items
179
+ else
180
+ raise EwsError, "Could not retrieve folder. #{rm.code}: #{rm.message_text}"
181
+ end
182
+ end
183
+
184
+ def copy_move_items_parser(resp, resp_type = :copy_item_response_message)
185
+ resp.response_messages.collect {|r|
186
+ obj = {}
187
+ if r.success?
188
+ obj[:success] = true
189
+ item = r.items.first
190
+ key = item.keys.first
191
+ obj[:item_id] = item[key][:elems][0][:item_id][:attribs][:id]
192
+ else
193
+ obj[:success] = false
194
+ obj[:error_message] = "#{r.response_code}: #{r.message_text}"
195
+ end
196
+ obj
197
+ }
198
+ end
199
+
200
+ def export_items_args(item_ids)
201
+ default_args = {}
202
+ default_args[:item_ids] = []
203
+ if item_ids.is_a?(Array) then
204
+ item_ids.each do |id|
205
+ default_args[:item_ids] = default_args[:item_ids] + [{:item_id => {:id => id}}]
206
+ end
207
+ else
208
+ default_args[:item_ids] = [{:item_id => {:id => item_ids}}]
209
+ end
210
+ default_args
211
+ end
212
+
213
+ def export_items_parser(resp)
214
+ rm = resp.response_messages
215
+ if(rm)
216
+ items = []
217
+ rm.each do |i|
218
+ if i.success? then
219
+ type = i.type
220
+ items << class_by_name(type).new(ews, i.message[:elems])
221
+ else
222
+ code = i.respond_to?(:code) ? i.code : "Unknown"
223
+ text = i.respond_to?(:message_text) ? i.message_text : "Unknown"
224
+ items << "Could not retrieve item. #{code}: #{text}"
225
+ end
226
+ end
227
+ items
228
+ end
229
+ end
230
+
231
+ end # Viewpoint::EWS::ItemAccessors
@@ -0,0 +1,99 @@
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::MailboxAccessors
20
+ include Viewpoint::EWS
21
+
22
+ # Resolve contacts in the Exchange Data Store
23
+ # @param [String] ustring A string to resolve contacts to.
24
+ # @return [Array<MailboxUser>] It returns an Array of MailboxUsers.
25
+ def search_contacts(ustring)
26
+ resp = ews.resolve_names(:name => ustring)
27
+
28
+ users = []
29
+ if(resp.status == 'Success')
30
+ mb = resp.response_message[:elems][:resolution_set][:elems][0][:resolution][:elems][0]
31
+ users << Types::MailboxUser.new(ews, mb[:mailbox][:elems])
32
+ elsif(resp.code == 'ErrorNameResolutionMultipleResults')
33
+ resp.response_message[:elems][:resolution_set][:elems].each do |u|
34
+ if u[:resolution][:elems][0][:mailbox]
35
+ users << Types::MailboxUser.new(ews, u[:resolution][:elems][0][:mailbox][:elems])
36
+ end
37
+ end
38
+ else
39
+ raise EwsError, "Find User produced an error: #{resp.code}: #{resp.message}"
40
+ end
41
+ users
42
+ end
43
+
44
+ # GetUserAvailability request
45
+ # @see http://msdn.microsoft.com/en-us/library/aa563800.aspx
46
+ # @param [Array<String>] emails A list of emails you want to retrieve free-busy info for.
47
+ # @param [Hash] opts
48
+ # @option opts [DateTime] :start_time
49
+ # @option opts [DateTime] :end_time
50
+ # @option opts [String] :routing_type should be one of the ConnectingSID variables Viewpoint::EWS::ConnectingSID
51
+ # @option opts [Symbol] :requested_view :merged_only/:free_busy/
52
+ # :free_busy_merged/:detailed/:detailed_merged
53
+ # @option opts [Hash] :time_zone The TimeZone data
54
+ # Example: {:bias => 'UTC offset in minutes',
55
+ # :standard_time => {:bias => 480, :time => '02:00:00',
56
+ # :day_order => 5, :month => 10, :day_of_week => 'Sunday'},
57
+ # :daylight_time => {same options as :standard_time}}
58
+ def get_user_availability(emails, opts)
59
+ opts = opts.clone
60
+ args = get_user_availability_args(emails, opts)
61
+ resp = ews.get_user_availability(args.merge(opts))
62
+ get_user_availability_parser(resp)
63
+ end
64
+
65
+
66
+ private
67
+
68
+ def get_user_availability_args(emails, opts)
69
+ unless opts.has_key?(:start_time) && opts.has_key?(:end_time) && opts.has_key?(:requested_view)
70
+ raise EwsBadArgumentError, "You must specify a start_time, end_time and requested_view."
71
+ end
72
+
73
+ routing = opts[:routing_type]
74
+
75
+ default_args = {
76
+ mailbox_data: (emails.collect{ |e|
77
+ user = {address: e}
78
+ user[:routing_type] = routing if routing
79
+ [email: user]
80
+ }.flatten),
81
+ free_busy_view_options: {
82
+ time_window: {
83
+ start_time: opts[:start_time],
84
+ end_time: opts[:end_time]
85
+ },
86
+ requested_view: { :requested_free_busy_view => opts[:requested_view] },
87
+ }
88
+ }
89
+ end
90
+
91
+ def get_user_availability_parser(resp)
92
+ if(resp.status == 'Success')
93
+ resp
94
+ else
95
+ raise EwsError, "GetUserAvailability produced an error: #{resp.code}: #{resp.message}"
96
+ end
97
+ end
98
+
99
+ end # Viewpoint::EWS::MailboxAccessors
@@ -0,0 +1,93 @@
1
+ =begin
2
+ This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services.
3
+
4
+ Copyright © 2011 Dan Wanek <dan.wanek@gmail.com>
5
+
6
+ Licensed under the Apache License, Version 2.0 (the "License");
7
+ you may not use this file except in compliance with the License.
8
+ You may obtain a copy of the License at
9
+
10
+ http://www.apache.org/licenses/LICENSE-2.0
11
+
12
+ Unless required by applicable law or agreed to in writing, software
13
+ distributed under the License is distributed on an "AS IS" BASIS,
14
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ See the License for the specific language governing permissions and
16
+ limitations under the License.
17
+ =end
18
+ module Viewpoint::EWS::MessageAccessors
19
+ include Viewpoint::EWS
20
+
21
+ # Send an E-mail message
22
+ #
23
+ # @param [Hash] opts A Hash with message params
24
+ # @option opts [String] :subject The message subject
25
+ # @option opts [String] :body The message body
26
+ # @option opts [Array] :to_recipients An array of e-mail addresses to send to
27
+ # @option opts [Array] :cc_recipients An array of e-mail addresses to send to
28
+ # @option opts [Array] :bcc_recipients An array of e-mail addresses to send to
29
+ # @option opts [Array] :extended_properties An array of extended properties
30
+ # [{extended_field_uri: {epros}, value: <val>}] or values: [<val>, <val>]
31
+ # @option opts [Boolean] :draft if true it will save to the draft folder
32
+ # without sending the message.
33
+ # @option opts [String,Symbol,Hash] saved_item_folder_id Either a
34
+ # FolderId(String) or a DistinguishedFolderId(Symbol). You can also pass a
35
+ # Hash in the form: {id: <fold_id>, change_key: <change_key>}
36
+ # @option opts [Array<File>] :file_attachments an Array of File or Tempfile objects
37
+ # @option opts [Array<File>] :inline_attachments an Array of Inline File or Tempfile objects
38
+ # @return [Message,Boolean] Returns true if the message is sent, false if
39
+ # nothing is returned from EWS or if draft is true it will return the
40
+ # Message object. Finally, if something goes wrong, it raises an error
41
+ # with a message stating why the e-mail could not be sent.
42
+ # @todo Finish ItemAttachments
43
+ def send_message(opts = {}, &block)
44
+ msg = Template::Message.new opts.clone
45
+ yield msg if block_given?
46
+ if msg.has_attachments?
47
+ draft = msg.draft
48
+ msg.draft = true
49
+ resp = parse_create_item(ews.create_item(msg.to_ews))
50
+ msg.file_attachments.each do |f|
51
+ next unless f.kind_of?(File) or f.kind_of?(Tempfile)
52
+ resp.add_file_attachment(f)
53
+ end
54
+ msg.inline_attachments.each do |f|
55
+ next unless f.kind_of?(File) or f.kind_of?(Tempfile)
56
+ resp.add_inline_attachment(f)
57
+ end
58
+ if draft
59
+ resp.submit_attachments!
60
+ resp
61
+ else
62
+ resp.submit!
63
+ end
64
+ else
65
+ resp = ews.create_item(msg.to_ews)
66
+ resp.response_messages ? parse_create_item(resp) : false
67
+ end
68
+ end
69
+
70
+ # See #send_message for options
71
+ def draft_message(opts = {}, &block)
72
+ send_message opts.merge(draft: true), &block
73
+ end
74
+
75
+
76
+ private
77
+
78
+
79
+ def parse_create_item(resp)
80
+ rm = resp.response_messages[0]
81
+ if(rm.status == 'Success')
82
+ rm.items.empty? ? true : parse_message(rm.items.first)
83
+ else
84
+ raise EwsError, "Could not send message. #{rm.code}: #{rm.message_text}"
85
+ end
86
+ end
87
+
88
+ def parse_message(msg)
89
+ mtype = msg.keys.first
90
+ message = class_by_name(mtype).new(ews, msg[mtype])
91
+ end
92
+
93
+ end # Viewpoint::EWS::MessageAccessors