rust_rcs_core/imdn/
mod.rs

1// Copyright 2023 宋昊文
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use crate::cpim::cpim_message::{CPIMHeaders, CPIMMessage};
16
17use crate::internet::body::message_body::MessageBody;
18use crate::internet::header;
19use crate::internet::header_field::AsHeaderField;
20use crate::internet::headers::content_type::AsContentType;
21
22use crate::util::raw_string::StrEq;
23
24pub struct IMDNInfo<'a> {
25    pub imdn_id: &'a [u8],
26    pub disposition_notification: Option<&'a [u8]>,
27}
28
29pub trait GetIMDNInfo<'a> {
30    fn get_imdn_info_from_inflated_headers(
31        &'a self,
32        headers: Vec<(Vec<u8>, &'a [u8])>,
33    ) -> Result<IMDNInfo, &'static str>;
34    fn get_imdn_info(&self) -> Result<IMDNInfo, &'static str>;
35}
36
37impl<'a> GetIMDNInfo<'a> for CPIMMessage {
38    fn get_imdn_info_from_inflated_headers(
39        &'a self,
40        headers: Vec<(Vec<u8>, &'a [u8])>,
41    ) -> Result<IMDNInfo, &'static str> {
42        let mut imdn_id: Option<&[u8]> = None;
43        let mut disposition_notification: Option<&[u8]> = None;
44
45        for (n, v) in headers {
46            if &n == b"<urn:ietf:params:imdn>.Message-ID" {
47                imdn_id = Some(v);
48            } else if &n == b"<urn:ietf:params:imdn>.Disposition-Notification" {
49                disposition_notification = Some(v);
50            }
51        }
52
53        if let Some(imdn_id) = imdn_id {
54            return Ok(IMDNInfo {
55                imdn_id,
56                disposition_notification,
57            });
58        }
59
60        Err("cannot find Message-ID")
61    }
62
63    fn get_imdn_info(&self) -> Result<IMDNInfo, &'static str> {
64        match &self.headers {
65            CPIMHeaders::Deflated(headers) => {
66                let mut inflated_headers: Vec<(Vec<u8>, &[u8])> = Vec::with_capacity(headers.len());
67
68                let inflator = self.ns.as_inflator();
69                for header in headers {
70                    inflated_headers.push(inflator(&header));
71                }
72
73                self.get_imdn_info_from_inflated_headers(inflated_headers)
74            }
75
76            CPIMHeaders::Inflated(headers) => {
77                let mut inflated_headers: Vec<(Vec<u8>, &[u8])> = Vec::with_capacity(headers.len());
78
79                for header in headers {
80                    inflated_headers.push((header.get_name().to_vec(), header.get_value()));
81                }
82
83                self.get_imdn_info_from_inflated_headers(inflated_headers)
84            }
85        }
86    }
87}
88
89pub fn message_contains_imdn(message: &MessageBody, notification_checked: bool) -> bool {
90    let mut notification_checked = notification_checked;
91
92    if !notification_checked {
93        if let Some(content_disposition_header) =
94            header::search(&message.headers, b"Content-Disposition", false)
95        {
96            if content_disposition_header.get_value() == b"notification" {
97                notification_checked = true;
98            }
99        }
100    }
101
102    if notification_checked {
103        if let Some(content_type_header) = header::search(&message.headers, b"Content-Type", false)
104        {
105            let content_type_header_field = content_type_header.get_value().as_header_field();
106            if let Some(content_type) = content_type_header_field.as_content_type() {
107                if content_type.major_type.equals_bytes(b"message", true)
108                    && content_type.sub_type.equals_bytes(b"imdn+xml", true)
109                {
110                    return true;
111                }
112            }
113        }
114    }
115
116    false
117}