Go to:
Gentoo Home
Documentation
Forums
Lists
Bugs
Planet
Store
Wiki
Get Gentoo!
Gentoo's Bugzilla – Attachment 145296 Details for
Bug 212306
net-misc/asterisk-1.2.26.2 ebuild version bump and/or new use flag
Home
|
New
–
[Ex]
|
Browse
|
Search
|
Privacy Policy
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
net-misc/asterisk-1.2.26.2.diff
asterisk-1.2.26.2.diff (text/plain), 57.27 KB, created by
Vieri
on 2008-03-04 19:11:02 UTC
(
hide
)
Description:
net-misc/asterisk-1.2.26.2.diff
Filename:
MIME Type:
Creator:
Vieri
Created:
2008-03-04 19:11:02 UTC
Size:
57.27 KB
patch
obsolete
>diff -ruN asterisk-ori/asterisk-1.2.26.2.ebuild asterisk/asterisk-1.2.26.2.ebuild >--- asterisk-ori/asterisk-1.2.26.2.ebuild 1970-01-01 01:00:00.000000000 +0100 >+++ asterisk/asterisk-1.2.26.2.ebuild 2008-03-04 19:58:52.000000000 +0100 >@@ -0,0 +1,478 @@ >+# Copyright 1999-2008 Gentoo Foundation >+# Distributed under the terms of the GNU General Public License v2 >+# $Header: $ >+ >+inherit eutils multilib toolchain-funcs >+ >+IUSE="alsa bri curl debug doc gtk h323 hardened lowmem mmx \ >+ nosamples odbc osp postgres pri speex sqlite ssl zaptel \ >+ elibc_uclibc backports" >+ >+BRI_VERSION="0.3.0-PRE-1y-h" >+AST_PATCHES="1.2.26.2-patches-1.0" >+JB_PATCHES="1.2.11-jb" >+ >+MY_P="${P/_p/.}" >+ >+DESCRIPTION="Asterisk: A Modular Open Source PBX System" >+HOMEPAGE="http://www.asterisk.org/" >+SRC_URI="http://ftp.digium.com/pub/asterisk/releases/${MY_P}.tar.gz >+ http://www.netdomination.org/pub/asterisk/${PN}-${AST_PATCHES}.tar.bz2 >+ mirror://gentoo/${PN}-${AST_PATCHES}.tar.bz2 >+ bri? ( mirror://gentoo/${MY_P}-bristuff-${BRI_VERSION}.diff.bz2 >+ http://www.junghanns.net/downloads/bristuff-${BRI_VERSION}.tar.gz )" >+ >+S="${WORKDIR}/${MY_P}" >+S_BRI="${WORKDIR}/bristuff-${BRI_VERSION}" >+ >+SLOT="0" >+LICENSE="GPL-2" >+KEYWORDS="~alpha amd64 ~hppa ~ppc sparc x86" >+ >+RDEPEND="dev-libs/newt >+ media-sound/sox >+ ssl? ( dev-libs/openssl ) >+ gtk? ( =x11-libs/gtk+-1.2* ) >+ pri? ( >=net-libs/libpri-1.2.5 ) >+ h323? ( >=dev-libs/pwlib-1.8.3 >+ >=net-libs/openh323-1.15.0 ) >+ alsa? ( media-libs/alsa-lib ) >+ curl? ( net-misc/curl ) >+ odbc? ( dev-db/unixODBC ) >+ speex? ( media-libs/speex ) >+ sqlite? ( <dev-db/sqlite-3.0.0 ) >+ zaptel? ( >=net-misc/zaptel-1.2.16 ) >+ postgres? ( dev-db/postgresql ) >+ osp? ( >=net-libs/osptoolkit-3.3.4 ) >+ bri? ( >=net-libs/libpri-1.2.5 >+ >=net-misc/zaptel-1.2.18 )" >+ >+DEPEND="${RDEPEND} >+ sys-devel/flex >+ sys-devel/bison >+ doc? ( app-doc/doxygen ) >+ virtual/logger" >+ >+#asterisk uses special mpg123 functions and does not work with mpeg321, bug #42703 >+PDEPEND="|| ( media-sound/mpg123 net-misc/asterisk-addons )" >+ >+QA_TEXTRELS_x86="usr/lib/asterisk/modules/codec_gsm.so" >+QA_EXECSTACK_x86="usr/lib/asterisk/modules/codec_gsm.so" >+ >+# >+# List of modules to ignore during scan (because they have been removed in 1.2.x) >+# >+SCAN_IGNORE_MODS=" >+ app_qcall >+ chan_modem >+ chan_modem_i4l >+ chan_modem_bestdata >+ chan_modme_aopen" >+ >+# >+# shortcuts >+# >+is_ast10update() { >+ return $(has_version "=net-misc/asterisk-1.0*") >+} >+ >+is_astupdate() { >+ if ! is_ast10update; then >+ return $(has_version "<net-misc/asterisk-${PV}") >+ fi >+ return 0 >+} >+ >+# >+# Display a nice countdown... >+# >+countdown() { >+ local n >+ >+ ebeep >+ >+ n=${1:-10} >+ while [[ $n -gt 0 ]]; do >+ echo -en " Waiting $n second(s)...\r" >+ sleep 1 >+ (( n-- )) >+ done >+} >+ >+# >+# Scan for asterisk-1.0.x modules that will have to be updated >+# >+scan_modules() { >+ local modules_list="" >+ local n >+ >+ for x in $(ls -1 "${ROOT}"usr/$(get_libdir)/asterisk/modules/*.so); do >+ echo -en "Scanning.... $(basename ${x}) \r" >+ >+ # skip blacklisted modules >+ hasq $(basename ${x//.so}) ${SCAN_IGNORE_MODS} && continue >+ >+ if $(readelf -s "${x}" | grep -q "\(ast_load\|ast_destroy\)$"); then >+ modules_list="${modules_list} $(basename ${x//.so})" >+ fi >+ done >+ >+ if [[ -n "${modules_list}" ]]; then >+ echo " ========================================================" >+ ewarn "Please update or unmerge the following modules:" >+ echo >+ >+ n=0 >+ for x in ${modules_list}; do >+ ewarn " - ${x}" >+ (( n++ )) >+ done >+ >+ echo >+ ewarn "Warning: $n outdated module(s) found!" >+ ewarn "Warning: asterisk may not work if you don't update them!" >+ echo " ========================================================" >+ echo >+ einfo "You can use the \"asterisk-updater\" script to update the modules" >+ echo >+ countdown >+ echo >+ return 1 >+ else >+ einfo "No asterisk-1.0.x modules found!" >+ return 0 >+ fi >+} >+ >+pkg_setup() { >+ local checkfailed=0 waitaftermsg=0 >+ >+ if is_ast10update; then >+ ewarn " Asterisk UPGRADE Warning" >+ ewarn "" >+ ewarn "- Please read ${ROOT}usr/share/doc/${PF}/UPGRADE.txt.gz after the installation!" >+ ewarn "" >+ ewarn " Asterisk UPGRADE Warning" >+ echo >+ waitaftermsg=1 >+ fi >+ >+ if use bri; then >+ if ! built_with_use net-libs/libpri bri; then >+ die "net-libs/libpri must be rebuilt ith USE=bri." >+ fi >+ elif use pri; then >+ if built_with_use net-libs/libpri bri; then >+ die "net-libs/libpri must be rebuilt without USE=bri." >+ fi >+ fi >+ >+ # >+ # Regular checks >+ # >+ einfo "Running some pre-flight checks..." >+ echo >+ >+} >+ >+src_unpack() { >+ unpack ${A} >+ cd "${S}" >+ >+ # >+ # gentoo patchset >+ # >+ for x in $(grep -v "^#\| \+" "${WORKDIR}"/patches/patches.list); do >+ epatch "${WORKDIR}"/patches/${x} >+ done >+ >+ if use mmx; then >+ if ! use hardened; then >+ einfo "Enabling mmx optimization" >+ sed -i -e "s:^#\(K6OPT[\t ]\+= -DK6OPT\):\1:" \ >+ Makefile >+ else >+ ewarn "Hardened use-flag is set, not enabling mmx optimization for codec_gsm!" >+ fi >+ fi >+ >+ if ! use debug; then >+ einfo "Disabling debug support" >+ sed -i -e "s:^\(DEBUG=\):#\1:" \ >+ Makefile >+ fi >+ >+ if ! use ssl; then >+ einfo "Disabling crypto support" >+ sed -i -e 's:^#\(NOCRYPTO=yes\):\1:' \ >+ -e '/^LIBS+=-lssl/d' Makefile || die >+ fi >+ >+ epatch "${FILESDIR}"/1.2.0/asterisk-1.2.21.1-h323-dumb-makefile.diff >+ >+ # >+ # uclibc patch >+ # >+ if use elibc_uclibc; then >+ einfo "Patching asterisk for uclibc..." >+ epatch "${FILESDIR}"/1.0.0/${PN}-1.0.5-uclibc-dns.diff >+ epatch "${FILESDIR}"/1.2.0/${PN}-1.2.1-uclibc-getloadavg.diff >+ fi >+ >+ # >+ # BRI patches >+ # >+ if use bri; then >+ einfo "Patching asterisk w/ BRI stuff" >+ >+ epatch "${WORKDIR}"/${MY_P}-bristuff-${BRI_VERSION}.diff >+ #epatch "${S_BRI}"/patches/asterisk.patch >+ fi >+ >+ # >+ # Disable AEL, security bug #171884 >+ # Re-enable at your own risk (no USE since it can be critical) >+ # >+ sed -i -e 's/pbx_ael.so//' pbx/Makefile || die >+ >+ # >+ # Some useful backports >+ # >+ if use backports; then >+ einfo "Adding func_odbc backport" >+ # http://svncommunity.digium.com/view/func_odbc/1.2/ >+ cp "${FILESDIR}"/1.2.0/backports/func_odbc/*.c "${WORKDIR}"/${P}/funcs/ >+ cp "${FILESDIR}"/1.2.0/backports/func_odbc/*.h "${WORKDIR}"/${P}/include/ >+ cp "${FILESDIR}"/1.2.0/backports/func_odbc/*.sample "${WORKDIR}"/${P}/configs/ >+ >+ einfo "Adding app_stack2 backport" >+ # http://svncommunity.digium.com/view/app_stack/1.2/ >+ cp "${FILESDIR}"/1.2.0/backports/app_stack/*.c "${WORKDIR}"/${P}/apps/ >+ epatch "${FILESDIR}"/1.2.0/backports/app_stack/asterisk-app_stack2-makefile.diff >+ fi >+ >+} >+ >+src_compile() { >+ local myopts >+ >+ use lowmem && \ >+ myopts="-DLOW_MEMORY" >+ >+ if use h323; then >+ einfo "Building H.323 wrapper lib..." >+ make -C channels/h323 \ >+ NOTRACE=1 \ >+ PWLIBDIR=/usr/share/pwlib \ >+ OPENH323DIR=/usr/share/openh323 \ >+ libchanh323.a Makefile.ast || die "Make h323 failed" >+ fi >+ >+ einfo "Building Asterisk..." >+ make \ >+ CC=$(tc-getCC) \ >+ NOTRACE=1 \ >+ OPTIMIZE="${CFLAGS}" \ >+ PWLIBDIR=/usr/share/pwlib \ >+ OPENH323DIR=/usr/share/openh323 \ >+ OPTIONS="${myopts}" || die "Make failed" >+ >+ # create api docs >+ use doc && \ >+ make progdocs >+ >+ # build bristuff's ISDNguard >+ use bri && \ >+ make -C "${S_BRI}"/ISDNguard >+} >+ >+src_install() { >+ >+ # install asterisk >+ make DESTDIR="${D}" ASTLIBDIR="\$(INSTALL_PREFIX)/usr/$(get_libdir)/asterisk" install || die "Make install failed" >+ make DESTDIR="${D}" ASTLIBDIR="\$(INSTALL_PREFIX)/usr/$(get_libdir)/asterisk" samples || die "Failed to create sample files" >+ >+ # remove bristuff capi >+ use bri && \ >+ rm -f "${D}"usr/$(get_libdir)/asterisk/modules/{app,chan}_capi*.so 2>/dev/null >+ >+ # remove installed sample files if nosamples flag is set >+ if use nosamples; then >+ einfo "Skipping installation of sample files..." >+ rm -rf "${D}"var/spool/asterisk/voicemail/default >+ rm -f "${D}"var/lib/asterisk/mohmp3/* >+ rm -f "${D}"var/lib/asterisk/sounds/demo-* >+ rm -f "${D}"var/lib/asterisk/agi-bin/* >+ else >+ einfo "Sample files have been installed" >+ keepdir /var/spool/asterisk/voicemail/default/1234/INBOX >+ fi >+ >+ # move sample configuration files to doc directory >+ if is_ast10update; then >+ elog "Updating from old (pre-1.2) asterisk version, new configuration files have been installed" >+ elog "into ${ROOT}etc/asterisk, use etc-update or dispatch-conf to update them" >+ elif has_version "net-misc/asterisk"; then >+ elog "Configuration samples have been moved to: $ROOT/usr/share/doc/${PF}/conf" >+ insinto /usr/share/doc/${PF}/conf >+ doins "${D}"etc/asterisk/*.conf* >+ rm -f "${D}"etc/asterisk/*.conf* 2>/dev/null >+ fi >+ >+ # don't delete these directories, even if they are empty >+ for x in voicemail meetme system dictate monitor tmp; do >+ keepdir /var/spool/asterisk/${x} >+ done >+ keepdir /var/lib/asterisk/sounds/priv-callerintros >+ keepdir /var/lib/asterisk/mohmp3 >+ keepdir /var/lib/asterisk/agi-bin >+ keepdir /var/log/asterisk/cdr-csv >+ keepdir /var/log/asterisk/cdr-custom >+ keepdir /var/run/asterisk >+ >+ # install astxs >+ dobin contrib/scripts/astxs >+ >+ newinitd "${FILESDIR}"/1.2.0/asterisk.rc6 asterisk >+ newconfd "${FILESDIR}"/1.2.0/asterisk.confd asterisk >+ >+ # install standard docs... >+ dodoc BUGS CREDITS LICENSE ChangeLog HARDWARE README README.fpm >+ dodoc SECURITY doc/CODING-GUIDELINES doc/linkedlists.README UPGRADE.txt >+ dodoc doc/README.* >+ dodoc doc/*.txt >+ >+ docinto scripts >+ dodoc contrib/scripts/* >+ >+ docinto utils >+ dodoc contrib/utils/* >+ >+ docinto configs >+ dodoc configs/* >+ >+ # install api docs >+ if use doc; then >+ insinto /usr/share/doc/${PF}/api/html >+ doins doc/api/html/* >+ fi >+ >+ # install ISDNguard >+ if use bri; then >+ cd "${S_BRI}"/ISDNguard >+ dosbin ISDNguard >+ >+ docinto ISDNguard >+ dodoc INSTALL.ISDNguard >+ >+ cd "${S}" >+ fi >+ >+ insinto /usr/share/doc/${PF}/cgi >+ doins contrib/scripts/vmail.cgi >+ doins images/*.gif >+ >+ # install asterisk-updater >+ dosbin "${FILESDIR}"/1.2.0/asterisk-updater >+ >+ # install asterisk.h, a lot of external modules need this >+ insinto /usr/include/asterisk >+ doins include/asterisk.h >+ >+ # make sure misdn/capi stuff is not installed, provided by asterisk-chan_.. >+ rm -f "${D}"/etc/asterisk/misdn.conf "${D}"/usr/lib/asterisk/modules/chan_misdn.so \ >+ "${D}"/usr/share/doc/${PF}/{conf/misdn.conf,configs/misdn.conf.sample.gz,README.misdn.gz} >+ rm -f "${D}"/usr/include/asterisk/chan_capi{,_app}.h \ >+ "${D}"/usr/share/doc/${PF}/{conf/capi.conf,configs/capi.conf.sample.gz} >+} >+ >+pkg_preinst() { >+ enewgroup asterisk >+ enewuser asterisk -1 -1 /var/lib/asterisk asterisk >+} >+ >+pkg_postinst() { >+ einfo "Fixing permissions" >+ chown -R asterisk:asterisk "${ROOT}"var/log/asterisk >+ chmod -R u=rwX,g=rX,o= "${ROOT}"var/log/asterisk >+ >+ for x in lib run spool; do >+ chown -R asterisk:asterisk "${ROOT}"var/${x}/asterisk >+ chmod -R u=rwX,g=rwX,o= "${ROOT}"var/${x}/asterisk >+ done >+ >+ chown asterisk:asterisk "${ROOT}"etc/asterisk/ >+ chown asterisk:asterisk "${ROOT}"etc/asterisk/*.adsi >+ chown asterisk:asterisk "${ROOT}"etc/asterisk/extensions.ael >+ chmod u=rwX,g=rwX,o= "${ROOT}"etc/asterisk/ >+ chmod u=rwX,g=rwX,o= "${ROOT}"etc/asterisk/*.adsi >+ chmod u=rwX,g=rwX,o= "${ROOT}"etc/asterisk/extensions.ael >+ echo >+ >+ # >+ # Announcements, warnings, reminders... >+ # >+ einfo "Asterisk has been installed" >+ einfo "" >+ elog "If you want to know more about asterisk, visit these sites:" >+ elog "http://www.asteriskdocs.org/" >+ elog "http://www.voip-info.org/wiki-Asterisk" >+ elog >+ elog "http://www.automated.it/guidetoasterisk.htm" >+ elog >+ elog "Gentoo VoIP IRC Channel:" >+ elog "#gentoo-voip @ irc.freenode.net" >+ elog >+ elog "Please note that AEL is no longer built because of security bugs" >+ elog "See http://bugs.gentoo.org/show_bug.cgi?id=171884" >+ elog >+ echo >+ echo >+ >+ # >+ # Warning about 1.0 -> 1.2 changes... >+ # >+ if is_ast10update; then >+ ewarn "" >+ ewarn "- Please read ${ROOT}usr/share/doc/${PF}/UPGRADE.txt.gz before continuing" >+ ewarn "" >+ fi >+ >+ if is_astupdate; then >+ ewarn "" >+ ewarn " - The initgroups patch has been dropped, please update your" >+ ewarn " \"conf.d/asterisk\" and \"init.d/asterisk\" file!" >+ ewarn "" >+ fi >+ >+ # scan for old modules >+ if is_ast10update; then >+ einfo "Asterisk has been updated from pre-1.2.x, scanning for old modules" >+ scan_modules >+ fi >+} >+ >+pkg_config() { >+ einfo "Do you want to reset file permissions and ownerships (y/N)?" >+ >+ read tmp >+ tmp="$(echo $tmp | tr [:upper:] [:lower:])" >+ >+ if [[ "$tmp" = "y" ]] ||\ >+ [[ "$tmp" = "yes" ]] >+ then >+ einfo "Resetting permissions to defaults..." >+ >+ for x in spool run lib log; do >+ chown -R asterisk:asterisk "${ROOT}"var/${x}/asterisk >+ chmod -R u=rwX,g=rX,o= "${ROOT}"var/${x}/asterisk >+ done >+ >+ chown -R root:asterisk "${ROOT}"etc/asterisk >+ chmod -R u=rwX,g=rX,o= "${ROOT}"etc/asterisk >+ >+ einfo "done" >+ else >+ einfo "skipping" >+ fi >+} >diff -ruN asterisk-ori/files/1.2.0/backports/app_stack/app_stack2.c asterisk/files/1.2.0/backports/app_stack/app_stack2.c >--- asterisk-ori/files/1.2.0/backports/app_stack/app_stack2.c 1970-01-01 01:00:00.000000000 +0100 >+++ asterisk/files/1.2.0/backports/app_stack/app_stack2.c 2008-03-03 20:05:51.000000000 +0100 >@@ -0,0 +1,267 @@ >+/* >+ * Asterisk -- An open source telephony toolkit. >+ * >+ * Copyright (c) 2004-2006 Tilghman Lesher <app_stack_v003@the-tilghman.com>. >+ * >+ * This code is released by the author with no restrictions on usage. >+ * >+ * See http://www.asterisk.org for more information about >+ * the Asterisk project. Please do not directly contact >+ * any of the maintainers of this project for assistance; >+ * the project provides a web site, mailing lists and IRC >+ * channels for your use. >+ * >+ * This program is free software, distributed under the terms of >+ * the GNU General Public License Version 2. See the LICENSE file >+ * at the top of the source tree. >+ */ >+ >+/*! \file >+ * >+ * \brief Stack applications Gosub, Return, etc. >+ * >+ * \ingroup applications >+ */ >+ >+#include <stdio.h> >+#include <stdlib.h> >+#include <unistd.h> >+#include <string.h> >+ >+#include "asterisk/options.h" >+#include "asterisk/logger.h" >+#include "asterisk/channel.h" >+#include "asterisk/chanvars.h" >+#include "asterisk/pbx.h" >+#include "asterisk/module.h" >+#include "asterisk/config.h" >+#include "asterisk/app.h" >+ >+#define STACKVAR "~GOSUB2~STACK~" >+ >+static const char *tdesc = "Stack Routines"; >+ >+static const char *app_gosub = "Gosub2"; >+static const char *app_gosubif = "GosubIf2"; >+static const char *app_return = "Return2"; >+static const char *app_pop = "StackPop2"; >+ >+static const char *gosub_synopsis = "Jump to label, saving return address"; >+static const char *gosubif_synopsis = "Jump to label, saving return address"; >+static const char *return_synopsis = "Return from gosub routine"; >+static const char *pop_synopsis = "Remove one address from gosub stack"; >+ >+static const char *gosub_descrip = >+"Gosub2([[context|]exten|]priority[(arg1[|...][|argN])])\n" >+" Jumps to the label specified, saving the return address.\n"; >+static const char *gosubif_descrip = >+"GosubIf2(condition?labeliftrue[(arg1[|...])][:labeliffalse[(arg1[|...])]])\n" >+" If the condition is true, then jump to labeliftrue. If false, jumps to\n" >+"labeliffalse, if specified. In either case, a jump saves the return point\n" >+"in the dialplan, to be returned to with a Return.\n"; >+static const char *return_descrip = >+"Return2([return-value])\n" >+" Jumps to the last label on the stack, removing it. The return value, if\n" >+"any, is saved in the channel variable GOSUB_RETVAL.\n"; >+static const char *pop_descrip = >+"StackPop2()\n" >+" Removes last label on the stack, discarding it.\n"; >+ >+STANDARD_LOCAL_USER; >+ >+LOCAL_USER_DECL; >+ >+static int pop_exec(struct ast_channel *chan, void *data) >+{ >+ const char *frame = pbx_builtin_getvar_helper(chan, STACKVAR); >+ int numargs = 0, i; >+ char argname[15]; >+ >+ /* Pop any arguments for this stack frame off the variable stack */ >+ if (frame) { >+ numargs = atoi(frame); >+ for (i = 1; i <= numargs; i++) { >+ snprintf(argname, sizeof(argname), "ARG%d", i); >+ pbx_builtin_setvar_helper(chan, argname, NULL); >+ } >+ } >+ >+ /* Remove the last frame from the Gosub stack */ >+ pbx_builtin_setvar_helper(chan, STACKVAR, NULL); >+ >+ return 0; >+} >+ >+static int return_exec(struct ast_channel *chan, void *data) >+{ >+ char *label = pbx_builtin_getvar_helper(chan, STACKVAR); >+ char argname[15], *retval = data; >+ int numargs, i; >+ >+ if (ast_strlen_zero(label)) { >+ ast_log(LOG_ERROR, "Return2 without Gosub2: stack is empty\n"); >+ return -1; >+ } >+ >+ /* Pop any arguments for this stack frame off the variable stack */ >+ numargs = atoi(label); >+ for (i = 1; i <= numargs; i++) { >+ snprintf(argname, sizeof(argname), "ARG%d", i); >+ pbx_builtin_setvar_helper(chan, argname, NULL); >+ } >+ >+ /* If the label exists, it will always have a ':' */ >+ label = strchr(label, ':') + 1; >+ >+ if (ast_parseable_goto(chan, label)) { >+ ast_log(LOG_WARNING, "No next statement after Gosub2?\n"); >+ return -1; >+ } >+ >+ /* Remove the current frame from the Gosub stack */ >+ pbx_builtin_setvar_helper(chan, STACKVAR, NULL); >+ >+ /* Set a return value, if any */ >+ pbx_builtin_setvar_helper(chan, "GOSUB_RETVAL", !ast_strlen_zero(retval) ? retval : ""); >+ return 0; >+} >+ >+static int gosub_exec(struct ast_channel *chan, void *data) >+{ >+ char newlabel[AST_MAX_EXTENSION + AST_MAX_CONTEXT + 11 + 11 + 4]; >+ char argname[15], *tmp = ast_strdupa(data), *label, *endparen; >+ int i; >+ struct localuser *u; >+ AST_DECLARE_APP_ARGS(args2, >+ AST_APP_ARG(argval)[100]; >+ ); >+ >+ if (ast_strlen_zero(data)) { >+ ast_log(LOG_ERROR, "Gosub2 requires an argument: Gosub2([[context|]exten|]priority[(arg1[|...][|argN])])\n"); >+ return -1; >+ } >+ >+ LOCAL_USER_ADD(u); >+ >+ /* Separate the arguments from the label */ >+ /* NOTE: you cannot use ast_app_separate_args for this, because '(' cannot be used as a delimiter. */ >+ label = strsep(&tmp, "("); >+ if (tmp) { >+ endparen = strrchr(tmp, ')'); >+ if (endparen) >+ *endparen = '\0'; >+ else >+ ast_log(LOG_WARNING, "Ouch. No closing paren: '%s'?\n", (char *)data); >+ AST_STANDARD_APP_ARGS(args2, tmp); >+ } else >+ args2.argc = 0; >+ >+ /* Create the return address, but don't save it until we know that the Gosub destination exists */ >+ snprintf(newlabel, sizeof(newlabel), "%d:%s|%s|%d", args2.argc == 2 ? args2.argc : 0, chan->context, chan->exten, chan->priority + 1); >+ >+ if (ast_parseable_goto(chan, data)) { >+ ast_log(LOG_WARNING, "Destination '%s' does not exist in the dialplan\n", (char *)data); >+ LOCAL_USER_REMOVE(u); >+ return -1; >+ } >+ >+ /* Now that we know for certain that we're going to a new location, set our arguments */ >+ for (i = 0; i < args2.argc; i++) { >+ snprintf(argname, sizeof(argname), "ARG%d", i + 1); >+ pbx_builtin_pushvar_helper(chan, argname, args2.argval[i]); >+ ast_log(LOG_DEBUG, "Setting %s to '%s'\n", argname, args2.argval[i]); >+ } >+ >+ /* And finally, save our return address */ >+ pbx_builtin_pushvar_helper(chan, STACKVAR, newlabel); >+ ast_log(LOG_DEBUG, "Setting gosub return address to %s\n", newlabel); >+ >+ LOCAL_USER_REMOVE(u); >+ >+ return 0; >+} >+ >+static int gosubif_exec(struct ast_channel *chan, void *data) >+{ >+ struct localuser *u; >+ char *args; >+ int res=0; >+ AST_DECLARE_APP_ARGS(cond, >+ AST_APP_ARG(ition); >+ AST_APP_ARG(labels); >+ ); >+ AST_DECLARE_APP_ARGS(label, >+ AST_APP_ARG(iftrue); >+ AST_APP_ARG(iffalse); >+ ); >+ >+ if (ast_strlen_zero(data)) { >+ ast_log(LOG_WARNING, "GosubIf2 requires an argument: GosubIf2(cond?label1(args):label2(args)\n"); >+ return 0; >+ } >+ >+ LOCAL_USER_ADD(u); >+ >+ args = ast_strdupa((char *)data); >+ /* AST_NONSTANDARD_APP_ARGS(cond, args, '?'); */ >+ cond.argc = ast_app_separate_args(args, '?', cond.argv, (sizeof(cond) - sizeof(cond.argc)) / sizeof(cond.argv[0])); >+ if (cond.argc != 2) { >+ ast_log(LOG_WARNING, "GosubIf2 requires an argument: GosubIf2(cond?label1(args):label2(args)\n"); >+ LOCAL_USER_REMOVE(u); >+ return 0; >+ } >+ >+ /* AST_NONSTANDARD_APP_ARGS(label, cond.labels, ':'); */ >+ label.argc = ast_app_separate_args(cond.labels, ':', label.argv, (sizeof(label) - sizeof(label.argc)) / sizeof(label.argv[0])); >+ >+ if (pbx_checkcondition(cond.ition)) { >+ if (!ast_strlen_zero(label.iftrue)) >+ res = gosub_exec(chan, label.iftrue); >+ } else if (!ast_strlen_zero(label.iffalse)) { >+ res = gosub_exec(chan, label.iffalse); >+ } >+ >+ LOCAL_USER_REMOVE(u); >+ return res; >+} >+ >+int unload_module(void) >+{ >+ ast_unregister_application(app_return); >+ ast_unregister_application(app_pop); >+ ast_unregister_application(app_gosubif); >+ ast_unregister_application(app_gosub); >+ >+ STANDARD_HANGUP_LOCALUSERS; >+ >+ return 0; >+} >+ >+int load_module(void) >+{ >+ ast_register_application(app_pop, pop_exec, pop_synopsis, pop_descrip); >+ ast_register_application(app_return, return_exec, return_synopsis, return_descrip); >+ ast_register_application(app_gosubif, gosubif_exec, gosubif_synopsis, gosubif_descrip); >+ ast_register_application(app_gosub, gosub_exec, gosub_synopsis, gosub_descrip); >+ >+ return 0; >+} >+ >+char *description(void) >+{ >+ return (char *) tdesc; >+} >+ >+int usecount(void) >+{ >+ int res; >+ >+ STANDARD_USECOUNT(res); >+ >+ return res; >+} >+ >+char *key() >+{ >+ return ASTERISK_GPL_KEY; >+} >diff -ruN asterisk-ori/files/1.2.0/backports/app_stack/asterisk-app_stack2-makefile.diff asterisk/files/1.2.0/backports/app_stack/asterisk-app_stack2-makefile.diff >--- asterisk-ori/files/1.2.0/backports/app_stack/asterisk-app_stack2-makefile.diff 1970-01-01 01:00:00.000000000 +0100 >+++ asterisk/files/1.2.0/backports/app_stack/asterisk-app_stack2-makefile.diff 2008-03-03 21:10:33.000000000 +0100 >@@ -0,0 +1,11 @@ >+--- asterisk-1.2.26.2-original/apps/Makefile 2006-04-30 15:38:22.000000000 +0200 >++++ asterisk-1.2.26.2/apps/Makefile 2008-03-03 21:07:33.000000000 +0100 >+@@ -44,6 +44,8 @@ >+ #APPS+=app_skel.so >+ #APPS+=app_rpt.so >+ >++APPS+=app_stack2.so >++ >+ ifndef WITHOUT_ZAPTEL >+ ifneq ($(wildcard $(CROSS_COMPILE_TARGET)/usr/include/linux/zaptel.h)$(wildcard $(CROSS_COMPILE_TARGET)/usr/local/include/zaptel.h),) >+ APPS+=app_zapras.so app_meetme.so app_flash.so app_zapbarge.so app_zapscan.so app_page.so >diff -ruN asterisk-ori/files/1.2.0/backports/func_odbc/func_array.c asterisk/files/1.2.0/backports/func_odbc/func_array.c >--- asterisk-ori/files/1.2.0/backports/func_odbc/func_array.c 1970-01-01 01:00:00.000000000 +0100 >+++ asterisk/files/1.2.0/backports/func_odbc/func_array.c 2008-03-03 19:17:40.000000000 +0100 >@@ -0,0 +1,332 @@ >+/* >+ * Asterisk -- An open source telephony toolkit. >+ * >+ * Copyright (C) 2005, Tilghman Lesher. >+ * >+ * See http://www.asterisk.org for more information about >+ * the Asterisk project. Please do not directly contact >+ * any of the maintainers of this project for assistance; >+ * the project provides a web site, mailing lists and IRC >+ * channels for your use. >+ * >+ * This program is free software, distributed under the terms of >+ * the GNU General Public License Version 2. See the LICENSE file >+ * at the top of the source tree. >+ */ >+ >+/*! \file >+ * >+ * \brief ARRAY dialplan function >+ * >+ * \author Tilghman Lesher >+ */ >+ >+#include <stdlib.h> >+#include <stdio.h> >+#include <string.h> >+#include <sys/types.h> >+#include <sched.h> >+ >+#include "asterisk.h" >+ >+ASTERISK_FILE_VERSION(__FILE__, "$Revision: 20003 $") >+ >+#include "asterisk/module.h" >+#include "asterisk/channel.h" >+#include "asterisk/pbx.h" >+#include "asterisk/logger.h" >+#include "asterisk/utils.h" >+#include "asterisk/app.h" >+#include "asterisk/localtime.h" >+#include "asterisk/linkedlists.h" >+ >+#include "separate.h" >+ >+#define HASH_PREFIX "~HASH~%s~" >+#define HASH_FORMAT HASH_PREFIX "%s~" >+ >+AST_MUTEX_DEFINE_STATIC(local_lock); >+static int use_count = 0; >+ >+static char *app_clearhash = "ClearHash"; >+static char *syn_clearhash = "Clear the keys from a specified hashname"; >+static char *desc_clearhash = >+"ClearHash(<hashname>)\n" >+" Clears all keys out of the specified hashname\n"; >+ >+/* This function probably should migrate to main/pbx.c, as pbx_builtin_clearvar_prefix() */ >+static void clearvar_prefix(struct ast_channel *chan, const char *prefix) >+{ >+ struct ast_var_t *newvar; >+ int len = strlen(prefix); >+ AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->varshead, newvar, entries) { >+ if (strncasecmp(prefix, ast_var_name(newvar), len) == 0) { >+ AST_LIST_REMOVE_CURRENT(&chan->varshead, entries); >+ free(newvar); >+ } >+ } >+ AST_LIST_TRAVERSE_SAFE_END >+} >+ >+static int exec_clearhash(struct ast_channel *chan, void *data) >+{ >+ char prefix[80]; >+ snprintf(prefix, sizeof(prefix), HASH_PREFIX, data ? (char *)data : "null"); >+ clearvar_prefix(chan, prefix); >+ return 0; >+} >+ >+static void array(struct ast_channel *chan, char *cmd, char *var, const char *value) >+{ >+ AST_DECLARE_APP_ARGS(arg1, >+ AST_APP_ARG(var)[100]; >+ ); >+ AST_DECLARE_APP_ARGS(arg2, >+ AST_APP_ARG(val)[100]; >+ ); >+ char *origvar = "", *value2, varname[256]; >+ int i, ishash = 0; >+ >+ value2 = ast_strdupa(value); >+ if (!var || !value2) >+ return; >+ >+ ast_mutex_lock(&local_lock); >+ use_count++; >+ ast_mutex_unlock(&local_lock); >+ >+ if (!strcmp(cmd, "HASH")) { >+ const char *var2 = pbx_builtin_getvar_helper(chan, "~ODBCFIELDS~"); >+ origvar = var; >+ if (var2) >+ var = ast_strdupa(var2); >+ else >+ return; >+ ishash = 1; >+ } >+ >+ /* The functions this will generally be used with are SORT and ODBC_*, which >+ * both return comma-delimited lists. However, if somebody uses literal lists, >+ * their commas will be translated to vertical bars by the load, and I don't >+ * want them to be surprised by the result. Hence, we prefer commas as the >+ * delimiter, but we'll fall back to vertical bars if commas aren't found. >+ */ >+ ast_log(LOG_DEBUG, "array (%s=%s)\n", var, value2); >+ if (strchr(var, ',')) >+ TRUNK_NONSTANDARD_APP_ARGS(arg1, var, ','); >+ else >+ TRUNK_STANDARD_APP_ARGS(arg1, var); >+ >+ if (strchr(value2, ',')) >+ TRUNK_NONSTANDARD_APP_ARGS(arg2, value2, ','); >+ else >+ TRUNK_STANDARD_APP_ARGS(arg2, value2); >+ >+ for (i = 0; i < arg1.argc; i++) { >+ ast_log(LOG_DEBUG, "array set value (%s=%s)\n", arg1.var[i], >+ arg2.val[i]); >+ if (i < arg2.argc) { >+ if (ishash) { >+ snprintf(varname, sizeof(varname), HASH_FORMAT, origvar, arg1.var[i]); >+ pbx_builtin_setvar_helper(chan, varname, arg2.val[i]); >+ } else { >+ pbx_builtin_setvar_helper(chan, arg1.var[i], arg2.val[i]); >+ } >+ } else { >+ /* We could unset the variable, by passing a NULL, but due to >+ * pushvar semantics, that could create some undesired behavior. */ >+ if (ishash) { >+ snprintf(varname, sizeof(varname), HASH_FORMAT, origvar, arg1.var[i]); >+ pbx_builtin_setvar_helper(chan, varname, ""); >+ } else { >+ pbx_builtin_setvar_helper(chan, arg1.var[i], ""); >+ } >+ } >+ } >+ >+ ast_mutex_lock(&local_lock); >+ use_count--; >+ ast_mutex_unlock(&local_lock); >+ >+ return; >+} >+ >+static char *hashkeys_read(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len) >+{ >+ struct ast_var_t *newvar; >+ int plen; >+ char prefix[80]; >+ snprintf(prefix, sizeof(prefix), HASH_PREFIX, data); >+ plen = strlen(prefix); >+ >+ memset(buf, 0, len); >+ AST_LIST_TRAVERSE(&chan->varshead, newvar, entries) { >+ if (strncasecmp(prefix, ast_var_name(newvar), plen) == 0) { >+ /* Copy everything after the prefix */ >+ strncat(buf, ast_var_name(newvar) + plen, len); >+ /* Trim the trailing ~ */ >+ buf[strlen(buf) - 1] = ','; >+ } >+ } >+ /* Trim the trailing comma */ >+ buf[strlen(buf) - 1] = '\0'; >+ return buf; >+} >+ >+static void hash_write(struct ast_channel *chan, char *cmd, char *var, const char *value) >+{ >+ char varname[256]; >+ AST_DECLARE_APP_ARGS(arg, >+ AST_APP_ARG(hashname); >+ AST_APP_ARG(hashkey); >+ ); >+ >+ ast_mutex_lock(&local_lock); >+ use_count++; >+ ast_mutex_unlock(&local_lock); >+ >+ if (!strchr(var, '|')) { >+ /* Single argument version */ >+ array(chan, "HASH", var, value); >+ return; >+ } >+ >+ TRUNK_STANDARD_APP_ARGS(arg, var); >+ snprintf(varname, sizeof(varname), HASH_FORMAT, arg.hashname, arg.hashkey); >+ pbx_builtin_setvar_helper(chan, varname, value); >+ >+ ast_mutex_lock(&local_lock); >+ use_count--; >+ ast_mutex_unlock(&local_lock); >+} >+ >+static char *hash_read(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len) >+{ >+ char varname[256]; >+ const char *varvalue; >+ AST_DECLARE_APP_ARGS(arg, >+ AST_APP_ARG(hashname); >+ AST_APP_ARG(hashkey); >+ ); >+ >+ ast_mutex_lock(&local_lock); >+ use_count++; >+ ast_mutex_unlock(&local_lock); >+ >+ TRUNK_STANDARD_APP_ARGS(arg, data); >+ if (arg.argc == 2) { >+ snprintf(varname, sizeof(varname), HASH_FORMAT, arg.hashname, arg.hashkey); >+ varvalue = pbx_builtin_getvar_helper(chan, varname); >+ if (varvalue) >+ ast_copy_string(buf, varvalue, len); >+ else >+ *buf = '\0'; >+ } else if (arg.argc == 1) { >+ char colnames[4096]; >+ int i; >+ AST_DECLARE_APP_ARGS(arg2, >+ AST_APP_ARG(col)[100]; >+ ); >+ >+ /* Get column names, in no particular order */ >+ hashkeys_read(chan, "HASHKEYS", arg.hashname, colnames, sizeof(colnames)); >+ pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", colnames); >+ >+ TRUNK_NONSTANDARD_APP_ARGS(arg2, colnames, ','); >+ *buf = '\0'; >+ >+ /* Now get the corresponding column values, in exactly the same order */ >+ for (i = 0; i < arg2.argc; i++) { >+ snprintf(varname, sizeof(varname), HASH_FORMAT, arg.hashname, arg2.col[i]); >+ varvalue = pbx_builtin_getvar_helper(chan, varname); >+ strncat(buf, varvalue, len); >+ strncat(buf, ",", len); >+ } >+ >+ /* Strip trailing comma */ >+ buf[strlen(buf) - 1] = '\0'; >+ } >+ >+ return buf; >+} >+ >+static struct ast_custom_function array_function = { >+ .name = "ARRAY", >+ .synopsis = "Allows setting multiple variables at once", >+ .syntax = "ARRAY(var1[|var2[...][|varN]])", >+ .write = array, >+ .desc = >+ "The comma-separated list passed as a value to which the function is set will\n" >+ "be interpreted as a set of values to which the comma-separated list of\n" >+ "variable names in the argument should be set.\n" >+ "Hence, Set(ARRAY(var1,var2)=1,2) will set var1 to 1 and var2 to 2\n" >+ "Note: remember to either backslash your commas in extensions.conf or quote the\n" >+ "entire argument, since Set can take multiple arguments itself.\n", >+}; >+ >+static struct ast_custom_function hash_function = { >+ .name = "HASH", >+ .synopsis = "Implementation of a dialplan associative array", >+ .syntax = "HASH(hashname[|hashkey])", >+ .write = hash_write, >+ .read = hash_read, >+ .desc = >+ "In two argument mode, gets and sets values to corresponding keys within a named\n" >+ "associative array. The single-argument mode will only work when assigned to from\n" >+ "a function defined by func_odbc.so.\n", >+}; >+ >+static struct ast_custom_function hashkeys_function = { >+ .name = "HASHKEYS", >+ .synopsis = "Retrieve the keys of a HASH()", >+ .syntax = "HASHKEYS(<hashname>)", >+ .read = hashkeys_read, >+ .desc = >+ "Returns a comma-delimited list of the current keys of an associative array\n" >+ "defined by the HASH() function. Note that if you iterate over the keys of\n" >+ "the result, adding keys during iteration will cause the result of the HASHKEYS\n" >+ "function to change.\n", >+}; >+ >+static char *tdesc = "String handling dialplan functions"; >+ >+int unload_module(void) >+{ >+ int res = 0; >+ >+ res |= ast_custom_function_unregister(&array_function); >+ res |= ast_custom_function_unregister(&hash_function); >+ res |= ast_custom_function_unregister(&hashkeys_function); >+ res |= ast_unregister_application(app_clearhash); >+ sched_yield(); /* Any remaining process gets time to clear out. Increases safety if a force unload is attempted. */ >+ >+ return res; >+} >+ >+int load_module(void) >+{ >+ int res = 0; >+ >+ res |= ast_custom_function_register(&array_function); >+ res |= ast_custom_function_register(&hash_function); >+ res |= ast_custom_function_register(&hashkeys_function); >+ res |= ast_register_application(app_clearhash, exec_clearhash, syn_clearhash, desc_clearhash); >+ >+ return res; >+} >+ >+char *description(void) >+{ >+ return tdesc; >+} >+ >+int usecount(void) >+{ >+ return use_count; >+} >+ >+char *key(void) >+{ >+ return ASTERISK_GPL_KEY; >+} >+ >diff -ruN asterisk-ori/files/1.2.0/backports/func_odbc/func_odbc.c asterisk/files/1.2.0/backports/func_odbc/func_odbc.c >--- asterisk-ori/files/1.2.0/backports/func_odbc/func_odbc.c 1970-01-01 01:00:00.000000000 +0100 >+++ asterisk/files/1.2.0/backports/func_odbc/func_odbc.c 2008-03-03 19:18:11.000000000 +0100 >@@ -0,0 +1,800 @@ >+/* >+ * Asterisk -- An open source telephony toolkit. >+ * >+ * Copyright (c) 2005 Tilghman Lesher >+ * >+ * Tilghman Lesher <func_odbc__200604@the-tilghman.com> >+ * >+ * See http://www.asterisk.org for more information about >+ * the Asterisk project. Please do not directly contact >+ * any of the maintainers of this project for assistance; >+ * the project provides a web site, mailing lists and IRC >+ * channels for your use. >+ * >+ * This program is free software, distributed under the terms of >+ * the GNU General Public License Version 2. See the LICENSE file >+ * at the top of the source tree. >+ */ >+ >+/*! >+ * \file >+ * >+ * \brief ODBC lookups >+ * >+ * \author Tilghman Lesher <func_odbc__200604@the-tilghman.com> >+ */ >+ >+#include <sys/types.h> >+#include <stdio.h> >+#include <stdlib.h> >+#include <unistd.h> >+#include <string.h> >+#include <errno.h> >+ >+#include "asterisk.h" >+ >+ASTERISK_FILE_VERSION(__FILE__, "$Revision$") >+ >+#include "asterisk/module.h" >+#include "asterisk/file.h" >+#include "asterisk/logger.h" >+#include "asterisk/options.h" >+#include "asterisk/channel.h" >+#include "asterisk/pbx.h" >+#include "asterisk/module.h" >+#include "asterisk/config.h" >+#include "asterisk/res_odbc.h" >+#include "asterisk/app.h" >+ >+#include "separate.h" >+ >+static char *tdesc = "ODBC lookups"; >+ >+static char *config = "func_odbc.conf"; >+ >+enum { >+ OPT_ESCAPECOMMAS = (1 << 0), >+} odbc_option_flags; >+ >+struct acf_odbc_query { >+ AST_LIST_ENTRY(acf_odbc_query) list; >+ char readhandle[5][30]; >+ char writehandle[5][30]; >+ char sql_read[2048]; >+ char sql_write[2048]; >+ unsigned int flags; >+ struct ast_custom_function *acf; >+}; >+ >+AST_LIST_HEAD_STATIC(queries, acf_odbc_query); >+ >+#ifdef NEEDTRACE >+static void acf_odbc_error(SQLHSTMT stmt, int res) >+{ >+ char state[10] = "", diagnostic[256] = ""; >+ SQLINTEGER nativeerror = 0; >+ SQLSMALLINT diagbytes = 0; >+ SQLGetDiagRec(SQL_HANDLE_STMT, stmt, 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); >+ ast_log(LOG_WARNING, "SQL return value %d: error %s: %s (len %d)\n", res, state, diagnostic, diagbytes); >+} >+#endif >+ >+/* >+ * Master control routine >+ */ >+#define INCREMENT_DSN if (++dsn < 5 && !ast_strlen_zero(query->writehandle[dsn])) goto retry_write >+static void acf_odbc_write(struct ast_channel *chan, char *cmd, char *data, const char *value) >+{ >+ odbc_obj *obj; >+ struct acf_odbc_query *query; >+ char *s, *t, buf[2048]="", varname[15]; >+ int res, i, dsn = 0, alloc, prepare, execute; >+ SQLHSTMT stmt; >+ SQLINTEGER nativeerror=0, numfields=0, rows=0; >+ SQLSMALLINT diagbytes=0; >+ unsigned char state[10], diagnostic[256]; >+ AST_DECLARE_APP_ARGS(args, >+ AST_APP_ARG(arg)[100]; >+ ); >+ AST_DECLARE_APP_ARGS(values, >+ AST_APP_ARG(val)[100]; >+ ); >+#ifdef NEEDTRACE >+ SQLINTEGER enable = 1; >+ char *tracefile = "/tmp/odbc.trace"; >+#endif >+ >+ AST_LIST_LOCK(&queries); >+ AST_LIST_TRAVERSE(&queries, query, list) { >+ if (!strcmp(query->acf->name, cmd)) { >+ break; >+ } >+ } >+ >+ if (!query) { >+ ast_log(LOG_ERROR, "No such function '%s'\n", cmd); >+ AST_LIST_UNLOCK(&queries); >+ return; >+ } >+ >+ /* Parse our arguments */ >+ s = ast_strdupa(data); >+ if (value) { >+ t = ast_strdupa(value); >+ } else { >+ t = ""; >+ } >+ >+ if (!s || !t) { >+ ast_log(LOG_ERROR, "Out of memory\n"); >+ AST_LIST_UNLOCK(&queries); >+ return; >+ } >+ >+ TRUNK_STANDARD_APP_ARGS(args, s); >+ for (i = 0; i < args.argc; i++) { >+ snprintf(varname, sizeof(varname), "ARG%d", i + 1); >+ pbx_builtin_pushvar_helper(chan, varname, args.arg[i]); >+ } >+ >+ TRUNK_NONSTANDARD_APP_ARGS(values, t, ','); >+ for (i = 0; i < values.argc; i++) { >+ snprintf(varname, sizeof(varname), "VAL%d", i + 1); >+ pbx_builtin_pushvar_helper(chan, varname, values.val[i]); >+ } >+ >+ /* Additionally set the value as a whole */ >+ /* Note that pbx_builtin_setvar_helper will quite happily take a NULL for the 3rd argument */ >+ pbx_builtin_pushvar_helper(chan, "VALUE", value ? value : ""); >+ >+ pbx_substitute_variables_helper(chan, query->sql_write, buf, sizeof(buf) - 1); >+ >+ /* Restore prior values */ >+ for (i = 0; i < args.argc; i++) { >+ snprintf(varname, sizeof(varname), "ARG%d", i + 1); >+ pbx_builtin_setvar_helper(chan, varname, NULL); >+ } >+ >+ for (i = 0; i < values.argc; i++) { >+ snprintf(varname, sizeof(varname), "VAL%d", i + 1); >+ pbx_builtin_setvar_helper(chan, varname, NULL); >+ } >+ pbx_builtin_setvar_helper(chan, "VALUE", NULL); >+ >+ AST_LIST_UNLOCK(&queries); >+ >+retry_write: >+ obj = fetch_odbc_obj(query->writehandle[dsn], 0); >+ >+ if (!obj) { >+ INCREMENT_DSN; >+ ast_log(LOG_ERROR, "Unable to load ODBC write class (check res_odbc.conf)\n"); >+ return; >+ } >+ >+#ifdef NEEDTRACE >+ SQLSetConnectAttr(obj->con, SQL_ATTR_TRACE, &enable, SQL_IS_INTEGER); >+ SQLSetConnectAttr(obj->con, SQL_ATTR_TRACEFILE, tracefile, strlen(tracefile)); >+#endif >+ >+ for (execute = 0; execute < 2; execute++) { >+ for (prepare = 0; prepare < 2; prepare++) { >+ for (alloc = 0; alloc < 2; alloc++) { >+ res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt); >+ if ((res == SQL_SUCCESS) || (res == SQL_SUCCESS_WITH_INFO)) >+ break; >+ else if (alloc == 0) >+ odbc_sanity_check(obj); >+ else { >+ INCREMENT_DSN; >+ ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n"); >+ pbx_builtin_setvar_helper(chan, "ODBCROWS", "-1"); >+ return; >+ } >+ } >+ >+ res = SQLPrepare(stmt, (unsigned char *)buf, SQL_NTS); >+ if ((res == SQL_SUCCESS) || (res == SQL_SUCCESS_WITH_INFO)) >+ break; >+ else if (prepare == 0) >+ odbc_sanity_check(obj); >+ else { >+ INCREMENT_DSN; >+ ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", buf); >+ SQLCloseCursor(stmt); >+ SQLFreeHandle (SQL_HANDLE_STMT, stmt); >+ pbx_builtin_setvar_helper(chan, "ODBCROWS", "-1"); >+ return; >+ } >+ } >+ >+ res = SQLExecute(stmt); >+ if ((res == SQL_SUCCESS) || (res == SQL_SUCCESS_WITH_INFO)) { >+ /* Rows affected */ >+ SQLRowCount(stmt, &rows); >+ break; >+ } else if (execute == 0) >+ odbc_sanity_check(obj); >+ else { >+ if (res == SQL_ERROR) { >+ SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); >+ for (i = 0; i <= numfields; i++) { >+ SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); >+ ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes); >+ if (i > 10) { >+ ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); >+ break; >+ } >+ } >+ } >+ INCREMENT_DSN; >+ >+ if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { >+ ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", buf); >+ } >+ rows = -1; >+ } >+ } >+ >+ /* Output the affected rows, for all cases. In the event of failure, we >+ * flag this as -1 rows. Note that this is different from 0 affected rows >+ * which would be the case if we succeeded in our query, but the values did >+ * not change. */ >+ snprintf(varname, sizeof(varname), "%d", (int)rows); >+ pbx_builtin_setvar_helper(chan, "ODBCROWS", varname); >+ >+ SQLCloseCursor(stmt); >+ SQLFreeHandle(SQL_HANDLE_STMT, stmt); >+} >+#undef INCREMENT_DSN >+ >+#define INCREMENT_DSN if (++dsn < 5 && !ast_strlen_zero(query->readhandle[dsn])) goto restartread; >+static char *acf_odbc_read(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len) >+{ >+ odbc_obj *obj; >+ struct acf_odbc_query *query; >+ char *s, sql[2048] = "", varname[15], colnames[2048] = ""; >+ int res, x, buflen = 0, dsn = 0, escapecommas, alloc, prepare, execute; >+ AST_DECLARE_APP_ARGS(args, >+ AST_APP_ARG(arg)[100]; >+ ); >+ SQLHSTMT stmt; >+ SQLSMALLINT colcount=0; >+ SQLINTEGER indicator; >+ SQLSMALLINT collength; >+#ifdef NEEDTRACE >+ SQLINTEGER enable = 1; >+ char *tracefile = "/tmp/odbc.trace"; >+#endif >+ >+ AST_LIST_LOCK(&queries); >+ AST_LIST_TRAVERSE(&queries, query, list) { >+ if (!strcmp(query->acf->name, cmd)) { >+ break; >+ } >+ } >+ >+ if (!query) { >+ ast_log(LOG_ERROR, "No such function '%s'\n", cmd); >+ AST_LIST_UNLOCK(&queries); >+ return ""; >+ } >+ >+ /* Parse our arguments */ >+ if (!(s = ast_strdupa(data))) { >+ AST_LIST_UNLOCK(&queries); >+ return ""; >+ } >+ >+ TRUNK_STANDARD_APP_ARGS(args, s); >+ for (x = 0; x < args.argc; x++) { >+ snprintf(varname, sizeof(varname), "ARG%d", x + 1); >+ pbx_builtin_pushvar_helper(chan, varname, args.arg[x]); >+ } >+ >+ pbx_substitute_variables_helper(chan, query->sql_read, sql, sizeof(sql) - 1); >+ >+ /* Restore prior values */ >+ for (x = 0; x < args.argc; x++) { >+ snprintf(varname, sizeof(varname), "ARG%d", x + 1); >+ pbx_builtin_setvar_helper(chan, varname, NULL); >+ } >+ >+ /* Save this flag, so we can release the lock */ >+ escapecommas = ast_test_flag(query, OPT_ESCAPECOMMAS); >+ >+ AST_LIST_UNLOCK(&queries); >+ >+restartread: >+ obj = fetch_odbc_obj(query->readhandle[dsn], 0); >+ >+ if (!obj) { >+ INCREMENT_DSN; >+ ast_log(LOG_ERROR, "Unable to load ODBC read class (check res_odbc.conf)\n"); >+ return ""; >+ } >+ >+#ifdef NEEDTRACE >+ SQLSetConnectAttr(obj->con, SQL_ATTR_TRACE, &enable, SQL_IS_INTEGER); >+ SQLSetConnectAttr(obj->con, SQL_ATTR_TRACEFILE, tracefile, strlen(tracefile)); >+#endif >+ >+ for (execute = 0; execute < 2; execute++) { >+ for (prepare = 0; prepare < 2; prepare++) { >+ for (alloc = 0; alloc < 2; alloc++) { >+ res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt); >+ if ((res == SQL_SUCCESS) || (res == SQL_SUCCESS_WITH_INFO)) >+ break; >+ else if (alloc == 0) >+ odbc_sanity_check(obj); >+ else { >+ INCREMENT_DSN; >+ ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n"); >+ return ""; >+ } >+ } >+ >+ res = SQLPrepare(stmt, (unsigned char *)sql, SQL_NTS); >+ if ((res == SQL_SUCCESS) || (res == SQL_SUCCESS_WITH_INFO)) >+ break; >+ else if (prepare == 0) >+ odbc_sanity_check(obj); >+ else { >+ INCREMENT_DSN; >+ SQLCloseCursor(stmt); >+ SQLFreeHandle(SQL_HANDLE_STMT, stmt); >+ ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql); >+ return ""; >+ } >+ } >+ >+ res = odbc_smart_execute(obj, stmt); >+ if ((res == SQL_SUCCESS) || (res == SQL_SUCCESS_WITH_INFO)) >+ break; >+ else if (execute == 0) >+ odbc_sanity_check(obj); >+ else { >+ INCREMENT_DSN; >+ SQLCloseCursor(stmt); >+ SQLFreeHandle(SQL_HANDLE_STMT, stmt); >+ ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql); >+ return ""; >+ } >+ } >+ >+ res = SQLNumResultCols(stmt, &colcount); >+ if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { >+ ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql); >+ SQLCloseCursor(stmt); >+ SQLFreeHandle (SQL_HANDLE_STMT, stmt); >+ return ""; >+ } >+ >+ memset(buf, 0, len); >+ >+ res = SQLFetch(stmt); >+ if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { >+ if (res == SQL_NO_DATA) { >+ if (option_verbose > 3) { >+ ast_verbose(VERBOSE_PREFIX_4 "Found no rows [%s]\n", sql); >+ } >+ } else if (option_verbose > 3) { >+ ast_log(LOG_WARNING, "Error %d in FETCH [%s]\n", res, sql); >+ } >+ goto acf_out; >+ } >+ >+ for (x = 0; x < colcount; x++) { >+ int i, namelen; >+ char coldata[256], colname[256]; >+ >+ res = SQLDescribeCol(stmt, x + 1, (unsigned char *)colname, sizeof(colname), &collength, NULL, NULL, NULL, NULL); >+ if (((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) || collength == 0) { >+ snprintf(colname, sizeof(colname), "field%d", x); >+ } >+ >+ if (!ast_strlen_zero(colnames)) >+ strncat(colnames, ",", sizeof(colnames) - 1); >+ namelen = strlen(colnames); >+ >+ /* Copy data, encoding '\' and ',' for the argument parser */ >+ for (i = 0; i < sizeof(colname); i++) { >+ if (escapecommas && (colname[i] == '\\' || colname[i] == ',')) { >+ colnames[namelen++] = '\\'; >+ } >+ colnames[namelen++] = colname[i]; >+ >+ if (namelen >= sizeof(colnames) - 2) { >+ colnames[namelen >= sizeof(colnames) ? sizeof(colnames) - 1 : namelen] = '\0'; >+ break; >+ } >+ >+ if (colname[i] == '\0') >+ break; >+ } >+ >+ buflen = strlen(buf); >+ res = SQLGetData(stmt, x + 1, SQL_CHAR, coldata, sizeof(coldata), &indicator); >+ if (indicator == SQL_NULL_DATA) { >+ coldata[0] = '\0'; >+ res = SQL_SUCCESS; >+ } >+ >+ if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { >+ ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql); >+ SQLCloseCursor(stmt); >+ SQLFreeHandle(SQL_HANDLE_STMT, stmt); >+ return ""; >+ } >+ >+ /* Copy data, encoding '\' and ',' for the argument parser */ >+ for (i = 0; i < sizeof(coldata); i++) { >+ if (escapecommas && (coldata[i] == '\\' || coldata[i] == ',')) { >+ buf[buflen++] = '\\'; >+ } >+ buf[buflen++] = coldata[i]; >+ >+ if (buflen >= len - 2) { >+ buf[buflen >= len ? len - 1 : buflen] = '\0'; >+ break; >+ } >+ >+ if (coldata[i] == '\0') >+ break; >+ } >+ >+ buf[buflen - 1] = ','; >+ } >+ /* Trim trailing comma */ >+ buf[buflen - 1] = '\0'; >+ >+ pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", colnames); >+ >+acf_out: >+ SQLCloseCursor(stmt); >+ SQLFreeHandle(SQL_HANDLE_STMT, stmt); >+ return buf; >+} >+#undef INCREMENT_DSN >+ >+static char *acf_escape(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len) >+{ >+ char *in, *out = buf; >+ for (in = data; *in && out - buf < len; in++) { >+ if (*in == '\'') { >+ *out = '\''; >+ out++; >+ } >+ *out = *in; >+ out++; >+ } >+ *out = '\0'; >+ return buf; >+} >+ >+static struct ast_custom_function escape_function = { >+ .name = "SQL_ESC", >+ .synopsis = "Escapes single ticks for use in SQL statements", >+ .syntax = "SQL_ESC(<string>)", >+ .desc = >+"Used in SQL templates to escape data which may contain single ticks (') which\n" >+"are otherwise used to delimit data. For example:\n" >+"SELECT foo FROM bar WHERE baz='${SQL_ESC(${ARG1})}'\n", >+ .read = acf_escape, >+ .write = NULL, >+}; >+ >+ >+static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_query **query) >+{ >+ const char *tmp; >+ int i; >+ >+ if (!cfg || !catg) { >+ return -1; >+ } >+ >+ *query = calloc(1, sizeof(struct acf_odbc_query)); >+ if (! (*query)) >+ return ENOMEM; >+ >+ if (((tmp = ast_variable_retrieve(cfg, catg, "writehandle"))) || ((tmp = ast_variable_retrieve(cfg, catg, "dsn")))) { >+ char *tmp2 = ast_strdupa(tmp); >+ AST_DECLARE_APP_ARGS(write, >+ AST_APP_ARG(dsn)[5]; >+ ); >+ TRUNK_NONSTANDARD_APP_ARGS(write, tmp2, ','); >+ for (i = 0; i < 5; i++) { >+ if (!ast_strlen_zero(write.dsn[i])) >+ ast_copy_string((*query)->writehandle[i], write.dsn[i], sizeof((*query)->writehandle[i])); >+ } >+ } >+ >+ if ((tmp = ast_variable_retrieve(cfg, catg, "readhandle"))) { >+ char *tmp2 = ast_strdupa(tmp); >+ AST_DECLARE_APP_ARGS(read, >+ AST_APP_ARG(dsn)[5]; >+ ); >+ TRUNK_NONSTANDARD_APP_ARGS(read, tmp2, ','); >+ for (i = 0; i < 5; i++) { >+ if (!ast_strlen_zero(read.dsn[i])) >+ ast_copy_string((*query)->readhandle[i], read.dsn[i], sizeof((*query)->readhandle[i])); >+ } >+ } else { >+ /* If no separate readhandle, then use the writehandle for reading */ >+ for (i = 0; i < 5; i++) { >+ if (!ast_strlen_zero((*query)->writehandle[i])) >+ ast_copy_string((*query)->readhandle[i], (*query)->writehandle[i], sizeof((*query)->readhandle[i])); >+ } >+ } >+ >+ if ((tmp = ast_variable_retrieve(cfg, catg, "read"))) { >+ ast_log(LOG_WARNING, "Parameter 'read' is deprecated for category %s. Please use 'readsql' instead.\n", catg); >+ ast_copy_string((*query)->sql_read, tmp, sizeof((*query)->sql_read)); >+ } else if ((tmp = ast_variable_retrieve(cfg, catg, "readsql"))) >+ ast_copy_string((*query)->sql_read, tmp, sizeof((*query)->sql_read)); >+ >+ if (!ast_strlen_zero((*query)->sql_read) && ast_strlen_zero((*query)->readhandle[0])) { >+ free(*query); >+ *query = NULL; >+ ast_log(LOG_ERROR, "There is SQL, but no ODBC class to be used for reading: %s\n", catg); >+ return EINVAL; >+ } >+ >+ if ((tmp = ast_variable_retrieve(cfg, catg, "write"))) { >+ ast_log(LOG_WARNING, "Parameter 'write' is deprecated for category %s. Please use 'writesql' instead.\n", catg); >+ ast_copy_string((*query)->sql_write, tmp, sizeof((*query)->sql_write)); >+ } else if ((tmp = ast_variable_retrieve(cfg, catg, "writesql"))) >+ ast_copy_string((*query)->sql_write, tmp, sizeof((*query)->sql_write)); >+ >+ if (!ast_strlen_zero((*query)->sql_write) && ast_strlen_zero((*query)->writehandle[0])) { >+ free(*query); >+ *query = NULL; >+ ast_log(LOG_ERROR, "There is SQL, but no ODBC class to be used for writing: %s\n", catg); >+ return EINVAL; >+ } >+ >+ /* Allow escaping of embedded commas in fields to be turned off */ >+ ast_set_flag((*query), OPT_ESCAPECOMMAS); >+ if ((tmp = ast_variable_retrieve(cfg, catg, "escapecommas"))) { >+ if (ast_false(tmp)) >+ ast_clear_flag((*query), OPT_ESCAPECOMMAS); >+ } >+ >+ (*query)->acf = calloc(1, sizeof(struct ast_custom_function)); >+ if (! (*query)->acf) { >+ free(*query); >+ *query = NULL; >+ return ENOMEM; >+ } >+ >+ if ((tmp = ast_variable_retrieve(cfg, catg, "prefix")) && !ast_strlen_zero(tmp)) { >+ asprintf((char **)&((*query)->acf->name), "%s_%s", tmp, catg); >+ } else { >+ asprintf((char **)&((*query)->acf->name), "ODBC_%s", catg); >+ } >+ >+ if (!((*query)->acf->name)) { >+ free((*query)->acf); >+ free(*query); >+ *query = NULL; >+ return ENOMEM; >+ } >+ >+ asprintf((char **)&((*query)->acf->syntax), "%s(<arg1>[...[,<argN>]])", (*query)->acf->name); >+ >+ if (!((*query)->acf->syntax)) { >+ free((char *)(*query)->acf->name); >+ free((*query)->acf); >+ free(*query); >+ *query = NULL; >+ return ENOMEM; >+ } >+ >+ (*query)->acf->synopsis = "Runs the referenced query with the specified arguments"; >+ if (!ast_strlen_zero((*query)->sql_read) && !ast_strlen_zero((*query)->sql_write)) { >+ asprintf((char **)&((*query)->acf->desc), >+ "Runs the following query, as defined in func_odbc.conf, performing\n" >+ "substitution of the arguments into the query as specified by ${ARG1},\n" >+ "${ARG2}, ... ${ARGn}. When setting the function, the values are provided\n" >+ "either in whole as ${VALUE} or parsed as ${VAL1}, ${VAL2}, ... ${VALn}.\n" >+ "\nRead:\n%s\n\nWrite:\n%s\n", >+ (*query)->sql_read, >+ (*query)->sql_write); >+ } else if (!ast_strlen_zero((*query)->sql_read)) { >+ asprintf((char **)&((*query)->acf->desc), >+ "Runs the following query, as defined in func_odbc.conf, performing\n" >+ "substitution of the arguments into the query as specified by ${ARG1},\n" >+ "${ARG2}, ... ${ARGn}. This function may only be read, not set.\n\nSQL:\n%s\n", >+ (*query)->sql_read); >+ } else if (!ast_strlen_zero((*query)->sql_write)) { >+ asprintf((char **)&((*query)->acf->desc), >+ "Runs the following query, as defined in func_odbc.conf, performing\n" >+ "substitution of the arguments into the query as specified by ${ARG1},\n" >+ "${ARG2}, ... ${ARGn}. The values are provided either in whole as\n" >+ "${VALUE} or parsed as ${VAL1}, ${VAL2}, ... ${VALn}.\n" >+ "This function may only be set.\nSQL:\n%s\n", >+ (*query)->sql_write); >+ } else { >+ free((char *)(*query)->acf->syntax); >+ free((char *)(*query)->acf->name); >+ free((*query)->acf); >+ free(*query); >+ *query = NULL; >+ ast_log(LOG_WARNING, "Section %s was found, but there was no SQL to execute. Ignoring.\n", catg); >+ return EINVAL; >+ } >+ >+ /* Could be out of memory, or could be we have neither sql_read nor sql_write */ >+ if (! ((*query)->acf->desc)) { >+ free((char *)(*query)->acf->syntax); >+ free((char *)(*query)->acf->name); >+ free((*query)->acf); >+ free(*query); >+ *query = NULL; >+ return ENOMEM; >+ } >+ >+ if (ast_strlen_zero((*query)->sql_read)) { >+ (*query)->acf->read = NULL; >+ } else { >+ (*query)->acf->read = acf_odbc_read; >+ } >+ >+ if (ast_strlen_zero((*query)->sql_write)) { >+ (*query)->acf->write = NULL; >+ } else { >+ (*query)->acf->write = acf_odbc_write; >+ } >+ >+ return 0; >+} >+ >+static int free_acf_query(struct acf_odbc_query *query) >+{ >+ if (query) { >+ if (query->acf) { >+ if (query->acf->name) >+ free(query->acf->name); >+ if (query->acf->syntax) >+ free(query->acf->syntax); >+ if (query->acf->desc) >+ free(query->acf->desc); >+ free(query->acf); >+ } >+ free(query); >+ } >+ return 0; >+} >+ >+static int odbc_load_module(void) >+{ >+ int res = 0; >+ struct ast_config *cfg; >+ char *catg; >+ >+ AST_LIST_LOCK(&queries); >+ >+ cfg = ast_config_load(config); >+ if (!cfg) { >+ ast_log(LOG_WARNING, "Unable to load config for func_odbc: %s\n", config); >+ AST_LIST_UNLOCK(&queries); >+ return -1; >+ } >+ >+ for (catg = ast_category_browse(cfg, NULL); >+ catg; >+ catg = ast_category_browse(cfg, catg)) { >+ struct acf_odbc_query *query = NULL; >+ int err; >+ >+ if ((err = init_acf_query(cfg, catg, &query))) { >+ if (err == ENOMEM) >+ ast_log(LOG_ERROR, "Out of memory\n"); >+ else if (err == EINVAL) >+ ast_log(LOG_ERROR, "Invalid parameters for category %s\n", catg); >+ else >+ ast_log(LOG_ERROR, "%s (%d)\n", strerror(err), err); >+ } else { >+ AST_LIST_INSERT_HEAD(&queries, query, list); >+ ast_custom_function_register(query->acf); >+ } >+ } >+ >+ ast_config_destroy(cfg); >+ ast_custom_function_register(&escape_function); >+ >+ AST_LIST_UNLOCK(&queries); >+ return res; >+} >+ >+static int odbc_unload_module(void) >+{ >+ struct acf_odbc_query *query; >+ >+ AST_LIST_LOCK(&queries); >+ while (!AST_LIST_EMPTY(&queries)) { >+ query = AST_LIST_REMOVE_HEAD(&queries, list); >+ ast_custom_function_unregister(query->acf); >+ free_acf_query(query); >+ } >+ >+ ast_custom_function_unregister(&escape_function); >+ >+ /* Allow any threads waiting for this lock to pass (avoids a race) */ >+ AST_LIST_UNLOCK(&queries); >+ AST_LIST_LOCK(&queries); >+ >+ AST_LIST_UNLOCK(&queries); >+ return 0; >+} >+ >+int reload(void) >+{ >+ int res = 0; >+ struct ast_config *cfg; >+ struct acf_odbc_query *oldquery; >+ char *catg; >+ >+ AST_LIST_LOCK(&queries); >+ >+ while (!AST_LIST_EMPTY(&queries)) { >+ oldquery = AST_LIST_REMOVE_HEAD(&queries, list); >+ ast_custom_function_unregister(oldquery->acf); >+ free_acf_query(oldquery); >+ } >+ >+ cfg = ast_config_load(config); >+ if (!cfg) { >+ ast_log(LOG_WARNING, "Unable to load config for func_odbc: %s\n", config); >+ goto reload_out; >+ } >+ >+ for (catg = ast_category_browse(cfg, NULL); >+ catg; >+ catg = ast_category_browse(cfg, catg)) { >+ struct acf_odbc_query *query = NULL; >+ >+ if (init_acf_query(cfg, catg, &query)) { >+ ast_log(LOG_ERROR, "Cannot initialize query %s\n", catg); >+ } else { >+ AST_LIST_INSERT_HEAD(&queries, query, list); >+ ast_custom_function_register(query->acf); >+ } >+ } >+ >+ ast_config_destroy(cfg); >+reload_out: >+ AST_LIST_UNLOCK(&queries); >+ return res; >+} >+ >+int unload_module(void) >+{ >+ return odbc_unload_module(); >+} >+ >+int load_module(void) >+{ >+ return odbc_load_module(); >+} >+ >+char *description(void) >+{ >+ return tdesc; >+} >+ >+int usecount(void) >+{ >+ if (! ast_mutex_trylock(&(&queries)->lock)) { >+ ast_mutex_unlock(&(&queries)->lock); >+ return 0; >+ } else { >+ return 1; >+ } >+} >+ >+char *key() >+{ >+ return ASTERISK_GPL_KEY; >+} >diff -ruN asterisk-ori/files/1.2.0/backports/func_odbc/func_odbc.conf.sample asterisk/files/1.2.0/backports/func_odbc/func_odbc.conf.sample >--- asterisk-ori/files/1.2.0/backports/func_odbc/func_odbc.conf.sample 1970-01-01 01:00:00.000000000 +0100 >+++ asterisk/files/1.2.0/backports/func_odbc/func_odbc.conf.sample 2008-03-03 19:18:45.000000000 +0100 >@@ -0,0 +1,43 @@ >+; >+; func_odbc.conf >+; >+; Each context is a separately defined function. By convention, all >+; functions are entirely uppercase, so the defined contexts should also >+; be all-uppercase, but there is nothing that enforces this. All functions >+; are case-sensitive, however. >+; >+; For substitution, you have ${ARG1}, ${ARG2} ... ${ARGn} >+; for the arguments to each SQL statement. >+; >+; In addition, for write statements, you have ${VAL1}, ${VAL2} ... ${VALn} >+; parsed, just like arguments, for the values. In addition, if you want the >+; whole value, never mind the parsing, you can get that with ${VALUE}. >+; >+; >+; If you have data which may potentially contain single ticks, you may wish >+; to use the dialplan function SQL_ESC() to escape the data prior to its >+; inclusion in the SQL statement. >+ >+ >+; ODBC_SQL - Allow an SQL statement to be built entirely in the dialplan >+[SQL] >+readhandle=mysql1 >+readsql=${ARG1} >+ >+; ODBC_ANTIGF - A blacklist. >+[ANTIGF] >+readhandle=mysql1 >+readsql=SELECT COUNT(*) FROM exgirlfriends WHERE callerid='${SQL_ESC(${ARG1})}' >+ >+; ODBC_PRESENCE - Retrieve and update presence >+[PRESENCE] >+readhandle=mysql1 >+writehandle=mysql1 >+readsql=SELECT location FROM presence WHERE id='${SQL_ESC(${ARG1})}' >+writesql=UPDATE presence SET location='${SQL_ESC(${VAL1})}' WHERE id='${SQL_ESC(${ARG1})}' >+; >+;prefix=OFFICE ; Changes this function from ODBC_PRESENCE to OFFICE_PRESENCE >+;escapecommas=no ; Normally, commas within a field are escaped such that each >+ ; field may be separated into individual variables with ARRAY or HASH. >+ ; This option turns that behavior off [default=yes]. >+ >diff -ruN asterisk-ori/files/1.2.0/backports/func_odbc/separate.h asterisk/files/1.2.0/backports/func_odbc/separate.h >--- asterisk-ori/files/1.2.0/backports/func_odbc/separate.h 1970-01-01 01:00:00.000000000 +0100 >+++ asterisk/files/1.2.0/backports/func_odbc/separate.h 2008-03-03 19:19:17.000000000 +0100 >@@ -0,0 +1,47 @@ >+#define TRUNK_STANDARD_APP_ARGS(args, parse) \ >+ args.argc = trunk_app_separate_args(parse, '|', args.argv, (sizeof(args) - sizeof(args.argc)) / sizeof(args.argv[0])) >+#define TRUNK_NONSTANDARD_APP_ARGS(args, parse, sep) \ >+ args.argc = trunk_app_separate_args(parse, sep, args.argv, (sizeof(args) - sizeof(args.argc)) / sizeof(args.argv[0])) >+ >+static unsigned int trunk_app_separate_args(char *buf, char delim, char **array, int arraylen) >+{ >+ int argc; >+ char *scan; >+ int paren = 0, quote = 0; >+ >+ if (!buf || !array || !arraylen) >+ return 0; >+ >+ memset(array, 0, arraylen * sizeof(*array)); >+ >+ scan = buf; >+ >+ for (argc = 0; *scan && (argc < arraylen - 1); argc++) { >+ array[argc] = scan; >+ for (; *scan; scan++) { >+ if (*scan == '(') >+ paren++; >+ else if (*scan == ')') { >+ if (paren) >+ paren--; >+ } else if (*scan == '"') { >+ quote = quote ? 0 : 1; >+ /* Remove quote character from argument */ >+ memmove(scan, scan + 1, strlen(scan)); >+ scan--; >+ } else if (*scan == '\\') { >+ /* Literal character, don't parse */ >+ memmove(scan, scan + 1, strlen(scan)); >+ } else if ((*scan == delim) && !paren && !quote) { >+ *scan++ = '\0'; >+ break; >+ } >+ } >+ } >+ >+ if (*scan) >+ array[argc++] = scan; >+ >+ return argc; >+} >+
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 212306
:
145296
|
145298
|
145299
|
146339
|
146341
|
146557
|
146558
|
146559
|
146645
|
146646