1use bytes::Bytes;
9
10use crate::error::HeaderError;
11use crate::headers::address::Address;
12use crate::headers::grammar;
13use crate::message::{Headers, TypedHeader};
14use crate::name::HeaderName;
15use crate::uri::Scheme;
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
19#[non_exhaustive]
20pub enum IgnoredIdentityReason {
21 UnexpectedScheme,
23 DuplicateSip,
25 DuplicateSips,
27 DuplicateTel,
29 SipAfterSips,
31 SipsAfterSip,
33}
34
35#[derive(Debug, Clone)]
37pub struct IgnoredIdentity {
38 index: usize,
39 address: Address,
40 reason: IgnoredIdentityReason,
41}
42
43impl IgnoredIdentity {
44 #[must_use]
46 pub fn index(&self) -> usize {
47 self.index
48 }
49
50 #[must_use]
52 pub fn address(&self) -> &Address {
53 &self.address
54 }
55
56 #[must_use]
58 pub fn reason(&self) -> IgnoredIdentityReason {
59 self.reason
60 }
61}
62
63fn validate_common(address: &Address, header: &'static str) -> Result<(), HeaderError> {
64 if !address.params.is_empty() {
68 return Err(HeaderError::Syntax { header });
69 }
70
71 if let Some(display_name) = &address.display_name {
72 let valid_ascii = display_name.iter().all(|byte| {
77 byte.is_ascii_graphic() || matches!(byte, b' ' | b'\t') || !byte.is_ascii()
78 });
79 if !valid_ascii || std::str::from_utf8(display_name).is_err() {
80 return Err(HeaderError::Syntax { header });
81 }
82 }
83
84 Ok(())
85}
86
87fn validate_address(address: &Address, header: &'static str) -> Result<(), HeaderError> {
88 validate_common(address, header)?;
89 if !matches!(
90 address.uri.scheme(),
91 Scheme::Sip | Scheme::Sips | Scheme::Tel
92 ) {
93 return Err(HeaderError::Syntax { header });
94 }
95 Ok(())
96}
97
98fn parse_received_value(value: &[u8], header: &'static str) -> Result<Address, HeaderError> {
99 let address = Address::parse(value, header)?;
100 validate_common(&address, header)?;
101 Ok(address)
102}
103
104fn parse_value(value: &[u8], header: &'static str) -> Result<Address, HeaderError> {
105 let address = parse_received_value(value, header)?;
106 validate_address(&address, header)?;
107 Ok(address)
108}
109
110fn parse_list(value: &[u8], header: &'static str) -> Result<Vec<Address>, HeaderError> {
111 grammar::split_list(value, header)?
112 .into_iter()
113 .map(|part| parse_value(part, header))
114 .collect()
115}
116
117fn validate_list<'a>(
118 values: impl IntoIterator<Item = &'a Address>,
119 header: &'static str,
120) -> Result<(), HeaderError> {
121 let mut values = values.into_iter();
122 let first = values.next().ok_or(HeaderError::Syntax { header })?;
123 let second = values.next();
124 if values.next().is_some() {
125 return Err(HeaderError::Syntax { header });
126 }
127 match second {
128 None => Ok(()),
129 Some(second)
130 if is_sip_family(first) != is_sip_family(second) && is_tel(first) != is_tel(second) =>
131 {
132 Ok(())
133 }
134 Some(_) => Err(HeaderError::Syntax { header }),
135 }
136}
137
138#[must_use]
139fn is_sip_family(address: &Address) -> bool {
140 matches!(address.uri.scheme(), Scheme::Sip | Scheme::Sips)
141}
142
143#[must_use]
144fn is_tel(address: &Address) -> bool {
145 matches!(address.uri.scheme(), Scheme::Tel)
146}
147
148fn serialize(address: &Address) -> Bytes {
149 let mut out = Vec::new();
150 if let Some(display_name) = &address.display_name {
151 out.push(b'"');
152 for &byte in display_name {
153 if matches!(byte, b'"' | b'\\') {
154 out.push(b'\\');
155 }
156 out.push(byte);
157 }
158 out.extend_from_slice(b"\" ");
159 }
160 out.push(b'<');
161 address.uri.write_to(&mut out);
162 out.push(b'>');
163 Bytes::from(out)
164}
165
166#[derive(Default)]
167struct SeenSchemes {
168 sip: bool,
169 sips: bool,
170 tel: bool,
171}
172
173impl SeenSchemes {
174 fn classify(&mut self, address: &Address) -> Option<IgnoredIdentityReason> {
175 match address.uri.scheme() {
176 Scheme::Sip if self.sip => Some(IgnoredIdentityReason::DuplicateSip),
177 Scheme::Sip => {
178 self.sip = true;
179 self.sips.then_some(IgnoredIdentityReason::SipAfterSips)
180 }
181 Scheme::Sips if self.sips => Some(IgnoredIdentityReason::DuplicateSips),
182 Scheme::Sips => {
183 self.sips = true;
184 self.sip.then_some(IgnoredIdentityReason::SipsAfterSip)
185 }
186 Scheme::Tel if self.tel => Some(IgnoredIdentityReason::DuplicateTel),
187 Scheme::Tel => {
188 self.tel = true;
189 None
190 }
191 Scheme::Other(_) => Some(IgnoredIdentityReason::UnexpectedScheme),
192 }
193 }
194}
195
196struct ReceivedIdentityList {
197 values: Vec<Address>,
198 ignored: Vec<IgnoredIdentity>,
199}
200
201fn receive_list(
202 headers: &Headers,
203 name: &HeaderName,
204 label: &'static str,
205) -> Result<Option<ReceivedIdentityList>, HeaderError> {
206 let mut present = false;
207 let mut index = 0usize;
208 let mut seen = SeenSchemes::default();
209 let mut values = Vec::new();
210 let mut ignored = Vec::new();
211
212 for row in headers.get_all(name) {
213 present = true;
214 let value = row.value();
215 for part in grammar::split_list(value.as_ref(), label)? {
216 let address = parse_received_value(part, label)?;
217 if let Some(reason) = seen.classify(&address) {
218 ignored.push(IgnoredIdentity {
219 index,
220 address,
221 reason,
222 });
223 } else {
224 values.push(address);
225 }
226 index += 1;
227 }
228 }
229
230 Ok(present.then_some(ReceivedIdentityList { values, ignored }))
231}
232
233macro_rules! identity_header {
234 (
235 $(#[$meta:meta])*
236 $type:ident, $list:ident => $variant:ident, $label:literal
237 ) => {
238 $(#[$meta])*
239 #[derive(Debug, Clone)]
240 pub struct $type(Address);
241
242 impl $type {
243 pub fn new(address: Address) -> Result<Self, HeaderError> {
248 validate_address(&address, $label)?;
249 Ok(Self(address))
250 }
251
252 #[must_use]
254 pub fn address(&self) -> &Address {
255 &self.0
256 }
257
258 #[must_use]
260 pub fn to_bytes(&self) -> Bytes {
261 serialize(&self.0)
262 }
263 }
264
265 impl std::ops::Deref for $type {
266 type Target = Address;
267
268 fn deref(&self) -> &Address {
269 &self.0
270 }
271 }
272
273 impl TypedHeader for $type {
274 const NAME: HeaderName = HeaderName::$variant;
275 const VALIDATE_LIST: bool = true;
276
277 fn decode(value: &[u8]) -> Result<Self, HeaderError> {
278 parse_value(value, $label).map(Self)
279 }
280
281 fn decode_list(value: &[u8]) -> Result<Vec<Self>, HeaderError> {
282 parse_list(value, $label).map(|values| values.into_iter().map(Self).collect())
283 }
284
285 fn validate_list(values: &[&Self]) -> Result<(), HeaderError> {
286 validate_list(values.iter().map(|value| &value.0), $label)
287 }
288 }
289
290 #[derive(Debug, Clone)]
292 pub struct $list {
293 values: Vec<$type>,
294 ignored: Vec<IgnoredIdentity>,
295 }
296
297 impl $list {
298 pub fn new(
300 values: impl IntoIterator<Item = $type>,
301 ) -> Result<Self, HeaderError> {
302 let values = values.into_iter().collect::<Vec<_>>();
303 validate_list(values.iter().map(|value| &value.0), $label)?;
304 Ok(Self {
305 values,
306 ignored: Vec::new(),
307 })
308 }
309
310 pub fn from_headers(headers: &Headers) -> Result<Option<Self>, HeaderError> {
317 receive_list(headers, &HeaderName::$variant, $label).map(|received| {
318 received.map(|received| Self {
319 values: received.values.into_iter().map($type).collect(),
320 ignored: received.ignored,
321 })
322 })
323 }
324
325 #[must_use]
327 pub fn values(&self) -> &[$type] {
328 &self.values
329 }
330
331 #[must_use]
336 pub fn ignored(&self) -> &[IgnoredIdentity] {
337 &self.ignored
338 }
339
340 #[must_use]
342 pub fn requires_rewrite(&self) -> bool {
343 !self.ignored.is_empty()
344 }
345
346 #[must_use]
348 pub fn into_parts(self) -> (Vec<$type>, Vec<IgnoredIdentity>) {
349 (self.values, self.ignored)
350 }
351
352 #[must_use]
358 pub fn to_bytes(&self) -> Option<Bytes> {
359 if self.values.is_empty() {
360 return None;
361 }
362 let mut out = Vec::new();
363 for (position, value) in self.values.iter().enumerate() {
364 if position != 0 {
365 out.extend_from_slice(b", ");
366 }
367 out.extend_from_slice(&value.to_bytes());
368 }
369 Some(Bytes::from(out))
370 }
371 }
372 };
373}
374
375identity_header!(
376 PAssertedIdentity, PAssertedIdentityList => PAssertedIdentity, "P-Asserted-Identity"
380);
381identity_header!(
382 PPreferredIdentity, PPreferredIdentityList => PPreferredIdentity, "P-Preferred-Identity"
386);