diff --git a/.gitignore b/.gitignore
index 16acc6448..bfce84f17 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,7 @@ opt/gemeinschaft/etc/asterisk/extensions.ael
*.pyc
.gemeinschaft-version
*.komodoproject
+
+# exclude yealink firmware images
+opt/gemeinschaft/htdocs/prov/yealink/fw/*.rom
+
diff --git a/etc/asterisk/asterisk.conf b/etc/asterisk/asterisk.conf
index 33fe71975..391c7f148 100644
--- a/etc/asterisk/asterisk.conf
+++ b/etc/asterisk/asterisk.conf
@@ -32,7 +32,7 @@
astetcdir => /opt/gemeinschaft/etc/asterisk
astmoddir => /usr/lib/asterisk/modules
astvarlibdir => /var/lib/asterisk
-astdatadir => /var/lib/asterisk
+astdatadir => /usr/share/asterisk
astagidir => /var/lib/asterisk/agi-bin
astspooldir => /var/spool/asterisk
astrundir => /var/run/asterisk
diff --git a/etc/gemeinschaft/gemeinschaft.php b/etc/gemeinschaft/gemeinschaft.php
index 75fc80761..d35c4d7a7 100644
--- a/etc/gemeinschaft/gemeinschaft.php
+++ b/etc/gemeinschaft/gemeinschaft.php
@@ -275,6 +275,7 @@
//$PROV_MODELS_ENABLED_AASTRA = '*'; # or '51i,53i,55i,57i'
//$PROV_MODELS_ENABLED_GRANDSTREAM = '*'; # or 'bt110,gxp2000,gxp2020', ...
//$PROV_MODELS_ENABLED_TIPTEL = '*'; # or 'ip280,ip284,ip286'
+//$PROV_MODELS_ENABLED_YEALINK = '*'; # or 'yealink-sip-t46g,yealink-sip-t48g'
//$PROV_MODELS_ENABLED_POLYCOM = '*'; # or 'spip-550,spip-670', ...
@@ -490,6 +491,56 @@
# 'f20' Private Hold
# 'f27' XML Browser
+//-----------------------[ Yealink ]-----------------------//
+
+$YEALINK_PROV_ENABLED = true; # do provisioning for Yealink?
+
+$YEALINK_PROV_HTTP_PASS = 'admin'; # e.g. "gEheiM23y89sdo23", default: 'admin'
+ # to password protect the phone's web gui.
+ # changing these values will likely cause automatic rebooting to fail
+
+//$YEALINK_PROV_NTP = @$PROV_HOST;
+//$YEALINK_PROV_NTP = '192.168.1.130';
+ # NTP Server. the stupid Tiptel needs it
+
+ # Set $LOG_LEVEL to "NOTICE" or even "DEBUG" and
+ # tail -f /var/log/gemeinschaft/gs.log
+ # Test the update mechanism with 1 or 2 phones. This is especially
+ # important with PoE (Power over Ethernet) switches.
+$YEALINK_PROV_FW_UPDATE = false; # allow firmware updates?
+
+//$YEALINK_PROV_KEY_BLACKLIST = '';
+ # do not show these softkey functions in GUI,
+ # comma separated list (e.g. 'f5,f12,f17'), default: ''
+ # 'f13' SpeedDial
+ # 'f16' BLF
+ # 'f1' Conference
+ # 'f2' Forward
+ # 'f3' Transfer
+ # 'f4' Hold
+ # 'f5' DND
+ # 'f6' Redial
+ # 'f7' Call Return
+ # 'f8' SMS
+ # 'f9' Call Pickup
+ # 'f10' Call Park
+ # 'f11' Custom
+ # 'f12' Voicemail
+ # 'f14' Intercom
+ # 'f15' Line
+ # 'f17' URL
+ # 'f18' Group Listening
+ # 'f19' Public Hold
+ # 'f20' Private Hold
+ # 'f27' XML Browser
+
+$YEALINK_PROV_FW_DEFAULT_SIP_T42G = '';
+$YEALINK_PROV_FW_DEFAULT_SIP_T46G = '';
+$YEALINK_PROV_FW_DEFAULT_SIP_T48G = '';
+
+$YEALINK_PROV_FW_DEFAULT_SIP_T42S = '';
+$YEALINK_PROV_FW_DEFAULT_SIP_T46S = '';
+$YEALINK_PROV_FW_DEFAULT_SIP_T46U = '';
//-----------------------[ Polycom ]----------------------//
@@ -676,6 +727,9 @@
//$FAX_INIT_DOCDIR = '/tmp/';
# directory containing fax documents to be used by "send-fax.php"
+//$FAX_MAP_IAXMODEM_USER = "";
+ # use group membership of user for dialout by IAXmodem
+
/***********************************************************
* BRANCH OFFICE INTEGRATION (BOI)
***********************************************************/
diff --git a/install.sh b/install.sh
index a84b9ad2f..9e4b96faa 100644
--- a/install.sh
+++ b/install.sh
@@ -219,7 +219,7 @@ ${APTITUDE_INSTALL} \
vim less git linux-headers-$(uname -r) \
gcc make gcc make ncurses-dev zlib1g-dev \
g++ libxml2-dev doxygen libmysql++-dev libcrypto++-dev libssl-dev \
- libportaudio2 portaudio19-dev libasound-dev
+ libportaudio2 portaudio19-dev libasound-dev lame
# now that we have vim, enable syntax highlighting by default:
if ( which vim 1>>/dev/null 2>>/dev/null ); then
@@ -302,6 +302,24 @@ sleep 3
#
sed -i -r -e 's/^(RAMRUN=)no/\1yes/' /etc/default/rcS || true
+# install libjansson-dev, sqlite3, libsqlite-dev
+#
+echo ""
+echo "***"
+echo "*** Installing libjansson-dev, sqlite3, libsqlite3-dev ..."
+echo "***"
+if ( ! which libjansson-dev 1>>/dev/null 2>>/dev/null ); then
+ ${APTITUDE_INSTALL} libjansson-dev
+fi
+if ( ! which sqlite3 1>>/dev/null 2>>/dev/null ); then
+ ${APTITUDE_INSTALL} sqlite3
+fi
+if ( ! which libsqlite3-dev 1>>/dev/null 2>>/dev/null ); then
+ ${APTITUDE_INSTALL} libsqlite3-dev
+fi
+if ( ! which uuid-dev 1>>/dev/null 2>>/dev/null ); then
+ ${APTITUDE_INSTALL} uuid-dev
+fi
# install dahdi
#
@@ -319,14 +337,37 @@ make config
# generate /etc/dahdi/system.conf:
dahdi_genconf || true
+# install asterisk
+#
+echo ""
+echo "***"
+echo "*** Installing Asterisk ..."
+echo "***"
cd /usr/local/src/
-$DOWNLOAD "http://downloads.asterisk.org/pub/telephony/asterisk/asterisk-13-current.tar.gz"
-tar -xvzf asterisk-13-current.tar.gz
-cd $(tar -tzf asterisk-13-current.tar.gz | head -n 1 | cut -d '/' -f1)
+$DOWNLOAD "http://downloads.asterisk.org/pub/telephony/asterisk/old-releases/asterisk-13.15.1.tar.gz"
+$DOWNLOAD "https://issues.asterisk.org/jira/secure/attachment/55471/asterisk-13.13.1-one-way-audio.patch"
+tar -xvzf asterisk-13.15.1.tar.gz
+cd $(tar -tzf asterisk-13.15.1.tar.gz | head -n 1 | cut -d '/' -f1)
+
+# patch asterisk
+#
+echo ""
+echo "***"
+echo "*** Patching Asterisk ..."
+echo "***"
+# Patch against 1-way-audio when transcoding
+patch -p0 < ../asterisk-13.13.1-one-way-audio.patch
+
+# read -p "Patching completed, Press enter to continue"
+
./configure
make menuselect.makeopts
menuselect/menuselect --enable res_config_mysql menuselect.makeopts
menuselect/menuselect --enable cdr_mysql menuselect.makeopts
+menuselect/menuselect --enable app_meetme menuselect.makeopts
+menuselect/menuselect --enable app_setcallerid menuselect.makeopts
+# read -p "Setting asterisk options completed, Press enter to continue"
+
make
make install
make samples
@@ -391,7 +432,7 @@ ${APTITUDE_INSTALL} \
sipsak \
mysql-client mysql-server \
apache2 \
- php5-cli libapache2-mod-php5 php5-mysql php5-ldap \
+ php5-cli libapache2-mod-php5 php5-mysql php5-ldap php5-curl \
python2.6 \
python-mysqldb \
sox libsox-fmt-all mpg123
diff --git a/opt/gemeinschaft/dialplan-scripts/in-user-get-ringer.agi b/opt/gemeinschaft/dialplan-scripts/in-user-get-ringer.agi
index c604adf2d..40e5ac88c 100755
--- a/opt/gemeinschaft/dialplan-scripts/in-user-get-ringer.agi
+++ b/opt/gemeinschaft/dialplan-scripts/in-user-get-ringer.agi
@@ -208,6 +208,23 @@ elseif (strToLower(subStr($user['phone_type'],0,6)) === 'tiptel') {
}
}
+}
+elseif (strToLower(subStr($user['phone_type'],0,7)) === 'yealink') {
+
+ $ringtones = _get_ringers( $user['id'] );
+
+ if (@$ringtones[$source]['file']) {
+ gs_agi_set_variable( 'ringer', ('<'. GS_PROV_SCHEME .'://'. GS_PROV_HOST . (GS_PROV_PORT ? ':'.GS_PROV_PORT : '') . GS_PROV_PATH .'ringtones/'. $ringtones[$source]['file'] .'-tiptel.wav>') );
+ } elseif (array_key_exists('bellcore', $ringtones[$source])) {
+
+ if (@$ringtones[$source]['bellcore'] == 1) exit();
+ if (@$ringtones[$source]['bellcore'] != 0) {
+ gs_agi_set_variable( 'ringer', ('Bellcore-dr'. $ringtones[$source]['bellcore'] ) );
+ } else {
+ gs_agi_set_variable( 'ringer', ('Bellcore-dr0') );
+ }
+ }
+
}
else {
diff --git a/opt/gemeinschaft/dialplan-scripts/out-route.agi b/opt/gemeinschaft/dialplan-scripts/out-route.agi
index c2ed28fc4..dacae1736 100755
--- a/opt/gemeinschaft/dialplan-scripts/out-route.agi
+++ b/opt/gemeinschaft/dialplan-scripts/out-route.agi
@@ -70,6 +70,19 @@ $user_id = (int)trim($argv[4]);
include_once( GS_DIR .'inc/db_connect.php' );
+// Map user for use by IAXmodem if configured
+if ($argv[4] == 'IAXmodem') {
+ # use map user from gemeinschaft.php
+
+ $db = gs_db_slave_connect();
+ if (! $db) gs_agi_err( 'DB error' );
+
+ $user_id = (int)$db->executeGetOne( 'SELECT `id` FROM `users` WHERE `user`=\''. $db->escape(gs_get_conf('GS_FAX_MAP_IAXMODEM_USER')) .'\'' );
+ if ($user_id < 1) $user_id=0;
+}
+else {
+ $user_id = (int)trim($argv[4]);
+}
$qualify_cid = true;
diff --git a/opt/gemeinschaft/etc/asterisk/iax-nodes.conf.php b/opt/gemeinschaft/etc/asterisk/iax-nodes.conf.php
index 70ef9ffce..a91af7fac 100755
--- a/opt/gemeinschaft/etc/asterisk/iax-nodes.conf.php
+++ b/opt/gemeinschaft/etc/asterisk/iax-nodes.conf.php
@@ -134,6 +134,7 @@
$params['permit' ] = null;
$codecs_allow = array();
+ $codecs_allow['g722' ] = false;
$codecs_allow['alaw' ] = true;
$codecs_allow['ulaw' ] = false;
diff --git a/opt/gemeinschaft/etc/asterisk/sip-nodes.conf.php b/opt/gemeinschaft/etc/asterisk/sip-nodes.conf.php
index 85d9a3568..71cab40e2 100755
--- a/opt/gemeinschaft/etc/asterisk/sip-nodes.conf.php
+++ b/opt/gemeinschaft/etc/asterisk/sip-nodes.conf.php
@@ -138,6 +138,7 @@
$params['permit' ] = null;
$codecs_allow = array();
+ $codecs_allow['g722' ] = false;
$codecs_allow['alaw' ] = true;
$codecs_allow['ulaw' ] = false;
diff --git a/opt/gemeinschaft/etc/asterisk/sip_notify.conf b/opt/gemeinschaft/etc/asterisk/sip_notify.conf
index ab36a3b0d..ae758bc22 100644
--- a/opt/gemeinschaft/etc/asterisk/sip_notify.conf
+++ b/opt/gemeinschaft/etc/asterisk/sip_notify.conf
@@ -122,3 +122,11 @@ Content-Length=>0
;Content-Length=>0
+;------------------------------- Yealink
+[yealink-check-cfg]
+Event=>check-sync\;reboot=false
+
+[yealink-check-cfg-reboot]
+Event=>check-sync\;reboot=true
+
+
diff --git a/opt/gemeinschaft/htdocs/gui/mod/admin_users.php b/opt/gemeinschaft/htdocs/gui/mod/admin_users.php
index f6aa2d8ef..54d35bae0 100644
--- a/opt/gemeinschaft/htdocs/gui/mod/admin_users.php
+++ b/opt/gemeinschaft/htdocs/gui/mod/admin_users.php
@@ -36,6 +36,8 @@
include_once( GS_DIR .'inc/gs-fns/gs_user_external_number_del.php' );
include_once( GS_DIR .'inc/gs-fns/gs_pickupgroup_user_add.php' );
include_once( GS_DIR .'inc/gs-fns/gs_callblocking_set.php' );
+include_once( GS_DIR .'inc/gs-fns/gs_user_ip_by_ext.php' );
+include_once( GS_DIR .'inc/gs-fns/gs_user_phonemodel_get.php' );
include_once( GS_DIR .'inc/group-fns.php' );
require_once( GS_DIR .'inc/boi-soap/boi-api.php' );
include_once( GS_DIR .'lib/utf8-normalize/gs_utf_normal.php' );
@@ -1028,6 +1030,24 @@ function count_users_logged_in( $DB ) {
←
+
+ | : |
+
+
+ |
+
+
+ |
+
+
+ | : |
+
+
+ |
+
+
+ |
+
diff --git a/opt/gemeinschaft/htdocs/gui/mod/inc_keyprof.php b/opt/gemeinschaft/htdocs/gui/mod/inc_keyprof.php
index 32ef66661..e2205af8b 100644
--- a/opt/gemeinschaft/htdocs/gui/mod/inc_keyprof.php
+++ b/opt/gemeinschaft/htdocs/gui/mod/inc_keyprof.php
@@ -69,6 +69,12 @@
$phone_types['snom-710'] = 'Snom 710';
if (in_array('*', $enabled_models) || in_array('715', $enabled_models))
$phone_types['snom-715'] = 'Snom 715';
+ if (in_array('*', $enabled_models) || in_array('d305', $enabled_models))
+ $phone_types['snom-d305'] = 'Snom D305';
+ if (in_array('*', $enabled_models) || in_array('d315', $enabled_models))
+ $phone_types['snom-d315'] = 'Snom D315';
+ if (in_array('*', $enabled_models) || in_array('d375', $enabled_models))
+ $phone_types['snom-d375'] = 'Snom D375';
}
/*
# Maybe there will be some reason for enabling keys on Snom M3 phones in future.
@@ -114,7 +120,21 @@
if (in_array('*', $enabled_models) || in_array('ip286', $enabled_models))
$phone_types['tiptel-ip286'] = 'Tiptel IP 286';
}
-
+if (gs_get_conf('GS_YEALINK_PROV_ENABLED')) {
+ $enabled_models = preg_split('/[,\\s]+/', gs_get_conf('GS_PROV_MODELS_ENABLED_YEALINK'));
+ if (in_array('*', $enabled_models) || in_array('yealink-sip-t42g', $enabled_models))
+ $phone_types['yealink-sip-t42g' ] = 'Yealink SIP T42G';
+ if (in_array('*', $enabled_models) || in_array('yealink-sip-t46g', $enabled_models))
+ $phone_types['yealink-sip-t46g' ] = 'Yealink SIP T46G';
+ if (in_array('*', $enabled_models) || in_array('yealink-sip-t48g', $enabled_models))
+ $phone_types['yealink-sip-t48g' ] = 'Yealink SIP T48G';
+ if (in_array('*', $enabled_models) || in_array('yealink-sip-t42s', $enabled_models))
+ $phone_types['yealink-sip-t42s' ] = 'Yealink SIP T42S';
+ if (in_array('*', $enabled_models) || in_array('yealink-sip-t46s', $enabled_models))
+ $phone_types['yealink-sip-t46s' ] = 'Yealink SIP T46S';
+ if (in_array('*', $enabled_models) || in_array('yealink-sip-t46u', $enabled_models))
+ $phone_types['yealink-sip-t46u' ] = 'Yealink SIP T46U';
+ }
$key_functions_snom = array(
'none' => __('Leer'), # none
@@ -235,6 +255,36 @@
unset($key_functions_tiptel[$keyfn]);
}
+$key_functions_yealink = array(
+ 'f0' => __('Leer'),
+ 'f13' => __('Zielwahl'), # SpeedDial
+ 'f16' => __('BLF'), # BLF
+ //'f1' => __('Konferenz'), # Conference
+ //'f2' => __('Forward'), # Forward
+ 'f3' => __('Übergabe'), # Transfer
+ 'f4' => __('Halten'), # Hold
+ 'f5' => __('Nicht stören'), # DND
+ //'f6' => __('Redial'), # Redial
+ //'f7' => __('CallReturn'), # Call Return
+ //'f8' => __('SMS'), # SMS
+ //'f9' => __('CallPickup'), # Call Pickup
+ //'f10' => __('CallPark'), # Call Park
+ //'f11' => __('Custom'), # Custom
+ //'f12' => __('Voicemail'), # Voicemail
+ //'f14' => __('Intercom'), # Intercom
+ //'f15' => __('Leitung'), # Line (for line key only)
+ //'f17' => __('URL'), # URL
+ //'f18' => __('GroupListening'), # Group Listening
+ //'f19' => __('PublicHold'), # Public Hold
+ //'f20' => __('PrivateHold'), # Private Hold
+ //'f27' => __('XML Browser'), # XML Browser
+);
+$key_function_none_yealink = 'f0';
+$key_functions_blacklist = preg_split('/[\\s,]+/', gs_get_conf('GS_YEALINK_PROV_KEY_BLACKLIST'));
+foreach ($key_functions_blacklist as $keyfn) {
+ if (array_key_exists($keyfn, $key_functions_yealink))
+ unset($key_functions_yealink[$keyfn]);
+}
$key_default = array(
@@ -285,6 +335,9 @@
elseif (array_key_exists('snom-710', $phone_types)) $phone_type = 'snom-710';
elseif (array_key_exists('snom-715', $phone_types)) $phone_type = 'snom-715';
elseif (array_key_exists('snom-821', $phone_types)) $phone_type = 'snom-821';
+ elseif (array_key_exists('snom-d305', $phone_types)) $phone_type = 'snom-d305';
+ elseif (array_key_exists('snom-d315', $phone_types)) $phone_type = 'snom-d315';
+ elseif (array_key_exists('snom-d375', $phone_types)) $phone_type = 'snom-d375';
} else
if (gs_get_conf('GS_SIEMENS_PROV_ENABLED')) {
if (array_key_exists('siemens-os20', $phone_types)) $phone_type = 'siemens-os20';
@@ -307,8 +360,16 @@
if (array_key_exists('tiptel-ip284', $phone_types)) $phone_type = 'tiptel-ip284';
elseif (array_key_exists('tiptel-ip286', $phone_types)) $phone_type = 'tiptel-ip286';
}
+ if (gs_get_conf('GS_YEALINK_PROV_ENABLED')) {
+ if (array_key_exists('yealink-sip-t42g', $phone_types)) $phone_type = 'yealink-sip-t42g';
+ elseif (array_key_exists('yealink-sip-t46g', $phone_types)) $phone_type = 'yealink-sip-t46g';
+ elseif (array_key_exists('yealink-sip-t48g', $phone_types)) $phone_type = 'yealink-sip-t48g';
+ elseif (array_key_exists('yealink-sip-t42s', $phone_types)) $phone_type = 'yealink-sip-t42s';
+ elseif (array_key_exists('yealink-sip-t46s', $phone_types)) $phone_type = 'yealink-sip-t46s';
+ elseif (array_key_exists('yealink-sip-t46u', $phone_types)) $phone_type = 'yealink-sip-t46u';
+ }
}
-if (in_array($phone_type, array('snom-300', 'snom-320', 'snom-360', 'snom-370', 'snom-870', 'snom-760', 'snom-720', 'snom-725', 'snom-710', 'snom-715', 'snom-821'), true)) {
+if (in_array($phone_type, array('snom-300', 'snom-320', 'snom-360', 'snom-370', 'snom-870', 'snom-760', 'snom-720', 'snom-725', 'snom-710', 'snom-715', 'snom-821', 'snom-d305', 'snom-d315', 'snom-d375'), true)) {
$phone_layout = 'snom';
$key_function_none = $key_function_none_snom;
} elseif (in_array($phone_type, array('siemens-os20', 'siemens-os40', 'siemens-os60', 'siemens-os80'), true)) {
@@ -323,6 +384,9 @@
} elseif (in_array($phone_type, array('tiptel-ip284', 'tiptel-ip286'), true)) {
$phone_layout = 'tiptel';
$key_function_none = $key_function_none_tiptel;
+} elseif (in_array($phone_type, array('yealink-sip-t42g', 'yealink-sip-t46g', 'yealink-sip-t48g', 'yealink-sip-t42s', 'yealink-sip-t46s', 'yealink-sip-t46u'), true)) {
+ $phone_layout = 'yealink';
+ $key_function_none = $key_function_none_yealink;
} else {
$phone_layout = false;
$key_function_none = false;
@@ -1035,6 +1099,16 @@ function gs_dlg_abort()
//$key_levels[0]['to' ] = 15;
break;
}
+ switch ($phone_type) {
+ case 'snom-d305':
+ case 'snom-d315':
+ $key_levels = array(
+ 0 => array('from'> 0,
+ 'to' => 1, 'shifted'=>false,
+ 'title' => htmlEnt($phone_type_title))
+ );
+ break;
+ }
break;
case 'siemens':
//if ($show_ext_modules >= 0) {
@@ -1264,6 +1338,127 @@ function gs_dlg_abort()
'title'=> __('Erweiterungs-Modul') .' 3 '. __('Spalte') .' 2')
);
}
+ break;
+ case 'yealink':
+ switch($phone_type) {
+ case 'yealink-sip-t46g':
+ $key_levels = array(
+ 0 => array('from'=> 1, 'to'=> 27, 'shifted'=>false,
+ 'title'=> htmlEnt($phone_type_title))
+ );
+ break;
+ case 'yealink-sip-t46s':
+ $key_levels = array(
+ 0 => array('from'=> 1, 'to'=> 27, 'shifted'=>false,
+ 'title'=> htmlEnt($phone_type_title))
+ );
+ break;
+ case 'yealink-sip-t46u':
+ $key_levels = array(
+ 0 => array('from'=> 1, 'to'=> 27, 'shifted'=>false,
+ 'title'=> htmlEnt($phone_type_title))
+ );
+ break;
+ case 'yealink-sip-t48g':
+ $key_levels = array(
+ 0 => array('from'=> 1, 'to'=> 29, 'shifted'=>false,
+ 'title'=> htmlEnt($phone_type_title))
+ );
+ break;
+ case 'yealink-sip-t42g':
+ $show_ext_modules=0;
+ $key_levels = array(
+ 0 => array('from'=> 1, 'to'=> 15, 'shifted'=>false,
+ 'title'=> htmlEnt($phone_type_title))
+ );
+ break;
+ case 'yealink-sip-t42s':
+ $show_ext_modules=0;
+ $key_levels = array(
+ 0 => array('from'=> 1, 'to'=> 15, 'shifted'=>false,
+ 'title'=> htmlEnt($phone_type_title))
+ );
+ break;
+ }
+ // EXT43 with 3 layers
+ if ($phone_type == 'yealink-sip-t46u') {
+ if ($show_ext_modules >= 1) {
+ $key_levels += array(
+ 1 => array('from'=> 101, 'to'=> 120, 'shifted'=>false,
+ 'title'=> __('Erweiterungs-Modul') .' 1 '. __('Ebene') .' 1')
+ );
+ $key_levels += array(
+ 2 => array('from'=> 121, 'to'=> 140, 'shifted'=>false,
+ 'title'=> __('Erweiterungs-Modul') .' 1 '. __('Ebene') .' 2')
+ );
+ $key_levels += array(
+ 3 => array('from'=> 141, 'to'=> 160, 'shifted'=>false,
+ 'title'=> __('Erweiterungs-Modul') .' 1 '. __('Ebene') .' 3')
+ );
+ }
+ if ($show_ext_modules >= 2) {
+ $key_levels += array(
+ 4 => array('from'=> 201, 'to'=> 220, 'shifted'=>false,
+ 'title'=> __('Erweiterungs-Modul') .' 2 '. __('Ebene') .' 1')
+ );
+ $key_levels += array(
+ 5 => array('from'=> 221, 'to'=> 240, 'shifted'=>false,
+ 'title'=> __('Erweiterungs-Modul') .' 2 '. __('Ebene') .' 2')
+ );
+ $key_levels += array(
+ 6 => array('from'=> 241, 'to'=> 260, 'shifted'=>false,
+ 'title'=> __('Erweiterungs-Modul') .' 2 '. __('Ebene') .' 3')
+ );
+ }
+ if ($show_ext_modules >= 3) {
+ $key_levels += array(
+ 7 => array('from'=> 301, 'to'=> 320, 'shifted'=>false,
+ 'title'=> __('Erweiterungs-Modul') .' 3 '. __('Ebene') .' 1')
+ );
+ $key_levels += array(
+ 8 => array('from'=> 321, 'to'=> 340, 'shifted'=>false,
+ 'title'=> __('Erweiterungs-Modul') .' 3 '. __('Ebene') .' 2')
+ );
+ $key_levels += array(
+ 9 => array('from'=> 341, 'to'=> 360, 'shifted'=>false,
+ 'title'=> __('Erweiterungs-Modul') .' 3 '. __('Ebene') .' 3')
+ );
+ }
+ }
+ // EXT40 with 2 layers
+ else {
+ if ($show_ext_modules >= 1) {
+ $key_levels += array(
+ 1 => array('from'=> 101, 'to'=> 120, 'shifted'=>false,
+ 'title'=> __('Erweiterungs-Modul') .' 1 '. __('Ebene') .' 1')
+ );
+ $key_levels += array(
+ 2 => array('from'=> 121, 'to'=> 140, 'shifted'=>false,
+ 'title'=> __('Erweiterungs-Modul') .' 1 '. __('Ebene') .' 2')
+ );
+ }
+ if ($show_ext_modules >= 2) {
+ $key_levels += array(
+ 3 => array('from'=> 201, 'to'=> 220, 'shifted'=>false,
+ 'title'=> __('Erweiterungs-Modul') .' 2 '. __('Ebene') .' 1')
+ );
+ $key_levels += array(
+ 4 => array('from'=> 221, 'to'=> 240, 'shifted'=>false,
+ 'title'=> __('Erweiterungs-Modul') .' 2 '. __('Ebene') .' 2')
+ );
+ }
+ if ($show_ext_modules >= 3) {
+ $key_levels += array(
+ 5 => array('from'=> 301, 'to'=> 320, 'shifted'=>false,
+ 'title'=> __('Erweiterungs-Modul') .' 3 '. __('Ebene') .' 1')
+ );
+ $key_levels += array(
+ 6 => array('from'=> 321, 'to'=> 340, 'shifted'=>false,
+ 'title'=> __('Erweiterungs-Modul') .' 3 '. __('Ebene') .' 2')
+ );
+ }
+ }
+
break;
}
@@ -1331,6 +1526,10 @@ function gs_dlg_abort()
switch ($key_level_idx) {
case 0: $left = 0; $right = 11; break;
}
+ case ('snom-d305' || 'snom-d315'):
+ switch ($key_level_idx) {
+ case 0: $left = 0; $right = 1; break;
+ }
default:
switch ($key_level_idx) {
case 0: $left = 0; $right = 6; break;
@@ -1345,7 +1544,7 @@ function gs_dlg_abort()
for ($i=$key_level_info['from']; $i<=$key_level_info['to']; ++$i) {
if ($phone_layout === 'snom') {
- if ($phone_type === 'snom-760' || $phone_type === 'snom-870' || $phone_type == 'snom-720' || $phone_type == 'snom-725' || $phone_type == 'snom-710' || $phone_type == 'snom-715' || $phone_type == 'snom-821') {
+ if ($phone_type === 'snom-760' || $phone_type === 'snom-870' || $phone_type == 'snom-720' || $phone_type == 'snom-725' || $phone_type == 'snom-710' || $phone_type == 'snom-715' || $phone_type == 'snom-821' || $phone_type == 'snom-d305' || $phone_type == 'snom-d315') {
$knum = $i;
$knump = str_pad($knum, 3, '0', STR_PAD_LEFT);
}else {
@@ -1435,7 +1634,7 @@ function gs_dlg_abort()
echo ' $title) {
//if ($can_write || $function === $key['function']) {
diff --git a/opt/gemeinschaft/htdocs/gui/mod/prov_phones.php b/opt/gemeinschaft/htdocs/gui/mod/prov_phones.php
index 00d180f2c..53d2614b8 100644
--- a/opt/gemeinschaft/htdocs/gui/mod/prov_phones.php
+++ b/opt/gemeinschaft/htdocs/gui/mod/prov_phones.php
@@ -59,6 +59,9 @@ function _mac_addr_display( $mac )
$phone_types['snom-870' ] = 'Snom 870';
$phone_types['snom-760' ] = 'Snom 760';
$phone_types['snom-720' ] = 'Snom 720';
+ $phone_types['snom-d305' ] = 'Snom D305';
+ $phone_types['snom-d315' ] = 'Snom D315';
+ $phone_types['snom-d375' ] = 'Snom D375';
}
if (gs_get_conf('GS_SNOM_PROV_M3_ACCOUNTS')) {
$phone_types['snom-m3' ] = 'Snom M3';
@@ -100,6 +103,14 @@ function _mac_addr_display( $mac )
$phone_types['tiptel-ip284' ] = 'Tiptel IP 284';
$phone_types['tiptel-ip286' ] = 'Tiptel IP 286';
}
+if (gs_get_conf('GS_YEALINK_PROV_ENABLED')) {
+ $phone_types['yealink-sip-t42g' ] = 'Yealink SIP T42G';
+ $phone_types['yealink-sip-t46g' ] = 'Yealink SIP T46G';
+ $phone_types['yealink-sip-t48g' ] = 'Yealink SIP T48G';
+ $phone_types['yealink-sip-t42s' ] = 'Yealink SIP T42S';
+ $phone_types['yealink-sip-t46s' ] = 'Yealink SIP T46S';
+ $phone_types['yealink-sip-t46u' ] = 'Yealink SIP T46U';
+}
if (gs_get_conf('GS_POLYCOM_PROV_ENABLED')) {
$phone_types['polycom-spip-300'] = 'Polycom SoundPoint IP 300';
$phone_types['polycom-spip-500'] = 'Polycom SoundPoint IP 500';
diff --git a/opt/gemeinschaft/htdocs/gui/mod/prov_provparams.php b/opt/gemeinschaft/htdocs/gui/mod/prov_provparams.php
index 58be1fa42..904bbd03e 100644
--- a/opt/gemeinschaft/htdocs/gui/mod/prov_provparams.php
+++ b/opt/gemeinschaft/htdocs/gui/mod/prov_provparams.php
@@ -65,6 +65,14 @@
$phone_types['aastra-55i'] = 'Aastra 55i';
$phone_types['aastra-57i'] = 'Aastra 57i';
}
+if (gs_get_conf('GS_YEALINK_PROV_ENABLED')) {
+ $phone_types['yealink-sip-t42g' ] = 'Yealink SIP T42G';
+ $phone_types['yealink-sip-t46g' ] = 'Yealink SIP T46G';
+ $phone_types['yealink-sip-t48g' ] = 'Yealink SIP T48G';
+ $phone_types['yealink-sip-t42s' ] = 'Yealink SIP T42S';
+ $phone_types['yealink-sip-t46s' ] = 'Yealink SIP T46S';
+ $phone_types['yealink-sip-t46u' ] = 'Yealink SIP T46U';
+}
if (gs_get_conf('GS_GRANDSTREAM_PROV_ENABLED')) {
$phone_types['grandstream-ht287' ] = 'Grandstream HT 287';
$phone_types['grandstream-bt110' ] = 'Grandstream BT 110';
diff --git a/opt/gemeinschaft/htdocs/gui/mod/routing_gws-iax.php b/opt/gemeinschaft/htdocs/gui/mod/routing_gws-iax.php
index fddd1fc5b..03eadc247 100644
--- a/opt/gemeinschaft/htdocs/gui/mod/routing_gws-iax.php
+++ b/opt/gemeinschaft/htdocs/gui/mod/routing_gws-iax.php
@@ -447,6 +447,7 @@ function confirm_delete() {
echo ' | ', __('Codecs') ,': | ',"\n";
echo '',"\n";
$codecs = array(
+ 'g722' => 'G.722',
'alaw' => 'G.711a',
'ulaw' => 'G.711u',
'gsm' => 'GSM'
@@ -456,7 +457,7 @@ function confirm_delete() {
echo '',"\n";
- echo '',"\n";
+ echo ' ',"\n";
}
echo ' (', htmlEnt(__('Standard')) ,': ', htmlEnt('G.711a') ,')',"\n";
echo ' | ',"\n";
diff --git a/opt/gemeinschaft/htdocs/gui/mod/routing_gws-sip.php b/opt/gemeinschaft/htdocs/gui/mod/routing_gws-sip.php
index f09a6f983..61590cf45 100644
--- a/opt/gemeinschaft/htdocs/gui/mod/routing_gws-sip.php
+++ b/opt/gemeinschaft/htdocs/gui/mod/routing_gws-sip.php
@@ -457,6 +457,7 @@ function confirm_delete() {
echo '', __('Codecs') ,': | ',"\n";
echo '',"\n";
$codecs = array(
+ 'g722' => 'G.722',
'alaw' => 'G.711a',
'ulaw' => 'G.711u',
'gsm' => 'GSM',
@@ -469,7 +470,7 @@ function confirm_delete() {
echo '',"\n";
- echo '',"\n";
+ echo ' ',"\n";
}
echo ' (', htmlEnt(__('Standard')) ,': ', htmlEnt('G.711a') ,')',"\n";
echo ' | ',"\n";
diff --git a/opt/gemeinschaft/htdocs/prov/snom/settings.php b/opt/gemeinschaft/htdocs/prov/snom/settings.php
index 1fc3f36b8..4901c9b4f 100644
--- a/opt/gemeinschaft/htdocs/prov/snom/settings.php
+++ b/opt/gemeinschaft/htdocs/prov/snom/settings.php
@@ -121,7 +121,7 @@ function _settings_err( $msg='' )
$ua = trim( @$_SERVER['HTTP_USER_AGENT'] );
if (! preg_match('/^Mozilla/i', $ua)
-|| ! preg_match('/snom[0-9]{3}/i', $ua) ) {
+|| ! preg_match('/snomd?[0-9]{3}/i', $ua) ) {
gs_log( GS_LOG_WARNING, "Phone with MAC \"$mac\" (Snom) has invalid User-Agent (\"". $ua ."\")" );
# don't explain this to the users
_settings_err( 'No! See log for details.' );
@@ -134,15 +134,15 @@ function _settings_err( $msg='' )
# user-agents:
# 360: "Mozilla/4.0 (compatible; snom360-SIP 6.5.2; snom360 ramdisk v3.31; snom360 linux 3.25)"
# 370: "Mozilla/4.0 (compatible; snom370-SIP 7.1.2)"
-if (preg_match('/snom([1-9][0-9]{2})/i', $ua, $m)) # e.g. "snom360"
- $phone_model = $m[1];
+if (preg_match('/snom(d?[1-9][0-9]{2})/i', $ua, $m)) # e.g. "snom360"
+ $phone_model = strtolower($m[1]);
else
$phone_model = 'unknown';
$phone_type = 'snom-'.$phone_model; # e.g. "snom-360"
# to be used when auto-adding the phone
-$fw_vers = (preg_match('/snom[0-9]{3}-SIP\s+(\d+\.\d+\.\d+)/', $ua, $m))
+$fw_vers = (preg_match('/snomd?[0-9]{3}-SIP\s+(\d+\.(\d+\.){1,3}\d+)/i', $ua, $m))
? $m[1] : '0.0.0';
$fw_vers_nrml = _snom_normalize_version( $fw_vers );
@@ -725,8 +725,8 @@ function _settings_out()
}
}
psetting('dnd_mode' , $dnd_mode, true);
-psetting('dnd_on_code' , 'dnd-on');
-psetting('dnd_off_code' , 'dnd-off');
+psetting('dnd_on_code' , 'dnd-on@'. $host);
+psetting('dnd_off_code' , 'dnd-off@'. $host);
psetting('preselection_nr' , '');
@@ -964,6 +964,17 @@ function _settings_out()
setting('fkey', 4, 'keyevent F_TRANSFER', array('context'=>'active'));
setting('fkey', 5, 'keyevent F_MUTE', array('context'=>'active'));
}
+if ($phone_model == 'd305' || $phone_model == 'd315') {
+ psetting('status_msgs_that_are_blocked', '');
+ psetting('dkey_fkey1', 'url '. $prov_url_snom .'dial-log.php?user=$user_name1', array('context'=>'active'));
+ psetting('dkey_fkey2', 'url '. $prov_url_snom .'pb.php?m=$mac&u=$user_name1', array('context'=>'active'));
+ psetting('gui_fkey1', 'keyevent F_CALL_LIST');
+ psetting('gui_fkey2', 'keyevent F_ADR_BOOK');
+ psetting('gui_fkey3', 'keyevent F_SETTINGS');
+ setting('fkey', 2, 'url '. $prov_url_snom .'pb.php?m=$mac&u=$user_name1', array('context'=>'active'));
+ setting('fkey', 3, 'keyevent F_TRANSFER', array('context'=>'active'));
+ setting('fkey', 4, 'keyevent F_MUTE', array('context'=>'active'));
+}
if (($phone_model == '710') || ($phone_model == '715')) {
psetting('dkey_fkey1', 'url '. $prov_url_snom .'dial-log.php?user=$user_name1', array('context'=>'active'));
psetting('dkey_fkey2', 'url '. $prov_url_snom .'pb.php?m=$mac&u=$user_name1', array('context'=>'active'));
diff --git a/opt/gemeinschaft/htdocs/prov/tiptel/settings.php b/opt/gemeinschaft/htdocs/prov/tiptel/settings.php
index 78f1976a8..6ab296f6d 100644
--- a/opt/gemeinschaft/htdocs/prov/tiptel/settings.php
+++ b/opt/gemeinschaft/htdocs/prov/tiptel/settings.php
@@ -89,6 +89,8 @@ function _settings_err( $msg='' )
if (! gs_get_conf('GS_TIPTEL_PROV_ENABLED')) {
gs_log( GS_LOG_DEBUG, "Tiptel provisioning not enabled" );
_settings_err( 'Not enabled.' );
+} else {
+ gs_log( GS_LOG_DEBUG, "Tiptel provisioning enabled" );
}
diff --git a/opt/gemeinschaft/htdocs/prov/yealink/.htaccess b/opt/gemeinschaft/htdocs/prov/yealink/.htaccess
new file mode 100644
index 000000000..25444214d
--- /dev/null
+++ b/opt/gemeinschaft/htdocs/prov/yealink/.htaccess
@@ -0,0 +1,28 @@
+# Gemeinschaft
+# $Revision: 1 $
+
+# Provisioning for Tiptel / Yealink *requires* mod_rewrite in order to work!
+
+
+ RewriteEngine on
+
+ # The phone asks for
+ # C.cfg
+
+ # Rewrite requests for .txt
+ # xx.72 Firmware requests 001565xxxxxxC.cfg
+ RewriteRule ^(001565[0-9a-f]*)C.cfg$ settings.php?mac=$1 [L]
+
+ # xx.73 Firmware requests 001565xxxxxx.cfg
+ RewriteRule ^(001565[0-9a-f]*).cfg$ settings.php?mac=$1 [L]
+
+ # newer Yealink phones have 805ec0xxxxxx.cfg
+ RewriteRule ^(805ec0[0-9a-f]*).cfg$ settings.php?mac=$1 [L]
+
+ # even newer Yealink phones have 805e0cxxxxxx.cfg
+ RewriteRule ^(805e0c[0-9a-f]*).cfg$ settings.php?mac=$1 [L]
+
+ # PB
+ # RewriteRule ^pb.([0-9]*).(imported|prv|gs).([0-9]*).xml$ pb.php?u=$1&t=$2&p=$3 [L]
+
+
diff --git a/opt/gemeinschaft/htdocs/prov/yealink/dial-log.php b/opt/gemeinschaft/htdocs/prov/yealink/dial-log.php
new file mode 100644
index 000000000..cbac12a33
--- /dev/null
+++ b/opt/gemeinschaft/htdocs/prov/yealink/dial-log.php
@@ -0,0 +1,234 @@
+
+*
+* based on Snom by
+* Stefan Wintermeyer
+* Philipp Kempgen
+* Peter Kozak
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+* MA 02110-1301, USA.
+\*******************************************************************/
+
+# caution: earlier versions of Snom firmware do not like
+# indented XML
+
+define( 'GS_VALID', true ); /// this is a parent file
+require_once( dirName(__FILE__) .'/../../../inc/conf.php' );
+include_once( GS_DIR .'inc/db_connect.php' );
+include_once( GS_DIR .'inc/gettext.php' );
+include_once( GS_DIR .'inc/langhelper.php' );
+require_once( GS_DIR .'inc/string.php' );
+
+header( 'Expires: 0' );
+header( 'Pragma: no-cache' );
+header( 'Cache-Control: private, no-cache, must-revalidate' );
+header( 'Vary: *' );
+
+function yealinkXmlEsc( $str )
+{
+ return htmlEnt( $str );
+}
+
+function _ob_send()
+{
+ if (! headers_sent()) {
+ header( 'Content-Type: application/xml' );
+ header( 'Content-Length: '. (int)@ob_get_length() );
+ }
+ @ob_end_flush();
+ die();
+}
+
+function _err( $msg='' )
+{
+ @ob_end_clean();
+ ob_start();
+ echo
+ '','xml version="1.0" encoding="utf-8"?','>', "\n",
+ '', "\n",
+ '', __('Fehler'), '', "\n",
+ '', yealinkXmlEsc( __('Fehler') .': '. $msg ), '', "\n",
+ '', "\n";
+ _ob_send();
+}
+
+
+if (! gs_get_conf('GS_YEALINK_PROV_ENABLED')) {
+ gs_log( GS_LOG_DEBUG, "Yealink provisioning not enabled" );
+ _err( 'Not enabled.' );
+}
+
+
+$user = trim( @ $_REQUEST['user'] );
+if (! preg_match('/^\d+$/', $user))
+ _err( 'Not a valid SIP user.' );
+
+$mac = preg_replace('/[^\dA-Z]/', '', strToUpper(trim( @$_REQUEST['mac'] )));
+
+$type = trim( @ $_REQUEST['type'] );
+if (! in_array( $type, array('in','out','missed','queue'), true ))
+ $type = false;
+
+$db = gs_db_slave_connect();
+
+# get user_id
+#
+$user_id = (int)$db->executeGetOne( 'SELECT `_user_id` FROM `ast_sipfriends` WHERE `name`=\''. $db->escape($user) .'\'' );
+if ($user_id < 1)
+ _err( 'Unknown user.' );
+
+
+$remote_addr = @$_SERVER['REMOTE_ADDR'];
+$remote_addr_check = $db->executeGetOne( 'SELECT `current_ip` FROM `users` WHERE `id`='. $user_id );
+if ($remote_addr != $remote_addr_check) _err( 'Not authorized' );
+
+unset($remote_addr_check);
+unset($remote_addr);
+unset($user_id_check);
+
+// setup i18n stuff
+gs_setlang( gs_get_lang_user($db, $user, GS_LANG_FORMAT_GS) );
+gs_loadtextdomain( 'gemeinschaft-gui' );
+gs_settextdomain( 'gemeinschaft-gui' );
+
+$typeToTitle = array(
+ 'out' => __("Gew\xC3\xA4hlt"),
+ 'missed' => __("Verpasst"),
+ 'in' => __("Angenommen"),
+ 'queue' => __("Warteschlangen")
+);
+
+ob_start();
+
+
+$url_yealink_dl = GS_PROV_SCHEME .'://'. GS_PROV_HOST . (GS_PROV_PORT ? ':'.GS_PROV_PORT : '') . GS_PROV_PATH .'yealink/dial-log.php';
+
+#################################### INITIAL SCREEN {
+if (! $type) {
+
+ # delete outdated entries
+ #
+ $db->execute( 'DELETE FROM `dial_log` WHERE `user_id`='. $user_id .' AND `timestamp`<'. (time()-(int)GS_PROV_DIAL_LOG_LIFE) );
+
+
+
+ echo '','xml version="1.0" encoding="utf-8"?','>', "\n";
+ echo
+ '', "\n",
+ '', __('Anruflisten') ,'', "\n";
+
+ foreach ($typeToTitle as $t => $title) {
+
+ $num_calls = (int)$db->executeGetOne( 'SELECT COUNT(*) FROM `dial_log` WHERE `user_id`='. $user_id .' AND `type`=\''. $t .'\'' );
+ //if ($num_calls > 0) {
+ echo
+ "\n",
+ '', "\n";
+ //}
+ }
+
+ echo
+ "\n",
+ '';
+
+}
+#################################### INITIAL SCREEN }
+
+
+
+#################################### DIAL LOG {
+else {
+
+ echo '','xml version="1.0" encoding="utf-8"?','>', "\n";
+ if ($type === 'queue'){
+ $query =
+ 'SELECT
+ `timestamp` `ts`, `number`, `remote_name`, `remote_user_id`
+ FROM `dial_log`
+ WHERE
+ `user_id`='. $user_id .' AND
+ `type`=\''. $type .'\'
+ ORDER BY `ts` DESC
+ LIMIT 20';
+ } else {
+ $query =
+ 'SELECT
+ MAX(`timestamp`) `ts`, `number`, `remote_name`, `remote_user_id`,
+ COUNT(*) `num_calls`
+ FROM `dial_log`
+ WHERE
+ `user_id`='. $user_id .' AND
+ `type`=\''. $type .'\'
+ GROUP BY `number`
+ ORDER BY `ts` DESC
+ LIMIT 20';
+ }
+ $rs = $db->execute( $query );
+
+ echo
+ '',
+ '', yealinkXmlEsc( $typeToTitle[$type] ) ,
+ ($rs->numRows() == 0 ? ' ('.yealinkXmlEsc(__('keine')).')' : '') ,
+ '', "\n";
+
+ while ($r = $rs->fetchRow()) {
+
+ $entry_name = $r['number'];
+ if ($r['remote_name'] != '') {
+ $entry_name .= ' '. $r['remote_name'];
+ }
+ if (date('dm') == date('dm', (int)$r['ts']))
+ $when = date('H:i', (int)$r['ts']);
+ else
+ $when = date('d.m.', (int)$r['ts']);
+ $entry_name = $when .' '. $entry_name;
+ if ($r['num_calls'] > 1) {
+ $entry_name .= ' ('. $r['num_calls'] .')';
+ }
+ echo
+ "\n",
+ '', "\n";
+
+ }
+
+ echo
+ "\n",
+ '';
+
+}
+#################################### DIAL LOG }
+
+
+_ob_send();
+
+?>
diff --git a/opt/gemeinschaft/htdocs/prov/yealink/fw/readme_firmware.txt b/opt/gemeinschaft/htdocs/prov/yealink/fw/readme_firmware.txt
new file mode 100644
index 000000000..e551a374b
--- /dev/null
+++ b/opt/gemeinschaft/htdocs/prov/yealink/fw/readme_firmware.txt
@@ -0,0 +1,5 @@
+Place Yealink firmware images in this folder.
+
+Use filename format "aa.bb.cc.dd.rom", e.g. "28.80.00.95.rom" for T46G and
+"35.80.00.95.rom" for T48G.
+
diff --git a/opt/gemeinschaft/htdocs/prov/yealink/pb_on_phone.php b/opt/gemeinschaft/htdocs/prov/yealink/pb_on_phone.php
new file mode 100644
index 000000000..4db131806
--- /dev/null
+++ b/opt/gemeinschaft/htdocs/prov/yealink/pb_on_phone.php
@@ -0,0 +1,183 @@
+
+*
+* based on Tiptel by
+* Sebastian Ertz
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+* MA 02110-1301, USA.
+\*******************************************************************/
+
+define( 'GS_VALID', true ); /// this is a parent file
+
+require_once( dirName(__FILE__) .'/../../../inc/conf.php' );
+//require_once( GS_DIR .'inc/util.php' );
+//require_once( GS_DIR .'inc/gs-lib.php' );
+require_once( GS_DIR .'inc/prov-fns.php' );
+set_error_handler('err_handler_die_on_err');
+require_once( GS_DIR .'inc/string.php' );
+require_once( GS_DIR .'inc/db_connect.php' );
+include_once( GS_DIR .'inc/group-fns.php' );
+
+header( 'Expires: 0' );
+header( 'Pragma: no-cache' );
+header( 'Cache-Control: private, no-cache, must-revalidate' );
+header( 'Vary: *' );
+
+
+function yealinkXmlEsc( $str )
+{
+ return htmlEnt( $str );
+}
+
+function _err( $msg='' )
+{
+ @ob_end_clean();
+ @ob_start();
+ echo '',"\n";
+ if (! headers_sent()) {
+ header( 'Content-Type: text/plain; charset=utf-8' );
+ header( 'Content-Length: '. (int)@ob_get_length() );
+ }
+ @ob_end_flush();
+ exit(1);
+}
+
+function getUserID( $ext )
+{
+ global $db;
+
+ if (! preg_match('/^\d+$/', $ext))
+ _err( 'Invalid username' );
+
+ $user_id = (int)$db->executeGetOne( 'SELECT `_user_id` FROM `ast_sipfriends` WHERE `name`=\''. $db->escape($ext) .'\'' );
+ if ($user_id < 1)
+ _err( 'Unknown user' );
+ return $user_id;
+}
+
+if (! gs_get_conf('GS_YEALINK_PROV_ENABLED')) {
+ gs_log( GS_LOG_DEBUG, "Yealink provisioning not enabled" );
+ _err( 'Not enabled' );
+}
+
+
+$type = trim( @$_REQUEST['t'] );
+if (! in_array( $type, array('gs','prv','imported'), true )) {
+ _err( 'Not allowed' );
+}
+
+
+$mac = strToUpper(trim( @$_REQUEST['m'] ));
+
+//FIXME - we need authentication here
+
+$requester = gs_prov_check_trust_requester();
+if (! $requester['allowed']) {
+ _err( 'No! See log for details.' );
+}
+
+# connect to db
+$db = gs_db_slave_connect();
+if (! $db) {
+ gs_log( GS_LOG_WARNING, "Phone with MAC \"$mac\" (Yealink) ask for phonebook - Could not connect to DB" );
+ _err( 'No! See log for details.' );
+}
+
+
+# get user_id
+$user = trim( @$_REQUEST['u'] );
+$user_id = getUserID( $user );
+
+
+if ($type === 'gs') { # INTERNAL phonebook
+ $user_groups = gs_group_members_groups_get(array($user_id), 'user');
+ $permission_groups = gs_group_permissions_get($user_groups, 'phonebook_user');
+ $group_members = gs_group_members_get($permission_groups);
+
+ $pb = array(
+ 'type' => 'gs',
+ 'title' => gs_get_conf('GS_PB_INTERNAL_TITLE', __("Intern")),
+ 'query' => 'SELECT `u`.`lastname` `ln`, `u`.`firstname` `fn`, `s`.`name` `ext`
+ FROM
+ `users` `u` JOIN
+ `ast_sipfriends` `s` ON (`s`.`_user_id`=`u`.`id`)
+ WHERE
+ `u`.`id` IN ('.implode(',', $group_members).') AND
+ `u`.`id`!='.$user_id.'
+ ORDER BY `u`.`lastname`, `u`.`firstname`'
+ );
+}
+elseif ($type ==='prv') { # PRIVATE phonebook
+ $pb = array(
+ 'type' => 'prv',
+ 'title' => gs_get_conf('GS_PB_PRIVATE_TITLE', __("Pers\xC3\xB6nlich")),
+ 'query' => 'SELECT `pb`.`lastname` `ln`, `pb`.`firstname` `fn`, `pb`.`number` `ext`
+ FROM
+ `pb_prv` `pb`
+ WHERE `pb`.`user_id`='.$user_id.'
+ ORDER BY `pb`.`lastname`, `pb`.`firstname`'
+ );
+}
+elseif ($type === 'imported') { # IMPORTED phonebook
+ if (! gs_get_conf('GS_PB_IMPORTED_ENABLED'))
+ _err( 'Not allowed' );
+
+ $pb = array(
+ 'type' => 'imported',
+ 'title' => gs_get_conf('GS_PB_IMPORTED_TITLE', __("Extern")),
+ 'query' => 'SELECT `lastname` `ln`, `firstname` `fn`, `number` `ext`
+ FROM `pb_ldap`
+ ORDER BY `lastname`, `firstname`'
+ );
+}
+
+
+ob_start();
+
+echo '','xml version="1.0" encoding="utf-8"?','>' ,"\n";
+echo '' ,"\n";
+
+$rs = $db->execute( $pb['query'] );
+
+if ( $rs && $rs->numRows() !== 0 ) {
+ while ($r = $rs->fetchRow()) {
+ $lastname = $r['ln'];
+ $firstname = $r['fn'];
+ $number = $r['ext'];
+
+ echo '' ,
+ ''. yealinkXmlEsc($lastname) .', '. yealinkXmlEsc($firstname) . '',
+ ''. yealinkXmlEsc($number). "",
+ '' ,"\n";
+ }
+}
+
+echo '' ,"\n";
+
+if (! headers_sent()) {
+ header( 'Content-Type: application/xml' );
+ header( 'Content-Length: '. (int)@ob_get_length() );
+}
+@ob_end_flush();
+
+?>
diff --git a/opt/gemeinschaft/htdocs/prov/yealink/readme_dhcp.txt b/opt/gemeinschaft/htdocs/prov/yealink/readme_dhcp.txt
new file mode 100644
index 000000000..5f98db5f1
--- /dev/null
+++ b/opt/gemeinschaft/htdocs/prov/yealink/readme_dhcp.txt
@@ -0,0 +1,36 @@
+Sample DHCP Server Config (edit IPs to fit your needs):
+
+
+
+subnet 192.168.x.0 netmask 255.255.255.0 {
+ range 192.168.x.100 192.168.x.150;
+
+ # Snom-Phones, MAC starts with 00:04:13
+ if binary-to-ascii(16, 32, "", substring(hardware, 0, 4)) = "1000413" {
+ log(info, "request from snom phone, setting proper options.");
+ # GS3
+ option tftp-server-name "http://192.168.x.250";
+ option bootfile-name "/gemeinschaft/prov/snom/settings.php?mac={mac}";
+ }
+
+ # Yealink-Phones, MAC starts with 00:15:65
+ if binary-to-ascii(16, 32, "", substring(hardware, 0, 4)) = "1001565" {
+ log(info, "request from yealink phone, setting proper options.");
+ # GS3
+ option tftp-server-name "http://192.168.x.250/gemeinschaft/prov/yealink/$MAC.cfg";
+ }
+ # Yealink-Phones, MAC starts with 80:5e:c0
+ if binary-to-ascii(16, 32, "", substring(hardware, 0, 4)) = "1805ec0" {
+ log(info, "request from yealink phone, setting proper options.");
+ # GS3
+ option tftp-server-name "http://192.168.9.1/gemeinschaft/prov/yealink/$MAC.cfg";
+ }
+ # Yealink-Phones, MAC starts with 80:5e:0c
+ if binary-to-ascii(16, 32, "", substring(hardware, 0, 4)) = "1805e0c" {
+ log(info, "request from yealink phone, setting proper options.");
+ # GS3
+ option tftp-server-name "http://192.168.9.1/gemeinschaft/prov/yealink/$MAC.cfg";
+ }
+
+}
+
diff --git a/opt/gemeinschaft/htdocs/prov/yealink/settings.php b/opt/gemeinschaft/htdocs/prov/yealink/settings.php
new file mode 100644
index 000000000..37c8bec1e
--- /dev/null
+++ b/opt/gemeinschaft/htdocs/prov/yealink/settings.php
@@ -0,0 +1,1107 @@
+
+* Mirco Bartels
+*
+* based on Tiptel provisioning by
+* Sebastian Ertz
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+* MA 02110-1301, USA.
+\*******************************************************************/
+
+define( 'GS_VALID', true ); /// this is a parent file
+
+header( 'Expires: 0' );
+header( 'Pragma: no-cache' );
+header( 'Cache-Control: private, no-cache, must-revalidate' );
+header( 'Vary: *' );
+
+
+require_once( dirName(__FILE__) .'/../../../inc/conf.php' );
+require_once( GS_DIR .'inc/util.php' );
+require_once( GS_DIR .'inc/gs-lib.php' );
+require_once( GS_DIR .'inc/prov-fns.php' );
+require_once( GS_DIR .'inc/quote_shell_arg.php' );
+set_error_handler('err_handler_die_on_err');
+
+function _yealink_astlang_to_yealinklang($langcode)
+{
+ $lang_default = 'German';
+
+ $lang_transtable = array(
+ 'de' => 'German',
+ 'en' => 'English',
+ 'us' => 'English',
+ );
+
+ $lang_ret = $lang_transtable[$langcode];
+ if(strlen($lang_ret) == 0)
+ return $lang_default;
+
+ return $lang_ret;
+}
+
+function _yealink_normalize_version( $fwvers )
+{
+ $tmp = explode('.', $fwvers);
+ $v0 = str_pad((int)@$tmp[0], 2, '0', STR_PAD_LEFT);
+ $v1 = str_pad((int)@$tmp[1], 2, '0', STR_PAD_LEFT);
+ $v2 = str_pad((int)@$tmp[2], 2, '0', STR_PAD_LEFT);
+ $v3 = str_pad((int)@$tmp[3], 2, '0', STR_PAD_LEFT);
+ return $v0.'.'.$v1.'.'.$v2.'.'.$v3;
+}
+
+function _yealink_fwcmp( $fwvers1, $fwvers2 )
+{
+ //$fwvers1 = _yealink_normalize_version( $fwvers1 ); # we trust it has been normalized!
+ $fwvers2 = _yealink_normalize_version( $fwvers2 );
+ return strCmp($fwvers1, $fwvers2);
+}
+
+function _settings_err( $msg='' )
+{
+ @ob_end_clean();
+ @ob_start();
+ echo '# ', ($msg != '' ? $msg : 'Error') ,"\n";
+ gs_log( GS_LOG_DEBUG, $msg );
+ if (! headers_sent()) {
+ header( 'Content-Type: text/plain; charset=utf-8' );
+ header( 'Content-Length: '. (int)@ob_get_length() );
+ }
+ @ob_end_flush();
+ exit(1);
+}
+
+// Tiptel and Yealink share OUI from MAC address. So redirect Tiptel phones to Tiptel provisioning.
+function _redirect_tiptel()
+{
+ $prov_url_tiptel = GS_PROV_SCHEME .'://'. GS_PROV_HOST . (GS_PROV_PORT ? ':'.GS_PROV_PORT : '') . GS_PROV_PATH.'tiptel/'.$_REQUEST['mac'].'.cfg';
+
+ gs_log( GS_LOG_DEBUG, 'Redirecting to Tiptel Provisoning: '.$prov_url_tiptel );
+
+ $options = array('http' => array('user_agent' => @$_SERVER['HTTP_USER_AGENT']));
+ $context = stream_context_create($options);
+ $response = file_get_contents($prov_url_tiptel, false, $context);
+
+ ob_start();
+ echo $response;
+ if (! headers_sent()) {
+ header( 'Content-Type: text/plain; charset=utf-8' );
+ header( 'Content-Length: '. (int)@ob_get_length() );
+ }
+ @ob_end_flush();
+ exit(1);
+}
+
+if (! gs_get_conf('GS_YEALINK_PROV_ENABLED')) {
+ gs_log( GS_LOG_DEBUG, "Yealink provisioning not enabled" );
+ _settings_err( 'Not enabled.' );
+}
+
+$requester = gs_prov_check_trust_requester();
+if (! $requester['allowed']) {
+ _settings_err( 'No! See log for details.' );
+}
+
+$mac = preg_replace( '/[^0-9A-F]/', '', strToUpper( @$_REQUEST['mac'] ) );
+if (strLen($mac) !== 12) {
+ gs_log( GS_LOG_NOTICE, "Yealink provisioning: Invalid MAC address \"$mac\" (wrong length)" );
+ # don't explain this to the users
+ _settings_err( 'No! See log for details.' );
+}
+if (hexDec(subStr($mac,0,2)) % 2 == 1) {
+ gs_log( GS_LOG_NOTICE, "Yealink provisioning: Invalid MAC address \"$mac\" (multicast address)" );
+ # don't explain this to the users
+ _settings_err( 'No! See log for details.' );
+}
+if ($mac === '000000000000') {
+ gs_log( GS_LOG_NOTICE, "Yealink provisioning: Invalid MAC address \"$mac\" (huh?)" );
+ # don't explain this to the users
+ _settings_err( 'No! See log for details.' );
+}
+
+# make sure the phone is a Yealink:
+#
+if ((subStr($mac,0,6) !== '001565') && (subStr($mac,0,6) !== '805EC0') && (subStr($mac,0,6) !== '805E0C')) {
+ gs_log( GS_LOG_NOTICE, "Yealink provisioning: MAC address \"$mac\" is not a Yealink phone" );
+ # don't explain this to the users
+ _settings_err( 'No! See log for details.' );
+}
+
+# HTTP_USER_AGENTs
+#
+# e.g. yealink SIP-T46G: "Yealink SIP-T46G 28.72.0.25 00:15:65:5b:53:84"
+#
+$ua = trim( @$_SERVER['HTTP_USER_AGENT'] );
+$ua_parts = explode(' ', $ua);
+# redirect Tiptel phones to Tiptel provisioning
+if (strToLower(@$ua_parts[0]) == 'tiptel') {
+ gs_log( GS_LOG_WARNING, "Phone with MAC \"$mac\" (Tiptel) has invalid User-Agent (\"". $ua ."\"); Redirecting to Tiptel provisioning!" );
+
+ _redirect_tiptel();
+}
+else if (strToLower(@$ua_parts[0]) !== 'yealink') {
+ gs_log( GS_LOG_WARNING, "Phone with MAC \"$mac\" (Yealink) has invalid User-Agent (\"". $ua ."\")" );
+ # don't explain this to the users
+ _settings_err( 'No! See log for details.' );
+}
+
+gs_log( GS_LOG_DEBUG, "Yealink model $ua found." );
+
+# find out the type of the phone:
+if (preg_match('/SIP-(T42G|T46G|T48G|T42S|T46S|T46U)/', @$ua_parts[1], $m)) { # e.g. "SIP-T46G", "SIP-T48G" or "SIP-T22P"
+ $phone_model = 'SIP-'.$m[1];
+ $phone_model_config = 'SIP_'.$m[1];
+}
+else
+ $phone_model = 'unknown';
+
+$phone_type = 'yealink-'.strToLower($phone_model); # e.g. "yealink-sip-t46g" or "yealink-sip-t48g"
+# to be used when auto-adding the phone
+
+# find out the firmware version of the phone
+$fw_vers = (preg_match('/(\d+\.\d+\.\d+\.\d+)/', @$ua_parts[2], $m))
+ ? $m[1] : '0.0.0.0';
+
+$fw_vers_nrml = _yealink_normalize_version( $fw_vers );
+
+gs_log( GS_LOG_DEBUG, "Yealink phone \"$mac\" asks for settings (UA: ...\"$ua\") - model: $phone_model" );
+
+$prov_url_yealink = GS_PROV_SCHEME .'://'. GS_PROV_HOST . (GS_PROV_PORT ? ':'.GS_PROV_PORT : '') . GS_PROV_PATH .'yealink/';
+
+
+require_once( GS_DIR .'inc/db_connect.php' );
+require_once( GS_DIR .'inc/nobody-extensions.php' );
+include_once( GS_DIR .'inc/gs-fns/gs_callforward_get.php' );
+include_once( GS_DIR .'inc/gs-fns/gs_keys_get.php' );
+include_once( GS_DIR .'inc/gs-fns/gs_prov_params_get.php' );
+include_once( GS_DIR .'inc/gs-fns/gs_user_prov_params_get.php' );
+include_once( GS_DIR .'inc/cron-rule.php' );
+
+
+$settings = array();
+
+function psetting( $param, $val='' )
+{
+ global $settings;
+
+ $settings[$param] = $val;
+}
+
+function _settings_out() //TODO Variablen l�schen (warte auf RE von Yealink)
+{
+ global $settings;
+
+ echo "#!version:1.0.0.1\n";
+
+ foreach ($settings as $param => $val) {
+ echo $param .' = '. $val . "\n";
+ }
+}
+
+
+$db = gs_db_master_connect();
+if (! $db) {
+ gs_log( GS_LOG_WARNING, "Yealink phone asks for settings - Could not connect to DB" );
+ _settings_err( 'Could not connect to DB.' );
+}
+
+# do we know the phone?
+#
+$user_id = @gs_prov_user_id_by_mac_addr( $db, $mac );
+if ($user_id < 1) {
+ if (! GS_PROV_AUTO_ADD_PHONE) {
+ gs_log( GS_LOG_NOTICE, "New phone $mac not added to DB. Enable PROV_AUTO_ADD_PHONE" );
+ _settings_err( 'Unknown phone. (Enable PROV_AUTO_ADD_PHONE in order to auto-add)' );
+ }
+ gs_log( GS_LOG_NOTICE, "Adding new Yealink phone $mac to DB" );
+
+ $user_id = @gs_prov_add_phone_get_nobody_user_id( $db, $mac, $phone_type, $requester['phone_ip'] );
+ if ($user_id < 1) {
+ gs_log( GS_LOG_WARNING, "Failed to add nobody user for new phone $mac" );
+ _settings_err( 'Failed to add nobody user for new phone.' );
+ }
+}
+
+
+# is it a valid user id?
+#
+$num = (int)$db->executeGetOne( 'SELECT COUNT(*) FROM `users` WHERE `id`='. $user_id );
+if ($num < 1)
+ $user_id = 0;
+
+if ($user_id < 1) {
+ # something bad happened, nobody (not even a nobody user) is logged
+ # in at that phone. assign the default nobody user of the phone:
+ $user_id = @gs_prov_assign_default_nobody( $db, $mac, null );
+ if ($user_id < 1) {
+ _settings_err( 'Failed to assign nobody account to phone '. $mac );
+ }
+}
+
+
+# get host for user
+#
+$host = @gs_prov_get_host_for_user_id( $db, $user_id );
+if (! $host) {
+ _settings_err( 'Failed to find host.' );
+}
+$pbx = $host; # $host might be changed if SBC configured
+
+
+# who is logged in at that phone?
+#
+$user = @gs_prov_get_user_info( $db, $user_id );
+if (! is_array($user)) {
+ _settings_err( 'DB error.' );
+}
+
+
+# store the current firmware version and type information in the database:
+#
+@$db->execute(
+ 'UPDATE `phones` SET '.
+ '`firmware_cur`=\''. $db->escape($fw_vers_nrml) .'\', '.
+ '`type`=\''. $db->escape($phone_type) .'\' '.
+ 'WHERE `mac_addr`=\''. $db->escape($mac) .'\''
+ );
+
+
+# firmware update
+#
+if (! gs_get_conf('GS_YEALINK_PROV_FW_UPDATE')) {
+ gs_log( GS_LOG_DEBUG, 'Yealink firmware update not enabled' );
+} else {
+ # get phone_id
+ $phone_id = (int)$db->executeGetOne( 'SELECT `id` FROM `phones` WHERE `mac_addr`=\''. $db->escape($mac) .'\'' );
+
+ # do we have to update to a default version?
+ #
+ $fw_was_upgraded_manually = (int)$db->executeGetOne(
+ 'SELECT `fw_manual_update` '.
+ 'FROM `phones` '.
+ 'WHERE `id`='. $phone_id
+ );
+ if ($fw_was_upgraded_manually) {
+ gs_log( GS_LOG_DEBUG, "Phone $mac: Firmware was upgraded \"manually\". Not scheduling an upgrade." );
+ } else {
+ $fw_default_vers = _yealink_normalize_version(trim(gs_get_conf('GS_YEALINK_PROV_FW_DEFAULT_'.strToUpper($phone_model_config))));
+ if (in_array($fw_default_vers, array(null, false,''), true)) {
+ gs_log( GS_LOG_DEBUG, "Phone $mac: No default firmware set in config file" );
+ } elseif (subStr($fw_default_vers,0,2) === '00') {
+ gs_log( GS_LOG_DEBUG, "Phone $mac: Bad default firmware set in config file: $fw_default_vers" );
+ } else {
+ if ($fw_vers_nrml != $fw_default_vers) {
+ gs_log( GS_LOG_NOTICE, "Phone $mac: The Firmware version ($fw_vers_nrml) differs from the default version ($fw_default_vers), scheduling an upgrade ..." );
+ # simply add a provisioning job to the database. This is done to be clean and we cann trace the job.
+ $ok = $db->execute(
+ 'INSERT INTO `prov_jobs` ('.
+ '`id`, '.
+ '`inserted`, '.
+ '`running`, '.
+ '`trigger`, '.
+ '`phone_id`, '.
+ '`type`, '.
+ '`immediate`, '.
+ '`minute`, '.
+ '`hour`, '.
+ '`day`, '.
+ '`month`, '.
+ '`dow`, '.
+ '`data` '.
+ ') VALUES ('.
+ 'NULL, '.
+ ((int)time()) .', '.
+ '0, '.
+ '\'client\', '.
+ ((int)$phone_id) .', '.
+ '\'firmware\', '.
+ '0, '.
+ '\'*\', '.
+ '\'*\', '.
+ '\'*\', '.
+ '\'*\', '.
+ '\'*\', '.
+ '\''. $db->escape($fw_default_vers) .'\''.
+ ')'
+ );
+ }
+ }
+ }
+
+ # check provisioning jobs
+ #
+ $rs = $db->execute(
+ 'SELECT `id`, `running`, `minute`, `hour`, `day`, `month`, `dow`, `data` '.
+ 'FROM `prov_jobs` '.
+ 'WHERE `phone_id`='.$phone_id.' AND `type`=\'firmware\' '.
+ 'ORDER BY `running` DESC, `inserted`' );
+ /*if (! $rs) {
+ gs_log( GS_LOG_WARNING, "DB error" );
+ return;
+ }*/
+ while ($job = $rs->fetchRow()) {
+ if ($job['running']) {
+ break;
+ }
+
+ # check cron rule
+ $c = new CronRule();
+ $ok = $c->set_Rule( $job['minute'] .' '. $job['hour'] .' '. $job['day'] .' '. $job['month'] .' '. $job['dow'] );
+ if (! $ok) {
+ gs_log( GS_LOG_WARNING, "Phone $mac: Job ".$job['id']." has a bad cron rule (". $c->errMsg ."). Deleting ..." );
+ $db->execute( 'DELETE FROM `prov_jobs` WHERE `id`='.((int)$job['id']).' AND `running`=0' );
+ unset($c);
+ continue;
+ }
+ if (! $c->validate_time()) {
+ gs_log( GS_LOG_DEBUG, "Phone $mac: Job ".$job['id'].": Rule does not match" );
+ unset($c);
+ continue;
+ }
+ unset($c);
+ gs_log( GS_LOG_DEBUG, "Phone $mac: Job ".$job['id'].": Rule match" );
+
+ $fw_new_vers = _yealink_normalize_version( $job['data'] );
+ if (subStr($fw_new_vers,0,2)=='00') {
+ gs_log( GS_LOG_NOTICE, "Phone $mac: Bad new fw version $fw_new_vers" );
+ $db->execute( 'DELETE FROM `prov_jobs` WHERE `id`='.((int)$job['id']).' AND `running`=0' );
+ continue;
+ }
+ if ( (subStr($fw_new_vers,0,2) != '18' && $phone_model === 'ip28xs')
+ || (subStr($fw_new_vers,0,2) != '09' && $phone_model === 'ip280')
+ || (subStr($fw_new_vers,0,2) != '06' && $phone_model === 'ip284')
+ || (subStr($fw_new_vers,0,2) != '02' && $phone_model === 'ip286') ) {
+ gs_log( GS_LOG_NOTICE, "Phone $mac: Bad new fw version $fw_new_vers for $phone_model" );
+ $db->execute( 'DELETE FROM `prov_jobs` WHERE `id`='.((int)$job['id']).' AND `running`=0' );
+ continue;
+ }
+ $firmware_path = '/opt/gemeinschaft/htdocs/prov/yealink/fw/'.$fw_new_vers.'.rom';
+ if ( ! file_exists($firmware_path) || ! is_readable($firmware_path) ) {
+ gs_log( GS_LOG_NOTICE, "Phone $mac: ".$firmware_path." not exits or not readable" );
+ $db->execute( 'DELETE FROM `prov_jobs` WHERE `id`='.((int)$job['id']).' AND `running`=0' );
+ continue;
+ }
+ if ( $fw_new_vers == $fw_vers_nrml ) {
+ gs_log( GS_LOG_NOTICE, "Phone $mac: FW $fw_vers_nrml == $fw_new_vers" );
+ $db->execute( 'DELETE FROM `prov_jobs` WHERE `id`='.((int)$job['id']).' AND `running`=0' );
+ continue;
+ }
+
+ gs_log( GS_LOG_NOTICE, "Phone $mac: Upgrade FW $fw_vers_nrml -> $fw_new_vers" );
+
+ # Configure
+ ###It configures the access URL of the firmware file.
+ ###The default value is blank.It takes effect after a reboot.
+ psetting('firmware.url', $prov_url_yealink.'fw/'.$fw_new_vers.'.rom');
+
+ break;
+ }
+}
+
+
+# store the user's current IP address in the database:
+#
+if (! @gs_prov_update_user_ip( $db, $user_id, $requester['phone_ip'] )) {
+ gs_log( GS_LOG_WARNING, 'Failed to store current IP addr of user ID '. $user_id );
+}
+
+
+# get SIP proxy to be set as the phone's outbound proxy
+#
+$sip_proxy_and_sbc = gs_prov_get_wan_outbound_proxy( $db, $requester['phone_ip'], $user_id );
+if ($sip_proxy_and_sbc['sip_server_from_wan'] != '') {
+ $host = $sip_proxy_and_sbc['sip_server_from_wan'];
+}
+
+
+# get extension without route prefix
+#
+if (gs_get_conf('GS_BOI_ENABLED')) {
+ $hp_route_prefix = (string)$db->executeGetOne(
+ 'SELECT `value` FROM `host_params` '.
+ 'WHERE '.
+ '`host_id`='. (int)$user['host_id'] .' AND '.
+ '`param`=\'route_prefix\''
+ );
+ $user_ext = (subStr($user['name'],0,strLen($hp_route_prefix)) === $hp_route_prefix)
+ ? subStr($user['name'], strLen($hp_route_prefix)) : $user['name'];
+ gs_log( GS_LOG_DEBUG, "Mapping ext. ". $user['name'] ." to $user_ext for provisioning - route_prefix: $hp_route_prefix, host id: ". $user['host_id'] );
+} else {
+ $hp_route_prefix = '';
+ $user_ext = $user['name'];
+}
+
+# Phonetype Check
+if ( in_array($phone_type, array('yealink-sip-t42g','yealink-sip-t46g','yealink-sip-t48g','yealink-sip-t42s','yealink-sip-t46s','yealink-sip-t46u'), true) ) {
+
+ #####################################################################
+ # Common provisioning parameters (applicable to SIP-T28P/T26P/T22P/T20P/T21P/T19P/T46G/T42G/T41P IP phones running firmware version 72 or later)
+ #####################################################################
+
+ # Language
+ ##It configures the language of the web user interface.
+ ##Chinese_S is only applicable to SIP-T19P, SIP-T21P and SIP-T46G IP phones.
+ ##Chinese_T is only applicable to SIP-T46G IP phones.
+ ##French, Portuguese and Spanish are not applicable to SIP-T19P and SIP-T21P IP phones.
+ psetting('lang.wui', 'English');
+ ##It configures the language of the phone user interface.
+ ##Chinese_S and Chinese_T are only applicable to SIP-T19P, SIP-T21P and SIP-T46G IP phones.
+ ##The default value is English.
+ psetting('lang.gui', _yealink_astlang_to_yealinklang($user['language']));
+
+ # Network LLDP enable (for identifying IP phone on LLDP-enabled switches)
+ psetting('network.lldp.enable', '1');
+ psetting('network.lldp.packet_interval', '60');
+
+ # Remote Phonebook
+ ###X ranges from 1 to 5
+ ###remote_phonebook.data.X.url =
+ ###remote_phonebook.data.X.name =
+
+ $i=1;
+ # Intern
+ psetting('remote_phonebook.data.'.$i.'.url', $prov_url_yealink.'pb_on_phone.php?u='.$user_ext.'&t=gs');
+ psetting('remote_phonebook.data.'.$i.'.name', 'Intern');
+ $i++;
+
+ if (gs_get_conf('GS_PB_IMPORTED_ENABLED')) {
+ # Firma
+ psetting('remote_phonebook.data.'.$i.'.url', $prov_url_yealink.'pb_on_phone.php?u='.$user_ext.'&t=imported');
+ psetting('remote_phonebook.data.'.$i.'.name', 'Firma');
+ $i++;
+ };
+
+ # Personal
+ psetting('remote_phonebook.data.'.$i.'.url', $prov_url_yealink.'pb_on_phone.php?u='.$user_ext.'&t=prv');
+ psetting('remote_phonebook.data.'.$i.'.name', 'Pers�nlich');
+ $i++;
+
+ # empty 4 and 5
+ psetting('remote_phonebook.data.'.$i.'.url', '');
+ psetting('remote_phonebook.data.'.$i.'.name', '');
+ $i++;
+
+ psetting('remote_phonebook.data.'.$i.'.url', '');
+ psetting('remote_phonebook.data.'.$i.'.name', '');
+
+ psetting('remote_phonebook.display_name', 'Telefonbuch');
+
+ ###Super Search recommended by Yealink support
+ psetting('remote_phonebook.super_search.enable', '1');
+ psetting('directory.search_type', '1');
+
+
+ # Show Remote Phonebook on Home Screen
+ psetting('programablekey.2.type', '47');
+ psetting('programablekey.2.line', '1');
+ psetting('programablekey.2.value', '');
+ psetting('programablekey.2.label', 'Tel.buch');
+
+ ##It enables or disables the phone to perform a remote phone book search when receiving an incoming call.
+ ##0-Disabled,1-Enabled.
+ ##The default value is 0.
+ psetting('features.remote_phonebook.enable', '1');
+ ##It enables or disables the phone to perform a remote phone book search when accessing.
+ ##0-Disabled,1-Enabled.
+ ##The default value is 0.
+ psetting('features.remote_phonebook.enter_update_enable', '1');
+ ##It configures the interval (in seconds) for the phone to update the data of the remote phone book from the remote phone book server.
+ ##The default value is 21600.Integer from 3600 to 2592000.
+ psetting('features.remote_phonebook.flash_time', '3600');
+
+ # Ringtone
+ # exp.: tftp://192.168.1.100/Ring9.wav
+ # http://192.168.178.26/gemeinschaft/prov/ringtones/admin-int-fgz-tiptel.wav
+ #psetting('ringtone.url', 'http://192.168.178.26/gemeinschaft/prov/ringtones/admin-int-fgz-tiptel.wav');
+ #psetting('ringtone.delete', '');
+ #Delete all the custom ringtones uploaded through auto provisioning
+ #psetting('ringtone.delete', 'http://localhost/all');
+
+ # Country Tone
+ # Custom,Australia,Austria, Brazil,Belgium,China, Czech,Denmark,Finland,France,Germany,Great Britain,Greece,Hungary,Lithuania,India, Italy,Japan,Mexico, New Zealand,
+ # Netherlands,Norway,Portugal,Spain,Switzerland,Sweden,Russia, UnitedStates, Chile,Czech ETSI
+ psetting('voice.tone.country', 'Germany');
+
+ # Sending volume
+ # integer range from -50 to 50, default is 0
+ # handset is a bit quiet, so so raise it up a bit
+ psetting('voice.handfree_send', '0');
+ psetting('voice.handset_send', '10');
+ psetting('voice.headset_send', '0');
+
+ # DND
+ psetting('features.dnd.enable', '0');
+ psetting('features.dnd.on_code', 'dnd-on');
+ psetting('features.dnd.off_code', 'dnd-off');
+
+ # Display own Extension
+ psetting('features.show_default_account', '1');
+
+ # Security
+ ###Define the login username and password of the user, var and administrator.
+ ###If you change the username of the administrator from "admin" to "admin1", your new administrator's username should be configured as: security.user_name.admin = admin1.
+ ###If you change the password of the administrator from "admin" to "admin1pwd", your new administrator's password should be configured as: security.user_password = admin1:admin1pwd.
+ ###The following examples change the user's username to "user23" and the user's password to "user23pwd".
+ ###security.user_name.user = user23
+ ###security.user_password = user23:user23pwd
+ ###The following examples change the var's username to "var55" and the var's password to "var55pwd".
+ ###security.user_name.var = var55
+ ###security.user_password = var55:var55pwd
+ #psetting('security.user_name.user', '');
+ #psetting('security.user_name.admin', '');
+ #psetting('security.user_name.var', '');
+ psetting('security.user_password', 'admin:'.gs_get_conf('GS_YEALINK_PROV_HTTP_PASS'));
+
+ # Reboot on SIP NOTIFY
+ # 0=reboot, if additional parameter "reboot=true" was given, 1=reboot always, 2=ignore SIP NOTIFY message
+ psetting('sip.notify_reboot_enable', '0');
+
+
+ # Transfer
+ psetting('transfer.blind_tran_on_hook_enable', '1');
+ psetting('transfer.on_hook_trans_enable', '1');
+ psetting('transfer.semi_attend_tran_enable', '1');
+
+ # DSS Key press on active call: 0=new call 1=attended transfer 2=blind transfer
+ psetting('transfer.dsskey_deal_type', '1');
+
+ # Enables or disables custom soft keys layout feature.
+ psetting('phone_setting.custom_softkey_enable', '1');
+
+ # DSS extended key length
+ psetting('features.config_dsskey_length', '1');
+
+ # blf_and_callpark_idle_led_enable
+ psetting('features.blf_and_callpark_idle_led_enable', '1');
+
+ # push XML server
+ psetting('push_xml.server', $host);
+
+ # features.action_uri_limit_ip
+ psetting('features.action_uri_limit_ip', 'any');
+
+ # RTCP-XR features
+ psetting('phone_setting.vq_rtcpxr.session_report.enable', '1');
+ psetting('phone_setting.vq_rtcpxr.interval_report.enable', '1');
+ psetting('phone_setting.vq_rtcpxr_interval_period', '20');
+ psetting('phone_setting.vq_rtcpxr.states_show_on_web.enable', '1');
+ psetting('voice.rtcp_xr.enable', '1');
+
+ # Disable Warnings Display (Default Password set, Network, ...)
+ psetting('phone_setting.warnings_display.mode', '0');
+
+ #####################################################################
+ # MAC-specific provisioning parameters (applicable to SIP-T28P/T26P/T22P/T20P/T21P/T19P/T46G/T42G/T41P IP phones running firmware version 72 or later)
+ #####################################################################
+ # Account1 Basic Settings
+ psetting('account.1.enable', '1'); # 0 = disable, 1 = enable
+ psetting('account.1.label', $user_ext .' '. mb_subStr($user['firstname'],0,1) .'. '. $user['lastname']);
+ psetting('account.1.display_name', $user['callerid']);
+ psetting('account.1.auth_name', $user_ext);
+ psetting('account.1.user_name', $user_ext);
+ psetting('account.1.password', $user['secret']);
+ psetting('account.1.outbound_proxy_enable', '0'); # 0 = disable, 1 = enable
+ psetting('account.1.outbound_host', '');
+ psetting('account.1.outbound_port', '5061');
+ ##It configures the local SIP port for account 1. The default value is 5060.
+ psetting('account.1.sip_listen_port', '5060');
+ ##It configures the transport type for account 1. 0-UDP,1-TCP,2-TLS,3-DNS-NAPTR
+ psetting('account.1.transport', '0'); ##The default value is 0.
+
+ // # Failback
+ psetting('account.1.sip_server.1.address', $host);
+ psetting('account.1.sip_server.1.port', '5060');
+ psetting('account.1.sip_server.1.expires', '120');
+
+ // # Register Advanced
+ // ##It configures the SIP server type for account X.0-Default,2-BroadSoft,4-Cosmocom,6-UCAP
+ // ##The default value is 0.
+ psetting('account.1.sip_server_type', '0');
+
+ psetting('voice_mail.number.1', 'voicemail');
+ psetting('account.1.subscribe_mwi', '1');
+ psetting('account.1.display_mwi.enable', '1');
+ psetting('account.1.subscribe_mwi_to_vm', '1');
+
+ # Codecs
+ psetting('account.1.codec.1.enable', '1');
+ psetting('account.1.codec.2.enable', '1');
+ psetting('account.1.codec.3.enable', '1');
+ psetting('account.1.codec.4.enable', '0');
+ psetting('account.1.codec.5.enable', '0');
+ psetting('account.1.codec.6.enable', '0');
+ psetting('account.1.codec.7.enable', '0');
+ psetting('account.1.codec.8.enable', '0');
+ psetting('account.1.codec.9.enable', '0');
+ psetting('account.1.codec.10.enable', '0');
+ psetting('account.1.codec.11.enable', '0');
+
+ psetting('account.1.codec.1.payload_type', 'PCMA');
+ psetting('account.1.codec.2.payload_type', 'PCMU');
+ psetting('account.1.codec.3.payload_type', 'G722');
+ psetting('account.1.codec.4.payload_type', 'G723_53');
+ psetting('account.1.codec.5.payload_type', 'G723_63');
+ psetting('account.1.codec.6.payload_type', 'G729');
+ psetting('account.1.codec.7.payload_type', 'iLBC');
+ psetting('account.1.codec.8.payload_type', 'G726-16');
+ psetting('account.1.codec.9.payload_type', 'G726-24');
+ psetting('account.1.codec.10.payload_type', 'G726-32');
+ psetting('account.1.codec.11.payload_type', 'G726-40');
+
+ psetting('account.1.codec.1.priority', '2');
+ psetting('account.1.codec.2.priority', '3');
+ psetting('account.1.codec.3.priority', '1');
+ psetting('account.1.codec.4.priority', '0');
+ psetting('account.1.codec.5.priority', '0');
+ psetting('account.1.codec.6.priority', '0');
+ psetting('account.1.codec.7.priority', '0');
+ psetting('account.1.codec.8.priority', '0');
+ psetting('account.1.codec.9.priority', '0');
+ psetting('account.1.codec.10.priority', '0');
+ psetting('account.1.codec.11.priority', '0');
+
+ psetting('account.1.codec.1.rtpmap', '8'); # PCMA
+ psetting('account.1.codec.2.rtpmap', '0'); # PCMU
+ psetting('account.1.codec.3.rtpmap', '9'); # G722
+ psetting('account.1.codec.4.rtpmap', '4'); # G723_53
+ psetting('account.1.codec.5.rtpmap', '4'); # G723_63
+ psetting('account.1.codec.6.rtpmap', '18'); # G729
+ psetting('account.1.codec.7.rtpmap', '106'); # iLBC
+ psetting('account.1.codec.8.rtpmap', '103'); # G726-16
+ psetting('account.1.codec.9.rtpmap', '104'); # G726-24
+ psetting('account.1.codec.10.rtpmap', '102'); # G726-32
+ psetting('account.1.codec.11.rtpmap', '105'); # G726-40
+
+ psetting('account.1.ptime', '20'); # 20ms
+
+ // psetting('account.1.unregister_on_reboot', '');
+ // psetting('account.1.sip_trust_ctrl', '');
+ // psetting('account.1.proxy_require', '');
+ // psetting('account.1.srv_ttl_timer_enable', '');
+ // psetting('account.1.register_mac', '1'); # 0 = disable, 1 = enable
+ // psetting('account.1.register_line', '1'); # 0 = disable, 1 = enable
+ // psetting('account.1.reg_fail_retry_interval', '30'); # 0 to 1800, default 30
+
+ // # NAT
+ // ##It enables or disables the NAT traversal for account X.0-Disabled,1-Enabled
+ // ##The default value is 0.
+ // psetting('account.1.nat.nat_traversal', '');
+ // ##It configures the IP address or domain name of the STUN server for account X.
+ // ##The default value is blank.
+ // psetting('account.1.nat.stun_server', '');
+ // ##It configures the port of the STUN server for account X.
+ // ##The default value is 3478.
+ // psetting('account.1.nat.stun_port', '');
+ // ##It configures the type of keep-alive packets sent by the phone to the NAT device to keep the communication port open so that NAT can continue to function for account X.
+ // ##The default value is 1.
+ // psetting('account.1.nat.udp_update_enable', '');
+ // ##It configures the keep-alive interval (in seconds) for account X.
+ // ##The default value is 30.Integer from 15 to 2147483647
+ // psetting('account.1.nat.udp_update_time', '');
+ // ##It enables or disables NAT Rport feature for account X.0-Disabled,1-Enabled
+ // ##The default value is 0.
+ // psetting('account.1.nat.rport', '');
+
+ // # Pickup
+ // ##It enables or disables the phone to pick up a call according to the SIP header of dialog-info for account X
+ // ##0-Disabled,1-Enabled.
+ // ##The default value is 0.
+ // Must be DISABLED to work on Asterisk PBX
+ psetting('account.1.dialoginfo_callpickup', '0');
+ // ##It configures the group pickup code for account X.
+ // ##The default value is blank.
+ psetting('account.1.group_pickup_code', '');
+ // ##It configures the directed pickup code for account X.
+ // ##The default value is blank.
+ psetting('account.1.direct_pickup_code', '*81*');
+
+
+ # DTMF 0=Inband 1=RFC2833 2=SIP INFO 3=RFC2833+SIP INFO
+ psetting('account.1.dtmf.type', '1');
+
+ # DTMF Info Type 1=DTMF-Relay 2=DTMF 3=Telephone-Event
+ psetting('account.1.dtmf.info_type', '1');
+
+ # allow alert info URL
+ psetting('account.1.alert_info_url_enable', '1');
+
+ # CID Source. 0-FROM 1-PAI 2-PAI-FROM 3-RPID-PAI-FROM 4-PAI-RPID-FROM 5-RPID-FROM
+ psetting('account.1.cid_source', '3');
+
+ # Time
+ ##It configures the time zone.For more available time zones, refer to Time Zones on page 215.
+ ##The default value is +8.
+ psetting('local_time.time_zone', '+1');
+ psetting('local_time.time_zone_name', 'Germany(Berlin)');
+ ##It configures the time zone name.For more available time zone names, refer to Time Zones on page 215.
+ ##The default time zone name is China(Beijing).
+ psetting('local_time.ntp_server1', gs_get_conf('GS_YEALINK_PROV_NTP'));
+ psetting('local_time.ntp_server2', gs_get_conf('GS_YEALINK_PROV_NTP')); # override default chinese NTP server
+ ## NTP setting fron DHCP has high priority
+ psetting('local_time.manual_ntp_srv_prior','0');
+ psetting('local_time.interval' , strval(rand(980,1020))); # default 1000
+ psetting('local_time.time_format', '1');
+ psetting('local_time.date_format', '5'); # 0-WWW MMM DD; 1-DD-MMM-YY; 2-YYYY-MM-DD; 3-DD/MM/YYYY; 4-MM/DD/YY; 5-DD MMM YYYY; 6-WWW DD MMM
+
+ #######################################################################################
+ ## Features Pickup(Except T20P model) ##
+ #######################################################################################
+ ##It enables or disables the phone to display the GPickup soft key when the phone is in the pre-dialing screen.
+ ##0-Disabled,1-Enabled.
+ ##The default value is 0.
+ psetting('features.pickup.group_pickup_enable', '0');
+
+ ##It configures the group call pickup code.
+ ##The default value is blank.
+ psetting('features.pickup.group_pickup_code', '');
+
+ ##It enables or disables the phone to display the DPickup soft key when the phone is in the pre-dialing screen.
+ ##0-Disabled,1-Enabled.
+ ##The default value is 0.
+ psetting('features.pickup.direct_pickup_enable', '1');
+
+ ##It configures the directed call pickup code.
+ ##The default value is blank.
+ psetting('features.pickup.direct_pickup_code', '*81*');
+
+ ##It enables or disables the phone to display a visual alert when the monitored user receives an incoming call.
+ ##0-Disabled,1-Enabled.
+ ##The default value is 0.
+ psetting('features.pickup.blf_visual_enable', '0');
+
+ ##It enables or disables the phone to play an audio alert when the monitored user receives an incoming call.
+ ##0-Disabled,1-Enabled.
+ ##The default value is 0.
+ psetting('features.pickup.blf_audio_enable', '0');
+
+ #####################################################################
+ # Keys and Device specific settings
+ #####################################################################
+
+ switch ($phone_type) {
+ case 'yealink-sip-t42g':
+ $max_keys=15;
+ break;
+ case 'yealink-sip-t46g':
+ $max_keys=27;
+ psetting('screensaver.wait_time', '21600');
+ break;
+ case 'yealink-sip-t48g':
+ $max_keys=29;
+ psetting('screensaver.wait_time', '21600');
+ break;
+ case 'yealink-sip-t42s':
+ $max_keys=15;
+ break;
+ case 'yealink-sip-t46s':
+ $max_keys=27;
+ psetting('screensaver.wait_time', '21600');
+ break;
+ case 'yealink-sip-t46u':
+ $max_keys=27;
+ psetting('screensaver.wait_time', '21600');
+ break;
+ }
+
+ # RESET KEYS
+ for ($i=1; $i <= $max_keys; $i++) {
+ psetting('linekey.'.$i.'.line', '0');
+ psetting('linekey.'.$i.'.value', '');
+ psetting('linekey.'.$i.'.pickup_value', '');
+ psetting('linekey.'.$i.'.extension', '');
+ psetting('linekey.'.$i.'.type', '0');
+ psetting('linekey.'.$i.'.xml_phonebook', '0');
+ psetting('linekey.'.$i.'.label', '');
+ }
+
+ # TODO: RESET PROGRAMMABLE KEYS?
+ # Programable Key 1 (default "History") > GS History
+ # Programable Key 5 (UP Key)(default "History") > GS History
+ # Programable Key 6 (DOWN Key)(default "Phonebook") > XML Phonebook
+ psetting('programablekey.1.type', '27'); # XML Browser
+ psetting('programablekey.1.value', $prov_url_yealink.'dial-log.php?user='.$user_ext );
+ psetting('programablekey.1.label', 'Anrufliste');
+ psetting('programablekey.5.type', '27'); # XML Browser
+ psetting('programablekey.5.value', $prov_url_yealink.'dial-log.php?user='.$user_ext );
+ psetting('programablekey.5.label', 'Anrufliste');
+
+ psetting('programablekey.6.type', '47'); # XML Phonebook
+ psetting('programablekey.6.value', '' );
+ psetting('programablekey.6.label', 'Tel.Buch');
+
+ # max 6 EXP40 Modules allowed
+ # get max configured EXP40 count to speed up provisioning
+ $max_ext_modules = (int)$db->executeGetOne( 'SELECT `g`.`show_ext_modules` FROM `users` `u` JOIN `user_groups` `g` ON (`g`.`id`=`u`.`group_id`) WHERE `u`.`id`='.$user_id );
+ if ($max_ext_modules >6) { $max_ext_modules=6; }
+
+
+ # RESET EXP KEYS on EXP40
+ if ($phone_type == 'yealink-sip-t46g' || $phone_type == 'yealink-sip-t48g' || $phone_type == 'yealink-sip-t46s') {
+ for ($j=1; $j<=$max_ext_modules; $j++) {
+ for ($i=1; $i <= 40; $i++) {
+ psetting('expansion_module.'.$j.'.key.'.$i.'.line', '0');
+ psetting('expansion_module.'.$j.'.key.'.$i.'.value', '');
+ psetting('expansion_module.'.$j.'.key.'.$i.'.type', '0');
+ psetting('expansion_module.'.$j.'.key.'.$i.'.label', '');
+ }
+ }
+ }
+
+ # RESET EXP KEYS on EXP43
+ if ($phone_type == 'yealink-sip-t46u') {
+ # max 3 EXP43 Modules allowed
+ # get max configured EXP43 count to speed up provisioning
+ if ($max_ext_modules >3) { $max_ext_modules=3; }
+
+ for ($j=1; $j<=$max_ext_modules; $j++) {
+ for ($i=1; $i <= 60; $i++) {
+ psetting('expansion_module.'.$j.'.key.'.$i.'.line', '0');
+ psetting('expansion_module.'.$j.'.key.'.$i.'.value', '');
+ psetting('expansion_module.'.$j.'.key.'.$i.'.type', '0');
+ psetting('expansion_module.'.$j.'.key.'.$i.'.label', '');
+ }
+ }
+ }
+
+
+ $softkeys = null;
+ $GS_Softkeys = gs_get_key_prov_obj( $phone_type );
+ if ($GS_Softkeys->set_user( $user['user'] )) {
+ if ($GS_Softkeys->retrieve_keys( $phone_type, array(
+ '{GS_PROV_HOST}' => gs_get_conf('GS_PROV_HOST'),
+ '{GS_P_PBX}' => $pbx,
+ '{GS_P_EXTEN}' => $user_ext,
+ '{GS_P_ROUTE_PREFIX}' => $hp_route_prefix,
+ '{GS_P_USER}' => $user['user']
+ ) )) {
+ $softkeys = $GS_Softkeys->get_keys();
+ }
+ }
+ if (! is_array($softkeys)) {
+ gs_log( GS_LOG_WARNING, 'Failed to get softkeys' );
+ } else {
+ gs_log( GS_LOG_DEBUG, 'Num Softkeys to set: '.count($softkeys) );
+
+ foreach ($softkeys as $key_name => $key_defs) {
+ if (array_key_exists('slf', $key_defs)) {
+ $key_def = $key_defs['slf'];
+ } elseif (array_key_exists('inh', $key_defs)) {
+ $key_def = $key_defs['inh'];
+ } else {
+ continue;
+ }
+
+ # $key_name is Fxxyy , where xx is extension module and yy is key index
+ $key_idx = (int)lTrim(subStr($key_name,3),'0');
+ $key_exp = (int)lTrim(subStr($key_name,1,2),'0');
+ # gs_log( GS_LOG_DEBUG, 'Softkey '.$key_name.' -> Exp='.$key_exp.' Idx='.$key_idx );
+ if ($key_def['function'] === 'f0') continue;
+
+ #######################################################################################
+ ## Line Keys ##
+ #######################################################################################
+ if ($key_idx >= 1 && $key_idx <= $max_keys && $key_exp == 0) {
+ gs_log( GS_LOG_DEBUG, 'Set LineKey('.$key_idx.') value=\''.$key_def['data'].'\' type=\''.subStr($key_def['function'],1).'\' label=\''.$key_def['label'].'\'' );
+
+ ###It configures the desired line to apply the key feature.Integer from 1 to 6
+ psetting('linekey.'.$key_idx.'.line', 1);
+ ###It configures the value of the line key feature.
+ ###For example, when setting the key feature to BLF, it configures the number of the monitored user.
+ ###The default value is blank.
+ psetting('linekey.'.$key_idx.'.value', $key_def['data']);
+ # for BLF
+ if (subStr($key_def['function'],1) == 16 ) {
+ ###It configures the pickup code for BLF feature or conference ID followed by the # sign for Meet-Me conference feature.
+ ###It only applies to BLF and Meet-Me conference features.
+ ###The default value is blank
+ psetting('linekey.'.$key_idx.'.pickup_value', '*81*');
+ }
+ ###It configures the key feature for the line key X.
+ #The valid types are:
+ #0-NA 1-Conference 2-Forward 3-Transfer 4-Hold 5-DND 7-Call Return 8-SMS 9-Directed Pickup
+ #10-Call Park 11-DTMF 12-Voice Mail 13-Speed Dial 14-Intercom 15-Line 16-BLF 17-URL 18-Group Listening
+ #20-Private Hold 22-XML Group 23-Group Pickup 24-Multicast Paging 25-Record 27-XML Browser
+ #34-Hot Desking 35-URL Record 38-LDAP 39-BLF List
+ #40-Prefix 41-Zero Touch 42-ACD 45-Local Group 46-Network Group 49-Custom Button
+ #50-Keypad Lock 55-Meet-Me Conference 56-Retrieve Park 57-Hoteling 58-ACD Grace 59-Sisp Code
+ #60-Emergency 61-Directory
+ #----
+ #0-NA ��Only for T41/T42/T46)
+ #22-XML Group (Not support T20)
+ #38-LDAP (Not support T20)
+ #46-Network Group (Not support T20)
+ #8-SMS (Only support T21/T46/T22/T26/T28)
+ #17-URL (Only support T41/T42/T46)
+ #49-Custom Button (Only support T20/T22/T26/T28)
+ psetting('linekey.'.$key_idx.'.type', subStr($key_def['function'],1));
+ ###It configures the desired local group/XML group/network group for the line key X.
+ ###It only applies to the Local Group, XML Group and Network Group features.
+ ###XML Group and Network Group features are not applicable to SIP-T20P IP phones.
+ // psetting('linekey.'.$key_idx.'.xml_phonebook', '0');
+ ###It configures the label displayed on the LCD screen for each line key.
+ ###The default value is blank.
+ psetting('linekey.'.$key_idx.'.label', $key_def['label']);
+ }
+ #######################################################################################
+ ## Expansion Keys ##
+ #######################################################################################
+ else if ($key_idx >= 1 && $key_idx <= 40 && $key_exp >= 1 && $key_exp <=6) {
+ gs_log( GS_LOG_DEBUG, 'Set ExpKey('.$key_idx.') value=\''.$key_def['data'].'\' type=\''.subStr($key_def['function'],1).'\' label=\''.$key_def['label'].'\'' );
+ ###It configures the desired line to apply the key feature.Integer from 1 to 6
+ psetting('expansion_module.'.$key_exp.'.key.'.$key_idx.'.line', 1);
+ ###It configures the value of the line key feature.
+ ###For example, when setting the key feature to BLF, it configures the number of the monitored user.
+ ###The default value is blank.
+ psetting('expansion_module.'.$key_exp.'.key.'.$key_idx.'.value', $key_def['data']);
+ # for BLF
+ if (subStr($key_def['function'],1) == 16 ) {
+ ###It configures the pickup code for BLF feature or conference ID followed by the # sign for Meet-Me conference feature.
+ ###It only applies to BLF and Meet-Me conference features.
+ ###The default value is blank
+ psetting('expansion_module.'.$key_exp.'.key.'.$key_idx.'.pickup_value', '*81*');
+ }
+ ###It configures the key feature for the line key X.
+ #The valid types are:
+ #0-NA 1-Conference 2-Forward 3-Transfer 4-Hold 5-DND 7-Call Return 8-SMS 9-Directed Pickup
+ #10-Call Park 11-DTMF 12-Voice Mail 13-Speed Dial 14-Intercom 15-Line 16-BLF 17-URL 18-Group Listening
+ #20-Private Hold 22-XML Group 23-Group Pickup 24-Multicast Paging 25-Record 27-XML Browser
+ #34-Hot Desking 35-URL Record 38-LDAP 39-BLF List
+ #40-Prefix 41-Zero Touch 42-ACD 45-Local Group 46-Network Group 49-Custom Button
+ #50-Keypad Lock 55-Meet-Me Conference 56-Retrieve Park 57-Hoteling 58-ACD Grace 59-Sisp Code
+ #60-Emergency 61-Directory
+ #----
+ #0-NA ��Only for T41/T42/T46)
+ #22-XML Group (Not support T20)
+ #38-LDAP (Not support T20)
+ #46-Network Group (Not support T20)
+ #8-SMS (Only support T21/T46/T22/T26/T28)
+ #17-URL (Only support T41/T42/T46)
+ #49-Custom Button (Only support T20/T22/T26/T28)
+ psetting('expansion_module.'.$key_exp.'.key.'.$key_idx.'.type', subStr($key_def['function'],1));
+ ###It configures the desired local group/XML group/network group for the line key X.
+ ###It only applies to the Local Group, XML Group and Network Group features.
+ ###XML Group and Network Group features are not applicable to SIP-T20P IP phones.
+ // psetting('linekey.'.$key_idx.'.xml_phonebook', '0');
+ ###It configures the label displayed on the LCD screen for each line key.
+ ###The default value is blank.
+ psetting('expansion_module.'.$key_exp.'.key.'.$key_idx.'.label', $key_def['label']);
+
+ }
+ # TODO: Programmable Keys
+ # TODO: Keys on Expansion Modul
+ }
+ }
+}
+
+
+#####################################################################
+# Override provisioning parameters (group profile)
+#####################################################################
+$prov_params = null;
+$GS_ProvParams = gs_get_prov_params_obj( $phone_type );
+if ($GS_ProvParams->set_user( $user['user'] )) {
+ if ($GS_ProvParams->retrieve_params( $phone_type, array(
+ '{GS_PROV_HOST}' => gs_get_conf('GS_PROV_HOST'),
+ '{GS_P_PBX}' => $pbx,
+ '{GS_P_EXTEN}' => $user_ext,
+ '{GS_P_ROUTE_PREFIX}' => $hp_route_prefix,
+ '{GS_P_USER}' => $user['user']
+ ) )) {
+ $prov_params = $GS_ProvParams->get_params();
+ }
+}
+
+gs_log( GS_LOG_DEBUG, "Retrieved ".count($prov_params)." Group-Profile parameters for phone_type: ".$phone_type );
+
+if (! is_array($prov_params)) {
+ gs_log( GS_LOG_WARNING, 'Failed to get provisioning parameters (group)' );
+} else {
+ foreach ($prov_params as $param_name => $param_arr) {
+ foreach ($param_arr as $param_index => $param_value) {
+ if ($param_index == -1) {
+ # not an array
+ if (! array_key_exists($param_name, $settings)) {
+ # new parameter
+ gs_log( GS_LOG_DEBUG, "Group prov. param \"$param_name\": \"$param_value\"" );
+ } else {
+ # override parameter
+ gs_log( GS_LOG_DEBUG, "Overriding group prov. param \"$param_name\": \"$param_value\"" );
+ }
+
+ psetting($param_name, $param_value);
+ } else {
+ # array
+ gs_log( GS_LOG_NOTICE, "Group prov. param \"$param_name\"[$param_index]: Yealink does not support arrays" );
+ }
+ }
+ }
+}
+unset($prov_params);
+unset($GS_ProvParams);
+
+
+#####################################################################
+# Override provisioning parameters (user profile)
+#####################################################################
+$prov_params = @gs_user_prov_params_get( $user['user'], $phone_type );
+
+gs_log( GS_LOG_DEBUG, "Retrieved ".count($prov_params)." User-Profile parameters for phone_type: ".$phone_type.", user: ".$user['user'] );
+
+if (! is_array($prov_params)) {
+ gs_log( GS_LOG_WARNING, 'Failed to get provisioning parameters (user)' );
+} else {
+ foreach ($prov_params as $p) {
+ if ($p['index'] === null
+ || $p['index'] == -1) {
+ # not an array
+ if (! array_key_exists($p['param'], $settings)) {
+ # new parameter
+ gs_log( GS_LOG_DEBUG, 'User prov. param "'.$p['param'].'": "'.$p['value'].'"' );
+ } else {
+ # override parameter
+ gs_log( GS_LOG_DEBUG, 'Overriding user prov. param "'.$p['param'].'": "'.$p['value'].'"' );
+ }
+
+ psetting($p['param'], $p['value']);
+ } else {
+ # array
+ gs_log( GS_LOG_NOTICE, 'User prov. param "'.$p['param'].'"['.$p['index'].']: Yealink does not support arrays"' );
+ }
+ }
+}
+unset($prov_params);
+
+
+#####################################################################
+# output
+#####################################################################
+ob_start();
+_settings_out();
+if (! headers_sent()) {
+ header( 'Content-Type: text/plain; charset=utf-8' );
+ # avoid chunked transfer-encoding
+ header( 'Content-Length: '. (int)@ob_get_length() );
+}
+@ob_flush();
+
+?>
diff --git a/opt/gemeinschaft/inc/conf.php b/opt/gemeinschaft/inc/conf.php
index 6dde6d673..5afa37b4a 100644
--- a/opt/gemeinschaft/inc/conf.php
+++ b/opt/gemeinschaft/inc/conf.php
@@ -127,7 +127,6 @@ function gs_get_conf( $key, $default=null )
return @defined($key) ? constant($key) : $default;
}
-
$conf = '/etc/gemeinschaft/gemeinschaft.php';
if (! file_exists( $conf )) {
trigger_error( "Config file \"$conf\" not found!\n", E_USER_ERROR );
@@ -140,7 +139,6 @@ function gs_get_conf( $key, $default=null )
}
}
-
function _gscnf( $param, $default=null )
{
if (@array_key_exists($param, $GLOBALS)) {
@@ -245,6 +243,7 @@ function _gscnf( $param, $default=null )
_gscnf( 'PROV_MODELS_ENABLED_AASTRA' , '*' ); # / '51i,53i,55i,57i'
_gscnf( 'PROV_MODELS_ENABLED_GRANDSTREAM' , '*' ); # / 'gxp2000,gxp2020'...
_gscnf( 'PROV_MODELS_ENABLED_TIPTEL' , '*' ); # / 'ip280,ip284,ip286'
+_gscnf( 'PROV_MODELS_ENABLED_YEALINK' , '*' ); # / 'yealink-sip-t46g,yealink-sip-t48g'
_gscnf( 'PROV_MODELS_ENABLED_POLYCOM' , '*' ); # / 'spip-550,spip-670', ...
_gscnf( 'SNOM_PROV_ENABLED' , false );
@@ -332,6 +331,20 @@ function _gscnf( $param, $default=null )
_gscnf( 'TIPTEL_PROV_FW_DEFAULT_IP286' , null );
_gscnf( 'TIPTEL_PROV_KEY_BLACKLIST' , '' );
+_gscnf( 'YEALINK_PROV_ENABLED' , false );
+_gscnf( 'YEALINK_PROV_HTTP_PASS' , '' );
+_gscnf( 'YEALINK_PROV_NTP' , gs_get_conf('GS_PROV_HOST','') );
+_gscnf( 'YEALINK_PROV_FW_UPDATE' , false );
+_gscnf( 'YEALINK_PROV_FW_DEFAULT_SIP_T42G', null );
+_gscnf( 'YEALINK_PROV_FW_DEFAULT_SIP_T46G', null );
+_gscnf( 'YEALINK_PROV_FW_DEFAULT_SIP_T48G', null );
+_gscnf( 'YEALINK_PROV_FW_DEFAULT_SIP_T42S', null );
+_gscnf( 'YEALINK_PROV_FW_DEFAULT_SIP_T46S', null );
+_gscnf( 'YEALINK_PROV_FW_DEFAULT_SIP_T46U', null );
+//_gscnf( 'YEALINK_PROV_FW_DEFAULT_IP284' , null );
+//_gscnf( 'YEALINK_PROV_FW_DEFAULT_IP286' , null );
+_gscnf( 'YEALINK_PROV_KEY_BLACKLIST' , '' );
+
_gscnf( 'CANONIZE_OUTBOUND' , true );
_gscnf( 'CANONIZE_INTL_PREFIX' , '00' );
_gscnf( 'CANONIZE_COUNTRY_CODE' , '49' );
@@ -398,6 +411,7 @@ function _gscnf( $param, $default=null )
_gscnf( 'FAX_HYLAFAX_PASS' , '' );
_gscnf( 'FAX_HYLAFAX_PATH' , '/var/spool/hylafax/' );
_gscnf( 'FAX_INIT_DOCDIR' , '/tmp/' );
+_gscnf( 'FAX_MAP_IAXMODEM_USER' , '' );
_gscnf( 'BOI_ENABLED' , false );
diff --git a/opt/gemeinschaft/inc/gs-fns/gs_prov_params_get.php b/opt/gemeinschaft/inc/gs-fns/gs_prov_params_get.php
index d9a65fddd..4e310f7bd 100644
--- a/opt/gemeinschaft/inc/gs-fns/gs_prov_params_get.php
+++ b/opt/gemeinschaft/inc/gs-fns/gs_prov_params_get.php
@@ -70,8 +70,7 @@ function gs_prov_params_get( $username, $phone_type )
if (! is_array($path))
return new GsError( 'DB error.' );
foreach ($path as $group) {
- if ($group['prov_param_profile_id'] > 0) {
-
+ if ($group['prov_param_profile_id'] > 0) {
//echo 'Get group\'s prov param profile, id '. $group['prov_param_profile_id'] ."\n";
$rs = $db->execute(
'SELECT `param`, `index`, `value` '.
@@ -90,7 +89,31 @@ function gs_prov_params_get( $username, $phone_type )
}
}
}
-
+
+ # get keys for phonetype
+ if($user['group_id'] < 1) {
+ $mptt = new YADB_MPTT($db, 'user_groups', 'lft', 'rgt', 'title');
+ $group = $mptt->_db_query( 'SELECT * FROM user_groups WHERE `title`=\''. $db->escape($phone_type) .'\'' );
+ if (! $group)
+ return new GsError( 'DB error.' );
+ if ($group['prov_param_profile_id'] > 0) {
+ //echo 'Get group\'s prov param profile, id '. $group['prov_param_profile_id'] ."\n";
+ $rs = $db->execute(
+ 'SELECT `param`, `index`, `value` '.
+ 'FROM `prov_params` '.
+ 'WHERE '.
+ '`profile_id`='. $group['prov_param_profile_id'] .' AND '.
+ '`phone_type`=\''. $db->escape($phone_type) .'\' '.
+ 'ORDER BY `param`, `index`' );
+ while ($r = $rs->fetchRow()) {
+ $r['_set_by'] = 'g';
+ $r['_setter'] = $user['group_id'];
+
+ $params[$r['param']][$r['index']] = $r['value'];
+ }
+ }
+ }
+
return $params;
}
diff --git a/opt/gemeinschaft/inc/gs-fns/gs_prov_phone_checkcfg.php b/opt/gemeinschaft/inc/gs-fns/gs_prov_phone_checkcfg.php
index 462378d04..5f5bc8f6e 100644
--- a/opt/gemeinschaft/inc/gs-fns/gs_prov_phone_checkcfg.php
+++ b/opt/gemeinschaft/inc/gs-fns/gs_prov_phone_checkcfg.php
@@ -235,6 +235,9 @@ function _gs_prov_phone_checkcfg_by_ip_do( $ip, $reboot=true )
if (gs_get_conf('GS_TIPTEL_PROV_ENABLED')) {
_gs_prov_phone_checkcfg_by_ip_do_tiptel( $ip, $reboot );
}
+ if (gs_get_conf('GS_YEALINK_PROV_ENABLED')) {
+ _gs_prov_phone_checkcfg_by_ip_do_yealink( $ip, $reboot );
+ }
//return $err == 0;
return true;
@@ -318,9 +321,69 @@ function _gs_prov_phone_checkcfg_by_ip_do_grandstream( $ip, $reboot=true )
{
if (_gs_prov_phone_checkcfg_exclude_ip( $ip )) return;
+ $db = @gs_db_slave_connect();
+ if (! $db) {
+ gs_log(GS_LOG_WARNING, 'Failed to connect to DB');
+ return;
+ }
+
+ $type = @$db->executeGetOne('
+ SELECT
+ `p`.`type`
+ FROM
+ `users` `u`
+ JOIN
+ `phones` `p` ON (`p`.`user_id` = `u`.`id`)
+ WHERE
+ `u`.`current_ip` = \''. $db->escape($ip) .'\'
+ ');
+
+ $model = strtoupper( str_replace( 'grandstream-', '', $type ) );
+
+ if ( preg_match('/^GXP21([0-9]{2})$/', $model) ) {
+ reboot_grandstream21xx( $ip, $model );
+ return;
+ }
+
@ exec( '/opt/gemeinschaft/sbin/gs-grandstream-reboot --ip='. qsa($ip) .' >>/dev/null 2>>/dev/null &', $out, $err );
}
+function reboot_grandstream21xx($ip_addr, $model)
+{
+ $socket = fsockopen("$ip_addr","23", $errno, $errstr, 1000);
+ if (!$socket) {
+ // echo "$errstr ($errno)
\n";
+ exit;
+ }
+ read_up_to("Grandstream $model Command Shell Copyright 2011",$socket);
+ fputs($socket, "admin\r\n");
+ read_up_to("$model",$socket);
+ fputs($socket, "reboot\r\n");
+ read_up_to("Rebooting",$socket);
+ fputs($socket, "exit\r\n");
+ read_up_to("endlessssssssss",$socket); //this is just to keep it until reboot command execute
+ fclose($socket);
+}
+
+function read_up_to($string,$socket)
+{
+ $max_loop = 30;
+ $resp = "";
+ while (!feof($socket))
+ {
+ if ($max_loop<0)
+ break;
+ $max_loop--;
+ $resp .= fgets($socket, 10);
+ // echo $resp."
";
+ if (strstr($resp,$string))
+ {
+ // echo "found" . $resp . "
";
+ break;
+ }
+ }
+}
+
function _gs_prov_phone_checkcfg_by_ip_do_polycom( $ip, $reboot=true )
{
if (_gs_prov_phone_checkcfg_exclude_ip( $ip )) return;
@@ -372,6 +435,27 @@ function _gs_prov_phone_checkcfg_by_ip_do_tiptel( $ip, $reboot=true )
@ exec( '/opt/gemeinschaft/sbin/gs-tiptel-reboot --ip='. qsa($ip) .' >>/dev/null 2>>/dev/null &', $out, $err );
}
+function _gs_prov_phone_checkcfg_by_ip_do_yealink( $ip, $reboot=true )
+{
+ if (_gs_prov_phone_checkcfg_exclude_ip( $ip )) return;
+
+ gs_log(GS_LOG_DEBUG, "Send yealink update config \"$ip\"");
+
+ $url = 'http://' . qsa($ip) .'/servlet';
+
+ //open connection
+ $ch = curl_init();
+
+ //set the url, number of POST vars, POST data
+ curl_setopt($ch,CURLOPT_URL,$url);
+ curl_setopt($ch,CURLOPT_POST,3);
+ curl_setopt($ch,CURLOPT_POSTFIELDS,'p=settings-autop&q=write&now=true');
+
+ //execute post
+ $result = curl_exec($ch);
+
+}
+
// PRIVATE:
function _gs_prov_phone_checkcfg_by_ext_do( $ext, $reboot=true )
{
@@ -434,7 +518,9 @@ function _gs_prov_phone_checkcfg_by_ext_do( $ext, $reboot=true )
if (gs_get_conf('GS_TIPTEL_PROV_ENABLED')) {
_gs_prov_phone_checkcfg_by_ext_do_tiptel( $ext, $reboot );
}
-
+ if (gs_get_conf('GS_YEALINK_PROV_ENABLED')) {
+ _gs_prov_phone_checkcfg_by_ext_do_yealink( $ext, $reboot );
+ }
//return $err == 0;
return true;
}
@@ -548,7 +634,28 @@ function _gs_prov_phone_checkcfg_by_ext_do_aastra( $ext, $reboot=true )
function _gs_prov_phone_checkcfg_by_ext_do_grandstream( $ext, $reboot=true )
{
- //FIXME
+ $db = @gs_db_slave_connect();
+ if (! $db) {
+ gs_log(GS_LOG_WARNING, 'Failed to connect to DB');
+ return;
+ }
+
+ $ip = @$db->executeGetOne(
+ 'SELECT
+ `u`.`current_ip`
+ FROM
+ `ast_sipfriends` `s`
+ JOIN
+ `users` `u` ON (`u`.`id`=`s`.`_user_id`)
+ WHERE `s`.`name`=\''. $db->escape($ext) .'\''
+ );
+
+ if (! $ip || ! preg_match('/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/', $ip)) {
+ gs_log(GS_LOG_WARNING, 'Bad IP');
+ return;
+ }
+
+ _gs_prov_phone_checkcfg_by_ip_do_grandstream( $ip, $reboot);
}
function _gs_prov_phone_checkcfg_by_ext_do_polycom( $ext, $reboot=true )
@@ -574,4 +681,22 @@ function _gs_prov_phone_checkcfg_by_ext_do_tiptel( $ext, $reboot=true )
//FIXME
}
+function _gs_prov_phone_checkcfg_by_ext_do_yealink( $ext, $reboot=true )
+{
+ $sip_notify = $reboot ? 'yealink-check-cfg-reboot' : 'yealink-check-cfg';
+ @exec( 'sudo asterisk -rx \'sip notify '. $sip_notify .' '. $ext .'\' >>/dev/null 2>>/dev/null &', $out, $err );
+
+ $hosts = @gs_hosts_get(false);
+ if (isGsError($hosts)) {
+ gs_log(GS_LOG_WARNING, 'Failed to get hosts - '. $hosts->getMsg());
+ } elseif (! is_array($hosts)) {
+ gs_log(GS_LOG_WARNING, 'Failed to get hosts');
+ } else {
+ $cmd = 'asterisk -rx \'sip notify '. $sip_notify .' '. $ext .'\'';
+ foreach ($hosts as $host) {
+ @exec( 'sudo ssh -o StrictHostKeyChecking=no -o BatchMode=yes -l root '. qsa($host['host']) .' '. qsa($cmd) .' >>/dev/null 2>>/dev/null &' );
+ }
+ }
+}
+
?>
\ No newline at end of file