Well, I still haven't found the problem with t_fseek, but everything else is coming along quite well. The command loop now resembles its final form, and everything has been modified to use table-driven code. Commands are defined using data structures:

typedef struct {
    char* name;
    imap_command_proc_t handler;
    int group;
    int minargs, maxargs;
    char* summary;
    char* synopsis;
    char** help;
} imap_command_t;

The command loop uses this information to do as much error-checking as it can, which keeps lots of logic in the tables and out of the handler functions.

The three char* sections at the bottom are used for helpful error messages and online help. Writing individual handler functions is no harder than writing command-line C programs. You even get "Usage:" messages and error reporting for free.

I'm going to finish off the online help system before leaving for dinner. When it's done, rudimentary IMAP protocol documentation will be available over the network (instead of in my source comments, where it lives now). Of course, this will also be table-driven.