From c04544838dab848be1b1eca6c7527e4a3d6f4e9b Mon Sep 17 00:00:00 2001 From: Karchnu Date: Sun, 1 Nov 2020 16:28:02 +0100 Subject: [PATCH] Initial commit for the generic mailer. --- .gitignore | 4 + shard.yml | 21 +++++ src/mailer.cr | 227 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 252 insertions(+) create mode 100644 .gitignore create mode 100644 shard.yml create mode 100644 src/mailer.cr diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8f0270e --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +shard.lock +bin +drop +lib diff --git a/shard.yml b/shard.yml new file mode 100644 index 0000000..69b7020 --- /dev/null +++ b/shard.yml @@ -0,0 +1,21 @@ +name: mailerd +version: 0.1.0 + +description: | + Simple email sending service. + +dependencies: + kemal: + github: kemalcr/kemal + crinja: + github: straight-shoota/crinja + email: + github: arcage/crystal-email + authd: + git: https://git.baguette.netlib.re/Baguette/authd.git + +targets: + mailerd: + main: src/mailer.cr + +license: ISC diff --git a/src/mailer.cr b/src/mailer.cr new file mode 100644 index 0000000..7407c8d --- /dev/null +++ b/src/mailer.cr @@ -0,0 +1,227 @@ +require "email" +require "option_parser" +require "baguette-crystal-base" + +require "crinja" + +class Context + class_property simulation : Bool = false + class_property command : String = "undefined" + + class_property args = [] of String +end + +class Baguette::Configuration + class Mailer < Base + # Default mailer: 127.0.0.1, not "localhost" for glibc fuckery reasons. + # Without domain name resolution, one can statically compile the mailer + # for machines without glibc (such as on alpine linux). + property smtpd_host : String = "127.0.0.1" + property smtpd_port : UInt16 = 25 + + property verbosity : Int32 = 3 + + # template => subject + property templates : YAML::Any? = nil + property templates_directory : String = "templates/" + + def initialize + end + end +end + + +class OptionParser + def to_s(io : IO) + if banner = @banner + io << banner + io << "\n\n" + end + @flags.join io, "\n" + end +end + +opt_simulation = -> (parser : OptionParser) { + parser.on "-s", "--simulation", "Simulation: do not do anything." do + Context.simulation = true + Baguette::Log.info "Simulation." + end +} + +unrecognized_args_to_context_args = -> (parser : OptionParser, + nexact : Int32?, + at_least : Int32?) { + + # With the right args, these will be interpreted as serialized data. + parser.unknown_args do |args| + + # either we test with the exact expected number of arguments or the least. + if exact = nexact + if args.size != exact + Baguette::Log.error "#{parser}" + exit 1 + end + elsif least = at_least + if args.size < least + Baguette::Log.error "#{parser}" + exit 1 + end + else + Baguette::Log.error "Number of parameters not even provided!" + Baguette::Log.error "#{parser}" + exit 1 + end + + args.each do |arg| + Baguette::Log.debug "Unrecognized argument: #{arg} (adding to Context.args)" + if Context.args.nil? + Context.args = Array(String).new + end + Context.args.not_nil! << arg + end + end +} + +opt_help = -> (parser : OptionParser) { + parser.on "-h", "--help", "Prints command usage." do + puts "usage: #{PROGRAM_NAME} command -h" + puts + puts parser + + case Context.command + when /send/ + #ENUM.names.each do |n| + # Baguette::Log.warning "- #{n}" + #end + end + + exit 0 + end +} + + +parser = OptionParser.new do |parser| + parser.banner = "Welcome on the Altideal CLI administration." + parser.on "-v verbosity", "--verbosity v", "Verbosity. From 0 to 4 (debug)." do |v| + Baguette::Context.verbosity = v.to_i + Baguette::Log.info "verbosity = #{v}" + end + + opt_simulation.call parser + + parser.on("send", "Send an email.") do + parser.banner = "usage: send