* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) University of Cambridge 1995 - 2015 */
+/* Copyright (c) University of Cambridge 1995 - 2016 */
/* See the file NOTICE for conditions of use and distribution. */
US"hash",
US"hmac",
US"if",
-#ifdef EXPERIMENTAL_INTERNATIONAL
+#ifdef SUPPORT_I18N
US"imapfolder",
#endif
US"length",
EITEM_HASH,
EITEM_HMAC,
EITEM_IF,
-#ifdef EXPERIMENTAL_INTERNATIONAL
+#ifdef SUPPORT_I18N
EITEM_IMAPFOLDER,
#endif
EITEM_LENGTH,
US"reverse_ip",
US"time_eval",
US"time_interval"
-#ifdef EXPERIMENTAL_INTERNATIONAL
+#ifdef SUPPORT_I18N
,US"utf8_domain_from_alabel",
US"utf8_domain_to_alabel",
US"utf8_localpart_from_alabel",
EOP_REVERSE_IP,
EOP_TIME_EVAL,
EOP_TIME_INTERVAL
-#ifdef EXPERIMENTAL_INTERNATIONAL
+#ifdef SUPPORT_I18N
,EOP_UTF8_DOMAIN_FROM_ALABEL,
EOP_UTF8_DOMAIN_TO_ALABEL,
EOP_UTF8_LOCALPART_FROM_ALABEL,
US"addresses",
US"base62",
US"base62d",
+ US"base64",
+ US"base64d",
US"domain",
US"escape",
US"eval",
EOP_ADDRESSES,
EOP_BASE62,
EOP_BASE62D,
+ EOP_BASE64,
+ EOP_BASE64D,
EOP_DOMAIN,
EOP_ESCAPE,
EOP_EVAL,
{ "dcc_header", vtype_stringptr, &dcc_header },
{ "dcc_result", vtype_stringptr, &dcc_result },
#endif
-#ifdef WITH_OLD_DEMIME
- { "demime_errorlevel", vtype_int, &demime_errorlevel },
- { "demime_reason", vtype_stringptr, &demime_reason },
-#endif
#ifndef DISABLE_DKIM
{ "dkim_algo", vtype_dkim, (void *)DKIM_ALGO },
{ "dkim_bodylength", vtype_dkim, (void *)DKIM_BODYLENGTH },
{ "dnslist_value", vtype_stringptr, &dnslist_value },
{ "domain", vtype_stringptr, &deliver_domain },
{ "domain_data", vtype_stringptr, &deliver_domain_data },
-#ifdef EXPERIMENTAL_EVENT
+#ifndef DISABLE_EVENT
{ "event_data", vtype_stringptr, &event_data },
/*XXX want to use generic vars for as many of these as possible*/
{ "exim_path", vtype_stringptr, &exim_path },
{ "exim_uid", vtype_uid, &exim_uid },
{ "exim_version", vtype_stringptr, &version_string },
-#ifdef WITH_OLD_DEMIME
- { "found_extension", vtype_stringptr, &found_extension },
-#endif
{ "headers_added", vtype_string_func, &fn_hdrs_added },
{ "home", vtype_stringptr, &deliver_home },
{ "host", vtype_stringptr, &deliver_host },
{ "host_lookup_deferred",vtype_int, &host_lookup_deferred },
{ "host_lookup_failed", vtype_int, &host_lookup_failed },
{ "host_port", vtype_int, &deliver_host_port },
+ { "initial_cwd", vtype_stringptr, &initial_cwd },
{ "inode", vtype_ino, &deliver_inode },
{ "interface_address", vtype_stringptr, &interface_address },
{ "interface_port", vtype_int, &interface_port },
{ "message_id", vtype_stringptr, &message_id },
{ "message_linecount", vtype_int, &message_linecount },
{ "message_size", vtype_int, &message_size },
-#ifdef EXPERIMENTAL_INTERNATIONAL
+#ifdef SUPPORT_I18N
{ "message_smtputf8", vtype_bool, &message_smtputf8 },
#endif
#ifdef WITH_CONTENT_SCAN
{ "prdr_requested", vtype_bool, &prdr_requested },
#endif
{ "primary_hostname", vtype_stringptr, &primary_hostname },
-#ifdef SUPPORT_PROXY
- { "proxy_host_address", vtype_stringptr, &proxy_host_address },
- { "proxy_host_port", vtype_int, &proxy_host_port },
+#if defined(SUPPORT_PROXY) || defined(SUPPORT_SOCKS)
+ { "proxy_external_address",vtype_stringptr, &proxy_external_address },
+ { "proxy_external_port", vtype_int, &proxy_external_port },
+ { "proxy_local_address", vtype_stringptr, &proxy_local_address },
+ { "proxy_local_port", vtype_int, &proxy_local_port },
{ "proxy_session", vtype_bool, &proxy_session },
- { "proxy_target_address",vtype_stringptr, &proxy_target_address },
- { "proxy_target_port", vtype_int, &proxy_target_port },
#endif
{ "prvscheck_address", vtype_stringptr, &prvscheck_address },
{ "prvscheck_keynum", vtype_stringptr, &prvscheck_keynum },
Returns: a pointer to the character after the last digit
*/
+/*XXX consider expanding to int_eximarith_t. But the test for
+"overbig numbers" in 0002 still needs to overflow it. */
static uschar *
read_number(int *n, uschar *s)
{
tree_node *node =
tree_search((name[4] == 'c')? acl_var_c : acl_var_m, name + 4);
- return (node == NULL)? (strict_acl_vars? NULL : US"") : node->data.ptr;
+ return node ? node->data.ptr : strict_acl_vars ? NULL : US"";
}
/* Handle $auth<n> variables. */
switch (vp->type)
{
case vtype_filter_int:
- if (!filter_running) return NULL;
- /* Fall through */
- /* VVVVVVVVVVVV */
+ if (!filter_running) return NULL;
+ /* Fall through */
+ /* VVVVVVVVVVVV */
case vtype_int:
- sprintf(CS var_buffer, "%d", *(int *)(val)); /* Integer */
- return var_buffer;
+ sprintf(CS var_buffer, "%d", *(int *)(val)); /* Integer */
+ return var_buffer;
case vtype_ino:
- sprintf(CS var_buffer, "%ld", (long int)(*(ino_t *)(val))); /* Inode */
- return var_buffer;
+ sprintf(CS var_buffer, "%ld", (long int)(*(ino_t *)(val))); /* Inode */
+ return var_buffer;
case vtype_gid:
- sprintf(CS var_buffer, "%ld", (long int)(*(gid_t *)(val))); /* gid */
- return var_buffer;
+ sprintf(CS var_buffer, "%ld", (long int)(*(gid_t *)(val))); /* gid */
+ return var_buffer;
case vtype_uid:
- sprintf(CS var_buffer, "%ld", (long int)(*(uid_t *)(val))); /* uid */
- return var_buffer;
+ sprintf(CS var_buffer, "%ld", (long int)(*(uid_t *)(val))); /* uid */
+ return var_buffer;
case vtype_bool:
- sprintf(CS var_buffer, "%s", *(BOOL *)(val) ? "yes" : "no"); /* bool */
- return var_buffer;
+ sprintf(CS var_buffer, "%s", *(BOOL *)(val) ? "yes" : "no"); /* bool */
+ return var_buffer;
case vtype_stringptr: /* Pointer to string */
- s = *((uschar **)(val));
- return (s == NULL)? US"" : s;
+ return (s = *((uschar **)(val))) ? s : US"";
case vtype_pid:
- sprintf(CS var_buffer, "%d", (int)getpid()); /* pid */
- return var_buffer;
+ sprintf(CS var_buffer, "%d", (int)getpid()); /* pid */
+ return var_buffer;
case vtype_load_avg:
- sprintf(CS var_buffer, "%d", OS_GETLOADAVG()); /* load_average */
- return var_buffer;
+ sprintf(CS var_buffer, "%d", OS_GETLOADAVG()); /* load_average */
+ return var_buffer;
case vtype_host_lookup: /* Lookup if not done so */
- if (sender_host_name == NULL && sender_host_address != NULL &&
- !host_lookup_failed && host_name_lookup() == OK)
- host_build_sender_fullhost();
- return (sender_host_name == NULL)? US"" : sender_host_name;
+ if (sender_host_name == NULL && sender_host_address != NULL &&
+ !host_lookup_failed && host_name_lookup() == OK)
+ host_build_sender_fullhost();
+ return (sender_host_name == NULL)? US"" : sender_host_name;
case vtype_localpart: /* Get local part from address */
- s = *((uschar **)(val));
- if (s == NULL) return US"";
- domain = Ustrrchr(s, '@');
- if (domain == NULL) return s;
- if (domain - s > sizeof(var_buffer) - 1)
- log_write(0, LOG_MAIN|LOG_PANIC_DIE, "local part longer than " SIZE_T_FMT
- " in string expansion", sizeof(var_buffer));
- Ustrncpy(var_buffer, s, domain - s);
- var_buffer[domain - s] = 0;
- return var_buffer;
+ s = *((uschar **)(val));
+ if (s == NULL) return US"";
+ domain = Ustrrchr(s, '@');
+ if (domain == NULL) return s;
+ if (domain - s > sizeof(var_buffer) - 1)
+ log_write(0, LOG_MAIN|LOG_PANIC_DIE, "local part longer than " SIZE_T_FMT
+ " in string expansion", sizeof(var_buffer));
+ Ustrncpy(var_buffer, s, domain - s);
+ var_buffer[domain - s] = 0;
+ return var_buffer;
case vtype_domain: /* Get domain from address */
- s = *((uschar **)(val));
- if (s == NULL) return US"";
- domain = Ustrrchr(s, '@');
- return (domain == NULL)? US"" : domain + 1;
+ s = *((uschar **)(val));
+ if (s == NULL) return US"";
+ domain = Ustrrchr(s, '@');
+ return (domain == NULL)? US"" : domain + 1;
case vtype_msgheaders:
- return find_header(NULL, exists_only, newsize, FALSE, NULL);
+ return find_header(NULL, exists_only, newsize, FALSE, NULL);
case vtype_msgheaders_raw:
- return find_header(NULL, exists_only, newsize, TRUE, NULL);
+ return find_header(NULL, exists_only, newsize, TRUE, NULL);
case vtype_msgbody: /* Pointer to msgbody string */
case vtype_msgbody_end: /* Ditto, the end of the msg */
- ss = (uschar **)(val);
- if (*ss == NULL && deliver_datafile >= 0) /* Read body when needed */
- {
- uschar *body;
- off_t start_offset = SPOOL_DATA_START_OFFSET;
- int len = message_body_visible;
- if (len > message_size) len = message_size;
- *ss = body = store_malloc(len+1);
- body[0] = 0;
- if (vp->type == vtype_msgbody_end)
+ ss = (uschar **)(val);
+ if (*ss == NULL && deliver_datafile >= 0) /* Read body when needed */
{
- struct stat statbuf;
- if (fstat(deliver_datafile, &statbuf) == 0)
+ uschar *body;
+ off_t start_offset = SPOOL_DATA_START_OFFSET;
+ int len = message_body_visible;
+ if (len > message_size) len = message_size;
+ *ss = body = store_malloc(len+1);
+ body[0] = 0;
+ if (vp->type == vtype_msgbody_end)
{
- start_offset = statbuf.st_size - len;
- if (start_offset < SPOOL_DATA_START_OFFSET)
- start_offset = SPOOL_DATA_START_OFFSET;
- }
- }
- lseek(deliver_datafile, start_offset, SEEK_SET);
- len = read(deliver_datafile, body, len);
- if (len > 0)
- {
- body[len] = 0;
- if (message_body_newlines) /* Separate loops for efficiency */
- {
- while (len > 0)
- { if (body[--len] == 0) body[len] = ' '; }
+ struct stat statbuf;
+ if (fstat(deliver_datafile, &statbuf) == 0)
+ {
+ start_offset = statbuf.st_size - len;
+ if (start_offset < SPOOL_DATA_START_OFFSET)
+ start_offset = SPOOL_DATA_START_OFFSET;
+ }
}
- else
+ if (lseek(deliver_datafile, start_offset, SEEK_SET) < 0)
+ log_write(0, LOG_MAIN|LOG_PANIC_DIE, "deliver_datafile lseek: %s",
+ strerror(errno));
+ len = read(deliver_datafile, body, len);
+ if (len > 0)
{
- while (len > 0)
- { if (body[--len] == '\n' || body[len] == 0) body[len] = ' '; }
+ body[len] = 0;
+ if (message_body_newlines) /* Separate loops for efficiency */
+ while (len > 0)
+ { if (body[--len] == 0) body[len] = ' '; }
+ else
+ while (len > 0)
+ { if (body[--len] == '\n' || body[len] == 0) body[len] = ' '; }
}
}
- }
- return (*ss == NULL)? US"" : *ss;
+ return (*ss == NULL)? US"" : *ss;
case vtype_todbsdin: /* BSD inbox time of day */
- return tod_stamp(tod_bsdin);
+ return tod_stamp(tod_bsdin);
case vtype_tode: /* Unix epoch time of day */
- return tod_stamp(tod_epoch);
+ return tod_stamp(tod_epoch);
case vtype_todel: /* Unix epoch/usec time of day */
- return tod_stamp(tod_epoch_l);
+ return tod_stamp(tod_epoch_l);
case vtype_todf: /* Full time of day */
- return tod_stamp(tod_full);
+ return tod_stamp(tod_full);
case vtype_todl: /* Log format time of day */
- return tod_stamp(tod_log_bare); /* (without timezone) */
+ return tod_stamp(tod_log_bare); /* (without timezone) */
case vtype_todzone: /* Time zone offset only */
- return tod_stamp(tod_zone);
+ return tod_stamp(tod_zone);
case vtype_todzulu: /* Zulu time */
- return tod_stamp(tod_zulu);
+ return tod_stamp(tod_zulu);
case vtype_todlf: /* Log file datestamp tod */
- return tod_stamp(tod_log_datestamp_daily);
+ return tod_stamp(tod_log_datestamp_daily);
case vtype_reply: /* Get reply address */
- s = find_header(US"reply-to:", exists_only, newsize, TRUE,
- headers_charset);
- if (s != NULL) while (isspace(*s)) s++;
- if (s == NULL || *s == 0)
- {
- *newsize = 0; /* For the *s==0 case */
- s = find_header(US"from:", exists_only, newsize, TRUE, headers_charset);
- }
- if (s != NULL)
- {
- uschar *t;
- while (isspace(*s)) s++;
- for (t = s; *t != 0; t++) if (*t == '\n') *t = ' ';
- while (t > s && isspace(t[-1])) t--;
- *t = 0;
- }
- return (s == NULL)? US"" : s;
+ s = find_header(US"reply-to:", exists_only, newsize, TRUE,
+ headers_charset);
+ if (s != NULL) while (isspace(*s)) s++;
+ if (s == NULL || *s == 0)
+ {
+ *newsize = 0; /* For the *s==0 case */
+ s = find_header(US"from:", exists_only, newsize, TRUE, headers_charset);
+ }
+ if (s != NULL)
+ {
+ uschar *t;
+ while (isspace(*s)) s++;
+ for (t = s; *t != 0; t++) if (*t == '\n') *t = ' ';
+ while (t > s && isspace(t[-1])) t--;
+ *t = 0;
+ }
+ return (s == NULL)? US"" : s;
case vtype_string_func:
{
return var_buffer;
case vtype_cert:
- return *(void **)val ? US"<cert>" : US"";
+ return *(void **)val ? US"<cert>" : US"";
- #ifndef DISABLE_DKIM
+#ifndef DISABLE_DKIM
case vtype_dkim:
- return dkim_exim_expand_query((int)(long)val);
- #endif
+ return dkim_exim_expand_query((int)(long)val);
+#endif
}
Sub array will be corrupted on return.
Returns: OK access is granted by an ACCEPT verb
- DISCARD access is granted by a DISCARD verb
+ DISCARD access is (apparently) granted by a DISCARD verb
FAIL access is denied
FAIL_DROP access is denied; drop the connection
DEFER can't tell at the moment
case 3: return NULL;
}
- *resetok = FALSE;
+ *resetok = FALSE; /* eval_acl() might allocate; do not reclaim */
if (yield != NULL) switch(eval_acl(sub, nelem(sub), &user_msg))
{
case OK:
case DEFER:
expand_string_forcedfail = TRUE;
+ /*FALLTHROUGH*/
default:
expand_string_message = string_sprintf("error from acl \"%s\"", sub[0]);
return NULL;
if (sublen == 24)
{
- uschar *coded = auth_b64encode((uschar *)digest, 16);
+ uschar *coded = b64encode((uschar *)digest, 16);
DEBUG(D_auth) debug_printf("crypteq: using MD5+B64 hashing\n"
" subject=%s\n crypted=%s\n", coded, sub[1]+5);
tempcond = (Ustrcmp(coded, sub[1]+5) == 0);
if (sublen == 28)
{
- uschar *coded = auth_b64encode((uschar *)digest, 20);
+ uschar *coded = b64encode((uschar *)digest, 20);
DEBUG(D_auth) debug_printf("crypteq: using SHA1+B64 hashing\n"
" subject=%s\n crypted=%s\n", coded, sub[1]+6);
tempcond = (Ustrcmp(coded, sub[1]+6) == 0);
#define XSTR(s) STR(s)
DEBUG(D_auth) debug_printf("crypteq: using %s()\n"
" subject=%s\n crypted=%s\n",
- (which == 0)? XSTR(DEFAULT_CRYPT) : (which == 1)? "crypt" : "crypt16",
+ which == 0 ? XSTR(DEFAULT_CRYPT) : which == 1 ? "crypt" : "crypt16",
coded, sub[1]);
#undef STR
#undef XSTR
salt), force failure. Otherwise we get false positives: with an empty
string the yield of crypt() is an empty string! */
- tempcond = (Ustrlen(sub[1]) < 2)? FALSE :
- (Ustrcmp(coded, sub[1]) == 0);
+ if (coded)
+ tempcond = Ustrlen(sub[1]) < 2 ? FALSE : Ustrcmp(coded, sub[1]) == 0;
+ else if (errno == EINVAL)
+ tempcond = FALSE;
+ else
+ {
+ expand_string_message = string_sprintf("crypt error: %s\n",
+ US strerror(errno));
+ return NULL;
+ }
}
break;
#endif /* SUPPORT_CRYPTEQ */
yieldptr points to the output string pointer
sizeptr points to the output string size
ptrptr points to the output string pointer
- type "lookup" or "if" or "extract" or "run", for error message
+ type "lookup", "if", "extract", "run", "env", "listextract" or
+ "certextract" for error message
resetok if not NULL, pointer to flag - write FALSE if unsafe to reset
the store.
}
else
{
- if (yes && lookup_value != NULL)
+ if (yes && lookup_value)
*yieldptr = string_cat(*yieldptr, sizeptr, ptrptr, lookup_value,
Ustrlen(lookup_value));
lookup_value = save_lookup;
if (yes)
*yieldptr = string_cat(*yieldptr, sizeptr, ptrptr, sub1, Ustrlen(sub1));
-/* If this is called from a lookup or an extract, we want to restore $value to
-what it was at the start of the item, so that it has this value during the
-second string expansion. For the call from "if" or "run" to this function,
-save_lookup is set to lookup_value, so that this statement does nothing. */
+/* If this is called from a lookup/env or a (cert)extract, we want to restore
+$value to what it was at the start of the item, so that it has this value
+during the second string expansion. For the call from "if" or "run" to this
+function, save_lookup is set to lookup_value, so that this statement does
+nothing. */
lookup_value = save_lookup;
return NULL;
hash_source = string_cat(NULL,&size,&offset,key_num,1);
-string_cat(hash_source,&size,&offset,daystamp,3);
-string_cat(hash_source,&size,&offset,address,Ustrlen(address));
+hash_source = string_cat(hash_source,&size,&offset,daystamp,3);
+hash_source = string_cat(hash_source,&size,&offset,address,Ustrlen(address));
hash_source[offset] = '\0';
DEBUG(D_expand) debug_printf("prvs: hash source is '%s'\n", hash_source);
* Join a file onto the output string *
*************************************************/
-/* This is used for readfile and after a run expansion. It joins the contents
-of a file onto the output string, globally replacing newlines with a given
-string (optionally). The file is closed at the end.
+/* This is used for readfile/readsock and after a run expansion.
+It joins the contents of a file onto the output string, globally replacing
+newlines with a given string (optionally).
Arguments:
f the FILE
static uschar *
cat_file(FILE *f, uschar *yield, int *sizep, int *ptrp, uschar *eol)
{
-int eollen;
+int eollen = eol ? Ustrlen(eol) : 0;
uschar buffer[1024];
-eollen = (eol == NULL)? 0 : Ustrlen(eol);
-
-while (Ufgets(buffer, sizeof(buffer), f) != NULL)
+while (Ufgets(buffer, sizeof(buffer), f))
{
int len = Ustrlen(buffer);
- if (eol != NULL && buffer[len-1] == '\n') len--;
+ if (eol && buffer[len-1] == '\n') len--;
yield = string_cat(yield, sizep, ptrp, buffer, len);
if (buffer[len] != 0)
yield = string_cat(yield, sizep, ptrp, eol, eollen);
}
-if (yield != NULL) yield[*ptrp] = 0;
+if (yield) yield[*ptrp] = 0;
return yield;
}
{
uschar *s = *sptr;
int_eximarith_t x = eval_op_mult(&s, decimal, error);
-if (*error == NULL)
+if (!*error)
{
while (*s == '+' || *s == '-')
{
int op = *s++;
int_eximarith_t y = eval_op_mult(&s, decimal, error);
- if (*error != NULL) break;
+ if (*error) break;
+ if ( (x >= EXIM_ARITH_MAX/2 && x >= EXIM_ARITH_MAX/2)
+ || (x <= -(EXIM_ARITH_MAX/2) && y <= -(EXIM_ARITH_MAX/2)))
+ { /* over-conservative check */
+ *error = op == '+'
+ ? US"overflow in sum" : US"overflow in difference";
+ break;
+ }
if (op == '+') x += y; else x -= y;
}
}
/* Variable */
- else
+ else if (!(value = find_variable(name, FALSE, skipping, &newsize)))
{
- value = find_variable(name, FALSE, skipping, &newsize);
- if (value == NULL)
- {
- expand_string_message =
- string_sprintf("unknown variable name \"%s\"", name);
- check_variable_error_message(name);
- goto EXPAND_FAILED;
- }
+ expand_string_message =
+ string_sprintf("unknown variable name \"%s\"", name);
+ check_variable_error_message(name);
+ goto EXPAND_FAILED;
}
/* If the data is known to be in a new buffer, newsize will be set to the
case DEFER:
expand_string_forcedfail = TRUE;
+ /*FALLTHROUGH*/
default:
expand_string_message = string_sprintf("error from acl \"%s\"", sub[0]);
goto EXPAND_FAILED;
continue;
}
-#ifdef EXPERIMENTAL_INTERNATIONAL
+#ifdef SUPPORT_I18N
case EITEM_IMAPFOLDER:
{ /* ${imapfolder {name}{sep]{specials}} */
uschar *sub_arg[3];
const uschar **argv;
pid_t pid;
int fd_in, fd_out;
- int lsize = 0;
- int lptr = 0;
+ int lsize = 0, lptr = 0;
if ((expand_forbid & RDO_RUN) != 0)
{
NULL, /* no transporting address */
US"${run} expansion", /* for error messages */
&expand_string_message)) /* where to put error message */
- {
goto EXPAND_FAILED;
- }
/* Create the child process, making it a group leader. */
- pid = child_open(USS argv, NULL, 0077, &fd_in, &fd_out, TRUE);
-
- if (pid < 0)
+ if ((pid = child_open(USS argv, NULL, 0077, &fd_in, &fd_out, TRUE)) < 0)
{
expand_string_message =
string_sprintf("couldn't create child process: %s", strerror(errno));
/* Read the pipe to get the command's output into $value (which is kept
in lookup_value). Read during execution, so that if the output exceeds
- the OS pipe buffer limit, we don't block forever. */
+ the OS pipe buffer limit, we don't block forever. Remember to not release
+ memory just allocated for $value. */
+ resetok = FALSE;
f = fdopen(fd_out, "rb");
sigalrm_seen = FALSE;
alarm(60);
- lookup_value = cat_file(f, lookup_value, &lsize, &lptr, NULL);
+ lookup_value = cat_file(f, NULL, &lsize, &lptr, NULL);
alarm(0);
(void)fclose(f);
int save_expand_nmax =
save_expand_strings(save_expand_nstring, save_expand_nlength);
- /* Read the arguments */
+ /* While skipping we cannot rely on the data for expansions being
+ available (eg. $item) hence cannot decide on numeric vs. keyed.
+ Just read as many arguments as there are. */
+
+ if (skipping)
+ {
+ while (isspace(*s)) s++;
+ while (*s == '{')
+ {
+ if (!expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok))
+ goto EXPAND_FAILED; /*{*/
+ if (*s++ != '}') goto EXPAND_FAILED_CURLY;
+ while (isspace(*s)) s++;
+ }
+ if (*s != '}')
+ goto EXPAND_FAILED_CURLY;
+ }
- for (i = 0; i < j; i++)
+ else for (i = 0; i < j; i++) /* Read the proper number of arguments */
{
while (isspace(*s)) s++;
if (*s == '{') /*}*/
while (len > 0 && isspace(p[len-1])) len--;
p[len] = 0;
- if (!skipping)
+ if (*p == 0)
{
- if (*p == 0)
- {
- expand_string_message = US"first argument of \"extract\" must "
- "not be empty";
- goto EXPAND_FAILED;
- }
+ expand_string_message = US"first argument of \"extract\" must "
+ "not be empty";
+ goto EXPAND_FAILED;
+ }
- if (*p == '-')
- {
- field_number = -1;
- p++;
- }
- while (*p != 0 && isdigit(*p)) x = x * 10 + *p++ - '0';
- if (*p == 0)
- {
- field_number *= x;
- j = 3; /* Need 3 args */
- field_number_set = TRUE;
- }
+ if (*p == '-')
+ {
+ field_number = -1;
+ p++;
+ }
+ while (*p != 0 && isdigit(*p)) x = x * 10 + *p++ - '0';
+ if (*p == 0)
+ {
+ field_number *= x;
+ j = 3; /* Need 3 args */
+ field_number_set = TRUE;
}
}
}
&yield, /* output pointer */
&size, /* output size */
&ptr, /* output current point */
- US"extract", /* condition type */
+ US"listextract", /* condition type */
&resetok))
{
case 1: goto EXPAND_FAILED; /* when all is well, the */
&yield, /* output pointer */
&size, /* output size */
&ptr, /* output current point */
- US"extract", /* condition type */
+ US"certextract", /* condition type */
&resetok))
{
case 1: goto EXPAND_FAILED; /* when all is well, the */
case EOP_MD5:
case EOP_SHA1:
case EOP_SHA256:
+ case EOP_BASE64:
if (s[1] == '$')
{
const uschar * s1 = s;
}
}
- enc = auth_b64encode(sub, out - sub);
+ enc = b64encode(sub, out - sub);
yield = string_cat(yield, &size, &ptr, enc, Ustrlen(enc));
continue;
}
continue;
}
-#ifdef EXPERIMENTAL_INTERNATIONAL
+#ifdef SUPPORT_I18N
case EOP_UTF8_DOMAIN_TO_ALABEL:
{
uschar * error = NULL;
/* Convert string to base64 encoding */
case EOP_STR2B64:
+ case EOP_BASE64:
+ {
+#ifdef SUPPORT_TLS
+ uschar * s = vp && *(void **)vp->value
+ ? tls_cert_der_b64(*(void **)vp->value)
+ : b64encode(sub, Ustrlen(sub));
+#else
+ uschar * s = b64encode(sub, Ustrlen(sub));
+#endif
+ yield = string_cat(yield, &size, &ptr, s, Ustrlen(s));
+ continue;
+ }
+
+ case EOP_BASE64D:
{
- uschar *encstr = auth_b64encode(sub, Ustrlen(sub));
- yield = string_cat(yield, &size, &ptr, encstr, Ustrlen(encstr));
+ uschar * s;
+ int len = b64decode(sub, &s);
+ if (len < 0)
+ {
+ expand_string_message = string_sprintf("string \"%s\" is not "
+ "well-formed for \"%s\" operator", sub, name);
+ goto EXPAND_FAILED;
+ }
+ yield = string_cat(yield, &size, &ptr, s, Ustrlen(s));
continue;
}
if (Ustrspn(argv[i], "abcdefghijklmnopqrtsuvwxyz0123456789-.:/") ==
Ustrlen(argv[i]))
{
- #ifdef LOOKUP_LDAP
+#ifdef LOOKUP_LDAP
eldap_default_servers = argv[i];
- #endif
- #ifdef LOOKUP_MYSQL
+#endif
+#ifdef LOOKUP_MYSQL
mysql_servers = argv[i];
- #endif
- #ifdef LOOKUP_PGSQL
+#endif
+#ifdef LOOKUP_PGSQL
pgsql_servers = argv[i];
- #endif
- #ifdef EXPERIMENTAL_REDIS
+#endif
+#ifdef LOOKUP_REDIS
redis_servers = argv[i];
- #endif
+#endif
}
- #ifdef EXIM_PERL
+#ifdef EXIM_PERL
else opt_perl_startup = argv[i];
- #endif
+#endif
}
printf("Testing string expansion: debug_level = %d\n\n", debug_level);