rvoip_sip/server/transfer.rs
1//! B2BUA-side transfer orchestration helpers.
2//!
3//! Per CARVE_PLAN §3 (transfer row): the actual SIP REFER mechanics
4//! (the `refer(...)` builder, `accept_refer`, `transfer_attended`, etc.)
5//! already live in [`UnifiedCoordinator`] and are NOT re-implemented here.
6//! This module provides B2BUA-side scenario glue — pick which leg, build
7//! the target, choose blind vs attended — that calls into those methods.
8
9use std::sync::Arc;
10
11use crate::api::unified::UnifiedCoordinator;
12use crate::SessionId;
13use thiserror::Error;
14
15/// Error returned by the B2BUA transfer helpers.
16#[derive(Debug, Error)]
17pub enum TransferError {
18 /// The transfer (REFER send or accept) failed.
19 #[error("transfer failed: {0}")]
20 Failed(String),
21}
22
23impl From<crate::errors::SessionError> for TransferError {
24 fn from(err: crate::errors::SessionError) -> Self {
25 TransferError::Failed(err.to_string())
26 }
27}
28
29/// Blind transfer: send a REFER on `source_session` pointing at `target_uri`.
30/// The transferee dials `target_uri` directly; no Replaces header involved.
31/// (RFC 3515.)
32pub async fn blind_transfer(
33 coordinator: &Arc<UnifiedCoordinator>,
34 source_session: &SessionId,
35 target_uri: &str,
36) -> Result<(), TransferError> {
37 coordinator
38 .refer(source_session, target_uri.to_string())
39 .send()
40 .await
41 .map_err(Into::into)
42}
43
44/// Attended transfer with Replaces (RFC 3891 / RFC 5589): send a REFER on
45/// `source_session` whose Refer-To header carries a Replaces parameter
46/// referencing `replacing_session`. Caller is expected to have already
47/// established `replacing_session` and `target_uri` should encode the
48/// transferee leg appropriately.
49pub async fn attended_transfer(
50 coordinator: &Arc<UnifiedCoordinator>,
51 source_session: &SessionId,
52 target_uri: &str,
53 replaces: &str,
54) -> Result<(), TransferError> {
55 coordinator
56 .refer(source_session, target_uri.to_string())
57 .with_replaces(replaces.to_string())
58 .send()
59 .await
60 .map_err(Into::into)
61}
62
63/// Accept an inbound REFER on `session_id`. Triggers the
64/// downstream-call-and-NOTIFY flow per RFC 3515.
65pub async fn accept_inbound_refer(
66 coordinator: &UnifiedCoordinator,
67 session_id: &SessionId,
68) -> Result<(), TransferError> {
69 coordinator
70 .accept_refer(session_id)
71 .await
72 .map_err(Into::into)
73}