boomerang-mocksmtpd 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 177797030b204a198e54e981150acde7640896f755737aee67af8c8baa1a0c64
4
+ data.tar.gz: 2b9b775c5f4eb9c4eb25cf0c8d38d0197581ac049c64ab895ef67465e2af97ae
5
+ SHA512:
6
+ metadata.gz: dc51298ff87bd815fa59a6412218cb6288ff7f3c23ad833ca5ee4f9c84665c64ab5e8164e8f35dded7fad03ccc50bd449b6fd40bee97a378d3dfc9e9b89bc304
7
+ data.tar.gz: 83585bfd0a2530d8f7426f8aac05b11e0c6fd3ca39ab462ab97cd607dd08154a6e41fc20cbab412f51ee38e069f42a7d6774fafd6e9b8f3eb76519a81d38876f
data/ChangeLog CHANGED
@@ -1,17 +1,22 @@
1
- == 0.0.3 / 2008-11-08
2
-
3
- * rescue Process.eid NotImplementedError.
4
- * warn when Process.eid can't be changed.
5
- * read log level from config file.
6
- * change param name from Loglevel to LogLevel
7
- * add debug log.
8
-
9
- == 0.0.2 / 2008-11-03
10
-
11
- * release gem version.
12
-
13
- == 0.0.1 / 2008-11-03
14
-
15
- * moved into github
16
- * initial release
17
-
1
+ == 0.0.4 / 2022-06-17
2
+
3
+ * support for pid file in windows/linux
4
+ * added --silent option
5
+
6
+ == 0.0.3 / 2008-11-08
7
+
8
+ * rescue Process.eid NotImplementedError.
9
+ * warn when Process.eid can't be changed.
10
+ * read log level from config file.
11
+ * change param name from Loglevel to LogLevel
12
+ * add debug log.
13
+
14
+ == 0.0.2 / 2008-11-03
15
+
16
+ * release gem version.
17
+
18
+ == 0.0.1 / 2008-11-03
19
+
20
+ * moved into github
21
+ * initial release
22
+
data/README CHANGED
@@ -1,59 +1,59 @@
1
-
2
- = mocksmtpd
3
-
4
-
5
- == Description
6
-
7
- Mocksmtpd is a SMTP server for developping and testing web application. This SMTP server does not send mail anywhere. Otherwise, save all mails as HTML format.
8
-
9
- You can test mail using browser testing tools like Selenium.
10
-
11
- === Screenshot
12
-
13
- http://koseki2.tumblr.com/post/57148631
14
- http://koseki2.tumblr.com/post/57148564
15
-
16
- == Installation
17
-
18
- === Archive Installation
19
-
20
- rake install
21
-
22
- === Gem Installation
23
-
24
- gem sources -a http://gems.github.com
25
- gem install koseki-mocksmtpd
26
-
27
- == Quick Start
28
-
29
- $ mocksmtpd init
30
- $ cd ./mocksmtpd
31
- $ sudo mocksmtpd
32
-
33
- == Usaage
34
-
35
- mocksmtpd init [dirname] ... create log,inbox dir and config file.
36
- mocksmtpd ... start as console mode.
37
- mocksmtpd start ... start as daemon.
38
- mocksmtpd stop ... stop running daemon.
39
-
40
- === Options
41
-
42
- The default config file is ./mocksmtpd.conf, but you can specify any other file using -f option.
43
-
44
- -f / --config=FILE ... Specify config file.
45
- --help ... Show help.
46
- --silent ... Disable console output.
47
- --version ... Show version.
48
-
49
- == Features/Problems
50
-
51
-
52
- == Synopsis
53
-
54
-
55
- == Copyright
56
-
57
- Author:: KOSEKI Kengo <koseki@gmail.com>
58
- Copyright:: Copyright (c) 2008
59
- License:: Ruby Licence
1
+
2
+ = mocksmtpd
3
+
4
+
5
+ == Description
6
+
7
+ Mocksmtpd is a SMTP server for developping and testing web application. This SMTP server does not send mail anywhere. Otherwise, save all mails as HTML format.
8
+
9
+ You can test mail using browser testing tools like Selenium.
10
+
11
+ === Screenshot
12
+
13
+ http://koseki2.tumblr.com/post/57148631
14
+ http://koseki2.tumblr.com/post/57148564
15
+
16
+ == Installation
17
+
18
+ === Archive Installation
19
+
20
+ rake install
21
+
22
+ === Gem Installation
23
+
24
+ gem sources -a http://gems.github.com
25
+ gem install koseki-mocksmtpd
26
+
27
+ == Quick Start
28
+
29
+ $ mocksmtpd init
30
+ $ cd ./mocksmtpd
31
+ $ sudo mocksmtpd
32
+
33
+ == Usaage
34
+
35
+ mocksmtpd init [dirname] ... create log,inbox dir and config file.
36
+ mocksmtpd ... start as console mode.
37
+ mocksmtpd start ... start as daemon.
38
+ mocksmtpd stop ... stop running daemon.
39
+
40
+ === Options
41
+
42
+ The default config file is ./mocksmtpd.conf, but you can specify any other file using -f option.
43
+
44
+ -f / --config=FILE ... Specify config file.
45
+ --help ... Show help.
46
+ --silent ... Disable console output.
47
+ --version ... Show version.
48
+
49
+ == Features/Problems
50
+
51
+
52
+ == Synopsis
53
+
54
+
55
+ == Copyright
56
+
57
+ Author:: KOSEKI Kengo <koseki@gmail.com>
58
+ Copyright:: Copyright (c) 2008
59
+ License:: Ruby Licence
data/Rakefile CHANGED
@@ -1,144 +1,13 @@
1
- require 'rubygems'
2
- require 'rake'
3
- require 'rake/clean'
4
- require 'rake/testtask'
5
- require 'rake/packagetask'
6
- require 'rake/gempackagetask'
7
- require 'rake/rdoctask'
8
- require 'rake/contrib/rubyforgepublisher'
9
- require 'rake/contrib/sshpublisher'
10
- require 'fileutils'
11
- require 'lib/mocksmtpd'
12
- include FileUtils
13
-
14
- NAME = "mocksmtpd"
15
- AUTHOR = "KOSEKI Kengo"
16
- EMAIL = "koseki@gmail.com"
17
- DESCRIPTION = "Mock SMTP server for development/testing."
18
- RUBYFORGE_PROJECT = "mocksmtpd"
19
- HOMEPATH = "http://github.com/koseki/mocksmtpd/"
20
- BIN_FILES = %w(mocksmtpd)
21
-
22
- VERS = Mocksmtpd::VERSION
23
- REV = File.read(".svn/entries")[/committed-rev="(d+)"/, 1] rescue nil
24
- CLEAN.include ['**/.*.sw?', '*.gem', '.config']
25
- RDOC_OPTS = [
26
- '--title', "#{NAME} documentation",
27
- "--charset", "utf-8",
28
- "--opname", "index.html",
29
- "--line-numbers",
30
- "--main", "README",
31
- "--inline-source",
32
- ]
33
-
34
- task :default => [:test]
35
- task :package => [:clean]
36
-
37
- Rake::TestTask.new("test") do |t|
38
- t.libs << "test"
39
- t.pattern = "test/**/*_test.rb"
40
- t.verbose = true
41
- end
42
-
43
- spec = Gem::Specification.new do |s|
44
- s.name = NAME
45
- s.version = VERS
46
- s.platform = Gem::Platform::RUBY
47
- s.has_rdoc = true
48
- s.extra_rdoc_files = ["README", "ChangeLog"]
49
- s.rdoc_options += RDOC_OPTS + ['--exclude', '^(examples|extras)/']
50
- s.summary = DESCRIPTION
51
- s.description = DESCRIPTION
52
- s.author = AUTHOR
53
- s.email = EMAIL
54
- s.homepage = HOMEPATH
55
- s.executables = BIN_FILES
56
- s.rubyforge_project = RUBYFORGE_PROJECT
57
- s.bindir = "bin"
58
- s.require_path = "lib"
59
- #s.autorequire = ""
60
- s.test_files = Dir["test/*_test.rb"]
61
-
62
- #s.add_dependency('activesupport', '>=1.3.1')
63
- #s.required_ruby_version = '>= 1.8.2'
64
-
65
- s.files = %w(README ChangeLog Rakefile) +
66
- Dir.glob("{bin,doc,test,lib,templates,generator,extras,website,script}/**/*") +
67
- Dir.glob("ext/**/*.{h,c,rb}") +
68
- Dir.glob("examples/**/*.rb") +
69
- Dir.glob("tools/*.rb") +
70
- Dir.glob("rails/*.rb")
71
-
72
- s.extensions = FileList["ext/**/extconf.rb"].to_a
73
- end
74
-
75
- Rake::GemPackageTask.new(spec) do |p|
76
- p.need_tar = true
77
- p.gem_spec = spec
78
- end
79
-
80
- task :install do
81
- name = "#{NAME}-#{VERS}.gem"
82
- sh %{rake package}
83
- sh %{sudo gem install pkg/#{name}}
84
- end
85
-
86
- task :uninstall => [:clean] do
87
- sh %{sudo gem uninstall #{NAME}}
88
- end
89
-
90
-
91
- Rake::RDocTask.new do |rdoc|
92
- rdoc.rdoc_dir = 'html'
93
- rdoc.options += RDOC_OPTS
94
- rdoc.template = "resh"
95
- #rdoc.template = "#{ENV['template']}.rb" if ENV['template']
96
- if ENV['DOC_FILES']
97
- rdoc.rdoc_files.include(ENV['DOC_FILES'].split(/,\s*/))
98
- else
99
- rdoc.rdoc_files.include('README', 'ChangeLog')
100
- rdoc.rdoc_files.include('lib/**/*.rb')
101
- rdoc.rdoc_files.include('ext/**/*.c')
102
- end
103
- end
104
-
105
- desc "Publish to RubyForge"
106
- task :rubyforge => [:rdoc, :package] do
107
- require 'rubyforge'
108
- Rake::RubyForgePublisher.new(RUBYFORGE_PROJECT, '').upload
109
- end
110
-
111
- desc 'Package and upload the release to rubyforge.'
112
- task :release => [:clean, :package] do |t|
113
- v = ENV["VERSION"] or abort "Must supply VERSION=x.y.z"
114
- abort "Versions don't match #{v} vs #{VERS}" unless v == VERS
115
- pkg = "pkg/#{NAME}-#{VERS}"
116
-
117
- require 'rubyforge'
118
- rf = RubyForge.new.configure
119
- puts "Logging in"
120
- rf.login
121
-
122
- c = rf.userconfig
123
- # c["release_notes"] = description if description
124
- # c["release_changes"] = changes if changes
125
- c["preformatted"] = true
126
-
127
- files = [
128
- "#{pkg}.tgz",
129
- "#{pkg}.gem"
130
- ].compact
131
-
132
- puts "Releasing #{NAME} v. #{VERS}"
133
- rf.add_release RUBYFORGE_PROJECT, NAME, VERS, *files
134
- end
135
-
136
- desc 'Show information about the gem.'
137
- task :debug_gem do
138
- puts spec.to_ruby
139
- end
140
-
141
- desc 'Update gem spec'
142
- task :gemspec do
143
- open("#{NAME}.gemspec", 'w').write spec.to_ruby
144
- end
1
+ require "bundler/gem_tasks"
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+
5
+ require_relative 'lib/mocksmtpd'
6
+
7
+ task :default => [:test]
8
+
9
+ Rake::TestTask.new("test") do |t|
10
+ t.libs << "test"
11
+ t.pattern = "test/**/*_test.rb"
12
+ t.verbose = true
13
+ end
data/bin/mocksmtpd CHANGED
@@ -1,6 +1,6 @@
1
- #! /usr/bin/env ruby
2
-
3
- require "rubygems"
4
- require "mocksmtpd"
5
-
1
+ #! /usr/bin/env ruby
2
+
3
+ require "rubygems"
4
+ require "mocksmtpd"
5
+
6
6
  Mocksmtpd.new(ARGV).run
data/lib/mocksmtpd.rb CHANGED
@@ -8,7 +8,7 @@ require 'nkf'
8
8
  require 'smtpserver'
9
9
 
10
10
  class Mocksmtpd
11
- VERSION = '0.0.3'
11
+ VERSION = '0.0.4'
12
12
  TEMPLATE_DIR = Pathname.new(File.dirname(__FILE__)) + "../templates"
13
13
 
14
14
  include ERB::Util
@@ -132,8 +132,13 @@ class Mocksmtpd
132
132
 
133
133
  pid = File.read(@pidfile)
134
134
  print "Stopping #{pid}..." unless @silent
135
- #system "kill -TERM #{pid}"
136
- system "taskkill /F /PID #{pid} 1>NUL"
135
+ if RbConfig::CONFIG['host_os'] =~ /mswin|mingw/
136
+ system "taskkill /F /PID #{pid} 1>NUL"
137
+ else
138
+ system "sudo kill -TERM #{pid} 1>NUL"
139
+ end
140
+ sleep(1)
141
+ File.delete(@pidfile) if File.exist?(@pidfile)
137
142
  puts "done" unless @silent
138
143
  end
139
144
 
@@ -177,7 +182,7 @@ class Mocksmtpd
177
182
  end
178
183
 
179
184
  def delete_pid_file
180
- File.delete(@pidfile)
185
+ File.delete(@pidfile) if File.exist?(@pidfile)
181
186
  @logger.debug("pid file deleted: file=#{@pidfile}")
182
187
  end
183
188
 
@@ -253,9 +258,9 @@ class Mocksmtpd
253
258
  subject = src.match(/^Subject:\s*(.+)/i).to_a[1].to_s.strip
254
259
  date = src.match(/^Date:\s*(.+)/i).to_a[1].to_s.strip
255
260
 
256
- src = ERB::Util.h(src)
257
- src = src.gsub(%r{https?://[-_.!~*\'()a-zA-Z0-9;\/?:\@&=+\$,%#]+},'<a href="\0">\0</a>')
258
- src = src.gsub(/(?:\r\n|\r|\n)/, "<br />\n")
261
+ # src = ERB::Util.h(src)
262
+ # src = src.gsub(%r{https?://[-_.!~*\'()a-zA-Z0-9;\/?:\@&=+\$,%#]+},'<a href="\0">\0</a>')
263
+ # src = src.gsub(/(?:\r\n|\r|\n)/, "<br />\n")
259
264
 
260
265
  if date.empty?
261
266
  date = Time.now
data/lib/smtpserver.rb CHANGED
@@ -1,257 +1,257 @@
1
- # http://tmtm.org/ja/ruby/smtpd/
2
- # http://rubyist.g.hatena.ne.jp/muscovyduck/20070707/p1
3
-
4
- require 'webrick'
5
- require 'tempfile'
6
-
7
- module GetsSafe
8
- def gets_safe(rs = nil, timeout = @timeout, maxlength = @maxlength)
9
- rs = $/ unless rs
10
- f = self.kind_of?(IO) ? self : STDIN
11
- @gets_safe_buf = '' unless @gets_safe_buf
12
- until @gets_safe_buf.include? rs do
13
- if maxlength and @gets_safe_buf.length > maxlength then
14
- raise Errno::E2BIG, 'too long'
15
- end
16
- if IO.select([f], nil, nil, timeout) == nil then
17
- raise Errno::ETIMEDOUT, 'timeout exceeded'
18
- end
19
- begin
20
- @gets_safe_buf << f.sysread(4096)
21
- rescue EOFError, Errno::ECONNRESET
22
- return @gets_safe_buf.empty? ? nil : @gets_safe_buf.slice!(0..-1)
23
- end
24
- end
25
- p = @gets_safe_buf.index rs
26
- if maxlength and p > maxlength then
27
- raise Errno::E2BIG, 'too long'
28
- end
29
- return @gets_safe_buf.slice!(0, p+rs.length)
30
- end
31
- attr_accessor :timeout, :maxlength
32
- end
33
-
34
- class SMTPD
35
- class Error < StandardError; end
36
-
37
- def initialize(sock, domain)
38
- @sock = sock
39
- @domain = domain
40
- @error_interval = 5
41
- class << @sock
42
- include GetsSafe
43
- end
44
- @helo_hook = nil
45
- @mail_hook = nil
46
- @rcpt_hook = nil
47
- @data_hook = nil
48
- @data_each_line = nil
49
- @rset_hook = nil
50
- @noop_hook = nil
51
- @quit_hook = nil
52
- end
53
- attr_writer :helo_hook, :mail_hook, :rcpt_hook, :data_hook,
54
- :data_each_line, :rset_hook, :noop_hook, :quit_hook
55
-
56
- def start
57
- @helo_name = nil
58
- @sender = nil
59
- @recipients = []
60
- catch(:close) do
61
- puts_safe "220 #{@domain} service ready"
62
- while comm = @sock.gets_safe do
63
- catch :next_comm do
64
- comm.sub!(/\r?\n/, '')
65
- comm, arg = comm.split(/\s+/,2)
66
- break if comm == nil
67
- case comm.upcase
68
- when 'EHLO' then comm_helo arg
69
- when 'HELO' then comm_helo arg
70
- when 'MAIL' then comm_mail arg
71
- when 'RCPT' then comm_rcpt arg
72
- when 'DATA' then comm_data arg
73
- when 'RSET' then comm_rset arg
74
- when 'NOOP' then comm_noop arg
75
- when 'QUIT' then comm_quit arg
76
- else
77
- error '502 Error: command not implemented'
78
- end
79
- end
80
- end
81
- end
82
- end
83
-
84
- def line_length_limit=(n)
85
- @sock.maxlength = n
86
- end
87
-
88
- def input_timeout=(n)
89
- @sock.timeout = n
90
- end
91
-
92
- attr_reader :line_length_limit, :input_timeout
93
- attr_accessor :error_interval
94
- attr_accessor :use_file, :max_size
95
-
96
- private
97
- def comm_helo(arg)
98
- if arg == nil or arg.split.size != 1 then
99
- error '501 Syntax: HELO hostname'
100
- end
101
- @helo_hook.call(arg) if @helo_hook
102
- @helo_name = arg
103
- reply "250 #{@domain}"
104
- end
105
-
106
- def comm_mail(arg)
107
- if @sender != nil then
108
- error '503 Error: nested MAIL command'
109
- end
110
- if arg !~ /^FROM:/i then
111
- error '501 Syntax: MAIL FROM: <address>'
112
- end
113
- sender = parse_addr $'
114
- if sender == nil then
115
- error '501 Syntax: MAIL FROM: <address>'
116
- end
117
- @mail_hook.call(sender) if @mail_hook
118
- @sender = sender
119
- reply '250 Ok'
120
- end
121
-
122
- def comm_rcpt(arg)
123
- if @sender == nil then
124
- error '503 Error: need MAIL command'
125
- end
126
- if arg !~ /^TO:/i then
127
- error '501 Syntax: RCPT TO: <address>'
128
- end
129
- rcpt = parse_addr $'
130
- if rcpt == nil then
131
- error '501 Syntax: RCPT TO: <address>'
132
- end
133
- @rcpt_hook.call(rcpt) if @rcpt_hook
134
- @recipients << rcpt
135
- reply '250 Ok'
136
- end
137
-
138
- def comm_data(arg)
139
- if @recipients.size == 0 then
140
- error '503 Error: need RCPT command'
141
- end
142
- if arg != nil then
143
- error '501 Syntax: DATA'
144
- end
145
- reply '354 End data with <CR><LF>.<CR><LF>'
146
- if @data_hook
147
- tmpf = @use_file ? Tempfile.new('smtpd') : ''
148
- end
149
- size = 0
150
- loop do
151
- l = @sock.gets_safe
152
- if l == nil then
153
- raise SMTPD::Error, 'unexpected EOF'
154
- end
155
- if l.chomp == '.' then break end
156
- if l[0] == ?. then
157
- l[0,1] = ''
158
- end
159
- size += l.size
160
- if @max_size and @max_size < size then
161
- error '552 Error: message too large'
162
- end
163
- @data_each_line.call(l) if @data_each_line
164
- tmpf << l if @data_hook
165
- end
166
- if @data_hook then
167
- if @use_file then
168
- tmpf.pos = 0
169
- @data_hook.call(tmpf, @sender, @recipients)
170
- tmpf.close(true)
171
- else
172
- @data_hook.call(tmpf, @sender, @recipients)
173
- end
174
- end
175
- reply '250 Ok'
176
- @sender = nil
177
- @recipients = []
178
- end
179
-
180
- def comm_rset(arg)
181
- if arg != nil then
182
- error '501 Syntax: RSET'
183
- end
184
- @rset_hook.call(@sender, @recipients) if @rset_hook
185
- reply '250 Ok'
186
- @sender = nil
187
- @recipients = []
188
- end
189
-
190
- def comm_noop(arg)
191
- if arg != nil then
192
- error '501 Syntax: NOOP'
193
- end
194
- @noop_hook.call(@sender, @recipients) if @noop_hook
195
- reply '250 Ok'
196
- end
197
-
198
- def comm_quit(arg)
199
- if arg != nil then
200
- error '501 Syntax: QUIT'
201
- end
202
- @quit_hook.call(@sender, @recipients) if @quit_hook
203
- reply '221 Bye'
204
- throw :close
205
- end
206
-
207
- def parse_addr(str)
208
- str = str.strip
209
- if str == '' then
210
- return nil
211
- end
212
- if str =~ /^<(.*)>$/ then
213
- return $1.gsub(/\s+/, '')
214
- end
215
- if str =~ /\s/ then
216
- return nil
217
- end
218
- str
219
- end
220
-
221
- def reply(msg)
222
- puts_safe msg
223
- end
224
-
225
- def error(msg)
226
- sleep @error_interval if @error_interval
227
- puts_safe msg
228
- throw :next_comm
229
- end
230
-
231
- def puts_safe(str)
232
- begin
233
- @sock.puts str + "\r\n"
234
- rescue
235
- raise SMTPD::Error, "cannot send to client: '#{str.gsub(/\s+/," ")}': #{$!.to_s}"
236
- end
237
- end
238
- end
239
-
240
- SMTPDError = SMTPD::Error
241
-
242
- class SMTPServer < WEBrick::GenericServer
243
- def run(sock)
244
- server = SMTPD.new(sock, @config[:ServerName])
245
- server.input_timeout = @config[:RequestTimeout]
246
- server.line_length_limit = @config[:LineLengthLimit]
247
- server.helo_hook = @config[:HeloHook]
248
- server.mail_hook = @config[:MailHook]
249
- server.rcpt_hook = @config[:RcptHook]
250
- server.data_hook = @config[:DataHook]
251
- server.data_each_line = @config[:DataEachLine]
252
- server.rset_hook = @config[:RsetHook]
253
- server.noop_hook = @config[:NoopHook]
254
- server.quit_hook = @config[:QuitHook]
255
- server.start
256
- end
257
- end
1
+ # http://tmtm.org/ja/ruby/smtpd/
2
+ # http://rubyist.g.hatena.ne.jp/muscovyduck/20070707/p1
3
+
4
+ require 'webrick'
5
+ require 'tempfile'
6
+
7
+ module GetsSafe
8
+ def gets_safe(rs = nil, timeout = @timeout, maxlength = @maxlength)
9
+ rs = $/ unless rs
10
+ f = self.kind_of?(IO) ? self : STDIN
11
+ @gets_safe_buf = '' unless @gets_safe_buf
12
+ until @gets_safe_buf.include? rs do
13
+ if maxlength and @gets_safe_buf.length > maxlength then
14
+ raise Errno::E2BIG, 'too long'
15
+ end
16
+ if IO.select([f], nil, nil, timeout) == nil then
17
+ raise Errno::ETIMEDOUT, 'timeout exceeded'
18
+ end
19
+ begin
20
+ @gets_safe_buf << f.sysread(4096)
21
+ rescue EOFError, Errno::ECONNRESET
22
+ return @gets_safe_buf.empty? ? nil : @gets_safe_buf.slice!(0..-1)
23
+ end
24
+ end
25
+ p = @gets_safe_buf.index rs
26
+ if maxlength and p > maxlength then
27
+ raise Errno::E2BIG, 'too long'
28
+ end
29
+ return @gets_safe_buf.slice!(0, p+rs.length)
30
+ end
31
+ attr_accessor :timeout, :maxlength
32
+ end
33
+
34
+ class SMTPD
35
+ class Error < StandardError; end
36
+
37
+ def initialize(sock, domain)
38
+ @sock = sock
39
+ @domain = domain
40
+ @error_interval = 5
41
+ class << @sock
42
+ include GetsSafe
43
+ end
44
+ @helo_hook = nil
45
+ @mail_hook = nil
46
+ @rcpt_hook = nil
47
+ @data_hook = nil
48
+ @data_each_line = nil
49
+ @rset_hook = nil
50
+ @noop_hook = nil
51
+ @quit_hook = nil
52
+ end
53
+ attr_writer :helo_hook, :mail_hook, :rcpt_hook, :data_hook,
54
+ :data_each_line, :rset_hook, :noop_hook, :quit_hook
55
+
56
+ def start
57
+ @helo_name = nil
58
+ @sender = nil
59
+ @recipients = []
60
+ catch(:close) do
61
+ puts_safe "220 #{@domain} service ready"
62
+ while comm = @sock.gets_safe do
63
+ catch :next_comm do
64
+ comm.sub!(/\r?\n/, '')
65
+ comm, arg = comm.split(/\s+/,2)
66
+ break if comm == nil
67
+ case comm.upcase
68
+ when 'EHLO' then comm_helo arg
69
+ when 'HELO' then comm_helo arg
70
+ when 'MAIL' then comm_mail arg
71
+ when 'RCPT' then comm_rcpt arg
72
+ when 'DATA' then comm_data arg
73
+ when 'RSET' then comm_rset arg
74
+ when 'NOOP' then comm_noop arg
75
+ when 'QUIT' then comm_quit arg
76
+ else
77
+ error '502 Error: command not implemented'
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+
84
+ def line_length_limit=(n)
85
+ @sock.maxlength = n
86
+ end
87
+
88
+ def input_timeout=(n)
89
+ @sock.timeout = n
90
+ end
91
+
92
+ attr_reader :line_length_limit, :input_timeout
93
+ attr_accessor :error_interval
94
+ attr_accessor :use_file, :max_size
95
+
96
+ private
97
+ def comm_helo(arg)
98
+ if arg == nil or arg.split.size != 1 then
99
+ error '501 Syntax: HELO hostname'
100
+ end
101
+ @helo_hook.call(arg) if @helo_hook
102
+ @helo_name = arg
103
+ reply "250 #{@domain}"
104
+ end
105
+
106
+ def comm_mail(arg)
107
+ if @sender != nil then
108
+ error '503 Error: nested MAIL command'
109
+ end
110
+ if arg !~ /^FROM:/i then
111
+ error '501 Syntax: MAIL FROM: <address>'
112
+ end
113
+ sender = parse_addr $'
114
+ if sender == nil then
115
+ error '501 Syntax: MAIL FROM: <address>'
116
+ end
117
+ @mail_hook.call(sender) if @mail_hook
118
+ @sender = sender
119
+ reply '250 Ok'
120
+ end
121
+
122
+ def comm_rcpt(arg)
123
+ if @sender == nil then
124
+ error '503 Error: need MAIL command'
125
+ end
126
+ if arg !~ /^TO:/i then
127
+ error '501 Syntax: RCPT TO: <address>'
128
+ end
129
+ rcpt = parse_addr $'
130
+ if rcpt == nil then
131
+ error '501 Syntax: RCPT TO: <address>'
132
+ end
133
+ @rcpt_hook.call(rcpt) if @rcpt_hook
134
+ @recipients << rcpt
135
+ reply '250 Ok'
136
+ end
137
+
138
+ def comm_data(arg)
139
+ if @recipients.size == 0 then
140
+ error '503 Error: need RCPT command'
141
+ end
142
+ if arg != nil then
143
+ error '501 Syntax: DATA'
144
+ end
145
+ reply '354 End data with <CR><LF>.<CR><LF>'
146
+ if @data_hook
147
+ tmpf = @use_file ? Tempfile.new('smtpd') : ''
148
+ end
149
+ size = 0
150
+ loop do
151
+ l = @sock.gets_safe
152
+ if l == nil then
153
+ raise SMTPD::Error, 'unexpected EOF'
154
+ end
155
+ if l.chomp == '.' then break end
156
+ if l[0] == ?. then
157
+ l[0,1] = ''
158
+ end
159
+ size += l.size
160
+ if @max_size and @max_size < size then
161
+ error '552 Error: message too large'
162
+ end
163
+ @data_each_line.call(l) if @data_each_line
164
+ tmpf << l if @data_hook
165
+ end
166
+ if @data_hook then
167
+ if @use_file then
168
+ tmpf.pos = 0
169
+ @data_hook.call(tmpf, @sender, @recipients)
170
+ tmpf.close(true)
171
+ else
172
+ @data_hook.call(tmpf, @sender, @recipients)
173
+ end
174
+ end
175
+ reply '250 Ok'
176
+ @sender = nil
177
+ @recipients = []
178
+ end
179
+
180
+ def comm_rset(arg)
181
+ if arg != nil then
182
+ error '501 Syntax: RSET'
183
+ end
184
+ @rset_hook.call(@sender, @recipients) if @rset_hook
185
+ reply '250 Ok'
186
+ @sender = nil
187
+ @recipients = []
188
+ end
189
+
190
+ def comm_noop(arg)
191
+ if arg != nil then
192
+ error '501 Syntax: NOOP'
193
+ end
194
+ @noop_hook.call(@sender, @recipients) if @noop_hook
195
+ reply '250 Ok'
196
+ end
197
+
198
+ def comm_quit(arg)
199
+ if arg != nil then
200
+ error '501 Syntax: QUIT'
201
+ end
202
+ @quit_hook.call(@sender, @recipients) if @quit_hook
203
+ reply '221 Bye'
204
+ throw :close
205
+ end
206
+
207
+ def parse_addr(str)
208
+ str = str.strip
209
+ if str == '' then
210
+ return nil
211
+ end
212
+ if str =~ /^<(.*)>$/ then
213
+ return $1.gsub(/\s+/, '')
214
+ end
215
+ if str =~ /\s/ then
216
+ return nil
217
+ end
218
+ str
219
+ end
220
+
221
+ def reply(msg)
222
+ puts_safe msg
223
+ end
224
+
225
+ def error(msg)
226
+ sleep @error_interval if @error_interval
227
+ puts_safe msg
228
+ throw :next_comm
229
+ end
230
+
231
+ def puts_safe(str)
232
+ begin
233
+ @sock.puts str + "\r\n"
234
+ rescue
235
+ raise SMTPD::Error, "cannot send to client: '#{str.gsub(/\s+/," ")}': #{$!.to_s}"
236
+ end
237
+ end
238
+ end
239
+
240
+ SMTPDError = SMTPD::Error
241
+
242
+ class SMTPServer < WEBrick::GenericServer
243
+ def run(sock)
244
+ server = SMTPD.new(sock, @config[:ServerName])
245
+ server.input_timeout = @config[:RequestTimeout]
246
+ server.line_length_limit = @config[:LineLengthLimit]
247
+ server.helo_hook = @config[:HeloHook]
248
+ server.mail_hook = @config[:MailHook]
249
+ server.rcpt_hook = @config[:RcptHook]
250
+ server.data_hook = @config[:DataHook]
251
+ server.data_each_line = @config[:DataEachLine]
252
+ server.rset_hook = @config[:RsetHook]
253
+ server.noop_hook = @config[:NoopHook]
254
+ server.quit_hook = @config[:QuitHook]
255
+ server.start
256
+ end
257
+ end
@@ -1,46 +1,46 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3
- <html xmlns="http://www.w3.org/1999/xhtml">
4
- <head>
5
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
6
- <link rel="index" href="./index.html" />
7
- <title>Inbox</title>
8
- <style type="text/css">
9
- body {
10
- background:#eee;
11
- }
12
- table {
13
- border: 1px #999 solid;
14
- border-collapse: collapse;
15
- }
16
- th, td {
17
- border: 1px #999 solid;
18
- padding: 6px 12px;
19
- }
20
- th {
21
- background: #ccc;
22
- }
23
- td {
24
- background: white;
25
- }
26
- </style>
27
- </head>
28
- <body>
29
- <h1>Inbox</h1>
30
- <table>
31
- <thead>
32
- <tr>
33
- <th>Date</th>
34
- <th>Subject</th>
35
- <th>From</th>
36
- <th>To</th>
37
- </tr>
38
- </thead>
39
-
40
- <tbody>
41
- <!-- ADD -->
42
-
43
- </tbody>
44
- </table>
45
- </body>
46
- </html>
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3
+ <html xmlns="http://www.w3.org/1999/xhtml">
4
+ <head>
5
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
6
+ <link rel="index" href="./index.html" />
7
+ <title>Inbox</title>
8
+ <style type="text/css">
9
+ body {
10
+ background:#eee;
11
+ }
12
+ table {
13
+ border: 1px #999 solid;
14
+ border-collapse: collapse;
15
+ }
16
+ th, td {
17
+ border: 1px #999 solid;
18
+ padding: 6px 12px;
19
+ }
20
+ th {
21
+ background: #ccc;
22
+ }
23
+ td {
24
+ background: white;
25
+ }
26
+ </style>
27
+ </head>
28
+ <body>
29
+ <h1>Inbox</h1>
30
+ <table>
31
+ <thead>
32
+ <tr>
33
+ <th>Date</th>
34
+ <th>Subject</th>
35
+ <th>From</th>
36
+ <th>To</th>
37
+ </tr>
38
+ </thead>
39
+
40
+ <tbody>
41
+ <!-- ADD -->
42
+
43
+ </tbody>
44
+ </table>
45
+ </body>
46
+ </html>
@@ -1,8 +1,8 @@
1
- <!-- ADD -->
2
-
3
- <tr>
4
- <td><%= mail[:date].strftime("%Y-%m-%d %H:%M:%S") %></td>
5
- <td><a href="<%=h mail[:file] %>"><%=h mail[:subject] %></a></td>
6
- <td><%=h mail[:sender] %></td>
7
- <td><%=h mail[:recipients].to_a.join(",") %></td>
8
- </tr>
1
+ <!-- ADD -->
2
+
3
+ <tr>
4
+ <td><%= mail[:date].strftime("%Y-%m-%d %H:%M:%S") %></td>
5
+ <td><a href="<%=h mail[:file] %>"><%=h mail[:subject] %></a></td>
6
+ <td><%=h mail[:sender] %></td>
7
+ <td><%=h mail[:recipients].to_a.join(",") %></td>
8
+ </tr>
@@ -1,16 +1,16 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3
- <html xmlns="http://www.w3.org/1999/xhtml">
4
- <head>
5
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
6
- <link rel="index" href="./index.html" />
7
- <title><%=h mail[:subject] %> (<%= mail[:date].to_s %>)</title>
8
- </head>
9
- <body style="background:#eee">
10
- <h1 id="subject"><%=h mail[:subject] %></h1>
11
- <div><p id="date" style="font-size:0.8em;"><%= mail[:date].to_s %></div>
12
- <div id="source" style="border: solid 1px #666; background:white; padding:2em;">
13
- <p><%= mail[:source] %></p>
14
- </div>
15
- </body>
16
- </html>
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3
+ <html xmlns="http://www.w3.org/1999/xhtml">
4
+ <head>
5
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
6
+ <link rel="index" href="./index.html" />
7
+ <title><%=h mail[:subject] %> (<%= mail[:date].to_s %>)</title>
8
+ </head>
9
+ <body style="background:#eee">
10
+ <h1 id="subject"><%=h mail[:subject] %></h1>
11
+ <div><p id="date" style="font-size:0.8em;"><%= mail[:date].to_s %></div>
12
+ <div id="source" style="border: solid 1px #666; background:white; padding:2em;">
13
+ <p><%= mail[:source] %></p>
14
+ </div>
15
+ </body>
16
+ </html>
@@ -1,10 +1,10 @@
1
- ServerName: mocksmtpd
2
- Port: 25
3
- RequestTimeout: 120
4
- LineLengthLimit: 1024
5
- LogLevel: INFO
6
-
7
- LogFile: ./log/mocksmtpd.log
8
- PidFile: ./log/mocksmtpd.pid
9
- InboxDir: ./inbox
10
- Umask: 2
1
+ ServerName: mocksmtpd
2
+ Port: 25
3
+ RequestTimeout: 120
4
+ LineLengthLimit: 1024
5
+ LogLevel: INFO
6
+
7
+ LogFile: ./log/mocksmtpd.log
8
+ PidFile: ./log/mocksmtpd.pid
9
+ InboxDir: ./inbox
10
+ Umask: 2
@@ -1,5 +1,5 @@
1
- require File.dirname(__FILE__) + '/test_helper.rb'
2
-
3
- require "test/unit"
4
- class MocksmtpdTest < Test::Unit::TestCase
5
- end
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ require "test/unit"
4
+ class MocksmtpdTest < Test::Unit::TestCase
5
+ end
data/test/test_helper.rb CHANGED
@@ -1,3 +1,3 @@
1
- require 'test/unit'
2
- require File.dirname(__FILE__) + '/../lib/mocksmtpd'
3
-
1
+ require 'test/unit'
2
+ require File.dirname(__FILE__) + '/../lib/mocksmtpd'
3
+
metadata CHANGED
@@ -1,78 +1,69 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: boomerang-mocksmtpd
3
- version: !ruby/object:Gem::Version
4
- version: 0.0.3
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.4
5
5
  platform: ruby
6
- authors:
7
- - BB
8
- autorequire:
6
+ authors:
7
+ - BB
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
-
12
- date: 2008-11-08 00:00:00 +01:00
13
- default_executable: mocksmtpd
11
+ date: 2008-11-08 00:00:00.000000000 Z
14
12
  dependencies: []
15
-
16
13
  description: Mock SMTP server for development/testing.
17
14
  email: b@gmail.com
18
- executables:
19
- - mocksmtpd
15
+ executables:
16
+ - mocksmtpd
20
17
  extensions: []
21
-
22
- extra_rdoc_files:
23
- - README
24
- - ChangeLog
25
- files:
26
- - README
27
- - ChangeLog
28
- - Rakefile
29
- - bin/mocksmtpd
30
- - test/mocksmtpd_test.rb
31
- - test/test_helper.rb
32
- - lib/mocksmtpd.rb
33
- - lib/smtpserver.rb
34
- - templates/html/index.erb
35
- - templates/html/index_entry.erb
36
- - templates/html/mail.erb
37
- - templates/mocksmtpd.conf.erb
38
- has_rdoc: true
18
+ extra_rdoc_files:
19
+ - README
20
+ - ChangeLog
21
+ files:
22
+ - ChangeLog
23
+ - README
24
+ - Rakefile
25
+ - bin/mocksmtpd
26
+ - lib/mocksmtpd.rb
27
+ - lib/smtpserver.rb
28
+ - templates/html/index.erb
29
+ - templates/html/index_entry.erb
30
+ - templates/html/mail.erb
31
+ - templates/mocksmtpd.conf.erb
32
+ - test/mocksmtpd_test.rb
33
+ - test/test_helper.rb
39
34
  homepage: http://github.com/boomerang/mocksmtpd/
40
35
  licenses: []
41
-
42
- post_install_message:
43
- rdoc_options:
44
- - --title
45
- - mocksmtpd documentation
46
- - --charset
47
- - utf-8
48
- - --opname
49
- - index.html
50
- - --line-numbers
51
- - --main
52
- - README
53
- - --inline-source
54
- - --exclude
55
- - ^(examples|extras)/
56
- require_paths:
57
- - lib
58
- required_ruby_version: !ruby/object:Gem::Requirement
59
- requirements:
60
- - - ">="
61
- - !ruby/object:Gem::Version
62
- version: "0"
63
- version:
64
- required_rubygems_version: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
67
- - !ruby/object:Gem::Version
68
- version: "0"
69
- version:
36
+ metadata: {}
37
+ post_install_message:
38
+ rdoc_options:
39
+ - "--title"
40
+ - mocksmtpd documentation
41
+ - "--charset"
42
+ - utf-8
43
+ - "--opname"
44
+ - index.html
45
+ - "--line-numbers"
46
+ - "--main"
47
+ - README
48
+ - "--inline-source"
49
+ - "--exclude"
50
+ - "^(examples|extras)/"
51
+ require_paths:
52
+ - lib
53
+ required_ruby_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
70
63
  requirements: []
71
-
72
- rubyforge_project: mocksmtpd
73
- rubygems_version: 1.3.5
74
- signing_key:
64
+ rubygems_version: 3.0.3.1
65
+ signing_key:
75
66
  specification_version: 2
76
67
  summary: Mock SMTP server for development/testing.
77
- test_files:
78
- - test/mocksmtpd_test.rb
68
+ test_files:
69
+ - test/mocksmtpd_test.rb