{ "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 },
static uschar *
fn_queue_size(void)
{
-struct sockaddr_un sun = {.sun_family = AF_UNIX};
+struct sockaddr_un sa_un = {.sun_family = AF_UNIX};
uschar buf[16];
int fd;
ssize_t len;
const uschar * where;
+#ifndef EXIM_HAVE_ABSTRACT_UNIX_SOCKETS
+uschar * sname;
+#endif
+fd_set fds;
+struct timeval tv;
if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
{
return NULL;
}
-#define ABSTRACT_CLIENT
-#ifdef ABSTRACT_CLIENT
-sun.sun_path[0] = 0; /* Abstract local socket addr - Linux-specific? */
+#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(sun.sun_path+1, sizeof(sun.sun_path)-1, "exim_%d", getpid());
+ + snprintf(sa_un.sun_path+1, sizeof(sa_un.sun_path)-1, "exim_%d", getpid());
#else
+sname = string_sprintf("%s/p_%d", spool_directory, getpid());
len = offsetof(struct sockaddr_un, sun_path)
- + snprintf(sun.sun_path, sizeof(sun.sun_path), "%s/p_%d",
- spool_directory, getpid());
+ + snprintf(sa_un.sun_path, sizeof(sa_un.sun_path), "%s", sname);
#endif
-if (bind(fd, (const struct sockaddr *)&sun, len) < 0)
+if (bind(fd, (const struct sockaddr *)&sa_un, len) < 0)
{ where = US"bind"; goto bad; }
#ifdef notdef
-debug_printf("local%s '%s'\n", *sun.sun_path ? "" : " abstract",
- sun.sun_path+ (*sun.sun_path ? 0 : 1));
+debug_printf("local addr '%s%s'\n",
+ *sa_un.sun_path ? "" : "@",
+ sa_un.sun_path + (*sa_un.sun_path ? 0 : 1));
#endif
-sun.sun_path[0] = 0; /* Abstract local socket addr - Linux-specific? */
+#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(sun.sun_path+1, sizeof(sun.sun_path)-1, "%s", NOTIFIER_SOCKET_NAME);
+ + snprintf(sa_un.sun_path+1, sizeof(sa_un.sun_path)-1, "%s", NOTIFIER_SOCKET_NAME);
+#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);
+#endif
-if (connect(fd, (const struct sockaddr *)&sun, len) < 0)
- { where = US"connect"; goto bad; }
+if (connect(fd, (const struct sockaddr *)&sa_un, len) < 0)
+ { 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
+Uunlink(sname);
+#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));
{
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];
if (sigalrm_seen)
{
- yield->ptr = save_ptr;
+ if (yield) yield->ptr = save_ptr;
expand_string_message = US "socket read timed out";
goto SOCK_FAIL;
}
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;
}