Skip to content

Commit aca3b58

Browse files
committed
Implemented sms read
1 parent f5014cd commit aca3b58

File tree

4 files changed

+104
-11
lines changed

4 files changed

+104
-11
lines changed

args.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ type (
99

1010
SMSSendArgs struct {
1111
PhoneNumber string `validate:"e164" arg:"-p,--phone,required" help:"Receiver's phone number"`
12-
Message string `validate:"printascii" arg:"-m,--msg,required" help:"Message to be sent"`
12+
Message string `validate:"alphanum" arg:"-m,--msg,required" help:"Message to be sent"`
1313
}
1414

1515
SMSReadArgs struct {

drivers/driver_ctl.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package drivers
33
import (
44
"fmt"
55
"log/slog"
6+
"time"
67

78
"github.com/brokenCursor/usb-modem-cli/logging"
89
"github.com/spf13/viper"
@@ -27,12 +28,13 @@ type (
2728
BaseModem
2829

2930
SendSMS(phone string, message string) error
30-
// GetAllSMS() ([]SMS, error)
31+
ReadAllSMS() ([]SMS, error)
3132
}
3233
)
3334

3435
type (
3536
SMS struct {
37+
Time time.Time
3638
Sender string
3739
Message string
3840
}
@@ -53,7 +55,6 @@ func init() {
5355
}
5456

5557
func IsRegistered(name string) bool {
56-
// Check if driver has already been registered
5758
_, ok := Drivers[name]
5859
return ok
5960
}

drivers/zte8810ft.go

Lines changed: 89 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package drivers
22

33
import (
4+
"encoding/hex"
45
"encoding/json"
56
"fmt"
67
"io"
@@ -14,6 +15,7 @@ import (
1415
cfg "github.com/brokenCursor/usb-modem-cli/config"
1516
"github.com/spf13/viper"
1617
"github.com/warthog618/sms/encoding/gsm7"
18+
"github.com/warthog618/sms/encoding/ucs2"
1719
)
1820

1921
// DO NOT USE DIRECTLY
@@ -31,6 +33,17 @@ type (
3133
pppConnected struct {
3234
Connected string `json:"ppp_status"`
3335
}
36+
37+
rawIncomingSMS struct {
38+
Messages []struct {
39+
ID string `json:"id"`
40+
Source string `json:"number"`
41+
Content string `json:"content"`
42+
Tag string `json:"tag"`
43+
Date string `json:"date"`
44+
DraftGroupID string `json:"draft_group_id"`
45+
} `json:"messages"`
46+
}
3447
)
3548

3649
func init() {
@@ -227,14 +240,8 @@ func (m *zte8810ft) GetCellConnStatus() (*LinkStatus, error) {
227240
}
228241

229242
func (m *zte8810ft) SendSMS(phone string, message string) error {
230-
// GET /goform/goform_set_cmd_process?goformId=SEND_SMS
231-
// Prepare everything to make a request
232-
233243
// Encode message into GSM-7 as byte array
234244
encodedMsg, err := gsm7.Encode([]byte(message))
235-
switch err {
236-
237-
}
238245
if err != nil {
239246
return ActionError{Action: "sms send", Err: err}
240247
}
@@ -304,3 +311,79 @@ func (m *zte8810ft) SendSMS(phone string, message string) error {
304311

305312
return nil
306313
}
314+
315+
func (m *zte8810ft) ReadAllSMS() ([]SMS, error) {
316+
// http://10.96.170.1/goform/goform_get_cmd_process?cmd=sms_data_total&page=0&data_per_page=100&mem_store=1&tags=12&order_by=order+by+id+desc&_=1724578532798
317+
// Build query
318+
u := m.getBaseURL("/goform/goform_get_cmd_process")
319+
query := u.Query()
320+
query.Add("cmd", "sms_data_total")
321+
query.Add("page", "0")
322+
query.Add("data_per_page", "100")
323+
query.Add("mem_store", "1")
324+
query.Add("tags", "12") // 1 - Received, unread | 2 - Sent | 12 - Received, read + unread | 11 - Drafts (??)
325+
query.Add("order_by", "order by id desc")
326+
query.Add("_", strconv.FormatInt((time.Now().UnixMilli)(), 10))
327+
u.RawQuery = query.Encode()
328+
329+
request, err := m.getNewRequest("GET", u, http.Header{}, nil)
330+
if err != nil {
331+
return nil, ActionError{Action: "sms read", Err: err}
332+
}
333+
m.logger.With("request", request.URL.String()).Debug("request")
334+
335+
resp, err := m.httpClient.Do(request)
336+
337+
// Process errors
338+
switch {
339+
case err != nil:
340+
return nil, ActionError{Action: "status", Err: err}
341+
case resp.StatusCode != 200:
342+
return nil, ActionError{Action: "status", Err: fmt.Errorf("response status %d", resp.StatusCode)}
343+
}
344+
345+
// Read the response
346+
defer resp.Body.Close()
347+
body, err := io.ReadAll(resp.Body)
348+
if err != nil {
349+
return nil, ErrUnknown
350+
}
351+
352+
rawSMS := new(rawIncomingSMS)
353+
354+
err = json.Unmarshal(body, &rawSMS)
355+
if err != nil {
356+
m.logger.With("body", body).Debug("failed to unmarshal body to struct")
357+
return nil, ActionError{Action: "sms read", Err: err}
358+
}
359+
360+
processedSMS := make([]SMS, len(rawSMS.Messages))
361+
for i := range rawSMS.Messages {
362+
processedSMS[i].Sender = rawSMS.Messages[i].Source
363+
364+
// Extract datetime
365+
date, err := time.Parse("06,01,02,15,04,05,-07", rawSMS.Messages[i].Date)
366+
if err != nil {
367+
m.logger.With("id", rawSMS.Messages[i].ID, "raw_date", rawSMS.Messages[i].Date, "err", err).Debug("failed to parse datetime")
368+
return nil, ActionError{Action: "sms read", Err: fmt.Errorf("failed to decode message datetime")}
369+
}
370+
processedSMS[i].Time = date
371+
372+
// Extract contents
373+
rawBytes, err := hex.DecodeString(rawSMS.Messages[i].Content)
374+
if err != nil {
375+
m.logger.With("id", rawSMS.Messages[i].ID, "raw_content", rawSMS.Messages[i].Content).Debug("failed to parse content")
376+
return nil, ActionError{Action: "sms read", Err: fmt.Errorf("failed to parse message content")}
377+
}
378+
379+
runes, err := ucs2.Decode(rawBytes)
380+
if err != nil {
381+
m.logger.With("id", rawSMS.Messages[i].ID, "raw_content", rawSMS.Messages[i].Content).Debug("failed to decode content")
382+
return nil, ActionError{Action: "sms read", Err: fmt.Errorf("failed to decode message content")}
383+
}
384+
385+
processedSMS[i].Message = string(runes)
386+
}
387+
388+
return processedSMS, nil
389+
}

mcli.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package main
33
import (
44
"log/slog"
55
"os"
6+
"time"
67

78
"github.com/alexflint/go-arg"
89
"github.com/brokenCursor/usb-modem-cli/config"
@@ -98,7 +99,6 @@ func run() error {
9899
}
99100
}
100101
case args.SMS != nil:
101-
// None of this is implemented :)
102102
sms, ok := modem.(drivers.ModemSMS)
103103
if !ok {
104104
return DriverSupportError{Driver: modem, Function: "SMS"}
@@ -108,13 +108,22 @@ func run() error {
108108
case args.SMS.Send != nil:
109109
err := validate.Struct(args.SMS.Send)
110110
if err != nil {
111-
parser.FailSubcommand("Unknown action", "sms")
111+
parser.FailSubcommand("Unknown values or action", "sms")
112112
}
113113

114114
err = sms.SendSMS(args.SMS.Send.PhoneNumber, args.SMS.Send.Message)
115115
if err != nil {
116116
return err
117117
}
118+
case args.SMS.Read != nil:
119+
messages, err := sms.ReadAllSMS()
120+
if err != nil {
121+
return err
122+
}
123+
124+
for i := range messages {
125+
cfmt.Printf("{{ID:}}::cyan %d\n{{Source:}}::green %s\n{{Time:}}::yellow %s\n{{Text:}}::#FA8100\n%s\n---\n", i, messages[i].Sender, messages[i].Time.Format(time.DateTime), messages[i].Message)
126+
}
118127
}
119128
case parser.Subcommand() == nil:
120129
parser.Fail("Missing or unknown command")

0 commit comments

Comments
 (0)