MIME messages are handled by the mhn command. You can change the default configuration of mhn by editing the profiles that it reads. You can configure mhn through two personal profiles; a system-wide profile is used if yours don't have the entries that mhn needs. This section has detailed information and examples of the entries you can put in the profiles.
The Section How mhn Shows a Message has an introduction that you may want to read before you get started with the detailed explanation here.
But mhn also uses special profile entries that start with mhn-, like mhn-store-text/plain:. These can't be typed on the command line; they're only read from files. This section explains those special profile entries and how to set them.
mhn reads those entries from three files, in this order:
The person who installed MH on your host also installed the mhn_defaults file. It should have global entries, reasonable defaults for most accounts on the system to use. If you're lucky, mhn_defaults contains entries for all the specialized programs mhn needs to handle different content types. Those programs may be scattered around your filesystem.
The entries in mhn_defaults may not be right for you, though. For instance, most of your system's accounts may use the X Window System, but you always work on an old ASCII terminal. The default profile entries that start X programs will just print errors on your ASCII terminal. In that case, you can add entries to your MH profile that work on your terminal; mhn will use these entries instead of the entries in mhn_defaults. (You don't have to duplicate the mhn_defaults entries that are correct for you. For instance, if the mhn-show-text/enriched: entry in mhn_defaults works on your ASCII terminal, there's no need to put another mhn-show-text/enriched: entry in your MH profile.)
Or, you may use several different types of terminals. You could have X at work and a terminal emulator program on your PC at home. The system defaults might be right on your X system, but not on your PC. So, you'll set the MHN environment variable when you're at home; it can point to an alternate profile with entries that your PC needs.
Of course, a mixture of profile entries might be right for you: some in your MH profile, some in an MHN file for one of your displays, another in a second MHN file for another situation, a third MHN file that's read by a custom shell script you've set up. Who knows? :-)
Here's the basic idea. As a process starts, the UNIX environment variables set in the parent process are copied to the child process. The MHN environment variable must be set in the parent process of mhn.
In most cases, the right place to set the environment variable is the startup file, like .login or .profile, that your login shell reads. But if you run MH (and mhn) from a process that isn't started by your login shell -- for instance, in some window systems or as a shell script that runs from cron(8)-- you'll need to set the MHN environment variable there. X Window System users may want to use a file like .xsession.
If you'll have more than one MHN file, it helps to have a system for naming them. I put all of mine in my MH directory with filenames that include the TERM environment variable setting -- like mhn-prf.vt100 and mhn-prf.xterm. You may want to put all of them in a separate directory.
To set MHN automatically from your login shell, you'll need to decide what characteristics of your login session change from place to place. Have your shell setup file execute the correct command to set the environment variable:
setenv MHN /full/pathname/of/file ...C shell
MHN=/full/pathname/of/file; export MHN ...Bourne/Korn shell
Here are some ideas. A book about UNIX shells will give the overview of the constructs below. If you need help with nitty-gritty details of your particular system, ask your system administrator:
setenv MHN /path/to/directory/mhn-prf.$TERM ...C shell
MHN=/path/to/directory/mhn-prf.$TERM ...Bourne/Korn shells
export MHN
C shell:
switch ($TERM) case vt*: case wyse*: setenv MHN /path/mhn-prf.ascii breaksw default: setenv MHN /path/mhn-prf.X breaksw endswBourne and Korn shells:
case "$TERM" in vt*|wyse*) MHN=/path/mhn-prf.ascii ;; *) MHN=/path/mhn-prf.X ;; esac export MHNThis setup also works if you want to set MHN on some terminals but not others.
% who barbie ttyq9 Aug 27 11:16 (ncd5.foo.com:0.0) ken ttyqb Aug 27 13:12 (macsnack.foo.com)(Long hostnames may be truncated. Check yours before you write this test.) If this will help, try commands like these for the C shell:
set tty="`tty`" switch (`who | sed -n "/ $tty:t /s/.*(\(.*\))/\1/p"`) case *0.0: ...set MHN for X display 0 case macsnack*: ...set MHN for the host macsnack.foo.comThat uses the C shell's :t modifier to get a tty name like ttyq9. Then it uses sed to search for that line in the who output -- and give the text between the parentheses for that tty name to the switch. This case *0.0: matches lines ending with 0.0, and the case macsnack*: matches lines that start with macsnack.
To do the same thing in the Bourne and Korn shells, use a case statement:
basetty=`basename \`tty\`` case "`who | sed -n \"/ $basetty /s/.*(\(.*\))/\1/p\"`" in *0.0) ...set MHN for X display 0 macsnack*) ...set MHN for the host macsnack.foo.com
C shell:
switch ("`tty`") case /dev/tty[pqrs]?: # rlogin, telnet: setenv MHN ... breaksw case /dev/tty02: # at my desk: setenv MHN ... breaksw endswBourne and Korn shells:
case "`tty`" in /dev/tty[pqrs]?) # rlogin, telnet: MHN=... ;; /dev/tty02) # at my desk: MHN=... ;; esac export MHN
C shell:
if ($?DISPLAY) then # X setenv MHN ... breaksw else if ($?WIN_PARENT) # SunView setenv MHN ... breaksw else ... endifBourne and Korn shells:
if [ -n "$DISPLAY" ] then # X MHN=... elsif [ -n "$WIN_PARENT" ] then # SunView MHN=... else ... fi export MHN
C shell:
set try="`mhpath +`/mhn-prf.`hostname`" if (-e "$try") setenv MHN $tryBourne and Korn shells:
try="`mhpath +`/mhn-prf.`hostname`" test -f "$try" && { MHN="$try"; export MHN; }The command mhpath + returns the path of the MH directory on my current host. hostname returns the hostname (you may need uname -n instead). So, if you log in to the machine kumquat, and you have a file called mhn-prf.kumquat in your MH directory, it will be used.
To be sure the environment variable is being set correctly, type one of the following commands just before you use show or mhn. You're set to go if you see the value you want (which might be an empty answer, if you don't want MHN set in this situation!):
% printenv MHN /u/jerry/Mail/mhn-prf.vt100...or...
% env | grep MHN= MHN=/u/jerry/Mail/mhn-prf.vt100And now you're ready for the real fun! ;-)
Any profile may have six kinds of mhn profile entries. Entries that start with mhn-show- are used when showing messages. The mhn-compose- entries are used to compose a draft message content when the mhn directive doesn't give a filename. Entries starting with mhn-charset- are used to decide how to handle a particular character set. The mhn-storage: entry and entries starting with mhn-store- tell mhn where and how to store messages. The mhn-cache: and mhn-private-cache: entries tell where external body parts are cached. And a few systems will have the entry mhn-access-ftp: to handle FTP transfers of external body parts.
Here's part of an mhn_defaults file:
mhn-charset-iso-8859-1: xterm -fn '-*-*-*-*-*-*-*-*-*-*-*-*-iso8859-1' -e %s mhn-charset-iso-8859-8: xterm -fn '-*-*-*-*-*-*-*-*-*-*-*-*-iso8859-8' -e %s mhn-compose-audio/basic: cat < /dev/audio mhn-show-application/PostScript: %plpr -Pps mhn-show-audio/basic: %pcat > /dev/audio mhn-show-image/x-pbm: %ppbmtoxwd | /usr/bin/X11/xwud -geometry =-0+0 mhn-show-image/x-pgm: %ppgmtopbm | pbmtoxwd | /usr/bin/X11/xwud -geometry =-0+0 mhn-show-image/xwd: %p/usr/bin/X11/xwud -geometry =-0+0 mhn-show-image/x-xwd: %p/usr/bin/X11/xwud -geometry =-0+0 mhn-show-image: %p/usr/local/bin/xv -geometry =-0+0 '%f' mhn-store-application/PostScript: %m%P.ps mhn-store-text: %m%P.txt mhn-store-video/mpeg: %m%P.mpgEach entry has two parts. The first part is the entry name, like mhn-store-text:. The rest of the entry has instructions for handling that content type. These instructions are called a string:
Here's an example of what you can do. The mhn_defaults file above is installed on a SPARCstation named server with its own built-in audio. If I do a remote login to server to get my email, I don't want audio to be played and recorded on server; it could be hundreds of miles away from me. I want audio to be processed on the host I'm using, slug. So I've added the entries in the next Example to a MHN profile on server. They use the rsh(1) command to send audio across the network, to and from slug:
Example: Server profile entry to handle audio on a remote client
mhn-compose-audio/basic: rsh slug cat \< /dev/audio mhn-show-audio/basic: %prsh slug 'echo "Sending audio to slug..."; set t=/tmp/mhn$$; cat > $t; cp $t /dev/audio; rm -f $t'If I run comp on server to send an audio/basic content, mhn will run the command rsh slug cat \< /dev/audio. Because the input redirection character is escaped (\<), the shell on server will ignore it; the redirection will be done on slug, and the cat command will run on slug and send the audio down the network to server. Next, if a message on server has audio to "show" (play), the profile entry outputs a note to remind me to wait (audio files can be big). Then it stores a temporary filename in a shell variable, sends the audio down the network to the temporary file on slug, and runs cp on slug to send the audio to slug's speaker. I used a temporary file to collect all the audio before playing it; this avoids network delays that could make the audio sound "choppy."
This example wasn't meant to impress you. :-) I wanted to show what you can do if you understand how UNIX shells work. For instance, even though the commands in mhn profile entries are interpreted by the Bourne shell, my account on slug uses the C shell... so I knew that the rsh commands had to use C shell syntax. Your entries probably won't need to be this complex -- but it's nice to know what mhn lets you do!
Next, let's take a close look at each kind of profile entry. The first section below is a tutorial. Sections near the end provide reference information.
After showing the header, mhn shows the body parts one-by-one. Or, for a multipart/parallel message, mhn will show parts at the same time unless a %e escape (listed in the Table Display String Escapes) prevents it. In a MIME message, each body part has a content-type. To display a content, mhn runs a UNIX command. It finds the commands in profile entries, as explained in the Section Profiles that mhn Reads.
If mhn can't find a profile entry, it has two defaults: the moreproc: entry (in your MH profile) is used for text/plain contents, and the MH show command is used for message/rfc822.
(Yes, mhn can run show. If the message/rfc822 content is itself a MIME message, show can start mhn again. MIME messages can contain other MIME messages, so this behavior makes sense.)
If mhn runs out of choices, it complains and quits with an error like:
mhn: don't know how to display content (content application/x-foobar in message 6, part 2)You might want to add defaults for all content-types -- as a fallback, in case there isn't a command for a particular subtype. Be careful that the defaults won't do anything unexpected with subtypes you haven't heard of (like x-foobar above). Because all MIME-encoded messages are 7-bit ASCII text (for now, at least), a safe way to display unknown content-types is with a pager -- for instance, your moreproc. Then, if mhn shows you garbage, you can just quit the pager and go on to the next part of the message.
(Although I said "all MIME messages are 7-bit for now," some companies use 8-bit or binary content, and more will do that as mail transfer starts to handle 8-bit data. In that case, be sure that the default display program you choose can handle any 8-bit data (including characters like NUL) without locking up your terminal or causing you other grief. It might be better to let mhn complain and quit instead of trying to handle all defaults.)
CAUTION: Some graphic file formats may contain commands that can be dangerous security holes. For instance, PostScript files can hold commands that delete other files.
File viewers are beginning to have security features built in. For instance, GNU ghostscript has a -safer option to disable the PostScript file-deletion "feature." I can't possibly tell you how safe every file viewing program is. But, if you're concerned about security, you should check before you use an unknown file viewer to display an unknown content.
Here are three example entries to get you started:
mhn-show-image: %pxv '%f' mhn-show-audio/basic: %lraw2audio 2>/dev/null | play mhn-show-video/mpeg:Let's look at those three entries.
mhn would decode the message part (for example, translate 7-bit base64 into an 8-bit binary file) and store the decoded part in a temporary file. Then mhn would use the first entry, replace %f with the temporary filename, and run the command xv 'tempfile'. (xv is a great viewing program for the X Window System; it knows how to display a lot of graphic file formats.)
The %p in the display string above is an escape that tells mhn to list content information on the terminal (like mhn -list would), then prompt and wait:
part 3 image/x-pbm 40K Sample waveform Press <return> to show content...When you see that prompt, you can skip the part (not run xv to display it) by pressing your interrupt key -- often, that's CTRL-C. Or, you can skip the rest of the message and get back to a shell prompt by pressing your QUIT key -- typically CTRL-\. If you don't want mhn to pause or print the description of the part, don't put %p in the display command. You also can prevent the pause by giving mhn its -nopause switch.
The escape %l tells mhn to give a listing, like mhn -list would, before it runs the "display" command. Unlike %p, the %l doesn't prompt and wait for you to press RETURN. So this command will print a one-line listing of the part, then play the sound immediately.
NOTE: A good general-purpose viewer for text, especially text with 8-bit characters, is less. Add moreproc: less to your MH profile. MH 6.8.3 comes with less version 177. The latest versions of less are even better at handling international text. Check an up-to-date archive site like ftp.uu.net or ask Archie.
If you use less, read its manual page for configuration information. In less version 177, you can display the ISO-8859-1 character set by setting the LESSCHARSET environment variable to latin1 and the LESS environment variable to r.
Now is a good time to edit your MH profile (or an MHN file, if you'd rather) and experiment. The steps below will lead you through the basics of display strings.
The examples above showed the %f, %l and %p escapes. The Table below lists all of the escapes for display strings.
mhn-show-text/plain: %phead -3Find a junk text/plain message that you'll want to remove. If your folders are full of various MIME messages, use mhn -list to find a message that has the content types you want. (If you don't have any, send yourself one now.) When you show the message, you should see the header, the prompt from %p, and the first three lines of the body:
% show (Message inbox:172) Date: Thu, 25 Aug 1994 06:37:23 PDT To: Randy Wyse <randy@xmaaw.com> From: Jerry Peek <jerry@ora.com> Subject: Re: Book outline MIME-Version: 1.0 part text/plain 2441 Press <return> to show content... First three lines of the body appear on your screen %Of course, that's not a useful way to display most messages: you'd usually like to see all of the content. But don't delete that entry in your profile yet.
Notice that you didn't give a filename to that head command. mhn passed the content to the standard input of the head command. You can give a filename wih the %f or %F escapes. We'll try that next.
Let's add a more complex entry to your profile. This one runs the pr(1) command, which formats a file for printing. The pr -h option specifies a heading you want to print at the top of a page. But your entry won't send the content to a printer. Instead, it will display the pr-formatted version on your terminal -- using the more(1) pager program. If you don't have more, substitute the pager you use -- like pg or less -- in the command. Be sure to use the escape %F (uppercase letter "F"), not %f:
mhn-show-text: pr -h '%d (content-type: text/%s)' '%F' | moreThat display string is a command like one you might type at a shell prompt. In fact, before you show a message, try typing that command at a shell prompt to see what it does. Replace the %F escape with the filename of a text file in your current directory:
% pr -h '%d (content-type: text/%s)' 'somefile' | more Jul 31 09:17 1994 %d (content-type: text/%s) Page 1 first screenful of somefile appears... -- More --Because mhn wasn't interpreting the %s and %d escapes, the pr command displays them literally in its heading.
Next, let's see if we can make that profile entry work on a real message. (Note: I'm trying to surprise you here.) Let's show the same message with the content-type text/plain that you did in the previous example:
% show ...What happens? You should see the first three lines of the body; that's all. mhn should not have used your new mhn-show-text: display string! Why? Because your profile entry, mhn-show-text:, is the default for text contents. It's used when there isn't a profile entry for the particular subtype (in this example, text/plain). But you also have a mhn-show-text/plain: entry, so it's used instead.
Now, let's make your profile entry take effect. Change the content-type of the message by editing it with your favorite editor (emacs, vi, etc.):
% emacs `mhpath cur`(The `mhpath cur` command, in backquotes, puts the absolute pathname of the current message on your editor command line.) Find the Content-type: header field and change it to the unlikely value text/x-haha. If there's a ; charset=something parameter on that Content-type: header field, remove it. Also, if the message doesn't have a Content-Description: field, add one. The two fields should look like this:
Content-type: text/x-haha Content-Description: Test message!Okay? Now your test message has a different content-type that (probably!) no other profile entry will match. Let's try it:
% show Jan 09 09:17 1995 Test message! (content-type: text/x-haha) Page 1 first screenful of content appears... -- More --Please do not read the rest of the message yet. Think: Which command is in control of your display at this moment? It's the command started by the shell, which was started by mhn. The shell's command line looks like this:
pr -h 'Test message! (content-type: text/x-haha)' 'filename' | moremhn filled in the escapes as the Table Display String Escapes showed: %d got the description, %s got the subtype, and %F got the temporary filename (shown here as filename) that mhn chose for holding the content.
The more pager is printing a prompt. You can give more's "quit" command (usually, q) to make the pager stop. Or, you can finish displaying the message and quit the pager. You wouldn't use mhn's "quit" command (CTRL-C or CTRL-\) at the -- More -- prompt because mhn isn't in control now. When your display command finishes, mhn is in control again: it can show the next part of the message, if any, or quit.
Ready for another example? Before you get started, make a note of the message number you used in the previous example. You'll be using it again in the Section Displaying Other Character Sets: mhn-charset-.
The Metamail package is a group of programs for working with MIME mail. If it isn't on your system, The Section Metamail explains where to get it. mhn does some of the things that Metamail was written to do -- mhn knows how to create and understand MIME messages and how to deal with multipart contents. But mhn doesn't know how to display other contents. For instance, mhn can't handle enriched text -- the text/enriched content type. The Metamail package comes with a program named richtext that was written for handling the obsolete text/richtext content. The -e option makes versions 2.7 and above of richtext display enriched text.
Let's make a profile entry that runs richtext -e. You may already have a profile entry for displaying enriched text. Search for it with grep -i, which ignores the difference between upper- and lowercase letters as it searches. Fill in the filenames below (though you can leave $MHN as it is, if you've created that file; your shell will replace it with the filename from the environment variable):
% grep -i "text/enriched" $MHN .mh_profile /path/to/library/directory/mhn_defaultsIf you didn't see a matching line, you're ready to go. If you saw a matching line in your system mhn_defaults file, remember that your personal entry will override it. Make an entry like the one below. If the richtext program isn't in a standard system directory (in your shell's search path), you'll need to use an absolute pathname:
mhn-show-text/enriched: %prichtext -e -t '%F'The -t option is just for this exercise. It puts asterisks around bold text (*bold*) and underscores around italic text (_italic_).
Now, you'll need an enriched text message. You can search for a non-multipart message by using pick and its --content-type switch. If that doesn't match a message, you can search all the messages, multipart included, with pick -search:
pick --content-type text/enriched ...single-part messages
pick -search "^content-type: text/enriched" ...multipart, too
No luck? Just create a simple enriched text message with a text editor. Section Sending MIME Mail has an example. Include at least one word in boldface and one word in italic text.
Next, show the message. The %p escape should make mhn pause before the text/enriched content. The whole body should be shown at once, without stopping, because you haven't used a pager. richtext has a simple pager built in; you can get it by using the -p option. Now that you've seen what the -t option does, you can remove it (unless you have a dumb terminal, in which case you might want to keep it). If you have the richtext(1) manual page on your system, check it for other interesting options that you might want. Your entry should look something like this:
mhn-show-text/enriched: %prichtext -e -p '%F'Try it again. Optimize the boldface and italic handling for your display. If you have other displays, you can try showing the message there, too; if you need different settings, make a MHN profile for one display or the other.
I haven't shown the %a escape, the Content-Type: parameters, yet. There's an example in the getrich script in Section Composing Content: mhn-compose-.
At this point, if you haven't read the mhn(1) manual page, you're ready to read the first few pages of it. Read through the end of the section called "Showing the Contents." It mentions character sets, which will be a good introduction to the next section of this tutorial.
(MH has other support for "international" characters -- that is, non-English characters. See Section International Character Support.)
There are three things mhn needs to know to work with multiple character sets:
Content-type: text/plain; charset="iso-8859-1"Messages that don't have a Content-type: header field are, by default (in MIME), text/plain; charset="us-ascii".
Note that MM_CHARSET is not necessarily the character set you'd like to use. It's the character set that your current display can show (and, presumably, that your keyboard can produce).
When you send a message that has any 8-bit (non-ASCII) characters, the value of MM_CHARSET is copied into the charset= parameter.
For example, if your current character set is us-ascii and you try to show an iso-8859-1 message, mhn will search your profiles for the entry mhn-charset-iso-8859-1:. The entry should have a command string that will display the character set. And that's what this section is about.
mhn-charset-iso-8859-1: xterm -fn '-*-*-medium-r-normal-*-*-120-*-*-c-*-iso8859-1' -e '%s' mhn-charset-iso-8859-1: %s | iso2asc 0Both use the %s escape; it is required. The first one starts xterm, an X Window System terminal emulator. This opens a new window on your X display with a font that includes all iso-8859-1 characters. (Although I haven't seen the problems myself, I've heard that some X fonts which are labelled as iso8859 don't contain all of the ISO-8859 characters.) The second entry is for people who can't display iso-8859-1 because they have an ASCII-only terminal. It uses the iso2asc ISOto-ASCII converter program. (If iso2asc isn't on your system, you can get a copy from ftp://ftp.ora.com/published/oreilly/nutshell/MHxmh/iso2asc.tar.Z.
To set up for the next exercise, please put the following two entries in your profile. (If you did the tutorial in the previous section, you probably already have the text/plain entry.)
mhn-show-text/plain: %phead -3 mhn-charset-x-upperlower: %s | tr '[a-z]' '[A-Z]'If you know the UNIX tr(1) command, the second entry should look familiar. It translates all lowercase characters to uppercase.
Next, edit the text/plain message you used in the previous section. Change the Content-type: field to read:
Content-type: text/plain; charset="x-upperlower"If the message body has any non-ASCII characters, please delete them for this example. (Sorry.) The message should have only upper- and lowercase English letters (A-Z and a-z), digits and punctuation.
Now on to the example. "What is this x-upperlower?," you're probably asking. To make a simpler example for people who are new to the idea of displaying other character sets -- and to be sure no one can accuse me of character-set favoritism :-) -- I've just invented a new character set named x-upperlower. The x-upperlower character set has all the English letters, both upper- and lowercase. (Actually, it's the us-ascii character set. But we'll ignore that.)
Here's our problem in this exercise. You'll play the part of a person with an old computer display. Your terminal can't display lowercase characters. It's ALL UPPERCASE. When people with these old terminals display a message that has this field:
Content-type: text/something; charset="x-upperlower"they can't see the lowercase letters. They need a mhn-charset-x-upperlower: profile entry to translate the lowercase letters into something they can see: that is, to translate the lowercase letters into ALL UPPERCASE.
Show the text/plain message that you just edited. The content (the body, that is) should come out ALL UPPERCASE. That's because the message has the parameter charset=x-upperlower in it. But the MM_CHARSET environment variable on your terminal isn't set to x-upperlower. So, mhn uses your mhn-charset-x-upperlower: profile entry to translate the x-upperlower characters to a character set you can see. (Please ignore those lowercase letters in the header. ;-) The MIME RFC 1521 spec only applies to the message body.)
% show (Message inbox:172) Date: Thu, 25 Aug 1994 06:37:23 PDT To: Randy Wyse <randy@xmaaw.com> From: Jerry Peek <jerry@ora.com> Subject: Re: Book outline MIME-Version: 1.0 part text/plain 2441 Press <return> to show content... FIRST THREE LINES OF THE BODY APPEAR ON YOUR SCREEN IN UPPERCASE %To build its command line for displaying the message in a different character set, mhn:
head -3 | tr '[a-z]' '[A-Z]'(Also look back at the profile entries, if you'd like.) The head -3 command displays the first three lines of the content. That output is piped to tr '[a-z]' '[A-Z]', which translates the content into uppercase for your ancient uppercase-only terminal.
Now, let's say you've moved to a terminal that can show both upper- and lowercase letters. To tell mhn about this, you need to set the MM_CHARSET environment variable to the name of your character set -- that is, to x-upperlower:
% setenv MM_CHARSET "x-upperlower" ...C shell
$ MM_CHARSET="x-upperlower" ...Bourne/Korn shell
$ export MM_CHARSET
Now when you show your text/plain message, two interesting things should happen. Try it:
% show (Message inbox:172) Date: Thu, 25 Aug 1994 06:37:23 PDT To: Randy Wyse <randy@xmaaw.com> From: Jerry Peek <jerry@ora.com> Subject: Re: Book outline MIME-Version: 1.0 All the lines of the body appear on your screen with no "Press <return>..." prompt. %Because your terminal can display x-upperlower, and because the message is plain text, MH doesn't need a special display command to show it on your terminal. It ignores the %phead -3 command for text/plain. It shows the message as it would show a non-MIME message. In fact, show doesn't even invoke mhn for this message.
If you want to see what mhn would do with the message if show had invoked it, try it. (Just type mhn at the shell prompt.) mhn should use your mhn-show-text/plain: profile entry, prompt you to Press <return>..., and run %phead -3 to show the first three lines.
To avoid confusion later, you should probably take the mhn-show-text/plain: display string out of your profile. Also set the MM_CHARSET environment variable to the character set your terminal can actually handle -- for example, us-ascii or iso-8859-1.
If you use a window system, open a new window for this part of the tutorial. Otherwise, start a subshell by typing the name of your shell at the prompt. For example, if you use the C shell:
% csh %The separate window, or subshell, will make it easy to undo the changes to your environment in this tutorial.
Make a little shell script named showenv that shows the UNIX environment. If your system has the env(1) command, use it; otherwise, you probably have printenv(1). Put that command in the showenv file and make it executable. Then run the shell script:
% vi showenv ...put these two lines in the file: #!/bin/sh env % chmod 755 showenv % showenv DISPLAY=:0.0 ... VISUAL=/usr/ucb/vi(If the current directory isn't in your search path, you may need to type ./showenv to run the script.)
Next, compose a draft message in the usual way, with the comp program. Make a multipart message with three parts: enriched text entered from the draft (a #< directive), a non-text file, and the output of the who(1) program. Then get to a What now? prompt and wait; do not run mhn to encode the draft.
% comp To: someone cc: Subject: Testing mhn ------ #<text/enriched The stuff in this message is <bold>junk</bold>, just some stuff I'm using to test <italic>mhn</italic>. #text/plain [The output of who(1)] |who #application/octet-stream [The who(1) program binary] /bin/who CTRL-D What now?At this point, the whatnow program is prompting you. If you haven't read the overview of what's happening at this point, you should probably look at the Section What now? -- and the whatnow Program. Now, a question for you: What makes mhn act the way it does when you run it from a What now? prompt? (Note: don't run mhn yet!) When you run mhn from a shell prompt, it displays a message. But when you run mhn from a What now? prompt, it encodes a message. What's happening? The difference is in the UNIX environment set by the whatnow program. Let's look at the environment. Tell whatnow to run your showenv script:
What now? edit showenv DISPLAY=:0.0 ... mhdraft=/u/joe/Mail/drafts/3 ...(If you get a "command not found" error, use a pathname -- for example, edit ./showenv.) The whatnow program has stored the absolute pathname of the draft file in the mhdraft environment variable. When you run mhn from within whatnow, mhn sees the mhdraft environment variable and becomes a message-encoder instead of a message-displayer.
Now quit and leave your unencoded draft message where it is. Then change your current directory to the one where your draft file is. (Note that older versions of whatnow don't show the draft pathname as they quit; if you don't know where your draft is, look back at the value of the mhdraft variable.) List the directory and look for your draft:
What now? q whatnow: draft left on /u/joe/Mail/drafts/3 % cd /u/joe/Mail/drafts % ls ... 3 ...If you run showenv again, you'll see that the mhdraft variable isn't set. Because we need mhn to encode the draft, add mhdraft to your environment. Use the pathname to your draft message:
$ mhdraft=/u/joe/Mail/drafts/3 ...Bourne/Korn shells
$ export mhdraft
% setenv mhdraft /u/joe/Mail/drafts/3 ...C shells
Now you're ready to encode the draft. Run mhn:
% mhn /u/joe/Mail/drafts/3 composing content text/plain from command whoIf you get errors -- for example, mhn can't read the file /bin/who because your system administrator has denied read permission -- edit the draft file and change the directives. (Use your favorite editor and the draft filename, like this: vi 3.) Then rerun mhn -- and be sure you don't get the error.
Now list your directory again. You should see the encoded draft and another file: the original draft with the directives in it. Read them both with a pager program like more(1):
% ls ... ,3.orig ... 3 ... % more ,3.orig 3 :::::::::::::: ,3.orig :::::::::::::: To: someone Subject: Testing mhn ------ #<text/enriched The stuff in this message is <bold>junk</bold>, just some stuff I'm using to test <italic>mhn</italic>. #text/plain [The output of who(1)] |who #application/octet-stream [The who(1) program binary] /bin/who -- More-- (Next file: 3) :::::::::::::: 3 :::::::::::::: To: someone Subject: Testing mhn MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----- =_aaaaaaaaaa0" Content-ID: <904.783368683.0@joebob.kermit.tx.us> ------- =_aaaaaaaaaa0 Content-Type: text/enriched; charset="us-ascii" Content-ID: <904.783368683.1@joebob.kermit.tx.us> The stuff in this message is <bold>junk</bold>, just some stuff I'm using to test <italic>mhn</italic>. ------- =_aaaaaaaaaa0 Content-Type: text/plain; charset="us-ascii" Content-ID: <904.783368683.2@joebob.kermit.tx.us> Content-Description: The output of who(1) joe console Oct 28 06:23 joe ttyp0 Oct 28 06:24 (:0.0) joe ttyp1 Oct 28 06:24 (:0.0) joe ttyp2 Oct 28 06:24 (:0.0) ------- =_aaaaaaaaaa0 Content-Type: application/octet-stream Content-ID: <904.783368683.3@joebob.kermit.tx.us> Content-Description: The who(1) program binary Content-Transfer-Encoding: base64 gQMBCAAACZAAAARAAAAASAAAAAAAACAAAAAAAAAAAAC8ECAA0AOgQJIDoESVKiAClAKgBJQCQAoX ... AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== ------- =_aaaaaaaaaa0--Now assume you've changed your mind about your draft. You'd like to include another part: your signature file. Editing the draft (the file 3) can be a hassle; it isn't always easy to create MIME-format messages by hand. But you can replace the encoded draft with the original file that has the directives. Then edit the draft and re-run mhn. Let's do it:
% mv ,3.orig 3 % vi 3 ...add this directive to the end: #text/plain [signature] /u/joe/.signature % mhn /u/joe/Mail/drafts/3 composing content text/plain from command who % more 3 ...re-encoded draft appears...That's enough experimenting with mhn at a shell prompt. Unless you want to keep working from a shell prompt, close the separate window or end the subshell by typing exit:
% exit %You should be back at your original shell in the original current directory. The mhdraft environment variable should not be set. (If you want to check, run showenv again.) Now you're ready to experiment with mhn directives.
Let's start by looking at the type directives, #type/subtype. (If you need a reminder of the syntax, check Tables 1-3 in the Section Syntax of mhn Directives.) mhn gets the content for those directives by looking at the last argument:
mhn handles any escapes in the composition string. Then it runs the string with a Bourne shell; the standard output of this command is used as the content.
The rest of this section is about these composition strings.
Table: Composition String Escapes
How do you give the editor a filename to edit from the composition string? The %f and %F escapes do that. Both escapes give the filename, but one of them changes the way that mhn handles output. Normally -- if you don't use any escapes, or if you use any escape except %F -- mhn directs the standard output of the composition command to the message content. This is good; it lets the output of the command be sent in the mail message. But you won't want that to happen when you use an interactive text editor. If it did, you couldn't see the screen or prompts that the editor makes: those would be redirected into the content, instead of shown on your screen! Notice in the previous Table that the %F escape is replaced with a filename and it tells mhn not to redirect the composition command standard output to the content. That's what you want in a case like this.
Add a composition string to your profile that runs getrich. The script will need some parameters, so add the escapes shown:
mhn-compose-text/enriched: getrich '%F' %aIf getrich was supposed to make more than one subtype (as in an mhn-compose-text: composition string), it would probably need to know what subtype it should produce. In that case, you would also put a %s parameter in the composition string. In this example, though, %s would be useless because getrich will always make text/enriched content.
To get started, make a simple getrich that displays the parameters mhn passed to it and then outputs some dummy enriched text. (It won't start a text editor yet.) Here's the script. You can write it in Perl or some other language if you prefer:
#!/bin/sh ### getrich - create enriched text for mhn ### Usage (in mhn profile): mhn-compose-text/enriched: getrich '%F' %a # show command line arguments. Write to standard error so # mhn won't add this text to the message content: echo "getrich: got these arguments: $*" 1>&2 # Output two lines of enriched text: echo 'This is a <bold>bold</bold> word from the "getrich" script. This one is <italic>italic</italic>.' > "$1" # Make sure mhn keeps the output: exit 0The two-line echo command at the end of the script writes two lines into $1, which is the filename from the first %F parameter. Use chmod +x to make the getrich script executable.
Next, make a short file named sampletext with two or three lines of enriched text in it.
Now, make a new draft with three different flavors of enriched text directive. One includes text you type into the draft, one reads the short enriched text you created above, and the third runs getrich. (If your directive doesn't give a pathname to another directory, mhn will read sampletext from the current directory.)
#<text/enriched [text typed into the draft] The stuff in this part is <bold>junk</bold>, some text I'm using to test <italic>mhn</italic>. #text/enriched [text from a file] sampletext #text/enriched [text from getrich]After you run mhn, take a look at the draft. It should contain the text from all three parts.
What now? edit mhn composing content text/enriched from command /tmp/getrich '/tmp/mhnb00987' getrich: got these arguments: /tmp/mhnb00987 What now? list ... ------- =_aaaaaaaaaa0 Content-Type: text/enriched; charset="us-ascii" Content-ID: <987.783374275.1@ora.com> Content-Description: text typed into the draft The stuff in this part is <bold>junk</bold>, some text I'm using to test <italic>mhn</italic>. ------- =_aaaaaaaaaa0 Content-Type: text/enriched; charset="us-ascii" Content-ID: <987.783374275.2@ora.com> Content-Description: text from a file This is sample enriched text from the <italic>sampletext</italic> file. Are we having fun yet??? ------- =_aaaaaaaaaa0 Content-Type: text/enriched; charset="us-ascii" Content-ID: <987.783374275.3@ora.com> Content-Description: text from getrich This is a <bold>bold</bold> word from the "getrich" script. This one is <italic>italic</italic>. ------- =_aaaaaaaaaa0-- What now? quit delete(If your lproc is set to use show when you list the draft, you won't see the encoded draft. In that case, you can see the encoded draft with the more(1) pager by typing edit more.)
The last line of getrich sets a zero exit status. This is important: if the composition command returns a nonzero status, mhn will abort and not encode the draft. If you'd like to experiment, change the exit 0 to exit 1, compose a new message for getrich and run mhn:
... #text/enriched [output from getrich script?] CTRL-D What now? e mhn composing content text/enriched from command /tmp/getrich '/tmp/mhnb00993' getrich: got these arguments: /tmp/mhnb00993 Exit 1 What now?Let's hack getrich to use the parameters passed from the %a escape and to actually run a text editor. The order of the composition string parameters is important. You put the content filename (%F) first, before the optional parameters. The script will grab the filename from its first argument; the rest of the arguments will be parameters from the directive. Here's the revised getrich:
#!/bin/sh ### getrich - create enriched text for mhn ### Usage (in mhn profile): mhn-compose-text/enriched: getrich '%F' %a # Grab content filename: file="$1"; shift # If there are parameters, "handle" them: for param do echo "getrich: what is this '$param' parameter for??" 1>&2 done # Create content by running enriched text editor (actually, vi). vi "$file" # Make sure mhn keeps the output: exit 0If you use a window system, you might change the editor line to open a separate window with a text editor in it. For instance, in the X Window System you could open a new xterm running the vi editor with:
xterm -e "vi $file"Now compose a draft with a directive that will run getrich. Add some parameters if you'd like to. (If you don't add parameters, the for loop in getrich won't run to process the parameters -- and you won't see the messages about parameters.)
% comp ... #text/enriched; x-temperature="98.6 F"; x-foo=bar [text from getrich] CTRL-D What now? edit mhn composing content text/enriched from command /tmp/getrich '/tmp/mhna01003' x-temperature="98.6 F" x-foo="bar" getrich: what is this 'x-temperature=98.6 F' parameter for?? getrich: what is this 'x-foo=bar' parameter for?? ...editor starts on the empty /tmp/mhna01003 file What now? list ... MIME-Version: 1.0 Content-Type: text/enriched; x-temperature="98.6 F"; x-foo="bar"; charset="us-ascii" Content-ID: <1003.783375452.1@ora.com> Content-Description: text from getrich This is the enriched text I'm entering with <italic>vi</italic>. What now?When you list the draft, you should see the enriched text that you entered with the editor.
This simple version of getrich displayed the x-temperature and x-foo parameters you passed to it. The script could have used them for something -- for example, post-processing the output with a command like compress -- if you set it up that way. Notice that mhn also copied the parameters to the Content-Type: header field (and added a charset parameter, too).
Because the Section Decoding and Storing MIME Messages introduced mhn storage with examples from configuration files, this section will be mostly reference.
mhn -store uses the profile entry mhn-store-type/subtype:, otherwise it uses mhn-store-type:. If it can't find a profile entry, mhn tries these defaults:
Table: mhn Storage Formatting Strings
mhn-store-text: %m%P.%sFor example, if message 23 is text/plain, it would be stored in a file named 23.plain. If you were storing the multipart message 67, part 1.3 is text/enriched and part 3 is text/x-pgp; the files would be named 67.1.3.enriched and 67.3.x-pgp.
mhn-store-audio/basic: | raw2audio -e ulaw -s 8000 -c 1 > %m%P.au
mhn-store-text: | cruncher text %s %aIf cruncher were a Bourne shell script, $1 would be text, $2 might be (for example) plain or enriched, and the other arguments (if any) might look like type=tar or x-conversions=compress.
Each user can access two cache directories, public and private.
The Public Cache
The public cache directory is usually named in your system's mhn_defaults file. That lets everyone on the system share the public cache. If you need to set a different public cache directory, put an mhn-cache: entry in your MH profile or MHN profile. And, of course, any user can ignore the public cache by setting the -rcache and -wcache switches to private or never.
If everyone on the system is allowed to write to the public cache, the system administrator needs to make its directory world-writable (mode 777). mhn will create all the cache files read-only (mode 444), but that doesn't stop people from removing cached files when they shouldn't. On many UNIX systems, the owner of a directory can set its sticky bit by using chmod 1777. On those systems, people will be able to add files to the directory, but they can't remove or rename files that were created by someone else.
Computers with networked filesystems can share a public cache between hosts. Any user on a host sharing that filesystem can save a public content. The mhn_defaults files on all those systems need to point to the right directory. Of course, if the network connections are slow, you may be undoing some of the benefit of cached contents: fast access to message parts without network delays.
Each user can have her own private cache. Unless you name one in the mhn-private-cache: profile entry, the default will be a subdirectory of your MH directory named .cache. The default name starts with a dot (.) to "hide" it from the ls command. But the default cache will still show up in the folders command output. I put my cache somewhere else:
mhn-private-cache: /home/jerry/tmp/mhn-private-cacheIf you don't want to use space in your home directory, you could try putting the cache in a subdirectory of a system temporary-file directory like /tmp/mhn-cache-yourname. Remember to protect the directory (chmod 700) if you might be storing private messages. Also remember that a cache directory in /tmp may be deleted or emptied by the system. That may be just what you want, of course. But if you want your cache to be more permanent, put it somewhere else and use the cleanup scripts below.
Cleaning the Caches
Cached copies of external body parts can get out of date. For instance, a cached copy of today's weather map probably wouldn't be much use by next week. mhn is good at writing to the caches, but it doesn't have a way to clean them up. This section has a few ideas.
The MIME standard, RFC 1521, describes an optional expiration= parameter for external body parts. The parameter says that after the date given, the content might be missing or invalid. Unfortunately, not all messages use that parameter. Even if they do, mhn doesn't save that date anywhere that I can see. Tidy users can get the expiration date from mhn -list -verbose and remove old cached contents. (If your system has many cache "housekeepers" like that, setting the sticky bit on the public cache directory might be a bad idea!) You'll probably still get plenty of old files in your caches.
Unless someone goes through the caches by hand every week or two to clean out old files, the best way to clean up is with a script run by cron(8) or at(1). The script can use find(1) to search for and remove files that are more than some number of days old. With its -mtime switch, find will remove the files based on the date they were stored. Or, if you use the -atime switch, the test will be on when the file was last accessed. If a cached file hasn't been accessed for a while, it might be a safe bet to remove. Finally, you might use the size of the file (find -size) as a factor. Big files take longer to copy over the network, so you could keep them longer. Of course, big files take more disk space, so you might want to delete them sooner. Whatever. :-)
If you have a better scheme for cleaning out caches, please tell me about it!
Why would you want to write your own program? You might be on a site that's behind an Internet firewall -- and need access beyond the firewall. You might be on a site with no Internet access -- and need to send a request to an email-to-FTP gateway like ftpmail. Or your host might not support a "sockets" interface.
The mhnftpmail shell script below is an example of a program you can run from an mhn-access-ftp: profile entry. It uses the seven parameters passed from mhn to build an email message to an ftpmail server. You can customize it for any ftpmail server you want to use, including the popular (but overloaded) server ftpmail@decwrl.dec.com. The script is set up for Lee McLoughlin's ftpmail server from the host src.doc.ic.ac.uk. (It's explained in detail in O'Reilly & Associates' book Managing Internet Information Services.)
This example shows the script being called as I show a message. The script doesn't have to be this verbose: edit it if you'd like to.
% next ... Retrieve book.catalog (content 1.2) using anonymous FTP from site ftp.ora.com? y mhnftpmail: sending mail to 'ftpmail@online.ora.com': open ftp.ora.com anonymous jerry@foobar.ora.com binary mime chdir pub get book.catalog The 'Exit 1' error below makes sure mhn won't try to cache the missing response: Exit 1 mhn: don't know how to display any of the contents (content multipart/alternative in message 55)The script returns a nonzero exit status to be sure that mhn won't think that the FTP job succeeded. You'll have to manually handle the file that ftpmail sends.
Here's the mhnftpmail Bourne shell script:
#!/bin/sh ### mhnftpmail - submit ftpmail request for mhn ### Usage (in mhn profile): mhn-access-ftp: mhnftpmail # Customize this script for your site and ftpmail server. mhmail=/usr/local/mh/mhmail # Absolute path to mhmail program ftpmail='ftpmail@online.ora.com' #ftpmail=yourname@yourhost # Uncomment for debugging # Build message to send in $msg (multi-line) shell variable. # arguments passed by mhn: $1 - domain name of ftp site, $2 - username, # $3 - password, $4 - remote directory, $5 - remote filename, # $6 - local filename (not used here), $7 - "ascii" or "binary": msg="open $1 $2 $3 $7 mime chdir $4 get $5" # Say what's happening (on standard error): cat << END_OF_STUFF 1>&2 `basename $0`: sending mail to '$ftpmail': $msg The 'Exit 1' error below makes sure mhn won't try to cache the missing response: END_OF_STUFF # Send mail, exit with status 1 so mhn won't think we have the content. $mhmail "$ftpmail" -body "$msg" exit 1
Most people probably use mhn:
automhnproc: mhnYou can use any program you want. For instance, if you've switched to MH from another MIME MUA, you could use the familiar Metamail program and your own .mailcap file. The program you use should be able to take the absolute pathname of the draft from its first argument, encode the draft, and write it back. It should also return a zero exit status if it succeeded; if whatnow gets a nonzero status from the automhnproc, it will prompt you again with What now?. So, there's nothing to stop you from writing a script -- in, say, Perl or the Bourne shell -- that does whatever you want (and, maybe, calls mhn when it's done). The mysend script might give you some ideas.
[Table of Contents] [Index] [Previous: An MH Profile, in General] [Next: International Character Support]
This file is from the third edition of the book MH & xmh: Email for Users & Programmers, ISBN 1-56592-093-7, by Jerry Peek. Copyright © 1991, 1992, 1995 by O'Reilly & Associates, Inc. This file is freely-available; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. For more information, see the file copying.htm.
Suggestions are welcome: Jerry Peek <jerry@ora.com>
HIVE: All information for read only. Please respect copyright! |