6.5. Macros
Macros are a very useful construct designed to
avoid repetition in the dialplan. They also help in making changes
to the dialplan. To illustrate this point, let's look at our sample
dialplan again. If you remember the changes we made for voicemail,
we ended up with the following for John's extension:
exten => 101,1,Dial(${JOHN},10,r)
exten => 101,2,VoiceMail(u101@default)
exten => 101,102,VoiceMail(b101@default)
Now imagine you have a hundred users on your
Asterisk systemsetting up the extensions would involve a lot of
copying and pasting. Then imagine that you need to make a change to
the way your extensions work. That would involve a lot of editing,
and you'd be almost certain to have errors.
Instead, you can define a macro that contains a
list of steps to take, and then have all of the phone extensions
refer to that macro. All you need to change is the macro, and
everything in the dialplan that references that macro will change
as well.
|
If you're familiar with computer programming,
you'll recognize that macros are similar to subroutines in many modern
programming languages. If you're not familiar with computer
programming, don't worrywe'll walk you through creating a
macro.
|
|
The best way to appreciate macros is to see one
in action, so let's move right along.
6.5.1. Defining Macros
For our first macro, let's take the dialplan
logic we used above to set up voicemail for John and turn it into a
macro. Then we'll use the macro to give John and Jane (and the rest
of their coworkers) the same functionality.
Macro definitions look a lot like contexts. (In
fact, you could argue that they really are small, limited
contexts.) You define a macro by placing macro- and the
name of your macro in square brackets, like this:
[macro-voicemail]
Macro names must start with macro-.
This distinguishes them from regular contexts. The commands within
the macro are built pretty nearly identically to anything else in
the dialplanthe only limiting factor is that macros use only the
s extension. Let's add our voicemail logic to the macro,
changing the extension to s as we go:
[macro-voicemail]
exten => s,1,Dial(${JOHN},10,r)
exten => s,2,VoiceMail(u101@default)
exten => s,102,VoiceMail(b101@default)
That's a start, but it's not perfect, as it's
still specific to John and his mailbox number. To make the macro
generic so that it will work not only for John but also for all his
coworkers, we'll take advantage of another property of macros:
arguments. But first, let's see how we call macros in our
dialplan.
6.5.2. Calling Macros from the
Dialplan
To use a macro in our dialplan, we use the
Macro( ) application. This application calls the specified
macro and passes it any arguments. For example, to call our
voicemail macro from our dialplan, we can do the following:
exten => 101,1,Macro(voicemail)
The Macro( ) application also defines
several special variables for our use. They include:
${MACRO_CONTEXT}
-
The original context in which the macro was
called.
${MACRO_EXTEN}
-
The original extension in which the macro was
called.
${MACRO_PRIORITY}
-
The original priority in which the macro was
called.
${ARG n}
-
The nth argument passed to the
macro. For example, the first argument would be ${ARG1},
the second ${ARG2}, and so on.
As we explained earlier, the way we initially
defined our macro was hard-coded for John, instead of being
generic. Let's change our macro to use ${MACRO_EXTEN}
instead of 101 for the mailbox number. That way, if we
call the macro from extension 101 the voicemail messages will go to
mailbox 101, if we call the macro from extension 102 messages will
go to mailbox 102, and so on:
[macro-voicemail]
exten => s,1,Dial(${JOHN},10,r)
exten => s,2,VoiceMail(u${MACRO_EXTEN}@default)
exten => s,102,VoiceMail(b${MACRO_EXTEN}@default)
6.5.3. Using Arguments in Macros
Okay, now we're getting closer to having the
macro the way we want it, but we still have one thing left to
changewe need to pass in the channel to dial, as it's currently
still hard-coded for ${JOHN} (remember that we defined the
variable JOHN as the channel to call when we want to reach
John). Let's pass in the channel as an argument, and then our first
macro will be complete:
[macro-voicemail]
exten => s,1,Dial(${ARG1},10,r)
exten => s,2,VoiceMail(u${MACRO_EXTEN}@default)
exten => s,102,VoiceMail(b${MACRO_EXTEN}@default)
Now that our macro is done, we can use it in our
dialplan. Here's how we can call our macro to provide voicemail to
John, Jane, and Jack:
exten => 101,1,Macro(voicemail,${JOHN})
exten => 102,1,Macro(voicemail,${JANE})
exten => 103,1,Macro(voicemail,${JACK})
With 50 or more users, this dialplan will still
look neat and organizedwe'll simply have one line per user,
referencing a macro that can be as complicated as required. We
could even have a few different macros for various user types, such
as executives, courtesy_phones,
call_center_agents, analog_sets,
sales_department, and so on.
A more advanced version of the macro might look
something like this:
[macro-voicemail]
exten => s,1,Dial(${ARG1},20)
exten => s,2,Goto(s-${DIALSTATUS},1)
exten => s-NOANSWER,1,Voicemail(u${MACRO_EXTEN})
exten => s-NOANSWER,2,Goto(incoming,s,1)
exten => s-BUSY,1,Voicemail(b${MACRO_EXTEN})
exten => s-BUSY,2,Goto(incoming,s,1)
exten => _s-.,1,Goto(s-NOANSWER,1)
This macro depends on a nice side effect of the
Dial( ) application: when you use the Dial( )
application, it sets the DIALSTATUS variable to indicate
whether the call was successful or not. In this case, we're
handling the NOANSWER and BUSY cases, and
treating all other result codes as a NOANSWER. |