;;; gnus-uu.el --- extract (uu)encoded files in Gnus
-;; Copyright (C) 1985,86,87,93,94,95,96,97 Free Software Foundation, Inc.
+;; Copyright (C) 1985, 1986, 1987, 1993, 1994, 1995, 1996, 1997, 1998, 2000,
+;; 2001, 2002, 2003, 2004 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
;; 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 -")
+ ("\\.\\(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")
("\\.\\(flc\\|fli\\|rle\\|iff\\|pfx\\|avi\\|sme\\|rpza\\|dl\\|qt\\|rsrc\\|mov\\)$" "xanim")
("\\.\\(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.
(defcustom gnus-uu-user-view-rules-end
'(("" "file"))
- "What actions are to be taken if no rule matched the file name.
+ "*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
("\\.Z$" "uncompress")
("\\.gz$" "gunzip")
("\\.arc$" "arc -x"))
- "See `gnus-uu-user-archive-rules'."
+ "*See `gnus-uu-user-archive-rules'."
:group 'gnus-extract-archive
:type '(repeat (group regexp (string :tag "Command"))))
;; Various variables users may set
-(defcustom 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/\"."
:group 'gnus-extract
(defcustom gnus-uu-digest-headers
'("^Date:" "^From:" "^To:" "^Cc:" "^Subject:" "^Message-ID:" "^Keywords:"
- "^Summary:" "^References:")
- "List of regexps to match headers included in digested messages.
-The headers will be included in the sequence they are matched."
+ "^Summary:" "^References:" "^Content-Type:" "^Content-Transfer-Encoding:"
+ "^MIME-Version:" "^Content-Disposition:" "^Content-Description:"
+ "^Content-ID:" "^User-Agent:" "^X-Face:")
+ "*List of regexps to match headers included in digested messages.
+The headers will be included in the sequence they are matched. If nil
+include all headers."
:group 'gnus-extract
:type '(repeat regexp))
(defvar gnus-uu-saved-article-name nil)
-(defvar gnus-uu-begin-string "^begin[ \t]+[0-7][0-7][0-7][ \t]+\\(.*\\)$")
+(defvar gnus-uu-begin-string "^begin[ \t]+0?[0-7][0-7][0-7][ \t]+\\(.*\\)$")
(defvar gnus-uu-end-string "^end[ \t]*$")
(defvar gnus-uu-body-line "^M")
(defvar gnus-uu-shar-begin-string "^#! */bin/sh")
(defvar gnus-uu-shar-file-name nil)
-(defvar gnus-uu-shar-name-marker "begin [0-7][0-7][0-7][ \t]+\\(\\(\\w\\|\\.\\)*\\b\\)")
+(defvar gnus-uu-shar-name-marker
+ "begin 0?[0-7][0-7][0-7][ \t]+\\(\\(\\w\\|[.\\:]\\)*\\b\\)")
(defvar gnus-uu-postscript-begin-string "^%!PS-")
(defvar gnus-uu-postscript-end-string "^%%EOF$")
(defvar gnus-uu-default-dir gnus-article-save-directory)
(defvar gnus-uu-digest-from-subject nil)
-
-;; 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
- "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)
- "u" gnus-uu-decode-uu-view
- "U" gnus-uu-decode-uu-and-save-view
- "s" gnus-uu-decode-unshar-view
- "S" gnus-uu-decode-unshar-and-save-view
- "o" gnus-uu-decode-save-view
- "O" gnus-uu-decode-save-view
- "b" gnus-uu-decode-binhex-view
- "B" gnus-uu-decode-binhex-view
- "p" gnus-uu-decode-postscript-view
- "P" gnus-uu-decode-postscript-and-save-view)
-
+(defvar gnus-uu-digest-buffer nil)
;; Commands.
gnus-uu-default-dir
gnus-uu-default-dir))))
(setq gnus-uu-binhex-article-name
- (make-temp-name (concat gnus-uu-work-dir "binhex")))
+ (mm-make-temp-file (expand-file-name "binhex" gnus-uu-work-dir)))
(gnus-uu-decode-with-method 'gnus-uu-binhex-article n dir))
(defun gnus-uu-decode-uu-view (&optional n)
(read-file-name "Unbinhex, view and save in dir: "
gnus-uu-default-dir gnus-uu-default-dir)))
(setq gnus-uu-binhex-article-name
- (make-temp-name (concat gnus-uu-work-dir "binhex")))
+ (mm-make-temp-file (expand-file-name "binhex" gnus-uu-work-dir)))
(let ((gnus-view-pseudos (or gnus-view-pseudos 'automatic)))
(gnus-uu-decode-binhex n file)))
"Digests and forwards all articles in this series."
(interactive "P")
(let ((gnus-uu-save-in-digest t)
- (file (make-temp-name (nnheader-concat gnus-uu-tmp-dir "forward")))
- buf subject from newsgroups)
- (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)
- (erase-buffer)
- (insert-file file)
- (let ((fs gnus-uu-digest-from-subject))
- (when fs
- (setq from (caar fs)
- subject (gnus-simplify-subject-fuzzy (cdar fs))
- fs (cdr fs))
- (while (and fs (or from subject))
- (when from
- (unless (string= from (caar fs))
- (setq from nil)))
- (when subject
- (unless (string= (gnus-simplify-subject-fuzzy (cdar fs))
- subject)
- (setq subject nil)))
- (setq fs (cdr fs))))
- (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))
- (when (re-search-forward "^Subject: ")
- (delete-region (point) (gnus-point-at-eol))
- (insert subject))
- (goto-char (point-min))
- (when (re-search-forward "^From: ")
- (delete-region (point) (gnus-point-at-eol))
- (insert from))
- (message-forward post))
- (delete-file file)
- (kill-buffer buf)
+ (file (mm-make-temp-file (nnheader-concat gnus-uu-tmp-dir "forward")))
+ (message-forward-as-mime message-forward-as-mime)
+ (mail-parse-charset gnus-newsgroup-charset)
+ (mail-parse-ignored-charsets gnus-newsgroup-ignored-charsets)
+ gnus-uu-digest-buffer subject from)
+ (if (and n (not (numberp n)))
+ (setq message-forward-as-mime (not message-forward-as-mime)
+ n nil))
+ (let ((gnus-article-reply (gnus-summary-work-articles n)))
+ (gnus-setup-message 'forward
+ (setq gnus-uu-digest-from-subject nil)
+ (setq gnus-uu-digest-buffer
+ (gnus-get-buffer-create " *gnus-uu-forward*"))
+ (gnus-uu-decode-save n file)
+ (switch-to-buffer gnus-uu-digest-buffer)
+ (let ((fs gnus-uu-digest-from-subject))
+ (when fs
+ (setq from (caar fs)
+ subject (gnus-simplify-subject-fuzzy (cdar fs))
+ fs (cdr fs))
+ (while (and fs (or from subject))
+ (when from
+ (unless (string= from (caar fs))
+ (setq from nil)))
+ (when subject
+ (unless (string= (gnus-simplify-subject-fuzzy (cdar fs))
+ subject)
+ (setq subject nil)))
+ (setq fs (cdr fs))))
+ (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))
+ (when (re-search-forward "^Subject: ")
+ (delete-region (point) (point-at-eol))
+ (insert subject))
+ (goto-char (point-min))
+ (when (re-search-forward "^From:")
+ (delete-region (point) (point-at-eol))
+ (insert " " from))
+ (let ((message-forward-decoded-p t))
+ (message-forward post))))
(setq gnus-uu-digest-from-subject nil)))
(defun gnus-uu-digest-post-forward (&optional n)
;; Process marking.
+(defun gnus-message-process-mark (unmarkp new-marked)
+ (let ((old (- (length gnus-newsgroup-processable) (length new-marked))))
+ (message "%d mark%s %s%s"
+ (length new-marked)
+ (if (= (length new-marked) 1) "" "s")
+ (if unmarkp "removed" "added")
+ (cond
+ ((and (zerop old)
+ (not unmarkp))
+ "")
+ (unmarkp
+ (format ", %d remain marked"
+ (length gnus-newsgroup-processable)))
+ (t
+ (format ", %d already marked" old))))))
+
+(defun gnus-new-processable (unmarkp articles)
+ (if unmarkp
+ (gnus-intersection gnus-newsgroup-processable articles)
+ (gnus-set-difference articles gnus-newsgroup-processable)))
+
(defun gnus-uu-mark-by-regexp (regexp &optional unmark)
- "Ask for a regular expression and set the process mark on all articles that match."
- (interactive (list (read-from-minibuffer "Mark (regexp): ")))
- (let ((articles (gnus-uu-find-articles-matching regexp)))
- (while articles
- (if unmark
- (gnus-summary-remove-process-mark (pop articles))
- (gnus-summary-set-process-mark (pop articles))))
- (message ""))
+ "Set the process mark on articles whose subjects match REGEXP.
+When called interactively, prompt for REGEXP.
+Optional UNMARK non-nil means unmark instead of mark."
+ (interactive "sMark (regexp): \nP")
+ (save-excursion
+ (let* ((articles (gnus-uu-find-articles-matching regexp))
+ (new-marked (gnus-new-processable unmark articles)))
+ (while articles
+ (if unmark
+ (gnus-summary-remove-process-mark (pop articles))
+ (gnus-summary-set-process-mark (pop articles))))
+ (gnus-message-process-mark unmark new-marked)))
(gnus-summary-position-point))
-(defun gnus-uu-unmark-by-regexp (regexp &optional unmark)
- "Ask for a regular expression and remove the process mark on all articles that match."
- (interactive (list (read-from-minibuffer "Mark (regexp): ")))
+(defun gnus-uu-unmark-by-regexp (regexp)
+ "Remove the process mark from articles whose subjects match REGEXP.
+When called interactively, prompt for REGEXP."
+ (interactive "sUnmark (regexp): ")
(gnus-uu-mark-by-regexp regexp t))
(defun gnus-uu-mark-series ()
"Mark the current series with the process mark."
(interactive)
- (let ((articles (gnus-uu-find-articles-matching)))
+ (let* ((articles (gnus-uu-find-articles-matching))
+ (l (length articles)))
(while articles
(gnus-summary-set-process-mark (car articles))
(setq articles (cdr articles)))
- (message ""))
+ (message "Marked %d articles" l))
(gnus-summary-position-point))
(defun gnus-uu-mark-region (beg end &optional unmark)
(defun gnus-uu-mark-thread ()
"Marks all articles downwards in this thread."
(interactive)
- (let ((level (gnus-summary-thread-level)))
- (while (and (gnus-summary-set-process-mark (gnus-summary-article-number))
- (zerop (gnus-summary-next-subject 1))
- (> (gnus-summary-thread-level) level))))
+ (gnus-save-hidden-threads
+ (let ((level (gnus-summary-thread-level)))
+ (while (and (gnus-summary-set-process-mark
+ (gnus-summary-article-number))
+ (zerop (gnus-summary-next-subject 1 nil t))
+ (> (gnus-summary-thread-level) level)))))
(gnus-summary-position-point))
(defun gnus-uu-unmark-thread ()
"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)))
(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))
+ (let ((score (or score gnus-summary-default-score 0))
(data gnus-newsgroup-data))
(save-excursion
(while data
(gnus-uu-save-separate-articles
(save-excursion
(set-buffer buffer)
- (gnus-write-buffer
+ (gnus-write-buffer-as-coding-system
+ nnheader-text-coding-system
(concat gnus-uu-saved-article-name gnus-current-article))
(cond ((eq in-state 'first) (list gnus-uu-saved-article-name 'begin))
((eq in-state 'first-and-last) (list gnus-uu-saved-article-name
(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*"))
- (erase-buffer))
(save-excursion
- (set-buffer (get-buffer-create "*gnus-uu-pre*"))
+ (set-buffer (gnus-get-buffer-create "*gnus-uu-body*"))
+ (erase-buffer))
+ (save-excursion
+ (set-buffer (gnus-get-buffer-create "*gnus-uu-pre*"))
(erase-buffer)
(insert (format
- "Date: %s\nFrom: %s\nSubject: %s Digest\n\nTopics:\n"
- (current-time-string) name name))))
+ "Date: %s\nFrom: %s\nSubject: %s Digest\n\n"
+ (current-time-string) name name))
+ (insert "Topics:\n")))
(when (not (eq in-state 'end))
(setq state (list 'middle))))
(save-excursion
- (set-buffer (get-buffer "*gnus-uu-body*"))
+ (set-buffer "*gnus-uu-body*")
(goto-char (setq beg (point-max)))
(save-excursion
(save-restriction
(set-buffer buffer)
(let (buffer-read-only)
- (gnus-set-text-properties (point-min) (point-max) nil)
+ (set-text-properties (point-min) (point-max) nil)
;; These two are necessary for XEmacs 19.12 fascism.
(put-text-property (point-min) (point-max) 'invisible nil)
(put-text-property (point-min) (point-max) 'intangible nil))
(goto-char (point-min))
- (re-search-forward "\n\n")
- ;; Quote all 30-dash lines.
- (save-excursion
- (while (re-search-forward "^-" nil t)
- (beginning-of-line)
- (delete-char 1)
- (insert "- ")))
+ (search-forward "\n\n")
+ (unless gnus-uu-digest-buffer
+ ;; Quote all 30-dash lines.
+ (save-excursion
+ (while (re-search-forward "^-" nil t)
+ (beginning-of-line)
+ (delete-char 1)
+ (insert "- "))))
(setq body (buffer-substring (1- (point)) (point-max)))
(narrow-to-region (point-min) (point))
(if (not (setq headers gnus-uu-digest-headers))
- (setq sorthead (buffer-substring (point-min) (point-max)))
+ (setq sorthead (buffer-string))
(while headers
(setq headline (car headers))
(setq headers (cdr headers))
(1- (point)))
(progn (forward-line 1) (point)))))))))
(widen)))
+ (insert message-forward-start-separator)
(insert sorthead) (goto-char (point-max))
(insert body) (goto-char (point-max))
- (insert (concat "\n" (make-string 30 ?-) "\n\n"))
(goto-char beg)
- (when (re-search-forward "^Subject: \\(.*\\)$" nil t)
- (setq subj (buffer-substring (match-beginning 1) (match-end 1)))
+ (when (re-search-forward "^Subject:" nil t)
+ (setq subj (nnheader-decode-subject
+ (buffer-substring (match-end 0) (std11-field-end)))))
+ (when subj
(save-excursion
- (set-buffer (get-buffer "*gnus-uu-pre*"))
+ (set-buffer "*gnus-uu-pre*")
(insert (format " %s\n" subj)))))
(when (or (eq in-state 'last)
(eq in-state 'first-and-last))
- (save-excursion
- (set-buffer (get-buffer "*gnus-uu-pre*"))
- (insert (format "\n\n%s\n\n" (make-string 70 ?-)))
- (gnus-write-buffer gnus-uu-saved-article-name))
- (save-excursion
- (set-buffer (get-buffer "*gnus-uu-body*"))
- (goto-char (point-max))
- (insert
- (concat (setq end-string (format "End of %s Digest" name))
- "\n"))
- (insert (concat (make-string (length end-string) ?*) "\n"))
- (write-region
- (point-min) (point-max) gnus-uu-saved-article-name t))
- (kill-buffer (get-buffer "*gnus-uu-pre*"))
- (kill-buffer (get-buffer "*gnus-uu-body*"))
+ (if gnus-uu-digest-buffer
+ (with-current-buffer gnus-uu-digest-buffer
+ (erase-buffer)
+ (insert-buffer "*gnus-uu-pre*")
+ (goto-char (point-max))
+ (insert-buffer "*gnus-uu-body*"))
+ (save-excursion
+ (set-buffer "*gnus-uu-pre*")
+ (insert (format "\n\n%s\n\n" (make-string 70 ?-)))
+ (if gnus-uu-digest-buffer
+ (with-current-buffer gnus-uu-digest-buffer
+ (erase-buffer)
+ (insert-buffer "*gnus-uu-pre*"))
+ (gnus-write-buffer-as-coding-system
+ nnheader-text-coding-system gnus-uu-saved-article-name)))
+ (save-excursion
+ (set-buffer "*gnus-uu-body*")
+ (goto-char (point-max))
+ (insert
+ (concat (setq end-string (format "End of %s Digest" name))
+ "\n"))
+ (insert (concat (make-string (length end-string) ?*) "\n"))
+ (if gnus-uu-digest-buffer
+ (with-current-buffer gnus-uu-digest-buffer
+ (goto-char (point-max))
+ (insert-buffer "*gnus-uu-body*"))
+ (let ((file-name-coding-system nnmail-pathname-coding-system))
+ (write-region-as-coding-system
+ nnheader-text-coding-system
+ (point-min) (point-max) gnus-uu-saved-article-name t)))))
+ (gnus-kill-buffer "*gnus-uu-pre*")
+ (gnus-kill-buffer "*gnus-uu-body*")
(push 'end state))
(if (memq 'begin state)
(cons gnus-uu-saved-article-name state)
(if (looking-at gnus-uu-binhex-begin-line)
(progn
(setq state (list 'begin))
- (write-region 1 1 gnus-uu-binhex-article-name))
+ (write-region (point-min) (point-min)
+ gnus-uu-binhex-article-name))
(setq state (list 'middle)))
(goto-char (point-max))
(re-search-backward (concat gnus-uu-binhex-body-line "\\|"
(beginning-of-line)
(forward-line 1)
(when (file-exists-p gnus-uu-binhex-article-name)
- (append-to-file start-char (point) gnus-uu-binhex-article-name))))
+ (write-region-as-binary start-char (point)
+ gnus-uu-binhex-article-name 'append))))
(if (memq 'begin state)
(cons gnus-uu-binhex-article-name state)
state)))
(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"))
(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)
+ (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-string)))
(defun gnus-uu-get-list-of-articles (n)
;; If N is non-nil, the article numbers of the N next articles
(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)
;; Expand numbers, sort, and return the list of article
;; numbers.
- (mapcar (lambda (sub) (cdr sub))
+ (mapcar 'cdr
(sort (gnus-uu-expand-numbers
list-of-subjects
(not do-not-translate))
(let ((out-list string-list)
string)
(save-excursion
- (set-buffer (get-buffer-create gnus-uu-output-buffer-name))
- (buffer-disable-undo (current-buffer))
+ (set-buffer (gnus-get-buffer-create gnus-uu-output-buffer-name))
+ (buffer-disable-undo)
(while string-list
(erase-buffer)
(insert (caar string-list))
;; Expand numbers.
(goto-char (point-min))
(while (re-search-forward "[0-9]+" nil t)
- (replace-match
- (format "%06d"
- (string-to-int (buffer-substring
- (match-beginning 0) (match-end 0))))))
+ (ignore-errors
+ (replace-match
+ (format "%06d"
+ (string-to-int (buffer-substring
+ (match-beginning 0) (match-end 0)))))))
(setq string (buffer-substring 1 (point-max)))
(setcar (car string-list) string)
(setq string-list (cdr string-list))))
&optional sloppy limit no-errors)
(let ((state 'first)
(gnus-asynchronous nil)
+ (gnus-inhibit-treatment t)
has-been-begin article result-file result-files process-state
gnus-summary-display-article-function
- gnus-article-display-hook gnus-article-prepare-hook
+ gnus-article-prepare-hook gnus-display-mime-function
article-series files)
(while (and articles
(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.
+ ;; 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
(while article-series
(gnus-summary-tick-article (pop article-series) t))))
+ ;; The original article buffer is hosed, shoot it down.
+ (gnus-kill-buffer gnus-original-article-buffer)
+ (setq gnus-current-article nil)
result-files))
(defun gnus-uu-grab-view (file)
(when gnus-uu-default-dir
(let ((to-file (concat (file-name-as-directory gnus-uu-default-dir)
(file-name-nondirectory file))))
- (rename-file file to-file)
- (unless (file-exists-p file)
- (make-symbolic-link to-file file)))))
+ (cond ((fboundp 'make-symbolic-link)
+ (rename-file file to-file)
+ (unless (file-exists-p file)
+ (make-symbolic-link to-file file)))
+ (t
+ (copy-file file to-file))))))
(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)))
;; We replace certain characters that could make things messy.
(setq gnus-uu-file-name
(let ((nnheader-file-name-translation-alist
- '((?/ . ?,) (? . ?_) (?* . ?_) (?$ . ?_))))
+ '((?/ . ?,) (? . ?_) (?* . ?_) (?$ . ?_))))
(nnheader-translate-file-chars (match-string 1))))
- (replace-match (concat "begin 644 " gnus-uu-file-name) t t)
+ (replace-match (concat "begin 644 " gnus-uu-file-name) t t)
;; Remove any non gnus-uu-body-line right after start.
(forward-line 1)
(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))))
;; Try to correct mishandled uucode.
(when gnus-uu-correct-stripped-uucode
(gnus-uu-check-correct-stripped-uucode start-char (point)))
- (run-hooks 'gnus-uu-pre-uudecode-hook)
+ (gnus-run-hooks 'gnus-uu-pre-uudecode-hook)
;; Send the text to the process.
(condition-case nil
(cons (if (= (length files) 1) (car files) files) state)
state))))
+(defvar gnus-uu-unshar-warning
+ "*** WARNING ***
+
+Shell archives are an archaic method of bundling files for distribution
+across computer networks. During the unpacking process, arbitrary commands
+are executed on your system, and all kinds of nasty things can happen.
+Please examine the archive very carefully before you instruct Emacs to
+unpack it. You can browse the archive buffer using \\[scroll-other-window].
+
+If you are unsure what to do, please answer \"no\"."
+ "Text of warning message displayed by `gnus-uu-unshar-article'.
+Make sure that this text consists only of few text lines. Otherwise,
+Gnus might fail to display all of it.")
+
+
;; This function is used by `gnus-uu-grab-articles' to treat
;; a shared article.
(defun gnus-uu-unshar-article (process-buffer in-state)
(goto-char (point-min))
(if (not (re-search-forward gnus-uu-shar-begin-string nil t))
(setq state (list 'wrong-type))
- (beginning-of-line)
- (setq start-char (point))
- (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 " "
- gnus-shell-command-separator " sh"))))
+ (save-window-excursion
+ (save-excursion
+ (switch-to-buffer (current-buffer))
+ (delete-other-windows)
+ (let ((buffer (get-buffer-create (generate-new-buffer-name
+ "*Warning*"))))
+ (unless
+ (unwind-protect
+ (with-current-buffer buffer
+ (insert (substitute-command-keys
+ gnus-uu-unshar-warning))
+ (goto-char (point-min))
+ (display-buffer buffer)
+ (yes-or-no-p "This is a shell archive, unshar it? "))
+ (kill-buffer buffer))
+ (setq state (list 'error))))))
+ (unless (memq 'error state)
+ (beginning-of-line)
+ (setq start-char (point))
+ (call-process-region
+ start-char (point-max) shell-file-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")))))
state))
;; Returns the name of what the shar file is going to unpack.
(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)
+ (if (eq 0 (call-process shell-file-name nil
+ (gnus-get-buffer-create gnus-uu-output-buffer-name)
nil shell-command-switch command))
(message "")
(gnus-message 2 "Error during unpacking of archive")
(defun gnus-uu-check-correct-stripped-uucode (start end)
(save-excursion
(let (found beg length)
- (if (not gnus-uu-correct-stripped-uucode)
- ()
+ (unless gnus-uu-correct-stripped-uucode
(goto-char start)
(if (re-search-forward " \\|`" end t)
(forward-line 1))))
(while (not (eobp))
- (if (looking-at (concat gnus-uu-begin-string "\\|"
- gnus-uu-end-string))
- ()
+ (unless (looking-at (concat gnus-uu-begin-string "\\|"
+ gnus-uu-end-string))
(when (not found)
- (beginning-of-line)
- (setq beg (point))
- (end-of-line)
- (setq length (- (point) beg)))
+ (setq length (- (point-at-eol) (point-at-bol))))
(setq found t)
(beginning-of-line)
(setq beg (point))
(end-of-line)
- (when (not (= length (- (point) beg)))
+ (unless (= length (- (point) beg))
(insert (make-string (- length (- (point) beg)) ? ))))
(forward-line 1)))))))
gnus-uu-tmp-dir)))
(setq gnus-uu-work-dir
- (make-temp-name (concat gnus-uu-tmp-dir "gnus")))
- (gnus-make-directory gnus-uu-work-dir)
- (set-file-modes gnus-uu-work-dir 448)
+ (mm-make-temp-file (concat gnus-uu-tmp-dir "gnus") 'dir))
+ (gnus-set-file-modes gnus-uu-work-dir 448)
(setq gnus-uu-work-dir (file-name-as-directory gnus-uu-work-dir))
(push (cons gnus-newsgroup-name gnus-uu-work-dir)
gnus-uu-tmp-alist))))
(push (list (aref arg new-pos)) accum)
(setq pos (1+ new-pos)))
(if (= pos 0)
- arg
+ arg
(apply 'concat (nconc (nreverse accum) (list (substring arg pos)))))))
;; Inputs an action and a filename and returns a full command, making sure
;; that the filename will be treated as a single argument when the shell
;; executes the command.
(defun gnus-uu-command (action file)
- (let ((quoted-file (gnus-quote-arg-for-sh-or-csh file)))
+ (let ((quoted-file (shell-quote-argument file)))
(if (string-match "%s" action)
(format action quoted-file)
(concat action " " quoted-file))))
(if (file-directory-p file)
(gnus-uu-delete-work-dir file)
(gnus-message 9 "Deleting file %s..." file)
- (delete-file file))))
- (delete-directory dir)))
- (gnus-message 7 ""))
+ (condition-case err
+ (delete-file file)
+ (error (gnus-message 3 "Deleting file %s failed... %s" file err))))))
+ (condition-case err
+ (delete-directory dir)
+ (error (gnus-message 3 "Deleting directory %s failed... %s" file err))))
+ (gnus-message 7 "")))
;; Initializing
(gnus-summary-post-news)
- (use-local-map (copy-keymap (current-local-map)))
- (local-set-key "\C-c\C-c" 'gnus-summary-edit-article-done)
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map (current-local-map))
+ (use-local-map map))
+ ;;(local-set-key "\C-c\C-c" 'gnus-summary-edit-article-done)
(local-set-key "\C-c\C-c" 'gnus-uu-post-news-inews)
(local-set-key "\C-c\C-s" 'gnus-uu-post-news-inews)
(local-set-key "\C-c\C-i" 'gnus-uu-post-insert-binary-in-article)
(when (gnus-uu-post-encode-file "uuencode" path file-name)
(goto-char (point-min))
(forward-line 1)
- (while (re-search-forward " " nil t)
+ (while (search-forward " " nil t)
(replace-match "`"))
t))
;; Encodes with base64 and adds MIME headers
(defun gnus-uu-post-encode-mime (path file-name)
- (when (zerop (call-process shell-file-name nil t nil shell-command-switch
- (format "%s %s -o %s" "mmencode" path file-name)))
+ (when (eq 0 (call-process shell-file-name nil t nil shell-command-switch
+ (format "%s %s -o %s" "mmencode" path file-name)))
(gnus-uu-post-make-mime file-name "base64")
t))
(goto-char (point-min))
(re-search-forward (concat "^" (regexp-quote mail-header-separator) "$"))
(forward-line -1)
- (narrow-to-region 1 (point))
+ (narrow-to-region (point-min) (point))
(unless (mail-fetch-field "mime-version")
(widen)
(insert "MIME-Version: 1.0\n"))
;; Encodes a file PATH with COMMAND, leaving the result in the
;; current buffer.
(defun gnus-uu-post-encode-file (command path file-name)
- (= 0 (call-process shell-file-name nil t nil shell-command-switch
- (format "%s %s %s" command path file-name))))
+ (eq 0 (call-process shell-file-name nil t nil shell-command-switch
+ (format "%s %s %s" command path file-name))))
(defun gnus-uu-post-news-inews ()
"Posts the composed news article and encoded 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))
(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)
(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))
(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))
- (setq length (count-lines 1 (point-max)))
+ (setq length (count-lines (point-min) (point-max)))
(setq parts (/ length gnus-uu-post-length))
(unless (< (% length gnus-uu-post-length) 4)
(incf parts)))
(goto-char (point-min))
(re-search-forward
(concat "^" (regexp-quote mail-header-separator) "$") nil t)
- (beginning-of-line)
- (setq header (buffer-substring 1 (point)))
+ (setq header (buffer-substring (point-min) (point-at-bol)))
(goto-char (point-min))
(when gnus-uu-post-separate-description
(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)
(when (not gnus-uu-post-separate-description)
(set-buffer-modified-p nil)
- (when (fboundp 'bury-buffer)
- (bury-buffer)))))
+ (bury-buffer))))
(provide 'gnus-uu)
-;; gnus-uu.el ends here
+;;; gnus-uu.el ends here