diff --git a/main.go b/main.go index 30078e2..25aeb4b 100644 --- a/main.go +++ b/main.go @@ -1,24 +1,23 @@ package main import ( - "bufio" - "fmt" - "os" - "mailq-inspector/parser" + "bufio" + "fmt" + "mailq-inspector/parser" + "os" ) - 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) - } + // 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 index 30c043d..7b8220c 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -1,86 +1,86 @@ package parser import ( - "bufio" - "errors" - "fmt" - "regexp" - "strconv" - "strings" - "time" + "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 + 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)) + 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 + 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 + 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 }