OSSP CVS Repository

ossp - Difference in ossp-pkg/lmtp2nntp/lmtp.c versions 1.1 and 1.2
Not logged in
[Honeypot]  [Browse]  [Home]  [Login]  [Reports
[Search]  [Ticket]  [Timeline
  [History

ossp-pkg/lmtp2nntp/lmtp.c 1.1 -> 1.2

--- 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 <stdio.h>
 #include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
 
 #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;
 }
 

CVSTrac 2.0.1