90 lines
2.3 KiB
Ruby
90 lines
2.3 KiB
Ruby
class ImapServer
|
|
# Handle one client socket
|
|
class ClientHandler
|
|
Dir["lib/imap_server/client_handler/*.rb"].each do |mod|
|
|
mod_name = File.basename(mod, ".rb")
|
|
require_relative "client_handler/#{mod_name}"
|
|
include const_get(mod_name.capitalize)
|
|
end
|
|
|
|
def initialize(server:, socket:)
|
|
@server = server
|
|
@socket = socket
|
|
end
|
|
|
|
# write something to the client
|
|
def write(*messages)
|
|
if messages.size == 1
|
|
raw_message = messages.first.to_s
|
|
$logger.debug "S: #{raw_message.chomp}"
|
|
@socket.write raw_message
|
|
else
|
|
messages.each { write(_1) }
|
|
end
|
|
end
|
|
|
|
# read the socket and return the next client message
|
|
def read
|
|
input = @socket.gets if !@socket.closed?
|
|
input&.chomp!
|
|
$logger.debug "C: #{input}"
|
|
input
|
|
end
|
|
|
|
def greeting
|
|
write ServerMessage.new("OK IMAP4rev1 AUTH=PLAIN server ready")
|
|
end
|
|
|
|
# Start a new imap connection
|
|
def start
|
|
greeting
|
|
|
|
loop do
|
|
client_input = read
|
|
break if client_input.nil?
|
|
|
|
process(client_input)
|
|
end
|
|
end
|
|
|
|
# Handles ONE input from the client.
|
|
# Handlement is done by delegating behavior of the command to external handler
|
|
# loaded as modules.
|
|
#
|
|
# The handlers start as #handle_ followed with the command token downcased.
|
|
# Handlers will receive the parser client message and the current user authenticated.
|
|
# If needed, a reference to the current context is provided along with the client message
|
|
# with msg#handler.
|
|
def process(client_input)
|
|
client_message = ClientMessage.parse(client_input).with(self)
|
|
handler_method = "handle_#{client_message.command}"
|
|
if respond_to?(handler_method)
|
|
send(handler_method, msg: client_message, user: @user)
|
|
else
|
|
write ServerMessage.new("KO Unhandled command \"#{client_message.command}\"", tag: client_message.tag)
|
|
end
|
|
rescue StandardError => e
|
|
$logger.error e
|
|
end
|
|
|
|
# TODO: move this module
|
|
module CommandHelpers
|
|
attr_accessor :selected, :user
|
|
|
|
def authentified?
|
|
@user
|
|
end
|
|
|
|
def authenticate_user!(username:, password:)
|
|
if (@user = User.authenticate(username: username, password: password))
|
|
true
|
|
else
|
|
false
|
|
end
|
|
end
|
|
end
|
|
include CommandHelpers
|
|
|
|
end
|
|
end
|