Originate With Label?

Home » Asterisk Users » Originate With Label?
Asterisk Users 24 Comments

Hi.

https://wiki.asterisk.org/wiki/display/AST/Asterisk+16+Application_Originate

I need to use Originate() in a dialplan, pointing to another location in the same extension of the same context, so for example:

Originate(Local/${Dest}@Dialout,exten,${CONTEXT},${EXTEN},158);

I don’t seem to be able to substitute the priority 158 with a label – is this deliberate or is this a bug?

If it is deliberate, is there any workaround which would enable me to use Originate when the dialplan is written in AEL, which makes it not possible for me to define priority numbers?

(Alternatively, is there a way to define priority numbers in AEL?)

I’d prefer the first solution – being able to use Originate with a label as the target – as it’s neater and more generic.

Thanks,

Antony.


“this restriction will not apply in the event of the occurrence (certified by the United States Centers for Disease Control or successor body) of a widespread viral infection transmitted via bites or contact with bodily fluids that causes human corpses to reanimate and seek to consume living human flesh, blood, brain or nerve tissue and is likely to result in the fall of organized civilization.”

– https://aws.amazon.com/service-terms/ paragraph 42.10

Please reply to the list;
please *don’t* CC me.

24 thoughts on - Originate With Label?

  • The underlying API that Originate uses here
    (ast_pbx_outgoing_exten_predial) accepts an integer priority, not a string, which would preclude labels. However, Originate itself could accept a string and convert it to the integer priority before making that call. I think that would be an improvement/new feature, not a bug that exists today, per se, but an easy and useful enhancement at that. Another option would be a dialplan function to allow users to manually get the integer priority of a label, which could be useful for existing code that expects numeric priorities.

    NA

  • Hi Anthony,

    I love to hear about AEL use-cases.  I’m happy that AEL is working out for you.

    Without modifying the code for Originate(), you can do this while staying purely in AEL
    Here’s your workaround:

    context something {
    s => {
    Originate(Local/${Dest}@Dialout,exten,${CONTEXT},GotoLabel,1,,v(GotoExten=${EXTEN}^GotoLabel=LabelName));
    }

    GotoLabel => {
    goto ${CONTEXT}, ${GotoExten}, ${GotoLabel};
    }
    }

  • And, additionally.  You really *should* be breaking down components into their own macros or extension blocks.  Adding labels to jump into the middle of an extension is typically a sign that you’ve outgrown your overall design.

    It’s much. much. much easier to build a system up from different contexts,extensions and use goto/gosub and make your system more modular instead of having one-giant-context with one-giant-extension that tries to do everything.

    Hope this helps!

  • It is, although there are ways I think it can be improved – I’m wondering how best to go about proposing these.

    The most obvious for now are:

    – please can “a=1;” be converted to use Set() instead of MSet() (especially since MSet is officially deprecated)?

    – same thing for for (;;)

    – please can gosub be added, to convert into Gosub() (matching goto converting to Goto())? The & syntax is completely different from the rest of the language, and also creates redundant assignments at the start of the subroutine for parsing the parameters. Now that macros are deprecated in favour of subroutines, it makes sense, I think, to make gosub a part of AEL.

    – it would be great if the redundant NoOp()s which get created by if .. else, while … and for(;;) could be (maybe optionally?) removed from the resultant dialplan code – otherwise you end up with lots of added commands such as NoOp(Finish if_if_fromTrunk_208_209); in the output.

    – finally, it would be good if the documentation could be clear about whether the extensions.conf [general] section can be substituted using AEL. I haven’t yet worked out whether this is possible or not.

    Right, I had wondered about using the v option. Thanks for the suggestion.

    In the meantime I came up with:

    Originate(Local/${Dest}@Dialout,exten,${CONTEXT},Orig${EXTEN},1);

    _OrigX. => goto ${EXTEN:4},target;

    Oh, I already have plenty of contexts and a fair number of extensions. I’m not writing the entire dialplan in one context 🙂

    There’s a good reason why I need to jump to another location in the same context once the Originate has completed.

    Very much agreed.

    Antony.


    I conclude that there are two ways of constructing a software design: One way is to make it so simple that there are _obviously_ no deficiencies, and the other way is to make it so complicated that there are no _obvious_
    deficiencies.

    – C A R Hoare

    Please reply to the list;
    please *don’t* CC me.

  • https://wiki.asterisk.org/wiki/display/AST/Asterisk+13+Application_MSet includes the sentence “MSet behaves in a similar fashion to the way Set worked in 1.2/1.4 and is thus prone to doing things that you may not expect.” and ends with “Avoid its use if possible.”

    So, that may not mean “officially deprecated”, but it still strongly suggests to me that it’s undesirable for AEL to convert all assignments into MSet instead of Set (allowing the user to explicitly write MSet if that’s what’s desired).

    Antony.


    Atheism is a non-prophet-making organisation.

    Please reply to the list;
    please *don’t* CC me.

  • Sure, but even with that it’s not “unofficially deprecated”. It’s sound reasoning, however, that because of the behavior of MSet then switching could be a good idea.

  • Some users of AEL might rely on the ‘odd behavior’ of MSet (the most obvious of which is the removal of quotes).  This would definitely have to be an option if all conversions were to use Set instead of MSet.

    But!  What specific reason do you have for wanting Set() instead of MSet() for all assignments that can’t be otherwise just written as an in-line Set() instead?

    Also.. if you specifically want to use Set(), there’s nothing preventing you from just using Set()

    The assignment (ex: a=1) style shortcut is mostly useful for math-based operations. such as making nice syntactic sugar for something like:
    a = ${a} + 1

    You can of course accomplish math operations a traditional Set() by using traditional $[] syntax.  So for the intended purposes it’s pretty much a shortcut for simple assignments or math.  Anything else, you would need to call Set() directly.

  • Hi Antony,

    Right… using a=1; one advantage of using AEL, so you don’t have to type Set() everywhere… but what I’m trying to get at is… and my original question is:  what specific situation prevents you from using a=1; style syntax?  Why are you feeling the need to use Set(a=1) instead of a=1.  What are specific examples where the ‘straight-assignment’
    isn’t working for you?

    Note: Make sure to use ‘Reply All’.. I typically do a list reply and direct reply.

  • I don’t have any examples where MSet() ends up doing something I do not want, but going by the documentation saying “avoid its use if possible”, that’s what I prefer to do.

    Okay, replying to you as well this time, but please don’t do the same back to me (see sig).

    Antony.


    If the human brain were so simple that we could understand it, we’d be so simple that we couldn’t.

    Please reply to the list;
    please *don’t* CC me.

  • Currently being discussed!  We can definitely continue talking about the pros and cons of adding an option for this or maybe finding another way altogether.

    I see that for (;;) produces an empty MSet().  Definitely this can be cleaned up.  Thanks for bringing this up.  In the meantime you can use while (1)

    I agree that AEL keyword ‘gosub’ should exist.  That’s been one of my todo items.  From not only a consistency perspective, but from a syntax checking perspective it would benefit from reporting whether or not your gosub destination exists or not, just like goto will complain that the destination doesn’t exist when the context/extension/priority used is not valid.

    The ‘&’ syntax does use GoSub under the hood, and not the deprecated Macro().  And I’m not sure what you mean by redundant parameters?  When you use AEL ‘macro’ to define a ‘& destination’, it uses the positional parameters that are passed in as ARG1/ARG2/etc that are inherent in using GoSub and converts them to more friendly named-parameters (as defined in the macro definition).  This is why there’s always a group of MSet’s generated when using AEL ‘macro’.  If you don’t want these extra MSets, then feel free to define a straight up context to GoSub into and you can do your own parameter processing using ARG1/ARG2/etc

    They aren’t redundant specifically, they were left in there (not by me)
    for debugging/tracing purposes.  But for the casual user, I agree they are mysterious and not very useful. My idea to address this is to instead report on the actual if condition to assist with tracing/troubleshooting.

    This is a mockup of what the new-style if/else processor would output

                        26. NoOp(AEL IF(“\${DIALSTATUS}” == “BUSY”) —
    extensions.ael:1405)
                        27. GotoIf($[“${DIALSTATUS}” == “BUSY”]?28:30)
                        28. Set(voiceMailOptions=b)
                        29. Goto(32)
                        30. NoOp(AEL ELSE — extensions.ael:1409)
                        31. Set(voiceMailOptions=u)
                        31. NoOp(AEL END ELSE — extensions.ael:1410)
                        32. NoOp(AEL END IF(“\${DIALSTATUS}” == “BUSY”) —
    extensions.ael:1411)
                        33. NoOp(DoStuff)

    My idea is that the ‘if’ block would be preceded by outputting the logical condition we’re about to check, along with the original ael line number, and then at the end of the if block, we would get an associated END IF with the original ael line number.  This would enable the ability to quickly locate the code where conditions are being used and also be able to look at the logs and see why your code is doing what it’s doing without a lot of extra verbosity and without needing a lot of work to find which ael-lines are running.

    [general] section options are not available in ael… currently there’s no mechanism to support that sort of thing.

    bracket items like [general] aren’t supported in the AEL parser. and some of the options don’t even make sense and/or apply to AEL like static/writeprotect

  • Why all the GotoIfs? Why not just use the If/EndIf applications
    (assuming they get merged)? Much cleaner syntax:

    If($[“${DIALSTATUS}”=”BUSY”])
    Set(voiceMailOptions=b)
    Else()
    Set(voiceMailOptions=u)
    EndIf()

    NA

  • That’s definitely very doable.  If/Else/Endif was not available at the time AEL was created.  This would be much cleaner code generation as well.

  • Yes, it would useful to implement “backward compatibility” options for AEL, just as exist for whatever “non-AEL” is called.

    Some equivalent of [general] in extensions.conf might be good?

    No, no – I didn’t literally mean “(;;)”, I meant this as an abbreviation for the generic format of the for() syntax.

    True; that works for literally “for(;;)”, but I think I’ve never bothered to use that 🙂

    I meant it wouod be good to use Set() instead of MSet() for the first and third parts of “for (one; two; three);”

    Sounds good.

    Yes, agreed.

    That’s precisely what I mean 🙂

    If you use Gosub(), you can reference your parameters as ARG1/2/3/etc, but if you use &, you end up with several “MSet(xxx=${ARG1});” etc at the start of your subroutine.

    These, in my opinion, are redundant,

    See above 🙂

    I do.

    I just wish there were a gosub in AEL mapping to Gosub() to match goto mapping to Goto().

    Hence my “maybe optionally” suggestion.

    I’d prefer to see an option in extensions.ael to say whether you want them at all or not.

    I would disagree with *any* extra NoOp()s being included in the resultant output unless the user has asked for them.

    Let the code simply express what the user wrote and not add anything
    (especially stuff which will end up in a verbose log) which doesn’t correspond to the original input (unless necessary for the logic to work).

    Nice as a debugging tool, please make it optional, dependent on a configuration setting.

    Maybe for the things that would make sense for AEL (see above), this would be a useful addition?

    Agreed, would be nice to find this clearly documented.

    Antony.


    Never write it in Perl if you can do it in Awk. Never do it in Awk if sed can handle it. Never use sed when tr can do the job. Never invoke tr when cat is sufficient. Avoid using cat whenever possible.

    Please reply to the list;
    please *don’t* CC me.

  • I do now.

    I use CDR UniqueIDs to track calls being processed through my system, so at the start of a context where a call arrives, I assign the value to a variable I can use later in the dialplan.

    In /etc/asterisk/asterisk.conf I have:

    ; Prefix uniqueid with a system name for
    ; Global uniqueness issues. autosystemname = yes

    If I write in my AEL dialplan:

    Set(Tracker=${CDR(uniqueid)});

    this results in executing:

    Set(Tracker=eagle.domain.com-1661872057.2349)

    Just what I want.

    However writing:

    Tracker=${CDR(uniqueid)};

    results in:

    MSet(Tracker=-1661872057.2349)

    systemname is missing.

    Antony.


    I don’t know, maybe if we all waited then cosmic rays would write all our software for us. Of course it might take a while.

    – Ron Minnich, Los Alamos National Laboratory

    Please reply to the list;
    please *don’t* CC me.

  • Hi Antony,

    This is not a problem with MSet.

    Keep in mind that AEL is a transpiler, the AEL itself is not evaluated at the time of execution… extensions.conf-style dialplan is what’s being executed.

    Also… keep in mind that var=val assignments always use surround the value with $[]  which will either evaluate math or boolean expressions.

    Since ‘eagle.domain.com’ is not numeric, and not boolean, it’s expected it would not be included in the final value.

    If you do a ‘dialplan show’ on the context after AEL has processed it, you’ll clearly see the MSet and ${CDR(uniqueid)} being inside $[]

    If you run the same code through extensions.conf you’ll get exactly the same result… so I would call this expected behavior.

    The fix/workaround is to explicitly use Set() when you need to work with anything non-numeric and non-boolean

  • No, it is indeed the documented behaviour of MSet “MSet behaves in a similar fashion to the way Set worked in 1.2/1.4 and is thus prone to doing things that you may not expect.”

    Agreed.

    Yes, but to be fair, that is not what I would expect Tracker=${CDR(uniqueid)}
    to do in any other language.

    Yes.

    I think we’ll have to disagree on what a programmer “expects” a syntax like var=value to do, then.

    True, and that is precisely what I have been doing in order to avoid such problems. This example slipped through my conversion process (I’ve been converting previously-non-AEL dialplans into AEL because I prefer the general style).

    What I am suggesting is that Tracker=${CDR(uniqueid)} should be converted by AEL into Set(Tracker=${CDR(uniqueid)}) in order to avoid this sort of surprise.

    If someone knows they want to perform arithmetic, they can write Result=$[${var1}-4] and end up with Set(Result=$[${var1}-4]) after AEL has done its transpilation.

    Maybe you could offer an example of where MSet() does what most people would expect, and Set() does not?

    I still intend to abide by the documentation for MSet “Avoid its use if possible.”, and I simply think it would be good if AEL: did the same.

    Antony.


    +++ Divide By Cucumber Error. Please Reinstall Universe And Reboot +++

    Please reply to the list;
    please *don’t* CC me.

  • Please re-evaluate what I wrote previously.  Again, this is not a problem with MSet.  You can see this for yourself if you do an inline MSet(Tracker=${CDR(uniqueid)});  this will work fine.

    Just because the documentation says that MSet should not be used, it’s not appropriate to blame all undesirable behaviors on MSet(), since clearly MSet() is not the problem here.

    You agreed below that $[] is not what you expected var=val to do… but… despite being unexpected, it’s actually the defined behavior. 
    And since there is no official specification for AEL, the specification for AEL is what AEL does.  (And I’m not trying to give you a hard time on this.. I’m just stating facts:  This is very much like Perl language.. where the spec for Perl *is* the Perl interpreter).

    In this case, what the language does… is what it’s supposed to do
    (unless it’s a bug).  Ie: any inherent behaviors especially major transpiling behaviors, are going to stay the way they are as to not break people’s existing usages of it.  I didn’t write the AEL system, I’m just maintaining it.  So I’m not trying to “defend my honor” or anything.  I’m just stating the reality of the situation about maintaining compatibility and not making a major change to the language for syntactic sugar sake.

    If you still need clarification as to why MSet isn’t the problem, then this example should clear it up:

    extensions.conf MSet(Tracker=${CDR(uniqueid)});       // works as expected MSet(Tracker=$[${CDR(uniqueid)}]);   // undesirable, due to conversion to math/boolean

    extensions.ael MSet(Tracker=${CDR(uniqueid)});        // works as expected MSet(Tracker=$[${CDR(uniqueid)}]);    // undesirable, due to conversion to math/boolean

    extensions.ael Tracker=${CDR(uniqueid)};  // converted to MSet(Tracker=$[${CDR(uniqueid)}]);   which is the same *exact* behavior of extensions.conf

    So… you can see from the above..  if you put your assignment value containing a string into a $[]  you’ll loose the string value, regardless of whether or not it’s an AEL var=val assignment or not.

    On the flip-side… anyone who currently relies on purely numeric/boolean handling of the current implementation would be incredibly surprised to find their AEL suddenly broken… so we need to take that into account.

    When I write AEL needing arithmatic, i use var=val notation, skipping the need for Set and $[]

    I’m a huge fan of enhancements and improvements and bug fixes, but as noted, MSet isn’t the problem here.  I’ll look into making an option available on switching the ‘setter’, but making the change from MSet to Set will not fix your issue.  But… currently I don’t see a justifiable reason to make this a thing, unless there’s actual problems demonstrated with the fact that MSet is being used.

  • Let me correct myself.  The documentation doesn’t say it shouldn’t be used… it’s making you aware of possible side-effects.  It’s perfectly legitimate to use MSet() if you prefer the assumptions/behaviors of MSet() as opposed to the assumptions/behaviors of Set().

  • Aha – now I see that my problems (or confusions) are being caused by the automatic wrapping in $[..] and not by MSet itself, thank you.

    Agreed.

    Indeed.

    I realise that the better solution might be to wrap assignments (inside Set()
    or MSet(), no matter) with $[..] *only* if the expressions contain arithmetic operators + – * / and not if they are simple a=b assignments, including a=${b}.

    This would ensure that even if ${b} expanded to something containing a dash, it would be interpreted as a mathematical minus sign in a=${b}

    Indeed, I agree with you now. I was focusing on MSet and not $[..]

    I would still be interested to know whether there are any examples of MSet()
    doing what one expects and Set() in the same situation causing a problem.

    Thanks,

    Antony.


    This sentence contains exacly three erors.

    Please reply to the list;
    please *don’t* CC me.

  • One thing MSet does that Set doesn’t is assign multiple variables at once (hence the name, multiple set). e.g. instead of:
    same => n,Set(a=1)
    same => n,Set(b=2)
    same => n,Set(c=3)

    just do:
    same => n,MSet(a=1,b=2,c=3)

    I’m not sure if that still works in AEL, e.g. if you can do:
    a = 1, b = 2, c = 3;

    This requires MSet; the Set application only sets one variable per invocation. The SET function has limited ability to do this but doesn’t always work. This is not so much “causing a problem” as a limitation of Set that is really by design. This is probably a big reason MSet is not and won’t be deprecated – it serves this distinctly different purpose. Judicious use of MSet can reduce dialplan clutter when setting lots of variables, but typically different assignments are not written like that anyways, so maybe not relevant to AEL.

  • I would hesitate about making this happen as well.. without a migration-plan in place.

    Typically:
    1) Add a new option that would flip the behavior of var=val sets to auto-detect math and act accordingly on whether or not to use $[] (which comes with its own issues)

    2) Warn about the change in the application: Ie: In Asterisk 20 there would be a warning stating in Asterisk 21 this will be the new default behavior

    But, there’s issues with auto-detecting math.  Because it’s impossible for a compiler/transpiler to correctly assess *intent*. It can read the symbols and say, “Oh, I see you have some math symbols here, lets force this to math mode” in a purely search and replace context.  Here’s the problem with that.  Variables can contain all kinds of (very unpredictable from a compiler perspective) stuff.

    How is the compiler supposed to tell the difference between the following examples, for intent var1 = ${a} + ${b} / ${c};
    var2 = Hello World / Hello Bob / Hello Sue var3 = *1*1*1* HEY THERE IS A PROBLEM *1*1*1
    var4 = This-Is-Some-Dash-Separated-Data: 1-2-3-4-5-6

    I’m not saying I personally write code like this, but there are some quick examples that can easily proof this to be the wrong approach

    I think what you’re looking for is quoted strings. var1 = “This-Is-Some-Dash-Separated-Data: 1-2-3-4-5-6”
    Which gets converted to an MSet(var1=$[
    “This-Is-Some-Dash-Separated-Data: 1-2-3-4-5-6” ])

    Which considering MSet actually has a desired behavior here of removing quotes, your value of var1 will be exactly what you expect it to be

    AEL

      9999 => {

        var = “hi there – what’s – up 0 * 1 / 4 not math”;

        NoOp(${var});

      }

    Dialplan:

    vbox-markm-x64*CLI> dialplan show 9999@services

    [ Context ‘services’ created by ‘pbx_ael’ ]

      ‘9999’ =>         1. MSet(var=$[ “hi there – what’s – up 0 * 1 / 4 not math”]) [pbx_ael]

                        2. NoOp(${var})                               [pbx_ael]

    Execution:

    MSet(var=”hi there – what’s – up 0 * 1 / 4 not math”)

    NoOp(hi there – what’s – up 0 * 1 / 4 not math)

  • Agreed; I didn’t mean “please change it now”!

    Agreed, but for text strings containing such symbols, I have to say that my natural inclination would be to put them in quote marks, as you say:

    It’s when the *value of a variable* on the right hand side of the assignment happens to contain an arithmetic operator that the real surprise occurs.

    Strangely enough, I just discovered that as a solution to my example problem, which was:

    ———
    Set(Tracker=${CDR(uniqueid)});

    resulting in:

    Set(Tracker=eagle.domain.com-1661872057.2349)

    Just what I want.

    However:

    Tracker=${CDR(uniqueid)};

    results in:

    MSet(Tracker=-1661872057.2349)
    ———

    If I simply do

    Tracker=”${CDR(uniqueid)}”;

    it works as required.

    It’s just not the sort of syntax I’ve seen in any other language, and it feels
    (to me) weird.

    Maybe the documentation: “NOTE: AEL wraps the right hand side of an assignment with $[ ] to allow expressions to be used If this is unwanted, you can protect the right hand side from being wrapped by using the Set() application.” could be enhanced to point out that quote marks can overcome the problem as well?

    https://wiki.asterisk.org/wiki/display/AST/AEL+Variables

    Antony.


    “640 kilobytes (of RAM) should be enough for anybody.”

    – Bill Gates

    Please reply to the list;
    please *don’t* CC me.

  • ^^^ Yup!  This is what I was suggesting in my last email.  Just add quotes.

    Think of it this way.  Compared to other languages.. If you want to do math, do math, if you want to use a string, use a string.  I think it follows the convention quite nicely, other than the weird behavior of AEL of when you use an assignment of mixed text-math without quoting.

    c
    —-
    a = 1 + 1; /* correct */
    b = “foo”; /* correct */
    c = 1 + “bar”; /* syntax error */

    perl
    —-
    $a = 1 + 1;  # correct
    $b = “foo”;  # correct
    $c = 1 + “bar”; # syntax error

    php
    —-
    $a = 1 + 1;
    $b = “foo”;
    $c = 1 + “bar”; # treats “bar” as 0, results in a runtime warning, final value: $c=1

    python
    —-
    a = 1 + 1 # correct b = “foo”  # correct c = 1 + “bar” # runtime error

    So… the only weird thing here… is AEL ‘works’ with “
    “, and does something unexpected with it

    Thanks for the suggestion.. I’ll update the documentation and add some examples.