Lately, I have got many doubts from people trying to understand the logic behind time conditions. So, I will try in this article to explain it. Let us start with some basic ideas: a) FusionPBX is only a frontend of FreeSWITCH, do not forget this, as all the dial plan magic happens inside FreeSWITCH; b) as for FreeSWITCH eyes', the concept of time condition do not exist, it is just another dial plan with some condition based on the time.
With all this said, I will start explaining.
The XML Dialplan and its Conditions
FreeSWITCH XML representation of a dial plan is as basic as follows:
<extension name='SOME_NAME' SOME_OTHER_LABELS>
This is a very simple example. There are other that are far way more complex, but for explaining the logic, this simple skeleton will do it. What it is important here is the logic: if the conditions are met, then the action tag is executed, otherwise, the anti-action tag takes place if it exists.
FreeSWITCH gets the dial plans set through FusionPBX Lua XML Handler and it starts evaluating each one. If the condition hits, the action tags take place. FusionPBX XML representation is more friendly. Here it is an example:
This is a common example of a FusionPBX Outbound Route. What it is important here is the dial plan processing; ALL, I repeat ALL the conditions must meet in order to execute the action tags. It is a logic AND; if one of them is not met, then the anti-action tag will take place (if it exists). If there are anti-action tags in place, FreeSWITCH will continue or not the missing dial plans evaluation depending on the continue label.
FreeSWITCH support nested dial plans. This kind of dial plans is used to make complex decisions. If you know C or PHP coding, you can see it as a switch/case direction or a cascade of if-then-else. FusionPBX uses them, the use case it comes to my mind right away is the user_record dial plan.
As you can see, there are subsets inside the dial plan. FusionPBX uses the group column to make this happens. The important thing here is that logic inside the nested dial plans (subsets) is different. FreeSWITCH will evaluate all of them, and it will stop if one of the following conditions is met:
- A subset condition fails, and it has the break label set to a value different than always or null.
- A subset condition hits and there is an instruction that starts a session, for example transferring to an IVR
In the user_record dial plan, all actions are SET. Therefore, the FreeSWITCH will continue the evaluation and execution of the subsequent subsets regardless if the first has hit. Stay with me on this, Time Conditions in FusionPBX 4.2+ are somehow similar with this.
Then, and just to remember, a time condition is just an XML dial plan. FreeSWITCH wiki has the time condition well documented. I do not need to write them again.
In FusionPBX 4.0 it was very straight forward, but for a reason, the author of the project decided to rewrite it and make it far way more complex from 4.1 (devel) at some point. The following image is how the time conditions looked:
Look at it, it is almost identical to any dial plan. Now let us give a look to the modern time conditions in FusionPBX 4.2.
The logic on the new Dialplans is a general OR with a short circuit. It will evaluate each time condition and execute the first that hits.
A short circuit is very handy when evaluating OR conditions. Let us say we have condition-1 OR condition-2 OR condition-3, if condition-1 is true, you do not need to continue the evaluation of the rest as it is true anyway, regardless the result of the others.
A Bug or a Bad Design?
If you see the XML representation of the new Time Condition App, you will see it uses nested dial plans (groups) to make this work. It took away the anti-action tags and it allowed to put together more than one similar condition. This will help you not to have a time condition per holiday, you can have them all in one.
However, there is a price to pay. Because of the use of groups (subsets), it has the same behavior explained in the user_record dial plan. FreeSWITCH will continue the evaluation of each subset if the conditions already stated are met.
For most people, this will work, as you always do a transfer to an extension, a ring group or an IVR. They start a session. But if you need to pass to a more complex condition, such an LUA script that it does not start a session, FreeSWITCH will continue the evaluation and it is almost likely that the alternate destination will hit, as it doesn't have any other condition but the dialed number (which it is already met). For example, look the following conditions:
If this is executed the January 27th, the bday.lua script will be executed. Only God and I know what that script does. But if that script does not start a session (aka do a transfer or a bridge), the last condition (alternate condition) that points to *411 will be executed. Therefore, it is not an if-then-else logic, it is an inclusive OR logic that turns on/off the short circuit logic. Do not forget this.
In my view, there is not an easy way to fix this without rewriting the logic of the current Time Condition application.
An easy workaround is not using alternate destination, and let another dial plan catch the action. You can also edit by hand the dial plan and add a second action, like a hang up after the LUA script execution is done.
Good luck!blog comments powered by Disqus