From 2a26e4fb3ae3ce827839e6b3eaf4dbab2ed86232 Mon Sep 17 00:00:00 2001 From: Jan Philipp Timme Date: Sat, 29 Dec 2018 01:42:50 +0100 Subject: [PATCH] Initial import --- main.go | 24 ++++++++++++++ parser/parser.go | 86 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 main.go create mode 100644 parser/parser.go diff --git a/main.go b/main.go new file mode 100644 index 0000000..30078e2 --- /dev/null +++ b/main.go @@ -0,0 +1,24 @@ +package main + +import ( + "bufio" + "fmt" + "os" + "mailq-inspector/parser" +) + + +func main() { + // Read data from stdin + scanner := bufio.NewScanner(os.Stdin) + entries, err := parser.ParseMailQ(scanner) + if err != nil { + fmt.Printf("Got error from parser: %s\n", err.Error()) + os.Exit(1) + } else { + for _, entry := range entries { + fmt.Printf("%s\n", entry.String()) + } + os.Exit(0) + } +} diff --git a/parser/parser.go b/parser/parser.go new file mode 100644 index 0000000..30c043d --- /dev/null +++ b/parser/parser.go @@ -0,0 +1,86 @@ +package parser + +import ( + "bufio" + "errors" + "fmt" + "regexp" + "strconv" + "strings" + "time" +) + +type Entry struct { + id string + status string + date time.Time + size int + sender string + recipients []string + reason string +} + +func (m Entry) String() string { + return fmt.Sprintf("ID: %s, Status: %s, Size: %d bytes, Sender: %s, Recipients: %d", m.id, m.status, m.size, m.sender, len(m.recipients)) +} + +func ParseMailQ(scanner *bufio.Scanner) ([]Entry, error) { + const dateFormat = "2006 Mon Jan _2 15:04:05" + var messageIdStart = regexp.MustCompile("^[0-9A-Za-z]+[*!]? ") + scanner.Scan() + line := scanner.Text() + if strings.HasPrefix(line, "Mail queue is empty") { + // If mail queue is empty, there is nothing to do + return nil, errors.New(line) + } else if strings.HasPrefix(line, "-Queue ID-") == false { + // Abort if input does not look like output from mailq(1) + return nil, errors.New("Sorry, this does not look like output from mailq(1).") + } + var currentMail Entry + var queueEntries []Entry + + for scanner.Scan() { + // Read input line by line + line := scanner.Text() + fields := strings.Fields(line) + if strings.HasPrefix(line, "--") { + // Handle the summary line at the end of mailq output + break + } else if messageIdStart.MatchString(line) { + // Handle line starting next mail in queue + messageId := fields[0] + if strings.HasSuffix(messageId, "*") { + currentMail.status = "active" + } else if strings.HasSuffix(messageId, "!") { + currentMail.status = "hold" + } else { + currentMail.status = "deferred" + } + dateString := strconv.Itoa(time.Now().Year()) + " " + strings.Join(fields[2:6], " ") + mailDate, _ := time.Parse(dateFormat, dateString) + currentMail.id = strings.TrimRight(messageId, "*!") + currentMail.size, _ = strconv.Atoi(fields[1]) + currentMail.date = mailDate + currentMail.sender = fields[6] + continue + } else if strings.HasPrefix(line, "(") && strings.HasSuffix(line, ")") { + // Handle reason for deferred status (if deferred at all, may be missing) + currentMail.reason = strings.Trim(strings.TrimSpace(line), "()") + continue + } else if len(fields) == 1 { + // Handle line with one of the mail recipients + currentMail.recipients = append(currentMail.recipients, fields[0]) + continue + } else if len(fields) == 0 { + // If the next line is empty, make sure to push current mail to list + // and create a new struct for the next mail to process + queueEntries = append(queueEntries, currentMail) + currentMail = Entry{} + } + } + if scanner.Err() != nil { + // If the scanner failed, let our caller know. + return nil, errors.New("Something went wrong with reading from stdin. Sorry!") + } + return queueEntries, nil +}