received 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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.save(mail.merge({:ts => Time.now.to_i}), :safe => true)
23
+ @coll.insert(mail.merge({:ts => Time.now.to_i}), :safe => {:fsync => true})
23
24
  end
24
25
  end
25
26
  end
@@ -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
- logger.info "stored mail from: #{mail[:from]}"
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
@@ -1,3 +1,3 @@
1
1
  module Received
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
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
- @mock.stub!(:logger).and_return(Logger.new($stderr))
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
- it "does full receive flow" do
15
- @mock.should_receive(:send_data).with("250-localhost\r\n")
16
- @mock.should_receive(:send_data).with("250-8BITMIME\r\n250 PIPELINING\r\n")
17
- @mock.should_receive(:send_data).with("250 OK\r\n").exactly(3).times
18
- @mock.should_receive(:send_data).with("354 End data with <CR><LF>.<CR><LF>\r\n")
19
- @mock.should_receive(:send_data).with("250 OK\r\n").exactly(2).times
20
- @mock.should_receive(:send_data).with("221 Bye\r\n")
21
- body = "Subject: spec\r\nspec\r\n"
22
- @mock.should_receive(:mail_received).with({
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: false
5
- segments:
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-06-02 00:00:00 +03:00
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.3.7
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