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  }