MHN(1)

NAME
mhn - multi-media MH

SYNOPSIS
mhn [[+folder] [msgs] | [-file file]]
[-part number]... [-type content]...
[-list [-headers] [-noheaders]
       [-realsize] [-norealsize]] [-nolist]
[-show [-serialonly] [-noserialonly]
       [-form formfile] [-pause] [-nopause]] [-noshow]
[-store [-auto] [-noauto]] [-nostore]
[-cache] [-nocache] [-rcache policy] [-wcache policy]
[-check] [-nocheck]
[-ebcdicsafe] [-noebcdicsafe]
[-rfc934mode] [-norfc934mode]
[-verbose] [-noverbose]
[-help]

DESCRIPTION
The mhn command manipulates multi-media messages as specified in RFC 1521. Four action switches direct the operation of mhn, namely `-list', `-show', `-store', and `-cache'. Any of these switches may be used concurrently. Normally these action switches will operate on the content of each of the named messages. However, by using the `-part' and `-type' switches, the scope of the operation can be focused on particular subparts (of a multipart content) and/or particular content types. A part specification consists of a series of numbers separated by dots. For example, in a multipart content containing three parts, these would be named as 1, 2, and 3, respectively. If part 2 was also a multipart content containing two parts, these would be named as 2.1 and 2.2, respectively. Note that the `-part' switch is effective for only messages containing a multipart content. If a message has some other kind of content, or if the part is itself another multipart content, the `-part' switch will not prevent the content from being acted upon. A content specification consists of a content type and a subtype. The initial list of “standard” content types and subtypes can be found in RFC 1521. A list of commonly used contents is briefly reproduced here:

Type	Subtypes
----	--------
text	plain
multipart	mixed, alternative, digest, parallel
message	rfc822, partial, external-body
application	octet-stream, postscript
image	jpeg, gif, x-pbm, x-pgm, x-ppm, x-xwd
audio	basic
video	mpeg

Subtypes are mandatory.

To specify a content, regardless of its subtype, just use the name of the content, e.g., “audio”. To specify a specific subtype, separate the two with a slash, e.g., “audio/basic”. Note that regardless of the values given to the `-type' switch, a multipart content (of any subtype listed above) is always acted upon. Further note that if the `-type' switch is used, and it is desirable to act on a message/external-body content, then the `-type' switch must be used twice: once for message/external-body and once for the content externally referenced. Each content may optionally have an integrity check associated with it. If present and the `-check' switch is given, then mhn will attempt to verify the integrity of the content. The option `-file file' directs mhn to use the specified file as the source message, rather than a message from a folder. Note that the file should be a validly formatted message, just like any other MH message. It should NOT be in mail drop format (to convert a file in mail drop format to a folder of MH messages, see inc (1)). The `-list' switch tells mhn to list the table of contents associated with the named messages. The `-headers' switch indicates that a one-line banner should be displayed above the listing. The `-realsize' switch tells mhn to evaluate the “native” (decoded) format of each content prior to listing. This provides an accurate count at the expense of a small delay. The `-show' switch tells mhn to display the contents of the named messages. The headers of the message are displayed with the mhlproc, using format file mhl.headers. (The choice of format file can be overridden by the `-form formfile' switch.) mhn will look for information in the user's profile to determine how the different contents should be displayed. This is accomplished by consulting a display string, and executing it under /bin/sh, with the standard input set to the content. The display string may contain these escapes:

%a	additional arguments
%e	exclusive execution
%f	filename containing content
%F	%e, %f, and stdin is terminal not content
%l	display listing prior to displaying content
%p	%l, and ask for confirmation
%s	subtype
%d	content description

For those display strings containing the e- or F-escape, mhn will execute at most one of these at any given time. Although the F-escape expands to be the filename containing the content, the e-escape has no expansion as far as the shell is concerned. When the p-escape prompts for confirmation, typing INTR (usually control-C) will tell mhn not to display that content. (The p-escape can be disabled by specifying `-nopause'.) Further, when mhn is display a content, typing QUIT (usually control-\) will tell mhn to wrap things up immediately. Note that if the content being displayed is multipart, but not one of the subtypes listed above, then the f- and F-escapes expand to multiple filenames, one for each subordinate content. Further, stdin is not redirected from the terminal to the content. First, mhn will look for an entry of the form:

mhn-show-<type>/<subtype>

to determine the command to use to display the content. If this isn't found, mhn will look for an entry of the form:

mhn-show-<type>

to determine the display command. If this isn't found, mhn has two default values:

mhn-show-text/plain: %pmoreproc '%F'
mhn-show-message/rfc822: %pshow -file '%F'

If neither apply, mhn will check to see if the message has a application/octet-stream content with parameter “type=tar”. If so, mhn will use an appropriate command. If not, mhn will complain. Example entries might be:

mhn-show-audio/basic: raw2audio 2>/dev/null | play
mhn-show-image: xv '%f'
mhn-show-application/PostScript: lpr -Pps

Note that when using the f- or F-escape, it's a good idea to use single-quotes around the escape. This prevents misinterpretation by the shell of any funny characters that might be present in the filename. Because the text content might be in a non-ASCII character set, when mhn encounters a “charset” parameter for this content, it checks to see whether the environment variable $MM_CHARSET is set and whether the value of this environment variable is equal to the value of the charset parameter. If not, then mhn will look for an entry of the form:

mhn-charset-<charset>

which should contain a command creating an environment to render the character set. This command string should containing a single “%s”, which will be filled-in with the command to display the content. An example entry might be:

mhn-charset-iso-8859-1: xterm -fn '-*-*-medium-r-normal-*-*-120-*-*-c-*-iso8859-*' -e %s

Note that many pagination programs strip off the high-order bit. However, newer releases of the less program have modest support for single-octet character sets. The source to less version 177, which has such support, is found in the MH source tree under miscellany/less-177. In order to view messages sent in the ISO 8859/1 character set using less, put these lines in your .login file:

setenv LESSCHARSET latin1
setenv LESS "-f"

The first line tells less to use 8859/1 definition for determing whether a character is “normal”, “control“, or “binary”. The second line tells less not to warn you if it encounters a file that has non-ASCII characters. Then, simply set the moreproc profile entry to less, and it will get called automatically. (To handle other single-octet character sets, look at the less (1) manual entry for information about the LESSCHARDEF environment variable.) Finally, mhn will process each message serially -- it won't start showing the next message until all the commands executed to display the current message have terminated. In the case of a multipart content (of any subtype listed above), the content contains advice indicating if the parts should be displayed serially or in parallel. Because this may cause confusion, particularly on uni-window displays, the `-serialonly' switch can be given to tell mhn to never display parts in parallel. The `-store' switch tells mhn to store the contents of the named messages in “native” (decoded) format. Two things must be determined: the directory to store the content, and the filenames. Files are written in the directory given by the mhn-storage profile entry, e.g.,

mhn-storage: /tmp

If this entry isn't present, the current working directory is used. mhn will look for information in the user's profile to determine how the different contents should be stored. This is achieved through the use of a formatting string, which may contain these escapes:

%m	message number
%P	.part
%p	part
%s	subtype

If the content isn't part of a multipart (of any subtype listed above) content, the p-escapes are ignored. Note that if the formatting string starts with a “+” character, then these escapes are ignored, and the content is stored in the named folder. (A formatting string consisting solely of a “+” character indicates the current folder.) Further, a formatting string consisting solely of a “-” character indicates the standard-output. First, mhn will look for an entry of the form:

mhn-store-<type>/<subtype>

to determine the formatting string. If this isn't found, mhn will look for an entry of the form:

mhn-store-<type>

to determine the formatting string. If this isn't found, mhn will check to see if the content is application/octet-stream with parameter “type=tar”. If so, mhn will choose an appropriate filename. If the content is not application/octet-stream, then mhn will check to see if the content is a message. If so, mhn will use the value “+”. If not, mhn will use the value “%m%P.%s”. Note that if the formatting string starts with a '/', then content will be stored in the full path given (rather than using the value of mhn-storage or the current working directory.) Similarly, if the formatting string starts with a '|', then mhn will execute a command which should ultimately store the content. Note that before executing the command, mhn will change to the appropriate directory. Also note that if the formatting string starts with a '|', then mhn will also honor the a-escape when processing the formatting string. Example entries might be:

mhn-store-text: %m%P.txt
mhn-store-audio/basic: | raw2audio -e ulaw -s 8000 -c 1 > %m%P.au
mhn-store-application/PostScript: %m%P.ps

Further, note that when asked to store a content containing a partial message, mhn will try to locate all of the portions and combine them accordingly. Thus, if someone's sent you a message in several parts, you might put them all in their own folder and do:

mhn all -store

This will store exactly one message, containing the sum of the parts. Note that if mhn can not locate each part, it will not store anything. Finally, if the `-auto' switch is given and the content contains information indicating the filename the content should be stored as (and if the filename doesn't begin with a '/'), then the filename from the content will be used instead. For contents of type message/external-body, mhn supports these access-types:

afs
anon-ftp
ftp
local-file
mail-server

For the “anon-ftp” and “ftp” access types, if your system supports a SOCKETs interface to TCP/IP, then mhn will use a built-in FTP client. Otherwise, mhn will look for the mhn-access-ftp profile entry, e.g.,

mhn-access-ftp: myftp.sh

to determine the pathname of a program to perform the FTP retrieval. This program is invoked with these arguments:

domain name of FTP-site
username
password
remote directory
remote filename
local filename
“ascii” or “binary”

The program should terminate with a zero-valued exit-status if the retrieval is successful. When mhn encounters an external content containing a “Content-ID:” field, and if the content allows caching, then depending on the caching behavior of mhn, the content might be read from or written to a cache. The caching behavior of mhn is controlled with the `-rcache' and `-wcache' switches, which define the policy for reading from, and writing to, the cache, respectively. One of four policies may be specified: “public”, indicating that mhn should make use of a publically-accessible content cache; “private”, indicating that mhn should make use of the user's private content cache; “never”, indicating that mhn should never make use of caching; and, “ask”, indicating that mhn should ask the user. There are two directories where contents may be cached: the profile entry mhn-cache names a directory containing world-readable contents, and, the profile entry mhn-private-cache names a directory containing private contents. The former should be an absolute (rooted) directory name. For example,

mhn-cache: /tmp

might be used if you didn't care that the cache got wiped after each reboot of the system. The latter is interpreted relative to the user's MH directory, if not rooted, e.g.,

mhn-private-cache: .cache

(which is the default value). When you encounter a content of type message/external-body with access type “mail-server”, mhn will ask you if may send a message to a mail-server requesting the content, e.g.,

% show 1
Retrieve content by asking mail-server@...
SEND file
? yes
mhn: request sent

Regardless of your decision, mhn can't perform any other processing on the content. However, if mhn is allowed to request the content, then when it arrives, there should be a top-level “Content-ID:” field which corresponds to the value in the original message/external-body content. You should now use the `-cache' switch to tell mhn to enter the arriving content into the content cache, e.g.,

% mhn -cache 2
caching message 2 as file ...

You can then re-process the original message/external-body content, and “the right thing should happen”, e.g.,

% show 1
 ...
The mhn program can also be used as a simple editor to aid in composing multi-media messages. When invoked by a whatnow program, mhn will expect the body of the draft to be formatted as an “mhn composition file.” The syntax of this is straight-forward:

   body         ::=     1*(content | EOL)
   content      ::=     directive | plaintext
   directive    ::=     "#" type "/" subtype
                            0*(";" attribute "=" value)
                            [ "(" comment ")" ]
                            [ "<" id ">" ]
                            [ "[" description "]" ]
                            [ filename ]
                            EOL
                      | "#@" type "/" subtype
                            0*(";" attribute "=" value)
                            [ "(" comment ")" ]
                            [ "<" id ">" ]
                            [ "[" description "]" ]
                            external-parameters
                            EOL
                      | "#forw"
                            [ "<" id ">" ]
                            [ "[" description "]" ]
                            [ "+"folder ] [ 0*msg ]
                            EOL
                      | "#begin"
                              [ "<" id ">" ]
                              [ "[" description "]" ]
                              [   "alternative"
                                | "parallel"
                                | something-else    ]
                              EOL
                            1*body
                        "#end" EOL
   plaintext    ::=     [ "Content-Description:"
                              description EOL EOL ]
                            1*line
                        [ "#" EOL ]
                      | "#<" type "/" subtype
                            0*(";" attribute "=" value)
                            [ "(" comment ")" ]
                            [ "[" description "]" ]
                            EOL
                            1*line
                        [ "#" EOL ]
   line         ::=     "##" text EOL
                        -- interpreted as "#"text EOL
                      | text EOL

Basically, the body contains one or more contents. A content consists of either a directive, indicated with a “#” as the first character of a line; or, plaintext (one or more lines of text). The continuation character, “\“, may be used to enter a single directive on more than one line, e.g.,

#@application/octet-stream; \
    type=tar; \
    x-conversions=compress

There are four kinds of directives: “type” directives, which name the type and subtype of the content; “external-type” directives, which also name the type and subtype of the content; the “forw” directive, which is used to forward a digest of messages; and, the “begin” directive, which is used to create a multipart content. For the type directives, the user may optionally specify the name of a file containing the contents in “native” (decoded) format. (If the filename starts with the “|” character, then this gives a command whose output is captured accordingly.) If a filename is not given, mhn will look for information in the user's profile to determine how the different contents should be composed. This is accomplished by consulting a composition string, and executing it under /bin/sh, with the standard output set to the content. The composition string may contain these escapes:

%a	additional arguments
%f	filename containing content
%F	%f, and stdout is not re-directed
%s	subtype

First, mhn will look for an entry of the form:

mhn-compose-<type>/<subtype>

to determine the command to use to compose the content. If this isn't found, mhn will look for an entry of the form:

mhn-compose-<type>

to determine the composition command. If this isn't found, mhn will complain. An example entry might be:

mhn-compose-audio/basic: record | raw2audio -F

Because commands like these will vary, depending on the display environment used for login, composition strings for different contents should probably be put in the file specified by the $MHN environment variable, instead of directly in your user profile. The external-type directives are used to provide a reference to a content, rather than enclosing the contents itself. Hence, instead of providing a filename as with the type directives, external-parameters are supplied. These look like regular parameters, so they must be separated accordingly, e.g.,

#@application/octet-stream; \
    type=tar; \
    x-conversions=compress [] \
    access-type=anon-ftp; \
    name="mh-mime.tar.Z"; \
    directory="mrose/mh-mime"; \
    site="ftp.ics.uci.edu"

By specifying “[]”, an empty description string is given, and the start of the external-parameters is identified. These parameters are of the form:

access-type=	usually anon-ftp or mail-server
name=	filename
permission=	read-only or read-write
site=	hostname
directory=	directoryname (optional)
mode=	usually ascii or image (optional)
size=	number of octets
server=	mailbox
subject=	subject to send
body=	command to send for retrieval

For the forw directive, the user may optionally specify the name of the folder and which messages are to be forwarded. if a folder is not given, it defaults to the current folder. Similarly, if a message is not given, it defaults to the current message. Hence, the forw directive is similar to the forw (1) command, except that the former uses the MIME rules for encapsulation rather than those specified in RFC 934. Usage of the `-rfc934mode' switch indicates whether mhn should attempt to utilize the encapsulation rules in such a way as to appear that RFC 934 is being used. If given, then RFC 934-compliant user-agents should be able to burst the message on reception -- providing that the messages being encapsulated do not contain encapsulated messages themselves. The drawback of this approach is that the encapsulations are generated by placing an extra newline at the end of the body of each message. For the begin directive, the user must specify at least one content between the begin and end pairs. For all of these directives, the user may include a brief description of the content between the “[” character and the “]” character. By default, mhn will generate a unique “Content-ID:” for each directive; however, the user may override this by defining the ID using the “<” and “>” characters. Putting this all together, here is a brief example of what a user's components file might look like:

To:
cc:
Subject:
--------
#audio/basic [Flint phone]  \
    |raw2audio -F < /home/mrose/lib/multi-media/flint.au
#image/gif   [MTR's photo] \
                    /home/mrose/lib/multi-media/mrose.gif

For a later example, we'll call this components file mhncomps. As noted earlier, in addition to directives, plaintext can be present. Plaintext is gathered, until a directive is found or the draft is exhausted, and this is made to form a text content. If the plaintext must contain a “#” at the beginning of a line, simply double it, e.g.,

##when sent, this line will start with only one #

If you want to end the plaintext prior to a directive, e.g., to have two plaintext contents adjacent, simply insert a line containing a single “#” character, e.g.,

this is the first content
#
and this is the second

Finally, if the plaintext starts with a line of the form:

Content-Description: text

then this will be used to describe the plaintext content. NOTE WELL: you must follow this line with a blank line before starting your text. By default, plaintext is captured as a text/plain content. You can override this by starting the plaintext with “#<” followed by a content-type specification, e.g.,

#<text/richtext
this content will be tagged as text/richtext
#
and this content will be tagged as text/plain

Note that if you use the “#<” plaintext-form, then the content-description must be on the same line which identifies the content type of the plaintext. If mhn is successful, it renames the original draft to start with the “,” character and end with the string “.orig”, e.g., if you are editing the file “draft”, it will be renamed to “,draft.orig”. This allows you to easily recover the mhn composition file. If the `-check' switch is given, mhn will associate an integrity check with each content. Note that MH will not invoke mhn automatically, unless you add this line to your .mh_profile file:

automhnproc: mhn

Otherwise, you must specifically give the command

What now? edit mhn

prior to sending the draft. You can easily tailor MH to help you remember to do this. Suppose you have these lines in your profile:

mcomp:          -editor mprompter -form mhncomps
mprompter:      -noprepend -norapid
mprompter-next: mhn

where mcomp is a link to comp (1), and mprompter is a link to prompter (1). Then to send a message using the mhncomps components file above, the sequence is:

% mcomp
To: user@host
cc:
Subject: multi-media message
--------
#audio/basic [Flint phone]  \
    |raw2audio -F < /home/mrose/lib/multi-media/flint.au
#image/gif   [MTR's photo] \
                    /home/mrose/lib/multi-media/mrose.gif
--------Enter additional text
This message contains three contents.
<CTRL-D>
--------
What now? edit (this invokes mhn)
What now? send

You have to remember to type the additional edit command, but it should be fairly obvious from the interaction. Finally, you should consider adding this line to your profile:

lproc: show

This way, if you decide to list after invoking mhn as your editor, the command

What now? list

will work as you expect. When you want to send a bunch of files to someone, you can run the viamail shell script, which is similar the tarmail command:

/usr/local/lib/mh/viamail mailpath “subject” files ...

viamail will archive the directories/files you name with tar (1), and then mail the compressed archive to the `mailpath' with the given `subject'. The archive will be automatically split up into as many messages as necessary in order to get past most mailers. Sometimes you want viamail to pause after posting a partial message. This is usually the case when you are running sendmail and expect to generate a lot of partial messages. If the first argument given to viamail starts with a dash, then it is interpreted as the number of seconds to pause in between postings, e.g.,

/usr/local/lib/mh/viamail -300 mailpath “subject” files ...

will pause 5 minutes in between each posting. When these messages are received, invoke mhn once, with the list of messages, and the `-store' command. The mhn program will then store exactly one message containing the archive. You can then use `-show' to find out what's inside; possibly followed by `-store' to write the archive to a file where you can subsequently uncompress and untar it, e.g.,

% mhn -list all
 msg part  type/subtype             size description
   1       message/partial           47K part 1 of 4
   2       message/partial           47K part 2 of 4
   3       message/partial           47K part 3 of 4
   4       message/partial           18K part 4 of 4
% mhn -store all
% mhn -list -verbose last
 msg part  type/subtype             size description
   5       application/octet-stream 118K
             (extract with uncompress | tar xvpf -)
             type=tar
             x-conversions=compress
% mhn -show last
 msg part  type/subtype             size description
   5       application/octet-stream 118K
-- headers of message, followed by tar listing appears here
% mhn -store last
% uncompress < 5.tar.Z | tar xvpf -

Alternately, by using the `-auto' switch, mhn will automatically do the extraction for you, e.g.,

% mhn -list all
 msg part  type/subtype             size description
   1       message/partial           47K part 1 of 4
   2       message/partial           47K part 2 of 4
   3       message/partial           47K part 3 of 4
   4       message/partial           18K part 4 of 4
% mhn -store all
% mhn -list -verbose last
 msg part  type/subtype             size description
   5       application/octet-stream 118K
             (extract with uncompress | tar xvpf -)
             type=tar
             x-conversions=compress
% mhn -show last
 msg part  type/subtype             size description
   5       application/octet-stream 118K
-- headers of message, followed by tar listing appears here
% mhn -store -auto last
-- tar listing appears here as files are extracted

As the second tar listing is generated, the files are extracted. A prudent user will never put `-auto' in the .mh_profile file. The correct procedure is to first use `-show', to find out what will be extracted. Then mhn can be invoked with `-store' and `-auto' to perform the extraction. Because the display environment in which mhn operates may vary for a user, mhn will look for the environment variable $MHN. If present, this specifies the name of an additional user profile which should be read. Hence, when a user logs in on a particular display device, this environment variable should be set to refer to a file containing definitions useful for the display device. Normally, only entries of the form

mhn-show-<type>/<subtype>
mhn-show-<type>

need be present. Finally, mhn will attempt to consult one other additional user profile, e.g.,

/usr/local/lib/mh/mhn_defaults

which is created automatically during MH installation. ^$HOME/.mh_profile~^The user profile ^$MHN~^Additional profile entries ^/usr/local/lib/mh/mhn_defaults~^System-default profile entries ^/usr/local/lib/mh/mhl.headers~^The headers template ^Path:~^To determine the user's MH directory ^Current-Folder:~^To find the default current folder ^mhlproc:~^Default program to display message headers ^mhn-access-ftp:~^Program to retrieve contents via FTP ^mhn-cache~^Public directory to store cached external contents ^mhn-charset-<charset>~^Template for environment to render character sets ^mhn-compose-<type>*~^Template for composing contents ^mhn-private-cache~^Personal directory to store cached external contents ^mhn-show-<type>*~^Template for displaying contents ^mhn-storage~^Directory to store contents ^mhn-store-<type>*~^Template for storing contents ^moreproc:~^Default program to display text/plain content mhl(1)
MIME: Mechanisms for Specifying and Describing the Format of Internet Message Bodies (RFC 1521),
Proposed Standard for Message Encapsulation (RFC 934). `+folder' defaults to the current folder `msgs' defaults to cur `-noauto' `-nocache' `-nocheck' `-noebcdicsafe' `-form mhl.headers' `-headers' `-pause' `-rcache ask' `-realsize' `-rfc934mode' `-noserialonly' `-show' `-noverbose' `-wcache ask' If a folder is given, it will become the current folder. The last message selected will become the current message. Partial messages contained within a multipart content are not reassembled with the `-store' switch.