viewpoint 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|