-;;; nndiary.el --- A diary backend for Gnus
+;;; nndiary.el --- A diary back end for Gnus
-;; Copyright (C) 1999-2001 Didier Verna.
-
-;; PRCS: $Id: nndiary.el 1.22 Tue, 04 Sep 2001 11:32:13 +0200 didier $
+;; Copyright (C) 1999-2012 Free Software Foundation, Inc.
;; Author: Didier Verna <didier@xemacs.org>
;; Maintainer: Didier Verna <didier@xemacs.org>
;; Created: Fri Jul 16 18:55:42 1999
-;; Last Revision: Wed Aug 8 17:36:21 2001
;; 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
+;; 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
+;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
-;; NNDiary is distributed in the hope that it will be useful,
+;; 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
-;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;; Description:
;; ===========
-;; This package implements NNDiary, a diary backend for Gnus. NNDiary is a
-;; mail backend, pretty similar to nnml in its functionnning (it has all the
-;; features of nnml, actually), but in which messages are treated as event
-;; reminders.
-
-;; Here is a typical scenario:
-;; - You've got a date with Andy Mc Dowell or Bruce Willis (select according
-;; to your sexual preference) in one month. You don't want to forget it.
-;; - Send a (special) diary message to yourself (see below).
-;; - Forget all about it and keep on getting and reading new mail, as usual.
-;; - From time to time, as you type `g' in the group buffer and as the date
-;; is getting closer, the message will pop up again, just like if it were
-;; new and unread.
-;; - Read your "new" messages, this one included, and start dreaming of the
-;; night you're gonna have.
-;; - Once the date is over (you actually fell asleep just after dinner), the
-;; message will be automatically deleted if it is marked as expirable.
-
-;; Some more notes on the diary backend:
-;; - NNDiary is a *real* mail backend. You *really* send real diary
-;; messsages. This means for instance that you can give appointements to
-;; anybody (provided they use Gnus and NNDiary) by sending the diary message
-;; to them as well.
-;; - However, since NNDiary also has a 'request-post method, you can also
-;; `C-u a' instead of `C-u m' on a diary group and the message won't actually
-;; be sent; just stored in the group.
-;; - The events you want to remember need not be punctual. You can set up
-;; reminders for regular dates (like once each week, each monday at 13:30
-;; and so on). Diary messages of this kind will never be deleted (unless
-;; you do it explicitely). But that, you guessed.
-
-
-;; Usage:
-;; =====
-
-;; 1/ Diary messages contain several `X-Diary-*' special headers. You *must*
-;; arrange that these messages be split in a private folder *before* Gnus
-;; treat them. You need this because Gnus is not able yet to manage
-;; multiple backends for mail retrieval. Getting them from a separate
-;; source will compensate this misfeature to some extent, as we will see.
-;; As an example, here's my procmailrc entry to store diary files in
-;; ~/.nndiary (the default nndiary mail source file):
-;;
-;; :0 HD :
-;; * ^X-Diary
-;; .nndiary
-;;
-;; 2/ Install nndiary somewhere Emacs / Gnus can find it. Normally, you
-;; *don't* have to '(require 'nndiary) anywhere. Gnus will do so when
-;; appropriate as long as nndiary is somewhere in the load path.
-;; 3/ Now, customize nndiary: type `M-x customize-group', and then `nndiary'
-;; at the prompt (note that if you have not restarted Emacs yet, you'll
-;; have to the load the library by hand before being able to customize it).
-;; In particular, you should customize the following options:
-;; - `nndiary-mail-sources', which overrides the normal `mail-sources'
-;; value for diary messages retrieving. It defaults to
-;; '(file :path "~/.nndiary").
-;; - `nndiary-split-methods', which overrides the normal
-;; `nnmail-split-methods' value for diary messages splitting. You can
-;; have all the diary groups you want (for example, I have a birthdays
-;; group, and stuff like that).
-;; - `nndiary-reminders', the list of times when you want to be reminded
-;; of your appointements (e.g. 3 weeks before, then 2 days before, then
-;; 1 hour before and that's it).
-;; 4/ You *must* use the group timestamp feature of Gnus. This adds a
-;; timestamp to each groups' parameters (please refer to the Gnus
-;; documentation ("Group Timestamp" info node) to see how it's done.
-;; 5/ Once you have done this, you may add a permanent nndiary virtual server
-;; (something like '(nndiary "")) to your `gnus-secondary-select-methods'.
-;; Yes, this server will be able to retrieve mails and split them when you
-;; type `g' in the group buffer, just as if it were your only mail backend.
-;; This is the benefit of using a private folder.
-;; 6/ Hopefully, almost everything (see the TODO section below) will work as
-;; expected when you restart Gnus: in the group buffer, `g' and `M-g' will
-;; also get your new diary mails, `F' will find your new diary groups etc.
-
-
-;; How to send diary messages:
-;; ==========================
-
-;; There are 7 special headers in diary messages. These headers are of the
-;; form `X-Diary-<something>', the <something> being one of `Minute', `Hour',
-;; `Dom', `Month', `Year', `Time-Zone' and `Dow'. `Dom' means "Day of Month",
-;; and `dow' means "Day of Week". These headers actually behave like crontab
-;; specifications and define the event date(s).
-
-;; For all headers but the `Time-Zone' one, a header value is either a
-;; star (meaning all possible values), or a list of fields (separated by a
-;; comma). A field is either an integer, or a range. A range is two integers
-;; separated by a dash. Possible integer values are 0-59 for `Minute', 0-23
-;; for `Hour', 1-31 for `Dom', `1-12' for Month, above 1971 for `Year' and 0-6
-;; for `Dow' (0 = sunday). As a special case, a star in either `Dom' or `Dow'
-;; doesn't mean "all possible values", but "use only the other field". Note
-;; that if both are star'ed, the use of either one gives the same result :-),
-
-;; The `Time-Zone' header is special in that it can have only one value (you
-;; bet ;-).
-;; A star doesn't mean "all possible values" (because it has no sense), but
-;; "the current local time zone".
-
-;; As an example, here's how you would say "Each Monday and each 1st of month,
-;; at 12:00, 20:00, 21:00, 22:00, 23:00 and 24:00, from 1999 to 2010" (I let
-;; you find what to do then):
-;;
-;; X-Diary-Minute: 0
-;; X-Diary-Hour: 12, 20-24
-;; X-Diary-Dom: 1
-;; X-Diary-Month: *
-;; X-Diary-Year: 1999-2010
-;; X-Diary-Dow: 1
-;; X-Diary-Time-Zone: *
-;;
-;;
-;; Sending a diary message is not different from sending any other kind of
-;; mail, except that such messages are identified by the presence of these
-;; special headers.
-
+;; nndiary is a mail back end designed to handle mails as diary event
+;; reminders. It is now fully documented in the Gnus manual.
;; Bugs / Todo:
;; * Respooling doesn't work because contrary to the request-scan function,
;; Gnus won't allow me to override the split methods when calling the
-;; respooling backend functions.
-;; * The time zone mechanism is subject to change.
+;; respooling back end functions.
+;; * There's a bug in the time zone mechanism with variable TZ locations.
;; * We could allow a keyword like `ask' in X-Diary-* headers, that would mean
-;; "ask for value upon reception of the message". Suggested by Jody Klymak.
+;; "ask for value upon reception of the message".
;; * We could add an optional header X-Diary-Reminders to specify a special
;; reminders value for this message. Suggested by Jody Klymak.
-;; * Modify the request-accept-article function to make it prompt for diary
-;; headers if they're missing.
+;; * We should check messages validity in other circumstances than just
+;; moving an article from somewhere else (request-accept). For instance,
+;; when editing / saving and so on.
+
;; Remarks:
;; =======
-;; * nnoo.
-;; NNDiary is very similar to nnml. This makes the idea of using nnoo (to
-;; derive nndiary from nnml) natural. However, my experience with nnoo is
-;; that for reasonably complex backends like this one, noo is a burden
-;; rather than an help. It's tricky to use, not everything can be
-;; inherited, what can be inherited and when is not very clear, and you've
-;; got to be very careful because a little mistake can fuck up your your
-;; other backends, especially because their variables will be use instead of
-;; your real ones. Finally, I found it easier to just clone the needed
-;; parts of nnml, and tracking nnml updates is not a big deal.
+;; * nnoo. NNDiary is very similar to nnml. This makes the idea of using nnoo
+;; (to derive nndiary from nnml) natural. However, my experience with nnoo
+;; is that for reasonably complex back ends like this one, nnoo is a burden
+;; rather than an help. It's tricky to use, not everything can be inherited,
+;; what can be inherited and when is not very clear, and you've got to be
+;; very careful because a little mistake can fuck up your other back ends,
+;; especially because their variables will be use instead of your real ones.
+;; Finally, I found it easier to just clone the needed parts of nnml, and
+;; tracking nnml updates is not a big deal.
;; IMHO, nnoo is actually badly designed. A much simpler, and yet more
;; powerful one would be to make *real* functions and variables for a new
-;; backend based on another. Lisp is a reflexive language so that's a very
-;; easy thing to do: inspect the function's form, replace occurences of
+;; back end based on another. Lisp is a reflexive language so that's a very
+;; easy thing to do: inspect the function's form, replace occurrences of
;; <nnfrom> (even in strings) with <nnto>, and you're done.
;; * nndiary-get-new-mail, nndiary-mail-source and nndiary-split-methods:
;; NNDiary has some experimental parts, in the sense Gnus normally uses only
-;; one mail backends for mail retreival and splitting. This backend is also
-;; an attempt to make it behave differently. For Gnus developpers: as you
-;; can see if you snarf into the code, that was not a very difficult thing
-;; to do. Something should be done about the respooling breakage though.
+;; one mail back ends for mail retrieval and splitting. This back end is
+;; also an attempt to make it behave differently. For Gnus developers: as
+;; you can see if you snarf into the code, that was not a very difficult
+;; thing to do. Something should be done about the respooling breakage
+;; though.
;;; Code:
;; Compatibility Functions =================================================
-(if (fboundp 'signal-error)
+(eval-and-compile
+ (if (fboundp 'signal-error)
+ (defun nndiary-error (&rest args)
+ (apply #'signal-error 'nndiary args))
(defun nndiary-error (&rest args)
- (apply #'signal-error 'nndiary args))
- (defun nndiary-error (&rest args)
- (apply #'error args)))
+ (apply #'error args))))
-;; Backend behavior customization ===========================================
+;; Back End behavior customization ===========================================
(defgroup nndiary nil
- "The Gnus Diary backend."
+ "The Gnus Diary back end."
+ :version "22.1"
:group 'gnus-diary)
(defcustom nndiary-mail-sources
`((file :path ,(expand-file-name "~/.nndiary")))
"*NNDiary specific mail sources.
This variable is used by nndiary in place of the standard `mail-sources'
-variable. These sources must contain diary messages ONLY."
+variable when `nndiary-get-new-mail' is set to non-nil. These sources
+must contain diary messages ONLY."
:group 'nndiary
:group 'mail-source
:type 'sexp)
(defcustom nndiary-split-methods '(("diary" ""))
"*NNDiary specific split methods.
This variable is used by nndiary in place of the standard
-`nnmail-split-methods' variable."
+`nnmail-split-methods' variable when `nndiary-get-new-mail' is set to
+non-nil."
:group 'nndiary
:group 'nnmail-split
:type '(choice (repeat :tag "Alist" (group (string :tag "Name") regexp))
(defcustom nndiary-reminders '((0 . day))
- "*Different times when you want to be reminded of your appointements.
+ "*Different times when you want to be reminded of your appointments.
Diary articles will appear again, as if they'd been just received.
Entries look like (3 . day) which means something like \"Please
NOTE: the units of measure actually express dates, not durations: if you
use 'week, messages will pop up on Sundays at 00:00 (or Mondays if
-`nndiary-week-starts-on-monday' is non nil) and *not* 7 days before the
-appointement, if you use 'month, messages will pop up on the first day of
+`nndiary-week-starts-on-monday' is non-nil) and *not* 7 days before the
+appointment, if you use 'month, messages will pop up on the first day of
each months, at 00:00 and so on.
If you really want to specify a duration (like 24 hours exactly), you can
In order to make this clear, here are some examples:
- '(0 . day): this is the default value of `nndiary-reminders'. It means
- pop up the appointements of the day each morning at 00:00.
+ pop up the appointments of the day each morning at 00:00.
-- '(1 . day): this means pop up the appointements the day before, at 00:00.
+- '(1 . day): this means pop up the appointments the day before, at 00:00.
-- '(6 . hour): for an appointement at 18:30, this would pop up the
- appointement message at 12:00.
+- '(6 . hour): for an appointment at 18:30, this would pop up the
+ appointment message at 12:00.
-- '(360 . minute): for an appointement at 18:30 and 15 seconds, this would
- pop up the appointement message at 12:30."
+- '(360 . minute): for an appointment at 18:30 and 15 seconds, this would
+ pop up the appointment message at 12:30."
:group 'nndiary
:type '(repeat (cons :format "%v\n"
(integer :format "%v")
:group 'nndiary
:type 'hook)
+(defcustom nndiary-request-accept-article-hooks nil
+ "*Hooks to run before accepting an article.
+Executed near the beginning of `nndiary-request-accept-article'.
+The hooks will be called with the article in the current buffer."
+ :group 'nndiary
+ :type 'hook)
+
(defcustom nndiary-check-directory-twice t
"*If t, check directories twice to avoid NFS failures."
:group 'nndiary
:type 'boolean)
-;; Backend declaration ======================================================
+;; Back End declaration ======================================================
;; Well, most of this is nnml clonage.
(nnoo-declare nndiary)
(defvoo nndiary-directory (nnheader-concat gnus-directory "diary/")
- "Spool directory for the nndiary backend.")
+ "Spool directory for the nndiary back end.")
(defvoo nndiary-active-file
(expand-file-name "active" nndiary-directory)
- "Active file for the nndiary backend.")
+ "Active file for the nndiary back end.")
(defvoo nndiary-newsgroups-file
(expand-file-name "newsgroups" nndiary-directory)
- "Newsgroups description file for the nndiary backend.")
+ "Newsgroups description file for the nndiary back end.")
-(defvoo nndiary-get-new-mail t
+(defvoo nndiary-get-new-mail nil
"Whether nndiary gets new mail and split it.
-Contrary to traditional mail backends, this variable should always be
-non-nil because nndiary uses its own mail-sources and split-methods.")
+Contrary to traditional mail back ends, this variable can be set to t
+even if your primary mail back end also retrieves mail. In such a case,
+NDiary uses its own mail-sources and split-methods.")
(defvoo nndiary-nov-is-evil nil
"If non-nil, Gnus will never use nov databases for nndiary groups.
\f
-;; $Format: "(defconst nndiary-prcs-major-version \"$ProjectMajorVersion$\")"$
-(defconst nndiary-prcs-major-version "branch-0-2")
-;; $Format: "(defconst nndiary-prcs-minor-version \"$ProjectMinorVersion$\")"$
-(defconst nndiary-prcs-minor-version "1")
-(defconst nndiary-version
- (let ((level nndiary-prcs-minor-version)
- major minor status)
- (string-match "\\(branch\\|version\\)-\\([0-9]+\\)-\\([0-9]+\\)"
- nndiary-prcs-major-version)
- (setq major (match-string 2 nndiary-prcs-major-version)
- minor (match-string 3 nndiary-prcs-major-version)
- status (match-string 1 nndiary-prcs-major-version))
- (cond ((string= status "version")
- (setq level (int-to-string (1- (string-to-int level))))
- (if (eq level 0)
- (concat major "." minor)
- (concat major "." minor "." level)))
- ((string= status "branch")
- (concat major "." minor "-b" level))))
- "Current Diary backend version.")
+(defconst nndiary-version "0.2-b14"
+ "Current Diary back end version.")
(defun nndiary-version ()
- "Current Diary backend version."
+ "Current Diary back end version."
(interactive)
(message "NNDiary version %s" nndiary-version))
-
(defvoo nndiary-nov-file-name ".overview")
(defvoo nndiary-current-directory nil)
;; List of NNDiary headers that specify the time spec. Each header name is
;; followed by either two integers (specifying a range of possible values
;; for this header) or one list (specifying all the possible values for this
- ;; header). In the latter case, the list does NOT include the unspecifyed
+ ;; header). In the latter case, the list does NOT include the unspecified
;; spec (*).
;; For time zone values, we have symbolic time zone names associated with
;; the (relative) number of seconds ahead GMT.
)
+(defsubst nndiary-schedule ()
+ (let (head)
+ (condition-case arg
+ (mapcar
+ (lambda (elt)
+ (setq head (nth 0 elt))
+ (nndiary-parse-schedule (nth 0 elt) (nth 1 elt) (nth 2 elt)))
+ nndiary-headers)
+ (error
+ (nnheader-report 'nndiary "X-Diary-%s header parse error: %s."
+ head (cdr arg))
+ nil))
+ ))
;;; Interface functions =====================================================
(deffoo nndiary-retrieve-headers (sequence &optional group server fetch-old)
(when (nndiary-possibly-change-directory group server)
- (save-excursion
- (set-buffer nntp-server-buffer)
+ (with-current-buffer nntp-server-buffer
(erase-buffer)
(let* ((file nil)
(number (length sequence))
(nnheader-report 'nndiary "Article %s retrieved" id)
;; We return the article number.
(cons (if group-num (car group-num) group)
- (string-to-int (file-name-nondirectory path)))))))
+ (string-to-number (file-name-nondirectory path)))))))
-(deffoo nndiary-request-group (group &optional server dont-check)
+(deffoo nndiary-request-group (group &optional server dont-check info)
(let ((file-name-coding-system nnmail-pathname-coding-system))
(cond
((not (nndiary-possibly-change-directory group server))
(deffoo nndiary-request-scan (&optional group server)
;; Use our own mail sources and split methods while Gnus doesn't let us have
- ;; multiple backends for retrieving mail.
+ ;; multiple back ends for retrieving mail.
(let ((mail-sources nndiary-mail-sources)
(nnmail-split-methods nndiary-split-methods))
(setq nndiary-article-file-alist nil)
(with-temp-buffer
(nndiary-request-article number group server (current-buffer))
(let ((nndiary-current-directory nil))
- (nnmail-expiry-target-group nnmail-expiry-target group))))
+ (nnmail-expiry-target-group nnmail-expiry-target group)))
+ (nndiary-possibly-change-directory group server))
(nnheader-message 5 "Deleting article %s in %s" number group)
(condition-case ()
(funcall nnmail-delete-file-function article)
(nconc rest articles)))
(deffoo nndiary-request-move-article
- (article group server accept-form &optional last)
+ (article group server accept-form &optional last move-is-internal)
(let ((buf (get-buffer-create " *nndiary move*"))
result)
(nndiary-possibly-change-directory group server)
(let (nndiary-current-directory
nndiary-current-group
nndiary-article-file-alist)
- (save-excursion
- (set-buffer buf)
+ (with-current-buffer buf
(insert-buffer-substring nntp-server-buffer)
(setq result (eval accept-form))
(kill-buffer (current-buffer))
(deffoo nndiary-request-accept-article (group &optional server last)
(nndiary-possibly-change-directory group server)
(nnmail-check-syntax)
- (let (result)
- (when nnmail-cache-accepted-message-ids
- (nnmail-cache-insert (nnmail-fetch-field "message-id")))
- (if (stringp group)
+ (run-hooks 'nndiary-request-accept-article-hooks)
+ (when (nndiary-schedule)
+ (let (result)
+ (when nnmail-cache-accepted-message-ids
+ (nnmail-cache-insert (nnmail-fetch-field "message-id")
+ group
+ (nnmail-fetch-field "subject")))
+ (if (stringp group)
+ (and
+ (nnmail-activate 'nndiary)
+ (setq result
+ (car (nndiary-save-mail
+ (list (cons group (nndiary-active-number group))))))
+ (progn
+ (nnmail-save-active nndiary-group-alist nndiary-active-file)
+ (and last (nndiary-save-nov))))
(and
(nnmail-activate 'nndiary)
- (setq result
- (car (nndiary-save-mail
- (list (cons group (nndiary-active-number group))))))
- (progn
+ (if (and (not (setq result
+ (nnmail-article-group 'nndiary-active-number)))
+ (yes-or-no-p "Moved to `junk' group; delete article? "))
+ (setq result 'junk)
+ (setq result (car (nndiary-save-mail result))))
+ (when last
(nnmail-save-active nndiary-group-alist nndiary-active-file)
- (and last (nndiary-save-nov))))
- (and
- (nnmail-activate 'nndiary)
- (if (and (not (setq result
- (nnmail-article-group 'nndiary-active-number)))
- (yes-or-no-p "Moved to `junk' group; delete article? "))
- (setq result 'junk)
- (setq result (car (nndiary-save-mail result))))
- (when last
- (nnmail-save-active nndiary-group-alist nndiary-active-file)
- (when nnmail-cache-accepted-message-ids
- (nnmail-cache-close))
- (nndiary-save-nov))))
- result))
+ (when nnmail-cache-accepted-message-ids
+ (nnmail-cache-close))
+ (nndiary-save-nov))))
+ result))
+ )
(deffoo nndiary-request-post (&optional server)
(nnmail-do-request-post 'nndiary-request-accept-article server))
(deffoo nndiary-request-replace-article (article group buffer)
(nndiary-possibly-change-directory group)
- (save-excursion
- (set-buffer buffer)
+ (with-current-buffer buffer
(nndiary-possibly-create-directory group)
(let ((chars (nnmail-insert-lines))
(art (concat (int-to-string article) "\t"))
t)
(setq headers (nndiary-parse-head chars article))
;; Replace the NOV line in the NOV file.
- (save-excursion
- (set-buffer (nndiary-open-nov group))
+ (with-current-buffer (nndiary-open-nov group)
(goto-char (point-min))
(if (or (looking-at art)
(search-forward (concat "\n" art) nil t))
;; we should insert it. (This situation should never
;; occur, but one likes to make sure...)
(while (and (looking-at "[0-9]+\t")
- (< (string-to-int
+ (< (string-to-number
(buffer-substring
(match-beginning 0) (match-end 0)))
article)
;; Find an article number in the current group given the Message-ID.
(defun nndiary-find-group-number (id)
- (save-excursion
- (set-buffer (get-buffer-create " *nndiary id*"))
+ (with-current-buffer (get-buffer-create " *nndiary id*")
(let ((alist nndiary-group-alist)
number)
;; We want to look through all .overview files, but we want to
(search-forward id nil t)) ; We find the ID.
;; And the id is in the fourth field.
(if (not (and (search-backward "\t" nil t 4)
- (not (search-backward"\t" (gnus-point-at-bol) t))))
+ (not (search-backward"\t" (point-at-bol) t))))
(forward-line 1)
(beginning-of-line)
(setq found t)
(let ((nov (expand-file-name nndiary-nov-file-name
nndiary-current-directory)))
(when (file-exists-p nov)
- (save-excursion
- (set-buffer nntp-server-buffer)
+ (with-current-buffer nntp-server-buffer
(erase-buffer)
(nnheader-insert-file-contents nov)
(if (and fetch-old
(defun nndiary-add-nov (group article headers)
"Add a nov line for the GROUP base."
- (save-excursion
- (set-buffer (nndiary-open-nov group))
+ (with-current-buffer (nndiary-open-nov group)
(goto-char (point-max))
(mail-header-set-number headers article)
(nnheader-insert-nov headers)))
(narrow-to-region
(goto-char (point-min))
(if (search-forward "\n\n" nil t) (1- (point)) (point-max))))
- ;; Fold continuation lines.
- (goto-char (point-min))
- (while (re-search-forward "\\(\r?\n[ \t]+\\)+" nil t)
- (replace-match " " t t))
- ;; Remove any tabs; they are too confusing.
- (subst-char-in-region (point-min) (point-max) ?\t ? )
- (let ((headers (nnheader-parse-head t)))
+ (let ((headers (nnheader-parse-naked-head)))
(mail-header-set-chars headers chars)
(mail-header-set-number headers number)
headers))))
(or (cdr (assoc group nndiary-nov-buffer-alist))
(let ((buffer (get-buffer-create (format " *nndiary overview %s*"
group))))
- (save-excursion
- (set-buffer buffer)
+ (with-current-buffer buffer
(set (make-local-variable 'nndiary-nov-buffer-file-name)
(expand-file-name
nndiary-nov-file-name
(file-directory-p dir))
(nndiary-generate-nov-databases-1 dir seen))))
;; Do this directory.
- (let ((files (sort (nnheader-article-to-file-alist dir)
+ (let ((nndiary-files (sort (nnheader-article-to-file-alist dir)
'car-less-than-car)))
- (if (not files)
+ (if (not nndiary-files)
(let* ((group (nnheader-file-to-group
(directory-file-name dir) nndiary-directory))
(info (cadr (assoc group nndiary-group-alist))))
(setcar info (1+ (cdr info)))))
(funcall nndiary-generate-active-function dir)
;; Generate the nov file.
- (nndiary-generate-nov-file dir files)
+ (nndiary-generate-nov-file dir nndiary-files)
(unless no-active
(nnmail-save-active nndiary-group-alist nndiary-active-file))))))
-(eval-when-compile (defvar files))
+(defvar nndiary-files) ; dynamically bound in nndiary-generate-nov-databases-1
(defun nndiary-generate-active-info (dir)
;; Update the active info for this group.
(let* ((group (nnheader-file-to-group
(last (or (caadr entry) 0)))
(setq nndiary-group-alist (delq entry nndiary-group-alist))
(push (list group
- (cons (or (caar files) (1+ last))
+ (cons (or (caar nndiary-files) (1+ last))
(max last
- (or (let ((f files))
- (while (cdr f) (setq f (cdr f)))
- (caar f))
+ (or (caar (last nndiary-files))
0))))
nndiary-group-alist)))
(nov (concat dir nndiary-nov-file-name))
(nov-buffer (get-buffer-create " *nov*"))
chars file headers)
- (save-excursion
- ;; Init the nov buffer.
- (set-buffer nov-buffer)
+ ;; Init the nov buffer.
+ (with-current-buffer nov-buffer
(buffer-disable-undo)
(erase-buffer)
(set-buffer nntp-server-buffer)
(unless (zerop (buffer-size))
(goto-char (point-min))
(setq headers (nndiary-parse-head chars (caar files)))
- (save-excursion
- (set-buffer nov-buffer)
+ (with-current-buffer nov-buffer
(goto-char (point-max))
(nnheader-insert-nov headers)))
(widen))
(setq files (cdr files)))
- (save-excursion
- (set-buffer nov-buffer)
+ (with-current-buffer nov-buffer
(nnmail-write-region 1 (point-max) nov nil 'nomesg)
(kill-buffer (current-buffer))))))
(defun nndiary-nov-delete-article (group article)
- (save-excursion
- (set-buffer (nndiary-open-nov group))
+ (with-current-buffer (nndiary-open-nov group)
(when (nnheader-find-nov-line article)
(delete-region (point) (progn (forward-line 1) (point)))
(when (bobp)
(nnheader-article-to-file-alist nndiary-current-directory))))
-(defun nndiary-string-to-int (str min &optional max)
- ;; Like `string-to-int' but barf if STR is not exactly an integer, and not
+(defun nndiary-string-to-number (str min &optional max)
+ ;; Like `string-to-number' but barf if STR is not exactly an integer, and not
;; within the specified bounds.
;; Signals are caught by `nndiary-schedule'.
(if (not (string-match "^[ \t]*[0-9]+[ \t]*$" str))
(nndiary-error "not an integer value")
;; else
- (let ((val (string-to-int str)))
+ (let ((val (string-to-number str)))
(and (or (< val min)
(and max (> val max)))
(nndiary-error "value out of range"))
val)))
(defun nndiary-parse-schedule-value (str min-or-values max)
- ;; Parse the schedule string STR.
- ;; Signals are caught by `nndary-schedule'.
+ ;; Parse the schedule string STR, or signal an error.
+ ;; Signals are caught by `nndiary-schedule'.
(if (string-match "[ \t]*\\*[ \t]*" str)
- ;; unspecifyed
+ ;; unspecified
nil
- ;; specifyed
+ ;; specified
(if (listp min-or-values)
;; min-or-values is values
;; #### NOTE: this is actually only a hack for time zones.
(let ((res (split-string val "-")))
(cond
((= (length res) 1)
- (nndiary-string-to-int (car res) min-or-values max))
+ (nndiary-string-to-number (car res) min-or-values max))
((= (length res) 2)
;; don't know if crontab accepts this, but ensure
;; that BEG is <= END
- (let ((beg (nndiary-string-to-int (car res) min-or-values max))
- (end (nndiary-string-to-int (cadr res) min-or-values max)))
+ (let ((beg (nndiary-string-to-number (car res) min-or-values max))
+ (end (nndiary-string-to-number (cadr res) min-or-values max)))
(cond ((< beg end)
(cons beg end))
((= beg end)
;; - Returns nil if `*'
;; - Otherwise returns a list of integers and/or ranges (BEG . END)
;; The exception is the Timze-Zone value which is always of the form (STR).
- ;; Signals are caught by `nndary-schedule'.
+ ;; Signals are caught by `nndiary-schedule'.
(let ((header (format "^X-Diary-%s: \\(.*\\)$" head)))
(goto-char (point-min))
(if (not (re-search-forward header nil t))
(nndiary-parse-schedule-value (match-string 1) min-or-values max))
))
-(defsubst nndiary-schedule ()
- (mapcar
- (lambda (elt)
- (condition-case arg
- (nndiary-parse-schedule (nth 0 elt) (nth 1 elt) (nth 2 elt))
- (t
- (nnheader-report 'nndiary "X-Diary-%s header parse error: %s."
- (car elt) (cdr arg))
- nil)))
- nndiary-headers))
-
(defun nndiary-max (spec)
;; Returns the max of specification SPEC, or nil for permanent schedules.
(unless (null spec)
(nth 6 date-elts))))
reminder res)
;; remove the DOW and DST entries
- (setf (nthcdr 6 date-elts) (nthcdr 8 date-elts))
+ (setcdr (nthcdr 5 date-elts) (nthcdr 8 date-elts))
(while (setq reminder (pop reminders))
(push
(cond ((eq (cdr reminder) 'minute)
(sort res 'time-less-p)))
(defun nndiary-last-occurence (sched)
- ;; Returns the last occurence of schedule SCHED as an Emacs time struct, or
+ ;; Returns the last occurrence of schedule SCHED as an Emacs time struct, or
;; nil for permanent schedule or errors.
(let ((minute (nndiary-max (nth 0 sched)))
(hour (nndiary-max (nth 1 sched)))
(or minute (setq minute 59))
(or hour (setq hour 23))
;; I'll just compute all possible values and test them by decreasing
- ;; order until one succeeds. This is probably quide rude, but I got
+ ;; order until one succeeds. This is probably quite rude, but I got
;; bored in finding a good algorithm for doing that ;-)
;; ### FIXME: remove identical entries.
(let ((dom-list (nth 2 sched))
(encode-time 0 minute hour
(car days) month year time-zone)))
)))))
- ;; There's an upper limit, but we didn't find any last occurence.
+ ;; There's an upper limit, but we didn't find any last occurrence.
;; This means that the schedule is undecidable. This can happen if
;; you happen to say something like "each Feb 31 until 2038".
(progn
))))
(defun nndiary-next-occurence (sched now)
- ;; Returns the next occurence of schedule SCHED, starting from time NOW.
- ;; If there's no next occurence, returns the last one (if any) which is then
+ ;; Returns the next occurrence of schedule SCHED, starting from time NOW.
+ ;; If there's no next occurrence, returns the last one (if any) which is then
;; in the past.
(let* ((today (decode-time now))
(this-minute (nth 1 today))
;; The article should be re-considered as unread if there's a reminder
;; between the group timestamp and the current time.
(when (and sched (setq sched (nndiary-next-occurence sched now)))
- (let ((reminders ;; add the next occurence itself at the end.
+ (let ((reminders ;; add the next occurrence itself at the end.
(append (nndiary-compute-reminders sched) (list sched))))
(while (and reminders (time-less-p (car reminders) timestamp))
(pop reminders))
;; The reminders might be empty if the last date is in the past,
- ;; or we've got at least the next occurence itself left. All past
+ ;; or we've got at least the next occurrence itself left. All past
;; dates are renewed.
(or (not reminders)
(time-less-p (car reminders) now)))
;; The end... ===============================================================
-(mapcar
- (lambda (elt)
- (let ((header (intern (format "X-Diary-%s" (car elt)))))
- ;; Required for building NOV databases and some other stuff
- (add-to-list 'gnus-extra-headers header)
- (add-to-list 'nnmail-extra-headers header)))
- nndiary-headers)
+(dolist (header nndiary-headers)
+ (setq header (intern (format "X-Diary-%s" (car header))))
+ ;; Required for building NOV databases and some other stuff.
+ (add-to-list 'gnus-extra-headers header)
+ (add-to-list 'nnmail-extra-headers header))
(unless (assoc "nndiary" gnus-valid-select-methods)
(gnus-declare-backend "nndiary" 'post-mail 'respool 'address))
(provide 'nndiary)
-
;;; nndiary.el ends here