diff --git a/cli/cli.go b/cli/cli.go index 7355ff3..8262e92 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -8,6 +8,7 @@ import ( "gopkg.in/readline.v1" "log" "os" + "strconv" "strings" ) @@ -51,6 +52,42 @@ func main() { } words := strings.SplitN(line.Line, " ", 1) + + if id, err := strconv.Atoi(words[0]); err == nil { + found := false + for _, contact := range c.Contacts { + if int(contact.Id) == id { + c.SetCurrentContact(contact) + found = true + break + } + } + + if !found { + fmt.Printf("no contact %d\n", id) + } + continue + } + + if c.CurrentContact != nil { + if len(words[0]) > 0 && words[0][0] == '/' { + words[0] = words[0][1:] + } else { + _, err := c.Backend.SendMessage(context.Background(), &rpc.Message{ + Sender: &rpc.Entity{IsSelf: true}, + Recipient: &rpc.Entity{ + ContactId: c.CurrentContact.Id, + Address: c.CurrentContact.Address, + }, + Text: line.Line, + }) + if err != nil { + fmt.Printf("send message error: %v\n", err) + } + continue + } + } + switch words[0] { case "clear": readline.ClearScreen(readline.Stdout) @@ -92,7 +129,7 @@ func main() { } fmt.Printf(". %s\n", strings.ToLower(status.String())) for _, contact := range contacts { - fmt.Printf("... %s\n", contact.Nickname) + fmt.Printf("... [%d] %s\n", contact.Id, contact.Nickname) } } diff --git a/cli/client.go b/cli/client.go index e473b0f..4c981d8 100644 --- a/cli/client.go +++ b/cli/client.go @@ -6,6 +6,7 @@ import ( "golang.org/x/net/context" "gopkg.in/readline.v1" "log" + "strings" ) type Client struct { @@ -18,6 +19,8 @@ type Client struct { // XXX threadsafety NetworkStatus ricochet.NetworkStatus Contacts []*ricochet.Contact + + CurrentContact *ricochet.Contact } // XXX need to handle backend connection loss/reconnection.. @@ -50,6 +53,22 @@ func (c *Client) Initialize() error { return nil } +func (c *Client) SetCurrentContact(contact *ricochet.Contact) { + c.CurrentContact = contact + if c.CurrentContact != nil { + config := *c.Input.Config + config.Prompt = fmt.Sprintf("%s > ", c.CurrentContact.Nickname) + config.UniqueEditLine = true + c.Input.SetConfig(&config) + fmt.Printf("--- %s (%s) ---\n", c.CurrentContact.Nickname, strings.ToLower(c.CurrentContact.Status.String())) + } else { + config := *c.Input.Config + config.Prompt = "> " + config.UniqueEditLine = false + c.Input.SetConfig(&config) + } +} + func (c *Client) monitorNetwork() { stream, err := c.Backend.MonitorNetwork(context.Background(), &ricochet.MonitorNetworkRequest{}) if err != nil { @@ -152,6 +171,10 @@ func (c *Client) monitorContacts() { log.Printf("updated contact: %v", contact) } + if c.CurrentContact != nil && c.CurrentContact.Id == contact.Id { + c.SetCurrentContact(contact) + } + case ricochet.ContactEvent_DELETE: if contact == nil { log.Printf("Ignoring contact delete event with null contact") @@ -173,6 +196,10 @@ func (c *Client) monitorContacts() { log.Printf("deleted contact: %v", contact) } + if c.CurrentContact != nil && c.CurrentContact.Id == contact.Id { + c.SetCurrentContact(nil) + } + default: log.Printf("Ignoring unknown contact event: %v", event) } @@ -197,6 +224,48 @@ func (c *Client) monitorConversations() { break } - log.Printf("Conversation event: %v", event) + // XXX Should also handle POPULATE + if event.Type != ricochet.ConversationEvent_RECEIVE && + event.Type != ricochet.ConversationEvent_SEND { + continue + } + + message := event.Msg + if message == nil || message.Recipient == nil || message.Sender == nil { + log.Printf("Ignoring invalid conversation event: %v", event) + continue + } + + var remoteContact *ricochet.Contact + var remoteEntity *ricochet.Entity + + if !message.Sender.IsSelf { + remoteEntity = message.Sender + } else { + remoteEntity = message.Recipient + } + + for _, contact := range c.Contacts { + if remoteEntity.ContactId == contact.Id && remoteEntity.Address == contact.Address { + remoteContact = contact + break + } + } + + if remoteContact == nil { + log.Printf("Ignoring conversation event with unknown contact: %v", event) + continue + } + + if remoteContact == c.CurrentContact { + // XXX so unsafe + if message.Sender.IsSelf { + fmt.Fprintf(c.Input.Stdout(), "\r%s > %s\n", remoteContact.Nickname, message.Text) + } else { + fmt.Fprintf(c.Input.Stdout(), "\r%s < %s\n", remoteContact.Nickname, message.Text) + } + } else if !message.Sender.IsSelf { + fmt.Fprintf(c.Input.Stdout(), "\r---- %s < %s\n", remoteContact.Nickname, message.Text) + } } }