;;; gnus-diary.el --- Wrapper around the NNDiary Gnus backend
-;; Copyright (C) 1999 Didier Verna.
-
-;; PRCS: $Id: gnus-diary.el 1.8 Tue, 04 Sep 2001 11:32:13 +0200 didier $
+;; Copyright (c) 2001, 2002, 2003 Free Software Foundation, Inc.
+;; Copyright (C) 1999, 2000, 2001 Didier Verna.
;; Author: Didier Verna <didier@xemacs.org>
;; Maintainer: Didier Verna <didier@xemacs.org>
-;; Created: Tue Jul 20 10:42:55 1999 under XEmacs 21.2 (beta 18)
-;; Last Revision: Wed Aug 8 14:38:14 2001
+;; Created: Tue Jul 20 10:42:55 1999
;; Keywords: calendar mail news
-;; This file is part of NNDiary.
+;; This file is part of GNU Emacs.
-;; NNDiary 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 of the License, or
-;; (at your option) any later version.
+;; GNU Emacs 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 of the License,
+;; or (at your option) any later version.
-;; NNDiary 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.
+;; GNU Emacs 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 this program; if not, write to the Free Software
;; ===========
;; Gnus-Diary is a wrapper around the NNDiary Gnus backend. It is here to
-;; make your nndiary-user life easier in differnet ways. So, you don't have
+;; make your nndiary-user life easier in different ways. So, you don't have
;; to use it if you don't want to. But, really, you should.
-;; Gnus-Diary offers the following improvements on top of the NNDiary backend:
+;; Gnus-Diary offers the following features on top of the NNDiary backend:
-;; - A nice summary line format:
-;; Displaying diary messages in standard summary line format (usually
-;; something like "<From Joe>: <Subject>") is pretty useless. Most of the
-;; time, you're the one who wrote the message, and you mostly want to see
-;; the event's date. Gnus-Diary offers you a nice summary line format which
-;; will do this. By default, a summary line will appear like this:
+;; - A nice summary line format:
+;; Displaying diary messages in standard summary line format (usually
+;; something like "<From Joe>: <Subject>") is pretty useless. Most of the
+;; time, you're the one who wrote the message, and you mostly want to see
+;; the event's date. Gnus-Diary offers you a nice summary line format
+;; which will do this. By default, a summary line will appear like this:
;;
;; <Event Date>: <Subject> <Remaining time>
;;
;; headers will be inserted automatically (but not filled with proper
;; values yet).
+;; - An interactive mail-to-diary convertion function:
+;; The function `gnus-diary-check-message' ensures that the current message
+;; contains all the required diary headers, and prompts you for values /
+;; correction if needed. This function is hooked in the nndiary backend so
+;; that moving an article to an nndiary group will trigger it
+;; automatically. It is also bound to `C-c D c' in message-mode and
+;; article-edit-mode in order to ease the process of converting a usual
+;; mail to a diary one. This function takes a prefix argument which will
+;; force prompting of all diary headers, regardless of their
+;; presence/validity. That way, you can very easily reschedule a diary
+;; message for instance.
+
;; Usage:
;; =====
;; Bugs / Todo:
;; ===========
-;; * Provide `gnus-group-diary-mail' and `gnus-group-post-diary-news' (or
-;; something like that), that would do just like `gnus-group-mail' and
-;; `gnus-group-post-news', but also prompt for diary header values with
-;; completion etc.
-;; * Maybe not actually: we could just have a function that converts *any*
-;; message to a diary one, by prompting the schedule. You could then forward
-;; a message and make it a diary one etc.
;;; Code:
(require 'nndiary)
+(require 'message)
+(require 'gnus-art)
(defgroup gnus-diary nil
- "Utilities on top of the nndiary backend for Gnus.")
+ "Utilities on top of the nndiary backend for Gnus."
+ :version "22.1")
-(defcustom gnus-diary-summary-line-format "%U%R%z%I %uD: %(%s%) (%ud)\n"
+(defcustom gnus-diary-summary-line-format "%U%R%z %uD: %(%s%) (%ud)\n"
"*Summary line format for nndiary groups."
:type 'string
:group 'gnus-diary
"Current Diary backend version.")
+;; Compatibility functions ==================================================
+
+(eval-and-compile
+ (if (fboundp 'kill-entire-line)
+ (defalias 'gnus-diary-kill-entire-line 'kill-entire-line)
+ (defun gnus-diary-kill-entire-line ()
+ (beginning-of-line)
+ (let ((kill-whole-line t))
+ (kill-line)))))
+
+
;; Summary line format ======================================================
(defun gnus-diary-delay-format-french (past delay)
(if (null delay)
"maintenant!"
;; Keep only a precision of two degrees
- (and (> (length delay) 1) (setf (nthcdr 2 delay) nil))
+ (and (> (length delay) 1) (setcdr (cdr delay) nil))
(concat (if past "il y a " "dans ")
(let ((str "")
del)
(if (null delay)
"now!"
;; Keep only a precision of two degrees
- (and (> (length delay) 1) (setf (nthcdr 2 delay) nil))
+ (and (> (length delay) 1) (setcdr (cdr delay) nil))
(concat (unless past "in ")
(let ((str "")
del)
(let ((head (cdr (assoc (intern (format "X-Diary-%s" (car elt)))
headers))))
(when head
- (nndiary-parse-schedule-value head (cadr elt) (caddr elt)))))
+ (nndiary-parse-schedule-value head (cadr elt) (car (cddr elt))))))
nndiary-headers))
;; #### NOTE: Gnus sometimes gives me a HEADER not corresponding to any
(o1 (nndiary-next-occurence s1 now))
(o2 (nndiary-next-occurence s2 now)))
(if (and (= (car o1) (car o2)) (= (cadr o1) (cadr o2)))
- (< (mail-header-number h1) (mail-header-number h2))
+ (< (mail-header-number h1) (mail-header-number h2))
(time-less-p o1 o2))))
(interactive "P")
(gnus-summary-sort 'schedule reverse))
+(defvar gnus-summary-misc-menu) ;; Avoid byte compiler warning.
(add-hook 'gnus-summary-menu-hook
(lambda ()
(easy-menu-add-item gnus-summary-misc-menu
'nndiary)]
"Sort by number")))
+
+
;; Group parameters autosetting =============================================
(defun gnus-diary-update-group-parameters (group)
(add-hook 'gnus-subscribe-newsgroup-hooks
'gnus-diary-maybe-update-group-parameters)
+
+;; Diary Message Checking ===================================================
+
+(defvar gnus-diary-header-value-history nil
+ ;; History variable for header value prompting
+ )
+
+(defun gnus-diary-narrow-to-headers ()
+ "Narrow the current buffer to the header part.
+Point is left at the beginning of the region.
+The buffer is assumed to contain a message, but the format is unknown."
+ (cond ((eq major-mode 'message-mode)
+ (message-narrow-to-headers))
+ (t
+ (goto-char (point-min))
+ (when (search-forward "\n\n" nil t)
+ (narrow-to-region (point-min) (- (point) 1))
+ (goto-char (point-min))))
+ ))
+
+(defun gnus-diary-add-header (str)
+ "Add a header to the current buffer.
+The buffer is assumed to contain a message, but the format is unknown."
+ (cond ((eq major-mode 'message-mode)
+ (message-add-header str))
+ (t
+ (save-restriction
+ (gnus-diary-narrow-to-headers)
+ (goto-char (point-max))
+ (if (string-match "\n$" str)
+ (insert str)
+ (insert str ?\n))))
+ ))
+
+(defun gnus-diary-check-message (arg)
+ "Ensure that the current message is a valid for NNDiary.
+This function checks that all NNDiary required headers are present and
+valid, and prompts for values / correction otherwise.
+
+If ARG (or prefix) is non-nil, force prompting for all fields."
+ (interactive "P")
+ (save-excursion
+ (mapcar
+ (lambda (head)
+ (let ((header (concat "X-Diary-" (car head)))
+ (ask arg)
+ value invalid)
+ ;; First, try to find the header, and checks for validity:
+ (save-restriction
+ (gnus-diary-narrow-to-headers)
+ (when (re-search-forward (concat "^" header ":") nil t)
+ (unless (eq (char-after) ? )
+ (insert " "))
+ (setq value (buffer-substring (point) (point-at-eol)))
+ (and (string-match "[ \t]*\\([^ \t]+\\)[ \t]*" value)
+ (setq value (match-string 1 value)))
+ (condition-case ()
+ (nndiary-parse-schedule-value value
+ (nth 1 head) (nth 2 head))
+ (t
+ (setq invalid t)))
+ ;; #### NOTE: this (along with the `gnus-diary-add-header'
+ ;; function) could be rewritten in a better way, in particular
+ ;; not to blindly remove an already present header and reinsert
+ ;; it somewhere else afterwards.
+ (when (or ask invalid)
+ (gnus-diary-kill-entire-line))
+ ))
+ ;; Now, loop until a valid value is provided:
+ (while (or ask (not value) invalid)
+ (let ((prompt (concat (and invalid
+ (prog1 "(current value invalid) "
+ (beep)))
+ header ": ")))
+ (setq value
+ (if (listp (nth 1 head))
+ (completing-read prompt (cons '("*" nil) (nth 1 head))
+ nil t value
+ gnus-diary-header-value-history)
+ (read-string prompt value
+ gnus-diary-header-value-history))))
+ (setq ask nil)
+ (setq invalid nil)
+ (condition-case ()
+ (nndiary-parse-schedule-value value
+ (nth 1 head) (nth 2 head))
+ (t
+ (setq invalid t))))
+ (gnus-diary-add-header (concat header ": " value))
+ ))
+ nndiary-headers)
+ ))
+
+(add-hook 'nndiary-request-accept-article-hooks
+ (lambda () (gnus-diary-check-message nil)))
+
+(define-key message-mode-map "\C-cDc" 'gnus-diary-check-message)
+(define-key gnus-article-edit-mode-map "\C-cDc" 'gnus-diary-check-message)
+
+
+;; The end ==================================================================
+
(defun gnus-diary-version ()
"Current Diary backend version."
(interactive)
(message "NNDiary version %s" nndiary-version))
+(define-key message-mode-map "\C-cDv" 'gnus-diary-version)
+(define-key gnus-article-edit-mode-map "\C-cDv" 'gnus-diary-version)
+
+
(provide 'gnus-diary)
+;;; arch-tag: 98467e70-337e-4ddc-b92d-45d403ff1b4b
;;; gnus-diary.el ends here