uron 1.0.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,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 0591180df0f68252415b03b5a89b7d05126f8916
4
+ data.tar.gz: c71803232c8244075cdad60c3b888ff06bbd1ad6
5
+ SHA512:
6
+ metadata.gz: 443387254be0ecaf8dca82886036822369b5c266b9ea642bdb3098cafc32b3afaf33db3f2878a7cddee814eb339816c98e24ab81039d5112ea9ac6b2444bdcf2
7
+ data.tar.gz: 1ce8c88b1106bf918c36e2050dddd20195f94054111f50783d9ba42a5db791032143e86b606ea92a6c4e8cfd6cd5047c756001adb0c11deb0df2683a7d37f5a7
@@ -0,0 +1,2 @@
1
+ pkg/*
2
+ Gemfile.lock
@@ -0,0 +1,8 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.1
4
+ - 2.0.0
5
+ - 1.9.3
6
+ - 1.8.7
7
+ script:
8
+ - bundle exec rake build test
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
@@ -0,0 +1,150 @@
1
+ [![Build Status](https://img.shields.io/travis/unak/uron.svg)](https://travis-ci.org/unak/uron)
2
+
3
+ uron
4
+ ====
5
+
6
+ This software is published at `https://github.com/unak/uron`.
7
+
8
+
9
+ What's This?
10
+ ------------
11
+
12
+ uron is a mail delivery agent, like procmail.
13
+
14
+ Currently, uron has not been tested well yet.
15
+
16
+
17
+ Requirement
18
+ -----------
19
+
20
+ Ruby 1.8.7, 1.9.3 or later.
21
+
22
+ uron assumes that your system follows the Maildir specification.
23
+
24
+
25
+ How to Use
26
+ ----------
27
+
28
+ Write `~/.forward` file.
29
+ If you cannot understand what you have to do, you cannot use uron.
30
+
31
+
32
+ Delivery Setting
33
+ ----------------
34
+ Write `~/.uronrc` file.
35
+
36
+ ### Basic Definitions
37
+
38
+ #### `Maildir`
39
+
40
+ The path of your maildir.
41
+ If not specified, `~/Maildir` is assumed.
42
+
43
+ #### `Log`
44
+
45
+ The path of the log file.
46
+ If not specified, uron outputs no log.
47
+
48
+ ### Delivery Rules
49
+
50
+ In delivery rules, you can write Ruby code in code blocks.
51
+ If a block returns a true value, uron assumes that the mail is delivered
52
+ and exits.
53
+
54
+ #### `header`
55
+
56
+ Takes one Hash parameter and optional block.
57
+
58
+ The Hash parameter must include at least one key which means a mail header.
59
+ The key is all lower cases and converted `-` to `_'.
60
+ The value of the key must be a Regexp or an Array of Regexps.
61
+ uron matches the Regexp(s) to the value of mail headers specified by the key,
62
+ and do something if matched.
63
+
64
+ If `:delivery` is included in the Hash parameter, delivery the mail to
65
+ the value, and exits.
66
+ If `:transfer` is included in the Hash parameter, transfer the mail to
67
+ the value, and exits.
68
+ If `:invoke` is included in the Hash parameter, invoke the command specfied
69
+ by the value, and if the command returns zero, exits.
70
+ If a block is passed, call the block.
71
+
72
+ Examples:
73
+
74
+ header :subject => /\A[mailing-list:/, :delivery => "mailing-list"
75
+ This means that if the subject of the mail starts with `[mailing-list:`,
76
+ delivery the mail to `mailing-list` directory (it's relative from your
77
+ Maildir.)
78
+
79
+ header :subject => /\A[mailing-list:/ do
80
+ delivery "mailing-list"
81
+ end
82
+ Same as above.
83
+
84
+ ### Delivery Commands
85
+
86
+ #### `delivery`
87
+
88
+ Takes one String parameter and delivery the mail to the directory specfied by
89
+ the parameter.
90
+ The parameter must be relative from your Maildir.
91
+
92
+ Examples:
93
+
94
+ delivery "mailing-list"
95
+
96
+ #### `transfer`
97
+
98
+ Takes two String parameters and transfer the mail to the host and the address
99
+ specfied by the parameters.
100
+
101
+ Examples:
102
+
103
+ transfer "some.host.of.example.com", "foo@example.com"
104
+
105
+ #### `invoke`
106
+
107
+ Takes at least one String parameters and invoke the command specified by
108
+ the 1st parameter and passes command arguments specified by rest parameters.
109
+ Passes the mail via stdin to the command.
110
+
111
+ Returns the status value of the command.
112
+
113
+ Examples:
114
+
115
+ if invoke("bsfilter", "-a") == 0
116
+ delivery ".spam"
117
+ else
118
+ false
119
+ end
120
+
121
+ #### `logging`
122
+
123
+ Takes one String parameter and outout it to the log file.
124
+
125
+
126
+ License
127
+ -------
128
+
129
+ Copyright (c) 2012 NAKAMURA Usaku usa@garbagecollect.jp
130
+
131
+ Redistribution and use in source and binary forms, with or without
132
+ modification, are permitted provided that the following conditions are met:
133
+
134
+ 1. Redistributions of source code must retain the above copyright notice,
135
+ this list of conditions and the following disclaimer.
136
+ 2. Redistributions in binary form must reproduce the above copyright notice,
137
+ this list of conditions and the following disclaimer in the documentation
138
+ and/or other materials provided with the distribution.
139
+
140
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
141
+ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
142
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
143
+ DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
144
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
145
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
146
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
147
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
148
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
149
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
150
+
@@ -0,0 +1,7 @@
1
+ # -*- Ruby -*-
2
+ require "bundler/gem_tasks"
3
+
4
+ desc "Runs test"
5
+ task :test do
6
+ ruby 'test/test_uron.rb'
7
+ end
@@ -0,0 +1,309 @@
1
+ #!ruby
2
+ # coding: UTF-8
3
+
4
+ #
5
+ # Copyright (c) 2012 NAKAMURA Usaku usa@garbagecollect.jp
6
+ #
7
+ # Redistribution and use in source and binary forms, with or without
8
+ # modification, are permitted provided that the following conditions are met:
9
+ #
10
+ # 1. Redistributions of source code must retain the above copyright notice,
11
+ # this list of conditions and the following disclaimer.
12
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
13
+ # this list of conditions and the following disclaimer in the documentation
14
+ # and/or other materials provided with the distribution.
15
+ #
16
+ # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
17
+ # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
+ # DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
20
+ # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21
+ # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22
+ # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23
+ # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24
+ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
+ #
27
+
28
+ require "etc"
29
+ require "fileutils"
30
+ require "net/smtp"
31
+ require "socket"
32
+
33
+ #
34
+ #= uron - a mail delivery agent
35
+ #
36
+ class Uron
37
+ ConfigError = Class.new(RuntimeError)
38
+
39
+ # execute uron
40
+ #
41
+ # _rc_ is a String of the configuration file.
42
+ # _io_ is a IO of the mail. (optional)
43
+ def self.run(rc, io = $stdin)
44
+ uron = Uron.new(rc)
45
+ uron.run(io)
46
+ end
47
+
48
+ # processed mail
49
+ attr_reader :mail
50
+
51
+ # path of Maildir
52
+ attr_reader :maildir
53
+
54
+ # path of log file
55
+ attr_reader :logfile
56
+
57
+ # initialize the Uron object
58
+ #
59
+ # _rc_ is a String of the configuration file.
60
+ # _io_ is a IO of the mail.
61
+ def initialize(rc)
62
+ self.class.class_eval do
63
+ remove_const :Maildir if defined?(Maildir)
64
+ remove_const :Log if defined?(Log)
65
+ end
66
+
67
+ @ruleset = []
68
+
69
+ open(rc) do |f|
70
+ eval(f.read, binding, rc)
71
+ end
72
+
73
+ @maildir = File.expand_path((Maildir rescue "~/Maildir"))
74
+ @logfile = File.expand_path(Log) rescue nil
75
+ end
76
+
77
+ # execute uron
78
+ #
79
+ # _io_ is a IO of the mail. (optional)
80
+ def run(io = $stdin)
81
+ @mail = self.class::Mail.read(io)
82
+
83
+ logging "From #{(@mail.headers[:from] || []).first} #{Time.now}"
84
+ logging " Subject: #{@mail.headers[:subject].first[0, 69]}" if @mail.headers.include?(:subject)
85
+
86
+ catch(:tag) do
87
+ @ruleset.each do |sym, conds, block|
88
+ if @mail.headers[sym]
89
+ conds = [conds] unless conds.is_a?(Array)
90
+ conds.each do |cond|
91
+ @mail.headers[sym].each do |header|
92
+ begin
93
+ block.call(@mail) && throw(:tag) if cond =~ header
94
+ rescue
95
+ logging $!
96
+ raise $!
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
102
+
103
+ # if here, no rule was adpoted
104
+ delivery ""
105
+ end
106
+
107
+ 0
108
+ end
109
+
110
+ # output a log
111
+ #
112
+ # _log_ is an Exception or a String.
113
+ def logging(log)
114
+ return unless @logfile
115
+ open(@logfile, "a") do |f|
116
+ f.flock(File::LOCK_EX)
117
+ f.seek(0, File::SEEK_END)
118
+
119
+ if log.is_a?(Exception)
120
+ log = ["#{log.class}: #{log.message}", *log.backtrace].join("\n\t")
121
+ end
122
+ f.puts log
123
+
124
+ f.flock(File::LOCK_UN)
125
+ end
126
+ end
127
+
128
+ # check specified header and process the mail
129
+ #
130
+ # _h_ is a Hash which includes a Symbol of a header as the key and an Array
131
+ # of Regexps as the value to checking the contents of the header.
132
+ # if _h_ includes :dir, the value means the path to be delivered.
133
+ # if _block_ is passed, uron processes it.
134
+ def header(h, &block)
135
+ deliv = h.delete(:delivery)
136
+ trans = h.delete(:transfer)
137
+ invok = h.delete(:invoke)
138
+ t = [deliv, trans, invok, block].compact
139
+ raise ConfigError, "need one of :delivery, :transfer, :invoke or a block" if t.empty?
140
+ raise ConfigError, "can specify only one of :delivery, :transfer, :invoke or a block" if t.size != 1
141
+ block = proc{ delivery deliv } if deliv
142
+ block = proc{ transfer *trans } if trans
143
+ block = proc{ invoke(*invok) == 0 } if invok
144
+ @ruleset.push([h.keys.first, h.values.flatten(1), block])
145
+ end
146
+
147
+ # deliver the mail to a directory
148
+ #
149
+ # _dir_ is a String specifes the target directory.
150
+ def delivery(dir)
151
+ dir = @maildir if dir.empty?
152
+ ldir = File.expand_path(File.join(dir, "new"), @maildir)
153
+ FileUtils.mkdir_p(ldir)
154
+ n = 1
155
+ begin
156
+ file = "%d.%d_%d.%s" % [Time.now.to_i, Process.pid, n, Socket.gethostname]
157
+ open(File.expand_path(file, ldir), "wb", File::CREAT | File::EXCL) do |f|
158
+ f.write mail.plain
159
+ f.chmod 0600
160
+ end
161
+ logging " Folder: %.60s %8d" % [File.join(dir, 'new', file)[0, 60], mail.plain.bytesize]
162
+ rescue Errno::EACCES
163
+ if n > 100
164
+ logging $!
165
+ raise $!
166
+ end
167
+ n += 1
168
+ retry
169
+ end
170
+ true # means success
171
+ end
172
+
173
+ # transfer the mail to some host
174
+ #
175
+ # _host_ is a String specifies the target host name (or the IP address).
176
+ # _to_ is a String specifies the target address.
177
+ # _port_ is an optional parameter of a Numeric specifies the target host port.
178
+ # _from_ is an optional parameter of a String specifies the envelove from.
179
+ def transfer(host, to, port = 25, from = nil)
180
+ from ||= Etc.getlogin
181
+ Net::SMTP.start(host, port) do |smtp|
182
+ smtp.send_mail(mail.plain, from, to)
183
+ end
184
+ logging " Trans: %.60s %8d" % [to[0, 60], mail.plain.bytesize]
185
+ true # mains success
186
+ end
187
+
188
+ # invoke a command
189
+ #
190
+ # _cmd_ is a String specifies the command.
191
+ # _args_ are Strings that will be passed to the command.
192
+ #
193
+ # this method passes the mail to the command via stdin, and returns the exit
194
+ # status value of it.
195
+ def invoke(cmd, *args)
196
+ result = nil
197
+ begin
198
+ unless args.empty?
199
+ cmd = cmd + ' ' + args.map{|e| "'#{e}'"}.join(' ')
200
+ end
201
+ IO.popen(cmd, 'wb') do |f|
202
+ f.print mail.plain
203
+ end
204
+ result = $?.to_i
205
+ rescue
206
+ result = -1
207
+ logging $!
208
+ raise $!
209
+ end
210
+ logging " Invoke: %.60s %8d" % [cmd[0, 60], result]
211
+ result
212
+ end
213
+
214
+ # mail
215
+ class Mail
216
+ # read a mail from stdin
217
+ #
218
+ # _io_ is a IO of the mail. (optional)
219
+ def self.read(io = $stdin)
220
+ self.new(io.binmode.read)
221
+ end
222
+
223
+ # a Hash of mail headers
224
+ attr_reader :headers
225
+
226
+ # an Array of mail body
227
+ attr_reader :body
228
+
229
+ # a String of the orignal mail text
230
+ attr_reader :plain
231
+
232
+ # initialize a Uron::Mail object
233
+ #
234
+ # _plain_ is the original mail text.
235
+ def initialize(plain)
236
+ @plain = plain.dup
237
+ parse(@plain)
238
+ end
239
+
240
+ # parse the mail text
241
+ #
242
+ # _plain_ is the original mail text.
243
+ def parse(plain)
244
+ @headers = {}
245
+ @body = []
246
+ header_p = true
247
+ prev = nil
248
+ plain.each_line do |line|
249
+ if header_p
250
+ # header
251
+ line.chomp!
252
+ if line.empty?
253
+ set_header(prev) if prev
254
+ header_p = false
255
+ next
256
+ end
257
+
258
+ if /\A\s/ =~ line
259
+ prev = (prev || "") + " " + line.sub(/\A\s+/, '')
260
+ else
261
+ set_header(prev) if prev
262
+ prev = line
263
+ end
264
+ else
265
+ # body
266
+ if @body.empty?
267
+ @body.push(line)
268
+ else
269
+ @body.last << line
270
+ end
271
+ end
272
+ end
273
+ end
274
+
275
+ # set a header to @headers
276
+ def set_header(line)
277
+ title, data = line.split(/: */, 2)
278
+ title = title.tr("-", "_").downcase.to_sym
279
+ @headers[title] = [] unless @headers.include?(title)
280
+ @headers[title].push(data)
281
+ end
282
+ end
283
+ end
284
+
285
+ if __FILE__ == $0
286
+ require "optparse"
287
+
288
+ rcfile = "~/.uronrc"
289
+
290
+ opt = OptionParser.new
291
+ opt.on('-r RCFILE', '--rc', 'use RCFILE as the ruleset configurations.') do |v|
292
+ rcfile = v
293
+ end
294
+ opt.parse!
295
+ unless ARGV.empty?
296
+ $stderr.puts "unknown argument(s): #{ARGV.join(' ')}"
297
+ $stderr.puts
298
+ $stderr.puts opt.help
299
+ exit 1
300
+ end
301
+
302
+ begin
303
+ exit Uron.run(File.expand_path(rcfile))
304
+ rescue
305
+ $stderr.puts "#{$!.class}: #{$!.message}"
306
+ $stderr.puts $!.backtrace.join("\n\t")
307
+ exit 1
308
+ end
309
+ end
@@ -0,0 +1,38 @@
1
+ require "net/smtp"
2
+
3
+ class SMTPMock
4
+ attr_reader :host
5
+ attr_reader :port
6
+ attr_reader :helo
7
+ attr_reader :src
8
+ attr_reader :from
9
+ attr_reader :to
10
+
11
+ def self.instance
12
+ @@instance
13
+ end
14
+
15
+ def initialize(host, port = 25)
16
+ @@instance = self
17
+
18
+ @host = host
19
+ @port = port
20
+ end
21
+
22
+ def start(helo, account, password, auth, &block)
23
+ @helo = helo
24
+ block.call(self) if block
25
+ end
26
+
27
+ def send_mail(src, from, *to)
28
+ @src = src
29
+ @from = from
30
+ @to = to
31
+ end
32
+ end
33
+
34
+ class Net::SMTP
35
+ def self.new(*args)
36
+ SMTPMock.new(*args)
37
+ end
38
+ end
@@ -0,0 +1,262 @@
1
+ require "test/unit"
2
+ require "etc"
3
+ require "fileutils"
4
+ require "rbconfig"
5
+ require "stringio"
6
+ require "tempfile"
7
+ require "tmpdir"
8
+ unless defined?(require_relative)
9
+ def require_relative(feature)
10
+ require File.expand_path(feature, File.dirname(File.expand_path(__FILE__)))
11
+ end
12
+ end
13
+ require_relative "smtpmock"
14
+ require_relative "../bin/uron"
15
+
16
+ unless defined?(File::NULL)
17
+ if /mswin|mingw|bccwin|djgpp/ =~ RUBY_PLATFORM
18
+ File::NULL = "NUL"
19
+ else
20
+ File::NULL = "/dev/null"
21
+ end
22
+ end
23
+
24
+
25
+ class TestUron < Test::Unit::TestCase
26
+ def setup
27
+ @tmpdir = Dir.mktmpdir
28
+ @maildir = @tmpdir
29
+ @logfile = File.expand_path("log", @maildir)
30
+
31
+ ruby = File.join(RbConfig::CONFIG["bindir"], RbConfig::CONFIG["ruby_install_name"] + RbConfig::CONFIG["EXEEXT"])
32
+ @rc = make_rc <<-END_OF_RC
33
+ Maildir = "#{@tmpdir}"
34
+ Log = "#{@logfile}"
35
+
36
+ header :from => /\\Ausa@/ do
37
+ delivery ".test"
38
+ end
39
+
40
+ header :to => /\\Ausa@/, :delivery => ".test"
41
+
42
+ header :from => /\\Ausa2@/ do
43
+ transfer "mx.example.com", "usa@example.com"
44
+ end
45
+
46
+ header :to => /\\Ausa2@/, :transfer => ["mx.example.com", "usa@example.com"]
47
+
48
+ header :from => /\\Ausa3@/ do
49
+ invoke("#{ruby}", "-e", "exit /^From:.*usa3@/ =~ ARGF.read ? 0 : 1") == 0
50
+ end
51
+
52
+ header :to => /\\Ausa3@/, :invoke => ["#{ruby}", "-e", "exit /^To:.*usa3@/ =~ ARGF.read ? 0 : 1"]
53
+ END_OF_RC
54
+ end
55
+
56
+ def teardown
57
+ @rc.unlink
58
+ FileUtils.rm_rf @tmpdir
59
+ end
60
+
61
+ def make_rc(str)
62
+ tmprc = Tempfile.open("uron_test")
63
+ tmprc.binmode
64
+ tmprc.puts str
65
+ tmprc.close
66
+ tmprc
67
+ end
68
+
69
+ def test_new
70
+ uron = Uron.new(@rc.path)
71
+ assert uron.is_a?(Uron)
72
+ end
73
+
74
+ def test_run_m
75
+ null = open(File::NULL)
76
+ begin
77
+ assert_nothing_raised do
78
+ Uron.run(@rc.path, null)
79
+ end
80
+ ensure
81
+ null.close
82
+ end
83
+ end
84
+
85
+ def test_run
86
+ uron = Uron.new(@rc.path)
87
+ null = open(File::NULL)
88
+ begin
89
+ assert_nothing_raised do
90
+ uron.run(null)
91
+ end
92
+ ensure
93
+ null.close
94
+ end
95
+ end
96
+
97
+ def test_maildir
98
+ uron = Uron.new(@rc.path)
99
+ assert_equal @maildir, uron.maildir
100
+
101
+ uron = Uron.new(File::NULL)
102
+ assert_equal File.expand_path("~/Maildir"), uron.maildir
103
+ end
104
+
105
+ def test_logfile
106
+ uron = Uron.new(@rc.path)
107
+ assert_equal @logfile, uron.logfile
108
+
109
+ uron = Uron.new(File::NULL)
110
+ assert_nil uron.logfile
111
+ end
112
+
113
+ def test_logging
114
+ uron = Uron.new(@rc.path)
115
+ uron.logging "test"
116
+ assert_equal "test", File.read(uron.logfile).chomp
117
+
118
+ ex = nil
119
+ begin
120
+ raise RuntimeError, "foo"
121
+ rescue
122
+ ex = $!
123
+ end
124
+ uron.logging ex
125
+ assert_match /^RuntimeError: foo\n\t.*\btest_uron\.rb:\d+:in `test_logging'/, File.read(uron.logfile) #'
126
+ end
127
+
128
+ def test_header
129
+ tmprc = make_rc <<-END_OF_RC
130
+ header :foo => //
131
+ END_OF_RC
132
+ assert_raise(Uron::ConfigError) do
133
+ Uron.new(tmprc.path)
134
+ end
135
+ tmprc.unlink
136
+
137
+ tmprc = make_rc <<-END_OF_RC
138
+ header :foo => //, :delivery => "", :transfer => []
139
+ END_OF_RC
140
+ assert_raise(Uron::ConfigError) do
141
+ Uron.new(tmprc.path)
142
+ end
143
+ tmprc.unlink
144
+
145
+ tmprc = make_rc <<-END_OF_RC
146
+ header :foo => //, :delivery => "" do
147
+ end
148
+ END_OF_RC
149
+ assert_raise(Uron::ConfigError) do
150
+ Uron.new(tmprc.path)
151
+ end
152
+ tmprc.unlink
153
+
154
+ tmprc = make_rc <<-END_OF_RC
155
+ header :foo => //, :transfer => [] do
156
+ end
157
+ END_OF_RC
158
+ assert_raise(Uron::ConfigError) do
159
+ Uron.new(tmprc.path)
160
+ end
161
+ tmprc.unlink
162
+
163
+ tmprc = make_rc <<-END_OF_RC
164
+ Log = "#{@logfile}"
165
+ header :from => /\\Ausa\\b/ do
166
+ next false
167
+ end
168
+ header :from => /\\Ausa\\b/ do
169
+ next true
170
+ end
171
+ END_OF_RC
172
+ assert_nothing_raised do
173
+ io = StringIO.new("From: usa@example.com\r\n\r\n")
174
+ assert_equal 0, Uron.run(tmprc.path, io)
175
+ mail = Dir.glob(File.join(@maildir, "new", "*")).find{|e| /\A[^\.]/ =~ e}
176
+ assert_nil mail
177
+ assert_match /\AFrom [^\n]+\r?\n\z/, File.read(@logfile)
178
+ end
179
+ tmprc.unlink
180
+ end
181
+
182
+ def test_delivery
183
+ io = StringIO.new("From: usa@example.com\r\n\r\n")
184
+ assert_equal 0, Uron.run(@rc.path, io)
185
+ mail = Dir.glob(File.join(@maildir, "new", "*")).find{|e| /\A[^\.]/ =~ e}
186
+ assert_nil mail
187
+ mail = Dir.glob(File.join(@maildir, ".test", "new", "*")).find{|e| /\A[^\.]/ =~ e}
188
+ assert_equal io.string, open(mail, "rb"){|f| f.read}
189
+ assert_match /\sFolder:[^\n]+\s#{io.string.size}\r?\n\z/, File.read(@logfile)
190
+ File.unlink mail if File.exist?(mail)
191
+
192
+ io = StringIO.new("To: usa@example.com\r\n\r\n")
193
+ assert_equal 0, Uron.run(@rc.path, io)
194
+ mail = Dir.glob(File.join(@maildir, "new", "*")).find{|e| /\A[^\.]/ =~ e}
195
+ assert_nil mail
196
+ mail = Dir.glob(File.join(@maildir, ".test", "new", "*")).find{|e| /\A[^\.]/ =~ e}
197
+ assert_equal io.string, open(mail, "rb"){|f| f.read}
198
+ assert_match /\sFolder:[^\n]+\s#{io.string.size}\r?\n\z/, File.read(@logfile)
199
+ File.unlink mail if File.exist?(mail)
200
+
201
+ io = StringIO.new("From: foo@example.com\r\n\r\n")
202
+ assert_equal 0, Uron.run(@rc.path, io)
203
+ mail = Dir.glob(File.join(@maildir, ".test", "new", "*")).find{|e| /\A[^\.]/ =~ e}
204
+ assert_nil mail
205
+ mail = Dir.glob(File.join(@maildir, "new", "*")).find{|e| /\A[^\.]/ =~ e}
206
+ io.rewind
207
+ assert_equal io.string, open(mail, "rb"){|f| f.read}
208
+ assert_match /\sFolder:[^\n]+\s#{io.string.size}\r?\n\z/, File.read(@logfile)
209
+ end
210
+
211
+ def test_transfer
212
+ io = StringIO.new("From: usa2@example.com\r\n\r\n")
213
+ assert_equal 0, Uron.run(@rc.path, io)
214
+ mail = Dir.glob(File.join(@maildir, "new", "*")).find{|e| /\A[^\.]/ =~ e}
215
+ assert_nil mail
216
+ assert_match /\sTrans:[^\n]+\s#{io.string.size}\r?\n\z/, File.read(@logfile)
217
+ assert_equal "mx.example.com", SMTPMock.instance.host
218
+ assert_equal 25, SMTPMock.instance.port
219
+ assert_match /\Alocalhost\b/, SMTPMock.instance.helo
220
+ assert_equal Etc.getlogin, SMTPMock.instance.from
221
+ assert_equal ["usa@example.com"], SMTPMock.instance.to
222
+ assert_equal io.string, SMTPMock.instance.src
223
+
224
+ io = StringIO.new("To: usa2@example.com\r\n\r\n")
225
+ assert_equal 0, Uron.run(@rc.path, io)
226
+ mail = Dir.glob(File.join(@maildir, "new", "*")).find{|e| /\A[^\.]/ =~ e}
227
+ assert_nil mail
228
+ assert_match /\sTrans:[^\n]+\s#{io.string.size}\r?\n\z/, File.read(@logfile)
229
+ assert_equal "mx.example.com", SMTPMock.instance.host
230
+ assert_equal 25, SMTPMock.instance.port
231
+ assert_match /\Alocalhost\b/, SMTPMock.instance.helo
232
+ assert_equal Etc.getlogin, SMTPMock.instance.from
233
+ assert_equal ["usa@example.com"], SMTPMock.instance.to
234
+ assert_equal io.string, SMTPMock.instance.src
235
+
236
+ io = StringIO.new(s = "From: foo@example.com\r\n\r\n")
237
+ assert_equal 0, Uron.run(@rc.path, io)
238
+ mail = Dir.glob(File.join(@maildir, "new", "*")).find{|e| /\A[^\.]/ =~ e}
239
+ assert_equal io.string, open(mail, "rb"){|f| f.read}
240
+ assert_match /\sFolder:[^\n]+\s#{io.string.size}\r?\n\z/, File.read(@logfile)
241
+ end
242
+
243
+ def test_invoke
244
+ io = StringIO.new("From: usa3@example.com\r\n\r\n")
245
+ assert_equal 0, Uron.run(@rc.path, io)
246
+ mail = Dir.glob(File.join(@maildir, "new", "*")).find{|e| /\A[^\.]/ =~ e}
247
+ assert_nil mail
248
+ assert_match /\sInvoke:[^\n]+\s0\r?\n\z/, File.read(@logfile)
249
+
250
+ io = StringIO.new("To: usa3@example.com\r\n\r\n")
251
+ assert_equal 0, Uron.run(@rc.path, io)
252
+ mail = Dir.glob(File.join(@maildir, "new", "*")).find{|e| /\A[^\.]/ =~ e}
253
+ assert_nil mail
254
+ assert_match /\sInvoke:[^\n]+\s0\r?\n\z/, File.read(@logfile)
255
+
256
+ io = StringIO.new(s = "From: foo@example.com\r\n\r\n")
257
+ assert_equal 0, Uron.run(@rc.path, io)
258
+ mail = Dir.glob(File.join(@maildir, "new", "*")).find{|e| /\A[^\.]/ =~ e}
259
+ assert_equal io.string, open(mail, "rb"){|f| f.read}
260
+ assert_match /\sFolder:[^\n]+\s#{io.string.size}\r?\n\z/, File.read(@logfile)
261
+ end
262
+ end
@@ -0,0 +1,21 @@
1
+ # coding: utf-8
2
+ # -*- Ruby -*-
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "uron"
5
+ spec.version = "1.0.0"
6
+ spec.authors = ["U.Nakamura"]
7
+ spec.email = ["usa@garbagecollect.jp"]
8
+ spec.description = %q{uron is a mail delivery agent}
9
+ spec.summary = %q{uron is a mail delivery agent}
10
+ spec.homepage = "https://github.com/unak/uron"
11
+ spec.license = "BSD-2-Clause"
12
+
13
+ spec.files = `git ls-files`.split($/)
14
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
15
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
16
+ spec.require_paths = ["lib"]
17
+
18
+ spec.add_development_dependency "bundler", "~> 1.3"
19
+ spec.add_development_dependency "rake"
20
+ spec.add_development_dependency "test-unit"
21
+ end
metadata ADDED
@@ -0,0 +1,98 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: uron
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - U.Nakamura
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-04-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: test-unit
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: uron is a mail delivery agent
56
+ email:
57
+ - usa@garbagecollect.jp
58
+ executables:
59
+ - uron.rb
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - ".gitignore"
64
+ - ".travis.yml"
65
+ - Gemfile
66
+ - README.md
67
+ - Rakefile
68
+ - bin/uron.rb
69
+ - test/smtpmock.rb
70
+ - test/test_uron.rb
71
+ - uron.gemspec
72
+ homepage: https://github.com/unak/uron
73
+ licenses:
74
+ - BSD-2-Clause
75
+ metadata: {}
76
+ post_install_message:
77
+ rdoc_options: []
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ requirements: []
91
+ rubyforge_project:
92
+ rubygems_version: 2.2.2
93
+ signing_key:
94
+ specification_version: 4
95
+ summary: uron is a mail delivery agent
96
+ test_files:
97
+ - test/smtpmock.rb
98
+ - test/test_uron.rb