diff --git a/.gitignore b/.gitignore index 0a14fb5228..188ea88d55 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,28 @@ .deps .\#* \#* +Debug/ +Release/ +All/ +bin/ +*.user +*.suo +*.ncb +*.pdb +*.map +*.lib +*.obj +*.idb +*.res +*.exp +*.exe +*.manifest +*.dep +*.dll +BuildLog.htm +Path +w32/Library/lastversion +w32/Library/tmpVersion.Bat .version AUTHORS COPYING @@ -17,6 +39,7 @@ Makefile.in NEWS README aclocal.m4 +autom4te.cache build/Makefile build/Makefile.in build/config/compile @@ -29,9 +52,11 @@ build/freeswitch.pc build/getlib.sh build/getsounds.sh build/modmake.rules +config.cache config.log config.status configure +configure.lineno freeswitch fs_cli fs_ivrd diff --git a/Makefile.am b/Makefile.am index afb5673877..a9e4921344 100644 --- a/Makefile.am +++ b/Makefile.am @@ -349,7 +349,21 @@ src/include/switch_version.h: src/include/switch_version.h.in .version $(libfree cat src/include/switch_version.h.in > src/include/switch_version.h ; \ touch .version ; \ else \ - version=`svnversion . -n || echo hacked` ; \ + if [ -d .git ] ; then \ + version=`git log --format="%h %ci" -1 HEAD | head -1 || echo hacked` ; \ + if [ "x$$version" == "xhacked" ] ; then \ + version="hacked-`date -u +%Y%m%dT%H%M%SZ`" ; \ + else \ + version="git-$$version" ; \ + fi ;\ + else \ + version=`svnversion . -n || echo hacked` ; \ + if [ "x$$version" == "xhacked" ] ; then \ + version="hacked-`date -u +%Y%m%dT%H%M%SZ`" ; \ + else \ + version="svn-$$version" ; \ + fi ;\ + fi ; \ oldversion=`cat .version 2>/dev/null || echo "0"` ; \ if test "$$oldversion" != "$$version" || test $$force = 1 ; then \ cat src/include/switch_version.h.in | sed "s/@SWITCH_VERSION_REVISION@/$$version/g" > src/include/switch_version.h ; \ @@ -437,23 +451,30 @@ install-data-local: test -d $(DESTDIR)$(sysconfdir) || $(MAKE) samples-conf test -d $(DESTDIR)$(htdocsdir) || $(MAKE) samples-htdocs -is-svn: - @if [ ! -d .svn ] ; then \ +is-scm: + @if [ ! -d .svn -a ! -d .git ] ; then \ echo ; echo ; \ - echo "**************************************************************************************************" ; \ - echo "You can not update a release tarball or without a svn working copy, please checkout fresh from svn" ; \ - echo "**************************************************************************************************" ; \ + echo "*****************************************************************************************************" ; \ + echo "You can not update a release tarball or without a git or svn working copy please clone our git tree: " ; \ + echo "git clone git://git.freeswitch.org/freeswitch.git " ; \ + echo "or check out our read only svn mirror: " ; \ + echo "svn checkout http://svn.freeswitch.org/svn/freeswitch/trunk " ; \ + echo "*****************************************************************************************************" ; \ echo ; echo ; \ exit 1; \ fi -update: is-svn +update: is-scm @if test -d .svn ; then \ test ! -f .version || rm -f .version ; \ echo Updating... ; \ svn update ; \ + elif test -d .git ; then \ + test ! -f .version || rm -f .version ; \ + echo "Pulling updates..." ; \ + git pull ; \ else \ - echo "This source directory is not an svn working copy" ; \ + echo "This source directory is not a git tree or svn working copy" ; \ fi .nodepends: @@ -483,18 +504,18 @@ core_install: install_core everything: install -up: is-svn clean - svn update +up: is-scm clean + $(MAKE) update $(MAKE) -j core $(MAKE) -j modules $(MAKE) install -sync: is-svn - svn update +sync: is-scm + $(MAKE) update $(MAKE) install -speedy-sync: is-svn - svn update +speedy-sync: is-scm + $(MAKE) update $(MAKE) -j install libs/openzap/Makefile: @@ -570,15 +591,15 @@ cluecon: @echo @echo http://www.cluecon.com @sleep 5 -current: cluecon is-svn update-clean - svn update +current: cluecon update-clean is-scm + $(MAKE) update $(MAKE) all $(MAKE) install installall: current -speedy-current: is-svn update-clean - svn update +speedy-current: update-clean is-scm + $(MAKE) update $(MAKE) speedy-sure $(MAKE) install diff --git a/build/swigall.sh b/build/swigall.sh index ee7abf19cd..0525faf073 100755 --- a/build/swigall.sh +++ b/build/swigall.sh @@ -1,6 +1,6 @@ cd src/mod/languages/mod_lua make swigclean -make mod_lua_wrap.cpp +make lua_wrap cd ../../../.. cd src/mod/languages/mod_perl diff --git a/configure.in b/configure.in index de262a86db..16ba3e6999 100644 --- a/configure.in +++ b/configure.in @@ -3,11 +3,11 @@ # Must change all of the below together # For a release, set revision for that tagged release as well and uncomment -AC_INIT([freeswitch], [1.0.trunk], BUG-REPORT-ADDRESS) +AC_INIT([freeswitch], [1.0.head], BUG-REPORT-ADDRESS) AC_SUBST(SWITCH_VERSION_MAJOR, [1]) AC_SUBST(SWITCH_VERSION_MINOR, [0]) -AC_SUBST(SWITCH_VERSION_MICRO, [trunk]) -#AC_SUBST(SWITCH_VERSION_REVISION, [svn-revision-here]) +AC_SUBST(SWITCH_VERSION_MICRO, [head]) +#AC_SUBST(SWITCH_VERSION_REVISION, []) AC_CONFIG_FILES([src/include/switch_version.h.in:src/include/switch_version.h.template]) AC_CONFIG_FILES([.version:.version.in]) diff --git a/libs/.gitignore b/libs/.gitignore index 5cce65bcdb..838f103194 100644 --- a/libs/.gitignore +++ b/libs/.gitignore @@ -189,6 +189,9 @@ ilbc/src/ilbc.h ilbc/src/stamp-h1 ilbc/tests/Makefile ilbc/tests/Makefile.in +js/nsprpub/lib/ds/libplds4.so.1 +js/nsprpub/lib/libc/src/libplc4.so.1 +js/nsprpub/pr/src/libnspr4.so.1 js/Makefile js/aclocal.m4 js/config.guess @@ -990,3 +993,74 @@ unimrcp/build/acmacros/ltoptions.m4 unimrcp/build/acmacros/ltsugar.m4 unimrcp/build/acmacros/ltversion.m4 unimrcp/build/acmacros/lt~obsolete.m4 +*.tar.gz +celt-0.7.1/ +flite-1.3.99/ +freeradius-client-1.1.6/ +iksemel/test/tst-dom +iksemel/test/tst-filter +iksemel/test/tst-iks +iksemel/test/tst-ikstack +iksemel/test/tst-jid +iksemel/test/tst-md5 +iksemel/test/tst-sax +iksemel/test/tst-sha +iksemel/tools/ikslint +iksemel/tools/iksperf +iksemel/tools/iksroster +json-c-0.9/ +lame-3.97/ +libmemcached-0.32/ +libshout-2.2.2/ +mpg123/ +openldap-2.4.19/ +pocketsphinx-0.5.99/ +portaudio/bin-stamp +portaudio/bin/ +portaudio/lib-stamp +silk/Decoder +silk/Encoder +silk/signalCompare +soundtouch-1.3.1/ +sphinxbase-0.4.99/ +unimrcp/platforms/asr-client/asrclient +unimrcp/platforms/umc/umc +unimrcp/platforms/unimrcp-client/unimrcpclient +unimrcp/platforms/unimrcp-server/unimrcpserver +yaml/config.h +yaml/stamp-h1 +yaml/tests/example-deconstructor +yaml/tests/example-deconstructor-alt +yaml/tests/example-reformatter +yaml/tests/example-reformatter-alt +yaml/tests/run-dumper +yaml/tests/run-emitter +yaml/tests/run-loader +yaml/tests/run-parser +yaml/tests/run-scanner +Communicator_semi_40.cd_semi_6000/ +libogg-1.1.3/ +pthreads-w32-2-7-0-release/ +sounds/ +sphinxbase-0.4.99/ +sofia-sip/libsofia-sip-ua/http/http_tag_dll.c +sofia-sip/libsofia-sip-ua/iptsec/auth_tag_dll.c +sofia-sip/libsofia-sip-ua/msg/msg_tag_dll.c +sofia-sip/libsofia-sip-ua/msg/msg_tag_ref.c +sofia-sip/libsofia-sip-ua/nea/nea_tag_dll.c +sofia-sip/libsofia-sip-ua/nta/nta_tag_dll.c +sofia-sip/libsofia-sip-ua/nth/nth_tag_dll.c +sofia-sip/libsofia-sip-ua/nua/nua_tag_dll.c +sofia-sip/libsofia-sip-ua/sdp/sdp_tag_dll.c +sofia-sip/libsofia-sip-ua/sip/sip_tag_dll.c +sofia-sip/libsofia-sip-ua/soa/soa_tag_dll.c +sofia-sip/libsofia-sip-ua/stun/stun_tag_dll.c +sofia-sip/libsofia-sip-ua/su/su_tag_dll.c +sofia-sip/libsofia-sip-ua/tport/tport_tag_dll.c +sofia-sip/libsofia-sip-ua/url/url_tag_dll.c +win32/pcre/pcre_chartables.c +apr-util/include/apu_config.h +apr-util/include/apu_select_dbm.h +include/ +js/nsprpub/pr/include/prcpucfg.h +apr-util/xml/expat/lib/config.h diff --git a/libs/apr-util/test/data/.empty b/libs/apr-util/test/data/.empty new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/esl/java/classes/.empty b/libs/esl/java/classes/.empty new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/freetdm/Makefile.am b/libs/freetdm/Makefile.am index 5f829b6614..a90da6659e 100644 --- a/libs/freetdm/Makefile.am +++ b/libs/freetdm/Makefile.am @@ -105,7 +105,7 @@ core-install: install-libLTLIBRARIES # # tools & test programs # -noinst_PROGRAMS = testtones detect_tones detect_dtmf testisdn testpri testr2 testanalog testapp testcid +noinst_PROGRAMS = testtones detect_tones detect_dtmf testpri testr2 testanalog testapp testcid #testisdn if HAVE_SCTP noinst_PROGRAMS += testboost endif @@ -131,9 +131,9 @@ detect_dtmf_SOURCES = $(SRC)/detect_dtmf.c detect_dtmf_LDADD = libfreetdm.la detect_dtmf_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS) -testisdn_SOURCES = $(SRC)/testisdn.c -testisdn_LDADD = libfreetdm.la -testisdn_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS) +#testisdn_SOURCES = $(SRC)/testisdn.c +#testisdn_LDADD = libfreetdm.la +#testisdn_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS) testpri_SOURCES = $(SRC)/testpri.c testpri_LDADD = libfreetdm.la @@ -160,7 +160,7 @@ testanalog_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS) # # ftmod modules # -mod_LTLIBRARIES = ftmod_zt.la ftmod_skel.la ftmod_isdn.la ftmod_analog.la ftmod_analog_em.la +mod_LTLIBRARIES = ftmod_zt.la ftmod_skel.la ftmod_analog.la ftmod_analog_em.la #ftmod_isdn.la if HAVE_SCTP @@ -196,32 +196,32 @@ ftmod_wanpipe_la_LDFLAGS = -module -avoid-version -lsangoma ftmod_wanpipe_la_LIBADD = $(MYLIB) endif -ftmod_isdn_la_SOURCES = \ -$(SRC)/isdn/EuroISDNStateNT.c \ -$(SRC)/isdn/EuroISDNStateTE.c \ -$(SRC)/isdn/mfifo.c \ -$(SRC)/isdn/Q921.c \ -$(SRC)/isdn/Q931api.c \ -$(SRC)/isdn/Q931.c \ -$(SRC)/isdn/Q931ie.c \ -$(SRC)/isdn/Q931mes.c \ -$(SRC)/isdn/Q931StateNT.c \ -$(SRC)/isdn/Q931StateTE.c \ -$(SRC)/isdn/nationalmes.c \ -$(SRC)/isdn/nationalStateNT.c \ -$(SRC)/isdn/nationalStateTE.c \ -$(SRC)/isdn/DMSmes.c \ -$(SRC)/isdn/DMSStateNT.c \ -$(SRC)/isdn/DMSStateTE.c \ -$(SRC)/isdn/5ESSmes.c \ -$(SRC)/isdn/5ESSStateNT.c \ -$(SRC)/isdn/5ESSStateTE.c \ -$(SRC)/isdn/Q932mes.c \ -$(SRC)/ftmod/ftmod_isdn/ftmod_isdn.c +#ftmod_isdn_la_SOURCES = \ +#$(SRC)/isdn/EuroISDNStateNT.c \ +#$(SRC)/isdn/EuroISDNStateTE.c \ +#$(SRC)/isdn/mfifo.c \ +#$(SRC)/isdn/Q921.c \ +#$(SRC)/isdn/Q931api.c \ +#$(SRC)/isdn/Q931.c \ +#$(SRC)/isdn/Q931ie.c \ +#$(SRC)/isdn/Q931mes.c \ +#$(SRC)/isdn/Q931StateNT.c \ +#$(SRC)/isdn/Q931StateTE.c \ +#$(SRC)/isdn/nationalmes.c \ +#$(SRC)/isdn/nationalStateNT.c \ +#$(SRC)/isdn/nationalStateTE.c \ +#$(SRC)/isdn/DMSmes.c \ +#$(SRC)/isdn/DMSStateNT.c \ +#$(SRC)/isdn/DMSStateTE.c \ +#$(SRC)/isdn/5ESSmes.c \ +#$(SRC)/isdn/5ESSStateNT.c \ +#$(SRC)/isdn/5ESSStateTE.c \ +#$(SRC)/isdn/Q932mes.c \ +#$(SRC)/ftmod/ftmod_isdn/ftmod_isdn.c -ftmod_isdn_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS) -D_GNU_SOURCE -ftmod_isdn_la_LDFLAGS = $(PCAP_LIB_FLAGS) -module -avoid-version -ftmod_isdn_la_LIBADD = $(MYLIB) +#ftmod_isdn_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS) -D_GNU_SOURCE +#ftmod_isdn_la_LDFLAGS = $(PCAP_LIB_FLAGS) -module -avoid-version +#ftmod_isdn_la_LIBADD = $(MYLIB) ftmod_analog_la_SOURCES = $(SRC)/ftmod/ftmod_analog/ftmod_analog.c ftmod_analog_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS) diff --git a/libs/js/nsprpub/include/.empty b/libs/js/nsprpub/include/.empty new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/js/nsprpub/macbuild/.empty b/libs/js/nsprpub/macbuild/.empty new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/js/nsprpub/pkg/solaris/SUNWnspr/.empty b/libs/js/nsprpub/pkg/solaris/SUNWnspr/.empty new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/js/nsprpub/pkg/solaris/SUNWnsprx/.empty b/libs/js/nsprpub/pkg/solaris/SUNWnsprx/.empty new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/js/nsprpub/pkg/solaris/SUNWpr-devl/.empty b/libs/js/nsprpub/pkg/solaris/SUNWpr-devl/.empty new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/js/nsprpub/pkg/solaris/SUNWprdx/.empty b/libs/js/nsprpub/pkg/solaris/SUNWprdx/.empty new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/js/nsprpub/pkg/solaris/SUNWprx-devl/.empty b/libs/js/nsprpub/pkg/solaris/SUNWprx-devl/.empty new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/js/nsprpub/pkg/solaris/SUNWprx/.empty b/libs/js/nsprpub/pkg/solaris/SUNWprx/.empty new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/js/nsprpub/pr/src/cthreads/.empty b/libs/js/nsprpub/pr/src/cthreads/.empty new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/js/nsprpub/pr/tests/macbuild/.empty b/libs/js/nsprpub/pr/tests/macbuild/.empty new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/portaudio/doc/html/.empty b/libs/portaudio/doc/html/.empty new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/sofia-sip/configure.ac b/libs/sofia-sip/configure.ac index fcedf33260..0eb2418ad9 100644 --- a/libs/sofia-sip/configure.ac +++ b/libs/sofia-sip/configure.ac @@ -100,13 +100,16 @@ if test "x${ax_cv_c_compiler_vendor}" = "xsun" ; then fi fi +SOFIA_PLAT_CFLAGS= # openbsd seems to not define NULL as a void pointer, I blame standards by committee for this. # This is a dirty hack, but shuts up all the warnings case "$host" in - *-openbsd*) SOFIA_CFLAGS="$SOFIA_CFLAGS -DNULL='(void *) 0L'";; + *-openbsd*) SOFIA_PLAT_CFLAGS="-DNULL='(void *) 0L'";; *) ;; esac +AC_SUBST(SOFIA_PLAT_CFLAGS, $SOFIA_PLAT_CFLAGS) + ### checks for header files ### ----------------------- diff --git a/libs/sofia-sip/libsofia-sip-ua/sofia.am b/libs/sofia-sip/libsofia-sip-ua/sofia.am index b5e5ec88f2..a7d8c346d6 100644 --- a/libs/sofia-sip/libsofia-sip-ua/sofia.am +++ b/libs/sofia-sip/libsofia-sip-ua/sofia.am @@ -1,7 +1,7 @@ # common Makefile targets for libsofia-sip-ua modules # --------------------------------------------------- -AM_CFLAGS = $(CWFLAG) $(SOFIA_CFLAGS) $(SOFIA_COVERAGE) +AM_CFLAGS = $(CWFLAG) $(SOFIA_CFLAGS) $(SOFIA_COVERAGE) $(SOFIA_PLAT_CFLAGS) # Use with --enable-ndebug if NDEBUG diff --git a/libs/sofia-sip/rules/sofia.am b/libs/sofia-sip/rules/sofia.am index 3d3b88f50f..a312e1355f 100644 --- a/libs/sofia-sip/rules/sofia.am +++ b/libs/sofia-sip/rules/sofia.am @@ -4,7 +4,7 @@ sofiasrcdir = ${top_srcdir}/libsofia-sip-ua sofiabuilddir = ${top_builddir}/libsofia-sip-ua -AM_CFLAGS = $(CWFLAG) $(SOFIA_COVERAGE) $(SOFIA_CFLAGS) $(openssl_CFLAGS) +AM_CFLAGS = $(CWFLAG) $(SOFIA_COVERAGE) $(SOFIA_CFLAGS) $(openssl_CFLAGS) $(SOFIA_PLAT_CFLAGS) SOFIA_COVERAGE = $(COVERAGE_FLAGS) diff --git a/libs/sqlite/art/tmp/.empty b/libs/sqlite/art/tmp/.empty new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/sqlite/notes/.empty b/libs/sqlite/notes/.empty new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/sqlite/src/ex/.empty b/libs/sqlite/src/ex/.empty new file mode 100644 index 0000000000..e69de29bb2 diff --git a/scripts/tagscript.sh b/scripts/tagscript.sh index 9ba4826dbc..44797b3640 100755 --- a/scripts/tagscript.sh +++ b/scripts/tagscript.sh @@ -35,11 +35,12 @@ fi sed -e "s|\(AC_SUBST(SWITCH_VERSION_MAJOR, \[\).*\(\])\)|\1$major\2|" \ -e "s|\(AC_SUBST(SWITCH_VERSION_MINOR, \[\).*\(\])\)|\1$minor\2|" \ -e "s|\(AC_SUBST(SWITCH_VERSION_MICRO, \[\).*\(\])\)|\1$micro\2|" \ - -e "s|\(AC_SUBST(SWITCH_VERSION_REVISION, \[\).*\(\])\)|\1$rev\2|" \ + -e "s|\(AC_INIT(\[freeswitch\], \[\).*\(\], BUG-REPORT-ADDRESS)\)|\1$major.$minor.$micro\2|" \ -i configure.in if [ -n "$rev" ]; then - sed -e "s|#\(AC_SUBST(SWITCH_VERSION_REVISION\)|\1|" \ + sed -e "s|\(AC_SUBST(SWITCH_VERSION_REVISION, \[\).*\(\])\)|\1$rev\2|" \ + -e "s|#\(AC_SUBST(SWITCH_VERSION_REVISION\)|\1|" \ -i configure.in fi @@ -61,16 +62,17 @@ rm -f docs/COPYING rm -f docs/ChangeLog rm -rf .git cd .. -tar -czvf $dst_name.tar.gz $dst_dir -tar -cjvf $dst_name.tar.bz2 $dst_dir -tar -cJvf $dst_name.tar.xz $dst_dir -rm -rf $dst_dir +tar -cvf $dst_name.tar $dst_dir +gzip -9 -c $dst_name.tar > $dst_name.tar.gz || echo "gzip not available" +bzip2 -z -k $dst_name.tar || echo "bzip2 not available" +xz -z -9 -k $dst_name.tar || echo "xz / xz-utils not available" +rm -rf $dst_name.tar $dst_dir cat 1>&2 < * - * mod_cidlookup.c -- API for querying cid->name services + * mod_cidlookup.c -- API for querying cid->name services and local data * */ diff --git a/src/mod/applications/mod_enum/Makefile.am b/src/mod/applications/mod_enum/Makefile.am index 65199901d0..c512f7691d 100644 --- a/src/mod/applications/mod_enum/Makefile.am +++ b/src/mod/applications/mod_enum/Makefile.am @@ -2,13 +2,12 @@ include $(top_srcdir)/build/modmake.rulesam MODNAME=mod_enum UDNS_DIR=$(switch_srcdir)/libs/udns -AM_CFLAGS += -I$(UDNS_DIR) -DHAVE_POLL +mod_enum_la_CFLAGS = -I$(UDNS_DIR) -DHAVE_POLL $(AM_CFLAGS) mod_LTLIBRARIES = mod_enum.la mod_enum_la_SOURCES = mod_enum.c mod_enum_la_SOURCES += $(UDNS_DIR)/udns_dn.c $(UDNS_DIR)/udns_dntosp.c $(UDNS_DIR)/udns_parse.c $(UDNS_DIR)/udns_misc.c mod_enum_la_SOURCES += $(UDNS_DIR)/udns_rr_a.c $(UDNS_DIR)/udns_rr_ptr.c $(UDNS_DIR)/udns_rr_mx.c $(UDNS_DIR)/udns_rr_txt.c $(UDNS_DIR)/udns_bl.c mod_enum_la_SOURCES += $(UDNS_DIR)/udns_rr_srv.c $(UDNS_DIR)/udns_rr_naptr.c $(UDNS_DIR)/udns_codes.c $(UDNS_DIR)/udns_resolver.c -mod_enum_la_CFLAGS = $(AM_CFLAGS) mod_enum_la_LIBADD = $(switch_builddir)/libfreeswitch.la mod_enum_la_LDFLAGS = -avoid-version -module -no-undefined -shared diff --git a/src/mod/endpoints/mod_portaudio/Makefile.am b/src/mod/endpoints/mod_portaudio/Makefile.am index 56f82daf79..88d8754868 100644 --- a/src/mod/endpoints/mod_portaudio/Makefile.am +++ b/src/mod/endpoints/mod_portaudio/Makefile.am @@ -6,8 +6,7 @@ PALA=$(switch_builddir)/libs/portaudio/lib/libportaudio.la mod_LTLIBRARIES = mod_portaudio.la mod_portaudio_la_SOURCES = mod_portaudio.c pablio.c pa_ringbuffer.c -mod_portaudio_la_CFLAGS = $(AM_CFLAGS) -mod_portaudio_la_CFLAGS += -I. -I$(PA_DIR)/include -D__EXTENSION__=1 +mod_portaudio_la_CFLAGS = -I. -I$(PA_DIR)/include -D__EXTENSION__=1 $(AM_CFLAGS) mod_portaudio_la_LIBADD = $(switch_builddir)/libfreeswitch.la $(PALA) mod_portaudio_la_LDFLAGS = -avoid-version -module -no-undefined -shared $(PA_LIBS) diff --git a/src/mod/endpoints/mod_skinny/Makefile.am b/src/mod/endpoints/mod_skinny/Makefile.am index 212aa924ac..1ac0cd30c2 100644 --- a/src/mod/endpoints/mod_skinny/Makefile.am +++ b/src/mod/endpoints/mod_skinny/Makefile.am @@ -3,7 +3,7 @@ include $(top_srcdir)/build/modmake.rulesam MODNAME=mod_skinny mod_LTLIBRARIES = mod_skinny.la -mod_skinny_la_SOURCES = mod_skinny.c skinny_protocol.c skinny_tables.c -mod_skinny_la_CFLAGS = $(AM_CFLAGS) -DSKINNY_SVN_VERSION=\"`cat $(switch_builddir)/.version`\" +mod_skinny_la_SOURCES = mod_skinny.c skinny_protocol.c skinny_tables.c skinny_api.c +mod_skinny_la_CFLAGS = $(AM_CFLAGS) mod_skinny_la_LIBADD = $(switch_builddir)/libfreeswitch.la mod_skinny_la_LDFLAGS = -avoid-version -module -no-undefined -shared diff --git a/src/mod/endpoints/mod_skinny/Net/Skinny/Message.pm b/src/mod/endpoints/mod_skinny/Net/Skinny/Message.pm index e69a80f4ba..6a1a0ef1cf 100644 --- a/src/mod/endpoints/mod_skinny/Net/Skinny/Message.pm +++ b/src/mod/endpoints/mod_skinny/Net/Skinny/Message.pm @@ -49,7 +49,9 @@ sub send { $parsed_count++; } if($parsed_count != scalar(keys %{$self->{'data'}})) { - printf "Incomplete message: %d out of %d\n", $parsed_count, scalar(keys %{$self->{'data'}}); + printf "Incomplete message (type=%s (%X)) %d out of %d\n", Net::Skinny::Protocol::skinny_message_type2str($self->{'type'}), $self->{'type'}, + $parsed_count, scalar(keys %{$self->{'data'}}); + print Dumper(@$struct); return; } $self->{'socket'}->send_data($self->{'type'}, $raw); diff --git a/src/mod/endpoints/mod_skinny/mod_skinny.c b/src/mod/endpoints/mod_skinny/mod_skinny.c index 3107138b73..571223ccac 100644 --- a/src/mod/endpoints/mod_skinny/mod_skinny.c +++ b/src/mod/endpoints/mod_skinny/mod_skinny.c @@ -33,15 +33,14 @@ #include "mod_skinny.h" #include "skinny_protocol.h" #include "skinny_tables.h" +#include "skinny_api.h" SWITCH_MODULE_LOAD_FUNCTION(mod_skinny_load); SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_skinny_shutdown); -SWITCH_MODULE_RUNTIME_FUNCTION(mod_skinny_runtime); -SWITCH_MODULE_DEFINITION(mod_skinny, mod_skinny_load, mod_skinny_shutdown, mod_skinny_runtime); +SWITCH_MODULE_DEFINITION(mod_skinny, mod_skinny_load, mod_skinny_shutdown, NULL); switch_endpoint_interface_t *skinny_endpoint_interface; -static switch_memory_pool_t *module_pool = NULL; skinny_globals_t globals; @@ -65,6 +64,7 @@ static char lines_sql[] = " device_name VARCHAR(16),\n" " device_instance INTEGER,\n" " position INTEGER,\n" + " line_instance INTEGER,\n" " label VARCHAR(40),\n" " value VARCHAR(24),\n" " caller_name VARCHAR(44),\n" @@ -88,10 +88,20 @@ static char buttons_sql[] = " settings VARCHAR(44)\n" ");\n"; +static char active_lines_sql[] = + "CREATE TABLE skinny_active_lines (\n" + " device_name VARCHAR(16),\n" + " device_instance INTEGER,\n" + " line_instance INTEGER,\n" + " channel_uuid VARCHAR(256),\n" + " call_id INTEGER,\n" + " call_state INTEGER\n" + ");\n"; + /*****************************************************************************/ /* PROFILES FUNCTIONS */ /*****************************************************************************/ -static switch_status_t dump_profile(const skinny_profile_t *profile, switch_stream_handle_t *stream) +switch_status_t skinny_profile_dump(const skinny_profile_t *profile, switch_stream_handle_t *stream) { const char *line = "================================================================================================="; switch_assert(profile); @@ -120,12 +130,16 @@ static switch_status_t dump_profile(const skinny_profile_t *profile, switch_stre } -static skinny_profile_t *skinny_find_profile(const char *profile_name) +skinny_profile_t *skinny_find_profile(const char *profile_name) { - return (skinny_profile_t *) switch_core_hash_find(globals.profile_hash, profile_name); + skinny_profile_t *profile; + switch_mutex_lock(globals.mutex); + profile = (skinny_profile_t *) switch_core_hash_find(globals.profile_hash, profile_name); + switch_mutex_unlock(globals.mutex); + return profile; } -static switch_status_t skinny_profile_find_listener_by_device_name(skinny_profile_t *profile, const char *device_name, listener_t **listener) +switch_status_t skinny_profile_find_listener_by_device_name(skinny_profile_t *profile, const char *device_name, listener_t **listener) { switch_mutex_lock(profile->listener_mutex); for (listener_t *l = profile->listeners; l; l = l->next) { @@ -138,48 +152,105 @@ static switch_status_t skinny_profile_find_listener_by_device_name(skinny_profil return SWITCH_STATUS_SUCCESS; } -struct skinny_profile_find_listener_helper { +switch_status_t skinny_profile_find_listener_by_device_name_and_instance(skinny_profile_t *profile, const char *device_name, uint32_t device_instance, listener_t **listener) +{ + switch_mutex_lock(profile->listener_mutex); + for (listener_t *l = profile->listeners; l; l = l->next) { + if (!strcmp(l->device_name, device_name) && (l->device_instance == device_instance)) { + *listener = l; + } + } + switch_mutex_unlock(profile->listener_mutex); + + return SWITCH_STATUS_SUCCESS; +} + +struct skinny_profile_find_session_uuid_helper { skinny_profile_t *profile; - listener_t *listener; - uint32_t line; + char *channel_uuid; + uint32_t line_instance; }; -static int skinny_profile_find_listener_callback(void *pArg, int argc, char **argv, char **columnNames) +int skinny_profile_find_session_uuid_callback(void *pArg, int argc, char **argv, char **columnNames) { - struct skinny_profile_find_listener_helper *helper = pArg; - skinny_profile_t *profile = helper->profile; - char *device_name = argv[0]; - /* uint32_t position = atoi(argv[1]); */ - uint32_t relative_position = atoi(argv[2]); + struct skinny_profile_find_session_uuid_helper *helper = pArg; - skinny_profile_find_listener_by_device_name(profile, device_name, &helper->listener); + char *channel_uuid = argv[0]; + uint32_t line_instance = atoi(argv[1]); - if(helper->listener) { - helper->line = relative_position; + if(helper->channel_uuid == NULL) { + helper->channel_uuid = switch_mprintf("%s", channel_uuid); + helper->line_instance = line_instance; } + return 0; } -static switch_status_t skinny_profile_find_listener_by_dest(skinny_profile_t *profile, const char *dest, listener_t **l, uint32_t *line) +char * skinny_profile_find_session_uuid(skinny_profile_t *profile, listener_t *listener, uint32_t *line_instance_p, uint32_t call_id) { + struct skinny_profile_find_session_uuid_helper helper = {0}; char *sql; - struct skinny_profile_find_listener_helper helper = {0}; + char *device_condition = NULL; + char *line_instance_condition = NULL; + char *call_id_condition = NULL; + + switch_assert(profile); helper.profile = profile; - - if ((sql = switch_mprintf("SELECT device_name, position, " - "(SELECT count(*) from skinny_lines sl2 " - "WHERE sl2.device_name= sl1.device_name AND sl2.device_instance= sl1.device_instance AND sl2.position <= sl1.position) AS relative_position " - "FROM skinny_lines sl1 WHERE value='%s'", - dest))) { - skinny_execute_sql_callback(profile, profile->listener_mutex, sql, skinny_profile_find_listener_callback, &helper); + helper.channel_uuid = NULL; + + if(listener) { + device_condition = switch_mprintf("device_name='%s' AND device_instance=%d", + listener->device_name, listener->device_instance); + } else { + device_condition = switch_mprintf("1=1"); + } + switch_assert(device_condition); + if(*line_instance_p > 0) { + line_instance_condition = switch_mprintf("line_instance=%d", *line_instance_p); + } else { + line_instance_condition = switch_mprintf("1=1"); + } + switch_assert(line_instance_condition); + if(call_id > 0) { + call_id_condition = switch_mprintf("call_id=%d", call_id); + } else { + call_id_condition = switch_mprintf("1=1"); + } + switch_assert(call_id_condition); + if((sql = switch_mprintf( + "SELECT channel_uuid, line_instance " + "FROM skinny_active_lines " + "WHERE %s AND %s AND %s " + "ORDER BY channel_uuid DESC", + device_condition, line_instance_condition, call_id_condition + ))) { + skinny_execute_sql_callback(profile, profile->sql_mutex, sql, + skinny_profile_find_session_uuid_callback, &helper); switch_safe_free(sql); } + switch_safe_free(device_condition); + switch_safe_free(line_instance_condition); + switch_safe_free(call_id_condition); + *line_instance_p = helper.line_instance; + return helper.channel_uuid; +} +switch_core_session_t * skinny_profile_find_session(skinny_profile_t *profile, listener_t *listener, uint32_t *line_instance_p, uint32_t call_id) +{ + char *uuid; + switch_core_session_t *result = NULL; + uuid = skinny_profile_find_session_uuid(profile, listener, line_instance_p, call_id); - *line = helper.line; - *l = helper.listener; - - return SWITCH_STATUS_SUCCESS; + if(!zstr(uuid)) { + result = switch_core_session_locate(uuid); + if(!result) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, + "Unable to find session %s on %s:%d, line %d\n", + uuid, listener->device_name, listener->device_instance, *line_instance_p); + } + switch_safe_free(uuid); + } + return result; } /*****************************************************************************/ @@ -262,28 +333,73 @@ switch_bool_t skinny_execute_sql_callback(skinny_profile_t *profile, /*****************************************************************************/ /* CHANNEL FUNCTIONS */ /*****************************************************************************/ -uint32_t skinny_line_perform_set_state(listener_t *listener, const char *file, const char *func, int line, uint32_t instance, uint32_t state, uint32_t call_id) +void skinny_line_perform_set_state(const char *file, const char *func, int line, listener_t *listener, uint32_t line_instance, uint32_t call_id, uint32_t call_state) { + switch_event_t *event = NULL; switch_assert(listener); - + + skinny_device_event(listener, &event, SWITCH_EVENT_CUSTOM, SKINNY_EVENT_CALL_STATE); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-Line-Instance", "%d", line_instance); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-Call-Id", "%d", call_id); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-Call-State", "%d", call_state); + switch_event_fire(&event); switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_DEBUG, - "Device %s, line %d State Change %s (%d) -> %s (%d) (no session)\n", - listener->device_name, instance, - skinny_soft_key_set2str(listener->line_state[instance]), listener->line_state[instance], - skinny_soft_key_set2str(state), state); - - send_select_soft_keys(listener, instance, call_id, state, 0xffff); - listener->line_state[instance] = state; - - return listener->line_state[instance]; + "Device %s:%d, Line %d, Call %d Change State to %s (%d)\n", + listener->device_name, listener->device_instance, line_instance, call_id, + skinny_call_state2str(call_state), call_state); } -uint32_t skinny_line_get_state(listener_t *listener, uint32_t instance) + +struct skinny_line_get_state_helper { + uint32_t call_state; +}; + +int skinny_line_get_state_callback(void *pArg, int argc, char **argv, char **columnNames) { + struct skinny_line_get_state_helper *helper = pArg; + helper->call_state = atoi(argv[0]); + return 0; +} + +uint32_t skinny_line_get_state(listener_t *listener, uint32_t line_instance, uint32_t call_id) +{ + char *line_instance_condition; + char *call_id_condition; + char *sql; + struct skinny_line_get_state_helper helper = {0}; + switch_assert(listener); - return listener->line_state[instance]; + if(line_instance > 0) { + line_instance_condition = switch_mprintf("line_instance=%d", line_instance); + } else { + line_instance_condition = switch_mprintf("1=1"); + } + switch_assert(line_instance_condition); + if(call_id > 0) { + call_id_condition = switch_mprintf("call_id=%d", call_id); + } else { + call_id_condition = switch_mprintf("1=1"); + } + switch_assert(call_id_condition); + + if ((sql = switch_mprintf( + "SELECT call_state FROM skinny_active_lines " + "WHERE device_name='%s' AND device_instance=%d " + "AND %s AND %s", + listener->device_name, listener->device_instance, + line_instance_condition, call_id_condition + ))) { + skinny_execute_sql_callback(listener->profile, listener->profile->sql_mutex, sql, skinny_line_get_state_callback, &helper); + switch_safe_free(sql); + } + switch_safe_free(line_instance_condition); + switch_safe_free(call_id_condition); + + return helper.call_state; } + + switch_status_t skinny_tech_set_codec(private_t *tech_pvt, int force) { int ms; @@ -302,11 +418,11 @@ switch_status_t skinny_tech_set_codec(private_t *tech_pvt, int force) if (strcasecmp(tech_pvt->read_impl.iananame, tech_pvt->iananame) || tech_pvt->read_impl.samples_per_second != tech_pvt->rm_rate || tech_pvt->codec_ms != (uint32_t)tech_pvt->read_impl.microseconds_per_packet / 1000) { - + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Changing Codec from %s@%dms to %s@%dms\n", tech_pvt->read_impl.iananame, tech_pvt->read_impl.microseconds_per_packet / 1000, tech_pvt->rm_encoding, tech_pvt->codec_ms); - + switch_core_session_lock_codec_write(tech_pvt->session); switch_core_session_lock_codec_read(tech_pvt->session); resetting = 1; @@ -317,7 +433,7 @@ switch_status_t skinny_tech_set_codec(private_t *tech_pvt, int force) switch_goto_status(SWITCH_STATUS_SUCCESS, end); } } - + if (switch_core_codec_init(&tech_pvt->read_codec, tech_pvt->iananame, tech_pvt->rm_fmtp, @@ -358,9 +474,7 @@ switch_status_t skinny_tech_set_codec(private_t *tech_pvt, int force) tech_pvt->read_impl.microseconds_per_packet, tech_pvt->read_impl.samples_per_packet ) != SWITCH_STATUS_SUCCESS) { - switch_channel_t *channel = NULL; - channel = switch_core_session_get_channel(tech_pvt->session); - assert(channel != NULL); + switch_channel_t *channel = switch_core_session_get_channel(tech_pvt->session); switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); switch_goto_status(SWITCH_STATUS_FALSE, end); @@ -407,28 +521,19 @@ switch_status_t skinny_tech_set_codec(private_t *tech_pvt, int force) return status; } -void tech_init(private_t *tech_pvt, switch_core_session_t *session, listener_t *listener, uint32_t line) +void tech_init(private_t *tech_pvt, skinny_profile_t *profile, switch_core_session_t *session) { - struct line_stat_res_message *button = NULL; - switch_assert(tech_pvt); switch_assert(session); - switch_assert(listener); - + tech_pvt->read_frame.data = tech_pvt->databuf; tech_pvt->read_frame.buflen = sizeof(tech_pvt->databuf); switch_mutex_init(&tech_pvt->mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session)); switch_mutex_init(&tech_pvt->flag_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session)); - tech_pvt->call_id = listener->profile->next_call_id++; - tech_pvt->listener = listener; - tech_pvt->line = line; + tech_pvt->call_id = ++profile->next_call_id; + tech_pvt->profile = profile; switch_core_session_set_private(session, tech_pvt); tech_pvt->session = session; - - skinny_line_get(listener, line, &button); - tech_pvt->line_name = switch_core_strdup(listener->pool, button->name); - tech_pvt->line_shortname = switch_core_strdup(listener->pool, button->shortname); - tech_pvt->line_displayname = switch_core_strdup(listener->pool, button->displayname); } /* @@ -438,14 +543,9 @@ void tech_init(private_t *tech_pvt, switch_core_session_t *session, listener_t * */ switch_status_t channel_on_init(switch_core_session_t *session) { - switch_channel_t *channel; - private_t *tech_pvt = NULL; + switch_channel_t *channel = switch_core_session_get_channel(session); + private_t *tech_pvt = switch_core_session_get_private(session); - tech_pvt = switch_core_session_get_private(session); - assert(tech_pvt != NULL); - - channel = switch_core_session_get_channel(session); - assert(channel != NULL); switch_set_flag_locked(tech_pvt, TFLAG_IO); /* Move channel's state machine to ROUTING. This means the call is trying @@ -453,9 +553,6 @@ switch_status_t channel_on_init(switch_core_session_t *session) where a destination has been identified. If the channel is simply left in the initial state, nothing will happen. */ switch_channel_set_state(channel, CS_ROUTING); - switch_mutex_lock(globals.calls_mutex); - globals.calls++; - switch_mutex_unlock(globals.calls_mutex); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s CHANNEL INIT\n", switch_channel_get_name(channel)); @@ -464,14 +561,7 @@ switch_status_t channel_on_init(switch_core_session_t *session) switch_status_t channel_on_routing(switch_core_session_t *session) { - switch_channel_t *channel = NULL; - private_t *tech_pvt = NULL; - - channel = switch_core_session_get_channel(session); - assert(channel != NULL); - - tech_pvt = switch_core_session_get_private(session); - assert(tech_pvt != NULL); + switch_channel_t *channel = switch_core_session_get_channel(session); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s CHANNEL ROUTING\n", switch_channel_get_name(channel)); @@ -480,15 +570,7 @@ switch_status_t channel_on_routing(switch_core_session_t *session) switch_status_t channel_on_execute(switch_core_session_t *session) { - - switch_channel_t *channel = NULL; - private_t *tech_pvt = NULL; - - channel = switch_core_session_get_channel(session); - assert(channel != NULL); - - tech_pvt = switch_core_session_get_private(session); - assert(tech_pvt != NULL); + switch_channel_t *channel = switch_core_session_get_channel(session); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s CHANNEL EXECUTE\n", switch_channel_get_name(channel)); @@ -498,19 +580,14 @@ switch_status_t channel_on_execute(switch_core_session_t *session) switch_status_t channel_on_destroy(switch_core_session_t *session) { - switch_channel_t *channel = NULL; - private_t *tech_pvt = NULL; - - channel = switch_core_session_get_channel(session); - assert(channel != NULL); - - tech_pvt = switch_core_session_get_private(session); + switch_channel_t *channel = switch_core_session_get_channel(session); + private_t *tech_pvt = switch_core_session_get_private(session); if (tech_pvt) { if (switch_core_codec_ready(&tech_pvt->read_codec)) { switch_core_codec_destroy(&tech_pvt->read_codec); } - + if (switch_core_codec_ready(&tech_pvt->write_codec)) { switch_core_codec_destroy(&tech_pvt->write_codec); } @@ -521,73 +598,92 @@ switch_status_t channel_on_destroy(switch_core_session_t *session) return SWITCH_STATUS_SUCCESS; } +struct channel_on_hangup_helper { + private_t *tech_pvt; +}; + +int channel_on_hangup_callback(void *pArg, int argc, char **argv, char **columnNames) +{ + struct channel_on_hangup_helper *helper = pArg; + listener_t *listener = NULL; + + char *device_name = argv[0]; + uint32_t device_instance = atoi(argv[1]); + /* uint32_t position = atoi(argv[2]); */ + uint32_t line_instance = atoi(argv[3]); + /* char *label = argv[4]; */ + /* char *value = argv[5]; */ + /* char *caller_name = argv[6]; */ + /* uint32_t ring_on_idle = atoi(argv[7]); */ + /* uint32_t ring_on_active = atoi(argv[8]); */ + /* uint32_t busy_trigger = atoi(argv[9]); */ + /* char *forward_all = argv[10]; */ + /* char *forward_busy = argv[11]; */ + /* char *forward_noanswer = argv[12]; */ + /* uint32_t noanswer_duration = atoi(argv[13]); */ + /* char *channel_uuid = argv[14]; */ + uint32_t call_id = atoi(argv[15]); + uint32_t call_state = atoi(argv[16]); + + skinny_profile_find_listener_by_device_name_and_instance(helper->tech_pvt->profile, device_name, device_instance, &listener); + if(listener) { + if(call_state == SKINNY_CONNECTED) { + send_stop_tone(listener, line_instance, call_id); + } + send_set_lamp(listener, SKINNY_BUTTON_LINE, line_instance, SKINNY_LAMP_OFF); + send_clear_prompt_status(listener, line_instance, call_id); + if(call_state == SKINNY_CONNECTED) { /* calling parties */ + send_close_receive_channel(listener, + call_id, /* uint32_t conference_id, */ + helper->tech_pvt->party_id, /* uint32_t pass_thru_party_id, */ + call_id /* uint32_t conference_id2, */ + ); + send_stop_media_transmission(listener, + call_id, /* uint32_t conference_id, */ + helper->tech_pvt->party_id, /* uint32_t pass_thru_party_id, */ + call_id /* uint32_t conference_id2, */ + ); + } + + skinny_line_set_state(listener, line_instance, call_id, SKINNY_ON_HOOK); + send_select_soft_keys(listener, line_instance, call_id, SKINNY_KEY_SET_ON_HOOK, 0xffff); + /* TODO: DefineTimeDate */ + send_set_speaker_mode(listener, SKINNY_SPEAKER_OFF); + send_set_ringer(listener, SKINNY_RING_OFF, SKINNY_RING_FOREVER, 0, call_id); + + } + return 0; +} switch_status_t channel_on_hangup(switch_core_session_t *session) { - switch_channel_t *channel = NULL; - private_t *tech_pvt = NULL; - listener_t *listener = NULL; + struct channel_on_hangup_helper helper = {0}; + switch_channel_t *channel = switch_core_session_get_channel(session); + private_t *tech_pvt = switch_core_session_get_private(session); + char *sql; - channel = switch_core_session_get_channel(session); - assert(channel != NULL); - - tech_pvt = switch_core_session_get_private(session); - assert(tech_pvt != NULL); - - listener = tech_pvt->listener; - assert(listener != NULL); - switch_clear_flag_locked(tech_pvt, TFLAG_IO); switch_clear_flag_locked(tech_pvt, TFLAG_VOICE); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s CHANNEL HANGUP\n", switch_channel_get_name(channel)); - listener->session[tech_pvt->line] = NULL; + helper.tech_pvt= tech_pvt; - stop_tone(listener, tech_pvt->line, tech_pvt->call_id); - set_lamp(listener, SKINNY_BUTTON_LINE, tech_pvt->line, SKINNY_LAMP_OFF); - clear_prompt_status(listener, tech_pvt->line, tech_pvt->call_id); - - if( skinny_line_get_state(tech_pvt->listener, tech_pvt->line) == SKINNY_KEY_SET_CONNECTED ) { - close_receive_channel(listener, - tech_pvt->call_id, /* uint32_t conference_id, */ - tech_pvt->party_id, /* uint32_t pass_thru_party_id, */ - tech_pvt->call_id /* uint32_t conference_id2, */ - ); - stop_media_transmission(listener, - tech_pvt->call_id, /* uint32_t conference_id, */ - tech_pvt->party_id, /* uint32_t pass_thru_party_id, */ - tech_pvt->call_id /* uint32_t conference_id2, */ - ); - switch_mutex_lock(globals.calls_mutex); - globals.calls--; - if (globals.calls < 0) { - globals.calls = 0; - } - switch_mutex_unlock(globals.calls_mutex); + skinny_session_walk_lines(tech_pvt->profile, switch_core_session_get_uuid(session), channel_on_hangup_callback, &helper); + if ((sql = switch_mprintf( + "DELETE FROM skinny_active_lines WHERE channel_uuid='%s'", + switch_core_session_get_uuid(session) + ))) { + skinny_execute_sql(tech_pvt->profile, sql, tech_pvt->profile->sql_mutex); + switch_safe_free(sql); } - send_call_state(listener, - SKINNY_ON_HOOK, - tech_pvt->line, - tech_pvt->call_id); - skinny_line_set_state(listener, tech_pvt->line, SKINNY_KEY_SET_ON_HOOK, tech_pvt->call_id); - /* TODO: DefineTimeDate */ - set_speaker_mode(listener, SKINNY_SPEAKER_OFF); - set_ringer(listener, SKINNY_RING_OFF, SKINNY_RING_FOREVER, 0); - return SWITCH_STATUS_SUCCESS; } switch_status_t channel_kill_channel(switch_core_session_t *session, int sig) { - switch_channel_t *channel = NULL; - private_t *tech_pvt = NULL; - - channel = switch_core_session_get_channel(session); - assert(channel != NULL); - - tech_pvt = switch_core_session_get_private(session); - assert(tech_pvt != NULL); + switch_channel_t *channel = switch_core_session_get_channel(session); + private_t *tech_pvt = switch_core_session_get_private(session); switch (sig) { case SWITCH_SIG_KILL: @@ -601,7 +697,7 @@ switch_status_t channel_kill_channel(switch_core_session_t *session, int sig) default: break; } - + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s CHANNEL KILL %d\n", switch_channel_get_name(channel), sig); return SWITCH_STATUS_SUCCESS; @@ -631,16 +727,10 @@ switch_status_t channel_send_dtmf(switch_core_session_t *session, const switch_d switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id) { - switch_channel_t *channel = NULL; - private_t *tech_pvt = NULL; + switch_channel_t *channel = switch_core_session_get_channel(session); + private_t *tech_pvt = switch_core_session_get_private(session); int payload = 0; - channel = switch_core_session_get_channel(session); - assert(channel != NULL); - - tech_pvt = switch_core_session_get_private(session); - assert(tech_pvt != NULL); - while (!(tech_pvt->read_codec.implementation && switch_rtp_ready(tech_pvt->rtp_session))) { if (switch_channel_ready(channel)) { switch_yield(10000); @@ -705,16 +795,9 @@ switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_ switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id) { - switch_channel_t *channel = NULL; - private_t *tech_pvt = NULL; + private_t *tech_pvt = switch_core_session_get_private(session); //switch_frame_t *pframe; switch_status_t status = SWITCH_STATUS_SUCCESS; - - channel = switch_core_session_get_channel(session); - assert(channel != NULL); - - tech_pvt = switch_core_session_get_private(session); - assert(tech_pvt != NULL); if (!switch_test_flag(tech_pvt, TFLAG_IO)) { return SWITCH_STATUS_FALSE; @@ -737,31 +820,12 @@ switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame switch_status_t channel_answer_channel(switch_core_session_t *session) { - private_t *tech_pvt; - switch_channel_t *channel = NULL; - - channel = switch_core_session_get_channel(session); - assert(channel != NULL); - - tech_pvt = switch_core_session_get_private(session); - assert(tech_pvt != NULL); - - return SWITCH_STATUS_SUCCESS; } switch_status_t channel_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg) { - switch_channel_t *channel; - private_t *tech_pvt; - - channel = switch_core_session_get_channel(session); - assert(channel != NULL); - - tech_pvt = (private_t *) switch_core_session_get_private(session); - assert(tech_pvt != NULL); - switch (msg->message_id) { case SWITCH_MESSAGE_INDICATE_ANSWER: { @@ -785,11 +849,10 @@ switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, swi switch_call_cause_t cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; switch_core_session_t *nsession = NULL; private_t *tech_pvt; - + char *profile_name, *dest; skinny_profile_t *profile = NULL; - listener_t *listener = NULL; - uint32_t line = 0; + char *sql; char name[128]; switch_channel_t *channel; switch_caller_profile_t *caller_profile; @@ -827,32 +890,13 @@ switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, swi cause = SWITCH_CAUSE_UNALLOCATED_NUMBER; goto error; } - + snprintf(name, sizeof(name), "SKINNY/%s/%s", profile->name, dest); channel = switch_core_session_get_channel(nsession); switch_channel_set_name(channel, name); - - if ((skinny_profile_find_listener_by_dest(profile, dest, &listener, &line) != SWITCH_STATUS_SUCCESS)) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Problem while retrieving listener and line for destination %s in profile %s\n", dest, profile_name); - cause = SWITCH_CAUSE_UNALLOCATED_NUMBER; - goto error; - } - - if (!listener) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Invalid destination or phone not registred %s in profile %s\n", dest, profile_name); - cause = SWITCH_CAUSE_UNALLOCATED_NUMBER; - goto error; - } - - if (line == 0) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Invalid destination or phone not registred %s in profile %s\n", dest, profile_name); - cause = SWITCH_CAUSE_UNALLOCATED_NUMBER; - goto error; - } - - tech_init(tech_pvt, nsession, listener, line); + tech_init(tech_pvt, profile, nsession); caller_profile = switch_caller_profile_clone(nsession, outbound_profile); switch_channel_set_caller_profile(channel, caller_profile); @@ -861,19 +905,23 @@ switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, swi switch_channel_set_flag(channel, CF_OUTBOUND); switch_set_flag_locked(tech_pvt, TFLAG_OUTBOUND); - if(tech_pvt->listener->session[tech_pvt->line]) { /* Line is busy */ - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Device line is busy %s in profile %s\n", dest, profile_name); - cause = SWITCH_CAUSE_USER_BUSY; + if ((sql = switch_mprintf( + "INSERT INTO skinny_active_lines " + "(device_name, device_instance, line_instance, channel_uuid, call_id, call_state) " + "SELECT device_name, device_instance, line_instance, '%s', %d, %d " + "FROM skinny_lines " + "WHERE value='%s'", + switch_core_session_get_uuid(nsession), tech_pvt->call_id, SKINNY_ON_HOOK, dest + ))) { + skinny_execute_sql(profile, sql, profile->sql_mutex); + switch_safe_free(sql); + } + + cause = skinny_ring_lines(tech_pvt); + + if(cause != SWITCH_CAUSE_SUCCESS) { goto error; } - tech_pvt->listener->session[tech_pvt->line] = nsession; - send_call_state(tech_pvt->listener, SKINNY_RING_IN, tech_pvt->line, tech_pvt->call_id); - skinny_line_set_state(tech_pvt->listener, tech_pvt->line, SKINNY_KEY_SET_RING_IN, tech_pvt->call_id); - display_prompt_status(tech_pvt->listener, 0, "\200\027tel", tech_pvt->line, tech_pvt->call_id); - /* displayprinotifiymessage */ - skinny_send_call_info(nsession); - set_lamp(tech_pvt->listener, SKINNY_BUTTON_LINE, tech_pvt->line, SKINNY_LAMP_BLINK); - set_ringer(tech_pvt->listener, SKINNY_RING_OUTSIDE, SKINNY_RING_FOREVER, 0); *new_session = nsession; @@ -950,6 +998,15 @@ switch_io_routines_t skinny_io_routines = { /* LISTENER FUNCTIONS */ /*****************************************************************************/ +uint8_t listener_is_ready(listener_t *listener) +{ + return globals.running + && listener + && listener->sock + && switch_test_flag(listener, LFLAG_RUNNING) + && listener->profile->listener_ready; +} + static void add_listener(listener_t *listener) { skinny_profile_t *profile; @@ -992,8 +1049,9 @@ static void walk_listeners(skinny_listener_callback_func_t callback, void *pvt) void *val; skinny_profile_t *profile; listener_t *l; - + /* walk listeners */ + switch_mutex_lock(globals.mutex); for (hi = switch_hash_first(NULL, globals.profile_hash); hi; hi = switch_hash_next(hi)) { switch_hash_this(hi, NULL, NULL, &val); profile = (skinny_profile_t *) val; @@ -1004,6 +1062,7 @@ static void walk_listeners(skinny_listener_callback_func_t callback, void *pvt) } switch_mutex_unlock(profile->listener_mutex); } + switch_mutex_unlock(globals.mutex); } static void flush_listener(listener_t *listener, switch_bool_t flush_log, switch_bool_t flush_events) @@ -1012,12 +1071,12 @@ static void flush_listener(listener_t *listener, switch_bool_t flush_log, switch if(!zstr(listener->device_name)) { skinny_profile_t *profile = listener->profile; char *sql; - + if ((sql = switch_mprintf( "DELETE FROM skinny_devices " "WHERE name='%s' and instance=%d", listener->device_name, listener->device_instance))) { - skinny_execute_sql(profile, sql, profile->listener_mutex); + skinny_execute_sql(profile, sql, profile->sql_mutex); switch_safe_free(sql); } @@ -1025,7 +1084,7 @@ static void flush_listener(listener_t *listener, switch_bool_t flush_log, switch "DELETE FROM skinny_lines " "WHERE device_name='%s' and device_instance=%d", listener->device_name, listener->device_instance))) { - skinny_execute_sql(profile, sql, profile->listener_mutex); + skinny_execute_sql(profile, sql, profile->sql_mutex); switch_safe_free(sql); } @@ -1033,7 +1092,7 @@ static void flush_listener(listener_t *listener, switch_bool_t flush_log, switch "DELETE FROM skinny_buttons " "WHERE device_name='%s' and device_instance=%d", listener->device_name, listener->device_instance))) { - skinny_execute_sql(profile, sql, profile->listener_mutex); + skinny_execute_sql(profile, sql, profile->sql_mutex); switch_safe_free(sql); } @@ -1069,12 +1128,13 @@ static int dump_device_callback(void *pArg, int argc, char **argv, char **column return 0; } -static switch_status_t dump_device(skinny_profile_t *profile, const char *device_name, switch_stream_handle_t *stream) +switch_status_t dump_device(skinny_profile_t *profile, const char *device_name, switch_stream_handle_t *stream) { char *sql; - if ((sql = switch_mprintf("SELECT * FROM skinny_devices WHERE name LIKE '%s'", + if ((sql = switch_mprintf("SELECT name, user_id, instance, ip, type, max_streams, port, codec_string " + "FROM skinny_devices WHERE name='%s'", device_name))) { - skinny_execute_sql_callback(profile, profile->listener_mutex, sql, dump_device_callback, stream); + skinny_execute_sql_callback(profile, profile->sql_mutex, sql, dump_device_callback, stream); switch_safe_free(sql); } @@ -1120,7 +1180,7 @@ switch_status_t keepalive_listener(listener_t *listener, void *pvt) switch_assert(listener); assert(listener->profile); profile = listener->profile; - + listener->expire_time = switch_epoch_time_now(NULL)+profile->keep_alive*110/100; return SWITCH_STATUS_SUCCESS; @@ -1141,9 +1201,9 @@ static void *SWITCH_THREAD_FUNC listener_run(switch_thread_t *thread, void *obj) switch_mutex_lock(profile->listener_mutex); profile->listener_threads++; switch_mutex_unlock(profile->listener_mutex); - + switch_assert(listener != NULL); - + switch_socket_opt_set(listener->sock, SWITCH_SO_TCP_NODELAY, TRUE); switch_socket_opt_set(listener->sock, SWITCH_SO_NONBLOCK, TRUE); @@ -1161,7 +1221,7 @@ static void *SWITCH_THREAD_FUNC listener_run(switch_thread_t *thread, void *obj) add_listener(listener); - while (globals.running && switch_test_flag(listener, LFLAG_RUNNING) && profile->listener_ready) { + while (listener_is_ready(listener)) { status = skinny_read_packet(listener, &request); if (status != SWITCH_STATUS_SUCCESS) { @@ -1200,6 +1260,7 @@ static void *SWITCH_THREAD_FUNC listener_run(switch_thread_t *thread, void *obj) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Connection Closed\n"); } + /* TODO for(int line = 0 ; line < SKINNY_MAX_BUTTON_COUNT ; line++) { if(listener->session[line]) { switch_channel_clear_flag(switch_core_session_get_channel(listener->session[line]), CF_CONTROLLED); @@ -1208,6 +1269,7 @@ static void *SWITCH_THREAD_FUNC listener_run(switch_thread_t *thread, void *obj) destroy_pool = 0; } } + */ if(destroy_pool == 0) { goto no_destroy_pool; } @@ -1237,25 +1299,26 @@ static void launch_listener_thread(listener_t *listener) switch_thread_create(&thread, thd_attr, listener_run, listener, listener->pool); } -int skinny_socket_create_and_bind(skinny_profile_t *profile) +static void *SWITCH_THREAD_FUNC skinny_profile_run(switch_thread_t *thread, void *obj) { + skinny_profile_t *profile = (skinny_profile_t *) obj; switch_status_t rv; switch_sockaddr_t *sa; switch_socket_t *inbound_socket = NULL; listener_t *listener; - switch_memory_pool_t *pool = NULL, *listener_pool = NULL; + switch_memory_pool_t *tmp_pool = NULL, *listener_pool = NULL; uint32_t errs = 0; - if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) { + if (switch_core_new_memory_pool(&tmp_pool) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "OH OH no pool\n"); - return SWITCH_STATUS_TERM; + return NULL; } while(globals.running) { - rv = switch_sockaddr_info_get(&sa, profile->ip, SWITCH_INET, profile->port, 0, pool); + rv = switch_sockaddr_info_get(&sa, profile->ip, SWITCH_INET, profile->port, 0, tmp_pool); if (rv) goto fail; - rv = switch_socket_create(&profile->sock, switch_sockaddr_get_family(sa), SOCK_STREAM, SWITCH_PROTO_TCP, pool); + rv = switch_socket_create(&profile->sock, switch_sockaddr_get_family(sa), SOCK_STREAM, SWITCH_PROTO_TCP, tmp_pool); if (rv) goto sock_fail; rv = switch_socket_opt_set(profile->sock, SWITCH_SO_REUSEADDR, 1); @@ -1299,7 +1362,7 @@ int skinny_socket_create_and_bind(skinny_profile_t *profile) errs = 0; } - + if (!(listener = switch_core_alloc(listener_pool, sizeof(*listener)))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error\n"); break; @@ -1325,9 +1388,9 @@ int skinny_socket_create_and_bind(skinny_profile_t *profile) end: close_socket(&profile->sock, profile); - - if (pool) { - switch_core_destroy_memory_pool(&pool); + + if (tmp_pool) { + switch_core_destroy_memory_pool(&tmp_pool); } if (listener_pool) { @@ -1336,7 +1399,7 @@ int skinny_socket_create_and_bind(skinny_profile_t *profile) fail: - return SWITCH_STATUS_TERM; + return NULL; } /*****************************************************************************/ @@ -1353,18 +1416,18 @@ static void skinny_profile_set(skinny_profile_t *profile, char *var, char *val) return; if (!strcasecmp(var, "domain")) { - profile->domain = switch_core_strdup(module_pool, val); + profile->domain = switch_core_strdup(profile->pool, val); } else if (!strcasecmp(var, "ip")) { - profile->ip = switch_core_strdup(module_pool, val); + profile->ip = switch_core_strdup(profile->pool, val); } else if (!strcasecmp(var, "dialplan")) { - profile->dialplan = switch_core_strdup(module_pool, val); + profile->dialplan = switch_core_strdup(profile->pool, val); } else if (!strcasecmp(var, "context")) { - profile->context = switch_core_strdup(module_pool, val); + profile->context = switch_core_strdup(profile->pool, val); } else if (!strcasecmp(var, "date-format")) { strncpy(profile->date_format, val, 6); } else if (!strcasecmp(var, "odbc-dsn") && !zstr(val)) { if (switch_odbc_available()) { - profile->odbc_dsn = switch_core_strdup(module_pool, val); + profile->odbc_dsn = switch_core_strdup(profile->pool, val); if ((profile->odbc_user = strchr(profile->odbc_dsn, ':'))) { *profile->odbc_user++ = '\0'; if ((profile->odbc_pass = strchr(profile->odbc_user, ':'))) { @@ -1382,18 +1445,12 @@ static switch_status_t load_skinny_config(void) char *cf = "skinny.conf"; switch_xml_t xcfg, xml, xprofiles, xprofile; - memset(&globals, 0, sizeof(globals)); - globals.running = 1; - - switch_core_hash_init(&globals.profile_hash, module_pool); - - switch_mutex_init(&globals.calls_mutex, SWITCH_MUTEX_NESTED, module_pool); - if (!(xml = switch_xml_open_cfg(cf, &xcfg, NULL))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", cf); return SWITCH_STATUS_TERM; } + switch_mutex_lock(globals.mutex); if ((xprofiles = switch_xml_child(xcfg, "profiles"))) { for (xprofile = switch_xml_child(xprofiles, "profile"); xprofile; xprofile = xprofile->next) { char *profile_name = (char *) switch_xml_attr_soft(xprofile, "name"); @@ -1404,14 +1461,23 @@ static switch_status_t load_skinny_config(void) continue; } if (xsettings) { + switch_memory_pool_t *profile_pool = NULL; char dbname[256]; switch_core_db_t *db; skinny_profile_t *profile = NULL; switch_xml_t param; - - profile = switch_core_alloc(module_pool, sizeof(skinny_profile_t)); + + if (switch_core_new_memory_pool(&profile_pool) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "OH OH no pool\n"); + return SWITCH_STATUS_TERM; + } + profile = switch_core_alloc(profile_pool, sizeof(skinny_profile_t)); + profile->pool = profile_pool; profile->name = profile_name; - + switch_mutex_init(&profile->listener_mutex, SWITCH_MUTEX_NESTED, profile->pool); + switch_mutex_init(&profile->sql_mutex, SWITCH_MUTEX_NESTED, profile->pool); + switch_mutex_init(&profile->sock_mutex, SWITCH_MUTEX_NESTED, profile->pool); + for (param = switch_xml_child(xsettings, "param"); param; param = param->next) { char *var = (char *) switch_xml_attr_soft(param, "name"); char *val = (char *) switch_xml_attr_soft(param, "value"); @@ -1436,7 +1502,7 @@ static switch_status_t load_skinny_config(void) profile->debug = atoi(val); } } /* param */ - + if (!profile->dialplan) { skinny_profile_set(profile, "dialplan","default"); } @@ -1450,7 +1516,7 @@ static switch_status_t load_skinny_config(void) } switch_snprintf(dbname, sizeof(dbname), "skinny_%s", profile->name); - profile->dbname = switch_core_strdup(module_pool, dbname); + profile->dbname = switch_core_strdup(profile->pool, dbname); if (switch_odbc_available() && profile->odbc_dsn) { if (!(profile->master_odbc = switch_odbc_handle_new(profile->odbc_dsn, profile->odbc_user, profile->odbc_pass))) { @@ -1467,23 +1533,28 @@ static switch_status_t load_skinny_config(void) switch_odbc_handle_exec(profile->master_odbc, devices_sql, NULL, NULL); switch_odbc_handle_exec(profile->master_odbc, lines_sql, NULL, NULL); switch_odbc_handle_exec(profile->master_odbc, buttons_sql, NULL, NULL); + switch_odbc_handle_exec(profile->master_odbc, active_lines_sql, NULL, NULL); } else { if ((db = switch_core_db_open_file(profile->dbname))) { switch_core_db_test_reactive(db, "SELECT * FROM skinny_devices", NULL, devices_sql); switch_core_db_test_reactive(db, "SELECT * FROM skinny_lines", NULL, lines_sql); switch_core_db_test_reactive(db, "SELECT * FROM skinny_buttons", NULL, buttons_sql); + switch_core_db_test_reactive(db, "SELECT * FROM skinny_active_lines", NULL, active_lines_sql); } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Cannot Open SQL Database!\n"); continue; } switch_core_db_close(db); } - - skinny_execute_sql_callback(profile, profile->listener_mutex, "DELETE FROM skinny_devices", NULL, NULL); - skinny_execute_sql_callback(profile, profile->listener_mutex, "DELETE FROM skinny_lines", NULL, NULL); - skinny_execute_sql_callback(profile, profile->listener_mutex, "DELETE FROM skinny_buttons", NULL, NULL); + + skinny_execute_sql_callback(profile, profile->sql_mutex, "DELETE FROM skinny_devices", NULL, NULL); + skinny_execute_sql_callback(profile, profile->sql_mutex, "DELETE FROM skinny_lines", NULL, NULL); + skinny_execute_sql_callback(profile, profile->sql_mutex, "DELETE FROM skinny_buttons", NULL, NULL); + skinny_execute_sql_callback(profile, profile->sql_mutex, "DELETE FROM skinny_active_lines", NULL, NULL); - switch_core_hash_insert(globals.profile_hash, profile->name, profile); + switch_mutex_lock(globals.mutex); + switch_core_hash_insert(globals.profile_hash, profile->name, profile); + switch_mutex_unlock(globals.mutex); profile = NULL; } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, @@ -1492,498 +1563,170 @@ static switch_status_t load_skinny_config(void) } /* profile */ } switch_xml_free(xml); + switch_mutex_unlock(globals.mutex); return SWITCH_STATUS_SUCCESS; } -static switch_status_t cmd_status_profile(const char *profile_name, switch_stream_handle_t *stream) -{ - skinny_profile_t *profile; - if ((profile = skinny_find_profile(profile_name))) { - dump_profile(profile, stream); - } else { - stream->write_function(stream, "Profile not found!\n"); - } - - return SWITCH_STATUS_SUCCESS; -} - -static switch_status_t cmd_status_profile_device(const char *profile_name, const char *device_name, switch_stream_handle_t *stream) -{ - skinny_profile_t *profile; - if ((profile = skinny_find_profile(profile_name))) { - dump_device(profile, device_name, stream); - } else { - stream->write_function(stream, "Profile not found!\n"); - } - - return SWITCH_STATUS_SUCCESS; -} - -static switch_status_t cmd_profile_device_send_ringer_message(const char *profile_name, const char *device_name, const char *ring_type, const char *ring_mode, switch_stream_handle_t *stream) -{ - skinny_profile_t *profile; - - if ((profile = skinny_find_profile(profile_name))) { - listener_t *listener = NULL; - skinny_profile_find_listener_by_device_name(profile, device_name, &listener); - if(listener) { - set_ringer(listener, skinny_str2ring_type(ring_type), skinny_str2ring_mode(ring_mode), 0); - } else { - stream->write_function(stream, "Listener not found!\n"); - } - } else { - stream->write_function(stream, "Profile not found!\n"); - } - - return SWITCH_STATUS_SUCCESS; -} - -static switch_status_t cmd_profile_device_send_lamp_message(const char *profile_name, const char *device_name, const char *stimulus, const char *instance, const char *lamp_mode, switch_stream_handle_t *stream) -{ - skinny_profile_t *profile; - - if ((profile = skinny_find_profile(profile_name))) { - listener_t *listener = NULL; - skinny_profile_find_listener_by_device_name(profile, device_name, &listener); - if(listener) { - set_lamp(listener, skinny_str2button(stimulus), atoi(instance), skinny_str2lamp_mode(lamp_mode)); - } else { - stream->write_function(stream, "Listener not found!\n"); - } - } else { - stream->write_function(stream, "Profile not found!\n"); - } - - return SWITCH_STATUS_SUCCESS; -} - -static switch_status_t cmd_profile_device_send_speaker_mode_message(const char *profile_name, const char *device_name, const char *speaker_mode, switch_stream_handle_t *stream) -{ - skinny_profile_t *profile; - - if ((profile = skinny_find_profile(profile_name))) { - listener_t *listener = NULL; - skinny_profile_find_listener_by_device_name(profile, device_name, &listener); - if(listener) { - set_speaker_mode(listener, skinny_str2speaker_mode(speaker_mode)); - } else { - stream->write_function(stream, "Listener not found!\n"); - } - } else { - stream->write_function(stream, "Profile not found!\n"); - } - - return SWITCH_STATUS_SUCCESS; -} - -static switch_status_t cmd_profile_device_send_call_state_message(const char *profile_name, const char *device_name, const char *call_state, const char *line_instance, const char *call_id, switch_stream_handle_t *stream) -{ - skinny_profile_t *profile; - - if ((profile = skinny_find_profile(profile_name))) { - listener_t *listener = NULL; - skinny_profile_find_listener_by_device_name(profile, device_name, &listener); - if(listener) { - send_call_state(listener, skinny_str2call_state(call_state), atoi(line_instance), atoi(call_id)); - } else { - stream->write_function(stream, "Listener not found!\n"); - } - } else { - stream->write_function(stream, "Profile not found!\n"); - } - - return SWITCH_STATUS_SUCCESS; -} - -static switch_status_t cmd_profile_device_send_reset_message(const char *profile_name, const char *device_name, const char *reset_type, switch_stream_handle_t *stream) -{ - skinny_profile_t *profile; - - if ((profile = skinny_find_profile(profile_name))) { - listener_t *listener = NULL; - skinny_profile_find_listener_by_device_name(profile, device_name, &listener); - if(listener) { - send_reset(listener, skinny_str2device_reset_type(reset_type)); - } else { - stream->write_function(stream, "Listener not found!\n"); - } - } else { - stream->write_function(stream, "Profile not found!\n"); - } - - return SWITCH_STATUS_SUCCESS; -} - -SWITCH_STANDARD_API(skinny_function) -{ - char *argv[1024] = { 0 }; - int argc = 0; - char *mycmd = NULL; - switch_status_t status = SWITCH_STATUS_SUCCESS; - const char *usage_string = "USAGE:\n" - "--------------------------------------------------------------------------------\n" - "skinny help\n" - "skinny status profile \n" - "skinny status profile device \n" - "skinny profile device send ResetMessage [DeviceReset|DeviceRestart]\n" - "skinny profile device send SetRingerMessage \n" - "skinny profile device send SetLampMessage \n" - "skinny profile device send SetSpeakerModeMessage \n" - "skinny profile device send CallStateMessage \n" - "--------------------------------------------------------------------------------\n"; - if (session) { - return SWITCH_STATUS_FALSE; - } - - if (zstr(cmd)) { - stream->write_function(stream, "%s", usage_string); - goto done; - } - - if (!(mycmd = strdup(cmd))) { - status = SWITCH_STATUS_MEMERR; - goto done; - } - - if (!(argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) || !argv[0]) { - stream->write_function(stream, "%s", usage_string); - goto done; - } - - if (!strcasecmp(argv[0], "help")) {/* skinny help */ - stream->write_function(stream, "%s", usage_string); - goto done; - } else if (argc == 3 && !strcasecmp(argv[0], "status") && !strcasecmp(argv[1], "profile")) { - /* skinny status profile */ - status = cmd_status_profile(argv[2], stream); - } else if (argc == 5 && !strcasecmp(argv[0], "status") && !strcasecmp(argv[1], "profile") && !strcasecmp(argv[3], "device")) { - /* skinny status profile device */ - status = cmd_status_profile_device(argv[2], argv[4], stream); - } else if (argc >= 6 && !strcasecmp(argv[0], "profile") && !strcasecmp(argv[2], "device") && !strcasecmp(argv[4], "send")) { - /* skinny profile device send ... */ - switch(skinny_str2message_type(argv[5])) { - case SET_RINGER_MESSAGE: - if(argc == 8) { - /* SetRingerMessage */ - status = cmd_profile_device_send_ringer_message(argv[1], argv[3], argv[6], argv[7], stream); - } - break; - case SET_LAMP_MESSAGE: - if (argc == 9) { - /* SetLampMessage */ - status = cmd_profile_device_send_lamp_message(argv[1], argv[3], argv[6], argv[7], argv[8], stream); - } - break; - case SET_SPEAKER_MODE_MESSAGE: - if (argc == 7) { - /* SetSpeakerModeMessage */ - status = cmd_profile_device_send_speaker_mode_message(argv[1], argv[3], argv[6], stream); - } - break; - case CALL_STATE_MESSAGE: - if (argc == 9) { - /* CallStateMessage */ - status = cmd_profile_device_send_call_state_message(argv[1], argv[3], argv[6], argv[7], argv[8], stream); - } - break; - case RESET_MESSAGE: - if (argc == 7) { - /* ResetMessage */ - status = cmd_profile_device_send_reset_message(argv[1], argv[3], argv[6], stream); - } - break; - default: - stream->write_function(stream, "Unhandled message %s\n", argv[5]); - } - } else { - stream->write_function(stream, "Unknown Command [%s]\n", argv[0]); - } - -done: - switch_safe_free(mycmd); - return status; -} - static void event_handler(switch_event_t *event) { + char *subclass; + if (event->event_id == SWITCH_EVENT_HEARTBEAT) { walk_listeners(kill_expired_listener, NULL); - } -} + } else if ((subclass = switch_event_get_header_nil(event, "Event-Subclass")) && !strcasecmp(subclass, SKINNY_EVENT_CALL_STATE)) { + char *profile_name = switch_event_get_header_nil(event, "Skinny-Profile-Name"); + char *device_name = switch_event_get_header_nil(event, "Skinny-Device-Name"); + uint32_t device_instance = atoi(switch_event_get_header_nil(event, "Skinny-Station-Instance")); + uint32_t line_instance = atoi(switch_event_get_header_nil(event, "Skinny-Line-Instance")); + uint32_t call_id = atoi(switch_event_get_header_nil(event, "Skinny-Call-Id")); + uint32_t call_state = atoi(switch_event_get_header_nil(event, "Skinny-Call-State")); + skinny_profile_t *profile; + listener_t *listener = NULL; + char *line_instance_condition, *call_id_condition; + char *sql; -static switch_status_t skinny_list_profiles(const char *line, const char *cursor, switch_console_callback_match_t **matches) -{ - switch_console_callback_match_t *my_matches = NULL; - switch_status_t status = SWITCH_STATUS_FALSE; - switch_hash_index_t *hi; - void *val; - skinny_profile_t *profile; - - /* walk profiles */ - for (hi = switch_hash_first(NULL, globals.profile_hash); hi; hi = switch_hash_next(hi)) { - switch_hash_this(hi, NULL, NULL, &val); - profile = (skinny_profile_t *) val; + if ((profile = skinny_find_profile(profile_name))) { + skinny_profile_find_listener_by_device_name_and_instance(profile, device_name, device_instance, &listener); + if(listener) { + if(line_instance > 0) { + line_instance_condition = switch_mprintf("line_instance=%d", line_instance); + } else { + line_instance_condition = switch_mprintf("1=1"); + } + switch_assert(line_instance_condition); + if(call_id > 0) { + call_id_condition = switch_mprintf("call_id=%d", call_id); + } else { + call_id_condition = switch_mprintf("1=1"); + } + switch_assert(call_id_condition); - switch_console_push_match(&my_matches, profile->name); - } - - if (my_matches) { - *matches = my_matches; - status = SWITCH_STATUS_SUCCESS; - } - - return status; -} - -struct match_helper { - switch_console_callback_match_t *my_matches; -}; - -static int skinny_list_devices_callback(void *pArg, int argc, char **argv, char **columnNames) -{ - struct match_helper *h = (struct match_helper *) pArg; - char *device_name = argv[0]; - - switch_console_push_match(&h->my_matches, device_name); - return 0; -} - -static switch_status_t skinny_list_devices(const char *line, const char *cursor, switch_console_callback_match_t **matches) -{ - struct match_helper h = { 0 }; - switch_status_t status = SWITCH_STATUS_FALSE; - skinny_profile_t *profile = NULL; - char *sql; - - char *myline; - char *argv[1024] = { 0 }; - int argc = 0; - - if (!(myline = strdup(line))) { - status = SWITCH_STATUS_MEMERR; - return status; - } - if (!(argc = switch_separate_string(myline, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) || argc != 5) { - return status; - } - - if(!strcasecmp(argv[1], "profile")) {/* skinny profile ... */ - profile = skinny_find_profile(argv[2]); - } else if(!strcasecmp(argv[2], "profile")) {/* skinny status profile ... */ - profile = skinny_find_profile(argv[3]); - } - - if(profile) { - if ((sql = switch_mprintf("SELECT name FROM skinny_devices"))) { - skinny_execute_sql_callback(profile, profile->listener_mutex, sql, skinny_list_devices_callback, &h); - switch_safe_free(sql); + if ((sql = switch_mprintf( + "UPDATE skinny_active_lines " + "SET call_state=%d " + "WHERE device_name='%s' AND device_instance=%d " + "AND %s AND %s", + call_state, + listener->device_name, listener->device_instance, + line_instance_condition, call_id_condition + ))) { + skinny_execute_sql(listener->profile, sql, listener->profile->sql_mutex); + switch_safe_free(sql); + send_call_state(listener, call_state, line_instance, call_id); + } + switch_safe_free(line_instance_condition); + switch_safe_free(call_id_condition); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, + "Device %s:%d in profile '%s' not found.\n", device_name, device_instance, profile_name); + } + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, + "Profile '%s' not found.\n", profile_name); } } - - if (h.my_matches) { - *matches = h.my_matches; - status = SWITCH_STATUS_SUCCESS; - } - - return status; } -static switch_status_t skinny_list_reset_types(const char *line, const char *cursor, switch_console_callback_match_t **matches) -{ - switch_status_t status = SWITCH_STATUS_FALSE; - SKINNY_PUSH_DEVICE_RESET_TYPES - return status; -} - -static switch_status_t skinny_list_stimuli(const char *line, const char *cursor, switch_console_callback_match_t **matches) -{ - switch_status_t status = SWITCH_STATUS_FALSE; - SKINNY_PUSH_STIMULI - return status; -} - -static switch_status_t skinny_list_ring_types(const char *line, const char *cursor, switch_console_callback_match_t **matches) -{ - switch_status_t status = SWITCH_STATUS_FALSE; - SKINNY_PUSH_RING_TYPES - return status; -} - -static switch_status_t skinny_list_ring_modes(const char *line, const char *cursor, switch_console_callback_match_t **matches) -{ - switch_status_t status = SWITCH_STATUS_FALSE; - SKINNY_PUSH_RING_MODES - return status; -} - -static switch_status_t skinny_list_stimulus_instances(const char *line, const char *cursor, switch_console_callback_match_t **matches) -{ - switch_status_t status = SWITCH_STATUS_FALSE; - switch_console_callback_match_t *my_matches = NULL; - - switch_console_push_match(&my_matches, ""); - switch_console_push_match(&my_matches, "0"); - - if (my_matches) { - *matches = my_matches; - status = SWITCH_STATUS_SUCCESS; - } - return status; -} - -static switch_status_t skinny_list_stimulus_modes(const char *line, const char *cursor, switch_console_callback_match_t **matches) -{ - switch_status_t status = SWITCH_STATUS_FALSE; - SKINNY_PUSH_LAMP_MODES - return status; -} - -static switch_status_t skinny_list_speaker_modes(const char *line, const char *cursor, switch_console_callback_match_t **matches) -{ - switch_status_t status = SWITCH_STATUS_FALSE; - SKINNY_PUSH_SPEAKER_MODES - return status; -} - -static switch_status_t skinny_list_call_states(const char *line, const char *cursor, switch_console_callback_match_t **matches) -{ - switch_status_t status = SWITCH_STATUS_FALSE; - SKINNY_PUSH_CALL_STATES - return status; -} - -static switch_status_t skinny_list_line_instances(const char *line, const char *cursor, switch_console_callback_match_t **matches) -{ - switch_status_t status = SWITCH_STATUS_FALSE; - switch_console_callback_match_t *my_matches = NULL; - - /* TODO */ - switch_console_push_match(&my_matches, "1"); - switch_console_push_match(&my_matches, ""); - - if (my_matches) { - *matches = my_matches; - status = SWITCH_STATUS_SUCCESS; - } - return status; -} - -static switch_status_t skinny_list_call_ids(const char *line, const char *cursor, switch_console_callback_match_t **matches) -{ - switch_status_t status = SWITCH_STATUS_FALSE; - switch_console_callback_match_t *my_matches = NULL; - - /* TODO */ - switch_console_push_match(&my_matches, "1345"); - switch_console_push_match(&my_matches, ""); - - if (my_matches) { - *matches = my_matches; - status = SWITCH_STATUS_SUCCESS; - } - return status; -} /*****************************************************************************/ SWITCH_MODULE_LOAD_FUNCTION(mod_skinny_load) { switch_hash_index_t *hi; - void *val; - skinny_profile_t *profile; + /* globals init */ + memset(&globals, 0, sizeof(globals)); - switch_api_interface_t *api_interface; - - module_pool = pool; + if (switch_core_new_memory_pool(&globals.pool) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "OH OH no pool\n"); + return SWITCH_STATUS_TERM; + } + switch_mutex_init(&globals.mutex, SWITCH_MUTEX_NESTED, globals.pool); + switch_core_hash_init(&globals.profile_hash, globals.pool); + globals.running = 1; load_skinny_config(); - /* init listeners */ - for (hi = switch_hash_first(NULL, globals.profile_hash); hi; hi = switch_hash_next(hi)) { - switch_hash_this(hi, NULL, NULL, &val); - profile = (skinny_profile_t *) val; - - switch_mutex_init(&profile->listener_mutex, SWITCH_MUTEX_NESTED, module_pool); - switch_mutex_init(&profile->sock_mutex, SWITCH_MUTEX_NESTED, module_pool); - - } - + /* bind to events */ if ((switch_event_bind_removable(modname, SWITCH_EVENT_HEARTBEAT, NULL, event_handler, NULL, &globals.heartbeat_node) != SWITCH_STATUS_SUCCESS)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind our heartbeat handler!\n"); /* Not such severe to prevent loading */ } + if ((switch_event_bind_removable(modname, SWITCH_EVENT_CUSTOM, SKINNY_EVENT_CALL_STATE, event_handler, NULL, &globals.call_state_node) != SWITCH_STATUS_SUCCESS)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind our call_state handler!\n"); + return SWITCH_STATUS_TERM; + } + /* reserve events */ if (switch_event_reserve_subclass(SKINNY_EVENT_REGISTER) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", SKINNY_EVENT_REGISTER); return SWITCH_STATUS_TERM; } + if (switch_event_reserve_subclass(SKINNY_EVENT_UNREGISTER) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", SKINNY_EVENT_UNREGISTER); + return SWITCH_STATUS_TERM; + } + if (switch_event_reserve_subclass(SKINNY_EVENT_EXPIRE) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", SKINNY_EVENT_EXPIRE); + return SWITCH_STATUS_TERM; + } + if (switch_event_reserve_subclass(SKINNY_EVENT_ALARM) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", SKINNY_EVENT_ALARM); + return SWITCH_STATUS_TERM; + } + if (switch_event_reserve_subclass(SKINNY_EVENT_CALL_STATE) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", SKINNY_EVENT_CALL_STATE); + return SWITCH_STATUS_TERM; + } /* connect my internal structure to the blank pointer passed to me */ - *module_interface = switch_loadable_module_create_module_interface(pool, modname); + *module_interface = switch_loadable_module_create_module_interface(globals.pool, modname); skinny_endpoint_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_ENDPOINT_INTERFACE); skinny_endpoint_interface->interface_name = "skinny"; skinny_endpoint_interface->io_routines = &skinny_io_routines; skinny_endpoint_interface->state_handler = &skinny_state_handlers; + skinny_api_register(module_interface); - SWITCH_ADD_API(api_interface, "skinny", "Skinny Controls", skinny_function, " "); - switch_console_set_complete("add skinny help"); + /* launch listeners */ + switch_mutex_lock(globals.mutex); + for (hi = switch_hash_first(NULL, globals.profile_hash); hi; hi = switch_hash_next(hi)) { + void *val; + skinny_profile_t *profile; + switch_thread_t *thread; + switch_threadattr_t *thd_attr = NULL; - switch_console_set_complete("add skinny status profile ::skinny::list_profiles"); - switch_console_set_complete("add skinny status profile ::skinny::list_profiles device ::skinny::list_devices"); + switch_hash_this(hi, NULL, NULL, &val); + profile = (skinny_profile_t *) val; - switch_console_set_complete("add skinny profile ::skinny::list_profiles device ::skinny::list_devices send ResetMessage ::skinny::list_reset_types"); - switch_console_set_complete("add skinny profile ::skinny::list_profiles device ::skinny::list_devices send SetRingerMessage ::skinny::list_ring_types ::skinny::list_ring_modes"); - switch_console_set_complete("add skinny profile ::skinny::list_profiles device ::skinny::list_devices send SetLampMessage ::skinny::list_stimuli ::skinny::list_stimulus_instances ::skinny::list_stimulus_modes"); - switch_console_set_complete("add skinny profile ::skinny::list_profiles device ::skinny::list_devices send SetSpeakerModeMessage ::skinny::list_speaker_modes"); - switch_console_set_complete("add skinny profile ::skinny::list_profiles device ::skinny::list_devices send CallStateMessage ::skinny::list_call_states ::skinny::list_line_instances ::skinny::list_call_ids"); - - switch_console_add_complete_func("::skinny::list_profiles", skinny_list_profiles); - switch_console_add_complete_func("::skinny::list_devices", skinny_list_devices); - switch_console_add_complete_func("::skinny::list_reset_types", skinny_list_reset_types); - switch_console_add_complete_func("::skinny::list_ring_types", skinny_list_ring_types); - switch_console_add_complete_func("::skinny::list_ring_modes", skinny_list_ring_modes); - switch_console_add_complete_func("::skinny::list_stimuli", skinny_list_stimuli); - switch_console_add_complete_func("::skinny::list_stimulus_instances", skinny_list_stimulus_instances); - switch_console_add_complete_func("::skinny::list_stimulus_modes", skinny_list_stimulus_modes); - switch_console_add_complete_func("::skinny::list_speaker_modes", skinny_list_speaker_modes); - switch_console_add_complete_func("::skinny::list_call_states", skinny_list_call_states); - switch_console_add_complete_func("::skinny::list_line_instances", skinny_list_line_instances); - switch_console_add_complete_func("::skinny::list_call_ids", skinny_list_call_ids); + switch_threadattr_create(&thd_attr, profile->pool); + switch_threadattr_detach_set(thd_attr, 1); + switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE); + switch_thread_create(&thread, thd_attr, skinny_profile_run, profile, profile->pool); + } + switch_mutex_unlock(globals.mutex); /* indicate that the module should continue to be loaded */ return SWITCH_STATUS_SUCCESS; } -SWITCH_MODULE_RUNTIME_FUNCTION(mod_skinny_runtime) -{ - switch_status_t status = SWITCH_STATUS_SUCCESS; - switch_hash_index_t *hi; - void *val; - skinny_profile_t *profile; - - /* launch listeners */ - for (hi = switch_hash_first(NULL, globals.profile_hash); hi; hi = switch_hash_next(hi)) { - switch_hash_this(hi, NULL, NULL, &val); - profile = (skinny_profile_t *) val; - - status = skinny_socket_create_and_bind(profile); - if(status != SWITCH_STATUS_SUCCESS) { - return status; - } - } - return status; -} - SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_skinny_shutdown) { switch_hash_index_t *hi; void *val; - skinny_profile_t *profile; + switch_memory_pool_t *pool = globals.pool; + switch_mutex_t *mutex = globals.mutex; int sanity = 0; - switch_event_free_subclass(SKINNY_EVENT_REGISTER); + /* release events */ switch_event_unbind(&globals.heartbeat_node); + switch_event_unbind(&globals.call_state_node); + switch_event_free_subclass(SKINNY_EVENT_REGISTER); + switch_event_free_subclass(SKINNY_EVENT_UNREGISTER); + switch_event_free_subclass(SKINNY_EVENT_EXPIRE); + switch_event_free_subclass(SKINNY_EVENT_ALARM); + switch_event_free_subclass(SKINNY_EVENT_CALL_STATE); + + switch_mutex_lock(mutex); globals.running = 0; @@ -1991,7 +1734,9 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_skinny_shutdown) walk_listeners(kill_listener, NULL); /* close sockets */ + switch_mutex_lock(globals.mutex); for (hi = switch_hash_first(NULL, globals.profile_hash); hi; hi = switch_hash_next(hi)) { + skinny_profile_t *profile; switch_hash_this(hi, NULL, NULL, &val); profile = (skinny_profile_t *) val; @@ -2004,8 +1749,14 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_skinny_shutdown) break; } } + switch_core_destroy_memory_pool(&profile->pool); } + switch_mutex_unlock(globals.mutex); + switch_core_hash_destroy(&globals.profile_hash); + memset(&globals, 0, sizeof(globals)); + switch_mutex_unlock(mutex); + switch_core_destroy_memory_pool(&pool); return SWITCH_STATUS_SUCCESS; } diff --git a/src/mod/endpoints/mod_skinny/mod_skinny.h b/src/mod/endpoints/mod_skinny/mod_skinny.h index 88a5b70287..7bcc40b96c 100644 --- a/src/mod/endpoints/mod_skinny/mod_skinny.h +++ b/src/mod/endpoints/mod_skinny/mod_skinny.h @@ -42,50 +42,54 @@ #define SKINNY_EVENT_UNREGISTER "skinny::unregister" #define SKINNY_EVENT_EXPIRE "skinny::expire" #define SKINNY_EVENT_ALARM "skinny::alarm" +#define SKINNY_EVENT_CALL_STATE "skinny::call_state" struct skinny_globals { - /* data */ - int calls; - switch_mutex_t *calls_mutex; - switch_hash_t *profile_hash; - switch_event_node_t *heartbeat_node; - int running; + int running; + switch_memory_pool_t *pool; + switch_mutex_t *mutex; + switch_hash_t *profile_hash; + switch_event_node_t *heartbeat_node; + switch_event_node_t *call_state_node; }; typedef struct skinny_globals skinny_globals_t; skinny_globals_t globals; struct skinny_profile { - /* prefs */ - char *name; - char *domain; - char *ip; - unsigned int port; - char *dialplan; - char *context; - uint32_t keep_alive; - char date_format[6]; - int debug; - /* db */ - char *dbname; - char *odbc_dsn; - char *odbc_user; - char *odbc_pass; - switch_odbc_handle_t *master_odbc; - /* stats */ - uint32_t ib_calls; - uint32_t ob_calls; - uint32_t ib_failed_calls; - uint32_t ob_failed_calls; - /* listener */ - int listener_threads; - switch_mutex_t *listener_mutex; - switch_socket_t *sock; - switch_mutex_t *sock_mutex; - struct listener *listeners; - uint8_t listener_ready; - /* call id */ - uint32_t next_call_id; + /* prefs */ + char *name; + char *domain; + char *ip; + unsigned int port; + char *dialplan; + char *context; + uint32_t keep_alive; + char date_format[6]; + int debug; + /* db */ + char *dbname; + char *odbc_dsn; + char *odbc_user; + char *odbc_pass; + switch_odbc_handle_t *master_odbc; + switch_mutex_t *sql_mutex; + /* stats */ + uint32_t ib_calls; + uint32_t ob_calls; + uint32_t ib_failed_calls; + uint32_t ob_failed_calls; + /* listener */ + int listener_threads; + switch_mutex_t *listener_mutex; + switch_socket_t *sock; + switch_mutex_t *sock_mutex; + struct listener *listeners; + uint8_t listener_ready; + /* call id */ + uint32_t next_call_id; + /* others */ + switch_memory_pool_t *pool; }; typedef struct skinny_profile skinny_profile_t; @@ -95,28 +99,26 @@ typedef struct skinny_profile skinny_profile_t; /*****************************************************************************/ typedef enum { - LFLAG_RUNNING = (1 << 0), + LFLAG_RUNNING = (1 << 0), } event_flag_t; #define SKINNY_MAX_LINES 42 struct listener { - skinny_profile_t *profile; - char device_name[16]; - uint32_t device_instance; - switch_core_session_t *session[SKINNY_MAX_LINES]; - uint32_t line_state[SKINNY_MAX_LINES]; /* See enum skinny_key_set */ + skinny_profile_t *profile; + char device_name[16]; + uint32_t device_instance; - switch_socket_t *sock; - switch_memory_pool_t *pool; - switch_thread_rwlock_t *rwlock; - switch_sockaddr_t *sa; - char remote_ip[50]; - switch_mutex_t *flag_mutex; - uint32_t flags; - switch_port_t remote_port; - uint32_t id; - time_t expire_time; - struct listener *next; + switch_socket_t *sock; + switch_memory_pool_t *pool; + switch_thread_rwlock_t *rwlock; + switch_sockaddr_t *sa; + char remote_ip[50]; + switch_mutex_t *flag_mutex; + uint32_t flags; + switch_port_t remote_port; + uint32_t id; + time_t expire_time; + struct listener *next; }; typedef struct listener listener_t; @@ -127,83 +129,92 @@ typedef switch_status_t (*skinny_listener_callback_func_t) (listener_t *listener /* CHANNEL TYPES */ /*****************************************************************************/ typedef enum { - TFLAG_IO = (1 << 0), - TFLAG_INBOUND = (1 << 1), - TFLAG_OUTBOUND = (1 << 2), - TFLAG_DTMF = (1 << 3), - TFLAG_VOICE = (1 << 4), - TFLAG_HANGUP = (1 << 5), - TFLAG_LINEAR = (1 << 6), - TFLAG_CODEC = (1 << 7), - - TFLAG_READING = (1 << 9), - TFLAG_WRITING = (1 << 10) + TFLAG_IO = (1 << 0), + TFLAG_INBOUND = (1 << 1), + TFLAG_OUTBOUND = (1 << 2), + TFLAG_DTMF = (1 << 3), + TFLAG_VOICE = (1 << 4), + TFLAG_HANGUP = (1 << 5), + TFLAG_LINEAR = (1 << 6), + TFLAG_CODEC = (1 << 7), + + TFLAG_READING = (1 << 9), + TFLAG_WRITING = (1 << 10) } TFLAGS; typedef enum { - GFLAG_MY_CODEC_PREFS = (1 << 0) + GFLAG_MY_CODEC_PREFS = (1 << 0) } GFLAGS; struct private_object { - unsigned int flags; - switch_frame_t read_frame; - unsigned char databuf[SWITCH_RECOMMENDED_BUFFER_SIZE]; - switch_core_session_t *session; - switch_caller_profile_t *caller_profile; - switch_mutex_t *mutex; - switch_mutex_t *flag_mutex; - /* identification */ - struct listener *listener; - uint32_t line; - uint32_t call_id; - uint32_t party_id; - char *line_name; - char *line_shortname; - char *line_displayname; - char dest[10]; - /* codec */ - char *iananame; - switch_codec_t read_codec; - switch_codec_t write_codec; - switch_codec_implementation_t read_impl; - switch_codec_implementation_t write_impl; - unsigned long rm_rate; - uint32_t codec_ms; - char *rm_encoding; - char *rm_fmtp; - switch_payload_t agreed_pt; - /* RTP */ - switch_rtp_t *rtp_session; - char *local_sdp_audio_ip; - switch_port_t local_sdp_audio_port; - char *remote_sdp_audio_ip; - switch_port_t remote_sdp_audio_port; + unsigned int flags; + switch_frame_t read_frame; + unsigned char databuf[SWITCH_RECOMMENDED_BUFFER_SIZE]; + switch_core_session_t *session; + switch_caller_profile_t *caller_profile; + switch_mutex_t *mutex; + switch_mutex_t *flag_mutex; + /* identification */ + uint32_t call_id; + uint32_t party_id; + + skinny_profile_t *profile; + + /* codec */ + char *iananame; + switch_codec_t read_codec; + switch_codec_t write_codec; + switch_codec_implementation_t read_impl; + switch_codec_implementation_t write_impl; + unsigned long rm_rate; + uint32_t codec_ms; + char *rm_encoding; + char *rm_fmtp; + switch_payload_t agreed_pt; + /* RTP */ + switch_rtp_t *rtp_session; + char *local_sdp_audio_ip; + switch_port_t local_sdp_audio_port; + char *remote_sdp_audio_ip; + switch_port_t remote_sdp_audio_port; }; typedef struct private_object private_t; +/*****************************************************************************/ +/* PROFILES FUNCTIONS */ +/*****************************************************************************/ +skinny_profile_t *skinny_find_profile(const char *profile_name); +switch_status_t skinny_profile_dump(const skinny_profile_t *profile, switch_stream_handle_t *stream); +switch_status_t skinny_profile_find_listener_by_device_name(skinny_profile_t *profile, const char *device_name, listener_t **listener); +switch_status_t skinny_profile_find_listener_by_device_name_and_instance(skinny_profile_t *profile, const char *device_name, uint32_t device_instance, listener_t **listener); +char * skinny_profile_find_session_uuid(skinny_profile_t *profile, listener_t *listener, uint32_t *line_instance_p, uint32_t call_id); +switch_core_session_t * skinny_profile_find_session(skinny_profile_t *profile, listener_t *listener, uint32_t *line_instance_p, uint32_t call_id); +switch_status_t dump_device(skinny_profile_t *profile, const char *device_name, switch_stream_handle_t *stream); + /*****************************************************************************/ /* SQL FUNCTIONS */ /*****************************************************************************/ void skinny_execute_sql(skinny_profile_t *profile, char *sql, switch_mutex_t *mutex); switch_bool_t skinny_execute_sql_callback(skinny_profile_t *profile, - switch_mutex_t *mutex, char *sql, switch_core_db_callback_func_t callback, void *pdata); + switch_mutex_t *mutex, char *sql, switch_core_db_callback_func_t callback, void *pdata); /*****************************************************************************/ /* LISTENER FUNCTIONS */ /*****************************************************************************/ +uint8_t listener_is_ready(listener_t *listener); switch_status_t keepalive_listener(listener_t *listener, void *pvt); /*****************************************************************************/ /* CHANNEL FUNCTIONS */ /*****************************************************************************/ -uint32_t skinny_line_perform_set_state(listener_t *listener, const char *file, const char *func, int line, uint32_t instance, uint32_t state, uint32_t call_id); -#define skinny_line_set_state(listener, instance, state, call_id) skinny_line_perform_set_state(listener, __FILE__, __SWITCH_FUNC__, __LINE__, instance, state, call_id) +void skinny_line_perform_set_state(const char *file, const char *func, int line, listener_t *listener, uint32_t line_instance, uint32_t call_id, uint32_t call_state); +#define skinny_line_set_state(listener, line_instance, call_id, call_state) skinny_line_perform_set_state(__FILE__, __SWITCH_FUNC__, __LINE__, listener, line_instance, call_id, call_state) -uint32_t skinny_line_get_state(listener_t *listener, uint32_t instance); +uint32_t skinny_line_get_state(listener_t *listener, uint32_t line_instance, uint32_t call_id); switch_status_t skinny_tech_set_codec(private_t *tech_pvt, int force); -void tech_init(private_t *tech_pvt, switch_core_session_t *session, listener_t *listener, uint32_t line); +void tech_init(private_t *tech_pvt, skinny_profile_t *profile, switch_core_session_t *session); switch_status_t channel_on_init(switch_core_session_t *session); switch_status_t channel_on_hangup(switch_core_session_t *session); switch_status_t channel_on_destroy(switch_core_session_t *session); @@ -211,8 +222,8 @@ switch_status_t channel_on_routing(switch_core_session_t *session); switch_status_t channel_on_exchange_media(switch_core_session_t *session); switch_status_t channel_on_soft_execute(switch_core_session_t *session); switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event, - switch_caller_profile_t *outbound_profile, - switch_core_session_t **new_session, switch_memory_pool_t **pool, switch_originate_flag_t flags, switch_call_cause_t *cancel_cause); + switch_caller_profile_t *outbound_profile, + switch_core_session_t **new_session, switch_memory_pool_t **pool, switch_originate_flag_t flags, switch_call_cause_t *cancel_cause); switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id); switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id); switch_status_t channel_kill_channel(switch_core_session_t *session, int sig); @@ -224,3 +235,14 @@ switch_endpoint_interface_t *skinny_get_endpoint_interface(); #endif /* _MOD_SKINNY_H */ +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4: + */ + diff --git a/src/mod/endpoints/mod_skinny/skinny_api.c b/src/mod/endpoints/mod_skinny/skinny_api.c new file mode 100644 index 0000000000..25ec6da702 --- /dev/null +++ b/src/mod/endpoints/mod_skinny/skinny_api.c @@ -0,0 +1,473 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2010, Mathieu Parent + * + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * + * The Initial Developer of the Original Code is + * Mathieu Parent + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Mathieu Parent + * + * + * skinny_api.c -- Skinny Call Control Protocol (SCCP) Endpoint Module + * + */ + +#include +#include "mod_skinny.h" +#include "skinny_protocol.h" +#include "skinny_tables.h" + +/*****************************************************************************/ +/* skinny_api_list_* */ +/*****************************************************************************/ + +static switch_status_t skinny_api_list_profiles(const char *line, const char *cursor, switch_console_callback_match_t **matches) +{ + switch_console_callback_match_t *my_matches = NULL; + switch_status_t status = SWITCH_STATUS_FALSE; + switch_hash_index_t *hi; + void *val; + skinny_profile_t *profile; + + /* walk profiles */ + switch_mutex_lock(globals.mutex); + for (hi = switch_hash_first(NULL, globals.profile_hash); hi; hi = switch_hash_next(hi)) { + switch_hash_this(hi, NULL, NULL, &val); + profile = (skinny_profile_t *) val; + + switch_console_push_match(&my_matches, profile->name); + } + switch_mutex_unlock(globals.mutex); + + if (my_matches) { + *matches = my_matches; + status = SWITCH_STATUS_SUCCESS; + } + + return status; +} + +struct match_helper { + switch_console_callback_match_t *my_matches; +}; + +static int skinny_api_list_devices_callback(void *pArg, int argc, char **argv, char **columnNames) +{ + struct match_helper *h = (struct match_helper *) pArg; + char *device_name = argv[0]; + + switch_console_push_match(&h->my_matches, device_name); + return 0; +} + +static switch_status_t skinny_api_list_devices(const char *line, const char *cursor, switch_console_callback_match_t **matches) +{ + struct match_helper h = { 0 }; + switch_status_t status = SWITCH_STATUS_FALSE; + skinny_profile_t *profile = NULL; + char *sql; + + char *myline; + char *argv[1024] = { 0 }; + int argc = 0; + + if (!(myline = strdup(line))) { + status = SWITCH_STATUS_MEMERR; + return status; + } + if (!(argc = switch_separate_string(myline, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) || argc != 5) { + return status; + } + + if(!strcasecmp(argv[1], "profile")) {/* skinny profile ... */ + profile = skinny_find_profile(argv[2]); + } else if(!strcasecmp(argv[2], "profile")) {/* skinny status profile ... */ + profile = skinny_find_profile(argv[3]); + } + + if(profile) { + if ((sql = switch_mprintf("SELECT name FROM skinny_devices"))) { + skinny_execute_sql_callback(profile, profile->sql_mutex, sql, skinny_api_list_devices_callback, &h); + switch_safe_free(sql); + } + } + + if (h.my_matches) { + *matches = h.my_matches; + status = SWITCH_STATUS_SUCCESS; + } + + return status; +} + +static switch_status_t skinny_api_list_reset_types(const char *line, const char *cursor, switch_console_callback_match_t **matches) +{ + switch_status_t status = SWITCH_STATUS_FALSE; + SKINNY_PUSH_DEVICE_RESET_TYPES + return status; +} + +static switch_status_t skinny_api_list_stimuli(const char *line, const char *cursor, switch_console_callback_match_t **matches) +{ + switch_status_t status = SWITCH_STATUS_FALSE; + SKINNY_PUSH_STIMULI + return status; +} + +static switch_status_t skinny_api_list_ring_types(const char *line, const char *cursor, switch_console_callback_match_t **matches) +{ + switch_status_t status = SWITCH_STATUS_FALSE; + SKINNY_PUSH_RING_TYPES + return status; +} + +static switch_status_t skinny_api_list_ring_modes(const char *line, const char *cursor, switch_console_callback_match_t **matches) +{ + switch_status_t status = SWITCH_STATUS_FALSE; + SKINNY_PUSH_RING_MODES + return status; +} + +static switch_status_t skinny_api_list_stimulus_instances(const char *line, const char *cursor, switch_console_callback_match_t **matches) +{ + switch_status_t status = SWITCH_STATUS_FALSE; + switch_console_callback_match_t *my_matches = NULL; + + switch_console_push_match(&my_matches, ""); + switch_console_push_match(&my_matches, "0"); + + if (my_matches) { + *matches = my_matches; + status = SWITCH_STATUS_SUCCESS; + } + return status; +} + +static switch_status_t skinny_api_list_stimulus_modes(const char *line, const char *cursor, switch_console_callback_match_t **matches) +{ + switch_status_t status = SWITCH_STATUS_FALSE; + SKINNY_PUSH_LAMP_MODES + return status; +} + +static switch_status_t skinny_api_list_speaker_modes(const char *line, const char *cursor, switch_console_callback_match_t **matches) +{ + switch_status_t status = SWITCH_STATUS_FALSE; + SKINNY_PUSH_SPEAKER_MODES + return status; +} + +static switch_status_t skinny_api_list_call_states(const char *line, const char *cursor, switch_console_callback_match_t **matches) +{ + switch_status_t status = SWITCH_STATUS_FALSE; + SKINNY_PUSH_CALL_STATES + return status; +} + +static switch_status_t skinny_api_list_line_instances(const char *line, const char *cursor, switch_console_callback_match_t **matches) +{ + switch_status_t status = SWITCH_STATUS_FALSE; + switch_console_callback_match_t *my_matches = NULL; + + /* TODO */ + switch_console_push_match(&my_matches, "1"); + switch_console_push_match(&my_matches, ""); + + if (my_matches) { + *matches = my_matches; + status = SWITCH_STATUS_SUCCESS; + } + return status; +} + +static switch_status_t skinny_api_list_call_ids(const char *line, const char *cursor, switch_console_callback_match_t **matches) +{ + switch_status_t status = SWITCH_STATUS_FALSE; + switch_console_callback_match_t *my_matches = NULL; + + /* TODO */ + switch_console_push_match(&my_matches, "1345"); + switch_console_push_match(&my_matches, ""); + + if (my_matches) { + *matches = my_matches; + status = SWITCH_STATUS_SUCCESS; + } + return status; +} + +/*****************************************************************************/ +/* skinny_api_cmd_* */ +/*****************************************************************************/ +static switch_status_t skinny_api_cmd_status_profile(const char *profile_name, switch_stream_handle_t *stream) +{ + skinny_profile_t *profile; + if ((profile = skinny_find_profile(profile_name))) { + skinny_profile_dump(profile, stream); + } else { + stream->write_function(stream, "Profile not found!\n"); + } + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t skinny_api_cmd_status_profile_device(const char *profile_name, const char *device_name, switch_stream_handle_t *stream) +{ + skinny_profile_t *profile; + if ((profile = skinny_find_profile(profile_name))) { + dump_device(profile, device_name, stream); + } else { + stream->write_function(stream, "Profile not found!\n"); + } + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t skinny_api_cmd_profile_device_send_ringer_message(const char *profile_name, const char *device_name, const char *ring_type, const char *ring_mode, switch_stream_handle_t *stream) +{ + skinny_profile_t *profile; + + if ((profile = skinny_find_profile(profile_name))) { + listener_t *listener = NULL; + skinny_profile_find_listener_by_device_name(profile, device_name, &listener); + if(listener) { + send_set_ringer(listener, skinny_str2ring_type(ring_type), skinny_str2ring_mode(ring_mode), 0, 0); + } else { + stream->write_function(stream, "Listener not found!\n"); + } + } else { + stream->write_function(stream, "Profile not found!\n"); + } + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t skinny_api_cmd_profile_device_send_lamp_message(const char *profile_name, const char *device_name, const char *stimulus, const char *instance, const char *lamp_mode, switch_stream_handle_t *stream) +{ + skinny_profile_t *profile; + + if ((profile = skinny_find_profile(profile_name))) { + listener_t *listener = NULL; + skinny_profile_find_listener_by_device_name(profile, device_name, &listener); + if(listener) { + send_set_lamp(listener, skinny_str2button(stimulus), atoi(instance), skinny_str2lamp_mode(lamp_mode)); + } else { + stream->write_function(stream, "Listener not found!\n"); + } + } else { + stream->write_function(stream, "Profile not found!\n"); + } + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t skinny_api_cmd_profile_device_send_speaker_mode_message(const char *profile_name, const char *device_name, const char *speaker_mode, switch_stream_handle_t *stream) +{ + skinny_profile_t *profile; + + if ((profile = skinny_find_profile(profile_name))) { + listener_t *listener = NULL; + skinny_profile_find_listener_by_device_name(profile, device_name, &listener); + if(listener) { + send_set_speaker_mode(listener, skinny_str2speaker_mode(speaker_mode)); + } else { + stream->write_function(stream, "Listener not found!\n"); + } + } else { + stream->write_function(stream, "Profile not found!\n"); + } + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t skinny_api_cmd_profile_device_send_call_state_message(const char *profile_name, const char *device_name, const char *call_state, const char *line_instance, const char *call_id, switch_stream_handle_t *stream) +{ + skinny_profile_t *profile; + + if ((profile = skinny_find_profile(profile_name))) { + listener_t *listener = NULL; + skinny_profile_find_listener_by_device_name(profile, device_name, &listener); + if(listener) { + send_call_state(listener, skinny_str2call_state(call_state), atoi(line_instance), atoi(call_id)); + } else { + stream->write_function(stream, "Listener not found!\n"); + } + } else { + stream->write_function(stream, "Profile not found!\n"); + } + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t skinny_api_cmd_profile_device_send_reset_message(const char *profile_name, const char *device_name, const char *reset_type, switch_stream_handle_t *stream) +{ + skinny_profile_t *profile; + + if ((profile = skinny_find_profile(profile_name))) { + listener_t *listener = NULL; + skinny_profile_find_listener_by_device_name(profile, device_name, &listener); + if(listener) { + send_reset(listener, skinny_str2device_reset_type(reset_type)); + } else { + stream->write_function(stream, "Listener not found!\n"); + } + } else { + stream->write_function(stream, "Profile not found!\n"); + } + + return SWITCH_STATUS_SUCCESS; +} + +/*****************************************************************************/ +/* API */ +/*****************************************************************************/ +SWITCH_STANDARD_API(skinny_function) +{ + char *argv[1024] = { 0 }; + int argc = 0; + char *mycmd = NULL; + switch_status_t status = SWITCH_STATUS_SUCCESS; + const char *usage_string = "USAGE:\n" + "--------------------------------------------------------------------------------\n" + "skinny help\n" + "skinny status profile \n" + "skinny status profile device \n" + "skinny profile device send ResetMessage [DeviceReset|DeviceRestart]\n" + "skinny profile device send SetRingerMessage \n" + "skinny profile device send SetLampMessage \n" + "skinny profile device send SetSpeakerModeMessage \n" + "skinny profile device send CallStateMessage \n" + "--------------------------------------------------------------------------------\n"; + if (session) { + return SWITCH_STATUS_FALSE; + } + + if (zstr(cmd)) { + stream->write_function(stream, "%s", usage_string); + goto done; + } + + if (!(mycmd = strdup(cmd))) { + status = SWITCH_STATUS_MEMERR; + goto done; + } + + if (!(argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) || !argv[0]) { + stream->write_function(stream, "%s", usage_string); + goto done; + } + + if (!strcasecmp(argv[0], "help")) {/* skinny help */ + stream->write_function(stream, "%s", usage_string); + goto done; + } else if (argc == 3 && !strcasecmp(argv[0], "status") && !strcasecmp(argv[1], "profile")) { + /* skinny status profile */ + status = skinny_api_cmd_status_profile(argv[2], stream); + } else if (argc == 5 && !strcasecmp(argv[0], "status") && !strcasecmp(argv[1], "profile") && !strcasecmp(argv[3], "device")) { + /* skinny status profile device */ + status = skinny_api_cmd_status_profile_device(argv[2], argv[4], stream); + } else if (argc >= 6 && !strcasecmp(argv[0], "profile") && !strcasecmp(argv[2], "device") && !strcasecmp(argv[4], "send")) { + /* skinny profile device send ... */ + switch(skinny_str2message_type(argv[5])) { + case SET_RINGER_MESSAGE: + if(argc == 8) { + /* SetRingerMessage */ + status = skinny_api_cmd_profile_device_send_ringer_message(argv[1], argv[3], argv[6], argv[7], stream); + } + break; + case SET_LAMP_MESSAGE: + if (argc == 9) { + /* SetLampMessage */ + status = skinny_api_cmd_profile_device_send_lamp_message(argv[1], argv[3], argv[6], argv[7], argv[8], stream); + } + break; + case SET_SPEAKER_MODE_MESSAGE: + if (argc == 7) { + /* SetSpeakerModeMessage */ + status = skinny_api_cmd_profile_device_send_speaker_mode_message(argv[1], argv[3], argv[6], stream); + } + break; + case CALL_STATE_MESSAGE: + if (argc == 9) { + /* CallStateMessage */ + status = skinny_api_cmd_profile_device_send_call_state_message(argv[1], argv[3], argv[6], argv[7], argv[8], stream); + } + break; + case RESET_MESSAGE: + if (argc == 7) { + /* ResetMessage */ + status = skinny_api_cmd_profile_device_send_reset_message(argv[1], argv[3], argv[6], stream); + } + break; + default: + stream->write_function(stream, "Unhandled message %s\n", argv[5]); + } + } else { + stream->write_function(stream, "Unknown Command [%s]\n", argv[0]); + } + +done: + switch_safe_free(mycmd); + return status; +} + +switch_status_t skinny_api_register(switch_loadable_module_interface_t **module_interface) +{ + switch_api_interface_t *api_interface; + + SWITCH_ADD_API(api_interface, "skinny", "Skinny Controls", skinny_function, " "); + switch_console_set_complete("add skinny help"); + + switch_console_set_complete("add skinny status profile ::skinny::list_profiles"); + switch_console_set_complete("add skinny status profile ::skinny::list_profiles device ::skinny::list_devices"); + + switch_console_set_complete("add skinny profile ::skinny::list_profiles device ::skinny::list_devices send ResetMessage ::skinny::list_reset_types"); + switch_console_set_complete("add skinny profile ::skinny::list_profiles device ::skinny::list_devices send SetRingerMessage ::skinny::list_ring_types ::skinny::list_ring_modes"); + switch_console_set_complete("add skinny profile ::skinny::list_profiles device ::skinny::list_devices send SetLampMessage ::skinny::list_stimuli ::skinny::list_stimulus_instances ::skinny::list_stimulus_modes"); + switch_console_set_complete("add skinny profile ::skinny::list_profiles device ::skinny::list_devices send SetSpeakerModeMessage ::skinny::list_speaker_modes"); + switch_console_set_complete("add skinny profile ::skinny::list_profiles device ::skinny::list_devices send CallStateMessage ::skinny::list_call_states ::skinny::list_line_instances ::skinny::list_call_ids"); + + switch_console_add_complete_func("::skinny::list_profiles", skinny_api_list_profiles); + switch_console_add_complete_func("::skinny::list_devices", skinny_api_list_devices); + switch_console_add_complete_func("::skinny::list_reset_types", skinny_api_list_reset_types); + switch_console_add_complete_func("::skinny::list_ring_types", skinny_api_list_ring_types); + switch_console_add_complete_func("::skinny::list_ring_modes", skinny_api_list_ring_modes); + switch_console_add_complete_func("::skinny::list_stimuli", skinny_api_list_stimuli); + switch_console_add_complete_func("::skinny::list_stimulus_instances", skinny_api_list_stimulus_instances); + switch_console_add_complete_func("::skinny::list_stimulus_modes", skinny_api_list_stimulus_modes); + switch_console_add_complete_func("::skinny::list_speaker_modes", skinny_api_list_speaker_modes); + switch_console_add_complete_func("::skinny::list_call_states", skinny_api_list_call_states); + switch_console_add_complete_func("::skinny::list_line_instances", skinny_api_list_line_instances); + switch_console_add_complete_func("::skinny::list_call_ids", skinny_api_list_call_ids); + return SWITCH_STATUS_SUCCESS; +} + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4: + */ + diff --git a/src/mod/endpoints/mod_skinny/skinny_api.h b/src/mod/endpoints/mod_skinny/skinny_api.h new file mode 100644 index 0000000000..fc405c2515 --- /dev/null +++ b/src/mod/endpoints/mod_skinny/skinny_api.h @@ -0,0 +1,50 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2010, Mathieu Parent + * + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * + * The Initial Developer of the Original Code is + * Mathieu Parent + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Mathieu Parent + * + * + * skinny_api.h -- Skinny Call Control Protocol (SCCP) Endpoint Module + * + */ + +#ifndef _SKINNY_API_H +#define _SKINNY_API_H + +switch_status_t skinny_api_register(switch_loadable_module_interface_t **module_interface); + +#endif /* _SKINNY_API_H */ + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4: + */ + diff --git a/src/mod/endpoints/mod_skinny/skinny_protocol.c b/src/mod/endpoints/mod_skinny/skinny_protocol.c index a7438c05cc..533a922f32 100644 --- a/src/mod/endpoints/mod_skinny/skinny_protocol.c +++ b/src/mod/endpoints/mod_skinny/skinny_protocol.c @@ -141,14 +141,14 @@ switch_status_t skinny_read_packet(listener_t *listener, skinny_message_t **req) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to allocate memory.\n"); return SWITCH_STATUS_MEMERR; } - - if (!globals.running) { + + if (!listener_is_ready(listener)) { return SWITCH_STATUS_FALSE; } ptr = mbuf; - while (listener->sock && globals.running) { + while (listener_is_ready(listener)) { uint8_t do_sleep = 1; if(bytes < SKINNY_MESSAGE_FIELD_SIZE) { /* We have nothing yet, get length header field */ @@ -159,15 +159,15 @@ switch_status_t skinny_read_packet(listener_t *listener, skinny_message_t **req) } status = switch_socket_recv(listener->sock, ptr, &mlen); - - if (!globals.running || (!SWITCH_STATUS_IS_BREAK(status) && status != SWITCH_STATUS_SUCCESS)) { + + if (!listener_is_ready(listener) || (!SWITCH_STATUS_IS_BREAK(status) && status != SWITCH_STATUS_SUCCESS)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Socket break.\n"); return SWITCH_STATUS_FALSE; } - + if(mlen) { bytes += mlen; - + if(bytes >= SKINNY_MESSAGE_FIELD_SIZE) { do_sleep = 0; ptr += mlen; @@ -218,23 +218,25 @@ int skinny_device_event_callback(void *pArg, int argc, char **argv, char **colum { switch_event_t *event = (switch_event_t *) pArg; - char *device_name = argv[0]; - char *user_id = argv[1]; - char *instance = argv[2]; - char *ip = argv[3]; - char *device_type = argv[4]; - char *max_streams = argv[5]; - char *port = argv[6]; - char *codec_string = argv[7]; + char *profile_name = argv[0]; + char *device_name = argv[1]; + char *user_id = argv[2]; + char *device_instance = argv[3]; + char *ip = argv[4]; + char *device_type = argv[5]; + char *max_streams = argv[6]; + char *port = argv[7]; + char *codec_string = argv[8]; - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Skinny-Device-Name", device_name); - switch_event_add_header( event, SWITCH_STACK_BOTTOM, "Skinny-User-Id", "%s", user_id); - switch_event_add_header( event, SWITCH_STACK_BOTTOM, "Skinny-Instance", "%s", instance); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Skinny-IP", ip); - switch_event_add_header( event, SWITCH_STACK_BOTTOM, "Skinny-Device-Type", "%s", device_type); - switch_event_add_header( event, SWITCH_STACK_BOTTOM, "Skinny-Max-Streams", "%s", max_streams); - switch_event_add_header( event, SWITCH_STACK_BOTTOM, "Skinny-Port", "%s", port); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Skinny-Codecs", codec_string); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-Profile-Name", "%s", profile_name); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-Device-Name", "%s", device_name); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-Station-User-Id", "%s", user_id); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-Station-Instance", "%s", device_instance); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-IP-Address", "%s", ip); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-Device-Type", "%s", device_type); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-Max-Streams", "%s", max_streams); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-Port", "%s", port); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-Codecs", "%s", codec_string); return 0; } @@ -249,8 +251,12 @@ switch_status_t skinny_device_event(listener_t *listener, switch_event_t **ev, s switch_event_create_subclass(&event, event_id, subclass_name); switch_assert(event); - if ((sql = switch_mprintf("SELECT * FROM skinny_devices WHERE name='%s' AND instance=%d", listener->device_name, listener->device_instance))) { - skinny_execute_sql_callback(profile, profile->listener_mutex, sql, skinny_device_event_callback, event); + if ((sql = switch_mprintf("SELECT '%s', name, user_id, instance, ip, type, max_streams, port, codec_string " + "FROM skinny_devices " + "WHERE name='%s' AND instance=%d", + listener->profile->name, + listener->device_name, listener->device_instance))) { + skinny_execute_sql_callback(profile, profile->sql_mutex, sql, skinny_device_event_callback, event); switch_safe_free(sql); } @@ -259,30 +265,30 @@ switch_status_t skinny_device_event(listener_t *listener, switch_event_t **ev, s } /*****************************************************************************/ -switch_status_t skinny_send_call_info(switch_core_session_t *session) +switch_status_t skinny_send_call_info(switch_core_session_t *session, listener_t *listener, uint32_t line_instance) { private_t *tech_pvt; switch_channel_t *channel; - listener_t *listener; - + char calling_party_name[40] = "UNKNOWN"; char calling_party[24] = "0000000000"; char called_party_name[40] = "UNKNOWN"; char called_party[24] = "0000000000"; - - tech_pvt = switch_core_session_get_private(session); - switch_assert(tech_pvt != NULL); - channel = switch_core_session_get_channel(session); - switch_assert(channel != NULL); - listener = tech_pvt->listener; - switch_assert(listener != NULL); + channel = switch_core_session_get_channel(session); + tech_pvt = switch_core_session_get_private(session); switch_assert(tech_pvt->caller_profile != NULL); - + if( switch_channel_test_flag(channel, CF_OUTBOUND) ) { - strncpy(calling_party_name, tech_pvt->line_displayname, 40); - strncpy(calling_party, tech_pvt->line_name, 24); + struct line_stat_res_message *button = NULL; + + skinny_line_get(listener, line_instance, &button); + + if (button) { + strncpy(calling_party_name, button->displayname, 40); + strncpy(calling_party, button->name, 24); + } strncpy(called_party_name, tech_pvt->caller_profile->caller_id_name, 40); strncpy(called_party, tech_pvt->caller_profile->caller_id_number, 24); } else { @@ -290,12 +296,12 @@ switch_status_t skinny_send_call_info(switch_core_session_t *session) strncpy(calling_party, tech_pvt->caller_profile->caller_id_number, 24); /* TODO called party */ } - send_call_info(tech_pvt->listener, + send_call_info(listener, calling_party_name, /* char calling_party_name[40], */ calling_party, /* char calling_party[24], */ called_party_name, /* char called_party_name[40], */ called_party, /* char called_party[24], */ - tech_pvt->line, /* uint32_t line_instance, */ + line_instance, /* uint32_t line_instance, */ tech_pvt->call_id, /* uint32_t call_id, */ SKINNY_OUTBOUND_CALL, /* uint32_t call_type, */ "", /* TODO char original_called_party_name[40], */ @@ -316,169 +322,429 @@ switch_status_t skinny_send_call_info(switch_core_session_t *session) } /*****************************************************************************/ -switch_status_t skinny_create_session(listener_t *listener, uint32_t line, uint32_t to_state) +switch_status_t skinny_session_walk_lines(skinny_profile_t *profile, char *channel_uuid, switch_core_db_callback_func_t callback, void *data) { - switch_core_session_t *session; + char *sql; + if ((sql = switch_mprintf( + "SELECT skinny_lines.*, channel_uuid, call_id, call_state " + "FROM skinny_active_lines " + "INNER JOIN skinny_lines " + "ON skinny_active_lines.device_name = skinny_lines.device_name " + "AND skinny_active_lines.device_instance = skinny_lines.device_instance " + "AND skinny_active_lines.line_instance = skinny_lines.line_instance " + "WHERE channel_uuid='%s'", + channel_uuid))) { + skinny_execute_sql_callback(profile, profile->sql_mutex, sql, callback, data); + switch_safe_free(sql); + } + return SWITCH_STATUS_SUCCESS; +} + +switch_status_t skinny_session_walk_lines_by_call_id(skinny_profile_t *profile, uint32_t call_id, switch_core_db_callback_func_t callback, void *data) +{ + char *sql; + if ((sql = switch_mprintf( + "SELECT skinny_lines.*, channel_uuid, call_id, call_state " + "FROM skinny_active_lines " + "INNER JOIN skinny_lines " + "ON skinny_active_lines.device_name = skinny_lines.device_name " + "AND skinny_active_lines.device_instance = skinny_lines.device_instance " + "AND skinny_active_lines.line_instance = skinny_lines.line_instance " + "WHERE call_id='%d'", + call_id))) { + skinny_execute_sql_callback(profile, profile->sql_mutex, sql, callback, data); + switch_safe_free(sql); + } + return SWITCH_STATUS_SUCCESS; +} + +/*****************************************************************************/ +struct skinny_ring_lines_helper { + private_t *tech_pvt; + uint32_t lines_count; +}; + +int skinny_ring_lines_callback(void *pArg, int argc, char **argv, char **columnNames) +{ + struct skinny_ring_lines_helper *helper = pArg; + char *tmp; + + char *device_name = argv[0]; + uint32_t device_instance = atoi(argv[1]); + /* uint32_t position = atoi(argv[2]); */ + uint32_t line_instance = atoi(argv[3]); + /* char *label = argv[4]; */ + /* char *value = argv[5]; */ + /* char *caller_name = argv[6]; */ + /* uint32_t ring_on_idle = atoi(argv[7]); */ + /* uint32_t ring_on_active = atoi(argv[8]); */ + /* uint32_t busy_trigger = atoi(argv[9]); */ + /* char *forward_all = argv[10]; */ + /* char *forward_busy = argv[11]; */ + /* char *forward_noanswer = argv[12]; */ + /* uint32_t noanswer_duration = atoi(argv[13]); */ + /* char *channel_uuid = argv[14]; */ + /* uint32_t call_id = atoi(argv[15]); */ + /* uint32_t call_state = atoi(argv[16]); */ + + listener_t *listener = NULL; + + skinny_profile_find_listener_by_device_name_and_instance(helper->tech_pvt->profile, + device_name, device_instance, &listener); + if(listener) { + helper->lines_count++; + skinny_line_set_state(listener, line_instance, helper->tech_pvt->call_id, SKINNY_RING_IN); + send_select_soft_keys(listener, line_instance, helper->tech_pvt->call_id, SKINNY_KEY_SET_RING_IN, 0xffff); + if ((tmp = switch_mprintf("\200\027%s", helper->tech_pvt->caller_profile->destination_number))) { + send_display_prompt_status(listener, 0, tmp, line_instance, helper->tech_pvt->call_id); + switch_safe_free(tmp); + } + if ((tmp = switch_mprintf("\005\000\000\000%s", helper->tech_pvt->caller_profile->destination_number))) { + send_display_pri_notify(listener, 10 /* message_timeout */, 5 /* priority */, tmp); + switch_safe_free(tmp); + } + skinny_send_call_info(helper->tech_pvt->session, listener, line_instance); + send_set_lamp(listener, SKINNY_BUTTON_LINE, line_instance, SKINNY_LAMP_BLINK); + send_set_ringer(listener, SKINNY_RING_INSIDE, SKINNY_RING_FOREVER, 0, helper->tech_pvt->call_id); + } + return 0; +} + +switch_call_cause_t skinny_ring_lines(private_t *tech_pvt) +{ + switch_status_t status; + struct skinny_ring_lines_helper helper = {0}; + + switch_assert(tech_pvt); + switch_assert(tech_pvt->profile); + switch_assert(tech_pvt->session); + + helper.tech_pvt = tech_pvt; + helper.lines_count = 0; + + status = skinny_session_walk_lines(tech_pvt->profile, + switch_core_session_get_uuid(tech_pvt->session), skinny_ring_lines_callback, &helper); + if(status != SWITCH_STATUS_SUCCESS) { + return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; + } else if(helper.lines_count == 0) { + return SWITCH_CAUSE_UNALLOCATED_NUMBER; + } else { + return SWITCH_CAUSE_SUCCESS; + } +} + +/*****************************************************************************/ +switch_status_t skinny_create_ingoing_session(listener_t *listener, uint32_t *line_instance_p, switch_core_session_t **session) +{ + uint32_t line_instance; + switch_core_session_t *nsession; switch_channel_t *channel; private_t *tech_pvt; char name[128]; + char *sql; + struct line_stat_res_message *button = NULL; - if(listener->session[line]) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "There is already a session on line %d of device %s\n", - line, listener->device_name); - - session = listener->session[line]; - - channel = switch_core_session_get_channel(session); - assert(channel != NULL); - - tech_pvt = switch_core_session_get_private(session); - assert(tech_pvt != NULL); - } else { - - if (!(session = switch_core_session_request(skinny_get_endpoint_interface(), SWITCH_CALL_DIRECTION_INBOUND, NULL))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error Creating Session\n"); - goto error; - } - - if (!(tech_pvt = (struct private_object *) switch_core_session_alloc(session, sizeof(*tech_pvt)))) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Error Creating Session private object\n"); - goto error; - } - - switch_core_session_add_stream(session, NULL); - - tech_init(tech_pvt, session, listener, line); - - channel = switch_core_session_get_channel(session); - - snprintf(name, sizeof(name), "SKINNY/%s/%s:%d/%d", listener->profile->name, listener->device_name, listener->device_instance, tech_pvt->line); - switch_channel_set_name(channel, name); - - if (switch_core_session_thread_launch(session) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Error Creating Session thread\n"); - goto error; - } - - if (!(tech_pvt->caller_profile = switch_caller_profile_new(switch_core_session_get_pool(session), - NULL, listener->profile->dialplan, tech_pvt->line_displayname, tech_pvt->line_name, listener->remote_ip, NULL, NULL, NULL, "skinny" /* modname */, listener->profile->context, tech_pvt->dest)) != 0) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Error Creating Session caller profile\n"); - goto error; - } - - switch_channel_set_caller_profile(channel, tech_pvt->caller_profile); - + line_instance = *line_instance_p; + if((nsession = skinny_profile_find_session(listener->profile, listener, line_instance_p, 0))) { + switch_core_session_rwunlock(nsession); + if(skinny_line_get_state(listener, *line_instance_p, 0) == SKINNY_OFF_HOOK) { + /* Reuse existing session */ + *session = nsession; + return SWITCH_STATUS_SUCCESS; + } + skinny_session_hold_line(nsession, listener, *line_instance_p); } - - set_ringer(listener, SKINNY_RING_OFF, SKINNY_RING_FOREVER, 0); - set_speaker_mode(listener, SKINNY_SPEAKER_ON); - set_lamp(listener, SKINNY_BUTTON_LINE, tech_pvt->line, SKINNY_LAMP_ON); - send_call_state(listener, - SKINNY_OFF_HOOK, - tech_pvt->line, - tech_pvt->call_id); - skinny_line_set_state(listener, tech_pvt->line, to_state, tech_pvt->call_id); - display_prompt_status(listener, - 0, - "\200\000", - tech_pvt->line, - tech_pvt->call_id); - activate_call_plane(listener, tech_pvt->line); - start_tone(listener, SKINNY_TONE_DIALTONE, 0, tech_pvt->line, tech_pvt->call_id); + *line_instance_p = line_instance; + if(*line_instance_p == 0) { + *line_instance_p = 1; + } + + skinny_line_get(listener, *line_instance_p, &button); + + if (!button || !button->shortname) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Line %d not found on device %s %d\n", + *line_instance_p, listener->device_name, listener->device_instance); + goto error; + } + + if (!(nsession = switch_core_session_request(skinny_get_endpoint_interface(), + SWITCH_CALL_DIRECTION_INBOUND, NULL))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error Creating Session\n"); + goto error; + } + + if (!(tech_pvt = (struct private_object *) switch_core_session_alloc(nsession, sizeof(*tech_pvt)))) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(nsession), SWITCH_LOG_CRIT, + "Error Creating Session private object\n"); + goto error; + } + + switch_core_session_add_stream(nsession, NULL); + + tech_init(tech_pvt, listener->profile, nsession); + + channel = switch_core_session_get_channel(nsession); + + snprintf(name, sizeof(name), "SKINNY/%s/%s:%d/%d", listener->profile->name, + listener->device_name, listener->device_instance, *line_instance_p); + switch_channel_set_name(channel, name); + + if (switch_core_session_thread_launch(nsession) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(nsession), SWITCH_LOG_CRIT, + "Error Creating Session thread\n"); + goto error; + } + + if (!(tech_pvt->caller_profile = switch_caller_profile_new(switch_core_session_get_pool(nsession), + NULL, listener->profile->dialplan, + button->shortname, button->name, + listener->remote_ip, NULL, NULL, NULL, + "skinny" /* modname */, + listener->profile->context, + "")) != 0) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(nsession), SWITCH_LOG_CRIT, + "Error Creating Session caller profile\n"); + goto error; + } + + switch_channel_set_caller_profile(channel, tech_pvt->caller_profile); + + if ((sql = switch_mprintf( + "INSERT INTO skinny_active_lines " + "(device_name, device_instance, line_instance, channel_uuid, call_id, call_state) " + "SELECT device_name, device_instance, line_instance, '%s', %d, %d " + "FROM skinny_lines " + "WHERE value='%s'", + switch_core_session_get_uuid(nsession), tech_pvt->call_id, SKINNY_ON_HOOK, button->shortname + ))) { + skinny_execute_sql(listener->profile, sql, listener->profile->sql_mutex); + switch_safe_free(sql); + } + + send_set_ringer(listener, SKINNY_RING_OFF, SKINNY_RING_FOREVER, 0, tech_pvt->call_id); + send_set_speaker_mode(listener, SKINNY_SPEAKER_ON); + send_set_lamp(listener, SKINNY_BUTTON_LINE, *line_instance_p, SKINNY_LAMP_ON); + skinny_line_set_state(listener, *line_instance_p, tech_pvt->call_id, SKINNY_OFF_HOOK); + send_select_soft_keys(listener, *line_instance_p, tech_pvt->call_id, SKINNY_KEY_SET_OFF_HOOK, 0xffff); + send_display_prompt_status(listener, 0, "\200\000", + *line_instance_p, tech_pvt->call_id); + send_activate_call_plane(listener, *line_instance_p); goto done; error: - if (session) { - switch_core_session_destroy(&session); + if (nsession) { + switch_core_session_destroy(&nsession); } return SWITCH_STATUS_FALSE; done: - listener->session[line] = session; + *session = nsession; return SWITCH_STATUS_SUCCESS; } -switch_status_t skinny_process_dest(listener_t *listener, uint32_t line) +switch_status_t skinny_session_process_dest(switch_core_session_t *session, listener_t *listener, uint32_t line_instance, char *dest, char append_dest, uint32_t backspace) { switch_channel_t *channel = NULL; private_t *tech_pvt = NULL; - channel = switch_core_session_get_channel(listener->session[line]); - assert(channel != NULL); + switch_assert(session); + switch_assert(listener); + switch_assert(listener->profile); + + channel = switch_core_session_get_channel(session); + tech_pvt = switch_core_session_get_private(session); - tech_pvt = switch_core_session_get_private(listener->session[line]); - assert(tech_pvt != NULL); - - tech_pvt->caller_profile->destination_number = switch_core_strdup(tech_pvt->caller_profile->pool, tech_pvt->dest); - if(strlen(tech_pvt->dest) >= 4) { /* TODO Number is complete -> check against dialplan */ - if (switch_channel_get_state(channel) == CS_NEW) { - switch_channel_set_state(channel, CS_INIT); - } - - send_dialed_number(listener, tech_pvt->dest, tech_pvt->line, tech_pvt->call_id); - skinny_answer(listener->session[line]); + if(!dest) { + if(append_dest == '\0') {/* no digit yet */ + send_start_tone(listener, SKINNY_TONE_DIALTONE, 0, line_instance, tech_pvt->call_id); + } else { + if(strlen(tech_pvt->caller_profile->destination_number) == 0) {/* first digit */ + send_stop_tone(listener, line_instance, tech_pvt->call_id); + send_select_soft_keys(listener, line_instance, tech_pvt->call_id, + SKINNY_KEY_SET_DIGITS_AFTER_DIALING_FIRST_DIGIT, 0xffff); + } + tech_pvt->caller_profile->destination_number = switch_core_sprintf(tech_pvt->caller_profile->pool, + "%s%c", tech_pvt->caller_profile->destination_number, append_dest); + } + } else { + tech_pvt->caller_profile->destination_number = switch_core_strdup(tech_pvt->caller_profile->pool, + dest); } + /* TODO Number is complete -> check against dialplan */ + if((strlen(tech_pvt->caller_profile->destination_number) >= 4) || dest) { + send_dialed_number(listener, tech_pvt->caller_profile->destination_number, line_instance, tech_pvt->call_id); + skinny_line_set_state(listener, line_instance, tech_pvt->call_id, SKINNY_PROCEED); + skinny_send_call_info(session, listener, line_instance); + skinny_session_start_media(session, listener, line_instance); + } + + switch_core_session_rwunlock(session); + return SWITCH_STATUS_SUCCESS; } -switch_status_t skinny_answer(switch_core_session_t *session) +switch_status_t skinny_session_ring_out(switch_core_session_t *session, listener_t *listener, uint32_t line_instance) { + switch_channel_t *channel = NULL; + private_t *tech_pvt = NULL; + + switch_assert(session); + switch_assert(listener); + switch_assert(listener->profile); + + channel = switch_core_session_get_channel(session); + tech_pvt = switch_core_session_get_private(session); + + skinny_line_set_state(listener, line_instance, tech_pvt->call_id, SKINNY_RING_OUT); + send_select_soft_keys(listener, line_instance, tech_pvt->call_id, + SKINNY_KEY_SET_RING_OUT, 0xffff); + send_display_prompt_status(listener, 0, "\200\026", + line_instance, tech_pvt->call_id); + skinny_send_call_info(session, listener, line_instance); + + switch_core_session_rwunlock(session); + + return SWITCH_STATUS_SUCCESS; +} + + +struct skinny_session_answer_helper { private_t *tech_pvt; listener_t *listener; - - tech_pvt = switch_core_session_get_private(session); - switch_assert(tech_pvt != NULL); - - listener = tech_pvt->listener; - switch_assert(listener != NULL); + uint32_t line_instance; +}; + +int skinny_session_answer_callback(void *pArg, int argc, char **argv, char **columnNames) +{ + struct skinny_session_answer_helper *helper = pArg; + listener_t *listener = NULL; + + char *device_name = argv[0]; + uint32_t device_instance = atoi(argv[1]); + /* uint32_t position = atoi(argv[2]); */ + uint32_t line_instance = atoi(argv[3]); + /* char *label = argv[4]; */ + /* char *value = argv[5]; */ + /* char *caller_name = argv[6]; */ + /* uint32_t ring_on_idle = atoi(argv[7]); */ + /* uint32_t ring_on_active = atoi(argv[8]); */ + /* uint32_t busy_trigger = atoi(argv[9]); */ + /* char *forward_all = argv[10]; */ + /* char *forward_busy = argv[11]; */ + /* char *forward_noanswer = argv[12]; */ + /* uint32_t noanswer_duration = atoi(argv[13]); */ + /* char *channel_uuid = argv[14]; */ + /* uint32_t call_id = atoi(argv[15]); */ + /* uint32_t call_state = atoi(argv[16]); */ + + skinny_profile_find_listener_by_device_name_and_instance(helper->tech_pvt->profile, device_name, device_instance, &listener); + if(listener) { + if(!strcmp(device_name, helper->listener->device_name) + && (device_instance == helper->listener->device_instance) + && (line_instance == helper->line_instance)) {/* the answering line */ + + + send_set_ringer(listener, SKINNY_RING_OFF, SKINNY_RING_FOREVER, 0, helper->tech_pvt->call_id); + send_set_speaker_mode(listener, SKINNY_SPEAKER_ON); + send_set_lamp(listener, SKINNY_BUTTON_LINE, line_instance, SKINNY_LAMP_ON); + skinny_line_set_state(listener, line_instance, helper->tech_pvt->call_id, SKINNY_OFF_HOOK); + /* send_select_soft_keys(listener, line_instance, helper->tech_pvt->call_id, SKINNY_KEY_SET_OFF_HOOK, 0xffff); */ + /* display_prompt_status(listener, 0, "\200\000", + line_instance, tech_pvt->call_id); */ + send_activate_call_plane(listener, line_instance); + } + } + return 0; +} + +switch_status_t skinny_session_answer(switch_core_session_t *session, listener_t *listener, uint32_t line_instance) +{ + struct skinny_session_answer_helper helper = {0}; + switch_channel_t *channel = NULL; + private_t *tech_pvt = NULL; + + switch_assert(session); + switch_assert(listener); + switch_assert(listener->profile); + + channel = switch_core_session_get_channel(session); + tech_pvt = switch_core_session_get_private(session); + + helper.tech_pvt = tech_pvt; + helper.listener = listener; + helper.line_instance = line_instance; + + skinny_session_walk_lines(tech_pvt->profile, switch_core_session_get_uuid(session), skinny_session_answer_callback, &helper); + + skinny_session_start_media(session, listener, line_instance); + + switch_core_session_rwunlock(session); - set_ringer(listener, SKINNY_RING_OFF, SKINNY_RING_FOREVER, 0); /* TODO : here ? */ - stop_tone(listener, tech_pvt->line, tech_pvt->call_id); - open_receive_channel(listener, - tech_pvt->call_id, /* uint32_t conference_id, */ - 0, /* uint32_t pass_thru_party_id, */ - 20, /* uint32_t packets, */ - SKINNY_CODEC_ULAW_64K, /* uint32_t payload_capacity, */ - 0, /* uint32_t echo_cancel_type, */ - 0, /* uint32_t g723_bitrate, */ - 0, /* uint32_t conference_id2, */ - 0 /* uint32_t reserved[10] */ - ); - send_call_state(listener, - SKINNY_CONNECTED, - tech_pvt->line, - tech_pvt->call_id); - skinny_line_set_state(listener, tech_pvt->line, SKINNY_KEY_SET_CONNECTED, tech_pvt->call_id); - display_prompt_status(listener, - 0, - "\200\030", - tech_pvt->line, - tech_pvt->call_id); - skinny_send_call_info(session); return SWITCH_STATUS_SUCCESS; } -switch_status_t skinny_hold_line(listener_t *listener, uint32_t line) +switch_status_t skinny_session_start_media(switch_core_session_t *session, listener_t *listener, uint32_t line_instance) { switch_channel_t *channel = NULL; private_t *tech_pvt = NULL; - channel = switch_core_session_get_channel(listener->session[line]); - assert(channel != NULL); + switch_assert(session); + switch_assert(listener); + switch_assert(listener->profile); + + channel = switch_core_session_get_channel(session); + tech_pvt = switch_core_session_get_private(session); + + send_stop_tone(listener, line_instance, tech_pvt->call_id); + send_open_receive_channel(listener, + tech_pvt->call_id, /* uint32_t conference_id, */ + tech_pvt->call_id, /* uint32_t pass_thru_party_id, */ + 20, /* uint32_t packets, */ + SKINNY_CODEC_ULAW_64K, /* uint32_t payload_capacity, */ + 0, /* uint32_t echo_cancel_type, */ + 0, /* uint32_t g723_bitrate, */ + 0, /* uint32_t conference_id2, */ + 0 /* uint32_t reserved[10] */ + ); + skinny_line_set_state(listener, line_instance, tech_pvt->call_id, SKINNY_CONNECTED); + send_select_soft_keys(listener, line_instance, tech_pvt->call_id, + SKINNY_KEY_SET_CONNECTED, 0xffff); + send_display_prompt_status(listener, + 0, + "\200\030", + line_instance, + tech_pvt->call_id); + skinny_send_call_info(session, listener, line_instance); - tech_pvt = switch_core_session_get_private(listener->session[line]); - assert(tech_pvt != NULL); + switch_core_session_rwunlock(session); + + return SWITCH_STATUS_SUCCESS; +} + +switch_status_t skinny_session_hold_line(switch_core_session_t *session, listener_t *listener, uint32_t line_instance) +{ + switch_channel_t *channel = NULL; + private_t *tech_pvt = NULL; + + switch_assert(session); + switch_assert(listener); + switch_assert(listener->profile); + + channel = switch_core_session_get_channel(session); + tech_pvt = switch_core_session_get_private(session); /* TODO */ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Hold is not implemented yet. Hanging up the line.\n"); switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING); + switch_core_session_rwunlock(session); + return SWITCH_STATUS_SUCCESS; } -switch_status_t skinny_unhold_line(listener_t *listener, uint32_t line) +switch_status_t skinny_session_unhold_line(switch_core_session_t *session, listener_t *listener, uint32_t line_instance) { /* TODO */ return SWITCH_STATUS_SUCCESS; @@ -516,7 +782,7 @@ void skinny_line_get(listener_t *listener, uint32_t instance, struct line_stat_r switch_assert(listener->device_name); helper.button = switch_core_alloc(listener->pool, sizeof(struct line_stat_res_message)); - + if ((sql = switch_mprintf( "SELECT '%d' AS wanted_position, position, label, value, caller_name " "FROM skinny_lines " @@ -525,7 +791,7 @@ void skinny_line_get(listener_t *listener, uint32_t instance, struct line_stat_r instance, listener->device_name, listener->device_instance ))) { - skinny_execute_sql_callback(listener->profile, listener->profile->listener_mutex, sql, skinny_line_get_callback, &helper); + skinny_execute_sql_callback(listener->profile, listener->profile->sql_mutex, sql, skinny_line_get_callback, &helper); switch_safe_free(sql); } *button = helper.button; @@ -559,7 +825,7 @@ void skinny_speed_dial_get(listener_t *listener, uint32_t instance, struct speed switch_assert(listener->device_name); helper.button = switch_core_alloc(listener->pool, sizeof(struct speed_dial_stat_res_message)); - + if ((sql = switch_mprintf( "SELECT '%d' AS wanted_position, position, label, value, settings " "FROM skinny_buttons " @@ -569,7 +835,7 @@ void skinny_speed_dial_get(listener_t *listener, uint32_t instance, struct speed listener->device_name, listener->device_instance, SKINNY_BUTTON_SPEED_DIAL ))) { - skinny_execute_sql_callback(listener->profile, listener->profile->listener_mutex, sql, skinny_speed_dial_get_callback, &helper); + skinny_execute_sql_callback(listener->profile, listener->profile->sql_mutex, sql, skinny_speed_dial_get_callback, &helper); switch_safe_free(sql); } *button = helper.button; @@ -603,7 +869,7 @@ void skinny_service_url_get(listener_t *listener, uint32_t instance, struct serv switch_assert(listener->device_name); helper.button = switch_core_alloc(listener->pool, sizeof(struct service_url_stat_res_message)); - + if ((sql = switch_mprintf( "SELECT '%d' AS wanted_position, position, label, value, settings " "FROM skinny_buttons " @@ -614,7 +880,7 @@ void skinny_service_url_get(listener_t *listener, uint32_t instance, struct serv listener->device_instance, SKINNY_BUTTON_SERVICE_URL ))) { - skinny_execute_sql_callback(listener->profile, listener->profile->listener_mutex, sql, skinny_service_url_get_callback, &helper); + skinny_execute_sql_callback(listener->profile, listener->profile->sql_mutex, sql, skinny_service_url_get_callback, &helper); switch_safe_free(sql); } *button = helper.button; @@ -649,7 +915,7 @@ void skinny_feature_get(listener_t *listener, uint32_t instance, struct feature_ switch_assert(listener->device_name); helper.button = switch_core_alloc(listener->pool, sizeof(struct feature_stat_res_message)); - + if ((sql = switch_mprintf( "SELECT '%d' AS wanted_position, position, label, value, settings " "FROM skinny_buttons " @@ -660,7 +926,7 @@ void skinny_feature_get(listener_t *listener, uint32_t instance, struct feature_ listener->device_instance, SKINNY_BUTTON_SPEED_DIAL, SKINNY_BUTTON_SERVICE_URL ))) { - skinny_execute_sql_callback(listener->profile, listener->profile->listener_mutex, sql, skinny_feature_get_callback, &helper); + skinny_execute_sql_callback(listener->profile, listener->profile->sql_mutex, sql, skinny_feature_get_callback, &helper); switch_safe_free(sql); } *button = helper.button; @@ -669,7 +935,26 @@ void skinny_feature_get(listener_t *listener, uint32_t instance, struct feature_ /*****************************************************************************/ /* SKINNY MESSAGE SENDER */ /*****************************************************************************/ -switch_status_t start_tone(listener_t *listener, +switch_status_t send_register_ack(listener_t *listener, + uint32_t keep_alive, + char *date_format, + char *reserved, + uint32_t secondary_keep_alive, + char *reserved2) +{ + skinny_message_t *message; + message = switch_core_alloc(listener->pool, 12+sizeof(message->data.reg_ack)); + message->type = REGISTER_ACK_MESSAGE; + message->length = 4 + sizeof(message->data.reg_ack); + message->data.reg_ack.keep_alive = keep_alive; + strncpy(message->data.reg_ack.date_format, date_format, 6); + strncpy(message->data.reg_ack.reserved, reserved, 2); + message->data.reg_ack.secondary_keep_alive = keep_alive; + strncpy(message->data.reg_ack.reserved2, reserved2, 4); + return skinny_send_reply(listener, message); +} + +switch_status_t send_start_tone(listener_t *listener, uint32_t tone, uint32_t reserved, uint32_t line_instance, @@ -683,11 +968,10 @@ switch_status_t start_tone(listener_t *listener, message->data.start_tone.reserved = reserved; message->data.start_tone.line_instance = line_instance; message->data.start_tone.call_id = call_id; - skinny_send_reply(listener, message); - return SWITCH_STATUS_SUCCESS; + return skinny_send_reply(listener, message); } -switch_status_t stop_tone(listener_t *listener, +switch_status_t send_stop_tone(listener_t *listener, uint32_t line_instance, uint32_t call_id) { @@ -697,14 +981,14 @@ switch_status_t stop_tone(listener_t *listener, message->length = 4 + sizeof(message->data.stop_tone); message->data.stop_tone.line_instance = line_instance; message->data.stop_tone.call_id = call_id; - skinny_send_reply(listener, message); - return SWITCH_STATUS_SUCCESS; + return skinny_send_reply(listener, message); } -switch_status_t set_ringer(listener_t *listener, +switch_status_t send_set_ringer(listener_t *listener, uint32_t ring_type, uint32_t ring_mode, - uint32_t unknown) + uint32_t line_instance, + uint32_t call_id) { skinny_message_t *message; message = switch_core_alloc(listener->pool, 12+sizeof(message->data.ringer)); @@ -712,12 +996,12 @@ switch_status_t set_ringer(listener_t *listener, message->length = 4 + sizeof(message->data.ringer); message->data.ringer.ring_type = ring_type; message->data.ringer.ring_mode = ring_mode; - message->data.ringer.unknown = unknown; - skinny_send_reply(listener, message); - return SWITCH_STATUS_SUCCESS; + message->data.ringer.line_instance = line_instance; + message->data.ringer.call_id = call_id; + return skinny_send_reply(listener, message); } -switch_status_t set_lamp(listener_t *listener, +switch_status_t send_set_lamp(listener_t *listener, uint32_t stimulus, uint32_t stimulus_instance, uint32_t mode) @@ -729,11 +1013,10 @@ switch_status_t set_lamp(listener_t *listener, message->data.lamp.stimulus = stimulus; message->data.lamp.stimulus_instance = stimulus_instance; message->data.lamp.mode = mode; - skinny_send_reply(listener, message); - return SWITCH_STATUS_SUCCESS; + return skinny_send_reply(listener, message); } -switch_status_t set_speaker_mode(listener_t *listener, +switch_status_t send_set_speaker_mode(listener_t *listener, uint32_t mode) { skinny_message_t *message; @@ -741,11 +1024,10 @@ switch_status_t set_speaker_mode(listener_t *listener, message->type = SET_SPEAKER_MODE_MESSAGE; message->length = 4 + sizeof(message->data.speaker_mode); message->data.speaker_mode.mode = mode; - skinny_send_reply(listener, message); - return SWITCH_STATUS_SUCCESS; + return skinny_send_reply(listener, message); } -switch_status_t start_media_transmission(listener_t *listener, +switch_status_t send_start_media_transmission(listener_t *listener, uint32_t conference_id, uint32_t pass_thru_party_id, uint32_t remote_ip, @@ -772,11 +1054,10 @@ switch_status_t start_media_transmission(listener_t *listener, message->data.start_media.max_frames_per_packet = max_frames_per_packet; message->data.start_media.g723_bitrate = g723_bitrate; /* ... */ - skinny_send_reply(listener, message); - return SWITCH_STATUS_SUCCESS; + return skinny_send_reply(listener, message); } -switch_status_t stop_media_transmission(listener_t *listener, +switch_status_t send_stop_media_transmission(listener_t *listener, uint32_t conference_id, uint32_t pass_thru_party_id, uint32_t conference_id2) @@ -789,8 +1070,7 @@ switch_status_t stop_media_transmission(listener_t *listener, message->data.stop_media.pass_thru_party_id = pass_thru_party_id; message->data.stop_media.conference_id2 = conference_id2; /* ... */ - skinny_send_reply(listener, message); - return SWITCH_STATUS_SUCCESS; + return skinny_send_reply(listener, message); } switch_status_t send_call_info(listener_t *listener, @@ -819,31 +1099,95 @@ switch_status_t send_call_info(listener_t *listener, message = switch_core_alloc(listener->pool, 12+sizeof(message->data.call_info)); message->type = CALL_INFO_MESSAGE; message->length = 4 + sizeof(message->data.call_info); - strcpy(message->data.call_info.calling_party_name, calling_party_name); - strcpy(message->data.call_info.calling_party, calling_party); - strcpy(message->data.call_info.called_party_name, called_party_name); - strcpy(message->data.call_info.called_party, called_party); + strncpy(message->data.call_info.calling_party_name, calling_party_name, 40); + strncpy(message->data.call_info.calling_party, calling_party, 24); + strncpy(message->data.call_info.called_party_name, called_party_name, 40); + strncpy(message->data.call_info.called_party, called_party, 24); message->data.call_info.line_instance = line_instance; message->data.call_info.call_id = call_id; message->data.call_info.call_type = call_type; - strcpy(message->data.call_info.original_called_party_name, original_called_party_name); - strcpy(message->data.call_info.original_called_party, original_called_party); - strcpy(message->data.call_info.last_redirecting_party_name, last_redirecting_party_name); - strcpy(message->data.call_info.last_redirecting_party, last_redirecting_party); + strncpy(message->data.call_info.original_called_party_name, original_called_party_name, 40); + strncpy(message->data.call_info.original_called_party, original_called_party, 24); + strncpy(message->data.call_info.last_redirecting_party_name, last_redirecting_party_name, 40); + strncpy(message->data.call_info.last_redirecting_party, last_redirecting_party, 24); message->data.call_info.original_called_party_redirect_reason = original_called_party_redirect_reason; message->data.call_info.last_redirecting_reason = last_redirecting_reason; - strcpy(message->data.call_info.calling_party_voice_mailbox, calling_party_voice_mailbox); - strcpy(message->data.call_info.called_party_voice_mailbox, called_party_voice_mailbox); - strcpy(message->data.call_info.original_called_party_voice_mailbox, original_called_party_voice_mailbox); - strcpy(message->data.call_info.last_redirecting_voice_mailbox, last_redirecting_voice_mailbox); + strncpy(message->data.call_info.calling_party_voice_mailbox, calling_party_voice_mailbox, 24); + strncpy(message->data.call_info.called_party_voice_mailbox, called_party_voice_mailbox, 24); + strncpy(message->data.call_info.original_called_party_voice_mailbox, original_called_party_voice_mailbox, 24); + strncpy(message->data.call_info.last_redirecting_voice_mailbox, last_redirecting_voice_mailbox, 24); message->data.call_info.call_instance = call_instance; message->data.call_info.call_security_status = call_security_status; message->data.call_info.party_pi_restriction_bits = party_pi_restriction_bits; - skinny_send_reply(listener, message); - return SWITCH_STATUS_SUCCESS; + return skinny_send_reply(listener, message); } -switch_status_t open_receive_channel(listener_t *listener, +switch_status_t send_define_time_date(listener_t *listener, + uint32_t year, + uint32_t month, + uint32_t day_of_week, /* monday = 1 */ + uint32_t day, + uint32_t hour, + uint32_t minute, + uint32_t seconds, + uint32_t milliseconds, + uint32_t timestamp) +{ + skinny_message_t *message; + message = switch_core_alloc(listener->pool, 12+sizeof(message->data.define_time_date)); + message->type = DEFINE_TIME_DATE_MESSAGE; + message->length = 4+sizeof(message->data.define_time_date); + message->data.define_time_date.year = year; + message->data.define_time_date.month = month; + message->data.define_time_date.day_of_week = day_of_week; + message->data.define_time_date.day = day; + message->data.define_time_date.hour = hour; + message->data.define_time_date.minute = minute; + message->data.define_time_date.seconds = seconds; + message->data.define_time_date.milliseconds = milliseconds; + message->data.define_time_date.timestamp = timestamp; + return skinny_send_reply(listener, message); +} + +switch_status_t send_define_current_time_date(listener_t *listener) +{ + switch_time_t ts; + switch_time_exp_t tm; + ts = switch_micro_time_now(); + switch_time_exp_lt(&tm, ts); + return send_define_time_date(listener, + tm.tm_year + 1900, + tm.tm_mon + 1, + tm.tm_wday, + tm.tm_yday + 1, + tm.tm_hour, + tm.tm_min, + tm.tm_sec + 1, + tm.tm_usec / 1000, + ts / 1000000); +} + +switch_status_t send_capabilities_req(listener_t *listener) +{ + skinny_message_t *message; + message = switch_core_alloc(listener->pool, 12); + message->type = CAPABILITIES_REQ_MESSAGE; + message->length = 4; + return skinny_send_reply(listener, message); +} + +switch_status_t send_register_reject(listener_t *listener, + char *error) +{ + skinny_message_t *message; + message = switch_core_alloc(listener->pool, 12+sizeof(message->data.reg_rej)); + message->type = REGISTER_REJECT_MESSAGE; + message->length = 4 + sizeof(message->data.reg_rej); + strncpy(message->data.reg_rej.error, error, 33); + return skinny_send_reply(listener, message); +} + +switch_status_t send_open_receive_channel(listener_t *listener, uint32_t conference_id, uint32_t pass_thru_party_id, uint32_t packets, @@ -876,11 +1220,10 @@ switch_status_t open_receive_channel(listener_t *listener, message->data.open_receive_channel.reserved[8] = reserved[8]; message->data.open_receive_channel.reserved[9] = reserved[9]; */ - skinny_send_reply(listener, message); - return SWITCH_STATUS_SUCCESS; + return skinny_send_reply(listener, message); } -switch_status_t close_receive_channel(listener_t *listener, +switch_status_t send_close_receive_channel(listener_t *listener, uint32_t conference_id, uint32_t pass_thru_party_id, uint32_t conference_id2) @@ -892,8 +1235,7 @@ switch_status_t close_receive_channel(listener_t *listener, message->data.close_receive_channel.conference_id = conference_id; message->data.close_receive_channel.pass_thru_party_id = pass_thru_party_id; message->data.close_receive_channel.conference_id2 = conference_id2; - skinny_send_reply(listener, message); - return SWITCH_STATUS_SUCCESS; + return skinny_send_reply(listener, message); } switch_status_t send_select_soft_keys(listener_t *listener, @@ -910,8 +1252,7 @@ switch_status_t send_select_soft_keys(listener_t *listener, message->data.select_soft_keys.call_id = call_id; message->data.select_soft_keys.soft_key_set = soft_key_set; message->data.select_soft_keys.valid_key_mask = valid_key_mask; - skinny_send_reply(listener, message); - return SWITCH_STATUS_SUCCESS; + return skinny_send_reply(listener, message); } switch_status_t send_call_state(listener_t *listener, @@ -926,11 +1267,10 @@ switch_status_t send_call_state(listener_t *listener, message->data.call_state.call_state = call_state; message->data.call_state.line_instance = line_instance; message->data.call_state.call_id = call_id; - skinny_send_reply(listener, message); - return SWITCH_STATUS_SUCCESS; + return skinny_send_reply(listener, message); } -switch_status_t display_prompt_status(listener_t *listener, +switch_status_t send_display_prompt_status(listener_t *listener, uint32_t timeout, char display[32], uint32_t line_instance, @@ -941,14 +1281,13 @@ switch_status_t display_prompt_status(listener_t *listener, message->type = DISPLAY_PROMPT_STATUS_MESSAGE; message->length = 4 + sizeof(message->data.display_prompt_status); message->data.display_prompt_status.timeout = timeout; - strcpy(message->data.display_prompt_status.display, display); + strncpy(message->data.display_prompt_status.display, display, 32); message->data.display_prompt_status.line_instance = line_instance; message->data.display_prompt_status.call_id = call_id; - skinny_send_reply(listener, message); - return SWITCH_STATUS_SUCCESS; + return skinny_send_reply(listener, message); } -switch_status_t clear_prompt_status(listener_t *listener, +switch_status_t send_clear_prompt_status(listener_t *listener, uint32_t line_instance, uint32_t call_id) { @@ -958,11 +1297,10 @@ switch_status_t clear_prompt_status(listener_t *listener, message->length = 4 + sizeof(message->data.clear_prompt_status); message->data.clear_prompt_status.line_instance = line_instance; message->data.clear_prompt_status.call_id = call_id; - skinny_send_reply(listener, message); - return SWITCH_STATUS_SUCCESS; + return skinny_send_reply(listener, message); } -switch_status_t activate_call_plane(listener_t *listener, +switch_status_t send_activate_call_plane(listener_t *listener, uint32_t line_instance) { skinny_message_t *message; @@ -970,8 +1308,7 @@ switch_status_t activate_call_plane(listener_t *listener, message->type = ACTIVATE_CALL_PLANE_MESSAGE; message->length = 4 + sizeof(message->data.activate_call_plane); message->data.activate_call_plane.line_instance = line_instance; - skinny_send_reply(listener, message); - return SWITCH_STATUS_SUCCESS; + return skinny_send_reply(listener, message); } switch_status_t send_dialed_number(listener_t *listener, @@ -983,23 +1320,36 @@ switch_status_t send_dialed_number(listener_t *listener, message = switch_core_alloc(listener->pool, 12+sizeof(message->data.dialed_number)); message->type = DIALED_NUMBER_MESSAGE; message->length = 4 + sizeof(message->data.dialed_number); - strcpy(message->data.dialed_number.called_party, called_party); + strncpy(message->data.dialed_number.called_party, called_party, 24); message->data.dialed_number.line_instance = line_instance; message->data.dialed_number.call_id = call_id; - skinny_send_reply(listener, message); - return SWITCH_STATUS_SUCCESS; + return skinny_send_reply(listener, message); } -switch_status_t send_reset(listener_t *listener, - uint32_t reset_type) +switch_status_t send_display_pri_notify(listener_t *listener, + uint32_t message_timeout, + uint32_t priority, + char *notify) +{ + skinny_message_t *message; + message = switch_core_alloc(listener->pool, 12+sizeof(message->data.display_pri_notify)); + message->type = DISPLAY_PRI_NOTIFY_MESSAGE; + message->length = 4 + sizeof(message->data.display_pri_notify); + message->data.display_pri_notify.message_timeout = message_timeout; + message->data.display_pri_notify.priority = priority; + strncpy(message->data.display_pri_notify.notify, notify, 32); + return skinny_send_reply(listener, message); +} + + +switch_status_t send_reset(listener_t *listener, uint32_t reset_type) { skinny_message_t *message; message = switch_core_alloc(listener->pool, 12+sizeof(message->data.reset)); message->type = RESET_MESSAGE; message->length = 4 + sizeof(message->data.reset); message->data.reset.reset_type = reset_type; - skinny_send_reply(listener, message); - return SWITCH_STATUS_SUCCESS; + return skinny_send_reply(listener, message); } /* Message handling */ @@ -1020,14 +1370,13 @@ switch_status_t skinny_handle_alarm(listener_t *listener, skinny_message_t *requ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-Alarm-Param1", "%d", request->data.alarm.alarm_param1); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-Alarm-Param2", "%d", request->data.alarm.alarm_param2); switch_event_fire(&event); - + return SWITCH_STATUS_SUCCESS; } switch_status_t skinny_handle_register(listener_t *listener, skinny_message_t *request) { switch_status_t status = SWITCH_STATUS_FALSE; - skinny_message_t *message; skinny_profile_t *profile; switch_event_t *event = NULL; switch_event_t *params = NULL; @@ -1041,11 +1390,7 @@ switch_status_t skinny_handle_register(listener_t *listener, skinny_message_t *r if(!zstr(listener->device_name)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "A device is already registred on this listener.\n"); - message = switch_core_alloc(listener->pool, 12+sizeof(message->data.reg_rej)); - message->type = REGISTER_REJ_MESSAGE; - message->length = 4 + sizeof(message->data.reg_rej); - strcpy(message->data.reg_rej.error, "A device is already registred on this listener"); - skinny_send_reply(listener, message); + send_register_reject(listener, "A device is already registred on this listener"); return SWITCH_STATUS_FALSE; } @@ -1057,11 +1402,7 @@ switch_status_t skinny_handle_register(listener_t *listener, skinny_message_t *r switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Can't find device [%s@%s]\n" "You must define a domain called '%s' in your directory and add a user with id=\"%s\".\n" , request->data.reg.device_name, profile->domain, profile->domain, request->data.reg.device_name); - message = switch_core_alloc(listener->pool, 12+sizeof(message->data.reg_rej)); - message->type = REGISTER_REJ_MESSAGE; - message->length = 4 + sizeof(message->data.reg_rej); - strcpy(message->data.reg_rej.error, "Device not found"); - skinny_send_reply(listener, message); + send_register_reject(listener, "Device not found"); status = SWITCH_STATUS_FALSE; goto end; } @@ -1078,18 +1419,19 @@ switch_status_t skinny_handle_register(listener_t *listener, skinny_message_t *r request->data.reg.max_streams, "" /* codec_string */ ))) { - skinny_execute_sql(profile, sql, profile->listener_mutex); + skinny_execute_sql(profile, sql, profile->sql_mutex); switch_safe_free(sql); } - strcpy(listener->device_name, request->data.reg.device_name); + strncpy(listener->device_name, request->data.reg.device_name, 16); listener->device_instance = request->data.reg.instance; xskinny = switch_xml_child(xuser, "skinny"); if (xskinny) { xbuttons = switch_xml_child(xskinny, "buttons"); if (xbuttons) { + uint32_t line_instance = 1; for (xbutton = switch_xml_child(xbuttons, "button"); xbutton; xbutton = xbutton->next) { uint32_t position = atoi(switch_xml_attr_soft(xbutton, "position")); uint32_t type = skinny_str2button(switch_xml_attr_soft(xbutton, "type")); @@ -1106,16 +1448,16 @@ switch_status_t skinny_handle_register(listener_t *listener, skinny_message_t *r uint32_t noanswer_duration = atoi(switch_xml_attr_soft(xbutton, "noanswer-duration")); if ((sql = switch_mprintf( "INSERT INTO skinny_lines " - "(device_name, device_instance, position, " + "(device_name, device_instance, position, line_instance, " "label, value, caller_name, " "ring_on_idle, ring_on_active, busy_trigger, " - "forward_all, forward_busy, forward_noanswer, noanswer_duration) " - "VALUES('%s', %d, %d, '%s', '%s', '%s', %d, %d, %d, '%s', '%s', '%s', %d)", - request->data.reg.device_name, request->data.reg.instance, position, + "forward_all, forward_busy, forward_noanswer, noanswer_duration) " + "VALUES('%s', %d, %d, %d, '%s', '%s', '%s', %d, %d, %d, '%s', '%s', '%s', %d)", + request->data.reg.device_name, request->data.reg.instance, position, line_instance++, label, value, caller_name, ring_on_idle, ring_on_active, busy_trigger, - forward_all, forward_busy, forward_noanswer, noanswer_duration))) { - skinny_execute_sql(profile, sql, profile->listener_mutex); + forward_all, forward_busy, forward_noanswer, noanswer_duration))) { + skinny_execute_sql(profile, sql, profile->sql_mutex); switch_safe_free(sql); } } else { @@ -1131,7 +1473,7 @@ switch_status_t skinny_handle_register(listener_t *listener, skinny_message_t *r label, value, settings))) { - skinny_execute_sql(profile, sql, profile->listener_mutex); + skinny_execute_sql(profile, sql, profile->sql_mutex); switch_safe_free(sql); } } @@ -1142,38 +1484,29 @@ switch_status_t skinny_handle_register(listener_t *listener, skinny_message_t *r status = SWITCH_STATUS_SUCCESS; /* Reply with RegisterAckMessage */ - message = switch_core_alloc(listener->pool, 12+sizeof(message->data.reg_ack)); - message->type = REGISTER_ACK_MESSAGE; - message->length = 4 + sizeof(message->data.reg_ack); - message->data.reg_ack.keepAlive = profile->keep_alive; - memcpy(message->data.reg_ack.dateFormat, profile->date_format, 6); - message->data.reg_ack.secondaryKeepAlive = profile->keep_alive; - skinny_send_reply(listener, message); + send_register_ack(listener, profile->keep_alive, profile->date_format, "", profile->keep_alive, ""); /* Send CapabilitiesReqMessage */ - message = switch_core_alloc(listener->pool, 12); - message->type = CAPABILITIES_REQ_MESSAGE; - message->length = 4; - skinny_send_reply(listener, message); + send_capabilities_req(listener); /* skinny::register event */ skinny_device_event(listener, &event, SWITCH_EVENT_CUSTOM, SKINNY_EVENT_REGISTER); switch_event_fire(&event); - + keepalive_listener(listener, NULL); end: if(params) { switch_event_destroy(¶ms); } - + return status; } switch_status_t skinny_headset_status_message(listener_t *listener, skinny_message_t *request) { skinny_check_data_length(request, sizeof(request->data.headset_status)); - + /* Nothing to do */ return SWITCH_STATUS_SUCCESS; } @@ -1188,12 +1521,12 @@ int skinny_config_stat_res_callback(void *pArg, int argc, char **argv, char **co char *server_name = argv[4]; int number_lines = atoi(argv[5]); int number_speed_dials = atoi(argv[6]); - - strcpy(message->data.config_res.device_name, device_name); + + strncpy(message->data.config_res.device_name, device_name, 16); message->data.config_res.user_id = user_id; message->data.config_res.instance = instance; - strcpy(message->data.config_res.user_name, user_name); - strcpy(message->data.config_res.server_name, server_name); + strncpy(message->data.config_res.user_name, user_name, 40); + strncpy(message->data.config_res.server_name, server_name, 40); message->data.config_res.number_lines = number_lines; message->data.config_res.number_speed_dials = number_speed_dials; @@ -1227,7 +1560,7 @@ switch_status_t skinny_handle_config_stat_request(listener_t *listener, skinny_m SKINNY_BUTTON_SPEED_DIAL, listener->device_name ))) { - skinny_execute_sql_callback(profile, profile->listener_mutex, sql, skinny_config_stat_res_callback, message); + skinny_execute_sql_callback(profile, profile->sql_mutex, sql, skinny_config_stat_res_callback, message); switch_safe_free(sql); } skinny_send_reply(listener, message); @@ -1244,7 +1577,7 @@ switch_status_t skinny_handle_capabilities_response(listener_t *listener, skinny uint32_t n = 0; char *codec_order[SWITCH_MAX_CODECS]; char *codec_string; - + size_t string_len, string_pos, pos; switch_assert(listener->profile); @@ -1287,10 +1620,10 @@ switch_status_t skinny_handle_capabilities_response(listener_t *listener, skinny codec_string, listener->device_name ))) { - skinny_execute_sql(profile, sql, profile->listener_mutex); + skinny_execute_sql(profile, sql, profile->sql_mutex); switch_safe_free(sql); } - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Codecs %s supported.\n", codec_string); return SWITCH_STATUS_SUCCESS; } @@ -1309,11 +1642,11 @@ switch_status_t skinny_handle_port_message(listener_t *listener, skinny_message_ if ((sql = switch_mprintf( "UPDATE skinny_devices SET port=%d WHERE name='%s' and instance=%d", - request->data.as_uint16, + request->data.port.port, listener->device_name, listener->device_instance ))) { - skinny_execute_sql(profile, sql, profile->listener_mutex); + skinny_execute_sql(profile, sql, profile->sql_mutex); switch_safe_free(sql); } return SWITCH_STATUS_SUCCESS; @@ -1366,7 +1699,7 @@ switch_status_t skinny_handle_button_template_request(listener_t *listener, skin message->data.button_template.button_offset = 0; message->data.button_template.button_count = 0; message->data.button_template.total_button_count = 0; - + helper.message = message; /* Add buttons */ @@ -1378,10 +1711,10 @@ switch_status_t skinny_handle_button_template_request(listener_t *listener, skin SKINNY_BUTTON_UNDEFINED, listener->device_name, listener->device_instance ))) { - skinny_execute_sql_callback(profile, profile->listener_mutex, sql, skinny_handle_button_template_request_callback, &helper); + skinny_execute_sql_callback(profile, profile->sql_mutex, sql, skinny_handle_button_template_request_callback, &helper); switch_safe_free(sql); } - + /* Add lines */ if ((sql = switch_mprintf( "SELECT device_name, device_instance, position, %d AS type " @@ -1391,10 +1724,10 @@ switch_status_t skinny_handle_button_template_request(listener_t *listener, skin SKINNY_BUTTON_LINE, listener->device_name, listener->device_instance ))) { - skinny_execute_sql_callback(profile, profile->listener_mutex, sql, skinny_handle_button_template_request_callback, &helper); + skinny_execute_sql_callback(profile, profile->sql_mutex, sql, skinny_handle_button_template_request_callback, &helper); switch_safe_free(sql); } - + /* Fill remaining buttons with Undefined */ for(int i = 0; i+1 < helper.max_position; i++) { if(message->data.button_template.btn[i].button_definition == SKINNY_BUTTON_UNKNOWN) { @@ -1427,11 +1760,11 @@ switch_status_t skinny_handle_soft_key_template_request(listener_t *listener, sk message->data.soft_key_template.soft_key_offset = 0; message->data.soft_key_template.soft_key_count = 21; message->data.soft_key_template.total_soft_key_count = 21; - + memcpy(message->data.soft_key_template.soft_key, soft_key_template_default, sizeof(soft_key_template_default)); - + skinny_send_reply(listener, message); return SWITCH_STATUS_SUCCESS; @@ -1454,7 +1787,7 @@ switch_status_t skinny_handle_soft_key_set_request(listener_t *listener, skinny_ message->data.soft_key_set.soft_key_set_offset = 0; message->data.soft_key_set.soft_key_set_count = 11; message->data.soft_key_set.total_soft_key_set_count = 11; - + /* TODO fill the set */ message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_ON_HOOK].soft_key_template_index[0] = SOFTKEY_REDIAL; message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_ON_HOOK].soft_key_template_index[1] = SOFTKEY_NEWCALL; @@ -1464,8 +1797,8 @@ switch_status_t skinny_handle_soft_key_set_request(listener_t *listener, skinny_ skinny_send_reply(listener, message); /* Init the states */ - skinny_line_set_state(listener, 0, SKINNY_KEY_SET_ON_HOOK, 0); - + send_select_soft_keys(listener, 0, 0, SKINNY_KEY_SET_ON_HOOK, 0xffff); + return SWITCH_STATUS_SUCCESS; } @@ -1479,7 +1812,7 @@ switch_status_t skinny_handle_line_stat_request(listener_t *listener, skinny_mes message = switch_core_alloc(listener->pool, 12+sizeof(message->data.line_res)); message->type = LINE_STAT_RES_MESSAGE; message->length = 4 + sizeof(message->data.line_res); - + skinny_line_get(listener, request->data.line_req.number, &button); memcpy(&message->data.line_res, button, sizeof(struct line_stat_res_message)); @@ -1499,7 +1832,7 @@ switch_status_t skinny_handle_speed_dial_stat_request(listener_t *listener, skin message = switch_core_alloc(listener->pool, 12+sizeof(message->data.speed_dial_res)); message->type = SPEED_DIAL_STAT_RES_MESSAGE; message->length = 4 + sizeof(message->data.speed_dial_res); - + skinny_speed_dial_get(listener, request->data.speed_dial_req.number, &button); memcpy(&message->data.speed_dial_res, button, sizeof(struct speed_dial_stat_res_message)); @@ -1519,7 +1852,7 @@ switch_status_t skinny_handle_service_url_stat_request(listener_t *listener, ski message = switch_core_alloc(listener->pool, 12+sizeof(message->data.service_url_res)); message->type = SERVICE_URL_STAT_RES_MESSAGE; message->length = 4 + sizeof(message->data.service_url_res); - + skinny_service_url_get(listener, request->data.service_url_req.service_url_index, &button); memcpy(&message->data.service_url_res, button, sizeof(struct service_url_stat_res_message)); @@ -1539,7 +1872,7 @@ switch_status_t skinny_handle_feature_stat_request(listener_t *listener, skinny_ message = switch_core_alloc(listener->pool, 12+sizeof(message->data.feature_res)); message->type = FEATURE_STAT_RES_MESSAGE; message->length = 4 + sizeof(message->data.feature_res); - + skinny_feature_get(listener, request->data.feature_req.feature_index, &button); memcpy(&message->data.feature_res, button, sizeof(struct feature_stat_res_message)); @@ -1559,26 +1892,7 @@ switch_status_t skinny_handle_register_available_lines_message(listener_t *liste switch_status_t skinny_handle_time_date_request(listener_t *listener, skinny_message_t *request) { - skinny_message_t *message; - switch_time_t ts; - switch_time_exp_t tm; - - message = switch_core_alloc(listener->pool, 12+sizeof(message->data.define_time_date)); - message->type = DEFINE_TIME_DATE_MESSAGE; - message->length = 4+sizeof(message->data.define_time_date); - ts = switch_micro_time_now(); - switch_time_exp_lt(&tm, ts); - message->data.define_time_date.year = tm.tm_year + 1900; - message->data.define_time_date.month = tm.tm_mon + 1; - message->data.define_time_date.day_of_week = tm.tm_wday; - message->data.define_time_date.day = tm.tm_yday + 1; - message->data.define_time_date.hour = tm.tm_hour; - message->data.define_time_date.minute = tm.tm_min; - message->data.define_time_date.seconds = tm.tm_sec + 1; - message->data.define_time_date.milliseconds = tm.tm_usec / 1000; - message->data.define_time_date.timestamp = ts / 1000000; - skinny_send_reply(listener, message); - return SWITCH_STATUS_SUCCESS; + return send_define_current_time_date(listener); } switch_status_t skinny_handle_keep_alive_message(listener_t *listener, skinny_message_t *request) @@ -1596,173 +1910,128 @@ switch_status_t skinny_handle_keep_alive_message(listener_t *listener, skinny_me switch_status_t skinny_handle_soft_key_event_message(listener_t *listener, skinny_message_t *request) { switch_status_t status = SWITCH_STATUS_SUCCESS; - - skinny_profile_t *profile; + uint32_t line_instance = 0; + switch_core_session_t *session = NULL; switch_channel_t *channel = NULL; - uint32_t line; private_t *tech_pvt = NULL; - + switch_assert(listener); switch_assert(listener->profile); - switch_assert(listener->device_name); - - profile = listener->profile; - + skinny_check_data_length(request, sizeof(request->data.soft_key_event)); - if(request->data.soft_key_event.line_instance) { - line = request->data.soft_key_event.line_instance; - } else { - line = 1; - } - /* Close/Hold busy lines */ - for(int i = 0 ; i < SKINNY_MAX_BUTTON_COUNT ; i++) { - if(i == line) { - continue; - } - if(listener->session[i]) { - channel = switch_core_session_get_channel(listener->session[i]); - assert(channel != NULL); - if((skinny_line_get_state(listener, i) == SKINNY_KEY_SET_ON_HOOK) - || (skinny_line_get_state(listener, i) == SKINNY_KEY_SET_OFF_HOOK) - || (skinny_line_get_state(listener, i) == SKINNY_KEY_SET_RING_OUT) - || (skinny_line_get_state(listener, i) == SKINNY_KEY_SET_DIGITS_AFTER_DIALING_FIRST_DIGIT) - || (skinny_line_get_state(listener, i) == SKINNY_KEY_SET_OFF_HOOK_WITH_FEATURES)) { + line_instance = request->data.soft_key_event.line_instance; - switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING); - channel = NULL; - } else if((skinny_line_get_state(listener, i) == SKINNY_KEY_SET_RING_IN) - || (skinny_line_get_state(listener, i) == SKINNY_KEY_SET_CONNECTED) - || (skinny_line_get_state(listener, i) == SKINNY_KEY_SET_CONNECTED_WITH_TRANSFER) - || (skinny_line_get_state(listener, i) == SKINNY_KEY_SET_CONNECTED_WITH_CONFERENCE)) { - skinny_hold_line(listener, i); - } /* remaining: SKINNY_KEY_SET_ON_HOLD */ - } - } - - if(!listener->session[line]) { /*the line is not busy */ - switch(request->data.soft_key_event.event) { - case SOFTKEY_REDIAL: - skinny_create_session(listener, line, SKINNY_KEY_SET_DIGITS_AFTER_DIALING_FIRST_DIGIT); - - tech_pvt = switch_core_session_get_private(listener->session[line]); - assert(tech_pvt != NULL); - - strcpy(tech_pvt->dest, "redial"); - skinny_process_dest(listener, line); - break; - case SOFTKEY_NEWCALL: - skinny_create_session(listener, line, SKINNY_KEY_SET_OFF_HOOK); - break; - default: - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, - "Unknown SoftKeyEvent type while not busy: %d.\n", request->data.soft_key_event.event); - } - } else { /* the line is busy */ - if(skinny_line_get_state(listener, line) == SKINNY_KEY_SET_ON_HOLD) { - skinny_unhold_line(listener, line); - } - switch(request->data.soft_key_event.event) { - case SOFTKEY_ANSWER: - skinny_answer(listener->session[line]); - break; - case SOFTKEY_ENDCALL: - channel = switch_core_session_get_channel(listener->session[line]); - assert(channel != NULL); + switch(request->data.soft_key_event.event) { + case SOFTKEY_REDIAL: + status = skinny_create_ingoing_session(listener, &line_instance, &session); - switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING); + skinny_session_process_dest(session, listener, line_instance, "redial", '\0', 0); + break; + case SOFTKEY_NEWCALL: + status = skinny_create_ingoing_session(listener, &line_instance, &session); + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); - break; - default: - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, - "Unknown SoftKeyEvent type while busy: %d.\n", request->data.soft_key_event.event); - } + skinny_session_process_dest(session, listener, line_instance, NULL, '\0', 0); + break; + case SOFTKEY_HOLD: + session = skinny_profile_find_session(listener->profile, listener, &line_instance, request->data.soft_key_event.call_id); + + if(session) { + status = skinny_session_hold_line(session, listener, line_instance); + } + break; + case SOFTKEY_ENDCALL: + session = skinny_profile_find_session(listener->profile, listener, &line_instance, request->data.soft_key_event.call_id); + + if(session) { + channel = switch_core_session_get_channel(session); + + switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING); + } + break; + case SOFTKEY_RESUME: + session = skinny_profile_find_session(listener->profile, listener, &line_instance, request->data.soft_key_event.call_id); + + if(session) { + status = skinny_session_unhold_line(session, listener, line_instance); + } + break; + case SOFTKEY_ANSWER: + session = skinny_profile_find_session(listener->profile, listener, &line_instance, request->data.soft_key_event.call_id); + + if(session) { + status = skinny_session_answer(session, listener, line_instance); + } + break; + default: + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, + "Unknown SoftKeyEvent type while busy: %d.\n", request->data.soft_key_event.event); } + + if(session) { + switch_core_session_rwunlock(session); + } + return status; } switch_status_t skinny_handle_off_hook_message(listener_t *listener, skinny_message_t *request) { - skinny_profile_t *profile; - uint32_t line; - - switch_assert(listener->profile); - switch_assert(listener->device_name); - - profile = listener->profile; + uint32_t line_instance; + switch_core_session_t *session = NULL; + private_t *tech_pvt = NULL; skinny_check_data_length(request, sizeof(request->data.off_hook)); - if(request->data.off_hook.line_instance) { - line = request->data.off_hook.line_instance; + if(request->data.off_hook.line_instance > 0) { + line_instance = request->data.off_hook.line_instance; } else { - line = 1; + line_instance = 1; } - if(listener->session[line]) { /*answering a call */ - skinny_answer(listener->session[line]); + + session = skinny_profile_find_session(listener->profile, listener, &line_instance, request->data.off_hook.call_id); + + if(session) { /*answering a call */ + skinny_session_answer(session, listener, line_instance); } else { /* start a new call */ - skinny_create_session(listener, line, SKINNY_KEY_SET_OFF_HOOK); + skinny_create_ingoing_session(listener, &line_instance, &session); + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + + skinny_session_process_dest(session, listener, line_instance, NULL, '\0', 0); } return SWITCH_STATUS_SUCCESS; } switch_status_t skinny_handle_stimulus_message(listener_t *listener, skinny_message_t *request) { - skinny_profile_t *profile; struct speed_dial_stat_res_message *button = NULL; - uint32_t line = 0; - private_t *tech_pvt = NULL; + uint32_t line_instance = 0; + uint32_t call_id = 0; + switch_core_session_t *session = NULL; - switch_assert(listener->profile); - switch_assert(listener->device_name); + skinny_check_data_length(request, sizeof(request->data.stimulus)-sizeof(request->data.stimulus.call_id)); - profile = listener->profile; - - skinny_check_data_length(request, sizeof(request->data.stimulus)); - - if(request->data.stimulus.instance_type == SKINNY_BUTTON_LINE) {/* Choose the specified line */ - line = request->data.stimulus.instance; - } - if(line == 0) {/* If none, find the first busy line */ - for(int i = 0 ; i < SKINNY_MAX_BUTTON_COUNT ; i++) { - if(listener->session[i]) { - line = i; - break; - } - } - } - if(line == 0) {/* If none, choose the first line */ - line = 1; + if(skinny_check_data_length_soft(request, sizeof(request->data.stimulus))) { + call_id = request->data.stimulus.call_id; } + switch(request->data.stimulus.instance_type) { case SKINNY_BUTTON_LAST_NUMBER_REDIAL: - skinny_create_session(listener, line, SKINNY_KEY_SET_DIGITS_AFTER_DIALING_FIRST_DIGIT); - - tech_pvt = switch_core_session_get_private(listener->session[line]); - assert(tech_pvt != NULL); - - strcpy(tech_pvt->dest, "redial"); - skinny_process_dest(listener, line); + skinny_create_ingoing_session(listener, &line_instance, &session); + skinny_session_process_dest(session, listener, line_instance, "redial", '\0', 0); break; case SKINNY_BUTTON_VOICEMAIL: - skinny_create_session(listener, line, SKINNY_KEY_SET_DIGITS_AFTER_DIALING_FIRST_DIGIT); - - tech_pvt = switch_core_session_get_private(listener->session[line]); - assert(tech_pvt != NULL); - - strcpy(tech_pvt->dest, "vmain"); - skinny_process_dest(listener, line); + skinny_create_ingoing_session(listener, &line_instance, &session); + skinny_session_process_dest(session, listener, line_instance, "vmain", '\0', 0); break; case SKINNY_BUTTON_SPEED_DIAL: skinny_speed_dial_get(listener, request->data.stimulus.instance, &button); if(strlen(button->line) > 0) { - skinny_create_session(listener, line, SKINNY_KEY_SET_DIGITS_AFTER_DIALING_FIRST_DIGIT); - - tech_pvt = switch_core_session_get_private(listener->session[line]); - assert(tech_pvt != NULL); - - strcpy(tech_pvt->dest, button->line); - skinny_process_dest(listener, line); + skinny_create_ingoing_session(listener, &line_instance, &session); + skinny_session_process_dest(session, listener, line_instance, button->line, '\0', 0); } break; default: @@ -1774,35 +2043,21 @@ switch_status_t skinny_handle_stimulus_message(listener_t *listener, skinny_mess switch_status_t skinny_handle_open_receive_channel_ack_message(listener_t *listener, skinny_message_t *request) { switch_status_t status = SWITCH_STATUS_SUCCESS; - skinny_profile_t *profile; - uint32_t line = 0; - - switch_assert(listener->profile); - switch_assert(listener->device_name); - - profile = listener->profile; + uint32_t line_instance = 0; + switch_core_session_t *session; skinny_check_data_length(request, sizeof(request->data.open_receive_channel_ack)); - for(int i = 0 ; i < SKINNY_MAX_BUTTON_COUNT ; i++) { - if(listener->session[i]) { - private_t *tech_pvt = NULL; - tech_pvt = switch_core_session_get_private(listener->session[i]); - - if(tech_pvt->party_id == request->data.open_receive_channel_ack.pass_thru_party_id) { - line = i; - } - } - } + session = skinny_profile_find_session(listener->profile, listener, &line_instance, request->data.open_receive_channel_ack.pass_thru_party_id); - if(listener->session[line]) { + if(session) { const char *err = NULL; private_t *tech_pvt = NULL; switch_channel_t *channel = NULL; struct in_addr addr; - tech_pvt = switch_core_session_get_private(listener->session[line]); - channel = switch_core_session_get_channel(listener->session[line]); + tech_pvt = switch_core_session_get_private(session); + channel = switch_core_session_get_channel(session); /* Codec */ tech_pvt->iananame = "PCMU"; /* TODO */ @@ -1810,18 +2065,18 @@ switch_status_t skinny_handle_open_receive_channel_ack_message(listener_t *liste tech_pvt->rm_rate = 8000; /* TODO */ tech_pvt->rm_fmtp = NULL; /* TODO */ tech_pvt->agreed_pt = (switch_payload_t) 0; /* TODO */ - tech_pvt->rm_encoding = switch_core_strdup(switch_core_session_get_pool(listener->session[line]), ""); + tech_pvt->rm_encoding = switch_core_strdup(switch_core_session_get_pool(session), ""); skinny_tech_set_codec(tech_pvt, 0); if ((status = skinny_tech_set_codec(tech_pvt, 0)) != SWITCH_STATUS_SUCCESS) { goto end; } - + /* Request a local port from the core's allocator */ if (!(tech_pvt->local_sdp_audio_port = switch_rtp_request_port(listener->profile->ip))) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_CRIT, "No RTP ports available!\n"); return SWITCH_STATUS_FALSE; } - tech_pvt->local_sdp_audio_ip = switch_core_strdup(switch_core_session_get_pool(listener->session[line]), listener->profile->ip); + tech_pvt->local_sdp_audio_ip = switch_core_strdup(switch_core_session_get_pool(session), listener->profile->ip); tech_pvt->remote_sdp_audio_ip = inet_ntoa(request->data.open_receive_channel_ack.ip); tech_pvt->remote_sdp_audio_port = request->data.open_receive_channel_ack.port; @@ -1834,7 +2089,7 @@ switch_status_t skinny_handle_open_receive_channel_ack_message(listener_t *liste tech_pvt->read_impl.samples_per_packet, tech_pvt->codec_ms * 1000, (switch_rtp_flag_t) 0, "soft", &err, - switch_core_session_get_pool(listener->session[line])); + switch_core_session_get_pool(session)); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "AUDIO RTP [%s] %s:%d->%s:%d codec: %u ms: %d [%s]\n", switch_channel_get_name(channel), @@ -1846,7 +2101,7 @@ switch_status_t skinny_handle_open_receive_channel_ack_message(listener_t *liste tech_pvt->read_impl.microseconds_per_packet / 1000, switch_rtp_ready(tech_pvt->rtp_session) ? "SUCCESS" : err); inet_aton(tech_pvt->local_sdp_audio_ip, &addr); - start_media_transmission(listener, + send_start_media_transmission(listener, tech_pvt->call_id, /* uint32_t conference_id, */ tech_pvt->party_id, /* uint32_t pass_thru_party_id, */ addr.s_addr, /* uint32_t remote_ip, */ @@ -1858,7 +2113,12 @@ switch_status_t skinny_handle_open_receive_channel_ack_message(listener_t *liste 0, /* uint16_t max_frames_per_packet, */ 0 /* uint32_t g723_bitrate */ ); + if (switch_channel_get_state(channel) == CS_NEW) { + switch_channel_set_state(channel, CS_INIT); + } switch_channel_mark_answered(channel); + + switch_core_session_rwunlock(session); } end: return status; @@ -1866,35 +2126,28 @@ end: switch_status_t skinny_handle_keypad_button_message(listener_t *listener, skinny_message_t *request) { - uint32_t line = 0; + uint32_t line_instance = 0; + switch_core_session_t *session; skinny_check_data_length(request, sizeof(request->data.keypad_button)); + + if(request->data.keypad_button.line_instance) { + line_instance = request->data.keypad_button.line_instance; + } else { + line_instance = 1; + } - /* Choose the specified line */ - line = request->data.keypad_button.line_instance; - if(line == 0) {/* If none, find the first busy line */ - for(int i = 0 ; i < SKINNY_MAX_BUTTON_COUNT ; i++) { - if(listener->session[i]) { - line = i; - break; - } - } - } - if(line == 0) {/* If none, choose the first line */ - line = 1; - } - if(listener->session[line]) { + session = skinny_profile_find_session(listener->profile, listener, &line_instance, request->data.keypad_button.call_id); + + if(session) { switch_channel_t *channel = NULL; private_t *tech_pvt = NULL; char digit = '\0'; - channel = switch_core_session_get_channel(listener->session[line]); - assert(channel != NULL); + channel = switch_core_session_get_channel(session); + tech_pvt = switch_core_session_get_private(session); - tech_pvt = switch_core_session_get_private(listener->session[line]); - assert(tech_pvt != NULL); - - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(listener->session[line]), SWITCH_LOG_DEBUG, "SEND DTMF ON CALL %d [%d]\n", tech_pvt->call_id, request->data.keypad_button.button); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "SEND DTMF ON CALL %d [%d]\n", tech_pvt->call_id, request->data.keypad_button.button); if (request->data.keypad_button.button == 14) { digit = '*'; @@ -1903,21 +2156,14 @@ switch_status_t skinny_handle_keypad_button_message(listener_t *listener, skinny } else if (request->data.keypad_button.button >= 0 && request->data.keypad_button.button <= 9) { digit = '0' + request->data.keypad_button.button; } else { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(listener->session[line]), SWITCH_LOG_WARNING, "UNKNOW DTMF RECEIVED ON CALL %d [%d]\n", tech_pvt->call_id, request->data.keypad_button.button); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "UNKNOW DTMF RECEIVED ON CALL %d [%d]\n", tech_pvt->call_id, request->data.keypad_button.button); } /* TODO check call_id and line */ - if((skinny_line_get_state(listener, tech_pvt->line) == SKINNY_KEY_SET_OFF_HOOK) - || (skinny_line_get_state(listener, tech_pvt->line) == SKINNY_KEY_SET_DIGITS_AFTER_DIALING_FIRST_DIGIT)) { - if(strlen(tech_pvt->dest) == 0) {/* first digit */ - stop_tone(listener, tech_pvt->line, tech_pvt->call_id); - skinny_line_set_state(listener, tech_pvt->line, SKINNY_KEY_SET_DIGITS_AFTER_DIALING_FIRST_DIGIT, tech_pvt->call_id); - } - - tech_pvt->dest[strlen(tech_pvt->dest)] = digit; - - skinny_process_dest(listener, tech_pvt->line); + if((skinny_line_get_state(listener, line_instance, tech_pvt->call_id) == SKINNY_OFF_HOOK)) { + + skinny_session_process_dest(session, listener, line_instance, NULL, digit, 0); } else { if(digit != '\0') { switch_dtmf_t dtmf = { 0, switch_core_default_dtmf_duration(0)}; @@ -1925,6 +2171,7 @@ switch_status_t skinny_handle_keypad_button_message(listener_t *listener, skinny switch_channel_queue_dtmf(channel, &dtmf); } } + switch_core_session_rwunlock(session); } return SWITCH_STATUS_SUCCESS; @@ -1933,35 +2180,23 @@ switch_status_t skinny_handle_keypad_button_message(listener_t *listener, skinny switch_status_t skinny_handle_on_hook_message(listener_t *listener, skinny_message_t *request) { switch_status_t status = SWITCH_STATUS_SUCCESS; - skinny_profile_t *profile; - uint32_t line = 0; - - switch_assert(listener->profile); - switch_assert(listener->device_name); - - profile = listener->profile; + switch_core_session_t *session = NULL; + uint32_t line_instance = 0; skinny_check_data_length(request, sizeof(request->data.on_hook)); - if(request->data.on_hook.line_instance != 0) { - line = request->data.on_hook.line_instance; - } else { - /* Find first active line */ - for(int i = 0 ; i < SKINNY_MAX_BUTTON_COUNT ; i++) { - if(listener->session[i]) { - line = i; - break; - } - } - } + line_instance = request->data.on_hook.line_instance; + + session = skinny_profile_find_session(listener->profile, listener, &line_instance, request->data.on_hook.call_id); - if(listener->session[line]) { + if(session) { switch_channel_t *channel = NULL; - channel = switch_core_session_get_channel(listener->session[line]); - assert(channel != NULL); + channel = switch_core_session_get_channel(session); switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING); + + switch_core_session_rwunlock(session); } return status; } @@ -2069,3 +2304,14 @@ switch_status_t skinny_perform_send_reply(listener_t *listener, const char *file return SWITCH_STATUS_SUCCESS; } +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4: + */ + diff --git a/src/mod/endpoints/mod_skinny/skinny_protocol.h b/src/mod/endpoints/mod_skinny/skinny_protocol.h index c0af0b771e..ea004f12fc 100644 --- a/src/mod/endpoints/mod_skinny/skinny_protocol.h +++ b/src/mod/endpoints/mod_skinny/skinny_protocol.h @@ -49,57 +49,60 @@ /* RegisterMessage */ #define REGISTER_MESSAGE 0x0001 struct register_message { - char device_name[16]; - uint32_t user_id; - uint32_t instance; - struct in_addr ip; - uint32_t device_type; - uint32_t max_streams; + char device_name[16]; + uint32_t user_id; + uint32_t instance; + struct in_addr ip; + uint32_t device_type; + uint32_t max_streams; }; /* PortMessage */ #define PORT_MESSAGE 0x0002 +struct port_message { + uint16_t port; +}; /* KeypadButtonMessage */ #define KEYPAD_BUTTON_MESSAGE 0x0003 struct keypad_button_message { - uint32_t button; - uint32_t line_instance; - uint32_t call_id; + uint32_t button; + uint32_t line_instance; + uint32_t call_id; }; /* StimulusMessage */ #define STIMULUS_MESSAGE 0x0005 struct stimulus_message { - uint32_t instance_type; /* See enum skinny_button_definition */ - uint32_t instance; - /* uint32_t call_reference; */ + uint32_t instance_type; /* See enum skinny_button_definition */ + uint32_t instance; + uint32_t call_id; }; /* OffHookMessage */ #define OFF_HOOK_MESSAGE 0x0006 struct off_hook_message { - uint32_t line_instance; - /* uint32_t call_id; */ + uint32_t line_instance; + uint32_t call_id; }; /* OnHookMessage */ #define ON_HOOK_MESSAGE 0x0007 struct on_hook_message { - uint32_t line_instance; - uint32_t call_id; + uint32_t line_instance; + uint32_t call_id; }; /* SpeedDialStatReqMessage */ #define SPEED_DIAL_STAT_REQ_MESSAGE 0x000A struct speed_dial_stat_req_message { - uint32_t number; + uint32_t number; }; /* LineStatReqMessage */ #define LINE_STAT_REQ_MESSAGE 0x000B struct line_stat_req_message { - uint32_t number; + uint32_t number; }; /* ConfigStatReqMessage */ @@ -114,32 +117,32 @@ struct line_stat_req_message { /* CapabilitiesResMessage */ #define CAPABILITIES_RES_MESSAGE 0x0010 struct station_capabilities { - uint32_t codec; - uint16_t frames; - char reserved[10]; + uint32_t codec; + uint16_t frames; + char reserved[10]; }; struct capabilities_res_message { - uint32_t count; - struct station_capabilities caps[SWITCH_MAX_CODECS]; + uint32_t count; + struct station_capabilities caps[SWITCH_MAX_CODECS]; }; /* AlarmMessage */ #define ALARM_MESSAGE 0x0020 struct alarm_message { - uint32_t alarm_severity; - char display_message[80]; - uint32_t alarm_param1; - uint32_t alarm_param2; + uint32_t alarm_severity; + char display_message[80]; + uint32_t alarm_param1; + uint32_t alarm_param2; }; /* OpenReceiveChannelAck */ #define OPEN_RECEIVE_CHANNEL_ACK_MESSAGE 0x0022 struct open_receive_channel_ack_message { - uint32_t status; - struct in_addr ip; - uint32_t port; - uint32_t pass_thru_party_id; + uint32_t status; + struct in_addr ip; + uint32_t port; + uint32_t pass_thru_party_id; }; /* SoftKeySetReqMessage */ @@ -148,9 +151,9 @@ struct open_receive_channel_ack_message { /* SoftKeyEventMessage */ #define SOFT_KEY_EVENT_MESSAGE 0x0026 struct soft_key_event_message { - uint32_t event; - uint32_t line_instance; - uint32_t callreference; + uint32_t event; + uint32_t line_instance; + uint32_t call_id; }; /* UnregisterMessage */ @@ -162,196 +165,197 @@ struct soft_key_event_message { /* ServiceUrlStatReqMessage */ #define SERVICE_URL_STAT_REQ_MESSAGE 0x0033 struct service_url_stat_req_message { - uint32_t service_url_index; + uint32_t service_url_index; }; /* FeatureStatReqMessage */ #define FEATURE_STAT_REQ_MESSAGE 0x0034 struct feature_stat_req_message { - uint32_t feature_index; + uint32_t feature_index; }; /* HeadsetStatusMessage */ #define HEADSET_STATUS_MESSAGE 0x002B struct headset_status_message { - uint32_t mode; + uint32_t mode; }; /* RegisterAvailableLinesMessage */ #define REGISTER_AVAILABLE_LINES_MESSAGE 0x002D struct register_available_lines_message { - uint32_t count; + uint32_t count; }; /* RegisterAckMessage */ #define REGISTER_ACK_MESSAGE 0x0081 struct register_ack_message { - uint32_t keepAlive; - char dateFormat[6]; - char reserved[2]; - uint32_t secondaryKeepAlive; - char reserved2[4]; + uint32_t keep_alive; + char date_format[6]; + char reserved[2]; + uint32_t secondary_keep_alive; + char reserved2[4]; }; /* StartToneMessage */ #define START_TONE_MESSAGE 0x0082 struct start_tone_message { - uint32_t tone; /* see enum skinny_tone */ - uint32_t reserved; - uint32_t line_instance; - uint32_t call_id; + uint32_t tone; /* see enum skinny_tone */ + uint32_t reserved; + uint32_t line_instance; + uint32_t call_id; }; /* StopToneMessage */ #define STOP_TONE_MESSAGE 0x0083 struct stop_tone_message { - uint32_t line_instance; - uint32_t call_id; + uint32_t line_instance; + uint32_t call_id; }; /* SetRingerMessage */ #define SET_RINGER_MESSAGE 0x0085 struct set_ringer_message { - uint32_t ring_type; /* See enum skinny_ring_type */ - uint32_t ring_mode; /* See enum skinny_ring_mode */ - uint32_t unknown; /* ?? */ + uint32_t ring_type; /* See enum skinny_ring_type */ + uint32_t ring_mode; /* See enum skinny_ring_mode */ + uint32_t line_instance; + uint32_t call_id; }; /* SetLampMessage */ #define SET_LAMP_MESSAGE 0x0086 struct set_lamp_message { - uint32_t stimulus; /* See enum skinny_button_definition */ - uint32_t stimulus_instance; - uint32_t mode; /* See enum skinny_lamp_mode */ + uint32_t stimulus; /* See enum skinny_button_definition */ + uint32_t stimulus_instance; + uint32_t mode; /* See enum skinny_lamp_mode */ }; /* SetSpeakerModeMessage */ #define SET_SPEAKER_MODE_MESSAGE 0x0088 struct set_speaker_mode_message { - uint32_t mode; /* See enum skinny_speaker_mode */ + uint32_t mode; /* See enum skinny_speaker_mode */ }; /* StartMediaTransmissionMessage */ #define START_MEDIA_TRANSMISSION_MESSAGE 0x008A struct start_media_transmission_message { - uint32_t conference_id; - uint32_t pass_thru_party_id; - uint32_t remote_ip; - uint32_t remote_port; - uint32_t ms_per_packet; - uint32_t payload_capacity; - uint32_t precedence; - uint32_t silence_suppression; - uint16_t max_frames_per_packet; - uint32_t g723_bitrate; - /* ... */ + uint32_t conference_id; + uint32_t pass_thru_party_id; + uint32_t remote_ip; + uint32_t remote_port; + uint32_t ms_per_packet; + uint32_t payload_capacity; + uint32_t precedence; + uint32_t silence_suppression; + uint16_t max_frames_per_packet; + uint32_t g723_bitrate; + /* ... */ }; /* StopMediaTransmissionMessage */ #define STOP_MEDIA_TRANSMISSION_MESSAGE 0x008B struct stop_media_transmission_message { - uint32_t conference_id; - uint32_t pass_thru_party_id; - uint32_t conference_id2; - /* ... */ + uint32_t conference_id; + uint32_t pass_thru_party_id; + uint32_t conference_id2; + /* ... */ }; /* CallInfoMessage */ #define CALL_INFO_MESSAGE 0x008F struct call_info_message { - char calling_party_name[40]; - char calling_party[24]; - char called_party_name[40]; - char called_party[24]; - uint32_t line_instance; - uint32_t call_id; - uint32_t call_type; /* See enum skinny_call_type */ - char original_called_party_name[40]; - char original_called_party[24]; - char last_redirecting_party_name[40]; - char last_redirecting_party[24]; - uint32_t original_called_party_redirect_reason; - uint32_t last_redirecting_reason; - char calling_party_voice_mailbox[24]; - char called_party_voice_mailbox[24]; - char original_called_party_voice_mailbox[24]; - char last_redirecting_voice_mailbox[24]; - uint32_t call_instance; - uint32_t call_security_status; - uint32_t party_pi_restriction_bits; + char calling_party_name[40]; + char calling_party[24]; + char called_party_name[40]; + char called_party[24]; + uint32_t line_instance; + uint32_t call_id; + uint32_t call_type; /* See enum skinny_call_type */ + char original_called_party_name[40]; + char original_called_party[24]; + char last_redirecting_party_name[40]; + char last_redirecting_party[24]; + uint32_t original_called_party_redirect_reason; + uint32_t last_redirecting_reason; + char calling_party_voice_mailbox[24]; + char called_party_voice_mailbox[24]; + char original_called_party_voice_mailbox[24]; + char last_redirecting_voice_mailbox[24]; + uint32_t call_instance; + uint32_t call_security_status; + uint32_t party_pi_restriction_bits; }; /* SpeedDialStatMessage */ #define SPEED_DIAL_STAT_RES_MESSAGE 0x0091 struct speed_dial_stat_res_message { - uint32_t number; - char line[24]; - char label[40]; + uint32_t number; + char line[24]; + char label[40]; }; /* LineStatMessage */ #define LINE_STAT_RES_MESSAGE 0x0092 struct line_stat_res_message { - uint32_t number; - char name[24]; - char shortname[40]; - char displayname[44]; + uint32_t number; + char name[24]; + char shortname[40]; + char displayname[44]; }; /* ConfigStatMessage */ #define CONFIG_STAT_RES_MESSAGE 0x0093 struct config_stat_res_message { - char device_name[16]; - uint32_t user_id; - uint32_t instance; - char user_name[40]; - char server_name[40]; - uint32_t number_lines; - uint32_t number_speed_dials; + char device_name[16]; + uint32_t user_id; + uint32_t instance; + char user_name[40]; + char server_name[40]; + uint32_t number_lines; + uint32_t number_speed_dials; }; /* DefineTimeDate */ #define DEFINE_TIME_DATE_MESSAGE 0x0094 struct define_time_date_message { - uint32_t year; - uint32_t month; - uint32_t day_of_week; /* monday = 1 */ - uint32_t day; - uint32_t hour; - uint32_t minute; - uint32_t seconds; - uint32_t milliseconds; - uint32_t timestamp; + uint32_t year; + uint32_t month; + uint32_t day_of_week; /* monday = 1 */ + uint32_t day; + uint32_t hour; + uint32_t minute; + uint32_t seconds; + uint32_t milliseconds; + uint32_t timestamp; }; /* ButtonTemplateMessage */ #define BUTTON_TEMPLATE_RES_MESSAGE 0x0097 struct button_definition { - uint8_t instance_number; - uint8_t button_definition; /* See enum skinny_button_definition */ + uint8_t instance_number; + uint8_t button_definition; /* See enum skinny_button_definition */ }; #define SKINNY_MAX_BUTTON_COUNT 42 struct button_template_message { - uint32_t button_offset; - uint32_t button_count; - uint32_t total_button_count; - struct button_definition btn[SKINNY_MAX_BUTTON_COUNT]; + uint32_t button_offset; + uint32_t button_count; + uint32_t total_button_count; + struct button_definition btn[SKINNY_MAX_BUTTON_COUNT]; }; /* CapabilitiesReqMessage */ #define CAPABILITIES_REQ_MESSAGE 0x009B /* RegisterRejectMessage */ -#define REGISTER_REJ_MESSAGE 0x009D -struct register_rej_message { - char error[33]; +#define REGISTER_REJECT_MESSAGE 0x009D +struct register_reject_message { + char error[33]; }; /* ResetMessage */ #define RESET_MESSAGE 0x009F struct reset_message { - uint32_t reset_type; /* See enum skinny_device_reset_types */ + uint32_t reset_type; /* See enum skinny_device_reset_types */ }; /* KeepAliveAckMessage */ @@ -360,122 +364,130 @@ struct reset_message { /* OpenReceiveChannelMessage */ #define OPEN_RECEIVE_CHANNEL_MESSAGE 0x0105 struct open_receive_channel_message { - uint32_t conference_id; - uint32_t pass_thru_party_id; - uint32_t packets; - uint32_t payload_capacity; - uint32_t echo_cancel_type; - uint32_t g723_bitrate; - uint32_t conference_id2; - uint32_t reserved[10]; + uint32_t conference_id; + uint32_t pass_thru_party_id; + uint32_t packets; + uint32_t payload_capacity; + uint32_t echo_cancel_type; + uint32_t g723_bitrate; + uint32_t conference_id2; + uint32_t reserved[10]; }; /* CloseReceiveChannelMessage */ #define CLOSE_RECEIVE_CHANNEL_MESSAGE 0x0106 struct close_receive_channel_message { - uint32_t conference_id; - uint32_t pass_thru_party_id; - uint32_t conference_id2; + uint32_t conference_id; + uint32_t pass_thru_party_id; + uint32_t conference_id2; }; /* SoftKeyTemplateResMessage */ #define SOFT_KEY_TEMPLATE_RES_MESSAGE 0x0108 struct soft_key_template_definition { - char soft_key_label[16]; - uint32_t soft_key_event; + char soft_key_label[16]; + uint32_t soft_key_event; }; struct soft_key_template_res_message { - uint32_t soft_key_offset; - uint32_t soft_key_count; - uint32_t total_soft_key_count; - struct soft_key_template_definition soft_key[32]; + uint32_t soft_key_offset; + uint32_t soft_key_count; + uint32_t total_soft_key_count; + struct soft_key_template_definition soft_key[32]; }; /* SoftKeySetResMessage */ #define SOFT_KEY_SET_RES_MESSAGE 0x0109 struct soft_key_set_definition { - uint8_t soft_key_template_index[16]; /* See enum skinny_soft_key_event */ - uint16_t soft_key_info_index[16]; + uint8_t soft_key_template_index[16]; /* See enum skinny_soft_key_event */ + uint16_t soft_key_info_index[16]; }; struct soft_key_set_res_message { - uint32_t soft_key_set_offset; - uint32_t soft_key_set_count; - uint32_t total_soft_key_set_count; - struct soft_key_set_definition soft_key_set[16]; - uint32_t res; + uint32_t soft_key_set_offset; + uint32_t soft_key_set_count; + uint32_t total_soft_key_set_count; + struct soft_key_set_definition soft_key_set[16]; + uint32_t res; }; /* SelectSoftKeysMessage */ #define SELECT_SOFT_KEYS_MESSAGE 0x0110 struct select_soft_keys_message { - uint32_t line_instance; - uint32_t call_id; - uint32_t soft_key_set; /* See enum skinny_key_set */ - uint32_t valid_key_mask; + uint32_t line_instance; + uint32_t call_id; + uint32_t soft_key_set; /* See enum skinny_key_set */ + uint32_t valid_key_mask; }; /* CallStateMessage */ #define CALL_STATE_MESSAGE 0x0111 struct call_state_message { - uint32_t call_state; /* See enum skinny_call_state */ - uint32_t line_instance; - uint32_t call_id; + uint32_t call_state; /* See enum skinny_call_state */ + uint32_t line_instance; + uint32_t call_id; }; /* DisplayPromptStatusMessage */ #define DISPLAY_PROMPT_STATUS_MESSAGE 0x0112 struct display_prompt_status_message { - uint32_t timeout; - char display[32]; - uint32_t line_instance; - uint32_t call_id; + uint32_t timeout; + char display[32]; + uint32_t line_instance; + uint32_t call_id; }; /* ClearPromptStatusMessage */ #define CLEAR_PROMPT_STATUS_MESSAGE 0x0113 struct clear_prompt_status_message { - uint32_t line_instance; - uint32_t call_id; + uint32_t line_instance; + uint32_t call_id; }; /* ActivateCallPlaneMessage */ #define ACTIVATE_CALL_PLANE_MESSAGE 0x0116 struct activate_call_plane_message { - uint32_t line_instance; + uint32_t line_instance; }; /* UnregisterAckMessage */ #define UNREGISTER_ACK_MESSAGE 0x0118 struct unregister_ack_message { - uint32_t unregister_status; + uint32_t unregister_status; }; /* DialedNumberMessage */ #define DIALED_NUMBER_MESSAGE 0x011D struct dialed_number_message { - char called_party[24]; - uint32_t line_instance; - uint32_t call_id; + char called_party[24]; + uint32_t line_instance; + uint32_t call_id; }; /* FeatureStatMessage */ #define FEATURE_STAT_RES_MESSAGE 0x011F struct feature_stat_res_message { - uint32_t index; - uint32_t id; - char text_label[40]; - uint32_t status; + uint32_t index; + uint32_t id; + char text_label[40]; + uint32_t status; +}; + +/* DisplayPriNotifyMessage */ +#define DISPLAY_PRI_NOTIFY_MESSAGE 0x0120 +struct display_pri_notify_message { + uint32_t message_timeout; + uint32_t priority; + char notify[32]; }; /* ServiceUrlStatMessage */ #define SERVICE_URL_STAT_RES_MESSAGE 0x012F struct service_url_stat_res_message { - uint32_t index; - char url[256]; - char display_name[40]; + uint32_t index; + char url[256]; + char display_name[40]; }; /*****************************************************************************/ @@ -486,54 +498,56 @@ struct service_url_stat_res_message { #define SKINNY_MESSAGE_MAXSIZE 1000 union skinny_data { - struct register_message reg; - struct keypad_button_message keypad_button; - struct stimulus_message stimulus; - struct off_hook_message off_hook; - struct on_hook_message on_hook; - struct speed_dial_stat_req_message speed_dial_req; - struct line_stat_req_message line_req; - struct capabilities_res_message cap_res; - struct alarm_message alarm; - struct open_receive_channel_ack_message open_receive_channel_ack; - struct soft_key_event_message soft_key_event; - struct service_url_stat_req_message service_url_req; - struct feature_stat_req_message feature_req; - struct headset_status_message headset_status; - struct register_available_lines_message reg_lines; - struct register_ack_message reg_ack; - struct start_tone_message start_tone; - struct stop_tone_message stop_tone; - struct set_ringer_message ringer; - struct set_lamp_message lamp; - struct set_speaker_mode_message speaker_mode; - struct start_media_transmission_message start_media; - struct stop_media_transmission_message stop_media; - struct call_info_message call_info; - struct speed_dial_stat_res_message speed_dial_res; - struct line_stat_res_message line_res; - struct config_stat_res_message config_res; - struct define_time_date_message define_time_date; - struct button_template_message button_template; - struct register_rej_message reg_rej; - struct reset_message reset; - struct open_receive_channel_message open_receive_channel; - struct close_receive_channel_message close_receive_channel; - struct soft_key_template_res_message soft_key_template; - struct soft_key_set_res_message soft_key_set; - struct select_soft_keys_message select_soft_keys; - struct call_state_message call_state; - struct display_prompt_status_message display_prompt_status; - struct clear_prompt_status_message clear_prompt_status; - struct activate_call_plane_message activate_call_plane; - struct unregister_ack_message unregister_ack; - struct dialed_number_message dialed_number; - struct feature_stat_res_message feature_res; - struct service_url_stat_res_message service_url_res; - - uint16_t as_uint16; - char as_char; - void *raw; + struct register_message reg; + struct port_message port; + struct keypad_button_message keypad_button; + struct stimulus_message stimulus; + struct off_hook_message off_hook; + struct on_hook_message on_hook; + struct speed_dial_stat_req_message speed_dial_req; + struct line_stat_req_message line_req; + struct capabilities_res_message cap_res; + struct alarm_message alarm; + struct open_receive_channel_ack_message open_receive_channel_ack; + struct soft_key_event_message soft_key_event; + struct service_url_stat_req_message service_url_req; + struct feature_stat_req_message feature_req; + struct headset_status_message headset_status; + struct register_available_lines_message reg_lines; + struct register_ack_message reg_ack; + struct start_tone_message start_tone; + struct stop_tone_message stop_tone; + struct set_ringer_message ringer; + struct set_lamp_message lamp; + struct set_speaker_mode_message speaker_mode; + struct start_media_transmission_message start_media; + struct stop_media_transmission_message stop_media; + struct call_info_message call_info; + struct speed_dial_stat_res_message speed_dial_res; + struct line_stat_res_message line_res; + struct config_stat_res_message config_res; + struct define_time_date_message define_time_date; + struct button_template_message button_template; + struct register_reject_message reg_rej; + struct reset_message reset; + struct open_receive_channel_message open_receive_channel; + struct close_receive_channel_message close_receive_channel; + struct soft_key_template_res_message soft_key_template; + struct soft_key_set_res_message soft_key_set; + struct select_soft_keys_message select_soft_keys; + struct call_state_message call_state; + struct display_prompt_status_message display_prompt_status; + struct clear_prompt_status_message clear_prompt_status; + struct activate_call_plane_message activate_call_plane; + struct unregister_ack_message unregister_ack; + struct dialed_number_message dialed_number; + struct feature_stat_res_message feature_res; + struct display_pri_notify_message display_pri_notify; + struct service_url_stat_res_message service_url_res; + + uint16_t as_uint16; + char as_char; + void *raw; }; /* @@ -541,10 +555,10 @@ union skinny_data { * body is type+data */ struct skinny_message { - uint32_t length; - uint32_t reserved; - uint32_t type; - union skinny_data data; + uint32_t length; + uint32_t reserved; + uint32_t type; + union skinny_data data; }; typedef struct skinny_message skinny_message_t; @@ -552,40 +566,40 @@ typedef struct skinny_message skinny_message_t; /* SKINNY TYPES */ /*****************************************************************************/ enum skinny_codecs { - SKINNY_CODEC_ALAW_64K = 2, - SKINNY_CODEC_ALAW_56K = 3, - SKINNY_CODEC_ULAW_64K = 4, - SKINNY_CODEC_ULAW_56K = 5, - SKINNY_CODEC_G722_64K = 6, - SKINNY_CODEC_G722_56K = 7, - SKINNY_CODEC_G722_48K = 8, - SKINNY_CODEC_G723_1 = 9, - SKINNY_CODEC_G728 = 10, - SKINNY_CODEC_G729 = 11, - SKINNY_CODEC_G729A = 12, - SKINNY_CODEC_IS11172 = 13, - SKINNY_CODEC_IS13818 = 14, - SKINNY_CODEC_G729B = 15, - SKINNY_CODEC_G729AB = 16, - SKINNY_CODEC_GSM_FULL = 18, - SKINNY_CODEC_GSM_HALF = 19, - SKINNY_CODEC_GSM_EFULL = 20, - SKINNY_CODEC_WIDEBAND_256K = 25, - SKINNY_CODEC_DATA_64K = 32, - SKINNY_CODEC_DATA_56K = 33, - SKINNY_CODEC_GSM = 80, - SKINNY_CODEC_ACTIVEVOICE = 81, - SKINNY_CODEC_G726_32K = 82, - SKINNY_CODEC_G726_24K = 83, - SKINNY_CODEC_G726_16K = 84, - SKINNY_CODEC_G729B_BIS = 85, - SKINNY_CODEC_G729B_LOW = 86, - SKINNY_CODEC_H261 = 100, - SKINNY_CODEC_H263 = 101, - SKINNY_CODEC_VIDEO = 102, - SKINNY_CODEC_T120 = 105, - SKINNY_CODEC_H224 = 106, - SKINNY_CODEC_RFC2833_DYNPAYLOAD = 257 + SKINNY_CODEC_ALAW_64K = 2, + SKINNY_CODEC_ALAW_56K = 3, + SKINNY_CODEC_ULAW_64K = 4, + SKINNY_CODEC_ULAW_56K = 5, + SKINNY_CODEC_G722_64K = 6, + SKINNY_CODEC_G722_56K = 7, + SKINNY_CODEC_G722_48K = 8, + SKINNY_CODEC_G723_1 = 9, + SKINNY_CODEC_G728 = 10, + SKINNY_CODEC_G729 = 11, + SKINNY_CODEC_G729A = 12, + SKINNY_CODEC_IS11172 = 13, + SKINNY_CODEC_IS13818 = 14, + SKINNY_CODEC_G729B = 15, + SKINNY_CODEC_G729AB = 16, + SKINNY_CODEC_GSM_FULL = 18, + SKINNY_CODEC_GSM_HALF = 19, + SKINNY_CODEC_GSM_EFULL = 20, + SKINNY_CODEC_WIDEBAND_256K = 25, + SKINNY_CODEC_DATA_64K = 32, + SKINNY_CODEC_DATA_56K = 33, + SKINNY_CODEC_GSM = 80, + SKINNY_CODEC_ACTIVEVOICE = 81, + SKINNY_CODEC_G726_32K = 82, + SKINNY_CODEC_G726_24K = 83, + SKINNY_CODEC_G726_16K = 84, + SKINNY_CODEC_G729B_BIS = 85, + SKINNY_CODEC_G729B_LOW = 86, + SKINNY_CODEC_H261 = 100, + SKINNY_CODEC_H263 = 101, + SKINNY_CODEC_VIDEO = 102, + SKINNY_CODEC_T120 = 105, + SKINNY_CODEC_H224 = 106, + SKINNY_CODEC_RFC2833_DYNPAYLOAD = 257 }; typedef switch_status_t (*skinny_command_t) (char **argv, int argc, switch_stream_handle_t *stream); @@ -594,20 +608,28 @@ typedef switch_status_t (*skinny_command_t) (char **argv, int argc, switch_strea /* SKINNY FUNCTIONS */ /*****************************************************************************/ #define skinny_check_data_length(message, len) \ - if (message->length < len+4) {\ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Received Too Short Skinny Message (Expected %" SWITCH_SIZE_T_FMT ", got %d).\n", len+4, message->length);\ - return SWITCH_STATUS_FALSE;\ - } + if (message->length < len+4) {\ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Received Too Short Skinny Message (Expected %" SWITCH_SIZE_T_FMT ", got %d).\n", len+4, message->length);\ + return SWITCH_STATUS_FALSE;\ + } +#define skinny_check_data_length_soft(message, len) \ + (message->length >= len+4) switch_status_t skinny_read_packet(listener_t *listener, skinny_message_t **req); switch_status_t skinny_device_event(listener_t *listener, switch_event_t **ev, switch_event_types_t event_id, const char *subclass_name); -switch_status_t skinny_send_call_info(switch_core_session_t *session); +switch_status_t skinny_send_call_info(switch_core_session_t *session, listener_t *listener, uint32_t line_instance); +switch_status_t skinny_session_walk_lines(skinny_profile_t *profile, char *channel_uuid, switch_core_db_callback_func_t callback, void *data); +switch_call_cause_t skinny_ring_lines(private_t *tech_pvt); -switch_status_t skinny_create_session(listener_t *listener, uint32_t line, uint32_t to_state); -switch_status_t skinny_process_dest(listener_t *listener, uint32_t line); -switch_status_t skinny_answer(switch_core_session_t *session); +switch_status_t skinny_create_ingoing_session(listener_t *listener, uint32_t *line_instance, switch_core_session_t **session); +switch_status_t skinny_session_process_dest(switch_core_session_t *session, listener_t *listener, uint32_t line_instance, char *dest, char append_dest, uint32_t backspace); +switch_status_t skinny_session_ring_out(switch_core_session_t *session, listener_t *listener, uint32_t line_instance); +switch_status_t skinny_session_answer(switch_core_session_t *session, listener_t *listener, uint32_t line_instance); +switch_status_t skinny_session_start_media(switch_core_session_t *session, listener_t *listener, uint32_t line_instance); +switch_status_t skinny_session_hold_line(switch_core_session_t *session, listener_t *listener, uint32_t line_instance); +switch_status_t skinny_session_unhold_line(switch_core_session_t *session, listener_t *listener, uint32_t line_instance); void skinny_line_get(listener_t *listener, uint32_t instance, struct line_stat_res_message **button); void skinny_speed_dial_get(listener_t *listener, uint32_t instance, struct speed_dial_stat_res_message **button); @@ -620,98 +642,131 @@ switch_status_t skinny_handle_request(listener_t *listener, skinny_message_t *re /*****************************************************************************/ /* SKINNY MESSAGE HELPER */ /*****************************************************************************/ -switch_status_t start_tone(listener_t *listener, - uint32_t tone, - uint32_t reserved, - uint32_t line_instance, - uint32_t call_id); -switch_status_t stop_tone(listener_t *listener, - uint32_t line_instance, - uint32_t call_id); -switch_status_t set_ringer(listener_t *listener, - uint32_t ring_type, - uint32_t ring_mode, - uint32_t unknown); -switch_status_t set_lamp(listener_t *listener, - uint32_t stimulus, - uint32_t stimulus_instance, - uint32_t mode); -switch_status_t set_speaker_mode(listener_t *listener, - uint32_t mode); -switch_status_t start_media_transmission(listener_t *listener, - uint32_t conference_id, - uint32_t pass_thru_party_id, - uint32_t remote_ip, - uint32_t remote_port, - uint32_t ms_per_packet, - uint32_t payload_capacity, - uint32_t precedence, - uint32_t silence_suppression, - uint16_t max_frames_per_packet, - uint32_t g723_bitrate); -switch_status_t stop_media_transmission(listener_t *listener, - uint32_t conference_id, - uint32_t pass_thru_party_id, - uint32_t conference_id2); +switch_status_t send_register_ack(listener_t *listener, + uint32_t keep_alive, + char *date_format, + char *reserved, + uint32_t secondary_keep_alive, + char *reserved2); +switch_status_t send_start_tone(listener_t *listener, + uint32_t tone, + uint32_t reserved, + uint32_t line_instance, + uint32_t call_id); +switch_status_t send_stop_tone(listener_t *listener, + uint32_t line_instance, + uint32_t call_id); +switch_status_t send_set_ringer(listener_t *listener, + uint32_t ring_type, + uint32_t ring_mode, + uint32_t line_instance, + uint32_t call_id); +switch_status_t send_set_lamp(listener_t *listener, + uint32_t stimulus, + uint32_t stimulus_instance, + uint32_t mode); +switch_status_t send_set_speaker_mode(listener_t *listener, + uint32_t mode); +switch_status_t send_start_media_transmission(listener_t *listener, + uint32_t conference_id, + uint32_t pass_thru_party_id, + uint32_t remote_ip, + uint32_t remote_port, + uint32_t ms_per_packet, + uint32_t payload_capacity, + uint32_t precedence, + uint32_t silence_suppression, + uint16_t max_frames_per_packet, + uint32_t g723_bitrate); +switch_status_t send_stop_media_transmission(listener_t *listener, + uint32_t conference_id, + uint32_t pass_thru_party_id, + uint32_t conference_id2); switch_status_t send_call_info(listener_t *listener, - char calling_party_name[40], - char calling_party[24], - char called_party_name[40], - char called_party[24], - uint32_t line_instance, - uint32_t call_id, - uint32_t call_type, - char original_called_party_name[40], - char original_called_party[24], - char last_redirecting_party_name[40], - char last_redirecting_party[24], - uint32_t original_called_party_redirect_reason, - uint32_t last_redirecting_reason, - char calling_party_voice_mailbox[24], - char called_party_voice_mailbox[24], - char original_called_party_voice_mailbox[24], - char last_redirecting_voice_mailbox[24], - uint32_t call_instance, - uint32_t call_security_status, - uint32_t party_pi_restriction_bits); -switch_status_t open_receive_channel(listener_t *listener, - uint32_t conference_id, - uint32_t pass_thru_party_id, - uint32_t packets, - uint32_t payload_capacity, - uint32_t echo_cancel_type, - uint32_t g723_bitrate, - uint32_t conference_id2, - uint32_t reserved[10]); -switch_status_t close_receive_channel(listener_t *listener, - uint32_t conference_id, - uint32_t pass_thru_party_id, - uint32_t conference_id2); + char calling_party_name[40], + char calling_party[24], + char called_party_name[40], + char called_party[24], + uint32_t line_instance, + uint32_t call_id, + uint32_t call_type, + char original_called_party_name[40], + char original_called_party[24], + char last_redirecting_party_name[40], + char last_redirecting_party[24], + uint32_t original_called_party_redirect_reason, + uint32_t last_redirecting_reason, + char calling_party_voice_mailbox[24], + char called_party_voice_mailbox[24], + char original_called_party_voice_mailbox[24], + char last_redirecting_voice_mailbox[24], + uint32_t call_instance, + uint32_t call_security_status, + uint32_t party_pi_restriction_bits); +switch_status_t send_define_time_date(listener_t *listener, + uint32_t year, + uint32_t month, + uint32_t day_of_week, /* monday = 1 */ + uint32_t day, + uint32_t hour, + uint32_t minute, + uint32_t seconds, + uint32_t milliseconds, + uint32_t timestamp); +switch_status_t send_define_current_time_date(listener_t *listener); +switch_status_t send_open_receive_channel(listener_t *listener, + uint32_t conference_id, + uint32_t pass_thru_party_id, + uint32_t packets, + uint32_t payload_capacity, + uint32_t echo_cancel_type, + uint32_t g723_bitrate, + uint32_t conference_id2, + uint32_t reserved[10]); +switch_status_t send_close_receive_channel(listener_t *listener, + uint32_t conference_id, + uint32_t pass_thru_party_id, + uint32_t conference_id2); switch_status_t send_select_soft_keys(listener_t *listener, - uint32_t line_instance, - uint32_t call_id, - uint32_t soft_key_set, - uint32_t valid_key_mask); + uint32_t line_instance, + uint32_t call_id, + uint32_t soft_key_set, + uint32_t valid_key_mask); switch_status_t send_call_state(listener_t *listener, - uint32_t call_state, - uint32_t line_instance, - uint32_t call_id); -switch_status_t display_prompt_status(listener_t *listener, - uint32_t timeout, - char display[32], - uint32_t line_instance, - uint32_t call_id); -switch_status_t clear_prompt_status(listener_t *listener, - uint32_t line_instance, - uint32_t call_id); -switch_status_t activate_call_plane(listener_t *listener, - uint32_t line_instance); + uint32_t call_state, + uint32_t line_instance, + uint32_t call_id); +switch_status_t send_display_prompt_status(listener_t *listener, + uint32_t timeout, + char display[32], + uint32_t line_instance, + uint32_t call_id); +switch_status_t send_clear_prompt_status(listener_t *listener, + uint32_t line_instance, + uint32_t call_id); +switch_status_t send_activate_call_plane(listener_t *listener, + uint32_t line_instance); switch_status_t send_dialed_number(listener_t *listener, - char called_party[24], - uint32_t line_instance, - uint32_t call_id); + char called_party[24], + uint32_t line_instance, + uint32_t call_id); +switch_status_t send_display_pri_notify(listener_t *listener, + uint32_t message_timeout, + uint32_t priority, + char *notify); switch_status_t send_reset(listener_t *listener, - uint32_t reset_type); + uint32_t reset_type); #endif /* _SKINNY_PROTOCOL_H */ +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4: + */ + diff --git a/src/mod/endpoints/mod_skinny/skinny_tables.c b/src/mod/endpoints/mod_skinny/skinny_tables.c index 667ae3cd63..5ddd53ac87 100644 --- a/src/mod/endpoints/mod_skinny/skinny_tables.c +++ b/src/mod/endpoints/mod_skinny/skinny_tables.c @@ -35,157 +35,169 @@ /* Translation tables */ struct skinny_table SKINNY_MESSAGE_TYPES[] = { - {"KeepAliveMessage", KEEP_ALIVE_MESSAGE}, - {"RegisterMessage", REGISTER_MESSAGE}, - {"PortMessage", PORT_MESSAGE}, - {"KeypadButtonMessage", KEYPAD_BUTTON_MESSAGE}, - {"StimulusMessage", STIMULUS_MESSAGE}, - {"OffHookMessage", OFF_HOOK_MESSAGE}, - {"OnHookMessage", ON_HOOK_MESSAGE}, - {"SpeedDialStatReqMessage", SPEED_DIAL_STAT_REQ_MESSAGE}, - {"LineStatReqMessage", LINE_STAT_REQ_MESSAGE}, - {"ConfigStatReqMessage", CONFIG_STAT_REQ_MESSAGE}, - {"TimeDateReqMessage", TIME_DATE_REQ_MESSAGE}, - {"ButtonTemplateReqMessage", BUTTON_TEMPLATE_REQ_MESSAGE}, - {"CapabilitiesReqMessage", CAPABILITIES_RES_MESSAGE}, - {"AlarmMessage", ALARM_MESSAGE}, - {"OpenReceiveChannelAckMessage", OPEN_RECEIVE_CHANNEL_ACK_MESSAGE}, - {"SoftKeySetReqMessage", SOFT_KEY_SET_REQ_MESSAGE}, - {"SoftKeyEventMessage", SOFT_KEY_EVENT_MESSAGE}, - {"UnregisterMessage", UNREGISTER_MESSAGE}, - {"SoftKeyTemplateReqMessage", SOFT_KEY_TEMPLATE_REQ_MESSAGE}, - {"ServiceUrlStatReqMessage", SERVICE_URL_STAT_REQ_MESSAGE}, - {"FeatureStatReqMessage", FEATURE_STAT_REQ_MESSAGE}, - {"HeadsetStatusMessage", HEADSET_STATUS_MESSAGE}, - {"RegisterAvailableLinesMessage", REGISTER_AVAILABLE_LINES_MESSAGE}, - {"RegisterAckMessage", REGISTER_ACK_MESSAGE}, - {"StartToneMessage", START_TONE_MESSAGE}, - {"StopToneMessage", STOP_TONE_MESSAGE}, - {"SetRingerMessage", SET_RINGER_MESSAGE}, - {"SetLampMessage", SET_LAMP_MESSAGE}, - {"SetSpeakerModeMessage", SET_SPEAKER_MODE_MESSAGE}, - {"StartMediaTransmissionMessage", START_MEDIA_TRANSMISSION_MESSAGE}, - {"StopMediaTransmissionMessage", STOP_MEDIA_TRANSMISSION_MESSAGE}, - {"CallInfoMessage", CALL_INFO_MESSAGE}, - {"SpeedDialStatResMessage", SPEED_DIAL_STAT_RES_MESSAGE}, - {"LineStatResMessage", LINE_STAT_RES_MESSAGE}, - {"ConfigStatResMessage", CONFIG_STAT_RES_MESSAGE}, - {"DefineTimeDateMessage", DEFINE_TIME_DATE_MESSAGE}, - {"ButtonTemplateResMessage", BUTTON_TEMPLATE_RES_MESSAGE}, - {"CapabilitiesReqMessage", CAPABILITIES_REQ_MESSAGE}, - {"RegisterRejMessage", REGISTER_REJ_MESSAGE}, - {"ResetMessage", RESET_MESSAGE}, - {"KeepAliveAckMessage", KEEP_ALIVE_ACK_MESSAGE}, - {"OpenReceiveChannelMessage", OPEN_RECEIVE_CHANNEL_MESSAGE}, - {"OCloseReceiveChannelMessage", CLOSE_RECEIVE_CHANNEL_MESSAGE}, - {"SoftKeyTemplateResMessage", SOFT_KEY_TEMPLATE_RES_MESSAGE}, - {"SoftKeySetResMessage", SOFT_KEY_SET_RES_MESSAGE}, - {"SelectSoftKeysMessage", SELECT_SOFT_KEYS_MESSAGE}, - {"CallStateMessage", CALL_STATE_MESSAGE}, - {"DisplayPromptStatusMessage", DISPLAY_PROMPT_STATUS_MESSAGE}, - {"ClearPromptStatusMessage", CLEAR_PROMPT_STATUS_MESSAGE}, - {"ActivateCallPlaneMessage", ACTIVATE_CALL_PLANE_MESSAGE}, - {"UnregisterAckMessage", UNREGISTER_ACK_MESSAGE}, - {"DialedNumberMessage", DIALED_NUMBER_MESSAGE}, - {"FeatureResMessage", FEATURE_STAT_RES_MESSAGE}, - {"ServiceUrlStatMessage", SERVICE_URL_STAT_RES_MESSAGE}, - {NULL, 0} + {"KeepAliveMessage", KEEP_ALIVE_MESSAGE}, + {"RegisterMessage", REGISTER_MESSAGE}, + {"PortMessage", PORT_MESSAGE}, + {"KeypadButtonMessage", KEYPAD_BUTTON_MESSAGE}, + {"StimulusMessage", STIMULUS_MESSAGE}, + {"OffHookMessage", OFF_HOOK_MESSAGE}, + {"OnHookMessage", ON_HOOK_MESSAGE}, + {"SpeedDialStatReqMessage", SPEED_DIAL_STAT_REQ_MESSAGE}, + {"LineStatReqMessage", LINE_STAT_REQ_MESSAGE}, + {"ConfigStatReqMessage", CONFIG_STAT_REQ_MESSAGE}, + {"TimeDateReqMessage", TIME_DATE_REQ_MESSAGE}, + {"ButtonTemplateReqMessage", BUTTON_TEMPLATE_REQ_MESSAGE}, + {"CapabilitiesReqMessage", CAPABILITIES_RES_MESSAGE}, + {"AlarmMessage", ALARM_MESSAGE}, + {"OpenReceiveChannelAckMessage", OPEN_RECEIVE_CHANNEL_ACK_MESSAGE}, + {"SoftKeySetReqMessage", SOFT_KEY_SET_REQ_MESSAGE}, + {"SoftKeyEventMessage", SOFT_KEY_EVENT_MESSAGE}, + {"UnregisterMessage", UNREGISTER_MESSAGE}, + {"SoftKeyTemplateReqMessage", SOFT_KEY_TEMPLATE_REQ_MESSAGE}, + {"ServiceUrlStatReqMessage", SERVICE_URL_STAT_REQ_MESSAGE}, + {"FeatureStatReqMessage", FEATURE_STAT_REQ_MESSAGE}, + {"HeadsetStatusMessage", HEADSET_STATUS_MESSAGE}, + {"RegisterAvailableLinesMessage", REGISTER_AVAILABLE_LINES_MESSAGE}, + {"RegisterAckMessage", REGISTER_ACK_MESSAGE}, + {"StartToneMessage", START_TONE_MESSAGE}, + {"StopToneMessage", STOP_TONE_MESSAGE}, + {"SetRingerMessage", SET_RINGER_MESSAGE}, + {"SetLampMessage", SET_LAMP_MESSAGE}, + {"SetSpeakerModeMessage", SET_SPEAKER_MODE_MESSAGE}, + {"StartMediaTransmissionMessage", START_MEDIA_TRANSMISSION_MESSAGE}, + {"StopMediaTransmissionMessage", STOP_MEDIA_TRANSMISSION_MESSAGE}, + {"CallInfoMessage", CALL_INFO_MESSAGE}, + {"SpeedDialStatResMessage", SPEED_DIAL_STAT_RES_MESSAGE}, + {"LineStatResMessage", LINE_STAT_RES_MESSAGE}, + {"ConfigStatResMessage", CONFIG_STAT_RES_MESSAGE}, + {"DefineTimeDateMessage", DEFINE_TIME_DATE_MESSAGE}, + {"ButtonTemplateResMessage", BUTTON_TEMPLATE_RES_MESSAGE}, + {"CapabilitiesReqMessage", CAPABILITIES_REQ_MESSAGE}, + {"RegisterRejectMessage", REGISTER_REJECT_MESSAGE}, + {"ResetMessage", RESET_MESSAGE}, + {"KeepAliveAckMessage", KEEP_ALIVE_ACK_MESSAGE}, + {"OpenReceiveChannelMessage", OPEN_RECEIVE_CHANNEL_MESSAGE}, + {"CloseReceiveChannelMessage", CLOSE_RECEIVE_CHANNEL_MESSAGE}, + {"SoftKeyTemplateResMessage", SOFT_KEY_TEMPLATE_RES_MESSAGE}, + {"SoftKeySetResMessage", SOFT_KEY_SET_RES_MESSAGE}, + {"SelectSoftKeysMessage", SELECT_SOFT_KEYS_MESSAGE}, + {"CallStateMessage", CALL_STATE_MESSAGE}, + {"DisplayPromptStatusMessage", DISPLAY_PROMPT_STATUS_MESSAGE}, + {"ClearPromptStatusMessage", CLEAR_PROMPT_STATUS_MESSAGE}, + {"ActivateCallPlaneMessage", ACTIVATE_CALL_PLANE_MESSAGE}, + {"UnregisterAckMessage", UNREGISTER_ACK_MESSAGE}, + {"DialedNumberMessage", DIALED_NUMBER_MESSAGE}, + {"FeatureResMessage", FEATURE_STAT_RES_MESSAGE}, + {"DisplayPriNotifyMessage", DISPLAY_PRI_NOTIFY_MESSAGE}, + {"ServiceUrlStatMessage", SERVICE_URL_STAT_RES_MESSAGE}, + {NULL, 0} }; SKINNY_DECLARE_ID2STR(skinny_message_type2str, SKINNY_MESSAGE_TYPES, "UnknownMessage") SKINNY_DECLARE_STR2ID(skinny_str2message_type, SKINNY_MESSAGE_TYPES, -1) struct skinny_table SKINNY_RING_TYPES[] = { - {"RingOff", SKINNY_RING_OFF}, - {"RingInside", SKINNY_RING_INSIDE}, - {"RingOutside", SKINNY_RING_OUTSIDE}, - {"RingFeature", SKINNY_RING_FEATURE}, - {NULL, 0} + {"RingOff", SKINNY_RING_OFF}, + {"RingInside", SKINNY_RING_INSIDE}, + {"RingOutside", SKINNY_RING_OUTSIDE}, + {"RingFeature", SKINNY_RING_FEATURE}, + {NULL, 0} }; SKINNY_DECLARE_ID2STR(skinny_ring_type2str, SKINNY_RING_TYPES, "RingTypeUnknown") SKINNY_DECLARE_STR2ID(skinny_str2ring_type, SKINNY_RING_TYPES, -1) struct skinny_table SKINNY_RING_MODES[] = { - {"RingForever", SKINNY_RING_FOREVER}, - {"RingOnce", SKINNY_RING_ONCE}, - {NULL, 0} + {"RingForever", SKINNY_RING_FOREVER}, + {"RingOnce", SKINNY_RING_ONCE}, + {NULL, 0} }; SKINNY_DECLARE_ID2STR(skinny_ring_mode2str, SKINNY_RING_MODES, "RingModeUnknown") SKINNY_DECLARE_STR2ID(skinny_str2ring_mode, SKINNY_RING_MODES, -1) struct skinny_table SKINNY_BUTTONS[] = { - {"Unknown", SKINNY_BUTTON_UNKNOWN}, - {"LastNumberRedial", SKINNY_BUTTON_LAST_NUMBER_REDIAL}, - {"SpeedDial", SKINNY_BUTTON_SPEED_DIAL}, - {"Line", SKINNY_BUTTON_LINE}, - {"Voicemail", SKINNY_BUTTON_VOICEMAIL}, - {"Privacy", SKINNY_BUTTON_PRIVACY}, - {"ServiceUrl", SKINNY_BUTTON_SERVICE_URL}, - {"Undefined", SKINNY_BUTTON_UNDEFINED}, - {NULL, 0} + {"Unknown", SKINNY_BUTTON_UNKNOWN}, + {"LastNumberRedial", SKINNY_BUTTON_LAST_NUMBER_REDIAL}, + {"SpeedDial", SKINNY_BUTTON_SPEED_DIAL}, + {"Line", SKINNY_BUTTON_LINE}, + {"Voicemail", SKINNY_BUTTON_VOICEMAIL}, + {"Privacy", SKINNY_BUTTON_PRIVACY}, + {"ServiceUrl", SKINNY_BUTTON_SERVICE_URL}, + {"Undefined", SKINNY_BUTTON_UNDEFINED}, + {NULL, 0} }; SKINNY_DECLARE_ID2STR(skinny_button2str, SKINNY_BUTTONS, "Unknown") SKINNY_DECLARE_STR2ID(skinny_str2button, SKINNY_BUTTONS, -1) struct skinny_table SKINNY_LAMP_MODES[] = { - {"Off", SKINNY_LAMP_OFF}, - {"On", SKINNY_LAMP_ON}, - {"Wink", SKINNY_LAMP_WINK}, - {"Flash", SKINNY_LAMP_FLASH}, - {"Blink", SKINNY_LAMP_BLINK}, - {NULL, 0} + {"Off", SKINNY_LAMP_OFF}, + {"On", SKINNY_LAMP_ON}, + {"Wink", SKINNY_LAMP_WINK}, + {"Flash", SKINNY_LAMP_FLASH}, + {"Blink", SKINNY_LAMP_BLINK}, + {NULL, 0} }; SKINNY_DECLARE_ID2STR(skinny_lamp_mode2str, SKINNY_LAMP_MODES, "Unknown") SKINNY_DECLARE_STR2ID(skinny_str2lamp_mode, SKINNY_LAMP_MODES, -1) struct skinny_table SKINNY_SPEAKER_MODES[] = { - {"SpeakerOn", SKINNY_SPEAKER_ON}, - {"SpeakerOff", SKINNY_SPEAKER_OFF}, - {NULL, 0} + {"SpeakerOn", SKINNY_SPEAKER_ON}, + {"SpeakerOff", SKINNY_SPEAKER_OFF}, + {NULL, 0} }; SKINNY_DECLARE_ID2STR(skinny_speaker_mode2str, SKINNY_SPEAKER_MODES, "Unknown") SKINNY_DECLARE_STR2ID(skinny_str2speaker_mode, SKINNY_SPEAKER_MODES, -1) struct skinny_table SKINNY_KEY_SETS[] = { - {"KeySetOnHook", SKINNY_KEY_SET_ON_HOOK}, - {"KeySetConnected", SKINNY_KEY_SET_CONNECTED}, - {"KeySetOnHold", SKINNY_KEY_SET_ON_HOLD}, - {"KeySetRingIn", SKINNY_KEY_SET_RING_IN}, - {"KeySetOffHook", SKINNY_KEY_SET_OFF_HOOK}, - {"KeySetConnectedWithTransfer", SKINNY_KEY_SET_CONNECTED_WITH_TRANSFER}, - {"KeySetDigitsAfterDialingFirstDigit", SKINNY_KEY_SET_DIGITS_AFTER_DIALING_FIRST_DIGIT}, - {"KeySetConnectedWithConference", SKINNY_KEY_SET_CONNECTED_WITH_CONFERENCE}, - {"KeySetRingOut", SKINNY_KEY_SET_RING_OUT}, - {"KeySetOffHookWithFeatures", SKINNY_KEY_SET_OFF_HOOK_WITH_FEATURES}, - {NULL, 0} + {"KeySetOnHook", SKINNY_KEY_SET_ON_HOOK}, + {"KeySetConnected", SKINNY_KEY_SET_CONNECTED}, + {"KeySetOnHold", SKINNY_KEY_SET_ON_HOLD}, + {"KeySetRingIn", SKINNY_KEY_SET_RING_IN}, + {"KeySetOffHook", SKINNY_KEY_SET_OFF_HOOK}, + {"KeySetConnectedWithTransfer", SKINNY_KEY_SET_CONNECTED_WITH_TRANSFER}, + {"KeySetDigitsAfterDialingFirstDigit", SKINNY_KEY_SET_DIGITS_AFTER_DIALING_FIRST_DIGIT}, + {"KeySetConnectedWithConference", SKINNY_KEY_SET_CONNECTED_WITH_CONFERENCE}, + {"KeySetRingOut", SKINNY_KEY_SET_RING_OUT}, + {"KeySetOffHookWithFeatures", SKINNY_KEY_SET_OFF_HOOK_WITH_FEATURES}, + {NULL, 0} }; SKINNY_DECLARE_ID2STR(skinny_soft_key_set2str, SKINNY_KEY_SETS, "UNKNOWN_SOFT_KEY_SET") SKINNY_DECLARE_STR2ID(skinny_str2soft_key_set, SKINNY_KEY_SETS, -1) struct skinny_table SKINNY_CALL_STATES[] = { - {"OffHook", SKINNY_OFF_HOOK}, - {"OnHook", SKINNY_ON_HOOK}, - {"RingOut", SKINNY_RING_OUT}, - {"RingIn", SKINNY_RING_IN}, - {"Connected", SKINNY_CONNECTED}, - {"Busy", SKINNY_BUSY}, - {"Congestion", SKINNY_CONGESTION}, - {"Hold", SKINNY_HOLD}, - {"CallWaiting", SKINNY_CALL_WAITING}, - {"CallTransfer", SKINNY_CALL_TRANSFER}, - {"CallPark", SKINNY_CALL_PARK}, - {"Proceed", SKINNY_PROCEED}, - {"CallRemoteMultiline", SKINNY_CALL_REMOTE_MULTILINE}, - {"InvalidNumber", SKINNY_INVALID_NUMBER}, - {NULL, 0} + {"OffHook", SKINNY_OFF_HOOK}, + {"OnHook", SKINNY_ON_HOOK}, + {"RingOut", SKINNY_RING_OUT}, + {"RingIn", SKINNY_RING_IN}, + {"Connected", SKINNY_CONNECTED}, + {"Busy", SKINNY_BUSY}, + {"LineInUse", SKINNY_LINE_IN_USE}, + {"Hold", SKINNY_HOLD}, + {"CallWaiting", SKINNY_CALL_WAITING}, + {"CallTransfer", SKINNY_CALL_TRANSFER}, + {"CallPark", SKINNY_CALL_PARK}, + {"Proceed", SKINNY_PROCEED}, + {"InUseRemotely", SKINNY_IN_USE_REMOTELY}, + {"InvalidNumber", SKINNY_INVALID_NUMBER}, + {NULL, 0} }; SKINNY_DECLARE_ID2STR(skinny_call_state2str, SKINNY_CALL_STATES, "CallStateUnknown") SKINNY_DECLARE_STR2ID(skinny_str2call_state, SKINNY_CALL_STATES, -1) struct skinny_table SKINNY_DEVICE_RESET_TYPES[] = { - {"DeviceReset", SKINNY_DEVICE_RESET}, - {"DeviceRestart", SKINNY_DEVICE_RESTART}, - {NULL, 0} + {"DeviceReset", SKINNY_DEVICE_RESET}, + {"DeviceRestart", SKINNY_DEVICE_RESTART}, + {NULL, 0} }; SKINNY_DECLARE_ID2STR(skinny_device_reset_type2str, SKINNY_DEVICE_RESET_TYPES, "DeviceResetTypeUnknown") SKINNY_DECLARE_STR2ID(skinny_str2device_reset_type, SKINNY_DEVICE_RESET_TYPES, -1) +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4: + */ + diff --git a/src/mod/endpoints/mod_skinny/skinny_tables.h b/src/mod/endpoints/mod_skinny/skinny_tables.h index 5672446bc0..9e3ab3be4c 100644 --- a/src/mod/endpoints/mod_skinny/skinny_tables.h +++ b/src/mod/endpoints/mod_skinny/skinny_tables.h @@ -36,74 +36,74 @@ /* SKINNY TABLES */ /*****************************************************************************/ struct skinny_table { - const char *name; - uint32_t id; + const char *name; + uint32_t id; }; #define SKINNY_DECLARE_ID2STR(func, TABLE, DEFAULT_STR) \ const char *func(uint32_t id) \ { \ - const char *str = DEFAULT_STR; \ - \ - for (uint8_t x = 0; x < (sizeof(TABLE) / sizeof(struct skinny_table)) - 1; x++) {\ - if (TABLE[x].id == id) {\ - str = TABLE[x].name;\ - break;\ - }\ - }\ - \ - return str;\ + const char *str = DEFAULT_STR; \ + \ + for (uint8_t x = 0; x < (sizeof(TABLE) / sizeof(struct skinny_table)) - 1; x++) {\ + if (TABLE[x].id == id) {\ + str = TABLE[x].name;\ + break;\ + }\ + }\ + \ + return str;\ } #define SKINNY_DECLARE_STR2ID(func, TABLE, DEFAULT_ID) \ uint32_t func(const char *str)\ {\ - uint32_t id = DEFAULT_ID;\ - \ - if (*str > 47 && *str < 58) {\ - id = atoi(str);\ - } else {\ - for (uint8_t x = 0; x < (sizeof(TABLE) / sizeof(struct skinny_table)) - 1 && TABLE[x].name; x++) {\ - if (!strcasecmp(TABLE[x].name, str)) {\ - id = TABLE[x].id;\ - break;\ - }\ - }\ - }\ - return id;\ + uint32_t id = DEFAULT_ID;\ + \ + if (*str > 47 && *str < 58) {\ + id = atoi(str);\ + } else {\ + for (uint8_t x = 0; x < (sizeof(TABLE) / sizeof(struct skinny_table)) - 1 && TABLE[x].name; x++) {\ + if (!strcasecmp(TABLE[x].name, str)) {\ + id = TABLE[x].id;\ + break;\ + }\ + }\ + }\ + return id;\ } #define SKINNY_DECLARE_PUSH_MATCH(TABLE) \ - switch_console_callback_match_t *my_matches = NULL;\ - for (uint8_t x = 0; x < (sizeof(TABLE) / sizeof(struct skinny_table)) - 1; x++) {\ - switch_console_push_match(&my_matches, TABLE[x].name);\ - }\ - if (my_matches) {\ - *matches = my_matches;\ - status = SWITCH_STATUS_SUCCESS;\ - } - + switch_console_callback_match_t *my_matches = NULL;\ + for (uint8_t x = 0; x < (sizeof(TABLE) / sizeof(struct skinny_table)) - 1; x++) {\ + switch_console_push_match(&my_matches, TABLE[x].name);\ + }\ + if (my_matches) {\ + *matches = my_matches;\ + status = SWITCH_STATUS_SUCCESS;\ + } -struct skinny_table SKINNY_MESSAGE_TYPES[55]; + +struct skinny_table SKINNY_MESSAGE_TYPES[56]; const char *skinny_message_type2str(uint32_t id); uint32_t skinny_str2message_type(const char *str); #define SKINNY_PUSH_MESSAGE_TYPES SKINNY_DECLARE_PUSH_MATCH(SKINNY_MESSAGE_TYPES) enum skinny_tone { - SKINNY_TONE_SILENCE = 0x00, - SKINNY_TONE_DIALTONE = 0x21, - SKINNY_TONE_BUSYTONE = 0x23, - SKINNY_TONE_ALERT = 0x24, - SKINNY_TONE_REORDER = 0x25, - SKINNY_TONE_CALLWAITTONE = 0x2D, - SKINNY_TONE_NOTONE = 0x7F, + SKINNY_TONE_SILENCE = 0x00, + SKINNY_TONE_DIALTONE = 0x21, + SKINNY_TONE_BUSYTONE = 0x23, + SKINNY_TONE_ALERT = 0x24, + SKINNY_TONE_REORDER = 0x25, + SKINNY_TONE_CALLWAITTONE = 0x2D, + SKINNY_TONE_NOTONE = 0x7F, }; enum skinny_ring_type { - SKINNY_RING_OFF = 1, - SKINNY_RING_INSIDE = 2, - SKINNY_RING_OUTSIDE = 3, - SKINNY_RING_FEATURE = 4 + SKINNY_RING_OFF = 1, + SKINNY_RING_INSIDE = 2, + SKINNY_RING_OUTSIDE = 3, + SKINNY_RING_FEATURE = 4 }; struct skinny_table SKINNY_RING_TYPES[5]; const char *skinny_ring_type2str(uint32_t id); @@ -111,8 +111,8 @@ uint32_t skinny_str2ring_type(const char *str); #define SKINNY_PUSH_RING_TYPES SKINNY_DECLARE_PUSH_MATCH(SKINNY_RING_TYPES) enum skinny_ring_mode { - SKINNY_RING_FOREVER = 1, - SKINNY_RING_ONCE = 2, + SKINNY_RING_FOREVER = 1, + SKINNY_RING_ONCE = 2, }; struct skinny_table SKINNY_RING_MODES[3]; const char *skinny_ring_mode2str(uint32_t id); @@ -121,11 +121,11 @@ uint32_t skinny_str2ring_mode(const char *str); enum skinny_lamp_mode { - SKINNY_LAMP_OFF = 1, - SKINNY_LAMP_ON = 2, - SKINNY_LAMP_WINK = 3, - SKINNY_LAMP_FLASH = 4, - SKINNY_LAMP_BLINK = 5, + SKINNY_LAMP_OFF = 1, + SKINNY_LAMP_ON = 2, + SKINNY_LAMP_WINK = 3, + SKINNY_LAMP_FLASH = 4, + SKINNY_LAMP_BLINK = 5, }; struct skinny_table SKINNY_LAMP_MODES[6]; const char *skinny_lamp_mode2str(uint32_t id); @@ -133,8 +133,8 @@ uint32_t skinny_str2lamp_mode(const char *str); #define SKINNY_PUSH_LAMP_MODES SKINNY_DECLARE_PUSH_MATCH(SKINNY_LAMP_MODES) enum skinny_speaker_mode { - SKINNY_SPEAKER_ON = 1, - SKINNY_SPEAKER_OFF = 2, + SKINNY_SPEAKER_ON = 1, + SKINNY_SPEAKER_OFF = 2, }; struct skinny_table SKINNY_SPEAKER_MODES[3]; const char *skinny_speaker_mode2str(uint32_t id); @@ -142,20 +142,20 @@ uint32_t skinny_str2speaker_mode(const char *str); #define SKINNY_PUSH_SPEAKER_MODES SKINNY_DECLARE_PUSH_MATCH(SKINNY_SPEAKER_MODES) enum skinny_call_type { - SKINNY_INBOUND_CALL = 1, - SKINNY_OUTBOUND_CALL = 2, - SKINNY_FORWARD_CALL = 3, + SKINNY_INBOUND_CALL = 1, + SKINNY_OUTBOUND_CALL = 2, + SKINNY_FORWARD_CALL = 3, }; enum skinny_button_definition { - SKINNY_BUTTON_UNKNOWN = 0x00, - SKINNY_BUTTON_LAST_NUMBER_REDIAL = 0x01, - SKINNY_BUTTON_SPEED_DIAL = 0x02, - SKINNY_BUTTON_LINE = 0x09, - SKINNY_BUTTON_VOICEMAIL = 0x0F, - SKINNY_BUTTON_PRIVACY = 0x13, - SKINNY_BUTTON_SERVICE_URL = 0x14, - SKINNY_BUTTON_UNDEFINED = 0xFF, + SKINNY_BUTTON_UNKNOWN = 0x00, + SKINNY_BUTTON_LAST_NUMBER_REDIAL = 0x01, + SKINNY_BUTTON_SPEED_DIAL = 0x02, + SKINNY_BUTTON_LINE = 0x09, + SKINNY_BUTTON_VOICEMAIL = 0x0F, + SKINNY_BUTTON_PRIVACY = 0x13, + SKINNY_BUTTON_SERVICE_URL = 0x14, + SKINNY_BUTTON_UNDEFINED = 0xFF, }; struct skinny_table SKINNY_BUTTONS[9]; const char *skinny_button2str(uint32_t id); @@ -163,39 +163,39 @@ uint32_t skinny_str2button(const char *str); #define SKINNY_PUSH_STIMULI SKINNY_DECLARE_PUSH_MATCH(SKINNY_BUTTONS) enum skinny_soft_key_event { - SOFTKEY_REDIAL = 0x01, - SOFTKEY_NEWCALL = 0x02, - SOFTKEY_HOLD = 0x03, - SOFTKEY_TRANSFER = 0x04, - SOFTKEY_CFWDALL = 0x05, - SOFTKEY_CFWDBUSY = 0x06, - SOFTKEY_CFWDNOANSWER = 0x07, - SOFTKEY_BACKSPACE = 0x08, - SOFTKEY_ENDCALL = 0x09, - SOFTKEY_RESUME = 0x0A, - SOFTKEY_ANSWER = 0x0B, - SOFTKEY_INFO = 0x0C, - SOFTKEY_CONFRM = 0x0D, - SOFTKEY_PARK = 0x0E, - SOFTKEY_JOIN = 0x0F, - SOFTKEY_MEETMECONFRM = 0x10, - SOFTKEY_CALLPICKUP = 0x11, - SOFTKEY_GRPCALLPICKUP = 0x12, - SOFTKEY_DND = 0x13, - SOFTKEY_IDIVERT = 0x14, + SOFTKEY_REDIAL = 0x01, + SOFTKEY_NEWCALL = 0x02, + SOFTKEY_HOLD = 0x03, + SOFTKEY_TRANSFER = 0x04, + SOFTKEY_CFWDALL = 0x05, + SOFTKEY_CFWDBUSY = 0x06, + SOFTKEY_CFWDNOANSWER = 0x07, + SOFTKEY_BACKSPACE = 0x08, + SOFTKEY_ENDCALL = 0x09, + SOFTKEY_RESUME = 0x0A, + SOFTKEY_ANSWER = 0x0B, + SOFTKEY_INFO = 0x0C, + SOFTKEY_CONFRM = 0x0D, + SOFTKEY_PARK = 0x0E, + SOFTKEY_JOIN = 0x0F, + SOFTKEY_MEETMECONFRM = 0x10, + SOFTKEY_CALLPICKUP = 0x11, + SOFTKEY_GRPCALLPICKUP = 0x12, + SOFTKEY_DND = 0x13, + SOFTKEY_IDIVERT = 0x14, }; enum skinny_key_set { - SKINNY_KEY_SET_ON_HOOK = 0, - SKINNY_KEY_SET_CONNECTED = 1, - SKINNY_KEY_SET_ON_HOLD = 2, - SKINNY_KEY_SET_RING_IN = 3, - SKINNY_KEY_SET_OFF_HOOK = 4, - SKINNY_KEY_SET_CONNECTED_WITH_TRANSFER = 5, - SKINNY_KEY_SET_DIGITS_AFTER_DIALING_FIRST_DIGIT = 6, - SKINNY_KEY_SET_CONNECTED_WITH_CONFERENCE = 7, - SKINNY_KEY_SET_RING_OUT = 8, - SKINNY_KEY_SET_OFF_HOOK_WITH_FEATURES = 9, + SKINNY_KEY_SET_ON_HOOK = 0, + SKINNY_KEY_SET_CONNECTED = 1, + SKINNY_KEY_SET_ON_HOLD = 2, + SKINNY_KEY_SET_RING_IN = 3, + SKINNY_KEY_SET_OFF_HOOK = 4, + SKINNY_KEY_SET_CONNECTED_WITH_TRANSFER = 5, + SKINNY_KEY_SET_DIGITS_AFTER_DIALING_FIRST_DIGIT = 6, + SKINNY_KEY_SET_CONNECTED_WITH_CONFERENCE = 7, + SKINNY_KEY_SET_RING_OUT = 8, + SKINNY_KEY_SET_OFF_HOOK_WITH_FEATURES = 9, }; struct skinny_table SKINNY_KEY_SETS[11]; const char *skinny_soft_key_set2str(uint32_t id); @@ -204,20 +204,20 @@ uint32_t skinny_str2soft_key_set(const char *str); enum skinny_call_state { - SKINNY_OFF_HOOK = 1, - SKINNY_ON_HOOK = 2, - SKINNY_RING_OUT = 3, - SKINNY_RING_IN = 4, - SKINNY_CONNECTED = 5, - SKINNY_BUSY = 6, - SKINNY_CONGESTION = 7, - SKINNY_HOLD = 8, - SKINNY_CALL_WAITING = 9, - SKINNY_CALL_TRANSFER = 10, - SKINNY_CALL_PARK = 11, - SKINNY_PROCEED = 12, - SKINNY_CALL_REMOTE_MULTILINE = 13, - SKINNY_INVALID_NUMBER = 14 + SKINNY_OFF_HOOK = 1, + SKINNY_ON_HOOK = 2, + SKINNY_RING_OUT = 3, + SKINNY_RING_IN = 4, + SKINNY_CONNECTED = 5, + SKINNY_BUSY = 6, + SKINNY_LINE_IN_USE = 7, + SKINNY_HOLD = 8, + SKINNY_CALL_WAITING = 9, + SKINNY_CALL_TRANSFER = 10, + SKINNY_CALL_PARK = 11, + SKINNY_PROCEED = 12, + SKINNY_IN_USE_REMOTELY = 13, + SKINNY_INVALID_NUMBER = 14 }; struct skinny_table SKINNY_CALL_STATES[15]; const char *skinny_call_state2str(uint32_t id); @@ -235,3 +235,14 @@ uint32_t skinny_str2device_reset_type(const char *str); #endif /* _SKINNY_TABLES_H */ +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4: + */ + diff --git a/src/mod/endpoints/mod_skinny/test-skinny.pl b/src/mod/endpoints/mod_skinny/test-skinny.pl index 4821fc9b50..390466f530 100644 --- a/src/mod/endpoints/mod_skinny/test-skinny.pl +++ b/src/mod/endpoints/mod_skinny/test-skinny.pl @@ -11,12 +11,13 @@ BEGIN { use strict; use warnings; +use Sys::Hostname; use Net::Skinny; use Net::Skinny::Protocol qw/:all/; use Net::Skinny::Message; #Config -my $skinny_server = '127.0.0.1'; +my $skinny_server = hostname; my $device_name = "SEP001120AABBCC"; my $device_ip = 10+256*(11+256*(12+256*13)); # 10.11.12.13 #====== @@ -70,6 +71,7 @@ $socket->receive_message(); # SoftKeyTemplateRes $socket->send_message(SOFT_KEY_SET_REQ_MESSAGE); $socket->receive_message(); # SoftKeySetRes +$socket->receive_message(); # SelectSoftKeys $socket->send_message( LINE_STAT_REQ_MESSAGE, @@ -82,8 +84,68 @@ $socket->send_message( count => 2 ); -while(1) { - $socket->sleep(20); +for(my $i = 0; $i < 1; $i++) { + $socket->sleep(5); $socket->send_message(KEEP_ALIVE_MESSAGE); $socket->receive_message(); # keepaliveack } +$socket->sleep(5); + +#NewCall +$socket->send_message( + SOFT_KEY_EVENT_MESSAGE, + event => 2, #NewCall + line_instance => 2, + call_id => 0 + ); +$socket->receive_message(); # SetRinger +$socket->receive_message(); # SetSpeakerMode +$socket->receive_message(); # SetLamp +$socket->receive_message(); # SelectSoftKeys +$socket->receive_message(); # DisplayPromptStatus +$socket->receive_message(); # ActivateCallPlane +$socket->receive_message(); # StartTone + +$socket->sleep(5); + +#VoiceMail +$socket->send_message( + STIMULUS_MESSAGE, + instance_type => 0xf, #VoiceMail + instance => 0, + ); +$socket->receive_message(); # +$socket->receive_message(); # +$socket->receive_message(); # +$socket->receive_message(); # +$socket->receive_message(); # +$socket->receive_message(); # +$socket->receive_message(); # +$socket->receive_message(); # +$socket->receive_message(); # +$socket->receive_message(); # + +# +$socket->send_message( + OPEN_RECEIVE_CHANNEL_ACK_MESSAGE, + status => 1, + ip => $device_ip, + port => 12, + pass_thru_party_id => 0, + ); +$socket->receive_message(); # StartMediaTransmission + +$socket->sleep(20); + +#EndCall +$socket->send_message( + SOFT_KEY_EVENT_MESSAGE, + event => 0x09, #NewCall + line_instance => 1, + call_id => 0 + ); + +while(1) { + $socket->receive_message(); +} + diff --git a/src/mod/endpoints/mod_skypopen/Makefile.am b/src/mod/endpoints/mod_skypopen/Makefile.am index 466a09b7b8..d696fae783 100644 --- a/src/mod/endpoints/mod_skypopen/Makefile.am +++ b/src/mod/endpoints/mod_skypopen/Makefile.am @@ -2,6 +2,6 @@ include $(top_srcdir)/build/modmake.rulesam MODNAME=mod_skypopen mod_LTLIBRARIES = mod_skypopen.la mod_skypopen_la_SOURCES = mod_skypopen.c skypopen_protocol.c -mod_skypopen_la_CFLAGS = $(AM_CFLAGS) -DSKYPOPEN_SVN_VERSION=\"`cat $(switch_builddir)/.version`\" -I../../../../libs/spandsp/src -I../../../..//libs/tiff-3.8.2/libtiff +mod_skypopen_la_CFLAGS = $(AM_CFLAGS) -DSKYPOPEN_SVN_VERSION=\"`git describe`\" -I../../../../libs/spandsp/src -I../../../..//libs/tiff-3.8.2/libtiff mod_skypopen_la_LIBADD = $(switch_builddir)/libfreeswitch.la mod_skypopen_la_LDFLAGS = -L../../../../libs/spandsp/src -avoid-version -module -no-undefined -shared -lX11 -lspandsp diff --git a/src/mod/formats/mod_portaudio_stream/Makefile.am b/src/mod/formats/mod_portaudio_stream/Makefile.am index 9b9900c03a..ae9896a7b0 100644 --- a/src/mod/formats/mod_portaudio_stream/Makefile.am +++ b/src/mod/formats/mod_portaudio_stream/Makefile.am @@ -7,8 +7,7 @@ MODPA_DIR=$(switch_srcdir)/src/mod/endpoints/mod_portaudio mod_LTLIBRARIES = mod_portaudio_stream.la mod_portaudio_stream_la_SOURCES = mod_portaudio_stream.c $(MODPA_DIR)/pablio.c $(MODPA_DIR)/pa_ringbuffer.c -mod_portaudio_stream_la_CFLAGS = $(AM_CFLAGS) -mod_portaudio_stream_la_CFLAGS += -I. -I$(PA_DIR)/include -D__EXTENSION__=1 -I$(MODPA_DIR) +mod_portaudio_stream_la_CFLAGS = -I. -I$(PA_DIR)/include -D__EXTENSION__=1 -I$(MODPA_DIR) $(AM_CFLAGS) mod_portaudio_stream_la_LIBADD = $(switch_builddir)/libfreeswitch.la $(PALA) mod_portaudio_stream_la_LDFLAGS = -avoid-version -module -no-undefined -shared $(PA_LIBS) diff --git a/src/mod/languages/mod_managed/freeswitch_wrap.cxx b/src/mod/languages/mod_managed/freeswitch_wrap.cxx index aab23429f8..737940ec6c 100644 --- a/src/mod/languages/mod_managed/freeswitch_wrap.cxx +++ b/src/mod/languages/mod_managed/freeswitch_wrap.cxx @@ -21403,6 +21403,26 @@ SWIGEXPORT char * SWIGSTDCALL CSharp_switch_channel_get_variable_partner(void * } +SWIGEXPORT int SWIGSTDCALL CSharp_switch_channel_export_variable_var_check(void * jarg1, char * jarg2, char * jarg3, int jarg4, int jarg5) { + int jresult ; + switch_channel_t *arg1 = (switch_channel_t *) 0 ; + char *arg2 = (char *) 0 ; + char *arg3 = (char *) 0 ; + switch_bool_t arg4 ; + switch_bool_t arg5 ; + switch_status_t result; + + arg1 = (switch_channel_t *)jarg1; + arg2 = (char *)jarg2; + arg3 = (char *)jarg3; + arg4 = (switch_bool_t)jarg4; + arg5 = (switch_bool_t)jarg5; + result = (switch_status_t)switch_channel_export_variable_var_check(arg1,(char const *)arg2,(char const *)arg3,arg4,arg5); + jresult = result; + return jresult; +} + + SWIGEXPORT char * SWIGSTDCALL CSharp_switch_channel_get_variable_dup(void * jarg1, char * jarg2, int jarg3) { char * jresult ; switch_channel_t *arg1 = (switch_channel_t *) 0 ; diff --git a/src/mod/languages/mod_managed/managed/FreeSWITCH.Managed.dll b/src/mod/languages/mod_managed/managed/FreeSWITCH.Managed.dll deleted file mode 100644 index fb5f57172e..0000000000 Binary files a/src/mod/languages/mod_managed/managed/FreeSWITCH.Managed.dll and /dev/null differ diff --git a/src/mod/languages/mod_managed/managed/FreeSWITCH.Managed.pdb b/src/mod/languages/mod_managed/managed/FreeSWITCH.Managed.pdb deleted file mode 100644 index 4689e6d01a..0000000000 Binary files a/src/mod/languages/mod_managed/managed/FreeSWITCH.Managed.pdb and /dev/null differ diff --git a/src/mod/languages/mod_managed/managed/swig.cs b/src/mod/languages/mod_managed/managed/swig.cs index 90b0c57877..13756d32a6 100644 --- a/src/mod/languages/mod_managed/managed/swig.cs +++ b/src/mod/languages/mod_managed/managed/swig.cs @@ -2904,6 +2904,11 @@ public class freeswitch { return ret; } + public static switch_status_t switch_channel_export_variable_var_check(SWIGTYPE_p_switch_channel channel, string varname, string value, switch_bool_t var_check, switch_bool_t nolocal) { + switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_channel_export_variable_var_check(SWIGTYPE_p_switch_channel.getCPtr(channel), varname, value, (int)var_check, (int)nolocal); + return ret; + } + public static string switch_channel_get_variable_dup(SWIGTYPE_p_switch_channel channel, string varname, switch_bool_t dup) { string ret = freeswitchPINVOKE.switch_channel_get_variable_dup(SWIGTYPE_p_switch_channel.getCPtr(channel), varname, (int)dup); return ret; @@ -10209,6 +10214,9 @@ class freeswitchPINVOKE { [DllImport("mod_managed", EntryPoint="CSharp_switch_channel_get_variable_partner")] public static extern string switch_channel_get_variable_partner(HandleRef jarg1, string jarg2); + [DllImport("mod_managed", EntryPoint="CSharp_switch_channel_export_variable_var_check")] + public static extern int switch_channel_export_variable_var_check(HandleRef jarg1, string jarg2, string jarg3, int jarg4, int jarg5); + [DllImport("mod_managed", EntryPoint="CSharp_switch_channel_get_variable_dup")] public static extern string switch_channel_get_variable_dup(HandleRef jarg1, string jarg2, int jarg3); diff --git a/src/mod/timers/.empty b/src/mod/timers/.empty new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/switch_channel.c b/src/switch_channel.c index fe661d4d66..ba9429721a 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -737,6 +737,37 @@ SWITCH_DECLARE(switch_status_t) switch_channel_set_profile_var(switch_channel_t return status; } +SWITCH_DECLARE(switch_status_t) switch_channel_export_variable_var_check(switch_channel_t *channel, const char *varname, const char *value, switch_bool_t var_check, switch_bool_t nolocal) +{ + const char *exports, *exports_varname = varname; + switch_status_t status; + + exports = switch_channel_get_variable(channel, SWITCH_EXPORT_VARS_VARIABLE); + + if (nolocal) { + exports_varname = switch_mprintf("nolocal:%s", varname); + } + + if ((status = switch_channel_set_variable_var_check(channel, exports_varname, value, var_check)) != SWITCH_STATUS_SUCCESS) { + goto done; + } + + if (varname && value) { + if (exports) { + switch_channel_set_variable_printf(channel, SWITCH_EXPORT_VARS_VARIABLE, "%s,%s", exports, exports_varname); + } else { + switch_channel_set_variable(channel, SWITCH_EXPORT_VARS_VARIABLE, exports_varname); + } + } + +done: + if (exports_varname != varname) { + free((char*)exports_varname); + } + + return status; +} + SWITCH_DECLARE(switch_status_t) switch_channel_set_variable_var_check(switch_channel_t *channel, const char *varname, const char *value, switch_bool_t var_check) { diff --git a/web/etc/.empty b/web/etc/.empty new file mode 100644 index 0000000000..e69de29bb2 diff --git a/web/planet/.empty b/web/planet/.empty new file mode 100644 index 0000000000..e69de29bb2