X-Git-Url: https://vcs.fsf.org/?p=exim.git;a=blobdiff_plain;f=src%2Fsrc%2Fexpand.c;h=64a3a86e6156a5b3282dc475f67fa0023de579d8;hp=7e1b32343050182980b40062f3b155ed8e18b25a;hb=51c7471d48efd62b2d4f5647782ba1e849d4c35a;hpb=bc338899110ea22098559081f77cbd0f7a8044bd diff --git a/src/src/expand.c b/src/src/expand.c index 7e1b32343..64a3a86e6 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -204,7 +204,8 @@ static uschar *op_table_main[] = { US"str2b64", US"strlen", US"substr", - US"uc" }; + US"uc", + US"utf8clean" }; enum { EOP_ADDRESS = sizeof(op_table_underscore)/sizeof(uschar *), @@ -240,7 +241,8 @@ enum { EOP_STR2B64, EOP_STRLEN, EOP_SUBSTR, - EOP_UC }; + EOP_UC, + EOP_UTF8CLEAN }; /* Table of condition names, and corresponding switch numbers. The names must @@ -2847,7 +2849,9 @@ switch(cond_type) be no maintenance burden from replicating it. */ if (len == 0) boolvalue = FALSE; - else if (Ustrspn(t, "0123456789") == len) + else if (*t == '-' + ? Ustrspn(t+1, "0123456789") == len-1 + : Ustrspn(t, "0123456789") == len) { boolvalue = (Uatoi(t) == 0) ? FALSE : TRUE; /* expand_check_condition only does a literal string "0" check */ @@ -4497,10 +4501,7 @@ while (*s != 0) if (Ustrncmp(sub_arg[0], "inet:", 5) == 0) { - BOOL connected = FALSE; - int namelen, port; - host_item shost; - host_item *h; + int port; uschar *server_name = sub_arg[0] + 5; uschar *port_name = Ustrrchr(server_name, ':'); @@ -4537,76 +4538,9 @@ while (*s != 0) port = ntohs(service_info->s_port); } - /* Sort out the server. */ - - shost.next = NULL; - shost.address = NULL; - shost.port = port; - shost.mx = -1; - - namelen = Ustrlen(server_name); - - /* Anything enclosed in [] must be an IP address. */ - - if (server_name[0] == '[' && - server_name[namelen - 1] == ']') - { - server_name[namelen - 1] = 0; - server_name++; - if (string_is_ip_address(server_name, NULL) == 0) - { - expand_string_message = - string_sprintf("malformed IP address \"%s\"", server_name); - goto EXPAND_FAILED; - } - shost.name = shost.address = server_name; - } - - /* Otherwise check for an unadorned IP address */ - - else if (string_is_ip_address(server_name, NULL) != 0) - shost.name = shost.address = server_name; - - /* Otherwise lookup IP address(es) from the name */ - - else - { - shost.name = server_name; - if (host_find_byname(&shost, NULL, HOST_FIND_QUALIFY_SINGLE, NULL, - FALSE) != HOST_FOUND) - { - expand_string_message = - string_sprintf("no IP address found for host %s", shost.name); - goto EXPAND_FAILED; - } - } - - /* Try to connect to the server - test each IP till one works */ - - for (h = &shost; h != NULL; h = h->next) - { - int af = (Ustrchr(h->address, ':') != 0)? AF_INET6 : AF_INET; - if ((fd = ip_socket(SOCK_STREAM, af)) == -1) - { - expand_string_message = string_sprintf("failed to create socket: " - "%s", strerror(errno)); + if ((fd = ip_connectedsocket(SOCK_STREAM, server_name, port, port, + timeout, NULL, &expand_string_message)) < 0) goto SOCK_FAIL; - } - - if (ip_connect(fd, af, h->address, port, timeout) == 0) - { - connected = TRUE; - break; - } - } - - if (!connected) - { - expand_string_message = string_sprintf("failed to connect to " - "socket %s: couldn't connect to any host", sub_arg[0], - strerror(errno)); - goto SOCK_FAIL; - } } /* Handle a Unix domain socket */ @@ -5353,7 +5287,6 @@ while (*s != 0) uschar *list, *expr, *temp; uschar *save_iterate_item = iterate_item; uschar *save_lookup_value = lookup_value; - BOOL dummy; while (isspace(*s)) s++; if (*s++ != '{') goto EXPAND_FAILED_CURLY; @@ -6206,6 +6139,89 @@ while (*s != 0) 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: @@ -6834,4 +6850,7 @@ return 0; #endif +/* + vi: aw ai sw=2 +*/ /* End of expand.c */