module Rews
module Folder
# represents a Folder in a mailbox on an Exchange server
class Folder
attr_reader :client
attr_reader :folder_id
attr_reader :attributes
def initialize(client, folder)
@client = client
@folder_id = VanillaFolderId.new(client, folder[:folder_id])
@attributes = folder
end
def ==(other)
other.is_a?(Folder) &&
@client == other.client &&
@folder_id == other.folder_id &&
@attributes == other.attributes
end
# access the +Folder+ +attributes+
def [](key)
@attributes[key]
end
# keys of the +Folder+ +attributes+
def keys
@attributes.keys
end
def inspect
"#<#{self.class} @folder_id=#{@folder_id.inspect}, @attributes=#{@attributes.inspect}>"
end
end
# find_* methods on Folder::BaseFolderId return a +FindResult+
class FindResult
VIEW_ATTRS = [:includes_last_item_in_range,
:indexed_paging_offset,
:total_items_in_view]
VIEW_ATTRS.each do |attr|
attr_reader attr
end
# the +result+ of the +find_*+ call
attr_reader :result
def initialize(view, &proc)
VIEW_ATTRS.each do |attr|
self.instance_variable_set("@#{attr}", view[attr])
end
@result = proc.call(view) if proc
end
# count of items in the +result+
def length
result.length
end
# alias for +length+
def size
result.size
end
# access an element from +result+
def [](key)
result[key]
end
def inspect
attrs = VIEW_ATTRS.map{|attr| "@#{attr}=#{self.send(attr)}"}.join(", ")
"#<#{self.class} #{attrs}, @result=#{@result.inspect}>"
end
end
# Identifies a Folder
class BaseFolderId
include Util
attr_reader :client
def initialize(client)
@client=client
end
FIND_FOLDER_OPTS = {
:restriction=>nil,
:indexed_page_folder_view=>View::INDEXED_PAGE_VIEW_OPTS,
:folder_shape=>Shape::FOLDER_SHAPE_OPTS}
# find Folder::Folders within a Folder::Folder
def find_folder(opts={})
opts = check_opts(FIND_FOLDER_OPTS, opts)
r = with_error_check(client, :find_folder_response, :response_messages, :find_folder_response_message) do
client.savon_client.request(:wsdl, "FindFolder", "Traversal"=>"Shallow") do
http.headers["SOAPAction"] = "\"#{SCHEMA_MESSAGES}/FindFolder\"" # required by EWS 2007
soap.namespaces["xmlns:t"]=SCHEMA_TYPES
xml = Builder::XmlMarkup.new
xml << Shape::FolderShape.new(opts[:folder_shape]||{}).to_xml
xml << View::IndexedPageFolderView.new(opts[:indexed_page_folder_view]).to_xml if opts[:indexed_page_folder_view]
xml << Restriction.new(opts[:restriction]).to_xml if opts[:restriction]
xml.wsdl :ParentFolderIds do
xml << self.to_xml
end
soap.body = xml.target!
end
end
FindResult.new(r.fetch_in(:root_folder)) do |view|
results = view.fetch_in(:folders, :folder)
results = [results] if !results.is_a?(Array)
results.compact.map do |folder|
Folder.new(client, folder)
end
end
end
# find Folder::FolderIdss within a Folder::FolderIds
def find_folder_id(opts={})
opts = check_opts(FIND_FOLDER_OPTS, opts)
shape = opts[:folder_shape] ||={}
shape[:base_shape]||=:IdOnly
r = find_folder(opts)
r.result.map!(&:folder_id)
r
end
FIND_ITEM_OPTS = {
:restriction=>nil,
:sort_order=>nil,
:indexed_page_item_view=>View::INDEXED_PAGE_VIEW_OPTS,
:item_shape=>Shape::ITEM_SHAPE_OPTS}
# find Item::Items in a folder
def find_item(opts={})
opts = check_opts(FIND_ITEM_OPTS, opts)
r = with_error_check(client, :find_item_response, :response_messages, :find_item_response_message) do
client.savon_client.request(:wsdl, "FindItem", "Traversal"=>"Shallow") do
http.headers["SOAPAction"] = "\"#{SCHEMA_MESSAGES}/FindItem\"" # required by EWS 2007
soap.namespaces["xmlns:t"]=SCHEMA_TYPES
xml = Builder::XmlMarkup.new
xml << Shape::ItemShape.new(opts[:item_shape]||{}).to_xml
xml << View::IndexedPageItemView.new(opts[:indexed_page_item_view]).to_xml if opts[:indexed_page_item_view]
xml << Restriction.new(opts[:restriction]).to_xml if opts[:restriction]
xml << SortOrder.new(opts[:sort_order]).to_xml if opts[:sort_order]
xml.wsdl :ParentFolderIds do
xml << self.to_xml
end
soap.body = xml.target!
end
end
FindResult.new(r.to_hash.fetch_in(:root_folder)) do |view|
results = Item.read_items(client, view[:items])
end
end
# find Item::ItemIdss in a folder
def find_item_id(opts={})
opts = check_opts(FIND_ITEM_OPTS, opts)
shape = opts[:item_shape] ||= {}
shape[:base_shape]||=:IdOnly
r = find_item(opts)
r.result.map!(&:item_id)
r
end
GET_ITEM_OPTS = {
:item_shape=>Shape::ITEM_SHAPE_OPTS,
:ignore_change_keys=>nil
}
# retrieve a bunch of Item::Items in one API hit.
# takes a list of Item::ItemIds, or a list of Item::Item,
# or a Folder::FindResult and options to specify +Shape::ItemShape+
def get_item(message_ids, opts={})
opts = check_opts(GET_ITEM_OPTS, opts)
message_ids = message_ids.result if message_ids.is_a?(FindResult)
r = with_error_check(client, :get_item_response,:response_messages,:get_item_response_message) do
client.savon_client.request(:wsdl, "GetItem") do
http.headers["SOAPAction"] = "\"#{SCHEMA_MESSAGES}/GetItem\"" # required by EWS 2007
soap.namespaces["xmlns:t"]=SCHEMA_TYPES
xml = Builder::XmlMarkup.new
xml << Shape::ItemShape.new(opts[:item_shape]||{}).to_xml
xml.wsdl :ItemIds do
message_ids.each do |mid|
mid = mid.item_id if mid.is_a?(Item::Item)
xml << mid.to_xml(opts[:ignore_change_keys])
end
end
soap.body = xml.target!
end
end
Item.read_get_item_response_messages(client, r)
end
DELETE_ITEM_OPTS = {
:delete_type! =>nil,
:ignore_change_keys=>false
}
# delete a bunch of Items in one API hit.
# takes a list of Item::ItemIds, or a list of Item::Item,
# or a Folder::FindResult and options to specify DeleteType
def delete_item(message_ids, opts={})
opts = check_opts(DELETE_ITEM_OPTS, opts)
message_ids = message_ids.result if message_ids.is_a?(FindResult)
r = with_error_check(client, :delete_item_response, :response_messages, :delete_item_response_message) do
client.savon_client.request(:wsdl, "DeleteItem", :DeleteType=>opts[:delete_type]) do
http.headers["SOAPAction"] = "\"#{SCHEMA_MESSAGES}/DeleteItem\"" # required by EWS 2007
soap.namespaces["xmlns:t"]=SCHEMA_TYPES
xml = Builder::XmlMarkup.new
xml.wsdl :ItemIds do
message_ids.each do |mid|
mid = mid.item_id if mid.is_a?(Item::Item)
xml << mid.to_xml(opts[:ignore_change_keys])
end
end
soap.body = xml.target!
end
end
true
end
end
# identifies a regular (non-distinguished) Folder on an Exchange server
class VanillaFolderId < BaseFolderId
# the Id of the Folder
attr_reader :id
# +change_key+ identifies a specific version of the Folder
attr_reader :change_key
def initialize(client, folder_id)
super(client)
@id=folder_id[:id]
@change_key=folder_id[:change_key]
raise "no id" if !@id
end
def ==(other)
other.is_a?(VanillaFolderId) &&
@client == other.client &&
@id == other.id &&
@change_key == other.change_key
end
# a JSON compatible key for persistently identifying this folder
def key(ignore_change_key=false)
key = ["folder", id]
key << change_key if !ignore_change_key
key
end
def to_xml
xml = Builder::XmlMarkup.new
attrs = {:Id=>id.to_s}
attrs[:ChangeKey] = change_key.to_s if change_key
xml.t :FolderId, attrs
xml.target!
end
def inspect
"#<#{self.class} @id=#{id}, @change_key=#{change_key}>"
end
end
# identifies a DistinguishedFolder in a mailbox on an Exchange server.
# the Client.distinguished_folder_id method returns DistinguishedFolderIds
class DistinguishedFolderId < BaseFolderId
# the Id of the DistinguishedFolder e.g. "inbox"
attr_reader :id
# the email address of the mailbox containing the DistinguishedFolder
attr_reader :mailbox_email
def initialize(client, id, mailbox_email=nil)
super(client)
@id = id
@mailbox_email = mailbox_email
raise "no id" if !@id
end
def ==(other)
other.is_a?(DistinguishedFolderId) &&
@client == other.client &&
@id == other.id &&
@mailbox_email == other.mailbox_email
end
# a JSON compatible key for persistently identifying this folder
def key(ignore_change_key=false)
key = ["distinguished_folder", id]
key << mailbox_email if mailbox_email
key
end
def to_xml
xml = Builder::XmlMarkup.new
xml.t :DistinguishedFolderId, :Id=>id do
if mailbox_email
xml.t :Mailbox do
xml.t :EmailAddress, mailbox_email
end
end
end
xml.target!
end
def inspect
"#<#{self.class} @id=#{id}, @mailbox_email=#{mailbox_email}>"
end
end
end
end