package mailcap import ( "os" "strings" "fmt" "bufio" ) type Entry map[string]string type Fields []Entry type Cap map[string]Fields type Mailcap struct { Caps Cap } func NewMailcap() *Mailcap { mc := Mailcap{Caps{}} mc.getCaps() return &mc } (m *Mailcap) func ShowAll() { fmt.Print(m.Caps) } (m *Mailcap) func Show(mime string) { if v, ok := m.Caps["mime"] { fmt.Println(mime + ":") fmt.Print(v) } else { fmt.Printf("Cannot find %s\n", mime) } } (m *Mailcap) func getCaps() { lnNum := 0 for mailcapFile := range getMailcapFileList() { file, err := os.Open(mailcapFile) if err != nil { continue } moreCaps, lnNum, err := readMailcapFile(file, lnNum) for k, v := range moreCaps { if v, ok := m.Caps[key]; ok { m.Caps[key] = m.Caps[key] + value } else { m.Caps[key] = value } } file.close() } } // Retrieve a slice of strings with all mailcap files // found on the system. func getMailcapFileList() (mCapSlice []string) { var home string = "." if val, ok := os.LookupEnv('MAILCAPS'); ok { mCapSlice = strings.Split(val, string(os.PathListSeparator)) } else { if val, ok := os.LookupEnv('HOME'); ok { home = val } mCapSlice = []string{ home + "/.mailcap", "/etc/mailcap", "/usr/etc/mailcap", "/usr/local/etc/mailcap" } } } func readMailcapFile(f *os.File,ln int) (Cap, int) { caps := Cap{} reader := bufio.NewReader(f) for { l, e := reader.ReadString('\n') if e != nil || l[0] == '#' || strings.TrimSpace(l) == "" { continue } // Handle continuations for long lines nxtLn := l for ;nxtLn[len(nxtLn)-3:] == "\\\n"; { nxtLn, er = reader.ReadString('\n') if er != nil || strings.TrimSpace(nxtLn) == "" { nxtLn = "\n" } l = l[:len(l)-2] + nxtLn } // Parse the line key, fields, err := parseLine(l) if err != nil { continue } if ln >= 0 { fields["lineno"] = ln ln += 1 } types := strings.Split(key, "/") for t := range types { t = strings.TrimSpace(t) } key = strings.Join(types, "/") key = strings.ToLower(key) if _, ok := caps[key] { append(caps[key], fields) } else { caps[key] = fields } return caps, ln } } func parseLine(ln) (string, Entry, error) { outputFields := Entry{} i := 0 n := len(ln) fields := make([]string, 0, 10) for ;i < n; { field, i = parseField(ln, i, n) append(fields, field) i += 1 } if len(fields) < 2 { return "", outputFields,fmt.Errorf("Not enough fields present in line") } key, view := fields[0], fields[1] outputFields["view"] = view rest := make([]string,0,0) if len(fields) > 2 { rest = fields[2:] } for f := range rest { var fkey, fvalue string i = string.Index(f, r"=") if i < 0 { fkey = f fvalue = "" } else { fkey = strings.TrimSpace(f[:i]) fvalue = strings.TrimSpace(f[i+1:]) } if _, ok := outputFields[fkey]; !ok { // If the key doesnt exist in the map, add it outputFields[fkey] = fvalue } } return key, outputFields, nil } func parseField(ln string, i, n int) (string, int) { // get one key-value pair from mailcap entry start := i for ;i < n; { c := ln[i] if c == ';' { break } else if c == '\\' { i += 2 } else { i += 1 } } return strings.TrimSpace(line[start:i]), i }