Mercurial > emacs
annotate lisp/gnus/nnsoup.el @ 24419:30e478cd167e
(shell-command-default-error-buffer): Renamed from
shell-command-on-region-default-error-buffer.
(shell-command-on-region): Mention in echo area when there
is some error output. Mention success or failure, too.
Accumulate multiple error outputs
going forward, with formfeed in between. Display the error buffer
when we have put something in it.
(shell-command): Add the ERROR-BUFFER argument feature.
author | Karl Heuer <kwzh@gnu.org> |
---|---|
date | Mon, 01 Mar 1999 03:19:32 +0000 |
parents | 15fc6acbae7a |
children | 6df76c3ff5c2 |
rev | line source |
---|---|
17493 | 1 ;;; nnsoup.el --- SOUP access for Gnus |
24357
15fc6acbae7a
Upgrading to Gnus 5.7; see ChangeLog
Lars Magne Ingebrigtsen <larsi@gnus.org>
parents:
19969
diff
changeset
|
2 ;; Copyright (C) 1995,96,97,98 Free Software Foundation, Inc. |
17493 | 3 |
24357
15fc6acbae7a
Upgrading to Gnus 5.7; see ChangeLog
Lars Magne Ingebrigtsen <larsi@gnus.org>
parents:
19969
diff
changeset
|
4 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org> |
17493 | 5 ;; Masanobu UMEDA <umerin@flab.flab.fujitsu.junet> |
6 ;; Keywords: news, mail | |
7 | |
8 ;; This file is part of GNU Emacs. | |
9 | |
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) | |
13 ;; any later version. | |
14 | |
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. | |
19 | |
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 the | |
22 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
23 ;; Boston, MA 02111-1307, USA. | |
24 | |
25 ;;; Commentary: | |
26 | |
27 ;;; Code: | |
28 | |
29 (require 'nnheader) | |
30 (require 'nnmail) | |
31 (require 'gnus-soup) | |
32 (require 'gnus-msg) | |
33 (require 'nnoo) | |
34 (eval-when-compile (require 'cl)) | |
35 | |
36 (nnoo-declare nnsoup) | |
37 | |
38 (defvoo nnsoup-directory "~/SOUP/" | |
39 "*SOUP packet directory.") | |
40 | |
41 (defvoo nnsoup-tmp-directory "/tmp/" | |
42 "*Where nnsoup will store temporary files.") | |
43 | |
44 (defvoo nnsoup-replies-directory (concat nnsoup-directory "replies/") | |
45 "*Directory where outgoing packets will be composed.") | |
46 | |
47 (defvoo nnsoup-replies-format-type ?n | |
48 "*Format of the replies packages.") | |
49 | |
50 (defvoo nnsoup-replies-index-type ?n | |
51 "*Index type of the replies packages.") | |
52 | |
53 (defvoo nnsoup-active-file (concat nnsoup-directory "active") | |
54 "Active file.") | |
55 | |
56 (defvoo nnsoup-packer "tar cf - %s | gzip > $HOME/Soupin%d.tgz" | |
57 "Format string command for packing a SOUP packet. | |
58 The SOUP files will be inserted where the %s is in the string. | |
59 This string MUST contain both %s and %d. The file number will be | |
60 inserted where %d appears.") | |
61 | |
62 (defvoo nnsoup-unpacker "gunzip -c %s | tar xvf -" | |
63 "*Format string command for unpacking a SOUP packet. | |
64 The SOUP packet file name will be inserted at the %s.") | |
65 | |
66 (defvoo nnsoup-packet-directory "~/" | |
67 "*Where nnsoup will look for incoming packets.") | |
68 | |
69 (defvoo nnsoup-packet-regexp "Soupout" | |
70 "*Regular expression matching SOUP packets in `nnsoup-packet-directory'.") | |
71 | |
24357
15fc6acbae7a
Upgrading to Gnus 5.7; see ChangeLog
Lars Magne Ingebrigtsen <larsi@gnus.org>
parents:
19969
diff
changeset
|
72 (defvoo nnsoup-always-save t |
15fc6acbae7a
Upgrading to Gnus 5.7; see ChangeLog
Lars Magne Ingebrigtsen <larsi@gnus.org>
parents:
19969
diff
changeset
|
73 "If non nil commit the reply buffer on each message send. |
15fc6acbae7a
Upgrading to Gnus 5.7; see ChangeLog
Lars Magne Ingebrigtsen <larsi@gnus.org>
parents:
19969
diff
changeset
|
74 This is necessary if using message mode outside Gnus with nnsoup as a |
15fc6acbae7a
Upgrading to Gnus 5.7; see ChangeLog
Lars Magne Ingebrigtsen <larsi@gnus.org>
parents:
19969
diff
changeset
|
75 backend for the messages.") |
15fc6acbae7a
Upgrading to Gnus 5.7; see ChangeLog
Lars Magne Ingebrigtsen <larsi@gnus.org>
parents:
19969
diff
changeset
|
76 |
17493 | 77 |
78 | |
79 (defconst nnsoup-version "nnsoup 0.0" | |
80 "nnsoup version.") | |
81 | |
82 (defvoo nnsoup-status-string "") | |
83 (defvoo nnsoup-group-alist nil) | |
84 (defvoo nnsoup-current-prefix 0) | |
85 (defvoo nnsoup-replies-list nil) | |
86 (defvoo nnsoup-buffers nil) | |
87 (defvoo nnsoup-current-group nil) | |
88 (defvoo nnsoup-group-alist-touched nil) | |
89 (defvoo nnsoup-article-alist nil) | |
90 | |
91 | |
92 ;;; Interface functions. | |
93 | |
94 (nnoo-define-basics nnsoup) | |
95 | |
96 (deffoo nnsoup-retrieve-headers (sequence &optional group server fetch-old) | |
97 (nnsoup-possibly-change-group group) | |
98 (save-excursion | |
99 (set-buffer nntp-server-buffer) | |
100 (erase-buffer) | |
101 (let ((areas (cddr (assoc nnsoup-current-group nnsoup-group-alist))) | |
102 (articles sequence) | |
103 (use-nov t) | |
104 useful-areas this-area-seq msg-buf) | |
105 (if (stringp (car sequence)) | |
106 ;; We don't support fetching by Message-ID. | |
107 'headers | |
108 ;; We go through all the areas and find which files the | |
109 ;; articles in SEQUENCE come from. | |
110 (while (and areas sequence) | |
111 ;; Peel off areas that are below sequence. | |
112 (while (and areas (< (cdaar areas) (car sequence))) | |
113 (setq areas (cdr areas))) | |
114 (when areas | |
115 ;; This is a useful area. | |
116 (push (car areas) useful-areas) | |
117 (setq this-area-seq nil) | |
118 ;; We take note whether this MSG has a corresponding IDX | |
119 ;; for later use. | |
120 (when (or (= (gnus-soup-encoding-index | |
121 (gnus-soup-area-encoding (nth 1 (car areas)))) ?n) | |
122 (not (file-exists-p | |
123 (nnsoup-file | |
124 (gnus-soup-area-prefix (nth 1 (car areas))))))) | |
125 (setq use-nov nil)) | |
126 ;; We assign the portion of `sequence' that is relevant to | |
127 ;; this MSG packet to this packet. | |
128 (while (and sequence (<= (car sequence) (cdaar areas))) | |
129 (push (car sequence) this-area-seq) | |
130 (setq sequence (cdr sequence))) | |
131 (setcar useful-areas (cons (nreverse this-area-seq) | |
132 (car useful-areas))))) | |
133 | |
134 ;; We now have a list of article numbers and corresponding | |
135 ;; areas. | |
136 (setq useful-areas (nreverse useful-areas)) | |
137 | |
138 ;; Two different approaches depending on whether all the MSG | |
139 ;; files have corresponding IDX files. If they all do, we | |
140 ;; simply return the relevant IDX files and let Gnus sort out | |
141 ;; what lines are relevant. If some of the IDX files are | |
142 ;; missing, we must return HEADs for all the articles. | |
143 (if use-nov | |
144 ;; We have IDX files for all areas. | |
145 (progn | |
146 (while useful-areas | |
147 (goto-char (point-max)) | |
148 (let ((b (point)) | |
149 (number (car (nth 1 (car useful-areas)))) | |
150 (index-buffer (nnsoup-index-buffer | |
151 (gnus-soup-area-prefix | |
152 (nth 2 (car useful-areas)))))) | |
153 (when index-buffer | |
154 (insert-buffer-substring index-buffer) | |
155 (goto-char b) | |
156 ;; We have to remove the index number entires and | |
157 ;; insert article numbers instead. | |
158 (while (looking-at "[0-9]+") | |
159 (replace-match (int-to-string number) t t) | |
160 (incf number) | |
161 (forward-line 1)))) | |
162 (setq useful-areas (cdr useful-areas))) | |
163 'nov) | |
164 ;; We insert HEADs. | |
165 (while useful-areas | |
166 (setq articles (caar useful-areas) | |
167 useful-areas (cdr useful-areas)) | |
168 (while articles | |
169 (when (setq msg-buf | |
170 (nnsoup-narrow-to-article | |
171 (car articles) (cdar useful-areas) 'head)) | |
172 (goto-char (point-max)) | |
173 (insert (format "221 %d Article retrieved.\n" (car articles))) | |
174 (insert-buffer-substring msg-buf) | |
175 (goto-char (point-max)) | |
176 (insert ".\n")) | |
177 (setq articles (cdr articles)))) | |
178 | |
179 (nnheader-fold-continuation-lines) | |
180 'headers))))) | |
181 | |
182 (deffoo nnsoup-open-server (server &optional defs) | |
183 (nnoo-change-server 'nnsoup server defs) | |
184 (when (not (file-exists-p nnsoup-directory)) | |
185 (condition-case () | |
186 (make-directory nnsoup-directory t) | |
187 (error t))) | |
188 (cond | |
189 ((not (file-exists-p nnsoup-directory)) | |
190 (nnsoup-close-server) | |
191 (nnheader-report 'nnsoup "Couldn't create directory: %s" nnsoup-directory)) | |
192 ((not (file-directory-p (file-truename nnsoup-directory))) | |
193 (nnsoup-close-server) | |
194 (nnheader-report 'nnsoup "Not a directory: %s" nnsoup-directory)) | |
195 (t | |
196 (nnsoup-read-active-file) | |
197 (nnheader-report 'nnsoup "Opened server %s using directory %s" | |
198 server nnsoup-directory) | |
199 t))) | |
200 | |
201 (deffoo nnsoup-request-close () | |
202 (nnsoup-write-active-file) | |
203 (nnsoup-write-replies) | |
204 (gnus-soup-save-areas) | |
205 ;; Kill all nnsoup buffers. | |
206 (let (buffer) | |
207 (while nnsoup-buffers | |
208 (setq buffer (cdr (pop nnsoup-buffers))) | |
209 (and buffer | |
210 (buffer-name buffer) | |
211 (kill-buffer buffer)))) | |
212 (setq nnsoup-group-alist nil | |
213 nnsoup-group-alist-touched nil | |
214 nnsoup-current-group nil | |
215 nnsoup-replies-list nil) | |
216 (nnoo-close-server 'nnoo) | |
217 t) | |
218 | |
219 (deffoo nnsoup-request-article (id &optional newsgroup server buffer) | |
220 (nnsoup-possibly-change-group newsgroup) | |
221 (let (buf) | |
222 (save-excursion | |
223 (set-buffer (or buffer nntp-server-buffer)) | |
224 (erase-buffer) | |
225 (when (and (not (stringp id)) | |
226 (setq buf (nnsoup-narrow-to-article id))) | |
227 (insert-buffer-substring buf) | |
228 t)))) | |
229 | |
230 (deffoo nnsoup-request-group (group &optional server dont-check) | |
231 (nnsoup-possibly-change-group group) | |
232 (if dont-check | |
233 t | |
234 (let ((active (cadr (assoc group nnsoup-group-alist)))) | |
235 (if (not active) | |
236 (nnheader-report 'nnsoup "No such group: %s" group) | |
237 (nnheader-insert | |
238 "211 %d %d %d %s\n" | |
239 (max (1+ (- (cdr active) (car active))) 0) | |
240 (car active) (cdr active) group))))) | |
241 | |
242 (deffoo nnsoup-request-type (group &optional article) | |
243 (nnsoup-possibly-change-group group) | |
19969
5f1ab3dd344d
*** empty log message ***
Lars Magne Ingebrigtsen <larsi@gnus.org>
parents:
17493
diff
changeset
|
244 ;; Try to guess the type based on the first article in the group. |
17493 | 245 (when (not article) |
246 (setq article | |
247 (cdaar (cddr (assoc group nnsoup-group-alist))))) | |
248 (if (not article) | |
249 'unknown | |
250 (let ((kind (gnus-soup-encoding-kind | |
251 (gnus-soup-area-encoding | |
252 (nth 1 (nnsoup-article-to-area | |
253 article nnsoup-current-group)))))) | |
254 (cond ((= kind ?m) 'mail) | |
255 ((= kind ?n) 'news) | |
256 (t 'unknown))))) | |
257 | |
258 (deffoo nnsoup-close-group (group &optional server) | |
259 ;; Kill all nnsoup buffers. | |
260 (let ((buffers nnsoup-buffers) | |
261 elem) | |
262 (while buffers | |
263 (when (equal (car (setq elem (pop buffers))) group) | |
264 (setq nnsoup-buffers (delq elem nnsoup-buffers)) | |
265 (and (cdr elem) (buffer-name (cdr elem)) | |
266 (kill-buffer (cdr elem)))))) | |
267 t) | |
268 | |
269 (deffoo nnsoup-request-list (&optional server) | |
270 (save-excursion | |
271 (set-buffer nntp-server-buffer) | |
272 (erase-buffer) | |
273 (unless nnsoup-group-alist | |
274 (nnsoup-read-active-file)) | |
275 (let ((alist nnsoup-group-alist) | |
276 (standard-output (current-buffer)) | |
277 entry) | |
278 (while (setq entry (pop alist)) | |
279 (insert (car entry) " ") | |
280 (princ (cdadr entry)) | |
281 (insert " ") | |
282 (princ (caadr entry)) | |
283 (insert " y\n")) | |
284 t))) | |
285 | |
286 (deffoo nnsoup-request-scan (group &optional server) | |
287 (nnsoup-unpack-packets)) | |
288 | |
289 (deffoo nnsoup-request-newgroups (date &optional server) | |
290 (nnsoup-request-list)) | |
291 | |
292 (deffoo nnsoup-request-list-newsgroups (&optional server) | |
293 nil) | |
294 | |
295 (deffoo nnsoup-request-post (&optional server) | |
296 (nnsoup-store-reply "news") | |
297 t) | |
298 | |
299 (deffoo nnsoup-request-mail (&optional server) | |
300 (nnsoup-store-reply "mail") | |
301 t) | |
302 | |
303 (deffoo nnsoup-request-expire-articles (articles group &optional server force) | |
304 (nnsoup-possibly-change-group group) | |
305 (let* ((total-infolist (assoc group nnsoup-group-alist)) | |
306 (active (cadr total-infolist)) | |
307 (infolist (cddr total-infolist)) | |
308 info range-list mod-time prefix) | |
309 (while infolist | |
310 (setq info (pop infolist) | |
311 range-list (gnus-uncompress-range (car info)) | |
312 prefix (gnus-soup-area-prefix (nth 1 info))) | |
313 (when ;; All the articles in this file are marked for expiry. | |
314 (and (or (setq mod-time (nth 5 (file-attributes | |
315 (nnsoup-file prefix)))) | |
316 (setq mod-time (nth 5 (file-attributes | |
317 (nnsoup-file prefix t))))) | |
318 (gnus-sublist-p articles range-list) | |
319 ;; This file is old enough. | |
320 (nnmail-expired-article-p group mod-time force)) | |
321 ;; Ok, we delete this file. | |
322 (when (ignore-errors | |
323 (nnheader-message | |
324 5 "Deleting %s in group %s..." (nnsoup-file prefix) | |
325 group) | |
326 (when (file-exists-p (nnsoup-file prefix)) | |
327 (delete-file (nnsoup-file prefix))) | |
328 (nnheader-message | |
329 5 "Deleting %s in group %s..." (nnsoup-file prefix t) | |
330 group) | |
331 (when (file-exists-p (nnsoup-file prefix t)) | |
332 (delete-file (nnsoup-file prefix t))) | |
333 t) | |
334 (setcdr (cdr total-infolist) (delq info (cddr total-infolist))) | |
335 (setq articles (gnus-sorted-complement articles range-list)))) | |
336 (when (not mod-time) | |
337 (setcdr (cdr total-infolist) (delq info (cddr total-infolist))))) | |
338 (if (cddr total-infolist) | |
339 (setcar active (caaadr (cdr total-infolist))) | |
340 (setcar active (1+ (cdr active)))) | |
341 (nnsoup-write-active-file t) | |
342 ;; Return the articles that weren't expired. | |
343 articles)) | |
344 | |
345 | |
346 ;;; Internal functions | |
347 | |
348 (defun nnsoup-possibly-change-group (group &optional force) | |
349 (when (and group | |
350 (not (equal nnsoup-current-group group))) | |
351 (setq nnsoup-article-alist nil) | |
352 (setq nnsoup-current-group group)) | |
353 t) | |
354 | |
355 (defun nnsoup-read-active-file () | |
356 (setq nnsoup-group-alist nil) | |
357 (when (file-exists-p nnsoup-active-file) | |
358 (ignore-errors | |
359 (load nnsoup-active-file t t t)) | |
360 ;; Be backwards compatible. | |
361 (when (and nnsoup-group-alist | |
362 (not (atom (caadar nnsoup-group-alist)))) | |
363 (let ((alist nnsoup-group-alist) | |
364 entry e min max) | |
365 (while (setq e (cdr (setq entry (pop alist)))) | |
366 (setq min (caaar e)) | |
367 (while (cdr e) | |
368 (setq e (cdr e))) | |
369 (setq max (cdaar e)) | |
370 (setcdr entry (cons (cons min max) (cdr entry))))) | |
371 (setq nnsoup-group-alist-touched t)) | |
372 nnsoup-group-alist)) | |
373 | |
374 (defun nnsoup-write-active-file (&optional force) | |
375 (when (and nnsoup-group-alist | |
376 (or force | |
377 nnsoup-group-alist-touched)) | |
378 (setq nnsoup-group-alist-touched nil) | |
379 (nnheader-temp-write nnsoup-active-file | |
380 (gnus-prin1 `(setq nnsoup-group-alist ',nnsoup-group-alist)) | |
381 (insert "\n") | |
382 (gnus-prin1 `(setq nnsoup-current-prefix ,nnsoup-current-prefix)) | |
383 (insert "\n")))) | |
384 | |
385 (defun nnsoup-next-prefix () | |
386 "Return the next free prefix." | |
387 (let (prefix) | |
388 (while (or (file-exists-p | |
389 (nnsoup-file (setq prefix (int-to-string | |
390 nnsoup-current-prefix)))) | |
391 (file-exists-p (nnsoup-file prefix t))) | |
392 (incf nnsoup-current-prefix)) | |
393 (incf nnsoup-current-prefix) | |
394 prefix)) | |
395 | |
396 (defun nnsoup-file-name (dir file) | |
397 "Return the full path of FILE (in any case) in DIR." | |
398 (let* ((case-fold-search t) | |
399 (files (directory-files dir t)) | |
400 (regexp (concat (regexp-quote file) "$"))) | |
401 (car (delq nil | |
402 (mapcar | |
403 (lambda (file) | |
404 (if (string-match regexp file) | |
405 file | |
406 nil)) | |
407 files))))) | |
408 | |
409 (defun nnsoup-read-areas () | |
410 (let ((areas-file (nnsoup-file-name nnsoup-tmp-directory "areas"))) | |
411 (when areas-file | |
412 (save-excursion | |
413 (set-buffer nntp-server-buffer) | |
414 (let ((areas (gnus-soup-parse-areas areas-file)) | |
415 entry number area lnum cur-prefix file) | |
416 ;; Go through all areas in the new AREAS file. | |
417 (while (setq area (pop areas)) | |
418 ;; Change the name to the permanent name and move the files. | |
419 (setq cur-prefix (nnsoup-next-prefix)) | |
24357
15fc6acbae7a
Upgrading to Gnus 5.7; see ChangeLog
Lars Magne Ingebrigtsen <larsi@gnus.org>
parents:
19969
diff
changeset
|
420 (nnheader-message 5 "Incorporating file %s..." cur-prefix) |
17493 | 421 (when (file-exists-p |
422 (setq file (concat nnsoup-tmp-directory | |
423 (gnus-soup-area-prefix area) ".IDX"))) | |
424 (rename-file file (nnsoup-file cur-prefix))) | |
425 (when (file-exists-p | |
426 (setq file (concat nnsoup-tmp-directory | |
427 (gnus-soup-area-prefix area) ".MSG"))) | |
428 (rename-file file (nnsoup-file cur-prefix t)) | |
429 (gnus-soup-set-area-prefix area cur-prefix) | |
430 ;; Find the number of new articles in this area. | |
431 (setq number (nnsoup-number-of-articles area)) | |
432 (if (not (setq entry (assoc (gnus-soup-area-name area) | |
433 nnsoup-group-alist))) | |
434 ;; If this is a new area (group), we just add this info to | |
435 ;; the group alist. | |
436 (push (list (gnus-soup-area-name area) | |
437 (cons 1 number) | |
438 (list (cons 1 number) area)) | |
439 nnsoup-group-alist) | |
440 ;; There are already articles in this group, so we add this | |
441 ;; info to the end of the entry. | |
442 (nconc entry (list (list (cons (1+ (setq lnum (cdadr entry))) | |
443 (+ lnum number)) | |
444 area))) | |
445 (setcdr (cadr entry) (+ lnum number)))))) | |
446 (nnsoup-write-active-file t) | |
447 (delete-file areas-file))))) | |
448 | |
449 (defun nnsoup-number-of-articles (area) | |
450 (save-excursion | |
451 (cond | |
452 ;; If the number is in the area info, we just return it. | |
453 ((gnus-soup-area-number area) | |
454 (gnus-soup-area-number area)) | |
455 ;; If there is an index file, we just count the lines. | |
456 ((/= (gnus-soup-encoding-index (gnus-soup-area-encoding area)) ?n) | |
457 (set-buffer (nnsoup-index-buffer (gnus-soup-area-prefix area))) | |
458 (count-lines (point-min) (point-max))) | |
459 ;; We do it the hard way - re-searching through the message | |
460 ;; buffer. | |
461 (t | |
462 (set-buffer (nnsoup-message-buffer (gnus-soup-area-prefix area))) | |
463 (unless (assoc (gnus-soup-area-prefix area) nnsoup-article-alist) | |
464 (nnsoup-dissect-buffer area)) | |
465 (length (cdr (assoc (gnus-soup-area-prefix area) | |
466 nnsoup-article-alist))))))) | |
467 | |
468 (defun nnsoup-dissect-buffer (area) | |
469 (let ((mbox-delim (concat "^" message-unix-mail-delimiter)) | |
470 (format (gnus-soup-encoding-format (gnus-soup-area-encoding area))) | |
471 (i 0) | |
472 alist len) | |
473 (goto-char (point-min)) | |
474 (cond | |
475 ;; rnews batch format | |
476 ((= format ?n) | |
477 (while (looking-at "^#! *rnews \\(+[0-9]+\\) *$") | |
478 (forward-line 1) | |
479 (push (list | |
480 (incf i) (point) | |
481 (progn | |
482 (forward-char (string-to-number (match-string 1))) | |
483 (point))) | |
484 alist))) | |
485 ;; Unix mbox format | |
486 ((= format ?m) | |
487 (while (looking-at mbox-delim) | |
488 (forward-line 1) | |
489 (push (list | |
490 (incf i) (point) | |
491 (progn | |
492 (if (re-search-forward mbox-delim nil t) | |
493 (beginning-of-line) | |
494 (goto-char (point-max))) | |
495 (point))) | |
496 alist))) | |
497 ;; MMDF format | |
498 ((= format ?M) | |
499 (while (looking-at "\^A\^A\^A\^A\n") | |
500 (forward-line 1) | |
501 (push (list | |
502 (incf i) (point) | |
503 (progn | |
504 (if (search-forward "\n\^A\^A\^A\^A\n" nil t) | |
505 (beginning-of-line) | |
506 (goto-char (point-max))) | |
507 (point))) | |
508 alist))) | |
509 ;; Binary format | |
510 ((or (= format ?B) (= format ?b)) | |
511 (while (not (eobp)) | |
512 (setq len (+ (* (char-after (point)) (expt 2.0 24)) | |
513 (* (char-after (+ (point) 1)) (expt 2 16)) | |
514 (* (char-after (+ (point) 2)) (expt 2 8)) | |
515 (char-after (+ (point) 3)))) | |
516 (push (list | |
517 (incf i) (+ (point) 4) | |
518 (progn | |
519 (forward-char (floor (+ len 4))) | |
520 (point))) | |
521 alist))) | |
522 (t | |
523 (error "Unknown format: %c" format))) | |
524 (push (cons (gnus-soup-area-prefix area) alist) nnsoup-article-alist))) | |
525 | |
526 (defun nnsoup-index-buffer (prefix &optional message) | |
527 (let* ((file (concat prefix (if message ".MSG" ".IDX"))) | |
528 (buffer-name (concat " *nnsoup " file "*"))) | |
529 (or (get-buffer buffer-name) ; File already loaded. | |
530 (when (file-exists-p (concat nnsoup-directory file)) | |
531 (save-excursion ; Load the file. | |
532 (set-buffer (get-buffer-create buffer-name)) | |
533 (buffer-disable-undo (current-buffer)) | |
534 (push (cons nnsoup-current-group (current-buffer)) nnsoup-buffers) | |
535 (nnheader-insert-file-contents (concat nnsoup-directory file)) | |
536 (current-buffer)))))) | |
537 | |
538 (defun nnsoup-file (prefix &optional message) | |
539 (expand-file-name | |
540 (concat nnsoup-directory prefix (if message ".MSG" ".IDX")))) | |
541 | |
542 (defun nnsoup-message-buffer (prefix) | |
543 (nnsoup-index-buffer prefix 'msg)) | |
544 | |
545 (defun nnsoup-unpack-packets () | |
546 "Unpack all packets in `nnsoup-packet-directory'." | |
547 (let ((packets (directory-files | |
548 nnsoup-packet-directory t nnsoup-packet-regexp)) | |
549 packet) | |
550 (while (setq packet (pop packets)) | |
24357
15fc6acbae7a
Upgrading to Gnus 5.7; see ChangeLog
Lars Magne Ingebrigtsen <larsi@gnus.org>
parents:
19969
diff
changeset
|
551 (nnheader-message 5 "nnsoup: unpacking %s..." packet) |
17493 | 552 (if (not (gnus-soup-unpack-packet |
553 nnsoup-tmp-directory nnsoup-unpacker packet)) | |
24357
15fc6acbae7a
Upgrading to Gnus 5.7; see ChangeLog
Lars Magne Ingebrigtsen <larsi@gnus.org>
parents:
19969
diff
changeset
|
554 (nnheader-message 5 "Couldn't unpack %s" packet) |
17493 | 555 (delete-file packet) |
556 (nnsoup-read-areas) | |
24357
15fc6acbae7a
Upgrading to Gnus 5.7; see ChangeLog
Lars Magne Ingebrigtsen <larsi@gnus.org>
parents:
19969
diff
changeset
|
557 (nnheader-message 5 "Unpacking...done"))))) |
17493 | 558 |
559 (defun nnsoup-narrow-to-article (article &optional area head) | |
560 (let* ((area (or area (nnsoup-article-to-area article nnsoup-current-group))) | |
561 (prefix (and area (gnus-soup-area-prefix (nth 1 area)))) | |
562 (msg-buf (and prefix (nnsoup-index-buffer prefix 'msg))) | |
563 beg end) | |
564 (when area | |
565 (save-excursion | |
566 (cond | |
567 ;; There is no MSG file. | |
568 ((null msg-buf) | |
569 nil) | |
570 ;; We use the index file to find out where the article | |
571 ;; begins and ends. | |
572 ((and (= (gnus-soup-encoding-index | |
573 (gnus-soup-area-encoding (nth 1 area))) | |
574 ?c) | |
575 (file-exists-p (nnsoup-file prefix))) | |
576 (set-buffer (nnsoup-index-buffer prefix)) | |
577 (widen) | |
578 (goto-char (point-min)) | |
579 (forward-line (- article (caar area))) | |
580 (setq beg (read (current-buffer))) | |
581 (forward-line 1) | |
582 (if (looking-at "[0-9]+") | |
583 (progn | |
584 (setq end (read (current-buffer))) | |
585 (set-buffer msg-buf) | |
586 (widen) | |
587 (let ((format (gnus-soup-encoding-format | |
588 (gnus-soup-area-encoding (nth 1 area))))) | |
589 (goto-char end) | |
590 (when (or (= format ?n) (= format ?m)) | |
591 (setq end (progn (forward-line -1) (point)))))) | |
592 (set-buffer msg-buf)) | |
593 (widen) | |
594 (narrow-to-region beg (or end (point-max)))) | |
595 (t | |
596 (set-buffer msg-buf) | |
597 (widen) | |
598 (unless (assoc (gnus-soup-area-prefix (nth 1 area)) | |
599 nnsoup-article-alist) | |
600 (nnsoup-dissect-buffer (nth 1 area))) | |
601 (let ((entry (assq article (cdr (assoc (gnus-soup-area-prefix | |
602 (nth 1 area)) | |
603 nnsoup-article-alist))))) | |
604 (when entry | |
605 (narrow-to-region (cadr entry) (caddr entry)))))) | |
606 (goto-char (point-min)) | |
607 (if (not head) | |
608 () | |
609 (narrow-to-region | |
610 (point-min) | |
611 (if (search-forward "\n\n" nil t) | |
612 (1- (point)) | |
613 (point-max)))) | |
614 msg-buf)))) | |
615 | |
616 ;;;###autoload | |
617 (defun nnsoup-pack-replies () | |
618 "Make an outbound package of SOUP replies." | |
619 (interactive) | |
620 (unless (file-exists-p nnsoup-replies-directory) | |
24357
15fc6acbae7a
Upgrading to Gnus 5.7; see ChangeLog
Lars Magne Ingebrigtsen <larsi@gnus.org>
parents:
19969
diff
changeset
|
621 (nnheader-message 5 "No such directory: %s" nnsoup-replies-directory)) |
17493 | 622 ;; Write all data buffers. |
623 (gnus-soup-save-areas) | |
624 ;; Write the active file. | |
625 (nnsoup-write-active-file) | |
626 ;; Write the REPLIES file. | |
627 (nnsoup-write-replies) | |
628 ;; Check whether there is anything here. | |
629 (when (null (directory-files nnsoup-replies-directory nil "\\.MSG$")) | |
19969
5f1ab3dd344d
*** empty log message ***
Lars Magne Ingebrigtsen <larsi@gnus.org>
parents:
17493
diff
changeset
|
630 (error "No files to pack")) |
17493 | 631 ;; Pack all these files into a SOUP packet. |
632 (gnus-soup-pack nnsoup-replies-directory nnsoup-packer)) | |
633 | |
634 (defun nnsoup-write-replies () | |
635 "Write the REPLIES file." | |
636 (when nnsoup-replies-list | |
637 (gnus-soup-write-replies nnsoup-replies-directory nnsoup-replies-list) | |
638 (setq nnsoup-replies-list nil))) | |
639 | |
640 (defun nnsoup-article-to-area (article group) | |
641 "Return the area that ARTICLE in GROUP is located in." | |
642 (let ((areas (cddr (assoc group nnsoup-group-alist)))) | |
643 (while (and areas (< (cdaar areas) article)) | |
644 (setq areas (cdr areas))) | |
645 (and areas (car areas)))) | |
646 | |
647 (defvar nnsoup-old-functions | |
648 (list message-send-mail-function message-send-news-function)) | |
649 | |
650 ;;;###autoload | |
651 (defun nnsoup-set-variables () | |
652 "Use the SOUP methods for posting news and mailing mail." | |
653 (interactive) | |
654 (setq message-send-news-function 'nnsoup-request-post) | |
655 (setq message-send-mail-function 'nnsoup-request-mail)) | |
656 | |
657 ;;;###autoload | |
658 (defun nnsoup-revert-variables () | |
659 "Revert posting and mailing methods to the standard Emacs methods." | |
660 (interactive) | |
661 (setq message-send-mail-function (car nnsoup-old-functions)) | |
662 (setq message-send-news-function (cadr nnsoup-old-functions))) | |
663 | |
664 (defun nnsoup-store-reply (kind) | |
665 ;; Mostly stolen from `message.el'. | |
666 (require 'mail-utils) | |
667 (let ((tembuf (generate-new-buffer " message temp")) | |
668 (case-fold-search nil) | |
24357
15fc6acbae7a
Upgrading to Gnus 5.7; see ChangeLog
Lars Magne Ingebrigtsen <larsi@gnus.org>
parents:
19969
diff
changeset
|
669 (real-header-separator mail-header-separator) |
15fc6acbae7a
Upgrading to Gnus 5.7; see ChangeLog
Lars Magne Ingebrigtsen <larsi@gnus.org>
parents:
19969
diff
changeset
|
670 (mail-header-separator "") |
17493 | 671 delimline |
672 (mailbuf (current-buffer))) | |
673 (unwind-protect | |
674 (save-excursion | |
675 (save-restriction | |
676 (message-narrow-to-headers) | |
677 (if (equal kind "mail") | |
678 (message-generate-headers message-required-mail-headers) | |
679 (message-generate-headers message-required-news-headers))) | |
680 (set-buffer tembuf) | |
681 (erase-buffer) | |
682 (insert-buffer-substring mailbuf) | |
683 ;; Remove some headers. | |
684 (save-restriction | |
685 (message-narrow-to-headers) | |
686 ;; Remove some headers. | |
687 (message-remove-header message-ignored-mail-headers t)) | |
688 (goto-char (point-max)) | |
689 ;; require one newline at the end. | |
690 (or (= (preceding-char) ?\n) | |
691 (insert ?\n)) | |
692 (let ((case-fold-search t)) | |
693 ;; Change header-delimiter to be what sendmail expects. | |
694 (goto-char (point-min)) | |
695 (re-search-forward | |
24357
15fc6acbae7a
Upgrading to Gnus 5.7; see ChangeLog
Lars Magne Ingebrigtsen <larsi@gnus.org>
parents:
19969
diff
changeset
|
696 (concat "^" (regexp-quote real-header-separator) "\n")) |
17493 | 697 (replace-match "\n") |
698 (backward-char 1) | |
699 (setq delimline (point-marker)) | |
700 ;; Insert an extra newline if we need it to work around | |
701 ;; Sun's bug that swallows newlines. | |
702 (goto-char (1+ delimline)) | |
703 (when (eval message-mailer-swallows-blank-line) | |
704 (newline)) | |
705 (let ((msg-buf | |
706 (gnus-soup-store | |
707 nnsoup-replies-directory | |
708 (nnsoup-kind-to-prefix kind) nil nnsoup-replies-format-type | |
709 nnsoup-replies-index-type)) | |
710 (num 0)) | |
711 (when (and msg-buf (bufferp msg-buf)) | |
712 (save-excursion | |
713 (set-buffer msg-buf) | |
714 (goto-char (point-min)) | |
715 (while (re-search-forward "^#! *rnews" nil t) | |
24357
15fc6acbae7a
Upgrading to Gnus 5.7; see ChangeLog
Lars Magne Ingebrigtsen <larsi@gnus.org>
parents:
19969
diff
changeset
|
716 (incf num)) |
15fc6acbae7a
Upgrading to Gnus 5.7; see ChangeLog
Lars Magne Ingebrigtsen <larsi@gnus.org>
parents:
19969
diff
changeset
|
717 (when nnsoup-always-save |
15fc6acbae7a
Upgrading to Gnus 5.7; see ChangeLog
Lars Magne Ingebrigtsen <larsi@gnus.org>
parents:
19969
diff
changeset
|
718 (save-buffer))) |
15fc6acbae7a
Upgrading to Gnus 5.7; see ChangeLog
Lars Magne Ingebrigtsen <larsi@gnus.org>
parents:
19969
diff
changeset
|
719 (nnheader-message 5 "Stored %d messages" num))) |
17493 | 720 (nnsoup-write-replies) |
721 (kill-buffer tembuf)))))) | |
722 | |
723 (defun nnsoup-kind-to-prefix (kind) | |
724 (unless nnsoup-replies-list | |
725 (setq nnsoup-replies-list | |
726 (gnus-soup-parse-replies | |
727 (concat nnsoup-replies-directory "REPLIES")))) | |
728 (let ((replies nnsoup-replies-list)) | |
729 (while (and replies | |
730 (not (string= kind (gnus-soup-reply-kind (car replies))))) | |
731 (setq replies (cdr replies))) | |
732 (if replies | |
733 (gnus-soup-reply-prefix (car replies)) | |
734 (push (vector (gnus-soup-unique-prefix nnsoup-replies-directory) | |
735 kind | |
736 (format "%c%c%c" | |
737 nnsoup-replies-format-type | |
738 nnsoup-replies-index-type | |
739 (if (string= kind "news") | |
740 ?n ?m))) | |
741 nnsoup-replies-list) | |
742 (gnus-soup-reply-prefix (car nnsoup-replies-list))))) | |
743 | |
744 (defun nnsoup-make-active () | |
745 "(Re-)create the SOUP active file." | |
746 (interactive) | |
747 (let ((files (sort (directory-files nnsoup-directory t "IDX$") | |
748 (lambda (f1 f2) | |
749 (< (progn (string-match "/\\([0-9]+\\)\\." f1) | |
750 (string-to-int (match-string 1 f1))) | |
751 (progn (string-match "/\\([0-9]+\\)\\." f2) | |
752 (string-to-int (match-string 1 f2))))))) | |
753 active group lines ident elem min) | |
754 (set-buffer (get-buffer-create " *nnsoup work*")) | |
755 (buffer-disable-undo (current-buffer)) | |
756 (while files | |
24357
15fc6acbae7a
Upgrading to Gnus 5.7; see ChangeLog
Lars Magne Ingebrigtsen <larsi@gnus.org>
parents:
19969
diff
changeset
|
757 (nnheader-message 5 "Doing %s..." (car files)) |
17493 | 758 (erase-buffer) |
759 (nnheader-insert-file-contents (car files)) | |
760 (goto-char (point-min)) | |
761 (if (not (re-search-forward "^[^\t]*\t[^\t]*\t[^\t]*\t[^\t]*\t[^\t]*\t[^\t]*\t[^\t]*\t[^\t]*\t *\\(Xref: \\)? *[^ ]* \\([^ ]+\\):[0-9]" nil t)) | |
762 (setq group "unknown") | |
763 (setq group (match-string 2))) | |
764 (setq lines (count-lines (point-min) (point-max))) | |
765 (setq ident (progn (string-match | |
766 "/\\([0-9]+\\)\\." (car files)) | |
767 (substring | |
768 (car files) (match-beginning 1) | |
769 (match-end 1)))) | |
770 (if (not (setq elem (assoc group active))) | |
771 (push (list group (cons 1 lines) | |
772 (list (cons 1 lines) | |
773 (vector ident group "ncm" "" lines))) | |
774 active) | |
775 (nconc elem | |
776 (list | |
777 (list (cons (1+ (setq min (cdadr elem))) | |
778 (+ min lines)) | |
779 (vector ident group "ncm" "" lines)))) | |
780 (setcdr (cadr elem) (+ min lines))) | |
781 (setq files (cdr files))) | |
24357
15fc6acbae7a
Upgrading to Gnus 5.7; see ChangeLog
Lars Magne Ingebrigtsen <larsi@gnus.org>
parents:
19969
diff
changeset
|
782 (nnheader-message 5 "") |
17493 | 783 (setq nnsoup-group-alist active) |
784 (nnsoup-write-active-file t))) | |
785 | |
786 (defun nnsoup-delete-unreferenced-message-files () | |
787 "Delete any *.MSG and *.IDX files that aren't known by nnsoup." | |
788 (interactive) | |
789 (let* ((known (apply 'nconc (mapcar | |
790 (lambda (ga) | |
791 (mapcar | |
792 (lambda (area) | |
793 (gnus-soup-area-prefix (cadr area))) | |
794 (cddr ga))) | |
795 nnsoup-group-alist))) | |
796 (regexp "\\.MSG$\\|\\.IDX$") | |
797 (files (directory-files nnsoup-directory nil regexp)) | |
798 non-files file) | |
799 ;; Find all files that aren't known by nnsoup. | |
800 (while (setq file (pop files)) | |
801 (string-match regexp file) | |
802 (unless (member (substring file 0 (match-beginning 0)) known) | |
803 (push file non-files))) | |
804 ;; Sort and delete the files. | |
805 (setq non-files (sort non-files 'string<)) | |
806 (map-y-or-n-p "Delete file %s? " | |
807 (lambda (file) (delete-file (concat nnsoup-directory file))) | |
808 non-files))) | |
809 | |
810 (provide 'nnsoup) | |
811 | |
812 ;;; nnsoup.el ends here |