Add an error type to configure::auto_mozilla module

This commit is contained in:
Alexander Krotov
2019-12-01 22:30:21 +01:00
parent 0ac0851ef3
commit cb52a299cc

View File

@@ -1,17 +1,36 @@
//! Thunderbird's Autoconfiguration implementation //! # Thunderbird's Autoconfiguration implementation
//!
//! Documentation: https://developer.mozilla.org/en-US/docs/Mozilla/Thunderbird/Autoconfiguration */
use failure::Fail;
use quick_xml; use quick_xml;
use quick_xml::events::{BytesEnd, BytesStart, BytesText}; use quick_xml::events::{BytesEnd, BytesStart, BytesText};
use crate::constants::*; use crate::constants::*;
use crate::context::Context; use crate::context::Context;
use crate::error::Error;
use crate::login_param::LoginParam; use crate::login_param::LoginParam;
use super::read_autoconf_file; use super::read_autoconf_file;
/* ******************************************************************************
* Thunderbird's Autoconfigure #[derive(Debug, Fail)]
******************************************************************************/ pub enum Error {
/* documentation: https://developer.mozilla.org/en-US/docs/Mozilla/Thunderbird/Autoconfiguration */ #[fail(display = "Invalid email address: {:?}", _0)]
InvalidEmailAddress(String),
#[fail(display = "XML error at position {}", position)]
InvalidXml {
position: usize,
#[cause]
error: quick_xml::Error,
},
#[fail(display = "Bad or incomplete autoconfig")]
IncompleteAutoconfig(LoginParam),
}
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug)]
struct MozAutoconfigure<'a> { struct MozAutoconfigure<'a> {
pub in_emailaddr: &'a str, pub in_emailaddr: &'a str,
pub in_emaildomain: &'a str, pub in_emaildomain: &'a str,
@@ -23,13 +42,14 @@ struct MozAutoconfigure<'a> {
pub tag_config: MozConfigTag, pub tag_config: MozConfigTag,
} }
#[derive(PartialEq)] #[derive(Debug, PartialEq)]
enum MozServer { enum MozServer {
Undefined, Undefined,
Imap, Imap,
Smtp, Smtp,
} }
#[derive(Debug)]
enum MozConfigTag { enum MozConfigTag {
Undefined, Undefined,
Hostname, Hostname,
@@ -38,15 +58,14 @@ enum MozConfigTag {
Username, Username,
} }
pub fn moz_parse_xml(in_emailaddr: &str, xml_raw: &str) -> Result<LoginParam, Error> { pub fn parse_xml(in_emailaddr: &str, xml_raw: &str) -> Result<LoginParam> {
let mut reader = quick_xml::Reader::from_str(xml_raw); let mut reader = quick_xml::Reader::from_str(xml_raw);
reader.trim_text(true); reader.trim_text(true);
// Split address into local part and domain part. // Split address into local part and domain part.
let p = match in_emailaddr.find('@') { let p = in_emailaddr
Some(i) => i, .find('@')
None => bail!("Email address {} does not contain @", in_emailaddr), .ok_or(Error::InvalidEmailAddress(in_emailaddr.to_string()))?;
};
let (in_emaillocalpart, in_emaildomain) = in_emailaddr.split_at(p); let (in_emaillocalpart, in_emaildomain) = in_emailaddr.split_at(p);
let in_emaildomain = &in_emaildomain[1..]; let in_emaildomain = &in_emaildomain[1..];
@@ -63,22 +82,22 @@ pub fn moz_parse_xml(in_emailaddr: &str, xml_raw: &str) -> Result<LoginParam, Er
let mut buf = Vec::new(); let mut buf = Vec::new();
loop { loop {
match reader.read_event(&mut buf) { let event = reader
Ok(quick_xml::events::Event::Start(ref e)) => { .read_event(&mut buf)
.map_err(|error| Error::InvalidXml {
position: reader.buffer_position(),
error,
})?;
match event {
quick_xml::events::Event::Start(ref e) => {
moz_autoconfigure_starttag_cb(e, &mut moz_ac, &reader) moz_autoconfigure_starttag_cb(e, &mut moz_ac, &reader)
} }
Ok(quick_xml::events::Event::End(ref e)) => moz_autoconfigure_endtag_cb(e, &mut moz_ac), quick_xml::events::Event::End(ref e) => moz_autoconfigure_endtag_cb(e, &mut moz_ac),
Ok(quick_xml::events::Event::Text(ref e)) => { quick_xml::events::Event::Text(ref e) => {
moz_autoconfigure_text_cb(e, &mut moz_ac, &reader) moz_autoconfigure_text_cb(e, &mut moz_ac, &reader)
} }
Err(e) => { quick_xml::events::Event::Eof => break,
bail!(
"Configure xml: Error at position {}: {:?}",
reader.buffer_position(),
e
);
}
Ok(quick_xml::events::Event::Eof) => break,
_ => (), _ => (),
} }
buf.clear(); buf.clear();
@@ -89,11 +108,10 @@ pub fn moz_parse_xml(in_emailaddr: &str, xml_raw: &str) -> Result<LoginParam, Er
|| moz_ac.out.send_server.is_empty() || moz_ac.out.send_server.is_empty()
|| moz_ac.out.send_port == 0 || moz_ac.out.send_port == 0
{ {
let r = moz_ac.out.to_string(); Err(Error::IncompleteAutoconfig(moz_ac.out))
bail!("Bad or incomplete autoconfig: {}", r,); } else {
Ok(moz_ac.out)
} }
Ok(moz_ac.out)
} }
pub fn moz_autoconfigure( pub fn moz_autoconfigure(
@@ -103,7 +121,7 @@ pub fn moz_autoconfigure(
) -> Option<LoginParam> { ) -> Option<LoginParam> {
let xml_raw = read_autoconf_file(context, url)?; let xml_raw = read_autoconf_file(context, url)?;
match moz_parse_xml(&param_in.addr, &xml_raw) { match parse_xml(&param_in.addr, &xml_raw) {
Err(err) => { Err(err) => {
warn!(context, "{}", err); warn!(context, "{}", err);
None None
@@ -314,7 +332,7 @@ mod tests {
</loginPageInfo> </loginPageInfo>
</webMail> </webMail>
</clientConfig>"; </clientConfig>";
let res = moz_parse_xml("example@outlook.com", xml_raw).expect("XML parsing failed"); let res = parse_xml("example@outlook.com", xml_raw).expect("XML parsing failed");
assert_eq!(res.mail_server, "outlook.office365.com"); assert_eq!(res.mail_server, "outlook.office365.com");
assert_eq!(res.mail_port, 993); assert_eq!(res.mail_port, 993);
assert_eq!(res.send_server, "smtp.office365.com"); assert_eq!(res.send_server, "smtp.office365.com");