sms_pdu.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944
  1. package device
  2. import (
  3. "crypto/rand"
  4. "encoding/hex"
  5. "errors"
  6. "fmt"
  7. "strconv"
  8. "strings"
  9. "time"
  10. "unicode/utf16"
  11. )
  12. var gsm7DefaultAlphabet = [128]rune{
  13. '@', '£', '$', '¥', 'è', 'é', 'ù', 'ì',
  14. 'ò', 'Ç', '\n', 'Ø', 'ø', '\r', 'Å', 'å',
  15. 'Δ', '_', 'Φ', 'Γ', 'Λ', 'Ω', 'Π', 'Ψ',
  16. 'Σ', 'Θ', 'Ξ', '\x1b', 'Æ', 'æ', 'ß', 'É',
  17. ' ', '!', '"', '#', '¤', '%', '&', '\'',
  18. '(', ')', '*', '+', ',', '-', '.', '/',
  19. '0', '1', '2', '3', '4', '5', '6', '7',
  20. '8', '9', ':', ';', '<', '=', '>', '?',
  21. '¡', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
  22. 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
  23. 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
  24. 'X', 'Y', 'Z', 'Ä', 'Ö', 'Ñ', 'Ü', '§',
  25. '¿', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
  26. 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
  27. 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
  28. 'x', 'y', 'z', 'ä', 'ö', 'ñ', 'ü', 'à',
  29. }
  30. var gsm7ExtensionAlphabet = map[byte]rune{
  31. 0x0a: '\f',
  32. 0x14: '^',
  33. 0x28: '{',
  34. 0x29: '}',
  35. 0x2f: '\\',
  36. 0x3c: '[',
  37. 0x3d: '~',
  38. 0x3e: ']',
  39. 0x40: '|',
  40. 0x65: '€',
  41. }
  42. var gsm7Encoder = func() map[rune][]byte {
  43. result := make(map[rune][]byte, len(gsm7DefaultAlphabet)+len(gsm7ExtensionAlphabet))
  44. for code, character := range gsm7DefaultAlphabet {
  45. if code == 0x1b {
  46. continue
  47. }
  48. result[character] = []byte{byte(code)}
  49. }
  50. for code, character := range gsm7ExtensionAlphabet {
  51. result[character] = []byte{0x1b, code}
  52. }
  53. return result
  54. }()
  55. type preparedSMS struct {
  56. to string
  57. encoding SMSEncoding
  58. payload []byte
  59. prompt string
  60. setup []string
  61. tpduLength int
  62. part int
  63. total int
  64. concatReference *int
  65. }
  66. // PrepareSMSSubmitTPDUs applies the same recipient validation, alphabet
  67. // selection and concatenation rules as SendSMS, but returns raw SMS-SUBMIT
  68. // TPDUs suitable for a non-AT transport such as 3GPP SMS over IMS.
  69. func PrepareSMSSubmitTPDUs(recipient, text string) ([]SMSSubmitTPDU, error) {
  70. parts, err := prepareSMSParts(recipient, text)
  71. if err != nil {
  72. return nil, err
  73. }
  74. result := make([]SMSSubmitTPDU, 0, len(parts))
  75. for _, part := range parts {
  76. pduHex := string(part.payload)
  77. encoding := part.encoding
  78. if part.encoding == SMSEncodingGSM7Text {
  79. septets, ok := encodeGSM7(text)
  80. if !ok {
  81. return nil, errors.New("SMS text could not be encoded as GSM-7")
  82. }
  83. pduHex, _, err = encodeSubmitPDU(part.to, septets, nil)
  84. if err != nil {
  85. return nil, err
  86. }
  87. encoding = SMSEncodingGSM7PDU
  88. }
  89. pdu, err := hex.DecodeString(pduHex)
  90. if err != nil || len(pdu) < 2 {
  91. return nil, errors.New("encoded SMS PDU is invalid")
  92. }
  93. smscBytes := int(pdu[0])
  94. if 1+smscBytes >= len(pdu) {
  95. return nil, errors.New("encoded SMS PDU has no TPDU")
  96. }
  97. result = append(result, SMSSubmitTPDU{
  98. To: part.to,
  99. Encoding: encoding,
  100. TPDU: append([]byte(nil), pdu[1+smscBytes:]...),
  101. Part: part.part,
  102. Total: part.total,
  103. ConcatReference: part.concatReference,
  104. })
  105. }
  106. return result, nil
  107. }
  108. // DecodeSMSDeliverTPDU decodes a TPDU carried by RP-DATA. The existing modem
  109. // decoder expects the AT PDU-mode SMSC prefix, so an empty SMSC is prepended.
  110. func DecodeSMSDeliverTPDU(tpdu []byte) (SMSMessage, error) {
  111. if len(tpdu) == 0 {
  112. return SMSMessage{}, errors.New("SMS TPDU is empty")
  113. }
  114. pdu := make([]byte, 1, len(tpdu)+1)
  115. pdu = append(pdu, tpdu...)
  116. return decodeSMSPDU(hex.EncodeToString(pdu))
  117. }
  118. func prepareSMS(recipient, text string) (preparedSMS, error) {
  119. parts, err := prepareSMSPartsWithReference(recipient, text, 0)
  120. if err != nil {
  121. return preparedSMS{}, err
  122. }
  123. if len(parts) != 1 {
  124. return preparedSMS{}, fmt.Errorf(
  125. "%w: message requires %d parts",
  126. ErrSMSTooLong,
  127. len(parts),
  128. )
  129. }
  130. return parts[0], nil
  131. }
  132. func prepareSMSParts(recipient, text string) ([]preparedSMS, error) {
  133. parts, err := prepareSMSPartsWithReference(recipient, text, 0)
  134. if err != nil || len(parts) <= 1 {
  135. return parts, err
  136. }
  137. var reference [1]byte
  138. if _, err := rand.Read(reference[:]); err != nil {
  139. return nil, fmt.Errorf("generate SMS concatenation reference: %w", err)
  140. }
  141. return prepareSMSPartsWithReference(recipient, text, reference[0])
  142. }
  143. func prepareSMSPartsWithReference(
  144. recipient string,
  145. text string,
  146. reference byte,
  147. ) ([]preparedSMS, error) {
  148. recipient, err := normalizeSMSRecipient(recipient)
  149. if err != nil {
  150. return nil, err
  151. }
  152. if text == "" {
  153. return nil, ErrSMSEmpty
  154. }
  155. if strings.IndexByte(text, 0) >= 0 {
  156. return nil, errors.New("SMS text contains NUL")
  157. }
  158. septets, gsm7 := encodeGSM7(text)
  159. if gsm7 && len(septets) <= 160 && canSendDirectGSM7(text) {
  160. return []preparedSMS{{
  161. to: recipient,
  162. encoding: SMSEncodingGSM7Text,
  163. payload: []byte(text),
  164. prompt: fmt.Sprintf(`AT+CMGS="%s"`, recipient),
  165. setup: []string{
  166. "AT+CMGF=1",
  167. `AT+CSCS="GSM"`,
  168. // TP-SRR requests a network delivery status report.
  169. "AT+CSMP=49,167,0,0",
  170. },
  171. part: 1,
  172. total: 1,
  173. }}, nil
  174. }
  175. if gsm7 && len(septets) <= 160 {
  176. pdu, tpduLength, err := encodeSubmitPDU(recipient, septets, nil)
  177. if err != nil {
  178. return nil, err
  179. }
  180. return []preparedSMS{{
  181. to: recipient,
  182. encoding: SMSEncodingGSM7PDU,
  183. payload: []byte(pdu),
  184. prompt: fmt.Sprintf("AT+CMGS=%d", tpduLength),
  185. setup: []string{"AT+CMGF=0"},
  186. tpduLength: tpduLength,
  187. part: 1,
  188. total: 1,
  189. }}, nil
  190. }
  191. if gsm7 {
  192. segments := splitGSM7(septets, 153)
  193. if len(segments) > 255 {
  194. return nil, fmt.Errorf(
  195. "%w: GSM-7 requires %d concatenated parts; maximum is 255",
  196. ErrSMSTooLong,
  197. len(segments),
  198. )
  199. }
  200. referenceValue := int(reference)
  201. result := make([]preparedSMS, 0, len(segments))
  202. for index, segment := range segments {
  203. header := concatUDH(reference, len(segments), index+1)
  204. pdu, tpduLength, encodeErr := encodeSubmitPDUWithHeader(
  205. recipient,
  206. segment,
  207. nil,
  208. header,
  209. )
  210. if encodeErr != nil {
  211. return nil, encodeErr
  212. }
  213. result = append(result, preparedSMS{
  214. to: recipient,
  215. encoding: SMSEncodingGSM7PDU,
  216. payload: []byte(pdu),
  217. prompt: fmt.Sprintf("AT+CMGS=%d", tpduLength),
  218. setup: []string{"AT+CMGF=0"},
  219. tpduLength: tpduLength,
  220. part: index + 1,
  221. total: len(segments),
  222. concatReference: &referenceValue,
  223. })
  224. }
  225. return result, nil
  226. }
  227. units := utf16.Encode([]rune(text))
  228. if len(units) <= 70 {
  229. ucs2 := encodeUCS2Units(units)
  230. pdu, tpduLength, err := encodeSubmitPDU(recipient, nil, ucs2)
  231. if err != nil {
  232. return nil, err
  233. }
  234. return []preparedSMS{{
  235. to: recipient,
  236. encoding: SMSEncodingUCS2PDU,
  237. payload: []byte(pdu),
  238. prompt: fmt.Sprintf("AT+CMGS=%d", tpduLength),
  239. setup: []string{"AT+CMGF=0"},
  240. tpduLength: tpduLength,
  241. part: 1,
  242. total: 1,
  243. }}, nil
  244. }
  245. segments := splitUCS2(units, 67)
  246. if len(segments) > 255 {
  247. return nil, fmt.Errorf(
  248. "%w: UCS2 requires %d concatenated parts; maximum is 255",
  249. ErrSMSTooLong,
  250. len(segments),
  251. )
  252. }
  253. referenceValue := int(reference)
  254. result := make([]preparedSMS, 0, len(segments))
  255. for index, segment := range segments {
  256. header := concatUDH(reference, len(segments), index+1)
  257. pdu, tpduLength, encodeErr := encodeSubmitPDUWithHeader(
  258. recipient,
  259. nil,
  260. encodeUCS2Units(segment),
  261. header,
  262. )
  263. if encodeErr != nil {
  264. return nil, encodeErr
  265. }
  266. result = append(result, preparedSMS{
  267. to: recipient,
  268. encoding: SMSEncodingUCS2PDU,
  269. payload: []byte(pdu),
  270. prompt: fmt.Sprintf("AT+CMGS=%d", tpduLength),
  271. setup: []string{"AT+CMGF=0"},
  272. tpduLength: tpduLength,
  273. part: index + 1,
  274. total: len(segments),
  275. concatReference: &referenceValue,
  276. })
  277. }
  278. return result, nil
  279. }
  280. func splitGSM7(septets []byte, maximum int) [][]byte {
  281. var result [][]byte
  282. for len(septets) > 0 {
  283. count := maximum
  284. if count > len(septets) {
  285. count = len(septets)
  286. }
  287. if count < len(septets) && septets[count-1] == 0x1b {
  288. count--
  289. }
  290. result = append(result, append([]byte(nil), septets[:count]...))
  291. septets = septets[count:]
  292. }
  293. return result
  294. }
  295. func splitUCS2(units []uint16, maximum int) [][]uint16 {
  296. var result [][]uint16
  297. for len(units) > 0 {
  298. count := maximum
  299. if count > len(units) {
  300. count = len(units)
  301. }
  302. if count < len(units) &&
  303. utf16.IsSurrogate(rune(units[count-1])) &&
  304. units[count-1] >= 0xd800 && units[count-1] <= 0xdbff &&
  305. units[count] >= 0xdc00 && units[count] <= 0xdfff {
  306. count--
  307. }
  308. result = append(result, append([]uint16(nil), units[:count]...))
  309. units = units[count:]
  310. }
  311. return result
  312. }
  313. func encodeUCS2Units(units []uint16) []byte {
  314. result := make([]byte, 0, len(units)*2)
  315. for _, unit := range units {
  316. result = append(result, byte(unit>>8), byte(unit))
  317. }
  318. return result
  319. }
  320. func concatUDH(reference byte, total, sequence int) []byte {
  321. return []byte{0x05, 0x00, 0x03, reference, byte(total), byte(sequence)}
  322. }
  323. func normalizeSMSRecipient(value string) (string, error) {
  324. var result strings.Builder
  325. for _, character := range strings.TrimSpace(value) {
  326. switch {
  327. case character >= '0' && character <= '9':
  328. result.WriteRune(character)
  329. case character == '+' && result.Len() == 0:
  330. result.WriteRune(character)
  331. case character == ' ' || character == '-' ||
  332. character == '(' || character == ')':
  333. default:
  334. return "", ErrSMSInvalidRecipient
  335. }
  336. }
  337. normalized := result.String()
  338. digits := strings.TrimPrefix(normalized, "+")
  339. if len(digits) < 1 || len(digits) > 20 {
  340. return "", ErrSMSInvalidRecipient
  341. }
  342. if strings.IndexFunc(digits, func(character rune) bool {
  343. return character < '0' || character > '9'
  344. }) >= 0 {
  345. return "", ErrSMSInvalidRecipient
  346. }
  347. return normalized, nil
  348. }
  349. func encodeGSM7(text string) ([]byte, bool) {
  350. result := make([]byte, 0, len(text))
  351. for _, character := range text {
  352. encoded, ok := gsm7Encoder[character]
  353. if !ok {
  354. return nil, false
  355. }
  356. result = append(result, encoded...)
  357. }
  358. return result, true
  359. }
  360. func canSendDirectGSM7(text string) bool {
  361. for _, character := range text {
  362. encoded, ok := gsm7Encoder[character]
  363. if !ok || len(encoded) != 1 || encoded[0] == 0x1b ||
  364. character > 0x7f || byte(character) != encoded[0] {
  365. return false
  366. }
  367. }
  368. return true
  369. }
  370. func encodeSubmitPDU(
  371. recipient string,
  372. gsm7Septets []byte,
  373. ucs2 []byte,
  374. ) (string, int, error) {
  375. return encodeSubmitPDUWithHeader(recipient, gsm7Septets, ucs2, nil)
  376. }
  377. func encodeSubmitPDUWithHeader(
  378. recipient string,
  379. gsm7Septets []byte,
  380. ucs2 []byte,
  381. userDataHeader []byte,
  382. ) (string, int, error) {
  383. digits := strings.TrimPrefix(recipient, "+")
  384. address, err := encodeSemiOctets(digits)
  385. if err != nil {
  386. return "", 0, err
  387. }
  388. toa := byte(0x81)
  389. if strings.HasPrefix(recipient, "+") {
  390. toa = 0x91
  391. }
  392. // SMS-SUBMIT with TP-SRR set so both AT PDU mode and SMS over IMS can
  393. // receive an SMS-STATUS-REPORT for this submission.
  394. firstOctet := byte(0x21)
  395. if len(userDataHeader) > 0 {
  396. if int(userDataHeader[0])+1 != len(userDataHeader) {
  397. return "", 0, errors.New("invalid SMS concatenation header")
  398. }
  399. firstOctet |= 0x40
  400. }
  401. pdu := []byte{
  402. 0x00, // Use the SMSC configured on the SIM.
  403. firstOctet,
  404. 0x00, // TP-MR allocated by the modem/network.
  405. byte(len(digits)),
  406. toa,
  407. }
  408. pdu = append(pdu, address...)
  409. pdu = append(pdu, 0x00) // TP-PID
  410. switch {
  411. case gsm7Septets != nil:
  412. headerSeptets := 0
  413. startBit := 0
  414. if len(userDataHeader) > 0 {
  415. headerSeptets = (len(userDataHeader)*8 + 6) / 7
  416. startBit = headerSeptets * 7
  417. }
  418. userDataLength := headerSeptets + len(gsm7Septets)
  419. if userDataLength > 160 {
  420. return "", 0, ErrSMSTooLong
  421. }
  422. packed := packSeptets(gsm7Septets, startBit)
  423. copy(packed, userDataHeader)
  424. pdu = append(pdu, 0x00, byte(userDataLength))
  425. pdu = append(pdu, packed...)
  426. case ucs2 != nil:
  427. userDataLength := len(userDataHeader) + len(ucs2)
  428. if userDataLength > 140 {
  429. return "", 0, ErrSMSTooLong
  430. }
  431. pdu = append(pdu, 0x08, byte(userDataLength))
  432. pdu = append(pdu, userDataHeader...)
  433. pdu = append(pdu, ucs2...)
  434. default:
  435. return "", 0, errors.New("SMS PDU has no user data")
  436. }
  437. return strings.ToUpper(hex.EncodeToString(pdu)), len(pdu) - 1, nil
  438. }
  439. func encodeSemiOctets(digits string) ([]byte, error) {
  440. if digits == "" {
  441. return nil, ErrSMSInvalidRecipient
  442. }
  443. result := make([]byte, (len(digits)+1)/2)
  444. for index := 0; index < len(digits); index += 2 {
  445. low := digits[index]
  446. if low < '0' || low > '9' {
  447. return nil, ErrSMSInvalidRecipient
  448. }
  449. high := byte('F')
  450. if index+1 < len(digits) {
  451. high = digits[index+1]
  452. if high < '0' || high > '9' {
  453. return nil, ErrSMSInvalidRecipient
  454. }
  455. }
  456. highNibble := byte(0x0f)
  457. if high != 'F' {
  458. highNibble = high - '0'
  459. }
  460. result[index/2] = (highNibble << 4) | (low - '0')
  461. }
  462. return result, nil
  463. }
  464. func packSeptets(septets []byte, startBit int) []byte {
  465. if len(septets) == 0 {
  466. return nil
  467. }
  468. bitLength := startBit + len(septets)*7
  469. result := make([]byte, (bitLength+7)/8)
  470. for index, septet := range septets {
  471. bit := startBit + index*7
  472. byteIndex := bit / 8
  473. shift := uint(bit % 8)
  474. result[byteIndex] |= (septet & 0x7f) << shift
  475. if shift > 1 && byteIndex+1 < len(result) {
  476. result[byteIndex+1] |= (septet & 0x7f) >> (8 - shift)
  477. }
  478. }
  479. return result
  480. }
  481. func unpackSeptets(data []byte, count, startBit int) ([]byte, error) {
  482. if count < 0 || startBit < 0 || startBit+count*7 > len(data)*8 {
  483. return nil, errors.New("GSM-7 user data is truncated")
  484. }
  485. result := make([]byte, count)
  486. for index := 0; index < count; index++ {
  487. bit := startBit + index*7
  488. byteIndex := bit / 8
  489. shift := uint(bit % 8)
  490. value := data[byteIndex] >> shift
  491. if shift > 1 && byteIndex+1 < len(data) {
  492. value |= data[byteIndex+1] << (8 - shift)
  493. }
  494. result[index] = value & 0x7f
  495. }
  496. return result, nil
  497. }
  498. func decodeGSM7(septets []byte) (string, error) {
  499. var result strings.Builder
  500. for index := 0; index < len(septets); index++ {
  501. code := septets[index]
  502. if code != 0x1b {
  503. if int(code) >= len(gsm7DefaultAlphabet) {
  504. return result.String(), errors.New("invalid GSM-7 code")
  505. }
  506. result.WriteRune(gsm7DefaultAlphabet[code])
  507. continue
  508. }
  509. index++
  510. if index >= len(septets) {
  511. return result.String(), errors.New("trailing GSM-7 escape")
  512. }
  513. character, ok := gsm7ExtensionAlphabet[septets[index]]
  514. if !ok {
  515. return result.String(), fmt.Errorf(
  516. "unknown GSM-7 extension 0x%02X",
  517. septets[index],
  518. )
  519. }
  520. result.WriteRune(character)
  521. }
  522. return result.String(), nil
  523. }
  524. type pduCursor struct {
  525. data []byte
  526. index int
  527. }
  528. func (cursor *pduCursor) byte() (byte, error) {
  529. if cursor.index >= len(cursor.data) {
  530. return 0, errors.New("SMS PDU is truncated")
  531. }
  532. value := cursor.data[cursor.index]
  533. cursor.index++
  534. return value, nil
  535. }
  536. func (cursor *pduCursor) bytes(count int) ([]byte, error) {
  537. if count < 0 || cursor.index+count > len(cursor.data) {
  538. return nil, errors.New("SMS PDU is truncated")
  539. }
  540. value := cursor.data[cursor.index : cursor.index+count]
  541. cursor.index += count
  542. return value, nil
  543. }
  544. func decodeSMSPDU(raw string) (SMSMessage, error) {
  545. raw = strings.ToUpper(strings.TrimSpace(raw))
  546. message := SMSMessage{
  547. Direction: SMSDirectionUnknown,
  548. Encoding: SMSEncodingUnknown,
  549. StorageStatus: SMSStatusUnknown,
  550. RawPDU: raw,
  551. }
  552. decoded, err := hex.DecodeString(raw)
  553. if err != nil || len(decoded) < 2 {
  554. if err == nil {
  555. err = errors.New("SMS PDU is too short")
  556. }
  557. return message, err
  558. }
  559. cursor := &pduCursor{data: decoded}
  560. smscLength, _ := cursor.byte()
  561. if int(smscLength) > len(decoded)-1 {
  562. return message, errors.New("SMS PDU SMSC length exceeds payload")
  563. }
  564. if smscLength > 0 {
  565. smsc, _ := cursor.bytes(int(smscLength))
  566. if len(smsc) > 1 {
  567. message.ServiceCenter = decodeNumericAddress(
  568. smsc[1:],
  569. (len(smsc)-1)*2,
  570. smsc[0],
  571. )
  572. }
  573. }
  574. firstOctet, err := cursor.byte()
  575. if err != nil {
  576. return message, err
  577. }
  578. switch firstOctet & 0x03 {
  579. case 0:
  580. message.Direction = SMSDirectionReceived
  581. err = decodeDeliverPDU(cursor, firstOctet, &message)
  582. case 1:
  583. message.Direction = SMSDirectionSubmitted
  584. err = decodeSubmitPDU(cursor, firstOctet, &message)
  585. case 2:
  586. message.Direction = SMSDirectionStatusReport
  587. err = decodeStatusReportPDU(cursor, &message)
  588. default:
  589. err = errors.New("unsupported SMS PDU message type")
  590. }
  591. return message, err
  592. }
  593. func decodeDeliverPDU(
  594. cursor *pduCursor,
  595. firstOctet byte,
  596. message *SMSMessage,
  597. ) error {
  598. address, err := readTPAddress(cursor)
  599. if err != nil {
  600. return err
  601. }
  602. message.From = address
  603. pid, err := cursor.byte()
  604. if err != nil {
  605. return err
  606. }
  607. dcs, err := cursor.byte()
  608. if err != nil {
  609. return err
  610. }
  611. message.ProtocolID = int(pid)
  612. message.DataCodingScheme = int(dcs)
  613. timestamp, err := cursor.bytes(7)
  614. if err != nil {
  615. return err
  616. }
  617. if parsed, timestampErr := decodeSMSTimestamp(timestamp); timestampErr == nil {
  618. message.ServiceCenterTimestamp = parsed
  619. }
  620. udl, err := cursor.byte()
  621. if err != nil {
  622. return err
  623. }
  624. return decodeUserData(cursor.data[cursor.index:], firstOctet, dcs, int(udl), message)
  625. }
  626. func decodeSubmitPDU(
  627. cursor *pduCursor,
  628. firstOctet byte,
  629. message *SMSMessage,
  630. ) error {
  631. reference, err := cursor.byte()
  632. if err != nil {
  633. return err
  634. }
  635. message.MessageReference = intPointer(int(reference))
  636. address, err := readTPAddress(cursor)
  637. if err != nil {
  638. return err
  639. }
  640. message.To = address
  641. pid, err := cursor.byte()
  642. if err != nil {
  643. return err
  644. }
  645. dcs, err := cursor.byte()
  646. if err != nil {
  647. return err
  648. }
  649. message.ProtocolID = int(pid)
  650. message.DataCodingScheme = int(dcs)
  651. switch (firstOctet >> 3) & 0x03 {
  652. case 2:
  653. if _, err := cursor.byte(); err != nil {
  654. return err
  655. }
  656. case 1, 3:
  657. if _, err := cursor.bytes(7); err != nil {
  658. return err
  659. }
  660. }
  661. udl, err := cursor.byte()
  662. if err != nil {
  663. return err
  664. }
  665. return decodeUserData(cursor.data[cursor.index:], firstOctet, dcs, int(udl), message)
  666. }
  667. func decodeStatusReportPDU(
  668. cursor *pduCursor,
  669. message *SMSMessage,
  670. ) error {
  671. reference, err := cursor.byte()
  672. if err != nil {
  673. return err
  674. }
  675. message.MessageReference = intPointer(int(reference))
  676. address, err := readTPAddress(cursor)
  677. if err != nil {
  678. return err
  679. }
  680. message.To = address
  681. scts, err := cursor.bytes(7)
  682. if err != nil {
  683. return err
  684. }
  685. discharge, err := cursor.bytes(7)
  686. if err != nil {
  687. return err
  688. }
  689. status, err := cursor.byte()
  690. if err != nil {
  691. return err
  692. }
  693. message.StatusCode = intPointer(int(status))
  694. message.DeliveryStatus = smsDeliveryStatus(status)
  695. if parsed, parseErr := decodeSMSTimestamp(scts); parseErr == nil {
  696. message.ServiceCenterTimestamp = parsed
  697. }
  698. if parsed, parseErr := decodeSMSTimestamp(discharge); parseErr == nil {
  699. message.DischargeTimestamp = parsed
  700. }
  701. return nil
  702. }
  703. func smsDeliveryStatus(status byte) string {
  704. switch {
  705. case status <= 0x1f:
  706. return "delivered"
  707. case status <= 0x3f:
  708. return "temporary_error"
  709. case status <= 0x5f:
  710. return "permanent_error"
  711. case status <= 0x7f:
  712. return "temporary_error_no_retry"
  713. default:
  714. return "reserved"
  715. }
  716. }
  717. func readTPAddress(cursor *pduCursor) (string, error) {
  718. length, err := cursor.byte()
  719. if err != nil {
  720. return "", err
  721. }
  722. toa, err := cursor.byte()
  723. if err != nil {
  724. return "", err
  725. }
  726. byteCount := (int(length) + 1) / 2
  727. value, err := cursor.bytes(byteCount)
  728. if err != nil {
  729. return "", err
  730. }
  731. if toa&0x70 == 0x50 {
  732. septetCount := int(length) * 4 / 7
  733. septets, unpackErr := unpackSeptets(value, septetCount, 0)
  734. if unpackErr != nil {
  735. return "", unpackErr
  736. }
  737. return decodeGSM7(septets)
  738. }
  739. return decodeNumericAddress(value, int(length), toa), nil
  740. }
  741. func decodeNumericAddress(value []byte, digits int, toa byte) string {
  742. var result strings.Builder
  743. if toa&0x70 == 0x10 {
  744. result.WriteByte('+')
  745. }
  746. written := 0
  747. for _, octet := range value {
  748. for _, digit := range []byte{octet & 0x0f, octet >> 4} {
  749. if written >= digits {
  750. return result.String()
  751. }
  752. if digit <= 9 {
  753. result.WriteByte('0' + digit)
  754. written++
  755. }
  756. }
  757. }
  758. return result.String()
  759. }
  760. func decodeUserData(
  761. data []byte,
  762. firstOctet byte,
  763. dcs byte,
  764. udl int,
  765. message *SMSMessage,
  766. ) error {
  767. alphabet := dcs & 0x0c
  768. expectedBytes := udl
  769. if alphabet == 0 {
  770. expectedBytes = (udl*7 + 7) / 8
  771. }
  772. if expectedBytes > len(data) {
  773. return errors.New("SMS user data is truncated")
  774. }
  775. data = data[:expectedBytes]
  776. message.RawUserData = strings.ToUpper(hex.EncodeToString(data))
  777. headerBytes := 0
  778. if firstOctet&0x40 != 0 {
  779. if len(data) == 0 {
  780. return errors.New("SMS has UDHI but no user data header")
  781. }
  782. headerBytes = int(data[0]) + 1
  783. if headerBytes > len(data) {
  784. return errors.New("SMS user data header is truncated")
  785. }
  786. message.Concat = parseConcatHeader(data[1:headerBytes])
  787. }
  788. switch alphabet {
  789. case 0:
  790. message.Encoding = SMSEncodingGSM7PDU
  791. headerSeptets := 0
  792. if headerBytes > 0 {
  793. headerSeptets = (headerBytes*8 + 6) / 7
  794. }
  795. textSeptets := udl - headerSeptets
  796. septets, err := unpackSeptets(data, textSeptets, headerSeptets*7)
  797. if err != nil {
  798. return err
  799. }
  800. text, err := decodeGSM7(septets)
  801. message.Text = text
  802. return err
  803. case 8:
  804. message.Encoding = SMSEncodingUCS2PDU
  805. payload := data[headerBytes:]
  806. if len(payload)%2 != 0 {
  807. return errors.New("UCS2 SMS has an odd byte count")
  808. }
  809. units := make([]uint16, 0, len(payload)/2)
  810. for index := 0; index < len(payload); index += 2 {
  811. units = append(units, uint16(payload[index])<<8|uint16(payload[index+1]))
  812. }
  813. message.Text = string(utf16.Decode(units))
  814. return nil
  815. default:
  816. message.Encoding = SMSEncoding8BitPDU
  817. return nil
  818. }
  819. }
  820. func parseConcatHeader(header []byte) *SMSConcatInfo {
  821. for index := 0; index+1 < len(header); {
  822. identifier := header[index]
  823. length := int(header[index+1])
  824. index += 2
  825. if index+length > len(header) {
  826. return nil
  827. }
  828. value := header[index : index+length]
  829. switch {
  830. case identifier == 0x00 && length == 3:
  831. return &SMSConcatInfo{
  832. Reference: int(value[0]),
  833. Total: int(value[1]),
  834. Sequence: int(value[2]),
  835. }
  836. case identifier == 0x08 && length == 4:
  837. return &SMSConcatInfo{
  838. Reference: int(value[0])<<8 | int(value[1]),
  839. Total: int(value[2]),
  840. Sequence: int(value[3]),
  841. }
  842. }
  843. index += length
  844. }
  845. return nil
  846. }
  847. func decodeSMSTimestamp(value []byte) (*time.Time, error) {
  848. if len(value) != 7 {
  849. return nil, errors.New("SMS timestamp must be seven octets")
  850. }
  851. component := func(octet byte) (int, error) {
  852. low, high := int(octet&0x0f), int(octet>>4)
  853. if low > 9 || high > 9 {
  854. return 0, errors.New("invalid timestamp semi-octet")
  855. }
  856. return low*10 + high, nil
  857. }
  858. parts := make([]int, 6)
  859. for index := range parts {
  860. parsed, err := component(value[index])
  861. if err != nil {
  862. return nil, err
  863. }
  864. parts[index] = parsed
  865. }
  866. zoneByte := value[6]
  867. negative := zoneByte&0x08 != 0
  868. zoneByte &^= 0x08
  869. quarters, err := component(zoneByte)
  870. if err != nil || quarters > 56 {
  871. return nil, errors.New("invalid SMS timestamp timezone")
  872. }
  873. offset := quarters * 15 * 60
  874. if negative {
  875. offset = -offset
  876. }
  877. year := 2000 + parts[0]
  878. if parts[0] >= 90 {
  879. year = 1900 + parts[0]
  880. }
  881. if parts[1] < 1 || parts[1] > 12 ||
  882. parts[2] < 1 || parts[2] > 31 ||
  883. parts[3] > 23 || parts[4] > 59 || parts[5] > 60 {
  884. return nil, errors.New("invalid SMS timestamp component")
  885. }
  886. zone := time.FixedZone("SMS", offset)
  887. result := time.Date(
  888. year,
  889. time.Month(parts[1]),
  890. parts[2],
  891. parts[3],
  892. parts[4],
  893. parts[5],
  894. 0,
  895. zone,
  896. )
  897. return &result, nil
  898. }
  899. func parseDecimal(value string) (int, bool) {
  900. number, err := strconv.Atoi(strings.Trim(strings.TrimSpace(value), `"`))
  901. return number, err == nil
  902. }