Port 1027 used to be an unauthenticated console (see ServerCore's ConsoleServer/ConsoleSession fix) that also exposed the raw SMTP command set (AUTH/DATA/EHLO/EXPN/HELO/...) to anyone who could reach it. It's now started only when barantmail.cfg has a real "admin" section configured (BARANTMailConfig::hasAdmin/getAdminPort/ getAdminUser/getAdminPassword), matching the same optional-listener pattern already used for smtpTLS/imap/pop3, and registers four real commands instead of the SMTP command table: domain add|remove|list mailbox add|remove|list alias add|remove|list password reset MailFileSystem gained the actual domain/mailbox/alias/password CRUD these commands call (createDomain/removeDomain/listDomains, createMailbox/removeMailbox/listMailboxes, createAlias/removeAlias/ listAliases, setPassword), matching its existing on-disk layout: a domain is a directory, a mailbox is a directory with Inbox/Spam/Trash and a .password file, an alias is a plain file listing target mailboxes one per line. getAliasMailboxes() was previously an unconditional stub that always returned empty (confirmed via grep to have zero callers anywhere), so an alias could be "created" but could never actually receive mail. It's now wired for real: SMTPServer::inCreate() checks ifAliasExists()/getAliasMailboxes() during local delivery and copies the same spam-scanned message to every target mailbox (extracted into a new deliverToMailbox() helper so the alias and single-mailbox delivery paths share it).
60 lines
2.5 KiB
C++
60 lines
2.5 KiB
C++
#include "__ADMIN_ALIAS.h"
|
|
|
|
namespace mail {
|
|
|
|
__ADMIN_ALIAS::__ADMIN_ALIAS(MailFileSystem &mailFileSystem) : mailFileSystem(mailFileSystem) {}
|
|
|
|
int __ADMIN_ALIAS::processCommand(coreutils::ZString &request, core::TCPSession &session) {
|
|
if (request.getList().size() < 2) {
|
|
session.out << "Usage: alias add alias@domain target@domain[,target2@domain] | remove alias@domain | list domain" << "\r\n";
|
|
return 1;
|
|
}
|
|
std::string verb = request[1].str();
|
|
std::string error;
|
|
|
|
if (verb == "add") {
|
|
if (request.getList().size() < 4) {
|
|
session.out << "Usage: alias add alias@domain target@domain[,target2@domain]" << "\r\n";
|
|
return 1;
|
|
}
|
|
coreutils::ZString alias(request[2]);
|
|
coreutils::ZString targets(request[3]);
|
|
bool ok = mailFileSystem.createAlias(alias, targets, error);
|
|
session.out << (ok ? "OK." : ("Failed: " + error)) << "\r\n";
|
|
} else if (verb == "remove") {
|
|
if (request.getList().size() < 3) {
|
|
session.out << "Usage: alias remove alias@domain" << "\r\n";
|
|
return 1;
|
|
}
|
|
coreutils::ZString alias(request[2]);
|
|
bool ok = mailFileSystem.removeAlias(alias, error);
|
|
session.out << (ok ? "OK." : ("Failed: " + error)) << "\r\n";
|
|
} else if (verb == "list") {
|
|
if (request.getList().size() < 3) {
|
|
session.out << "Usage: alias list domain" << "\r\n";
|
|
return 1;
|
|
}
|
|
coreutils::ZString domain(request[2]);
|
|
for (auto &alias : mailFileSystem.listAliases(domain)) {
|
|
// listAliases() only returns the local part (the filename
|
|
// on disk) - getAliasMailboxes() needs the full "user@domain"
|
|
// form since it calls getMailBoxPath() itself to find that
|
|
// same file.
|
|
coreutils::MString fullAddress;
|
|
fullAddress << alias << "@" << domain;
|
|
std::string fullAddressStr = fullAddress.str();
|
|
coreutils::ZString aliasAddress(fullAddressStr);
|
|
session.out << alias << "@" << domain << " -> ";
|
|
auto targets = mailFileSystem.getAliasMailboxes(aliasAddress);
|
|
for (size_t i = 0; i < targets.size(); ++i)
|
|
session.out << (i ? ", " : "") << targets[i];
|
|
session.out << "\r\n";
|
|
}
|
|
} else {
|
|
session.out << "Usage: alias add alias@domain target@domain[,target2@domain] | remove alias@domain | list domain" << "\r\n";
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
}
|