1use serde::{Deserialize, Serialize};
8use std::fmt;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
12pub enum ConnectionStatus {
13 #[serde(rename = "900")]
14 Connecting,
15 #[serde(rename = "901")]
16 Connected,
17 #[serde(rename = "902")]
18 Disconnected,
19 #[serde(rename = "903")]
20 Disconnecting,
21 #[serde(rename = "904")]
22 ConnectFailed,
23 #[serde(rename = "905")]
24 ConnectStatusNull,
25 #[serde(rename = "906")]
26 ConnectStatusError,
27}
28
29impl fmt::Display for ConnectionStatus {
30 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31 let text = match self {
32 ConnectionStatus::Connecting => "CONNECTING",
33 ConnectionStatus::Connected => "CONNECTED",
34 ConnectionStatus::Disconnected => "DISCONNECTED",
35 ConnectionStatus::Disconnecting => "DISCONNECTING",
36 ConnectionStatus::ConnectFailed => "CONNECT_FAILED",
37 ConnectionStatus::ConnectStatusNull => "CONNECT_STATUS_NULL",
38 ConnectionStatus::ConnectStatusError => "CONNECT_STATUS_ERROR",
39 };
40 write!(f, "{text}")
41 }
42}
43
44impl ConnectionStatus {
45 pub fn is_connected(&self) -> bool {
47 matches!(self, ConnectionStatus::Connected)
48 }
49
50 pub fn is_connecting(&self) -> bool {
52 matches!(self, ConnectionStatus::Connecting)
53 }
54
55 pub fn is_disconnected(&self) -> bool {
57 matches!(
58 self,
59 ConnectionStatus::Disconnected | ConnectionStatus::Disconnecting
60 )
61 }
62
63 pub fn is_failed(&self) -> bool {
65 matches!(
66 self,
67 ConnectionStatus::ConnectFailed
68 | ConnectionStatus::ConnectStatusNull
69 | ConnectionStatus::ConnectStatusError
70 )
71 }
72}
73
74#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
76pub enum NetworkType {
77 #[serde(rename = "7")]
78 Hspa,
79 #[serde(rename = "19")]
80 Lte,
81 #[serde(rename = "41")]
82 LteCarrierAggregation,
83 #[serde(rename = "101")]
84 FiveGNsa,
85 #[serde(rename = "102")]
86 FiveGSa,
87}
88
89impl fmt::Display for NetworkType {
90 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91 let text = match self {
92 NetworkType::Hspa => "HSPA (3G)",
93 NetworkType::Lte => "LTE (4G)",
94 NetworkType::LteCarrierAggregation => "LTE CA (4G+)",
95 NetworkType::FiveGNsa => "5G NSA",
96 NetworkType::FiveGSa => "5G SA",
97 };
98 write!(f, "{text}")
99 }
100}
101
102impl NetworkType {
103 pub fn extended_text(&self) -> &'static str {
105 match self {
106 NetworkType::Hspa => "HSPA",
107 NetworkType::Lte => "LTE",
108 NetworkType::LteCarrierAggregation => "LTE Carrier Aggregation",
109 NetworkType::FiveGNsa => "5G Non-Standalone",
110 NetworkType::FiveGSa => "5G Standalone",
111 }
112 }
113
114 pub fn is_5g(&self) -> bool {
116 matches!(self, NetworkType::FiveGNsa | NetworkType::FiveGSa)
117 }
118
119 pub fn is_4g(&self) -> bool {
121 matches!(self, NetworkType::Lte | NetworkType::LteCarrierAggregation)
122 }
123
124 pub fn is_3g(&self) -> bool {
126 matches!(self, NetworkType::Hspa)
127 }
128}
129
130#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
132pub enum NetworkModeType {
133 #[serde(rename = "00")]
134 Auto,
135 #[serde(rename = "01")]
136 TwoGOnly,
137 #[serde(rename = "02")]
138 ThreeGOnly,
139 #[serde(rename = "03")]
140 FourGOnly,
141 #[serde(rename = "0201")]
142 ThreeGPreferredTwoGFallback,
143 #[serde(rename = "0301")]
144 FourGPreferredTwoGFallback,
145 #[serde(rename = "0302")]
146 FourGPreferredThreeGFallback,
147}
148
149impl fmt::Display for NetworkModeType {
150 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
151 let text = match self {
152 NetworkModeType::Auto => "Auto (2G/3G/4G)",
153 NetworkModeType::TwoGOnly => "2G Only (GSM/EDGE)",
154 NetworkModeType::ThreeGOnly => "3G Only (UMTS/HSPA)",
155 NetworkModeType::FourGOnly => "4G Only (LTE)",
156 NetworkModeType::ThreeGPreferredTwoGFallback => "3G Preferred, 2G Fallback",
157 NetworkModeType::FourGPreferredTwoGFallback => "4G Preferred, 2G Fallback",
158 NetworkModeType::FourGPreferredThreeGFallback => "4G Preferred, 3G Fallback",
159 };
160 write!(f, "{text}")
161 }
162}
163
164#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
166pub enum SimStatus {
167 #[serde(rename = "0")]
168 NotReady,
169 #[serde(rename = "1")]
170 Ready,
171}
172
173impl SimStatus {
174 pub fn is_ready(&self) -> bool {
176 matches!(self, SimStatus::Ready)
177 }
178}
179
180#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
182pub enum RoamingStatus {
183 #[serde(rename = "0")]
184 NotRoaming,
185 #[serde(rename = "1")]
186 Roaming,
187}
188
189impl RoamingStatus {
190 pub fn is_roaming(&self) -> bool {
192 matches!(self, RoamingStatus::Roaming)
193 }
194}
195
196#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
198pub enum ServiceStatus {
199 #[serde(rename = "0")]
200 NoService,
201 #[serde(rename = "1")]
202 LimitedService,
203 #[serde(rename = "2")]
204 FullService,
205}
206
207impl ServiceStatus {
208 pub fn is_available(&self) -> bool {
210 matches!(
211 self,
212 ServiceStatus::LimitedService | ServiceStatus::FullService
213 )
214 }
215
216 pub fn is_full_service(&self) -> bool {
218 matches!(self, ServiceStatus::FullService)
219 }
220}
221
222#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
224pub enum SmsStatus {
225 #[serde(rename = "0")]
226 Unread,
227 #[serde(rename = "1")]
228 Read,
229 #[serde(rename = "2")]
230 PendingSend,
231 #[serde(rename = "3")]
232 Sent,
233 #[serde(rename = "4")]
234 SendFailed,
235}
236
237impl SmsStatus {
238 pub fn is_unread(&self) -> bool {
239 matches!(self, SmsStatus::Unread)
240 }
241
242 pub fn is_read(&self) -> bool {
243 matches!(self, SmsStatus::Read)
244 }
245
246 pub fn is_sent(&self) -> bool {
247 matches!(self, SmsStatus::Sent)
248 }
249}
250
251#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
253pub enum SmsPriority {
254 #[serde(rename = "0")]
255 Normal,
256 #[serde(rename = "1")]
257 High,
258}
259
260#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
262pub enum SmsType {
263 #[serde(rename = "1")]
264 Single,
265 #[serde(rename = "2")]
266 Multipart,
267 #[serde(rename = "5")]
268 Unicode,
269 #[serde(rename = "7")]
270 DeliveryConfirmationSuccess,
271 #[serde(rename = "8")]
272 DeliveryConfirmationFailure,
273}
274
275#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
277pub enum SmsBoxType {
278 #[serde(rename = "1")]
279 LocalInbox,
280 #[serde(rename = "2")]
281 LocalOutbox,
282 #[serde(rename = "3")]
283 LocalDraft,
284 #[serde(rename = "4")]
285 SimInbox,
286 #[serde(rename = "5")]
287 SimOutbox,
288 #[serde(rename = "6")]
289 SimDraft,
290}
291
292impl fmt::Display for SmsBoxType {
293 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
294 let text = match self {
295 SmsBoxType::LocalInbox => "1",
296 SmsBoxType::LocalOutbox => "2",
297 SmsBoxType::LocalDraft => "3",
298 SmsBoxType::SimInbox => "4",
299 SmsBoxType::SimOutbox => "5",
300 SmsBoxType::SimDraft => "6",
301 };
302 write!(f, "{text}")
303 }
304}
305
306#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
308pub enum SmsSortType {
309 #[serde(rename = "0")]
310 ByTime,
311 #[serde(rename = "1")]
312 ByName,
313}
314
315impl fmt::Display for SmsSortType {
316 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
317 let text = match self {
318 SmsSortType::ByTime => "0",
319 SmsSortType::ByName => "1",
320 };
321 write!(f, "{text}")
322 }
323}
324
325#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
327pub enum LoginStatus {
328 #[serde(rename = "0")]
329 LoggedIn,
330 #[serde(rename = "-1")]
331 NotLoggedIn,
332 #[serde(rename = "-2")]
333 RepeatLoginRequired,
334}
335
336impl LoginStatus {
337 pub fn is_logged_in(&self) -> bool {
339 matches!(self, LoginStatus::LoggedIn)
340 }
341}
342
343#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
345pub enum LockStatus {
346 #[serde(rename = "0")]
347 Unlocked,
348 #[serde(rename = "1")]
349 Locked,
350}
351
352impl LockStatus {
353 pub fn is_locked(&self) -> bool {
355 matches!(self, LockStatus::Locked)
356 }
357}
358
359#[derive(Debug, Clone, Copy, PartialEq, Eq)]
361pub enum DhcpStatus {
362 Disabled,
363 Enabled,
364}
365
366impl Serialize for DhcpStatus {
367 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
368 where
369 S: serde::Serializer,
370 {
371 let value = match self {
372 DhcpStatus::Disabled => "0",
373 DhcpStatus::Enabled => "1",
374 };
375 serializer.serialize_str(value)
376 }
377}
378
379impl<'de> Deserialize<'de> for DhcpStatus {
380 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
381 where
382 D: serde::Deserializer<'de>,
383 {
384 let value = String::deserialize(deserializer)?;
385 match value.as_str() {
386 "0" => Ok(DhcpStatus::Disabled),
387 "1" => Ok(DhcpStatus::Enabled),
388 _ => Err(serde::de::Error::custom(format!(
389 "Invalid DHCP status: {value}"
390 ))),
391 }
392 }
393}
394
395impl DhcpStatus {
396 pub fn is_enabled(&self) -> bool {
398 matches!(self, DhcpStatus::Enabled)
399 }
400}
401
402#[derive(Debug, Clone, Copy, PartialEq, Eq)]
404pub enum DnsStatus {
405 Disabled,
406 Enabled,
407}
408
409impl Serialize for DnsStatus {
410 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
411 where
412 S: serde::Serializer,
413 {
414 let value = match self {
415 DnsStatus::Disabled => "0",
416 DnsStatus::Enabled => "1",
417 };
418 serializer.serialize_str(value)
419 }
420}
421
422impl<'de> Deserialize<'de> for DnsStatus {
423 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
424 where
425 D: serde::Deserializer<'de>,
426 {
427 let value = String::deserialize(deserializer)?;
428 match value.as_str() {
429 "0" => Ok(DnsStatus::Disabled),
430 "1" => Ok(DnsStatus::Enabled),
431 _ => Err(serde::de::Error::custom(format!(
432 "Invalid DNS status: {value}"
433 ))),
434 }
435 }
436}
437
438impl DnsStatus {
439 pub fn is_enabled(&self) -> bool {
441 matches!(self, DnsStatus::Enabled)
442 }
443}
444
445#[derive(Debug, Clone, Copy, PartialEq, Eq)]
447pub enum DeviceControlType {
448 Reboot,
449 FactoryReset,
450 BackupConfiguration,
451 PowerOff,
452}
453
454impl Serialize for DeviceControlType {
455 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
456 where
457 S: serde::Serializer,
458 {
459 let value = match self {
460 DeviceControlType::Reboot => 1,
461 DeviceControlType::FactoryReset => 2,
462 DeviceControlType::BackupConfiguration => 3,
463 DeviceControlType::PowerOff => 4,
464 };
465 serializer.serialize_i32(value)
466 }
467}
468
469impl<'de> Deserialize<'de> for DeviceControlType {
470 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
471 where
472 D: serde::Deserializer<'de>,
473 {
474 let value = i32::deserialize(deserializer)?;
475 match value {
476 1 => Ok(DeviceControlType::Reboot),
477 2 => Ok(DeviceControlType::FactoryReset),
478 3 => Ok(DeviceControlType::BackupConfiguration),
479 4 => Ok(DeviceControlType::PowerOff),
480 _ => Err(serde::de::Error::custom(format!(
481 "Invalid device control type: {value}"
482 ))),
483 }
484 }
485}
486
487impl fmt::Display for DeviceControlType {
488 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
489 let text = match self {
490 DeviceControlType::Reboot => "Reboot",
491 DeviceControlType::FactoryReset => "Factory Reset",
492 DeviceControlType::BackupConfiguration => "Backup Configuration",
493 DeviceControlType::PowerOff => "Power Off",
494 };
495 write!(f, "{text}")
496 }
497}
498
499#[derive(Debug, Clone, PartialEq, Eq)]
501pub enum ApiErrorCode {
502 WrongToken,
504 CsrfTokenInvalid,
505 WrongSessionToken,
506
507 UsernameWrong,
509 PasswordWrong,
510 AlreadyLoggedIn,
511 UsernameOrPasswordWrong,
512 TooManyLoginAttempts,
513 PasswordChangeRequired,
514
515 SystemUnknown,
517 SystemNoSupport,
518 NoRights,
519 SystemBusy,
520 FormatError,
521
522 Unknown(String),
524}
525
526impl Serialize for ApiErrorCode {
527 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
528 where
529 S: serde::Serializer,
530 {
531 let value = match self {
532 ApiErrorCode::WrongToken => "125001",
533 ApiErrorCode::CsrfTokenInvalid => "125002",
534 ApiErrorCode::WrongSessionToken => "125003",
535 ApiErrorCode::UsernameWrong => "108001",
536 ApiErrorCode::PasswordWrong => "108002",
537 ApiErrorCode::AlreadyLoggedIn => "108003",
538 ApiErrorCode::UsernameOrPasswordWrong => "108006",
539 ApiErrorCode::TooManyLoginAttempts => "108007",
540 ApiErrorCode::PasswordChangeRequired => "115002",
541 ApiErrorCode::SystemUnknown => "100001",
542 ApiErrorCode::SystemNoSupport => "100002",
543 ApiErrorCode::NoRights => "100003",
544 ApiErrorCode::SystemBusy => "100004",
545 ApiErrorCode::FormatError => "100005",
546 ApiErrorCode::Unknown(code) => code.as_str(),
547 };
548 serializer.serialize_str(value)
549 }
550}
551
552impl<'de> Deserialize<'de> for ApiErrorCode {
553 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
554 where
555 D: serde::Deserializer<'de>,
556 {
557 let value = String::deserialize(deserializer)?;
558 match value.as_str() {
559 "125001" => Ok(ApiErrorCode::WrongToken),
560 "125002" => Ok(ApiErrorCode::CsrfTokenInvalid),
561 "125003" => Ok(ApiErrorCode::WrongSessionToken),
562 "108001" => Ok(ApiErrorCode::UsernameWrong),
563 "108002" => Ok(ApiErrorCode::PasswordWrong),
564 "108003" => Ok(ApiErrorCode::AlreadyLoggedIn),
565 "108006" => Ok(ApiErrorCode::UsernameOrPasswordWrong),
566 "108007" => Ok(ApiErrorCode::TooManyLoginAttempts),
567 "115002" => Ok(ApiErrorCode::PasswordChangeRequired),
568 "100001" => Ok(ApiErrorCode::SystemUnknown),
569 "100002" => Ok(ApiErrorCode::SystemNoSupport),
570 "100003" => Ok(ApiErrorCode::NoRights),
571 "100004" => Ok(ApiErrorCode::SystemBusy),
572 "100005" => Ok(ApiErrorCode::FormatError),
573 _ => Ok(ApiErrorCode::Unknown(value)),
574 }
575 }
576}
577
578impl fmt::Display for ApiErrorCode {
579 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
580 let text = match self {
581 ApiErrorCode::WrongToken => "Wrong token",
582 ApiErrorCode::CsrfTokenInvalid => "CSRF token invalid",
583 ApiErrorCode::WrongSessionToken => "Wrong session token",
584 ApiErrorCode::UsernameWrong => "Username wrong",
585 ApiErrorCode::PasswordWrong => "Password wrong",
586 ApiErrorCode::AlreadyLoggedIn => "Already logged in",
587 ApiErrorCode::UsernameOrPasswordWrong => "Username or password wrong",
588 ApiErrorCode::TooManyLoginAttempts => "Too many login attempts",
589 ApiErrorCode::PasswordChangeRequired => "Password change required",
590 ApiErrorCode::SystemUnknown => "System unknown error",
591 ApiErrorCode::SystemNoSupport => "System does not support this operation",
592 ApiErrorCode::NoRights => "No rights (login required)",
593 ApiErrorCode::SystemBusy => "System busy",
594 ApiErrorCode::FormatError => "Format error",
595 ApiErrorCode::Unknown(code) => return write!(f, "Unknown error (code: {code})"),
596 };
597 write!(f, "{text}")
598 }
599}
600
601impl ApiErrorCode {
602 pub fn is_csrf_error(&self) -> bool {
604 matches!(
605 self,
606 ApiErrorCode::CsrfTokenInvalid | ApiErrorCode::WrongToken
607 )
608 }
609
610 pub fn is_session_error(&self) -> bool {
612 matches!(self, ApiErrorCode::WrongSessionToken)
613 }
614
615 pub fn is_auth_error(&self) -> bool {
617 matches!(
618 self,
619 ApiErrorCode::UsernameWrong
620 | ApiErrorCode::PasswordWrong
621 | ApiErrorCode::UsernameOrPasswordWrong
622 | ApiErrorCode::TooManyLoginAttempts
623 | ApiErrorCode::PasswordChangeRequired
624 )
625 }
626
627 pub fn as_int(&self) -> i32 {
629 match self {
630 ApiErrorCode::WrongToken => 125001,
631 ApiErrorCode::CsrfTokenInvalid => 125002,
632 ApiErrorCode::WrongSessionToken => 125003,
633 ApiErrorCode::UsernameWrong => 108001,
634 ApiErrorCode::PasswordWrong => 108002,
635 ApiErrorCode::AlreadyLoggedIn => 108003,
636 ApiErrorCode::UsernameOrPasswordWrong => 108006,
637 ApiErrorCode::TooManyLoginAttempts => 108007,
638 ApiErrorCode::PasswordChangeRequired => 115002,
639 ApiErrorCode::SystemUnknown => 100001,
640 ApiErrorCode::SystemNoSupport => 100002,
641 ApiErrorCode::NoRights => 100003,
642 ApiErrorCode::SystemBusy => 100004,
643 ApiErrorCode::FormatError => 100005,
644 ApiErrorCode::Unknown(code) => code.parse().unwrap_or(-1),
645 }
646 }
647}
648
649#[cfg(test)]
650mod tests {
651 use super::*;
652
653 #[test]
654 fn test_connection_status_display() {
655 assert_eq!(ConnectionStatus::Connected.to_string(), "CONNECTED");
656 assert_eq!(ConnectionStatus::Connecting.to_string(), "CONNECTING");
657 assert_eq!(ConnectionStatus::Disconnected.to_string(), "DISCONNECTED");
658 }
659
660 #[test]
661 fn test_connection_status_methods() {
662 assert!(ConnectionStatus::Connected.is_connected());
663 assert!(!ConnectionStatus::Connecting.is_connected());
664
665 assert!(ConnectionStatus::Connecting.is_connecting());
666 assert!(!ConnectionStatus::Connected.is_connecting());
667
668 assert!(ConnectionStatus::Disconnected.is_disconnected());
669 assert!(!ConnectionStatus::Connected.is_disconnected());
670
671 assert!(ConnectionStatus::ConnectFailed.is_failed());
672 assert!(!ConnectionStatus::Connected.is_failed());
673 }
674
675 #[test]
676 fn test_network_type_display() {
677 assert_eq!(NetworkType::Lte.to_string(), "LTE (4G)");
678 assert_eq!(NetworkType::FiveGNsa.to_string(), "5G NSA");
679 assert_eq!(NetworkType::Hspa.to_string(), "HSPA (3G)");
680 }
681
682 #[test]
683 fn test_network_type_methods() {
684 assert!(NetworkType::FiveGNsa.is_5g());
685 assert!(!NetworkType::Lte.is_5g());
686
687 assert!(NetworkType::Lte.is_4g());
688 assert!(!NetworkType::Hspa.is_4g());
689
690 assert!(NetworkType::Hspa.is_3g());
691 assert!(!NetworkType::Lte.is_3g());
692 }
693
694 #[test]
695 fn test_network_mode_type_display() {
696 assert_eq!(NetworkModeType::Auto.to_string(), "Auto (2G/3G/4G)");
697 assert_eq!(NetworkModeType::FourGOnly.to_string(), "4G Only (LTE)");
698 }
699
700 #[test]
701 fn test_status_methods() {
702 assert!(SimStatus::Ready.is_ready());
703 assert!(!SimStatus::NotReady.is_ready());
704
705 assert!(RoamingStatus::Roaming.is_roaming());
706 assert!(!RoamingStatus::NotRoaming.is_roaming());
707
708 assert!(ServiceStatus::FullService.is_available());
709 assert!(ServiceStatus::FullService.is_full_service());
710 assert!(!ServiceStatus::NoService.is_available());
711 }
712
713 #[test]
714 fn test_sms_status_methods() {
715 assert!(SmsStatus::Unread.is_unread());
716 assert!(!SmsStatus::Read.is_unread());
717
718 assert!(SmsStatus::Read.is_read());
719 assert!(!SmsStatus::Unread.is_read());
720
721 assert!(SmsStatus::Sent.is_sent());
722 assert!(!SmsStatus::Unread.is_sent());
723 }
724
725 #[test]
726 fn test_api_error_code_methods() {
727 assert!(ApiErrorCode::CsrfTokenInvalid.is_csrf_error());
728 assert!(!ApiErrorCode::UsernameWrong.is_csrf_error());
729
730 assert!(ApiErrorCode::WrongSessionToken.is_session_error());
731 assert!(!ApiErrorCode::CsrfTokenInvalid.is_session_error());
732
733 assert!(ApiErrorCode::UsernameWrong.is_auth_error());
734 assert!(!ApiErrorCode::CsrfTokenInvalid.is_auth_error());
735 }
736}