{ "local_part", vtype_stringptr, &deliver_localpart },
{ "local_part_data", vtype_stringptr, &deliver_localpart_data },
{ "local_part_prefix", vtype_stringptr, &deliver_localpart_prefix },
+ { "local_part_prefix_v", vtype_stringptr, &deliver_localpart_prefix_v },
{ "local_part_suffix", vtype_stringptr, &deliver_localpart_suffix },
+ { "local_part_suffix_v", vtype_stringptr, &deliver_localpart_suffix_v },
{ "local_part_verified", vtype_stringptr, &deliver_localpart_verified },
#ifdef HAVE_LOCAL_SCAN
{ "local_scan_data", vtype_stringptr, &local_scan_data },
expand_getkeyed(uschar * key, const uschar * s)
{
int length = Ustrlen(key);
-while (isspace(*s)) s++;
+Uskip_whitespace(&s);
/* Loop to search for the key */
while (*s && *s != '=' && !isspace(*s)) s++;
dkeylength = s - dkey;
- while (isspace(*s)) s++;
- if (*s == '=') while (isspace((*(++s))));
+ if (Uskip_whitespace(&s) == '=') while (isspace((*(++s))));
data = string_dequote(&s);
if (length == dkeylength && strncmpic(key, dkey, length) == 0)
return data;
- while (isspace(*s)) s++;
+ Uskip_whitespace(&s);
}
return NULL;
#ifndef EXIM_HAVE_ABSTRACT_UNIX_SOCKETS
uschar * sname;
#endif
+fd_set fds;
+struct timeval tv;
if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
{
#ifdef EXIM_HAVE_ABSTRACT_UNIX_SOCKETS
sa_un.sun_path[0] = 0; /* Abstract local socket addr - Linux-specific? */
len = offsetof(struct sockaddr_un, sun_path) + 1
- + snprintf(sa_un.sun_path+1, sizeof(sa_un.sun_path)-1, "%s", NOTIFIER_SOCKET_NAME);
+ + snprintf(sa_un.sun_path+1, sizeof(sa_un.sun_path)-1, "%s",
+ expand_string(notifier_socket));
#else
len = offsetof(struct sockaddr_un, sun_path)
- + snprintf(sa_un.sun_path, sizeof(sa_un.sun_path), "%s/%s",
- spool_directory, NOTIFIER_SOCKET_NAME);
+ + snprintf(sa_un.sun_path, sizeof(sa_un.sun_path), "%s",
+ expand_string(notifier_socket));
#endif
if (connect(fd, (const struct sockaddr *)&sa_un, len) < 0)
- { where = US"connect"; goto bad; }
+ { where = US"connect"; goto bad2; }
buf[0] = NOTIFY_QUEUE_SIZE_REQ;
if (send(fd, buf, 1, 0) < 0) { where = US"send"; goto bad; }
-if ((len = recv(fd, buf, sizeof(buf), 0)) < 0) { where = US"recv"; goto bad; }
+FD_ZERO(&fds); FD_SET(fd, &fds);
+tv.tv_sec = 2; tv.tv_usec = 0;
+if (select(fd + 1, (SELECT_ARG2_TYPE *)&fds, NULL, NULL, &tv) != 1)
+ {
+ DEBUG(D_expand) debug_printf("no daemon response; using local evaluation\n");
+ len = snprintf(CS buf, sizeof(buf), "%u", queue_count_cached());
+ }
+else if ((len = recv(fd, buf, sizeof(buf), 0)) < 0)
+ { where = US"recv"; goto bad2; }
close(fd);
#ifndef EXIM_HAVE_ABSTRACT_UNIX_SOCKETS
#endif
return string_copyn(buf, len);
+bad2:
+#ifndef EXIM_HAVE_ABSTRACT_UNIX_SOCKETS
+ Uunlink(sname);
+#endif
bad:
close(fd);
DEBUG(D_expand) debug_printf(" %s: %s\n", where, strerror(errno));
s = find_header(US"reply-to:", newsize,
exists_only ? FH_EXISTS_ONLY|FH_WANT_RAW : FH_WANT_RAW,
headers_charset);
- if (s) while (isspace(*s)) s++;
+ if (s) Uskip_whitespace(&s);
if (!s || !*s)
{
*newsize = 0; /* For the *s==0 case */
if (s)
{
uschar *t;
- while (isspace(*s)) s++;
- for (t = s; *t != 0; t++) if (*t == '\n') *t = ' ';
+ Uskip_whitespace(&s);
+ for (t = s; *t; t++) if (*t == '\n') *t = ' ';
while (t > s && isspace(t[-1])) t--;
*t = 0;
}
{
const uschar *s = *sptr;
-while (isspace(*s)) s++;
+Uskip_whitespace(&s);
for (int i = 0; i < n; i++)
{
if (*s != '{')
if (!(sub[i] = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, resetok)))
return 3;
if (*s++ != '}') return 1;
- while (isspace(*s)) s++;
+ Uskip_whitespace(&s);
}
if (check_end && *s++ != '}')
{
unsigned depth = 0;
BOOL quotesmode = wrap[0] == wrap[1];
-while (isspace(*p)) p++;
-
-if (*p == *wrap)
+if (Uskip_whitespace(&p) == *wrap)
{
s = ++p;
wrap++;
int_eximarith_t n;
uschar *s = *sptr;
-while (isspace(*s)) s++;
-if (isdigit((c = *s)))
+if (isdigit((c = Uskip_whitespace(&s))))
{
int count;
(void)sscanf(CS s, (decimal? SC_EXIM_DEC "%n" : SC_EXIM_ARITH "%n"), &n, &count);
case 'm': n *= 1024*1024; s++; break;
case 'g': n *= 1024*1024*1024; s++; break;
}
- while (isspace (*s)) s++;
+ Uskip_whitespace(&s);
}
else if (c == '(')
{
{
uschar *s = *sptr;
int_eximarith_t x;
-while (isspace(*s)) s++;
+Uskip_whitespace(&s);
if (*s == '+' || *s == '-' || *s == '~')
{
int op = *s++;
int expand_setup = 0;
int nameptr = 0;
uschar *key, *filename;
- const uschar *affix;
+ const uschar * affix, * opts;
uschar *save_lookup_value = lookup_value;
int save_expand_nmax =
save_expand_strings(save_expand_nstring, save_expand_nlength);
kinds. Allow everything except space or { to appear; the actual content
is checked by search_findtype_partial. */ /*}*/
- while (*s != 0 && *s != '{' && !isspace(*s)) /*}*/
+ while (*s && *s != '{' && !isspace(*s)) /*}*/
{
if (nameptr < sizeof(name) - 1) name[nameptr++] = *s;
s++;
}
- name[nameptr] = 0;
+ name[nameptr] = '\0';
while (isspace(*s)) s++;
/* Now check for the individual search type and any partial or default
options. Only those types that are actually in the binary are valid. */
- stype = search_findtype_partial(name, &partial, &affix, &affixlen,
- &starflags);
- if (stype < 0)
+ if ((stype = search_findtype_partial(name, &partial, &affix, &affixlen,
+ &starflags, &opts)) < 0)
{
expand_string_message = search_error_message;
goto EXPAND_FAILED;
if (mac_islookup(stype, lookup_querystyle))
filename = NULL;
else
- {
- if (*filename != '/')
- {
- expand_string_message = string_sprintf(
- "absolute file name expected for \"%s\" lookup", name);
- goto EXPAND_FAILED;
- }
- while (*key != 0 && !isspace(*key)) key++;
- if (*key != 0) *key++ = 0;
- }
+ if (*filename == '/')
+ {
+ while (*key && !isspace(*key)) key++;
+ if (*key) *key++ = '\0';
+ }
+ else
+ filename = NULL;
}
/* If skipping, don't do the next bit - just lookup_value == NULL, as if
goto EXPAND_FAILED;
}
lookup_value = search_find(handle, filename, key, partial, affix,
- affixlen, starflags, &expand_setup);
+ affixlen, starflags, &expand_setup, opts);
if (f.search_find_defer)
{
expand_string_message =
{
client_conn_ctx cctx;
int timeout = 5;
- int save_ptr = yield->ptr;
+ int save_ptr = gstring_length(yield);
FILE * fp = NULL;
uschar * arg;
uschar * sub_arg[4];
uschar * item;
int sep = 0;
- item = string_nextinlist(&list, &sep, NULL, 0);
- if ((timeout = readconf_readtime(item, 0, FALSE)) < 0)
+ if ( !(item = string_nextinlist(&list, &sep, NULL, 0))
+ || !*item
+ || (timeout = readconf_readtime(item, 0, FALSE)) < 0)
{
expand_string_message = string_sprintf("bad time value %s", item);
goto EXPAND_FAILED;
if (sigalrm_seen)
{
- yield->ptr = save_ptr;
+ if (yield) yield->ptr = save_ptr;
expand_string_message = US "socket read timed out";
goto SOCK_FAIL;
}
/* Create the child process, making it a group leader. */
- if ((pid = child_open(USS argv, NULL, 0077, &fd_in, &fd_out, TRUE)) < 0)
+ if ((pid = child_open(USS argv, NULL, 0077, &fd_in, &fd_out, TRUE,
+ US"expand-run")) < 0)
{
expand_string_message =
string_sprintf("couldn't create child process: %s", strerror(errno));
case EITEM_TR:
{
- int oldptr = yield->ptr;
+ int oldptr = gstring_length(yield);
int o2m;
uschar *sub[3];
case EITEM_REDUCE:
{
int sep = 0;
- int save_ptr = yield->ptr;
+ int save_ptr = gstring_length(yield);
uschar outsep[2] = { '\0', '\0' };
const uschar *list, *expr, *temp;
uschar *save_iterate_item = iterate_item;
item of the output list, add in a space if the new item begins with the
separator character, or is an empty string. */
- if (yield->ptr != save_ptr && (temp[0] == *outsep || temp[0] == 0))
+ if ( yield && yield->ptr != save_ptr
+ && (temp[0] == *outsep || temp[0] == 0))
yield = string_catn(yield, US" ", 1);
/* Add the string in "temp" to the output list that we are building,
the redundant final separator. Even though an empty item at the end of a
list does not count, this is tidier. */
- else if (yield->ptr != save_ptr) yield->ptr--;
+ else if (yield && yield->ptr != save_ptr) yield->ptr--;
/* Restore preserved $item */
{
uschar outsep[2] = { ':', '\0' };
uschar *address, *error;
- int save_ptr = yield->ptr;
+ int save_ptr = gstring_length(yield);
int start, end, domain; /* Not really used */
while (isspace(*sub)) sub++;
if (address)
{
- if (yield->ptr != save_ptr && address[0] == *outsep)
+ if (yield && yield->ptr != save_ptr && address[0] == *outsep)
yield = string_catn(yield, US" ", 1);
for (;;)
/* If we have generated anything, remove the redundant final
separator. */
- if (yield->ptr != save_ptr) yield->ptr--;
+ if (yield && yield->ptr != save_ptr) yield->ptr--;
f.parse_allow_group = FALSE;
continue;
}
case EOP_QUOTE_LOCAL_PART:
if (!arg)
{
- BOOL needs_quote = (*sub == 0); /* TRUE for empty string */
+ BOOL needs_quote = (!*sub); /* TRUE for empty string */
uschar *t = sub - 1;
if (c == EOP_QUOTE)
case EOP_FROM_UTF8:
{
- while (*sub != 0)
+ uschar * buff = store_get(4, is_tainted(sub));
+ while (*sub)
{
int c;
- uschar buff[4];
GETUTF8INC(c, sub);
if (c > 255) c = '_';
buff[0] = c;
continue;
}
- /* replace illegal UTF-8 sequences by replacement character */
+ /* replace illegal UTF-8 sequences by replacement character */
#define UTF8_REPLACEMENT_CHAR US"?"
int complete;
uschar seq_buff[4]; /* accumulate utf-8 here */
- while (*sub != 0)
+ /* Manually track tainting, as we deal in individual chars below */
+
+ if (is_tainted(sub))
+ if (yield->s && yield->ptr)
+ gstring_rebuffer(yield);
+ else
+ yield->s = store_get(yield->size = Ustrlen(sub), TRUE);
+
+ /* Check the UTF-8, byte-by-byte */
+
+ while (*sub)
{
complete = 0;
uschar c = *sub++;
}
else /* no bytes left: new sequence */
{
- if((c & 0x80) == 0) /* 1-byte sequence, US-ASCII, keep it */
+ if(!(c & 0x80)) /* 1-byte sequence, US-ASCII, keep it */
{
yield = string_catn(yield, &c, 1);
continue;
* Eg, ${length_1:フィル} is one byte, not one character, so we expect
* ${utf8clean:${length_1:フィル}} to yield '?' */
if (bytes_left != 0)
- {
yield = string_catn(yield, UTF8_REPLACEMENT_CHAR, 1);
- }
+
continue;
}