ews-api 0.1.0.a
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/.document +5 -0
- data/.gitignore +24 -0
- data/LICENSE +20 -0
- data/README.rdoc +38 -0
- data/Rakefile +88 -0
- data/VERSION +1 -0
- data/ews-api.gemspec +96 -0
- data/lib/ews-api.rb +16 -0
- data/lib/ews/attachment.rb +7 -0
- data/lib/ews/error.rb +14 -0
- data/lib/ews/folder.rb +44 -0
- data/lib/ews/message.rb +22 -0
- data/lib/ews/model.rb +37 -0
- data/lib/ews/parser.rb +166 -0
- data/lib/ews/service.rb +476 -0
- data/spec/ews/attachment_spec.rb +29 -0
- data/spec/ews/folder_spec.rb +85 -0
- data/spec/ews/message_spec.rb +28 -0
- data/spec/ews/model_spec.rb +31 -0
- data/spec/ews/parser_spec.rb +119 -0
- data/spec/ews/service_spec.rb +14 -0
- data/spec/fixtures/find_folder.xml +25 -0
- data/spec/fixtures/find_item.xml +20 -0
- data/spec/fixtures/find_item_all_properties.xml +120 -0
- data/spec/fixtures/get_attachment.xml +77 -0
- data/spec/fixtures/get_folder.xml +16 -0
- data/spec/fixtures/get_item_all_properties.xml +80 -0
- data/spec/fixtures/get_item_default.xml +46 -0
- data/spec/fixtures/get_item_id_only.xml +13 -0
- data/spec/fixtures/get_item_no_attachments.xml +75 -0
- data/spec/fixtures/get_item_with_error.xml +11 -0
- data/spec/integration.rb +153 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +61 -0
- metadata +145 -0
data/.document
ADDED
data/.gitignore
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
## MAC OS
|
2
|
+
.DS_Store
|
3
|
+
|
4
|
+
## TEXTMATE
|
5
|
+
*.tmproj
|
6
|
+
tmtags
|
7
|
+
|
8
|
+
## EMACS
|
9
|
+
*~
|
10
|
+
\#*
|
11
|
+
.\#*
|
12
|
+
|
13
|
+
## VIM
|
14
|
+
*.swp
|
15
|
+
|
16
|
+
## PROJECT::GENERAL
|
17
|
+
coverage
|
18
|
+
rdoc
|
19
|
+
pkg
|
20
|
+
doc
|
21
|
+
.yardoc
|
22
|
+
|
23
|
+
## PROJECT::SPECIFIC
|
24
|
+
spec/test-config.yml
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Jeremy Burks
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
= ews-api
|
2
|
+
|
3
|
+
Exchange Web Services API.
|
4
|
+
|
5
|
+
== Configuration
|
6
|
+
|
7
|
+
Set the endpoint
|
8
|
+
|
9
|
+
EWS::Service.endpoint :uri => 'https://example.com/ews/exchange.asmx',
|
10
|
+
:version => 1
|
11
|
+
|
12
|
+
Set the credentials if the service requires autentication. NTLM is known to work.
|
13
|
+
|
14
|
+
EWS::Service.set_auth 'testuser', 'xxxxxx'
|
15
|
+
|
16
|
+
== Testing
|
17
|
+
|
18
|
+
Typically it isn't a good idea for tests to depend on external resources.
|
19
|
+
This project is in its early days and I am new to EWS. So as to make it
|
20
|
+
easier to implement the service the tests depend on connecting to EWS.
|
21
|
+
|
22
|
+
If +spec/test-config+ exists it will be loaded and the +EWS::Service+ will
|
23
|
+
be configured.
|
24
|
+
|
25
|
+
The config file is ignored via +.gitignore+.
|
26
|
+
|
27
|
+
=== Example +spec/test-config.yml+
|
28
|
+
|
29
|
+
# Example spec/test-config.yml
|
30
|
+
endpoint:
|
31
|
+
:uri: 'https://localhost/ews/exchange.asmx'
|
32
|
+
:version: 1
|
33
|
+
username: testuser
|
34
|
+
password: xxxxxx
|
35
|
+
|
36
|
+
== Copyright
|
37
|
+
|
38
|
+
Copyright (c) 2009 Jeremy Burks. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "ews-api"
|
8
|
+
gem.summary = 'Exchange Web Services API'
|
9
|
+
gem.description = "Exchange Web Services API. It doesn't use soap4r."
|
10
|
+
gem.email = "jeremy.burks@gmail.com"
|
11
|
+
gem.homepage = "http://github.com/jrun/ews-api"
|
12
|
+
gem.authors = ["jrun"]
|
13
|
+
gem.add_dependency 'httpclient'
|
14
|
+
gem.add_dependency 'rubyntlm'
|
15
|
+
gem.add_dependency 'handsoap', '1.1.4'
|
16
|
+
gem.add_development_dependency "rspec", ">= 1.2.9"
|
17
|
+
gem.add_development_dependency "yard", ">= 0"
|
18
|
+
|
19
|
+
desc "Install development dependencies."
|
20
|
+
task :setup do
|
21
|
+
gems = ::Gem::SourceIndex.from_installed_gems
|
22
|
+
gem.dependencies.each do |dep|
|
23
|
+
if gems.find_name(dep.name, dep.version_requirements).empty?
|
24
|
+
puts "Installing dependency: #{dep}"
|
25
|
+
system %Q|gem install #{dep.name} -v "#{dep.version_requirements}" --development|
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
desc "Build and reinstall the gem locally."
|
31
|
+
task :reinstall => :build do
|
32
|
+
version = File.read('VERSION')
|
33
|
+
if (system("gem list #{gem.name} -l") || "") =~ /#{gem.name}-#{version}/
|
34
|
+
system "gem uninstall #{gem.name}"
|
35
|
+
end
|
36
|
+
system "gem install --no-rdoc --no-ri -l pkg/#{gem.name}-#{version}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
Jeweler::GemcutterTasks.new
|
41
|
+
rescue LoadError
|
42
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
43
|
+
end
|
44
|
+
|
45
|
+
require 'spec/rake/spectask'
|
46
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
47
|
+
spec.libs << 'lib' << 'spec'
|
48
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
49
|
+
end
|
50
|
+
|
51
|
+
desc 'Run tests against a real EWS server'
|
52
|
+
Spec::Rake::SpecTask.new(:integration) do |spec|
|
53
|
+
spec.libs << 'lib' << 'spec'
|
54
|
+
spec.spec_files = FileList['spec/integration.rb']
|
55
|
+
end
|
56
|
+
|
57
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
58
|
+
spec.libs << 'lib' << 'spec'
|
59
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
60
|
+
spec.rcov = true
|
61
|
+
end
|
62
|
+
|
63
|
+
task :spec => :check_dependencies
|
64
|
+
task :default => :spec
|
65
|
+
task :build => [:spec, :yard]
|
66
|
+
|
67
|
+
begin
|
68
|
+
require 'yard'
|
69
|
+
YARD::Rake::YardocTask.new
|
70
|
+
rescue LoadError
|
71
|
+
task :yardoc do
|
72
|
+
abort "YARD is not available. In order to run yardoc, you must: sudo gem install yard"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
begin
|
77
|
+
require 'grancher/task'
|
78
|
+
Grancher::Task.new do |g|
|
79
|
+
g.branch = 'gh-pages'
|
80
|
+
g.push_to = 'origin'
|
81
|
+
g.directory 'doc'
|
82
|
+
end
|
83
|
+
rescue LoadError
|
84
|
+
task :publish do
|
85
|
+
abort "grancher is not available. Run 'rake setup' to install all development dependencies."
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0.a
|
data/ews-api.gemspec
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{ews-api}
|
8
|
+
s.version = "0.1.0.a"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["jrun"]
|
12
|
+
s.date = %q{2009-12-17}
|
13
|
+
s.description = %q{Exchange Web Services API. It doesn't use soap4r.}
|
14
|
+
s.email = %q{jeremy.burks@gmail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".gitignore",
|
22
|
+
"LICENSE",
|
23
|
+
"README.rdoc",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"ews-api.gemspec",
|
27
|
+
"lib/ews-api.rb",
|
28
|
+
"lib/ews/attachment.rb",
|
29
|
+
"lib/ews/error.rb",
|
30
|
+
"lib/ews/folder.rb",
|
31
|
+
"lib/ews/message.rb",
|
32
|
+
"lib/ews/model.rb",
|
33
|
+
"lib/ews/parser.rb",
|
34
|
+
"lib/ews/service.rb",
|
35
|
+
"spec/ews/attachment_spec.rb",
|
36
|
+
"spec/ews/folder_spec.rb",
|
37
|
+
"spec/ews/message_spec.rb",
|
38
|
+
"spec/ews/model_spec.rb",
|
39
|
+
"spec/ews/parser_spec.rb",
|
40
|
+
"spec/ews/service_spec.rb",
|
41
|
+
"spec/fixtures/find_folder.xml",
|
42
|
+
"spec/fixtures/find_item.xml",
|
43
|
+
"spec/fixtures/find_item_all_properties.xml",
|
44
|
+
"spec/fixtures/get_attachment.xml",
|
45
|
+
"spec/fixtures/get_folder.xml",
|
46
|
+
"spec/fixtures/get_item_all_properties.xml",
|
47
|
+
"spec/fixtures/get_item_default.xml",
|
48
|
+
"spec/fixtures/get_item_id_only.xml",
|
49
|
+
"spec/fixtures/get_item_no_attachments.xml",
|
50
|
+
"spec/fixtures/get_item_with_error.xml",
|
51
|
+
"spec/integration.rb",
|
52
|
+
"spec/spec.opts",
|
53
|
+
"spec/spec_helper.rb"
|
54
|
+
]
|
55
|
+
s.homepage = %q{http://github.com/jrun/ews-api}
|
56
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
57
|
+
s.require_paths = ["lib"]
|
58
|
+
s.rubygems_version = %q{1.3.5}
|
59
|
+
s.summary = %q{Exchange Web Services API}
|
60
|
+
s.test_files = [
|
61
|
+
"spec/spec_helper.rb",
|
62
|
+
"spec/integration.rb",
|
63
|
+
"spec/ews/parser_spec.rb",
|
64
|
+
"spec/ews/message_spec.rb",
|
65
|
+
"spec/ews/attachment_spec.rb",
|
66
|
+
"spec/ews/folder_spec.rb",
|
67
|
+
"spec/ews/service_spec.rb",
|
68
|
+
"spec/ews/model_spec.rb"
|
69
|
+
]
|
70
|
+
|
71
|
+
if s.respond_to? :specification_version then
|
72
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
73
|
+
s.specification_version = 3
|
74
|
+
|
75
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
76
|
+
s.add_runtime_dependency(%q<httpclient>, [">= 0"])
|
77
|
+
s.add_runtime_dependency(%q<rubyntlm>, [">= 0"])
|
78
|
+
s.add_runtime_dependency(%q<handsoap>, ["= 1.1.4"])
|
79
|
+
s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
|
80
|
+
s.add_development_dependency(%q<yard>, [">= 0"])
|
81
|
+
else
|
82
|
+
s.add_dependency(%q<httpclient>, [">= 0"])
|
83
|
+
s.add_dependency(%q<rubyntlm>, [">= 0"])
|
84
|
+
s.add_dependency(%q<handsoap>, ["= 1.1.4"])
|
85
|
+
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
86
|
+
s.add_dependency(%q<yard>, [">= 0"])
|
87
|
+
end
|
88
|
+
else
|
89
|
+
s.add_dependency(%q<httpclient>, [">= 0"])
|
90
|
+
s.add_dependency(%q<rubyntlm>, [">= 0"])
|
91
|
+
s.add_dependency(%q<handsoap>, ["= 1.1.4"])
|
92
|
+
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
93
|
+
s.add_dependency(%q<yard>, [">= 0"])
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
data/lib/ews-api.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'net/ntlm'
|
2
|
+
require 'handsoap'
|
3
|
+
|
4
|
+
require 'ews/error'
|
5
|
+
require 'ews/model'
|
6
|
+
require 'ews/attachment'
|
7
|
+
require 'ews/message'
|
8
|
+
require 'ews/folder'
|
9
|
+
require 'ews/parser'
|
10
|
+
require 'ews/service'
|
11
|
+
|
12
|
+
module EWS
|
13
|
+
def self.inbox
|
14
|
+
Service.get_folder(:inbox, :base_shape => :AllProperties)
|
15
|
+
end
|
16
|
+
end
|
data/lib/ews/error.rb
ADDED
data/lib/ews/folder.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
module EWS
|
2
|
+
|
3
|
+
class Folder < Model
|
4
|
+
def id
|
5
|
+
attrs[:folder_id][:id]
|
6
|
+
end
|
7
|
+
|
8
|
+
def change_key
|
9
|
+
attrs[:folder_id][:change_key]
|
10
|
+
end
|
11
|
+
|
12
|
+
def name
|
13
|
+
attrs[:display_name]
|
14
|
+
end
|
15
|
+
|
16
|
+
def each_message
|
17
|
+
items.each {|message| yield message }
|
18
|
+
end
|
19
|
+
|
20
|
+
def folders
|
21
|
+
@folders ||= find_folders.inject({}) do |folders, folder|
|
22
|
+
folders[folder.name] = folder
|
23
|
+
folders
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def items
|
28
|
+
@items ||= find_folder_items
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
def find_folder_items
|
33
|
+
# NOTE: This assumes Service#find_item only returns
|
34
|
+
# Messages. That is true now but will change as more
|
35
|
+
# of the parser is implemented.
|
36
|
+
service.find_item(self.name, :base_shape => :AllProperties)
|
37
|
+
end
|
38
|
+
|
39
|
+
def find_folders
|
40
|
+
service.find_folder(self.name)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
data/lib/ews/message.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
module EWS
|
2
|
+
|
3
|
+
class Message < Model
|
4
|
+
def id
|
5
|
+
@id ||= attrs[:item_id][:id]
|
6
|
+
end
|
7
|
+
|
8
|
+
def change_key
|
9
|
+
@change_key ||= attrs[:item_id][:change_key]
|
10
|
+
end
|
11
|
+
|
12
|
+
def shallow?
|
13
|
+
self.body.nil? || self.header.nil?
|
14
|
+
end
|
15
|
+
|
16
|
+
def move_to!(folder_id)
|
17
|
+
# TODO: support DistinguishedFolderId?
|
18
|
+
service.move_item! folder_id, [self.id]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
data/lib/ews/model.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
module EWS
|
2
|
+
|
3
|
+
class Model
|
4
|
+
def initialize(attrs = {})
|
5
|
+
@attrs = attrs.dup
|
6
|
+
end
|
7
|
+
|
8
|
+
def shallow?
|
9
|
+
raise NotImplementedError, "Each model must determine when it is shallow."
|
10
|
+
end
|
11
|
+
|
12
|
+
protected
|
13
|
+
attr_reader :attrs
|
14
|
+
|
15
|
+
def service
|
16
|
+
EWS::Service
|
17
|
+
end
|
18
|
+
|
19
|
+
public
|
20
|
+
def method_missing(meth, *args)
|
21
|
+
method_name = meth.to_s
|
22
|
+
if method_name.end_with?('=')
|
23
|
+
attr = method_name.chomp('=').to_sym
|
24
|
+
@attrs[attr] = args.first
|
25
|
+
elsif method_name.end_with?('?')
|
26
|
+
attr = method_name.chomp('?').to_sym
|
27
|
+
@attrs[attr] == true
|
28
|
+
elsif @attrs.has_key?(meth)
|
29
|
+
@attrs[meth]
|
30
|
+
else
|
31
|
+
super meth, *args
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
data/lib/ews/parser.rb
ADDED
@@ -0,0 +1,166 @@
|
|
1
|
+
module EWS
|
2
|
+
|
3
|
+
class Parser
|
4
|
+
def parse_find_folder(doc)
|
5
|
+
doc.xpath('//t:Folders/child::*').map do |node|
|
6
|
+
parse_exchange_folder node.xpath('.') # force NodeSelection
|
7
|
+
end.compact
|
8
|
+
end
|
9
|
+
|
10
|
+
def parse_get_folder(doc)
|
11
|
+
parse_exchange_folder doc.xpath('//m:Folders/child::*[1]')
|
12
|
+
end
|
13
|
+
|
14
|
+
def parse_find_item(doc)
|
15
|
+
doc.xpath('//t:Items/child::*').map do |node|
|
16
|
+
parse_exchange_item node.xpath('.') # force NodeSelection
|
17
|
+
end.compact
|
18
|
+
end
|
19
|
+
|
20
|
+
def parse_get_item(doc)
|
21
|
+
parse_exchange_item doc.xpath('//m:Items/child::*[1]')
|
22
|
+
end
|
23
|
+
|
24
|
+
def parse_get_attachment(doc)
|
25
|
+
parse_attachment doc.xpath('//m:Attachments/child::*[1]')
|
26
|
+
end
|
27
|
+
|
28
|
+
# Checks the ResponseMessage for errors.
|
29
|
+
#
|
30
|
+
# @see http://msdn.microsoft.com/en-us/library/aa494164%28EXCHG.80%29.aspx
|
31
|
+
# Exhange 2007 Valid Response Messages
|
32
|
+
def parse_response_message(doc)
|
33
|
+
error_node = doc.xpath('//m:ResponseMessages/child::*[@ResponseClass="Error"]')
|
34
|
+
unless error_node.empty?
|
35
|
+
error_msg = error_node.xpath('m:MessageText/text()').to_s
|
36
|
+
response_code = error_node.xpath('m:ResponseCode/text()').to_s
|
37
|
+
raise EWS::ResponseError.new(error_msg, response_code)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
def parse_exchange_folder(folder_node)
|
43
|
+
case folder_node.node_name
|
44
|
+
when 'Folder'
|
45
|
+
parse_folder folder_node
|
46
|
+
when 'CalendarFolder'
|
47
|
+
when 'ContactsFolder'
|
48
|
+
when 'SearchFolder'
|
49
|
+
when 'TasksFolder'
|
50
|
+
else
|
51
|
+
nil
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def parse_folder(folder_node)
|
56
|
+
attrs = {
|
57
|
+
:folder_id => parse_id(folder_node.xpath('t:FolderId')),
|
58
|
+
:display_name => folder_node.xpath('t:DisplayName/text()').to_s,
|
59
|
+
:total_count => folder_node.xpath('t:TotalCount/text()').to_i,
|
60
|
+
:child_folder_count => folder_node.xpath('t:ChildFolderCount/text()').to_i,
|
61
|
+
:unread_count => folder_node.xpath('t:UnreadCount/text()').to_i
|
62
|
+
}
|
63
|
+
Folder.new attrs
|
64
|
+
end
|
65
|
+
|
66
|
+
def parse_exchange_item(item_node)
|
67
|
+
case item_node.node_name
|
68
|
+
when 'Item'
|
69
|
+
when 'Message'
|
70
|
+
parse_message item_node
|
71
|
+
when 'CalendarItem'
|
72
|
+
when 'Contact'
|
73
|
+
when 'Task'
|
74
|
+
when 'MeetingMessage'
|
75
|
+
when 'MeetingRequest'
|
76
|
+
when 'MeetingResponse'
|
77
|
+
when 'MeetingCancellation'
|
78
|
+
else
|
79
|
+
nil
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def parse_message(message_node)
|
84
|
+
attrs = {
|
85
|
+
:item_id => parse_id(message_node.xpath('t:ItemId')),
|
86
|
+
:parent_folder_id => parse_id(message_node.xpath('t:ParentFolderId')),
|
87
|
+
:subject => message_node.xpath('t:Subject/text()').to_s,
|
88
|
+
:body => message_node.xpath('t:Body/text()').to_s,
|
89
|
+
:body_type => message_node.xpath('t:Body/@BodyType').to_s
|
90
|
+
}
|
91
|
+
|
92
|
+
nodeset = message_node.xpath('t:HasAttachments')
|
93
|
+
attrs[:has_attachments] = if not nodeset.empty?
|
94
|
+
parse_bool(nodeset)
|
95
|
+
end
|
96
|
+
|
97
|
+
nodeset = message_node.xpath('t:Attachments')
|
98
|
+
attrs[:attachments] = if not nodeset.empty?
|
99
|
+
nodeset.xpath('t:ItemAttachment|t:FileAttachment').map do |node|
|
100
|
+
parse_attachment node
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
nodeset = message_node.xpath('t:InternetMessageHeaders')
|
105
|
+
attrs[:header] = if not nodeset.empty?
|
106
|
+
parse_header nodeset
|
107
|
+
end
|
108
|
+
|
109
|
+
Message.new attrs
|
110
|
+
end
|
111
|
+
|
112
|
+
EXCHANGE_ITEM_XPATH = ['t:Item',
|
113
|
+
't:Message',
|
114
|
+
't:CalendarItem',
|
115
|
+
't:Contact',
|
116
|
+
't:Task',
|
117
|
+
't:MeetingMessage',
|
118
|
+
't:MeetingRequest',
|
119
|
+
't:MeetingResponse',
|
120
|
+
't:MeetingCancellation'].join('|').freeze
|
121
|
+
|
122
|
+
def parse_attachment(attachment_node)
|
123
|
+
attrs = {
|
124
|
+
:attachment_id => attachment_node.xpath('t:AttachmentId/@Id').to_s,
|
125
|
+
:name => attachment_node.xpath('t:Name/text()').to_s,
|
126
|
+
:content_type => attachment_node.xpath('t:ContentType/text()').to_s,
|
127
|
+
:content_id => attachment_node.xpath('t:ContentId/text()').to_s,
|
128
|
+
:content_location => attachment_node.xpath('t:ContentLocation/text()').to_s
|
129
|
+
}
|
130
|
+
|
131
|
+
case attachment_node.node_name
|
132
|
+
when 'ItemAttachment'
|
133
|
+
attrs[:item] = parse_exchange_item attachment_node.xpath(EXCHANGE_ITEM_XPATH)
|
134
|
+
when 'FileAttachment'
|
135
|
+
end
|
136
|
+
|
137
|
+
Attachment.new attrs
|
138
|
+
end
|
139
|
+
|
140
|
+
def parse_header(header_node)
|
141
|
+
header_node.xpath('t:InternetMessageHeader').inject({}) do |header, node|
|
142
|
+
name = node.xpath('@HeaderName').to_s.downcase
|
143
|
+
header[name] = [] unless header.has_key?(name)
|
144
|
+
header[name] << node.xpath('text()').to_s
|
145
|
+
header
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def parse_id(id_node)
|
150
|
+
return nil if id_node.empty?
|
151
|
+
{ :id => id_node.xpath('@Id').to_s,
|
152
|
+
:change_key => id_node.xpath('@ChangeKey').to_s }
|
153
|
+
end
|
154
|
+
|
155
|
+
def parse_bool(val)
|
156
|
+
case val.to_s.downcase
|
157
|
+
when 'true'
|
158
|
+
true
|
159
|
+
when 'false'
|
160
|
+
false
|
161
|
+
else
|
162
|
+
nil
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|