Index: ossp-pkg/lmtp2nntp/00TODO RCS File: /v/ossp/cvs/ossp-pkg/lmtp2nntp/00TODO,v rcsdiff -q -kk '-r1.4' '-r1.5' -u '/v/ossp/cvs/ossp-pkg/lmtp2nntp/00TODO,v' 2>/dev/null --- 00TODO 2001/07/24 11:32:06 1.4 +++ 00TODO 2001/07/25 11:29:38 1.5 @@ -58,3 +58,9 @@ o cw.alert@news.de.cw.net cw.alert: "|lmtp2nntp ... -d cw.alert" +ID logging problem + +lmtp_reset() is to be called from a callback, usually RSET. It cleans up all +messages, see lmtp_message(). + + Index: ossp-pkg/lmtp2nntp/lmtp.c RCS File: /v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/lmtp.c,v rcsdiff -q -kk '-r1.3' '-r1.4' -u '/v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/lmtp.c,v' 2>/dev/null --- lmtp.c 2001/07/24 11:32:07 1.3 +++ lmtp.c 2001/07/25 11:29:38 1.4 @@ -41,14 +41,19 @@ } /*************************************************************************/ -/* - * return >= 0 number of chars read, zero is empty line - * return = -1 end of file, no chars inside - * return = -2 buffer overrun, chars inside but no newline seen - * return = -3 io error (errno), buffer content undefined - */ static int readline(lmtp_t *lmtp, char *buf, size_t buflen) { + /* read a line + * + * NOTE: the underlying readline() already reduces any CR/LF combination + * to a string terminating zero. + * + * return >= 0 number of chars read, zero is empty line + * return = -1 end of file, no chars inside + * return = -2 buffer overrun, chars inside but no newline seen + * return = -3 io error (errno), buffer content undefined + */ + size_t n; char c; lmtp_readline_t *rl = &lmtp->rl; @@ -91,6 +96,15 @@ lmtp_t *lmtp_create(int rfd, int wfd, lmtp_io_t *io) { + /* create a lmtp structure allocating memory for it and initializing it. + * A lmtp_cb_default() callback is registered for the default "" verb. + * The _rfd_ and _wfd_ args are passed to the read(), write() and + * select() functions and must have meaning for them. If _io_ is NULL, + * the system io functions are used. You can provide an _io_ structure + * and specify alternate functions. Ommiting one or more functions inside + * the _io_ structure by NULLing it causes use of the system default + * function. + */ lmtp_t *lmtp = NULL; if ((lmtp = (lmtp_t *)malloc(sizeof(lmtp_t))) == NULL) @@ -123,12 +137,33 @@ void lmtp_destroy(lmtp_t *lmtp) { - free(lmtp); + int i; + lmtp_msg_t *msg; + lmtp_msg_t *next; + + //_readmsg : if ((cpBuf = (char *)malloc(nBuf)) == NULL) + + for (i = 0; (i < LMTP_MAXVERBS) && (lmtp->dispatch[i] != NULL); i++) { + msg = lmtp->dispatch[i]->msg; + do { + next = lmtp->dispatch[i]->msg->next; + free(msg); /* linked messages */ + msg = next; + } while(next != NULL); + free(lmtp->dispatch[i]); /* lmtp_register() */ + } + free(lmtp->dispatch); /* lmtp_create() */ + free(lmtp); /* lmtp_create() */ return; } lmtp_rc_t lmtp_readline(lmtp_t *lmtp, char *buf, size_t buflen) { + /* read a line + * + * NOTE: the underlying readline() already reduces any CR/LF combination + * to a string terminating zero. + */ lmtp_rc_t rc; rc = readline(lmtp, buf, buflen); @@ -140,13 +175,19 @@ lmtp_rc_t lmtp_readmsg(lmtp_t *lmtp, char **cppBuf, size_t maxlen) { - /* read lines until end of message, unescape dots + /* read lines until end of message, unescape dots * - * RFC821 "Simple Mail Transfer Protocol" [...] 4.5.2. TRANSPARENCY [...] - * When a line of mail text is received by the receiver-SMTP it checks - * the line. If the line is composed of a single period it is the end of - * mail. If the first character is a period and there are other - * characters on the line, the first character is deleted. [...] + * NOTE: the lmtp_readline()'s underlying readline() already reduces any + * CR/LF combination to a string terminating zero. Callers of this + * function must assume multiline messages have lines terminated + * with NL only. + * + * RFC821 "Simple Mail Transfer Protocol" [excerpt] + * 4.5.2. TRANSPARENCY + * When a line of mail text is received by the receiver-SMTP it checks + * the line. If the line is composed of a single period it is the end of + * mail. If the first character is a period and there are other + * characters on the line, the first character is deleted. */ lmtp_rc_t rc = LMTP_OK; @@ -158,48 +199,39 @@ size_t offsetline; /* memorizing start of line when reallocing in the middle of a line */ nBuf = 4096; - if ((cpBuf = (char *)malloc(nBuf)) == NULL) - return LMTP_ERR_MEM; - *cppBuf = cpBuf; - cpPtr = cpBuf; - cpLine = cpBuf; + if ((cpBuf = (char *)malloc(nBuf)) == NULL) return LMTP_ERR_MEM; + *cppBuf = cpBuf; /* tell caller about the buffer */ + cpPtr = cpBuf; /* initialize write cursor */ + cpLine = cpBuf; /* initialize start of line */ while (1) { -// printf("DEBUG: cpPtr-cpBuf=%d, nBuf=%d, nBuf-(cpPtr-cpBuf)=%d\n", cpPtr-cpBuf, nBuf, nBuf-(cpPtr-cpBuf)); rc = lmtp_readline(lmtp, cpPtr, nBuf-(cpPtr-cpBuf)); -// printf("DEBUG: lmtp_readline()=***%s***, rc=%d\n", cpPtr, rc); if (rc == LMTP_ERR_OVERFLOW) { - if (nBuf == maxlen) - return LMTP_ERR_OVERFLOW; - offset = nBuf-1; - offsetline = cpLine - cpBuf; - nBuf *= 2; - if (nBuf > maxlen) - nBuf = maxlen; + if (nBuf == maxlen) return LMTP_ERR_OVERFLOW; + offset = nBuf-1; /* write cursor offset is end of buffer */ + offsetline = cpLine - cpBuf; /* remember start of line offset */ + nBuf *= 2; /* increase buffer */ + if (nBuf > maxlen) nBuf = maxlen; /* but don't exceed maximum */ if ((cpBuf = (char *)realloc(cpBuf, nBuf)) == NULL) { - free(cpBuf); + free(cpBuf); //FIXME double check isn't this a destroy() task? */ return LMTP_ERR_MEM; } - *cppBuf = cpBuf; - cpPtr = cpBuf + offset; - cpLine = cpBuf + offsetline; + *cppBuf = cpBuf; /* tell caller about the new buffer */ + cpPtr = cpBuf + offset; /* recover write cursor */ + cpLine = cpBuf + offsetline; /* recover start of line */ } else if (rc == LMTP_OK) { - if (strcmp(cpLine, ".") == 0) { -// printf("DEBUG: \".\" found ***%s***\n", cpLine); - *cpLine = '\0'; + if (strcmp(cpLine, ".") == 0) { /* dot alone is end of message */ + *cpLine = '\0'; /* hide dot from caller */ break; } - if (*cpLine == '.') - memmove(cpLine, cpLine+1, strlen(cpLine+1)+1); /* escaped dot */ - cpPtr += strlen(cpPtr); - *cpPtr++ = '\n'; - *cpPtr = '\0'; - cpLine = cpPtr; - } - else { - /* rc == LMTP_ERR_SYSTEM, etc. */ - break; + if (*cpLine == '.') /* escaped dot */ + memmove(cpLine, cpLine+1, strlen(cpLine+1)+1); + cpPtr += strlen(cpPtr); /* write cursor to the end */ + *cpPtr++ = '\n'; /* artifical NL */ + *cpPtr = '\0'; /* artifical end of string */ + cpLine = cpPtr; /* start of line */ } + else break; /* rc == LMTP_ERR* */ } return rc; } @@ -210,10 +242,17 @@ * pulls the verb out and attaches the verb to req->verb; * * LMTP_OK req->msg set, req->verb set means normal operation + * LMTP_OK req->msg set, req->verb "" means no verb seen * LMTP_EOF req->msg set, req->verb NULL means eof * LMTP_ERR_OVERFLOW req->msg set, req->verb NULL means buf overflow * LMTP_ERR_SYSTEM req->msg set, req->verb NULL means system error - * LMTP_ERR_VERB req->msg set, req->verb NULL means no verb seen + * + * RFC821 "Simple Mail Transfer Protocol" [excerpts] + * 4.1.1. COMMAND SEMANTICS + * The command codes themselves are alphabetic characters terminated by + * if parameters follow and otherwise. + * 4.1.2. COMMAND SYNTAX + * ::= the space character (ASCII code 32) */ lmtp_rc_t rc; @@ -230,18 +269,21 @@ return rc; for (i = 0; (i < LMTP_MAXVERBS) && (lmtp->dispatch[i] != NULL); i++) { - if ((verb = lmtp->dispatch[i]->verb) != NULL) { - if ((verblen = strlen(verb)) == 0) - continue; - if( (strlen(req->msg) >= verblen) //FIXME check for verb\s + if ((verb = lmtp->dispatch[i]->verb) != NULL) { /* skip NULL verb */ + if ((verblen = strlen(verb)) == 0) continue; /* skip "" verb */ + if( (strlen(req->msg) >= verblen) && (strncasecmp(req->msg, verb, verblen) == 0) + && ( (req->msg[verblen] == '\0') + || (req->msg[verblen] == ' ') + ) ) { req->verb = verb; return LMTP_OK; } } } - return LMTP_ERR_VERB; + req->verb = ""; + return LMTP_OK; } lmtp_rc_t lmtp_response(lmtp_t *lmtp, lmtp_res_t *res) @@ -292,13 +334,15 @@ return rc; } -char **lmtp_message(lmtp_t *lmtp, char *verb) +lmtp_msg_t *lmtp_message(lmtp_t *lmtp, char *verb) { + /* get the first message attached to a verb's dispatch structure. The + * messages are fifo linked lists. + */ int i; - char **cpp = NULL; - if ((i = verbindex(lmtp, verb)) >= 0) - cpp = lmtp->dispatch[i]->msg; + lmtp_msg_t *cpp = NULL; + if ((i = verbindex(lmtp, verb)) >= 0) cpp = lmtp->dispatch[i]->msg; return cpp; } @@ -309,21 +353,56 @@ char *lmtp_error(lmtp_t *lmtp, lmtp_rc_t rc) { - char *str = NULL; + /* get an error message matching the given lmtp_rc_t code usually + * returned by a previously called function + */ + char *str; + + str = "LMTP: errorcode has no description"; + if (rc == LMTP_OK ) str = "LMTP: no error"; + if (rc == LMTP_EOF ) str = "LMTP: eof"; + if (rc == LMTP_ERR_SYSTEM ) str = "LMTP: see errno"; + if (rc == LMTP_ERR_MEM ) str = "LMTP: dynamic memory allocation failed"; + if (rc == LMTP_ERR_OVERFLOW) str = "LMTP: static allocated memory exhausted"; + if (rc == LMTP_ERR_ARG ) str = "LMTP: invalid arg was passed to function"; + if (rc == LMTP_ERR_UNKNOWN ) str = "LMTP: guru meditation"; + return str; } lmtp_rc_t lmtp_register(lmtp_t *lmtp, char *verb, lmtp_cb_t cb, void *ctx, lmtp_cb_t *oldcb, void **oldctx) { + /* For _lmtp_ structure, register a _verb_ and associate a callback + * function _cb_ to it. A context can be specified which will be passed + * to the callback function for every call. Consider the context being + * user data. The library itself does not care about the context except + * passing it along. If the verb was registered previously, the + * registration is replaced and if _oldcb_ and/or _oldctx_ is given, the + * previous registration is returned. Calling the previously registered + * callbacks from within the newly registered callback effectively allows + * hooking or chaining to a previous registered callback. The _ctx_, + * _oldcb_ and _oldctx_ are optional and might be passed as NULL in case + * you don't care. Setting _cb_ to NULL means to check only for a + * previous registration; + */ lmtp_rc_t rc = LMTP_OK; - int overload=0; /* overload returns old, no overload increases table */ + int overload=0; /* overload (replacement) detected has to return old oldcb + and/or oldctx, no overload requires growth of dispatch + table */ int i; + if (cb == NULL) { /* checking for existing callback only */ + i = verbindex(lmtp, verb); + if (oldcb != NULL) *oldcb = (i == -1) ? NULL : lmtp->dispatch[i]->cb; + if (oldctx != NULL) *oldctx = (i == -1) ? NULL : lmtp->dispatch[i]->ctx; + return LMTP_OK; + } + for (i = 0; lmtp->dispatch[i] != NULL; i++) { if (strcasecmp(verb, lmtp->dispatch[i]->verb) == 0) { overload=1; - if(oldcb != NULL) *oldcb = lmtp->dispatch[i]->cb; - if(oldctx != NULL) *oldctx = lmtp->dispatch[i]->ctx; + if (oldcb != NULL) *oldcb = lmtp->dispatch[i]->cb; + if (oldctx != NULL) *oldctx = lmtp->dispatch[i]->ctx; break; } } @@ -334,10 +413,9 @@ (lmtp_dispatch_t *)malloc(sizeof(lmtp_dispatch_t))) == NULL) return LMTP_ERR_MEM; lmtp->dispatch[i+1] = NULL; - if(oldcb != NULL) *oldcb = NULL; - if(oldctx != NULL) *oldctx = NULL; + if (oldcb != NULL) *oldcb = NULL; + if (oldctx != NULL) *oldctx = NULL; } - lmtp->dispatch[i]->verb = strdup(verb); lmtp->dispatch[i]->cb = cb; lmtp->dispatch[i]->ctx = ctx; @@ -348,9 +426,16 @@ lmtp_rc_t lmtp_loop(lmtp_t *lmtp) { + /* Print a welcome message then execute a request/ dispatch loop until + * request signals no more data. Each request is checked to contain a + * registered verb and if a verb is found the correspondig callback is + * executed. The create() function usually cares to register a default + * callback in order to handle unregistered verbs. The psoudoverb for + * default is the empty string "". + */ + lmtp_rc_t rc = LMTP_OK; lmtp_req_t req; lmtp_res_t res; - lmtp_rc_t rc = LMTP_OK; char *verb; int i; @@ -359,15 +444,12 @@ res.statusmsg = "LMTP server ready (lmtp2nntp)"; if ((rc = lmtp_response(lmtp, &res)) != LMTP_OK) return rc; - while ((rc = lmtp_request(lmtp, &req)) == LMTP_OK || (rc == LMTP_ERR_VERB)) { + while ((rc = lmtp_request(lmtp, &req)) == LMTP_OK) { verb = req.verb; - if (rc == LMTP_ERR_VERB) - verb = ""; - if ((i = verbindex(lmtp, verb)) == -1) - return LMTP_ERR_VERB; - rc = lmtp->dispatch[i]->cb(lmtp, &lmtp->io, &req, lmtp->dispatch[i]->ctx); - if (rc != LMTP_OK) - break; + if ((i = verbindex(lmtp, verb)) != -1) { + rc = lmtp->dispatch[i]->cb(lmtp, &lmtp->io, &req, lmtp->dispatch[i]->ctx); + if (rc != LMTP_OK) break; + } } return rc; } Index: ossp-pkg/lmtp2nntp/lmtp.h RCS File: /v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/lmtp.h,v rcsdiff -q -kk '-r1.3' '-r1.4' -u '/v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/lmtp.h,v' 2>/dev/null --- lmtp.h 2001/07/24 11:32:07 1.3 +++ lmtp.h 2001/07/25 11:29:38 1.4 @@ -27,13 +27,18 @@ char *statusmsg; /* message with >=0*NLs, not terminating with NL. NUL */ } lmtp_res_t; +struct lmtp_msg_st { + struct lmtp_msg_st *next; + char *msg; +}; +typedef struct lmtp_msg_st lmtp_msg_t; + typedef enum { LMTP_OK, LMTP_EOF, /* eof */ LMTP_ERR_SYSTEM, /* see errno */ LMTP_ERR_MEM, /* dynamic memory allocation failed */ LMTP_ERR_OVERFLOW, /* static allocated memory exhausted */ - LMTP_ERR_VERB, /* search for verb failed */ LMTP_ERR_ARG, /* invalid arg was passed to function */ LMTP_ERR_UNKNOWN /* guru meditation */ } lmtp_rc_t; @@ -46,7 +51,7 @@ lmtp_rc_t lmtp_readmsg (lmtp_t *lmtp, char **buf, size_t maxlen); lmtp_rc_t lmtp_request (lmtp_t *lmtp, lmtp_req_t *req); lmtp_rc_t lmtp_response(lmtp_t *lmtp, lmtp_res_t *res); -char **lmtp_message (lmtp_t *lmtp, char *verb); +lmtp_msg_t *lmtp_message (lmtp_t *lmtp, char *verb); void lmtp_reset (lmtp_t *lmtp); char *lmtp_error (lmtp_t *lmtp, lmtp_rc_t rc); lmtp_rc_t lmtp_register(lmtp_t *lmtp, char *verb, lmtp_cb_t cb, void *ctx, lmtp_cb_t *oldcb, void **oldctx); Index: ossp-pkg/lmtp2nntp/lmtp2nntp.c RCS File: /v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/lmtp2nntp.c,v rcsdiff -q -kk '-r1.3' '-r1.4' -u '/v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/lmtp2nntp.c,v' 2>/dev/null --- lmtp2nntp.c 2001/07/24 11:32:07 1.3 +++ lmtp2nntp.c 2001/07/25 11:29:38 1.4 @@ -37,6 +37,8 @@ static lmtp_rc_t lmtp_cb_mail (lmtp_t *lmtp, lmtp_io_t *io, lmtp_req_t *req, void *ctx); static lmtp_rc_t lmtp_cb_rcpt (lmtp_t *lmtp, lmtp_io_t *io, lmtp_req_t *req, void *ctx); static lmtp_rc_t lmtp_cb_data (lmtp_t *lmtp, lmtp_io_t *io, lmtp_req_t *req, void *ctx); +static lmtp_rc_t lmtp_cb_noop (lmtp_t *lmtp, lmtp_io_t *io, lmtp_req_t *req, void *ctx); +static lmtp_rc_t lmtp_cb_rset (lmtp_t *lmtp, lmtp_io_t *io, lmtp_req_t *req, void *ctx); static lmtp_rc_t lmtp_cb_quit (lmtp_t *lmtp, lmtp_io_t *io, lmtp_req_t *req, void *ctx); static void usage(char *command); @@ -44,9 +46,30 @@ int main(int argc, char **argv) { - int i; // general purpose scratch int, index ... + int i; /* general purpose scratch int, index ... */ - // read in the arguments + { + char buf[1000]; + int bufused = 0; + int tracefile; + +// printf("DEBUG: start of argdump\n", buf); + for (i=0; i