#!/bin/sh # Sip / IAX extensions # Add to internal extensions add_extension() { logdebug 1 "Adding $1/$2 extension to $3" eval "local ext=\"\${dialplan_ext_$3}\"" [ -z "${ext}" ] && append dialplan_exts "$3" " " local lower=`echo $1|tr [A-Z] [a-z]` eval "local ext=\"\${${lower}_last_extension}\"" [ -z "${ext}" ] && eval "${lower}_last_extension=\"$3\"" append dialplan_ext_$3 $1/${2} "&" } check_append_local() { local extension="${1}" logdebug 3 "added local context for ${1}" eval "local isadded=\"\${dialplan_add_local_${extension}-0}\"" if [ "$isadded" != "1" ] ; then logdebug 3 "Not added before - adding" eval "dialplan_add_local_${extension}=1" append dialplan_locals "$extension" eval "dialplan_local_${1}_context=\"${2}\"" eval "dialplan_local_${1}_selfmailbox=\"${3}\"" eval "dialplan_local_${1}_mailbox=\"${4}\"" eval "dialplan_local_${1}_displayname=\"${5}\"" return 0 else return 1 fi } append_dialplan_locals(){ for i in ${dialplan_locals} ; do local extension=$i for x in context selfmailbox mailbox displayname ; do eval "x_${x}=\${dialplan_local_${i}_${x}}" done local newcontext=local_${extension} if check_add_context ${newcontext} ; then # add_dialplan_voice ${newcontext} ${x_last_extension} ${x_last_mailbox} # Make sure as much is matched as possible #add_dialplan_goto ${newcontext} _[0-9#*+]. ${x_last_context} # add_dialplan_include ${newcontext} ${x_last_context} append_dialplan_context ${newcontext} "exten => ${match_all},1,Set(CALLERID(num)=${extension})" local next=2 if [ ! -z "${x_displayname}" ] ; then append_dialplan_context ${newcontext} "exten => ${match_all},2,Set(CALLERID(name)=${x_displayname})" local next=3 fi if [ ! -z "${x_mailbox}" ] ; then [ "${x_selfmailbox}" = "yes" ] && append_dialplan_context ${newcontext} "exten => ${extension},${next},VoiceMailMain(${x_mailbox})" [ ! -z "${dialplan_voiceboxext}" ] && append_dialplan_context ${newcontext} "exten => ${dialplan_voiceboxext},${next},VoiceMailMain(${x_mailbox})" fi append_dialplan_context ${newcontext} "exten => ${match_all},${next},Goto(${x_context},\${EXTEN},1)" fi done } # Sip check_add_sipitems() { if [ "${sip_doregister}" == "1" ] ; then local line="register => ${sip_last_username}@${sip_last_fromdomain}:${sip_last_secret}:${sip_last_username}@${sip_sectionname}" case ${sip_last_registerextension} in -) line="$line/${sip_last_username}" ;; .*) line="$line/${sip_last_registerextension}" ;; esac append sip_register "$line" "$N" sip_doregister=0 fi do_check_add_items sip } check_add_iaxitems() { do_check_add_items iax } do_check_add_items(){ for i in type last_host last_context selfmailbox last_extension last_mailbox last_displayname ; do eval "x_${i}=\"\${${1}_${i}-}\"" done if [ ! -z "${x_last_context}" ] ; then if [ ! -z "${x_last_extension}" ] ; then [ "${x_last_context}" = "-" ] && eval "x_last_context=\"\${${1}_opt_context}\"" check_append_local "${x_last_extension}" "${x_last_context}" "${x_selfmailbox}" "${x_last_mailbox}" "${x_last_displayname}" x_last_context=local_${x_last_extension} fi if [ "${x_last_context}" != "-" ] ; then append ${1}_sections "context=${x_last_context}" "$N" fi if [ "${x_type}" != "user" -a -z "${x_last_host}" ] ; then append ${1}_sections "host=dynamic" "$N" fi fi for i in last_username last_fromdomain last_secret last_username \ sectionname last_fromuser last_context last_extension last_mailbox \ last_type last_host last_displayname ; do eval unset $1_$i done eval ${1}_selfmailbox=no eval ${1}_last_registerextension=- } reload_sip() { astcmd "sip reload" return 1 # reboot } unload_sip() astcmd "unload chan_sip.so" rtp_option_list="rtpstart rtpend rtpdtmftimeout rtcpinterval rtpchecksums" # Validate RTP options valid_rtp_option() { is_in_list $1 ${rtp_option_list} } # Validate sip options, depending on context. valid_sipiax_option() { local use_glob=1 local use_glob_iax=1 local use_glob_sip=1 local use_user=1 local use_peer=1 local use_user_sip=1 local use_user_iax=1 local use_peer_sip=1 local use_peer_iax=1 case "$1" in globalsip) use_glob_sip=0 use_glob=0 ;; usersip) use_glob_sip=0 use_glob=0 use_user=0 ;; peersip|friendsip) use_glob_sip=0 use_glob=0 use_user=0 use_peer=0 use_user_sip=0 use_peer_sip=0 ;; globaliax) use_glob_iax=0 use_glob=0 ;; useriax) use_glob_iax=0 use_glob=0 use_user=0 ;; peeriax|friendiax) use_glob_iax=0 use_glob=0 use_user=0 use_peer=0 use_user_iax=0 use_peer_iax=0 ;; esac case "$2" in writeprotect|static) return ${use_glob_iax} ;; # Integer port|\ maxexpirey|\ rtptimeout|\ rtpholdtimeout|\ defaultexpirey|\ registertimeout|\ registerattempts|\ call-limit) return ${use_glob_sip} ;; # ip addr bindaddr|\ externip) return ${use_glob_sip} ;; # net/mask localnet) return ${use_glob_sip} ;; permit|\ deny) return ${use_user_sip} ;; # Domain name realm|\ domain) return ${use_glob_sip} ;; # valid context context) return ${use_glob} ;; # Mime type notifymimetype) return ${use_glob_sip} ;; # Yes/No canreinvite) return ${use_glob} ;; nat|allowoverlap|allowsubscribe|allowtransfer|\ videosupport) return ${use_glob_sip} ;; pedantic|\ trustrpid|\ promiscredir|\ useclientcode) return ${use_user_sip} ;; # Enums dtmfmode) return ${use_glob_sip} ;; type) return ${use_user} ;; insecure|callingpres|\ progressinband) return ${use_user_sip} ;; # List allow|\ disallow) return ${use_glob_sip} ;; # Register string register) return ${use_glob_sip} ;; # String username|secret|md5secret|host|\ mailbox) return ${use_user} ;; auth) return ${use_user_iax} ;; callgroup|pickupgroup|language|accountcode|\ setvar|callerid|amaflags|subscribecontext|\ maxcallbitrate|rfc2833compensate|\ mailbox) return ${use_user_sip};; template|fromdomain|regexten|fromuser|\ qualify|defaultip|sendrpid|\ outboundproxy) return ${use_peer_sip};; extension) return 0;; *) return 1;; esac } ast_add_conf sip init_sipconf() { ast_add_reload sip ast_enable_type sipgeneral ast_enable_type sip ast_enable_type target sip_opt_port=5060 sip_opt_bindaddr=0.0.0.0 sip_opt_context=default sip_opt_maxexpirey=3600 sip_opt_defaultexpirey=3600 sip_opt_notifymimetype=text/plain sip_opt_rtptimeout=60 sip_opt_rtpholdtimeout=300 config_get WAN_IP wan ipaddr # TODO check why the above does not work all the time if [ -z "${WAN_IP}" ] ; then config_get WAN_IF wan ifname WAN_IP=$(ifconfig ${WAN_IF} | grep "inet addr:" | sed 's/^.*inet addr:\([^ ]*\) .*$/\1/') fi sip_opt_externip=${WAN_IP} sip_opt_realm=asterisk config_get LAN_MASK lan netmask config_get LAN_IP lan ipaddr local LAN_NET=$(/bin/ipcalc.sh $LAN_IP $LAN_MASK | grep NETWORK | cut -d= -f2) sip_opt_localnet_def=$LAN_NET/$LAN_MASK sip_opt_localip=${LAN_IP} # default to ulaw only sip_opt_allow= sip_opt_registertimeout=20 sip_opt_registerattempts=10 sip_opt_canreinvite=no sip_sections= } sip_list="port bindaddr context maxexpirey defaultexpirey notifymimetype \ rtptimeout rtpholdtimeout realm externip" create_sipconf() { append_dialplan_locals file=${DEST_DIR}/sip.conf get_checksum sip_conf $file local isempty=1 if [ -z "${sip_sections}" ] ; then rm -f $file isempty=2 else [ -z "${sip_opt_domain}" ] && sip_opt_domain="domain=${sip_opt_realm}" echo "${asteriskuci_gen}[general]" > $file echo "${sip_opt_domain}" >> "$file" echo "domain=${sip_opt_localip}" >> "$file" for i in ${sip_list} ; do eval value=\$sip_opt_$i [ ! -z "$value" ] && ( echo "$i=$value" >> $file ) done [ -z "${sip_opt_localnet}" ] && sip_opt_localnet="localnet=${sip_opt_localnet_def}" echo "${sip_opt_localnet}" >> "${file}" echo "disallow=all" >> $file local rhs="${sip_opt_allow}" [ -z "$rhs" ] && rhs=ulaw while [ ! -z "$rhs" ] ; do cur=${rhs%%,*} nvar=${rhs#*,} enable_format ${cur} echo "allow=${cur}" >> $file [ "$nvar" == "$rhs" ] && break rhs=${nvar} done echo "${N}${sip_register}${N}${N}${sip_sections}" >> $file unset sip_register unset sip_sections fi check_checksum "$sip_conf" "$file" || ast_sip_restart=$isempty } handle_sipgeneral() { option_cb(){ if [ "${1%_LENGTH}" = "${1}" ] ; then local opt=${1%_ITEM*} logdebug 4 "SipGeneral option ${opt} $2" if valid_sipiax_option globalsip ${opt} "$2" ; then case "${opt}" in host) sip_opt_host="$2" [ -z "${sip_opt_host}" ] && sip_opt_host=dynamic ;; allow) append sip_opt_allow "$2" "," ;; domain) split_append sip_opt_domain domain= "$2" "${N}" ;; localnet) split_append sip_opt_localnet localnet= "$2" "${N}" ;; *) eval "sip_opt_$1=\"\$2\"" ;; esac elif valid_rtp_option $1 "$2" ; then eval "rtp_opt_$1=\"\$2\"" else logerror "Invalid SIP global option: $1" fi fi } } handle_sip() { check_add sipitems append sip_sections [$1] "$N$N" enable_module chan_sip sip_sectionname=${1#sip_} sip_type=peer sip_doregister=0 sip_last_context=- sip_last_doregister=- sip_selfmailbox=no option_cb() { logdebug 3 "SIP/${sip_sectionname}: '$1' '$2'" case $1 in type) sip_type=$2 append sip_sections "$1=$2" "$N" ;; register) [ "$2" == "yes" ] && sip_doregister=1 ;; registerextension|displayname) eval sip_last_$1="$2";; allow|allow_ITEM*) split_append sip_sections allow= "$2" "${N}" enable_format ;; extension|extension_ITEM*) add_extension SIP ${sip_sectionname} "$2" ;; context) sip_last_context="$2" ;; selfmailbox) sip_selfmailbox="$2" ;; incoming|incoming_ITEM*) add_incoming SIP ${sip_sectionname} "$2" ;; timeout|prefix|internationalprefix|alwaysinternational|countrycode) eval "target_$1_SIP_${sectionname}=\"$2\"" ;; *_LENGTH) ;; *) eval sip_last_$1="$2" local opt=${1%_ITEM*} if valid_sipiax_option ${sip_type}sip ${opt} $2 ; then append sip_sections "${opt}=$2" "$N" else logerror "Invalid SIP option for ${sip_type}: ${opt}" fi esac } } # rtp.conf ast_add_conf rtp init_rtpconf() { ast_add_reload rtp rtp_opt_rtpstart=5000 rtp_opt_rtpend=31000 rtp_opt_rtpchecksums= rtp_opt_rtpdtmftimeout= rtp_opt_rtcpinterval=5000 } create_rtpconf() { file=${DEST_DIR}/rtp.conf get_checksum rtp_conf $file local isempty=1 if module_enabled chan_sip ; then echo "${asteriskuci_gen}[general]" > $file for i in $rtp_option_list ; do eval "local val=\"\$rtp_opt_$i\"" if [ ! -z "$val" ] ; then lhs=$i case "$i" in rtpdtmftimeout) lhs=dtmftimeout esac echo "$lhs=$val" >> $file fi done else rm -f $file isempty=2 fi check_checksum "$rtp_conf" "$file" || ast_rtp_restart=$isempty } reload_rtp() astcmd "rtp reload" unload_rtp() astcmd "unload rtp" # Iax ast_add_conf iax init_iaxconf() { ast_add_reload iax ast_enable_type iaxgeneral ast_enable_type iax return 0 } create_iaxconf() { local file=$DEST_DIR/iax.conf get_checksum iax_conf $file local isempty=1 if [ -z "${iax_sections}" ] ; then rm -f $file isempty=2 else echo "${asteriskuci_gen}${iax_general}$N$N${iax_sections}" > $file fi check_checksum "$iax_conf" "$file" || ast_iax_restart=${isempty} } handle_iaxgeneral() { iax_general="[general]" option_cb() { case $1 in allow_LENGTH) ;; allow|allow_ITEM*) split_append iax_general allow= "$2" "${N}" enable_format ;; *) if valid_sipiax_option globaliax $1 $2 ; then eval "iax_opt_$1=\"$2\"" append iax_general "$1=$2" "$N" else logerror "Invalid IAX global option: $1" fi ;; esac } } handle_iax() { check_add iaxitems iax_type=peer iax_sectionname="${1#iax_}" append iax_sections "[${iax_sectionname}]" "$N$N" iax_last_context=- iax_selfmailbox=no enable_module chan_iax2 option_cb() { case $1 in type) iax_type=$2 append iax_sections "type=$2" "$N" ;; allow_LENGTH|incoming_LENGTH) ;; allow|allow_ITEM*) split_append iax_sections allow= "$2" "${N}" enable_format ;; extension_LENGTH) ;; extension|extension_ITEM*) add_extension IAX ${iax_sectionname} "$2" ;; displayname) eval iax_last_$1="$2";; context) eval iax_last_context="$2" ;; selfmailbox) eval iax_selfmailbox="$2" ;; incoming|incoming_ITEM*) add_incoming IAX ${iax_sectionname} "$2" ;; timeout|prefix|internationalprefix|alwaysinternational|countrycode) eval "target_$1_IAX_${sectionname}=\"$2\"" ;; *) eval iax_last_$1="$2" if valid_sipiax_option ${iax_type}iax $1 $2 ; then append iax_sections "$1=$2" "$N" else logerror "Invalid IAX option for ${iax_type}: $1" fi esac } } reload_iax() { astcmd "iax2 reload" return 1 } unload_iax() astcmd "unload chan_iax2.so" handle_target() { # Target name if split_targettype targettype targetname "${1}" ; then logdebug 4 "Handle target ${targettype}/${targetname} - ${1}" handle_dialtarget "${targettype}" "${targetname}" else logerror "No target type specified for target $1" fi } # Set up options sip/iax targets for outgoing sip/iax handle_dialtarget() { # Dialzone target option dt_areatype="$1" dt_areaname="$2" logdebug 1 "Dialzone Target for ${dt_areatype}/${dt_areaname}" option_cb(){ logdebug 3 "Option $1='$2' for dialzone target" case $1 in timeout|prefix|internationalprefix|alwaysinternational|countrycode) eval "target_$1_${dt_areatype}_${dt_areaname}=\"$2\"" ;; *) logerror "Invalid target for ${dt_areatype}/${dt_areaname}: ${1}" esac } } # vim: ts=2 sw=2 noet foldmethod=indent