Skip to main content

sccp_protocol/message/codec/
conference.rs

1//! Family-specific codec helpers delegated to by the exhaustive central dispatch.
2
3use super::*;
4
5pub(super) const MAX_CONFERENCE_PASSTHROUGH_DATA: usize = 2000;
6pub(super) const MAX_AUDIT_CONFERENCE_ENTRIES: usize = 32;
7pub(super) const MAX_AUDIT_PARTICIPANT_DATA: usize = 256;
8
9pub(super) fn encode_participant_request(
10    message_id: u32,
11    conference_id: crate::types::ConferenceId,
12    participant: &ConferenceParticipant,
13) -> Result<WireParticipantRequest, CodecError> {
14    Ok(WireParticipantRequest {
15        conference_id: conference_id.get(),
16        call_reference: participant.call_reference.get(),
17        presentation_restrictions: participant.presentation_restrictions.bits(),
18        participant_name: WireFixedText::new(message_id, "participant name", &participant.name)?,
19        participant_number: WireFixedText::new(
20            message_id,
21            "participant number",
22            &participant.number,
23        )?,
24        conference_name: WireFixedText::new(
25            message_id,
26            "conference name",
27            &participant.conference_name,
28        )?,
29    })
30}
31
32pub(super) fn decode_participant_request(
33    payload: &[u8],
34    message_id: u32,
35) -> Result<(crate::types::ConferenceId, ConferenceParticipant), CodecError> {
36    validate_exact_payload(payload, message_id, 108)?;
37    let value: WireParticipantRequest = decode(message_id, payload)?;
38    Ok((
39        value.conference_id.into(),
40        ConferenceParticipant {
41            call_reference: value.call_reference.into(),
42            presentation_restrictions: PartyInformationRestrictions::from_bits_retain(
43                value.presentation_restrictions,
44            ),
45            name: value.participant_name.text()?,
46            number: value.participant_number.text()?,
47            conference_name: value.conference_name.text()?,
48        },
49    ))
50}
51
52impl ConferenceParticipantChange {
53    /// Place the typed participant change inside the standard V1 application
54    /// envelope. The caller supplies application-specific routing metadata.
55    pub fn to_user_data_v1(
56        &self,
57        routing: ParticipantChangeRouting,
58    ) -> Result<UserDataV1Message, CodecError> {
59        let data = encode(
60            wire_id::USER_TO_DEVICE_DATA_V1,
61            &encode_participant_request(
62                wire_id::USER_TO_DEVICE_DATA_V1,
63                self.conference_id,
64                &self.participant,
65            )?,
66        )?;
67        Ok(UserDataV1Message {
68            application_id: routing.application_id.get(),
69            line_instance: routing.line_instance,
70            call_reference: self.participant.call_reference.get(),
71            transaction_id: routing.transaction_id.get(),
72            sequence_flag: routing.sequence_flag,
73            display_priority: routing.display_priority,
74            conference_id: self.conference_id.get(),
75            application_instance_id: routing.application_instance_id.get(),
76            routing: routing.routing,
77            data,
78        })
79    }
80
81    /// Decode a participant change from a V1 application envelope and reject
82    /// mismatched envelope/payload call or conference identities.
83    pub fn from_user_data_v1(message: &UserDataV1Message) -> Result<Self, CodecError> {
84        let (conference_id, participant) =
85            decode_participant_request(&message.data, wire_id::USER_TO_DEVICE_DATA_V1)?;
86        if message.conference_id != conference_id.get() {
87            return Err(CodecError::InvalidValue {
88                message_id: wire_id::USER_TO_DEVICE_DATA_V1,
89                field: "participant change conference ID",
90                value: u64::from(message.conference_id),
91            });
92        }
93        if message.call_reference != participant.call_reference.get() {
94            return Err(CodecError::InvalidValue {
95                message_id: wire_id::USER_TO_DEVICE_DATA_V1,
96                field: "participant change call reference",
97                value: u64::from(message.call_reference),
98            });
99        }
100        Ok(Self {
101            conference_id,
102            participant,
103        })
104    }
105}
106
107pub(super) fn validate_conference_data_length(
108    payload: &[u8],
109    message_id: u32,
110    header_size: usize,
111    length_offset: usize,
112) -> Result<(), CodecError> {
113    if payload.len() < header_size {
114        return Err(CodecError::Truncated {
115            message_id,
116            needed: header_size,
117            actual: payload.len(),
118        });
119    }
120    let data_length = usize_from_wire(
121        message_id,
122        "conference passthrough data",
123        u32::from_le_bytes(
124            payload[length_offset..length_offset + 4]
125                .try_into()
126                .expect("validated conference header contains length word"),
127        ),
128    )?;
129    if data_length > MAX_CONFERENCE_PASSTHROUGH_DATA {
130        return Err(CodecError::CountTooLarge {
131            message_id,
132            field: "conference passthrough data",
133            count: data_length,
134            maximum: MAX_CONFERENCE_PASSTHROUGH_DATA,
135        });
136    }
137    let needed = header_size + data_length;
138    if payload.len() < needed {
139        return Err(CodecError::Truncated {
140            message_id,
141            needed,
142            actual: payload.len(),
143        });
144    }
145    Ok(())
146}
147
148pub(super) fn validate_conference_data_for_encode(
149    message_id: u32,
150    passthrough_data: &[u8],
151) -> Result<u32, CodecError> {
152    if passthrough_data.len() > MAX_CONFERENCE_PASSTHROUGH_DATA {
153        return Err(CodecError::CountTooLarge {
154            message_id,
155            field: "conference passthrough data",
156            count: passthrough_data.len(),
157            maximum: MAX_CONFERENCE_PASSTHROUGH_DATA,
158        });
159    }
160    wire_count(
161        message_id,
162        "conference passthrough data",
163        passthrough_data.len(),
164    )
165}