Skip to content
Dec 17 / Scotty

Asterisk to Voiceflex – an example on the NSLU2

I have had numerous comments and requests regarding Asterisk configuration for Voiceflex. I have neglected my blog somewhat lately, but when I googled for “BCM50 SIP” the other day, I was suprised to see my own blog high up the listings! I have decided to revisit this, as it has obviously generated a lot of interest.

I have a bash script that I used on the Linksys NSLU2 (“the SLUG”) in order to quickly configure Asterisk to act as a gateway between a Nortel BCM50 and Voiceflex’s SIP trunks. Although there is no longer a need to use the NSLU2 in this fashion, as Voiceflex can dispense with SIP authentication when the BCM50 is on a static IP, I will post the scripts, as well as the relevant Asterisk config files, as they may be useful for anybody that wants to configure Asterisk with SIP trunks.

Firstly,  the Asterisk configs: obviously, do not use these as-is, you will need to change the details to suit!

sip.conf

[general]

context=default
bindport=5060
bindaddr=0.0.0.0
srvlookup=yes
domain=asterisk

disallow=all
allow=alaw,g729,g723
language=en
relaxdtmf=yes
trustrpid=no
useragent=Asterisk PBX
promiscredir=yes
canreinvite=yes

domain=146.101.248.200,incoming-voiceflex
domain=192.168.40.6,incoming-voiceflex
domain=10.10.10.10,incoming-bcm
domain=10.10.11.11,default

#include /etc/asterisk/sip_nat.conf

#include /etc/asterisk/sip_accounts.conf

[sip-bcm]
type=peer
host=10.10.10.10
context=incoming-bcm

#include /etc/asterisk/sip_og_context.conf

; sip ext for xlite, for testing
[200]
type=friend
regexten=200
secret=donttell
context=default
host=10.10.10.10
canreinvite=no
insecure=port,invite

sip_nat.conf

externip=11.11.11.11
localnet=192.168.192.0/24
nat=yes

sip_accounts.conf

;sip_accounts.conf generated by autoasterflex
register => 12345678:shhhsecret@sip.voiceflex.com

registertimeout=20
registerattempts=0

[authentication]
auth=12345678:shhhsecret@146.101.248.200
auth=12345678:shhhsecret@voiceflex
auth=12345678:shhhsecret@sip.voiceflex.com

sip_og_context.conf

[voiceflex]
type=friend
callerid=01234567890
fromuser=01234567890
defaultuser=12345678@voiceflex
disallow=all
allow=alaw,ulaw,g729
fromdomain=voiceflex
secret=shhhsecret
host=sip.voiceflex.com
insecure=invite,port
context=incoming-voiceflex

extensions_incoming_voiceflex.conf

[incoming-voiceflex]
exten => s,1,Dial(SIP/666666@sip-bcm,,r);
exten => 666666,1,Dial(SIP/666666@sip-bcm,,r);

extensions.conf

; extensions.conf - asterisk dialplan

[general]
static=yes
writeprotect=no
autofallthrough=yes
clearglobalvars=no
priorityjumping=no

[globals]

[incoming-bcm]
exten => 200,1,Dial(SIP/200,,r);
exten => _9.,1,Dial(SIP/${EXTEN:1}@voiceflex,,r);
exten => _8.,1,SIPDtmfMode(inband);
exten => _8.,2,Dial(SIP/${EXTEN:1}@voiceflex,,r);

;this context must be absent prior to  running autoasterflex
;[incoming-voiceflex]
;exten => s,1,Dial(SIP/234567@sip-bcm,,r);
;exten => 234567,1,Dial(SIP/234567@sip-bcm,,r);

[default]
exten => _9.,1,Dial(SIP/${EXTEN:1}@voiceflex,,r);
exten => 300,1,Dial(SIP/234567@sip-bcm,,r);
exten => 234567,1,Dial(SIP/234567@sip-bcm,,r);

#include /etc/asterisk/extensions_incoming_voiceflex.conf

Finally, here is a little shell script that I was using, in order to configure an NSLU2 with Asterisk already installed, to configure the SIP trunks. USE WITH CAUTION – answering “y” to “Change IP & DNS settings (y/n) ?” will re-write the network interface config (/etc/network/interfaces) and DNS client config (/etc/resolf.conf) on the machine that you run it on (if it is Linux based.) I would advise anybody using the script to exercise care doing this, and only to do so if you have read and understand the script.

autoasterflex.sh

#!/bin/bash

#autoasterflex

echo "Caller ID of incoming SIP Trunk?"
read CALLERID
echo "SIP Account number?"
read SIPACCT
echo "SIP Account password?"
read SIPPASS
echo "PBX IP Address?"
read BCMIP
echo "WAN IP Address?"
read EXTERNIP
echo "Local network? (eg 192.168.0.1/24)"
read LOCALNET
echo "Digits to send to pbx as received digits?"
read DDI
echo "Change IP & DNS settings (y/n) ?"
read CHANGEIP

if [ "$CHANGEIP" == "y" ]; then
	echo "Slug IP?"
	read SLUGIP
	echo "Slug Netmask?"
	read SLUGSN
	echo "Slug Default Gateway?"
	read SLUGDGW
	echo "DNS Server?"
	read SLUGDNS
fi

# modify existing sip_og_context.conf
sed -i "s/callerid=.*/callerid=${CALLERID}/" /etc/asterisk/sip_og_context.conf
sed -i "s/fromuser=.*/fromuser=${CALLERID}/" /etc/asterisk/sip_og_context.conf
sed -i "s/defaultuser=.*/defaultuser=${SIPACCT}@voiceflex/" /etc/asterisk/sip_og_context.conf
sed -i "s/secret=.*/secret=${SIPPASS}/" /etc/asterisk/sip_og_context.conf

# delete existing si_accounts.conf, create a new one
rm -f /etc/asterisk/sip_accounts.conf
echo ";sip_accounts.conf generated by autoasterflex" >> /etc/asterisk/sip_accounts.conf
echo "register => ${SIPACCT}:${SIPPASS}@sip.voiceflex.com" >> /etc/asterisk/sip_accounts.conf
echo "" >> /etc/asterisk/sip_accounts.conf
echo "registertimeout=20" >> /etc/asterisk/sip_accounts.conf
echo "registerattempts=0" >> /etc/asterisk/sip_accounts.conf
echo "" >> /etc/asterisk/sip_accounts.conf
echo "[authentication]" >> /etc/asterisk/sip_accounts.conf
echo "auth=${SIPACCT}:${SIPPASS}@146.101.248.200" >> /etc/asterisk/sip_accounts.conf
echo "auth=${SIPACCT}:${SIPPASS}@voiceflex" >> /etc/asterisk/sip_accounts.conf
echo "auth=${SIPACCT}:${SIPPASS}@sip.voiceflex.com" >> /etc/asterisk/sip_accounts.conf

#delete existing sip_nat.conf,  create a new one
rm -f /etc/asterisk/sip_nat.conf
echo "externip=${EXTERNIP}" >> /etc/asterisk/sip_nat.conf
echo "localnet=${LOCALNET}" >> /etc/asterisk/sip_nat.conf
echo "nat=yes" >> /etc/asterisk/sip_nat.conf

#check extensions.conf has #include /etc/asterisk/extensions_incoming_voiceflex.conf, append if absent
INCVFLEXCONFPRESENT=`grep '/etc/asterisk/extensions_incoming_voiceflex.conf' /etc/asterisk/extensions.conf`
if [ "" == "$INCVFLEXCONFPRESENT" ]; then
	echo ""  >> /etc/asterisk/extensions.conf
	echo "#include /etc/asterisk/extensions_incoming_voiceflex.conf" >> /etc/asterisk/extensions.conf
fi

#delete existing extensions_incoming_voiceflex.conf, recreate
rm -f /etc/asterisk/extensions_incoming_voiceflex.conf
echo "[incoming-voiceflex]" >> /etc/asterisk/extensions_incoming_voiceflex.conf
echo "exten => s,1,Dial(SIP/${DDI}@sip-bcm,,r);" >> /etc/asterisk/extensions_incoming_voiceflex.conf
echo "exten => ${DDI},1,Dial(SIP/${DDI}@sip-bcm,,r);" >> /etc/asterisk/extensions_incoming_voiceflex.conf

# modify sip.conf
sed -i "s/domain=.*,incoming-bcm/domain=${BCMIP},incoming-bcm/" /etc/asterisk/sip.conf
sed -i "s/host=.*/host=${BCMIP}/" /etc/asterisk/sip.conf

if [ "$CHANGEIP" == "y" ]; then
	#recreate /etc/network/interfaces
	rm -f /etc/network/interfaces
	echo "# /etc/network/interfaces" >> /etc/network/interfaces
	echo "# recreated by autoasterflex" >> /etc/network/interfaces
	echo "#" >> /etc/network/interfaces
	echo "# the loopback interface" >> /etc/network/interfaces
	echo "auto lo" >> /etc/network/interfaces
	echo "iface lo inet loopback" >> /etc/network/interfaces
	echo "#" >> /etc/network/interfaces
	echo "# the interface used by default during boot" >> /etc/network/interfaces
	echo "auto eth0" >> /etc/network/interfaces
	echo "#" >> /etc/network/interfaces
	echo "# static entry for eth0" >> /etc/network/interfaces
	echo "iface eth0 inet static" >> /etc/network/interfaces
	echo "    address ${SLUGIP}" >> /etc/network/interfaces
	echo "    netmask ${SLUGSN}" >> /etc/network/interfaces
	echo "    gateway ${SLUGDGW}" >> /etc/network/interfaces

	#recreate /etc/resolf.conf
	rm -f /etc/resolv.conf
	echo "search workgroup" >> /etc/resolf.conf
	echo "nameserver ${SLUGDNS}" >> /etc/resolv.conf
fi

#done
echo "Changes done. execute shutdown -r now to restart with new settings."

I hope this helps.

Popularity: 100% [?]

Dec 16 / Scotty

CakePHP ExtendAssociations – HABTM Update by HABTM primary key

For a few years now I have been using Brandon Parise’s great CakePHP behaviour, ExtendAssociations, which I originally found here at the Bakery. Lately I have been developing an app that has a HABTM relationship that has extra data stored in the relationship, and also can have multiple entries for the same association.
To explain further, I have a Sale model, that can be associated to multiple Items. each association stores the sale price and the quantity of the item. Also, say for example a Sale has 4 of Item X associated to it at £99, this cound be added to at a later date with 2 Item X at £130 for example. Since each HABTM association cannot be identified uniquely by the tuple of sale_id and item_id, the HABTM table must have a primary key field for itself.

The original ExtendAssociations update action did not provide an update action. I provided one a while ago here, but this is not sufficient for the scenario mentioned above, so here is another action which can update an HABTM association using the HABTM join table primary key as a reference:

function habtmUpdatePrimary(&$model, $assoc, $ids = array(), $extra = array() ) {
		if(!is_array($ids)) {
			$extra = array($extra);
			$ids = array($ids);
		}

		// make sure the association exists
		if(isset($model->hasAndBelongsToMany[$assoc])) {
			// get association data
			$joinTable = $model->hasAndBelongsToMany[$assoc]['joinTable'];
			$associationForeignKey = $model->hasAndBelongsToMany[$assoc]['associationForeignKey'];
			$foreignKey = $model->hasAndBelongsToMany[$assoc]['foreignKey'];

			$joinClass = array($model->name, $assoc);
			sort($joinClass);
			$joinClass = Inflector::pluralize($joinClass[0]) . $joinClass[1];
			$joinTablePrimaryKey = $model->$joinClass->primaryKey;

			if( !empty($joinTable) && !empty($joinTablePrimaryKey) ) {

				$success = true;
				foreach($ids as  $index => $id)
				{
					// execute SQL query for each $id
					$sql = array();
					foreach( $extra[$index] as $key => $value ) {
					    if ($value != null) {
							$sql[] = $key . " = '". addslashes($value) . "'";
						} else {
                			$sql[] = $key . " = NULL";
              			}
          			}
					$result = $model->query( "UPDATE `$model->tablePrefix.$joinTable` set ".implode( "," , $sql )." WHERE $joinTablePrimaryKey = $id");
					if (!$result) $success = false;
				}
				return $success;
			} else {
				// invalid join table name or primary key field name
				return false;
			}
		} else {
			// association doesn't exist, return false
			return false;
		}
	}

Here is the associated action to delete a HABTM by join table primary key:

function habtmDeletePrimary(&$model, $assoc, $ids) {
if(!is_array($ids))
$ids = array($ids);

// make sure the association exists
if(isset($model->hasAndBelongsToMany[$assoc])) {

//get extra data
$joinTable = $model->hasAndBelongsToMany[$assoc]['joinTable'];
$foreignKey = $model->hasAndBelongsToMany[$assoc]['foreignKey'];
$associationForeignKey = $model->hasAndBelongsToMany[$assoc]['associationForeignKey'];

$joinClass = array($model->name, $assoc);
sort($joinClass);
$joinClass = Inflector::pluralize($joinClass[0]) . $joinClass[1];
$joinTablePrimaryKey = $model->$joinClass->primaryKey;

$sql = "DELETE FROM `$model->tablePrefix.$joinTable` WHERE ";
$first = true;
foreach($ids as $id)
{
$sql .= ($first?"":" OR ") . "`$joinTablePrimaryKey` = '$id'";
$first = false;
}

// execute SQL
$success = $model->query($sql);
return $success;
}

// association doesn't exist, return false
return false;
}

Here is the full code for the version of ExtendAssociations that I currently use – any comments / criticisms / improvements welcome. I would again like to thank Brandon Parise for graciously publishing the original Behaviour, nice work!

/**
* Extend Associations Behavior
* Extends some basic add/delete function to the HABTM relationship
* in CakePHP.  Also includes an unbindAll($exceptions=array()) for
* unbinding ALL associations on the fly.
*
* Now also adds / updates extra data (ie fields in the HABTM join table other than the keys),
* as well as handling HABTMs that have multiple entries for the same association
* and their own primary key.
*
* This code is loosely based on the concepts from:
* http://rossoft.wordpress.com/2006/08/23/working-with-habtm-associations/
*
* @author Brandon Parise <brandon@parisemedia.com>, updated and extended by Scott Donnelly <scott@donnel.ly>
* @package CakePHP Behaviors
*
*/
class ExtendAssociationsBehavior extends ModelBehavior {
/**
* Model-specific settings
* @var array
*/
var $settings = array();

/**
* Setup
* Noething sp
*
* @param unknown_type $model
* @param unknown_type $settings
*/
function setup(&$model, $settings = array()) {
// no special setup required
$this->settings[$model->name] = $settings;
}

/**
* Add an HABTM association
*
* @param Model $model
* @param string $assoc
* @param int $id
* @param mixed $assoc_ids
* @return boolean
*/
function habtmAdd(&$model, $assoc, $id, $assoc_ids , $extra = array() ) {
if(!is_array($assoc_ids)) {
$assoc_ids = array($assoc_ids);
$extra = array($extra);
}

// make sure the association exists
if(isset($model->hasAndBelongsToMany[$assoc])) {

// get association data
$joinTable = $model->hasAndBelongsToMany[$assoc]['joinTable'];
$associationForeignKey = $model->hasAndBelongsToMany[$assoc]['associationForeignKey'];
$foreignKey = $model->hasAndBelongsToMany[$assoc]['foreignKey'];

$success = true;
$n = 0;

if( !empty( $joinTable ) ) {
foreach($assoc_ids as $assoc_id)
{
// execute SQL query for each $assoc_id
$values = array("'" . $id . "'", "'" . $assoc_id . "'");
$cols = array("`" . $foreignKey . "`", "`" . $associationForeignKey . "`");
foreach( $extra[$n] as $key => $value )
{
array_push($cols, '`' . $key . '`');
array_push($values, "'" . addslashes($value) . "'");
}

$n++;
$result = $model->query( "INSERT INTO `$model->tablePrefix.$joinTable` (" . implode( ", ", $cols) . ") VALUES (" . implode( "," , $values ) . ")");
if (!$result) $success = false;
}
} else {
return false;
}
return $success;
}

// association doesn't exist, return false
return false;
}

/**
* Delete an HABTM Association
*
* @param Model $model
* @param string $assoc
* @param int $id
* @param mixed $assoc_ids
* @return boolean
*/
function habtmDelete(&$model, $assoc, $id, $assoc_ids) {
if(!is_array($assoc_ids))
$assoc_ids = array($assoc_ids);

// make sure the association exists
if(isset($model->hasAndBelongsToMany[$assoc])) {

//get extra data
$joinTable = $model->hasAndBelongsToMany[$assoc]['joinTable'];
$foreignKey = $model->hasAndBelongsToMany[$assoc]['foreignKey'];
$associationForeignKey = $model->hasAndBelongsToMany[$assoc]['associationForeignKey'];

//build SQL query
$sql = "DELETE FROM `$model->tablePrefix.$joinTable` WHERE `$foreignKey` = '$id'";
if($assoc_ids[0] != '*') {
$sql .= " AND (";
$first = true;
foreach($assoc_ids as $assoc_id)
{
$sql .= ($first?"":" OR ") . "`$associationForeignKey` = '$assoc_id'";
$first = false;
}
$sql .= ")";
}

// execute SQL
$success = $model->query($sql);
return $success;
}

// association doesn't exist, return false
return false;
}

/**
* Delete an HABTM Association, specified by primary key id, rather than foreignkey / associationforeignkey
*
* @param Model $model
* @param string $assoc
* @param mixed $ids
* @return boolean
*/
function habtmDeletePrimary(&$model, $assoc, $ids) {
if(!is_array($ids))
$ids = array($ids);

// make sure the association exists
if(isset($model->hasAndBelongsToMany[$assoc])) {

//get extra data
$joinTable = $model->hasAndBelongsToMany[$assoc]['joinTable'];
$foreignKey = $model->hasAndBelongsToMany[$assoc]['foreignKey'];
$associationForeignKey = $model->hasAndBelongsToMany[$assoc]['associationForeignKey'];

$joinClass = array($model->name, $assoc);
sort($joinClass);
$joinClass = Inflector::pluralize($joinClass[0]) . $joinClass[1];
$joinTablePrimaryKey = $model->$joinClass->primaryKey;

$sql = "DELETE FROM `$model->tablePrefix.$joinTable` WHERE ";
$first = true;
foreach($ids as $id)
{
$sql .= ($first?"":" OR ") . "`$joinTablePrimaryKey` = '$id'";
$first = false;
}

// execute SQL
$success = $model->query($sql);
return $success;
}

// association doesn't exist, return false
return false;
}

/**
* update HABTM Associations, including extra data, referenced by joined models primary keys
*
* @param Model $model
* @param string $assoc
* @param int $id
* @param int $assoc_ids
* @param mixed $extra
* @return boolean
*/
function habtmUpdate(&$model, $assoc, $id, $assoc_ids, $extra = array() ) {
if(!is_array($assoc_ids)) {
$assoc_ids = array($assoc_ids);
$extra = array($extra);
}

// make sure the association exists
if(isset($model->hasAndBelongsToMany[$assoc])) {

// get association data
$joinTable = $model->hasAndBelongsToMany[$assoc]['joinTable'];
$associationForeignKey = $model->hasAndBelongsToMany[$assoc]['associationForeignKey'];
$foreignKey = $model->hasAndBelongsToMany[$assoc]['foreignKey'];

if( !empty( $joinTable ) ) {

$success = true;
foreach($assoc_ids as $index => $assoc_id)
{
// build query for each $assoc_id
$sql = array();
foreach( $extra[$index] as $key => $value ) {
if ($value != null) {
$sql[] = $key . " = '". addslashes($value) . "'";
} else {
$sql[] = $key . " = NULL";
}
}
// update each association with the new values
$result = $model->query( "UPDATE `$model->tablePrefix.$joinTable` set ".implode( "," , $sql )." WHERE $foreignKey = $id AND $associationForeignKey = '$assoc_id'");
if (!$result) $success = false;
}

return $success;
} else {
// join table not specified, return false
return false;
}
} else {
// association doesn't exist, return false
return false;
}
}

/**
* retrieve HABTM Associations, accessed by join table primary key
*
* @param Model $model
* @param string $assoc
* @param int $id
* @return boolean
*/
function habtmFetch(&$model, $assoc, $ids) {
if(!is_array($ids))
$ids = array($ids);

// make sure the association exists
if(isset($model->hasAndBelongsToMany[$assoc])) {

// get association data
$joinTable = $model->hasAndBelongsToMany[$assoc]['joinTable'];
$associationForeignKey = $model->hasAndBelongsToMany[$assoc]['associationForeignKey'];
$foreignKey = $model->hasAndBelongsToMany[$assoc]['foreignKey'];

$joinClass = array($model->name, $assoc);
sort($joinClass);
$joinClass = Inflector::pluralize($joinClass[0]) . $joinClass[1];
$joinTablePrimaryKey = $model->$joinClass->primaryKey;

$n = 0;
if( !empty( $joinTable ) )
{
$whereClause = "(";
foreach($ids as $id)
{
// craft where clause
if ($n > 0) $whereClause .= " OR ";
$whereClause .= "$joinTablePrimaryKey = $id";
$n++;
}
$whereClause .=")";

$res = $model->query( "SELECT * FROM `$model->tablePrefix.$joinTable` WHERE $whereClause");
}
return $res;
}
// association doesn't exist, return false
return false;
}

/**
* Update HABTM Associations, accessed by join table primary key
*
* @param Model $model
* @param string $assoc
* @param int $id
* @param mixed $extra
* @return boolean
*/
function habtmUpdatePrimary(&$model, $assoc, $ids = array(), $extra = array() ) {
if(!is_array($ids)) {
$extra = array($extra);
$ids = array($ids);
}

// make sure the association exists
if(isset($model->hasAndBelongsToMany[$assoc])) {
// get association data
$joinTable = $model->hasAndBelongsToMany[$assoc]['joinTable'];
$associationForeignKey = $model->hasAndBelongsToMany[$assoc]['associationForeignKey'];
$foreignKey = $model->hasAndBelongsToMany[$assoc]['foreignKey'];

$joinClass = array($model->name, $assoc);
sort($joinClass);
$joinClass = Inflector::pluralize($joinClass[0]) . $joinClass[1];
$joinTablePrimaryKey = $model->$joinClass->primaryKey;

if( !empty($joinTable) && !empty($joinTablePrimaryKey) ) {

$success = true;
foreach($ids as  $index => $id)
{
// execute SQL query for each $id
$sql = array();
foreach( $extra[$index] as $key => $value ) {
if ($value != null) {
$sql[] = $key . " = '". addslashes($value) . "'";
} else {
$sql[] = $key . " = NULL";
}
}
$result = $model->query( "UPDATE `$model->tablePrefix.$joinTable` set ".implode( "," , $sql )." WHERE $joinTablePrimaryKey = $id");
if (!$result) $success = false;
}
return $success;
} else {
// invalid join table name or primary key field name
return false;
}
} else {
// association doesn't exist, return false
return false;
}
}

/**
* Delete All HABTM Associations
* Just a nicer way to do easily delete all.
*
* @param Model $model
* @param string $assoc
* @param int $id
* @return boolean
*/
function habtmDeleteAll(&$model, $assoc, $id) {
return $this->habtmDelete($model, $assoc, $id, '*');
}

/**
* Find
* This method allows cake to do the dirty work to
* fetch the current HABTM association.
*
* @param Model $model
* @param string $assoc
* @param int $id
* @return array
*/
function __habtmFind(&$model, $assoc, $id) {
// temp holder for model-sensitive params
$tmp_recursive = $model->recursive;
$tmp_cacheQueries = $model->cacheQueries;

$model->recursive = 1;
$model->cacheQueries = false;

// unbind all models except the habtm association
$this->unbindAll($model, array('hasAndBelongsToMany' => array($assoc)));
$data = $model->find(array($model->name.'.'.$model->primaryKey => $id));

$model->recursive = $tmp_recursive;
$model->cacheQueries = $tmp_cacheQueries;

if(!empty($data)) {
// use Set::extract to extract the id's ONLY of the $assoc
$data[$assoc] = array($assoc => Set::extract($data, $assoc.'.{n}.'.$model->primaryKey));
}

return $data;
}

/**
* UnbindAll with Exceptions
* Allows you to quickly unbindAll of a model's
* associations with the exception of param 2.
*
* Usage:
*   $this->Model->unbindAll(); // unbinds ALL
*   $this->Model->unbindAll(array('hasMany' => array('Model2')) // unbind All except hasMany-Model2
*
* @param Model $model
* @param array $exceptions
*/
function unbindAll(&$model, $exceptions = array()) {
$unbind = array();
foreach($model->__associations as $type) {
foreach($model->{$type} as $assoc=>$assocData) {
// if the assoc is NOT in the exceptions list then
// add it to the list of models to be unbound.
if(@!in_array($assoc, $exceptions[$type])) {
$unbind[$type][] = $assoc;
}
}
}
// if we actually have models to unbind
if(count($unbind) > 0) {
$model->unbindModel($unbind);
}
}
}
$model->tablePrefix.

Popularity: 36% [?]

Aug 9 / Scotty

BCM50 SIP DTMF update 2

The BCM50 sends SIP INFO messages for DTMF. using Asterisk’s SIPDtmfMode() application, the DTMF send mode can be forced to in-band. Since the call has been set up as G711, in-band DTMF will still be intelligible by the far end. I have tested this in our lab set-up, and it works fine, so that is issue 1 out of the way. As for issue 2, I have placed a call to a number which I know will not answer (Looks like I’m the only mug that works on a Saturday :-) ). The call rang out for over 2 minutes before receiving a SIP 486 (user busy) from Voiceflex, with their Asterisk server setting X-Asterisk-HangupCause as “Network out of order”. 2 minutes seems like plenty of time to be ringing to me, most likely this is limited by a max ringing timeout timer somewhere along the line, either at Voiceflex or on the PSTN.

Popularity: 9% [?]

Aug 9 / Scotty

BCM50 SIP trunk update

I have now deployed the solution mentioned in the previous post “in-the-wild”, running on an NSLU2 via unslung. A bit of tweaking was required, but the solution has been up and running for over a week now with only a couple of slight issues:

1) Sending DTMF does not work. This is possibly due to using G.729 rather than aLaw, assuming the BCM50 uses in-band DTMF. I will investigate further, as it may be that Voiceflex have my SIP trunks configured to use SIP INFO or RFC2833.

2) When calling a PSTN number from the BCM, if the call is ringing longer than a certain time, the call is disconnected. I will replicate this in the lab to determine the cause.

UPDATE:

I have a couple of updates to this – see BCM50 SIP Update 2, and Here

Popularity: 8% [?]

Jul 19 / Scotty

Eureka!

I have managed to get a BCM50 Release 2 to communicate with an authenticating public SIP trunk provider (Voiceflex, in case you are wondering.) Now, neither Voiceflex, nor Nortel support this. According to our suppliers, nobody else is doing this. But, by putting Asterisk in between them (which Voiceflex seem to be using too, judging from their voice prompts), I have the BCM50 working fine on Voiceflex’s SIP trunks.
Now all I need to do is get it up and running on an NSLU2 or similar.

Watch this space to find out how it goes at a client site.

UPDATE – Voiceflex now do support this – if you are connecting from a static WAN address, they will allow connections from this IP without authentication if you request it. If you are using the BCM50 (this includes release 3), this will work for you – unless you have a dynamic WAN address, in which case the technique mentioned here is still useful.

Popularity: 7% [?]

Jul 17 / Scotty

Is it not my day, or am I just shit with virtualization?

After converting the vdi to a vmdk, the VMware VM a) has the vmdk stuck at 2.5Gb and full instead of 10Gb, and b) does not boot. Grrraaaaaaaaaagh!

I am reinstalling the OS onto a new mdk from scratch instead, I only had XP, uVNC, and ACT! on there, I can reinstall quicker than it will be faffing around with vmware-vdiskmanager and the like.

Popularity: 1% [?]

Jul 17 / Scotty

VirtualBox Host interface networking is rubbish

What a total nightmare it is trying to get VirtualBox’s host interface networking to work. The only way I can see to get it working on a windows host is by using ICS or a network bridge – both not possible on a 2003 Server. (please somebody prove me wrong.) Why can’t it be like VMWare and Just Work? Virtualbox’s user manual helpfully states “If your host is running Windows XP or newer, you can also use the built-in bridging feature to connect your host interfaces to your physical network card.” Last time I checked, Server 2003 R2 is newer than XP. Perhaps innotek did not envisage the need to run a VM on a server PC. Well, thats a morning wasted, now I am going to try to migrate the vmdk to VMWare instead. oh, joy.

EDIT: In case you need to know, you can convert VirtualBox-style VDI images to VMWare VMDK images by using qemu. the syntax is:

qemu-img convert original.vdi new.vmdk

Popularity: 5% [?]

Jul 17 / Scotty

I’m back!

Its been a while since I’ve posted, so I’ve taken some time out to sort out a few aspects of my online persona. As anyone who knows me knows, I’m not a big facebook fan – it’s just not my thing. So I am going to try to make a concerted effort to use all the tools and tricks that all self-respecting up-to-the-minute geeks should be using – del.icio.us, Twitter, jabber, and my blog.

I want to start posting more articles on things like CakePHP, Asterisk, OpenSER, SIP/SIMPLE, DirectX, Linux, Astrophotography, Electronics, and all the other stuff that I do that may be interesting to some people out there of a more technical bent.

So lets hope this turning over of a new leaf on my blog lasts, and maybe someone may find it useful, who knows?!

Popularity: 1% [?]

May 6 / Scotty

Congratulations, Mr and Mrs Bowes!

Congratulations to Laura and Tim, who got married on Saturday, and are know sunning it up in Jamaica for a week!

A great day was had by all, cant believe my little sis is married and has her own house. The service, reception, band, wedding car, everything were all fantastic. Hope you are both together forever, me and Sarah will come visit you soon!

x

Popularity: 1% [?]

Feb 20 / Scotty

CakePHP 1.2 RSSHelper example

There seems to be precious little information out there regarding CakePHP 1.2′s RSSHelper. so here is a quick how-to:

Controller:
function rss() {
$this->layoutPath = 'rss';

$this->Appointment->recursive = 0;

$this->set('data', $this->Appointment->findAll());

$this->set('channel', array('title' => "Recent Appointments",
'link' => "/appointments/rss",
'description' => "Recently Booked Appointments" ));
}

View:

function xformRSS($data)

{

return array('title' => "New Appointment",
   'link' => "/appointments/view/" . $data['Appointment']['id'],
   'guid' => "/appointments/view/" . $data['Appointment']['id'],
   'description' => $data['Appointment']['description'],
   'pubDate' => $data['Appointment']['created']);

}

echo $rss->items($data, 'xformRSS');

Popularity: 13% [?]