comparison lisp/packages/mime-compose.el @ 0:376386a54a3c r19-14

Import from CVS: tag r19-14
author cvs
date Mon, 13 Aug 2007 08:45:50 +0200
parents
children ec9a17fef872
comparison
equal deleted inserted replaced
-1:000000000000 0:376386a54a3c
1 ;;; File: --- mime-compose.el ---
2 ;;; Author: Marc Andreessen (marca@ncsa.uiuc.edu)
3 ;;; Additional code: Keith Waclena (k-waclena@uchicago.edu).
4 ;;; Christopher Davis (ckd@eff.org).
5 ;;; Copyright (C) National Center for Supercomputing Applications, 1992.
6 ;;;
7 ;;; This program is free software; you can redistribute it and/or modify
8 ;;; it under the terms of the GNU General Public License as published by
9 ;;; the Free Software Foundation; either version 1, or (at your option)
10 ;;; any later version.
11 ;;;
12 ;;; This program is distributed in the hope that it will be useful,
13 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ;;; GNU General Public License for more details.
16 ;;;
17 ;;; You should have received a copy of the GNU General Public License
18 ;;; along with your copy of Emacs; if not, write to the Free Software
19 ;;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 ;;;
21 ;;; Synched up with: Not in FSF.
22
23 ;;; -------------------------------- CONTENTS --------------------------------
24 ;;;
25 ;;; mime-compose: Utility routines for composing MIME-compliant mail.
26 ;;; !Revision: 1.5 !
27 ;;; !Date: 1994/03/24 00:00:47 !
28 ;;;
29 ;;; Canonical list of features:
30 ;;; Automatic MIME header construction.
31 ;;; Include GIF/JPEG image.
32 ;;; Include audio file.
33 ;;; Include PostScript file.
34 ;;; Include MPEG animation sequence.
35 ;;; Include raw binary/nonbinary file.
36 ;;; Include xwd window dump taken on the fly.
37 ;;; Include reference to anonymous/regular FTP.
38 ;;; Include audio snippet recorded on the fly.
39 ;;; Convert region to MIME richtext.
40 ;;; Convert region to any ISO 8859 charset.
41 ;;; Optional conversion of plaintext bodyparts to quoted-printable
42 ;;; with arbitrary charset when messages are sent.
43 ;;; Deemphasizing/highlighting of MIME headers.
44 ;;; Completion on content type and charset.
45 ;;; Automatic encoding in base64 and quoted-printable formats.
46 ;;; Selective display hides raw data.
47 ;;; Works with mail-mode and mh.
48 ;;;
49 ;;; ------------------------------ INSTRUCTIONS ------------------------------
50 ;;;
51 ;;; Use the normal Emacs mail composer (C-x m).
52 ;;;
53 ;;; (Or, use with Emacs mh-e by loading this file *after* loading mh-e.
54 ;;; But due to incestuous hookification, you can't require mime-compose
55 ;;; inside 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) function what happens
64 ;;; ~~~~~~~~~ (~~~~~~~~~) ~~~~~~~~ ~~~~~~~~~~~~
65 ;;; C-c g (C-c C-m g) mime-include-gif Add a GIF file.
66 ;;; C-c j (C-c C-m j) mime-include-jpeg Add a JPEG file.
67 ;;; C-c a (C-c C-m a) mime-include-audio Add an audio file.
68 ;;; C-c p (C-c C-m p) mime-include-postscript Add a PostScript file.
69 ;;; C-c v (C-c C-m v) mime-include-mpeg Add an MPEG file.
70 ;;;
71 ;;; (Note that mime-compose assumes you have the 'mmencode' program
72 ;;; installed on your system. See 'WHAT MIME IS' below for more
73 ;;; information on mmencode and the metamail distribution.)
74 ;;;
75 ;;; Some mime-compose commands create data themselves; these follow:
76 ;;;
77 ;;; C-c x (C-c C-m x)
78 ;;; mime-include-xwd-dump
79 ;;; Add the result of an X-window dump. The program named in
80 ;;; mime-xwd-command will be run, and the resulting dump will be
81 ;;; inserted into the message.
82 ;;; C-c s (C-c C-m s)
83 ;;; mime-include-audio-snippet
84 ;;; Add an audio snippet, recorded on the fly. CURRENTLY THIS WORKS
85 ;;; ONLY FOR SILICON GRAPHICS INDIGO AND 4D/35's. The Sun version
86 ;;; may also work; see the source code below. Recording begins
87 ;;; immediately; press 'y' to end recording or 'n' to abort the
88 ;;; whole process. The resulting audio file will be converted to
89 ;;; standard mulaw format and incorporated into the message.
90 ;;;
91 ;;; If you have a raw binary file and MIME or mime-compose doesn't
92 ;;; have built-in support for its format (e.g. an Emacs Lisp
93 ;;; byte-compiled file), you can use:
94 ;;;
95 ;;; C-c r (C-c C-m r)
96 ;;; mime-include-raw-binary
97 ;;; Add a raw binary file. You will be prompted for both the
98 ;;; filename and the content type of the file; if you do not give a
99 ;;; content type, the default (application/octet-stream) will be
100 ;;; used, and the recipient will be able to have his/her MIME mail
101 ;;; handler extract the raw binary file from the message.
102 ;;;
103 ;;; Similarly, to include nonbinary (text) files using
104 ;;; quoted-printable encoding, use:
105 ;;;
106 ;;; C-c n (C-c C-m n)
107 ;;; mime-include-raw-nonbinary
108 ;;; Add a raw nonbinary (text) file. You will be prompted for both
109 ;;; the filename and the content type of the file (which defaults to
110 ;;; text/plain). With prefix arg, you will also be prompted for the
111 ;;; character set (default is US-ASCII).
112 ;;;
113 ;;; You can also point to external elements: files that will not be
114 ;;; included in the document, but can be accessed by the recipient in
115 ;;; some other way (most commonly, via FTP). The following commands
116 ;;; handle this:
117 ;;;
118 ;;; C-c e (C-c C-m e)
119 ;;; mime-include-external-anonftp
120 ;;; Point to an external file (assumed to be accessable via
121 ;;; anonymous FTP). You will be prompted for the name of the FTP
122 ;;; site, the remote directory name, and remote filename, the remote
123 ;;; file's content type, and a description of the remote file.
124 ;;; C-c f (C-c C-m f)
125 ;;; mime-include-external-ftp
126 ;;; This is the same as 'C-c e', except that the file will be
127 ;;; accessed via regular FTP rather than anonymous FTP -- a username
128 ;;; and password will have to be provided by the recipient to gain
129 ;;; access to the file.
130 ;;;
131 ;;; Note that whenever you are prompted for a content type, Emacs'
132 ;;; completion feature is active: press TAB for a list of valid types.
133 ;;; You can also enter a type not in the completion list.
134 ;;;
135 ;;; If you type in text that belongs in a character set other than the
136 ;;; default (US-ASCII), you can use the following function to encode
137 ;;; the text and generate appropriate MIME headers:
138 ;;;
139 ;;; C-c C-r i (C-c C-m C-r i)
140 ;;; mime-region-to-charset
141 ;;; Encode region in an alternate character set. (MIME only
142 ;;; sanctions the use of ISO charsets; thus, the command key for
143 ;;; this function is 'i'.) You will be prompted for a character set
144 ;;; (minibuffer completion is provided).
145 ;;;
146 ;;; MIME also defines a 'richtext' format; you can encode the current
147 ;;; region as richtext with:
148 ;;;
149 ;;; C-c C-r r (C-c C-m C-r r)
150 ;;; mime-region-to-richtext
151 ;;; Encode region as richtext. With prefix arg, you will be
152 ;;; prompted for a character set, else the default (US-ASCII) is
153 ;;; used.
154 ;;;
155 ;;; If you regularly use 8-bit characters in your messages, you will
156 ;;; probably want all of your plaintext bodyparts automatically
157 ;;; encoded in quoted-printable and labeled as belonging to the
158 ;;; character set that you're using when a message is sent. To have
159 ;;; this happen, set this variable:
160 ;;;
161 ;;; mime-encode-plaintext-on-send (variable, default NIL)
162 ;;; If T, all text/plain bodyparts in the message will be encoded in
163 ;;; quoted-printable and labeled with charset mime-default-charset
164 ;;; (by default, US-ASCII) when a message is sent. If NIL,
165 ;;; text/plain bodyparts will not be touched.
166 ;;;
167 ;;; ---------------------------- ADDITIONAL NOTES ----------------------------
168 ;;;
169 ;;; mime-compose uses Emacs' selective-display feature: only the first
170 ;;; line of any encoded data file will be displayed, followed by
171 ;;; ellipses (indicating that some data is not being shown). See the
172 ;;; variable 'mime-use-selective-display' below.
173 ;;;
174 ;;; If you are running XEmacs/Lucid Emacs, the mail-mode popup menu (attached
175 ;;; to the third mouse button) will include mime-compose entries.
176 ;;;
177 ;;; If you are running XEmacs/Lucid Emacs or Epoch, highlighting will be used
178 ;;; to deemphasize the various MIME headers (but emphasize the various
179 ;;; MIME content types). You can turn this feature off; see the
180 ;;; variable 'mime-use-highlighting'.
181 ;;;
182 ;;; After your message has been `mimified' (by including a MIME
183 ;;; element), it is best not to put trailing text outside the final
184 ;;; boundary at the end of the file -- such text will not be
185 ;;; considered to be part of the message by MIME-compliant mail
186 ;;; readers (although it will still be sent).
187 ;;;
188 ;;; As you compose a complex MIME message, you may notice useless
189 ;;; bodyparts accumulating: extra text/plain bodyparts, in particular,
190 ;;; containing no text. These bodyparts will be stripped from the
191 ;;; message before the message is sent, so you (and I) won't look like
192 ;;; a moron to the recipient.
193 ;;;
194 ;;; A command that usually isn't necessary, but is provided in case
195 ;;; you wish to send a plaintext message with the various MIME headers
196 ;;; and boundaries, is:
197 ;;;
198 ;;; C-c m (C-c C-m m) mime-mimify-message Mimify a message.
199 ;;;
200 ;;; MIME messages can contain elements and structures not yet
201 ;;; supported by mime-compose. If you have ideas or code for support
202 ;;; that should be provided by mime-compose, please send them to the
203 ;;; author.
204 ;;;
205 ;;; ------------------------ WHAT MIME-COMPOSE IS NOT ------------------------
206 ;;;
207 ;;; mime-compose is not a MIME message handler. It will not interpret
208 ;;; MIME messages, display images, or anything similar.
209 ;;;
210 ;;; mime-compose is not intelligent enough (yet) to construct complex
211 ;;; MIME messages (with nested boundaries, parallel message elements,
212 ;;; and so on).
213 ;;;
214 ;;; mime-compose will not enforce correctness (MIME compliance) on
215 ;;; your messages. mime-compose generates MIME-compliant message
216 ;;; elements, but will sit quietly if you alter them or add your own
217 ;;; incorrect elements.
218 ;;;
219 ;;; In particular, note that the MIME specification demands a blank
220 ;;; line following the Content declarations for a bodypart.
221 ;;; mime-compose will give you that blank line, but will not demand
222 ;;; that you leave it blank; if you don't, your message will not be
223 ;;; happy.
224 ;;;
225 ;;; ------------------------------ WHAT MIME IS ------------------------------
226 ;;;
227 ;;; MIME defines a format for email messages containing non-plaintext
228 ;;; elements (images, audio, etc.). MIME is detailed in Internet RFC
229 ;;; 1341, by N. Borenstein and N. Freed. You can FTP this RFC from
230 ;;; many archive sites, including uxc.cso.uiuc.edu.
231 ;;;
232 ;;; Few mail readers handle MIME messages, yet. However, most popular
233 ;;; mail readers can be easily patched to feed MIME messages to a
234 ;;; program called 'metamail', which can handle MIME messages. You
235 ;;; can FTP metamail from thumper.bellcore.com in /pub/nsb as
236 ;;; mm.tar.Z. Since mime-compose requires the existence of the
237 ;;; program 'mmencode' (from the metamail distribution) to insert
238 ;;; binary and nonbinary files into messages, it is a Good Idea to
239 ;;; have metamail installed on your system.
240 ;;;
241 ;;; --------------------------------------------------------------------------
242 ;;; LCD Archive Entry:
243 ;;; mime-compose|Marc Andreessen|marca@ncsa.uiuc.edu|
244 ;;; MIME-compliant message generation utilities.|
245 ;;; !Date: 1994/03/24 00:00:47 !|!Revision: 1.5 !|~/misc/mime-compose.el.Z|
246 ;;; --------------------------------------------------------------------------
247
248 (provide 'mime-compose)
249
250 (defvar mime-running-mh-e (featurep 'mh-e)
251 "Non-nil if running under mh-e.")
252
253 (if (not mime-running-mh-e)
254 (require 'sendmail))
255
256 ;;; ---------------------- User-customizable variables -----------------------
257
258 (defvar mime-compose-hook nil
259 "*Invoked exactly once by first invocation of mime-mimify-message,
260 before any processing is done.")
261
262 (defvar mime-use-selective-display t
263 "*Flag for using selective-display to hide bodies of MIME enclosures.
264 If non-NIL, selective-display will be used; if NIL, it will not be used.")
265
266 (defvar mime-default-charset "US-ASCII"
267 "*Default character set for MIME messages elements. According to the
268 MIME specification, this can be either US-ASCII or ISO-8859-x, where x
269 must be between 1 and 9 inclusive.")
270
271 (defvar mime-encode-plaintext-on-send nil
272 "*Non-NIL if plaintext bodyparts should be encoded in quoted-printable
273 and labeled with mime-default-charset when a message is sent; NIL
274 otherwise.")
275
276 (defvar mime-use-highlighting t
277 "*Flag to use highlighting for MIME headers and content types in
278 Epoch or XEmacs/Lucid Emacs; if non-NIL, highlighting will be used.")
279
280 (defvar mime-deemphasize-color "grey80"
281 "*Color for de-highlighting MIME headers in Epoch or XEmacs/Lucid Emacs.")
282
283 (defvar mime-emphasize-color "yellow"
284 "*Color for highlighting MIME content types in Epoch or XEmacs/Lucid Emacs.")
285
286 (defvar mime-name-included-files t
287 "*If non-NIL, use name attribute for included files.")
288
289 (defvar mime-use-waiting-messages t
290 "*If non-NIL, enable waiting messages feature.")
291
292 (defvar mime-primary-boundary "mysteryboxofun"
293 "*Word used as the primary MIME boundary.")
294
295 (defvar mime-xwd-command "xwd -frame"
296 "*Command used to do a window dump under the X Window System.")
297
298 (defvar mime-encode-base64-command "mmencode"
299 "*Command used to encode data in base64 format.")
300
301 (defvar mime-encode-qp-command "mmencode -q"
302 "*Command used to encode data in quoted-printable format.")
303
304 (defvar mime-babbling-description "talking"
305 "*Adjective(s) (or gerunds; I never could tell them apart) applying to
306 audio snippets.")
307
308 (defvar mime-sgi-record-program "/usr/sbin/recordaiff"
309 "*Full name of SGI audio record program.")
310
311 (defvar mime-sun-record-program "/usr/demo/SOUND/record"
312 "*Full name of Sun audio record program, patched with the context
313 diff found at the end of mime-compose.el.")
314
315 ;;; ---------------------------- Other variables -----------------------------
316
317 (defvar mime-compose-hook-was-run nil
318 "NIL implies we haven't yet run mime-compose-hook.")
319
320 (defvar mime-valid-include-types
321 '(("image/gif" 1)
322 ("image/jpeg" 2)
323 ("application/postscript" 3)
324 ("application/andrew-inset" 4)
325 ("application/octet-stream" 5)
326 ("text/richtext" 6)
327 ("text/plain" 7)
328 ("audio/basic" 8)
329 ("video/mpeg" 9)
330 ("message/rfc822" 10)
331 ;; These aren't ``standard'', but are useful.
332 ("application/x-emacs-lisp" 11)
333 ("application/x-unix-tar-z" 12)
334 ("application/x-dvi" 13)
335 ("image/x-xbm" 14)
336 ("image/x-xwd" 15)
337 ("image/x-tiff" 16)
338 ("audio/x-aiff" 17)
339 ("text/x-html" 18))
340 "A list of valid content types for minibuffer completion.")
341
342 (defvar mime-valid-charsets
343 '(("US-ASCII" 1)
344 ("ISO-8859-1" 2)
345 ("ISO-8859-2" 3)
346 ("ISO-8859-3" 4)
347 ("ISO-8859-4" 5)
348 ("ISO-8859-5" 6)
349 ("ISO-8859-6" 7)
350 ("ISO-8859-7" 8)
351 ("ISO-8859-8" 9)
352 ("ISO-8859-9" 10))
353 "A list of valid charset names for minibuffer completion.")
354
355 (defvar mime-using-silicon-graphics
356 (or (eq system-type 'silicon-graphics-unix) (eq system-type 'irix))
357 "Flag to indicate use of Silicon Graphics platform. If T, Emacs is being
358 run on a Silicon Graphics workstation; else it is not.")
359
360 (defvar mime-running-lemacs (string-match "XEmacs\\|Lucid" emacs-version)
361 "Non-nil if running XEmacs/Lucid Emacs.")
362
363 (defvar mime-running-epoch (boundp 'epoch::version)
364 "Non-nil if running Epoch.")
365
366 (if (and mime-running-epoch mime-use-highlighting)
367 (progn
368 (defvar mime-deemphasize-style (make-style))
369 (set-style-foreground mime-deemphasize-style mime-deemphasize-color)
370 (defvar mime-emphasize-style (make-style))
371 (set-style-foreground mime-emphasize-style mime-emphasize-color)))
372
373 (if (and mime-running-lemacs mime-use-highlighting)
374 (progn
375 (defvar mime-deemphasize-style (make-face 'mime-deemphasize-face))
376 (set-face-foreground mime-deemphasize-style mime-deemphasize-color)
377 (defvar mime-emphasize-style (make-face 'mime-emphasize-face))
378 (set-face-foreground mime-emphasize-style mime-emphasize-color)))
379
380 (defvar mime-audio-file "/tmp/.fooblatz"
381 "Filename to store audio snippets recorded on the fly.")
382
383 (defvar mime-audio-tmp-file "/tmp/.fooblatz.aiff"
384 "Filename to store audio snippets recorded on the fly.")
385
386 (defconst mime-waiting-message-lines
387 '("Mail mime-compose bug reports to marca@ncsa.uiuc.edu and pray for help."
388 "For the daring: ftp.ncsa.uiuc.edu:/outgoing/marca/mime-compose.el"
389 "Feature requests? Fervent wishes? Unfulfilled desires? Write code!"
390 "mime-compose.el: the Kitchen Sink(tm) of mail composers."
391 "Q: How many Elisp hackers does it take to change a light bulb?"
392 "A: None -- we glow in the dark."
393 ".gnol oot yaw rof scamE gnisu neeb ev'uoy ,siht daer nac uoy fI"
394 "Macs? We don' need no steenkin Macs! We got MIME!"
395 "All hail MIME. All hail MIME. Yay. Yay. Woo. Woo.")
396 "List of stupid strings to display while waiting for more to do.")
397
398 ;;; --------------------------- Utility functions ----------------------------
399
400 (defun mime-primary-boundary ()
401 "Return the current primary boundary. Note that in the current version
402 of mime-compose.el, there is no support for secondary boundaries (for
403 parallel or alternate bodyparts, etc.). In the future, there may be."
404 mime-primary-boundary)
405
406 (defun mime-hide-region (from to hideflag)
407 "Hides or shows lines from FROM to TO, according to HIDEFLAG:
408 If T, region is hidden, else if NIL, region is shown."
409 (let ((old (if hideflag ?\n ?\^M))
410 (new (if hideflag ?\^M ?\n))
411 (modp (buffer-modified-p)))
412 (unwind-protect (progn
413 (subst-char-in-region from to old new t))
414 (set-buffer-modified-p modp))))
415
416 (defun mime-maybe-hide-region (start end)
417 "Hide the current region if mime-use-selective-display is T."
418 (if mime-use-selective-display
419 (mime-hide-region start end t)))
420
421 (defun mime-add-description (description)
422 "Add a description to the current MIME message element."
423 (interactive "sDescription: ")
424 (save-excursion
425 (if (re-search-backward (concat "--" (mime-primary-boundary))
426 (point-min) t)
427 (progn
428 (next-line 2)
429 (insert "Content-Description: " description "\n")))))
430
431 (defun mime-display-waiting-messages ()
432 "Display cute messages until input arrives. Shamelessly stolen
433 from VM, the Kitchen Sink(tm) of mail readers."
434 (if mime-use-waiting-messages
435 (progn
436 (if (sit-for 2)
437 (let ((lines mime-waiting-message-lines))
438 (message
439 "mime-compose.el !Revision: 1.5 !, by marca@ncsa.uiuc.edu")
440 (while (and (sit-for 4) lines)
441 (message (car lines))
442 (setq lines (cdr lines)))))
443 (message "")
444 (if (not (input-pending-p))
445 (progn
446 (sit-for 2)
447 ;; TODO: Don't recurse; iterate.
448 (if (not (input-pending-p))
449 (mime-display-waiting-messages)))))))
450
451 ;;; ------------------------------ Highlighting ------------------------------
452
453 (if mime-use-highlighting
454 (progn
455 (if mime-running-lemacs
456 (defun mime-add-zone (start end style)
457 "Add a XEmacs/Lucid Emacs extent from START to END with STYLE."
458 (let ((extent (make-extent start end)))
459 (set-extent-face extent style)
460 (set-extent-property extent 'mime-compose t))))
461 (if mime-running-epoch
462 (defun mime-add-zone (start end style)
463 "Add an Epoch zone from START to END with STYLE."
464 (let ((zone (add-zone start end style)))
465 (epoch::set-zone-data zone 'mime-compose))))))
466
467 (defun mime-maybe-highlight-region (start end)
468 "Maybe highlight a region of text. Region is from START to END."
469 (if (and (or mime-running-epoch mime-running-lemacs)
470 mime-use-highlighting)
471 (progn
472 (mime-add-zone start end mime-deemphasize-style)
473 (save-excursion
474 (goto-char start)
475 (if (re-search-forward "Content-Type: " end t)
476 (let ((s (match-end 0)))
477 (re-search-forward "[;\n]")
478 (mime-add-zone
479 s (- (match-end 0) 1) mime-emphasize-style)))))))
480
481 ;;; -------------------------- mime-mimify-message ---------------------------
482
483 (defun mime-mimify-message ()
484 "Add MIME headers to a message. Add an initial informational message
485 for mail readers that don't process MIME messages automatically. Add
486 an initial area for plaintext. Add a closing boundary at the end of
487 the message.
488
489 This function is safe to call more than once."
490 (interactive)
491 (if (not mime-compose-hook-was-run)
492 (progn
493 (setq mime-compose-hook-was-run t)
494 (run-hooks 'mime-compose-hook)))
495 (let ((mail-header-separator (if (eq major-mode 'mh-letter-mode)
496 "\n\n\\|^-+$"
497 mail-header-separator)))
498 (or
499 (save-excursion
500 (goto-char (point-min))
501 (re-search-forward "^Mime-Version: "
502 (save-excursion
503 (goto-char (point-min))
504 (re-search-forward mail-header-separator)
505 (point))
506 t))
507 (let ((mime-virgin-message (save-excursion
508 (next-line -1)
509 (looking-at mail-header-separator))))
510 (if mime-virgin-message
511 (insert "\n"))
512 (save-excursion
513 (save-excursion
514 (goto-char (point-min))
515 (re-search-forward mail-header-separator)
516 (beginning-of-line)
517 (insert "Mime-Version: 1.0\n")
518 (insert "Content-Description: A MIME message created by mime-compose.el.\n")
519 (insert "Content-Type: multipart/mixed; boundary=" (mime-primary-boundary) "\n")
520 (mime-maybe-highlight-region (save-excursion (next-line -3) (point))
521 (- (point) 1))
522 (next-line 1)
523 (let ((start (point)) end)
524 (insert "> THIS IS A MESSAGE IN 'MIME' FORMAT.\n")
525 (insert
526 "> If you are reading this, your mail reader may not support MIME.\n")
527 (insert
528 "> Some parts of this message will be readable as plain text.\n")
529 (setq end (point))
530 (mime-maybe-hide-region start (- end 1)))
531 (insert "\n")
532 (goto-char (point-max))
533 (insert "\n")
534 (insert "\n")
535 (insert "--" (mime-primary-boundary) "--\n")
536 (mime-maybe-highlight-region (save-excursion (next-line -1) (point))
537 (- (point) 1)))
538 (save-excursion
539 (goto-char (point-min))
540 (re-search-forward mail-header-separator)
541 (beginning-of-line)
542 ;; THIS HAS TO MATCH the number of lines of text included
543 ;; as a message ``header'' above.
544 (if mime-use-selective-display
545 (next-line 3)
546 (next-line 5))
547 (insert "--" (mime-primary-boundary) "\n")
548 (insert "Content-Type: text/plain\n")
549 (mime-maybe-highlight-region
550 (save-excursion (next-line -2) (point))
551 (- (point) 1))
552 (insert "\n"))
553 (if mime-virgin-message
554 (backward-delete-char 1))))))
555 (if (interactive-p)
556 (mime-display-waiting-messages)))
557
558 (defun mime-open-text-bodypart ()
559 "At current point, just open up a new plaintext bodypart."
560 (interactive)
561 (mime-mimify-message)
562 (push-mark)
563 (let ((start (point)) end)
564 (insert "--" (mime-primary-boundary) "\n")
565 (insert "Content-Type: text/plain")
566 (setq end (point))
567 (insert "\n\n")
568 (mime-maybe-highlight-region start end))
569 (mime-display-waiting-messages))
570
571 ;;; ---------------------------- file inclusions -----------------------------
572
573 (defun mime-include-file (filename content-type binary &optional charset)
574 "Include a file named by FILENAME and with MIME content type
575 CONTENT-TYPE. If third argument BINARY is T, then the file is binary;
576 else it's text. Optional fourth arg CHARSET names character set for
577 data. Data will be encoded in base64 or quoted-printable format as
578 appropriate."
579 (mime-mimify-message)
580 (push-mark)
581 (insert "--" (mime-primary-boundary) "\n")
582 (insert "Content-Type: " content-type)
583 (if charset
584 (insert "; charset=" charset))
585 (if (and mime-name-included-files (not (string= filename mime-audio-file)))
586 (insert "; name=\"" (file-name-nondirectory filename) "\""))
587 (insert "\n")
588 (if (not (string= filename mime-audio-file))
589 (insert "Content-Description: " filename "\n"))
590 (if binary
591 (insert "Content-Transfer-Encoding: base64\n")
592 (insert "Content-Transfer-Encoding: quoted-printable\n"))
593 (mime-maybe-highlight-region
594 (save-excursion (re-search-backward
595 (concat "--" (mime-primary-boundary))) (point))
596 (- (point) 1))
597 (let ((start (point)) end (seldisp selective-display))
598 (next-line 1)
599 (save-excursion
600 (next-line -1)
601 (insert-file filename))
602 (setq end (- (point) 1))
603 (setq selective-display nil)
604 (if binary
605 (shell-command-on-region start end mime-encode-base64-command t)
606 (shell-command-on-region start end mime-encode-qp-command t))
607 (setq selective-display seldisp)
608 (setq end (point))
609 (mime-maybe-hide-region start (- end 1))
610 (insert "\n")
611 (insert "--" (mime-primary-boundary) "\n")
612 (insert "Content-Type: text/plain\n")
613 (mime-maybe-highlight-region
614 (save-excursion (re-search-backward
615 (concat "--" (mime-primary-boundary))) (point))
616 (- (point) 1))
617 (insert "\n\n")
618 (next-line -1)))
619
620 (defun mime-include-binary-file (filename content-type)
621 "Include a binary file named by FILENAME at point in a MIME message.
622 CONTENT-TYPE names MIME content type of file. Data will be encoded in
623 base64 format."
624 (mime-include-file filename content-type t))
625
626 (defun mime-include-nonbinary-file (filename content-type &optional charset)
627 "Include a nonbinary file named by FILENAME at point in a MIME
628 message. CONTENT-TYPE names MIME content type of file; optional third
629 arg CHARSET names MIME character set. Data will be encoded in
630 quoted-printable format."
631 (mime-include-file filename content-type nil charset))
632
633 ;;; -------------------------- external references ---------------------------
634
635 (defun mime-include-external (site directory name content-type description
636 access-type)
637 "Include an external pointer in a MIME message. Args are SITE,
638 DIRECTORY, NAME, CONTENT-TYPE, DESCRIPTION, and ACCESS-TYPE; these are
639 all strings."
640 (mime-mimify-message)
641 (push-mark)
642 (insert "--" (mime-primary-boundary) "\n")
643 (insert "Content-Type: message/external-body;\n")
644 (insert "\taccess-type=\"" access-type "\";\n")
645 (insert "\tsite=\"" site "\";\n")
646 (insert "\tdirectory=\"" directory "\";\n")
647 (insert "\tname=\"" name "\"\n")
648 (insert "Content-Description: " description "\n")
649 (insert "\n")
650 (insert "Content-Type: " content-type "\n")
651 (mime-maybe-highlight-region
652 (save-excursion (re-search-backward
653 (concat "--" (mime-primary-boundary))) (point))
654 (- (point) 1))
655 (insert "\n")
656 (insert "\n")
657 (insert "--" (mime-primary-boundary) "\n")
658 (insert "Content-Type: text/plain\n")
659 (mime-maybe-highlight-region
660 (save-excursion (re-search-backward
661 (concat "--" (mime-primary-boundary))) (point))
662 (- (point) 1))
663 (insert "\n"))
664
665 (defun mime-include-external-anonftp (site directory name description)
666 "Include an external pointer (anonymous FTP) in a MIME message. Args
667 are SITE, DIRECTORY, NAME, and DESCRIPTION; these are all strings, and
668 if interactive, will be prompted for."
669 (interactive
670 "sFTP site: \nsRemote directory name: \nsRemote filename: \nsDescription: ")
671 (let ((content-type
672 (completing-read "Content type: " mime-valid-include-types
673 nil nil nil)))
674 ;; Unadvertised default.
675 (if (string= content-type "")
676 (setq content-type "application/octet-stream"))
677 (mime-include-external site directory name content-type
678 description "anon-ftp"))
679 (mime-display-waiting-messages))
680
681 (defun mime-include-external-ftp (site directory name description)
682 "Include an external pointer (regular FTP) in a MIME message. Args
683 are SITE, DIRECTORY, NAME, and DESCRIPTION; these are all strings, and
684 if interactive, will be prompted for."
685 (interactive
686 "sFTP site: \nsRemote directory name: \nsRemote filename: \nsDescription: ")
687 (let ((content-type
688 (completing-read "Content type: " mime-valid-include-types
689 nil nil nil)))
690 ;; Unadvertised default.
691 (if (string= content-type "")
692 (setq content-type "application/octet-stream"))
693 (mime-include-external site directory name content-type
694 description "ftp"))
695 (mime-display-waiting-messages))
696
697 ;;; ------------------------------ window dumps ------------------------------
698
699 (defun mime-include-xwd-dump ()
700 "Run program named by 'mime-xwd-command' and include the results in
701 a MIME message."
702 (interactive)
703 (mime-mimify-message)
704 (push-mark)
705 (insert "--" (mime-primary-boundary) "\n")
706 (insert "Content-Type: image/x-xwd\n")
707 (insert "Content-Description: Window dump from " (system-name) "\n")
708 (insert "Content-Transfer-Encoding: base64\n")
709 (mime-maybe-highlight-region
710 (save-excursion (re-search-backward
711 (concat "--" (mime-primary-boundary))) (point))
712 (- (point) 1))
713 (insert "\n")
714 (let ((start (point)) end (seldisp selective-display))
715 (next-line 1)
716 (save-excursion
717 (next-line -1)
718 (message "When crosshair cursor appears, click on window...")
719 (sit-for 0)
720 (call-process "/bin/sh" nil t nil "-c" mime-xwd-command)
721 (message "")
722 (sit-for 0))
723 (setq end (point))
724 (setq selective-display nil)
725 (shell-command-on-region start end mime-encode-base64-command t)
726 (setq selective-display seldisp)
727 (setq end (point))
728 (mime-maybe-hide-region start (- end 1))
729 (insert "\n")
730 (insert "--" (mime-primary-boundary) "\n")
731 (insert "Content-Type: text/plain\n")
732 (mime-maybe-highlight-region
733 (save-excursion (re-search-backward
734 (concat "--" (mime-primary-boundary))) (point))
735 (- (point) 1))
736 (insert "\n\n")
737 (next-line -1))
738 (mime-display-waiting-messages))
739
740 ;;; ----------------------------- audio snippets -----------------------------
741
742 (defun mime-sgi-grab-audio-snippet ()
743 "Grab an audio snippet into file named in 'mime-audio-file'.
744 This routine works on SGI Indigo's and 4D/35's."
745 (let (audio-process done-flag)
746 (setq audio-process
747 (start-process "snippet" "snippet"
748 mime-sgi-record-program "-n" "1" "-s" "8" "-r" "8000"
749 mime-audio-tmp-file))
750 ;; Quick hack to make Emacs sit until recording is done.
751 (setq done-flag
752 (y-or-n-p "Press y when done recording (n to abort): "))
753 (interrupt-process "snippet")
754 ;; Wait until recordaiff has written data to disk.
755 (while (eq (process-status "snippet") 'run)
756 (message "Waiting...")
757 (sleep-for 1))
758 (message "Done waiting.")
759 ;; Kill off recordaiff and our buffer.
760 (delete-process "snippet")
761 (kill-buffer "snippet")
762 ;; Remove the old mulaw file and do the conversion.
763 (call-process "/bin/rm" nil nil nil "-f" mime-audio-file)
764 (if done-flag
765 (call-process "/usr/sbin/sfconvert" nil nil nil mime-audio-tmp-file
766 mime-audio-file "-o" "mulaw"))
767 (call-process "/bin/rm" nil nil nil "-f" mime-audio-tmp-file)
768 ;; Return done flag. If nil, mime-include-audio-snippet should
769 ;; clean up.
770 done-flag))
771
772 (defun mime-sun-grab-audio-snippet ()
773 "Grab an audio snippet into file named in 'mime-audio-file'.
774 This is the Sun version. I don't know how well it works. It also
775 requires a patched version of /usr/demo/SOUND/record.c; see the
776 context diff at the end of mime-compose.el.
777
778 Courtesy Christopher Davis <ckd@eff.org>."
779 (let (audio-process done-flag)
780 (setq audio-process
781 (start-process "snippet" "snippet"
782 mime-sun-record-program "-m" mime-audio-file))
783 ;; Quick hack to make Emacs sit until recording is done.
784 (setq done-flag
785 (y-or-n-p "Press y when done recording (n to abort): "))
786 (interrupt-process "snippet")
787 ;; Wait until the record process is done.
788 (while (eq (process-status "snippet") 'run)
789 (message "Waiting...")
790 (sleep-for 1))
791 (message "Done waiting.")
792 ;; Kill off the record process and our buffer.
793 (delete-process "snippet")
794 (kill-buffer "snippet")
795 ;; Return done flag. If nil, mime-include-audio-snippet should
796 ;; clean up.
797 done-flag))
798
799 (defun mime-include-audio-snippet ()
800 "Record a snippet of audio in a MIME message. This should work on
801 both Silicon Graphics and Sun platforms. Code contributions for other
802 platforms are welcome."
803 (interactive)
804 (let ((mime-grab-audio-snippet
805 (if mime-using-silicon-graphics
806 'mime-sgi-grab-audio-snippet
807 'mime-sun-grab-audio-snippet)))
808 (if (eq (funcall mime-grab-audio-snippet) t)
809 (progn
810 (mime-include-binary-file mime-audio-file "audio/basic")
811 (save-excursion
812 (next-line -4)
813 (mime-add-description
814 (concat (user-full-name) " "
815 mime-babbling-description "."))))))
816 (mime-display-waiting-messages))
817
818 ;;; ------------------------- Basic include commands -------------------------
819
820 (defun mime-include-gif (filename)
821 "Include a GIF file named by FILENAME."
822 (interactive "fGIF image filename: ")
823 (mime-include-binary-file filename "image/gif")
824 (mime-display-waiting-messages))
825
826 (defun mime-include-jpeg (filename)
827 "Include a JPEG file named by FILENAME."
828 (interactive "fJPEG image filename: ")
829 (mime-include-binary-file filename "image/jpeg")
830 (mime-display-waiting-messages))
831
832 (defun mime-include-audio (filename &optional prefix-arg)
833 "Include an audio file named by FILENAME. Note that to match the
834 MIME specification for audio/basic, this should be an 8-bit mulaw file.
835 With prefix arg, use AIFF format (unofficial MIME subtype audio/x-aiff)
836 instead of audio/basic."
837 (interactive "fAudio filename: \nP")
838 (if prefix-arg
839 (mime-include-binary-file filename "audio/x-aiff")
840 (mime-include-binary-file filename "audio/basic"))
841 (mime-display-waiting-messages))
842
843 (defun mime-include-mpeg (filename)
844 "Include a MPEG file named by FILENAME."
845 (interactive "fMPEG animation filename: ")
846 (mime-include-binary-file filename "video/mpeg")
847 (mime-display-waiting-messages))
848
849 (defun mime-include-postscript (filename)
850 "Include a PostScript file named by FILENAME."
851 (interactive "fPostScript filename: ")
852 (mime-include-nonbinary-file filename "application/postscript")
853 (mime-display-waiting-messages))
854
855 (defun mime-include-raw-binary (filename)
856 "Include a raw binary file named by FILENAME."
857 (interactive "fRaw binary filename: ")
858 (let ((content-type
859 (completing-read "Content type (RET for default): "
860 mime-valid-include-types
861 nil nil nil)))
862 (if (string= content-type "")
863 (setq content-type "application/octet-stream"))
864 (mime-include-binary-file filename content-type))
865 (mime-display-waiting-messages))
866
867 (defun mime-include-raw-nonbinary (filename &optional prefix-arg)
868 "Include a raw nonbinary file named by FILENAME. With prefix arg,
869 prompt for character set."
870 (interactive "fRaw nonbinary filename: \nP")
871 (let ((charset
872 (if prefix-arg
873 (completing-read "Character set: " mime-valid-charsets
874 nil nil nil)
875 mime-default-charset))
876 (content-type
877 (completing-read "Content type (RET for default): "
878 mime-valid-include-types
879 nil nil nil)))
880 (if (string= content-type "")
881 (setq content-type "text/plain"))
882 (if (string= charset "")
883 (setq charset "asdfasdfdfsdafs"))
884 (mime-include-nonbinary-file filename content-type charset))
885 (mime-display-waiting-messages))
886
887 ;;; ---------------------------- Region commands -----------------------------
888
889 (defun mime-encode-region (start end content-type charset)
890 "Encode a region specified by START and END. CONTENT-TYPE and
891 CHARSET name the content type and character set of the data in the
892 region."
893 ;; Start by encoding the region in quoted-printable. This will
894 ;; move end, but not start.
895 (goto-char end)
896 (let ((seldisp selective-display))
897 (setq selective-display nil)
898 (shell-command-on-region start end mime-encode-qp-command t)
899 (setq selective-display seldisp))
900 ;; Now pick up the new end.
901 (setq end (point))
902 ;; Pop up to start and insert the header; this will also change
903 ;; end, but with save-excursion we'll end up at the new end.
904 (save-excursion
905 (goto-char start)
906 (push-mark)
907 (insert "--" (mime-primary-boundary) "\n")
908 (insert "Content-Type: " content-type "; charset=" charset "\n")
909 (insert "Content-Transfer-Encoding: quoted-printable\n")
910 (mime-maybe-highlight-region
911 (save-excursion (re-search-backward
912 (concat "--" (mime-primary-boundary))) (point))
913 (- (point) 1))
914 (insert "\n"))
915 ;; Pick up the new end again.
916 (setq end (point))
917 ;; Insert the trailing boundary and the new text/plain header.
918 (insert "\n")
919 (insert "--" (mime-primary-boundary) "\n")
920 (insert "Content-Type: text/plain\n")
921 (mime-maybe-highlight-region
922 (save-excursion (re-search-backward
923 (concat "--" (mime-primary-boundary))) (point))
924 (- (point) 1))
925 (insert "\n")
926 ;; Last but not least, add MIME headers if necessary.
927 (save-excursion
928 (mime-mimify-message)))
929
930 (defun mime-region-to-richtext (start end &optional prefix-arg)
931 "Convert the current region to MIME richtext. MIME headers are
932 added if necessary; a MIME boundary is added at the start of the
933 region to indicate richtext; the conversion (see below) is done; a new
934 boundary is added for more text.
935
936 With prefix arg, prompt for character set; else use value of
937 mime-default-charset.
938
939 Currently no textual conversion is done, other than encoding in
940 quoted-printable format. Instead, you use directives such as <bold>
941 and </bold> in the text, as described in the MIME RFC. The
942 alternative would be to parse tilde sequences as is done in the mailto
943 program. Let me know if you think the latter would be more
944 appropriate for mime-compose.el."
945 (interactive "r\nP")
946 (let ((charset
947 (if (not prefix-arg)
948 mime-default-charset
949 (completing-read "Character set: " mime-valid-charsets
950 nil nil nil))))
951 ;; Unadvertised default.
952 (if (string= charset "")
953 (setq charset mime-default-charset))
954 (mime-encode-region start end "text/richtext"
955 charset))
956 (mime-display-waiting-messages))
957
958 (defun mime-region-to-charset (start end)
959 "Convert the current region to plaintext in a non-default character
960 set. You are prompted for a character set, and the text in the region
961 is encoded in quoted-printable format and identified as being in that
962 character set."
963 (interactive "r")
964 (let ((charset
965 (completing-read "Character set: " mime-valid-charsets
966 nil nil nil)))
967 ;; Unadvertised default.
968 (if (string= charset "")
969 (setq charset mime-default-charset))
970 (mime-encode-region start end "text/plain" charset))
971 (mime-display-waiting-messages))
972
973 ;;; -------------------------------- Keymaps ---------------------------------
974
975 ;;; Add functions to MH letter mode.
976 (if mime-running-mh-e
977 ;; Running mh-e.
978 (if (or (not (boundp 'mh-letter-mode-mime-map))
979 (not mh-letter-mode-mime-map))
980 (progn
981 (setq mh-letter-mode-mime-map (make-sparse-keymap))
982 (define-key mh-letter-mode-map "\C-c\C-m" mh-letter-mode-mime-map)
983 (define-key mh-letter-mode-mime-map "m" 'mime-mimify-message)
984 (define-key mh-letter-mode-mime-map "g" 'mime-include-gif)
985 (define-key mh-letter-mode-mime-map "j" 'mime-include-jpeg)
986 (define-key mh-letter-mode-mime-map "a" 'mime-include-audio)
987 (define-key mh-letter-mode-mime-map "v" 'mime-include-mpeg)
988 (define-key mh-letter-mode-mime-map "p" 'mime-include-postscript)
989 (define-key mh-letter-mode-mime-map "r" 'mime-include-raw-binary)
990 (define-key mh-letter-mode-mime-map "n" 'mime-include-raw-nonbinary)
991 (define-key mh-letter-mode-mime-map "x" 'mime-include-xwd-dump)
992 (define-key mh-letter-mode-mime-map "e"
993 'mime-include-external-anonftp)
994 (define-key mh-letter-mode-mime-map "f"
995 'mime-include-external-ftp)
996 (define-key mh-letter-mode-mime-map "s"
997 'mime-include-audio-snippet)
998 ;; Functions that operate on regions.
999 (defvar mime-region-map (make-sparse-keymap))
1000 (define-key mh-letter-mode-mime-map "\C-r" mime-region-map)
1001 (define-key mime-region-map "r" 'mime-region-to-richtext)
1002 (define-key mime-region-map "i" 'mime-region-to-charset)))
1003 ;; Not running mh-e.
1004 (progn
1005 (define-key mail-mode-map "\C-cm" 'mime-mimify-message)
1006 (define-key mail-mode-map "\C-cg" 'mime-include-gif)
1007 (define-key mail-mode-map "\C-cj" 'mime-include-jpeg)
1008 (define-key mail-mode-map "\C-ca" 'mime-include-audio)
1009 (define-key mail-mode-map "\C-cp" 'mime-include-postscript)
1010 (define-key mail-mode-map "\C-cr" 'mime-include-raw-binary)
1011 (define-key mail-mode-map "\C-cn" 'mime-include-raw-nonbinary)
1012 (define-key mail-mode-map "\C-cx" 'mime-include-xwd-dump)
1013 (define-key mail-mode-map "\C-ce" 'mime-include-external-anonftp)
1014 (define-key mail-mode-map "\C-cf" 'mime-include-external-ftp)
1015 (define-key mail-mode-map "\C-cs" 'mime-include-audio-snippet)
1016 (define-key mail-mode-map "\C-cv" 'mime-include-mpeg)
1017
1018 ;; Functions that operate on regions.
1019 (defvar mime-region-map (make-sparse-keymap))
1020 (define-key mail-mode-map "\C-c\C-r" mime-region-map)
1021 (define-key mime-region-map "r" 'mime-region-to-richtext)
1022 (define-key mime-region-map "i" 'mime-region-to-charset)))
1023
1024 ;;; -------------------------------- Menubar ---------------------------------
1025
1026 (defvar mime-compose-menu
1027 (list
1028 "MIME Inclusions:"
1029 "----"
1030 ["Include GIF File" mime-include-gif t]
1031 ["Include JPEG File" mime-include-jpeg t]
1032 ["Include MPEG File" mime-include-mpeg t]
1033 ["Include Audio File" mime-include-audio t]
1034 ["Include PostScript File" mime-include-postscript t]
1035 ["Include XWD Dump" mime-include-xwd-dump t]
1036 ["Include Audio Snippet" mime-include-audio-snippet t]
1037 ["Include Raw Binary File" mime-include-raw-binary t]
1038 ["Include Raw Nonbinary File" mime-include-raw-nonbinary t]
1039 ["Include External AnonFTP" mime-include-external-anonftp t]
1040 ["Include External FTP" mime-include-external-ftp t]
1041 )
1042 "Popup menu for MIME Compose.")
1043
1044 ;; Attach menu to mail-mode-menu.
1045 (and mime-running-lemacs
1046 (setq mail-menubar-menu (append mail-menubar-menu '("---") mime-compose-menu))
1047 (setq mail-popup-menu (append mail-popup-menu '("---") mime-compose-menu)))
1048
1049 ;; Arrange to attach to VM's mail mode menu.
1050 (defun mime-compose-attach-to-mode-menu ()
1051 (if (boundp 'vm-menu-mail-menu)
1052 (progn
1053 (setq vm-menu-mail-menu
1054 (nconc vm-menu-mail-menu (list "----") mime-compose-menu))
1055 (remove-hook 'vm-mail-mode-hook 'mime-compose-attach-to-mode-menu))))
1056
1057 (add-hook 'vm-mail-mode-hook 'mime-compose-attach-to-mode-menu)
1058
1059 ;;; ----------------------------- New mail-send ------------------------------
1060
1061 ;; If we're not running XEmacs, pop in a new mail-send routine.
1062 (if (not mime-running-lemacs)
1063 (defun mail-send ()
1064 "Send the message in the current buffer.
1065 If mail-interactive is non-nil, wait for success indication
1066 or error messages, and inform user.
1067 Otherwise any failure is reported in a message back to
1068 the user from the mailer."
1069 (interactive)
1070 (message "Sending...")
1071 (run-hooks 'mail-send-hook)
1072 (funcall send-mail-function)
1073 (set-buffer-modified-p nil)
1074 (delete-auto-save-file-if-necessary)
1075 (message "Sending...done")))
1076
1077 ;;; --------------------------------- Hooks ----------------------------------
1078
1079 ;; Author: Daniel LaLiberte (liberte@cs.uiuc.edu).
1080 (defun mime-postpend-unique-hook (hook-var hook-function)
1081 "Postpend HOOK-VAR with HOOK-FUNCTION, if it is not already an element.
1082 hook-var's value may be a single function or a list of functions."
1083 (if (boundp hook-var)
1084 (let ((value (symbol-value hook-var)))
1085 (if (and (listp value) (not (eq (car value) 'lambda)))
1086 (and (not (memq hook-function value))
1087 (set hook-var (append value (list hook-function))))
1088 (and (not (eq hook-function value))
1089 (set hook-var (append value (list hook-function))))))
1090 (set hook-var (list hook-function))))
1091
1092 (defun mime-unfrob-selective-display ()
1093 "Turn off selective display throughout this buffer."
1094 (if mime-use-selective-display
1095 (progn
1096 (message "Unfrobbing selective-display...")
1097 (mime-hide-region (point-min) (point-max) nil))))
1098
1099 (defun mime-strip-useless-bodyparts ()
1100 "Strip useless (empty) bodyparts out of a message."
1101 (save-excursion
1102 (goto-char (point-min))
1103 (while (re-search-forward
1104 (concat "^--" (mime-primary-boundary)
1105 "\nContent-Type: text.*[\n]*--" (mime-primary-boundary))
1106 (point-max) t)
1107 (replace-match (concat "--" (mime-primary-boundary)) t t)
1108 ;; Go all the way back up to start over.
1109 (goto-char (point-min)))))
1110
1111 (defun mime-encode-region-qp (start end)
1112 "Encode a region specified by START and END in quoted-printable
1113 format. Return the new endpoint. Do not use save-excursion."
1114 ;; Start by encoding the region in quoted-printable. This will
1115 ;; move end, but not start.
1116 (goto-char end)
1117 (let ((seldisp selective-display))
1118 (setq selective-display nil)
1119 (shell-command-on-region start end mime-encode-qp-command t)
1120 (setq selective-display seldisp)))
1121
1122 (defun mime-encode-plaintext ()
1123 "Encode all plaintext bodyparts in the message in quoted-printable
1124 and set the charset to mime-default-charset."
1125 (save-excursion
1126 (goto-char (point-min))
1127 ;; We're looking for text/plain bodyparts with no extra fields.
1128 (while (re-search-forward
1129 (concat "^--" (mime-primary-boundary)
1130 "\nContent-Type: text/plain\n") (point-max) t)
1131 (let* ((head (match-beginning 0))
1132 (start (match-end 0))
1133 ;; Assume there's a closing boundary; go find it.
1134 (end (save-excursion (re-search-forward
1135 (concat "^--" (mime-primary-boundary)))
1136 (- (match-beginning 0) 1))))
1137 ;; Maybe there's already a Content-Transfer-Encoding. If so,
1138 ;; never mind.
1139 (or (re-search-forward "^Content-Transfer-Encoding: " end t)
1140 (let ((new-end (save-excursion
1141 (mime-encode-region-qp start end))))
1142 (save-excursion
1143 (goto-char head)
1144 (next-line 1)
1145 (end-of-line)
1146 (let ((s (point)))
1147 (insert "; charset=" mime-default-charset "\n")
1148 (insert "Content-Transfer-Encoding: quoted-printable")
1149 (mime-maybe-highlight-region s (point))))))))))
1150
1151 (defun mime-send-hook-function ()
1152 "Function to be called from mail-send-hook. Unfrob selective
1153 display if active, strip out empty (useless) bodyparts, and optionally
1154 encode plaintext bodyparts in quoted-printable with a given charset."
1155 (mime-unfrob-selective-display)
1156 (mime-strip-useless-bodyparts)
1157 (and mime-encode-plaintext-on-send
1158 (mime-encode-plaintext)))
1159
1160 ;; Before the message is sent, remove the selective display crap.
1161 (if mime-running-mh-e
1162 (mime-postpend-unique-hook 'mh-before-send-letter-hook
1163 'mime-send-hook-function)
1164 (mime-postpend-unique-hook 'mail-send-hook 'mime-send-hook-function))
1165
1166 (defun mime-setup-hook-function ()
1167 (if mime-use-selective-display
1168 (setq selective-display t)))
1169
1170 ;; During mail setup, activate selective-display if necessary. We use
1171 ;; mail-mode-hook rather than mail-setup-hook because if a message is
1172 ;; being composed and C-x m gets hit again, mail-mode will be
1173 ;; reentered, causing selective-display to revert to nil and possibly
1174 ;; screwing up the display bigtime unless mail-mode-hook knows what to
1175 ;; do.
1176 (if mime-running-mh-e
1177 (mime-postpend-unique-hook 'mh-letter-mode-hook
1178 'mime-setup-hook-function)
1179 (mime-postpend-unique-hook 'mail-mode-hook 'mime-setup-hook-function))
1180
1181 ;;; ------------------------- END OF MIME-COMPOSE.EL -------------------------
1182
1183 ;;; ---------------------- PATCH FOR SUN RECORD PROGRAM ----------------------
1184
1185 ;;; This patch must be applied to record.c as found in the Sun demo
1186 ;;; directories in order to enable on-the-fly audio recording in
1187 ;;; mime-compose.
1188
1189 ;; *** record.c.orig Wed Oct 23 13:56:38 1991
1190 ;; --- record.c Sun Dec 6 22:50:06 1992
1191 ;; ***************
1192 ;; *** 2,7 ****
1193 ;; --- 2,9 ----
1194 ;; static char sccsid[] = "@(#)record.c 1.2 90/01/02 Copyr 1989 Sun Micro";
1195 ;; #endif
1196 ;; /* Copyright (c) 1989 by Sun Microsystems, Inc. */
1197 ;; + /* 921206: modifications to not output audio header (ckd@eff.org) */
1198 ;; + /* yes, I know it's ugly code... sorry... */
1199 ;;
1200 ;; #include <stdio.h>
1201 ;; #include <errno.h>
1202 ;; ***************
1203 ;; *** 30,36 ****
1204 ;; /* Local variables */
1205 ;; char *prog;
1206 ;; char prog_desc[] = "Record an audio file";
1207 ;; ! char prog_opts[] = "aft:v:d:i:?"; /* getopt() flags */
1208 ;;
1209 ;; char *Stdout = "stdout";
1210 ;;
1211 ;; --- 32,38 ----
1212 ;; /* Local variables */
1213 ;; char *prog;
1214 ;; char prog_desc[] = "Record an audio file";
1215 ;; ! char prog_opts[] = "aft:v:d:i:?m"; /* getopt() flags */
1216 ;;
1217 ;; char *Stdout = "stdout";
1218 ;;
1219 ;; ***************
1220 ;; *** 69,76 ****
1221 ;; usage()
1222 ;; {
1223 ;; Error(stderr, "%s -- usage:\n\t%s ", prog_desc, prog);
1224 ;; ! Error(stderr, "\t[-a] [-v #] [-t #] [-i msg] [-d dev] [file]\n");
1225 ;; Error(stderr, "where:\n\t-a\tAppend to output file\n");
1226 ;; Error(stderr, "\t-f\tIgnore sample rate differences on append\n");
1227 ;; Error(stderr, "\t-v #\tSet record volume (0 - %d)\n", MAX_GAIN);
1228 ;; Error(stderr, "\t-t #\tSpecify record time (hh:mm:ss.dd)\n");
1229 ;; --- 71,79 ----
1230 ;; usage()
1231 ;; {
1232 ;; Error(stderr, "%s -- usage:\n\t%s ", prog_desc, prog);
1233 ;; ! Error(stderr, "\t[-a] [-m] [-v #] [-t #] [-i msg] [-d dev] [file]\n");
1234 ;; Error(stderr, "where:\n\t-a\tAppend to output file\n");
1235 ;; + Error(stderr, "\t-m\tDon't add audio header (for MIME)\n");
1236 ;; Error(stderr, "\t-f\tIgnore sample rate differences on append\n");
1237 ;; Error(stderr, "\t-v #\tSet record volume (0 - %d)\n", MAX_GAIN);
1238 ;; Error(stderr, "\t-t #\tSpecify record time (hh:mm:ss.dd)\n");
1239 ;; ***************
1240 ;; *** 112,117 ****
1241 ;; --- 115,121 ----
1242 ;; int cnt;
1243 ;; int err;
1244 ;; int ofd;
1245 ;; + int addheader = 1;
1246 ;; double vol;
1247 ;; struct stat st;
1248 ;; struct sigvec vec;
1249 ;; ***************
1250 ;; *** 150,155 ****
1251 ;; --- 154,162 ----
1252 ;; Info = optarg; /* set information string */
1253 ;; Ilen = strlen(Info);
1254 ;; break;
1255 ;; + case 'm':
1256 ;; + addheader = 0; /* no header (for MIME) */
1257 ;; + break;
1258 ;; case '?':
1259 ;; usage();
1260 ;; /*NOTREACHED*/
1261 ;; ***************
1262 ;; *** 288,293 ****
1263 ;; --- 295,301 ----
1264 ;; exit(1);
1265 ;; }
1266 ;; } else {
1267 ;; + if (addheader) {
1268 ;; if (audio_write_filehdr(ofd, &Dev_hdr, Info, Ilen) !=
1269 ;; AUDIO_SUCCESS) {
1270 ;; Error(stderr, "%s: error writing header for \n", prog);
1271 ;; ***************
1272 ;; *** 294,299 ****
1273 ;; --- 302,308 ----
1274 ;; perror(Ofile);
1275 ;; exit(1);
1276 ;; }
1277 ;; + }
1278 ;; }
1279 ;;
1280 ;; /* If -v flag, set the record volume now */
1281
1282 ;;; ------------------------------ END OF PATCH ------------------------------
1283