mail_headers/header_components/
mailbox.rs

1use soft_ascii_string::SoftAsciiChar;
2
3use internals::error::EncodingError;
4use internals::encoder::{EncodableInHeader, EncodingWriter};
5use ::{HeaderTryFrom, HeaderTryInto};
6use ::error::ComponentCreationError;
7
8use super::Phrase;
9use super::Email;
10
11pub struct NoDisplayName;
12
13#[derive(Debug, Hash, Eq, PartialEq, Clone)]
14pub struct Mailbox {
15    pub display_name: Option<Phrase>,
16    pub email: Email
17}
18
19impl Mailbox {
20
21    pub fn auto_gen_name<F>(&mut self, default_fn: F) -> Result<(), ComponentCreationError>
22        where F: FnOnce(&Email) -> Result<Option<Phrase>, ComponentCreationError>
23    {
24        if self.display_name.is_none() {
25            let default_name = default_fn(&self.email)?;
26            self.display_name = default_name;
27        }
28        Ok(())
29    }
30
31    pub fn with_default_name<F>(mut self, default_fn: F) -> Result<Mailbox, ComponentCreationError>
32        where F: FnOnce(&Email) -> Result<Option<Phrase>, ComponentCreationError>
33    {
34        self.auto_gen_name(default_fn)?;
35        Ok(self)
36    }
37}
38
39impl From<Email> for Mailbox {
40
41    fn from( email: Email ) -> Self {
42        Mailbox {
43            email,
44            display_name: None,
45        }
46    }
47}
48
49impl From<(Option<Phrase>, Email)> for Mailbox {
50    fn from( pair: (Option<Phrase>, Email) ) -> Self {
51        let (display_name, email) = pair;
52        Mailbox { display_name, email }
53    }
54}
55
56impl<E> HeaderTryFrom<E> for Mailbox
57    where E: HeaderTryInto<Email>
58{
59    fn try_from(email: E) -> Result<Self, ComponentCreationError> {
60        Ok( Mailbox::from( email.try_into()? ) )
61    }
62}
63
64impl<E> HeaderTryFrom<(NoDisplayName, E)> for Mailbox
65    where E: HeaderTryInto<Email>
66{
67    fn try_from( pair: (NoDisplayName, E) ) -> Result<Self, ComponentCreationError> {
68        let email = pair.1.try_into()?;
69        Ok( Mailbox { display_name: None, email } )
70    }
71}
72impl<P, E> HeaderTryFrom<(Option<P>, E)> for Mailbox
73    where P: HeaderTryInto<Phrase>, E: HeaderTryInto<Email>
74{
75    fn try_from(pair: (Option<P>, E)) -> Result<Self, ComponentCreationError> {
76        let display_name = if let Some( dn )= pair.0 {
77            Some( dn.try_into()? )
78        } else { None };
79        let email = pair.1.try_into()?;
80        Ok( Mailbox { display_name, email } )
81    }
82}
83
84impl<P, E> HeaderTryFrom<(P, E)> for Mailbox
85    where P: HeaderTryInto<Phrase>, E: HeaderTryInto<Email>
86{
87    fn try_from( pair: (P, E) ) -> Result<Self, ComponentCreationError> {
88        let display_name = Some( pair.0.try_into()? );
89        let email = pair.1.try_into()?;
90        Ok( Mailbox { display_name, email } )
91    }
92}
93
94
95impl EncodableInHeader for  Mailbox {
96
97    fn encode(&self, handle: &mut EncodingWriter) -> Result<(), EncodingError> {
98        if let Some( display_name ) = self.display_name.as_ref() {
99            display_name.encode( handle )?;
100            handle.write_fws();
101        }
102        //for now this always uses the "<user@do.main>" form even if no display-name is given
103        handle.write_char( SoftAsciiChar::from_unchecked('<') )?;
104        self.email.encode( handle )?;
105        handle.write_char( SoftAsciiChar::from_unchecked('>') )?;
106        Ok( () )
107    }
108
109    fn boxed_clone(&self) -> Box<EncodableInHeader> {
110        Box::new(self.clone())
111    }
112}
113
114
115#[cfg(test)]
116mod test {
117    use ::header_components::{ Email, Phrase };
118    use super::*;
119
120    ec_test!{ email_only, {
121        let email = Email::try_from( "affen@haus" )?;
122        Mailbox::from(email)
123    } => ascii => [
124        Text "<",
125        MarkFWS,
126        Text "affen",
127        MarkFWS,
128        Text "@",
129        MarkFWS,
130        Text "haus",
131        MarkFWS,
132        Text ">"
133    ]}
134
135    ec_test!{ with_display_text, {
136        Mailbox {
137            display_name: Some( Phrase::try_from( "ay ya" ).unwrap() ),
138            email: Email::try_from( "affen@haus" ).unwrap(),
139        }
140    } => ascii => [
141        Text "ay",
142        MarkFWS,
143        Text " ya",
144        MarkFWS,
145        Text " <",
146        MarkFWS,
147        Text "affen",
148        MarkFWS,
149        Text "@",
150        MarkFWS,
151        Text "haus",
152        MarkFWS,
153        Text ">"
154    ]}
155
156
157    mod with_default_name {
158        use super::*;
159
160        #[test]
161        fn does_nothing_if_display_name_is_set() {
162            let mailbox = Mailbox {
163                display_name: Some( Phrase::try_from( "ay ya" ).unwrap() ),
164                email: Email::try_from( "ab@cd" ).unwrap(),
165            };
166            let mailbox2 = mailbox.clone();
167            let mailbox = mailbox.with_default_name(|_| Ok(None)).unwrap();
168            assert_eq!(mailbox, mailbox2);
169        }
170
171        #[test]
172        fn generates_a_display_name_if_needed() {
173            let mailbox = Mailbox {
174                display_name: None,
175                email: Email::try_from( "ab@cd" ).unwrap(),
176            };
177            let mailbox = mailbox.with_default_name(|email| {
178                assert_eq!(email, &Email::try_from( "ab@cd" ).unwrap());
179                Ok(Some(Phrase::try_from( "ay ya" )?))
180            }).unwrap();
181
182            assert_eq!(mailbox, Mailbox {
183                display_name: Some( Phrase::try_from( "ay ya" ).unwrap() ),
184                email: Email::try_from( "ab@cd" ).unwrap(),
185            });
186        }
187
188        #[test]
189        fn can_decide_to_not_generate_a_name() {
190            let mailbox = Mailbox {
191                display_name: None,
192                email: Email::try_from( "ab@cd" ).unwrap(),
193            };
194            let new_mailbox = mailbox.clone().with_default_name(|_| Ok(None)).unwrap();
195            assert_eq!(mailbox, new_mailbox);
196        }
197
198        #[test]
199        fn forward_errors() {
200            let mailbox = Mailbox {
201                display_name: None,
202                email: Email::try_from( "ab@cd" ).unwrap(),
203            };
204            let result = mailbox.clone().with_default_name(|_| {
205                Err(ComponentCreationError::new("DisplayName"))
206            });
207            let err = assert_err!(result);
208            assert_eq!(err.to_string(), "creating component DisplayName failed");
209        }
210    }
211}
212