#!/usr/bin/env amm import $ivy.`com.sun.mail:javax.mail:1.6.2` import $ivy.`com.lihaoyi::os-lib:0.8.1` import javax.mail.internet._ import os.up // paths val icon = "/usr/share/icons/Adwaita/48x48/actions/mail-message-new.png" val cacheFile = envPath("XDG_CACHE_HOME", os.home/".cache") / "seen-mails" val maildir = envPath("MAILDIR", os.home/"Mail") def from(msg: MimeMessage): String = msg.getFrom.headOption .map(_.asInstanceOf[InternetAddress]) .map(addr => Option(addr.getPersonal).map(_.replace("&", "&")).getOrElse(addr.getAddress)) .getOrElse("unknown") def subject(msg: MimeMessage): String = Option(msg.getSubject).map(_.replace("&", "&")).getOrElse("") case class MailInfo(from: String, subject: String, mailbox: String) object MailInfo: def fromPath(p: os.Path, maildir: os.Path) = val msg = readMessage(p) val address = msg.getFrom.head.asInstanceOf[InternetAddress] MailInfo( from(msg), subject(msg), (p/up/up relativeTo maildir).toString ) val session = javax.mail.Session.getDefaultInstance(new java.util.Properties) def readMessage(path: os.Path): MimeMessage = val in = os.read.inputStream(path) new MimeMessage(session, in) def envPath(envVar: String, default: os.Path): os.Path = sys.env.get(envVar).map(s => os.Path(s)).getOrElse(default) val cache = if (os.exists(cacheFile)) os.read.lines(cacheFile).toSet else Set.empty[String] val newMailPaths = os.proc("fd", "-t", "f" ,".*:2,[PRTDF]*$", "-a", maildir) .call().out.lines.toSet val unseenMailPaths = newMailPaths &~ cache val unseenMails = unseenMailPaths.map(p => MailInfo.fromPath(os.Path(p), maildir)) if !unseenMails.isEmpty then val markup = unseenMails.map(msg => s"${msg.from}: ${msg.subject}
").mkString os.proc("notify-send", s"--icon=$icon", "Mails", markup).call() os.write.over(cacheFile, newMailPaths.mkString("", "\n", "\n"))