asterisk dialplan peculiarities / regex with eqtilde
In the Asterisk PBX dialplan, expressions can be formed using the
$[...]
syntax. Addition, subtraction, comparison and so on are
defined. As is a regex operator: =~
Unfortunately, the documentation about the details of the implementation is hard to find.
Here, a breakdown of my findings:
static struct val * op_eqtilde
is defined inmain/ast_expr2.y
- It uses the
REG_EXTENDED
flag when callingregcomp
: so extended regular expression syntax is used. - The
REG_ICASE
flag is NOT used: case sensitive. - If you don’t use parentheses (substring addressing) the returned
value is the amount of characters that match:
rm[0].rm_eo - rm[0].rm_so
- If you do use parentheses, the returned value is the content of the
outermost substring match: slice of original between
rm[1].rm_so
andrm[1].rm_eo
That last bit can cause a bit of trouble. For example, you would think that the following two statements are equivalent.
exten => 333,1,Hangup(${IF($["${HANGUPCAUSE}"=~"^0$|^27$|^29$|^34$|^38$|^42$|^66$"]?${HANGUPCAUSE}:USER_BUSY)})
...and...
exten => 333,1,Hangup(${IF($["${HANGUPCAUSE}"=~"^(0|27|29|34|38|42|66)$"]?${HANGUPCAUSE}:USER_BUSY)})
They aren’t. The latter one will give you an error and a Hangup()
with
an empty argument when ${HANGUPCAUSE}
falls outside the listed values,
because the value returned to IF()
is empty.
func_logic.c: Syntax IF(<expr>?[<true>][:<false>]) (expr must be non-null, and either <true> or <false> must be non-null)
func_logic.c: In this case, <expr>='', <true>='USER_BUSY', and <false>='0'
pbx.c: -- Executing [333@context:1] Hangup("SIP/somewhere", "") in new stack
The easy fix: add a LEN()
. It’ll look better than the first priority
(extension rule) shown.
exten => 333,1,Hangup(${IF(${LEN($["${HANGUPCAUSE}"=~"^(0|27|29|34|38|42|66)$"])}?${HANGUPCAUSE}:USER_BUSY)})