eventmachine-email_server 0.0.5 → 0.0.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 21e73cc7eef3bcb21a34c103138939f1f9f216cf
4
- data.tar.gz: 03f42527251cde1a286b920f1ee50c84a1318596
3
+ metadata.gz: f9618746cec3c86bbed9a6ec20828cc326279246
4
+ data.tar.gz: 99191abe30a58e83b6a1c764a354c4ec5d4337dd
5
5
  SHA512:
6
- metadata.gz: 59518897af038bd1fb86ff14cda06f4ec6cd3c4363b2730af532611d8aab3c16123be073973aa08a253dd7c271112efcb613e70aeabed5bd5112f07ce6d86725
7
- data.tar.gz: 40f009d49032f6bba06e0a7b4ba215530c788687f648e49e4e1d89f1075a9d60649ef56d62b35262f09852850dab56c46d6ef5a7284c44948ef8873bf9bbf6ec
6
+ metadata.gz: 4dd0f0614b1522e4421fe937c22cc064a2f2cb9da4cd231de94b0288d36ae62f28c70dd852c62c3e60b8ada66e7397dbba021d7328b98b9d4d8d07a61c302485
7
+ data.tar.gz: 461427eb727203f4850c8d2d52d3fdf716df05e23ad316c9621a91de959c0e222006a7c18bbe96cba023c6fc6e46b0849cff58cb7ff9c5404e89c81bce5596e7
data/README.md CHANGED
@@ -39,6 +39,7 @@ Or install it yourself as:
39
39
 
40
40
  Simple usage:
41
41
 
42
+ require 'eventmachine'
42
43
  require 'eventmachine/email_server'
43
44
  include EventMachine::EmailServer
44
45
  EM.run {
@@ -48,38 +49,39 @@ Simple usage:
48
49
 
49
50
  Everything turned on:
50
51
 
52
+ require 'eventmachine'
51
53
  require 'eventmachine/email_server'
52
54
  include EventMachine::EmailServer
53
55
  require 'ratelimit/bucketbased'
54
- require 'dnsbl/client'
55
- require 'sqlite3'
56
56
 
57
- s = SQLite3::Database.new("email_server.sqlite3")
58
- userstore = Sqlite3UserStore.new(s)
59
- emailstore = Sqlite3EmailStore.new(s)
60
- userstore << User.new(1, "chris", "password", "chris@example.org")
61
-
57
+ userstore = MemoryUserStore.new()
58
+ emailstore = MemoryEmailStore.new()
59
+ userstore << User.new(1, "chris", "chris", "chris@example.org")
60
+
62
61
  config = {
63
62
  'default' => RateLimit::Config.new('default', 2, 2, -2, 1, 1, 1),
64
63
  }
65
64
  storage = RateLimit::Memory.new
66
65
  rl = RateLimit::BucketBased.new(storage, config, 'default')
67
-
66
+
68
67
  classifier = EventMachine::EmailServer::Classifier.new("test/test.classifier", [:spam, :ham], [:spam])
69
68
  classifier.train(:spam, "Amazing pillz viagra cialis levitra staxyn")
70
69
  classifier.train(:ham, "Big pigs make great bacon")
71
-
70
+
72
71
  SMTPServer.reverse_ptr_check(true)
73
72
  SMTPServer.graylist(Hash.new)
74
73
  SMTPServer.ratelimiter(rl)
75
- SMTPServer.dnsbl_check(true)
74
+ SMTPServer.dnsbl_check(true)
76
75
  SMTPServer.spf_check(true)
77
76
  SMTPServer.reject_filters << /viagra/i
78
77
  SMTPServer.classifier(classifier)
79
-
78
+
80
79
  EM.run {
81
80
  pop3 = EventMachine::start_server "0.0.0.0", 2110, POP3Server, "example.org", userstore, emailstore
82
81
  smtp = EventMachine::start_server "0.0.0.0", 2025, SMTPServer, "example.org", userstore, emailstore
82
+ timer = EventMachine::Timer.new(0.1) do
83
+ EM.stop
84
+ end
83
85
  }
84
86
 
85
87
 
@@ -23,13 +23,17 @@ module EventMachine
23
23
 
24
24
  def receive_data(data)
25
25
  puts ">> #{data}" if @debug
26
- ok, op = process_line(data)
27
- if ok
28
- puts "<< #{op}" if @debug
29
- send_data(op+"\r\n")
26
+ data.split(/[\r\n]+/).each do |line|
27
+ process_line(line)
30
28
  end
31
29
  end
32
30
 
31
+ def send(data, close=false)
32
+ puts "<< #{data}" if @debug
33
+ send_data("#{data}\r\n")
34
+ close_connection if close
35
+ end
36
+
33
37
  def unbind(reason=nil)
34
38
  @emails.find_all {|e| e.marked}.each do |email|
35
39
  @emailstore.delete_email(email)
@@ -38,107 +42,124 @@ module EventMachine
38
42
  end
39
43
 
40
44
  def process_line(line)
41
- line.chomp!
42
- case @state
45
+ case @state
43
46
  when 'auth'
44
- case line
45
- when /^QUIT$/
46
- return false, "+OK dewey POP3 server signing off"
47
- when /^CAPA$/
48
- return true, "+OK Capability list follows\r\n"+@@capabilities.join("\r\n")+"\r\n."
49
- when /^USER (.+)$/
50
- user($1)
51
- if @user
52
- return true, "+OK #{@user.username} is most welcome here"
53
- else
54
- @failed += 1
55
- if @failed > 2
56
- return false, "-ERR you're out!"
57
- end
58
- return true, "-ERR sorry, no mailbox for #{$1} here"
59
- end
60
- when /^PASS (.+)$/
61
- if pass($1)
62
- @state = 'trans'
63
- emails
64
- msgs, bytes = stat
65
- return true, "+OK #{@user.username}'s maildrop has #{msgs} messages (#{bytes} octets)"
66
- else
67
- @failed += 1
68
- if @failed > 2
69
- return false, "-ERR you're out!"
70
- end
71
- return true, "-ERR no dope."
72
- end
73
- when /^APOP ([^\s]+) (.+)$/
74
- if apop($1,$2)
75
- @state = 'trans'
76
- emails
77
- return true, "+OK #{@user.username} is most welcome here"
78
- else
79
- @failed += 1
80
- if @failed > 2
81
- return false, "-ERR you're out!"
82
- end
83
- return true, "-ERR sorry, no mailbox for #{$1} here"
84
- end
85
- end
47
+ auth_state(line)
86
48
  when 'trans'
87
- case line
88
- when /^NOOP$/
89
- return true, "+OK"
90
- when /^STAT$/
91
- msgs, bytes = stat
92
- return true, "+OK #{msgs} #{bytes}"
93
- when /^LIST$/
94
- msgs, bytes = stat
95
- msg = "+OK #{msgs} messages (#{bytes} octets)\r\n"
96
- list.each do |num, bytes|
97
- msg += "#{num} #{bytes}\r\n"
98
- end
99
- msg += "."
100
- return true, msg
101
- when /^LIST (\d+)$/
102
- msgs, bytes = stat
103
- num, bytes = list($1)
104
- if num
105
- return true, "+OK #{num} #{bytes}"
106
- else
107
- return true, "-ERR no such message, only #{msgs} messages in maildrop"
108
- end
109
- when /^RETR (\d+)$/
110
- msg = retr($1)
111
- if msg
112
- msg = "+OK #{msg.length} octets\r\n" + msg + "\r\n."
113
- else
114
- msg = "-ERR no such message"
115
- end
116
- return true, msg
117
- when /^DELE (\d+)$/
118
- if dele($1)
119
- return true, "+OK message #{$1} marked"
120
- else
121
- return true, "-ERR message #{$1} already marked"
122
- end
123
- when /^RSET$/
124
- rset
125
- msgs, bytes = stat
126
- return true, "+OK maildrop has #{msgs} messages (#{bytes} octets)"
127
- when /^QUIT$/
128
- @state = 'update'
129
- quit
130
- msgs, bytes = stat
131
- if msgs > 0
132
- return true, "+OK dewey POP3 server signing off (#{msgs} messages left)"
133
- else
134
- return true, "+OK dewey POP3 server signing off (maildrop empty)"
135
- end
136
- when /^TOP (\d+) (\d+)$/
137
- lines = $2
138
- msg = retr($1)
139
- unless msg
140
- return true, "-ERR no such message"
141
- end
49
+ trans_state(line)
50
+ when 'update'
51
+ update_state(line)
52
+ else
53
+ send("-ERR unknown command")
54
+ end
55
+ end
56
+
57
+ def auth_state(line)
58
+ case line
59
+ when /^QUIT$/
60
+ send("+OK dewey POP3 server signing off", true)
61
+ when /^CAPA$/
62
+ send("+OK Capability list follows\r\n"+@@capabilities.join("\r\n")+"\r\n.")
63
+ when /^USER (.+)$/
64
+ user($1)
65
+ if @user
66
+ send("+OK #{@user.username} is most welcome here")
67
+ else
68
+ @failed += 1
69
+ if @failed > 2
70
+ send("-ERR you're out!", true)
71
+ else
72
+ send("-ERR sorry, no mailbox for #{$1} here")
73
+ end
74
+ end
75
+ when /^PASS (.+)$/
76
+ if pass($1)
77
+ @state = 'trans'
78
+ emails
79
+ msgs, bytes = stat
80
+ send("+OK #{@user.username}'s maildrop has #{msgs} messages (#{bytes} octets)")
81
+ else
82
+ @failed += 1
83
+ if @failed > 2
84
+ send("-ERR you're out!", true)
85
+ else
86
+ send("-ERR no dope.")
87
+ end
88
+ end
89
+ when /^APOP ([^\s]+) (.+)$/
90
+ if apop($1,$2)
91
+ @state = 'trans'
92
+ emails
93
+ send("+OK #{@user.username} is most welcome here")
94
+ else
95
+ @failed += 1
96
+ if @failed > 2
97
+ send("-ERR you're out!", true)
98
+ else
99
+ send("-ERR sorry, no mailbox for #{$1} here")
100
+ end
101
+ end
102
+ else
103
+ send("-ERR unknown command")
104
+ end
105
+ end
106
+
107
+ def trans_state(line)
108
+ case line
109
+ when /^NOOP$/
110
+ send("+OK")
111
+ when /^STAT$/
112
+ msgs, bytes = stat
113
+ send("+OK #{msgs} #{bytes}")
114
+ when /^LIST$/
115
+ msgs, bytes = stat
116
+ msg = "+OK #{msgs} messages (#{bytes} octets)\r\n"
117
+ list.each do |num, bytes|
118
+ msg += "#{num} #{bytes}\r\n"
119
+ end
120
+ msg += "."
121
+ send(msg)
122
+ when /^LIST (\d+)$/
123
+ msgs, bytes = stat
124
+ num, bytes = list($1)
125
+ if num
126
+ send("+OK #{num} #{bytes}")
127
+ else
128
+ send("-ERR no such message, only #{msgs} messages in maildrop")
129
+ end
130
+ when /^RETR (\d+)$/
131
+ msg = retr($1)
132
+ if msg
133
+ msg = "+OK #{msg.length} octets\r\n" + msg + "\r\n."
134
+ else
135
+ msg = "-ERR no such message"
136
+ end
137
+ send(msg)
138
+ when /^DELE (\d+)$/
139
+ if dele($1)
140
+ send("+OK message #{$1} marked")
141
+ else
142
+ send("-ERR message #{$1} already marked")
143
+ end
144
+ when /^RSET$/
145
+ rset
146
+ msgs, bytes = stat
147
+ send("+OK maildrop has #{msgs} messages (#{bytes} octets)")
148
+ when /^QUIT$/
149
+ @state = 'update'
150
+ quit
151
+ msgs, bytes = stat
152
+ if msgs > 0
153
+ send("+OK dewey POP3 server signing off (#{msgs} messages left)", true)
154
+ else
155
+ send("+OK dewey POP3 server signing off (maildrop empty)", true)
156
+ end
157
+ when /^TOP (\d+) (\d+)$/
158
+ lines = $2
159
+ msg = retr($1)
160
+ unless msg
161
+ send("-ERR no such message")
162
+ else
142
163
  cnt = nil
143
164
  final = ""
144
165
  msg.split(/\n/).each do |l|
@@ -151,26 +172,31 @@ module EventMachine
151
172
  cnt = 0
152
173
  end
153
174
  end
154
- return true, "+OK\r\n"+final+"\r\n."
155
- when /^UIDL$/
156
- msgid = 0
157
- msg = ''
158
- @emails.each do |e|
159
- msgid += 1
160
- next if e.marked
161
- msg += "#{msgid} #{Digest::MD5.new.update(msg).hexdigest}"
162
- end
163
- return true, "+OK\r\n#{msg}\r\n.";
164
- end
165
- when 'update'
166
- case line
167
- when /^QUIT$/
168
- return true, "+OK dewey POP3 server signing off"
169
- end
170
- end
171
- return true, "-ERR unknown command"
172
- end
173
-
175
+ send("+OK\r\n"+final+"\r\n.")
176
+ end
177
+ when /^UIDL$/
178
+ msgid = 0
179
+ msg = ''
180
+ @emails.each do |e|
181
+ msgid += 1
182
+ next if e.marked
183
+ msg += "#{msgid} #{Digest::MD5.new.update(e.body).hexdigest}\r\n"
184
+ end
185
+ send("+OK\r\n#{msg}.")
186
+ else
187
+ send("-ERR unknown command")
188
+ end
189
+ end
190
+
191
+ def update_state(line)
192
+ case line
193
+ when /^QUIT$/
194
+ send("+OK dewey POP3 server signing off", true)
195
+ else
196
+ send("-ERR unknown command")
197
+ end
198
+ end
199
+
174
200
  def user(username)
175
201
  @user = @userstore.user_by_username(username)
176
202
  end
@@ -90,8 +90,7 @@ module EventMachine
90
90
  end
91
91
 
92
92
  def post_init
93
- puts ">> 220 hello" if @debug
94
- send_data "220 #{@hostname} ESMTP Service ready\n"
93
+ send "220 #{@hostname} ESMTP Service ready"
95
94
  end
96
95
 
97
96
  def receive_data(data)
@@ -102,7 +101,9 @@ module EventMachine
102
101
  end
103
102
 
104
103
  def check_ptr(helo, ip)
105
- if @@reverse_ptr_check
104
+ if helo =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/ and helo == ip
105
+ @ptr_ok = true
106
+ elsif @@reverse_ptr_check
106
107
  @ptr_ok = false
107
108
  @pending_checks << :ptr
108
109
  d = EM::DNS::Resolver.resolve helo
@@ -175,7 +176,9 @@ module EventMachine
175
176
 
176
177
  pool.perform do |dispatcher|
177
178
  completion = dispatcher.dispatch do |spf_server|
178
-
179
+ if helo =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/ and helo == ip
180
+ helo = nil
181
+ end
179
182
  request = SPF::Request.new(
180
183
  versions: [1, 2], # optional
181
184
  scope: 'mfrom', # or 'helo', 'pra'
@@ -235,18 +238,19 @@ module EventMachine
235
238
  end
236
239
 
237
240
  def process_line(line)
238
- if (@data_mode) && (line.chomp =~ /^\.$/)
241
+ if (@data_mode) && (line.chomp == '.')
239
242
  @data_mode = false
240
243
  check_reject
241
244
  check_classifier
242
245
  @pending_checks -= [:content]
246
+ p @pending_checks
243
247
  if @pending_checks.length == 0
244
248
  send_answer
245
249
  end
246
250
  elsif @data_mode
247
251
  @email_body += line
248
252
  elsif (line =~ /^(HELO|EHLO) (.*)/)
249
- helo = $2.chomp
253
+ helo = $2.chomp.gsub(/^\[/,'').gsub(/\]$/,'')
250
254
  port, ip = Socket.unpack_sockaddr_in(get_peername)
251
255
  check_ptr(helo, ip)
252
256
  check_dnsbl(ip)
@@ -1,5 +1,5 @@
1
1
  module EventMachine
2
2
  module EmailServer
3
- VERSION = "0.0.5"
3
+ VERSION = "0.0.6"
4
4
  end
5
5
  end
@@ -49,14 +49,10 @@ Looks like we had fun!
49
49
  @pool = EM::Pool.new
50
50
  SMTPServer.reset
51
51
  remove_scraps
52
+ $dns_port = 53
52
53
  end
53
54
 
54
55
  def remove_scraps
55
- ["test.sqlite3", "email_server.sqlite3"].each do |f|
56
- if File.exist?("test/#{f}")
57
- File.unlink("test/#{f}")
58
- end
59
- end
60
56
  end
61
57
 
62
58
  def teardown
@@ -313,7 +309,6 @@ Looks like we had fun!
313
309
  userstore = MemoryUserStore.new
314
310
  emailstore = MemoryEmailStore.new
315
311
  setup_user(userstore)
316
- $dns_port = 53
317
312
 
318
313
  SMTPServer.spf_check(true)
319
314
  EM.run {
@@ -360,10 +355,10 @@ Looks like we had fun!
360
355
 
361
356
  def test_example
362
357
  return unless @test_vector.call(__method__)
358
+ #require 'eventmachine'
363
359
  #require 'eventmachine/email_server'
364
360
  #include EventMachine::EmailServer
365
361
  #require 'ratelimit/bucketbased'
366
- #require 'dnsbl/client'
367
362
 
368
363
  userstore = MemoryUserStore.new()
369
364
  emailstore = MemoryEmailStore.new()
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: eventmachine-email_server
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - chrislee35
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-03-10 00:00:00.000000000 Z
11
+ date: 2015-03-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: eventmachine