home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #26 / NN_1992_26.iso / spool / gnu / emacs / sources / 779 < prev    next >
Encoding:
Text File  |  1992-11-07  |  25.4 KB  |  631 lines

  1. Newsgroups: gnu.emacs.sources
  2. Path: sparky!uunet!zaphod.mps.ohio-state.edu!uwm.edu!ux1.cso.uiuc.edu!news.cso.uiuc.edu!ux3.cso.uiuc.edu!marca
  3. From: marca@ncsa.uiuc.edu (Marc Andreessen)
  4. Subject: mime-compose.el (new & improved)
  5. Message-ID: <MARCA.92Nov6065415@wintermute.ncsa.uiuc.edu>
  6. Sender: usenet@news.cso.uiuc.edu (Net Noise owner)
  7. Organization: Nat'l Center for Supercomputing Applications
  8. Date: Fri, 6 Nov 1992 11:54:15 GMT
  9. Lines: 620
  10.  
  11. A new version of mime-compose.el follows.  New features are many and
  12. varied; most interesting is probably use of selective-display (so you
  13. never have to look at a bajillion lines of base64-encoded data).
  14. Second most interesting is on-the-fly audio recording (for IRIS
  15. platforms only, at the moment).
  16.  
  17. This works under Emacs, Epoch, and Lucid Emacs (with an enhanced
  18. mail-mode popup menu for the latter).
  19.  
  20. Feedback always welcome...
  21.  
  22. Marc
  23.  
  24. ;;; --------------------------------------------------------------------------
  25. ;;; File: --- mime-compose.el ---
  26. ;;; Author: Marc Andreessen (marca@ncsa.uiuc.edu)
  27. ;;; Additional code: Keith Waclena (k-waclena@uchicago.edu).
  28. ;;; Copyright (C) National Center for Supercomputing Applications, 1992.
  29. ;;;
  30. ;;; This program is free software; you can redistribute it and/or modify
  31. ;;; it under the terms of the GNU General Public License as published by
  32. ;;; the Free Software Foundation; either version 1, or (at your option)
  33. ;;; any later version.
  34. ;;;
  35. ;;; This program is distributed in the hope that it will be useful,
  36. ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  37. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  38. ;;; GNU General Public License for more details.
  39. ;;;
  40. ;;; You should have received a copy of the GNU General Public License
  41. ;;; along with your copy of Emacs; if not, write to the Free Software
  42. ;;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  43. ;;;
  44. ;;; -------------------------------- CONTENTS --------------------------------
  45. ;;;
  46. ;;; mime-compose: Utility routines for composing MIME-compliant mail.
  47. ;;; $Revision: 1.16 $
  48. ;;; $Date: 1992/11/06 14:50:59 $
  49. ;;;
  50. ;;; ------------------------------ INSTRUCTIONS ------------------------------
  51. ;;;
  52. ;;; Use the normal Emacs mail composer (C-x m).
  53. ;;;
  54. ;;; (Or, use with Emacs mh-e by loading this file *after* loading mh-e.
  55. ;;; Try putting (require 'mime-compose) in mh-letter-mode-hook.)
  56. ;;;
  57. ;;; Do nothing special to prepare a message to have MIME elements
  58. ;;; included in it.
  59. ;;;
  60. ;;; The basic commands to add MIME elements (images, audio, etc.) to a
  61. ;;; message are as follows:
  62. ;;;
  63. ;;; mail-mode  mh-e         command
  64. ;;; ~~~~~~~~~  ~~~~~~~~~    ~~~~~~~
  65. ;;; C-c g      C-c C-m g    Add a GIF file.
  66. ;;; C-c j      C-c C-m j    Add a JPEG file.
  67. ;;; C-c a      C-c C-m a    Add an audio file.
  68. ;;; C-c p      C-c C-m p    Add a PostScript file.
  69. ;;;
  70. ;;; (Note that mime-compose assumes you have the 'mmencode' program
  71. ;;; installed on your system.  See 'WHAT MIME IS' below for more
  72. ;;; information on mmencode and the metamail distribution.)
  73. ;;;
  74. ;;; Some mime-compose commands create data themselves; these follow:
  75. ;;;
  76. ;;; C-c x     C-c C-m x
  77. ;;;   Add the result of an X-window dump.  The program named in
  78. ;;;   mime-xwd-command will be run, and the resulting dump will be
  79. ;;;   inserted into the message.
  80. ;;; C-c s     C-c C-m s
  81. ;;;   Add an audio snippet, recorded on the fly.  CURRENTLY THIS WORKS
  82. ;;;   ONLY FOR SILICON GRAPHICS INDIGO AND 4D/35's.  Recording begins
  83. ;;;   immediately; press 'y' to end recording or 'n' to abort the
  84. ;;;   whole process.  The resulting audio file will be converted to
  85. ;;;   standard mulaw format and incorporated into the message.
  86. ;;;
  87. ;;; If you have a raw binary file and MIME or mime-compose doesn't
  88. ;;; have built-in support for its format (e.g. an Emacs Lisp
  89. ;;; byte-compiled file), you can use:
  90. ;;;
  91. ;;; C-c r     C-c C-m r
  92. ;;;   Add a raw binary file.  You will be prompted for both the
  93. ;;;   filename and the content type of the file; if you do not give a
  94. ;;;   content type, the default (application/octet-stream) will be
  95. ;;;   used, and the recipient will be able to have his/her MIME mail
  96. ;;;   handler extract the raw binary file from the message.
  97. ;;;
  98. ;;; Similarly, to include nonbinary (text) files using
  99. ;;; quoted-printable encoding, use:
  100. ;;;
  101. ;;; C-c n     C-c C-m n
  102. ;;;   Add a raw nonbinary (text) file.  You will be prompted for both
  103. ;;;   the filename and the content type of the file (which defaults to
  104. ;;;   text/plain).
  105. ;;;
  106. ;;; In addition to including files and generating inclusions on the
  107. ;;; fly, you can also point to external elements: files that will not
  108. ;;; be included in the document, but can be accessed by the recipient
  109. ;;; in some other way (most commonly, via FTP).  The following
  110. ;;; commands handle this:
  111. ;;;
  112. ;;; C-c e     C-c C-m e
  113. ;;;   Point to an external file (assumed to be accessable via
  114. ;;;   anonymous FTP).  You will be prompted for the name of the FTP
  115. ;;;   site, the remote directory name, and remote filename, the remote
  116. ;;;   file's content type, and a description of the remote file.
  117. ;;; C-c f     C-c C-m f
  118. ;;;   This is the same as 'C-c e', except that the file will be
  119. ;;;   accessed via regular FTP rather than anonymous FTP -- a username
  120. ;;;   and password will have to be provided by the recipient to gain
  121. ;;;   access to the file.
  122. ;;;
  123. ;;; Note that whenever you are prompted for a content type, Emacs'
  124. ;;; completion feature is active: press TAB for a list of valid types.
  125. ;;; You can also enter a type not in the completion list.
  126. ;;;
  127. ;;; ---------------------------- ADDITIONAL NOTES ----------------------------
  128. ;;;
  129. ;;; If you are running Lucid Emacs, the mail-mode popup menu (attached
  130. ;;; to the third mouse button) will include mime-compose entries.
  131. ;;;
  132. ;;; After your message has been `mimified' (by including a MIME
  133. ;;; element), it is best not to put trailing text outside the final
  134. ;;; boundary at the end of the file -- such text will not be
  135. ;;; considered to be part of the message by MIME-compliant mail
  136. ;;; readers (although it will still be sent).
  137. ;;;
  138. ;;; A command that usually isn't necessary, but is provided in case
  139. ;;; you wish to send a plaintext message with the various MIME headers
  140. ;;; and boundaries, is:
  141. ;;;
  142. ;;; C-c m     C-c C-m m     Mimify a message.
  143. ;;;
  144. ;;; Note that Emacs' selective-display feature is used: only the first
  145. ;;; line of any encoded data file will be displayed, followed by
  146. ;;; ellipses (indicating that some data is not being shown).  See the
  147. ;;; variable 'mime-use-selective-display' below.
  148. ;;;
  149. ;;; MIME messages can contain elements and structures not yet
  150. ;;; supported by mime-compose.  If you have ideas or code for support
  151. ;;; that should be provided by mime-compose, please send them to the
  152. ;;; author.
  153. ;;;
  154. ;;; ------------------------ WHAT MIME-COMPOSE IS NOT ------------------------
  155. ;;;
  156. ;;; mime-compose is not a MIME message handler.  It will not interpret
  157. ;;; MIME messages, display images, or anything similar.
  158. ;;;
  159. ;;; mime-compose is not intelligent enough (yet) to construct complex
  160. ;;; MIME messages (with nested boundaries, parallel message elements,
  161. ;;; and so on).
  162. ;;;
  163. ;;; mime-compose will not enforce correctness (MIME compliance) on
  164. ;;; your messages.  mime-compose generates MIME-compliant message
  165. ;;; elements, but will sit quietly if you alter them or add your own
  166. ;;; incorrect elements.
  167. ;;;
  168. ;;; ------------------------------ WHAT MIME IS ------------------------------
  169. ;;;
  170. ;;; MIME defines a format for email messages containing non-plaintext
  171. ;;; elements (images, audio, etc.).  MIME is detailed in Internet RFC
  172. ;;; 1341, by N. Borenstein and N. Freed.  You can FTP this RFC from
  173. ;;; many archive sites, including uxc.cso.uiuc.edu.
  174. ;;;
  175. ;;; Few mail readers handle MIME messages, yet.  However, most popular
  176. ;;; mail readers can be easily patched to feed MIME messages to a
  177. ;;; program called 'metamail', which can handle MIME messages.  You
  178. ;;; can FTP metamail from thumper.bellcore.com in /pub/nsb as
  179. ;;; mm.tar.Z.  Since mime-compose requires the existence of the
  180. ;;; program 'mmencode' (from the metamail distribution) to insert
  181. ;;; binary files into messages, it is a Good Idea to have metamail
  182. ;;; installed on your system.
  183. ;;;
  184. ;;; --------------------------------------------------------------------------
  185. ;;; LCD Archive Entry:
  186. ;;; mime-compose|Marc Andreessen|marca@ncsa.uiuc.edu
  187. ;;; |MIME-compliant message generation utilities.
  188. ;;; |$Date: 1992/11/06 14:50:59 $|$Revision: 1.16 $|
  189. ;;; --------------------------------------------------------------------------
  190.  
  191. (provide 'mime-compose)
  192. (require 'sendmail)
  193.  
  194. (defvar mime-primary-boundary "mysteryboxofun"
  195.   "*Word used as a MIME boundary.")
  196.  
  197. (defvar mime-xwd-command "xwd -frame"
  198.   "*Command used to do a window dump under the X Window System.")
  199.  
  200. (defvar mime-encode-base64-command "mmencode"
  201.   "*Command used to encode in base64.")
  202.  
  203. (defvar mime-encode-qp-command "mmencode -q"
  204.   "*Command used to encode in quoted-printable.")
  205.  
  206. (defvar mime-use-selective-display t
  207.   "*Use selective-display to hide bodies of MIME enclosures.")
  208.  
  209. (defvar mime-valid-include-types 
  210.   '(("image/gif" 1) 
  211.     ("image/jpeg" 2) 
  212.     ("image/x-xbm" 3) 
  213.     ("image/x-xwd" 4) 
  214.     ("application/postscript" 5) 
  215.     ("application/andrew-inset" 6) 
  216.     ("application/octet-stream" 7)
  217.     ("text/richtext" 8) 
  218.     ("text/plain" 9) 
  219.     ("audio/basic" 10))
  220.   "A list of valid content types for minibuffer completion.")
  221.  
  222. (defun mime-primary-boundary ()
  223.   "Return the current primary boundary."
  224.   mime-primary-boundary)
  225.  
  226. (defun mime-hide-region (from to hideflag)
  227.   "Hides or shows lines from FROM to TO, according to FLAG."
  228.   (let ((old (if hideflag ?\n ?\^M))
  229.         (new (if hideflag ?\^M ?\n))
  230.         (modp (buffer-modified-p)))
  231.     (unwind-protect (progn
  232.                       (subst-char-in-region from to
  233.                                             old new t))
  234.       (set-buffer-modified-p modp))))
  235.  
  236. (defun mime-maybe-hide-region (start end)
  237.   "Hide the current region if mime-use-selective-display is T."
  238.   (if mime-use-selective-display
  239.       (mime-hide-region start end t)))
  240.  
  241. (defun mime-mimify-message ()
  242.   "Add MIME headers to a message.  Add an initial informational message
  243. for mailreaders that don't process MIME automatically.  Add an initial
  244. area for plaintext.  Add a closing boundary at the end of the message.
  245. This function is safe to call more than once."
  246.   (interactive)
  247.   (let ((mail-header-separator (if (eq major-mode 'mh-letter-mode)
  248.                    "\n\n\\|^-+$"
  249.                  mail-header-separator)))
  250.     (or
  251.      (save-excursion
  252.        (goto-char (point-min))
  253.        (re-search-forward "^Mime-Version: "
  254.                           (save-excursion
  255.                             (goto-char (point-min))
  256.                             (re-search-forward mail-header-separator)
  257.                             (point))
  258.                           t))
  259.      (let ((mime-virgin-message (save-excursion
  260.                                   (next-line -1)
  261.                                   (looking-at mail-header-separator))))
  262.        (if mime-virgin-message
  263.            (insert "\n"))
  264.        ;; Configure selective-display if we want it...
  265.        (save-excursion
  266.          (save-excursion
  267.            (goto-char (point-min))
  268.            (re-search-forward mail-header-separator)
  269.            (beginning-of-line)
  270.            (insert "Mime-Version: 1.0\n")
  271.            (insert "Content-Type: multipart/mixed;\n")
  272.            (insert "\tboundary=" (mime-primary-boundary) "\n")
  273.            (next-line 1)
  274.            (let ((start (point)) end)
  275.              (insert "> THIS IS A MESSAGE IN 'MIME' FORMAT.\n")
  276.              (insert 
  277.               "> If you are reading this, your mail reader may not support MIME.\n")
  278.              (insert 
  279.               "> Some parts of this message will be readable as plain text.\n")
  280.              (setq end (point))
  281.              (mime-maybe-hide-region start (- end 1)))
  282.            (insert "\n")
  283.            (goto-char (point-max))
  284.            (insert "\n")
  285.            (insert "\n")
  286.            (insert "--" (mime-primary-boundary) "--\n"))
  287.          (save-excursion
  288.            (goto-char (point-min))
  289.            (re-search-forward mail-header-separator)
  290.            (beginning-of-line)
  291.            ;; THIS HAS TO MATCH the number of lines of text included
  292.            ;; as a message ``header'' above.
  293.            (if mime-use-selective-display
  294.                (next-line 3)
  295.              (next-line 5))
  296.            (insert "--" (mime-primary-boundary) "\n")
  297.            (insert "Content-type: text/plain\n")
  298.            (insert "\n"))
  299.          (if mime-virgin-message
  300.              (backward-delete-char 1)))))))
  301.  
  302. (defun mime-include-file (filename content-type binary)
  303.   "Include a file.  If third argument BINARY is T, then the file
  304. is binary; else it's text."
  305.   (mime-mimify-message)
  306.   (push-mark)
  307.   (insert "--" (mime-primary-boundary) "\n")
  308.   (insert "Content-type: " content-type "\n")
  309.   (if binary
  310.       (insert "Content-Transfer-Encoding: base64\n")
  311.     (insert "Content-Transfer-Encoding: quoted-printable\n"))
  312.   (insert "\n")
  313.   (let ((start (point)) end (seldisp selective-display))
  314.     (next-line 1)
  315.     (save-excursion
  316.       (next-line -1)
  317.       (insert-file filename))
  318.     (setq end (point))
  319.     (setq selective-display nil)
  320.     (if binary
  321.         (shell-command-on-region start end mime-encode-base64-command t)
  322.       (shell-command-on-region start end mime-encode-qp-command t))
  323.     (setq selective-display seldisp)
  324.     (setq end (point))
  325.     (mime-maybe-hide-region start (- end 1))
  326.     (insert "\n")
  327.     (insert "--" (mime-primary-boundary) "\n")
  328.     (insert "Content-type: text/plain\n")
  329.     (insert "\n\n")
  330.     (next-line -1)))
  331.  
  332. (defun mime-include-binary-file (filename content-type)
  333.   "Include a binary file at point in a MIME message.  Encode it
  334. in base64 mode."
  335.   (mime-include-file filename content-type t))
  336.  
  337. (defun mime-include-nonbinary-file (filename content-type)
  338.   "Include a nonbinary file at point in a MIME message.  Encode it
  339. in quoted-printable mode."
  340.   (mime-include-file filename content-type nil))
  341.  
  342. (defun mime-include-external (site directory name content-type description 
  343.                                    access-type)
  344.   "Include an external pointer in a MIME message."
  345.   (mime-mimify-message)
  346.   (insert "--" (mime-primary-boundary) "\n")
  347.   (insert "Content-type: message/external-body;\n")
  348.   (insert "\taccess-type=\"" access-type "\";\n")
  349.   (insert "\tsite=\"" site "\";\n")
  350.   (insert "\tdirectory=\"" directory "\";\n")
  351.   (insert "\tname=\"" name "\"\n")
  352.   (insert "Content-description: " description "\n")
  353.   (insert "\n")
  354.   (insert "Content-type: " content-type "\n")
  355.   (insert "\n")
  356.   (insert "\n")
  357.   (insert "--" (mime-primary-boundary) "\n")
  358.   (insert "Content-type: text/plain\n")
  359.   (insert "\n"))
  360.  
  361. (defun mime-include-external-anonftp (site directory name description)
  362.   "Include an external pointer (anonymous FTP) in a MIME message."
  363.   (interactive "sFTP site: \nsRemote directory name: \nsRemote filename: \nsDescription: ")
  364.   (let ((content-type 
  365.          (completing-read "Content type: " mime-valid-include-types
  366.                           nil nil nil)))
  367.     ;; Unadvertised default.
  368.     (if (string= content-type "")
  369.         (setq content-type "application/octet-stream"))
  370.     (mime-include-external site directory name content-type 
  371.                            description "anon-ftp")))
  372.  
  373. (defun mime-include-external-ftp (site directory name description)
  374.   "Include an external pointer (regular FTP) in a MIME message."
  375.   (interactive "sFTP site: \nsRemote directory name: \nsRemote filename: \nsDescription: ")
  376.   (let ((content-type 
  377.          (completing-read "Content type: " mime-valid-include-types
  378.                           nil nil nil)))
  379.     ;; Unadvertised default.
  380.     (if (string= content-type "")
  381.         (setq content-type "application/octet-stream"))
  382.     (mime-include-external site directory name content-type 
  383.                            description "ftp")))
  384.  
  385. (defun mime-include-xwd-dump ()
  386.   "Run xwd and include the results in a MIME message."
  387.   (interactive)
  388.   (mime-mimify-message)
  389.   (push-mark)
  390.   (insert "--" (mime-primary-boundary) "\n")
  391.   (insert "Content-type: image/x-xwd\n")
  392.   (insert "Content-Transfer-Encoding: base64\n")
  393.   (insert "\n")
  394.   (let ((start (point)) end (seldisp selective-display))
  395.     (next-line 1)
  396.     (save-excursion
  397.       (next-line -1)
  398.       (message "When crosshair cursor appears, click on window...")
  399.       (sit-for 0)
  400.       (call-process "/bin/sh" nil t nil "-c" mime-xwd-command)
  401.       (message "")
  402.       (sit-for 0))
  403.     (setq end (point))
  404.     (setq selective-display nil)
  405.     (shell-command-on-region start end mime-encode-base64-command t)
  406.     (setq selective-display seldisp)
  407.     (setq end (point))
  408.     (mime-maybe-hide-region start (- end 1))
  409.     (insert "\n")
  410.     (insert "--" (mime-primary-boundary) "\n")
  411.     (insert "Content-type: text/plain\n")
  412.     (insert "\n\n")
  413.     (next-line -1)))
  414.  
  415. (defvar mime-audio-file "/tmp/fooblatz")
  416. (defvar mime-audio-tmp-file "/tmp/fooblatz.aiff")
  417.  
  418. (defun mime-grab-audio-snippet ()
  419.   "Grab an audio snippet into hardcoded file /tmp/fooblatz.
  420. This only works on SGI Indigo's and PI/35's.  Contributed code
  421. for Sparcs and other platforms is more than welcome."
  422.   (let (audio-process done-flag)
  423.     (setq audio-process 
  424.           (start-process "snippet" "snippet" 
  425.                          "recordaiff" "-n" "1" "-s" "8" "-r" "8000"
  426.                          mime-audio-tmp-file))
  427.     ;; Quick hack to make Emacs sit until recording is done.
  428.     (setq done-flag
  429.           (y-or-n-p "Press y when done recording (n to abort): "))
  430.     (interrupt-process "snippet")
  431.     ;; Wait until recordaiff has written data to disk. */
  432.     (while (eq (process-status "snippet") 'run)
  433.       (message "Waiting...")
  434.       (sleep-for 1))
  435.     ;; Kill off recordaiff and our buffer.
  436.     (delete-process "snippet")
  437.     (kill-buffer "snippet")
  438.     ;; Remove the old mulaw file and do the conversion.
  439.     (call-process "/bin/rm" nil nil nil "-f" mime-audio-file)
  440.     (if done-flag
  441.         (call-process "/usr/sbin/sfconvert" nil nil nil mime-audio-tmp-file
  442.                       mime-audio-file "-o" "mulaw"))
  443.     (call-process "/bin/rm" nil nil nil "-f" mime-audio-tmp-file)
  444.     ;; Return done flag.  If nil, mime-include-audio-snippet should
  445.     ;; clean up.
  446.     done-flag))
  447.  
  448. (defun mime-include-audio-snippet ()
  449.   "Record a snippet of audio in a MIME message.  This will only work
  450. on SGI IRIS Indigo's and PI/35's."
  451.   (interactive)
  452.   (if (eq (mime-grab-audio-snippet) t)
  453.       (mime-include-binary-file mime-audio-file "audio/basic")))
  454.  
  455. (defun mime-include-gif (filename)
  456.   "Include a GIF file."
  457.   (interactive "fGIF image filename: ")
  458.   (mime-include-binary-file filename "image/gif"))
  459. (defun mime-include-jpeg (filename)
  460.   "Include a JPEG file."
  461.   (interactive "fJPEG image filename: ")
  462.   (mime-include-binary-file filename "image/jpeg"))
  463. (defun mime-include-audio (filename)
  464.   "Include an audio file."
  465.   (interactive "fAudio filename: ")
  466.   (mime-include-binary-file filename "audio/basic"))
  467. (defun mime-include-postscript (filename)
  468.   "Include a PostScript file."
  469.   (interactive "fPostScript filename: ")
  470.   (mime-include-nonbinary-file filename "application/postscript"))
  471. (defun mime-include-raw-binary (filename)
  472.   "Include a raw binary file."
  473.   (interactive "fRaw binary filename: ")
  474.   (let ((content-type 
  475.          (completing-read "Content type (RET for default): " 
  476.                           mime-valid-include-types
  477.                           nil nil nil)))
  478.     (if (string= content-type "")
  479.         (setq content-type "application/octet-stream"))
  480.     (mime-include-binary-file filename content-type)))
  481. (defun mime-include-raw-nonbinary (filename)
  482.   "Include a raw binary file."
  483.   (interactive "fRaw nonbinary filename: ")
  484.   (let ((content-type 
  485.          (completing-read "Content type (RET for default): " 
  486.                           mime-valid-include-types
  487.                           nil nil nil)))
  488.     (if (string= content-type "")
  489.         (setq content-type "text/plain"))
  490.     (mime-include-nonbinary-file filename content-type)))
  491.  
  492. ;;; -------------------------------- Keymaps ---------------------------------
  493.  
  494. ;;; Add functions to basic mail mode.
  495. (define-key mail-mode-map "\C-cm" 'mime-mimify-message)
  496. (define-key mail-mode-map "\C-cg" 'mime-include-gif)
  497. (define-key mail-mode-map "\C-cj" 'mime-include-jpeg)
  498. (define-key mail-mode-map "\C-ca" 'mime-include-audio)
  499. (define-key mail-mode-map "\C-cp" 'mime-include-postscript)
  500. (define-key mail-mode-map "\C-cr" 'mime-include-raw-binary)
  501. (define-key mail-mode-map "\C-cn" 'mime-include-raw-nonbinary)
  502. (define-key mail-mode-map "\C-cx" 'mime-include-xwd-dump)
  503. (define-key mail-mode-map "\C-ce" 'mime-include-external-anonftp)
  504. (define-key mail-mode-map "\C-cf" 'mime-include-external-ftp)
  505. (define-key mail-mode-map "\C-cs" 'mime-include-audio-snippet)
  506.  
  507. ;;; Add functions to MH letter mode.
  508. (if (boundp 'mh-letter-mode-map)
  509.     (if (or (not (boundp 'mh-letter-mode-mime-map)) 
  510.             (not mh-letter-mode-mime-map))
  511.         (progn
  512.           (setq mh-letter-mode-mime-map (make-sparse-keymap))
  513.           (define-key mh-letter-mode-map "\C-c\C-m" mh-letter-mode-mime-map)
  514.           (define-key mh-letter-mode-mime-map "m" 'mime-mimify-message)
  515.           (define-key mh-letter-mode-mime-map "g" 'mime-include-gif)
  516.           (define-key mh-letter-mode-mime-map "j" 'mime-include-jpeg)
  517.           (define-key mh-letter-mode-mime-map "a" 'mime-include-audio)
  518.           (define-key mh-letter-mode-mime-map "p" 'mime-include-postscript)
  519.           (define-key mh-letter-mode-mime-map "r" 'mime-include-raw-binary)
  520.           (define-key mh-letter-mode-mime-map "n" 'mime-include-raw-nonbinary)
  521.           (define-key mh-letter-mode-mime-map "x" 'mime-include-xwd-dump)
  522.           (define-key mh-letter-mode-mime-map "e" 
  523.             'mime-include-external-anonftp)
  524.           (define-key mh-letter-mode-mime-map "f" 
  525.             'mime-include-external-ftp)
  526.           (define-key mh-letter-mode-mime-map "s"
  527.             'mime-include-audio-snippet))))
  528.  
  529. ;;; -------------------------------- Menubar ---------------------------------
  530.  
  531. (defvar mime-running-lemacs (string-match "Lucid" emacs-version)
  532.   "Non-nil if running Lucid Emacs.")
  533.  
  534. ;; All we do at the moment is replace the popup menu defined in
  535. ;; Lucid Emacs 19.3's sendmail.el.
  536. (if mime-running-lemacs
  537.     (progn
  538.       (setq mail-mode-menu
  539.         '("Mail Mode"
  540.           "Sending Mail:"
  541.           "----"
  542.           ["Send and Exit"        mail-send-and-exit        t]
  543.           ["Send Mail"            mail-send            t]
  544.           ["Sent Via"            mail-sent-via            t]
  545.           "----"
  546.           "Go to Field:"
  547.           "----"
  548.           ["To:"            mail-to                t]
  549.           ["Subject:"            mail-subject            t]
  550.           ["CC:"            mail-cc                t]
  551.           ["BCC:"            mail-bcc            t]
  552.           ["Text"            mail-text            t]
  553.           "----"
  554.           "Miscellaneous Commands:"
  555.           "----"
  556.           ["Yank Original"        mail-yank-original        t]
  557.           ["Fill Yanked Message"    mail-fill-yanked-message    t]
  558.           ["Insert Signature"        mail-signature            t]
  559.           "----"
  560.           "MIME Inclusions:"
  561.           "----"
  562.           ["Include GIF File"           mime-include-gif                t]
  563.           ["Include JPEG File"          mime-include-jpeg               t]
  564.           ["Include Audio File"         mime-include-audio              t]
  565.           ["Include PostScript File"    mime-include-postscript         t]
  566.           ["Include XWD Dump"           mime-include-xwd-dump           t]
  567.           ["Include Audio Snippet"      mime-include-audio-snippet      t]
  568.           ["Include Raw Binary File"    mime-include-raw-binary         t]
  569.           ["Include Raw Nonbinary File" mime-include-raw-nonbinary      t]
  570.           ["Include External AnonFTP"   mime-include-external-anonftp   t]
  571.           ["Include External FTP"       mime-include-external-ftp       t]
  572.           "----"
  573.           ["Abort" kill-buffer t]
  574.           ))))
  575.  
  576. ;;; ----------------------------- New mail-send ------------------------------
  577.  
  578. ;; If we're not running Lemacs, pop in a new mail-send routine.
  579. (if (not mime-running-lemacs)
  580.     (defun mail-send ()
  581.       "Send the message in the current buffer.
  582. If  mail-interactive  is non-nil, wait for success indication
  583. or error messages, and inform user.
  584. Otherwise any failure is reported in a message back to
  585. the user from the mailer."
  586.       (interactive)
  587.       (message "Sending...")
  588.       (run-hooks 'mail-send-hook)
  589.       (funcall send-mail-function)
  590.       (set-buffer-modified-p nil)
  591.       (delete-auto-save-file-if-necessary)
  592.       (message "Sending...done")))
  593.  
  594. ;;; --------------------------------- Hooks ----------------------------------
  595.  
  596. ;; Author: Daniel LaLiberte (liberte@cs.uiuc.edu).
  597. (defun mime-postpend-unique-hook (hook-var hook-function)
  598.   "Postpend HOOK-VAR with HOOK-FUNCTION, if it is not already an element.
  599. hook-var's value may be a single function or a list of functions."
  600.   (if (boundp hook-var)
  601.       (let ((value (symbol-value hook-var)))
  602.         (if (and (listp value) (not (eq (car value) 'lambda)))
  603.             (and (not (memq hook-function value))
  604.                  (set hook-var (append value (list hook-function))))
  605.           (and (not (eq hook-function value))
  606.                (set hook-var (append value (list hook-function))))))
  607.     (set hook-var (list hook-function))))
  608.  
  609. (defun mime-unfrob-selective-display ()
  610.   "Turn off selective display throughout this buffer."
  611.   (if mime-use-selective-display
  612.       (progn
  613.         (message "Unfrobbing selective-display...")
  614.         (mime-hide-region (point-min) (point-max) nil))))
  615.  
  616. ;; Before the message is sent, remove the selective display crap.
  617. (mime-postpend-unique-hook 'mail-send-hook 'mime-unfrob-selective-display)
  618.  
  619. (defun mime-setup-hook-function ()
  620.   (if mime-use-selective-display
  621.       (setq selective-display t)))
  622.  
  623. ;; During mail setup, activate selective-display if necessary.
  624. (mime-postpend-unique-hook 'mail-setup-hook 'mime-setup-hook-function)
  625.  
  626. --
  627. Marc Andreessen
  628. Software Development Group
  629. National Center for Supercomputing Applications
  630. marca@ncsa.uiuc.edu
  631.