X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/a94bdef382a12b5677b6d6f5eb6e686bfc8cf665..1d28cc061677bd07d9bed48dd84bd5c590247043:/src/src/transports/pipe.c diff --git a/src/src/transports/pipe.c b/src/src/transports/pipe.c index 0535b6743..c3547eefe 100644 --- a/src/src/transports/pipe.c +++ b/src/src/transports/pipe.c @@ -2,8 +2,10 @@ * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2015 */ +/* Copyright (c) The Exim maintainers 2020 - 2022 */ +/* Copyright (c) University of Cambridge 1995 - 2018 */ /* See the file NOTICE for conditions of use and distribution. */ +/* SPDX-License-Identifier: GPL-2.0-or-later */ #include "../exim.h" @@ -21,72 +23,50 @@ with "*" are not settable by the user but are used by the option-reading software for alternative value types. Some options are stored in the transport instance block so as to be publicly visible; these are flagged with opt_public. */ +#define LOFF(field) OPT_OFF(pipe_transport_options_block, field) optionlist pipe_transport_options[] = { - { "allow_commands", opt_stringptr, - (void *)offsetof(pipe_transport_options_block, allow_commands) }, + { "allow_commands", opt_stringptr, LOFF(allow_commands) }, { "batch_id", opt_stringptr | opt_public, - (void *)offsetof(transport_instance, batch_id) }, + OPT_OFF(transport_instance, batch_id) }, { "batch_max", opt_int | opt_public, - (void *)offsetof(transport_instance, batch_max) }, - { "check_string", opt_stringptr, - (void *)offsetof(pipe_transport_options_block, check_string) }, - { "command", opt_stringptr, - (void *)offsetof(pipe_transport_options_block, cmd) }, - { "environment", opt_stringptr, - (void *)offsetof(pipe_transport_options_block, environment) }, - { "escape_string", opt_stringptr, - (void *)offsetof(pipe_transport_options_block, escape_string) }, - { "force_command", opt_bool, - (void *)offsetof(pipe_transport_options_block, force_command) }, - { "freeze_exec_fail", opt_bool, - (void *)offsetof(pipe_transport_options_block, freeze_exec_fail) }, - { "freeze_signal", opt_bool, - (void *)offsetof(pipe_transport_options_block, freeze_signal) }, - { "ignore_status", opt_bool, - (void *)offsetof(pipe_transport_options_block, ignore_status) }, + OPT_OFF(transport_instance, batch_max) }, + { "check_string", opt_stringptr, LOFF(check_string) }, + { "command", opt_stringptr, LOFF(cmd) }, + { "environment", opt_stringptr, LOFF(environment) }, + { "escape_string", opt_stringptr, LOFF(escape_string) }, + { "force_command", opt_bool, LOFF(force_command) }, + { "freeze_exec_fail", opt_bool, LOFF(freeze_exec_fail) }, + { "freeze_signal", opt_bool, LOFF(freeze_signal) }, + { "ignore_status", opt_bool, LOFF(ignore_status) }, { "log_defer_output", opt_bool | opt_public, - (void *)offsetof(transport_instance, log_defer_output) }, + OPT_OFF(transport_instance, log_defer_output) }, { "log_fail_output", opt_bool | opt_public, - (void *)offsetof(transport_instance, log_fail_output) }, + OPT_OFF(transport_instance, log_fail_output) }, { "log_output", opt_bool | opt_public, - (void *)offsetof(transport_instance, log_output) }, - { "max_output", opt_mkint, - (void *)offsetof(pipe_transport_options_block, max_output) }, - { "message_prefix", opt_stringptr, - (void *)offsetof(pipe_transport_options_block, message_prefix) }, - { "message_suffix", opt_stringptr, - (void *)offsetof(pipe_transport_options_block, message_suffix) }, - { "path", opt_stringptr, - (void *)offsetof(pipe_transport_options_block, path) }, - { "permit_coredump", opt_bool, - (void *)offsetof(pipe_transport_options_block, permit_coredump) }, + OPT_OFF(transport_instance, log_output) }, + { "max_output", opt_mkint, LOFF(max_output) }, + { "message_prefix", opt_stringptr, LOFF(message_prefix) }, + { "message_suffix", opt_stringptr, LOFF(message_suffix) }, + { "path", opt_stringptr, LOFF(path) }, + { "permit_coredump", opt_bool, LOFF(permit_coredump) }, { "pipe_as_creator", opt_bool | opt_public, - (void *)offsetof(transport_instance, deliver_as_creator) }, - { "restrict_to_path", opt_bool, - (void *)offsetof(pipe_transport_options_block, restrict_to_path) }, + OPT_OFF(transport_instance, deliver_as_creator) }, + { "restrict_to_path", opt_bool, LOFF(restrict_to_path) }, { "return_fail_output",opt_bool | opt_public, - (void *)offsetof(transport_instance, return_fail_output) }, + OPT_OFF(transport_instance, return_fail_output) }, { "return_output", opt_bool | opt_public, - (void *)offsetof(transport_instance, return_output) }, - { "temp_errors", opt_stringptr, - (void *)offsetof(pipe_transport_options_block, temp_errors) }, - { "timeout", opt_time, - (void *)offsetof(pipe_transport_options_block, timeout) }, - { "timeout_defer", opt_bool, - (void *)offsetof(pipe_transport_options_block, timeout_defer) }, - { "umask", opt_octint, - (void *)offsetof(pipe_transport_options_block, umask) }, - { "use_bsmtp", opt_bool, - (void *)offsetof(pipe_transport_options_block, use_bsmtp) }, + OPT_OFF(transport_instance, return_output) }, + { "temp_errors", opt_stringptr, LOFF(temp_errors) }, + { "timeout", opt_time, LOFF(timeout) }, + { "timeout_defer", opt_bool, LOFF(timeout_defer) }, + { "umask", opt_octint, LOFF(umask) }, + { "use_bsmtp", opt_bool, LOFF(use_bsmtp) }, #ifdef HAVE_SETCLASSRESOURCES - { "use_classresources", opt_bool, - (void *)offsetof(pipe_transport_options_block, use_classresources) }, + { "use_classresources", opt_bool, LOFF(use_classresources) }, #endif - { "use_crlf", opt_bool, - (void *)offsetof(pipe_transport_options_block, use_crlf) }, - { "use_shell", opt_bool, - (void *)offsetof(pipe_transport_options_block, use_shell) }, + { "use_crlf", opt_bool, LOFF(use_crlf) }, + { "use_shell", opt_bool, LOFF(use_shell) }, }; /* Size of the options list. An extern variable has to be used so that its @@ -95,34 +75,27 @@ address can appear in the tables drtables.c. */ int pipe_transport_options_count = sizeof(pipe_transport_options)/sizeof(optionlist); + +#ifdef MACRO_PREDEF + +/* Dummy values */ +pipe_transport_options_block pipe_transport_option_defaults = {0}; +void pipe_transport_init(transport_instance *tblock) {} +BOOL pipe_transport_entry(transport_instance *tblock, address_item *addr) {return FALSE;} + +#else /*!MACRO_PREDEF*/ + + /* Default private options block for the pipe transport. */ pipe_transport_options_block pipe_transport_option_defaults = { - NULL, /* cmd */ - NULL, /* allow_commands */ - NULL, /* environment */ - US"/bin:/usr/bin", /* path */ - NULL, /* message_prefix (reset in init if not bsmtp) */ - NULL, /* message_suffix (ditto) */ - US mac_expanded_string(EX_TEMPFAIL) ":" /* temp_errors */ - mac_expanded_string(EX_CANTCREAT), - NULL, /* check_string */ - NULL, /* escape_string */ - 022, /* umask */ - 20480, /* max_output */ - 60*60, /* timeout */ - 0, /* options */ - FALSE, /* force_command */ - FALSE, /* freeze_exec_fail */ - FALSE, /* freeze_signal */ - FALSE, /* ignore_status */ - FALSE, /* permit_coredump */ - FALSE, /* restrict_to_path */ - FALSE, /* timeout_defer */ - FALSE, /* use_shell */ - FALSE, /* use_bsmtp */ - FALSE, /* use_classresources */ - FALSE /* use_crlf */ + .path = US"/bin:/usr/bin", + .temp_errors = US mac_expanded_string(EX_TEMPFAIL) ":" + mac_expanded_string(EX_CANTCREAT), + .umask = 022, + .max_output = 20480, + .timeout = 60*60, + /* all others null/zero/false */ }; @@ -154,13 +127,6 @@ pipe_transport_setup(transport_instance *tblock, address_item *addrlist, pipe_transport_options_block *ob = (pipe_transport_options_block *)(tblock->options_block); -addrlist = addrlist; /* Keep compiler happy */ -dummy = dummy; -uid = uid; -gid = gid; -errmsg = errmsg; -ob = ob; - #ifdef HAVE_SETCLASSRESOURCES if (ob->use_classresources) { @@ -295,12 +261,12 @@ if (ob->allow_commands && ob->use_shell) driver options. Only one of body_only and headers_only can be set. */ ob->options |= - (tblock->body_only? topt_no_headers : 0) | - (tblock->headers_only? topt_no_body : 0) | - (tblock->return_path_add? topt_add_return_path : 0) | - (tblock->delivery_date_add? topt_add_delivery_date : 0) | - (tblock->envelope_to_add? topt_add_envelope_to : 0) | - (ob->use_crlf? topt_use_crlf : 0); + (tblock->body_only ? topt_no_headers : 0) + | (tblock->headers_only ? topt_no_body : 0) + | (tblock->return_path_add ? topt_add_return_path : 0) + | (tblock->delivery_date_add ? topt_add_delivery_date : 0) + | (tblock->envelope_to_add ? topt_add_envelope_to : 0) + | (ob->use_crlf ? topt_use_crlf : 0); } @@ -339,7 +305,7 @@ the items if necessary. If it fails, this function fails (error information is in the addresses). */ if (!transport_set_up_command(argvptr, cmd, expand_arguments, expand_fail, - addr, string_sprintf("%.50s transport", tname), NULL)) + addr, FALSE, string_sprintf("%.50s transport", tname), NULL)) return FALSE; /* Point to the set-up arguments. */ @@ -452,7 +418,7 @@ set_up_shell_command(const uschar ***argvptr, uschar *cmd, { const uschar **argv; -*argvptr = argv = store_get((4)*sizeof(uschar *)); +*argvptr = argv = store_get((4)*sizeof(uschar *), GET_UNTAINTED); argv[0] = US"/bin/sh"; argv[1] = US"-c"; @@ -460,51 +426,51 @@ argv[1] = US"-c"; /* We have to take special action to handle the special "variable" called $pipe_addresses, which is not recognized by the normal expansion function. */ -DEBUG(D_transport) - debug_printf("shell pipe command before expansion:\n %s\n", cmd); - if (expand_arguments) { - uschar *s = cmd; - uschar *p = Ustrstr(cmd, "pipe_addresses"); + uschar * p = Ustrstr(cmd, "pipe_addresses"); + gstring * g = NULL; + + DEBUG(D_transport) + debug_printf("shell pipe command before expansion:\n %s\n", cmd); + + /* Allow $recipients in the expansion iff it comes from a system filter */ + + f.enable_dollar_recipients = addr && addr->parent && + Ustrcmp(addr->parent->address, "system-filter") == 0; if (p != NULL && ( (p > cmd && p[-1] == '$') || (p > cmd + 1 && p[-2] == '$' && p[-1] == '{' && p[14] == '}'))) { - address_item *ad; uschar *q = p + 14; - int size = Ustrlen(cmd) + 64; - int offset; if (p[-1] == '{') { q++; p--; } - s = store_get(size); - offset = p - cmd - 1; - Ustrncpy(s, cmd, offset); + g = string_get(Ustrlen(cmd) + 64); + g = string_catn(g, cmd, p - cmd - 1); - for (ad = addr; ad != NULL; ad = ad->next) + for (address_item * ad = addr; ad; ad = ad->next) { + DEBUG(D_transport) if (is_tainted(ad->address)) + debug_printf("tainted element '%s' from $pipe_addresses\n", ad->address); + /*XXX string_append_listele() ? */ - if (ad != addr) s = string_catn(s, &size, &offset, US" ", 1); - s = string_cat(s, &size, &offset, ad->address); + if (ad != addr) g = string_catn(g, US" ", 1); + g = string_cat(g, ad->address); } - s = string_cat(s, &size, &offset, q); - s[offset] = 0; + g = string_cat(g, q); + argv[2] = (cmd = string_from_gstring(g)) ? expand_string(cmd) : NULL; } + else + argv[2] = expand_string(cmd); - /* Allow $recipients in the expansion iff it comes from a system filter */ - - enable_dollar_recipients = addr != NULL && - addr->parent != NULL && - Ustrcmp(addr->parent->address, "system-filter") == 0; - argv[2] = expand_string(s); - enable_dollar_recipients = FALSE; + f.enable_dollar_recipients = FALSE; - if (argv[2] == NULL) + if (!argv[2]) { - addr->transport_return = search_find_defer? DEFER : expand_fail; + addr->transport_return = f.search_find_defer ? DEFER : expand_fail; addr->message = string_sprintf("Expansion of command \"%s\" " "in %s transport failed: %s", cmd, tname, expand_string_message); @@ -514,9 +480,14 @@ if (expand_arguments) DEBUG(D_transport) debug_printf("shell pipe command after expansion:\n %s\n", argv[2]); } -else argv[2] = cmd; +else + { + DEBUG(D_transport) + debug_printf("shell pipe command (no expansion):\n %s\n", cmd); + argv[2] = cmd; + } -argv[3] = (uschar *)0; +argv[3] = US 0; return TRUE; } @@ -552,11 +523,11 @@ const uschar *envlist = ob->environment; uschar *cmd, *ss; uschar *eol = ob->use_crlf ? US"\r\n" : US"\n"; transport_ctx tctx = { - tblock, - addr, - ob->check_string, - ob->escape_string, - ob->options /* set at initialization time */ + .tblock = tblock, + .addr = addr, + .check_string = ob->check_string, + .escape_string = ob->escape_string, + ob->options | topt_not_socket /* set at initialization time */ }; DEBUG(D_transport) debug_printf("%s transport entered\n", tblock->name); @@ -573,10 +544,9 @@ symbol. In other cases, the command is supplied as one of the pipe transport's options. */ if (testflag(addr, af_pfr) && addr->local_part[0] == '|') - { if (ob->force_command) { - /* Enables expansion of $address_pipe into seperate arguments */ + /* Enables expansion of $address_pipe into separate arguments */ setflag(addr, af_force_command); cmd = ob->cmd; expand_arguments = TRUE; @@ -589,7 +559,6 @@ if (testflag(addr, af_pfr) && addr->local_part[0] == '|') expand_arguments = testflag(addr, af_expand_pipe); expand_fail = FAIL; } - } else { cmd = ob->cmd; @@ -598,17 +567,24 @@ else } /* If no command has been supplied, we are in trouble. - * We also check for an empty string since it may be - * coming from addr->local_part[0] == '|' - */ +We also check for an empty string since it may be +coming from addr->local_part[0] == '|' */ -if (cmd == NULL || *cmd == '\0') +if (!cmd || !*cmd) { addr->transport_return = DEFER; addr->message = string_sprintf("no command specified for %s transport", tblock->name); return FALSE; } +if (is_tainted(cmd)) + { + DEBUG(D_transport) debug_printf("cmd '%s' is tainted\n", cmd); + addr->message = string_sprintf("Tainted '%s' (command " + "for %s transport) not permitted", cmd, tblock->name); + addr->transport_return = PANIC; + return FALSE; + } /* When a pipe is set up by a filter file, there may be values for $thisaddress and numerical the variables in existence. These are passed in @@ -618,8 +594,8 @@ if (expand_arguments && addr->pipe_expandn) { uschar **ss = addr->pipe_expandn; expand_nmax = -1; - if (*ss != NULL) filter_thisaddress = *ss++; - while (*ss != NULL) + if (*ss) filter_thisaddress = *ss++; + while (*ss) { expand_nstring[++expand_nmax] = *ss; expand_nlength[expand_nmax] = Ustrlen(*ss++); @@ -662,19 +638,18 @@ envp[envcount++] = string_sprintf("QUALIFY_DOMAIN=%s", qualify_domain_sender); envp[envcount++] = string_sprintf("SENDER=%s", sender_address); envp[envcount++] = US"SHELL=/bin/sh"; -if (addr->host_list != NULL) +if (addr->host_list) envp[envcount++] = string_sprintf("HOST=%s", addr->host_list->name); -if (timestamps_utc) envp[envcount++] = US"TZ=UTC"; -else if (timezone_string != NULL && timezone_string[0] != 0) +if (f.timestamps_utc) + envp[envcount++] = US"TZ=UTC"; +else if (timezone_string && timezone_string[0]) envp[envcount++] = string_sprintf("TZ=%s", timezone_string); /* Add any requested items */ if (envlist) - { - envlist = expand_cstring(envlist); - if (envlist == NULL) + if (!(envlist = expand_cstring(envlist))) { addr->transport_return = DEFER; addr->message = string_sprintf("failed to expand string \"%s\" " @@ -682,14 +657,13 @@ if (envlist) expand_string_message); return FALSE; } - } -while ((ss = string_nextinlist(&envlist, &envsep, big_buffer, big_buffer_size)) - != NULL) +while ((ss = string_nextinlist(&envlist, &envsep, NULL, 0))) { - if (envcount > sizeof(envp)/sizeof(uschar *) - 2) + if (envcount > nelem(envp) - 2) { addr->transport_return = DEFER; + addr->basic_errno = E2BIG; addr->message = string_sprintf("too many environment settings for " "%s transport", tblock->name); return FALSE; @@ -701,7 +675,7 @@ envp[envcount] = NULL; /* If the -N option is set, can't do any more. */ -if (dont_deliver) +if (f.dont_deliver) { DEBUG(D_transport) debug_printf("*** delivery by %s transport bypassed by -N option", @@ -731,7 +705,8 @@ reading of the output pipe. */ uid/gid and current directory. Request that the new process be a process group leader, so we can kill it and all its children on a timeout. */ -if ((pid = child_open(USS argv, envp, ob->umask, &fd_in, &fd_out, TRUE)) < 0) +if ((pid = child_open(USS argv, envp, ob->umask, &fd_in, &fd_out, TRUE, + US"pipe-tpt-cmd")) < 0) { addr->transport_return = DEFER; addr->message = string_sprintf( @@ -739,10 +714,11 @@ if ((pid = child_open(USS argv, envp, ob->umask, &fd_in, &fd_out, TRUE)) < 0) strerror(errno)); return FALSE; } +tctx.u.fd = fd_in; /* Now fork a process to handle the output that comes down the pipe. */ -if ((outpid = fork()) < 0) +if ((outpid = exim_fork(US"pipe-tpt-output")) < 0) { addr->basic_errno = errno; addr->transport_return = DEFER; @@ -800,7 +776,7 @@ bit here to let the sub-process get going, but it may still not complete. So we ignore all writing errors. (When in the test harness, we do do a short sleep so any debugging output is likely to be in the same order.) */ -if (running_in_test_harness) millisleep(500); +testharness_pause_ms(500); DEBUG(D_transport) debug_printf("Writing message to pipe\n"); @@ -818,18 +794,18 @@ transport_count = 0; /* First write any configured prefix information */ -if (ob->message_prefix != NULL) +if (ob->message_prefix) { uschar *prefix = expand_string(ob->message_prefix); - if (prefix == NULL) + if (!prefix) { - addr->transport_return = search_find_defer? DEFER : PANIC; + addr->transport_return = f.search_find_defer? DEFER : PANIC; addr->message = string_sprintf("Expansion of \"%s\" (prefix for %s " "transport) failed: %s", ob->message_prefix, tblock->name, expand_string_message); return FALSE; } - if (!transport_write_block(fd_in, prefix, Ustrlen(prefix))) + if (!transport_write_block(&tctx, prefix, Ustrlen(prefix), FALSE)) goto END_WRITE; } @@ -840,12 +816,10 @@ than one address available here, all must be included. Force SMTP dot-handling. if (ob->use_bsmtp) { - address_item *a; - if (!transport_write_string(fd_in, "MAIL FROM:<%s>%s", return_path, eol)) goto END_WRITE; - for (a = addr; a; a = a->next) + for (address_item * a = addr; a; a = a->next) if (!transport_write_string(fd_in, "RCPT TO:<%s>%s", transport_rcpt_address(a, tblock->rcpt_include_affixes), @@ -857,7 +831,7 @@ if (ob->use_bsmtp) /* Now the actual message */ -if (!transport_write_message(fd_in, &tctx, 0)) +if (!transport_write_message(&tctx, 0)) goto END_WRITE; /* Now any configured suffix */ @@ -867,13 +841,13 @@ if (ob->message_suffix) uschar *suffix = expand_string(ob->message_suffix); if (!suffix) { - addr->transport_return = search_find_defer? DEFER : PANIC; + addr->transport_return = f.search_find_defer? DEFER : PANIC; addr->message = string_sprintf("Expansion of \"%s\" (suffix for %s " "transport) failed: %s", ob->message_suffix, tblock->name, expand_string_message); return FALSE; } - if (!transport_write_block(fd_in, suffix, Ustrlen(suffix))) + if (!transport_write_block(&tctx, suffix, Ustrlen(suffix), FALSE)) goto END_WRITE; } @@ -906,7 +880,7 @@ if (!written_ok) if (errno == ETIMEDOUT) { addr->message = string_sprintf("%stimeout while writing to pipe", - transport_filter_timed_out? "transport filter " : ""); + f.transport_filter_timed_out ? "transport filter " : ""); addr->transport_return = ob->timeout_defer? DEFER : FAIL; timeout = 1; } @@ -927,7 +901,7 @@ if (!written_ok) addr->more_errno, (addr->more_errno == EX_EXECFAILED)? ": unable to execute command" : ""); else if (errno == ERRNO_WRITEINCOMPLETE) - addr->message = string_sprintf("Failed repeatedly to write data"); + addr->message = US"Failed repeatedly to write data"; else addr->message = string_sprintf("Error %d", errno); return FALSE; @@ -940,8 +914,8 @@ above timed out. */ if ((rc = child_close(pid, timeout)) != 0) { - uschar *tmsg = (addr->message == NULL)? US"" : - string_sprintf(" (preceded by %s)", addr->message); + uschar * tmsg = addr->message + ? string_sprintf(" (preceded by %s)", addr->message) : US""; /* The process did not complete in time; kill its process group and fail the delivery. It appears to be necessary to kill the output process too, as @@ -972,7 +946,7 @@ if ((rc = child_close(pid, timeout)) != 0) This prevents the transport_filter timeout message from getting overwritten by the exit error which is not the cause of the problem. */ - else if (transport_filter_timed_out) + else if (f.transport_filter_timed_out) { killpg(pid, SIGKILL); kill(outpid, SIGKILL); @@ -1024,7 +998,7 @@ if ((rc = child_close(pid, timeout)) != 0) the command that was given is a non-existent path). By default this is treated as just another failure, but if freeze_exec_fail is set, the reaction is to freeze the message rather than bounce the address. Exim used to signal - this failure with EX_UNAVAILABLE, which is definined in many systems as + this failure with EX_UNAVAILABLE, which is defined in many systems as #define EX_UNAVAILABLE 69 @@ -1047,7 +1021,7 @@ if ((rc = child_close(pid, timeout)) != 0) { /* Always handle execve() failure specially if requested to */ - if (ob->freeze_exec_fail && (rc == EX_EXECFAILED)) + if (ob->freeze_exec_fail && rc == EX_EXECFAILED) { addr->transport_return = DEFER; addr->special_action = SPECIAL_FREEZE; @@ -1060,9 +1034,9 @@ if ((rc = child_close(pid, timeout)) != 0) else if (!ob->ignore_status) { uschar *ss; - int size, ptr, i; + gstring * g; - /* If temp_errors is "*" all codes are temporary. Initializion checks + /* If temp_errors is "*" all codes are temporary. Initialization checks that it's either "*" or a list of numbers. If not "*", scan the list of temporary failure codes; if any match, the result is DEFER. */ @@ -1085,9 +1059,7 @@ if ((rc = child_close(pid, timeout)) != 0) addr->message = string_sprintf("Child process of %s transport returned " "%d", tblock->name, rc); - - ptr = Ustrlen(addr->message); - size = ptr + 1; + g = string_cat(NULL, addr->message); /* If the return code is > 128, it often means that a shell command was terminated by a signal. */ @@ -1097,37 +1069,36 @@ if ((rc = child_close(pid, timeout)) != 0) rc-128, os_strsignal(rc-128)) : US os_strexit(rc); - if (*ss != 0) + if (*ss) { - addr->message = string_catn(addr->message, &size, &ptr, US" ", 1); - addr->message = string_cat (addr->message, &size, &ptr, ss); + g = string_catn(g, US" ", 1); + g = string_cat (g, ss); } /* Now add the command and arguments */ - addr->message = string_catn(addr->message, &size, &ptr, - US" from command:", 14); + g = string_catn(g, US" from command:", 14); - for (i = 0; i < sizeof(argv)/sizeof(int *) && argv[i] != NULL; i++) + for (int i = 0; i < sizeof(argv)/sizeof(int *) && argv[i] != NULL; i++) { BOOL quote = FALSE; - addr->message = string_catn(addr->message, &size, &ptr, US" ", 1); + g = string_catn(g, US" ", 1); if (Ustrpbrk(argv[i], " \t") != NULL) { quote = TRUE; - addr->message = string_catn(addr->message, &size, &ptr, US"\"", 1); + g = string_catn(g, US"\"", 1); } - addr->message = string_cat(addr->message, &size, &ptr, argv[i]); + g = string_cat(g, argv[i]); if (quote) - addr->message = string_catn(addr->message, &size, &ptr, US"\"", 1); + g = string_catn(g, US"\"", 1); } /* Add previous filter timeout message, if present. */ if (*tmsg) - addr->message = string_cat(addr->message, &size, &ptr, tmsg); + g = string_cat(g, tmsg); - addr->message[ptr] = 0; /* Ensure concatenated string terminated */ + addr->message = string_from_gstring(g); } } } @@ -1150,4 +1121,5 @@ if (addr->transport_return != OK) return FALSE; } +#endif /*!MACRO_PREDEF*/ /* End of transport/pipe.c */