diff --git a/src/configure/auto_mozilla.rs b/src/configure/auto_mozilla.rs index b350b05ed..56943333f 100644 --- a/src/configure/auto_mozilla.rs +++ b/src/configure/auto_mozilla.rs @@ -3,6 +3,7 @@ use quick_xml::events::{BytesEnd, BytesStart, BytesText}; use crate::constants::*; use crate::context::Context; +use crate::error::Error; use crate::login_param::LoginParam; use super::read_autoconf_file; @@ -11,7 +12,7 @@ use super::read_autoconf_file; ******************************************************************************/ /* documentation: https://developer.mozilla.org/en-US/docs/Mozilla/Thunderbird/Autoconfiguration */ struct MozAutoconfigure<'a> { - pub in_0: &'a LoginParam, + pub in_emailaddr: &'a str, pub in_emaildomain: &'a str, pub in_emaillocalpart: &'a str, pub out: LoginParam, @@ -21,6 +22,7 @@ struct MozAutoconfigure<'a> { pub tag_config: MozConfigTag, } +#[derive(PartialEq)] enum MozServer { Undefined, Imap, @@ -35,25 +37,20 @@ enum MozConfigTag { Username, } -pub fn moz_autoconfigure( - context: &Context, - url: &str, - param_in: &LoginParam, -) -> Option { - let xml_raw = read_autoconf_file(context, url)?; - - // Split address into local part and domain part. - let p = param_in.addr.find('@')?; - let (in_emaillocalpart, in_emaildomain) = param_in.addr.split_at(p); - let in_emaildomain = &in_emaildomain[1..]; - - let mut reader = quick_xml::Reader::from_str(&xml_raw); +pub fn moz_parse_xml(in_emailaddr: &str, xml_raw: &str) -> Result { + let mut reader = quick_xml::Reader::from_str(xml_raw); reader.trim_text(true); - let mut buf = Vec::new(); + // Split address into local part and domain part. + let p = match in_emailaddr.find('@') { + Some(i) => i, + None => bail!("Email address {} does not contain @", in_emailaddr), + }; + let (in_emaillocalpart, in_emaildomain) = in_emailaddr.split_at(p); + let in_emaildomain = &in_emaildomain[1..]; let mut moz_ac = MozAutoconfigure { - in_0: param_in, + in_emailaddr, in_emaildomain, in_emaillocalpart, out: LoginParam::new(), @@ -62,6 +59,8 @@ pub fn moz_autoconfigure( tag_server: MozServer::Undefined, tag_config: MozConfigTag::Undefined, }; + + let mut buf = Vec::new(); loop { match reader.read_event(&mut buf) { Ok(quick_xml::events::Event::Start(ref e)) => { @@ -72,8 +71,7 @@ pub fn moz_autoconfigure( moz_autoconfigure_text_cb(e, &mut moz_ac, &reader) } Err(e) => { - warn!( - context, + bail!( "Configure xml: Error at position {}: {:?}", reader.buffer_position(), e @@ -91,11 +89,26 @@ pub fn moz_autoconfigure( || moz_ac.out.send_port == 0 { let r = moz_ac.out.to_string(); - warn!(context, "Bad or incomplete autoconfig: {}", r,); - return None; + bail!("Bad or incomplete autoconfig: {}", r,); } - Some(moz_ac.out) + Ok(moz_ac.out) +} + +pub fn moz_autoconfigure( + context: &Context, + url: &str, + param_in: &LoginParam, +) -> Option { + let xml_raw = read_autoconf_file(context, url)?; + + match moz_parse_xml(¶m_in.addr, &xml_raw) { + Err(err) => { + warn!(context, "{}", err); + None + } + Ok(lp) => Some(lp), + } } fn moz_autoconfigure_text_cb( @@ -105,7 +118,7 @@ fn moz_autoconfigure_text_cb( ) { let val = event.unescape_and_decode(reader).unwrap_or_default(); - let addr = &moz_ac.in_0.addr; + let addr = moz_ac.in_emailaddr; let email_local = moz_ac.in_emaillocalpart; let email_domain = moz_ac.in_emaildomain; @@ -160,13 +173,17 @@ fn moz_autoconfigure_endtag_cb(event: &BytesEnd, moz_ac: &mut MozAutoconfigure) let tag = String::from_utf8_lossy(event.name()).trim().to_lowercase(); if tag == "incomingserver" { + if moz_ac.tag_server == MozServer::Imap { + moz_ac.out_imap_set = true; + } moz_ac.tag_server = MozServer::Undefined; moz_ac.tag_config = MozConfigTag::Undefined; - moz_ac.out_imap_set = true; } else if tag == "outgoingserver" { + if moz_ac.tag_server == MozServer::Smtp { + moz_ac.out_smtp_set = true; + } moz_ac.tag_server = MozServer::Undefined; moz_ac.tag_config = MozConfigTag::Undefined; - moz_ac.out_smtp_set = true; } else { moz_ac.tag_config = MozConfigTag::Undefined; } @@ -217,3 +234,89 @@ fn moz_autoconfigure_starttag_cb( moz_ac.tag_config = MozConfigTag::Username; } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_parse_outlook_autoconfig() { + // Copied from https://autoconfig.thunderbird.net/v1.1/outlook.com on 2019-10-11 + let xml_raw = +" + + hotmail.com + hotmail.co.uk + hotmail.co.jp + hotmail.com.br + hotmail.de + hotmail.fr + hotmail.it + hotmail.es + live.com + live.co.uk + live.co.jp + live.de + live.fr + live.it + live.jp + msn.com + outlook.com + Outlook.com (Microsoft) + Outlook + + outlook.office365.com + 443 + %EMAILADDRESS% + SSL + OAuth2 + https://outlook.office365.com/owa/ + https://outlook.office365.com/ews/exchange.asmx + true + + + outlook.office365.com + 993 + SSL + password-cleartext + %EMAILADDRESS% + + + outlook.office365.com + 995 + SSL + password-cleartext + %EMAILADDRESS% + + true + + + + + smtp.office365.com + 587 + STARTTLS + password-cleartext + %EMAILADDRESS% + + + Set up an email app with Outlook.com + + + + + + %EMAILADDRESS% + + + + + +"; + let res = moz_parse_xml("example@outlook.com", xml_raw).expect("XML parsing failed"); + assert_eq!(res.mail_server, "outlook.office365.com"); + assert_eq!(res.mail_port, 993); + assert_eq!(res.send_server, "smtp.office365.com"); + assert_eq!(res.send_port, 587); + } +}