summary refs log blame commit diff stats
path: root/commands/commands.go
blob: 04462d2acbc4ff24b158d3b5dd43593ee5d75c10 (plain) (tree)
1
2
3
4
5
6
7
8
9
10




                

                                 
                                          

 
                                                              
 
                                    
 




















                                                              

 
                                                                            






                                                        
                                               
                                     
         
                                     
 
package commands

import (
	"errors"

	"github.com/google/shlex"

	"git.sr.ht/~sircmpwn/aerc/widgets"
)

type AercCommand func(aerc *widgets.Aerc, args []string) error

type Commands map[string]AercCommand

func NewCommands() *Commands {
	cmds := Commands(make(map[string]AercCommand))
	return &cmds
}

func (cmds *Commands) dict() map[string]AercCommand {
	return map[string]AercCommand(*cmds)
}

func (cmds *Commands) Register(name string, cmd AercCommand) {
	cmds.dict()[name] = cmd
}

type NoSuchCommand string

func (err NoSuchCommand) Error() string {
	return "Unknown command " + string(err)
}

type CommandSource interface {
	Commands() *Commands
}

func (cmds *Commands) ExecuteCommand(aerc *widgets.Aerc, cmd string) error {
	args, err := shlex.Split(cmd)
	if err != nil {
		return err
	}
	if len(args) == 0 {
		return errors.New("Expected a command.")
	}
	if fn, ok := cmds.dict()[args[0]]; ok {
		return fn(aerc, args)
	}
	return NoSuchCommand(args[0])
}
// Check for fmt flags if ni == len(format) { goto handle_end_error } c = rune(format[ni]) if c == '+' || c == '-' || c == '#' || c == ' ' || c == '0' { ni++ } // Check for precision and width if ni == len(format) { goto handle_end_error } c = rune(format[ni]) for unicode.IsDigit(c) { ni++ c = rune(format[ni]) } if c == '.' { ni++ c = rune(format[ni]) for unicode.IsDigit(c) { ni++ c = rune(format[ni]) } } retval = append(retval, []byte(format[i:ni])...) // Get final format verb if ni == len(format) { goto handle_end_error } c = rune(format[ni]) switch c { case '%': retval = append(retval, '%') case 'a': if len(msg.Envelope.From) == 0 { return "", nil, errors.New("found no address for sender") } addr := msg.Envelope.From[0] retval = append(retval, 's') args = append(args, fmt.Sprintf("%s@%s", addr.MailboxName, addr.HostName)) case 'A': var addr *imap.Address if len(msg.Envelope.ReplyTo) == 0 { if len(msg.Envelope.From) == 0 { return "", nil, errors.New("found no address for sender or reply-to") } else { addr = msg.Envelope.From[0] } } else { addr = msg.Envelope.ReplyTo[0] } retval = append(retval, 's') args = append(args, fmt.Sprintf("%s@%s", addr.MailboxName, addr.HostName)) case 'C': retval = append(retval, 'd') args = append(args, number) case 'd': retval = append(retval, 's') args = append(args, msg.InternalDate.Format(conf.Ui.TimestampFormat)) case 'D': retval = append(retval, 's') args = append(args, msg.InternalDate.Local().Format(conf.Ui.TimestampFormat)) case 'f': if len(msg.Envelope.From) == 0 { return "", nil, errors.New("found no address for sender") } addr := FormatAddress(msg.Envelope.From[0]) retval = append(retval, 's') args = append(args, addr) case 'F': if len(msg.Envelope.From) == 0 { return "", nil, errors.New("found no address for sender") } addr := msg.Envelope.From[0] // TODO: handle case when sender is current user. Then // use recipient's name var val string if addr.PersonalName != "" { val = addr.PersonalName } else { val = fmt.Sprintf("%s@%s", addr.MailboxName, addr.HostName) } retval = append(retval, 's') args = append(args, val) case 'i': retval = append(retval, 's') args = append(args, msg.Envelope.MessageId) case 'n': if len(msg.Envelope.From) == 0 { return "", nil, errors.New("found no address for sender") } addr := msg.Envelope.From[0] var val string if addr.PersonalName != "" { val = addr.PersonalName } else { val = fmt.Sprintf("%s@%s", addr.MailboxName, addr.HostName) } retval = append(retval, 's') args = append(args, val) case 'r': addrs := FormatAddresses(msg.Envelope.To) retval = append(retval, 's') args = append(args, addrs) case 'R': addrs := FormatAddresses(msg.Envelope.Cc) retval = append(retval, 's') args = append(args, addrs) case 's': retval = append(retval, 's') args = append(args, msg.Envelope.Subject) case 'u': if len(msg.Envelope.From) == 0 { return "", nil, errors.New("found no address for sender") } addr := msg.Envelope.From[0] retval = append(retval, 's') args = append(args, addr.MailboxName) case 'v': if len(msg.Envelope.From) == 0 { return "", nil, errors.New("found no address for sender") } addr := msg.Envelope.From[0] // check if message is from current user if addr.PersonalName != "" { retval = append(retval, 's') args = append(args, strings.Split(addr.PersonalName, " ")[0]) } case 'Z': // calculate all flags var readFlag = "" var delFlag = "" var flaggedFlag = "" for _, flag := range msg.Flags { if flag == imap.SeenFlag { readFlag = "O" // message is old } else if flag == imap.RecentFlag { readFlag = "N" // message is new } else if flag == imap.AnsweredFlag { readFlag = "r" // message has been replied to } if flag == imap.DeletedFlag { delFlag = "D" // TODO: check if attachments } if flag == imap.FlaggedFlag { flaggedFlag = "!" } // TODO: check gpg stuff } retval = append(retval, '3', 's') args = append(args, readFlag+delFlag+flaggedFlag) // Move the below cases to proper alphabetical positions once // implemented case 'l': // TODO: number of lines in the message retval = append(retval, 'd') args = append(args, msg.Size) case 'e': // TODO: current message number in thread fallthrough case 'E': // TODO: number of messages in current thread fallthrough case 'H': // TODO: spam attribute(s) of this message fallthrough case 'L': // TODO: fallthrough case 'X': // TODO: number of attachments fallthrough case 'y': // TODO: X-Label field fallthrough case 'Y': // TODO: X-Label field and some other constraints fallthrough default: // Just ignore it and print as is // so %k in index format becomes %%k to Printf retval = append(retval, '%') retval = append(retval, byte(c)) } i = ni + 1 } return string(retval), args, nil handle_end_error: return "", nil, errors.New("reached end of string while parsing index format") }