OSSP CVS Repository

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

ossp-pkg/lmtp2nntp/lmtp2nntp_option.c 1.8
/*
**  Copyright (c) 2001-2002 The OSSP Project <http://www.ossp.org/>
**  Copyright (c) 2001-2002 Cable & Wireless Deutschland <http://www.cw.com/de/>
**
**  This file is part of OSSP lmtp2nntp, an LMTP speaking local
**  mailer which forwards mails as Usenet news articles via NNTP.
**  It can be found at http://www.ossp.org/pkg/lmtp2nntp/.
**
**  This program is free software; you can redistribute it and/or
**  modify it under the terms of the GNU General Public  License
**  as published by the Free Software Foundation; either version
**  2.0 of the License, or (at your option) any later version.
**
**  This program 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
**  General Public License for more details.
**
**  You should have received a copy of the GNU General Public License
**  along with this file; if not, write to the Free Software
**  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
**  USA, or contact the OSSP project <ossp@ossp.org>.
**
**  lmtp2nntp_option.h: option parsing
*/

#include <stdlib.h>
#include <stdio.h>
#include <sys/stat.h>

/* third party (included) */
#include "lmtp2nntp_argz.h"

/* third party (linked in) */
#include "str.h"
#include "val.h"
#include "popt.h"

/* library version check (compile-time) */
#define STR_VERSION_HEX_REQ 0x009206
#define STR_VERSION_STR_REQ "0.9.6"
#ifdef STR_VERSION_HEX
#if STR_VERSION_HEX < STR_VERSION_HEX_REQ
#error "require a newer version of OSSP Str"
#endif
#endif

/* own headers */
#include "lmtp2nntp_global.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#if defined(HAVE_DMALLOC_H) && defined(DMALLOC)
#include "dmalloc.h"
#endif
#include "lmtp2nntp_option.h"
#include "lmtp2nntp_config.h"
#include "lmtp2nntp_lmtp.h"
#include "lmtp2nntp_nntp.h"
#include "lmtp2nntp_msg.h"
#define _LMTP2NNTP_VERSION_C_AS_HEADER_
#include "lmtp2nntp_version.c"
#undef  _LMTP2NNTP_VERSION_C_AS_HEADER_

#ifndef FALSE
#define FALSE (1 != 1)
#endif
#ifndef TRUE
#define TRUE (!FALSE)
#endif

#ifndef NUL
#define NUL '\0'
#endif

#if 0
static val_rc_t dumper(void *ctx, const char *name, int type, const char *desc, void *data)
{
    optionval_t *oc;
    int i;

    if (type != VAL_TYPE_PTR)
        return VAL_OK;

    oc = *(optionval_t **)data;

    switch (oc->type) {
        case OPT_FLAG:
            printf("DEBUG: <%5s>, name=<%20s>, OPT_FLAG,   desc=<%20s>, data@%.8lx->[%d]%d\n",     (char *)ctx, name, desc, (long)oc, oc->ndata, oc->data.f); break;
        case OPT_SINGLE:
            printf("DEBUG: <%5s>, name=<%20s>, OPT_SINGLE, desc=<%20s>, data@%.8lx->[%d]\"%s\"\n", (char *)ctx, name, desc, (long)oc, oc->ndata, oc->data.s == NULL ? "NULL" : oc->data.s);
            break;
        case OPT_MULTI:
            printf("DEBUG: <%5s>, name=<%20s>, OPT_MULTI,  desc=<%20s>, data@%.8lx->[%d]%.8lx\n",  (char *)ctx, name, desc, (long)oc, oc->ndata, (long)oc->data.m);
            for (i = 0; i < oc->ndata; i++) {
                {
                    int j;
                    printf("DEBUG: ");
                    for (j=0; j<8; j++) printf("%.2x ", (unsigned char)oc->data.m[i][j]);
                    printf(" ");
                    for (j=0; j<8; j++) printf("%c", isprint(oc->data.m[i][j]) ? oc->data.m[i][j] : '.');
                    printf(" ");
                }
                printf("DEBUG: [%3d] %.8lx \"%s\"\n", i, (long)oc->data.m[i], oc->data.m[i]);
            }
            break;
        default:
            break;
    }
    return VAL_OK;
}
#endif

static lmtp2nntp_option_rc_t option_find(lmtp2nntp_option_t *o, int number, optionval_t **ocp)
{
    lmtp2nntp_option_rc_t rc = VAL_OK;

    if (o == NULL || ocp == NULL)
        return OPTION_ERR_ARG;

    *ocp = o->first;
    while (*ocp != NULL && (*ocp)->number != number)
        *ocp = (*ocp)->next;

    return rc;
}


lmtp2nntp_option_rc_t option_register(lmtp2nntp_option_t *o, char *longname, char shortname, optiontype_t type, optionloop_cb_t *cb, char *cbctx, char *descrip, char *argdescrip)
{
    lmtp2nntp_option_rc_t rc = VAL_OK;
    optionval_t *oc;
    
    //printf("DEBUG: enter option_register(%.8lx, \"%s\", '%c', %d, %.8lx, %.8lx, \"%s\", \"%s\")\n", (long)o, longname, shortname, type, (long)cb, (long)cbctx, descrip, argdescrip);

    if (o == NULL || longname == NULL)
        return OPTION_ERR_ARG;

    /* create a optionval_t structure */
    if ((oc = (optionval_t *)malloc(sizeof(optionval_t))) == NULL)
        return OPTION_ERR_MEM;
    //printf("DEBUG: optionval_t structure malloc'ed\n");
    oc->next         = NULL;
    oc->parent       = o;
    oc->longname     = strdup(longname);
    oc->shortname    = shortname;
    oc->descrip      = descrip == NULL ? NULL : strdup(descrip);
    oc->argdescrip   = argdescrip == NULL ? NULL : strdup(argdescrip);
    oc->type         = type;
    oc->cb           = cb;
    oc->cbctx        = cbctx;
    oc->val          = o->vo;
    oc->number       = o->pi + 1; /* 0 is a reserved val in popt, so offset 1 */
    oc->data.f       = 0;
    oc->data.s       = NULL; /* just in case a pointer is larger than int */
    oc->data.m       = NULL;
    oc->ndata        = 0;
    if (   (                      oc->longname   == NULL)
        || (descrip    != NULL && oc->descrip    == NULL)
        || (argdescrip != NULL && oc->argdescrip == NULL)
          )
        CU(OPTION_ERR_MEM);

    //printf("DEBUG: optionval_t structure created, oc at %.8lx is %.8lx\n", (long)&oc, (long)oc);

    /* feed lib_val */
    if (val_reg(oc->val, oc->longname, VAL_TYPE_PTR, oc->descrip, NULL) != VAL_OK)
        CU(OPTION_ERR_USE);
    if (val_set(oc->val, oc->longname, oc) != VAL_OK)
        CU(OPTION_ERR_USE);
    //printf("DEBUG: val_reg'ed\n");

#if 0
    {
        optionval_t *ov = 0x12345678;

        if (val_get(oc->val, oc->longname, &ov) == VAL_OK)
            printf("DEBUG: oc->val %.8lx %s in %.8lx d = \"s\"\n", (long)oc->val, oc->longname, (long)(oc));
        if (val_get(o->vo,   oc->longname, &ov) == VAL_OK)
            printf("DEBUG: o->vo   %.8lx %s in %.8lx d = \"s\"\n", (long)o->vo,   oc->longname, (long)(ov));
        printf("DEBUG: val_get'ed\n");
    }
#endif

    /* feed lib_popt */
    //printf("DEBUG: o->pi=%d, o->pn=%d\n", o->pi, o->pn);
    if (o->pi >= (o->pn-2)) { /* correction by two here, in malloc and realloc is for AUTOHELP and TABLEEND */
        if (o->pt == NULL) {
            //printf("DEBUG: malloc\n");
            o->pt = (struct popt_option *)malloc(                (1 + 2) * sizeof(struct popt_option));
            o->pn = 1;
        }
        else {
            //printf("DEBUG: realloc\n");
            o->pt = (struct popt_option *)realloc(o->pt, (o->pn * 2 + 2) * sizeof(struct popt_option));
            o->pn = o->pn * 2;
        }
    }
    if (o->pt == NULL)
        CU(OPTION_ERR_MEM);
    o->pt[o->pi].longName   = oc->longname;
    o->pt[o->pi].shortName  = oc->shortname;
    o->pt[o->pi].argInfo    = oc->type == OPT_FLAG ? POPT_ARG_NONE : POPT_ARG_STRING;
    o->pt[o->pi].arg        = NULL;
    o->pt[o->pi].val        = oc->number;
    o->pt[o->pi].descrip    = oc->descrip;
    o->pt[o->pi].argDescrip = oc->argdescrip;

    /* append POPT_AUTOHELP */
    o->pt[o->pi+1].longName   = NULL;
    o->pt[o->pi+1].shortName  = '\0';
    o->pt[o->pi+1].argInfo    = POPT_ARG_INCLUDE_TABLE;
    o->pt[o->pi+1].arg        = popt_helpoptions;
    o->pt[o->pi+1].val        = 0;
    o->pt[o->pi+1].descrip    = "Help options:";
    o->pt[o->pi+1].argDescrip = NULL;

    /* append POPT_TABLEEND */
    o->pt[o->pi+2].longName   = NULL;
    o->pt[o->pi+2].shortName  = '\0';
    o->pt[o->pi+2].argInfo    = 0;
    o->pt[o->pi+2].arg        = 0;
    o->pt[o->pi+2].val        = 0;
    o->pt[o->pi+2].descrip    = NULL;
    o->pt[o->pi+2].argDescrip = NULL;
    o->pi++;
    //printf("DEBUG: popt'ed\n");

    /* link in this new optionval_t structure */
    if (o->first == NULL) {
        o->first = oc;
        o->last  = oc;
    }
    else {
        o->last->next = oc; 
        o->last       = oc;
    }
    //printf("DEBUG: linked\n");

    return rc;

    CUS:
    if (oc != NULL) {
        if (oc->argdescrip != NULL) free(oc->argdescrip);
        if (oc->descrip    != NULL) free(oc->descrip);
        if (oc->longname   != NULL) free(oc->longname);
        free(oc);
    }
    return rc;
}

lmtp2nntp_option_rc_t option_create(lmtp2nntp_option_t **op, val_t *parent)
{
    //printf("DEBUG: enter option_create(%.8lx)\n", (long)op);

    if (op == NULL)
        return OPTION_ERR_ARG;

    if ((*op = (lmtp2nntp_option_t *)malloc(sizeof(lmtp2nntp_option_t))) == NULL)
        return OPTION_ERR_MEM;
    (*op)->childsmax = 0;
    (*op)->daemonize = 0;
    (*op)->kill = 0;
    (*op)->pidfile = 0;
    (*op)->acl.as = 0;
    (*op)->acl.az = NULL;
    (*op)->bind = NULL;
    (*op)->client = NULL;
    (*op)->destination.as = 0;
    (*op)->destination.az = NULL;
    (*op)->groupmode = NULL;
    (*op)->headervalue.as = 0;
    (*op)->headervalue.az = NULL;
    (*op)->include.as = 0;
    (*op)->include.az = NULL;
    (*op)->size = 0;
    (*op)->timeoutlmtpaccept = 0;
    (*op)->timeoutlmtpread = 0;
    (*op)->timeoutlmtpwrite = 0;
    (*op)->timeoutnntpconnect = 0;
    (*op)->timeoutnntpread = 0;
    (*op)->timeoutnntpwrite = 0;
    (*op)->mailfrom = NULL;
    (*op)->nodename = NULL;
    (*op)->operationmode = NULL;
    (*op)->l2spec = NULL;
    (*op)->uid = NULL;
    (*op)->restrictheader.as = 0;
    (*op)->restrictheader.az = NULL;
    (*op)->newsgroup.as = 0;
    (*op)->newsgroup.az = NULL;
                    /**/
    (*op)->first = NULL;
    (*op)->last = NULL;
    (*op)->vo = NULL;
    (*op)->pn = 0;
    (*op)->pi = 0;
    (*op)->pt = NULL;

    if (val_create(&((*op)->vo)) != VAL_OK) {
        free(*op);
        return OPTION_ERR_VAL;
    }
    if (val_reg(parent, "option", VAL_TYPE_VAL, "option", (void *)&((*op)->vo)) != VAL_OK) {
        free(*op);
        return OPTION_ERR_VAL;
    }
    return OPTION_OK;
}

static lmtp2nntp_option_rc_t option_parse_internal(lmtp2nntp_option_t *o, int argc, char **argv)
{
    int i;
    char *cp;
    optionval_t *ocp;
    popt_context poptCon;   /* context for parsing command-line options */

#if 0
    {
        int i; 
    
        for (i=0; i<argc; i++)
            printf("DEBUG: argv[%3d] = ***%s***\n", i, argv[i]);
    }
#endif

    poptCon = popt_getcontext(NULL, argc, (const char **)argv, o->pt, 0);
    popt_setotheroptionhelp(poptCon, "[OPTIONS]* [newsgroup ...]");
    //printf("DEBUG: argc=%d\n", argc);
    if (argc < 2) {
        popt_printusage(poptCon, stderr, 0);
        exit(1);
    }
    while ((i = popt_getnextopt(poptCon)) >= 0) {
        (void)option_find(o, i, &ocp);
        //printf("DEBUG: ocp->type=%d\n", ocp->type);
        if (ocp->cb != NULL)
            ocp->cb(ocp, cp = (ocp->type == OPT_FLAG ? NULL : (char *)popt_getoptarg(poptCon)), ocp->cbctx);
        //printf("DEBUG: popt_getnextopt returned  %d \"%s\", \"%s\"\n", i-1, o->pt[i-1].longName, ocp->longname);
        //printf("DEBUG: popt_getoptarg  returned  \"%s\"\n", cp);
    }
    //printf("DEBUG: current popt error is \"%s\"(%d)\n", popt_strerror(i), i);
    //printf("DEBUG: ----\n");

    {
        int largc;
        char **largv;
        char *cpNew;

        if ((largv = (char **)malloc((1 + 1) * sizeof(char **))) == NULL)
            return OPTION_ERR_MEM;
        largc = 0;
        largv[largc++] = "leftover";
        largv[largc] = NULL;
        while ((cp = (char *)popt_getarg(poptCon)) != NULL) {
            //printf("DEBUG: popt_getarg returned \"%s\"\n", cp);
            if ((largv = (char **)realloc(largv, (largc + 2) * sizeof(char **))) == NULL)
                return OPTION_ERR_MEM;
            largv[largc++] = "--newsgroup";
            largv[largc] = NULL;
            if ((cpNew = strdup(cp)) == NULL)
                return OPTION_ERR_MEM;
            //printf("DEBUG: cpNew = \"%s\"\n", cpNew);
            largv[largc++] = cpNew;
            largv[largc] = NULL;
            //printf("DEBUG: largc = \"%d\"\n", largc);
#if 0
            for (i=0; i<largc; i++)
                printf("DEBUG: largv[%d] = \"%s\"\n", i, largv[i]);
#endif
        }
        if (largc > 1)
            option_parse_internal(o, largc, largv);
    }
    //printf("DEBUG: current popt error is \"%s\"(%d)\n", popt_strerror(i), i);
    popt_freecontext(poptCon);
    return OPTION_OK;
}

static lmtp2nntp_option_rc_t stdsyntax(optionval_t *oc, char *arg, char *cbctx)
{
    //printf("DEBUG: enter stdsyntax %.8lx, \"%s\", \"%s\"\n", (long)oc, arg, cbctx);

    //printf("DEBUG: oc->type=%d\n", oc->type);
    switch (oc->type) {
        case OPT_FLAG:
            //printf("DEBUG: flag   %20s = %s should match %s\n", oc->longname, arg, cbctx);
            if (arg != NULL || cbctx != NULL)
                return OPTION_ERR_ARG;
            if (oc->ndata >= 1)
                return OPTION_ERR_USE;
            oc->data.f = 1;
            oc->ndata = 1;
            break;
        case OPT_SINGLE:
            //printf("DEBUG: single %20s = %s should match %s\n", oc->longname, arg, cbctx);
            if (arg == NULL)
                return OPTION_ERR_ARG;
            /* use this if repeated overwriting definitions are not allowed
             *  if (oc->ndata >= 1 || oc->data.s != NULL)
             *      return OPTION_ERR_USE;
             */
            if (cbctx != NULL)
                if (str_parse(arg, cbctx) <= 0) {
                    //printf("DEBUG: \"%s\" does NOT match \"%s\"\n", arg, cbctx);
                    return OPTION_ERR_USE;
                }
            //printf("DEBUG: \"%s\" does match \"%s\"\n", arg, cbctx);
            if ((oc->data.s = strdup(arg)) == NULL)
                    return OPTION_ERR_MEM;
            oc->ndata = 1;
            break;
        case OPT_MULTI:
            //printf("DEBUG: multi  %20s = %s should match %s\n", oc->longname, arg, cbctx);
            if (arg == NULL)
                return OPTION_ERR_ARG;
            if (oc->ndata >= 1 && oc->data.m == NULL)
                    return OPTION_ERR_USE;
            if (cbctx != NULL)
                if (str_parse(arg, cbctx) <= 0) {
                    //printf("DEBUG: \"%s\" does NOT match \"%s\"\n", arg, cbctx);
                    return OPTION_ERR_USE;
                }
            //printf("DEBUG: \"%s\" does match \"%s\"\n", arg, cbctx);
            /* malloc/realloc                                 existing + this new + terminating NULL */
            if (oc->data.m == NULL) {
                //printf("DEBUG: before  malloc, oc->data.m = %.8lx - ", (long)oc->data.m);
                //printf("DEBUG: requesting %d bytes\n",         (        0 + 1 + 1) * sizeof(char **));
                if ((oc->data.m = (char **)malloc(             (        0 + 1 + 1) * sizeof(char **))) == NULL)
                    return OPTION_ERR_MEM;
                //printf("DEBUG: after   malloc, oc->data.m = %.8lx\n", (long)oc->data.m);
            }
            else {
                //printf("DEBUG: before realloc, oc->data.m = %.8lx\n", (long)oc->data.m);
                //printf("DEBUG: requesting %d bytes\n",         (oc->ndata + 1 + 1) * sizeof(char **));
                if ((oc->data.m = (char **)realloc(oc->data.m, (oc->ndata + 1 + 1) * sizeof(char **))) == NULL)
                    return OPTION_ERR_MEM;
                //printf("DEBUG: after  realloc, oc->data.m = %.8lx\n", (long)oc->data.m);
            }
            if ((oc->data.m[oc->ndata] = strdup(arg)) == NULL)
                    return OPTION_ERR_MEM;
            oc->ndata++;
            oc->data.m[oc->ndata] = NULL;
#if 0
            {
                int i;
                printf("DEBUG: oc->ndata=%d\n", oc->ndata);
                for (i=0; i<=oc->ndata; i++)
                    printf("DEBUG: oc->data[%3d] at %.8lx points to  %.8lx = %s\n", i, (long)&oc->data.m[i], (long)oc->data.m[i], oc->data.m[i]);
            }
#endif
            break;
        default:
            return OPTION_ERR_ARG;
            break;
    }
    return OPTION_OK;
}

static lmtp2nntp_option_rc_t includeit(optionval_t *oc, char *arg, char *cbctx)
{
    lmtp2nntp_option_t *o;
    volatile char *cpBuf = NULL;
    int argc = 0;
    char **argv = NULL;

    //printf("DEBUG: enter includeit %.8lx, \"%s\", \"%s\"\n", (long)oc, arg, cbctx);

    if ((o = oc->parent) == NULL)
        return OPTION_ERR_USE;

    stdsyntax(oc, arg, cbctx);
    //printf("DEBUG: *** 1 *** file going to be read in now\n");
    {
        const char *filename = arg;
        struct stat sb;
        volatile int fd = -1;
        ex_t ex;

        try {
            if (stat(filename, &sb) == -1) throw(0, 0, "stat");
            if ((cpBuf = (char *)malloc((size_t)sb.st_size + 1)) == NULL) throw(0, 0, "malloc");
            if ((fd = open(filename, O_RDONLY)) == -1) throw(0, 0, "open");
            if (read(fd, (void *)cpBuf, (size_t)sb.st_size) != (ssize_t)sb.st_size) throw(0, 0, "read");
            cpBuf[(int)sb.st_size] = '\0';
        }
        cleanup {
            if (fd != -1) close(fd);
        }
        catch (ex) {
            fprintf(stderr, "ERROR: caught %s\n", ex.ex_value == NULL ? "N/A" : (char *)ex.ex_value);
            rethrow;
        }
    }
    //printf("DEBUG: *** 2 *** file as it was just read in ***\n%s***\n", cpBuf);

    {
        char *cpI;  /* pointer to next character to be read */
        char *cpO;  /* pointer to next character to be written. Used for eliminating
                       backslash+newline at a line continuation */
        char *cpL;  /* pointer to start of line */
        int pline;  /* current physical (disregarding line continuation) line number */
        int lline;  /* current logical lines first physical line number */
        int eline;  /* flag signaling empty or just whitespace-filled line */
        char c;     /* current character */
        char p;     /* previous character */
        int eof;    /* flag signaling end of file detected */

        cpI = (char *)cpBuf;
        cpO = (char *)cpBuf;
        eof = FALSE;
        pline = 1;
        p = NUL;

        cpL = cpO;
        lline = pline;
        eline = TRUE;
        while(!eof) {
            c = *cpI++;
            *cpO++ = c;
            if (c == NUL)
                eof = TRUE;
            else
                if (!isspace(c))
                    eline = FALSE;
            if (eof || (c == '\n')) {
                pline++;
                if (!eof && (p == '\\')) { /* line continuation situation */
                    cpO-=2; /* need to remove both backslash+newline */
                }
                else {
                    if (!eline) { /* process logical line unless it's empty */
                        *(cpO-1) = NUL;
                        if (lline == (pline-1))
                            ;//printf("DEBUG: line[%3d] = ***%s***\n", lline, cpL);
                        else
                            ;//printf("DEBUG: [%3d-%3d] = ***%s***\n", lline, pline-1, cpL);
                        {
                            char *cp = cpL;
                            char *option;
                            char *value;
                            char *cpNew;
                            argz_t Newarg;

                            Newarg.as = 0;
                            Newarg.az = NULL;
                            if ((option = str_token(&cp, " \t", "\"'", "#", STR_STRIPQUOTES|STR_BACKSLASHESC)) == NULL)
                                //printf("DEBUG: no command - comment only\n")
                                ;/* don't care about comments */
                            else {
                                //printf("DEBUG:    option = ***%s***\n", option);
                                if (argv == NULL) {
                                    if ((argv = (char **)malloc(   (   1 + 1) * sizeof(char **))) == NULL)
                                        return OPTION_ERR_MEM;
                                    argc = 0;
                                    argv[argc++] = "include";
                                    argv[argc] = NULL;
                                }

                                if ((cpNew = (char *)malloc(2 + strlen(option) + 1)) == NULL)
                                    return OPTION_ERR_MEM;
                                cpNew[0]=NUL;
                                strcat(cpNew, "--");
                                strcat(cpNew, option);
                                if ((argv = (char **)realloc(argv, (argc + 1) * sizeof(char **))) == NULL)
                                    return OPTION_ERR_MEM;
                                argv[argc++] = cpNew;
                                argv[argc] = NULL;

                                if ((value = str_token(&cp, " \t", "\"'", "#", STR_STRIPQUOTES|STR_BACKSLASHESC)) == NULL)
                                    ;//printf("DEBUG: no value - section\n");
                                else {
                                    while(isspace((int)*value)) value++;
                                    //printf("DEBUG:     value = ***%s***\n", value);
                                    if ((cpNew = strdup(value)) == NULL)
                                        return OPTION_ERR_MEM;
                                    if ((argv = (char **)realloc(argv, (argc + 1) * sizeof(char **))) == NULL)
                                        return OPTION_ERR_MEM;
                                    argv[argc++] = cpNew;
                                    argv[argc] = NULL;
                                }
                            }
                        }
                    }
                    cpL = cpO;
                    lline = pline;
                    eline = TRUE;
                }
            }
            p = c;
        }
    }
    return option_parse_internal(o, argc, argv);
}

lmtp2nntp_option_rc_t option_parse(lmtp2nntp_option_t *o, int argc, char **argv)
{
    lmtp2nntp_option_rc_t rc;
    //printf("DEBUG: enter option_parse(%.8lx, %d, %.8lx)\n", (long)o, argc, (long)argv);

    if (o == NULL)
        return OPTION_ERR_ARG;

    (void)option_register(o, "childsmax",          'C', OPT_SINGLE, &stdsyntax, "m/[0-9]+/", "foo01", "childsmax" );
    (void)option_register(o, "daemonize",          'D', OPT_FLAG,   &stdsyntax, NULL,        "foo02", NULL );
    (void)option_register(o, "kill",               'K', OPT_FLAG,   &stdsyntax, NULL,        "foo03", NULL );
    (void)option_register(o, "pidfile",            'P', OPT_SINGLE, &stdsyntax, "m/.*/",     "foo04", "pidfile" );
    (void)option_register(o, "veryverbose",        'V', OPT_FLAG,   &stdsyntax, NULL,        "foo05", NULL );
    (void)option_register(o, "acl",                'a', OPT_MULTI,  &stdsyntax, "m/.*/",     "foo06", "addr[/mask]" );
    (void)option_register(o, "bind",               'b', OPT_SINGLE, &stdsyntax, "m/.*/",     "foo07", "addr[:port]|-|path[:perms]" );
    (void)option_register(o, "client",             'c', OPT_SINGLE, &stdsyntax, "m/.*/",     "foo08", "addr[:port]" );
    (void)option_register(o, "destination",        'd', OPT_MULTI,  &stdsyntax, "m/.*/",     "foo09", "addr[:port]" );
    (void)option_register(o, "groupmode",          'g', OPT_SINGLE, &stdsyntax, "m/.*/",     "foo10", "groupmode" );
    (void)option_register(o, "headervalue",        'h', OPT_MULTI,  &stdsyntax, "m/.*/",     "foo11", "header: value" );
    (void)option_register(o, "include",            'i', OPT_MULTI,  &includeit, "m/.*/",     "foo12", "configfile" );
    (void)option_register(o, "size",               's', OPT_SINGLE, &stdsyntax, "m/.*/",     "foo13", "bytes" );
    (void)option_register(o, "timeoutlmtp",        NUL, OPT_SINGLE, &stdsyntax, "m/.*/",     "foo14", "sec" );
    (void)option_register(o, "timeoutlmtpaccept",  NUL, OPT_SINGLE, &stdsyntax, "m/.*/",     "fo14a", "sec" );
    (void)option_register(o, "timeoutlmtpread",    NUL, OPT_SINGLE, &stdsyntax, "m/.*/",     "foo15", "sec" );
    (void)option_register(o, "timeoutlmtpwrite",   NUL, OPT_SINGLE, &stdsyntax, "m/.*/",     "foo16", "sec" );
    (void)option_register(o, "timeoutnntp",        NUL, OPT_SINGLE, &stdsyntax, "m/.*/",     "foo17", "sec" );
    (void)option_register(o, "timeoutnntpconnect", NUL, OPT_SINGLE, &stdsyntax, "m/.*/",     "fo17a", "sec" );
    (void)option_register(o, "timeoutnntpread",    NUL, OPT_SINGLE, &stdsyntax, "m/.*/",     "foo18", "sec" );
    (void)option_register(o, "timeoutnntpwrite",   NUL, OPT_SINGLE, &stdsyntax, "m/.*/",     "foo19", "sec" );
    (void)option_register(o, "mailfrom",           'm', OPT_SINGLE, &stdsyntax, "m/.*/",     "foo20", "regex" );
    (void)option_register(o, "nodename",           'n', OPT_SINGLE, &stdsyntax, "m/.*/",     "foo21", "nodename" );
    (void)option_register(o, "operationmode",      'o', OPT_SINGLE, &stdsyntax, "m/.*/",     "foo22", "post|feed" );
    (void)option_register(o, "l2spec",             'l', OPT_SINGLE, &stdsyntax, "m/.*/",     "L2 channel tree textual specification", "l2spec" );
    (void)option_register(o, "user",               'u', OPT_SINGLE, &stdsyntax, "m/.*/",     "foo24", "uid|name" );
    (void)option_register(o, "version",            'v', OPT_FLAG,   &stdsyntax, NULL,        "fo24a", NULL );
    (void)option_register(o, "restrictheader",     'r', OPT_SINGLE, &stdsyntax, "m/.*/",     "foo25", "regex" );
    (void)option_register(o, "newsgroup",          NUL, OPT_MULTI,  &stdsyntax, "m/.*/",     "foo26", "newsgroup");

#if 0
    {
        int i;

        for (i=0; i<26; i++) {
            printf("DEBUG: o->pt[%3d].longName   = %s   \n", i,       o->pt[i].longName  );
            printf("DEBUG: o->pt[%3d].shortName  = %c   \n", i,       o->pt[i].shortName );
            printf("DEBUG: o->pt[%3d].argInfo    = %d   \n", i,       o->pt[i].argInfo   );
            printf("DEBUG: o->pt[%3d].arg        = %.8lx\n", i, (long)o->pt[i].arg       );
            printf("DEBUG: o->pt[%3d].val        = %d   \n", i,       o->pt[i].val       );
            printf("DEBUG: o->pt[%3d].descrip    = %s   \n", i,       o->pt[i].descrip   );
            printf("DEBUG: o->pt[%3d].argDescrip = %s   \n", i,       o->pt[i].argDescrip);
        }
    }
#endif

    //val_apply(o->vo, "", 9, dumper, "vorher" );
    rc = option_parse_internal(o, argc, argv);
    //val_apply(o->vo, "", 9, dumper, "nachher" );
    return rc;
}

lmtp2nntp_option_rc_t option_destroy(lmtp2nntp_option_t *o)
{
    optionval_t *oc;
    int i;

    //printf("DEBUG: option_destroy %.8lx\n", (long)o);

    if (o == NULL)
        return OPTION_ERR_ARG;

    oc = o->first;
    while (oc != NULL) {
        if (oc->type == OPT_SINGLE && oc->data.s != NULL)
            free(oc->data.s);
        if (oc->type == OPT_MULTI  && oc->data.m != NULL) {
            for (i = 0; i < oc->ndata; i++)
                if (oc->data.m[i] == NULL)
                    break;
                else
                    free(oc->data.m[i]);
            free(oc->data.m);
        }
        oc = oc->next;
    }
    if (o->vo != NULL)
        val_destroy(o->vo);
    free(o);

    return OPTION_OK;
}

CVSTrac 2.0.1