imap_to_rss 1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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