[exim-cvs] cvs commit: exim/exim-doc/doc-txt ChangeLog NewSt…

Top Page
Delete this message
Reply to this message
Author: Philip Hazel
Date:  
To: exim-cvs
Subject: [exim-cvs] cvs commit: exim/exim-doc/doc-txt ChangeLog NewStuff exim/exim-src ACKNOWLEDGMENTS exim/exim-src/src expand.c exim/exim-test/scripts/0000-Basic 0002 exim/exim-test/stdout 0002
ph10 2006/11/13 11:26:37 GMT

  Modified files:
    exim-doc/doc-txt     ChangeLog NewStuff 
    exim-src             ACKNOWLEDGMENTS 
    exim-src/src         expand.c 
    exim-test/scripts/0000-Basic 0002 
    exim-test/stdout     0002 
  Log:
  Add bitwise logical operators to ${eval:


  Revision  Changes    Path
  1.430     +2 -0      exim/exim-doc/doc-txt/ChangeLog
  1.121     +177 -148  exim/exim-doc/doc-txt/NewStuff
  1.63      +2 -1      exim/exim-src/ACKNOWLEDGMENTS
  1.69      +145 -34   exim/exim-src/src/expand.c
  1.8       +14 -0     exim/exim-test/scripts/0000-Basic/0002
  1.8       +17 -3     exim/exim-test/stdout/0002


  Index: ChangeLog
  ===================================================================
  RCS file: /home/cvs/exim/exim-doc/doc-txt/ChangeLog,v
  retrieving revision 1.429
  retrieving revision 1.430
  diff -u -r1.429 -r1.430
  --- ChangeLog    7 Nov 2006 16:50:36 -0000    1.429
  +++ ChangeLog    13 Nov 2006 11:26:37 -0000    1.430
  @@ -1,4 +1,4 @@
  -$Cambridge: exim/exim-doc/doc-txt/ChangeLog,v 1.429 2006/11/07 16:50:36 ph10 Exp $
  +$Cambridge: exim/exim-doc/doc-txt/ChangeLog,v 1.430 2006/11/13 11:26:37 ph10 Exp $


   Change log file for Exim from version 4.21
   -------------------------------------------
  @@ -261,6 +261,8 @@
         been fixed so that -R and -S can now usefully be given with -q<time>.


PH/40 Import PCRE release 6.7 (fixes some bugs).
+
+PH/41 Add bitwise logical operations to eval (courtesy Brad Jorsch).


Exim version 4.63

  Index: NewStuff
  ===================================================================
  RCS file: /home/cvs/exim/exim-doc/doc-txt/NewStuff,v
  retrieving revision 1.120
  retrieving revision 1.121
  diff -u -r1.120 -r1.121
  --- NewStuff    6 Nov 2006 15:50:12 -0000    1.120
  +++ NewStuff    13 Nov 2006 11:26:37 -0000    1.121
  @@ -1,4 +1,4 @@
  -$Cambridge: exim/exim-doc/doc-txt/NewStuff,v 1.120 2006/11/06 15:50:12 ph10 Exp $
  +$Cambridge: exim/exim-doc/doc-txt/NewStuff,v 1.121 2006/11/13 11:26:37 ph10 Exp $


New Features in Exim
--------------------
@@ -12,156 +12,185 @@
Version 4.64
------------

  -1. ACL variables can now be given arbitrary names, as long as they start with
  -   "acl_c" or "acl_m" (for connection variables and message variables), are
  -   at least six characters long, with the sixth character being either a digit
  -   or an underscore. The rest of the name can contain alphanumeric characters
  -   and underscores. This is a compatible change because the old set of
  -   variables such as acl_m12 are a subset of the allowed names. There may now
  -   be any number of ACL variables. For example:
  -
  -     set acl_c13   = value for original ACL variable
  -     set acl_c13b  = whatever
  -     set acl_m_foo = something
  -
  -   What happens if a syntactically valid but undefined ACL variable is
  -   referenced depends on the setting of the strict_acl_vars option. If it is
  -   false (the default), an empty string is substituted; if it is true, an error
  -   is generated. This affects all ACL variables, including the "old" ones such
  -   as acl_c4. (Previously there wasn't the concept of an undefined ACL
  -   variable.)
  -
  -   The implementation has been done in such a way that spool files containing
  -   ACL variable settings written by previous releases of Exim are compatible
  -   and can be read by the new release. If only the original numeric names are
  -   used, spool files written by the new release can be read by earlier
  -   releases.
  -
  -2. There is a new ACL modifier called log_reject_target. It makes it possible
  -   to specify which logs are used for messages about ACL rejections. Its
  -   argument is a list of words which can be "main", "reject", or "panic". The
  -   default is "main:reject". The list may be empty, in which case a rejection
  -   is not logged at all. For example, this ACL fragment writes no logging
  -   information when access is denied:
  -
  -     deny <some conditions>
  -          log_reject_target =
  -
  -   The modifier can be used in SMTP and non-SMTP ACLs. It applies to both
  -   permanent and temporary rejections.
  -
  -3. There is a new authenticator called "dovecot". This is an interface to the
  -   authentication facility of the Dovecot POP/IMAP server, which can support a
  -   number of authentication methods. If you are using Dovecot to authenticate
  -   POP/IMAP clients, it might be helpful to use the same mechanisms for SMTP
  -   authentication. This is a server authenticator only. The only option is
  -   server_socket, which must specify the socket which is the interface to
  -   Dovecot authentication. The public_name option must specify an
  -   authentication mechanism that Dovecot is configured to support. You can have
  -   several authenticators for different mechanisms. For example:
  -
  -     dovecot_plain:
  -       driver = dovecot
  -       public_name = PLAIN
  -       server_name = /var/run/dovecot/auth-client
  -       server_setid = $auth1
  -
  -     dovecot_ntlm:
  -       driver = dovecot
  -       public_name = NTLM
  -       server_name = /var/run/dovecot/auth-client
  -       server_setid = $auth1
  -
  -   If the SMTP connection is encrypted, or if $sender_host_address is equal to
  -   $interface_address (that is, the connection is local), the "secured" option
  -   is passed in the Dovecot authentication command. If, for a TLS connection, a
  -   client certificate has been verified, the "valid-client-cert" option is
  -   passed.
  -
  -4. The variable $message_headers_raw provides a concatenation of all the
  -   messages's headers without any decoding. This is in contrast to
  -   $message_headers, which does RFC2047 decoding on the header contents.
  -
  -5. In a DNS black list, when the facility for restricting the matching IP
  -   values is used, the text from the TXT record that is set in $dnslist_text
  -   may not reflect the true reason for rejection. This happens when lists are
  -   merged and the IP address in the A record is used to distinguish them;
  -   unfortunately there is only one TXT record. One way round this is not to use
  -   merged lists, but that can be inefficient because it requires multiple DNS
  -   lookups where one would do in the vast majority of cases when the host of
  -   interest is not on any of the lists.
  -
  -   A less inefficient way of solving this problem has now been implemented. If
  -   two domain names, comma-separated, are given, the second is used first to do
  -   an initial check, making use of any IP value restrictions that are set. If
  -   there is a match, the first domain is used, without any IP value
  -   restrictions, to get the TXT record. As a byproduct of this, there is also a
  -   check that the IP being tested is indeed on the first list. The first domain
  -   is the one that is put in $dnslist_domain. For example:
  -
  -     reject message  = rejected because $sender_ip_address is blacklisted \
  -                       at $dnslist_domain\n$dnslist_text
  -            dnslists = sbl.spamhaus.org,sbl-xbl.spamhaus.org=127.0.0.2 : \
  -                       dul.dnsbl.sorbs.net,dnsbl.sorbs.net=127.0.0.10
  -
  -   For the first blacklist item, this starts by doing a lookup in
  -   sbl-xbl.spamhaus.org and testing for a 127.0.0.2 return. If there is a
  -   match, it then looks in sbl.spamhaus.org, without checking the return value,
  -   and as long as something is found, it looks for the corresponding TXT
  -   record. If there is no match in sbl-xbl.spamhaus.org, nothing more is done.
  -   The second blacklist item is processed similarly.
  -
  -   If you are interested in more than one merged list, the same list must be
  -   given several times, but because the results of the DNS lookups are cached,
  -   the DNS calls themselves are not repeated. For example:
  -
  -     reject dnslists = http.dnsbl.sorbs.net,dnsbl.sorbs.net=127.0.0.2 : \
  -                      socks.dnsbl.sorbs.net,dnsbl.sorbs.net=127.0.0.3 : \
  -                       misc.dnsbl.sorbs.net,dnsbl.sorbs.net=127.0.0.4 : \
  + 1. ACL variables can now be given arbitrary names, as long as they start with
  +    "acl_c" or "acl_m" (for connection variables and message variables), are at
  +    least six characters long, with the sixth character being either a digit or
  +    an underscore. The rest of the name can contain alphanumeric characters and
  +    underscores. This is a compatible change because the old set of variables
  +    such as acl_m12 are a subset of the allowed names. There may now be any
  +    number of ACL variables. For example:
  +
  +      set acl_c13   = value for original ACL variable
  +      set acl_c13b  = whatever
  +      set acl_m_foo = something
  +
  +    What happens if a syntactically valid but undefined ACL variable is
  +    referenced depends on the setting of the strict_acl_vars option. If it is
  +    false (the default), an empty string is substituted; if it is true, an
  +    error is generated. This affects all ACL variables, including the "old"
  +    ones such as acl_c4. (Previously there wasn't the concept of an undefined
  +    ACL variable.)
  +
  +    The implementation has been done in such a way that spool files containing
  +    ACL variable settings written by previous releases of Exim are compatible
  +    and can be read by the new release. If only the original numeric names are
  +    used, spool files written by the new release can be read by earlier
  +    releases.
  +
  + 2. There is a new ACL modifier called log_reject_target. It makes it possible
  +    to specify which logs are used for messages about ACL rejections. Its
  +    argument is a list of words which can be "main", "reject", or "panic". The
  +    default is "main:reject". The list may be empty, in which case a rejection
  +    is not logged at all. For example, this ACL fragment writes no logging
  +    information when access is denied:
  +
  +      deny <some conditions>
  +           log_reject_target =
  +
  +    The modifier can be used in SMTP and non-SMTP ACLs. It applies to both
  +    permanent and temporary rejections.
  +
  + 3. There is a new authenticator called "dovecot". This is an interface to the
  +    authentication facility of the Dovecot POP/IMAP server, which can support a
  +    number of authentication methods. If you are using Dovecot to authenticate
  +    POP/IMAP clients, it might be helpful to use the same mechanisms for SMTP
  +    authentication. This is a server authenticator only. The only option is
  +    server_socket, which must specify the socket which is the interface to
  +    Dovecot authentication. The public_name option must specify an
  +    authentication mechanism that Dovecot is configured to support. You can
  +    have several authenticators for different mechanisms. For example:
  +
  +      dovecot_plain:
  +        driver = dovecot
  +        public_name = PLAIN
  +        server_name = /var/run/dovecot/auth-client
  +        server_setid = $auth1
  +
  +      dovecot_ntlm:
  +        driver = dovecot
  +        public_name = NTLM
  +        server_name = /var/run/dovecot/auth-client
  +        server_setid = $auth1
  +
  +    If the SMTP connection is encrypted, or if $sender_host_address is equal to
  +    $interface_address (that is, the connection is local), the "secured" option
  +    is passed in the Dovecot authentication command. If, for a TLS connection,
  +    a client certificate has been verified, the "valid-client-cert" option is
  +    passed.
  +
  + 4. The variable $message_headers_raw provides a concatenation of all the
  +    messages's headers without any decoding. This is in contrast to
  +    $message_headers, which does RFC2047 decoding on the header contents.
  +
  + 5. In a DNS black list, when the facility for restricting the matching IP
  +    values is used, the text from the TXT record that is set in $dnslist_text
  +    may not reflect the true reason for rejection. This happens when lists are
  +    merged and the IP address in the A record is used to distinguish them;
  +    unfortunately there is only one TXT record. One way round this is not to
  +    use merged lists, but that can be inefficient because it requires multiple
  +    DNS lookups where one would do in the vast majority of cases when the host
  +    of interest is not on any of the lists.
  +
  +    A less inefficient way of solving this problem has now been implemented. If
  +    two domain names, comma-separated, are given, the second is used first to
  +    do an initial check, making use of any IP value restrictions that are set.
  +    If there is a match, the first domain is used, without any IP value
  +    restrictions, to get the TXT record. As a byproduct of this, there is also
  +    a check that the IP being tested is indeed on the first list. The first
  +    domain is the one that is put in $dnslist_domain. For example:
  +
  +      reject message  = rejected because $sender_ip_address is blacklisted \
  +                        at $dnslist_domain\n$dnslist_text
  +             dnslists = sbl.spamhaus.org,sbl-xbl.spamhaus.org=127.0.0.2 : \
                           dul.dnsbl.sorbs.net,dnsbl.sorbs.net=127.0.0.10


  -   In this case there is a lookup in dnsbl.sorbs.net, and if none of the IP
  -   values matches (or if no record is found), this is the only lookup that is
  -   done. Only if there is a match is one of the more specific lists consulted.
  -
  -6. All authenticators now have a server_condition option. Previously, only
  -   plaintext had this, and this has not changed: it must be set to the
  -   authenticator as a server. For the others, if server_condition is set, it is
  -   expanded if authentication is successful, and treated exactly as it is in
  -   plaintext. This can serve as a means of adding authorization to an
  -   authenticator.
  -
  -7. There is a new command-line option called -Mset. It is useful only in
  -   conjunction with -be (that is, when testing string expansions). It must be
  -   followed by a message id; Exim loads the given message from its spool before
  -   doing the expansions, thus setting message-specific variables such as
  -   $message_size and the header variables. The $recipients variable is
  -   available. This feature is provided to make it easier to test expansions
  -   that make use of these variables. However, Exim must be called by an admin
  -   user when -Mset is used.
  -
  -8. Another similar new command-line option is called -bem. It operates like -be
  -   except that it must be followed by the name of a file. For example:
  -
  -     exim -bem /tmp/testmessage
  -
  -   The file is read as a message (as if receiving a locally-submitted non-SMTP
  -   message) before any of the test expansions are done. Thus, message-specific
  -   variables such as $message_size and $h_from: are available. However, no
  -   Received: header is added to the message. If the -t option is set,
  -   recipients are read from the headers in the normal way, and are shown in the
  -   $recipients variable. Note that recipients cannot be given on the command
  -   line, because further arguments are taken as strings to expand (just like
  -   -be).
  -
  -9. When an address is delayed because of a 4xx response to a RCPT command, it
  -   is now the combination of sender and recipient that is delayed in subsequent
  -   queue runs until its retry time is reached. You can revert to the previous
  -   behavious, that is, delay the recipient independent of the sender, by
  -   setting address_retry_include_sender=false in the smtp transport. However,
  -   this can lead to problems with servers that regularly issue 4xx responses to
  -   RCPT commands.
  -
  +    For the first blacklist item, this starts by doing a lookup in
  +    sbl-xbl.spamhaus.org and testing for a 127.0.0.2 return. If there is a
  +    match, it then looks in sbl.spamhaus.org, without checking the return
  +    value, and as long as something is found, it looks for the corresponding
  +    TXT record. If there is no match in sbl-xbl.spamhaus.org, nothing more is
  +    done. The second blacklist item is processed similarly.
  +
  +    If you are interested in more than one merged list, the same list must be
  +    given several times, but because the results of the DNS lookups are cached,
  +    the DNS calls themselves are not repeated. For example:
  +
  +      reject dnslists = http.dnsbl.sorbs.net,dnsbl.sorbs.net=127.0.0.2 : \
  +                       socks.dnsbl.sorbs.net,dnsbl.sorbs.net=127.0.0.3 : \
  +                        misc.dnsbl.sorbs.net,dnsbl.sorbs.net=127.0.0.4 : \
  +                         dul.dnsbl.sorbs.net,dnsbl.sorbs.net=127.0.0.10
  +
  +    In this case there is a lookup in dnsbl.sorbs.net, and if none of the IP
  +    values matches (or if no record is found), this is the only lookup that is
  +    done. Only if there is a match is one of the more specific lists consulted.
  +
  + 6. All authenticators now have a server_condition option. Previously, only
  +    plaintext had this, and this has not changed: it must be set to the
  +    authenticator as a server. For the others, if server_condition is set, it
  +    is expanded if authentication is successful, and treated exactly as it is
  +    in plaintext. This can serve as a means of adding authorization to an
  +    authenticator.
  +
  + 7. There is a new command-line option called -Mset. It is useful only in
  +    conjunction with -be (that is, when testing string expansions). It must be
  +    followed by a message id; Exim loads the given message from its spool
  +    before doing the expansions, thus setting message-specific variables such
  +    as $message_size and the header variables. The $recipients variable is
  +    available. This feature is provided to make it easier to test expansions
  +    that make use of these variables. However, Exim must be called by an admin
  +    user when -Mset is used.
  +
  + 8. Another similar new command-line option is called -bem. It operates like
  +    -be except that it must be followed by the name of a file. For example:
  +
  +      exim -bem /tmp/testmessage
  +
  +    The file is read as a message (as if receiving a locally-submitted non-SMTP
  +    message) before any of the test expansions are done. Thus, message-specific
  +    variables such as $message_size and $h_from: are available. However, no
  +    Received: header is added to the message. If the -t option is set,
  +    recipients are read from the headers in the normal way, and are shown in
  +    the $recipients variable. Note that recipients cannot be given on the
  +    command line, because further arguments are taken as strings to expand
  +    (just like -be).
  +
  + 9. When an address is delayed because of a 4xx response to a RCPT command, it
  +    is now the combination of sender and recipient that is delayed in
  +    subsequent queue runs until its retry time is reached. You can revert to
  +    the previous behavious, that is, delay the recipient independent of the
  +    sender, by setting address_retry_include_sender=false in the smtp
  +    transport. However, this can lead to problems with servers that regularly
  +    issue 4xx responses to RCPT commands.
  +
  +10. Unary negation and the bitwise logical operators and, or, xor, not, and
  +    shift, have been added to the eval: and eval10: expansion items. These
  +    items may now contain arithmetic operators (plus, minus, times, divide,
  +    remainder, negate), bitwise operators (and, or, xor, not, shift), and
  +    parentheses. All operations are carried out using signed integer
  +    arithmetic. Operator priorities are as in C, namely:
  +
  +      (highest) not, negate
  +                times, divide, remainder
  +                plus, minus
  +                shift-left, shift-right
  +                and
  +                xor
  +      (lowest)  or
  +
  +    Binary operators with the same priority are evaluated from left to right.
  +    For example:
  +
  +      ${eval:1+1}            yields 2
  +      ${eval:1+2*3}          yields 7
  +      ${eval:(1+2)*3}        yields 9
  +      ${eval:2+42%5}         yields 4
  +      ${eval:0xc&5}          yields 4
  +      ${eval:0xc|5}          yields 13
  +      ${eval:0xc^5}          yields 9
  +      ${eval:0xc>>1}         yields 6
  +      ${eval:0xc<<1}         yields 24
  +      ${eval:~255&0x1234}    yields 4608
  +      ${eval:-(~255&0x1234)} yields -4608



Version 4.63

  Index: ACKNOWLEDGMENTS
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/ACKNOWLEDGMENTS,v
  retrieving revision 1.62
  retrieving revision 1.63
  diff -u -r1.62 -r1.63
  --- ACKNOWLEDGMENTS    31 Oct 2006 11:14:18 -0000    1.62
  +++ ACKNOWLEDGMENTS    13 Nov 2006 11:26:37 -0000    1.63
  @@ -1,4 +1,4 @@
  -$Cambridge: exim/exim-src/ACKNOWLEDGMENTS,v 1.62 2006/10/31 11:14:18 ph10 Exp $
  +$Cambridge: exim/exim-src/ACKNOWLEDGMENTS,v 1.63 2006/11/13 11:26:37 ph10 Exp $


EXIM ACKNOWLEDGEMENTS

@@ -20,7 +20,7 @@
Philip Hazel

Lists created: 20 November 2002
-Last updated: 31 October 2006
+Last updated: 13 November 2006


   THE OLD LIST
  @@ -173,6 +173,7 @@
                             Patch for -Mset
   Bob Johannessen           Patch for Sieve envelope tests bug
                             Patch for negative uid/gid bug
  +Brad Jorsch               Patch for bitwise logical operators
   Christian Kellner         Patch for LDAP dereferencing
   Alex Kiernan              Patches for libradius
                             Diagnosis of milliwait clock-backwards bug


  Index: expand.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/expand.c,v
  retrieving revision 1.68
  retrieving revision 1.69
  diff -u -r1.68 -r1.69
  --- expand.c    31 Oct 2006 14:26:34 -0000    1.68
  +++ expand.c    13 Nov 2006 11:26:37 -0000    1.69
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/expand.c,v 1.68 2006/10/31 14:26:34 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/expand.c,v 1.69 2006/11/13 11:26:37 ph10 Exp $ */


   /*************************************************
   *     Exim - an Internet mail transport agent    *
  @@ -2719,63 +2719,53 @@
   *          Evaluate numeric expression           *
   *************************************************/


-/* This is a set of mutually recursive functions that evaluate a simple
-arithmetic expression involving only + - * / and parentheses. The only one that
-is called from elsewhere is eval_expr, whose interface is:
+/* This is a set of mutually recursive functions that evaluate an arithmetic
+expression involving + - * / % & | ^ ~ << >> and parentheses. The only one of
+these functions that is called from elsewhere is eval_expr, whose interface is:

   Arguments:
  -  sptr          pointer to the pointer to the string - gets updated
  -  decimal       TRUE if numbers are to be assumed decimal
  -  error         pointer to where to put an error message - must be NULL on input
  -  endket        TRUE if ')' must terminate - FALSE for external call
  +  sptr        pointer to the pointer to the string - gets updated
  +  decimal     TRUE if numbers are to be assumed decimal
  +  error       pointer to where to put an error message - must be NULL on input
  +  endket      TRUE if ')' must terminate - FALSE for external call


  -
  -Returns:        on success: the value of the expression, with *error still NULL
  -                on failure: an undefined value, with *error = a message
  +Returns:      on success: the value of the expression, with *error still NULL
  +              on failure: an undefined value, with *error = a message
   */


-static int eval_sumterm(uschar **, BOOL, uschar **);
+static int eval_op_or(uschar **, BOOL, uschar **);
+

   static int
   eval_expr(uschar **sptr, BOOL decimal, uschar **error, BOOL endket)
   {
   uschar *s = *sptr;
  -int x = eval_sumterm(&s, decimal, error);
  +int x = eval_op_or(&s, decimal, error);
   if (*error == NULL)
     {
  -  while (*s == '+' || *s == '-')
  +  if (endket)
       {
  -    int op = *s++;
  -    int y = eval_sumterm(&s, decimal, error);
  -    if (*error != NULL) break;
  -    if (op == '+') x += y; else x -= y;
  -    }
  -  if (*error == NULL)
  -    {
  -    if (endket)
  -      {
  -      if (*s != ')')
  -        *error = US"expecting closing parenthesis";
  -      else
  -        while (isspace(*(++s)));
  -      }
  -    else if (*s != 0) *error = US"expecting + or -";
  +    if (*s != ')')
  +      *error = US"expecting closing parenthesis";
  +    else
  +      while (isspace(*(++s)));
       }
  +  else if (*s != 0) *error = US"expecting operator";
     }
  -
   *sptr = s;
   return x;
   }


  +
   static int
  -eval_term(uschar **sptr, BOOL decimal, uschar **error)
  +eval_number(uschar **sptr, BOOL decimal, uschar **error)
   {
   register int c;
   int n;
   uschar *s = *sptr;
   while (isspace(*s)) s++;
   c = *s;
  -if (isdigit(c) || ((c == '-' || c == '+') && isdigit(s[1])))
  +if (isdigit(c))
     {
     int count;
     (void)sscanf(CS s, (decimal? "%d%n" : "%i%n"), &n, &count);
  @@ -2798,16 +2788,38 @@
   return n;
   }


  -static int eval_sumterm(uschar **sptr, BOOL decimal, uschar **error)
  +
  +static int eval_op_unary(uschar **sptr, BOOL decimal, uschar **error)
  +{
  +uschar *s = *sptr;
  +int x;
  +while (isspace(*s)) s++;
  +if (*s == '+' || *s == '-' || *s == '~')
  +  {
  +  int op = *s++;
  +  x = eval_op_unary(&s, decimal, error);
  +  if (op == '-') x = -x;
  +    else if (op == '~') x = ~x;
  +  }
  +else
  +  {
  +  x = eval_number(&s, decimal, error);
  +  }
  +*sptr = s;
  +return x;
  +}
  +
  +
  +static int eval_op_mult(uschar **sptr, BOOL decimal, uschar **error)
   {
   uschar *s = *sptr;
  -int x = eval_term(&s, decimal, error);
  +int x = eval_op_unary(&s, decimal, error);
   if (*error == NULL)
     {
     while (*s == '*' || *s == '/' || *s == '%')
       {
       int op = *s++;
  -    int y = eval_term(&s, decimal, error);
  +    int y = eval_op_unary(&s, decimal, error);
       if (*error != NULL) break;
       if (op == '*') x *= y;
         else if (op == '/') x /= y;
  @@ -2818,6 +2830,105 @@
   return x;
   }


  +
  +static int eval_op_sum(uschar **sptr, BOOL decimal, uschar **error)
  +{
  +uschar *s = *sptr;
  +int x = eval_op_mult(&s, decimal, error);
  +if (*error == NULL)
  +  {
  +  while (*s == '+' || *s == '-')
  +    {
  +    int op = *s++;
  +    int y = eval_op_mult(&s, decimal, error);
  +    if (*error != NULL) break;
  +    if (op == '+') x += y; else x -= y;
  +    }
  +  }
  +*sptr = s;
  +return x;
  +}
  +
  +
  +static int eval_op_shift(uschar **sptr, BOOL decimal, uschar **error)
  +{
  +uschar *s = *sptr;
  +int x = eval_op_sum(&s, decimal, error);
  +if (*error == NULL)
  +  {
  +  while ((*s == '<' || *s == '>') && s[1] == s[0])
  +    {
  +    int y;
  +    int op = *s++;
  +    s++;
  +    y = eval_op_sum(&s, decimal, error);
  +    if (*error != NULL) break;
  +    if (op == '<') x <<= y; else x >>= y;
  +    }
  +  }
  +*sptr = s;
  +return x;
  +}
  +
  +
  +static int eval_op_and(uschar **sptr, BOOL decimal, uschar **error)
  +{
  +uschar *s = *sptr;
  +int x = eval_op_shift(&s, decimal, error);
  +if (*error == NULL)
  +  {
  +  while (*s == '&')
  +    {
  +    int y;
  +    s++;
  +    y = eval_op_shift(&s, decimal, error);
  +    if (*error != NULL) break;
  +    x &= y;
  +    }
  +  }
  +*sptr = s;
  +return x;
  +}
  +
  +
  +static int eval_op_xor(uschar **sptr, BOOL decimal, uschar **error)
  +{
  +uschar *s = *sptr;
  +int x = eval_op_and(&s, decimal, error);
  +if (*error == NULL)
  +  {
  +  while (*s == '^')
  +    {
  +    int y;
  +    s++;
  +    y = eval_op_and(&s, decimal, error);
  +    if (*error != NULL) break;
  +    x ^= y;
  +    }
  +  }
  +*sptr = s;
  +return x;
  +}
  +
  +
  +static int eval_op_or(uschar **sptr, BOOL decimal, uschar **error)
  +{
  +uschar *s = *sptr;
  +int x = eval_op_xor(&s, decimal, error);
  +if (*error == NULL)
  +  {
  +  while (*s == '|')
  +    {
  +    int y;
  +    s++;
  +    y = eval_op_xor(&s, decimal, error);
  +    if (*error != NULL) break;
  +    x |= y;
  +    }
  +  }
  +*sptr = s;
  +return x;
  +}





  Index: 0002
  ===================================================================
  RCS file: /home/cvs/exim/exim-test/scripts/0000-Basic/0002,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- 0002    31 Oct 2006 14:26:34 -0000    1.7
  +++ 0002    13 Nov 2006 11:26:37 -0000    1.8
  @@ -67,6 +67,20 @@
   eval:   ${eval:08}
   eval10: ${eval10:077}
   eval10: ${eval10:08}
  +eval10: ${eval10:0x1234}
  +eval:   ${eval:2+42%5}
  +eval:   ${eval:0xc&5}          
  +eval:   ${eval:0xc & 5 }          
  +eval:   ${eval:0x0c|5}          
  +eval:   ${eval:0xc^5}          
  +eval:   ${eval:0xc>>1}         
  +eval:   ${eval:0xc >> 2}         
  +eval:   ${eval:0xc >> 4 }         
  +eval:   ${eval:0xc<<1}         
  +eval:   ${eval:~255&0x1234}    
  +eval:   ${eval:~ 255&0x1234}    
  +eval:   ${eval: -(~255&0x1234)} 
  +
   expand: \$primary_hostname ${expand:\$primary_hostname}
   hash:   ${hash_3:monty} ${hash_5:monty} ${hash_4_62:monty python}
   hash:   ${hash_3:abc}X ${hash_3:ab}X ${hash_3:a}X ${hash_3:}X


  Index: 0002
  ===================================================================
  RCS file: /home/cvs/exim/exim-test/stdout/0002,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- 0002    31 Oct 2006 14:26:34 -0000    1.7
  +++ 0002    13 Nov 2006 11:26:37 -0000    1.8
  @@ -48,15 +48,29 @@
   > eval:   1
   > eval:   1
   > Failed: error in expression evaluation: expecting closing parenthesis (after processing "-2 - (-3")
  -> Failed: error in expression evaluation: expecting + or - (after processing "-2 - -3")
  +> Failed: error in expression evaluation: expecting operator (after processing "-2 - -3")
   > eval:   1
   > eval:   -5
  -> Failed: error in expression evaluation: expecting number or opening parenthesis (after processing "-2 -")
  +> eval:   1
   > eval:   40962
   > eval:   63
  -> Failed: error in expression evaluation: expecting + or - (after processing "0")
  +> Failed: error in expression evaluation: expecting operator (after processing "0")
   > eval10: 77
   > eval10: 8
  +> Failed: error in expression evaluation: expecting operator (after processing "0")
  +> eval:   4
  +> eval:   4
  +> eval:   4
  +> eval:   13
  +> eval:   9
  +> eval:   6
  +> eval:   3
  +> eval:   0
  +> eval:   24
  +> eval:   4608
  +> eval:   4608
  +> eval:   -4608
  +> 
   > expand: $primary_hostname myhost.test.ex
   > hash:   jmg monty fbWx
   > hash:   abcX abX aX X