(report-emacs-bug): Insert at separator, not at end.
[emacs.git] / lisp / gnus-uu.el
blobe4006a456756de48da36056c9a7d05e888703f18
1 ;;; gnus-uu.el --- extract, view or save (uu)encoded files from gnus
3 ;; Copyright (C) 1985, 1986, 1987, 1993, 1994 Free Software Foundation, Inc.
5 ;; Author: Lars Ingebrigtsen <larsi@ifi.uio.no>
6 ;; Created: 2 Oct 1993
7 ;; Version: v2.5.2
8 ;; Last Modified: 1994/04/13
9 ;; Keyword: news
11 ;; This file is part of GNU Emacs.
13 ;; GNU Emacs is free software; you can redistribute it and/or modify
14 ;; it under the terms of the GNU General Public License as published by
15 ;; the Free Software Foundation; either version 2, or (at your option)
16 ;; any later version.
18 ;; GNU Emacs is distributed in the hope that it will be useful,
19 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 ;; GNU General Public License for more details.
23 ;; You should have received a copy of the GNU General Public License
24 ;; along with GNU Emacs; see the file COPYING. If not, write to
25 ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
27 ;;; Commentary:
29 ;; All gnus-uu commands start with `C-c C-v'.
31 ;; Typing `C-c C-v C-v' (`gnus-uu-decode-and-view') in the summary
32 ;; buffer will try to find all articles in the same series, uudecode
33 ;; them and view the resulting file(s).
35 ;; gnus-uu guesses what articles are in the series according to the
36 ;; following simple rule: The subjects must be identical, except for
37 ;; the last two numbers of the line.
39 ;; For example: If you choose a subject called "cat.gif (2/3)" gnus-uu
40 ;; will find all the articles that matches "^cat.gif
41 ;; ([0-9]+/[0-9]+).*$". Subjects that are nonstandard, like "cat.gif
42 ;; (2/3) Part 6 of a series", will not be properly recognized by 'C-c
43 ;; C-v C-v', and you have to mark the articles manually with '#'.
45 ;; Typing `C-c C-v v' (`gnus-uu-decode-and-save') will do the same as
46 ;; `C-c C-v C-v', except that it will not display the resulting file,
47 ;; but save it instead.
49 ;; Typing `C-c C-v s' (`gnus-uu-shar-and-save') does the same as `C-c
50 ;; C-v v', and `C-c C-v C-s' (`gnus-uu-shar-and-view') does the same
51 ;; as `C-c C-v C-v', except that they unshar files instead, i. e. run
52 ;; them through /bin/sh. Most shar files can be viewed and/or saved
53 ;; with the normal uudecode commands, which is much safer, as no
54 ;; foreign code is run.
56 ;; `#' (`gnus-uu-mark-article') marks an article for later
57 ;; decoding/unsharing/saving/viewing. The files will be decoded in the
58 ;; sequence they were marked. To decode the files after you've marked
59 ;; the articles you are interested in, type the corresponding key
60 ;; strokes as the normal decoding commands, but put a `M-' in the last
61 ;; keystroke. For instance, to perform a standard uudecode and view,
62 ;; you would type `C-c C-v C-v'. To perform a marked uudecode and
63 ;; view, say `C-v C-v M-C-v'. All the other view and save commands are
64 ;; handled the same way; marked uudecode and save is then `C-c C-v
65 ;; M-v'.
67 ;; `M-#' (`gnus-uu-unmark-article') will remove the mark from a
68 ;; previosly marked article.
70 ;; `C-c C-v C-u' (`gnus-uu-unmark-all-articles') will remove the mark from
71 ;; all marked articles.
73 ;; `C-c C-v C-r' (`gnus-uu-mark-by-regexp') will prompt for a regular
74 ;; expression and mark (forward) all articles matching that regular
75 ;; expression.
77 ;; There's an additional way to reach the decoding functions to make
78 ;; future expansions easier: `C-c C-v C-m'
79 ;; (`gnus-uu-multi-decode-and-view') and the corresponding save, marked
80 ;; view and marked save keystrokes, `C-c C-v m', `C-c C-v M-C-m' and
81 ;; `C-c C-v M-m' respectively. You will be prompted for decoding
82 ;; method, like uudecode, shar, binhex or plain save. Note that
83 ;; methods like binhex and save doesn't have view modes; even if you
84 ;; issue a view command (`C-c C-v C-m' and "binhex"), gnus-uu will
85 ;; just save the resulting binhex file.
87 ;; `C-c C-v C-b' (`gnus-uu-decode-and-show-in-buffer') will decode the
88 ;; current article and display the results in an emacs buffer. This
89 ;; might be useful if there's jsut some text in the current article
90 ;; that has been uuencoded by some perverse poster.
92 ;; `C-c C-v a' (`gnus-uu-decode-and-save-all-articles') looks at all the
93 ;; articles in the current newsgroup and tries to uudecode everything
94 ;; it can find. The user will be prompted for a directory where the
95 ;; resulting files (if any) will be stored. `C-c C-v M-a' only looks
96 ;; at unread article. `C-c C-v w' does the same as `C-c C-v a', but
97 ;; also marks as read all articles it has peeked through, even if they
98 ;; weren't uuencoded articles. `C-c C-v M-w' is, as you might have
99 ;; guessed, similar to `C-c C-v M-a'.
101 ;; `C-c C-v C-l' (`gnus-uu-edit-begin-line') lets you edit the begin
102 ;; line of the current buffer. Useful to change an incorrect suffix or
103 ;; an incorrect begin line.
106 ;; When using the view commands, `C-c C-v C-v' for instance, gnus-uu
107 ;; will (normally, see below) try to view the file according to the
108 ;; rules given in `gnus-uu-default-view-rules' and
109 ;; `gnus-uu-user-view-rules'. If it recognises the file, it will
110 ;; display it immediately. If the file is some sort of archive,
111 ;; gnus-uu will attempt to unpack the archive and see if any of the
112 ;; files in the archive can be viewed. For instance, if you have a
113 ;; gzipped tar file "pics.tar.gz" containing the files "pic1.jpg" and
114 ;; "pic2.gif", gnus-uu will uncompress and detar the main file, and
115 ;; then view the two pictures. This unpacking process is recursive, so
116 ;; if the archive contains archives of archives, it'll all be
117 ;; unpacked.
119 ;; If the view command doesn't recognise the file type, or can't view
120 ;; it because you don't have the viewer, or can't view *any* of the
121 ;; files in the archive, the user will be asked if she wishes to have
122 ;; the file saved somewhere. Note that if the decoded file is an
123 ;; archive, and gnus-uu manages to view some of the files in the
124 ;; archive, it won't tell the user that there were some files that
125 ;; were unviewable. See "Interactive view" for a different approach.
128 ;; Note that gnus-uu adds a function to `gnus-exit-group-hook' to
129 ;; clear the list of marked articles and check for any generated files
130 ;; that might have escaped deletion if the user typed `C-g'.
133 ;; `C-c C-v C-a' (`gnus-uu-toggle-asynchronous') toggles the
134 ;; `gnus-uu-asynchronous' variable. See below for explanation.
136 ;; `C-c C-v C-q' (`gnus-uu-toggle-query') toggles the
137 ;; `gnus-uu-ask-before-view' variable. See below for explanation.
139 ;; `C-c C-v C-p' (`gnus-uu-toggle-always-ask') toggles the
140 ;; `gnus-uu-view-and-save' variable. See below for explanation.
142 ;; `C-c C-v C-k' (`gnus-uu-toggle-kill-carriage-return') toggles the
143 ;; `gnus-uu-kill-carriage-return' variable. See below for explanation.
145 ;; `C-c C-v C-i' (`gnus-uu-toggle-interactive-view') toggles interactive
146 ;; mode. If it is turned on, gnus-uu won't view files immediately but
147 ;; give you a buffer with the default commands and files and lets you
148 ;; edit the commands and execute them at leisure.
150 ;; `C-c C-v C-t' (`gnus-uu-toggle-any-variable') is an interface to the
151 ;; five toggle commands listed above.
153 ;; `gnus-uu-toggle-correct-stripped-articles' toggles whether to check
154 ;; and correct uuencoded articles that may have had trailing spaces
155 ;; stripped by mailers.
158 ;; Customization
160 ;; To load this file when starting gnus, put sumething like the
161 ;; following in your .emacs file:
163 ;; (setq gnus-group-mode-hook
164 ;; '(lambda () (load "gnus-uu")))
166 ;; To make gnus-uu use, for instance, "xli" to view JPEGs and GIFs,
167 ;; put this in your .emacs file:
169 ;; (setq gnus-uu-user-view-rules
170 ;; (list
171 ;; '("jpg$\\|gif$" "xli")
172 ;; ))
174 ;; This variable is a list where each list item is a list containing
175 ;; two strings. The first string is a regular expression. If the file
176 ;; name is matched by this expression, the command given in the
177 ;; second string is executed on this file. If the command contains
178 ;; "%s", the file will be inserted there in the command string. Eg.
179 ;; "giftoppm %s | xv -" will result in the file name being inserted at
180 ;; the "%s".
182 ;; If you don't want to display certain file types, like if you
183 ;; haven't got sound capabilities, you could put something like
185 ;; (setq gnus-uu-user-view-rules
186 ;; (list
187 ;; '("au$\\|voc$\\|wav$" nil)
188 ;; ))
190 ;; in your .emacs file.
192 ;; There's a similar variable called `gnus-uu-user-archive-rules'
193 ;; which gives a list of unarcers to use when looking inside archives
194 ;; for files to display.
196 ;; If you don't want gnus-uu to look inside archives for files to
197 ;; display, say
199 ;; (setq gnus-uu-do-not-unpack-archives t)
202 ;; If you want gnus-uu to ask you if you want to save a file after
203 ;; viewing, say
205 ;; (setq gnus-uu-view-and-save t)
208 ;; If you don't want to wait for the viewing command to finish before
209 ;; returning to emacs, say
211 ;; (setq gnus-uu-asynchronous t)
214 ;; This can be useful if you're viewing long .mod files, for instance,
215 ;; which often takes several minutes. Note, however, that since
216 ;; gnus-uu doesn't ask, and if you are viewing an archive with lots of
217 ;; viewable files, you'll get them all up more or less at once, which
218 ;; can be confusing, to say the least. To get gnus-uu to ask you
219 ;; before viewing a file, say
221 ;; (setq gnus-uu-ask-before-view t)
223 ;; You can set this variable even if you're not using asynchronous
224 ;; viewing, of course.
226 ;; If the articles has been posted by some numbscull with a PC (isn't
227 ;; that a bit redundant, though?) and there's lots of carriage returns
228 ;; everywhere, say
230 ;; (setq gnus-uu-kill-carriage-return t)
232 ;; If you want gnus-uu to ignore the default file rules when viewing,
233 ;; for instance if there's several file types that you can't view, set
234 ;; `gnus-uu-ignore-default-view-rules' to t. There's a similar
235 ;; variable to disable the default unarchive rule list,
236 ;; `gnus-uu-ignore-default-archive-rules'.
238 ;; If you want a more interactive approach to file viewing, say
240 ;; (setq gnus-uu-use-interactive-view t)
242 ;; If this variable is set, whenever you type `C-c C-v C-v' (or any of
243 ;; the other view commands), gnus-uu will present you with a buffer
244 ;; with the default actions and file names after decoding. You can
245 ;; edit the command lines and execute them in a convenient fashion.
246 ;; The output from the commands will be displayed in a small window at
247 ;; the bottom of the emacs window. End interactive mode by typing `C-c
248 ;; C-c' in the view window.
250 ;; If you want gnus-uu to unmark articles that you have asked to
251 ;; decode, but can't be decoded (if, for instance, the articles aren't
252 ;; uuencoded files or the posting is incomplete), say
254 ;; (setq gnus-uu-unmark-articles-not-decoded t)
257 ;; History
259 ;; v1.0: First version released Oct 2 1992.
261 ;; v1.1: Changed `C-c C-r' to `C-c C-e' and `C-c C-p' to `C-c C-k'.
262 ;; Changed (setq gnus-exit-group-hook) to (add-hook). Removed
263 ;; checking for "Re:" for finding parts.
265 ;; v2.2: Fixed handling of currupted archives. Changed uudecoding to
266 ;; an asynchronous process to avoid loading tons of data into emacs
267 ;; buffers. No longer reads articles emacs already have aboard. Fixed
268 ;; a firmer support for shar files. Made regexp searches for files
269 ;; more convenient. Added `C-c C-l' for editing uucode begin
270 ;; lines. Added multi-system decoder entry point. Added interactive
271 ;; view mode. Added function for decoding and saving all uuencoded
272 ;; articles in the current newsgroup.
274 ;; v2.3: After suggestions I have changed all the gnus-uu key bindings
275 ;; to avoid hogging all the user keys (C-c LETTER). Also added
276 ;; (provide) and fixed some saving stuff. First posted version to
277 ;; gnu.emacs.sources.
279 ;; v2.4: Fixed some more in the save-all category. Automatic fixing of
280 ;; uucode "begin" lines: names on the form of "dir/file" are
281 ;; translated into "dir-file". Added a function for fixing stripped
282 ;; uucode articles. Added binhex save.
284 ;; v2.5: First version copyrighted by FSF. Changed lots of
285 ;; documentation strings.
287 ;; v2.5.1: Added uuencode/posting code to post binary files.
290 ;; Default keymap overview:
292 ;; All commands start with `C-c C-v'. The difference is in the third
293 ;; keystroke. All view commands are `C-LETTER'. All save commands are
294 ;; just `LETTER'. All marked commands are the same as the unmarked
295 ;; commands, except that they have `M-' before in the last keystroke.
297 ;; `C-c C-v C-v' gnus-uu-decode-and-view
298 ;; `C-c C-v v' gnus-uu-decode-and-save
299 ;; `C-c C-v C-s' gnus-uu-shar-and-view
300 ;; `C-c C-v s' gnus-uu-shar-and-save
301 ;; `C-c C-v C-m' gnus-uu-multi-decode-and-view
302 ;; `C-c C-v m' gnus-uu-multi-decode-and-save
304 ;; `C-c C-v C-b' gnus-uu-decode-and-show-in-buffer
305 ;; `C-c C-v C-l' gnus-uu-edit-begin-line
306 ;; `C-c C-v M-a' gnus-uu-decode-and-save-all-unread-articles
307 ;; `C-c C-v a' gnus-uu-decode-and-save-all-articles
308 ;; `C-c C-v M-w' gnus-uu-decode-and-save-all-unread-articles-and-mark
309 ;; `C-c C-v w' gnus-uu-decode-and-save-all-articles-and-mark
311 ;; `#' gnus-uu-mark-article
312 ;; `M-#' gnus-uu-unmark-article
313 ;; `C-c C-v C-u' gnus-uu-unmark-all-articles
314 ;; `C-c C-v C-r' gnus-uu-mark-by-regexp
315 ;; `C-c C-v M-C-v' gnus-uu-marked-decode-and-view
316 ;; `C-c C-v M-v' gnus-uu-marked-decode-and-save
317 ;; `C-c C-v M-C-s' gnus-uu-marked-shar-and-view
318 ;; `C-c C-v M-s' gnus-uu-marked-shar-and-save
319 ;; `C-c C-v M-C-m' gnus-uu-marked-multi-decode-and-view
320 ;; `C-c C-v M-m' gnus-uu-marked-multi-decode-and-save
322 ;; `C-c C-v C-a' gnus-uu-toggle-asynchronous
323 ;; `C-c C-v C-q' gnus-uu-toggle-query
324 ;; `C-c C-v C-p' gnus-uu-toggle-always-ask
325 ;; `C-c C-v C-k' gnus-uu-toggle-kill-carriage-return
326 ;; `C-c C-v C-i' gnus-uu-toggle-interactive-view
327 ;; `C-c C-v C-t' gnus-uu-toggle-any-variable
329 ;;; Code:
331 (require 'gnus)
332 (require 'gnuspost)
334 ;; Binding of keys to the gnus-uu functions.
336 (defvar gnus-uu-ctl-map nil)
337 (define-prefix-command 'gnus-uu-ctl-map)
338 (define-key gnus-summary-mode-map "\C-c\C-v" gnus-uu-ctl-map)
340 (define-key gnus-uu-ctl-map "\C-v" 'gnus-uu-decode-and-view)
341 (define-key gnus-uu-ctl-map "v" 'gnus-uu-decode-and-save)
342 (define-key gnus-uu-ctl-map "\C-s" 'gnus-uu-shar-and-view)
343 (define-key gnus-uu-ctl-map "s" 'gnus-uu-shar-and-save)
344 (define-key gnus-uu-ctl-map "\C-m" 'gnus-uu-multi-decode-and-view)
345 (define-key gnus-uu-ctl-map "m" 'gnus-uu-multi-decode-and-save)
347 (define-key gnus-uu-ctl-map "\C-b" 'gnus-uu-decode-and-show-in-buffer)
349 (define-key gnus-summary-mode-map "#" 'gnus-uu-mark-article)
350 (define-key gnus-summary-mode-map "\M-#" 'gnus-uu-unmark-article)
351 (define-key gnus-uu-ctl-map "\C-u" 'gnus-uu-unmark-all-articles)
352 (define-key gnus-uu-ctl-map "\C-r" 'gnus-uu-mark-by-regexp)
354 (define-key gnus-uu-ctl-map "\M-\C-v" 'gnus-uu-marked-decode-and-view)
355 (define-key gnus-uu-ctl-map "\M-v" 'gnus-uu-marked-decode-and-save)
356 (define-key gnus-uu-ctl-map "\M-\C-s" 'gnus-uu-marked-shar-and-view)
357 (define-key gnus-uu-ctl-map "\M-s" 'gnus-uu-marked-shar-and-save)
358 (define-key gnus-uu-ctl-map "\M-\C-m" 'gnus-uu-marked-multi-decode-and-view)
359 (define-key gnus-uu-ctl-map "\M-m" 'gnus-uu-marked-multi-decode-and-save)
361 (define-key gnus-uu-ctl-map "\C-a" 'gnus-uu-toggle-asynchronous)
362 (define-key gnus-uu-ctl-map "\C-q" 'gnus-uu-toggle-query)
363 (define-key gnus-uu-ctl-map "\C-p" 'gnus-uu-toggle-always-ask)
364 (define-key gnus-uu-ctl-map "\C-k" 'gnus-uu-toggle-kill-carriage-return)
365 (define-key gnus-uu-ctl-map "\C-i" 'gnus-uu-toggle-interactive-view)
366 (define-key gnus-uu-ctl-map "\C-t" 'gnus-uu-toggle-any-variable)
368 (define-key gnus-uu-ctl-map "\C-l" 'gnus-uu-edit-begin-line)
370 (define-key gnus-uu-ctl-map "\M-a" 'gnus-uu-decode-and-save-all-unread-articles)
371 (define-key gnus-uu-ctl-map "a" 'gnus-uu-decode-and-save-all-articles)
372 (define-key gnus-uu-ctl-map "\M-w" 'gnus-uu-decode-and-save-all-unread-articles-and-mark)
373 (define-key gnus-uu-ctl-map "w" 'gnus-uu-decode-and-save-all-articles-and-mark)
375 ;(load "rnewspost")
376 ;(define-key news-reply-mode-map "\C-c\C-v" 'gnus-uu-uuencode-and-post)
378 ;; Dummy function gnus-uu
380 (defun gnus-uu ()
381 "gnus-uu is a package for uudecoding and viewing articles.
383 By default, all gnus-uu keystrokes begin with `C-c C-v'.
385 There four decoding commands categories:
386 All commands for viewing are `C-c C-v C-LETTER'.
387 All commands for saving are `C-c C-v LETTER'.
388 All commands for marked viewing are `C-c C-v C-M-LETTER'.
389 All commands for marked saving are `C-c C-v M-LETTER'.
391 \\<gnus-summary-mode-map>\\[gnus-uu-decode-and-view]\tDecode and view articles
392 \\[gnus-uu-decode-and-save]\tDecode and save articles
393 \\[gnus-uu-shar-and-view]\tUnshar and view articles
394 \\[gnus-uu-shar-and-save]\tUnshar and save articles
395 \\[gnus-uu-multi-decode-and-view]\tChoose a decoding method, decode and view articles
396 \\[gnus-uu-multi-decode-and-save]\tChoose a decoding method, decode and save articles
398 \\[gnus-uu-decode-and-show-in-buffer]\tDecode the current article and view the result in a buffer
399 \\[gnus-uu-edit-begin-line]\tEdit the 'begin' line of an uuencoded article
401 \\[gnus-uu-decode-and-save-all-unread-articles]\tDecode and save all unread articles
402 \\[gnus-uu-decode-and-save-all-articles]\tDecode and save all articles
403 \\[gnus-uu-decode-and-save-all-unread-articles-and-mark]\tDecode and save all unread articles and catch up
404 \\[gnus-uu-decode-and-save-all-articles-and-mark]\tDecode and save all articles and catch up
406 \\[gnus-uu-mark-article]\tMark the current article for decoding
407 \\[gnus-uu-unmark-article]\tUnmark the current article
408 \\[gnus-uu-unmark-all-articles]\tUnmark all articles
409 \\[gnus-uu-mark-by-regexp]\tMark articles for decoding by regexp
410 \\[gnus-uu-marked-decode-and-view]\tDecode and view marked articles
411 \\[gnus-uu-marked-decode-and-save]\tDecode and save marked articles
412 \\[gnus-uu-marked-shar-and-view]\tUnshar and view marked articles
413 \\[gnus-uu-marked-shar-and-save]\tUnshar and save marked articles
414 \\[gnus-uu-marked-multi-decode-and-view]\tChoose decoding method, decode and view marked articles
415 \\[gnus-uu-marked-multi-decode-and-save]\tChoose decoding method, decode and save marked articles
417 \\[gnus-uu-toggle-asynchronous]\tToggle asynchronous viewing mode
418 \\[gnus-uu-toggle-query]\tToggle whether to ask before viewing a file
419 \\[gnus-uu-toggle-always-ask]\tToggle whether to ask to save a file after viewing
420 \\[gnus-uu-toggle-kill-carriage-return]\tToggle whether to strip trailing carriage returns
421 \\[gnus-uu-toggle-interactive-view]\tToggle whether to use interactive viewing mode
422 \\[gnus-uu-toggle-any-variable]\tToggle any of the things above
424 User configurable variables:
426 Rule Variables
428 gnus-uu uses \"rule\" variables to decide how to view a file. All
429 these variables are of the form
431 (list '(regexp1 command2)
432 '(regexp2 command2)
433 ...)
435 `gnus-uu-user-view-rules'
436 This variable is consulted first when viewing files. If you wish
437 to use, for instance, sox to convert an .au sound file, you could
438 say something like:
440 (setq gnus-uu-user-view-rules
441 (list '(\"\\\\.au$\" \"sox %s -t .aiff > /dev/audio\")))
443 `gnus-uu-user-view-rules-end'
444 This variable is consulted if gnus-uu couldn't make any matches
445 from the user and default view rules.
447 `gnus-uu-user-interactive-view-rules'
448 This is the variable used instead of `gnus-uu-user-view-rules'
449 when in interactive mode.
451 `gnus-uu-user-interactive-view-rules-end'
452 This variable is used instead of `gnus-uu-user-view-rules-end'
453 when in interactive mode.
455 `gnus-uu-user-archive-rules`
456 This variable can be used to say what comamnds should be used to
457 unpack archives.
460 Other Variables
462 `gnus-uu-tmp-dir'
463 Where gnus-uu does its work.
465 `gnus-uu-do-not-unpack-archives'
466 Non-nil means that gnus-uu won't peek inside archives looking for
467 files to dispay.
469 `gnus-uu-view-and-save'
470 Non-nil means that the user will always be asked to save a file
471 after viewing it.
473 `gnus-uu-asynchronous'
474 Non-nil means that files will be viewed asynchronously.
476 `gnus-uu-ask-before-view'
477 Non-nil means that gnus-uu will ask you before viewing each file
479 `gnus-uu-ignore-default-view-rules'
480 Non-nil means that gnus-uu will ignore the default viewing rules.
482 `gnus-uu-ignore-default-archive-rules'
483 Non-nil means that gnus-uu will ignore the default archive
484 unpacking commands.
486 `gnus-uu-kill-carriage-return'
487 Non-nil means that gnus-uu will strip all carriage returns from
488 articles.
490 `gnus-uu-unmark-articles-not-decoded'
491 Non-nil means that gnus-uu will mark articles that were
492 unsuccessfully decoded as unread.
494 `gnus-uu-output-window-height'
495 This variable says how tall the output buffer window is to be
496 when using interactive view mode.
498 `gnus-uu-correct-stripped-uucode'
499 Non-nil means that gnus-uu will *try* to fix uuencoded files that
500 have had traling spaces deleted.
502 `gnus-uu-use-interactive-view'
503 Non-nil means that gnus-uu will use interactive viewing mode."
504 (interactive)
507 ;; Default viewing action rules
509 (defvar gnus-uu-default-view-rules
510 (list
511 '("\\.\\(jpe?g\\|gif\\|tiff?\\|p[pgb]m\\|xwd\\|xbm\\|pcx\\)$" "xv")
512 '("\\.tga$" "tgatoppm %s | xv -")
513 '("\\.te?xt$\\|\\.doc$\\|read.*me" "xterm -e less")
514 '("\\.fli$" "xflick")
515 '("\\.\\(wav\\|aiff\\|hcom\\|u[blw]\\|s[bfw]\\|voc\\|smp\\)$"
516 "sox -v .5 %s -t .au -u - > /dev/audio")
517 '("\\.au$" "cat %s > /dev/audio")
518 '("\\.mod$" "str32")
519 '("\\.ps$" "ghostview")
520 '("\\.dvi$" "xdvi")
521 '("\\.1$" "xterm -e man -l")
522 '("\\.html$" "xmosaic")
523 '("\\.mpe?g$" "mpeg_play")
524 '("\\.\\(tar\\|arj\\|zip\\|zoo\\|arc\\|gz\\|Z\\|lzh\\|ar\\)$"
525 "gnus-uu-archive"))
527 "Default actions to be taken when the user asks to view a file.
528 To change the behaviour, you can either edit this variable or set
529 `gnus-uu-user-view-rules' to something useful.
531 For example:
533 To make gnus-uu use 'xli' to display JPEG and GIF files, put the
534 following in your .emacs file
536 (setq gnus-uu-user-view-rules (list '(\"jpg$\\\\|gif$\" \"xli\")))
538 Both these variables are lists of lists with two string elements. The
539 first string is a regular expression. If the file name matches this
540 regular expression, the command in the second string is executed with
541 the file as an argument.
543 If the command string contains \"%s\", the file name will be inserted
544 at that point in the command string. If there's no \"%s\" in the
545 command string, the file name will be appended to the command string
546 before executing.
548 There are several user variables to tailor the behaviour of gnus-uu to
549 your needs. First we have `gnus-uu-user-view-rules', which is the
550 variable gnus-uu first consults when trying to decide how to view a
551 file. If this variable contains no matches, gnus-uu examines the
552 default rule vaiable provided in this package. If gnus-uu finds no
553 match here, it uses `gnus-uu-user-view-rules-end' to try to make a
554 match.
556 Unless, of course, you are using the interactive view mode. Then
557 `gnus-uu-user-interactive-view-rules' and
558 `gnus-uu-user-interactive-view-rules-end' will be used instead.")
560 (defvar gnus-uu-user-view-rules nil
561 "Variable detailing what actions are to be taken to view a file.
562 See the documentation on the `gnus-uu-default-view-rules' variable for
563 details.")
565 (defvar gnus-uu-user-view-rules-end nil
566 "Variable saying what actions are to be taken if no rule matched the file name.
567 See the documentation on the `gnus-uu-default-view-rules' variable for
568 details.")
570 (defvar gnus-uu-user-interactive-view-rules nil
571 "Variable detailing what actions are to be taken to view a file when using interactive mode.
572 See the documentation on the `gnus-uu-default-view-rules' variable for
573 details.")
575 (defvar gnus-uu-user-interactive-view-rules-end nil
576 "Variable saying what actions are to be taken if no rule matched the file name when using interactive mode.
577 See the documentation on the `gnus-uu-default-view-rules' variable for
578 details.")
580 (defvar gnus-uu-default-interactive-view-rules-begin
581 (list
582 '("\\.te?xt$\\|\\.doc$\\|read.*me\\|\\.c?$\\|\\.h$\\|\\.bat$\\|\\.asm$\\|makefile" "cat %s | sed s/
583 //g")
584 '("\\.pas$" "cat %s | sed s/
585 //g")
589 ;; Default unpacking commands
591 (defvar gnus-uu-default-archive-rules
592 (list '("\\.tar$" "tar xf")
593 '("\\.zip$" "unzip")
594 '("\\.ar$" "ar x")
595 '("\\.arj$" "unarj x")
596 '("\\.zoo$" "zoo -e")
597 '("\\.lzh$" "lha x")
598 '("\\.Z$" "uncompress")
599 '("\\.gz$" "gunzip")
600 '("\\.arc$" "arc -x"))
603 (defvar gnus-uu-user-archive-rules nil
604 "A list that can be set to override the default archive unpacking commands.
605 To use, for instance, 'untar' to unpack tar files and 'zip -x' to
606 unpack zip files, say the following:
607 (setq gnus-uu-user-archive-rules
608 (list '(\"\\\\.tar$\" \"untar\")
609 '(\"\\\\.zip$\" \"zip -x\")))"
613 ;; Various variables users may set
615 (defvar gnus-uu-tmp-dir "/tmp/"
616 "Variable saying where gnus-uu is to do its work.
617 Default is \"/tmp/\".")
619 (defvar gnus-uu-do-not-unpack-archives nil
620 "Non-nil means that gnus-uu won't peek inside archives looking for files to dispay.
621 Default is nil.")
623 (defvar gnus-uu-view-and-save nil
624 "Non-nil means that the user will always be asked to save a file after viewing it.
625 If the variable is nil, the suer will only be asked to save if the
626 viewing is unsuccessful. Default is nil.")
628 (defvar gnus-uu-asynchronous nil
629 "Non-nil means that files will be viewed asynchronously.
630 Default is nil.")
632 (defvar gnus-uu-ask-before-view nil
633 "Non-nil means that gnus-uu will ask you before viewing each file.
634 Especially useful when `gnus-uu-asynchronous' is set. Default is
635 nil.")
637 (defvar gnus-uu-ignore-default-view-rules nil
638 "Non-nil means that gnus-uu will ignore the default viewing rules.
639 Only the user viewing rules will be consulted. Default is nil.")
641 (defvar gnus-uu-ignore-default-archive-rules nil
642 "Non-nil means that gnus-uu will ignore the default archive unpacking commands.
643 Only the user unpacking commands will be consulted. Default is nil.")
645 (defvar gnus-uu-kill-carriage-return t
646 "Non-nil means that gnus-uu will strip all carriage returns from articles.
647 Default is t.")
649 (defvar gnus-uu-unmark-articles-not-decoded nil
650 "Non-nil means that gnus-uu will mark articles that were unsuccessfully decoded as unread.
651 Default is nil.")
653 (defvar gnus-uu-output-window-height 20
654 "This variable says how tall the output buffer window is to be when using interactive view mode.
655 Change it at your convenience. Default is 20.")
657 (defvar gnus-uu-correct-stripped-uucode nil
658 "Non-nil means that gnus-uu will *try* to fix uuencoded files that have had traling spaces deleted.
659 Default is nil.")
661 (defvar gnus-uu-use-interactive-view nil
662 "Non-nil means that gnus-uu will use interactive viewing mode.
663 Gnus-uu will create a special buffer where the user may choose
664 interactively which files to view and how. Default is nil.")
667 ;; Internal variables
669 (defconst gnus-uu-begin-string "^begin[ \t]+[0-7][0-7][0-7][ \t]+\\(.*\\)$")
670 (defconst gnus-uu-end-string "^end[ \t]*$")
671 (defconst gnus-uu-body-line
672 "^M.............................................................?$")
673 (defconst gnus-uu-shar-begin-string "^#! */bin/sh")
675 (defvar gnus-uu-shar-file-name nil)
676 (defconst gnus-uu-shar-name-marker "begin [0-7][0-7][0-7][ \t]+\\(\\(\\w\\|\\.\\)*\\b\\)")
677 (defvar gnus-uu-shar-directory nil)
679 (defvar gnus-uu-file-name nil)
680 (defconst gnus-uu-uudecode-process nil)
682 (defvar gnus-uu-interactive-file-list nil)
683 (defvar gnus-uu-marked-article-list nil)
684 (defvar gnus-uu-generated-file-list nil)
686 (defconst gnus-uu-interactive-buffer-name "*gnus-uu interactive*")
687 (defconst gnus-uu-output-buffer-name "*Gnus UU Output*")
688 (defconst gnus-uu-result-buffer "*Gnus UU Result Buffer*")
690 (defconst gnus-uu-error-during-unarching nil)
692 ;; Interactive functions
694 ;; UUdecode and view
696 (defun gnus-uu-decode-and-view ()
697 "UUdecodes and 'views' (if possible) the resulting file.
698 'Viewing' can be any action at all, as defined in the
699 `gnus-uu-file-action-list' variable. Running 'xv' on gifs and 'cat
700 >/dev/audio' on au files are popular actions. If the file can't be
701 viewed, the user is asked if she would like to save the file instead."
702 (interactive)
703 (gnus-uu-decode-and-view-or-save t nil))
705 (defun gnus-uu-decode-and-save ()
706 "Decodes and saves the resulting file."
707 (interactive)
708 (gnus-uu-decode-and-view-or-save nil nil))
710 (defun gnus-uu-marked-decode-and-view ()
711 "Decodes and views articles marked.
712 The marked equivalent to `gnus-uu-decode-and-view'."
713 (interactive)
714 (gnus-uu-decode-and-view-or-save t t))
716 (defun gnus-uu-marked-decode-and-save ()
717 "Decodes and saves articles marked.
718 The marked equivalent to `gnus-uu-decode-and-save'."
719 (interactive)
720 (gnus-uu-decode-and-view-or-save nil t))
723 ;; Unshar and view
725 (defun gnus-uu-shar-and-view ()
726 "Unshars and views articles.
727 The shar equivalent of `gnus-uu-decode-and-view'."
728 (interactive)
729 (gnus-uu-unshar-and-view-or-save t nil))
731 (defun gnus-uu-shar-and-save ()
732 "Unshars and saves files.
733 The shar equivalent to `gnus-uu-decode-and-save'."
734 (interactive)
735 (gnus-uu-unshar-and-view-or-save nil nil))
737 (defun gnus-uu-marked-shar-and-view ()
738 "Unshars and views articles marked.
739 The marked equivalent to `gnus-uu-shar-and-view'."
740 (interactive)
741 (gnus-uu-unshar-and-view-or-save t t))
743 (defun gnus-uu-marked-shar-and-save ()
744 "Unshars and saves articles marked.
745 The marked equivalent to `gnus-uu-shar-and-save'."
746 (interactive)
747 (gnus-uu-unshar-and-view-or-save nil t))
750 ;; Decode and show in buffer
752 (defun gnus-uu-decode-and-show-in-buffer ()
753 "Uudecodes the current article and displays the result in a buffer.
754 Might be useful if someone has, for instance, some text uuencoded in
755 their sigs. (Stranger things have happened.)"
756 (interactive)
757 (let ((uu-buffer (get-buffer-create gnus-uu-output-buffer-name))
758 list-of-articles file-name)
759 (save-excursion
760 (and
761 (setq list-of-articles (list gnus-current-article))
762 (gnus-uu-grab-articles list-of-articles 'gnus-uu-uustrip-article-as)
763 (setq file-name (gnus-uu-decode gnus-uu-tmp-dir))
764 (progn
765 (save-excursion
766 (set-buffer uu-buffer)
767 (erase-buffer)
768 (insert-file-contents file-name))
769 (set-window-buffer (get-buffer-window gnus-article-buffer)
770 uu-buffer)
771 (message (format "Showing file %s in buffer" file-name))
772 (delete-file file-name))))))
775 ;; Toggle commands
777 (defun gnus-uu-toggle-asynchronous ()
778 "This function toggles asynchronous viewing."
779 (interactive)
780 (if (setq gnus-uu-asynchronous (not gnus-uu-asynchronous))
781 (message "gnus-uu will now view files asynchronously")
782 (message "gnus-uu will now view files synchronously")))
784 (defun gnus-uu-toggle-query ()
785 "This function toggles whether to ask before viewing or not."
786 (interactive)
787 (if (setq gnus-uu-ask-before-view (not gnus-uu-ask-before-view))
788 (message "gnus-uu will now ask before viewing")
789 (message "gnus-uu will now view without asking first")))
791 (defun gnus-uu-toggle-always-ask ()
792 "This function toggles whether to always ask to save a file after viewing."
793 (interactive)
794 (if (setq gnus-uu-view-and-save (not gnus-uu-view-and-save))
795 (message "gnus-uu will now ask to save the file after viewing")
796 (message "gnus-uu will now not ask to save after successful viewing")))
798 (defun gnus-uu-toggle-interactive-view ()
799 "This function toggles whether to use interactive view."
800 (interactive)
801 (if (setq gnus-uu-use-interactive-view (not gnus-uu-use-interactive-view))
802 (message "gnus-uu will now use interactive view")
803 (message "gnus-uu will now use non-interactive view")))
805 (defun gnus-uu-toggle-unmark-undecoded ()
806 "This function toggles whether to unmark articles not decoded."
807 (interactive)
808 (if (setq gnus-uu-unmark-articles-not-decoded
809 (not gnus-uu-unmark-articles-not-decoded))
810 (message "gnus-uu will now unmark articles not decoded")
811 (message "gnus-uu will now not unmark articles not decoded")))
813 (defun gnus-uu-toggle-kill-carriage-return ()
814 "This function toggles the stripping of carriage returns from the articles."
815 (interactive)
816 (if (setq gnus-uu-kill-carriage-return (not gnus-uu-kill-carriage-return))
817 (message "gnus-uu will now strip carriage returns")
818 (message "gnus-uu won't strip carriage returns")))
820 (defun gnus-uu-toggle-correct-stripped-uucode ()
821 "This function toggles whether to correct stripped uucode."
822 (interactive)
823 (if (setq gnus-uu-correct-stripped-uucode
824 (not gnus-uu-correct-stripped-uucode))
825 (message "gnus-uu will now correct stripped uucode")
826 (message "gnus-uu won't check and correct stripped uucode")))
828 (defun gnus-uu-toggle-any-variable ()
829 "This function ask what variable the user wants to toggle."
830 (interactive)
831 (let (rep)
832 (message "(a)sync, (q)uery, (p)ask, (k)ill CR, (i)nteractive, (u)nmark, (c)orrect")
833 (setq rep (read-char))
834 (if (= rep ?a)
835 (gnus-uu-toggle-asynchronous))
836 (if (= rep ?q)
837 (gnus-uu-toggle-query))
838 (if (= rep ?p)
839 (gnus-uu-toggle-always-ask))
840 (if (= rep ?k)
841 (gnus-uu-toggle-kill-carriage-return))
842 (if (= rep ?u)
843 (gnus-uu-toggle-unmark-undecoded))
844 (if (= rep ?c)
845 (gnus-uu-toggle-correct-stripped-uucode))
846 (if (= rep ?i)
847 (gnus-uu-toggle-interactive-view))))
850 ;; Edit line
852 (defun gnus-uu-edit-begin-line ()
853 "Edit the begin line of the current article."
854 (interactive)
855 (let ((buffer-read-only nil)
856 begin b)
857 (save-excursion
858 (set-buffer gnus-article-buffer)
859 (goto-line 1)
860 (if (not (re-search-forward "begin " nil t))
861 (progn (message "No begin line in the current article") (sit-for 2))
862 (beginning-of-line)
863 (setq b (point))
864 (end-of-line)
865 (setq begin (buffer-substring b (point)))
866 (setq begin (read-string "" begin))
867 (setq buffer-read-only nil)
868 (delete-region b (point))
869 (insert-string begin)))))
871 ;; Multi functions
873 (defun gnus-uu-multi-decode-and-view ()
874 "Choose a method of decoding and then decode and view.
875 This function lets the user decide what method to use for decoding.
876 Other than that, it's equivalent to the other decode-and-view
877 functions."
878 (interactive)
879 (gnus-uu-multi-decode-and-view-or-save t nil))
881 (defun gnus-uu-multi-decode-and-save ()
882 "Choose a method of decoding and then decode and save.
883 This function lets the user decide what method to use for decoding.
884 Other than that, it's equivalent to the other decode-and-save
885 functions."
886 (interactive)
887 (gnus-uu-multi-decode-and-view-or-save nil nil))
889 (defun gnus-uu-marked-multi-decode-and-view ()
890 "Choose a method of decoding and then decode and view the marked articles.
891 This function lets the user decide what method to use for decoding.
892 Other than that, it's equivalent to the other marked decode-and-view
893 functions."
894 (interactive)
895 (gnus-uu-multi-decode-and-view-or-save t t))
897 (defun gnus-uu-marked-multi-decode-and-save ()
898 "Choose a method of decoding and then decode and save the marked articles.
899 This function lets the user decide what method to use for decoding.
900 Other than that, it's equivalent to the other marked decode-and-save
901 functions."
902 (interactive)
903 (gnus-uu-multi-decode-and-view-or-save t t))
905 (defun gnus-uu-multi-decode-and-view-or-save (view marked)
906 (let (decode-type)
907 (message "(u)udecode, (s)har, s(a)ve, (b)inhex: ")
908 (setq decode-type (read-char))
909 (if (= decode-type ?
910 ) (setq decode-type ?u))
911 (if (= decode-type ?u)
912 (gnus-uu-decode-and-view-or-save view marked)
913 (if (= decode-type ?s)
914 (gnus-uu-unshar-and-view-or-save view marked)
915 (if (= decode-type ?b)
916 (gnus-uu-binhex-and-save view marked)
917 (if (= decode-type ?a)
918 (gnus-uu-save-articles view marked)
919 (message (format "Unknown decode method '%c'." decode-type))
920 (sit-for 2)))))))
923 ;; uuencode and post
925 (defconst gnus-uu-uuencode-post-length 90)
927 (defun gnus-uu-post ()
928 (interactive)
929 (let ((uuencode-buffer-name "*uuencode buffer*")
930 (send-buffer-name "*uuencode send buffer*")
931 (top-string "[ cut here %s (%s %d/%d) %s gnus-uu ]")
932 file uubuf short-file length parts header i end beg
933 beg-line minlen buf post-buf whole-len)
934 (setq file (read-file-name
935 "What file do you want to uuencode and post? " "~/Unrd.jpg"))
936 (if (not (file-exists-p file))
937 (message "%s: No such file" file)
938 (save-excursion
939 (setq post-buf (current-buffer))
940 (set-buffer (setq uubuf (get-buffer-create uuencode-buffer-name)))
941 (erase-buffer)
942 (if (string-match "^~/" file)
943 (setq file (concat "$HOME" (substring file 1))))
944 (if (string-match "/[^/]*$" file)
945 (setq short-file (substring file (1+ (match-beginning 0))))
946 (setq short-file file))
947 (call-process "sh" nil uubuf nil "-c"
948 (format "uuencode %s %s" file short-file))
949 (goto-char 1)
950 (forward-line 1)
951 (while (re-search-forward " " nil t)
952 (replace-match "`"))
953 (setq length (count-lines 1 (point-max)))
954 (setq parts (/ length gnus-uu-uuencode-post-length))
955 (if (not (< (% length gnus-uu-uuencode-post-length) 4))
956 (setq parts (1+ parts)))
957 (message "Det er %d parts" parts))
958 (goto-char 1)
959 (search-forward mail-header-separator nil t)
960 (beginning-of-line)
961 (forward-line 1)
962 (setq header (buffer-substring 1 (point)))
963 (goto-char 1)
964 (if (re-search-forward "^Subject: " nil t)
965 (progn
966 (end-of-line)
967 (insert (format " (0/%d)" parts))))
968 ; (save-excursion
969 ; (set-buffer (get-buffer-create "*tull"))
970 ; (erase-buffer)
971 ; (goto-char (point-max))
972 ; (insert-buffer send-buffer-name))
973 (gnus-inews-news)
975 (save-excursion
976 (setq i 1)
977 (setq beg 1)
978 (while (not (> i parts))
979 (set-buffer (get-buffer-create send-buffer-name))
980 (erase-buffer)
981 (insert header)
982 (insert "\n")
983 (setq whole-len
984 (- 62 (length (format top-string "" short-file i parts ""))))
985 (setq minlen (/ whole-len 2))
986 (setq
987 beg-line
988 (format top-string
989 (make-string minlen ?-)
990 short-file i parts
991 (make-string (if (= 0 (% whole-len 2)) (1- minlen) minlen) ?-)))
992 (insert beg-line)
993 (insert "\n")
994 (goto-char 1)
995 (if (re-search-forward "^Subject: " nil t)
996 (progn
997 (end-of-line)
998 (insert (format " (%d/%d)" i parts))))
999 (goto-char (point-max))
1000 (save-excursion
1001 (set-buffer uubuf)
1002 (goto-char beg)
1003 (if (= i parts)
1004 (goto-char (point-max))
1005 (forward-line gnus-uu-uuencode-post-length))
1006 (setq end (point)))
1007 (insert-buffer-substring uubuf beg end)
1008 (insert beg-line)
1009 (insert "\n")
1010 (setq beg end)
1011 (setq i (1+ i))
1012 ; (save-excursion
1013 ; (set-buffer (get-buffer-create "*tull"))
1014 ; (goto-char (point-max))
1015 ; (insert-buffer send-buffer-name))
1016 (gnus-inews-news)
1018 (and (setq buf (get-buffer send-buffer-name))
1019 (kill-buffer buf))
1020 (and (setq buf (get-buffer uuencode-buffer-name))
1021 (kill-buffer buf)))))
1025 ;; Decode and all files
1027 (defconst gnus-uu-rest-of-articles nil)
1028 (defconst gnus-uu-do-sloppy-uudecode nil)
1029 (defvar gnus-uu-current-save-dir nil)
1031 (defun gnus-uu-decode-and-save-all-unread-articles ()
1032 "Try to decode all unread articles and saves the result.
1033 This function reads all unread articles in the current group and sees
1034 whether it can uudecode the articles. The user will be prompted for an
1035 directory to put the resulting (if any) files."
1036 (interactive)
1037 (gnus-uu-decode-and-save-articles t t))
1039 (defun gnus-uu-decode-and-save-all-articles ()
1040 "Try to decode all articles and saves the result.
1041 Does the same as `gnus-uu-decode-and-save-all-unread-articles', except
1042 that it grabs all articles visible, unread or not."
1043 (interactive)
1044 (gnus-uu-decode-and-save-articles nil t))
1046 (defun gnus-uu-decode-and-save-all-unread-articles-and-mark ()
1047 "Try to decode all unread articles and saves the result and marks everything as read.
1048 Does the same as `gnus-uu-decode-and-save-all-unread-articles', except that
1049 it marks everything as read, even if it couldn't decode the articles."
1050 (interactive)
1051 (gnus-uu-decode-and-save-articles t nil))
1053 (defun gnus-uu-decode-and-save-all-articles-and-mark ()
1054 "Try to decode all articles and saves the result and marks everything as read.
1055 Does the same as `gnus-uu-decode-and-save-all-articles', except that
1056 it marks everything as read, even if it couldn't decode the articles."
1057 (interactive)
1058 (gnus-uu-decode-and-save-articles nil nil))
1060 (defun gnus-uu-decode-and-save-articles (&optional unread unmark)
1061 (let ((gnus-uu-unmark-articles-not-decoded unmark)
1062 (filest "")
1063 where dir did unmark saved-list)
1064 (setq gnus-uu-do-sloppy-uudecode t)
1065 (setq dir (gnus-uu-read-directory "Where do you want the files? "))
1066 (message "Grabbing...")
1067 (setq gnus-uu-rest-of-articles
1068 (gnus-uu-get-list-of-articles "^." nil unread))
1069 (setq gnus-uu-file-name nil)
1070 (while (and gnus-uu-rest-of-articles
1071 (gnus-uu-grab-articles gnus-uu-rest-of-articles
1072 'gnus-uu-uustrip-article-as))
1073 (if gnus-uu-file-name
1074 (progn
1075 (setq saved-list (cons gnus-uu-file-name saved-list))
1076 (rename-file (concat gnus-uu-tmp-dir gnus-uu-file-name)
1077 (concat dir gnus-uu-file-name) t)
1078 (setq did t)
1079 (setq gnus-uu-file-name nil))))
1080 (if (not did)
1082 (while saved-list
1083 (setq filest (concat filest " " (car saved-list)))
1084 (setq saved-list (cdr saved-list)))
1085 (message "Saved%s" filest)))
1086 (setq gnus-uu-do-sloppy-uudecode nil))
1089 ;; Work functions
1091 (defun gnus-uu-decode-and-view-or-save (view marked)
1092 (gnus-uu-initialize)
1093 (let (file decoded)
1094 (save-excursion
1095 (if (gnus-uu-decode-and-strip nil marked)
1096 (progn
1097 (setq decoded t)
1098 (setq file (concat gnus-uu-tmp-dir gnus-uu-file-name))
1099 (if view
1100 (gnus-uu-view-file file)
1101 (gnus-uu-save-file file)))))
1103 (gnus-uu-summary-next-subject)
1105 (if gnus-uu-error-during-unarching
1106 (gnus-uu-clean-up)
1107 (if (and gnus-uu-use-interactive-view view decoded)
1108 (gnus-uu-do-interactive)))
1110 (if (or (not gnus-uu-use-interactive-view) (not decoded))
1111 (gnus-uu-clean-up))))
1114 ; Unshars and views/saves marked/unmarked articles.
1116 (defun gnus-uu-unshar-and-view-or-save (view marked)
1117 (gnus-uu-initialize)
1118 (let (tar-file files decoded)
1119 (save-excursion
1120 (setq gnus-uu-shar-directory
1121 (make-temp-name (concat gnus-uu-tmp-dir "gnusuush")))
1122 (make-directory gnus-uu-shar-directory)
1123 (gnus-uu-add-file gnus-uu-shar-directory)
1124 (if (gnus-uu-decode-and-strip t marked)
1125 (progn
1126 (setq decoded t)
1127 (setq files (directory-files gnus-uu-shar-directory t))
1128 (setq gnus-uu-generated-file-list
1129 (append files gnus-uu-generated-file-list))
1130 (if (> (length files) 3)
1131 (progn
1132 (setq tar-file
1133 (concat
1134 (make-temp-name (concat gnus-uu-tmp-dir "gnusuuar"))
1135 ".tar"))
1136 (gnus-uu-add-file tar-file)
1137 (call-process "sh" nil
1138 (get-buffer-create gnus-uu-output-buffer-name)
1139 nil "-c"
1140 (format "cd %s ; tar cf %s * ; cd .. ; rm -r %s"
1141 gnus-uu-shar-directory
1142 tar-file
1143 gnus-uu-shar-directory))
1144 (if view
1145 (gnus-uu-view-file tar-file)
1146 (gnus-uu-save-file tar-file)))
1147 (if view
1148 (gnus-uu-view-file (elt files 2))
1149 (gnus-uu-save-file (elt files 2)))))))
1151 (gnus-uu-summary-next-subject)
1153 (if (and gnus-uu-use-interactive-view view decoded)
1154 (gnus-uu-do-interactive))
1156 (if (or (not gnus-uu-use-interactive-view) (not decoded))
1157 (gnus-uu-clean-up))))
1160 (defconst gnus-uu-saved-article-name nil)
1161 (defun gnus-uu-save-articles (view marked)
1162 (let (list-of-articles)
1163 (save-excursion
1164 (if (not marked)
1165 (setq list-of-articles (gnus-uu-get-list-of-articles))
1166 (setq list-of-articles (reverse gnus-uu-marked-article-list))
1167 (setq gnus-uu-marked-article-list nil))
1168 (if (not list-of-articles)
1169 (progn
1170 (message "No list of articles")
1171 (sit-for 2))
1172 (setq gnus-uu-saved-article-name
1173 (concat gnus-uu-tmp-dir
1174 (read-file-name "Enter file name: " gnus-newsgroup-name
1175 gnus-newsgroup-name)))
1176 (gnus-uu-add-file gnus-uu-saved-article-name)
1177 (if (gnus-uu-grab-articles list-of-articles 'gnus-uu-save-article)
1178 (gnus-uu-save-file gnus-uu-saved-article-name))))))
1181 (defun gnus-uu-save-article (buffer in-state)
1182 (save-excursion
1183 (set-buffer buffer)
1184 (call-process-region
1185 1 (point-max) "sh" nil (get-buffer-create gnus-uu-output-buffer-name)
1186 nil "-c" (concat "cat >> " gnus-uu-saved-article-name)))
1187 'ok)
1190 ;; Binhex
1191 (defconst gnus-uu-binhex-body-line
1192 "^................................................................$")
1193 (defconst gnus-uu-binhex-begin-line
1194 "^:...............................................................$")
1195 (defconst gnus-uu-binhex-end-line
1196 ":$")
1197 (defvar gnus-uu-binhex-article-name nil)
1200 (defun gnus-uu-binhex-and-save (view marked)
1201 (let (list-of-articles)
1202 (save-excursion
1203 (if (not marked)
1204 (setq list-of-articles (gnus-uu-get-list-of-articles))
1205 (setq list-of-articles (reverse gnus-uu-marked-article-list))
1206 (setq gnus-uu-marked-article-list nil))
1207 (if (not list-of-articles)
1208 (progn
1209 (message "No list of articles")
1210 (sit-for 2))
1211 (setq gnus-uu-binhex-article-name
1212 (concat gnus-uu-tmp-dir
1213 (read-file-name "Enter binhex file name: "
1214 gnus-newsgroup-name
1215 gnus-newsgroup-name)))
1216 (gnus-uu-add-file gnus-uu-binhex-article-name)
1217 (if (gnus-uu-grab-articles list-of-articles 'gnus-uu-binhex-article)
1218 (gnus-uu-save-file gnus-uu-binhex-article-name))))))
1221 (defun gnus-uu-binhex-article (buffer in-state)
1222 (let ((state 'ok)
1223 start-char)
1224 (save-excursion
1225 (set-buffer buffer)
1226 (goto-char 1)
1227 (if (not (re-search-forward (concat gnus-uu-binhex-begin-line "\\|"
1228 gnus-uu-binhex-body-line) nil t))
1229 (setq state 'wrong-type)
1230 (beginning-of-line)
1231 (setq start-char (point))
1232 (if (looking-at gnus-uu-binhex-begin-line)
1233 (setq state 'begin)
1234 (setq state 'middle))
1235 (goto-char (point-max))
1236 (re-search-backward (concat gnus-uu-binhex-body-line "\\|"
1237 gnus-uu-binhex-end-line) nil t)
1238 (if (looking-at gnus-uu-binhex-end-line)
1239 (if (eq state 'begin)
1240 (setq state 'begin-and-end)
1241 (setq state 'end)))
1242 (beginning-of-line)
1243 (forward-line 1)
1244 (append-to-file start-char (point) gnus-uu-binhex-article-name)))
1245 state))
1248 ;; Internal view commands
1250 ; This function takes two parameters. The first is name of the file to
1251 ; be viewed. `gnus-uu-view-file' will look for an action associated
1252 ; with the file type of the file. If it finds an appropriate action,
1253 ; the file will be attempted displayed.
1255 ; The second parameter specifies if the user is to be asked whether to
1256 ; save the file if viewing is unsuccessful. t means "do not ask."
1258 ; Note that the file given will be deleted by this function, one way
1259 ; or another. If `gnus-uu-asynchronous' is set, it won't be deleted
1260 ; right away, but sometime later. If the user is offered to save the
1261 ; file, it'll be moved to wherever the user wants it.
1263 ; `gnus-uu-view-file' returns t if viewing is successful.
1265 (defun gnus-uu-view-file (file-name &optional dont-ask)
1266 (let (action did-view
1267 (didnt-want t)
1268 (do-view t))
1269 (setq action
1270 (gnus-uu-choose-action
1271 file-name
1272 (append
1273 (if (and gnus-uu-use-interactive-view
1274 gnus-uu-user-interactive-view-rules)
1275 gnus-uu-user-interactive-view-rules
1276 gnus-uu-user-view-rules)
1277 (if (or gnus-uu-ignore-default-view-rules
1278 (not gnus-uu-use-interactive-view))
1280 gnus-uu-default-interactive-view-rules-begin)
1281 (if gnus-uu-ignore-default-view-rules
1282 nil
1283 gnus-uu-default-view-rules)
1284 (if (and gnus-uu-use-interactive-view
1285 gnus-uu-user-interactive-view-rules-end)
1286 gnus-uu-user-interactive-view-rules-end
1287 gnus-uu-user-view-rules-end))))
1289 (if (and gnus-uu-use-interactive-view
1290 (not (string= (or action "") "gnus-uu-archive")))
1291 (gnus-uu-enter-interactive-file (or action "") file-name)
1293 (if action
1294 (if (string= action "gnus-uu-archive")
1295 (setq did-view (gnus-uu-treat-archive file-name))
1297 (if gnus-uu-ask-before-view
1298 (setq didnt-want
1299 (or (not
1300 (setq do-view
1301 (y-or-n-p
1302 (format "Do you want to view %s? "
1303 file-name))))
1304 didnt-want)))
1306 (if do-view
1307 (setq did-view
1308 (if gnus-uu-asynchronous
1309 (gnus-uu-call-asynchronous file-name action)
1310 (gnus-uu-call-synchronous file-name action))))))
1312 (if (and (not dont-ask) (not gnus-uu-use-interactive-view))
1313 (progn
1314 (if (and
1315 didnt-want
1316 (or (not action)
1317 (and (string= action "gnus-uu-archive")
1318 (not did-view))))
1319 (progn
1320 (message
1321 (format "Could find no rule for %s" file-name))
1322 (sit-for 2)))
1323 (and (or (not did-view) gnus-uu-view-and-save)
1324 (y-or-n-p
1325 (format "Do you want to save the file %s? "
1326 file-name))
1327 (gnus-uu-save-file file-name))))
1329 (if (and (file-exists-p file-name)
1330 (not gnus-uu-use-interactive-view)
1331 (or
1332 (not (and gnus-uu-asynchronous did-view))
1333 (string= action "gnus-uu-archive")))
1334 (delete-file file-name)))
1336 did-view))
1339 ; `gnus-uu-call-synchronous' takes two parameters: The name of the
1340 ; file to be displayed and the command to display it with. Returns t
1341 ; on success and nil if the file couldn't be displayed.
1343 (defun gnus-uu-call-synchronous (file-name action)
1344 (let (did-view command)
1345 (save-excursion
1346 (set-buffer (get-buffer-create gnus-uu-output-buffer-name))
1347 (erase-buffer)
1348 (setq command (gnus-uu-command action file-name))
1349 (message (format "Viewing with '%s'" command))
1350 (if (not (= 0 (call-process "sh" nil t nil "-c" command)))
1351 (progn
1352 (goto-char 1)
1353 (while (re-search-forward "\n" nil t)
1354 (replace-match " "))
1355 (message (concat "Error: " (buffer-substring 1 (point-max))))
1356 (sit-for 2))
1357 (message "")
1358 (setq did-view t)))
1359 did-view))
1361 ; `gnus-uu-call-asyncronous' takes two parameters: The name of the
1362 ; file to be displayed and the command to display it with. Since the
1363 ; view command is executed asynchronously, it's kinda hard to decide
1364 ; whether the command succeded or not, so this function always returns
1365 ; t. It also adds "; rm -f file-name" to the end of the execution
1366 ; string, so the file will be removed after viewing has ended.
1368 (defun gnus-uu-call-asynchronous (file-name action)
1369 (let (command file tmp-file start)
1370 (while (string-match "/" file-name start)
1371 (setq start (1+ (match-beginning 0))))
1372 (setq file (substring file-name start))
1373 (setq tmp-file (concat gnus-uu-tmp-dir file))
1374 (if (string= tmp-file file-name)
1376 (rename-file file-name tmp-file t)
1377 (setq file-name tmp-file))
1379 (setq command (gnus-uu-command action file-name))
1380 (setq command (format "%s ; rm -f %s" command file-name))
1381 (message (format "Viewing with %s" command))
1382 (start-process "gnus-uu-view" nil "sh" "-c" command)
1386 ; `gnus-uu-decode-and-strip' does all the main work. It finds out what
1387 ; articles to grab, grabs them, strips the result and decodes. If any
1388 ; of these operations fail, it returns nil, t otherwise. If shar is
1389 ; t, it will pass this on to `gnus-uu-grab-articles', which will
1390 ; (probably) unshar the articles. If use-marked is non-nil, it won't
1391 ; try to find articles, but use the marked list.
1393 (defun gnus-uu-decode-and-strip (&optional shar use-marked)
1394 (let (list-of-articles)
1395 (save-excursion
1397 (if use-marked
1398 (progn (if (eq gnus-uu-marked-article-list ())
1399 (message "No articles marked")
1400 (setq list-of-articles (reverse gnus-uu-marked-article-list))
1401 (gnus-uu-unmark-all-articles)))
1402 (setq list-of-articles (gnus-uu-get-list-of-articles)))
1404 (and list-of-articles
1405 (gnus-uu-grab-articles list-of-articles
1406 (if shar
1407 'gnus-uu-unshar-article
1408 'gnus-uu-uustrip-article-as))))))
1411 ; Takes a string and puts a \ in front of every special character;
1412 ; ignores any leading "version numbers" thingies that they use in the
1413 ; comp.binaries groups, and either replaces anything that looks like
1414 ; "2/3" with "[0-9]+/[0-9]+" or, if it can't find something like that,
1415 ; replaces the last two numbers with "[0-9]+". This, in my experience,
1416 ; should get most postings of a series."
1418 (defun gnus-uu-reginize-string (string)
1419 (let ((count 2)
1420 (vernum "v[0-9]+[a-z][0-9]+:")
1421 reg beg)
1422 (save-excursion
1423 (set-buffer (get-buffer-create gnus-uu-output-buffer-name))
1424 (erase-buffer)
1425 (insert (regexp-quote string))
1426 (setq beg 1)
1428 (setq case-fold-search nil)
1429 (goto-char 1)
1430 (if (looking-at vernum)
1431 (progn
1432 (replace-match vernum t t)
1433 (setq beg (length vernum))))
1435 (goto-char beg)
1436 (if (re-search-forward "[ \t]*[0-9]+/[0-9]+" nil t)
1437 (replace-match " [0-9]+/[0-9]+")
1439 (goto-char beg)
1440 (if (re-search-forward "[0-9]+[ \t]*of[ \t]*[0-9]+" nil t)
1441 (replace-match "[0-9]+ of [0-9]+")
1443 (end-of-line)
1444 (while (and (re-search-backward "[0-9]" nil t) (> count 0))
1445 (while (and
1446 (looking-at "[0-9]")
1447 (< 1 (goto-char (1- (point))))))
1448 (re-search-forward "[0-9]+" nil t)
1449 (replace-match "[0-9]+")
1450 (backward-char 5)
1451 (setq count (1- count)))))
1453 (goto-char beg)
1454 (while (re-search-forward "[ \t]+" nil t)
1455 (replace-match "[ \t]*" t t))
1457 (buffer-substring 1 (point-max)))))
1460 ; Finds all articles that matches the regular expression given.
1461 ; Returns the resulting list.
1463 (defun gnus-uu-get-list-of-articles (&optional subject mark-articles only-unread)
1464 (let (beg end reg-subject list-of-subjects list-of-numbers art-num)
1465 (save-excursion
1467 ; If the subject is not given, this function looks at the current subject
1468 ; and takes that.
1470 (if subject
1471 (setq reg-subject subject)
1472 (end-of-line)
1473 (setq end (point))
1474 (beginning-of-line)
1475 (if (not (re-search-forward "\\] " end t))
1476 (progn (message "No valid subject chosen") (sit-for 2))
1477 (setq subject (buffer-substring (point) end))
1478 (setq reg-subject
1479 (concat "\\[.*\\] " (gnus-uu-reginize-string subject)))))
1481 ; (message reg-subject)(sleep-for 2)
1483 (if reg-subject
1484 (progn
1486 ; Collect all subjects matching reg-subject.
1488 (let ((case-fold-search t))
1489 (setq case-fold-search t)
1490 (goto-char 1)
1491 (while (re-search-forward reg-subject nil t)
1492 (beginning-of-line)
1493 (setq beg (point))
1494 (if (or (not only-unread) (looking-at " \\|-"))
1495 (progn
1496 (end-of-line)
1497 (setq list-of-subjects (cons
1498 (buffer-substring beg (point))
1499 list-of-subjects)))
1500 (end-of-line))))
1502 ; Expand all numbers in all the subjects: (hi9 -> hi0009, etc).
1504 (setq list-of-subjects (gnus-uu-expand-numbers list-of-subjects))
1506 ; Sort the subjects.
1508 (setq list-of-subjects (sort list-of-subjects 'gnus-uu-string<))
1510 ; Get the article numbers from the sorted list of subjects.
1512 (while list-of-subjects
1513 (setq art-num (gnus-uu-article-number (car list-of-subjects)))
1514 (if mark-articles (gnus-summary-mark-as-read art-num ?#))
1515 (setq list-of-numbers (cons art-num list-of-numbers))
1516 (setq list-of-subjects (cdr list-of-subjects)))
1518 (setq list-of-numbers (nreverse list-of-numbers))
1520 (if (not list-of-numbers)
1521 (progn
1522 (message (concat "No subjects matched " subject))
1523 (sit-for 2)))))
1525 list-of-numbers)))
1528 ; Takes a list of strings and "expands" all numbers in all the
1529 ; strings. That is, this function makes all numbers equal length by
1530 ; prepending lots of zeroes before each number. This is to ease later
1531 ; sorting to find out what sequence the articles are supposed to be
1532 ; decoded in. Returns the list of expanded strings.
1534 (defun gnus-uu-expand-numbers (string-list)
1535 (let (string out-list pos num)
1536 (save-excursion
1537 (set-buffer (get-buffer-create gnus-uu-output-buffer-name))
1538 (while string-list
1539 (erase-buffer)
1540 (setq string (car string-list))
1541 (setq string-list (cdr string-list))
1542 (insert string)
1543 (goto-char 1)
1544 (while (re-search-forward "[ \t]+" nil t)
1545 (replace-match " "))
1546 (goto-char 1)
1547 (while (re-search-forward "[A-Za-z]" nil t)
1548 (replace-match "a" t t))
1550 (goto-char 1)
1551 (if (not (search-forward "] " nil t))
1553 (while (re-search-forward "[0-9]+" nil t)
1554 (replace-match
1555 (format "%06d"
1556 (string-to-int (buffer-substring
1557 (match-beginning 0) (match-end 0))))))
1558 (setq string (buffer-substring 1 (point-max)))
1559 (setq out-list (cons string out-list)))))
1560 out-list))
1563 ; Used in a sort for finding out what string is bigger, but ignoring
1564 ; everything before the subject part.
1566 (defun gnus-uu-string< (string1 string2)
1567 (string< (substring string1 (string-match "\\] " string1))
1568 (substring string2 (string-match "\\] " string2))))
1571 ;; gnus-uu-grab-article
1573 ; This is the general multi-article treatment function. It takes a
1574 ; list of articles to be grabbed and a function to apply to each
1575 ; article. It puts the result in `gnus-uu-result-buffer'.
1577 ; The function to be called should take two parameters. The first is
1578 ; the buffer that has the article that should be treated. The function
1579 ; should leave the result in this buffer as well. This result is then
1580 ; appended on to the `gnus-uu-result-buffer'.
1582 ; The second parameter is the state of the list of articles, and can
1583 ; have three values: 'start, 'middle and 'end.
1585 ; The function can have several return values:
1586 ; 'error if there was an error while treating.
1587 ; 'end if the last article has been sighted.
1588 ; 'begin-and-end if the article is both the beginning and
1589 ; the end. All these three return values results in
1590 ; `gnus-uu-grab-articles' stopping traversing of the list
1591 ; of articles.
1592 ; 'middle if the article is a "middle" article.
1593 ; 'ok if everything is ok.
1595 (defvar gnus-uu-has-been-grabbed nil)
1597 (defun gnus-uu-unmark-list-of-grabbed (&optional dont-unmark-last-article)
1598 (let (art)
1599 (if (or (not gnus-uu-has-been-grabbed)
1600 (not gnus-uu-unmark-articles-not-decoded))
1602 (if dont-unmark-last-article
1603 (progn
1604 (setq art (car gnus-uu-has-been-grabbed))
1605 (setq gnus-uu-has-been-grabbed (cdr gnus-uu-has-been-grabbed))))
1606 (while gnus-uu-has-been-grabbed
1607 (gnus-summary-mark-as-unread (car gnus-uu-has-been-grabbed) t)
1608 (setq gnus-uu-has-been-grabbed (cdr gnus-uu-has-been-grabbed)))
1609 (if dont-unmark-last-article
1610 (setq gnus-uu-has-been-grabbed (list art))))))
1613 ; This function takes a list of articles and a function to apply to
1614 ; each article grabbed. The result of the function is appended on to
1615 ; `gnus-uu-result-buffer'.
1617 ; This function returns t if the grabbing and the process-function
1618 ; has been successful and nil otherwise."
1620 (defun gnus-uu-grab-articles (list-of-articles process-function)
1621 (let ((result-buffer (get-buffer-create gnus-uu-result-buffer))
1622 (state 'first)
1623 (process-state 'ok)
1624 (result t)
1625 (wrong-type t)
1626 (has-been-begin nil)
1627 (article nil))
1629 (save-excursion
1630 (set-buffer result-buffer)
1631 (erase-buffer))
1632 (setq gnus-uu-has-been-grabbed nil)
1633 (while (and list-of-articles
1634 (not (eq process-state 'end))
1635 (not (eq process-state 'begin-and-end))
1636 (not (eq process-state 'error)))
1637 (setq article (car list-of-articles))
1638 (setq list-of-articles (cdr list-of-articles))
1639 (setq gnus-uu-has-been-grabbed (cons article gnus-uu-has-been-grabbed))
1641 (if (eq list-of-articles ()) (setq state 'last))
1643 (message (format "Getting article %d" article))
1644 (if (not (= (or gnus-current-article 0) article))
1645 (gnus-summary-display-article article))
1646 (gnus-summary-mark-as-read article)
1648 (save-excursion
1649 (set-buffer gnus-article-buffer)
1650 (widen))
1652 (setq process-state (funcall process-function gnus-article-buffer state))
1654 (if (or (eq process-state 'begin) (eq process-state 'begin-and-end)
1655 (eq process-state 'ok))
1656 (setq has-been-begin t))
1658 (if (not (eq process-state 'wrong-type))
1659 (setq wrong-type nil)
1660 (if gnus-uu-unmark-articles-not-decoded
1661 (gnus-summary-mark-as-unread article t)))
1663 (if gnus-uu-do-sloppy-uudecode
1664 (setq wrong-type nil))
1666 (if (and (not has-been-begin)
1667 (not gnus-uu-do-sloppy-uudecode)
1668 (or (eq process-state 'end)
1669 (eq process-state 'middle)))
1670 (progn
1671 (setq process-state 'error)
1672 (message "No begin part at the beginning")
1673 (sit-for 2))
1674 (setq state 'middle)))
1676 (if (and (not has-been-begin) (not gnus-uu-do-sloppy-uudecode))
1677 (progn
1678 (setq result nil)
1679 (message "Wrong type file")
1680 (sit-for 2))
1681 (if (eq process-state 'error)
1682 (setq result nil)
1683 (if (not (or (eq process-state 'ok)
1684 (eq process-state 'end)
1685 (eq process-state 'begin-and-end)))
1686 (progn
1687 (if (not gnus-uu-do-sloppy-uudecode)
1688 (progn
1689 (message "End of articles reached before end of file")
1690 (sit-for 2)))
1691 (gnus-uu-unmark-list-of-grabbed)
1692 (setq result nil)))))
1693 (setq gnus-uu-rest-of-articles list-of-articles)
1694 result))
1697 (defun gnus-uu-uudecode-sentinel (process event)
1698 ; (message "Process '%s' has received event '%s'" process event)
1699 ; (sit-for 2)
1700 (delete-process (get-process process)))
1703 (defun gnus-uu-uustrip-article-as (process-buffer in-state)
1704 (let ((state 'ok)
1705 (process-connection-type nil)
1706 start-char pst name-beg name-end buf-state)
1707 (save-excursion
1708 (set-buffer process-buffer)
1709 (setq buf-state buffer-read-only)
1710 (setq buffer-read-only nil)
1712 (goto-char 1)
1714 (if gnus-uu-kill-carriage-return
1715 (progn
1716 (while (search-forward "
1717 " nil t)
1718 (delete-backward-char 1))
1719 (goto-char 1)))
1721 (if (not (re-search-forward gnus-uu-begin-string nil t))
1722 (if (not (re-search-forward gnus-uu-body-line nil t))
1723 (setq state 'wrong-type)))
1725 (if (eq state 'wrong-type)
1727 (beginning-of-line)
1728 (setq start-char (point))
1730 (if (looking-at gnus-uu-begin-string)
1731 (progn
1732 (setq name-end (match-end 1))
1733 (goto-char (setq name-beg (match-beginning 1)))
1734 (while (re-search-forward "/" name-end t)
1735 (replace-match "-"))
1736 (setq gnus-uu-file-name (buffer-substring name-beg name-end))
1737 (and gnus-uu-uudecode-process
1738 (setq pst (process-status
1739 (or gnus-uu-uudecode-process "nevair")))
1740 (if (or (eq pst 'stop) (eq pst 'run))
1741 (progn
1742 (delete-process gnus-uu-uudecode-process)
1743 (gnus-uu-unmark-list-of-grabbed t))))
1744 (setq gnus-uu-uudecode-process
1745 (start-process
1746 "*uudecode*"
1747 (get-buffer-create gnus-uu-output-buffer-name)
1748 "sh" "-c"
1749 (format "cd %s ; uudecode" gnus-uu-tmp-dir)))
1750 (set-process-sentinel
1751 gnus-uu-uudecode-process 'gnus-uu-uudecode-sentinel)
1752 (setq state 'begin)
1753 (gnus-uu-add-file (concat gnus-uu-tmp-dir gnus-uu-file-name)))
1754 (setq state 'middle))
1756 (goto-char (point-max))
1758 (re-search-backward
1759 (concat gnus-uu-body-line "\\|" gnus-uu-end-string) nil t)
1760 (beginning-of-line)
1762 (if (looking-at gnus-uu-end-string)
1763 (if (eq state 'begin)
1764 (setq state 'begin-and-end)
1765 (setq state 'end)))
1766 (forward-line 1)
1768 ; (message "Ja: %s" state)(sit-for 0)(sleep-for 2)
1770 (and gnus-uu-uudecode-process
1771 (setq pst (process-status (or gnus-uu-uudecode-process "nevair")))
1772 (if (or (eq pst 'run) (eq pst 'stop))
1773 (progn
1774 (if gnus-uu-correct-stripped-uucode
1775 (progn
1776 (gnus-uu-check-correct-stripped-uucode
1777 start-char (point))
1778 (goto-char (point-max))
1779 (re-search-backward
1780 (concat gnus-uu-body-line "\\|" gnus-uu-end-string)
1781 nil t)
1782 (forward-line 1)))
1783 (condition-case err
1784 (process-send-region gnus-uu-uudecode-process
1785 start-char (point))
1786 (error
1787 (progn
1788 (message "Her var en uuerror")
1789 (sleep-for 2)
1790 (setq state 'wrong-type)
1791 (delete-process gnus-uu-uudecode-process)))))
1792 (setq state 'wrong-type)))
1793 (if (not gnus-uu-uudecode-process)
1794 (setq state 'wrong-type)))
1796 (setq buffer-read-only buf-state))
1797 state))
1800 ; This function is used by `gnus-uu-grab-articles' to treat
1801 ; a shared article.
1803 (defun gnus-uu-unshar-article (process-buffer in-state)
1804 (let ((state 'ok)
1805 start-char)
1806 (save-excursion
1807 (set-buffer process-buffer)
1808 (goto-char 1)
1809 (if (not (re-search-forward gnus-uu-shar-begin-string nil t))
1810 (setq state 'wrong-type)
1811 (beginning-of-line)
1812 (setq start-char (point))
1813 (call-process-region
1814 start-char (point-max) "sh" nil
1815 (get-buffer-create gnus-uu-output-buffer-name) nil
1816 "-c" (concat "cd " gnus-uu-shar-directory " ; sh"))))
1817 state))
1820 ; Returns the name of what the shar file is going to unpack.
1822 (defun gnus-uu-find-name-in-shar ()
1823 (let ((oldpoint (point))
1824 res)
1825 (goto-char 1)
1826 (if (re-search-forward gnus-uu-shar-name-marker nil t)
1827 (setq res (buffer-substring (match-beginning 1) (match-end 1))))
1828 (goto-char oldpoint)
1829 res))
1832 ; Returns the article number of the given subject.
1834 (defun gnus-uu-article-number (subject)
1835 (let (end)
1836 (string-match "[0-9]+[^0-9]" subject 1)
1837 (setq end (match-end 0))
1838 (string-to-int
1839 (substring subject (string-match "[0-9]" subject 1) end))))
1842 ; UUdecodes everything in the buffer and returns the name of the
1843 ; resulting file.
1845 (defun gnus-uu-decode (directory)
1846 (let ((command (concat "cd " directory " ; uudecode"))
1847 file-name)
1848 (save-excursion
1849 (message "Uudecoding...")
1850 (set-buffer (get-buffer-create gnus-uu-result-buffer))
1851 (setq file-name (concat gnus-uu-tmp-dir gnus-uu-file-name))
1852 (gnus-uu-add-file file-name)
1853 (call-process-region 1 (point-max) "sh" nil t nil "-c" command)
1854 file-name)))
1857 ; `gnus-uu-choose-action' chooses what action to perform given the name
1858 ; and `gnus-uu-file-action-list'. Returns either nil if no action is
1859 ; found, or the name of the command to run if such a rule is found.
1861 (defun gnus-uu-choose-action (file-name file-action-list)
1862 (let ((action-list (copy-sequence file-action-list))
1863 rule action)
1864 (while (not (or (eq action-list ()) action))
1865 (setq rule (car action-list))
1866 (setq action-list (cdr action-list))
1867 (if (string-match (car rule) file-name)
1868 (setq action (car (cdr rule)))))
1869 action))
1872 ; Moves the file from the tmp directory to where the user wants it.
1874 (defun gnus-uu-save-file (from-file-name &optional default-dir ignore-existing)
1875 (let (dir file-name command)
1876 (string-match "/[^/]*$" from-file-name)
1877 (setq file-name (substring from-file-name (1+ (match-beginning 0))))
1878 (if default-dir
1879 (setq dir default-dir)
1880 (setq dir (gnus-uu-read-directory "Where do you want the file? ")))
1881 (if (and (not ignore-existing) (file-exists-p (concat dir file-name)))
1882 (progn
1883 (message (concat "There already is a file called " file-name))
1884 (sit-for 2)
1885 (setq file-name
1886 (read-file-name "Give a new name: " dir (concat dir file-name)
1887 nil file-name)))
1888 (setq file-name (concat dir file-name)))
1889 (rename-file from-file-name file-name t)))
1892 (defun gnus-uu-read-directory (prompt &optional default)
1893 (let (dir ok create)
1894 (while (not ok)
1895 (setq ok t)
1896 (setq dir (if default default
1897 (read-file-name prompt gnus-uu-current-save-dir
1898 gnus-uu-current-save-dir)))
1899 (while (string-match "/$" dir)
1900 (setq dir (substring dir 0 (match-beginning 0))))
1901 (if (file-exists-p dir)
1902 (if (not (file-directory-p dir))
1903 (progn
1904 (setq ok nil)
1905 (message "%s is a file" dir)
1906 (sit-for 2)))
1907 (setq create ?o)
1908 (while (not (or (= create ?y) (= create ?n)))
1909 (message "%s: No such directory. Do you want to create it? (y/n)"
1910 dir)
1911 (setq create (read-char)))
1912 (if (= create ?y) (make-directory dir))))
1913 (setq gnus-uu-current-save-dir (concat dir "/"))))
1916 ; Unpacks an archive and views all the files in it. Returns t if
1917 ; viewing one or more files is successful.
1919 (defun gnus-uu-treat-archive (file-name)
1920 (let ((arc-dir (make-temp-name
1921 (concat gnus-uu-tmp-dir "gnusuu")))
1922 action command files file did-view short-file-name)
1923 (setq action (gnus-uu-choose-action
1924 file-name (append gnus-uu-user-archive-rules
1925 (if gnus-uu-ignore-default-archive-rules
1927 gnus-uu-default-archive-rules))))
1928 (if (not action)
1929 (progn (message (format "No unpackers for the file %s" file-name))
1930 (sit-for 2))
1931 (string-match "/[^/]*$" file-name)
1932 (setq short-file-name (substring file-name (1+ (match-beginning 0))))
1933 (setq command (format "%s %s %s ; cd %s ; %s "
1934 (if (or (string= action "uncompress")
1935 (string= action "gunzip"))
1936 "cp"
1937 "mv")
1938 (gnus-uu-command "" file-name) arc-dir
1939 arc-dir
1940 (gnus-uu-command action short-file-name)))
1942 (make-directory arc-dir)
1943 (gnus-uu-add-file arc-dir)
1945 (save-excursion
1946 (set-buffer (get-buffer-create gnus-uu-output-buffer-name))
1947 (erase-buffer))
1949 (message (format "Unpacking with %s..." action))
1950 (sleep-for 1)
1952 (if (= 0 (call-process "sh" nil
1953 (get-buffer-create gnus-uu-output-buffer-name)
1954 nil "-c" command))
1955 (message "")
1956 (message "Error during unpacking of archive")
1957 (sit-for 0) (sleep-for 2)
1958 (setq gnus-uu-error-during-unarching t))
1960 (if (not (or (string= action "uncompress")
1961 (string= action "gunzip")))
1962 (call-process "sh" nil (get-buffer gnus-uu-output-buffer-name)
1963 nil "-c" (format "mv %s %s"
1964 (gnus-uu-command "" (concat arc-dir "/" short-file-name))
1965 gnus-uu-tmp-dir)))
1966 (gnus-uu-add-file (concat gnus-uu-tmp-dir short-file-name))
1968 (setq did-view
1969 (or (gnus-uu-show-directory arc-dir gnus-uu-use-interactive-view)
1970 did-view))
1972 (if (and (not gnus-uu-use-interactive-view)
1973 (file-directory-p arc-dir))
1974 (delete-directory arc-dir)))
1976 did-view))
1979 ; Tries to view all the files in the given directory. Returns t if
1980 ; viewing one or more files is successful.
1982 (defun gnus-uu-show-directory (dir &optional dont-delete-files)
1983 (let (files file did-view)
1984 (setq files (directory-files dir t))
1985 (setq gnus-uu-generated-file-list
1986 (append files gnus-uu-generated-file-list))
1987 (while files
1988 (setq file (car files))
1989 (setq files (cdr files))
1990 (if (and (not (string-match "/\\.$" file))
1991 (not (string-match "/\\.\\.$" file)))
1992 (progn
1993 (set-file-modes file 448)
1994 (if (file-directory-p file)
1995 (setq did-view (or (gnus-uu-show-directory file
1996 dont-delete-files)
1997 did-view))
1998 (setq did-view (or (gnus-uu-view-file file t) did-view))
1999 (if (and (not dont-delete-files) (file-exists-p file))
2000 (delete-file file))))))
2001 (if (not dont-delete-files) (delete-directory dir))
2002 did-view))
2005 ;; Manual marking
2007 (defun gnus-uu-enter-mark-in-list ()
2008 (let (article beg)
2009 (beginning-of-line)
2010 (setq beg (point))
2011 (end-of-line)
2012 (setq article (gnus-uu-article-number
2013 (buffer-substring beg (point))))
2014 (message (format "Adding article %d to list" article))
2015 (setq gnus-uu-marked-article-list
2016 (cons article gnus-uu-marked-article-list))))
2018 (defun gnus-uu-mark-article ()
2019 "Marks the current article to be decoded later."
2020 (interactive)
2021 (gnus-uu-enter-mark-in-list)
2022 (gnus-summary-mark-as-read nil ?#)
2023 (gnus-summary-next-subject 1 nil))
2025 (defun gnus-uu-unmark-article ()
2026 "Unmarks the current article."
2027 (interactive)
2028 (let ((in (copy-sequence gnus-uu-marked-article-list))
2029 out article beg found
2030 (old-point (point)))
2031 (beginning-of-line)
2032 (setq beg (point))
2033 (end-of-line)
2034 (setq article (gnus-uu-article-number (buffer-substring beg (point))))
2035 (message (format "Removing article %d" article))
2036 (while in
2037 (if (not (= (car in) article))
2038 (setq out (cons (car in) out))
2039 (setq found t)
2040 (message (format "Removing article %d" article)))
2041 (setq in (cdr in)))
2042 (if (not found) (message "Not a marked article."))
2043 (setq gnus-uu-marked-article-list (reverse out))
2044 (gnus-summary-mark-as-unread nil t)
2045 (gnus-summary-next-subject 1 nil)))
2048 (defun gnus-uu-unmark-all-articles ()
2049 "Removes the mark from all articles marked for decoding."
2050 (interactive)
2051 (let ((articles (copy-sequence gnus-uu-marked-article-list)))
2052 (while articles
2053 (gnus-summary-goto-subject (car articles))
2054 (gnus-summary-mark-as-unread nil t)
2055 (setq articles (cdr articles)))
2056 (setq gnus-uu-marked-article-list ())))
2058 (defun gnus-uu-mark-by-regexp ()
2059 "Asks for a regular expression and marks all articles that match."
2060 (interactive)
2061 (let (exp)
2062 (setq exp (read-from-minibuffer "Enter regular expression: "))
2063 (setq gnus-uu-marked-article-list
2064 (reverse (gnus-uu-get-list-of-articles exp t)))
2065 (message "")))
2068 ;; Various
2070 (defun gnus-uu-check-correct-stripped-uucode (start end)
2071 (let (found beg length short)
2072 (if (not gnus-uu-correct-stripped-uucode)
2074 (goto-char start)
2076 (if (re-search-forward " \\|`" end t)
2077 (progn
2078 (goto-char start)
2079 (while (not (eobp))
2080 (progn
2081 (if (looking-at "\n") (replace-match ""))
2082 (forward-line 1))))
2084 (while (not (eobp))
2085 (if (looking-at (concat gnus-uu-begin-string "\\|"
2086 gnus-uu-end-string))
2088 (if (not found)
2089 (progn
2090 (beginning-of-line)
2091 (setq beg (point))
2092 (end-of-line)
2093 (setq length (- (point) beg))))
2094 (setq found t)
2095 (beginning-of-line)
2096 (setq beg (point))
2097 (end-of-line)
2098 (if (not (= length (- (point) beg)))
2099 (insert (make-string (- length (- (point) beg)) ? ))))
2100 (forward-line 1))))))
2102 (defun gnus-uu-initialize ()
2103 (setq gnus-uu-error-during-unarching nil)
2104 (if (not gnus-uu-use-interactive-view)
2106 (save-excursion
2107 (setq gnus-uu-interactive-file-list nil)
2108 (set-buffer (get-buffer-create gnus-uu-interactive-buffer-name))
2109 (erase-buffer)
2110 (gnus-uu-mode)
2111 (insert
2112 "# Press return to execute a command.
2113 # Press `C-c C-c' to exit interactive view.
2115 "))))
2118 ; Kills the temporary uu buffers, kills any processes, etc.
2120 (defun gnus-uu-clean-up ()
2121 (let (buf pst)
2122 (setq gnus-uu-do-sloppy-uudecode nil)
2123 (and gnus-uu-uudecode-process
2124 (setq pst (process-status (or gnus-uu-uudecode-process "nevair")))
2125 (if (or (eq pst 'stop) (eq pst 'run))
2126 (delete-process gnus-uu-uudecode-process)))
2127 (and (not gnus-uu-asynchronous)
2128 (setq buf (get-buffer gnus-uu-output-buffer-name))
2129 (kill-buffer buf))
2130 (and (setq buf (get-buffer gnus-uu-result-buffer))
2131 (kill-buffer buf))))
2134 ; `gnus-uu-check-for-generated-files' deletes any generated files that
2135 ; hasn't been deleted, if, for instance, the user terminated decoding
2136 ; with `C-g'.
2138 (defun gnus-uu-check-for-generated-files ()
2139 (let (file)
2140 (while gnus-uu-generated-file-list
2141 (setq file (car gnus-uu-generated-file-list))
2142 (setq gnus-uu-generated-file-list (cdr gnus-uu-generated-file-list))
2143 (if (not (string-match "/\\.[\\.]?$" file))
2144 (progn
2145 (if (file-directory-p file)
2146 (delete-directory file)
2147 (if (file-exists-p file)
2148 (delete-file file))))))))
2151 ; Add a file to be checked (and deleted if it still exists upon
2152 ; exiting the newsgroup) to a list
2153 (defun gnus-uu-add-file (file)
2154 (setq gnus-uu-generated-file-list
2155 (cons file gnus-uu-generated-file-list)))
2158 ; Go to the next unread subject. If there is no further unread
2159 ; subjects, go to the last subject in the buffer.
2160 (defun gnus-uu-summary-next-subject ()
2161 (if (not (gnus-summary-search-forward t))
2162 (progn
2163 (goto-char 1)
2164 (sit-for 0)
2165 (goto-char (point-max))
2166 (forward-line -1)
2167 (beginning-of-line)
2168 (search-forward ":" nil t)))
2169 (sit-for 0)
2170 (gnus-summary-recenter))
2172 ; Inputs an action and a file and returns a full command, putting
2173 ; ticks round the file name and escaping any ticks in the file name.
2174 (defun gnus-uu-command (action file)
2175 (let ((ofile ""))
2176 (while (string-match "`\\|\"\\|\\$\\|\\\\" file)
2177 (progn
2178 (setq ofile
2179 (concat ofile (substring file 0 (match-beginning 0)) "\\"
2180 (substring file (match-beginning 0) (match-end 0))))
2181 (setq file (substring file (1+ (match-beginning 0))))))
2182 (setq ofile (concat "\"" ofile file "\""))
2183 (if (string-match "%s" action)
2184 (format action ofile)
2185 (concat action " " ofile))))
2188 ;; Initializing
2190 (add-hook 'gnus-exit-group-hook
2191 '(lambda ()
2192 (gnus-uu-clean-up)
2193 (setq gnus-uu-marked-article-list nil)
2194 (gnus-uu-check-for-generated-files)))
2197 ;; Interactive exec mode
2199 (defvar gnus-uu-output-window nil)
2200 (defvar gnus-uu-mode-hook nil)
2201 (defvar gnus-uu-mode-map nil)
2203 (defun gnus-uu-do-interactive ()
2204 (let (int-buffer out-buf)
2205 (set-buffer
2206 (setq int-buffer (get-buffer gnus-uu-interactive-buffer-name)))
2207 (switch-to-buffer-other-window int-buffer)
2208 (pop-to-buffer int-buffer)
2209 (setq gnus-uu-output-window
2210 (split-window nil (- (window-height) gnus-uu-output-window-height)))
2211 (set-window-buffer gnus-uu-output-window
2212 (setq out-buf
2213 (get-buffer-create gnus-uu-output-buffer-name)))
2214 (save-excursion (set-buffer out-buf) (erase-buffer))
2215 (goto-char 1)
2216 (forward-line 3)
2217 (run-hooks 'gnus-uu-mode-hook)))
2220 (defun gnus-uu-enter-interactive-file (action file)
2221 (let (command)
2222 (save-excursion
2223 (setq gnus-uu-interactive-file-list
2224 (cons file gnus-uu-interactive-file-list))
2225 (set-buffer (get-buffer gnus-uu-interactive-buffer-name))
2226 (setq command (gnus-uu-command action file))
2227 (insert (format "%s\n" command)))))
2230 (defun gnus-uu-interactive-execute ()
2231 "Executes the command on the current line in interactive mode."
2232 (interactive)
2233 (let (beg out-buf command)
2234 (beginning-of-line)
2235 (setq beg (point))
2236 (end-of-line)
2237 (setq command (buffer-substring beg (point)))
2238 (setq out-buf (get-buffer-create gnus-uu-output-buffer-name))
2239 (save-excursion
2240 (set-buffer out-buf)
2241 (erase-buffer)
2242 (insert (format "$ %s \n\n" command)))
2243 (message "Executing...")
2244 (if gnus-uu-asynchronous
2245 (start-process "gnus-uu-view" out-buf "sh" "-c" command)
2246 (call-process "sh" nil out-buf nil "-c" command)
2247 (message ""))
2248 (forward-line 1)
2249 (beginning-of-line)))
2252 (defun gnus-uu-interactive-end ()
2253 "This function exits interactive view mode and returns to summary mode."
2254 (interactive)
2255 (let (buf)
2256 (delete-window gnus-uu-output-window)
2257 (gnus-uu-clean-up)
2258 (if (not gnus-uu-asynchronous) (gnus-uu-check-for-generated-files))
2259 (setq buf (get-buffer gnus-uu-interactive-buffer-name))
2260 (if gnus-article-buffer (switch-to-buffer gnus-article-buffer))
2261 (if buf (kill-buffer buf))
2262 (pop-to-buffer gnus-summary-buffer)))
2265 (if gnus-uu-mode-map
2267 (setq gnus-uu-mode-map (make-sparse-keymap))
2268 (define-key gnus-uu-mode-map "\C-c\C-x" 'gnus-uu-interactive-execute)
2269 (define-key gnus-uu-mode-map "\C-c\C-v" 'gnus-uu-interactive-execute)
2270 (define-key gnus-uu-mode-map "\C-m" 'gnus-uu-interactive-execute)
2271 (define-key gnus-uu-mode-map "\C-c\C-c" 'gnus-uu-interactive-end)
2272 (define-key gnus-uu-mode-map "\C-cs"
2273 'gnus-uu-interactive-save-current-file)
2274 (define-key gnus-uu-mode-map "\C-c\C-s"
2275 'gnus-uu-interactive-save-current-file-silent)
2276 (define-key gnus-uu-mode-map "\C-c\C-w" 'gnus-uu-interactive-save-all-files)
2277 (define-key gnus-uu-mode-map "\C-c\C-o" 'gnus-uu-interactive-save-original-file))
2280 (defun gnus-uu-interactive-save-original-file ()
2281 "Saves the file from whence the file on the current line came from."
2282 (interactive)
2283 (let (file)
2284 (if (file-exists-p
2285 (setq file (concat gnus-uu-tmp-dir
2286 (or gnus-uu-file-name gnus-uu-shar-file-name))))
2287 (gnus-uu-save-file file)
2288 (message "Already saved."))))
2291 (defun gnus-uu-interactive-save-current-file-silent ()
2292 "Saves the file referred to on the current line in the current directory."
2293 (interactive)
2294 (gnus-uu-interactive-save-current-file t))
2296 (defun gnus-uu-interactive-save-current-file (&optional dont-ask silent)
2297 "Saves the file referred to on the current line."
2298 (interactive)
2299 (let (files beg line file)
2300 (setq files (copy-sequence gnus-uu-interactive-file-list))
2301 (beginning-of-line)
2302 (setq beg (point))
2303 (end-of-line)
2304 (setq line (buffer-substring beg (point)))
2305 (while (and files
2306 (not (string-match
2307 (concat "" (regexp-quote (setq file (car files))) "")
2308 line)))
2309 (setq files (cdr files)))
2310 (beginning-of-line)
2311 (forward-line 1)
2312 (if (not files)
2313 (if (not silent)
2314 (progn (message "Could not find file") (sit-for 2)))
2315 (gnus-uu-save-file file (if dont-ask gnus-uu-current-save-dir nil) silent)
2316 (delete-region beg (point)))))
2319 (defun gnus-uu-interactive-save-all-files ()
2320 "Saves all files referred to in the interactive buffer."
2321 (interactive)
2322 (let (dir)
2323 (goto-char 1)
2324 (setq dir (gnus-uu-read-directory "Where do you want the files? "))
2325 (while (not (eobp))
2326 (gnus-uu-interactive-save-current-file t t))))
2328 (defun gnus-uu-mode ()
2329 "Major mode for editing view commands in gnus-uu.
2331 Commands:
2332 \\<gnus-uu-mode-map>Return, C-c C-v, C-c C-x Execute the current command
2333 \\[gnus-uu-interactive-end] End interactive mode
2334 \\[gnus-uu-interactive-save-current-file] Save the current file
2335 \\[gnus-uu-interactive-save-current-file-silent] Save the current file without asking
2336 where to put it
2337 \\[gnus-uu-interactive-save-all-files] Save all files
2338 \\[gnus-uu-interactive-save-original-file] Save the original file: If the files
2339 originated in an archive, the archive
2340 file is saved.
2342 (interactive)
2343 (kill-all-local-variables)
2344 (use-local-map gnus-uu-mode-map)
2345 (setq mode-name "gnus-uu")
2346 (setq major-mode 'gnus-uu-mode)
2349 (define-key gnus-uu-mode-map "\C-c\C-x" 'gnus-uu-interactive-execute)
2350 (define-key gnus-uu-mode-map "\C-c\C-v" 'gnus-uu-interactive-execute)
2351 (define-key gnus-uu-mode-map "\C-m" 'gnus-uu-interactive-execute)
2352 (define-key gnus-uu-mode-map "\C-c\C-c" 'gnus-uu-interactive-end)
2353 (define-key gnus-uu-mode-map "\C-cs"
2354 'gnus-uu-interactive-save-current-file)
2355 (define-key gnus-uu-mode-map "\C-c\C-s"
2356 'gnus-uu-interactive-save-current-file-silent)
2357 (define-key gnus-uu-mode-map "\C-c\C-a" 'gnus-uu-interactive-save-all-files)
2358 (define-key gnus-uu-mode-map "\C-c\C-o" 'gnus-uu-interactive-save-original-file)
2360 (provide 'gnus-uu)
2362 ;; gnus-uu.el ends here