Bug #198: Add remove_header ACL modifier.
[exim.git] / src / src / acl.c
index d0db7171eac1153855a33b72396653dea878728c..3b23a915b5aaa8fcd89812df1203a7d9e05e25e3 100644 (file)
@@ -88,6 +88,7 @@ enum { ACLC_ACL,
 #ifdef WITH_CONTENT_SCAN
        ACLC_REGEX,
 #endif
+       ACLC_REMOVE_HEADER,
        ACLC_SENDER_DOMAINS,
        ACLC_SENDERS,
        ACLC_SET,
@@ -150,6 +151,7 @@ static uschar *conditions[] = {
 #ifdef WITH_CONTENT_SCAN
   US"regex",
 #endif
+  US"remove_header",
   US"sender_domains", US"senders", US"set",
 #ifdef WITH_CONTENT_SCAN
   US"spam",
@@ -280,6 +282,7 @@ static uschar cond_expand_at_top[] = {
 #ifdef WITH_CONTENT_SCAN
   TRUE,    /* regex */
 #endif
+  TRUE,    /* remove_header */
   FALSE,   /* sender_domains */
   FALSE,   /* senders */
   TRUE,    /* set */
@@ -340,6 +343,7 @@ static uschar cond_modifiers[] = {
 #ifdef WITH_CONTENT_SCAN
   FALSE,   /* regex */
 #endif
+  TRUE,    /* remove_header */
   FALSE,   /* sender_domains */
   FALSE,   /* senders */
   TRUE,    /* set */
@@ -465,6 +469,12 @@ static unsigned int cond_forbids[] = {
     (1<<ACL_WHERE_MIME)),
   #endif
 
+  (unsigned int)
+  ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|       /* remove_header */
+    (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
+    (1<<ACL_WHERE_MIME)|(1<<ACL_WHERE_NOTSMTP)|
+    (1<<ACL_WHERE_NOTSMTP_START)),
+
   (1<<ACL_WHERE_AUTH)|(1<<ACL_WHERE_CONNECT)|      /* sender_domains */
     (1<<ACL_WHERE_HELO)|
     (1<<ACL_WHERE_MAILAUTH)|(1<<ACL_WHERE_QUIT)|
@@ -1037,6 +1047,31 @@ for (p = q = hstring; *p != 0; )
 
 
 
+/*************************************************
+*        Set up removed header line(s)           *
+*************************************************/
+
+/* This function is called by the remove_header modifier.  The argument is
+treated as a sequence of header names which are added to a colon separated
+list, provided there isn't an identical one already there.
+
+Argument:   string of header names
+Returns:    nothing
+*/
+
+static void
+setup_remove_header(uschar *hnames)
+{
+if (*hnames != 0)
+  {
+  if (acl_removed_headers == NULL)
+    acl_removed_headers = hnames;
+  else
+    acl_removed_headers = string_sprintf("%s : %s", acl_removed_headers, hnames);
+  }
+}
+
+
 
 /*************************************************
 *               Handle warnings                  *
@@ -3294,6 +3329,10 @@ for (; cb != NULL; cb = cb->next)
     break;
     #endif
 
+    case ACLC_REMOVE_HEADER:
+    setup_remove_header(arg);
+    break;
+
     case ACLC_SENDER_DOMAINS:
       {
       uschar *sdomain;
@@ -3873,23 +3912,28 @@ acl_check_wargs(int where, address_item *addr, uschar *s, int level,
   uschar **user_msgptr, uschar **log_msgptr)
 {
 uschar * tmp;
+uschar * tmp_arg[9];   /* must match acl_arg[] */
 uschar * name;
+int i;
 
 if (!(tmp = string_dequote(&s)) || !(name = expand_string(tmp)))
   goto bad;
 
-for (acl_narg = 0; acl_narg < sizeof(acl_arg)/sizeof(*acl_arg); acl_narg++)
+for (i = 0; i < 9; i++)
   {
   while (*s && isspace(*s)) s++;
   if (!*s) break;
-  if (!(tmp = string_dequote(&s)) || !(acl_arg[acl_narg] = expand_string(tmp)))
+  if (!(tmp = string_dequote(&s)) || !(tmp_arg[i] = expand_string(tmp)))
     {
     tmp = name;
     goto bad;
     }
   }
+acl_narg = i;
+for (i = 0; i < acl_narg; i++) acl_arg[i] = tmp_arg[i];
+while (i < 9) acl_arg[i++] = NULL;
 
-return acl_check_internal(where, addr, name, level+1, user_msgptr, log_msgptr);
+return acl_check_internal(where, addr, name, level, user_msgptr, log_msgptr);
 
 bad:
 if (expand_string_forcedfail) return ERROR;