From 556ea57f37b9fdcfcbe677943cdc20daab5b6cfd Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Sat, 12 Oct 2019 00:50:32 +0300 Subject: [PATCH 1/3] auto_mozilla: split XML parsing into separate function --- src/configure/auto_mozilla.rs | 56 +++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/src/configure/auto_mozilla.rs b/src/configure/auto_mozilla.rs index b350b05ed..15d53dc41 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, @@ -35,25 +36,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 +58,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 +70,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 +88,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 +117,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; From ce67f593f662536c36c4f99dab1eb77292aa3055 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Sat, 12 Oct 2019 01:00:03 +0300 Subject: [PATCH 2/3] Add XML parsing test for Mozilla autoconfig --- src/configure/auto_mozilla.rs | 86 +++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/src/configure/auto_mozilla.rs b/src/configure/auto_mozilla.rs index 15d53dc41..87920c1c2 100644 --- a/src/configure/auto_mozilla.rs +++ b/src/configure/auto_mozilla.rs @@ -229,3 +229,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); + } +} From 5f7279eb85e5b6b2c36c133571505e32f8efdc31 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Sat, 12 Oct 2019 02:09:28 +0300 Subject: [PATCH 3/3] auto_mozilla: server is only configured if the type matches This fixes the testcase introduced in previous commit --- src/configure/auto_mozilla.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/configure/auto_mozilla.rs b/src/configure/auto_mozilla.rs index 87920c1c2..56943333f 100644 --- a/src/configure/auto_mozilla.rs +++ b/src/configure/auto_mozilla.rs @@ -22,6 +22,7 @@ struct MozAutoconfigure<'a> { pub tag_config: MozConfigTag, } +#[derive(PartialEq)] enum MozServer { Undefined, Imap, @@ -172,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; }