[Asterisk-Users] RE: What about a higher level configuration language

Steve Murphy murf at e-tools.com
Sun Sep 26 17:38:36 MST 2004


I see some discussion on "higher level config files" -- namely the
extensions.conf

I too, for several months, have been pondering the fact that priorities
are like "assembly language", or the line numbers in old BASIC variants.

I've been thinking and investigating another extensions.conf language,
for which a compiler could be written to convert back to the normal
extensions.conf. The goal would be to get rid of priority numbers
altogether, enforce good programming style (code all the possibilities),
check the arguments to app calls, to make sure they are OK, and other
useful things.

My ideas run counter to a few of the examples provided, and I've not
quite "thunk" thru all the little issues yet, but it looks like a good
time to share at least some of my notes:



1. The new format will have macros, but with named arguments. That way,
we can verify the macro references.

2. The new format will use "blocks", like C, C++, and Java, with curly
brackets {}.

3. The new format will use labels, so Goto commands will go to a label,
not a priority number. Numbers should no longer appear anywhere in
Goto's. Contexts might/might not be necc, as labels could be global.

4. Applications and other commands that skip to new priority numbers
will have syntax, like labeled blocks, for each possibility. It will be
a syntax error to omit these. This forces the user to complete the
structure, and think about what to do in error conditions, so as not to
experience gross failure or strangeness when unexpected results are
encountered.

5. The start, timeout, illegal, etc. extensions will be given names. The
illegal, timeout, etc. blocks will be required for each context, at
least that have an extension.

Consider a current context format:

=================================================================================
[privacyManagerFailed]
exten => s,1,Background(tt-allbusy)
exten => s,2,Background(tt-somethingwrong)
exten => s,3,Background(tt-monkeysintro)
exten => s,4,Background(tt-monkeys)
exten => s,5,Background(tt-weasels)
exten => s,6,Hangup


[homeline]
exten => s,1,Answer
exten => s,2,SetVar,repeatcount=0
exten => s,3,Zapateller,nocallerid
exten => s,4,PrivacyManager
exten => s,105,Goto(privacyManagerFailed,s,1)
exten => s,5,GotoIf($[ "${CALLERIDNUM}" : "1" ]?callerid-bad|s|1:s|6)
exten => s,6,GotoIf($[ \"${CALLERIDNUM}\"  = \"3078888888\" &
\"${CALLERIDNAME}\" : \"Privacy Manager\" ]?callerid-liar|s|1:s|7)
exten => s,7,System(/usr/local/bin/who-is-it ${CALLERIDNUM}
"${CALLERIDNAME}"&)
exten => s,8,GotoIf($[ \"${CALLERIDNUM}\" = \"3077777777\" |
\"${CALLERIDNUM}\" = \"3076666666\" ]?s|9:s|10)
exten => s,9,SetMusicOnHold(mohlds)
exten => s,10,Background,homeline-intro1  ;; Script: Hello-- Welcome
blah blah...


=================================================================================

A new way to put it:


=================================================================================
context homeline
{
	start
	{
		Answer();
		repeatcount=0;
		Zapateller(nocallerid);
		PrivacyManager() Fail=
					{
					Background(tt-allbusy); 					Background(tt-somethingwrong);
					Background(tt-monkeysintro); 					Background(tt-monkeys);
					Background(tt-weasels);
					Hangup();
					};
		if $["${CALLERIDNUM}" : "1" ]
			callerid-bad;
		if $[ \"${CALLERIDNUM}\"  = \"3077545675\" & \"${CALLERIDNAME}\" :
\"Privacy Manager\" ]
			callerid-liar;

		System(/usr/local/bin/who-is-it ${CALLERIDNUM} "${CALLERIDNAME}"&)
Fail = {};

		if $[ \"${CALLERIDNUM}\" = \"3075274255\" | \"${CALLERIDNUM}\" =
\"3077548154\" ]
		{
			SetMusicOnHold(mohrock);
		}
	play_it_again_sam:
		Background(murphy-homeline-intro1);

	}
1	{
	System(/usr/bin/play /var/lib/asterisk/sounds/call-for.gsm|0)
	System(/usr/bin/play
/var/spool/asterisk/voicemail/default/2/greet.wav&|0)
	Dial(Zap/3r1&Zap/5r1&Sip/sonya|35|mt) Unavailable={    // Ring the
interface, 20 seconds maximum
								Voicemail2(u2);         // If unavailable, send to voicemail w/
unavail announce
								Hangup;                 // If they press #, return to start
						  	    }
						Busy={
							Voicemail2(b2);          // If busy, send to voicemail w/ busy
announce
							Hangup;                  // If they press #, return to start
							};
	}

2   {
		Goto homeline_kids;
    }

3   {
		...

	}

4   {

	VoicemailMain2();
	Goto play_it_again_sam;
    }

	fax { Dial(Zap/4) Busy={} Unavailable= {};  }
	
	timeout 
	{
		repeatcount = $[${repeatcount} + 1];
		if $[ ${repeatcount} < 3] 
			play_it_again_sam;
		else
		{
			Hangup();
		}
	}
	invalid
	{
		Background(invalid);
		goto play_it_again_sam;
	}
		
}

In the above, start, timeout, invalid, and fax are all special extension
names. 

A number like 99, or a pattern would all serve as an extension name,
just as in the original format. In the above, 1,2,3,4 are all
pattern/extension names. 

All the applications and commands that would or could cause a
redirection in the flow of statements will have alternative, hard-wired
labels associated with them, (like "Busy" and "Unavailable" in the dial
command) that you must supply either a label reference, a block of
{instructions;} of code, or a null or empty block of instructions {}.
Here is a list I made a while back of all the commands that played with
the priority:
	ChanIsAvail()  +101
	DBGet()         +101
        Dial            +101 (and +201, and +301, after privacy updates)
        EnumLookup()   +101
        CheckGroup()   +101
	HasVoicemail() +101
	SendImage()     +101   (and possible -1 return value)
	LookupBlacklist  +101 
	Macro()           --returns to next line after call
	OSPLookup()      +101
	OSPNext()         +101
	OSPFinish()       +100?
	ParkAndAnnounce()  --jumps
	PrivacyManager()   +101
	AddQueueMember()   +101
	RemoveQueueMember() +101
	SendText()           +101
	System()              +101, also -1 return poss.
	Transfer()            +101
	TXTLookup()    +101
	SendURL()       +101
	Voicemail[2]()   +101
	MailboxExists()   +101
	AgentMonitorOutgoing()  +101
Each path out of the application will have to be named, like "Busy",
"Unavailable", "Error", etc, and also the -1 return results should be
caught and have a path name also, as with System(). (I had no idea there
is a "u" extension to handle -1 result codes?)

Null blocks on labeled alternative could yield a warning. Missing
alternatives generate syntax errors... This seems like a hassle, but
really, you don't want strange things to happen if you don't code for an
error condition, do you? Such complicates the syntax for the config
file, but pays back for it in forcing coders to be complete.

Each app/command should have its own entry in the grammar; that way, we
can verify the arguments and do a proper syntax check for each arg, with
clear diagnostics.

That's my two cents, direct from the notes I've been making over the
last months. I see some overlap with ideas already expressed... which is
good! I love serendipity.

I don't think that changing the extensions.conf is necessary. These
kinds of features could be provided as a "front end" set of tools for
configuring asterisk. A simple make in /etc/asterisk/, for instance,
could update extensions.conf from this new config language, and send
asterisk the "extensions reload" command, if there are no errors, or
somesuch.

murf




-- 
Steve Murphy <murf at e-tools.com>
Electronic Tools Company




More information about the asterisk-users mailing list