;;; nntodo.el --- Manage todo items with Gnus ;; Copyright (C) 1999 by Kai Grossjohann. ;; Authors: Kai.Grossjohann@CS.Uni-Dortmund.DE, ;; John Wiegley ;; Keywords: news, mail, calendar, convenience ;; Version: $Id: nntodo.el,v 1.3 2004/06/15 16:27:57 sigma Exp $ ;; This file is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; This file is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, ;; Boston, MA 02111-1307, USA. ;;; Commentary: ;; Warning: this is alpha code! Use at your own risk! Don your ;; asbestos longjohns! Might eat your mail for lunch! ;; This file provides a new Gnus backend, nntodo, for storing todo ;; items. Each todo item is a message but has a special header ;; `X-Todo-Priority' for the priority of a todo item. It is possible ;; to sort todo items by creation date and by priority. Sorting by ;; due date hasn't been done yet. ;;; Kudos: ;; Dan Nicolaescu for providing me with a first ;; implementation to look at and steal from. ;;; Code: ;;; Backend definition: (require 'nnheader) (require 'nnmail) (require 'gnus-start) (require 'nnmbox) (require 'nnoo) (require 'cl) (require 'gnus-sum) (nnoo-declare nntodo nnmbox) ;; If this variable isn't named nntodo-mbox-file, strange things ;; happen. This seems to be a nnoo-ey problem. (defvoo nntodo-mbox-file (expand-file-name (nnheader-concat gnus-home-directory ".nntodo")) "Name of the todo file in the user's home directory." nnmbox-mbox-file) ;; Similar. (defvoo nntodo-active-file (expand-file-name (nnheader-concat gnus-home-directory ".nntodo-active")) "Name of the actile file for the todo file." nnmbox-active-file) ;; Can we protect better? (defvoo nntodo-get-new-mail nil "Whether nntodo should get new mail. MUST be nil!" nnmbox-get-new-mail) (defvoo nntodo-current-group "" nil nnmbox-current-group) (defconst nntodo-version "1.4") (defvoo nntodo-status-string "" nil nnmbox-status-string) (nnoo-define-basics nntodo) ;; Too bad that nnmbox-create-mbox-file isn't nnoo'd. (deffoo nntodo-open-server (server &optional defs) (nnoo-change-server 'nntodo server defs) (nntodo-create-mbox-file) (cond ((not (file-exists-p nntodo-mbox-file)) (nntodo-close-server) (nnheader-report 'nntodo "No such file: %s" nntodo-mbox-file)) ((file-directory-p nntodo-mbox-file) (nntodo-close-server) (nnheader-report 'nntodo "Not a regular file: %s" nntodo-mbox-file)) (t (nnheader-report 'nntodo "Opened server %s using mbox %s" server nntodo-mbox-file) t))) ;; Copy of nnmbox-create-mbox-file, except for file name. (defun nntodo-create-mbox-file () (when (not (file-exists-p nntodo-mbox-file)) (nnmail-write-region 1 1 nntodo-mbox-file t 'nomesg))) ;; When creating a group, it gets some special settings (deffoo nntodo-request-create-group (group &optional server args) "Do whatever the nnmbox function does, then set a few group params." (nnoo-parent-function 'nntodo 'nnmbox-request-create-group (list group server args)) ;; Instead of setting these parameters for each group, isn't there a ;; way of somehow putting this into the server spec or into the ;; backend code? ;; Summary line looks different for todo items. (gnus-group-set-parameter (gnus-group-prefixed-name group (list "nntodo" server)) 'gnus-summary-line-format (list "%5N %U%R %7uT: %s\n")) ;; Why does the following not work? `gnus-post-method' is nil or ;; something like this in the message buffer after hitting `a' in an ;; nntodo group. (gnus-group-set-parameter (gnus-group-prefixed-name group (list "nntodo" server)) 'gnus-post-method '('current)) ;; Because the post method thing doesn't work, we need this. (gnus-group-set-parameter (gnus-group-prefixed-name group (list "nntodo" server)) 'gcc-self t) ;; default is to sort by priority, then by number (gnus-group-set-parameter (gnus-group-prefixed-name group (list "nntodo" server)) 'gnus-thread-sort-functions '('(gnus-thread-sort-by-number gnus-thread-sort-by-priority))) ;; Enter gnus-todo-mode in nntodo summaries. (gnus-group-set-parameter (gnus-group-prefixed-name group (list "nntodo" server)) 'dummy '( (gnus-todo-mode 1) ))) ;; Ask for priority when entering articles. (deffoo nntodo-request-accept-article (group &optional server last) "Add/modify priority header before storing the message." (let (prio) (save-restriction (message-narrow-to-headers-or-head) (unless (message-fetch-field "X-Todo-Priority") (setq prio (todo-gnus-get-priority prio)) (message-remove-header "X-Todo-Priority" nil nil) (mail-position-on-field "X-Todo-Priority") (insert prio)))) (nnoo-parent-function 'nntodo 'nnmbox-request-accept-article (list group server last))) (nnoo-import nntodo (nnmbox)) ;;; Utility code: ;; Hook nntodo backend into Gnus (unless (assoc "nntodo" gnus-valid-select-methods) (gnus-declare-backend "nntodo" 'post 'respool 'address)) ;;; Creating todo items: (defvar todo-gnus-priority-alist '(("high" . 0) ("medium" . 1) ("low" . 2)) "Association between prio names and values.") (defun todo-gnus-get-priority (&optional prio) "Read a priority from the minibuffer." (interactive) (unless prio (setq prio "medium")) (completing-read "Priority (medium): " todo-gnus-priority-alist nil ;predicate t ;require-match nil nil prio)) ;; The following section is gross. Isn't there a better way to do ;; this? Maybe specify a special sending function for nntodo groups? ;; But how? (defun todo-gnus-message-send-hook () "Inserts required headers in todo item." (when (and (boundp 'gnus-message-group-art) gnus-message-group-art (car gnus-message-group-art) (string-match "^nntodo\\>" (car gnus-message-group-art))) (message-remove-header "Newsgroups"))) (add-hook 'message-send-hook 'todo-gnus-message-send-hook) (add-to-list 'gnus-extra-headers 'X-Todo-Priority) (add-to-list 'nnmail-extra-headers 'X-Todo-Priority) ;;; Summary buffer: ;; This function is used in nntodo-request-create-group to set ;; `gnus-summary-line-format'. (defun gnus-user-format-function-T (head) (let* ((extra-headers (mail-header-extra head))) (cdr (assoc 'X-Todo-Priority extra-headers)))) ;; Sorting by priority. Code pretty much gleaned from gnus-sum.el ;; without any deeper understanding at all. (defun gnus-article-sort-by-priority (h1 h2) (let* ((e1 (mail-header-extra h1)) (e2 (mail-header-extra h2)) (p1 (cdr (assoc 'X-Todo-Priority e1))) (p2 (cdr (assoc 'X-Todo-Priority e2))) (n1 (cdr (assoc p1 todo-gnus-priority-alist))) (n2 (cdr (assoc p2 todo-gnus-priority-alist)))) (unless n1 (error "Unknown priority: %s" p1)) (unless n2 (error "Unknown priority: %s" p2)) (if (= n1 n2) (< (mail-header-number h1) (mail-header-number h2)) (< n1 n2)))) (defun gnus-thread-sort-by-priority (h1 h2) (gnus-article-sort-by-priority (gnus-thread-header h1) (gnus-thread-header h2))) (defun gnus-summary-sort-by-priority (&optional reverse) "Sort the summary buffer by priority. Argument REVERSE means reverse order." (interactive "P") (gnus-summary-sort 'priority reverse)) ;; Todo minor mode. ;; Gee, this seems to be simple with easy-mmode! (require 'easy-mmode) (defvar gnus-todo-mode-map (easy-mmode-define-keymap (list (cons (kbd "i n") (cons "Sort by number" 'gnus-summary-sort-by-number)) (cons (kbd "i p") (cons "Sort by priority" 'gnus-summary-sort-by-priority)) (cons (kbd "i i") (cons "Add new todo item" 'gnus-summary-post-news)) (cons (kbd "i d") (cons "Delete todo item" 'gnus-summary-delete-article))) "Todo")) (easy-mmode-define-minor-mode gnus-todo-mode "Minor mode for nntodo summary buffers. Without ARG, toggle gnus-todo-mode. With ARG, turn on iff ARG is positive, else turn off." nil " Todo" gnus-todo-mode-map) ;;; Epilog: (provide 'nntodo) ;;; nntodo.el ends here