--- lmtp2nntp_msg.c 2002/03/13 14:41:13 1.4
+++ lmtp2nntp_msg.c 2002/04/18 14:09:25 1.5
@@ -460,3 +460,466 @@
return str;
}
+ //FIXME below is the header rewriting engine which must be cleaned up and integrated
+
+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)
+ throw(0,0,0);
+ if (hdC->next != NULL && hdC->next->prev == hdC)
+ throw(0,0,0);
+ 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;
+ if (hdNew->prev != NULL)
+ hdNew->prev->next = hdNew;
+ if (hdNew->next != NULL)
+ hdNew->next->prev = hdNew;
+ 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;
+}
+
+struct regex_ctx_st; //FIXME go into a header!
+typedef struct regex_ctx_st regex_ctx_t;
+struct regex_ctx_st {
+ int nMatch;
+ const char **acpMatch;
+ l2_env_t *l2_env;
+ l2_channel_t *l2;
+};
+
+static var_rc_t regex_lookup(
+ var_t *var, 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)
+{
+ regex_ctx_t *ctx = (regex_ctx_t *)_ctx;
+ var_rc_t rc;
+ char *cp;
+ int i;
+
+ logbook(ctx->l2, L2_LEVEL_DEBUG, "rgx_lookup variable \"%s\" (%d)", var_ptr, var_len);
+ rc = VAR_ERR_UNDEFINED_VARIABLE;
+ i = atoi(var_ptr); /* works with both '}' and '\0' termination */
+ if (i < ctx->nMatch) {
+ *val_ptr = ctx->acpMatch[i];
+ *val_len = strlen(ctx->acpMatch[i]);
+ *val_size = 0;
+ rc = VAR_OK;
+ }
+ if (rc == VAR_OK)
+ logbook(ctx->l2, L2_LEVEL_DEBUG, "rgx_lookup variable \"%s\" (%d) ok: result is \"%s\" (%d)", var_ptr, var_len, *val_ptr, *val_len);
+ else
+ logbook(ctx->l2, L2_LEVEL_DEBUG, "rgx_lookup variable \"%s\" (%d) failed: %s (%d)", var_ptr, var_len, var_strerror(var, rc, &cp) == VAR_OK ? cp : "Unknown Error", rc);
+ return rc;
+}
+
+static var_rc_t operate_cb(
+ var_t *var, void *ctx,
+ const char *op_ptr, size_t op_len,
+ const char *arg_ptr, size_t arg_len,
+ const char *val_ptr, size_t val_len,
+ char **out_ptr, size_t *out_len, size_t *out_size)
+{
+ int i;
+
+ if (val_ptr == NULL) {
+ *out_ptr = "";
+ *out_len = 0;
+ *out_size = 0;
+ return VAR_OK;
+ }
+ if (op_len == 6 && strncmp(op_ptr, "return", 6) == 0) {
+ *out_ptr = malloc(arg_len);
+ *out_len = arg_len;
+ *out_size = arg_len;
+ memcpy(*out_ptr, arg_ptr, arg_len);
+ return VAR_OK;
+ }
+ else if (op_len == 5 && strncmp(op_ptr, "upper", 5) == 0) {
+ *out_ptr = malloc(val_len);
+ *out_len = val_len;
+ *out_size = val_len;
+ for (i = 0; i < val_len; i++)
+ (*out_ptr)[i] = (char)toupper((int)(val_ptr[i]));
+ return VAR_OK;
+ }
+ else if (op_len == 5 && strncmp(op_ptr, "lower", 5) == 0) {
+ *out_ptr = malloc(val_len);
+ *out_len = val_len;
+ *out_size = val_len;
+ for (i = 0; i < val_len; i++)
+ (*out_ptr)[i] = (char)tolower((int)(val_ptr[i]));
+ return VAR_OK;
+ }
+ else
+ return VAR_ERR_UNDEFINED_OPERATION;
+}
+
+void msg_headermatrixbuildup(msg_t *msg)
+{
+ ex_t ex;
+ volatile headerdata_t *hdNew = NULL;
+ try {
+ headerdata_t *hdI, *hdP;
+ char *cp;
+
+ cp = NULL;
+ while ((cp = argz_next(msg->azHeaders, msg->asHeaders, cp)) != NULL) { /* for each message header */
+
+ /*FIXME we want O(1) here */
+ for (hdP = NULL, hdI = msg->hdFirst; hdI != NULL; hdP = hdI, hdI = hdI->next) { /* for each matrix header */
+ if (hdI->name == NULL || strlen(hdI->name) == 0 || hdI->ndata == 0)
+ continue;
+ if (strcasecmp(cp, hdI->name) == 0)
+ break;
+ }
+
+ if (hdI == NULL) {
+ hdNew = headercreate(); /* not found, create new */
+ hdNew->name = strdupex(cp);
+ hdI = (headerdata_t *)hdNew; hdNew = NULL; /* ex cleanup */
+ if (hdP == NULL)
+ msg->hdFirst = hdI; /* no previous? this is the first */
+ else {
+ hdP->next = hdI;
+ hdI->prev = hdP;
+ }
+ }
+ cp = argz_next(msg->azHeaders, msg->asHeaders, cp);
+ if (hdI->ndata == 0) {
+ logbook(msg->l2, L2_LEVEL_DEBUG, "header=%s, currently empty", hdI->name);
+ hdI->data.s = strdupex(cp);
+ hdI->ndata = 1;
+ }
+ else if(hdI->ndata == 1) {
+ char *cpOld;
+ cpOld = hdI->data.s;
+ logbook(msg->l2, L2_LEVEL_DEBUG, "header=%s, currently single valued", hdI->name);
+ hdI->data.m = (char **)mallocex(3 * sizeof(char *));
+ hdI->data.m[0] = strdupex(cpOld); //FIXME
+ hdI->data.m[1] = strdupex(cp);
+ hdI->data.m[2] = NULL;
+ hdI->ndata = 2;
+ }
+ else {
+ logbook(msg->l2, L2_LEVEL_DEBUG, "header=%s, currently multi valued %d", hdI->name, hdI->ndata);
+ hdI->data.m = (char **)reallocex(hdI->data.m, (hdI->ndata + 2) * sizeof(char *));
+ hdI->data.m[hdI->ndata++] = strdupex(cp);
+ hdI->data.m[hdI->ndata] = NULL;
+ }
+ }
+ }
+ cleanup {
+ if (hdNew != NULL)
+ free((headerdata_t *)hdNew);
+ }
+ catch(ex) {
+ rethrow;
+ }
+}
+
+void msg_headermatrixteardwn(msg_t *msg)
+{
+ ex_t ex;
+ try {
+ headerdata_t *hdI;
+
+ if (msg->azHeaders != NULL)
+ free(msg->azHeaders);
+ msg->azHeaders = NULL;
+ msg->asHeaders = 0;
+
+ for (hdI = msg->hdFirst; hdI != NULL; hdI = hdI->next) { /* for each matrix header */
+ logbook(msg->l2, L2_LEVEL_DEBUG, "FIXME trace loop hdI=%.8lx, hI->name=\"%s\"", hdI, hdI->name);
+ if (hdI->name == NULL || strlen(hdI->name) == 0 || hdI->ndata == 0)
+ continue;
+ if (hdI->ndata == 0) {
+ logbook(msg->l2, L2_LEVEL_DEBUG, "header=%s, no data", hdI->name);
+ }
+ else if(hdI->ndata == 1) { /* header data is single valued */
+ logbook(msg->l2, L2_LEVEL_DEBUG, "header=%s, data=%s", hdI->name, hdI->data.s);
+ argz_add(&msg->azHeaders, &msg->asHeaders, hdI->name);
+ argz_add(&msg->azHeaders, &msg->asHeaders, hdI->data.s);
+ }
+ else { /* header data is multi valued */
+ int i;
+ for (i = 0; i < hdI->ndata; i++) {
+ logbook(msg->l2, L2_LEVEL_DEBUG, "header=%s[%d], data=%s", hdI->name, i, hdI->data.m[i]);
+ argz_add(&msg->azHeaders, &msg->asHeaders, hdI->name);
+ argz_add(&msg->azHeaders, &msg->asHeaders, hdI->data.m[i]);
+ }
+ }
+ }
+ }
+ catch(ex) {
+ rethrow;
+ }
+}
+
+void headerrewrite(lmtp2nntp_t *ctx)
+{
+ headerrule_t *hrI;
+ headerdata_t *hdI, *hdNew;
+ regex_ctx_t *regex_ctx;
+#define OVECSIZE 30
+ int ovec[OVECSIZE];
+ var_rc_t rc; char *cp; //FIXME what a bad name, it's not the returncode of this function
+
+ /* short circuit in case no headerrules were set up */
+ if (ctx->option_firstheaderrule == NULL)
+ return;
+
+ { //FIXME debug code block
+ int i;
+ headerrule_t *hrD;
+ headerdata_t *hdD;
+
+ logbook(ctx->l2, L2_LEVEL_DEBUG, "FIXME trace ---------- headerrewrite() ----------");
+ for (hrD = ctx->option_firstheaderrule; hrD != NULL; hrD = hrD->next)
+ logbook(ctx->l2, L2_LEVEL_DEBUG, "hrD->header=%s", hrD->header);
+ for (hdD = ctx->msg->hdFirst; hdD != NULL; hdD = hdD->next) {
+ if (hdD->ndata == 0)
+ logbook(ctx->l2, L2_LEVEL_DEBUG, "hdD->name=%s: (NO DATA)", hdD->name);
+ if (hdD->ndata == 1)
+ logbook(ctx->l2, L2_LEVEL_DEBUG, "hdD->name:hdD->data.s %s %s", hdD->name, hdD->data.s);
+ if (hdD->ndata > 1)
+ for (i = 0; i < hdD->ndata; i++)
+ logbook(ctx->l2, L2_LEVEL_DEBUG, "hdD->name:hdD->data.m[%d] %s %s", i, hdD->name, hdD->data.m[i]);
+ }
+ }
+
+ regex_ctx = (regex_ctx_t *)mallocex(sizeof(regex_ctx_t));
+ regex_ctx->nMatch = 0;
+ regex_ctx->acpMatch = NULL;
+ regex_ctx->l2_env = ctx->l2_env;
+ regex_ctx->l2 = ctx->l2;
+ if ((rc = var_config(ctx->config_varregex, VAR_CONFIG_CB_VALUE, regex_lookup, regex_ctx)) != VAR_OK) {
+ logbook(ctx->l2, L2_LEVEL_ERROR, "configure regex callback failed with %s (%d)", var_strerror(ctx->config_varctx, rc, &cp) == VAR_OK ? cp : "Unknown Error", rc);
+ throw(0,0,0);
+ }
+ if ((rc = var_config(ctx->config_varregex, VAR_CONFIG_CB_OPERATION, operate_cb, NULL)) != VAR_OK) {
+ logbook(ctx->l2, L2_LEVEL_ERROR, "configure operate callback failed with %s (%d)", var_strerror(ctx->config_varctx, rc, &cp) == VAR_OK ? cp : "Unknown Error", rc);
+ throw(0,0,0);
+ }
+ for (hrI = ctx->option_firstheaderrule; hrI != NULL; hrI = hrI->next) { /* for each rule */
+ { //FIXME debug code block
+ int i;
+ headerrule_t *hrD;
+ headerdata_t *hdD;
+
+ logbook(ctx->l2, L2_LEVEL_DEBUG, "FIXME trace ---------- headerrewrite() ---------- MIDDLE");
+ for (hrD = ctx->option_firstheaderrule; hrD != NULL; hrD = hrD->next)
+ logbook(ctx->l2, L2_LEVEL_DEBUG, "hrD->header=%s", hrD->header);
+ for (hdD = ctx->msg->hdFirst; hdD != NULL; hdD = hdD->next) {
+ //logbook(ctx->l2, L2_LEVEL_DEBUG, "hdD=%.8lx, hdD->name=%.8lx, hdD->data.s=%.8lx", (long)hdD, (long)&hdD->name, (long)&hdD->data.s);
+ if (hdD->ndata == 0)
+ logbook(ctx->l2, L2_LEVEL_DEBUG, "hdD->name=%s: (NO DATA)", hdD->name);
+ if (hdD->ndata == 1)
+ logbook(ctx->l2, L2_LEVEL_DEBUG, "hdD->name:hdD->data.s %s %s", hdD->name, hdD->data.s);
+ if (hdD->ndata > 1)
+ for (i = 0; i < hdD->ndata; i++)
+ logbook(ctx->l2, L2_LEVEL_DEBUG, "hdD->name:hdD->data.m[%d] %s %s", i, hdD->name, hdD->data.m[i]);
+ }
+ }
+ if (hrI->regex != NULL) {
+ logbook(ctx->l2, L2_LEVEL_DEBUG, "rule has regex %s", hrI->regex);
+ for (hdI = ctx->msg->hdFirst; hdI != NULL; hdI = hdI->next) { /* for each header */
+ if (hdI->name == NULL || strlen(hdI->name) == 0 || hdI->ndata == 0)
+ continue;
+ regex_ctx->nMatch = pcre_exec(hrI->pcreRegex, hrI->pcreExtra, hdI->name, strlen(hdI->name), 0, 0, ovec, OVECSIZE);
+ if (regex_ctx->nMatch >= 1) {
+ int i;
+ char *cp;
+ logbook(ctx->l2, L2_LEVEL_DEBUG, "regex matches, %d references", regex_ctx->nMatch);
+ pcre_get_substring_list(hdI->name, ovec, regex_ctx->nMatch, ®ex_ctx->acpMatch);
+ if (regex_ctx->acpMatch != NULL)
+ for (i = 0; i < regex_ctx->nMatch; i++)
+ logbook(ctx->l2, L2_LEVEL_DEBUG, "regex reference[%d]=\'%s\'", i, regex_ctx->acpMatch[i] == NULL ? "(UNDEFINED)" : regex_ctx->acpMatch[i]);
+ hdNew = headercreate();
+ /* expanding regex references into header name */
+ {
+ var_rc_t var_rc;
+ char *res_ptr;
+ logbook(ctx->l2, L2_LEVEL_DEBUG, "expanding regex references in headername '%s'", hrI->header);
+ if ((var_rc = var_expand(ctx->config_varregex, hrI->header, strlen(hrI->header), &res_ptr, NULL, FALSE)) != VAR_OK) {
+ logbook(ctx->l2, L2_LEVEL_ERROR, "expansion of '%s' failed: %s", hrI->header, var_strerror(ctx->config_varctx, rc, &cp) == VAR_OK ? cp : "Unknown Error", rc);
+ }
+ logbook(ctx->l2, L2_LEVEL_DEBUG, "expansion result '%s'", res_ptr);
+ if (strlen(res_ptr) == 0) {
+ logbook(ctx->l2, L2_LEVEL_DEBUG, "marking deleted - emtpy headername");
+ hdNew->name = NULL; //FIXME rename ->header to ->name
+ /*FIXME clean up data.s and data.m */
+ hdNew->ndata = 0;
+ }
+ else {
+ hdNew->name = res_ptr; //FIXME rename ->header to ->name
+ }
+ }
+ if (hrI->val == NULL) {
+ logbook(ctx->l2, L2_LEVEL_DEBUG, "marking deleted - empty headervalue before expansion");
+ /*FIXME clean up data.s and data.m */
+ hdNew->ndata = 0;
+ }
+ else {
+ /* expanding regex references into header value */
+ {
+ var_rc_t var_rc;
+ char *res_ptr;
+ logbook(ctx->l2, L2_LEVEL_DEBUG, "expanding regex references in header value '%s'", hrI->val);
+ if ((var_rc = var_expand(ctx->config_varregex, hrI->val, strlen(hrI->val), &res_ptr, NULL, FALSE)) != VAR_OK) {
+ logbook(ctx->l2, L2_LEVEL_ERROR, "expansion of '%s' failed: %s", hrI->val, var_strerror(ctx->config_varctx, rc, &cp) == VAR_OK ? cp : "Unknown Error", rc);
+ }
+ logbook(ctx->l2, L2_LEVEL_DEBUG, "expansion result '%s'", res_ptr);
+ cp = res_ptr;
+ }
+ /* expanding variables into header value */
+ if (hrI->val != NULL) {
+ var_rc_t var_rc;
+ char *res_ptr;
+ logbook(ctx->l2, L2_LEVEL_DEBUG, "expanding variables in header value '%s'", hrI->val);
+ if ((var_rc = var_expand(ctx->config_varctx, cp, strlen(cp), &res_ptr, NULL, FALSE)) != VAR_OK) {
+ logbook(ctx->l2, L2_LEVEL_ERROR, "expansion of '%s' failed: %s", cp, var_strerror(ctx->config_varctx, rc, &cp) == VAR_OK ? cp : "Unknown Error", rc);
+ }
+ logbook(ctx->l2, L2_LEVEL_DEBUG, "expansion result '%s'", res_ptr);
+ if (strlen(res_ptr) == 0) {
+ logbook(ctx->l2, L2_LEVEL_DEBUG, "marking deleted - empty headervalue after expansion");
+ /*FIXME clean up data.s and data.m */
+ hdNew->ndata = 0;
+ }
+ else {
+ 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 {
+ logbook(ctx->l2, L2_LEVEL_DEBUG, "rule has no regex but static header %s", hrI->header);
+ hdNew = headercreate();
+ hdNew->name = strdupex(hrI->header); //FIXME rename ->header to ->name
+ if (hrI->val == NULL) {
+ logbook(ctx->l2, L2_LEVEL_DEBUG, "marking deleted");
+ /*FIXME clean up data.s and data.m */
+ hdNew->ndata = 0;
+ }
+ else {
+ /*FIXME clean up data.m */
+ /* expanding variables into header value */
+ var_rc_t var_rc;
+ char *res_ptr;
+ logbook(ctx->l2, L2_LEVEL_DEBUG, "expanding variables in header value '%s'", hrI->val);
+ if ((var_rc = var_expand(ctx->config_varctx, hrI->val, strlen(hrI->val), &res_ptr, NULL, FALSE)) != VAR_OK) {
+ logbook(ctx->l2, L2_LEVEL_ERROR, "expansion of '%s' failed: %s", hrI->val, var_strerror(ctx->config_varctx, rc, &cp) == VAR_OK ? cp : "Unknown Error", rc);
+ }
+ logbook(ctx->l2, L2_LEVEL_DEBUG, "expansion result '%s'", res_ptr);
+ if (strlen(res_ptr) == 0) {
+ logbook(ctx->l2, L2_LEVEL_DEBUG, "marking deleted - empty headervalue after expansion");
+ /*FIXME clean up data.s and data.m */
+ hdNew->ndata = 0;
+ }
+ else {
+ hdNew->data.s = res_ptr;
+ hdNew->ndata = 1;
+ }
+ }
+ for (hdI = ctx->msg->hdFirst; hdI != NULL; hdI = hdI->next) { /* for each header */
+ if (hdI->name == NULL || strlen(hdI->name) == 0)
+ continue;
+ logbook(ctx->l2, L2_LEVEL_DEBUG, "hrI->header=%s, hdI->name=%s", hrI->header, hdI->name);
+ if (strcasecmp(hrI->header, hdI->name) == 0)
+ break;
+ }
+ if (hdI != NULL) {
+ logbook(ctx->l2, L2_LEVEL_DEBUG, "replacing header %s", hrI->header);
+ headerreplace(hdI, hdNew);
+ if (hdNew->prev == NULL) {
+ logbook(ctx->l2, L2_LEVEL_DEBUG, "FIXME trace #1");
+ ctx->msg->hdFirst = hdNew;
+ }
+ }
+ else {
+ logbook(ctx->l2, L2_LEVEL_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;
+ headerrule_t *hrD;
+ headerdata_t *hdD;
+
+ logbook(ctx->l2, L2_LEVEL_DEBUG, "FIXME trace ---------- headerrewrite() ---------- FINISH");
+ for (hrD = ctx->option_firstheaderrule; hrD != NULL; hrD = hrD->next)
+ logbook(ctx->l2, L2_LEVEL_DEBUG, "hrD->header=%s", hrD->header);
+ for (hdD = ctx->msg->hdFirst; hdD != NULL; hdD = hdD->next) {
+ if (hdD->ndata == 0)
+ logbook(ctx->l2, L2_LEVEL_DEBUG, "hdD->name=%s: (NO DATA)", hdD->name);
+ if (hdD->ndata == 1)
+ logbook(ctx->l2, L2_LEVEL_DEBUG, "hdD->name:hdD->data.s %s %s", hdD->name, hdD->data.s);
+ if (hdD->ndata > 1)
+ for (i = 0; i < hdD->ndata; i++)
+ logbook(ctx->l2, L2_LEVEL_DEBUG, "hdD->name:hdD->data.m[%d] %s %s", i, hdD->name, hdD->data.m[i]);
+ }
+ }
+}
|