boomerang-mocksmtpd 0.0.3 → 0.0.5

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: b4b799bb74fb8ad18780af6399f27c310c8af6ae485b3469f386159458220f45
4
+ data.tar.gz: f82c8d20b990ab736f7f0358e966567acd992dad168aeacc997ea39f3a405df2
5
+ SHA512:
6
+ metadata.gz: 7e47d1f2fb10e10a46a3bf9bb223736b883c387cfdfd677e9daef97c88ee14b3cd0c183075cec641ef9bc50df2b4608eacc389ace87ae314ee6d957a7f0b4482
7
+ data.tar.gz: 17f782d77ced0a5cb46edec9b23072d1de80b766a9871af114b97c81f190cff379a1f272de1d3afbfb636c54834f561efa989b25def214eaaa43525321bb69ad
data/ChangeLog CHANGED
@@ -1,17 +1,26 @@
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.5 / 2025-07-31
2
+
3
+ * Passing trim_mode with the 3rd argument of ERB.new is deprecated
4
+
5
+ == 0.0.4 / 2022-06-17
6
+
7
+ * support for pid file in windows/linux
8
+ * added --silent option
9
+
10
+ == 0.0.3 / 2008-11-08
11
+
12
+ * rescue Process.eid NotImplementedError.
13
+ * warn when Process.eid can't be changed.
14
+ * read log level from config file.
15
+ * change param name from Loglevel to LogLevel
16
+ * add debug log.
17
+
18
+ == 0.0.2 / 2008-11-03
19
+
20
+ * release gem version.
21
+
22
+ == 0.0.1 / 2008-11-03
23
+
24
+ * moved into github
25
+ * initial release
26
+
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.5'
12
12
  TEMPLATE_DIR = Pathname.new(File.dirname(__FILE__)) + "../templates"
13
13
 
14
14
  include ERB::Util
@@ -101,7 +101,7 @@ class Mocksmtpd
101
101
  def template(name)
102
102
  path = TEMPLATE_DIR + "#{name}.erb"
103
103
  src = path.read
104
- return ERB.new(src, nil, "%-")
104
+ return ERB.new(src, trim_mode: "%-")
105
105
  end
106
106
 
107
107
  def init
@@ -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.5
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.3.26
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