received 0.2.0 → 0.3.0
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.
- data/bin/received +1 -0
- data/lib/received/backend/mongodb.rb +2 -1
- data/lib/received/connection.rb +10 -3
- data/lib/received/lmtp.rb +9 -2
- data/lib/received/version.rb +1 -1
- data/spec/lmtp_spec.rb +42 -20
- metadata +4 -26
data/bin/received
CHANGED
@@ -46,6 +46,7 @@ if options.delete(:daemon)
|
|
46
46
|
# Drop privileges if started as superuser
|
47
47
|
params.merge!({:user => options[:user] || 'nobody', :group => options[:group] || 'nobody'}) if Process.uid == 0
|
48
48
|
Daemons.daemonize(params)
|
49
|
+
File.umask(0007)
|
49
50
|
end
|
50
51
|
|
51
52
|
server = Received::Server.new(options)
|
@@ -18,8 +18,9 @@ module Received
|
|
18
18
|
# Store mail in MongoDB
|
19
19
|
#
|
20
20
|
# @param [Hash] mail
|
21
|
+
# @return [ObjectId] object_id
|
21
22
|
def store(mail)
|
22
|
-
@coll.
|
23
|
+
@coll.insert(mail.merge({:ts => Time.now.to_i}), :safe => {:fsync => true})
|
23
24
|
end
|
24
25
|
end
|
25
26
|
end
|
data/lib/received/connection.rb
CHANGED
@@ -34,12 +34,19 @@ module Received
|
|
34
34
|
#
|
35
35
|
# @param [Hash] mail
|
36
36
|
# @see Received::Backend::Base#store
|
37
|
+
# @return [Boolean] saving succeeded
|
37
38
|
def mail_received(mail)
|
38
39
|
begin
|
39
|
-
@backend.store(mail)
|
40
|
-
|
40
|
+
if insert_id = @backend.store(mail)
|
41
|
+
logger.info "stored mail from: #{mail[:from]} (#{insert_id})"
|
42
|
+
return true
|
43
|
+
else
|
44
|
+
logger.error "saving of mail from #{mail[:from]} failed"
|
45
|
+
end
|
46
|
+
false
|
41
47
|
rescue Exception => e
|
42
|
-
logger.error "saving failed with: #{e.message}"
|
48
|
+
logger.error "saving of mail from #{mail[:from]} failed with: #{e.message}"
|
49
|
+
false
|
43
50
|
end
|
44
51
|
end
|
45
52
|
|
data/lib/received/lmtp.rb
CHANGED
@@ -71,9 +71,12 @@ module Received
|
|
71
71
|
end
|
72
72
|
when :data
|
73
73
|
if ev == ".\r\n"
|
74
|
-
@rcpt.size.times {ok}
|
75
74
|
mail = {:from => @from, :rcpt => @rcpt, :body => @body.join}
|
76
|
-
@conn.mail_received(mail)
|
75
|
+
if @conn.mail_received(mail)
|
76
|
+
@rcpt.size.times {ok}
|
77
|
+
else
|
78
|
+
@rcpt.size.times {error_in_processing}
|
79
|
+
end
|
77
80
|
:data_received
|
78
81
|
else
|
79
82
|
@body << ev
|
@@ -123,6 +126,10 @@ module Received
|
|
123
126
|
emit "500 command unrecognized"
|
124
127
|
end
|
125
128
|
|
129
|
+
def error_in_processing
|
130
|
+
emit "451 Requested action aborted: local error in processing"
|
131
|
+
end
|
132
|
+
|
126
133
|
def emit(str)
|
127
134
|
@conn.send_data "#{str}\r\n"
|
128
135
|
# return nil, so there won't be implicit state transition
|
data/lib/received/version.rb
CHANGED
data/spec/lmtp_spec.rb
CHANGED
@@ -5,33 +5,55 @@ describe Received::LMTP do
|
|
5
5
|
before :each do
|
6
6
|
@mock = mock 'conn'
|
7
7
|
@mock.should_receive(:send_data).with("220 localhost LMTP server ready\r\n")
|
8
|
-
|
8
|
+
logger = Logger.new($stderr)
|
9
|
+
@mock.stub!(:logger).and_return(logger)
|
9
10
|
@mock.logger.debug "*** Starting test ***"
|
10
11
|
@proto = Received::LMTP.new(@mock)
|
11
12
|
@proto.start!
|
12
13
|
end
|
13
14
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
:from => 'spec1@example.com',
|
24
|
-
:rcpt => ['spec2@example.com', 'spec3@example.com'],
|
25
|
-
:body => body
|
26
|
-
})
|
27
|
-
@mock.should_receive(:close_connection_after_writing)
|
28
|
-
|
29
|
-
["LHLO", "MAIL FROM:<spec1@example.com>", "RCPT TO:<spec2@example.com>",
|
30
|
-
"RCPT TO:<spec3@example.com>", "DATA", "#{body}.", "QUIT"].each do |line|
|
31
|
-
@mock.logger.debug "client: #{line}"
|
32
|
-
@proto.on_data(line + "\r\n")
|
15
|
+
describe "Full flow" do
|
16
|
+
let(:body) { "Subject: spec\r\nspec\r\n" }
|
17
|
+
|
18
|
+
def begin_flow!
|
19
|
+
["LHLO", "MAIL FROM:<spec1@example.com>", "RCPT TO:<spec2@example.com>",
|
20
|
+
"RCPT TO:<spec3@example.com>", "DATA", "#{body}.", "QUIT"].each do |line|
|
21
|
+
@mock.logger.debug "client: #{line}"
|
22
|
+
@proto.on_data(line + "\r\n")
|
23
|
+
end
|
33
24
|
end
|
34
25
|
|
26
|
+
def common_expectations!
|
27
|
+
@mock.should_receive(:send_data).with("250-localhost\r\n")
|
28
|
+
@mock.should_receive(:send_data).with("250-8BITMIME\r\n250 PIPELINING\r\n")
|
29
|
+
@mock.should_receive(:send_data).with("250 OK\r\n").exactly(3).times
|
30
|
+
@mock.should_receive(:send_data).with("354 End data with <CR><LF>.<CR><LF>\r\n")
|
31
|
+
end
|
32
|
+
|
33
|
+
it "receives mail" do
|
34
|
+
common_expectations!
|
35
|
+
@mock.should_receive(:send_data).with("250 OK\r\n").exactly(2).times
|
36
|
+
@mock.should_receive(:send_data).with("221 Bye\r\n")
|
37
|
+
@mock.should_receive(:mail_received).with({
|
38
|
+
:from => 'spec1@example.com',
|
39
|
+
:rcpt => ['spec2@example.com', 'spec3@example.com'],
|
40
|
+
:body => body
|
41
|
+
}).and_return(true)
|
42
|
+
@mock.should_receive(:close_connection_after_writing)
|
43
|
+
|
44
|
+
begin_flow!
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
it "returns error when it cannot save email" do
|
49
|
+
common_expectations!
|
50
|
+
@mock.should_receive(:mail_received).once.and_return(false)
|
51
|
+
@mock.should_receive(:send_data).with(/451/).exactly(2).times
|
52
|
+
@mock.should_receive(:send_data).with("221 Bye\r\n")
|
53
|
+
@mock.should_receive(:close_connection_after_writing)
|
54
|
+
|
55
|
+
begin_flow!
|
56
|
+
end
|
35
57
|
end
|
36
58
|
|
37
59
|
it "parses multiline" do
|
metadata
CHANGED
@@ -1,12 +1,8 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: received
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
prerelease:
|
5
|
-
|
6
|
-
- 0
|
7
|
-
- 2
|
8
|
-
- 0
|
9
|
-
version: 0.2.0
|
4
|
+
prerelease:
|
5
|
+
version: 0.3.0
|
10
6
|
platform: ruby
|
11
7
|
authors:
|
12
8
|
- Roman Shterenzon
|
@@ -14,8 +10,7 @@ autorequire:
|
|
14
10
|
bindir: bin
|
15
11
|
cert_chain: []
|
16
12
|
|
17
|
-
date: 2011-
|
18
|
-
default_executable:
|
13
|
+
date: 2011-09-13 00:00:00 Z
|
19
14
|
dependencies:
|
20
15
|
- !ruby/object:Gem::Dependency
|
21
16
|
name: daemons
|
@@ -25,8 +20,6 @@ dependencies:
|
|
25
20
|
requirements:
|
26
21
|
- - ">="
|
27
22
|
- !ruby/object:Gem::Version
|
28
|
-
segments:
|
29
|
-
- 0
|
30
23
|
version: "0"
|
31
24
|
type: :runtime
|
32
25
|
version_requirements: *id001
|
@@ -38,8 +31,6 @@ dependencies:
|
|
38
31
|
requirements:
|
39
32
|
- - ">="
|
40
33
|
- !ruby/object:Gem::Version
|
41
|
-
segments:
|
42
|
-
- 0
|
43
34
|
version: "0"
|
44
35
|
type: :runtime
|
45
36
|
version_requirements: *id002
|
@@ -51,10 +42,6 @@ dependencies:
|
|
51
42
|
requirements:
|
52
43
|
- - ~>
|
53
44
|
- !ruby/object:Gem::Version
|
54
|
-
segments:
|
55
|
-
- 1
|
56
|
-
- 3
|
57
|
-
- 0
|
58
45
|
version: 1.3.0
|
59
46
|
type: :runtime
|
60
47
|
version_requirements: *id003
|
@@ -66,10 +53,6 @@ dependencies:
|
|
66
53
|
requirements:
|
67
54
|
- - ~>
|
68
55
|
- !ruby/object:Gem::Version
|
69
|
-
segments:
|
70
|
-
- 1
|
71
|
-
- 3
|
72
|
-
- 0
|
73
56
|
version: 1.3.0
|
74
57
|
type: :runtime
|
75
58
|
version_requirements: *id004
|
@@ -100,7 +83,6 @@ files:
|
|
100
83
|
- received.gemspec
|
101
84
|
- spec/lmtp_spec.rb
|
102
85
|
- spec/spec_helper.rb
|
103
|
-
has_rdoc: true
|
104
86
|
homepage: ""
|
105
87
|
licenses: []
|
106
88
|
|
@@ -114,21 +96,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
114
96
|
requirements:
|
115
97
|
- - ">="
|
116
98
|
- !ruby/object:Gem::Version
|
117
|
-
segments:
|
118
|
-
- 0
|
119
99
|
version: "0"
|
120
100
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
121
101
|
none: false
|
122
102
|
requirements:
|
123
103
|
- - ">="
|
124
104
|
- !ruby/object:Gem::Version
|
125
|
-
segments:
|
126
|
-
- 0
|
127
105
|
version: "0"
|
128
106
|
requirements: []
|
129
107
|
|
130
108
|
rubyforge_project:
|
131
|
-
rubygems_version: 1.
|
109
|
+
rubygems_version: 1.8.10
|
132
110
|
signing_key:
|
133
111
|
specification_version: 3
|
134
112
|
summary: Receive mail from Postfix and store it somewhere
|