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)
exten => 101,n,GotoIf($["${DIALSTATUS}" = "BUSY"]?busy:unavail)
exten => 101,n(unavail),Voicemail(101@default,u)
exten => 101,n,Hangup()
exten => 101,n(busy),VoiceMail(101@default,b)
exten => 101,n,Hangup()
Now imagine you have a hundred users on your
Asterisk
system—setting
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 worry—we'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
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
almost
identically
to
anything
else in
the
dialplan;
the 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)
exten => s,n,GotoIf($["${DIALSTATUS}" = "BUSY"]?busy:unavail)
exten => s,n(unavail),Voicemail(101@default,u)
exten => s,n,Hangup()
exten => s,n(busy),VoiceMail(101@default,b)
exten => s,n,Hangup()
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 of
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
hardcoded
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, and
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)
exten => s,n,GotoIf($["${DIALSTATUS}" = "BUSY"]?busy:unavail)
exten => s,n(unavail),Voicemail(${MACRO_EXTEN}@default,u)
exten => s,n,Hangup()
exten => s,n(busy),VoiceMail(${MACRO_EXTEN}@default,b)
exten => s,n,Hangup()
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
change;
we need
to pass
in the
channel
to dial,
as it's
currently
still
hardcoded
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)
exten => s,n,GotoIf($["${DIALSTATUS}" = "BUSY"]?busy:unavail)
exten => s,n(unavail),Voicemail(${MCARO_EXTEN}@default,u)
exten => s,n,Hangup()
exten => s,n(busy),VoiceMail(${MCARO_EXTEN}@default,b)
exten => s,n,Hangup()
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
organized;
we'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,n,Goto(s-${DIALSTATUS},1)
exten => s-NOANSWER,1,Voicemail(${MACRO_EXTEN},u)
exten => s-NOANSWER,n,Goto(incoming,s,1)
exten => s-BUSY,1,Voicemail(${MACRO_EXTEN},b)
exten => s-BUSY,n,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