388 lines
11 KiB
TypeScript
388 lines
11 KiB
TypeScript
/**
|
|
* Mailer CLI
|
|
* Main command-line interface implementation
|
|
*/
|
|
|
|
import { DaemonManager } from '../daemon/daemon-manager.ts';
|
|
import { ConfigManager } from '../config/config-manager.ts';
|
|
import { DnsManager } from '../dns/dns-manager.ts';
|
|
import { CloudflareClient } from '../dns/cloudflare-client.ts';
|
|
import { Email } from '../mail/core/index.ts';
|
|
import { commitinfo } from '../00_commitinfo_data.ts';
|
|
|
|
export class MailerCli {
|
|
private configManager: ConfigManager;
|
|
private daemonManager: DaemonManager;
|
|
private dnsManager: DnsManager;
|
|
|
|
constructor() {
|
|
this.configManager = new ConfigManager();
|
|
this.daemonManager = new DaemonManager();
|
|
this.dnsManager = new DnsManager();
|
|
}
|
|
|
|
/**
|
|
* Parse and execute CLI commands
|
|
*/
|
|
async parseAndExecute(args: string[]): Promise<void> {
|
|
// Get command
|
|
const command = args[2] || 'help';
|
|
const subcommand = args[3];
|
|
const commandArgs = args.slice(4);
|
|
|
|
try {
|
|
switch (command) {
|
|
case 'service':
|
|
await this.handleServiceCommand(subcommand, commandArgs);
|
|
break;
|
|
|
|
case 'domain':
|
|
await this.handleDomainCommand(subcommand, commandArgs);
|
|
break;
|
|
|
|
case 'dns':
|
|
await this.handleDnsCommand(subcommand, commandArgs);
|
|
break;
|
|
|
|
case 'send':
|
|
await this.handleSendCommand(commandArgs);
|
|
break;
|
|
|
|
case 'config':
|
|
await this.handleConfigCommand(subcommand, commandArgs);
|
|
break;
|
|
|
|
case 'version':
|
|
case '--version':
|
|
case '-v':
|
|
this.showVersion();
|
|
break;
|
|
|
|
case 'help':
|
|
case '--help':
|
|
case '-h':
|
|
default:
|
|
this.showHelp();
|
|
break;
|
|
}
|
|
} catch (error) {
|
|
console.error(`Error: ${error.message}`);
|
|
Deno.exit(1);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handle service commands (daemon control)
|
|
*/
|
|
private async handleServiceCommand(subcommand: string, args: string[]): Promise<void> {
|
|
switch (subcommand) {
|
|
case 'start':
|
|
console.log('Starting mailer daemon...');
|
|
await this.daemonManager.start();
|
|
break;
|
|
|
|
case 'stop':
|
|
console.log('Stopping mailer daemon...');
|
|
await this.daemonManager.stop();
|
|
break;
|
|
|
|
case 'restart':
|
|
console.log('Restarting mailer daemon...');
|
|
await this.daemonManager.stop();
|
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
await this.daemonManager.start();
|
|
break;
|
|
|
|
case 'status':
|
|
console.log('Checking mailer daemon status...');
|
|
// TODO: Implement status check
|
|
break;
|
|
|
|
case 'enable':
|
|
console.log('Enabling mailer service (systemd)...');
|
|
// TODO: Implement systemd enable
|
|
break;
|
|
|
|
case 'disable':
|
|
console.log('Disabling mailer service (systemd)...');
|
|
// TODO: Implement systemd disable
|
|
break;
|
|
|
|
default:
|
|
console.log('Usage: mailer service {start|stop|restart|status|enable|disable}');
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handle domain management commands
|
|
*/
|
|
private async handleDomainCommand(subcommand: string, args: string[]): Promise<void> {
|
|
const config = await this.configManager.load();
|
|
|
|
switch (subcommand) {
|
|
case 'add': {
|
|
const domain = args[0];
|
|
if (!domain) {
|
|
console.error('Error: Domain name required');
|
|
console.log('Usage: mailer domain add <domain>');
|
|
Deno.exit(1);
|
|
}
|
|
|
|
config.domains.push({
|
|
domain,
|
|
dnsMode: 'external-dns',
|
|
});
|
|
|
|
await this.configManager.save(config);
|
|
console.log(`✓ Domain ${domain} added`);
|
|
break;
|
|
}
|
|
|
|
case 'remove': {
|
|
const domain = args[0];
|
|
if (!domain) {
|
|
console.error('Error: Domain name required');
|
|
console.log('Usage: mailer domain remove <domain>');
|
|
Deno.exit(1);
|
|
}
|
|
|
|
config.domains = config.domains.filter(d => d.domain !== domain);
|
|
await this.configManager.save(config);
|
|
console.log(`✓ Domain ${domain} removed`);
|
|
break;
|
|
}
|
|
|
|
case 'list':
|
|
console.log('Configured domains:');
|
|
if (config.domains.length === 0) {
|
|
console.log(' (none)');
|
|
} else {
|
|
for (const domain of config.domains) {
|
|
console.log(` - ${domain.domain} (${domain.dnsMode})`);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
console.log('Usage: mailer domain {add|remove|list} [domain]');
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handle DNS commands
|
|
*/
|
|
private async handleDnsCommand(subcommand: string, args: string[]): Promise<void> {
|
|
const domain = args[0];
|
|
|
|
if (!domain && subcommand !== 'help') {
|
|
console.error('Error: Domain name required');
|
|
console.log('Usage: mailer dns {setup|validate|show} <domain>');
|
|
Deno.exit(1);
|
|
}
|
|
|
|
switch (subcommand) {
|
|
case 'setup': {
|
|
console.log(`Setting up DNS for ${domain}...`);
|
|
|
|
const config = await this.configManager.load();
|
|
const domainConfig = config.domains.find(d => d.domain === domain);
|
|
|
|
if (!domainConfig) {
|
|
console.error(`Error: Domain ${domain} not configured. Add it first with: mailer domain add ${domain}`);
|
|
Deno.exit(1);
|
|
}
|
|
|
|
if (!domainConfig.cloudflare?.apiToken) {
|
|
console.error('Error: Cloudflare API token not configured');
|
|
console.log('Set it with: mailer config set cloudflare.apiToken <token>');
|
|
Deno.exit(1);
|
|
}
|
|
|
|
const cloudflare = new CloudflareClient({ apiToken: domainConfig.cloudflare.apiToken });
|
|
const records = this.dnsManager.getRequiredRecords(domain, config.hostname);
|
|
await cloudflare.createRecords(domain, records);
|
|
|
|
console.log(`✓ DNS records created for ${domain}`);
|
|
break;
|
|
}
|
|
|
|
case 'validate': {
|
|
console.log(`Validating DNS for ${domain}...`);
|
|
const result = await this.dnsManager.validateDomain(domain);
|
|
|
|
if (result.valid) {
|
|
console.log(`✓ DNS configuration is valid`);
|
|
} else {
|
|
console.log(`✗ DNS configuration has errors:`);
|
|
for (const error of result.errors) {
|
|
console.log(` - ${error}`);
|
|
}
|
|
}
|
|
|
|
if (result.warnings.length > 0) {
|
|
console.log('Warnings:');
|
|
for (const warning of result.warnings) {
|
|
console.log(` - ${warning}`);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case 'show': {
|
|
console.log(`Required DNS records for ${domain}:`);
|
|
const config = await this.configManager.load();
|
|
const records = this.dnsManager.getRequiredRecords(domain, config.hostname);
|
|
|
|
for (const record of records) {
|
|
console.log(`\n${record.type} Record:`);
|
|
console.log(` Name: ${record.name}`);
|
|
console.log(` Value: ${record.value}`);
|
|
if (record.priority) console.log(` Priority: ${record.priority}`);
|
|
if (record.ttl) console.log(` TTL: ${record.ttl}`);
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
console.log('Usage: mailer dns {setup|validate|show} <domain>');
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handle send command
|
|
*/
|
|
private async handleSendCommand(args: string[]): Promise<void> {
|
|
console.log('Sending email...');
|
|
|
|
// Parse basic arguments
|
|
const from = args[args.indexOf('--from') + 1];
|
|
const to = args[args.indexOf('--to') + 1];
|
|
const subject = args[args.indexOf('--subject') + 1];
|
|
const text = args[args.indexOf('--text') + 1];
|
|
|
|
if (!from || !to || !subject || !text) {
|
|
console.error('Error: Missing required arguments');
|
|
console.log('Usage: mailer send --from <email> --to <email> --subject <subject> --text <text>');
|
|
Deno.exit(1);
|
|
}
|
|
|
|
const email = new Email({
|
|
from,
|
|
to,
|
|
subject,
|
|
text,
|
|
});
|
|
|
|
console.log(`✓ Email created: ${email.toString()}`);
|
|
// TODO: Actually send the email via SMTP client
|
|
console.log('TODO: Implement actual sending');
|
|
}
|
|
|
|
/**
|
|
* Handle config commands
|
|
*/
|
|
private async handleConfigCommand(subcommand: string, args: string[]): Promise<void> {
|
|
const config = await this.configManager.load();
|
|
|
|
switch (subcommand) {
|
|
case 'show':
|
|
console.log('Current configuration:');
|
|
console.log(JSON.stringify(config, null, 2));
|
|
break;
|
|
|
|
case 'set': {
|
|
const key = args[0];
|
|
const value = args[1];
|
|
|
|
if (!key || !value) {
|
|
console.error('Error: Key and value required');
|
|
console.log('Usage: mailer config set <key> <value>');
|
|
Deno.exit(1);
|
|
}
|
|
|
|
// Simple key-value setting (can be enhanced)
|
|
if (key === 'smtpPort') config.smtpPort = parseInt(value);
|
|
else if (key === 'apiPort') config.apiPort = parseInt(value);
|
|
else if (key === 'hostname') config.hostname = value;
|
|
else {
|
|
console.error(`Error: Unknown config key: ${key}`);
|
|
Deno.exit(1);
|
|
}
|
|
|
|
await this.configManager.save(config);
|
|
console.log(`✓ Configuration updated: ${key} = ${value}`);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
console.log('Usage: mailer config {show|set} [key] [value]');
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Show version information
|
|
*/
|
|
private showVersion(): void {
|
|
console.log(`${commitinfo.name} v${commitinfo.version}`);
|
|
console.log(commitinfo.description);
|
|
}
|
|
|
|
/**
|
|
* Show help information
|
|
*/
|
|
private showHelp(): void {
|
|
console.log(`
|
|
${commitinfo.name} v${commitinfo.version}
|
|
${commitinfo.description}
|
|
|
|
Usage: mailer <command> [options]
|
|
|
|
Commands:
|
|
service <action> Daemon service control
|
|
start Start the mailer daemon
|
|
stop Stop the mailer daemon
|
|
restart Restart the mailer daemon
|
|
status Show daemon status
|
|
enable Enable systemd service
|
|
disable Disable systemd service
|
|
|
|
domain <action> [domain] Domain management
|
|
add <domain> Add a domain
|
|
remove <domain> Remove a domain
|
|
list List all domains
|
|
|
|
dns <action> <domain> DNS management
|
|
setup <domain> Auto-configure DNS via Cloudflare
|
|
validate <domain> Validate DNS configuration
|
|
show <domain> Show required DNS records
|
|
|
|
send [options] Send an email
|
|
--from <email> Sender email address
|
|
--to <email> Recipient email address
|
|
--subject <subject> Email subject
|
|
--text <text> Email body text
|
|
|
|
config <action> Configuration management
|
|
show Show current configuration
|
|
set <key> <value> Set configuration value
|
|
|
|
version, -v, --version Show version information
|
|
help, -h, --help Show this help message
|
|
|
|
Examples:
|
|
mailer service start Start the mailer daemon
|
|
mailer domain add example.com Add example.com domain
|
|
mailer dns setup example.com Setup DNS for example.com
|
|
mailer send --from sender@example.com --to recipient@example.com \\
|
|
--subject "Hello" --text "World"
|
|
|
|
For more information, visit:
|
|
https://code.foss.global/serve.zone/mailer
|
|
`);
|
|
}
|
|
}
|