Add warning about missing colon to invalid expansion when it involved
[exim.git] / src / src / expand.c
index fc4d63aad3bb26e9cf245f3a84d26cd6dc59b59d..b91f0316aaca604c3794a6d292495afaf0ce47d6 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/expand.c,v 1.63 2006/10/03 08:54:50 ph10 Exp $ */
+/* $Cambridge: exim/src/src/expand.c,v 1.68 2006/10/31 14:26:34 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -1124,6 +1124,12 @@ for (i = 0; i < 2; i++)
           while (isspace(*t)) t++;          /* remove leading white space */
         ilen = h->slen - (t - h->text);     /* length to insert */
 
+        /* Unless wanted raw, remove trailing whitespace, including the
+        newline. */
+
+        if (!want_raw)
+          while (ilen > 0 && isspace(t[ilen-1])) ilen--;
+
         /* Set comma = 1 if handling a single header and it's one of those
         that contains an address list, except when asked for raw headers. Only
         need to do this once. */
@@ -1135,7 +1141,7 @@ for (i = 0; i < 2; i++)
         /* First pass - compute total store needed; second pass - compute
         total store used, including this header. */
 
-        size += ilen + comma;
+        size += ilen + comma + 1;  /* +1 for the newline */
 
         /* Second pass - concatentate the data, up to a maximum. Note that
         the loop stops when size hits the limit. */
@@ -1144,14 +1150,19 @@ for (i = 0; i < 2; i++)
           {
           if (size > header_insert_maxlen)
             {
-            ilen -= size - header_insert_maxlen;
+            ilen -= size - header_insert_maxlen - 1;
             comma = 0;
             }
           Ustrncpy(ptr, t, ilen);
           ptr += ilen;
-          if (comma != 0 && ilen > 0)
+
+          /* For a non-raw header, put in the comma if needed, then add
+          back the newline we removed above, provided there was some text in
+          the header. */
+
+          if (!want_raw && ilen > 0)
             {
-            ptr[-1] = ',';
+            if (comma != 0) *ptr++ = ',';
             *ptr++ = '\n';
             }
           }
@@ -1159,8 +1170,9 @@ for (i = 0; i < 2; i++)
       }
     }
 
-  /* At end of first pass, truncate size if necessary, and get the buffer
-  to hold the data, returning the buffer size. */
+  /* At end of first pass, return NULL if no header found. Then truncate size
+  if necessary, and get the buffer to hold the data, returning the buffer size.
+  */
 
   if (i == 0)
     {
@@ -1171,10 +1183,6 @@ for (i = 0; i < 2; i++)
     }
   }
 
-/* Remove a redundant added comma if present */
-
-if (comma != 0 && ptr > yield) ptr -= 2;
-
 /* That's all we do for raw header expansion. */
 
 if (want_raw)
@@ -1182,15 +1190,16 @@ if (want_raw)
   *ptr = 0;
   }
 
-/* Otherwise, we remove trailing whitespace, including newlines. Then we do RFC
-2047 decoding, translating the charset if requested. The rfc2047_decode2()
+/* Otherwise, remove a final newline and a redundant added comma. Then we do
+RFC 2047 decoding, translating the charset if requested. The rfc2047_decode2()
 function can return an error with decoded data if the charset translation
 fails. If decoding fails, it returns NULL. */
 
 else
   {
   uschar *decoded, *error;
-  while (ptr > yield && isspace(ptr[-1])) ptr--;
+  if (ptr > yield && ptr[-1] == '\n') ptr--;
+  if (ptr > yield && comma != 0 && ptr[-1] == ',') ptr--;
   *ptr = 0;
   decoded = rfc2047_decode2(yield, check_rfc2047_length, charset, '?', NULL,
     newsize, &error);
@@ -1680,7 +1689,9 @@ switch(cond_type)
 
   s = read_name(name, 256, s+1, US"_");
 
-  /* Test for a header's existence */
+  /* Test for a header's existence. If the name contains a closing brace
+  character, this may be a user error where the terminating colon has been
+  omitted. Set a flag to adjust a subsequent error message in this case. */
 
   if (Ustrncmp(name, "h_", 2) == 0 ||
       Ustrncmp(name, "rh_", 3) == 0 ||
@@ -1690,6 +1701,7 @@ switch(cond_type)
       Ustrncmp(name, "bheader_", 8) == 0)
     {
     s = read_header_name(name, 256, s);
+    if (Ustrchr(name, '}') != NULL) malformed_header = TRUE;
     if (yield != NULL) *yield =
       (find_header(name, TRUE, NULL, FALSE, NULL) != NULL) == testfor;
     }
@@ -2964,7 +2976,7 @@ while (*s != 0)
       value = find_header(name, FALSE, &newsize, want_raw, charset);
 
       /* If we didn't find the header, and the header contains a closing brace
-      characters, this may be a user error where the terminating colon
+      character, this may be a user error where the terminating colon
       has been omitted. Set a flag to adjust the error message in this case.
       But there is no error here - nothing gets inserted. */
 
@@ -3748,7 +3760,8 @@ while (*s != 0)
           else
             {
             shost.name = server_name;
-            if (host_find_byname(&shost, NULL, NULL, FALSE) != HOST_FOUND)
+            if (host_find_byname(&shost, NULL, HOST_FIND_QUALIFY_SINGLE, NULL,
+                FALSE) != HOST_FOUND)
               {
               expand_string_message =
                 string_sprintf("no IP address found for host %s", shost.name);
@@ -3823,6 +3836,14 @@ while (*s != 0)
             }
           }
 
+        /* Shut down the sending side of the socket. This helps some servers to
+        recognise that it is their turn to do some work. Just in case some
+        system doesn't have this function, make it conditional. */
+
+        #ifdef SHUT_WR
+        shutdown(fd, SHUT_WR);
+        #endif
+
         /* Now we need to read from the socket, under a timeout. The function
         that reads a file can be used. */