diff --git a/Cargo.lock b/Cargo.lock
index 2efe9e8..8b04332 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1799,14 +1799,18 @@ name = "mailpot-cli"
version = "0.1.1"
dependencies = [
"assert_cmd",
+ "base64 0.21.0",
"clap",
"clap_mangen",
"log",
"mailpot",
"mailpot-tests",
"predicates",
+ "serde",
+ "serde_json",
"stderrlog",
"tempfile",
+ "ureq",
]
[[package]]
@@ -3222,6 +3226,18 @@ version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
+[[package]]
+name = "ureq"
+version = "2.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "338b31dd1314f68f3aabf3ed57ab922df95ffcd902476ca7ba3c4ce7b908c46d"
+dependencies = [
+ "base64 0.13.1",
+ "log",
+ "once_cell",
+ "url",
+]
+
[[package]]
name = "url"
version = "2.3.1"
diff --git a/cli/Cargo.toml b/cli/Cargo.toml
index 9caadea..54a3638 100644
--- a/cli/Cargo.toml
+++ b/cli/Cargo.toml
@@ -16,10 +16,14 @@ name = "mpot"
path = "src/main.rs"
[dependencies]
+base64 = { version = "0.21" }
clap = { version = "^4.2", default-features = false, features = ["derive", "cargo", "unicode", "help", "usage", "error-context", "suggestions"] }
log = "0.4"
mailpot = { version = "^0.1", path = "../core" }
+serde = { version = "^1", features = ["derive", ] }
+serde_json = "^1"
stderrlog = "^0.5"
+ureq = { version = "2.6", default-features = false }
[dev-dependencies]
assert_cmd = "2"
diff --git a/cli/build.rs b/cli/build.rs
index 0f3e9a4..568d926 100644
--- a/cli/build.rs
+++ b/cli/build.rs
@@ -27,7 +27,7 @@ use clap::ArgAction;
use clap_mangen::{roff, Man};
use roff::{bold, italic, roman, Inline, Roff};
-include!("src/lib.rs");
+include!("src/args.rs");
fn main() -> std::io::Result<()> {
println!("cargo:rerun-if-changed=./src/lib.rs");
diff --git a/cli/src/args.rs b/cli/src/args.rs
new file mode 100644
index 0000000..d3f79d9
--- /dev/null
+++ b/cli/src/args.rs
@@ -0,0 +1,496 @@
+/*
+ * This file is part of mailpot
+ *
+ * Copyright 2020 - Manos Pitsidianakis
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+pub use std::path::PathBuf;
+
+pub use clap::{Args, CommandFactory, Parser, Subcommand};
+
+#[derive(Debug, Parser)]
+#[command(
+ name = "mpot",
+ about = "mailing list manager",
+ long_about = "Tool for mailpot mailing list management.",
+ before_long_help = "GNU Affero version 3 or later ",
+ author,
+ version
+)]
+pub struct Opt {
+ /// Print logs.
+ #[arg(short, long)]
+ pub debug: bool,
+ /// Configuration file to use.
+ #[arg(short, long, value_parser)]
+ pub config: Option,
+ #[command(subcommand)]
+ pub cmd: Command,
+ /// Silence all output.
+ #[arg(short, long)]
+ pub quiet: bool,
+ /// Verbose mode (-v, -vv, -vvv, etc).
+ #[arg(short, long, action = clap::ArgAction::Count)]
+ pub verbose: u8,
+ /// Debug log timestamp (sec, ms, ns, none).
+ #[arg(short, long)]
+ pub ts: Option,
+}
+
+#[derive(Debug, Subcommand)]
+pub enum Command {
+ /// Prints a sample config file to STDOUT.
+ ///
+ /// You can generate a new configuration file by writing the output to a
+ /// file, e.g: mpot sample-config --with-smtp > config.toml
+ SampleConfig {
+ /// Use an SMTP connection instead of a shell process.
+ #[arg(long)]
+ with_smtp: bool,
+ },
+ /// Dumps database data to STDOUT.
+ DumpDatabase,
+ /// Lists all registered mailing lists.
+ ListLists,
+ /// Mailing list management.
+ List {
+ /// Selects mailing list to operate on.
+ list_id: String,
+ #[command(subcommand)]
+ cmd: ListCommand,
+ },
+ /// Create new list.
+ CreateList {
+ /// List name.
+ #[arg(long)]
+ name: String,
+ /// List ID.
+ #[arg(long)]
+ id: String,
+ /// List e-mail address.
+ #[arg(long)]
+ address: String,
+ /// List description.
+ #[arg(long)]
+ description: Option,
+ /// List archive URL.
+ #[arg(long)]
+ archive_url: Option,
+ },
+ /// Post message from STDIN to list.
+ Post {
+ /// Show e-mail processing result without actually consuming it.
+ #[arg(long)]
+ dry_run: bool,
+ },
+ /// Flush outgoing e-mail queue.
+ FlushQueue {
+ /// Show e-mail processing result without actually consuming it.
+ #[arg(long)]
+ dry_run: bool,
+ },
+ /// Mail that has not been handled properly end up in the error queue.
+ ErrorQueue {
+ #[command(subcommand)]
+ cmd: ErrorQueueCommand,
+ },
+ /// Import a maildir folder into an existing list.
+ ImportMaildir {
+ /// List-ID or primary key value.
+ list_id: String,
+ /// Path to a maildir mailbox.
+ /// Must contain {cur, tmp, new} folders.
+ #[arg(long, value_parser)]
+ maildir_path: PathBuf,
+ },
+ /// Update postfix maps and master.cf (probably needs root permissions).
+ UpdatePostfixConfig {
+ #[arg(short = 'p', long)]
+ /// Override location of master.cf file (default:
+ /// /etc/postfix/master.cf)
+ master_cf: Option,
+ #[clap(flatten)]
+ config: PostfixConfig,
+ },
+ /// Print postfix maps and master.cf entry to STDOUT.
+ ///
+ /// Map output should be added to transport_maps and local_recipient_maps
+ /// parameters in postfix's main.cf. It must be saved in a plain text
+ /// file. To make postfix be able to read them, the postmap application
+ /// must be executed with the path to the map file as its sole argument.
+ ///
+ /// postmap /path/to/mylist_maps
+ ///
+ /// postmap is usually distributed along with the other postfix binaries.
+ ///
+ /// The master.cf entry must be manually appended to the master.cf file. See .
+ PrintPostfixConfig {
+ #[clap(flatten)]
+ config: PostfixConfig,
+ },
+ /// All Accounts.
+ Accounts,
+ /// Account info.
+ AccountInfo {
+ /// Account address.
+ address: String,
+ },
+ /// Add account.
+ AddAccount {
+ /// E-mail address.
+ #[arg(long)]
+ address: String,
+ /// SSH public key for authentication.
+ #[arg(long)]
+ password: String,
+ /// Name.
+ #[arg(long)]
+ name: Option,
+ /// Public key.
+ #[arg(long)]
+ public_key: Option,
+ #[arg(long)]
+ /// Is account enabled.
+ enabled: Option,
+ },
+ /// Remove account.
+ RemoveAccount {
+ #[arg(long)]
+ /// E-mail address.
+ address: String,
+ },
+ /// Update account info.
+ UpdateAccount {
+ /// Address to edit.
+ address: String,
+ /// Public key for authentication.
+ #[arg(long)]
+ password: Option,
+ /// Name.
+ #[arg(long)]
+ name: Option