Please Donate to Support the Development Work

Please note that all the tools are provided as free downloads. They are fully featured versions. We need your donations and corporate sponsorships to continue the development work. Please make a donation if you are using the software.

Thank you.

Property List Support for Asterisk & CallWeaver

The key to better GUI integration

Background

Asterisk uses the outdated Windows INI format to store its configuration. This format was the default configuration file format for Microsoft Windows before 1995, when it was superseded by a better system of storing configuration data. Even when it was first introduced with Microsoft Windows it was inferior to other formats in use at that time. The format has serious disadvantages and its continued use by Asterisk represents an impediment to better GUI integration for Asterisk both on MacOS X and other platforms.

MacOS X inherited its property list based system for persistent storage of configuration data from its predecessor, NeXT. It is the most advanced configuration system available today and it is used systemwide for configuration data of both the operating system and applications. The flexibility and ease with which MacOS X developers can create rich GUI applications is to a large extent the result of this system. Yet, with CF-Lite, Apple has made the system available as free open source software for use on other Unix based and Unix like platforms, including BSD, Linux and Cygwin, a Unix compatibility layer for Windows.

Further reading on MacOS X property lists and persistent configuration data storage:


Using Property Lists

Sunrise Telephone Systems Ltd. started development on property list support for Asterisk in order to make better GUI integration possible for Asterisk both on MacOS X and other platforms. The aim is to entirely replace the INI based configuration system with a property list based system.

The immediate benefit will be that the configuration files will be fewer, clearer and easier to understand and edit. For example, the Windows INI format does not support nesting of data and therefore several files are needed to group settings which could otherwise have been stored in a single file. Further, the property list format is cleaner and it is common practise to make identifiers more intuitive so that their purpose will be obvious from their name even to a novice.

All static configuration settings that belong to the asterisk core will be stored as a property list in a single master configuration file. Property lists can be stored in three different formats, binary, XML or plaintext. The following is an example of a master configuration file in plaintext plist format ...

/*
 * Default Asterisk/CallWeaver master configuration file - Version 0.90
 *
 * This master file consolidates all static configuration settings
 * of the Asterisk/CallWeaver core which were previously located in
 * asterisk.conf, logger.conf, manager.conf and modules.conf,
 * further the configuration settings of the optional resource
 * module res_config.so previously stored in extconfig.conf.
 *
 * This file is in ASCII plain text property list format which
 * replaces the previously used Windows INI file format as default.
 * 
 * Syntax:
 *
 *  plist = key-value-pair { key-value-pair }
 *  key-value-pair = identifier "=" ( value | value-container ) ";"
 *  identifier = simple-identifier | quoted-identifier
 *  simple-identifier = letter | digit { letter | digit }
 *  quoted-identifier = '"' printable-char { printable-char } '"'
 *  value = boolean | number | string
 *  value-container = dictionary | value-list
 *  dictionary = "{" plist "}" ";"
 *  value-list = "(" value { "," value } ")"
 *  boolean = "yes" | "no"
 *  number = digit { digit } [ "." digit { digit } ]
 *  string = '"' printable-char | escaped-char '"'
 */

/* settings for debugging */
Debugging = {
	ExtendedDebugMode = no;
	TimestampFormatString = "%F %T";
};

Dialplan = {
	// use Asterisk 1.0 dialplan engine
	Engine = "asterisk_v1.0";
	Filename = "extensions.conf"; 
	MethodOfConfiguration = ini;
};

/* settings previously located in asterisk.conf */
Directories = {
	// change these when using CallWeaver
	AGIDir = "/var/lib/asterisk/agi-bin"; 
	BinDir = "/usr/sbin"; 
	EtcDir = "/etc/asterisk"; 
	KeyDir = "/var/lib/asterisk/keys"; 
	LogDir = "/var/log/asterisk"; 
	ModDir = "/usr/lib/asterisk/modules"; 
	RunDir = "/var/run"; 
	SpoolDir = "/var/spool/asterisk"; 
	VarLibDir = "/var/lib/asterisk"; 
}; 

Filenames = {
	// change these when using CallWeaver
	Database = "astdb";
	Executable = "asterisk";
	PIDFile = "asterisk.pid";
	Socket = "asterisk.ctl";
}; 

/* settings previously located in logger.conf */
Logfiles = {
	// logging to the console
	console = {
		Enabled = yes;
		LogLevels = (notice, warning, error);
	};
	debug = {
		Enabled = no;
		LogLevels = (debug);
	};
	// logging to the default log file 
	messages = {
		Enabled = yes;
		LogLevels = (notice, warning, error);
	};
	// logging to syslog daemon
	syslog.local0 = {
		Enabled = no;
		LogLevels = (notice, warning, error);
	};
	// example of log file with all log levels
	verbose = {
		Enabled = no;
		LogLevels = (notice, warning, error, debug, verbose);
	}; 
}; 

/* settings previously located in manager.conf */
MgrAPI = {
	Enabled = no;
	IPaddress = "0.0.0.0";	// listen on all available interfaces
	PortNumber = 5038; 		// port to listen on
	UserAccounts = {
		fred = {
			Enabled = no; 
			HostsDenied = "0.0.0.0/0.0.0.0"; 
			HostsPermitted = "1.2.3.4/255.255.255.0"; 
			Password = 12345; 
			PermissionsToRead = (system, call, log, verbose, command, agent, user); 
			PermissionsToWrite = (system, call, log, verbose, command, agent, user); 
		}; 
	};
}; 

/* settings previously located in modules.conf and extconfig.conf */
Modules = {
	// the file name of a module is used as key for its entry
	// LoadOnLaunch determines whether or not to load the module
	// MethodOfConfiguration can be any of: none, plist, ini, odbc, pgsql
	app_conference.so = {
		LoadOnLaunch = yes;
		MethodOfConfiguration = none; // no config file
	}; 
	chan_applemodem.so = {
		LoadOnLaunch = yes; 
		MethodOfConfiguration = plist; // property list format
		PluginOfModule = chan_modem.so; // dependency
	}; 
	chan_modem.so = {
		LoadOnLaunch = yes;
		MethodOfConfiguration = ini; // Windows INI format
	};
	res_shadowconf.so = {
		LoadOnLaunch = yes;
		MethodOfConfiguration = plist; // property list format
	};
	res_zeroconf.so = {
		LoadOnLaunch = yes;
		MethodOfConfiguration = plist; // property list format
	};
};

/* settings previously located in asterisk.conf */
Options = {
	AppendHostToLogFiles = no; 
	AutoLoadModules = yes; 
	AutoRotateQueueLog = no; 
	ConsoleVerbosityLevel = 3; 
	DumpCoreOnCrash = no; 
	InitCryptoKeysOnLaunch = no; 
	PseudoRealtimeMode = no; 
	RecSoundsAsTempFiles = yes; 
};

The Asterisk Dialplan

Unlike the configuration data in the master plist, the data stored in the dialplan is considered to be of dynamic nature and therefore, it will be stored separately. The dialplan section in the master plist controls which dialplan Asterisk will be using, which dialplan engine to use and which format the dialplan is represented in. The default settings will mimic the exact same behaviour of Asterisk as it is at present, both dialplan language and format will initially remain the same ...

/* Configuration to exhibit the exact same dialplan behaviour as Asterisk 1.0 */
Dialplan = {
	// use Asterisk 1.0 dialplan engine
	Engine = "asterisk_v1.0";
	Filename = "extensions.conf"; 
	MethodOfConfiguration = ini;
};

Nevertheless, we have been experimenting with ways how to represent the existing dialplan syntax in a property list and add aliases for patterns to be matched. The results look promising so far, but more work is needed to finalise it. The following is an experimental snippet of dialplan data represented in plaintext property list format ...

// E X P E R I M E N T A L   M E T A   D I A L P L A N

// Define named keypad patterns
// This is for most folks and uses
patterns = {
	// 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, *, # match themselves
	// X matches any single digit from 0 to 9
	// Y matches any single digit from 1 to 9
	// N matches any single digit from 2 to 9
	// % matches any single digit, * or #
	// leading + matches + and international prefix
	// trailing ~ matches any number of digits
	// [0-8] matches any single digit from 0 to 8
	// 0[11,22,33]9 matches any of 0119, 0229, 0339
	// spaces are allowed but ignored, for readability

	+ = "011";
	International = "+YX~";
	NANPA = "1 NXX NXX XXXX";

	4-Digit-PIN = "%%%%";
	2-and-3-Digit-Service-Code = ( "*XX", "*XXX" );

	US-tollfree = "1 8[00,66,77,88] NXX XXXX";
	JP-tollfree = ( "0120 XXX XXXX", "0077 XXX XXXX" );
};

// Define named regular expressions
// This is for experts and witchcraft
regex = {
	// any regular expression
	matchall = ".*";
	SIPURI = "^[a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$"
};

// Define defaults
defaults = {
	// use asterisk 1.0 dialplan engine
	engine = "asterisk_v1.0";
	// store scripts inline
	storage = inline;
	// cache external scripts
	cache = yes;
};

// Define a context "incoming"
incoming = {
	include = (mainmenu, disa, default);

	// match calls to our US toll-free number
	18005551234 = {
		script = {
			1 = "NoOp(incoming call on ${EXTEN})";
			2 = "Dial(SIP/2000,60,r)";
			3 = "Hangup"
		};
		// engine omitted - default will be used
		// storage omitted - default will be used
	};

	// match calls to SIP URIs using named regex "SIPURI"
	SIPURI = {
		script = "sipuri-in.pl";
		engine = "mod_perl.so";
		storage = plaintext;
	};
};

// Define a context "outgoing"
outgoing = {

	// match named pattern "US-Tollfree"
	US-Tollfree = {
		script = "ustf-out.io";
		engine = "mod_io.so";
		storage = plaintext;
	};

	// match named pattern "NANPA"
	NANPA = {
		script = "nanpa-out.io";
		engine = "mod_io.so";
		storage = plaintext;
	};

	// match named pattern International
	International = {
		script = "intl-out.js";
		engine = "mod_js.so";
		storage = odbc;
	};
};

// Define a context "foobar"
// This shows how to pass every match to a single script
foobar = {

	// match named regex "matchall"
	matchall = {
		script = "foobar.pl";
		engine = "mod_perl.so";
		storage = plaintext;
	};
};

Asterisk Plug-in Modules

Each plug-in module will continue to have its own configuration file, but we will convert them all into property list format as well and this will become the default. However, the format for module configuration data will remain to be configurable on a per module basis through using the res_config module which so far supports odbc, mysql and pgsql. We will add plist and ini format plug-ins. The dialplan section in the master plist controls which modules will be loaded and what configuration file format to use ...

Modules = {
	// Dialplan applications
	app_conference.so = {
		LoadOnLaunch = yes;
		MethodOfConfiguration = none; // no config file
	};
	// etc
	
	// Channel drivers
	chan_iax.so = {
		LoadOnLaunch = yes; 
		MethodOfConfiguration = plist; // property list format
	};
	// etc
	
	// Resource modules
	res_zeroconf.so = {
		LoadOnLaunch = yes;
		MethodOfConfiguration = plist; // property list format
	};
	// etc
};

Removal of the Asterisk INI configuration file reader

Asterisk's INI file reader is a very naive and badly written data file reader. Not only does it violate every priniciple of software design, but it also represents a serious security threat because it does not perform any checks on the data it reads into memory.

Since the 1950's the commonly accepted practise for reading information stored as plaintext has been to read characters one by one from the source file and pass them to a scanner to perform lexical analysis during which malformed text and illegal characters are either rejected or filtered out, then tokenize the input stream and pass the token stream to a parser for syntax analysis. The Asterisk INI file reader does none of this and therefore the integrity of the configuration data cannot be guaranteed. Worse still, there is not even a formal definition of what constitutes legal configuration data because the Asterisk INI file reader is not based on any grammar. It will take any input without any checks whatsoever.

For this reason alone the Asterisk INI file reader ought to be removed or replaced by a proper parser that is based on a formal grammar. The good news is that with the replacement of INI configuration files by property lists, the INI file reader will no longer be needed inside the Asterisk core and it will be removed altogether from future MacOS X Asterisk releases. The property list parser is part of Apple's Core Foundation and CF-Lite frameworks so it will not need to reside within the core.

Sunrise Telephone Systems has developed a standalone conversion utility to automatically translate Asterisk INI files to plaintext property lists. Unlike Asterisk's configuration file reader, this utility is based on a formal grammar and it implements a proper scanner for lexical analysis and a proper parser for syntax analysis to be performed on INI files prior to conversion to property lists, thereby ensuring data integrity.

In addition to the conversion utility there will be a resource plug-in based on the Sunrise Asterisk INI file scanner and parser to allow Asterisk to read INI configuration files as an optional format in conjunction with res_config. It is worth noting that the open sourced scanner and parser code provided by Sunrise is modular and could be used to replace the existing INI file reader in the Asterisk core to fix the data integrity problem in Asterisk.org releases. The code is released under an MIT license.


Configuration compatibility with legacy systems

There will be several measures to ensure configuration compatibility between old and new.

The compatibility of module configuration data is achieved through the use of res_config plug-ins for INI and plist format. These plug-ins can be loaded on any Asterisk system and will work on any platform.

In addition, and in order to allow exchange of configuration data of the Asterisk core, a standalone conversion utility is provided to convert between INI and plist format.

Further still, another plug-in module, res_shadowconf, will be developed to shadow the active configuration data of Asterisk and loaded modules into a set of INI formatted shadow configuration files located in /etc/asterisk/shadow. The shadow files will be for reference only, modifying them will not have any effect on the configuration, but they can be used to show other Asterisk users who do not yet use plists when asking for assistance.


Cross-platform compatibility

The ideal situation would be for Asterisk on other platforms to adopt the OSX property list system which is vastly superior to the way in which other platforms store configuration data. Apple's free open source CF-Lite framework makes this possible.

However, without strong popular demand in the Asterisk community, it will be rather difficult to get the necessary changes accepted into Asterisk.org releases, regardless of the merits. We have therefore approached the people at CallWeaver.org and suggested to adopt the property list based configuration system into their upcoming release.

CallWeaver.org is a vendor-independent project based on a forked version of Asterisk 1.2. The Project agreed to adopt property list support if we provide the necessary modifications.


GUI integration, that's what it is all about

The main driver behind the new configuration system is better GUI integration. Once Asterisk supports property lists, all of its configuration data can be examined and modified with Apple's Property List Editor ...

Property List Editor showing Asterisk master plist

All available GUI tools from Sunrise Telephone Systems will then be upgraded to take advantage of Asterisk's property list support. The following screenshots are some examples on how Asterisk Launcher will extended in the future to provide better control ...

Asterisk Launcher 2

Asterisk Launcher 2

Asterisk Launcher 2

Asterisk Launcher 2


Source Code

The following source files have been released for review thus far ...

Modifications and additions to the Asterisk/OpenPBX.org core

ast_plist_support.zip -- all the above files in a single zip archive

Asterisk INI file to property list conversion utility -- aini2plist v1.10

aini2plist.zip -- all the above files in a single zip archive

aini2plist-xcodeproj.zip -- all the above files as an Xcode project file


Developers welcome

Now, all we have to do is finish the work. Developers interested to join this effort please contact us by email. The code for Asterisk and CallWeaver (both core and plug-ins) is being written in C and we use the Core Foundation framework on OSX, CF-Lite on other platforms. The configuration file conversion utility is being written in ANSI C and has no dependencies on any third party libraries.


Join the Macintosh Telephony Mailing List

List membership is free. Click here for details.


Legal Disclaimer

Asterisk is a trademark of Digium Inc. Apple, AppleScript, Bonjour, Cocoa, Macintalk, Macintosh and MacOS X are trademarks of Apple Inc. The Asterisk software is released under the GNU General Public License (GPL). The Asterisk for Macintosh Distribution is maintained and released by Sunrise Telephone Systems in accordance with the GPL whilst Apple's and Digium's trademarks are mentioned for reference only in order to inform about the origin and purpose of the software. The mentioning of those marks does not imply any kind of endorsement neither by Apple Inc nor by Digium Inc. A4M is a trademark of Sunrise Telephone Systems. A4M specific icons shown on this page are the property of Sunrise Telephone Systems, their use for other purposes than use or redistribution of the unmodified A4M software distribution or parts thereof requires written permission.

 

Asterisk on Tiger, Asterisk on OSX Tiger, Asterisk on MacOSX Tiger, Asterisk on MacOS X Tiger. Asterisk on OSX 10.4 Tiger, Asterisk on MacOSX 10.4 Tiger, Asterisk on MacOS X 10.4 Tiger. Asterisk the open source Macintosh PBX, not only for Linux. Asterisk on the Mac, Asterisk on OSX, Asterisk on MacOSX, Asterisk on MacOS X. MacPBX, MacPBX, Macintosh PBX, Macintosh Private Branch eXchange, Mac Telephone System, Macintosh Telephone System. VoIP on the Mac, VoIP on OSX, VoIP on MacOSX, VoIP on MacOS X. Mac VoIP server, Macintosh VoIP server, OSX VoIP server, MacOSX VoIP server, MaxOS X VoIP server. Mac telephony server, Macintosh telephony server, OSX telephony server, MacOSX telephony server, MacOS X telphony server. Mac SIP server, Macintosh SIP server, OSX SIP server, MacOSX SIP server, MacOS X SIP server.