viewpoint 0.0.5 → 0.1.0

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 (59) hide show
  1. data/README +84 -45
  2. data/Rakefile +7 -5
  3. data/TODO +6 -0
  4. data/VERSION +1 -1
  5. data/lib/exceptions/exceptions.rb +34 -0
  6. data/lib/extensions/string.rb +37 -0
  7. data/lib/model/calendar_folder.rb +45 -0
  8. data/lib/model/calendar_item.rb +145 -0
  9. data/lib/model/contact.rb +58 -0
  10. data/lib/model/contacts_folder.rb +35 -0
  11. data/lib/model/distribution_list.rb +26 -0
  12. data/lib/model/event.rb +118 -0
  13. data/lib/model/folder.rb +36 -0
  14. data/lib/model/generic_folder.rb +302 -0
  15. data/lib/model/item.rb +126 -0
  16. data/lib/model/mailbox_user.rb +107 -0
  17. data/lib/model/meeting_cancellation.rb +28 -0
  18. data/lib/{viewpoint/errors.rb → model/meeting_message.rb} +10 -14
  19. data/lib/model/meeting_request.rb +26 -0
  20. data/lib/model/meeting_response.rb +26 -0
  21. data/lib/model/message.rb +73 -0
  22. data/lib/model/model.rb +161 -0
  23. data/lib/model/search_folder.rb +36 -0
  24. data/lib/model/task.rb +62 -0
  25. data/lib/model/task_list.rb +19 -0
  26. data/lib/model/tasks_folder.rb +33 -0
  27. data/lib/soap/handsoap/builder.rb +22 -0
  28. data/lib/soap/handsoap/builders/ews_build_helpers.rb +317 -0
  29. data/lib/soap/handsoap/builders/ews_builder.rb +86 -0
  30. data/lib/soap/handsoap/ews_service.rb +646 -0
  31. data/lib/soap/handsoap/parser.rb +106 -0
  32. data/lib/soap/handsoap/parsers/ews_parser.rb +165 -0
  33. data/lib/soap/soap_provider.rb +75 -0
  34. data/lib/viewpoint.rb +98 -3
  35. data/preamble +1 -1
  36. data/test/spec/basic_functions.spec +51 -0
  37. data/test/spec/folder_subscriptions.spec +35 -0
  38. data/test/spec/folder_synchronization.spec +28 -0
  39. data/utils/ewsWSDL2rb.rb +29 -0
  40. metadata +101 -43
  41. data/lib/exchwebserv.rb +0 -6
  42. data/lib/soap/viewpoint.conf +0 -3
  43. data/lib/viewpoint/calendar.rb +0 -128
  44. data/lib/viewpoint/calendar_item.rb +0 -118
  45. data/lib/viewpoint/event.rb +0 -0
  46. data/lib/viewpoint/exchange_headers.rb +0 -49
  47. data/lib/viewpoint/exchwebserv.rb +0 -236
  48. data/lib/viewpoint/folder.rb +0 -358
  49. data/lib/viewpoint/item.rb +0 -101
  50. data/lib/viewpoint/mail.rb +0 -117
  51. data/lib/viewpoint/message.rb +0 -132
  52. data/lib/viewpoint/task.rb +0 -0
  53. data/lib/viewpoint/tasks.rb +0 -0
  54. data/lib/wsdl/defaultMappingRegistry.rb +0 -10680
  55. data/lib/wsdl/exchangeServiceBinding.rb +0 -349
  56. data/lib/wsdl/exchangeServiceTypes.rb +0 -11013
  57. data/test/spec/basic_features_spec.rb +0 -37
  58. data/test/test_client.rb +0 -13
  59. data/test/testrestrict.rb +0 -75
@@ -1,118 +0,0 @@
1
- #############################################################################
2
- # Copyright © 2009 Dan Wanek <dan.wanek@gmail.com>
3
- #
4
- #
5
- # This file is part of Viewpoint.
6
- #
7
- # Viewpoint is free software: you can redistribute it and/or
8
- # modify it under the terms of the GNU General Public License as published
9
- # by the Free Software Foundation, either version 3 of the License, or (at
10
- # your option) any later version.
11
- #
12
- # Viewpoint is distributed in the hope that it will be useful,
13
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
15
- # Public License for more details.
16
- #
17
- # You should have received a copy of the GNU General Public License along
18
- # with Viewpoint. If not, see <http://www.gnu.org/licenses/>.
19
- #############################################################################
20
- $:.unshift(File.dirname(__FILE__))
21
- require 'rubygems'
22
- require 'icalendar'
23
- require 'item'
24
-
25
- class Viewpoint::CalendarItem < Viewpoint::Item
26
- include Viewpoint
27
-
28
- attr_reader :subject, :organizer, :location, :start, :end, :cal_item_type
29
-
30
- # Initialize an Exchange Web Services item
31
- def initialize(ews_item, parent_folder)
32
- raise InvalidEWSItemError if ews_item.nil?
33
-
34
- @subject = ews_item.subject # String
35
- @location = ews_item.location if ews_item.location
36
- @cal_item_type = ews_item.calendarItemType
37
- @organizer = ews_item.organizer.mailbox.name if ews_item.organizer and ews_item.organizer.mailbox # String
38
- @start = ews_item.start if ews_item.start # DateTime
39
- @end = ews_item.v_end if ews_item.v_end # DateTime
40
- @busy_status = ews_item.legacyFreeBusyStatus if ews_item.legacyFreeBusyStatus # String
41
- @date_time_recieved = ews_item.dateTimeReceived if ews_item.dateTimeReceived # DateTime
42
-
43
- # This is where the event object gets loaded if it
44
- # is requested. Think of it like IMAP downloading the
45
- # body when the message is viewed.
46
- @message = nil
47
-
48
- super(ews_item, parent_folder)
49
- end
50
-
51
-
52
- def body
53
- get_calitem if @message == nil
54
- @message.body
55
- end
56
-
57
- def sender
58
- @organizer
59
- end
60
-
61
-
62
- # Convert item to iCal format: http://www.ietf.org/rfc/rfc2445.txt
63
- # Returns Icalendar::Event object
64
- def to_ical_event
65
- get_calitem if @message == nil
66
- iev = Icalendar::Event.new
67
- iev.uid = @message.uID
68
- unless(@message.organizer == nil)
69
- iev.organizer = "CN=\"#{@message.organizer.mailbox.name}\"" if @message.organizer.mailbox.name
70
- iev.organizer += ":MAILTO:#{@message.organizer.mailbox.emailAddress}" if @message.organizer.mailbox.emailAddress
71
- end
72
- # TODO: Handle EWS Timezones better. TZ_HASH in viewpoint.rb is the start of this
73
- require 'time'
74
- #tzoffset = @message.timeZone.sub(/^\(GMT([^\)]+)\).*$/,'\1')
75
- dtstart = Time.at(@message.start.strftime('%s').to_i)
76
- dtend = Time.at(@message.v_end.strftime('%s').to_i)
77
- dtstamp = Time.at(@message.dateTimeStamp.strftime('%s').to_i)
78
- last_modified = Time.at(@message.lastModifiedTime.strftime('%s').to_i)
79
- timestr = "%Y%m%dT%H%M%S"
80
- iev.dtstart = dtstart.strftime(timestr)
81
- iev.dtend = dtend.strftime(timestr)
82
- iev.tzid = dtstart.strftime('%Z')
83
- iev.dtstamp = dtstamp.strftime(timestr)
84
- iev.last_modified = last_modified.strftime(timestr)
85
- iev.location = @message.location if @message.location
86
- iev.klass = @message.sensitivity if @message.sensitivity
87
- iev.summary = @message.subject if @message.subject
88
- iev.description = @message.body if @message.body
89
- iev.transp = @message.legacyFreeBusyStatus if @message.legacyFreeBusyStatus
90
- iev.duration = @message.duration if @message.duration
91
- iev.sequence = @message.appointmentSequenceNumber if @message.appointmentSequenceNumber
92
- iev.status = @message.myResponseType if @message.myResponseType
93
- #iev.attach @message.attachments if @message.hasAttachments
94
- @message.requiredAttendees.each do |pers|
95
- output = "ROLE=REQ-PARTICIPANT;CN=\"#{pers.mailbox.name}\"" if pers.mailbox.respond_to?(:name)
96
- output += ":MAILTO:#{pers.mailbox.emailAddress}" if pers.mailbox.respond_to?(:emailAddress)
97
- iev.attendees << output if output
98
- end if @message.requiredAttendees
99
- @message.optionalAttendees.each do |pers|
100
- output = "ROLE=OPT-PARTICIPANT;CN=\"#{pers.mailbox.name}\"" if pers.mailbox.respond_to?(:name)
101
- output += ":MAILTO:#{pers.mailbox.emailAddress}" if pers.mailbox.respond_to?(:emailAddress)
102
- iev.attendees << output if output
103
- end if @message.optionalAttendees
104
-
105
- #iev.categories = @message.categories if @message.categories
106
- #iev.resources = @message.resources if @message.resources
107
- return iev
108
- end
109
-
110
-
111
- # These methods are marked 'private' because they return EWS Types and I am trying to
112
- # hide those because they are not elegant and a bit too tedious for the public interface.
113
- private
114
-
115
- def get_calitem
116
- @message = @parent_folder.get_item(@item_id)
117
- end
118
- end
File without changes
@@ -1,49 +0,0 @@
1
- #############################################################################
2
- # Copyright © 2009 Dan Wanek <dan.wanek@gmail.com>
3
- #
4
- #
5
- # This file is part of Viewpoint.
6
- #
7
- # Viewpoint is free software: you can redistribute it and/or
8
- # modify it under the terms of the GNU General Public License as published
9
- # by the Free Software Foundation, either version 3 of the License, or (at
10
- # your option) any later version.
11
- #
12
- # Viewpoint is distributed in the hope that it will be useful,
13
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
15
- # Public License for more details.
16
- #
17
- # You should have received a copy of the GNU General Public License along
18
- # with Viewpoint. If not, see <http://www.gnu.org/licenses/>.
19
- #############################################################################
20
- require 'rubygems'
21
- gem 'soap4r'
22
- require 'soap/header/simplehandler'
23
-
24
-
25
- # Some functionality of EWS depends on setting the "RequestServerVersion"
26
- # element with a specified "Version" attribute. That is all this class
27
- # is doing.
28
- # It is used during the initial connection process by setting the
29
- # headerhandler in the serivce binding.
30
- # *<tt>@exchange.headerhandler << ExchangeHeaders.new</tt>
31
- class Viewpoint::ExchangeHeaders < SOAP::Header::SimpleHandler
32
- NAMESPACE = 'http://schemas.microsoft.com/exchange/services/2006/types'
33
-
34
- def initialize
35
- @qname = XSD::QName.new(NAMESPACE,"RequestServerVersion")
36
- super(@qname)
37
- end
38
-
39
- def on_simple_outbound
40
- {
41
- "xmlattr_Version" => "Exchange2007_SP1"
42
- }
43
- end
44
-
45
- def on_outbound
46
- h = on_simple_outbound
47
- h ? SOAP::SOAPElement.from_obj(h, nil) : nil
48
- end
49
- end
@@ -1,236 +0,0 @@
1
- #############################################################################
2
- # Copyright © 2009 Dan Wanek <dan.wanek@gmail.com>
3
- #
4
- #
5
- # This file is part of Viewpoint.
6
- #
7
- # Viewpoint is free software: you can redistribute it and/or
8
- # modify it under the terms of the GNU General Public License as published
9
- # by the Free Software Foundation, either version 3 of the License, or (at
10
- # your option) any later version.
11
- #
12
- # Viewpoint is distributed in the hope that it will be useful,
13
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
15
- # Public License for more details.
16
- #
17
- # You should have received a copy of the GNU General Public License along
18
- # with Viewpoint. If not, see <http://www.gnu.org/licenses/>.
19
- #############################################################################
20
- $:.unshift(File.dirname(__FILE__))
21
- require 'rubygems'
22
- require 'singleton'
23
- require 'wsdl/exchangeServiceBinding'
24
- # --- Custom libs ---
25
- require 'exchange_headers'
26
- # --- Folder Types ---
27
- require 'folder'
28
- require 'calendar'
29
- require 'mail'
30
-
31
- # This class will act as the controller for a client connection to the
32
- # Exchange web service.
33
- class Viewpoint::ExchWebServ
34
- include Viewpoint
35
- include Singleton
36
-
37
- attr_reader :ews, :user, :authenticated, :email
38
-
39
- def initialize
40
- @authenticated = false
41
- @user = nil
42
- @pass = nil
43
- @email = nil
44
- @ews_endpoint = nil
45
-
46
- # Connection to Exchange web services.
47
- # You can get fetch this from an accessor later.
48
- @ews = nil
49
-
50
- # Stores folders returned from 'find_folders'
51
- @folders = {}
52
-
53
- # Do initial authentication
54
- #do_auth
55
- end
56
-
57
-
58
- # Finds all folders and returns a hash of FolderTypes
59
- def find_folders
60
- ff = FindFolderType.new()
61
- ff.xmlattr_Traversal = FolderQueryTraversalType::Deep
62
- ff.folderShape = FolderResponseShapeType.new( DefaultShapeNamesType::AllProperties )
63
- fid = NonEmptyArrayOfBaseFolderIdsType.new()
64
- fidt = DistinguishedFolderIdType.new
65
- fidt.xmlattr_Id = DistinguishedFolderIdNameType::Root
66
- fid.distinguishedFolderId = fidt
67
- ff.parentFolderIds = fid
68
-
69
- # FindFolderResponseType
70
- resp = @ews.findFolder(ff)
71
-
72
- # ArrayOfResponseMessagesType
73
- msgs = resp.responseMessages
74
-
75
- # Array of FindFolderResponseMessageType
76
- msgs.findFolderResponseMessage.each do |elem|
77
- # Mail Folders
78
- mail_folders = {}
79
- elem.rootFolder.folders.folder.each do |folder|
80
- if( folder.folderClass != nil)
81
- mail_folders[folder.displayName] = MailFolder.new(folder)
82
- end
83
- end
84
- @folders['MailFolder'] = mail_folders
85
-
86
- # CalendarFolderType
87
- cal_folders = {}
88
- elem.rootFolder.folders.calendarFolder.each do |folder|
89
- cal_folders[folder.displayName] = CalendarFolder.new(folder)
90
- end
91
- @folders['CalendarFolder'] = cal_folders
92
-
93
- #elem.rootFolder.folders.contactsFolder.each do |folder|
94
- #end
95
- #elem.rootFolder.folders.searchFolder.each do |folder|
96
- #end
97
- #elem.rootFolder.folders.tasksFolder.each do |folder|
98
- #end
99
- end
100
- return @folders
101
- end
102
-
103
- # Return folder
104
- # The default is to return a folder that is a subclass of Folder from the
105
- # SqliteDB, but if fetch_from_ews is set to true it will go out and return
106
- # the FolderType object from EWS.
107
- # Parameters:
108
- # folder_ids: NonEmptyArrayOfBaseFolderIdsType or String if fetch_from_ews is not set
109
- # fetch_from_ews: boolean
110
- # folder_shape: DefaultShapeNamesType
111
- def get_folder(folder_ids, fetch_from_ews = false, folder_shape = DefaultShapeNamesType::AllProperties)
112
- unless fetch_from_ews
113
- return @folders['MailFolder'][folder_ids] ||
114
- @folders['CalendarFolder'][folder_ids]
115
- end
116
-
117
- folder_shape = FolderResponseShapeType.new( folder_shape )
118
- get_folder = GetFolderType.new(folder_shape, folder_ids)
119
-
120
- resp = @ews.getFolder(get_folder).responseMessages.getFolderResponseMessage[0].folders.folder[0]
121
- end
122
-
123
- # Parameters:
124
- # display_name: String
125
- # fetch_from_ews: boolean
126
- # folder_shape: DefaultShapeNamesType
127
- def get_folder_by_name(display_name, fetch_from_ews = true, folder_shape = DefaultShapeNamesType::AllProperties)
128
- #folder_ids = NonEmptyArrayOfBaseFolderIdsType.new()
129
- dist_name = DistinguishedFolderIdType.new
130
- dist_name.xmlattr_Id = DistinguishedFolderIdNameType.new(display_name.downcase)
131
- #folder_ids.distinguishedFolderId = dist_name
132
- folder_ids = NonEmptyArrayOfBaseFolderIdsType.new(nil, [dist_name])
133
-
134
- get_folder(folder_ids, true, folder_shape)
135
- end
136
-
137
- # Parameters:
138
- # folder_id: String
139
- # change_key: String
140
- # folder_shape: DefaultShapeNamesType
141
- def get_folder_by_id(folder_id, change_key = nil, fetch_from_ews = true, folder_shape = DefaultShapeNamesType::AllProperties)
142
- folder_ids = NonEmptyArrayOfBaseFolderIdsType.new()
143
- folder_id_t = FolderIdType.new
144
- folder_id_t.xmlattr_Id = folder_id
145
- folder_id_t.xmlattr_ChangeKey = change_key unless change_key == nil
146
- folder_ids.folderId = folder_id
147
- folder_ids = NonEmptyArrayOfBaseFolderIdsType.new([folder_id_t], nil)
148
-
149
- get_folder(folder_ids, true, folder_shape)
150
- end
151
-
152
- def get_mail_folders
153
- return @folders['MailFolder']
154
- end
155
-
156
- def get_calendar_folders
157
- return @folders['CalendarFolder']
158
- end
159
-
160
- def authenticate(user = nil, pass = nil, endpoint = nil)
161
- unless @authenticated
162
- @user = user
163
- @pass = pass
164
- @ews_endpoint = endpoint
165
- do_auth unless @authenticated
166
- end
167
- @authenticated
168
- end
169
-
170
-
171
- # Resolve a Contact name.
172
- # More info: http://msdn.microsoft.com/en-us/library/aa563518.aspx
173
- def resolve_name(unresolved_entry, full_contact_data = false)
174
- rn_t = ResolveNamesType.new(nil,unresolved_entry)
175
- rn_t.xmlattr_ReturnFullContactData = full_contact_data
176
- ews.resolveNames(rn_t).responseMessages.resolveNamesResponseMessage.first
177
- end
178
-
179
- private
180
- def do_auth
181
- retry_count = 0
182
- begin
183
- if( File.exists?("#{ENV['HOME']}/.viewpointrc") )
184
- props = SOAP::Property.load(File.new("#{ENV['HOME']}/.viewpointrc"))
185
- @user = props['exchange.ews.user'] if @user == nil
186
- @pass = props['exchange.ews.pass'] if @pass == nil
187
- @ews_endpoint = props['exchange.ews.endpoint'] if @ews_endpoint == nil
188
- elsif( File.exists?("#{File.dirname(__FILE__)}/soap/viewpoint.conf") )
189
- props = SOAP::Property.load(File.new("#{File.dirname(__FILE__)}/soap/viewpoint.conf"))
190
- @user = props['exchange.ews.user'] if @user == nil
191
- @pass = props['exchange.ews.pass'] if @pass == nil
192
- @ews_endpoint = props['exchange.ews.endpoint'] if @ews_endpoint == nil
193
- elsif(@ews_endpoint == nil && @user == nil && @pass == nil)
194
- require 'highline/import'
195
- @ews_endpoint = ask("Exchange EWS Endpoint: ") { |q| q.echo = true }
196
- @user = ask("User: ") { |q| q.echo = true }
197
- @pass = ask("Pass: ") { |q| q.echo = "*"}
198
- else
199
- # Nothing to do
200
- end
201
-
202
- @ews = ExchangeServiceBinding.new(@ews_endpoint)
203
- @ews.options["protocol.http.auth.ntlm"] = [@ews_endpoint.sub(/\/[^\/]+$/,'/'),@user,@pass]
204
- @ews.headerhandler << ExchangeHeaders.new
205
-
206
- # Log SOAP request and response for debugging. Run ruby with the '-d' option.
207
- if($DEBUG) then
208
- @ews.wiredump_file_base = "viewpoint-soaplog"
209
- end
210
-
211
- # Do a ResolveNames operation to make sure that authentication works.
212
- # If you don't do an operation, you won't find out that bad credentials
213
- # were entered until later. The ResolveNames operation is completely
214
- # arbitrary and could be any EWS call.
215
- # http://msdn.microsoft.com/en-us/library/bb409286.aspx
216
- resp = resolve_name(@user + '@')
217
- # Set email while we're at it
218
- @email = resp.resolutionSet.resolution.first.mailbox.emailAddress
219
-
220
- rescue SOAP::HTTPStreamError
221
- puts "Bad Login! Try Again."
222
- if( retry_count < 2)
223
- retry_count += 1
224
- retry
225
- else
226
- puts "-----------------------------------------------------------"
227
- puts "Could not log into Exchange Web Services. Make sure your information is correct"
228
- puts "End Point: #{@ews_endpoint}"
229
- puts "User: #{@user}"
230
- puts "-----------------------------------------------------------"
231
- return
232
- end
233
- end
234
- @authenticated = true
235
- end
236
- end
@@ -1,358 +0,0 @@
1
- #############################################################################
2
- # Copyright © 2009 Dan Wanek <dan.wanek@gmail.com>
3
- #
4
- #
5
- # This file is part of Viewpoint.
6
- #
7
- # Viewpoint is free software: you can redistribute it and/or
8
- # modify it under the terms of the GNU General Public License as published
9
- # by the Free Software Foundation, either version 3 of the License, or (at
10
- # your option) any later version.
11
- #
12
- # Viewpoint is distributed in the hope that it will be useful,
13
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
15
- # Public License for more details.
16
- #
17
- # You should have received a copy of the GNU General Public License along
18
- # with Viewpoint. If not, see <http://www.gnu.org/licenses/>.
19
- #############################################################################
20
- require 'rubygems'
21
-
22
- # This class is inherited by all folder subtypes such as Mail, Calendar,
23
- # Tasks and Search. It will serve as the brain for all of the methods that
24
- # each of these folder types have in common.
25
- class Viewpoint::Folder
26
- include Viewpoint
27
-
28
- attr_accessor :folder_id, :parent_id, :display_name
29
- def initialize(folder)
30
- @folder_id = folder.folderId.xmlattr_Id
31
- @parent_id = folder.parentFolderId.xmlattr_Id unless folder.parentFolderId == nil
32
- @display_name = folder.displayName
33
- @sync_state = nil
34
- @subscription_id = nil
35
- @watermark = nil
36
- end
37
-
38
- # Subscribe to folder and save the subscription_id into the database. Subsequent calls
39
- # to check_subscription will use that id.
40
- # Returns true if the operation is successful, false otherwise
41
- def subscribe
42
- # Refresh the subscription if already subscribed
43
- if( subscribed? )
44
- unsubscribe
45
- end
46
- subscribe = SubscribeType.new
47
- pull = PullSubscriptionRequestType.new
48
-
49
- # Set-up folder Id
50
- f_id_t = FolderIdType.new
51
- f_id_t.xmlattr_Id = @folder_id
52
- f_ids = NonEmptyArrayOfBaseFolderIdsType.new([f_id_t],nil)
53
- pull.folderIds = f_ids
54
-
55
- # Set-up event types
56
- event_types = NonEmptyArrayOfNotificationEventTypesType.new
57
- event_types.push(NotificationEventTypeType::CopiedEvent)
58
- event_types.push(NotificationEventTypeType::CreatedEvent)
59
- event_types.push(NotificationEventTypeType::DeletedEvent)
60
- event_types.push(NotificationEventTypeType::ModifiedEvent)
61
- event_types.push(NotificationEventTypeType::MovedEvent)
62
- event_types.push(NotificationEventTypeType::NewMailEvent)
63
- pull.eventTypes = event_types
64
-
65
- pull.timeout = 10
66
-
67
- subscribe.pullSubscriptionRequest = pull
68
-
69
- resp = ExchWebServ.instance.ews.subscribe(subscribe).responseMessages.subscribeResponseMessage.first
70
- @subscription_id = resp.subscriptionId
71
- @watermark = resp.watermark
72
-
73
- return (resp.responseCode == "NoError")? true: false
74
- end
75
-
76
- def subscribed?
77
- ( @subscription_id.nil? or @watermark.nil? )? false : true
78
- end
79
-
80
-
81
- # unsubscribe from folder
82
- # Returns true if unsubscription succeeds, false otherwise
83
- def unsubscribe
84
- begin
85
- if( @subscription_id == nil ) then
86
- return true
87
- end
88
-
89
- unsub_t = UnsubscribeType.new(@subscription_id)
90
- resp = ExchWebServ.instance.ews.unsubscribe(unsub_t).responseMessages.unsubscribeResponseMessage.first
91
-
92
- return (resp.responseCode == "NoError")? true: false
93
- end
94
- end
95
-
96
-
97
- # Fetch events with the subscription_id. If one does not exists or is expired,
98
- # call subscribe.
99
- # Returns a hash with the event type as the key and an Array of Hashes that
100
- # represent each event's data
101
- # An :error key is set if there is a problem
102
- def check_subscription
103
- begin
104
- if( @subscription_id == nil or @watermark == nil) then
105
- self.subscribe
106
- end
107
- ge = GetEventsType.new(@subscription_id, @watermark)
108
-
109
- resp = ExchWebServ.instance.ews.getEvents(ge).responseMessages.getEventsResponseMessage
110
-
111
- #TODO: Add more event processing
112
-
113
-
114
- notifications = resp.first.notification
115
-
116
- notif_hash = {}
117
- # Process Notifications
118
- if( notifications.copiedEvent != nil)
119
- notif_hash[:copiedEvent] = []
120
- notifications.copiedEvent.each do |note|
121
- @watermark = note.watermark
122
- item = {}
123
- item.store(:old_item_id,note.oldItemId.xmlattr_Id) if note.itemId
124
- item.store(:old_folder_id,note.oldParentFolderId.xmlattr_Id) if note.oldParentFolderId
125
- item.store(:item_id,note.itemId.xmlattr_Id) if note.itemId
126
- item.store(:folder_id,note.parentFolderId.xmlattr_Id) if note.parentFolderId
127
- notif_hash[:copiedEvent] << item
128
- end
129
- end
130
-
131
- if( notifications.createdEvent != nil)
132
- notif_hash[:createdEvent] = []
133
- notifications.createdEvent.each do |note|
134
- @watermark = note.watermark
135
- item = {}
136
- item.store(:item_id,note.itemId.xmlattr_Id) if note.itemId
137
- item.store(:folder_id,note.parentFolderId.xmlattr_Id) if note.parentFolderId
138
- notif_hash[:createdEvent] << item
139
- end
140
- end
141
-
142
- if( notifications.deletedEvent != nil)
143
- notif_hash[:deletedEvent] = []
144
- notifications.deletedEvent.each do |note|
145
- @watermark = note.watermark
146
- item = {}
147
- item.store(:item_id,note.itemId.xmlattr_Id) if note.itemId
148
- item.store(:folder_id,note.parentFolderId.xmlattr_Id) if note.parentFolderId
149
- notif_hash[:deletedEvent] << item
150
- end
151
- end
152
-
153
- if( notifications.modifiedEvent != nil)
154
- notif_hash[:modifiedEvent] = []
155
- notifications.modifiedEvent.each do |note|
156
- @watermark = note.watermark
157
- item = {}
158
- item.store(:item_id,note.itemId.xmlattr_Id) if note.itemId
159
- item.store(:folder_id,note.folderId.xmlattr_Id) if note.folderId
160
- item.store(:parent_folder_id,note.parentFolderId.xmlattr_Id) if note.parentFolderId
161
- item.store(:unreadCount,note.unreadCount)
162
- notif_hash[:modifiedEvent] << item
163
- end
164
- end
165
-
166
- if( notifications.movedEvent != nil)
167
- notif_hash[:movedEvent] = []
168
- notifications.movedEvent.each do |note|
169
- @watermark = note.watermark
170
- item = {}
171
- item.store(:old_item_id,note.oldItemId.xmlattr_Id) if note.oldItemId
172
- item.store(:old_folder_id,note.oldParentFolderId.xmlattr_Id) if note.oldParentFolderId
173
- item.store(:item_id,note.itemId.xmlattr_Id) if note.itemId
174
- item.store(:folder_id,note.parentFolderId.xmlattr_Id) if note.parentFolderId
175
- notif_hash[:movedEvent] << item
176
- end
177
- end
178
-
179
- if( notifications.newMailEvent!= nil)
180
- notif_hash[:newMailEvent] = []
181
- notifications.newMailEvent.each do |note|
182
- @watermark = note.watermark
183
- item = {}
184
- item.store(:item_id,note.itemId.xmlattr_Id) if note.itemId
185
- item.store(:folder_id,note.parentFolderId.xmlattr_Id) if note.parentFolderId
186
- notif_hash[:newMailEvent] << item
187
- end
188
- end
189
-
190
- if( notifications.statusEvent != nil)
191
- notifications.statusEvent.each do |note|
192
- @watermark = note.watermark
193
- end
194
- end
195
-
196
- rescue NoMethodError
197
- # This ocurrs if something bad happened to the subscription.
198
- # This is handled by resubscribing to the subscription and returning
199
- # an error key.
200
- self.subscribe
201
- return {:error => "Something bad happened to your subscription. You have been re-subscribed" }
202
- end
203
-
204
- #return resp
205
- notif_hash[:resp] = resp
206
- return notif_hash
207
- end
208
-
209
-
210
- # This is a proxy for the SyncFolderItems operation detailed here: http://msdn.microsoft.com/en-us/library/aa563967.aspx
211
- # It returns a SyncFolderItemsResponseType object
212
- def sync_folder(max_items = 256)
213
- begin
214
- # ItemResponseShapeType
215
- itemshapeT = ItemResponseShapeType.new(DefaultShapeNamesType::IdOnly, false)
216
-
217
- # TargetFolderIdType
218
- tfolderidT = TargetFolderIdType.new
219
- folderidT = FolderIdType.new
220
- folderidT.xmlattr_Id = self.folder_id
221
- tfolderidT.folderId = folderidT
222
-
223
- # SyncFolderItemsType
224
- syncitemsT = SyncFolderItemsType.new(itemshapeT,tfolderidT,self.sync_state,nil,max_items)
225
-
226
- # Call Sync => returns SyncFolderItemsResponseType
227
- resp = ExchWebServ.instance.ews.syncFolderItems(syncitemsT).responseMessages.syncFolderItemsResponseMessage[0]
228
- @sync_state = resp.syncState
229
- return resp
230
- rescue
231
- puts "** Something happened during synchronizing folder => #{self.display_name}"
232
- raise
233
- end
234
- end
235
-
236
-
237
- # Wrapper around EWS's FindItem method: http://msdn.microsoft.com/en-us/library/aa566107.aspx
238
- # The specifics of this method should be set up in the child classes and then this method should
239
- # be called with a parameter of FindItemType: http://msdn.microsoft.com/en-us/library/aa566370.aspx
240
- # This allows for a central place of error handling. See Calendar::get_events for an example
241
- # of how this works.
242
- def find_items(find_item_t)
243
- # FindItemResponseMessageType: http://msdn.microsoft.com/en-us/library/aa566424.aspx
244
- resp = ExchWebServ.instance.ews.findItem(find_item_t).responseMessages.findItemResponseMessage[0]
245
-
246
- #TODO: Error handling
247
- if resp.xmlattr_ResponseClass == "Success"
248
- return resp
249
- else
250
- return nil
251
- end
252
- end
253
-
254
-
255
- # Fetch item by item_id
256
- # Params: item_id: ItemIdType
257
- # item_type: String (message, calendarItem)
258
- # all_props: boolean; default is to get just the Default props
259
- # Returns: a Item type of some sort ( depends on 'item_type' parameter )
260
- def get_item(item_id, item_type = nil, all_props = false)
261
- get_item = GetItemType.new
262
-
263
- if all_props
264
- shape_name = DefaultShapeNamesType::AllProperties
265
- else
266
- shape_name = DefaultShapeNamesType::Default
267
- end
268
-
269
- item_shape = ItemResponseShapeType.new( shape_name, false, BodyTypeResponseType::Text )
270
-
271
- #additional_props = NonEmptyArrayOfPathsToElementType.new
272
- #prop_a = PathToUnindexedFieldType.new
273
- #prop_b = PathToUnindexedFieldType.new
274
- #prop_c = PathToUnindexedFieldType.new
275
- #prop_d = PathToUnindexedFieldType.new
276
- #prop_a.xmlattr_FieldURI = UnindexedFieldURIType::CalendarMeetingTimeZone
277
- #prop_b.xmlattr_FieldURI = UnindexedFieldURIType.new("calendar:EndTimeZone")
278
- #prop_c.xmlattr_FieldURI = UnindexedFieldURIType::ItemInternetMessageHeaders
279
- #prop_d.xmlattr_FieldURI = UnindexedFieldURIType::MessageFrom
280
- #additional_props.upath << prop_a
281
- #additional_props.upath << prop_b
282
- #additional_props.upath << prop_c
283
- #additional_props << prop_d
284
- #item_shape.additionalProperties = additional_props
285
-
286
-
287
-
288
- item_id_t = ItemIdType.new
289
- item_id_t.xmlattr_Id = item_id
290
- item_ids = NonEmptyArrayOfBaseItemIdsType.new([item_id_t])
291
-
292
- get_item.itemShape = item_shape
293
- get_item.itemIds= item_ids
294
-
295
- # ItemInfoResponseMessageType: http://msdn.microsoft.com/en-us/library/aa565417.aspx
296
- resp = ExchWebServ.instance.ews.getItem(get_item).responseMessages.getItemResponseMessage[0]
297
-
298
- #TODO: Error handling
299
- if resp.xmlattr_ResponseClass == "Success"
300
- item = resp.items.send(item_type)
301
- if( item.length > 1 )
302
- puts "ERROR: Item Id should only resolve to a single item!"
303
- end
304
- return item[0]
305
- else
306
- return nil
307
- end
308
- end
309
-
310
-
311
- # More info: http://msdn.microsoft.com/en-us/library/aa565781.aspx
312
- def move_item(item_id, new_folder)
313
- return false unless new_folder.kind_of?(Viewpoint::Folder)
314
-
315
- folder_id_t = FolderIdType.new
316
- folder_id_t.xmlattr_Id = new_folder.folder_id
317
- target_folder_t = TargetFolderIdType.new(folder_id_t)
318
-
319
- item_ids = NonEmptyArrayOfBaseItemIdsType.new
320
- item_t = ItemIdType.new
321
- item_t.xmlattr_Id = item_id
322
- item_ids.itemId << item_t
323
-
324
- move_t = MoveItemType.new(target_folder_t, item_ids)
325
- resp = ExchWebServ.instance.ews.moveItem(move_t).responseMessages.moveItemResponseMessage.first
326
- #TODO: Error handling
327
- if resp.xmlattr_ResponseClass == "Success"
328
- return true
329
- else
330
- return false
331
- end
332
- end
333
-
334
- # Delete item by item_id
335
- # More info: http://msdn.microsoft.com/en-us/library/aa580484.aspx
336
- def delete_item(item_id, delete_type=DisposalType::HardDelete)
337
- item_ids = NonEmptyArrayOfBaseItemIdsType.new
338
- item = ItemIdType.new
339
- item.xmlattr_Id = item_id
340
- item_ids.itemId << item
341
-
342
- delete = DeleteItemType.new(item_ids)
343
- delete.xmlattr_DeleteType = delete_type
344
- resp = ExchWebServ.instance.ews.deleteItem(delete).responseMessages.deleteItemResponseMessage.first
345
-
346
- #TODO: Error handling
347
- if resp.xmlattr_ResponseClass == "Success"
348
- return true
349
- else
350
- return false
351
- end
352
- end
353
-
354
- # Move item to Deleted Items folder instead of deleting it
355
- def recycle_item(item_id)
356
- delete_item(item_id, DisposalType::MoveToDeletedItems)
357
- end
358
- end