eventmachine-email_server 0.0.5 → 0.0.6

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