/** * 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 { // 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 { 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 { 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 '); 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 '); 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 { const domain = args[0]; if (!domain && subcommand !== 'help') { console.error('Error: Domain name required'); console.log('Usage: mailer dns {setup|validate|show} '); 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 '); 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} '); break; } } /** * Handle send command */ private async handleSendCommand(args: string[]): Promise { 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 --to --subject --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 { 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 '); 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 [options] Commands: service 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 [domain] Domain management add Add a domain remove Remove a domain list List all domains dns DNS management setup Auto-configure DNS via Cloudflare validate Validate DNS configuration show Show required DNS records send [options] Send an email --from Sender email address --to Recipient email address --subject Email subject --text Email body text config Configuration management show Show current configuration set 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 `); } }