1use sip_header::SipHeader;
4
5sip_header::define_header_enum! {
6 tests_mod: sofia_variable_generated_tests,
7 error_type: ParseSofiaVariableError => "unknown sofia variable",
8 pub enum SofiaVariable {
13 SipFromUser => "sip_from_user",
15 SipFromHost => "sip_from_host",
16 SipFromPort => "sip_from_port",
17 SipFromUri => "sip_from_uri",
18 SipFromDisplay => "sip_from_display",
19 SipFromTag => "sip_from_tag",
20 SipFromComment => "sip_from_comment",
21 SipFromUserStripped => "sip_from_user_stripped",
22 SipFullFrom => "sip_full_from",
23
24 SipToUser => "sip_to_user",
26 SipToHost => "sip_to_host",
27 SipToPort => "sip_to_port",
28 SipToUri => "sip_to_uri",
29 SipToDisplay => "sip_to_display",
30 SipToTag => "sip_to_tag",
31 SipToComment => "sip_to_comment",
32 SipFullTo => "sip_full_to",
33
34 SipContactUser => "sip_contact_user",
36 SipContactHost => "sip_contact_host",
37 SipContactPort => "sip_contact_port",
38 SipContactUri => "sip_contact_uri",
39 SipContactParams => "sip_contact_params",
40
41 SipReqUser => "sip_req_user",
43 SipReqHost => "sip_req_host",
44 SipReqPort => "sip_req_port",
45 SipReqUri => "sip_req_uri",
46
47 SipViaHost => "sip_via_host",
49 SipViaPort => "sip_via_port",
50 SipViaRport => "sip_via_rport",
51 SipViaProtocol => "sip_via_protocol",
52 SipFullVia => "sip_full_via",
53 SipFullRoute => "sip_full_route",
54
55 SipCallId => "sip_call_id",
57 SipCseq => "sip_cseq",
58 SipUserAgent => "sip_user_agent",
59 SipSubject => "sip_subject",
60 SipAllow => "sip_allow",
61 SipAcceptLanguage => "sip_accept_language",
62 SipCallInfo => "sip_call_info",
63 SipDateEpochTime => "sip_date_epoch_time",
64
65 SipReceivedIp => "sip_received_ip",
67 SipReceivedPort => "sip_received_port",
68 SipNetworkIp => "sip_network_ip",
69 SipNetworkPort => "sip_network_port",
70 SipNatDetected => "sip_nat_detected",
71 SipTransport => "sip_transport",
72 SipReplyHost => "sip_reply_host",
73
74 SipAuthUsername => "sip_auth_username",
76 SipAuthPassword => "sip_auth_password",
77 SipAuthorized => "sip_authorized",
78 SipAclAuthedBy => "sip_acl_authed_by",
79 SipAclToken => "sip_acl_token",
80 SipChallengeRealm => "sip_challenge_realm",
81
82 SipInviteFailureStatus => "sip_invite_failure_status",
84 SipInviteFailurePhrase => "sip_invite_failure_phrase",
85 SipHangupDisposition => "sip_hangup_disposition",
86 SipTermStatus => "sip_term_status",
87 SipTermCause => "sip_term_cause",
88 SipReason => "sip_reason",
89
90 SipPAssertedIdentity => "sip_P-Asserted-Identity",
92 SipPPreferredIdentity => "sip_P-Preferred-Identity",
93 SipPrivacy => "sip_Privacy",
94 SipRemotePartyId => "sip_Remote-Party-ID",
95 SipStirShakenAttest => "sip_stir_shaken_attest",
96 SipVerstat => "sip_verstat",
97 SipVerstatDetailed => "sip_verstat_detailed",
98
99 SipInviteCallId => "sip_invite_call_id",
101 SipInviteCseq => "sip_invite_cseq",
102 SipInviteFullFrom => "sip_invite_full_from",
103 SipInviteFullTo => "sip_invite_full_to",
104 SipInviteFullVia => "sip_invite_full_via",
105 SipInviteFromUri => "sip_invite_from_uri",
106 SipInviteToUri => "sip_invite_to_uri",
107 SipInviteReqUri => "sip_invite_req_uri",
108 SipInviteRecordRoute => "sip_invite_record_route",
109 SipInviteRouteUri => "sip_invite_route_uri",
110 SipInviteDomain => "sip_invite_domain",
111 SipInviteParams => "sip_invite_params",
112
113 SipAutoAnswer => "sip_auto_answer",
115 SipAutoSimplify => "sip_auto_simplify",
116 SipEnableSoa => "sip_enable_soa",
117 SipCopyCustomHeaders => "sip_copy_custom_headers",
118 SipCopyMultipart => "sip_copy_multipart",
119 SipLoopedCall => "sip_looped_call",
120
121 SipRedirectedTo => "sip_redirected_to",
123 SipRedirectedBy => "sip_redirected_by",
124 SipRedirectDialstring => "sip_redirect_dialstring",
125 SipReferReply => "sip_refer_reply",
126 SipReferStatusCode => "sip_refer_status_code",
127 SipReferredByFull => "sip_referred_by_full",
128 SipReferredByCid => "sip_referred_by_cid",
129 SipReinviteSdp => "sip_reinvite_sdp",
130
131 SipGateway => "sip_gateway",
133 SipGatewayName => "sip_gateway_name",
134 SipUseGateway => "sip_use_gateway",
135 SipDestinationUrl => "sip_destination_url",
136
137 SipProfileName => "sip_profile_name",
139 SofiaProfileName => "sofia_profile_name",
140 SofiaProfileUrl => "sofia_profile_url",
141 SofiaProfileDomainName => "sofia_profile_domain_name",
142
143 RtpSecureMediaConfirmed => "rtp_secure_media_confirmed",
145 Rtp2833SendPayload => "rtp_2833_send_payload",
146 Rtp2833RecvPayload => "rtp_2833_recv_payload",
147 RtpDisableHold => "rtp_disable_hold",
148 RtpJitterBufferPlc => "rtp_jitter_buffer_plc",
149 RtpVideoMaxBandwidthIn => "rtp_video_max_bandwidth_in",
150 RtpVideoMaxBandwidthOut => "rtp_video_max_bandwidth_out",
151
152 SipCalleeIdName => "sip_callee_id_name",
154 SipCalleeIdNumber => "sip_callee_id_number",
155 SipCidType => "sip_cid_type",
156
157 SipRtpRxstat => "sip_rtp_rxstat",
159 SipRtpTxstat => "sip_rtp_txstat",
160 SipPRtpStat => "sip_p_rtp_stat",
161
162 SipHistoryInfo => "sip_history_info",
164 SipGeolocation => "sip_geolocation",
165
166 SipMultipart => "sip_multipart",
168 }
169}
170
171#[non_exhaustive]
173#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
174pub enum CarriedHeader {
175 Verbatim(SipHeader),
177 Derived(SipHeader),
180}
181
182impl SofiaVariable {
183 pub fn carried_header(&self) -> Option<CarriedHeader> {
193 use CarriedHeader::{Derived, Verbatim};
194 use SipHeader as H;
195
196 match self {
197 Self::SipFromUser
198 | Self::SipFromHost
199 | Self::SipFromPort
200 | Self::SipFromUri
201 | Self::SipFromDisplay
202 | Self::SipFromTag
203 | Self::SipFromComment
204 | Self::SipFromUserStripped => Some(Derived(H::From)),
205 Self::SipFullFrom => Some(Verbatim(H::From)),
206
207 Self::SipToUser
208 | Self::SipToHost
209 | Self::SipToPort
210 | Self::SipToUri
211 | Self::SipToDisplay
212 | Self::SipToTag
213 | Self::SipToComment => Some(Derived(H::To)),
214 Self::SipFullTo => Some(Verbatim(H::To)),
215
216 Self::SipContactUser
217 | Self::SipContactHost
218 | Self::SipContactPort
219 | Self::SipContactUri
220 | Self::SipContactParams => Some(Derived(H::Contact)),
221
222 Self::SipReqUser
224 | Self::SipReqHost
225 | Self::SipReqPort
226 | Self::SipReqUri
227 | Self::SipInviteReqUri => None,
228
229 Self::SipViaHost | Self::SipViaPort | Self::SipViaRport | Self::SipViaProtocol => {
230 Some(Derived(H::Via))
231 }
232 Self::SipFullVia => Some(Verbatim(H::Via)),
233 Self::SipFullRoute => Some(Verbatim(H::Route)),
234
235 Self::SipCallId => Some(Verbatim(H::CallId)),
236 Self::SipCseq => Some(Verbatim(H::Cseq)),
237 Self::SipUserAgent => Some(Verbatim(H::UserAgent)),
239 Self::SipSubject => Some(Verbatim(H::Subject)),
240 Self::SipAllow => Some(Verbatim(H::Allow)),
241 Self::SipAcceptLanguage => Some(Derived(H::AcceptLanguage)),
243 Self::SipCallInfo => Some(Verbatim(H::CallInfo)),
244 Self::SipDateEpochTime => Some(Derived(H::Date)),
245
246 Self::SipReceivedIp
247 | Self::SipReceivedPort
248 | Self::SipNetworkIp
249 | Self::SipNetworkPort
250 | Self::SipNatDetected
251 | Self::SipTransport
252 | Self::SipReplyHost => None,
253
254 Self::SipAuthUsername
255 | Self::SipAuthPassword
256 | Self::SipAuthorized
257 | Self::SipAclAuthedBy
258 | Self::SipAclToken
259 | Self::SipChallengeRealm => None,
260
261 Self::SipInviteFailureStatus
262 | Self::SipInviteFailurePhrase
263 | Self::SipHangupDisposition
264 | Self::SipTermStatus
265 | Self::SipTermCause => None,
266 Self::SipReason => Some(Verbatim(H::Reason)),
267
268 Self::SipPAssertedIdentity => Some(Verbatim(H::PAssertedIdentity)),
269 Self::SipPPreferredIdentity => Some(Verbatim(H::PPreferredIdentity)),
270 Self::SipPrivacy => Some(Verbatim(H::Privacy)),
271 Self::SipRemotePartyId => Some(Verbatim(H::RemotePartyId)),
272 Self::SipStirShakenAttest | Self::SipVerstat | Self::SipVerstatDetailed => None,
275
276 Self::SipInviteCallId => Some(Verbatim(H::CallId)),
277 Self::SipInviteCseq => Some(Verbatim(H::Cseq)),
278 Self::SipInviteFullFrom => Some(Verbatim(H::From)),
279 Self::SipInviteFullTo => Some(Verbatim(H::To)),
280 Self::SipInviteFullVia => Some(Verbatim(H::Via)),
281 Self::SipInviteFromUri => Some(Derived(H::From)),
282 Self::SipInviteToUri => Some(Derived(H::To)),
283 Self::SipInviteRecordRoute => Some(Verbatim(H::RecordRoute)),
284 Self::SipInviteRouteUri => Some(Derived(H::Route)),
285 Self::SipInviteDomain | Self::SipInviteParams => None,
286
287 Self::SipAutoAnswer
288 | Self::SipAutoSimplify
289 | Self::SipEnableSoa
290 | Self::SipCopyCustomHeaders
291 | Self::SipCopyMultipart
292 | Self::SipLoopedCall => None,
293
294 Self::SipRedirectedTo => Some(Verbatim(H::Contact)),
295 Self::SipRedirectedBy => Some(Verbatim(H::Diversion)),
296 Self::SipReferredByFull => Some(Verbatim(H::ReferredBy)),
297 Self::SipReferredByCid => Some(Derived(H::ReferredBy)),
298 Self::SipRedirectDialstring
299 | Self::SipReferReply
300 | Self::SipReferStatusCode
301 | Self::SipReinviteSdp => None,
302
303 Self::SipGateway
304 | Self::SipGatewayName
305 | Self::SipUseGateway
306 | Self::SipDestinationUrl
307 | Self::SipProfileName
308 | Self::SofiaProfileName
309 | Self::SofiaProfileUrl
310 | Self::SofiaProfileDomainName => None,
311
312 Self::RtpSecureMediaConfirmed
313 | Self::Rtp2833SendPayload
314 | Self::Rtp2833RecvPayload
315 | Self::RtpDisableHold
316 | Self::RtpJitterBufferPlc
317 | Self::RtpVideoMaxBandwidthIn
318 | Self::RtpVideoMaxBandwidthOut => None,
319
320 Self::SipCalleeIdName | Self::SipCalleeIdNumber | Self::SipCidType => None,
323
324 Self::SipRtpRxstat | Self::SipRtpTxstat | Self::SipPRtpStat => None,
326
327 Self::SipHistoryInfo => Some(Verbatim(H::HistoryInfo)),
328 Self::SipGeolocation => Some(Verbatim(H::Geolocation)),
329
330 Self::SipMultipart => None,
331 }
332 }
333}
334
335#[cfg(test)]
336mod tests {
337 use super::*;
338
339 #[test]
340 fn display_round_trip() {
341 assert_eq!(SofiaVariable::SipCallId.to_string(), "sip_call_id");
342 assert_eq!(
343 SofiaVariable::SipFromDisplay.to_string(),
344 "sip_from_display"
345 );
346 assert_eq!(
347 SofiaVariable::SofiaProfileName.to_string(),
348 "sofia_profile_name"
349 );
350 }
351
352 #[test]
353 fn as_ref_str() {
354 let v: &str = SofiaVariable::SipNetworkIp.as_ref();
355 assert_eq!(v, "sip_network_ip");
356 }
357
358 #[test]
359 fn from_str_case_insensitive() {
360 assert_eq!(
361 "sip_call_id".parse::<SofiaVariable>(),
362 Ok(SofiaVariable::SipCallId)
363 );
364 assert_eq!(
365 "SIP_CALL_ID".parse::<SofiaVariable>(),
366 Ok(SofiaVariable::SipCallId)
367 );
368 }
369
370 #[test]
371 fn from_str_unknown() {
372 let err = "nonexistent_sip_var".parse::<SofiaVariable>();
373 assert!(err.is_err());
374 }
375
376 #[test]
377 fn carried_header_verbatim() {
378 assert_eq!(
379 SofiaVariable::SipPrivacy.carried_header(),
380 Some(CarriedHeader::Verbatim(SipHeader::Privacy))
381 );
382 assert_eq!(
383 SofiaVariable::SipPAssertedIdentity.carried_header(),
384 Some(CarriedHeader::Verbatim(SipHeader::PAssertedIdentity))
385 );
386 assert_eq!(
387 SofiaVariable::SipRemotePartyId.carried_header(),
388 Some(CarriedHeader::Verbatim(SipHeader::RemotePartyId))
389 );
390 assert_eq!(
391 SofiaVariable::SipFullFrom.carried_header(),
392 Some(CarriedHeader::Verbatim(SipHeader::From))
393 );
394 }
395
396 #[test]
397 fn carried_header_derived() {
398 assert_eq!(
399 SofiaVariable::SipFromUser.carried_header(),
400 Some(CarriedHeader::Derived(SipHeader::From))
401 );
402 }
403
404 #[test]
405 fn carried_header_none() {
406 assert_eq!(SofiaVariable::SipReqUri.carried_header(), None);
408 assert_eq!(SofiaVariable::SipGateway.carried_header(), None);
409 }
410
411 #[test]
414 fn hyphenated_wire_names_match_their_header() {
415 for var in SofiaVariable::ALL {
416 let Some(suffix) = var
417 .as_str()
418 .strip_prefix("sip_")
419 else {
420 continue;
421 };
422 if !suffix.contains('-') {
423 continue;
424 }
425 let Some(carried) = var.carried_header() else {
426 panic!("{} spells a header but carries none", var.as_str());
427 };
428 let CarriedHeader::Verbatim(header) = carried else {
429 panic!("{} spells a header but is not verbatim", var.as_str());
430 };
431 assert_eq!(header.as_str(), suffix, "for {}", var.as_str());
432 }
433 }
434}