#! /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 # # 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 # # 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 # 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 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 ;; *) echo >&2 "Incorrect value for ZAPBRI_SIGNALLING ($ZAPBRI_SIGNALLING). Abortring" exit 1 ;; esac die() { echo "$@" >&2 exit 1 } say() { if [ "$verbose" = no ]; then return fi echo "$@" >&2 } # 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 ] [-e ] [-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() { if pids="$(pgrep asterisk)" [ "$pids" != '' ] then die "Before unloading -- STOP asterisk (pids=$pids)." fi 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/*) # 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 if [ "$span_yellow" != '' ]; then span_yellow=",$span_yellow"; fi # 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 fi ;; esac # 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 <$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 <$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 <$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 '1' >$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_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_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 ;; *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/*|*XPP_BRI*) 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 <> ${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 ;; 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 /etc/init.d/asterisk 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 1 fi fi if [ "$do_unload" = yes ] then unload_modules exit 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 0 fi if [ -x /etc/init.d/asterisk ] then /etc/init.d/asterisk 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: