This commit was generated by cvs2svn to compensate for changes in r3071,
[elisp/gnus.git-] / lisp / gnus-uu.el
index 1caef47..19929f3 100644 (file)
@@ -1,7 +1,7 @@
 ;;; gnus-uu.el --- extract (uu)encoded files in Gnus
 ;; Copyright (C) 1985,86,87,93,94,95,96,97,98 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
 
@@ -54,8 +54,8 @@
 ;; Default viewing action rules
 
 (defcustom 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")
+  '(("\\.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 -")
@@ -513,12 +513,12 @@ didn't work, and overwrite existing files.  Otherwise, ask each time."
   (interactive "P")
   (let ((gnus-uu-save-in-digest t)
        (file (make-temp-name (nnheader-concat gnus-uu-tmp-dir "forward")))
-       buf subject from newsgroups)
+       buf subject from)
     (gnus-setup-message 'forward
       (setq gnus-uu-digest-from-subject nil)
       (gnus-uu-decode-save n file)
-      (setq buf (switch-to-buffer (get-buffer-create " *gnus-uu-forward*")))
-      (gnus-add-current-to-buffer-list)
+      (setq buf (switch-to-buffer
+                (gnus-get-buffer-create " *gnus-uu-forward*")))
       (erase-buffer)
       (insert-file file)
       (let ((fs gnus-uu-digest-from-subject))
@@ -638,7 +638,7 @@ didn't work, and overwrite existing files.  Otherwise, ask each time."
   "Invert the list of process-marked articles."
   (interactive)
   (let ((data gnus-newsgroup-data)
-       d number)
+       number)
     (save-excursion
       (while data
        (if (memq (setq number (gnus-data-number (pop data)))
@@ -648,7 +648,7 @@ didn't work, and overwrite existing files.  Otherwise, ask each time."
   (gnus-summary-position-point))
 
 (defun gnus-uu-mark-over (&optional score)
-  "Mark all articles with a score over SCORE (the prefix.)"
+  "Mark all articles with a score over SCORE (the prefix)."
   (interactive "P")
   (let ((score (gnus-score-default score))
        (data gnus-newsgroup-data))
@@ -828,16 +828,15 @@ didn't work, and overwrite existing files.  Otherwise, ask each time."
                  (mail-header-subject header))
            gnus-uu-digest-from-subject))
     (let ((name (file-name-nondirectory gnus-uu-saved-article-name))
-         (delim (concat "^" (make-string 30 ?-) "$"))
          beg subj headers headline sorthead body end-string state)
       (if (or (eq in-state 'first)
              (eq in-state 'first-and-last))
          (progn
            (setq state (list 'begin))
-           (save-excursion (set-buffer (get-buffer-create "*gnus-uu-body*"))
+           (save-excursion (set-buffer (gnus-get-buffer-create "*gnus-uu-body*"))
                            (erase-buffer))
            (save-excursion
-             (set-buffer (get-buffer-create "*gnus-uu-pre*"))
+             (set-buffer (gnus-get-buffer-create "*gnus-uu-pre*"))
              (erase-buffer)
              (insert (format
                       "Date: %s\nFrom: %s\nSubject: %s Digest\n\nTopics:\n"
@@ -970,7 +969,7 @@ didn't work, and overwrite existing files.  Otherwise, ask each time."
        (if (not (re-search-forward gnus-uu-postscript-end-string nil t))
            (setq state (list 'wrong-type))
          (setq end-char (point))
-         (set-buffer (get-buffer-create gnus-uu-output-buffer-name))
+         (set-buffer (gnus-get-buffer-create gnus-uu-output-buffer-name))
          (insert-buffer-substring process-buffer start-char end-char)
          (setq file-name (concat gnus-uu-work-dir
                                  (cdr gnus-article-current) ".ps"))
@@ -1020,45 +1019,36 @@ didn't work, and overwrite existing files.  Otherwise, ask each time."
 
 (defun gnus-uu-reginize-string (string)
   ;; Takes a string and puts a \ in front of every special character;
-  ;; 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
-  ;; my experience, should get most postings of a series.
-  (let ((count 2)
-       (vernum "v[0-9]+[a-z][0-9]+:")
-       beg)
-    (save-excursion
-      (set-buffer (get-buffer-create gnus-uu-output-buffer-name))
-      (buffer-disable-undo (current-buffer))
-      (erase-buffer)
-      (insert (regexp-quote string))
-      (setq beg 1)
+  ;; replaces the last thing that looks like "2/3" with "[0-9]+/3"
+  ;; or, if it can't find something like that, tries "2 of 3", then
+  ;; finally just replaces the next to last number with "[0-9]+".
+  (save-excursion
+    (set-buffer (gnus-get-buffer-create gnus-uu-output-buffer-name))
+    (buffer-disable-undo (current-buffer))
+    (erase-buffer)
+    (insert (regexp-quote string))
 
-      (setq case-fold-search nil)
-      (goto-char (point-min))
-      (when (looking-at vernum)
-       (replace-match vernum t t)
-       (setq beg (length vernum)))
+    (setq case-fold-search nil)
 
-      (goto-char beg)
-      (if (re-search-forward "[ \t]*[0-9]+/[0-9]+" nil t)
-         (replace-match " [0-9]+/[0-9]+")
+    (end-of-line)
+    (if (re-search-backward "\\([^0-9]\\)[0-9]+/\\([0-9]+\\)" nil t)
+       (replace-match "\\1[0-9]+/\\2")
 
-       (goto-char beg)
-       (if (re-search-forward "[0-9]+[ \t]*of[ \t]*[0-9]+" nil t)
-           (replace-match "[0-9]+ of [0-9]+")
+      (end-of-line)
+      (if (re-search-backward "\\([^0-9]\\)[0-9]+[ \t]*of[ \t]*\\([0-9]+\\)"
+                             nil t)
+         (replace-match "\\1[0-9]+ of \\2")
 
-         (end-of-line)
-          (if (re-search-backward "\\([^0-9]\\)[0-9]+\\([^0-9]+\\)[0-9]+"
-                                  nil t)
-              (replace-match "\\1[0-9]+\\2[0-9]+" t nil nil nil))))
+       (end-of-line)
+       (if (re-search-backward "\\([^0-9]\\)[0-9]+\\([^0-9]+\\)[0-9]+"
+                               nil t)
+           (replace-match "\\1[0-9]+\\2[0-9]+" t nil nil nil))))
 
-      (goto-char beg)
-      (while (re-search-forward "[ \t]+" nil t)
-       (replace-match "[ \t]*" t t))
+    (goto-char 1)
+    (while (re-search-forward "[ \t]+" nil t)
+      (replace-match "[ \t]+" t t))
 
-      (buffer-substring 1 (point-max)))))
+    (buffer-substring 1 (point-max))))
 
 (defun gnus-uu-get-list-of-articles (n)
   ;; If N is non-nil, the article numbers of the N next articles
@@ -1098,8 +1088,7 @@ didn't work, and overwrite existing files.  Otherwise, ask each time."
                     (gnus-uu-reginize-string (gnus-summary-article-subject))))
        list-of-subjects)
     (save-excursion
-      (if (not subject)
-         ()
+      (when subject
        ;; Collect all subjects matching subject.
        (let ((case-fold-search t)
              (data gnus-newsgroup-data)
@@ -1134,7 +1123,7 @@ didn't work, and overwrite existing files.  Otherwise, ask each time."
   (let ((out-list string-list)
        string)
     (save-excursion
-      (set-buffer (get-buffer-create gnus-uu-output-buffer-name))
+      (set-buffer (gnus-get-buffer-create gnus-uu-output-buffer-name))
       (buffer-disable-undo (current-buffer))
       (while string-list
        (erase-buffer)
@@ -1221,119 +1210,121 @@ didn't work, and overwrite existing files.  Otherwise, ask each time."
                    (not (memq 'end process-state))))
 
       (setq article (pop articles))
-      (push article article-series)
-
-      (unless articles
-       (if (eq state 'first)
-           (setq state 'first-and-last)
-         (setq state 'last)))
+      (when (vectorp (gnus-summary-article-header article))
+       (push article article-series)
 
-      (let ((part (gnus-uu-part-number article)))
-       (gnus-message 6 "Getting article %d%s..."
-                     article (if (string= part "") "" (concat ", " part))))
-      (gnus-summary-display-article article)
+       (unless articles
+         (if (eq state 'first)
+             (setq state 'first-and-last)
+           (setq state 'last)))
 
-      ;; Push the article to the processing function.
-      (save-excursion
-       (set-buffer gnus-original-article-buffer)
-       (let ((buffer-read-only nil))
-         (save-excursion
-           (set-buffer gnus-summary-buffer)
-           (setq process-state
-                 (funcall process-function
-                          gnus-original-article-buffer state)))))
-
-      (gnus-summary-remove-process-mark article)
-
-      ;; If this is the beginning of a decoded file, we push it
-      ;; on to a list.
-      (when (or (memq 'begin process-state)
-               (and (or (eq state 'first)
-                        (eq state 'first-and-last))
-                    (memq 'ok process-state)))
-       (when has-been-begin
-         ;; 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)
-                    (not gnus-uu-be-dangerous)
-                    (or (eq gnus-uu-be-dangerous t)
-                        (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)))
-       (setq has-been-begin t))
-
-      ;; Check whether we have decoded one complete file.
-      (when (memq 'end process-state)
-       (setq article-series nil)
-       (setq has-been-begin nil)
-       (if (stringp result-file)
-           (setq files (list result-file))
-         (setq files result-file))
-       (setq result-file (car files))
-       (while files
-         (push (list (cons 'name (pop files))
-                     (cons 'article article))
-               result-files))
-       ;; Allow user-defined functions to be run on this file.
-       (when gnus-uu-grabbed-file-functions
-         (let ((funcs gnus-uu-grabbed-file-functions))
-           (unless (listp funcs)
-             (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)))
-
-      ;; If this is the last article to be decoded, and
-      ;; we still haven't reached the end, then we delete
-      ;; the partially decoded file.
-      (and (or (eq state 'last) (eq state 'first-and-last))
-          (not (memq 'end process-state))
-          result-file
-          (file-exists-p result-file)
-          (not gnus-uu-be-dangerous)
-          (or (eq gnus-uu-be-dangerous t)
-              (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
-      (when (and (or (memq 'wrong-type process-state)
-                    (memq 'error process-state))
-                gnus-uu-unmark-articles-not-decoded)
-       (gnus-summary-tick-article article t))
-
-      ;; Set the new series state.
-      (if (and (not has-been-begin)
-              (not sloppy)
-              (or (memq 'end process-state)
-                  (memq 'middle process-state)))
-         (progn
-           (setq process-state (list 'error))
-           (gnus-message 2 "No begin part at the beginning")
-           (sleep-for 2))
-       (setq state 'middle)))
+       (let ((part (gnus-uu-part-number article)))
+         (gnus-message 6 "Getting article %d%s..."
+                       article (if (string= part "") "" (concat ", " part))))
+       (gnus-summary-display-article article)
 
-    ;; When there are no result-files, then something must be wrong.
-    (if result-files
-       (message "")
-      (cond
-       ((not has-been-begin)
-       (gnus-message 2 "Wrong type file"))
-       ((memq 'error process-state)
-       (gnus-message 2 "An error occurred during decoding"))
-       ((not (or (memq 'ok process-state)
-                (memq 'end process-state)))
-       (gnus-message 2 "End of articles reached before end of file")))
-      ;; Make unsuccessfully decoded articles unread.
-      (when gnus-uu-unmark-articles-not-decoded
-       (while article-series
-         (gnus-summary-tick-article (pop article-series) t))))
+       ;; Push the article to the processing function.
+       (save-excursion
+         (set-buffer gnus-original-article-buffer)
+         (let ((buffer-read-only nil))
+           (save-excursion
+             (set-buffer gnus-summary-buffer)
+             (setq process-state
+                   (funcall process-function
+                            gnus-original-article-buffer state)))))
+
+       (gnus-summary-remove-process-mark article)
+
+       ;; If this is the beginning of a decoded file, we push it
+       ;; on to a list.
+       (when (or (memq 'begin process-state)
+                 (and (or (eq state 'first)
+                          (eq state 'first-and-last))
+                      (memq 'ok process-state)))
+         (when has-been-begin
+           ;; 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)
+                      (not gnus-uu-be-dangerous)
+                      (or (eq gnus-uu-be-dangerous t)
+                          (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)))
+         (setq has-been-begin t))
+
+       ;; Check whether we have decoded one complete file.
+       (when (memq 'end process-state)
+         (setq article-series nil)
+         (setq has-been-begin nil)
+         (if (stringp result-file)
+             (setq files (list result-file))
+           (setq files result-file))
+         (setq result-file (car files))
+         (while files
+           (push (list (cons 'name (pop files))
+                       (cons 'article article))
+                 result-files))
+         ;; Allow user-defined functions to be run on this file.
+         (when gnus-uu-grabbed-file-functions
+           (let ((funcs gnus-uu-grabbed-file-functions))
+             (unless (listp funcs)
+               (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)))
+
+       ;; If this is the last article to be decoded, and
+       ;; we still haven't reached the end, then we delete
+       ;; the partially decoded file.
+       (and (or (eq state 'last) (eq state 'first-and-last))
+            (not (memq 'end process-state))
+            result-file
+            (file-exists-p result-file)
+            (not gnus-uu-be-dangerous)
+            (or (eq gnus-uu-be-dangerous t)
+                (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
+       (when (and (or (memq 'wrong-type process-state)
+                      (memq 'error process-state))
+                  gnus-uu-unmark-articles-not-decoded)
+         (gnus-summary-tick-article article t))
+
+       ;; Set the new series state.
+       (if (and (not has-been-begin)
+                (not sloppy)
+                (or (memq 'end process-state)
+                    (memq 'middle process-state)))
+           (progn
+             (setq process-state (list 'error))
+             (gnus-message 2 "No begin part at the beginning")
+             (sleep-for 2))
+         (setq state 'middle)))
+
+      ;; When there are no result-files, then something must be wrong.
+      (if result-files
+         (message "")
+       (cond
+        ((not has-been-begin)
+         (gnus-message 2 "Wrong type file"))
+        ((memq 'error process-state)
+         (gnus-message 2 "An error occurred during decoding"))
+        ((not (or (memq 'ok process-state)
+                  (memq 'end process-state)))
+         (gnus-message 2 "End of articles reached before end of file")))
+       ;; Make unsuccessfully decoded articles unread.
+       (when gnus-uu-unmark-articles-not-decoded
+         (while article-series
+           (gnus-summary-tick-article (pop article-series) t)))))
 
     result-files))
 
@@ -1357,11 +1348,18 @@ didn't work, and overwrite existing files.  Otherwise, ask each time."
 
 (defun gnus-uu-part-number (article)
   (let* ((header (gnus-summary-article-header article))
-        (subject (and header (mail-header-subject header))))
-    (if (and subject
-            (string-match "[0-9]+ */[0-9]+\\|[0-9]+ * of *[0-9]+" subject))
-       (match-string 0 subject)
-      "")))
+        (subject (and header (mail-header-subject header)))
+        (part nil))
+    (if subject
+       (while (string-match "[0-9]+/[0-9]+\\|[0-9]+[ \t]+of[ \t]+[0-9]+"
+                            subject)
+         (setq part (match-string 0 subject))
+         (setq subject (substring subject (match-end 0)))))
+    (or part
+       (while (string-match "\\([0-9]+\\)[^0-9]+\\([0-9]+\\)" subject)
+         (setq part (match-string 0 subject))
+         (setq subject (substring subject (match-end 0)))))
+    (or part "")))
 
 (defun gnus-uu-uudecode-sentinel (process event)
   (delete-process (get-process process)))
@@ -1419,7 +1417,7 @@ didn't work, and overwrite existing files.  Otherwise, ask each time."
                  (setq gnus-uu-uudecode-process
                        (start-process
                         "*uudecode*"
-                        (get-buffer-create gnus-uu-output-buffer-name)
+                        (gnus-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))))
@@ -1485,7 +1483,7 @@ didn't work, and overwrite existing files.  Otherwise, ask each time."
        (setq start-char (point))
        (call-process-region
         start-char (point-max) shell-file-name nil
-        (get-buffer-create gnus-uu-output-buffer-name) nil
+        (gnus-get-buffer-create gnus-uu-output-buffer-name) nil
         shell-command-switch
         (concat "cd " gnus-uu-work-dir " "
                 gnus-shell-command-separator  " sh"))))
@@ -1548,13 +1546,13 @@ didn't work, and overwrite existing files.  Otherwise, ask each time."
     (setq command (format "cd %s ; %s" dir (gnus-uu-command action file-path)))
 
     (save-excursion
-      (set-buffer (get-buffer-create gnus-uu-output-buffer-name))
+      (set-buffer (gnus-get-buffer-create gnus-uu-output-buffer-name))
       (erase-buffer))
 
     (gnus-message 5 "Unpacking: %s..." (gnus-uu-command action file-path))
 
     (if (= 0 (call-process shell-file-name nil
-                          (get-buffer-create gnus-uu-output-buffer-name)
+                          (gnus-get-buffer-create gnus-uu-output-buffer-name)
                           nil shell-command-switch command))
        (message "")
       (gnus-message 2 "Error during unpacking of archive")
@@ -1901,8 +1899,10 @@ If no file has been included, the user will be asked for a file."
     (goto-char (point-max))
     (insert (format "\n%s\n" gnus-uu-post-binary-separator))
 
+    ;; #### Unix-specific?
     (when (string-match "^~/" file-path)
       (setq file-path (concat "$HOME" (substring file-path 1))))
+    ;; #### Unix-specific?
     (if (string-match "/[^/]*$" file-path)
        (setq file-name (substring file-path (1+ (match-beginning 0))))
       (setq file-name file-path))
@@ -1910,7 +1910,7 @@ If no file has been included, the user will be asked for a file."
     (unwind-protect
        (if (save-excursion
              (set-buffer (setq uubuf
-                               (get-buffer-create uuencode-buffer-name)))
+                               (gnus-get-buffer-create uuencode-buffer-name)))
              (erase-buffer)
              (funcall gnus-uu-post-encode-method file-path file-name))
            (insert-buffer-substring uubuf)
@@ -1925,7 +1925,7 @@ If no file has been included, the user will be asked for a file."
        (top-string "[ cut here %s (%s %d/%d) %s gnus-uu ]")
        (separator (concat mail-header-separator "\n\n"))
        uubuf length parts header i end beg
-       beg-line minlen buf post-buf whole-len beg-binary end-binary)
+       beg-line minlen post-buf whole-len beg-binary end-binary)
 
     (setq post-buf (current-buffer))
 
@@ -1943,7 +1943,7 @@ If no file has been included, the user will be asked for a file."
     (setq end-binary (point-max))
 
     (save-excursion
-      (set-buffer (setq uubuf (get-buffer-create encoded-buffer-name)))
+      (set-buffer (setq uubuf (gnus-get-buffer-create encoded-buffer-name)))
       (erase-buffer)
       (insert-buffer-substring post-buf beg-binary end-binary)
       (goto-char (point-min))
@@ -1975,7 +1975,7 @@ If no file has been included, the user will be asked for a file."
       (setq i 1)
       (setq beg 1)
       (while (not (> i parts))
-       (set-buffer (get-buffer-create send-buffer-name))
+       (set-buffer (gnus-get-buffer-create send-buffer-name))
        (erase-buffer)
        (insert header)
        (when (and threaded gnus-uu-post-message-id)