Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Usage

-v, --verbose Output more information
-l, --logfile FILE Write log to FILE. Outputs to STDOUT (or /var/log/post_office.log when daemonized) by default.
-m, --mailbox NUM Use separate mailboxes
-s, --smtp PORT Specify SMTP port to use
-p, --pop3 PORT Specify POP3 port to use

Expand Down Expand Up @@ -69,6 +70,13 @@ PostOffice daemon can be started on Mac OS X system startup.

The Startup Item is stored in */Library/StartupItems/PostOffice*

Distinct Mailboxes
------------------

By default, sent emails are broadcast to all clients connected to the POP3 server. To simulate delivery to specific email addresses, use the `--mailbox NUM` setting. `NUM` specifies the number of POP3 ports to be opened. The first port number is specified with `--pop3 PORT`, and increments from there.

When connecting to the POP3 server with the mailbox setting enabled, set the `username` field to the desired email address.

Planned features
----------------

Expand Down
33 changes: 21 additions & 12 deletions bin/post_office
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ require 'thread'
require 'smtp_server.rb'
require 'pop_server.rb'
require 'config_file.rb'
require 'store.rb'

options = ConfigFile.detect.read

Expand All @@ -17,22 +18,27 @@ optparse = OptionParser.new do |opts|
opts.banner = "Usage: #{__FILE__} [options]"

options[:verbose] ||= false
opts.on( '-v', '--verbose', 'Output more information' ) do
opts.on('-v', '--verbose', 'Output more information') do
options[:verbose] = true
end

options[:logfile] ||= nil
opts.on( '-l', '--logfile FILE', 'Write log to FILE. Outputs to STDOUT (or /var/log/post_office.log when daemonized) by default.' ) do |file|
opts.on('-l', '--logfile FILE', 'Write log to FILE. Outputs to STDOUT (or /var/log/post_office.log when daemonized) by default.') do |file|
options[:logfile] = file
end

options[:mailbox] ||= 1
opts.on('-m', '--mailbox NUM', 'Use separate mailboxes') do |mailbox|
options[:mailbox] = mailbox
end

options[:smtp_port] ||= 25
opts.on( '-s', '--smtp PORT', 'Specify SMTP port to use' ) do |port|
opts.on('-s', '--smtp PORT', 'Specify SMTP port to use') do |port|
options[:smtp_port] = port
end

options[:pop3_port] ||= 110
opts.on( '-p', '--pop3 PORT', 'Specify POP3 port to use' ) do |port|
opts.on('-p', '--pop3 PORT', 'Specify POP3 port to use') do |port|
options[:pop3_port] = port
end

Expand All @@ -45,7 +51,7 @@ optparse = OptionParser.new do |opts|
options[:startup_item] = :remove
end

opts.on( '-h', '--help', 'Display this screen' ) do
opts.on('-h', '--help', 'Display this screen') do
puts opts
exit
end
Expand All @@ -59,8 +65,8 @@ optparse.parse!
if options[:startup_item]
require 'startup_item.rb'
case options[:startup_item]
when :install then StartupItem.install
when :remove then StartupItem.remove
when :install then StartupItem.install
when :remove then StartupItem.remove
end
exit
end
Expand All @@ -70,17 +76,20 @@ end
#
$log = Logger.new(options[:logfile] || STDOUT)
$log.level = options[:verbose] ? Logger::DEBUG : Logger::INFO
$log.datetime_format = "%H:%M:%S"
$log.datetime_format = '%H:%M:%S'

begin
smtp_server = Thread.new{ SMTPServer.new(options[:smtp_port]) }
pop_server = Thread.new{ POPServer.new(options[:pop3_port]) }
Store.instance.mailbox = options[:mailbox]
smtp_server = Thread.new { SMTPServer.new(options[:smtp_port]) }

options[:mailbox].to_i.times do |i|
pop3_port = options[:pop3_port].to_i + i
pop_server = Thread.new { POPServer.new(pop3_port) }
end
smtp_server.join
pop_server.join
rescue Interrupt
$log.info "Interrupt..."
$log.info 'Interrupt...'
rescue Errno::EACCES
$log.error "I need root access to open ports #{options[:smtp_port]} and / or #{options[:pop3_port]}. Please sudo #{__FILE__}"
end

22 changes: 11 additions & 11 deletions lib/generic_server.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,10 @@
# time, so use client.object_id when storing local data

class GenericServer

def initialize(options)
@port = options[:port]
server = TCPServer.open(@port)
$log.info "#{self.class.to_s} listening on port #{@port}"
$log.info "#{self.class} listening on port #{@port}"

# Try to increase the buffer to give us some more time to parse incoming data
begin
Expand All @@ -39,37 +38,38 @@ def initialize(options)
Thread.start(server.accept) do |client|
begin
client_addr = client.addr
$log.info "#{self.class.to_s} accepted connection #{client.object_id} from #{client_addr.inspect}"
$log.info "#{self.class} accepted connection #{client.object_id} from #{client_addr.inspect}"
greet client

# Keep processing commands until somebody closed the connection
begin
input = client.gets

# The first word of a line should contain the command
command = input.to_s.gsub(/ .*/,"").upcase.gsub(/[\r\n]/,"")
command = input.to_s.gsub(/ .*/, '').upcase.gsub(/[\r\n]/, '')

$log.debug "#{client.object_id}:#{@port} < #{input}"

process(client, command, input)

end until client.closed?
$log.info "#{self.class.to_s} closed connection #{client.object_id} with #{client_addr.inspect}"
$log.info "#{self.class} closed connection #{client.object_id} with #{client_addr.inspect}"
rescue => detail
$log.error "#{client.object_id}:#{@port} ! #{$!}"
$log.error "#{client.object_id}:#{@port} ! #{$ERROR_INFO}"
$log.error detail
client.close
end
end
end
end

# Respond to client by sending back text
def respond(client, text)
$log.debug "#{client.object_id}:#{@port} > #{text}"
client.write text
rescue
$log.error "#{client.object_id}:#{@port} ! #{$!}"
rescue => detail
$log.error "#{client.object_id}:#{@port} ! #{$ERROR_INFO}"
$log.error detail
client.close
end

end
end
Loading