OSSP CVS Repository

ossp - ossp-pkg/lmtp2nntp/lmtp.c 1.2
Not logged in
[Honeypot]  [Browse]  [Directory]  [Home]  [Login
[Reports]  [Search]  [Ticket]  [Timeline
  [Raw

ossp-pkg/lmtp2nntp/lmtp.c 1.2

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>

#include "lmtp.h"
#include "lmtp_p.h"

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;
    char c;
    lmtp_readline_t *rl = &lmtp->rl;

    for (n = 0; n < buflen-1;) {

        /* fetch one character (but read more) */
        if (rl->rl_cnt <= 0) {
            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 */
        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 */

    }
    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)
{
    lmtp_t *lmtp = NULL;

    if ((lmtp = (lmtp_t *)malloc(sizeof(lmtp_t))) == NULL) 
        return NULL;

    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_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_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_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;
}

void lmtp_reset(lmtp_t *lmtp)
{
    return;
}

char *lmtp_error(lmtp_t *lmtp, lmtp_rc_t rc)
{
    char *str = NULL;
    return str;
}

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 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)
{
    lmtp_req_t req;
    lmtp_res_t res;
    lmtp_rc_t rc;
    int i;
    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