viewpoint 1.0.0.beta.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +16 -11
  3. data/lib/ews/connection.rb +15 -6
  4. data/lib/ews/convert_accessors.rb +56 -0
  5. data/lib/ews/errors.rb +56 -0
  6. data/lib/ews/ews_client.rb +33 -3
  7. data/lib/ews/exceptions/exceptions.rb +2 -0
  8. data/lib/ews/folder_accessors.rb +66 -1
  9. data/lib/ews/impersonation.rb +30 -0
  10. data/lib/ews/item_accessors.rb +77 -3
  11. data/lib/ews/mailbox_accessors.rb +6 -1
  12. data/lib/ews/message_accessors.rb +9 -2
  13. data/lib/ews/room_accessors.rb +48 -0
  14. data/lib/ews/roomlist_accessors.rb +47 -0
  15. data/lib/ews/soap.rb +1 -0
  16. data/lib/ews/soap/builders/ews_builder.rb +303 -48
  17. data/lib/ews/soap/ews_response.rb +2 -1
  18. data/lib/ews/soap/ews_soap_free_busy_response.rb +13 -3
  19. data/lib/ews/soap/ews_soap_response.rb +1 -1
  20. data/lib/ews/soap/ews_soap_room_response.rb +53 -0
  21. data/lib/ews/soap/ews_soap_roomlist_response.rb +54 -0
  22. data/lib/ews/soap/exchange_data_services.rb +49 -11
  23. data/lib/ews/soap/exchange_synchronization.rb +93 -0
  24. data/lib/ews/soap/exchange_time_zones.rb +56 -0
  25. data/lib/ews/soap/exchange_web_service.rb +36 -66
  26. data/lib/ews/soap/parsers/ews_sax_document.rb +8 -4
  27. data/lib/ews/soap/response_message.rb +3 -1
  28. data/lib/ews/soap/responses/create_attachment_response_message.rb +2 -1
  29. data/lib/ews/soap/responses/send_notification_response_message.rb +2 -1
  30. data/lib/{extensions/string.rb → ews/soap/responses/sync_folder_hierarchy_response_message.rb} +18 -17
  31. data/lib/ews/soap/responses/sync_folder_items_response_message.rb +36 -0
  32. data/lib/ews/templates/calendar_item.rb +78 -0
  33. data/lib/ews/templates/message.rb +8 -1
  34. data/lib/ews/templates/task.rb +74 -0
  35. data/lib/ews/types.rb +59 -11
  36. data/lib/ews/types/calendar_folder.rb +42 -0
  37. data/lib/ews/types/calendar_item.rb +93 -1
  38. data/lib/ews/types/export_items_response_message.rb +52 -0
  39. data/lib/ews/types/generic_folder.rb +70 -2
  40. data/lib/ews/types/item.rb +64 -4
  41. data/lib/ews/types/item_attachment.rb +41 -3
  42. data/lib/ews/types/item_field_uri_map.rb +1 -1
  43. data/lib/ews/types/task.rb +30 -0
  44. data/lib/ews/types/tasks_folder.rb +19 -0
  45. data/lib/viewpoint.rb +14 -14
  46. data/lib/viewpoint/logging.rb +27 -0
  47. data/lib/viewpoint/logging/config.rb +24 -0
  48. data/lib/viewpoint/string_utils.rb +76 -0
  49. metadata +82 -76
@@ -49,10 +49,15 @@ module Viewpoint::EWS::MailboxAccessors
49
49
  # @option opts [DateTime] :end_time
50
50
  # @option opts [Symbol] :requested_view :merged_only/:free_busy/
51
51
  # :free_busy_merged/:detailed/:detailed_merged
52
+ # @option opts [Hash] :time_zone The TimeZone data
53
+ # Example: {:bias => 'UTC offset in minutes',
54
+ # :standard_time => {:bias => 480, :time => '02:00:00',
55
+ # :day_order => 5, :month => 10, :day_of_week => 'Sunday'},
56
+ # :daylight_time => {same options as :standard_time}}
52
57
  def get_user_availability(emails, opts)
53
58
  opts = opts.clone
54
59
  args = get_user_availability_args(emails, opts)
55
- resp = ews.get_user_availability(args)
60
+ resp = ews.get_user_availability(args.merge(opts))
56
61
  get_user_availability_parser(resp)
57
62
  end
58
63
 
@@ -26,12 +26,15 @@ module Viewpoint::EWS::MessageAccessors
26
26
  # @option opts [Array] :to_recipients An array of e-mail addresses to send to
27
27
  # @option opts [Array] :cc_recipients An array of e-mail addresses to send to
28
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>]
29
31
  # @option opts [Boolean] :draft if true it will save to the draft folder
30
32
  # without sending the message.
31
33
  # @option opts [String,Symbol,Hash] saved_item_folder_id Either a
32
34
  # FolderId(String) or a DistinguishedFolderId(Symbol). You can also pass a
33
35
  # Hash in the form: {id: <fold_id>, change_key: <change_key>}
34
- # @option opts [Array<File>] :file_attachments an Array of File objects
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
35
38
  # @return [Message,Boolean] Returns true if the message is sent, false if
36
39
  # nothing is returned from EWS or if draft is true it will return the
37
40
  # Message object. Finally, if something goes wrong, it raises an error
@@ -45,9 +48,13 @@ module Viewpoint::EWS::MessageAccessors
45
48
  msg.draft = true
46
49
  resp = parse_create_item(ews.create_item(msg.to_ews))
47
50
  msg.file_attachments.each do |f|
48
- next unless f.kind_of?(File)
51
+ next unless f.kind_of?(File) or f.kind_of?(Tempfile)
49
52
  resp.add_file_attachment(f)
50
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
51
58
  if draft
52
59
  resp.submit_attachments!
53
60
  resp
@@ -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
@@ -47,6 +47,7 @@ module Viewpoint
47
47
  VERSION_2010_SP1 = 'Exchange2010_SP1'
48
48
  VERSION_2010_SP2 = 'Exchange2010_SP2'
49
49
  VERSION_2013 = 'Exchange2013'
50
+ VERSION_2013_SP1 = 'Exchange2013_SP1'
50
51
  VERSION_NONE = 'none'
51
52
 
52
53
  HARD_DELETE = 'HardDelete'
@@ -21,6 +21,8 @@ module Viewpoint::EWS::SOAP
21
21
  # know how to build themselves so each parent element can delegate creation of
22
22
  # subelements to a method of the same name with a '!' after it.
23
23
  class EwsBuilder
24
+ include Viewpoint::EWS
25
+ include Viewpoint::StringUtils
24
26
 
25
27
  attr_reader :nbuild
26
28
  def initialize
@@ -34,6 +36,7 @@ module Viewpoint::EWS::SOAP
34
36
  # @param [Hash] opts
35
37
  # @option opts [String] :server_version The version string that should get
36
38
  # set in the Header. See ExchangeWebService#initialize
39
+ # @option opts [Hash] :time_zone_context TimeZoneDefinition. Format: !{id: time_zone_identifier}
37
40
  # @example
38
41
  # xb = EwsBuilder.new
39
42
  # xb.build! do |part, b|
@@ -48,6 +51,8 @@ module Viewpoint::EWS::SOAP
48
51
  node.parent.namespace = parent_namespace(node)
49
52
  node.Header {
50
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]
51
56
  yield(:header, self) if block_given?
52
57
  }
53
58
  node.Body {
@@ -60,7 +65,8 @@ module Viewpoint::EWS::SOAP
60
65
  # Build XML from a passed in Hash or Array in a specified format.
61
66
  # @param [Array,Hash] elems The elements to add to the Builder. They must
62
67
  # be specified like so:
63
- # {:top =>
68
+ #
69
+ # !{:top =>
64
70
  # { :xmlns => 'http://stonesthrow/soap',
65
71
  # :sub_elements => [
66
72
  # {:elem1 => {:text => 'inside'}},
@@ -87,10 +93,14 @@ module Viewpoint::EWS::SOAP
87
93
  vals = vals.first.clone
88
94
  se = vals.delete(:sub_elements)
89
95
  txt = vals.delete(:text)
96
+ xmlns_attribute = vals.delete(:xmlns_attribute)
90
97
 
91
- @nbuild.send(keys.first.to_s.camel_case, txt, vals) {|x|
98
+ node = @nbuild.send(camel_case(keys.first), txt, vals) {|x|
92
99
  build_xml!(se) if se
93
100
  }
101
+
102
+ # Set node level namespace
103
+ node.xmlns = NAMESPACES["xmlns:#{xmlns_attribute}"] if xmlns_attribute
94
104
  when 'Array'
95
105
  elems.each do |e|
96
106
  build_xml!(e)
@@ -122,6 +132,7 @@ module Viewpoint::EWS::SOAP
122
132
  @nbuild[NS_EWS_MESSAGES].ItemShape {
123
133
  @nbuild.parent.default_namespace = @default_ns
124
134
  base_shape!(item_shape[:base_shape])
135
+ mime_content!(item_shape[:include_mime_content]) if item_shape.has_key?(:include_mime_content)
125
136
  body_type!(item_shape[:body_type]) if item_shape[:body_type]
126
137
  if(item_shape[:additional_properties])
127
138
  additional_properties!(item_shape[:additional_properties])
@@ -129,10 +140,23 @@ module Viewpoint::EWS::SOAP
129
140
  }
130
141
  end
131
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
+
132
152
  # Build the BaseShape element
133
153
  # @see http://msdn.microsoft.com/en-us/library/aa580545.aspx
134
154
  def base_shape!(base_shape)
135
- @nbuild[NS_EWS_TYPES].BaseShape(base_shape.to_s.camel_case)
155
+ @nbuild[NS_EWS_TYPES].BaseShape(camel_case(base_shape))
156
+ end
157
+
158
+ def mime_content!(include_mime_content)
159
+ @nbuild[NS_EWS_TYPES].IncludeMimeContent(include_mime_content.to_s.downcase)
136
160
  end
137
161
 
138
162
  def body_type!(body_type)
@@ -228,6 +252,18 @@ module Viewpoint::EWS::SOAP
228
252
  }
229
253
  end
230
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
+
231
267
  # @see http://msdn.microsoft.com/en-us/library/aa580744(v=EXCHG.140).aspx
232
268
  def occurrence_item_id!(id)
233
269
  @nbuild[NS_EWS_TYPES].OccurrenceItemId {|x|
@@ -310,7 +346,7 @@ module Viewpoint::EWS::SOAP
310
346
  def additional_properties!(addprops)
311
347
  @nbuild[NS_EWS_TYPES].AdditionalProperties {
312
348
  addprops.each_pair {|k,v|
313
- dispatch_field_uri!({k => v})
349
+ dispatch_field_uri!({k => v}, NS_EWS_TYPES)
314
350
  }
315
351
  }
316
352
  end
@@ -354,8 +390,8 @@ module Viewpoint::EWS::SOAP
354
390
 
355
391
  def user_oof_settings!(opts)
356
392
  nbuild[NS_EWS_TYPES].UserOofSettings {
357
- nbuild.OofState(opts[:oof_state].to_s.camel_case)
358
- nbuild.ExternalAudience(opts[:external_audience].to_s.camel_case) if opts[:external_audience]
393
+ nbuild.OofState(camel_case(opts[:oof_state]))
394
+ nbuild.ExternalAudience(camel_case(opts[:external_audience])) if opts[:external_audience]
359
395
  duration!(opts[:duration]) if opts[:duration]
360
396
  nbuild.InternalReply {
361
397
  nbuild.Message(opts[:internal_reply])
@@ -368,30 +404,30 @@ module Viewpoint::EWS::SOAP
368
404
 
369
405
  def duration!(opts)
370
406
  nbuild.Duration {
371
- nbuild.StartTime(opts[:start_time].new_offset(0).strftime('%FT%H:%M:%SZ'))
372
- nbuild.EndTime(opts[:end_time].new_offset(0).strftime('%FT%H:%M:%SZ'))
407
+ nbuild.StartTime(format_time opts[:start_time])
408
+ nbuild.EndTime(format_time opts[:end_time])
373
409
  }
374
410
  end
375
411
 
376
412
  def mailbox_data!(md)
377
413
  nbuild[NS_EWS_TYPES].MailboxData {
378
- nbuild.Email {
414
+ nbuild[NS_EWS_TYPES].Email {
379
415
  mbox = md[:email]
380
416
  name!(mbox[:name]) if mbox[:name]
381
417
  address!(mbox[:address]) if mbox[:address] # for Availability query
382
418
  routing_type!(mbox[:routing_type]) if mbox[:routing_type]
383
419
  }
384
- nbuild.AttendeeType 'Required'
420
+ nbuild[NS_EWS_TYPES].AttendeeType 'Required'
385
421
  }
386
422
  end
387
423
 
388
424
  def free_busy_view_options!(opts)
389
425
  nbuild[NS_EWS_TYPES].FreeBusyViewOptions {
390
- nbuild.TimeWindow {
391
- nbuild.StartTime(opts[:time_window][:start_time])
392
- nbuild.EndTime(opts[:time_window][:end_time])
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])
393
429
  }
394
- nbuild.RequestedView(opts[:requested_view][:requested_free_busy_view].to_s.camel_case)
430
+ nbuild[NS_EWS_TYPES].RequestedView(camel_case(opts[:requested_view][:requested_free_busy_view]))
395
431
  }
396
432
  end
397
433
 
@@ -399,25 +435,92 @@ module Viewpoint::EWS::SOAP
399
435
  end
400
436
 
401
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
+
402
457
  nbuild[NS_EWS_TYPES].TimeZone {
403
- nbuild.Bias(480)
404
- nbuild.StandardTime {
405
- nbuild.Bias(0)
406
- nbuild.Time("02:00:00")
407
- nbuild.DayOrder(5)
408
- nbuild.Month(10)
409
- nbuild.DayOfWeek('Sunday')
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])
410
465
  }
411
- nbuild.DaylightTime {
412
- nbuild.Bias(-60)
413
- nbuild.Time("02:00:00")
414
- nbuild.DayOrder(1)
415
- nbuild.Month(4)
416
- nbuild.DayOfWeek('Sunday')
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])
417
472
  }
418
473
  }
419
474
  end
420
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
+
421
524
  # Build the Restriction element
422
525
  # @see http://msdn.microsoft.com/en-us/library/aa563791.aspx
423
526
  # @param [Hash] restriction a well-formatted Hash that can be fed to #build_xml!
@@ -518,17 +621,26 @@ module Viewpoint::EWS::SOAP
518
621
  }
519
622
  end
520
623
 
624
+ def ews_types_builder
625
+ nbuild[NS_EWS_TYPES]
626
+ end
627
+
521
628
  def field_uRI(expr)
522
- nbuild[NS_EWS_TYPES].FieldURI('FieldURI' => expr[:field_uRI])
629
+ value = expr.is_a?(Hash) ? (expr[:field_uRI] || expr[:field_uri]) : expr
630
+ ews_types_builder.FieldURI('FieldURI' => value)
523
631
  end
524
632
 
633
+ alias_method :field_uri, :field_uRI
634
+
525
635
  def indexed_field_uRI(expr)
526
636
  nbuild[NS_EWS_TYPES].IndexedFieldURI(
527
- 'FieldURI' => expr[:field_uRI],
637
+ 'FieldURI' => (expr[:field_uRI] || expr[:field_uri]),
528
638
  'FieldIndex' => expr[:field_index]
529
639
  )
530
640
  end
531
641
 
642
+ alias_method :indexed_field_uri, :indexed_field_uRI
643
+
532
644
  def extended_field_uRI(expr)
533
645
  nbuild[NS_EWS_TYPES].ExtendedFieldURI {
534
646
  nbuild.parent['DistinguishedPropertySetId'] = expr[:distinguished_property_set_id] if expr[:distinguished_property_set_id]
@@ -540,6 +652,32 @@ module Viewpoint::EWS::SOAP
540
652
  }
541
653
  end
542
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
+
543
681
  def field_uRI_or_constant(expr)
544
682
  nbuild[NS_EWS_TYPES].FieldURIOrConstant {
545
683
  type = expr.keys.first
@@ -547,6 +685,8 @@ module Viewpoint::EWS::SOAP
547
685
  }
548
686
  end
549
687
 
688
+ alias_method :field_uri_or_constant, :field_uRI_or_constant
689
+
550
690
  def constant(expr)
551
691
  nbuild[NS_EWS_TYPES].Constant('Value' => expr[:value])
552
692
  end
@@ -554,14 +694,14 @@ module Viewpoint::EWS::SOAP
554
694
  # Build the CalendarView element
555
695
  def calendar_view!(cal_view)
556
696
  attribs = {}
557
- cal_view.each_pair {|k,v| attribs[k.to_s.camel_case] = v.to_s}
697
+ cal_view.each_pair {|k,v| attribs[camel_case(k)] = v.to_s}
558
698
  @nbuild[NS_EWS_MESSAGES].CalendarView(attribs)
559
699
  end
560
700
 
561
701
  # Build the ContactsView element
562
702
  def contacts_view!(con_view)
563
703
  attribs = {}
564
- con_view.each_pair {|k,v| attribs[k.to_s.camel_case] = v.to_s}
704
+ con_view.each_pair {|k,v| attribs[camel_case(k)] = v.to_s}
565
705
  @nbuild[NS_EWS_MESSAGES].ContactsView(attribs)
566
706
  end
567
707
 
@@ -569,7 +709,7 @@ module Viewpoint::EWS::SOAP
569
709
  def event_types!(evtypes)
570
710
  @nbuild[NS_EWS_TYPES].EventTypes {
571
711
  evtypes.each do |et|
572
- @nbuild[NS_EWS_TYPES].EventType(et.to_s.camel_case)
712
+ @nbuild[NS_EWS_TYPES].EventType(camel_case(et))
573
713
  end
574
714
  }
575
715
  end
@@ -673,6 +813,9 @@ module Viewpoint::EWS::SOAP
673
813
 
674
814
  def message!(item)
675
815
  nbuild[NS_EWS_TYPES].Message {
816
+ if item[:extended_properties]
817
+ extended_properties! item.delete(:extended_properties)
818
+ end
676
819
  item.each_pair {|k,v|
677
820
  self.send("#{k}!", v)
678
821
  }
@@ -687,6 +830,14 @@ module Viewpoint::EWS::SOAP
687
830
  }
688
831
  end
689
832
 
833
+ def task!(item)
834
+ nbuild[NS_EWS_TYPES].Task {
835
+ item.each_pair {|k,v|
836
+ self.send("#{k}!", v)
837
+ }
838
+ }
839
+ end
840
+
690
841
  def forward_item!(item)
691
842
  nbuild[NS_EWS_TYPES].ForwardItem {
692
843
  item.each_pair {|k,v|
@@ -722,6 +873,10 @@ module Viewpoint::EWS::SOAP
722
873
  nbuild[NS_EWS_TYPES].Subject(sub)
723
874
  end
724
875
 
876
+ def importance!(sub)
877
+ nbuild[NS_EWS_TYPES].Importance(sub)
878
+ end
879
+
725
880
  def body!(b)
726
881
  nbuild[NS_EWS_TYPES].Body(b[:text]) {|x|
727
882
  x.parent['BodyType'] = b[:body_type] if b[:body_type]
@@ -754,6 +909,12 @@ module Viewpoint::EWS::SOAP
754
909
  }
755
910
  end
756
911
 
912
+ def from!(f)
913
+ nbuild[NS_EWS_TYPES].From {
914
+ mailbox! f
915
+ }
916
+ end
917
+
757
918
  def required_attendees!(attendees)
758
919
  nbuild[NS_EWS_TYPES].RequiredAttendees {
759
920
  attendees.each {|a| attendee!(a[:attendee])}
@@ -772,10 +933,10 @@ module Viewpoint::EWS::SOAP
772
933
  }
773
934
  end
774
935
 
936
+ # @todo support ResponseType, LastResponseTime: http://msdn.microsoft.com/en-us/library/aa580339.aspx
775
937
  def attendee!(a)
776
938
  nbuild[NS_EWS_TYPES].Attendee {
777
939
  mailbox!(a[:mailbox])
778
- #@todo support ResponseType, LastResponseTime: http://msdn.microsoft.com/en-us/library/aa580339.aspx
779
940
  }
780
941
  end
781
942
 
@@ -787,6 +948,41 @@ module Viewpoint::EWS::SOAP
787
948
  nbuild[NS_EWS_TYPES].End(et[:text])
788
949
  end
789
950
 
951
+ def start_date!(sd)
952
+ nbuild[NS_EWS_TYPES].StartDate format_time(sd[:text])
953
+ end
954
+
955
+ def due_date!(dd)
956
+ nbuild[NS_EWS_TYPES].DueDate format_time(dd[:text])
957
+ end
958
+
959
+ def location!(loc)
960
+ nbuild[NS_EWS_TYPES].Location(loc)
961
+ end
962
+
963
+ def is_all_day_event!(all_day)
964
+ nbuild[NS_EWS_TYPES].IsAllDayEvent(all_day)
965
+ end
966
+
967
+ def reminder_is_set!(reminder)
968
+ nbuild[NS_EWS_TYPES].ReminderIsSet reminder
969
+ end
970
+
971
+ def reminder_due_by!(date)
972
+ nbuild[NS_EWS_TYPES].ReminderDueBy format_time(date)
973
+ end
974
+
975
+ def reminder_minutes_before_start!(minutes)
976
+ nbuild[NS_EWS_TYPES].ReminderMinutesBeforeStart minutes
977
+ end
978
+
979
+ # @see http://msdn.microsoft.com/en-us/library/aa566143(v=exchg.150).aspx
980
+ # possible values Exchange Server 2010 = [Free, Tentative, Busy, OOF, NoData]
981
+ # Exchange Server 2013 = [Free, Tentative, Busy, OOF, WorkingElsewhere, NoData]
982
+ def legacy_free_busy_status!(state)
983
+ nbuild[NS_EWS_TYPES].LegacyFreeBusyStatus(state)
984
+ end
985
+
790
986
  # @see http://msdn.microsoft.com/en-us/library/aa565428(v=exchg.140).aspx
791
987
  def item_changes!(changes)
792
988
  nbuild.ItemChanges {
@@ -830,9 +1026,9 @@ module Viewpoint::EWS::SOAP
830
1026
  uri = upd.select {|k,v| k =~ /_uri/i}
831
1027
  raise EwsBadArgumentError, "Bad argument given for SetItemField." if uri.keys.length != 1
832
1028
  upd.delete(uri.keys.first)
833
- @nbuild.SetItemField {
834
- dispatch_field_uri!(uri)
835
- dispatch_field_item!(upd)
1029
+ @nbuild[NS_EWS_TYPES].SetItemField {
1030
+ dispatch_field_uri!(uri, NS_EWS_TYPES)
1031
+ dispatch_field_item!(upd, NS_EWS_TYPES)
836
1032
  }
837
1033
  end
838
1034
 
@@ -840,8 +1036,8 @@ module Viewpoint::EWS::SOAP
840
1036
  def delete_item_field!(upd)
841
1037
  uri = upd.select {|k,v| k =~ /_uri/i}
842
1038
  raise EwsBadArgumentError, "Bad argument given for SetItemField." if uri.keys.length != 1
843
- @nbuild.DeleteItemField {
844
- dispatch_field_uri!(uri)
1039
+ @nbuild[NS_EWS_TYPES].DeleteItemField {
1040
+ dispatch_field_uri!(uri, NS_EWS_TYPES)
845
1041
  }
846
1042
  end
847
1043
 
@@ -850,17 +1046,26 @@ module Viewpoint::EWS::SOAP
850
1046
  @nbuild.ReturnNewItemIds(retval)
851
1047
  end
852
1048
 
1049
+ def inline_attachment!(fa)
1050
+ @nbuild[NS_EWS_TYPES].FileAttachment {
1051
+ @nbuild[NS_EWS_TYPES].Name(fa.name)
1052
+ @nbuild[NS_EWS_TYPES].ContentId(fa.name)
1053
+ @nbuild[NS_EWS_TYPES].IsInline(true)
1054
+ @nbuild[NS_EWS_TYPES].Content(fa.content)
1055
+ }
1056
+ end
1057
+
853
1058
  def file_attachment!(fa)
854
1059
  @nbuild[NS_EWS_TYPES].FileAttachment {
855
- @nbuild.Name(fa.name)
856
- @nbuild.Content(fa.content)
1060
+ @nbuild[NS_EWS_TYPES].Name(fa.name)
1061
+ @nbuild[NS_EWS_TYPES].Content(fa.content)
857
1062
  }
858
1063
  end
859
1064
 
860
1065
  def item_attachment!(ia)
861
1066
  @nbuild[NS_EWS_TYPES].ItemAttachment {
862
- @nbuild.Name(ia.name)
863
- @nbuild.Item {
1067
+ @nbuild[NS_EWS_TYPES].Name(ia.name)
1068
+ @nbuild[NS_EWS_TYPES].Item {
864
1069
  item_id!(ia.item)
865
1070
  }
866
1071
  }
@@ -949,21 +1154,25 @@ module Viewpoint::EWS::SOAP
949
1154
 
950
1155
  # A helper to dispatch to a FieldURI, IndexedFieldURI, or an ExtendedFieldURI
951
1156
  # @todo Implement ExtendedFieldURI
952
- def dispatch_field_uri!(uri)
1157
+ def dispatch_field_uri!(uri, ns=NS_EWS_MESSAGES)
953
1158
  type = uri.keys.first
954
1159
  vals = uri[type].is_a?(Array) ? uri[type] : [uri[type]]
955
1160
  case type
956
1161
  when :field_uRI, :field_uri
957
1162
  vals.each do |val|
958
- nbuild.FieldURI('FieldURI' => val[:field_uRI])
1163
+ value = val.is_a?(Hash) ? val[type] : val
1164
+ nbuild[ns].FieldURI('FieldURI' => value)
959
1165
  end
960
1166
  when :indexed_field_uRI, :indexed_field_uri
961
1167
  vals.each do |val|
962
- nbuild.IndexedFieldURI('FieldURI' => val[:field_uRI], 'FieldIndex' => val[:field_index])
1168
+ nbuild[ns].IndexedFieldURI(
1169
+ 'FieldURI' => (val[:field_uRI] || val[:field_uri]),
1170
+ 'FieldIndex' => val[:field_index]
1171
+ )
963
1172
  end
964
1173
  when :extended_field_uRI, :extended_field_uri
965
1174
  vals.each do |val|
966
- nbuild.ExtendedFieldURI {
1175
+ nbuild[ns].ExtendedFieldURI {
967
1176
  nbuild.parent['DistinguishedPropertySetId'] = val[:distinguished_property_set_id] if val[:distinguished_property_set_id]
968
1177
  nbuild.parent['PropertySetId'] = val[:property_set_id] if val[:property_set_id]
969
1178
  nbuild.parent['PropertyTag'] = val[:property_tag] if val[:property_tag]
@@ -975,13 +1184,24 @@ module Viewpoint::EWS::SOAP
975
1184
  else
976
1185
  raise EwsBadArgumentError, "Bad URI type. #{type}"
977
1186
  end
978
-
979
1187
  end
980
1188
 
981
- def dispatch_field_item!(item)
1189
+ # Insert item, enforce xmlns attribute if prefix is present
1190
+ def dispatch_field_item!(item, ns_prefix = nil)
1191
+ item.values.first[:xmlns_attribute] = ns_prefix if ns_prefix
982
1192
  build_xml!(item)
983
1193
  end
984
1194
 
1195
+ def room_list!(cfg_prop)
1196
+ @nbuild[NS_EWS_MESSAGES].RoomList {
1197
+ email_address!(cfg_prop)
1198
+ }
1199
+ end
1200
+
1201
+ def room_lists!
1202
+ @nbuild[NS_EWS_MESSAGES].GetRoomLists
1203
+ end
1204
+
985
1205
 
986
1206
  private
987
1207
 
@@ -997,6 +1217,26 @@ private
997
1217
  end
998
1218
  end
999
1219
 
1220
+ def set_impersonation!(type, address)
1221
+ if type && type != ""
1222
+ nbuild[NS_EWS_TYPES].ExchangeImpersonation {
1223
+ nbuild[NS_EWS_TYPES].ConnectingSID {
1224
+ nbuild[NS_EWS_TYPES].method_missing type, address
1225
+ }
1226
+ }
1227
+ end
1228
+ end
1229
+
1230
+ # Set TimeZoneContext Header
1231
+ # @param time_zone_def [Hash] !{id: time_zone_identifier, name: time_zone_name}
1232
+ def set_time_zone_context_header!(time_zone_def)
1233
+ if time_zone_def
1234
+ nbuild[NS_EWS_TYPES].TimeZoneContext do
1235
+ time_zone_definition! time_zone_def
1236
+ end
1237
+ end
1238
+ end
1239
+
1000
1240
  # some methods need special naming so they use the '_r' suffix like 'and'
1001
1241
  def normalize_type(type)
1002
1242
  case type
@@ -1007,5 +1247,20 @@ private
1007
1247
  end
1008
1248
  end
1009
1249
 
1250
+ def format_time(time)
1251
+ case time
1252
+ when Time, Date, DateTime
1253
+ time.to_datetime.new_offset(0).iso8601
1254
+ when String
1255
+ begin
1256
+ DateTime.parse(time).new_offset(0).iso8601
1257
+ rescue ArgumentError
1258
+ raise EwsBadArgumentError, "Invalid Time argument (#{time})"
1259
+ end
1260
+ else
1261
+ raise EwsBadArgumentError, "Invalid Time argument (#{time})"
1262
+ end
1263
+ end
1264
+
1010
1265
  end # EwsBuilder
1011
1266
  end # Viewpoint::EWS::SOAP