String handling: refactor the expanding-string routines and users to use a descriptor...
authorJeremy Harris <jgh146exb@wizmail.org>
Tue, 3 Oct 2017 15:13:26 +0000 (16:13 +0100)
committerJeremy Harris <jgh146exb@wizmail.org>
Tue, 3 Oct 2017 15:13:26 +0000 (16:13 +0100)
50 files changed:
src/src/acl.c
src/src/daemon.c
src/src/debug.c
src/src/deliver.c
src/src/dkim.c
src/src/dkim.h
src/src/dkim_transport.c
src/src/exim.c
src/src/expand.c
src/src/filter.c
src/src/functions.h
src/src/host.c
src/src/imap_utf7.c
src/src/lookups/dnsdb.c
src/src/lookups/ibase.c
src/src/lookups/ldap.c
src/src/lookups/lf_functions.h
src/src/lookups/lf_quote.c
src/src/lookups/lsearch.c
src/src/lookups/mysql.c
src/src/lookups/nisplus.c
src/src/lookups/oracle.c
src/src/lookups/pgsql.c
src/src/lookups/redis.c
src/src/lookups/sqlite.c
src/src/malware.c
src/src/mime.c
src/src/pdkim/pdkim.c
src/src/pdkim/pdkim.h
src/src/pdkim/signing.c
src/src/pdkim/signing.h
src/src/perl.c
src/src/readconf.c
src/src/receive.c
src/src/rfc2047.c
src/src/route.c
src/src/routers/redirect.c
src/src/routers/rf_get_munge_headers.c
src/src/sieve.c
src/src/smtp_in.c
src/src/spam.c
src/src/string.c
src/src/structs.h
src/src/tls-openssl.c
src/src/tls.c
src/src/tlscert-gnu.c
src/src/tlscert-openssl.c
src/src/transport.c
src/src/transports/pipe.c
src/src/utf8.c

index b5ffa0193ed58372ca72918d9d922eaf543f502f..79feb5f68076ae55552d570867ed741583e06865 100644 (file)
@@ -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;
 }
 
 
index b91b43746159ef16f3393de4abe749591c1ab85e..7d55287858d067e87f9129f1d4d56a7c95855f1b 100644 (file)
@@ -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;
       }
 
index 09e03f1e499f81a9476a6ce279af089803ed631e..17a87d2d2fb958af544261eda81c03f3319b8bdb 100644 (file)
@@ -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 */
 
index 648c63d691d6e977ceac9705a93dcbf619cb6d99..1241fa3cf818ab80b79cff4e64f355fb23aba703 100644 (file)
@@ -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 "
index cd8a16ae61b8cd04f96143d4325a6a097bd3bda1..723267cbfaa65c4b550bbbd07cb2b51f0585cae8 100644 (file)
@@ -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"<UNSET>";
-  logmsg = string_append(logmsg, &size, &ptr, 2, "d=", s);
+  logmsg = string_append(NULL, 2, "d=", s);
   if (!(s = sig->selector)) s = US"<UNSET>";
-  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;
index a3419db42fb4973536307cdb9d0f51e3368e1fa8..8b12e21ed516fdf1404faa7e3a064e561e717ccf 100644 (file)
@@ -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);
index 85a73dcaeb872c20b7c45ffbecf8a7bb6d36fbd2..b61c41edcc49467eabe79c5034ba40f245e49ed1 100644 (file)
@@ -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))
index f09b26902a3a7b77b818b741503f0501c3a870f9..7114b75298d17f6f42742b2a531caf6a02be7507 100644 (file)
@@ -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);
 }
 
 
index 353b8ea56b6cdb6a19f0226d826b681bd9254e72..9cbfbe883b1e5d62166a52aba732f5a485256e75 100644 (file)
@@ -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",
index 86232c1870471fab889688cb0613e9036305bffa..0b3ef8b2da1ed3f0cc29ed02186691d4fbea211d 100644 (file)
@@ -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"<default>" : 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"<default>",
+         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;
index 9d1f6dc6e118ac7ae2c8e5b8750fa0ed43fa1979..e6aada27af9b9c7964bed598b8589a993775f3a0 100644 (file)
@@ -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 */
index ec262805e3dbb8796bc2b0a7f6b54eb44f669633..c02fc5532462df7b4e45ffda1b32c3c383b1f7eb 100644 (file)
@@ -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
index 0c3d5a20dc125e55f9e1994d96ff86ad67c3cf8c..323225c231a06972832ca3858bc4431a5257f69a 100644 (file)
@@ -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 */
index bf3acd6ef03d3d1ce0cb8a39d153949d217542b7..9e95b9038ca79053c7a54d6fca2796207a620cec 100644 (file)
 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;
 }
 
index 7f1775c1ffb7e1f5f4e99ad3cb43b28e4ed68abf..58bced201912c993f3f28d63b7ba0d134add11f6 100644 (file)
@@ -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 */
+  }
 }
 
 
index b52ef2221ee1293c1254f9fd990788cdb5007f99..8d6ac2674b7448e6b6b83c3cd88bdec46cd1323e 100644 (file)
@@ -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);
index d2487d3621cd5a51be4b9344a8627ba9e06dd565..210aae4d5993ba6e18491a17c699a1310643015f 100644 (file)
@@ -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 **,
index 2a76756e9cf417c2febeec6456424ae2fc12488a..1541d0d1602a4ea69c5fd9bb5bd8a718b9bac291 100644 (file)
@@ -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 */
index 6101d00ac521a54c2d7da1f9d07a3c32b0fdcbd7..745856d02e9ad50854a99a983556fb256c1de5fe 100644 (file)
@@ -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;
index ddc7dc8414484d29962e475e3ed9e3d10a0fc378..53789133e7796fde76047d294a5d25b2534ec375 100644 (file)
@@ -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
index ff632a1caba466b5da91682e1c6d80a18afbbc85..03c3431034a55dd15cb1391dd2bda51273b2f448 100644 (file)
@@ -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;
   }
 
index eca15f1b40ffbe574bfab08c07fdf9788c944011..bc14def701f5985fbf5f3152da9d1af89975232d 100644 (file)
@@ -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
index d71f97b33164502370244d2218d05f4c346456a9..ef8f0997dc17be9ede7e01358d299c38d5238cf7 100644 (file)
@@ -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
index 3a96f5ef940139337f9dc8b269de95e4b10e0925..e8989ca3a1580733c786d0a64b0650e1d6945c1a 100644 (file)
@@ -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
index 0b01fdbce9b1d9df7007c848fc1ea123774df377..0df85373681087a745aeaf2c2b2eb87a135981a9 100644 (file)
@@ -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]:"<NULL>");
-    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]:"<NULL>");
-  }
+  res = string_cat(res, argv[0] ? US argv[0] : US "<NULL>");
 
-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;
 }
 
index 32f2e9e492461fd4209e70570925df71a29bf4fb..ccb7e6d2043f152c784f9ab29773091b40e93508 100644 (file)
@@ -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
        {
index 61dabd2ac6561be2b0f88f3526147ed54d88adcc..36737e9eb235a1e20967ee54e2755ea17b6566db 100644 (file)
@@ -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);
 }
 
 
index 695288162740d0598e7f4caab42c7110908ef38d..06d455d7dbeaeb116ac7905ac1735651e979c754 100644 (file)
@@ -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; p<len; p++)
     else if (c == '\n')
       {
       if (!(ctx->flags & 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; p<len; p++)
       ctx->flags &= ~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 '<CR><LF>' */
-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;
index e82f26c05a40d9e376369e63a9a24807c8ee3fda..a34999ad83d42afbfebcf51b7a4d2bb75ee1dccd 100644 (file)
@@ -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;
index e8cb297ca1cb03c94c582ef5bdf15ddb61c8219e..edded11a4f65eaf87bca4e8f85785fedbb079a46 100644 (file)
@@ -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*/
 }
 
 
index abf25598800f8ad7afd8dd36a08e713367fbb91e..61e241e5dfe1febd44809076fe56f2a62f3ea149 100644 (file)
@@ -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 *);
index 5f4f0d98dcad7699173bad27b5762d381047de77..6966d73b5adf96d446e376f2e9936dc74b85e148 100644 (file)
@@ -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;
 
index f831f866a3ecd11ff667581aab7b4fa0bafc2e6b..1cbbd83ef868383f64770614e5ff3d529bdbeb91 100644 (file)
@@ -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;
   }
index 65e9fb415127f301e017c68e5d86b42132e382e9..4fb0c26cbc3f2026aeda3653db3a785e889d9c5d 100644 (file)
@@ -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. */
 
index 041a18858768ace59de0f89b6c38c433ffe8fbdd..cb4a661bf99a82312b5f49a202058d0d57ad5eb0 100644 (file)
@@ -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);
 }
 
 
index bbaa5285d37f9decffcfb9e81f77d851602d9b29..1b9676f3f87ffd3aea6017f76b67bea0f2e93a87 100644 (file)
@@ -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
index 9923af58514af31cbc369b69fc412c99ee4d4b19..5b6a08818f811a65d3d7050e1276e1f9d3de777a 100644 (file)
@@ -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);
index 745704f6241ddb112a4af50957dca8f5cc8d481c..bf8dc4a5d5ec95b45b048bb39a4b555f98455f54 100644 (file)
@@ -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 */
index 32d9279eaba612ce4d52ecced3394a551925b48e..3bb10785b8948389d5a28b92ae54bb2d3f0f1e62 100644 (file)
@@ -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; i<end && !eq_asciicase(&hname,i,0); ++i);
       if (i==end)
         {
-        if (header->length==-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)<reason_end) mime_body+=(sizeof(nlnl)-1);
             else mime_body=reason_end-1;
-            addr->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;
index 0f8d5599b6a9173411ff094e1a961ec2c665b626..8e7e431cda1224878af0b378e8359ef8898aab88 100644 (file)
@@ -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;
 
index 20154da4f40f310d5885daa13592ce40348e9883..6ca6678f88cdd0f7645ba9f582c5b613eadd7232 100644 (file)
@@ -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 */
index 2de595afb664d3602bc40fc3c50ff728ca7118ab..cfe8012849d8434cfc33ab299ac3a2d0174f9b07 100644 (file)
@@ -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.
 
index c16899a0c7a3ace69082250938c8afb5183f363f..22c141c0d634e244910111e81771e6d39b6b6b12 100644 (file)
@@ -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;
 
 
index c0ed6f992c3a976dbcf49cb77ee8b948c77c6770..6f10cf5f7d03ca0bba0fd30c36f3d6ee06d0c050 100644 (file)
@@ -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;)
index c93eb4579069e36365aba99a222aa3e12bf038b0..a24b939a4eafd0cd8d9766d8502377b07587df5c 100644 (file)
@@ -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);
 }
 
 
index 65d01214ab41f00d8590e5b2c4d16fcda2a8eb81..c9df5ea19973a014a967314e5eba490bfea4ce07 100644 (file)
@@ -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*/
 }
index 87623a8794be6f24ee4df83fa7eb2f14620454b6..bfd4dc112a93f31c705fc32ae2776bcf2d4451cb 100644 (file)
@@ -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);
 }
 
 
index 5d4102ef8781b21279ae7ab5e38784349423967a..75af68f9ba82dbf78caf89644b181b2d01128ecc 100644 (file)
@@ -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;
 }
 
index be02560611b7a5bdef4c3fbfc55e6dcf3da048d1..0ce281fd0d2af39468cbb9a4290fb02c561c5431 100644 (file)
@@ -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);
       }
     }
   }
index 4647785b9da36fdb2492c15618568e85bf60cf91..dcc944af93516ffb90e4f797f092609d7776a027 100644 (file)
@@ -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