Skip to main content

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}