viewpoint 0.0.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 (71) hide show
  1. data/COPYING.txt +674 -0
  2. data/README +60 -0
  3. data/Rakefile +39 -0
  4. data/examples/cal2ical.rb +29 -0
  5. data/examples/ews_fusefs.rb +364 -0
  6. data/examples/webclient/.gems +2 -0
  7. data/examples/webclient/README +1 -0
  8. data/examples/webclient/config.ru +26 -0
  9. data/examples/webclient/ews_access_handler.rb +42 -0
  10. data/examples/webclient/public/css/mail.css +33 -0
  11. data/examples/webclient/public/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  12. data/examples/webclient/public/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  13. data/examples/webclient/public/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  14. data/examples/webclient/public/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  15. data/examples/webclient/public/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  16. data/examples/webclient/public/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  17. data/examples/webclient/public/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  18. data/examples/webclient/public/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  19. data/examples/webclient/public/css/smoothness/images/ui-icons_222222_256x240.png +0 -0
  20. data/examples/webclient/public/css/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
  21. data/examples/webclient/public/css/smoothness/images/ui-icons_454545_256x240.png +0 -0
  22. data/examples/webclient/public/css/smoothness/images/ui-icons_888888_256x240.png +0 -0
  23. data/examples/webclient/public/css/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
  24. data/examples/webclient/public/css/smoothness/jquery-ui-1.7.2.custom.css +406 -0
  25. data/examples/webclient/public/css/ui-lightness/images/ui-bg_diagonals-thick_18_b81900_40x40.png +0 -0
  26. data/examples/webclient/public/css/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png +0 -0
  27. data/examples/webclient/public/css/ui-lightness/images/ui-bg_flat_10_000000_40x100.png +0 -0
  28. data/examples/webclient/public/css/ui-lightness/images/ui-bg_glass_100_f6f6f6_1x400.png +0 -0
  29. data/examples/webclient/public/css/ui-lightness/images/ui-bg_glass_100_fdf5ce_1x400.png +0 -0
  30. data/examples/webclient/public/css/ui-lightness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  31. data/examples/webclient/public/css/ui-lightness/images/ui-bg_gloss-wave_35_f6a828_500x100.png +0 -0
  32. data/examples/webclient/public/css/ui-lightness/images/ui-bg_highlight-soft_100_eeeeee_1x100.png +0 -0
  33. data/examples/webclient/public/css/ui-lightness/images/ui-bg_highlight-soft_75_ffe45c_1x100.png +0 -0
  34. data/examples/webclient/public/css/ui-lightness/images/ui-icons_222222_256x240.png +0 -0
  35. data/examples/webclient/public/css/ui-lightness/images/ui-icons_228ef1_256x240.png +0 -0
  36. data/examples/webclient/public/css/ui-lightness/images/ui-icons_ef8c08_256x240.png +0 -0
  37. data/examples/webclient/public/css/ui-lightness/images/ui-icons_ffd27a_256x240.png +0 -0
  38. data/examples/webclient/public/css/ui-lightness/images/ui-icons_ffffff_256x240.png +0 -0
  39. data/examples/webclient/public/css/ui-lightness/jquery-ui-1.7.2.custom.css +406 -0
  40. data/examples/webclient/public/js/jquery-1.3.2.min.js +19 -0
  41. data/examples/webclient/public/js/jquery-ui-1.7.2.custom.min.js +145 -0
  42. data/examples/webclient/viewpoint_web.rb +295 -0
  43. data/examples/webclient/views/_footer.haml +1 -0
  44. data/examples/webclient/views/_header.haml +11 -0
  45. data/examples/webclient/views/_tagline.haml +1 -0
  46. data/examples/webclient/views/index.haml +20 -0
  47. data/examples/webclient/views/layout.haml +42 -0
  48. data/examples/webclient/views/mail.haml +45 -0
  49. data/examples/webclient/views/welcome.haml +0 -0
  50. data/lib/calendar.rb +121 -0
  51. data/lib/calendar_item.rb +110 -0
  52. data/lib/event.rb +0 -0
  53. data/lib/exchange_headers.rb +50 -0
  54. data/lib/exchwebserv.rb +228 -0
  55. data/lib/folder.rb +269 -0
  56. data/lib/item.rb +56 -0
  57. data/lib/mail.rb +118 -0
  58. data/lib/message.rb +134 -0
  59. data/lib/soap/viewpoint.conf +3 -0
  60. data/lib/task.rb +0 -0
  61. data/lib/tasks.rb +0 -0
  62. data/lib/viewpoint.rb +2 -0
  63. data/lib/wsdl/defaultMappingRegistry.rb +10680 -0
  64. data/lib/wsdl/exchangeServiceBinding.rb +349 -0
  65. data/lib/wsdl/exchangeServiceTypes.rb +11013 -0
  66. data/preamble +19 -0
  67. data/test/spec/authtest_spec.rb +12 -0
  68. data/test/spec/findfolders_spec.rb +14 -0
  69. data/test/test_client.rb +12 -0
  70. data/test/testrestrict.rb +75 -0
  71. metadata +130 -0
@@ -0,0 +1,269 @@
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
+ require 'viewpoint'
22
+
23
+ # This class is inherited by all folder subtypes such as Mail, Calendar,
24
+ # Tasks and Search. It will serve as the brain for all of the methods that
25
+ # each of these folder types have in common.
26
+ class Viewpoint::Folder
27
+ include Viewpoint
28
+
29
+ attr_accessor :folder_id, :parent_id, :display_name
30
+ def initialize(folder)
31
+ @folder_id = folder.folderId.xmlattr_Id
32
+ @parent_id = folder.parentFolderId.xmlattr_Id unless folder.parentFolderId == nil
33
+ @display_name = folder.displayName
34
+ @sync_state = nil
35
+ @subscription_id = nil
36
+ @watermark = nil
37
+ end
38
+
39
+ # Subscribe to folder and save the subscription_id into the database. Subsequent calls
40
+ # to check_subscription will use that id.
41
+ # Returns true if the operation is successful, false otherwise
42
+ def subscribe
43
+ subscribe = SubscribeType.new
44
+ pull = PullSubscriptionRequestType.new
45
+
46
+ # Set-up folder Id
47
+ dist_fid = DistinguishedFolderIdType.new
48
+ dist_fid.xmlattr_Id = DistinguishedFolderIdNameType::Calendar
49
+ f_ids = NonEmptyArrayOfBaseFolderIdsType.new()
50
+ f_ids.distinguishedFolderId = dist_fid
51
+ pull.folderIds = f_ids
52
+
53
+ # Set-up event types
54
+ event_types = NonEmptyArrayOfNotificationEventTypesType.new
55
+ #event_types.push(NotificationEventTypeType::NewMailEvent)
56
+ event_types.push(NotificationEventTypeType::CreatedEvent)
57
+ event_types.push(NotificationEventTypeType::DeletedEvent)
58
+ #event_types.push(NotificationEventTypeType::ModifiedEvent)
59
+ event_types.push(NotificationEventTypeType::MovedEvent)
60
+ pull.eventTypes = event_types
61
+
62
+ pull.timeout = 10
63
+
64
+ subscribe.pullSubscriptionRequest = pull
65
+
66
+ resp = ExchWebServ.instance.ews.subscribe(subscribe).responseMessages.subscribeResponseMessage[0]
67
+ @subscription_id = resp.subscriptionId
68
+ @watermark = resp.watermark
69
+
70
+ return (resp.responseCode == "NoError")? true: false
71
+ end
72
+
73
+
74
+ # Fetch events with the subscription_id. If one does not exists or is expired,
75
+ # call subscribe.
76
+ def check_subscription
77
+ begin
78
+ if( @subscription_id == nil or @watermark == nil) then
79
+ self.subscribe
80
+ end
81
+ ge = GetEventsType.new(@subscription_id, @watermark)
82
+
83
+ resp = ExchWebServ.instance.ews.getEvents(ge).responseMessages.getEventsResponseMessage[0]
84
+
85
+ #TODO: Add more event processing
86
+
87
+
88
+ notifications = resp.notification
89
+
90
+ # Process Notifications
91
+ if( notifications.createdEvent != nil)
92
+ notifications.createdEvent.each do |note|
93
+ @watermark = note.watermark
94
+ end
95
+ end
96
+
97
+ if( notifications.deletedEvent != nil)
98
+ notifications.deletedEvent.each do |note|
99
+ @watermark = note.watermark
100
+ end
101
+ end
102
+
103
+ if( notifications.movedEvent != nil)
104
+ notifications.movedEvent.each do |note|
105
+ @watermark = note.watermark
106
+ end
107
+ end
108
+
109
+ if( notifications.statusEvent != nil)
110
+ notifications.statusEvent.each do |note|
111
+ @watermark = note.watermark
112
+ end
113
+ end
114
+
115
+ end
116
+
117
+ return resp
118
+ end
119
+
120
+
121
+ # This is a proxy for the SyncFolderItems operation detailed here: http://msdn.microsoft.com/en-us/library/aa563967.aspx
122
+ # It returns a SyncFolderItemsResponseType object
123
+ def sync_folder(max_items = 256)
124
+ begin
125
+ # ItemResponseShapeType
126
+ itemshapeT = ItemResponseShapeType.new(DefaultShapeNamesType::IdOnly, false)
127
+
128
+ # TargetFolderIdType
129
+ tfolderidT = TargetFolderIdType.new
130
+ folderidT = FolderIdType.new
131
+ folderidT.xmlattr_Id = self.folder_id
132
+ tfolderidT.folderId = folderidT
133
+
134
+ # SyncFolderItemsType
135
+ syncitemsT = SyncFolderItemsType.new(itemshapeT,tfolderidT,self.sync_state,nil,max_items)
136
+
137
+ # Call Sync => returns SyncFolderItemsResponseType
138
+ resp = ExchWebServ.instance.ews.syncFolderItems(syncitemsT).responseMessages.syncFolderItemsResponseMessage[0]
139
+ @sync_state = resp.syncState
140
+ return resp
141
+ rescue
142
+ puts "** Something happened during synchronizing folder => #{self.display_name}"
143
+ raise
144
+ end
145
+ end
146
+
147
+
148
+ # Wrapper around EWS's FindItem method: http://msdn.microsoft.com/en-us/library/aa566107.aspx
149
+ # The specifics of this method should be set up in the child classes and then this method should
150
+ # be called with a parameter of FindItemType: http://msdn.microsoft.com/en-us/library/aa566370.aspx
151
+ # This allows for a central place of error handling. See Calendar::get_events for an example
152
+ # of how this works.
153
+ def find_items(find_item_t)
154
+ # FindItemResponseMessageType: http://msdn.microsoft.com/en-us/library/aa566424.aspx
155
+ resp = ExchWebServ.instance.ews.findItem(find_item_t).responseMessages.findItemResponseMessage[0]
156
+
157
+ #TODO: Error handling
158
+ if resp.xmlattr_ResponseClass == "Success"
159
+ return resp
160
+ else
161
+ return nil
162
+ end
163
+ end
164
+
165
+
166
+ # Fetch item by item_id
167
+ # Params: item_id: ItemIdType
168
+ # item_type: String (message, calendarItem)
169
+ # all_props: boolean; default is to get just the Default props
170
+ # Returns: a Item type of some sort ( depends on 'item_type' parameter )
171
+ def get_item(item_id, item_type = nil, all_props = false)
172
+ get_item = GetItemType.new
173
+
174
+ if all_props
175
+ shape_name = DefaultShapeNamesType::AllProperties
176
+ else
177
+ shape_name = DefaultShapeNamesType::Default
178
+ end
179
+
180
+ item_shape = ItemResponseShapeType.new( shape_name, false, BodyTypeResponseType::Text )
181
+
182
+ #additional_props = NonEmptyArrayOfPathsToElementType.new
183
+ #prop_a = PathToUnindexedFieldType.new
184
+ #prop_b = PathToUnindexedFieldType.new
185
+ #prop_c = PathToUnindexedFieldType.new
186
+ #prop_d = PathToUnindexedFieldType.new
187
+ #prop_a.xmlattr_FieldURI = UnindexedFieldURIType::CalendarMeetingTimeZone
188
+ #prop_b.xmlattr_FieldURI = UnindexedFieldURIType.new("calendar:EndTimeZone")
189
+ #prop_c.xmlattr_FieldURI = UnindexedFieldURIType::ItemInternetMessageHeaders
190
+ #prop_d.xmlattr_FieldURI = UnindexedFieldURIType::MessageFrom
191
+ #additional_props.upath << prop_a
192
+ #additional_props.upath << prop_b
193
+ #additional_props.upath << prop_c
194
+ #additional_props << prop_d
195
+ #item_shape.additionalProperties = additional_props
196
+
197
+
198
+
199
+ item_id_t = ItemIdType.new
200
+ item_id_t.xmlattr_Id = item_id
201
+ item_ids = NonEmptyArrayOfBaseItemIdsType.new([item_id_t])
202
+
203
+ get_item.itemShape = item_shape
204
+ get_item.itemIds= item_ids
205
+
206
+ # ItemInfoResponseMessageType: http://msdn.microsoft.com/en-us/library/aa565417.aspx
207
+ resp = ExchWebServ.instance.ews.getItem(get_item).responseMessages.getItemResponseMessage[0]
208
+
209
+ #TODO: Error handling
210
+ if resp.xmlattr_ResponseClass == "Success"
211
+ item = resp.items.send(item_type)
212
+ if( item.length > 1 )
213
+ puts "ERROR: Item Id should only resolve to a single item!"
214
+ end
215
+ return item[0]
216
+ else
217
+ return nil
218
+ end
219
+ end
220
+
221
+
222
+ # More info: http://msdn.microsoft.com/en-us/library/aa565781.aspx
223
+ def move_item(item_id, new_folder)
224
+ return false unless new_folder.kind_of?(Viewpoint::Folder)
225
+
226
+ folder_id_t = FolderIdType.new
227
+ folder_id_t.xmlattr_Id = new_folder.folder_id
228
+ target_folder_t = TargetFolderIdType.new(folder_id_t)
229
+
230
+ item_ids = NonEmptyArrayOfBaseItemIdsType.new
231
+ item_t = ItemIdType.new
232
+ item_t.xmlattr_Id = item_id
233
+ item_ids.itemId << item_t
234
+
235
+ move_t = MoveItemType.new(target_folder_t, item_ids)
236
+ resp = ExchWebServ.instance.ews.moveItem(move_t).responseMessages.moveItemResponseMessage.first
237
+ #TODO: Error handling
238
+ if resp.xmlattr_ResponseClass == "Success"
239
+ return true
240
+ else
241
+ return false
242
+ end
243
+ end
244
+
245
+ # Delete item by item_id
246
+ # More info: http://msdn.microsoft.com/en-us/library/aa580484.aspx
247
+ def delete_item(item_id, delete_type=DisposalType::HardDelete)
248
+ item_ids = NonEmptyArrayOfBaseItemIdsType.new
249
+ item = ItemIdType.new
250
+ item.xmlattr_Id = item_id
251
+ item_ids.itemId << item
252
+
253
+ delete = DeleteItemType.new(item_ids)
254
+ delete.xmlattr_DeleteType = delete_type
255
+ resp = ExchWebServ.instance.ews.deleteItem(delete).responseMessages.deleteItemResponseMessage.first
256
+
257
+ #TODO: Error handling
258
+ if resp.xmlattr_ResponseClass == "Success"
259
+ return true
260
+ else
261
+ return false
262
+ end
263
+ end
264
+
265
+ # Move item to Deleted Items folder instead of deleting it
266
+ def recycle_item(item_id)
267
+ delete_item(item_id, DisposalType::MoveToDeletedItems)
268
+ end
269
+ end
@@ -0,0 +1,56 @@
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 'viewpoint'
21
+
22
+
23
+ # This class is inherited by all Item subtypes such as Message, Event,
24
+ # and Task. It will serve as the brain for all of the methods that
25
+ # each of these Item types have in common.
26
+ class Viewpoint::Item
27
+ include Viewpoint
28
+
29
+ attr_accessor :item_id
30
+
31
+ # Initialize an Exchange Web Services item
32
+ def initialize(ews_item, parent_folder)
33
+ @item_id = ews_item.itemId.xmlattr_Id
34
+ @parent_folder = parent_folder
35
+ end
36
+
37
+ # Takes an object of type Viewpoint::Folder as an argument
38
+ # Returns a boolean value, true if the move ocurred, false otherwise.
39
+ def move_to!(new_folder)
40
+ retval = @parent_folder.move_item(@item_id, new_folder)
41
+ @parent_folder = new_folder if retval
42
+
43
+ return retval
44
+ end
45
+
46
+
47
+ # Returns a boolean value, true if the delete ocurred, false otherwise.
48
+ def delete!
49
+ @parent_folder.delete_item(@item_id)
50
+ end
51
+
52
+ # Returns a boolean value, true if the recycle ocurred, false otherwise.
53
+ def recycle!
54
+ @parent_folder.recycle_item(@item_id)
55
+ end
56
+ end
@@ -0,0 +1,118 @@
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 'wsdl/exchangeServiceBinding'
23
+ # --- Folder Types ---
24
+ require 'folder'
25
+ # --- Item Types ---
26
+ require 'message'
27
+
28
+ require 'viewpoint'
29
+
30
+
31
+ class Viewpoint::MailFolder < Viewpoint::Folder
32
+ include Viewpoint
33
+
34
+ # initialize with an item of MailFolderType
35
+ def initialize(folder)
36
+ super(folder)
37
+ end
38
+
39
+ def get_todays_messages
40
+ get_messages( DateTime.parse(Date.today.to_s).to_s )
41
+ end
42
+
43
+ # Get messages between a certain time period. Defaults to "today"
44
+ # Input: DateTime of start, DateTime of end
45
+ # This method will return an Array of Message
46
+ def get_messages(since = (DateTime.parse(Date.today.to_s)) )
47
+ # Set-up FindItemType
48
+ find_item_t = FindItemType.new
49
+ find_item_t.xmlattr_Traversal = ItemQueryTraversalType::Shallow
50
+ item_shape = ItemResponseShapeType.new(DefaultShapeNamesType::IdOnly, false)
51
+
52
+ additional_props = NonEmptyArrayOfPathsToElementType.new
53
+ prop_a = PathToUnindexedFieldType.new
54
+ prop_b = PathToUnindexedFieldType.new
55
+ prop_c = PathToUnindexedFieldType.new
56
+ prop_d = PathToUnindexedFieldType.new
57
+ prop_e = PathToUnindexedFieldType.new
58
+ prop_f = PathToUnindexedFieldType.new
59
+ prop_a.xmlattr_FieldURI = UnindexedFieldURIType::ItemSubject
60
+ prop_b.xmlattr_FieldURI = UnindexedFieldURIType::ItemDateTimeReceived
61
+ prop_c.xmlattr_FieldURI = UnindexedFieldURIType::MessageSender
62
+ prop_d.xmlattr_FieldURI = UnindexedFieldURIType::MessageFrom
63
+ prop_e.xmlattr_FieldURI = UnindexedFieldURIType::MessageIsRead
64
+ prop_f.xmlattr_FieldURI = UnindexedFieldURIType::MessageInternetMessageId
65
+ additional_props.upath << prop_a
66
+ additional_props.upath << prop_b
67
+ additional_props.upath << prop_c
68
+ additional_props.upath << prop_d
69
+ additional_props.upath << prop_e
70
+ additional_props.upath << prop_f
71
+ item_shape.additionalProperties = additional_props
72
+ find_item_t.itemShape = item_shape
73
+
74
+
75
+ # Set-up folder Ids to search in
76
+ folder_ids = NonEmptyArrayOfBaseFolderIdsType.new()
77
+ dist_folder = DistinguishedFolderIdType.new
78
+ dist_folder.xmlattr_Id = DistinguishedFolderIdNameType.new(@display_name.downcase)
79
+ folder_ids.distinguishedFolderId = dist_folder
80
+ find_item_t.parentFolderIds = folder_ids
81
+
82
+
83
+ # Set-up date-based restriction.
84
+ restriction = RestrictionType.new
85
+ search_type = IsGreaterThanOrEqualToType.new
86
+ fielduri = PathToUnindexedFieldType.new
87
+ fielduri.xmlattr_FieldURI = UnindexedFieldURIType::ItemDateTimeReceived
88
+ const = FieldURIOrConstantType.new
89
+ c = ConstantValueType.new
90
+ c.xmlattr_Value = (DateTime.now - 2).new_offset(0).to_s
91
+ const.constant = c
92
+ search_type.path = fielduri
93
+ search_type.fieldURIOrConstant = const
94
+ restriction.isGreaterThanOrEqualTo = search_type
95
+
96
+ find_item_t.restriction = restriction
97
+
98
+ resp = find_items(find_item_t)
99
+
100
+ if resp != nil
101
+ messages = []
102
+ resp.rootFolder.items.message.each do |msg|
103
+ messages << Message.new(msg, self)
104
+ end
105
+
106
+ return messages
107
+ else
108
+ return resp
109
+ end
110
+
111
+ end
112
+
113
+
114
+ # See docs for Folder::get_item
115
+ def get_item(item_id)
116
+ msg = super(item_id, "message", true)
117
+ end
118
+ end
@@ -0,0 +1,134 @@
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 'item'
22
+ require 'viewpoint'
23
+
24
+ class Viewpoint::Message < Viewpoint::Item
25
+ include Viewpoint
26
+
27
+ attr_reader :subject, :parent_folder, :sender, :date_time_recieved
28
+ attr_reader :ews_item if $DEBUG
29
+
30
+ # Initialize an Exchange Web Services item of MessageType
31
+ def initialize(ews_item, parent_folder)
32
+ # keep this now for debuging
33
+ @ews_item = ews_item if $DEBUG
34
+ @subject = ews_item.subject # String
35
+ @sender = ews_item.sender.mailbox.name if ews_item.sender # String
36
+ @recipients =
37
+ @is_read = ews_item.isRead # boolean
38
+ @date_time_recieved = ews_item.dateTimeReceived # DateTime
39
+
40
+ # This is where the entire message object gets loaded if it
41
+ # is requested. Think of it like IMAP downloading the
42
+ # body when the message is viewed.
43
+ @message = nil
44
+
45
+ super(ews_item, parent_folder)
46
+ end
47
+
48
+ def body
49
+ get_message if @message == nil
50
+ return @message.body
51
+ end
52
+
53
+ def recipients
54
+ get_message if @message == nil
55
+ to_recipients = ''
56
+ @message.toRecipients.each do |r|
57
+ to_recipients += ', ' if to_recipients != ''
58
+ to_recipients += "#{r.name} <#{r.emailAddress}>"
59
+ end
60
+
61
+ return to_recipients
62
+ end
63
+
64
+ def cc_recipients
65
+ get_message if @message == nil
66
+ if( @message.ccRecipients != nil)
67
+ cc = ''
68
+ @message.ccRecipients.each do |r|
69
+ cc += ', ' if cc != ''
70
+ cc += "#{r.name} <#{r.emailAddress}>"
71
+ end
72
+ return cc
73
+ end
74
+ return nil
75
+ end
76
+
77
+ def bcc_recipients
78
+ get_message if @message == nil
79
+ if( @message.bccRecipients != nil)
80
+ bcc = ''
81
+ @message.bccRecipients.each do |r|
82
+ bcc += ', ' if bcc != ''
83
+ bcc += "#{r.name} <#{r.emailAddress}>"
84
+ end
85
+ return bcc
86
+ end
87
+ return nil
88
+ end
89
+
90
+ def get_message
91
+ @message = @parent_folder.get_item(@item_id)
92
+ end
93
+
94
+ # Output the message in RFC 822 format: http://www.ietf.org/rfc/rfc0822.txt
95
+ def to_rfc822
96
+ get_message if @message == nil
97
+ rfc822 = []
98
+ rfc822.push 'Return-Path' => @message.sender.mailbox.emailAddress
99
+ rfc822.push 'Delivered-To' => @message.receivedBy.mailbox.emailAddress
100
+ @message.internetMessageHeaders.each do |hdr|
101
+ # TODO: Quick Fix... needs more research
102
+ if( hdr.xmlattr_HeaderName == 'Content-Type' && hdr =~ /tnef/ )
103
+ rfc822.push hdr.xmlattr_HeaderName => 'multipart/alternative'
104
+ else
105
+ rfc822.push hdr.xmlattr_HeaderName => hdr
106
+ end
107
+ end
108
+
109
+ # From
110
+ rfc822.push 'From' => "#{@message.sender.mailbox.name} <#{@message.sender.mailbox.emailAddress}>"
111
+
112
+ # To
113
+ rfc822.push 'To' => self.recipients
114
+
115
+ # CC
116
+ if( ( cc = self.cc_recipients) != nil)
117
+ rfc822.push 'Cc' => cc
118
+ end
119
+
120
+ # BCC
121
+ if( ( bcc = self.bcc_recipients) != nil)
122
+ rfc822.push 'Bcc' => bcc
123
+ end
124
+
125
+ rfc822_msg = ""
126
+ rfc822.each do |line|
127
+ line.each_pair do |key,val|
128
+ rfc822_msg += "#{key}: #{val}\n"
129
+ end
130
+ end
131
+
132
+ rfc822_msg += "\n\n#{@message.body}"
133
+ end
134
+ end