Programming exmh
by Brent Welch

exmh is a Tcl/Tk script that uses the MH programs to manage your mail. The script is interpreted at runtime and is therefore distributed in source form. You can read the source to figure out what is really going on. Furthermore, you can take advantage of the Tcl library facility to override parts of the implementation.

Even if you don't know Tcl, you can probably figure it out as you read through the source. There isn't enough room here to talk in any detail about Tcl programming. Tcl and Tk come with reasonably good online manual pages. There are books about Tcl, too. The Reference List suggests some.

Your custom Tcl code is kept in your ~/.tk/exmh directory. You maintain this as a Tcl library -- by keeping a file called tclIndex up-to-date. tclIndex holds a list of Tcl procedures and the files that implement them. The normal Tcl shells (tclsh and wish) provide a Tcl command auto_mkindex that generates this file for you. Within a Tcl shell you use it like this:

    auto_mkindex ~/.tk/exmh  *.tcl
    
The first argument is a directory name. The second argument is a filename pattern -- usually *.tcl. If you add a new file or procedure to this directory, remember to update the index by running this command.

exmh uses the Tcl library facility for the main sources, too. The implementation has been split into more than 50 files; exmh loads these on demand as different features are invoked. The per-user library directory is searched first; this means you can replace parts of the exmh implementation. While this is quite flexible, it is not ideal. The natural unit of replacement is a whole file -- but a file might contain several Tcl procedures, even though you want to change only one. Also, when a new exmh release comes out, there might be incompatibilities with your customized code.

(Note for TclX users: the auto_path stuff is different; the personal library seems not to work. If you figure out the right thing to do in the main exmh script auto_path_update procedure, let me know.)

In most cases you'll merely supply new code -- as opposed to replacing (fixing) parts of the implementation. Because you can define buttons and menus that invoke this new code without touching the released sources, you should be able to graft on new functionality somewhat cleanly.

Start your custom Tcl library by copying the user.tcl file from the script library into your ~/.tk/exmh directory. It contains two empty hook procedures, User_Init and User_Layout. User_Init is called early, before most other modules are initialized. User_Layout is called late, just after the widget tree has been created and almost every module has been initialized.

Some optional hook procedures have names beginning with Hook_. These procedures are called, if they exist, so you don't need stub versions if you don't use them. Because of the way the library facility works, though, you have to either include your Hook procedures in your copy of user.tcl or source the file that contains them from inside your User_Init procedure.

You can also call several hook procedures from the same point by appending things to the standard hook names. That is, the implementation calls all procedures that match the pattern Hook_Foo*. You could define Hook_FooBrent and Hook_FooWelch; both would be called at the Foo hook point. The hook points are:

Hook_FolderChange $folder
Called after you changed into the named folder.
folderHook(enter,$folder)
folderHook(leave,$folder)
The folderHook array can be used to define enter and leave hooks for a folder. Just set these array elements to be the Tcl commands you want invoked before and after the folder change.
Hook_CheckPoint
Called at Quit time.
Hook_SeditSend $draft $t
Called as a message is being sent. The argument is the pathname of the draft message. You can process the message here before it is delivered. If this raises an error, the message is not sent.
Hook_MsgShow $pathname mimeHdr
Called before a message is displayed. The first argument is the pathname of the message file. The second is the name of an array that contains header information plucked out of the message. Because of multipart messages, the elements of the array look like:
mimeHdr(0=1,hdrs)
Lists all the fields defined in the message. The header keys are downcased (from, to, subject, etc.).
mimeHdr(0=1,hdr,key)
Contains the header field with the given key, e.g., from or subject.
Note that the MsgParseFrom procedure, defined in msgShow.tcl, extracts the address part of a header field. Use it as a starting point for your code.

For more information about exmh, see the home page at http://www.beedub.com/exmh/.