imap_to_rss 1.0.1 → 1.1
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +0 -0
- data/.autotest +14 -18
- data/History.txt +13 -0
- data/Manifest.txt +6 -0
- data/Rakefile +12 -8
- data/lib/imap_to_rss.rb +7 -7
- data/lib/imap_to_rss/handler/amazon.rb +20 -15
- data/lib/imap_to_rss/handler/hsbc.rb +58 -29
- data/lib/imap_to_rss/handler/itunes.rb +49 -0
- data/lib/imap_to_rss/test_case.rb +66 -0
- data/test/test_imap_to_rss_handler_amazon.rb +737 -0
- data/test/test_imap_to_rss_handler_hsbc.rb +134 -0
- data/test/test_imap_to_rss_handler_itunes.rb +104 -0
- data/test/test_imap_to_rss_handler_ups.rb +72 -0
- metadata +15 -6
- metadata.gz.sig +0 -0
data.tar.gz.sig
CHANGED
Binary file
|
data/.autotest
CHANGED
@@ -2,22 +2,18 @@
|
|
2
2
|
|
3
3
|
require 'autotest/restart'
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
#
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
# end
|
5
|
+
Autotest.add_hook :initialize do |at|
|
6
|
+
|
7
|
+
at.testlib = 'minitest/unit'
|
8
|
+
|
9
|
+
def at.path_to_classname(s)
|
10
|
+
sep = File::SEPARATOR
|
11
|
+
f = s.sub(/^test#{sep}/, '').sub(/\.rb$/, '').split(sep)
|
12
|
+
f = f.map { |path| path.split(/_|(\d+)/).map { |seg| seg.capitalize }.join }
|
13
|
+
f = f.map { |path| path =~ /^Test/ ? path : "Test#{path}" }
|
14
|
+
name = f.join('::').sub 'ImapToRss', 'IMAPToRSS'
|
15
|
+
name.sub 'Hsbc', 'HSBC'
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
20
19
|
|
21
|
-
# Autotest.add_hook :run_command do |at|
|
22
|
-
# system "rake build"
|
23
|
-
# end
|
data/History.txt
CHANGED
@@ -1,3 +1,16 @@
|
|
1
|
+
=== 1.1 / 2009-09-01
|
2
|
+
|
3
|
+
* 1 major enhancement
|
4
|
+
* Added iTunes handler
|
5
|
+
|
6
|
+
* 1 bug fix
|
7
|
+
* Fixed various bugs in the Amazon handler
|
8
|
+
|
9
|
+
=== 1.0.2 / 2009-05-21
|
10
|
+
|
11
|
+
* 1 bug fix
|
12
|
+
* Don't crash when found messages weren't handled
|
13
|
+
|
1
14
|
=== 1.0.1 / 2009-05-18
|
2
15
|
|
3
16
|
* 1 bug fix
|
data/Manifest.txt
CHANGED
@@ -8,4 +8,10 @@ lib/imap_to_rss.rb
|
|
8
8
|
lib/imap_to_rss/handler.rb
|
9
9
|
lib/imap_to_rss/handler/amazon.rb
|
10
10
|
lib/imap_to_rss/handler/hsbc.rb
|
11
|
+
lib/imap_to_rss/handler/itunes.rb
|
11
12
|
lib/imap_to_rss/handler/ups.rb
|
13
|
+
lib/imap_to_rss/test_case.rb
|
14
|
+
test/test_imap_to_rss_handler_amazon.rb
|
15
|
+
test/test_imap_to_rss_handler_hsbc.rb
|
16
|
+
test/test_imap_to_rss_handler_itunes.rb
|
17
|
+
test/test_imap_to_rss_handler_ups.rb
|
data/Rakefile
CHANGED
@@ -2,16 +2,20 @@
|
|
2
2
|
|
3
3
|
require 'rubygems'
|
4
4
|
require 'hoe'
|
5
|
-
$:.unshift 'lib'
|
6
|
-
require 'imap_to_rss'
|
7
5
|
|
8
|
-
Hoe.
|
9
|
-
itor.rubyforge_name = 'seattlerb'
|
10
|
-
itor.developer 'Eric Hodel', 'drbrain@example.com'
|
6
|
+
Hoe.add_include_dirs "../../imap_processor/dev/lib"
|
11
7
|
|
12
|
-
|
13
|
-
|
14
|
-
|
8
|
+
Hoe.plugin :seattlerb
|
9
|
+
|
10
|
+
Hoe.spec 'imap_to_rss' do
|
11
|
+
developer 'Eric Hodel', 'drbrain@example.com'
|
12
|
+
|
13
|
+
self.rubyforge_name = 'seattlerb'
|
14
|
+
self.testlib = :minitest
|
15
|
+
|
16
|
+
extra_deps << ['imap_processor', '~> 1.1']
|
17
|
+
extra_deps << ['nokogiri', '~> 1.2']
|
18
|
+
extra_deps << ['tmail', '~> 1.2']
|
15
19
|
end
|
16
20
|
|
17
21
|
# vim: syntax=Ruby
|
data/lib/imap_to_rss.rb
CHANGED
@@ -14,7 +14,7 @@ class IMAPToRSS < IMAPProcessor
|
|
14
14
|
##
|
15
15
|
# The version of IMAPToRSS you are using
|
16
16
|
|
17
|
-
VERSION = '1.
|
17
|
+
VERSION = '1.1'
|
18
18
|
|
19
19
|
##
|
20
20
|
# A Struct representing an RSS item for the RSS feed. Contains fields
|
@@ -70,7 +70,7 @@ class IMAPToRSS < IMAPProcessor
|
|
70
70
|
##
|
71
71
|
# Creates a new IMAPToRSS and connects to the selected server.
|
72
72
|
|
73
|
-
def initialize(options)
|
73
|
+
def initialize(options = {})
|
74
74
|
super
|
75
75
|
|
76
76
|
@handlers = []
|
@@ -177,13 +177,13 @@ class IMAPToRSS < IMAPProcessor
|
|
177
177
|
|
178
178
|
handled = handler.handle messages
|
179
179
|
|
180
|
+
# only tag handled messages, examined messages may be handled in the
|
181
|
+
# future
|
182
|
+
next if handled.empty?
|
183
|
+
|
180
184
|
@imap.store handled, '+FLAGS', %w[IMAP_TO_RSS]
|
181
185
|
|
182
|
-
if dest_mailbox
|
183
|
-
@imap.copy handled, dest_mailbox
|
184
|
-
@imap.store handled, '+FLAGS', [:Deleted]
|
185
|
-
@imap.expunge
|
186
|
-
end
|
186
|
+
move_messages handled, dest_mailbox if dest_mailbox
|
187
187
|
end
|
188
188
|
|
189
189
|
build_rss
|
@@ -86,11 +86,11 @@ class IMAPToRSS::Handler::Amazon < IMAPToRSS::Handler
|
|
86
86
|
|
87
87
|
def aws_bill
|
88
88
|
@mail.body =~ /^Total: (.*)/
|
89
|
-
total = $1
|
89
|
+
total = $1.strip
|
90
90
|
|
91
91
|
@mail.body =~ /^(http.*)/
|
92
92
|
|
93
|
-
add_item "Amazon Web Services Bill: #{total}", '', $1
|
93
|
+
add_item "Amazon Web Services Bill: #{total}", '', $1.strip
|
94
94
|
end
|
95
95
|
|
96
96
|
##
|
@@ -99,20 +99,20 @@ class IMAPToRSS::Handler::Amazon < IMAPToRSS::Handler
|
|
99
99
|
def gift_card
|
100
100
|
url = "https://www.amazon.com/gp/css/account/payment/view-gc-balance.html"
|
101
101
|
@mail.body =~ /^Amount: (.*)/
|
102
|
-
amount = $1
|
102
|
+
amount = $1.strip
|
103
103
|
|
104
104
|
@mail.body =~ /^From: (.*)/
|
105
|
-
from = $1
|
105
|
+
from = $1.strip
|
106
106
|
|
107
107
|
@mail.body =~ /^Gift Message: (.*)/
|
108
|
-
message = $1
|
108
|
+
message = $1.strip
|
109
109
|
|
110
110
|
@mail.body =~ /^Claim code (.*)/
|
111
|
-
claim_code = $1
|
111
|
+
claim_code = $1.strip
|
112
112
|
|
113
113
|
subject = "Amazon Gift Card from #{from} - #{amount}!"
|
114
114
|
|
115
|
-
description = "<p><strong>#{from}
|
115
|
+
description = "<p><strong>#{from} sent you a #{amount} gift card!</strong>\n\n"
|
116
116
|
description << "<p>#{message}\n\n"
|
117
117
|
description << "<h2>#{claim_code}</h2>\n\n"
|
118
118
|
description << "<p><a href=\"#{url}\">Claim your gift card</a>"
|
@@ -130,8 +130,8 @@ class IMAPToRSS::Handler::Amazon < IMAPToRSS::Handler
|
|
130
130
|
items = @mail.body.scan(/(\d?) of (.*)/)
|
131
131
|
|
132
132
|
url = order_url order_number
|
133
|
-
subject = "Amazon order
|
134
|
-
description = "<p>You
|
133
|
+
subject = "Amazon order cancellation #{order_number}"
|
134
|
+
description = "<p>You cancelled your order:\n\n"
|
135
135
|
|
136
136
|
description << order_table(items)
|
137
137
|
|
@@ -143,28 +143,33 @@ class IMAPToRSS::Handler::Amazon < IMAPToRSS::Handler
|
|
143
143
|
|
144
144
|
def order_shipped
|
145
145
|
@mail.body =~ /^(The following items .*?:\r\n.*?)(Shipping Carrier|Item Subtotal)/m
|
146
|
+
|
146
147
|
items = $1.map do |item|
|
147
148
|
next unless item =~ /\d+\s(.*?)\$[\d.]+\s+(\d+)/
|
148
149
|
[$2, $1.strip]
|
149
150
|
end.compact
|
150
151
|
|
151
|
-
carrier = $1.strip if
|
152
|
+
carrier = $1.strip if
|
153
|
+
@mail.body =~ /(?:Shipping Carrier:|Shipped via) (.*)/
|
152
154
|
date = $1.strip if @mail.body =~ /Ship Date: (.*)/
|
153
155
|
speed = $1.strip if @mail.body =~ /Shipping Speed: (.*)/
|
154
|
-
tracking_number = $1.strip if
|
156
|
+
tracking_number = $1.strip if
|
157
|
+
@mail.body =~ /(?:Carrier Tracking ID|Tracking number): (.*)/
|
155
158
|
|
156
|
-
@mail.body =~ /Your shipping address:\r\n\r\n(.*?)\r\n\r\n/m
|
159
|
+
@mail.body =~ /(?:Your shipping address|This shipment was sent to):\r\n\r\n(.*?)\r\n\r\n/m
|
157
160
|
address = $1.split("\n").map { |line| line.strip }.join "<br />\n" if $1
|
158
161
|
|
159
162
|
if tracking_number then
|
160
163
|
url = case carrier
|
161
164
|
when 'USPS' then
|
162
|
-
|
165
|
+
"http://trkcnfrm1.smi.usps.com/PTSInternetWeb/InterLabelInquiry.do?strOrigTrackNum=#{tracking_number}"
|
163
166
|
when 'FedEx' then
|
164
|
-
|
167
|
+
"http://fedex.com/Tracking?tracknumbers=#{tracking_number}"
|
168
|
+
when 'UPS' then
|
169
|
+
"http://wwwapps.ups.com/WebTracking/processInputRequest?InquiryNumber1=#{tracking_number}"
|
165
170
|
else
|
166
171
|
log "Unknown carrier: %p" % carrier
|
167
|
-
|
172
|
+
"http://www.google.com/search?q=#{tracking_number}"
|
168
173
|
end
|
169
174
|
end
|
170
175
|
|
@@ -18,47 +18,76 @@ class IMAPToRSS::Handler::HSBC < IMAPToRSS::Handler
|
|
18
18
|
|
19
19
|
def handle(uids)
|
20
20
|
each_message uids, 'text/plain' do |uid, mail|
|
21
|
-
|
22
|
-
|
21
|
+
@mail = mail
|
22
|
+
@url = nil
|
23
|
+
@description = nil
|
23
24
|
|
24
25
|
case mail.from.first
|
25
|
-
when 'HSBC@email.hsbcusa.com' then
|
26
|
-
mail.body =~ /^Dear.*?,
|
27
|
-
([ \t]*\r?\n){2,}
|
28
|
-
(.*?)
|
29
|
-
([ \t]*\r?\n){2,}/mx
|
30
|
-
next false unless $2
|
31
|
-
|
32
|
-
description = $2
|
33
26
|
when 'A2ATransfer@us.hsbc.com' then
|
34
|
-
|
35
|
-
([ \t]*\r?\n){2,}
|
36
|
-
(.*?)
|
37
|
-
([ \t]*\r?\n){2,}
|
38
|
-
Sincerely,/mx
|
39
|
-
next false unless $2
|
40
|
-
|
41
|
-
body = $2
|
42
|
-
|
43
|
-
body.gsub!(/[*\r]/, '')
|
44
|
-
body.gsub!(/[ \t]*\n/, "\n")
|
45
|
-
body = body.split(/\n\n+/).map { |para| "<p>#{para}</p>" }
|
46
|
-
|
47
|
-
description = body.join "\n\n"
|
27
|
+
next false unless handle_a2atransfer
|
48
28
|
when 'alerts@email.hsbcusa.com' then
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
url = $1
|
29
|
+
next false unless handle_alert
|
30
|
+
when 'HSBC@email.hsbcusa.com' then
|
31
|
+
next false unless handle_hsbc
|
53
32
|
else
|
54
33
|
log "Unknown From: #{mail.from.join ', '}"
|
55
34
|
next false
|
56
35
|
end
|
57
36
|
|
58
|
-
add_item mail.subject, description, mail.from, mail.date, url,
|
37
|
+
add_item mail.subject, @description, mail.from, mail.date, @url,
|
59
38
|
mail.message_id, 'HSBC'
|
60
39
|
end
|
61
40
|
end
|
62
41
|
|
42
|
+
def handle_a2atransfer
|
43
|
+
@mail.body =~ /^Dear.*?[,:]
|
44
|
+
([ \t]*\r?\n){2,}
|
45
|
+
(.*?)
|
46
|
+
([ \t]*\r?\n){2,}
|
47
|
+
Sincerely,/mx
|
48
|
+
|
49
|
+
return false unless $2
|
50
|
+
|
51
|
+
body = $2
|
52
|
+
|
53
|
+
body.gsub!(/[*\r]/, '')
|
54
|
+
body.gsub!(/[ \t]*\n/, "\n")
|
55
|
+
body = body.split(/\n\n+/).map { |para| "<p>#{para}</p>" }
|
56
|
+
|
57
|
+
@description = body.join "\n\n"
|
58
|
+
end
|
59
|
+
|
60
|
+
def handle_alert
|
61
|
+
@mail.body =~ /^Dear.*?,
|
62
|
+
([ \t]*\r?\n){2,}
|
63
|
+
(.*?)
|
64
|
+
([ \t]*\r?\n){2,}/mx
|
65
|
+
return false unless $2
|
66
|
+
|
67
|
+
@description = $2
|
68
|
+
end
|
69
|
+
|
70
|
+
def handle_hsbc
|
71
|
+
case @mail.body
|
72
|
+
when /purchase exceeding/ then
|
73
|
+
@mail.body =~ /Description: (.*)/
|
74
|
+
purchase = $1.strip
|
75
|
+
@mail.body =~ /^Amount: \$\s+([\d.]+)/
|
76
|
+
amount = $1
|
77
|
+
|
78
|
+
@description = <<-DESC
|
79
|
+
<p>Your purchase of #{purchase} was for $#{amount} which exceeds your
|
80
|
+
notification limit
|
81
|
+
DESC
|
82
|
+
when /^Dear.*?,
|
83
|
+
([ \t]*\r?\n){2,}
|
84
|
+
(.*?)
|
85
|
+
([ \t]*\r?\n){2,}/mx
|
86
|
+
@description = $2
|
87
|
+
end
|
88
|
+
|
89
|
+
return false unless @description
|
90
|
+
end
|
91
|
+
|
63
92
|
end
|
64
93
|
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'imap_to_rss/handler'
|
2
|
+
|
3
|
+
##
|
4
|
+
# Processes iTunes receipts
|
5
|
+
|
6
|
+
class IMAPToRSS::Handler::Itunes < IMAPToRSS::Handler
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@search = 'FROM', 'itunes'
|
10
|
+
end
|
11
|
+
|
12
|
+
def handle(uids)
|
13
|
+
each_message uids, 'text/plain' do |uid, mail|
|
14
|
+
body = ''
|
15
|
+
mail.body =~ /Order Number: ([^\s]*)/
|
16
|
+
order_number = $1
|
17
|
+
|
18
|
+
next false unless order_number
|
19
|
+
|
20
|
+
mail.body =~ /Order Total: (\$[\d.]+)/
|
21
|
+
total = $1
|
22
|
+
|
23
|
+
mail.body =~ /Purchase History:.*?(https:.*?)\r/m
|
24
|
+
url = $1
|
25
|
+
|
26
|
+
mail.body =~ /^Item\sNumber.*?
|
27
|
+
(^-+\r?\n)
|
28
|
+
(.*?)
|
29
|
+
\1/mx
|
30
|
+
|
31
|
+
body << "<table>\n<tr><th>Item<th>Price\n"
|
32
|
+
|
33
|
+
$2.scan(/^([^\s]+)\s+(.*?)\s+(Free|\$[\d.]+)/) do |item, name, price|
|
34
|
+
body << "<tr><td>#{name}<td>#{price}\n"
|
35
|
+
end
|
36
|
+
|
37
|
+
body << "</table>\n"
|
38
|
+
|
39
|
+
body << "<p>Total: #{total}"
|
40
|
+
|
41
|
+
subject = "iTunes Receipt ##{order_number}, #{total}"
|
42
|
+
|
43
|
+
add_item subject, body, mail.from, mail.date, url,
|
44
|
+
mail.message_id, 'iTunes'
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'imap_to_rss'
|
3
|
+
|
4
|
+
# :stopdoc:
|
5
|
+
class IMAPToRSS
|
6
|
+
def connect(*args)
|
7
|
+
o = Object.new
|
8
|
+
def o.imap() end
|
9
|
+
o
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class IMAPToRSS::Handler
|
14
|
+
attr_accessor :mail
|
15
|
+
end
|
16
|
+
# :startdoc:
|
17
|
+
|
18
|
+
##
|
19
|
+
# Test case for IMAPToRSS handlers
|
20
|
+
|
21
|
+
class IMAPToRSS::TestCase < MiniTest::Unit::TestCase
|
22
|
+
|
23
|
+
##
|
24
|
+
# Sets this test case up with +handler+. Provides instance variables
|
25
|
+
# <tt>@itor</tt> and <tt>@handler</tt>
|
26
|
+
|
27
|
+
def setup(handler)
|
28
|
+
@itor = IMAPToRSS.new
|
29
|
+
@handler = handler
|
30
|
+
@handler.setup @itor
|
31
|
+
end
|
32
|
+
|
33
|
+
##
|
34
|
+
# Returns a new TMail::Mail from +options+. Defaults are:
|
35
|
+
#
|
36
|
+
# from:: from@example.com
|
37
|
+
# date:: Time.at 0
|
38
|
+
# to:: to@example.com
|
39
|
+
# subject:: subject for this mail
|
40
|
+
# body:: Hi! I'm a body!
|
41
|
+
#
|
42
|
+
# The mail body will be normalized to \r\n line breaks.
|
43
|
+
|
44
|
+
def util_mail(options = {})
|
45
|
+
options = {
|
46
|
+
:from => 'from@example.com',
|
47
|
+
:date => Time.at(0),
|
48
|
+
:to => 'to@example.com',
|
49
|
+
:subject => 'subject for this mail',
|
50
|
+
:body => 'Hi! I\'m a body!'
|
51
|
+
}.merge options
|
52
|
+
|
53
|
+
body = options[:body].split(/\r?\n/).join "\r\n"
|
54
|
+
|
55
|
+
TMail::Mail.parse <<-MAIL
|
56
|
+
From: #{options[:from]}\r
|
57
|
+
Date: #{options[:date].rfc2822}\r
|
58
|
+
To: #{options[:to]}\r
|
59
|
+
Subject: #{options[:subject]}\r
|
60
|
+
\r
|
61
|
+
#{body}
|
62
|
+
MAIL
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|