1
use crate::parser::property::{
2
    prop_attach, prop_attendee, prop_categories, prop_classification, prop_comment, prop_contact,
3
    prop_date_time_created, prop_date_time_stamp, prop_date_time_start, prop_description,
4
    prop_exception_date_times, prop_iana, prop_last_modified, prop_organizer,
5
    prop_recurrence_date_times, prop_recurrence_id, prop_recurrence_rule, prop_related_to,
6
    prop_request_status, prop_sequence, prop_status, prop_summary, prop_unique_identifier,
7
    prop_url, prop_x,
8
};
9
use crate::parser::types::CalendarComponent;
10
use crate::parser::types::ComponentProperty;
11
use crate::parser::Error;
12
use nom::branch::alt;
13
use nom::bytes::streaming::tag;
14
use nom::combinator::cut;
15
use nom::error::ParseError;
16
use nom::multi::many0;
17
use nom::sequence::tuple;
18
use nom::{IResult, Parser};
19

            
20
318
pub fn component_journal<'a, E>(input: &'a [u8]) -> IResult<&'a [u8], CalendarComponent<'a>, E>
21
318
where
22
318
    E: ParseError<&'a [u8]>
23
318
        + nom::error::FromExternalError<&'a [u8], nom::Err<E>>
24
318
        + From<Error<'a>>,
25
318
{
26
318
    let (input, (_, properties, _)) = tuple((
27
318
        tag("BEGIN:VJOURNAL\r\n"),
28
318
        cut(many0(alt((
29
318
            alt((
30
318
                prop_date_time_stamp.map(ComponentProperty::DateTimeStamp),
31
318
                prop_unique_identifier.map(ComponentProperty::UniqueIdentifier),
32
318
                prop_classification.map(ComponentProperty::Classification),
33
318
                prop_date_time_created.map(ComponentProperty::DateTimeCreated),
34
318
                prop_date_time_start.map(ComponentProperty::DateTimeStart),
35
318
                prop_last_modified.map(ComponentProperty::LastModified),
36
318
                prop_organizer.map(ComponentProperty::Organizer),
37
318
                prop_recurrence_id.map(ComponentProperty::RecurrenceId),
38
318
                prop_sequence.map(ComponentProperty::Sequence),
39
318
                prop_status.map(ComponentProperty::Status),
40
318
                prop_summary.map(ComponentProperty::Summary),
41
318
                prop_url.map(ComponentProperty::Url),
42
318
                prop_recurrence_rule.map(ComponentProperty::RecurrenceRule),
43
318
                prop_attach.map(ComponentProperty::Attach),
44
318
                prop_attendee.map(ComponentProperty::Attendee),
45
318
            )),
46
318
            alt((
47
318
                prop_categories.map(ComponentProperty::Categories),
48
318
                prop_comment.map(ComponentProperty::Comment),
49
318
                prop_contact.map(ComponentProperty::Contact),
50
318
                prop_description.map(ComponentProperty::Description),
51
318
                prop_exception_date_times.map(ComponentProperty::ExceptionDateTimes),
52
318
                prop_related_to.map(ComponentProperty::RelatedTo),
53
318
                prop_recurrence_date_times.map(ComponentProperty::RecurrenceDateTimes),
54
318
                prop_request_status.map(ComponentProperty::RequestStatus),
55
318
            )),
56
318
            prop_x.map(ComponentProperty::XProperty),
57
318
            prop_iana.map(ComponentProperty::IanaProperty),
58
318
        )))),
59
318
        tag("END:VJOURNAL\r\n"),
60
318
    ))(input)?;
61

            
62
12
    Ok((input, CalendarComponent::Journal { properties }))
63
318
}
64

            
65
#[cfg(test)]
66
mod tests {
67
    use super::*;
68
    use crate::common::Value;
69
    use crate::parser::types::{
70
        Date, DateOrDateTime, DateTime, DateTimeStampProperty, DateTimeStartProperty,
71
        DescriptionProperty, ParamValue, SummaryProperty, Time, UniqueIdentifierProperty,
72
    };
73
    use crate::parser::Error;
74
    use crate::test_utils::check_rem;
75

            
76
    #[test]
77
2
    fn test_component_journal() {
78
2
        let input = b"BEGIN:VJOURNAL\r\n\
79
2
UID:19970901T130000Z-123405@example.com\r\n\
80
2
DTSTAMP:19970901T130000Z\r\n\
81
2
DTSTART;VALUE=DATE:19970317\r\n\
82
2
SUMMARY:Staff meeting minutes\r\n\
83
2
DESCRIPTION:1. Staff meeting: Participants include Joe\\,\r\n  Lisa\\, and Bob. Aurora project plans were reviewed.\r\n  There is currently no budget reserves for this project.\r\n  Lisa will escalate to management. Next meeting on Tuesday.\\n\r\n 2. Telephone Conference: ABC Corp. sales representative\r\n  called to discuss new printer. Promised to get us a demo by\r\n  Friday.\\n3. Henry Miller (Handsoff Insurance): Car was\r\n  totaled by tree. Is looking into a loaner car. 555-2323\r\n  (tel).\r\nEND:VJOURNAL\r\n";
84
2

            
85
2
        let (rem, component) = component_journal::<Error>(input).unwrap();
86
2
        check_rem(rem, 0);
87
2

            
88
2
        match component {
89
2
            CalendarComponent::Journal { properties } => {
90
2
                assert_eq!(properties.len(), 5);
91

            
92
2
                assert_eq!(
93
2
                    properties[0],
94
2
                    ComponentProperty::UniqueIdentifier(UniqueIdentifierProperty {
95
2
                        other_params: vec![],
96
2
                        value: b"19970901T130000Z-123405@example.com".to_vec(),
97
2
                    })
98
2
                );
99

            
100
2
                assert_eq!(
101
2
                    properties[1],
102
2
                    ComponentProperty::DateTimeStamp(DateTimeStampProperty {
103
2
                        other_params: vec![],
104
2
                        value: DateTime {
105
2
                            date: Date {
106
2
                                year: 1997,
107
2
                                month: 9,
108
2
                                day: 1,
109
2
                            },
110
2
                            time: Time {
111
2
                                hour: 13,
112
2
                                minute: 0,
113
2
                                second: 0,
114
2
                                is_utc: true,
115
2
                            },
116
2
                        }
117
2
                    })
118
2
                );
119

            
120
2
                assert_eq!(
121
2
                    properties[2],
122
2
                    ComponentProperty::DateTimeStart(DateTimeStartProperty {
123
2
                        params: vec![ParamValue::ValueType { value: Value::Date }],
124
2
                        value: DateOrDateTime::Date(Date {
125
2
                            year: 1997,
126
2
                            month: 3,
127
2
                            day: 17,
128
2
                        })
129
2
                    })
130
2
                );
131

            
132
2
                assert_eq!(
133
2
                    properties[3],
134
2
                    ComponentProperty::Summary(SummaryProperty {
135
2
                        params: vec![],
136
2
                        value: b"Staff meeting minutes".to_vec(),
137
2
                    })
138
2
                );
139

            
140
2
                assert_eq!(
141
2
                    properties[4],
142
2
                    ComponentProperty::Description(DescriptionProperty {
143
2
                        params: vec![],
144
2
                        value: br#"1. Staff meeting: Participants include Joe, Lisa, and Bob. Aurora project plans were reviewed. There is currently no budget reserves for this project. Lisa will escalate to management. Next meeting on Tuesday.
145
2
2. Telephone Conference: ABC Corp. sales representative called to discuss new printer. Promised to get us a demo by Friday.
146
2
3. Henry Miller (Handsoff Insurance): Car was totaled by tree. Is looking into a loaner car. 555-2323 (tel)."#.to_vec(),
147
2
                    })
148
2
                );
149
            }
150
            _ => panic!("Wrong component type"),
151
        }
152
2
    }
153
}