From mboxrd@z Thu Jan 1 00:00:00 1970 X-Msuck: nntp://news.gmane.io/gmane.emacs.gnus.general/37761 Path: main.gmane.org!not-for-mail From: Dan Nicolaescu Newsgroups: gmane.emacs.gnus.general Subject: Re: [ANNOUNCE] NNDiary, a diary backend for Gnus. Date: 13 Aug 2001 11:29:12 -0700 Organization: SunSITE.dk - Supporting Opensource Software Message-ID: References: NNTP-Posting-Host: coloc-standby.netfonds.no Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Trace: main.gmane.org 1035173119 15515 80.91.224.250 (21 Oct 2002 04:05:19 GMT) X-Complaints-To: usenet@main.gmane.org NNTP-Posting-Date: Mon, 21 Oct 2002 04:05:19 +0000 (UTC) Return-Path: Return-Path: Original-Received: (qmail 29642 invoked from network); 13 Aug 2001 18:26:09 -0000 Original-Received: from sunsite.dk (130.225.51.30) by gnus.org with SMTP; 13 Aug 2001 18:26:09 -0000 Original-Received: (qmail 3835 invoked by uid 509); 13 Aug 2001 18:26:06 -0000 Original-To: ding@gnus.org Original-Path: not-for-mail Original-Newsgroups: emacs.ding Original-NNTP-Posting-Host: amrm2.ics.uci.edu Original-X-Trace: sunsite.dk 997727166 880 128.195.11.178 (13 Aug 2001 18:26:06 GMT) Original-X-Complaints-To: news@sunsite.dk Original-NNTP-Posting-Date: Mon, 13 Aug 2001 18:26:06 +0000 (UTC) X-Authenticated: @ User-Agent: Gnus/5.09 (Gnus v5.9.0) Emacs/21.0.102 Original-Lines: 631 Xref: main.gmane.org gmane.emacs.gnus.general:37761 X-Report-Spam: http://spam.gmane.org/gmane.emacs.gnus.general:37761 --=-=-= Content-Type: text/plain; charset=iso-8859-1 Content-Transfer-Encoding: 8bit Kai.Grossjohann@CS.Uni-Dortmund.DE (Kai Großjohann) writes: > Dan Nicolaescu writes: > > > I have a backend that I have been using for a while that does > > something similar to nndiary. > > I think it would be a good idea for someone to look at nntodo, nndiary > and your backend and make a comparison. Maybe the best parts of all > of this could be integrated somehow... I attach my backend here. I have been using it for quite a while. Just add (require 'nnlater) in your startup files. It creates an nnlater group that cannot be deleted (so that you don't lose whatever is in there by mistake). I copy stuff to the nnlater group from other groups using 'B c', it will ask when to show the message in the nnlater group. It uses nnoo and inherits from nnml, it uses the NOV file so it does not have to parse the messages in the group all the time. It's not totally bug-free... Hope this helps... --=-=-= Content-Type: application/emacs-lisp Content-Disposition: attachment; filename=nnlater.el Content-Description: nnlater.el ;;; nnlater.el --- do stuff later for Gnus ;; Copyright (C) 1995,96,97,98 Free Software Foundation, Inc. ;; Author: Dan Nicolaescu ;; Keywords: news ;; This file is not part of GNU Emacs. ;; 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, or (at your option) ;; any later version. ;; 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 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: ;;; Code: (require 'nnheader) (require 'nnmail) (require 'gnus-start) (require 'nnml) (require 'nnml) (require 'nnoo) (eval-when-compile (require 'cl) ;; This is just to shut up the byte-compiler. (fset 'nnlater-request-group 'ignore)) (nnoo-declare nnlater nnml) (defvoo nnlater-directory (nnheader-concat gnus-directory "later/") "Where nnlater will store its files." nnml-directory) (defvoo nnlater-current-group "" nil nnml-current-group) (defvoo nnlater-get-new-mail nil nil nnml-get-new-mail) (defvoo nnlater-current-directory nil nil nnml-current-directory) (defconst nnlater-version "nnlater 1.0") (defvoo nnlater-status-string "" nil nnml-status-string) ;;; Interface functions. (nnoo-define-basics nnlater) (deffoo nnlater-open-server (server &optional defs) (nnoo-change-server 'nnlater server defs) (cond ((not (file-exists-p nnlater-directory)) (nnlater-close-server) (nnheader-report 'nnlater "No such file or directory: %s" nnlater-directory)) ((not (file-directory-p (file-truename nnlater-directory))) (nnlater-close-server) (nnheader-report 'nnlater "Not a directory: %s" nnlater-directory)) (t (nnheader-report 'nnlater "Opened server %s using directory %s" server nnlater-directory) t))) (deffoo nnlater-retrieve-headers (articles &optional group server fetch-old) (nnlater-possibly-change-group group) (save-excursion (set-buffer nntp-server-buffer) (erase-buffer) (let* (article) ;; We don't support fetching by Message-ID. (if (stringp (car articles)) 'headers (while articles (narrow-to-region (point) (point)) (when (nnlater-request-article (setq article (pop articles)) group server (current-buffer)) (goto-char (point-min)) (if (search-forward "\n\n" nil t) (forward-line -1) (goto-char (point-max))) (delete-region (point) (point-max)) (goto-char (point-min)) (insert (format "221 %d Article retrieved.\n" article)) (widen) (goto-char (point-max)) (insert ".\n"))) (nnheader-fold-continuation-lines) 'headers)))) (deffoo nnlater-request-article (id &optional group server buffer) (nnlater-possibly-change-group group) (when (numberp id) ;; We get the newest file of the auto-saved file and the ;; "real" file. (let* ((file (nnlater-article-filename id)) (auto (nnlater-auto-save-file-name file)) (newest (if (file-newer-than-file-p file auto) file auto)) (nntp-server-buffer (or buffer nntp-server-buffer))) (when (and (file-exists-p newest) (let ((nnmail-file-coding-system message-draft-coding-system)) (nnmail-find-file newest))) (save-excursion (set-buffer nntp-server-buffer) (goto-char (point-min)) ;; If there's a mail header separator in this file, ;; we remove it. (when (re-search-forward (concat "^" mail-header-separator "$") nil t) (replace-match "" t t))) t)))) (deffoo nnlater-request-restore-buffer (article &optional group server) "Request a new buffer that is restored to the state of ARTICLE." (nnlater-possibly-change-group group) (when (nnlater-request-article article group server (current-buffer)) (message-remove-header "xref") (message-remove-header "lines") t)) ;; Called with NOV header as parameter, looks for X-nnlater and returns ;; t if the value contained is before the current time ;; Right now it's lame... (defun nnlater-show (nov) (let ((item-time (cdr (assq 'X-nnlater (aref nov 9))))) (time-less-p (apply 'encode-time (parse-time-string item-time)) (current-time)))) (defun nnlater-articles-to-show (group) (let ((nov-name (concat (file-name-as-directory (concat nnlater-directory group)) nnml-nov-file-name))) (if (file-exists-p nov-name) (with-temp-buffer (nnheader-insert-file-contents nov-name) (beginning-of-buffer) (let (header show-list) (while (not (eobp)) (setq header (nnheader-parse-nov)) (if (funcall 'nnlater-show header) (push (aref header 0) show-list)) (forward-line 1)) (nreverse show-list)))))) (deffoo nnlater-request-update-info (group info &optional server) (nnlater-possibly-change-group group) (gnus-info-set-read info (gnus-update-read-articles (gnus-group-prefixed-name group '(nnlater "")) (nnlater-articles-to-show group) t)) (let (marks) (when (setq marks (nth 3 info)) (setcar (nthcdr 3 info) (if (assq 'unsend marks) (list (assq 'unsend marks)) nil)))) t) (deffoo nnlater-request-associate-buffer (group) "Associate the current buffer with some article in the `later' group." (nnlater-open-server "") (nnlater-request-group group) (nnlater-possibly-change-group group) (let ((gnus-verbose-backends nil) (buf (current-buffer)) article file) (with-temp-buffer (insert-buffer-substring buf) (setq article (nnlater-request-accept-article group (nnoo-current-server 'nnlater) t 'noinsert) file (nnlater-article-filename article))) (setq buffer-file-name (expand-file-name file) buffer-auto-save-file-name (make-auto-save-file-name)) (goto-char (point-min)) ;(if (not (assq 'X-nnlater (aref header 9))) ;(message "req-ass-buf") ;; FIXME: do we need this? (insert (format "X-nnlater1: %s" (nnlater-query-time))) ;) (clear-visited-file-modtime) article)) (deffoo nnlater-request-expire-articles (articles group &optional server force) (nnlater-possibly-change-group group) (let* ((nnml-allow-delete-final t) (res (nnoo-parent-function 'nnlater 'nnml-request-expire-articles (list articles group server force))) article) ;; Delete all the "state" files of articles that have been expired. (while articles (unless (memq (setq article (pop articles)) res) (let ((auto (nnlater-auto-save-file-name (nnlater-article-filename article)))) (when (file-exists-p auto) (funcall nnmail-delete-file-function auto))) (dolist (backup (let ((kept-new-versions 1) (kept-old-versions 0)) (find-backup-file-name (nnlater-article-filename article)))) (when (file-exists-p backup) (funcall nnmail-delete-file-function backup))))) res)) (deffoo nnlater-request-accept-article (group &optional server last noinsert) (nnlater-possibly-change-group group) (goto-char (point-min)) (insert (format "X-nnlater: %s\n" (nnlater-query-time))) (let ((gnus-verbose-backends nil) (result (nnoo-parent-function 'nnlater 'nnml-request-accept-article (list group server last))) (header nil)) ;(message (format "crt-buffer: %s" (current-buffer))) (set-buffer nntp-server-buffer) (nnheader-insert-file-contents (nnlater-article-filename (cdr result))) (goto-char (point-min)) ;(message (format "result: %s" result)) ;(message (format "group: %s" group)) ;(message (format "server: %s" server)) ;(message (format "last: %s" last)) (setq header (nnheader-parse-head)) ;(message (format "aici: %s" header)) ;(if (not (assq 'X-nnlater (aref header 9))) ;(message "request-acc-art") ;) ;; regenerate the nov database ;; FIXME: there should be a better way to have it regenerated... (nnlater-generate-nov-databases) result)) (deffoo nnlater-request-create-group (group &optional server args) (nnlater-possibly-change-group group) (if (file-exists-p nnlater-current-directory) (if (file-directory-p nnlater-current-directory) (unless (assoc group nnml-group-alist) (let (active) (push (list group (setq active (cons 1 0))) nnml-group-alist) (nnml-possibly-create-directory group) (nnml-possibly-change-directory group server) (let ((articles (nnlater-articles))) ;; FIXME: maybe we need to check what articles to ;; show (when articles (setcar active (apply 'min articles)) (setcdr active (apply 'max articles)))))) nil) (condition-case () (progn (gnus-make-directory nnlater-current-directory) t) (file-error nil)))) ;;; Low-Level Interface (defun nnlater-possibly-change-group (group) (when (and group (not (equal group nnlater-current-group))) (nnlater-open-server "") (setq nnlater-current-group group) (setq nnlater-current-directory (nnheader-concat nnlater-directory group)))) (defun nnlater-article-filename (article &rest args) (apply 'concat (file-name-as-directory nnlater-current-directory) (int-to-string article) args)) (defun nnlater-auto-save-file-name (file) (save-excursion (prog1 (progn (set-buffer (get-buffer-create " *later tmp*")) (setq buffer-file-name file) (make-auto-save-file-name)) (kill-buffer (current-buffer))))) (defun nnlater-articles () "Return the list of messages in the group." (gnus-make-directory nnlater-current-directory) (sort (mapcar 'string-to-int (directory-files nnlater-current-directory nil "\\`[0-9]+\\'" t)) '<)) (defvoo nnlater-active-file (concat (file-name-as-directory nnlater-directory) "active") "Mail active file.") (defvoo nnlater-generate-active-function 'nnlater-generate-active-info) (defun nnlater-generate-nov-databases () "Generate NOV databases in all nnlater directories." (interactive) ;; Read the active file to make sure we don't re-use articles ;; numbers in empty groups. (nnmail-activate 'nnml) (nnml-open-server (or (nnoo-current-server 'nnlater) "")) (setq nnlater-directory (expand-file-name nnlater-directory)) ;; Recurse down the directories. (nnlater-generate-nov-databases-1 nnlater-directory nil t) ;; Save the active file. (nnmail-save-active nnml-group-alist nnlater-active-file)) (defun nnlater-generate-nov-databases-1 (dir &optional seen no-active) "Regenerate the NOV database in DIR." (interactive "DRegenerate NOV in: ") (setq dir (file-name-as-directory dir)) ;; Only scan this sub-tree if we haven't been here yet. (unless (member (file-truename dir) seen) (push (file-truename dir) seen) ;; We descend recursively (let ((dirs (directory-files dir t nil t)) dir) (while (setq dir (pop dirs)) (when (and (not (string-match "^\\." (file-name-nondirectory dir))) (file-directory-p dir)) (nnlater-generate-nov-databases-1 dir seen)))) ;; Do this directory. (let ((files (sort (nnheader-article-to-file-alist dir) 'car-less-than-car))) (if (not files) (let* ((group (nnheader-file-to-group (directory-file-name dir) nnlater-directory)) (info (cadr (assoc group nnml-group-alist)))) (when info (setcar info (1+ (cdr info))))) (funcall nnlater-generate-active-function dir) ;; Generate the nov file. (nnml-generate-nov-file dir files) (unless no-active (nnmail-save-active nnml-group-alist nnlater-active-file)))))) (eval-when-compile (defvar files)) (defun nnlater-generate-active-info (dir) ;; Update the active info for this group. (let ((group (nnheader-file-to-group (directory-file-name dir) nnlater-directory))) (setq nnml-group-alist (delq (assoc group nnml-group-alist) nnml-group-alist)) (push (list group (cons (caar files) (let ((f files)) (while (cdr f) (setq f (cdr f))) (caar f)))) nnml-group-alist))) (defun nnlater-request-regenerate (server) (nnml-possibly-change-directory nil server) (nnlater-generate-nov-databases) t) (defvar gnus-delay-default-delay "3d" "*Default length of delay.") (defvar gnus-delay-default-hour 8 "*If deadline is given as date, then assume this time of day.") ;; Tis function is supposed to be called when a message is moved to ;; an nnlater group and it does not have an X-nnlater header. ;; lifted from gnus-delay.el (defun nnlater-query-time () "Delay this article by some time. DELAY is a string, giving the length of the time. Possible values are: * for in minutes (`m'), hours (`h'), days (`d'), weeks (`w'), months (`M'), or years (`Y'); * YYYY-MM-DD for a specific date. The time of day is given by the variable `gnus-delay-default-hour', minute and second are zero." (interactive) (let ((delay (read-string "Target date (YYYY-MM-DD) or length of delay (units in [mhdwMY]): " gnus-delay-default-delay)) num unit days year month day deadline) (cond ((string-match "\\([0-9][0-9][0-9]?[0-9]?\\)-\\([0-9]+\\)-\\([0-9]+\\)" delay) (setq year (string-to-number (match-string 1 delay)) month (string-to-number (match-string 2 delay)) day (string-to-number (match-string 3 delay))) (setq deadline (message-make-date (encode-time 0 0 ; second and minute gnus-delay-default-hour day month year)))) ((string-match "\\([0-9]+\\)\\s-*\\([mhdwMY]\\)" delay) (setq num (match-string 1 delay)) (setq unit (match-string 2 delay)) ;; Start from seconds, then multiply into needed units. (setq num (string-to-number num)) (cond ((string= unit "Y") (setq delay (* num 60 60 24 365))) ((string= unit "M") (setq delay (* num 60 60 24 30))) ((string= unit "w") (setq delay (* num 60 60 24 7))) ((string= unit "d") (setq delay (* num 60 60 24))) ((string= unit "h") (setq delay (* num 60 60))) (t (setq delay (* num 60)))) (setq deadline (message-make-date (seconds-to-time (+ (time-to-seconds (current-time)) delay))))) (t (error "Malformed delay `%s'" delay))))) ;; FIXME: these should be somewhere in a setup function (add-to-list 'gnus-extra-headers 'X-nnlater) (add-to-list 'nnmail-extra-headers 'X-nnlater) ;;; created following the `gnus-start-draft-setup' model ;;;###autoload (defun gnus-start-later-setup () "Make sure the `later' group exists." (gnus-request-create-group "later" '(nnlater "")) (unless (gnus-gethash "nnlater:later" gnus-newsrc-hashtb) (let ((gnus-level-default-subscribed 1)) (gnus-subscribe-group "nnlater:later" nil '(nnlater ""))) (gnus-group-set-parameter "nnlater:later" 'charset "nil") (gnus-group-set-parameter "nnlater:later" 'gnus-dummy '((gnus-later-mode))))) (autoload 'gnus-later-mode "gnus-later" nil t) (add-hook 'gnus-setup-news-hook 'gnus-start-later-setup) (nnoo-import nnlater (nnml nnml-retrieve-headers nnml-request-group nnml-close-group nnml-request-list nnml-request-newsgroups nnml-request-move-article nnml-request-replace-article)) (provide 'nnlater) ;; hook (unless (assoc "nnlater" gnus-valid-select-methods) (gnus-declare-backend "nnlater" 'post 'respool 'address)) ;;; nnlater.el ends here --=-=-= Content-Type: application/emacs-lisp Content-Disposition: attachment; filename=gnus-later.el Content-Description: gnus-later.el ;;; gnus-later.el --- later support for Gnus ;; Copyright (C) 1997,98 Free Software Foundation, Inc. ;; Author: Dan Nicolaescu ;; Keywords: news ;; This file is part of GNU Emacs. ;; 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, or (at your option) ;; any later version. ;; 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 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: ;;; Code: (require 'gnus) (require 'gnus-sum) (require 'message) (require 'gnus-msg) (require 'nnlater) (require 'gnus-agent) (eval-when-compile (require 'cl)) ;;; Later minor mode (defvar gnus-later-mode nil "Minor mode for providing summary buffers for nnlater.") (defvar gnus-later-mode-map nil) (unless gnus-later-mode-map (setq gnus-later-mode-map (make-sparse-keymap)) (gnus-define-keys gnus-later-mode-map "De" gnus-later-edit-message)) (defun gnus-later-make-menu-bar () (unless (boundp 'gnus-later-menu) (easy-menu-define gnus-later-menu gnus-later-mode-map "" '("Later" ["Edit" gnus-later-edit-message t] ["Delete later" gnus-summary-delete-article t])))) (defun gnus-later-mode (&optional arg) "Minor mode for `later' summary buffers. \\{gnus-later-mode-map}" (interactive "P") (when (eq major-mode 'gnus-summary-mode) (when (set (make-local-variable 'gnus-later-mode) (if (null arg) (not gnus-later-mode) (> (prefix-numeric-value arg) 0))) ;; Set up the menu. (when (gnus-visual-p 'later-menu 'menu) (gnus-later-make-menu-bar)) (gnus-add-minor-mode 'gnus-later-mode " Later" gnus-later-mode-map) (gnus-run-hooks 'gnus-later-mode-hook)))) ;;; Commands (defun gnus-later-edit-message () "Enter a mail/post buffer to edit and send the Later article." (interactive) (let ((article (gnus-summary-article-number))) (gnus-summary-mark-as-read article gnus-canceled-mark) (gnus-later-setup article gnus-newsgroup-name) (set-buffer-modified-p t) (save-buffer) (let ((gnus-verbose-backends nil)) (gnus-request-expire-articles (list article) gnus-newsgroup-name t)) (push `((lambda () (when (gnus-buffer-exists-p ,gnus-summary-buffer) (save-excursion (set-buffer ,gnus-summary-buffer) (gnus-cache-possibly-remove-article ,article nil nil nil t))))) message-send-actions))) ;;; Utility functions ;;;!!!If this is byte-compiled, it fails miserably. ;;;!!!This is because `gnus-setup-message' uses uninterned symbols. ;;;!!!This has been fixed in recent versions of Emacs and XEmacs, ;;;!!!but for the time being, we'll just run this tiny function uncompiled. (progn (defun gnus-later-setup (narticle group) (gnus-setup-message 'forward (let ((article narticle)) (message-mail) (erase-buffer) (if (not (gnus-request-restore-buffer article group)) (error "Couldn't restore the article") ;; Insert the separator. (goto-char (point-min)) (search-forward "\n\n") (forward-char -1) (insert mail-header-separator) (forward-line 1) (message-set-auto-save-file-name)))))) (provide 'gnus-later) ;;; gnus-later.el ends here --=-=-=--