summaryrefslogtreecommitdiffstats
path: root/headers/src/header_components/mailbox.rs
diff options
context:
space:
mode:
Diffstat (limited to 'headers/src/header_components/mailbox.rs')
-rw-r--r--headers/src/header_components/mailbox.rs212
1 files changed, 212 insertions, 0 deletions
diff --git a/headers/src/header_components/mailbox.rs b/headers/src/header_components/mailbox.rs
new file mode 100644
index 0000000..fa1e34d
--- /dev/null
+++ b/headers/src/header_components/mailbox.rs
@@ -0,0 +1,212 @@
+use soft_ascii_string::SoftAsciiChar;
+
+use internals::error::EncodingError;
+use internals::encoder::{EncodableInHeader, EncodingWriter};
+use ::{HeaderTryFrom, HeaderTryInto};
+use ::error::ComponentCreationError;
+
+use super::Phrase;
+use super::Email;
+
+pub struct NoDisplayName;
+
+#[derive(Debug, Hash, Eq, PartialEq, Clone)]
+pub struct Mailbox {
+ pub display_name: Option<Phrase>,
+ pub email: Email
+}
+
+impl Mailbox {
+
+ pub fn auto_gen_name<F>(&mut self, default_fn: F) -> Result<(), ComponentCreationError>
+ where F: FnOnce(&Email) -> Result<Option<Phrase>, ComponentCreationError>
+ {
+ if self.display_name.is_none() {
+ let default_name = default_fn(&self.email)?;
+ self.display_name = default_name;
+ }
+ Ok(())
+ }
+
+ pub fn with_default_name<F>(mut self, default_fn: F) -> Result<Mailbox, ComponentCreationError>
+ where F: FnOnce(&Email) -> Result<Option<Phrase>, ComponentCreationError>
+ {
+ self.auto_gen_name(default_fn)?;
+ Ok(self)
+ }
+}
+
+impl From<Email> for Mailbox {
+
+ fn from( email: Email ) -> Self {
+ Mailbox {
+ email,
+ display_name: None,
+ }
+ }
+}
+
+impl From<(Option<Phrase>, Email)> for Mailbox {
+ fn from( pair: (Option<Phrase>, Email) ) -> Self {
+ let (display_name, email) = pair;
+ Mailbox { display_name, email }
+ }
+}
+
+impl<E> HeaderTryFrom<E> for Mailbox
+ where E: HeaderTryInto<Email>
+{
+ fn try_from(email: E) -> Result<Self, ComponentCreationError> {
+ Ok( Mailbox::from( email.try_into()? ) )
+ }
+}
+
+impl<E> HeaderTryFrom<(NoDisplayName, E)> for Mailbox
+ where E: HeaderTryInto<Email>
+{
+ fn try_from( pair: (NoDisplayName, E) ) -> Result<Self, ComponentCreationError> {
+ let email = pair.1.try_into()?;
+ Ok( Mailbox { display_name: None, email } )
+ }
+}
+impl<P, E> HeaderTryFrom<(Option<P>, E)> for Mailbox
+ where P: HeaderTryInto<Phrase>, E: HeaderTryInto<Email>
+{
+ fn try_from(pair: (Option<P>, E)) -> Result<Self, ComponentCreationError> {
+ let display_name = if let Some( dn )= pair.0 {
+ Some( dn.try_into()? )
+ } else { None };
+ let email = pair.1.try_into()?;
+ Ok( Mailbox { display_name, email } )
+ }
+}
+
+impl<P, E> HeaderTryFrom<(P, E)> for Mailbox
+ where P: HeaderTryInto<Phrase>, E: HeaderTryInto<Email>
+{
+ fn try_from( pair: (P, E) ) -> Result<Self, ComponentCreationError> {
+ let display_name = Some( pair.0.try_into()? );
+ let email = pair.1.try_into()?;
+ Ok( Mailbox { display_name, email } )
+ }
+}
+
+
+impl EncodableInHeader for Mailbox {
+
+ fn encode(&self, handle: &mut EncodingWriter) -> Result<(), EncodingError> {
+ if let Some( display_name ) = self.display_name.as_ref() {
+ display_name.encode( handle )?;
+ handle.write_fws();
+ }
+ //for now this always uses the "<user@do.main>" form even if no display-name is given
+ handle.write_char( SoftAsciiChar::from_unchecked('<') )?;
+ self.email.encode( handle )?;
+ handle.write_char( SoftAsciiChar::from_unchecked('>') )?;
+ Ok( () )
+ }
+
+ fn boxed_clone(&self) -> Box<EncodableInHeader> {
+ Box::new(self.clone())
+ }
+}
+
+
+#[cfg(test)]
+mod test {
+ use ::header_components::{ Email, Phrase };
+ use super::*;
+
+ ec_test!{ email_only, {
+ let email = Email::try_from( "affen@haus" )?;
+ Mailbox::from(email)
+ } => ascii => [
+ Text "<",
+ MarkFWS,
+ Text "affen",
+ MarkFWS,
+ Text "@",
+ MarkFWS,
+ Text "haus",
+ MarkFWS,
+ Text ">"
+ ]}
+
+ ec_test!{ with_display_text, {
+ Mailbox {
+ display_name: Some( Phrase::try_from( "ay ya" ).unwrap() ),
+ email: Email::try_from( "affen@haus" ).unwrap(),
+ }
+ } => ascii => [
+ Text "ay",
+ MarkFWS,
+ Text " ya",
+ MarkFWS,
+ Text " <",
+ MarkFWS,
+ Text "affen",
+ MarkFWS,
+ Text "@",
+ MarkFWS,
+ Text "haus",
+ MarkFWS,
+ Text ">"
+ ]}
+
+
+ mod with_default_name {
+ use super::*;
+
+ #[test]
+ fn does_nothing_if_display_name_is_set() {
+ let mailbox = Mailbox {
+ display_name: Some( Phrase::try_from( "ay ya" ).unwrap() ),
+ email: Email::try_from( "ab@cd" ).unwrap(),
+ };
+ let mailbox2 = mailbox.clone();
+ let mailbox = mailbox.with_default_name(|_| Ok(None)).unwrap();
+ assert_eq!(mailbox, mailbox2);
+ }
+
+ #[test]
+ fn generates_a_display_name_if_needed() {
+ let mailbox = Mailbox {
+ display_name: None,
+ email: Email::try_from( "ab@cd" ).unwrap(),
+ };
+ let mailbox = mailbox.with_default_name(|email| {
+ assert_eq!(email, &Email::try_from( "ab@cd" ).unwrap());
+ Ok(Some(Phrase::try_from( "ay ya" )?))
+ }).unwrap();
+
+ assert_eq!(mailbox, Mailbox {
+ display_name: Some( Phrase::try_from( "ay ya" ).unwrap() ),
+ email: Email::try_from( "ab@cd" ).unwrap(),
+ });
+ }
+
+ #[test]
+ fn can_decide_to_not_generate_a_name() {
+ let mailbox = Mailbox {
+ display_name: None,
+ email: Email::try_from( "ab@cd" ).unwrap(),
+ };
+ let new_mailbox = mailbox.clone().with_default_name(|_| Ok(None)).unwrap();
+ assert_eq!(mailbox, new_mailbox);
+ }
+
+ #[test]
+ fn forward_errors() {
+ let mailbox = Mailbox {
+ display_name: None,
+ email: Email::try_from( "ab@cd" ).unwrap(),
+ };
+ let result = mailbox.clone().with_default_name(|_| {
+ Err(ComponentCreationError::new("DisplayName"))
+ });
+ let err = assert_err!(result);
+ assert_eq!(err.to_string(), "creating component DisplayName failed");
+ }
+ }
+}
+