imap_to_rss 1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1 @@
1
+ +������x�@fj/g�p_sFMUr�@�h ��,31��ލ�e�z���G�lf��zO�2�r�R �|�x��"�i�=z�U�6)��R��U�ڈ��dl��X�k<�B;m��ʖ�ua<e>q�=�>͐x�����i���;tC�q���$��Mb��ZAgy[h�ɖ�H�����">
@@ -0,0 +1,23 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'autotest/restart'
4
+
5
+ # Autotest.add_hook :initialize do |at|
6
+ # at.extra_files << "../some/external/dependency.rb"
7
+ #
8
+ # at.libs << ":../some/external"
9
+ #
10
+ # at.add_exception 'vendor'
11
+ #
12
+ # at.add_mapping(/dependency.rb/) do |f, _|
13
+ # at.files_matching(/test_.*rb$/)
14
+ # end
15
+ #
16
+ # %w(TestA TestB).each do |klass|
17
+ # at.extra_class_map[klass] = "test/test_misc.rb"
18
+ # end
19
+ # end
20
+
21
+ # Autotest.add_hook :run_command do |at|
22
+ # system "rake build"
23
+ # end
@@ -0,0 +1,6 @@
1
+ === 1.0 / 2009-05-14
2
+
3
+ * 1 major enhancement
4
+
5
+ * Birthday!
6
+
@@ -0,0 +1,11 @@
1
+ .autotest
2
+ History.txt
3
+ Manifest.txt
4
+ README.txt
5
+ Rakefile
6
+ bin/imap_to_rss
7
+ lib/imap_to_rss.rb
8
+ lib/imap_to_rss/handler.rb
9
+ lib/imap_to_rss/handler/amazon.rb
10
+ lib/imap_to_rss/handler/hsbc.rb
11
+ lib/imap_to_rss/handler/ups.rb
@@ -0,0 +1,53 @@
1
+ = imap_to_rss
2
+
3
+ * http://seattlerb.rubyforge.org/imap_to_rss
4
+
5
+ == DESCRIPTION:
6
+
7
+ IMAPToRSS turns messages on an IMAP server into RSS entries when the match a
8
+ handler. Included handlers work for email from Amazon, HSBC and UPS.
9
+ IMAPToRSS automatically loads handlers for any other mail.
10
+
11
+ == SYNOPSIS:
12
+
13
+ $ imap_to_rss --boxes INBOX --move _Money
14
+ [...]
15
+ $ open imap_to_rss.rss
16
+
17
+ See IMAPToRSS::Handler for instructions on writing a handler.
18
+
19
+ == REQUIREMENTS:
20
+
21
+ * An IMAP server
22
+ * imap_processor
23
+ * Email matching one of the handlers
24
+
25
+ == INSTALL:
26
+
27
+ * gem install imap_to_rss
28
+ * add imap_to_rss to your crontab
29
+
30
+ == LICENSE:
31
+
32
+ (The MIT License)
33
+
34
+ Copyright (c) 2009 Eric Hodel
35
+
36
+ Permission is hereby granted, free of charge, to any person obtaining
37
+ a copy of this software and associated documentation files (the
38
+ 'Software'), to deal in the Software without restriction, including
39
+ without limitation the rights to use, copy, modify, merge, publish,
40
+ distribute, sublicense, and/or sell copies of the Software, and to
41
+ permit persons to whom the Software is furnished to do so, subject to
42
+ the following conditions:
43
+
44
+ The above copyright notice and this permission notice shall be
45
+ included in all copies or substantial portions of the Software.
46
+
47
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
48
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
49
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
50
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
51
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
52
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
53
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,17 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+ $:.unshift 'lib'
6
+ require 'imap_to_rss'
7
+
8
+ Hoe.new 'imap_to_rss', IMAPToRSS::VERSION do |itor|
9
+ itor.rubyforge_name = 'seattlerb'
10
+ itor.developer 'Eric Hodel', 'drbrain@example.com'
11
+
12
+ itor.extra_deps << ['imap_processor', '~> 1.0']
13
+ itor.extra_deps << ['nokogiri', '~> 1.2']
14
+ itor.extra_deps << ['tmail', '~> 1.2']
15
+ end
16
+
17
+ # vim: syntax=Ruby
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'imap_to_rss'
4
+
5
+ IMAPToRSS.run ARGV
6
+
@@ -0,0 +1,201 @@
1
+ require 'rubygems'
2
+ require 'imap_processor'
3
+ require 'tmail'
4
+ require 'nokogiri'
5
+
6
+ ##
7
+ # IMAPToRSS takes messages from your mailboxes, runs them through handlers,
8
+ # then turns them into an RSS feed. Handlers can be added via a plugin system
9
+ # so long as they subclass IMAPToRSS::Handler and live in the
10
+ # <tt>imap_to_rss/handler/</tt> directory.
11
+
12
+ class IMAPToRSS < IMAPProcessor
13
+
14
+ ##
15
+ # The version of IMAPToRSS you are using
16
+
17
+ VERSION = '1.0'
18
+
19
+ ##
20
+ # A Struct representing an RSS item for the RSS feed. Contains fields
21
+ # +title+, +description+, +author+, +pub_date+, +link+, +guid+, and
22
+ # +category+.
23
+ #
24
+ # Typically, the message id of the email can be used for the guid. When
25
+ # the RSS feed is generated, the guid is never used as a URL (isPermaLink is
26
+ # set to false).
27
+
28
+ RSSItem = Struct.new :title, :description, :author, :pub_date,
29
+ :link, :guid, :category
30
+
31
+ ##
32
+ # All added RSS items
33
+
34
+ attr_reader :rss_items
35
+
36
+ ##
37
+ # Processes command-line options
38
+
39
+ def self.process_args(args)
40
+ required_args = {
41
+ :Output => 'imap_to_rss.rss'
42
+ }
43
+
44
+ add_move
45
+
46
+ super __FILE__, args, required_args do |opts, options|
47
+ handlers = IMAPToRSS::Handler.handlers.map do |handler|
48
+ handler.name.split('::').last
49
+ end
50
+
51
+ opts.separator ''
52
+ opts.separator "Handlers: #{handlers.join ', '}"
53
+ opts.separator ''
54
+
55
+ opts.on("--handler=HANDLER", handlers,
56
+ "Handler to run",
57
+ "Default: all handlers") do |handler|
58
+ options[:Handler] = handler
59
+ end
60
+
61
+ opts.on("--output=FILE",
62
+ "File to write the RSS feed to",
63
+ "Default: #{options[:Output]}",
64
+ "Options file name: File") do |file|
65
+ options[:Output] = file
66
+ end
67
+ end
68
+ end
69
+
70
+ ##
71
+ # Creates a new IMAPToRSS and connects to the selected server.
72
+
73
+ def initialize(options)
74
+ super
75
+
76
+ @handlers = []
77
+ @rss_items = []
78
+ @output = options[:Output]
79
+
80
+ connection = connect options[:Host], options[:Port], options[:SSL],
81
+ options[:Username], options[:Password], options[:Auth]
82
+
83
+ @imap = connection.imap
84
+ end
85
+
86
+ ##
87
+ # Builds an RSS feed from rss_items
88
+
89
+ def build_rss
90
+ log 'Building RSS feed'
91
+ rss = Nokogiri::XML::Builder.new
92
+
93
+ rss_items = @rss_items.sort_by { |rss_item| rss_item.pub_date }
94
+ host = options[:Host]
95
+
96
+ copyover = []
97
+
98
+ if File.exist? @output then
99
+ doc = nil
100
+
101
+ open @output, 'rb' do |io| doc = Nokogiri::XML io end
102
+
103
+ copyover_count = 50 - rss_items.length
104
+
105
+ if copyover_count > 0 then
106
+ items = doc.xpath('//rss/channel/item')
107
+
108
+ index = [copyover_count, items.length].min
109
+
110
+ copyover = items.to_a[-index..-1]
111
+ end
112
+ end
113
+
114
+ rss.rss :version => '2.0' do
115
+ rss.channel do
116
+ rss.title 'IMAP to RSS'
117
+ rss.description "An RSS feed built from your IMAP server"
118
+ rss.generator "imap_to_rss version #{IMAPToRSS::VERSION}"
119
+ rss.docs 'http://cyber.law.harvard.edu/rss/rss.html'
120
+
121
+ copyover.each do |item|
122
+ rss.send :insert, item
123
+ end
124
+
125
+ rss_items.each do |item|
126
+ rss.item do
127
+ rss.title item.title
128
+ rss.description item.description
129
+ rss.author item.author
130
+ rss.pubDate item.pub_date.rfc822
131
+ rss.link item.link if item.link
132
+ rss.guid item.guid, :isPermaLink => false if item.guid
133
+ rss.category item.category if item.category
134
+ end
135
+ end
136
+ end
137
+ end
138
+
139
+ open @output, 'w' do |io|
140
+ io.write rss.to_xml
141
+ end
142
+
143
+ log 'Saved RSS feed'
144
+ end
145
+
146
+ ##
147
+ # Processes mailboxes with each handler then writes out the RSS file.
148
+
149
+ def run
150
+ handlers = IMAPToRSS::Handler.handlers
151
+
152
+ handlers.delete_if do |handler|
153
+ handler.name.split('::').last != options[:Handler]
154
+ end if options[:Handler]
155
+
156
+ handlers = handlers.map do |handler|
157
+ handler = handler.new
158
+ handler.setup self
159
+ handler
160
+ end
161
+
162
+ dest_mailbox = options[:MoveTo]
163
+
164
+ @boxes.each do |mailbox|
165
+ @imap.select mailbox
166
+ log "Selected mailbox #{mailbox}"
167
+
168
+ handlers.each do |handler|
169
+ log "Running handler #{handler.search.join ' '}"
170
+ messages = @imap.search [
171
+ 'NOT', 'DELETED',
172
+ 'NOT', 'KEYWORD', 'IMAP_TO_RSS',
173
+ *handler.search
174
+ ]
175
+
176
+ next if messages.empty?
177
+
178
+ handled = handler.handle messages
179
+
180
+ @imap.store handled, '+FLAGS', %w[IMAP_TO_RSS]
181
+
182
+ if dest_mailbox then
183
+ @imap.copy handled, dest_mailbox
184
+ @imap.store handled, '+FLAGS', [:Deleted]
185
+ @imap.expunge
186
+ end
187
+ end
188
+
189
+ build_rss
190
+ end
191
+ end
192
+
193
+ end
194
+
195
+ plugins = Gem.find_files 'imap_to_rss/handler/*'
196
+
197
+ plugins.each do |plugin|
198
+ # strip path info to always require latest
199
+ require plugin.sub(/.*(imap_to_rss.handler.*)\.[^.]+$/, '\1')
200
+ end
201
+
@@ -0,0 +1,101 @@
1
+ require 'imap_to_rss'
2
+ require 'time'
3
+
4
+ ##
5
+ # Base message handler class. Subclass this to define your own handlers, and
6
+ # override the #initialize and #handle methods.
7
+ #
8
+ # To have the handler automatically be picked up by IMAPToRSS, place it in the
9
+ # <tt>imap_to_rss/handler/</tt> directory.
10
+
11
+ class IMAPToRSS::Handler
12
+
13
+ ##
14
+ # IMAP SEARCH command keywords to search
15
+
16
+ attr_accessor :search
17
+
18
+ @handlers = []
19
+
20
+ ##
21
+ # Collect handler subclasses
22
+
23
+ def self.inherited(subclass)
24
+ @handlers << subclass
25
+ end
26
+
27
+ ##
28
+ # List of found handlers
29
+
30
+ def self.handlers
31
+ @handlers
32
+ end
33
+
34
+ ##
35
+ # :method: initialize
36
+ #
37
+ # Override and set <tt>@search</tt> to IMAP search terms for the messages
38
+ # you're interested in. (Usually something simple like 'FROM', 'amazon' is
39
+ # enough.) Deleted messages and previously handled messages will be
40
+ # automatically ignored.
41
+ #
42
+ # You can tell imap_to_rss to re-scan messages by clearing the IMAP_TO_RSS
43
+ # keyword with imap_keywords:
44
+ #
45
+ # imap_keywords --no-list --keywords IMAP_TO_RSS --delete
46
+
47
+ ##
48
+ # Adds an item to the RSS feed with given parts
49
+
50
+ def add_item(title, description, author, pub_date, link = nil, guid = nil,
51
+ category = nil)
52
+ pub_date = case pub_date
53
+ when Time then
54
+ pub_date
55
+ when Date, DateTime then
56
+ Time.parse pub_date.to_s
57
+ else
58
+ Time.parse pub_date
59
+ end
60
+
61
+ item = IMAPToRSS::RSSItem.new title, description, author, pub_date, link,
62
+ guid, category
63
+
64
+ @itor.rss_items << item
65
+ end
66
+
67
+ ##
68
+ # Delegates to IMAPToRSS#each_message
69
+
70
+ def each_message(*args, &block)
71
+ @itor.each_message(*args, &block)
72
+ end
73
+
74
+ ##
75
+ # Guts of the handler, implement this yourself. It should call #add_item
76
+ # for each message found.
77
+ #
78
+ # See IMAPToRSS::Handler::UPS for a simple handler,
79
+ # IMAPToRSS::Handler::Amazon for a complex one.
80
+
81
+ def handle(uids)
82
+ raise NotImplementedError, 'write me'
83
+ end
84
+
85
+ ##
86
+ # Delegates to IMAPToRSS
87
+
88
+ def log(*args)
89
+ @itor.log(*args)
90
+ end
91
+
92
+ ##
93
+ # Sets up delegators to IMAPToRSS
94
+
95
+ def setup(imap_to_rss)
96
+ @itor = imap_to_rss
97
+ @imap = imap_to_rss.imap
98
+ end
99
+
100
+ end
101
+
@@ -0,0 +1,259 @@
1
+ require 'imap_to_rss/handler'
2
+
3
+ ##
4
+ # Handles messages from Amazon
5
+
6
+ class IMAPToRSS::Handler::Amazon < IMAPToRSS::Handler
7
+
8
+ ##
9
+ # Selects messages with amazon in the From header
10
+
11
+ def initialize
12
+ @search = 'FROM', 'amazon'
13
+ end
14
+
15
+ ##
16
+ # Turns +uids+ into RSSItems
17
+
18
+ def handle(uids)
19
+ each_message uids, 'text/plain' do |uid, mail|
20
+ @mail = mail
21
+
22
+ case @mail.subject
23
+ when /^Your Order with Amazon.com/ then
24
+ if @mail.body =~ /Your purchase has been divided into/ then
25
+ @mail.body.split(/^Order #\d+/).each do |order|
26
+ add_order order
27
+ end
28
+ else
29
+ add_order @mail.body
30
+ end
31
+ when /has shipped!$/ then
32
+ order_shipped_bang
33
+ when /has shipped/ then
34
+ order_shipped
35
+ when /^Amazon.com - Order Revision \((.*?)\)/ then
36
+ order_revision $1
37
+ when /^Amazon.com - Your Cancellation/ then
38
+ order_cancellation
39
+ when /sent you an Amazon.com Gift Card!$/ then
40
+ gift_card
41
+ when /^Amazon Web Services Billing Statement Available/ then
42
+ aws_bill
43
+ when /^Your savings from Amazon.com/, # ignore
44
+ /^Your Amazon.com Purchase from/ then # dup of regular order email
45
+ next
46
+ else
47
+ log "Unknown Subject: %p" % @mail.subject
48
+ next
49
+ end
50
+ end
51
+ end
52
+
53
+ ##
54
+ # Adds an RSS item with +subject+, +description+ and +url+
55
+
56
+ def add_item(subject, description, url)
57
+ super subject, description, @mail.from, @mail.date, url, @mail.message_id,
58
+ 'Amazon'
59
+ end
60
+
61
+ ##
62
+ # Adds an RSS item from order +order+
63
+
64
+ def add_order(order)
65
+ items = order.scan(/^(\d+) "(.*?)"/)
66
+
67
+ order =~ /Order number:\s+([\d-]+)/
68
+ return unless $1
69
+ order_number = $1
70
+ url = order_url order_number
71
+
72
+ order =~ /^Total for this Order:\s+(.*)/
73
+ total = $1.strip
74
+
75
+ subject = "Amazon order #{order_number}"
76
+
77
+ description = "<p>Total: #{total}\n"
78
+
79
+ description << order_table(items)
80
+
81
+ add_item subject, description, url
82
+ end
83
+
84
+ ##
85
+ # Adds an RSS item for an AWS bill
86
+
87
+ def aws_bill
88
+ @mail.body =~ /^Total: (.*)/
89
+ total = $1
90
+
91
+ @mail.body =~ /^(http.*)/
92
+
93
+ add_item "Amazon Web Services Bill: #{total}", '', $1
94
+ end
95
+
96
+ ##
97
+ # Adds an RSS item for a gift card
98
+
99
+ def gift_card
100
+ url = "https://www.amazon.com/gp/css/account/payment/view-gc-balance.html"
101
+ @mail.body =~ /^Amount: (.*)/
102
+ amount = $1
103
+
104
+ @mail.body =~ /^From: (.*)/
105
+ from = $1
106
+
107
+ @mail.body =~ /^Gift Message: (.*)/
108
+ message = $1
109
+
110
+ @mail.body =~ /^Claim code (.*)/
111
+ claim_code = $1
112
+
113
+ subject = "Amazon Gift Card from #{from} - #{amount}!"
114
+
115
+ description = "<p><strong>#{from} send you a #{amount} gift card!</strong>\n\n"
116
+ description << "<p>#{message}\n\n"
117
+ description << "<h2>#{claim_code}</h2>\n\n"
118
+ description << "<p><a href=\"#{url}\">Claim your gift card</a>"
119
+
120
+ add_item subject, description, url
121
+ end
122
+
123
+ ##
124
+ # Adds an RSS item for an order cancellation
125
+
126
+ def order_cancellation
127
+ @mail.body =~ /order #(.*?) /
128
+ order_number = $1
129
+
130
+ items = @mail.body.scan(/(\d?) of (.*)/)
131
+
132
+ url = order_url order_number
133
+ subject = "Amazon order cancelation #{order_number}"
134
+ description = "<p>You canceled your order:\n\n"
135
+
136
+ description << order_table(items)
137
+
138
+ add_item subject, description, url
139
+ end
140
+
141
+ ##
142
+ # Adds an RSS item for a shipped order
143
+
144
+ def order_shipped
145
+ @mail.body =~ /^(The following items .*?:\r\n.*?)(Shipping Carrier|Item Subtotal)/m
146
+ items = $1.map do |item|
147
+ next unless item =~ /\d+\s(.*?)\$[\d.]+\s+(\d+)/
148
+ [$2, $1.strip]
149
+ end.compact
150
+
151
+ carrier = $1.strip if @mail.body =~ /Shipping Carrier: (.*)/
152
+ date = $1.strip if @mail.body =~ /Ship Date: (.*)/
153
+ speed = $1.strip if @mail.body =~ /Shipping Speed: (.*)/
154
+ tracking_number = $1.strip if @mail.body =~ /Carrier Tracking ID: (.*)/
155
+
156
+ @mail.body =~ /Your shipping address:\r\n\r\n(.*?)\r\n\r\n/m
157
+ address = $1.split("\n").map { |line| line.strip }.join "<br />\n" if $1
158
+
159
+ if tracking_number then
160
+ url = case carrier
161
+ when 'USPS' then
162
+ "http://trkcnfrm1.smi.usps.com/PTSInternetWeb/InterLabelInquiry.do?strOrigTrackNum=#{tracking_number}"
163
+ when 'FedEx' then
164
+ "http://fedex.com/Tracking?tracknumbers=#{tracking_number}"
165
+ else
166
+ log "Unknown carrier: %p" % carrier
167
+ nil
168
+ end
169
+ end
170
+
171
+ subject = @mail.subject
172
+
173
+ description = order_table items
174
+ if url then
175
+ description << "<p>Via <a href=\"#{url}\">#{carrier}</a>\n\n"
176
+ elsif carrier then
177
+ description << "<p>Via #{carrier} (no tracking number found)\n\n"
178
+ end
179
+ description << "<p>To:<br>\n#{address}" if address
180
+
181
+ add_item subject, description, url
182
+ end
183
+
184
+ ##
185
+ # Adds an RSS item for a shipped order (alternate subject ending with !)
186
+
187
+ def order_shipped_bang
188
+ @mail.body =~ /this shipment:\r\n\r\n(.*?)\r\n\r\nShip/m
189
+ items = $1.scan(/(\d+) of (.*)/)
190
+
191
+ carrier = $1.strip if @mail.body =~ /Shipped via (.*?)\s/
192
+ tracking_number = $1.strip if @mail.body =~ /Tracking number: (.*?)\s/
193
+
194
+ @mail.body =~ /This shipment was sent to:\r\n\r\n(.*?)\r\n\r\n/m
195
+ address = $1.split("\n").map { |line| line.strip }.join "<br />\n" if $1
196
+
197
+ if tracking_number then
198
+ url = case carrier
199
+ when 'USPS' then
200
+ "http://trkcnfrm1.smi.usps.com/PTSInternetWeb/InterLabelInquiry.do?strOrigTrackNum=#{tracking_number}"
201
+ when 'FedEx' then
202
+ "http://fedex.com/Tracking?tracknumbers=#{tracking_number}"
203
+ else
204
+ log "Unknown carrier: %p" % carrier
205
+ nil
206
+ end
207
+ end
208
+
209
+ subject = @mail.subject
210
+
211
+ description = order_table items
212
+
213
+ if url then
214
+ description << "<p>Via <a href=\"#{url}\">#{carrier}</a>\n\n"
215
+ elsif carrier then
216
+ description << "<p>Via #{carrier} (no tracking number found)\n\n"
217
+ end
218
+ description << "<p>To:<br>\n#{address}" if address
219
+
220
+ add_item subject, description, url
221
+ end
222
+
223
+ ##
224
+ # Adds an RSS item for an order revision on +order_number+
225
+
226
+ def order_revision(order_number)
227
+ url = order_url order_number
228
+ subject = "Order Revision (#{order_number})"
229
+
230
+ @mail.body =~ /^Dear .*?,\r\n\r\n(.*?)\r\n\r\n/m
231
+
232
+ description = "<p>#{$1}"
233
+
234
+ add_item subject, description, url
235
+ end
236
+
237
+ ##
238
+ # Creates an HTML table for +items+
239
+
240
+ def order_table(items)
241
+ table = "<table>\n<tr><th>Quantity<th>Description\n"
242
+
243
+ items.each do |qty, desc|
244
+ table << "<tr><td>#{qty}<td>#{desc.strip}\n"
245
+ end
246
+ table << "</table>\n\n"
247
+
248
+ table
249
+ end
250
+
251
+ ##
252
+ # Returns the link for order +order_number+
253
+
254
+ def order_url(order_number)
255
+ "https://www.amazon.com/gp/css/summary/edit.html?ie=UTF8&orderID=#{order_number}"
256
+ end
257
+
258
+ end
259
+
@@ -0,0 +1,62 @@
1
+ require 'imap_to_rss/handler'
2
+
3
+ ##
4
+ # Handles messages from HSBC savings and HSBC credit cards
5
+
6
+ class IMAPToRSS::Handler::HSBC < IMAPToRSS::Handler
7
+
8
+ ##
9
+ # Selects messages with hsbc in the From header
10
+
11
+ def initialize
12
+ @search = 'FROM', 'hsbc'
13
+ end
14
+
15
+ ##
16
+ # Turns +uids+ into RSS items for bank-to-bank transfers and general
17
+ # announcements like CC payments due or interest rate changes.
18
+
19
+ def handle(uids)
20
+ each_message uids, 'text/plain' do |uid, mail|
21
+ url = nil
22
+ description = nil
23
+
24
+ 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
+
31
+ next unless $2
32
+
33
+ description = $2
34
+ when 'A2ATransfer@us.hsbc.com' then
35
+ mail.body =~ /^Dear.*?[,:]
36
+ ([ \t]*\r?\n){2,}
37
+ (.*?)
38
+ ([ \t]*\r?\n){2,}
39
+ Sincerely,/mx
40
+
41
+ body = $2
42
+ body.gsub!(/[*\r]/, '')
43
+ body.gsub!(/[ \t]*\n/, "\n")
44
+ body = body.split(/\n\n+/).map { |para| "<p>#{para}</p>" }
45
+
46
+ description = body.join "\n\n"
47
+ when 'alerts@email.hsbcusa.com' then
48
+ mail.body =~ /^(http:.*)/
49
+
50
+ url = $1
51
+ else
52
+ log "Unknown From: #{mail.from.join ', '}"
53
+ next
54
+ end
55
+
56
+ add_item mail.subject, description, mail.from, mail.date, url,
57
+ mail.message_id, 'HSBC'
58
+ end
59
+ end
60
+
61
+ end
62
+
@@ -0,0 +1,34 @@
1
+ require 'imap_to_rss/handler'
2
+
3
+ ##
4
+ # Turns messages from UPS into links to the tracking page
5
+
6
+ class IMAPToRSS::Handler::UPS < IMAPToRSS::Handler
7
+
8
+ ##
9
+ # Selects messages with ups in the From header
10
+
11
+ def initialize
12
+ @search = 'FROM', 'ups'
13
+ end
14
+
15
+ ##
16
+ # Scans +uids+ for UPS tracking numbers and turns them into RSS items
17
+
18
+ def handle(uids)
19
+ each_message uids, 'text/plain' do |uid, mail|
20
+ mail.body =~ /Tracking Number:\s+(\w+)/
21
+
22
+ tracking_number = $1
23
+
24
+ url = "http://wwwapps.ups.com/WebTracking/processRequest?tracknum=#{tracking_number}"
25
+
26
+ description = %{Package shipped: <a href="#{url}">#{tracking_number}</a>}
27
+
28
+ add_item mail.subject, description, mail.from, mail.date, url,
29
+ mail.message_id, 'UPS'
30
+ end
31
+ end
32
+
33
+ end
34
+
metadata ADDED
@@ -0,0 +1,132 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: imap_to_rss
3
+ version: !ruby/object:Gem::Version
4
+ version: "1.0"
5
+ platform: ruby
6
+ authors:
7
+ - Eric Hodel
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain:
11
+ - |
12
+ -----BEGIN CERTIFICATE-----
13
+ MIIDNjCCAh6gAwIBAgIBADANBgkqhkiG9w0BAQUFADBBMRAwDgYDVQQDDAdkcmJy
14
+ YWluMRgwFgYKCZImiZPyLGQBGRYIc2VnbWVudDcxEzARBgoJkiaJk/IsZAEZFgNu
15
+ ZXQwHhcNMDcxMjIxMDIwNDE0WhcNMDgxMjIwMDIwNDE0WjBBMRAwDgYDVQQDDAdk
16
+ cmJyYWluMRgwFgYKCZImiZPyLGQBGRYIc2VnbWVudDcxEzARBgoJkiaJk/IsZAEZ
17
+ FgNuZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCbbgLrGLGIDE76
18
+ LV/cvxdEzCuYuS3oG9PrSZnuDweySUfdp/so0cDq+j8bqy6OzZSw07gdjwFMSd6J
19
+ U5ddZCVywn5nnAQ+Ui7jMW54CYt5/H6f2US6U0hQOjJR6cpfiymgxGdfyTiVcvTm
20
+ Gj/okWrQl0NjYOYBpDi+9PPmaH2RmLJu0dB/NylsDnW5j6yN1BEI8MfJRR+HRKZY
21
+ mUtgzBwF1V4KIZQ8EuL6I/nHVu07i6IkrpAgxpXUfdJQJi0oZAqXurAV3yTxkFwd
22
+ g62YrrW26mDe+pZBzR6bpLE+PmXCzz7UxUq3AE0gPHbiMXie3EFE0oxnsU3lIduh
23
+ sCANiQ8BAgMBAAGjOTA3MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQW
24
+ BBS5k4Z75VSpdM0AclG2UvzFA/VW5DANBgkqhkiG9w0BAQUFAAOCAQEAHagT4lfX
25
+ kP/hDaiwGct7XPuVGbrOsKRVD59FF5kETBxEc9UQ1clKWngf8JoVuEoKD774dW19
26
+ bU0GOVWO+J6FMmT/Cp7nuFJ79egMf/gy4gfUfQMuvfcr6DvZUPIs9P/TlK59iMYF
27
+ DIOQ3DxdF3rMzztNUCizN4taVscEsjCcgW6WkUJnGdqlu3OHWpQxZBJkBTjPCoc6
28
+ UW6on70SFPmAy/5Cq0OJNGEWBfgD9q7rrs/X8GGwUWqXb85RXnUVi/P8Up75E0ag
29
+ 14jEc90kN+C7oI/AGCBN0j6JnEtYIEJZibjjDJTSMWlUKKkj30kq7hlUC2CepJ4v
30
+ x52qPcexcYZR7w==
31
+ -----END CERTIFICATE-----
32
+
33
+ date: 2009-05-15 00:00:00 -07:00
34
+ default_executable:
35
+ dependencies:
36
+ - !ruby/object:Gem::Dependency
37
+ name: imap_processor
38
+ type: :runtime
39
+ version_requirement:
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ~>
43
+ - !ruby/object:Gem::Version
44
+ version: "1.0"
45
+ version:
46
+ - !ruby/object:Gem::Dependency
47
+ name: nokogiri
48
+ type: :runtime
49
+ version_requirement:
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: "1.2"
55
+ version:
56
+ - !ruby/object:Gem::Dependency
57
+ name: tmail
58
+ type: :runtime
59
+ version_requirement:
60
+ version_requirements: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ~>
63
+ - !ruby/object:Gem::Version
64
+ version: "1.2"
65
+ version:
66
+ - !ruby/object:Gem::Dependency
67
+ name: hoe
68
+ type: :development
69
+ version_requirement:
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: 1.12.1
75
+ version:
76
+ description: |-
77
+ IMAPToRSS turns messages on an IMAP server into RSS entries when the match a
78
+ handler. Included handlers work for email from Amazon, HSBC and UPS.
79
+ IMAPToRSS automatically loads handlers for any other mail.
80
+ email:
81
+ - drbrain@example.com
82
+ executables:
83
+ - imap_to_rss
84
+ extensions: []
85
+
86
+ extra_rdoc_files:
87
+ - History.txt
88
+ - Manifest.txt
89
+ - README.txt
90
+ files:
91
+ - .autotest
92
+ - History.txt
93
+ - Manifest.txt
94
+ - README.txt
95
+ - Rakefile
96
+ - bin/imap_to_rss
97
+ - lib/imap_to_rss.rb
98
+ - lib/imap_to_rss/handler.rb
99
+ - lib/imap_to_rss/handler/amazon.rb
100
+ - lib/imap_to_rss/handler/hsbc.rb
101
+ - lib/imap_to_rss/handler/ups.rb
102
+ has_rdoc: true
103
+ homepage: http://seattlerb.rubyforge.org/imap_to_rss
104
+ licenses: []
105
+
106
+ post_install_message:
107
+ rdoc_options:
108
+ - --main
109
+ - README.txt
110
+ require_paths:
111
+ - lib
112
+ required_ruby_version: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: "0"
117
+ version:
118
+ required_rubygems_version: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ version: "0"
123
+ version:
124
+ requirements: []
125
+
126
+ rubyforge_project: seattlerb
127
+ rubygems_version: 1.3.3
128
+ signing_key:
129
+ specification_version: 3
130
+ summary: IMAPToRSS turns messages on an IMAP server into RSS entries when the match a handler
131
+ test_files: []
132
+
@@ -0,0 +1,2 @@
1
+ w��S�r>��߄������P;�D�dԿ�7?���V�@c�ʷ�V(?��Q
2
+ 9ޣj�_N65dun�[�,+�[�V!��n7