summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeal H. Walfield <neal@pep.foundation>2019-07-08 14:47:44 +0200
committerNeal H. Walfield <neal@pep.foundation>2019-07-08 14:49:16 +0200
commit9ff5fbcf805c0d1237cc8f5fd0325f805e145ddd (patch)
tree844f2fd1ef46b179545dc9dd1cd0d748807d6bcc
parentb2f4b977f9278e6f3074ce6e671b71099cc09316 (diff)
rfc2822: Support unquoted @s in the display name
- Some OpenPGP implementations generate user ids that look like: foo@bar.com <foo@bar.com> foo@bar.com is not a valid display-name, because the '@' needs to be quoted. Support this variant anyway.
-rw-r--r--rfc2822/src/grammar.lalrpop16
-rw-r--r--rfc2822/src/lib.rs23
2 files changed, 31 insertions, 8 deletions
diff --git a/rfc2822/src/grammar.lalrpop b/rfc2822/src/grammar.lalrpop
index 4f664c5c..208d3da2 100644
--- a/rfc2822/src/grammar.lalrpop
+++ b/rfc2822/src/grammar.lalrpop
@@ -247,13 +247,19 @@ atext_plus : String = {
// The display-name in a name-addr production often includes a ., but
// is not quoted. The RFC even recommends supporting this variant.
-other_or_dot : String = {
+// Also some OpenPGP implementations create User IDs that look like:
+//
+// foo@bar.com <foo@bar.com>
+//
+// That is, with an unquoted at! Support that too.
+other_or_dot_or_at : String = {
<a:OTHER> => a.to_string(),
<d:DOT> => d.to_string(),
+ <a:AT> => a.to_string(),
}
-atext_dot_plus : String = {
- <a:other_or_dot+> => strings_flatten(a.into_iter(), ""),
+atext_dot_at_plus : String = {
+ <a:other_or_dot_or_at+> => strings_flatten(a.into_iter(), ""),
}
// atom = [CFWS] 1*atext [CFWS]
@@ -267,7 +273,7 @@ pub(crate) Atom : Vec<Component> = {
}
atom : Vec<Component> = {
- <c1:CFWS?> <a:atext_dot_plus> <c2:CFWS?> =>
+ <c1:CFWS?> <a:atext_dot_at_plus> <c2:CFWS?> =>
components_concat!(
c1,
Component::Text(a),
@@ -277,7 +283,7 @@ atom : Vec<Component> = {
// See the phrase production for why this variant of the 'atom'
// production exists, and why the 'CFWS?'es are not included.
atom_prime : Component = {
- <a:atext_dot_plus> => Component::Text(a),
+ <a:atext_dot_at_plus> => Component::Text(a),
}
// dot-atom = [CFWS] dot-atom-text [CFWS]
diff --git a/rfc2822/src/lib.rs b/rfc2822/src/lib.rs
index d956afb7..2edb8090 100644
--- a/rfc2822/src/lib.rs
+++ b/rfc2822/src/lib.rs
@@ -805,7 +805,7 @@ mod tests {
// atom = [CFWS] 1*atext [CFWS]
//
- // Note: our atom parser also allows for dots.
+ // Note: our atom parser also allows for dots and ats.
//
// An atom is a sequence of characters.
//
@@ -825,7 +825,7 @@ mod tests {
"!", "#", "$", "%", "&", "'", "*", "+", "-",
"/", "=", "?", "^", "_", "`", "{", "|", "}", "~",
// Extension:
- "."]
+ ".", "@"]
.into_iter()
{
c(s, Some(vec![Component::Text(s.to_string())]))
@@ -833,7 +833,7 @@ mod tests {
for &s in ["\x02", " ",
"(", ")", "<", ">", "[", "]", ":", ";",
- "@", "\\", ",", "\""]
+ "\\", ",", "\""]
.into_iter()
{
c(s, None)
@@ -1518,6 +1518,22 @@ mod tests {
}
#[test]
+ fn display_name_parser() {
+ c!(grammar::DisplayNameParser::new(), Vec<Component>);
+
+ c("Willi Wonka",
+ Some(vec![ Component::Text("Willi Wonka".into()) ]));
+
+ // As an extention we unquoted dots.
+ c("Willi A. Wonka",
+ Some(vec![ Component::Text("Willi A. Wonka".into()) ]));
+
+ // As an extention we unquoted ats.
+ c("foo@example.org",
+ Some(vec![ Component::Text("foo@example.org".into()) ]));
+ }
+
+ #[test]
fn name_addr_api() {
fn c_(name: Option<&str>, comment: Option<&str>, email: Option<&str>)
{
@@ -1545,6 +1561,7 @@ mod tests {
c("Harold Hutchins", "(artist)", "harold.hutchins@captain-underpants.com");
c("Mr. Meaner", "(Gym Teacher)", "kenny@jerome-horwitz.k12.us");
+ c("foo@bar.com", "display name with at", "foo@bar.com");
}
#[test]