Skip to main content

freeswitch_types/variables/
sofia.rs

1//! Typed mod_sofia / SIP channel variable names.
2
3use serde::{Deserialize, Serialize};
4
5/// Error returned when parsing an unrecognized Sofia variable name.
6#[derive(Debug, Clone, PartialEq, Eq)]
7pub struct ParseSofiaVariableError(pub String);
8
9impl std::fmt::Display for ParseSofiaVariableError {
10    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
11        write!(f, "unknown sofia variable: {}", self.0)
12    }
13}
14
15impl std::error::Error for ParseSofiaVariableError {}
16
17define_header_enum! {
18    error_type: ParseSofiaVariableError,
19    /// mod_sofia / SIP channel variable names (the part after the `variable_` prefix).
20    ///
21    /// Use with [`HeaderLookup::variable()`](crate::HeaderLookup::variable) for type-safe lookups.
22    /// Core FreeSWITCH variables belong in [`ChannelVariable`](super::ChannelVariable).
23    pub enum SofiaVariable {
24        // --- SIP From ---
25        SipFromUser => "sip_from_user",
26        SipFromHost => "sip_from_host",
27        SipFromPort => "sip_from_port",
28        SipFromUri => "sip_from_uri",
29        SipFromDisplay => "sip_from_display",
30        SipFromTag => "sip_from_tag",
31        SipFromComment => "sip_from_comment",
32        SipFromUserStripped => "sip_from_user_stripped",
33        SipFullFrom => "sip_full_from",
34
35        // --- SIP To ---
36        SipToUser => "sip_to_user",
37        SipToHost => "sip_to_host",
38        SipToPort => "sip_to_port",
39        SipToUri => "sip_to_uri",
40        SipToDisplay => "sip_to_display",
41        SipToTag => "sip_to_tag",
42        SipToComment => "sip_to_comment",
43        SipFullTo => "sip_full_to",
44
45        // --- SIP Contact ---
46        SipContactUser => "sip_contact_user",
47        SipContactHost => "sip_contact_host",
48        SipContactPort => "sip_contact_port",
49        SipContactUri => "sip_contact_uri",
50        SipContactParams => "sip_contact_params",
51
52        // --- SIP Request ---
53        SipReqUser => "sip_req_user",
54        SipReqHost => "sip_req_host",
55        SipReqPort => "sip_req_port",
56        SipReqUri => "sip_req_uri",
57
58        // --- SIP Via ---
59        SipViaHost => "sip_via_host",
60        SipViaPort => "sip_via_port",
61        SipViaRport => "sip_via_rport",
62        SipViaProtocol => "sip_via_protocol",
63        SipFullVia => "sip_full_via",
64        SipFullRoute => "sip_full_route",
65
66        // --- SIP Session ---
67        SipCallId => "sip_call_id",
68        SipCseq => "sip_cseq",
69        SipUserAgent => "sip_user_agent",
70        SipSubject => "sip_subject",
71        SipAllow => "sip_allow",
72        SipAcceptLanguage => "sip_accept_language",
73        SipCallInfo => "sip_call_info",
74        SipDateEpochTime => "sip_date_epoch_time",
75
76        // --- SIP Network ---
77        SipReceivedIp => "sip_received_ip",
78        SipReceivedPort => "sip_received_port",
79        SipNetworkIp => "sip_network_ip",
80        SipNetworkPort => "sip_network_port",
81        SipNatDetected => "sip_nat_detected",
82        SipTransport => "sip_transport",
83        SipReplyHost => "sip_reply_host",
84
85        // --- SIP Auth ---
86        SipAuthUsername => "sip_auth_username",
87        SipAuthPassword => "sip_auth_password",
88        SipAuthorized => "sip_authorized",
89        SipAclAuthedBy => "sip_acl_authed_by",
90        SipAclToken => "sip_acl_token",
91        SipChallengeRealm => "sip_challenge_realm",
92
93        // --- SIP Failure / Hangup ---
94        SipInviteFailureStatus => "sip_invite_failure_status",
95        SipInviteFailurePhrase => "sip_invite_failure_phrase",
96        SipHangupDisposition => "sip_hangup_disposition",
97        SipTermStatus => "sip_term_status",
98        SipTermCause => "sip_term_cause",
99        SipReason => "sip_reason",
100
101        // --- SIP Identity / Privacy ---
102        SipPAssertedIdentity => "sip_P-Asserted-Identity",
103        SipPPreferredIdentity => "sip_P-Preferred-Identity",
104        SipPrivacy => "sip_Privacy",
105        SipRemotePartyId => "sip_Remote-Party-ID",
106        SipStirShakenAttest => "sip_stir_shaken_attest",
107        SipVerstat => "sip_verstat",
108        SipVerstatDetailed => "sip_verstat_detailed",
109
110        // --- SIP Invite Details ---
111        SipInviteCallId => "sip_invite_call_id",
112        SipInviteCseq => "sip_invite_cseq",
113        SipInviteFullFrom => "sip_invite_full_from",
114        SipInviteFullTo => "sip_invite_full_to",
115        SipInviteFullVia => "sip_invite_full_via",
116        SipInviteFromUri => "sip_invite_from_uri",
117        SipInviteToUri => "sip_invite_to_uri",
118        SipInviteReqUri => "sip_invite_req_uri",
119        SipInviteRecordRoute => "sip_invite_record_route",
120        SipInviteRouteUri => "sip_invite_route_uri",
121        SipInviteDomain => "sip_invite_domain",
122        SipInviteParams => "sip_invite_params",
123
124        // --- SIP Features ---
125        SipAutoAnswer => "sip_auto_answer",
126        SipAutoSimplify => "sip_auto_simplify",
127        SipEnableSoa => "sip_enable_soa",
128        SipCopyCustomHeaders => "sip_copy_custom_headers",
129        SipCopyMultipart => "sip_copy_multipart",
130        SipLoopedCall => "sip_looped_call",
131
132        // --- SIP Redirect / Transfer ---
133        SipRedirectedTo => "sip_redirected_to",
134        SipRedirectedBy => "sip_redirected_by",
135        SipRedirectDialstring => "sip_redirect_dialstring",
136        SipReferReply => "sip_refer_reply",
137        SipReferStatusCode => "sip_refer_status_code",
138        SipReferredByFull => "sip_referred_by_full",
139        SipReferredByCid => "sip_referred_by_cid",
140        SipReinviteSdp => "sip_reinvite_sdp",
141
142        // --- SIP Gateway ---
143        SipGateway => "sip_gateway",
144        SipGatewayName => "sip_gateway_name",
145        SipUseGateway => "sip_use_gateway",
146        SipDestinationUrl => "sip_destination_url",
147
148        // --- Sofia Profile ---
149        SipProfileName => "sip_profile_name",
150        SofiaProfileName => "sofia_profile_name",
151        SofiaProfileUrl => "sofia_profile_url",
152        SofiaProfileDomainName => "sofia_profile_domain_name",
153
154        // --- RTP / SRTP (set via mod_sofia / switch_core_media) ---
155        RtpSecureMediaConfirmed => "rtp_secure_media_confirmed",
156        Rtp2833SendPayload => "rtp_2833_send_payload",
157        Rtp2833RecvPayload => "rtp_2833_recv_payload",
158        RtpDisableHold => "rtp_disable_hold",
159        RtpJitterBufferPlc => "rtp_jitter_buffer_plc",
160        RtpVideoMaxBandwidthIn => "rtp_video_max_bandwidth_in",
161        RtpVideoMaxBandwidthOut => "rtp_video_max_bandwidth_out",
162
163        // --- SIP Callee / Display ---
164        SipCalleeIdName => "sip_callee_id_name",
165        SipCalleeIdNumber => "sip_callee_id_number",
166        SipCidType => "sip_cid_type",
167
168        // --- SIP RTP Stats ---
169        SipRtpRxstat => "sip_rtp_rxstat",
170        SipRtpTxstat => "sip_rtp_txstat",
171        SipPRtpStat => "sip_p_rtp_stat",
172
173        // --- SIP History ---
174        SipHistoryInfo => "sip_history_info",
175        SipGeolocation => "sip_geolocation",
176    }
177}
178
179#[cfg(test)]
180mod tests {
181    use super::*;
182
183    #[test]
184    fn display_round_trip() {
185        assert_eq!(SofiaVariable::SipCallId.to_string(), "sip_call_id");
186        assert_eq!(
187            SofiaVariable::SipFromDisplay.to_string(),
188            "sip_from_display"
189        );
190        assert_eq!(
191            SofiaVariable::SofiaProfileName.to_string(),
192            "sofia_profile_name"
193        );
194    }
195
196    #[test]
197    fn as_ref_str() {
198        let v: &str = SofiaVariable::SipNetworkIp.as_ref();
199        assert_eq!(v, "sip_network_ip");
200    }
201
202    #[test]
203    fn from_str_case_insensitive() {
204        assert_eq!(
205            "sip_call_id".parse::<SofiaVariable>(),
206            Ok(SofiaVariable::SipCallId)
207        );
208        assert_eq!(
209            "SIP_CALL_ID".parse::<SofiaVariable>(),
210            Ok(SofiaVariable::SipCallId)
211        );
212    }
213
214    #[test]
215    fn from_str_unknown() {
216        let err = "nonexistent_sip_var".parse::<SofiaVariable>();
217        assert!(err.is_err());
218    }
219
220    #[test]
221    fn from_str_round_trip_sample() {
222        let variants = [
223            SofiaVariable::SipCallId,
224            SofiaVariable::SipFromUser,
225            SofiaVariable::SipToHost,
226            SofiaVariable::SipNetworkIp,
227            SofiaVariable::SipHangupDisposition,
228            SofiaVariable::SipPAssertedIdentity,
229            SofiaVariable::SofiaProfileName,
230            SofiaVariable::RtpSecureMediaConfirmed,
231            SofiaVariable::SipGatewayName,
232            SofiaVariable::SipInviteCallId,
233        ];
234        for v in variants {
235            let wire = v.to_string();
236            let parsed: SofiaVariable = wire
237                .parse()
238                .unwrap();
239            assert_eq!(parsed, v, "round-trip failed for {wire}");
240        }
241    }
242}