github.com/keybase/client/go@v0.0.0-20240520164431-4f512a4c85a3/client/chat_send_common.go (about) 1 // Copyright 2016 Keybase, Inc. All rights reserved. Use of 2 // this source code is governed by the included BSD license. 3 4 package client 5 6 import ( 7 "fmt" 8 "time" 9 10 "golang.org/x/net/context" 11 12 "github.com/keybase/client/go/libkb" 13 "github.com/keybase/client/go/protocol/chat1" 14 "github.com/keybase/client/go/protocol/gregor1" 15 "github.com/keybase/client/go/protocol/keybase1" 16 ) 17 18 type ChatSendArg struct { 19 resolvingRequest chatConversationResolvingRequest 20 21 // Only one of these should be set 22 message string 23 setTopicName string 24 setHeadline string 25 clearHeadline bool 26 deleteHistory *chat1.MessageDeleteHistory 27 ephemeralLifetime time.Duration 28 29 hasTTY bool 30 nonBlock bool 31 team bool // TODO is this field used? 32 mustNotExist bool 33 } 34 35 func chatSend(ctx context.Context, g *libkb.GlobalContext, c ChatSendArg) error { 36 resolver, err := newChatConversationResolver(g) 37 if err != nil { 38 return err 39 } 40 41 createIfNotExists := true 42 if c.clearHeadline || c.deleteHistory != nil { 43 createIfNotExists = false 44 } 45 conversation, userChosen, err := resolver.Resolve(ctx, c.resolvingRequest, chatConversationResolvingBehavior{ 46 CreateIfNotExists: createIfNotExists, 47 MustNotExist: c.mustNotExist, 48 Interactive: c.hasTTY, 49 IdentifyBehavior: keybase1.TLFIdentifyBehavior_CHAT_CLI, 50 }) 51 switch err.(type) { 52 case nil: 53 case libkb.ResolutionError: 54 return fmt.Errorf("could not resolve `%s` into Keybase user(s) or a team", c.resolvingRequest.TlfName) 55 default: 56 return err 57 } 58 conversationInfo := conversation.Info 59 60 var arg chat1.PostLocalArg 61 arg.ConversationID = conversationInfo.Id 62 arg.IdentifyBehavior = keybase1.TLFIdentifyBehavior_CHAT_CLI 63 64 var msg chat1.MessagePlaintext 65 // msgV1.ClientHeader.{Sender,SenderDevice} are filled by service 66 msg.ClientHeader.Conv = conversationInfo.Triple 67 msg.ClientHeader.TlfName = conversationInfo.TlfName 68 msg.ClientHeader.TlfPublic = (conversationInfo.Visibility == keybase1.TLFVisibility_PUBLIC) 69 70 // Whether the user is really sure they want to send to the selected conversation. 71 // We require an additional confirmation if the choose menu was used. 72 confirmed := !userChosen 73 74 // Do one of set topic name, set headline, or send message 75 switch { 76 case c.setTopicName != "": 77 msg.ClientHeader.MessageType = chat1.MessageType_METADATA 78 msg.MessageBody = chat1.NewMessageBodyWithMetadata(chat1.MessageConversationMetadata{ConversationTitle: c.setTopicName}) 79 case c.setHeadline != "": 80 msg.ClientHeader.MessageType = chat1.MessageType_HEADLINE 81 msg.MessageBody = chat1.NewMessageBodyWithHeadline(chat1.MessageHeadline{Headline: c.setHeadline}) 82 case c.clearHeadline: 83 msg.ClientHeader.MessageType = chat1.MessageType_HEADLINE 84 msg.MessageBody = chat1.NewMessageBodyWithHeadline(chat1.MessageHeadline{Headline: ""}) 85 case c.deleteHistory != nil: 86 msg.ClientHeader.MessageType = chat1.MessageType_DELETEHISTORY 87 msg.ClientHeader.DeleteHistory = c.deleteHistory 88 msg.MessageBody = chat1.NewMessageBodyWithDeletehistory(*c.deleteHistory) 89 default: 90 // Ask for message contents 91 if len(c.message) == 0 { 92 promptText := "Please enter message content: " 93 if !confirmed { 94 promptText = fmt.Sprintf("Send to [%s]? Hit Ctrl-C to cancel, or enter message content to send: ", conversationInfo.TlfName) 95 } 96 c.message, err = g.UI.GetTerminalUI().Prompt(PromptDescriptorEnterChatMessage, promptText) 97 if err != nil { 98 return err 99 } 100 confirmed = true 101 } 102 if c.ephemeralLifetime != 0 { 103 lifetime := gregor1.ToDurationSec(c.ephemeralLifetime) 104 msg.ClientHeader.EphemeralMetadata = &chat1.MsgEphemeralMetadata{Lifetime: lifetime} 105 } 106 107 msg.ClientHeader.MessageType = chat1.MessageType_TEXT 108 msg.MessageBody = chat1.NewMessageBodyWithText(chat1.MessageText{Body: c.message}) 109 } 110 111 if !confirmed { 112 promptText := fmt.Sprintf("Send to [%s]? Hit Ctrl-C to cancel, or enter to send.", conversationInfo.TlfName) 113 _, err = g.UI.GetTerminalUI().Prompt(PromptDescriptorEnterChatMessage, promptText) 114 if err != nil { 115 return err 116 } 117 } 118 119 arg.Msg = msg 120 121 if c.nonBlock { 122 var nbarg chat1.PostLocalNonblockArg 123 nbarg.ConversationID = arg.ConversationID 124 nbarg.Msg = arg.Msg 125 nbarg.IdentifyBehavior = arg.IdentifyBehavior 126 if _, err = resolver.ChatClient.PostLocalNonblock(ctx, nbarg); err != nil { 127 return err 128 } 129 } else { 130 if _, err = resolver.ChatClient.PostLocal(ctx, arg); err != nil { 131 return err 132 } 133 } 134 135 return nil 136 }