*** empty log message ***
[gnus] / lisp / gnus-uu.el
index bd23e9e..a0adc3a 100644 (file)
 
 ;;; Code: 
 
-(require 'gnus)
+(require 'gnus-load)
+(require 'gnus-art)
+(require 'message)
 (require 'gnus-msg)
-(eval-when-compile (require 'cl))
 
 ;; Default viewing action rules
 
@@ -61,21 +62,21 @@ following in your .emacs file:
 
   (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.")
 
@@ -187,7 +188,7 @@ Default is nil.")
 
 (defvar 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.")
 
 (defvar gnus-uu-grabbed-file-functions nil
   "*Functions run on each file after successful decoding.
@@ -197,7 +198,7 @@ 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.")
+Only the user unpacking commands will be consulted.  Default is nil.")
 
 (defvar gnus-uu-kill-carriage-return t
   "*Non-nil means that gnus-uu will strip all carriage returns from articles.
@@ -206,7 +207,7 @@ Default is t.")
 (defvar 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
+to guess at a content-type based on file name suffixes.  Default
 it nil.")
 
 (defvar gnus-uu-unmark-articles-not-decoded nil
@@ -220,7 +221,7 @@ Default is nil.")
 (defvar 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 -
+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.")
 
@@ -269,35 +270,37 @@ The headers will be included in the sequence they are matched.")
 
 ;; Keymaps
 
-(gnus-define-keys 
- (gnus-uu-mark-map "P" gnus-summary-mark-map)
- "p" gnus-summary-mark-as-processable
- "u" gnus-summary-unmark-as-processable
- "U" gnus-summary-unmark-all-processable
- "v" gnus-uu-mark-over
- "s" gnus-uu-mark-series
- "r" gnus-uu-mark-region
- "R" gnus-uu-mark-by-regexp
- "t" gnus-uu-mark-thread
- "T" gnus-uu-unmark-thread
- "a" gnus-uu-mark-all
- "b" gnus-uu-mark-buffer
- "S" gnus-uu-mark-sparse)
-
-(gnus-define-keys 
- (gnus-uu-extract-map "X" gnus-summary-mode-map)
- ;;"x" gnus-uu-extract-any
- ;;"m" gnus-uu-extract-mime
- "u" gnus-uu-decode-uu
- "U" gnus-uu-decode-uu-and-save
- "s" gnus-uu-decode-unshar
- "S" gnus-uu-decode-unshar-and-save
- "o" gnus-uu-decode-save
- "O" gnus-uu-decode-save
- "b" gnus-uu-decode-binhex
- "B" gnus-uu-decode-binhex
- "p" gnus-uu-decode-postscript
- "P" gnus-uu-decode-postscript-and-save)
+(gnus-define-keys (gnus-uu-mark-map "P" gnus-summary-mark-map)
+  "p" gnus-summary-mark-as-processable
+  "u" gnus-summary-unmark-as-processable
+  "U" gnus-summary-unmark-all-processable
+  "v" gnus-uu-mark-over
+  "s" gnus-uu-mark-series
+  "r" gnus-uu-mark-region
+  "R" gnus-uu-mark-by-regexp
+  "t" gnus-uu-mark-thread
+  "T" gnus-uu-unmark-thread
+  "a" gnus-uu-mark-all
+  "b" gnus-uu-mark-buffer
+  "S" gnus-uu-mark-sparse
+  "k" gnus-summary-kill-process-mark
+  "y" gnus-summary-yank-process-mark
+  "w" gnus-summary-save-process-mark
+  "i" gnus-uu-invert-processable)
+
+(gnus-define-keys (gnus-uu-extract-map "X" gnus-summary-mode-map)
+  ;;"x" gnus-uu-extract-any
+  ;;"m" gnus-uu-extract-mime
+  "u" gnus-uu-decode-uu
+  "U" gnus-uu-decode-uu-and-save
+  "s" gnus-uu-decode-unshar
+  "S" gnus-uu-decode-unshar-and-save
+  "o" gnus-uu-decode-save
+  "O" gnus-uu-decode-save
+  "b" gnus-uu-decode-binhex
+  "B" gnus-uu-decode-binhex
+  "p" gnus-uu-decode-postscript
+  "P" gnus-uu-decode-postscript-and-save)
 
 (gnus-define-keys 
  (gnus-uu-extract-view-map "v" gnus-uu-extract-map)
@@ -432,7 +435,7 @@ The headers will be included in the sequence they are matched.")
   (interactive "P")
   (let ((gnus-uu-save-in-digest t)
        (file (make-temp-name (concat gnus-uu-tmp-dir "forward")))
-       buf subject from)
+       buf subject from newsgroups)
     (setq gnus-uu-digest-from-subject nil)
     (gnus-uu-decode-save n file)
     (setq buf (switch-to-buffer (get-buffer-create " *gnus-uu-forward*")))
@@ -441,32 +444,34 @@ The headers will be included in the sequence they are matched.")
     (delete-other-windows)
     (insert-file file)
     (let ((fs gnus-uu-digest-from-subject))
-      (if (not fs)
-         ()
+      (when fs
        (setq from (caar fs)
              subject (gnus-simplify-subject-fuzzy (cdar fs))
              fs (cdr fs))
        (while (and fs (or from subject))
-         (and from
-              (or (string= from (caar fs))
-                  (setq from nil)))
-         (and subject
-              (or (string= (gnus-simplify-subject-fuzzy (cdar fs))
-                           subject)
-                  (setq subject nil)))
+         (when from
+           (or (string= from (caar fs))
+               (setq from nil)))
+         (when subject
+           (or (string= (gnus-simplify-subject-fuzzy (cdar fs))
+                        subject)
+               (setq subject nil)))
          (setq fs (cdr fs))))
-      (or subject (setq subject "Digested Articles"))
-      (or from (setq from "Various")))
+      (unless subject
+       (setq subject "Digested Articles"))
+      (unless from 
+       (setq from
+             (if (gnus-news-group-p gnus-newsgroup-name)
+                 gnus-newsgroup-name
+               "Various"))))
     (goto-char (point-min))
-    (and (re-search-forward "^Subject: ")
-        (progn
-          (delete-region (point) (gnus-point-at-eol))
-          (insert subject)))
+    (when (re-search-forward "^Subject: ")
+      (delete-region (point) (gnus-point-at-eol))
+      (insert subject))
     (goto-char (point-min))
-    (and (re-search-forward "^From: ")
-        (progn
-          (delete-region (point) (gnus-point-at-eol))
-          (insert from)))
+    (when (re-search-forward "^From: ")
+      (delete-region (point) (gnus-point-at-eol))
+      (insert from))
     (message-forward post)
     (delete-file file)
     (kill-buffer buf)
@@ -556,6 +561,18 @@ The headers will be included in the sequence they are matched.")
                (> (gnus-summary-thread-level) level))))
   (gnus-summary-position-point))
 
+(defun gnus-uu-invert-processable ()
+  "Invert the list of process-marked articles."
+  (let ((data gnus-newsgroup-data)
+       d number)
+    (save-excursion
+      (while data
+       (if (memq (setq number (gnus-data-number (pop data)))
+                 gnus-newsgroup-processable)
+           (gnus-summary-remove-process-mark number)
+         (gnus-summary-set-process-mark number)))))
+  (gnus-summary-position-point))
+
 (defun gnus-uu-mark-over (&optional score)
   "Mark all articles with a score over SCORE (the prefix.)"
   (interactive "P")
@@ -563,7 +580,7 @@ The headers will be included in the sequence they are matched.")
        (data gnus-newsgroup-data))
     (save-excursion
       (while data
-       (when (> (or (cdr (assq (gnus-data-number (caar data))
+       (when (> (or (cdr (assq (gnus-data-number (car data))
                                gnus-newsgroup-scored))
                     gnus-summary-default-score 0)
                 score)
@@ -664,7 +681,7 @@ The headers will be included in the sequence they are matched.")
       (and scan (setq files (gnus-uu-scan-directory gnus-uu-work-dir))))
     (and save (gnus-uu-save-files files save))
     (if (eq gnus-uu-do-not-unpack-archives nil)
-      (setq files (gnus-uu-unpack-files files)))
+       (setq files (gnus-uu-unpack-files files)))
     (setq files (nreverse (gnus-uu-get-actions files)))
     (or not-insert (not gnus-insert-pseudo-articles)
        (gnus-summary-insert-pseudos files save))))
@@ -694,8 +711,7 @@ The headers will be included in the sequence they are matched.")
        (string-match reg file)
        (setq fromdir (substring file (match-end 0)))
        (if (file-directory-p file)
-           (unless (file-exists-p (concat dir fromdir))
-             (make-directory (concat dir fromdir) t))
+           (gnus-make-directory (concat dir fromdir))
          (setq to-file (concat dir fromdir))
          (when (or (not (file-exists-p to-file))
                    (gnus-y-or-n-p (format "%s exists; overwrite? " to-file)))
@@ -929,7 +945,7 @@ The headers will be included in the sequence they are matched.")
   ;; ignores any leading "version numbers" thingies that they use in
   ;; the comp.binaries groups, and either replaces anything that looks
   ;; like "2/3" with "[0-9]+/[0-9]+" or, if it can't find something
-  ;; like that, replaces the last two numbers with "[0-9]+". This, in
+  ;; like that, replaces the last two numbers with "[0-9]+".  This, in
   ;; my experience, should get most postings of a series.
   (let ((count 2)
        (vernum "v[0-9]+[a-z][0-9]+:")
@@ -1002,8 +1018,8 @@ The headers will be included in the sequence they are matched.")
 (defun gnus-uu-find-articles-matching 
   (&optional subject only-unread do-not-translate)
   ;; Finds all articles that matches the regexp SUBJECT.  If it is
-  ;; nil, the current article name will be used. If ONLY-UNREAD is
-  ;; non-nil, only unread articles are chosen. If DO-NOT-TRANSLATE is
+  ;; nil, the current article name will be used.  If ONLY-UNREAD is
+  ;; non-nil, only unread articles are chosen.  If DO-NOT-TRANSLATE is
   ;; non-nil, article names are not equalized before sorting.
   (let ((subject (or subject 
                     (gnus-uu-reginize-string (gnus-summary-article-subject))))
@@ -1040,9 +1056,9 @@ The headers will be included in the sequence they are matched.")
 (defun gnus-uu-expand-numbers (string-list &optional translate)
   ;; Takes a list of strings and "expands" all numbers in all the
   ;; strings.  That is, this function makes all numbers equal length by
-  ;; prepending lots of zeroes before each number. This is to ease later
+  ;; prepending lots of zeroes before each number.  This is to ease later
   ;; sorting to find out what sequence the articles are supposed to be
-  ;; decoded in. Returns the list of expanded strings.
+  ;; decoded in.  Returns the list of expanded strings.
   (let ((out-list string-list)
        string)
     (save-excursion
@@ -1078,21 +1094,21 @@ The headers will be included in the sequence they are matched.")
 ;; to apply to each article.
 ;;
 ;; The function to be called should take two parameters.  The first
-;; parameter is the article buffer. The function should leave the
-;; result, if any, in this buffer. Most treatment functions will just
+;; parameter is the article buffer.  The function should leave the
+;; result, if any, in this buffer.  Most treatment functions will just
 ;; generate files...
 ;;
 ;; The second parameter is the state of the list of articles, and can
 ;; have four values: `first', `middle', `last' and `first-and-last'.
 ;;
-;; The function should return a list. The list may contain the
+;; The function should return a list.  The list may contain the
 ;; following symbols:
 ;; `error' if an error occurred
 ;; `begin' if the beginning of an encoded file has been received
 ;;   If the list returned contains a `begin', the first element of
 ;;   the list *must* be a string with the file name of the decoded
 ;;   file.
-;; `end' if the the end of an encoded file has been received
+;; `end' if the end of an encoded file has been received
 ;; `middle' if the article was a body part of an encoded file
 ;; `wrong-type' if the article was not a part of an encoded file
 ;; `ok', which can be used everything is ok
@@ -1122,6 +1138,7 @@ The headers will be included in the sequence they are matched.")
 (defun gnus-uu-grab-articles (articles process-function 
                                       &optional sloppy limit no-errors)
   (let ((state 'first) 
+       (gnus-asynchronous nil)
        has-been-begin article result-file result-files process-state
        gnus-summary-display-article-function
        gnus-article-display-hook gnus-article-prepare-hook
@@ -1167,7 +1184,10 @@ The headers will be included in the sequence they are matched.")
            ;; If there is a `result-file' here, that means that the
            ;; file was unsuccessfully decoded, so we delete it.
            (when (and result-file 
-                      (file-exists-p result-file)) 
+                      (file-exists-p result-file)
+                      (gnus-y-or-n-p
+                       (format "Delete unsuccessfully decoded file %s"
+                               result-file)))
              (delete-file result-file)))
        (when (memq 'begin process-state)
          (setq result-file (car process-state)))
@@ -1192,6 +1212,7 @@ The headers will be included in the sequence they are matched.")
              (setq funcs (list funcs)))
            (while funcs
              (funcall (pop funcs) result-file))))
+       (setq result-file nil)
        ;; Check whether we have decoded enough articles.
        (and limit (= (length result-files) limit)
             (setq articles nil)))
@@ -1203,6 +1224,7 @@ The headers will be included in the sequence they are matched.")
           (not (memq 'end process-state))
           result-file 
           (file-exists-p result-file)
+          (gnus-y-or-n-p (format "Delete incomplete file %s? " result-file))
           (delete-file result-file))
 
       ;; If this was a file of the wrong sort, then 
@@ -1314,12 +1336,18 @@ The headers will be included in the sequence they are matched.")
            (gnus-uu-unmark-list-of-grabbed t))
 
          ;; Start a new uudecoding process.
-         (setq gnus-uu-uudecode-process
-               (start-process 
-                "*uudecode*" 
-                (get-buffer-create gnus-uu-output-buffer-name)
-                shell-file-name shell-command-switch
-                (format "cd %s ; uudecode" gnus-uu-work-dir)))
+         (let ((cdir default-directory))
+           (unwind-protect
+               (progn
+                 (cd gnus-uu-work-dir)
+                 (setq gnus-uu-uudecode-process
+                       (start-process 
+                        "*uudecode*" 
+                        (get-buffer-create gnus-uu-output-buffer-name)
+                        shell-file-name shell-command-switch
+                        (format "cd %s %s uudecode" gnus-uu-work-dir
+                                gnus-shell-command-separator))))
+             (cd cdir)))
          (set-process-sentinel 
           gnus-uu-uudecode-process 'gnus-uu-uudecode-sentinel)
          (setq state (list 'begin))
@@ -1382,7 +1410,9 @@ The headers will be included in the sequence they are matched.")
        (call-process-region 
         start-char (point-max) shell-file-name nil 
         (get-buffer-create gnus-uu-output-buffer-name) nil 
-        shell-command-switch (concat "cd " gnus-uu-work-dir " ; sh"))))
+        shell-command-switch 
+        (concat "cd " gnus-uu-work-dir " " 
+                gnus-shell-command-separator  " sh"))))
     state))
 
 ;; Returns the name of what the shar file is going to unpack.
@@ -1421,7 +1451,7 @@ The headers will be included in the sequence they are matched.")
     action))
 
 (defun gnus-uu-treat-archive (file-path)
-  ;; Unpacks an archive. Returns t if unpacking is successful.
+  ;; Unpacks an archive.  Returns t if unpacking is successful.
   (let ((did-unpack t)
        action command dir)
     (setq action (gnus-uu-choose-action 
@@ -1574,8 +1604,7 @@ The headers will be included in the sequence they are matched.")
 
       (setq gnus-uu-work-dir 
            (make-temp-name (concat gnus-uu-tmp-dir "gnus")))
-      (if (not (file-directory-p gnus-uu-work-dir)) 
-         (gnus-make-directory gnus-uu-work-dir))
+      (gnus-make-directory gnus-uu-work-dir)
       (set-file-modes gnus-uu-work-dir 448)
       (setq gnus-uu-work-dir (file-name-as-directory gnus-uu-work-dir))
       (setq gnus-uu-tmp-alist (cons (cons gnus-newsgroup-name gnus-uu-work-dir)
@@ -1584,7 +1613,7 @@ The headers will be included in the sequence they are matched.")
 
 ;; Kills the temporary uu buffers, kills any processes, etc.
 (defun gnus-uu-clean-up ()
-  (let (buf pst)
+  (let (buf)
     (and gnus-uu-uudecode-process
         (memq (process-status (or gnus-uu-uudecode-process "nevair"))
               '(stop run))
@@ -1637,7 +1666,7 @@ The headers will be included in the sequence they are matched.")
 ;;;
 
 ;; Any function that is to be used as and encoding method will take two
-;; parameters: PATH-NAME and FILE-NAME. (E.g. "/home/gaga/spiral.jpg"
+;; parameters: PATH-NAME and FILE-NAME.  (E.g. "/home/gaga/spiral.jpg"
 ;; and "spiral.jpg", respectively.) The function should return nil if
 ;; the encoding wasn't successful.
 (defvar gnus-uu-post-encode-method 'gnus-uu-post-encode-uuencode
@@ -1661,15 +1690,15 @@ post the entire file.")
 (defvar gnus-uu-post-threaded nil
   "Non-nil means that gnus-uu will post the encoded file in a thread.
 This may not be smart, as no other decoder I have seen are able to
-follow threads when collecting uuencoded articles. (Well, I have seen
+follow threads when collecting uuencoded articles.  (Well, I have seen
 one package that does that - gnus-uu, but somehow, I don't think that 
 counts...) Default is nil.")
 
 (defvar gnus-uu-post-separate-description t
   "Non-nil means that the description will be posted in a separate article.
-The first article will typically be numbered (0/x). If this variable
+The first article will typically be numbered (0/x).  If this variable
 is nil, the description the user enters will be included at the 
-beginning of the first article, which will be numbered (1/x). Default 
+beginning of the first article, which will be numbered (1/x).  Default 
 is t.")
 
 (defvar gnus-uu-post-binary-separator "--binary follows this line--")
@@ -1790,7 +1819,7 @@ If no file has been included, the user will be asked for a file."
        (set-window-configuration gnus-uu-winconf-post-news)))
       
 ;; Asks for a file to encode, encodes it and inserts the result in
-;; the current buffer. Returns the file name the user gave.
+;; the current buffer.  Returns the file name the user gave.
 (defun gnus-uu-post-insert-binary ()
   (let ((uuencode-buffer-name "*uuencode buffer*")
        file-path uubuf file-name)