Index: ossp-pkg/lmtp2nntp/00TODO RCS File: /v/ossp/cvs/ossp-pkg/lmtp2nntp/00TODO,v rcsdiff -q -kk '-r1.2' '-r1.3' -u '/v/ossp/cvs/ossp-pkg/lmtp2nntp/00TODO,v' 2>/dev/null --- 00TODO 2001/07/17 12:40:06 1.2 +++ 00TODO 2001/07/23 12:14:06 1.3 @@ -42,3 +42,7 @@ x wait() NOOP > x x wait() QUIT > exit +readline() from pth test* +rfc822 header parsing from petidomo +string functions from http://www.engelschall.com/sw/str + Index: ossp-pkg/lmtp2nntp/lmtp.c RCS File: /v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/lmtp.c,v rcsdiff -q -kk '-r1.1' '-r1.2' -u '/v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/lmtp.c,v' 2>/dev/null --- lmtp.c 2001/07/17 12:40:07 1.1 +++ lmtp.c 2001/07/23 12:14:06 1.2 @@ -1,54 +1,138 @@ +#include #include +#include +#include +#include #include "lmtp.h" #include "lmtp_p.h" -static int readline(lmtp_readline_t *rl, int fd, char *buf, size_t buflen) +lmtp_rc_t lmtp_cb_default(lmtp_io_t *io, lmtp_req_t *req, lmtp_res_t *res, void *ctx); +lmtp_rc_t lmtp_cb_lhlo(lmtp_io_t *io, lmtp_req_t *req, lmtp_res_t *res, void *ctx); +lmtp_rc_t lmtp_cb_quit(lmtp_io_t *io, lmtp_req_t *req, lmtp_res_t *res, void *ctx); + +int verbindex(lmtp_t *lmtp, char *verb); + +/* + * test a function + * + */ + +void lmtp_debug_dumplmtp(lmtp_t *lmtp); +void test(void) +{ + lmtp_t *lmtp; + lmtp_rc_t rc; + lmtp_req_t req; + lmtp_res_t res; +#define BUFLEN 100 + char buf[BUFLEN]; + + + printf("DEBUG: 01 lmtp_create\n"); lmtp = lmtp_create(STDIN_FILENO, STDOUT_FILENO, NULL); + // printf("DEBUG: 02\n"); lmtp_debug_dumplmtp(lmtp); + printf("DEBUG: 03 lmtp_register\n"); lmtp_register(lmtp, "LHLO", lmtp_cb_lhlo, NULL, NULL, NULL); + printf("DEBUG: 03 lmtp_register\n"); lmtp_register(lmtp, "QUIT", lmtp_cb_quit, NULL, NULL, NULL); + // printf("DEBUG: 04\n"); lmtp_debug_dumplmtp(lmtp); + + /* + printf("DEBUG: 05 lmtp_response\n"); res.statuscode="123"; + res.dsncode="1.2.3"; + res.statusmsg="Hello,\nthis is a\nmultiline\nmessage"; + lmtp_response(lmtp, &res); + */ + + /* + do { + rc = lmtp_readline(lmtp, buf, BUFLEN); + printf("DEBUG: 06 lmtp_readline=%d ***%s***\n", rc, buf); + } while(rc == LMTP_OK); + */ + + /* + do { + rc = lmtp_request(lmtp, &req); + printf("DEBUG: 07 lmtp_request=%d ***%s***%s***\n", rc, req.verb, req.msg); + } while(rc == LMTP_OK || rc == LMTP_ERR_VERB); + */ + + printf("DEBUG: 08 lmtp_loop=%d\n", lmtp_loop(lmtp)); + + printf("DEBUG: 99.\n"); + return; +} + +void lmtp_debug_dumplmtp(lmtp_t *lmtp) +{ + int i; + + printf("lmtp = %ld \n", (long)lmtp); + printf("io.select = %ld \n", (long)lmtp->io.select); + printf("io.read = %ld \n", (long)lmtp->io.read); + printf("io.write = %ld \n", (long)lmtp->io.write); + printf("rl.cnt = %d \n", lmtp->rl.rl_cnt); + printf("rl.bufptr =*%39s*\n", lmtp->rl.rl_bufptr); + printf("rl.buf =*%39s*\n", lmtp->rl.rl_buf); + for (i = 0; (i < LMTP_MAXVERBS) && (lmtp->dispatch[i] != NULL); i++) { + printf("dispatch[i].verb =*%39s*\n", lmtp->dispatch[i]->verb); + printf("dispatch[i].cb = %ld \n", (long)lmtp->dispatch[i]->cb); + printf("dispatch[i].ctx = %ld \n", (long)lmtp->dispatch[i]->ctx); + // printf("dispatch[i].msg =*%39s*\n", lmtp->dispatch[i]->msg); + } + printf("rfd = %d \n", lmtp->rfd); + printf("wfd = %d \n", lmtp->wfd); + + return; +} +/*************************************************************************/ + +/* + * return > 0 number of chars read + * return = 0 end of file, no chars inside + * return = -1 buffer overrun, chars inside but no newline seen + * return = -2 io error (errno), buffer content undefined + */ +static int readline(lmtp_t *lmtp, char *buf, size_t buflen) { size_t n; - ssize_t rc; - char c = '\0', *cp; + char c; + lmtp_readline_t *rl = &lmtp->rl; - cp = (char *)buf; - for (n = 1; n < buflen; n++) { + for (n = 0; n < buflen-1;) { /* fetch one character (but read more) */ - rc = 1; if (rl->rl_cnt <= 0) { - if ((rl->rl_cnt = rl->rl_read(fd, rl->rl_buf, LMTP_READLINE_MAXLEN)) < 0) - rc = -1; - else if (rl->rl_cnt == 0) - rc = 0; - else - rl->rl_bufptr = rl->rl_buf; - } - if (rc == 1) { - rl->rl_cnt--; - c = *rl->rl_bufptr++; + if ((rl->rl_cnt = lmtp->io.read(lmtp->rfd, rl->rl_buf, LMTP_LINE_MAXLEN)) < 0) + return -2; /* error see errno */ + if (rl->rl_cnt == 0) + return 0; /* EOF */ + rl->rl_bufptr = rl->rl_buf; } /* act on fetched character */ - if (rc == 1) { - if (c == '\r') { - n--; - continue; - } - *cp++ = c; - if (c == '\n') - break; - } - else if (rc == 0) { - if (n == 1) - return 0; - else - break; - } - else - return -1; + rl->rl_cnt--; + c = *rl->rl_bufptr++; + if (c == '\r') + continue; /* skip copying CR */ + if (c == '\n') + break; /* end of line */ + buf[n++] = c; /* output char into given buffer */ + } - *cp = '\0'; - return n; + buf[n] = '\0'; /* string termination */ + return (n == (buflen-1)) ? -1 : n; +} + +int verbindex(lmtp_t *lmtp, char *verb) +{ + /* returns the index of the verb or -1 if verb not registered */ + + int i; + for (i = 0; (i < LMTP_MAXVERBS) && (lmtp->dispatch[i] != NULL); i++) { + if (strcasecmp(lmtp->dispatch[i]->verb, verb) == 0) return i; + } + return -1; } lmtp_t *lmtp_create(int rfd, int wfd, lmtp_io_t *io) @@ -57,36 +141,162 @@ if ((lmtp = (lmtp_t *)malloc(sizeof(lmtp_t))) == NULL) return NULL; - lmtp->io.select = select; - lmtp->io.read = read; - lmtp->io.write = write; + + if(io == NULL) { + lmtp->io.select = select; + lmtp->io.read = read; + lmtp->io.write = write; + } else { + lmtp->io.select = io->select; + lmtp->io.read = io->read; + lmtp->io.write = io->write; + } lmtp->rl.rl_cnt = 0; lmtp->rl.rl_bufptr = NULL; - lmtp->rl.rl_read = lmtp->io.read; - /* lmtp->dispatch = ... */ + lmtp->rl.rl_buf[0] = '\0'; + lmtp->rfd = rfd; + lmtp->wfd = wfd; + + if ((lmtp->dispatch = (lmtp_dispatch_t **)malloc(sizeof(void *)*LMTP_MAXVERBS)) == NULL) + return NULL; + + lmtp->dispatch[0] = NULL; + return lmtp; } void lmtp_destroy(lmtp_t *lmtp) { + free(lmtp); return; } -lmtp_rc_t lmtp_request(lmtp_t *lmtp, lmtp_req_t *req) +lmtp_rc_t lmtp_readline(lmtp_t *lmtp, char *buf, size_t buflen) +{ + lmtp_rc_t rc; + + rc = readline(lmtp, buf, buflen); + if(rc == -2) return LMTP_ERR_SYSTEM; /* io error (errno), buffer content undefined */ + if(rc == -1) return LMTP_ERR_OVERFLOW; /* buffer overrun, chars inside but no newline seen */ + if(rc == 0) return LMTP_EOF; /* end of file, no chars inside */ + return LMTP_OK; +} + +lmtp_rc_t lmtp_readmsg(lmtp_t *lmtp, char *buf, size_t buflen) { + /* 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. [...] + */ + lmtp_rc_t rc = LMTP_OK; + do { + rc = lmtp_readline(lmtp, buf, buflen); + printf("DEBUG: 06 lmtp_readline=%d ***%s***\n", rc, buf); + if (strcmp(buf, ".") == 0) break; + } while(rc == LMTP_OK); +/*FIXME escaping and more missing*/ return rc; } -lmtp_rc_t lmtp_result(lmtp_t *lmtp, lmtp_res_t *res) +lmtp_rc_t lmtp_request(lmtp_t *lmtp, lmtp_req_t *req) +{ + /* reads a line and attaches the buffer to req->msg; + * pulls the verb out and attaches the verb to req->verb; + * + * LMTP_OK req->msg set, req->verb set means normal operation + * 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 + */ + + lmtp_rc_t rc; + char *verb; + int verblen; + int i; + + req->verb = NULL; + + if ((req->msg = (char *)malloc(LMTP_LINE_MAXLEN)) == (char *)NULL) + return LMTP_ERR_MEM; + + if ((rc = lmtp_readline(lmtp, req->msg, LMTP_LINE_MAXLEN)) != LMTP_OK) + return rc; + + for (i = 0; (i < LMTP_MAXVERBS) && (lmtp->dispatch[i] != NULL); i++) { + if ((verb = lmtp->dispatch[i]->verb) != NULL) { + verblen = strlen(verb); + if( (strlen(req->msg) >= verblen) + && (strncasecmp(req->msg, verb, verblen) == 0) + ) { + req->verb = verb; + return LMTP_OK; + } + } + } + return LMTP_ERR_VERB; +} + +lmtp_rc_t lmtp_response(lmtp_t *lmtp, lmtp_res_t *res) { + /* write the status message. For multiline status messages it is + * neccessary to repeat the status and dsn codes for every line with a + * dash after the status for every line but the last one + */ lmtp_rc_t rc = LMTP_OK; + int dash; + int len; + char *cpS; + char *cpE; + char formatbuf[LMTP_LINE_MAXLEN]; + + if ( strlen(res->statuscode) != 3 + || !isdigit(res->statuscode[0]) + || !isdigit(res->statuscode[1]) + || !isdigit(res->statuscode[2]) + ) return LMTP_ERR_ARG; + + if (res->dsncode != NULL) + if ( (strlen(res->dsncode) != 5) + || !isdigit(res->dsncode[0]) + || (res->dsncode[1] != '.') + || !isdigit(res->dsncode[2]) + || (res->dsncode[3] != '.') + || !isdigit(res->dsncode[4]) + || (res->dsncode[0] != res->statuscode[0]) + ) return LMTP_ERR_ARG; + + cpS = res->statusmsg; + for (dash = 1; dash == 1; ) { + if ((cpE = strchr(cpS, '\n')) == NULL) { + cpE = cpS+strlen(cpS); + dash = 0; + } + if (res->dsncode != NULL) + len = sprintf(formatbuf, "%3.3s%c%5.5s ", res->statuscode, dash ? '-' : ' ', res->dsncode); + else + len = sprintf(formatbuf, "%3.3s%c", res->statuscode, dash ? '-' : ' '); + strncpy(formatbuf+len, cpS, cpE-cpS); + len += (cpE-cpS); + formatbuf[len++] = '\n'; + lmtp->io.write(lmtp->wfd, formatbuf, len); + cpS = cpE+1; + } return rc; } char **lmtp_message(lmtp_t *lmtp, char *verb) { + int i; + char **cpp = NULL; + if ((i = verbindex(lmtp, verb)) >= 0) + cpp = lmtp->dispatch[i]->msg; return cpp; } @@ -101,10 +311,37 @@ return str; } -lmtp_cb_t lmtp_register(lmtp_t *lmtp, char *verb, lmtp_type_t type, lmtp_cb_t *cb, void *ctx) +lmtp_rc_t lmtp_register(lmtp_t *lmtp, char *verb, lmtp_cb_t cb, void *ctx, lmtp_cb_t *oldcb, void **oldctx) { - lmtp_cb_t old = NULL; - return old; + lmtp_rc_t rc = LMTP_OK; + int overload=0; /* overload returns old, no overload increases table */ + int i; + + for (i = 0; lmtp->dispatch[i] != NULL; i++) { + if (strcmp(verb, lmtp->dispatch[i]->verb) == 0) { + overload=1; + if(oldcb != NULL) *oldcb = lmtp->dispatch[i]->cb; + if(oldctx != NULL) *oldctx = lmtp->dispatch[i]->ctx; + break; + } + } + if (i > LMTP_MAXVERBS-2) return LMTP_ERR_OVERFLOW; + + if (!overload) { + if ((lmtp->dispatch[i] = + (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; + } + + lmtp->dispatch[i]->verb = strdup(verb); + lmtp->dispatch[i]->cb = cb; + lmtp->dispatch[i]->ctx = ctx; + lmtp->dispatch[i]->msg = NULL; + + return rc; } lmtp_rc_t lmtp_loop(lmtp_t *lmtp) @@ -113,16 +350,44 @@ lmtp_res_t res; lmtp_rc_t rc; int i; - - while ((rc = lmtp_request(lmtp, &req)) == LMTP_OK) { - for (i = 0; lmtp->dispatch[i]->verb != NULL; i++) { - if (strcmp(req.verb, lmtp->dispatch[i]->verb) == 0) { - lmtp->dispatch[i]->cb(&lmtp->io, &req, &res, lmtp->dispatch[i]->cbctx); - if ((rc = lmtp_result(lmtp, &res)) != LMTP_OK) - return rc; - } + while ((rc = lmtp_request(lmtp, &req)) == LMTP_OK || (rc == LMTP_ERR_VERB)) { + if (rc != LMTP_ERR_VERB) { + if ((i = verbindex(lmtp, req.verb)) == -1) + return LMTP_ERR_VERB; + rc = lmtp->dispatch[i]->cb(&lmtp->io, &req, &res, lmtp->dispatch[i]->ctx); + } else { + rc = lmtp_cb_default(&lmtp->io, &req, &res, NULL); } + if (lmtp_response(lmtp, &res) != LMTP_OK) break; + if (rc != LMTP_OK) break; } + return LMTP_OK; +} + +lmtp_rc_t lmtp_cb_default(lmtp_io_t *io, lmtp_req_t *req, lmtp_res_t *res, void *ctx) +{ + lmtp_rc_t rc = LMTP_OK; + res->statuscode = "500"; + res->dsncode = "5.5.1"; + res->statusmsg = "Command unrecognized."; + return rc; +} + +lmtp_rc_t lmtp_cb_lhlo(lmtp_io_t *io, lmtp_req_t *req, lmtp_res_t *res, void *ctx) +{ + lmtp_rc_t rc = LMTP_OK; + res->statuscode = "250"; + res->dsncode = NULL; /* DSN not used for greeting */ + res->statusmsg = "ENHANCEDSTATUSCODES\nDSN"; /* RFC2034, RFC1894 */ + return rc; +} + +lmtp_rc_t lmtp_cb_quit(lmtp_io_t *io, lmtp_req_t *req, lmtp_res_t *res, void *ctx) +{ + lmtp_rc_t rc = LMTP_EOF; + res->statuscode = "221"; + res->dsncode = "2.0.0"; + res->statusmsg = "Closing connection."; return rc; } Index: ossp-pkg/lmtp2nntp/lmtp.h RCS File: /v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/lmtp.h,v rcsdiff -q -kk '-r1.1' '-r1.2' -u '/v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/lmtp.h,v' 2>/dev/null --- lmtp.h 2001/07/17 12:40:07 1.1 +++ lmtp.h 2001/07/23 12:14:06 1.2 @@ -1,3 +1,4 @@ + #ifndef __LMTP_H__ #define __LMTP_H__ @@ -16,37 +17,39 @@ } lmtp_io_t; typedef struct { - char *verb; - char *msg; + char *verb; /* verb found */ + char *msg; /* wholly message including verb */ } lmtp_req_t; typedef struct { - int rc; - char *dsn; - char *msg; + char *statuscode; /* digit digit digit NUL */ + char *dsncode; /* digit dot digit dot digit NUL */ + char *statusmsg; /* message with >=0*NLs, not terminating with NL. NUL */ } lmtp_res_t; typedef enum { LMTP_OK, - LMTP_ERR_SYSTEM, /* see errno */ - LMTP_ERR_INVALID_VERB + 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; -typedef enum { - LMTP_TYPE_SINGLELINE, - LMTP_TYPE_MULTILINE -} lmtp_type_t; - typedef lmtp_rc_t (*lmtp_cb_t)(lmtp_io_t *io, lmtp_req_t *req, lmtp_res_t *res, void *ctx); lmtp_t *lmtp_create (int rfd, int wfd, lmtp_io_t *io); void lmtp_destroy (lmtp_t *lmtp); +lmtp_rc_t lmtp_readline(lmtp_t *lmtp, char *buf, size_t buflen); +lmtp_rc_t lmtp_readmsg (lmtp_t *lmtp, char *buf, size_t buflen); lmtp_rc_t lmtp_request (lmtp_t *lmtp, lmtp_req_t *req); -lmtp_rc_t lmtp_result (lmtp_t *lmtp, lmtp_res_t *res); +lmtp_rc_t lmtp_response(lmtp_t *lmtp, lmtp_res_t *res); char **lmtp_message (lmtp_t *lmtp, char *verb); void lmtp_reset (lmtp_t *lmtp); char *lmtp_error (lmtp_t *lmtp, lmtp_rc_t rc); -lmtp_cb_t lmtp_register(lmtp_t *lmtp, char *verb, lmtp_type_t type, lmtp_cb_t *cb, void *ctx); +lmtp_rc_t lmtp_register(lmtp_t *lmtp, char *verb, lmtp_cb_t cb, void *ctx, lmtp_cb_t *oldcb, void **oldctx); lmtp_rc_t lmtp_loop (lmtp_t *lmtp); #endif /* __LMTP_H__ */ Index: ossp-pkg/lmtp2nntp/lmtp2nntp.c RCS File: /v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/lmtp2nntp.c,v rcsdiff -q -kk '-r1.1' '-r1.2' -u '/v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/lmtp2nntp.c,v' 2>/dev/null --- lmtp2nntp.c 2001/07/17 12:40:07 1.1 +++ lmtp2nntp.c 2001/07/23 12:14:06 1.2 @@ -19,6 +19,7 @@ #define ERR_DELIVERY -2 void usage(char *command); +void test(void); int main(int argc, char **argv) { @@ -48,6 +49,8 @@ argc -= optind; argv += optind; // remaining args is/are newsgroup/s printf("Hello, World!\n"); + test(); + printf("Hello, Again!\n"); return 0; } @@ -64,3 +67,4 @@ return; } +