String handling: refactor the expanding-string routines and users to use a descriptor...
authorJeremy Harris <jgh146exb@wizmail.org>
Thu, 12 Oct 2017 21:05:14 +0000 (22:05 +0100)
committerJeremy Harris <jgh146exb@wizmail.org>
Sat, 14 Oct 2017 14:34:17 +0000 (15:34 +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 b5ffa01..79feb5f 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 b91b437..7d55287 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 09e03f1..17a87d2 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 6310eec..0bd67d8 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 cd8a16a..723267c 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 a3419db..8b12e21 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 85a73dc..b61c41e 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 f0c00cd..40df72c 100644 (file)
@@ -1150,8 +1150,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++)
@@ -1162,26 +1161,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);
 }
 
 
@@ -1254,11 +1251,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++)
   {
@@ -1293,23 +1288,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 67b3d65..c2690b0 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++;
@@ -6823,26 +6792,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;
@@ -6852,7 +6821,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;
         }
@@ -6889,24 +6858,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;
         }
 
@@ -6938,7 +6907,7 @@ while (*s != 0)
           goto EXPAND_FAILED;
           }
 
-        yield = string_cat(yield, &size, &ptr, sub);
+        yield = string_cat(yield, sub);
         continue;
         }
 
@@ -6951,8 +6920,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;
         }
@@ -6965,7 +6934,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;
         }
 
@@ -6982,7 +6951,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;
         }
 
@@ -6998,7 +6967,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;
         }
@@ -7033,7 +7002,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;
                  }
              }
@@ -7042,7 +7011,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 */
@@ -7075,11 +7044,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;
         }
@@ -7096,7 +7065,7 @@ while (*s != 0)
            string_printing(sub), error);
          goto EXPAND_FAILED;
          }
-       yield = string_cat(yield, &size, &ptr, s);
+       yield = string_cat(yield, s);
         continue;
        }
 
@@ -7111,7 +7080,7 @@ while (*s != 0)
            string_printing(sub), error);
          goto EXPAND_FAILED;
          }
-       yield = string_cat(yield, &size, &ptr, s);
+       yield = string_cat(yield, s);
         continue;
        }
 
@@ -7126,8 +7095,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;
        }
 
@@ -7142,7 +7111,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 */
@@ -7152,7 +7121,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;
         }
 
@@ -7163,8 +7132,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;
        }
 
@@ -7184,7 +7153,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;
         }
 
@@ -7200,7 +7169,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;
         }
 
@@ -7215,7 +7184,7 @@ while (*s != 0)
           goto EXPAND_FAILED;
           }
         t = readconf_printtime(n);
-        yield = string_cat(yield, &size, &ptr, t);
+        yield = string_cat(yield, t);
         continue;
         }
 
@@ -7231,7 +7200,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;
        }
 
@@ -7245,7 +7214,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;
         }
 
@@ -7255,7 +7224,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;
         }
 
@@ -7346,7 +7315,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;
         }
 
@@ -7401,7 +7370,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;
         }
 
@@ -7416,7 +7385,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;
         }
 
@@ -7435,7 +7404,7 @@ while (*s != 0)
           goto EXPAND_FAILED;
           }
         invert_address(reversed, sub);
-        yield = string_cat(yield, &size, &ptr, reversed);
+        yield = string_cat(yield, reversed);
         continue;
         }
 
@@ -7459,11 +7428,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)))
       {
@@ -7475,12 +7446,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;
     }
 
@@ -7508,15 +7480,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)
@@ -7528,13 +7501,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".
@@ -7552,7 +7525,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 86232c1..0b3ef8b 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 e9f71c9..111e5c3 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,12 @@ 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 gstring *string_cat (gstring *, const uschar *     ) WARN_UNUSED_RESULT;
+extern gstring *string_catn(gstring *, 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 *);
@@ -451,6 +453,8 @@ extern uschar *string_copynlc(uschar *, int);
 extern uschar *string_dequote(const uschar **);
 extern BOOL    string_format(uschar *, int, const char *, ...) ALMOST_PRINTF(3,4);
 extern uschar *string_format_size(int, uschar *);
+extern uschar *string_from_gstring(gstring *);
+extern gstring *string_get(unsigned);
 extern int     string_interpret_escape(const uschar **);
 extern int     string_is_ip_address(const uschar *, int *);
 #ifdef SUPPORT_I18N
@@ -534,6 +538,7 @@ 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);
 
+
 /* vi: aw
 */
 /* End of functions.h */
index ec26280..c02fc55 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 0c3d5a2..323225c 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 bf3acd6..9e95b90 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 7f1775c..58bced2 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 b52ef22..8d6ac26 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 d2487d3..210aae4 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 2a76756..1541d0d 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 6101d00..745856d 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 b5133bc..0d3d92a 100644 (file)
@@ -140,11 +140,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];
@@ -288,7 +286,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;
     }
@@ -308,25 +307,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)
@@ -348,15 +347,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
@@ -367,13 +366,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 ff632a1..03c3431 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 eca15f1..bc14def 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 d71f97b..ef8f099 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 3a96f5e..e8989ca 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 0b01fdb..0df8537 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 e39cea8..f9b9919 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 61dabd2..36737e9 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 6952881..06d455d 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 e82f26c..a34999a 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 e8cb297..1396b19 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(gstring * 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 abf2559..61e241e 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 5f4f0d9..6966d73 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 f831f86..1cbbd83 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 66d2d3f..2d9aacd 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 */
@@ -3408,9 +3407,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)))
@@ -3422,8 +3420,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,
@@ -3442,13 +3440,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",
@@ -3773,10 +3768,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;
 
@@ -3809,13 +3802,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)
     {
@@ -3949,58 +3941,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
@@ -4009,11 +3996,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!
@@ -4029,7 +4016,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
@@ -4052,20 +4039,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;
 
@@ -4082,11 +4069,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");
@@ -4099,7 +4083,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,
@@ -4156,11 +4140,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. */
 
@@ -4224,7 +4207,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(). */
 
@@ -4236,7 +4219,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 041a188..cb4a661 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 bbaa528..1b9676f 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 9923af5..5b6a088 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 745704f..bf8dc4a 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 32d9279..3bb1078 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 9847c86..b5839f5 100644 (file)
@@ -1711,37 +1711,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
 
@@ -1760,45 +1745,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);
@@ -1810,17 +1790,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"";
 }
 
 
@@ -2371,11 +2353,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++)
@@ -2899,35 +2881,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. */
 
@@ -2946,7 +2925,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. */
@@ -3324,7 +3303,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"";
@@ -3847,11 +3827,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 */
@@ -4147,15 +4128,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);
         }
       }
 
@@ -4175,18 +4154,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
@@ -4198,12 +4176,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
@@ -4215,15 +4193,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;
         }
 
@@ -4232,18 +4210,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
@@ -4252,8 +4230,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;
         }
@@ -4294,29 +4272,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;
         }
@@ -4330,8 +4308,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
@@ -4340,8 +4318,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
 
@@ -4349,36 +4327,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 20154da..6ca6678 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 f3bf343..ee57319 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,65 +999,120 @@ 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;
 }
 
 
 
+/************************************************/
+/* Create a growable-string with some preassigned space */
+
+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. */
+
+uschar *
+string_from_gstring(gstring * g)
+{
+if (!g) return NULL;
+g->s[g->ptr] = '\0';
+return g->s;
+}
+
 /*************************************************
 *             Add chars to string                *
 *************************************************/
 
+void
+gstring_grow(gstring * g, int p, int count)
+{
+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))
+  {
+  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;
+  }
+}
+
+
+
 /* 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
@@ -1068,16 +1122,10 @@ 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
@@ -1086,74 +1134,40 @@ Returns:   pointer to the start of the string, changed if copied for expansion.
 */
 /* coverity[+alloc] */
 
-uschar *
-string_catn(uschar *string, int *size, int *ptr, const uschar *s, int count)
+gstring *
+string_catn(gstring * g, const uschar *s, int count)
 {
-int p = *ptr;
+int p;
 
-if (p + count >= *size)
+if (!g)
   {
-  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;
-    }
+  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.
-
-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(). */
+latter has to check for zero bytes. */
 
-/* coverity[deref_parm_field_in_call] : FALSE */
-memcpy(string + p, s, count);
-*ptr = p + count;
-return string;
+memcpy(g->s + p, s, count);
+g->ptr = p + count;
+return g;
 }
-
-
-uschar *
-string_cat(uschar *string, int *size, int *ptr, const uschar *s)
+gstring *
+string_cat(gstring *string, const uschar *s)
 {
-return string_catn(string, size, ptr, s, Ustrlen(s));
+return string_catn(string, s, Ustrlen(s));
 }
-#endif  /* COMPILE_UTILITY */
 
 
 
-#ifndef COMPILE_UTILITY
 /*************************************************
 *        Append strings to another string        *
 *************************************************/
@@ -1162,12 +1176,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 +1186,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 +1218,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 c16899a..22c141c 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                &n