OSSP CVS Repository

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

ossp-pkg/lmtp2nntp/lmtp.c 1.3 -> 1.4

--- 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
+     *  <SP> if parameters follow and <CRLF> otherwise.
+     *  4.1.2. COMMAND SYNTAX
+     *  <SP> ::= 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;
 }

CVSTrac 2.0.1