12 min read

When calls come into the switch, we tell Asterisk step-by-step how to handle the call. Steps can be as simple as playing a sound file to running a customized script. We are limited mostly by our imaginations at this point.

We define all the steps we want Asterisk to perform in our extensions.conf file, in the customary location /etc/asterisk. Before we begin, we need to set priorityjumping=yes in the [general] section of extensions.conf. This will allow the tips and tricks in this article to work with Asterisk 1.6.x.

Creating a context

What is a context? Simply said, a context is a group of extensions. Each extension must exist within a context. There is more to contexts than grouping extensions though. In our extensions.conf file (or any included files), a context is denoted by square brackets “[ ]”, as shown:

[mycontext]
. . .

So, if a context is a group of extensions, why do we need more than one? Let’s think for a minute. Not all employees should be able to dial every phone. Would you trust your 16-year-old intern with the ability to dial international calls? I wouldn’t. Also, do you want your president to be bothered by customers in the waiting room who use a courtesy phone and misdial? We could find that hazardous to our continued employment.

Certain extensions are hidden or made inaccessible from other extensions by context. This gives us some level of security. It also allows us to host multiple phone systems on a single server.

Imagine you have two businesses on the same phone system, each with only two handsets. It’d be a pain to have each dial four digits to reach the other handset. We can use contexts to treat each company as if it were on a separate server.

Something very important about contexts is we can include other contexts through the use of the include directive. This means all extensions in an included context are available. The value of this may not be immediately apparent, but soon we will see the full power of this tool.

Suppose we have some context named bob. If we wanted bob to include default, then we would have the following in our extensions.conf:

[bob]
include => default

This single line placed in any context gives that context the ability to dial any extension in the default context, as well as all contexts included in the default context. This means that if the default context included the foo context, then anybody in the bob context could dial extensions in the foo context.

Suppose we had the following in our extensions.conf file:

[foo]
exten => 1,1,Playback(tt-monkeys)
include => bar
[bar]
exten => 1,1,Playback(tt-weasels)

Now I know that we haven’t yet discussed the definition of extensions. That’s OK. All we need to know is that extension 1 in foo will play back a file that sounds like monkeys, and extension 1 in bar will play back a file that says, “weasels have taken over our phone system”.

If we are in context foo and press 1, which file will play? This shows us the danger of include. We should be careful not to include multiple matches for the same extension. If we do include multiple contexts, the first included context with a match will win. Consider the following file:

[foobar1]
include => foo
include => bar
[foobar2]
include => bar
include => foo

If we are in context foobar1 and press 1, we will hear monkeys, while if we are in context foobar2 and press 1, we will hear weasels. While this can trip the unwary, we will use it to our advantage later on.

Creating an extension

We all have a good idea about what an extension is. On our legacy PBX, each handset was an extension. Pretty simple, right?

While conceptually simple, there is a little wrinkle. If all we want to do is provide a few handsets, then there’s one extension per phone. But Asterisk can do much more! We need to think of an extension as a group of commands that tells Asterisk to do some things. As amorphous as that may be, it’s true.

An extension can be tied to one handset, a queue, groups of handsets, or voicemail. An extension can be attributed to many different areas of the system. If you’re familiar with programming terms, perhaps you could say that extensions are polymorphic.

To go further, extensions can be used to provide access to other applications, sound files, or other services of Asterisk. Extensions are important to the magic of Asterisk.

Now that we know why we create extensions, let’s think about how we create them. Again, they are in the extensions.conf file, or any files that you include from there.

We may decide to break up files such as extensions.conf into multiple configuration files. A common example of this is when we create large groups of extensions and choose to give each its own file. This also applies to the other configuration files we use.

The general format for a line in the extensions.conf file is:

exten => extensionnum,priority,action

Let’s take a closer look. Each line begins with the command exten. This is a directive inside Asterisk. You do not change this for each extension.

Next, we have the extension number. Each extension has a unique number. This number is how Asterisk knows which set of commands to run. This extension can be detected in three major ways. First, the phone company may send it in with the calls, as is the case with DID numbers. Users can enter an extension using their touch-tone keys. Finally, there are a few special extensions defined. Some of these are:

  • s: start extension. If no other extension number is entered, then this is the extension to execute.
  • t: timeout extension. If a user is required to give input, but does not do so quickly enough, this is the extension that will be executed.
  • i: invalid extension . If a user enters an extension that is not valid, this is the extension that will be executed.
  • fax: fax calls. If Asterisk detects a fax, the call will be rerouted to this extension.

Then we have the priority. Asterisk will start at priority 1 by default, complete the requested command, and then proceed to priority n+1. Some commands can force Asterisk to jump to priority n+101, allowing us to route based on decisions, such as if the phone is busy.

Finally, we have the action. This is where we tell Asterisk what we want to do. Some of the more common actions we may want to perform are:

  • Answer: This accepts the call. Many applications require that the call be answered before they can run as expected.
  • Playback(filename): This command plays a file in .wav or .gsm format. It is important to note that the call must be answered before playing.
  • Background(filename): This command is like Playback, except that it listens for input from the user. It too requires that the call be answered first.
  • Goto(context,extension,priority): Here, we send the call to the specified context, extension, and priority. While useful, this can be a bad style, as it can be very confusing to us if something goes wrong. However, it can be a good style if it keeps us from duplicating extension definitions, as moves, adds, or changes would only have to be updated in one place.
  • Queue(queuename|options): This command does what it seems like it should. It places the current call in the queue, which we should have already defined in the queues.conf file.
  • Voicemail(extension): This transfers the current call to the voicemail application. There are some special options as well. If we preceed the extension with the letter s, it skips the greeting. When we place the letter u before the extension, it uses the unavailable greeting, and b uses the busy greeting.
  • VoicemailMain: This application allows users to listen to their messages, and also record their greetings and name, and set other configuration options.
  • Dial(technology/id,options,timeout): This is where we tell Asterisk to make the phone ring, and when the line is answered, to bridge the call. Common options include:
    • t: Allow the called user to transfer the call by pressing the # key.
    • T: Allow the calling user to transfer the call by pressing the # key.
    • r: Indicate ringing to the calling party.
    • m: Provide music on hold to the calling party.
    • H: Allow the calling party to hang up by pressing the * key.
    • g: Go on in the context if the destination hangs up.

While this list is not exhaustive, it should be enough to get us started. Suppose we just want to make a DAHDI phone ring, which is on interface 1, and we are going to work completely in the default context. Our extensions.conf file would look like:

[default]
exten => s,1,Dial(dahdi/1)

Pretty simple, right? Now, imagine we want to transfer to the voicemail of user 100 if someone is on the phone. As Dial sends you to priority n+101 when the line is busy or not available, all we have to do is define what we want to do. Our dialplan would look like:

[default]
exten => s,1,Dial(dahdi/1)
exten => s,102,Voicemail(b100)

Great! We have some of the functionality that users have come to expect. But are you happy yet? The problem is that a phone could ring for years before someone picks it up.

So, for our next exercise, suppose we want to transfer the call to voicemail when the phone is not answered in 30 seconds. So, obviously, we’re going to have to use the option in Dial to define a time-out. Our dialplan would have something like:

[default]
exten => s,1,Dial(dahdi/1|30)
exten => s,2,Voicemail(u100)
exten => s,102,Voicemail(b100)

All we’re doing is telling Asterisk how to handle the call, in a step-by-step way. It is important to think about all scenarios that a call can go through, and plan for them. Just to reiterate a point I made earlier, planning ahead will save us hours of debugging later.

Suppose we want to send anyone who is in a place where they shouldn’t be to user 0’s voicemail, which will be checked periodically by the receptionist.

[default]
exten => s,1,Dial(dahdi/1|30)
exten => s,2,Voicemail(u100)
exten => s,102,Voicemail(b100)
exten => i,1,Voicemail(s0)
exten => t,1,Voicemail(s0)

All right, we’re getting somewhere now! At least we know each call will be handled in some way. What about faxes? Suppose we have only one fax machine (or a centralized fax server) on DAHDI interface 2, then our dialplan should look similar to:

[default]
exten => s,1,Dial(dahdi/1|30)
exten => s,2,Voicemail(u100)
exten => s,102,Voicemail(b100)
exten => i,1,Voicemail(s0)
exten => t,1,Voicemail(s0)
exten => fax,1,Dial(dahdi/2)

Congratulations! We now have a working phone system. May be not the most interesting yet, but we’re making great progress. Don’t worry, our phone system will grow in features.

Now, to create a list of useful extensions, we need to define a set of commands for each handset we have. Suppose we have three SIP phone users—1001-1003, with extensions 1001-1003. Our default context would look like:

[default]
exten => 1001,1,Dial(SIP/1001|30)
exten => 1001,2,Voicemail(u1001)
exten => 1001,102,Voicemail(b1001)
exten => 1002,1,Dial(SIP/1002|30)
exten => 1002,2,Voicemail(u1002)
exten => 1002,102,Voicemail(b1002)
exten => 1003,1,Dial(SIP/1003|30)
exten => 1003,2,Voicemail(u1003)
exten => 1003,102,Voicemail(b1003)
exten => i,1,Voicemail(s0)
exten => t,1,Voicemail(s0)
exten => fax,1,Dial(dahdi/2)

For every extension we add, the length of extensions.conf will grow by four lines (three lines of code, and one line of whitespace). This is not very easy to read, and it is very easy to make mistakes. There has to be a better way, right? Of course there is!

We can use macros to define common actions. We will create a special macro context. The name of these contexts always starts with macro-. Suppose we want to call this one macro-normal. We would have:

[macro-normal]
exten => s,1,Dial(${ARG2}|30)
exten => s,2,Voicemail(u${ARG1})
exten => s,102,Voicemail(b${ARG1})

Now, to create the same three extensions, we would have:

exten => 1001,1,Macro(normal|1001|SIP/1001)
exten => 1002,1,Macro(normal|1002|SIP/1002)
exten => 1003,1,Macro(normal|1003|SIP/1003)

So now, each extension we add requires only one extra line in extensions.conf. This is much more efficient and less prone to errors. But what if we knew that any four-digit extension beginning with a 1 would be a normal, SIP extension?

Here it is time for us to discuss Asterisk’s powerful pattern-matching capabilities. We can define extensions with certain special wildcards in them, and Asterisk will match any extension that fits the description.

Using the underscore (_) character warns Asterisk that the extension number will include pattern matching. When matching patterns, the X character represents any number (0 to 9), the Z character will match the numbers 1 to 9, the N character represents numbers 2 to 9, and the period (.) represents a string of any number of digits.

Also, we can use certain variables in our dialplan. One such variable is ${EXTEN}, which represents the extension that was used.

So, for this example, we could use the following definition:

exten => _1XXX,1,Macro(normal|${EXTEN}|SIP/${EXTEN})

This one line of code has now defined 1000 extensions, from 1000 to 1999. All we have to do is ensure that our voicemail user, extension, and SIP user are all the same number. Pretty cool, huh?

Note that if we wish to modify the behavior of all extensions, all we have to do is modify the macro. This should help us quite a bit as we tweak Asterisk to fit our business needs.

LEAVE A REPLY

Please enter your comment!
Please enter your name here