/* ** Copyright (c) 2001-2002 The OSSP Project ** Copyright (c) 2001-2002 Cable & Wireless Deutschland ** ** 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 . ** ** lmtp2nntp_option.h: option parsing */ #include #include #include /* 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; ipt, 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 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; }