struct dnssec_domains
[exim.git] / src / src / expand.c
index 1f0c5cb3cfd14799cccb8822d901a1a73a2fa0c0..2092701630b254008d68dfdef81dd869ebd6f131 100644 (file)
@@ -114,6 +114,9 @@ static uschar *item_table[] = {
   US"hash",
   US"hmac",
   US"if",
+#ifdef EXPERIMENTAL_INTERNATIONAL
+  US"imapfolder",
+#endif
   US"length",
   US"listextract",
   US"lookup",
@@ -140,6 +143,9 @@ enum {
   EITEM_HASH,
   EITEM_HMAC,
   EITEM_IF,
+#ifdef EXPERIMENTAL_INTERNATIONAL
+  EITEM_IMAPFOLDER,
+#endif
   EITEM_LENGTH,
   EITEM_LISTEXTRACT,
   EITEM_LOOKUP,
@@ -168,7 +174,14 @@ static uschar *op_table_underscore[] = {
   US"quote_local_part",
   US"reverse_ip",
   US"time_eval",
-  US"time_interval"};
+  US"time_interval"
+#ifdef EXPERIMENTAL_INTERNATIONAL
+ ,US"utf8_domain_from_alabel",
+  US"utf8_domain_to_alabel",
+  US"utf8_localpart_from_alabel",
+  US"utf8_localpart_to_alabel"
+#endif
+  };
 
 enum {
   EOP_FROM_UTF8,
@@ -176,7 +189,14 @@ enum {
   EOP_QUOTE_LOCAL_PART,
   EOP_REVERSE_IP,
   EOP_TIME_EVAL,
-  EOP_TIME_INTERVAL };
+  EOP_TIME_INTERVAL
+#ifdef EXPERIMENTAL_INTERNATIONAL
+ ,EOP_UTF8_DOMAIN_FROM_ALABEL,
+  EOP_UTF8_DOMAIN_TO_ALABEL,
+  EOP_UTF8_LOCALPART_FROM_ALABEL,
+  EOP_UTF8_LOCALPART_TO_ALABEL
+#endif
+  };
 
 static uschar *op_table_main[] = {
   US"address",
@@ -549,6 +569,9 @@ static var_entry var_table[] = {
   { "message_id",          vtype_stringptr,   &message_id },
   { "message_linecount",   vtype_int,         &message_linecount },
   { "message_size",        vtype_int,         &message_size },
+#ifdef EXPERIMENTAL_INTERNATIONAL
+  { "message_smtputf8",    vtype_bool,        &message_smtputf8 },
+#endif
 #ifdef WITH_CONTENT_SCAN
   { "mime_anomaly_level",  vtype_int,         &mime_anomaly_level },
   { "mime_anomaly_text",   vtype_stringptr,   &mime_anomaly_text },
@@ -2026,15 +2049,15 @@ static int
 eval_acl(uschar ** sub, int nsub, uschar ** user_msgp)
 {
 int i;
-uschar * tmp = NULL;
 int sav_narg = acl_narg;
 int ret;
+uschar * dummy_logmsg;
 extern int acl_where;
 
 if(--nsub > sizeof(acl_arg)/sizeof(*acl_arg)) nsub = sizeof(acl_arg)/sizeof(*acl_arg);
 for (i = 0; i < nsub && sub[i+1]; i++)
   {
-  tmp = acl_arg[i];
+  uschar * tmp = acl_arg[i];
   acl_arg[i] = sub[i+1];       /* place callers args in the globals */
   sub[i+1] = tmp;              /* stash the old args using our caller's storage */
   }
@@ -2051,7 +2074,7 @@ DEBUG(D_expand)
     acl_narg>0 ? acl_arg[0] : US"<none>",
     acl_narg>1 ? " +more"   : "");
 
-ret = acl_eval(acl_where, sub[0], user_msgp, &tmp);
+ret = acl_eval(acl_where, sub[0], user_msgp, &dummy_logmsg);
 
 for (i = 0; i < nsub; i++)
   acl_arg[i] = sub[i+1];       /* restore old args */
@@ -4053,6 +4076,45 @@ while (*s != 0)
       continue;
       }
 
+#ifdef EXPERIMENTAL_INTERNATIONAL
+    case EITEM_IMAPFOLDER:
+      {                                /* ${imapfolder {name}{sep]{specials}} */
+      uschar *sub_arg[3];
+      uschar *encoded;
+
+      switch(read_subs(sub_arg, 3, 1, &s, skipping, TRUE, name, &resetok))
+        {
+        case 1: goto EXPAND_FAILED_CURLY;
+        case 2:
+        case 3: goto EXPAND_FAILED;
+        }
+
+      if (sub_arg[1] == NULL)          /* One argument */
+       {
+       sub_arg[1] = "/";               /* default separator */
+       sub_arg[2] = NULL;
+       }
+      else if (sub_arg[2] == NULL)     /* Two arguments */
+       sub_arg[2] = NULL;
+
+      if (Ustrlen(sub_arg[1]) != 1)
+       {
+       expand_string_message = 
+         string_sprintf(
+               "IMAP folder separator must be one character, found \"%s\"", 
+               sub_arg[1]);
+       goto EXPAND_FAILED;
+       }
+
+      if (!(encoded = imap_utf7_encode(sub_arg[0], headers_charset,
+                         sub_arg[1][0], sub_arg[2], &expand_string_message)))
+       goto EXPAND_FAILED;
+      if (!skipping)
+       yield = string_cat(yield, &size, &ptr, encoded, Ustrlen(encoded));
+      continue;
+      }
+#endif
+
     /* Handle database lookups unless locked out. If "skipping" is TRUE, we are
     expanding an internal string that isn't actually going to be used. All we
     need to do is check the syntax, so don't do a lookup at all. Preserve the
@@ -5501,7 +5563,7 @@ while (*s != 0)
         while (isspace(*s)) s++;
         if (*s++ != '{') goto EXPAND_FAILED_CURLY;
         t = expand_string_internal(s, TRUE, &s, skipping, TRUE, &resetok);
-        if (temp == NULL) goto EXPAND_FAILED;
+        if (!t) goto EXPAND_FAILED;
         lookup_value = t;
         if (*s++ != '}') goto EXPAND_FAILED_CURLY;
         }
@@ -6552,16 +6614,13 @@ while (*s != 0)
          if (bytes_left)
            {
            if ((c & 0xc0) != 0x80)
-             {
                    /* wrong continuation byte; invalidate all bytes */
              complete = 1; /* error */
-             }
            else
              {
              codepoint = (codepoint << 6) | (c & 0x3f);
              seq_buff[index++] = c;
              if (--bytes_left == 0)            /* codepoint complete */
-               {
                if(codepoint > 0x10FFFF)        /* is it too large? */
                  complete = -1;        /* error (RFC3629 limit) */
                else
@@ -6569,7 +6628,6 @@ while (*s != 0)
                  yield = string_cat(yield, &size, &ptr, seq_buff, seq_len);
                  index = 0;
                  }
-               }
              }
            }
          else  /* no bytes left: new sequence */
@@ -6612,13 +6670,75 @@ while (*s != 0)
            yield = string_cat(yield, &size, &ptr, UTF8_REPLACEMENT_CHAR, 1);
            }
          if ((complete == 1) && ((c & 0x80) == 0))
-           { /* ASCII character follows incomplete sequence */
+                       /* ASCII character follows incomplete sequence */
              yield = string_cat(yield, &size, &ptr, &c, 1);
-           }
          }
         continue;
         }
 
+#ifdef EXPERIMENTAL_INTERNATIONAL
+      case EOP_UTF8_DOMAIN_TO_ALABEL:
+       {
+        uschar * error = NULL;
+       uschar * s = string_domain_utf8_to_alabel(sub, &error);
+       if (error)
+         {
+         expand_string_message = string_sprintf(
+           "error converting utf8 (%s) to alabel: %s",
+           string_printing(sub), error);
+         goto EXPAND_FAILED;
+         }
+       yield = string_cat(yield, &size, &ptr, s, Ustrlen(s));
+        continue;
+       }
+
+      case EOP_UTF8_DOMAIN_FROM_ALABEL:
+       {
+        uschar * error = NULL;
+       uschar * s = string_domain_alabel_to_utf8(sub, &error);
+       if (error)
+         {
+         expand_string_message = string_sprintf(
+           "error converting alabel (%s) to utf8: %s",
+           string_printing(sub), error);
+         goto EXPAND_FAILED;
+         }
+       yield = string_cat(yield, &size, &ptr, s, Ustrlen(s));
+        continue;
+       }
+
+      case EOP_UTF8_LOCALPART_TO_ALABEL:
+       {
+        uschar * error = NULL;
+       uschar * s = string_localpart_utf8_to_alabel(sub, &error);
+       if (error)
+         {
+         expand_string_message = string_sprintf(
+           "error converting utf8 (%s) to alabel: %s",
+           string_printing(sub), error);
+         goto EXPAND_FAILED;
+         }
+       yield = string_cat(yield, &size, &ptr, s, Ustrlen(s));
+       DEBUG(D_expand) debug_printf("yield: '%s'\n", yield);
+        continue;
+       }
+
+      case EOP_UTF8_LOCALPART_FROM_ALABEL:
+       {
+        uschar * error = NULL;
+       uschar * s = string_localpart_alabel_to_utf8(sub, &error);
+       if (error)
+         {
+         expand_string_message = string_sprintf(
+           "error converting alabel (%s) to utf8: %s",
+           string_printing(sub), error);
+         goto EXPAND_FAILED;
+         }
+       yield = string_cat(yield, &size, &ptr, s, Ustrlen(s));
+        continue;
+       }
+#endif /* EXPERIMENTAL_INTERNATIONAL */
+
       /* escape turns all non-printing characters into escape sequences. */
 
       case EOP_ESCAPE: