# Snooping on xmh

If you're trying to find out how xmh uses MH commands so that you can change the way commands work without causing problems, try the techniques in this section.

## Use the debug Resource

If you set the xmh*debug resource, xmh will write debugging information to its standard error. The easiest way to do that is by starting xmh from an xterm window (probably with a scrollbar). For example:

        % xmh -xrm '*debug:1'
        # 4 : /u/ehuser/.mh_profile
        # 4 : <Closed>
        # 4 : /u/ehuser/.xmhcheck
        # 4 : <Closed>
        Making screen ... Realizing... done.
         setting toc ... # 4 : /u/ehuser/Mail/inbox/.xmhcache
        # 4 : <Closed>
        # 4 : /u/ehuser/Mail/inbox/.mh_sequences
        # 4 : <Closed>
        done.
        (Checking for new mail... done)
        (Checking for new mail... done)
                ...etc....
        [magic toc check ... done]
                ...etc....
        (Checking for new mail... done)
        [magic toc check ...# 4 : /u/ehuser/Mail/inbox/.xmhcache
        # 4 : <Closed>
        Executing scan ... pid=13898 blocking.
        unblocked; child not done.
        reading alternate input...read.
        blocking.
        unblocked; child not done.
        reading alternate input...read.
        done
        # 4 : /u/ehuser/Mail/inbox/.xmhcache
        # 4 : <Closed>
        # 4 : /u/ehuser/Mail/inbox/.mh_sequences
        # 4 : <Closed>
         done]

Here's some brief explanation:

- Messages like `# 4 : /u/ehuser/.mh_profile` show xmh opening the MH profile file; the `4` means xmh is using UNIX file descriptor 4. The `# 4 : <Closed>` lines is printed when it's done.
- As xmh builds the master window, it prints `Making` `screen... Realizing... done`.
- The lines between `setting toc...` and the next `done.` show the steps in building the Table of Contents.
- A message `(Checking for new mail...` `done)` is printed every time xmh checks your system mailbox -- and other mail drops listed in your .xmhcheck file).
- The `[magic toc check... done]` shows xmh checking the Table of Contents to see if it's out of date for some reason. For instance, maybe an `Fcc:` message was dropped into the folder. If the TOC needs updating, you'll see the message `Rescanning foldername` above the Table of Contents; xmh will run scan.
- `Executing scan... pid=13898` shows the MH command name and the UNIX process ID number. While the process runs, xmh waits for it and prints `blocking.`. Every second or so, xmh prints `unblocked; child not done.`; then it reads output from the process and says `reading alternate input...read.` until the process finishes.

To learn more, start xmh, try things, and watch the messages in your xterm window. You might want to browse through the source code to find out exactly what's happening as each debugging message is printed. Search the code for the string `DEBUG`.

## Use Accounting Information

Many UNIX systems keep accounting data about the processes that each user runs. When xmh runs a standard UNIX command, it starts a process to do that. Therefore, to find out whether xmh used an MH command, run the xmh command, then check the accounting data. Many UNIX systems show that data with the lastcomm(1) program. For example, after I used the xmh `Sort Folder` command, lastcomm showed that the sortm and scan commands had been run:

        % lastcomm ehuser
        scan             ehuser   ??         0.23 secs Wed Jul 18 09:10
        sortm            ehuser   ??         0.48 secs Wed Jul 18 09:10
        xwud             ehuser   ttyp1      0.45 secs Wed Jul 18 08:48
                ...

Unfortunately, lastcomm doesn't show what command-line switches were used or what was in the command's environment as it ran. The next section can help with that.

## Make a Front End Shell Script

A much more flexible way to snoop on xmh is by replacing MH commands with shell scripts. In fact, this method doesn't just work for snooping -- you can also use it to change the way that xmh runs MH commands.

The idea is to make a directory full of symbolic links to all the MH programs. Tell xmh to use that directory by adding it to your path or setting the MhPath resource. Then, when you want to see or change how xmh uses an MH command, replace the symbolic link with a shell script. The shell script can write log messages to a file, display command-line options that xmh called it with, and execute the MH command. The steps are explained in the next section.

> CAUTION: With a radical change like this, there's always the chance of making a mistake that loses or corrupts your mail. If you use xmh for reading important email, I don't recommend this method unless you're very comfortable with UNIX and shell programming.

Making the MhPath Directory, Making xmh Use It

Here are the steps you need to follow to set up the MhPath directory. You only need to do this once.

1. First, make a directory on your account with symbolic links to the executable MH commands. You could name it xmhbin. (To make the directory, use the command `mkdir $HOME/xmhbin`.)
2. Next, link the MH commands. I use symbolic links because they're easy to list (with ls -l) and see where the links "point." But you may also be able to use UNIX "hard" links if the MH executables are on the same filesystem as your home directory.
   - For instance, if your MH commands (comp, inc, etc.) are all stored in the directory /usr/local/mh, you could link theminto your new directory this way:

               % ln -s /usr/local/mh/* $HOME/xmhbin
               % cd $HOME/xmhbin
               % ls -l
               lrwxrwxrwx  1 ehuser   17 Jul 15 09:37 ali -> /usr/local/mh/ali
               lrwxrwxrwx  1 ehuser   18 Jul 15 09:37 anno -> /usr/local/mh/anno
                       ...

     xmh doesn't actually use all of the MH commands, so you could probably omit some of those links. There's a list of MH commands used at the end of your online xmh(1) manual page.
   - If your system's MH commands are mixed in a directory with other executables, you usually won't want to link in the other programs. Use a shell loop (I use the C shell here) to make the links you want.Start from your xmhbin directory.

               % foreach prog (ali anno burst ...)
               ? ln -s /usr/local/bin/$prog
               ? end

     The section Looping Through a List of Arguments has more information on shell loops.
3. Then start xmh using the new executables and be sure it still works. Type one of the following commands.
   - For xmh Release 3 or 4:

               % xmh -xrm "*MhPath:$HOME/xmhbin" &

     The double quotes (`"`) around the `-xrm` string let the shell replace `$HOME` with its value. If you put the MhPath entry in a resource file such as .Xdefaults which isn't read by a shell, you'll need to use the literal pathname of the directory (like /xxx/you/xmhbin).
   - xmh Release 5 and 6 look in the search path for commands before using the *MhPath resource. Set your search path temporarily before you start xmh. If you want to make the change permanent, edit your .cshrc or .profile file later. Put your $HOME/xmhbin directory somewhere before the MH binary directory (like /usr/local/mh). Here's an example for the C shell:

               % set path=($HOME/xmhbin $path)
               % xmh &

4. Try a couple of xmh commands that run MH commands, such as `Incorporate New Mail` or `Sort Folder`. Then use ls -lut to show the last access time of the symbolic links in your xmhbin; when xmh uses them, their last access time (atime) will be updated, and you can see that in the ls -lut output.

Replace a Link with a Shell Script

The next step is to replace a link with a front-end shell script. First, rename the link (or remove it):

        % pwd
        /xxx/yyy/xmhbin
        % mv sortm sortm.orig

Here's a simple shell script for sortm. (This file is in the book's online archive, too, at examples/xmh/bin/sortm.sh.) It writes a lot of information to a log file in your home directory, then executes the MH command:

        #! /bin/sh
        # sortm - front end to MH sortm command, run from xmh
        # appends logging information to $HOME/sortm.log first
        # use subshell to gather all command output, stdout and stderr:
        (date
        echo "args are: $0 $*"
        echo "environment has:"
        printenv) >> $HOME/sortm.log 2>&1

        # run the real command with exec, so this script
        # (and the shell that runs it) can exit now:
        exec /usr/local/mh/sortm $*

After you've installed the script, try it (in this case, use the `Sort Folder` command). The sortm.log file in your home directory should look something like this:

        % cat $HOME/sortm.log
        Wed Jul 18 10:12:46 EDT 1990
        args are: /xxx/you/xmhbin/sortm +/xxx/you/Mail/inbox -noverbose
        environment has:
        DISPLAY=unix:0.0
        EDITOR=/usr/ucb/vi
        HOME=/xxx/you
                ...

and, of course, your current folder should have been sorted.

Standard Output vs. Standard Error

If your shell script writes any messages to the standard output, xmh may ignore them. Or, in cases where xmh is expecting to read useful information on the standard output, xmh could accidentally include what your script writes to the standard output. For example, when you `Rescan Folder`, xmh runs scan and puts the scan standard output into the .xmhcache file.

xmh Release 4 added a nice new feature: if a command writes a message to the standard error, the message is displayed in a notice box. Your script can use this feature to send you messages. As a semi-useless but easy to understand example, here's a version of pick that shows the command-line options xmh uses. (This file is in the book's online archive, too, at examples/xmh/bin/pick.sh.)

        #! /bin/sh
        echo "pick arguments are: $*" | fmt -50 1>&2
        exec /usr/local/mh/pick ${1+"$@"}

The `fmt -50` command folds lines at whitespace to keep the box width reasonable. If you don't have fmt, try fold instead. The `${1+"$@"}` works around a problem with command-line parameters in sme older Bourne shells. I ran that pick front-end with search shown in the Figure Example of Pick skip button. The window I got after pick finishes is shown in the Figure below. (It makes me glad I did that with an xmh `Pick` window instead of typing the MH pick command myself.)

Figure: Making a notice box

I don't recommend using xmh notice boxes for commands that make a lot of output. I'd bet that they weren't really designed for this sort of abuse....

> NOTE: xmh Release 3 isn't happy about unexpected output and doesn't make the nice notice boxes. Use a log file instead.

## Read the Source Code

Here's one last idea: if your computer has the xmh source code online and you feel like digging into it, that's the best way to find out exactly what's happening. Look at the C programs (the *.c files) in the xmh subdirectory of your X source tree.