viewpoint 0.0.1

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