1 ;;; nndiary.el --- A diary back end for Gnus
3 ;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004,
4 ;; 2005, 2006 Free Software Foundation, Inc.
6 ;; Author: Didier Verna <didier@xemacs.org>
7 ;; Maintainer: Didier Verna <didier@xemacs.org>
8 ;; Created: Fri Jul 16 18:55:42 1999
9 ;; Keywords: calendar mail news
11 ;; This file is part of GNU Emacs.
13 ;; GNU Emacs is free software; you can redistribute it and/or modify
14 ;; it under the terms of the GNU General Public License as published by
15 ;; the Free Software Foundation; either version 2 of the License, or
16 ;; (at your option) any later version.
18 ;; GNU Emacs is distributed in the hope that it will be useful,
19 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 ;; GNU General Public License for more details.
23 ;; You should have received a copy of the GNU General Public License
24 ;; along with this program; if not, write to the Free Software
25 ;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 ;; MA 02110-1301, USA.
31 ;; Contents management by FCM version 0.1.
36 ;; nndiary is a mail back end designed to handle mails as diary event
37 ;; reminders. It is now fully documented in the Gnus manual.
43 ;; * Respooling doesn't work because contrary to the request-scan function,
44 ;; Gnus won't allow me to override the split methods when calling the
45 ;; respooling back end functions.
46 ;; * There's a bug in the time zone mechanism with variable TZ locations.
47 ;; * We could allow a keyword like `ask' in X-Diary-* headers, that would mean
48 ;; "ask for value upon reception of the message".
49 ;; * We could add an optional header X-Diary-Reminders to specify a special
50 ;; reminders value for this message. Suggested by Jody Klymak.
51 ;; * We should check messages validity in other circumstances than just
52 ;; moving an article from somewhere else (request-accept). For instance,
53 ;; when editing / saving and so on.
59 ;; * nnoo. NNDiary is very similar to nnml. This makes the idea of using nnoo
60 ;; (to derive nndiary from nnml) natural. However, my experience with nnoo
61 ;; is that for reasonably complex back ends like this one, noo is a burden
62 ;; rather than an help. It's tricky to use, not everything can be inherited,
63 ;; what can be inherited and when is not very clear, and you've got to be
64 ;; very careful because a little mistake can fuck up your other back ends,
65 ;; especially because their variables will be use instead of your real ones.
66 ;; Finally, I found it easier to just clone the needed parts of nnml, and
67 ;; tracking nnml updates is not a big deal.
69 ;; IMHO, nnoo is actually badly designed. A much simpler, and yet more
70 ;; powerful one would be to make *real* functions and variables for a new
71 ;; back end based on another. Lisp is a reflexive language so that's a very
72 ;; easy thing to do: inspect the function's form, replace occurences of
73 ;; <nnfrom> (even in strings) with <nnto>, and you're done.
75 ;; * nndiary-get-new-mail, nndiary-mail-source and nndiary-split-methods:
76 ;; NNDiary has some experimental parts, in the sense Gnus normally uses only
77 ;; one mail back ends for mail retreival and splitting. This back end is
78 ;; also an attempt to make it behave differently. For Gnus developpers: as
79 ;; you can see if you snarf into the code, that was not a very difficult
80 ;; thing to do. Something should be done about the respooling breakage
89 (eval-when-compile (require 'cl))
94 ;; Compatibility Functions =================================================
97 (if (fboundp 'signal-error)
98 (defun nndiary-error (&rest args)
99 (apply #'signal-error 'nndiary args))
100 (defun nndiary-error (&rest args)
101 (apply #'error args))))
104 ;; Back End behavior customization ===========================================
106 (defgroup nndiary nil
107 "The Gnus Diary back end."
111 (defcustom nndiary-mail-sources
112 `((file :path ,(expand-file-name "~/.nndiary")))
113 "*NNDiary specific mail sources.
114 This variable is used by nndiary in place of the standard `mail-sources'
115 variable when `nndiary-get-new-mail' is set to non-nil. These sources
116 must contain diary messages ONLY."
121 (defcustom nndiary-split-methods '(("diary" ""))
122 "*NNDiary specific split methods.
123 This variable is used by nndiary in place of the standard
124 `nnmail-split-methods' variable when `nndiary-get-new-mail' is set to
128 :type '(choice (repeat :tag "Alist" (group (string :tag "Name") regexp))
129 (function-item nnmail-split-fancy)
130 (function :tag "Other")))
133 (defcustom nndiary-reminders '((0 . day))
134 "*Different times when you want to be reminded of your appointements.
135 Diary articles will appear again, as if they'd been just received.
137 Entries look like (3 . day) which means something like \"Please
138 Hortense, would you be so kind as to remind me of my appointments 3 days
139 before the date, thank you very much. Anda, hmmm... by the way, are you
140 doing anything special tonight ?\".
142 The units of measure are 'minute 'hour 'day 'week 'month and 'year (no,
143 not 'century, sorry).
145 NOTE: the units of measure actually express dates, not durations: if you
146 use 'week, messages will pop up on Sundays at 00:00 (or Mondays if
147 `nndiary-week-starts-on-monday' is non nil) and *not* 7 days before the
148 appointement, if you use 'month, messages will pop up on the first day of
149 each months, at 00:00 and so on.
151 If you really want to specify a duration (like 24 hours exactly), you can
152 use the equivalent in minutes (the smallest unit). A fuzz of 60 seconds
153 maximum in the reminder is not that painful, I think. Although this
154 scheme might appear somewhat weird at a first glance, it is very powerful.
155 In order to make this clear, here are some examples:
157 - '(0 . day): this is the default value of `nndiary-reminders'. It means
158 pop up the appointements of the day each morning at 00:00.
160 - '(1 . day): this means pop up the appointements the day before, at 00:00.
162 - '(6 . hour): for an appointement at 18:30, this would pop up the
163 appointement message at 12:00.
165 - '(360 . minute): for an appointement at 18:30 and 15 seconds, this would
166 pop up the appointement message at 12:30."
168 :type '(repeat (cons :format "%v\n"
169 (integer :format "%v")
170 (choice :format "%[%v(s)%] before...\n"
172 (const :format "%v" minute)
173 (const :format "%v" hour)
174 (const :format "%v" day)
175 (const :format "%v" week)
176 (const :format "%v" month)
177 (const :format "%v" year)))))
179 (defcustom nndiary-week-starts-on-monday nil
180 "*Whether a week starts on monday (otherwise, sunday)."
185 (defcustom nndiary-request-create-group-hooks nil
186 "*Hooks to run after `nndiary-request-create-group' is executed.
187 The hooks will be called with the full group name as argument."
191 (defcustom nndiary-request-update-info-hooks nil
192 "*Hooks to run after `nndiary-request-update-info-group' is executed.
193 The hooks will be called with the full group name as argument."
197 (defcustom nndiary-request-accept-article-hooks nil
198 "*Hooks to run before accepting an article.
199 Executed near the beginning of `nndiary-request-accept-article'.
200 The hooks will be called with the article in the current buffer."
204 (defcustom nndiary-check-directory-twice t
205 "*If t, check directories twice to avoid NFS failures."
210 ;; Back End declaration ======================================================
212 ;; Well, most of this is nnml clonage.
214 (nnoo-declare nndiary)
216 (defvoo nndiary-directory (nnheader-concat gnus-directory "diary/")
217 "Spool directory for the nndiary back end.")
219 (defvoo nndiary-active-file
220 (expand-file-name "active" nndiary-directory)
221 "Active file for the nndiary back end.")
223 (defvoo nndiary-newsgroups-file
224 (expand-file-name "newsgroups" nndiary-directory)
225 "Newsgroups description file for the nndiary back end.")
227 (defvoo nndiary-get-new-mail nil
228 "Whether nndiary gets new mail and split it.
229 Contrary to traditional mail back ends, this variable can be set to t
230 even if your primary mail back end also retreives mail. In such a case,
231 NDiary uses its own mail-sources and split-methods.")
233 (defvoo nndiary-nov-is-evil nil
234 "If non-nil, Gnus will never use nov databases for nndiary groups.
235 Using nov databases will speed up header fetching considerably.
236 This variable shouldn't be flipped much. If you have, for some reason,
237 set this to t, and want to set it to nil again, you should always run
238 the `nndiary-generate-nov-databases' command. The function will go
239 through all nnml directories and generate nov databases for them
240 all. This may very well take some time.")
242 (defvoo nndiary-prepare-save-mail-hook nil
243 "*Hook run narrowed to an article before saving.")
245 (defvoo nndiary-inhibit-expiry nil
246 "If non-nil, inhibit expiry.")
250 (defconst nndiary-version "0.2-b14"
251 "Current Diary back end version.")
253 (defun nndiary-version ()
254 "Current Diary back end version."
256 (message "NNDiary version %s" nndiary-version))
258 (defvoo nndiary-nov-file-name ".overview")
260 (defvoo nndiary-current-directory nil)
261 (defvoo nndiary-current-group nil)
262 (defvoo nndiary-status-string "" )
263 (defvoo nndiary-nov-buffer-alist nil)
264 (defvoo nndiary-group-alist nil)
265 (defvoo nndiary-active-timestamp nil)
266 (defvoo nndiary-article-file-alist nil)
268 (defvoo nndiary-generate-active-function 'nndiary-generate-active-info)
269 (defvoo nndiary-nov-buffer-file-name nil)
270 (defvoo nndiary-file-coding-system nnmail-file-coding-system)
272 (defconst nndiary-headers