From: spike@world.std.com (Joe Ilacqua)
Subject: MIME support for GNUS.
Organization: Software Tool & Die
Date: Wed, 23 Dec 1992 23:28:19 GMT


	This is more of a proof of concept than a finished product,
but it seems to work.  This package allows you to read MIME format
news articles, use richtext in you postings, and insert (presumably
binary) files into you messages.

	You need to have "Metamail" installed and have
"transparent.el" in your load path.
Have fun.

->Spike

#!/bin/sh
# This is a shell archive (produced by shar 3.50)
# To extract the files from this archive, save it to a file, remove
# everything above the "!/bin/sh" line above, and type "sh file_name".
#
# made 12/23/1992 23:24 UTC by spike@world
# Source directory /staff/spike
#
# existing files will NOT be overwritten unless -c is specified
#
# This shar contains:
# length  mode       name
# ------ ---------- ------------------------------------------
#   9416 -rw-rw-r-- gnus-mime.el
#
# ============= gnus-mime.el ==============
if test -f 'gnus-mime.el' -a X"$1" != X"-c"; then
	echo 'x - skipping gnus-mime.el (File already exists)'
else
echo 'x - extracting gnus-mime.el (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'gnus-mime.el' &&
;;;  Support to read/post MIME format USENET articles in GNUS.
X
;;  Author Spike <Spike@world.std.com>
;;  with code from Michael Littman's <mlittman@breeze.bellcore.com>
;;  richtext.el and metamail's MH-E patches.
X
X
;;  This requires that you have the metamail package installed
;;  (thumper.bellcore.com:/pub/nsb/mm.tar.Z) and transparent.el
;;  
;;  This package provides four basic functions
;;
;;  gnus-Subject-run-metamail - invokes metamail on the selected news article.
;;  gnus-inews-article - replaces the standard gnus-inews-article with one
;;                       which inserts MIME headers and does Richtext style
;;                       signatures.
;;  gnus-richtext-posting - converts the posting buffer to Richtext format,
;;                          knows how to make text bold, italics, and
;;                          underlined.
;;  gnus-insert-file-as-mime - Allows you to insert arbitrary data into
;;                             a posting in MIME format.  Automatically
;;                             recognizes some formats (GIF, JPEG, PS),
;;                             more can be add through "auto-mime-id-list".
X
;;  As ships this binds gnus-Subject-run-metamail to "@" in the "*Subject*"
;;  buffer.  gnus-richtext-posting to "C-c r" and "gnus-insert-file-as-mime" to
;;  "C-c i" in the posting buffer.
;;
X
;;  To use put "(load-library "gnus-mime.el")" in your ".emacs" or "default.el"
X
;;  If you want GNUS to announce MIME postings but something like:
;;  (setq gnus-Article-prepare-hook
;;       '(lambda ()
;;	  (gnus-Subject-check-content-type)))
;;  in your ".emacs" file.
X
;; CAVEATS: You can only insert one file per posting.  You can not call
;;          gnus-richtext-posting after calling gnus-insert-file-as-mime.
X
(require 'transparent)
(load-library "rnewspost") ;; sigh...  This could be better.
(require 'gnuspost)
(provide 'gnus-mime)
X
(defvar gnus-invoke-mime-key "@" 
X  "The key that calls gnus-Subject-run-metamail")
X
(define-key gnus-Subject-mode-map gnus-invoke-mime-key
X  'gnus-Subject-run-metamail)
X
(define-key news-reply-mode-map "\C-cr" 'gnus-richtext-posting)
(define-key news-reply-mode-map "\C-ci" 'gnus-insert-file-as-mime)
X
(defvar auto-mime-id-list nil "\
A list of filename patterns vs corresponding MIME type strings
Each element looks like (REGEXP . TYPE).")
(setq auto-mime-id-list (mapcar 'purecopy
X                              '(("\\.gif$" . "image/gif")
X				("\\.jpg$" . "image/jpeg")
X				("\\.xwd$" . "image/x-xwd")
X				("\\.ps$"  . "application/PostScript"))))
X
;;;;;;
X
(defun gnus-Subject-check-content-type ()
X  (if (gnus-fetch-field "Mime-Version")
X      (let ((content-type (gnus-fetch-field "Content-Type")))
X	   (message (concat "You can use '" gnus-invoke-mime-key 
X			    "' to view this '" content-type 
X			    "' MIME format article.")))))
X
(defun gnus-Subject-run-metamail ()
X  (interactive)
X  "Process Selected Article Through \"metamail\"."
X  (gnus-Subject-select-article)
X  (gnus-eval-in-buffer-window gnus-Article-buffer
X  (let ((metamail-tmpfile (make-temp-name "/tmp/rmailct")))
X    (save-restriction
X      (widen)
X      (write-region (point-min) (point-max) metamail-tmpfile))
X    (if 
X	(and window-system (getenv "DISPLAY"))
X	(let ((buffer-read-only nil))
X	  (push-mark (point) t)
X	  (erase-buffer)
X	  (call-process "metamail" nil t t
X		 "-m" "mh-e" "-x" "-d" "-q" "-z" metamail-tmpfile)
X	  (exchange-point-and-mark)
X	  (set-buffer-modified-p nil)
X	  (other-window -1))
X      (progn
X	(other-window -1)
X	(switch-to-buffer "METAMAIL")
X	(erase-buffer)
X	(sit-for 0)
X	(transparent-window
X	 "METAMAIL"
X	 "metamail"
X	 (list "-p" "-d" "-q" metamail-tmpfile)
X	 nil
X	 (concat
X	  "\n\r\n\r*****************************************"
X	  "*******************************\n\rPress any key "
X	  "to go back to EMACS\n\r\n\r***********************" 
X	  "*************************************************\n\r")))
X      )
X    )
X  )
X )
X
X
(defvar rich-substitutions
X      '(
X        ("<"        "<lt>") ; in case some one sends less-thans.
X        ("\\B%\\b" "</italic>") ; needs to be first to not get closing tags.
X        ("\\b%\\B" "<italic>")
X        ("\\B\\*\\b" "<bold>")
X        ("\\b\\*\\B" "</bold>")
X        ("
" "
<nl>")
X        ("\\B_\\b" "<underline>")
X        ("\\b_\\B" "</underline>")
X        )
X      "A table of REGEXP to translate text to MIME's text/richtext format.")
X
(defun gnus-richtext-posting ()
X  "Convert the current buffer to MIME's \"text/richtext\" format.
\"*foo*\" is converted to bold, \"%foo%\" to italics, and \"_foo_\" to
underlined. Note: this does not recognize font markers *after*
punctuation, thus \"*foo!*\" will not work."
X  (interactive)
X  (mail-position-on-field "Subject")
X  (or (gnus-fetch-field "Mime-Version")
X      (insert "\nMime-Version: 1.0"))
X  (or (gnus-fetch-field "Content-Type")
X      (insert "\nContent-Type: text/richtext"))
X  (goto-char (point-min))
X  (search-forward (concat "\n" mail-header-separator "\n") nil t)
X  (perform-rich-sub)
X  )
X
(defun perform-rich-sub ()
X  "Perform the rich substiution."
X  (let ((subs rich-substitutions)
X        pat rep
X        (top (point)))
X    (save-excursion
X      (while subs
X        (setq pat (car (car subs)))
X        (setq rep (car (cdr (car subs))))
X        (setq subs (cdr subs))
X        (goto-char top)
X        (while (re-search-forward pat (point-max) t)
X          (replace-match rep))
X        ))))
X
(defun gnus-insert-file-as-mime (filename)
X  "Encode and insert a file into the posting buffer and setup the correct
MIME headers for that file type."
X  (interactive "FFind file: ")
X  (let ((ctype nil)
X	(boundary
X	 (concat "GNUS.BOUNDARY." (system-name) "." (current-time-string))))
X    (let ((mlist auto-mime-id-list)
X	  (name filename))
X      (while (and (not ctype) mlist)
X	(if (string-match (car (car mlist)) name)
X	    (setq ctype (cdr (car mlist))))
X              (setq mlist (cdr mlist))))
X    (if (not ctype)
X	(setq ctype 
X	      (read-string "MIME content type: " "application/octet-stream")))
X    (goto-char (point-min))
X    (re-search-forward
X     (concat "^" (regexp-quote mail-header-separator) "\n"))
X    (insert (concat "--" boundary "\n"))
X    (insert "Content-type: text/richtext\n")
X    (insert "Content-Transfer-Encoding: quoted-printable\n\n")
X    (goto-char (point-max))
X    (insert (concat "\n--" boundary "\n"))
X    (insert (concat "Content-type: " ctype "\n"))
X    (insert "Content-Transfer-Encoding: base64\n\n")
X    (shell-command (concat "mmencode " filename) t)
X    (goto-char (point-max))
X    (insert (concat "\n--" boundary "\n"))
X    (mail-position-on-field "Subject")
X    (or (gnus-fetch-field "Mime-Version")
X	(insert "\nMime-Version: 1.0"))
X    (if (gnus-fetch-field "Content-Type")
X	(progn
X	  (mail-position-on-field "Content-Type")
X	  (beginning-of-line)
X	  (delete-region (point) (progn (forward-line 1) (point)))))
X      (insert (concat "Content-Type: multipart/mixed;\n"
X		      "\tboundary=\"" boundary "\"\n"))
X    ))
X
(defun gnus-inews-article ()
X  "NNTP inews interface."
X  (let ((signature
X	 (if gnus-signature-file
X	     (expand-file-name gnus-signature-file nil)))
X	(distribution nil)
X	(artbuf (current-buffer))
X	(tmpbuf (get-buffer-create " *GNUS-posting*"))
X	(ctype nil))
X    (save-excursion
X      (set-buffer tmpbuf)
X      (buffer-flush-undo (current-buffer))
X      (erase-buffer)
X      (insert-buffer-substring artbuf)
X      ;; Get distribution.
X      (setq distribution (gnus-fetch-field "Distribution"))
X      (if signature
X	  (progn
X	    ;; Change signature file by distribution.
X	    ;; Suggested by hyoko@flab.fujitsu.junet.
X	    (if (file-exists-p (concat signature "-" distribution))
X		(setq signature (concat signature "-" distribution)))
X	    ;; Insert signature.
X	    (if (file-exists-p signature)
X		(progn
X		  ;; Mime signature format
X		  (setq ctype (gnus-fetch-field "Content-Type"))
X		  (if (and ctype (string-match "multipart/mixed" ctype))
X		      (progn
X			(string-match "boundary=\"" ctype)
X			(setq boundary (substring ctype  (- (match-end 0) 1)))
X			(string-match "\"" boundary)
X			(setq boundary 
X			      (substring boundary 0 (- (match-end 0) 1)))
X			(goto-char (point-max))
X			(insert (concat "--" boundary "\n"))
X			(insert "Content-type: text/richtext\n")
X			(insert "Content-Transfer-Encoding: quoted-printable\n\n")
X			))
X		  (goto-char (point-max))
X		  (insert "<signature>")
X		  (insert-file-contents signature)
X		  (goto-char (point-max))
X		  (insert "</signature>\n")))
X	    ))
X      ;; Prepare article headers.
X      (save-restriction
X	(goto-char (point-min))
X	(search-forward "\n\n")
X	(narrow-to-region (point-min) (point))
X	(gnus-inews-insert-headers)
X	;; insert mime headers if needed.
X	(goto-char (point-max))
X	(forward-line -2)
X	(or (gnus-fetch-field "Mime-Version")
X	    (insert "Mime-Version: 1.0"\n))
X	(or (gnus-fetch-field "Content-Type")
X	    (insert "Content-Type: text/richtext\n"))
X	;; Save author copy of posted article. The article must be
X	;;  copied before being posted because `gnus-request-post'
X	;;  modifies the buffer.
X	(let ((case-fold-search t))
X	  ;; Find and handle any FCC fields.
X	  (goto-char (point-min))
X	  (if (re-search-forward "^FCC:" nil t)
X	      (gnus-inews-do-fcc))))
X      (widen)
X      ;; Run final inews hooks.
X      (run-hooks 'gnus-Inews-article-hook)
X      ;; Post an article to NNTP server.
X      ;; Return NIL if post failed.
X      (prog1
X	  (gnus-request-post)
X	(kill-buffer (current-buffer)))
X      )))
SHAR_EOF
chmod 0664 gnus-mime.el ||
echo 'restore of gnus-mime.el failed'
Wc_c="`wc -c < 'gnus-mime.el'`"
test 9416 -eq "$Wc_c" ||
	echo 'gnus-mime.el: original size 9416, current size' "$Wc_c"
fi
exit 0