/* ** 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.c: LMTP to NNTP configuration parsing */ #include #include #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include /* third party (included) */ // #include "lmtp2nntp_argz.h" // #include "lmtp2nntp_shpat.h" // #include "lmtp2nntp_daemon.h" #include "lmtp2nntp_popt.h" #include "val.h" /* third party (linked in) */ #include "str.h" // #include "l2.h" // #include "var.h" /* library version check (compile-time) */ #define L2_VERSION_HEX_REQ 0x001200 #define L2_VERSION_STR_REQ "0.1.0" #define STR_VERSION_HEX_REQ 0x009206 #define STR_VERSION_STR_REQ "0.9.6" #ifdef L2_VERSION_HEX #if L2_VERSION_HEX < L2_VERSION_HEX_REQ #error "require a newer version of OSSP L2" #endif #endif #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_config.h" #include "lmtp2nntp_lmtp.h" #include "lmtp2nntp_nntp.h" #include "lmtp2nntp_msg.h" #include "sa.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 void die(char *); //FIXME void die(char *msg) { printf("ERROR: %s\n", msg); exit(-1); } static val_rc_t dumper(void *ctx, const char *name, int type, const char *desc, void *data) { switch (type) { case VAL_TYPE_VAL: fprintf(stderr, "DEBUG: <%10s>, name=<%10s>, VAL_TYPE_VAL, desc=<%20s>, data@%.8lx INTERNAL\n", (char *)ctx, name, desc, (long)data); break; case VAL_TYPE_PTR: fprintf(stderr, "DEBUG: <%10s>, name=<%10s>, VAL_TYPE_PTR, desc=<%20s>, data@%.8lx=%.8lx\n", (char *)ctx, name, desc, (long)data, *(long *)data); break; case VAL_TYPE_CHAR: fprintf(stderr, "DEBUG: <%10s>, name=<%10s>, VAL_TYPE_CHAR, desc=<%20s>, data@%.8lx='%c'\n", (char *)ctx, name, desc, (long)data, *(char *)data); break; case VAL_TYPE_SHORT: fprintf(stderr, "DEBUG: <%10s>, name=<%10s>, VAL_TYPE_SHORT, desc=<%20s>, data@%.8lx=%8d\n", (char *)ctx, name, desc, (long)data, *(short *)data); break; case VAL_TYPE_INT: fprintf(stderr, "DEBUG: <%10s>, name=<%10s>, VAL_TYPE_INT, desc=<%20s>, data@%.8lx=%8d\n", (char *)ctx, name, desc, (long)data, *(int *)data); break; case VAL_TYPE_LONG: fprintf(stderr, "DEBUG: <%10s>, name=<%10s>, VAL_TYPE_LONG, desc=<%20s>, data@%.8lx=%8ld\n", (char *)ctx, name, desc, (long)data, *(long *)data); break; case VAL_TYPE_FLOAT: fprintf(stderr, "DEBUG: <%10s>, name=<%10s>, VAL_TYPE_FLOAT, desc=<%20s>, data@%.8lx=%8f\n", (char *)ctx, name, desc, (long)data, *(float *)data); break; case VAL_TYPE_DOUBLE: fprintf(stderr, "DEBUG: <%10s>, name=<%10s>, VAL_TYPE_DOUBLE, desc=<%20s>, data@%.8lx=%8f\n", (char *)ctx, name, desc, (long)data, *(double *)data); break; default: fprintf(stderr, "DEBUG: <%10s>, name=<%10s>, type = %.8lx, desc=<%20s>, data@%.8lx\n", (char *)ctx, name, (long)type, desc, (long)data); } return VAL_OK; } void dotconftest(int argc, char **argv) /*FIXME*/ { popt_context poptCon; /* context for parsing command-line options */ lmtp2nntp_config_t *ctx; char *cpBuf; struct popt_option poptTable[] = { { "childsmax", 'C', POPT_ARG_STRING, NULL, 'C', "foo", "childsmax" }, { "daemonize", 'D', POPT_ARG_NONE, NULL, 'D', "foo", NULL }, { "kill", 'K', POPT_ARG_NONE, NULL, 'K', "foo", NULL }, { "pidfile", 'P', POPT_ARG_STRING, NULL, 'P', "foo", "pidfile" }, { "veryverbose", 'V', POPT_ARG_NONE, NULL, 'V', "foo", NULL }, { "acl", 'a', POPT_ARG_STRING, NULL, 'a', "foo", "addr[/mask]" }, { "bind", 'b', POPT_ARG_STRING, NULL, 'b', "foo", "addr[:port]|-|path[:perms]" }, { "client", 'c', POPT_ARG_STRING, NULL, 'c', "foo", "addr[:port]" }, { "destination", 'd', POPT_ARG_STRING, NULL, 'd', "foo", "addr[:port]" }, { "groupmode", 'g', POPT_ARG_STRING, NULL, 'g', "foo", "groupmode" }, { "headervalue", 'h', POPT_ARG_STRING, NULL, 'h', "foo", "header: value" }, { "include", 'i', POPT_ARG_STRING, NULL, 'i', "foo", "configfile" }, { "size", 's', POPT_ARG_STRING, NULL, 's', "foo", "bytes" }, { "timeout", 't', POPT_ARG_STRING, NULL, 't', "foo", "name=sec" }, { "mailfrom", 'm', POPT_ARG_STRING, NULL, 'm', "foo", "regex" }, { "nodename", 'n', POPT_ARG_STRING, NULL, 'n', "foo", "nodename" }, { "operationmode", 'o', POPT_ARG_STRING, NULL, 'o', "foo", "post|feed" }, { "l2spec", 'l', POPT_ARG_STRING, NULL, 'l', "foo", "spec" }, { "uid", 'u', POPT_ARG_STRING, NULL, 'u', "foo", "number|name" }, { "restrictheader", 'r', POPT_ARG_STRING, NULL, 'r', "foo", "regex" }, { "newsgroup", NUL, POPT_ARG_STRING |POPT_ARGFLAG_DOC_HIDDEN, NULL, 1, NULL, NULL }, POPT_AUTOHELP { NULL, 0, 0, NULL, 0 } }; ctx = malloc(sizeof(lmtp2nntp_config_t)); ctx->option_childsmax = 10; { int testint = 10; int testintout = 100; int testint2 = 20; int testintout2 = 200; val_rc_t rc; val_t *v, *v2, *v3; if ((rc = val_create(&v)) != VAL_OK) die("val_create"); printf("DEBUG: testint = %d, testintout = %d\n", testint, testintout); if ((rc = val_reg(v, "foo", VAL_TYPE_INT, "foo variable", (void *)&testint)) != VAL_OK) die("val_reg"); testint++; if ((rc = val_get(v, "foo", &testintout)) != VAL_OK) die("val_get"); printf("DEBUG: testint = %d, testintout = %d\n", testint, testintout); if ((rc = val_set(v, "foo", 2)) != VAL_OK) die("val_set"); if ((rc = val_get(v, "foo", &testintout)) != VAL_OK) die("val_get"); printf("DEBUG: testint = %d, testintout = %d\n", testint, testintout); if ((rc = val_create(&v2)) != VAL_OK) die("val_create 2"); #if 0 if ((rc = val_reg(v, "bar", VAL_TYPE_VAL, "bar variable", (void *)&v2)) != VAL_OK) die("val_reg 2"); #endif val_reg(v, "bar", VAL_TYPE_VAL, "bar variable", NULL); val_set(v, "bar", v2); if ((rc = val_get(v, "bar", &v3)) != VAL_OK) die("val_get v3"); if ((rc = val_reg(v2, "quux", VAL_TYPE_INT, "quux variable", (void *)&testint2)) != VAL_OK) die("val_reg 2b"); testint2++; if ((rc = val_get(v2, "quux", &testintout2)) != VAL_OK) die("val_get 2c"); printf("DEBUG: testint2 = %d, testintout2 = %d\n", testint2, testintout2); if ((rc = val_get(v, "bar.quux", &testintout2)) != VAL_OK) { fprintf(stderr, "rc=%d\n", rc); die("val_get 2d"); } printf("DEBUG: testint2 = %d, testintout2 = %d\n", testint2, testintout2); printf("DEBUG: testint at address %lx\n", (long)&testint); printf("DEBUG: testintout at address %lx\n", (long)&testintout); printf("DEBUG: testint2 at address %lx\n", (long)&testint2); printf("DEBUG: testint2out at address %lx\n", (long)&testintout2); if ((rc = val_reg(v, "bar.ptr", VAL_TYPE_PTR, "bar ptr (&testint)", NULL)) != VAL_OK) die("val_ret for bar.ptr using inline data"); if ((rc = val_set(v, "bar.ptr", &testint)) != VAL_OK) die("val_set for bar.ptr using inline data"); if ((rc = val_reg(v, "bar.char", VAL_TYPE_CHAR, "bar character (!)", NULL)) != VAL_OK) die("val_ret for bar.char using inline data"); if ((rc = val_set(v, "bar.char", '!')) != VAL_OK) die("val_set for bar.char using inline data"); if ((rc = val_reg(v, "bar.short", VAL_TYPE_SHORT, "bar short (555)", NULL)) != VAL_OK) die("val_ret for bar.short using inline data"); if ((rc = val_set(v, "bar.short", 555)) != VAL_OK) die("val_set for bar.short using inline data"); if ((rc = val_reg(v, "bar.int", VAL_TYPE_INT, "bar integer (76543)", NULL)) != VAL_OK) die("val_ret for bar.int using inline data"); if ((rc = val_set(v, "bar.int", 76543)) != VAL_OK) die("val_set for bar.int using inline data"); if ((rc = val_reg(v, "bar.long", VAL_TYPE_LONG, "bar long (2097152)", NULL)) != VAL_OK) die("val_ret for bar.long using inline data"); if ((rc = val_set(v, "bar.long", 2097152)) != VAL_OK) die("val_set for bar.long using inline data"); if ((rc = val_reg(v, "bar.float", VAL_TYPE_FLOAT, "bar float (1.955830)", NULL)) != VAL_OK) die("val_ret for bar.float using inline data"); if ((rc = val_set(v, "bar.float", 1.95583)) != VAL_OK) die("val_set for bar.float using inline data"); if ((rc = val_reg(v, "bar.double", VAL_TYPE_DOUBLE, "bar double (3.1415+)", NULL)) != VAL_OK) die("val_ret for bar.double using inline data"); if ((rc = val_set(v, "bar.double", 3.14159265358979)) != VAL_OK) die("val_set for bar.double using inline data"); // OK val_apply(v, "", 9, dumper, "v" ); // OK val_apply(v2, "", 9, dumper, "v2"); // OK val_apply(v, "", 0, dumper, "v" ); // OK val_apply(v, "bar", 1, dumper, "v" ); // OK val_apply(v2, "", 0, dumper, "v" ); // OK val_apply(v, "", 1, dumper, "v" ); // OK val_apply(v, "foo", 0, dumper, "v" ); // OK val_apply(v2, "char", 2, dumper, "v" ); // OK val_apply(v, "bar.char", 2, dumper, "v" ); if ((rc = val_destroy(v2)) != VAL_OK) die("val_destroy 2"); if ((rc = val_destroy(v)) != VAL_OK) die("val_destroy"); return; } { char c; char *cp; poptCon = popt_getcontext(NULL, argc, (const char **)argv, poptTable, 0); popt_setotheroptionhelp(poptCon, "[OPTIONS]* [newsgroup ...]"); printf("DEBUG: argc=%d\n", argc); if (argc < 2) { popt_printusage(poptCon, stderr, 0); exit(1); } while ((c = popt_getnextopt(poptCon)) >= 0) { printf("DEBUG: popt_getnextopt returned %d='%c'\n", (int)c, c); } while ((cp = popt_getarg(poptCon)) != NULL) { printf("DEBUG: popt_getarg returned \"%s\"\n", cp); } printf("DEBUG: popt_getnextopt ended with \"%s\"(%d)\n", popt_strerror((int)c), (int)c); popt_freecontext(poptCon); return; } /* Braindump fuer configure ich brauche eine Tabelle, die alle optionen in langer und kurzer Form enthaelt, Angabe ob flag, single- oder multivalue, callbacks fuer die syntaxpruefung des human-readable inputs, die conversion ins interne binaryformat sowie rueckwandlung in human-readable format. Dazu informationen fuer help. */ /* Braindump fuer var ich brauche eine struktur, aus der man ersehen kann, welche variablen es gibt. { struct "system.uname.sysname", varstring, struct "system.uname.nodename", struct "system.uname.release", struct "system.uname.version", struct "system.uname.machine", <<< ctx->progname = strdup(argv[0]); <<< foo = ctx->progname; >>> rc = varreg("main.progname", &ctx->progname); >>> rc = varset("main.progname", strdup(argv[0])); //equivalent to ctx->progname = strdup(argv[0]); >>> rc = varget("main.progname", &foo); //equivalent to foo = ctx->progname } */ { const char *filename = "example.conf"; struct stat sb; int fd; if (stat(filename, &sb) == -1) die("stat"); if ((cpBuf = (char *)malloc((size_t)sb.st_size + 1)) == NULL) die("malloc"); if ((fd = open(filename, O_RDONLY)) == -1) die("open"); if (read(fd, (void *)cpBuf, (size_t)sb.st_size) != (ssize_t)sb.st_size) die("read"); cpBuf[(int)sb.st_size] = '\0'; if (close(fd) == -1) die("close"); } //FIXME printf("DEBUG: *** 1 *** 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 = cpBuf; cpO = 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 *command; char *value; if ((command = str_token(&cp, " \t", "\"'", "#", STR_STRIPQUOTES|STR_BACKSLASHESC)) == NULL) ;//printf("DEBUG: no command - comment only\n"); else { printf("DEBUG: command = ***%s***\n", command); 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); } } } } cpL = cpO; lline = pline; eline = TRUE; } } p = c; } } }