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.
- data/COPYING.txt +674 -0
- data/README +60 -0
- data/Rakefile +39 -0
- data/examples/cal2ical.rb +29 -0
- data/examples/ews_fusefs.rb +364 -0
- data/examples/webclient/.gems +2 -0
- data/examples/webclient/README +1 -0
- data/examples/webclient/config.ru +26 -0
- data/examples/webclient/ews_access_handler.rb +42 -0
- data/examples/webclient/public/css/mail.css +33 -0
- data/examples/webclient/public/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/examples/webclient/public/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/examples/webclient/public/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/examples/webclient/public/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/examples/webclient/public/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/examples/webclient/public/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/examples/webclient/public/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/examples/webclient/public/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/examples/webclient/public/css/smoothness/images/ui-icons_222222_256x240.png +0 -0
- data/examples/webclient/public/css/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
- data/examples/webclient/public/css/smoothness/images/ui-icons_454545_256x240.png +0 -0
- data/examples/webclient/public/css/smoothness/images/ui-icons_888888_256x240.png +0 -0
- data/examples/webclient/public/css/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/examples/webclient/public/css/smoothness/jquery-ui-1.7.2.custom.css +406 -0
- data/examples/webclient/public/css/ui-lightness/images/ui-bg_diagonals-thick_18_b81900_40x40.png +0 -0
- data/examples/webclient/public/css/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png +0 -0
- data/examples/webclient/public/css/ui-lightness/images/ui-bg_flat_10_000000_40x100.png +0 -0
- data/examples/webclient/public/css/ui-lightness/images/ui-bg_glass_100_f6f6f6_1x400.png +0 -0
- data/examples/webclient/public/css/ui-lightness/images/ui-bg_glass_100_fdf5ce_1x400.png +0 -0
- data/examples/webclient/public/css/ui-lightness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/examples/webclient/public/css/ui-lightness/images/ui-bg_gloss-wave_35_f6a828_500x100.png +0 -0
- data/examples/webclient/public/css/ui-lightness/images/ui-bg_highlight-soft_100_eeeeee_1x100.png +0 -0
- data/examples/webclient/public/css/ui-lightness/images/ui-bg_highlight-soft_75_ffe45c_1x100.png +0 -0
- data/examples/webclient/public/css/ui-lightness/images/ui-icons_222222_256x240.png +0 -0
- data/examples/webclient/public/css/ui-lightness/images/ui-icons_228ef1_256x240.png +0 -0
- data/examples/webclient/public/css/ui-lightness/images/ui-icons_ef8c08_256x240.png +0 -0
- data/examples/webclient/public/css/ui-lightness/images/ui-icons_ffd27a_256x240.png +0 -0
- data/examples/webclient/public/css/ui-lightness/images/ui-icons_ffffff_256x240.png +0 -0
- data/examples/webclient/public/css/ui-lightness/jquery-ui-1.7.2.custom.css +406 -0
- data/examples/webclient/public/js/jquery-1.3.2.min.js +19 -0
- data/examples/webclient/public/js/jquery-ui-1.7.2.custom.min.js +145 -0
- data/examples/webclient/viewpoint_web.rb +295 -0
- data/examples/webclient/views/_footer.haml +1 -0
- data/examples/webclient/views/_header.haml +11 -0
- data/examples/webclient/views/_tagline.haml +1 -0
- data/examples/webclient/views/index.haml +20 -0
- data/examples/webclient/views/layout.haml +42 -0
- data/examples/webclient/views/mail.haml +45 -0
- data/examples/webclient/views/welcome.haml +0 -0
- data/lib/calendar.rb +121 -0
- data/lib/calendar_item.rb +110 -0
- data/lib/event.rb +0 -0
- data/lib/exchange_headers.rb +50 -0
- data/lib/exchwebserv.rb +228 -0
- data/lib/folder.rb +269 -0
- data/lib/item.rb +56 -0
- data/lib/mail.rb +118 -0
- data/lib/message.rb +134 -0
- data/lib/soap/viewpoint.conf +3 -0
- data/lib/task.rb +0 -0
- data/lib/tasks.rb +0 -0
- data/lib/viewpoint.rb +2 -0
- data/lib/wsdl/defaultMappingRegistry.rb +10680 -0
- data/lib/wsdl/exchangeServiceBinding.rb +349 -0
- data/lib/wsdl/exchangeServiceTypes.rb +11013 -0
- data/preamble +19 -0
- data/test/spec/authtest_spec.rb +12 -0
- data/test/spec/findfolders_spec.rb +14 -0
- data/test/test_client.rb +12 -0
- data/test/testrestrict.rb +75 -0
- metadata +130 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
%h3 The Outlook Webmail Alternative
|
|
@@ -0,0 +1,20 @@
|
|
|
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
|
+
%h2 Viewpoint Web Client
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
-#############################################################################
|
|
2
|
+
-# Copyright © 2009 Dan Wanek <dwanek@nd.gov>
|
|
3
|
+
-#
|
|
4
|
+
-#
|
|
5
|
+
-# This file is part of CommentMonster.
|
|
6
|
+
-#
|
|
7
|
+
-# CommentMonster 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
|
+
-# CommentMonster 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 CommentMonster. If not, see <http://www.gnu.org/licenses/>.
|
|
19
|
+
-#############################################################################
|
|
20
|
+
!!! XML
|
|
21
|
+
!!!
|
|
22
|
+
%html
|
|
23
|
+
%head
|
|
24
|
+
%link{:rel => "stylesheet", :href => "css/ui-lightness/jquery-ui-1.7.2.custom.css", :type => "text/css"}
|
|
25
|
+
%link{:rel => "stylesheet", :href => "css/mail.css", :type => "text/css"}
|
|
26
|
+
%script{:type => "text/javascript", :src => "js/jquery-1.3.2.min.js"}
|
|
27
|
+
%script{:type => "text/javascript", :src => "js/jquery-ui-1.7.2.custom.min.js"}
|
|
28
|
+
:javascript
|
|
29
|
+
$(function(){
|
|
30
|
+
$('#tabs').tabs();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
%body
|
|
34
|
+
#page
|
|
35
|
+
#header
|
|
36
|
+
= partial :_header
|
|
37
|
+
#tagline
|
|
38
|
+
= partial :_tagline
|
|
39
|
+
#content
|
|
40
|
+
= yield
|
|
41
|
+
#footer
|
|
42
|
+
= partial :_footer
|
|
@@ -0,0 +1,45 @@
|
|
|
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
|
+
%html
|
|
21
|
+
%head
|
|
22
|
+
%link{:rel => "stylesheet", :href => "css/ui-lightness/jquery-ui-1.7.2.custom.css", :type => "text/css"}
|
|
23
|
+
%link{:rel => "stylesheet", :href => "css/mail.css", :type => "text/css"}
|
|
24
|
+
%script{:type => "text/javascript", :src => "js/jquery-1.3.2.min.js"}
|
|
25
|
+
%script{:type => "text/javascript", :src => "js/jquery-ui-1.7.2.custom.min.js"}
|
|
26
|
+
:javascript
|
|
27
|
+
$(function(){
|
|
28
|
+
$(".msg_header:even").addClass("even_msg");
|
|
29
|
+
$(".msg_header:odd").addClass("odd_msg");
|
|
30
|
+
$(".msg_header").click(function(e) {
|
|
31
|
+
//var txt = $(this).children(".msg_id").attr('id');
|
|
32
|
+
var txt = $(this).children('input').attr('value');
|
|
33
|
+
$("#msg_body").load("/msg", { msg_id: txt } );
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
%body
|
|
38
|
+
%div#msg_body
|
|
39
|
+
- msgs.each do |msg|
|
|
40
|
+
%div.msg_header
|
|
41
|
+
%input{:type => 'hidden', :id => 'msg_id', :value => msg.item_id}
|
|
42
|
+
%div.sender= msg.sender
|
|
43
|
+
%div.subject= msg.subject
|
|
44
|
+
%div.date= msg.date_time_recieved.strftime('%b %y')
|
|
45
|
+
%div.msg_body
|
|
File without changes
|
data/lib/calendar.rb
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
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 'wsdl/exchangeServiceBinding'
|
|
24
|
+
require 'viewpoint'
|
|
25
|
+
# --- Folder Types ---
|
|
26
|
+
require 'folder'
|
|
27
|
+
# --- Item Types ---
|
|
28
|
+
require 'calendar_item'
|
|
29
|
+
#require 'meeting_request'
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class Viewpoint::CalendarFolder < Viewpoint::Folder
|
|
34
|
+
include Viewpoint
|
|
35
|
+
|
|
36
|
+
# initialize with an item of CalendarFolderType
|
|
37
|
+
def initialize(folder)
|
|
38
|
+
# Call initialize in the
|
|
39
|
+
super(folder)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def get_todays_events
|
|
43
|
+
get_events(DateTime.parse(Date.today.to_s), DateTime.parse(Date.today.next.to_s))
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def get_weeks_events
|
|
47
|
+
start_date = Date.today
|
|
48
|
+
end_date = (start_date + ( 6 - start_date.wday))
|
|
49
|
+
|
|
50
|
+
get_events(DateTime.parse(start_date.to_s), DateTime.parse(end_date.to_s))
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Get events between a certain time period. Defaults to "today"
|
|
54
|
+
# Input: DateTime of start, DateTime of end
|
|
55
|
+
# You can get a year of events by passing 'nil, nil', but you should really consider using synchronization then.
|
|
56
|
+
# This method will return an Array of CalendarItem
|
|
57
|
+
def get_events(start_time = (DateTime.parse(Date.today.to_s)), end_time = (DateTime.parse(Date.today.next.to_s)))
|
|
58
|
+
find_item_t = FindItemType.new
|
|
59
|
+
find_item_t.xmlattr_Traversal = ItemQueryTraversalType::Shallow
|
|
60
|
+
item_shape = ItemResponseShapeType.new(DefaultShapeNamesType::Default, false)
|
|
61
|
+
|
|
62
|
+
find_item_t.itemShape = item_shape
|
|
63
|
+
|
|
64
|
+
folder_ids = NonEmptyArrayOfBaseFolderIdsType.new()
|
|
65
|
+
dist_folder = DistinguishedFolderIdType.new
|
|
66
|
+
dist_folder.xmlattr_Id = DistinguishedFolderIdNameType.new(@display_name.downcase)
|
|
67
|
+
folder_ids.distinguishedFolderId = dist_folder
|
|
68
|
+
find_item_t.parentFolderIds = folder_ids
|
|
69
|
+
|
|
70
|
+
# If we pass nil, force times to be:
|
|
71
|
+
# start: 1 years ago
|
|
72
|
+
# end: 1 years from now
|
|
73
|
+
cal_span = CalendarViewType.new
|
|
74
|
+
if ( start_time == nil or end_time == nil)
|
|
75
|
+
cal_span.xmlattr_StartDate = DateTime.parse((Date.today - 365).to_s).to_s
|
|
76
|
+
cal_span.xmlattr_EndDate = DateTime.parse((Date.today + 365).to_s).to_s
|
|
77
|
+
find_item_t.calendarView = cal_span
|
|
78
|
+
else
|
|
79
|
+
cal_span.xmlattr_StartDate = start_time.to_s
|
|
80
|
+
cal_span.xmlattr_EndDate = end_time.to_s
|
|
81
|
+
find_item_t.calendarView = cal_span
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
resp = find_items(find_item_t)
|
|
85
|
+
if resp != nil
|
|
86
|
+
cal_items = []
|
|
87
|
+
|
|
88
|
+
resp.rootFolder.items.calendarItem.each do |cali|
|
|
89
|
+
cal_items << CalendarItem.new(cali, self)
|
|
90
|
+
end
|
|
91
|
+
# TODO: Handle the following types of Calendar data
|
|
92
|
+
# meetingMessage
|
|
93
|
+
# meetingRequest
|
|
94
|
+
# meetingResponse
|
|
95
|
+
# meetingCancellation
|
|
96
|
+
|
|
97
|
+
return cal_items
|
|
98
|
+
else
|
|
99
|
+
return resp # return nil
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
# Returns an Icalendar::Calendar object
|
|
105
|
+
# Input: DateTime of start, DateTime of end
|
|
106
|
+
def to_ical(dtstart = nil, dtend = nil)
|
|
107
|
+
ical = Icalendar::Calendar.new
|
|
108
|
+
events = get_events(dtstart, dtend)
|
|
109
|
+
events.each do |ev|
|
|
110
|
+
ical.add_event(ev.to_ical_event)
|
|
111
|
+
end
|
|
112
|
+
return ical
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
# See docs for Folder::get_item
|
|
117
|
+
def get_item(item_id)
|
|
118
|
+
cali = super(item_id, "calendarItem", true)
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
@@ -0,0 +1,110 @@
|
|
|
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 'viewpoint'
|
|
24
|
+
require 'item'
|
|
25
|
+
|
|
26
|
+
class Viewpoint::CalendarItem < Viewpoint::Item
|
|
27
|
+
include Viewpoint
|
|
28
|
+
|
|
29
|
+
attr_reader :subject, :parent_folder, :sender
|
|
30
|
+
attr_reader :ews_item if $DEBUG
|
|
31
|
+
|
|
32
|
+
# Initialize an Exchange Web Services item
|
|
33
|
+
def initialize(ews_item, parent_folder)
|
|
34
|
+
# keep this now for debuging
|
|
35
|
+
@ews_item = ews_item if $DEBUG
|
|
36
|
+
@subject = ews_item.subject # String
|
|
37
|
+
@location = ews_item.location if ews_item.location
|
|
38
|
+
@cal_item_type = ews_item.calendarItemType
|
|
39
|
+
@organizer = ews_item.organizer.mailbox.name if ews_item.organizer and ews_item.organizer.mailbox # String
|
|
40
|
+
@start = ews_item.start if ews_item.start # DateTime
|
|
41
|
+
@end = ews_item.v_end if ews_item.v_end # DateTime
|
|
42
|
+
@busy_status = ews_item.legacyFreeBusyStatus if ews_item.legacyFreeBusyStatus # String
|
|
43
|
+
@date_time_recieved = ews_item.dateTimeReceived if ews_item.dateTimeReceived # DateTime
|
|
44
|
+
|
|
45
|
+
# This is where the event object gets loaded if it
|
|
46
|
+
# is requested. Think of it like IMAP downloading the
|
|
47
|
+
# body when the message is viewed.
|
|
48
|
+
@message = nil
|
|
49
|
+
|
|
50
|
+
super(ews_item, parent_folder)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
# Convert item to iCal format: http://www.ietf.org/rfc/rfc2445.txt
|
|
55
|
+
# Returns Icalendar::Event object
|
|
56
|
+
def to_ical_event
|
|
57
|
+
get_calitem if @message == nil
|
|
58
|
+
iev = Icalendar::Event.new
|
|
59
|
+
iev.uid = @message.uID
|
|
60
|
+
unless(@message.organizer == nil)
|
|
61
|
+
iev.organizer = "CN=\"#{@message.organizer.mailbox.name}\"" if @message.organizer.mailbox.name
|
|
62
|
+
iev.organizer += ":MAILTO:#{@message.organizer.mailbox.emailAddress}" if @message.organizer.mailbox.emailAddress
|
|
63
|
+
end
|
|
64
|
+
# TODO: Handle EWS Timezones better. TZ_HASH in viewpoint.rb is the start of this
|
|
65
|
+
require 'time'
|
|
66
|
+
#tzoffset = @message.timeZone.sub(/^\(GMT([^\)]+)\).*$/,'\1')
|
|
67
|
+
dtstart = Time.at(@message.start.strftime('%s').to_i)
|
|
68
|
+
dtend = Time.at(@message.v_end.strftime('%s').to_i)
|
|
69
|
+
dtstamp = Time.at(@message.dateTimeStamp.strftime('%s').to_i)
|
|
70
|
+
last_modified = Time.at(@message.lastModifiedTime.strftime('%s').to_i)
|
|
71
|
+
timestr = "%Y%m%dT%H%M%S"
|
|
72
|
+
iev.dtstart = dtstart.strftime(timestr)
|
|
73
|
+
iev.dtend = dtend.strftime(timestr)
|
|
74
|
+
iev.tzid = dtstart.strftime('%Z')
|
|
75
|
+
iev.dtstamp = dtstamp.strftime(timestr)
|
|
76
|
+
iev.last_modified = last_modified.strftime(timestr)
|
|
77
|
+
iev.location = @message.location if @message.location
|
|
78
|
+
iev.klass = @message.sensitivity if @message.sensitivity
|
|
79
|
+
iev.summary = @message.subject if @message.subject
|
|
80
|
+
iev.description = @message.body if @message.body
|
|
81
|
+
iev.transp = @message.legacyFreeBusyStatus if @message.legacyFreeBusyStatus
|
|
82
|
+
iev.duration = @message.duration if @message.duration
|
|
83
|
+
iev.sequence = @message.appointmentSequenceNumber if @message.appointmentSequenceNumber
|
|
84
|
+
iev.status = @message.myResponseType if @message.myResponseType
|
|
85
|
+
#iev.attach @message.attachments if @message.hasAttachments
|
|
86
|
+
@message.requiredAttendees.each do |pers|
|
|
87
|
+
output = "ROLE=REQ-PARTICIPANT;CN=\"#{pers.mailbox.name}\"" if pers.mailbox.respond_to?(:name)
|
|
88
|
+
output += ":MAILTO:#{pers.mailbox.emailAddress}" if pers.mailbox.respond_to?(:emailAddress)
|
|
89
|
+
iev.attendees << output if output
|
|
90
|
+
end if @message.requiredAttendees
|
|
91
|
+
@message.optionalAttendees.each do |pers|
|
|
92
|
+
output = "ROLE=OPT-PARTICIPANT;CN=\"#{pers.mailbox.name}\"" if pers.mailbox.respond_to?(:name)
|
|
93
|
+
output += ":MAILTO:#{pers.mailbox.emailAddress}" if pers.mailbox.respond_to?(:emailAddress)
|
|
94
|
+
iev.attendees << output if output
|
|
95
|
+
end if @message.optionalAttendees
|
|
96
|
+
|
|
97
|
+
#iev.categories = @message.categories if @message.categories
|
|
98
|
+
#iev.resources = @message.resources if @message.resources
|
|
99
|
+
return iev
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
# These methods are marked 'private' because they return EWS Types and I am trying to
|
|
104
|
+
# hide those because they are not elegant and a bit too tedious for the public interface.
|
|
105
|
+
private
|
|
106
|
+
|
|
107
|
+
def get_calitem
|
|
108
|
+
@message = @parent_folder.get_item(@item_id)
|
|
109
|
+
end
|
|
110
|
+
end
|
data/lib/event.rb
ADDED
|
File without changes
|
|
@@ -0,0 +1,50 @@
|
|
|
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
|
+
require 'viewpoint'
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# Some functionality of EWS depends on setting the "RequestServerVersion"
|
|
27
|
+
# element with a specified "Version" attribute. That is all this class
|
|
28
|
+
# is doing.
|
|
29
|
+
# It is used during the initial connection process by setting the
|
|
30
|
+
# headerhandler in the serivce binding.
|
|
31
|
+
# *<tt>@exchange.headerhandler << ExchangeHeaders.new</tt>
|
|
32
|
+
class Viewpoint::ExchangeHeaders < SOAP::Header::SimpleHandler
|
|
33
|
+
NAMESPACE = 'http://schemas.microsoft.com/exchange/services/2006/types'
|
|
34
|
+
|
|
35
|
+
def initialize
|
|
36
|
+
@qname = XSD::QName.new(NAMESPACE,"RequestServerVersion")
|
|
37
|
+
super(@qname)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def on_simple_outbound
|
|
41
|
+
{
|
|
42
|
+
"xmlattr_Version" => "Exchange2007_SP1"
|
|
43
|
+
}
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def on_outbound
|
|
47
|
+
h = on_simple_outbound
|
|
48
|
+
h ? SOAP::SOAPElement.from_obj(h, nil) : nil
|
|
49
|
+
end
|
|
50
|
+
end
|
data/lib/exchwebserv.rb
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
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 'highline/import'
|
|
23
|
+
require 'singleton'
|
|
24
|
+
require 'wsdl/exchangeServiceBinding'
|
|
25
|
+
# --- Custom libs ---
|
|
26
|
+
require 'exchange_headers'
|
|
27
|
+
# --- Folder Types ---
|
|
28
|
+
require 'folder'
|
|
29
|
+
require 'calendar'
|
|
30
|
+
require 'mail'
|
|
31
|
+
|
|
32
|
+
require 'viewpoint'
|
|
33
|
+
|
|
34
|
+
# This class will act as the controller for a client connection to the
|
|
35
|
+
# Exchange web service.
|
|
36
|
+
class Viewpoint::ExchWebServ
|
|
37
|
+
include Viewpoint
|
|
38
|
+
include Singleton
|
|
39
|
+
|
|
40
|
+
attr_reader :ews, :user, :authenticated
|
|
41
|
+
|
|
42
|
+
def initialize
|
|
43
|
+
@authenticated = false
|
|
44
|
+
@user = nil
|
|
45
|
+
@pass = nil
|
|
46
|
+
@ews_endpoint = nil
|
|
47
|
+
|
|
48
|
+
# Connection to Exchange web services.
|
|
49
|
+
# You can get fetch this from an accessor later.
|
|
50
|
+
@ews = nil
|
|
51
|
+
|
|
52
|
+
# Stores folders returned from 'find_folders'
|
|
53
|
+
@folders = {}
|
|
54
|
+
|
|
55
|
+
# Do initial authentication
|
|
56
|
+
#do_auth
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
# Finds all folders and returns a hash of FolderTypes
|
|
61
|
+
def find_folders
|
|
62
|
+
ff = FindFolderType.new()
|
|
63
|
+
ff.xmlattr_Traversal = FolderQueryTraversalType::Deep
|
|
64
|
+
ff.folderShape = FolderResponseShapeType.new( DefaultShapeNamesType::AllProperties )
|
|
65
|
+
fid = NonEmptyArrayOfBaseFolderIdsType.new()
|
|
66
|
+
fidt = DistinguishedFolderIdType.new
|
|
67
|
+
fidt.xmlattr_Id = DistinguishedFolderIdNameType::Root
|
|
68
|
+
fid.distinguishedFolderId = fidt
|
|
69
|
+
ff.parentFolderIds = fid
|
|
70
|
+
|
|
71
|
+
# FindFolderResponseType
|
|
72
|
+
resp = @ews.findFolder(ff)
|
|
73
|
+
|
|
74
|
+
# ArrayOfResponseMessagesType
|
|
75
|
+
msgs = resp.responseMessages
|
|
76
|
+
|
|
77
|
+
# Array of FindFolderResponseMessageType
|
|
78
|
+
msgs.findFolderResponseMessage.each do |elem|
|
|
79
|
+
# Mail Folders
|
|
80
|
+
mail_folders = {}
|
|
81
|
+
elem.rootFolder.folders.folder.each do |folder|
|
|
82
|
+
if( folder.folderClass != nil)
|
|
83
|
+
mail_folders[folder.displayName] = MailFolder.new(folder)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
@folders['MailFolder'] = mail_folders
|
|
87
|
+
|
|
88
|
+
# CalendarFolderType
|
|
89
|
+
cal_folders = {}
|
|
90
|
+
elem.rootFolder.folders.calendarFolder.each do |folder|
|
|
91
|
+
cal_folders[folder.displayName] = CalendarFolder.new(folder)
|
|
92
|
+
end
|
|
93
|
+
@folders['CalendarFolder'] = cal_folders
|
|
94
|
+
|
|
95
|
+
#elem.rootFolder.folders.contactsFolder.each do |folder|
|
|
96
|
+
#end
|
|
97
|
+
#elem.rootFolder.folders.searchFolder.each do |folder|
|
|
98
|
+
#end
|
|
99
|
+
#elem.rootFolder.folders.tasksFolder.each do |folder|
|
|
100
|
+
#end
|
|
101
|
+
end
|
|
102
|
+
return @folders
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Return folder
|
|
106
|
+
# The default is to return a folder that is a subclass of Folder from the
|
|
107
|
+
# SqliteDB, but if fetch_from_ews is set to true it will go out and return
|
|
108
|
+
# the FolderType object from EWS.
|
|
109
|
+
# Parameters:
|
|
110
|
+
# folder_ids: NonEmptyArrayOfBaseFolderIdsType or String if fetch_from_ews is not set
|
|
111
|
+
# fetch_from_ews: boolean
|
|
112
|
+
# folder_shape: DefaultShapeNamesType
|
|
113
|
+
def get_folder(folder_ids, fetch_from_ews = false, folder_shape = DefaultShapeNamesType::AllProperties)
|
|
114
|
+
unless fetch_from_ews
|
|
115
|
+
return @folders['MailFolder'][folder_ids] ||
|
|
116
|
+
@folders['CalendarFolder'][folder_ids]
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
folder_shape = FolderResponseShapeType.new( folder_shape )
|
|
120
|
+
get_folder = GetFolderType.new(folder_shape, folder_ids)
|
|
121
|
+
|
|
122
|
+
resp = @ews.getFolder(get_folder).responseMessages.getFolderResponseMessage[0].folders.folder[0]
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# Parameters:
|
|
126
|
+
# display_name: String
|
|
127
|
+
# fetch_from_ews: boolean
|
|
128
|
+
# folder_shape: DefaultShapeNamesType
|
|
129
|
+
def get_folder_by_name(display_name, fetch_from_ews = true, folder_shape = DefaultShapeNamesType::AllProperties)
|
|
130
|
+
#folder_ids = NonEmptyArrayOfBaseFolderIdsType.new()
|
|
131
|
+
dist_name = DistinguishedFolderIdType.new
|
|
132
|
+
dist_name.xmlattr_Id = DistinguishedFolderIdNameType.new(display_name.downcase)
|
|
133
|
+
#folder_ids.distinguishedFolderId = dist_name
|
|
134
|
+
folder_ids = NonEmptyArrayOfBaseFolderIdsType.new(nil, [dist_name])
|
|
135
|
+
|
|
136
|
+
get_folder(folder_ids, true, folder_shape)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Parameters:
|
|
140
|
+
# folder_id: String
|
|
141
|
+
# change_key: String
|
|
142
|
+
# folder_shape: DefaultShapeNamesType
|
|
143
|
+
def get_folder_by_id(folder_id, change_key = nil, fetch_from_ews = true, folder_shape = DefaultShapeNamesType::AllProperties)
|
|
144
|
+
folder_ids = NonEmptyArrayOfBaseFolderIdsType.new()
|
|
145
|
+
folder_id_t = FolderIdType.new
|
|
146
|
+
folder_id_t.xmlattr_Id = folder_id
|
|
147
|
+
folder_id_t.xmlattr_ChangeKey = change_key unless change_key == nil
|
|
148
|
+
folder_ids.folderId = folder_id
|
|
149
|
+
folder_ids = NonEmptyArrayOfBaseFolderIdsType.new([folder_id_t], nil)
|
|
150
|
+
|
|
151
|
+
get_folder(folder_ids, true, folder_shape)
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def get_mail_folders
|
|
155
|
+
return @folders['MailFolder']
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def get_calendar_folders
|
|
159
|
+
return @folders['CalendarFolder']
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def authenticate(user = nil, pass = nil, endpoint = nil)
|
|
163
|
+
unless @authenticated
|
|
164
|
+
@user = user
|
|
165
|
+
@pass = pass
|
|
166
|
+
@ews_endpoint = endpoint
|
|
167
|
+
do_auth unless @authenticated
|
|
168
|
+
end
|
|
169
|
+
@authenticated
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
private
|
|
173
|
+
def do_auth
|
|
174
|
+
retry_count = 0
|
|
175
|
+
begin
|
|
176
|
+
if( File.exists?("#{ENV['HOME']}/.viewpointrc") )
|
|
177
|
+
props = SOAP::Property.load(File.new("#{ENV['HOME']}/.viewpointrc"))
|
|
178
|
+
@user = props['exchange.ews.user'] if @user == nil
|
|
179
|
+
@pass = props['exchange.ews.pass'] if @pass == nil
|
|
180
|
+
@ews_endpoint = props['exchange.ews.endpoint'] if @ews_endpoint == nil
|
|
181
|
+
elsif( File.exists?("#{File.dirname(__FILE__)}/soap/viewpoint.conf") )
|
|
182
|
+
props = SOAP::Property.load(File.new("#{File.dirname(__FILE__)}/soap/viewpoint.conf"))
|
|
183
|
+
@user = props['exchange.ews.user'] if @user == nil
|
|
184
|
+
@pass = props['exchange.ews.pass'] if @pass == nil
|
|
185
|
+
@ews_endpoint = props['exchange.ews.endpoint'] if @ews_endpoint == nil
|
|
186
|
+
elsif(@ews_endpoint == nil && @user == nil && @pass == nil)
|
|
187
|
+
@ews_endpoint = ask("Exchange EWS Endpoint: ") { |q| q.echo = true }
|
|
188
|
+
@user = ask("User: ") { |q| q.echo = true }
|
|
189
|
+
@pass = ask("Pass: ") { |q| q.echo = "*"}
|
|
190
|
+
else
|
|
191
|
+
# Nothing to do
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
@ews = ExchangeServiceBinding.new(@ews_endpoint)
|
|
195
|
+
@ews.options["protocol.http.auth.ntlm"] = [@ews_endpoint.sub(/\/[^\/]+$/,'/'),@user,@pass]
|
|
196
|
+
@ews.headerhandler << ExchangeHeaders.new
|
|
197
|
+
|
|
198
|
+
# Log SOAP request and response for debugging. Run ruby with the '-d' option.
|
|
199
|
+
if($DEBUG) then
|
|
200
|
+
@ews.wiredump_file_base = "viewpoint-soaplog"
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# Do a ResolveNames operation to make sure that authentication works.
|
|
204
|
+
# If you don't do an operation, you won't find out that bad credentials
|
|
205
|
+
# were entered until later. The ResolveNames operation is completely
|
|
206
|
+
# arbitrary and could be any EWS call.
|
|
207
|
+
# http://msdn.microsoft.com/en-us/library/bb409286.aspx
|
|
208
|
+
rnt = ResolveNamesType.new(nil,@user)
|
|
209
|
+
rnt.xmlattr_ReturnFullContactData = false
|
|
210
|
+
ews.resolveNames(rnt)
|
|
211
|
+
|
|
212
|
+
rescue SOAP::HTTPStreamError
|
|
213
|
+
puts "Bad Login! Try Again."
|
|
214
|
+
if( retry_count < 2)
|
|
215
|
+
retry_count += 1
|
|
216
|
+
retry
|
|
217
|
+
else
|
|
218
|
+
puts "-----------------------------------------------------------"
|
|
219
|
+
puts "Could not log into Exchange Web Services. Make sure your information is correct"
|
|
220
|
+
puts "End Point: #{@ews_endpoint}"
|
|
221
|
+
puts "User: #{@user}"
|
|
222
|
+
puts "-----------------------------------------------------------"
|
|
223
|
+
return
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
@authenticated = true
|
|
227
|
+
end
|
|
228
|
+
end
|