MH & nmh: Email for Users & Programmers

May, 2006

Using Links

Because MH stores messages in UNIX files, it can take advantage of UNIX links, introduced here. They let you have more than one name for the same file. The following list presents an overview of using links:

Making Links

To link messages, use the refile -link command. When you give more than one destination folder name to refile -- with or without -link -- the message will be linked between those folders.

Remember that MH makes standard ("hard") links, not symbolic ("soft") links. If you need to link between filesystems, see the Section Using Symbolic Links.

Are These Two Messages Linked?

(xmh users: instead of scan, check your table of contents. Instead of rmm, use Delete.)

To find out whether two messages are linked, first scan them both. The format file called scan.size will show the number of characters in each message (for more information see the Section scan Format Files):

    % scan -form scan.size 13 +reports
      13  12/14   892 Vicki Thomas       Progress Report<<I'm out o
    % scan -form scan.size 22 +vicki
      22  12/14   892 Vicki Thomas       Progress Report<<I'm out o
The messages look identical: each one has 892 characters. But to be sure that the messages are linked (and not just identical copies), compare the files' i-numbers. (To be completely sure, you need to compare the device names, too. But it's very unlikely that two message files which scan the same and have the same i-numbers would not be linked.) (You may also want to read the Section Technical Stuff About Links.) To compare the i-numbers, list the two message files with ls -li. Be sure to use backquotes (`), not single quotes ('). Fill in the message number and folder name:
    % ls -li `mhpath 13 +reports`
     20930 -rw-------  1 eds   892 Feb  1 04:32 /u1/eds/Mail/reports/13
    % ls -li `mhpath 22 +vicki`
      2508 -rw-------  2 eds   892 Dec 14 17:31 /u1/eds/Mail/vicki/22
The first number in the ls -li output is the i-number of the file (your version of ls might be different -- if you aren't sure, ask a local expert). These two files have different i-numbers (20930 and 2508), so they are not linked. The third item in each line is the link count -- it tells how many links that file has. Here, the first file has one link (itself) and the second has two. If the files were linked, both link counts would be the same.

If you want to replace the "non-linked" message in the reports folder with a link to the message in the vicki folder, here's how:

  1. Remove the message you don't want:
          % rmm +reports 13
  2. Link to the other copy. You can do it in one step with refile and its -src switch:
          % refile -link +reports -src +vicki 22
    That might be easier to see in two steps:
          % folder +vicki
                      vicki+ has   32 messages (   1-  32); cur=   4.
          % refile -link 22 +reports
The new link in the reports folder will have a new message number -- the last message in the folder.

A Folder Full of Links

(xmh users: instead of refile, use Copy as Link.)

Have you ever asked yourself, "What folder did I put that message in?" You can use pick and a loop to search lots of folders, as in Section Searching More Than One Folder. This section explains a setup you might like better: a link folder. (That's not official MH terminology. I made up the name.)

When you want to save a message, you can link the message into two folders: the folder where you'd usually store it, and a special folder that has links to all (or many of) your messages. Because the link doesn't take any more disk space, why not do it? The refile command can link messages into more than one folder. See the Section Moving and Linking Messages: refile.

To find a message, search the link folder.

One Folder, Many Folders, Subfolders...

There are a lot of ways to set up a link folder, depending on your mail configuration and your wants. Find something that's simple enough to manage but capable enough to help you find your messages. Some ideas to get you started:

Whatever you do, I think I've given you enough ideas to get you started. Why not try a link folder -- and take advantage of the flexibility that MH gives you?

Making the Links

To refile a message into your recipes folder with a link to the link folder a, type:

    % refile +recipes +a
In some cases, instead of using a top-level a folder, I make a separate a subfolder with a name like mh-book/a:
    % refile +mh-book/a +mh-book/revisions +mh-book/readers
If you use the C shell, its curly-brace operators {...,...} will let you automatically repeat the top-level folder name. From the previous example:

% refile +mh-book/{a,revisions,readers}    C shell

If you already have folders full of messages, you can use refile -link to link existing messages into your link folder. Use a command like:

    % refile -link all +a
Or, use a shell loop like the one in the Example below. In the example, I give the loop a list of a few folders; it links all of those messages into a folder called ln.

Example: Linking existing messages into new all-message folder

C shell:

    % foreach f (rpts memos ...)
    ? refile -src +$f -link all +ln
    ? end
Bourne and Korn shells:
    $ for f in rpts memos ...
    > do refile -src +$f -link all +ln
    > done
To link all messages in all folders instead, you could replace the first line of the previous Example with the line:
    % foreach f (`folders -fast | fgrep -v -x ln`)
    $ for f in `folders -fast | fgrep -v -x ln`
The command fgrep -v -x ln avoids trouble by omitting the ln folder in the list of folders to link from. Add the -recurse option to make folders include subfolders too.

Finding Stuff in a Link Folder

After making that setup, you might want to sort the link folder by date once in a while (see the Section Sorting Messages: sortm). That makes it easier for pick to find messages, because the folder can get really huge. If you're looking for a message from the last month, and your a folder has a year's worth of messages, you can give pick a shorter range of messages to search. For example, if you guess that there aren't more than 100 messages from the last month, you can save a lot of time with:

    % pick last:100 ...

Don't Break Links Accidentally

If you make links to many of your messages, you'll probably want to give the -inplace switch to commands that edit messages. It makes sure that annotations won't break one of your links. Do it in your MH profile for the anno command. Also, if you use -annotate with repl, forw, or dist, add -inplace there, too.

Removing Messages

There's one gotcha about linked messages. When you want to remove the message, if you don't remove all the links, the message isn't taken off the disk. There's no MH command that does the whole job. But, with help from a couple of UNIX commands, it's a pretty easy job to do. (Reading the Chapter Key Parts of the UNIX Filesystem should help you understand the steps below.) If you do this a lot, it's worth writing a little shell script to find the links for you -- and maybe even to remove them.

Let's say you want to remove message 234 in your reports folder and its link in the a folder:

  1. cd to your MH directory by typing cd Mail -- or, more generally:
          % cd `mhpath +`
  2. Find the i-number of the message. Do that by listing it in its folder with ls -i:
          % ls -i reports/234
           37023 reports/234
  3. Use find to search the link folder for a message with the same i-number (in this case, it's 37023):
          % find a -inum 37023 -print
  4. The message is number 1708 in your a folder. Remove it and its other link. Then you're done:
          % rmm 234 +reports
          % rmm 1708 +a
If you aren't sure what folder the links are in, have find search all folders for the message. Use the pathname . (dot) instead of the folder name:
    % find . -inum 37023 -print
There, we found the link in the a folder and another link too: message 23 in the done folder.

Links Between Users

It's as easy to link to another user's messages as it is to link to your own. This is especially useful when a group needs to share certain messages from folder(s) but doesn't want to wade through the unimportant messages in another user's folder -- each user can link to only the messages he or she needs.

For example, a group of software maintenance people might want to link to certain messages in certain folders on a central problem-tracking account. Each maintenance person could have a folder in his or her MH directory, with a list of messages for the problems that were assigned to him or her. When a new problem is assigned, the maintainer could make a new link. When the problem is solved, the maintainer could rmm his or her personal link to the message. The group's manager could use a command like anno -inplace to update the messages in the central problem-tracking folders, and all the maintainers would see the changes in their linked messages instantly.

In the right situation, with some planning and forethought, a system like that can be effective. Here are some things to watch out for:

Here's an example. The user ehuser wants to link to message 2 in jdpeek's folder named tester. She makes that folder her current folder, finds the message, then links it to her test folder:
    % folder +/u3/jdpeek/Mail/tester
    /u3/jdpeek/Mail/tester+ has    5 messages (  1-  5); cur=  4.
    % scan
       1  04/06   rcvtty -- how do I use it?<<I've
       2  11/13 well!pokey@phlabs  Re: Encapsulation destroying goo
       3  03/09 Barbara Zimmerman  Confused over mh-format files<<O
    scan: unable to open message 4: Permission denied, continuing...
    scan: unable to open message 5: Permission denied, continuing...
    % refile -link 2 +test
    % scan +test
       1+ 12/14 jdpeek@rodan.acs.  I'm out of town<<I'm out of town
       2  01/28*To:                << -- Jerry Peek; Syracuse Univers
       3  02/03*To:jerryp          sdaff<<dfkjdf --Jerry Peek; Syra
       4  12/14 jdpeek@rodan.acs.  I'm out of town<<I'm out of town
       5  11/13 well!pokey@phlabs  Re: Encapsulation destroying goo
Notice that no matter what your current folder is, you always refer to your own folders with their normal name (like +test). You refer to other users' folders by using a full pathname with a plus sign (+) before it, like +/u3/jdpeek/Mail/tester. (But you can still use relative folder operators. For instance, let's say your current folder is /u3/jdpeek/Mail/tester. You could get to its subfolder sub with @sub as well as with +/u3/jdpeek/Mail/tester/sub. See the Section Relative Folder Names for more information.)

Also notice the Permission denied warnings. The warnings tell ehuser that jdpeek hasn't given her permission to read those two messages. The Section Sharing Other Users' Folders explains more.

Using Symbolic Links

(xmh users: it's possible to do this with standard UNIX commands in an xterm window. I don't recommend symbolic links to folders for xmh, though; the NOTE in Section MH Directory Path tells why.)

As the Section Links explains, the hard links that MH uses can't cross filesystems. MH can't link to a message in a folder on another filesystem or across a network. (Not yet, at least.) Instead of bothering with the complications of links, MH (but not xmh) users can access any folder on any filesystem by typing its pathname -- see the Section Sharing Other Users' Folders.

Still need to make a link? Does your UNIX have symlinks (symbolic links, the ln -s command)? It's possible to make symlinks to folders, but that can be tricky. Symlinks will also work for individual messages. I recommend that you don't use symlinks unless you need them. Unlike hard links, each symlink takes a block of disk space. Also, because MH doesn't support them (not yet, anyway), using symlinks with MH seems like a "hack" to me... but not enough of a hack to keep me from explaining how to use them. :-)

I'll use my setup as an example. I have a workstation with a local disk that has a /mhdir directory; I store most of my mail there. But I need to share some of my mail with other people in the company. That mail is in my home directory, /u/jerry/Mail, which is part of a filesystem mounted across the network to all of our computers. On my workstation, my MH profile has Path: /mhdir in it. (On other computers, I set the MH environment variable to point to an MH profile with the other Path:. But that's not important in this example.)

Symlinks to Messages

To make a new symlink from my stuff folder on my local filesystem that points to message 822 in the bookq folder on the other filesystem:

    % scan 822 +/u/jerry/Mail/bookq
     822 -07/10 Jeffrey Smith   Vol 8 of X Windows set<<Hi! Is Vol 8
    % ln -s `mhpath 822` `mhpath new +stuff`
    % scan last +stuff
       2 -07/10 Jeffrey Smith   Vol 8 of X Windows set<<Hi! Is Vol 8
    % ls -l `mhpath 2`
    lrwxrwxrwx  1 jerry       23 Jul 14 09:20 /mhdir/stuff/2 -> /u/jerry/Mail/bookq/822
NOTE: Don't use sortm or folder -pack on the folder where a symbolic link points (in the example above, the bookq folder). If you do, the link may end up pointing to a different message -- or no message at all.

Hard links (the kind that MH makes) don't have this problem.

If you remove or refile the message that a link points to, remember to remove the link too. Otherwise you'll see strange errors like:

    % rmm 822 +/u/jerry/Mail/bookq
    % scan +stuff
       1  01/26 To:jerry           Messages to handle in inbox, bookq
    scan: unable to open message 2: No such file or directory, continuing...
In general, you can just use rmm to remove the link. If that doesn't work, remove it with the UNIX rm command:
    % rm `mhpath 2`

Symlinks to Folders

You can also make a symbolic link from your top-level MH directory to another folder in a different MH directory or vice versa.

CAUTION: If you link to folders -- especially to subfolders -- be sure you know what you're doing. If you link to a folder, and there's also a symlink from a folder underneath it pointing back to your folder, you can get an infinite loop. MH commands like folder -recurse will not catch this.

Also, be sure to remove the link with rm, not rmf. See the CAUTION at the end of this section.

The nmh folder -recurse and flist -recurse commands use a trick to speed up subfolder searches that can cause you headaches if you symlink to other folders. If you make a folder whose "subfolders" are all actually symlinks (to other folders), nmh won't search it recursively. A workaround is to make at least one real subfolder -- which can be empty. (The gory details: If a folder directory has just two hard links, nmh -- version 1.0 and some earlier versions, at least -- assumes that the folder has no subdirectories -- no subfolders, that is -- and it stops searching recursively.)

The other problem you can have with symlinks to folders comes when you use folders for a summary of your folders (or, worse, in a loop run by some script to do something to all your folders). If one of the folders is a read-only folder, it can appear twice. Say I've made a symlink named project in my local MH directory that points to the read-only folder /u/barb/Mail/zeta. Unless I remember to rmf the reference to /u/barb/Mail/zeta (explained in the Section Removing Folders: rmf), the folders output will look like the next Example.

Example: Symlink causes double listing of read-only folder

               Folder      # of messages (  range  ); cur  msg ...
    /u/barb/Mail/zeta  has   52 messages (   1-  64).
              project  has   52 messages (   1-  64).
And, of course, the relative folder operator @ won't do what you expect it to after you change your current folder through a symlink.

"Okay, okay," you say, "tell me how to do it anyway!" It's easy. Just cd to the directory above where you want the folder to appear, and then use ln -s. For instance, I'll make the link to Barb's zeta folder shown in the example above. In this case, to make the top-level "folder" (symlink), I'll need to go to the top-level MH directory:

    % cd `mhpath +`
    % ln -s /u/barb/Mail/zeta project
The next example shows how to make a "subfolder" (symlink) called work/zeta to Barb's zeta folder. When the symlink has the same name as what it points to, you don't need to give ln the name twice:
    % cd `mhpath +work`
    % ln -s /u/barb/Mail/zeta
If you remove the folder that a symlink points to, remember to remove the symlink too. To remove the symlink, be sure to use the UNIX rm command, not the MH rmf command! For example, to remove a symlink named tmp, type:
    % rm `mhpath +tmp`
CAUTION: Do not use the MH rmf command to remove a symbolic link to a folder. If you do (on MH 6.7.2 and 6.8.3, at least), rmf will not remove the symlink. Instead, if it can, rmf will remove all messages from the folder that the link points to! That's another reason why I think you should avoid symbolic links to folders.