* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) University of Cambridge 1995 - 2012 */
+/* Copyright (c) University of Cambridge 1995 - 2013 */
/* See the file NOTICE for conditions of use and distribution. */
US"hmac",
US"if",
US"length",
+ US"listextract",
US"lookup",
US"map",
US"nhash",
EITEM_HMAC,
EITEM_IF,
EITEM_LENGTH,
+ EITEM_LISTEXTRACT,
EITEM_LOOKUP,
EITEM_MAP,
EITEM_NHASH,
US"str2b64",
US"strlen",
US"substr",
- US"uc" };
+ US"uc",
+ US"utf8clean" };
enum {
EOP_ADDRESS = sizeof(op_table_underscore)/sizeof(uschar *),
EOP_STR2B64,
EOP_STRLEN,
EOP_SUBSTR,
- EOP_UC };
+ EOP_UC,
+ EOP_UTF8CLEAN };
/* Table of condition names, and corresponding switch numbers. The names must
{ "parent_local_part", vtype_stringptr, &deliver_localpart_parent },
{ "pid", vtype_pid, NULL },
{ "primary_hostname", vtype_stringptr, &primary_hostname },
+#ifdef EXPERIMENTAL_PROXY
+ { "proxy_host_address", vtype_stringptr, &proxy_host_address },
+ { "proxy_host_port", vtype_int, &proxy_host_port },
+ { "proxy_session", vtype_bool, &proxy_session },
+#endif
{ "prvscheck_address", vtype_stringptr, &prvscheck_address },
{ "prvscheck_keynum", vtype_stringptr, &prvscheck_keynum },
{ "prvscheck_result", vtype_stringptr, &prvscheck_result },
}
+static uschar *
+expand_getlistele (int field, uschar *list)
+{
+uschar * tlist= list;
+int sep= 0;
+uschar dummy;
+
+if(field<0)
+{
+ for(field++; string_nextinlist(&tlist, &sep, &dummy, 1); ) field++;
+ sep= 0;
+}
+if(field==0) return NULL;
+while(--field>0 && (string_nextinlist(&list, &sep, &dummy, 1))) ;
+return string_nextinlist(&list, &sep, NULL, 0);
+}
/*************************************************
* Extract a substring from a string *
for (i = 0; i < j; i++)
{
while (isspace(*s)) s++;
- if (*s == '{')
+ if (*s == '{') /*}*/
{
sub[i] = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok);
if (sub[i] == NULL) goto EXPAND_FAILED; /*{*/
continue;
}
+ /* return the Nth item from a list */
+
+ case EITEM_LISTEXTRACT:
+ {
+ int i;
+ int field_number = 1;
+ uschar *save_lookup_value = lookup_value;
+ uschar *sub[2];
+ int save_expand_nmax =
+ save_expand_strings(save_expand_nstring, save_expand_nlength);
+
+ /* Read the field & list arguments */
+
+ for (i = 0; i < 2; i++)
+ {
+ while (isspace(*s)) s++;
+ if (*s != '{') /*}*/
+ goto EXPAND_FAILED_CURLY;
+
+ sub[i] = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok);
+ if (!sub[i]) goto EXPAND_FAILED; /*{*/
+ if (*s++ != '}') goto EXPAND_FAILED_CURLY;
+
+ /* After removal of leading and trailing white space, the first
+ argument must be numeric and nonempty. */
+
+ if (i == 0)
+ {
+ int len;
+ int x = 0;
+ uschar *p = sub[0];
+
+ while (isspace(*p)) p++;
+ sub[0] = p;
+
+ len = Ustrlen(p);
+ while (len > 0 && isspace(p[len-1])) len--;
+ p[len] = 0;
+
+ if (!*p && !skipping)
+ {
+ expand_string_message = US"first argument of \"listextract\" must "
+ "not be empty";
+ goto EXPAND_FAILED;
+ }
+
+ if (*p == '-')
+ {
+ field_number = -1;
+ p++;
+ }
+ while (*p && isdigit(*p)) x = x * 10 + *p++ - '0';
+ if (*p)
+ {
+ expand_string_message = US"first argument of \"listextract\" must "
+ "be numeric";
+ goto EXPAND_FAILED;
+ }
+ field_number *= x;
+ }
+ }
+
+ /* Extract the numbered element into $value. If
+ skipping, just pretend the extraction failed. */
+
+ lookup_value = skipping? NULL : expand_getlistele(field_number, sub[1]);
+
+ /* If no string follows, $value gets substituted; otherwise there can
+ be yes/no strings, as for lookup or if. */
+
+ switch(process_yesno(
+ skipping, /* were previously skipping */
+ lookup_value != NULL, /* success/failure indicator */
+ save_lookup_value, /* value to reset for string2 */
+ &s, /* input pointer */
+ &yield, /* output pointer */
+ &size, /* output size */
+ &ptr, /* output current point */
+ US"extract", /* condition type */
+ &resetok))
+ {
+ case 1: goto EXPAND_FAILED; /* when all is well, the */
+ case 2: goto EXPAND_FAILED_CURLY; /* returned value is 0 */
+ }
+
+ /* All done - restore numerical variables. */
+
+ restore_expand_strings(save_expand_nmax, save_expand_nstring,
+ save_expand_nlength);
+
+ continue;
+ }
+
/* Handle list operations */
case EITEM_FILTER:
continue;
}
+ /* replace illegal UTF-8 sequences by replacement character */
+
+ #define UTF8_REPLACEMENT_CHAR US"?"
+
+ case EOP_UTF8CLEAN:
+ {
+ int seq_len, index = 0;
+ int bytes_left = 0;
+ uschar seq_buff[4]; /* accumulate utf-8 here */
+
+ while (*sub != 0)
+ {
+ int complete;
+ long codepoint;
+ uschar c;
+
+ complete = 0;
+ c = *sub++;
+ if(bytes_left)
+ {
+ if ((c & 0xc0) != 0x80)
+ {
+ /* wrong continuation byte; invalidate all bytes */
+ complete = 1; /* error */
+ }
+ else
+ {
+ codepoint = (codepoint << 6) | (c & 0x3f);
+ seq_buff[index++] = c;
+ if (--bytes_left == 0) /* codepoint complete */
+ {
+ if(codepoint > 0x10FFFF) /* is it too large? */
+ complete = -1; /* error */
+ else
+ { /* finished; output utf-8 sequence */
+ yield = string_cat(yield, &size, &ptr, seq_buff, seq_len);
+ index = 0;
+ }
+ }
+ }
+ }
+ else /* no bytes left: new sequence */
+ {
+ if((c & 0x80) == 0) /* 1-byte sequence, US-ASCII, keep it */
+ {
+ yield = string_cat(yield, &size, &ptr, &c, 1);
+ continue;
+ }
+ if((c & 0xe0) == 0xc0) /* 2-byte sequence */
+ {
+ bytes_left = 1;
+ codepoint = c & 0x1f;
+ }
+ else if((c & 0xf0) == 0xe0) /* 3-byte sequence */
+ {
+ bytes_left = 2;
+ codepoint = c & 0x0f;
+ }
+ else if((c & 0xf8) == 0xf0) /* 4-byte sequence */
+ {
+ bytes_left = 3;
+ codepoint = c & 0x07;
+ }
+ else /* invalid or too long (RFC3629 allows only 4 bytes) */
+ complete = -1;
+
+ seq_buff[index++] = c;
+ seq_len = bytes_left + 1;
+ } /* if(bytes_left) */
+
+ if (complete != 0)
+ {
+ bytes_left = index = 0;
+ yield = string_cat(yield, &size, &ptr, UTF8_REPLACEMENT_CHAR, 1);
+ }
+ if ((complete == 1) && ((c & 0x80) == 0))
+ { /* ASCII character follows incomplete sequence */
+ yield = string_cat(yield, &size, &ptr, &c, 1);
+ }
+ }
+ continue;
+ }
+
/* escape turns all non-printing characters into escape sequences. */
case EOP_ESCAPE:
#endif
+/*
+ vi: aw ai sw=2
+*/
/* End of expand.c */