1use crate::device::device::{Connector, Endpoint, RecordOptions, TranscribeOptions};
4use crate::device::shared::{AiOptions, CallControl};
5use crate::device::utils::{get_caller_id, get_listen, get_transcribe};
6use crate::{format_number, ConnectState, FlowState, NumberFormat, RecordReference};
7use cal_jambonz::dial::TranscribeDial;
8use cal_jambonz::listen::Listen;
9use cal_jambonz::shared::shared::SIPStatus;
10use serde::{Deserialize, Serialize};
11use std::fmt::{Debug, Formatter};
12
13#[derive(Serialize, Deserialize, Clone)]
14#[serde(rename_all = "camelCase")]
15pub struct Client {
16 pub username: String,
17 pub password: String,
18 #[serde(default = "crate::device::shared::build_client_profile")]
19 pub profile: ClientProfile,
20 pub user: Option<RecordReference>,
21 #[serde(default = "crate::device::shared::build_format")]
22 pub format: NumberFormat,
23 #[serde(default = "crate::device::shared::build_present")]
24 pub present: String,
25 #[serde(default = "crate::device::shared::build_country_code")]
26 pub country_code: String,
27 #[serde(default = "crate::device::shared::build_connect_to")]
28 pub on_complete: String,
29 #[serde(default = "crate::device::shared::build_connect_to")]
30 pub on_busy: String,
31 #[serde(default = "crate::device::shared::build_connect_to")]
32 pub on_fail: String,
33 #[serde(default = "crate::device::shared::build_connect_to")]
34 pub on_no_answer: String,
35 #[serde(default = "crate::device::shared::build_ring_time")]
36 pub ring_time: u8,
37 #[serde(default = "crate::device::shared::build_call_time")]
38 pub max_call_time: u16,
39 #[serde(default)]
40 pub transcribe_options: TranscribeOptions,
41 #[serde(default)]
42 pub record_options: RecordOptions,
43 #[serde(default)]
44 pub ai_options: AiOptions,
45 #[serde(default)]
46 pub call_control: CallControl,
47}
48
49impl Endpoint for Client {
50 fn get_caller_id(&self, state: &FlowState) -> String {
51 get_caller_id(&self.format, state)
52 }
53
54 fn get_called_id(&self, state: &FlowState) -> String {
55 let country_code = state.account.country_code();
56 let mut called_id = match state.data.get("to") {
57 Some(dt) => dt.value.clone(),
58 None => state.initial_request.to.clone(),
59 };
60 called_id = format_number(
61 called_id.as_str(),
62 state.account.country_code(),
63 &self.format,
64 );
65 match self.profile {
66 ClientProfile::GenericSoftphone
67 | ClientProfile::CallablePhone
68 | ClientProfile::Avaya
69 | ClientProfile::Generic => called_id,
70 ClientProfile::GenericE164Plus => {
71 format_number(called_id.as_str(), country_code, &NumberFormat::E164Plus)
72 }
73 ClientProfile::AvayaE164 => {
74 format_number(called_id.as_str(), country_code, &NumberFormat::E164)
75 }
76 }
77 }
78
79 fn get_listen(&self, state: &FlowState) -> Option<Listen> {
80 get_listen(&self.record_options, self.ai_options.clone(), state)
81 }
82
83 fn get_transcribe(&self, _state: &FlowState) -> Option<TranscribeDial> {
84 get_transcribe(self.transcribe_options.clone())
85 }
86}
87
88impl Connector for Client {
89 fn get_connect_to(&mut self, state: &mut FlowState) -> ConnectState {
90 match &state.get_dial_status() {
91 Some(status) => match status {
92 SIPStatus::Ok => ConnectState::complete(self.on_complete.as_str()),
93 SIPStatus::RequestTerminated => ConnectState::no_answer(self.on_no_answer.as_str()),
94 SIPStatus::BusyHere | SIPStatus::BusyEverywhere => {
95 ConnectState::busy(self.on_busy.as_str())
96 }
97 _ => ConnectState::fail(self.on_fail.as_str()),
98 },
99 None => ConnectState::dialling(),
100 }
101 }
102}
103
104#[derive(Serialize, Deserialize, Clone)]
105#[serde(rename_all = "snake_case")]
106pub enum ClientProfile {
107 Generic,
108 GenericE164Plus,
109 GenericSoftphone,
110 CallablePhone,
111 Avaya,
112 AvayaE164,
113}
114
115impl Debug for Client {
117 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
118 f.debug_struct("Client")
119 .field("username", &self.username)
120 .field("password", &"REDACTED")
121 .field("profile", &self.profile)
122 .field("user", &self.user)
123 .field("format", &self.format)
124 .field("present", &self.present)
125 .field("country_code", &self.country_code)
126 .field("on_complete", &self.on_complete)
127 .field("on_busy", &self.on_busy)
128 .field("on_fail", &self.on_fail)
129 .field("on_no_answer", &self.on_no_answer)
130 .field("ring_time", &self.ring_time)
131 .field("max_call_time", &self.max_call_time)
132 .field("transcribe_options", &self.transcribe_options)
133 .field("record_options", &self.record_options)
134 .field("ai_options", &self.ai_options)
135 .field("call_control", &self.call_control)
136 .finish()
137 }
138}
139
140impl Debug for ClientProfile {
141 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
142 match self {
143 ClientProfile::GenericE164Plus => write!(f, "GenericE164Plus"),
144 ClientProfile::CallablePhone => write!(f, "CallablePhone"),
145 ClientProfile::Avaya => write!(f, "Avaya"),
146 ClientProfile::Generic => write!(f, "Generic"),
147 ClientProfile::GenericSoftphone => write!(f, "GenericSoftphone"),
148 ClientProfile::AvayaE164 => write!(f, "AvayaE164"),
149 }
150 }
151}
152
153impl Debug for NumberFormat {
154 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
155 match self {
156 NumberFormat::National => write!(f, "National"),
157 NumberFormat::E164Plus => write!(f, "E164+"),
158 NumberFormat::E164 => write!(f, "E164"),
159 }
160 }
161}
162