viewpoint 0.1.26 → 1.1.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 (112) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +203 -0
  3. data/lib/ews/calendar_accessors.rb +34 -0
  4. data/lib/ews/connection.rb +140 -0
  5. data/lib/ews/connection_helper.rb +35 -0
  6. data/lib/ews/convert_accessors.rb +56 -0
  7. data/lib/{exceptions/exceptions.rb → ews/errors.rb} +29 -19
  8. data/lib/ews/ews_client.rb +105 -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 +242 -0
  13. data/lib/ews/mailbox_accessors.rb +92 -0
  14. data/lib/ews/meeting_accessors.rb +39 -0
  15. data/lib/ews/message_accessors.rb +93 -0
  16. data/lib/ews/push_subscription_accessors.rb +33 -0
  17. data/lib/ews/room_accessors.rb +48 -0
  18. data/lib/ews/roomlist_accessors.rb +47 -0
  19. data/lib/ews/soap.rb +64 -0
  20. data/lib/ews/soap/builders/ews_builder.rb +1384 -0
  21. data/lib/ews/soap/ews_response.rb +84 -0
  22. data/lib/ews/soap/ews_soap_availability_response.rb +58 -0
  23. data/lib/ews/soap/ews_soap_free_busy_response.rb +119 -0
  24. data/lib/ews/soap/ews_soap_response.rb +103 -0
  25. data/lib/ews/soap/ews_soap_room_response.rb +53 -0
  26. data/lib/ews/soap/ews_soap_roomlist_response.rb +54 -0
  27. data/lib/ews/soap/exchange_availability.rb +61 -0
  28. data/lib/ews/soap/exchange_data_services.rb +780 -0
  29. data/lib/ews/soap/exchange_notification.rb +146 -0
  30. data/lib/ews/soap/exchange_synchronization.rb +93 -0
  31. data/lib/ews/soap/exchange_time_zones.rb +56 -0
  32. data/lib/ews/soap/exchange_user_configuration.rb +33 -0
  33. data/lib/ews/soap/exchange_web_service.rb +264 -0
  34. data/lib/{model/item_attachment.rb → ews/soap/parsers/ews_parser.rb} +24 -14
  35. data/lib/ews/soap/parsers/ews_sax_document.rb +70 -0
  36. data/lib/ews/soap/response_message.rb +80 -0
  37. data/lib/ews/soap/responses/create_attachment_response_message.rb +47 -0
  38. data/lib/{model/meeting_message.rb → ews/soap/responses/create_item_response_message.rb} +7 -10
  39. data/lib/ews/soap/responses/find_item_response_message.rb +80 -0
  40. data/lib/ews/soap/responses/get_events_response_message.rb +53 -0
  41. data/lib/ews/soap/responses/send_notification_response_message.rb +59 -0
  42. data/lib/{model/attachment.rb → ews/soap/responses/subscribe_response_message.rb} +17 -13
  43. data/lib/{model/attendee.rb → ews/soap/responses/sync_folder_hierarchy_response_message.rb} +14 -15
  44. data/lib/ews/soap/responses/sync_folder_items_response_message.rb +36 -0
  45. data/lib/ews/templates/calendar_item.rb +79 -0
  46. data/lib/ews/templates/forward_item.rb +24 -0
  47. data/lib/ews/templates/message.rb +85 -0
  48. data/lib/ews/templates/reply_to_item.rb +25 -0
  49. data/lib/ews/templates/task.rb +74 -0
  50. data/lib/ews/types.rb +194 -0
  51. data/lib/ews/types/attachment.rb +77 -0
  52. data/lib/{model/meeting_cancellation.rb → ews/types/attendee.rb} +9 -8
  53. data/lib/ews/types/calendar_folder.rb +50 -0
  54. data/lib/ews/types/calendar_item.rb +130 -0
  55. data/lib/ews/types/contact.rb +7 -0
  56. data/lib/ews/types/contacts_folder.rb +8 -0
  57. data/lib/ews/types/copied_event.rb +51 -0
  58. data/lib/{soap/handsoap/builder.rb → ews/types/created_event.rb} +5 -2
  59. data/lib/ews/types/deleted_event.rb +24 -0
  60. data/lib/ews/types/distribution_list.rb +7 -0
  61. data/lib/ews/types/event.rb +62 -0
  62. data/lib/ews/types/export_items_response_message.rb +52 -0
  63. data/lib/ews/types/file_attachment.rb +65 -0
  64. data/lib/ews/types/folder.rb +60 -0
  65. data/lib/ews/types/free_busy_changed_event.rb +24 -0
  66. data/lib/ews/types/generic_folder.rb +418 -0
  67. data/lib/ews/types/item.rb +447 -0
  68. data/lib/ews/types/item_attachment.rb +84 -0
  69. data/lib/{model → ews/types}/item_field_uri_map.rb +2 -18
  70. data/lib/ews/types/mailbox_user.rb +156 -0
  71. data/lib/ews/types/meeting_cancellation.rb +7 -0
  72. data/lib/ews/types/meeting_message.rb +7 -0
  73. data/lib/ews/types/meeting_request.rb +7 -0
  74. data/lib/ews/types/meeting_response.rb +7 -0
  75. data/lib/ews/types/message.rb +7 -0
  76. data/lib/ews/types/modified_event.rb +48 -0
  77. data/lib/{extensions/string.rb → ews/types/moved_event.rb} +31 -15
  78. data/lib/ews/types/new_mail_event.rb +24 -0
  79. data/lib/ews/types/out_of_office.rb +147 -0
  80. data/lib/ews/types/post_item.rb +7 -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 +41 -0
  84. data/lib/ews/types/tasks_folder.rb +27 -0
  85. data/lib/viewpoint.rb +85 -108
  86. data/lib/{model/distribution_list.rb → viewpoint/logging.rb} +6 -3
  87. data/lib/{model/meeting_response.rb → viewpoint/logging/config.rb} +3 -3
  88. data/lib/viewpoint/string_utils.rb +76 -0
  89. metadata +156 -123
  90. data/README +0 -114
  91. data/lib/model/calendar_folder.rb +0 -67
  92. data/lib/model/calendar_item.rb +0 -267
  93. data/lib/model/contact.rb +0 -238
  94. data/lib/model/contacts_folder.rb +0 -46
  95. data/lib/model/event.rb +0 -116
  96. data/lib/model/file_attachment.rb +0 -53
  97. data/lib/model/folder.rb +0 -47
  98. data/lib/model/generic_folder.rb +0 -461
  99. data/lib/model/item.rb +0 -312
  100. data/lib/model/mailbox_user.rb +0 -146
  101. data/lib/model/meeting_request.rb +0 -39
  102. data/lib/model/message.rb +0 -142
  103. data/lib/model/model.rb +0 -269
  104. data/lib/model/search_folder.rb +0 -48
  105. data/lib/model/task.rb +0 -121
  106. data/lib/model/tasks_folder.rb +0 -44
  107. data/lib/soap/handsoap/builders/ews_build_helpers.rb +0 -383
  108. data/lib/soap/handsoap/builders/ews_builder.rb +0 -146
  109. data/lib/soap/handsoap/ews_service.rb +0 -790
  110. data/lib/soap/handsoap/parser.rb +0 -104
  111. data/lib/soap/handsoap/parsers/ews_parser.rb +0 -245
  112. data/lib/soap/soap_provider.rb +0 -64
@@ -0,0 +1,33 @@
1
+ =begin
2
+ This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services.
3
+
4
+ Copyright © 2011 Dan Wanek <dan.wanek@gmail.com>
5
+
6
+ Licensed under the Apache License, Version 2.0 (the "License");
7
+ you may not use this file except in compliance with the License.
8
+ You may obtain a copy of the License at
9
+
10
+ http://www.apache.org/licenses/LICENSE-2.0
11
+
12
+ Unless required by applicable law or agreed to in writing, software
13
+ distributed under the License is distributed on an "AS IS" BASIS,
14
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ See the License for the specific language governing permissions and
16
+ limitations under the License.
17
+ =end
18
+
19
+ module Viewpoint::EWS::PushSubscriptionAccessors
20
+ include Viewpoint::EWS
21
+
22
+ def parse_send_notification(msg)
23
+ parser = Viewpoint::EWS::SOAP::EwsParser.new(msg)
24
+ resp = parser.parse response_class: Viewpoint::EWS::SOAP::EwsResponse
25
+ rmsg = resp.response_messages[0]
26
+ if rmsg.success?
27
+ rmsg
28
+ else
29
+ raise EwsSubscriptionError, "#{rmsg.code}: #{rmsg.message_text}"
30
+ end
31
+ end
32
+
33
+ end # Viewpoint::EWS::PushSubscriptionAccessors
@@ -0,0 +1,48 @@
1
+ =begin
2
+ This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services.
3
+
4
+ Copyright © 2013 Camille Baldock <viewpoint@camillebaldock.co.uk>
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::RoomAccessors
20
+ include Viewpoint::EWS
21
+
22
+ # Gets the rooms that are available within the specified room distribution list
23
+ # @see http://msdn.microsoft.com/en-us/library/dd899415.aspx
24
+ # @param [String] roomDistributionList
25
+ def get_rooms(roomDistributionList)
26
+ resp = ews.get_rooms(roomDistributionList)
27
+ get_rooms_parser(resp)
28
+ end
29
+
30
+ def room_name( room )
31
+ room[:room][:elems][:id][:elems][0][:name][:text]
32
+ end
33
+
34
+ def room_email( room )
35
+ room[:room][:elems][:id][:elems][1][:email_address][:text]
36
+ end
37
+
38
+ private
39
+
40
+ def get_rooms_parser(resp)
41
+ if resp.success?
42
+ resp
43
+ else
44
+ raise EwsError, "GetRooms produced an error: #{resp.code}: #{resp.message}"
45
+ end
46
+ end
47
+
48
+ end # Viewpoint::EWS::RoomAccessors
@@ -0,0 +1,47 @@
1
+ =begin
2
+ This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services.
3
+
4
+ Copyright © 2013 Camille Baldock <viewpoint@camillebaldock.co.uk>
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::RoomlistAccessors
20
+ include Viewpoint::EWS
21
+
22
+ # Gets the room lists that are available within the Exchange organization.
23
+ # @see http://msdn.microsoft.com/en-us/library/dd899416.aspx
24
+ def get_room_lists
25
+ resp = ews.get_room_lists
26
+ get_room_lists_parser(resp)
27
+ end
28
+
29
+ def roomlist_name( roomlist )
30
+ roomlist[:address][:elems][:name][:text]
31
+ end
32
+
33
+ def roomlist_email( roomlist )
34
+ roomlist[:address][:elems][:email_address][:text]
35
+ end
36
+
37
+ private
38
+
39
+ def get_room_lists_parser(resp)
40
+ if resp.success?
41
+ resp
42
+ else
43
+ raise EwsError, "GetRoomLists produced an error: #{resp.code}: #{resp.message}"
44
+ end
45
+ end
46
+
47
+ end # Viewpoint::EWS::RoomlistAccessors
data/lib/ews/soap.rb ADDED
@@ -0,0 +1,64 @@
1
+ =begin
2
+ This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services.
3
+
4
+ Copyright © 2011 Dan Wanek <dan.wanek@gmail.com>
5
+
6
+ Licensed under the Apache License, Version 2.0 (the "License");
7
+ you may not use this file except in compliance with the License.
8
+ You may obtain a copy of the License at
9
+
10
+ http://www.apache.org/licenses/LICENSE-2.0
11
+
12
+ Unless required by applicable law or agreed to in writing, software
13
+ distributed under the License is distributed on an "AS IS" BASIS,
14
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ See the License for the specific language governing permissions and
16
+ limitations under the License.
17
+ =end
18
+
19
+ # This module defines some constants and other niceties to make available to
20
+ # the underlying SOAP classes and modules that do the actual work.
21
+ module Viewpoint
22
+ module EWS
23
+ module SOAP
24
+
25
+ # CONSTANTS
26
+
27
+ NS_SOAP = 'soap'.freeze
28
+ NS_EWS_TYPES = 't'.freeze
29
+ NS_EWS_MESSAGES = 'm'.freeze
30
+ NAMESPACES = {
31
+ "xmlns:#{NS_SOAP}" => 'http://schemas.xmlsoap.org/soap/envelope/',
32
+ "xmlns:#{NS_EWS_TYPES}" => 'http://schemas.microsoft.com/exchange/services/2006/types',
33
+ "xmlns:#{NS_EWS_MESSAGES}" => 'http://schemas.microsoft.com/exchange/services/2006/messages',
34
+ }.freeze
35
+
36
+ # used in ResolveNames to determine where names are resolved
37
+ ActiveDirectory = 'ActiveDirectory'
38
+ ActiveDirectoryContacts = 'ActiveDirectoryContacts'
39
+ Contacts = 'Contacts'
40
+ ContactsActiveDirectory = 'ContactsActiveDirectory'
41
+
42
+ # Target specific Exchange Server versions
43
+ # @see http://msdn.microsoft.com/en-us/library/bb891876(v=exchg.140).aspx
44
+ VERSION_2007 = 'Exchange2007'
45
+ VERSION_2007_SP1 = 'Exchange2007_SP1'
46
+ VERSION_2010 = 'Exchange2010'
47
+ VERSION_2010_SP1 = 'Exchange2010_SP1'
48
+ VERSION_2010_SP2 = 'Exchange2010_SP2'
49
+ VERSION_2013 = 'Exchange2013'
50
+ VERSION_2013_SP1 = 'Exchange2013_SP1'
51
+ VERSION_NONE = 'none'
52
+
53
+ HARD_DELETE = 'HardDelete'
54
+ SOFT_DELETE = 'SoftDelete'
55
+ MOVE_TO_DELETED_ITEMS = 'MoveToDeletedItems'
56
+
57
+ def initialize
58
+ @log = Logging.logger[self.class.name.to_s.to_sym]
59
+ @default_ns = NAMESPACES["xmlns:#{NS_EWS_MESSAGES}"]
60
+ end
61
+
62
+ end # SOAP
63
+ end # EWS
64
+ end # Viewpoint
@@ -0,0 +1,1384 @@
1
+ =begin
2
+ This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services.
3
+
4
+ Copyright © 2011 Dan Wanek <dan.wanek@gmail.com>
5
+
6
+ Licensed under the Apache License, Version 2.0 (the "License");
7
+ you may not use this file except in compliance with the License.
8
+ You may obtain a copy of the License at
9
+
10
+ http://www.apache.org/licenses/LICENSE-2.0
11
+
12
+ Unless required by applicable law or agreed to in writing, software
13
+ distributed under the License is distributed on an "AS IS" BASIS,
14
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ See the License for the specific language governing permissions and
16
+ limitations under the License.
17
+ =end
18
+ module Viewpoint::EWS::SOAP
19
+
20
+ # This class includes the element builders. The idea is that each element should
21
+ # know how to build themselves so each parent element can delegate creation of
22
+ # subelements to a method of the same name with a '!' after it.
23
+ class EwsBuilder
24
+ include Viewpoint::EWS
25
+ include Viewpoint::StringUtils
26
+
27
+ attr_reader :nbuild
28
+ def initialize
29
+ @nbuild = Nokogiri::XML::Builder.new
30
+ end
31
+
32
+ # Build the SOAP envelope and yield this object so subelements can be built. Once
33
+ # you have the EwsBuilder object you can use the nbuild object like shown in the
34
+ # example for the Header section. The nbuild object is the underlying
35
+ # Nokogiri::XML::Builder object.
36
+ # @param [Hash] opts
37
+ # @option opts [String] :server_version The version string that should get
38
+ # set in the Header. See ExchangeWebService#initialize
39
+ # @option opts [Hash] :time_zone_context TimeZoneDefinition. Format: !{id: time_zone_identifier}
40
+ # @example
41
+ # xb = EwsBuilder.new
42
+ # xb.build! do |part, b|
43
+ # if(part == :header)
44
+ # b.nbuild.MyVar('blablabla')
45
+ # else
46
+ # b.folder_shape!({:base_shape => 'Default'})
47
+ # end
48
+ # end
49
+ def build!(opts = {}, &block)
50
+ @nbuild.Envelope(NAMESPACES) do |node|
51
+ node.parent.namespace = parent_namespace(node)
52
+ node.Header {
53
+ set_version_header! opts[:server_version]
54
+ set_impersonation! opts[:impersonation_type], opts[:impersonation_mail]
55
+ set_time_zone_context_header! opts[:time_zone_context]
56
+ yield(:header, self) if block_given?
57
+ }
58
+ node.Body {
59
+ yield(:body, self) if block_given?
60
+ }
61
+ end
62
+ @nbuild.doc
63
+ end
64
+
65
+ # Build XML from a passed in Hash or Array in a specified format.
66
+ # @param [Array,Hash] elems The elements to add to the Builder. They must
67
+ # be specified like so:
68
+ #
69
+ # !{:top =>
70
+ # { :xmlns => 'http://stonesthrow/soap',
71
+ # :sub_elements => [
72
+ # {:elem1 => {:text => 'inside'}},
73
+ # {:elem2 => {:text => 'inside2'}}
74
+ # ],
75
+ # :id => '3232', :tx_dd => 23, :asdf => 'turkey'
76
+ # }
77
+ # }
78
+ # or
79
+ # [ {:first => {:text => 'hello'}},
80
+ # {:second => {:text => 'world'}}
81
+ # ]
82
+ #
83
+ # NOTE: there are specialized keys for text (:text), child elements
84
+ # (:sub_elements) and namespaces (:xmlns).
85
+ def build_xml!(elems)
86
+ case elems.class.name
87
+ when 'Hash'
88
+ keys = elems.keys
89
+ vals = elems.values
90
+ if(keys.length > 1 && !vals.is_a?(Hash))
91
+ raise "invalid input: #{elems}"
92
+ end
93
+ vals = vals.first.clone
94
+ se = vals.delete(:sub_elements)
95
+ txt = vals.delete(:text)
96
+ xmlns_attribute = vals.delete(:xmlns_attribute)
97
+
98
+ node = @nbuild.send(camel_case(keys.first), txt, vals) {|x|
99
+ build_xml!(se) if se
100
+ }
101
+
102
+ # Set node level namespace
103
+ node.xmlns = NAMESPACES["xmlns:#{xmlns_attribute}"] if xmlns_attribute
104
+ when 'Array'
105
+ elems.each do |e|
106
+ build_xml!(e)
107
+ end
108
+ else
109
+ raise "Unsupported type: #{elems.class.name}"
110
+ end
111
+ end
112
+
113
+ # Build the FolderShape element
114
+ # @see http://msdn.microsoft.com/en-us/library/aa494311.aspx
115
+ # @param [Hash] folder_shape The folder shape structure to build from
116
+ # @todo need fully support all options
117
+ def folder_shape!(folder_shape)
118
+ @nbuild.FolderShape {
119
+ @nbuild.parent.default_namespace = @default_ns
120
+ base_shape!(folder_shape[:base_shape])
121
+ if(folder_shape[:additional_properties])
122
+ additional_properties!(folder_shape[:additional_properties])
123
+ end
124
+ }
125
+ end
126
+
127
+ # Build the ItemShape element
128
+ # @see http://msdn.microsoft.com/en-us/library/aa565261.aspx
129
+ # @param [Hash] item_shape The item shape structure to build from
130
+ # @todo need fully support all options
131
+ def item_shape!(item_shape)
132
+ @nbuild[NS_EWS_MESSAGES].ItemShape {
133
+ @nbuild.parent.default_namespace = @default_ns
134
+ base_shape!(item_shape[:base_shape])
135
+ include_mime_content!(item_shape[:include_mime_content]) if item_shape.has_key?(:include_mime_content)
136
+ body_type!(item_shape[:body_type]) if item_shape[:body_type]
137
+ if(item_shape[:additional_properties])
138
+ additional_properties!(item_shape[:additional_properties])
139
+ end
140
+ }
141
+ end
142
+
143
+ # Build the IndexedPageItemView element
144
+ # @see http://msdn.microsoft.com/en-us/library/exchange/aa563549(v=exchg.150).aspx
145
+ # @todo needs peer check
146
+ def indexed_page_item_view!(indexed_page_item_view)
147
+ attribs = {}
148
+ indexed_page_item_view.each_pair {|k,v| attribs[camel_case(k)] = v.to_s}
149
+ @nbuild[NS_EWS_MESSAGES].IndexedPageItemView(attribs)
150
+ end
151
+
152
+ # Build the BaseShape element
153
+ # @see http://msdn.microsoft.com/en-us/library/aa580545.aspx
154
+ def base_shape!(base_shape)
155
+ @nbuild[NS_EWS_TYPES].BaseShape(camel_case(base_shape))
156
+ end
157
+
158
+ def include_mime_content!(include_mime_content)
159
+ @nbuild[NS_EWS_TYPES].IncludeMimeContent(include_mime_content.to_s.downcase)
160
+ end
161
+
162
+ def body_type!(body_type)
163
+ body_type = body_type.to_s
164
+ if body_type =~ /html/i
165
+ body_type = body_type.upcase
166
+ else
167
+ body_type = body_type.downcase.capitalize
168
+ end
169
+ nbuild[NS_EWS_TYPES].BodyType(body_type)
170
+ end
171
+
172
+ # Build the ParentFolderIds element
173
+ # @see http://msdn.microsoft.com/en-us/library/aa565998.aspx
174
+ def parent_folder_ids!(pfids)
175
+ @nbuild[NS_EWS_MESSAGES].ParentFolderIds {
176
+ pfids.each do |pfid|
177
+ dispatch_folder_id!(pfid)
178
+ end
179
+ }
180
+ end
181
+
182
+ # Build the ParentFolderId element
183
+ # @see http://msdn.microsoft.com/en-us/library/aa563268.aspx
184
+ def parent_folder_id!(pfid)
185
+ @nbuild.ParentFolderId {
186
+ dispatch_folder_id!(pfid)
187
+ }
188
+ end
189
+
190
+ # Build the FolderIds element
191
+ # @see http://msdn.microsoft.com/en-us/library/aa580509.aspx
192
+ def folder_ids!(fids, act_as=nil)
193
+ ns = @nbuild.parent.name.match(/subscription/i) ? NS_EWS_TYPES : NS_EWS_MESSAGES
194
+ @nbuild[ns].FolderIds {
195
+ fids.each do |fid|
196
+ fid[:act_as] = act_as if act_as != nil
197
+ dispatch_folder_id!(fid)
198
+ end
199
+ }
200
+ end
201
+
202
+ # Build the SyncFolderId element
203
+ # @see http://msdn.microsoft.com/en-us/library/aa580296.aspx
204
+ def sync_folder_id!(fid)
205
+ @nbuild.SyncFolderId {
206
+ dispatch_folder_id!(fid)
207
+ }
208
+ end
209
+
210
+ # Build the DistinguishedFolderId element
211
+ # @see http://msdn.microsoft.com/en-us/library/aa580808.aspx
212
+ # @todo add support for the Mailbox child object
213
+ def distinguished_folder_id!(dfid, change_key = nil, act_as = nil)
214
+ attribs = {'Id' => dfid.to_s}
215
+ attribs['ChangeKey'] = change_key if change_key
216
+ @nbuild[NS_EWS_TYPES].DistinguishedFolderId(attribs) {
217
+ if ! act_as.nil?
218
+ mailbox!({:email_address => act_as})
219
+ end
220
+ }
221
+ end
222
+
223
+ # Build the FolderId element
224
+ # @see http://msdn.microsoft.com/en-us/library/aa579461.aspx
225
+ def folder_id!(fid, change_key = nil)
226
+ attribs = {'Id' => fid}
227
+ attribs['ChangeKey'] = change_key if change_key
228
+ @nbuild[NS_EWS_TYPES].FolderId(attribs)
229
+ end
230
+
231
+ # @see http://msdn.microsoft.com/en-us/library/aa563525(v=EXCHG.140).aspx
232
+ def item_ids!(item_ids)
233
+ @nbuild.ItemIds {
234
+ item_ids.each do |iid|
235
+ dispatch_item_id!(iid)
236
+ end
237
+ }
238
+ end
239
+
240
+ def parent_item_id!(id)
241
+ nbuild.ParentItemId {|x|
242
+ x.parent['Id'] = id[:id]
243
+ x.parent['ChangeKey'] = id[:change_key] if id[:change_key]
244
+ }
245
+ end
246
+
247
+ # @see http://msdn.microsoft.com/en-us/library/aa580234(v=EXCHG.140).aspx
248
+ def item_id!(id)
249
+ nbuild[NS_EWS_TYPES].ItemId {|x|
250
+ x.parent['Id'] = id[:id]
251
+ x.parent['ChangeKey'] = id[:change_key] if id[:change_key]
252
+ }
253
+ end
254
+
255
+ # @see http://msdn.microsoft.com/en-us/library/ff709503(v=exchg.140).aspx
256
+ def export_item_ids!(item_ids)
257
+ ns = @nbuild.parent.name.match(/subscription/i) ? NS_EWS_TYPES : NS_EWS_MESSAGES
258
+ @nbuild[ns].ExportItems{
259
+ @nbuild.ItemIds {
260
+ item_ids.each do |iid|
261
+ dispatch_item_id!(iid)
262
+ end
263
+ }
264
+ }
265
+ end
266
+
267
+ # @see http://msdn.microsoft.com/en-us/library/aa580744(v=EXCHG.140).aspx
268
+ def occurrence_item_id!(id)
269
+ @nbuild[NS_EWS_TYPES].OccurrenceItemId {|x|
270
+ x.parent['RecurringMasterId'] = id[:recurring_master_id]
271
+ x.parent['ChangeKey'] = id[:change_key] if id[:change_key]
272
+ x.parent['InstanceIndex'] = id[:instance_index]
273
+ }
274
+ end
275
+
276
+ # @see http://msdn.microsoft.com/en-us/library/aa581019(v=EXCHG.140).aspx
277
+ def recurring_master_item_id!(id)
278
+ @nbuild[NS_EWS_TYPES].RecurringMasterItemId {|x|
279
+ x.parent['OccurrenceId'] = id[:occurrence_id]
280
+ x.parent['ChangeKey'] = id[:change_key] if id[:change_key]
281
+ }
282
+ end
283
+
284
+ # @see http://msdn.microsoft.com/en-us/library/aa565020(v=EXCHG.140).aspx
285
+ def to_folder_id!(to_fid)
286
+ @nbuild[NS_EWS_MESSAGES].ToFolderId {
287
+ dispatch_folder_id!(to_fid)
288
+ }
289
+ end
290
+
291
+ # @see http://msdn.microsoft.com/en-us/library/aa564009.aspx
292
+ def folders!(folders)
293
+ @nbuild.Folders {|x|
294
+ folders.each do |fold|
295
+ fold.each_pair do |ftype, vars| # convenience, should only be one pair
296
+ ftype = "#{ftype}!".to_sym
297
+ if self.respond_to? ftype
298
+ self.send ftype, vars
299
+ else
300
+ raise Viewpoint::EWS::EwsNotImplemented,
301
+ "#{ftype} not implemented as a builder."
302
+ end
303
+ end
304
+ end
305
+ }
306
+ end
307
+
308
+ def folder!(folder, type = :Folder)
309
+ nbuild[NS_EWS_TYPES].send(type) {|x|
310
+ folder.each_pair do |e,v|
311
+ ftype = "#{e}!".to_sym
312
+ if e == :folder_id
313
+ dispatch_folder_id!(v)
314
+ elsif self.respond_to?(ftype)
315
+ self.send ftype, v
316
+ else
317
+ raise Viewpoint::EWS::EwsNotImplemented,
318
+ "#{ftype} not implemented as a builder."
319
+ end
320
+ end
321
+ }
322
+ end
323
+
324
+ def calendar_folder!(folder)
325
+ folder! folder, :CalendarFolder
326
+ end
327
+
328
+ def contacts_folder!(folder)
329
+ folder! folder, :ContactsFolder
330
+ end
331
+
332
+ def search_folder!(folder)
333
+ folder! folder, :SearchFolder
334
+ end
335
+
336
+ def tasks_folder!(folder)
337
+ folder! folder, :TasksFolder
338
+ end
339
+
340
+ def display_name!(name)
341
+ nbuild[NS_EWS_TYPES].DisplayName(name)
342
+ end
343
+
344
+ # Build the AdditionalProperties element
345
+ # @see http://msdn.microsoft.com/en-us/library/aa563810.aspx
346
+ def additional_properties!(addprops)
347
+ @nbuild[NS_EWS_TYPES].AdditionalProperties {
348
+ addprops.each_pair {|k,v|
349
+ dispatch_field_uri!({k => v}, NS_EWS_TYPES)
350
+ }
351
+ }
352
+ end
353
+
354
+ # Build the Mailbox element.
355
+ # This element is commonly used for delegation. Typically passing an
356
+ # email_address is sufficient
357
+ # @see http://msdn.microsoft.com/en-us/library/aa565036.aspx
358
+ # @param [Hash] mailbox A well-formated hash
359
+ def mailbox!(mbox)
360
+ nbuild[NS_EWS_TYPES].Mailbox {
361
+ name!(mbox[:name]) if mbox[:name]
362
+ email_address!(mbox[:email_address]) if mbox[:email_address]
363
+ address!(mbox[:address]) if mbox[:address] # for Availability query
364
+ routing_type!(mbox[:routing_type]) if mbox[:routing_type]
365
+ mailbox_type!(mbox[:mailbox_type]) if mbox[:mailbox_type]
366
+ item_id!(mbox[:item_id]) if mbox[:item_id]
367
+ }
368
+ end
369
+
370
+ def name!(name)
371
+ nbuild[NS_EWS_TYPES].Name(name)
372
+ end
373
+
374
+ def email_address!(email)
375
+ nbuild[NS_EWS_TYPES].EmailAddress(email)
376
+ end
377
+
378
+ def address!(email)
379
+ nbuild[NS_EWS_TYPES].Address(email)
380
+ end
381
+
382
+ # This is stupid. The only valid value is "SMTP"
383
+ def routing_type!(type)
384
+ nbuild[NS_EWS_TYPES].RoutingType(type)
385
+ end
386
+
387
+ def mailbox_type!(type)Standard
388
+ nbuild[NS_EWS_TYPES].MailboxType(type)
389
+ end
390
+
391
+ def user_oof_settings!(opts)
392
+ nbuild[NS_EWS_TYPES].UserOofSettings {
393
+ nbuild.OofState(camel_case(opts[:oof_state]))
394
+ nbuild.ExternalAudience(camel_case(opts[:external_audience])) if opts[:external_audience]
395
+ duration!(opts[:duration]) if opts[:duration]
396
+ nbuild.InternalReply {
397
+ nbuild.Message(opts[:internal_reply])
398
+ } if opts[:external_reply]
399
+ nbuild.ExternalReply {
400
+ nbuild.Message(opts[:external_reply])
401
+ } if opts[:external_reply]
402
+ }
403
+ end
404
+
405
+ def duration!(opts)
406
+ nbuild.Duration {
407
+ nbuild.StartTime(format_time opts[:start_time])
408
+ nbuild.EndTime(format_time opts[:end_time])
409
+ }
410
+ end
411
+
412
+ def mailbox_data!(md)
413
+ nbuild[NS_EWS_TYPES].MailboxData {
414
+ nbuild[NS_EWS_TYPES].Email {
415
+ mbox = md[:email]
416
+ name!(mbox[:name]) if mbox[:name]
417
+ address!(mbox[:address]) if mbox[:address] # for Availability query
418
+ routing_type!(mbox[:routing_type]) if mbox[:routing_type]
419
+ }
420
+ nbuild[NS_EWS_TYPES].AttendeeType 'Required'
421
+ }
422
+ end
423
+
424
+ def free_busy_view_options!(opts)
425
+ nbuild[NS_EWS_TYPES].FreeBusyViewOptions {
426
+ nbuild[NS_EWS_TYPES].TimeWindow {
427
+ nbuild[NS_EWS_TYPES].StartTime(format_time opts[:time_window][:start_time])
428
+ nbuild[NS_EWS_TYPES].EndTime(format_time opts[:time_window][:end_time])
429
+ }
430
+ nbuild[NS_EWS_TYPES].RequestedView(camel_case(opts[:requested_view][:requested_free_busy_view]))
431
+ }
432
+ end
433
+
434
+ def suggestions_view_options!(opts)
435
+ end
436
+
437
+ def time_zone!(zone)
438
+ zone ||= {}
439
+ zone = {
440
+ bias: zone[:bias] || 480,
441
+ standard_time: {
442
+ bias: 0,
443
+ time: "02:00:00",
444
+ day_order: 5,
445
+ month: 10,
446
+ day_of_week: 'Sunday'
447
+ }.merge(zone[:standard_time] || {}),
448
+ daylight_time: {
449
+ bias: -60,
450
+ time: "02:00:00",
451
+ day_order: 1,
452
+ month: 4,
453
+ day_of_week: 'Sunday'
454
+ }.merge(zone[:daylight_time] || {})
455
+ }
456
+
457
+ nbuild[NS_EWS_TYPES].TimeZone {
458
+ nbuild[NS_EWS_TYPES].Bias(zone[:bias])
459
+ nbuild[NS_EWS_TYPES].StandardTime {
460
+ nbuild[NS_EWS_TYPES].Bias(zone[:standard_time][:bias])
461
+ nbuild[NS_EWS_TYPES].Time(zone[:standard_time][:time])
462
+ nbuild[NS_EWS_TYPES].DayOrder(zone[:standard_time][:day_order])
463
+ nbuild[NS_EWS_TYPES].Month(zone[:standard_time][:month])
464
+ nbuild[NS_EWS_TYPES].DayOfWeek(zone[:standard_time][:day_of_week])
465
+ }
466
+ nbuild[NS_EWS_TYPES].DaylightTime {
467
+ nbuild[NS_EWS_TYPES].Bias(zone[:daylight_time][:bias])
468
+ nbuild[NS_EWS_TYPES].Time(zone[:daylight_time][:time])
469
+ nbuild[NS_EWS_TYPES].DayOrder(zone[:daylight_time][:day_order])
470
+ nbuild[NS_EWS_TYPES].Month(zone[:daylight_time][:month])
471
+ nbuild[NS_EWS_TYPES].DayOfWeek(zone[:daylight_time][:day_of_week])
472
+ }
473
+ }
474
+ end
475
+
476
+ # Request all known time_zones from server
477
+ def get_server_time_zones!(get_time_zone_options)
478
+ nbuild[NS_EWS_MESSAGES].GetServerTimeZones('ReturnFullTimeZoneData' => get_time_zone_options[:full]) do
479
+ if get_time_zone_options[:ids] && get_time_zone_options[:ids].any?
480
+ nbuild[NS_EWS_MESSAGES].Ids do
481
+ get_time_zone_options[:ids].each do |id|
482
+ nbuild[NS_EWS_TYPES].Id id
483
+ end
484
+ end
485
+ end
486
+ end
487
+ end
488
+
489
+ # Specifies an optional time zone for the start time
490
+ # @param [Hash] attributes
491
+ # @option attributes :id [String] ID of the Microsoft well known time zone
492
+ # @option attributes :name [String] Optional name of the time zone
493
+ # @todo Implement sub elements Periods, TransitionsGroups and Transitions to override zone
494
+ # @see http://msdn.microsoft.com/en-us/library/exchange/dd899524.aspx
495
+ def start_time_zone!(zone)
496
+ attributes = {}
497
+ attributes['Id'] = zone[:id] if zone[:id]
498
+ attributes['Name'] = zone[:name] if zone[:name]
499
+ nbuild[NS_EWS_TYPES].StartTimeZone(attributes)
500
+ end
501
+
502
+ # Specifies an optional time zone for the end time
503
+ # @param [Hash] attributes
504
+ # @option attributes :id [String] ID of the Microsoft well known time zone
505
+ # @option attributes :name [String] Optional name of the time zone
506
+ # @todo Implement sub elements Periods, TransitionsGroups and Transitions to override zone
507
+ # @see http://msdn.microsoft.com/en-us/library/exchange/dd899434.aspx
508
+ def end_time_zone!(zone)
509
+ attributes = {}
510
+ attributes['Id'] = zone[:id] if zone[:id]
511
+ attributes['Name'] = zone[:name] if zone[:name]
512
+ nbuild[NS_EWS_TYPES].EndTimeZone(attributes)
513
+ end
514
+
515
+ # Specify a time zone
516
+ # @todo Implement subelements Periods, TransitionsGroups and Transitions to override zone
517
+ # @see http://msdn.microsoft.com/en-us/library/exchange/dd899488.aspx
518
+ def time_zone_definition!(zone)
519
+ attributes = {'Id' => zone[:id]}
520
+ attributes['Name'] = zone[:name] if zone[:name]
521
+ nbuild[NS_EWS_TYPES].TimeZoneDefinition(attributes)
522
+ end
523
+
524
+ # Build the Restriction element
525
+ # @see http://msdn.microsoft.com/en-us/library/aa563791.aspx
526
+ # @param [Hash] restriction a well-formatted Hash that can be fed to #build_xml!
527
+ def restriction!(restriction)
528
+ @nbuild[NS_EWS_MESSAGES].Restriction {
529
+ restriction.each_pair do |k,v|
530
+ self.send normalize_type(k), v
531
+ end
532
+ }
533
+ end
534
+
535
+ def and_r(expr)
536
+ and_or('And', expr)
537
+ end
538
+
539
+ def or_r(expr)
540
+ and_or('Or', expr)
541
+ end
542
+
543
+ def and_or(type, expr)
544
+ @nbuild[NS_EWS_TYPES].send(type) {
545
+ expr.each do |e|
546
+ type = e.keys.first
547
+ self.send normalize_type(type), e[type]
548
+ end
549
+ }
550
+ end
551
+
552
+ def not_r(expr)
553
+ @nbuild[NS_EWS_TYPES].Not {
554
+ type = expr.keys.first
555
+ self.send(type, expr[type])
556
+ }
557
+ end
558
+
559
+ def contains(expr)
560
+ @nbuild[NS_EWS_TYPES].Contains(
561
+ 'ContainmentMode' => expr.delete(:containment_mode),
562
+ 'ContainmentComparison' => expr.delete(:containment_comparison)) {
563
+ c = expr.delete(:constant) # remove constant 1st for ordering
564
+ type = expr.keys.first
565
+ self.send(type, expr[type])
566
+ constant(c)
567
+ }
568
+ end
569
+
570
+ def excludes(expr)
571
+ @nbuild[NS_EWS_TYPES].Excludes {
572
+ b = expr.delete(:bitmask) # remove bitmask 1st for ordering
573
+ type = expr.keys.first
574
+ self.send(type, expr[type])
575
+ bitmask(b)
576
+ }
577
+ end
578
+
579
+ def exists(expr)
580
+ @nbuild[NS_EWS_TYPES].Exists {
581
+ type = expr.keys.first
582
+ self.send(type, expr[type])
583
+ }
584
+ end
585
+
586
+ def bitmask(expr)
587
+ @nbuild[NS_EWS_TYPES].Bitmask('Value' => expr[:value])
588
+ end
589
+
590
+ def is_equal_to(expr)
591
+ restriction_compare('IsEqualTo',expr)
592
+ end
593
+
594
+ def is_greater_than(expr)
595
+ restriction_compare('IsGreaterThan',expr)
596
+ end
597
+
598
+ def is_greater_than_or_equal_to(expr)
599
+ restriction_compare('IsGreaterThanOrEqualTo',expr)
600
+ end
601
+
602
+ def is_less_than(expr)
603
+ restriction_compare('IsLessThan',expr)
604
+ end
605
+
606
+ def is_less_than_or_equal_to(expr)
607
+ restriction_compare('IsLessThanOrEqualTo',expr)
608
+ end
609
+
610
+ def is_not_equal_to(expr)
611
+ restriction_compare('IsNotEqualTo',expr)
612
+ end
613
+
614
+ def restriction_compare(type,expr)
615
+ nbuild[NS_EWS_TYPES].send(type) {
616
+ expr.each do |e|
617
+ e.each_pair do |k,v|
618
+ self.send(k, v)
619
+ end
620
+ end
621
+ }
622
+ end
623
+
624
+ def ews_types_builder
625
+ nbuild[NS_EWS_TYPES]
626
+ end
627
+
628
+ def field_uRI(expr)
629
+ value = expr.is_a?(Hash) ? (expr[:field_uRI] || expr[:field_uri]) : expr
630
+ ews_types_builder.FieldURI('FieldURI' => value)
631
+ end
632
+
633
+ alias_method :field_uri, :field_uRI
634
+
635
+ def indexed_field_uRI(expr)
636
+ nbuild[NS_EWS_TYPES].IndexedFieldURI(
637
+ 'FieldURI' => (expr[:field_uRI] || expr[:field_uri]),
638
+ 'FieldIndex' => expr[:field_index]
639
+ )
640
+ end
641
+
642
+ alias_method :indexed_field_uri, :indexed_field_uRI
643
+
644
+ def extended_field_uRI(expr)
645
+ nbuild[NS_EWS_TYPES].ExtendedFieldURI {
646
+ nbuild.parent['DistinguishedPropertySetId'] = expr[:distinguished_property_set_id] if expr[:distinguished_property_set_id]
647
+ nbuild.parent['PropertySetId'] = expr[:property_set_id] if expr[:property_set_id]
648
+ nbuild.parent['PropertyTag'] = expr[:property_tag] if expr[:property_tag]
649
+ nbuild.parent['PropertyName'] = expr[:property_name] if expr[:property_name]
650
+ nbuild.parent['PropertyId'] = expr[:property_id] if expr[:property_id]
651
+ nbuild.parent['PropertyType'] = expr[:property_type] if expr[:property_type]
652
+ }
653
+ end
654
+
655
+ alias_method :extended_field_uri, :extended_field_uRI
656
+
657
+ def extended_properties!(eprops)
658
+ eprops.each {|ep| extended_property!(ep)}
659
+ end
660
+
661
+ def extended_property!(eprop)
662
+ nbuild[NS_EWS_TYPES].ExtendedProperty {
663
+ key = eprop.keys.grep(/extended/i).first
664
+ dispatch_field_uri!({key => eprop[key]}, NS_EWS_TYPES)
665
+ if eprop[:values]
666
+ nbuild.Values {
667
+ eprop[:values].each do |v|
668
+ value! v
669
+ end
670
+ }
671
+ elsif eprop[:value]
672
+ value! eprop[:value]
673
+ end
674
+ }
675
+ end
676
+
677
+ def value!(val)
678
+ nbuild[NS_EWS_TYPES].Value(val)
679
+ end
680
+
681
+ def field_uRI_or_constant(expr)
682
+ nbuild[NS_EWS_TYPES].FieldURIOrConstant {
683
+ type = expr.keys.first
684
+ self.send(type, expr[type])
685
+ }
686
+ end
687
+
688
+ alias_method :field_uri_or_constant, :field_uRI_or_constant
689
+
690
+ def constant(expr)
691
+ nbuild[NS_EWS_TYPES].Constant('Value' => expr[:value])
692
+ end
693
+
694
+ # Build the CalendarView element
695
+ def calendar_view!(cal_view)
696
+ attribs = {}
697
+ cal_view.each_pair {|k,v| attribs[camel_case(k)] = v.to_s}
698
+ @nbuild[NS_EWS_MESSAGES].CalendarView(attribs)
699
+ end
700
+
701
+ # Build the ContactsView element
702
+ def contacts_view!(con_view)
703
+ attribs = {}
704
+ con_view.each_pair {|k,v| attribs[camel_case(k)] = v.to_s}
705
+ @nbuild[NS_EWS_MESSAGES].ContactsView(attribs)
706
+ end
707
+
708
+ # @see http://msdn.microsoft.com/en-us/library/aa579678(v=EXCHG.140).aspx
709
+ def event_types!(evtypes)
710
+ @nbuild[NS_EWS_TYPES].EventTypes {
711
+ evtypes.each do |et|
712
+ @nbuild[NS_EWS_TYPES].EventType(camel_case(et))
713
+ end
714
+ }
715
+ end
716
+
717
+ # @see http://msdn.microsoft.com/en-us/library/aa565886(v=EXCHG.140).aspx
718
+ def watermark!(wmark, ns = NS_EWS_TYPES)
719
+ @nbuild[ns].Watermark(wmark)
720
+ end
721
+
722
+ # @see http://msdn.microsoft.com/en-us/library/aa565201(v=EXCHG.140).aspx
723
+ def timeout!(tout)
724
+ @nbuild[NS_EWS_TYPES].Timeout(tout)
725
+ end
726
+
727
+ # @see http://msdn.microsoft.com/en-us/library/aa564048(v=EXCHG.140).aspx
728
+ def status_frequency!(freq)
729
+ @nbuild[NS_EWS_TYPES].StatusFrequency(freq)
730
+ end
731
+
732
+ # @see http://msdn.microsoft.com/en-us/library/aa566309(v=EXCHG.140).aspx
733
+ def uRL!(url)
734
+ @nbuild[NS_EWS_TYPES].URL(url)
735
+ end
736
+
737
+ # @see http://msdn.microsoft.com/en-us/library/aa563790(v=EXCHG.140).aspx
738
+ def subscription_id!(subid)
739
+ @nbuild.SubscriptionId(subid)
740
+ end
741
+
742
+ # @see http://msdn.microsoft.com/en-us/library/aa563455(v=EXCHG.140).aspx
743
+ def pull_subscription_request(subopts)
744
+ subscribe_all = subopts[:subscribe_to_all_folders] ? 'true' : 'false'
745
+ @nbuild.PullSubscriptionRequest('SubscribeToAllFolders' => subscribe_all) {
746
+ folder_ids!(subopts[:folder_ids]) if subopts[:folder_ids]
747
+ event_types!(subopts[:event_types]) if subopts[:event_types]
748
+ watermark!(subopts[:watermark]) if subopts[:watermark]
749
+ timeout!(subopts[:timeout]) if subopts[:timeout]
750
+ }
751
+ end
752
+
753
+ # @see http://msdn.microsoft.com/en-us/library/aa563599(v=EXCHG.140).aspx
754
+ def push_subscription_request(subopts)
755
+ subscribe_all = subopts[:subscribe_to_all_folders] ? 'true' : 'false'
756
+ @nbuild.PushSubscriptionRequest('SubscribeToAllFolders' => subscribe_all) {
757
+ folder_ids!(subopts[:folder_ids]) if subopts[:folder_ids]
758
+ event_types!(subopts[:event_types]) if subopts[:event_types]
759
+ watermark!(subopts[:watermark]) if subopts[:watermark]
760
+ status_frequency!(subopts[:status_frequency]) if subopts[:status_frequency]
761
+ uRL!(subopts[:uRL]) if subopts[:uRL]
762
+ }
763
+ end
764
+
765
+ # @see http://msdn.microsoft.com/en-us/library/ff406182(v=EXCHG.140).aspx
766
+ def streaming_subscription_request(subopts)
767
+ subscribe_all = subopts[:subscribe_to_all_folders] ? 'true' : 'false'
768
+ @nbuild.StreamingSubscriptionRequest('SubscribeToAllFolders' => subscribe_all) {
769
+ folder_ids!(subopts[:folder_ids]) if subopts[:folder_ids]
770
+ event_types!(subopts[:event_types]) if subopts[:event_types]
771
+ }
772
+ end
773
+
774
+ # @see http://msdn.microsoft.com/en-us/library/aa565970(v=EXCHG.140).aspx
775
+ def sync_state!(syncstate)
776
+ @nbuild.SyncState(syncstate)
777
+ end
778
+
779
+ # @see http://msdn.microsoft.com/en-us/library/aa563785(v=EXCHG.140).aspx
780
+ def ignore!(item_ids)
781
+ @nbuild.Ignore {
782
+ item_ids.each do |iid|
783
+ item_id!(iid)
784
+ end
785
+ }
786
+ end
787
+
788
+ # @see http://msdn.microsoft.com/en-us/library/aa566325(v=EXCHG.140).aspx
789
+ def max_changes_returned!(cnum)
790
+ @nbuild[NS_EWS_MESSAGES].MaxChangesReturned(cnum)
791
+ end
792
+
793
+ # @see http://msdn.microsoft.com/en-us/library/dd899531(v=EXCHG.140).aspx
794
+ def sync_scope!(scope)
795
+ @nbuild.SyncScope(scope)
796
+ end
797
+
798
+ # @see http://msdn.microsoft.com/en-us/library/aa580758(v=EXCHG.140).aspx
799
+ def saved_item_folder_id!(fid)
800
+ @nbuild.SavedItemFolderId {
801
+ dispatch_folder_id!(fid)
802
+ }
803
+ end
804
+
805
+ # @see http://msdn.microsoft.com/en-us/library/aa565652(v=exchg.140).aspx
806
+ def item!(item)
807
+ nbuild.Item {
808
+ item.each_pair {|k,v|
809
+ self.send("#{k}!", v)
810
+ }
811
+ }
812
+ end
813
+
814
+ def message!(item)
815
+ nbuild[NS_EWS_TYPES].Message {
816
+ if item[:extended_properties]
817
+ extended_properties! item.delete(:extended_properties)
818
+ end
819
+ item.each_pair {|k,v|
820
+ self.send("#{k}!", v)
821
+ }
822
+ }
823
+ end
824
+
825
+ def categories!(categories)
826
+ nbuild[NS_EWS_TYPES].Categories {
827
+ categories.each do |c|
828
+ nbuild[NS_EWS_TYPES].String(c)
829
+ end
830
+ }
831
+ end
832
+
833
+ def is_from_me!(ans)
834
+ return unless ans
835
+
836
+ nbuild[NS_EWS_TYPES].IsFromMe
837
+ end
838
+
839
+ def mime_content!(mime_content)
840
+ @nbuild[NS_EWS_TYPES].MimeContent(mime_content)
841
+ end
842
+
843
+ def is_read!(read)
844
+ nbuild[NS_EWS_TYPES].IsRead(read)
845
+ end
846
+
847
+ def calendar_item!(item)
848
+ nbuild[NS_EWS_TYPES].CalendarItem {
849
+ item.each_pair {|k,v|
850
+ self.send("#{k}!", v)
851
+ }
852
+ }
853
+ end
854
+
855
+ def calendar_item_type!(type)
856
+ nbuild[NS_EWS_TYPES].CalendarItemType(type)
857
+ end
858
+
859
+ def recurrence!(item)
860
+ nbuild[NS_EWS_TYPES].Recurrence {
861
+ item.each_pair { |k, v|
862
+ self.send("#{k}!", v)
863
+ }
864
+ }
865
+ end
866
+
867
+ def daily_recurrence!(item)
868
+ nbuild[NS_EWS_TYPES].DailyRecurrence {
869
+ item.each_pair { |k, v|
870
+ self.send("#{k}!", v)
871
+ }
872
+ }
873
+ end
874
+
875
+ def weekly_recurrence!(item)
876
+ nbuild[NS_EWS_TYPES].WeeklyRecurrence {
877
+ item.each_pair { |k, v|
878
+ self.send("#{k}!", v)
879
+ }
880
+ }
881
+ end
882
+
883
+ def interval!(num)
884
+ nbuild[NS_EWS_TYPES].Interval(num)
885
+ end
886
+
887
+ def no_end_recurrence!(item)
888
+ nbuild[NS_EWS_TYPES].NoEndRecurrence {
889
+ item.each_pair { |k, v|
890
+ self.send("#{k}!", v)
891
+ }
892
+ }
893
+ end
894
+
895
+ def numbered_recurrence!(item)
896
+ nbuild[NS_EWS_TYPES].NumberedRecurrence {
897
+ item.each_pair { |k, v|
898
+ self.send("#{k}!", v)
899
+ }
900
+ }
901
+ end
902
+
903
+ def number_of_occurrences!(count)
904
+ nbuild[NS_EWS_TYPES].NumberOfOccurrences(count)
905
+ end
906
+
907
+
908
+ def task!(item)
909
+ nbuild[NS_EWS_TYPES].Task {
910
+ item.each_pair {|k, v|
911
+ self.send("#{k}!", v)
912
+ }
913
+ }
914
+ end
915
+
916
+ def forward_item!(item)
917
+ nbuild[NS_EWS_TYPES].ForwardItem {
918
+ item.each_pair {|k,v|
919
+ self.send("#{k}!", v)
920
+ }
921
+ }
922
+ end
923
+
924
+ def reply_to_item!(item)
925
+ nbuild[NS_EWS_TYPES].ReplyToItem {
926
+ item.each_pair {|k,v|
927
+ self.send("#{k}!", v)
928
+ }
929
+ }
930
+ end
931
+
932
+ def reply_all_to_item!(item)
933
+ nbuild[NS_EWS_TYPES].ReplyAllToItem {
934
+ item.each_pair {|k,v|
935
+ self.send("#{k}!", v)
936
+ }
937
+ }
938
+ end
939
+
940
+ def reference_item_id!(id)
941
+ nbuild[NS_EWS_TYPES].ReferenceItemId {|x|
942
+ x.parent['Id'] = id[:id]
943
+ x.parent['ChangeKey'] = id[:change_key] if id[:change_key]
944
+ }
945
+ end
946
+
947
+ def subject!(sub)
948
+ nbuild[NS_EWS_TYPES].Subject(sub)
949
+ end
950
+
951
+ def importance!(sub)
952
+ nbuild[NS_EWS_TYPES].Importance(sub)
953
+ end
954
+
955
+ def body!(b)
956
+ nbuild[NS_EWS_TYPES].Body(b[:text]) {|x|
957
+ x.parent['BodyType'] = b[:body_type] if b[:body_type]
958
+ }
959
+ end
960
+
961
+ def new_body_content!(b)
962
+ nbuild[NS_EWS_TYPES].NewBodyContent(b[:text]) {|x|
963
+ x.parent['BodyType'] = b[:body_type] if b[:body_type]
964
+ }
965
+ end
966
+
967
+ # @see http://msdn.microsoft.com/en-us/library/aa563719(v=exchg.140).aspx
968
+ # @param [Array] r An array of Mailbox type hashes to send to #mailbox!
969
+ def to_recipients!(r)
970
+ nbuild[NS_EWS_TYPES].ToRecipients {
971
+ r.each {|mbox| mailbox!(mbox[:mailbox]) }
972
+ }
973
+ end
974
+
975
+ def cc_recipients!(r)
976
+ nbuild[NS_EWS_TYPES].CcRecipients {
977
+ r.each {|mbox| mailbox!(mbox[:mailbox]) }
978
+ }
979
+ end
980
+
981
+ def bcc_recipients!(r)
982
+ nbuild[NS_EWS_TYPES].BccRecipients {
983
+ r.each {|mbox| mailbox!(mbox[:mailbox]) }
984
+ }
985
+ end
986
+
987
+ def from!(f)
988
+ nbuild[NS_EWS_TYPES].From {
989
+ mailbox! f[:mailbox]
990
+ }
991
+ end
992
+
993
+ def sender!(f)
994
+ nbuild[NS_EWS_TYPES].Sender {
995
+ mailbox! f[:mailbox]
996
+ }
997
+ end
998
+
999
+ def required_attendees!(attendees)
1000
+ nbuild[NS_EWS_TYPES].RequiredAttendees {
1001
+ attendees.each {|a| attendee!(a[:attendee])}
1002
+ }
1003
+ end
1004
+
1005
+ def optional_attendees!(attendees)
1006
+ nbuild[NS_EWS_TYPES].OptionalAttendees {
1007
+ attendees.each {|a| attendee!(a[:attendee])}
1008
+ }
1009
+ end
1010
+
1011
+ def resources!(attendees)
1012
+ nbuild[NS_EWS_TYPES].Resources {
1013
+ attendees.each {|a| attendee!(a[:attendee])}
1014
+ }
1015
+ end
1016
+
1017
+ # @todo support ResponseType, LastResponseTime: http://msdn.microsoft.com/en-us/library/aa580339.aspx
1018
+ def attendee!(a)
1019
+ nbuild[NS_EWS_TYPES].Attendee {
1020
+ mailbox!(a[:mailbox])
1021
+ }
1022
+ end
1023
+
1024
+ def start!(st)
1025
+ nbuild[NS_EWS_TYPES].Start(st[:text])
1026
+ end
1027
+
1028
+ def end!(et)
1029
+ nbuild[NS_EWS_TYPES].End(et[:text])
1030
+ end
1031
+
1032
+ def start_date!(sd)
1033
+ nbuild[NS_EWS_TYPES].StartDate sd[:text]
1034
+ end
1035
+
1036
+ def due_date!(dd)
1037
+ nbuild[NS_EWS_TYPES].DueDate format_time(dd[:text])
1038
+ end
1039
+
1040
+ def location!(loc)
1041
+ nbuild[NS_EWS_TYPES].Location(loc)
1042
+ end
1043
+
1044
+ def is_all_day_event!(all_day)
1045
+ nbuild[NS_EWS_TYPES].IsAllDayEvent(all_day)
1046
+ end
1047
+
1048
+ def is_response_requested!(response_requested)
1049
+ nbuild[NS_EWS_TYPES].IsResponseRequested(response_requested)
1050
+ end
1051
+
1052
+ def reminder_is_set!(reminder)
1053
+ nbuild[NS_EWS_TYPES].ReminderIsSet reminder
1054
+ end
1055
+
1056
+ def reminder_due_by!(date)
1057
+ nbuild[NS_EWS_TYPES].ReminderDueBy format_time(date)
1058
+ end
1059
+
1060
+ def reminder_minutes_before_start!(minutes)
1061
+ nbuild[NS_EWS_TYPES].ReminderMinutesBeforeStart minutes
1062
+ end
1063
+
1064
+ # @see http://msdn.microsoft.com/en-us/library/aa566143(v=exchg.150).aspx
1065
+ # possible values Exchange Server 2010 = [Free, Tentative, Busy, OOF, NoData]
1066
+ # Exchange Server 2013 = [Free, Tentative, Busy, OOF, WorkingElsewhere, NoData]
1067
+ def legacy_free_busy_status!(state)
1068
+ nbuild[NS_EWS_TYPES].LegacyFreeBusyStatus(state)
1069
+ end
1070
+
1071
+ # @see http://msdn.microsoft.com/en-us/library/aa565428(v=exchg.140).aspx
1072
+ def item_changes!(changes)
1073
+ nbuild.ItemChanges {
1074
+ changes.each do |chg|
1075
+ item_change!(chg)
1076
+ end
1077
+ }
1078
+ end
1079
+
1080
+ # @see http://msdn.microsoft.com/en-us/library/aa581081(v=exchg.140).aspx
1081
+ def item_change!(change)
1082
+ @nbuild[NS_EWS_TYPES].ItemChange {
1083
+ updates = change.delete(:updates) # Remove updates so dispatch_item_id works correctly
1084
+ dispatch_item_id!(change)
1085
+ updates!(updates)
1086
+ }
1087
+ end
1088
+
1089
+ # @see http://msdn.microsoft.com/en-us/library/aa581074(v=exchg.140).aspx
1090
+ def updates!(updates)
1091
+ @nbuild[NS_EWS_TYPES].Updates {
1092
+ updates.each do |update|
1093
+ dispatch_update_type!(update)
1094
+ end
1095
+ }
1096
+ end
1097
+
1098
+ # @see http://msdn.microsoft.com/en-us/library/aa581317(v=exchg.140).aspx
1099
+ def append_to_item_field!(upd)
1100
+ uri = upd.select {|k,v| k =~ /_uri/i}
1101
+ raise EwsBadArgumentError, "Bad argument given for AppendToItemField." if uri.keys.length != 1
1102
+ upd.delete(uri.keys.first)
1103
+ @nbuild.AppendToItemField {
1104
+ dispatch_field_uri!(uri)
1105
+ dispatch_field_item!(upd)
1106
+ }
1107
+ end
1108
+
1109
+ # @see http://msdn.microsoft.com/en-us/library/aa581487(v=exchg.140).aspx
1110
+ def set_item_field!(upd)
1111
+ uri = upd.select {|k,v| k =~ /_uri/i}
1112
+ raise EwsBadArgumentError, "Bad argument given for SetItemField." if uri.keys.length != 1
1113
+ upd.delete(uri.keys.first)
1114
+ @nbuild[NS_EWS_TYPES].SetItemField {
1115
+ dispatch_field_uri!(uri, NS_EWS_TYPES)
1116
+ dispatch_field_item!(upd, NS_EWS_TYPES)
1117
+ }
1118
+ end
1119
+
1120
+ # @see http://msdn.microsoft.com/en-us/library/aa580330(v=exchg.140).aspx
1121
+ def delete_item_field!(upd)
1122
+ uri = upd.select {|k,v| k =~ /_uri/i}
1123
+ raise EwsBadArgumentError, "Bad argument given for SetItemField." if uri.keys.length != 1
1124
+ @nbuild[NS_EWS_TYPES].DeleteItemField {
1125
+ dispatch_field_uri!(uri, NS_EWS_TYPES)
1126
+ }
1127
+ end
1128
+
1129
+ # @see http://msdn.microsoft.com/en-us/library/ff709497(v=exchg.140).aspx
1130
+ def return_new_item_ids!(retval)
1131
+ @nbuild.ReturnNewItemIds(retval)
1132
+ end
1133
+
1134
+ def inline_attachment!(fa)
1135
+ @nbuild[NS_EWS_TYPES].FileAttachment {
1136
+ @nbuild[NS_EWS_TYPES].Name(fa.name)
1137
+ @nbuild[NS_EWS_TYPES].ContentId(fa.name)
1138
+ @nbuild[NS_EWS_TYPES].IsInline(true)
1139
+ @nbuild[NS_EWS_TYPES].Content(fa.content)
1140
+ }
1141
+ end
1142
+
1143
+ def file_attachment!(fa)
1144
+ @nbuild[NS_EWS_TYPES].FileAttachment {
1145
+ @nbuild[NS_EWS_TYPES].Name(fa.name)
1146
+ @nbuild[NS_EWS_TYPES].Content(fa.content)
1147
+ }
1148
+ end
1149
+
1150
+ def item_attachment!(ia)
1151
+ @nbuild[NS_EWS_TYPES].ItemAttachment {
1152
+ @nbuild[NS_EWS_TYPES].Name(ia.name)
1153
+ @nbuild[NS_EWS_TYPES].Item {
1154
+ item_id!(ia.item)
1155
+ }
1156
+ }
1157
+ end
1158
+
1159
+ # Build the AttachmentIds element
1160
+ # @see http://msdn.microsoft.com/en-us/library/aa580686.aspx
1161
+ def attachment_ids!(aids)
1162
+ @nbuild.AttachmentIds {
1163
+ @nbuild.parent.default_namespace = @default_ns
1164
+ aids.each do |aid|
1165
+ attachment_id!(aid)
1166
+ end
1167
+ }
1168
+ end
1169
+
1170
+ # Build the AttachmentId element
1171
+ # @see http://msdn.microsoft.com/en-us/library/aa580764.aspx
1172
+ def attachment_id!(aid)
1173
+ attribs = {'Id' => aid}
1174
+ @nbuild[NS_EWS_TYPES].AttachmentId(attribs)
1175
+ end
1176
+
1177
+ def user_configuration_name!(cfg_name)
1178
+ attribs = {'Name' => cfg_name.delete(:name)}
1179
+ @nbuild[NS_EWS_MESSAGES].UserConfigurationName(attribs) {
1180
+ fid = cfg_name.keys.first
1181
+ self.send "#{fid}!", cfg_name[fid][:id], cfg_name[fid][:change_key]
1182
+ }
1183
+ end
1184
+
1185
+ def user_configuration_properties!(cfg_prop)
1186
+ @nbuild[NS_EWS_MESSAGES].UserConfigurationProperties(cfg_prop)
1187
+ end
1188
+
1189
+ # ---------------------- Helpers -------------------- #
1190
+
1191
+ # A helper method to dispatch to a FolderId or DistinguishedFolderId correctly
1192
+ # @param [Hash] fid A folder_id
1193
+ # Ex: {:id => myid, :change_key => ck}
1194
+ def dispatch_folder_id!(fid)
1195
+ if(fid[:id].is_a?(String))
1196
+ folder_id!(fid[:id], fid[:change_key])
1197
+ elsif(fid[:id].is_a?(Symbol))
1198
+ distinguished_folder_id!(fid[:id], fid[:change_key], fid[:act_as])
1199
+ else
1200
+ raise EwsBadArgumentError, "Bad argument given for a FolderId. #{fid[:id].class}"
1201
+ end
1202
+ end
1203
+
1204
+ # A helper method to dispatch to an ItemId, OccurrenceItemId, or a RecurringMasterItemId
1205
+ # @param [Hash] iid The item id of some type
1206
+ def dispatch_item_id!(iid)
1207
+ type = iid.keys.first
1208
+ item = iid[type]
1209
+ case type
1210
+ when :item_id
1211
+ item_id!(item)
1212
+ when :occurrence_item_id
1213
+ occurrence_item_id!(item)
1214
+ when :recurring_master_item_id
1215
+ recurring_master_item_id!(item)
1216
+ else
1217
+ raise EwsBadArgumentError, "Bad ItemId type. #{type}"
1218
+ end
1219
+ end
1220
+
1221
+ # A helper method to dispatch to a AppendToItemField, SetItemField, or
1222
+ # DeleteItemField
1223
+ # @param [Hash] update An update of some type
1224
+ def dispatch_update_type!(update)
1225
+ type = update.keys.first
1226
+ upd = update[type]
1227
+ case type
1228
+ when :append_to_item_field
1229
+ append_to_item_field!(upd)
1230
+ when :set_item_field
1231
+ set_item_field!(upd)
1232
+ when :delete_item_field
1233
+ delete_item_field!(upd)
1234
+ else
1235
+ raise EwsBadArgumentError, "Bad Update type. #{type}"
1236
+ end
1237
+ end
1238
+
1239
+ # A helper to dispatch to a FieldURI, IndexedFieldURI, or an ExtendedFieldURI
1240
+ # @todo Implement ExtendedFieldURI
1241
+ def dispatch_field_uri!(uri, ns=NS_EWS_MESSAGES)
1242
+ type = uri.keys.first
1243
+ vals = uri[type].is_a?(Array) ? uri[type] : [uri[type]]
1244
+ case type
1245
+ when :field_uRI, :field_uri
1246
+ vals.each do |val|
1247
+ value = val.is_a?(Hash) ? val[type] : val
1248
+ nbuild[ns].FieldURI('FieldURI' => value)
1249
+ end
1250
+ when :indexed_field_uRI, :indexed_field_uri
1251
+ vals.each do |val|
1252
+ nbuild[ns].IndexedFieldURI(
1253
+ 'FieldURI' => (val[:field_uRI] || val[:field_uri]),
1254
+ 'FieldIndex' => val[:field_index]
1255
+ )
1256
+ end
1257
+ when :extended_field_uRI, :extended_field_uri
1258
+ vals.each do |val|
1259
+ nbuild[ns].ExtendedFieldURI {
1260
+ nbuild.parent['DistinguishedPropertySetId'] = val[:distinguished_property_set_id] if val[:distinguished_property_set_id]
1261
+ nbuild.parent['PropertySetId'] = val[:property_set_id] if val[:property_set_id]
1262
+ nbuild.parent['PropertyTag'] = val[:property_tag] if val[:property_tag]
1263
+ nbuild.parent['PropertyName'] = val[:property_name] if val[:property_name]
1264
+ nbuild.parent['PropertyId'] = val[:property_id] if val[:property_id]
1265
+ nbuild.parent['PropertyType'] = val[:property_type] if val[:property_type]
1266
+ }
1267
+ end
1268
+ else
1269
+ raise EwsBadArgumentError, "Bad URI type. #{type}"
1270
+ end
1271
+ end
1272
+
1273
+ # Insert item, enforce xmlns attribute if prefix is present
1274
+ def dispatch_field_item!(item, ns_prefix = nil)
1275
+ item.values.first[:xmlns_attribute] = ns_prefix if ns_prefix
1276
+ build_xml!(item)
1277
+ end
1278
+
1279
+ def room_list!(cfg_prop)
1280
+ @nbuild[NS_EWS_MESSAGES].RoomList {
1281
+ email_address!(cfg_prop)
1282
+ }
1283
+ end
1284
+
1285
+ def room_lists!
1286
+ @nbuild[NS_EWS_MESSAGES].GetRoomLists
1287
+ end
1288
+
1289
+ def accept_item!(opts)
1290
+ @nbuild[NS_EWS_TYPES].AcceptItem {
1291
+ sensitivity!(opts)
1292
+ body!(opts) if opts[:text]
1293
+ reference_item_id!(opts)
1294
+ }
1295
+ end
1296
+
1297
+ def tentatively_accept_item!(opts)
1298
+ @nbuild[NS_EWS_TYPES].TentativelyAcceptItem {
1299
+ sensitivity!(opts)
1300
+ body!(opts) if opts[:text]
1301
+ reference_item_id!(opts)
1302
+ }
1303
+ end
1304
+
1305
+ def decline_item!(opts)
1306
+ @nbuild[NS_EWS_TYPES].DeclineItem {
1307
+ sensitivity!(opts)
1308
+ body!(opts) if opts[:text]
1309
+ reference_item_id!(opts)
1310
+ }
1311
+ end
1312
+
1313
+ def sensitivity!(value)
1314
+ nbuild[NS_EWS_TYPES].Sensitivity(value[:sensitivity])
1315
+ end
1316
+
1317
+ private
1318
+
1319
+ def parent_namespace(node)
1320
+ node.parent.namespace_definitions.find {|ns| ns.prefix == NS_SOAP}
1321
+ end
1322
+
1323
+ def set_version_header!(version)
1324
+ if version && !(version == 'none')
1325
+ nbuild[NS_EWS_TYPES].RequestServerVersion {|x|
1326
+ x.parent['Version'] = version
1327
+ }
1328
+ end
1329
+ end
1330
+
1331
+ def set_impersonation!(type, address)
1332
+ if type && type != ""
1333
+ nbuild[NS_EWS_TYPES].ExchangeImpersonation {
1334
+ nbuild[NS_EWS_TYPES].ConnectingSID {
1335
+ nbuild[NS_EWS_TYPES].method_missing type, address
1336
+ }
1337
+ }
1338
+ end
1339
+ end
1340
+
1341
+ # Set TimeZoneContext Header
1342
+ # @param time_zone_def [Hash] !{id: time_zone_identifier, name: time_zone_name}
1343
+ def set_time_zone_context_header!(time_zone_def)
1344
+ if time_zone_def
1345
+ nbuild[NS_EWS_TYPES].TimeZoneContext do
1346
+ time_zone_definition! time_zone_def
1347
+ end
1348
+ end
1349
+ end
1350
+
1351
+ def meeting_time_zone!(mtz)
1352
+ nbuild[NS_EWS_TYPES].MeetingTimeZone do |x|
1353
+ x.parent['TimeZoneName'] = mtz[:time_zone_name] if mtz[:time_zone_name]
1354
+ nbuild[NS_EWS_TYPES].BaseOffset(mtz[:base_offset][:text]) if mtz[:base_offset]
1355
+ end
1356
+ end
1357
+
1358
+ # some methods need special naming so they use the '_r' suffix like 'and'
1359
+ def normalize_type(type)
1360
+ case type
1361
+ when :and, :or, :not
1362
+ "#{type}_r".to_sym
1363
+ else
1364
+ type
1365
+ end
1366
+ end
1367
+
1368
+ def format_time(time)
1369
+ case time
1370
+ when Time, Date, DateTime
1371
+ time.to_datetime.new_offset(0).iso8601
1372
+ when String
1373
+ begin
1374
+ DateTime.parse(time).new_offset(0).iso8601
1375
+ rescue ArgumentError
1376
+ raise EwsBadArgumentError, "Invalid Time argument (#{time})"
1377
+ end
1378
+ else
1379
+ raise EwsBadArgumentError, "Invalid Time argument (#{time})"
1380
+ end
1381
+ end
1382
+
1383
+ end # EwsBuilder
1384
+ end # Viewpoint::EWS::SOAP