Remove trailing whitespace.
[gnus] / lisp / nndiary.el
1 ;;; nndiary.el --- A diary back end for Gnus
2
3 ;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004,
4 ;;   2005, 2006 Free Software Foundation, Inc.
5
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
10
11 ;; This file is part of GNU Emacs.
12
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.
17
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.
22
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.
27
28
29 ;;; Commentary:
30
31 ;; Contents management by FCM version 0.1.
32
33 ;; Description:
34 ;; ===========
35
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.
38
39
40 ;; Bugs / Todo:
41 ;; ===========
42
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.
54
55
56 ;; Remarks:
57 ;; =======
58
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.
68
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.
74
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
81 ;;   though.
82
83
84 ;;; Code:
85
86 (require 'nnoo)
87 (require 'nnheader)
88 (require 'nnmail)
89 (eval-when-compile (require 'cl))
90
91 (require 'gnus-start)
92 (require 'gnus-sum)
93
94 ;; Compatibility Functions  =================================================
95
96 (eval-and-compile
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))))
102
103
104 ;; Back End behavior customization ===========================================
105
106 (defgroup nndiary nil
107   "The Gnus Diary back end."
108   :version "22.1"
109   :group 'gnus-diary)
110
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."
117   :group 'nndiary
118   :group 'mail-source
119   :type 'sexp)
120
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
125 non-nil."
126   :group 'nndiary
127   :group 'nnmail-split
128   :type '(choice (repeat :tag "Alist" (group (string :tag "Name") regexp))
129                  (function-item nnmail-split-fancy)
130                  (function :tag "Other")))
131
132
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.
136
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 ?\".
141
142 The units of measure are 'minute 'hour 'day 'week 'month and 'year (no,
143 not 'century, sorry).
144
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.
150
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:
156
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.
159
160 - '(1 . day): this means pop up the appointements the day before, at 00:00.
161
162 - '(6 . hour): for an appointement at 18:30, this would pop up the
163   appointement message at 12:00.
164
165 - '(360 . minute): for an appointement at 18:30 and 15 seconds, this would
166   pop up the appointement message at 12:30."
167   :group 'nndiary
168   :type '(repeat (cons :format "%v\n"
169                        (integer :format "%v")
170                        (choice :format "%[%v(s)%] before...\n"
171                                :value day
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)))))
178
179 (defcustom nndiary-week-starts-on-monday nil
180   "*Whether a week starts on monday (otherwise, sunday)."
181   :type 'boolean
182   :group 'nndiary)
183
184
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."
188   :group 'nndiary
189   :type 'hook)
190
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."
194   :group 'nndiary
195   :type 'hook)
196
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."
201   :group 'nndiary
202   :type 'hook)
203
204 (defcustom nndiary-check-directory-twice t
205   "*If t, check directories twice to avoid NFS failures."
206   :group 'nndiary
207   :type 'boolean)
208
209
210 ;; Back End declaration ======================================================
211
212 ;; Well, most of this is nnml clonage.
213
214 (nnoo-declare nndiary)
215
216 (defvoo nndiary-directory (nnheader-concat gnus-directory "diary/")
217   "Spool directory for the nndiary back end.")
218
219 (defvoo nndiary-active-file
220     (expand-file-name "active" nndiary-directory)
221   "Active file for the nndiary back end.")
222
223 (defvoo nndiary-newsgroups-file
224     (expand-file-name "newsgroups" nndiary-directory)
225   "Newsgroups description file for the nndiary back end.")
226
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.")
232
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.")
241
242 (defvoo nndiary-prepare-save-mail-hook nil
243   "*Hook run narrowed to an article before saving.")
244
245 (defvoo nndiary-inhibit-expiry nil
246   "If non-nil, inhibit expiry.")
247
248 \f
249
250 (defconst nndiary-version "0.2-b14"
251   "Current Diary back end version.")
252
253 (defun nndiary-version ()
254   "Current Diary back end version."
255   (interactive)
256   (message "NNDiary version %s" nndiary-version))
257
258 (defvoo nndiary-nov-file-name ".overview")
259
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)
267
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)
271
272 (defconst nndiary-headers
273   '(("Minute" 0 59)