diff --git a/cmd/signaldctl/cmd/subscribe.go b/cmd/signaldctl/cmd/subscribe.go new file mode 100644 index 0000000..b0c27ec --- /dev/null +++ b/cmd/signaldctl/cmd/subscribe.go @@ -0,0 +1,71 @@ +// Copyright © 2020 Finn Herzfeld +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +package cmd + +import ( + "encoding/json" + "fmt" + "log" + "math/rand" + "os" + + "github.com/spf13/cobra" + + "gitlab.com/signald/signald-go/signald/client-protocol/v0" +) + +// subscribeCmd represents the subscribe command +var subscribeCmd = &cobra.Command{ + Use: "subscribe", + Short: "subscribe to incoming messages", + Long: `receive incoming messages from Signal`, + Run: func(cmd *cobra.Command, args []string) { + requestID := fmt.Sprint("signaldctl-", rand.Intn(1000)) + err := s.RawRequest(v0.LegacyRequest{ + Type: "subscribe", + Username: username, + ID: requestID, + }) + if err != nil { + log.Fatal("error sending request: ", err) + } + + c := make(chan v0.LegacyResponse) + go s.Listen(c) + + go func() { + defer s.CloseResponseListener(requestID) + r := <-s.GetResponseListener(requestID) + if r.GetError() != nil { + log.Fatal("error subscribing: ", r.GetError()) + } + }() + + for { + msg := <-c + if err := json.NewEncoder(os.Stdout).Encode(msg); err != nil { + log.Fatal("error encoding response to JSON. this should never happen", err) + } + } + }, +} + +func init() { + RootCmd.AddCommand(subscribeCmd) + + subscribeCmd.Flags().StringVarP(&username, "username", "u", "", "The phone number to subscribe to") + must(subscribeCmd.MarkFlagRequired("username")) +} diff --git a/signald/client-protocol/v0/signaldresponse.go b/signald/client-protocol/v0/signaldresponse.go index c57d922..7a59ff6 100644 --- a/signald/client-protocol/v0/signaldresponse.go +++ b/signald/client-protocol/v0/signaldresponse.go @@ -1,55 +1,55 @@ package v0 type LegacyResponse struct { - ID string - Data LegacyResponseData - Type string + ID string `json:",omitempty"` + Data LegacyResponseData `json:",omitempty"` + Type string `json:",omitempty"` } // ResponseData is where most of the data in the response is stored. type LegacyResponseData struct { - Groups []Group - Accounts []Account - URI string - DataMessage DataMessage - Message string - Username string - Source JsonAddress - SourceDevice int - Type string - IsReceipt bool - Timestamp int64 - ServerTimestamp int64 + Groups []Group `json:",omitempty"` + Accounts []Account `json:",omitempty"` + URI string `json:",omitempty"` + DataMessage DataMessage `json:",omitempty"` + Message string `json:",omitempty"` + Username string `json:",omitempty"` + Source JsonAddress `json:",omitempty"` + SourceDevice int `json:",omitempty"` + Type string `json:",omitempty"` + IsReceipt bool `json:",omitempty"` + Timestamp int64 `json:",omitempty"` + ServerTimestamp int64 `json:",omitempty"` } // Group represents a group in signal type Group struct { - GroupID string - Members []string - Name string - AvatarID int + GroupID string `json:",omitempty"` + Members []string `json:",omitempty"` + Name string `json:",omitempty"` + AvatarID int `json:",omitempty"` } // Account represents a user account registered to signald type Account struct { - Username string - DeviceID int - Filename string - Registered bool - HasKeys bool `json:"has_keys"` + Username string `json:",omitempty"` + DeviceID int `json:",omitempty"` + Filename string `json:",omitempty"` + Registered bool `json:",omitempty"` + HasKeys bool `json:"has_keys,omitempty"` Subscribed bool } // DataMessage is the main component of incoming text messages type DataMessage struct { - Timestamp int64 - Body string - ExpiresInSeconds int64 - GroupInfo IncomingGroupInfo `json:"group"` + Timestamp int64 `json:",omitempty"` + Body string `json:",omitempty"` + ExpiresInSeconds int64 `json:",omitempty"` + GroupInfo IncomingGroupInfo `json:"group,omitempty"` } // IncomingGroupInfo is information about a particular group type IncomingGroupInfo struct { - GroupID string - Type string + GroupID string `json:",omitempty"` + Type string `json:",omitempty"` } diff --git a/signald/signald.go b/signald/signald.go index 74ba296..4e1fa5d 100644 --- a/signald/signald.go +++ b/signald/signald.go @@ -24,6 +24,7 @@ import ( "net" "os" "strconv" + "strings" "gitlab.com/signald/signald-go/signald/client-protocol/v0" ) @@ -70,6 +71,9 @@ func (s *Signald) Listen(c chan v0.LegacyResponse) { msg, err := s.readNext() if err == io.EOF { log.Println("signald-go: socket disconnected!") + if c != nil { + close(c) + } return } @@ -88,12 +92,12 @@ func (s *Signald) Listen(c chan v0.LegacyResponse) { } if c != nil { - legacyResponse := v0.LegacyResponse{ - ID: msg.ID, - Type: msg.Type, + legacyResponse := v0.LegacyResponse{ID: msg.ID, Type: msg.Type} + if err := json.Unmarshal(msg.Data, &legacyResponse.Data); err != nil { + log.Println("signald-go receive error: ", err) + } else { + c <- legacyResponse } - _ = json.Unmarshal(msg.Data, &legacyResponse.Data) - c <- legacyResponse } } } @@ -102,7 +106,7 @@ func (s *Signald) RawRequest(request interface{}) error { if debugSignaldIO { buffer := bytes.Buffer{} if err := json.NewEncoder(&buffer).Encode(request); err == nil { - log.Println("[to signald]", buffer.String()) + log.Println("[to signald]", strings.TrimSpace(buffer.String())) } } return json.NewEncoder(s.socket).Encode(request) @@ -133,7 +137,7 @@ func (s *Signald) readNext() (b BasicResponse, err error) { if debugSignaldIO { buffer := bytes.Buffer{} err = json.NewDecoder(io.TeeReader(s.socket, &buffer)).Decode(&b) - log.Println("[from signald]", buffer.String()) + log.Println("[from signald]", strings.TrimSpace(buffer.String())) } else { err = json.NewDecoder(s.socket).Decode(&b) }