1use super::*;
4
5#[derive(Clone, Debug, serde::Deserialize, Eq, PartialEq, Serialize)]
7#[serde(rename = "CiscoIPPhoneStatus", deny_unknown_fields)]
8pub struct CiscoIpPhoneStatus {
9 #[serde(rename = "Text", default, skip_serializing_if = "Option::is_none")]
10 pub text: Option<String>,
11 #[serde(rename = "Timer", default, skip_serializing_if = "Option::is_none")]
12 pub timer_seconds: Option<u16>,
14 #[serde(rename = "LocationX", default, skip_serializing_if = "Option::is_none")]
15 pub location_x: Option<i16>,
17 #[serde(rename = "LocationY", default, skip_serializing_if = "Option::is_none")]
18 pub location_y: Option<i16>,
20 #[serde(rename = "Width")]
21 pub width: u16,
23 #[serde(rename = "Height")]
24 pub height: u16,
26 #[serde(rename = "Depth")]
27 pub depth: u16,
29 #[serde(rename = "Data", default, skip_serializing_if = "Option::is_none")]
30 pub data: Option<PhoneBitmapData>,
31}
32
33impl CiscoIpPhoneStatus {
34 pub fn validate(&self) -> Result<(), PhoneXmlError> {
36 validate_optional_text("phone status text", self.text.as_deref(), 0, 32)?;
37 if self
38 .location_x
39 .is_some_and(|value| !(-1..=105).contains(&value))
40 {
41 return Err(PhoneXmlError::InvalidField {
42 field: "phone status horizontal location",
43 expected: "between -1 and 105",
44 });
45 }
46 if self
47 .location_y
48 .is_some_and(|value| !(-1..=20).contains(&value))
49 {
50 return Err(PhoneXmlError::InvalidField {
51 field: "phone status vertical location",
52 expected: "between -1 and 20",
53 });
54 }
55 if !(1..=106).contains(&self.width) {
56 return Err(PhoneXmlError::InvalidField {
57 field: "phone status width",
58 expected: "between 1 and 106",
59 });
60 }
61 if !(1..=21).contains(&self.height) {
62 return Err(PhoneXmlError::InvalidField {
63 field: "phone status height",
64 expected: "between 1 and 21",
65 });
66 }
67 if !(1..=2).contains(&self.depth) {
68 return Err(PhoneXmlError::InvalidField {
69 field: "phone status depth",
70 expected: "between 1 and 2",
71 });
72 }
73 if let Some(data) = &self.data {
74 validate_count(
75 "phone status bitmap bytes",
76 data.as_bytes().len(),
77 PHONE_STATUS_BITMAP_MAX_BYTES,
78 )?;
79 }
80 Ok(())
81 }
82}
83
84#[derive(Clone, Debug, serde::Deserialize, Eq, PartialEq, Serialize)]
86#[serde(rename = "CiscoIPPhoneStatusFile", deny_unknown_fields)]
87pub struct CiscoIpPhoneStatusFile {
88 #[serde(rename = "Text", default, skip_serializing_if = "Option::is_none")]
89 pub text: Option<String>,
90 #[serde(rename = "Timer", default, skip_serializing_if = "Option::is_none")]
91 pub timer_seconds: Option<u16>,
93 #[serde(rename = "LocationX", default, skip_serializing_if = "Option::is_none")]
94 pub location_x: Option<i16>,
96 #[serde(rename = "LocationY", default, skip_serializing_if = "Option::is_none")]
97 pub location_y: Option<i16>,
99 #[serde(rename = "URL")]
100 pub url: PhoneImageUrl,
101}
102
103impl CiscoIpPhoneStatusFile {
104 pub fn validate(&self) -> Result<(), PhoneXmlError> {
106 validate_optional_text("phone status text", self.text.as_deref(), 0, 32)?;
107 if self
108 .location_x
109 .is_some_and(|value| !(-1..=261).contains(&value))
110 {
111 return Err(PhoneXmlError::InvalidField {
112 field: "phone status-file horizontal location",
113 expected: "between -1 and 261",
114 });
115 }
116 if self
117 .location_y
118 .is_some_and(|value| !(-1..=49).contains(&value))
119 {
120 return Err(PhoneXmlError::InvalidField {
121 field: "phone status-file vertical location",
122 expected: "between -1 and 49",
123 });
124 }
125 Ok(())
126 }
127}
128
129#[derive(Clone, Debug, Eq, PartialEq)]
131pub enum PhoneStatusDocument {
132 Bitmap(CiscoIpPhoneStatus),
133 File(CiscoIpPhoneStatusFile),
134}
135
136impl PhoneStatusDocument {
137 pub fn validate(&self) -> Result<(), PhoneXmlError> {
139 match self {
140 Self::Bitmap(document) => document.validate(),
141 Self::File(document) => document.validate(),
142 }
143 }
144
145 pub fn from_xml(document: &[u8]) -> Result<Self, PhoneXmlError> {
147 #[derive(serde::Deserialize)]
148 enum StatusDocumentEnvelope {
149 #[serde(rename = "CiscoIPPhoneStatus")]
150 Bitmap(CiscoIpPhoneStatus),
151 #[serde(rename = "CiscoIPPhoneStatusFile")]
152 File(CiscoIpPhoneStatusFile),
153 }
154 let document = match from_bytes(document, PHONE_STATUS_MAX_BYTES)? {
155 StatusDocumentEnvelope::Bitmap(document) => Self::Bitmap(document),
156 StatusDocumentEnvelope::File(document) => Self::File(document),
157 };
158 document.validate()?;
159 Ok(document)
160 }
161
162 pub fn to_xml(&self) -> Result<String, PhoneXmlError> {
164 self.to_xml_with_limit(PHONE_STATUS_MAX_BYTES)
165 }
166
167 pub fn to_xml_with_limit(&self, maximum_bytes: usize) -> Result<String, PhoneXmlError> {
169 self.validate()?;
170 match self {
171 Self::Bitmap(document) => to_string(document, maximum_bytes),
172 Self::File(document) => to_string(document, maximum_bytes),
173 }
174 }
175}