package bot import "strings" // Command is a parsed "/name@target argument" line. type Command struct { // Name is the command without the leading slash, lowercased. Name string // Target is the bot username the command was addressed to, without the // "@", or "" when the user did not address anyone. Target string // Argument is everything after the command, trimmed. Argument string } // ParseCommand splits a message that starts with a slash. // // The "@username" suffix is not optional to handle. Telegram appends it // automatically whenever more than one bot is in a chat, so in exactly the busy // groups where the bot is most visible, every command arrives as // "/cep@thebotname 01001000". A bot that only matches the bare form looks broken // there. // // ok is false when the text is not a command at all. func ParseCommand(text string) (Command, bool) { trimmed := strings.TrimSpace(text) if !strings.HasPrefix(trimmed, "/") || len(trimmed) == 1 { return Command{}, false } head, argument, _ := strings.Cut(trimmed[1:], " ") name, target, _ := strings.Cut(head, "@") if name == "" { return Command{}, false } return Command{ Name: strings.ToLower(name), Target: target, Argument: strings.TrimSpace(argument), }, true } // AddressedTo reports whether the command is for the bot with this username. // // An unaddressed command counts as addressed: in a private chat nobody types // the suffix, and in a group with a single bot Telegram does not add it either. // A command addressed to some other bot is not ours, and answering it would put // two replies under one message. func (c Command) AddressedTo(username string) bool { return c.Target == "" || strings.EqualFold(c.Target, username) }