diff --git a/cmd/signaldctl/cmd/account/link/link-account.go b/cmd/signaldctl/cmd/account/link/link-account.go new file mode 100644 index 0000000..1868721 --- /dev/null +++ b/cmd/signaldctl/cmd/account/link/link-account.go @@ -0,0 +1,99 @@ +// Copyright © 2021 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 link + +import ( + "encoding/json" + "log" + "os" + + "github.com/jedib0t/go-pretty/v6/table" + "github.com/mdp/qrterminal" + "github.com/spf13/cobra" + "gopkg.in/yaml.v2" + + "gitlab.com/signald/signald-go/cmd/signaldctl/common" + "gitlab.com/signald/signald-go/signald" + "gitlab.com/signald/signald-go/signald/client-protocol/v0" +) + +var ( + noWait bool + + LinkAccountCmd = &cobra.Command{ + Use: "link", + Short: "create a local account by linking to an existing Signal account", + Run: func(_ *cobra.Command, _ []string) { + requestID := signald.GenerateID() + err := common.Signald.RawRequest(v0.LegacyRequest{Type: "link", ID: requestID}) + if err != nil { + log.Fatal("error sending request: ", err) + } + c := make(chan v0.LegacyResponse) + go common.Signald.Listen(c) + uri := common.GetResponse(c, requestID) + if uri.Type != "linking_uri" { + log.Fatalf("unexpected response from signald when requesting link: %+v", uri) + } + + switch common.OutputFormat { + case common.OutputFormatJSON: + err := json.NewEncoder(os.Stdout).Encode(uri.Data.URI) + if err != nil { + log.Fatal(err, "error encoding response to stdout") + } + case common.OutputFormatYAML: + err := yaml.NewEncoder(os.Stdout).Encode(uri.Data.URI) + if err != nil { + log.Fatal(err, "error encoding response to stdout") + } + case common.OutputFormatCSV, common.OutputFormatTable: + t := table.NewWriter() + t.SetOutputMirror(os.Stdout) + t.AppendHeader(table.Row{"URI"}) + t.AppendRow(table.Row{uri.Data.URI}) + if common.OutputFormat == common.OutputFormatCSV { + t.RenderCSV() + } else { + t.Render() + } + case common.OutputFormatQR, common.OutputFormatDefault: + qrterminal.Generate(uri.Data.URI, qrterminal.M, os.Stdout) + default: + log.Fatal("unsupported output format") + } + + if noWait { + return + } + + finish := common.GetResponse(c, requestID) + if finish.Type == "linking_successful" { + log.Println("linking successful") + return + } + if finish.Type == "linking_error" { + log.Fatal("error from signald:", finish.Data.Message) + } else { + log.Fatal("unexpected message from signald:", finish.Data.Message) + } + }, + } +) + +func init() { + LinkAccountCmd.Flags().BoolVar(&noWait, "no-wait", false, "return after the linking URI is printed to stdout. By default, signaldctl will wait until the server acknowledges that the linking has completed before exiting") +} diff --git a/cmd/signaldctl/cmd/get/account/account.go b/cmd/signaldctl/cmd/account/list/list-accounts.go similarity index 94% rename from cmd/signaldctl/cmd/get/account/account.go rename to cmd/signaldctl/cmd/account/list/list-accounts.go index ceb425e..01d86c7 100644 --- a/cmd/signaldctl/cmd/get/account/account.go +++ b/cmd/signaldctl/cmd/account/list/list-accounts.go @@ -13,7 +13,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -package account +package list import ( "encoding/json" @@ -30,10 +30,9 @@ import ( ) var ( - GetAccountCmd = &cobra.Command{ - Use: "account", - Aliases: []string{"accounts"}, - Short: "return a list of accounts", + ListAccountCmd = &cobra.Command{ + Use: "list", + Short: "return a list of accounts", Run: func(_ *cobra.Command, _ []string) { requestID := signald.GenerateID() err := common.Signald.RawRequest(v0.LegacyRequest{ diff --git a/cmd/signaldctl/cmd/account/register/register-account.go b/cmd/signaldctl/cmd/account/register/register-account.go new file mode 100644 index 0000000..76b8e50 --- /dev/null +++ b/cmd/signaldctl/cmd/account/register/register-account.go @@ -0,0 +1,66 @@ +// Copyright © 2021 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 register + +import ( + "log" + + "github.com/spf13/cobra" + + "gitlab.com/signald/signald-go/cmd/signaldctl/common" + "gitlab.com/signald/signald-go/signald" + "gitlab.com/signald/signald-go/signald/client-protocol/v0" +) + +var ( + phoneNumber string + voice bool + + RegisterAccountCmd = &cobra.Command{ + Use: "register", + Short: "begin the process of creating a new account", + PreRun: func(_ *cobra.Command, _ []string) { + if phoneNumber == "" { + log.Fatal("--phone-number required") + } + }, + Run: func(_ *cobra.Command, _ []string) { + requestID := signald.GenerateID() + err := common.Signald.RawRequest(v0.LegacyRequest{ + Type: "register", + ID: requestID, + Username: phoneNumber, + Voice: voice, + }) + if err != nil { + log.Fatal("error sending request to signald: ", err) + } + c := make(chan v0.LegacyResponse) + go common.Signald.Listen(c) + response := common.GetResponse(c, requestID) + if response.Type == "verification_required" { + log.Println("verification code requested. submit with: signaldctl account verify --phone-number", phoneNumber, "--code XXX-XXX") + } else { + log.Fatalf("unexpected response from signald when requesting verification code: %+v", response) + } + }, + } +) + +func init() { + RegisterAccountCmd.Flags().StringVarP(&phoneNumber, "number", "n", "", "phone number being registered") + RegisterAccountCmd.Flags().BoolVarP(&voice, "voice", "V", false, "request verification code be sent via an automated voice call (code is sent via SMS by default)") +} diff --git a/cmd/signaldctl/cmd/account/root.go b/cmd/signaldctl/cmd/account/root.go new file mode 100644 index 0000000..95a77a6 --- /dev/null +++ b/cmd/signaldctl/cmd/account/root.go @@ -0,0 +1,37 @@ +// Copyright © 2021 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 account + +import ( + "github.com/spf13/cobra" + + "gitlab.com/signald/signald-go/cmd/signaldctl/cmd/account/link" + "gitlab.com/signald/signald-go/cmd/signaldctl/cmd/account/list" + "gitlab.com/signald/signald-go/cmd/signaldctl/cmd/account/register" + "gitlab.com/signald/signald-go/cmd/signaldctl/cmd/account/verify" +) + +var AccountCmd = &cobra.Command{ + Use: "account", + Aliases: []string{"accounts"}, +} + +func init() { + AccountCmd.AddCommand(link.LinkAccountCmd) + AccountCmd.AddCommand(list.ListAccountCmd) + AccountCmd.AddCommand(register.RegisterAccountCmd) + AccountCmd.AddCommand(verify.VerifyAccountCmd) +} diff --git a/cmd/signaldctl/cmd/account/verify/verify-account.go b/cmd/signaldctl/cmd/account/verify/verify-account.go new file mode 100644 index 0000000..2d8e066 --- /dev/null +++ b/cmd/signaldctl/cmd/account/verify/verify-account.go @@ -0,0 +1,69 @@ +// Copyright © 2021 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 verify + +import ( + "log" + + "github.com/spf13/cobra" + + "gitlab.com/signald/signald-go/cmd/signaldctl/common" + "gitlab.com/signald/signald-go/signald" + "gitlab.com/signald/signald-go/signald/client-protocol/v0" +) + +var ( + phoneNumber string + code string + + VerifyAccountCmd = &cobra.Command{ + Use: "verify", + Short: "verify an account and complete the registration process", + PreRun: func(_ *cobra.Command, _ []string) { + if phoneNumber == "" { + log.Fatal("--phone-number required") + } + if code == "" { + log.Fatal("--code required") + } + }, + Run: func(_ *cobra.Command, _ []string) { + requestID := signald.GenerateID() + err := common.Signald.RawRequest(v0.LegacyRequest{ + Type: "verify", + ID: requestID, + Username: phoneNumber, + Code: code, + }) + if err != nil { + log.Fatal("error sending request to signald: ", err) + } + c := make(chan v0.LegacyResponse) + go common.Signald.Listen(c) + response := common.GetResponse(c, requestID) + if response.Type == "verification_succeeded" { + log.Fatal("verification code requested. re-run with --verify") + } else { + log.Fatalf("unexpected response from signald when requesting verification code: %+v", response) + } + }, + } +) + +func init() { + VerifyAccountCmd.Flags().StringVarP(&phoneNumber, "phone-number", "n", "", "phone number being verified") + VerifyAccountCmd.Flags().StringVarP(&code, "code", "c", "", "verification code to submit") +} diff --git a/cmd/signaldctl/cmd/create/account/account.go b/cmd/signaldctl/cmd/create/account/account.go deleted file mode 100644 index a911a56..0000000 --- a/cmd/signaldctl/cmd/create/account/account.go +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright © 2021 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 account - -import ( - "log" - - "github.com/spf13/cobra" - - "gitlab.com/signald/signald-go/signald/client-protocol/v0" -) - -var ( - actionLink bool - actionRequestCode bool - actionVerify bool - - phoneNumber string - code string - voice bool - noWait bool - - CreateAccountCmd = &cobra.Command{ - Use: "account", - Aliases: []string{"accounts"}, - Short: "create an account", - PreRun: func(_ *cobra.Command, _ []string) { - - actionCount := 0 - if actionLink { - actionCount++ - } - if actionRequestCode { - actionCount++ - } - if actionVerify { - actionCount++ - } - if actionCount > 1 { - log.Fatal("invalid arguments: must select exactly one of --request-code, --verify or --link") - } - - if actionLink { - if phoneNumber != "" { - log.Fatal("cannot use --phone-number with --link") - } - if code != "" { - log.Fatal("cannot use --code with --link") - } - if voice { - log.Fatal("cannot use --voice with --link") - } - } - - if actionRequestCode { - if phoneNumber == "" { - log.Fatal("--phone-number required") - } - if code != "" { - log.Fatal("cannot use --code with --request-code") - } - if noWait { - log.Fatal("cannot use --no-wait with --request-code") - } - } - - if actionVerify { - if phoneNumber == "" { - log.Fatal("--phone-number required") - } - if code == "" { - log.Fatal("--code required") - } - if voice { - log.Fatal("cannot use --voice with --verify") - } - if noWait { - log.Fatal("cannot use --no-wait with --verify") - } - } - }, - Run: func(_ *cobra.Command, _ []string) { - if actionLink { - link() - } - - if actionRequestCode { - requestCode() - } - - if actionVerify { - verify() - } - }, - } -) - -func init() { - CreateAccountCmd.Flags().BoolVarP(&actionLink, "link", "l", false, "link an existing account") - CreateAccountCmd.Flags().BoolVarP(&actionRequestCode, "request-code", "r", false, "request a verification code") - CreateAccountCmd.Flags().BoolVarP(&actionVerify, "verify", "v", false, "submit a verification code and complete a new account registration") - - CreateAccountCmd.Flags().StringVarP(&phoneNumber, "number", "n", "", "only with --request-code or --verify. phone number being registered") - CreateAccountCmd.Flags().StringVarP(&code, "code", "c", "", "only with --verify. verification code to submit") - CreateAccountCmd.Flags().BoolVarP(&voice, "voice", "V", false, "only with --request-code. request verification code be sent via an automated voice call (code is sent via SMS by default)") - CreateAccountCmd.Flags().BoolVar(&noWait, "no-wait", false, "only with --link. return after the linking URI is printed to stdout. By default, --link will wait until the server acknowledges that the linking has completed") -} - -func getResponse(c chan v0.LegacyResponse, id string) v0.LegacyResponse { - for { - message := <-c - if message.ID == id { - return message - } - } -} diff --git a/cmd/signaldctl/cmd/create/account/link.go b/cmd/signaldctl/cmd/create/account/link.go deleted file mode 100644 index a2b5452..0000000 --- a/cmd/signaldctl/cmd/create/account/link.go +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright © 2021 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 account - -import ( - "encoding/json" - "log" - "os" - - "github.com/jedib0t/go-pretty/v6/table" - "github.com/mdp/qrterminal" - "gopkg.in/yaml.v2" - - "gitlab.com/signald/signald-go/cmd/signaldctl/common" - "gitlab.com/signald/signald-go/signald" - "gitlab.com/signald/signald-go/signald/client-protocol/v0" -) - -func link() { - requestID := signald.GenerateID() - err := common.Signald.RawRequest(v0.LegacyRequest{Type: "link", ID: requestID}) - if err != nil { - log.Fatal("error sending request: ", err) - } - c := make(chan v0.LegacyResponse) - go common.Signald.Listen(c) - uri := getResponse(c, requestID) - if uri.Type != "linking_uri" { - log.Fatalf("unexpected response from signald when requesting link: %+v", uri) - } - - switch common.OutputFormat { - case common.OutputFormatJSON: - err := json.NewEncoder(os.Stdout).Encode(uri.Data.URI) - if err != nil { - log.Fatal(err, "error encoding response to stdout") - } - case common.OutputFormatYAML: - err := yaml.NewEncoder(os.Stdout).Encode(uri.Data.URI) - if err != nil { - log.Fatal(err, "error encoding response to stdout") - } - case common.OutputFormatCSV, common.OutputFormatTable: - t := table.NewWriter() - t.SetOutputMirror(os.Stdout) - t.AppendHeader(table.Row{"URI"}) - t.AppendRow(table.Row{uri.Data.URI}) - if common.OutputFormat == common.OutputFormatCSV { - t.RenderCSV() - } else { - t.Render() - } - case common.OutputFormatQR, common.OutputFormatDefault: - qrterminal.Generate(uri.Data.URI, qrterminal.M, os.Stdout) - default: - log.Fatal("unsupported output format") - } - - if noWait { - return - } - - finish := getResponse(c, requestID) - if finish.Type == "linking_successful" { - log.Println("linking successful") - return - } - if finish.Type == "linking_error" { - log.Fatal("error from signald:", finish.Data.Message) - } else { - log.Fatal("unexpected message from signald:", finish.Data.Message) - } -} diff --git a/cmd/signaldctl/cmd/create/account/request-code.go b/cmd/signaldctl/cmd/create/account/request-code.go deleted file mode 100644 index 5d069b0..0000000 --- a/cmd/signaldctl/cmd/create/account/request-code.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright © 2021 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 account - -import ( - "log" - - "gitlab.com/signald/signald-go/cmd/signaldctl/common" - "gitlab.com/signald/signald-go/signald" - "gitlab.com/signald/signald-go/signald/client-protocol/v0" -) - -func requestCode() { - requestID := signald.GenerateID() - err := common.Signald.RawRequest(v0.LegacyRequest{ - Type: "register", - ID: requestID, - Username: phoneNumber, - Voice: voice, - }) - if err != nil { - log.Fatal("error sending request to signald: ", err) - } - c := make(chan v0.LegacyResponse) - go common.Signald.Listen(c) - response := getResponse(c, requestID) - if response.Type == "verification_required" { - log.Fatal("verification code requested. re-run with --verify") - } else { - log.Fatalf("unexpected response from signald when requesting verification code: %+v", response) - } -} diff --git a/cmd/signaldctl/cmd/create/account/verify.go b/cmd/signaldctl/cmd/create/account/verify.go deleted file mode 100644 index 97f1e64..0000000 --- a/cmd/signaldctl/cmd/create/account/verify.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright © 2021 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 account - -import ( - "log" - - "gitlab.com/signald/signald-go/cmd/signaldctl/common" - "gitlab.com/signald/signald-go/signald" - "gitlab.com/signald/signald-go/signald/client-protocol/v0" -) - -func verify() { - requestID := signald.GenerateID() - err := common.Signald.RawRequest(v0.LegacyRequest{ - Type: "verify", - ID: requestID, - Username: phoneNumber, - Code: code, - }) - if err != nil { - log.Fatal("error sending request to signald: ", err) - } - c := make(chan v0.LegacyResponse) - go common.Signald.Listen(c) - response := getResponse(c, requestID) - if response.Type == "verification_succeeded" { - log.Fatal("verification code requested. re-run with --verify") - } else { - log.Fatalf("unexpected response from signald when requesting verification code: %+v", response) - } -} diff --git a/cmd/signaldctl/cmd/get/group/group.go b/cmd/signaldctl/cmd/group/list/list-group.go similarity index 59% rename from cmd/signaldctl/cmd/get/group/group.go rename to cmd/signaldctl/cmd/group/list/list-group.go index b1d8c90..ccbadf8 100644 --- a/cmd/signaldctl/cmd/get/group/group.go +++ b/cmd/signaldctl/cmd/group/list/list-group.go @@ -13,7 +13,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -package group +package list import ( "encoding/json" @@ -29,41 +29,16 @@ import ( ) var ( - account string - groupID string - GetGroupCmd = &cobra.Command{ - Use: "group", - Aliases: []string{"groups"}, - Short: "return a list of Signal groups", + account string + ListGroupCmd = &cobra.Command{ + Use: "list", + Short: "return a list of Signal groups", Run: func(_ *cobra.Command, _ []string) { go common.Signald.Listen(nil) - var resp v1.GroupList - if len(groupID) == 0 || len(groupID) == 24 { - var err error - req := v1.ListGroupsRequest{Account: account} - resp, err = req.Submit(common.Signald) - if err != nil { - log.Fatal(err, "error communicating with signald") - } - - if len(groupID) == 24 { - for _, group := range resp.LegacyGroups { - if group.GroupId == groupID { - resp = v1.GroupList{LegacyGroups: []*v1.JsonGroupInfo{group}} - break - } - } - log.Fatal("group not found") - } - } else if len(groupID) == 44 { - req := v1.GetGroupRequest{Account: account, GroupID: groupID} - group, err := req.Submit(common.Signald) - if err != nil { - log.Fatal(err, "error communicating with signald") - } - resp = v1.GroupList{Groups: []*v1.JsonGroupV2Info{&group}} - } else { - log.Fatal("malformed group ID (expected length of 24 or 44)") + req := v1.ListGroupsRequest{Account: account} + resp, err := req.Submit(common.Signald) + if err != nil { + log.Fatal(err, "error communicating with signald") } switch common.OutputFormat { @@ -103,7 +78,6 @@ var ( ) func init() { - GetGroupCmd.Flags().StringVarP(&account, "account", "a", "", "the signald account to use") - GetGroupCmd.Flags().StringVarP(&groupID, "group-id", "g", "", "if set, fetches the latest state of a group from the server (local state is used for legacy groups). If unset, return all groups") - common.Must(GetGroupCmd.MarkFlagRequired("account")) + ListGroupCmd.Flags().StringVarP(&account, "account", "a", "", "the signald account to use") + common.Must(ListGroupCmd.MarkFlagRequired("account")) } diff --git a/cmd/signaldctl/cmd/create/root.go b/cmd/signaldctl/cmd/group/root.go similarity index 79% rename from cmd/signaldctl/cmd/create/root.go rename to cmd/signaldctl/cmd/group/root.go index e623c70..b1c760c 100644 --- a/cmd/signaldctl/cmd/create/root.go +++ b/cmd/signaldctl/cmd/group/root.go @@ -13,16 +13,19 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -package create +package group import ( "github.com/spf13/cobra" - "gitlab.com/signald/signald-go/cmd/signaldctl/cmd/create/account" + "gitlab.com/signald/signald-go/cmd/signaldctl/cmd/group/list" ) -var CreateCmd = &cobra.Command{Use: "create"} +var GroupCmd = &cobra.Command{ + Use: "group", + Aliases: []string{"groups"}, +} func init() { - CreateCmd.AddCommand(account.CreateAccountCmd) + GroupCmd.AddCommand(list.ListGroupCmd) } diff --git a/cmd/signaldctl/cmd/get/root.go b/cmd/signaldctl/cmd/message/root.go similarity index 74% rename from cmd/signaldctl/cmd/get/root.go rename to cmd/signaldctl/cmd/message/root.go index 47bff8f..d121601 100644 --- a/cmd/signaldctl/cmd/get/root.go +++ b/cmd/signaldctl/cmd/message/root.go @@ -13,18 +13,19 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -package get +package message import ( "github.com/spf13/cobra" - "gitlab.com/signald/signald-go/cmd/signaldctl/cmd/get/account" - "gitlab.com/signald/signald-go/cmd/signaldctl/cmd/get/group" + "gitlab.com/signald/signald-go/cmd/signaldctl/cmd/message/send" ) -var GetCmd = &cobra.Command{Use: "get"} +var MessageCmd = &cobra.Command{ + Use: "message", + Aliases: []string{"msg", "messages"}, +} func init() { - GetCmd.AddCommand(group.GetGroupCmd) - GetCmd.AddCommand(account.GetAccountCmd) + MessageCmd.AddCommand(send.SendMessageCmd) } diff --git a/cmd/signaldctl/cmd/message/send/send-message.go b/cmd/signaldctl/cmd/message/send/send-message.go new file mode 100644 index 0000000..8fac4b4 --- /dev/null +++ b/cmd/signaldctl/cmd/message/send/send-message.go @@ -0,0 +1,115 @@ +// Copyright © 2021 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 send + +import ( + "encoding/json" + "fmt" + "log" + "os" + + "github.com/jedib0t/go-pretty/v6/table" + "github.com/spf13/cobra" + "gopkg.in/yaml.v2" + + "gitlab.com/signald/signald-go/cmd/signaldctl/common" + "gitlab.com/signald/signald-go/signald/client-protocol/v1" +) + +var ( + account string + to string + message string + + SendMessageCmd = &cobra.Command{ + Use: "send", + Short: "send a message", + PreRun: func(_ *cobra.Command, _ []string) { + if account == "" { + log.Fatal("--account required") + } + if to == "" { + log.Fatal("--to required") + } + if message == "" { + log.Fatal("--message required") + } + }, + Run: func(_ *cobra.Command, _ []string) { + req := v1.SendRequest{ + Username: account, + MessageBody: message, + RecipientAddress: &v1.JsonAddress{Number: to}, + } + resp, err := req.Submit(common.Signald) + if err != nil { + log.Fatal("error sending request to signald: ", err) + } + switch common.OutputFormat { + case common.OutputFormatJSON: + err := json.NewEncoder(os.Stdout).Encode(resp) + if err != nil { + log.Fatal(err, "error encoding response to stdout") + } + case common.OutputFormatYAML: + err := yaml.NewEncoder(os.Stdout).Encode(resp) + if err != nil { + log.Fatal(err, "error encoding response to stdout") + } + case common.OutputFormatCSV, common.OutputFormatTable, common.OutputFormatDefault: + t := table.NewWriter() + t.SetOutputMirror(os.Stdout) + t.AppendHeader(table.Row{"Number", "UUID", "Duration", "Send Error"}) + for _, result := range resp.Results { + if result.Success != nil { + t.AppendRow(table.Row{ + result.Address.Number, + result.Address.UUID, + result.Success.Duration, + nil, + }) + } else { + var sendError string + if result.IdentityFailure != "" { + sendError = fmt.Sprintf("identity failure: %s\n", result.IdentityFailure) + } + if result.NetworkFailure { + sendError = "network failure" + } + if result.UnregisteredFailure { + sendError = "not on" + } + t.AppendRow(table.Row{result.Address.Number, result.Address.UUID, nil, sendError}) + } + } + + if common.OutputFormat == common.OutputFormatCSV { + t.RenderCSV() + } else { + t.Render() + } + default: + log.Fatal("Unsupported output format") + } + }, + } +) + +func init() { + SendMessageCmd.Flags().StringVarP(&account, "account", "a", "", "local account to use") + SendMessageCmd.Flags().StringVarP(&to, "to", "t", "", "account to send the message to") + SendMessageCmd.Flags().StringVarP(&message, "message", "m", "", "the body of the message to send") +} diff --git a/cmd/signaldctl/cmd/root.go b/cmd/signaldctl/cmd/root.go index 74fa33d..fca4194 100644 --- a/cmd/signaldctl/cmd/root.go +++ b/cmd/signaldctl/cmd/root.go @@ -23,8 +23,9 @@ import ( "github.com/spf13/cobra" "github.com/spf13/viper" - "gitlab.com/signald/signald-go/cmd/signaldctl/cmd/create" - "gitlab.com/signald/signald-go/cmd/signaldctl/cmd/get" + "gitlab.com/signald/signald-go/cmd/signaldctl/cmd/account" + "gitlab.com/signald/signald-go/cmd/signaldctl/cmd/group" + "gitlab.com/signald/signald-go/cmd/signaldctl/cmd/message" "gitlab.com/signald/signald-go/cmd/signaldctl/common" "gitlab.com/signald/signald-go/signald" ) @@ -59,9 +60,10 @@ func init() { cobra.OnInitialize(initConfig) RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.signaldctl.yaml)") RootCmd.PersistentFlags().StringVarP(&socketPath, "socket", "s", "/var/run/signald/signald.sock", "the path to the signald socket file") - RootCmd.PersistentFlags().StringVarP(&common.OutputFormat, "output-format", "o", "default", "the output format. Options are table (default), json or yaml") - RootCmd.AddCommand(get.GetCmd) - RootCmd.AddCommand(create.CreateCmd) + RootCmd.PersistentFlags().StringVarP(&common.OutputFormat, "output-format", "o", "default", "the output format. options are usually table, yaml and json, default is usually table. Some commands have other options.") + RootCmd.AddCommand(group.GroupCmd) + RootCmd.AddCommand(account.AccountCmd) + RootCmd.AddCommand(message.MessageCmd) } // initConfig reads in config file and ENV variables if set. diff --git a/cmd/signaldctl/common/signald.go b/cmd/signaldctl/common/signald.go index 3287838..95773e1 100644 --- a/cmd/signaldctl/common/signald.go +++ b/cmd/signaldctl/common/signald.go @@ -4,6 +4,7 @@ import ( "log" "gitlab.com/signald/signald-go/signald" + "gitlab.com/signald/signald-go/signald/client-protocol/v0" ) var ( @@ -17,3 +18,12 @@ func Must(err error) { log.Fatal(err) } } + +func GetResponse(c chan v0.LegacyResponse, id string) v0.LegacyResponse { + for { + message := <-c + if message.ID == id { + return message + } + } +}