- uschar * saved_condition;
- /* We already have a condition, we're conducting a crude hack to let
- multiple condition rules be chained together, despite storing them in
- text form. */
- *str_target = string_copy_malloc( (saved_condition = *str_target)
- ? string_sprintf("${if and{{bool_lax{%s}}{bool_lax{%s}}}}",
- saved_condition, sptr)
- : sptr);
- /* TODO(pdp): there is a memory leak here and just below
- when we set 3 or more conditions; I still don't
- understand the store mechanism enough to know
- what's the safe way to free content from an earlier store.
- AFAICT, stores stack, so freeing an early stored item also stores
- all data alloc'd after it. If we knew conditions were adjacent,
- we could survive that, but we don't. So I *think* we need to take
- another bit from opt_type to indicate "malloced"; this seems like
- quite a hack, especially for this one case. It also means that
- we can't ever reclaim the store from the *first* condition.
-
- Because we only do this once, near process start-up, I'm prepared to
- let this slide for the time being, even though it rankles. */
- }
- else if (ol->type & opt_rep_str)
- {
- uschar sep_o = Ustrncmp(name, "headers_add", 11)==0 ? '\n' : ':';
- int sep_i = -(int)sep_o;
- const uschar * list = sptr;
- uschar * s;
- gstring * list_o = NULL;
-
- if (*str_target)
- {
- list_o = string_get(Ustrlen(*str_target) + Ustrlen(sptr));
- list_o = string_cat(list_o, *str_target);
- }
-
- while ((s = string_nextinlist(&list, &sep_i, NULL, 0)))
- list_o = string_append_listele(list_o, sep_o, s);
-
- if (list_o)
- *str_target = string_copy_malloc(string_from_gstring(list_o));
- }
- else
- {
- *str_target = sptr;
- freesptr = FALSE;
- }
- break;
-
- case opt_rewrite:
- if (data_block)
- *USS (US data_block + (long int)(ol->value)) = sptr;
- else
- *USS (ol->value) = sptr;
- freesptr = FALSE;
- if (type == opt_rewrite)
- {
- int sep = 0;
- int *flagptr;
- uschar *p = sptr;
- rewrite_rule **chain;
- optionlist *ol3;
-
- sprintf(CS name2, "*%.50s_rules", name);
- ol2 = find_option(name2, oltop, last);
- sprintf(CS name2, "*%.50s_flags", name);
- ol3 = find_option(name2, oltop, last);
-
- if (ol2 == NULL || ol3 == NULL)
- log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
- "rewrite rules not available for driver");
-
- if (data_block == NULL)
- {
- chain = (rewrite_rule **)(ol2->value);
- flagptr = (int *)(ol3->value);
- }
- else
- {
- chain = (rewrite_rule **)(US data_block + (long int)(ol2->value));
- flagptr = (int *)(US data_block + (long int)(ol3->value));
- }
-
- while ((p = string_nextinlist(CUSS &sptr, &sep, big_buffer, BIG_BUFFER_SIZE)))
- {
- rewrite_rule *next = readconf_one_rewrite(p, flagptr, FALSE);
- *chain = next;
- chain = &(next->next);
- }
-
- if ((*flagptr & (rewrite_all_envelope | rewrite_smtp)) != 0)
- log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "rewrite rule specifies a "
- "non-header rewrite - not allowed at transport time -");
- }
- break;
-
- /* If it was an expanded uid, see if there is any expansion to be
- done by checking for the presence of a $ character. If there is, save it
- in the corresponding *expand_user option field. Otherwise, fall through
- to treat it as a fixed uid. Ensure mutual exclusivity of the two kinds
- of data. */
-
- case opt_expand_uid:
- sprintf(CS name2, "*expand_%.50s", name);
- ol2 = find_option(name2, oltop, last);
- if (ol2 != NULL)
- {
- uschar *ss = (Ustrchr(sptr, '$') != NULL)? sptr : NULL;
-
- if (data_block == NULL)
- *((uschar **)(ol2->value)) = ss;
- else
- *((uschar **)(US data_block + (long int)(ol2->value))) = ss;
-
- if (ss != NULL)
- {
- *(get_set_flag(name, oltop, last, data_block)) = FALSE;
- freesptr = FALSE;
- break;
- }
- }
-
- /* Look up a fixed uid, and also make use of the corresponding gid
- if a passwd entry is returned and the gid has not been set. */
-
- case opt_uid:
- if (!route_finduser(sptr, &pw, &uid))
- log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "user %s was not found", sptr);
- if (data_block == NULL)
- *((uid_t *)(ol->value)) = uid;
- else
- *((uid_t *)(US data_block + (long int)(ol->value))) = uid;
-
- /* Set the flag indicating a fixed value is set */
-
- *(get_set_flag(name, oltop, last, data_block)) = TRUE;
-
- /* Handle matching gid if we have a passwd entry: done by finding the
- same name with terminating "user" changed to "group"; if not found,
- ignore. Also ignore if the value is already set. */
-
- if (pw == NULL) break;
- Ustrcpy(name+Ustrlen(name)-4, "group");
- ol2 = find_option(name, oltop, last);
- if (ol2 != NULL && ((ol2->type & opt_mask) == opt_gid ||
- (ol2->type & opt_mask) == opt_expand_gid))
- {
- BOOL *set_flag = get_set_flag(name, oltop, last, data_block);
- if (! *set_flag)
- {
- if (data_block == NULL)
- *((gid_t *)(ol2->value)) = pw->pw_gid;
- else
- *((gid_t *)(US data_block + (long int)(ol2->value))) = pw->pw_gid;
- *set_flag = TRUE;
- }
- }
- break;
-
- /* If it was an expanded gid, see if there is any expansion to be
- done by checking for the presence of a $ character. If there is, save it
- in the corresponding *expand_user option field. Otherwise, fall through
- to treat it as a fixed gid. Ensure mutual exclusivity of the two kinds
- of data. */
-
- case opt_expand_gid:
- sprintf(CS name2, "*expand_%.50s", name);
- ol2 = find_option(name2, oltop, last);
- if (ol2 != NULL)
- {
- uschar *ss = (Ustrchr(sptr, '$') != NULL)? sptr : NULL;
+ /* If this was a string, set the variable to point to the new string,
+ and set the flag so its store isn't reclaimed. If it was a list of rewrite
+ rules, we still keep the string (for printing), and parse the rules into a
+ control block and flags word. */
+
+ case opt_stringptr:
+ str_target = data_block ? USS (US data_block + ol->v.offset)
+ : USS ol->v.value;
+ if (ol->type & opt_rep_con)
+ {
+ uschar * saved_condition;
+ /* We already have a condition, we're conducting a crude hack to let
+ multiple condition rules be chained together, despite storing them in
+ text form. */
+ *str_target = string_copy_perm( (saved_condition = *str_target)
+ ? string_sprintf("${if and{{bool_lax{%s}}{bool_lax{%s}}}}",
+ saved_condition, sptr)
+ : sptr,
+ FALSE);
+ /* TODO(pdp): there is a memory leak here and just below
+ when we set 3 or more conditions; I still don't
+ understand the store mechanism enough to know
+ what's the safe way to free content from an earlier store.
+ AFAICT, stores stack, so freeing an early stored item also stores
+ all data alloc'd after it. If we knew conditions were adjacent,
+ we could survive that, but we don't. So I *think* we need to take
+ another bit from opt_type to indicate "malloced"; this seems like
+ quite a hack, especially for this one case. It also means that
+ we can't ever reclaim the store from the *first* condition.
+
+ Because we only do this once, near process start-up, I'm prepared to
+ let this slide for the time being, even though it rankles. */
+ }
+ else if (ol->type & opt_rep_str)
+ {
+ uschar sep_o =
+ Ustrncmp(name, "headers_add", 11) == 0 ? '\n'
+ : Ustrncmp(name, "set", 3) == 0 ? ';'
+ : ':';
+ int sep_i = -(int)sep_o;
+ const uschar * list = sptr;
+ uschar * s;
+ gstring * list_o = NULL;
+
+ if (*str_target)
+ {
+ list_o = string_get(Ustrlen(*str_target) + Ustrlen(sptr));
+ list_o = string_cat(list_o, *str_target);
+ }
+
+ while ((s = string_nextinlist(&list, &sep_i, NULL, 0)))
+ list_o = string_append_listele(list_o, sep_o, s);
+
+ if (list_o)
+ *str_target = string_copy_perm(string_from_gstring(list_o), FALSE);
+ }
+ else
+ {
+ *str_target = sptr;
+ freesptr = FALSE;
+ }
+ break;