diff --git a/main.go b/main.go index 6ad7e27..b708f8e 100644 --- a/main.go +++ b/main.go @@ -7,7 +7,6 @@ import ( "os" "os/exec" "strconv" - "text/tabwriter" ) import ( @@ -30,10 +29,12 @@ func parseArguments() { mailqCommandPtr := flag.String("mailqCommand", "mailq", "Command to use for getting mailq output") mailqCommandArgsPtr := flag.String("mailqCommandArgs", "", "Optional arguments to pass to mailqCommand") interactivePtr := flag.Bool("interactive", false, "Set to true for shell mode") + machineFormatPtr := flag.Bool("machineFormat", false, "Set to true to get output suitable for cut/awk/...") flag.Parse() settings["mailqCommand"] = *mailqCommandPtr settings["mailqCommandArgs"] = *mailqCommandArgsPtr settings["interactive"] = strconv.FormatBool(*interactivePtr) + settings["machineFormat"] = strconv.FormatBool(*machineFormatPtr) } func interactiveShell() { @@ -49,35 +50,12 @@ func showQueue() { pagerReader, pagerWriter := io.Pipe() pagerDone := make(chan bool) go launchPager(pagerReader, pagerDone) - printQueueEntries(queue, pagerWriter) + queue.PrintHumanReadable(pagerWriter) pagerWriter.Close() // Wait for pager to be closed before continuing the main program <-pagerDone } -func fetchQueue() (parser.MailQ, error) { - if settings["mailqCommandArgs"] == "" { - return readFromCmd(exec.Command(settings["mailqCommand"])) - } else { - return readFromCmd(exec.Command(settings["mailqCommand"], settings["mailqCommandArgs"])) - } -} - -func printQueueEntries(queue parser.MailQ, writer io.Writer) { - fmt.Fprintf(writer, "%d entries total (%d active, %d deferred, %d on hold)\n\n", len(queue.Entries), queue.NumActive, queue.NumDeferred, queue.NumHold) - tabWriter := tabwriter.NewWriter(writer, 2, 2, 1, ' ', tabwriter.TabIndent) - fmt.Fprintf(tabWriter, "| %s\t| %s\t| %s\t| %s\t| %s\t| %s\t| %s\t| %s\t| \n", "Date", "Id", "Status", "Size", "Sender", "#", "First Recipient", "Reason") - for _, entry := range queue.Entries { - _, writeError := fmt.Fprintf(tabWriter, "| %s\t| %s\t| %s\t| %d\t| %s\t| {%d}\t| %s\t| %s\t| \n", entry.Date.Format(parser.SortableDateFormat), entry.Id, entry.Status, entry.Size, entry.Sender, len(entry.Recipients), entry.Recipients[0], entry.Reason) - if writeError != nil { - // A writeError is expected once the reader was closed - // This happens when the pager application got terminated - break - } - } - tabWriter.Flush() -} - func launchPager(reader *io.PipeReader, pagerDone chan<- bool) { cmd := exec.Command("less", "--chop-long-lines") cmd.Stdin = reader @@ -93,6 +71,14 @@ func launchPager(reader *io.PipeReader, pagerDone chan<- bool) { } } +func fetchQueue() (parser.MailQ, error) { + if settings["mailqCommandArgs"] == "" { + return readFromCmd(exec.Command(settings["mailqCommand"])) + } else { + return readFromCmd(exec.Command(settings["mailqCommand"], settings["mailqCommandArgs"])) + } +} + func readFromCmd(cmd *exec.Cmd) (parser.MailQ, error) { stdout, err := cmd.StdoutPipe() if err != nil { diff --git a/parser/parser.go b/parser/parser.go index 9b4921e..d9dc680 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -8,6 +8,7 @@ import ( "regexp" "strconv" "strings" + "text/tabwriter" "time" ) @@ -31,10 +32,6 @@ type MailQ struct { const SortableDateFormat = "2006-01-02 15:04:05" -func (m QEntry) ShortString() string { - return fmt.Sprintf("[%s] %s <%s> -> %d recipients (%d bytes)", m.Date.Format(SortableDateFormat), m.Id, m.Sender, len(m.Recipients), m.Size) -} - func (m QEntry) String() string { var recipientSuffix string if len(m.Recipients) > 1 { @@ -43,6 +40,10 @@ func (m QEntry) String() string { return fmt.Sprintf("[%s] %s <%s> -> {%d}<%s>%s (%s, %d bytes)", m.Date.Format(SortableDateFormat), m.Id, m.Sender, len(m.Recipients), m.Recipients[0], recipientSuffix, m.Status, m.Size) } +func (m QEntry) MachineReadableString() string { + return fmt.Sprintf("%s_%d_%s_%s_%s", m.Id, m.Status, m.Date.Format(SortableDateFormat), m.Size, m.Sender, m.Reason, strings.Join(m.Recipients, ",")) +} + func (m QEntry) DetailedString() string { var reasonStr string if m.Reason == "" { @@ -51,6 +52,30 @@ func (m QEntry) DetailedString() string { return fmt.Sprintf("Id: %s\nDate: %s\nStatus: %s\nReason: %s\nSize: %d\nSender: %s\nRecipients: %s", m.Id, m.Date.Format(SortableDateFormat), m.Status, reasonStr, m.Size, m.Sender, strings.Join(m.Recipients, ", ")) } +func (queue MailQ) PrintMachineReadable(writer io.Writer) { + for _, entry := range queue.Entries { + fmt.Fprintf(writer, "%s\n", entry.MachineReadableString()) + } +} + +func (queue MailQ) PrintHumanReadable(writer io.Writer) { + if len(queue.Entries) == 0 { + fmt.Fprintf(writer, "Mail queue is empty\n") + } else { + fmt.Fprintf(writer, "%d entries total (%d active, %d deferred, %d on hold)\n\n", len(queue.Entries), queue.NumActive, queue.NumDeferred, queue.NumHold) + tabWriter := tabwriter.NewWriter(writer, 2, 2, 1, ' ', tabwriter.TabIndent) + fmt.Fprintf(tabWriter, "| %s\t| %s\t| %s\t| %s\t| %s\t| %s\t| %s\t| %s\t| \n", "Date", "Id", "Status", "Size", "Sender", "#", "First Recipient", "Reason") + for _, entry := range queue.Entries { + _, writeError := fmt.Fprintf(tabWriter, "| %s\t| %s\t| %s\t| %d\t| %s\t| {%d}\t| %s\t| %s\t| \n", entry.Date.Format(SortableDateFormat), entry.Id, entry.Status, entry.Size, entry.Sender, len(entry.Recipients), entry.Recipients[0], entry.Reason) + if writeError != nil { + // A writeError is expected once the reader was closed + break + } + } + tabWriter.Flush() + } +} + func ParseMailQ(dataSource io.Reader) (MailQ, error) { const dateFormat = "2006 Mon Jan _2 15:04:05" var messageIdStart = regexp.MustCompile("^[0-9A-Za-z]+[*!]? ")