bodyparts 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +1 -1
- data/VERSION +1 -1
- data/bodyparts.gemspec +2 -2
- data/lib/bodyparts.rb +36 -23
- data/spec/bodyparts_spec.rb +12 -3
- data/spec/spec_helper.rb +15 -4
- metadata +3 -3
data/README.rdoc
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.2
|
data/bodyparts.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{bodyparts}
|
8
|
-
s.version = "0.1.
|
8
|
+
s.version = "0.1.2"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Max Ogden"]
|
12
|
-
s.date = %q{2010-06-
|
12
|
+
s.date = %q{2010-06-10}
|
13
13
|
s.description = %q{Separates new messages from included reply chains in the body of forwarded emails}
|
14
14
|
s.email = %q{max@maxogden.com}
|
15
15
|
s.extra_rdoc_files = [
|
data/lib/bodyparts.rb
CHANGED
@@ -1,32 +1,45 @@
|
|
1
1
|
require 'mail'
|
2
|
+
require 'tmail'
|
2
3
|
|
3
4
|
class BodyParts
|
4
|
-
def self.
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
5
|
+
def self.rules
|
6
|
+
[{ :server => 'Gmail', :reply_delimiter => /^On.*?wrote:.$/m },
|
7
|
+
{ :server => 'Yahoo! Mail', :reply_delimiter => /^_+\r\nFrom:/ },
|
8
|
+
{ :server => 'Microsoft Live Mail/Hotmail', :reply_delimiter => /\r\n\r\n(Date|Subject):/ },
|
9
|
+
{ :server => 'Outlook Express/AOL Webmail', :reply_delimiter => /^-+.*Original Message.*-+/ }]
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.extract_tmail_attributes(tmail_object)
|
13
|
+
message_id = tmail_object.message_id
|
14
|
+
x_mailer = tmail_object['x-mailer'].to_s
|
15
|
+
body = if tmail_object.multipart?
|
16
|
+
tmail_object.parts.first.body
|
17
|
+
else
|
18
|
+
tmail_object.body
|
19
|
+
end
|
20
|
+
{:message_id => message_id, :x_mailer => x_mailer, :body => body}
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.extract_mail_attributes(mail_object)
|
24
|
+
message_id = mail_object['message_id']
|
25
|
+
x_mailer = mail_object['x-mailer']
|
23
26
|
|
24
|
-
if
|
25
|
-
body =
|
27
|
+
if mail_object.multipart?
|
28
|
+
body = mail_object.parts.first.body.raw_source
|
26
29
|
else
|
27
|
-
body =
|
30
|
+
body = mail_object.body.raw_source
|
31
|
+
end
|
32
|
+
{:message_id => message_id, :x_mailer => x_mailer, :body => body}
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.find_reply_in(email)
|
36
|
+
email = Mail::Message.new(email) if email.is_a? String
|
37
|
+
mail_attributes = case email.class.to_s
|
38
|
+
when "TMail::Mail" then extract_tmail_attributes(email)
|
39
|
+
when "Mail::Message" then extract_mail_attributes(email)
|
40
|
+
else raise "You must pass in either a TMail or Mail object or raw email source text"
|
28
41
|
end
|
29
|
-
|
42
|
+
body = mail_attributes[:body]
|
30
43
|
matches = rules.map {|rule| body.match(rule[:reply_delimiter])}.compact!
|
31
44
|
unless matches.empty?
|
32
45
|
match = matches.sort_by {|m| m.begin(0)}.first
|
data/spec/bodyparts_spec.rb
CHANGED
@@ -1,23 +1,32 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
2
|
|
3
3
|
describe "BodyParts" do
|
4
|
+
|
5
|
+
[TMail::Mail, Mail].each do |mail_object|
|
6
|
+
it "should accept and parse #{mail_object} objects as input" do
|
7
|
+
generic = FakeMessage.fake_emails[:generic]
|
8
|
+
message = FakeMessage.new_mail(mail_object, generic[:headers])
|
9
|
+
BodyParts.find_reply_in(message)[:new_message].should == generic[:reply_text]
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
4
13
|
%w(gmail yahoo hotmail aol_webmail generic).each do |mail_server|
|
5
14
|
it "should strip out the replies from a #{mail_server} message containing forwarded junk" do
|
6
15
|
mail_server = FakeMessage.fake_emails[mail_server.to_sym]
|
7
|
-
message = FakeMessage.new_mail(mail_server[:headers])
|
16
|
+
message = FakeMessage.new_mail(Mail, mail_server[:headers])
|
8
17
|
BodyParts.find_reply_in(message.to_s)[:new_message].should == mail_server[:reply_text]
|
9
18
|
end
|
10
19
|
end
|
11
20
|
|
12
21
|
it "should always use the first reply delimiter in a message containing multiple replies" do
|
13
22
|
multiple_replies = FakeMessage.fake_emails[:multiple_replies]
|
14
|
-
message = FakeMessage.new_mail(multiple_replies[:headers])
|
23
|
+
message = FakeMessage.new_mail(Mail, multiple_replies[:headers])
|
15
24
|
BodyParts.find_reply_in(message.to_s)[:new_message].should == multiple_replies[:reply_text]
|
16
25
|
end
|
17
26
|
|
18
27
|
it "should return the rest of the thread" do
|
19
28
|
generic = FakeMessage.fake_emails[:generic]
|
20
|
-
message = FakeMessage.new_mail(generic[:headers])
|
29
|
+
message = FakeMessage.new_mail(Mail, generic[:headers])
|
21
30
|
BodyParts.find_reply_in(message.to_s).should == {:new_message => generic[:reply_text], :rest_of_thread => generic[:rest_of_thread].gsub("\n", "\r\n").strip}
|
22
31
|
end
|
23
32
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -16,13 +16,24 @@ class FakeMessage
|
|
16
16
|
}
|
17
17
|
end
|
18
18
|
|
19
|
-
def self.new_mail(custom_headers={})
|
19
|
+
def self.new_mail(mail_class, custom_headers={})
|
20
20
|
headers = default_mail_headers.merge(custom_headers)
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
|
22
|
+
mail = mail_class.new do
|
23
|
+
if mail_class == Mail
|
24
|
+
text_part do
|
25
|
+
body headers.delete("body")
|
26
|
+
end
|
24
27
|
end
|
25
28
|
end
|
29
|
+
|
30
|
+
if mail_class == TMail::Mail
|
31
|
+
%w(body from to).each do |attr|
|
32
|
+
mail.send "#{attr}=", headers[attr]
|
33
|
+
headers.delete attr
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
26
37
|
headers.each {|header, content| mail[header] = content }
|
27
38
|
mail
|
28
39
|
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
version: 0.1.
|
8
|
+
- 2
|
9
|
+
version: 0.1.2
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Max Ogden
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-06-
|
17
|
+
date: 2010-06-10 00:00:00 -07:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|