Monday, June 25, 2007

fetchmail -- by Eric S Raymond

Raymond has written a famous book TAUP "The Art of Unix Programming", I borrowed it from library several times, I liked to read it--.

Until today, I download the source code of fetchmail, (it is a C case study in TAUP). Interesting found that fetchmail is really written by Raymond, so I see why there are a lot of samples are from fetchmail, POP3, SMTP etc, in the book (TAUP). Fetchmail is written by C and it is so neat!! As I cscope into it, the struct as "method", "query", etc, I like such nice design. When read the code, I found some routines are very long, is it a pity? But at least the whole functions or interfaces are kept light! The hard part to me is I am not going to learn the protocols (POP3, SMTP, RFCs). It is not documented in a doxygen layout although it contains a doxygen config file. Discard such things, I still think fetchmail is very good sample on C, it is great because it is coded farely "light" in C, even it deals with different protocols (RFCs).

Here is a demo in "fetchmail.h":

struct method /* describe methods for protocol state machine */
{
const char *name; /* protocol name */
const char *service; /* service port (unencrypted) */
const char *sslservice; /* service port (SSL) */
flag tagged; /* if true, generate & expect command tags */
flag delimited; /* if true, accept "." message delimiter */
int (*parse_response)(int, char *);
/* response_parsing function */
int (*getauth)(int, struct query *, char *);
/* authorization fetcher */
int (*getrange)(int, struct query *, const char *, int *, int *, int *);
/* get message range to fetch */
int (*getsizes)(int, int, int *);
/* get sizes of messages */
int (*getpartialsizes)(int, int, int, int *);
/* get sizes of subset of messages */
int (*is_old)(int, struct query *, int);
/* check for old message */
int (*fetch_headers)(int, struct query *, int, int *);
/* fetch header from a given message */
int (*fetch_body)(int, struct query *, int, int *);
/* fetch a given message */
int (*trail)(int, struct query *, const char *);
/* eat trailer of a message */
int (*delete_msg)(int, struct query *, int);
/* delete method */
int (*mark_seen)(int, struct query *, int);
/* mark as seen method */
int (*end_mailbox_poll)(int, struct query *);
/* end-of-mailbox processing */
int (*logout_cmd)(int, struct query *);
/* logout command */
flag retry; /* can getrange poll for new messages? */
};