;;; imapcount.el --- get inbox count from imap server for mode line ;; Author: Noah Friedman ;; Created: 2019-05-05 ;; Public domain. ;; $Id: imapcount.el,v 1.5 2019/05/24 19:58:20 friedman Exp $ ;;; Commentary: ;; Use the command `imapcount-start' to start using this mode ;; The command `imapcount-stop' will disable checking mail count. ;; Things to consider for the future: ;; * handle count for more than one folder ;; * display count of only new messages ;;; Code: (require 'imap) (require 'auth-source) (defgroup imapcount nil "get inbox count from imap server for mode line" :group 'extensions) (defcustom imapcount-server '("localhost" 993 tls login) "List of the form \(SERVER PORT STREAM AUTH\) See function `imap-open' for details." :type 'list :group 'imapcount) (defcustom imapcount-user (user-login-name) "User name for imap login" :type 'string :group 'imapcount) (defcustom imapcount-pass nil "User password for imap plain auth login" :type '(choice string function) :group 'imapcount) (defcustom imapcount-folder "INBOX" "IMAP folder to watch" :type 'string :group 'imapcount) (defcustom imapcount-mail-string-format "M:%s" "Mode line format for message count, when non-zero. If there are no messages, mode string is empty." :type 'string :group 'imapcount) (defvar imapcount-process-buffer nil) (defvar imapcount-last-error nil) ;; for debugging ;;;###autoload (defun imapcount-start () "Connect to IMAP server and begin checking folder message count. Server and connection parameters are specified by `imapcount-server'. Username is specified by `imapcount-user'. Password is specified by `imapcount-pass'. If this is nil, the user will be queried interactively. Mailbox name is specified by `imapcount-folder'. Format of mode line by `imapcount-mail-string-format'. A mode value of \"?\" indicates some error communicating with the imap server. Inspect the variable `imapcount-last-error' for possible useful details, and use the debugging facilities in the `imap' package for further analysis. Typically, it's just a lost connection and you can restart it by running this command again. Use \\[imapcount-stop] to end mailbox monitoring." (interactive) (imapcount-stop) (setq imapcount-process-buffer (get-buffer (apply 'imap-open imapcount-server))) (let ((proc (get-buffer-process imapcount-process-buffer))) (if (fboundp 'set-process-query-on-exit-flag) ;; New as of v22 (set-process-query-on-exit-flag proc nil) (process-kill-without-query proc))) (imap-authenticate imapcount-user (imapcount-get-pass) imapcount-process-buffer) (setq display-time-mail-function 'imapcount-set-mail-string) (display-time-update)) (defun imapcount-stop () "Terminate IMAP connection, if any, and clear mode line mail count" (interactive) (when (eq display-time-mail-function 'imapcount-set-mail-string) (setq display-time-mail-function nil display-time-mail-string nil) (display-time-update)) (if (imapcount-process-buffer-live-p) (imap-close imapcount-process-buffer)) (if imapcount-process-buffer (kill-buffer imapcount-process-buffer)) (setq imapcount-process-buffer nil imapcount-last-error nil)) (defun imapcount-get-pass () (cond ((stringp imapcount-pass) imapcount-pass) ((and imapcount-pass (or (symbolp imapcount-pass) (functionp imapcount-pass))) (funcall imapcount-pass)) (t (let* ((port (nth 1 imapcount-server)) (auth-source-do-cache nil) (auth-source-creation-prompts '((secret . "IMAP password for %u@%h:%p: "))) (auth-info (car (auth-source-search :host (nth 0 imapcount-server) :port (format "%s" port) :user imapcount-user :require '(:host :port :user :secret) :max 1 :create t))) (save-function (plist-get auth-info :save-function)) (pass (plist-get auth-info :secret))) (if save-function (funcall save-function)) (if (functionp pass) (funcall pass) pass))))) (defun imapcount-process-buffer-live-p () (and imapcount-process-buffer (buffer-live-p imapcount-process-buffer) (process-live-p (get-buffer-process imapcount-process-buffer)))) (defun imapcount-message-count () (condition-case err (imap-mailbox-status imapcount-folder 'messages imapcount-process-buffer) (error (progn (setq imapcount-last-error (cdr err)) "?")))) (defun imapcount-set-mail-string () (let ((count (imapcount-message-count))) (if (member count '(0 "")) (setq display-time-mail-string nil) (setq display-time-mail-string (format imapcount-mail-string-format count))))) (provide 'imapcount) ;; imapcount.el ends here