OSSP CVS Repository

ossp - Check-in [568]
Not logged in
[Honeypot]  [Browse]  [Home]  [Login]  [Reports
[Search]  [Ticket]  [Timeline
  [Patchset]  [Tagging/Branching

Check-in Number: 568
Date: 2001-Jul-25 17:02:57 (local)
2001-Jul-25 15:02:57 (UTC)
User:thl
Branch:
Comment: added argz library and first inter-callback functionality
Tickets:
Inspections:
Files:
ossp-pkg/lmtp2nntp/argz.c      added-> 1.1
ossp-pkg/lmtp2nntp/argz.h      added-> 1.1
ossp-pkg/lmtp2nntp/argz.html      added-> 1.1
ossp-pkg/lmtp2nntp/lmtp.c      1.4 -> 1.5     16 inserted, 44 deleted
ossp-pkg/lmtp2nntp/lmtp.h      1.4 -> 1.5     0 inserted, 9 deleted
ossp-pkg/lmtp2nntp/lmtp2nntp.c      1.4 -> 1.5     196 inserted, 160 deleted

ossp-pkg/lmtp2nntp/argz.c -> 1.1

*** /dev/null    Sat Nov 23 01:26:20 2024
--- -    Sat Nov 23 01:26:25 2024
***************
*** 0 ****
--- 1,396 ----
+ /* Routines for dealing with '\0' separated arg vectors.
+    Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+    This file is part of the GNU C Library.
+    Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1996.
+ 
+    The GNU C Library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public License as
+    published by the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version.
+ 
+    The GNU C Library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+ 
+    You should have received a copy of the GNU Library General Public
+    License along with the GNU C Library; see the file COPYING.LIB.  If not,
+    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+    Boston, MA 02111-1307, USA.  */
+ 
+ #include <errno.h>
+ #include <stdlib.h>
+ #include <string.h>
+ 
+ #include "argz.h"
+ 
+ /* Find the length of STRING, but scan at most MAXLEN characters.
+    If no '\0' terminator is found in that many characters, return MAXLEN.  */
+ static size_t my_strnlen(const char *string, size_t maxlen)
+ {
+     const char *end = memchr(string, '\0', maxlen);
+     return end ? (size_t) (end - string) : maxlen;
+ }
+ 
+ static char *my_strndup(const char *s, size_t n)
+ {
+     size_t len = my_strnlen(s, n);
+     char *new = malloc(len + 1);
+ 
+     if (new == NULL)
+         return NULL;
+     new[len] = '\0';
+     return (char *)memcpy(new, s, len);
+ }
+ 
+ /* Copy SRC to DEST, returning the address of the terminating '\0' in DEST. */
+ static char *my_stpcpy(char *dest, const char *src)
+ {
+     register char *d = dest;
+     register const char *s = src;
+ 
+     do {
+       *d++ = *s;
+     } while (*s++ != '\0');
+     return d - 1;
+ }
+ 
+ int argz_add_sep(char **argz, size_t * argz_len, const char *string, int delim)
+ {
+        size_t nlen = strlen(string) + 1;
+ 
+        if (nlen > 1) {
+                const char *rp;
+                char *wp;
+ 
+                *argz = (char *)realloc(*argz, *argz_len + nlen);
+                if (*argz == NULL)
+                        return ENOMEM;
+ 
+                wp = *argz + *argz_len;
+                rp = string;
+                do {
+                        if (*rp == delim) {
+                                if (wp > *argz && wp[-1] != '\0')
+                                        *wp++ = '\0';
+                                else
+                                        --nlen;
+                        }
+                        else
+                                *wp++ = *rp;
+                } while (*rp++ != '\0');
+ 
+                *argz_len += nlen;
+        }
+ 
+        return 0;
+ }
+ 
+ /* Add BUF, of length BUF_LEN to the argz vector in ARGZ & ARGZ_LEN.  */
+ int argz_append(char **argz, size_t * argz_len, const char *buf, size_t buf_len)
+ {
+        size_t new_argz_len = *argz_len + buf_len;
+        char *new_argz = realloc(*argz, new_argz_len);
+        if (new_argz) {
+                memcpy(new_argz + *argz_len, buf, buf_len);
+                *argz = new_argz;
+                *argz_len = new_argz_len;
+                return 0;
+        }
+        else
+                return ENOMEM;
+ }
+ 
+ /* Add STR to the argz vector in ARGZ & ARGZ_LEN.  This should be moved into
+  * argz.c in libshouldbelibc.  */
+ int argz_add(char **argz, size_t * argz_len, const char *str)
+ {
+        return argz_append(argz, argz_len, str, strlen(str) + 1);
+ }
+ 
+ /* Returns the number of strings in ARGZ.  */
+ size_t argz_count(const char *argz, size_t len)
+ {
+        size_t count = 0;
+        while (len > 0) {
+                size_t part_len = strlen(argz);
+                argz += part_len + 1;
+                len -= part_len + 1;
+                count++;
+        }
+        return count;
+ }
+ 
+ /* Make a '\0' separated arg vector from a unix argv vector, returning it in
+  * ARGZ, and the total length in LEN.  If a memory allocation error occurs,
+  * ENOMEM is returned, otherwise 0.  */
+ int argz_create(char *const argv[], char **argz, size_t * len)
+ {
+        int argc;
+        size_t tlen = 0;
+        char *const *ap;
+        char *p;
+ 
+        for (argc = 0; argv[argc] != NULL; ++argc)
+                tlen += strlen(argv[argc]) + 1;
+ 
+        if (tlen == 0)
+                *argz = NULL;
+        else {
+                *argz = malloc(tlen);
+                if (*argz == NULL)
+                        return ENOMEM;
+ 
+                for (p = *argz, ap = argv; *ap; ++ap, ++p)
+                        p = my_stpcpy(p, *ap);
+        }
+        *len = tlen;
+ 
+        return 0;
+ }
+ 
+ int argz_create_sep(const char *string, int delim, char **argz, size_t * len)
+ {
+        size_t nlen = strlen(string) + 1;
+ 
+        if (nlen > 1) {
+                const char *rp;
+                char *wp;
+ 
+                *argz = (char *)malloc(nlen);
+                if (*argz == NULL)
+                        return ENOMEM;
+ 
+                rp = string;
+                wp = *argz;
+                do
+                        if (*rp == delim) {
+                                if (wp > *argz && wp[-1] != '\0')
+                                        *wp++ = '\0';
+                                else
+                                        --nlen;
+                        }
+                        else
+                                *wp++ = *rp;
+                while (*rp++ != '\0');
+ 
+                if (nlen == 0) {
+                        free(*argz);
+                        *argz = NULL;
+                        *len = 0;
+                }
+ 
+                *len = nlen;
+        }
+        else {
+                *argz = NULL;
+                *len = 0;
+        }
+ 
+        return 0;
+ }
+ 
+ /* Delete ENTRY from ARGZ & ARGZ_LEN, if any.  */
+ void argz_delete(char **argz, size_t * argz_len, char *entry)
+ {
+        if (entry)
+                /* Get rid of the old value for NAME.  */
+        {
+                size_t entry_len = strlen(entry) + 1;
+                *argz_len -= entry_len;
+                memmove(entry, entry + entry_len, *argz_len - (entry - *argz));
+                if (*argz_len == 0) {
+                        free(*argz);
+                        *argz = 0;
+                }
+        }
+ }
+ 
+ /* Puts pointers to each string in ARGZ, plus a terminating 0 element, into
+  * ARGV, which must be large enough to hold them all.  */
+ void argz_extract(const char *argz, size_t len, char **argv)
+ {
+        while (len > 0) {
+                size_t part_len = strlen(argz);
+                *argv++ = (char *)argz;
+                argz += part_len + 1;
+                len -= part_len + 1;
+        }
+        *argv = 0;
+ }
+ 
+ /* Insert ENTRY into ARGZ & ARGZ_LEN before BEFORE, which should be an
+  * existing entry in ARGZ; if BEFORE is NULL, ENTRY is appended to the end.
+  * Since ARGZ's first entry is the same as ARGZ, argz_insert (ARGZ, ARGZ_LEN,
+  * ARGZ, ENTRY) will insert ENTRY at the beginning of ARGZ.  If BEFORE is not
+  * in ARGZ, EINVAL is returned, else if memory can't be allocated for the new
+  * ARGZ, ENOMEM is returned, else 0.  */
+ int argz_insert(char **argz, size_t * argz_len, char *before, const char *entry)
+ {
+        if (!before)
+                return argz_add(argz, argz_len, entry);
+ 
+        if (before < *argz || before >= *argz + *argz_len)
+                return EINVAL;
+ 
+        if (before > *argz)
+                /* Make sure before is actually the beginning of an entry.  */
+                while (before[-1])
+                        before--;
+ 
+        {
+                size_t after_before = *argz_len - (before - *argz);
+                size_t entry_len = strlen(entry) + 1;
+                size_t new_argz_len = *argz_len + entry_len;
+                char *new_argz = realloc(*argz, new_argz_len);
+ 
+                if (new_argz) {
+                        before = new_argz + (before - *argz);
+                        memmove(before + entry_len, before, after_before);
+                        memmove(before, entry, entry_len);
+                        *argz = new_argz;
+                        *argz_len = new_argz_len;
+                        return 0;
+                }
+                else
+                        return ENOMEM;
+        }
+ }
+ 
+ char *argz_next(const char *argz, size_t argz_len, const char *entry)
+ {
+        if (entry) {
+                if (entry < argz + argz_len)
+                        entry = strchr(entry, '\0') + 1;
+ 
+                return entry >= argz + argz_len ? NULL : (char *)entry;
+        }
+        else if (argz_len > 0)
+                return (char *)argz;
+        else
+                return NULL;
+ }
+ 
+ /* Append BUF, of length BUF_LEN to *TO, of length *TO_LEN, reallocating and
+  * updating *TO & *TO_LEN appropriately.  If an allocation error occurs,
+  * *TO's old value is freed, and *TO is set to 0.  */
+ static void
+ str_append(char **to, size_t * to_len, const char *buf, const size_t buf_len)
+ {
+        size_t new_len = *to_len + buf_len;
+        char *new_to = realloc(*to, new_len + 1);
+ 
+        if (new_to) {
+                /* *((char *)__mempcpy(new_to + *to_len, buf, buf_len)) = '\0'; */
+                memcpy(new_to + *to_len, buf, buf_len);
+         *(new_to + *to_len + buf_len) = '\0';
+                *to = new_to;
+                *to_len = new_len;
+        }
+        else {
+                free(*to);
+                *to = 0;
+        }
+ }
+ 
+ /* Replace any occurrences of the string STR in ARGZ with WITH, reallocating
+  * ARGZ as necessary.  If REPLACE_COUNT is non-zero, *REPLACE_COUNT will be
+  * incremented by number of replacements performed.  */
+ int argz_replace(char **argz, size_t * argz_len, const char *str,
+                           const char *with, unsigned *replace_count)
+ {
+        int err = 0;
+ 
+        if (str && *str) {
+                char *arg = 0;
+                char *src = *argz;
+                size_t src_len = *argz_len;
+                char *dst = 0;
+                size_t dst_len = 0;
+                int delayed_copy = 1;              /* True while we've avoided copying
+                                                                            * anything.  */
+                size_t str_len = strlen(str), with_len = strlen(with);
+ 
+                while (!err && (arg = argz_next(src, src_len, arg))) {
+                        char *match = strstr(arg, str);
+                        if (match) {
+                                char *from = match + str_len;
+                                size_t to_len = match - arg;
+                                char *to = my_strndup(arg, to_len);
+ 
+                                while (to && from) {
+                                        str_append(&to, &to_len, with, with_len);
+                                        if (to) {
+                                                match = strstr(from, str);
+                                                if (match) {
+                                                        str_append(&to, &to_len, from, match - from);
+                                                        from = match + str_len;
+                                                }
+                                                else {
+                                                        str_append(&to, &to_len, from, strlen(from));
+                                                        from = 0;
+                                                }
+                                        }
+                                }
+ 
+                                if (to) {
+                                        if (delayed_copy)
+                                                /* We avoided copying SRC to DST until we found a
+                                                 * match; now that we've done so, copy everything
+                                                 * from the start of SRC.  */
+                                        {
+                                                if (arg > src)
+                                                        err =
+                                                                argz_append(&dst, &dst_len, src,
+                                                                                          (arg - src));
+                                                delayed_copy = 0;
+                                        }
+                                        if (!err)
+                                                err = argz_add(&dst, &dst_len, to);
+                                        free(to);
+                                }
+                                else
+                                        err = ENOMEM;
+ 
+                                if (replace_count)
+                                        (*replace_count)++;
+                        }
+                        else if (!delayed_copy)
+                                err = argz_add(&dst, &dst_len, arg);
+                }
+ 
+                if (!err) {
+                        if (!delayed_copy)
+                                /* We never found any instances of str.  */
+                        {
+                                if (src)
+                                        free(src);
+                                *argz = dst;
+                                *argz_len = dst_len;
+                        }
+                }
+                else if (dst_len > 0)
+                        free(dst);
+        }
+ 
+        return err;
+ }
+ 
+ /* Make '\0' separated arg vector ARGZ printable by converting all the '\0's
+  * except the last into the character SEP.  */
+ void argz_stringify(char *argz, size_t len, int sep)
+ {
+        if (len > 0) {
+                while (1) {
+                        size_t part_len = my_strnlen(argz, len);
+                        argz += part_len;
+                        len -= part_len;
+                        if (len-- <= 1)                    /* includes final '\0' we want to stop 
+                                                                            * at */
+                                break;
+                        *argz++ = sep;
+                }
+     }
+     return;
+ }
+ 


ossp-pkg/lmtp2nntp/argz.h -> 1.1

*** /dev/null    Sat Nov 23 01:26:20 2024
--- -    Sat Nov 23 01:26:25 2024
***************
*** 0 ****
--- 1,40 ----
+ /* Routines for dealing with '\0' separated arg vectors.
+    Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+    This file is part of the GNU C Library.
+    Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1996.
+ 
+    The GNU C Library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public License as
+    published by the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version.
+ 
+    The GNU C Library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+ 
+    You should have received a copy of the GNU Library General Public
+    License along with the GNU C Library; see the file COPYING.LIB.  If not,
+    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+    Boston, MA 02111-1307, USA.  */
+ 
+ #ifndef _ARGZ_H_
+ #define _ARGZ_H_
+ 
+ #include <string.h>
+ 
+ extern int    argz_create    (char *const _argv[], char **_argz, size_t * _len);
+ extern int    argz_create_sep(const char *_string, int _sep, char **_argz, size_t * _len);
+ extern size_t argz_count     (const char *_argz, size_t _len);
+ extern void   argz_extract   (const char *_argz, size_t _len, char **_argv);
+ extern void   argz_stringify (char *_argz, size_t _len, int _sep);
+ extern int    argz_append    (char **_argz, size_t * _argz_len, const char *_buf, size_t _buf_len);
+ extern int    argz_add       (char **_argz, size_t * _argz_len, const char *_str);
+ extern int    argz_add_sep   (char **_argz, size_t * _argz_len, const char *_string, int _delim);
+ extern void   argz_delete    (char **_argz, size_t * _argz_len, char *_entry);
+ extern int    argz_insert    (char **_argz, size_t * _argz_len, char *_before, const char *_entry);
+ extern int    argz_replace   (char **_argz, size_t * _argz_len, const char *_str, const char *_with, unsigned int *_replace_count);
+ extern char  *argz_next      (const char *_argz, size_t _argz_len, const char *_entry);
+ 
+ #endif /* _ARGZ_H_ */
+ 


ossp-pkg/lmtp2nntp/argz.html -> 1.1

*** /dev/null    Sat Nov 23 01:26:20 2024
--- -    Sat Nov 23 01:26:25 2024
***************
*** 0 ****
--- 1,238 ----
+ <HTML>
+ <HEAD>
+ <!-- Created by texi2html 1.56k from argz.texi on 25 July 2001 -->
+ 
+ <TITLE>Untitled Document</TITLE>
+ </HEAD>
+ <BODY>
+ <H1>Untitled Document</H1>
+ <P>
+ <P><HR><P>
+ 
+ 
+ 
+ <H2><A NAME="SEC1" HREF="argz_toc.html#TOC1">Argz Vectors</A></H2>
+ 
+ <P>
+ <A NAME="IDX1"></A>
+ <A NAME="IDX2"></A>
+ <A NAME="IDX3"></A>
+ <EM>argz vectors</EM> are vectors of strings in a contiguous block of
+ memory, each element separated from its neighbors by null-characters
+ (<CODE>'\0'</CODE>).
+ 
+ 
+ 
+ 
+ <H3><A NAME="SEC2" HREF="argz_toc.html#TOC2">Argz Functions</A></H3>
+ 
+ <P>
+ Each argz vector is represented by a pointer to the first element, of
+ type <CODE>char *</CODE>, and a size, of type <CODE>size_t</CODE>, both of which can
+ be initialized to <CODE>0</CODE> to represent an empty argz vector.  All argz
+ functions accept either a pointer and a size argument, or pointers to
+ them, if they will be modified.
+ 
+ 
+ <P>
+ The argz functions use <CODE>malloc</CODE>/<CODE>realloc</CODE> to allocate/grow
+ argz vectors, and so any argz vector creating using these functions may
+ be freed by using <CODE>free</CODE>; conversely, any argz function that may
+ grow a string expects that string to have been allocated using
+ <CODE>malloc</CODE> (those argz functions that only examine their arguments or
+ modify them in place will work on any sort of memory).
+ 
+ 
+ <P>
+ All argz functions that do memory allocation have a return type of
+ <CODE>int</CODE>, and return <CODE>0</CODE> for success, and <CODE>ENOMEM</CODE> if an
+ allocation error occurs.
+ 
+ 
+ <P>
+ <A NAME="IDX4"></A>
+ These functions are declared in the standard include file <TT>`argz.h'</TT>.
+ 
+ 
+ <P>
+ <DL>
+ <DT><U>Function:</U> int <B>argz_create</B> <I>(char *const <VAR>argv</VAR>[], char **<VAR>argz</VAR>, size_t *<VAR>argz_len</VAR>)</I>
+ <DD><A NAME="IDX5"></A>
+ The <CODE>argz_create</CODE> function converts the Unix-style argument vector
+ <VAR>argv</VAR> (a vector of pointers to normal C strings, terminated by
+ <CODE>(char *)0</CODE>;) into an argz vector with
+ the same elements, which is returned in <VAR>argz</VAR> and <VAR>argz_len</VAR>.
+ </DL>
+ 
+ 
+ <P>
+ <DL>
+ <DT><U>Function:</U> int <B>argz_create_sep</B> <I>(const char *<VAR>string</VAR>, int <VAR>sep</VAR>, char **<VAR>argz</VAR>, size_t *<VAR>argz_len</VAR>)</I>
+ <DD><A NAME="IDX6"></A>
+ The <CODE>argz_create_sep</CODE> function converts the null-terminated string
+ <VAR>string</VAR> into an argz vector (returned in <VAR>argz</VAR> and
+ <VAR>argz_len</VAR>) by splitting it into elements at every occurrence of the
+ character <VAR>sep</VAR>.
+ </DL>
+ 
+ 
+ <P>
+ <DL>
+ <DT><U>Function:</U> size_t <B>argz_count</B> <I>(const char *<VAR>argz</VAR>, size_t <VAR>arg_len</VAR>)</I>
+ <DD><A NAME="IDX7"></A>
+ Returns the number of elements in the argz vector <VAR>argz</VAR> and
+ <VAR>argz_len</VAR>.
+ </DL>
+ 
+ 
+ <P>
+ <DL>
+ <DT><U>Function:</U> void <B>argz_extract</B> <I>(char *<VAR>argz</VAR>, size_t <VAR>argz_len</VAR>, char **<VAR>argv</VAR>)</I>
+ <DD><A NAME="IDX8"></A>
+ The <CODE>argz_extract</CODE> function converts the argz vector <VAR>argz</VAR> and
+ <VAR>argz_len</VAR> into a Unix-style argument vector stored in <VAR>argv</VAR>,
+ by putting pointers to every element in <VAR>argz</VAR> into successive
+ positions in <VAR>argv</VAR>, followed by a terminator of <CODE>0</CODE>.
+ <VAR>Argv</VAR> must be pre-allocated with enough space to hold all the
+ elements in <VAR>argz</VAR> plus the terminating <CODE>(char *)0</CODE>
+ (<CODE>(argz_count (<VAR>argz</VAR>, <VAR>argz_len</VAR>) + 1) * sizeof (char *)</CODE>
+ bytes should be enough).  Note that the string pointers stored into
+ <VAR>argv</VAR> point into <VAR>argz</VAR>---they are not copies--and so
+ <VAR>argz</VAR> must be copied if it will be changed while <VAR>argv</VAR> is
+ still active.  This function is useful for passing the elements in
+ <VAR>argz</VAR> to an exec function.
+ </DL>
+ 
+ 
+ <P>
+ <DL>
+ <DT><U>Function:</U> void <B>argz_stringify</B> <I>(char *<VAR>argz</VAR>, size_t <VAR>len</VAR>, int <VAR>sep</VAR>)</I>
+ <DD><A NAME="IDX9"></A>
+ The <CODE>argz_stringify</CODE> converts <VAR>argz</VAR> into a normal string with
+ the elements separated by the character <VAR>sep</VAR>, by replacing each
+ <CODE>'\0'</CODE> inside <VAR>argz</VAR> (except the last one, which terminates the
+ string) with <VAR>sep</VAR>.  This is handy for printing <VAR>argz</VAR> in a
+ readable manner.
+ </DL>
+ 
+ 
+ <P>
+ <DL>
+ <DT><U>Function:</U> int <B>argz_add</B> <I>(char **<VAR>argz</VAR>, size_t *<VAR>argz_len</VAR>, const char *<VAR>str</VAR>)</I>
+ <DD><A NAME="IDX10"></A>
+ The <CODE>argz_add</CODE> function adds the string <VAR>str</VAR> to the end of the
+ argz vector <CODE>*<VAR>argz</VAR></CODE>, and updates <CODE>*<VAR>argz</VAR></CODE> and
+ <CODE>*<VAR>argz_len</VAR></CODE> accordingly.
+ </DL>
+ 
+ 
+ <P>
+ <DL>
+ <DT><U>Function:</U> int <B>argz_add_sep</B> <I>(char **<VAR>argz</VAR>, size_t *<VAR>argz_len</VAR>, const char *<VAR>str</VAR>, int <VAR>delim</VAR>)</I>
+ <DD><A NAME="IDX11"></A>
+ The <CODE>argz_add_sep</CODE> function is similar to <CODE>argz_add</CODE>, but
+ <VAR>str</VAR> is split into separate elements in the result at occurrences of
+ the character <VAR>delim</VAR>.  This is useful, for instance, for
+ adding the components of a Unix search path to an argz vector, by using
+ a value of <CODE>':'</CODE> for <VAR>delim</VAR>.
+ </DL>
+ 
+ 
+ <P>
+ <DL>
+ <DT><U>Function:</U> int <B>argz_append</B> <I>(char **<VAR>argz</VAR>, size_t *<VAR>argz_len</VAR>, const char *<VAR>buf</VAR>, size_t <VAR>buf_len</VAR>)</I>
+ <DD><A NAME="IDX12"></A>
+ The <CODE>argz_append</CODE> function appends <VAR>buf_len</VAR> bytes starting at
+ <VAR>buf</VAR> to the argz vector <CODE>*<VAR>argz</VAR></CODE>, reallocating
+ <CODE>*<VAR>argz</VAR></CODE> to accommodate it, and adding <VAR>buf_len</VAR> to
+ <CODE>*<VAR>argz_len</VAR></CODE>.
+ </DL>
+ 
+ 
+ <P>
+ <DL>
+ <DT><U>Function:</U> int <B>argz_delete</B> <I>(char **<VAR>argz</VAR>, size_t *<VAR>argz_len</VAR>, char *<VAR>entry</VAR>)</I>
+ <DD><A NAME="IDX13"></A>
+ If <VAR>entry</VAR> points to the beginning of one of the elements in the
+ argz vector <CODE>*<VAR>argz</VAR></CODE>, the <CODE>argz_delete</CODE> function will
+ remove this entry and reallocate <CODE>*<VAR>argz</VAR></CODE>, modifying
+ <CODE>*<VAR>argz</VAR></CODE> and <CODE>*<VAR>argz_len</VAR></CODE> accordingly.  Note that as
+ destructive argz functions usually reallocate their argz argument,
+ pointers into argz vectors such as <VAR>entry</VAR> will then become invalid.
+ </DL>
+ 
+ 
+ <P>
+ <DL>
+ <DT><U>Function:</U> int <B>argz_insert</B> <I>(char **<VAR>argz</VAR>, size_t *<VAR>argz_len</VAR>, char *<VAR>before</VAR>, const char *<VAR>entry</VAR>)</I>
+ <DD><A NAME="IDX14"></A>
+ The <CODE>argz_insert</CODE> function inserts the string <VAR>entry</VAR> into the
+ argz vector <CODE>*<VAR>argz</VAR></CODE> at a point just before the existing
+ element pointed to by <VAR>before</VAR>, reallocating <CODE>*<VAR>argz</VAR></CODE> and
+ updating <CODE>*<VAR>argz</VAR></CODE> and <CODE>*<VAR>argz_len</VAR></CODE>.  If <VAR>before</VAR>
+ is <CODE>0</CODE>, <VAR>entry</VAR> is added to the end instead (as if by
+ <CODE>argz_add</CODE>).  Since the first element is in fact the same as
+ <CODE>*<VAR>argz</VAR></CODE>, passing in <CODE>*<VAR>argz</VAR></CODE> as the value of
+ <VAR>before</VAR> will result in <VAR>entry</VAR> being inserted at the beginning.
+ </DL>
+ 
+ 
+ <P>
+ <DL>
+ <DT><U>Function:</U> char * <B>argz_next</B> <I>(char *<VAR>argz</VAR>, size_t <VAR>argz_len</VAR>, const char *<VAR>entry</VAR>)</I>
+ <DD><A NAME="IDX15"></A>
+ The <CODE>argz_next</CODE> function provides a convenient way of iterating
+ over the elements in the argz vector <VAR>argz</VAR>.  It returns a pointer
+ to the next element in <VAR>argz</VAR> after the element <VAR>entry</VAR>, or
+ <CODE>0</CODE> if there are no elements following <VAR>entry</VAR>.  If <VAR>entry</VAR>
+ is <CODE>0</CODE>, the first element of <VAR>argz</VAR> is returned.
+ 
+ 
+ <P>
+ This behavior suggests two styles of iteration:
+ 
+ 
+ 
+ <PRE>
+     char *entry = 0;
+     while ((entry = argz_next (<VAR>argz</VAR>, <VAR>argz_len</VAR>, entry)))
+       <VAR>action</VAR>;
+ </PRE>
+ 
+ <P>
+ (the double parentheses are necessary to make some C compilers shut up
+ about what they consider a questionable <CODE>while</CODE>-test) and:
+ 
+ 
+ 
+ <PRE>
+     char *entry;
+     for (entry = <VAR>argz</VAR>;
+          entry;
+          entry = argz_next (<VAR>argz</VAR>, <VAR>argz_len</VAR>, entry))
+       <VAR>action</VAR>;
+ </PRE>
+ 
+ <P>
+ Note that the latter depends on <VAR>argz</VAR> having a value of <CODE>0</CODE> if
+ it is empty (rather than a pointer to an empty block of memory); this
+ invariant is maintained for argz vectors created by the functions here.
+ </DL>
+ 
+ 
+ <P>
+ <DL>
+ <DT><U>Function:</U> int <B>argz_replace</B> <I>(char **<VAR>argz</VAR>, size_t *<VAR>argz_len</VAR>, const char *<VAR>str</VAR>, const char *<VAR>with</VAR>, unsigned *<VAR>replace_count</VAR>)</I>
+ <DD><A NAME="IDX16"></A>
+ Replace any occurrences of the string <VAR>str</VAR> in <VAR>argz</VAR> with
+ <VAR>with</VAR>, reallocating <VAR>argz</VAR> as necessary.  If
+ <VAR>replace_count</VAR> is non-zero, <CODE>*<VAR>replace_count</VAR></CODE> will be
+ incremented by number of replacements performed.
+ </DL>
+ 
+ 
+ <P><HR><P>
+ This document was generated on 25 July 2001 using
+ <A HREF="http://wwwinfo.cern.ch/dis/texi2html/">texi2html</A>&nbsp;1.56k.
+ </BODY>
+ </HTML>


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

--- lmtp.c       2001/07/25 11:29:38     1.4
+++ lmtp.c       2001/07/25 15:02:57     1.5
@@ -22,7 +22,6 @@
     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);
@@ -98,8 +97,8 @@
 {
     /*  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 _rfd_ and _wfd_ args are passed to the read(), write() 
+     *  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
@@ -111,11 +110,9 @@
         return NULL;
 
     if(io == NULL) {
-        lmtp->io.select = select;
         lmtp->io.read   = read;
         lmtp->io.write  = write;
     } else {
-        lmtp->io.select = io->select ? io->select : select;
         lmtp->io.read   = io->read   ? io->read   : read;
         lmtp->io.write  = io->write  ? io->write  : write;
     }
@@ -138,18 +135,8 @@
 void lmtp_destroy(lmtp_t *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() */
@@ -175,7 +162,8 @@
 
 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.
+     *  on success, returns a buffer which has to be free(3)d by the caller
      *
      *  NOTE: the lmtp_readline()'s underlying readline() already reduces any
      *        CR/LF combination to a string terminating zero. Callers of this
@@ -192,6 +180,7 @@
 
     lmtp_rc_t rc = LMTP_OK;
     char *cpBuf;       /* buffer as a whole */
+    char *cpBufrealloc;/* buffer before realloc */
     char *cpPtr;       /* write cursor */
     char *cpLine;      /* start of the current line (see offsetline) */
     size_t nBuf;       /* size of buffer, doubled through realloc until maximum reached */
@@ -211,10 +200,11 @@
             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); //FIXME double check isn't this a destroy() task?  */
+            if ((cpBufrealloc = (char *)realloc(cpBuf, nBuf)) == NULL) {
+                free(cpBuf);
                 return LMTP_ERR_MEM;
             }
+            cpBuf = cpBufrealloc;
             *cppBuf = cpBuf;                    /* tell caller about the new buffer */
             cpPtr = cpBuf + offset;             /* recover write cursor */
             cpLine = cpBuf + offsetline;        /* recover start of line */
@@ -334,23 +324,6 @@
     return rc;
 }
 
-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;
-
-    lmtp_msg_t *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)
 {
     /*  get an error message matching the given lmtp_rc_t code usually
@@ -358,14 +331,14 @@
      */
     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";
+                                      str = "LMTP: errorcode has no description";
+    if      (rc == LMTP_OK          ) str = "LMTP: no error";
+    else if (rc == LMTP_EOF         ) str = "LMTP: eof";
+    else if (rc == LMTP_ERR_SYSTEM  ) str = "LMTP: see errno";
+    else if (rc == LMTP_ERR_MEM     ) str = "LMTP: dynamic memory allocation failed";
+    else if (rc == LMTP_ERR_OVERFLOW) str = "LMTP: static allocated memory exhausted";
+    else if (rc == LMTP_ERR_ARG     ) str = "LMTP: invalid arg was passed to function";
+    else if (rc == LMTP_ERR_UNKNOWN ) str = "LMTP: guru meditation";
 
     return str;
 }
@@ -419,7 +392,6 @@
     lmtp->dispatch[i]->verb = strdup(verb);
     lmtp->dispatch[i]->cb   = cb;
     lmtp->dispatch[i]->ctx  = ctx;
-    lmtp->dispatch[i]->msg  = NULL;
 
     return rc;
 }


ossp-pkg/lmtp2nntp/lmtp.h 1.4 -> 1.5

--- lmtp.h       2001/07/25 11:29:38     1.4
+++ lmtp.h       2001/07/25 15:02:57     1.5
@@ -11,7 +11,6 @@
 typedef struct lmtp_st lmtp_t;
 
 typedef struct {
-    int     (*select)(int nfds, fd_set *rfds, fd_set *wrfds, fd_set *efds, struct timeval *t);
     ssize_t (*read)  (int fd, void *buf, size_t nbytes);
     ssize_t (*write) (int fd, const void *buf, size_t nbytes);
 } lmtp_io_t;
@@ -27,12 +26,6 @@
     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 */
@@ -51,8 +44,6 @@
 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);
-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);
 lmtp_rc_t   lmtp_loop    (lmtp_t *lmtp);


ossp-pkg/lmtp2nntp/lmtp2nntp.c 1.4 -> 1.5

--- lmtp2nntp.c  2001/07/25 11:29:38     1.4
+++ lmtp2nntp.c  2001/07/25 15:02:57     1.5
@@ -1,4 +1,3 @@
-
 /*
  * mail2nntp.c
  *
@@ -13,6 +12,7 @@
  */
 
 
+#include <stdlib.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <errno.h>
@@ -21,15 +21,25 @@
 
 /* third party */
 #include "str.h"
+#include "argz.h"
 
 /* own headers */
 #include "lmtp.h"
 
+#ifndef FALSE
+#define FALSE (1 != 1)
+#endif
+#ifndef TRUE
+#define TRUE (!FALSE)
+#endif
+
 #define ERR_EXECUTION -1
 #define ERR_DELIVERY -2
 
 #define MESSAGE_MAXLEN 8*1024*1024
 
+extern void lmtp_debug_dumplmtp(lmtp_t *lmtp);
+
 static ssize_t trace_read(int d, void *buf, size_t nbytes);
 static ssize_t trace_write(int d, const void *buf, size_t nbytes);
 
@@ -41,80 +51,25 @@
 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);
-static void test(void);
-
-int main(int argc, char **argv)
-{
-    int i; /* general purpose scratch int, index ... */
-
-    {
-        char buf[1000];
-        int bufused = 0;
-        int tracefile;
-
-// printf("DEBUG: start of argdump\n", buf);
-        for (i=0; i<argc; i++) {
-// printf("DEBUG: [%d]=***%s***\n", i, argv[i]);
-            bufused+=sprintf(buf+bufused, "[%d]=\"%s\"\n", i, argv[i]);
-        }
-// printf("DEBUG: buffer ***%s***\n", buf);
-        if ((tracefile = open("/tmp/t", O_CREAT|O_WRONLY|O_APPEND, 0664)) != -1) {
-            write(tracefile, buf, bufused);
-// printf("DEBUG: writing\n", buf);
-            close(tracefile);
-        }
-// printf("DEBUG: end of argdump\n", buf);
-    }
-
-    /* read in the arguments */
-
-#if 0
-
-    while ((i = getopt(argc, argv, "p:l:h:m:tv")) != -1)
-        switch (i) {
-            case 'p': // -p protocol
-                break;
-            case 'l': // -l logtarget
-                break;
-            case 'h': // -h host[:port]
-                break;
-            case 'm': // -m mode
-                break;
-            case 'd': // -t (tracing)
-                break;
-            case 'v': // -v (verbose)
-                break;
-            case '?':
-            default:
-                //FIXME usage(argv[0]);
-                //FIXME exit(ERR_EXECUTION);
-        }
-    argc -= optind; argv += optind; // remaining args is/are newsgroup/s
-#endif
-    
-    //FIXME printf("Hello, World!\n");
-    test();
-    //FIXME printf("Hello, Again!\n");
-    return 0;
-}
-
-/*
- * print usage information
- *
- */
-
-static void usage(char *command)
-{
-    fprintf(stderr, "USAGE: %s [-p protocol] [-l logtarget] "\
-     "[-h host[:port]] [-m mode] [-t] [-v] newsgroup [newsgroup ...]\n",
-     command);
-    return;
-}
+typedef struct {
+    int option_verbose;
+    int option_tracing;
+    int option_mode;
+    char  *azNewsgroups;
+    size_t asNewsgroups;
+    char *rfc822message;
+    int saw_lhlo;
+    char  *azRcpt;
+    size_t asRcpt;
+} lmtp2nntp_t;
+
+enum {
+    MODE_ONCE,
+    MODE_MANY
+};
 
 /*
  * tracing
- *
  */
 ssize_t trace_read(int d, void *buf, size_t nbytes)
 {
@@ -143,72 +98,137 @@
 }
 
 /*
- * test a function
- *
+ * print usage information
  */
+static void usage(char *command)
+{
+    fprintf(stderr, 
+            "USAGE: %s [-p protocol] [-l logtarget] "
+            "[-h host[:port]] [-m mode] [-t] [-v] newsgroup [newsgroup ...]\n",
+            command);
+    return;
+}
 
-extern void lmtp_debug_dumplmtp(lmtp_t *lmtp);
-static void test(void)
+int main(int argc, char **argv)
 {
+    int rc = 0;
     lmtp_t *lmtp;
-    lmtp_rc_t rc;
-    lmtp_req_t req;
-    lmtp_res_t res;
-    lmtp_io_t io;
-#define BUFLEN 100
-    char buf[BUFLEN];
-    lmtp_cb_t oldcb = NULL;
-    
+    lmtp_io_t lmtp_io;
+    lmtp2nntp_t *ctx;
+    int i; /* general purpose scratch int, index ... */
 
-    io.read=trace_read;
-    io.write=trace_write;
-    io.select=select;
-    lmtp = lmtp_create(STDIN_FILENO, STDOUT_FILENO, &io);
-    // lmtp_debug_dumplmtp(lmtp);
-    lmtp_register(lmtp, "LHLO",         NULL, NULL,&oldcb,NULL); // printf("DEBUG: 1 oldcb=%d\n", (int)oldcb);
-    lmtp_register(lmtp, "LHLO", lmtp_cb_lhlo, NULL,&oldcb,NULL); // printf("DEBUG: 2 oldcb=%d\n", (int)oldcb);
-    lmtp_register(lmtp, "LHLO",         NULL, NULL,&oldcb,NULL); // printf("DEBUG: 3 oldcb=%d\n", (int)oldcb);
-    lmtp_register(lmtp, "MAIL", lmtp_cb_mail, NULL, NULL, NULL);
-    lmtp_register(lmtp, "RCPT", lmtp_cb_rcpt, NULL, NULL, NULL);
-    lmtp_register(lmtp, "DATA", lmtp_cb_data, NULL, NULL, NULL);
-    lmtp_register(lmtp, "NOOP", lmtp_cb_noop, NULL, NULL, NULL);
-    lmtp_register(lmtp, "RSET", lmtp_cb_rset, NULL, NULL, NULL);
-    lmtp_register(lmtp, "QUIT", lmtp_cb_quit, NULL, NULL, NULL);
-    // 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);
-    */
+    char *progname = argv[0];
 
-    /* printf("DEBUG: 08 lmtp_loop=%d\n", */ lmtp_loop(lmtp) /*)*/;
+    /* create application context */
+    if ((ctx = (lmtp2nntp_t *)malloc(sizeof(lmtp2nntp_t))) == NULL)
+        exit(ERR_EXECUTION);
+    ctx->option_verbose = FALSE;
+    ctx->option_tracing = FALSE;
+    ctx->option_mode = MODE_MANY;
+    ctx->azNewsgroups = NULL;
+    ctx->asNewsgroups = 0;
+    ctx->rfc822message = NULL;
+    ctx->saw_lhlo = FALSE;
+    ctx->azRcpt = NULL;
+    ctx->asRcpt = 0;
 
-    /* printf("DEBUG: 99.\n"); */
-    return;
+    /* read in the arguments */
+    {
+        char buf[1000];
+        int bufused = 0;
+        int tracefile;
+
+        for (i=0; i<argc; i++)
+            bufused+=sprintf(buf+bufused, "[%d]=\"%s\"\n", i, argv[i]);
+        if ((tracefile = open("/tmp/t", O_CREAT|O_WRONLY|O_APPEND, 0664)) != -1) {
+            write(tracefile, buf, bufused);
+            close(tracefile);
+        }
+    }
+    while ((i = getopt(argc, argv, "p:l:h:m:tvo:c:i:t:")) != -1) {
+        switch (i) {
+            case 'p': // -p protocol
+                break;
+            case 'l': // -l logtarget
+                break;
+            case 'o': // FIXME
+                break;
+            case 'c': // FIXME
+                break;
+            case 'i': // FIXME
+                break;
+            case 't': // FIXME
+                break;
+            case 'h': // -h host[:port]
+                break;
+            case 'm': // -m mode
+                if (strcasecmp(argv[optind], "once") == 0)
+                    ctx->option_mode = MODE_ONCE;
+                else if (strcasecmp(argv[optind], "many") == 0)
+                    ctx->option_mode = MODE_MANY;
+                else {
+                    fprintf(stderr, "%s:Error: Invalid mode \"%s\" to option -m\n", progname, argv[optind]);
+                    exit(ERR_EXECUTION);
+                }
+                break;
+            case 'd': // -t (tracing)
+                ctx->option_tracing = TRUE;
+                break;
+            case 'v': // -v (verbose)
+                ctx->option_verbose = TRUE;
+                break;
+            case '?':
+            default:
+                usage(progname);
+                exit(ERR_EXECUTION);
+        }
+    }
+    /* remaining arguments are newsgroup names */
+    for (i = optind; i < argc; i++)
+        argz_add(&ctx->azNewsgroups, &ctx->asNewsgroups, argv[i]);
+
+    /* initialize LMTP context */
+    lmtp_io.read  = trace_read;
+    lmtp_io.write = trace_write;
+    if ((lmtp = lmtp_create(STDIN_FILENO, STDOUT_FILENO, &lmtp_io)) == NULL) {
+        fprintf(stderr, "%s:Error: Unable to initialize LMTP library\n", progname);
+        exit(ERR_EXECUTION);
+    }
+    lmtp_register(lmtp, "LHLO", lmtp_cb_lhlo, ctx, NULL, NULL); 
+    lmtp_register(lmtp, "MAIL", lmtp_cb_mail, ctx, NULL, NULL);
+    lmtp_register(lmtp, "RCPT", lmtp_cb_rcpt, ctx, NULL, NULL);
+    lmtp_register(lmtp, "DATA", lmtp_cb_data, ctx, NULL, NULL);
+    lmtp_register(lmtp, "NOOP", lmtp_cb_noop, ctx, NULL, NULL);
+    lmtp_register(lmtp, "RSET", lmtp_cb_rset, ctx, NULL, NULL);
+    lmtp_register(lmtp, "QUIT", lmtp_cb_quit, ctx, NULL, NULL);
+    
+    /* loop for LMTP protocol */
+    lmtp_loop(lmtp);
+
+    return 0;
 }
-static lmtp_rc_t lmtp_cb_lhlo(lmtp_t *lmtp, lmtp_io_t *io, lmtp_req_t *req, void *ctx)
+
+static lmtp_rc_t lmtp_cb_lhlo(lmtp_t *lmtp, lmtp_io_t *io, lmtp_req_t *req, void *_ctx)
 {
-    lmtp_res_t res;
+    /*  
+     *  RFC821 [excerpt] 4.1. SMTP COMMANDS
+     *  4.1.1.  COMMAND SEMANTICS, HELO
+     *  This command and an OK reply to it confirm that both the sender-SMTP
+     *  and the receiver-SMTP are in the initial state, that is, there is no
+     *  transaction in progress and all state tables and buffers are cleared.
+     * 
+     */
     lmtp_rc_t rc = LMTP_OK;
+    lmtp_res_t res;
+    lmtp2nntp_t *ctx = (lmtp2nntp_t *)_ctx;
+
+    //FIXME use rset() not lmtp_cb_rset()
+    ctx->saw_lhlo = TRUE;
+
     res.statuscode = "250";
     res.dsncode    = NULL; /* DSN not used for greeting */
     res.statusmsg  = "ENHANCEDSTATUSCODES\nDSN\nPIPELINING\n8BITMIME";
+    res.statusmsg  = "ENHANCEDSTATUSCODES\nDSN\n8BITMIME";
         /*
          *  RFC2034 = EHANCEDSTATUSCODES
          *  RFC1894 = DSN
@@ -219,71 +239,80 @@
     return rc;
 }
 
-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_mail(lmtp_t *lmtp, lmtp_io_t *io, lmtp_req_t *req, void *_ctx)
 {
     lmtp_res_t res;
     lmtp_rc_t rc = LMTP_OK;
-    res.statuscode = "553";
-    res.dsncode    = "5.1.8";
-    res.statusmsg  = "Bad sender FIXME";
-    res.statuscode = "250";
-    res.dsncode    = "2.1.0";
-    res.statusmsg  = "Sender ok FIXME";
-    lmtp_response(lmtp, &res);
+    lmtp2nntp_t *ctx = (lmtp2nntp_t *)_ctx;
+
+    if (ctx->saw_lhlo == TRUE) {
+        res.statuscode = "250";
+        res.dsncode    = "2.1.0";
+        res.statusmsg  = "Sender ok FIXME";
+        lmtp_response(lmtp, &res);
+    } else {
+        res.statuscode = "553";
+        res.dsncode    = "5.1.8";
+        res.statusmsg  = "friendly people say LHLO to open a transmission channel";
+        lmtp_response(lmtp, &res);
+    }
     return rc;
 }
 
-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_rcpt(lmtp_t *lmtp, lmtp_io_t *io, lmtp_req_t *req, void *_ctx)
 {
     lmtp_rc_t rc = LMTP_OK;
     lmtp_res_t res;
-    char **cp;
+    lmtp2nntp_t *ctx = (lmtp2nntp_t *)_ctx;
 
+    argz_add(&ctx->azRcpt, &ctx->asRcpt, req->msg);
     res.statuscode = "250";
     res.dsncode    = "2.1.5";
     res.statusmsg  = "Recipient ok FIXME";
     lmtp_response(lmtp, &res);
 
-    cp = lmtp_message(lmtp, "RCPT");
-    if (cp == NULL) {
-        printf("DEBUG: cp=NULL\n");
-    } else {
-        printf("DEBUG: cp=%d\n", cp);
-    }
-
     return rc;
 }
 
 
-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_data(lmtp_t *lmtp, lmtp_io_t *io, lmtp_req_t *req, void *_ctx)
 {
     lmtp_res_t res;
     lmtp_rc_t rc = LMTP_OK;
+    lmtp2nntp_t *ctx = (lmtp2nntp_t *)_ctx;
     char *buf;
     char errorstring[128];
+    char *rcpt;
 
     res.statuscode = "354";
     res.dsncode    = NULL; /* DSN not used for data */
     res.statusmsg  = "Enter mail, end with \".\" on a line by itself";
     lmtp_response(lmtp, &res);
     rc = lmtp_readmsg(lmtp, &buf, MESSAGE_MAXLEN);
-    if(rc == LMTP_OK) {
-// printf("DEBUG: message=***%s***\n", buf);
-        res.statuscode = "250";
-        res.dsncode    = "2.0.0";
-        res.statusmsg  = "Message accepted for delivery";
-    } else if (rc == LMTP_ERR_OVERFLOW) {
-        res.statuscode = "500";
-        res.dsncode    = "5.0.0";
-        res.statusmsg  = "Message accepted for delivery";
-    } else if (rc == LMTP_ERR_SYSTEM) {
-        res.statuscode = "500";
-        res.dsncode    = "5.0.0";
-        str_format(errorstring, sizeof(errorstring),
-                   "Message accepted for delivery %s", strerror(errno));
-        res.statusmsg  = errorstring;
+
+    rcpt = NULL;
+    while ((rcpt = argz_next(ctx->azRcpt, ctx->asRcpt, rcpt)) != NULL)
+    {
+        if(rc == LMTP_OK) {
+            res.statuscode = "250";
+            res.dsncode    = "2.0.0";
+            // res.statusmsg  = "Message accepted for delivery";
+            str_format(errorstring, sizeof(errorstring),
+                       "Message accepted for delivery to %s", rcpt);
+            res.statusmsg  = errorstring;
+        } else if (rc == LMTP_ERR_OVERFLOW) {
+            res.statuscode = "500";
+            res.dsncode    = "5.0.0";
+            res.statusmsg  = "Message accepted for delivery";
+        } else if (rc == LMTP_ERR_SYSTEM) {
+            res.statuscode = "500";
+            res.dsncode    = "5.0.0";
+            str_format(errorstring, sizeof(errorstring),
+                       "Message accepted for delivery %s", strerror(errno));
+            res.statusmsg  = errorstring;
+        }
+        lmtp_response(lmtp, &res);
     }
-    lmtp_response(lmtp, &res);
     return rc;
 }
 
@@ -297,10 +326,17 @@
     lmtp_response(lmtp, &res);
     return rc;
 }
-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_rset(lmtp_t *lmtp, lmtp_io_t *io, lmtp_req_t *req, void *_ctx)
 {
+    lmtp2nntp_t *ctx = (lmtp2nntp_t *)_ctx;
     lmtp_res_t res;
     lmtp_rc_t rc = LMTP_OK;
+
+    if (ctx->azRcpt != NULL) {
+        free(ctx->azRcpt);
+        ctx->azRcpt = NULL;
+        ctx->asRcpt = 0;
+    }
     res.statuscode = "250";
     res.dsncode    = "2.0.0";
     res.statusmsg  = "Reset state.";

CVSTrac 2.0.1