# 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/.