diff --git a/mailcap.go b/mailcap.go index dd665e4..18cd244 100644 --- a/mailcap.go +++ b/mailcap.go @@ -19,34 +19,27 @@ import ( // contain options for various keys (test, view, edit, etc). type Entry map[string]string -// Entries is a slice of entries that gets used as a part of the Cap type -type Entries []Entry - -// Cap is a map of Entries and represents each mimetype and a slice of the -// various entries (programs) available for that mimetype. -type Cap map[string]Entries - // Mailcap is the main struct to interact with. It contains a Cap, as // caps, that represents the full mailcap db for the system. It has a // number of receivers to facilitate retrieving a command from a mimetype. type Mailcap struct { - Caps Cap + DB map[string][]Entry } // Creates and initializes the mailcap struct/db // and returns a pointer to Mailcap struct func NewMailcap() *Mailcap { - mc := Mailcap{make(Cap)} + mc := Mailcap{make(map[string][]Entry)} mc.getCaps() return &mc } -// Returns Entries for a given mimetype and an error or nil. -func (m *Mailcap) GetAllMime(mime string) (Entries, error) { - if v, ok := m.Caps[mime]; ok { +// Returns []Entry for a given mimetype and an error or nil. +func (m *Mailcap) GetAllMime(mime string) ([]Entry, error) { + if v, ok := m.DB[mime]; ok { return v, nil } - return make(Entries, 0), fmt.Errorf("Cannot find %s\n", mime) + return nil, fmt.Errorf("Cannot find %s\n", mime) } // Retrieves an Entry for a given mimetype and key. @@ -83,23 +76,22 @@ func (m *Mailcap) FindMatch(mime, key string, needsTerm bool) (Entry, error) { return v, nil } - return make(Entry), fmt.Errorf("Unable to find key %q in entries for %s", key, mime) + return nil, fmt.Errorf("Unable to find key %q in entries for %s", key, mime) } -// Called on an Entry type returned by FindMatch. Executes the -// program associated with the Entry. Calls the action that was -// set by FindMatch when generating the entry. If not action is -// set, SetAction will need to be called. A filepath string is -// passed to Execute in order to declare the target of the program -// being called. Returns an error or nil. -func (e Entry) Execute(path string) error { +// Called on an Entry type that has an action set (either by calling +// SetAction on the Entry or by it being returned by FindMatch. +// Returns a pointer to type exec.Command and an error (or nil). +// The caller needs to remember to set Std in/out/err on the returned +// Cmd as is needed by their use case. +func (e Entry) Command(path string) (*exec.Cmd, error) { key, ok := e["action"] if !ok { - return fmt.Errorf("No action has been set for this entry, was the entry returned by FindMatch?") + return nil, fmt.Errorf("No action has been set for this entry, use SetAction to set the action") } command, ok := e[key] if !ok { - return fmt.Errorf("Entry does not have the key %q", key) + return nil, fmt.Errorf("Entry does not have the key %q", key) } matchFields := strings.Fields(command) @@ -110,16 +102,7 @@ func (e Entry) Execute(path string) error { } c := exec.Command(matchFields[0], matchFields[1:]...) - c.Stdin = os.Stdin - c.Stdout = os.Stdout - c.Stderr = os.Stderr - - execErr := c.Run() - if execErr != nil { - return execErr - } - - return nil + return c, nil } // Sets the action (key) for the entry calling it. This action @@ -136,10 +119,11 @@ func (e Entry) SetAction(action string) error { return nil } -// Retrieve the command for a particular action as a string. -// The string will not have a path inserted into it and will have +// Retrieve the command string for a particular action. The +// string will not have a path inserted into it and will have // %s to represent the place that the path will go. -func (e Entry) GetCommand(action string) (string, error) { +// Returns a string and error (or nil). +func (e Entry) CommandString(action string) (string, error) { if v, ok := e[action]; ok { return v, nil } @@ -160,17 +144,17 @@ func (e Entry) Actions() []string { // Look up all of the Entry types available for // a given mime and key. Returns an Entry slice (Fields) -func (m *Mailcap) lookup(mime, key string) Entries { - f := make(Entries, 0, 5) - if val, ok := m.Caps[mime]; ok { +func (m *Mailcap) lookup(mime, key string) []Entry { + f := make([]Entry, 0, 5) + if val, ok := m.DB[mime]; ok { f = append(f, val...) } splitMime := strings.SplitN(mime,"/",2) catchAllMime := splitMime[0] + "/*" - if val, ok := m.Caps[catchAllMime]; ok && mime != catchAllMime { + if val, ok := m.DB[catchAllMime]; ok && mime != catchAllMime { f = append(f, val...) } - output := make(Entries, 0, len(f)) + output := make([]Entry, 0, len(f)) for _, v := range f { if _, ok := v[key]; ok { output = append(output, v) @@ -191,7 +175,7 @@ func (m *Mailcap) lookup(mime, key string) Entries { // Caps paramater of the Mailcap struct in question func (m *Mailcap) getCaps() { lnNum := 0 - moreCaps := make(Cap) + moreCaps := make(map[string][]Entry) for _, mailcapFile := range getMailcapFileList() { file, err := os.Open(mailcapFile) if err != nil { @@ -199,12 +183,12 @@ func (m *Mailcap) getCaps() { } moreCaps, lnNum = readMailcapFile(file, lnNum) for k, v := range moreCaps { - if _, ok := m.Caps[k]; ok { + if _, ok := m.DB[k]; ok { for _, item := range v { - m.Caps[k] = append(m.Caps[k], item) + m.DB[k] = append(m.DB[k], item) } } else { - m.Caps[k] = v + m.DB[k] = v } } file.Close() @@ -234,8 +218,8 @@ func getMailcapFileList() (mCapSlice []string) { // Reads an individual mailcap file and returns a Cap // and a line number -func readMailcapFile(f *os.File,ln int) (Cap, int) { - caps := make(Cap) +func readMailcapFile(f *os.File,ln int) (map[string][]Entry, int) { + caps := make(map[string][]Entry) reader := bufio.NewReader(f) for { l, e := reader.ReadString('\n') @@ -275,7 +259,7 @@ func readMailcapFile(f *os.File,ln int) (Cap, int) { if _, ok := caps[key]; ok { caps[key] = append(caps[key], fields) } else { - caps[key] = make(Entries,0,10) + caps[key] = make([]Entry,0,10) caps[key] = append(caps[key], fields) } } @@ -297,7 +281,7 @@ func parseLine(ln string) (string, Entry, error) { i += 1 } if len(fields) < 2 { - return "", outputFields,fmt.Errorf("Not enough fields present in line") + return "", nil,fmt.Errorf("Not enough fields present in line") } key, view := fields[0], fields[1] outputFields["view"] = view