/* * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL * * Modified by Coffey Labs in 2026 for INBUXA. */ use crate::{Server, manager::application::Resource, network::legacy::is_legacy_service}; use registry::schema::enums::ServiceProtocol; use std::fmt::Write; use utils::url_params::UrlParams; impl Server { pub async fn handle_autoconfig_request( &self, uri: Option<&str>, ) -> trc::Result>> { // Obtain parameters let params = UrlParams::new(uri); let emailaddress_param = params .get("emailaddress") .unwrap_or_default() .to_lowercase(); let default_host = &self.core.network.server_name; let (emailaddress, domain) = if let Some((_, domain)) = emailaddress_param.rsplit_once('@') { (emailaddress_param.as_str(), domain) } else { ("%EMAILADDRESS%", default_host.as_str()) }; // inbuxa: legacy-protocols LP-7, LP-14a let legacy_off = self.legacy_protocols_off_for(domain).await?; // Build XML response let mut config = String::with_capacity(1024); config.push_str("\n"); config.push_str("\n"); let _ = writeln!(&mut config, "\t"); let _ = writeln!(&mut config, "\t\t{domain}"); let _ = writeln!(&mut config, "\t\t{emailaddress}"); let _ = writeln!( &mut config, "\t\t{domain}" ); for (protocol, service) in &self.core.network.info.services { if legacy_off && is_legacy_service(protocol) { continue; } let (protocol, tag, ports) = match protocol { ServiceProtocol::Smtp => ("smtp", "outgoingServer", [587, 465]), ServiceProtocol::Imap => ("imap", "incomingServer", [143, 993]), ServiceProtocol::Pop3 => ("pop3", "incomingServer", [110, 995]), _ => continue, }; for (is_tls, port) in ports.into_iter().enumerate() { if is_tls == 1 || service.cleartext { let server_name = service.hostname.as_deref().unwrap_or(default_host); let _ = writeln!(&mut config, "\t\t<{tag} type=\"{protocol}\">"); let _ = writeln!(&mut config, "\t\t\t{server_name}"); let _ = writeln!(&mut config, "\t\t\t{port}"); let _ = writeln!( &mut config, "\t\t\t{}", if is_tls == 1 { "SSL" } else { "STARTTLS" } ); let _ = writeln!(&mut config, "\t\t\t{emailaddress}"); let _ = writeln!( &mut config, "\t\t\tpassword-cleartext" ); let _ = writeln!(&mut config, "\t\t"); } } } config.push_str("\t\n"); for (protocol, service) in &self.core.network.info.services { let (tag, protocol, url) = match protocol { ServiceProtocol::Carddav => ("addressBook", "carddav", "card"), ServiceProtocol::Caldav => ("calendar", "caldav", "cal"), ServiceProtocol::Webdav => ("fileShare", "webdav", "file"), _ => continue, }; let server_name = service.hostname.as_deref().unwrap_or(default_host); let _ = writeln!(&mut config, "\t<{tag} type=\"{protocol}\">"); let _ = writeln!(&mut config, "\t\t{emailaddress}"); let _ = writeln!( &mut config, "\t\thttp-basic" ); let _ = writeln!( &mut config, "\t\thttps://{server_name}/dav/{url}" ); let _ = writeln!(&mut config, "\t"); } let _ = writeln!( &mut config, "\t" ); config.push_str("\n"); Ok(Resource::new( "application/xml; charset=utf-8", config.into_bytes(), )) } }