;;; gnus-uu.el --- extract (uu)encoded files in Gnus
-;; Copyright (C) 1985,86,87,93,94,95,96 Free Software Foundation, Inc.
+;; Copyright (C) 1985, 1986, 1987, 1993, 1994, 1995, 1996, 1997, 1998, 2000,
+;; 2001, 2002 Free Software Foundation, Inc.
-;; Author: Lars Magne Ingebrigtsen <larsi@ifi.uio.no>
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
;; Created: 2 Oct 1993
;; Keyword: news
;;; Commentary:
-;;; Code:
+;;; Code:
-(require 'gnus-load)
+(eval-when-compile (require 'cl))
+
+(require 'gnus)
(require 'gnus-art)
(require 'message)
(require 'gnus-msg)
+(require 'mm-decode)
+
+(defgroup gnus-extract nil
+ "Extracting encoded files."
+ :prefix "gnus-uu-"
+ :group 'gnus)
+
+(defgroup gnus-extract-view nil
+ "Viewwing extracted files."
+ :group 'gnus-extract)
+
+(defgroup gnus-extract-archive nil
+ "Extracting encoded archives."
+ :group 'gnus-extract)
+
+(defgroup gnus-extract-post nil
+ "Extracting encoded archives."
+ :prefix "gnus-uu-post"
+ :group 'gnus-extract)
;; Default viewing action rules
-(defvar gnus-uu-default-view-rules
- '(("\\.te?xt$\\|\\.doc$\\|read.*me\\|\\.c?$\\|\\.h$\\|\\.bat$\\|\\.asm$\\|makefile" "cat %s | sed s/\r//g")
- ("\\.pas$" "cat %s | sed s/\r//g")
+(defcustom gnus-uu-default-view-rules
+ '(("\\.te?xt$\\|\\.doc$\\|read.*me\\|\\.c?$\\|\\.h$\\|\\.bat$\\|\\.asm$\\|makefile" "cat %s | sed 's/\r$//'")
+ ("\\.pas$" "cat %s | sed 's/\r$//'")
("\\.[1-9]$" "groff -mandoc -Tascii %s | sed s/\b.//g")
- ("\\.\\(jpe?g\\|gif\\|tiff?\\|p[pgb]m\\|xwd\\|xbm\\|pcx\\)$" "xv")
- ("\\.tga$" "tgatoppm %s | xv -")
- ("\\.\\(wav\\|aiff\\|hcom\\|u[blw]\\|s[bfw]\\|voc\\|smp\\)$"
+ ("\\.\\(jpe?g\\|gif\\|tiff?\\|p[pgb]m\\|xwd\\|xbm\\|pcx\\)$" "display")
+ ("\\.tga$" "tgatoppm %s | ee -")
+ ("\\.\\(wav\\|aiff\\|hcom\\|u[blw]\\|s[bfw]\\|voc\\|smp\\)$"
"sox -v .5 %s -t .au -u - > /dev/audio")
("\\.au$" "cat %s > /dev/audio")
("\\.midi?$" "playmidi -f")
("\\.html$" "xmosaic")
("\\.mpe?g$" "mpeg_play")
("\\.\\(flc\\|fli\\|rle\\|iff\\|pfx\\|avi\\|sme\\|rpza\\|dl\\|qt\\|rsrc\\|mov\\)$" "xanim")
- ("\\.\\(tar\\|arj\\|zip\\|zoo\\|arc\\|gz\\|Z\\|lzh\\|ar\\|lha\\)$"
+ ("\\.\\(tar\\|arj\\|zip\\|zoo\\|arc\\|gz\\|Z\\|lzh\\|ar\\|lha\\)$"
"gnus-uu-archive"))
- "*Default actions to be taken when the user asks to view a file.
+ "*Default actions to be taken when the user asks to view a file.
To change the behaviour, you can either edit this variable or set
`gnus-uu-user-view-rules' to something useful.
(setq gnus-uu-user-view-rules '((\"jpg$\\\\|gif$\" \"xli\")))
-Both these variables are lists of lists with two string elements. The
-first string is a regular expression. If the file name matches this
+Both these variables are lists of lists with two string elements. The
+first string is a regular expression. If the file name matches this
regular expression, the command in the second string is executed with
the file as an argument.
If the command string contains \"%s\", the file name will be inserted
-at that point in the command string. If there's no \"%s\" in the
+at that point in the command string. If there's no \"%s\" in the
command string, the file name will be appended to the command string
before executing.
There are several user variables to tailor the behaviour of gnus-uu to
-your needs. First we have `gnus-uu-user-view-rules', which is the
+your needs. First we have `gnus-uu-user-view-rules', which is the
variable gnus-uu first consults when trying to decide how to view a
-file. If this variable contains no matches, gnus-uu examines the
-default rule variable provided in this package. If gnus-uu finds no
+file. If this variable contains no matches, gnus-uu examines the
+default rule variable provided in this package. If gnus-uu finds no
match here, it uses `gnus-uu-user-view-rules-end' to try to make a
-match.")
-
-(defvar gnus-uu-user-view-rules nil
- "*Variable detailing what actions are to be taken to view a file.
-See the documentation on the `gnus-uu-default-view-rules' variable for
-details.")
-
-(defvar gnus-uu-user-view-rules-end
+match."
+ :group 'gnus-extract-view
+ :type '(repeat (group regexp (string :tag "Command"))))
+
+(defcustom gnus-uu-user-view-rules nil
+ "What actions are to be taken to view a file.
+See the documentation on the `gnus-uu-default-view-rules' variable for
+details."
+ :group 'gnus-extract-view
+ :type '(repeat (group regexp (string :tag "Command"))))
+
+(defcustom gnus-uu-user-view-rules-end
'(("" "file"))
- "*Variable saying what actions are to be taken if no rule matched the file name.
-See the documentation on the `gnus-uu-default-view-rules' variable for
-details.")
+ "*What actions are to be taken if no rule matched the file name.
+See the documentation on the `gnus-uu-default-view-rules' variable for
+details."
+ :group 'gnus-extract-view
+ :type '(repeat (group regexp (string :tag "Command"))))
;; Default unpacking commands
-(defvar gnus-uu-default-archive-rules
+(defcustom gnus-uu-default-archive-rules
'(("\\.tar$" "tar xf")
("\\.zip$" "unzip -o")
("\\.ar$" "ar x")
("\\.\\(lzh\\|lha\\)$" "lha x")
("\\.Z$" "uncompress")
("\\.gz$" "gunzip")
- ("\\.arc$" "arc -x")))
+ ("\\.arc$" "arc -x"))
+ "*See `gnus-uu-user-archive-rules'."
+ :group 'gnus-extract-archive
+ :type '(repeat (group regexp (string :tag "Command"))))
-(defvar gnus-uu-destructive-archivers
+(defvar gnus-uu-destructive-archivers
(list "uncompress" "gunzip"))
-(defvar gnus-uu-user-archive-rules nil
- "*A list that can be set to override the default archive unpacking commands.
+(defcustom gnus-uu-user-archive-rules nil
+ "A list that can be set to override the default archive unpacking commands.
To use, for instance, 'untar' to unpack tar files and 'zip -x' to
unpack zip files, say the following:
- (setq gnus-uu-user-archive-rules
+ (setq gnus-uu-user-archive-rules
'((\"\\\\.tar$\" \"untar\")
- (\"\\\\.zip$\" \"zip -x\")))")
+ (\"\\\\.zip$\" \"zip -x\")))"
+ :group 'gnus-extract-archive
+ :type '(repeat (group regexp (string :tag "Command"))))
-(defvar gnus-uu-ignore-files-by-name nil
+(defcustom gnus-uu-ignore-files-by-name nil
"*A regular expression saying what files should not be viewed based on name.
-If, for instance, you want gnus-uu to ignore all .au and .wav files,
+If, for instance, you want gnus-uu to ignore all .au and .wav files,
you could say something like
(setq gnus-uu-ignore-files-by-name \"\\\\.au$\\\\|\\\\.wav$\")
Note that this variable can be used in conjunction with the
-`gnus-uu-ignore-files-by-type' variable.")
+`gnus-uu-ignore-files-by-type' variable."
+ :group 'gnus-extract
+ :type '(choice (const :tag "off" nil)
+ (regexp :format "%v")))
-(defvar gnus-uu-ignore-files-by-type nil
+(defcustom gnus-uu-ignore-files-by-type nil
"*A regular expression saying what files that shouldn't be viewed, based on MIME file type.
-If, for instance, you want gnus-uu to ignore all audio files and all mpegs,
+If, for instance, you want gnus-uu to ignore all audio files and all mpegs,
you could say something like
(setq gnus-uu-ignore-files-by-type \"audio/\\\\|video/mpeg\")
Note that this variable can be used in conjunction with the
-`gnus-uu-ignore-files-by-name' variable.")
+`gnus-uu-ignore-files-by-name' variable."
+ :group 'gnus-extract
+ :type '(choice (const :tag "off" nil)
+ (regexp :format "%v")))
;; Pseudo-MIME support
("\\.rsrc$" "video/rsrc")
("\\..*$" "unknown/unknown")))
-;; Various variables users may set
+;; Various variables users may set
-(defvar gnus-uu-tmp-dir "/tmp/"
+(defcustom gnus-uu-tmp-dir
+ (cond ((fboundp 'temp-directory) (temp-directory))
+ ((boundp 'temporary-file-directory) temporary-file-directory)
+ ("/tmp/"))
"*Variable saying where gnus-uu is to do its work.
-Default is \"/tmp/\".")
+Default is \"/tmp/\"."
+ :group 'gnus-extract
+ :type 'directory)
-(defvar gnus-uu-do-not-unpack-archives nil
- "*Non-nil means that gnus-uu won't peek inside archives looking for files to display.
-Default is nil.")
+(defcustom gnus-uu-do-not-unpack-archives nil
+ "*Non-nil means that gnus-uu won't peek inside archives looking for files to display.
+Default is nil."
+ :group 'gnus-extract-archive
+ :type 'boolean)
-(defvar gnus-uu-ignore-default-view-rules nil
+(defcustom gnus-uu-ignore-default-view-rules nil
"*Non-nil means that gnus-uu will ignore the default viewing rules.
-Only the user viewing rules will be consulted. Default is nil.")
+Only the user viewing rules will be consulted. Default is nil."
+ :group 'gnus-extract-view
+ :type 'boolean)
-(defvar gnus-uu-grabbed-file-functions nil
- "*Functions run on each file after successful decoding.
+(defcustom gnus-uu-grabbed-file-functions nil
+ "Functions run on each file after successful decoding.
They will be called with the name of the file as the argument.
-Likely functions you can use in this list are `gnus-uu-grab-view'
-and `gnus-uu-grab-move'.")
-
-(defvar gnus-uu-ignore-default-archive-rules nil
- "*Non-nil means that gnus-uu will ignore the default archive unpacking commands.
-Only the user unpacking commands will be consulted. Default is nil.")
-
-(defvar gnus-uu-kill-carriage-return t
+Likely functions you can use in this list are `gnus-uu-grab-view'
+and `gnus-uu-grab-move'."
+ :group 'gnus-extract
+ :options '(gnus-uu-grab-view gnus-uu-grab-move)
+ :type 'hook)
+
+(defcustom gnus-uu-ignore-default-archive-rules nil
+ "*Non-nil means that gnus-uu will ignore the default archive unpacking commands.
+Only the user unpacking commands will be consulted. Default is nil."
+ :group 'gnus-extract-archive
+ :type 'boolean)
+
+(defcustom gnus-uu-kill-carriage-return t
"*Non-nil means that gnus-uu will strip all carriage returns from articles.
-Default is t.")
+Default is t."
+ :group 'gnus-extract
+ :type 'boolean)
-(defvar gnus-uu-view-with-metamail nil
+(defcustom gnus-uu-view-with-metamail nil
"*Non-nil means that files will be viewed with metamail.
The gnus-uu viewing functions will be ignored and gnus-uu will try
-to guess at a content-type based on file name suffixes. Default
-it nil.")
-
-(defvar gnus-uu-unmark-articles-not-decoded nil
- "*Non-nil means that gnus-uu will mark articles that were unsuccessfully decoded as unread.
-Default is nil.")
-
-(defvar gnus-uu-correct-stripped-uucode nil
- "*Non-nil means that gnus-uu will *try* to fix uuencoded files that have had trailing spaces deleted.
-Default is nil.")
-
-(defvar gnus-uu-save-in-digest nil
+to guess at a content-type based on file name suffixes. Default
+it nil."
+ :group 'gnus-extract
+ :type 'boolean)
+
+(defcustom gnus-uu-unmark-articles-not-decoded nil
+ "*Non-nil means that gnus-uu will mark articles that were unsuccessfully decoded as unread.
+Default is nil."
+ :group 'gnus-extract
+ :type 'boolean)
+
+(defcustom gnus-uu-correct-stripped-uucode nil
+ "*Non-nil means that gnus-uu will *try* to fix uuencoded files that have had trailing spaces deleted.
+Default is nil."
+ :group 'gnus-extract
+ :type 'boolean)
+
+(defcustom gnus-uu-save-in-digest nil
"*Non-nil means that gnus-uu, when asked to save without decoding, will save in digests.
-If this variable is nil, gnus-uu will just save everything in a
-file without any embellishments. The digesting almost conforms to RFC1153 -
-no easy way to specify any meaningful volume and issue numbers were found,
-so I simply dropped them.")
-
-(defvar gnus-uu-digest-headers
+If this variable is nil, gnus-uu will just save everything in a
+file without any embellishments. The digesting almost conforms to RFC1153 -
+no easy way to specify any meaningful volume and issue numbers were found,
+so I simply dropped them."
+ :group 'gnus-extract
+ :type 'boolean)
+
+(defcustom gnus-uu-pre-uudecode-hook nil
+ "Hook run before sending a message to uudecode."
+ :group 'gnus-extract
+ :type 'hook)
+
+(defcustom gnus-uu-digest-headers
'("^Date:" "^From:" "^To:" "^Cc:" "^Subject:" "^Message-ID:" "^Keywords:"
- "^Summary:" "^References:")
+ "^Summary:" "^References:" "^Content-Type:" "^Content-Transfer-Encoding:"
+ "^MIME-Version:" "^Content-Disposition:" "^Content-Description:"
+ "^Content-ID:")
"*List of regexps to match headers included in digested messages.
-The headers will be included in the sequence they are matched.")
-
-(defvar gnus-uu-save-separate-articles nil
- "*Non-nil means that gnus-uu will save articles in separate files.")
+The headers will be included in the sequence they are matched. If nil
+include all headers."
+ :group 'gnus-extract
+ :type '(repeat regexp))
+
+(defcustom gnus-uu-save-separate-articles nil
+ "*Non-nil means that gnus-uu will save articles in separate files."
+ :group 'gnus-extract
+ :type 'boolean)
+
+(defcustom gnus-uu-be-dangerous 'ask
+ "*Specifies what to do if unusual situations arise during decoding.
+If nil, be as conservative as possible. If t, ignore things that
+didn't work, and overwrite existing files. Otherwise, ask each time."
+ :group 'gnus-extract
+ :type '(choice (const :tag "conservative" nil)
+ (const :tag "ask" ask)
+ (const :tag "liberal" t)))
;; Internal variables
(defvar gnus-uu-saved-article-name nil)
-(defconst