Chinaunix首页 | 论坛 | 博客
  • 博客访问: 195357
  • 博文数量: 31
  • 博客积分: 2595
  • 博客等级: 少校
  • 技术积分: 334
  • 用 户 组: 普通用户
  • 注册时间: 2008-07-28 16:03
个人简介

知行合一

文章分类

全部博文(31)

文章存档

2015年(1)

2014年(1)

2010年(9)

2009年(20)

我的朋友

分类: 系统运维

2010-05-04 21:38:29

注:以下文章如需转载,请注明所属作者,转载地址,谢谢!
 

AEL使用范例(AEL Example USAGE

注释(Comments

“//” 注释掉整行

注释符会被词法扫描器移出,但是在应用和表达式中的“//”不会被辨认出来。最安全的放置注释符的地方是在”;”后或在空行中

 

最新的语法,可以像C格式的注释一样

/* this is a

multiline comment that

makes little or no sense!

*/

上下文(Contexts

AEL中的上下文和extensions.conf中一样,都是分机(extensions)的集合。

context default {

 

}

上下文也可以被声明为“abstract”,在这种情况下,这种声明表现了作者的意图。这种上下文只用来被包含在另一个上下文中,不会单独使用(译者注:单独使用也是可以的)。目前这个关键字被用来防止“goto”语句被检查。

abstract context longdist {

     _1NXXNXXXXXX => NoOp(generic long distance dialing actions in the US);

}

分机(Extensions

要在上下文中指定分机,那么要使用下面的语法。如果在分机中不止一个应用被调用,那么可以按照顺序将它们列在一个块(block)中。

context default {

    1234 => Playback(tt-monkeys);

    8000 => {

         NoOp(one);

         NoOp(two);

         NoOp(three);

    };

    _5XXX => NoOp(it's a pattern!);

}

有两条可供选择的功能被添加进了AEL语法中,一条是描述,一条就是关键字匹配(本条功能会将该优先级强制变为2.

你可以使用‘/’和CID数字结合的方式来匹配CID,见下面的例子:

context default {

    regexten _5XXX => NoOp(it's a pattern!);

}

 

context default {

    hint(Sip/1) _5XXX => NoOp(it's a pattern!);

}

 

context default {

    regexten hint(Sip/1) _5XXX => NoOp(it's a pattern!);

}

如果两者要同时存在,那么必须将后者放在前者的前面。

CID匹配和extensions.conf一样。’/’后面的数字会匹配呼叫着的ID

context zoombo

{

  819/7079953345 => { NoOp(hello, 3345); }

}

上例中,如果呼叫着的ID7079953345,并且拨叫的号码是819,那么将进入这个分机中进行处理。

包含(Includes

上下文可以被包含在另外的上下文中。所有被包含的上下文要在一个单独的block中列出。

context default {

    includes {

         local;

         longdistance;

         international;

    }

}

也可以指定限制的时间,就像extensions.conf文件格式一样。

context default {

    includes {

         local;

         longdistance|16:00-23:59|mon-fri|*|*;

         international;

    }

}

包含文件(#include

你可以使用#include+“文件路径”的方式来包含其他的文件。

#include "/etc/asterisk/testfor.ael"

#include一个有意思的特点就是你可以在ael文件中的任何位置使用。甚至于在宏,上下文,分机中都可以包含其他文件。#include不必写在一行的开始处。被包含文件可以包含其他文件,可以达到50级。如果你提供的路径是相对路径,那么解析器会在配置文件的目录中去寻找包含的文件。(通常是/etc/asterisk

拨号方案switchDialplan Switch

Switch在上下文中被列在它们自己的block当中。使用它们的原因可以在asterisk-dual servers, 以及asterisk 配置文件extensions.conf中找到。

context default {

    switches {

         DUNDi/e164;

         IAX2/box5;

    };

    eswitches {

         IAX2/context@${CURSERVER};

    }

}

Ignorepat可以用来告诉通道驱动在收到匹配的样式之前不停止拨号音。最常见的例子是‘9。一般放在最前面,放在后面可能会出问题。

context outgoing {

    ignorepat => 9;

}

变量(Variables

Asterisk中的变量没有类型,所以如果要定义一个变量,必须要指定它的值先。

全局变量有它们自己的块(block

globals {

    CONSOLE=Console/dsp;

    TRUNK=DAHDI/g2;

}

变量也可以在分机中被定义。

context foo {

    555 => {

         x=5;

         y=blah;

         divexample=10/2

         NoOp(x is ${x} and y is ${y} !);

    }

}

注意:AEL可以使用$[]来将赋值语句的右边的部分括起来以使用表达式。如果你不想这么干,那么可以通过使用Set()应用括在右边部分。可以查看READMEvariables部分来了解表达式$[]的要求和行为。

注意:下面的这些情况请使用$[]表达式:while();if();forxyz)中的y表达式;赋值语句的右半部份,a=b -> Seta=$[b]

向拨号方案函数写入数值可以同赋值变量相当对待。

context blah {

    s => {

         CALLERID(name)=ChickenMan;

         NoOp(My name is ${CALLERID(name)} !);

    }

}

你也可以像下面这样在一个宏中声明变量:

Macro myroutine(firstarg, secondarg)

{

  Myvar=1;

  NoOp(Myvar is set to ${myvar});

}

本地变量(Local Variables

1.21.4asterisk中,所有的变量都是通道变量(CHANNEL variables),包括函数的参数和相关的ARG1ARG2还有其他的一些变量等。

而在1.6以及更高的版本中,对于一个宏调用,我们将变量都变成了本地变量。他们不会影响和他们同名的其他通道变量。这个包括ARG1ARG2等等变量。

用户可以使用关键字local来声明他们自己的本地变量。

Macro myroutine(firstarg, secondarg)

{

  local Myvar=1;

  NoOp(Myvar is set to ${Myvar}, and firstarg is ${firstarg}, and secondarg is ${secondarg});

}

在上面的例子中,Myvarfirstarg,和secondarg都是本地变量,对于调用的代码(可能是一个分机,也可能是其他的宏)他们是不可见的

如果你需要在Set()应用中定义本地变量,你可以这样做:

Macro myroutine(firstarg, secondarg)

{

  Set(LOCAL(Myvar)=1);

  NoOp(Myvar is set to ${Myvar}, and firstarg is ${firstarg}, and secondarg is ${secondarg});

}

循环(Loops

AEL实现了‘for’和‘while’的循环。

context loops {

    1 => {

         for (x=0; ${x} < 3; x=${x} + 1) {

              Verbose(x is ${x} !);

         }

    }

    2 => {

         y=10;

         while (${y} >= 0) {

              Verbose(y is ${y} !);

              y=${y}-1;

         }

    }

}

注意:条件表达式(上面的”${y} >= 0”)在$[]中括着,所以它的值可以被计算出来。

注意:for循环表达式(上面的”$x < 3”)在$[]中括着,所以它的值可以被计算出来。

条件(Conditionals

AEL支持ifswitch声明,并增加了ifTimerandom。不像之前的AEL,不需要在if()random()ifTime()条件语句添加大括号。也允许有else语句。

context conditional {

    _8XXX => {

         Dial(SIP/${EXTEN});

         if ("${DIALSTATUS}" = "BUSY")

         {

              NoOp(yessir);

              Voicemail(${EXTEN},b);

         }

         else

              Voicemail(${EXTEN},u);

         ifTime (14:00-25:00,sat-sun,*,*)

              Voicemail(${EXTEN},b);

         else

         {

              Voicemail(${EXTEN},u);

              NoOp(hi, there!);

         }

         random(51) NoOp(This should appear 51% of the time);

 

         random( 60 )

         {

                       NoOp( This should appear 60% of the time );

         }

         else

         {

                       random(75)

                       {

                               NoOp( This should appear 30% of the time! );

                       }

                       else

                       {

                               NoOp( This should appear 10% of the time! );

                       }

          }

    }

    _777X => {

         switch (${EXTEN}) {

              case 7771:

                   NoOp(You called 7771!);

                   break;

              case 7772:

                   NoOp(You called 7772!);

                   break;

              case 7773:

                   NoOp(You called 7773!);

                   // fall thru-

              pattern 777[4-9]:

                    NoOp(You called 777 something!);

              default:

                   NoOp(In the default clause!);

         }

    }

}

BreakContinueReturn

三个关键字,breakcontinuereturn,为循环和switch提供流程的控制。

Break可以被用在switch和循环中,用来结束循环或是switch

Continue可以用在循环中(whilefor),立刻结束本次操作。

Return将结束contextmacro,可以用在任何地方。

Gotojump,和labels

这个AEL中如何进行goto的例子。

context gotoexample {

    s => {

begin:

         NoOp(Infinite Loop!  yay!);

         Wait(1);

         goto begin;    // go to label in same extension

    }

    3 => {

            goto s,begin;   // go to label in different extension

     }

     4 => {

            goto gotoexample,s,begin;  // overkill go to label in same context

     }

}

 

context gotoexample2 {

     s =>  {

   end:

           goto gotoexample,s,begin;   // go to label in different context

     }

}

 

context gotoexample {

    s => {

begin:

         NoOp(Infinite Loop!  yay!);

         Wait(1);

         jump s;    // go to first extension in same extension

    }

    3 => {

            jump s,begin;   // go to label in different extension

     }

     4 => {

            jump s,begin@gotoexample;  // overkill go to label in same context

     }

}

 

context gotoexample2 {

     s =>  {

   end:

           jump s@gotoexample;   // go to label in different context

     }

}

catchblock可以在宏中被标识一些特殊的分级(extensions

macro std-exten( ext , dev ) {

       Dial(${dev}/${ext},20);

       switch(${DIALSTATUS) {

       case BUSY:

               Voicemail(${ext},b);

               break;

       default:

               Voicemail(${ext},u);

 

       }

       catch a {

               VoiceMailMain(${ext});

               return;

       }

}

宏可以使用下面的方法被引用,&std-exten

context example {

    _5XXX => &std-exten(${EXTEN}, "IAX2");

    _6XXX => &std-exten(, "IAX2");

    _7XXX => &std-exten(${EXTEN},);

    _8XXX => &std-exten(,);

}

例子:

context demo {

    s => {

         Wait(1);

         Answer();

         TIMEOUT(digit)=5;

         TIMEOUT(response)=10;

restart:

         Background(demo-congrats);

instructions:

         for (x=0; ${x} < 3; x=${x} + 1) {

              Background(demo-instruct);

              WaitExten();

         }

    }

    2 => {

         Background(demo-moreinfo);

         goto s,instructions;

    }

    3 => {

         LANGUAGE()=fr;

         goto s,restart;

    }

 

    500 => {

         Playback(demo-abouttotry);

         Dial(IAX2/guest@misery.digium.com);

         Playback(demo-nogo);

         goto s,instructions;

    }

    600 => {

         Playback(demo-echotest);

         Echo();

         Playback(demo-echodone);

         goto s,instructions;

    }

    # => {

hangup:

         Playback(demo-thanks);

         Hangup();

    }

    t => goto #,hangup;

    i => Playback(invalid);

}

语义检查(Semantic checks

AEL在解析后,编译前,将对拨号方案树做一些检查:

l       调用不存在的宏

l       宏调用上下文

l       参数不相符的宏调用

l       缺少&的宏调用

l       在“GotoIf”,“GotoIfTime”,“while”,“endwhile”,“Random”,和“execIf”的调用,将使得通话转到AEL gotowhile等结构当中去。

l       Goto到一个空的分机中的标识

l       Goto到一个内嵌的分机,内嵌的上下文,或是一个不同上下文,或是任何包含(included)的上下文中不存在的标识。还会检查姊妹上下文引用(?)

l       在拨号方案中,总会对时间的值做检查的,包括ifTime()和包含的时间中的时间值:1、标明时间的范围需要使用破折号来进行分隔;2、小时必须在024之间3、如果提供了工作日列表,那么工作日必须在这个内部列表中4、一个月中的第几天必须是在131之间的范围当中;月份的名字则也必须在内部列表当中。

l       如果表达式被括在$[…]中,那么编译器将把它在括起来一边,将产生警告

l       会检查是否有重复的上下文名称。

l       会检查没有被其他上下文包含的抽象上下文。

l       如果一个标识是一个数值,那么产生警告

如果计划中的AALasterisk argument language)被开发出来并被整合进asterisk,那么一部分检查将会被移除。

提示和bugsHints and Bugs

检查一个字符串是否为null的最安全的方法是$[“${x}” = “”]。以前的做法和shell脚本中的做法一致,就是在两边都加上一些字符,如:$[${x}foo = foo]。但是这种做法的麻烦就是,如果x包含一些空格,则会产生语法错误。更加安全的做法就是如一开始提到的加上双引号。现在也有一些针对变量引用的函数可以被使用,如ISNULL()LEN(),他们可以被用来测试一个空字符串:${ISNULL(${X})}$[${LEN(${x})} = 0]

你要记住的是赋值有两种不同的方法。如果你选择’x=y;’那么AEL将使用$[]括起右边的变量。所以,当编译的时候,结果就是’Set(x=$[y])’。如果你不想产生这样的效果,那么就像如下这样来替代‘Set(x=y)‘。

Asterisk的一个初学者看了上面的介绍和结构可能会问:“字符串处理函数在什么地方?”,“类似于其他语言提供的很酷的操作在什么地方?”等等

答案就是asterisk的这些丰富的功能都可以通过AEL来提供:

l       applications:可以参考asteriskapplication命令文档

l       functions:函数通过${…}实现,并可以提供许多有用的功能

l       expressions:在$[…]包含的表达式被表达式计算引擎处理。包括一些字符串的处理,算法表达式等

l       应用网关接口(Application Gateway interface):asterisk可以通过管道同它产生的进程进行通信。AGI应用可以使用任何语言实现。一些强大的应用可以通过这种方式来实现。

l       变量(variables):通信的通道拥有一些变量,并且asterisk也提供一些公共的变量。这些变量可以被上面提到的机制操作。

 

 

 
 
阅读(3392) | 评论(0) | 转发(0) |
0

上一篇:asterisk使用之AEL[1]

下一篇:很满足

给主人留下些什么吧!~~