diff options
author | tzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb> | 2008-02-04 23:00:48 +0000 |
---|---|---|
committer | tzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb> | 2008-02-04 23:00:48 +0000 |
commit | 7e068801fbf82413ac0a5e63e586c268bd457434 (patch) | |
tree | 9b61e9a4e07167e0b7d347e4336245724befa29c /kernel/xpp/utils/genzaptelconf | |
parent | 29daeebad888269fa0ee2ca7e54e238c8498ca2d (diff) |
Move kernel stuff to under kernel/
(merged branch /zaptel/team/tzafrir/move )
Closes issue #7117.
git-svn-id: http://svn.digium.com/svn/zaptel/branches/1.4@3793 5390a7c7-147a-4af0-8ec9-7488f05a26cb
Diffstat (limited to 'kernel/xpp/utils/genzaptelconf')
-rwxr-xr-x | kernel/xpp/utils/genzaptelconf | 1195 |
1 files changed, 1195 insertions, 0 deletions
diff --git a/kernel/xpp/utils/genzaptelconf b/kernel/xpp/utils/genzaptelconf new file mode 100755 index 0000000..1435e9f --- /dev/null +++ b/kernel/xpp/utils/genzaptelconf @@ -0,0 +1,1195 @@ +#! /bin/bash + +# genzaptelconf: generate as smartly as you can: +# /etc/zaptel.conf +# /etc/asterisk/zapata-channels.conf (to be #include-d into zapata.conf) +# update: +# With '-M' /etc/modules (list of modules to load) +# +# Copyright (C) 2005 by Xorcom <support@xorcom.com> +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# +# If you have any technical questions, contact +# Tzafrir Cohen <tzafrir.cohen@xorcom.com> +# + +# The script uses a number of bash-specific features +# TODO: either ditch them or convert to perl +# Don't override variables here. +# Override them in /etc/default/zaptel (debian) or /etc/sysconfig/zaptel +# (redhat/centos) + +# /etc/default/zaptel may override the following variables +VERSION=0.5.10 +rcsid='$Id$' +lc_country=us +# set to: ls, ks or gs for (Loopstart, Kewlstart and GroundStart) +# on FXS channels (FXO signalling). +fxs_default_start=ks +base_exten=6000 +# If set: no context changes are made in zapata-channels.conf +#context_manual=yes +context_lines=from-pstn # context into which PSTN calls go +context_phones=from-internal # context for internal phones calls. +# The two below apply to input and output ports of the Xorcom Astribank: +context_input=astbank-input +context_output=astbank-output # useless, but helps marking the channels :-) +# TODO: what about PRI/BRI? +# If set: no group changes are made in zapata-channels.conf +#group_manual=yes +group_phones=5 # group for phones +group_lines=0 # group for lines +# Set fxs_immediate to 'yes' to make all FXS lines answer immediately. +fxs_immediate=no + +ZAPCONF_FILE=${ZAPCONF_FILE:-/etc/zaptel.conf} +ZAPCONF_FILE_SYSTEM=$ZAPCONF_FILE +ZAPATA_FILE=${ZAPATA_FILE:-/etc/asterisk/zapata-channels.conf} +ZAPSCAN_FILE=${ZAPSCAN_FILE:-/etc/asterisk/zapscan.conf} +ZAPTEL_BOOT_DEBIAN=${ZAPTEL_BOOT_DEBIAN:-/etc/default/zaptel} +ZAPTEL_BOOT_FEDORA=${ZAPTEL_BOOT_FEDORA:-/etc/sysconfig/zaptel} +MODLIST_FILE=/etc/modules +MODLIST_FILE_FEDORA=/etc/sysconfig/zaptel +exten_base_dir=/etc/asterisk/extensions-phones.d +exten_defs_file=/etc/asterisk/extensions-defs.conf +# perl utilities: +xpp_sync=/usr/sbin/xpp_sync +zt_registration=/usr/sbin/zt_registration +# how long to wait for /dev/zap/ctl to appear? (seconds) +DEVZAP_TIMEOUT=${DEVZAP_TIMEOUT:-20} +ZTCFG=${ZTCFG:-/sbin/ztcfg} +# BRI/PRI spans will be in an additional per-span group whose number +# is SPAN_GROUP_BASE + span-number +SPAN_GROUP_BASE=10 +# set to "yes" to make BRI NT spans set overlapdial (handy for ISDN phones +# and other devices). +brint_overlap=no + +# a temporary directory to store whatever we need to remember. +# +# The main loop of genconf is run in a sub-process. +tmp_dir= + +# A list of all modules: +# - the list of modules which will be probed (in this order) if -d is used +# - The module that will be deleted from /etc/modules , if -d -M is used +ALL_MODULES="wct4xxp wcte12xp wcte11xp wct1xxp wanpipe tor2 torisa qozap vzaphfc zaphfc ztgsm wctdm24xxp wctdm opvxa1200 wcfxo pciradio wcusb xpp_usb" + +# The name of the variable in /etc/sysconfig/zaptel into which to set +# the list of detected modules. +modules_var=MODULES +# On SuSE with the rpm package: +#modules_var=ZAPTEL_MODULES + +# What signalling to give to ZapBRI channels? +# bri: bri_net; bri_cpe (Bristuffed Asterisk. No multi- support) +# bri_ptmpi: bri_net_ptmp; bri_cpe_ptmp (Bristuffed Asterisk, multi- support) +# pri: pri_net; pri_cpe (Recent Asterisk. Experimental) +#ZAPBRI_SIGNALLING=bri +ZAPBRI_SIGNALLING=bri_ptmp +#ZAPBRI_SIGNALLING=pri +zapconf_def_termtype=te + +# A command to stop / start asterisk. Must support parameters "start" +# and "stop" . This is the executable: +ZAPCONF_ASTERISK_SCRIPT=/etc/init.d/asterisk +# +# Should you need to pass extra arguments: +ZAPCONF_ASTERISK_CMD=$ZAPCONF_ASTERISK_SCRIPT + +# read default configuration from /etc/default/zaptel +if [ -r $ZAPTEL_BOOT_DEBIAN ]; then . $ZAPTEL_BOOT_DEBIAN; fi +if [ -r $ZAPTEL_BOOT_FEDORA ]; then . $ZAPTEL_BOOT_FEDORA; fi + +if [ ! -x "$ZTCFG" ]; then + # Work around a bug in the rpm package: ztcfg should be in + # /sbin as it may be required for starting a network interface + if [ -x /usr/sbin/ztcfg ]; then + ZTCFG=/usr/sbin/ztcfg + else + echo >&2 "ztcfg is not on found, do you have zaptel properly installed?" + exit_cleanup 1 + fi +fi + +XPP_SYNC=auto # sync mode. can be set to '0' or '1' or HOST explicitly. + +# it is safe to use -c twice: the last one will be used. +ztcfg_cmd="$ZTCFG -c $ZAPCONF_FILE" + +# work around a bug (that was already fixed) in the installer: +if [ "$lc_country" = '' ]; then lc_country=us; fi + +force_stop_ast=no +do_detect=no +do_unload=no +do_module_list=no +verbose=no +do_restart=yes +fxsdisable=no +do_gen_zapscan=no + +span_te_timing_counter=1 + +case "$ZAPBRI_SIGNALLING" in +bri) ZAPBRI_NET=bri_net; ZAPBRI_CPE=bri_cpe ;; +pri) ZAPBRI_NET=pri_net; ZAPBRI_CPE=pri_cpe ;; +bri_ptmp) ZAPBRI_NET=bri_net_ptmp; ZAPBRI_CPE=bri_cpe_ptmp ;; +*) + die "Incorrect value for ZAPBRI_SIGNALLING ($ZAPBRI_SIGNALLING). Abortring" + ;; +esac + +die() { + echo "$@" >&2 + exit_cleanup 1 +} + +say() { + if [ "$verbose" = no ]; then + return + fi + echo "$@" >&2 +} + +# exit (exit value is the optional $1), and clean up after us +exit_cleanup() { + if [ -d "$tmp_dir" ]; then + # don't fail but don't hide error if directory is not + # empty + rmdir "$tmp_dir" || : + fi + exit $1 +} + +# Wait for udev to generate /dev/zap/ctl, if needed: +wait_for_zapctl() { + # if device file already exists, or if zaptel has failed to load: + # no point waiting. + if [ -c /dev/zap/ctl ] || ! grep -q zaptel /proc/modules ; then + return + fi + say "Waiting for /dev/zap/ctl to be generated" + devzap_found=0 + for i in `seq $DEVZAP_TIMEOUT`; do + sleep 1 + if [ -c /dev/zap/ctl ]; then + devzap_found=1 + break + fi + done + if [ "$devzap_found" != 1 ]; then + say "Still no /dev/zap/ctl after $devzap_timeout seconds." + echo >&2 "No /dev/zap/ctl: cannot run ztcfg. Aborting." + fi +} + +run_ztcfg() { + # Run ztcfg itself + if [ "$verbose" = no ]; then + $ztcfg_cmd "$@" + else + say "Reconfiguring identified channels" + $ztcfg_cmd -vv "$@" + fi +} + +update_module_list_debian() { + say "Updating Debian modules list $MODLIST_FILE." + del_args=`for i in $ALL_MODULES ztdummy + do + echo "$i" | sed s:.\*:-e\ '/^&/d': + done` + add_args=`for i in $* + do + echo "$i" | sed s:.\*:-e\ '\$a&': + done` + + sed -i.bak $del_args "$MODLIST_FILE" + for i in $* + do + echo "$i" + done >> "$MODLIST_FILE" +} + +update_module_list_fedora() { + say "Updating modules list in zaptel init config $MODLIST_FILE_FEDORA." + sed -i.bak -e "/^$modules_var=/d" "$MODLIST_FILE_FEDORA" + echo "$modules_var=\"$*\"" >> "$MODLIST_FILE_FEDORA" +} + +update_module_list() { + if [ -f "$MODLIST_FILE" ]; then + update_module_list_debian "$@" + elif [ -f "$MODLIST_FILE_FEDORA" ]; then + update_module_list_fedora "$@" + else + die "Can't find a modules list to update. Tried: $MODLIST_FILE, $MODLIST_FILE_FEDORA. Aborting" + fi +} + + + +zap_reg_xpp() { + if [ ! -d /proc/xpp ]; then return; fi + + # Get a list of connected Astribank devices, sorted by the name of + # the USB connector. That order is rather arbitrary, but will not + # change without changes to the cabling. + xbusses=`sed -e '/STATUS=connected/!d' -e 's/ *STATUS=.*//' -e 's/ *CONNECTOR=//' /proc/xpp/xbuses | sort -t: -k 2 | cut -d: -f1` + say "Zaptel registration order:" + say "$xbusses" + + # get a list of XPDs that were not yet registered as zaptel spans. + # this will be the case if you set the parameter zap_autoreg=0 to + # the module xpp + # Append /dev/null to provide a valid file name in case of an empty pattern. + xbusses_pattern=`echo $xbusses| sed -e 's|XBUS-[0-9]*|/proc/xpp/&/XPD-*/zt_registration|g'`' /dev/null' + xpds_to_register=`grep -l 0 $xbusses_pattern` + for file in $xpds_to_register; do + echo 1 >$file + done +} + +# Initialize the Xorcom Astribank (xpp/) +xpp_startup() { + # do nothing if the module xpp was not loaded, or if no + # Astribanks connected: + if [ ! -d /proc/xpp ]; then return 0; fi + if ! grep -q 'STATUS=connected' /proc/xpp/xbuses; then return 0; fi + + echo "Waiting for Astribank devices to initialize:" + cat /proc/xpp/XBUS-[0-9]*/waitfor_xpds 2>/dev/null || true + + # overriding locales for the above two, as perl can be noisy + # when locales are missing. + # No register all the devices if they didn't auto-register: + LC_ALL=C $zt_registration on + + # this one could actually be run after ztcfg: + LC_ALL=C $xpp_sync "$XPP_SYNC" +} + + + +usage() { + program=`basename $0` + + echo >&2 "$program: generate zaptel.conf and zapata.conf" + echo >&2 "(version $VERSION, $rcsid)" + echo >&2 "usage:" + echo >&2 " $program [-sRdv] [-m k|l|g] [-c <country_code>] [-e <base_exten>] [-F]" + echo >&2 " $program [-sRdv] -l" + echo >&2 " $program -su" + echo >&2 " $program -h (this screen)" + echo >&2 "" + echo >&2 "Options:" + echo >&2 " -c CODE: set the country code (default: $lc_country)" + echo >&2 " -e NUM: set the base extension number (default: $base_exten)" + echo >&2 " -F: Don't print FXSs in zapata.conf" + echo >&2 " -l: output a list of detected channels instead of zaptel.conf" + echo >&2 " -d: Perform hardware detection" + echo >&2 " -u: Unload zaptel modules (will not restart Asterisk)." + echo >&2 " -v: verbose" + echo >&2 " -s: Stop Asterisk before running, and start it at the end." + echo >&2 " -R: Don't restart asterisk in the end." + echo >&2 " -z: also generate zapscan.conf for the asterisk GUI." +} + +# print /etc/asterisk/zapscan.conf for the Asterisk-GUI +# $1: port type. Currently only fxs/fxo . Note that this is the type, and +# not the signalling (which would be the fxo fir an fxs port. +# $2: port number. Probably a range of ports is also allowed. +print_zapscan_port () { + if [ "$do_gen_zapscan" != 'yes' ]; then return 0; fi + + echo " +[$2] +port=$1 +" >>$zapscan_file +} + +# $1: channel number +print_pattern() { + local astbank_type='' + local reset_values="" + OPTIND=1 + while getopts 'a:' arg + do + case "$arg" in + a) case "$OPTARG" in input|output) astbank_type=$OPTARG;;esac ;; + esac + done + shift $(( $OPTIND-1 )) + + + local chan=$1 + local sig=$2 #fxs/fxo + local mode=$3 + local method + + if [ "$sig" = 'fxs' ]; then + # Coutries in which we need to use busydetect: + # United Arab Emirats, Israel, Slovenia + case "$lc_country" in + ae|il|si) + method=ls + ;; + *) + method=ks + ;; + esac + else + method="$fxs_default_start" + fi + case "$sig" in + fxs) sig_name=FXO;; + fxo) sig_name=FXS;; + esac + case "$mode" in + list) + echo $chan $sig_name $astbank_type;; + files) + # sadly, both input ports and output ports go into the same span as + # the FXS ports. Thus we need to separate between them. See also + # the zapata.conf section: + + echo ";;; line=\"$line\"" >> $zapata_file + + if [ "$astbank_type" != '' ]; + then echo "# astbanktype: $astbank_type" >>$zaptel_file; + fi + echo "${sig}$method=$chan" >>$zaptel_file + # zap2amp will rewrite those from zaptel.conf and hints there + if [ "$fxsdisable" = 'yes' ] && [ "$sig" = 'fxo' ]; then return; fi + + echo "signalling=${sig}_$method" >>$zapata_file + if [ "$sig" = 'fxo' ] + then + # to preconfigure channel 1's extension to 550, set + # chan_1_exten=550 + # in, e.g, /etc/default/zaptel + var_name=`echo chan_${chan}_exten` + cfg_exten=`echo ${!var_name} | tr -d -c 0-9` + var_name=`echo chan_${chan}_vmbox` + cfg_vmbox=`echo ${!var_name} | tr -d -c 0-9` + var_name=`echo chan_${chan}_cntxt` + cfg_cntxt=`echo ${!var_name} | tr -d -c 0-9` + + if [ "$cfg_exten" = '' ] + then # No extension number set for this channel + exten=$(($chan+$base_exten)) + else # use the pre-configured extension number + exten=$cfg_exten + fi + # is there any real need to set 'mailbox=' ? + if [ "x$cfg_vmbox" = x ] + then # No extension number set for this channel + vmbox=$exten + else # use the pre-configured extension number + vmbox=$cfg_vmbox + fi + echo "callerid=\"Channel $chan\" <$exten>" >> $zapata_file + reset_values="$reset_values callerid" + echo "mailbox=$exten" >> $zapata_file + reset_values="$reset_values mailbox" + if [ "$group_manual" != "yes" ] + then + echo "group=$group_phones" >> $zapata_file + reset_values="$reset_values group" + fi + if [ "$context_manual" != "yes" ] + then + if [ "$astbank_type" != '' ]; + then + context_var_name=context_$astbank_type + echo context=${!context_var_name} >> $zapata_file + else + echo "context=$context_phones" >> $zapata_file + fi + reset_values="$reset_values context" + fi + else # this is an FXO (trunk/phone: FXO signalling) + # we have may have set it. So reset it: + echo "callerid=asreceived" >> $zapata_file + if [ "$group_manual" != "yes" ] + then + echo "group=$group_lines" >> $zapata_file + fi + if [ "$context_manual" != "yes" ] + then + echo "context=$context_lines" >> $zapata_file + reset_values="$reset_values context" + fi + if [ "$lc_country" = 'uk' ] + then + echo "cidsignalling=v23" >> $zapata_file + case $line in + *WCFXO*) echo "cidstart=history" >> $zapata_file;; + *) echo "cidstart=polarity" >> $zapata_file;; + esac + reset_values="$reset_values cidsignalling cidstart" + fi + case "$line" in + *XPP_FXO*) + if [ "$xpp_fxo_rxgain" != '' ]; then + echo "rxgain=$xpp_fxo_rxgain" >> $zapata_file + reset_values="$reset_values rxgain" + fi + ;; + esac + # if kewlstart is not used, busydetect has to be employed: + if [ "$method" = 'ls' ] + then + echo 'busydetect=yes' >> $zapata_file + reset_values="$reset_values busydetect" + fi + fi + + if [ "$astbank_type" = 'input' ] || \ + ( [ "$fxs_immediate" = 'yes' ] && [ "$sig" = "fxo" ] ) + then + echo 'immediate=yes' >> $zapata_file + reset_values="$reset_values immediate" + fi + echo "channel => $chan" >> $zapata_file + reset_zapata_entry $zapata_file $reset_values + echo "" >> $zapata_file + + print_zapscan_port "$sig" "$chan" + ;; + esac + +} + +# the number of channels from /proc/zaptel +# must always print a number as its output. +count_proc_zap_lines() { + # if zaptel is not loaded there are 0 channels: + if [ ! -d /proc/zaptel ]; then echo '0'; return; fi + + ( + for file in `echo /proc/zaptel/* |grep -v '\*'` + do sed -e 1,2d $file # remove the two header lines + done + ) | wc -l # the total number of lines +} + +load_modules() { + say "Test Loading modules:" + for i in $ALL_MODULES + do + lines_before=`count_proc_zap_lines` + args="${i}_args" + eval "args=\$$args" + # a module is worth listing if it: + # a. loaded successfully, and + # b. added channels lines under /proc/zaptel/* + if /sbin/modprobe $i $args 2> /dev/null + then + check=0 + case "$i" in + xpp_usb) check=`grep 'STATUS=connected' 2>/dev/null /proc/xpp/xbuses | wc -l` ;; + *) if [ $lines_before -lt `count_proc_zap_lines` ]; then check=1; fi ;; + esac + if [ "$check" != 0 ] + then + probed_modules="$probed_modules $i" + say " ok $i $args" + else + say " - $i $args" + rmmod $i + fi + else + say " - $i $args" + fi + done +} + +# recursively unload a module and its dependencies, if possible. +# where's modprobe -r when you need it? +# inputs: module to unload. +# returns: the result from +unload_module() { + module="$1" + line=`lsmod 2>/dev/null | grep "^$1 "` + if [ "$line" = '' ]; then return; fi # module was not loaded + + set -- $line + # $1: the original module, $2: size, $3: refcount, $4: deps list + mods=`echo $4 | tr , ' '` + # xpp_usb keeps the xpds below busy, and hence must be removed + # before them: + case "$module" in xpd_*) mods="xpp_usb $mods";; esac + for mod in $mods; do + # run in a subshell, so it won't step over our vars: + (unload_module $mod) + # TODO: the following is probably the error handling we want: + # if [ $? != 0 ]; then return 1; fi + done + rmmod $module +} + +unload_modules() { + say "Unloading zaptel modules:" + unload_module zaptel + say '' +} + +# sleep a while until the xpp modules fully register +wait_for_xpp() { + if [ -d /proc/xpp ] + then + # wait for the XPDs to register: + # TODO: improve error reporting and produce a messagee here + cat /proc/xpp/XBUS-*/waitfor_xpds 2>/dev/null >/dev/null || true + fi +} + +detect() { + unload_modules + temporary_zapconf save + load_modules + temporary_zapconf restore + modlist="$probed_modules" + modlist="$(echo $modlist)" # clean spaces + if [ "$do_module_list" = yes ] + then + update_module_list "$modlist" + fi + if echo $modlist | grep -q xpp_usb; then wait_for_xpp; fi +} + +# The module configuration generated by zaptel includes a totally useless +# automatic run of ztcfg after modules loading. As a workaround for that, +# we provide an empty zaptel.conf temporarily. +# +# At hardware detection time we shouldn't really touch zaptel.conf . So we +# must keep a copy of it somewhere. +# +# I use ZAPCONF_FILE_SYSTEM rather than ZAPCONF_FILE, as the bogus modprobe +# entries will not be initiated by us. +# +# ZAPCONF_FILE_TMP is a "global", as it needs to be preserved between the +# call to 'save' and to 'restore' +ZAPCONF_FILE_TMP= +temporary_zapconf() { + case "$1" in + save) + say "Temporarily moving zaptel.conf aside to work around broken modprobe.conf" + ZAPCONF_FILE_TMP=`mktemp /tmp/genzaptelconf-zaptel.conf-XXXXXX` || die "Error creating temporary zaptel.conf" + if [ -f $ZAPCONF_FILE_SYSTEM ]; then + cp -a $ZAPCONF_FILE_SYSTEM $ZAPCONF_FILE_TMP + fi + echo -n >$ZAPCONF_FILE_SYSTEM + ;; + restore) + # restore original zaptel.conf: + if [ "$ZAPCONF_FILE_TMP" = '' ]; then return; fi + mv $ZAPCONF_FILE_TMP $ZAPCONF_FILE_SYSTEM + ZAPCONF_FILE_TMP='' + ;; + esac +} + +# run after the channel's entry. Used to reset all the values +reset_zapata_entry() { + conf_file="$1"; shift + + for arg in "$@"; do + case "$arg" in + busydetect) echo "$arg=no" >>$conf_file;; + context) echo "$arg=default" >>$conf_file;; + immediate) echo "$arg=no" >>$conf_file;; + overlapdial) echo "$arg=no" >>$conf_file;; + rxgain) echo "$arg=0" >>$conf_file;; + txgain) echo "$arg=0" >>$conf_file;; + *) echo "$arg=" >>$conf_file;; + esac + done +} + + +# we need to preserve the permissions of existing configurations files. +# However we also don't want to be left with incomplete configurations in +# case we are stopped in the middle. Thus we create a temporary file and +# mv it to the original file only when done. +# +# This function gives the temporary file the permissions of the original, +# or some sane defaults. +# +# The temporary file is generated here, and ths its name is passed through +# a variable whose name is passed as a parameter (new_var). +# +# $1: orig_cfg_file +# $2: new_var +gen_tmp_conf() { + orig_cfg_file=$1 + new_var=$2 + + # assign to new_var by reference: + eval $new_var=`mktemp /tmp/genzaptelconf-conf-XXXXXX` \ + || die "Unable to create temporary config file for $orig_cfg_file" + if [ -r "$orig_cfg_file" ]; then + chown --reference="$orig_cfg_file" ${!new_var} 2>/dev/null + chmod --reference="$orig_cfg_file" ${!new_var} 2>/dev/null + else + chmod 644 ${!new_var} + fi +} + +# Extract information from one digital channel (one line in a /proc/zaptel +# file). Information is saved to $tmp_dir/span_foo variables. +# FIXME: detection should move to when we know the number of channels +# and hence can tell between an E1 and a T1. +detect_digital_channel() { + line="$1" + chan_num="$2" + span_num="$3" + + # PRI/BRI channel + # Rather than identifying cards by the header line, we identify + # them by the channel names. This is shorter. + # This also allows us to count the channel numbers and check if + # we have a E1 span, a T1 span or a BRI span. + + # span_lastd is always the one before last + # channel. span_bchan is the last: + echo $chan_num >$tmp_dir/span_end + + if [ "`cat $tmp_dir/span_begin`" != "-1" ] + then + return #we already configured this span. + fi + + # Now we need to give initial configuration to the span + echo $chan_num >$tmp_dir/span_begin + echo $span_num >$tmp_dir/span_num + + case "$line" in + *ZTHFC*/* | *ztqoz*/* | *XPP_BRI_*/*) + # BRI channel + echo 'ccs' >$tmp_dir/span_framing + echo 'euroisdn' >$tmp_dir/span_switchtype + if [ "`cat $tmp_dir/span_termtype`" = 'nt' 2>/dev/null ] + then + echo $ZAPBRI_NET >$tmp_dir/span_signalling + else + echo $ZAPBRI_CPE >$tmp_dir/span_signalling + fi + ;; + *ztgsm*/*) + # Junghanns's GSM cards. + echo 'ccs' >$tmp_dir/span_framing + #Does this mean anything? + echo 'gsm' >$tmp_dir/span_signalling + ;; + *TE[24]/* | *WCT1/* | *Tor2/* | *TorISA/* | *WP[TE]1/* | \ + *R[124]T1/* | *XPP_[TEJ]1_*) + # FIXME: handle cwain around here. + # name: *cwain[12]/* . Always E1. + + # PRI span (E1/T1) + echo 'esf' >$tmp_dir/span_framing + echo 'b8zs' >$tmp_dir/span_coding + echo 'national' >$tmp_dir/span_switchtype + if [ "`cat $tmp_dir/span_termtype`" = 'nt' 2>/dev/null ] + then + echo pri_net >$tmp_dir/span_signalling + else + echo pri_cpe >$tmp_dir/span_signalling + fi + # an example of country-specific setup. This is probably not accurate + # Contributions are welcome + case "$lc_country" in + nl) + # (Just an example for per-country info) + echo 'ccs' >$tmp_dir/span_framing + echo 'ami' >$tmp_dir/span_coding + #echo 'crc4' >$tmp_dir/span_yellow + #echo 'euroisdn' >$tmp_dir/span_switchtype + #echo 'pri_cpe' >$tmp_dir/span_signalling + ;; + il|de|au) + echo 'ccs' >$tmp_dir/span_framing + echo 'hdb3' >$tmp_dir/span_coding + echo 'crc4' >$tmp_dir/span_yellow + echo 'euroisdn' >$tmp_dir/span_switchtype + ;; + cl) + echo 'ccs' >$tmp_dir/span_framing + echo 'hdb3' >$tmp_dir/span_coding + #echo 'crc4' >$tmp_dir/span_yellow + echo 'national' >$tmp_dir/span_switchtype + ;; + esac + ;; + esac +} + +# read information from the $tmp_dir/span_foo files and generate +# configuration for the span and its channels. +write_digital_config() { + # if the current file we checked was not of a digital span, we have + # nothing to do: + if [ "`cat $tmp_dir/span_begin`" = -1 ]; then return; fi + + # read files to variables: + for suffix in num begin end timing lbo framing \ + coding switchtype signalling yellow termtype + do + eval span_$suffix=`cat $tmp_dir/span_$suffix 2>/dev/null` + done + + # exactly the same logic is used in asterisk's chan_zap.c. + # also not that $(( )) is bash-specific + case "$((1+ $span_end - $span_begin))" in + 2|3|24) #ztgsm, BRI or T1 + dchan=$span_end + bchans="$span_begin-$(($span_end-1))" + ;; + 31) #E1 + dchan="$(($span_begin+15))" + bchans="$span_begin-$(($span_begin+14)),$(($span_begin+16))-$span_end" + if [ "$span_framing" = 'esf' ]; then + # don't leave an E1 span with defective defaults: + span_framing=ccs + span_coding=hdb3 + span_switchtype=euroisdn + span_yellow=crc4 + fi + ;; + esac + if [ "$span_yellow" != '' ]; then span_yellow=",$span_yellow"; fi + # Let's assume that a TE span should get the clock from the remote unit, + # and NT spans should provide timing. Just as a sane default. + # If we have several TE spans, the first will have priority 1, + # second: 2, etc. + case "$span_signalling" in *_cpe*) + span_timing=$span_te_timing_counter + span_te_timing_counter=$(($span_te_timing_counter + 1)) + ;; + esac + case "$mode" in + files) + echo span=$span_num,$span_timing,$span_lbo,$span_framing,$span_coding$span_yellow >> $zaptel_file + # leave a comment in zaptel.conf that allows to tell if + # this span is TE or NT: + if [ "$span_termtype" != '' ] + then echo "# termtype: $span_termtype" >>$zaptel_file + fi + + echo bchan=$bchans >>$zaptel_file + echo dchan=$dchan >>$zaptel_file + if [ "$fxsdisable" = 'yes' ] && [ "$span_termtype" = 'nt' ]; then return; fi + # You should not send content to zapata.conf below this line + + span_group=$(($SPAN_GROUP_BASE + $span_num)) + + if [ "$span_termtype" != '' ] + then + # an ISDN card's span that we know if it is in NT mode or TE mode. + # NT is the same as FXS for us and TE is the same as FXO + if [ "$span_termtype" = 'nt' ] + then + echo "callerid=\"Channels $span_begin - $span_end\" <$span_begin>" >> $zapata_file + reset_values="$reset_values callerid" + #echo "mailbox=$exten" + if [ "$brint_overlap" = 'yes' ] + then + echo "overlapdial=yes" >> $zapata_file + reset_values="$reset_values overlapdial" + fi + if [ "$group_manual" != "yes" ] + then + echo "group=$group_phones,$span_group" >> $zapata_file + reset_values="$reset_values group" + fi + if [ "$context_manual" != "yes" ] + then + echo "context=$context_phones" >> $zapata_file + fi + else + #echo "mailbox=" + if [ "$group_manual" != "yes" ] + then + echo "group=$group_lines,$span_group" >> $zapata_file + reset_values="$reset_values group" + fi + if [ "$context_manual" != "yes" ] + then + echo "context=$context_lines" >> $zapata_file + reset_values="$reset_values context" + fi + fi + fi + echo "switchtype = $span_switchtype" >> $zapata_file + echo "signalling = $span_signalling" >> $zapata_file + echo "channel => $bchans" >> $zapata_file + reset_zapata_entry $zapata_file $reset_values + reset_values= + ;; + list) + echo "### BRI/PRI: $span_termtype" + echo "$bchans Data" + echo "$dchan Control" + #echo BRI/PRI: chans: $bchans, control: $dchan + ;; + esac +} + +# This is where the actual detection configuration detection work happens. +genconf() { + local mode=$1 + local reset_values="" + +# spanlist=`echo /proc/zaptel/* | grep -v '\*'` +# spanlist=$(for i in `for i in /proc/zaptel/*; do if [ -f $i ]; then echo $i | cut -f 4 -d / ; fi; done | sort -n`; do echo -n "/proc/zaptel/$i "; done) +# spanlist=(cd /proc/zaptel; ls | sort -n | sed 's|^|/proc/zaptel/|') + spanlist=`ls /proc/zaptel/ 2>/dev/null | sort -n | sed 's|^|/proc/zaptel/|'` + + #if [ "$spanlist" == "" ]; then + # die "No zapata interfaces in /proc/zaptel" + #fi + + + case "$mode" in + files) + if [ "$do_gen_zapscan" = 'yes' ]; then + gen_tmp_conf "$ZAPSCAN_FILE" zapscan_file + cat <<EOF >$zapscan_file +; zapscan.conf: information about detected zaptel channels +; (currently: analog only) +; +; Automatically generated by $0 -- Please do not edit. + +EOF + fi + gen_tmp_conf "$ZAPTEL_FILE" zaptel_file + gen_tmp_conf "$ZAPATA_FILE" zapata_file + cat <<EOF >$zaptel_file +# Autogenerated by $0 -- do not hand edit +# Zaptel Configuration File +# +# This file is parsed by the Zaptel Configurator, ztcfg +# + +# It must be in the module loading order + +EOF + cat <<EOF >$zapata_file +; Autogenerated by $0 -- do not hand edit +; Zaptel Channels Configurations (zapata.conf) +; +; This is not intended to be a complete zapata.conf. Rather, it is intended +; to be #include-d by /etc/zapata.conf that will include the global settings +; +EOF + ;; + esac + + # For each line in the spanlist: see if it represents a channel. + # if it does, test that the channel is usable. + # we do that by configuring it (using ztcfg with a 1-line config file) + # and then trying to read 1 byte from the device file. + # + # The '<(command)' syntax creates a temporary file whose content is is the + # output of 'command'. + # + # Another problem with such an approach is how to include an existing + # configuration file. For instance: how to include some default settings. + # + # Maybe an 'include' directive should be added to zaptel.conf ? + #cat $spanlist | + for procfile in $spanlist + do + span_num=`basename $procfile` + # the first line is the title line. It states the model name + # the second line is empty + title=`head -n 1 $procfile` + # stuff that needs to be remembered accross lines (for PRI/BRI support) + case "$mode" in + list) echo "### $title";; + files) + echo "" >>$zaptel_file + echo "# $title" >>$zaptel_file + echo "" >>$zapata_file + echo "; $title" >>$zapata_file + ;; + esac + echo '-1' >$tmp_dir/span_begin + echo '-1' >$tmp_dir/span_end + echo '0' >$tmp_dir/span_timing + echo '0' >$tmp_dir/span_lbo + echo '' >$tmp_dir/span_framing + echo 'ami' >$tmp_dir/span_coding + echo '' >$tmp_dir/span_switchtype + echo '' >$tmp_dir/span_signalling + if [ "$zapconf_def_termtype" != '' ] + then + echo "$zapconf_def_termtype" >$tmp_dir/span_termtype + fi + + # Check if ZapBRI cards are in TE or NT mode + if echo $title | egrep -q '((quad|octo)BRI PCI ISDN Card.* \[NT\]\ |octoBRI \[NT\] |HFC-S PCI A ISDN.* \[NT\] |Xorcom .* (BRI|T1|E1)_NT)' + then + echo 'nt' >$tmp_dir/span_termtype + elif echo $title | egrep -q '((quad|octo)BRI PCI ISDN Card.* \[TE\]\ |octoBRI \[TE\] |HFC-S PCI A ISDN.* \[TE\] |Xorcom .* (BRI|T1|E1)_TE)' + then + echo 'te' >$tmp_dir/span_termtype + fi + + # The rest of the lines are per-channel lines + sed -e 1,2d $procfile | \ + while read line + do + # in case this is a real channel. + chan_num=`echo $line |awk '{print $1}'` + case "$line" in + *WCTDM/* | *\ WRTDM/* | *OPVXA1200/*) + # TDM400P/2400P and similar cards (Sangoma A200, OpenVox A1200) + # this can be either FXS or FXO + maybe_fxs=0 + maybe_fxo=0 + $ztcfg_cmd -c <(echo fxoks=$chan_num) &>/dev/null && maybe_fxs=1 + $ztcfg_cmd -c <(echo fxsks=$chan_num) &>/dev/null && maybe_fxo=1 + if [ $maybe_fxs = 1 ] && [ $maybe_fxo = 1 ] + then + # An installed module won't accept both FXS and FXO signalling types: + # this is an empty slot. + # TODO: I believe that the Sangoma A20x will reject both and thus + # print nothing here. + echo "# channel $chan_num, WCTDM, no module." >> $zaptel_file + continue + fi + + if [ $maybe_fxs = 1 ]; then print_pattern $chan_num fxo $mode; fi + if [ $maybe_fxo = 1 ]; then print_pattern $chan_num fxs $mode; fi + ;; + *WCFXO/*) + # X100P + print_pattern $chan_num fxs $mode || \ + echo "# channel $chan_num, WCFXO, inactive." >>$zaptel_file + ;; + *WCUSB/*) + print_pattern $chan_num fxo $mode + ;; + *XPP_FXO/*) + # Astribank FXO span + print_pattern $chan_num fxs $mode + ;; + *XPP_FXS/*) + # Astribank FXS span (regular port) + print_pattern $chan_num fxo $mode + ;; + *' FXO'/*) + # FXO module (probably Rhino) + print_pattern $chan_num fxs $mode + ;; + *' FXS'/*) + # FXS module (probably Rhino) + print_pattern $chan_num fxo $mode + ;; + *' ---'/*) + # no module (probably Rhino) + continue + ;; + *XPP_OUT/*) + # Astribank FXS span (output port) + print_pattern -a output $chan_num fxo $mode + ;; + *XPP_IN/*) + # Astribank FXS span (input port) + print_pattern -a input $chan_num fxo $mode + ;; + *ZTHFC*/* | *ztqoz*/* |*ztgsm/* |*TE[24]/* | \ + *WCT1/*|*Tor2/* | *TorISA/* | \ + *XPP_BRI_*/* | *WP[TE]1/* | *R[124]T1/* | \ + *XPP_[TE]1*/* ) + detect_digital_channel "$line" "$chan_num" "$span_num" + ;; + '') ;; # Empty line (after span header) + *) + case "$mode" in + list) echo "# ??: $line";; + files) + echo "# ??: $line" >>$zaptel_file + echo "; ??: $line" >>$zapata_file + esac + ;; + esac + done + # end of part in sub-process. + + write_digital_config + done + + if [ "$mode" = 'files' ] + then + cat <<EOF >> ${zaptel_file} + +# Global data + +loadzone = $loadzone +defaultzone = $defaultzone +EOF + fi + + if [ "$mode" = 'files' ]; then + mv ${ZAPCONF_FILE} ${ZAPCONF_FILE}.bak 2>/dev/null + mv $zaptel_file ${ZAPCONF_FILE} + mv ${ZAPATA_FILE} ${ZAPATA_FILE}.bak 2>/dev/nullk + mv $zapata_file ${ZAPATA_FILE} + if [ "$do_gen_zapscan" = 'yes' ]; then + mv $ZAPSCAN_FILE $ZAPSCAN_FILE.bak 2>/dev/null + mv $zapscan_file $ZAPSCAN_FILE + fi + + zapata_file_name=`basename $ZAPATA_FILE` + if ! grep -q "^#include.*$zapata_file_name" \ + /etc/asterisk/zapata.conf + then + say "Note: generated $ZAPATA_FILE not included in zapata.conf" + say "To fix: echo '#include $zapata_file_name' >>/etc/asterisk/zapata.conf" + fi + fi +} + +while getopts 'c:de:Fhlm:MRsuvz' arg +do + case "$arg" in + e) # guarantee that it is a number: + new_base_exten=`echo $OPTARG | tr -d -c 0-9` + if [ "x$new_base_exten" != x ]; then base_exten=$new_base_exten; fi + ;; + c) lc_country=`echo $OPTARG | tr -d -c a-z` ;; + d) do_detect=yes ;; + F) fxsdisable=yes;; + u) do_unload=yes ; force_stop_ast=yes ;; + v) verbose=yes ;; + l) mode='list' ;; + M) do_module_list=yes; do_detect=yes ;; + s) force_stop_ast=yes ;; + R) do_restart=no ;; + z) do_gen_zapscan=yes ;; + h) usage; exit 0;; + *) echo >&2 "unknown parameter -$arg, Aborting"; usage; exit 1;; + esac +done +shift $(( $OPTIND-1 )) +if [ $# != 0 ]; then + echo >&2 "$0: too many parameters" + usage + exit 1 +fi + +tmp_dir=`mktemp -d /tmp/genzaptelconf-dir-XXXXXX` || \ + die "$0: failed to create temporary directory. Aborting" + + +case "$lc_country" in + # the list was generated from the source of zaptel: + #grep '{.*[0-9]\+,.*"[a-z][a-z]"' zonedata.c | cut -d'"' -f 2 | xargs |tr ' ' '|' + us|au|fr|nl|uk|fi|es|jp|no|at|nz|it|gr|tw|cl|se|be|sg|il|br|hu|lt|pl|za|pt|ee|mx|in|de|ch|dk|cz|cn):;; + *) + lc_country=us + echo >&2 "unknown country-code $lc_country, defaulting to \"us\"" + ;; +esac +# any reason for loadzone and defaultzone to be different? If so, this is +# the place to make that difference +loadzone=$lc_country +defaultzone=$loadzone + +# make sure asterisk is not in our way +if [ "$force_stop_ast" = 'yes' ] +then + $ZAPCONF_ASTERISK_CMD stop 1>&2 +else + # if asterisk is running and we wanted to detect modules + # or simply to unload modules, asterisk needs to go away. + if ( [ "$do_unload" = yes ] || [ "$do_detect" = yes ] ) && \ + pidof asterisk >/dev/null + then + echo >&2 "Asterisk is already running. Configuration left untouched" + echo >&2 "You can use the option -s to shut down Asterisk for the" + echo >&2 "duration of the detection." + exit_cleanup 1 + fi +fi + +if [ "$do_unload" = yes ] +then + unload_modules + exit_cleanup $? +fi + +if [ "$do_detect" = yes ] +then + detect +fi + +if [ "$zapconf_use_perl" = yes ]; then + #redefine genconf to use perl utilities: + genconf() { + case "$1" in + list) zaptel_hardware ;; + files) zapconf ;; + esac + } +fi + +if [ "$mode" = list ]; then + genconf list +else + #zap_reg_xpp + xpp_startup + wait_for_zapctl + say "Generating '${ZAPCONF_FILE} and ${ZAPATA_FILE}'" + genconf files + run_ztcfg +fi + +if [ "$tmp_dir" != '' ] +then + rm -rf "$tmp_dir" +fi + +if [ "$force_stop_ast" != 'yes' ] || [ "$do_restart" != 'yes' ] +then + exit_cleanup 0 +fi + +if [ -x "$ZAPCONF_ASTERISK_SCRIPT" ] +then + $ZAPCONF_ASTERISK_CMD start 1>&2 +fi + +# if in verbose mode: verify that asterisk is running +if [ "$verbose" != 'no' ] + then + say "Checking channels configured in Asterisk:" + sleep 1 # give it some time. This is enough on our simple test server + if [ -x ast-cmd ] + then + ast-cmd cmd "zap show channels" + else + asterisk -rx "zap show channels" + fi +fi + +# vim:ts=8: |