// updateTray is called whenever a client detects that the number of unseen // messages *may* have changed. It will search the selected folder for unseen // messages, count them and store the result. Then it will use the notify // channel to let our main process update the status icon. func UpdateTray(c *imap.Client, notify chan bool, name string) { // Send > Search since Search adds CHARSET UTF-8 which might not be supported cmd, err := c.Send("SEARCH", "UNSEEN") if err != nil { fmt.Printf("%s failed to look for new messages\n", name) fmt.Println(" ", err) return } if _, ok := Unseen[name]; !ok { Unseen[name] = []uint32{} } unseenMessages := []uint32{} for cmd.InProgress() { // Wait for the next response (no timeout) err = c.Recv(-1) // Process command data for _, rsp := range cmd.Data { result := rsp.SearchResults() unseenMessages = append(unseenMessages, result...) } // Reset for next run cmd.Data = nil c.Data = nil } // Check command completion status if rsp, err := cmd.Result(imap.OK); err != nil { if err == imap.ErrAborted { fmt.Println("fetch command aborted") } else { fmt.Println("fetch error:", rsp.Info) } return } fmt.Printf("%d unseen\n", len(unseenMessages)) // Find messages that the user hasn't been notified of // TODO: Make this optional/configurable newUnseen, _ := imap.NewSeqSet("") numNewUnseen := 0 for _, uid := range unseenMessages { seen := false for _, olduid := range Unseen[name] { if olduid == uid { seen = true break } } if !seen { newUnseen.AddNum(uid) numNewUnseen++ } } // If we do have new unseen messages, fetch and display them if numNewUnseen > 0 { messages := make([]string, numNewUnseen) i := 0 // Fetch headers... cmd, _ = c.Fetch(newUnseen, "RFC822.HEADER") for cmd.InProgress() { c.Recv(-1) for _, rsp := range cmd.Data { header := imap.AsBytes(rsp.MessageInfo().Attrs["RFC822.HEADER"]) if msg, _ := mail.ReadMessage(bytes.NewReader(header)); msg != nil { subject := msg.Header.Get("Subject") messages[i], err = new(mime.WordDecoder).DecodeHeader(subject) if err != nil { messages[i] = subject } i++ } } cmd.Data = nil c.Data = nil } // Print them in reverse order to get newest first notification := "" for ; i > 0; i-- { notification += "> " + messages[i-1] + "\n" } notification = strings.TrimRight(notification, "\n") fmt.Println(notification) // And send them with notify-send! title := fmt.Sprintf("%s has new mail (%d unseen)", name, len(unseenMessages)) sh := exec.Command("/usr/bin/notify-send", "-i", "notification-message-email", "-c", "email", title, notification) err := sh.Start() if err != nil { fmt.Println("Failed to notify user...") fmt.Println(err) } go func() { // collect exit code to avoid zombies sh.Wait() }() } Unseen[name] = unseenMessages // Let main process know something has changed notify <- true }