From 59c22a5626d5bdd7ed7c96291ddfd488bc31b4af Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Sun, 6 Oct 2019 17:06:39 +0300 Subject: [PATCH 1/5] Move Outlook autodiscovery into separate function --- src/configure/auto_outlook.rs | 77 +++++++++++++++++++++-------------- 1 file changed, 46 insertions(+), 31 deletions(-) diff --git a/src/configure/auto_outlook.rs b/src/configure/auto_outlook.rs index ff6a4bc61..ce0d455b2 100644 --- a/src/configure/auto_outlook.rs +++ b/src/configure/auto_outlook.rs @@ -3,6 +3,7 @@ use quick_xml::events::BytesEnd; use crate::constants::*; use crate::context::Context; +use crate::error::Error; use crate::login_param::LoginParam; use super::read_autoconf_file; @@ -19,26 +20,23 @@ struct OutlookAutodiscover { pub config_redirecturl: Option, } -pub fn outlk_autodiscover( - context: &Context, - url: &str, - _param_in: &LoginParam, -) -> Option { - let mut url = url.to_string(); - /* Follow up to 10 xml-redirects (http-redirects are followed in read_autoconf_file() */ - for _i in 0..10 { - let mut outlk_ad = OutlookAutodiscover { - out: LoginParam::new(), - out_imap_set: false, - out_smtp_set: false, - config_type: None, - config_server: String::new(), - config_port: 0, - config_ssl: String::new(), - config_redirecturl: None, - }; +enum ParsingResult { + LoginParam(LoginParam), + RedirectUrl(String), +} + +fn outlk_parse_xml(xml_raw: &str) -> Result { + let mut outlk_ad = OutlookAutodiscover { + out: LoginParam::new(), + out_imap_set: false, + out_smtp_set: false, + config_type: None, + config_server: String::new(), + config_port: 0, + config_ssl: String::new(), + config_redirecturl: None, + }; - if let Some(xml_raw) = read_autoconf_file(context, &url) { let mut reader = quick_xml::Reader::from_str(&xml_raw); reader.trim_text(true); @@ -74,20 +72,15 @@ pub fn outlk_autodiscover( match tag.as_str() { "type" => outlk_ad.config_type = Some(val.trim().to_string()), "server" => outlk_ad.config_server = val.trim().to_string(), - "port" => { - outlk_ad.config_port = val.trim().parse().unwrap_or_default() - } + "port" => outlk_ad.config_port = val.trim().parse().unwrap_or_default(), "ssl" => outlk_ad.config_ssl = val.trim().to_string(), - "redirecturl" => { - outlk_ad.config_redirecturl = Some(val.trim().to_string()) - } + "redirecturl" => outlk_ad.config_redirecturl = Some(val.trim().to_string()), _ => {} }; } } Err(e) => { - error!( - context, + bail!( "Configure xml: Error at position {}: {:?}", reader.buffer_position(), e @@ -109,12 +102,34 @@ pub fn outlk_autodiscover( || outlk_ad.out.send_port == 0 { let r = outlk_ad.out.to_string(); - warn!(context, "Bad or incomplete autoconfig: {}", r,); + bail!("Bad or incomplete autoconfig: {}", r,); + } + Ok(ParsingResult::LoginParam(outlk_ad.out)) + } else { + Ok(ParsingResult::RedirectUrl( + outlk_ad.config_redirecturl.unwrap(), + )) + } +} + +pub fn outlk_autodiscover( + context: &Context, + url: &str, + _param_in: &LoginParam, +) -> Option { + let mut url = url.to_string(); + /* Follow up to 10 xml-redirects (http-redirects are followed in read_autoconf_file() */ + for _i in 0..10 { + if let Some(xml_raw) = read_autoconf_file(context, &url) { + match outlk_parse_xml(&xml_raw) { + Err(err) => { + warn!(context, "{}", err); return None; } - return Some(outlk_ad.out); - } else { - url = outlk_ad.config_redirecturl.unwrap(); + Ok(res) => match res { + ParsingResult::RedirectUrl(redirect_url) => url = redirect_url, + ParsingResult::LoginParam(login_param) => return Some(login_param), + }, } } else { return None; From daac8c482418033aa7c716ca6a4263205099c154 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Sun, 6 Oct 2019 17:09:37 +0300 Subject: [PATCH 2/5] rustfmt --- src/configure/auto_outlook.rs | 146 +++++++++++++++++----------------- 1 file changed, 73 insertions(+), 73 deletions(-) diff --git a/src/configure/auto_outlook.rs b/src/configure/auto_outlook.rs index ce0d455b2..7ef76cde9 100644 --- a/src/configure/auto_outlook.rs +++ b/src/configure/auto_outlook.rs @@ -26,90 +26,90 @@ enum ParsingResult { } fn outlk_parse_xml(xml_raw: &str) -> Result { - let mut outlk_ad = OutlookAutodiscover { - out: LoginParam::new(), - out_imap_set: false, - out_smtp_set: false, - config_type: None, - config_server: String::new(), - config_port: 0, - config_ssl: String::new(), - config_redirecturl: None, - }; + let mut outlk_ad = OutlookAutodiscover { + out: LoginParam::new(), + out_imap_set: false, + out_smtp_set: false, + config_type: None, + config_server: String::new(), + config_port: 0, + config_ssl: String::new(), + config_redirecturl: None, + }; - let mut reader = quick_xml::Reader::from_str(&xml_raw); - reader.trim_text(true); + let mut reader = quick_xml::Reader::from_str(&xml_raw); + reader.trim_text(true); - let mut buf = Vec::new(); + let mut buf = Vec::new(); - let mut current_tag: Option = None; + let mut current_tag: Option = None; - loop { - match reader.read_event(&mut buf) { - Ok(quick_xml::events::Event::Start(ref e)) => { - let tag = String::from_utf8_lossy(e.name()).trim().to_lowercase(); + loop { + match reader.read_event(&mut buf) { + Ok(quick_xml::events::Event::Start(ref e)) => { + let tag = String::from_utf8_lossy(e.name()).trim().to_lowercase(); - if tag == "protocol" { - outlk_ad.config_type = None; - outlk_ad.config_server = String::new(); - outlk_ad.config_port = 0; - outlk_ad.config_ssl = String::new(); - outlk_ad.config_redirecturl = None; + if tag == "protocol" { + outlk_ad.config_type = None; + outlk_ad.config_server = String::new(); + outlk_ad.config_port = 0; + outlk_ad.config_ssl = String::new(); + outlk_ad.config_redirecturl = None; - current_tag = None; - } else { - current_tag = Some(tag); - } - } - Ok(quick_xml::events::Event::End(ref e)) => { - outlk_autodiscover_endtag_cb(e, &mut outlk_ad); - current_tag = None; - } - Ok(quick_xml::events::Event::Text(ref e)) => { - let val = e.unescape_and_decode(&reader).unwrap_or_default(); - - if let Some(ref tag) = current_tag { - match tag.as_str() { - "type" => outlk_ad.config_type = Some(val.trim().to_string()), - "server" => outlk_ad.config_server = val.trim().to_string(), - "port" => outlk_ad.config_port = val.trim().parse().unwrap_or_default(), - "ssl" => outlk_ad.config_ssl = val.trim().to_string(), - "redirecturl" => outlk_ad.config_redirecturl = Some(val.trim().to_string()), - _ => {} - }; - } - } - Err(e) => { - bail!( - "Configure xml: Error at position {}: {:?}", - reader.buffer_position(), - e - ); - } - Ok(quick_xml::events::Event::Eof) => break, - _ => (), + current_tag = None; + } else { + current_tag = Some(tag); } - buf.clear(); } + Ok(quick_xml::events::Event::End(ref e)) => { + outlk_autodiscover_endtag_cb(e, &mut outlk_ad); + current_tag = None; + } + Ok(quick_xml::events::Event::Text(ref e)) => { + let val = e.unescape_and_decode(&reader).unwrap_or_default(); - // XML redirect via redirecturl - if outlk_ad.config_redirecturl.is_none() - || outlk_ad.config_redirecturl.as_ref().unwrap().is_empty() - { - if outlk_ad.out.mail_server.is_empty() - || outlk_ad.out.mail_port == 0 - || outlk_ad.out.send_server.is_empty() - || outlk_ad.out.send_port == 0 - { - let r = outlk_ad.out.to_string(); - bail!("Bad or incomplete autoconfig: {}", r,); + if let Some(ref tag) = current_tag { + match tag.as_str() { + "type" => outlk_ad.config_type = Some(val.trim().to_string()), + "server" => outlk_ad.config_server = val.trim().to_string(), + "port" => outlk_ad.config_port = val.trim().parse().unwrap_or_default(), + "ssl" => outlk_ad.config_ssl = val.trim().to_string(), + "redirecturl" => outlk_ad.config_redirecturl = Some(val.trim().to_string()), + _ => {} + }; } - Ok(ParsingResult::LoginParam(outlk_ad.out)) - } else { - Ok(ParsingResult::RedirectUrl( - outlk_ad.config_redirecturl.unwrap(), - )) } + Err(e) => { + bail!( + "Configure xml: Error at position {}: {:?}", + reader.buffer_position(), + e + ); + } + Ok(quick_xml::events::Event::Eof) => break, + _ => (), + } + buf.clear(); + } + + // XML redirect via redirecturl + if outlk_ad.config_redirecturl.is_none() + || outlk_ad.config_redirecturl.as_ref().unwrap().is_empty() + { + if outlk_ad.out.mail_server.is_empty() + || outlk_ad.out.mail_port == 0 + || outlk_ad.out.send_server.is_empty() + || outlk_ad.out.send_port == 0 + { + let r = outlk_ad.out.to_string(); + bail!("Bad or incomplete autoconfig: {}", r,); + } + Ok(ParsingResult::LoginParam(outlk_ad.out)) + } else { + Ok(ParsingResult::RedirectUrl( + outlk_ad.config_redirecturl.unwrap(), + )) + } } pub fn outlk_autodiscover( From a471ccc95ab3c5aed2f9e6f92ebb584acc1b67ad Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Fri, 11 Oct 2019 02:57:00 +0300 Subject: [PATCH 3/5] Test Outlook autoconfigure redirect parsing --- src/configure/auto_outlook.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/configure/auto_outlook.rs b/src/configure/auto_outlook.rs index 7ef76cde9..9ffb440b9 100644 --- a/src/configure/auto_outlook.rs +++ b/src/configure/auto_outlook.rs @@ -170,3 +170,35 @@ fn outlk_autodiscover_endtag_cb(event: &BytesEnd, outlk_ad: &mut OutlookAutodisc } } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_parse_redirect() { + let res = outlk_parse_xml(" + + + + + email + redirectUrl + https://mail.example.com/autodiscover/autodiscover.xml + + + + ").expect("XML is not parsed successfully"); + match res { + ParsingResult::LoginParam(_lp) => { + panic!("redirecturl is not found"); + } + ParsingResult::RedirectUrl(url) => { + assert_eq!( + url, + "https://mail.example.com/autodiscover/autodiscover.xml" + ); + } + } + } +} From 8e0e1bd58d0bfc03fb31587d48f03ba73c8fac76 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Mon, 14 Oct 2019 01:40:06 +0300 Subject: [PATCH 4/5] Add test for Outlook autodiscovery without redirect --- src/configure/auto_outlook.rs | 43 +++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/configure/auto_outlook.rs b/src/configure/auto_outlook.rs index 9ffb440b9..31044cce2 100644 --- a/src/configure/auto_outlook.rs +++ b/src/configure/auto_outlook.rs @@ -201,4 +201,47 @@ mod tests { } } } + + #[test] + fn test_parse_loginparam() { + let res = outlk_parse_xml( + "\ + + + + + email + settings + + IMAP + example.com + 993 + on + on + + + SMTP + smtp.example.com + 25 + off + on + + + +", + ) + .expect("XML is not parsed successfully"); + + match res { + ParsingResult::LoginParam(lp) => { + assert_eq!(lp.mail_server, "example.com"); + assert_eq!(lp.mail_port, 993); + assert_eq!(lp.send_server, "smtp.example.com"); + assert_eq!(lp.send_port, 25); + } + ParsingResult::RedirectUrl(_) => { + panic!("RedirectUrl is not expected"); + } + } + } } From c4d55f6ba4009673e827ddd32680b2b181d1fd5e Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Mon, 14 Oct 2019 13:43:04 +0300 Subject: [PATCH 5/5] auto_outlook: convert type to lowercase before comparison --- src/configure/auto_outlook.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/configure/auto_outlook.rs b/src/configure/auto_outlook.rs index 31044cce2..36818f3e1 100644 --- a/src/configure/auto_outlook.rs +++ b/src/configure/auto_outlook.rs @@ -70,7 +70,9 @@ fn outlk_parse_xml(xml_raw: &str) -> Result { if let Some(ref tag) = current_tag { match tag.as_str() { - "type" => outlk_ad.config_type = Some(val.trim().to_string()), + "type" => { + outlk_ad.config_type = Some(val.trim().to_lowercase().to_string()) + } "server" => outlk_ad.config_server = val.trim().to_string(), "port" => outlk_ad.config_port = val.trim().parse().unwrap_or_default(), "ssl" => outlk_ad.config_ssl = val.trim().to_string(),