-
Notifications
You must be signed in to change notification settings - Fork 20
/
sms.go
111 lines (104 loc) · 2.67 KB
/
sms.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// SPDX-License-Identifier: MIT
//
// Copyright © 2020 Kent Gibson <warthog618@gmail.com>.
// Package sms provides encoders and decoders for SMS PDUs.
package sms
import (
"github.com/warthog618/sms/encoding/tpdu"
"github.com/warthog618/sms/encoding/ucs2"
)
// DecodeConfig contains configuration option for Decode.
type DecodeConfig struct {
dopts []tpdu.UDDecodeOption
}
// Decode returns the UTF-8 message contained in a set of TPDUs.
//
// For concatenated messages the segments assumed to be the component TPDUs, in
// correct order. This is the case for segments returned by the Collector. It
// can be tested using IsCompleteMessage.
func Decode(segments []*tpdu.TPDU, options ...DecodeOption) ([]byte, error) {
cfg := DecodeConfig{}
for _, option := range options {
option.ApplyDecodeOption(&cfg)
}
if len(cfg.dopts) == 0 {
cfg.dopts = []tpdu.UDDecodeOption{tpdu.WithAllCharsets}
}
bl := 0
ts := make([][]byte, len(segments))
var danglingSurrogate ucs2.ErrDanglingSurrogate
for i, s := range segments {
a, _ := s.Alphabet()
ud := s.UD
if danglingSurrogate != nil {
ud = append([]byte(danglingSurrogate), ud...)
danglingSurrogate = nil
}
d, err := tpdu.DecodeUserData(ud, s.UDH, a, cfg.dopts...)
if err != nil {
switch e := err.(type) {
case ucs2.ErrDanglingSurrogate:
danglingSurrogate = e
default:
return nil, err
}
}
ts[i] = d
bl += len(d)
}
if danglingSurrogate != nil {
return nil, danglingSurrogate
}
m := make([]byte, 0, bl)
for _, t := range ts {
m = append(m, t...)
}
return m, nil
}
// IsCompleteMessage confirms that the TPDUs contain all the sgements required
// to reassemble a complete message and are in the correct order.
func IsCompleteMessage(segments []*tpdu.TPDU) bool {
if len(segments) == 0 {
return false
}
baseSegs, _, baseConcatRef, ok := segments[0].ConcatInfo()
if !ok {
return len(segments) == 1
}
if baseSegs != len(segments) {
return false
}
for i, s := range segments {
segs, seqno, concatRef, ok := s.ConcatInfo()
if !ok {
return false
}
if segs != baseSegs {
return false
}
if concatRef != baseConcatRef {
return false
}
if seqno != i+1 {
return false
}
}
return true
}
// UnmarshalConfig contains configuration options for Unmarshal.
type UnmarshalConfig struct {
dirn tpdu.Direction
}
// Unmarshal converts a binary SMS TPDU into the corresponding TPDU object.
func Unmarshal(src []byte, options ...UnmarshalOption) (*tpdu.TPDU, error) {
cfg := UnmarshalConfig{}
for _, option := range options {
option.ApplyUnmarshalOption(&cfg)
}
t := tpdu.TPDU{Direction: cfg.dirn}
err := t.UnmarshalBinary(src)
if err != nil {
return nil, err
}
return &t, nil
}