uron 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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