84 lines
2.8 KiB
Ruby
84 lines
2.8 KiB
Ruby
class Distributor
|
|
|
|
class Attributes < Hash
|
|
# Look at the subject if there are attributes parts.
|
|
# If not, look at the body too.
|
|
# TODO: this part can be improved with smarter attr detection
|
|
def self.parse(subject:, body:)
|
|
new = Attributes.new
|
|
subject_parts = subject.to_s.split(",")
|
|
if !subject_parts.empty?
|
|
subject_parts.each do
|
|
new.add_attribute!(_1)
|
|
end
|
|
elsif body.include?("=")
|
|
body.to_s.split("\r\n").each { new.add_attribute!(_1) }
|
|
end
|
|
|
|
new
|
|
end
|
|
|
|
def add_attribute!(key_eq_value)
|
|
k, v = key_eq_value.split("=", 2)
|
|
self[k.strip] = v.strip if k && v
|
|
end
|
|
end
|
|
|
|
def initialize
|
|
@smtp_client = Protocols::Smtp.new
|
|
@imap_client = Protocols::Imap.new
|
|
@imap_client.see_all_messages! if ENV["HARD_RESET_NOT_SEEN_MESSAGE"] == "true"
|
|
@handlers = {
|
|
:default => Actions::Distribute.new(distributor: self),
|
|
"subscribe" => Actions::Subscribe.new(distributor: self),
|
|
"unsubscribe" => Actions::Unsubscribe.new(distributor: self),
|
|
"help" => Actions::Help.new(distributor: self),
|
|
"set-permissions" => Actions::SetPermissions.new(distributor: self),
|
|
"list-users" => Actions::ListUsers.new(distributor: self),
|
|
"validate" => Actions::ValidateDistribute.new(distributor: self),
|
|
"refuse" => Actions::RefuseDistribute.new(distributor: self),
|
|
}
|
|
end
|
|
attr_reader :imap_client, :smtp_client, :handlers # if $debug # TODO: more alias for imap/smtp clients?
|
|
|
|
# Make sure any incoming email is properly directed to the right action.
|
|
def handle_one(mail)
|
|
$logger.info "incoming email from #{mail.from} | #{mail.subject}"
|
|
list = Mailinglist.search_mail(mail)
|
|
if list
|
|
subject, subject_attributes = mail.subject.split(",", 2)
|
|
attributes = Attributes.parse(subject: subject_attributes, body: mail.body)
|
|
handler = @handlers[subject] || @handlers[:default]
|
|
$logger.info "#{handler.class}#handle on <#{list.email}> for <#{mail.from}>"
|
|
handler.handle(list:, mail: mail, attributes:)
|
|
else
|
|
$logger.warn "list #{mail.to} do not exist (asked by #{mail.from})"
|
|
end
|
|
end
|
|
|
|
# alias for {Protocols::Smtp#distribute}
|
|
def distribute(*ary, **opt)
|
|
@smtp_client.distribute(*ary, **opt)
|
|
end
|
|
|
|
# Run the main loop that read all incoming emails.
|
|
def start(cpu_sleep: 1)
|
|
$logger.info "fetching new mail to distribute every #{cpu_sleep} second..."
|
|
loop do
|
|
begin
|
|
mail = @imap_client.fetch_next_unseen(inbox: Protocols::Imap::BASE_INBOX)
|
|
if mail
|
|
handle_one(mail)
|
|
mail.seen!(imap_client: @imap_client, inbox: Protocols::Imap::BASE_INBOX)
|
|
end
|
|
rescue StandardError => e
|
|
$logger.error(e)
|
|
end
|
|
|
|
sleep cpu_sleep
|
|
end
|
|
end
|
|
|
|
require_relative "distributor/action"
|
|
end
|