From 9ebe30c40a72707e9282d071a4c08f084775ac70 Mon Sep 17 00:00:00 2001 From: Laurent Dinclaux Date: Tue, 10 Feb 2026 10:56:45 +1100 Subject: [PATCH] Support separate IMAP and SMTP hosts in preconfig The preconfig previously used a single 'host' field for both IMAP and SMTP, making it impossible to configure different servers/schemes/ports (e.g. IMAPS on 993 + SMTP STARTTLS on 587). Also, ssl:// scheme was silently lost during parse_url() since only tls:// was recognized. Add imap_host and smtp_host as separate config keys with full scheme support (ssl://, tls://). The legacy 'host' key is still supported as fallback for backward compatibility. --- config.inc.php.dist | 13 +++++++--- lib/IdentSwitchPreconfig.php | 49 ++++++++++++++++++++++++++++++------ 2 files changed, 51 insertions(+), 11 deletions(-) diff --git a/config.inc.php.dist b/config.inc.php.dist index c4613e9..483d2b6 100644 --- a/config.inc.php.dist +++ b/config.inc.php.dist @@ -20,9 +20,15 @@ $config['ident_switch.preconfig'] = [ // Domain part of email address 'domain.tld' => [ - // Hostname, use ssl:// or tls:// notation if needed, for no security use imap:// (must always start with scheme). + // IMAP connection: scheme://host:port + // Schemes: ssl:// for IMAPS (port 993), tls:// for STARTTLS (port 143). // Required. - 'host' => 'imap://mail.domain.tld', + 'imap_host' => 'ssl://mail.domain.tld:993', + + // SMTP connection: scheme://host:port + // Schemes: tls:// for STARTTLS (port 587), ssl:// for SMTPS (port 465). + // Falls back to imap_host if not specified. + 'smtp_host' => 'tls://mail.domain.tld:587', // Login name, can be 'email' (full address from identity), 'mbox' (only mailbox part). // Any other value is treated as 'not specified' (default). @@ -34,7 +40,8 @@ $config['ident_switch.preconfig'] = [ ], 'another.tld' => [ - 'host' => 'tls://mail.another.tld', + 'imap_host' => 'tls://mail.another.tld:143', + 'smtp_host' => 'tls://mail.another.tld:587', 'user' => 'mbox', ], ]; diff --git a/lib/IdentSwitchPreconfig.php b/lib/IdentSwitchPreconfig.php index 1811da8..215cb12 100644 --- a/lib/IdentSwitchPreconfig.php +++ b/lib/IdentSwitchPreconfig.php @@ -41,7 +41,7 @@ class IdentSwitchPreconfig $cfg = $cfg[$dom] ?? null; if ($cfg) { - if (empty($cfg['host'])) { + if (empty($cfg['imap_host']) && empty($cfg['host'])) { return false; } } @@ -51,8 +51,13 @@ class IdentSwitchPreconfig /** * Apply preconfigured settings to an identity form record. * - * Parses the host URL to extract scheme, host, and port, then sets - * the username based on the config's 'user' setting (email or mbox). + * Parses IMAP and SMTP host URLs separately to extract scheme, host, + * and port, then sets the username based on the config's 'user' setting. + * + * Supports both new format (imap_host + smtp_host) and legacy format + * (single host for both). Schemes ssl:// and tls:// are handled: + * - IMAP: ssl:// is stored in host field, tls:// sets the TLS checkbox. + * - SMTP: scheme is stored directly in host field. * * @param array $record Identity record to modify (passed by reference). * @return bool True if the preconfig is readonly, false otherwise. @@ -68,13 +73,41 @@ class IdentSwitchPreconfig if (is_array($cfg)) { ident_switch::write_log("Applying predefined configuration for '{$email}'."); - if (!empty($cfg['host'])) { - $urlArr = parse_url($cfg['host']); + // IMAP: use imap_host, fallback to host + $imapUrl = $cfg['imap_host'] ?? $cfg['host'] ?? ''; + if (!empty($imapUrl)) { + $urlArr = parse_url($imapUrl); + $host = !empty($urlArr['host']) ? rcube::Q($urlArr['host'], 'url') : ''; + $scheme = strtolower($urlArr['scheme'] ?? ''); - $record['ident_switch.form.imap.host'] = $record['ident_switch.form.smtp.host'] = !empty($urlArr['host']) ? rcube::Q($urlArr['host'], 'url') : ''; - $record['ident_switch.form.imap.port'] = $record['ident_switch.form.smtp.port'] = !empty($urlArr['port']) ? intval($urlArr['port']) : ''; + if ($scheme === 'ssl') { + $record['ident_switch.form.imap.host'] = 'ssl://' . $host; + $record['ident_switch.form.imap.tls'] = false; + } elseif ($scheme === 'tls') { + $record['ident_switch.form.imap.host'] = $host; + $record['ident_switch.form.imap.tls'] = true; + } else { + $record['ident_switch.form.imap.host'] = $host; + $record['ident_switch.form.imap.tls'] = false; + } - $record['ident_switch.form.imap.tls'] = strcasecmp($urlArr['scheme'] ?? '', 'tls') === 0; + $record['ident_switch.form.imap.port'] = !empty($urlArr['port']) ? intval($urlArr['port']) : ''; + } + + // SMTP: use smtp_host, fallback to host + $smtpUrl = $cfg['smtp_host'] ?? $cfg['host'] ?? ''; + if (!empty($smtpUrl)) { + $urlArr = parse_url($smtpUrl); + $host = !empty($urlArr['host']) ? rcube::Q($urlArr['host'], 'url') : ''; + $scheme = strtolower($urlArr['scheme'] ?? ''); + + if ($scheme === 'tls' || $scheme === 'ssl') { + $record['ident_switch.form.smtp.host'] = $scheme . '://' . $host; + } else { + $record['ident_switch.form.smtp.host'] = $host; + } + + $record['ident_switch.form.smtp.port'] = !empty($urlArr['port']) ? intval($urlArr['port']) : ''; } $loginSet = false;