Skip to main content

freeswitch_types/variables/
sofia.rs

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