Index: ossp-pkg/lmtp2nntp/fixme.h RCS File: /v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/fixme.h,v rcsdiff -q -kk '-r1.16' '-r1.17' -u '/v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/fixme.h,v' 2>/dev/null --- fixme.h 2002/02/19 13:00:14 1.16 +++ fixme.h 2002/02/20 15:42:26 1.17 @@ -31,6 +31,7 @@ struct headerrule_st; typedef struct headerrule_st headerrule_t; +#include struct headerrule_st { headerrule_t *next; char *carve; /* pri, regex, header, val carved out here, so free up only this */ @@ -38,7 +39,24 @@ char *regex; char *header; char *val; + pcre *pcreRegex; + pcre_extra *pcreExtra; }; +headerrule_t *FIXME1; + +struct headerdata_st; +typedef struct headerdata_st headerdata_t; +struct headerdata_st { + headerdata_t *prev; + headerdata_t *next; + char *name; + int ndata; /* =0 means data is invalid, =1 means use data.s, >1 means use data.m */ + union { + char *s; + char **m; + } data; +}; +headerdata_t *FIXME2; typedef struct { l2_context_t ctx; Index: ossp-pkg/lmtp2nntp/lmtp2nntp_config.c RCS File: /v/ossp/cvs/ossp-pkg/lmtp2nntp/lmtp2nntp_config.c,v rcsdiff -q -kk '-r1.50' '-r1.51' -u '/v/ossp/cvs/ossp-pkg/lmtp2nntp/lmtp2nntp_config.c,v' 2>/dev/null --- lmtp2nntp_config.c 2002/02/14 15:11:08 1.50 +++ lmtp2nntp_config.c 2002/02/20 15:42:26 1.51 @@ -39,6 +39,7 @@ #include "pcre.h" #include "popt.h" #include "str.h" +#include "var.h" #include "val.h" /* library version check (compile-time) */ @@ -103,6 +104,8 @@ return L2_OK; } +static void headersimulation(lmtp2nntp_t *); //FIXME + void config_context(lmtp2nntp_t *ctx) { ex_t ex; @@ -539,6 +542,8 @@ char *cpVal; headerrule_t *hrI; headerrule_t *hrP; + const char *cpError; + int iError; if ( (val_get(ctx->val, "option.headerrule", &ov) != VAL_OK) || (ov->ndata < 0) @@ -554,8 +559,10 @@ log2(ctx, DEBUG, "cp = (data.m)[%d] = \"%s\"", i, cp); hrNew = (headerrule_t *)mallocex(sizeof(headerrule_t)); - hrNew->next = NULL; - hrNew->carve = NULL; // initialize variables which might have resources allocated that need to be cleaned up when an exception is caught + hrNew->next = NULL; + hrNew->carve = NULL; + hrNew->pcreRegex = NULL; + hrNew->pcreExtra = NULL; cp = hrNew->carve = strdupex(cp); /* priority */ @@ -600,8 +607,21 @@ hrNew->header = cpHeader; hrNew->val = cpVal; + if (cpRegex != NULL) { + /* compile regular expression into finite state machine and optimize */ + if ((hrNew->pcreRegex = pcre_compile(cpRegex, PCRE_CASELESS, &cpError, &iError, NULL)) == NULL) { + log3(ctx, ERROR, "option --headerrule, regex (%s) failed at pos %d with %s", cpRegex, iError, cpError); + throw(0,0,0); + } + hrNew->pcreExtra = pcre_study(hrNew->pcreRegex, 0, &cpError); + if (cpError != NULL) { + log1(ctx, ERROR, "option --headerrule, regex optimization failed with %s", cpError); + throw(0,0,0); + } + } + if (ctx->option_firstheaderrule == NULL) - ctx->option_firstheaderrule = (headerrule_t *)hrNew; // interesting point since hrNew is declared volatile we have to cast it. This makes me unhappy as it enlarges the code which is far from the spirit of lib_ex + ctx->option_firstheaderrule = (headerrule_t *)hrNew; /* first */ else { for (hrP = NULL, hrI = ctx->option_firstheaderrule; hrI != NULL && hrI->pri <= hrNew->pri; @@ -611,23 +631,20 @@ if (hrP != NULL) hrP->next = (headerrule_t *)hrNew; /* append */ else - ctx->option_firstheaderrule = (headerrule_t *)hrNew; /* newfirst */ + ctx->option_firstheaderrule = (headerrule_t *)hrNew; /* new first */ } - /* after linking the structure into a parental-controlled structure we - expect that the parental cleanup will handle normal and exceptional - resource releasing and therefore we *must* reset this variable initialization - to avoid accidental local cleanup! In fact, this code will fail if the - next statement is omitted. - */ - hrNew = NULL; // initialize variables which might have resources allocated that need to be cleaned up when an exception is caught - + hrNew = NULL; /* release cleanup responsibility */ } } } - cleanup { // make sure the conditional variables are *always* proper initialized and cleared volatile + cleanup { if (hrNew != NULL) { if (hrNew->carve != NULL) freeex(hrNew->carve); + if (hrNew->pcreRegex != NULL) + free(hrNew->pcreRegex); + if (hrNew->pcreExtra != NULL) + free(hrNew->pcreExtra); freeex((headerrule_t *)hrNew); } } @@ -1004,6 +1021,8 @@ catch (ex) rethrow; + headersimulation(ctx); //FIXME + //void testpcre(void) { char *szRegex; @@ -1077,3 +1096,307 @@ CUS: return; } + + + +static void headerdestroy(headerdata_t *hdC) +{ + int i; + + if (hdC->ndata > 1) { + for (i = 0; i < hdC->ndata; i++) { + if (hdC->data.m[i] == NULL) + break; + free(hdC->data.m[i]); + } + free (hdC->data.m); + } else + if (hdC->ndata == 1) + if (hdC->data.s != NULL) + free(hdC->data.s); + if (hdC->name != NULL) + free(hdC->name); + if (hdC->prev != NULL && hdC->prev->next == hdC) + return; //FIXME still linked, cannot be destroyed + if (hdC->next != NULL && hdC->next->prev == hdC) + return; //FIXME still linked, cannot be destroyed + free(hdC); +} + +static void headerdelete(headerdata_t *hdC) +{ + if (hdC->prev != NULL) + hdC->prev->next = hdC->next; + hdC->next = NULL; + if (hdC->next != NULL) + hdC->next->prev = hdC->prev; + hdC->prev = NULL; + headerdestroy(hdC); +} + +static void headerreplace(headerdata_t *hdC, headerdata_t *hdNew) +{ + hdNew->prev = hdC->prev; + hdC->prev = NULL; + hdNew->next = hdC->next; + hdC->next = NULL; + headerdestroy(hdC); +} + +static headerdata_t *headercreate(void) +{ + ex_t ex; + volatile headerdata_t *hdNew = NULL; + try { + hdNew = mallocex(sizeof(headerdata_t)); + hdNew->prev = NULL; + hdNew->next = NULL; + hdNew->name = NULL; + hdNew->ndata = 0; + } + catch (ex) { + if (hdNew != NULL) + free((headerdata_t *)hdNew); + rethrow; + } + return (headerdata_t *)hdNew; +} +#if 0 +//headermatrix() +{ + volatile header_t *hNew = NULL; + try { + char *cp; + + cp = NULL; + while ((cp = argz_next(ctx->msg->azHeaders, ctx->msg->asHeaders, cp)) != NULL) { + hNew = mallocex(sizeof(header_t)); + //FIXME + } + } + cleanup { + if (hNew != NULL) + free(hNew); + } + catch(ex) { + rethrow; + } +} +#endif + +static var_config_t ctx_lookup_cfg = { + '$', /* varinit */ + '{', /* startdelim */ + '}', /* enddelim */ + '[', /* startindex */ + ']', /* endindex */ + '#', /* current_index */ + '\\', /* escape */ + "a-zA-Z0-9_.-" /* namechars */ +}; + +static var_rc_t ctx_lookup( + void *_ctx, + const char *var_ptr, size_t var_len, int var_idx, + const char **val_ptr, size_t *val_len, size_t *val_size) +{ + lmtp2nntp_t *ctx = (lmtp2nntp_t *)_ctx; + /*FIXME + const char *name; + size_t len; + char *cp; + */ + var_rc_t rc; + + log2(ctx, DEBUG, "lookup variable \"%s\" (%d)", var_ptr, var_len); + rc = VAR_ERR_UNDEFINED_VARIABLE; + if (strncasecmp(var_ptr, "test", var_len) == 0) { + } + else if (strncasecmp(var_ptr, "xyz", var_len) == 0) { + *val_ptr = "Hello, World!"; + *val_len = strlen("Hello, World!"); + *val_size = 0; + rc = VAR_OK; + } + if (rc == VAR_OK) + log4(ctx, DEBUG, "lookup variable \"%s\" (%d) ok: result is \"%s\" (%d)", var_ptr, var_len, *val_ptr, *val_len); + else + log3(ctx, DEBUG, "lookup variable \"%s\" (%d) failed: %s", var_ptr, var_len, var_strerror(rc)); + return rc; +} + +static void headerrewrite(lmtp2nntp_t *ctx) +{ + headerrule_t *hrI; + headerdata_t *hdI, *hdNew; + /* + char *cp; + int i; + char *cpPri; + char *cpRegex; + char *cpHeader; + char *cpVal; + headerrule_t *hrP; + hrNew->pri = atoi(cpPri); + hrNew->regex = cpRegex; + hrNew->header = cpHeader; + hrNew->val = cpVal; + char *szRegex; + pcre *pcreRegex; + pcre_extra *pcreExtra; + const char *szError; + int nErrorOffset; + int opt; + char *buf; + int buf_size; +#define OVECSIZE 30 + int ovec[OVECSIZE]; + int i; + const char **cpList; + */ + int ovec[OVECSIZE]; + int iCheck; + + { //FIXME debug code block + int i; + + log0(ctx, DEBUG, "FIXME trace ---------- headerrewrite() ----------"); + for (hrI = ctx->option_firstheaderrule; hrI != NULL; hrI = hrI->next) + log1(ctx, DEBUG, "hrI->header=%s", hrI->header); + for (hdI = ctx->msg->hdFirst; hdI != NULL; hdI = hdI->next) { + if (hdI->ndata == 0) + log1(ctx, DEBUG, "hdI->name=%s, (NO DATA)", hdI->name); + if (hdI->ndata == 1) + log2(ctx, DEBUG, "hdI->name=%s, hdI->data.s=%s", hdI->name, hdI->data.s); + if (hdI->ndata > 1) + for (i = 0; i < hdI->ndata; i++) + log3(ctx, DEBUG, "hdI->name=%s, hdI->data.m[%d]=%s", hdI->name, i, hdI->data.m[i]); + } + } + + for (hrI = ctx->option_firstheaderrule; hrI != NULL; hrI = hrI->next) { /* for each rule */ + //log1(ctx, DEBUG, "FIXME trace loop hrI=%.8lx", hrI); + if (hrI->regex != NULL) { + log1(ctx, DEBUG, "rule has regex %s", hrI->regex); + for (hdI = ctx->msg->hdFirst; hdI != NULL; hdI = hdI->next) { /* for each header */ + //log2(ctx, DEBUG, "FIXME trace loop hdI=%.8lx, hI->name=\"%s\"", hdI, hdI->name); + if (hdI->name == NULL || strlen(hdI->name) == 0) + continue; //FIXME header w/o name cannot happen normally + iCheck = pcre_exec(hrI->pcreRegex, hrI->pcreExtra, hdI->name, strlen(hdI->name), 0, 0, ovec, OVECSIZE); + log1(ctx, DEBUG, "FIXME trace iCheck=%d", iCheck); + if (iCheck >= 1) { + log0(ctx, DEBUG, "regex matches"); + hdNew = headercreate(); + hdNew->name = strdupex(hrI->header); //FIXME rename ->header to ->name + { + var_rc_t var_rc; + char *res_ptr; + if ((var_rc = var_expand(hrI->val, strlen(hrI->val), &res_ptr, NULL, + ctx_lookup, ctx, &ctx_lookup_cfg, TRUE)) != VAR_OK) { + log2(ctx, ERROR, "expansion of '%s' failed: %s", hrI->val, var_strerror(var_rc)); + } + log2(ctx, ERROR, "expansion of '%s' succeeded: %s", hrI->val, res_ptr); + hdNew->data.s = res_ptr; + hdNew->ndata = 1; + /*FIXME clean up data.m */ + headerreplace(hdI, hdNew); + if (hdNew->prev == NULL) + ctx->msg->hdFirst = hdNew; + hdI = hdNew; + } + } + } + } + else { + log1(ctx, DEBUG, "rule has no regex but static header %s", hrI->header); + hdNew = headercreate(); + hdNew->name = strdupex(hrI->header); //FIXME rename ->header to ->name + hdNew->data.s = strdupex(hrI->val); + hdNew->ndata = 1; + /*FIXME clean up data.m */ + for (hdI = ctx->msg->hdFirst; hdI != NULL; hdI = hdI->next) { /* for each header */ + if (hdI->name == NULL || strlen(hdI->name) == 0) + continue; //FIXME header w/o name cannot happen normally + log2(ctx, DEBUG, "hrI->header=%s, hdI->name=%s", hrI->header, hdI->name); + if (strcmp(hrI->header, hdI->name) == 0) + break; + } + if (hdI != NULL) { + log1(ctx, DEBUG, "replacing header %s", hrI->header); + headerreplace(hdI, hdNew); + if (hdNew->prev == NULL) + ctx->msg->hdFirst = hdNew; + } + else { + log1(ctx, DEBUG, "appending header %s", hrI->header); + for (hdI = ctx->msg->hdFirst; hdI->next != NULL; hdI = hdI->next); + hdI->next = hdNew; + hdNew->prev = hdI; + } + } + } + + { //FIXME debug code block + int i; + + log0(ctx, DEBUG, "FIXME trace ---------- headerrewrite() ---------- FINISH"); + for (hrI = ctx->option_firstheaderrule; hrI != NULL; hrI = hrI->next) + log1(ctx, DEBUG, "hrI->header=%s", hrI->header); + for (hdI = ctx->msg->hdFirst; hdI != NULL; hdI = hdI->next) { + if (hdI->ndata == 0) + log1(ctx, DEBUG, "hdI->name=%s, (NO DATA)", hdI->name); + if (hdI->ndata == 1) + log2(ctx, DEBUG, "hdI->name=%s, hdI->data.s=%s", hdI->name, hdI->data.s); + if (hdI->ndata > 1) + for (i = 0; i < hdI->ndata; i++) + log3(ctx, DEBUG, "hdI->name=%s, hdI->data.m[%d]=%s", hdI->name, i, hdI->data.m[i]); + } + } +} + +static void headersimulation(lmtp2nntp_t *ctx) +{ + headerdata_t *hdI, *hdNew; + + ctx->msg = msg_create(); + + log0(ctx, DEBUG, "FIXME simulation - GO"); + char *replyto[4] = { "foo@example.com", "bar@example.com", "quux@example.com", NULL }; + + hdNew = headercreate(); + hdNew->name = "To"; + hdNew->data.s = "foo@invalid.com"; + hdNew->ndata = 1; + ctx->msg->hdFirst = hdNew; + hdI = hdNew; + + hdNew = headercreate(); + hdNew->name = "Reply-To"; + hdNew->data.m = replyto; + hdNew->ndata = 3; + hdI->next = hdNew; + hdI = hdNew; + + hdNew = headercreate(); + hdNew->name = "Subject"; + hdNew->data.s = "a tiny little test"; + hdNew->ndata = 1; + hdI->next = hdNew; + hdI = hdNew; + + hdNew = headercreate(); + hdNew->name = "Date"; + hdNew->data.s = "Mon, 18 Feb 2002 09:43:52 +0100"; + hdNew->ndata = 1; + hdI->next = hdNew; + hdI = hdNew; + + hdNew = headercreate(); + hdNew->name = "Message-ID"; + hdNew->data.s = "<200201172300.AAA29400@procter012.pg-cw.de>"; + hdNew->ndata = 1; + hdI->next = hdNew; + hdI = hdNew; + + headerrewrite(ctx); +} Index: ossp-pkg/lmtp2nntp/lmtp2nntp_msg.h RCS File: /v/ossp/cvs/ossp-pkg/lmtp2nntp/lmtp2nntp_msg.h,v rcsdiff -q -kk '-r1.2' '-r1.3' -u '/v/ossp/cvs/ossp-pkg/lmtp2nntp/lmtp2nntp_msg.h,v' 2>/dev/null --- lmtp2nntp_msg.h 2001/12/31 15:15:36 1.2 +++ lmtp2nntp_msg.h 2002/02/20 15:42:26 1.3 @@ -39,6 +39,7 @@ char *cpMsg; /* the wholly message to be received by DATA command */ char *azHeaders; /* header part of message above */ size_t asHeaders; + struct headerdata_st *hdFirst; /*FIXME i want headerdata_t here */ char *cpFid; /* foreign (aka sendmail queue) id from parsing headers */ char *cpBody; /* body part of message above */ char *cpMsgid;