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 in main/ast_expr2.y
  • It uses the REG_EXTENDED flag when calling regcomp: 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 and rm[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)})

asterisk log