1 ;;; nnbabyl.el --- mail mbox access for Gnus
2 ;; Copyright (C) 1995 Free Software Foundation, Inc.
4 ;; Author: Lars Ingebrigtsen <larsi@ifi.uio.no>
5 ;; Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
6 ;; Keywords: news, mail
8 ;; This file is part of GNU Emacs.
10 ;; GNU Emacs is free software; you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation; either version 2, or (at your option)
15 ;; GNU Emacs is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;; GNU General Public License for more details.
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs; see the file COPYING. If not, write to
22 ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
32 (defvar nnbabyl-mbox-file (expand-file-name "~/RMAIL")
33 "The name of the mail box file in the users home directory.")
35 (defvar nnbabyl-active-file (expand-file-name "~/.rmail-active")
36 "The name of the active file for the mail box.")
38 (defvar nnbabyl-get-new-mail t
39 "If non-nil, nnml will check the incoming mail file and split the mail.")
43 (defvar nnbabyl-mail-delimiter "\^_")
45 (defconst nnbabyl-version "nnbabyl 0.1"
48 (defvar nnbabyl-current-group nil
49 "Current nnbabyl news group directory.")
51 (defconst nnbabyl-mbox-buffer " *nnbabyl mbox buffer*")
53 (defvar nnbabyl-status-string "")
55 (defvar nnbabyl-group-alist nil)
57 ;;; Interface functions
59 (defun nnbabyl-retrieve-headers (sequence &optional newsgroup server)
60 "Retrieve the headers for the articles in SEQUENCE.
61 Newsgroup must be selected before calling this function."
63 (set-buffer nntp-server-buffer)
66 (number (length sequence))
68 beg article art-string start stop)
69 (nnbabyl-possibly-change-newsgroup newsgroup)
71 (setq article (car sequence))
72 (setq art-string (nnbabyl-article-string article))
73 (set-buffer nnbabyl-mbox-buffer)
74 (if (or (search-forward art-string nil t)
76 (search-forward art-string nil t)))
81 (concat "^" nnbabyl-mail-delimiter) nil t)
82 (while (and (not (looking-at ".+:"))
83 (zerop (forward-line 1))))
85 (search-forward "\n\n" nil t)
86 (setq stop (1- (point)))
87 (set-buffer nntp-server-buffer)
88 (insert (format "221 %d Article retrieved.\n" article))
90 (insert-buffer-substring nnbabyl-mbox-buffer start stop)
91 (goto-char (point-max))
93 (setq sequence (cdr sequence))
94 (setq count (1+ count))
95 (and (numberp nnmail-large-newsgroup)
96 (> number nnmail-large-newsgroup)
99 (message "nnbabyl: Receiving headers... %d%%"
100 (/ (* count 100) number))))
102 (and (numberp nnmail-large-newsgroup)
103 (> number nnmail-large-newsgroup)
104 gnus-verbose-backends
105 (message "nnbabyl: Receiving headers... done"))
107 ;; Fold continuation lines.
109 (while (re-search-forward "\\(\r?\n[ \t]+\\)+" nil t)
110 (replace-match " " t t))
113 (defun nnbabyl-open-server (host &optional service)
115 (setq nnbabyl-status-string "")
116 (setq nnbabyl-group-alist nil)
117 (nnheader-init-server-buffer))
119 (defun nnbabyl-close-server (&optional server)
123 (defun nnbabyl-server-opened (&optional server)
124 "Return server process status, T or NIL.
125 If the stream is opened, return T, otherwise return NIL."
126 (and nntp-server-buffer
127 (get-buffer nntp-server-buffer)))
129 (defun nnbabyl-status-message ()
130 "Return server status response as string."
131 nnbabyl-status-string)
133 (defun nnbabyl-request-article (article &optional newsgroup server buffer)
134 "Select ARTICLE by number."
135 (nnbabyl-possibly-change-newsgroup newsgroup)
136 (if (stringp article)
139 (set-buffer nnbabyl-mbox-buffer)
141 (if (search-forward (nnbabyl-article-string article) nil t)
143 (re-search-backward (concat "^" nnbabyl-mail-delimiter) nil t)
144 (while (and (not (looking-at ".+:"))
145 (zerop (forward-line 1))))
147 (or (and (re-search-forward
148 (concat "^" nnbabyl-mail-delimiter) nil t)
150 (goto-char (point-max)))
152 (let ((nntp-server-buffer (or buffer nntp-server-buffer)))
153 (set-buffer nntp-server-buffer)
155 (insert-buffer-substring nnbabyl-mbox-buffer start stop)
156 (goto-char (point-min))
157 (if (search-forward "\n*** EOOH ***" nil t)
159 (delete-region (progn (beginning-of-line) (point))
160 (or (search-forward "\n\n" nil t)
164 (defun nnbabyl-request-group (group &optional server dont-check)
167 (if (nnbabyl-possibly-change-newsgroup group)
170 (nnbabyl-get-new-mail)
172 (set-buffer nntp-server-buffer)
174 (let ((active (assoc group nnbabyl-group-alist)))
175 (insert (format "211 %d %d %d %s\n"
176 (1+ (- (cdr (car (cdr active)))
177 (car (car (cdr active)))))
178 (car (car (cdr active)))
179 (cdr (car (cdr active)))
183 (defun nnbabyl-close-group (group &optional server)
186 (defun nnbabyl-request-list (&optional server)
187 "List active newsgoups."
188 (if server (nnbabyl-get-new-mail))
189 (nnmail-find-file nnbabyl-active-file))
191 (defun nnbabyl-request-newgroups (date &optional server)
192 "List groups created after DATE."
193 (nnbabyl-request-list server))
195 (defun nnbabyl-request-list-newsgroups (&optional server)
196 "List newsgroups (defined in NNTP2)."
197 (setq nnbabyl-status-string "nnbabyl: LIST NEWSGROUPS is not implemented.")
200 (defun nnbabyl-request-post (&optional server)
201 "Post a new news in current buffer."
202 (mail-send-and-exit nil))
204 (fset 'nnbabyl-request-post-buffer 'nnmail-request-post-buffer)
206 (defun nnbabyl-request-expire-articles (articles newsgroup &optional server force)
207 "Expire all articles in the ARTICLES list in group GROUP.
208 The list of unexpired articles will be returned (ie. all articles that
209 were too fresh to be expired).
210 If FORCE is non-nil, the ARTICLES will be deleted without looking at
212 (nnbabyl-possibly-change-newsgroup newsgroup)
213 (let* ((days (or (and nnmail-expiry-wait-function
214 (funcall nnmail-expiry-wait-function newsgroup))
218 (set-buffer nnbabyl-mbox-buffer)
221 (if (search-forward (nnbabyl-article-string (car articles)) nil t)
223 (> (nnmail-days-between
224 (current-time-string)
226 (point) (progn (end-of-line) (point))))
229 (and gnus-verbose-backends
230 (message "Deleting: %s" (car articles)))
231 (nnbabyl-delete-mail))
232 (setq rest (cons (car articles) rest))))
233 (setq articles (cdr articles)))
237 (defun nnbabyl-request-move-article (article group server accept-form)
238 (nnbabyl-possibly-change-newsgroup group)
239 (let ((buf (get-buffer-create " *nnbabyl move*"))
242 (nnbabyl-request-article article group server)
245 (insert-buffer-substring nntp-server-buffer)
246 (goto-char (point-min))
247 (if (re-search-forward
249 (save-excursion (search-forward "\n\n" nil t) (point)) t)
250 (delete-region (progn (beginning-of-line) (point))
251 (progn (forward-line 1) (point))))
252 (setq result (eval accept-form))
253 (kill-buffer (current-buffer))
256 (set-buffer nnbabyl-mbox-buffer)
258 (if (search-forward (nnbabyl-article-string article) nil t)
259 (nnbabyl-delete-mail))
263 (defun nnbabyl-request-accept-article (group)
264 (let ((buf (current-buffer))
267 (setq nnbabyl-group-alist (nnmail-get-active))
269 (set-buffer nnbabyl-mbox-buffer)
270 (setq beg (goto-char (point-max)))
271 (insert-buffer-substring buf)
275 (search-forward "\n\n" nil t)
278 (while (re-search-backward "^X-Gnus-Newsgroup: " beg t)
279 (delete-region (point) (progn (forward-line 1) (point)))))
280 (setq result (nnbabyl-insert-newsgroup-line group)))
281 (setq result (nnbabyl-save-mail)))
284 (nnmail-save-active nnbabyl-group-alist nnbabyl-active-file))
287 (defun nnbabyl-request-replace-article (article group buffer)
288 (nnbabyl-possibly-change-newsgroup group)
290 (set-buffer nnbabyl-mbox-buffer)
292 (if (not (search-forward (nnbabyl-article-string article) nil t))
294 (nnbabyl-delete-mail t t)
295 (insert-buffer-substring buffer)
300 ;;; Low-Level Interface
302 (defun nnbabyl-delete-mail (&optional force leave-delim)
303 "If FORCE, delete article no matter how many X-Gnus-Newsgroup
304 headers there are. If LEAVE-DELIM, don't delete the Unix mbox
306 ;; Delete the current X-Gnus-Newsgroup line.
309 (progn (beginning-of-line) (point))
310 (progn (forward-line 1) (point))))
311 ;; Beginning of the article.
316 (re-search-backward (concat "^" nnbabyl-mail-delimiter) nil t)
317 (if leave-delim (progn (forward-line 1) (point))
318 (match-beginning 0)))
321 (or (and (re-search-forward (concat "^" nnbabyl-mail-delimiter)
323 (if (and (not (bobp)) leave-delim)
324 (progn (forward-line -2) (point))
325 (match-beginning 0)))
327 (goto-char (point-min))
328 ;; Only delete the article if no other groups owns it as well.
329 (if (or force (not (re-search-forward "^X-Gnus-Newsgroup: " nil t)))
330 (delete-region (point-min) (point-max))))))
332 (defun nnbabyl-possibly-change-newsgroup (newsgroup)
333 (if (not (get-buffer nnbabyl-mbox-buffer))
335 (let ((buf (or (get-buffer (file-name-nondirectory nnbabyl-mbox-file))
336 (create-file-buffer nnbabyl-mbox-file))))
337 (set-buffer (setq nnbabyl-mbox-buffer buf))
338 (insert-file-contents nnbabyl-mbox-file)
339 (setq buffer-file-name nnbabyl-mbox-file))
340 (buffer-disable-undo (current-buffer))))
341 (if (not nnbabyl-group-alist)
342 (setq nnbabyl-group-alist (nnmail-get-active)))
344 (if (assoc newsgroup nnbabyl-group-alist)
345 (setq nnbabyl-current-group newsgroup))))
347 (defun nnbabyl-article-string (article)
348 (concat "\nX-Gnus-Newsgroup: " nnbabyl-current-group ":"
349 (int-to-string article)))
351 (defun nnbabyl-save-mail ()
352 "Called narrowed to an article."
353 (let ((group-art (nreverse (nnmail-article-group 'nnbabyl-active-number))))
354 (nnmail-insert-lines)
355 (nnmail-insert-xref group-art)
356 (nnbabyl-insert-newsgroup-line group-art)))
358 (defun nnbabyl-insert-newsgroup-line (group-art)
360 (goto-char (point-min))
361 (or (looking-at "\^_")
362 (insert "\^_\^L\n0, unseen,,\n*** EOOH ***\n"))
363 (while (looking-at "From ")
364 (replace-match "Mail-from: ")
366 (if (search-forward "\n\n" nil t)
370 (insert (format "X-Gnus-Newsgroup: %s:%d %s\n"
371 (car (car group-art)) (cdr (car group-art))
372 (current-time-string)))
373 (setq group-art (cdr group-art)))))))
375 (defun nnbabyl-active-number (group)
376 "Find the next article number in GROUP."
377 (let ((active (car (cdr (assoc group nnbabyl-group-alist)))))
378 (setcdr active (1+ (cdr active)))
381 (defun nnbabyl-read-mbox ()
382 (nnbabyl-request-list)
383 (setq nnbabyl-group-alist (nnmail-get-active))
384 (if (not (file-exists-p nnbabyl-mbox-file))
385 (write-region 1 1 nnbabyl-mbox-file t 'nomesg))
386 (if (and nnbabyl-mbox-buffer
387 (get-buffer nnbabyl-mbox-buffer)
388 (buffer-name nnbabyl-mbox-buffer)
390 (set-buffer nnbabyl-mbox-buffer)
391 (= (buffer-size) (nth 7 (file-attributes nnbabyl-mbox-file)))))
394 (let ((delim (concat "^" nnbabyl-mail-delimiter))
395 (buf (or (get-buffer (file-name-nondirectory nnbabyl-mbox-file))
396 (create-file-buffer nnbabyl-mbox-file)))
398 (set-buffer (setq nnbabyl-mbox-buffer buf))
399 (insert-file-contents nnbabyl-mbox-file)
400 (setq buffer-file-name nnbabyl-mbox-file)
402 (buffer-disable-undo (current-buffer))
403 (goto-char (point-min))
404 (while (re-search-forward delim nil t)
405 (setq start (match-beginning 0))
406 (if (not (search-forward "\nX-Gnus-Newsgroup: "
411 (re-search-forward delim nil t)
419 (narrow-to-region start end)
420 (nnbabyl-save-mail))))
423 (defun nnbabyl-get-new-mail ()
426 (if (and nnmail-spool-file
427 (file-exists-p nnmail-spool-file)
428 (> (nth 7 (file-attributes nnmail-spool-file)) 0))
430 (and gnus-verbose-backends
431 (message "nnbabyl: Reading incoming mail..."))
433 (nnmail-move-inbox nnmail-spool-file
434 (concat nnbabyl-mbox-file "-Incoming")))
436 (let ((in-buf (nnmail-split-incoming
437 incoming 'nnbabyl-save-mail t)))
438 (set-buffer nnbabyl-mbox-buffer)
439 (goto-char (point-max))
440 (search-backward "\n\^_" nil t)
441 (insert-buffer-substring in-buf)
442 (kill-buffer in-buf)))
443 (run-hooks 'nnmail-read-incoming-hook)
444 (and gnus-verbose-backends
445 (message "nnbabyl: Reading incoming mail...done"))))
446 (and (buffer-modified-p nnbabyl-mbox-buffer)
448 (nnmail-save-active nnbabyl-group-alist nnbabyl-active-file)
449 (set-buffer nnbabyl-mbox-buffer)
451 ;; (if incoming (delete-file incoming))
456 ;;; nnbabyl.el ends here