From: Jeremy Harris Date: Tue, 3 Oct 2017 15:13:26 +0000 (+0100) Subject: String handling: refactor the expanding-string routines and users to use a descriptor... X-Git-Tag: exim-4_91_RC1~148^2~39 X-Git-Url: https://vcs.fsf.org/?a=commitdiff_plain;h=94e1f16d6033683bdebaf5092f64c58bc044dd2d;p=exim.git String handling: refactor the expanding-string routines and users to use a descriptor struct --- diff --git a/src/src/acl.c b/src/src/acl.c index b5ffa0193..79feb5f68 100644 --- a/src/src/acl.c +++ b/src/src/acl.c @@ -1036,9 +1036,7 @@ for (p = q; *p != 0; ) uschar * fn_hdrs_added(void) { -uschar * ret = NULL; -int size = 0; -int ptr = 0; +gstring * g = NULL; header_line * h = acl_added_headers; uschar * s; uschar * cp; @@ -1053,18 +1051,19 @@ do if (cp[1] == '\0') break; /* contains embedded newline; needs doubling */ - ret = string_catn(ret, &size, &ptr, s, cp-s+1); - ret = string_catn(ret, &size, &ptr, US"\n", 1); + g = string_catn(g, s, cp-s+1); + g = string_catn(g, US"\n", 1); s = cp+1; } /* last bit of header */ - ret = string_catn(ret, &size, &ptr, s, cp-s+1); /* newline-sep list */ +/*XXX could we use add_listele? */ + g = string_catn(g, s, cp-s+1); /* newline-sep list */ } while((h = h->next)); -ret[ptr-1] = '\0'; /* overwrite last newline */ -return ret; +g->s[g->ptr - 1] = '\0'; /* overwrite last newline */ +return g->s; } diff --git a/src/src/daemon.c b/src/src/daemon.c index b91b43746..7d5528785 100644 --- a/src/src/daemon.c +++ b/src/src/daemon.c @@ -143,10 +143,9 @@ union sockaddr_46 interface_sockaddr; EXIM_SOCKLEN_T ifsize = sizeof(interface_sockaddr); int dup_accept_socket = -1; int max_for_this_host = 0; -int wfsize = 0; -int wfptr = 0; int save_log_selector = *log_selector; -uschar *whofrom = NULL; +gstring * whofrom = NULL; +uschar * whofrom_s; void *reset_point = store_get(0); @@ -201,17 +200,16 @@ DEBUG(D_interface) debug_printf("interface address=%s port=%d\n", the local interface data. This is for logging; at the end of this function the memory is reclaimed. */ -whofrom = string_append(whofrom, &wfsize, &wfptr, 3, "[", sender_host_address, "]"); +whofrom = string_append(whofrom, 3, "[", sender_host_address, "]"); if (LOGGING(incoming_port)) - whofrom = string_append(whofrom, &wfsize, &wfptr, 2, ":", string_sprintf("%d", - sender_host_port)); + whofrom = string_append(whofrom, 2, ":", string_sprintf("%d", sender_host_port)); if (LOGGING(incoming_interface)) - whofrom = string_append(whofrom, &wfsize, &wfptr, 4, " I=[", + whofrom = string_append(whofrom, 4, " I=[", interface_address, "]:", string_sprintf("%d", interface_port)); -whofrom[wfptr] = 0; /* Terminate the newly-built string */ +(void) string_from_gstring(whofrom); /* Terminate the newly-built string */ /* Check maximum number of connections. We do not check for reserved connections or unacceptable hosts here. That is done in the subprocess because @@ -225,7 +223,7 @@ if (smtp_accept_max > 0 && smtp_accept_count >= smtp_accept_max) "please try again later.\r\n", FALSE); log_write(L_connection_reject, LOG_MAIN, "Connection from %s refused: too many connections", - whofrom); + whofrom->s); goto ERROR_RETURN; } @@ -244,7 +242,7 @@ if (smtp_load_reserve >= 0) smtp_printf("421 Too much load; please try again later.\r\n", FALSE); log_write(L_connection_reject, LOG_MAIN, "Connection from %s refused: load average = %.2f", - whofrom, (double)load_average/1000.0); + whofrom->s, (double)load_average/1000.0); goto ERROR_RETURN; } } @@ -264,7 +262,7 @@ if (smtp_accept_max_per_host != NULL) { if (!expand_string_forcedfail) log_write(0, LOG_MAIN|LOG_PANIC, "expansion of smtp_accept_max_per_host " - "failed for %s: %s", whofrom, expand_string_message); + "failed for %s: %s", whofrom->s, expand_string_message); } /* For speed, interpret a decimal number inline here */ else @@ -274,7 +272,7 @@ if (smtp_accept_max_per_host != NULL) max_for_this_host = max_for_this_host * 10 + *s++ - '0'; if (*s != 0) log_write(0, LOG_MAIN|LOG_PANIC, "expansion of smtp_accept_max_per_host " - "for %s contains non-digit: %s", whofrom, expanded); + "for %s contains non-digit: %s", whofrom->s, expanded); } } @@ -315,7 +313,7 @@ if ((max_for_this_host > 0) && "from this IP address; please try again later.\r\n", FALSE); log_write(L_connection_reject, LOG_MAIN, "Connection from %s refused: too many connections " - "from that IP address", whofrom); + "from that IP address", whofrom->s); goto ERROR_RETURN; } } @@ -341,7 +339,7 @@ if (LOGGING(smtp_connection)) save_log_selector &= ~L_smtp_connection; else log_write(L_smtp_connection, LOG_MAIN, "SMTP connection from %s " - "(TCP/IP connection count = %d)", whofrom, smtp_accept_count + 1); + "(TCP/IP connection count = %d)", whofrom->s, smtp_accept_count + 1); } /* Now we can fork the accepting process; do a lookup tidy, just in case any @@ -1072,14 +1070,10 @@ if (daemon_listen && !inetd_wait_mode) that contain neither a dot nor a colon are used to override daemon_smtp_port. Any other items are used to override local_interfaces. */ - if (override_local_interfaces != NULL) + if (override_local_interfaces) { - uschar *new_smtp_port = NULL; - uschar *new_local_interfaces = NULL; - int portsize = 0; - int portptr = 0; - int ifacesize = 0; - int ifaceptr = 0; + gstring * new_smtp_port = NULL; + gstring * new_local_interfaces = NULL; if (override_pid_file_path == NULL) write_pid = FALSE; @@ -1088,46 +1082,34 @@ if (daemon_listen && !inetd_wait_mode) while ((s = string_nextinlist(&list, &sep, big_buffer, big_buffer_size))) { uschar joinstr[4]; - uschar **ptr; - int *sizeptr; - int *ptrptr; + gstring ** gp; if (Ustrpbrk(s, ".:") == NULL) - { - ptr = &new_smtp_port; - sizeptr = &portsize; - ptrptr = &portptr; - } + gp = &new_smtp_port; else - { - ptr = &new_local_interfaces; - sizeptr = &ifacesize; - ptrptr = &ifaceptr; - } + gp = &new_local_interfaces; - if (*ptr == NULL) + if (!*gp) { joinstr[0] = sep; joinstr[1] = ' '; - *ptr = string_catn(*ptr, sizeptr, ptrptr, US"<", 1); + *gp = string_catn(*gp, US"<", 1); } - *ptr = string_catn(*ptr, sizeptr, ptrptr, joinstr, 2); - *ptr = string_cat (*ptr, sizeptr, ptrptr, s); + *gp = string_catn(*gp, joinstr, 2); + *gp = string_cat (*gp, s); } - if (new_smtp_port != NULL) + if (new_smtp_port) { - new_smtp_port[portptr] = 0; - daemon_smtp_port = new_smtp_port; + daemon_smtp_port = string_from_gstring(new_smtp_port); DEBUG(D_any) debug_printf("daemon_smtp_port overridden by -oX:\n %s\n", daemon_smtp_port); } - if (new_local_interfaces != NULL) + if (new_local_interfaces) { - new_local_interfaces[ifaceptr] = 0; - local_interfaces = new_local_interfaces; + local_interfaces = string_from_gstring(new_local_interfaces); local_iface_source = US"-oX data"; DEBUG(D_any) debug_printf("local_interfaces overridden by -oX:\n %s\n", local_interfaces); @@ -1173,7 +1155,7 @@ if (daemon_listen && !inetd_wait_mode) while ((s = string_nextinlist(&list, &sep, big_buffer, big_buffer_size))) if (!isdigit(*s)) { - int size = 0, len = 0; + gstring * g = NULL; list = tls_in.on_connect_ports; tls_in.on_connect_ports = NULL; @@ -1187,9 +1169,10 @@ if (daemon_listen && !inetd_wait_mode) log_write(0, LOG_PANIC_DIE|LOG_CONFIG, "TCP port \"%s\" not found", s); s = string_sprintf("%d", (int)ntohs(smtp_service->s_port)); } - tls_in.on_connect_ports = string_append_listele(tls_in.on_connect_ports, - &size, &len, ':', s); + g = string_append_listele(g, ':', s); } + if (g) + tls_in.on_connect_ports = g->s; break; } diff --git a/src/src/debug.c b/src/src/debug.c index 09e03f1e4..17a87d2d2 100644 --- a/src/src/debug.c +++ b/src/src/debug.c @@ -40,11 +40,11 @@ static void tree_printsub(tree_node *p, int pos, int barswitch) { int i; -if (p->right != NULL) tree_printsub(p->right, pos+2, 1); +if (p->right) tree_printsub(p->right, pos+2, 1); for (i = 0; i <= pos-1; i++) debug_printf("%c", tree_printline[i]); debug_printf("-->%s [%d]\n", p->name, p->balance); tree_printline[pos] = barswitch? '|' : ' '; -if (p->left != NULL) +if (p->left) { tree_printline[pos+2] = '|'; tree_printsub(p->left, pos+2, 0); @@ -58,7 +58,7 @@ debug_print_tree(tree_node *p) { int i; for (i = 0; i < tree_printlinesize; i++) tree_printline[i] = ' '; -if (p == NULL) debug_printf("Empty Tree\n"); else tree_printsub(p, 0, 0); +if (!p) debug_printf("Empty Tree\n"); else tree_printsub(p, 0, 0); debug_printf("---- End of tree ----\n"); } @@ -78,7 +78,7 @@ void debug_print_argv(const uschar ** argv) { debug_printf("exec"); -while (*argv != NULL) debug_printf(" %.256s", *argv++); +while (*argv) debug_printf(" %.256s", *argv++); debug_printf("\n"); } @@ -98,11 +98,11 @@ Returns: nothing void debug_print_string(uschar *debug_string) { -if (debug_string == NULL) return; +if (!debug_string) return; HDEBUG(D_any|D_v) { uschar *s = expand_string(debug_string); - if (s == NULL) + if (!s) debug_printf("failed to expand debug_output \"%s\": %s\n", debug_string, expand_string_message); else if (s[0] != 0) @@ -195,9 +195,7 @@ if (debug_ptr == debug_buffer) } DEBUG(D_pid) - { debug_ptr += sprintf(CS debug_ptr, "%5d ", (int)getpid()); - } /* Set up prefix if outputting for host checking and not debugging */ diff --git a/src/src/deliver.c b/src/src/deliver.c index 648c63d69..1241fa3cf 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -702,62 +702,58 @@ you can enable incoming_interface and disable outgoing_interface to get I= fields on incoming lines only. Arguments: - s The log line buffer - sizep Pointer to the buffer size - ptrp Pointer to current index into buffer + g The log line addr The address to be logged Returns: New value for s */ -static uschar * -d_log_interface(uschar *s, int *sizep, int *ptrp) +static gstring * +d_log_interface(gstring * g) { if (LOGGING(incoming_interface) && LOGGING(outgoing_interface) && sending_ip_address) { - s = string_append(s, sizep, ptrp, 2, US" I=[", sending_ip_address); - s = LOGGING(outgoing_port) - ? string_append(s, sizep, ptrp, 2, US"]:", - string_sprintf("%d", sending_port)) - : string_catn(s, sizep, ptrp, US"]", 1); + g = string_append(g, 2, US" I=[", sending_ip_address); + g = LOGGING(outgoing_port) + ? string_append(g, 2, US"]:", string_sprintf("%d", sending_port)) + : string_catn(g, US"]", 1); } -return s; +return g; } -static uschar * -d_hostlog(uschar * s, int * sp, int * pp, address_item * addr) +static gstring * +d_hostlog(gstring * g, address_item * addr) { host_item * h = addr->host_used; -s = string_append(s, sp, pp, 2, US" H=", h->name); +g = string_append(g, 2, US" H=", h->name); if (LOGGING(dnssec) && h->dnssec == DS_YES) - s = string_catn(s, sp, pp, US" DS", 3); + g = string_catn(g, US" DS", 3); -s = string_append(s, sp, pp, 3, US" [", h->address, US"]"); +g = string_append(g, 3, US" [", h->address, US"]"); if (LOGGING(outgoing_port)) - s = string_append(s, sp, pp, 2, US":", string_sprintf("%d", h->port)); + g = string_append(g, 2, US":", string_sprintf("%d", h->port)); #ifdef SUPPORT_SOCKS if (LOGGING(proxy) && proxy_local_address) { - s = string_append(s, sp, pp, 3, US" PRX=[", proxy_local_address, US"]"); + g = string_append(g, 3, US" PRX=[", proxy_local_address, US"]"); if (LOGGING(outgoing_port)) - s = string_append(s, sp, pp, 2, US":", string_sprintf("%d", - proxy_local_port)); + g = string_append(g, 2, US":", string_sprintf("%d", proxy_local_port)); } #endif -s = d_log_interface(s, sp, pp); +g = d_log_interface(g); if (testflag(addr, af_tcp_fastopen)) - s = string_catn(s, sp, pp, US" TFO", 4); + g = string_catn(g, US" TFO", 4); -return s; +return g; } @@ -765,13 +761,13 @@ return s; #ifdef SUPPORT_TLS -static uschar * -d_tlslog(uschar * s, int * sizep, int * ptrp, address_item * addr) +static gstring * +d_tlslog(gstring * s, address_item * addr) { if (LOGGING(tls_cipher) && addr->cipher) - s = string_append(s, sizep, ptrp, 2, US" X=", addr->cipher); + s = string_append(s, 2, US" X=", addr->cipher); if (LOGGING(tls_certificate_verified) && addr->cipher) - s = string_append(s, sizep, ptrp, 2, US" CV=", + s = string_append(s, 2, US" CV=", testflag(addr, af_cert_verified) ? #ifdef EXPERIMENTAL_DANE @@ -782,8 +778,7 @@ if (LOGGING(tls_certificate_verified) && addr->cipher) "yes" : "no"); if (LOGGING(tls_peerdn) && addr->peerdn) - s = string_append(s, sizep, ptrp, 3, US" DN=\"", - string_printing(addr->peerdn), US"\""); + s = string_append(s, 3, US" DN=\"", string_printing(addr->peerdn), US"\""); return s; } #endif @@ -873,15 +868,12 @@ router_name = transport_name = NULL; Arguments: addr the address being logged yield the current dynamic buffer pointer - sizeptr points to current size - ptrptr points to current insert pointer Returns: the new value of the buffer pointer */ -static uschar * -string_get_localpart(address_item *addr, uschar *yield, int *sizeptr, - int *ptrptr) +static gstring * +string_get_localpart(address_item * addr, gstring * yield) { uschar * s; @@ -892,7 +884,7 @@ if (testflag(addr, af_include_affixes) && s) if (testflag(addr, af_utf8_downcvt)) s = string_localpart_utf8_to_alabel(s, NULL); #endif - yield = string_cat(yield, sizeptr, ptrptr, s); + yield = string_cat(yield, s); } s = addr->local_part; @@ -900,7 +892,7 @@ s = addr->local_part; if (testflag(addr, af_utf8_downcvt)) s = string_localpart_utf8_to_alabel(s, NULL); #endif -yield = string_cat(yield, sizeptr, ptrptr, s); +yield = string_cat(yield, s); s = addr->suffix; if (testflag(addr, af_include_affixes) && s) @@ -909,7 +901,7 @@ if (testflag(addr, af_include_affixes) && s) if (testflag(addr, af_utf8_downcvt)) s = string_localpart_utf8_to_alabel(s, NULL); #endif - yield = string_cat(yield, sizeptr, ptrptr, s); + yield = string_cat(yield, s); } return yield; @@ -927,9 +919,7 @@ affixes set, the af_include_affixes bit will be set in the address. In that case, we include the affixes here too. Arguments: - str points to start of growing string, or NULL - size points to current allocation for string - ptr points to offset for append point; updated on exit + g points to growing-string struct addr bottom (ultimate) address all_parents if TRUE, include all parents success TRUE for successful delivery @@ -937,8 +927,8 @@ Arguments: Returns: a growable string in dynamic store */ -static uschar * -string_log_address(uschar * str, int * size, int * ptr, +static gstring * +string_log_address(gstring * g, address_item *addr, BOOL all_parents, BOOL success) { BOOL add_topaddr = TRUE; @@ -962,8 +952,8 @@ if ( testflag(addr, af_pfr) ) ) { if (testflag(addr, af_file) && addr->local_part[0] != '/') - str = string_catn(str, size, ptr, CUS"save ", 5); - str = string_get_localpart(addr, str, size, ptr); + g = string_catn(g, CUS"save ", 5); + g = string_get_localpart(addr, g); } /* Other deliveries start with the full address. It we have split it into local @@ -972,29 +962,31 @@ splitting is done; in those cases use the original field. */ else { - uschar * cmp = str + *ptr; + uschar * cmp = g->s + g->ptr; if (addr->local_part) { const uschar * s; - str = string_get_localpart(addr, str, size, ptr); - str = string_catn(str, size, ptr, US"@", 1); + g = string_get_localpart(addr, g); + g = string_catn(g, US"@", 1); s = addr->domain; #ifdef SUPPORT_I18N if (testflag(addr, af_utf8_downcvt)) s = string_localpart_utf8_to_alabel(s, NULL); #endif - str = string_cat(str, size, ptr, s); + g = string_cat(g, s); } else - str = string_cat(str, size, ptr, addr->address); + g = string_cat(g, addr->address); /* If the address we are going to print is the same as the top address, and all parents are not being included, don't add on the top address. First of all, do a caseless comparison; if this succeeds, do a caseful comparison on the local parts. */ + /*XXX dodgy coding. the string at "cmp" might not be nul-terminated if + we had to extend the allocation! */ - str[*ptr] = 0; + g->s[g->ptr] = '\0'; if ( strcmpic(cmp, topaddr->address) == 0 && Ustrncmp(cmp, topaddr->address, Ustrchr(cmp, '@') - cmp) == 0 && !addr->onetime_parent @@ -1015,23 +1007,23 @@ if ( (all_parents || testflag(addr, af_pfr)) address_item *addr2; for (addr2 = addr->parent; addr2 != topaddr; addr2 = addr2->parent) { - str = string_catn(str, size, ptr, s, 2); - str = string_cat (str, size, ptr, addr2->address); + g = string_catn(g, s, 2); + g = string_cat (g, addr2->address); if (!all_parents) break; s = US", "; } - str = string_catn(str, size, ptr, US")", 1); + g = string_catn(g, US")", 1); } /* Add the top address if it is required */ if (add_topaddr) - str = string_append(str, size, ptr, 3, + g = string_append(g, 3, US" <", addr->onetime_parent ? addr->onetime_parent : topaddr->address, US">"); -return str; +return g; } @@ -1086,9 +1078,7 @@ Arguments: void delivery_log(int flags, address_item * addr, int logchar, uschar * msg) { -int size = 256; /* Used for a temporary, */ -int ptr = 0; /* expanding buffer, for */ -uschar * s; /* building log lines; */ +gstring * g; /* Used for a temporary, expanding buffer, for building log lines */ void * reset_point; /* released afterwards. */ /* Log the delivery on the main log. We use an extensible string to build up @@ -1101,19 +1091,19 @@ pointer to a single host item in their host list, for use by the transport. */ lookup_dnssec_authenticated = NULL; #endif -s = reset_point = store_get(size); +g = reset_point = string_get(256); if (msg) - s = string_append(s, &size, &ptr, 2, host_and_ident(TRUE), US" "); + g = string_append(g, 2, host_and_ident(TRUE), US" "); else { - s[ptr++] = logchar; - s = string_catn(s, &size, &ptr, US"> ", 2); + g->s[0] = logchar; g->ptr = 1; + g = string_catn(g, US"> ", 2); } -s = string_log_address(s, &size, &ptr, addr, LOGGING(all_parents), TRUE); +g = string_log_address(g, addr, LOGGING(all_parents), TRUE); if (LOGGING(sender_on_delivery) || msg) - s = string_append(s, &size, &ptr, 3, US" F=<", + g = string_append(g, 3, US" F=<", #ifdef SUPPORT_I18N testflag(addr, af_utf8_downcvt) ? string_address_utf8_to_alabel(sender_address, NULL) @@ -1123,11 +1113,11 @@ if (LOGGING(sender_on_delivery) || msg) US">"); if (*queue_name) - s = string_append(s, &size, &ptr, 2, US" Q=", queue_name); + g = string_append(g, 2, US" Q=", queue_name); #ifdef EXPERIMENTAL_SRS if(addr->prop.srs_sender) - s = string_append(s, &size, &ptr, 3, US" SRS=<", addr->prop.srs_sender, US">"); + g = string_append(g, 3, US" SRS=<", addr->prop.srs_sender, US">"); #endif /* You might think that the return path must always be set for a successful @@ -1136,19 +1126,19 @@ when it is not set is for a delivery to /dev/null which is optimised by not being run at all. */ if (used_return_path && LOGGING(return_path_on_delivery)) - s = string_append(s, &size, &ptr, 3, US" P=<", used_return_path, US">"); + g = string_append(g, 3, US" P=<", used_return_path, US">"); if (msg) - s = string_append(s, &size, &ptr, 2, US" ", msg); + g = string_append(g, 2, US" ", msg); /* For a delivery from a system filter, there may not be a router */ if (addr->router) - s = string_append(s, &size, &ptr, 2, US" R=", addr->router->name); + g = string_append(g, 2, US" R=", addr->router->name); -s = string_append(s, &size, &ptr, 2, US" T=", addr->transport->name); +g = string_append(g, 2, US" T=", addr->transport->name); if (LOGGING(delivery_size)) - s = string_append(s, &size, &ptr, 2, US" S=", + g = string_append(g, 2, US" S=", string_sprintf("%d", transport_count)); /* Local delivery */ @@ -1156,10 +1146,10 @@ if (LOGGING(delivery_size)) if (addr->transport->info->local) { if (addr->host_list) - s = string_append(s, &size, &ptr, 2, US" H=", addr->host_list->name); - s = d_log_interface(s, &size, &ptr); + g = string_append(g, 2, US" H=", addr->host_list->name); + g = d_log_interface(g); if (addr->shadow_message) - s = string_cat(s, &size, &ptr, addr->shadow_message); + g = string_cat(g, addr->shadow_message); } /* Remote delivery */ @@ -1168,9 +1158,9 @@ else { if (addr->host_used) { - s = d_hostlog(s, &size, &ptr, addr); + g = d_hostlog(g, addr); if (continue_sequence > 1) - s = string_catn(s, &size, &ptr, US"*", 1); + g = string_catn(g, US"*", 1); #ifndef DISABLE_EVENT deliver_host_address = addr->host_used->address; @@ -1185,27 +1175,27 @@ else } #ifdef SUPPORT_TLS - s = d_tlslog(s, &size, &ptr, addr); + g = d_tlslog(g, addr); #endif if (addr->authenticator) { - s = string_append(s, &size, &ptr, 2, US" A=", addr->authenticator); + g = string_append(g, 2, US" A=", addr->authenticator); if (addr->auth_id) { - s = string_append(s, &size, &ptr, 2, US":", addr->auth_id); + g = string_append(g, 2, US":", addr->auth_id); if (LOGGING(smtp_mailauth) && addr->auth_sndr) - s = string_append(s, &size, &ptr, 2, US":", addr->auth_sndr); + g = string_append(g, 2, US":", addr->auth_sndr); } } #ifndef DISABLE_PRDR if (testflag(addr, af_prdr_used)) - s = string_catn(s, &size, &ptr, US" PRDR", 5); + g = string_catn(g, US" PRDR", 5); #endif if (testflag(addr, af_chunking_used)) - s = string_catn(s, &size, &ptr, US" K", 2); + g = string_catn(g, US" K", 2); } /* confirmation message (SMTP (host_used) and LMTP (driver_name)) */ @@ -1227,26 +1217,25 @@ if ( LOGGING(smtp_confirmation) } *p++ = '\"'; *p = 0; - s = string_append(s, &size, &ptr, 2, US" C=", big_buffer); + g = string_append(g, 2, US" C=", big_buffer); } /* Time on queue and actual time taken to deliver */ if (LOGGING(queue_time)) - s = string_append(s, &size, &ptr, 2, US" QT=", + g = string_append(g, 2, US" QT=", string_timesince(&received_time)); if (LOGGING(deliver_time)) { struct timeval diff = {.tv_sec = addr->more_errno, .tv_usec = addr->delivery_usec}; - s = string_append(s, &size, &ptr, 2, US" DT=", string_timediff(&diff)); + g = string_append(g, 2, US" DT=", string_timediff(&diff)); } /* string_cat() always leaves room for the terminator. Release the store we used to build the line after writing it. */ -s[ptr] = 0; -log_write(0, flags, "%s", s); +log_write(0, flags, "%s", string_from_gstring(g)); #ifndef DISABLE_EVENT if (!msg) msg_event_raise(US"msg:delivery", addr); @@ -1262,25 +1251,21 @@ static void deferral_log(address_item * addr, uschar * now, int logflags, uschar * driver_name, uschar * driver_kind) { -int size = 256; /* Used for a temporary, */ -int ptr = 0; /* expanding buffer, for */ -uschar * s; /* building log lines; */ -void * reset_point; /* released afterwards. */ - -uschar ss[32]; +gstring * g; +void * reset_point; /* Build up the line that is used for both the message log and the main log. */ -s = reset_point = store_get(size); +g = reset_point = string_get(256); /* Create the address string for logging. Must not do this earlier, because an OK result may be changed to FAIL when a pipe returns text. */ -s = string_log_address(s, &size, &ptr, addr, LOGGING(all_parents), FALSE); +g = string_log_address(g, addr, LOGGING(all_parents), FALSE); if (*queue_name) - s = string_append(s, &size, &ptr, 2, US" Q=", queue_name); + g = string_append(g, 2, US" Q=", queue_name); /* Either driver_name contains something and driver_kind contains " router" or " transport" (note the leading space), or driver_name is @@ -1291,45 +1276,42 @@ so nothing has been done at all, both variables contain null strings. */ if (driver_name) { if (driver_kind[1] == 't' && addr->router) - s = string_append(s, &size, &ptr, 2, US" R=", addr->router->name); - Ustrcpy(ss, " ?="); - ss[1] = toupper(driver_kind[1]); - s = string_append(s, &size, &ptr, 2, ss, driver_name); + g = string_append(g, 2, US" R=", addr->router->name); + g = string_cat(g, string_sprintf(" %c=%s", toupper(driver_kind[1]), driver_name)); } else if (driver_kind) - s = string_append(s, &size, &ptr, 2, US" ", driver_kind); + g = string_append(g, 2, US" ", driver_kind); /*XXX need an s+s+p sprintf */ -sprintf(CS ss, " defer (%d)", addr->basic_errno); -s = string_cat(s, &size, &ptr, ss); +g = string_cat(g, string_sprintf(" defer (%d)", addr->basic_errno)); if (addr->basic_errno > 0) - s = string_append(s, &size, &ptr, 2, US": ", + g = string_append(g, 2, US": ", US strerror(addr->basic_errno)); if (addr->host_used) { - s = string_append(s, &size, &ptr, 5, + g = string_append(g, 5, US" H=", addr->host_used->name, US" [", addr->host_used->address, US"]"); if (LOGGING(outgoing_port)) { int port = addr->host_used->port; - s = string_append(s, &size, &ptr, 2, + g = string_append(g, 2, US":", port == PORT_NONE ? US"25" : string_sprintf("%d", port)); } } if (addr->message) - s = string_append(s, &size, &ptr, 2, US": ", addr->message); + g = string_append(g, 2, US": ", addr->message); -s[ptr] = 0; +(void) string_from_gstring(g); /* Log the deferment in the message log, but don't clutter it up with retry-time defers after the first delivery attempt. */ if (deliver_firsttime || addr->basic_errno > ERRNO_RETRY_BASE) - deliver_msglog("%s %s\n", now, s); + deliver_msglog("%s %s\n", now, g->s); /* Write the main log and reset the store. For errors of the type "retry time not reached" (also remotes skipped @@ -1339,7 +1321,7 @@ others. */ log_write(addr->basic_errno <= ERRNO_RETRY_BASE ? L_retry_defer : 0, logflags, - "== %s", s); + "== %s", g->s); store_reset(reset_point); return; @@ -1350,60 +1332,56 @@ return; static void failure_log(address_item * addr, uschar * driver_kind, uschar * now) { -int size = 256; /* Used for a temporary, */ -int ptr = 0; /* expanding buffer, for */ -uschar * s; /* building log lines; */ -void * reset_point; /* released afterwards. */ +void * reset_point; +gstring * g = reset_point = string_get(256); /* Build up the log line for the message and main logs */ -s = reset_point = store_get(size); - /* Create the address string for logging. Must not do this earlier, because an OK result may be changed to FAIL when a pipe returns text. */ -s = string_log_address(s, &size, &ptr, addr, LOGGING(all_parents), FALSE); +g = string_log_address(g, addr, LOGGING(all_parents), FALSE); if (LOGGING(sender_on_delivery)) - s = string_append(s, &size, &ptr, 3, US" F=<", sender_address, US">"); + g = string_append(g, 3, US" F=<", sender_address, US">"); if (*queue_name) - s = string_append(s, &size, &ptr, 2, US" Q=", queue_name); + g = string_append(g, 2, US" Q=", queue_name); /* Return path may not be set if no delivery actually happened */ if (used_return_path && LOGGING(return_path_on_delivery)) - s = string_append(s, &size, &ptr, 3, US" P=<", used_return_path, US">"); + g = string_append(g, 3, US" P=<", used_return_path, US">"); if (addr->router) - s = string_append(s, &size, &ptr, 2, US" R=", addr->router->name); + g = string_append(g, 2, US" R=", addr->router->name); if (addr->transport) - s = string_append(s, &size, &ptr, 2, US" T=", addr->transport->name); + g = string_append(g, 2, US" T=", addr->transport->name); if (addr->host_used) - s = d_hostlog(s, &size, &ptr, addr); + g = d_hostlog(g, addr); #ifdef SUPPORT_TLS -s = d_tlslog(s, &size, &ptr, addr); +g = d_tlslog(g, addr); #endif if (addr->basic_errno > 0) - s = string_append(s, &size, &ptr, 2, US": ", US strerror(addr->basic_errno)); + g = string_append(g, 2, US": ", US strerror(addr->basic_errno)); if (addr->message) - s = string_append(s, &size, &ptr, 2, US": ", addr->message); + g = string_append(g, 2, US": ", addr->message); -s[ptr] = 0; +(void) string_from_gstring(g); /* Do the logging. For the message log, "routing failed" for those cases, just to make it clearer. */ if (driver_kind) - deliver_msglog("%s %s failed for %s\n", now, driver_kind, s); + deliver_msglog("%s %s failed for %s\n", now, driver_kind, g->s); else - deliver_msglog("%s %s\n", now, s); + deliver_msglog("%s %s\n", now, g->s); -log_write(0, LOG_MAIN, "** %s", s); +log_write(0, LOG_MAIN, "** %s", g->s); #ifndef DISABLE_EVENT msg_event_raise(US"msg:fail:delivery", addr); @@ -5153,9 +5131,8 @@ Returns: NULL or an expanded string static uschar * next_emf(FILE *f, uschar *which) { -int size = 256; -int ptr = 0; -uschar *para, *yield; +uschar *yield; +gstring * para; uschar buffer[256]; if (!f) return NULL; @@ -5163,16 +5140,14 @@ if (!f) return NULL; if (!Ufgets(buffer, sizeof(buffer), f) || Ustrcmp(buffer, "****\n") == 0) return NULL; -para = store_get(size); +para = string_get(256); for (;;) { - para = string_cat(para, &size, &ptr, buffer); + para = string_cat(para, buffer); if (!Ufgets(buffer, sizeof(buffer), f) || Ustrcmp(buffer, "****\n") == 0) break; } -para[ptr] = 0; - -if ((yield = expand_string(para))) +if ((yield = expand_string(string_from_gstring(para)))) return yield; log_write(0, LOG_MAIN|LOG_PANIC, "Failed to expand string from " diff --git a/src/src/dkim.c b/src/src/dkim.c index cd8a16ae6..723267cbf 100644 --- a/src/src/dkim.c +++ b/src/src/dkim.c @@ -126,6 +126,7 @@ dkim_exim_verify_finish(void) { pdkim_signature * sig = NULL; int dkim_signers_size = 0, dkim_signers_ptr = 0, rc; +gstring * g = NULL; const uschar * errstr; store_pool = POOL_PERM; @@ -158,113 +159,106 @@ if (rc != PDKIM_OK) for (sig = dkim_signatures; sig; sig = sig->next) { - int size = 0, ptr = 0; - uschar * logmsg = NULL, * s; + uschar * s; + gstring * logmsg; /* Log a line for each signature */ if (!(s = sig->domain)) s = US""; - logmsg = string_append(logmsg, &size, &ptr, 2, "d=", s); + logmsg = string_append(NULL, 2, "d=", s); if (!(s = sig->selector)) s = US""; - logmsg = string_append(logmsg, &size, &ptr, 2, " s=", s); - logmsg = string_append(logmsg, &size, &ptr, 7, + logmsg = string_append(logmsg, 2, " s=", s); + logmsg = string_append(logmsg, 7, " c=", sig->canon_headers == PDKIM_CANON_SIMPLE ? "simple" : "relaxed", "/", sig->canon_body == PDKIM_CANON_SIMPLE ? "simple" : "relaxed", " a=", dkim_sig_to_a_tag(sig), string_sprintf(" b=%d", (int)sig->sighash.len > -1 ? sig->sighash.len * 8 : 0)); - if ((s= sig->identity)) logmsg = string_append(logmsg, &size, &ptr, 2, " i=", s); - if (sig->created > 0) logmsg = string_append(logmsg, &size, &ptr, 1, + if ((s= sig->identity)) logmsg = string_append(logmsg, 2, " i=", s); + if (sig->created > 0) logmsg = string_cat(logmsg, string_sprintf(" t=%lu", sig->created)); - if (sig->expires > 0) logmsg = string_append(logmsg, &size, &ptr, 1, + if (sig->expires > 0) logmsg = string_cat(logmsg, string_sprintf(" x=%lu", sig->expires)); - if (sig->bodylength > -1) logmsg = string_append(logmsg, &size, &ptr, 1, + if (sig->bodylength > -1) logmsg = string_cat(logmsg, string_sprintf(" l=%lu", sig->bodylength)); switch (sig->verify_status) { case PDKIM_VERIFY_NONE: - logmsg = string_append(logmsg, &size, &ptr, 1, " [not verified]"); + logmsg = string_cat(logmsg, " [not verified]"); break; case PDKIM_VERIFY_INVALID: - logmsg = string_append(logmsg, &size, &ptr, 1, " [invalid - "); + logmsg = string_cat(logmsg, " [invalid - "); switch (sig->verify_ext_status) { case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE: - logmsg = string_append(logmsg, &size, &ptr, 1, + logmsg = string_cat(logmsg, "public key record (currently?) unavailable]"); break; case PDKIM_VERIFY_INVALID_BUFFER_SIZE: - logmsg = string_append(logmsg, &size, &ptr, 1, - "overlong public key record]"); + logmsg = string_cat(logmsg, "overlong public key record]"); break; case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD: case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT: - logmsg = string_append(logmsg, &size, &ptr, 1, - "syntax error in public key record]"); + logmsg = string_cat(logmsg, "syntax error in public key record]"); break; case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR: - logmsg = string_append(logmsg, &size, &ptr, 1, - "signature tag missing or invalid]"); + logmsg = string_cat(logmsg, "signature tag missing or invalid]"); break; case PDKIM_VERIFY_INVALID_DKIM_VERSION: - logmsg = string_append(logmsg, &size, &ptr, 1, - "unsupported DKIM version]"); + logmsg = string_cat(logmsg, "unsupported DKIM version]"); break; default: - logmsg = string_append(logmsg, &size, &ptr, 1, - "unspecified problem]"); + logmsg = string_cat(logmsg, "unspecified problem]"); } break; case PDKIM_VERIFY_FAIL: logmsg = - string_append(logmsg, &size, &ptr, 1, " [verification failed - "); + string_cat(logmsg, " [verification failed - "); switch (sig->verify_ext_status) { case PDKIM_VERIFY_FAIL_BODY: - logmsg = string_append(logmsg, &size, &ptr, 1, + logmsg = string_cat(logmsg, "body hash mismatch (body probably modified in transit)]"); break; case PDKIM_VERIFY_FAIL_MESSAGE: - logmsg = string_append(logmsg, &size, &ptr, 1, + logmsg = string_cat(logmsg, "signature did not verify (headers probably modified in transit)]"); break; default: - logmsg = string_append(logmsg, &size, &ptr, 1, "unspecified reason]"); + logmsg = string_cat(logmsg, "unspecified reason]"); } break; case PDKIM_VERIFY_PASS: - logmsg = - string_append(logmsg, &size, &ptr, 1, " [verification succeeded]"); + logmsg = string_cat(logmsg, " [verification succeeded]"); break; } - logmsg[ptr] = '\0'; - log_write(0, LOG_MAIN, "DKIM: %s", logmsg); + log_write(0, LOG_MAIN, "DKIM: %s", string_from_gstring(logmsg)); /* Build a colon-separated list of signing domains (and identities, if present) in dkim_signers */ if (sig->domain) - dkim_signers = string_append_listele(dkim_signers, &dkim_signers_size, - &dkim_signers_ptr, ':', sig->domain); + g = string_append_listele(g, ':', sig->domain); if (sig->identity) - dkim_signers = string_append_listele(dkim_signers, &dkim_signers_size, - &dkim_signers_ptr, ':', sig->identity); + g = string_append_listele(g, ':', sig->identity); /* Process next signature */ } +if (g) dkim_signers = g->s; + out: store_pool = dkim_verify_oldpool; } @@ -453,19 +447,16 @@ switch (what) If a prefix is given, prepend it to the file for the calculations. */ -blob * +gstring * dkim_exim_sign(int fd, off_t off, uschar * prefix, struct ob_dkim * dkim, const uschar ** errstr) { const uschar * dkim_domain; int sep = 0; -uschar * seen_doms = NULL; -int seen_doms_size = 0; -int seen_doms_offset = 0; +gstring * seen_doms = NULL; pdkim_ctx ctx; pdkim_signature * sig; -blob * sigbuf = NULL; -int sigsize = 0; +gstring * sigbuf; int pdkim_rc; int sread; uschar buf[4096]; @@ -498,8 +489,7 @@ while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep, NULL, 0))) 0, NULL, NULL, MCL_STRING, TRUE, NULL) == OK) continue; - seen_doms = string_append_listele(seen_doms, &seen_doms_size, - &seen_doms_offset, ':', dkim_signing_domain); + seen_doms = string_append_listele(seen_doms, ':', dkim_signing_domain); /* Set $dkim_selector expansion variable to each selector in list, for this domain. */ @@ -648,23 +638,10 @@ if (sread == -1) if ((pdkim_rc = pdkim_feed_finish(&ctx, &sig, errstr)) != PDKIM_OK) goto pk_bad; -sigbuf = store_get(sizeof(blob)); -sigbuf->data = NULL; -sigbuf->len = 0; - -while (sig) - { - int len = sigbuf->len; - sigbuf->data = string_append(sigbuf->data, &sigsize, &len, 2, - US sig->signature_header, US"\r\n"); - sigbuf->len = len; - sig = sig->next; - } +for (sigbuf = NULL; sig; sig = sig->next) + sigbuf = string_append(sigbuf, 2, US sig->signature_header, US"\r\n"); -if (sigbuf->data) - sigbuf->data[sigbuf->len] = '\0'; -else - sigbuf->data = US""; +(void) string_from_gstring(sigbuf); CLEANUP: store_pool = old_pool; diff --git a/src/src/dkim.h b/src/src/dkim.h index a3419db42..8b12e21ed 100644 --- a/src/src/dkim.h +++ b/src/src/dkim.h @@ -6,7 +6,7 @@ /* See the file NOTICE for conditions of use and distribution. */ void dkim_exim_init(void); -blob * dkim_exim_sign(int, off_t, uschar *, struct ob_dkim *, const uschar **); +gstring * dkim_exim_sign(int, off_t, uschar *, struct ob_dkim *, const uschar **); void dkim_exim_verify_init(BOOL); void dkim_exim_verify_feed(uschar *, int); void dkim_exim_verify_finish(void); diff --git a/src/src/dkim_transport.c b/src/src/dkim_transport.c index 85a73dcae..b61c41edc 100644 --- a/src/src/dkim_transport.c +++ b/src/src/dkim_transport.c @@ -118,7 +118,7 @@ int save_fd = tctx->u.fd; int save_options = tctx->options; BOOL save_wireformat = spool_file_wireformat; uschar * hdrs; -blob * dkim_signature; +gstring * dkim_signature; int hsize; const uschar * errstr; BOOL rc; @@ -133,8 +133,8 @@ tctx->options = tctx->options & ~(topt_end_dot | topt_use_bdat) | topt_output_string | topt_no_body; rc = transport_write_message(tctx, 0); -hdrs = tctx->u.msg; -hdrs[hsize = tctx->msg_ptr] = '\0'; +hdrs = string_from_gstring(tctx->u.msg); +hsize = tctx->u.msg->ptr; tctx->u.fd = save_fd; tctx->options = save_options; @@ -163,8 +163,8 @@ tctx->options &= ~topt_escape_headers; spool_file_wireformat = TRUE; transport_write_reset(0); if ( ( dkim_signature - && dkim_signature->len > 0 - && !write_chunk(tctx, dkim_signature->data, dkim_signature->len) + && dkim_signature->ptr > 0 + && !write_chunk(tctx, dkim_signature->s, dkim_signature->ptr) ) || !write_chunk(tctx, hdrs, hsize) ) @@ -204,7 +204,7 @@ int dkim_fd; int save_errno = 0; BOOL rc; uschar * dkim_spool_name; -blob * dkim_signature; +gstring * dkim_signature; int options, dlen; off_t k_file_size; const uschar * errstr; @@ -258,7 +258,7 @@ if (!(dkim_signature = dkim_exim_sign(dkim_fd, 0, NULL, dkim, &errstr))) } } else - dlen = dkim_signature->len; + dlen = dkim_signature->ptr; #ifndef OS_SENDFILE if (options & topt_use_bdat) @@ -280,7 +280,7 @@ if (options & topt_use_bdat) { if ( tctx->chunk_cb(tctx, dlen, 0) != OK || !transport_write_block(tctx, - dkim_signature->data, dlen, FALSE) + dkim_signature->s, dlen, FALSE) || tctx->chunk_cb(tctx, 0, tc_reap_prev) != OK ) goto err; @@ -294,7 +294,7 @@ if (options & topt_use_bdat) goto err; } -if(dlen > 0 && !transport_write_block(tctx, dkim_signature->data, dlen, TRUE)) +if(dlen > 0 && !transport_write_block(tctx, dkim_signature->s, dlen, TRUE)) goto err; if (!dkt_send_file(tctx->u.fd, dkim_fd, 0, k_file_size)) diff --git a/src/src/exim.c b/src/src/exim.c index f09b26902..7114b7529 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -1149,8 +1149,7 @@ uschar * local_part_quote(uschar *lpart) { BOOL needs_quote = FALSE; -int size, ptr; -uschar *yield; +gstring * g; uschar *t; for (t = lpart; !needs_quote && *t != 0; t++) @@ -1161,26 +1160,24 @@ for (t = lpart; !needs_quote && *t != 0; t++) if (!needs_quote) return lpart; -size = ptr = 0; -yield = string_catn(NULL, &size, &ptr, US"\"", 1); +g = string_catn(NULL, US"\"", 1); for (;;) { uschar *nq = US Ustrpbrk(lpart, "\\\""); if (nq == NULL) { - yield = string_cat(yield, &size, &ptr, lpart); + g = string_cat(g, lpart); break; } - yield = string_catn(yield, &size, &ptr, lpart, nq - lpart); - yield = string_catn(yield, &size, &ptr, US"\\", 1); - yield = string_catn(yield, &size, &ptr, nq, 1); + g = string_catn(g, lpart, nq - lpart); + g = string_catn(g, US"\\", 1); + g = string_catn(g, nq, 1); lpart = nq + 1; } -yield = string_catn(yield, &size, &ptr, US"\"", 1); -yield[ptr] = 0; -return yield; +g = string_catn(g, US"\"", 1); +return string_from_gstring(g); } @@ -1253,11 +1250,9 @@ static uschar * get_stdinput(char *(*fn_readline)(const char *), void(*fn_addhist)(const char *)) { int i; -int size = 0; -int ptr = 0; -uschar *yield = NULL; +gstring * g = NULL; -if (fn_readline == NULL) { printf("> "); fflush(stdout); } +if (!fn_readline) { printf("> "); fflush(stdout); } for (i = 0;; i++) { @@ -1292,23 +1287,22 @@ for (i = 0;; i++) while (p < ss && isspace(*p)) p++; /* leading space after cont */ } - yield = string_catn(yield, &size, &ptr, p, ss - p); + g = string_catn(g, p, ss - p); #ifdef USE_READLINE - if (fn_readline != NULL) free(readline_line); + if (fn_readline) free(readline_line); #endif - /* yield can only be NULL if ss==p */ - if (ss == p || yield[ptr-1] != '\\') - { - if (yield) yield[ptr] = 0; + /* g can only be NULL if ss==p */ + if (ss == p || g->s[g->ptr-1] != '\\') break; - } - yield[--ptr] = 0; + + --g->ptr; + (void) string_from_gstring(g); } -if (yield == NULL) printf("\n"); -return yield; +if (!g) printf("\n"); +return string_from_gstring(g); } diff --git a/src/src/expand.c b/src/src/expand.c index 353b8ea56..9cbfbe883 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -1666,20 +1666,18 @@ generated from a system filter, but not elsewhere. */ static uschar * fn_recipients(void) { -if (!enable_dollar_recipients) return NULL; else +gstring * g = NULL; +int i; + +if (!enable_dollar_recipients) return NULL; + +for (i = 0; i < recipients_count; i++) { - int size = 128; - int ptr = 0; - int i; - uschar * s = store_get(size); - for (i = 0; i < recipients_count; i++) - { - if (i != 0) s = string_catn(s, &size, &ptr, US", ", 2); - s = string_cat(s, &size, &ptr, recipients_list[i].address); - } - s[ptr] = 0; /* string_cat() leaves room */ - return s; + /*XXX variant of list_appendele? */ + if (i != 0) g = string_catn(g, US", ", 2); + g = string_cat(g, recipients_list[i].address); } +return string_from_gstring(g); } @@ -2362,8 +2360,6 @@ switch(cond_type) uschar *sub[10]; uschar *user_msg; BOOL cond = FALSE; - int size = 0; - int ptr = 0; while (isspace(*s)) s++; if (*s++ != '{') goto COND_FAILED_CURLY_START; /*}*/ @@ -2387,10 +2383,7 @@ switch(cond_type) case FAIL: lookup_value = NULL; if (user_msg) - { - lookup_value = string_cat(NULL, &size, &ptr, user_msg); - lookup_value[ptr] = '\0'; - } + lookup_value = string_copy(user_msg); *yield = cond == testfor; break; @@ -3160,9 +3153,7 @@ Arguments: yes TRUE if the first string is to be used, else use the second save_lookup a value to put back into lookup_value before the 2nd expansion sptr points to the input string pointer - yieldptr points to the output string pointer - sizeptr points to the output string size - ptrptr points to the output string pointer + yieldptr points to the output growable-string pointer 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 @@ -3175,7 +3166,7 @@ Returns: 0 OK; lookup_value has been reset to save_lookup static int process_yesno(BOOL skipping, BOOL yes, uschar *save_lookup, const uschar **sptr, - uschar **yieldptr, int *sizeptr, int *ptrptr, uschar *type, BOOL *resetok) + gstring ** yieldptr, uschar *type, BOOL *resetok) { int rc = 0; const uschar *s = *sptr; /* Local value */ @@ -3193,12 +3184,12 @@ if (*s == '}') if (type[0] == 'i') { if (yes && !skipping) - *yieldptr = string_catn(*yieldptr, sizeptr, ptrptr, US"true", 4); + *yieldptr = string_catn(*yieldptr, US"true", 4); } else { if (yes && lookup_value && !skipping) - *yieldptr = string_cat(*yieldptr, sizeptr, ptrptr, lookup_value); + *yieldptr = string_cat(*yieldptr, lookup_value); lookup_value = save_lookup; } s++; @@ -3229,7 +3220,7 @@ if (*s++ != '}') /* If we want the first string, add it to the output */ if (yes) - *yieldptr = string_cat(*yieldptr, sizeptr, ptrptr, sub1); + *yieldptr = string_cat(*yieldptr, sub1); /* 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 @@ -3259,7 +3250,7 @@ if (*s == '{') /* If we want the second string, add it to the output */ if (!yes) - *yieldptr = string_cat(*yieldptr, sizeptr, ptrptr, sub2); + *yieldptr = string_cat(*yieldptr, sub2); } /* If there is no second string, but the word "fail" is present when the use of @@ -3423,8 +3414,9 @@ Returns: pointer to string containing the first three static uschar * prvs_hmac_sha1(uschar *address, uschar *key, uschar *key_num, uschar *daystamp) { -uschar *hash_source, *p; -int size = 0,offset = 0,i; +gstring * hash_source; +uschar * p; +int i; hctx h; uschar innerhash[20]; uschar finalhash[20]; @@ -3438,12 +3430,13 @@ if (key_num == NULL) if (Ustrlen(key) > 64) return NULL; -hash_source = string_catn(NULL, &size, &offset, key_num, 1); -hash_source = string_catn(hash_source, &size, &offset, daystamp, 3); -hash_source = string_cat(hash_source, &size, &offset, address); -hash_source[offset] = '\0'; +hash_source = string_catn(NULL, key_num, 1); +hash_source = string_catn(hash_source, daystamp, 3); +hash_source = string_cat(hash_source, address); +(void) string_from_gstring(hash_source); -DEBUG(D_expand) debug_printf_indent("prvs: hash source is '%s'\n", hash_source); +DEBUG(D_expand) + debug_printf_indent("prvs: hash source is '%s'\n", hash_source->s); memset(innerkey, 0x36, 64); memset(outerkey, 0x5c, 64); @@ -3456,7 +3449,7 @@ for (i = 0; i < Ustrlen(key); i++) chash_start(HMAC_SHA1, &h); chash_mid(HMAC_SHA1, &h, innerkey); -chash_end(HMAC_SHA1, &h, hash_source, offset, innerhash); +chash_end(HMAC_SHA1, &h, hash_source->s, hash_source->ptr, innerhash); chash_start(HMAC_SHA1, &h); chash_mid(HMAC_SHA1, &h, outerkey); @@ -3486,16 +3479,14 @@ newlines with a given string (optionally). Arguments: f the FILE - yield pointer to the expandable string - sizep pointer to the current size - ptrp pointer to the current position + yield pointer to the expandable string struct eol newline replacement string, or NULL -Returns: new value of string pointer +Returns: new pointer for expandable string, terminated if non-null */ -static uschar * -cat_file(FILE *f, uschar *yield, int *sizep, int *ptrp, uschar *eol) +static gstring * +cat_file(FILE *f, gstring *yield, uschar *eol) { uschar buffer[1024]; @@ -3503,13 +3494,12 @@ while (Ufgets(buffer, sizeof(buffer), f)) { int len = Ustrlen(buffer); if (eol && buffer[len-1] == '\n') len--; - yield = string_catn(yield, sizep, ptrp, buffer, len); + yield = string_catn(yield, buffer, len); if (eol && buffer[len]) - yield = string_cat(yield, sizep, ptrp, eol); + yield = string_cat(yield, eol); } -if (yield) yield[*ptrp] = 0; - +(void) string_from_gstring(yield); return yield; } @@ -3857,9 +3847,7 @@ static uschar * expand_string_internal(const uschar *string, BOOL ket_ends, const uschar **left, BOOL skipping, BOOL honour_dollar, BOOL *resetok_p) { -int ptr = 0; -int size = Ustrlen(string)+ 64; -uschar *yield = store_get(size); +gstring * yield = string_get(Ustrlen(string) + 64); int item_type; const uschar *s = string; uschar *save_expand_nstring[EXPAND_MAXN+1]; @@ -3899,7 +3887,7 @@ while (*s != 0) { const uschar * t = s + 2; for (s = t; *s != 0; s++) if (*s == '\\' && s[1] == 'N') break; - yield = string_catn(yield, &size, &ptr, t, s - t); + yield = string_catn(yield, t, s - t); if (*s != 0) s += 2; } @@ -3908,7 +3896,7 @@ while (*s != 0) uschar ch[1]; ch[0] = string_interpret_escape(&s); s++; - yield = string_catn(yield, &size, &ptr, ch, 1); + yield = string_catn(yield, ch, 1); } continue; @@ -3923,7 +3911,7 @@ while (*s != 0) if (*s != '$' || !honour_dollar) { - yield = string_catn(yield, &size, &ptr, s++, 1); + yield = string_catn(yield, s++, 1); continue; } @@ -3939,17 +3927,18 @@ while (*s != 0) { int len; int newsize = 0; + gstring * g; s = read_name(name, sizeof(name), s, US"_"); /* If this is the first thing to be expanded, release the pre-allocated buffer. */ - if (ptr == 0 && yield != NULL) + if (yield && yield->ptr == 0) { if (resetok) store_reset(yield); yield = NULL; - size = 0; + g = store_get(sizeof(gstring)); } /* Header */ @@ -3971,7 +3960,7 @@ while (*s != 0) has been omitted. Set a flag to adjust the error message in this case. But there is no error here - nothing gets inserted. */ - if (value == NULL) + if (!value) { if (Ustrchr(name, '}') != NULL) malformed_header = TRUE; continue; @@ -3992,16 +3981,19 @@ while (*s != 0) size of that buffer. If this is the first thing in an expansion string, yield will be NULL; just point it at the new store instead of copying. Many expansion strings contain just one reference, so this is a useful - optimization, especially for humungous headers. */ + optimization, especially for humungous headers. We need to use a gstring + structure that is not allocated after that new-buffer, else a later store + reset in the middle of the buffer will make it inaccessible. */ len = Ustrlen(value); - if (yield == NULL && newsize != 0) + if (!yield && newsize != 0) { - yield = value; - size = newsize; - ptr = len; + yield = g; + yield->size = newsize; + yield->ptr = len; + yield->s = value; } - else yield = string_catn(yield, &size, &ptr, value, len); + else yield = string_catn(yield, value, len); continue; } @@ -4011,8 +4003,7 @@ while (*s != 0) int n; s = read_cnumber(&n, s); if (n >= 0 && n <= expand_nmax) - yield = string_catn(yield, &size, &ptr, expand_nstring[n], - expand_nlength[n]); + yield = string_catn(yield, expand_nstring[n], expand_nlength[n]); continue; } @@ -4037,8 +4028,7 @@ while (*s != 0) goto EXPAND_FAILED; } if (n >= 0 && n <= expand_nmax) - yield = string_catn(yield, &size, &ptr, expand_nstring[n], - expand_nlength[n]); + yield = string_catn(yield, expand_nstring[n], expand_nlength[n]); continue; } @@ -4089,7 +4079,7 @@ while (*s != 0) DEBUG(D_expand) debug_printf_indent("acl expansion yield: %s\n", user_msg); if (user_msg) - yield = string_cat(yield, &size, &ptr, user_msg); + yield = string_cat(yield, user_msg); continue; case DEFER: @@ -4139,8 +4129,6 @@ while (*s != 0) lookup_value, /* value to reset for string2 */ &s, /* input pointer */ &yield, /* output pointer */ - &size, /* output size */ - &ptr, /* output current point */ US"if", /* condition type */ &resetok)) { @@ -4189,7 +4177,7 @@ while (*s != 0) if (!(encoded = imap_utf7_encode(sub_arg[0], headers_charset, sub_arg[1][0], sub_arg[2], &expand_string_message))) goto EXPAND_FAILED; - yield = string_cat(yield, &size, &ptr, encoded); + yield = string_cat(yield, encoded); } continue; } @@ -4377,8 +4365,6 @@ while (*s != 0) save_lookup_value, /* value to reset for string2 */ &s, /* input pointer */ &yield, /* output pointer */ - &size, /* output size */ - &ptr, /* output current point */ US"lookup", /* condition type */ &resetok)) { @@ -4410,7 +4396,7 @@ while (*s != 0) #else /* EXIM_PERL */ { uschar *sub_arg[EXIM_PERL_MAX_ARGS + 2]; - uschar *new_yield; + gstring *new_yield; if ((expand_forbid & RDO_PERL) != 0) { @@ -4455,7 +4441,7 @@ while (*s != 0) /* Call the function */ sub_arg[EXIM_PERL_MAX_ARGS + 1] = NULL; - new_yield = call_perl_cat(yield, &size, &ptr, &expand_string_message, + new_yield = call_perl_cat(yield, &expand_string_message, sub_arg[0], sub_arg + 1); /* NULL yield indicates failure; if the message pointer has been set to @@ -4529,14 +4515,14 @@ while (*s != 0) /* Now separate the domain from the local part */ *domain++ = '\0'; - yield = string_catn(yield, &size, &ptr, US"prvs=", 5); - yield = string_catn(yield, &size, &ptr, sub_arg[2] ? sub_arg[2] : US"0", 1); - yield = string_catn(yield, &size, &ptr, prvs_daystamp(7), 3); - yield = string_catn(yield, &size, &ptr, p, 6); - yield = string_catn(yield, &size, &ptr, US"=", 1); - yield = string_cat (yield, &size, &ptr, sub_arg[0]); - yield = string_catn(yield, &size, &ptr, US"@", 1); - yield = string_cat (yield, &size, &ptr, domain); + yield = string_catn(yield, US"prvs=", 5); + yield = string_catn(yield, sub_arg[2] ? sub_arg[2] : US"0", 1); + yield = string_catn(yield, prvs_daystamp(7), 3); + yield = string_catn(yield, p, 6); + yield = string_catn(yield, US"=", 1); + yield = string_cat (yield, sub_arg[0]); + yield = string_catn(yield, US"@", 1); + yield = string_cat (yield, domain); continue; } @@ -4546,7 +4532,7 @@ while (*s != 0) case EITEM_PRVSCHECK: { uschar *sub_arg[3]; - int mysize = 0, myptr = 0; + gstring * g; const pcre *re; uschar *p; @@ -4590,10 +4576,10 @@ while (*s != 0) DEBUG(D_expand) debug_printf_indent("prvscheck domain: %s\n", domain); /* Set up expansion variables */ - prvscheck_address = string_cat (NULL, &mysize, &myptr, local_part); - prvscheck_address = string_catn(prvscheck_address, &mysize, &myptr, US"@", 1); - prvscheck_address = string_cat (prvscheck_address, &mysize, &myptr, domain); - prvscheck_address[myptr] = '\0'; + g = string_cat (NULL, local_part); + g = string_catn(g, US"@", 1); + g = string_cat (g, domain); + prvscheck_address = string_from_gstring(g); prvscheck_keynum = string_copy(key_num); /* Now expand the second argument */ @@ -4609,7 +4595,7 @@ while (*s != 0) p = prvs_hmac_sha1(prvscheck_address, sub_arg[0], prvscheck_keynum, daystamp); - if (p == NULL) + if (!p) { expand_string_message = US"hmac-sha1 conversion failed"; goto EXPAND_FAILED; @@ -4658,7 +4644,7 @@ while (*s != 0) case 3: goto EXPAND_FAILED; } - yield = string_cat(yield, &size, &ptr, + yield = string_cat(yield, !sub_arg[0] || !*sub_arg[0] ? prvscheck_address : sub_arg[0]); /* Reset the "internal" variables afterwards, because they are in @@ -4714,7 +4700,7 @@ while (*s != 0) goto EXPAND_FAILED; } - yield = cat_file(f, yield, &size, &ptr, sub_arg[1]); + yield = cat_file(f, yield, sub_arg[1]); (void)fclose(f); continue; } @@ -4726,7 +4712,7 @@ while (*s != 0) { int fd; int timeout = 5; - int save_ptr = ptr; + int save_ptr = yield->ptr; FILE *f; uschar *arg; uschar *sub_arg[4]; @@ -4902,7 +4888,7 @@ while (*s != 0) f = fdopen(fd, "rb"); sigalrm_seen = FALSE; alarm(timeout); - yield = cat_file(f, yield, &size, &ptr, sub_arg[3]); + yield = cat_file(f, yield, sub_arg[3]); alarm(0); (void)fclose(f); @@ -4911,7 +4897,7 @@ while (*s != 0) if (sigalrm_seen) { - ptr = save_ptr; + yield->ptr = save_ptr; expand_string_message = US "socket read timed out"; goto SOCK_FAIL; } @@ -4949,7 +4935,7 @@ while (*s != 0) DEBUG(D_any) debug_printf("%s\n", expand_string_message); if (!(arg = expand_string_internal(s+1, TRUE, &s, FALSE, TRUE, &resetok))) goto EXPAND_FAILED; - yield = string_cat(yield, &size, &ptr, arg); + yield = string_cat(yield, arg); if (*s++ != '}') { expand_string_message = US"missing '}' closing failstring for readsocket"; @@ -4968,7 +4954,6 @@ while (*s != 0) const uschar **argv; pid_t pid; int fd_in, fd_out; - int lsize = 0, lptr = 0; if ((expand_forbid & RDO_RUN) != 0) { @@ -5029,7 +5014,7 @@ while (*s != 0) f = fdopen(fd_out, "rb"); sigalrm_seen = FALSE; alarm(60); - lookup_value = cat_file(f, NULL, &lsize, &lptr, NULL); + lookup_value = string_from_gstring(cat_file(f, NULL, NULL)); alarm(0); (void)fclose(f); @@ -5065,8 +5050,6 @@ while (*s != 0) lookup_value, /* value to reset for string2 */ &s, /* input pointer */ &yield, /* output pointer */ - &size, /* output size */ - &ptr, /* output current point */ US"run", /* condition type */ &resetok)) { @@ -5081,7 +5064,7 @@ while (*s != 0) case EITEM_TR: { - int oldptr = ptr; + int oldptr = yield->ptr; int o2m; uschar *sub[3]; @@ -5092,16 +5075,16 @@ while (*s != 0) case 3: goto EXPAND_FAILED; } - yield = string_cat(yield, &size, &ptr, sub[0]); + yield = string_cat(yield, sub[0]); o2m = Ustrlen(sub[2]) - 1; - if (o2m >= 0) for (; oldptr < ptr; oldptr++) + if (o2m >= 0) for (; oldptr < yield->ptr; oldptr++) { - uschar *m = Ustrrchr(sub[1], yield[oldptr]); + uschar *m = Ustrrchr(sub[1], yield->s[oldptr]); if (m != NULL) { int o = m - sub[1]; - yield[oldptr] = sub[2][(o < o2m)? o : o2m]; + yield->s[oldptr] = sub[2][(o < o2m)? o : o2m]; } } @@ -5169,7 +5152,7 @@ while (*s != 0) extract_substr(sub[2], val[0], val[1], &len); if (ret == NULL) goto EXPAND_FAILED; - yield = string_catn(yield, &size, &ptr, ret, len); + yield = string_catn(yield, ret, len); continue; } @@ -5279,7 +5262,7 @@ while (*s != 0) DEBUG(D_any) debug_printf("HMAC[%s](%.*s,%s)=%.*s\n", sub[0], (int)keylen, keyptr, sub[2], hashlen*2, finalhash_hex); - yield = string_catn(yield, &size, &ptr, finalhash_hex, hashlen*2); + yield = string_catn(yield, finalhash_hex, hashlen*2); } continue; } @@ -5350,7 +5333,7 @@ while (*s != 0) emptyopt = 0; continue; } - yield = string_catn(yield, &size, &ptr, subject+moffset, slen-moffset); + yield = string_catn(yield, subject+moffset, slen-moffset); break; } @@ -5367,11 +5350,10 @@ while (*s != 0) /* Copy the characters before the match, plus the expanded insertion. */ - yield = string_catn(yield, &size, &ptr, subject + moffset, - ovector[0] - moffset); + yield = string_catn(yield, subject + moffset, ovector[0] - moffset); insert = expand_string(sub[2]); if (insert == NULL) goto EXPAND_FAILED; - yield = string_cat(yield, &size, &ptr, insert); + yield = string_cat(yield, insert); moffset = ovector[1]; moffsetextra = 0; @@ -5521,8 +5503,6 @@ while (*s != 0) 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)) { @@ -5623,8 +5603,6 @@ while (*s != 0) save_lookup_value, /* value to reset for string2 */ &s, /* input pointer */ &yield, /* output pointer */ - &size, /* output size */ - &ptr, /* output current point */ US"listextract", /* condition type */ &resetok)) { @@ -5709,8 +5687,6 @@ while (*s != 0) save_lookup_value, /* value to reset for string2 */ &s, /* input pointer */ &yield, /* output pointer */ - &size, /* output size */ - &ptr, /* output current point */ US"certextract", /* condition type */ &resetok)) { @@ -5731,7 +5707,7 @@ while (*s != 0) case EITEM_REDUCE: { int sep = 0; - int save_ptr = ptr; + int save_ptr = yield->ptr; uschar outsep[2] = { '\0', '\0' }; const uschar *list, *expr, *temp; uschar *save_iterate_item = iterate_item; @@ -5877,8 +5853,8 @@ while (*s != 0) item of the output list, add in a space if the new item begins with the separator character, or is an empty string. */ - if (ptr != save_ptr && (temp[0] == *outsep || temp[0] == 0)) - yield = string_catn(yield, &size, &ptr, US" ", 1); + if (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, This is done in chunks by searching for the separator character. */ @@ -5887,21 +5863,21 @@ while (*s != 0) { size_t seglen = Ustrcspn(temp, outsep); - yield = string_catn(yield, &size, &ptr, temp, seglen + 1); + yield = string_catn(yield, temp, seglen + 1); /* If we got to the end of the string we output one character too many; backup and end the loop. Otherwise arrange to double the separator. */ - if (temp[seglen] == '\0') { ptr--; break; } - yield = string_catn(yield, &size, &ptr, outsep, 1); + if (temp[seglen] == '\0') { yield->ptr--; break; } + yield = string_catn(yield, outsep, 1); temp += seglen + 1; } /* Output a separator after the string: we will remove the redundant final one at the end. */ - yield = string_catn(yield, &size, &ptr, outsep, 1); + yield = string_catn(yield, outsep, 1); } /* End of iteration over the list loop */ /* REDUCE has generated no output above: output the final value of @@ -5909,7 +5885,7 @@ while (*s != 0) if (item_type == EITEM_REDUCE) { - yield = string_cat(yield, &size, &ptr, lookup_value); + yield = string_cat(yield, lookup_value); lookup_value = save_lookup_value; /* Restore $value */ } @@ -5917,7 +5893,7 @@ while (*s != 0) the redundant final separator. Even though an empty item at the end of a list does not count, this is tidier. */ - else if (ptr != save_ptr) ptr--; + else if (yield->ptr != save_ptr) yield->ptr--; /* Restore preserved $item */ @@ -5993,10 +5969,8 @@ while (*s != 0) while ((srcitem = string_nextinlist(&srclist, &sep, NULL, 0))) { uschar * dstitem; - uschar * newlist = NULL; - int size = 0, len = 0; - uschar * newkeylist = NULL; - int ksize = 0, klen = 0; + gstring * newlist = NULL; + gstring * newkeylist = NULL; uschar * srcfield; DEBUG(D_expand) debug_printf_indent("%s: $item = \"%s\"\n", name, srcitem); @@ -6041,44 +6015,44 @@ while (*s != 0) /* New-item sorts before this dst-item. Append new-item, then dst-item, then remainder of dst list. */ - newlist = string_append_listele(newlist, &size, &len, sep, srcitem); - newkeylist = string_append_listele(newkeylist, &ksize, &klen, sep, srcfield); + newlist = string_append_listele(newlist, sep, srcitem); + newkeylist = string_append_listele(newkeylist, sep, srcfield); srcitem = NULL; - newlist = string_append_listele(newlist, &size, &len, sep, dstitem); - newkeylist = string_append_listele(newkeylist, &ksize, &klen, sep, dstfield); + newlist = string_append_listele(newlist, sep, dstitem); + newkeylist = string_append_listele(newkeylist, sep, dstfield); while ((dstitem = string_nextinlist(&dstlist, &sep, NULL, 0))) { if (!(dstfield = string_nextinlist(&dstkeylist, &sep, NULL, 0))) goto sort_mismatch; - newlist = string_append_listele(newlist, &size, &len, sep, dstitem); - newkeylist = string_append_listele(newkeylist, &ksize, &klen, sep, dstfield); + newlist = string_append_listele(newlist, sep, dstitem); + newkeylist = string_append_listele(newkeylist, sep, dstfield); } break; } - newlist = string_append_listele(newlist, &size, &len, sep, dstitem); - newkeylist = string_append_listele(newkeylist, &ksize, &klen, sep, dstfield); + newlist = string_append_listele(newlist, sep, dstitem); + newkeylist = string_append_listele(newkeylist, sep, dstfield); } /* If we ran out of dstlist without consuming srcitem, append it */ if (srcitem) { - newlist = string_append_listele(newlist, &size, &len, sep, srcitem); - newkeylist = string_append_listele(newkeylist, &ksize, &klen, sep, srcfield); + newlist = string_append_listele(newlist, sep, srcitem); + newkeylist = string_append_listele(newkeylist, sep, srcfield); } - dstlist = newlist; - dstkeylist = newkeylist; + dstlist = newlist->s; + dstkeylist = newkeylist->s; DEBUG(D_expand) debug_printf_indent("%s: dstlist = \"%s\"\n", name, dstlist); DEBUG(D_expand) debug_printf_indent("%s: dstkeylist = \"%s\"\n", name, dstkeylist); } if (dstlist) - yield = string_cat(yield, &size, &ptr, dstlist); + yield = string_cat(yield, dstlist); /* Restore preserved $item */ iterate_item = save_iterate_item; @@ -6176,7 +6150,7 @@ while (*s != 0) if(status == OK) { if (result == NULL) result = US""; - yield = string_cat(yield, &size, &ptr, result); + yield = string_cat(yield, result); continue; } else @@ -6216,8 +6190,6 @@ while (*s != 0) save_lookup_value, /* value to reset for string2 */ &s, /* input pointer */ &yield, /* output pointer */ - &size, /* output size */ - &ptr, /* output current point */ US"env", /* condition type */ &resetok)) { @@ -6308,8 +6280,7 @@ while (*s != 0) { uschar *t; unsigned long int n = Ustrtoul(sub, &t, 10); - uschar * s = NULL; - int sz = 0, i = 0; + gstring * g = NULL; if (*t != 0) { @@ -6318,9 +6289,9 @@ while (*s != 0) goto EXPAND_FAILED; } for ( ; n; n >>= 5) - s = string_catn(s, &sz, &i, &base32_chars[n & 0x1f], 1); + g = string_catn(g, &base32_chars[n & 0x1f], 1); - while (i > 0) yield = string_catn(yield, &size, &ptr, &s[--i], 1); + if (g) while (g->ptr > 0) yield = string_catn(yield, &g->s[--g->ptr], 1); continue; } @@ -6341,7 +6312,7 @@ while (*s != 0) n = n * 32 + (t - base32_chars); } s = string_sprintf("%ld", n); - yield = string_cat(yield, &size, &ptr, s); + yield = string_cat(yield, s); continue; } @@ -6356,7 +6327,7 @@ while (*s != 0) goto EXPAND_FAILED; } t = string_base62(n); - yield = string_cat(yield, &size, &ptr, t); + yield = string_cat(yield, t); continue; } @@ -6380,7 +6351,7 @@ while (*s != 0) n = n * BASE_62 + (t - base62_chars); } (void)sprintf(CS buf, "%ld", n); - yield = string_cat(yield, &size, &ptr, buf); + yield = string_cat(yield, buf); continue; } @@ -6394,7 +6365,7 @@ while (*s != 0) expand_string_message); goto EXPAND_FAILED; } - yield = string_cat(yield, &size, &ptr, expanded); + yield = string_cat(yield, expanded); continue; } @@ -6403,7 +6374,7 @@ while (*s != 0) int count = 0; uschar *t = sub - 1; while (*(++t) != 0) { *t = tolower(*t); count++; } - yield = string_catn(yield, &size, &ptr, sub, count); + yield = string_catn(yield, sub, count); continue; } @@ -6412,7 +6383,7 @@ while (*s != 0) int count = 0; uschar *t = sub - 1; while (*(++t) != 0) { *t = toupper(*t); count++; } - yield = string_catn(yield, &size, &ptr, sub, count); + yield = string_catn(yield, sub, count); continue; } @@ -6421,7 +6392,7 @@ while (*s != 0) if (vp && *(void **)vp->value) { uschar * cp = tls_cert_fprt_md5(*(void **)vp->value); - yield = string_cat(yield, &size, &ptr, cp); + yield = string_cat(yield, cp); } else #endif @@ -6433,7 +6404,7 @@ while (*s != 0) md5_start(&base); md5_end(&base, sub, Ustrlen(sub), digest); for(j = 0; j < 16; j++) sprintf(st+2*j, "%02x", digest[j]); - yield = string_cat(yield, &size, &ptr, US st); + yield = string_cat(yield, US st); } continue; @@ -6442,7 +6413,7 @@ while (*s != 0) if (vp && *(void **)vp->value) { uschar * cp = tls_cert_fprt_sha1(*(void **)vp->value); - yield = string_cat(yield, &size, &ptr, cp); + yield = string_cat(yield, cp); } else #endif @@ -6454,7 +6425,7 @@ while (*s != 0) sha1_start(&h); sha1_end(&h, sub, Ustrlen(sub), digest); for(j = 0; j < 20; j++) sprintf(st+2*j, "%02X", digest[j]); - yield = string_catn(yield, &size, &ptr, US st, 40); + yield = string_catn(yield, US st, 40); } continue; @@ -6463,7 +6434,7 @@ while (*s != 0) if (vp && *(void **)vp->value) { uschar * cp = tls_cert_fprt_sha256(*(void **)vp->value); - yield = string_cat(yield, &size, &ptr, cp); + yield = string_cat(yield, cp); } else { @@ -6481,7 +6452,7 @@ while (*s != 0) while (b.len-- > 0) { sprintf(st, "%02X", *b.data++); - yield = string_catn(yield, &size, &ptr, US st, 2); + yield = string_catn(yield, US st, 2); } } #else @@ -6513,7 +6484,7 @@ while (*s != 0) while (b.len-- > 0) { sprintf(st, "%02X", *b.data++); - yield = string_catn(yield, &size, &ptr, US st, 2); + yield = string_catn(yield, US st, 2); } } continue; @@ -6566,7 +6537,7 @@ while (*s != 0) } enc = b64encode(sub, out - sub); - yield = string_cat(yield, &size, &ptr, enc); + yield = string_cat(yield, enc); continue; } @@ -6578,10 +6549,9 @@ while (*s != 0) while (*(++t) != 0) { if (*t < 0x21 || 0x7E < *t) - yield = string_catn(yield, &size, &ptr, - string_sprintf("\\x%02x", *t), 4); + yield = string_catn(yield, string_sprintf("\\x%02x", *t), 4); else - yield = string_catn(yield, &size, &ptr, t, 1); + yield = string_catn(yield, t, 1); } continue; } @@ -6597,7 +6567,7 @@ while (*s != 0) while (string_nextinlist(CUSS &sub, &sep, buffer, sizeof(buffer)) != NULL) cnt++; cp = string_sprintf("%d", cnt); - yield = string_cat(yield, &size, &ptr, cp); + yield = string_cat(yield, cp); continue; } @@ -6647,11 +6617,11 @@ while (*s != 0) list = ((namedlist_block *)(t->data.ptr))->string; - while ((item = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL) + while ((item = string_nextinlist(&list, &sep, buffer, sizeof(buffer)))) { uschar * buf = US" : "; if (needsep) - yield = string_catn(yield, &size, &ptr, buf, 3); + yield = string_catn(yield, buf, 3); else needsep = TRUE; @@ -6667,21 +6637,21 @@ while (*s != 0) tok[0] = sep; tok[1] = ':'; tok[2] = 0; while ((cp= strpbrk(CCS item, tok))) { - yield = string_catn(yield, &size, &ptr, item, cp-CS item); + yield = string_catn(yield, item, cp - CS item); if (*cp++ == ':') /* colon in a non-colon-sep list item, needs doubling */ { - yield = string_catn(yield, &size, &ptr, US"::", 2); + yield = string_catn(yield, US"::", 2); item = US cp; } else /* sep in item; should already be doubled; emit once */ { - yield = string_catn(yield, &size, &ptr, US tok, 1); + yield = string_catn(yield, US tok, 1); if (*cp == sep) cp++; item = US cp; } } } - yield = string_cat(yield, &size, &ptr, item); + yield = string_cat(yield, item); } continue; } @@ -6729,7 +6699,7 @@ while (*s != 0) /* Convert to masked textual format and add to output. */ - yield = string_catn(yield, &size, &ptr, buffer, + yield = string_catn(yield, buffer, host_nmtoa(count, binary, mask, buffer, '.')); continue; } @@ -6759,8 +6729,7 @@ while (*s != 0) goto EXPAND_FAILED; } - yield = string_catn(yield, &size, &ptr, buffer, - c == EOP_IPV6NORM + yield = string_catn(yield, buffer, c == EOP_IPV6NORM ? ipv6_nmtoa(binary, buffer) : host_nmtoa(4, binary, -1, buffer, ':') ); @@ -6779,12 +6748,12 @@ while (*s != 0) if (c != EOP_DOMAIN) { if (c == EOP_LOCAL_PART && domain != 0) end = start + domain - 1; - yield = string_catn(yield, &size, &ptr, sub+start, end-start); + yield = string_catn(yield, sub+start, end-start); } else if (domain != 0) { domain += start; - yield = string_catn(yield, &size, &ptr, sub+domain, end-domain); + yield = string_catn(yield, sub+domain, end-domain); } continue; } @@ -6793,7 +6762,7 @@ while (*s != 0) { uschar outsep[2] = { ':', '\0' }; uschar *address, *error; - int save_ptr = ptr; + int save_ptr = yield->ptr; int start, end, domain; /* Not really used */ while (isspace(*sub)) sub++; @@ -6817,26 +6786,26 @@ while (*s != 0) if (address != NULL) { - if (ptr != save_ptr && address[0] == *outsep) - yield = string_catn(yield, &size, &ptr, US" ", 1); + if (yield->ptr != save_ptr && address[0] == *outsep) + yield = string_catn(yield, US" ", 1); for (;;) { size_t seglen = Ustrcspn(address, outsep); - yield = string_catn(yield, &size, &ptr, address, seglen + 1); + yield = string_catn(yield, address, seglen + 1); /* If we got to the end of the string we output one character too many. */ - if (address[seglen] == '\0') { ptr--; break; } - yield = string_catn(yield, &size, &ptr, outsep, 1); + if (address[seglen] == '\0') { yield->ptr--; break; } + yield = string_catn(yield, outsep, 1); address += seglen + 1; } /* Output a separator after the string: we will remove the redundant final one at the end. */ - yield = string_catn(yield, &size, &ptr, outsep, 1); + yield = string_catn(yield, outsep, 1); } if (saveend == '\0') break; @@ -6846,7 +6815,7 @@ while (*s != 0) /* If we have generated anything, remove the redundant final separator. */ - if (ptr != save_ptr) ptr--; + if (yield->ptr != save_ptr) yield->ptr--; parse_allow_group = FALSE; continue; } @@ -6883,24 +6852,24 @@ while (*s != 0) if (needs_quote) { - yield = string_catn(yield, &size, &ptr, US"\"", 1); + yield = string_catn(yield, US"\"", 1); t = sub - 1; while (*(++t) != 0) { if (*t == '\n') - yield = string_catn(yield, &size, &ptr, US"\\n", 2); + yield = string_catn(yield, US"\\n", 2); else if (*t == '\r') - yield = string_catn(yield, &size, &ptr, US"\\r", 2); + yield = string_catn(yield, US"\\r", 2); else { if (*t == '\\' || *t == '"') - yield = string_catn(yield, &size, &ptr, US"\\", 1); - yield = string_catn(yield, &size, &ptr, t, 1); + yield = string_catn(yield, US"\\", 1); + yield = string_catn(yield, t, 1); } } - yield = string_catn(yield, &size, &ptr, US"\"", 1); + yield = string_catn(yield, US"\"", 1); } - else yield = string_cat(yield, &size, &ptr, sub); + else yield = string_cat(yield, sub); continue; } @@ -6932,7 +6901,7 @@ while (*s != 0) goto EXPAND_FAILED; } - yield = string_cat(yield, &size, &ptr, sub); + yield = string_cat(yield, sub); continue; } @@ -6945,8 +6914,8 @@ while (*s != 0) while (*(++t) != 0) { if (!isalnum(*t)) - yield = string_catn(yield, &size, &ptr, US"\\", 1); - yield = string_catn(yield, &size, &ptr, t, 1); + yield = string_catn(yield, US"\\", 1); + yield = string_catn(yield, t, 1); } continue; } @@ -6959,7 +6928,7 @@ while (*s != 0) uschar buffer[2048]; const uschar *string = parse_quote_2047(sub, Ustrlen(sub), headers_charset, buffer, sizeof(buffer), FALSE); - yield = string_cat(yield, &size, &ptr, string); + yield = string_cat(yield, string); continue; } @@ -6976,7 +6945,7 @@ while (*s != 0) expand_string_message = error; goto EXPAND_FAILED; } - yield = string_catn(yield, &size, &ptr, decoded, len); + yield = string_catn(yield, decoded, len); continue; } @@ -6992,7 +6961,7 @@ while (*s != 0) GETUTF8INC(c, sub); if (c > 255) c = '_'; buff[0] = c; - yield = string_catn(yield, &size, &ptr, buff, 1); + yield = string_catn(yield, buff, 1); } continue; } @@ -7027,7 +6996,7 @@ while (*s != 0) complete = -1; /* error (RFC3629 limit) */ else { /* finished; output utf-8 sequence */ - yield = string_catn(yield, &size, &ptr, seq_buff, seq_len); + yield = string_catn(yield, seq_buff, seq_len); index = 0; } } @@ -7036,7 +7005,7 @@ while (*s != 0) { if((c & 0x80) == 0) /* 1-byte sequence, US-ASCII, keep it */ { - yield = string_catn(yield, &size, &ptr, &c, 1); + yield = string_catn(yield, &c, 1); continue; } if((c & 0xe0) == 0xc0) /* 2-byte sequence */ @@ -7069,11 +7038,11 @@ while (*s != 0) if (complete != 0) { bytes_left = index = 0; - yield = string_catn(yield, &size, &ptr, UTF8_REPLACEMENT_CHAR, 1); + yield = string_catn(yield, UTF8_REPLACEMENT_CHAR, 1); } if ((complete == 1) && ((c & 0x80) == 0)) /* ASCII character follows incomplete sequence */ - yield = string_catn(yield, &size, &ptr, &c, 1); + yield = string_catn(yield, &c, 1); } continue; } @@ -7090,7 +7059,7 @@ while (*s != 0) string_printing(sub), error); goto EXPAND_FAILED; } - yield = string_cat(yield, &size, &ptr, s); + yield = string_cat(yield, s); continue; } @@ -7105,7 +7074,7 @@ while (*s != 0) string_printing(sub), error); goto EXPAND_FAILED; } - yield = string_cat(yield, &size, &ptr, s); + yield = string_cat(yield, s); continue; } @@ -7120,8 +7089,8 @@ while (*s != 0) string_printing(sub), error); goto EXPAND_FAILED; } - yield = string_cat(yield, &size, &ptr, s); - DEBUG(D_expand) debug_printf_indent("yield: '%s'\n", yield); + yield = string_cat(yield, s); + DEBUG(D_expand) debug_printf_indent("yield: '%s'\n", yield->s); continue; } @@ -7136,7 +7105,7 @@ while (*s != 0) string_printing(sub), error); goto EXPAND_FAILED; } - yield = string_cat(yield, &size, &ptr, s); + yield = string_cat(yield, s); continue; } #endif /* EXPERIMENTAL_INTERNATIONAL */ @@ -7146,7 +7115,7 @@ while (*s != 0) case EOP_ESCAPE: { const uschar * t = string_printing(sub); - yield = string_cat(yield, &size, &ptr, t); + yield = string_cat(yield, t); continue; } @@ -7157,8 +7126,8 @@ while (*s != 0) for (s = sub; (c = *s); s++) yield = c < 127 && c != '\\' - ? string_catn(yield, &size, &ptr, s, 1) - : string_catn(yield, &size, &ptr, string_sprintf("\\%03o", c), 4); + ? string_catn(yield, s, 1) + : string_catn(yield, string_sprintf("\\%03o", c), 4); continue; } @@ -7178,7 +7147,7 @@ while (*s != 0) goto EXPAND_FAILED; } sprintf(CS var_buffer, PR_EXIM_ARITH, n); - yield = string_cat(yield, &size, &ptr, var_buffer); + yield = string_cat(yield, var_buffer); continue; } @@ -7194,7 +7163,7 @@ while (*s != 0) goto EXPAND_FAILED; } sprintf(CS var_buffer, "%d", n); - yield = string_cat(yield, &size, &ptr, var_buffer); + yield = string_cat(yield, var_buffer); continue; } @@ -7209,7 +7178,7 @@ while (*s != 0) goto EXPAND_FAILED; } t = readconf_printtime(n); - yield = string_cat(yield, &size, &ptr, t); + yield = string_cat(yield, t); continue; } @@ -7225,7 +7194,7 @@ while (*s != 0) #else uschar * s = b64encode(sub, Ustrlen(sub)); #endif - yield = string_cat(yield, &size, &ptr, s); + yield = string_cat(yield, s); continue; } @@ -7239,7 +7208,7 @@ while (*s != 0) "well-formed for \"%s\" operator", sub, name); goto EXPAND_FAILED; } - yield = string_cat(yield, &size, &ptr, s); + yield = string_cat(yield, s); continue; } @@ -7249,7 +7218,7 @@ while (*s != 0) { uschar buff[24]; (void)sprintf(CS buff, "%d", Ustrlen(sub)); - yield = string_cat(yield, &size, &ptr, buff); + yield = string_cat(yield, buff); continue; } @@ -7340,7 +7309,7 @@ while (*s != 0) extract_substr(sub, value1, value2, &len); if (ret == NULL) goto EXPAND_FAILED; - yield = string_catn(yield, &size, &ptr, ret, len); + yield = string_catn(yield, ret, len); continue; } @@ -7395,7 +7364,7 @@ while (*s != 0) (long)st.st_dev, (long)st.st_nlink, (long)st.st_uid, (long)st.st_gid, st.st_size, (long)st.st_atime, (long)st.st_mtime, (long)st.st_ctime); - yield = string_cat(yield, &size, &ptr, s); + yield = string_cat(yield, s); continue; } @@ -7410,7 +7379,7 @@ while (*s != 0) if (expand_string_message != NULL) goto EXPAND_FAILED; s = string_sprintf("%d", vaguely_random_number((int)max)); - yield = string_cat(yield, &size, &ptr, s); + yield = string_cat(yield, s); continue; } @@ -7429,7 +7398,7 @@ while (*s != 0) goto EXPAND_FAILED; } invert_address(reversed, sub); - yield = string_cat(yield, &size, &ptr, reversed); + yield = string_cat(yield, reversed); continue; } @@ -7453,11 +7422,13 @@ while (*s != 0) { int len; int newsize = 0; - if (ptr == 0) + gstring * g; + + if (yield && yield->ptr == 0) { if (resetok) store_reset(yield); yield = NULL; - size = 0; + g = store_get(sizeof(gstring)); } if (!(value = find_variable(name, FALSE, skipping, &newsize))) { @@ -7469,12 +7440,13 @@ while (*s != 0) len = Ustrlen(value); if (!yield && newsize) { - yield = value; - size = newsize; - ptr = len; + yield = g; + yield->size = newsize; + yield->ptr = len; + yield->s = value; } else - yield = string_catn(yield, &size, &ptr, value, len); + yield = string_catn(yield, value, len); continue; } @@ -7502,15 +7474,16 @@ if (ket_ends && *s == 0) added to the string. If so, set up an empty string. Add a terminating zero. If left != NULL, return a pointer to the terminator. */ -if (yield == NULL) yield = store_get(1); -yield[ptr] = 0; -if (left != NULL) *left = s; +if (!yield) + yield = string_get(1); +(void) string_from_gstring(yield); +if (left) *left = s; /* Any stacking store that was used above the final string is no longer needed. In many cases the final string will be the first one that was got and so there will be optimal store usage. */ -if (resetok) store_reset(yield + ptr + 1); +if (resetok) store_reset(yield->s + (yield->size = yield->ptr + 1)); else if (resetok_p) *resetok_p = FALSE; DEBUG(D_expand) @@ -7522,13 +7495,13 @@ DEBUG(D_expand) UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ "result: %s\n", skipping ? UTF8_VERT_RIGHT : UTF8_UP_RIGHT, - yield); + yield->s); if (skipping) debug_printf_indent(UTF8_UP_RIGHT UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ "skipping: result is not used\n"); } expand_level--; -return yield; +return yield->s; /* This is the failure exit: easiest to program with a goto. We still need to update the pointer to the terminator, for cases of nested calls with "fail". @@ -7546,7 +7519,7 @@ else if (!expand_string_message || !*expand_string_message) that is a bad idea, because expand_string_message is in dynamic store. */ EXPAND_FAILED: -if (left != NULL) *left = s; +if (left) *left = s; DEBUG(D_expand) { debug_printf_indent(UTF8_VERT_RIGHT "failed to expand: %s\n", diff --git a/src/src/filter.c b/src/src/filter.c index 86232c187..0b3ef8b2d 100644 --- a/src/src/filter.c +++ b/src/src/filter.c @@ -2101,254 +2101,252 @@ while (commands != NULL) case mail_command: case vacation_command: - if (return_path == NULL || return_path[0] == 0) - { - if (filter_test != FTEST_NONE) - printf("%s command ignored because return_path is empty\n", - command_list[commands->command]); - else DEBUG(D_filter) debug_printf("%s command ignored because return_path " - "is empty\n", command_list[commands->command]); - break; - } - - /* Check the contents of the strings. The type of string can be deduced - from the value of i. - - . If i is equal to mailarg_index_text it's a text string for the body, - where anything goes. - - . If i is > mailarg_index_text, we are dealing with a file name, which - cannot contain non-printing characters. - - . If i is less than mailarg_index_headers we are dealing with something - that will go in a single message header line, where newlines must be - followed by white space. - - . If i is equal to mailarg_index_headers, we have a string that contains - one or more headers. Newlines that are not followed by white space must - be followed by a header name. - */ - - for (i = 0; i < MAILARGS_STRING_COUNT; i++) - { - uschar *p; - uschar *s = expargs[i]; - - if (s == NULL) continue; - - if (i != mailarg_index_text) for (p = s; *p != 0; p++) - { - int c = *p; - if (i > mailarg_index_text) - { - if (!mac_isprint(c)) - { - *error_pointer = string_sprintf("non-printing character in \"%s\" " - "in %s command", string_printing(s), - command_list[commands->command]); - return FF_ERROR; - } - } - - /* i < mailarg_index_text */ - - else if (c == '\n' && !isspace(p[1])) - { - if (i < mailarg_index_headers) - { - *error_pointer = string_sprintf("\\n not followed by space in " - "\"%.1024s\" in %s command", string_printing(s), - command_list[commands->command]); - return FF_ERROR; - } - - /* Check for the start of a new header line within the string */ - - else - { - uschar *pp; - for (pp = p + 1;; pp++) - { - c = *pp; - if (c == ':' && pp != p + 1) break; - if (c == 0 || c == ':' || isspace(*pp)) - { - *error_pointer = string_sprintf("\\n not followed by space or " - "valid header name in \"%.1024s\" in %s command", - string_printing(s), command_list[commands->command]); - return FF_ERROR; - } - } - p = pp; - } - } - } /* Loop to scan the string */ + if (return_path == NULL || return_path[0] == 0) + { + if (filter_test != FTEST_NONE) + printf("%s command ignored because return_path is empty\n", + command_list[commands->command]); + else DEBUG(D_filter) debug_printf("%s command ignored because return_path " + "is empty\n", command_list[commands->command]); + break; + } + + /* Check the contents of the strings. The type of string can be deduced + from the value of i. + + . If i is equal to mailarg_index_text it's a text string for the body, + where anything goes. + + . If i is > mailarg_index_text, we are dealing with a file name, which + cannot contain non-printing characters. + + . If i is less than mailarg_index_headers we are dealing with something + that will go in a single message header line, where newlines must be + followed by white space. + + . If i is equal to mailarg_index_headers, we have a string that contains + one or more headers. Newlines that are not followed by white space must + be followed by a header name. + */ + + for (i = 0; i < MAILARGS_STRING_COUNT; i++) + { + uschar *p; + uschar *s = expargs[i]; + + if (s == NULL) continue; + + if (i != mailarg_index_text) for (p = s; *p != 0; p++) + { + int c = *p; + if (i > mailarg_index_text) + { + if (!mac_isprint(c)) + { + *error_pointer = string_sprintf("non-printing character in \"%s\" " + "in %s command", string_printing(s), + command_list[commands->command]); + return FF_ERROR; + } + } + + /* i < mailarg_index_text */ + + else if (c == '\n' && !isspace(p[1])) + { + if (i < mailarg_index_headers) + { + *error_pointer = string_sprintf("\\n not followed by space in " + "\"%.1024s\" in %s command", string_printing(s), + command_list[commands->command]); + return FF_ERROR; + } + + /* Check for the start of a new header line within the string */ + + else + { + uschar *pp; + for (pp = p + 1;; pp++) + { + c = *pp; + if (c == ':' && pp != p + 1) break; + if (c == 0 || c == ':' || isspace(*pp)) + { + *error_pointer = string_sprintf("\\n not followed by space or " + "valid header name in \"%.1024s\" in %s command", + string_printing(s), command_list[commands->command]); + return FF_ERROR; + } + } + p = pp; + } + } + } /* Loop to scan the string */ + + /* The string is OK */ + + commands->args[i].u = s; + } + + /* Proceed with mail or vacation command */ - /* The string is OK */ - - commands->args[i].u = s; - } - - /* Proceed with mail or vacation command */ - - if (filter_test != FTEST_NONE) - { - uschar *to = commands->args[mailarg_index_to].u; - indent(); - printf("%sail to: %s%s%s\n", (commands->seen)? "Seen m" : "M", - (to == NULL)? US"" : to, - (commands->command == vacation_command)? " (vacation)" : "", - (commands->noerror)? " (noerror)" : ""); - for (i = 1; i < MAILARGS_STRING_COUNT; i++) - { - uschar *arg = commands->args[i].u; - if (arg != NULL) - { - int len = Ustrlen(mailargs[i]); - int indent = (debug_selector != 0)? output_indent : 0; - while (len++ < 7 + indent) printf(" "); - printf("%s: %s%s\n", mailargs[i], string_printing(arg), - (commands->args[mailarg_index_expand].u != NULL && - Ustrcmp(mailargs[i], "file") == 0)? " (expanded)" : ""); - } - } - if (commands->args[mailarg_index_return].u != NULL) - printf("Return original message\n"); - } - else - { - uschar *tt; - uschar *log_addr = NULL; - uschar *to = commands->args[mailarg_index_to].u; - int size = 0; - int ptr = 0; - BOOL badflag; - - if (to == NULL) to = expand_string(US"$reply_address"); - while (isspace(*to)) to++; - - for (tt = to; *tt != 0; tt++) /* Get rid of newlines */ - if (*tt == '\n') *tt = ' '; - - DEBUG(D_filter) - { - debug_printf("Filter: %smail to: %s%s%s\n", - (commands->seen)? "seen " : "", - to, - (commands->command == vacation_command)? " (vacation)" : "", - (commands->noerror)? " (noerror)" : ""); - for (i = 1; i < MAILARGS_STRING_COUNT; i++) - { - uschar *arg = commands->args[i].u; - if (arg != NULL) - { - int len = Ustrlen(mailargs[i]); - while (len++ < 15) debug_printf(" "); - debug_printf("%s: %s%s\n", mailargs[i], string_printing(arg), - (commands->args[mailarg_index_expand].u != NULL && - Ustrcmp(mailargs[i], "file") == 0)? " (expanded)" : ""); - } - } - } - - /* Create the "address" for the autoreply. This is used only for logging, - as the actual recipients are extracted from the To: line by -t. We use the - same logic here to extract the working addresses (there may be more than - one). Just in case there are a vast number of addresses, stop when the - string gets too long. */ - - tt = to; - while (*tt != 0) - { - uschar *ss = parse_find_address_end(tt, FALSE); - uschar *recipient, *errmess; - int start, end, domain; - int temp = *ss; - - *ss = 0; - recipient = parse_extract_address(tt, &errmess, &start, &end, &domain, - FALSE); - *ss = temp; - - /* Ignore empty addresses and errors; an error will occur later if - there's something really bad. */ - - if (recipient != NULL) - { - log_addr = string_catn(log_addr, &size, &ptr, - log_addr ? US"," : US">", 1); - log_addr = string_cat(log_addr, &size, &ptr, recipient); - } - - /* Check size */ - - if (ptr > 256) - { - log_addr = string_catn(log_addr, &size, &ptr, US", ...", 5); - break; - } - - /* Move on past this address */ - - tt = ss + (*ss? 1:0); - while (isspace(*tt)) tt++; - } - - if ((badflag = !log_addr)) - log_addr = string_sprintf(">**bad-reply**"); + if (filter_test != FTEST_NONE) + { + uschar *to = commands->args[mailarg_index_to].u; + indent(); + printf("%sail to: %s%s%s\n", (commands->seen)? "Seen m" : "M", + to ? to : US"", + commands->command == vacation_command ? " (vacation)" : "", + commands->noerror ? " (noerror)" : ""); + for (i = 1; i < MAILARGS_STRING_COUNT; i++) + { + uschar *arg = commands->args[i].u; + if (arg) + { + int len = Ustrlen(mailargs[i]); + int indent = (debug_selector != 0)? output_indent : 0; + while (len++ < 7 + indent) printf(" "); + printf("%s: %s%s\n", mailargs[i], string_printing(arg), + (commands->args[mailarg_index_expand].u != NULL && + Ustrcmp(mailargs[i], "file") == 0)? " (expanded)" : ""); + } + } + if (commands->args[mailarg_index_return].u) + printf("Return original message\n"); + } else - log_addr[ptr] = 0; - - addr = deliver_make_addr(log_addr, FALSE); - setflag(addr, af_pfr); - if (badflag) setflag(addr, af_bad_reply); - if (commands->noerror) addr->prop.ignore_error = TRUE; - addr->next = *generated; - *generated = addr; - addr->reply = store_get(sizeof(reply_item)); - addr->reply->from = NULL; - addr->reply->to = string_copy(to); - addr->reply->file_expand = - commands->args[mailarg_index_expand].u != NULL; - addr->reply->expand_forbid = expand_forbid; - addr->reply->return_message = - commands->args[mailarg_index_return].u != NULL; - addr->reply->once_repeat = 0; - - if (commands->args[mailarg_index_once_repeat].u != NULL) - { - addr->reply->once_repeat = - readconf_readtime(commands->args[mailarg_index_once_repeat].u, 0, - FALSE); - if (addr->reply->once_repeat < 0) - { - *error_pointer = string_sprintf("Bad time value for \"once_repeat\" " - "in mail or vacation command: %s", - commands->args[mailarg_index_once_repeat]); - return FF_ERROR; - } - } - - /* Set up all the remaining string arguments (those other than "to") */ - - for (i = 1; i < mailargs_string_passed; i++) - { - uschar *ss = commands->args[i].u; - *((uschar **)(((uschar *)(addr->reply)) + reply_offsets[i])) = - (ss == NULL)? NULL : string_copy(ss); - } - } - break; + { + uschar *tt; + uschar *to = commands->args[mailarg_index_to].u; + gstring * log_addr = NULL; + + if (!to) to = expand_string(US"$reply_address"); + while (isspace(*to)) to++; + + for (tt = to; *tt != 0; tt++) /* Get rid of newlines */ + if (*tt == '\n') *tt = ' '; + + DEBUG(D_filter) + { + debug_printf("Filter: %smail to: %s%s%s\n", + commands->seen ? "seen " : "", + to, + commands->command == vacation_command ? " (vacation)" : "", + commands->noerror ? " (noerror)" : ""); + for (i = 1; i < MAILARGS_STRING_COUNT; i++) + { + uschar *arg = commands->args[i].u; + if (arg != NULL) + { + int len = Ustrlen(mailargs[i]); + while (len++ < 15) debug_printf(" "); + debug_printf("%s: %s%s\n", mailargs[i], string_printing(arg), + (commands->args[mailarg_index_expand].u != NULL && + Ustrcmp(mailargs[i], "file") == 0)? " (expanded)" : ""); + } + } + } + + /* Create the "address" for the autoreply. This is used only for logging, + as the actual recipients are extracted from the To: line by -t. We use the + same logic here to extract the working addresses (there may be more than + one). Just in case there are a vast number of addresses, stop when the + string gets too long. */ + + tt = to; + while (*tt != 0) + { + uschar *ss = parse_find_address_end(tt, FALSE); + uschar *recipient, *errmess; + int start, end, domain; + int temp = *ss; + + *ss = 0; + recipient = parse_extract_address(tt, &errmess, &start, &end, &domain, + FALSE); + *ss = temp; + + /* Ignore empty addresses and errors; an error will occur later if + there's something really bad. */ + + if (recipient) + { + log_addr = string_catn(log_addr, log_addr ? US"," : US">", 1); + log_addr = string_cat (log_addr, recipient); + } + + /* Check size */ + + if (log_addr && log_addr->ptr > 256) + { + log_addr = string_catn(log_addr, US", ...", 5); + break; + } + + /* Move on past this address */ + + tt = ss + (*ss ? 1 : 0); + while (isspace(*tt)) tt++; + } + + if (log_addr) + addr = deliver_make_addr(string_from_gstring(log_addr), FALSE); + else + { + addr = deliver_make_addr(US ">**bad-reply**", FALSE); + setflag(addr, af_bad_reply); + } + + setflag(addr, af_pfr); + if (commands->noerror) addr->prop.ignore_error = TRUE; + addr->next = *generated; + *generated = addr; + + addr->reply = store_get(sizeof(reply_item)); + addr->reply->from = NULL; + addr->reply->to = string_copy(to); + addr->reply->file_expand = + commands->args[mailarg_index_expand].u != NULL; + addr->reply->expand_forbid = expand_forbid; + addr->reply->return_message = + commands->args[mailarg_index_return].u != NULL; + addr->reply->once_repeat = 0; + + if (commands->args[mailarg_index_once_repeat].u != NULL) + { + addr->reply->once_repeat = + readconf_readtime(commands->args[mailarg_index_once_repeat].u, 0, + FALSE); + if (addr->reply->once_repeat < 0) + { + *error_pointer = string_sprintf("Bad time value for \"once_repeat\" " + "in mail or vacation command: %s", + commands->args[mailarg_index_once_repeat]); + return FF_ERROR; + } + } + + /* Set up all the remaining string arguments (those other than "to") */ + + for (i = 1; i < mailargs_string_passed; i++) + { + uschar *ss = commands->args[i].u; + *(USS((US addr->reply) + reply_offsets[i])) = + ss ? string_copy(ss) : NULL; + } + } + break; case testprint_command: - if (filter_test != FTEST_NONE || (debug_selector & D_filter) != 0) - { - const uschar *s = string_printing(expargs[0]); - if (filter_test == FTEST_NONE) - debug_printf("Filter: testprint: %s\n", s); - else - printf("Testprint: %s\n", s); - } + if (filter_test != FTEST_NONE || (debug_selector & D_filter) != 0) + { + const uschar *s = string_printing(expargs[0]); + if (filter_test == FTEST_NONE) + debug_printf("Filter: testprint: %s\n", s); + else + printf("Testprint: %s\n", s); + } } commands = commands->next; diff --git a/src/src/functions.h b/src/src/functions.h index 9d1f6dc6e..e6aada27a 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -13,7 +13,7 @@ are in in fact in separate headers. */ #ifdef EXIM_PERL -extern uschar *call_perl_cat(uschar *, int *, int *, uschar **, uschar *, +extern gstring *call_perl_cat(gstring *, uschar **, uschar *, uschar **) WARN_UNUSED_RESULT; extern void cleanup_perl(void); extern uschar *init_perl(uschar *); @@ -205,6 +205,8 @@ extern BOOL filter_system_interpret(address_item **, uschar **); extern uschar * fn_hdrs_added(void); +extern void gstring_grow(gstring *, int, int); + extern void header_add(int, const char *, ...); extern int header_checkname(header_line *, BOOL); extern BOOL header_match(uschar *, BOOL, BOOL, string_item *, int, ...); @@ -437,12 +439,10 @@ extern int stdin_getc(unsigned); extern int stdin_feof(void); extern int stdin_ferror(void); extern int stdin_ungetc(int); -extern uschar *string_append(uschar *, int *, int *, int, ...) WARN_UNUSED_RESULT; -extern uschar *string_append_listele(uschar *, int *, int *, uschar, const uschar *) WARN_UNUSED_RESULT; -extern uschar *string_append_listele_n(uschar *, int *, int *, uschar, const uschar *, unsigned) WARN_UNUSED_RESULT; +extern gstring *string_append(gstring *, int, ...) WARN_UNUSED_RESULT; +extern gstring *string_append_listele(gstring *, uschar, const uschar *) WARN_UNUSED_RESULT; +extern gstring *string_append_listele_n(gstring *, uschar, const uschar *, unsigned) WARN_UNUSED_RESULT; extern uschar *string_base62(unsigned long int); -extern uschar *string_cat(uschar *, int *, int *, const uschar *) WARN_UNUSED_RESULT; -extern uschar *string_catn(uschar *, int *, int *, const uschar *, int) WARN_UNUSED_RESULT; extern int string_compare_by_pointer(const void *, const void *); extern uschar *string_copy_dnsdomain(uschar *); extern uschar *string_copy_malloc(const uschar *); @@ -531,6 +531,93 @@ extern void version_init(void); extern BOOL write_chunk(transport_ctx *, uschar *, int); extern ssize_t write_to_fd_buf(int, const uschar *, size_t); +/******************************************************************************/ + +#if !defined(COMPILE_UTILITY) && !defined(MACRO_PREDEF) + +/* Create a growable-string with some preassigned space */ + +__inline__ gstring * +string_get(unsigned size) +{ +gstring * g = store_get(sizeof(gstring) + size); +g->size = size; +g->ptr = 0; +g->s = US(g + 1); +return g; +} + + +/* NUL-terminate the C string in the growable-string, and return it. */ + +__inline__ uschar * +string_from_gstring(gstring * g) +{ +if (!g) return NULL; +g->s[g->ptr] = '\0'; +return g->s; +} + + + +/* This function is used when building up strings of unknown length. Room is +always left for a terminating zero to be added to the string that is being +built. This function does not require the string that is being added to be NUL +terminated, because the number of characters to add is given explicitly. It is +sometimes called to extract parts of other strings. + +Arguments: + string points to the start of the string that is being built, or NULL + if this is a new string that has no contents yet + s points to characters to add + count count of characters to add; must not exceed the length of s, if s + is a C string. + +Returns: pointer to the start of the string, changed if copied for expansion. + Note that a NUL is not added, though space is left for one. This is + because string_cat() is often called multiple times to build up a + string - there's no point adding the NUL till the end. + +*/ +/* coverity[+alloc] */ + +WARN_UNUSED_RESULT +__inline__ gstring * +string_catn(gstring * g, const uschar *s, int count) +{ +int p; + +if (!g) + { + unsigned inc = count < 4096 ? 127 : 1023; + unsigned size = ((count + inc) & ~inc) + 1; + g = string_get(size); + } + +p = g->ptr; +if (p + count >= g->size) + gstring_grow(g, p, count); + +/* Because we always specify the exact number of characters to copy, we can +use memcpy(), which is likely to be more efficient than strncopy() because the +latter has to check for zero bytes. */ + +memcpy(g->s + p, s, count); +g->ptr = p + count; +return g; +} + + +WARN_UNUSED_RESULT +__inline__ gstring * +string_cat(gstring *string, const uschar *s) +{ +return string_catn(string, s, Ustrlen(s)); +} +#endif /*!COMPILE_UTILITY*/ + + + /* vi: aw */ /* End of functions.h */ diff --git a/src/src/host.c b/src/src/host.c index ec262805e..c02fc5532 100644 --- a/src/src/host.c +++ b/src/src/host.c @@ -586,46 +586,45 @@ else if (sender_helo_name[0] == '[' && /* Host name is not verified */ -if (sender_host_name == NULL) +if (!sender_host_name) { uschar *portptr = Ustrstr(address, "]:"); - int size = 0; - int ptr = 0; + gstring * g; int adlen; /* Sun compiler doesn't like ++ in initializers */ - adlen = (portptr == NULL)? Ustrlen(address) : (++portptr - address); - sender_fullhost = (sender_helo_name == NULL)? address : - string_sprintf("(%s) %s", sender_helo_name, address); + adlen = portptr ? (++portptr - address) : Ustrlen(address); + sender_fullhost = sender_helo_name + ? string_sprintf("(%s) %s", sender_helo_name, address) + : address; - sender_rcvhost = string_catn(NULL, &size, &ptr, address, adlen); + g = string_catn(NULL, address, adlen); if (sender_ident != NULL || show_helo || portptr != NULL) { int firstptr; - sender_rcvhost = string_catn(sender_rcvhost, &size, &ptr, US" (", 2); - firstptr = ptr; + g = string_catn(g, US" (", 2); + firstptr = g->ptr; - if (portptr != NULL) - sender_rcvhost = string_append(sender_rcvhost, &size, &ptr, 2, US"port=", - portptr + 1); + if (portptr) + g = string_append(g, 2, US"port=", portptr + 1); if (show_helo) - sender_rcvhost = string_append(sender_rcvhost, &size, &ptr, 2, - (firstptr == ptr)? US"helo=" : US" helo=", sender_helo_name); + g = string_append(g, 2, + firstptr == g->ptr ? US"helo=" : US" helo=", sender_helo_name); - if (sender_ident != NULL) - sender_rcvhost = string_append(sender_rcvhost, &size, &ptr, 2, - (firstptr == ptr)? US"ident=" : US" ident=", sender_ident); + if (sender_ident) + g = string_append(g, 2, + firstptr == g->ptr ? US"ident=" : US" ident=", sender_ident); - sender_rcvhost = string_catn(sender_rcvhost, &size, &ptr, US")", 1); + g = string_catn(g, US")", 1); } - sender_rcvhost[ptr] = 0; /* string_cat() always leaves room */ + sender_rcvhost = string_from_gstring(g); /* Release store, because string_cat allocated a minimum of 100 bytes that are rarely completely used. */ - store_reset(sender_rcvhost + ptr + 1); + store_reset(sender_rcvhost + g->ptr + 1); } /* Host name is known and verified. Unless we've already found that the HELO diff --git a/src/src/imap_utf7.c b/src/src/imap_utf7.c index 0c3d5a20d..323225c23 100644 --- a/src/src/imap_utf7.c +++ b/src/src/imap_utf7.c @@ -8,10 +8,9 @@ imap_utf7_encode(uschar *string, const uschar *charset, uschar sep, { static uschar encode_base64[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,"; -int ptr = 0; -int size = 0; size_t slen; -uschar *sptr, *yield = NULL; +uschar *sptr; +gstring * yield = NULL; int i = 0, j; /* compiler quietening */ uschar c = 0; /* compiler quietening */ BOOL base64mode = FALSE; @@ -170,7 +169,7 @@ while (slen > 0) if (outptr > outbuf + sizeof(outbuf) - 3) { - yield = string_catn(yield, &size, &ptr, outbuf, outptr - outbuf); + yield = string_catn(yield, outbuf, outptr - outbuf); outptr = outbuf; } @@ -196,12 +195,12 @@ if (base64mode) iconv_close(icd); #endif -yield = string_catn(yield, &size, &ptr, outbuf, outptr - outbuf); -if (yield[ptr-1] == '.') - ptr--; -yield[ptr] = '\0'; +yield = string_catn(yield, outbuf, outptr - outbuf); -return yield; +if (yield->s[yield->ptr-1] == '.') + yield->ptr--; + +return string_from_gstring(yield); } #endif /* whole file */ diff --git a/src/src/lookups/dnsdb.c b/src/src/lookups/dnsdb.c index bf3acd6ef..9e95b9038 100644 --- a/src/src/lookups/dnsdb.c +++ b/src/src/lookups/dnsdb.c @@ -14,17 +14,17 @@ header files. */ #ifndef T_TXT -#define T_TXT 16 +# define T_TXT 16 #endif /* Many systems do not have T_SPF. */ #ifndef T_SPF -#define T_SPF 99 +# define T_SPF 99 #endif /* New TLSA record for DANE */ #ifndef T_TLSA -#define T_TLSA 52 +# define T_TLSA 52 #endif /* Table of recognized DNS record types and their integer values. */ @@ -134,8 +134,6 @@ dnsdb_find(void *handle, uschar *filename, const uschar *keystring, int length, uschar **result, uschar **errmsg, uint *do_cache) { int rc; -int size = 256; -int ptr = 0; int sep = 0; int defer_mode = PASS; int dnssec_mode = OK; @@ -147,10 +145,10 @@ const uschar *outsep = CUS"\n"; const uschar *outsep2 = NULL; uschar *equals, *domain, *found; -/* Because we're the working in the search pool, we try to reclaim as much +/* Because we're working in the search pool, we try to reclaim as much store as possible later, so we preallocate the result here */ -uschar *yield = store_get(size); +gstring * yield = string_get(256); dns_record *rr; dns_answer dnsa; @@ -380,12 +378,9 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) /* Search the returned records */ - for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); - rr != NULL; - rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT)) + for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); rr; + rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT)) if (rr->type == searchtype) { - if (rr->type != searchtype) continue; - if (*do_cache > rr->ttl) *do_cache = rr->ttl; @@ -394,8 +389,8 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) dns_address *da; for (da = dns_address_from_rr(&dnsa, rr); da; da = da->next) { - if (ptr != 0) yield = string_catn(yield, &size, &ptr, outsep, 1); - yield = string_cat(yield, &size, &ptr, da->address); + if (yield->ptr) yield = string_catn(yield, outsep, 1); + yield = string_cat(yield, da->address); } continue; } @@ -403,16 +398,12 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) /* Other kinds of record just have one piece of data each, but there may be several of them, of course. */ - if (ptr != 0) yield = string_catn(yield, &size, &ptr, outsep, 1); + if (yield->ptr) yield = string_catn(yield, outsep, 1); if (type == T_TXT || type == T_SPF) { - if (outsep2 == NULL) - { - /* output only the first item of data */ - yield = string_catn(yield, &size, &ptr, US (rr->data+1), - (rr->data)[0]); - } + if (outsep2 == NULL) /* output only the first item of data */ + yield = string_catn(yield, US (rr->data+1), (rr->data)[0]); else { /* output all items */ @@ -421,9 +412,8 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) { uschar chunk_len = (rr->data)[data_offset++]; if (outsep2[0] != '\0' && data_offset != 1) - yield = string_catn(yield, &size, &ptr, outsep2, 1); - yield = string_catn(yield, &size, &ptr, - US ((rr->data)+data_offset), chunk_len); + yield = string_catn(yield, outsep2, 1); + yield = string_catn(yield, US ((rr->data)+data_offset), chunk_len); data_offset += chunk_len; } } @@ -449,7 +439,7 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) i++) sp += sprintf(CS sp, "%02x", (unsigned char)p[i]); - yield = string_cat(yield, &size, &ptr, s); + yield = string_cat(yield, s); } else /* T_CNAME, T_CSA, T_MX, T_MXH, T_NS, T_PTR, T_SOA, T_SRV */ { @@ -467,7 +457,7 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) case T_MX: GETSHORT(priority, p); sprintf(CS s, "%d%c", priority, *outsep2); - yield = string_cat(yield, &size, &ptr, s); + yield = string_cat(yield, s); break; case T_SRV: @@ -476,7 +466,7 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) GETSHORT(port, p); sprintf(CS s, "%d%c%d%c%d%c", priority, *outsep2, weight, *outsep2, port, *outsep2); - yield = string_cat(yield, &size, &ptr, s); + yield = string_cat(yield, s); break; case T_CSA: @@ -505,7 +495,7 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) } s[1] = ' '; - yield = string_catn(yield, &size, &ptr, s, 2); + yield = string_catn(yield, s, 2); break; default: @@ -526,14 +516,14 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) "domain=%s", dns_text_type(type), domain); break; } - else yield = string_cat(yield, &size, &ptr, s); + else yield = string_cat(yield, s); if (type == T_SOA && outsep2 != NULL) { unsigned long serial, refresh, retry, expire, minimum; p += rc; - yield = string_catn(yield, &size, &ptr, outsep2, 1); + yield = string_catn(yield, outsep2, 1); rc = dn_expand(dnsa.answer, dnsa.answer + dnsa.answerlen, p, (DN_EXPAND_ARG4_TYPE)s, sizeof(s)); @@ -543,7 +533,7 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) "domain=%s", dns_text_type(type), domain); break; } - else yield = string_cat(yield, &size, &ptr, s); + else yield = string_cat(yield, s); p += rc; GETLONG(serial, p); GETLONG(refresh, p); @@ -551,7 +541,7 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) sprintf(CS s, "%c%lu%c%lu%c%lu%c%lu%c%lu", *outsep2, serial, *outsep2, refresh, *outsep2, retry, *outsep2, expire, *outsep2, minimum); - yield = string_cat(yield, &size, &ptr, s); + yield = string_cat(yield, s); } } } /* Loop for list of returned records */ @@ -563,18 +553,18 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) /* Reclaim unused memory */ -store_reset(yield + ptr + 1); +store_reset(yield->s + yield->ptr + 1); -/* If ptr == 0 we have not found anything. Otherwise, insert the terminating +/* If yield NULL we have not found anything. Otherwise, insert the terminating zero and return the result. */ dns_retrans = save_retrans; dns_retry = save_retry; dns_init(FALSE, FALSE, FALSE); /* clear the dnssec bit for getaddrbyname */ -if (ptr == 0) return failrc; -yield[ptr] = 0; -*result = yield; +if (!yield || !yield->ptr) return failrc; + +*result = string_from_gstring(yield); return OK; } diff --git a/src/src/lookups/ibase.c b/src/src/lookups/ibase.c index 7f1775c1f..58bced201 100644 --- a/src/src/lookups/ibase.c +++ b/src/src/lookups/ibase.c @@ -109,332 +109,334 @@ static int perform_ibase_search(uschar * query, uschar * server, uschar ** resultptr, uschar ** errmsg, BOOL * defer_break) { - isc_stmt_handle stmth = NULL; - XSQLDA *out_sqlda; - XSQLVAR *var; - - char buffer[256]; - ISC_STATUS status[20], *statusp = status; - - int i; - int ssize = 0; - int offset = 0; - int yield = DEFER; - uschar *result = NULL; - ibase_connection *cn; - uschar *server_copy = NULL; - uschar *sdata[3]; +isc_stmt_handle stmth = NULL; +XSQLDA *out_sqlda; +XSQLVAR *var; + +char buffer[256]; +ISC_STATUS status[20], *statusp = status; + +gstring * result; +int i; +int yield = DEFER; +ibase_connection *cn; +uschar *server_copy = NULL; +uschar *sdata[3]; /* Disaggregate the parameters from the server argument. The order is host, database, user, password. We can write to the string, since it is in a nextinlist temporary buffer. The copy of the string that is used for caching has the password removed. This copy is also used for debugging output. */ - for (i = 2; i > 0; i--) { - uschar *pp = Ustrrchr(server, '|'); - if (pp == NULL) { - *errmsg = - string_sprintf("incomplete Interbase server data: %s", - (i == 3) ? server : server_copy); - *defer_break = TRUE; - return DEFER; - } - *pp++ = 0; - sdata[i] = pp; - if (i == 2) - server_copy = string_copy(server); /* sans password */ +for (i = 2; i > 0; i--) + { + uschar *pp = Ustrrchr(server, '|'); + + if (pp == NULL) + { + *errmsg = string_sprintf("incomplete Interbase server data: %s", + (i == 3) ? server : server_copy); + *defer_break = TRUE; + return DEFER; } - sdata[0] = server; /* What's left at the start */ + *pp++ = 0; + sdata[i] = pp; + if (i == 2) + server_copy = string_copy(server); /* sans password */ + } +sdata[0] = server; /* What's left at the start */ /* See if we have a cached connection to the server */ - for (cn = ibase_connections; cn != NULL; cn = cn->next) { - if (Ustrcmp(cn->server, server_copy) == 0) { - break; - } - } +for (cn = ibase_connections; cn != NULL; cn = cn->next) + if (Ustrcmp(cn->server, server_copy) == 0) + break; /* Use a previously cached connection ? */ - if (cn != NULL) { - static char db_info_options[] = { isc_info_base_level }; - - /* test if the connection is alive */ - if (isc_database_info - (status, &cn->dbh, sizeof(db_info_options), db_info_options, - sizeof(buffer), buffer)) { - /* error occurred: assume connection is down */ - DEBUG(D_lookup) - debug_printf - ("Interbase cleaning up cached connection: %s\n", - cn->server); - isc_detach_database(status, &cn->dbh); - } else { - DEBUG(D_lookup) - debug_printf("Interbase using cached connection for %s\n", - server_copy); - } - } else { - cn = store_get(sizeof(ibase_connection)); - cn->server = server_copy; - cn->dbh = NULL; - cn->transh = NULL; - cn->next = ibase_connections; - ibase_connections = cn; +if (cn) + { + static char db_info_options[] = { isc_info_base_level }; + + /* test if the connection is alive */ + if (isc_database_info(status, &cn->dbh, sizeof(db_info_options), + db_info_options, sizeof(buffer), buffer)) + { + /* error occurred: assume connection is down */ + DEBUG(D_lookup) + debug_printf + ("Interbase cleaning up cached connection: %s\n", + cn->server); + isc_detach_database(status, &cn->dbh); } + else + { + DEBUG(D_lookup) debug_printf("Interbase using cached connection for %s\n", + server_copy); + } + } +else + { + cn = store_get(sizeof(ibase_connection)); + cn->server = server_copy; + cn->dbh = NULL; + cn->transh = NULL; + cn->next = ibase_connections; + ibase_connections = cn; + } /* If no cached connection, we must set one up. */ - if (cn->dbh == NULL || cn->transh == NULL) { - - char *dpb, *p; - short dpb_length; - static char trans_options[] = - { isc_tpb_version3, isc_tpb_read, isc_tpb_read_committed, - isc_tpb_rec_version - }; - - /* Construct the database parameter buffer. */ - dpb = buffer; - *dpb++ = isc_dpb_version1; - *dpb++ = isc_dpb_user_name; - *dpb++ = strlen(sdata[1]); - for (p = sdata[1]; *p;) - *dpb++ = *p++; - *dpb++ = isc_dpb_password; - *dpb++ = strlen(sdata[2]); - for (p = sdata[2]; *p;) - *dpb++ = *p++; - dpb_length = dpb - buffer; - - DEBUG(D_lookup) - debug_printf("new Interbase connection: database=%s user=%s\n", - sdata[0], sdata[1]); - - /* Connect to the database */ - if (isc_attach_database - (status, 0, sdata[0], &cn->dbh, dpb_length, buffer)) { - isc_interprete(buffer, &statusp); - *errmsg = - string_sprintf("Interbase attach() failed: %s", buffer); - *defer_break = FALSE; - goto IBASE_EXIT; - } - - /* Now start a read-only read-committed transaction */ - if (isc_start_transaction - (status, &cn->transh, 1, &cn->dbh, sizeof(trans_options), - trans_options)) { - isc_interprete(buffer, &statusp); - isc_detach_database(status, &cn->dbh); - *errmsg = - string_sprintf("Interbase start_transaction() failed: %s", - buffer); - *defer_break = FALSE; - goto IBASE_EXIT; - } +if (cn->dbh == NULL || cn->transh == NULL) + { + char *dpb, *p; + short dpb_length; + static char trans_options[] = + { isc_tpb_version3, isc_tpb_read, isc_tpb_read_committed, + isc_tpb_rec_version + }; + + /* Construct the database parameter buffer. */ + dpb = buffer; + *dpb++ = isc_dpb_version1; + *dpb++ = isc_dpb_user_name; + *dpb++ = strlen(sdata[1]); + for (p = sdata[1]; *p;) + *dpb++ = *p++; + *dpb++ = isc_dpb_password; + *dpb++ = strlen(sdata[2]); + for (p = sdata[2]; *p;) + *dpb++ = *p++; + dpb_length = dpb - buffer; + + DEBUG(D_lookup) + debug_printf("new Interbase connection: database=%s user=%s\n", + sdata[0], sdata[1]); + + /* Connect to the database */ + if (isc_attach_database + (status, 0, sdata[0], &cn->dbh, dpb_length, buffer)) + { + isc_interprete(buffer, &statusp); + *errmsg = + string_sprintf("Interbase attach() failed: %s", buffer); + *defer_break = FALSE; + goto IBASE_EXIT; } -/* Run the query */ - if (isc_dsql_allocate_statement(status, &cn->dbh, &stmth)) { - isc_interprete(buffer, &statusp); - *errmsg = - string_sprintf("Interbase alloc_statement() failed: %s", - buffer); - *defer_break = FALSE; - goto IBASE_EXIT; + /* Now start a read-only read-committed transaction */ + if (isc_start_transaction + (status, &cn->transh, 1, &cn->dbh, sizeof(trans_options), + trans_options)) + { + isc_interprete(buffer, &statusp); + isc_detach_database(status, &cn->dbh); + *errmsg = + string_sprintf("Interbase start_transaction() failed: %s", + buffer); + *defer_break = FALSE; + goto IBASE_EXIT; } + } - out_sqlda = store_get(XSQLDA_LENGTH(1)); - out_sqlda->version = SQLDA_VERSION1; - out_sqlda->sqln = 1; - - if (isc_dsql_prepare - (status, &cn->transh, &stmth, 0, query, 1, out_sqlda)) { - isc_interprete(buffer, &statusp); - store_reset(out_sqlda); - out_sqlda = NULL; - *errmsg = - string_sprintf("Interbase prepare_statement() failed: %s", - buffer); - *defer_break = FALSE; - goto IBASE_EXIT; - } +/* Run the query */ +if (isc_dsql_allocate_statement(status, &cn->dbh, &stmth)) + { + isc_interprete(buffer, &statusp); + *errmsg = + string_sprintf("Interbase alloc_statement() failed: %s", + buffer); + *defer_break = FALSE; + goto IBASE_EXIT; + } + +out_sqlda = store_get(XSQLDA_LENGTH(1)); +out_sqlda->version = SQLDA_VERSION1; +out_sqlda->sqln = 1; + +if (isc_dsql_prepare + (status, &cn->transh, &stmth, 0, query, 1, out_sqlda)) + { + isc_interprete(buffer, &statusp); + store_reset(out_sqlda); + out_sqlda = NULL; + *errmsg = + string_sprintf("Interbase prepare_statement() failed: %s", + buffer); + *defer_break = FALSE; + goto IBASE_EXIT; + } /* re-allocate the output structure if there's more than one field */ - if (out_sqlda->sqln < out_sqlda->sqld) { - XSQLDA *new_sqlda = store_get(XSQLDA_LENGTH(out_sqlda->sqld)); - if (isc_dsql_describe - (status, &stmth, out_sqlda->version, new_sqlda)) { - isc_interprete(buffer, &statusp); - isc_dsql_free_statement(status, &stmth, DSQL_drop); - store_reset(out_sqlda); - out_sqlda = NULL; - *errmsg = - string_sprintf("Interbase describe_statement() failed: %s", - buffer); - *defer_break = FALSE; - goto IBASE_EXIT; - } - out_sqlda = new_sqlda; +if (out_sqlda->sqln < out_sqlda->sqld) + { + XSQLDA *new_sqlda = store_get(XSQLDA_LENGTH(out_sqlda->sqld)); + if (isc_dsql_describe + (status, &stmth, out_sqlda->version, new_sqlda)) + { + isc_interprete(buffer, &statusp); + isc_dsql_free_statement(status, &stmth, DSQL_drop); + store_reset(out_sqlda); + out_sqlda = NULL; + *errmsg = string_sprintf("Interbase describe_statement() failed: %s", + buffer); + *defer_break = FALSE; + goto IBASE_EXIT; } + out_sqlda = new_sqlda; + } /* allocate storage for every returned field */ - for (i = 0, var = out_sqlda->sqlvar; i < out_sqlda->sqld; i++, var++) { - switch (var->sqltype & ~1) { - case SQL_VARYING: - var->sqldata = - (char *) store_get(sizeof(char) * var->sqllen + 2); - break; - case SQL_TEXT: - var->sqldata = - (char *) store_get(sizeof(char) * var->sqllen); - break; - case SQL_SHORT: - var->sqldata = CS store_get(sizeof(short)); - break; - case SQL_LONG: - var->sqldata = CS store_get(sizeof(ISC_LONG)); - break; +for (i = 0, var = out_sqlda->sqlvar; i < out_sqlda->sqld; i++, var++) + { + switch (var->sqltype & ~1) + { + case SQL_VARYING: + var->sqldata = CS store_get(sizeof(char) * var->sqllen + 2); + break; + case SQL_TEXT: + var->sqldata = CS store_get(sizeof(char) * var->sqllen); + break; + case SQL_SHORT: + var->sqldata = CS store_get(sizeof(short)); + break; + case SQL_LONG: + var->sqldata = CS store_get(sizeof(ISC_LONG)); + break; #ifdef SQL_INT64 - case SQL_INT64: - var->sqldata = CS store_get(sizeof(ISC_INT64)); - break; + case SQL_INT64: + var->sqldata = CS store_get(sizeof(ISC_INT64)); + break; #endif - case SQL_FLOAT: - var->sqldata = CS store_get(sizeof(float)); - break; - case SQL_DOUBLE: - var->sqldata = CS store_get(sizeof(double)); - break; + case SQL_FLOAT: + var->sqldata = CS store_get(sizeof(float)); + break; + case SQL_DOUBLE: + var->sqldata = CS store_get(sizeof(double)); + break; #ifdef SQL_TIMESTAMP - case SQL_DATE: - var->sqldata = CS store_get(sizeof(ISC_QUAD)); - break; + case SQL_DATE: + var->sqldata = CS store_get(sizeof(ISC_QUAD)); + break; #else - case SQL_TIMESTAMP: - var->sqldata = CS store_get(sizeof(ISC_TIMESTAMP)); - break; - case SQL_TYPE_DATE: - var->sqldata = CS store_get(sizeof(ISC_DATE)); - break; - case SQL_TYPE_TIME: - var->sqldata = CS store_get(sizeof(ISC_TIME)); - break; -#endif - } - if (var->sqltype & 1) { - var->sqlind = (short *) store_get(sizeof(short)); - } + case SQL_TIMESTAMP: + var->sqldata = CS store_get(sizeof(ISC_TIMESTAMP)); + break; + case SQL_TYPE_DATE: + var->sqldata = CS store_get(sizeof(ISC_DATE)); + break; + case SQL_TYPE_TIME: + var->sqldata = CS store_get(sizeof(ISC_TIME)); + break; + #endif } - - /* finally, we're ready to execute the statement */ - if (isc_dsql_execute - (status, &cn->transh, &stmth, out_sqlda->version, NULL)) { - isc_interprete(buffer, &statusp); - *errmsg = - string_sprintf("Interbase describe_statement() failed: %s", - buffer); - isc_dsql_free_statement(status, &stmth, DSQL_drop); - *defer_break = FALSE; - goto IBASE_EXIT; + if (var->sqltype & 1) + var->sqlind = (short *) store_get(sizeof(short)); + } + +/* finally, we're ready to execute the statement */ +if (isc_dsql_execute + (status, &cn->transh, &stmth, out_sqlda->version, NULL)) + { + isc_interprete(buffer, &statusp); + *errmsg = string_sprintf("Interbase describe_statement() failed: %s", + buffer); + isc_dsql_free_statement(status, &stmth, DSQL_drop); + *defer_break = FALSE; + goto IBASE_EXIT; + } + +while (isc_dsql_fetch(status, &stmth, out_sqlda->version, out_sqlda) != 100L) + { + /* check if an error occurred */ + if (status[0] & status[1]) + { + isc_interprete(buffer, &statusp); + *errmsg = + string_sprintf("Interbase fetch() failed: %s", buffer); + isc_dsql_free_statement(status, &stmth, DSQL_drop); + *defer_break = FALSE; + goto IBASE_EXIT; } - while (isc_dsql_fetch(status, &stmth, out_sqlda->version, out_sqlda) != - 100L) { - /* check if an error occurred */ - if (status[0] & status[1]) { - isc_interprete(buffer, &statusp); - *errmsg = - string_sprintf("Interbase fetch() failed: %s", buffer); - isc_dsql_free_statement(status, &stmth, DSQL_drop); - *defer_break = FALSE; - goto IBASE_EXIT; - } - - if (result != NULL) - result = string_catn(result, &ssize, &offset, US "\n", 1); - - /* Find the number of fields returned. If this is one, we don't add field - names to the data. Otherwise we do. */ - if (out_sqlda->sqld == 1) { - if (out_sqlda->sqlvar[0].sqlind == NULL || *out_sqlda->sqlvar[0].sqlind != -1) /* NULL value yields nothing */ - result = - string_catn(result, &ssize, &offset, US buffer, - fetch_field(buffer, sizeof(buffer), - &out_sqlda->sqlvar[0])); - } - - else - for (i = 0; i < out_sqlda->sqld; i++) { - int len = fetch_field(buffer, sizeof(buffer), - &out_sqlda->sqlvar[i]); - - result = - string_cat(result, &ssize, &offset, - US out_sqlda->sqlvar[i].aliasname, - out_sqlda->sqlvar[i].aliasname_length); - result = string_catn(result, &ssize, &offset, US "=", 1); - - /* Quote the value if it contains spaces or is empty */ - - if (*out_sqlda->sqlvar[i].sqlind == -1) { /* NULL value */ - result = - string_catn(result, &ssize, &offset, US "\"\"", 2); - } - - else if (buffer[0] == 0 || Ustrchr(buffer, ' ') != NULL) { - int j; - result = - string_catn(result, &ssize, &offset, US "\"", 1); - for (j = 0; j < len; j++) { - if (buffer[j] == '\"' || buffer[j] == '\\') - result = - string_cat(result, &ssize, &offset, - US "\\", 1); - result = - string_cat(result, &ssize, &offset, - US buffer + j, 1); - } - result = - string_catn(result, &ssize, &offset, US "\"", 1); - } else { - result = - string_catn(result, &ssize, &offset, US buffer, len); - } - result = string_catn(result, &ssize, &offset, US " ", 1); - } + if (result) + result = string_catn(result, US "\n", 1); + + /* Find the number of fields returned. If this is one, we don't add field + names to the data. Otherwise we do. */ + if (out_sqlda->sqld == 1) + { + if (out_sqlda->sqlvar[0].sqlind == NULL || *out_sqlda->sqlvar[0].sqlind != -1) /* NULL value yields nothing */ + result = string_catn(result, US buffer, + fetch_field(buffer, sizeof(buffer), + &out_sqlda->sqlvar[0])); } + else + for (i = 0; i < out_sqlda->sqld; i++) + { + int len = fetch_field(buffer, sizeof(buffer), &out_sqlda->sqlvar[i]); + + result = string_catn(result, US out_sqlda->sqlvar[i].aliasname, + out_sqlda->sqlvar[i].aliasname_length); + result = string_catn(result, US "=", 1); + + /* Quote the value if it contains spaces or is empty */ + + if (*out_sqlda->sqlvar[i].sqlind == -1) /* NULL value */ + result = string_catn(result, US "\"\"", 2); + + else if (buffer[0] == 0 || Ustrchr(buffer, ' ') != NULL) + { + int j; + + result = string_catn(result, US "\"", 1); + for (j = 0; j < len; j++) + { + if (buffer[j] == '\"' || buffer[j] == '\\') + result = string_cat(result, US "\\", 1); + result = string_cat(result, US buffer + j, 1); + } + result = string_catn(result, US "\"", 1); + } + else + result = string_catn(result, US buffer, len); + result = string_catn(result, US " ", 1); + } + } + /* If result is NULL then no data has been found and so we return FAIL. Otherwise, we must terminate the string which has been built; string_cat() always leaves enough room for a terminating zero. */ - if (result == NULL) { - yield = FAIL; - *errmsg = US "Interbase: no data found"; - } else { - result[offset] = 0; - store_reset(result + offset + 1); - } +if (!result) + { + yield = FAIL; + *errmsg = US "Interbase: no data found"; + } +else + store_reset(result->s + result->ptr + 1); /* Get here by goto from various error checks. */ - IBASE_EXIT: +IBASE_EXIT: - if (stmth != NULL) - isc_dsql_free_statement(status, &stmth, DSQL_drop); +if (stmth) + isc_dsql_free_statement(status, &stmth, DSQL_drop); /* Non-NULL result indicates a successful result */ - if (result != NULL) { - *resultptr = result; - return OK; - } else { - DEBUG(D_lookup) debug_printf("%s\n", *errmsg); - return yield; /* FAIL or DEFER */ - } +if (result) + { + *resultptr = string_from_gstring(result); + return OK; + } +else + { + DEBUG(D_lookup) debug_printf("%s\n", *errmsg); + return yield; /* FAIL or DEFER */ + } } diff --git a/src/src/lookups/ldap.c b/src/src/lookups/ldap.c index b52ef2221..8d6ac2674 100644 --- a/src/src/lookups/ldap.c +++ b/src/src/lookups/ldap.c @@ -145,7 +145,7 @@ struct timeval *timeoutptr = NULL; uschar *attr; uschar **attrp; -uschar *data = NULL; +gstring * data = NULL; uschar *dn = NULL; uschar *host; uschar **values; @@ -161,9 +161,7 @@ int error_yield = DEFER; int msgid; int rc, ldap_rc, ldap_parse_rc; int port; -int ptr = 0; int rescount = 0; -int size = 0; BOOL attribute_found = FALSE; BOOL ldapi = FALSE; @@ -722,7 +720,7 @@ while ((rc = ldap_result(lcp->ld, msgid, 0, timeoutptr, &result)) == DEBUG(D_lookup) debug_printf("LDAP result loop\n"); for(e = ldap_first_entry(lcp->ld, result), valuecount = 0; - e != NULL; + e; e = ldap_next_entry(lcp->ld, e)) { uschar *new_dn; @@ -734,7 +732,7 @@ while ((rc = ldap_result(lcp->ld, msgid, 0, timeoutptr, &result)) == /* Results for multiple entries values are separated by newlines. */ - if (data != NULL) data = string_catn(data, &size, &ptr, US"\n", 1); + if (data) data = string_catn(data, US"\n", 1); /* Get the DN from the last result. */ @@ -762,8 +760,8 @@ while ((rc = ldap_result(lcp->ld, msgid, 0, timeoutptr, &result)) == { /* condition, because of the else */ if (new_dn != NULL) /* below, that's for the first only */ { - data = string_cat(data, &size, &ptr, new_dn); - data[ptr] = 0; + data = string_cat(data, new_dn); + (void) string_from_gstring(data); attribute_found = TRUE; } } @@ -776,8 +774,7 @@ while ((rc = ldap_result(lcp->ld, msgid, 0, timeoutptr, &result)) == If there are multiple values, they are given within the quotes, comma separated. */ else for (attr = US ldap_first_attribute(lcp->ld, e, &ber); - attr != NULL; - attr = US ldap_next_attribute(lcp->ld, e, ber)) + attr; attr = US ldap_next_attribute(lcp->ld, e, ber)) { DEBUG(D_lookup) debug_printf("LDAP attr loop\n"); @@ -789,21 +786,20 @@ while ((rc = ldap_result(lcp->ld, msgid, 0, timeoutptr, &result)) == { /* Get array of values for this attribute. */ - if ((firstval = values = USS ldap_get_values(lcp->ld, e, CS attr)) - != NULL) + if ((firstval = values = USS ldap_get_values(lcp->ld, e, CS attr))) { if (attrs_requested != 1) { if (insert_space) - data = string_catn(data, &size, &ptr, US" ", 1); + data = string_catn(data, US" ", 1); else insert_space = TRUE; - data = string_cat(data, &size, &ptr, attr); - data = string_catn(data, &size, &ptr, US"=\"", 2); + data = string_cat(data, attr); + data = string_catn(data, US"=\"", 2); } - while (*values != NULL) + while (*values) { uschar *value = *values; int len = Ustrlen(value); @@ -818,7 +814,7 @@ while ((rc = ldap_result(lcp->ld, msgid, 0, timeoutptr, &result)) == attribute and append only every non first value. */ if (data && valuecount > 1) - data = string_catn(data, &size, &ptr, US",", 1); + data = string_catn(data, US",", 1); /* For multiple attributes, the data is in quotes. We must escape internal quotes, backslashes, newlines, and must double commas. */ @@ -829,14 +825,14 @@ while ((rc = ldap_result(lcp->ld, msgid, 0, timeoutptr, &result)) == for (j = 0; j < len; j++) { if (value[j] == '\n') - data = string_catn(data, &size, &ptr, US"\\n", 2); + data = string_catn(data, US"\\n", 2); else if (value[j] == ',') - data = string_catn(data, &size, &ptr, US",,", 2); + data = string_catn(data, US",,", 2); else { if (value[j] == '\"' || value[j] == '\\') - data = string_catn(data, &size, &ptr, US"\\", 1); - data = string_catn(data, &size, &ptr, value+j, 1); + data = string_catn(data, US"\\", 1); + data = string_catn(data, value+j, 1); } } } @@ -848,9 +844,9 @@ while ((rc = ldap_result(lcp->ld, msgid, 0, timeoutptr, &result)) == int j; for (j = 0; j < len; j++) if (value[j] == ',') - data = string_catn(data, &size, &ptr, US",,", 2); + data = string_catn(data, US",,", 2); else - data = string_catn(data, &size, &ptr, value+j, 1); + data = string_catn(data, value+j, 1); } @@ -863,7 +859,7 @@ while ((rc = ldap_result(lcp->ld, msgid, 0, timeoutptr, &result)) == /* Closing quote at the end of the data for a named attribute. */ if (attrs_requested != 1) - data = string_catn(data, &size, &ptr, US"\"", 1); + data = string_catn(data, US"\"", 1); /* Free the values */ @@ -890,15 +886,15 @@ while ((rc = ldap_result(lcp->ld, msgid, 0, timeoutptr, &result)) == /* Terminate the dynamic string that we have built and reclaim unused store */ -if (data != NULL) +if (data) { - data[ptr] = 0; - store_reset(data + ptr + 1); + (void) string_from_gstring(data); + store_reset(data->s + data->ptr + 1); } /* Copy the last dn into eldap_dn */ -if (dn != NULL) +if (dn) { eldap_dn = string_copy(dn); #if defined LDAP_LIB_NETSCAPE || defined LDAP_LIB_OPENLDAP2 @@ -1077,8 +1073,8 @@ if (!attribute_found) /* Otherwise, it's all worked */ -DEBUG(D_lookup) debug_printf("LDAP search: returning: %s\n", data); -*res = data; +DEBUG(D_lookup) debug_printf("LDAP search: returning: %s\n", data->s); +*res = data->s; RETURN_OK: if (result != NULL) ldap_msgfree(result); diff --git a/src/src/lookups/lf_functions.h b/src/src/lookups/lf_functions.h index d2487d362..210aae4d5 100644 --- a/src/src/lookups/lf_functions.h +++ b/src/src/lookups/lf_functions.h @@ -9,7 +9,7 @@ extern int lf_check_file(int, uschar *, int, int, uid_t *, gid_t *, const char *, uschar **); -extern uschar *lf_quote(uschar *, uschar *, int, uschar *, int *, int *); +extern gstring *lf_quote(uschar *, uschar *, int, gstring *); extern int lf_sqlperform(const uschar *, const uschar *, const uschar *, const uschar *, uschar **, uschar **, uint *, int(*)(const uschar *, uschar *, uschar **, diff --git a/src/src/lookups/lf_quote.c b/src/src/lookups/lf_quote.c index 2a76756e9..1541d0d16 100644 --- a/src/src/lookups/lf_quote.c +++ b/src/src/lookups/lf_quote.c @@ -22,18 +22,15 @@ Arguments: name the field name value the data value vlength the data length - result the result pointer - asize points to the size variable - aoffset points to the offset variable + result the result expanding-string Returns: the result pointer (possibly updated) */ -uschar * -lf_quote(uschar *name, uschar *value, int vlength, uschar *result, int *asize, - int *aoffset) +gstring * +lf_quote(uschar *name, uschar *value, int vlength, gstring * result) { -result = string_append(result, asize, aoffset, 2, name, US"="); +result = string_append(result, 2, name, US"="); /* NULL is handled as an empty string */ @@ -49,19 +46,19 @@ character. */ if (value[0] == 0 || Ustrpbrk(value, " \t\n\r") != NULL || value[0] == '\"') { int j; - result = string_catn(result, asize, aoffset, US"\"", 1); + result = string_catn(result, US"\"", 1); for (j = 0; j < vlength; j++) { if (value[j] == '\"' || value[j] == '\\') - result = string_catn(result, asize, aoffset, US"\\", 1); - result = string_catn(result, asize, aoffset, US value+j, 1); + result = string_catn(result, US"\\", 1); + result = string_catn(result, US value+j, 1); } - result = string_catn(result, asize, aoffset, US"\"", 1); + result = string_catn(result, US"\"", 1); } else - result = string_catn(result, asize, aoffset, US value, vlength); + result = string_catn(result, US value, vlength); -return string_catn(result, asize, aoffset, US" ", 1); +return string_catn(result, US" ", 1); } /* End of lf_quote.c */ diff --git a/src/src/lookups/lsearch.c b/src/src/lookups/lsearch.c index 6101d00ac..745856d02 100644 --- a/src/src/lookups/lsearch.c +++ b/src/src/lookups/lsearch.c @@ -101,11 +101,10 @@ for (last_was_eol = TRUE; Ufgets(buffer, sizeof(buffer), f) != NULL; last_was_eol = this_is_eol) { - int ptr, size; int p = Ustrlen(buffer); int linekeylength; BOOL this_is_comment; - uschar *yield; + gstring * yield; uschar *s = buffer; /* Check whether this the final segment of a line. If it follows an @@ -240,7 +239,7 @@ for (last_was_eol = TRUE; /* Reset dynamic store, if we need to, and revert to the search pool */ - if (reset_point != NULL) + if (reset_point) { store_reset(reset_point); store_pool = old_pool; @@ -254,11 +253,9 @@ for (last_was_eol = TRUE; Initialize, and copy the first segment of data. */ this_is_comment = FALSE; - size = 100; - ptr = 0; - yield = store_get(size); + yield = string_get(100); if (*s != 0) - yield = string_cat(yield, &size, &ptr, s); + yield = string_cat(yield, s); /* Now handle continuations */ @@ -294,18 +291,17 @@ for (last_was_eol = TRUE; /* Join a physical or logical line continuation onto the result string. */ - yield = string_cat(yield, &size, &ptr, s); + yield = string_cat(yield, s); } - yield[ptr] = 0; - store_reset(yield + ptr + 1); - *result = yield; + store_reset(yield->s + yield->ptr + 1); + *result = string_from_gstring(yield); return OK; } /* Reset dynamic store, if we need to */ -if (reset_point != NULL) +if (reset_point) { store_reset(reset_point); store_pool = old_pool; diff --git a/src/src/lookups/mysql.c b/src/src/lookups/mysql.c index ddc7dc841..53789133e 100644 --- a/src/src/lookups/mysql.c +++ b/src/src/lookups/mysql.c @@ -94,11 +94,9 @@ MYSQL_ROW mysql_row_data; MYSQL_FIELD *fields; int i; -int ssize = 0; -int offset = 0; int yield = DEFER; unsigned int num_fields; -uschar *result = NULL; +gstring * result = NULL; mysql_connection *cn; uschar *server_copy = NULL; uschar *sdata[4]; @@ -242,7 +240,8 @@ if ((mysql_result = mysql_use_result(mysql_handle)) == NULL) if ( mysql_field_count(mysql_handle) == 0 ) { DEBUG(D_lookup) debug_printf("MYSQL: query was not one that returns data\n"); - result = string_sprintf("%d", mysql_affected_rows(mysql_handle)); + result = string_cat(result, + string_sprintf("%d", mysql_affected_rows(mysql_handle))); *do_cache = 0; goto MYSQL_EXIT; } @@ -262,25 +261,25 @@ row, we insert '\n' between them. */ fields = mysql_fetch_fields(mysql_result); -while ((mysql_row_data = mysql_fetch_row(mysql_result)) != NULL) +while ((mysql_row_data = mysql_fetch_row(mysql_result))) { unsigned long *lengths = mysql_fetch_lengths(mysql_result); - if (result != NULL) - result = string_catn(result, &ssize, &offset, US"\n", 1); + if (result) + result = string_catn(result, US"\n", 1); if (num_fields == 1) { if (mysql_row_data[0] != NULL) /* NULL value yields nothing */ - result = string_catn(result, &ssize, &offset, US mysql_row_data[0], + { + result = string_catn(result, US mysql_row_data[0], lengths[0]); + (void) string_from_gstring(result); + } } else for (i = 0; i < num_fields; i++) - { - result = lf_quote(US fields[i].name, US mysql_row_data[i], lengths[i], - result, &ssize, &offset); - } + result = lf_quote(US fields[i].name, US mysql_row_data[i], lengths[i], result); } /* more results? -1 = no, >0 = error, 0 = yes (keep looping) @@ -302,15 +301,15 @@ while((i = mysql_next_result(mysql_handle)) >= 0) { Otherwise, we must terminate the string which has been built; string_cat() always leaves enough room for a terminating zero. */ -if (result == NULL) +if (!result) { yield = FAIL; *errmsg = US"MYSQL: no data found"; } else { - result[offset] = 0; - store_reset(result + offset + 1); + (void) string_from_gstring(result); + store_reset(result->s + result->ptr + 1); } /* Get here by goto from various error checks and from the case where no data @@ -321,13 +320,13 @@ MYSQL_EXIT: /* Free mysal store for any result that was got; don't close the connection, as it is cached. */ -if (mysql_result != NULL) mysql_free_result(mysql_result); +if (mysql_result) mysql_free_result(mysql_result); /* Non-NULL result indicates a successful result */ -if (result != NULL) +if (result) { - *resultptr = result; + *resultptr = result->s; return OK; } else diff --git a/src/src/lookups/nisplus.c b/src/src/lookups/nisplus.c index ff632a1ca..03c343103 100644 --- a/src/src/lookups/nisplus.c +++ b/src/src/lookups/nisplus.c @@ -46,8 +46,6 @@ nisplus_find(void *handle, uschar *filename, uschar *query, int length, uschar **result, uschar **errmsg, uint *do_cache) { int i; -int ssize = 0; -int offset = 0; int error_error = FAIL; uschar *field_name = NULL; nis_result *nrt = NULL; @@ -57,6 +55,7 @@ struct entry_obj *eo; struct table_obj *ta; uschar *p = query + length; uschar *yield = NULL; +gstring * yield = NULL; do_cache = do_cache; /* Placate picky compilers */ @@ -156,33 +155,34 @@ for (i = 0; i < eo->en_cols.en_cols_len; i++) if (field_name == NULL) { - yield = string_cat(yield, &ssize, &offset,US tc->tc_name); - yield = string_catn(yield, &ssize, &offset, US"=", 1); + yield = string_cat (yield, tc->tc_name); + yield = string_catn(yield, US"=", 1); /* Quote the value if it contains spaces or is empty */ if (value[0] == 0 || Ustrchr(value, ' ') != NULL) { int j; - yield = string_catn(yield, &ssize, &offset, US"\"", 1); + yield = string_catn(yield, US"\"", 1); for (j = 0; j < len; j++) { if (value[j] == '\"' || value[j] == '\\') - yield = string_catn(yield, &ssize, &offset, US"\\", 1); - yield = string_catn(yield, &ssize, &offset, value+j, 1); + yield = string_catn(yield, US"\\", 1); + yield = string_catn(yield, value+j, 1); } - yield = string_catn(yield, &ssize, &offset, US"\"", 1); + yield = string_catn(yield, US"\"", 1); } - else yield = string_catn(yield, &ssize, &offset, value, len); + else + eyield = string_catn(yield, value, len); - yield = string_catn(yield, &ssize, &offset, US" ", 1); + yield = string_catn(yield, US" ", 1); } /* When the specified field is found, grab its data and finish */ else if (Ustrcmp(field_name, tc->tc_name) == 0) { - yield = string_copyn(value, len); + yield = string_catn(yield, value, len); goto NISPLUS_EXIT; } } @@ -190,26 +190,23 @@ for (i = 0; i < eo->en_cols.en_cols_len; i++) /* Error if a field name was specified and we didn't find it; if no field name, ensure the concatenated data is zero-terminated. */ -if (field_name != NULL) +if (field_name) *errmsg = string_sprintf("NIS+ field %s not found for %s", field_name, query); else - { - yield[offset] = 0; - store_reset(yield + offset + 1); - } + store_reset(yield->s + yield->ptr + 1); /* Restore the colon in the query, and free result store before finishing. */ NISPLUS_EXIT: -if (field_name != NULL) field_name[-1] = ':'; -if (nrt != NULL) nis_freeresult(nrt); -if (nre != NULL) nis_freeresult(nre); +if (field_name) field_name[-1] = ':'; +if (nrt) nis_freeresult(nrt); +if (nre) nis_freeresult(nre); -if (yield != NULL) +if (yield) { - *result = yield; + *result = string_from_gstring(yield); return OK; } diff --git a/src/src/lookups/oracle.c b/src/src/lookups/oracle.c index eca15f1b4..bc14def70 100644 --- a/src/src/lookups/oracle.c +++ b/src/src/lookups/oracle.c @@ -255,15 +255,12 @@ Ora_Define *def = NULL; void *hda = NULL; int i; -int ssize = 0; -int offset = 0; int yield = DEFER; unsigned int num_fields = 0; -uschar *result = NULL; +gstring * result = NULL; oracle_connection *cn = NULL; uschar *server_copy = NULL; uschar *sdata[4]; -uschar tmp[1024]; /* Disaggregate the parameters from the server argument. The order is host, database, user, password. We can write to the string, since it is in a @@ -292,19 +289,17 @@ if (sdata[1][0] == 0) sdata[1] = NULL; /* See if we have a cached connection to the server */ -for (cn = oracle_connections; cn != NULL; cn = cn->next) - { +for (cn = oracle_connections; cn; cn = cn->next) if (strcmp(cn->server, server_copy) == 0) { oracle_handle = cn->handle; hda = cn->hda_mem; break; } - } /* If no cached connection, we must set one up */ -if (cn == NULL) +if (!cn) { DEBUG(D_lookup) debug_printf("ORACLE new connection: host=%s database=%s " "user=%s\n", sdata[0], sdata[1], sdata[2]); @@ -400,12 +395,12 @@ while (cda->rc != NO_DATA_FOUND) /* Loop for each row */ ofetch(cda); if(cda->rc == NO_DATA_FOUND) break; - if (result) result = string_catn(result, &ssize, &offset, "\n", 1); + if (result) result = string_catn(result, "\n", 1); /* Single field - just add on the data */ if (num_fields == 1) - result = string_catn(result, &ssize, &offset, def[0].buf, def[0].col_retlen); + result = string_catn(result, def[0].buf, def[0].col_retlen); /* Multiple fields - precede by file name, removing {lead,trail}ing WS */ @@ -417,8 +412,8 @@ while (cda->rc != NO_DATA_FOUND) /* Loop for each row */ while (*s != 0 && isspace(*s)) s++; slen = Ustrlen(s); while (slen > 0 && isspace(s[slen-1])) slen--; - result = string_catn(result, &ssize, &offset, s, slen); - result = string_catn(result, &ssize, &offset, US"=", 1); + result = string_catn(result, s, slen); + result = string_catn(result, US"=", 1); /* int and float type wont ever need escaping. Otherwise, quote the value if it contains spaces or is empty. */ @@ -427,41 +422,38 @@ while (cda->rc != NO_DATA_FOUND) /* Loop for each row */ (def[i].buf[0] == 0 || strchr(def[i].buf, ' ') != NULL)) { int j; - result = string_catn(result, &ssize, &offset, "\"", 1); + result = string_catn(result, "\"", 1); for (j = 0; j < def[i].col_retlen; j++) { if (def[i].buf[j] == '\"' || def[i].buf[j] == '\\') - result = string_catn(result, &ssize, &offset, "\\", 1); - result = string_catn(result, &ssize, &offset, def[i].buf+j, 1); + result = string_catn(result, "\\", 1); + result = string_catn(result, def[i].buf+j, 1); } - result = string_catn(result, &ssize, &offset, "\"", 1); + result = string_catn(result, "\"", 1); } else switch(desc[i].dbtype) { case INT_TYPE: - sprintf(CS tmp, "%d", def[i].int_buf); - result = string_cat(result, &ssize, &offset, tmp); - break; + result = string_cat(result, string_sprintf("%d", def[i].int_buf)); + break; case FLOAT_TYPE: - sprintf(CS tmp, "%f", def[i].flt_buf); - result = string_cat(result, &ssize, &offset, tmp); - break; + result = string_cat(result, string_sprintf("%f", def[i].flt_buf)); + break; case STRING_TYPE: - result = string_catn(result, &ssize, &offset, def[i].buf, - def[i].col_retlen); - break; + result = string_catn(result, def[i].buf, def[i].col_retlen); + break; default: - *errmsg = string_sprintf("ORACLE: unknown field type %d", desc[i].dbtype); - *defer_break = FALSE; - result = NULL; - goto ORACLE_EXIT; + *errmsg = string_sprintf("ORACLE: unknown field type %d", desc[i].dbtype); + *defer_break = FALSE; + result = NULL; + goto ORACLE_EXIT; } - result = string_catn(result, &ssize, &offset, " ", 1); + result = string_catn(result, " ", 1); } } @@ -469,16 +461,13 @@ while (cda->rc != NO_DATA_FOUND) /* Loop for each row */ Otherwise, we must terminate the string which has been built; string_cat() always leaves enough room for a terminating zero. */ -if (result == NULL) +if (!result) { yield = FAIL; *errmsg = "ORACLE: no data found"; } else - { - result[offset] = 0; - store_reset(result + offset + 1); - } + store_reset(result->s + result->ptr + 1); /* Get here by goto from various error checks. */ @@ -492,9 +481,9 @@ ORACLE_EXIT_NO_VALS: /* Non-NULL result indicates a successful result */ -if (result != NULL) +if (result) { - *resultptr = result; + *resultptr = string_from_gstring(result); return OK; } else diff --git a/src/src/lookups/pgsql.c b/src/src/lookups/pgsql.c index d71f97b33..ef8f0997d 100644 --- a/src/src/lookups/pgsql.c +++ b/src/src/lookups/pgsql.c @@ -125,9 +125,7 @@ PGconn *pg_conn = NULL; PGresult *pg_result = NULL; int i; -uschar *result = NULL; -int ssize = 0; -int offset = 0; +gstring * result = NULL; int yield = DEFER; unsigned int num_fields, num_tuples; pgsql_connection *cn; @@ -287,30 +285,31 @@ else { case PGRES_EMPTY_QUERY: case PGRES_COMMAND_OK: - /* The command was successful but did not return any data since it was - * not SELECT but either an INSERT, UPDATE or DELETE statement. Tell the - * high level code to not cache this query, and clean the current cache for - * this handle by setting *do_cache zero. */ - result = string_copy(US PQcmdTuples(pg_result)); - offset = Ustrlen(result); - *do_cache = 0; - DEBUG(D_lookup) debug_printf("PGSQL: command does not return any data " - "but was successful. Rows affected: %s\n", result); + /* The command was successful but did not return any data since it was + not SELECT but either an INSERT, UPDATE or DELETE statement. Tell the + high level code to not cache this query, and clean the current cache for + this handle by setting *do_cache zero. */ + + result = string_cat(result, US PQcmdTuples(pg_result)); + *do_cache = 0; + DEBUG(D_lookup) debug_printf("PGSQL: command does not return any data " + "but was successful. Rows affected: %s\n", result->s); + break; case PGRES_TUPLES_OK: - break; + break; default: - /* This was the original code: - *errmsg = string_sprintf("PGSQL: query failed: %s\n", - PQresultErrorMessage(pg_result)); - This was suggested by a user: - */ + /* This was the original code: + *errmsg = string_sprintf("PGSQL: query failed: %s\n", + PQresultErrorMessage(pg_result)); + This was suggested by a user: + */ - *errmsg = string_sprintf("PGSQL: query failed: %s (%s) (%s)\n", + *errmsg = string_sprintf("PGSQL: query failed: %s (%s) (%s)\n", PQresultErrorMessage(pg_result), PQresStatus(PQresultStatus(pg_result)), query); - goto PGSQL_EXIT; + goto PGSQL_EXIT; } /* Result is in pg_result. Find the number of fields returned. If this is one, @@ -326,23 +325,19 @@ row, we insert '\n' between them. */ for (i = 0; i < num_tuples; i++) { - if (result != NULL) - result = string_catn(result, &ssize, &offset, US"\n", 1); - - if (num_fields == 1) - { - result = string_catn(result, &ssize, &offset, - US PQgetvalue(pg_result, i, 0), PQgetlength(pg_result, i, 0)); - } + if (result) + result = string_catn(result, US"\n", 1); - else + if (num_fields == 1) + result = string_catn(NULL, + US PQgetvalue(pg_result, i, 0), PQgetlength(pg_result, i, 0)); + else { int j; for (j = 0; j < num_fields; j++) { uschar *tmp = US PQgetvalue(pg_result, i, j); - result = lf_quote(US PQfname(pg_result, j), tmp, Ustrlen(tmp), result, - &ssize, &offset); + result = lf_quote(US PQfname(pg_result, j), tmp, Ustrlen(tmp), result); } } } @@ -351,16 +346,13 @@ for (i = 0; i < num_tuples; i++) Otherwise, we must terminate the string which has been built; string_cat() always leaves enough room for a terminating zero. */ -if (result == NULL) +if (!result) { yield = FAIL; *errmsg = US"PGSQL: no data found"; } else - { - result[offset] = 0; - store_reset(result + offset + 1); - } + store_reset(result->s + result->ptr + 1); /* Get here by goto from various error checks. */ @@ -369,13 +361,13 @@ PGSQL_EXIT: /* Free store for any result that was got; don't close the connection, as it is cached. */ -if (pg_result != NULL) PQclear(pg_result); +if (pg_result) PQclear(pg_result); /* Non-NULL result indicates a successful result */ -if (result != NULL) +if (result) { - *resultptr = result; + *resultptr = string_from_gstring(result); return OK; } else diff --git a/src/src/lookups/redis.c b/src/src/lookups/redis.c index 3a96f5ef9..e8989ca3a 100644 --- a/src/src/lookups/redis.c +++ b/src/src/lookups/redis.c @@ -80,13 +80,10 @@ redisReply *redis_reply = NULL; redisReply *entry = NULL; redisReply *tentry = NULL; redis_connection *cn; -int ssize = 0; -int offset = 0; int yield = DEFER; int i, j; -uschar *result = NULL; +gstring * result = NULL; uschar *server_copy = NULL; -uschar *tmp, *ttmp; uschar *sdata[3]; /* Disaggregate the parameters from the server argument. @@ -217,10 +214,13 @@ if(sdata[1]) for (i = 0; *s && i < nele(argv); i++) { - for (argv[i] = NULL, siz = ptr = 0; (c = *s) && !isspace(c); s++) + gstring * g; + + for (g = NULL; (c = *s) && !isspace(c); s++) if (c != '\\' || *++s) /* backslash protects next char */ - argv[i] = string_catn(argv[i], &siz, &ptr, s, 1); - *(argv[i]+ptr) = '\0'; + g = string_catn(g, s, 1); + argv[i] = string_from_gstring(g); + DEBUG(D_lookup) debug_printf("REDIS: argv[%d] '%s'\n", i, argv[i]); while (isspace(*s)) s++; } @@ -249,20 +249,18 @@ switch (redis_reply->type) case REDIS_REPLY_NIL: DEBUG(D_lookup) debug_printf("REDIS: query was not one that returned any data\n"); - result = string_sprintf(""); + result = string_catn(result, US"", 1); *do_cache = 0; goto REDIS_EXIT; /* NOTREACHED */ case REDIS_REPLY_INTEGER: - ttmp = (redis_reply->integer != 0) ? US"true" : US"false"; - result = string_cat(result, &ssize, &offset, US ttmp); + result = string_cat(result, redis_reply->integer != 0 ? US"true" : US"false"); break; case REDIS_REPLY_STRING: case REDIS_REPLY_STATUS: - result = string_catn(result, &ssize, &offset, - US redis_reply->str, redis_reply->len); + result = string_catn(result, US redis_reply->str, redis_reply->len); break; case REDIS_REPLY_ARRAY: @@ -275,17 +273,15 @@ switch (redis_reply->type) entry = redis_reply->element[i]; if (result) - result = string_catn(result, &ssize, &offset, US"\n", 1); + result = string_catn(result, US"\n", 1); switch (entry->type) { case REDIS_REPLY_INTEGER: - tmp = string_sprintf("%d", entry->integer); - result = string_cat(result, &ssize, &offset, US tmp); + result = string_cat(result, string_sprintf("%d", entry->integer)); break; case REDIS_REPLY_STRING: - result = string_catn(result, &ssize, &offset, - US entry->str, entry->len); + result = string_catn(result, US entry->str, entry->len); break; case REDIS_REPLY_ARRAY: for (j = 0; j < entry->elements; j++) @@ -293,17 +289,15 @@ switch (redis_reply->type) tentry = entry->element[j]; if (result) - result = string_catn(result, &ssize, &offset, US"\n", 1); + result = string_catn(result, US"\n", 1); switch (tentry->type) { case REDIS_REPLY_INTEGER: - ttmp = string_sprintf("%d", tentry->integer); - result = string_cat(result, &ssize, &offset, US ttmp); + result = string_cat(result, string_sprintf("%d", tentry->integer)); break; case REDIS_REPLY_STRING: - result = string_catn(result, &ssize, &offset, - US tentry->str, tentry->len); + result = string_catn(result, US tentry->str, tentry->len); break; case REDIS_REPLY_ARRAY: DEBUG(D_lookup) @@ -327,10 +321,7 @@ switch (redis_reply->type) if (result) - { - result[offset] = 0; - store_reset(result + offset + 1); - } + store_reset(result->s + result->ptr + 1); else { yield = FAIL; @@ -348,7 +339,7 @@ if (redis_reply) freeReplyObject(redis_reply); if (result) { - *resultptr = result; + *resultptr = string_from_gstring(result); return OK; } else diff --git a/src/src/lookups/sqlite.c b/src/src/lookups/sqlite.c index 0b01fdbce..0df853736 100644 --- a/src/src/lookups/sqlite.c +++ b/src/src/lookups/sqlite.c @@ -41,21 +41,16 @@ return db; /* See local README for interface description. */ -struct strbuf { - uschar *string; - int size; - int len; -}; - -static int sqlite_callback(void *arg, int argc, char **argv, char **azColName) +static int +sqlite_callback(void *arg, int argc, char **argv, char **azColName) { -struct strbuf *res = arg; +gstring * res = *(gstring **)arg; int i; /* For second and subsequent results, insert \n */ -if (res->string != NULL) - res->string = string_catn(res->string, &res->size, &res->len, US"\n", 1); +if (res) + res = string_catn(res, US"\n", 1); if (argc > 1) { @@ -63,18 +58,14 @@ if (argc > 1) for (i = 0; i < argc; i++) { uschar *value = US((argv[i] != NULL)? argv[i]:""); - res->string = lf_quote(US azColName[i], value, Ustrlen(value), res->string, - &res->size, &res->len); + res = lf_quote(US azColName[i], value, Ustrlen(value), res); } } else - { - res->string = string_append(res->string, &res->size, &res->len, 1, - (argv[0] != NULL)? argv[0]:""); - } + res = string_cat(res, argv[0] ? US argv[0] : US ""); -res->string[res->len] = 0; +*(gstring **)arg = res; return 0; } @@ -84,7 +75,7 @@ sqlite_find(void *handle, uschar *filename, const uschar *query, int length, uschar **result, uschar **errmsg, uint *do_cache) { int ret; -struct strbuf res = { NULL, 0, 0 }; +gstring * res = NULL; ret = sqlite3_exec(handle, CS query, sqlite_callback, &res, (char **)errmsg); if (ret != SQLITE_OK) @@ -93,9 +84,9 @@ if (ret != SQLITE_OK) return FAIL; } -if (res.string == NULL) *do_cache = 0; +if (!res) *do_cache = 0; -*result = res.string; +*result = string_from_gstring(res); return OK; } diff --git a/src/src/malware.c b/src/src/malware.c index 32f2e9e49..ccb7e6d20 100644 --- a/src/src/malware.c +++ b/src/src/malware.c @@ -710,6 +710,7 @@ badseek: err = errno; if (drweb_vnum) { int i; + gstring * g = NULL; /* setup default virus name */ malware_name = US"unknown"; @@ -721,7 +722,8 @@ badseek: err = errno; /* read and concatenate virus names into one string */ for (i = 0; i < drweb_vnum; i++) { - int size = 0, off = 0, ovector[10*3]; + int ovector[10*3]; + /* read the size of report */ if (!recv_len(sock, &drweb_slen, sizeof(drweb_slen), tmo)) return m_errlog_defer_3(scanent, CUS callout_address, @@ -745,16 +747,16 @@ badseek: err = errno; pcre_get_substring(CS tmpbuf, ovector, result, 1, &pre_malware_nb); if (i==0) /* the first name we just copy to malware_name */ - malware_name = string_append(NULL, &size, &off, - 1, pre_malware_nb); + g = string_cat(NULL, pre_malware_nb); + /*XXX could be string_append_listele? */ else /* concatenate each new virus name to previous */ - malware_name = string_append(malware_name, &size, &off, - 2, "/", pre_malware_nb); + g = string_append(g, 2, "/", pre_malware_nb); pcre_free_substring(pre_malware_nb); } } + malware_name = string_from_gstring(g); } else { diff --git a/src/src/mime.c b/src/src/mime.c index 61dabd2ac..36737e9eb 100644 --- a/src/src/mime.c +++ b/src/src/mime.c @@ -434,8 +434,7 @@ static uschar * mime_param_val(uschar ** sp) { uschar * s = *sp; -uschar * val = NULL; -int size = 0, ptr = 0; +gstring * val = NULL; /* debug_printf_indent(" considering paramval '%s'\n", s); */ @@ -444,14 +443,13 @@ while (*s && *s != ';') /* ; terminates */ { s++; /* skip opening " */ while (*s && *s != '"') /* " protects ; */ - val = string_catn(val, &size, &ptr, s++, 1); + val = string_catn(val, s++, 1); if (*s) s++; /* skip closing " */ } else - val = string_catn(val, &size, &ptr, s++, 1); -if (val) val[ptr] = '\0'; + val = string_catn(val, s++, 1); *sp = s; -return val; +return string_from_gstring(val); } static uschar * @@ -474,27 +472,25 @@ return s; static uschar * rfc2231_to_2047(const uschar * fname, const uschar * charset, int * len) { -int size = 0, ptr = 0; -uschar * val = string_catn(NULL, &size, &ptr, US"=?", 2); +gstring * val = string_catn(NULL, US"=?", 2); uschar c; if (charset) - val = string_cat(val, &size, &ptr, charset); -val = string_catn(val, &size, &ptr, US"?Q?", 3); + val = string_cat(val, charset); +val = string_catn(val, US"?Q?", 3); while ((c = *fname)) if (c == '%' && isxdigit(fname[1]) && isxdigit(fname[2])) { - val = string_catn(val, &size, &ptr, US"=", 1); - val = string_catn(val, &size, &ptr, ++fname, 2); + val = string_catn(val, US"=", 1); + val = string_catn(val, ++fname, 2); fname += 2; } else - val = string_catn(val, &size, &ptr, fname++, 1); + val = string_catn(val, fname++, 1); -val = string_catn(val, &size, &ptr, US"?=", 2); -val[*len = ptr] = '\0'; -return val; +val = string_catn(val, US"?=", 2); +return string_from_gstring(val); } diff --git a/src/src/pdkim/pdkim.c b/src/src/pdkim/pdkim.c index 695288162..06d455d7d 100644 --- a/src/src/pdkim/pdkim.c +++ b/src/src/pdkim/pdkim.c @@ -229,18 +229,20 @@ return new_entry; /* Trim whitespace fore & aft */ static void -pdkim_strtrim(uschar * str) +pdkim_strtrim(gstring * str) { -uschar * p = str; -uschar * q = str; -while (*p == '\t' || *p == ' ') p++; /* skip whitespace */ -while (*p) {*q = *p; q++; p++;} /* dump the leading whitespace */ -*q = '\0'; -while (q != str && ( (*q == '\0') || (*q == '\t') || (*q == ' ') ) ) - { /* dump trailing whitespace */ - *q = '\0'; - q--; - } +uschar * p = str->s; +uschar * q = p + str->ptr; + +while (*p == '\t' || *p == ' ') /* dump the leading whitespace */ + { str->size--; str->ptr--; str->s++; } + +while ( str->ptr > 0 + && (q = str->s + str->ptr - 1), *q == '\t' || *q == ' ' + ) + str->ptr--; /* dump trailing whitespace */ + +(void) string_from_gstring(str); } @@ -432,8 +434,8 @@ pdkim_parse_sig_header(pdkim_ctx * ctx, uschar * raw_hdr) { pdkim_signature * sig; uschar *p, *q; -uschar * cur_tag = NULL; int ts = 0, tl = 0; -uschar * cur_val = NULL; int vs = 0, vl = 0; +gstring * cur_tag = NULL; +gstring * cur_val = NULL; BOOL past_hname = FALSE; BOOL in_b_val = FALSE; int where = PDKIM_HDR_LIMBO; @@ -477,12 +479,11 @@ for (p = raw_hdr; ; p++) if (where == PDKIM_HDR_TAG) { if (c >= 'a' && c <= 'z') - cur_tag = string_catn(cur_tag, &ts, &tl, p, 1); + cur_tag = string_catn(cur_tag, p, 1); if (c == '=') { - cur_tag[tl] = '\0'; - if (Ustrcmp(cur_tag, "b") == 0) + if (Ustrcmp(string_from_gstring(cur_tag), "b") == 0) { *q++ = '='; in_b_val = TRUE; @@ -499,31 +500,31 @@ for (p = raw_hdr; ; p++) if (c == ';' || c == '\0') { - if (tl && vl) + if (cur_tag && cur_val) { - cur_val[vl] = '\0'; + (void) string_from_gstring(cur_val); pdkim_strtrim(cur_val); - DEBUG(D_acl) debug_printf(" %s=%s\n", cur_tag, cur_val); + DEBUG(D_acl) debug_printf(" %s=%s\n", cur_tag->s, cur_val->s); - switch (*cur_tag) + switch (*cur_tag->s) { case 'b': - pdkim_decode_base64(cur_val, - cur_tag[1] == 'h' ? &sig->bodyhash : &sig->sighash); + pdkim_decode_base64(cur_val->s, + cur_tag->s[1] == 'h' ? &sig->bodyhash : &sig->sighash); break; case 'v': /* We only support version 1, and that is currently the only version there is. */ sig->version = - Ustrcmp(cur_val, PDKIM_SIGNATURE_VERSION) == 0 ? 1 : -1; + Ustrcmp(cur_val->s, PDKIM_SIGNATURE_VERSION) == 0 ? 1 : -1; break; case 'a': { - uschar * s = Ustrchr(cur_val, '-'); + uschar * s = Ustrchr(cur_val->s, '-'); for(i = 0; i < nelem(pdkim_keytypes); i++) - if (Ustrncmp(cur_val, pdkim_keytypes[i], s - cur_val) == 0) + if (Ustrncmp(cur_val->s, pdkim_keytypes[i], s - cur_val->s) == 0) { sig->keytype = i; break; } for (++s, i = 0; i < nelem(pdkim_hashes); i++) if (Ustrcmp(s, pdkim_hashes[i].dkim_hashname) == 0) @@ -533,7 +534,7 @@ for (p = raw_hdr; ; p++) case 'c': for (i = 0; pdkim_combined_canons[i].str; i++) - if (Ustrcmp(cur_val, pdkim_combined_canons[i].str) == 0) + if (Ustrcmp(cur_val->s, pdkim_combined_canons[i].str) == 0) { sig->canon_headers = pdkim_combined_canons[i].canon_headers; sig->canon_body = pdkim_combined_canons[i].canon_body; @@ -542,40 +543,39 @@ for (p = raw_hdr; ; p++) break; case 'q': for (i = 0; pdkim_querymethods[i]; i++) - if (Ustrcmp(cur_val, pdkim_querymethods[i]) == 0) + if (Ustrcmp(cur_val->s, pdkim_querymethods[i]) == 0) { sig->querymethod = i; break; } break; case 's': - sig->selector = string_copy(cur_val); break; + sig->selector = string_copyn(cur_val->s, cur_val->ptr); break; case 'd': - sig->domain = string_copy(cur_val); break; + sig->domain = string_copyn(cur_val->s, cur_val->ptr); break; case 'i': - sig->identity = pdkim_decode_qp(cur_val); break; + sig->identity = pdkim_decode_qp(cur_val->s); break; case 't': - sig->created = strtoul(CS cur_val, NULL, 10); break; + sig->created = strtoul(CS cur_val->s, NULL, 10); break; case 'x': - sig->expires = strtoul(CS cur_val, NULL, 10); break; + sig->expires = strtoul(CS cur_val->s, NULL, 10); break; case 'l': - sig->bodylength = strtol(CS cur_val, NULL, 10); break; + sig->bodylength = strtol(CS cur_val->s, NULL, 10); break; case 'h': - sig->headernames = string_copy(cur_val); break; + sig->headernames = string_copyn(cur_val->s, cur_val->ptr); break; case 'z': - sig->copiedheaders = pdkim_decode_qp(cur_val); break; + sig->copiedheaders = pdkim_decode_qp(cur_val->s); break; default: DEBUG(D_acl) debug_printf(" Unknown tag encountered\n"); break; } } - tl = 0; - vl = 0; + cur_tag = cur_val = NULL; in_b_val = FALSE; where = PDKIM_HDR_LIMBO; } else - cur_val = string_catn(cur_val, &vs, &vl, p, 1); + cur_val = string_catn(cur_val, p, 1); } NEXT_CHAR: @@ -922,10 +922,10 @@ pdkim_header_complete(pdkim_ctx * ctx) pdkim_signature * sig, * last_sig; /* Special case: The last header can have an extra \r appended */ -if ( (ctx->cur_header_len > 1) && - (ctx->cur_header[(ctx->cur_header_len)-1] == '\r') ) - --ctx->cur_header_len; -ctx->cur_header[ctx->cur_header_len] = '\0'; +if ( (ctx->cur_header->ptr > 1) && + (ctx->cur_header->s[ctx->cur_header->ptr-1] == '\r') ) + --ctx->cur_header->ptr; +(void) string_from_gstring(ctx->cur_header); if (++ctx->num_headers > PDKIM_MAX_HEADERS) goto BAIL; @@ -934,8 +934,7 @@ if (ctx->flags & PDKIM_MODE_SIGN) for (sig = ctx->sig; sig; sig = sig->next) /* Traverse all signatures */ /* Add header to the signed headers list (in reverse order) */ - sig->headers = pdkim_prepend_stringlist(sig->headers, - ctx->cur_header); + sig->headers = pdkim_prepend_stringlist(sig->headers, ctx->cur_header->s); /* VERIFICATION ----------------------------------------------------------- */ /* DKIM-Signature: headers are added to the verification list */ @@ -945,10 +944,10 @@ else DEBUG(D_acl) { debug_printf("PDKIM >> raw hdr: "); - pdkim_quoteprint(CUS ctx->cur_header, ctx->cur_header_len); + pdkim_quoteprint(CUS ctx->cur_header->s, ctx->cur_header->ptr); } #endif - if (strncasecmp(CCS ctx->cur_header, + if (strncasecmp(CCS ctx->cur_header->s, DKIM_SIGNATURE_HEADERNAME, Ustrlen(DKIM_SIGNATURE_HEADERNAME)) == 0) { @@ -959,7 +958,7 @@ else DEBUG(D_acl) debug_printf( "PDKIM >> Found sig, trying to parse >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); - sig = pdkim_parse_sig_header(ctx, ctx->cur_header); + sig = pdkim_parse_sig_header(ctx, ctx->cur_header->s); if (!(last_sig = ctx->sig)) ctx->sig = sig; @@ -971,11 +970,11 @@ else } /* all headers are stored for signature verification */ - ctx->headers = pdkim_prepend_stringlist(ctx->headers, ctx->cur_header); + ctx->headers = pdkim_prepend_stringlist(ctx->headers, ctx->cur_header->s); } BAIL: -ctx->cur_header[ctx->cur_header_len = 0] = '\0'; /* leave buffer for reuse */ +ctx->cur_header->s[ctx->cur_header->ptr = 0] = '\0'; /* leave buffer for reuse */ return PDKIM_OK; } @@ -1027,8 +1026,7 @@ else for (p = 0; pflags & PDKIM_SEEN_CR)) /* emulate the CR */ - ctx->cur_header = string_catn(ctx->cur_header, &ctx->cur_header_size, - &ctx->cur_header_len, CUS "\r", 1); + ctx->cur_header = string_catn(ctx->cur_header, CUS "\r", 1); if (ctx->flags & PDKIM_SEEN_LF) /* Seen last header line */ { @@ -1051,9 +1049,8 @@ else for (p = 0; pflags &= ~PDKIM_SEEN_LF; } - if (ctx->cur_header_len < PDKIM_MAX_HEADER_LEN) - ctx->cur_header = string_catn(ctx->cur_header, &ctx->cur_header_size, - &ctx->cur_header_len, CUS &data[p], 1); + if (!ctx->cur_header || ctx->cur_header->ptr < PDKIM_MAX_HEADER_LEN) + ctx->cur_header = string_catn(ctx->cur_header, CUS &data[p], 1); } } return PDKIM_OK; @@ -1061,12 +1058,12 @@ return PDKIM_OK; -/* Extend a grwong header with a continuation-linebreak */ -static uschar * -pdkim_hdr_cont(uschar * str, int * size, int * ptr, int * col) +/* Extend a growing header with a continuation-linebreak */ +static gstring * +pdkim_hdr_cont(gstring * str, int * col) { *col = 1; -return string_catn(str, size, ptr, US"\r\n\t", 3); +return string_catn(str, US"\r\n\t", 3); } @@ -1080,8 +1077,6 @@ return string_catn(str, size, ptr, US"\r\n\t", 3); * * col: this int holds and receives column number (octets since last '\n') * str: partial string to append to - * size: current buffer size for str - * ptr: current tail-pointer for str * pad: padding, split line or space after before or after eg: ";" * intro: - must join to payload eg "h=", usually the tag name * payload: eg base64 data - long data can be split arbitrarily. @@ -1095,8 +1090,8 @@ return string_catn(str, size, ptr, US"\r\n\t", 3); * names longer than 78, or bogus col. Input is assumed to be free of line breaks. */ -static uschar * -pdkim_headcat(int * col, uschar * str, int * size, int * ptr, +static gstring * +pdkim_headcat(int * col, gstring * str, const uschar * pad, const uschar * intro, const uschar * payload) { size_t l; @@ -1105,8 +1100,8 @@ if (pad) { l = Ustrlen(pad); if (*col + l > 78) - str = pdkim_hdr_cont(str, size, ptr, col); - str = string_catn(str, size, ptr, pad, l); + str = pdkim_hdr_cont(str, col); + str = string_catn(str, pad, l); *col += l; } @@ -1114,7 +1109,7 @@ l = (pad?1:0) + (intro?Ustrlen(intro):0); if (*col + l > 78) { /*can't fit intro - start a new line to make room.*/ - str = pdkim_hdr_cont(str, size, ptr, col); + str = pdkim_hdr_cont(str, col); l = intro?Ustrlen(intro):0; } @@ -1124,7 +1119,7 @@ while (l>77) { /* this fragment will not fit on a single line */ if (pad) { - str = string_catn(str, size, ptr, US" ", 1); + str = string_catn(str, US" ", 1); *col += 1; pad = NULL; /* only want this once */ l--; @@ -1134,7 +1129,7 @@ while (l>77) { size_t sl = Ustrlen(intro); - str = string_catn(str, size, ptr, intro, sl); + str = string_catn(str, intro, sl); *col += sl; l -= sl; intro = NULL; /* only want this once */ @@ -1145,25 +1140,25 @@ while (l>77) size_t sl = Ustrlen(payload); size_t chomp = *col+sl < 77 ? sl : 78-*col; - str = string_catn(str, size, ptr, payload, chomp); + str = string_catn(str, payload, chomp); *col += chomp; payload += chomp; l -= chomp-1; } /* the while precondition tells us it didn't fit. */ - str = pdkim_hdr_cont(str, size, ptr, col); + str = pdkim_hdr_cont(str, col); } if (*col + l > 78) { - str = pdkim_hdr_cont(str, size, ptr, col); + str = pdkim_hdr_cont(str, col); pad = NULL; } if (pad) { - str = string_catn(str, size, ptr, US" ", 1); + str = string_catn(str, US" ", 1); *col += 1; pad = NULL; } @@ -1172,7 +1167,7 @@ if (intro) { size_t sl = Ustrlen(intro); - str = string_catn(str, size, ptr, intro, sl); + str = string_catn(str, intro, sl); *col += sl; l -= sl; intro = NULL; @@ -1182,7 +1177,7 @@ if (payload) { size_t sl = Ustrlen(payload); - str = string_catn(str, size, ptr, payload, sl); + str = string_catn(str, payload, sl); *col += sl; } @@ -1198,31 +1193,23 @@ pdkim_create_header(pdkim_signature * sig, BOOL final) uschar * base64_bh; uschar * base64_b; int col = 0; -uschar * hdr; int hdr_size = 0, hdr_len = 0; -uschar * canon_all; int can_size = 0, can_len = 0; +gstring * hdr; +gstring * canon_all; -canon_all = string_cat (NULL, &can_size, &can_len, - pdkim_canons[sig->canon_headers]); -canon_all = string_catn(canon_all, &can_size, &can_len, US"/", 1); -canon_all = string_cat (canon_all, &can_size, &can_len, - pdkim_canons[sig->canon_body]); -canon_all[can_len] = '\0'; +canon_all = string_cat (NULL, pdkim_canons[sig->canon_headers]); +canon_all = string_catn(canon_all, US"/", 1); +canon_all = string_cat (canon_all, pdkim_canons[sig->canon_body]); +(void) string_from_gstring(canon_all); -hdr = string_cat(NULL, &hdr_size, &hdr_len, - US"DKIM-Signature: v="PDKIM_SIGNATURE_VERSION); -col = hdr_len; +hdr = string_cat(NULL, US"DKIM-Signature: v="PDKIM_SIGNATURE_VERSION); +col = hdr->ptr; /* Required and static bits */ -hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"a=", - dkim_sig_to_a_tag(sig)); -hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"q=", - pdkim_querymethods[sig->querymethod]); -hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"c=", - canon_all); -hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"d=", - sig->domain); -hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"s=", - sig->selector); +hdr = pdkim_headcat(&col, hdr, US";", US"a=", dkim_sig_to_a_tag(sig)); +hdr = pdkim_headcat(&col, hdr, US";", US"q=", pdkim_querymethods[sig->querymethod]); +hdr = pdkim_headcat(&col, hdr, US";", US"c=", canon_all->s); +hdr = pdkim_headcat(&col, hdr, US";", US"d=", sig->domain); +hdr = pdkim_headcat(&col, hdr, US";", US"s=", sig->selector); /* list of header names can be split between items. */ { @@ -1237,9 +1224,9 @@ hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"s=", if (c) *c ='\0'; if (!i) - hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, NULL, NULL, US":"); + hdr = pdkim_headcat(&col, hdr, NULL, NULL, US":"); - hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, s, i, n); + hdr = pdkim_headcat(&col, hdr, s, i, n); if (!c) break; @@ -1251,18 +1238,18 @@ hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"s=", } base64_bh = pdkim_encode_base64(&sig->bodyhash); -hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"bh=", base64_bh); +hdr = pdkim_headcat(&col, hdr, US";", US"bh=", base64_bh); /* Optional bits */ if (sig->identity) - hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"i=", sig->identity); + hdr = pdkim_headcat(&col, hdr, US";", US"i=", sig->identity); if (sig->created > 0) { uschar minibuf[20]; snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->created); - hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"t=", minibuf); + hdr = pdkim_headcat(&col, hdr, US";", US"t=", minibuf); } if (sig->expires > 0) @@ -1270,7 +1257,7 @@ if (sig->expires > 0) uschar minibuf[20]; snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->expires); - hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"x=", minibuf); + hdr = pdkim_headcat(&col, hdr, US";", US"x=", minibuf); } if (sig->bodylength >= 0) @@ -1278,17 +1265,17 @@ if (sig->bodylength >= 0) uschar minibuf[20]; snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->bodylength); - hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"l=", minibuf); + hdr = pdkim_headcat(&col, hdr, US";", US"l=", minibuf); } /* Preliminary or final version? */ if (final) { base64_b = pdkim_encode_base64(&sig->sighash); - hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"b=", base64_b); + hdr = pdkim_headcat(&col, hdr, US";", US"b=", base64_b); /* add trailing semicolon: I'm not sure if this is actually needed */ - hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, NULL, US";", US""); + hdr = pdkim_headcat(&col, hdr, NULL, US";", US""); } else { @@ -1297,11 +1284,10 @@ else the headcat routine could insert a linebreak which the relaxer would reduce to a single space preceding the terminating semicolon, resulting in an incorrect header-hash. */ - hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"b=;", US""); + hdr = pdkim_headcat(&col, hdr, US";", US"b=;", US""); } -hdr[hdr_len] = '\0'; -return hdr; +return string_from_gstring(hdr); } @@ -1386,7 +1372,7 @@ pdkim_signature * sig; /* Check if we must still flush a (partial) header. If that is the case, the message has no body, and we must compute a body hash out of '' */ -if (ctx->cur_header && ctx->cur_header_len) +if (ctx->cur_header && ctx->cur_header->ptr > 0) { blob * rnl = NULL; int rc; @@ -1410,11 +1396,7 @@ for (sig = ctx->sig; sig; sig = sig->next) hctx hhash_ctx; uschar * sig_hdr = US""; blob hhash; - blob hdata; - int hdata_alloc = 0; - - hdata.data = NULL; - hdata.len = 0; + gstring * hdata = NULL; if (!exim_sha_init(&hhash_ctx, pdkim_hashes[sig->hashtype].exim_hashmethod)) { @@ -1441,7 +1423,7 @@ for (sig = ctx->sig; sig; sig = sig->next) if (ctx->flags & PDKIM_MODE_SIGN) { - int hs = 0, hl = 0; + gstring * g = NULL; pdkim_stringlist *p; const uschar * l; uschar * s; @@ -1456,8 +1438,7 @@ for (sig = ctx->sig; sig; sig = sig->next) if (header_name_match(rh, sig->sign_headers) == PDKIM_OK) { /* Collect header names (Note: colon presence is guaranteed here) */ - sig->headernames = string_append_listele_n(sig->headernames, &hs, &hl, - ':', rh, Ustrchr(rh, ':') - rh); + g = string_append_listele_n(g, ':', rh, Ustrchr(rh, ':') - rh); if (sig->canon_headers == PDKIM_CANON_RELAXED) rh = pdkim_relax_header(rh, TRUE); /* cook header for relaxed canon */ @@ -1466,7 +1447,7 @@ for (sig = ctx->sig; sig; sig = sig->next) exim_sha_update(&hhash_ctx, CUS rh, Ustrlen(rh)); /* Remember headers block for signing (when the library cannot do incremental) */ - (void) exim_dkim_data_append(&hdata, &hdata_alloc, rh); + hdata = exim_dkim_data_append(hdata, rh); DEBUG(D_acl) pdkim_quoteprint(rh, Ustrlen(rh)); } @@ -1476,8 +1457,8 @@ for (sig = ctx->sig; sig; sig = sig->next) l = sig->sign_headers; while((s = string_nextinlist(&l, &sep, NULL, 0))) if (*s != '_') - sig->headernames = string_append_listele(sig->headernames, &hs, &hl, ':', s); - sig->headernames[hl] = '\0'; + g = string_append_listele(g, ':', s); + sig->headernames = string_from_gstring(g); /* Create signature header with b= omitted */ sig_hdr = pdkim_create_header(sig, FALSE); @@ -1572,7 +1553,7 @@ for (sig = ctx->sig; sig; sig = sig->next) /* Remember headers block for signing (when the signing library cannot do incremental) */ if (ctx->flags & PDKIM_MODE_SIGN) - (void) exim_dkim_data_append(&hdata, &hdata_alloc, US sig_hdr); + hdata = exim_dkim_data_append(hdata, US sig_hdr); /* SIGNING ---------------------------------------------------------------- */ if (ctx->flags & PDKIM_MODE_SIGN) @@ -1591,14 +1572,15 @@ for (sig = ctx->sig; sig; sig = sig->next) calculated, with GnuTLS we have to sign an entire block of headers (due to available interfaces) and it recalculates the hash internally. */ -#if defined(SIGN_OPENSSL) || defined(SIGN_GCRYPT) - hdata = hhash; +#if defined(SIGN_GNUTLS) + hhash.data = hdata->s; + hhash.len = hdata->ptr; #endif /*XXX extend for non-RSA algos */ if ((*err = exim_dkim_sign(&sctx, pdkim_hashes[sig->hashtype].exim_hashmethod, - &hdata, &sig->sighash))) + &hhash, &sig->sighash))) { DEBUG(D_acl) debug_printf("signing: %s\n", *err); return PDKIM_ERR_RSA_SIGNING; diff --git a/src/src/pdkim/pdkim.h b/src/src/pdkim/pdkim.h index e82f26c05..a34999ad8 100644 --- a/src/src/pdkim/pdkim.h +++ b/src/src/pdkim/pdkim.h @@ -259,9 +259,7 @@ typedef struct pdkim_ctx { int(*dns_txt_callback)(char *, char *); /* Coder's little helpers */ - uschar *cur_header; - int cur_header_size; - int cur_header_len; + gstring *cur_header; uschar *linebuf; int linebuf_offset; int num_headers; diff --git a/src/src/pdkim/signing.c b/src/src/pdkim/signing.c index e8cb297ca..edded11a4 100644 --- a/src/src/pdkim/signing.c +++ b/src/src/pdkim/signing.c @@ -28,13 +28,10 @@ exim_dkim_init(void) /* accumulate data (gnutls-only). String to be appended must be nul-terminated. */ -blob * -exim_dkim_data_append(blob * b, int * alloc, uschar * s) +gstring * +exim_dkim_data_append(gstring * g, uschar * s) { -int len = b->len; -b->data = string_append(b->data, alloc, &len, 1, s); -b->len = len; -return b; +return string_cat(g, s); } @@ -268,10 +265,10 @@ return; /* Accumulate data (gnutls-only). String to be appended must be nul-terminated. */ -blob * -exim_dkim_data_append(blob * b, int * alloc, uschar * s) +gstring * +exim_dkim_data_append(blob * g, uschar * s) { -return b; /*dummy*/ +return g; /*dummy*/ } @@ -593,10 +590,10 @@ ERR_load_crypto_strings(); /* accumulate data (gnutls-only) */ -blob * -exim_dkim_data_append(blob * b, int * alloc, uschar * s) +gstring * +exim_dkim_data_append(gstring * g, uschar * s) { -return b; /*dummy*/ +return g; /*dummy*/ } diff --git a/src/src/pdkim/signing.h b/src/src/pdkim/signing.h index abf255988..61e241e5d 100644 --- a/src/src/pdkim/signing.h +++ b/src/src/pdkim/signing.h @@ -72,7 +72,7 @@ typedef struct { extern void exim_dkim_init(void); -extern blob * exim_dkim_data_append(blob *, int *, uschar *); +extern gstring * exim_dkim_data_append(gstring *, uschar *); extern const uschar * exim_dkim_signing_init(uschar *, es_ctx *); extern const uschar * exim_dkim_sign(es_ctx *, hashmethod, blob *, blob *); diff --git a/src/src/perl.c b/src/src/perl.c index 5f4f0d98d..6966d73b5 100644 --- a/src/src/perl.c +++ b/src/src/perl.c @@ -150,9 +150,8 @@ cleanup_perl(void) interp_perl = 0; } -uschar * -call_perl_cat(uschar *yield, int *sizep, int *ptrp, uschar **errstrp, - uschar *name, uschar **arg) +gstring * +call_perl_cat(gstring * yield, uschar **errstrp, uschar *name, uschar **arg) { dSP; SV *sv; @@ -186,7 +185,7 @@ call_perl_cat(uschar *yield, int *sizep, int *ptrp, uschar **errstrp, return NULL; } str = US SvPV(sv, len); - yield = string_catn(yield, sizep, ptrp, str, (int)len); + yield = string_catn(yield, str, (int)len); FREETMPS; LEAVE; diff --git a/src/src/readconf.c b/src/src/readconf.c index f831f866a..1cbbd83ef 100644 --- a/src/src/readconf.c +++ b/src/src/readconf.c @@ -983,10 +983,8 @@ for (;;) "absolute path \"%s\"", ss); else { - int offset = 0; - int size = 0; - ss = string_append(NULL, &size, &offset, 3, config_directory, "/", ss); - ss[offset] = '\0'; /* string_append() does not zero terminate the string! */ + gstring * g = string_append(NULL, 3, config_directory, "/", ss); + ss = string_from_gstring(g); } if (include_if_exists != 0 && (Ustat(ss, &statbuf) != 0)) continue; @@ -1699,16 +1697,19 @@ switch (type) int sep_i = -(int)sep_o; const uschar * list = sptr; uschar * s; - uschar * list_o = *str_target; - int size = 0, len = 0; + gstring * list_o = NULL; - if (list_o) - size = (len = Ustrlen(list_o)) + 1; + if (*str_target) + { + list_o = string_get(Ustrlen(*str_target) + Ustrlen(sptr)); + list_o = string_cat(list_o, *str_target); + } while ((s = string_nextinlist(&list, &sep_i, NULL, 0))) - list_o = string_append_listele(list_o, &size, &len, sep_o, s); + list_o = string_append_listele(list_o, sep_o, s); + if (list_o) - *str_target = string_copy_malloc(list_o); + *str_target = string_copy_malloc(string_from_gstring(list_o)); } else { @@ -3200,25 +3201,24 @@ if (config_file) /* relative configuration file name: working dir + / + basename(filename) */ uschar buf[PATH_MAX]; - int offset = 0; - int size = 0; + gstring * g; if (os_getcwd(buf, PATH_MAX) == NULL) { perror("exim: getcwd"); exit(EXIT_FAILURE); } - config_main_directory = string_cat(NULL, &size, &offset, buf); + g = string_cat(NULL, buf); /* If the dir does not end with a "/", append one */ - if (config_main_directory[offset-1] != '/') - config_main_directory = string_catn(config_main_directory, &size, &offset, US"/", 1); + if (g->s[g->ptr-1] != '/') + g = string_catn(g, US"/", 1); /* If the config file contains a "/", extract the directory part */ if (last_slash) - config_main_directory = string_catn(config_main_directory, &size, &offset, filename, last_slash - filename); + g = string_catn(g, filename, last_slash - filename); - config_main_directory[offset] = '\0'; + config_main_directory = string_from_gstring(g); } config_directory = config_main_directory; } diff --git a/src/src/receive.c b/src/src/receive.c index 65e9fb415..4fb0c26cb 100644 --- a/src/src/receive.c +++ b/src/src/receive.c @@ -1291,36 +1291,34 @@ the calling host to a string that is being built dynamically. Arguments: s the dynamic string - sizeptr points to the size variable - ptrptr points to the pointer variable Returns: the extended string */ -static uschar * -add_host_info_for_log(uschar * s, int * sizeptr, int * ptrptr) +static gstring * +add_host_info_for_log(gstring * g) { if (sender_fullhost) { if (LOGGING(dnssec) && sender_host_dnssec) /*XXX sender_helo_dnssec? */ - s = string_catn(s, sizeptr, ptrptr, US" DS", 3); - s = string_append(s, sizeptr, ptrptr, 2, US" H=", sender_fullhost); + g = string_catn(g, US" DS", 3); + g = string_append(g, 2, US" H=", sender_fullhost); if (LOGGING(incoming_interface) && interface_address != NULL) { - s = string_cat(s, sizeptr, ptrptr, + g = string_cat(g, string_sprintf(" I=[%s]:%d", interface_address, interface_port)); } } if (tcp_in_fastopen && !tcp_in_fastopen_logged) { - s = string_catn(s, sizeptr, ptrptr, US" TFO", 4); + g = string_catn(g, US" TFO", 4); tcp_in_fastopen_logged = TRUE; } if (sender_ident) - s = string_append(s, sizeptr, ptrptr, 2, US" U=", sender_ident); + g = string_append(g, 2, US" U=", sender_ident); if (received_protocol) - s = string_append(s, sizeptr, ptrptr, 2, US" P=", received_protocol); -return s; + g = string_append(g, 2, US" P=", received_protocol); +return g; } @@ -1625,7 +1623,7 @@ int process_info_len = Ustrlen(process_info); int error_rc = (error_handling == ERRORS_SENDER)? errors_sender_rc : EXIT_FAILURE; int header_size = 256; -int start, end, domain, size, sptr; +int start, end, domain; int id_resolution; int had_zero = 0; int prevlines_length = 0; @@ -1650,7 +1648,8 @@ error_block *bad_addresses = NULL; uschar *frozen_by = NULL; uschar *queued_by = NULL; -uschar *errmsg, *s; +uschar *errmsg; +gstring * g; struct stat statbuf; /* Final message to give to SMTP caller, and messages from ACLs */ @@ -3407,9 +3406,8 @@ else int sep = 0; const uschar *ptr = dkim_verify_signers_expanded; uschar *item = NULL; - uschar *seen_items = NULL; - int seen_items_size = 0; - int seen_items_offset = 0; + gstring * seen_items = NULL; + /* Default to OK when no items are present */ rc = OK; while ((item = string_nextinlist(&ptr, &sep, NULL, 0))) @@ -3421,8 +3419,8 @@ else no matter how often it appears in the expanded list. */ if (seen_items) { - uschar *seen_item = NULL; - const uschar *seen_items_list = seen_items; + uschar *seen_item; + const uschar *seen_items_list = string_from_gstring(seen_items); BOOL seen_this_item = FALSE; while ((seen_item = string_nextinlist(&seen_items_list, &sep, @@ -3441,13 +3439,10 @@ else continue; } - seen_items = string_append(seen_items, &seen_items_size, - &seen_items_offset, 1, ":"); + seen_items = string_cat(seen_items, ":"); } - seen_items = string_append(seen_items, &seen_items_size, - &seen_items_offset, 1, item); - seen_items[seen_items_offset] = '\0'; + seen_items = string_cat(seen_items, item); DEBUG(D_receive) debug_printf("calling acl_smtp_dkim for dkim_cur_signer=%s\n", @@ -3772,10 +3767,8 @@ multiline SMTP responses. */ else { uschar *istemp = US""; - uschar *s = NULL; uschar *smtp_code; - int size = 0; - int sptr = 0; + gstring * g; errmsg = local_scan_data; @@ -3808,13 +3801,12 @@ else break; } - s = string_append(s, &size, &sptr, 2, US"F=", - (sender_address[0] == 0)? US"<>" : sender_address); - s = add_host_info_for_log(s, &size, &sptr); - s[sptr] = 0; + g = string_append(g, 2, US"F=", + sender_address[0] == 0 ? US"<>" : sender_address); + g = add_host_info_for_log(g); log_write(0, LOG_MAIN|LOG_REJECT, "%s %srejected by local_scan(): %.256s", - s, istemp, string_printing(errmsg)); + string_from_gstring(g), istemp, string_printing(errmsg)); if (smtp_input) { @@ -3948,58 +3940,53 @@ it first! Include any message id that is in the message - since the syntax of a message id is actually an addr-spec, we can use the parse routine to canonicalize it. */ -size = 256; -sptr = 0; -s = store_get(size); +g = string_get(256); -s = string_append(s, &size, &sptr, 2, +g = string_append(g, 2, fake_response == FAIL ? US"(= " : US"<= ", sender_address[0] == 0 ? US"<>" : sender_address); if (message_reference) - s = string_append(s, &size, &sptr, 2, US" R=", message_reference); + g = string_append(g, 2, US" R=", message_reference); -s = add_host_info_for_log(s, &size, &sptr); +g = add_host_info_for_log(g); #ifdef SUPPORT_TLS if (LOGGING(tls_cipher) && tls_in.cipher) - s = string_append(s, &size, &sptr, 2, US" X=", tls_in.cipher); + g = string_append(g, 2, US" X=", tls_in.cipher); if (LOGGING(tls_certificate_verified) && tls_in.cipher) - s = string_append(s, &size, &sptr, 2, US" CV=", - tls_in.certificate_verified ? "yes":"no"); + g = string_append(g, 2, US" CV=", tls_in.certificate_verified ? "yes":"no"); if (LOGGING(tls_peerdn) && tls_in.peerdn) - s = string_append(s, &size, &sptr, 3, US" DN=\"", - string_printing(tls_in.peerdn), US"\""); + g = string_append(g, 3, US" DN=\"", string_printing(tls_in.peerdn), US"\""); if (LOGGING(tls_sni) && tls_in.sni) - s = string_append(s, &size, &sptr, 3, US" SNI=\"", - string_printing(tls_in.sni), US"\""); + g = string_append(g, 3, US" SNI=\"", string_printing(tls_in.sni), US"\""); #endif if (sender_host_authenticated) { - s = string_append(s, &size, &sptr, 2, US" A=", sender_host_authenticated); + g = string_append(g, 2, US" A=", sender_host_authenticated); if (authenticated_id) { - s = string_append(s, &size, &sptr, 2, US":", authenticated_id); + g = string_append(g, 2, US":", authenticated_id); if (LOGGING(smtp_mailauth) && authenticated_sender) - s = string_append(s, &size, &sptr, 2, US":", authenticated_sender); + g = string_append(g, 2, US":", authenticated_sender); } } #ifndef DISABLE_PRDR if (prdr_requested) - s = string_catn(s, &size, &sptr, US" PRDR", 5); + g = string_catn(g, US" PRDR", 5); #endif #ifdef SUPPORT_PROXY if (proxy_session && LOGGING(proxy)) - s = string_append(s, &size, &sptr, 2, US" PRX=", proxy_local_address); + g = string_append(g, 2, US" PRX=", proxy_local_address); #endif if (chunking_state > CHUNKING_OFFERED) - s = string_catn(s, &size, &sptr, US" K", 2); + g = string_catn(g, US" K", 2); sprintf(CS big_buffer, "%d", msg_size); -s = string_append(s, &size, &sptr, 2, US" S=", big_buffer); +g = string_append(g, 2, US" S=", big_buffer); /* log 8BITMIME mode announced in MAIL_FROM 0 ... no BODY= used @@ -4008,11 +3995,11 @@ s = string_append(s, &size, &sptr, 2, US" S=", big_buffer); if (LOGGING(8bitmime)) { sprintf(CS big_buffer, "%d", body_8bitmime); - s = string_append(s, &size, &sptr, 2, US" M8S=", big_buffer); + g = string_append(g, 2, US" M8S=", big_buffer); } if (*queue_name) - s = string_append(s, &size, &sptr, 2, US" Q=", queue_name); + g = string_append(g, 2, US" Q=", queue_name); /* If an addr-spec in a message-id contains a quoted string, it can contain any characters except " \ and CR and so in particular it can contain NL! @@ -4028,7 +4015,7 @@ if (msgid_header) &errmsg, &start, &end, &domain, FALSE); allow_domain_literals = save_allow_domain_literals; if (old_id != NULL) - s = string_append(s, &size, &sptr, 2, US" id=", string_printing(old_id)); + g = string_append(g, 2, US" id=", string_printing(old_id)); } /* If subject logging is turned on, create suitable printing-character @@ -4051,20 +4038,20 @@ if (LOGGING(subject) && subject_header != NULL) } *p++ = '\"'; *p = 0; - s = string_append(s, &size, &sptr, 2, US" T=", string_printing(big_buffer)); + g = string_append(g, 2, US" T=", string_printing(big_buffer)); } /* Terminate the string: string_cat() and string_append() leave room, but do not put the zero in. */ -s[sptr] = 0; +(void) string_from_gstring(g); /* Create a message log file if message logs are being used and this message is not blackholed. Write the reception stuff to it. We used to leave message log creation until the first delivery, but this has proved confusing for some people. */ -if (message_logs && blackholed_by == NULL) +if (message_logs && !blackholed_by) { int fd; @@ -4081,11 +4068,8 @@ if (message_logs && blackholed_by == NULL) } if (fd < 0) - { log_write(0, LOG_MAIN|LOG_PANIC, "Couldn't open message log %s: %s", spool_name, strerror(errno)); - } - else { FILE *message_log = fdopen(fd, "a"); @@ -4098,7 +4082,7 @@ if (message_logs && blackholed_by == NULL) else { uschar *now = tod_stamp(tod_log); - fprintf(message_log, "%s Received from %s\n", now, s+3); + fprintf(message_log, "%s Received from %s\n", now, g->s+3); if (deliver_freeze) fprintf(message_log, "%s frozen by %s\n", now, frozen_by); if (queue_only_policy) fprintf(message_log, @@ -4155,11 +4139,10 @@ if (smtp_input && sender_host_address != NULL && !sender_host_notsocket && /* Re-use the log line workspace */ - sptr = 0; - s = string_cat(s, &size, &sptr, US"SMTP connection lost after final dot"); - s = add_host_info_for_log(s, &size, &sptr); - s[sptr] = 0; - log_write(0, LOG_MAIN, "%s", s); + g->ptr = 0; + g = string_cat(g, US"SMTP connection lost after final dot"); + g = add_host_info_for_log(g); + log_write(0, LOG_MAIN, "%s", string_from_gstring(g)); /* Delete the files for this aborted message. */ @@ -4223,7 +4206,7 @@ if(!smtp_reply) log_write(0, LOG_MAIN | (LOGGING(received_recipients)? LOG_RECIPIENTS : 0) | (LOGGING(received_sender)? LOG_SENDER : 0), - "%s", s); + "%s", g->s); /* Log any control actions taken by an ACL or local_scan(). */ @@ -4235,7 +4218,7 @@ if(!smtp_reply) } receive_call_bombout = FALSE; -store_reset(s); /* The store for the main log message can be reused */ +store_reset(g); /* The store for the main log message can be reused */ /* If the message is frozen, and freeze_tell is set, do the telling. */ diff --git a/src/src/rfc2047.c b/src/src/rfc2047.c index 041a18858..cb4a661bf 100644 --- a/src/src/rfc2047.c +++ b/src/src/rfc2047.c @@ -188,10 +188,10 @@ uschar * rfc2047_decode2(uschar *string, BOOL lencheck, uschar *target, int zeroval, int *lenptr, int *sizeptr, uschar **error) { -int ptr = 0; int size = Ustrlen(string); size_t dlen; -uschar *dptr, *yield; +uschar *dptr; +gstring *yield; uschar *mimeword, *q1, *q2, *endword; *error = NULL; @@ -208,7 +208,10 @@ building the result as we go. The result may be longer than the input if it is translated into a multibyte code such as UTF-8. That's why we use the dynamic string building code. */ -yield = store_get(++size); +yield = store_get(sizeof(gstring) + ++size); +yield->size = size; +yield->ptr = 0; +yield->s = US(yield + 1); while (mimeword) { @@ -218,7 +221,7 @@ while (mimeword) #endif if (mimeword != string) - yield = string_catn(yield, &size, &ptr, string, mimeword - string); + yield = string_catn(yield, string, mimeword - string); /* Do a charset translation if required. This is supported only on hosts that have the iconv() function. Translation errors set error, but carry on, @@ -305,7 +308,7 @@ while (mimeword) /* Add the new string onto the result */ - yield = string_catn(yield, &size, &ptr, tptr, tlen); + yield = string_catn(yield, tptr, tlen); } #if HAVE_ICONV @@ -328,11 +331,11 @@ while (mimeword) /* Copy the remaining characters of the string, zero-terminate it, and return the length as well if requested. */ -yield = string_cat(yield, &size, &ptr, string); -yield[ptr] = 0; -if (lenptr) *lenptr = ptr; -if (sizeptr) *sizeptr = size; -return yield; +yield = string_cat(yield, string); + +if (lenptr) *lenptr = yield->ptr; +if (sizeptr) *sizeptr = yield->size; +return string_from_gstring(yield); } diff --git a/src/src/route.c b/src/src/route.c index bbaa5285d..1b9676f3f 100644 --- a/src/src/route.c +++ b/src/src/route.c @@ -140,7 +140,7 @@ optionlist optionlist_routers[] = { (void *)offsetof(router_instance, verify_sender) } }; -int optionlist_routers_size = sizeof(optionlist_routers)/sizeof(optionlist); +int optionlist_routers_size = nelem(optionlist_routers); #ifdef MACRO_PREDEF diff --git a/src/src/routers/redirect.c b/src/src/routers/redirect.c index 9923af585..5b6a08818 100644 --- a/src/src/routers/redirect.c +++ b/src/src/routers/redirect.c @@ -223,11 +223,11 @@ than false, there is likely to be a problem. */ if (ob->one_time) { ob->forbid_pipe = ob->forbid_file = ob->forbid_filter_reply = TRUE; - if (rblock->extra_headers != NULL || rblock->remove_headers != NULL) + if (rblock->extra_headers || rblock->remove_headers) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s router:\n " "\"headers_add\" and \"headers_remove\" are not permitted with " "\"one_time\"", rblock->name); - if (rblock->unseen || rblock->expand_unseen != NULL) + if (rblock->unseen || rblock->expand_unseen) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s router:\n " "\"unseen\" may not be used with \"one_time\"", rblock->name); } @@ -239,7 +239,7 @@ or if owngroups is set. */ if (ob->check_owner == TRUE_UNSET) ob->check_owner = rblock->check_local_user || - (ob->owners != NULL && ob->owners[0] != 0); + (ob->owners && ob->owners[0] != 0); if (ob->check_group == TRUE_UNSET) ob->check_group = (rblock->check_local_user && (ob->modemask & 020) == 0) || @@ -247,7 +247,7 @@ if (ob->check_group == TRUE_UNSET) /* If explicit qualify domain set, the preserve option is locked out */ -if (ob->qualify_domain != NULL && ob->qualify_preserve_domain) +if (ob->qualify_domain && ob->qualify_preserve_domain) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s router:\n " "only one of \"qualify_domain\" or \"qualify_preserve_domain\" must be set", rblock->name); diff --git a/src/src/routers/rf_get_munge_headers.c b/src/src/routers/rf_get_munge_headers.c index 745704f62..bf8dc4a5d 100644 --- a/src/src/routers/rf_get_munge_headers.c +++ b/src/src/routers/rf_get_munge_headers.c @@ -91,10 +91,10 @@ if (rblock->remove_headers) const uschar * list = rblock->remove_headers; int sep = ':'; uschar * s; - int size = 0, len = 0; + gstring * g = NULL; if (*remove_headers) - size = (len = Ustrlen(*remove_headers)) + 1; + g = string_cat(NULL, *remove_headers); while ((s = string_nextinlist(&list, &sep, NULL, 0))) if (!(s = expand_string(s))) @@ -108,12 +108,14 @@ if (rblock->remove_headers) } } else if (*s) - *remove_headers = string_append_listele(*remove_headers, &size, &len, ':', s); + g = string_append_listele(g, ':', s); + if (g) + *remove_headers = g->s; } return OK; } -/* vi: aw ai sw=4 +/* vi: aw ai sw=2 */ /* End of rf_get_munge_headers.c */ diff --git a/src/src/sieve.c b/src/src/sieve.c index 32d9279ea..3bb10785b 100644 --- a/src/src/sieve.c +++ b/src/src/sieve.c @@ -409,12 +409,14 @@ Returns -1 syntax error */ -static int parse_mailto_uri(struct Sieve *filter, const uschar *uri, string_item **recipient, struct String *header, struct String *subject, struct String *body) +static int +parse_mailto_uri(struct Sieve *filter, const uschar *uri, + string_item **recipient, struct String *header, struct String *subject, + struct String *body) { const uschar *start; struct String to, hname; struct String hvalue = {.character = NULL, .length = 0}; -int capacity; string_item *new; if (Ustrncmp(uri,"mailto:",7)) @@ -431,22 +433,21 @@ if (*uri && *uri!='?') for (start=uri; *uri && *uri!='?' && (*uri!='%' || *(uri+1)!='2' || tolower(*(uri+2))!='c'); ++uri); if (uri>start) { - capacity=0; - to.character= NULL; - to.length=0; - to.character=string_catn(to.character, &capacity, &to.length, start, uri-start); - to.character[to.length]='\0'; + gstring * g = string_catn(NULL, start, uri-start); + + to.character = string_from_gstring(g); + to.length = g->ptr; if (uri_decode(&to)==-1) { filter->errmsg=US"Invalid URI encoding"; return -1; } - new=store_get(sizeof(string_item)); - new->text=store_get(to.length+1); - if (to.length) memcpy(new->text,to.character,to.length); - new->text[to.length]='\0'; - new->next=*recipient; - *recipient=new; + new=store_get(sizeof(string_item)); + new->text=store_get(to.length+1); + if (to.length) memcpy(new->text,to.character,to.length); + new->text[to.length]='\0'; + new->next=*recipient; + *recipient=new; } else { @@ -465,11 +466,10 @@ if (*uri=='?') for (start=uri; *uri && (isalnum(*uri) || strchr("$-_.+!*'(),%",*uri)); ++uri); if (uri>start) { - capacity=0; - hname.character= NULL; - hname.length=0; - hname.character = string_catn(hname.character, &capacity, &hname.length, start, uri-start); - hname.character[hname.length]='\0'; + gstring * g = string_catn(NULL, start, uri-start); + + hname.character = string_from_gstring(g); + hname.length = g->ptr; if (uri_decode(&hname)==-1) { filter->errmsg=US"Invalid URI encoding"; @@ -488,11 +488,10 @@ if (*uri=='?') for (start=uri; *uri && (isalnum(*uri) || strchr("$-_.+!*'(),%",*uri)); ++uri); if (uri>start) { - capacity=0; - hvalue.character= NULL; - hvalue.length=0; - hvalue.character=string_catn(hvalue.character,&capacity,&hvalue.length,start,uri-start); - hvalue.character[hvalue.length]='\0'; + gstring * g = string_catn(NULL, start, uri-start); + + hname.character = string_from_gstring(g); + hname.length = g->ptr; if (uri_decode(&hvalue)==-1) { filter->errmsg=US"Invalid URI encoding"; @@ -528,13 +527,18 @@ if (*uri=='?') for (i=ignore; ilength==-1) header->length=0; - capacity=header->length; - header->character=string_catn(header->character,&capacity,&header->length,hname.character,hname.length); - header->character=string_catn(header->character,&capacity,&header->length,CUS ": ",2); - header->character=string_catn(header->character,&capacity,&header->length,hvalue.character,hvalue.length); - header->character=string_catn(header->character,&capacity,&header->length,CUS "\n",1); - header->character[header->length]='\0'; + gstring * g; + + if (header->length==-1) header->length = 0; + + g = string_catn(NULL, header->character, header->length); + g = string_catn(g, hname.character, hname.length); + g = string_catn(g, CUS ": ", 2); + g = string_catn(g, hvalue.character, hvalue.length); + g = string_catn(g, CUS "\n", 1); + + header->character = string_from_gstring(g); + header->length = g->ptr; } } if (*uri=='&') ++uri; @@ -992,10 +996,10 @@ Arguments: Returns: quoted string */ -static const uschar *quote(const struct String *header) +static const uschar * +quote(const struct String *header) { -uschar *quoted=NULL; -int size=0,ptr=0; +gstring * quoted = NULL; size_t l; const uschar *h; @@ -1006,26 +1010,20 @@ while (l) switch (*h) { case '\0': - { - quoted=string_catn(quoted,&size,&ptr,CUS "\\0",2); + quoted = string_catn(quoted, CUS "\\0", 2); break; - } case '$': case '{': case '}': - { - quoted=string_catn(quoted,&size,&ptr,CUS "\\",1); - } + quoted = string_catn(quoted, CUS "\\", 1); default: - { - quoted=string_catn(quoted,&size,&ptr,h,1); - } + quoted = string_catn(quoted, h, 1); } ++h; --l; } -quoted=string_catn(quoted,&size,&ptr,CUS "",1); -return quoted; +quoted = string_catn(quoted, CUS "", 1); +return string_from_gstring(quoted); } @@ -1476,10 +1474,12 @@ Returns: 1 success static int parse_string(struct Sieve *filter, struct String *data) { +gstring * g = NULL; int dataCapacity=0; -data->length=0; -data->character=(uschar*)0; +data->length = 0; +data->character = NULL; + if (*filter->pc=='"') /* quoted string */ { ++filter->pc; @@ -1487,11 +1487,17 @@ if (*filter->pc=='"') /* quoted string */ { if (*filter->pc=='"') /* end of string */ { - int foo=data->length; - ++filter->pc; + + if (g) + { + data->character = string_from_gstring(g); + data->length = g->ptr; + } + else + data->character = US"\0"; /* that way, there will be at least one character allocated */ - data->character=string_catn(data->character,&dataCapacity,&foo,CUS "",1); + #ifdef ENCODED_CHARACTER if (filter->require_encoded_character && string_decode(filter,data)==-1) @@ -1501,7 +1507,7 @@ if (*filter->pc=='"') /* quoted string */ } else if (*filter->pc=='\\' && *(filter->pc+1)) /* quoted character */ { - data->character=string_catn(data->character,&dataCapacity,&data->length,filter->pc+1,1); + g = string_catn(g, filter->pc+1, 1); filter->pc+=2; } else /* regular character */ @@ -1511,11 +1517,11 @@ if (*filter->pc=='"') /* quoted string */ #else if (*filter->pc=='\n') { - data->character=string_catn(data->character,&dataCapacity,&data->length,US"\r",1); + g = string_catn(g, US"\r", 1); ++filter->line; } #endif - data->character=string_catn(data->character,&dataCapacity,&data->length,filter->pc,1); + g = string_catn(g, filter->pc, 1); filter->pc++; } } @@ -1557,7 +1563,7 @@ else if (Ustrncmp(filter->pc,CUS "text:",5)==0) /* multiline string */ if (*filter->pc=='\n') /* end of line */ #endif { - data->character=string_catn(data->character,&dataCapacity,&data->length,CUS "\r\n",2); + g = string_catn(g, CUS "\r\n", 2); #ifdef RFC_EOL filter->pc+=2; #else @@ -1570,10 +1576,15 @@ else if (Ustrncmp(filter->pc,CUS "text:",5)==0) /* multiline string */ if (*filter->pc=='.' && *(filter->pc+1)=='\n') /* end of string */ #endif { - int foo=data->length; + if (g) + { + data->character = string_from_gstring(g); + data->length = g->ptr; + } + else + data->character = US"\0"; + /* that way, there will be at least one character allocated */ - /* that way, there will be at least one character allocated */ - data->character=string_catn(data->character,&dataCapacity,&foo,CUS "",1); #ifdef RFC_EOL filter->pc+=3; #else @@ -1589,13 +1600,13 @@ else if (Ustrncmp(filter->pc,CUS "text:",5)==0) /* multiline string */ } else if (*filter->pc=='.' && *(filter->pc+1)=='.') /* remove dot stuffing */ { - data->character=string_catn(data->character,&dataCapacity,&data->length,CUS ".",1); + g = string_catn(g, CUS ".", 1); filter->pc+=2; } } else /* regular character */ { - data->character=string_catn(data->character,&dataCapacity,&data->length,filter->pc,1); + g = string_catn(g, filter->pc, 1); filter->pc++; } } @@ -3275,15 +3286,14 @@ while (*filter->pc) if (exec) { address_item *addr; - int capacity,start; + int start; uschar *buffer; int buffer_capacity; - struct String key; md5 base; uschar digest[16]; uschar hexdigest[33]; int i; - uschar *once; + gstring * once; if (filter_personal(aliases,TRUE)) { @@ -3295,32 +3305,30 @@ while (*filter->pc) } /* build oncelog filename */ - key.character=(uschar*)0; - key.length=0; - capacity=0; + md5_start(&base); + if (handle.length==-1) { - if (subject.length!=-1) key.character=string_catn(key.character,&capacity,&key.length,subject.character,subject.length); - if (from.length!=-1) key.character=string_catn(key.character,&capacity,&key.length,from.character,from.length); - key.character=string_catn(key.character,&capacity,&key.length,reason_is_mime?US"1":US"0",1); - key.character=string_catn(key.character,&capacity,&key.length,reason.character,reason.length); + gstring * key = NULL; + if (subject.length!=-1) key =string_catn(key, subject.character, subject.length); + if (from.length!=-1) key = string_catn(key, from.character, from.length); + key = string_catn(key, reason_is_mime?US"1":US"0", 1); + key = string_catn(key, reason.character, reason.length); + md5_end(&base, key->s, key->ptr, digest); } else - key=handle; - md5_start(&base); - md5_end(&base, key.character, key.length, digest); + md5_end(&base, handle.character, handle.length, digest); + for (i = 0; i < 16; i++) sprintf(CS (hexdigest+2*i), "%02X", digest[i]); + if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0) - { debug_printf("Sieve: mail was personal, vacation file basename: %s\n", hexdigest); - } + if (filter_test == FTEST_NONE) { - capacity=Ustrlen(filter->vacation_directory); - start=capacity; - once=string_catn(filter->vacation_directory,&capacity,&start,US"/",1); - once=string_catn(once,&capacity,&start,hexdigest,33); - once[start] = '\0'; + once = string_cat (NULL, filter->vacation_directory); + once = string_catn(once, US"/", 1); + once = string_catn(once, hexdigest, 33); /* process subject */ @@ -3331,11 +3339,12 @@ while (*filter->pc) subject_def=expand_string(US"${if def:header_subject {true}{false}}"); if (Ustrcmp(subject_def,"true")==0) { + gstring * g = string_catn(NULL, US"Auto: ", 6); + expand_header(&subject,&str_subject); - capacity=6; - start=6; - subject.character=string_catn(US"Auto: ",&capacity,&start,subject.character,subject.length); - subject.length=start; + g = string_catn(g, subject.character, subject.length); + subject.character = string_from_gstring(g); + subject.length = g->ptr; } else { @@ -3363,7 +3372,7 @@ while (*filter->pc) buffer=store_get(buffer_capacity); /* deconst cast safe as we pass in a non-const item */ addr->reply->subject = US parse_quote_2047(subject.character, subject.length, US"utf-8", buffer, buffer_capacity, TRUE); - addr->reply->oncelog=once; + addr->reply->oncelog = string_from_gstring(once); addr->reply->once_repeat=days*86400; /* build body and MIME headers */ @@ -3372,6 +3381,7 @@ while (*filter->pc) { uschar *mime_body,*reason_end; static const uschar nlnl[]="\r\n\r\n"; + gstring * g; for ( @@ -3379,22 +3389,17 @@ while (*filter->pc) mime_body<(reason_end-(sizeof(nlnl)-1)) && memcmp(mime_body,nlnl,(sizeof(nlnl)-1)); ++mime_body ); - capacity = 0; - start = 0; - addr->reply->headers = string_catn(NULL,&capacity,&start,reason.character,mime_body-reason.character); - addr->reply->headers[start] = '\0'; - capacity = 0; - start = 0; + + addr->reply->headers = string_copyn(reason.character, mime_body-reason.character); + if (mime_body+(sizeof(nlnl)-1)reply->text = string_catn(NULL,&capacity,&start,mime_body,reason_end-mime_body); - addr->reply->text[start] = '\0'; + addr->reply->text = string_copyn(mime_body, reason_end-mime_body); } else { struct String qp = { .character = NULL, .length = 0 }; /* Keep compiler happy (PH) */ - capacity = 0; start = reason.length; addr->reply->headers = US"MIME-Version: 1.0\n" "Content-Type: text/plain;\n" @@ -3405,9 +3410,7 @@ while (*filter->pc) } } else if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0) - { debug_printf("Sieve: mail was not personal, vacation would ignore it\n"); - } } } else break; diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index 0f8d5599b..8e7e431cd 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -1710,37 +1710,22 @@ return string_sprintf("SMTP connection from %s", hostname); /* Append TLS-related information to a log line Arguments: - s String under construction: allocated string to extend, or NULL - sizep Pointer to current allocation size (update on return), or NULL - ptrp Pointer to index for new entries in string (update on return), or NULL + g String under construction: allocated string to extend, or NULL Returns: Allocated string or NULL */ -static uschar * -s_tlslog(uschar * s, int * sizep, int * ptrp) +static gstring * +s_tlslog(gstring * g) { - int size = sizep ? *sizep : 0; - int ptr = ptrp ? *ptrp : 0; - - if (LOGGING(tls_cipher) && tls_in.cipher != NULL) - s = string_append(s, &size, &ptr, 2, US" X=", tls_in.cipher); - if (LOGGING(tls_certificate_verified) && tls_in.cipher != NULL) - s = string_append(s, &size, &ptr, 2, US" CV=", - tls_in.certificate_verified? "yes":"no"); - if (LOGGING(tls_peerdn) && tls_in.peerdn != NULL) - s = string_append(s, &size, &ptr, 3, US" DN=\"", - string_printing(tls_in.peerdn), US"\""); - if (LOGGING(tls_sni) && tls_in.sni != NULL) - s = string_append(s, &size, &ptr, 3, US" SNI=\"", - string_printing(tls_in.sni), US"\""); - - if (s) - { - s[ptr] = '\0'; - if (sizep) *sizep = size; - if (ptrp) *ptrp = ptr; - } - return s; +if (LOGGING(tls_cipher) && tls_in.cipher) + g = string_append(g, 2, US" X=", tls_in.cipher); +if (LOGGING(tls_certificate_verified) && tls_in.cipher) + g = string_append(g, 2, US" CV=", tls_in.certificate_verified? "yes":"no"); +if (LOGGING(tls_peerdn) && tls_in.peerdn) + g = string_append(g, 3, US" DN=\"", string_printing(tls_in.peerdn), US"\""); +if (LOGGING(tls_sni) && tls_in.sni) + g = string_append(g, 3, US" SNI=\"", string_printing(tls_in.sni), US"\""); +return g; } #endif @@ -1759,45 +1744,40 @@ Returns: nothing void smtp_log_no_mail(void) { -int size, ptr, i; -uschar *s, *sep; +int i; +uschar * sep, * s; +gstring * g = NULL; if (smtp_mailcmd_count > 0 || !LOGGING(smtp_no_mail)) return; -s = NULL; -size = ptr = 0; - if (sender_host_authenticated != NULL) { - s = string_append(s, &size, &ptr, 2, US" A=", sender_host_authenticated); - if (authenticated_id != NULL) - s = string_append(s, &size, &ptr, 2, US":", authenticated_id); + g = string_append(g, 2, US" A=", sender_host_authenticated); + if (authenticated_id) g = string_append(g, 2, US":", authenticated_id); } #ifdef SUPPORT_TLS -s = s_tlslog(s, &size, &ptr); +g = s_tlslog(g); #endif -sep = (smtp_connection_had[SMTP_HBUFF_SIZE-1] != SCH_NONE)? - US" C=..." : US" C="; +sep = smtp_connection_had[SMTP_HBUFF_SIZE-1] != SCH_NONE ? US" C=..." : US" C="; + for (i = smtp_ch_index; i < SMTP_HBUFF_SIZE; i++) - { if (smtp_connection_had[i] != SCH_NONE) { - s = string_append(s, &size, &ptr, 2, sep, - smtp_names[smtp_connection_had[i]]); + g = string_append(g, 2, sep, smtp_names[smtp_connection_had[i]]); sep = US","; } - } for (i = 0; i < smtp_ch_index; i++) { - s = string_append(s, &size, &ptr, 2, sep, smtp_names[smtp_connection_had[i]]); + g = string_append(g, 2, sep, smtp_names[smtp_connection_had[i]]); sep = US","; } -if (s) s[ptr] = 0; else s = US""; +if (!(s = string_from_gstring(g))) s = US""; + log_write(0, LOG_MAIN, "no MAIL in %sSMTP connection from %s D=%s%s", tcp_in_fastopen ? US"TFO " : US"", host_and_ident(FALSE), string_timesince(&smtp_connection_start), s); @@ -1809,17 +1789,19 @@ log_write(0, LOG_MAIN, "no MAIL in %sSMTP connection from %s D=%s%s", uschar * smtp_cmd_hist(void) { -uschar * list = NULL; -int size = 0, len = 0, i; +int i; +gstring * list = NULL; +uschar * s; for (i = smtp_ch_index; i < SMTP_HBUFF_SIZE; i++) if (smtp_connection_had[i] != SCH_NONE) - list = string_append_listele(list, &size, &len, ',', - smtp_names[smtp_connection_had[i]]); + list = string_append_listele(list, ',', smtp_names[smtp_connection_had[i]]); + for (i = 0; i < smtp_ch_index; i++) - list = string_append_listele(list, &size, &len, ',', - smtp_names[smtp_connection_had[i]]); -return list ? list : US""; + list = string_append_listele(list, ',', smtp_names[smtp_connection_had[i]]); + +s = string_from_gstring(list); +return s ? s : US""; } @@ -2370,11 +2352,11 @@ Returns: FALSE if the session can not continue; something has BOOL smtp_start_session(void) { -int size = 256; -int ptr, esclen; +int esclen; uschar *user_msg, *log_msg; uschar *code, *esc; -uschar *p, *s, *ss; +uschar *p, *s; +gstring * ss; gettimeofday(&smtp_connection_start, NULL); for (smtp_ch_index = 0; smtp_ch_index < SMTP_HBUFF_SIZE; smtp_ch_index++) @@ -2898,35 +2880,32 @@ command. Sigh. To try to avoid this, build the complete greeting message first, and output it in one fell swoop. This gives a better chance of it ending up as a single packet. */ -ss = store_get(size); -ptr = 0; +ss = string_get(256); p = s; do /* At least once, in case we have an empty string */ { int len; uschar *linebreak = Ustrchr(p, '\n'); - ss = string_catn(ss, &size, &ptr, code, 3); + ss = string_catn(ss, code, 3); if (linebreak == NULL) { len = Ustrlen(p); - ss = string_catn(ss, &size, &ptr, US" ", 1); + ss = string_catn(ss, US" ", 1); } else { len = linebreak - p; - ss = string_catn(ss, &size, &ptr, US"-", 1); + ss = string_catn(ss, US"-", 1); } - ss = string_catn(ss, &size, &ptr, esc, esclen); - ss = string_catn(ss, &size, &ptr, p, len); - ss = string_catn(ss, &size, &ptr, US"\r\n", 2); + ss = string_catn(ss, esc, esclen); + ss = string_catn(ss, p, len); + ss = string_catn(ss, US"\r\n", 2); p += len; if (linebreak != NULL) p++; } while (*p != 0); -ss[ptr] = 0; /* string_cat leaves room for this */ - /* Before we write the banner, check that there is no input pending, unless this synchronisation check is disabled. */ @@ -2945,7 +2924,7 @@ if (!check_sync()) /* Now output the banner */ -smtp_printf("%s", FALSE, ss); +smtp_printf("%s", FALSE, string_from_gstring(ss)); /* Attempt to see if we sent the banner before the last ACK of the 3-way handshake arrived. If so we must have managed a TFO. */ @@ -3323,7 +3302,8 @@ is closing if required and return 2. */ if (log_reject_target != 0) { #ifdef SUPPORT_TLS - uschar * tls = s_tlslog(NULL, NULL, NULL); + gstring * g = s_tlslog(NULL); + uschar * tls = string_from_gstring(g); if (!tls) tls = US""; #else uschar * tls = US""; @@ -3846,11 +3826,12 @@ while (done <= 0) void (*oldsignal)(int); pid_t pid; int start, end, sender_domain, recipient_domain; - int ptr, size, rc; + int rc; int c; auth_instance *au; uschar *orcpt = NULL; int flags; + gstring * g; #ifdef AUTH_TLS /* Check once per STARTTLS or SSL-on-connect for a TLS AUTH */ @@ -4146,15 +4127,13 @@ while (done <= 0) sender_ident ? sender_ident : US"", sender_ident ? US" at " : US"", sender_host_name ? sender_host_name : sender_helo_name); - - ptr = Ustrlen(s); - size = ptr + 1; + g = string_cat(NULL, s); if (sender_host_address) { - s = string_catn(s, &size, &ptr, US" [", 2); - s = string_cat (s, &size, &ptr, sender_host_address); - s = string_catn(s, &size, &ptr, US"]", 1); + g = string_catn(g, US" [", 2); + g = string_cat (g, sender_host_address); + g = string_catn(g, US"]", 1); } } @@ -4174,18 +4153,17 @@ while (done <= 0) "newlines: message truncated: %s", string_printing(s)); *ss = 0; } - ptr = Ustrlen(s); - size = ptr + 1; + g = string_cat(NULL, s); } - s = string_catn(s, &size, &ptr, US"\r\n", 2); + g = string_catn(g, US"\r\n", 2); /* If we received EHLO, we must create a multiline response which includes the functions supported. */ if (esmtp) { - s[3] = '-'; + g->s[3] = '-'; /* I'm not entirely happy with this, as an MTA is supposed to check that it has enough room to accept a message of maximum size before @@ -4197,12 +4175,12 @@ while (done <= 0) { sprintf(CS big_buffer, "%.3s-SIZE %d\r\n", smtp_code, thismessage_size_limit); - s = string_cat(s, &size, &ptr, big_buffer); + g = string_cat(g, big_buffer); } else { - s = string_catn(s, &size, &ptr, smtp_code, 3); - s = string_catn(s, &size, &ptr, US"-SIZE\r\n", 7); + g = string_catn(g, smtp_code, 3); + g = string_catn(g, US"-SIZE\r\n", 7); } /* Exim does not do protocol conversion or data conversion. It is 8-bit @@ -4214,15 +4192,15 @@ while (done <= 0) if (accept_8bitmime) { - s = string_catn(s, &size, &ptr, smtp_code, 3); - s = string_catn(s, &size, &ptr, US"-8BITMIME\r\n", 11); + g = string_catn(g, smtp_code, 3); + g = string_catn(g, US"-8BITMIME\r\n", 11); } /* Advertise DSN support if configured to do so. */ if (verify_check_host(&dsn_advertise_hosts) != FAIL) { - s = string_catn(s, &size, &ptr, smtp_code, 3); - s = string_catn(s, &size, &ptr, US"-DSN\r\n", 6); + g = string_catn(g, smtp_code, 3); + g = string_catn(g, US"-DSN\r\n", 6); dsn_advertised = TRUE; } @@ -4231,18 +4209,18 @@ while (done <= 0) if (acl_smtp_etrn) { - s = string_catn(s, &size, &ptr, smtp_code, 3); - s = string_catn(s, &size, &ptr, US"-ETRN\r\n", 7); + g = string_catn(g, smtp_code, 3); + g = string_catn(g, US"-ETRN\r\n", 7); } if (acl_smtp_vrfy) { - s = string_catn(s, &size, &ptr, smtp_code, 3); - s = string_catn(s, &size, &ptr, US"-VRFY\r\n", 7); + g = string_catn(g, smtp_code, 3); + g = string_catn(g, US"-VRFY\r\n", 7); } if (acl_smtp_expn) { - s = string_catn(s, &size, &ptr, smtp_code, 3); - s = string_catn(s, &size, &ptr, US"-EXPN\r\n", 7); + g = string_catn(g, smtp_code, 3); + g = string_catn(g, US"-EXPN\r\n", 7); } /* Exim is quite happy with pipelining, so let the other end know that @@ -4251,8 +4229,8 @@ while (done <= 0) if (pipelining_enable && verify_check_host(&pipelining_advertise_hosts) == OK) { - s = string_catn(s, &size, &ptr, smtp_code, 3); - s = string_catn(s, &size, &ptr, US"-PIPELINING\r\n", 13); + g = string_catn(g, smtp_code, 3); + g = string_catn(g, US"-PIPELINING\r\n", 13); sync_cmd_limit = NON_SYNC_CMD_PIPELINING; pipelining_advertised = TRUE; } @@ -4293,29 +4271,29 @@ while (done <= 0) int saveptr; if (first) { - s = string_catn(s, &size, &ptr, smtp_code, 3); - s = string_catn(s, &size, &ptr, US"-AUTH", 5); + g = string_catn(g, smtp_code, 3); + g = string_catn(g, US"-AUTH", 5); first = FALSE; auth_advertised = TRUE; } - saveptr = ptr; - s = string_catn(s, &size, &ptr, US" ", 1); - s = string_cat (s, &size, &ptr, au->public_name); - while (++saveptr < ptr) s[saveptr] = toupper(s[saveptr]); + saveptr = g->ptr; + g = string_catn(g, US" ", 1); + g = string_cat (g, au->public_name); + while (++saveptr < g->ptr) g->s[saveptr] = toupper(g->s[saveptr]); au->advertised = TRUE; } } } - if (!first) s = string_catn(s, &size, &ptr, US"\r\n", 2); + if (!first) g = string_catn(g, US"\r\n", 2); } /* RFC 3030 CHUNKING */ if (verify_check_host(&chunking_advertise_hosts) != FAIL) { - s = string_catn(s, &size, &ptr, smtp_code, 3); - s = string_catn(s, &size, &ptr, US"-CHUNKING\r\n", 11); + g = string_catn(g, smtp_code, 3); + g = string_catn(g, US"-CHUNKING\r\n", 11); chunking_offered = TRUE; chunking_state = CHUNKING_OFFERED; } @@ -4329,8 +4307,8 @@ while (done <= 0) if (tls_in.active < 0 && verify_check_host(&tls_advertise_hosts) != FAIL) { - s = string_catn(s, &size, &ptr, smtp_code, 3); - s = string_catn(s, &size, &ptr, US"-STARTTLS\r\n", 11); + g = string_catn(g, smtp_code, 3); + g = string_catn(g, US"-STARTTLS\r\n", 11); tls_advertised = TRUE; } #endif @@ -4339,8 +4317,8 @@ while (done <= 0) /* Per Recipient Data Response, draft by Eric A. Hall extending RFC */ if (prdr_enable) { - s = string_catn(s, &size, &ptr, smtp_code, 3); - s = string_catn(s, &size, &ptr, US"-PRDR\r\n", 7); + g = string_catn(g, smtp_code, 3); + g = string_catn(g, US"-PRDR\r\n", 7); } #endif @@ -4348,36 +4326,36 @@ while (done <= 0) if ( accept_8bitmime && verify_check_host(&smtputf8_advertise_hosts) != FAIL) { - s = string_catn(s, &size, &ptr, smtp_code, 3); - s = string_catn(s, &size, &ptr, US"-SMTPUTF8\r\n", 11); + g = string_catn(g, smtp_code, 3); + g = string_catn(g, US"-SMTPUTF8\r\n", 11); smtputf8_advertised = TRUE; } #endif /* Finish off the multiline reply with one that is always available. */ - s = string_catn(s, &size, &ptr, smtp_code, 3); - s = string_catn(s, &size, &ptr, US" HELP\r\n", 7); + g = string_catn(g, smtp_code, 3); + g = string_catn(g, US" HELP\r\n", 7); } /* Terminate the string (for debug), write it, and note that HELO/EHLO has been seen. */ - s[ptr] = 0; - #ifdef SUPPORT_TLS - if (tls_in.active >= 0) (void)tls_write(TRUE, s, ptr, FALSE); else + if (tls_in.active >= 0) (void)tls_write(TRUE, g->s, g->ptr, FALSE); else #endif { - int i = fwrite(s, 1, ptr, smtp_out); i = i; /* compiler quietening */ + int i = fwrite(g->s, 1, g->ptr, smtp_out); i = i; /* compiler quietening */ } DEBUG(D_receive) { uschar *cr; - while ((cr = Ustrchr(s, '\r')) != NULL) /* lose CRs */ - memmove(cr, cr + 1, (ptr--) - (cr - s)); - debug_printf("SMTP>> %s", s); + + (void) string_from_gstring(g); + while ((cr = Ustrchr(g->s, '\r')) != NULL) /* lose CRs */ + memmove(cr, cr + 1, (g->ptr--) - (cr - g->s)); + debug_printf("SMTP>> %s", g->s); } helo_seen = TRUE; diff --git a/src/src/spam.c b/src/src/spam.c index 20154da4f..6ca6678f8 100644 --- a/src/src/spam.c +++ b/src/src/spam.c @@ -371,29 +371,28 @@ start = time(NULL); /* now we are connected to spamd on spamd_sock */ if (sd->is_rspamd) { - uschar * req_str = NULL; - int size = 0, len = 0; + gstring * req_str; const uschar * s; - req_str = string_append(req_str, &size, &len, 8, + req_str = string_append(NULL, 8, "CHECK RSPAMC/1.3\r\nContent-length: ", string_sprintf("%lu\r\n", mbox_size), "Queue-Id: ", message_id, "\r\nFrom: <", sender_address, ">\r\nRecipient-Number: ", string_sprintf("%d\r\n", recipients_count)); for (i = 0; i < recipients_count; i ++) - req_str = string_append(req_str, &size, &len, 3, + req_str = string_append(req_str, 3, "Rcpt: <", recipients_list[i].address, ">\r\n"); if ((s = expand_string(US"$sender_helo_name")) && *s) - req_str = string_append(req_str, &size, &len, 3, "Helo: ", s, "\r\n"); + req_str = string_append(req_str, 3, "Helo: ", s, "\r\n"); if ((s = expand_string(US"$sender_host_name")) && *s) - req_str = string_append(req_str, &size, &len, 3, "Hostname: ", s, "\r\n"); + req_str = string_append(req_str, 3, "Hostname: ", s, "\r\n"); if (sender_host_address) - req_str = string_append(req_str, &size, &len, 3, "IP: ", sender_host_address, "\r\n"); + req_str = string_append(req_str, 3, "IP: ", sender_host_address, "\r\n"); if ((s = expand_string(US"$authenticated_id")) && *s) - req_str = string_append(req_str, &size, &len, 3, "User: ", s, "\r\n"); - req_str = string_catn(req_str, &size, &len, "\r\n", 2); - wrote = send(spamd_sock, req_str, len, 0); + req_str = string_append(req_str, 3, "User: ", s, "\r\n"); + req_str = string_catn(req_str, "\r\n", 2); + wrote = send(spamd_sock, req_str->s, req_str->ptr, 0); } else { /* spamassassin variant */ diff --git a/src/src/string.c b/src/src/string.c index 2de595afb..cfe801284 100644 --- a/src/src/string.c +++ b/src/src/string.c @@ -930,9 +930,8 @@ if (buffer != NULL) else { - int size = 0; - int ptr = 0; const uschar *ss; + gstring * g = NULL; /* We know that *s != 0 at this point. However, it might be pointing to a separator, which could indicate an empty string, or (if an ispunct() @@ -954,13 +953,13 @@ else for (;;) { - for (ss = s + 1; *ss != 0 && *ss != sep; ss++); - buffer = string_catn(buffer, &size, &ptr, s, ss-s); + for (ss = s + 1; *ss != 0 && *ss != sep; ss++) ; + g = string_catn(g, s, ss-s); s = ss; if (*s == 0 || *(++s) != sep || sep_is_special) break; } - while (ptr > 0 && isspace(buffer[ptr-1])) ptr--; - buffer[ptr] = 0; + while (g->ptr > 0 && isspace(g->s[g->ptr-1])) g->ptr--; + buffer = string_from_gstring(g); } /* Update the current pointer and return the new string */ @@ -1000,56 +999,52 @@ Despite having the same growable-string interface as string_cat() the list is always returned null-terminated. Arguments: - list points to the start of the list that is being built, or NULL + list expanding-string for the list that is being built, or NULL if this is a new list that has no contents yet - sz (ptr to) amount of memory allocated for list; zero for a new list - off (ptr to) current list length in chars (insert point for next addition), - zero for a new list sep list separator character ele new element to be appended to the list Returns: pointer to the start of the list, changed if copied for expansion. */ -uschar * -string_append_listele(uschar * list, int * sz, int * off, - uschar sep, const uschar * ele) +gstring * +string_append_listele(gstring * list, uschar sep, const uschar * ele) { uschar * sp; -if (list) - list = string_catn(list, sz, off, &sep, 1); +if (list && list->ptr) + list = string_catn(list, &sep, 1); while((sp = Ustrchr(ele, sep))) { - list = string_catn(list, sz, off, ele, sp-ele+1); - list = string_catn(list, sz, off, &sep, 1); + list = string_catn(list, ele, sp-ele+1); + list = string_catn(list, &sep, 1); ele = sp+1; } -list = string_cat(list, sz, off, ele); -list[*off] = '\0'; +list = string_cat(list, ele); +(void) string_from_gstring(list); return list; } -uschar * -string_append_listele_n(uschar * list, int * sz, int * off, - uschar sep, const uschar * ele, unsigned len) +gstring * +string_append_listele_n(gstring * list, uschar sep, const uschar * ele, + unsigned len) { const uschar * sp; -if (list) - list = string_catn(list, sz, off, &sep, 1); +if (list && list->ptr) + list = string_catn(list, &sep, 1); while((sp = Ustrnchr(ele, sep, &len))) { - list = string_catn(list, sz, off, ele, sp-ele+1); - list = string_catn(list, sz, off, &sep, 1); + list = string_catn(list, ele, sp-ele+1); + list = string_catn(list, &sep, 1); ele = sp+1; len--; } -list = string_catn(list, sz, off, ele, len); -list[*off] = '\0'; +list = string_catn(list, ele, len); +(void) string_from_gstring(list); return list; } @@ -1058,102 +1053,44 @@ return list; /************************************************* * Add chars to string * *************************************************/ +/* See inline functions in functions.h */ -/* This function is used when building up strings of unknown length. Room is -always left for a terminating zero to be added to the string that is being -built. This function does not require the string that is being added to be NUL -terminated, because the number of characters to add is given explicitly. It is -sometimes called to extract parts of other strings. - -Arguments: - string points to the start of the string that is being built, or NULL - if this is a new string that has no contents yet - size points to a variable that holds the current capacity of the memory - block (updated if changed) - ptr points to a variable that holds the offset at which to add - characters, updated to the new offset - s points to characters to add - count count of characters to add; must not exceed the length of s, if s - is a C string. - -If string is given as NULL, *size and *ptr should both be zero. - -Returns: pointer to the start of the string, changed if copied for expansion. - Note that a NUL is not added, though space is left for one. This is - because string_cat() is often called multiple times to build up a - string - there's no point adding the NUL till the end. - -*/ -/* coverity[+alloc] */ - -uschar * -string_catn(uschar *string, int *size, int *ptr, const uschar *s, int count) +void +gstring_grow(gstring * g, int p, int count) { -int p = *ptr; - -if (p + count >= *size) +int oldsize = g->size; + +/* Mostly, string_cat() is used to build small strings of a few hundred +characters at most. There are times, however, when the strings are very much +longer (for example, a lookup that returns a vast number of alias addresses). +To try to keep things reasonable, we use increments whose size depends on the +existing length of the string. */ + +unsigned inc = oldsize < 4096 ? 127 : 1023; +g->size = ((p + count + inc) & ~inc) + 1; + +/* Try to extend an existing allocation. If the result of calling +store_extend() is false, either there isn't room in the current memory block, +or this string is not the top item on the dynamic store stack. We then have +to get a new chunk of store and copy the old string. When building large +strings, it is helpful to call store_release() on the old string, to release +memory blocks that have become empty. (The block will be freed if the string +is at its start.) However, we can do this only if we know that the old string +was the last item on the dynamic memory stack. This is the case if it matches +store_last_get. */ + +if (!store_extend(g->s, oldsize, g->size)) { - int oldsize = *size; - - /* Mostly, string_cat() is used to build small strings of a few hundred - characters at most. There are times, however, when the strings are very much - longer (for example, a lookup that returns a vast number of alias addresses). - To try to keep things reasonable, we use increments whose size depends on the - existing length of the string. */ - - int inc = (oldsize < 4096)? 100 : 1024; - while (*size <= p + count) *size += inc; - - /* New string */ - - if (string == NULL) string = store_get(*size); - - /* Try to extend an existing allocation. If the result of calling - store_extend() is false, either there isn't room in the current memory block, - or this string is not the top item on the dynamic store stack. We then have - to get a new chunk of store and copy the old string. When building large - strings, it is helpful to call store_release() on the old string, to release - memory blocks that have become empty. (The block will be freed if the string - is at its start.) However, we can do this only if we know that the old string - was the last item on the dynamic memory stack. This is the case if it matches - store_last_get. */ - - else if (!store_extend(string, oldsize, *size)) - { - BOOL release_ok = store_last_get[store_pool] == string; - uschar *newstring = store_get(*size); - memcpy(newstring, string, p); - if (release_ok) store_release(string); - string = newstring; - } + BOOL release_ok = store_last_get[store_pool] == g->s; + uschar *newstring = store_get(g->size); + memcpy(newstring, g->s, p); + if (release_ok) store_release(g->s); + g->s = newstring; } - -/* Because we always specify the exact number of characters to copy, we can -use memcpy(), which is likely to be more efficient than strncopy() because the -latter has to check for zero bytes. - -The Coverity annotation deals with the lack of correlated variable tracking; -common use is a null string and zero size and pointer, on first use for a -string being built. The "if" above then allocates, but Coverity assume that -the "if" might not happen and whines for a null-deref done by the memcpy(). */ - -/* coverity[deref_parm_field_in_call] : FALSE */ -memcpy(string + p, s, count); -*ptr = p + count; -return string; } -uschar * -string_cat(uschar *string, int *size, int *ptr, const uschar *s) -{ -return string_catn(string, size, ptr, s, Ustrlen(s)); -} -#endif /* COMPILE_UTILITY */ - - -#ifndef COMPILE_UTILITY /************************************************* * Append strings to another string * *************************************************/ @@ -1162,12 +1099,8 @@ return string_catn(string, size, ptr, s, Ustrlen(s)); It calls string_cat() to do the dirty work. Arguments: - string points to the start of the string that is being built, or NULL + string expanding-string that is being built, or NULL if this is a new string that has no contents yet - size points to a variable that holds the current capacity of the memory - block (updated if changed) - ptr points to a variable that holds the offset at which to add - characters, updated to the new offset count the number of strings to append ... "count" uschar* arguments, which must be valid zero-terminated C strings @@ -1176,17 +1109,16 @@ Returns: pointer to the start of the string, changed if copied for expansion. The string is not zero-terminated - see string_cat() above. */ -uschar * -string_append(uschar *string, int *size, int *ptr, int count, ...) +__inline__ gstring * +string_append(gstring *string, int count, ...) { va_list ap; -int i; va_start(ap, count); -for (i = 0; i < count; i++) +while (count-- > 0) { uschar *t = va_arg(ap, uschar *); - string = string_cat(string, size, ptr, t); + string = string_cat(string, t); } va_end(ap); @@ -1209,7 +1141,7 @@ as a va_list item. The formats are the usual printf() ones, with some omissions (never used) and three additions for strings: %S forces lower case, %T forces upper case, and -%#s or %#S prints nothing for a NULL string. Without thr # "NULL" is printed +%#s or %#S prints nothing for a NULL string. Without the # "NULL" is printed (useful in debugging). There is also the addition of %D and %M, which insert the date in the form used for datestamped log files. diff --git a/src/src/structs.h b/src/src/structs.h index c16899a0c..22c141c0d 100644 --- a/src/src/structs.h +++ b/src/src/structs.h @@ -25,6 +25,13 @@ struct smtp_outblock; struct transport_info; struct router_info; +/* Growable-string */ +typedef struct gstring { + int size; /* Current capacity of string memory */ + int ptr; /* Offset at which to append further chars */ + uschar * s; /* The string memory */ +} gstring; + /* Structure for remembering macros for the configuration file */ typedef struct macro_item { @@ -238,7 +245,7 @@ typedef int (*tpt_chunk_cmd_cb)(struct transport_context *, unsigned, unsigned); typedef struct transport_context { union { /* discriminated by option topt_output_string */ int fd; /* file descriptor to write message to */ - uschar * msg; /* allocated string with written message */ + gstring * msg; /* allocated string with written message */ } u; transport_instance * tblock; /* transport */ struct address_item * addr; @@ -249,10 +256,6 @@ typedef struct transport_context { /* items below only used with option topt_use_bdat */ tpt_chunk_cmd_cb chunk_cb; /* per-datachunk callback */ void * smtp_context; - - /* items below only used with option topt_output_string */ - int msg_size; - int msg_ptr; } transport_ctx; diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c index c0ed6f992..6f10cf5f7 100644 --- a/src/src/tls-openssl.c +++ b/src/src/tls-openssl.c @@ -2573,8 +2573,7 @@ tls_write(BOOL is_server, const uschar *buff, size_t len, BOOL more) { int outbytes, error, left; SSL *ssl = is_server ? server_ssl : client_ssl; -static uschar * corked = NULL; -static int c_size = 0, c_len = 0; +static gstring * corked = NULL; DEBUG(D_tls) debug_printf("%s(%p, %lu%s)\n", __FUNCTION__, buff, (unsigned long)len, more ? ", more" : ""); @@ -2586,12 +2585,12 @@ for the responses to the received SMTP MAIL , RCPT, DATA sequence, only. */ if (is_server && (more || corked)) { - corked = string_catn(corked, &c_size, &c_len, buff, len); + corked = string_catn(corked, buff, len); if (more) return len; - buff = CUS corked; - len = c_len; - corked = NULL; c_size = c_len = 0; + buff = CUS corked->s; + len = corked->ptr; + corked = NULL; } for (left = len; left > 0;) diff --git a/src/src/tls.c b/src/src/tls.c index c93eb4579..a24b939a4 100644 --- a/src/src/tls.c +++ b/src/src/tls.c @@ -263,8 +263,7 @@ uschar outsep = '\n'; uschar * ele; uschar * match = NULL; int len; -uschar * list = NULL; -int size = 0, pos = 0; +gstring * list = NULL; while ((ele = string_nextinlist(&mod, &insep, NULL, 0))) if (ele[0] != '>') @@ -279,8 +278,8 @@ while ((ele = string_nextinlist(CUSS &dn, &insep, NULL, 0))) if ( !match || Ustrncmp(ele, match, len) == 0 && ele[len] == '=' ) - list = string_append_listele(list, &size, &pos, outsep, ele+len+1); -return list; + list = string_append_listele(list, outsep, ele+len+1); +return string_from_gstring(list); } diff --git a/src/src/tlscert-gnu.c b/src/src/tlscert-gnu.c index 65d01214a..c9df5ea19 100644 --- a/src/src/tlscert-gnu.c +++ b/src/src/tlscert-gnu.c @@ -279,8 +279,7 @@ return cp2; uschar * tls_cert_subject_altname(void * cert, uschar * mod) { -uschar * list = NULL; -int lsize = 0, llen = 0; +gstring * list = NULL; int index; size_t siz; int ret; @@ -308,7 +307,7 @@ for(index = 0;; index++) (gnutls_x509_crt_t)cert, index, NULL, &siz, NULL)) { case GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE: - return list; /* no more elements; normal exit */ + return string_from_gstring(list); /* no more elements; normal exit */ case GNUTLS_E_SHORT_MEMORY_BUFFER: break; @@ -333,7 +332,7 @@ for(index = 0;; index++) case GNUTLS_SAN_RFC822NAME: tag = US"MAIL"; break; default: continue; /* ignore unrecognised types */ } - list = string_append_listele(list, &lsize, &llen, sep, + list = string_append_listele(list, sep, match == -1 ? string_sprintf("%s=%s", tag, ele) : ele); } /*NOTREACHED*/ @@ -347,8 +346,7 @@ gnutls_datum_t uri; int ret; uschar sep = '\n'; int index; -uschar * list = NULL; -int lsize = 0, llen = 0; +gstring * list = NULL; if (mod) if (*mod == '>' && *++mod) sep = *mod++; @@ -359,12 +357,11 @@ for(index = 0;; index++) index, GNUTLS_IA_OCSP_URI, &uri, NULL); if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) - return list; + return string_from_gstring(list); if (ret < 0) return g_err("gai", __FUNCTION__, ret); - list = string_append_listele_n(list, &lsize, &llen, sep, - uri.data, uri.size); + list = string_append_listele_n(list, sep, uri.data, uri.size); } /*NOTREACHED*/ @@ -385,8 +382,7 @@ int ret; size_t siz; uschar sep = '\n'; int index; -uschar * list = NULL; -int lsize = 0, llen = 0; +gstring * list = NULL; uschar * ele; if (mod) @@ -399,7 +395,7 @@ for(index = 0;; index++) (gnutls_x509_crt_t)cert, index, NULL, &siz, NULL, NULL)) { case GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE: - return list; + return string_from_gstring(list); case GNUTLS_E_SHORT_MEMORY_BUFFER: break; default: @@ -411,7 +407,7 @@ for(index = 0;; index++) (gnutls_x509_crt_t)cert, index, ele, &siz, NULL, NULL)) < 0) return g_err("gc1", __FUNCTION__, ret); - list = string_append_listele_n(list, &lsize, &llen, sep, ele, siz); + list = string_append_listele_n(list, sep, ele, siz); } /*NOTREACHED*/ } diff --git a/src/src/tlscert-openssl.c b/src/src/tlscert-openssl.c index 87623a879..bfd4dc112 100644 --- a/src/src/tlscert-openssl.c +++ b/src/src/tlscert-openssl.c @@ -342,8 +342,7 @@ return cp3; uschar * tls_cert_subject_altname(void * cert, uschar * mod) { -uschar * list = NULL; -int lsize = 0, llen = 0; +gstring * list = NULL; STACK_OF(GENERAL_NAME) * san = (STACK_OF(GENERAL_NAME) *) X509_get_ext_d2i((X509 *)cert, NID_subject_alt_name, NULL, NULL); uschar osep = '\n'; @@ -394,12 +393,12 @@ while (sk_GENERAL_NAME_num(san) > 0) ele = string_copyn(ele, len); if (Ustrlen(ele) == len) /* ignore any with embedded nul */ - list = string_append_listele(list, &lsize, &llen, osep, + list = string_append_listele(list, osep, match == -1 ? string_sprintf("%s=%s", tag, ele) : ele); } sk_GENERAL_NAME_free(san); -return list; +return string_from_gstring(list); } uschar * @@ -410,8 +409,7 @@ STACK_OF(ACCESS_DESCRIPTION) * ads = (STACK_OF(ACCESS_DESCRIPTION) *) int adsnum = sk_ACCESS_DESCRIPTION_num(ads); int i; uschar sep = '\n'; -uschar * list = NULL; -int size = 0, len = 0; +gstring * list = NULL; if (mod) if (*mod == '>' && *++mod) sep = *mod++; @@ -421,12 +419,12 @@ for (i = 0; i < adsnum; i++) ACCESS_DESCRIPTION * ad = sk_ACCESS_DESCRIPTION_value(ads, i); if (ad && OBJ_obj2nid(ad->method) == NID_ad_OCSP) - list = string_append_listele_n(list, &size, &len, sep, + list = string_append_listele_n(list, sep, ASN1_STRING_data(ad->location->d.ia5), ASN1_STRING_length(ad->location->d.ia5)); } sk_ACCESS_DESCRIPTION_free(ads); -return list; +return string_from_gstring(list); } uschar * @@ -439,8 +437,7 @@ DIST_POINT * dp; int dpsnum = sk_DIST_POINT_num(dps); int i; uschar sep = '\n'; -uschar * list = NULL; -int size = 0, len = 0; +gstring * list = NULL; if (mod) if (*mod == '>' && *++mod) sep = *mod++; @@ -457,12 +454,12 @@ if (dps) for (i = 0; i < dpsnum; i++) if ( (np = sk_GENERAL_NAME_value(names, j)) && np->type == GEN_URI ) - list = string_append_listele_n(list, &size, &len, sep, + list = string_append_listele_n(list, sep, ASN1_STRING_data(np->d.uniformResourceIdentifier), ASN1_STRING_length(np->d.uniformResourceIdentifier)); } sk_DIST_POINT_free(dps); -return list; +return string_from_gstring(list); } diff --git a/src/src/transport.c b/src/src/transport.c index 5d4102ef8..75af68f9b 100644 --- a/src/src/transport.c +++ b/src/src/transport.c @@ -346,12 +346,9 @@ if (!(tctx->options & topt_output_string)) /* Write to expanding-string. NOTE: not NUL-terminated */ if (!tctx->u.msg) - { - tctx->u.msg = store_get(tctx->msg_size = 1024); - tctx->msg_ptr = 0; - } + tctx->u.msg = string_get(1024); -tctx->u.msg = string_catn(tctx->u.msg, &tctx->msg_size, &tctx->msg_ptr, block, len); +tctx->u.msg = string_catn(tctx->u.msg, block, len); return TRUE; } diff --git a/src/src/transports/pipe.c b/src/src/transports/pipe.c index be0256061..0ce281fd0 100644 --- a/src/src/transports/pipe.c +++ b/src/src/transports/pipe.c @@ -471,13 +471,19 @@ 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"); + 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 */ + + enable_dollar_recipients = addr && addr->parent && + Ustrcmp(addr->parent->address, "system-filter") == 0; if (p != NULL && ( (p > cmd && p[-1] == '$') || @@ -485,37 +491,30 @@ if (expand_arguments) { 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 (ad = addr; ad; ad = ad->next) { /*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; - if (argv[2] == NULL) + if (!argv[2]) { - addr->transport_return = search_find_defer? DEFER : expand_fail; + addr->transport_return = search_find_defer ? DEFER : expand_fail; addr->message = string_sprintf("Expansion of command \"%s\" " "in %s transport failed: %s", cmd, tname, expand_string_message); @@ -525,7 +524,12 @@ 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] = US 0; return TRUE; @@ -1072,7 +1076,8 @@ if ((rc = child_close(pid, timeout)) != 0) else if (!ob->ignore_status) { uschar *ss; - int size, ptr, i; + gstring * g; + int i; /* 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 @@ -1097,9 +1102,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. */ @@ -1111,35 +1114,34 @@ if ((rc = child_close(pid, timeout)) != 0) if (*ss != 0) { - 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++) { 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); } } } diff --git a/src/src/utf8.c b/src/src/utf8.c index 4647785b9..dcc944af9 100644 --- a/src/src/utf8.c +++ b/src/src/utf8.c @@ -97,8 +97,7 @@ string_domain_alabel_to_utf8(const uschar * alabel, uschar ** err) #ifdef SUPPORT_I18N_2008 const uschar * label; int sep = '.'; -uschar * s = NULL; -int size = 0, len = 0; +gstring * g = NULL; while (label = string_nextinlist(&alabel, &sep, NULL, 0)) if ( string_is_alabel(label) @@ -106,8 +105,8 @@ while (label = string_nextinlist(&alabel, &sep, NULL, 0)) ) return NULL; else - s = string_append_listele(s, &size, &len, '.', label); -return s; + g = string_append_listele(g, '.', label); +return string_from_gstring(g); #else