1use std::fmt;
11use std::str::FromStr;
12use num::FromPrimitive;
13use std::convert::{Infallible, TryFrom};
14use crate::errors::*;
15use crate::gsm_encoding::{GsmMessageData, gsm_decode_string, decode_sms_7bit};
16
17#[repr(u8)]
20#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, FromPrimitive, Hash)]
21pub enum TypeOfNumber {
22 Unknown = 0b0_000_0000,
24 International = 0b0_001_0000,
26 National = 0b0_010_0000,
28 Special = 0b0_011_0000,
30 Gsm = 0b0_101_0000,
35 Short = 0b0_110_0000,
37 Reserved = 0b0_111_0000
39}
40#[repr(u8)]
44#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, FromPrimitive, Hash)]
45pub enum NumberingPlanIdentification {
46 NetworkDetermined = 0b0_000_0000,
47 IsdnTelephone = 0b0_000_0001,
48 Data = 0b0_000_0011,
49 Telex = 0b0_000_0100,
50 National = 0b0_000_1000,
51 Private = 0b0_000_1001,
52 Ermes = 0b0_000_1010
53}
54#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
60pub struct AddressType {
61 pub type_of_number: TypeOfNumber,
62 pub numbering_plan_identification: NumberingPlanIdentification
63}
64impl Default for AddressType {
65 fn default() -> Self {
66 AddressType {
67 type_of_number: TypeOfNumber::International,
68 numbering_plan_identification: NumberingPlanIdentification::IsdnTelephone
69 }
70 }
71}
72impl TryFrom<u8> for AddressType {
73 type Error = HuaweiError;
74 fn try_from(b: u8) -> HuaweiResult<Self> {
75 let ton = b & 0b0_111_0000;
76 let ton = TypeOfNumber::from_u8(ton)
77 .ok_or(HuaweiError::InvalidPdu("invalid type_of_number"))?;
78 let npi = b & 0b0_000_1111;
79 let npi = NumberingPlanIdentification::from_u8(npi)
80 .ok_or(HuaweiError::InvalidPdu("invalid numbering_plan_identification"))?;
81 Ok(Self {
82 type_of_number: ton,
83 numbering_plan_identification: npi
84 })
85 }
86}
87impl Into<u8> for AddressType {
88 fn into(self) -> u8 {
89 let mut ret: u8 = 0b1_000_0000;
90 ret |= self.type_of_number as u8;
91 ret |= self.numbering_plan_identification as u8;
92 ret
93 }
94}
95#[derive(Debug, Clone, PartialEq, Eq, Hash)]
97pub struct PhoneNumber(pub Vec<u8>);
98impl<'a> From<&'a [u8]> for PhoneNumber {
103 fn from(b: &[u8]) -> Self {
104 let mut ret = vec![];
105 for b in b.iter() {
106 let first = b & 0b0000_1111;
107 let second = (b & 0b1111_0000) >> 4;
108 ret.push(first);
109 if second != 0b0000_1111 {
110 ret.push(second);
111 }
112 }
113 PhoneNumber(ret)
114 }
115}
116impl PhoneNumber {
117 pub fn from_gsm(b: &[u8], len: usize) -> Self {
119 PhoneNumber(decode_sms_7bit(b, 0, len))
120 }
121 pub fn as_bytes(&self) -> Vec<u8> {
123 let mut ret = vec![];
124 let mut cur = 0b0000_0000;
125 for (i, b) in self.0.iter().enumerate() {
126 let mut b = *b;
127 if i % 2 == 0 {
128 cur |= b;
129 }
130 else {
131 b = b << 4;
132 cur |= b;
133 ret.push(cur);
134 cur = 0b0000_0000;
135 }
136 }
137 if self.0.len() % 2 != 0 {
138 cur |= 0b1111_0000;
139 ret.push(cur);
140 }
141 ret
142 }
143}
144#[derive(Debug, Clone, PartialEq, Eq, Hash)]
151pub struct PduAddress {
152 pub type_addr: AddressType,
153 pub number: PhoneNumber
154}
155impl fmt::Display for PduAddress {
156 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
157
158 let prefix = match self.type_addr.type_of_number {
159 TypeOfNumber::International => "+",
160 _ => ""
161 };
162 write!(f, "{}", prefix)?;
163 if self.type_addr.type_of_number == TypeOfNumber::Gsm {
164 write!(f, "{}", gsm_decode_string(&self.number.0))?;
165 }
166 else {
167 for b in self.number.0.iter() {
168 write!(f, "{}", b)?;
169 }
170 }
171 Ok(())
172 }
173}
174impl FromStr for PduAddress {
175 type Err = Infallible;
176 fn from_str(st: &str) -> Result<Self, Infallible> {
177 let mut int = false;
178 let buf = st.chars()
179 .filter_map(|x| {
180 match x {
181 '0'...'9' => Some(x as u8 - 48),
182 '+' => {
183 int = true;
184 None
185 },
186 _ => None
187 }
188 }).collect::<Vec<_>>();
189 let ton = if int {
190 TypeOfNumber::International
191 }
192 else {
193 TypeOfNumber::Unknown
194 };
195 Ok(PduAddress {
196 type_addr: AddressType {
197 type_of_number: ton,
198 numbering_plan_identification: NumberingPlanIdentification::IsdnTelephone
199 },
200 number: PhoneNumber(buf)
201 })
202 }
203}
204impl<'a> TryFrom<&'a [u8]> for PduAddress {
205 type Error = HuaweiError;
206 fn try_from(b: &[u8]) -> HuaweiResult<Self> {
207 if b.len() < 3 {
208 Err(HuaweiError::InvalidPdu("tried to make a PduAddress from less than 3 bytes"))?
209 }
210 let len = b[0] as usize;
211 let type_addr = AddressType::try_from(b[1])?;
212 let number = if type_addr.type_of_number == TypeOfNumber::Gsm {
213 let len = (len * 4) / 7;
214 PhoneNumber::from_gsm(&b[2..], len)
215 }
216 else {
217 PhoneNumber::from(&b[2..])
218 };
219 Ok(PduAddress { type_addr, number })
220 }
221}
222impl PduAddress {
223 pub fn as_bytes(&self, broken_len: bool) -> Vec<u8> {
231 let mut ret = vec![];
232 ret.push(self.type_addr.into());
233 ret.extend(self.number.as_bytes());
234 let len = if broken_len {
235 self.number.0.len()
236 } else {
237 ret.len()
238 };
239 ret.insert(0, len as u8);
240 ret
241 }
242}
243#[repr(u8)]
245#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, FromPrimitive)]
246pub enum MessageType {
247 SmsDeliver = 0b000000_00,
249 SmsCommand = 0b000000_10,
251 SmsSubmit = 0b000000_01,
253 Reserved = 0b000000_11
255}
256#[repr(u8)]
258#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, FromPrimitive)]
259pub enum VpFieldValidity {
260 Invalid = 0b0000_00_00,
262 Relative = 0b0000_10_00,
264 Enhanced = 0b0000_01_00,
266 Absolute = 0b0000_11_00,
268}
269#[derive(Debug, Copy, Clone, PartialEq, Eq)]
271pub struct PduFirstOctet {
272 mti: MessageType,
274 rd: bool,
276 vpf: VpFieldValidity,
278 srr: bool,
280 udhi: bool,
282 rp: bool
284}
285impl From<u8> for PduFirstOctet {
286 fn from(b: u8) -> Self {
287 let rd = (b & 0b00000100) > 0;
288 let srr = (b & 0b00100000) > 0;
289 let udhi = (b & 0b01000000) > 0;
290 let rp = (b & 0b10000000) > 0;
291 let mti = MessageType::from_u8(b & 0b000000_11)
292 .expect("MessageType conversions should be exhaustive!");
293 let vpf = VpFieldValidity::from_u8(b & 0b0000_11_00)
294 .expect("VpFieldValidity conversions should be exhaustive!");
295 PduFirstOctet { rd, srr, udhi, rp, mti, vpf }
296 }
297}
298impl Into<u8> for PduFirstOctet {
299 fn into(self) -> u8 {
300 let mut ret = 0b0000_0000;
301 ret |= self.mti as u8;
302 ret |= self.vpf as u8;
303 if self.rd {
304 ret |= 0b00000100;
305 }
306 if self.srr {
307 ret |= 0b00100000;
308 }
309 if self.udhi {
310 ret |= 0b01000000;
311 }
312 if self.rp {
313 ret |= 0b10000000;
314 }
315 ret
316 }
317}
318#[derive(Debug, Copy, Clone, PartialEq, Eq)]
327pub enum DataCodingScheme {
328 Standard {
330 compressed: bool,
332 class: MessageClass,
334 encoding: MessageEncoding
336 },
337 Reserved,
339 MessageWaitingDiscard {
341 waiting: bool,
343 type_indication: MessageWaitingType,
345 },
346 MessageWaiting {
348 waiting: bool,
350 type_indication: MessageWaitingType,
352 ucs2: bool
354 }
355}
356impl DataCodingScheme {
357 pub fn encoding(&self) -> MessageEncoding {
361 use self::DataCodingScheme::*;
362 match *self {
363 Standard { encoding, .. } => encoding,
364 Reserved => MessageEncoding::Gsm7Bit,
365 MessageWaitingDiscard { .. } => MessageEncoding::Gsm7Bit,
366 MessageWaiting { ucs2, .. } => if ucs2 {
367 MessageEncoding::Ucs2
368 }
369 else {
370 MessageEncoding::Gsm7Bit
371 }
372 }
373 }
374}
375impl From<u8> for DataCodingScheme {
376 fn from(b: u8) -> Self {
377 if (b & 0b1100_0000) == 0b0000_0000 {
378 let compressed = (b & 0b0010_0000) > 0;
379 let reserved = (b & 0b0001_0000) > 0;
380 let class = if reserved {
381 MessageClass::StoreToNv
384 }
385 else {
386 MessageClass::from_u8(b & 0b0000_0011)
387 .expect("MessageClass conversions should be exhaustive!")
388 };
389 let encoding = MessageEncoding::from_u8(b & 0b0000_1100)
390 .expect("MessageEncoding conversions should be exhaustive!");
391 DataCodingScheme::Standard { compressed, class, encoding }
392 }
393 else if (b & 0b1111_0000) == 0b1111_0000 {
394 let compressed = false;
395 let class = MessageClass::from_u8(b & 0b0000_0011)
396 .expect("MessageClass conversions should be exhaustive!");
397 let encoding = if (b & 0b0000_0100) > 0 {
398 MessageEncoding::Gsm7Bit
399 }
400 else {
401 MessageEncoding::EightBit
402 };
403 DataCodingScheme::Standard { compressed, class, encoding }
404 }
405 else if (b & 0b1111_0000) == 0b1100_0000 {
406 let waiting = (b & 0b0000_1000) > 0;
407 let type_indication = MessageWaitingType::from_u8(b & 0b0000_0011)
408 .expect("MessageWaitingType conversions should be exhaustive!");
409 DataCodingScheme::MessageWaitingDiscard { waiting, type_indication }
410 }
411 else if (b & 0b1111_0000) == 0b1101_0000 || (b & 0b1111_0000) == 0b1110_0000 {
412 let ucs2 = (b & 0b1111_0000) == 0b1110_0000;
413 let waiting = (b & 0b0000_1000) > 0;
414 let type_indication = MessageWaitingType::from_u8(b & 0b0000_0011)
415 .expect("MessageWaitingType conversions should be exhaustive!");
416 DataCodingScheme::MessageWaiting { ucs2, waiting, type_indication }
417 }
418 else {
419 DataCodingScheme::Reserved
420 }
421 }
422}
423impl Into<u8> for DataCodingScheme {
424 fn into(self) -> u8 {
425 use self::DataCodingScheme::*;
426 match self {
427 Standard { compressed, class, encoding } => {
428 let mut ret = 0b0001_0000;
429 if compressed {
430 ret |= 0b0010_0000;
431 }
432 ret |= class as u8;
433 ret |= encoding as u8;
434 ret
435 },
436 Reserved => 0b0100_0101,
437 MessageWaiting { waiting, type_indication, ucs2 } => {
438 let mut ret = if ucs2 {
439 0b1110_0000
440 }
441 else {
442 0b1101_0000
443 };
444 if waiting {
445 ret |= 0b0000_1000;
446 }
447 ret |= type_indication as u8;
448 ret
449 },
450 MessageWaitingDiscard { waiting, type_indication } => {
451 let mut ret = 0b1100_0000;
452 if waiting {
453 ret |= 0b0000_1000;
454 }
455 ret |= type_indication as u8;
456 ret
457 }
458 }
459 }
460}
461#[repr(u8)]
463#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, FromPrimitive)]
464pub enum MessageWaitingType {
465 Voice = 0b000000_00,
466 Fax = 0b000000_01,
467 Email = 0b000000_10,
468 Unknown = 0b000000_11
469}
470#[repr(u8)]
472#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, FromPrimitive)]
473pub enum MessageClass {
474 Silent = 0b000000_00,
476 StoreToNv = 0b000000_01,
478 StoreToSim = 0b000000_10,
480 StoreToTe = 0b000000_11
482}
483#[repr(u8)]
485#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, FromPrimitive)]
486pub enum MessageEncoding {
487 Gsm7Bit = 0b0000_00_00,
489 EightBit = 0b0000_01_00,
491 Ucs2 = 0b0000_10_00,
493 Reserved = 0b0000_11_00,
495}
496#[derive(Debug, Clone, PartialEq, Eq)]
498pub struct DeliverPduFirstOctet {
499 mti: MessageType,
501 sri: bool,
503 udhi: bool,
505 rp: bool
507}
508impl From<u8> for DeliverPduFirstOctet {
509 fn from(b: u8) -> Self {
510 let mti = MessageType::from_u8(b & 0b000000_11)
511 .expect("MessageType conversions should be exhaustive!");
512 let sri = (b & 0b00100000) > 0;
513 let udhi = (b & 0b01000000) > 0;
514 let rp = (b & 0b01000000) > 0;
515 DeliverPduFirstOctet { mti, sri, udhi, rp }
516 }
517}
518#[derive(Debug, Clone, PartialEq, Eq)]
520pub struct SmscTimestamp {
521 year: u8,
522 month: u8,
523 day: u8,
524 hour: u8,
525 minute: u8,
526 second: u8,
527 timezone: u8
529}
530pub(crate) fn reverse_byte(b: u8) -> u8 {
531 let units = b >> 4;
532 let tens = b & 0b0000_1111;
533 (tens * 10) + units
534}
535impl<'a> TryFrom<&'a [u8]> for SmscTimestamp {
536 type Error = HuaweiError;
537 fn try_from(b: &[u8]) -> HuaweiResult<Self> {
538 if b.len() != 7 {
539 Err(HuaweiError::InvalidPdu("SmscTimestamp must be 7 bytes long"))?
540 }
541 Ok(SmscTimestamp {
542 year: reverse_byte(b[0]),
543 month: reverse_byte(b[1]),
544 day: reverse_byte(b[2]),
545 hour: reverse_byte(b[3]),
546 minute: reverse_byte(b[4]),
547 second: reverse_byte(b[5]),
548 timezone: reverse_byte(b[6]),
549 })
550 }
551}
552#[derive(Debug, Clone, PartialEq, Eq)]
557pub struct DeliverPdu {
558 pub sca: Option<PduAddress>,
560 pub first_octet: DeliverPduFirstOctet,
562 pub originating_address: PduAddress,
564 pub dcs: DataCodingScheme,
566 pub scts: SmscTimestamp,
568 pub user_data: Vec<u8>,
570 pub user_data_len: u8
572}
573impl DeliverPdu {
574 pub fn get_message_data(&self) -> GsmMessageData {
578 GsmMessageData {
579 bytes: self.user_data.clone(),
580 user_data_len: self.user_data_len,
581 encoding: self.dcs.encoding(),
582 udh: self.first_octet.udhi
583 }
584 }
585}
586impl<'a> TryFrom<&'a [u8]> for DeliverPdu {
587 type Error = HuaweiError;
588 fn try_from(b: &[u8]) -> HuaweiResult<Self> {
589 if b.len() == 0 {
590 return Err(HuaweiError::InvalidPdu("zero-length input"));
591 }
592 let scalen = b[0];
593 let mut offset: usize = scalen as usize + 1;
594 let sca = if scalen > 0 {
595 let o = offset - 1;
596 check_offset!(b, o, "SCA");
597 Some(PduAddress::try_from(&b[0..offset])?)
598 }
599 else {
600 None
601 };
602 check_offset!(b, offset, "first octet");
603 let first_octet = DeliverPduFirstOctet::from(b[offset]);
604 offset += 1;
605 check_offset!(b, offset, "originating address len");
606 let destination_len_nybbles = b[offset];
607 let destination_len_octets = (destination_len_nybbles / 2) + destination_len_nybbles % 2;
610 let destination_offset = (destination_len_octets as usize) + 2;
614 let destination_end = offset + destination_offset;
615 let de = destination_end - 1;
616 check_offset!(b, de, "originating address");
617 let originating_address = PduAddress::try_from(&b[offset..destination_end])?;
618 offset += destination_offset;
619 check_offset!(b, offset, "protocol identifier");
620 let _pid = b[offset];
621 offset += 1;
622 check_offset!(b, offset, "data coding scheme");
623 let dcs = DataCodingScheme::from(b[offset]);
624 offset += 1;
625 let scts_end = offset + 7;
626 let ss = offset + 6;
627 check_offset!(b, ss, "service center timestamp");
628 let scts = SmscTimestamp::try_from(&b[offset..scts_end])?;
629 offset += 7;
630 check_offset!(b, offset, "user data len");
631 let user_data_len = b[offset];
632 offset += 1;
633 let user_data = if b.get(offset).is_some() {
634 b[offset..].to_owned()
635 }
636 else {
637 vec![]
638 };
639 Ok(DeliverPdu {
640 sca,
641 first_octet,
642 originating_address,
643 dcs,
644 scts,
645 user_data,
646 user_data_len
647 })
648
649 }
650}
651#[derive(Debug, Clone, PartialEq, Eq)]
656pub struct Pdu {
657 pub sca: Option<PduAddress>,
663 pub first_octet: PduFirstOctet,
665 pub message_id: u8,
670 pub destination: PduAddress,
672 pub dcs: DataCodingScheme,
674 pub validity_period: u8,
678 pub user_data: Vec<u8>,
680 pub user_data_len: u8
682}
683impl Pdu {
684 pub fn set_sca(&mut self, sca: PduAddress) {
686 self.sca = Some(sca);
687 }
688 pub fn make_simple_message(recipient: PduAddress, msg: GsmMessageData) -> Self {
691 Pdu {
692 sca: None,
693 first_octet: PduFirstOctet {
694 mti: MessageType::SmsSubmit,
695 rd: false,
696 vpf: VpFieldValidity::Invalid,
697 rp: false,
698 udhi: msg.udh,
699 srr: false
700 },
701 message_id: 0,
702 destination: recipient,
703 dcs: DataCodingScheme::Standard {
704 compressed: false,
705 class: MessageClass::StoreToNv,
706 encoding: msg.encoding
707 },
708 validity_period: 0,
709 user_data: msg.bytes,
710 user_data_len: msg.user_data_len as u8
711 }
712 }
713}
714impl Pdu {
715 pub fn as_bytes(&self) -> (Vec<u8>, usize) {
717 let mut ret = vec![];
718 let mut scalen = 1;
719 if let Some(ref sca) = self.sca {
720 let sca = sca.as_bytes(false);
721 scalen = sca.len();
722 ret.extend(sca);
723 }
724 else {
725 ret.push(0);
726 }
727 ret.push(self.first_octet.into());
728 ret.push(self.message_id);
729 ret.extend(self.destination.as_bytes(true));
730 ret.push(0);
731 ret.push(self.dcs.into());
732 if self.first_octet.vpf != VpFieldValidity::Invalid {
733 ret.push(self.validity_period);
734 }
735 ret.push(self.user_data_len);
736 ret.extend(self.user_data.clone());
737 let tpdu_len = ret.len() - scalen;
738 (ret, tpdu_len)
739 }
740}
741pub(crate) struct HexData<'a>(pub &'a [u8]);
742impl<'a> fmt::Display for HexData<'a> {
743 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
744 for b in self.0.iter() {
745 write!(f, "{:02X}", b)?;
746 }
747 Ok(())
748 }
749}
750impl<'a> HexData<'a> {
751 pub fn decode(data: &str) -> HuaweiResult<Vec<u8>> {
752 data.as_bytes()
753 .chunks(2)
754 .map(::std::str::from_utf8)
755 .map(|x| {
756 match x {
757 Ok(x) => u8::from_str_radix(x, 16)
758 .map_err(|_| HuaweiError::InvalidPdu("invalid hex string")),
759 Err(_) => Err(HuaweiError::InvalidPdu("invalid hex string"))
760 }
761 })
762 .collect()
763 }
764}