rexchange 0.1.4 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,9 @@
1
+ -- 0.2.0:
2
+ * Fixed a bug in Message#move_to when passing folders
3
+ * Added support for Contact browsing
4
+ * Added GenericItem to abstract Contacts and Messages
5
+ * Renamed Folder#messages to Folder#get_messages to avoid naming collisions
6
+
1
7
  -- 0.1.4:
2
8
  * Moved Folder::normalize_folder_name to String#normalize, and added support for MixedCase sources.
3
9
  * Fixed a bug where the normalized folder name was being used for the Folder#to_s result.
data/RAKEFILE CHANGED
@@ -7,7 +7,7 @@ require 'rake/gempackagetask'
7
7
  require 'rake/contrib/rubyforgepublisher'
8
8
  require 'pscp'
9
9
 
10
- PACKAGE_VERSION = '0.1.4'
10
+ PACKAGE_VERSION = '0.2.0'
11
11
 
12
12
  PACKAGE_FILES = FileList[
13
13
  'README',
@@ -0,0 +1,2 @@
1
+ # Provided for compatibility with RubyOnRails auto-require functionality.
2
+ require 'rexchange'
@@ -1,8 +1,22 @@
1
1
  require 'rexchange/session'
2
2
 
3
+ class String
4
+ def ends_with?(partial)
5
+ self[self.size - partial.size..self.size] == partial
6
+ end
7
+
8
+ def ensure_ends_with(partial)
9
+ self.ends_with?(partial) ? self : self + partial
10
+ end
11
+
12
+ def normalize
13
+ self.split(/(?=[A-Z][a-z]*)/).join('_').tr('- ', '_').squeeze('_').downcase
14
+ end
15
+ end
16
+
3
17
  module RExchange
4
18
  # Use STDOUT or another stream if you'd like to capture the HTTP debug output
5
- DEBUG_STREAM = nil
19
+ DEBUG_STREAM = $log
6
20
 
7
21
  # A shortcut to RExchange::Session#new's block syntax
8
22
  def self.open(uri, options = {})
@@ -0,0 +1,45 @@
1
+ require 'rexchange/generic_item'
2
+
3
+ module RExchange
4
+ class Contact < GenericItem
5
+
6
+ attribute_mappings :first_name => 'given_name',
7
+ :middle_name => 'middlename',
8
+ :last_name => 'sn',
9
+ :created_at => 'creationdate',
10
+ :address => 'mailingstreet',
11
+ :city => 'mailingcity',
12
+ :state => 'st',
13
+ :zip_code => 'mailingpostalcode',
14
+ :country => 'co',
15
+ :phone => 'home_phone',
16
+ :business_phone => 'telephone_number',
17
+ :fax => 'facsimiletelephonenumber',
18
+ :email => 'email1',
19
+ :website => 'businesshomepage',
20
+ :company => 'o'
21
+
22
+ def self.query(path)
23
+ <<-QBODY
24
+ <?xml version="1.0"?>
25
+ <D:searchrequest xmlns:D = "DAV:">
26
+ <D:sql>
27
+ SELECT "urn:schemas:contacts:givenName", "urn:schemas:contacts:middlename",
28
+ "urn:schemas:contacts:sn", "urn:schemas:contacts:title",
29
+ "urn:schemas:contacts:mailingstreet", "urn:schemas:contacts:mailingcity",
30
+ "urn:schemas:contacts:st", "urn:schemas:contacts:mailingpostalcode",
31
+ "urn:schemas:contacts:co", "urn:schemas:contacts:homePhone",
32
+ "urn:schemas:contacts:telephoneNumber", "urn:schemas:contacts:facsimiletelephonenumber",
33
+ "urn:schemas:contacts:mobile", "urn:schemas:contacts:email1",
34
+ "urn:schemas:contacts:businesshomepage", "urn:schemas:contacts:o", "DAV:creationdate"
35
+ FROM SCOPE('shallow traversal of "#{path}"')
36
+ WHERE "DAV:ishidden" = false
37
+ AND "DAV:isfolder" = false
38
+ AND "DAV:contentclass" = 'urn:content-classes:person'
39
+ </D:sql>
40
+ </D:searchrequest>
41
+ QBODY
42
+ end
43
+
44
+ end
45
+ end
@@ -1,8 +1,8 @@
1
1
  require 'rexml/document'
2
2
  require 'net/https'
3
- require 'rexchange/extensions'
4
3
  require 'rexchange/dav_search_request'
5
4
  require 'rexchange/message'
5
+ require 'rexchange/contact'
6
6
 
7
7
  module RExchange
8
8
 
@@ -31,8 +31,12 @@ module RExchange
31
31
 
32
32
  # Iterate through each RExchange::Message in this folder
33
33
  def each
34
- messages.each do |msg|
35
- yield msg
34
+ if @folder =~ /^contacts$/i || @parent =~ /\/contacts\//i
35
+ get_contacts
36
+ else
37
+ get_messages
38
+ end.each do |item|
39
+ yield item
36
40
  end
37
41
  end
38
42
 
@@ -46,13 +50,17 @@ module RExchange
46
50
  def messages_in(folder)
47
51
  folder.split('/').inject(@credentials.uri.path) do |final_path, current_path|
48
52
  Folder.new(@credentials, final_path, current_path)
49
- end.messages
53
+ end.get_messages
50
54
  end
51
55
 
52
- def messages
56
+ def get_messages
53
57
  RExchange::Message::find(@credentials, to_s)
54
58
  end
55
59
 
60
+ def get_contacts
61
+ RExchange::Contact::find(@credentials, to_s)
62
+ end
63
+
56
64
  # Join the strings passed in with '/'s between them
57
65
  def self.join(*args)
58
66
  args.collect { |f| f.to_s.ensure_ends_with('/') }.to_s.squeeze('/')
@@ -0,0 +1,64 @@
1
+ require 'rexml/document'
2
+ require 'ostruct'
3
+ require 'rexchange/dav_move_request'
4
+ require 'time'
5
+
6
+ module RExchange
7
+ class GenericItem
8
+ include REXML
9
+ include Enumerable
10
+
11
+ attr_accessor :attributes
12
+
13
+ # Used to access the attributes of the item as a hash.
14
+ def [](key)
15
+ return @attributes[key]
16
+ end
17
+
18
+ # Used to access the attributes of the item.
19
+ def method_missing(sym, *args)
20
+ return @attributes[sym.to_s] if @attributes.include?(sym.to_s)
21
+ end
22
+
23
+ def initialize(session, dav_property_node)
24
+ @attributes = {}
25
+ @session = session
26
+
27
+ dav_property_node.elements.each do |element|
28
+ if element.name.normalize =~ /date$/i
29
+ @attributes[element.name.normalize] = Time::parse(element.text)
30
+ else
31
+ @attributes[element.name.normalize] = element.text
32
+ end
33
+ end
34
+
35
+ return self
36
+ end
37
+
38
+ def self.attribute_mappings(mappings)
39
+ mappings.each_pair do |k,v|
40
+ define_method k do
41
+ @attributes[v]
42
+ end
43
+ end
44
+ end
45
+
46
+ def self.query(path)
47
+ raise 'YOU MUST DEFINE THIS'
48
+ end
49
+
50
+ # Retrieve an Array of items (such as Contact, Message, etc)
51
+ def self.find(credentials, path)
52
+ response = DavSearchRequest.execute(credentials, :body => query(path))
53
+
54
+ items = []
55
+ xpath_query = "//a:propstat[a:status/text() = 'HTTP/1.1 200 OK']/a:prop"
56
+
57
+ Document.new(response.body).elements.each(xpath_query) do |m|
58
+ items << self.new(credentials, m)
59
+ end
60
+
61
+ return items
62
+ end
63
+ end
64
+ end
@@ -1,40 +1,13 @@
1
- require 'rexml/document'
2
- require 'ostruct'
3
- require 'rexchange/dav_move_request'
1
+ require 'rexchange/generic_item'
4
2
 
5
3
  module RExchange
6
- class Message
7
- include REXML
8
- include Enumerable
9
-
10
- attr_accessor :attributes
4
+ class Message < GenericItem
11
5
 
12
6
  def to_s
13
7
  "To: #{to}, From: #{from}, Subject: #{subject}"
14
8
  end
15
9
 
16
- # Used to access the attributes of the message as a hash.
17
- def [](key)
18
- return @attributes[key]
19
- end
20
-
21
- # Used to access the attributes of the message. The following are available:
22
- # * href
23
- # * from
24
- # * to
25
- # * subject
26
- # * message-id
27
- # * date
28
- # * importance
29
- # * hasattachment
30
- def method_missing(sym, *args)
31
- return @attributes[sym.to_s] if @attributes.include?(sym.to_s)
32
- end
33
-
34
- # This is an alias for httpmail:hasattachment attribute.
35
- def has_attachments?
36
- return self['hasattachment']
37
- end
10
+ attribute_mappings 'has_attachments?' => 'hasattachment'
38
11
 
39
12
  # Returns the body of the message. This is either a httpmail:textdescription,
40
13
  # or a httpmail:htmldescription
@@ -42,17 +15,6 @@ module RExchange
42
15
  @attributes['textdescription'] || @attributes['htmldescription']
43
16
  end
44
17
 
45
- def initialize(session, dav_property_node)
46
- @attributes = {}
47
- @session = session
48
-
49
- dav_property_node.elements.each do |element|
50
- @attributes[element.name.tr('-', '_')] = element.text
51
- end
52
-
53
- return self
54
- end
55
-
56
18
  # Move this message to the specified folder.
57
19
  # The folder can be a string such as 'inbox/archive' or a RExchange::Folder.
58
20
  # === Example
@@ -61,15 +23,18 @@ module RExchange
61
23
  # end
62
24
  def move_to(folder)
63
25
  source = URI.parse(self.href).path
64
- destination = @session.uri.path.ensure_ends_with('/') + folder.to_s.ensure_ends_with('/') + source.split('/').last
26
+ destination = if folder.is_a?(RExchange::Folder)
27
+ folder.to_s.ensure_ends_with('/') + source.split('/').last
28
+ else
29
+ @session.uri.path.ensure_ends_with('/') + folder.to_s.ensure_ends_with('/') + source.split('/').last
30
+ end
65
31
 
32
+ $log.debug "move_to: source => \"#{source}\", destination => \"#{destination}\""
66
33
  DavMoveRequest.execute(@session, source, destination)
67
34
  end
68
35
 
69
- # Retrieve an Array of messages in this folder
70
- def Message.find(credentials, path)
71
-
72
- body = <<DABODY
36
+ def self.query(path)
37
+ <<-QBODY
73
38
  <?xml version="1.0"?>
74
39
  <D:searchrequest xmlns:D = "DAV:">
75
40
  <D:sql>
@@ -84,18 +49,7 @@ module RExchange
84
49
  AND "DAV:contentclass" = 'urn:content-classes:message'
85
50
  </D:sql>
86
51
  </D:searchrequest>
87
- DABODY
88
-
89
- response = DavSearchRequest.execute(credentials, :body => body)
90
-
91
- mail_messages = []
92
- xpath_query = "//a:propstat[a:status/text() = 'HTTP/1.1 200 OK']/a:prop"
93
-
94
- Document.new(response.body).elements.each(xpath_query) do |m|
95
- mail_messages << Message.new(credentials, m)
96
- end
97
-
98
- return mail_messages
52
+ QBODY
99
53
  end
100
54
  end
101
55
  end
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.10
3
3
  specification_version: 1
4
4
  name: rexchange
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.1.4
7
- date: 2006-02-01
6
+ version: 0.2.0
7
+ date: 2006-02-23
8
8
  summary: "A simple wrapper around Microsoft Exchange Server's WebDAV API"
9
9
  require_paths:
10
10
  - lib
@@ -31,13 +31,15 @@ files:
31
31
  - README
32
32
  - CHANGELOG
33
33
  - RAKEFILE
34
+ - lib/r_exchange.rb
34
35
  - lib/rexchange.rb
36
+ - lib/rexchange/contact.rb
35
37
  - lib/rexchange/credentials.rb
36
38
  - lib/rexchange/dav_move_request.rb
37
39
  - lib/rexchange/dav_search_request.rb
38
40
  - lib/rexchange/exchange_request.rb
39
- - lib/rexchange/extensions.rb
40
41
  - lib/rexchange/folder.rb
42
+ - lib/rexchange/generic_item.rb
41
43
  - lib/rexchange/message.rb
42
44
  - lib/rexchange/session.rb
43
45
  - test/functional.rb
@@ -1,13 +0,0 @@
1
- class String
2
- def ends_with?(partial)
3
- self[self.size - partial.size..self.size] == partial
4
- end
5
-
6
- def ensure_ends_with(partial)
7
- self.ends_with?(partial) ? self : self + partial
8
- end
9
-
10
- def normalize
11
- self.split(/(?=[A-Z][a-z]*)/).join('_').tr('- ', '_').squeeze('_').downcase
12
- end
13
- end