From 97834718c283d74e3571c1bf52d2840b93157cda Mon Sep 17 00:00:00 2001 From: Matthew Jordan Date: Fri, 4 Jul 2014 13:26:37 +0000 Subject: [PATCH] Remove many deprecated modules Billing records are fair, To get paid is quite bright, You should really use ODBC; Good-bye cdr_sqlite. Microsoft did once push H.323, Hell, we all remember NetMeeting. But try to compile chan_h323 now And you will take quite a beating. The XMPP and SIP war was fierce, And in the distant fray Was birthed res_jabber/chan_jingle; But neither to stay. For everyone did care and chase what Google professed. "Free Internet Calling" was what devotees cried, But Google did change the specs so often That the developers were happy the day chan_gtalk died. And then there was that odd application Dedicated to the Polish tongue. app_saycountpl was subsumed by Say; One could say its bell was rung. To read and parse a file from the dialplan You could (I guess) use an application. app_readfile did fill that purpose, but I think A function is perhaps better in its creation. Barging is rude, I'm not sure why we do it. Inwardly, the caller will probably sigh. But if you really must do it, Don't use app_dahdibarge, use ChanSpy. We all despise the sound of tinny robots It makes our queues so cold. To control such an abomination It's better to not use Wait/SetMusicOnHold. It's often nice to know properties of a channel It makes our calls right We have a nice function called CHANNEL And so SIPCHANINFO is sent off into the night. And now things get odd; Apparently one could delimit with a colon Properties from the SIPPEER function! Commas are in; all others are done. Finally, a word on pipes and commas. We're sorry. We can't say it enough. But those compatibility options in asterisk.conf; To maintain them forever was just too tough. This patch removes: * cdr_sqlite * chan_gtalk * chan_jingle * chan_h323 * res_jabber * app_saycountpl * app_readfile * app_dahdibarge It removes the following applications/functions: * WaitMusicOnHold * SetMusicOnHold * SIPCHANINFO It removes the colon delimiter from the SIPPEER function. Finally, it also removes all compatibility options that were configurable from asterisk.conf, as these all applied to compatibility with Asterisk 1.4 systems. Review: https://reviewboard.asterisk.org/r/3698/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@418019 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- CHANGES | 54 + UPGRADE.txt | 43 +- addons/Makefile | 1 - addons/app_saycountpl.c | 138 - apps/app_dahdibarge.c | 311 --- apps/app_readfile.c | 134 - channels/Makefile | 62 - channels/chan_gtalk.c | 2447 ---------------- channels/chan_h323.c | 3532 ----------------------- channels/chan_jingle.c | 2090 -------------- channels/chan_sip.c | 119 +- channels/h323/ChangeLog | 43 - channels/h323/INSTALL.openh323 | 18 - channels/h323/Makefile.in | 53 - channels/h323/README | 144 - channels/h323/TODO | 9 - channels/h323/ast_h323.cxx | 2678 ------------------ channels/h323/ast_h323.h | 187 -- channels/h323/ast_ptlib.h | 34 - channels/h323/caps_h323.cxx | 383 --- channels/h323/caps_h323.h | 172 -- channels/h323/chan_h323.h | 276 -- channels/h323/cisco-h225.asn | 74 - channels/h323/cisco-h225.cxx | 853 ------ channels/h323/cisco-h225.h | 300 -- channels/h323/compat_h323.cxx | 139 - channels/h323/compat_h323.h | 96 - channels/h323/noexport.map | 5 - configs/asterisk.conf.sample | 5 - configs/gtalk.conf.sample | 27 - configs/jabber.conf.sample | 39 - configs/jingle.conf.sample | 20 - include/asterisk/options.h | 12 - main/asterisk.c | 16 +- main/pbx.c | 4 - pbx/pbx_realtime.c | 32 +- res/ael/pval.c | 43 +- res/res_agi.c | 19 +- res/res_jabber.c | 4815 -------------------------------- res/res_musiconhold.c | 78 - utils/ael_main.c | 2 - utils/conf2ael.c | 1 - 42 files changed, 113 insertions(+), 19395 deletions(-) delete mode 100644 addons/app_saycountpl.c delete mode 100644 apps/app_dahdibarge.c delete mode 100644 apps/app_readfile.c delete mode 100644 channels/chan_gtalk.c delete mode 100644 channels/chan_h323.c delete mode 100644 channels/chan_jingle.c delete mode 100644 channels/h323/ChangeLog delete mode 100644 channels/h323/INSTALL.openh323 delete mode 100644 channels/h323/Makefile.in delete mode 100644 channels/h323/README delete mode 100644 channels/h323/TODO delete mode 100644 channels/h323/ast_h323.cxx delete mode 100644 channels/h323/ast_h323.h delete mode 100644 channels/h323/ast_ptlib.h delete mode 100644 channels/h323/caps_h323.cxx delete mode 100644 channels/h323/caps_h323.h delete mode 100644 channels/h323/chan_h323.h delete mode 100644 channels/h323/cisco-h225.asn delete mode 100644 channels/h323/cisco-h225.cxx delete mode 100644 channels/h323/cisco-h225.h delete mode 100644 channels/h323/compat_h323.cxx delete mode 100644 channels/h323/compat_h323.h delete mode 100644 channels/h323/noexport.map delete mode 100644 configs/gtalk.conf.sample delete mode 100644 configs/jabber.conf.sample delete mode 100644 configs/jingle.conf.sample delete mode 100644 res/res_jabber.c diff --git a/CHANGES b/CHANGES index e61cf52a74a..a6d3a6b9895 100644 --- a/CHANGES +++ b/CHANGES @@ -12,6 +12,21 @@ --- Functionality changes from Asterisk 12 to Asterisk 13 -------------------- ------------------------------------------------------------------------------ +app_dahdibarge +------------------ + * This module was deprecated and has been removed. Users of app_dahdibarge + should use ChanSpy instead. + +app_readfile +------------------ + * This module was deprecated and has been removed. Users of app_readfile + should use func_env's FILE function instead. + +app_saycountpl +------------------ + * This module was deprecated and has been removed. Users of app_saycountpl + should use the Say family of applications. + AMI ------------------ * New DeviceStateChanged and PresenceStateChanged AMI events have been added. @@ -30,6 +45,11 @@ AMI * New AMI actions PRIDebugSet, PRIDebugFileSet, and PRIDebugFileUnset enable manager control over PRI debugging levels and file output. +cdr_sqlite +----------------- + * This module was deprecated and has been removed. Users of cdr_sqlite + should use cdr_sqlite3_custom. + CEL ------------------ * The "bridge_technology" extra field key has been added to BRIDGE_ENTER @@ -47,6 +67,30 @@ chan_dahdi * Added several SS7 config option parameters described in chan_dahdi.conf.sample. +chan_gtalk +------------------ + * This module was deprecated and has been removed. Users of chan_gtalk + should use chan_motif. + +chan_h323 +------------------ + * This module was deprecated and has been removed. Users of chan_h323 + should use chan_ooh323. + +chan_jingle +------------------ + * This module was deprecated and has been removed. Users of chan_jingle + should use chan_motif. + +chan_sip +------------------ + * The SIPPEER dialplan function no longer supports using a colon as a + delimiter for parameters. The parameters for the function should be + delimited using a comma. + + * The SIPCHANINFO dialplan function was deprecated and has been removed. Users + of the function should use the CHANNEL function instead. + Core ------------------ * The TLS core in Asterisk now supports Perfect Forward Secrecy (PFS). @@ -80,6 +124,16 @@ JACK_HOOK * The JACK_HOOK function now supports audio with a sample rate higher than 8kHz. +MusicOnHold +------------------ + * The SetMusicOnHold dialplan application was deprecated and has been removed. + Users of the application should use the CHANNEL function's musicclass + setting instead. + + * The WaitMusicOnHold dialplan application was deprecated and has been + removed. Users of the application should use MusicOnHold with a duration + parameter instead. + Say ------------------ * The 'say' family of dialplan applications now support the Japanese diff --git a/UPGRADE.txt b/UPGRADE.txt index 1076cc380ab..fc63210cb0c 100644 --- a/UPGRADE.txt +++ b/UPGRADE.txt @@ -43,6 +43,13 @@ From 12 to 13: directly. This change also includes a new script, refcounter.py, in the contrib folder that will process the refs log file. + - The asterisk compatibility options in asterisk.conf have been removed. + These options enabled certain backwards compatibility features for + pbx_realtime, res_agi, and app_set that made their behaviour similar to + Asterisk 1.4. Users who used these backwards compatibility settings should + update their dialplans to use ',' instead of '|' as a delimiter, and should + use the Set dialplan application instead of the MSet dialplan application. + ARI: - The ARI version has been changed from 1.0.0 to 1.1.0. This is to reflect the backwards compatible changes listed below. @@ -117,6 +124,9 @@ CDRs: handler subroutine). In general, this is not the preferred default: this causes extra CDRs to be generated for a channel in many common dialplans. + - The cdr_sqlite module was deprecated and has been removed. Users of this + module should use the cdr_sqlite3_custom module instead. + chan_dahdi: - SS7 support now requires libss7 v2.0 or later. @@ -125,6 +135,18 @@ chan_dahdi: SETUP ACKNOWLEDGE message. Default is now no. +chan_gtalk + - This module was deprecated and has been removed. Users of chan_gtalk + should use chan_motif. + +chan_h323 + - This module was deprecated and has been removed. Users of chan_h323 + should use chan_ooh323. + +chan_jingle + - This module was deprecated and has been removed. Users of chan_jingle + should use chan_motif. + chan_pjsip: - Added a 'force_avp' option to chan_pjsip which will force the usage of 'RTP/AVP', 'RTP/AVPF', 'RTP/SAVP', or 'RTP/SAVPF' as the media transport type @@ -139,6 +161,13 @@ chan_sip: - Made set SIPREFERREDBYHDR as inheritable for better chan_pjsip interoperability. + - The SIPPEER dialplan function no longer supports using a colon as a + delimiter for parameters. The parameters for the function should be + delimited using a comma. + + - The SIPCHANINFO dialplan function was deprecated and has been removed. Users + of the function should use the CHANNEL function instead. + - Added a 'force_avp' option for chan_sip. When enabled this option will cause the media transport in the offer or answer SDP to be 'RTP/AVP', 'RTP/AVPF', 'RTP/SAVP', or 'RTP/SAVPF' even if a DTLS stream has been @@ -195,6 +224,15 @@ HTTP: keep alive time between HTTP requests is configured in http.conf with the session_keep_alive parameter. +MusicOnHold + - The SetMusicOnHold dialplan application was deprecated and has been removed. + Users of the application should use the CHANNEL function's musicclass + setting instead. + + - The WaitMusicOnHold dialplan application was deprecated and has been + removed. Users of the application should use MusicOnHold with a duration + parameter instead. + ODBC: - The compatibility setting, allow_empty_string_in_nontext, has been removed. Empty column values will be stored as empty strings during realtime updates. @@ -241,6 +279,10 @@ Realtime Configuration: - A new set of Alembic scripts has been added for CDR tables. This will create a 'cdr' table with the default schema that Asterisk expects. +res_jabber: + - This module was deprecated and has been removed. Users of this module should + use res_xmpp instead. + safe_asterisk: - The safe_asterisk script was previously not installed on top of an existing version. This caused bug-fixes in that script not to be deployed. If your @@ -270,6 +312,5 @@ WebSockets: In such cases, it may be necessary to adjust this value. Default is 100 ms. - =========================================================== =========================================================== diff --git a/addons/Makefile b/addons/Makefile index e1ff95f6499..96438f5d0e0 100644 --- a/addons/Makefile +++ b/addons/Makefile @@ -27,7 +27,6 @@ H323OBJS:=ooCmdChannel.o ooLogChan.o ooUtils.o ooGkClient.o context.o \ H323CFLAGS:=-Iooh323c/src -Iooh323c/src/h323 ALL_C_MODS:=app_mysql \ - app_saycountpl \ cdr_mysql \ chan_mobile \ chan_ooh323 \ diff --git a/addons/app_saycountpl.c b/addons/app_saycountpl.c deleted file mode 100644 index dce519d9416..00000000000 --- a/addons/app_saycountpl.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 2004, Andy Powell & TAAN Softworks Corp. - * - * 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 Say Polish counting words - * \author Andy Powell - */ - -/*** MODULEINFO - no - deprecated - say.conf - ***/ - -#include "asterisk.h" - -ASTERISK_FILE_VERSION(__FILE__, "$Revision$") - -#include "asterisk/file.h" -#include "asterisk/logger.h" -#include "asterisk/channel.h" -#include "asterisk/pbx.h" -#include "asterisk/module.h" -#include "asterisk/lock.h" -#include "asterisk/app.h" - -/*** DOCUMENTATION - - - Say Polish counting words. - - - - - - - - - Polish grammar has some funny rules for counting words. for example 1 zloty, - 2 zlote, 5 zlotych. This application will take the words for 1, 2-4 and 5 and - decide based on grammar rules which one to use with the number you pass to it. - Example: SayCountPL(zloty,zlote,zlotych,122) will give: zlote - - - - ***/ -static const char app[] = "SayCountPL"; - -static int saywords(struct ast_channel *chan, char *word1, char *word2, char *word5, int num) -{ - /* Put this in a separate proc because it's bound to change */ - int d = 0; - - if (num > 0) { - if (num % 1000 == 1) { - ast_streamfile(chan, word1, ast_channel_language(chan)); - d = ast_waitstream(chan,""); - } else if (((num % 10) >= 2) && ((num % 10) <= 4 ) && ((num % 100) < 10 || (num % 100) > 20)) { - ast_streamfile(chan, word2, ast_channel_language(chan)); - d = ast_waitstream(chan, ""); - } else { - ast_streamfile(chan, word5, ast_channel_language(chan)); - d = ast_waitstream(chan, ""); - } - } - - return d; -} - - -static int sayword_exec(struct ast_channel *chan, const char *data) -{ - int res = 0; - char *s; - int inum; - AST_DECLARE_APP_ARGS(args, - AST_APP_ARG(word1); - AST_APP_ARG(word2); - AST_APP_ARG(word5); - AST_APP_ARG(num); - ); - - if (!data) { - ast_log(LOG_WARNING, "SayCountPL requires 4 arguments: word-1,word-2,word-5,number\n"); - return -1; - } - - s = ast_strdupa(data); - - AST_STANDARD_APP_ARGS(args, s); - - /* Check to see if params passed */ - if (!args.word1 || !args.word2 || !args.word5 || !args.num) { - ast_log(LOG_WARNING, "SayCountPL requires 4 arguments: word-1,word-2,word-3,number\n"); - return -1; - } - - if (sscanf(args.num, "%30d", &inum) != 1) { - ast_log(LOG_WARNING, "'%s' is not a valid number\n", args.num); - return -1; - } - - /* do the saying part (after a bit of maths) */ - - res = saywords(chan, args.word1, args.word2, args.word5, inum); - - return res; -} - -static int unload_module(void) -{ - return ast_unregister_application(app); -} - -static int load_module(void) -{ - int res; - - res = ast_register_application_xml(app, sayword_exec); - - return res ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS; -} - -AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Say polish counting words"); diff --git a/apps/app_dahdibarge.c b/apps/app_dahdibarge.c deleted file mode 100644 index cc05a63f8d2..00000000000 --- a/apps/app_dahdibarge.c +++ /dev/null @@ -1,311 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 1999 - 2005, Digium, Inc. - * - * Mark Spencer - * - * Special thanks to comphealth.com for sponsoring this - * GPL application. - * - * 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 DAHDI Barge support - * - * \author Mark Spencer - * - * \note Special thanks to comphealth.com for sponsoring this - * GPL application. - * - * \ingroup applications - */ - -/*** MODULEINFO - dahdi - no - deprecated - app_chanspy - ***/ - -#include "asterisk.h" - -ASTERISK_FILE_VERSION(__FILE__, "$Revision$") - -#include - -#include "asterisk/lock.h" -#include "asterisk/file.h" -#include "asterisk/channel.h" -#include "asterisk/pbx.h" -#include "asterisk/module.h" -#include "asterisk/config.h" -#include "asterisk/app.h" -#include "asterisk/cli.h" -#include "asterisk/say.h" -#include "asterisk/utils.h" - -/*** DOCUMENTATION - - - Barge in (monitor) DAHDI channel. - - - - Channel to barge. - - - - Barges in on a specified DAHDI channel or prompts - if one is not specified. Returns -1 when caller user hangs - up and is independent of the state of the channel being monitored. - - - - ***/ -static const char app[] = "DAHDIBarge"; - -#define CONF_SIZE 160 - -static int careful_write(int fd, unsigned char *data, int len) -{ - int res; - while(len) { - res = write(fd, data, len); - if (res < 1) { - if (errno != EAGAIN) { - ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno)); - return -1; - } else - return 0; - } - len -= res; - data += res; - } - return 0; -} - -static int conf_run(struct ast_channel *chan, int confno, int confflags) -{ - int fd; - struct dahdi_confinfo dahdic; - struct ast_frame *f; - struct ast_channel *c; - struct ast_frame fr; - int outfd; - int ms; - int nfds; - int res; - int flags; - int retrydahdi; - int origfd; - int ret = -1; - - struct dahdi_bufferinfo bi; - char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET]; - char *buf = __buf + AST_FRIENDLY_OFFSET; - - /* Set it into U-law mode (write) */ - if (ast_set_write_format_by_id(chan, AST_FORMAT_ULAW) < 0) { - ast_log(LOG_WARNING, "Unable to set '%s' to write ulaw mode\n", ast_channel_name(chan)); - goto outrun; - } - - /* Set it into U-law mode (read) */ - if (ast_set_read_format_by_id(chan, AST_FORMAT_ULAW) < 0) { - ast_log(LOG_WARNING, "Unable to set '%s' to read ulaw mode\n", ast_channel_name(chan)); - goto outrun; - } - ast_indicate(chan, -1); - retrydahdi = strcasecmp(ast_channel_tech(chan)->type, "DAHDI"); -dahdiretry: - origfd = ast_channel_fd(chan, 0); - if (retrydahdi) { - fd = open("/dev/dahdi/pseudo", O_RDWR); - if (fd < 0) { - ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno)); - goto outrun; - } - /* Make non-blocking */ - flags = fcntl(fd, F_GETFL); - if (flags < 0) { - ast_log(LOG_WARNING, "Unable to get flags: %s\n", strerror(errno)); - close(fd); - goto outrun; - } - if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) { - ast_log(LOG_WARNING, "Unable to set flags: %s\n", strerror(errno)); - close(fd); - goto outrun; - } - /* Setup buffering information */ - memset(&bi, 0, sizeof(bi)); - bi.bufsize = CONF_SIZE; - bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE; - bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE; - bi.numbufs = 4; - if (ioctl(fd, DAHDI_SET_BUFINFO, &bi)) { - ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno)); - close(fd); - goto outrun; - } - nfds = 1; - } else { - /* XXX Make sure we're not running on a pseudo channel XXX */ - fd = ast_channel_fd(chan, 0); - nfds = 0; - } - memset(&dahdic, 0, sizeof(dahdic)); - /* Check to see if we're in a conference... */ - dahdic.chan = 0; - if (ioctl(fd, DAHDI_GETCONF, &dahdic)) { - ast_log(LOG_WARNING, "Error getting conference\n"); - close(fd); - goto outrun; - } - if (dahdic.confmode) { - /* Whoa, already in a conference... Retry... */ - if (!retrydahdi) { - ast_debug(1, "DAHDI channel is in a conference already, retrying with pseudo\n"); - retrydahdi = 1; - goto dahdiretry; - } - } - memset(&dahdic, 0, sizeof(dahdic)); - /* Add us to the conference */ - dahdic.chan = 0; - dahdic.confno = confno; - dahdic.confmode = DAHDI_CONF_MONITORBOTH; - - if (ioctl(fd, DAHDI_SETCONF, &dahdic)) { - ast_log(LOG_WARNING, "Error setting conference\n"); - close(fd); - goto outrun; - } - ast_debug(1, "Placed channel %s in DAHDI channel %d monitor\n", ast_channel_name(chan), confno); - - for(;;) { - outfd = -1; - ms = -1; - c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms); - if (c) { - if (ast_channel_fd(c, 0) != origfd) { - if (retrydahdi) { - /* Kill old pseudo */ - close(fd); - } - ast_debug(1, "Ooh, something swapped out under us, starting over\n"); - retrydahdi = 0; - goto dahdiretry; - } - f = ast_read(c); - if (!f) - break; - if ((f->frametype == AST_FRAME_DTMF) && (f->subclass.integer == '#')) { - ret = 0; - ast_frfree(f); - break; - } else if (fd != ast_channel_fd(chan, 0)) { - if (f->frametype == AST_FRAME_VOICE) { - if (f->subclass.format.id == AST_FORMAT_ULAW) { - /* Carefully write */ - careful_write(fd, f->data.ptr, f->datalen); - } else - ast_log(LOG_WARNING, "Huh? Got a non-ulaw (%s) frame in the conference\n", ast_getformatname(&f->subclass.format)); - } - } - ast_frfree(f); - } else if (outfd > -1) { - res = read(outfd, buf, CONF_SIZE); - if (res > 0) { - memset(&fr, 0, sizeof(fr)); - fr.frametype = AST_FRAME_VOICE; - ast_format_set(&fr.subclass.format, AST_FORMAT_ULAW, 0); - fr.datalen = res; - fr.samples = res; - fr.data.ptr = buf; - fr.offset = AST_FRIENDLY_OFFSET; - if (ast_write(chan, &fr) < 0) { - ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno)); - /* break; */ - } - } else - ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno)); - } - } - if (fd != ast_channel_fd(chan, 0)) - close(fd); - else { - /* Take out of conference */ - /* Add us to the conference */ - dahdic.chan = 0; - dahdic.confno = 0; - dahdic.confmode = 0; - if (ioctl(fd, DAHDI_SETCONF, &dahdic)) { - ast_log(LOG_WARNING, "Error setting conference\n"); - } - } - -outrun: - - return ret; -} - -static int conf_exec(struct ast_channel *chan, const char *data) -{ - int res = -1; - int retrycnt = 0; - int confflags = 0; - int confno = 0; - char confnostr[80] = ""; - - if (!ast_strlen_zero(data)) { - if ((sscanf(data, "DAHDI/%30d", &confno) != 1) && - (sscanf(data, "%30d", &confno) != 1)) { - ast_log(LOG_WARNING, "DAHDIBarge Argument (if specified) must be a channel number, not '%s'\n", (char *)data); - return 0; - } - } - - if (ast_channel_state(chan) != AST_STATE_UP) - ast_answer(chan); - - while(!confno && (++retrycnt < 4)) { - /* Prompt user for conference number */ - confnostr[0] = '\0'; - res = ast_app_getdata(chan, "conf-getchannel",confnostr, sizeof(confnostr) - 1, 0); - if (res <0) goto out; - if (sscanf(confnostr, "%30d", &confno) != 1) - confno = 0; - } - if (confno) { - /* XXX Should prompt user for pin if pin is required XXX */ - /* Run the conference */ - res = conf_run(chan, confno, confflags); - } -out: - /* Do the conference */ - return res; -} - -static int unload_module(void) -{ - return ast_unregister_application(app); -} - -static int load_module(void) -{ - return ((ast_register_application_xml(app, conf_exec)) ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_SUCCESS); -} - -AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Barge in on DAHDI channel application"); diff --git a/apps/app_readfile.c b/apps/app_readfile.c deleted file mode 100644 index d031406c205..00000000000 --- a/apps/app_readfile.c +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 1999 - 2005, Digium, Inc. - * - * Matt O'Gorman - * - * 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 ReadFile application -- Reads in a File for you. - * - * \author Matt O'Gorman - * - * \ingroup applications - */ - -/*** MODULEINFO - no - deprecated - func_env (FILE()) - ***/ - -#include "asterisk.h" - -ASTERISK_FILE_VERSION(__FILE__, "$Revision$") - -#include "asterisk/file.h" -#include "asterisk/channel.h" -#include "asterisk/pbx.h" -#include "asterisk/app.h" -#include "asterisk/module.h" - -/*** DOCUMENTATION - - - Read the contents of a text file into a channel variable. - - - - Result stored here. - - - - The name of the file to read. - - - Maximum number of characters to capture. - If not specified defaults to max. - - - - - Read the contents of a text file into channel variable varname - ReadFile has been deprecated in favor of Set(varname=${FILE(file,0,length)}) - - - System - Read - - - ***/ - -static char *app_readfile = "ReadFile"; - -static int readfile_exec(struct ast_channel *chan, const char *data) -{ - int res=0; - char *s, *varname=NULL, *file=NULL, *length=NULL, *returnvar=NULL; - int len=0; - static int deprecation_warning = 0; - - if (ast_strlen_zero(data)) { - ast_log(LOG_WARNING, "ReadFile require an argument!\n"); - return -1; - } - - s = ast_strdupa(data); - - varname = strsep(&s, "="); - file = strsep(&s, ","); - length = s; - - if (deprecation_warning++ % 10 == 0) - ast_log(LOG_WARNING, "ReadFile has been deprecated in favor of Set(%s=${FILE(%s,0,%s)})\n", varname, file, length); - - if (!varname || !file) { - ast_log(LOG_ERROR, "No file or variable specified!\n"); - return -1; - } - - if (length) { - if ((sscanf(length, "%30d", &len) != 1) || (len < 0)) { - ast_log(LOG_WARNING, "%s is not a positive number, defaulting length to max\n", length); - len = 0; - } - } - - if ((returnvar = ast_read_textfile(file))) { - if (len > 0) { - if (len < strlen(returnvar)) - returnvar[len]='\0'; - else - ast_log(LOG_WARNING, "%s is longer than %d, and %d \n", file, len, (int)strlen(returnvar)); - } - pbx_builtin_setvar_helper(chan, varname, returnvar); - ast_free(returnvar); - } - - return res; -} - - -static int unload_module(void) -{ - return ast_unregister_application(app_readfile); -} - -static int load_module(void) -{ - return ast_register_application_xml(app_readfile, readfile_exec); -} - -AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Stores output of file into a variable"); diff --git a/channels/Makefile b/channels/Makefile index 10913de312d..b24478a6a63 100644 --- a/channels/Makefile +++ b/channels/Makefile @@ -15,40 +15,6 @@ MODULE_PREFIX=chan MENUSELECT_CATEGORY=CHANNELS MENUSELECT_DESCRIPTION=Channel Drivers -ifeq ($(OSARCH),OpenBSD) - PTLIB=-lpt - H323LIB=-lh323 -endif - -ifeq ($(OSARCH),linux-gnu) - PTLIB=-lpt_linux_x86_r - H323LIB=-lh323_linux_x86_r - CHANH323LIB=-ldl -endif - -ifeq ($(OSARCH),FreeBSD) - PTLIB=-lpt_FreeBSD_x86_r - H323LIB=-lh323_FreeBSD_x86_r - CHANH323LIB=-pthread -endif - -ifeq ($(OSARCH),NetBSD) - PTLIB=-lpt_NetBSD_x86_r - H323LIB=-lh323_NetBSD_x86_r -endif - -ifeq ($(wildcard h323/libchanh323.a),) - MODULE_EXCLUDE += chan_h323 -endif - -ifndef OPENH323DIR - OPENH323DIR=$(HOME)/openh323 -endif - -ifndef PWLIBDIR - PWLIBDIR=$(HOME)/pwlib -endif - all: _all include $(ASTTOPDIR)/Makefile.moddir_rules @@ -57,20 +23,12 @@ ifneq ($(findstring $(OSARCH), mingw32 cygwin ),) LIBS+= -lres_monitor.so -lres_features.so endif -ifneq ($(wildcard h323/Makefile.ast),) -include h323/Makefile.ast -endif - clean:: $(MAKE) -C misdn clean rm -f dahdi/*.o dahdi/*.i rm -f sip/*.o sip/*.i rm -f iax2/*.o iax2/*.i rm -f pjsip/*.o pjsip/*.i - rm -f h323/libchanh323.a h323/Makefile.ast h323/*.o h323/*.dep - -dist-clean:: - rm -f h323/Makefile $(if $(filter chan_iax2,$(EMBEDDED_MODS)),modules.link,chan_iax2.so): $(subst .c,.o,$(wildcard iax2/*.c)) $(subst .c,.o,$(wildcard iax2/*.c)): _ASTCFLAGS+=$(call MOD_ASTCFLAGS,chan_iax2) @@ -91,20 +49,6 @@ CHAN_DAHDI_OBJS= \ $(if $(filter chan_dahdi,$(EMBEDDED_MODS)),modules.link,chan_dahdi.so): $(CHAN_DAHDI_OBJS) $(CHAN_DAHDI_OBJS): _ASTCFLAGS+=$(call MOD_ASTCFLAGS,chan_dahdi) -ifneq ($(filter chan_h323,$(EMBEDDED_MODS)),) -modules.link: h323/libchanh323.a -else -ifeq ($(OSARCH),linux-gnu) -chan_h323.so: chan_h323.o h323/libchanh323.a - $(ECHO_PREFIX) echo " [LD] $^ -> $@" - $(CMD_PREFIX) $(CXX) $(PTHREAD_CFLAGS) $(_ASTLDFLAGS) $(ASTLDFLAGS) $(SOLINK) -o $@ $< h323/libchanh323.a $(H323LDLIBS) -else -chan_h323.so: chan_h323.o h323/libchanh323.a - $(ECHO_PREFIX) echo " [LD] $^ -> $@" - $(CMD_PREFIX) $(CXX) $(PTHREAD_CFLAGS) $(_ASTLDFLAGS) $(ASTLDFLAGS) $(SOLINK) -o $@ $< h323/libchanh323.a $(CHANH323LIB) -L$(PWLIBDIR)/lib $(PTLIB) -L$(OPENH323DIR)/lib $(H323LIB) -L/usr/lib -lcrypto -lssl -lexpat -endif -endif - chan_misdn.o: _ASTCFLAGS+=-Imisdn misdn_config.o: _ASTCFLAGS+=-Imisdn @@ -122,9 +66,3 @@ chan_usbradio.o: ./xpmr/xpmr.c ./xpmr/xpmr.h ./xpmr/xpmr_coef.h chan_usbradio.so: LIBS+=-lusb -lasound chan_usbradio.so: _ASTCFLAGS+=-DNDEBUG -h323/Makefile.ast: - $(CMD_PREFIX) $(MAKE) -C h323 Makefile.ast - -h323/libchanh323.a: h323/Makefile.ast - $(CMD_PREFIX) $(MAKE) -C h323 libchanh323.a - diff --git a/channels/chan_gtalk.c b/channels/chan_gtalk.c deleted file mode 100644 index 7427fe1388f..00000000000 --- a/channels/chan_gtalk.c +++ /dev/null @@ -1,2447 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 1999 - 2005, Digium, Inc. - * - * Matt O'Gorman - * Philippe Sultan - * - * 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 - * - * \author Matt O'Gorman - * \author Philippe Sultan - * - * \brief Gtalk Channel Driver, until google/libjingle works with jingle spec - * - * \ingroup channel_drivers - * - * ********** General TODO:s - * \todo Support config reloading. - * \todo Fix native bridging. - */ - -/*! \li \ref chan_gtalk.c uses the configuration file \ref gtalk.conf - * \addtogroup configuration_file - */ - -/*! \page gtalk.conf gtalk.conf - * \verbinclude gtalk.conf.sample - */ - -/*** MODULEINFO - no - iksemel - res_jabber - openssl - deprecated - chan_motif - ***/ - -#include "asterisk.h" - -ASTERISK_FILE_VERSION(__FILE__, "$Revision$") - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "asterisk/lock.h" -#include "asterisk/channel.h" -#include "asterisk/config.h" -#include "asterisk/module.h" -#include "asterisk/pbx.h" -#include "asterisk/sched.h" -#include "asterisk/io.h" -#include "asterisk/rtp_engine.h" -#include "asterisk/stun.h" -#include "asterisk/acl.h" -#include "asterisk/callerid.h" -#include "asterisk/file.h" -#include "asterisk/cli.h" -#include "asterisk/app.h" -#include "asterisk/musiconhold.h" -#include "asterisk/manager.h" -#include "asterisk/stringfields.h" -#include "asterisk/utils.h" -#include "asterisk/causes.h" -#include "asterisk/astobj.h" -#include "asterisk/abstract_jb.h" -#include "asterisk/jabber.h" -#include "asterisk/jingle.h" -#include "asterisk/parking.h" -#include "asterisk/stasis_channels.h" - -#define GOOGLE_CONFIG "gtalk.conf" - -/*! Global jitterbuffer configuration - by default, jb is disabled */ -static struct ast_jb_conf default_jbconf = -{ - .flags = 0, - .max_size = -1, - .resync_threshold = -1, - .impl = "", - .target_extra = -1, -}; -static struct ast_jb_conf global_jbconf; - -enum gtalk_protocol { - AJI_PROTOCOL_UDP = 1, - AJI_PROTOCOL_SSLTCP = 2, -}; - -enum gtalk_connect_type { - AJI_CONNECT_STUN = 1, - AJI_CONNECT_LOCAL = 2, - AJI_CONNECT_RELAY = 3, -}; - -struct gtalk_pvt { - ast_mutex_t lock; /*!< Channel private lock */ - time_t laststun; - struct gtalk *parent; /*!< Parent client */ - char sid[100]; - char us[AJI_MAX_JIDLEN]; - char them[AJI_MAX_JIDLEN]; - char ring[10]; /*!< Message ID of ring */ - iksrule *ringrule; /*!< Rule for matching RING request */ - int initiator; /*!< If we're the initiator */ - int alreadygone; - struct ast_codec_pref prefs; - struct gtalk_candidate *theircandidates; - struct gtalk_candidate *ourcandidates; - char cid_num[80]; /*!< Caller ID num */ - char cid_name[80]; /*!< Caller ID name */ - char exten[80]; /*!< Called extension */ - struct ast_channel *owner; /*!< Master Channel */ - struct ast_rtp_instance *rtp; /*!< RTP audio session */ - struct ast_rtp_instance *vrtp; /*!< RTP video session */ - struct ast_format_cap *cap; - struct ast_format_cap *jointcap; /*!< Supported capability at both ends (codecs ) */ - struct ast_format_cap *peercap; - struct gtalk_pvt *next; /* Next entity */ -}; - -struct gtalk_candidate { - char name[100]; - enum gtalk_protocol protocol; - double preference; - char username[100]; - char password[100]; - enum gtalk_connect_type type; - char network[6]; - int generation; - char ip[16]; - int port; - int receipt; - struct gtalk_candidate *next; -}; - -struct gtalk { - ASTOBJ_COMPONENTS(struct gtalk); - struct aji_client *connection; - struct aji_buddy *buddy; - struct gtalk_pvt *p; - struct ast_codec_pref prefs; - int amaflags; /*!< AMA Flags */ - char user[AJI_MAX_JIDLEN]; - char context[AST_MAX_CONTEXT]; - char parkinglot[AST_MAX_CONTEXT]; /*!< Parkinglot */ - char accountcode[AST_MAX_ACCOUNT_CODE]; /*!< Account code */ - struct ast_format_cap *cap; - ast_group_t callgroup; /*!< Call group */ - ast_group_t pickupgroup; /*!< Pickup group */ - int callingpres; /*!< Calling presentation */ - int allowguest; - char language[MAX_LANGUAGE]; /*!< Default language for prompts */ - char musicclass[MAX_MUSICCLASS]; /*!< Music on Hold class */ -}; - -struct gtalk_container { - ASTOBJ_CONTAINER_COMPONENTS(struct gtalk); -}; - -static const char desc[] = "Gtalk Channel"; -static const char DEFAULT_CONTEXT[] = "default"; -static const int DEFAULT_ALLOWGUEST = 1; - -static struct ast_format_cap *global_capability; - -AST_MUTEX_DEFINE_STATIC(gtalklock); /*!< Protect the interface list (of gtalk_pvt's) */ - -/* Forward declarations */ -static struct ast_channel *gtalk_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause); -/*static int gtalk_digit(struct ast_channel *ast, char digit, unsigned int duration);*/ -static int gtalk_sendtext(struct ast_channel *ast, const char *text); -static int gtalk_digit_begin(struct ast_channel *ast, char digit); -static int gtalk_digit_end(struct ast_channel *ast, char digit, unsigned int duration); -static int gtalk_call(struct ast_channel *ast, const char *dest, int timeout); -static int gtalk_hangup(struct ast_channel *ast); -static int gtalk_answer(struct ast_channel *ast); -static int gtalk_action(struct gtalk *client, struct gtalk_pvt *p, const char *action); -static void gtalk_free_pvt(struct gtalk *client, struct gtalk_pvt *p); -static int gtalk_newcall(struct gtalk *client, ikspak *pak); -static struct ast_frame *gtalk_read(struct ast_channel *ast); -static int gtalk_write(struct ast_channel *ast, struct ast_frame *f); -static int gtalk_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen); -static int gtalk_fixup(struct ast_channel *oldchan, struct ast_channel *newchan); -static int gtalk_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen); -static struct gtalk_pvt *gtalk_alloc(struct gtalk *client, const char *us, const char *them, const char *sid); -static int gtalk_update_stun(struct gtalk *client, struct gtalk_pvt *p); -/* static char *gtalk_do_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a); */ -static char *gtalk_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a); -static char *gtalk_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a); -static int gtalk_update_externip(void); -static int gtalk_parser(void *data, ikspak *pak); -static int gtalk_create_candidates(struct gtalk *client, struct gtalk_pvt *p, char *sid, char *from, char *to); -static void gtalk_set_owner(struct gtalk_pvt *p, struct ast_channel *chan); - -/*! \brief PBX interface structure for channel registration */ -static struct ast_channel_tech gtalk_tech = { - .type = "Gtalk", - .description = "Gtalk Channel Driver", - .requester = gtalk_request, - .send_text = gtalk_sendtext, - .send_digit_begin = gtalk_digit_begin, - .send_digit_end = gtalk_digit_end, - /* XXX TODO native bridging is causing odd problems with DTMF pass-through with - * the gtalk servers. Enable native bridging once the source of this problem has - * been identified. - .bridge = ast_rtp_instance_bridge, */ - .call = gtalk_call, - .hangup = gtalk_hangup, - .answer = gtalk_answer, - .read = gtalk_read, - .write = gtalk_write, - .exception = gtalk_read, - .indicate = gtalk_indicate, - .fixup = gtalk_fixup, - .send_html = gtalk_sendhtml, - .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER -}; - -static struct sockaddr_in bindaddr = { 0, }; /*!< The address we bind to */ - -static struct ast_sched_context *sched; /*!< The scheduling context */ -static struct io_context *io; /*!< The IO context */ -static struct in_addr __ourip; - -static struct ast_cli_entry gtalk_cli[] = { -/* AST_CLI_DEFINE(gtalk_do_reload, "Reload GoogleTalk configuration"), XXX TODO reloads are not possible yet. */ - AST_CLI_DEFINE(gtalk_show_channels, "Show GoogleTalk channels"), - AST_CLI_DEFINE(gtalk_show_settings, "Show GoogleTalk global settings"), -}; - -static char externip[16]; -static char global_context[AST_MAX_CONTEXT]; -static char global_parkinglot[AST_MAX_CONTEXT]; -static int global_allowguest; -static struct sockaddr_in stunaddr; /*!< the stun server we get the externip from */ -static int global_stunaddr; - -static struct gtalk_container gtalk_list; - -static void gtalk_member_destroy(struct gtalk *obj) -{ - obj->cap = ast_format_cap_destroy(obj->cap); - if (obj->connection) { - ASTOBJ_UNREF(obj->connection, ast_aji_client_destroy); - } - if (obj->buddy) { - ASTOBJ_UNREF(obj->buddy, ast_aji_buddy_destroy); - } - ast_free(obj); -} - -/* XXX This could be a source of reference leaks given that the CONTAINER_FIND - * macros bump the refcount while the traversal does not. */ -static struct gtalk *find_gtalk(char *name, char *connection) -{ - struct gtalk *gtalk = NULL; - char *domain = NULL , *s = NULL; - - if (strchr(connection, '@')) { - s = ast_strdupa(connection); - domain = strsep(&s, "@"); - ast_verbose("OOOOH domain = %s\n", domain); - } - gtalk = ASTOBJ_CONTAINER_FIND(>alk_list, name); - if (!gtalk && strchr(name, '@')) - gtalk = ASTOBJ_CONTAINER_FIND_FULL(>alk_list, name, user,,, strcasecmp); - - if (!gtalk) { - /* guest call */ - ASTOBJ_CONTAINER_TRAVERSE(>alk_list, 1, { - ASTOBJ_RDLOCK(iterator); - if (!strcasecmp(iterator->name, "guest")) { - gtalk = iterator; - } - ASTOBJ_UNLOCK(iterator); - - if (gtalk) - break; - }); - - } - return gtalk; -} - - -static int add_codec_to_answer(const struct gtalk_pvt *p, struct ast_format *codec, iks *dcodecs) -{ - int res = 0; - const char *format = ast_getformatname(codec); - - if (!strcasecmp("ulaw", format)) { - iks *payload_eg711u, *payload_pcmu; - payload_pcmu = iks_new("payload-type"); - payload_eg711u = iks_new("payload-type"); - - if(!payload_eg711u || !payload_pcmu) { - iks_delete(payload_pcmu); - iks_delete(payload_eg711u); - ast_log(LOG_WARNING,"Failed to allocate iks node\n"); - return -1; - } - iks_insert_attrib(payload_pcmu, "id", "0"); - iks_insert_attrib(payload_pcmu, "name", "PCMU"); - iks_insert_attrib(payload_pcmu, "clockrate","8000"); - iks_insert_attrib(payload_pcmu, "bitrate","64000"); - iks_insert_attrib(payload_eg711u, "id", "100"); - iks_insert_attrib(payload_eg711u, "name", "EG711U"); - iks_insert_attrib(payload_eg711u, "clockrate","8000"); - iks_insert_attrib(payload_eg711u, "bitrate","64000"); - iks_insert_node(dcodecs, payload_pcmu); - iks_insert_node(dcodecs, payload_eg711u); - res ++; - } - if (!strcasecmp("alaw", format)) { - iks *payload_eg711a, *payload_pcma; - payload_pcma = iks_new("payload-type"); - payload_eg711a = iks_new("payload-type"); - if(!payload_eg711a || !payload_pcma) { - iks_delete(payload_eg711a); - iks_delete(payload_pcma); - ast_log(LOG_WARNING,"Failed to allocate iks node\n"); - return -1; - } - iks_insert_attrib(payload_pcma, "id", "8"); - iks_insert_attrib(payload_pcma, "name", "PCMA"); - iks_insert_attrib(payload_pcma, "clockrate","8000"); - iks_insert_attrib(payload_pcma, "bitrate","64000"); - payload_eg711a = iks_new("payload-type"); - iks_insert_attrib(payload_eg711a, "id", "101"); - iks_insert_attrib(payload_eg711a, "name", "EG711A"); - iks_insert_attrib(payload_eg711a, "clockrate","8000"); - iks_insert_attrib(payload_eg711a, "bitrate","64000"); - iks_insert_node(dcodecs, payload_pcma); - iks_insert_node(dcodecs, payload_eg711a); - res ++; - } - if (!strcasecmp("ilbc", format)) { - iks *payload_ilbc = iks_new("payload-type"); - if(!payload_ilbc) { - ast_log(LOG_WARNING,"Failed to allocate iks node\n"); - return -1; - } - iks_insert_attrib(payload_ilbc, "id", "97"); - iks_insert_attrib(payload_ilbc, "name", "iLBC"); - iks_insert_attrib(payload_ilbc, "clockrate","8000"); - iks_insert_attrib(payload_ilbc, "bitrate","13300"); - iks_insert_node(dcodecs, payload_ilbc); - res ++; - } - if (!strcasecmp("g723", format)) { - iks *payload_g723 = iks_new("payload-type"); - if(!payload_g723) { - ast_log(LOG_WARNING,"Failed to allocate iks node\n"); - return -1; - } - iks_insert_attrib(payload_g723, "id", "4"); - iks_insert_attrib(payload_g723, "name", "G723"); - iks_insert_attrib(payload_g723, "clockrate","8000"); - iks_insert_attrib(payload_g723, "bitrate","6300"); - iks_insert_node(dcodecs, payload_g723); - res ++; - } - if (!strcasecmp("speex", format)) { - iks *payload_speex = iks_new("payload-type"); - if(!payload_speex) { - ast_log(LOG_WARNING,"Failed to allocate iks node\n"); - return -1; - } - iks_insert_attrib(payload_speex, "id", "110"); - iks_insert_attrib(payload_speex, "name", "speex"); - iks_insert_attrib(payload_speex, "clockrate","8000"); - iks_insert_attrib(payload_speex, "bitrate","11000"); - iks_insert_node(dcodecs, payload_speex); - res++; - } - if (!strcasecmp("gsm", format)) { - iks *payload_gsm = iks_new("payload-type"); - if(!payload_gsm) { - ast_log(LOG_WARNING,"Failed to allocate iks node\n"); - return -1; - } - iks_insert_attrib(payload_gsm, "id", "103"); - iks_insert_attrib(payload_gsm, "name", "gsm"); - iks_insert_node(dcodecs, payload_gsm); - res++; - } - - return res; -} - -static int gtalk_invite(struct gtalk_pvt *p, char *to, char *from, char *sid, int initiator) -{ - struct gtalk *client = p->parent; - iks *iq, *gtalk, *dcodecs, *payload_telephone, *transport; - int x; - struct ast_format_cap *alreadysent; - int codecs_num = 0; - char *lowerto = NULL; - struct ast_format tmpfmt; - - iq = iks_new("iq"); - gtalk = iks_new("session"); - dcodecs = iks_new("description"); - transport = iks_new("transport"); - payload_telephone = iks_new("payload-type"); - if (!(iq && gtalk && dcodecs && transport && payload_telephone)) { - iks_delete(iq); - iks_delete(gtalk); - iks_delete(dcodecs); - iks_delete(transport); - iks_delete(payload_telephone); - - ast_log(LOG_ERROR, "Could not allocate iksemel nodes\n"); - return 0; - } - iks_insert_attrib(dcodecs, "xmlns", GOOGLE_AUDIO_NS); - iks_insert_attrib(dcodecs, "xml:lang", "en"); - - if (!(alreadysent = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK))) { - return 0; - } - for (x = 0; x < AST_CODEC_PREF_SIZE; x++) { - if (!(ast_codec_pref_index(&client->prefs, x, &tmpfmt))) { - break; - } - if (!(ast_format_cap_iscompatible(client->cap, &tmpfmt))) { - continue; - } - if (ast_format_cap_iscompatible(alreadysent, &tmpfmt)) { - continue; - } - codecs_num = add_codec_to_answer(p, &tmpfmt, dcodecs); - ast_format_cap_add(alreadysent, &tmpfmt); - } - alreadysent = ast_format_cap_destroy(alreadysent); - - if (codecs_num) { - /* only propose DTMF within an audio session */ - iks_insert_attrib(payload_telephone, "id", "101"); - iks_insert_attrib(payload_telephone, "name", "telephone-event"); - iks_insert_attrib(payload_telephone, "clockrate", "8000"); - } - iks_insert_attrib(transport,"xmlns",GOOGLE_TRANSPORT_NS); - - iks_insert_attrib(iq, "type", "set"); - iks_insert_attrib(iq, "to", to); - iks_insert_attrib(iq, "from", from); - iks_insert_attrib(iq, "id", client->connection->mid); - ast_aji_increment_mid(client->connection->mid); - - iks_insert_attrib(gtalk, "xmlns", GOOGLE_NS); - iks_insert_attrib(gtalk, "type",initiator ? "initiate": "accept"); - /* put the initiator attribute to lower case if we receive the call - * otherwise GoogleTalk won't establish the session */ - if (!initiator) { - char c; - char *t = lowerto = ast_strdupa(to); - while (((c = *t) != '/') && (*t++ = tolower(c))); - } - iks_insert_attrib(gtalk, "initiator", initiator ? from : lowerto); - iks_insert_attrib(gtalk, "id", sid); - iks_insert_node(iq, gtalk); - iks_insert_node(gtalk, dcodecs); - iks_insert_node(dcodecs, payload_telephone); - - ast_aji_send(client->connection, iq); - - iks_delete(payload_telephone); - iks_delete(transport); - iks_delete(dcodecs); - iks_delete(gtalk); - iks_delete(iq); - return 1; -} - -static int gtalk_ringing_ack(void *data, ikspak *pak) -{ - struct gtalk_pvt *p = data; - struct ast_channel *owner; - - ast_mutex_lock(&p->lock); - - if (p->ringrule) { - iks_filter_remove_rule(p->parent->connection->f, p->ringrule); - } - p->ringrule = NULL; - - /* this may be a redirect */ - if (!strcmp(S_OR(iks_find_attrib(pak->x, "type"), ""), "error")) { - char *name = NULL; - char *redirect = NULL; - iks *traversenodes = NULL; - traversenodes = pak->query; - while (traversenodes) { - if (!(name = iks_name(traversenodes))) { - break; - } - if (!strcasecmp(name, "error") && - ((redirect = iks_find_cdata(traversenodes, "redirect")) || - (redirect = iks_find_cdata(traversenodes, "sta:redirect"))) && - (redirect = strstr(redirect, "xmpp:"))) { - redirect += 5; - ast_debug(1, "redirect %s\n", redirect); - ast_copy_string(p->them, redirect, sizeof(p->them)); - - gtalk_invite(p, p->them, p->us, p->sid, 1); - break; - } - traversenodes = iks_next_tag(traversenodes); - } - } - gtalk_create_candidates(p->parent, p, p->sid, p->them, p->us); - owner = p->owner; - ast_mutex_unlock(&p->lock); - - if (owner) { - ast_queue_control(owner, AST_CONTROL_RINGING); - } - - return IKS_FILTER_EAT; -} - -static int gtalk_answer(struct ast_channel *ast) -{ - struct gtalk_pvt *p = ast_channel_tech_pvt(ast); - int res = 0; - - ast_debug(1, "Answer!\n"); - ast_mutex_lock(&p->lock); - gtalk_invite(p, p->them, p->us,p->sid, 0); - ast_mutex_unlock(&p->lock); - return res; -} - -static enum ast_rtp_glue_result gtalk_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance) -{ - struct gtalk_pvt *p = ast_channel_tech_pvt(chan); - enum ast_rtp_glue_result res = AST_RTP_GLUE_RESULT_FORBID; - - if (!p) - return res; - - ast_mutex_lock(&p->lock); - if (p->rtp){ - ao2_ref(p->rtp, +1); - *instance = p->rtp; - res = AST_RTP_GLUE_RESULT_LOCAL; - } - ast_mutex_unlock(&p->lock); - - return res; -} - -static void gtalk_get_codec(struct ast_channel *chan, struct ast_format_cap *result) -{ - struct gtalk_pvt *p = ast_channel_tech_pvt(chan); - ast_mutex_lock(&p->lock); - ast_format_cap_copy(result, p->peercap); - ast_mutex_unlock(&p->lock); -} - -static int gtalk_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *rtp, struct ast_rtp_instance *vrtp, struct ast_rtp_instance *trtp, const struct ast_format_cap *cap, int nat_active) -{ - struct gtalk_pvt *p; - - p = ast_channel_tech_pvt(chan); - if (!p) - return -1; - ast_mutex_lock(&p->lock); - -/* if (rtp) - ast_rtp_get_peer(rtp, &p->redirip); - else - memset(&p->redirip, 0, sizeof(p->redirip)); - p->redircodecs = codecs; */ - - /* Reset lastrtprx timer */ - ast_mutex_unlock(&p->lock); - return 0; -} - -static struct ast_rtp_glue gtalk_rtp_glue = { - .type = "Gtalk", - .get_rtp_info = gtalk_get_rtp_peer, - .get_codec = gtalk_get_codec, - .update_peer = gtalk_set_rtp_peer, -}; - -static int gtalk_response(struct gtalk *client, char *from, ikspak *pak, const char *reasonstr, const char *reasonstr2) -{ - iks *response = NULL, *error = NULL, *reason = NULL; - int res = -1; - - response = iks_new("iq"); - if (response) { - iks_insert_attrib(response, "type", "result"); - iks_insert_attrib(response, "from", from); - iks_insert_attrib(response, "to", S_OR(iks_find_attrib(pak->x, "from"), "")); - iks_insert_attrib(response, "id", S_OR(iks_find_attrib(pak->x, "id"), "")); - if (reasonstr) { - error = iks_new("error"); - if (error) { - iks_insert_attrib(error, "type", "cancel"); - reason = iks_new(reasonstr); - if (reason) - iks_insert_node(error, reason); - iks_insert_node(response, error); - } - } - ast_aji_send(client->connection, response); - res = 0; - } - - iks_delete(reason); - iks_delete(error); - iks_delete(response); - - return res; -} - -static int gtalk_is_answered(struct gtalk *client, ikspak *pak) -{ - struct gtalk_pvt *tmp = NULL; - char *from; - iks *codec; - char s1[BUFSIZ], s2[BUFSIZ], s3[BUFSIZ]; - int peernoncodeccapability; - - ast_debug(1, "The client is %s\n", client->name); - - /* Make sure our new call does exist */ - for (tmp = client->p; tmp; tmp = tmp->next) { - if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid)) { - break; - } else if (iks_find_with_attrib(pak->x, "ses:session", "id", tmp->sid)) { - break; - } - } - - if (!tmp) { - ast_log(LOG_WARNING, "Could not find session in iq\n"); - return -1; - } - - /* codec points to the first tag */ - codec = iks_first_tag(iks_first_tag(iks_first_tag(pak->x))); - while (codec) { - char *codec_id = iks_find_attrib(codec, "id"); - char *codec_name = iks_find_attrib(codec, "name"); - if (!codec_id || !codec_name) { - codec = iks_next_tag(codec); - continue; - } - - ast_rtp_codecs_payloads_set_m_type( - ast_rtp_instance_get_codecs(tmp->rtp), - tmp->rtp, - atoi(codec_id)); - ast_rtp_codecs_payloads_set_rtpmap_type( - ast_rtp_instance_get_codecs(tmp->rtp), - tmp->rtp, - atoi(codec_id), - "audio", - codec_name, - 0); - codec = iks_next_tag(codec); - } - - /* Now gather all of the codecs that we are asked for */ - ast_rtp_codecs_payload_formats(ast_rtp_instance_get_codecs(tmp->rtp), tmp->peercap, &peernoncodeccapability); - - /* at this point, we received an answer from the remote Gtalk client, - which allows us to compare capabilities */ - ast_format_cap_joint_copy(tmp->cap, tmp->peercap, tmp->jointcap); - if (ast_format_cap_is_empty(tmp->jointcap)) { - ast_log(LOG_WARNING, "Capabilities don't match : us - %s, peer - %s, combined - %s \n", ast_getformatname_multiple(s1, BUFSIZ, tmp->cap), - ast_getformatname_multiple(s2, BUFSIZ, tmp->peercap), - ast_getformatname_multiple(s3, BUFSIZ, tmp->jointcap)); - /* close session if capabilities don't match */ - ast_queue_hangup(tmp->owner); - - return -1; - - } - - from = iks_find_attrib(pak->x, "to"); - if (!from) { - from = client->connection->jid->full; - } - - if (tmp->owner) { - ast_queue_control(tmp->owner, AST_CONTROL_ANSWER); - } - gtalk_update_stun(tmp->parent, tmp); - gtalk_response(client, from, pak, NULL, NULL); - return 1; -} - -static int gtalk_is_accepted(struct gtalk *client, ikspak *pak) -{ - struct gtalk_pvt *tmp; - char *from; - - ast_debug(1, "The client is %s\n", client->name); - /* find corresponding call */ - for (tmp = client->p; tmp; tmp = tmp->next) { - if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid)) { - break; - } - } - - from = iks_find_attrib(pak->x, "to"); - if (!from) { - from = client->connection->jid->full; - } - - if (tmp) { - gtalk_update_stun(tmp->parent, tmp); - } else { - ast_log(LOG_NOTICE, "Whoa, didn't find call during accept?!\n"); - } - - /* answer 'iq' packet to let the remote peer know that we're alive */ - gtalk_response(client, from, pak, NULL, NULL); - return 1; -} - -static int gtalk_handle_dtmf(struct gtalk *client, ikspak *pak) -{ - struct gtalk_pvt *tmp; - iks *dtmfnode = NULL, *dtmfchild = NULL; - char *dtmf; - char *from; - /* Make sure our new call doesn't exist yet */ - for (tmp = client->p; tmp; tmp = tmp->next) { - if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) || iks_find_with_attrib(pak->x, "gtalk", "sid", tmp->sid)) - break; - } - from = iks_find_attrib(pak->x, "to"); - if (!from) { - from = client->connection->jid->full; - } - - if (tmp) { - if(iks_find_with_attrib(pak->x, "dtmf-method", "method", "rtp")) { - gtalk_response(client, from, pak, - "feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", - "unsupported-dtmf-method xmlns='http://jabber.org/protocol/gtalk/info/dtmf#errors'"); - return -1; - } - if ((dtmfnode = iks_find(pak->x, "dtmf"))) { - if((dtmf = iks_find_attrib(dtmfnode, "code"))) { - if(iks_find_with_attrib(pak->x, "dtmf", "action", "button-up")) { - struct ast_frame f = {AST_FRAME_DTMF_BEGIN, }; - f.subclass.integer = dtmf[0]; - ast_queue_frame(tmp->owner, &f); - ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer); - } else if(iks_find_with_attrib(pak->x, "dtmf", "action", "button-down")) { - struct ast_frame f = {AST_FRAME_DTMF_END, }; - f.subclass.integer = dtmf[0]; - ast_queue_frame(tmp->owner, &f); - ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer); - } else if(iks_find_attrib(pak->x, "dtmf")) { /* 250 millasecond default */ - struct ast_frame f = {AST_FRAME_DTMF, }; - f.subclass.integer = dtmf[0]; - ast_queue_frame(tmp->owner, &f); - ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer); - } - } - } else if ((dtmfnode = iks_find_with_attrib(pak->x, "gtalk", "action", "session-info"))) { - if((dtmfchild = iks_find(dtmfnode, "dtmf"))) { - if((dtmf = iks_find_attrib(dtmfchild, "code"))) { - if(iks_find_with_attrib(dtmfnode, "dtmf", "action", "button-up")) { - struct ast_frame f = {AST_FRAME_DTMF_END, }; - f.subclass.integer = dtmf[0]; - ast_queue_frame(tmp->owner, &f); - ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer); - } else if(iks_find_with_attrib(dtmfnode, "dtmf", "action", "button-down")) { - struct ast_frame f = {AST_FRAME_DTMF_BEGIN, }; - f.subclass.integer = dtmf[0]; - ast_queue_frame(tmp->owner, &f); - ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer); - } - } - } - } - gtalk_response(client, from, pak, NULL, NULL); - return 1; - } else { - ast_log(LOG_NOTICE, "Whoa, didn't find call!\n"); - } - - gtalk_response(client, from, pak, NULL, NULL); - return 1; -} - -static int gtalk_hangup_farend(struct gtalk *client, ikspak *pak) -{ - struct gtalk_pvt *tmp; - char *from; - - ast_debug(1, "The client is %s\n", client->name); - /* Make sure our new call doesn't exist yet */ - for (tmp = client->p; tmp; tmp = tmp->next) { - if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) || - (iks_find_attrib(pak->query, "id") && !strcmp(iks_find_attrib(pak->query, "id"), tmp->sid))) { - break; - } - } - from = iks_find_attrib(pak->x, "to"); - if (!from) { - from = client->connection->jid->full; - } - - if (tmp) { - tmp->alreadygone = 1; - if (tmp->owner) { - ast_queue_hangup(tmp->owner); - } - } else { - ast_log(LOG_NOTICE, "Whoa, didn't find call during hangup!\n"); - } - gtalk_response(client, from, pak, NULL, NULL); - return 1; -} - -static int gtalk_get_local_ip(struct ast_sockaddr *ourip) -{ - struct ast_sockaddr root; - struct ast_sockaddr bindaddr_tmp; - struct ast_sockaddr *addrs; - - /* If bind address is not 0.0.0.0, then bindaddr is our local ip. */ - ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr); - if (!ast_sockaddr_is_any(&bindaddr_tmp)) { - ast_sockaddr_copy(ourip, &bindaddr_tmp); - return 0; - } - - /* If no bind address was provided, lets see what ip we would use to connect to google.com and use that. - * If you can't resolve google.com from your network, then this module is useless for you anyway. */ - if (ast_sockaddr_resolve(&addrs, "google.com", PARSE_PORT_FORBID, AF_INET) > 0) { - ast_sockaddr_copy(&root, &addrs[0]); - ast_free(addrs); - if (!ast_ouraddrfor(&root, ourip)) { - return 0; - } - } - - /* As a last resort, use this function to find our local address. */ - return ast_find_ourip(ourip, &bindaddr_tmp, AF_INET); -} - -static int gtalk_create_candidates(struct gtalk *client, struct gtalk_pvt *p, char *sid, char *from, char *to) -{ - struct gtalk_candidate *tmp; - struct aji_client *c = client->connection; - struct gtalk_candidate *ours1 = NULL, *ours2 = NULL; - struct sockaddr_in sin = { 0, }; - struct ast_sockaddr sin_tmp; - struct ast_sockaddr us; - iks *iq, *gtalk, *candidate, *transport; - char user[17], pass[17], preference[5], port[7]; - char *lowerfrom = NULL; - - iq = iks_new("iq"); - gtalk = iks_new("session"); - candidate = iks_new("candidate"); - transport = iks_new("transport"); - if (!iq || !gtalk || !candidate || !transport) { - ast_log(LOG_ERROR, "Memory allocation error\n"); - goto safeout; - } - ours1 = ast_calloc(1, sizeof(*ours1)); - ours2 = ast_calloc(1, sizeof(*ours2)); - if (!ours1 || !ours2) - goto safeout; - - iks_insert_attrib(transport, "xmlns",GOOGLE_TRANSPORT_NS); - iks_insert_node(iq, gtalk); - iks_insert_node(gtalk,candidate); - iks_insert_node(gtalk,transport); - - for (; p; p = p->next) { - if (!strcasecmp(p->sid, sid)) - break; - } - - if (!p) { - ast_log(LOG_NOTICE, "No matching gtalk session - SID %s!\n", sid); - goto safeout; - } - - ast_rtp_instance_get_local_address(p->rtp, &sin_tmp); - ast_sockaddr_to_sin(&sin_tmp, &sin); - - gtalk_get_local_ip(&us); - - if (!strcmp(ast_sockaddr_stringify_addr(&us), "127.0.0.1")) { - ast_log(LOG_WARNING, "Found a loopback IP on the system, check your network configuration or set the bindaddr attribute.\n"); - } - - /* Setup our gtalk candidates */ - ast_copy_string(ours1->name, "rtp", sizeof(ours1->name)); - ours1->port = ntohs(sin.sin_port); - ours1->preference = 1; - snprintf(user, sizeof(user), "%08lx%08lx", (long unsigned)ast_random(), (long unsigned)ast_random()); - snprintf(pass, sizeof(pass), "%08lx%08lx", (long unsigned)ast_random(), (long unsigned)ast_random()); - ast_copy_string(ours1->username, user, sizeof(ours1->username)); - ast_copy_string(ours1->password, pass, sizeof(ours1->password)); - ast_copy_string(ours1->ip, ast_sockaddr_stringify_addr(&us), - sizeof(ours1->ip)); - ours1->protocol = AJI_PROTOCOL_UDP; - ours1->type = AJI_CONNECT_LOCAL; - ours1->generation = 0; - p->ourcandidates = ours1; - - /* XXX this is a blocking action. We send a STUN request to the server - * and wait for the response. If blocking here is a problem the STUN requests/responses - * for the externip may need to be done differently. */ - gtalk_update_externip(); - if (!ast_strlen_zero(externip)) { - ast_copy_string(ours2->username, user, sizeof(ours2->username)); - ast_copy_string(ours2->password, pass, sizeof(ours2->password)); - ast_copy_string(ours2->ip, externip, sizeof(ours2->ip)); - ast_copy_string(ours2->name, "rtp", sizeof(ours1->name)); - ours2->port = ntohs(sin.sin_port); - ours2->preference = 0.9; - ours2->protocol = AJI_PROTOCOL_UDP; - ours2->type = AJI_CONNECT_STUN; - ours2->generation = 0; - ours1->next = ours2; - ours2 = NULL; - } - ours1 = NULL; - - for (tmp = p->ourcandidates; tmp; tmp = tmp->next) { - snprintf(port, sizeof(port), "%d", tmp->port); - snprintf(preference, sizeof(preference), "%.2f", tmp->preference); - iks_insert_attrib(iq, "from", to); - iks_insert_attrib(iq, "to", from); - iks_insert_attrib(iq, "type", "set"); - iks_insert_attrib(iq, "id", c->mid); - ast_aji_increment_mid(c->mid); - iks_insert_attrib(gtalk, "type", "candidates"); - iks_insert_attrib(gtalk, "id", sid); - /* put the initiator attribute to lower case if we receive the call - * otherwise GoogleTalk won't establish the session */ - if (!p->initiator) { - char cur; - char *t = lowerfrom = ast_strdupa(from); - while (((cur = *t) != '/') && (*t++ = tolower(cur))); - } - iks_insert_attrib(gtalk, "initiator", (p->initiator) ? to : lowerfrom); - iks_insert_attrib(gtalk, "xmlns", GOOGLE_NS); - iks_insert_attrib(candidate, "name", tmp->name); - iks_insert_attrib(candidate, "address", tmp->ip); - iks_insert_attrib(candidate, "port", port); - iks_insert_attrib(candidate, "username", tmp->username); - iks_insert_attrib(candidate, "password", tmp->password); - iks_insert_attrib(candidate, "preference", preference); - if (tmp->protocol == AJI_PROTOCOL_UDP) - iks_insert_attrib(candidate, "protocol", "udp"); - if (tmp->protocol == AJI_PROTOCOL_SSLTCP) - iks_insert_attrib(candidate, "protocol", "ssltcp"); - if (tmp->type == AJI_CONNECT_STUN) - iks_insert_attrib(candidate, "type", "stun"); - if (tmp->type == AJI_CONNECT_LOCAL) - iks_insert_attrib(candidate, "type", "local"); - if (tmp->type == AJI_CONNECT_RELAY) - iks_insert_attrib(candidate, "type", "relay"); - iks_insert_attrib(candidate, "network", "0"); - iks_insert_attrib(candidate, "generation", "0"); - ast_aji_send(c, iq); - } - p->laststun = 0; - -safeout: - if (ours1) - ast_free(ours1); - if (ours2) - ast_free(ours2); - iks_delete(iq); - iks_delete(gtalk); - iks_delete(candidate); - iks_delete(transport); - - return 1; -} - -static void gtalk_set_owner(struct gtalk_pvt *p, struct ast_channel *chan) -{ - p->owner = chan; - if (p->rtp) { - ast_rtp_instance_set_channel_id(p->rtp, chan ? ast_channel_uniqueid(chan) : ""); - } - if (p->vrtp) { - ast_rtp_instance_set_channel_id(p->vrtp, chan ? ast_channel_uniqueid(chan) : ""); - } -} - -static struct gtalk_pvt *gtalk_alloc(struct gtalk *client, const char *us, const char *them, const char *sid) -{ - struct gtalk_pvt *tmp = NULL; - struct aji_resource *resources = NULL; - struct aji_buddy *buddy = NULL; - char idroster[200] = ""; - char *data, *exten = NULL; - struct ast_sockaddr bindaddr_tmp; - - ast_debug(1, "The client is %s for alloc\n", client->name); - if (!sid && !strchr(them, '/')) { /* I started call! */ - if (!strcasecmp(client->name, "guest")) { - buddy = ASTOBJ_CONTAINER_FIND(&client->connection->buddies, them); - if (buddy) { - resources = buddy->resources; - } - } else if (client->buddy) { - resources = client->buddy->resources; - } - - while (resources) { - if (resources->cap->jingle) { - break; - } - resources = resources->next; - } - if (resources) { - snprintf(idroster, sizeof(idroster), "%s/%s", them, resources->resource); - } else if ((*them == '+') || (strstr(them, "@voice.google.com"))) { - snprintf(idroster, sizeof(idroster), "%s", them); - } else { - ast_log(LOG_ERROR, "no gtalk capable clients to talk to.\n"); - if (buddy) { - ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy); - } - return NULL; - } - if (buddy) { - ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy); - } - } - if (!(tmp = ast_calloc(1, sizeof(*tmp)))) { - return NULL; - } - tmp->cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); - tmp->jointcap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); - tmp->peercap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); - if (!tmp->jointcap || !tmp->peercap || !tmp->cap) { - tmp->cap = ast_format_cap_destroy(tmp->cap); - tmp->jointcap = ast_format_cap_destroy(tmp->jointcap); - tmp->peercap = ast_format_cap_destroy(tmp->peercap); - ast_free(tmp); - return NULL; - } - - memcpy(&tmp->prefs, &client->prefs, sizeof(struct ast_codec_pref)); - - if (sid) { - ast_copy_string(tmp->sid, sid, sizeof(tmp->sid)); - ast_copy_string(tmp->them, them, sizeof(tmp->them)); - ast_copy_string(tmp->us, us, sizeof(tmp->us)); - } else { - snprintf(tmp->sid, sizeof(tmp->sid), "%08lx%08lx", (long unsigned)ast_random(), (long unsigned)ast_random()); - ast_copy_string(tmp->them, idroster, sizeof(tmp->them)); - ast_copy_string(tmp->us, us, sizeof(tmp->us)); - tmp->initiator = 1; - } - /* clear codecs */ - bindaddr.sin_family = AF_INET; - ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr); - if (!(tmp->rtp = ast_rtp_instance_new("asterisk", sched, &bindaddr_tmp, NULL))) { - ast_log(LOG_ERROR, "Failed to create a new RTP instance (possibly an invalid bindaddr?)\n"); - ast_free(tmp); - return NULL; - } - ast_rtp_instance_set_prop(tmp->rtp, AST_RTP_PROPERTY_RTCP, 1); - ast_rtp_instance_set_prop(tmp->rtp, AST_RTP_PROPERTY_STUN, 1); - ast_rtp_instance_set_prop(tmp->rtp, AST_RTP_PROPERTY_DTMF, 1); - ast_rtp_instance_dtmf_mode_set(tmp->rtp, AST_RTP_DTMF_MODE_RFC2833); - ast_rtp_codecs_payloads_clear(ast_rtp_instance_get_codecs(tmp->rtp), tmp->rtp); - - /* add user configured codec capabilites */ - if (!(ast_format_cap_is_empty(client->cap))) { - ast_format_cap_copy(tmp->cap, client->cap); - } else if (!(ast_format_cap_is_empty(global_capability))) { - ast_format_cap_copy(tmp->cap, global_capability); - } - - tmp->parent = client; - if (!tmp->rtp) { - ast_log(LOG_WARNING, "Out of RTP sessions?\n"); - ast_free(tmp); - return NULL; - } - - /* Set CALLERID(name) to the full JID of the remote peer */ - ast_copy_string(tmp->cid_name, tmp->them, sizeof(tmp->cid_name)); - - if(strchr(tmp->us, '/')) { - data = ast_strdupa(tmp->us); - exten = strsep(&data, "/"); - } else { - exten = tmp->us; - } - ast_copy_string(tmp->exten, exten, sizeof(tmp->exten)); - ast_mutex_init(&tmp->lock); - ast_mutex_lock(>alklock); - tmp->next = client->p; - client->p = tmp; - ast_mutex_unlock(>alklock); - return tmp; -} - -/*! \brief Start new gtalk channel */ -static struct ast_channel *gtalk_new(struct gtalk *client, struct gtalk_pvt *i, int state, const char *title, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor) -{ - struct ast_channel *tmp; - const char *n2; - struct ast_format_cap *what; /* used as SHALLOW COPY DO NOT DESTROY */ - struct ast_format tmpfmt; - - if (title) - n2 = title; - else - n2 = i->us; - tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, client->accountcode, i->exten, client->context, assignedids, requestor, client->amaflags, "Gtalk/%s-%04lx", n2, ast_random() & 0xffff); - if (!tmp) { - ast_log(LOG_WARNING, "Unable to allocate Gtalk channel structure!\n"); - return NULL; - } - - ast_channel_stage_snapshot(tmp); - - ast_channel_tech_set(tmp, >alk_tech); - - /* Select our native format based on codec preference until we receive - something from another device to the contrary. */ - if (!(ast_format_cap_is_empty(i->jointcap))) { - what = i->jointcap; - } else if (i->cap) { - what = i->cap; - } else { - what = global_capability; - } - - /* Set Frame packetization */ - if (i->rtp) { - ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(i->rtp), i->rtp, &i->prefs); - } - - ast_codec_choose(&i->prefs, what, 1, &tmpfmt); - ast_format_cap_add(ast_channel_nativeformats(tmp), &tmpfmt); - - ast_format_cap_iter_start(i->jointcap); - while (!(ast_format_cap_iter_next(i->jointcap, &tmpfmt))) { - if (AST_FORMAT_GET_TYPE(tmpfmt.id) == AST_FORMAT_TYPE_VIDEO) { - ast_format_cap_add(ast_channel_nativeformats(tmp), &tmpfmt); - } - } - ast_format_cap_iter_end(i->jointcap); - - if (i->rtp) { - ast_channel_set_fd(tmp, 0, ast_rtp_instance_fd(i->rtp, 0)); - ast_channel_set_fd(tmp, 1, ast_rtp_instance_fd(i->rtp, 1)); - } - if (i->vrtp) { - ast_channel_set_fd(tmp, 2, ast_rtp_instance_fd(i->vrtp, 0)); - ast_channel_set_fd(tmp, 3, ast_rtp_instance_fd(i->vrtp, 1)); - } - if (state == AST_STATE_RING) - ast_channel_rings_set(tmp, 1); - ast_channel_adsicpe_set(tmp, AST_ADSI_UNAVAILABLE); - - ast_best_codec(ast_channel_nativeformats(tmp), &tmpfmt); - ast_format_copy(ast_channel_writeformat(tmp), &tmpfmt); - ast_format_copy(ast_channel_rawwriteformat(tmp), &tmpfmt); - ast_format_copy(ast_channel_readformat(tmp), &tmpfmt); - ast_format_copy(ast_channel_rawreadformat(tmp), &tmpfmt); - ast_channel_tech_pvt_set(tmp, i); - - ast_channel_callgroup_set(tmp, client->callgroup); - ast_channel_pickupgroup_set(tmp, client->pickupgroup); - ast_channel_caller(tmp)->id.name.presentation = client->callingpres; - ast_channel_caller(tmp)->id.number.presentation = client->callingpres; - if (!ast_strlen_zero(client->accountcode)) - ast_channel_accountcode_set(tmp, client->accountcode); - if (client->amaflags) - ast_channel_amaflags_set(tmp, client->amaflags); - if (!ast_strlen_zero(client->language)) - ast_channel_language_set(tmp, client->language); - if (!ast_strlen_zero(client->musicclass)) - ast_channel_musicclass_set(tmp, client->musicclass); - if (!ast_strlen_zero(client->parkinglot)) - ast_channel_parkinglot_set(tmp, client->parkinglot); - gtalk_set_owner(i, tmp); - ast_module_ref(ast_module_info->self); - ast_channel_context_set(tmp, client->context); - ast_channel_exten_set(tmp, i->exten); - - if (!ast_strlen_zero(i->exten) && strcmp(i->exten, "s")) { - ast_channel_dialed(tmp)->number.str = ast_strdup(i->exten); - } - ast_channel_priority_set(tmp, 1); - if (i->rtp) - ast_jb_configure(tmp, &global_jbconf); - - ast_channel_stage_snapshot_done(tmp); - ast_channel_unlock(tmp); - - if (state != AST_STATE_DOWN && ast_pbx_start(tmp)) { - ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp)); - ast_channel_hangupcause_set(tmp, AST_CAUSE_SWITCH_CONGESTION); - ast_hangup(tmp); - tmp = NULL; - } - return tmp; -} - -static int gtalk_action(struct gtalk *client, struct gtalk_pvt *p, const char *action) -{ - iks *request, *session = NULL; - int res = -1; - char *lowerthem = NULL; - - request = iks_new("iq"); - if (request) { - iks_insert_attrib(request, "type", "set"); - iks_insert_attrib(request, "from", p->us); - iks_insert_attrib(request, "to", p->them); - iks_insert_attrib(request, "id", client->connection->mid); - ast_aji_increment_mid(client->connection->mid); - session = iks_new("session"); - if (session) { - iks_insert_attrib(session, "type", action); - iks_insert_attrib(session, "id", p->sid); - /* put the initiator attribute to lower case if we receive the call - * otherwise GoogleTalk won't establish the session */ - if (!p->initiator) { - char c; - char *t = lowerthem = ast_strdupa(p->them); - while (((c = *t) != '/') && (*t++ = tolower(c))); - } - iks_insert_attrib(session, "initiator", p->initiator ? p->us : lowerthem); - iks_insert_attrib(session, "xmlns", GOOGLE_NS); - iks_insert_node(request, session); - ast_aji_send(client->connection, request); - res = 0; - } - } - - iks_delete(session); - iks_delete(request); - - return res; -} - -static void gtalk_free_candidates(struct gtalk_candidate *candidate) -{ - struct gtalk_candidate *last; - while (candidate) { - last = candidate; - candidate = candidate->next; - ast_free(last); - } -} - -static void gtalk_free_pvt(struct gtalk *client, struct gtalk_pvt *p) -{ - struct gtalk_pvt *cur, *prev = NULL; - cur = client->p; - while (cur) { - if (cur == p) { - if (prev) - prev->next = p->next; - else - client->p = p->next; - break; - } - prev = cur; - cur = cur->next; - } - if (p->ringrule) - iks_filter_remove_rule(p->parent->connection->f, p->ringrule); - if (p->owner) - ast_log(LOG_WARNING, "Uh oh, there's an owner, this is going to be messy.\n"); - if (p->rtp) - ast_rtp_instance_destroy(p->rtp); - if (p->vrtp) - ast_rtp_instance_destroy(p->vrtp); - gtalk_free_candidates(p->theircandidates); - p->cap = ast_format_cap_destroy(p->cap); - p->jointcap = ast_format_cap_destroy(p->jointcap); - p->peercap = ast_format_cap_destroy(p->peercap); - ast_free(p); -} - - -static int gtalk_newcall(struct gtalk *client, ikspak *pak) -{ - struct gtalk_pvt *p, *tmp = client->p; - struct ast_channel *chan; - int res; - iks *codec; - char *from = NULL; - char s1[BUFSIZ], s2[BUFSIZ], s3[BUFSIZ]; - int peernoncodeccapability; - char *sid; - - /* Make sure our new call doesn't exist yet */ - from = iks_find_attrib(pak->x,"to"); - if (!from) { - from = client->connection->jid->full; - } - - while (tmp) { - if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) || - (iks_find_attrib(pak->query, "id") && !strcmp(iks_find_attrib(pak->query, "id"), tmp->sid))) { - ast_log(LOG_NOTICE, "Ignoring duplicate call setup on SID %s\n", tmp->sid); - gtalk_response(client, from, pak, "out-of-order", NULL); - return -1; - } - tmp = tmp->next; - } - - if (!strcasecmp(client->name, "guest")){ - /* the guest account is not tied to any configured XMPP client, - let's set it now */ - if (client->connection) { - ASTOBJ_UNREF(client->connection, ast_aji_client_destroy); - } - client->connection = ast_aji_get_client(from); - if (!client->connection) { - ast_log(LOG_ERROR, "No XMPP client to talk to, us (partial JID) : %s\n", from); - return -1; - } - } - - if (!(sid = iks_find_attrib(pak->query, "id"))) { - ast_log(LOG_WARNING, "Received Initiate without id attribute. Can not start call.\n"); - return -1; - } - - p = gtalk_alloc(client, from, pak->from->full, sid); - if (!p) { - ast_log(LOG_WARNING, "Unable to allocate gtalk structure!\n"); - return -1; - } - - chan = gtalk_new(client, p, AST_STATE_DOWN, pak->from->user, NULL, NULL); - if (!chan) { - gtalk_free_pvt(client, p); - return -1; - } - - ast_mutex_lock(&p->lock); - ast_copy_string(p->them, pak->from->full, sizeof(p->them)); - ast_copy_string(p->sid, sid, sizeof(p->sid)); - - /* codec points to the first tag */ - codec = iks_first_tag(iks_first_tag(pak->query)); - - while (codec) { - char *codec_id = iks_find_attrib(codec, "id"); - char *codec_name = iks_find_attrib(codec, "name"); - if (!codec_id || !codec_name) { - codec = iks_next_tag(codec); - continue; - } - if (!strcmp(S_OR(iks_name(codec), ""), "vid:payload-type") && p->vrtp) { - ast_rtp_codecs_payloads_set_m_type( - ast_rtp_instance_get_codecs(p->vrtp), - p->vrtp, - atoi(codec_id)); - ast_rtp_codecs_payloads_set_rtpmap_type( - ast_rtp_instance_get_codecs(p->vrtp), - p->vrtp, - atoi(codec_id), - "video", - codec_name, - 0); - } else { - ast_rtp_codecs_payloads_set_m_type( - ast_rtp_instance_get_codecs(p->rtp), - p->rtp, - atoi(codec_id)); - ast_rtp_codecs_payloads_set_rtpmap_type( - ast_rtp_instance_get_codecs(p->rtp), - p->rtp, - atoi(codec_id), - "audio", - codec_name, - 0); - } - codec = iks_next_tag(codec); - } - - /* Now gather all of the codecs that we are asked for */ - ast_rtp_codecs_payload_formats(ast_rtp_instance_get_codecs(p->rtp), p->peercap, &peernoncodeccapability); - ast_format_cap_joint_copy(p->cap, p->peercap, p->jointcap); - ast_mutex_unlock(&p->lock); - - ast_channel_lock(chan); - ast_setstate(chan, AST_STATE_RING); - ast_channel_unlock(chan); - if (ast_format_cap_is_empty(p->jointcap)) { - ast_log(LOG_WARNING, "Capabilities don't match : us - %s, peer - %s, combined - %s \n", ast_getformatname_multiple(s1, BUFSIZ, p->cap), - ast_getformatname_multiple(s2, BUFSIZ, p->peercap), - ast_getformatname_multiple(s3, BUFSIZ, p->jointcap)); - /* close session if capabilities don't match */ - gtalk_action(client, p, "reject"); - p->alreadygone = 1; - gtalk_hangup(chan); - ast_channel_release(chan); - return -1; - } - - res = ast_pbx_start(chan); - - switch (res) { - case AST_PBX_FAILED: - ast_log(LOG_WARNING, "Failed to start PBX :(\n"); - gtalk_response(client, from, pak, "service-unavailable", NULL); - break; - case AST_PBX_CALL_LIMIT: - ast_log(LOG_WARNING, "Failed to start PBX (call limit reached) \n"); - gtalk_response(client, from, pak, "service-unavailable", NULL); - break; - case AST_PBX_SUCCESS: - gtalk_response(client, from, pak, NULL, NULL); - gtalk_create_candidates(client, p, p->sid, p->them, p->us); - /* nothing to do */ - break; - } - - return 1; -} - -static int gtalk_update_externip(void) -{ - int sock; - char *newaddr; - struct sockaddr_in answer = { 0, }; - struct sockaddr_in *dst; - struct ast_sockaddr tmp_dst; - - if (!stunaddr.sin_addr.s_addr) { - return -1; - } - dst = &stunaddr; - - sock = socket(AF_INET, SOCK_DGRAM, 0); - if (sock < 0) { - ast_log(LOG_WARNING, "Unable to create STUN socket: %s\n", strerror(errno)); - return -1; - } - - ast_sockaddr_from_sin(&tmp_dst, dst); - if (ast_connect(sock, &tmp_dst) != 0) { - ast_log(LOG_WARNING, "STUN Failed to connect to %s\n", ast_sockaddr_stringify(&tmp_dst)); - close(sock); - return -1; - } - - if ((ast_stun_request(sock, &stunaddr, NULL, &answer))) { - close(sock); - return -1; - } - - newaddr = ast_strdupa(ast_inet_ntoa(answer.sin_addr)); - memcpy(externip, newaddr, sizeof(externip)); - - close(sock); - return 0; - -} - -static int gtalk_update_stun(struct gtalk *client, struct gtalk_pvt *p) -{ - struct gtalk_candidate *tmp; - struct hostent *hp; - struct ast_hostent ahp; - struct sockaddr_in sin = { 0, }; - struct sockaddr_in aux = { 0, }; - struct ast_sockaddr sin_tmp; - struct ast_sockaddr aux_tmp; - - if (time(NULL) == p->laststun) - return 0; - - tmp = p->theircandidates; - p->laststun = time(NULL); - while (tmp) { - char username[256]; - - /* Find the IP address of the host */ - if (!(hp = ast_gethostbyname(tmp->ip, &ahp))) { - ast_log(LOG_WARNING, "Could not get host by name for %s\n", tmp->ip); - tmp = tmp->next; - continue; - } - sin.sin_family = AF_INET; - memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr)); - sin.sin_port = htons(tmp->port); - snprintf(username, sizeof(username), "%s%s", tmp->username, p->ourcandidates->username); - - /* Find out the result of the STUN */ - ast_rtp_instance_get_remote_address(p->rtp, &aux_tmp); - ast_sockaddr_to_sin(&aux_tmp, &aux); - - /* If the STUN result is different from the IP of the hostname, - * lock on the stun IP of the hostname advertised by the - * remote client */ - if (aux.sin_addr.s_addr && (aux.sin_addr.s_addr != sin.sin_addr.s_addr)) { - ast_rtp_instance_stun_request(p->rtp, &aux_tmp, username); - } else { - ast_sockaddr_from_sin(&sin_tmp, &sin); - ast_rtp_instance_stun_request(p->rtp, &sin_tmp, username); - } - if (aux.sin_addr.s_addr) { - ast_debug(4, "Receiving RTP traffic from IP %s, matches with remote candidate's IP %s\n", ast_inet_ntoa(aux.sin_addr), tmp->ip); - ast_debug(4, "Sending STUN request to %s\n", tmp->ip); - } - - tmp = tmp->next; - } - return 1; -} - -static int gtalk_add_candidate(struct gtalk *client, ikspak *pak) -{ - struct gtalk_pvt *p = NULL, *tmp = NULL; - struct aji_client *c = client->connection; - struct gtalk_candidate *newcandidate = NULL; - iks *traversenodes = NULL, *receipt = NULL; - char *from; - - from = iks_find_attrib(pak->x,"to"); - if (!from) { - from = c->jid->full; - } - - for (tmp = client->p; tmp; tmp = tmp->next) { - if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) || - (iks_find_attrib(pak->query, "id") && !strcmp(iks_find_attrib(pak->query, "id"), tmp->sid))) { - p = tmp; - break; - } - } - - if (!p) { - return -1; - } - traversenodes = pak->query; - while(traversenodes) { - if(!strcasecmp(S_OR(iks_name(traversenodes), ""), "session")) { - traversenodes = iks_first_tag(traversenodes); - continue; - } - if(!strcasecmp(S_OR(iks_name(traversenodes), ""), "ses:session")) { - traversenodes = iks_child(traversenodes); - continue; - } - if(!strcasecmp(S_OR(iks_name(traversenodes), ""), "candidate") || !strcasecmp(S_OR(iks_name(traversenodes), ""), "ses:candidate")) { - newcandidate = ast_calloc(1, sizeof(*newcandidate)); - if (!newcandidate) - return 0; - ast_copy_string(newcandidate->name, - S_OR(iks_find_attrib(traversenodes, "name"), ""), - sizeof(newcandidate->name)); - ast_copy_string(newcandidate->ip, - S_OR(iks_find_attrib(traversenodes, "address"), ""), - sizeof(newcandidate->ip)); - newcandidate->port = atoi(iks_find_attrib(traversenodes, "port")); - ast_copy_string(newcandidate->username, - S_OR(iks_find_attrib(traversenodes, "username"), ""), - sizeof(newcandidate->username)); - ast_copy_string(newcandidate->password, - S_OR(iks_find_attrib(traversenodes, "password"), ""), - sizeof(newcandidate->password)); - newcandidate->preference = atof(iks_find_attrib(traversenodes, "preference")); - if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "protocol"), ""), "udp")) - newcandidate->protocol = AJI_PROTOCOL_UDP; - if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "protocol"), ""), "ssltcp")) - newcandidate->protocol = AJI_PROTOCOL_SSLTCP; - - if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "type"), ""), "stun")) - newcandidate->type = AJI_CONNECT_STUN; - if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "type"), ""), "local")) - newcandidate->type = AJI_CONNECT_LOCAL; - if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "type"), ""), "relay")) - newcandidate->type = AJI_CONNECT_RELAY; - ast_copy_string(newcandidate->network, - S_OR(iks_find_attrib(traversenodes, "network"), ""), - sizeof(newcandidate->network)); - newcandidate->generation = atoi(S_OR(iks_find_attrib(traversenodes, "generation"), "0")); - newcandidate->next = NULL; - - newcandidate->next = p->theircandidates; - p->theircandidates = newcandidate; - p->laststun = 0; - gtalk_update_stun(p->parent, p); - newcandidate = NULL; - } - traversenodes = iks_next_tag(traversenodes); - } - - receipt = iks_new("iq"); - iks_insert_attrib(receipt, "type", "result"); - iks_insert_attrib(receipt, "from", from); - iks_insert_attrib(receipt, "to", S_OR(iks_find_attrib(pak->x, "from"), "")); - iks_insert_attrib(receipt, "id", S_OR(iks_find_attrib(pak->x, "id"), "")); - ast_aji_send(c, receipt); - - iks_delete(receipt); - - return 1; -} - -static struct ast_frame *gtalk_rtp_read(struct ast_channel *ast, struct gtalk_pvt *p) -{ - struct ast_frame *f; - - if (!p->rtp) { - return &ast_null_frame; - } - f = ast_rtp_instance_read(p->rtp, 0); - gtalk_update_stun(p->parent, p); - if (p->owner) { - /* We already hold the channel lock */ - if (f->frametype == AST_FRAME_VOICE) { - if (!ast_format_cap_iscompatible(ast_channel_nativeformats(p->owner), &f->subclass.format)) { - ast_debug(1, "Oooh, format changed to %s\n", ast_getformatname(&f->subclass.format)); - ast_format_cap_remove_bytype(ast_channel_nativeformats(p->owner), AST_FORMAT_TYPE_AUDIO); - ast_format_cap_add(ast_channel_nativeformats(p->owner), &f->subclass.format); - ast_set_read_format(p->owner, ast_channel_readformat(p->owner)); - ast_set_write_format(p->owner, ast_channel_writeformat(p->owner)); - } - /* if ((ast_test_flag(p, SIP_DTMF) == SIP_DTMF_INBAND) && p->vad) { - f = ast_dsp_process(p->owner, p->vad, f); - if (option_debug && f && (f->frametype == AST_FRAME_DTMF)) - ast_debug(1, "* Detected inband DTMF '%c'\n", f->subclass); - } */ - } - } - return f; -} - -static struct ast_frame *gtalk_read(struct ast_channel *ast) -{ - struct ast_frame *fr; - struct gtalk_pvt *p = ast_channel_tech_pvt(ast); - - ast_mutex_lock(&p->lock); - fr = gtalk_rtp_read(ast, p); - ast_mutex_unlock(&p->lock); - return fr; -} - -/*! \brief Send frame to media channel (rtp) */ -static int gtalk_write(struct ast_channel *ast, struct ast_frame *frame) -{ - struct gtalk_pvt *p = ast_channel_tech_pvt(ast); - int res = 0; - char buf[256]; - - switch (frame->frametype) { - case AST_FRAME_VOICE: - if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &frame->subclass.format))) { - ast_log(LOG_WARNING, - "Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n", - ast_getformatname(&frame->subclass.format), - ast_getformatname_multiple(buf, sizeof(buf), ast_channel_nativeformats(ast)), - ast_getformatname(ast_channel_readformat(ast)), - ast_getformatname(ast_channel_writeformat(ast))); - return 0; - } - if (p) { - ast_mutex_lock(&p->lock); - if (p->rtp) { - res = ast_rtp_instance_write(p->rtp, frame); - } - ast_mutex_unlock(&p->lock); - } - break; - case AST_FRAME_VIDEO: - if (p) { - ast_mutex_lock(&p->lock); - if (p->vrtp) { - res = ast_rtp_instance_write(p->vrtp, frame); - } - ast_mutex_unlock(&p->lock); - } - break; - case AST_FRAME_IMAGE: - return 0; - break; - default: - ast_log(LOG_WARNING, "Can't send %u type frames with Gtalk write\n", - frame->frametype); - return 0; - } - - return res; -} - -static int gtalk_fixup(struct ast_channel *oldchan, struct ast_channel *newchan) -{ - struct gtalk_pvt *p = ast_channel_tech_pvt(newchan); - ast_mutex_lock(&p->lock); - - if ((p->owner != oldchan)) { - ast_mutex_unlock(&p->lock); - return -1; - } - if (p->owner == oldchan) { - gtalk_set_owner(p, newchan); - } - ast_mutex_unlock(&p->lock); - return 0; -} - -static int gtalk_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen) -{ - int res = 0; - - switch (condition) { - case AST_CONTROL_HOLD: - ast_moh_start(ast, data, NULL); - break; - case AST_CONTROL_UNHOLD: - ast_moh_stop(ast); - break; - default: - ast_debug(3, "Don't know how to indicate condition '%d'\n", condition); - /* fallthrough */ - case AST_CONTROL_PVT_CAUSE_CODE: - res = -1; - } - - return res; -} - -static int gtalk_sendtext(struct ast_channel *chan, const char *text) -{ - int res = 0; - struct aji_client *client = NULL; - struct gtalk_pvt *p = ast_channel_tech_pvt(chan); - - if (!p->parent) { - ast_log(LOG_ERROR, "Parent channel not found\n"); - return -1; - } - if (!p->parent->connection) { - ast_log(LOG_ERROR, "XMPP client not found\n"); - return -1; - } - client = p->parent->connection; - res = ast_aji_send_chat(client, p->them, text); - return res; -} - -static int gtalk_digit_begin(struct ast_channel *chan, char digit) -{ - struct gtalk_pvt *p = ast_channel_tech_pvt(chan); - int res = 0; - - ast_mutex_lock(&p->lock); - if (p->rtp) { - ast_rtp_instance_dtmf_begin(p->rtp, digit); - } else { - res = -1; - } - ast_mutex_unlock(&p->lock); - - return res; -} - -static int gtalk_digit_end(struct ast_channel *chan, char digit, unsigned int duration) -{ - struct gtalk_pvt *p = ast_channel_tech_pvt(chan); - int res = 0; - - ast_mutex_lock(&p->lock); - if (p->rtp) { - ast_rtp_instance_dtmf_end_with_duration(p->rtp, digit, duration); - } else { - res = -1; - } - ast_mutex_unlock(&p->lock); - - return res; -} - -/* This function is of not in use at the moment, but I am choosing to leave this - * within the code base as a reference to how DTMF is possible through - * jingle signaling. However, google currently does DTMF through the RTP. */ -#if 0 -static int gtalk_digit(struct ast_channel *ast, char digit, unsigned int duration) -{ - struct gtalk_pvt *p = ast->tech_pvt; - struct gtalk *client = p->parent; - iks *iq, *gtalk, *dtmf; - char buffer[2] = {digit, '\0'}; - char *lowerthem = NULL; - iq = iks_new("iq"); - gtalk = iks_new("gtalk"); - dtmf = iks_new("dtmf"); - if(!iq || !gtalk || !dtmf) { - iks_delete(iq); - iks_delete(gtalk); - iks_delete(dtmf); - ast_log(LOG_ERROR, "Did not send dtmf do to memory issue\n"); - return -1; - } - - iks_insert_attrib(iq, "type", "set"); - iks_insert_attrib(iq, "to", p->them); - iks_insert_attrib(iq, "from", p->us); - iks_insert_attrib(iq, "id", client->connection->mid); - ast_aji_increment_mid(client->connection->mid); - iks_insert_attrib(gtalk, "xmlns", "http://jabber.org/protocol/gtalk"); - iks_insert_attrib(gtalk, "action", "session-info"); - // put the initiator attribute to lower case if we receive the call - // otherwise GoogleTalk won't establish the session - if (!p->initiator) { - char c; - char *t = lowerthem = ast_strdupa(p->them); - while (((c = *t) != '/') && (*t++ = tolower(c))); - } - iks_insert_attrib(gtalk, "initiator", p->initiator ? p->us: lowerthem); - iks_insert_attrib(gtalk, "sid", p->sid); - iks_insert_attrib(dtmf, "xmlns", "http://jabber.org/protocol/gtalk/info/dtmf"); - iks_insert_attrib(dtmf, "code", buffer); - iks_insert_node(iq, gtalk); - iks_insert_node(gtalk, dtmf); - - ast_mutex_lock(&p->lock); - if (ast->dtmff.frametype == AST_FRAME_DTMF_BEGIN || duration == 0) { - iks_insert_attrib(dtmf, "action", "button-down"); - } else if (ast->dtmff.frametype == AST_FRAME_DTMF_END || duration != 0) { - iks_insert_attrib(dtmf, "action", "button-up"); - } - ast_aji_send(client->connection, iq); - - iks_delete(iq); - iks_delete(gtalk); - iks_delete(dtmf); - ast_mutex_unlock(&p->lock); - return 0; -} -#endif - -static int gtalk_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen) -{ - ast_log(LOG_NOTICE, "XXX Implement gtalk sendhtml XXX\n"); - - return -1; -} - -/*!\brief Initiate new call, part of PBX interface - * dest is the dial string */ -static int gtalk_call(struct ast_channel *ast, const char *dest, int timeout) -{ - struct gtalk_pvt *p = ast_channel_tech_pvt(ast); - - if ((ast_channel_state(ast) != AST_STATE_DOWN) && (ast_channel_state(ast) != AST_STATE_RESERVED)) { - ast_log(LOG_WARNING, "gtalk_call called on %s, neither down nor reserved\n", ast_channel_name(ast)); - return -1; - } - - ast_setstate(ast, AST_STATE_RING); - if (!p->ringrule) { - ast_copy_string(p->ring, p->parent->connection->mid, sizeof(p->ring)); - p->ringrule = iks_filter_add_rule(p->parent->connection->f, gtalk_ringing_ack, p, - IKS_RULE_ID, p->ring, IKS_RULE_DONE); - } else { - ast_log(LOG_WARNING, "Whoa, already have a ring rule!\n"); - } - - gtalk_invite(p, p->them, p->us, p->sid, 1); - - return 0; -} - -/*! \brief Hangup a call through the gtalk proxy channel */ -static int gtalk_hangup(struct ast_channel *ast) -{ - struct gtalk_pvt *p = ast_channel_tech_pvt(ast); - struct gtalk *client; - - ast_mutex_lock(&p->lock); - client = p->parent; - gtalk_set_owner(p, NULL); - ast_channel_tech_pvt_set(ast, NULL); - if (!p->alreadygone) { - gtalk_action(client, p, "terminate"); - } - ast_mutex_unlock(&p->lock); - - gtalk_free_pvt(client, p); - ast_module_unref(ast_module_info->self); - - return 0; -} - -/*!\brief Part of PBX interface */ -static struct ast_channel *gtalk_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause) -{ - struct gtalk_pvt *p = NULL; - struct gtalk *client = NULL; - char *sender = NULL, *to = NULL, *s = NULL; - struct ast_channel *chan = NULL; - - if (data) { - s = ast_strdupa(data); - sender = strsep(&s, "/"); - if (sender && (sender[0] != '\0')) { - to = strsep(&s, "/"); - } - if (!to) { - ast_log(LOG_ERROR, "Bad arguments in Gtalk Dialstring: %s\n", data); - return NULL; - } - if (!to) { - ast_log(LOG_ERROR, "Bad arguments in Gtalk Dialstring: %s\n", (char*) data); - return NULL; - } - } - - client = find_gtalk(to, sender); - if (!client) { - ast_log(LOG_WARNING, "Could not find recipient.\n"); - return NULL; - } - if (!strcasecmp(client->name, "guest")){ - /* the guest account is not tied to any configured XMPP client, - let's set it now */ - if (client->connection) { - ASTOBJ_UNREF(client->connection, ast_aji_client_destroy); - } - client->connection = ast_aji_get_client(sender); - if (!client->connection) { - ast_log(LOG_ERROR, "No XMPP client to talk to, us (partial JID) : %s\n", sender); - ASTOBJ_UNREF(client, gtalk_member_destroy); - return NULL; - } - } - - ASTOBJ_WRLOCK(client); - p = gtalk_alloc(client, strchr(sender, '@') ? sender : client->connection->jid->full, strchr(to, '@') ? to : client->user, NULL); - if (p) { - chan = gtalk_new(client, p, AST_STATE_DOWN, to, assignedids, requestor); - } - ASTOBJ_UNLOCK(client); - return chan; -} - -/*! \brief CLI command "gtalk show channels" */ -static char *gtalk_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) -{ -#define FORMAT "%-30.30s %-30.30s %-15.15s %-5.5s %-5.5s \n" - struct gtalk_pvt *p; - struct ast_channel *chan; - int numchans = 0; - char them[AJI_MAX_JIDLEN]; - char *jid = NULL; - char *resource = NULL; - - switch (cmd) { - case CLI_INIT: - e->command = "gtalk show channels"; - e->usage = - "Usage: gtalk show channels\n" - " Shows current state of the Gtalk channels.\n"; - return NULL; - case CLI_GENERATE: - return NULL; - } - - if (a->argc != 3) - return CLI_SHOWUSAGE; - - ast_mutex_lock(>alklock); - ast_cli(a->fd, FORMAT, "Channel", "Jabber ID", "Resource", "Read", "Write"); - ASTOBJ_CONTAINER_TRAVERSE(>alk_list, 1, { - ASTOBJ_WRLOCK(iterator); - p = iterator->p; - while(p) { - chan = p->owner; - ast_copy_string(them, p->them, sizeof(them)); - jid = them; - resource = strchr(them, '/'); - if (!resource) - resource = "None"; - else { - *resource = '\0'; - resource ++; - } - if (chan) - ast_cli(a->fd, FORMAT, - ast_channel_name(chan), - jid, - resource, - ast_getformatname(ast_channel_readformat(chan)), - ast_getformatname(ast_channel_writeformat(chan)) - ); - else - ast_log(LOG_WARNING, "No available channel\n"); - numchans ++; - p = p->next; - } - ASTOBJ_UNLOCK(iterator); - }); - - ast_mutex_unlock(>alklock); - - ast_cli(a->fd, "%d active gtalk channel%s\n", numchans, (numchans != 1) ? "s" : ""); - return CLI_SUCCESS; -#undef FORMAT -} - -/*! \brief List global settings for the GoogleTalk channel */ -static char *gtalk_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) -{ - char codec_buf[BUFSIZ]; - switch (cmd) { - case CLI_INIT: - e->command = "gtalk show settings"; - e->usage = - "Usage: gtalk show settings\n" - " Provides detailed list of the configuration on the GoogleTalk channel.\n"; - return NULL; - case CLI_GENERATE: - return NULL; - } - - if (a->argc != 3) { - return CLI_SHOWUSAGE; - } - -#define FORMAT " %-25.20s %-15.30s\n" - - ast_cli(a->fd, "\nGlobal Settings:\n"); - ast_cli(a->fd, "----------------\n"); - ast_cli(a->fd, FORMAT, "UDP Bindaddress:", ast_inet_ntoa(bindaddr.sin_addr)); - ast_cli(a->fd, FORMAT, "Stun Address:", global_stunaddr != 0 ? ast_inet_ntoa(stunaddr.sin_addr) : "Disabled"); - ast_cli(a->fd, FORMAT, "External IP:", S_OR(externip, "Disabled")); - ast_cli(a->fd, FORMAT, "Context:", global_context); - ast_cli(a->fd, FORMAT, "Codecs:", ast_getformatname_multiple(codec_buf, sizeof(codec_buf) - 1, global_capability)); - ast_cli(a->fd, FORMAT, "Parking Lot:", global_parkinglot); - ast_cli(a->fd, FORMAT, "Allow Guest:", AST_CLI_YESNO(global_allowguest)); - ast_cli(a->fd, "\n----\n"); - - return CLI_SUCCESS; -#undef FORMAT -} - -/*! \brief CLI command "gtalk reload" - * \todo XXX TODO make this work. */ -#if 0 -static char *gtalk_do_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) -{ - switch (cmd) { - case CLI_INIT: - e->command = "gtalk reload"; - e->usage = - "Usage: gtalk reload\n" - " Reload gtalk channel driver.\n"; - return NULL; - case CLI_GENERATE: - return NULL; - } - - ast_verbose("IT DOES WORK!\n"); - return CLI_SUCCESS; -} -#endif - -static int gtalk_parser(void *data, ikspak *pak) -{ - struct gtalk *client = ASTOBJ_REF((struct gtalk *) data); - int res; - iks *tmp; - - if (!strcasecmp(iks_name(pak->query), "jin:jingle") && (tmp = iks_next(pak->query)) && !strcasecmp(iks_name(tmp), "ses:session")) { - ast_debug(1, "New method detected. Skipping jingle offer and using old gtalk method.\n"); - pak->query = tmp; - } - - if (!strcmp(S_OR(iks_find_attrib(pak->x, "type"), ""), "error")) { - ast_log(LOG_NOTICE, "Remote peer reported an error, trying to establish the call anyway\n"); - } - - if (ast_strlen_zero(iks_find_attrib(pak->query, "type"))) { - ast_log(LOG_NOTICE, "No attribute \"type\" found. Ignoring message.\n"); - } else if (!strcmp(iks_find_attrib(pak->query, "type"), "initiate")) { - /* New call */ - gtalk_newcall(client, pak); - } else if (!strcmp(iks_find_attrib(pak->query, "type"), "candidates") || !strcmp(iks_find_attrib(pak->query, "type"), "transport-info")) { - ast_debug(3, "About to add candidate!\n"); - res = gtalk_add_candidate(client, pak); - if (!res) { - ast_log(LOG_WARNING, "Could not add any candidate\n"); - } else { - ast_debug(3, "Candidate Added!\n"); - } - } else if (!strcmp(iks_find_attrib(pak->query, "type"), "accept")) { - gtalk_is_answered(client, pak); - } else if (!strcmp(iks_find_attrib(pak->query, "type"), "transport-accept")) { - gtalk_is_accepted(client, pak); - } else if (!strcmp(iks_find_attrib(pak->query, "type"), "content-info") || iks_find_with_attrib(pak->x, "gtalk", "action", "session-info")) { - gtalk_handle_dtmf(client, pak); - } else if (!strcmp(iks_find_attrib(pak->query, "type"), "terminate")) { - gtalk_hangup_farend(client, pak); - } else if (!strcmp(iks_find_attrib(pak->query, "type"), "reject")) { - gtalk_hangup_farend(client, pak); - } - ASTOBJ_UNREF(client, gtalk_member_destroy); - return IKS_FILTER_EAT; -} - -static int gtalk_create_member(char *label, struct ast_variable *var, int allowguest, - struct ast_codec_pref prefs, char *context, - struct gtalk *member) -{ - struct aji_client *client; - - if (!member) - ast_log(LOG_WARNING, "Out of memory.\n"); - - ast_copy_string(member->name, label, sizeof(member->name)); - ast_copy_string(member->user, label, sizeof(member->user)); - ast_copy_string(member->context, context, sizeof(member->context)); - member->allowguest = allowguest; - member->prefs = prefs; - while (var) { - if (!strcasecmp(var->name, "username")) - ast_copy_string(member->user, var->value, sizeof(member->user)); - else if (!strcasecmp(var->name, "disallow")) - ast_parse_allow_disallow(&member->prefs, member->cap, var->value, 0); - else if (!strcasecmp(var->name, "allow")) - ast_parse_allow_disallow(&member->prefs, member->cap, var->value, 1); - else if (!strcasecmp(var->name, "context")) - ast_copy_string(member->context, var->value, sizeof(member->context)); - else if (!strcasecmp(var->name, "parkinglot")) - ast_copy_string(member->parkinglot, var->value, sizeof(member->parkinglot)); - else if (!strcasecmp(var->name, "connection")) { - if ((client = ast_aji_get_client(var->value))) { - member->connection = client; - iks_filter_add_rule(client->f, gtalk_parser, member, - IKS_RULE_TYPE, IKS_PAK_IQ, - IKS_RULE_FROM_PARTIAL, member->user, - IKS_RULE_NS, GOOGLE_NS, - IKS_RULE_DONE); - } else { - ast_log(LOG_ERROR, "connection referenced not found!\n"); - return 0; - } - } - var = var->next; - } - if (member->connection && member->user) - member->buddy = ASTOBJ_CONTAINER_FIND(&member->connection->buddies, member->user); - else { - ast_log(LOG_ERROR, "No Connection or Username!\n"); - } - return 1; -} - -static int gtalk_load_config(void) -{ - char *cat = NULL; - struct ast_config *cfg = NULL; - struct ast_variable *var; - struct gtalk *member; - struct ast_codec_pref prefs; - struct aji_client_container *clients; - struct gtalk_candidate *global_candidates = NULL; - struct hostent *hp; - struct ast_hostent ahp; - struct ast_flags config_flags = { 0 }; - - cfg = ast_config_load(GOOGLE_CONFIG, config_flags); - if (!cfg) { - return 0; - } else if (cfg == CONFIG_STATUS_FILEINVALID) { - ast_log(LOG_ERROR, "Config file %s is in an invalid format. Aborting.\n", GOOGLE_CONFIG); - return 0; - } - - /* Copy the default jb config over global_jbconf */ - memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf)); - - /* set defaults */ - memset(&prefs, 0, sizeof(prefs)); - memset(&stunaddr, 0, sizeof(stunaddr)); - global_stunaddr = 0; - global_allowguest = DEFAULT_ALLOWGUEST; - ast_copy_string(global_context, DEFAULT_CONTEXT, sizeof(global_context)); - ast_copy_string(global_parkinglot, DEFAULT_PARKINGLOT, sizeof(global_parkinglot)); - - cat = ast_category_browse(cfg, NULL); - for (var = ast_variable_browse(cfg, "general"); var; var = var->next) { - /* handle jb conf */ - if (!ast_jb_read_conf(&global_jbconf, var->name, var->value)) { - continue; - } - - if (!strcasecmp(var->name, "allowguest")) { - global_allowguest = (ast_true(ast_variable_retrieve(cfg, "general", "allowguest"))) ? 1 : 0; - } else if (!strcasecmp(var->name, "disallow")) { - ast_parse_allow_disallow(&prefs, global_capability, var->value, 0); - } else if (!strcasecmp(var->name, "allow")) { - ast_parse_allow_disallow(&prefs, global_capability, var->value, 1); - } else if (!strcasecmp(var->name, "context")) { - ast_copy_string(global_context, var->value, sizeof(global_context)); - } else if (!strcasecmp(var->name, "externip")) { - ast_copy_string(externip, var->value, sizeof(externip)); - } else if (!strcasecmp(var->name, "parkinglot")) { - ast_copy_string(global_parkinglot, var->value, sizeof(global_parkinglot)); - } else if (!strcasecmp(var->name, "bindaddr")) { - if (!(hp = ast_gethostbyname(var->value, &ahp))) { - ast_log(LOG_WARNING, "Invalid address: %s\n", var->value); - } else { - memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr)); - } - } else if (!strcasecmp(var->name, "stunaddr")) { - stunaddr.sin_port = htons(STANDARD_STUN_PORT); - global_stunaddr = 1; - if (ast_parse_arg(var->value, PARSE_INADDR, &stunaddr)) { - ast_log(LOG_WARNING, "Invalid STUN server address: %s\n", var->value); - } - } - } - while (cat) { - if (strcasecmp(cat, "general")) { - var = ast_variable_browse(cfg, cat); - member = ast_calloc(1, sizeof(*member)); - ASTOBJ_INIT(member); - ASTOBJ_WRLOCK(member); - member->cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); - if (!strcasecmp(cat, "guest")) { - ast_copy_string(member->name, "guest", sizeof(member->name)); - ast_copy_string(member->user, "guest", sizeof(member->user)); - ast_copy_string(member->context, global_context, sizeof(member->context)); - ast_copy_string(member->parkinglot, global_parkinglot, sizeof(member->parkinglot)); - member->allowguest = global_allowguest; - member->prefs = prefs; - while (var) { - if (!strcasecmp(var->name, "disallow")) { - ast_parse_allow_disallow(&member->prefs, member->cap, - var->value, 0); - } else if (!strcasecmp(var->name, "allow")) { - ast_parse_allow_disallow(&member->prefs, member->cap, - var->value, 1); - } else if (!strcasecmp(var->name, "context")) { - ast_copy_string(member->context, var->value, - sizeof(member->context)); - } else if (!strcasecmp(var->name, "parkinglot")) { - ast_copy_string(member->parkinglot, var->value, - sizeof(member->parkinglot)); - } - var = var->next; - } - ASTOBJ_UNLOCK(member); - clients = ast_aji_get_clients(); - if (clients) { - ASTOBJ_CONTAINER_TRAVERSE(clients, 1, { - ASTOBJ_WRLOCK(iterator); - ASTOBJ_WRLOCK(member); - if (member->connection) { - ASTOBJ_UNREF(member->connection, ast_aji_client_destroy); - } - member->connection = NULL; - iks_filter_add_rule(iterator->f, gtalk_parser, member, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS, GOOGLE_NS, IKS_RULE_DONE); - iks_filter_add_rule(iterator->f, gtalk_parser, member, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS, GOOGLE_JINGLE_NS, IKS_RULE_DONE); - iks_filter_add_rule(iterator->f, gtalk_parser, member, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS, "http://jabber.org/protocol/gtalk", IKS_RULE_DONE); - ASTOBJ_UNLOCK(member); - ASTOBJ_UNLOCK(iterator); - }); - ASTOBJ_CONTAINER_LINK(>alk_list, member); - ASTOBJ_UNREF(member, gtalk_member_destroy); - } else { - ASTOBJ_UNLOCK(member); - ASTOBJ_UNREF(member, gtalk_member_destroy); - } - } else { - ASTOBJ_UNLOCK(member); - if (gtalk_create_member(cat, var, global_allowguest, prefs, global_context, member)) { - ASTOBJ_CONTAINER_LINK(>alk_list, member); - } - ASTOBJ_UNREF(member, gtalk_member_destroy); - } - } - cat = ast_category_browse(cfg, cat); - } - - ast_config_destroy(cfg); - gtalk_update_externip(); - gtalk_free_candidates(global_candidates); - return 1; -} - -/*! - * \brief Load the module - * - * Module loading including tests for configuration or dependencies. - * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE, - * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails - * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the - * configuration file or other non-critical problem return - * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS. - */ -static int load_module(void) -{ - struct ast_sockaddr bindaddr_tmp; - struct ast_sockaddr ourip_tmp; - char *jabber_loaded = ast_module_helper("", "res_jabber.so", 0, 0, 0, 0); - struct ast_format tmpfmt; - - if (!(gtalk_tech.capabilities = ast_format_cap_alloc(0))) { - return AST_MODULE_LOAD_DECLINE; - } - if (!(global_capability = ast_format_cap_alloc(0))) { - return AST_MODULE_LOAD_DECLINE; - } - - ast_format_cap_add_all_by_type(gtalk_tech.capabilities, AST_FORMAT_TYPE_AUDIO); - ast_format_cap_add(global_capability, ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0)); - ast_format_cap_add(global_capability, ast_format_set(&tmpfmt, AST_FORMAT_GSM, 0)); - ast_format_cap_add(global_capability, ast_format_set(&tmpfmt, AST_FORMAT_ALAW, 0)); - ast_format_cap_add(global_capability, ast_format_set(&tmpfmt, AST_FORMAT_H263, 0)); - - free(jabber_loaded); - if (!jabber_loaded) { - /* If embedded, check for a different module name */ - jabber_loaded = ast_module_helper("", "res_jabber", 0, 0, 0, 0); - free(jabber_loaded); - if (!jabber_loaded) { - ast_log(LOG_ERROR, "chan_gtalk.so depends upon res_jabber.so\n"); - return AST_MODULE_LOAD_DECLINE; - } - } - - ASTOBJ_CONTAINER_INIT(>alk_list); - if (!gtalk_load_config()) { - ast_log(LOG_ERROR, "Unable to read config file %s. Not loading module.\n", GOOGLE_CONFIG); - return 0; - } - - sched = ast_sched_context_create(); - if (!sched) { - ast_log(LOG_WARNING, "Unable to create schedule context\n"); - } - - io = io_context_create(); - if (!io) { - ast_log(LOG_WARNING, "Unable to create I/O context\n"); - } - - ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr); - if (gtalk_get_local_ip(&ourip_tmp)) { - ast_log(LOG_WARNING, "Unable to get own IP address, Gtalk disabled\n"); - return 0; - } - __ourip.s_addr = htonl(ast_sockaddr_ipv4(&ourip_tmp)); - - ast_rtp_glue_register(>alk_rtp_glue); - ast_cli_register_multiple(gtalk_cli, ARRAY_LEN(gtalk_cli)); - - /* Make sure we can register our channel type */ - if (ast_channel_register(>alk_tech)) { - ast_log(LOG_ERROR, "Unable to register channel class %s\n", gtalk_tech.type); - return -1; - } - return 0; -} - -/*! \brief Reload module - * \todo XXX TODO make this work. */ -#if 0 -static int reload(void) -{ - return 0; -} -#endif -/*! \brief Unload the gtalk channel from Asterisk */ -static int unload_module(void) -{ - struct gtalk_pvt *privates = NULL; - ast_cli_unregister_multiple(gtalk_cli, ARRAY_LEN(gtalk_cli)); - /* First, take us out of the channel loop */ - ast_channel_unregister(>alk_tech); - ast_rtp_glue_unregister(>alk_rtp_glue); - - if (!ast_mutex_lock(>alklock)) { - /* Hangup all interfaces if they have an owner */ - ASTOBJ_CONTAINER_TRAVERSE(>alk_list, 1, { - ASTOBJ_WRLOCK(iterator); - privates = iterator->p; - while(privates) { - if (privates->owner) - ast_softhangup(privates->owner, AST_SOFTHANGUP_APPUNLOAD); - privates = privates->next; - } - iterator->p = NULL; - ASTOBJ_UNLOCK(iterator); - }); - ast_mutex_unlock(>alklock); - } else { - ast_log(LOG_WARNING, "Unable to lock the monitor\n"); - return -1; - } - ASTOBJ_CONTAINER_DESTROYALL(>alk_list, gtalk_member_destroy); - ASTOBJ_CONTAINER_DESTROY(>alk_list); - global_capability = ast_format_cap_destroy(global_capability); - gtalk_tech.capabilities = ast_format_cap_destroy(gtalk_tech.capabilities); - return 0; -} - -AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Gtalk Channel Driver", - .load = load_module, - .unload = unload_module, - /* .reload = reload, */ - .load_pri = AST_MODPRI_CHANNEL_DRIVER, - ); diff --git a/channels/chan_h323.c b/channels/chan_h323.c deleted file mode 100644 index 2101d2378ff..00000000000 --- a/channels/chan_h323.c +++ /dev/null @@ -1,3532 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 1999 - 2005 - * - * OpenH323 Channel Driver for ASTERISK PBX. - * By Jeremy McNamara - * For The NuFone Network - * - * chan_h323 has been derived from code created by - * Michael Manousos and Mark Spencer - * - * 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 This file is part of the chan_h323 driver for Asterisk - * - * \author Jeremy McNamara - * - * \par See also - * \arg Config_h323 - * OpenH323 http://www.voxgratia.org/ - * - * \ingroup channel_drivers - */ - -/*! \li \ref chan_h323.c uses the configuration file \ref h323.conf - * \addtogroup configuration_file - */ - -/*! \page h323.conf h323.conf - * \verbinclude h323.conf.sample - */ - -/*** MODULEINFO - openh323 - no - deprecated - chan_ooh323 - ***/ - -#ifdef __cplusplus -extern "C" { -#endif - -#include "asterisk.h" - -ASTERISK_FILE_VERSION(__FILE__, "$Revision$") - -#ifdef __cplusplus -} -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#include "asterisk/lock.h" -#include "asterisk/channel.h" -#include "asterisk/config.h" -#include "asterisk/module.h" -#include "asterisk/musiconhold.h" -#include "asterisk/pbx.h" -#include "asterisk/utils.h" -#include "asterisk/sched.h" -#include "asterisk/io.h" -#include "asterisk/rtp_engine.h" -#include "asterisk/acl.h" -#include "asterisk/callerid.h" -#include "asterisk/cli.h" -#include "asterisk/dsp.h" -#include "asterisk/causes.h" -#include "asterisk/stringfields.h" -#include "asterisk/abstract_jb.h" -#include "asterisk/astobj.h" -#include "asterisk/format.h" -#include "asterisk/format_cap.h" - -#ifdef __cplusplus -} -#endif - -#undef open -#undef close -#include "h323/chan_h323.h" - -receive_digit_cb on_receive_digit; -on_rtp_cb on_external_rtp_create; -start_rtp_cb on_start_rtp_channel; -setup_incoming_cb on_incoming_call; -setup_outbound_cb on_outgoing_call; -chan_ringing_cb on_chan_ringing; -con_established_cb on_connection_established; -clear_con_cb on_connection_cleared; -answer_call_cb on_answer_call; -progress_cb on_progress; -rfc2833_cb on_set_rfc2833_payload; -hangup_cb on_hangup; -setcapabilities_cb on_setcapabilities; -setpeercapabilities_cb on_setpeercapabilities; -onhold_cb on_hold; - -int h323debug; /*!< global debug flag */ - -/*! \brief Global jitterbuffer configuration - by default, jb is disabled - * \note Values shown here match the defaults shown in h323.conf.sample */ -static struct ast_jb_conf default_jbconf = -{ - .flags = 0, - .max_size = 200, - .resync_threshold = 1000, - .impl = "fixed", - .target_extra = 40, -}; -static struct ast_jb_conf global_jbconf; - -/** Variables required by Asterisk */ -static const char tdesc[] = "The NuFone Network's Open H.323 Channel Driver"; -static const char config[] = "h323.conf"; -static char default_context[AST_MAX_CONTEXT] = "default"; -static struct sockaddr_in bindaddr; - -#define GLOBAL_CAPABILITY (ast_format_id_to_old_bitfield(AST_FORMAT_G723_1) | \ - ast_format_id_to_old_bitfield(AST_FORMAT_GSM) | \ - ast_format_id_to_old_bitfield(AST_FORMAT_ULAW) | \ - ast_format_id_to_old_bitfield(AST_FORMAT_ALAW) | \ - ast_format_id_to_old_bitfield(AST_FORMAT_G729A) | \ - ast_format_id_to_old_bitfield(AST_FORMAT_G726_AAL2) | \ - ast_format_id_to_old_bitfield(AST_FORMAT_H261)) \ - -/** H.323 configuration values */ -static int h323_signalling_port = 1720; -static char gatekeeper[100]; -static int gatekeeper_disable = 1; -static int gatekeeper_discover = 0; -static int gkroute = 0; -/* Find user by alias (h.323 id) is default, alternative is the incoming call's source IP address*/ -static int userbyalias = 1; -static int acceptAnonymous = 1; -static unsigned int tos = 0; -static unsigned int cos = 0; -static char secret[50]; -static unsigned int unique = 0; - -static call_options_t global_options; - -/*! \brief Private structure of a OpenH323 channel */ -static struct oh323_pvt { - ast_mutex_t lock; /*!< Channel private lock */ - call_options_t options; /*!name); - ast_free(alias); -} - -static void oh323_destroy_user(struct oh323_user *user) -{ - if (h323debug) - ast_debug(1, "Destroying user '%s'\n", user->name); - ast_free_ha(user->ha); - ast_free(user); -} - -static void oh323_destroy_peer(struct oh323_peer *peer) -{ - if (h323debug) - ast_debug(1, "Destroying peer '%s'\n", peer->name); - ast_free_ha(peer->ha); - ast_free(peer); -} - -static int oh323_simulate_dtmf_end(const void *data) -{ - struct oh323_pvt *pvt = (struct oh323_pvt *)data; - - if (pvt) { - ast_mutex_lock(&pvt->lock); - /* Don't hold pvt lock while trying to lock the channel */ - while (pvt->owner && ast_channel_trylock(pvt->owner)) { - DEADLOCK_AVOIDANCE(&pvt->lock); - } - - if (pvt->owner) { - struct ast_frame f = { - .frametype = AST_FRAME_DTMF_END, - .subclass.integer = pvt->curDTMF, - .samples = 0, - .src = "SIMULATE_DTMF_END", - }; - ast_queue_frame(pvt->owner, &f); - ast_channel_unlock(pvt->owner); - } - - pvt->DTMFsched = -1; - ast_mutex_unlock(&pvt->lock); - } - - return 0; -} - -/*! \brief Channel and private structures should be already locked */ -static void __oh323_update_info(struct ast_channel *c, struct oh323_pvt *pvt) -{ - h323_format chan_nativeformats_bits = ast_format_cap_to_old_bitfield(ast_channel_nativeformats(c)); - if (chan_nativeformats_bits != pvt->nativeformats) { - if (h323debug) - ast_debug(1, "Preparing %s for new native format\n", ast_channel_name(c)); - ast_format_cap_from_old_bitfield(ast_channel_nativeformats(c), pvt->nativeformats); - ast_set_read_format(c, ast_channel_readformat(c)); - ast_set_write_format(c, ast_channel_writeformat(c)); - } - if (pvt->needhangup) { - if (h323debug) - ast_debug(1, "Process pending hangup for %s\n", ast_channel_name(c)); - ast_channel_softhangup_internal_flag_add(c, AST_SOFTHANGUP_DEV); - ast_channel_hangupcause_set(c, pvt->hangupcause); - ast_queue_hangup_with_cause(c, pvt->hangupcause); - pvt->needhangup = 0; - pvt->newstate = pvt->newcontrol = pvt->newdigit = pvt->DTMFsched = -1; - } - if (pvt->newstate >= 0) { - ast_setstate(c, pvt->newstate); - pvt->newstate = -1; - } - if (pvt->newcontrol >= 0) { - ast_queue_control(c, pvt->newcontrol); - pvt->newcontrol = -1; - } - if (pvt->newdigit >= 0) { - struct ast_frame f = { - .frametype = AST_FRAME_DTMF_END, - .subclass.integer = pvt->newdigit, - .samples = pvt->newduration * 8, - .len = pvt->newduration, - .src = "UPDATE_INFO", - }; - if (pvt->newdigit == ' ') { /* signalUpdate message */ - f.subclass.integer = pvt->curDTMF; - if (pvt->DTMFsched >= 0) { - AST_SCHED_DEL(sched, pvt->DTMFsched); - } - } else { /* Regular input or signal message */ - if (pvt->newduration) { /* This is a signal, signalUpdate follows */ - f.frametype = AST_FRAME_DTMF_BEGIN; - AST_SCHED_DEL(sched, pvt->DTMFsched); - pvt->DTMFsched = ast_sched_add(sched, pvt->newduration, oh323_simulate_dtmf_end, pvt); - if (h323debug) - ast_log(LOG_DTMF, "Scheduled DTMF END simulation for %d ms, id=%d\n", pvt->newduration, pvt->DTMFsched); - } - pvt->curDTMF = pvt->newdigit; - } - ast_queue_frame(c, &f); - pvt->newdigit = -1; - } - if (pvt->update_rtp_info > 0) { - if (pvt->rtp) { - ast_jb_configure(c, &global_jbconf); - ast_channel_set_fd(c, 0, ast_rtp_instance_fd(pvt->rtp, 0)); - ast_channel_set_fd(c, 1, ast_rtp_instance_fd(pvt->rtp, 1)); - ast_queue_frame(pvt->owner, &ast_null_frame); /* Tell Asterisk to apply changes */ - } - pvt->update_rtp_info = -1; - } -} - -/*! \brief Only channel structure should be locked */ -static void oh323_update_info(struct ast_channel *c) -{ - struct oh323_pvt *pvt = ast_channel_tech_pvt(c); - - if (pvt) { - ast_mutex_lock(&pvt->lock); - __oh323_update_info(c, pvt); - ast_mutex_unlock(&pvt->lock); - } -} - -static void cleanup_call_details(call_details_t *cd) -{ - if (cd->call_token) { - ast_free(cd->call_token); - cd->call_token = NULL; - } - if (cd->call_source_aliases) { - ast_free(cd->call_source_aliases); - cd->call_source_aliases = NULL; - } - if (cd->call_dest_alias) { - ast_free(cd->call_dest_alias); - cd->call_dest_alias = NULL; - } - if (cd->call_source_name) { - ast_free(cd->call_source_name); - cd->call_source_name = NULL; - } - if (cd->call_source_e164) { - ast_free(cd->call_source_e164); - cd->call_source_e164 = NULL; - } - if (cd->call_dest_e164) { - ast_free(cd->call_dest_e164); - cd->call_dest_e164 = NULL; - } - if (cd->sourceIp) { - ast_free(cd->sourceIp); - cd->sourceIp = NULL; - } - if (cd->redirect_number) { - ast_free(cd->redirect_number); - cd->redirect_number = NULL; - } -} - -static void __oh323_destroy(struct oh323_pvt *pvt) -{ - struct oh323_pvt *cur, *prev = NULL; - - AST_SCHED_DEL(sched, pvt->DTMFsched); - - if (pvt->rtp) { - ast_rtp_instance_destroy(pvt->rtp); - } - - /* Free dsp used for in-band DTMF detection */ - if (pvt->vad) { - ast_dsp_free(pvt->vad); - } - cleanup_call_details(&pvt->cd); - - /* Unlink us from the owner if we have one */ - if (pvt->owner) { - ast_channel_lock(pvt->owner); - if (h323debug) - ast_debug(1, "Detaching from %s\n", ast_channel_name(pvt->owner)); - ast_channel_tech_pvt_set(pvt->owner, NULL); - ast_channel_unlock(pvt->owner); - } - cur = iflist; - while(cur) { - if (cur == pvt) { - if (prev) - prev->next = cur->next; - else - iflist = cur->next; - break; - } - prev = cur; - cur = cur->next; - } - if (!cur) { - ast_log(LOG_WARNING, "%p is not in list?!?! \n", cur); - } else { - ast_mutex_unlock(&pvt->lock); - ast_mutex_destroy(&pvt->lock); - ast_free(pvt); - } -} - -static void oh323_destroy(struct oh323_pvt *pvt) -{ - if (h323debug) { - ast_debug(1, "Destroying channel %s\n", (pvt->owner ? ast_channel_name(pvt->owner) : "")); - } - ast_mutex_lock(&iflock); - ast_mutex_lock(&pvt->lock); - __oh323_destroy(pvt); - ast_mutex_unlock(&iflock); -} - -static int oh323_digit_begin(struct ast_channel *c, char digit) -{ - struct oh323_pvt *pvt = (struct oh323_pvt *) ast_channel_tech_pvt(c); - char *token; - - if (!pvt) { - ast_log(LOG_ERROR, "No private structure?! This is bad\n"); - return -1; - } - ast_mutex_lock(&pvt->lock); - if (pvt->rtp && - (((pvt->options.dtmfmode & H323_DTMF_RFC2833) && pvt->dtmf_pt[0]) - /*|| ((pvt->options.dtmfmode & H323_DTMF_CISCO) && pvt->dtmf_pt[1]))*/)) { - /* out-of-band DTMF */ - if (h323debug) { - ast_log(LOG_DTMF, "Begin sending out-of-band digit %c on %s\n", digit, ast_channel_name(c)); - } - ast_rtp_instance_dtmf_begin(pvt->rtp, digit); - ast_mutex_unlock(&pvt->lock); - } else if (pvt->txDtmfDigit != digit) { - /* in-band DTMF */ - if (h323debug) { - ast_log(LOG_DTMF, "Begin sending inband digit %c on %s\n", digit, ast_channel_name(c)); - } - pvt->txDtmfDigit = digit; - token = pvt->cd.call_token ? ast_strdup(pvt->cd.call_token) : NULL; - ast_mutex_unlock(&pvt->lock); - h323_send_tone(token, digit); - if (token) { - ast_free(token); - } - } else - ast_mutex_unlock(&pvt->lock); - oh323_update_info(c); - return 0; -} - -/*! \brief - * Send (play) the specified digit to the channel. - * - */ -static int oh323_digit_end(struct ast_channel *c, char digit, unsigned int duration) -{ - struct oh323_pvt *pvt = (struct oh323_pvt *) ast_channel_tech_pvt(c); - char *token; - - if (!pvt) { - ast_log(LOG_ERROR, "No private structure?! This is bad\n"); - return -1; - } - ast_mutex_lock(&pvt->lock); - if (pvt->rtp && (pvt->options.dtmfmode & H323_DTMF_RFC2833) && ((pvt->dtmf_pt[0] > 0) || (pvt->dtmf_pt[0] > 0))) { - /* out-of-band DTMF */ - if (h323debug) { - ast_log(LOG_DTMF, "End sending out-of-band digit %c on %s, duration %d\n", digit, ast_channel_name(c), duration); - } - ast_rtp_instance_dtmf_end(pvt->rtp, digit); - ast_mutex_unlock(&pvt->lock); - } else { - /* in-band DTMF */ - if (h323debug) { - ast_log(LOG_DTMF, "End sending inband digit %c on %s, duration %d\n", digit, ast_channel_name(c), duration); - } - pvt->txDtmfDigit = ' '; - token = pvt->cd.call_token ? ast_strdup(pvt->cd.call_token) : NULL; - ast_mutex_unlock(&pvt->lock); - h323_send_tone(token, ' '); - if (token) { - ast_free(token); - } - } - oh323_update_info(c); - return 0; -} - -/*! \brief - * Make a call over the specified channel to the specified - * destination. - * Returns -1 on error, 0 on success. - */ -static int oh323_call(struct ast_channel *c, const char *dest, int timeout) -{ - int res = 0; - struct oh323_pvt *pvt = (struct oh323_pvt *)ast_channel_tech_pvt(c); - const char *addr; - char called_addr[1024]; - - if (h323debug) { - ast_debug(1, "Calling to %s on %s\n", dest, ast_channel_name(c)); - } - if ((ast_channel_state(c) != AST_STATE_DOWN) && (ast_channel_state(c) != AST_STATE_RESERVED)) { - ast_log(LOG_WARNING, "Line is already in use (%s)\n", ast_channel_name(c)); - return -1; - } - ast_mutex_lock(&pvt->lock); - if (!gatekeeper_disable) { - if (ast_strlen_zero(pvt->exten)) { - ast_copy_string(called_addr, dest, sizeof(called_addr)); - } else { - snprintf(called_addr, sizeof(called_addr), "%s@%s", pvt->exten, dest); - } - } else { - res = htons(pvt->sa.sin_port); - addr = ast_inet_ntoa(pvt->sa.sin_addr); - if (ast_strlen_zero(pvt->exten)) { - snprintf(called_addr, sizeof(called_addr), "%s:%d", addr, res); - } else { - snprintf(called_addr, sizeof(called_addr), "%s@%s:%d", pvt->exten, addr, res); - } - } - /* make sure null terminated */ - called_addr[sizeof(called_addr) - 1] = '\0'; - - if (ast_channel_connected(c)->id.number.valid && ast_channel_connected(c)->id.number.str) { - ast_copy_string(pvt->options.cid_num, ast_channel_connected(c)->id.number.str, sizeof(pvt->options.cid_num)); - } - - if (ast_channel_connected(c)->id.name.valid && ast_channel_connected(c)->id.name.str) { - ast_copy_string(pvt->options.cid_name, ast_channel_connected(c)->id.name.str, sizeof(pvt->options.cid_name)); - } - - if (ast_channel_redirecting(c)->from.number.valid && ast_channel_redirecting(c)->from.number.str) { - ast_copy_string(pvt->options.cid_rdnis, ast_channel_redirecting(c)->from.number.str, sizeof(pvt->options.cid_rdnis)); - } - - pvt->options.presentation = ast_party_id_presentation(&ast_channel_connected(c)->id); - pvt->options.type_of_number = ast_channel_connected(c)->id.number.plan; - - if ((addr = pbx_builtin_getvar_helper(c, "PRIREDIRECTREASON"))) { - if (!strcasecmp(addr, "UNKNOWN")) - pvt->options.redirect_reason = 0; - else if (!strcasecmp(addr, "BUSY")) - pvt->options.redirect_reason = 1; - else if (!strcasecmp(addr, "NO_REPLY")) - pvt->options.redirect_reason = 2; - else if (!strcasecmp(addr, "UNCONDITIONAL")) - pvt->options.redirect_reason = 15; - else - pvt->options.redirect_reason = -1; - } else - pvt->options.redirect_reason = -1; - - pvt->options.transfer_capability = ast_channel_transfercapability(c); - - /* indicate that this is an outgoing call */ - pvt->outgoing = 1; - - ast_verb(3, "Requested transfer capability: 0x%.2x - %s\n", ast_channel_transfercapability(c), ast_transfercapability2str(ast_channel_transfercapability(c))); - if (h323debug) - ast_debug(1, "Placing outgoing call to %s, %d/%d\n", called_addr, pvt->options.dtmfcodec[0], pvt->options.dtmfcodec[1]); - ast_mutex_unlock(&pvt->lock); - res = h323_make_call(called_addr, &(pvt->cd), &pvt->options); - if (res) { - ast_log(LOG_NOTICE, "h323_make_call failed(%s)\n", ast_channel_name(c)); - return -1; - } - oh323_update_info(c); - return 0; -} - -static int oh323_answer(struct ast_channel *c) -{ - int res; - struct oh323_pvt *pvt = (struct oh323_pvt *) ast_channel_tech_pvt(c); - char *token; - - if (h323debug) - ast_debug(1, "Answering on %s\n", ast_channel_name(c)); - - ast_mutex_lock(&pvt->lock); - token = pvt->cd.call_token ? ast_strdup(pvt->cd.call_token) : NULL; - ast_mutex_unlock(&pvt->lock); - res = h323_answering_call(token, 0); - if (token) - ast_free(token); - - oh323_update_info(c); - if (ast_channel_state(c) != AST_STATE_UP) { - ast_setstate(c, AST_STATE_UP); - } - return res; -} - -static int oh323_hangup(struct ast_channel *c) -{ - struct oh323_pvt *pvt = (struct oh323_pvt *) ast_channel_tech_pvt(c); - int q931cause = AST_CAUSE_NORMAL_CLEARING; - char *call_token; - - - if (h323debug) - ast_debug(1, "Hanging up and scheduling destroy of call %s\n", ast_channel_name(c)); - - if (!ast_channel_tech_pvt(c)) { - ast_log(LOG_WARNING, "Asked to hangup channel not connected\n"); - return 0; - } - ast_mutex_lock(&pvt->lock); - /* Determine how to disconnect */ - if (pvt->owner != c) { - ast_log(LOG_WARNING, "Huh? We aren't the owner?\n"); - ast_mutex_unlock(&pvt->lock); - return 0; - } - - oh323_set_owner(pvt, NULL); - ast_channel_tech_pvt_set(c, NULL); - - if (ast_channel_hangupcause(c)) { - q931cause = ast_channel_hangupcause(c); - } else { - const char *cause = pbx_builtin_getvar_helper(c, "DIALSTATUS"); - if (cause) { - if (!strcmp(cause, "CONGESTION")) { - q931cause = AST_CAUSE_NORMAL_CIRCUIT_CONGESTION; - } else if (!strcmp(cause, "BUSY")) { - q931cause = AST_CAUSE_USER_BUSY; - } else if (!strcmp(cause, "CHANISUNVAIL")) { - q931cause = AST_CAUSE_REQUESTED_CHAN_UNAVAIL; - } else if (!strcmp(cause, "NOANSWER")) { - q931cause = AST_CAUSE_NO_ANSWER; - } else if (!strcmp(cause, "CANCEL")) { - q931cause = AST_CAUSE_CALL_REJECTED; - } - } - } - - /* Start the process if it's not already started */ - if (!pvt->alreadygone && !pvt->hangupcause) { - call_token = pvt->cd.call_token ? ast_strdup(pvt->cd.call_token) : NULL; - if (call_token) { - /* Release lock to eliminate deadlock */ - ast_mutex_unlock(&pvt->lock); - if (h323_clear_call(call_token, q931cause)) { - ast_log(LOG_WARNING, "ClearCall failed.\n"); - } - ast_free(call_token); - ast_mutex_lock(&pvt->lock); - } - } - pvt->needdestroy = 1; - ast_mutex_unlock(&pvt->lock); - - /* Update usage counter */ - ast_module_unref(ast_module_info->self); - - return 0; -} - -/*! \brief Retrieve audio/etc from channel. Assumes pvt->lock is already held. */ -static struct ast_frame *oh323_rtp_read(struct oh323_pvt *pvt) -{ - struct ast_frame *f; - - /* Only apply it for the first packet, we just need the correct ip/port */ - if (pvt->options.nat) { - ast_rtp_instance_set_prop(pvt->rtp, AST_RTP_PROPERTY_NAT, pvt->options.nat); - pvt->options.nat = 0; - } - - f = ast_rtp_instance_read(pvt->rtp, 0); - /* Don't send RFC2833 if we're not supposed to */ - if (f && (f->frametype == AST_FRAME_DTMF) && !(pvt->options.dtmfmode & (H323_DTMF_RFC2833 | H323_DTMF_CISCO))) { - return &ast_null_frame; - } - if (f && pvt->owner) { - /* We already hold the channel lock */ - if (f->frametype == AST_FRAME_VOICE) { - if (!ast_format_cap_iscompatible(ast_channel_nativeformats(pvt->owner), &f->subclass.format)) { - /* Try to avoid deadlock */ - if (ast_channel_trylock(pvt->owner)) { - ast_log(LOG_NOTICE, "Format changed but channel is locked. Ignoring frame...\n"); - return &ast_null_frame; - } - if (h323debug) - ast_debug(1, "Oooh, format changed to '%s'\n", ast_getformatname(&f->subclass.format)); - ast_format_cap_set(ast_channel_nativeformats(pvt->owner), &f->subclass.format); - - pvt->nativeformats = ast_format_to_old_bitfield(&f->subclass.format); - - ast_set_read_format(pvt->owner, ast_channel_readformat(pvt->owner)); - ast_set_write_format(pvt->owner,ast_channel_writeformat(pvt->owner)); - ast_channel_unlock(pvt->owner); - } - /* Do in-band DTMF detection */ - if ((pvt->options.dtmfmode & H323_DTMF_INBAND) && pvt->vad) { - if ((pvt->nativeformats & (AST_FORMAT_SLINEAR | AST_FORMAT_ALAW | AST_FORMAT_ULAW))) { - if (!ast_channel_trylock(pvt->owner)) { - f = ast_dsp_process(pvt->owner, pvt->vad, f); - ast_channel_unlock(pvt->owner); - } - else - ast_log(LOG_NOTICE, "Unable to process inband DTMF while channel is locked\n"); - } else if (pvt->nativeformats && !pvt->noInbandDtmf) { - ast_log(LOG_NOTICE, "Inband DTMF is not supported on codec %s. Use RFC2833\n", ast_getformatname(&f->subclass.format)); - pvt->noInbandDtmf = 1; - } - if (f &&(f->frametype == AST_FRAME_DTMF)) { - if (h323debug) - ast_log(LOG_DTMF, "Received in-band digit %c.\n", f->subclass.integer); - } - } - } - } - return f; -} - -static struct ast_frame *oh323_read(struct ast_channel *c) -{ - struct ast_frame *fr; - struct oh323_pvt *pvt = (struct oh323_pvt *)ast_channel_tech_pvt(c); - ast_mutex_lock(&pvt->lock); - __oh323_update_info(c, pvt); - switch(ast_channel_fdno(c)) { - case 0: - fr = oh323_rtp_read(pvt); - break; - case 1: - if (pvt->rtp) - fr = ast_rtp_instance_read(pvt->rtp, 1); - else - fr = &ast_null_frame; - break; - default: - ast_log(LOG_ERROR, "Unable to handle fd %d on channel %s\n", ast_channel_fdno(c), ast_channel_name(c)); - fr = &ast_null_frame; - break; - } - ast_mutex_unlock(&pvt->lock); - return fr; -} - -static int oh323_write(struct ast_channel *c, struct ast_frame *frame) -{ - struct oh323_pvt *pvt = (struct oh323_pvt *) ast_channel_tech_pvt(c); - int res = 0; - if (frame->frametype != AST_FRAME_VOICE) { - if (frame->frametype == AST_FRAME_IMAGE) { - return 0; - } else { - ast_log(LOG_WARNING, "Can't send %d type frames with H323 write\n", frame->frametype); - return 0; - } - } else { - if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(c), &frame->subclass.format))) { - char tmp[256]; - ast_log(LOG_WARNING, "Asked to transmit frame type '%s', while native formats is '%s' (read/write = %s/%s)\n", - ast_getformatname(&frame->subclass.format), - ast_getformatname_multiple(tmp, sizeof(tmp), ast_channel_nativeformats(c)), - ast_getformatname(ast_channel_readformat(c)), - ast_getformatname(ast_channel_writeformat(c))); - return 0; - } - } - if (pvt) { - ast_mutex_lock(&pvt->lock); - if (pvt->rtp && !pvt->recvonly) - res = ast_rtp_instance_write(pvt->rtp, frame); - __oh323_update_info(c, pvt); - ast_mutex_unlock(&pvt->lock); - } - return res; -} - -static int oh323_indicate(struct ast_channel *c, int condition, const void *data, size_t datalen) -{ - - struct oh323_pvt *pvt = (struct oh323_pvt *) ast_channel_tech_pvt(c); - char *token = (char *)NULL; - int res = -1; - int got_progress; - - ast_mutex_lock(&pvt->lock); - token = (pvt->cd.call_token ? ast_strdup(pvt->cd.call_token) : NULL); - got_progress = pvt->got_progress; - if (condition == AST_CONTROL_PROGRESS) - pvt->got_progress = 1; - else if ((condition == AST_CONTROL_BUSY) || (condition == AST_CONTROL_CONGESTION)) - pvt->alreadygone = 1; - ast_mutex_unlock(&pvt->lock); - - if (h323debug) - ast_debug(1, "OH323: Indicating %d on %s (%s)\n", condition, token, ast_channel_name(c)); - - switch(condition) { - case AST_CONTROL_RINGING: - if (ast_channel_state(c) == AST_STATE_RING || ast_channel_state(c) == AST_STATE_RINGING) { - h323_send_alerting(token); - res = (got_progress ? 0 : -1); /* Do not simulate any audio tones if we got PROGRESS message */ - } - break; - case AST_CONTROL_PROGRESS: - if (ast_channel_state(c) != AST_STATE_UP) { - /* Do not send PROGRESS message more than once */ - if (!got_progress) - h323_send_progress(token); - res = 0; - } - break; - case AST_CONTROL_BUSY: - if (ast_channel_state(c) != AST_STATE_UP) { - h323_answering_call(token, 1); - ast_softhangup_nolock(c, AST_SOFTHANGUP_DEV); - res = 0; - } - break; - case AST_CONTROL_INCOMPLETE: - /* While h323 does support overlapped dialing, this channel driver does not - * at this time. Treat a response of Incomplete as if it were congestion. - */ - case AST_CONTROL_CONGESTION: - if (ast_channel_state(c) != AST_STATE_UP) { - h323_answering_call(token, 1); - ast_softhangup_nolock(c, AST_SOFTHANGUP_DEV); - res = 0; - } - break; - case AST_CONTROL_HOLD: - h323_hold_call(token, 1); - /* We should start MOH only if remote party isn't provide audio for us */ - ast_moh_start(c, data, NULL); - res = 0; - break; - case AST_CONTROL_UNHOLD: - h323_hold_call(token, 0); - ast_moh_stop(c); - res = 0; - break; - case AST_CONTROL_SRCUPDATE: - ast_rtp_instance_update_source(pvt->rtp); - res = 0; - break; - case AST_CONTROL_SRCCHANGE: - ast_rtp_instance_change_source(pvt->rtp); - res = 0; - break; - case AST_CONTROL_PROCEEDING: - case AST_CONTROL_PVT_CAUSE_CODE: - case -1: - break; - default: - ast_log(LOG_WARNING, "OH323: Don't know how to indicate condition %d on %s\n", condition, token); - break; - } - - if (h323debug) - ast_debug(1, "OH323: Indicated %d on %s, res=%d\n", condition, token, res); - if (token) - ast_free(token); - oh323_update_info(c); - - return res; -} - -static int oh323_fixup(struct ast_channel *oldchan, struct ast_channel *newchan) -{ - struct oh323_pvt *pvt = (struct oh323_pvt *) ast_channel_tech_pvt(newchan); - - ast_mutex_lock(&pvt->lock); - if (pvt->owner != oldchan) { - ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, pvt->owner); - return -1; - } - oh323_set_owner(pvt, newchan); - ast_mutex_unlock(&pvt->lock); - return 0; -} - -static int __oh323_rtp_create(struct oh323_pvt *pvt) -{ - struct ast_sockaddr our_addr; - - if (pvt->rtp) - return 0; - - { - struct ast_sockaddr tmp; - - ast_sockaddr_from_sin(&tmp, &bindaddr); - if (ast_find_ourip(&our_addr, &tmp, AF_INET)) { - ast_mutex_unlock(&pvt->lock); - ast_log(LOG_ERROR, "Unable to locate local IP address for RTP stream\n"); - return -1; - } - } - our_addr.ss.ss_family = AF_INET; - pvt->rtp = ast_rtp_instance_new("asterisk", sched, &our_addr, NULL); - if (!pvt->rtp) { - ast_mutex_unlock(&pvt->lock); - ast_log(LOG_WARNING, "Unable to create RTP session: %s\n", strerror(errno)); - return -1; - } - if (h323debug) - ast_debug(1, "Created RTP channel\n"); - - ast_rtp_instance_set_qos(pvt->rtp, tos, cos, "H323 RTP"); - ast_rtp_instance_set_channel_id(pvt->rtp, pvt->owner ? ast_channel_uniqueid(pvt->owner) : ""); - - if (h323debug) - ast_debug(1, "Setting NAT on RTP to %d\n", pvt->options.nat); - ast_rtp_instance_set_prop(pvt->rtp, AST_RTP_PROPERTY_NAT, pvt->options.nat); - - if (pvt->dtmf_pt[0] > 0) - ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(pvt->rtp), pvt->rtp, pvt->dtmf_pt[0], "audio", "telephone-event", 0); - if (pvt->dtmf_pt[1] > 0) - ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(pvt->rtp), pvt->rtp, pvt->dtmf_pt[1], "audio", "cisco-telephone-event", 0); - - if (pvt->peercapability) - ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(pvt->rtp), pvt->rtp, &pvt->peer_prefs); - - if (pvt->owner && !ast_channel_trylock(pvt->owner)) { - ast_jb_configure(pvt->owner, &global_jbconf); - ast_channel_set_fd(pvt->owner, 0, ast_rtp_instance_fd(pvt->rtp, 0)); - ast_channel_set_fd(pvt->owner, 1, ast_rtp_instance_fd(pvt->rtp, 1)); - ast_queue_frame(pvt->owner, &ast_null_frame); /* Tell Asterisk to apply changes */ - ast_channel_unlock(pvt->owner); - } else - pvt->update_rtp_info = 1; - - return 0; -} - -/*! \brief Private structure should be locked on a call */ -static struct ast_channel *__oh323_new(struct oh323_pvt *pvt, int state, const char *host, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor) -{ - struct ast_channel *ch; - char *cid_num, *cid_name; - h323_format fmt; - struct ast_format tmpfmt; - - if (!ast_strlen_zero(pvt->options.cid_num)) - cid_num = pvt->options.cid_num; - else - cid_num = pvt->cd.call_source_e164; - - if (!ast_strlen_zero(pvt->options.cid_name)) - cid_name = pvt->options.cid_name; - else - cid_name = pvt->cd.call_source_name; - - /* Don't hold a oh323_pvt lock while we allocate a chanel */ - ast_mutex_unlock(&pvt->lock); - ch = ast_channel_alloc(1, state, cid_num, cid_name, pvt->accountcode, pvt->exten, pvt->context, assignedids, requestor, pvt->amaflags, "H323/%s", host); - /* Update usage counter */ - ast_module_ref(ast_module_info->self); - ast_mutex_lock(&pvt->lock); - if (ch) { - ast_channel_tech_set(ch, &oh323_tech); - if (!(fmt = pvt->jointcapability) && !(fmt = pvt->options.capability)) - fmt = global_options.capability; - - ast_format_cap_from_old_bitfield(ast_channel_nativeformats(ch), fmt); - ast_codec_choose(&pvt->options.prefs, ast_channel_nativeformats(ch), 1, &tmpfmt)/* | (pvt->jointcapability & AST_FORMAT_VIDEO_MASK)*/; - - ast_format_cap_set(ast_channel_nativeformats(ch), &tmpfmt); - - pvt->nativeformats = ast_format_cap_to_old_bitfield(ast_channel_nativeformats(ch)); - ast_best_codec(ast_channel_nativeformats(ch), &tmpfmt); - ast_format_copy(ast_channel_writeformat(ch), &tmpfmt); - ast_format_copy(ast_channel_rawwriteformat(ch), &tmpfmt); - ast_format_copy(ast_channel_readformat(ch), &tmpfmt); - ast_format_copy(ast_channel_rawreadformat(ch), &tmpfmt); - if (!pvt->rtp) - __oh323_rtp_create(pvt); -#if 0 - ast_channel_set_fd(ch, 0, ast_rtp_instance_fd(pvt->rtp, 0)); - ast_channel_set_fd(ch, 1, ast_rtp_instance_fd(pvt->rtp, 1)); -#endif -#ifdef VIDEO_SUPPORT - if (pvt->vrtp) { - ast_channel_set_fd(ch, 2, ast_rtp_instance_fd(pvt->vrtp, 0)); - ast_channel_set_fd(ch, 3, ast_rtp_instance_fd(pvt->vrtp, 1)); - } -#endif -#ifdef T38_SUPPORT - if (pvt->udptl) { - ast_channel_set_fd(ch, 4, ast_udptl_fd(pvt->udptl)); - } -#endif - if (state == AST_STATE_RING) { - ast_channel_rings_set(ch, 1); - } - /* Allocate dsp for in-band DTMF support */ - if (pvt->options.dtmfmode & H323_DTMF_INBAND) { - pvt->vad = ast_dsp_new(); - ast_dsp_set_features(pvt->vad, DSP_FEATURE_DIGIT_DETECT); - } - /* Register channel functions. */ - ast_channel_tech_pvt_set(ch, pvt); - /* Set the owner of this channel */ - oh323_set_owner(pvt, ch); - - ast_channel_context_set(ch, pvt->context); - ast_channel_exten_set(ch, pvt->exten); - ast_channel_priority_set(ch, 1); - if (!ast_strlen_zero(pvt->accountcode)) { - ast_channel_accountcode_set(ch, pvt->accountcode); - } - if (pvt->amaflags) { - ast_channel_amaflags_set(ch, pvt->amaflags); - } - - /* Don't use ast_set_callerid() here because it will - * generate a needless NewCallerID event */ - if (!ast_strlen_zero(cid_num)) { - ast_channel_caller(ch)->ani.number.valid = 1; - ast_channel_caller(ch)->ani.number.str = ast_strdup(cid_num); - } - - if (pvt->cd.redirect_reason >= 0) { - ast_channel_redirecting(ch)->from.number.valid = 1; - ast_channel_redirecting(ch)->from.number.str = ast_strdup(pvt->cd.redirect_number); - pbx_builtin_setvar_helper(ch, "PRIREDIRECTREASON", redirectingreason2str(pvt->cd.redirect_reason)); - } - ast_channel_caller(ch)->id.name.presentation = pvt->cd.presentation; - ast_channel_caller(ch)->id.number.presentation = pvt->cd.presentation; - ast_channel_caller(ch)->id.number.plan = pvt->cd.type_of_number; - - if (!ast_strlen_zero(pvt->exten) && strcmp(pvt->exten, "s")) { - ast_channel_dialed(ch)->number.str = ast_strdup(pvt->exten); - } - if (pvt->cd.transfer_capability >= 0) - ast_channel_transfercapability_set(ch, pvt->cd.transfer_capability); - ast_channel_unlock(ch); - if (state != AST_STATE_DOWN) { - if (ast_pbx_start(ch)) { - ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(ch)); - ast_hangup(ch); - ch = NULL; - } - } - } else { - ast_log(LOG_WARNING, "Unable to allocate channel structure\n"); - } - return ch; -} - -static struct oh323_pvt *oh323_alloc(int callid) -{ - struct oh323_pvt *pvt; - - pvt = ast_calloc(1, sizeof(*pvt)); - if (!pvt) { - ast_log(LOG_ERROR, "Couldn't allocate private structure. This is bad\n"); - return NULL; - } - pvt->cd.redirect_reason = -1; - pvt->cd.transfer_capability = -1; - /* Ensure the call token is allocated for outgoing call */ - if (!callid) { - if ((pvt->cd).call_token == NULL) { - (pvt->cd).call_token = ast_calloc(1, 128); - } - if (!pvt->cd.call_token) { - ast_log(LOG_ERROR, "Not enough memory to alocate call token\n"); - ast_rtp_instance_destroy(pvt->rtp); - ast_free(pvt); - return NULL; - } - memset((char *)(pvt->cd).call_token, 0, 128); - pvt->cd.call_reference = callid; - } - memcpy(&pvt->options, &global_options, sizeof(pvt->options)); - pvt->jointcapability = pvt->options.capability; - if (pvt->options.dtmfmode & (H323_DTMF_RFC2833 | H323_DTMF_CISCO)) { - pvt->nonCodecCapability |= AST_RTP_DTMF; - } else { - pvt->nonCodecCapability &= ~AST_RTP_DTMF; - } - ast_copy_string(pvt->context, default_context, sizeof(pvt->context)); - pvt->newstate = pvt->newcontrol = pvt->newdigit = pvt->update_rtp_info = pvt->DTMFsched = -1; - ast_mutex_init(&pvt->lock); - /* Add to interface list */ - ast_mutex_lock(&iflock); - pvt->next = iflist; - iflist = pvt; - ast_mutex_unlock(&iflock); - return pvt; -} - -static void oh323_set_owner(struct oh323_pvt *pvt, struct ast_channel *chan) -{ - pvt->owner = chan; - if (pvt->rtp) { - ast_rtp_instance_set_channel_id(pvt->rtp, chan ? ast_channel_uniqueid(chan) : ""); - } -} - -static struct oh323_pvt *find_call_locked(int call_reference, const char *token) -{ - struct oh323_pvt *pvt; - - ast_mutex_lock(&iflock); - pvt = iflist; - while(pvt) { - if (!pvt->needdestroy && ((signed int)pvt->cd.call_reference == call_reference)) { - /* Found the call */ - if ((token != NULL) && (pvt->cd.call_token != NULL) && (!strcmp(pvt->cd.call_token, token))) { - ast_mutex_lock(&pvt->lock); - ast_mutex_unlock(&iflock); - return pvt; - } else if (token == NULL) { - ast_log(LOG_WARNING, "Call Token is NULL\n"); - ast_mutex_lock(&pvt->lock); - ast_mutex_unlock(&iflock); - return pvt; - } - } - pvt = pvt->next; - } - ast_mutex_unlock(&iflock); - return NULL; -} - -static int update_state(struct oh323_pvt *pvt, int state, int signal) -{ - if (!pvt) - return 0; - if (pvt->owner && !ast_channel_trylock(pvt->owner)) { - if (state >= 0) - ast_setstate(pvt->owner, state); - if (signal >= 0) - ast_queue_control(pvt->owner, signal); - ast_channel_unlock(pvt->owner); - return 1; - } - else { - if (state >= 0) - pvt->newstate = state; - if (signal >= 0) - pvt->newcontrol = signal; - return 0; - } -} - -static struct oh323_alias *build_alias(const char *name, struct ast_variable *v, struct ast_variable *alt, int realtime) -{ - struct oh323_alias *alias; - int found = 0; - - alias = ASTOBJ_CONTAINER_FIND_UNLINK_FULL(&aliasl, name, name, 0, 0, strcasecmp); - - if (alias) - found++; - else { - if (!(alias = ast_calloc(1, sizeof(*alias)))) - return NULL; - ASTOBJ_INIT(alias); - } - if (!found && name) - ast_copy_string(alias->name, name, sizeof(alias->name)); - for (; v || ((v = alt) && !(alt = NULL)); v = v->next) { - if (!strcasecmp(v->name, "e164")) { - ast_copy_string(alias->e164, v->value, sizeof(alias->e164)); - } else if (!strcasecmp(v->name, "prefix")) { - ast_copy_string(alias->prefix, v->value, sizeof(alias->prefix)); - } else if (!strcasecmp(v->name, "context")) { - ast_copy_string(alias->context, v->value, sizeof(alias->context)); - } else if (!strcasecmp(v->name, "secret")) { - ast_copy_string(alias->secret, v->value, sizeof(alias->secret)); - } else { - if (strcasecmp(v->value, "h323")) { - ast_log(LOG_WARNING, "Keyword %s does not make sense in type=h323\n", v->name); - } - } - } - ASTOBJ_UNMARK(alias); - return alias; -} - -static struct oh323_alias *realtime_alias(const char *alias) -{ - struct ast_variable *var, *tmp; - struct oh323_alias *a; - - var = ast_load_realtime("h323", "name", alias, SENTINEL); - - if (!var) - return NULL; - - for (tmp = var; tmp; tmp = tmp->next) { - if (!strcasecmp(tmp->name, "type") && - !(!strcasecmp(tmp->value, "alias") || !strcasecmp(tmp->value, "h323"))) { - ast_variables_destroy(var); - return NULL; - } - } - - a = build_alias(alias, var, NULL, 1); - - ast_variables_destroy(var); - - return a; -} - -static int h323_parse_allow_disallow(struct ast_codec_pref *pref, h323_format *formats, const char *list, int allowing) -{ - int res; - struct ast_format_cap *cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); - if (!cap) { - return 1; - } - - ast_format_cap_from_old_bitfield(cap, *formats); - res = ast_parse_allow_disallow(pref, cap, list, allowing); - *formats = ast_format_cap_to_old_bitfield(cap); - cap = ast_format_cap_destroy(cap); - return res; - -} - -static int update_common_options(struct ast_variable *v, struct call_options *options) -{ - int tmp = 0; - char *val, *opt; - - if (!strcasecmp(v->name, "allow")) { - h323_parse_allow_disallow(&options->prefs, &options->capability, v->value, 1); - } else if (!strcasecmp(v->name, "autoframing")) { - options->autoframing = ast_true(v->value); - } else if (!strcasecmp(v->name, "disallow")) { - h323_parse_allow_disallow(&options->prefs, &options->capability, v->value, 0); - } else if (!strcasecmp(v->name, "dtmfmode")) { - val = ast_strdupa(v->value); - if ((opt = strchr(val, ':')) != (char *)NULL) { - *opt++ = '\0'; - tmp = atoi(opt); - } - if (!strcasecmp(v->value, "inband")) { - options->dtmfmode |= H323_DTMF_INBAND; - } else if (!strcasecmp(val, "rfc2833")) { - options->dtmfmode |= H323_DTMF_RFC2833; - if (!opt) { - options->dtmfcodec[0] = H323_DTMF_RFC2833_PT; - } else if ((tmp >= 96) && (tmp < 128)) { - options->dtmfcodec[0] = tmp; - } else { - options->dtmfcodec[0] = H323_DTMF_RFC2833_PT; - ast_log(LOG_WARNING, "Unknown rfc2833 payload %s specified at line %d, using default %d\n", opt, v->lineno, options->dtmfcodec[0]); - } - } else if (!strcasecmp(val, "cisco")) { - options->dtmfmode |= H323_DTMF_CISCO; - if (!opt) { - options->dtmfcodec[1] = H323_DTMF_CISCO_PT; - } else if ((tmp >= 96) && (tmp < 128)) { - options->dtmfcodec[1] = tmp; - } else { - options->dtmfcodec[1] = H323_DTMF_CISCO_PT; - ast_log(LOG_WARNING, "Unknown Cisco DTMF payload %s specified at line %d, using default %d\n", opt, v->lineno, options->dtmfcodec[1]); - } - } else if (!strcasecmp(v->value, "h245-signal")) { - options->dtmfmode |= H323_DTMF_SIGNAL; - } else { - ast_log(LOG_WARNING, "Unknown dtmf mode '%s' at line %d\n", v->value, v->lineno); - } - } else if (!strcasecmp(v->name, "dtmfcodec")) { - ast_log(LOG_NOTICE, "Option %s at line %d is deprecated. Use dtmfmode=rfc2833[:] instead.\n", v->name, v->lineno); - tmp = atoi(v->value); - if (tmp < 96) - ast_log(LOG_WARNING, "Invalid %s value %s at line %d\n", v->name, v->value, v->lineno); - else - options->dtmfcodec[0] = tmp; - } else if (!strcasecmp(v->name, "bridge")) { - options->bridge = ast_true(v->value); - } else if (!strcasecmp(v->name, "nat")) { - options->nat = ast_true(v->value); - } else if (!strcasecmp(v->name, "fastStart")) { - options->fastStart = ast_true(v->value); - } else if (!strcasecmp(v->name, "h245Tunneling")) { - options->h245Tunneling = ast_true(v->value); - } else if (!strcasecmp(v->name, "silenceSuppression")) { - options->silenceSuppression = ast_true(v->value); - } else if (!strcasecmp(v->name, "progress_setup")) { - tmp = atoi(v->value); - if ((tmp != 0) && (tmp != 1) && (tmp != 3) && (tmp != 8)) { - ast_log(LOG_WARNING, "Invalid value %s for %s at line %d, assuming 0\n", v->value, v->name, v->lineno); - tmp = 0; - } - options->progress_setup = tmp; - } else if (!strcasecmp(v->name, "progress_alert")) { - tmp = atoi(v->value); - if ((tmp != 0) && (tmp != 1) && (tmp != 8)) { - ast_log(LOG_WARNING, "Invalid value %s for %s at line %d, assuming 0\n", v->value, v->name, v->lineno); - tmp = 0; - } - options->progress_alert = tmp; - } else if (!strcasecmp(v->name, "progress_audio")) { - options->progress_audio = ast_true(v->value); - } else if (!strcasecmp(v->name, "callerid")) { - ast_callerid_split(v->value, options->cid_name, sizeof(options->cid_name), options->cid_num, sizeof(options->cid_num)); - } else if (!strcasecmp(v->name, "fullname")) { - ast_copy_string(options->cid_name, v->value, sizeof(options->cid_name)); - } else if (!strcasecmp(v->name, "cid_number")) { - ast_copy_string(options->cid_num, v->value, sizeof(options->cid_num)); - } else if (!strcasecmp(v->name, "tunneling")) { - if (!strcasecmp(v->value, "none")) - options->tunnelOptions = 0; - else if (!strcasecmp(v->value, "cisco")) - options->tunnelOptions |= H323_TUNNEL_CISCO; - else if (!strcasecmp(v->value, "qsig")) - options->tunnelOptions |= H323_TUNNEL_QSIG; - else - ast_log(LOG_WARNING, "Invalid value %s for %s at line %d\n", v->value, v->name, v->lineno); - } else if (!strcasecmp(v->name, "hold")) { - if (!strcasecmp(v->value, "none")) - options->holdHandling = ~0; - else if (!strcasecmp(v->value, "notify")) - options->holdHandling |= H323_HOLD_NOTIFY; - else if (!strcasecmp(v->value, "q931only")) - options->holdHandling |= H323_HOLD_NOTIFY | H323_HOLD_Q931ONLY; - else if (!strcasecmp(v->value, "h450")) - options->holdHandling |= H323_HOLD_H450; - else - ast_log(LOG_WARNING, "Invalid value %s for %s at line %d\n", v->value, v->name, v->lineno); - } else - return 1; - - return 0; -} - -static struct oh323_user *build_user(const char *name, struct ast_variable *v, struct ast_variable *alt, int realtime) -{ - struct oh323_user *user; - struct ast_ha *oldha; - int found = 0; - int format; - - user = ASTOBJ_CONTAINER_FIND_UNLINK_FULL(&userl, name, name, 0, 0, strcmp); - - if (user) - found++; - else { - if (!(user = ast_calloc(1, sizeof(*user)))) - return NULL; - ASTOBJ_INIT(user); - } - oldha = user->ha; - user->ha = (struct ast_ha *)NULL; - memcpy(&user->options, &global_options, sizeof(user->options)); - user->options.dtmfmode = 0; - user->options.holdHandling = 0; - /* Set default context */ - ast_copy_string(user->context, default_context, sizeof(user->context)); - if (!found) { - ast_copy_string(user->name, name, sizeof(user->name)); - } - -#if 0 /* XXX Port channel variables functionality from chan_sip XXX */ - if (user->chanvars) { - ast_variables_destroy(user->chanvars); - user->chanvars = NULL; - } -#endif - - for (; v || ((v = alt) && !(alt = NULL)); v = v->next) { - if (!update_common_options(v, &user->options)) - continue; - if (!strcasecmp(v->name, "context")) { - ast_copy_string(user->context, v->value, sizeof(user->context)); - } else if (!strcasecmp(v->name, "secret")) { - ast_copy_string(user->secret, v->value, sizeof(user->secret)); - } else if (!strcasecmp(v->name, "accountcode")) { - ast_copy_string(user->accountcode, v->value, sizeof(user->accountcode)); - } else if (!strcasecmp(v->name, "host")) { - if (!strcasecmp(v->value, "dynamic")) { - ast_log(LOG_ERROR, "A dynamic host on a type=user does not make any sense\n"); - ASTOBJ_UNREF(user, oh323_destroy_user); - return NULL; - } else { - struct ast_sockaddr tmp; - - tmp.ss.ss_family = AF_INET; - if (ast_get_ip(&tmp, v->value)) { - ASTOBJ_UNREF(user, oh323_destroy_user); - return NULL; - } - ast_sockaddr_to_sin(&tmp, &user->addr); - } - /* Let us know we need to use ip authentication */ - user->host = 1; - } else if (!strcasecmp(v->name, "amaflags")) { - format = ast_channel_string2amaflag(v->value); - if (format < 0) { - ast_log(LOG_WARNING, "Invalid AMA Flags: %s at line %d\n", v->value, v->lineno); - } else { - user->amaflags = format; - } - } else if (!strcasecmp(v->name, "permit") || - !strcasecmp(v->name, "deny")) { - int ha_error = 0; - - user->ha = ast_append_ha(v->name, v->value, user->ha, &ha_error); - if (ha_error) - ast_log(LOG_ERROR, "Bad ACL entry in configuration line %d : %s\n", v->lineno, v->value); - } - } - if (!user->options.dtmfmode) - user->options.dtmfmode = global_options.dtmfmode; - if (user->options.holdHandling == ~0) - user->options.holdHandling = 0; - else if (!user->options.holdHandling) - user->options.holdHandling = global_options.holdHandling; - ASTOBJ_UNMARK(user); - ast_free_ha(oldha); - return user; -} - -static struct oh323_user *realtime_user(const call_details_t *cd) -{ - struct ast_variable *var, *tmp; - struct oh323_user *user; - const char *username; - - if (userbyalias) - var = ast_load_realtime("h323", "name", username = cd->call_source_aliases, SENTINEL); - else { - username = (char *)NULL; - var = ast_load_realtime("h323", "host", cd->sourceIp, SENTINEL); - } - - if (!var) - return NULL; - - for (tmp = var; tmp; tmp = tmp->next) { - if (!strcasecmp(tmp->name, "type") && - !(!strcasecmp(tmp->value, "user") || !strcasecmp(tmp->value, "friend"))) { - ast_variables_destroy(var); - return NULL; - } else if (!username && !strcasecmp(tmp->name, "name")) - username = tmp->value; - } - - if (!username) { - ast_log(LOG_WARNING, "Cannot determine user name for IP address %s\n", cd->sourceIp); - ast_variables_destroy(var); - return NULL; - } - - user = build_user(username, var, NULL, 1); - - ast_variables_destroy(var); - - return user; -} - -static struct oh323_peer *build_peer(const char *name, struct ast_variable *v, struct ast_variable *alt, int realtime) -{ - struct oh323_peer *peer; - struct ast_ha *oldha; - int found = 0; - - peer = ASTOBJ_CONTAINER_FIND_UNLINK_FULL(&peerl, name, name, 0, 0, strcmp); - - if (peer) - found++; - else { - if (!(peer = ast_calloc(1, sizeof(*peer)))) - return NULL; - ASTOBJ_INIT(peer); - } - oldha = peer->ha; - peer->ha = NULL; - memcpy(&peer->options, &global_options, sizeof(peer->options)); - peer->options.dtmfmode = 0; - peer->options.holdHandling = 0; - peer->addr.sin_port = htons(h323_signalling_port); - peer->addr.sin_family = AF_INET; - if (!found && name) - ast_copy_string(peer->name, name, sizeof(peer->name)); - -#if 0 /* XXX Port channel variables functionality from chan_sip XXX */ - if (peer->chanvars) { - ast_variables_destroy(peer->chanvars); - peer->chanvars = NULL; - } -#endif - /* Default settings for mailbox */ - peer->mailbox[0] = '\0'; - - for (; v || ((v = alt) && !(alt = NULL)); v = v->next) { - if (!update_common_options(v, &peer->options)) - continue; - if (!strcasecmp(v->name, "host")) { - if (!strcasecmp(v->value, "dynamic")) { - ast_log(LOG_ERROR, "Dynamic host configuration not implemented.\n"); - ASTOBJ_UNREF(peer, oh323_destroy_peer); - return NULL; - } - { - struct ast_sockaddr tmp; - - tmp.ss.ss_family = AF_INET; - if (ast_get_ip(&tmp, v->value)) { - ast_log(LOG_ERROR, "Could not determine IP for %s\n", v->value); - ASTOBJ_UNREF(peer, oh323_destroy_peer); - return NULL; - } - ast_sockaddr_to_sin(&tmp, &peer->addr); - } - } else if (!strcasecmp(v->name, "port")) { - peer->addr.sin_port = htons(atoi(v->value)); - } else if (!strcasecmp(v->name, "permit") || - !strcasecmp(v->name, "deny")) { - int ha_error = 0; - - peer->ha = ast_append_ha(v->name, v->value, peer->ha, &ha_error); - if (ha_error) - ast_log(LOG_ERROR, "Bad ACL entry in configuration line %d : %s\n", v->lineno, v->value); - } else if (!strcasecmp(v->name, "mailbox")) { - ast_copy_string(peer->mailbox, v->value, sizeof(peer->mailbox)); - } else if (!strcasecmp(v->name, "hasvoicemail")) { - if (ast_true(v->value) && ast_strlen_zero(peer->mailbox)) { - /* - * hasvoicemail is a users.conf legacy voicemail enable method. - * hasvoicemail is only going to work for app_voicemail mailboxes. - */ - if (strchr(name, '@')) { - ast_copy_string(peer->mailbox, name, sizeof(peer->mailbox)); - } else { - snprintf(peer->mailbox, sizeof(peer->mailbox), "%s@default", name); - } - } - } - } - if (!peer->options.dtmfmode) - peer->options.dtmfmode = global_options.dtmfmode; - if (peer->options.holdHandling == ~0) - peer->options.holdHandling = 0; - else if (!peer->options.holdHandling) - peer->options.holdHandling = global_options.holdHandling; - ASTOBJ_UNMARK(peer); - ast_free_ha(oldha); - return peer; -} - -static struct oh323_peer *realtime_peer(const char *peername, struct sockaddr_in *sin) -{ - struct oh323_peer *peer; - struct ast_variable *var; - struct ast_variable *tmp; - const char *addr = NULL; - - /* First check on peer name */ - if (peername) - var = ast_load_realtime("h323", "name", peername, SENTINEL); - else if (sin) /* Then check on IP address for dynamic peers */ - var = ast_load_realtime("h323", "host", addr = ast_inet_ntoa(sin->sin_addr), SENTINEL); - else - return NULL; - - if (!var) - return NULL; - - for (tmp = var; tmp; tmp = tmp->next) { - /* If this is type=user, then skip this object. */ - if (!strcasecmp(tmp->name, "type") && - !(!strcasecmp(tmp->value, "peer") || !strcasecmp(tmp->value, "friend"))) { - ast_variables_destroy(var); - return NULL; - } else if (!peername && !strcasecmp(tmp->name, "name")) { - peername = tmp->value; - } - } - - if (!peername) { /* Did not find peer in realtime */ - ast_log(LOG_WARNING, "Cannot determine peer name for IP address %s\n", addr); - ast_variables_destroy(var); - return NULL; - } - - /* Peer found in realtime, now build it in memory */ - peer = build_peer(peername, var, NULL, 1); - - ast_variables_destroy(var); - - return peer; -} - -static int oh323_addrcmp_str(struct in_addr inaddr, char *addr) -{ - return strcmp(ast_inet_ntoa(inaddr), addr); -} - -static struct oh323_user *find_user(const call_details_t *cd, int realtime) -{ - struct oh323_user *u; - - if (userbyalias) - u = ASTOBJ_CONTAINER_FIND(&userl, cd->call_source_aliases); - else - u = ASTOBJ_CONTAINER_FIND_FULL(&userl, cd->sourceIp, addr.sin_addr, 0, 0, oh323_addrcmp_str); - - if (!u && realtime) - u = realtime_user(cd); - - if (!u && h323debug) - ast_debug(1, "Could not find user by name %s or address %s\n", cd->call_source_aliases, cd->sourceIp); - - return u; -} - -static int oh323_addrcmp(struct sockaddr_in addr, struct sockaddr_in *sin) -{ - int res; - - if (!sin) - res = -1; - else - res = inaddrcmp(&addr , sin); - - return res; -} - -static struct oh323_peer *find_peer(const char *peer, struct sockaddr_in *sin, int realtime) -{ - struct oh323_peer *p; - - if (peer) - p = ASTOBJ_CONTAINER_FIND(&peerl, peer); - else - p = ASTOBJ_CONTAINER_FIND_FULL(&peerl, sin, addr, 0, 0, oh323_addrcmp); - - if (!p && realtime) - p = realtime_peer(peer, sin); - - if (!p && h323debug) - ast_debug(1, "Could not find peer by name %s or address %s\n", (peer ? peer : ""), (sin ? ast_inet_ntoa(sin->sin_addr) : "")); - - return p; -} - -static int create_addr(struct oh323_pvt *pvt, char *opeer) -{ - struct hostent *hp; - struct ast_hostent ahp; - struct oh323_peer *p; - int portno; - int found = 0; - char *port; - char *hostn; - char peer[256] = ""; - - ast_copy_string(peer, opeer, sizeof(peer)); - port = strchr(peer, ':'); - if (port) { - *port = '\0'; - port++; - } - pvt->sa.sin_family = AF_INET; - p = find_peer(peer, NULL, 1); - if (p) { - found++; - memcpy(&pvt->options, &p->options, sizeof(pvt->options)); - pvt->jointcapability = pvt->options.capability; - if (pvt->options.dtmfmode) { - if (pvt->options.dtmfmode & H323_DTMF_RFC2833) { - pvt->nonCodecCapability |= AST_RTP_DTMF; - } else { - pvt->nonCodecCapability &= ~AST_RTP_DTMF; - } - } - if (p->addr.sin_addr.s_addr) { - pvt->sa.sin_addr = p->addr.sin_addr; - pvt->sa.sin_port = p->addr.sin_port; - } - ASTOBJ_UNREF(p, oh323_destroy_peer); - } - if (!p && !found) { - hostn = peer; - if (port) { - portno = atoi(port); - } else { - portno = h323_signalling_port; - } - hp = ast_gethostbyname(hostn, &ahp); - if (hp) { - memcpy(&pvt->sa.sin_addr, hp->h_addr, sizeof(pvt->sa.sin_addr)); - pvt->sa.sin_port = htons(portno); - /* Look peer by address */ - p = find_peer(NULL, &pvt->sa, 1); - memcpy(&pvt->options, (p ? &p->options : &global_options), sizeof(pvt->options)); - pvt->jointcapability = pvt->options.capability; - if (p) { - ASTOBJ_UNREF(p, oh323_destroy_peer); - } - if (pvt->options.dtmfmode) { - if (pvt->options.dtmfmode & H323_DTMF_RFC2833) { - pvt->nonCodecCapability |= AST_RTP_DTMF; - } else { - pvt->nonCodecCapability &= ~AST_RTP_DTMF; - } - } - return 0; - } else { - ast_log(LOG_WARNING, "No such host: %s\n", peer); - return -1; - } - } else if (!found) { - return -1; - } else { - return 0; - } -} -static struct ast_channel *oh323_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *dest, int *cause) -{ - struct oh323_pvt *pvt; - struct ast_channel *tmpc = NULL; - char *ext, *host; - char *h323id = NULL; - char tmp[256], tmp1[256]; - - if (h323debug) - ast_debug(1, "type=%s, format=%s, data=%s.\n", type, ast_getformatname_multiple(tmp, sizeof(tmp), cap), dest); - - pvt = oh323_alloc(0); - if (!pvt) { - ast_log(LOG_WARNING, "Unable to build pvt data for '%s'\n", dest); - return NULL; - } - if (!(ast_format_cap_has_type(cap, AST_FORMAT_TYPE_AUDIO))) { - ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%s'\n", ast_getformatname_multiple(tmp, sizeof(tmp), cap)); - oh323_destroy(pvt); - if (cause) - *cause = AST_CAUSE_INCOMPATIBLE_DESTINATION; - return NULL; - } - ast_copy_string(tmp, dest, sizeof(tmp)); - host = strchr(tmp, '@'); - if (host) { - *host = '\0'; - host++; - ext = tmp; - } else { - ext = strrchr(tmp, '/'); - if (ext) - *ext++ = '\0'; - host = tmp; - } - strtok_r(host, "/", &(h323id)); - if (!ast_strlen_zero(h323id)) { - h323_set_id(h323id); - } - if (ext) { - ast_copy_string(pvt->exten, ext, sizeof(pvt->exten)); - } - if (h323debug) - ast_debug(1, "Extension: %s Host: %s\n", pvt->exten, host); - - if (gatekeeper_disable) { - if (create_addr(pvt, host)) { - oh323_destroy(pvt); - if (cause) - *cause = AST_CAUSE_DESTINATION_OUT_OF_ORDER; - return NULL; - } - } - else { - memcpy(&pvt->options, &global_options, sizeof(pvt->options)); - pvt->jointcapability = pvt->options.capability; - if (pvt->options.dtmfmode) { - if (pvt->options.dtmfmode & H323_DTMF_RFC2833) { - pvt->nonCodecCapability |= AST_RTP_DTMF; - } else { - pvt->nonCodecCapability &= ~AST_RTP_DTMF; - } - } - } - - ast_mutex_lock(&caplock); - /* Generate unique channel identifier */ - snprintf(tmp1, sizeof(tmp1)-1, "%s-%u", host, ++unique); - tmp1[sizeof(tmp1)-1] = '\0'; - ast_mutex_unlock(&caplock); - - ast_mutex_lock(&pvt->lock); - tmpc = __oh323_new(pvt, AST_STATE_DOWN, tmp1, assignedids, requestor); - ast_mutex_unlock(&pvt->lock); - if (!tmpc) { - oh323_destroy(pvt); - if (cause) - *cause = AST_CAUSE_NORMAL_TEMPORARY_FAILURE; - } - ast_update_use_count(); - restart_monitor(); - return tmpc; -} - -/*! \brief Find a call by alias */ -static struct oh323_alias *find_alias(const char *source_aliases, int realtime) -{ - struct oh323_alias *a; - - a = ASTOBJ_CONTAINER_FIND(&aliasl, source_aliases); - - if (!a && realtime) - a = realtime_alias(source_aliases); - - return a; -} - -/*! \brief - * Callback for sending digits from H.323 up to asterisk - * - */ -static int receive_digit(unsigned call_reference, char digit, const char *token, int duration) -{ - struct oh323_pvt *pvt; - int res; - - pvt = find_call_locked(call_reference, token); - if (!pvt) { - ast_log(LOG_ERROR, "Received digit '%c' (%u ms) for call %s without private structure\n", digit, duration, token); - return -1; - } - if (h323debug) - ast_log(LOG_DTMF, "Received %s digit '%c' (%u ms) for call %s\n", (digit == ' ' ? "update for" : "new"), (digit == ' ' ? pvt->curDTMF : digit), duration, token); - - if (pvt->owner && !ast_channel_trylock(pvt->owner)) { - if (digit == '!') - res = ast_queue_control(pvt->owner, AST_CONTROL_FLASH); - else { - struct ast_frame f = { - .frametype = AST_FRAME_DTMF_END, - .subclass.integer = digit, - .samples = duration * 8, - .len = duration, - .src = "SEND_DIGIT", - }; - if (digit == ' ') { /* signalUpdate message */ - f.subclass.integer = pvt->curDTMF; - AST_SCHED_DEL(sched, pvt->DTMFsched); - } else { /* Regular input or signal message */ - if (pvt->DTMFsched >= 0) { - /* We still don't send DTMF END from previous event, send it now */ - AST_SCHED_DEL(sched, pvt->DTMFsched); - f.subclass.integer = pvt->curDTMF; - f.samples = f.len = 0; - ast_queue_frame(pvt->owner, &f); - /* Restore values */ - f.subclass.integer = digit; - f.samples = duration * 8; - f.len = duration; - } - if (duration) { /* This is a signal, signalUpdate follows */ - f.frametype = AST_FRAME_DTMF_BEGIN; - pvt->DTMFsched = ast_sched_add(sched, duration, oh323_simulate_dtmf_end, pvt); - if (h323debug) - ast_log(LOG_DTMF, "Scheduled DTMF END simulation for %d ms, id=%d\n", duration, pvt->DTMFsched); - } - pvt->curDTMF = digit; - } - res = ast_queue_frame(pvt->owner, &f); - } - ast_channel_unlock(pvt->owner); - } else { - if (digit == '!') - pvt->newcontrol = AST_CONTROL_FLASH; - else { - pvt->newduration = duration; - pvt->newdigit = digit; - } - res = 0; - } - ast_mutex_unlock(&pvt->lock); - return res; -} - -/*! \brief - * Callback function used to inform the H.323 stack of the local rtp ip/port details - * - * \return Returns the local RTP information - */ -static struct rtp_info *external_rtp_create(unsigned call_reference, const char * token) -{ - struct oh323_pvt *pvt; - struct sockaddr_in us; - struct rtp_info *info; - - info = ast_calloc(1, sizeof(*info)); - if (!info) { - ast_log(LOG_ERROR, "Unable to allocated info structure, this is very bad\n"); - return NULL; - } - pvt = find_call_locked(call_reference, token); - if (!pvt) { - ast_free(info); - ast_log(LOG_ERROR, "Unable to find call %s(%d)\n", token, call_reference); - return NULL; - } - if (!pvt->rtp) - __oh323_rtp_create(pvt); - if (!pvt->rtp) { - ast_mutex_unlock(&pvt->lock); - ast_free(info); - ast_log(LOG_ERROR, "No RTP stream is available for call %s (%d)", token, call_reference); - return NULL; - } - /* figure out our local RTP port and tell the H.323 stack about it */ - { - struct ast_sockaddr tmp; - - ast_rtp_instance_get_local_address(pvt->rtp, &tmp); - ast_sockaddr_to_sin(&tmp, &us); - } - ast_mutex_unlock(&pvt->lock); - - ast_copy_string(info->addr, ast_inet_ntoa(us.sin_addr), sizeof(info->addr)); - info->port = ntohs(us.sin_port); - if (h323debug) - ast_debug(1, "Sending RTP 'US' %s:%d\n", info->addr, info->port); - return info; -} - -/*! \brief - * Call-back function passing remote ip/port information from H.323 to asterisk - * - * Returns nothing - */ -static void setup_rtp_connection(unsigned call_reference, const char *remoteIp, int remotePort, const char *token, int pt) -{ - struct oh323_pvt *pvt; - struct sockaddr_in them; - int nativeformats_changed; - enum { NEED_NONE, NEED_HOLD, NEED_UNHOLD } rtp_change = NEED_NONE; - - if (h323debug) - ast_debug(1, "Setting up RTP connection for %s\n", token); - - /* Find the call or allocate a private structure if call not found */ - pvt = find_call_locked(call_reference, token); - if (!pvt) { - ast_log(LOG_ERROR, "Something is wrong: rtp\n"); - return; - } - if (pvt->alreadygone) { - ast_mutex_unlock(&pvt->lock); - return; - } - - if (!pvt->rtp) - __oh323_rtp_create(pvt); - - if ((pt == 2) && (pvt->jointcapability & AST_FORMAT_G726_AAL2)) { - ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(pvt->rtp), pvt->rtp, pt, "audio", "G726-32", AST_RTP_OPT_G726_NONSTANDARD); - } - - them.sin_family = AF_INET; - /* only works for IPv4 */ - them.sin_addr.s_addr = inet_addr(remoteIp); - them.sin_port = htons(remotePort); - - if (them.sin_addr.s_addr) { - { - struct ast_sockaddr tmp; - - ast_sockaddr_from_sin(&tmp, &them); - ast_rtp_instance_set_remote_address(pvt->rtp, &tmp); - } - if (pvt->recvonly) { - pvt->recvonly = 0; - rtp_change = NEED_UNHOLD; - } - } else { - ast_rtp_instance_stop(pvt->rtp); - if (!pvt->recvonly) { - pvt->recvonly = 1; - rtp_change = NEED_HOLD; - } - } - - /* Change native format to reflect information taken from OLC/OLCAck */ - nativeformats_changed = 0; - if (pt != 128 && pvt->rtp) { /* Payload type is invalid, so try to use previously decided */ - struct ast_rtp_payload_type rtptype = ast_rtp_codecs_payload_lookup(ast_rtp_instance_get_codecs(pvt->rtp), pt); - if (rtptype.asterisk_format) { - if (pvt->nativeformats != ast_format_to_old_bitfield(&rtptype.format)) { - pvt->nativeformats = ast_format_to_old_bitfield(&rtptype.format); - nativeformats_changed = 1; - } - } - } else if (h323debug) - ast_log(LOG_NOTICE, "Payload type is unknown, formats isn't changed\n"); - - /* Don't try to lock the channel if nothing changed */ - if (nativeformats_changed || pvt->options.progress_audio || (rtp_change != NEED_NONE)) { - if (pvt->owner && !ast_channel_trylock(pvt->owner)) { - struct ast_format_cap *pvt_native = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); - ast_format_cap_from_old_bitfield(pvt_native, pvt->nativeformats); - - /* Re-build translation path only if native format(s) has been changed */ - if (!(ast_format_cap_identical(ast_channel_nativeformats(pvt->owner), pvt_native))) { - if (h323debug) { - char tmp[256], tmp2[256]; - ast_debug(1, "Native format changed to '%s' from '%s', read format is %s, write format is %s\n", - ast_getformatname_multiple(tmp, sizeof(tmp), pvt_native), - ast_getformatname_multiple(tmp2, sizeof(tmp2), ast_channel_nativeformats(pvt->owner)), - ast_getformatname(ast_channel_readformat(pvt->owner)), - ast_getformatname(ast_channel_writeformat(pvt->owner))); - } - ast_format_cap_copy(ast_channel_nativeformats(pvt->owner), pvt_native); - ast_set_read_format(pvt->owner, ast_channel_readformat(pvt->owner)); - ast_set_write_format(pvt->owner, ast_channel_writeformat(pvt->owner)); - } - if (pvt->options.progress_audio) - ast_queue_control(pvt->owner, AST_CONTROL_PROGRESS); - switch (rtp_change) { - case NEED_HOLD: - ast_queue_hold(pvt->owner, NULL); - break; - case NEED_UNHOLD: - ast_queue_unhold(pvt->owner); - break; - default: - break; - } - ast_channel_unlock(pvt->owner); - pvt_native = ast_format_cap_destroy(pvt_native); - } else { - if (pvt->options.progress_audio) - pvt->newcontrol = AST_CONTROL_PROGRESS; - else if (rtp_change == NEED_HOLD) - pvt->newcontrol = AST_CONTROL_HOLD; - else if (rtp_change == NEED_UNHOLD) - pvt->newcontrol = AST_CONTROL_UNHOLD; - if (h323debug) - ast_debug(1, "RTP connection preparation for %s is pending...\n", token); - } - } - ast_mutex_unlock(&pvt->lock); - - if (h323debug) - ast_debug(1, "RTP connection prepared for %s\n", token); - - return; -} - -/*! \brief - * Call-back function to signal asterisk that the channel has been answered - * Returns nothing - */ -static void connection_made(unsigned call_reference, const char *token) -{ - struct oh323_pvt *pvt; - - if (h323debug) - ast_debug(1, "Call %s answered\n", token); - - pvt = find_call_locked(call_reference, token); - if (!pvt) { - ast_log(LOG_ERROR, "Something is wrong: connection\n"); - return; - } - - /* Inform asterisk about remote party connected only on outgoing calls */ - if (!pvt->outgoing) { - ast_mutex_unlock(&pvt->lock); - return; - } - /* Do not send ANSWER message more than once */ - if (!pvt->connection_established) { - pvt->connection_established = 1; - update_state(pvt, -1, AST_CONTROL_ANSWER); - } - ast_mutex_unlock(&pvt->lock); - return; -} - -static int progress(unsigned call_reference, const char *token, int inband) -{ - struct oh323_pvt *pvt; - - if (h323debug) - ast_debug(1, "Received ALERT/PROGRESS message for %s tones\n", (inband ? "inband" : "self-generated")); - - pvt = find_call_locked(call_reference, token); - if (!pvt) { - ast_log(LOG_ERROR, "Private structure not found in progress.\n"); - return -1; - } - if (!pvt->owner) { - ast_mutex_unlock(&pvt->lock); - ast_log(LOG_ERROR, "No Asterisk channel associated with private structure.\n"); - return -1; - } - update_state(pvt, -1, (inband ? AST_CONTROL_PROGRESS : AST_CONTROL_RINGING)); - ast_mutex_unlock(&pvt->lock); - - return 0; -} - -/*! \brief - * Call-back function for incoming calls - * - * Returns 1 on success - */ -static call_options_t *setup_incoming_call(call_details_t *cd) -{ - struct oh323_pvt *pvt; - struct oh323_user *user = NULL; - struct oh323_alias *alias = NULL; - - if (h323debug) - ast_debug(1, "Setting up incoming call for %s\n", cd->call_token); - - /* allocate the call*/ - pvt = oh323_alloc(cd->call_reference); - - if (!pvt) { - ast_log(LOG_ERROR, "Unable to allocate private structure, this is bad.\n"); - cleanup_call_details(cd); - return NULL; - } - - /* Populate the call details in the private structure */ - memcpy(&pvt->cd, cd, sizeof(pvt->cd)); - memcpy(&pvt->options, &global_options, sizeof(pvt->options)); - pvt->jointcapability = pvt->options.capability; - - if (h323debug) { - ast_verb(3, "Setting up Call\n"); - ast_verb(3, " \tCall token: [%s]\n", pvt->cd.call_token); - ast_verb(3, " \tCalling party name: [%s]\n", pvt->cd.call_source_name); - ast_verb(3, " \tCalling party number: [%s]\n", pvt->cd.call_source_e164); - ast_verb(3, " \tCalled party name: [%s]\n", pvt->cd.call_dest_alias); - ast_verb(3, " \tCalled party number: [%s]\n", pvt->cd.call_dest_e164); - if (pvt->cd.redirect_reason >= 0) - ast_verb(3, " \tRedirecting party number: [%s] (reason %d)\n", pvt->cd.redirect_number, pvt->cd.redirect_reason); - ast_verb(3, " \tCalling party IP: [%s]\n", pvt->cd.sourceIp); - } - - /* Decide if we are allowing Gatekeeper routed calls*/ - if ((!strcasecmp(cd->sourceIp, gatekeeper)) && (gkroute == -1) && !gatekeeper_disable) { - if (!ast_strlen_zero(cd->call_dest_e164)) { - ast_copy_string(pvt->exten, cd->call_dest_e164, sizeof(pvt->exten)); - ast_copy_string(pvt->context, default_context, sizeof(pvt->context)); - } else { - alias = find_alias(cd->call_dest_alias, 1); - if (!alias) { - ast_log(LOG_ERROR, "Call for %s rejected, alias not found\n", cd->call_dest_alias); - oh323_destroy(pvt); - return NULL; - } - ast_copy_string(pvt->exten, alias->name, sizeof(pvt->exten)); - ast_copy_string(pvt->context, alias->context, sizeof(pvt->context)); - } - } else { - /* Either this call is not from the Gatekeeper - or we are not allowing gk routed calls */ - user = find_user(cd, 1); - if (!user) { - if (!acceptAnonymous) { - ast_log(LOG_NOTICE, "Anonymous call from '%s@%s' rejected\n", pvt->cd.call_source_aliases, pvt->cd.sourceIp); - oh323_destroy(pvt); - return NULL; - } - if (ast_strlen_zero(default_context)) { - ast_log(LOG_ERROR, "Call from '%s@%s' rejected due to no default context\n", pvt->cd.call_source_aliases, pvt->cd.sourceIp); - oh323_destroy(pvt); - return NULL; - } - ast_copy_string(pvt->context, default_context, sizeof(pvt->context)); - if (!ast_strlen_zero(pvt->cd.call_dest_e164)) { - ast_copy_string(pvt->exten, cd->call_dest_e164, sizeof(pvt->exten)); - } else { - ast_copy_string(pvt->exten, cd->call_dest_alias, sizeof(pvt->exten)); - } - if (h323debug) - ast_debug(1, "Sending %s@%s to context [%s] extension %s\n", cd->call_source_aliases, cd->sourceIp, pvt->context, pvt->exten); - } else { - if (user->host) { - if (strcasecmp(cd->sourceIp, ast_inet_ntoa(user->addr.sin_addr))) { - if (ast_strlen_zero(user->context)) { - if (ast_strlen_zero(default_context)) { - ast_log(LOG_ERROR, "Call from '%s' rejected due to non-matching IP address (%s) and no default context\n", user->name, cd->sourceIp); - oh323_destroy(pvt); - ASTOBJ_UNREF(user, oh323_destroy_user); - return NULL; - } - ast_copy_string(pvt->context, default_context, sizeof(pvt->context)); - } else { - ast_copy_string(pvt->context, user->context, sizeof(pvt->context)); - } - pvt->exten[0] = 'i'; - pvt->exten[1] = '\0'; - ast_log(LOG_ERROR, "Call from '%s' rejected due to non-matching IP address (%s)s\n", user->name, cd->sourceIp); - oh323_destroy(pvt); - ASTOBJ_UNREF(user, oh323_destroy_user); - return NULL; /* XXX: Hmmm... Why to setup context if we drop connection immediately??? */ - } - } - ast_copy_string(pvt->context, user->context, sizeof(pvt->context)); - memcpy(&pvt->options, &user->options, sizeof(pvt->options)); - pvt->jointcapability = pvt->options.capability; - if (!ast_strlen_zero(pvt->cd.call_dest_e164)) { - ast_copy_string(pvt->exten, cd->call_dest_e164, sizeof(pvt->exten)); - } else { - ast_copy_string(pvt->exten, cd->call_dest_alias, sizeof(pvt->exten)); - } - if (!ast_strlen_zero(user->accountcode)) { - ast_copy_string(pvt->accountcode, user->accountcode, sizeof(pvt->accountcode)); - } - if (user->amaflags) { - pvt->amaflags = user->amaflags; - } - ASTOBJ_UNREF(user, oh323_destroy_user); - } - } - return &pvt->options; -} - -/*! \brief - * Call-back function to start PBX when OpenH323 ready to serve incoming call - * - * Returns 1 on success - */ -static int answer_call(unsigned call_reference, const char *token) -{ - struct oh323_pvt *pvt; - struct ast_channel *c = NULL; - enum {ext_original, ext_s, ext_i, ext_notexists} try_exten; - char tmp_exten[sizeof(pvt->exten)]; - - if (h323debug) - ast_debug(1, "Preparing Asterisk to answer for %s\n", token); - - /* Find the call or allocate a private structure if call not found */ - pvt = find_call_locked(call_reference, token); - if (!pvt) { - ast_log(LOG_ERROR, "Something is wrong: answer_call\n"); - return 0; - } - /* Check if requested extension@context pair exists in the dialplan */ - ast_copy_string(tmp_exten, pvt->exten, sizeof(tmp_exten)); - - /* Try to find best extension in specified context */ - if ((tmp_exten[0] != '\0') && (tmp_exten[1] == '\0')) { - if (tmp_exten[0] == 's') - try_exten = ext_s; - else if (tmp_exten[0] == 'i') - try_exten = ext_i; - else - try_exten = ext_original; - } else - try_exten = ext_original; - do { - if (ast_exists_extension(NULL, pvt->context, tmp_exten, 1, NULL)) - break; - switch (try_exten) { - case ext_original: - tmp_exten[0] = 's'; - tmp_exten[1] = '\0'; - try_exten = ext_s; - break; - case ext_s: - tmp_exten[0] = 'i'; - try_exten = ext_i; - break; - case ext_i: - try_exten = ext_notexists; - break; - default: - break; - } - } while (try_exten != ext_notexists); - - /* Drop the call if we don't have , s and i extensions */ - if (try_exten == ext_notexists) { - ast_log(LOG_NOTICE, "Dropping call because extensions '%s', 's' and 'i' doesn't exists in context [%s]\n", pvt->exten, pvt->context); - ast_mutex_unlock(&pvt->lock); - h323_clear_call(token, AST_CAUSE_UNALLOCATED); - return 0; - } else if ((try_exten != ext_original) && (strcmp(pvt->exten, tmp_exten) != 0)) { - if (h323debug) - ast_debug(1, "Going to extension %s@%s because %s@%s isn't exists\n", tmp_exten, pvt->context, pvt->exten, pvt->context); - ast_copy_string(pvt->exten, tmp_exten, sizeof(pvt->exten)); - } - - /* allocate a channel and tell asterisk about it */ - c = __oh323_new(pvt, AST_STATE_RINGING, pvt->cd.call_token, NULL, NULL); - - /* And release when done */ - ast_mutex_unlock(&pvt->lock); - if (!c) { - ast_log(LOG_ERROR, "Couldn't create channel. This is bad\n"); - return 0; - } - return 1; -} - -/*! \brief - * Call-back function to establish an outgoing H.323 call - * - * Returns 1 on success - */ -static int setup_outgoing_call(call_details_t *cd) -{ - /* Use argument here or free it immediately */ - cleanup_call_details(cd); - - return 1; -} - -/*! \brief - * Call-back function to signal asterisk that the channel is ringing - * Returns nothing - */ -static void chan_ringing(unsigned call_reference, const char *token) -{ - struct oh323_pvt *pvt; - - if (h323debug) - ast_debug(1, "Ringing on %s\n", token); - - pvt = find_call_locked(call_reference, token); - if (!pvt) { - ast_log(LOG_ERROR, "Something is wrong: ringing\n"); - return; - } - if (!pvt->owner) { - ast_mutex_unlock(&pvt->lock); - ast_log(LOG_ERROR, "Channel has no owner\n"); - return; - } - update_state(pvt, AST_STATE_RINGING, AST_CONTROL_RINGING); - ast_mutex_unlock(&pvt->lock); - return; -} - -/*! \brief - * Call-back function to cleanup communication - * Returns nothing, - */ -static void cleanup_connection(unsigned call_reference, const char *call_token) -{ - struct oh323_pvt *pvt; - - if (h323debug) - ast_debug(1, "Cleaning connection to %s\n", call_token); - - while (1) { - pvt = find_call_locked(call_reference, call_token); - if (!pvt) { - if (h323debug) - ast_debug(1, "No connection for %s\n", call_token); - return; - } - if (!pvt->owner || !ast_channel_trylock(pvt->owner)) - break; -#if 1 - ast_log(LOG_NOTICE, "Avoiding H.323 destory deadlock on %s\n", call_token); -#ifdef DEBUG_THREADS - /* XXX to be completed - * If we want to print more info on who is holding the lock, - * implement the relevant code in lock.h and use the routines - * supplied there. - */ -#endif -#endif - ast_mutex_unlock(&pvt->lock); - usleep(1); - } - if (pvt->rtp) { - /* Immediately stop RTP */ - ast_rtp_instance_destroy(pvt->rtp); - pvt->rtp = NULL; - } - /* Free dsp used for in-band DTMF detection */ - if (pvt->vad) { - ast_dsp_free(pvt->vad); - pvt->vad = NULL; - } - cleanup_call_details(&pvt->cd); - pvt->alreadygone = 1; - /* Send hangup */ - if (pvt->owner) { - ast_channel_softhangup_internal_flag_add(pvt->owner, AST_SOFTHANGUP_DEV); - ast_queue_hangup(pvt->owner); - ast_channel_unlock(pvt->owner); - } - ast_mutex_unlock(&pvt->lock); - if (h323debug) - ast_debug(1, "Connection to %s cleaned\n", call_token); - return; -} - -static void hangup_connection(unsigned int call_reference, const char *token, int cause) -{ - struct oh323_pvt *pvt; - - if (h323debug) - ast_debug(1, "Hanging up connection to %s with cause %d\n", token, cause); - - pvt = find_call_locked(call_reference, token); - if (!pvt) { - if (h323debug) - ast_debug(1, "Connection to %s already cleared\n", token); - return; - } - if (pvt->owner && !ast_channel_trylock(pvt->owner)) { - ast_channel_softhangup_internal_flag_add(pvt->owner, AST_SOFTHANGUP_DEV); - ast_channel_hangupcause_set(pvt->owner, pvt->hangupcause = cause); - ast_queue_hangup_with_cause(pvt->owner, cause); - ast_channel_unlock(pvt->owner); - } - else { - pvt->needhangup = 1; - pvt->hangupcause = cause; - if (h323debug) - ast_debug(1, "Hangup for %s is pending\n", token); - } - ast_mutex_unlock(&pvt->lock); -} - -static void set_dtmf_payload(unsigned call_reference, const char *token, int payload, int is_cisco) -{ - struct oh323_pvt *pvt; - - if (h323debug) - ast_debug(1, "Setting %s DTMF payload to %d on %s\n", (is_cisco ? "Cisco" : "RFC2833"), payload, token); - - pvt = find_call_locked(call_reference, token); - if (!pvt) { - return; - } - if (pvt->rtp) { - ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(pvt->rtp), pvt->rtp, payload, "audio", (is_cisco ? "cisco-telephone-event" : "telephone-event"), 0); - } - pvt->dtmf_pt[is_cisco ? 1 : 0] = payload; - ast_mutex_unlock(&pvt->lock); - if (h323debug) - ast_debug(1, "DTMF payload on %s set to %d\n", token, payload); -} - -static void set_peer_capabilities(unsigned call_reference, const char *token, int capabilities, struct ast_codec_pref *prefs) -{ - struct oh323_pvt *pvt; - - if (h323debug) - ast_debug(1, "Got remote capabilities from connection %s\n", token); - - pvt = find_call_locked(call_reference, token); - if (!pvt) - return; - pvt->peercapability = capabilities; - pvt->jointcapability = pvt->options.capability & capabilities; - if (prefs) { - memcpy(&pvt->peer_prefs, prefs, sizeof(pvt->peer_prefs)); - if (h323debug) { - int i; - for (i = 0; i < 32; ++i) { - if (!prefs->order[i]) - break; - ast_debug(1, "prefs[%d]=%s:%d\n", i, (prefs->order[i] ? ast_getformatname(&prefs->formats[i]) : ""), prefs->framing[i]); - } - } - if (pvt->rtp) { - if (pvt->options.autoframing) { - ast_debug(2, "Autoframing option set, using peer's packetization settings\n"); - ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(pvt->rtp), pvt->rtp, &pvt->peer_prefs); - } else { - ast_debug(2, "Autoframing option not set, ignoring peer's packetization settings\n"); - ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(pvt->rtp), pvt->rtp, &pvt->options.prefs); - } - } - } - ast_mutex_unlock(&pvt->lock); -} - -static void set_local_capabilities(unsigned call_reference, const char *token) -{ - struct oh323_pvt *pvt; - int capability, dtmfmode, pref_codec; - struct ast_codec_pref prefs; - - if (h323debug) - ast_debug(1, "Setting capabilities for connection %s\n", token); - - pvt = find_call_locked(call_reference, token); - if (!pvt) - return; - capability = (pvt->jointcapability) ? pvt->jointcapability : pvt->options.capability; - dtmfmode = pvt->options.dtmfmode; - prefs = pvt->options.prefs; - pref_codec = pvt->pref_codec; - ast_mutex_unlock(&pvt->lock); - h323_set_capabilities(token, capability, dtmfmode, &prefs, pref_codec); - - if (h323debug) { - int i; - for (i = 0; i < 32; i++) { - if (!prefs.order[i]) - break; - ast_debug(1, "local prefs[%d]=%s:%d\n", i, (prefs.order[i] ? ast_getformatname(&prefs.formats[i]) : ""), prefs.framing[i]); - } - ast_debug(1, "Capabilities for connection %s is set\n", token); - } -} - -static void remote_hold(unsigned call_reference, const char *token, int is_hold) -{ - struct oh323_pvt *pvt; - - if (h323debug) - ast_debug(1, "Setting %shold status for connection %s\n", (is_hold ? "" : "un"), token); - - pvt = find_call_locked(call_reference, token); - if (!pvt) - return; - if (pvt->owner && !ast_channel_trylock(pvt->owner)) { - if (is_hold) { - ast_queue_hold(pvt->owner, NULL); - } else { - ast_queue_unhold(pvt->owner); - } - ast_channel_unlock(pvt->owner); - } - else { - if (is_hold) - pvt->newcontrol = AST_CONTROL_HOLD; - else - pvt->newcontrol = AST_CONTROL_UNHOLD; - } - ast_mutex_unlock(&pvt->lock); -} - -static void *do_monitor(void *data) -{ - int res; - int reloading; - struct oh323_pvt *oh323 = NULL; - - for(;;) { - /* Check for a reload request */ - ast_mutex_lock(&h323_reload_lock); - reloading = h323_reloading; - h323_reloading = 0; - ast_mutex_unlock(&h323_reload_lock); - if (reloading) { - ast_verb(1, "Reloading H.323\n"); - h323_do_reload(); - } - /* Check for interfaces needing to be killed */ - if (!ast_mutex_trylock(&iflock)) { -#if 1 - do { - for (oh323 = iflist; oh323; oh323 = oh323->next) { - if (!ast_mutex_trylock(&oh323->lock)) { - if (oh323->needdestroy) { - __oh323_destroy(oh323); - break; - } - ast_mutex_unlock(&oh323->lock); - } - } - } while (/*oh323*/ 0); -#else -restartsearch: - oh323 = iflist; - while(oh323) { - if (!ast_mutex_trylock(&oh323->lock)) { - if (oh323->needdestroy) { - __oh323_destroy(oh323); - goto restartsearch; - } - ast_mutex_unlock(&oh323->lock); - oh323 = oh323->next; - } - } -#endif - ast_mutex_unlock(&iflock); - } else - oh323 = (struct oh323_pvt *)1; /* Force fast loop */ - pthread_testcancel(); - /* Wait for sched or io */ - res = ast_sched_wait(sched); - if ((res < 0) || (res > 1000)) { - res = 1000; - } - /* Do not wait if some channel(s) is destroyed, probably, more available too */ - if (oh323) - res = 1; - res = ast_io_wait(io, res); - pthread_testcancel(); - ast_mutex_lock(&monlock); - if (res >= 0) { - ast_sched_runq(sched); - } - ast_mutex_unlock(&monlock); - } - /* Never reached */ - return NULL; -} - -static int restart_monitor(void) -{ - /* If we're supposed to be stopped -- stay stopped */ - if (ast_mutex_lock(&monlock)) { - ast_log(LOG_WARNING, "Unable to lock monitor\n"); - return -1; - } - if (monitor_thread == AST_PTHREADT_STOP) { - ast_mutex_unlock(&monlock); - return 0; - } - if (monitor_thread == pthread_self()) { - ast_mutex_unlock(&monlock); - ast_log(LOG_WARNING, "Cannot kill myself\n"); - return -1; - } - if (monitor_thread && (monitor_thread != AST_PTHREADT_NULL)) { - /* Wake up the thread */ - pthread_kill(monitor_thread, SIGURG); - } else { - /* Start a new monitor */ - if (ast_pthread_create_background(&monitor_thread, NULL, do_monitor, NULL) < 0) { - monitor_thread = AST_PTHREADT_NULL; - ast_mutex_unlock(&monlock); - ast_log(LOG_ERROR, "Unable to start monitor thread.\n"); - return -1; - } - } - ast_mutex_unlock(&monlock); - return 0; -} - -static char *handle_cli_h323_set_trace(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) -{ - switch (cmd) { - case CLI_INIT: - e->command = "h323 set trace [on|off]"; - e->usage = - "Usage: h323 set trace (on|off|)\n" - " Enable/Disable H.323 stack tracing for debugging purposes\n"; - return NULL; - case CLI_GENERATE: - return NULL; - } - - if (a->argc != e->args) - return CLI_SHOWUSAGE; - if (!strcasecmp(a->argv[3], "off")) { - h323_debug(0, 0); - ast_cli(a->fd, "H.323 Trace Disabled\n"); - } else if (!strcasecmp(a->argv[3], "on")) { - h323_debug(1, 1); - ast_cli(a->fd, "H.323 Trace Enabled\n"); - } else { - int tracelevel = atoi(a->argv[3]); - h323_debug(1, tracelevel); - ast_cli(a->fd, "H.323 Trace Enabled (Trace Level: %d)\n", tracelevel); - } - return CLI_SUCCESS; -} - -static char *handle_cli_h323_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) -{ - switch (cmd) { - case CLI_INIT: - e->command = "h323 set debug [on|off]"; - e->usage = - "Usage: h323 set debug [on|off]\n" - " Enable/Disable H.323 debugging output\n"; - return NULL; - case CLI_GENERATE: - return NULL; - } - - if (a->argc != e->args) - return CLI_SHOWUSAGE; - if (strcasecmp(a->argv[3], "on") && strcasecmp(a->argv[3], "off")) - return CLI_SHOWUSAGE; - - h323debug = (strcasecmp(a->argv[3], "on")) ? 0 : 1; - ast_cli(a->fd, "H.323 Debugging %s\n", h323debug ? "Enabled" : "Disabled"); - return CLI_SUCCESS; -} - -static char *handle_cli_h323_cycle_gk(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) -{ - switch (cmd) { - case CLI_INIT: - e->command = "h323 cycle gk"; - e->usage = - "Usage: h323 cycle gk\n" - " Manually re-register with the Gatekeper (Currently Disabled)\n"; - return NULL; - case CLI_GENERATE: - return NULL; - } - - if (a->argc != 3) - return CLI_SHOWUSAGE; - - h323_gk_urq(); - - /* Possibly register with a GK */ - if (!gatekeeper_disable) { - if (h323_set_gk(gatekeeper_discover, gatekeeper, secret)) { - ast_log(LOG_ERROR, "Gatekeeper registration failed.\n"); - } - } - return CLI_SUCCESS; -} - -static char *handle_cli_h323_hangup(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) -{ - switch (cmd) { - case CLI_INIT: - e->command = "h323 hangup"; - e->usage = - "Usage: h323 hangup \n" - " Manually try to hang up the call identified by \n"; - return NULL; - case CLI_GENERATE: - return NULL; - } - - if (a->argc != 3) - return CLI_SHOWUSAGE; - if (h323_soft_hangup(a->argv[2])) { - ast_verb(3, "Hangup succeeded on %s\n", a->argv[2]); - } else { - ast_verb(3, "Hangup failed for %s\n", a->argv[2]); - } - return CLI_SUCCESS; -} - -static char *handle_cli_h323_show_tokens(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) -{ - switch (cmd) { - case CLI_INIT: - e->command = "h323 show tokens"; - e->usage = - "Usage: h323 show tokens\n" - " Print out all active call tokens\n"; - return NULL; - case CLI_GENERATE: - return NULL; - } - - if (a->argc != 3) - return CLI_SHOWUSAGE; - - h323_show_tokens(); - - return CLI_SUCCESS; -} - -static char *handle_cli_h323_show_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) -{ - switch (cmd) { - case CLI_INIT: - e->command = "h323 show version"; - e->usage = - "Usage: h323 show version\n" - " Show the version of the H.323 library in use\n"; - return NULL; - case CLI_GENERATE: - return NULL; - } - - if (a->argc != 3) - return CLI_SHOWUSAGE; - - h323_show_version(); - - return CLI_SUCCESS; -} - -static struct ast_cli_entry cli_h323[] = { - AST_CLI_DEFINE(handle_cli_h323_set_trace, "Enable/Disable H.323 Stack Tracing"), - AST_CLI_DEFINE(handle_cli_h323_set_debug, "Enable/Disable H.323 Debugging"), - AST_CLI_DEFINE(handle_cli_h323_cycle_gk, "Manually re-register with the Gatekeper"), - AST_CLI_DEFINE(handle_cli_h323_hangup, "Manually try to hang up a call"), - AST_CLI_DEFINE(handle_cli_h323_show_tokens, "Show all active call tokens"), - AST_CLI_DEFINE(handle_cli_h323_show_version, "Show the version of the H.323 library in use"), -}; - -static void delete_users(void) -{ - int pruned = 0; - - /* Delete all users */ - ASTOBJ_CONTAINER_WRLOCK(&userl); - ASTOBJ_CONTAINER_TRAVERSE(&userl, 1, do { - ASTOBJ_RDLOCK(iterator); - ASTOBJ_MARK(iterator); - ++pruned; - ASTOBJ_UNLOCK(iterator); - } while (0) ); - if (pruned) { - ASTOBJ_CONTAINER_PRUNE_MARKED(&userl, oh323_destroy_user); - } - ASTOBJ_CONTAINER_UNLOCK(&userl); - - ASTOBJ_CONTAINER_WRLOCK(&peerl); - ASTOBJ_CONTAINER_TRAVERSE(&peerl, 1, do { - ASTOBJ_RDLOCK(iterator); - ASTOBJ_MARK(iterator); - ASTOBJ_UNLOCK(iterator); - } while (0) ); - ASTOBJ_CONTAINER_UNLOCK(&peerl); -} - -static void delete_aliases(void) -{ - int pruned = 0; - - /* Delete all aliases */ - ASTOBJ_CONTAINER_WRLOCK(&aliasl); - ASTOBJ_CONTAINER_TRAVERSE(&aliasl, 1, do { - ASTOBJ_RDLOCK(iterator); - ASTOBJ_MARK(iterator); - ++pruned; - ASTOBJ_UNLOCK(iterator); - } while (0) ); - if (pruned) { - ASTOBJ_CONTAINER_PRUNE_MARKED(&aliasl, oh323_destroy_alias); - } - ASTOBJ_CONTAINER_UNLOCK(&aliasl); -} - -static void prune_peers(void) -{ - /* Prune peers who still are supposed to be deleted */ - ASTOBJ_CONTAINER_PRUNE_MARKED(&peerl, oh323_destroy_peer); -} - -static int reload_config(int is_reload) -{ - struct ast_config *cfg, *ucfg; - struct ast_variable *v; - struct oh323_peer *peer = NULL; - struct oh323_user *user = NULL; - struct oh323_alias *alias = NULL; - struct ast_hostent ahp; struct hostent *hp; - char *cat; - const char *utype; - int is_user, is_peer, is_alias; - char _gatekeeper[100]; - int gk_discover, gk_disable, gk_changed; - struct ast_flags config_flags = { is_reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; - - cfg = ast_config_load(config, config_flags); - - /* We *must* have a config file otherwise stop immediately */ - if (!cfg) { - ast_log(LOG_NOTICE, "Unable to load config %s, H.323 disabled\n", config); - return 1; - } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) { - ucfg = ast_config_load("users.conf", config_flags); - if (ucfg == CONFIG_STATUS_FILEUNCHANGED) { - return 0; - } else if (ucfg == CONFIG_STATUS_FILEINVALID) { - ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Aborting.\n"); - return 0; - } - ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED); - if ((cfg = ast_config_load(config, config_flags)) == CONFIG_STATUS_FILEINVALID) { - ast_log(LOG_ERROR, "Config file %s is in an invalid format. Aborting.\n", config); - ast_config_destroy(ucfg); - return 0; - } - } else if (cfg == CONFIG_STATUS_FILEINVALID) { - ast_log(LOG_ERROR, "Config file %s is in an invalid format. Aborting.\n", config); - return 0; - } else { - ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED); - if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) { - ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Aborting.\n"); - ast_config_destroy(cfg); - return 0; - } - } - - if (is_reload) { - delete_users(); - delete_aliases(); - prune_peers(); - } - - /* fire up the H.323 Endpoint */ - if (!h323_end_point_exist()) { - h323_end_point_create(); - } - ast_copy_string(_gatekeeper, gatekeeper, sizeof(_gatekeeper)); - gk_discover = gatekeeper_discover; - gk_disable = gatekeeper_disable; - memset(&bindaddr, 0, sizeof(bindaddr)); - memset(&global_options, 0, sizeof(global_options)); - global_options.fastStart = 1; - global_options.h245Tunneling = 1; - global_options.dtmfcodec[0] = H323_DTMF_RFC2833_PT; - global_options.dtmfcodec[1] = H323_DTMF_CISCO_PT; - global_options.dtmfmode = 0; - global_options.holdHandling = 0; - global_options.capability = GLOBAL_CAPABILITY; - global_options.bridge = 1; /* Do native bridging by default */ - global_options.autoframing = 0; - strcpy(default_context, "default"); - h323_signalling_port = 1720; - gatekeeper_disable = 1; - gatekeeper_discover = 0; - gkroute = 0; - userbyalias = 1; - acceptAnonymous = 1; - tos = 0; - cos = 0; - - /* Copy the default jb config over global_jbconf */ - memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf)); - - if (ucfg) { - struct ast_variable *gen; - int genhas_h323; - const char *has_h323; - - genhas_h323 = ast_true(ast_variable_retrieve(ucfg, "general", "hash323")); - gen = ast_variable_browse(ucfg, "general"); - for (cat = ast_category_browse(ucfg, NULL); cat; cat = ast_category_browse(ucfg, cat)) { - if (strcasecmp(cat, "general")) { - has_h323 = ast_variable_retrieve(ucfg, cat, "hash323"); - if (ast_true(has_h323) || (!has_h323 && genhas_h323)) { - user = build_user(cat, gen, ast_variable_browse(ucfg, cat), 0); - if (user) { - ASTOBJ_CONTAINER_LINK(&userl, user); - ASTOBJ_UNREF(user, oh323_destroy_user); - } - peer = build_peer(cat, gen, ast_variable_browse(ucfg, cat), 0); - if (peer) { - ASTOBJ_CONTAINER_LINK(&peerl, peer); - ASTOBJ_UNREF(peer, oh323_destroy_peer); - } - } - } - } - ast_config_destroy(ucfg); - } - - for (v = ast_variable_browse(cfg, "general"); v; v = v->next) { - /* handle jb conf */ - if (!ast_jb_read_conf(&global_jbconf, v->name, v->value)) - continue; - /* Create the interface list */ - if (!strcasecmp(v->name, "port")) { - h323_signalling_port = (int)strtol(v->value, NULL, 10); - } else if (!strcasecmp(v->name, "bindaddr")) { - if (!(hp = ast_gethostbyname(v->value, &ahp))) { - ast_log(LOG_WARNING, "Invalid address: %s\n", v->value); - } else { - memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr)); - } - } else if (!strcasecmp(v->name, "tos")) { /* Needs to be removed in next release */ - ast_log(LOG_WARNING, "The \"tos\" setting is deprecated in this version of Asterisk. Please change to \"tos_audio\".\n"); - if (ast_str2tos(v->value, &tos)) { - ast_log(LOG_WARNING, "Invalid tos_audio value at line %d, refer to QoS documentation\n", v->lineno); - } - } else if (!strcasecmp(v->name, "tos_audio")) { - if (ast_str2tos(v->value, &tos)) { - ast_log(LOG_WARNING, "Invalid tos_audio value at line %d, refer to QoS documentation\n", v->lineno); - } - } else if (!strcasecmp(v->name, "cos")) { - ast_log(LOG_WARNING, "The \"cos\" setting is deprecated in this version of Asterisk. Please change to \"cos_audio\".\n"); - if (ast_str2cos(v->value, &cos)) { - ast_log(LOG_WARNING, "Invalid cos_audio value at line %d, refer to QoS documentation\n", v->lineno); - } - } else if (!strcasecmp(v->name, "cos_audio")) { - if (ast_str2cos(v->value, &cos)) { - ast_log(LOG_WARNING, "Invalid cos_audio value at line %d, refer to QoS documentation\n", v->lineno); - } - } else if (!strcasecmp(v->name, "gatekeeper")) { - if (!strcasecmp(v->value, "DISABLE")) { - gatekeeper_disable = 1; - } else if (!strcasecmp(v->value, "DISCOVER")) { - gatekeeper_disable = 0; - gatekeeper_discover = 1; - } else { - gatekeeper_disable = 0; - ast_copy_string(gatekeeper, v->value, sizeof(gatekeeper)); - } - } else if (!strcasecmp(v->name, "secret")) { - ast_copy_string(secret, v->value, sizeof(secret)); - } else if (!strcasecmp(v->name, "AllowGKRouted")) { - gkroute = ast_true(v->value); - } else if (!strcasecmp(v->name, "context")) { - ast_copy_string(default_context, v->value, sizeof(default_context)); - ast_verb(2, "Setting default context to %s\n", default_context); - } else if (!strcasecmp(v->name, "UserByAlias")) { - userbyalias = ast_true(v->value); - } else if (!strcasecmp(v->name, "AcceptAnonymous")) { - acceptAnonymous = ast_true(v->value); - } else if (!update_common_options(v, &global_options)) { - /* dummy */ - } - } - if (!global_options.dtmfmode) - global_options.dtmfmode = H323_DTMF_RFC2833; - if (global_options.holdHandling == ~0) - global_options.holdHandling = 0; - else if (!global_options.holdHandling) - global_options.holdHandling = H323_HOLD_H450; - - for (cat = ast_category_browse(cfg, NULL); cat; cat = ast_category_browse(cfg, cat)) { - if (strcasecmp(cat, "general")) { - utype = ast_variable_retrieve(cfg, cat, "type"); - if (utype) { - is_user = is_peer = is_alias = 0; - if (!strcasecmp(utype, "user")) - is_user = 1; - else if (!strcasecmp(utype, "peer")) - is_peer = 1; - else if (!strcasecmp(utype, "friend")) - is_user = is_peer = 1; - else if (!strcasecmp(utype, "h323") || !strcasecmp(utype, "alias")) - is_alias = 1; - else { - ast_log(LOG_WARNING, "Unknown type '%s' for '%s' in %s\n", utype, cat, config); - continue; - } - if (is_user) { - user = build_user(cat, ast_variable_browse(cfg, cat), NULL, 0); - if (user) { - ASTOBJ_CONTAINER_LINK(&userl, user); - ASTOBJ_UNREF(user, oh323_destroy_user); - } - } - if (is_peer) { - peer = build_peer(cat, ast_variable_browse(cfg, cat), NULL, 0); - if (peer) { - ASTOBJ_CONTAINER_LINK(&peerl, peer); - ASTOBJ_UNREF(peer, oh323_destroy_peer); - } - } - if (is_alias) { - alias = build_alias(cat, ast_variable_browse(cfg, cat), NULL, 0); - if (alias) { - ASTOBJ_CONTAINER_LINK(&aliasl, alias); - ASTOBJ_UNREF(alias, oh323_destroy_alias); - } - } - } else { - ast_log(LOG_WARNING, "Section '%s' lacks type\n", cat); - } - } - } - ast_config_destroy(cfg); - - /* Register our H.323 aliases if any*/ - ASTOBJ_CONTAINER_WRLOCK(&aliasl); - ASTOBJ_CONTAINER_TRAVERSE(&aliasl, 1, do { - ASTOBJ_RDLOCK(iterator); - if (h323_set_alias(iterator)) { - ast_log(LOG_ERROR, "Alias %s rejected by endpoint\n", alias->name); - ASTOBJ_UNLOCK(iterator); - continue; - } - ASTOBJ_UNLOCK(iterator); - } while (0) ); - ASTOBJ_CONTAINER_UNLOCK(&aliasl); - - /* Don't touch GK if nothing changed because URQ will drop all existing calls */ - gk_changed = 0; - if (gatekeeper_disable != gk_disable) - gk_changed = is_reload; - else if(!gatekeeper_disable && (gatekeeper_discover != gk_discover)) - gk_changed = is_reload; - else if(!gatekeeper_disable && (strncmp(_gatekeeper, gatekeeper, sizeof(_gatekeeper)) != 0)) - gk_changed = is_reload; - if (gk_changed) { - if(!gk_disable) - h323_gk_urq(); - if (!gatekeeper_disable) { - if (h323_set_gk(gatekeeper_discover, gatekeeper, secret)) { - ast_log(LOG_ERROR, "Gatekeeper registration failed.\n"); - gatekeeper_disable = 1; - } - } - } - return 0; -} - -static int h323_reload(void) -{ - ast_mutex_lock(&h323_reload_lock); - if (h323_reloading) { - ast_verbose("Previous H.323 reload not yet done\n"); - } else { - h323_reloading = 1; - } - ast_mutex_unlock(&h323_reload_lock); - restart_monitor(); - return 0; -} - -static char *handle_cli_h323_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) -{ - switch (cmd) { - case CLI_INIT: - e->command = "h323 reload"; - e->usage = - "Usage: h323 reload\n" - " Reloads H.323 configuration from h323.conf\n"; - return NULL; - case CLI_GENERATE: - return NULL; - } - - if (a->argc != 2) - return CLI_SHOWUSAGE; - - h323_reload(); - - return CLI_SUCCESS; -} - -static int h323_do_reload(void) -{ - reload_config(1); - return 0; -} - -static int reload(void) -{ - if (!sched || !io) { - ast_log(LOG_NOTICE, "Unload and load chan_h323.so again in order to receive configuration changes.\n"); - return 0; - } - return h323_reload(); -} - -static struct ast_cli_entry cli_h323_reload = - AST_CLI_DEFINE(handle_cli_h323_reload, "Reload H.323 configuration"); - -static enum ast_rtp_glue_result oh323_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance) -{ - struct oh323_pvt *pvt; - enum ast_rtp_glue_result res = AST_RTP_GLUE_RESULT_LOCAL; - - if (!(pvt = (struct oh323_pvt *)ast_channel_tech_pvt(chan))) - return AST_RTP_GLUE_RESULT_FORBID; - - ast_mutex_lock(&pvt->lock); - *instance = pvt->rtp ? ao2_ref(pvt->rtp, +1), pvt->rtp : NULL; -#if 0 - if (pvt->options.bridge) { - res = AST_RTP_GLUE_RESULT_REMOTE; - } -#endif - ast_mutex_unlock(&pvt->lock); - - return res; -} - -#if 0 -static char *convertcap(struct ast_format *format) -{ - switch (format->id) { - case AST_FORMAT_G723_1: - return "G.723"; - case AST_FORMAT_GSM: - return "GSM"; - case AST_FORMAT_ULAW: - return "ULAW"; - case AST_FORMAT_ALAW: - return "ALAW"; - case AST_FORMAT_G722: - return "G.722"; - case AST_FORMAT_ADPCM: - return "G.728"; - case AST_FORMAT_G729A: - return "G.729"; - case AST_FORMAT_SPEEX: - return "SPEEX"; - case AST_FORMAT_ILBC: - return "ILBC"; - default: - ast_log(LOG_NOTICE, "Don't know how to deal with mode %s\n", ast_getformatname(format)); - return NULL; - } -} -#endif - -static int oh323_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *rtp, struct ast_rtp_instance *vrtp, struct ast_rtp_instance *trtp, const struct ast_format_cap *codecs, int nat_active) -{ - /* XXX Deal with Video */ - struct oh323_pvt *pvt; - struct sockaddr_in them = { 0, }; - struct sockaddr_in us = { 0, }; -#if 0 /* Native bridge still isn't ready */ - char *mode; -#endif - - if (!rtp) { - return 0; - } - -#if 0 /* Native bridge still isn't ready */ - mode = convertcap(&chan->writeformat); -#endif - - pvt = (struct oh323_pvt *) ast_channel_tech_pvt(chan); - if (!pvt) { - ast_log(LOG_ERROR, "No Private Structure, this is bad\n"); - return -1; - } - { - struct ast_sockaddr tmp; - - ast_rtp_instance_get_remote_address(rtp, &tmp); - ast_sockaddr_to_sin(&tmp, &them); - ast_rtp_instance_get_local_address(rtp, &tmp); - ast_sockaddr_to_sin(&tmp, &us); - } -#if 0 /* Native bridge still isn't ready */ - h323_native_bridge(pvt->cd.call_token, ast_inet_ntoa(them.sin_addr), mode); -#endif - return 0; -} - -static struct ast_rtp_glue oh323_rtp_glue = { - .type = "H323", - .get_rtp_info = oh323_get_rtp_peer, - .update_peer = oh323_set_rtp_peer, -}; - -static enum ast_module_load_result load_module(void) -{ - int res; - - if (!(oh323_tech.capabilities = ast_format_cap_alloc(0))) { - return AST_MODULE_LOAD_FAILURE; - } - ast_format_cap_add_all_by_type(oh323_tech.capabilities, AST_FORMAT_TYPE_AUDIO); - - h323debug = 0; - sched = ast_sched_context_create(); - if (!sched) { - ast_log(LOG_WARNING, "Unable to create schedule context\n"); - return AST_MODULE_LOAD_FAILURE; - } - io = io_context_create(); - if (!io) { - ast_log(LOG_WARNING, "Unable to create I/O context\n"); - return AST_MODULE_LOAD_FAILURE; - } - ast_cli_register(&cli_h323_reload); - ASTOBJ_CONTAINER_INIT(&userl); - ASTOBJ_CONTAINER_INIT(&peerl); - ASTOBJ_CONTAINER_INIT(&aliasl); - res = reload_config(0); - if (res) { - /* No config entry */ - ast_log(LOG_NOTICE, "Unload and load chan_h323.so again in order to receive configuration changes.\n"); - ast_cli_unregister(&cli_h323_reload); - io_context_destroy(io); - io = NULL; - ast_sched_context_destroy(sched); - sched = NULL; - ASTOBJ_CONTAINER_DESTROY(&userl); - ASTOBJ_CONTAINER_DESTROY(&peerl); - ASTOBJ_CONTAINER_DESTROY(&aliasl); - return AST_MODULE_LOAD_DECLINE; - } else { - /* Make sure we can register our channel type */ - if (ast_channel_register(&oh323_tech)) { - ast_log(LOG_ERROR, "Unable to register channel class 'H323'\n"); - ast_cli_unregister(&cli_h323_reload); - h323_end_process(); - io_context_destroy(io); - ast_sched_context_destroy(sched); - - ASTOBJ_CONTAINER_DESTROYALL(&userl, oh323_destroy_user); - ASTOBJ_CONTAINER_DESTROY(&userl); - ASTOBJ_CONTAINER_DESTROYALL(&peerl, oh323_destroy_peer); - ASTOBJ_CONTAINER_DESTROY(&peerl); - ASTOBJ_CONTAINER_DESTROYALL(&aliasl, oh323_destroy_alias); - ASTOBJ_CONTAINER_DESTROY(&aliasl); - - return AST_MODULE_LOAD_FAILURE; - } - ast_cli_register_multiple(cli_h323, sizeof(cli_h323) / sizeof(struct ast_cli_entry)); - - ast_rtp_glue_register(&oh323_rtp_glue); - - /* Register our callback functions */ - h323_callback_register(setup_incoming_call, - setup_outgoing_call, - external_rtp_create, - setup_rtp_connection, - cleanup_connection, - chan_ringing, - connection_made, - receive_digit, - answer_call, - progress, - set_dtmf_payload, - hangup_connection, - set_local_capabilities, - set_peer_capabilities, - remote_hold); - /* start the h.323 listener */ - if (h323_start_listener(h323_signalling_port, bindaddr)) { - ast_log(LOG_ERROR, "Unable to create H323 listener.\n"); - ast_rtp_glue_unregister(&oh323_rtp_glue); - ast_cli_unregister_multiple(cli_h323, sizeof(cli_h323) / sizeof(struct ast_cli_entry)); - ast_cli_unregister(&cli_h323_reload); - h323_end_process(); - io_context_destroy(io); - ast_sched_context_destroy(sched); - - ASTOBJ_CONTAINER_DESTROYALL(&userl, oh323_destroy_user); - ASTOBJ_CONTAINER_DESTROY(&userl); - ASTOBJ_CONTAINER_DESTROYALL(&peerl, oh323_destroy_peer); - ASTOBJ_CONTAINER_DESTROY(&peerl); - ASTOBJ_CONTAINER_DESTROYALL(&aliasl, oh323_destroy_alias); - ASTOBJ_CONTAINER_DESTROY(&aliasl); - - return AST_MODULE_LOAD_DECLINE; - } - /* Possibly register with a GK */ - if (!gatekeeper_disable) { - if (h323_set_gk(gatekeeper_discover, gatekeeper, secret)) { - ast_log(LOG_ERROR, "Gatekeeper registration failed.\n"); - gatekeeper_disable = 1; - res = AST_MODULE_LOAD_SUCCESS; - } - } - /* And start the monitor for the first time */ - restart_monitor(); - } - return res; -} - -static int unload_module(void) -{ - struct oh323_pvt *p, *pl; - - /* unregister commands */ - ast_cli_unregister_multiple(cli_h323, sizeof(cli_h323) / sizeof(struct ast_cli_entry)); - ast_cli_unregister(&cli_h323_reload); - - ast_channel_unregister(&oh323_tech); - ast_rtp_glue_unregister(&oh323_rtp_glue); - - if (!ast_mutex_lock(&iflock)) { - /* hangup all interfaces if they have an owner */ - p = iflist; - while(p) { - if (p->owner) { - ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD); - } - p = p->next; - } - iflist = NULL; - ast_mutex_unlock(&iflock); - } else { - ast_log(LOG_WARNING, "Unable to lock the interface list\n"); - return -1; - } - if (!ast_mutex_lock(&monlock)) { - if ((monitor_thread != AST_PTHREADT_STOP) && (monitor_thread != AST_PTHREADT_NULL)) { - if (monitor_thread != pthread_self()) { - pthread_cancel(monitor_thread); - } - pthread_kill(monitor_thread, SIGURG); - pthread_join(monitor_thread, NULL); - } - monitor_thread = AST_PTHREADT_STOP; - ast_mutex_unlock(&monlock); - } else { - ast_log(LOG_WARNING, "Unable to lock the monitor\n"); - return -1; - } - if (!ast_mutex_lock(&iflock)) { - /* destroy all the interfaces and free their memory */ - p = iflist; - while(p) { - pl = p; - p = p->next; - /* free associated memory */ - ast_mutex_destroy(&pl->lock); - ast_free(pl); - } - iflist = NULL; - ast_mutex_unlock(&iflock); - } else { - ast_log(LOG_WARNING, "Unable to lock the interface list\n"); - return -1; - } - if (!gatekeeper_disable) - h323_gk_urq(); - h323_end_process(); - if (io) - io_context_destroy(io); - if (sched) - ast_sched_context_destroy(sched); - - ASTOBJ_CONTAINER_DESTROYALL(&userl, oh323_destroy_user); - ASTOBJ_CONTAINER_DESTROY(&userl); - ASTOBJ_CONTAINER_DESTROYALL(&peerl, oh323_destroy_peer); - ASTOBJ_CONTAINER_DESTROY(&peerl); - ASTOBJ_CONTAINER_DESTROYALL(&aliasl, oh323_destroy_alias); - ASTOBJ_CONTAINER_DESTROY(&aliasl); - - oh323_tech.capabilities = ast_format_cap_destroy(oh323_tech.capabilities); - return 0; -} - -AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "The NuFone Network's OpenH323 Channel Driver", - .load = load_module, - .unload = unload_module, - .reload = reload, - .load_pri = AST_MODPRI_CHANNEL_DRIVER, -); diff --git a/channels/chan_jingle.c b/channels/chan_jingle.c deleted file mode 100644 index 68d9848e240..00000000000 --- a/channels/chan_jingle.c +++ /dev/null @@ -1,2090 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 1999 - 2005, Digium, Inc. - * - * Matt O'Gorman - * - * 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 - * - * \author Matt O'Gorman - * - * \brief Jingle Channel Driver - * - * Iksemel http://iksemel.jabberstudio.org/ - * - * \ingroup channel_drivers - */ - -/*! \li \ref chan_jingle.c uses the configuration file \ref jingle.conf - * \addtogroup configuration_file - */ - -/*! \page jingle.conf jingle.conf - * \verbinclude jingle.conf.sample - */ - -/*** MODULEINFO - iksemel - res_jabber - openssl - no - deprecated - chan_motif - ***/ - -#include "asterisk.h" - -ASTERISK_FILE_VERSION(__FILE__, "$Revision$") - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "asterisk/lock.h" -#include "asterisk/channel.h" -#include "asterisk/config.h" -#include "asterisk/module.h" -#include "asterisk/pbx.h" -#include "asterisk/sched.h" -#include "asterisk/io.h" -#include "asterisk/rtp_engine.h" -#include "asterisk/acl.h" -#include "asterisk/callerid.h" -#include "asterisk/file.h" -#include "asterisk/cli.h" -#include "asterisk/app.h" -#include "asterisk/musiconhold.h" -#include "asterisk/manager.h" -#include "asterisk/stringfields.h" -#include "asterisk/utils.h" -#include "asterisk/causes.h" -#include "asterisk/astobj.h" -#include "asterisk/abstract_jb.h" -#include "asterisk/jabber.h" -#include "asterisk/jingle.h" -#include "asterisk/stasis_channels.h" - -#define JINGLE_CONFIG "jingle.conf" - -/*! Global jitterbuffer configuration - by default, jb is disabled */ -static struct ast_jb_conf default_jbconf = -{ - .flags = 0, - .max_size = -1, - .resync_threshold = -1, - .impl = "", - .target_extra = -1, -}; -static struct ast_jb_conf global_jbconf; - -enum jingle_protocol { - AJI_PROTOCOL_UDP, - AJI_PROTOCOL_SSLTCP, -}; - -enum jingle_connect_type { - AJI_CONNECT_HOST, - AJI_CONNECT_PRFLX, - AJI_CONNECT_RELAY, - AJI_CONNECT_SRFLX, -}; - -struct jingle_pvt { - ast_mutex_t lock; /*!< Channel private lock */ - time_t laststun; - struct jingle *parent; /*!< Parent client */ - char sid[100]; - char them[AJI_MAX_JIDLEN]; - char ring[10]; /*!< Message ID of ring */ - iksrule *ringrule; /*!< Rule for matching RING request */ - int initiator; /*!< If we're the initiator */ - int alreadygone; - struct ast_codec_pref prefs; - struct jingle_candidate *theircandidates; - struct jingle_candidate *ourcandidates; - char cid_num[80]; /*!< Caller ID num */ - char cid_name[80]; /*!< Caller ID name */ - char exten[80]; /*!< Called extension */ - struct ast_channel *owner; /*!< Master Channel */ - char audio_content_name[100]; /*!< name attribute of content tag */ - struct ast_rtp_instance *rtp; /*!< RTP audio session */ - char video_content_name[100]; /*!< name attribute of content tag */ - struct ast_rtp_instance *vrtp; /*!< RTP video session */ - struct ast_format_cap *cap; - struct ast_format_cap *jointcap; /*!< Supported capability at both ends (codecs ) */ - struct ast_format_cap *peercap; - struct jingle_pvt *next; /* Next entity */ -}; - -struct jingle_candidate { - unsigned int component; /*!< ex. : 1 for RTP, 2 for RTCP */ - unsigned int foundation; /*!< Function of IP, protocol, type */ - unsigned int generation; - char ip[16]; - unsigned int network; - unsigned int port; - unsigned int priority; - enum jingle_protocol protocol; - char password[100]; - enum jingle_connect_type type; - char ufrag[100]; - unsigned int preference; - struct jingle_candidate *next; -}; - -struct jingle { - ASTOBJ_COMPONENTS(struct jingle); - struct aji_client *connection; - struct aji_buddy *buddy; - struct jingle_pvt *p; - struct ast_codec_pref prefs; - int amaflags; /*!< AMA Flags */ - char user[100]; - char context[100]; - char accountcode[AST_MAX_ACCOUNT_CODE]; /*!< Account code */ - struct ast_format_cap *cap; - ast_group_t callgroup; /*!< Call group */ - ast_group_t pickupgroup; /*!< Pickup group */ - int callingpres; /*!< Calling presentation */ - int allowguest; - char language[MAX_LANGUAGE]; /*!< Default language for prompts */ - char musicclass[MAX_MUSICCLASS]; /*!< Music on Hold class */ - char parkinglot[AST_MAX_CONTEXT]; /*!< Parkinglot */ -}; - -struct jingle_container { - ASTOBJ_CONTAINER_COMPONENTS(struct jingle); -}; - -static const char desc[] = "Jingle Channel"; -static const char channel_type[] = "Jingle"; - -static struct ast_format_cap *global_capability; - -AST_MUTEX_DEFINE_STATIC(jinglelock); /*!< Protect the interface list (of jingle_pvt's) */ - -/* Forward declarations */ -static struct ast_channel *jingle_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause); -static int jingle_sendtext(struct ast_channel *ast, const char *text); -static int jingle_digit_begin(struct ast_channel *ast, char digit); -static int jingle_digit_end(struct ast_channel *ast, char digit, unsigned int duration); -static int jingle_call(struct ast_channel *ast, const char *dest, int timeout); -static int jingle_hangup(struct ast_channel *ast); -static int jingle_answer(struct ast_channel *ast); -static int jingle_newcall(struct jingle *client, ikspak *pak); -static struct ast_frame *jingle_read(struct ast_channel *ast); -static int jingle_write(struct ast_channel *ast, struct ast_frame *f); -static int jingle_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen); -static int jingle_fixup(struct ast_channel *oldchan, struct ast_channel *newchan); -static int jingle_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen); -static struct jingle_pvt *jingle_alloc(struct jingle *client, const char *from, const char *sid); -static char *jingle_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a); -static char *jingle_do_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a); -static void jingle_set_owner(struct jingle_pvt *pvt, struct ast_channel *chan); - -/*! \brief PBX interface structure for channel registration */ -static struct ast_channel_tech jingle_tech = { - .type = "Jingle", - .description = "Jingle Channel Driver", - .requester = jingle_request, - .send_text = jingle_sendtext, - .send_digit_begin = jingle_digit_begin, - .send_digit_end = jingle_digit_end, - .call = jingle_call, - .hangup = jingle_hangup, - .answer = jingle_answer, - .read = jingle_read, - .write = jingle_write, - .exception = jingle_read, - .indicate = jingle_indicate, - .fixup = jingle_fixup, - .send_html = jingle_sendhtml, - .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER -}; - -static struct sockaddr_in bindaddr = { 0, }; /*!< The address we bind to */ - -static struct ast_sched_context *sched; /*!< The scheduling context */ -static struct io_context *io; /*!< The IO context */ -static struct in_addr __ourip; - -static struct ast_cli_entry jingle_cli[] = { - AST_CLI_DEFINE(jingle_do_reload, "Reload Jingle configuration"), - AST_CLI_DEFINE(jingle_show_channels, "Show Jingle channels"), -}; - - -static char externip[16]; - -static struct jingle_container jingle_list; - -static void jingle_member_destroy(struct jingle *obj) -{ - obj->cap = ast_format_cap_destroy(obj->cap); - if (obj->connection) { - ASTOBJ_UNREF(obj->connection, ast_aji_client_destroy); - } - if (obj->buddy) { - ASTOBJ_UNREF(obj->buddy, ast_aji_buddy_destroy); - } - ast_free(obj); -} - -/* XXX This could be a source of reference leaks given that the CONTAINER_FIND - * macros bump the refcount while the traversal does not. */ -static struct jingle *find_jingle(char *name, char *connection) -{ - struct jingle *jingle = NULL; - - jingle = ASTOBJ_CONTAINER_FIND(&jingle_list, name); - if (!jingle && strchr(name, '@')) - jingle = ASTOBJ_CONTAINER_FIND_FULL(&jingle_list, name, user,,, strcasecmp); - - if (!jingle) { - /* guest call */ - ASTOBJ_CONTAINER_TRAVERSE(&jingle_list, 1, { - ASTOBJ_RDLOCK(iterator); - if (!strcasecmp(iterator->name, "guest")) { - jingle = iterator; - } - ASTOBJ_UNLOCK(iterator); - - if (jingle) - break; - }); - - } - return jingle; -} - - -static void add_codec_to_answer(const struct jingle_pvt *p, struct ast_format *codec, iks *dcodecs) -{ - const char *format = ast_getformatname(codec); - - if (!strcasecmp("ulaw", format)) { - iks *payload_eg711u, *payload_pcmu; - payload_pcmu = iks_new("payload-type"); - iks_insert_attrib(payload_pcmu, "id", "0"); - iks_insert_attrib(payload_pcmu, "name", "PCMU"); - payload_eg711u = iks_new("payload-type"); - iks_insert_attrib(payload_eg711u, "id", "100"); - iks_insert_attrib(payload_eg711u, "name", "EG711U"); - iks_insert_node(dcodecs, payload_pcmu); - iks_insert_node(dcodecs, payload_eg711u); - } - if (!strcasecmp("alaw", format)) { - iks *payload_eg711a; - iks *payload_pcma = iks_new("payload-type"); - iks_insert_attrib(payload_pcma, "id", "8"); - iks_insert_attrib(payload_pcma, "name", "PCMA"); - payload_eg711a = iks_new("payload-type"); - iks_insert_attrib(payload_eg711a, "id", "101"); - iks_insert_attrib(payload_eg711a, "name", "EG711A"); - iks_insert_node(dcodecs, payload_pcma); - iks_insert_node(dcodecs, payload_eg711a); - } - if (!strcasecmp("ilbc", format)) { - iks *payload_ilbc = iks_new("payload-type"); - iks_insert_attrib(payload_ilbc, "id", "97"); - iks_insert_attrib(payload_ilbc, "name", "iLBC"); - iks_insert_node(dcodecs, payload_ilbc); - } - if (!strcasecmp("g723", format)) { - iks *payload_g723 = iks_new("payload-type"); - iks_insert_attrib(payload_g723, "id", "4"); - iks_insert_attrib(payload_g723, "name", "G723"); - iks_insert_node(dcodecs, payload_g723); - } -} - -static int jingle_accept_call(struct jingle *client, struct jingle_pvt *p) -{ - struct jingle_pvt *tmp = client->p; - struct aji_client *c = client->connection; - iks *iq, *jingle, *dcodecs, *payload_red, *payload_audio, *payload_cn; - int x; - struct ast_format pref_codec; - struct ast_format_cap *alreadysent = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); - - if (p->initiator || !alreadysent) - return 1; - - iq = iks_new("iq"); - jingle = iks_new(JINGLE_NODE); - dcodecs = iks_new("description"); - if (iq && jingle && dcodecs) { - iks_insert_attrib(dcodecs, "xmlns", JINGLE_AUDIO_RTP_NS); - - for (x = 0; x < AST_CODEC_PREF_SIZE; x++) { - if (!(ast_codec_pref_index(&client->prefs, x, &pref_codec))) - break; - if (!(ast_format_cap_iscompatible(client->cap, &pref_codec))) - continue; - if ((ast_format_cap_iscompatible(alreadysent, &pref_codec))) - continue; - add_codec_to_answer(p, &pref_codec, dcodecs); - ast_format_cap_add(alreadysent, &pref_codec); - } - payload_red = iks_new("payload-type"); - iks_insert_attrib(payload_red, "id", "117"); - iks_insert_attrib(payload_red, "name", "red"); - payload_audio = iks_new("payload-type"); - iks_insert_attrib(payload_audio, "id", "106"); - iks_insert_attrib(payload_audio, "name", "audio/telephone-event"); - payload_cn = iks_new("payload-type"); - iks_insert_attrib(payload_cn, "id", "13"); - iks_insert_attrib(payload_cn, "name", "CN"); - - - iks_insert_attrib(iq, "type", "set"); - iks_insert_attrib(iq, "to", (p->them) ? p->them : client->user); - iks_insert_attrib(iq, "id", client->connection->mid); - ast_aji_increment_mid(client->connection->mid); - - iks_insert_attrib(jingle, "xmlns", JINGLE_NS); - iks_insert_attrib(jingle, "action", JINGLE_ACCEPT); - iks_insert_attrib(jingle, "initiator", p->initiator ? client->connection->jid->full : p->them); - iks_insert_attrib(jingle, JINGLE_SID, tmp->sid); - iks_insert_node(iq, jingle); - iks_insert_node(jingle, dcodecs); - iks_insert_node(dcodecs, payload_red); - iks_insert_node(dcodecs, payload_audio); - iks_insert_node(dcodecs, payload_cn); - - ast_aji_send(c, iq); - - iks_delete(payload_red); - iks_delete(payload_audio); - iks_delete(payload_cn); - iks_delete(dcodecs); - iks_delete(jingle); - iks_delete(iq); - } - alreadysent = ast_format_cap_destroy(alreadysent); - return 1; -} - -static int jingle_ringing_ack(void *data, ikspak *pak) -{ - struct jingle_pvt *p = data; - - if (p->ringrule) - iks_filter_remove_rule(p->parent->connection->f, p->ringrule); - p->ringrule = NULL; - if (p->owner) - ast_queue_control(p->owner, AST_CONTROL_RINGING); - return IKS_FILTER_EAT; -} - -static int jingle_answer(struct ast_channel *ast) -{ - struct jingle_pvt *p = ast_channel_tech_pvt(ast); - struct jingle *client = p->parent; - int res = 0; - - ast_debug(1, "Answer!\n"); - ast_mutex_lock(&p->lock); - jingle_accept_call(client, p); - ast_mutex_unlock(&p->lock); - return res; -} - -static enum ast_rtp_glue_result jingle_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance) -{ - struct jingle_pvt *p = ast_channel_tech_pvt(chan); - enum ast_rtp_glue_result res = AST_RTP_GLUE_RESULT_FORBID; - - if (!p) - return res; - - ast_mutex_lock(&p->lock); - if (p->rtp) { - ao2_ref(p->rtp, +1); - *instance = p->rtp; - res = AST_RTP_GLUE_RESULT_LOCAL; - } - ast_mutex_unlock(&p->lock); - - return res; -} - -static void jingle_get_codec(struct ast_channel *chan, struct ast_format_cap *result) -{ - struct jingle_pvt *p = ast_channel_tech_pvt(chan); - ast_mutex_lock(&p->lock); - ast_format_cap_copy(result, p->peercap); - ast_mutex_unlock(&p->lock); -} - -static int jingle_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *rtp, struct ast_rtp_instance *vrtp, struct ast_rtp_instance *tpeer, const struct ast_format_cap *cap, int nat_active) -{ - struct jingle_pvt *p; - - p = ast_channel_tech_pvt(chan); - if (!p) - return -1; - ast_mutex_lock(&p->lock); - -/* if (rtp) - ast_rtp_get_peer(rtp, &p->redirip); - else - memset(&p->redirip, 0, sizeof(p->redirip)); - p->redircodecs = codecs; */ - - /* Reset lastrtprx timer */ - ast_mutex_unlock(&p->lock); - return 0; -} - -static struct ast_rtp_glue jingle_rtp_glue = { - .type = "Jingle", - .get_rtp_info = jingle_get_rtp_peer, - .get_codec = jingle_get_codec, - .update_peer = jingle_set_rtp_peer, -}; - -static int jingle_response(struct jingle *client, ikspak *pak, const char *reasonstr, const char *reasonstr2) -{ - iks *response = NULL, *error = NULL, *reason = NULL; - int res = -1; - - response = iks_new("iq"); - if (response) { - iks_insert_attrib(response, "type", "result"); - iks_insert_attrib(response, "from", client->connection->jid->full); - iks_insert_attrib(response, "to", iks_find_attrib(pak->x, "from")); - iks_insert_attrib(response, "id", iks_find_attrib(pak->x, "id")); - if (reasonstr) { - error = iks_new("error"); - if (error) { - iks_insert_attrib(error, "type", "cancel"); - reason = iks_new(reasonstr); - if (reason) - iks_insert_node(error, reason); - iks_insert_node(response, error); - } - } - ast_aji_send(client->connection, response); - res = 0; - } - - iks_delete(reason); - iks_delete(error); - iks_delete(response); - - return res; -} - -static int jingle_is_answered(struct jingle *client, ikspak *pak) -{ - struct jingle_pvt *tmp; - - ast_debug(1, "The client is %s\n", client->name); - /* Make sure our new call doesn't exist yet */ - for (tmp = client->p; tmp; tmp = tmp->next) { - if (iks_find_with_attrib(pak->x, JINGLE_NODE, JINGLE_SID, tmp->sid)) - break; - } - - if (tmp) { - if (tmp->owner) - ast_queue_control(tmp->owner, AST_CONTROL_ANSWER); - } else - ast_log(LOG_NOTICE, "Whoa, didn't find call!\n"); - jingle_response(client, pak, NULL, NULL); - return 1; -} - -static int jingle_handle_dtmf(struct jingle *client, ikspak *pak) -{ - struct jingle_pvt *tmp; - iks *dtmfnode = NULL, *dtmfchild = NULL; - char *dtmf; - /* Make sure our new call doesn't exist yet */ - for (tmp = client->p; tmp; tmp = tmp->next) { - if (iks_find_with_attrib(pak->x, JINGLE_NODE, JINGLE_SID, tmp->sid)) - break; - } - - if (tmp) { - if(iks_find_with_attrib(pak->x, "dtmf-method", "method", "rtp")) { - jingle_response(client,pak, - "feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", - "unsupported-dtmf-method xmlns='http://www.xmpp.org/extensions/xep-0181.html#ns-errors'"); - return -1; - } - if ((dtmfnode = iks_find(pak->x, "dtmf"))) { - if((dtmf = iks_find_attrib(dtmfnode, "code"))) { - if(iks_find_with_attrib(pak->x, "dtmf", "action", "button-up")) { - struct ast_frame f = {AST_FRAME_DTMF_BEGIN, }; - f.subclass.integer = dtmf[0]; - ast_queue_frame(tmp->owner, &f); - ast_verbose("JINGLE! DTMF-relay event received: %c\n", f.subclass.integer); - } else if(iks_find_with_attrib(pak->x, "dtmf", "action", "button-down")) { - struct ast_frame f = {AST_FRAME_DTMF_END, }; - f.subclass.integer = dtmf[0]; - ast_queue_frame(tmp->owner, &f); - ast_verbose("JINGLE! DTMF-relay event received: %c\n", f.subclass.integer); - } else if(iks_find_attrib(pak->x, "dtmf")) { /* 250 millasecond default */ - struct ast_frame f = {AST_FRAME_DTMF, }; - f.subclass.integer = dtmf[0]; - ast_queue_frame(tmp->owner, &f); - ast_verbose("JINGLE! DTMF-relay event received: %c\n", f.subclass.integer); - } - } - } else if ((dtmfnode = iks_find_with_attrib(pak->x, JINGLE_NODE, "action", "session-info"))) { - if((dtmfchild = iks_find(dtmfnode, "dtmf"))) { - if((dtmf = iks_find_attrib(dtmfchild, "code"))) { - if(iks_find_with_attrib(dtmfnode, "dtmf", "action", "button-up")) { - struct ast_frame f = {AST_FRAME_DTMF_END, }; - f.subclass.integer = dtmf[0]; - ast_queue_frame(tmp->owner, &f); - ast_verbose("JINGLE! DTMF-relay event received: %c\n", f.subclass.integer); - } else if(iks_find_with_attrib(dtmfnode, "dtmf", "action", "button-down")) { - struct ast_frame f = {AST_FRAME_DTMF_BEGIN, }; - f.subclass.integer = dtmf[0]; - ast_queue_frame(tmp->owner, &f); - ast_verbose("JINGLE! DTMF-relay event received: %c\n", f.subclass.integer); - } - } - } - } - jingle_response(client, pak, NULL, NULL); - return 1; - } else - ast_log(LOG_NOTICE, "Whoa, didn't find call!\n"); - - jingle_response(client, pak, NULL, NULL); - return 1; -} - - -static int jingle_hangup_farend(struct jingle *client, ikspak *pak) -{ - struct jingle_pvt *tmp; - - ast_debug(1, "The client is %s\n", client->name); - /* Make sure our new call doesn't exist yet */ - for (tmp = client->p; tmp; tmp = tmp->next) { - if (iks_find_with_attrib(pak->x, JINGLE_NODE, JINGLE_SID, tmp->sid)) - break; - } - - if (tmp) { - tmp->alreadygone = 1; - if (tmp->owner) - ast_queue_hangup(tmp->owner); - } else - ast_log(LOG_NOTICE, "Whoa, didn't find call!\n"); - jingle_response(client, pak, NULL, NULL); - return 1; -} - -static int jingle_create_candidates(struct jingle *client, struct jingle_pvt *p, char *sid, char *from) -{ - struct jingle_candidate *tmp; - struct aji_client *c = client->connection; - struct jingle_candidate *ours1 = NULL, *ours2 = NULL; - struct sockaddr_in sin = { 0, }; - struct ast_sockaddr sin_tmp; - struct ast_sockaddr us_tmp; - struct ast_sockaddr bindaddr_tmp; - struct in_addr us; - struct in_addr externaddr; - iks *iq, *jingle, *content, *transport, *candidate; - char component[16], foundation[16], generation[16], network[16], pass[16], port[7], priority[16], user[16]; - - - iq = iks_new("iq"); - jingle = iks_new(JINGLE_NODE); - content = iks_new("content"); - transport = iks_new("transport"); - candidate = iks_new("candidate"); - if (!iq || !jingle || !content || !transport || !candidate) { - ast_log(LOG_ERROR, "Memory allocation error\n"); - goto safeout; - } - ours1 = ast_calloc(1, sizeof(*ours1)); - ours2 = ast_calloc(1, sizeof(*ours2)); - if (!ours1 || !ours2) - goto safeout; - - iks_insert_node(iq, jingle); - iks_insert_node(jingle, content); - iks_insert_node(content, transport); - iks_insert_node(transport, candidate); - - for (; p; p = p->next) { - if (!strcasecmp(p->sid, sid)) - break; - } - - if (!p) { - ast_log(LOG_NOTICE, "No matching jingle session - SID %s!\n", sid); - goto safeout; - } - - ast_rtp_instance_get_local_address(p->rtp, &sin_tmp); - ast_sockaddr_to_sin(&sin_tmp, &sin); - ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr); - ast_find_ourip(&us_tmp, &bindaddr_tmp, AF_INET); - us.s_addr = htonl(ast_sockaddr_ipv4(&us_tmp)); - - /* Setup our first jingle candidate */ - ours1->component = 1; - ours1->foundation = (unsigned int)bindaddr.sin_addr.s_addr | AJI_CONNECT_HOST | AJI_PROTOCOL_UDP; - ours1->generation = 0; - ast_copy_string(ours1->ip, ast_inet_ntoa(us), sizeof(ours1->ip)); - ours1->network = 0; - ours1->port = ntohs(sin.sin_port); - ours1->priority = 1678246398; - ours1->protocol = AJI_PROTOCOL_UDP; - snprintf(pass, sizeof(pass), "%08lx%08lx", (unsigned long)ast_random(), (unsigned long)ast_random()); - ast_copy_string(ours1->password, pass, sizeof(ours1->password)); - ours1->type = AJI_CONNECT_HOST; - snprintf(user, sizeof(user), "%08lx%08lx", (unsigned long)ast_random(), (unsigned long)ast_random()); - ast_copy_string(ours1->ufrag, user, sizeof(ours1->ufrag)); - p->ourcandidates = ours1; - - if (!ast_strlen_zero(externip)) { - /* XXX We should really stun for this one not just go with externip XXX */ - if (inet_aton(externip, &externaddr)) - ast_log(LOG_WARNING, "Invalid extern IP : %s\n", externip); - - ours2->component = 1; - ours2->foundation = (unsigned int)externaddr.s_addr | AJI_CONNECT_PRFLX | AJI_PROTOCOL_UDP; - ours2->generation = 0; - ast_copy_string(ours2->ip, externip, sizeof(ours2->ip)); - ours2->network = 0; - ours2->port = ntohs(sin.sin_port); - ours2->priority = 1678246397; - ours2->protocol = AJI_PROTOCOL_UDP; - snprintf(pass, sizeof(pass), "%08lx%08lx", (unsigned long)ast_random(), (unsigned long)ast_random()); - ast_copy_string(ours2->password, pass, sizeof(ours2->password)); - ours2->type = AJI_CONNECT_PRFLX; - - snprintf(user, sizeof(user), "%08lx%08lx", (unsigned long)ast_random(), (unsigned long)ast_random()); - ast_copy_string(ours2->ufrag, user, sizeof(ours2->ufrag)); - ours1->next = ours2; - ours2 = NULL; - } - ours1 = NULL; - - for (tmp = p->ourcandidates; tmp; tmp = tmp->next) { - snprintf(component, sizeof(component), "%u", tmp->component); - snprintf(foundation, sizeof(foundation), "%u", tmp->foundation); - snprintf(generation, sizeof(generation), "%u", tmp->generation); - snprintf(network, sizeof(network), "%u", tmp->network); - snprintf(port, sizeof(port), "%u", tmp->port); - snprintf(priority, sizeof(priority), "%u", tmp->priority); - - iks_insert_attrib(iq, "from", c->jid->full); - iks_insert_attrib(iq, "to", from); - iks_insert_attrib(iq, "type", "set"); - iks_insert_attrib(iq, "id", c->mid); - ast_aji_increment_mid(c->mid); - iks_insert_attrib(jingle, "action", JINGLE_NEGOTIATE); - iks_insert_attrib(jingle, JINGLE_SID, sid); - iks_insert_attrib(jingle, "initiator", (p->initiator) ? c->jid->full : from); - iks_insert_attrib(jingle, "xmlns", JINGLE_NS); - iks_insert_attrib(content, "creator", p->initiator ? "initiator" : "responder"); - iks_insert_attrib(content, "name", "asterisk-audio-content"); - iks_insert_attrib(transport, "xmlns", JINGLE_ICE_UDP_NS); - iks_insert_attrib(candidate, "component", component); - iks_insert_attrib(candidate, "foundation", foundation); - iks_insert_attrib(candidate, "generation", generation); - iks_insert_attrib(candidate, "ip", tmp->ip); - iks_insert_attrib(candidate, "network", network); - iks_insert_attrib(candidate, "port", port); - iks_insert_attrib(candidate, "priority", priority); - switch (tmp->protocol) { - case AJI_PROTOCOL_UDP: - iks_insert_attrib(candidate, "protocol", "udp"); - break; - case AJI_PROTOCOL_SSLTCP: - iks_insert_attrib(candidate, "protocol", "ssltcp"); - break; - } - iks_insert_attrib(candidate, "pwd", tmp->password); - switch (tmp->type) { - case AJI_CONNECT_HOST: - iks_insert_attrib(candidate, "type", "host"); - break; - case AJI_CONNECT_PRFLX: - iks_insert_attrib(candidate, "type", "prflx"); - break; - case AJI_CONNECT_RELAY: - iks_insert_attrib(candidate, "type", "relay"); - break; - case AJI_CONNECT_SRFLX: - iks_insert_attrib(candidate, "type", "srflx"); - break; - } - iks_insert_attrib(candidate, "ufrag", tmp->ufrag); - - ast_aji_send(c, iq); - } - p->laststun = 0; - -safeout: - if (ours1) - ast_free(ours1); - if (ours2) - ast_free(ours2); - iks_delete(iq); - iks_delete(jingle); - iks_delete(content); - iks_delete(transport); - iks_delete(candidate); - - return 1; -} - -static struct jingle_pvt *jingle_alloc(struct jingle *client, const char *from, const char *sid) -{ - struct jingle_pvt *tmp = NULL; - struct aji_resource *resources = NULL; - struct aji_buddy *buddy = NULL; - char idroster[200]; - struct ast_sockaddr bindaddr_tmp; - - ast_debug(1, "The client is %s for alloc\n", client->name); - if (!sid && !strchr(from, '/')) { /* I started call! */ - if (!strcasecmp(client->name, "guest")) { - buddy = ASTOBJ_CONTAINER_FIND(&client->connection->buddies, from); - if (buddy) { - resources = buddy->resources; - } - } else if (client->buddy) - resources = client->buddy->resources; - while (resources) { - if (resources->cap->jingle) { - break; - } - resources = resources->next; - } - if (resources) - snprintf(idroster, sizeof(idroster), "%s/%s", from, resources->resource); - else { - ast_log(LOG_ERROR, "no jingle capable clients to talk to.\n"); - if (buddy) { - ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy); - } - return NULL; - } - if (buddy) { - ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy); - } - } - if (!(tmp = ast_calloc(1, sizeof(*tmp)))) { - return NULL; - } - - tmp->cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); - tmp->jointcap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); - tmp->peercap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); - if (!tmp->cap || !tmp->jointcap || !tmp->peercap) { - tmp->cap = ast_format_cap_destroy(tmp->cap); - tmp->jointcap = ast_format_cap_destroy(tmp->jointcap); - tmp->peercap = ast_format_cap_destroy(tmp->peercap); - ast_free(tmp); - return NULL; - } - memcpy(&tmp->prefs, &client->prefs, sizeof(tmp->prefs)); - - if (sid) { - ast_copy_string(tmp->sid, sid, sizeof(tmp->sid)); - ast_copy_string(tmp->them, from, sizeof(tmp->them)); - } else { - snprintf(tmp->sid, sizeof(tmp->sid), "%08lx%08lx", (unsigned long)ast_random(), (unsigned long)ast_random()); - ast_copy_string(tmp->them, idroster, sizeof(tmp->them)); - tmp->initiator = 1; - } - ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr); - tmp->rtp = ast_rtp_instance_new("asterisk", sched, &bindaddr_tmp, NULL); - tmp->parent = client; - if (!tmp->rtp) { - ast_log(LOG_WARNING, "Out of RTP sessions?\n"); - ast_free(tmp); - return NULL; - } - ast_copy_string(tmp->exten, "s", sizeof(tmp->exten)); - ast_mutex_init(&tmp->lock); - ast_mutex_lock(&jinglelock); - tmp->next = client->p; - client->p = tmp; - ast_mutex_unlock(&jinglelock); - return tmp; -} - -static void jingle_set_owner(struct jingle_pvt *pvt, struct ast_channel *chan) -{ - pvt->owner = chan; - if (pvt->rtp) { - ast_rtp_instance_set_channel_id(pvt->rtp, pvt->owner ? ast_channel_uniqueid(pvt->owner) : ""); - } - if (pvt->vrtp) { - ast_rtp_instance_set_channel_id(pvt->vrtp, pvt->owner ? ast_channel_uniqueid(pvt->owner) : ""); - } -} - -/*! \brief Start new jingle channel */ -static struct ast_channel *jingle_new(struct jingle *client, struct jingle_pvt *i, int state, const char *title, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor) -{ - struct ast_channel *tmp; - struct ast_format_cap *what; /* SHALLOW COPY DO NOT DESTROY */ - struct ast_format tmpfmt; - const char *str; - - if (title) - str = title; - else - str = i->them; - tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, "", "", "", assignedids, requestor, 0, "Jingle/%s-%04lx", str, ast_random() & 0xffff); - if (!tmp) { - ast_log(LOG_WARNING, "Unable to allocate Jingle channel structure!\n"); - return NULL; - } - - ast_channel_stage_snapshot(tmp); - - ast_channel_tech_set(tmp, &jingle_tech); - - /* Select our native format based on codec preference until we receive - something from another device to the contrary. */ - if (!ast_format_cap_is_empty(i->jointcap)) - what = i->jointcap; - else if (!(ast_format_cap_is_empty(i->cap))) - what = i->cap; - else - what = global_capability; - - /* Set Frame packetization */ - if (i->rtp) - ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(i->rtp), i->rtp, &i->prefs); - - ast_codec_choose(&i->prefs, what, 1, &tmpfmt); - ast_format_cap_add(ast_channel_nativeformats(tmp), &tmpfmt); - - ast_format_cap_iter_start(i->jointcap); - while (!(ast_format_cap_iter_next(i->jointcap, &tmpfmt))) { - if (AST_FORMAT_GET_TYPE(tmpfmt.id) == AST_FORMAT_TYPE_VIDEO) { - ast_format_cap_add(ast_channel_nativeformats(tmp), &tmpfmt); - } - } - ast_format_cap_iter_end(i->jointcap); - - if (i->rtp) { - ast_channel_set_fd(tmp, 0, ast_rtp_instance_fd(i->rtp, 0)); - ast_channel_set_fd(tmp, 1, ast_rtp_instance_fd(i->rtp, 1)); - } - if (i->vrtp) { - ast_channel_set_fd(tmp, 2, ast_rtp_instance_fd(i->vrtp, 0)); - ast_channel_set_fd(tmp, 3, ast_rtp_instance_fd(i->vrtp, 1)); - } - if (state == AST_STATE_RING) - ast_channel_rings_set(tmp, 1); - ast_channel_adsicpe_set(tmp, AST_ADSI_UNAVAILABLE); - - - ast_best_codec(ast_channel_nativeformats(tmp), &tmpfmt); - ast_format_copy(ast_channel_writeformat(tmp), &tmpfmt); - ast_format_copy(ast_channel_rawwriteformat(tmp), &tmpfmt); - ast_format_copy(ast_channel_readformat(tmp), &tmpfmt); - ast_format_copy(ast_channel_rawreadformat(tmp), &tmpfmt); - ast_channel_tech_pvt_set(tmp, i); - - ast_channel_callgroup_set(tmp, client->callgroup); - ast_channel_pickupgroup_set(tmp, client->pickupgroup); - ast_channel_caller(tmp)->id.name.presentation = client->callingpres; - ast_channel_caller(tmp)->id.number.presentation = client->callingpres; - if (!ast_strlen_zero(client->accountcode)) - ast_channel_accountcode_set(tmp, client->accountcode); - if (client->amaflags) - ast_channel_amaflags_set(tmp, client->amaflags); - if (!ast_strlen_zero(client->language)) - ast_channel_language_set(tmp, client->language); - if (!ast_strlen_zero(client->musicclass)) - ast_channel_musicclass_set(tmp, client->musicclass); - jingle_set_owner(i, tmp); - ast_channel_context_set(tmp, client->context); - ast_channel_exten_set(tmp, i->exten); - /* Don't use ast_set_callerid() here because it will - * generate an unnecessary NewCallerID event */ - if (!ast_strlen_zero(i->cid_num)) { - ast_channel_caller(tmp)->ani.number.valid = 1; - ast_channel_caller(tmp)->ani.number.str = ast_strdup(i->cid_num); - } - if (!ast_strlen_zero(i->exten) && strcmp(i->exten, "s")) { - ast_channel_dialed(tmp)->number.str = ast_strdup(i->exten); - } - ast_channel_priority_set(tmp, 1); - if (i->rtp) - ast_jb_configure(tmp, &global_jbconf); - - ast_channel_stage_snapshot_done(tmp); - ast_channel_unlock(tmp); - - if (state != AST_STATE_DOWN && ast_pbx_start(tmp)) { - ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp)); - ast_channel_hangupcause_set(tmp, AST_CAUSE_SWITCH_CONGESTION); - ast_hangup(tmp); - tmp = NULL; - } - - return tmp; -} - -static int jingle_action(struct jingle *client, struct jingle_pvt *p, const char *action) -{ - iks *iq, *jingle = NULL; - int res = -1; - - iq = iks_new("iq"); - jingle = iks_new("jingle"); - - if (iq) { - iks_insert_attrib(iq, "type", "set"); - iks_insert_attrib(iq, "from", client->connection->jid->full); - iks_insert_attrib(iq, "to", p->them); - iks_insert_attrib(iq, "id", client->connection->mid); - ast_aji_increment_mid(client->connection->mid); - if (jingle) { - iks_insert_attrib(jingle, "action", action); - iks_insert_attrib(jingle, JINGLE_SID, p->sid); - iks_insert_attrib(jingle, "initiator", p->initiator ? client->connection->jid->full : p->them); - iks_insert_attrib(jingle, "xmlns", JINGLE_NS); - - iks_insert_node(iq, jingle); - - ast_aji_send(client->connection, iq); - res = 0; - } - } - - iks_delete(jingle); - iks_delete(iq); - - return res; -} - -static void jingle_free_candidates(struct jingle_candidate *candidate) -{ - struct jingle_candidate *last; - while (candidate) { - last = candidate; - candidate = candidate->next; - ast_free(last); - } -} - -static void jingle_free_pvt(struct jingle *client, struct jingle_pvt *p) -{ - struct jingle_pvt *cur, *prev = NULL; - cur = client->p; - while (cur) { - if (cur == p) { - if (prev) - prev->next = p->next; - else - client->p = p->next; - break; - } - prev = cur; - cur = cur->next; - } - if (p->ringrule) - iks_filter_remove_rule(p->parent->connection->f, p->ringrule); - if (p->owner) - ast_log(LOG_WARNING, "Uh oh, there's an owner, this is going to be messy.\n"); - if (p->rtp) - ast_rtp_instance_destroy(p->rtp); - if (p->vrtp) - ast_rtp_instance_destroy(p->vrtp); - jingle_free_candidates(p->theircandidates); - p->cap = ast_format_cap_destroy(p->cap); - p->jointcap = ast_format_cap_destroy(p->jointcap); - p->peercap = ast_format_cap_destroy(p->peercap); - - ast_free(p); -} - - -static int jingle_newcall(struct jingle *client, ikspak *pak) -{ - struct jingle_pvt *p, *tmp = client->p; - struct ast_channel *chan; - int res; - iks *codec, *content, *description; - char *from = NULL; - - /* Make sure our new call doesn't exist yet */ - from = iks_find_attrib(pak->x,"to"); - if(!from) - from = client->connection->jid->full; - - while (tmp) { - if (iks_find_with_attrib(pak->x, JINGLE_NODE, JINGLE_SID, tmp->sid)) { - ast_log(LOG_NOTICE, "Ignoring duplicate call setup on SID %s\n", tmp->sid); - jingle_response(client, pak, "out-of-order", NULL); - return -1; - } - tmp = tmp->next; - } - - if (!strcasecmp(client->name, "guest")){ - /* the guest account is not tied to any configured XMPP client, - let's set it now */ - if (client->connection) { - ASTOBJ_UNREF(client->connection, ast_aji_client_destroy); - } - client->connection = ast_aji_get_client(from); - if (!client->connection) { - ast_log(LOG_ERROR, "No XMPP client to talk to, us (partial JID) : %s\n", from); - return -1; - } - } - - p = jingle_alloc(client, pak->from->partial, iks_find_attrib(pak->query, JINGLE_SID)); - if (!p) { - ast_log(LOG_WARNING, "Unable to allocate jingle structure!\n"); - return -1; - } - chan = jingle_new(client, p, AST_STATE_DOWN, pak->from->user, NULL, NULL); - if (!chan) { - jingle_free_pvt(client, p); - return -1; - } - ast_mutex_lock(&p->lock); - ast_copy_string(p->them, pak->from->full, sizeof(p->them)); - if (iks_find_attrib(pak->query, JINGLE_SID)) { - ast_copy_string(p->sid, iks_find_attrib(pak->query, JINGLE_SID), - sizeof(p->sid)); - } - - /* content points to the first tag */ - content = iks_child(iks_child(pak->x)); - while (content) { - description = iks_find_with_attrib(content, "description", "xmlns", JINGLE_AUDIO_RTP_NS); - if (description) { - /* audio content found */ - codec = iks_child(iks_child(content)); - ast_copy_string(p->audio_content_name, iks_find_attrib(content, "name"), sizeof(p->audio_content_name)); - - while (codec) { - ast_rtp_codecs_payloads_set_m_type(ast_rtp_instance_get_codecs(p->rtp), p->rtp, atoi(iks_find_attrib(codec, "id"))); - ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(p->rtp), p->rtp, atoi(iks_find_attrib(codec, "id")), "audio", iks_find_attrib(codec, "name"), 0); - codec = iks_next(codec); - } - } - - description = NULL; - codec = NULL; - - description = iks_find_with_attrib(content, "description", "xmlns", JINGLE_VIDEO_RTP_NS); - if (description) { - /* video content found */ - codec = iks_child(iks_child(content)); - ast_copy_string(p->video_content_name, iks_find_attrib(content, "name"), sizeof(p->video_content_name)); - - while (codec) { - ast_rtp_codecs_payloads_set_m_type(ast_rtp_instance_get_codecs(p->rtp), p->rtp, atoi(iks_find_attrib(codec, "id"))); - ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(p->rtp), p->rtp, atoi(iks_find_attrib(codec, "id")), "audio", iks_find_attrib(codec, "name"), 0); - codec = iks_next(codec); - } - } - - content = iks_next(content); - } - - ast_mutex_unlock(&p->lock); - ast_channel_lock(chan); - ast_setstate(chan, AST_STATE_RING); - ast_channel_unlock(chan); - res = ast_pbx_start(chan); - - switch (res) { - case AST_PBX_FAILED: - ast_log(LOG_WARNING, "Failed to start PBX :(\n"); - jingle_response(client, pak, "service-unavailable", NULL); - break; - case AST_PBX_CALL_LIMIT: - ast_log(LOG_WARNING, "Failed to start PBX (call limit reached) \n"); - jingle_response(client, pak, "service-unavailable", NULL); - break; - case AST_PBX_SUCCESS: - jingle_response(client, pak, NULL, NULL); - jingle_create_candidates(client, p, - iks_find_attrib(pak->query, JINGLE_SID), - iks_find_attrib(pak->x, "from")); - /* nothing to do */ - break; - } - - return 1; -} - -static int jingle_update_stun(struct jingle *client, struct jingle_pvt *p) -{ - struct jingle_candidate *tmp; - struct hostent *hp; - struct ast_hostent ahp; - struct sockaddr_in sin; - struct ast_sockaddr sin_tmp; - - if (time(NULL) == p->laststun) - return 0; - - tmp = p->theircandidates; - p->laststun = time(NULL); - while (tmp) { - char username[256]; - hp = ast_gethostbyname(tmp->ip, &ahp); - sin.sin_family = AF_INET; - memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr)); - sin.sin_port = htons(tmp->port); - snprintf(username, sizeof(username), "%s:%s", tmp->ufrag, p->ourcandidates->ufrag); - - ast_sockaddr_from_sin(&sin_tmp, &sin); - ast_rtp_instance_stun_request(p->rtp, &sin_tmp, username); - tmp = tmp->next; - } - return 1; -} - -static int jingle_add_candidate(struct jingle *client, ikspak *pak) -{ - struct jingle_pvt *p = NULL, *tmp = NULL; - struct aji_client *c = client->connection; - struct jingle_candidate *newcandidate = NULL; - iks *traversenodes = NULL, *receipt = NULL; - - for (tmp = client->p; tmp; tmp = tmp->next) { - if (iks_find_with_attrib(pak->x, JINGLE_NODE, JINGLE_SID, tmp->sid)) { - p = tmp; - break; - } - } - - if (!p) - return -1; - - traversenodes = pak->query; - while(traversenodes) { - if(!strcasecmp(iks_name(traversenodes), "jingle")) { - traversenodes = iks_child(traversenodes); - continue; - } - if(!strcasecmp(iks_name(traversenodes), "content")) { - traversenodes = iks_child(traversenodes); - continue; - } - if(!strcasecmp(iks_name(traversenodes), "transport")) { - traversenodes = iks_child(traversenodes); - continue; - } - - if(!strcasecmp(iks_name(traversenodes), "candidate")) { - newcandidate = ast_calloc(1, sizeof(*newcandidate)); - if (!newcandidate) - return 0; - ast_copy_string(newcandidate->ip, iks_find_attrib(traversenodes, "ip"), sizeof(newcandidate->ip)); - newcandidate->port = atoi(iks_find_attrib(traversenodes, "port")); - ast_copy_string(newcandidate->password, iks_find_attrib(traversenodes, "pwd"), sizeof(newcandidate->password)); - if (!strcasecmp(iks_find_attrib(traversenodes, "protocol"), "udp")) - newcandidate->protocol = AJI_PROTOCOL_UDP; - else if (!strcasecmp(iks_find_attrib(traversenodes, "protocol"), "ssltcp")) - newcandidate->protocol = AJI_PROTOCOL_SSLTCP; - - if (!strcasecmp(iks_find_attrib(traversenodes, "type"), "host")) - newcandidate->type = AJI_CONNECT_HOST; - else if (!strcasecmp(iks_find_attrib(traversenodes, "type"), "prflx")) - newcandidate->type = AJI_CONNECT_PRFLX; - else if (!strcasecmp(iks_find_attrib(traversenodes, "type"), "relay")) - newcandidate->type = AJI_CONNECT_RELAY; - else if (!strcasecmp(iks_find_attrib(traversenodes, "type"), "srflx")) - newcandidate->type = AJI_CONNECT_SRFLX; - - newcandidate->network = atoi(iks_find_attrib(traversenodes, "network")); - newcandidate->generation = atoi(iks_find_attrib(traversenodes, "generation")); - newcandidate->next = NULL; - - newcandidate->next = p->theircandidates; - p->theircandidates = newcandidate; - p->laststun = 0; - jingle_update_stun(p->parent, p); - newcandidate = NULL; - } - traversenodes = iks_next(traversenodes); - } - - receipt = iks_new("iq"); - iks_insert_attrib(receipt, "type", "result"); - iks_insert_attrib(receipt, "from", c->jid->full); - iks_insert_attrib(receipt, "to", iks_find_attrib(pak->x, "from")); - iks_insert_attrib(receipt, "id", iks_find_attrib(pak->x, "id")); - ast_aji_send(c, receipt); - - iks_delete(receipt); - - return 1; -} - -static struct ast_frame *jingle_rtp_read(struct ast_channel *ast, struct jingle_pvt *p) -{ - struct ast_frame *f; - - if (!p->rtp) - return &ast_null_frame; - f = ast_rtp_instance_read(p->rtp, 0); - jingle_update_stun(p->parent, p); - if (p->owner) { - /* We already hold the channel lock */ - if (f->frametype == AST_FRAME_VOICE) { - if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(p->owner), &f->subclass.format))) { - ast_debug(1, "Oooh, format changed to %s\n", ast_getformatname(&f->subclass.format)); - ast_format_cap_remove_bytype(ast_channel_nativeformats(p->owner), AST_FORMAT_TYPE_AUDIO); - ast_format_cap_add(ast_channel_nativeformats(p->owner), &f->subclass.format); - ast_set_read_format(p->owner, ast_channel_readformat(p->owner)); - ast_set_write_format(p->owner, ast_channel_writeformat(p->owner)); - } -/* if ((ast_test_flag(p, SIP_DTMF) == SIP_DTMF_INBAND) && p->vad) { - f = ast_dsp_process(p->owner, p->vad, f); - if (f && (f->frametype == AST_FRAME_DTMF)) - ast_debug(1, "* Detected inband DTMF '%c'\n", f->subclass.codec); - } */ - } - } - return f; -} - -static struct ast_frame *jingle_read(struct ast_channel *ast) -{ - struct ast_frame *fr; - struct jingle_pvt *p = ast_channel_tech_pvt(ast); - - ast_mutex_lock(&p->lock); - fr = jingle_rtp_read(ast, p); - ast_mutex_unlock(&p->lock); - return fr; -} - -/*! \brief Send frame to media channel (rtp) */ -static int jingle_write(struct ast_channel *ast, struct ast_frame *frame) -{ - struct jingle_pvt *p = ast_channel_tech_pvt(ast); - int res = 0; - char buf[256]; - - switch (frame->frametype) { - case AST_FRAME_VOICE: - if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &frame->subclass.format))) { - ast_log(LOG_WARNING, - "Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n", - ast_getformatname(&frame->subclass.format), - ast_getformatname_multiple(buf, sizeof(buf), ast_channel_nativeformats(ast)), - ast_getformatname(ast_channel_readformat(ast)), - ast_getformatname(ast_channel_writeformat(ast))); - return 0; - } - if (p) { - ast_mutex_lock(&p->lock); - if (p->rtp) { - res = ast_rtp_instance_write(p->rtp, frame); - } - ast_mutex_unlock(&p->lock); - } - break; - case AST_FRAME_VIDEO: - if (p) { - ast_mutex_lock(&p->lock); - if (p->vrtp) { - res = ast_rtp_instance_write(p->vrtp, frame); - } - ast_mutex_unlock(&p->lock); - } - break; - case AST_FRAME_IMAGE: - return 0; - break; - default: - ast_log(LOG_WARNING, "Can't send %u type frames with Jingle write\n", - frame->frametype); - return 0; - } - - return res; -} - -static int jingle_fixup(struct ast_channel *oldchan, struct ast_channel *newchan) -{ - struct jingle_pvt *p = ast_channel_tech_pvt(newchan); - ast_mutex_lock(&p->lock); - - if ((p->owner != oldchan)) { - ast_mutex_unlock(&p->lock); - return -1; - } - if (p->owner == oldchan) { - jingle_set_owner(p, newchan); - } - ast_mutex_unlock(&p->lock); - return 0; -} - -static int jingle_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen) -{ - int res = 0; - - switch (condition) { - case AST_CONTROL_HOLD: - ast_moh_start(ast, data, NULL); - break; - case AST_CONTROL_UNHOLD: - ast_moh_stop(ast); - break; - default: - ast_log(LOG_NOTICE, "Don't know how to indicate condition '%d'\n", condition); - /* fallthrough */ - case AST_CONTROL_PVT_CAUSE_CODE: - res = -1; - } - - return res; -} - -static int jingle_sendtext(struct ast_channel *chan, const char *text) -{ - int res = 0; - struct aji_client *client = NULL; - struct jingle_pvt *p = ast_channel_tech_pvt(chan); - - - if (!p->parent) { - ast_log(LOG_ERROR, "Parent channel not found\n"); - return -1; - } - if (!p->parent->connection) { - ast_log(LOG_ERROR, "XMPP client not found\n"); - return -1; - } - client = p->parent->connection; - res = ast_aji_send_chat(client, p->them, text); - return res; -} - -static int jingle_digit(struct ast_channel *ast, char digit, unsigned int duration) -{ - struct jingle_pvt *p = ast_channel_tech_pvt(ast); - struct jingle *client = p->parent; - iks *iq, *jingle, *dtmf; - char buffer[2] = {digit, '\0'}; - iq = iks_new("iq"); - jingle = iks_new("jingle"); - dtmf = iks_new("dtmf"); - if(!iq || !jingle || !dtmf) { - iks_delete(iq); - iks_delete(jingle); - iks_delete(dtmf); - ast_log(LOG_ERROR, "Did not send dtmf do to memory issue\n"); - return -1; - } - - iks_insert_attrib(iq, "type", "set"); - iks_insert_attrib(iq, "to", p->them); - iks_insert_attrib(iq, "from", client->connection->jid->full); - iks_insert_attrib(iq, "id", client->connection->mid); - ast_aji_increment_mid(client->connection->mid); - iks_insert_attrib(jingle, "xmlns", JINGLE_NS); - iks_insert_attrib(jingle, "action", "session-info"); - iks_insert_attrib(jingle, "initiator", p->initiator ? client->connection->jid->full : p->them); - iks_insert_attrib(jingle, "sid", p->sid); - iks_insert_attrib(dtmf, "xmlns", JINGLE_DTMF_NS); - iks_insert_attrib(dtmf, "code", buffer); - iks_insert_node(iq, jingle); - iks_insert_node(jingle, dtmf); - - ast_mutex_lock(&p->lock); - if (ast_channel_dtmff(ast)->frametype == AST_FRAME_DTMF_BEGIN || duration == 0) { - iks_insert_attrib(dtmf, "action", "button-down"); - } else if (ast_channel_dtmff(ast)->frametype == AST_FRAME_DTMF_END || duration != 0) { - iks_insert_attrib(dtmf, "action", "button-up"); - } - ast_aji_send(client->connection, iq); - - iks_delete(iq); - iks_delete(jingle); - iks_delete(dtmf); - ast_mutex_unlock(&p->lock); - return 0; -} - -static int jingle_digit_begin(struct ast_channel *chan, char digit) -{ - return jingle_digit(chan, digit, 0); -} - -static int jingle_digit_end(struct ast_channel *ast, char digit, unsigned int duration) -{ - return jingle_digit(ast, digit, duration); -} - -static int jingle_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen) -{ - ast_log(LOG_NOTICE, "XXX Implement jingle sendhtml XXX\n"); - - return -1; -} -static int jingle_transmit_invite(struct jingle_pvt *p) -{ - struct jingle *aux = NULL; - struct aji_client *client = NULL; - iks *iq, *jingle, *content, *description, *transport; - iks *payload_eg711u, *payload_pcmu; - - aux = p->parent; - client = aux->connection; - iq = iks_new("iq"); - jingle = iks_new(JINGLE_NODE); - content = iks_new("content"); - description = iks_new("description"); - transport = iks_new("transport"); - payload_pcmu = iks_new("payload-type"); - payload_eg711u = iks_new("payload-type"); - - ast_copy_string(p->audio_content_name, "asterisk-audio-content", sizeof(p->audio_content_name)); - - iks_insert_attrib(iq, "type", "set"); - iks_insert_attrib(iq, "to", p->them); - iks_insert_attrib(iq, "from", client->jid->full); - iks_insert_attrib(iq, "id", client->mid); - ast_aji_increment_mid(client->mid); - iks_insert_attrib(jingle, "action", JINGLE_INITIATE); - iks_insert_attrib(jingle, JINGLE_SID, p->sid); - iks_insert_attrib(jingle, "initiator", client->jid->full); - iks_insert_attrib(jingle, "xmlns", JINGLE_NS); - - /* For now, we only send one audio based content */ - iks_insert_attrib(content, "creator", "initiator"); - iks_insert_attrib(content, "name", p->audio_content_name); - iks_insert_attrib(content, "profile", "RTP/AVP"); - iks_insert_attrib(description, "xmlns", JINGLE_AUDIO_RTP_NS); - iks_insert_attrib(transport, "xmlns", JINGLE_ICE_UDP_NS); - iks_insert_attrib(payload_pcmu, "id", "0"); - iks_insert_attrib(payload_pcmu, "name", "PCMU"); - iks_insert_attrib(payload_eg711u, "id", "100"); - iks_insert_attrib(payload_eg711u, "name", "EG711U"); - iks_insert_node(description, payload_pcmu); - iks_insert_node(description, payload_eg711u); - iks_insert_node(content, description); - iks_insert_node(content, transport); - iks_insert_node(jingle, content); - iks_insert_node(iq, jingle); - - ast_aji_send(client, iq); - - iks_delete(iq); - iks_delete(jingle); - iks_delete(content); - iks_delete(description); - iks_delete(transport); - iks_delete(payload_eg711u); - iks_delete(payload_pcmu); - return 0; -} - -/* Not in use right now. -static int jingle_auto_congest(void *nothing) -{ - struct jingle_pvt *p = nothing; - - ast_mutex_lock(&p->lock); - if (p->owner) { - if (!ast_channel_trylock(p->owner)) { - ast_log(LOG_NOTICE, "Auto-congesting %s\n", p->owner->name); - ast_queue_control(p->owner, AST_CONTROL_CONGESTION); - ast_channel_unlock(p->owner); - } - } - ast_mutex_unlock(&p->lock); - return 0; -} -*/ - -/*! \brief Initiate new call, part of PBX interface - * dest is the dial string */ -static int jingle_call(struct ast_channel *ast, const char *dest, int timeout) -{ - struct jingle_pvt *p = ast_channel_tech_pvt(ast); - - if ((ast_channel_state(ast) != AST_STATE_DOWN) && (ast_channel_state(ast) != AST_STATE_RESERVED)) { - ast_log(LOG_WARNING, "jingle_call called on %s, neither down nor reserved\n", ast_channel_name(ast)); - return -1; - } - - ast_setstate(ast, AST_STATE_RING); - ast_format_cap_copy(p->jointcap, p->cap); - if (!p->ringrule) { - ast_copy_string(p->ring, p->parent->connection->mid, sizeof(p->ring)); - p->ringrule = iks_filter_add_rule(p->parent->connection->f, jingle_ringing_ack, p, - IKS_RULE_ID, p->ring, IKS_RULE_DONE); - } else - ast_log(LOG_WARNING, "Whoa, already have a ring rule!\n"); - - jingle_transmit_invite(p); - jingle_create_candidates(p->parent, p, p->sid, p->them); - - return 0; -} - -/*! \brief Hangup a call through the jingle proxy channel */ -static int jingle_hangup(struct ast_channel *ast) -{ - struct jingle_pvt *p = ast_channel_tech_pvt(ast); - struct jingle *client; - - ast_mutex_lock(&p->lock); - client = p->parent; - jingle_set_owner(p, NULL); - ast_channel_tech_pvt_set(ast, NULL); - if (!p->alreadygone) - jingle_action(client, p, JINGLE_TERMINATE); - ast_mutex_unlock(&p->lock); - - jingle_free_pvt(client, p); - - return 0; -} - -/*! \brief Part of PBX interface */ -static struct ast_channel *jingle_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause) -{ - struct jingle_pvt *p = NULL; - struct jingle *client = NULL; - char *sender = NULL, *to = NULL, *s = NULL; - struct ast_channel *chan = NULL; - - if (data) { - s = ast_strdupa(data); - sender = strsep(&s, "/"); - if (sender && (sender[0] != '\0')) - to = strsep(&s, "/"); - if (!to) { - ast_log(LOG_ERROR, "Bad arguments in Jingle Dialstring: %s\n", data); - return NULL; - } - if (!to) { - ast_log(LOG_ERROR, "Bad arguments in Jingle Dialstring: %s\n", (char*) data); - return NULL; - } - } - - client = find_jingle(to, sender); - if (!client) { - ast_log(LOG_WARNING, "Could not find recipient.\n"); - return NULL; - } - if (!strcasecmp(client->name, "guest")){ - /* the guest account is not tied to any configured XMPP client, - let's set it now */ - if (client->connection) { - ASTOBJ_UNREF(client->connection, ast_aji_client_destroy); - } - client->connection = ast_aji_get_client(sender); - if (!client->connection) { - ast_log(LOG_ERROR, "No XMPP client to talk to, us (partial JID) : %s\n", sender); - return NULL; - } - } - - ASTOBJ_WRLOCK(client); - p = jingle_alloc(client, to, NULL); - if (p) - chan = jingle_new(client, p, AST_STATE_DOWN, to, assignedids, requestor); - ASTOBJ_UNLOCK(client); - - return chan; -} - -/*! \brief CLI command "jingle show channels" */ -static char *jingle_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) -{ -#define FORMAT "%-30.30s %-30.30s %-15.15s %-5.5s %-5.5s \n" - struct jingle_pvt *p; - struct ast_channel *chan; - int numchans = 0; - char them[AJI_MAX_JIDLEN]; - char *jid = NULL; - char *resource = NULL; - - switch (cmd) { - case CLI_INIT: - e->command = "jingle show channels"; - e->usage = - "Usage: jingle show channels\n" - " Shows current state of the Jingle channels.\n"; - return NULL; - case CLI_GENERATE: - return NULL; - } - - if (a->argc != 3) - return CLI_SHOWUSAGE; - - ast_mutex_lock(&jinglelock); - ast_cli(a->fd, FORMAT, "Channel", "Jabber ID", "Resource", "Read", "Write"); - ASTOBJ_CONTAINER_TRAVERSE(&jingle_list, 1, { - ASTOBJ_WRLOCK(iterator); - p = iterator->p; - while(p) { - chan = p->owner; - ast_copy_string(them, p->them, sizeof(them)); - jid = them; - resource = strchr(them, '/'); - if (!resource) - resource = "None"; - else { - *resource = '\0'; - resource ++; - } - if (chan) - ast_cli(a->fd, FORMAT, - ast_channel_name(chan), - jid, - resource, - ast_getformatname(ast_channel_readformat(chan)), - ast_getformatname(ast_channel_writeformat(chan)) - ); - else - ast_log(LOG_WARNING, "No available channel\n"); - numchans ++; - p = p->next; - } - ASTOBJ_UNLOCK(iterator); - }); - - ast_mutex_unlock(&jinglelock); - - ast_cli(a->fd, "%d active jingle channel%s\n", numchans, (numchans != 1) ? "s" : ""); - return CLI_SUCCESS; -#undef FORMAT -} - -/*! \brief CLI command "jingle reload" */ -static char *jingle_do_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) -{ - switch (cmd) { - case CLI_INIT: - e->command = "jingle reload"; - e->usage = - "Usage: jingle reload\n" - " Reload jingle channel driver.\n"; - return NULL; - case CLI_GENERATE: - return NULL; - } - - return CLI_SUCCESS; -} - -static int jingle_parser(void *data, ikspak *pak) -{ - struct jingle *client = ASTOBJ_REF((struct jingle *) data); - ast_log(LOG_NOTICE, "Filter matched\n"); - - if (iks_find_with_attrib(pak->x, JINGLE_NODE, "action", JINGLE_INITIATE)) { - /* New call */ - jingle_newcall(client, pak); - } else if (iks_find_with_attrib(pak->x, JINGLE_NODE, "action", JINGLE_NEGOTIATE)) { - ast_debug(3, "About to add candidate!\n"); - jingle_add_candidate(client, pak); - ast_debug(3, "Candidate Added!\n"); - } else if (iks_find_with_attrib(pak->x, JINGLE_NODE, "action", JINGLE_ACCEPT)) { - jingle_is_answered(client, pak); - } else if (iks_find_with_attrib(pak->x, JINGLE_NODE, "action", JINGLE_INFO)) { - jingle_handle_dtmf(client, pak); - } else if (iks_find_with_attrib(pak->x, JINGLE_NODE, "action", JINGLE_TERMINATE)) { - jingle_hangup_farend(client, pak); - } else if (iks_find_with_attrib(pak->x, JINGLE_NODE, "action", "reject")) { - jingle_hangup_farend(client, pak); - } - ASTOBJ_UNREF(client, jingle_member_destroy); - return IKS_FILTER_EAT; -} -/* Not using this anymore probably take out soon -static struct jingle_candidate *jingle_create_candidate(char *args) -{ - char *name, *type, *preference, *protocol; - struct jingle_candidate *res; - res = ast_calloc(1, sizeof(*res)); - if (args) - name = args; - if ((args = strchr(args, ','))) { - *args = '\0'; - args++; - preference = args; - } - if ((args = strchr(args, ','))) { - *args = '\0'; - args++; - protocol = args; - } - if ((args = strchr(args, ','))) { - *args = '\0'; - args++; - type = args; - } - if (name) - ast_copy_string(res->name, name, sizeof(res->name)); - if (preference) { - res->preference = atof(preference); - } - if (protocol) { - if (!strcasecmp("udp", protocol)) - res->protocol = AJI_PROTOCOL_UDP; - if (!strcasecmp("ssltcp", protocol)) - res->protocol = AJI_PROTOCOL_SSLTCP; - } - if (type) { - if (!strcasecmp("host", type)) - res->type = AJI_CONNECT_HOST; - if (!strcasecmp("prflx", type)) - res->type = AJI_CONNECT_PRFLX; - if (!strcasecmp("relay", type)) - res->type = AJI_CONNECT_RELAY; - if (!strcasecmp("srflx", type)) - res->type = AJI_CONNECT_SRFLX; - } - - return res; -} -*/ - -static int jingle_create_member(char *label, struct ast_variable *var, int allowguest, - struct ast_codec_pref prefs, char *context, - struct jingle *member) -{ - struct aji_client *client; - - if (!member) - ast_log(LOG_WARNING, "Out of memory.\n"); - - ast_copy_string(member->name, label, sizeof(member->name)); - ast_copy_string(member->user, label, sizeof(member->user)); - ast_copy_string(member->context, context, sizeof(member->context)); - member->allowguest = allowguest; - member->prefs = prefs; - while (var) { -#if 0 - struct jingle_candidate *candidate = NULL; -#endif - if (!strcasecmp(var->name, "username")) - ast_copy_string(member->user, var->value, sizeof(member->user)); - else if (!strcasecmp(var->name, "disallow")) - ast_parse_allow_disallow(&member->prefs, member->cap, var->value, 0); - else if (!strcasecmp(var->name, "allow")) - ast_parse_allow_disallow(&member->prefs, member->cap, var->value, 1); - else if (!strcasecmp(var->name, "context")) - ast_copy_string(member->context, var->value, sizeof(member->context)); -#if 0 - else if (!strcasecmp(var->name, "candidate")) { - candidate = jingle_create_candidate(var->value); - if (candidate) { - candidate->next = member->ourcandidates; - member->ourcandidates = candidate; - } - } -#endif - else if (!strcasecmp(var->name, "connection")) { - if ((client = ast_aji_get_client(var->value))) { - member->connection = client; - iks_filter_add_rule(client->f, jingle_parser, member, - IKS_RULE_TYPE, IKS_PAK_IQ, - IKS_RULE_FROM_PARTIAL, member->user, - IKS_RULE_NS, JINGLE_NS, - IKS_RULE_DONE); - } else { - ast_log(LOG_ERROR, "connection referenced not found!\n"); - return 0; - } - } - var = var->next; - } - if (member->connection && member->user) - member->buddy = ASTOBJ_CONTAINER_FIND(&member->connection->buddies, member->user); - else { - ast_log(LOG_ERROR, "No Connection or Username!\n"); - } - return 1; -} - -static int jingle_load_config(void) -{ - char *cat = NULL; - struct ast_config *cfg = NULL; - char context[100]; - int allowguest = 1; - struct ast_variable *var; - struct jingle *member; - struct hostent *hp; - struct ast_hostent ahp; - struct ast_codec_pref prefs; - struct aji_client_container *clients; - struct jingle_candidate *global_candidates = NULL; - struct ast_flags config_flags = { 0 }; - - cfg = ast_config_load(JINGLE_CONFIG, config_flags); - if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) { - return 0; - } - - /* Copy the default jb config over global_jbconf */ - memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf)); - - cat = ast_category_browse(cfg, NULL); - for (var = ast_variable_browse(cfg, "general"); var; var = var->next) { - /* handle jb conf */ - if (!ast_jb_read_conf(&global_jbconf, var->name, var->value)) - continue; - - if (!strcasecmp(var->name, "allowguest")) - allowguest = - (ast_true(ast_variable_retrieve(cfg, "general", "allowguest"))) ? 1 : 0; - else if (!strcasecmp(var->name, "disallow")) - ast_parse_allow_disallow(&prefs, global_capability, var->value, 0); - else if (!strcasecmp(var->name, "allow")) - ast_parse_allow_disallow(&prefs, global_capability, var->value, 1); - else if (!strcasecmp(var->name, "context")) - ast_copy_string(context, var->value, sizeof(context)); - else if (!strcasecmp(var->name, "externip")) - ast_copy_string(externip, var->value, sizeof(externip)); - else if (!strcasecmp(var->name, "bindaddr")) { - if (!(hp = ast_gethostbyname(var->value, &ahp))) { - ast_log(LOG_WARNING, "Invalid address: %s\n", var->value); - } else { - memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr)); - } - } -/* Idea to allow for custom candidates */ -/* - else if (!strcasecmp(var->name, "candidate")) { - candidate = jingle_create_candidate(var->value); - if (candidate) { - candidate->next = global_candidates; - global_candidates = candidate; - } - } -*/ - } - while (cat) { - if (strcasecmp(cat, "general")) { - var = ast_variable_browse(cfg, cat); - member = ast_calloc(1, sizeof(*member)); - ASTOBJ_INIT(member); - ASTOBJ_WRLOCK(member); - member->cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); - if (!strcasecmp(cat, "guest")) { - ast_copy_string(member->name, "guest", sizeof(member->name)); - ast_copy_string(member->user, "guest", sizeof(member->user)); - ast_copy_string(member->context, context, sizeof(member->context)); - member->allowguest = allowguest; - member->prefs = prefs; - while (var) { - if (!strcasecmp(var->name, "disallow")) - ast_parse_allow_disallow(&member->prefs, member->cap, - var->value, 0); - else if (!strcasecmp(var->name, "allow")) - ast_parse_allow_disallow(&member->prefs, member->cap, - var->value, 1); - else if (!strcasecmp(var->name, "context")) - ast_copy_string(member->context, var->value, - sizeof(member->context)); - else if (!strcasecmp(var->name, "parkinglot")) - ast_copy_string(member->parkinglot, var->value, - sizeof(member->parkinglot)); -/* Idea to allow for custom candidates */ -/* - else if (!strcasecmp(var->name, "candidate")) { - candidate = jingle_create_candidate(var->value); - if (candidate) { - candidate->next = member->ourcandidates; - member->ourcandidates = candidate; - } - } -*/ - var = var->next; - } - ASTOBJ_UNLOCK(member); - clients = ast_aji_get_clients(); - if (clients) { - ASTOBJ_CONTAINER_TRAVERSE(clients, 1, { - ASTOBJ_WRLOCK(iterator); - ASTOBJ_WRLOCK(member); - if (member->connection) { - ASTOBJ_UNREF(member->connection, ast_aji_client_destroy); - } - member->connection = NULL; - iks_filter_add_rule(iterator->f, jingle_parser, member, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS, JINGLE_NS, IKS_RULE_DONE); - iks_filter_add_rule(iterator->f, jingle_parser, member, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS, JINGLE_DTMF_NS, IKS_RULE_DONE); - ASTOBJ_UNLOCK(member); - ASTOBJ_UNLOCK(iterator); - }); - ASTOBJ_CONTAINER_LINK(&jingle_list, member); - } else { - ASTOBJ_UNLOCK(member); - ASTOBJ_UNREF(member, jingle_member_destroy); - } - } else { - ASTOBJ_UNLOCK(member); - if (jingle_create_member(cat, var, allowguest, prefs, context, member)) - ASTOBJ_CONTAINER_LINK(&jingle_list, member); - ASTOBJ_UNREF(member, jingle_member_destroy); - } - } - cat = ast_category_browse(cfg, cat); - } - ast_config_destroy(cfg); - jingle_free_candidates(global_candidates); - return 1; -} - -/*! - * \brief Load the module - * - * Module loading including tests for configuration or dependencies. - * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE, - * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails - * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the - * configuration file or other non-critical problem return - * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS. - */ -static int load_module(void) -{ - struct ast_sockaddr ourip_tmp; - struct ast_sockaddr bindaddr_tmp; - struct ast_format tmpfmt; - - char *jabber_loaded = ast_module_helper("", "res_jabber.so", 0, 0, 0, 0); - - if (!(jingle_tech.capabilities = ast_format_cap_alloc(0))) { - return AST_MODULE_LOAD_DECLINE; - } - - ast_format_cap_add_all_by_type(jingle_tech.capabilities, AST_FORMAT_TYPE_AUDIO); - if (!(global_capability = ast_format_cap_alloc(0))) { - return AST_MODULE_LOAD_DECLINE; - } - ast_format_cap_add(global_capability, ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0)); - ast_format_cap_add(global_capability, ast_format_set(&tmpfmt, AST_FORMAT_GSM, 0)); - ast_format_cap_add(global_capability, ast_format_set(&tmpfmt, AST_FORMAT_ALAW, 0)); - ast_format_cap_add(global_capability, ast_format_set(&tmpfmt, AST_FORMAT_H263, 0)); - - free(jabber_loaded); - if (!jabber_loaded) { - /* Dependency module has a different name, if embedded */ - jabber_loaded = ast_module_helper("", "res_jabber", 0, 0, 0, 0); - free(jabber_loaded); - if (!jabber_loaded) { - ast_log(LOG_ERROR, "chan_jingle.so depends upon res_jabber.so\n"); - return AST_MODULE_LOAD_DECLINE; - } - } - - ASTOBJ_CONTAINER_INIT(&jingle_list); - if (!jingle_load_config()) { - ast_log(LOG_ERROR, "Unable to read config file %s. Not loading module.\n", JINGLE_CONFIG); - return AST_MODULE_LOAD_DECLINE; - } - - sched = ast_sched_context_create(); - if (!sched) { - ast_log(LOG_WARNING, "Unable to create schedule context\n"); - } - - io = io_context_create(); - if (!io) { - ast_log(LOG_WARNING, "Unable to create I/O context\n"); - } - - bindaddr.sin_family = AF_INET; - ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr); - if (ast_find_ourip(&ourip_tmp, &bindaddr_tmp, AF_INET)) { - ast_log(LOG_WARNING, "Unable to get own IP address, Jingle disabled\n"); - return 0; - } - __ourip.s_addr = htonl(ast_sockaddr_ipv4(&ourip_tmp)); - - ast_rtp_glue_register(&jingle_rtp_glue); - ast_cli_register_multiple(jingle_cli, ARRAY_LEN(jingle_cli)); - /* Make sure we can register our channel type */ - if (ast_channel_register(&jingle_tech)) { - ast_log(LOG_ERROR, "Unable to register channel class %s\n", channel_type); - return -1; - } - return 0; -} - -/*! \brief Reload module */ -static int reload(void) -{ - return 0; -} - -/*! \brief Unload the jingle channel from Asterisk */ -static int unload_module(void) -{ - struct jingle_pvt *privates = NULL; - ast_cli_unregister_multiple(jingle_cli, ARRAY_LEN(jingle_cli)); - /* First, take us out of the channel loop */ - ast_channel_unregister(&jingle_tech); - ast_rtp_glue_unregister(&jingle_rtp_glue); - - if (!ast_mutex_lock(&jinglelock)) { - /* Hangup all interfaces if they have an owner */ - ASTOBJ_CONTAINER_TRAVERSE(&jingle_list, 1, { - ASTOBJ_WRLOCK(iterator); - privates = iterator->p; - while(privates) { - if (privates->owner) - ast_softhangup(privates->owner, AST_SOFTHANGUP_APPUNLOAD); - privates = privates->next; - } - iterator->p = NULL; - ASTOBJ_UNLOCK(iterator); - }); - ast_mutex_unlock(&jinglelock); - } else { - ast_log(LOG_WARNING, "Unable to lock the monitor\n"); - return -1; - } - ASTOBJ_CONTAINER_DESTROYALL(&jingle_list, jingle_member_destroy); - ASTOBJ_CONTAINER_DESTROY(&jingle_list); - - global_capability = ast_format_cap_destroy(global_capability); - return 0; -} - -AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Jingle Channel Driver", - .load = load_module, - .unload = unload_module, - .reload = reload, - .load_pri = AST_MODPRI_CHANNEL_DRIVER, - ); diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 35f5f5ef702..086913b41e1 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -111,7 +111,7 @@ * \todo Fix TCP/TLS handling in dialplan, SRV records, transfers and much more * \todo Save TCP/TLS sessions in registry * If someone registers a SIPS uri, this forces us to set up a TLS connection back. - * \todo Add TCP/TLS information to function SIPPEER and SIPCHANINFO + * \todo Add TCP/TLS information to function SIPPEER and CHANNEL function * \todo If tcpenable=yes, we must open a TCP socket on the same address as the IP for UDP. * The tcpbindaddr config option should only be used to open ADDITIONAL ports * So we should propably go back to @@ -463,40 +463,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") - - - Gets the specified SIP parameter from the current channel. - - - - - - The IP address of the peer. - - - The source IP address of the peer. - - - The SIP URI from the From: header. - - - The SIP URI from the Contact: header. - - - The Useragent header used by the peer. - - - The name of the peer. - - - 1 if T38 is offered or enabled in this channel, - otherwise 0. - - - - - - Checks if domain is a local domain. @@ -22390,15 +22356,11 @@ static int function_sippeer(struct ast_channel *chan, const char *cmd, char *dat struct sip_peer *peer; char *colname; - if ((colname = strchr(data, ':'))) { /*! \todo Will be deprecated after 1.4 */ - static int deprecation_warning = 0; - *colname++ = '\0'; - if (deprecation_warning++ % 10 == 0) - ast_log(LOG_WARNING, "SIPPEER(): usage of ':' to separate arguments is deprecated. Please use ',' instead.\n"); - } else if ((colname = strchr(data, ','))) + if ((colname = strchr(data, ','))) { *colname++ = '\0'; - else + } else { colname = "ip"; + } if (!(peer = sip_find_peer(data, NULL, TRUE, FINDPEERS, FALSE, 0))) return -1; @@ -22495,77 +22457,6 @@ static struct ast_custom_function sippeer_function = { .read = function_sippeer, }; -/*! \brief ${SIPCHANINFO()} Dialplan function - reads sip channel data */ -static int function_sipchaninfo_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) -{ - struct sip_pvt *p; - static int deprecated = 0; - - *buf = 0; - - if (!chan) { - ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd); - return -1; - } - - if (!data) { - ast_log(LOG_WARNING, "This function requires a parameter name.\n"); - return -1; - } - - ast_channel_lock(chan); - if (!IS_SIP_TECH(ast_channel_tech(chan))) { - ast_log(LOG_WARNING, "This function can only be used on SIP channels.\n"); - ast_channel_unlock(chan); - return -1; - } - - if (deprecated++ % 20 == 0) { - /* Deprecated in 1.6.1 */ - ast_log(LOG_WARNING, "SIPCHANINFO() is deprecated. Please transition to using CHANNEL().\n"); - } - - p = ast_channel_tech_pvt(chan); - - /* If there is no private structure, this channel is no longer alive */ - if (!p) { - ast_channel_unlock(chan); - return -1; - } - - if (!strcasecmp(data, "peerip")) { - ast_copy_string(buf, ast_sockaddr_stringify_addr(&p->sa), len); - } else if (!strcasecmp(data, "recvip")) { - ast_copy_string(buf, ast_sockaddr_stringify_addr(&p->recv), len); - } else if (!strcasecmp(data, "from")) { - ast_copy_string(buf, p->from, len); - } else if (!strcasecmp(data, "uri")) { - ast_copy_string(buf, p->uri, len); - } else if (!strcasecmp(data, "useragent")) { - ast_copy_string(buf, p->useragent, len); - } else if (!strcasecmp(data, "peername")) { - ast_copy_string(buf, p->peername, len); - } else if (!strcasecmp(data, "t38passthrough")) { - if ((p->t38.state == T38_DISABLED) || (p->t38.state == T38_REJECTED)) { - ast_copy_string(buf, "0", len); - } else { /* T38 is offered or enabled in this call */ - ast_copy_string(buf, "1", len); - } - } else { - ast_channel_unlock(chan); - return -1; - } - ast_channel_unlock(chan); - - return 0; -} - -/*! \brief Structure to declare a dialplan function: SIPCHANINFO */ -static struct ast_custom_function sipchaninfo_function = { - .name = "SIPCHANINFO", - .read = function_sipchaninfo_read, -}; - /*! \brief update redirecting information for a channel based on headers * */ @@ -34425,7 +34316,6 @@ static int load_module(void) /* Register dialplan functions */ ast_custom_function_register(&sip_header_function); ast_custom_function_register(&sippeer_function); - ast_custom_function_register(&sipchaninfo_function); ast_custom_function_register(&checksipdomain_function); /* Register manager commands */ @@ -34518,7 +34408,6 @@ static int unload_module(void) ast_msg_tech_unregister(&sip_msg_tech); /* Unregister dial plan functions */ - ast_custom_function_unregister(&sipchaninfo_function); ast_custom_function_unregister(&sippeer_function); ast_custom_function_unregister(&sip_header_function); ast_custom_function_unregister(&checksipdomain_function); diff --git a/channels/h323/ChangeLog b/channels/h323/ChangeLog deleted file mode 100644 index ddbf0819335..00000000000 --- a/channels/h323/ChangeLog +++ /dev/null @@ -1,43 +0,0 @@ -Build - -- Hold lock when creating new H.323 channel to sync the audio channels - -- Decrement usage counter when appropriate - -- Actually unregister everything in unload_module - -- Add IP based authentication using 'host'in type=user's -0.1.0 - -- Intergration into the mainline Asterisk codebase - -- Remove reduandant debug info - -- Add Caller*id support - -- Inband DTMF - -- Retool port usage (to avoid possible seg fault condition) -0.0.6 - -- Configurable support for user-input (DTMF) - -- Reworked Gatekeeper support - -- Native bridging (but is still broken, help!) - -- Locally implement a non-broken G.723.1 Capability - -- Utilize the cleaner RTP method implemented by Mark - -- AllowGkRouted, thanks to Panny from http://hotlinks.co.uk - -- Clened up inbound call flow - -- Prefix, E.164 and Gateway support - -- Multi-homed support - -- Killed more seg's -0.0.5 - -- Added H.323 Alias support - -- Clened up inbound call flow - -- Fixed RTP port logic - -- Stomped on possible seg fault conditions thanks to Iain Stevenson -0.0.4 - -- Fixed one-way audio on inbound calls. Found - race condition in monitor thread. - -0.0.3 - -- Changed name to chan_h323 - -- Also renamed file names to futher avoid confusion - -0.0.2 - -- First public offering - -- removed most hardcoded values - -- lots of changes to alias/exension operation - -0.0.1 - -- initial build, lots of hardcoded crap - -- Proof of concept for External RTP diff --git a/channels/h323/INSTALL.openh323 b/channels/h323/INSTALL.openh323 deleted file mode 100644 index f46c3790585..00000000000 --- a/channels/h323/INSTALL.openh323 +++ /dev/null @@ -1,18 +0,0 @@ -To build Open H.323 see: - -http://www.openh323.org/build.html#unix - -You only need to do 'make opt'. Anything else you will be simply waisting time and HD space. -Also, you will notice they never tell you to 'make install' so don't do it. - - -On FreeBSD, the Makefiles are configured to -locate the compiled openh323 port, if it has -been built. Here is one way to build -openh323 and ptlib on such that the Makefiles -find it: - # cd /usr/ports/net/openh323 - # make -It is not necessary to install the port. The -asterisk makefiles do not use any files -installed by the port. diff --git a/channels/h323/Makefile.in b/channels/h323/Makefile.in deleted file mode 100644 index 2908c52cb6a..00000000000 --- a/channels/h323/Makefile.in +++ /dev/null @@ -1,53 +0,0 @@ -# -# Makefile -# -# Make file for OpenH323 support layer -# - -.PHONY: Makefile.ast clean - -default:: @OPENH323_BUILD@ - -# Verify those options with main Makefile -STDCCFLAGS = -DNDEBUG -STDCCFLAGS += -I../../include -include ../../include/asterisk/autoconfig.h -STDCCFLAGS += -fPIC -#OPTCCFLAGS += -CFLAGS = -pipe -TARGET = libchanh323.a -TARGET += Makefile.ast -SOURCES = ast_h323.cxx compat_h323.cxx cisco-h225.cxx caps_h323.cxx -OBJDIR = . -OBJS = - -ifndef OPENH323DIR -OPENH323DIR=@OPENH323DIR@ -endif - -ifneq ($(wildcard $(OPENH323DIR)/openh323u.mak),) -include $(OPENH323DIR)/openh323u.mak -endif - -notrace:: - $(MAKE) NOTRACE=1 opt - -$(SOURCES):: Makefile ../../Makefile - touch $@ - -libchanh323.a: $(OBJS) - ar crv $@ $(OBJS) - -# -# We have this file in svn, so this is commented out to ensure it doesn't try -# to run implicitly. However, it's still here for reference. -# -#cisco-h225.cxx:: cisco-h225.asn -# asnparser -m CISCO_H225 -c $< - -Makefile.ast: - @echo H323CFLAGS = $(STDCCFLAGS) $(OPTCCFLAGS) $(CFLAGS) >$@.tmp - @echo H323LDFLAGS = $(CFLAGS) $(LDFLAGS) >>$@.tmp - @echo H323LDLIBS = $(LDLIBS) $(ENDLDLIBS) $(ENDLDFLAGS) >>$@.tmp - @if [ -r $@ ] && cmp -s $@ $@.tmp; then rm -f $@.tmp; else mv -f $@.tmp $@; fi - -clean:: diff --git a/channels/h323/README b/channels/h323/README deleted file mode 100644 index 27a24c717d3..00000000000 --- a/channels/h323/README +++ /dev/null @@ -1,144 +0,0 @@ - Open H.323 Channel Driver for Asterisk - By Jeremy McNamara - For The NuFone Network - - First public release on November 10th, 2002 - - Dependancies (based on OpenH323/PWLib ones): - openssl-0.9.6b+ - openssl-devel-0.9.6b+ - expat-1.95+ - expat-dev-1.95+ - -Tested with Open H.323 version v1.18.0, PWLib v1.10.0 and GCC v3.2.2. Usage of any -other (especially prior OpenH323 v1.17.3 and PWLib v1.9.2) versions is not -supported. - -NOTICE: Whatever you do, DO NOT USE distrubution specific installs -of Open H.323 and PWLib. In fact, you should check to make sure -your distro did not install them for you without your knowledge. - - -To compile this code --------------------- -Once PWLib and Open H.323 have been compiled per their specific build -instructions, issue a make in the asterisk/channels/h323 directory with -argument used to build PWLib and OpenH323 (for example, make opt), then go -back to the Asterisk source top level directory and issue a make install. - - -The most common compile error ----------------------------- -If you receive ANYTHING that says 'undefined symbol' you are experiencing -typical version skew. For example: - -libh323_linux_x86_r.so.1: undefined symbol: GetNumberValueAt__C14PAbstractArrayi - -You need to search and destroy every version of libh323 and libpt then -completely recompile everything - -Example commands to make sure everything gets cleaned and then -rebult in proper order: - -cd /path/to/pwlib -./configure -make clean opt -cd /path/to/openh323 -./configure -make clean opt -cd /path/to/asterisk/channels/h323 -make opt -cd /path/to/asterisk -make install - - -Most common run-time error -------------------------- -libpt_linux_x86_r.so.1: cannot open shared object file: No such -file or directory - -You have not set the LD_LIBRARY_PATH environment variable. - -Example environment for sh/bash: - -PWLIBDIR=$HOME/pwlib -export PWLIBDIR -OPENH323DIR=$HOME/openh323 -export OPENH323DIR -LD_LIBRARY_PATH=$PWLIBDIR/lib:$OPENH323DIR/lib -export LD_LIBRARY_PATH - -We recomend puting the above directives into your /etc/profile so -you do not have to remember to export those values every time you -want to recompile. Make sure to logout and log back in, so your -envrionment can pick up the new variables. - - -Upgrading Asterisk ------------------ -After you svn update (or make update) Asterisk you have to go into -asterisk/channels/h323 and issue a make clean all, before compiling the -rest of asterisk. Doing this process every time you upgrade Asterisk -will ensure a sane build. - - -Dialing an H.323 channel ------------------------- -Without a gatekeeper: -exten => _1NXXNXXXXXX,1,Dial,H323/${EXTEN}@peer -or -exten => _1NXXNXXXXXX,1,Dial,H323/${EXTEN}@ip.or.hostname - -'peer' is defined in h323.conf as: - -[peer] -type=peer -host=1.2.3.4 -disallow=all -allow=ulaw - -Using a gatekeeper: -exten => _1NXXNXXXXXX,1,Dial,H323/${EXTEN} - -When using a gatekeeper you cannot utilize the type=peer features, -since the H.323 spec states that when a Gatekeeper is part of an H.323 network, -the Gatekeeper shall be used for all communication. - - -Developer Contact ----------------- -If you have trouble contact 'JerJer' in #Asterisk on -irc.freenode.net and/or send reasonable debug information to support@nufone.net. - -If are lucky enough to segfault this code please run a -backtrace and send the gory details. Segmentation faults are not -tolerated, no matter what Distro you run (even debian)! - -a simple bt example: - -# /usr/sbin/asterisk -vvvgc -... -[chan_h323.so] -Segmentation Fault (core dumped) - -# ls core.* -core.1976 - -# gdb /usr/sbin/asterisk core.1976 -...lots of useless garbage here... -(gdb) bt - -Send whatever shows up right after the 'bt' - -Also, a full debug screen output is almost needed. Make sure you are -in the full console mode (-c) and turn on 'h.323 debug' or worst case -senerio 'h.323 trace 4'. A nice way to capture debug info is with -script (man script). - -If you are motivated to update/fix this code please submit a -disclaimer along with the patch to the Asterisk bug -tracker: https://issues.asterisk.org/ - - -Jeremy McNamara -The NuFone Network diff --git a/channels/h323/TODO b/channels/h323/TODO deleted file mode 100644 index 1e114ca3bd7..00000000000 --- a/channels/h323/TODO +++ /dev/null @@ -1,9 +0,0 @@ -The NuFone Network's Open H.323 Channel Driver for Asterisk - - TODO: - - - H.323 Native Bridging - - - Gatekeeping support (started) - - - Acutally implement the options for broken H.323 stacks diff --git a/channels/h323/ast_h323.cxx b/channels/h323/ast_h323.cxx deleted file mode 100644 index b8f3aaaee20..00000000000 --- a/channels/h323/ast_h323.cxx +++ /dev/null @@ -1,2678 +0,0 @@ -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif -/* - * ast_h323.cpp - * - * OpenH323 Channel Driver for ASTERISK PBX. - * By Jeremy McNamara - * For The NuFone Network - * - * chan_h323 has been derived from code created by - * Michael Manousos and Mark Spencer - * - * This file is part of the chan_h323 driver for Asterisk - * - * chan_h323 is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * chan_h323 is distributed WITHOUT ANY WARRANTY; without even - * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Version Info: $Id$ - */ - -#define VERSION(a,b,c) ((a)*10000+(b)*100+(c)) - -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - -/* H323 Plus */ -#if VERSION(OPENH323_MAJOR, OPENH323_MINOR, OPENH323_BUILD) > VERSION(1,19,4) - -#ifdef H323_H450 -#include "h450/h4501.h" -#include "h450/h4504.h" -#include "h450/h45011.h" -#include "h450/h450pdu.h" -#endif - -#ifdef H323_H460 -#include -#endif - -#else /* !H323 Plus */ - -#include -#ifdef H323_H450 -#include "h4501.h" -#include "h4504.h" -#include "h45011.h" -#include "h450pdu.h" -#endif - -#endif /* H323 Plus */ - -#include "compat_h323.h" - -#include "asterisk.h" - -#ifdef __cplusplus -extern "C" { -#endif -#include "asterisk/compat.h" -#include "asterisk/logger.h" -#include "asterisk/channel.h" -#include "asterisk/astobj.h" -#ifdef __cplusplus -} -#endif - -#undef open -#undef close - -#include "chan_h323.h" -#include "ast_h323.h" -#include "cisco-h225.h" -#include "caps_h323.h" - -/* PWLIB_MAJOR renamed to PTLIB_MAJOR in 2.x.x */ -#if (defined(PTLIB_MAJOR) || VERSION(PWLIB_MAJOR, PWLIB_MINOR, PWLIB_BUILD) >= VERSION(1,12,0)) -#define SKIP_PWLIB_PIPE_BUG_WORKAROUND 1 -#endif - -/////////////////////////////////////////////// -/* We have to have a PProcess running for the life of the instance to give - * h323plus a static instance of PProcess to get system information. - * This class is defined with PDECLARE_PROCESS(). See pprocess.h from pwlib. - */ - -/* PWlib Required Components */ -#if VERSION(OPENH323_MAJOR, OPENH323_MINOR, OPENH323_BUILD) > VERSION(1,19,4) -#define MAJOR_VERSION 1 -#define MINOR_VERSION 19 -#define BUILD_TYPE ReleaseCode -#define BUILD_NUMBER 6 -#else -#define MAJOR_VERSION 1 -#define MINOR_VERSION 0 -#define BUILD_TYPE ReleaseCode -#define BUILD_NUMBER 0 -#endif - -const char *h323manufact = "The NuFone Networks"; -const char *h323product = "H.323 Channel Driver for Asterisk"; - -PDECLARE_PROCESS(MyProcess,PProcess,h323manufact,h323product,MAJOR_VERSION,MINOR_VERSION,BUILD_TYPE,BUILD_NUMBER) -static MyProcess localProcess; // active for the life of the DLL -/* void MyProcess::Main() -{ -} -*/ -//////////////////////////////////////////////// - - -/** Counter for the number of connections */ -static int channelsOpen; - -/** - * We assume that only one endPoint should exist. - * The application cannot run the h323_end_point_create() more than once - * FIXME: Singleton this, for safety - */ -static MyH323EndPoint *endPoint = NULL; - -#ifndef SKIP_PWLIB_PIPE_BUG_WORKAROUND -static int _timerChangePipe[2]; -#endif - -static unsigned traceOptions = PTrace::Timestamp | PTrace::Thread | PTrace::FileAndLine; - -class PAsteriskLog : public PObject, public iostream { - PCLASSINFO(PAsteriskLog, PObject); - - public: - PAsteriskLog() : iostream(cout.rdbuf()) { init(&buffer); } - ~PAsteriskLog() { flush(); } - - private: - PAsteriskLog(const PAsteriskLog &) : iostream(cout.rdbuf()) { } - PAsteriskLog & operator=(const PAsteriskLog &) { return *this; } - - class Buffer : public streambuf { - public: - virtual int overflow(int=EOF); - virtual int underflow(); - virtual int sync(); - PString string; - } buffer; - friend class Buffer; -}; - -static PAsteriskLog *logstream = NULL; - -int PAsteriskLog::Buffer::overflow(int c) -{ - if (pptr() >= epptr()) { - int ppos = pptr() - pbase(); - char *newptr = string.GetPointer(string.GetSize() + 2000); - setp(newptr, newptr + string.GetSize() - 1); - pbump(ppos); - } - if (c != EOF) { - *pptr() = (char)c; - pbump(1); - } - return 0; -} - -int PAsteriskLog::Buffer::underflow() -{ - return EOF; -} - -int PAsteriskLog::Buffer::sync() -{ - char *str = ast_strdup(string); - char *s, *s1; - char c; - - /* Pass each line with different ast_verbose() call */ - for (s = str; s && *s; s = s1) { - s1 = strchr(s, '\n'); - if (!s1) - s1 = s + strlen(s); - else - s1++; - c = *s1; - *s1 = '\0'; - ast_verbose("%s", s); - *s1 = c; - } - ast_free(str); - - string = PString(); - char *base = string.GetPointer(2000); - setp(base, base + string.GetSize() - 1); - return 0; -} - -static ostream &my_endl(ostream &os) -{ - if (logstream) { - PTrace::SetOptions(traceOptions); - return PTrace::End(os); - } - return endl(os); -} - -#define cout \ - (logstream ? (PTrace::ClearOptions((unsigned)-1), PTrace::Begin(0, __FILE__, __LINE__)) : std::cout) -#define endl my_endl - -void MyProcess::Main() -{ - PTrace::Initialise(PTrace::GetLevel(), NULL, traceOptions); - PTrace::SetStream(logstream); - - cout << " == Creating H.323 Endpoint" << endl; - if (endPoint) { - cout << " == ENDPOINT ALREADY CREATED" << endl; - return; - } - endPoint = new MyH323EndPoint(); - /* Due to a bug in the H.323 recomendation/stack we should request a sane - amount of bandwidth from the GK - this function is ignored if not using a GK - We are requesting 128 (64k in each direction), which is the worst case codec. */ - endPoint->SetInitialBandwidth(1280); -} - -void PAssertFunc(const char *msg) -{ - ast_log(LOG_ERROR, "%s\n", msg); - /* XXX: Probably we need to crash here */ -} - - -/** MyH323EndPoint - */ -MyH323EndPoint::MyH323EndPoint() - : H323EndPoint() -{ - /* Capabilities will be negotiated on per-connection basis */ - capabilities.RemoveAll(); - - /* Reset call setup timeout to some more reasonable value than 1 minute */ - signallingChannelCallTimeout = PTimeInterval(0, 0, 10); /* 10 minutes */ -} - -/** The fullAddress parameter is used directly in the MakeCall method so - * the General form for the fullAddress argument is : - * [alias@][transport$]host[:port] - * default values: alias = the same value as host. - * transport = ip. - * port = 1720. - */ -int MyH323EndPoint::MyMakeCall(const PString & dest, PString & token, void *_callReference, void *_opts) -{ - PString fullAddress; - MyH323Connection * connection; - H323Transport *transport = NULL; - unsigned int *callReference = (unsigned int *)_callReference; - call_options_t *opts = (call_options_t *)_opts; - - /* Determine whether we are using a gatekeeper or not. */ - if (GetGatekeeper()) { - fullAddress = dest; - if (h323debug) { - cout << " -- Making call to " << fullAddress << " using gatekeeper." << endl; - } - } else { - fullAddress = dest; - if (h323debug) { - cout << " -- Making call to " << fullAddress << " without gatekeeper." << endl; - } - /* Use bindaddr for outgoing calls too if we don't use gatekeeper */ - if (listeners.GetSize() > 0) { - H323TransportAddress taddr = listeners[0].GetTransportAddress(); - PIPSocket::Address addr; - WORD port; - if (taddr.GetIpAndPort(addr, port)) { - /* Create own transport for specific addresses only */ - if (addr) { - if (h323debug) - cout << "Using " << addr << " for outbound call" << endl; - transport = new MyH323TransportTCP(*this, addr); - if (!transport) - cout << "Unable to create transport for outgoing call" << endl; - } - } else - cout << "Unable to get address and port" << endl; - } - } - if (!(connection = (MyH323Connection *)H323EndPoint::MakeCallLocked(fullAddress, token, opts, transport))) { - if (h323debug) { - cout << "Error making call to \"" << fullAddress << '"' << endl; - } - return 1; - } - *callReference = connection->GetCallReference(); - - if (h323debug) { - cout << "\t-- " << GetLocalUserName() << " is calling host " << fullAddress << endl; - cout << "\t-- Call token is " << (const char *)token << endl; - cout << "\t-- Call reference is " << *callReference << endl; -#ifdef PTRACING - cout << "\t-- DTMF Payload is " << connection->dtmfCodec << endl; -#endif - } - connection->Unlock(); - return 0; -} - -void MyH323EndPoint::SetEndpointTypeInfo( H225_EndpointType & info ) const -{ - H323EndPoint::SetEndpointTypeInfo(info); - - if (terminalType == e_GatewayOnly){ - info.RemoveOptionalField(H225_EndpointType::e_terminal); - info.IncludeOptionalField(H225_EndpointType::e_gateway); - } - - info.m_gateway.IncludeOptionalField(H225_GatewayInfo::e_protocol); - info.m_gateway.m_protocol.SetSize(1); - H225_SupportedProtocols &protocol=info.m_gateway.m_protocol[0]; - protocol.SetTag(H225_SupportedProtocols::e_voice); - PINDEX as=SupportedPrefixes.GetSize(); - ((H225_VoiceCaps &)protocol).m_supportedPrefixes.SetSize(as); - for (PINDEX p=0; pSendUserInputTone(tone, 500); - connection->Unlock(); - } -} - -void MyH323EndPoint::OnClosedLogicalChannel(H323Connection & connection, const H323Channel & channel) -{ - channelsOpen--; - if (h323debug) { - cout << "\t\tchannelsOpen = " << channelsOpen << endl; - } - H323EndPoint::OnClosedLogicalChannel(connection, channel); -} - -PBoolean MyH323EndPoint::OnConnectionForwarded(H323Connection & connection, - const PString & forwardParty, - const H323SignalPDU & pdu) -{ - if (h323debug) { - cout << "\t-- Call Forwarded to " << forwardParty << endl; - } - return FALSE; -} - -PBoolean MyH323EndPoint::ForwardConnection(H323Connection & connection, - const PString & forwardParty, - const H323SignalPDU & pdu) -{ - if (h323debug) { - cout << "\t-- Forwarding call to " << forwardParty << endl; - } - return H323EndPoint::ForwardConnection(connection, forwardParty, pdu); -} - -void MyH323EndPoint::OnConnectionEstablished(H323Connection & connection, const PString & estCallToken) -{ - if (h323debug) { - cout << "\t=-= In OnConnectionEstablished for call " << connection.GetCallReference() << endl; - cout << "\t\t-- Connection Established with \"" << connection.GetRemotePartyName() << "\"" << endl; - } - on_connection_established(connection.GetCallReference(), (const char *)connection.GetCallToken()); -} - -/** OnConnectionCleared callback function is called upon the dropping of an established - * H323 connection. - */ -void MyH323EndPoint::OnConnectionCleared(H323Connection & connection, const PString & clearedCallToken) -{ - PString remoteName = connection.GetRemotePartyName(); - - switch (connection.GetCallEndReason()) { - case H323Connection::EndedByCallForwarded: - if (h323debug) { - cout << "-- " << remoteName << " has forwarded the call" << endl; - } - break; - case H323Connection::EndedByRemoteUser: - if (h323debug) { - cout << "-- " << remoteName << " has cleared the call" << endl; - } - break; - case H323Connection::EndedByCallerAbort: - if (h323debug) { - cout << "-- " << remoteName << " has stopped calling" << endl; - } - break; - case H323Connection::EndedByRefusal: - if (h323debug) { - cout << "-- " << remoteName << " did not accept your call" << endl; - } - break; - case H323Connection::EndedByRemoteBusy: - if (h323debug) { - cout << "-- " << remoteName << " was busy" << endl; - } - break; - case H323Connection::EndedByRemoteCongestion: - if (h323debug) { - cout << "-- Congested link to " << remoteName << endl; - } - break; - case H323Connection::EndedByNoAnswer: - if (h323debug) { - cout << "-- " << remoteName << " did not answer your call" << endl; - } - break; - case H323Connection::EndedByTransportFail: - if (h323debug) { - cout << "-- Call with " << remoteName << " ended abnormally" << endl; - } - break; - case H323Connection::EndedByCapabilityExchange: - if (h323debug) { - cout << "-- Could not find common codec with " << remoteName << endl; - } - break; - case H323Connection::EndedByNoAccept: - if (h323debug) { - cout << "-- Did not accept incoming call from " << remoteName << endl; - } - break; - case H323Connection::EndedByAnswerDenied: - if (h323debug) { - cout << "-- Refused incoming call from " << remoteName << endl; - } - break; - case H323Connection::EndedByNoUser: - if (h323debug) { - cout << "-- Remote endpoint could not find user: " << remoteName << endl; - } - break; - case H323Connection::EndedByNoBandwidth: - if (h323debug) { - cout << "-- Call to " << remoteName << " aborted, insufficient bandwidth." << endl; - } - break; - case H323Connection::EndedByUnreachable: - if (h323debug) { - cout << "-- " << remoteName << " could not be reached." << endl; - } - break; - case H323Connection::EndedByHostOffline: - if (h323debug) { - cout << "-- " << remoteName << " is not online." << endl; - } - break; - case H323Connection::EndedByNoEndPoint: - if (h323debug) { - cout << "-- No phone running for " << remoteName << endl; - } - break; - case H323Connection::EndedByConnectFail: - if (h323debug) { - cout << "-- Transport error calling " << remoteName << endl; - } - break; - default: - if (h323debug) { -#ifdef PTRACING - cout << " -- Call with " << remoteName << " completed (" << connection.GetCallEndReason() << ")" << endl; -#else - cout << " -- Call with " << remoteName << " completed ([" << (int)connection.GetCallEndReason() << "])" << endl; -#endif - } - } - - if (connection.IsEstablished()) { - if (h323debug) { - cout << "\t-- Call duration " << setprecision(0) << setw(5) << (PTime() - connection.GetConnectionStartTime()) << endl; - } - } - /* Invoke the PBX application registered callback */ - on_connection_cleared(connection.GetCallReference(), clearedCallToken); - return; -} - -H323Connection * MyH323EndPoint::CreateConnection(unsigned callReference, void *userData, H323Transport *transport, H323SignalPDU *setupPDU) -{ - unsigned options = 0; - call_options_t *opts = (call_options_t *)userData; - MyH323Connection *conn; - - if (opts && opts->fastStart) { - options |= H323Connection::FastStartOptionEnable; - } else { - options |= H323Connection::FastStartOptionDisable; - } - if (opts && opts->h245Tunneling) { - options |= H323Connection::H245TunnelingOptionEnable; - } else { - options |= H323Connection::H245TunnelingOptionDisable; - } -/* Disable until I can figure out the proper way to deal with this */ -#if 0 - if (opts->silenceSuppression) { - options |= H323Connection::SilenceSuppresionOptionEnable; - } else { - options |= H323Connection::SilenceSUppressionOptionDisable; - } -#endif - conn = new MyH323Connection(*this, callReference, options); - if (conn) { - if (opts) - conn->SetCallOptions(opts, (setupPDU ? TRUE : FALSE)); - } - return conn; -} - -/* MyH323Connection Implementation */ -MyH323Connection::MyH323Connection(MyH323EndPoint & ep, unsigned callReference, - unsigned options) - : H323Connection(ep, callReference, options) -{ -#ifdef H323_H450 - /* Dispatcher will free out all registered handlers */ - delete h450dispatcher; - h450dispatcher = new H450xDispatcher(*this); - h4502handler = new H4502Handler(*this, *h450dispatcher); - h4504handler = new MyH4504Handler(*this, *h450dispatcher); - h4506handler = new H4506Handler(*this, *h450dispatcher); - h45011handler = new H45011Handler(*this, *h450dispatcher); -#endif - cause = -1; - sessionId = 0; - bridging = FALSE; - holdHandling = progressSetup = progressAlert = 0; - dtmfMode = 0; - dtmfCodec[0] = dtmfCodec[1] = (RTP_DataFrame::PayloadTypes)0; - redirect_reason = -1; - transfer_capability = -1; -#ifdef TUNNELLING - tunnelOptions = remoteTunnelOptions = 0; -#endif - if (h323debug) { - cout << " == New H.323 Connection created." << endl; - } - return; -} - -MyH323Connection::~MyH323Connection() -{ - if (h323debug) { - cout << " == H.323 Connection deleted." << endl; - } - return; -} - -PBoolean MyH323Connection::OnReceivedProgress(const H323SignalPDU &pdu) -{ - PBoolean isInband; - unsigned pi; - - if (!H323Connection::OnReceivedProgress(pdu)) { - return FALSE; - } - - if (!pdu.GetQ931().GetProgressIndicator(pi)) - pi = 0; - if (h323debug) { - cout << "\t- Progress Indicator: " << pi << endl; - } - - switch(pi) { - case Q931::ProgressNotEndToEndISDN: - case Q931::ProgressInbandInformationAvailable: - isInband = TRUE; - break; - default: - isInband = FALSE; - } - on_progress(GetCallReference(), (const char *)GetCallToken(), isInband); - - return connectionState != ShuttingDownConnection; -} - -PBoolean MyH323Connection::MySendProgress() -{ - /* The code taken from H323Connection::AnsweringCall() but ALWAYS send - PROGRESS message, including slow start operations */ - H323SignalPDU progressPDU; - H225_Progress_UUIE &prog = progressPDU.BuildProgress(*this); - - if (!mediaWaitForConnect) { - if (SendFastStartAcknowledge(prog.m_fastStart)) - prog.IncludeOptionalField(H225_Progress_UUIE::e_fastStart); - else { - if (connectionState == ShuttingDownConnection) - return FALSE; - - /* Do early H.245 start */ - earlyStart = TRUE; - if (!h245Tunneling) { - if (!H323Connection::StartControlChannel()) - return FALSE; - prog.IncludeOptionalField(H225_Progress_UUIE::e_h245Address); - controlChannel->SetUpTransportPDU(prog.m_h245Address, TRUE); - } - } - } - progressPDU.GetQ931().SetProgressIndicator(Q931::ProgressInbandInformationAvailable); - -#ifdef TUNNELLING - EmbedTunneledInfo(progressPDU); -#endif - HandleTunnelPDU(&progressPDU); - WriteSignalPDU(progressPDU); - - return TRUE; -} - -H323Connection::AnswerCallResponse MyH323Connection::OnAnswerCall(const PString & caller, - const H323SignalPDU & setupPDU, - H323SignalPDU & connectPDU) -{ - unsigned pi; - - if (h323debug) { - cout << "\t=-= In OnAnswerCall for call " << GetCallReference() << endl; - } - - if (connectionState == ShuttingDownConnection) - return H323Connection::AnswerCallDenied; - - if (!setupPDU.GetQ931().GetProgressIndicator(pi)) { - pi = 0; - } - if (h323debug) { - cout << "\t\t- Progress Indicator: " << pi << endl; - } - if (progressAlert) { - pi = progressAlert; - } else if (pi == Q931::ProgressOriginNotISDN) { - pi = Q931::ProgressInbandInformationAvailable; - } - if (pi && alertingPDU) { - alertingPDU->GetQ931().SetProgressIndicator(pi); - } - if (h323debug) { - cout << "\t\t- Inserting PI of " << pi << " into ALERTING message" << endl; - } - -#ifdef TUNNELLING - if (alertingPDU) - EmbedTunneledInfo(*alertingPDU); - EmbedTunneledInfo(connectPDU); -#endif - - if (!on_answer_call(GetCallReference(), (const char *)GetCallToken())) { - return H323Connection::AnswerCallDenied; - } - /* The call will be answered later with "AnsweringCall()" function. - */ - return ((pi || (fastStartState != FastStartDisabled)) ? AnswerCallDeferredWithMedia : AnswerCallDeferred); -} - -PBoolean MyH323Connection::OnAlerting(const H323SignalPDU & alertingPDU, const PString & username) -{ - if (h323debug) { - cout << "\t=-= In OnAlerting for call " << GetCallReference() - << ": sessionId=" << sessionId << endl; - cout << "\t-- Ringing phone for \"" << username << "\"" << endl; - } - - if (on_progress) { - PBoolean isInband; - unsigned alertingPI; - - if (!alertingPDU.GetQ931().GetProgressIndicator(alertingPI)) { - alertingPI = 0; - } - if (h323debug) { - cout << "\t\t- Progress Indicator: " << alertingPI << endl; - } - - switch(alertingPI) { - case Q931::ProgressNotEndToEndISDN: - case Q931::ProgressInbandInformationAvailable: - isInband = TRUE; - break; - default: - isInband = FALSE; - } - on_progress(GetCallReference(), (const char *)GetCallToken(), isInband); - } - on_chan_ringing(GetCallReference(), (const char *)GetCallToken() ); - return connectionState != ShuttingDownConnection; -} - -void MyH323Connection::SetCallOptions(void *o, PBoolean isIncoming) -{ - call_options_t *opts = (call_options_t *)o; - - progressSetup = opts->progress_setup; - progressAlert = opts->progress_alert; - holdHandling = opts->holdHandling; - dtmfCodec[0] = (RTP_DataFrame::PayloadTypes)opts->dtmfcodec[0]; - dtmfCodec[1] = (RTP_DataFrame::PayloadTypes)opts->dtmfcodec[1]; - dtmfMode = opts->dtmfmode; - - if (isIncoming) { - fastStartState = (opts->fastStart ? FastStartInitiate : FastStartDisabled); - h245Tunneling = (opts->h245Tunneling ? TRUE : FALSE); - } else { - sourceE164 = PString(opts->cid_num); - SetLocalPartyName(PString(opts->cid_name)); - SetDisplayName(PString(opts->cid_name)); - if (opts->redirect_reason >= 0) { - rdnis = PString(opts->cid_rdnis); - redirect_reason = opts->redirect_reason; - } - cid_presentation = opts->presentation; - cid_ton = opts->type_of_number; - if (opts->transfer_capability >= 0) { - transfer_capability = opts->transfer_capability; - } - } - tunnelOptions = opts->tunnelOptions; -} - -void MyH323Connection::SetCallDetails(void *callDetails, const H323SignalPDU &setupPDU, PBoolean isIncoming) -{ - PString sourceE164; - PString destE164; - PString sourceAliases; - PString destAliases; - char *s, *s1; - call_details_t *cd = (call_details_t *)callDetails; - - memset(cd, 0, sizeof(*cd)); - cd->call_reference = GetCallReference(); - cd->call_token = strdup((const char *)GetCallToken()); - - sourceE164 = ""; - setupPDU.GetSourceE164(sourceE164); - cd->call_source_e164 = strdup((const char *)sourceE164); - - destE164 = ""; - setupPDU.GetDestinationE164(destE164); - cd->call_dest_e164 = strdup((const char *)destE164); - - /* XXX Is it possible to have this information for outgoing calls too? XXX */ - if (isIncoming) { - PString sourceName; - PIPSocket::Address Ip; - WORD sourcePort; - PString redirect_number; - unsigned redirect_reason; - unsigned plan, type, screening, presentation; - Q931::InformationTransferCapability capability; - unsigned transferRate, codingStandard, userInfoLayer1; - - /* Fetch presentation and type information about calling party's number */ - if (setupPDU.GetQ931().GetCallingPartyNumber(sourceName, &plan, &type, &presentation, &screening, 0, 0)) { - /* Construct fields back */ - cd->type_of_number = (type << 4) | plan; - cd->presentation = (presentation << 5) | screening; - } else if (cd->call_source_e164[0]) { - cd->type_of_number = 0; /* UNKNOWN */ - cd->presentation = 0x03; /* ALLOWED NETWORK NUMBER - Default */ - if (setupPDU.GetQ931().HasIE(Q931::UserUserIE)) { - const H225_Setup_UUIE &setup_uuie = setupPDU.m_h323_uu_pdu.m_h323_message_body; - if (setup_uuie.HasOptionalField(H225_Setup_UUIE::e_presentationIndicator)) - cd->presentation = (cd->presentation & 0x9f) | (((unsigned int)setup_uuie.m_presentationIndicator.GetTag()) << 5); - if (setup_uuie.HasOptionalField(H225_Setup_UUIE::e_screeningIndicator)) - cd->presentation = (cd->presentation & 0xe0) | (((unsigned int)setup_uuie.m_screeningIndicator.GetValue()) & 0x1f); - } - } else { - cd->type_of_number = 0; /* UNKNOWN */ - cd->presentation = 0x43; /* NUMBER NOT AVAILABLE */ - } - - sourceName = setupPDU.GetQ931().GetDisplayName(); - cd->call_source_name = strdup((const char *)sourceName); - - GetSignallingChannel()->GetRemoteAddress().GetIpAndPort(Ip, sourcePort); - cd->sourceIp = strdup((const char *)Ip.AsString()); - - if (setupPDU.GetQ931().GetRedirectingNumber(redirect_number, NULL, NULL, NULL, NULL, &redirect_reason, 0, 0, 0)) { - cd->redirect_number = strdup((const char *)redirect_number); - cd->redirect_reason = redirect_reason; - } - else - cd->redirect_reason = -1; - - /* Fetch Q.931's transfer capability */ - if (((Q931 &)setupPDU.GetQ931()).GetBearerCapabilities(capability, transferRate, &codingStandard, &userInfoLayer1)) - cd->transfer_capability = ((unsigned int)capability & 0x1f) | (codingStandard << 5); - else - cd->transfer_capability = 0x00; /* ITU coding of Speech */ - - /* Don't show local username as called party name */ - SetDisplayName(cd->call_dest_e164); - } - - /* Convert complex strings */ - // FIXME: deal more than one source alias - sourceAliases = setupPDU.GetSourceAliases(); - s1 = strdup((const char *)sourceAliases); - if ((s = strchr(s1, ' ')) != NULL) - *s = '\0'; - if ((s = strchr(s1, '\t')) != NULL) - *s = '\0'; - cd->call_source_aliases = s1; - - destAliases = setupPDU.GetDestinationAlias(); - s1 = strdup((const char *)destAliases); - if ((s = strchr(s1, ' ')) != NULL) - *s = '\0'; - if ((s = strchr(s1, '\t')) != NULL) - *s = '\0'; - cd->call_dest_alias = s1; -} - -#ifdef TUNNELLING -static PBoolean FetchInformationElements(Q931 &q931, const PBYTEArray &data) -{ - PINDEX offset = 0; - - while (offset < data.GetSize()) { - // Get field discriminator - int discriminator = data[offset++]; - -#if 0 - /* Do not overwrite existing IEs */ - if (q931.HasIE((Q931::InformationElementCodes)discriminator)) { - if ((discriminatir & 0x80) == 0) - offset += data[offset++]; - if (offset > data.GetSize()) - return FALSE; - continue; - } -#endif - - PBYTEArray * item = new PBYTEArray; - - // For discriminator with high bit set there is no data - if ((discriminator & 0x80) == 0) { - int len = data[offset++]; - -#if 0 // That is not H.225 but regular Q.931 (ISDN) IEs - if (discriminator == UserUserIE) { - // Special case of User-user field. See 7.2.2.31/H.225.0v4. - len <<= 8; - len |= data[offset++]; - - // we also have a protocol discriminator, which we ignore - offset++; - - // before decrementing the length, make sure it is not zero - if (len == 0) - return FALSE; - - // adjust for protocol discriminator - len--; - } -#endif - - if (offset + len > data.GetSize()) { - delete item; - return FALSE; - } - - memcpy(item->GetPointer(len), (const BYTE *)data+offset, len); - offset += len; - } - - q931.SetIE((Q931::InformationElementCodes)discriminator, *item); - delete item; - } - return TRUE; -} - -static PBoolean FetchCiscoTunneledInfo(Q931 &q931, const H323SignalPDU &pdu) -{ - PBoolean res = FALSE; - const H225_H323_UU_PDU &uuPDU = pdu.m_h323_uu_pdu; - - if(uuPDU.HasOptionalField(H225_H323_UU_PDU::e_nonStandardControl)) { - for(int i = 0; i < uuPDU.m_nonStandardControl.GetSize(); ++i) { - const H225_NonStandardParameter &np = uuPDU.m_nonStandardControl[i]; - const H225_NonStandardIdentifier &id = np.m_nonStandardIdentifier; - if (id.GetTag() == H225_NonStandardIdentifier::e_h221NonStandard) { - const H225_H221NonStandard &ni = id; - /* Check for Cisco */ - if ((ni.m_t35CountryCode == 181) && (ni.m_t35Extension == 0) && (ni.m_manufacturerCode == 18)) { - const PBYTEArray &data = np.m_data; - if (h323debug) - cout << setprecision(0) << "Received non-standard Cisco extension data " << np.m_data << endl; - CISCO_H225_H323_UU_NonStdInfo c; - PPER_Stream strm(data); - if (c.Decode(strm)) { - PBoolean haveIEs = FALSE; - if (h323debug) - cout << setprecision(0) << "H323_UU_NonStdInfo = " << c << endl; - if (c.HasOptionalField(CISCO_H225_H323_UU_NonStdInfo::e_protoParam)) { - FetchInformationElements(q931, c.m_protoParam.m_qsigNonStdInfo.m_rawMesg); - haveIEs = TRUE; - } - if (c.HasOptionalField(CISCO_H225_H323_UU_NonStdInfo::e_commonParam)) { - FetchInformationElements(q931, c.m_commonParam.m_redirectIEinfo.m_redirectIE); - haveIEs = TRUE; - } - if (haveIEs && h323debug) - cout << setprecision(0) << "Information elements collected:" << q931 << endl; - res = TRUE; - } else { - cout << "ERROR while decoding non-standard Cisco extension" << endl; - return FALSE; - } - } - } - } - } - return res; -} - -static PBoolean EmbedCiscoTunneledInfo(H323SignalPDU &pdu) -{ - static const struct { - Q931::InformationElementCodes ie; - PBoolean dontDelete; - } codes[] = { - { Q931::RedirectingNumberIE, }, - { Q931::FacilityIE, }, -// { Q931::CallingPartyNumberIE, TRUE }, - }; - - PBoolean res = FALSE; - PBoolean notRedirOnly = FALSE; - Q931 tmpQ931; - Q931 &q931 = pdu.GetQ931(); - - for(unsigned i = 0; i < ARRAY_LEN(codes); ++i) { - if (q931.HasIE(codes[i].ie)) { - tmpQ931.SetIE(codes[i].ie, q931.GetIE(codes[i].ie)); - if (!codes[i].dontDelete) - q931.RemoveIE(codes[i].ie); - if (codes[i].ie != Q931::RedirectingNumberIE) - notRedirOnly = TRUE; - res = TRUE; - } - } - /* Have something to embed */ - if (res) { - PBYTEArray msg; - if (!tmpQ931.Encode(msg)) - return FALSE; - PBYTEArray ies(msg.GetPointer() + 5, msg.GetSize() - 5); - - H225_H323_UU_PDU &uuPDU = pdu.m_h323_uu_pdu; - if(!uuPDU.HasOptionalField(H225_H323_UU_PDU::e_nonStandardControl)) { - uuPDU.IncludeOptionalField(H225_H323_UU_PDU::e_nonStandardControl); - uuPDU.m_nonStandardControl.SetSize(0); - } - H225_NonStandardParameter *np = new H225_NonStandardParameter; - uuPDU.m_nonStandardControl.Append(np); - H225_NonStandardIdentifier &nsi = (*np).m_nonStandardIdentifier; - nsi.SetTag(H225_NonStandardIdentifier::e_h221NonStandard); - H225_H221NonStandard &ns = nsi; - ns.m_t35CountryCode = 181; - ns.m_t35Extension = 0; - ns.m_manufacturerCode = 18; - - CISCO_H225_H323_UU_NonStdInfo c; - c.IncludeOptionalField(CISCO_H225_H323_UU_NonStdInfo::e_version); - c.m_version = 0; - - if (notRedirOnly) { - c.IncludeOptionalField(CISCO_H225_H323_UU_NonStdInfo::e_protoParam); - CISCO_H225_QsigNonStdInfo &qsigInfo = c.m_protoParam.m_qsigNonStdInfo; - qsigInfo.m_iei = ies[0]; - qsigInfo.m_rawMesg = ies; - } else { - c.IncludeOptionalField(CISCO_H225_H323_UU_NonStdInfo::e_commonParam); - c.m_commonParam.m_redirectIEinfo.m_redirectIE = ies; - } - PPER_Stream stream; - c.Encode(stream); - stream.CompleteEncoding(); - (*np).m_data = stream; - } - return res; -} - -static const char OID_QSIG[] = "1.3.12.9"; - -static PBoolean FetchQSIGTunneledInfo(Q931 &q931, const H323SignalPDU &pdu) -{ - PBoolean res = FALSE; - const H225_H323_UU_PDU &uuPDU = pdu.m_h323_uu_pdu; - if (uuPDU.HasOptionalField(H225_H323_UU_PDU::e_tunnelledSignallingMessage)) { - const H225_H323_UU_PDU_tunnelledSignallingMessage &sig = uuPDU.m_tunnelledSignallingMessage; - const H225_TunnelledProtocol_id &proto = sig.m_tunnelledProtocolID.m_id; - if ((proto.GetTag() == H225_TunnelledProtocol_id::e_tunnelledProtocolObjectID) && - (((const PASN_ObjectId &)proto).AsString() == OID_QSIG)) { - const H225_ArrayOf_PASN_OctetString &sigs = sig.m_messageContent; - for(int i = 0; i < sigs.GetSize(); ++i) { - const PASN_OctetString &msg = sigs[i]; - if (h323debug) - cout << setprecision(0) << "Q.931 message data is " << msg << endl; - if(!q931.Decode((const PBYTEArray &)msg)) { - cout << "Error while decoding Q.931 message" << endl; - return FALSE; - } - res = TRUE; - if (h323debug) - cout << setprecision(0) << "Received QSIG message " << q931 << endl; - } - } - } - return res; -} - -static H225_EndpointType *GetEndpointType(H323SignalPDU &pdu) -{ - if (!pdu.GetQ931().HasIE(Q931::UserUserIE)) - return NULL; - - H225_H323_UU_PDU_h323_message_body &body = pdu.m_h323_uu_pdu.m_h323_message_body; - switch (body.GetTag()) { - case H225_H323_UU_PDU_h323_message_body::e_setup: - return &((H225_Setup_UUIE &)body).m_sourceInfo; - case H225_H323_UU_PDU_h323_message_body::e_callProceeding: - return &((H225_CallProceeding_UUIE &)body).m_destinationInfo; - case H225_H323_UU_PDU_h323_message_body::e_connect: - return &((H225_Connect_UUIE &)body).m_destinationInfo; - case H225_H323_UU_PDU_h323_message_body::e_alerting: - return &((H225_Alerting_UUIE &)body).m_destinationInfo; - case H225_H323_UU_PDU_h323_message_body::e_facility: - return &((H225_Facility_UUIE &)body).m_destinationInfo; - case H225_H323_UU_PDU_h323_message_body::e_progress: - return &((H225_Progress_UUIE &)body).m_destinationInfo; - } - return NULL; -} - -static PBoolean QSIGTunnelRequested(H323SignalPDU &pdu) -{ - H225_EndpointType *epType = GetEndpointType(pdu); - if (epType) { - if (!(*epType).HasOptionalField(H225_EndpointType::e_supportedTunnelledProtocols)) { - return FALSE; - } - H225_ArrayOf_TunnelledProtocol &protos = (*epType).m_supportedTunnelledProtocols; - for (int i = 0; i < protos.GetSize(); ++i) - { - if ((protos[i].GetTag() == H225_TunnelledProtocol_id::e_tunnelledProtocolObjectID) && - (((const PASN_ObjectId &)protos[i]).AsString() == OID_QSIG)) { - return TRUE; - } - } - } - return FALSE; -} - -static PBoolean EmbedQSIGTunneledInfo(H323SignalPDU &pdu) -{ - static const Q931::InformationElementCodes codes[] = - { Q931::RedirectingNumberIE, Q931::FacilityIE }; - - Q931 &q931 = pdu.GetQ931(); - PBYTEArray message; - - q931.Encode(message); - - /* Remove non-standard IEs */ - for(unsigned i = 0; i < ARRAY_LEN(codes); ++i) { - if (q931.HasIE(codes[i])) { - q931.RemoveIE(codes[i]); - } - } - - H225_H323_UU_PDU &uuPDU = pdu.m_h323_uu_pdu; - H225_EndpointType *epType = GetEndpointType(pdu); - if (epType) { - if (!(*epType).HasOptionalField(H225_EndpointType::e_supportedTunnelledProtocols)) { - (*epType).IncludeOptionalField(H225_EndpointType::e_supportedTunnelledProtocols); - (*epType).m_supportedTunnelledProtocols.SetSize(0); - } - H225_ArrayOf_TunnelledProtocol &protos = (*epType).m_supportedTunnelledProtocols; - PBoolean addQSIG = TRUE; - for (int i = 0; i < protos.GetSize(); ++i) - { - if ((protos[i].GetTag() == H225_TunnelledProtocol_id::e_tunnelledProtocolObjectID) && - (((PASN_ObjectId &)protos[i]).AsString() == OID_QSIG)) { - addQSIG = FALSE; - break; - } - } - if (addQSIG) { - H225_TunnelledProtocol *proto = new H225_TunnelledProtocol; - (*proto).m_id.SetTag(H225_TunnelledProtocol_id::e_tunnelledProtocolObjectID); - (PASN_ObjectId &)(proto->m_id) = OID_QSIG; - protos.Append(proto); - } - } - if (!uuPDU.HasOptionalField(H225_H323_UU_PDU::e_tunnelledSignallingMessage)) - uuPDU.IncludeOptionalField(H225_H323_UU_PDU::e_tunnelledSignallingMessage); - H225_H323_UU_PDU_tunnelledSignallingMessage &sig = uuPDU.m_tunnelledSignallingMessage; - H225_TunnelledProtocol_id &proto = sig.m_tunnelledProtocolID.m_id; - if ((proto.GetTag() != H225_TunnelledProtocol_id::e_tunnelledProtocolObjectID) || - (((const PASN_ObjectId &)proto).AsString() != OID_QSIG)) { - proto.SetTag(H225_TunnelledProtocol_id::e_tunnelledProtocolObjectID); - (PASN_ObjectId &)proto = OID_QSIG; - sig.m_messageContent.SetSize(0); - } - PASN_OctetString *msg = new PASN_OctetString; - sig.m_messageContent.Append(msg); - *msg = message; - return TRUE; -} - -PBoolean MyH323Connection::EmbedTunneledInfo(H323SignalPDU &pdu) -{ - if ((tunnelOptions & H323_TUNNEL_QSIG) || (remoteTunnelOptions & H323_TUNNEL_QSIG)) - EmbedQSIGTunneledInfo(pdu); - if ((tunnelOptions & H323_TUNNEL_CISCO) || (remoteTunnelOptions & H323_TUNNEL_CISCO)) - EmbedCiscoTunneledInfo(pdu); - - return TRUE; -} - -/* Handle tunneled messages */ -PBoolean MyH323Connection::HandleSignalPDU(H323SignalPDU &pdu) -{ - if (pdu.GetQ931().HasIE(Q931::UserUserIE)) { - Q931 tunneledInfo; - const Q931 *q931Info; - - q931Info = NULL; - if (FetchCiscoTunneledInfo(tunneledInfo, pdu)) { - q931Info = &tunneledInfo; - remoteTunnelOptions |= H323_TUNNEL_CISCO; - } - if (FetchQSIGTunneledInfo(tunneledInfo, pdu)) { - q931Info = &tunneledInfo; - remoteTunnelOptions |= H323_TUNNEL_QSIG; - } - if (!(remoteTunnelOptions & H323_TUNNEL_QSIG) && QSIGTunnelRequested(pdu)) { - remoteTunnelOptions |= H323_TUNNEL_QSIG; - } - if (q931Info) { - if (q931Info->HasIE(Q931::RedirectingNumberIE)) { - pdu.GetQ931().SetIE(Q931::RedirectingNumberIE, q931Info->GetIE(Q931::RedirectingNumberIE)); - if (h323debug) { - PString number; - unsigned reason; - if(q931Info->GetRedirectingNumber(number, NULL, NULL, NULL, NULL, &reason, 0, 0, 0)) - cout << "Got redirection from " << number << ", reason " << reason << endl; - } - } - } - } - - return H323Connection::HandleSignalPDU(pdu); -} -#endif - -PBoolean MyH323Connection::OnReceivedSignalSetup(const H323SignalPDU & setupPDU) -{ - call_details_t cd; - - if (h323debug) { - cout << "\t--Received SETUP message" << endl; - } - - if (connectionState == ShuttingDownConnection) - return FALSE; - - SetCallDetails(&cd, setupPDU, TRUE); - - /* Notify Asterisk of the request */ - call_options_t *res = on_incoming_call(&cd); - - if (!res) { - if (h323debug) { - cout << "\t-- Call Failed" << endl; - } - return FALSE; - } - - SetCallOptions(res, TRUE); - - /* Disable fastStart if requested by remote side */ - if (h245Tunneling && !setupPDU.m_h323_uu_pdu.m_h245Tunneling) { - masterSlaveDeterminationProcedure->Stop(); - capabilityExchangeProcedure->Stop(); - PTRACE(3, "H225\tFast Start DISABLED!"); - h245Tunneling = FALSE; - } - - return H323Connection::OnReceivedSignalSetup(setupPDU); -} - -PBoolean MyH323Connection::OnSendSignalSetup(H323SignalPDU & setupPDU) -{ - call_details_t cd; - - if (h323debug) { - cout << "\t-- Sending SETUP message" << endl; - } - - if (connectionState == ShuttingDownConnection) - return FALSE; - - if (progressSetup) - setupPDU.GetQ931().SetProgressIndicator(progressSetup); - - if (redirect_reason >= 0) { - setupPDU.GetQ931().SetRedirectingNumber(rdnis, 0, 0, 0, 0, redirect_reason); - /* OpenH323 incorrectly fills number IE when redirecting reason is specified - fix it */ - PBYTEArray IE(setupPDU.GetQ931().GetIE(Q931::RedirectingNumberIE)); - IE[0] = IE[0] & 0x7f; - IE[1] = IE[1] & 0x7f; - setupPDU.GetQ931().SetIE(Q931::RedirectingNumberIE, IE); - } - - if (transfer_capability) - setupPDU.GetQ931().SetBearerCapabilities((Q931::InformationTransferCapability)(transfer_capability & 0x1f), 1, ((transfer_capability >> 5) & 3)); - - SetCallDetails(&cd, setupPDU, FALSE); - - int res = on_outgoing_call(&cd); - if (!res) { - if (h323debug) { - cout << "\t-- Call Failed" << endl; - } - return FALSE; - } - - /* OpenH323 will build calling party information with default - type and presentation information, so build it to be recorded - by embedding routines */ - setupPDU.GetQ931().SetCallingPartyNumber(sourceE164, (cid_ton >> 4) & 0x07, - cid_ton & 0x0f, (cid_presentation >> 5) & 0x03, cid_presentation & 0x1f); - setupPDU.GetQ931().SetDisplayName(GetDisplayName()); - -#ifdef TUNNELLING - EmbedTunneledInfo(setupPDU); -#endif - - return H323Connection::OnSendSignalSetup(setupPDU); -} - -static PBoolean BuildFastStartList(const H323Channel & channel, - H225_ArrayOf_PASN_OctetString & array, - H323Channel::Directions reverseDirection) -{ - H245_OpenLogicalChannel open; - const H323Capability & capability = channel.GetCapability(); - - if (channel.GetDirection() != reverseDirection) { - if (!capability.OnSendingPDU(open.m_forwardLogicalChannelParameters.m_dataType)) - return FALSE; - } - else { - if (!capability.OnSendingPDU(open.m_reverseLogicalChannelParameters.m_dataType)) - return FALSE; - - open.m_forwardLogicalChannelParameters.m_multiplexParameters.SetTag( - H245_OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters::e_none); - open.m_forwardLogicalChannelParameters.m_dataType.SetTag(H245_DataType::e_nullData); - open.IncludeOptionalField(H245_OpenLogicalChannel::e_reverseLogicalChannelParameters); - } - - if (!channel.OnSendingPDU(open)) - return FALSE; - - PTRACE(4, "H225\tBuild fastStart:\n " << setprecision(2) << open); - PINDEX last = array.GetSize(); - array.SetSize(last+1); - array[last].EncodeSubType(open); - - PTRACE(3, "H225\tBuilt fastStart for " << capability); - return TRUE; -} - -H323Connection::CallEndReason MyH323Connection::SendSignalSetup(const PString & alias, - const H323TransportAddress & address) -{ - // Start the call, first state is asking gatekeeper - connectionState = AwaitingGatekeeperAdmission; - - // Indicate the direction of call. - if (alias.IsEmpty()) - remotePartyName = remotePartyAddress = address; - else { - remotePartyName = alias; - remotePartyAddress = alias + '@' + address; - } - - // Start building the setup PDU to get various ID's - H323SignalPDU setupPDU; - H225_Setup_UUIE & setup = setupPDU.BuildSetup(*this, address); - -#ifdef H323_H450 - h450dispatcher->AttachToSetup(setupPDU); -#endif - - // Save the identifiers generated by BuildSetup - setupPDU.GetQ931().GetCalledPartyNumber(remotePartyNumber); - - H323TransportAddress gatekeeperRoute = address; - - // Check for gatekeeper and do admission check if have one - H323Gatekeeper * gatekeeper = endpoint.GetGatekeeper(); - H225_ArrayOf_AliasAddress newAliasAddresses; - if (gatekeeper != NULL) { - H323Gatekeeper::AdmissionResponse response; - response.transportAddress = &gatekeeperRoute; - response.aliasAddresses = &newAliasAddresses; - if (!gkAccessTokenOID) - response.accessTokenData = &gkAccessTokenData; - while (!gatekeeper->AdmissionRequest(*this, response, alias.IsEmpty())) { - PTRACE(1, "H225\tGatekeeper refused admission: " - << (response.rejectReason == UINT_MAX - ? PString("Transport error") - : H225_AdmissionRejectReason(response.rejectReason).GetTagName())); -#ifdef H323_H450 - h4502handler->onReceivedAdmissionReject(H4501_GeneralErrorList::e_notAvailable); -#endif - - switch (response.rejectReason) { - case H225_AdmissionRejectReason::e_calledPartyNotRegistered: - return EndedByNoUser; - case H225_AdmissionRejectReason::e_requestDenied: - return EndedByNoBandwidth; - case H225_AdmissionRejectReason::e_invalidPermission: - case H225_AdmissionRejectReason::e_securityDenial: - return EndedBySecurityDenial; - case H225_AdmissionRejectReason::e_resourceUnavailable: - return EndedByRemoteBusy; - case H225_AdmissionRejectReason::e_incompleteAddress: - if (OnInsufficientDigits()) - break; - // Then default case - default: - return EndedByGatekeeper; - } - - PString lastRemotePartyName = remotePartyName; - while (lastRemotePartyName == remotePartyName) { - Unlock(); // Release the mutex as can deadlock trying to clear call during connect. - digitsWaitFlag.Wait(); - if (!Lock()) // Lock while checking for shutting down. - return EndedByCallerAbort; - } - } - mustSendDRQ = TRUE; - if (response.gatekeeperRouted) { - setup.IncludeOptionalField(H225_Setup_UUIE::e_endpointIdentifier); - setup.m_endpointIdentifier = gatekeeper->GetEndpointIdentifier(); - gatekeeperRouted = TRUE; - } - } - -#ifdef H323_TRANSNEXUS_OSP - // check for OSP server (if not using GK) - if (gatekeeper == NULL) { - OpalOSP::Provider * ospProvider = endpoint.GetOSPProvider(); - if (ospProvider != NULL) { - OpalOSP::Transaction * transaction = new OpalOSP::Transaction(); - if (transaction->Open(*ospProvider) != 0) { - PTRACE(1, "H225\tCannot create OSP transaction"); - return EndedByOSPRefusal; - } - - OpalOSP::Transaction::DestinationInfo destInfo; - if (!AuthoriseOSPTransaction(*transaction, destInfo)) { - delete transaction; - return EndedByOSPRefusal; - } - - // save the transaction for use by the call - ospTransaction = transaction; - - // retreive the call information - gatekeeperRoute = destInfo.destinationAddress; - newAliasAddresses.Append(new H225_AliasAddress(destInfo.calledNumber)); - - // insert the token - setup.IncludeOptionalField(H225_Setup_UUIE::e_tokens); - destInfo.InsertToken(setup.m_tokens); - } - } -#endif - - // Update the field e_destinationAddress in the SETUP PDU to reflect the new - // alias received in the ACF (m_destinationInfo). - if (newAliasAddresses.GetSize() > 0) { - setup.IncludeOptionalField(H225_Setup_UUIE::e_destinationAddress); - setup.m_destinationAddress = newAliasAddresses; - - // Update the Q.931 Information Element (if is an E.164 address) - PString e164 = H323GetAliasAddressE164(newAliasAddresses); - if (!e164) - remotePartyNumber = e164; - } - - if (addAccessTokenToSetup && !gkAccessTokenOID && !gkAccessTokenData.IsEmpty()) { - PString oid1, oid2; - PINDEX comma = gkAccessTokenOID.Find(','); - if (comma == P_MAX_INDEX) - oid1 = oid2 = gkAccessTokenOID; - else { - oid1 = gkAccessTokenOID.Left(comma); - oid2 = gkAccessTokenOID.Mid(comma+1); - } - setup.IncludeOptionalField(H225_Setup_UUIE::e_tokens); - PINDEX last = setup.m_tokens.GetSize(); - setup.m_tokens.SetSize(last+1); - setup.m_tokens[last].m_tokenOID = oid1; - setup.m_tokens[last].IncludeOptionalField(H235_ClearToken::e_nonStandard); - setup.m_tokens[last].m_nonStandard.m_nonStandardIdentifier = oid2; - setup.m_tokens[last].m_nonStandard.m_data = gkAccessTokenData; - } - - if (!signallingChannel->SetRemoteAddress(gatekeeperRoute)) { - PTRACE(1, "H225\tInvalid " - << (gatekeeperRoute != address ? "gatekeeper" : "user") - << " supplied address: \"" << gatekeeperRoute << '"'); - connectionState = AwaitingTransportConnect; - return EndedByConnectFail; - } - - // Do the transport connect - connectionState = AwaitingTransportConnect; - - // Release the mutex as can deadlock trying to clear call during connect. - Unlock(); - - signallingChannel->SetWriteTimeout(100); - - PBoolean connectFailed = !signallingChannel->Connect(); - - // Lock while checking for shutting down. - if (!Lock()) - return EndedByCallerAbort; - - // See if transport connect failed, abort if so. - if (connectFailed) { - connectionState = NoConnectionActive; - switch (signallingChannel->GetErrorNumber()) { - case ENETUNREACH : - return EndedByUnreachable; - case ECONNREFUSED : - return EndedByNoEndPoint; - case ETIMEDOUT : - return EndedByHostOffline; - } - return EndedByConnectFail; - } - - PTRACE(3, "H225\tSending Setup PDU"); - connectionState = AwaitingSignalConnect; - - // Put in all the signalling addresses for link - setup.IncludeOptionalField(H225_Setup_UUIE::e_sourceCallSignalAddress); - signallingChannel->SetUpTransportPDU(setup.m_sourceCallSignalAddress, TRUE); - if (!setup.HasOptionalField(H225_Setup_UUIE::e_destCallSignalAddress)) { - setup.IncludeOptionalField(H225_Setup_UUIE::e_destCallSignalAddress); - signallingChannel->SetUpTransportPDU(setup.m_destCallSignalAddress, FALSE); - } - - // If a standard call do Fast Start (if required) - if (setup.m_conferenceGoal.GetTag() == H225_Setup_UUIE_conferenceGoal::e_create) { - - // Get the local capabilities before fast start is handled - OnSetLocalCapabilities(); - - // Ask the application what channels to open - PTRACE(3, "H225\tCheck for Fast start by local endpoint"); - fastStartChannels.RemoveAll(); - OnSelectLogicalChannels(); - - // If application called OpenLogicalChannel, put in the fastStart field - if (!fastStartChannels.IsEmpty()) { - PTRACE(3, "H225\tFast start begun by local endpoint"); - for (PINDEX i = 0; i < fastStartChannels.GetSize(); i++) - BuildFastStartList(fastStartChannels[i], setup.m_fastStart, H323Channel::IsReceiver); - if (setup.m_fastStart.GetSize() > 0) - setup.IncludeOptionalField(H225_Setup_UUIE::e_fastStart); - } - - // Search the capability set and see if we have video capability - for (PINDEX i = 0; i < localCapabilities.GetSize(); i++) { - switch (localCapabilities[i].GetMainType()) { - case H323Capability::e_Audio: - case H323Capability::e_UserInput: - break; - - default: // Is video or other data (eg T.120) - setupPDU.GetQ931().SetBearerCapabilities(Q931::TransferUnrestrictedDigital, 6); - i = localCapabilities.GetSize(); // Break out of the for loop - break; - } - } - } - - if (!OnSendSignalSetup(setupPDU)) - return EndedByNoAccept; - - // Do this again (was done when PDU was constructed) in case - // OnSendSignalSetup() changed something. -// setupPDU.SetQ931Fields(*this, TRUE); - setupPDU.GetQ931().GetCalledPartyNumber(remotePartyNumber); - - fastStartState = FastStartDisabled; - PBoolean set_lastPDUWasH245inSETUP = FALSE; - - if (h245Tunneling && doH245inSETUP) { - h245TunnelTxPDU = &setupPDU; - - // Try and start the master/slave and capability exchange through the tunnel - // Note: this used to be disallowed but is now allowed as of H323v4 - PBoolean ok = StartControlNegotiations(); - - h245TunnelTxPDU = NULL; - - if (!ok) - return EndedByTransportFail; - - if (setup.m_fastStart.GetSize() > 0) { - // Now if fast start as well need to put this in setup specific field - // and not the generic H.245 tunneling field - setup.IncludeOptionalField(H225_Setup_UUIE::e_parallelH245Control); - setup.m_parallelH245Control = setupPDU.m_h323_uu_pdu.m_h245Control; - setupPDU.m_h323_uu_pdu.RemoveOptionalField(H225_H323_UU_PDU::e_h245Control); - set_lastPDUWasH245inSETUP = TRUE; - } - } - - // Send the initial PDU - setupTime = PTime(); - if (!WriteSignalPDU(setupPDU)) - return EndedByTransportFail; - - // WriteSignalPDU always resets lastPDUWasH245inSETUP. - // So set it here if required - if (set_lastPDUWasH245inSETUP) - lastPDUWasH245inSETUP = TRUE; - - // Set timeout for remote party to answer the call - signallingChannel->SetReadTimeout(endpoint.GetSignallingChannelCallTimeout()); - - return NumCallEndReasons; -} - - -PBoolean MyH323Connection::OnSendReleaseComplete(H323SignalPDU & releaseCompletePDU) -{ - if (h323debug) { - cout << "\t-- Sending RELEASE COMPLETE" << endl; - } - if (cause > 0) - releaseCompletePDU.GetQ931().SetCause((Q931::CauseValues)cause); - -#ifdef TUNNELLING - EmbedTunneledInfo(releaseCompletePDU); -#endif - - return H323Connection::OnSendReleaseComplete(releaseCompletePDU); -} - -PBoolean MyH323Connection::OnReceivedFacility(const H323SignalPDU & pdu) -{ - if (h323debug) { - cout << "\t-- Received Facility message... " << endl; - } - return H323Connection::OnReceivedFacility(pdu); -} - -void MyH323Connection::OnReceivedReleaseComplete(const H323SignalPDU & pdu) -{ - if (h323debug) { - cout << "\t-- Received RELEASE COMPLETE message..." << endl; - } - if (on_hangup) - on_hangup(GetCallReference(), (const char *)GetCallToken(), pdu.GetQ931().GetCause()); - return H323Connection::OnReceivedReleaseComplete(pdu); -} - -PBoolean MyH323Connection::OnClosingLogicalChannel(H323Channel & channel) -{ - if (h323debug) { - cout << "\t-- Closing logical channel..." << endl; - } - return H323Connection::OnClosingLogicalChannel(channel); -} - -void MyH323Connection::SendUserInputTone(char tone, unsigned duration, unsigned logicalChannel, unsigned rtpTimestamp) -{ - SendUserInputModes mode = GetRealSendUserInputMode(); -// That is recursive call... Why? -// on_receive_digit(GetCallReference(), tone, (const char *)GetCallToken()); - if ((tone != ' ') || (mode == SendUserInputAsTone) || (mode == SendUserInputAsInlineRFC2833)) { - if (h323debug) { - cout << "\t-- Sending user input tone (" << tone << ") to remote" << endl; - } - H323Connection::SendUserInputTone(tone, duration); - } -} - -void MyH323Connection::OnUserInputTone(char tone, unsigned duration, unsigned logicalChannel, unsigned rtpTimestamp) -{ - /* Why we should check this? */ - if ((dtmfMode & (H323_DTMF_CISCO | H323_DTMF_RFC2833 | H323_DTMF_SIGNAL)) != 0) { - if (h323debug) { - cout << "\t-- Received user input tone (" << tone << ") from remote" << endl; - } - on_receive_digit(GetCallReference(), tone, (const char *)GetCallToken(), duration); - } -} - -void MyH323Connection::OnUserInputString(const PString &value) -{ - if (h323debug) { - cout << "\t-- Received user input string (" << value << ") from remote." << endl; - } - on_receive_digit(GetCallReference(), value[0], (const char *)GetCallToken(), 0); -} - -void MyH323Connection::OnSendCapabilitySet(H245_TerminalCapabilitySet & pdu) -{ - PINDEX i; - - H323Connection::OnSendCapabilitySet(pdu); - - H245_ArrayOf_CapabilityTableEntry & tables = pdu.m_capabilityTable; - for(i = 0; i < tables.GetSize(); i++) - { - H245_CapabilityTableEntry & entry = tables[i]; - if (entry.HasOptionalField(H245_CapabilityTableEntry::e_capability)) { - H245_Capability & cap = entry.m_capability; - if (cap.GetTag() == H245_Capability::e_receiveRTPAudioTelephonyEventCapability) { - H245_AudioTelephonyEventCapability & atec = cap; - atec.m_dynamicRTPPayloadType = dtmfCodec[0]; -// on_set_rfc2833_payload(GetCallReference(), (const char *)GetCallToken(), (int)dtmfCodec[0]); -#ifdef PTRACING - if (h323debug) { - cout << "\t-- Receiving RFC2833 on payload " << - atec.m_dynamicRTPPayloadType << endl; - } -#endif - } - } - } -} - -void MyH323Connection::OnSetLocalCapabilities() -{ - if (on_setcapabilities) - on_setcapabilities(GetCallReference(), (const char *)callToken); -} - -PBoolean MyH323Connection::OnReceivedCapabilitySet(const H323Capabilities & remoteCaps, - const H245_MultiplexCapability * muxCap, - H245_TerminalCapabilitySetReject & reject) -{ - struct __codec__ { - unsigned int asterisk_codec; - unsigned int h245_cap; - const char *oid; - const char *formatName; - }; - static const struct __codec__ codecs[] = { - { AST_FORMAT_G723_1, H245_AudioCapability::e_g7231 }, - { AST_FORMAT_GSM, H245_AudioCapability::e_gsmFullRate }, - { AST_FORMAT_ULAW, H245_AudioCapability::e_g711Ulaw64k }, - { AST_FORMAT_ALAW, H245_AudioCapability::e_g711Alaw64k }, - { AST_FORMAT_G729A, H245_AudioCapability::e_g729AnnexA }, - { AST_FORMAT_G729A, H245_AudioCapability::e_g729 }, - { AST_FORMAT_G726_AAL2, H245_AudioCapability::e_nonStandard, NULL, CISCO_G726r32 }, -#ifdef AST_FORMAT_MODEM - { AST_FORMAT_MODEM, H245_DataApplicationCapability_application::e_t38fax }, -#endif - { 0 } - }; - -#if 0 - static const struct __codec__ vcodecs[] = { -#ifdef HAVE_H261 - { AST_FORMAT_H261, H245_VideoCapability::e_h261VideoCapability }, -#endif -#ifdef HAVE_H263 - { AST_FORMAT_H263, H245_VideoCapability::e_h263VideoCapability }, -#endif -#ifdef HAVE_H264 - { AST_FORMAT_H264, H245_VideoCapability::e_genericVideoCapability, "0.0.8.241.0.0.1" }, -#endif - { 0 } - }; -#endif - struct ast_codec_pref prefs; - RTP_DataFrame::PayloadTypes pt; - - if (!H323Connection::OnReceivedCapabilitySet(remoteCaps, muxCap, reject)) { - return FALSE; - } - - memset(&prefs, 0, sizeof(prefs)); - int peer_capabilities = 0; - for (int i = 0; i < remoteCapabilities.GetSize(); ++i) { - unsigned int subType = remoteCapabilities[i].GetSubType(); - if (h323debug) { - cout << "Peer capability is " << remoteCapabilities[i] << endl; - } - switch(remoteCapabilities[i].GetMainType()) { - case H323Capability::e_Audio: - for (int x = 0; codecs[x].asterisk_codec > 0; ++x) { - if ((subType == codecs[x].h245_cap) && (!codecs[x].formatName || (!strcmp(codecs[x].formatName, (const char *)remoteCapabilities[i].GetFormatName())))) { - int ast_codec = codecs[x].asterisk_codec; - int ms = 0; - struct ast_format tmpfmt; - if (!(peer_capabilities & ast_format_id_to_old_bitfield((enum ast_format_id) ast_codec))) { - struct ast_format_list format; - ast_codec_pref_append(&prefs, ast_format_set(&tmpfmt, (enum ast_format_id) ast_codec, 0)); - format = ast_codec_pref_getsize(&prefs, &tmpfmt); - if ((ast_codec == AST_FORMAT_ALAW) || (ast_codec == AST_FORMAT_ULAW)) { - ms = remoteCapabilities[i].GetTxFramesInPacket(); - } else - ms = remoteCapabilities[i].GetTxFramesInPacket() * format.inc_ms; - ast_codec_pref_setsize(&prefs, &tmpfmt, ms); - } - if (h323debug) { - cout << "Found peer capability " << remoteCapabilities[i] << ", Asterisk code is " << ast_codec << ", frame size (in ms) is " << ms << endl; - } - peer_capabilities |= ast_format_id_to_old_bitfield((enum ast_format_id) ast_codec); - } - } - break; - case H323Capability::e_Data: - if (!strcmp((const char *)remoteCapabilities[i].GetFormatName(), CISCO_DTMF_RELAY)) { - pt = remoteCapabilities[i].GetPayloadType(); - if ((dtmfMode & H323_DTMF_CISCO) != 0) { - on_set_rfc2833_payload(GetCallReference(), (const char *)GetCallToken(), (int)pt, 1); -// if (sendUserInputMode == SendUserInputAsTone) -// sendUserInputMode = SendUserInputAsInlineRFC2833; - } -#ifdef PTRACING - if (h323debug) { - cout << "\t-- Outbound Cisco RTP DTMF on payload " << pt << endl; - } -#endif - } - break; - case H323Capability::e_UserInput: - if (!strcmp((const char *)remoteCapabilities[i].GetFormatName(), H323_UserInputCapability::SubTypeNames[H323_UserInputCapability::SignalToneRFC2833])) { - pt = remoteCapabilities[i].GetPayloadType(); - if ((dtmfMode & H323_DTMF_RFC2833) != 0) { - on_set_rfc2833_payload(GetCallReference(), (const char *)GetCallToken(), (int)pt, 0); -// if (sendUserInputMode == SendUserInputAsTone) -// sendUserInputMode = SendUserInputAsInlineRFC2833; - } -#ifdef PTRACING - if (h323debug) { - cout << "\t-- Outbound RFC2833 on payload " << pt << endl; - } -#endif - } - break; -#if 0 - case H323Capability::e_Video: - for (int x = 0; vcodecs[x].asterisk_codec > 0; ++x) { - if (subType == vcodecs[x].h245_cap) { - H245_CapabilityIdentifier *cap = NULL; - H245_GenericCapability y; - if (vcodecs[x].oid) { - cap = new H245_CapabilityIdentifier(H245_CapabilityIdentifier::e_standard); - PASN_ObjectId &object_id = *cap; - object_id = vcodecs[x].oid; - y.m_capabilityIdentifier = *cap; - } - if ((subType != H245_VideoCapability::e_genericVideoCapability) || - (vcodecs[x].oid && ((const H323GenericVideoCapability &)remoteCapabilities[i]).IsGenericMatch((const H245_GenericCapability)y))) { - if (h323debug) { - cout << "Found peer video capability " << remoteCapabilities[i] << ", Asterisk code is " << vcodecs[x].asterisk_codec << endl; - } - peer_capabilities |= vcodecs[x].asterisk_codec; - } - if (cap) - delete(cap); - } - } - break; -#endif - default: - break; - } - } - -#if 0 - redir_capabilities &= peer_capabilities; -#endif - if (on_setpeercapabilities) - on_setpeercapabilities(GetCallReference(), (const char *)callToken, peer_capabilities, &prefs); - - return TRUE; -} - -H323Channel * MyH323Connection::CreateRealTimeLogicalChannel(const H323Capability & capability, - H323Channel::Directions dir, - unsigned sessionID, - const H245_H2250LogicalChannelParameters * /*param*/, - RTP_QOS * /*param*/ ) -{ - /* Do not open tx channel when transmitter has been paused by empty TCS */ - if ((dir == H323Channel::IsTransmitter) && transmitterSidePaused) - return NULL; - - return new MyH323_ExternalRTPChannel(*this, capability, dir, sessionID); -} - -/** This callback function is invoked once upon creation of each - * channel for an H323 session - */ -PBoolean MyH323Connection::OnStartLogicalChannel(H323Channel & channel) -{ - /* Increase the count of channels we have open */ - channelsOpen++; - - if (h323debug) { - cout << "\t-- Started logical channel: " - << ((channel.GetDirection() == H323Channel::IsTransmitter) ? "sending " : ((channel.GetDirection() == H323Channel::IsReceiver) ? "receiving " : " ")) - << (const char *)(channel.GetCapability()).GetFormatName() << endl; - cout << "\t\t-- channelsOpen = " << channelsOpen << endl; - } - return connectionState != ShuttingDownConnection; -} - -void MyH323Connection::SetCapabilities(int caps, int dtmf_mode, void *_prefs, int pref_codec) -{ - PINDEX lastcap = -1; /* last common capability index */ - int alreadysent = 0; - int codec; - int x, y; - struct ast_codec_pref *prefs = (struct ast_codec_pref *)_prefs; - struct ast_format_list format; - int frames_per_packet; - struct ast_format tmpfmt; - H323Capability *cap; - - localCapabilities.RemoveAll(); - - /* Add audio codecs in preference order first, then - audio codecs without preference as allowed by mask */ - for (y = 0, x = -1; x < 32 + 32; ++x) { - ast_format_clear(&tmpfmt); - if (x < 0) - codec = pref_codec; - else if (y || (!(ast_codec_pref_index(prefs, x, &tmpfmt)))) { - if (!y) - y = 1; - else - y <<= 1; - codec = y; - } - if (tmpfmt.id) { - codec = ast_format_to_old_bitfield(&tmpfmt); - } - if (!(caps & codec) || (alreadysent & codec) || (AST_FORMAT_GET_TYPE(ast_format_id_from_old_bitfield(codec)) != AST_FORMAT_TYPE_AUDIO)) - continue; - alreadysent |= codec; - /* format.cur_ms will be set to default if packetization is not explicitly set */ - format = ast_codec_pref_getsize(prefs, ast_format_from_old_bitfield(&tmpfmt, codec)); - frames_per_packet = (format.inc_ms ? format.cur_ms / format.inc_ms : format.cur_ms); - switch(ast_format_id_from_old_bitfield(codec)) { -#if 0 - case AST_FORMAT_SPEEX: - /* Not real sure if Asterisk acutally supports all - of the various different bit rates so add them - all and figure it out later*/ - - lastcap = localCapabilities.SetCapability(0, 0, new SpeexNarrow2AudioCapability()); - lastcap = localCapabilities.SetCapability(0, 0, new SpeexNarrow3AudioCapability()); - lastcap = localCapabilities.SetCapability(0, 0, new SpeexNarrow4AudioCapability()); - lastcap = localCapabilities.SetCapability(0, 0, new SpeexNarrow5AudioCapability()); - lastcap = localCapabilities.SetCapability(0, 0, new SpeexNarrow6AudioCapability()); - break; -#endif - case AST_FORMAT_G729A: - AST_G729ACapability *g729aCap; - AST_G729Capability *g729Cap; - lastcap = localCapabilities.SetCapability(0, 0, g729aCap = new AST_G729ACapability(frames_per_packet)); - lastcap = localCapabilities.SetCapability(0, 0, g729Cap = new AST_G729Capability(frames_per_packet)); - g729aCap->SetTxFramesInPacket(format.cur_ms); - g729Cap->SetTxFramesInPacket(format.cur_ms); - break; - case AST_FORMAT_G723_1: - AST_G7231Capability *g7231Cap; - lastcap = localCapabilities.SetCapability(0, 0, g7231Cap = new AST_G7231Capability(frames_per_packet, TRUE)); - g7231Cap->SetTxFramesInPacket(format.cur_ms); - lastcap = localCapabilities.SetCapability(0, 0, g7231Cap = new AST_G7231Capability(frames_per_packet, FALSE)); - g7231Cap->SetTxFramesInPacket(format.cur_ms); - break; - case AST_FORMAT_GSM: - AST_GSM0610Capability *gsmCap; - lastcap = localCapabilities.SetCapability(0, 0, gsmCap = new AST_GSM0610Capability(frames_per_packet)); - gsmCap->SetTxFramesInPacket(format.cur_ms); - break; - case AST_FORMAT_ULAW: - AST_G711Capability *g711uCap; - lastcap = localCapabilities.SetCapability(0, 0, g711uCap = new AST_G711Capability(format.cur_ms, H323_G711Capability::muLaw)); - g711uCap->SetTxFramesInPacket(format.cur_ms); - break; - case AST_FORMAT_ALAW: - AST_G711Capability *g711aCap; - lastcap = localCapabilities.SetCapability(0, 0, g711aCap = new AST_G711Capability(format.cur_ms, H323_G711Capability::ALaw)); - g711aCap->SetTxFramesInPacket(format.cur_ms); - break; - case AST_FORMAT_G726_AAL2: - AST_CiscoG726Capability *g726Cap; - lastcap = localCapabilities.SetCapability(0, 0, g726Cap = new AST_CiscoG726Capability(frames_per_packet)); - g726Cap->SetTxFramesInPacket(format.cur_ms); - break; - default: - alreadysent &= ~codec; - break; - } - } - - cap = new H323_UserInputCapability(H323_UserInputCapability::HookFlashH245); - if (cap && cap->IsUsable(*this)) { - lastcap++; - lastcap = localCapabilities.SetCapability(0, lastcap, cap); - } else { - delete cap; /* Capability is not usable */ - } - - dtmfMode = dtmf_mode; - if (h323debug) { - cout << "DTMF mode is " << (int)dtmfMode << endl; - } - if (dtmfMode) { - lastcap++; - if (dtmfMode == H323_DTMF_INBAND) { - cap = new H323_UserInputCapability(H323_UserInputCapability::BasicString); - if (cap && cap->IsUsable(*this)) { - lastcap = localCapabilities.SetCapability(0, lastcap, cap); - } else { - delete cap; /* Capability is not usable */ - } - sendUserInputMode = SendUserInputAsString; - } else { - if ((dtmfMode & H323_DTMF_RFC2833) != 0) { - cap = new H323_UserInputCapability(H323_UserInputCapability::SignalToneRFC2833); - if (cap && cap->IsUsable(*this)) - lastcap = localCapabilities.SetCapability(0, lastcap, cap); - else { - dtmfMode |= H323_DTMF_SIGNAL; - delete cap; /* Capability is not usable */ - } - } - if ((dtmfMode & H323_DTMF_CISCO) != 0) { - /* Try Cisco's RTP DTMF relay too, but prefer RFC2833 or h245-signal */ - cap = new AST_CiscoDtmfCapability(); - if (cap && cap->IsUsable(*this)) { - lastcap = localCapabilities.SetCapability(0, lastcap, cap); - /* We cannot send Cisco RTP DTMFs, use h245-signal instead */ - dtmfMode |= H323_DTMF_SIGNAL; - } else { - dtmfMode |= H323_DTMF_SIGNAL; - delete cap; /* Capability is not usable */ - } - } - if ((dtmfMode & H323_DTMF_SIGNAL) != 0) { - /* Cisco usually sends DTMF correctly only through h245-alphanumeric or h245-signal */ - cap = new H323_UserInputCapability(H323_UserInputCapability::SignalToneH245); - if (cap && cap->IsUsable(*this)) - lastcap = localCapabilities.SetCapability(0, lastcap, cap); - else - delete cap; /* Capability is not usable */ - } - sendUserInputMode = SendUserInputAsTone; /* RFC2833 transmission handled at Asterisk level */ - } - } - - if (h323debug) { - cout << "Allowed Codecs for " << GetCallToken() << " (" << GetSignallingChannel()->GetLocalAddress() << "):\n\t" << setprecision(2) << localCapabilities << endl; - } -} - -PBoolean MyH323Connection::StartControlChannel(const H225_TransportAddress & h245Address) -{ - // Check that it is an IP address, all we support at the moment - if (h245Address.GetTag() != H225_TransportAddress::e_ipAddress -#if P_HAS_IPV6 - && h245Address.GetTag() != H225_TransportAddress::e_ip6Address -#endif - ) { - PTRACE(1, "H225\tConnect of H245 failed: Unsupported transport"); - return FALSE; - } - - // Already have the H245 channel up. - if (controlChannel != NULL) - return TRUE; - - PIPSocket::Address addr; - WORD port; - GetSignallingChannel()->GetLocalAddress().GetIpAndPort(addr, port); - if (addr) { - if (h323debug) - cout << "Using " << addr << " for outbound H.245 transport" << endl; - controlChannel = new MyH323TransportTCP(endpoint, addr); - } else - controlChannel = new MyH323TransportTCP(endpoint); - if (!controlChannel->SetRemoteAddress(h245Address)) { - PTRACE(1, "H225\tCould not extract H245 address"); - delete controlChannel; - controlChannel = NULL; - return FALSE; - } - if (!controlChannel->Connect()) { - PTRACE(1, "H225\tConnect of H245 failed: " << controlChannel->GetErrorText()); - delete controlChannel; - controlChannel = NULL; - return FALSE; - } - - controlChannel->StartControlChannel(*this); - return TRUE; -} - -#ifdef H323_H450 -void MyH323Connection::OnReceivedLocalCallHold(int linkedId) -{ - if (on_hold) - on_hold(GetCallReference(), (const char *)GetCallToken(), 1); -} - -void MyH323Connection::OnReceivedLocalCallRetrieve(int linkedId) -{ - if (on_hold) - on_hold(GetCallReference(), (const char *)GetCallToken(), 0); -} -#endif - -void MyH323Connection::MyHoldCall(PBoolean isHold) -{ - if (((holdHandling & H323_HOLD_NOTIFY) != 0) || ((holdHandling & H323_HOLD_Q931ONLY) != 0)) { - PBYTEArray x ((const BYTE *)(isHold ? "\xF9" : "\xFA"), 1); - H323SignalPDU signal; - signal.BuildNotify(*this); - signal.GetQ931().SetIE((Q931::InformationElementCodes)39 /* Q931::NotifyIE */, x); - if (h323debug) - cout << "Sending " << (isHold ? "HOLD" : "RETRIEVE") << " notification: " << signal << endl; - if ((holdHandling & H323_HOLD_Q931ONLY) != 0) { - PBYTEArray rawData; - signal.GetQ931().RemoveIE(Q931::UserUserIE); - signal.GetQ931().Encode(rawData); - signallingChannel->WritePDU(rawData); - } else - WriteSignalPDU(signal); - } -#ifdef H323_H450 - if ((holdHandling & H323_HOLD_H450) != 0) { - if (isHold) - h4504handler->HoldCall(TRUE); - else if (IsLocalHold()) - h4504handler->RetrieveCall(); - } -#endif -} - - -/* MyH323_ExternalRTPChannel */ -MyH323_ExternalRTPChannel::MyH323_ExternalRTPChannel(MyH323Connection & connection, - const H323Capability & capability, - Directions direction, - unsigned id) - : H323_ExternalRTPChannel::H323_ExternalRTPChannel(connection, capability, direction, id) -{ - struct rtp_info *info; - - /* Determine the Local (A side) IP Address and port */ - info = on_external_rtp_create(connection.GetCallReference(), (const char *)connection.GetCallToken()); - if (!info) { - cout << "\tERROR: on_external_rtp_create failure" << endl; - return; - } else { - localIpAddr = info->addr; - localPort = info->port; - /* tell the H.323 stack */ - SetExternalAddress(H323TransportAddress(localIpAddr, localPort), H323TransportAddress(localIpAddr, localPort + 1)); - /* clean up allocated memory */ - ast_free(info); - } - - /* Get the payload code */ - OpalMediaFormat format(capability.GetFormatName(), FALSE); - payloadCode = format.GetPayloadType(); -} - -MyH323_ExternalRTPChannel::~MyH323_ExternalRTPChannel() -{ - if (h323debug) { - cout << "\tExternalRTPChannel Destroyed" << endl; - } -} - -PBoolean MyH323_ExternalRTPChannel::Start(void) -{ - /* Call ancestor first */ - if (!H323_ExternalRTPChannel::Start()) { - return FALSE; - } - - if (h323debug) { - cout << "\t\tExternal RTP Session Starting" << endl; - cout << "\t\tRTP channel id " << sessionID << " parameters:" << endl; - } - - /* Collect the remote information */ - H323_ExternalRTPChannel::GetRemoteAddress(remoteIpAddr, remotePort); - - if (h323debug) { - cout << "\t\t-- remoteIpAddress: " << remoteIpAddr << endl; - cout << "\t\t-- remotePort: " << remotePort << endl; - cout << "\t\t-- ExternalIpAddress: " << localIpAddr << endl; - cout << "\t\t-- ExternalPort: " << localPort << endl; - } - /* Notify Asterisk of remote RTP information */ - on_start_rtp_channel(connection.GetCallReference(), (const char *)remoteIpAddr.AsString(), remotePort, - (const char *)connection.GetCallToken(), (int)payloadCode); - return TRUE; -} - -PBoolean MyH323_ExternalRTPChannel::OnReceivedAckPDU(const H245_H2250LogicalChannelAckParameters & param) -{ - if (h323debug) { - cout << " MyH323_ExternalRTPChannel::OnReceivedAckPDU" << endl; - } - - if (H323_ExternalRTPChannel::OnReceivedAckPDU(param)) { - GetRemoteAddress(remoteIpAddr, remotePort); - if (h323debug) { - cout << " -- remoteIpAddress: " << remoteIpAddr << endl; - cout << " -- remotePort: " << remotePort << endl; - } - on_start_rtp_channel(connection.GetCallReference(), (const char *)remoteIpAddr.AsString(), - remotePort, (const char *)connection.GetCallToken(), (int)payloadCode); - return TRUE; - } - return FALSE; -} - -#ifdef H323_H450 -MyH4504Handler::MyH4504Handler(MyH323Connection &_conn, H450xDispatcher &_disp) - :H4504Handler(_conn, _disp) -{ - conn = &_conn; -} - -void MyH4504Handler::OnReceivedLocalCallHold(int linkedId) -{ - if (conn) { - conn->Lock(); - conn->OnReceivedLocalCallHold(linkedId); - conn->Unlock(); - } -} - -void MyH4504Handler::OnReceivedLocalCallRetrieve(int linkedId) -{ - if (conn) { - conn->Lock(); - conn->OnReceivedLocalCallRetrieve(linkedId); - conn->Unlock(); - } -} -#endif - - -/** IMPLEMENTATION OF C FUNCTIONS */ - -/** - * The extern "C" directive takes care for - * the ANSI-C representation of linkable symbols - */ - -extern "C" { - -int h323_end_point_exist(void) -{ - if (!endPoint) { - return 0; - } - return 1; -} - -void h323_end_point_create(void) -{ - channelsOpen = 0; - logstream = new PAsteriskLog(); - PTrace::SetStream(logstream); - endPoint = new MyH323EndPoint(); -} - -void h323_gk_urq(void) -{ - if (!h323_end_point_exist()) { - cout << " ERROR: [h323_gk_urq] No Endpoint, this is bad" << endl; - return; - } - endPoint->RemoveGatekeeper(); -} - -void h323_debug(int flag, unsigned level) -{ - if (flag) { - PTrace:: SetLevel(level); - } else { - PTrace:: SetLevel(0); - } -} - -/** Installs the callback functions on behalf of the PBX application */ -void h323_callback_register(setup_incoming_cb ifunc, - setup_outbound_cb sfunc, - on_rtp_cb rtpfunc, - start_rtp_cb lfunc, - clear_con_cb clfunc, - chan_ringing_cb rfunc, - con_established_cb efunc, - receive_digit_cb dfunc, - answer_call_cb acfunc, - progress_cb pgfunc, - rfc2833_cb dtmffunc, - hangup_cb hangupfunc, - setcapabilities_cb capabilityfunc, - setpeercapabilities_cb peercapabilityfunc, - onhold_cb holdfunc) -{ - on_incoming_call = ifunc; - on_outgoing_call = sfunc; - on_external_rtp_create = rtpfunc; - on_start_rtp_channel = lfunc; - on_connection_cleared = clfunc; - on_chan_ringing = rfunc; - on_connection_established = efunc; - on_receive_digit = dfunc; - on_answer_call = acfunc; - on_progress = pgfunc; - on_set_rfc2833_payload = dtmffunc; - on_hangup = hangupfunc; - on_setcapabilities = capabilityfunc; - on_setpeercapabilities = peercapabilityfunc; - on_hold = holdfunc; -} - -/** - * Add capability to the capability table of the end point. - */ -int h323_set_capabilities(const char *token, int cap, int dtmf_mode, struct ast_codec_pref *prefs, int pref_codec) -{ - MyH323Connection *conn; - - if (!h323_end_point_exist()) { - cout << " ERROR: [h323_set_capablities] No Endpoint, this is bad" << endl; - return 1; - } - if (!token || !*token) { - cout << " ERROR: [h323_set_capabilities] Invalid call token specified." << endl; - return 1; - } - - PString myToken(token); - conn = (MyH323Connection *)endPoint->FindConnectionWithLock(myToken); - if (!conn) { - cout << " ERROR: [h323_set_capabilities] Unable to find connection " << token << endl; - return 1; - } - conn->SetCapabilities((/*conn->bridging ? conn->redir_capabilities :*/ cap), dtmf_mode, prefs, pref_codec); - conn->Unlock(); - - return 0; -} - -/** Start the H.323 listener */ -int h323_start_listener(int listenPort, struct sockaddr_in bindaddr) -{ - - if (!h323_end_point_exist()) { - cout << "ERROR: [h323_start_listener] No Endpoint, this is bad!" << endl; - return 1; - } - - PIPSocket::Address interfaceAddress(bindaddr.sin_addr); - if (!listenPort) { - listenPort = 1720; - } - /** H.323 listener */ - H323ListenerTCP *tcpListener; - tcpListener = new H323ListenerTCP(*endPoint, interfaceAddress, (WORD)listenPort); - if (!endPoint->StartListener(tcpListener)) { - cout << "ERROR: Could not open H.323 listener port on " << ((H323ListenerTCP *) tcpListener)->GetListenerPort() << endl; - delete tcpListener; - return 1; - } - cout << " == H.323 listener started" << endl; - return 0; -}; - -/* Addition of functions just to make the channel driver compile with H323Plus */ -#if VERSION(OPENH323_MAJOR, OPENH323_MINOR, OPENH323_BUILD) > VERSION(1,19,4) -/* Alternate RTP port information for Same NAT */ -BOOL MyH323_ExternalRTPChannel::OnReceivedAltPDU(const H245_ArrayOf_GenericInformation & alternate ) -{ - return TRUE; -} - -/* Alternate RTP port information for Same NAT */ -BOOL MyH323_ExternalRTPChannel::OnSendingAltPDU(H245_ArrayOf_GenericInformation & alternate) const -{ - return TRUE; -} - -/* Alternate RTP port information for Same NAT */ -void MyH323_ExternalRTPChannel::OnSendOpenAckAlt(H245_ArrayOf_GenericInformation & alternate) const -{ -} - -/* Alternate RTP port information for Same NAT */ -BOOL MyH323_ExternalRTPChannel::OnReceivedAckAltPDU(const H245_ArrayOf_GenericInformation & alternate) -{ - return TRUE; -} -#endif - - -int h323_set_alias(struct oh323_alias *alias) -{ - char *p; - char *num; - PString h323id(alias->name); - PString e164(alias->e164); - char *prefix; - - if (!h323_end_point_exist()) { - cout << "ERROR: [h323_set_alias] No Endpoint, this is bad!" << endl; - return 1; - } - - cout << "== Adding alias \"" << h323id << "\" to endpoint" << endl; - endPoint->AddAliasName(h323id); - endPoint->RemoveAliasName(PProcess::Current().GetName()); - - if (!e164.IsEmpty()) { - cout << "== Adding E.164 \"" << e164 << "\" to endpoint" << endl; - endPoint->AddAliasName(e164); - } - if (strlen(alias->prefix)) { - p = prefix = strdup(alias->prefix); - while((num = strsep(&p, ",")) != (char *)NULL) { - cout << "== Adding Prefix \"" << num << "\" to endpoint" << endl; - endPoint->SupportedPrefixes += PString(num); - endPoint->SetGateway(); - } - if (prefix) - ast_free(prefix); - } - return 0; -} - -void h323_set_id(char *id) -{ - PString h323id(id); - - if (h323debug) { - cout << " == Using '" << h323id << "' as our H.323ID for this call" << endl; - } - /* EVIL HACK */ - endPoint->SetLocalUserName(h323id); -} - -void h323_show_tokens(void) -{ - cout << "Current call tokens: " << setprecision(2) << endPoint->GetAllConnections() << endl; -} - -void h323_show_version(void) -{ - cout << "H.323 version: " << OPENH323_MAJOR << "." << OPENH323_MINOR << "." << OPENH323_BUILD << endl; -} - -/** Establish Gatekeeper communiations, if so configured, - * register aliases for the H.323 endpoint to respond to. - */ -int h323_set_gk(int gatekeeper_discover, char *gatekeeper, char *secret) -{ - PString gkName = PString(gatekeeper); - PString pass = PString(secret); - H323TransportUDP *rasChannel; - - if (!h323_end_point_exist()) { - cout << "ERROR: [h323_set_gk] No Endpoint, this is bad!" << endl; - return 1; - } - - if (!gatekeeper) { - cout << "Error: Gatekeeper cannot be NULL" << endl; - return 1; - } - if (strlen(secret)) { - endPoint->SetGatekeeperPassword(pass); - } - if (gatekeeper_discover) { - /* discover the gk using multicast */ - if (endPoint->DiscoverGatekeeper(new MyH323TransportUDP(*endPoint))) { - cout << "== Using " << (endPoint->GetGatekeeper())->GetName() << " as our Gatekeeper." << endl; - } else { - cout << "Warning: Could not find a gatekeeper." << endl; - return 1; - } - } else { - rasChannel = new MyH323TransportUDP(*endPoint); - - if (!rasChannel) { - cout << "Error: No RAS Channel, this is bad" << endl; - return 1; - } - if (endPoint->SetGatekeeper(gkName, rasChannel)) { - cout << "== Using " << (endPoint->GetGatekeeper())->GetName() << " as our Gatekeeper." << endl; - } else { - cout << "Error registering with gatekeeper \"" << gkName << "\". " << endl; - /* XXX Maybe we should fire a new thread to attempt to re-register later and not kill asterisk here? */ - return 1; - } - } - return 0; -} - -/** Send a DTMF tone over the H323Connection with the - * specified token. - */ -void h323_send_tone(const char *call_token, char tone) -{ - if (!h323_end_point_exist()) { - cout << "ERROR: [h323_send_tone] No Endpoint, this is bad!" << endl; - return; - } - PString token = PString(call_token); - endPoint->SendUserTone(token, tone); -} - -/** Make a call to the remote endpoint. - */ -int h323_make_call(char *dest, call_details_t *cd, call_options_t *call_options) -{ - int res; - PString token; - PString host(dest); - - if (!h323_end_point_exist()) { - return 1; - } - - res = endPoint->MyMakeCall(host, token, &cd->call_reference, call_options); - memcpy((char *)(cd->call_token), (const unsigned char *)token, token.GetLength()); - return res; -}; - -int h323_clear_call(const char *call_token, int cause) -{ - H225_ReleaseCompleteReason dummy; - H323Connection::CallEndReason r = H323Connection::EndedByLocalUser; - MyH323Connection *connection; - const PString currentToken(call_token); - - if (!h323_end_point_exist()) { - return 1; - } - - if (cause) { - r = H323TranslateToCallEndReason((Q931::CauseValues)(cause), dummy); - } - - connection = (MyH323Connection *)endPoint->FindConnectionWithLock(currentToken); - if (connection) { - connection->SetCause(cause); - connection->SetCallEndReason(r); - connection->Unlock(); - } - endPoint->ClearCall(currentToken, r); - return 0; -}; - -/* Send Alerting PDU to H.323 caller */ -int h323_send_alerting(const char *token) -{ - const PString currentToken(token); - H323Connection * connection; - - if (h323debug) { - cout << "\tSending alerting" << endl; - } - connection = endPoint->FindConnectionWithLock(currentToken); - if (!connection) { - cout << "No connection found for " << token << endl; - return -1; - } - connection->AnsweringCall(H323Connection::AnswerCallPending); - connection->Unlock(); - return 0; -} - -/* Send Progress PDU to H.323 caller */ -int h323_send_progress(const char *token) -{ - const PString currentToken(token); - H323Connection * connection; - - connection = endPoint->FindConnectionWithLock(currentToken); - if (!connection) { - cout << "No connection found for " << token << endl; - return -1; - } -#if 1 - ((MyH323Connection *)connection)->MySendProgress(); -#else - connection->AnsweringCall(H323Connection::AnswerCallDeferredWithMedia); -#endif - connection->Unlock(); - return 0; -} - -/** This function tells the h.323 stack to either - answer or deny an incoming call */ -int h323_answering_call(const char *token, int busy) -{ - const PString currentToken(token); - H323Connection * connection; - - connection = endPoint->FindConnectionWithLock(currentToken); - - if (!connection) { - cout << "No connection found for " << token << endl; - return -1; - } - if (!busy) { - if (h323debug) { - cout << "\tAnswering call " << token << endl; - } - connection->AnsweringCall(H323Connection::AnswerCallNow); - } else { - if (h323debug) { - cout << "\tdenying call " << token << endl; - } - connection->AnsweringCall(H323Connection::AnswerCallDenied); - } - connection->Unlock(); - return 0; -} - -int h323_soft_hangup(const char *data) -{ - PString token(data); - PBoolean result; - cout << "Soft hangup" << endl; - result = endPoint->ClearCall(token); - return result; -} - -/* alas, this doesn't work :( */ -void h323_native_bridge(const char *token, const char *them, char *capability) -{ - H323Channel *channel; - MyH323Connection *connection = (MyH323Connection *)endPoint->FindConnectionWithLock(token); - - if (!connection) { - cout << "ERROR: No connection found, this is bad" << endl; - return; - } - - cout << "Native Bridge: them [" << them << "]" << endl; - - channel = connection->FindChannel(connection->sessionId, TRUE); - connection->bridging = TRUE; - connection->CloseLogicalChannelNumber(channel->GetNumber()); - - connection->Unlock(); - return; - -} - -int h323_hold_call(const char *token, int is_hold) -{ - MyH323Connection *conn = (MyH323Connection *)endPoint->FindConnectionWithLock(token); - if (!conn) { - cout << "ERROR: No connection found, this is bad" << endl; - return -1; - } - conn->MyHoldCall((PBoolean)is_hold); - conn->Unlock(); - return 0; -} - -#undef cout -#undef endl -void h323_end_process(void) -{ - if (endPoint) { - delete endPoint; - endPoint = NULL; - } -#ifndef SKIP_PWLIB_PIPE_BUG_WORKAROUND - close(_timerChangePipe[0]); - close(_timerChangePipe[1]); -#endif - if (logstream) { - PTrace::SetStream(NULL); - delete logstream; - logstream = NULL; - } -} - -} /* extern "C" */ - diff --git a/channels/h323/ast_h323.h b/channels/h323/ast_h323.h deleted file mode 100644 index b9e793c0f51..00000000000 --- a/channels/h323/ast_h323.h +++ /dev/null @@ -1,187 +0,0 @@ -/* - * ast_h323.h - * - * OpenH323 Channel Driver for ASTERISK PBX. - * By Jeremy McNamara - * For The NuFone Network - * - * This code has been derived from code created by - * Michael Manousos and Mark Spencer - * - * This file is part of the chan_h323 driver for Asterisk - * - * chan_h323 is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * chan_h323 is distributed WITHOUT ANY WARRANTY; without even - * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Version Info: $Id$ - */ - -#ifndef AST_H323_H -#define AST_H323_H - -#include "ast_ptlib.h" - -#define VERSION(a,b,c) ((a)*10000+(b)*100+(c)) - -class MyH323EndPoint : public H323EndPoint -{ - PCLASSINFO(MyH323EndPoint, H323EndPoint); - -public: - MyH323EndPoint(); - int MyMakeCall(const PString &, PString &, void *_callReference, void *_opts); - PBoolean ClearCall(const PString &, H323Connection::CallEndReason reason); - PBoolean ClearCall(const PString &); - - void OnClosedLogicalChannel(H323Connection &, const H323Channel &); - void OnConnectionEstablished(H323Connection &, const PString &); - void OnConnectionCleared(H323Connection &, const PString &); - virtual H323Connection * CreateConnection(unsigned, void *, H323Transport *, H323SignalPDU *); - void SendUserTone(const PString &, char); - PBoolean OnConnectionForwarded(H323Connection &, const PString &, const H323SignalPDU &); - PBoolean ForwardConnection(H323Connection &, const PString &, const H323SignalPDU &); - void SetEndpointTypeInfo( H225_EndpointType & info ) const; - void SetGateway(void); - PStringArray SupportedPrefixes; -}; - -class MyH323Connection : public H323Connection -{ - PCLASSINFO(MyH323Connection, H323Connection); - -public: - MyH323Connection(MyH323EndPoint &, unsigned, unsigned); - ~MyH323Connection(); - H323Channel * CreateRealTimeLogicalChannel(const H323Capability &, - H323Channel::Directions, - unsigned, - const H245_H2250LogicalChannelParameters *, - RTP_QOS *); - H323Connection::AnswerCallResponse OnAnswerCall(const PString &, - const H323SignalPDU &, - H323SignalPDU &); - void OnReceivedReleaseComplete(const H323SignalPDU &); - PBoolean OnAlerting(const H323SignalPDU &, const PString &); - PBoolean OnSendReleaseComplete(H323SignalPDU &); - PBoolean OnReceivedSignalSetup(const H323SignalPDU &); - PBoolean OnReceivedFacility(const H323SignalPDU &); - PBoolean OnSendSignalSetup(H323SignalPDU &); - PBoolean OnStartLogicalChannel(H323Channel &); - PBoolean OnClosingLogicalChannel(H323Channel &); - virtual void SendUserInputTone(char tone, unsigned duration = 0, unsigned logicalChannel = 0, unsigned rtpTimestamp = 0); - virtual void OnUserInputTone(char, unsigned, unsigned, unsigned); - virtual void OnUserInputString(const PString &value); - PBoolean OnReceivedProgress(const H323SignalPDU &); - PBoolean MySendProgress(); - void OnSendCapabilitySet(H245_TerminalCapabilitySet &); - void OnSetLocalCapabilities(); - void SetCapabilities(int, int, void *, int); - PBoolean OnReceivedCapabilitySet(const H323Capabilities &, const H245_MultiplexCapability *, - H245_TerminalCapabilitySetReject &); - void SetCause(int _cause) { cause = _cause; }; - virtual PBoolean StartControlChannel(const H225_TransportAddress & h245Address); - void SetCallOptions(void *opts, PBoolean isIncoming); - void SetCallDetails(void *callDetails, const H323SignalPDU &setupPDU, PBoolean isIncoming); - virtual H323Connection::CallEndReason SendSignalSetup(const PString&, const H323TransportAddress&); -#ifdef TUNNELLING - virtual PBoolean HandleSignalPDU(H323SignalPDU &pdu); - PBoolean EmbedTunneledInfo(H323SignalPDU &pdu); -#endif -#ifdef H323_H450 - virtual void OnReceivedLocalCallHold(int linkedId); - virtual void OnReceivedLocalCallRetrieve(int linkedId); -#endif - void MyHoldCall(BOOL localHold); - - PString sourceAliases; - PString destAliases; - PString sourceE164; - PString destE164; - int cid_presentation; - int cid_ton; - PString rdnis; - int redirect_reason; - int transfer_capability; - - WORD sessionId; - PBoolean bridging; -#ifdef TUNNELLING - int remoteTunnelOptions; - int tunnelOptions; -#endif - - unsigned holdHandling; - unsigned progressSetup; - unsigned progressAlert; - int cause; - - RTP_DataFrame::PayloadTypes dtmfCodec[2]; - int dtmfMode; -}; - -class MyH323_ExternalRTPChannel : public H323_ExternalRTPChannel -{ - PCLASSINFO(MyH323_ExternalRTPChannel, H323_ExternalRTPChannel); - -public: - MyH323_ExternalRTPChannel( - MyH323Connection & connection, - const H323Capability & capability, - Directions direction, - unsigned sessionID); - - ~MyH323_ExternalRTPChannel(); - - /* Overrides */ - PBoolean Start(void); - PBoolean OnReceivedAckPDU(const H245_H2250LogicalChannelAckParameters & param); - -protected: - BYTE payloadCode; - - PIPSocket::Address localIpAddr; - PIPSocket::Address remoteIpAddr; - /* Additional functions in order to have chan_h323 compile with H323Plus */ -#if VERSION(OPENH323_MAJOR, OPENH323_MINOR, OPENH323_BUILD) > VERSION(1,19,4) - BOOL OnReceivedAltPDU(const H245_ArrayOf_GenericInformation & alternate ); - BOOL OnSendingAltPDU(H245_ArrayOf_GenericInformation & alternate) const; - void OnSendOpenAckAlt(H245_ArrayOf_GenericInformation & alternate) const; - BOOL OnReceivedAckAltPDU(const H245_ArrayOf_GenericInformation & alternate); -#endif - WORD localPort; - WORD remotePort; -}; - -#ifdef H323_H450 - -#if VERSION(OPENH323_MAJOR, OPENH323_MINOR, OPENH323_BUILD) > VERSION(1,19,4) -#include -#else -#include -#endif - -class MyH4504Handler : public H4504Handler -{ - PCLASSINFO(MyH4504Handler, H4504Handler); - -public: - MyH4504Handler(MyH323Connection &_conn, H450xDispatcher &_disp); - virtual void OnReceivedLocalCallHold(int linkedId); - virtual void OnReceivedLocalCallRetrieve(int linkedId); - -private: - MyH323Connection *conn; -}; -#endif - -#endif /* !defined AST_H323_H */ diff --git a/channels/h323/ast_ptlib.h b/channels/h323/ast_ptlib.h deleted file mode 100644 index 4b8ebf3d9d5..00000000000 --- a/channels/h323/ast_ptlib.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 2009, Digium, Inc. - * - * 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. - */ - -/* PTLib is Copyright (c) 2003 Equivalence Pty. Ltd. */ - -/*! - * \file - * \brief PTLib compatibility with previous versions of OPAL/PTLib/PWLib - */ - -#ifndef AST_PTLIB_H -#define AST_PTLIB_H - -#include -#if !defined(P_USE_STANDARD_CXX_BOOL) && !defined(P_USE_INTEGER_BOOL) -typedef BOOL PBoolean; -#define PTrue TRUE -#define PFalse FALSE -#endif - -#endif /* !defined AST_PTLIB_H */ diff --git a/channels/h323/caps_h323.cxx b/channels/h323/caps_h323.cxx deleted file mode 100644 index 3f7230f65cc..00000000000 --- a/channels/h323/caps_h323.cxx +++ /dev/null @@ -1,383 +0,0 @@ -#include -#include -#include -#include "ast_h323.h" -#include "caps_h323.h" - -#define DEFINE_G711_CAPABILITY(cls, code, capName) \ -class cls : public AST_G711Capability { \ -public: \ - cls() : AST_G711Capability(240, code) { } \ -}; \ -H323_REGISTER_CAPABILITY(cls, capName) \ - -DEFINE_G711_CAPABILITY(AST_G711ALaw64Capability, H323_G711Capability::ALaw, OPAL_G711_ALAW_64K); -DEFINE_G711_CAPABILITY(AST_G711uLaw64Capability, H323_G711Capability::muLaw, OPAL_G711_ULAW_64K); -H323_REGISTER_CAPABILITY(AST_G7231Capability, OPAL_G7231); -H323_REGISTER_CAPABILITY(AST_G729Capability, OPAL_G729); -H323_REGISTER_CAPABILITY(AST_G729ACapability, OPAL_G729A); -H323_REGISTER_CAPABILITY(AST_GSM0610Capability, OPAL_GSM0610); -H323_REGISTER_CAPABILITY(AST_CiscoG726Capability, CISCO_G726r32); -H323_REGISTER_CAPABILITY(AST_CiscoDtmfCapability, CISCO_DTMF_RELAY); - -OPAL_MEDIA_FORMAT_DECLARE(OpalG711ALaw64kFormat, - OPAL_G711_ALAW_64K, - OpalMediaFormat::DefaultAudioSessionID, - RTP_DataFrame::PCMA, - TRUE, // Needs jitter - 64000, // bits/sec - 8, // bytes/frame - 8, // 1 millisecond/frame - OpalMediaFormat::AudioTimeUnits, - 0); -OPAL_MEDIA_FORMAT_DECLARE(OpalG711uLaw64kFormat, - OPAL_G711_ULAW_64K, - OpalMediaFormat::DefaultAudioSessionID, - RTP_DataFrame::PCMU, - TRUE, // Needs jitter - 64000, // bits/sec - 8, // bytes/frame - 8, // 1 millisecond/frame - OpalMediaFormat::AudioTimeUnits, - 0); -OPAL_MEDIA_FORMAT_DECLARE(OpalG729Format, - OPAL_G729, - OpalMediaFormat::DefaultAudioSessionID, - RTP_DataFrame::G729, - TRUE, // Needs jitter - 8000, // bits/sec - 10, // bytes - 80, // 10 milliseconds - OpalMediaFormat::AudioTimeUnits, - 0); -OPAL_MEDIA_FORMAT_DECLARE(OpalG729AFormat, - OPAL_G729 "A", - OpalMediaFormat::DefaultAudioSessionID, - RTP_DataFrame::G729, - TRUE, // Needs jitter - 8000, // bits/sec - 10, // bytes - 80, // 10 milliseconds - OpalMediaFormat::AudioTimeUnits, - 0); -OPAL_MEDIA_FORMAT_DECLARE(OpalG7231_6k3Format, - OPAL_G7231_6k3, - OpalMediaFormat::DefaultAudioSessionID, - RTP_DataFrame::G7231, - TRUE, // Needs jitter - 6400, // bits/sec - 24, // bytes - 240, // 30 milliseconds - OpalMediaFormat::AudioTimeUnits, - 0); -OPAL_MEDIA_FORMAT_DECLARE(OpalG7231A_6k3Format, - OPAL_G7231A_6k3, - OpalMediaFormat::DefaultAudioSessionID, - RTP_DataFrame::G7231, - TRUE, // Needs jitter - 6400, // bits/sec - 24, // bytes - 240, // 30 milliseconds - OpalMediaFormat::AudioTimeUnits, - 0); -OPAL_MEDIA_FORMAT_DECLARE(OpalGSM0610Format, - OPAL_GSM0610, - OpalMediaFormat::DefaultAudioSessionID, - RTP_DataFrame::GSM, - TRUE, // Needs jitter - 13200, // bits/sec - 33, // bytes - 160, // 20 milliseconds - OpalMediaFormat::AudioTimeUnits, - 0); -OPAL_MEDIA_FORMAT_DECLARE(OpalCiscoG726Format, - CISCO_G726r32, - OpalMediaFormat::DefaultAudioSessionID, - RTP_DataFrame::G726, - TRUE, // Needs jitter - 32000, // bits/sec - 4, // bytes - 8, // 1 millisecond - OpalMediaFormat::AudioTimeUnits, - 0); -#if 0 -OPAL_MEDIA_FORMAT_DECLARE(OpalCiscoDTMFRelayFormat, - CISCO_DTMF_RELAY, - OpalMediaFormat::DefaultAudioSessionID, - (RTP_DataFrame::PayloadTypes)121, // Choose this for Cisco IOS compatibility - TRUE, // Needs jitter - 100, // bits/sec - 4, // bytes/frame - 8*150, // 150 millisecond - OpalMediaFormat::AudioTimeUnits, - 0); -#endif - -/* - * Capability: G.711 - */ -AST_G711Capability::AST_G711Capability(int rx_frames, H323_G711Capability::Mode m, H323_G711Capability::Speed s) - : H323AudioCapability(rx_frames, 30) // 240ms max, 30ms desired -{ - mode = m; - speed = s; -} - - -PObject * AST_G711Capability::Clone() const -{ - return new AST_G711Capability(*this); -} - - -unsigned AST_G711Capability::GetSubType() const -{ - static const unsigned G711SubType[2][2] = { - { H245_AudioCapability::e_g711Alaw64k, H245_AudioCapability::e_g711Alaw56k }, - { H245_AudioCapability::e_g711Ulaw64k, H245_AudioCapability::e_g711Ulaw56k } - }; - return G711SubType[mode][speed]; -} - - -PString AST_G711Capability::GetFormatName() const -{ - static const char * const G711Name[2][2] = { - { OPAL_G711_ALAW_64K, OPAL_G711_ALAW_56K }, - { OPAL_G711_ULAW_64K, OPAL_G711_ULAW_56K }, - }; - return G711Name[mode][speed]; -} - - -H323Codec * AST_G711Capability::CreateCodec(H323Codec::Direction direction) const -{ - return NULL; -} - - -/* - * Capability: G.723.1 - */ -AST_G7231Capability::AST_G7231Capability(int rx_frames, PBoolean annexA_) - : H323AudioCapability(rx_frames, 4) -{ - annexA = annexA_; -} - -PObject::Comparison AST_G7231Capability::Compare(const PObject & obj) const -{ - Comparison result = H323AudioCapability::Compare(obj); - if (result != EqualTo) { - return result; - } - PINDEX otherAnnexA = ((const AST_G7231Capability &)obj).annexA; - if (annexA < otherAnnexA) { - return LessThan; - } - if (annexA > otherAnnexA) { - return GreaterThan; - } - return EqualTo; -} - -PObject * AST_G7231Capability::Clone() const -{ - return new AST_G7231Capability(*this); -} - -PString AST_G7231Capability::GetFormatName() const -{ - return (annexA ? OPAL_G7231 "A" : OPAL_G7231); -} - -unsigned AST_G7231Capability::GetSubType() const -{ - return H245_AudioCapability::e_g7231; -} - -PBoolean AST_G7231Capability::OnSendingPDU(H245_AudioCapability & cap, - unsigned packetSize) const -{ - cap.SetTag(H245_AudioCapability::e_g7231); - H245_AudioCapability_g7231 & g7231 = cap; - g7231.m_maxAl_sduAudioFrames = packetSize; - g7231.m_silenceSuppression = annexA; - return TRUE; -} - -PBoolean AST_G7231Capability::OnReceivedPDU(const H245_AudioCapability & cap, - unsigned & packetSize) -{ - if (cap.GetTag() != H245_AudioCapability::e_g7231) { - return FALSE; - } - const H245_AudioCapability_g7231 & g7231 = cap; - packetSize = g7231.m_maxAl_sduAudioFrames; - annexA = g7231.m_silenceSuppression; - return TRUE; -} - -H323Codec * AST_G7231Capability::CreateCodec(H323Codec::Direction direction) const -{ - return NULL; -} - -/* - * Capability: G.729 - */ -AST_G729Capability::AST_G729Capability(int rx_frames) - : H323AudioCapability(rx_frames, 2) -{ -} - -PObject * AST_G729Capability::Clone() const -{ - return new AST_G729Capability(*this); -} - -unsigned AST_G729Capability::GetSubType() const -{ - return H245_AudioCapability::e_g729; -} - -PString AST_G729Capability::GetFormatName() const -{ - return OPAL_G729; -} - -H323Codec * AST_G729Capability::CreateCodec(H323Codec::Direction direction) const -{ - return NULL; -} - -/* - * Capability: G.729A - */ -AST_G729ACapability::AST_G729ACapability(int rx_frames) - : H323AudioCapability(rx_frames, 6) -{ -} - -PObject * AST_G729ACapability::Clone() const -{ - return new AST_G729ACapability(*this); -} - -unsigned AST_G729ACapability::GetSubType() const -{ - return H245_AudioCapability::e_g729AnnexA; -} - -PString AST_G729ACapability::GetFormatName() const -{ - return OPAL_G729A; -} - -H323Codec * AST_G729ACapability::CreateCodec(H323Codec::Direction direction) const -{ - return NULL; -} - -/* - * Capability: GSM full rate - */ -AST_GSM0610Capability::AST_GSM0610Capability(int rx_frames, int comfortNoise_, int scrambled_) - : H323AudioCapability(rx_frames, 2) -{ - comfortNoise = comfortNoise_; - scrambled = scrambled_; -} - -PObject * AST_GSM0610Capability::Clone() const -{ - return new AST_GSM0610Capability(*this); -} - -unsigned AST_GSM0610Capability::GetSubType() const -{ - return H245_AudioCapability::e_gsmFullRate; -} - -PBoolean AST_GSM0610Capability::OnSendingPDU(H245_AudioCapability & cap, - unsigned packetSize) const -{ - cap.SetTag(H245_AudioCapability::e_gsmFullRate); - H245_GSMAudioCapability & gsm = cap; - gsm.m_audioUnitSize = packetSize * 33; - gsm.m_comfortNoise = comfortNoise; - gsm.m_scrambled = scrambled; - return TRUE; -} - -PBoolean AST_GSM0610Capability::OnReceivedPDU(const H245_AudioCapability & cap, - unsigned & packetSize) -{ - if (cap.GetTag() != H245_AudioCapability::e_gsmFullRate) - return FALSE; - const H245_GSMAudioCapability & gsm = cap; - packetSize = (gsm.m_audioUnitSize + 32) / 33; - comfortNoise = gsm.m_comfortNoise; - scrambled = gsm.m_scrambled; - - return TRUE; -} - -PString AST_GSM0610Capability::GetFormatName() const -{ - return OPAL_GSM0610; -} - -H323Codec * AST_GSM0610Capability::CreateCodec(H323Codec::Direction direction) const -{ - return NULL; -} - -/* - * Capability: G.726 32 Kbps - */ -AST_CiscoG726Capability::AST_CiscoG726Capability(int rx_frames) - : H323NonStandardAudioCapability(rx_frames, 240, - 181, 0, 18, - (const BYTE *)"G726r32", 0) -{ -} - -PObject *AST_CiscoG726Capability::Clone() const -{ - return new AST_CiscoG726Capability(*this); -} - -H323Codec *AST_CiscoG726Capability::CreateCodec(H323Codec::Direction direction) const -{ - return NULL; -} - -PString AST_CiscoG726Capability::GetFormatName() const -{ - return PString(CISCO_G726r32); -} - -/* - * Capability: Cisco RTP DTMF Relay - */ -AST_CiscoDtmfCapability::AST_CiscoDtmfCapability() - : H323NonStandardDataCapability(0, 181, 0, 18, (const BYTE *)"RtpDtmfRelay", 0) -{ - rtpPayloadType = (RTP_DataFrame::PayloadTypes)121; -} - -PObject *AST_CiscoDtmfCapability::Clone() const -{ - return new AST_CiscoDtmfCapability(*this); -} - -H323Codec *AST_CiscoDtmfCapability::CreateCodec(H323Codec::Direction direction) const -{ - return NULL; -} - -PString AST_CiscoDtmfCapability::GetFormatName() const -{ - return PString(CISCO_DTMF_RELAY); -} diff --git a/channels/h323/caps_h323.h b/channels/h323/caps_h323.h deleted file mode 100644 index 251c6e7279f..00000000000 --- a/channels/h323/caps_h323.h +++ /dev/null @@ -1,172 +0,0 @@ -#ifndef __AST_H323CAPS_H -#define __AST_H323CAPS_H - -/**This class describes the G.711 codec capability. - */ -class AST_G711Capability : public H323AudioCapability -{ - PCLASSINFO(AST_G711Capability, H323AudioCapability); - -public: - AST_G711Capability(int rx_frames = 125, H323_G711Capability::Mode _mode = H323_G711Capability::muLaw, H323_G711Capability::Speed _speed = H323_G711Capability::At64k); - virtual PObject *Clone() const; - virtual H323Codec * CreateCodec(H323Codec::Direction direction) const; - virtual unsigned GetSubType() const; - virtual PString GetFormatName() const; - -protected: - H323_G711Capability::Mode mode; - H323_G711Capability::Speed speed; -}; - -/**This class describes the G.723.1 codec capability. - */ -class AST_G7231Capability : public H323AudioCapability -{ - PCLASSINFO(AST_G7231Capability, H323AudioCapability); - -public: - AST_G7231Capability(int rx_frames = 7, PBoolean annexA = TRUE); - Comparison Compare(const PObject & obj) const; - virtual PObject * Clone() const; - virtual H323Codec * CreateCodec(H323Codec::Direction direction) const; - virtual unsigned GetSubType() const; - virtual PString GetFormatName() const; - virtual PBoolean OnSendingPDU(H245_AudioCapability & pdu, unsigned packetSize) const; - virtual PBoolean OnReceivedPDU(const H245_AudioCapability & pdu, unsigned & packetSize); - -protected: - PBoolean annexA; -}; - -/**This class describes the (fake) G729 codec capability. - */ -class AST_G729Capability : public H323AudioCapability -{ - PCLASSINFO(AST_G729Capability, H323AudioCapability); - -public: - AST_G729Capability(int rx_frames = 24); - /* Create a copy of the object. */ - virtual PObject * Clone() const; - - /* Create the codec instance, allocating resources as required. */ - virtual H323Codec * CreateCodec(H323Codec::Direction direction) const; - - /* Get the sub-type of the capability. This is a code dependent on the - main type of the capability. - - This returns one of the four possible combinations of mode and speed - using the enum values of the protocol ASN H245_AudioCapability class. */ - virtual unsigned GetSubType() const; - - /* Get the name of the media data format this class represents. */ - virtual PString GetFormatName() const; -}; - -/* This class describes the VoiceAge G729A codec capability. */ -class AST_G729ACapability : public H323AudioCapability -{ - PCLASSINFO(AST_G729ACapability, H323AudioCapability); - -public: - /* Create a new G.729A capability. */ - AST_G729ACapability(int rx_frames = 24); - - /* Create a copy of the object. */ - virtual PObject * Clone() const; - /* Create the codec instance, allocating resources as required. */ - virtual H323Codec * CreateCodec(H323Codec::Direction direction) const; - - /* Get the sub-type of the capability. This is a code dependent on the - main type of the capability. - - This returns one of the four possible combinations of mode and speed - using the enum values of the protocol ASN H245_AudioCapability class. */ - virtual unsigned GetSubType() const; - - /* Get the name of the media data format this class represents. */ - virtual PString GetFormatName() const; -}; - -/* This class describes the GSM-06.10 codec capability. */ -class AST_GSM0610Capability : public H323AudioCapability -{ - PCLASSINFO(AST_GSM0610Capability, H323AudioCapability); - -public: - /* Create a new GSM capability. */ - AST_GSM0610Capability(int rx_frames = 24, int comfortNoise = 0, int scrambled = 0); - - /* Create a copy of the object. */ - virtual PObject * Clone() const; - - /* Create the codec instance, allocating resources as required. */ - virtual H323Codec * CreateCodec(H323Codec::Direction direction) const; - - /* Get the sub-type of the capability. This is a code dependent on the - main type of the capability. - - This returns one of the four possible combinations of mode and speed - using the enum values of the protocol ASN H245_AudioCapability class. */ - virtual unsigned GetSubType() const; - - /* Get the name of the media data format this class represents. */ - virtual PString GetFormatName() const; - - PBoolean OnSendingPDU(H245_AudioCapability & pdu, unsigned packetSize) const; - PBoolean OnReceivedPDU(const H245_AudioCapability & pdu, unsigned & packetSize); - -protected: - int comfortNoise; - int scrambled; -}; - -#define CISCO_G726r32 "G726r32" - -class AST_CiscoG726Capability : public H323NonStandardAudioCapability { - PCLASSINFO(AST_CiscoG726Capability, H323NonStandardAudioCapability); - -public: - /* Create a new Cisco G.726 capability */ - AST_CiscoG726Capability(int rx_frames = 80); - - /* Create a copy of the object. */ - virtual PObject * Clone() const; - - /* Create the codec instance, allocating resources as required. */ - virtual H323Codec * CreateCodec(H323Codec::Direction direction) const; - - /* Get the name of the media data format this class represents. */ - virtual PString GetFormatName() const; -}; - -#define CISCO_DTMF_RELAY "UserInput/RtpDtmfRelay" - -class AST_CiscoDtmfCapability : public H323NonStandardDataCapability -{ - PCLASSINFO(AST_CiscoDtmfCapability, H323NonStandardDataCapability); - -public: - /* Create a new Cisco RTP DTMF Relay capability */ - AST_CiscoDtmfCapability(); - - /* Create a copy of the object. */ - virtual PObject *Clone() const; - - /* Create the codec instance, allocating resources as required. */ - virtual H323Codec * CreateCodec(H323Codec::Direction direction) const; - - /* Get the name of the media data format this class represents. */ - virtual PString GetFormatName() const; - - virtual H323Channel *CreateChannel(H323Connection &, - H323Channel::Directions, - unsigned, - const H245_H2250LogicalChannelParameters *) const - { - return NULL; - } -}; - -#endif /* __AST_H323CAPS_H */ diff --git a/channels/h323/chan_h323.h b/channels/h323/chan_h323.h deleted file mode 100644 index 3787ad60d53..00000000000 --- a/channels/h323/chan_h323.h +++ /dev/null @@ -1,276 +0,0 @@ -/* - * chan_h323.h - * - * OpenH323 Channel Driver for ASTERISK PBX. - * By Jeremy McNamara - * For The NuFone Network - * - * This code has been derived from code created by - * Michael Manousos and Mark Spencer - * - * This file is part of the chan_h323 driver for Asterisk - * - * chan_h323 is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * chan_h323 is distributed WITHOUT ANY WARRANTY; without even - * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Version Info: $Id$ - */ - -#ifndef CHAN_H323_H -#define CHAN_H323_H - -#include -#include "asterisk/format.h" -#include "asterisk/app.h" - -/* - * Enable support for sending/reception of tunnelled Q.SIG messages and - * some sort of IEs (especially RedirectingNumber) which Cisco CallManager - * isn't like to pass in standard Q.931 message. - * - */ -#define TUNNELLING - -#define H323_TUNNEL_CISCO (1 << 0) -#define H323_TUNNEL_QSIG (1 << 1) - -#define H323_HOLD_NOTIFY (1 << 0) -#define H323_HOLD_Q931ONLY (1 << 1) -#define H323_HOLD_H450 (1 << 2) - -typedef int64_t h323_format; - -/** call_option struct holds various bits - * of information for each call */ -typedef struct call_options { - char cid_num[80]; - char cid_name[80]; - char cid_rdnis[80]; - int redirect_reason; - int presentation; - int type_of_number; - int transfer_capability; - int fastStart; - int h245Tunneling; - int silenceSuppression; - int progress_setup; - int progress_alert; - int progress_audio; - int dtmfcodec[2]; - int dtmfmode; - h323_format capability; - int bridge; - int nat; - int tunnelOptions; - int holdHandling; - int autoframing; /*!< turn on to override local settings with remote framing length */ - struct ast_codec_pref prefs; -} call_options_t; - -/* structure to hold the valid asterisk users */ -struct oh323_user { - ASTOBJ_COMPONENTS(struct oh323_user); -// char name[80]; - char context[80]; - char secret[80]; - char accountcode[AST_MAX_ACCOUNT_CODE]; - int amaflags; - int host; - struct sockaddr_in addr; - struct ast_ha *ha; - call_options_t options; -}; - -/* structure to hold the valid asterisk peers - All peers are registered to a GK if there is one */ -struct oh323_peer { - ASTOBJ_COMPONENTS(struct oh323_peer); - char mailbox[AST_MAX_MAILBOX_UNIQUEID]; - int delme; - struct sockaddr_in addr; - struct ast_ha *ha; - call_options_t options; -}; - -/* structure to hold the H.323 aliases which get registered to - the H.323 endpoint and gatekeeper */ -struct oh323_alias { - ASTOBJ_COMPONENTS(struct oh323_alias); - char e164[20]; /* tells a GK to route this E.164 to this alias */ - char prefix[500]; /* tells a GK this alias supports these prefixes */ - char secret[20]; /* the H.235 password to send to the GK for authentication */ - char context[80]; -}; - -/** call_details struct call detail records - to asterisk for processing and used for matching up - asterisk channels to acutal h.323 connections */ -typedef struct call_details { - unsigned int call_reference; - char *call_token; - char *call_source_aliases; - char *call_dest_alias; - char *call_source_name; - char *call_source_e164; - char *call_dest_e164; - char *redirect_number; - int redirect_reason; - int presentation; - int type_of_number; - int transfer_capability; - char *sourceIp; -} call_details_t; - -typedef struct rtp_info { - char addr[32]; - unsigned int port; -} rtp_info_t; - -/* This is a callback prototype function, called pass - DTMF down the RTP. */ -typedef int (*receive_digit_cb)(unsigned, char, const char *, int); -extern receive_digit_cb on_receive_digit; - -/* This is a callback prototype function, called to collect - the external RTP port from Asterisk. */ -typedef rtp_info_t *(*on_rtp_cb)(unsigned, const char *); -extern on_rtp_cb on_external_rtp_create; - -/* This is a callback prototype function, called to send - the remote IP and RTP port from H.323 to Asterisk */ -typedef void (*start_rtp_cb)(unsigned int, const char *, int, const char *, int); -extern start_rtp_cb on_start_rtp_channel; - -/* This is a callback that happens when call progress is - * made, and handles inband progress */ -typedef int (*progress_cb)(unsigned, const char *, int); -extern progress_cb on_progress; - -/* This is a callback prototype function, called upon - an incoming call happens. */ -typedef call_options_t *(*setup_incoming_cb)(call_details_t *); -extern setup_incoming_cb on_incoming_call; - -/* This is a callback prototype function, called upon - an outbound call. */ -typedef int (*setup_outbound_cb)(call_details_t *); -extern setup_outbound_cb on_outgoing_call; - -/* This is a callback prototype function, called when - OnAlerting is invoked */ -typedef void (*chan_ringing_cb)(unsigned, const char *); -extern chan_ringing_cb on_chan_ringing; - -/* This is a callback protoype function, called when - OnConnectionEstablished is inovked */ -typedef void (*con_established_cb)(unsigned, const char *); -extern con_established_cb on_connection_established; - -/* This is a callback prototype function, called when - OnConnectionCleared callback is invoked */ -typedef void (*clear_con_cb)(unsigned, const char *); -extern clear_con_cb on_connection_cleared; - -/* This is a callback prototype function, called when - an H.323 call is answered */ -typedef int (*answer_call_cb)(unsigned, const char *); -extern answer_call_cb on_answer_call; - -/* This is a callback prototype function, called when - we know which RTP payload type RFC2833 will be - transmitted */ -typedef void (*rfc2833_cb)(unsigned, const char *, int, int); -extern rfc2833_cb on_set_rfc2833_payload; - -typedef void (*hangup_cb)(unsigned, const char *, int); -extern hangup_cb on_hangup; - -typedef void (*setcapabilities_cb)(unsigned, const char *); -extern setcapabilities_cb on_setcapabilities; - -typedef void (*setpeercapabilities_cb)(unsigned, const char *, int, struct ast_codec_pref *); -extern setpeercapabilities_cb on_setpeercapabilities; - -typedef void (*onhold_cb)(unsigned, const char *, int); -extern onhold_cb on_hold; - -/* debug flag */ -extern int h323debug; - -#define H323_DTMF_RFC2833 (1 << 0) -#define H323_DTMF_CISCO (1 << 1) -#define H323_DTMF_SIGNAL (1 << 2) -#define H323_DTMF_INBAND (1 << 3) - -#define H323_DTMF_RFC2833_PT 101 -#define H323_DTMF_CISCO_PT 121 - -#ifdef __cplusplus -extern "C" { -#endif - - void h323_gk_urq(void); - void h323_end_point_create(void); - void h323_end_process(void); - int h323_end_point_exist(void); - - void h323_debug(int, unsigned); - - /* callback function handler*/ - void h323_callback_register(setup_incoming_cb, - setup_outbound_cb, - on_rtp_cb, - start_rtp_cb, - clear_con_cb, - chan_ringing_cb, - con_established_cb, - receive_digit_cb, - answer_call_cb, - progress_cb, - rfc2833_cb, - hangup_cb, - setcapabilities_cb, - setpeercapabilities_cb, - onhold_cb); - int h323_set_capabilities(const char *, int, int, struct ast_codec_pref *, int); - int h323_set_alias(struct oh323_alias *); - int h323_set_gk(int, char *, char *); - void h323_set_id(char *); - void h323_show_tokens(void); - void h323_show_version(void); - - /* H323 listener related funcions */ - int h323_start_listener(int, struct sockaddr_in); - - void h323_native_bridge(const char *, const char *, char *); - - /* Send a DTMF tone to remote endpoint */ - void h323_send_tone(const char *call_token, char tone); - - /* H323 create and destroy sessions */ - int h323_make_call(char *dest, call_details_t *cd, call_options_t *); - int h323_clear_call(const char *, int cause); - - /* H.323 alerting and progress */ - int h323_send_alerting(const char *token); - int h323_send_progress(const char *token); - int h323_answering_call(const char *token, int); - int h323_soft_hangup(const char *data); - int h323_show_codec(int fd, int argc, char *argv[]); - int h323_hold_call(const char *token, int); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/channels/h323/cisco-h225.asn b/channels/h323/cisco-h225.asn deleted file mode 100644 index 1372e67d58a..00000000000 --- a/channels/h323/cisco-h225.asn +++ /dev/null @@ -1,74 +0,0 @@ -CISCO-H225-MESSAGES DEFINITIONS AUTOMATIC TAGS ::= -BEGIN - -H323_UU_NonStdInfo ::= SEQUENCE -{ - version INTEGER OPTIONAL, - protoParam ProtoParam OPTIONAL, - commonParam CommonParam OPTIONAL, - ..., - dummy1 OCTET STRING OPTIONAL, - progIndParam ProgIndParam OPTIONAL, - callMgrParam CallMgrParam OPTIONAL, - callSignallingParam CallSignallingParam OPTIONAL, - dummy2 OCTET STRING OPTIONAL, - callPreserveParam CallPreserveParam OPTIONAL -} - -CommonParam ::= SEQUENCE -{ - redirectIEinfo RedirectIEinfo, - ... -} - -RedirectIEinfo ::= SEQUENCE -{ - redirectIE OCTET STRING, - ... -} - -ProgIndParam ::= SEQUENCE -{ - progIndIEinfo ProgIndIEinfo, - ... -} - -ProgIndIEinfo ::= SEQUENCE -{ - progIndIE OCTET STRING, - ... -} - -ProtoParam ::= SEQUENCE -{ - qsigNonStdInfo QsigNonStdInfo, - ... -} - -QsigNonStdInfo ::= SEQUENCE -{ - iei INTEGER, - rawMesg OCTET STRING, - ... -} - -CallMgrParam ::= SEQUENCE -{ - interclusterVersion INTEGER, - enterpriseID OCTET STRING, - ... -} - -CallPreserveParam ::= SEQUENCE -{ - callPreserveIE BOOLEAN, - ... -} - -CallSignallingParam ::= SEQUENCE -{ - connectedNumber OCTET STRING (1..127) OPTIONAL, - ... -} - -END diff --git a/channels/h323/cisco-h225.cxx b/channels/h323/cisco-h225.cxx deleted file mode 100644 index dac96a4e860..00000000000 --- a/channels/h323/cisco-h225.cxx +++ /dev/null @@ -1,853 +0,0 @@ -// -// cisco-h225.cxx -// -// Code automatically generated by asnparse. -// - -#ifdef P_USE_PRAGMA -#pragma implementation "cisco-h225.h" -#endif - -#include -#include "cisco-h225.h" - -#define new PNEW - - -#if ! H323_DISABLE_CISCO_H225 - -// -// RedirectIEinfo -// - -CISCO_H225_RedirectIEinfo::CISCO_H225_RedirectIEinfo(unsigned tag, PASN_Object::TagClass tagClass) - : PASN_Sequence(tag, tagClass, 0, TRUE, 0) -{ -} - - -#ifndef PASN_NOPRINTON -void CISCO_H225_RedirectIEinfo::PrintOn(ostream & strm) const -{ - int indent = strm.precision() + 2; - strm << "{\n"; - strm << setw(indent+13) << "redirectIE = " << setprecision(indent) << m_redirectIE << '\n'; - strm << setw(indent-1) << setprecision(indent-2) << "}"; -} -#endif - - -PObject::Comparison CISCO_H225_RedirectIEinfo::Compare(const PObject & obj) const -{ -#ifndef PASN_LEANANDMEAN - PAssert(PIsDescendant(&obj, CISCO_H225_RedirectIEinfo), PInvalidCast); -#endif - const CISCO_H225_RedirectIEinfo & other = (const CISCO_H225_RedirectIEinfo &)obj; - - Comparison result; - - if ((result = m_redirectIE.Compare(other.m_redirectIE)) != EqualTo) - return result; - - return PASN_Sequence::Compare(other); -} - - -PINDEX CISCO_H225_RedirectIEinfo::GetDataLength() const -{ - PINDEX length = 0; - length += m_redirectIE.GetObjectLength(); - return length; -} - - -PBoolean CISCO_H225_RedirectIEinfo::Decode(PASN_Stream & strm) -{ - if (!PreambleDecode(strm)) - return FALSE; - - if (!m_redirectIE.Decode(strm)) - return FALSE; - - return UnknownExtensionsDecode(strm); -} - - -void CISCO_H225_RedirectIEinfo::Encode(PASN_Stream & strm) const -{ - PreambleEncode(strm); - - m_redirectIE.Encode(strm); - - UnknownExtensionsEncode(strm); -} - - -PObject * CISCO_H225_RedirectIEinfo::Clone() const -{ -#ifndef PASN_LEANANDMEAN - PAssert(IsClass(CISCO_H225_RedirectIEinfo::Class()), PInvalidCast); -#endif - return new CISCO_H225_RedirectIEinfo(*this); -} - - -// -// ProgIndIEinfo -// - -CISCO_H225_ProgIndIEinfo::CISCO_H225_ProgIndIEinfo(unsigned tag, PASN_Object::TagClass tagClass) - : PASN_Sequence(tag, tagClass, 0, TRUE, 0) -{ -} - - -#ifndef PASN_NOPRINTON -void CISCO_H225_ProgIndIEinfo::PrintOn(ostream & strm) const -{ - int indent = strm.precision() + 2; - strm << "{\n"; - strm << setw(indent+12) << "progIndIE = " << setprecision(indent) << m_progIndIE << '\n'; - strm << setw(indent-1) << setprecision(indent-2) << "}"; -} -#endif - - -PObject::Comparison CISCO_H225_ProgIndIEinfo::Compare(const PObject & obj) const -{ -#ifndef PASN_LEANANDMEAN - PAssert(PIsDescendant(&obj, CISCO_H225_ProgIndIEinfo), PInvalidCast); -#endif - const CISCO_H225_ProgIndIEinfo & other = (const CISCO_H225_ProgIndIEinfo &)obj; - - Comparison result; - - if ((result = m_progIndIE.Compare(other.m_progIndIE)) != EqualTo) - return result; - - return PASN_Sequence::Compare(other); -} - - -PINDEX CISCO_H225_ProgIndIEinfo::GetDataLength() const -{ - PINDEX length = 0; - length += m_progIndIE.GetObjectLength(); - return length; -} - - -PBoolean CISCO_H225_ProgIndIEinfo::Decode(PASN_Stream & strm) -{ - if (!PreambleDecode(strm)) - return FALSE; - - if (!m_progIndIE.Decode(strm)) - return FALSE; - - return UnknownExtensionsDecode(strm); -} - - -void CISCO_H225_ProgIndIEinfo::Encode(PASN_Stream & strm) const -{ - PreambleEncode(strm); - - m_progIndIE.Encode(strm); - - UnknownExtensionsEncode(strm); -} - - -PObject * CISCO_H225_ProgIndIEinfo::Clone() const -{ -#ifndef PASN_LEANANDMEAN - PAssert(IsClass(CISCO_H225_ProgIndIEinfo::Class()), PInvalidCast); -#endif - return new CISCO_H225_ProgIndIEinfo(*this); -} - - -// -// QsigNonStdInfo -// - -CISCO_H225_QsigNonStdInfo::CISCO_H225_QsigNonStdInfo(unsigned tag, PASN_Object::TagClass tagClass) - : PASN_Sequence(tag, tagClass, 0, TRUE, 0) -{ -} - - -#ifndef PASN_NOPRINTON -void CISCO_H225_QsigNonStdInfo::PrintOn(ostream & strm) const -{ - int indent = strm.precision() + 2; - strm << "{\n"; - strm << setw(indent+6) << "iei = " << setprecision(indent) << m_iei << '\n'; - strm << setw(indent+10) << "rawMesg = " << setprecision(indent) << m_rawMesg << '\n'; - strm << setw(indent-1) << setprecision(indent-2) << "}"; -} -#endif - - -PObject::Comparison CISCO_H225_QsigNonStdInfo::Compare(const PObject & obj) const -{ -#ifndef PASN_LEANANDMEAN - PAssert(PIsDescendant(&obj, CISCO_H225_QsigNonStdInfo), PInvalidCast); -#endif - const CISCO_H225_QsigNonStdInfo & other = (const CISCO_H225_QsigNonStdInfo &)obj; - - Comparison result; - - if ((result = m_iei.Compare(other.m_iei)) != EqualTo) - return result; - if ((result = m_rawMesg.Compare(other.m_rawMesg)) != EqualTo) - return result; - - return PASN_Sequence::Compare(other); -} - - -PINDEX CISCO_H225_QsigNonStdInfo::GetDataLength() const -{ - PINDEX length = 0; - length += m_iei.GetObjectLength(); - length += m_rawMesg.GetObjectLength(); - return length; -} - - -PBoolean CISCO_H225_QsigNonStdInfo::Decode(PASN_Stream & strm) -{ - if (!PreambleDecode(strm)) - return FALSE; - - if (!m_iei.Decode(strm)) - return FALSE; - if (!m_rawMesg.Decode(strm)) - return FALSE; - - return UnknownExtensionsDecode(strm); -} - - -void CISCO_H225_QsigNonStdInfo::Encode(PASN_Stream & strm) const -{ - PreambleEncode(strm); - - m_iei.Encode(strm); - m_rawMesg.Encode(strm); - - UnknownExtensionsEncode(strm); -} - - -PObject * CISCO_H225_QsigNonStdInfo::Clone() const -{ -#ifndef PASN_LEANANDMEAN - PAssert(IsClass(CISCO_H225_QsigNonStdInfo::Class()), PInvalidCast); -#endif - return new CISCO_H225_QsigNonStdInfo(*this); -} - - -// -// CallMgrParam -// - -CISCO_H225_CallMgrParam::CISCO_H225_CallMgrParam(unsigned tag, PASN_Object::TagClass tagClass) - : PASN_Sequence(tag, tagClass, 0, TRUE, 0) -{ -} - - -#ifndef PASN_NOPRINTON -void CISCO_H225_CallMgrParam::PrintOn(ostream & strm) const -{ - int indent = strm.precision() + 2; - strm << "{\n"; - strm << setw(indent+22) << "interclusterVersion = " << setprecision(indent) << m_interclusterVersion << '\n'; - strm << setw(indent+15) << "enterpriseID = " << setprecision(indent) << m_enterpriseID << '\n'; - strm << setw(indent-1) << setprecision(indent-2) << "}"; -} -#endif - - -PObject::Comparison CISCO_H225_CallMgrParam::Compare(const PObject & obj) const -{ -#ifndef PASN_LEANANDMEAN - PAssert(PIsDescendant(&obj, CISCO_H225_CallMgrParam), PInvalidCast); -#endif - const CISCO_H225_CallMgrParam & other = (const CISCO_H225_CallMgrParam &)obj; - - Comparison result; - - if ((result = m_interclusterVersion.Compare(other.m_interclusterVersion)) != EqualTo) - return result; - if ((result = m_enterpriseID.Compare(other.m_enterpriseID)) != EqualTo) - return result; - - return PASN_Sequence::Compare(other); -} - - -PINDEX CISCO_H225_CallMgrParam::GetDataLength() const -{ - PINDEX length = 0; - length += m_interclusterVersion.GetObjectLength(); - length += m_enterpriseID.GetObjectLength(); - return length; -} - - -PBoolean CISCO_H225_CallMgrParam::Decode(PASN_Stream & strm) -{ - if (!PreambleDecode(strm)) - return FALSE; - - if (!m_interclusterVersion.Decode(strm)) - return FALSE; - if (!m_enterpriseID.Decode(strm)) - return FALSE; - - return UnknownExtensionsDecode(strm); -} - - -void CISCO_H225_CallMgrParam::Encode(PASN_Stream & strm) const -{ - PreambleEncode(strm); - - m_interclusterVersion.Encode(strm); - m_enterpriseID.Encode(strm); - - UnknownExtensionsEncode(strm); -} - - -PObject * CISCO_H225_CallMgrParam::Clone() const -{ -#ifndef PASN_LEANANDMEAN - PAssert(IsClass(CISCO_H225_CallMgrParam::Class()), PInvalidCast); -#endif - return new CISCO_H225_CallMgrParam(*this); -} - - -// -// CallPreserveParam -// - -CISCO_H225_CallPreserveParam::CISCO_H225_CallPreserveParam(unsigned tag, PASN_Object::TagClass tagClass) - : PASN_Sequence(tag, tagClass, 0, TRUE, 0) -{ -} - - -#ifndef PASN_NOPRINTON -void CISCO_H225_CallPreserveParam::PrintOn(ostream & strm) const -{ - int indent = strm.precision() + 2; - strm << "{\n"; - strm << setw(indent+17) << "callPreserveIE = " << setprecision(indent) << m_callPreserveIE << '\n'; - strm << setw(indent-1) << setprecision(indent-2) << "}"; -} -#endif - - -PObject::Comparison CISCO_H225_CallPreserveParam::Compare(const PObject & obj) const -{ -#ifndef PASN_LEANANDMEAN - PAssert(PIsDescendant(&obj, CISCO_H225_CallPreserveParam), PInvalidCast); -#endif - const CISCO_H225_CallPreserveParam & other = (const CISCO_H225_CallPreserveParam &)obj; - - Comparison result; - - if ((result = m_callPreserveIE.Compare(other.m_callPreserveIE)) != EqualTo) - return result; - - return PASN_Sequence::Compare(other); -} - - -PINDEX CISCO_H225_CallPreserveParam::GetDataLength() const -{ - PINDEX length = 0; - length += m_callPreserveIE.GetObjectLength(); - return length; -} - - -PBoolean CISCO_H225_CallPreserveParam::Decode(PASN_Stream & strm) -{ - if (!PreambleDecode(strm)) - return FALSE; - - if (!m_callPreserveIE.Decode(strm)) - return FALSE; - - return UnknownExtensionsDecode(strm); -} - - -void CISCO_H225_CallPreserveParam::Encode(PASN_Stream & strm) const -{ - PreambleEncode(strm); - - m_callPreserveIE.Encode(strm); - - UnknownExtensionsEncode(strm); -} - - -PObject * CISCO_H225_CallPreserveParam::Clone() const -{ -#ifndef PASN_LEANANDMEAN - PAssert(IsClass(CISCO_H225_CallPreserveParam::Class()), PInvalidCast); -#endif - return new CISCO_H225_CallPreserveParam(*this); -} - - -// -// CallSignallingParam -// - -CISCO_H225_CallSignallingParam::CISCO_H225_CallSignallingParam(unsigned tag, PASN_Object::TagClass tagClass) - : PASN_Sequence(tag, tagClass, 1, TRUE, 0) -{ - m_connectedNumber.SetConstraints(PASN_Object::FixedConstraint, 1, 127); -} - - -#ifndef PASN_NOPRINTON -void CISCO_H225_CallSignallingParam::PrintOn(ostream & strm) const -{ - int indent = strm.precision() + 2; - strm << "{\n"; - if (HasOptionalField(e_connectedNumber)) - strm << setw(indent+18) << "connectedNumber = " << setprecision(indent) << m_connectedNumber << '\n'; - strm << setw(indent-1) << setprecision(indent-2) << "}"; -} -#endif - - -PObject::Comparison CISCO_H225_CallSignallingParam::Compare(const PObject & obj) const -{ -#ifndef PASN_LEANANDMEAN - PAssert(PIsDescendant(&obj, CISCO_H225_CallSignallingParam), PInvalidCast); -#endif - const CISCO_H225_CallSignallingParam & other = (const CISCO_H225_CallSignallingParam &)obj; - - Comparison result; - - if ((result = m_connectedNumber.Compare(other.m_connectedNumber)) != EqualTo) - return result; - - return PASN_Sequence::Compare(other); -} - - -PINDEX CISCO_H225_CallSignallingParam::GetDataLength() const -{ - PINDEX length = 0; - if (HasOptionalField(e_connectedNumber)) - length += m_connectedNumber.GetObjectLength(); - return length; -} - - -PBoolean CISCO_H225_CallSignallingParam::Decode(PASN_Stream & strm) -{ - if (!PreambleDecode(strm)) - return FALSE; - - if (HasOptionalField(e_connectedNumber) && !m_connectedNumber.Decode(strm)) - return FALSE; - - return UnknownExtensionsDecode(strm); -} - - -void CISCO_H225_CallSignallingParam::Encode(PASN_Stream & strm) const -{ - PreambleEncode(strm); - - if (HasOptionalField(e_connectedNumber)) - m_connectedNumber.Encode(strm); - - UnknownExtensionsEncode(strm); -} - - -PObject * CISCO_H225_CallSignallingParam::Clone() const -{ -#ifndef PASN_LEANANDMEAN - PAssert(IsClass(CISCO_H225_CallSignallingParam::Class()), PInvalidCast); -#endif - return new CISCO_H225_CallSignallingParam(*this); -} - - -// -// CommonParam -// - -CISCO_H225_CommonParam::CISCO_H225_CommonParam(unsigned tag, PASN_Object::TagClass tagClass) - : PASN_Sequence(tag, tagClass, 0, TRUE, 0) -{ -} - - -#ifndef PASN_NOPRINTON -void CISCO_H225_CommonParam::PrintOn(ostream & strm) const -{ - int indent = strm.precision() + 2; - strm << "{\n"; - strm << setw(indent+17) << "redirectIEinfo = " << setprecision(indent) << m_redirectIEinfo << '\n'; - strm << setw(indent-1) << setprecision(indent-2) << "}"; -} -#endif - - -PObject::Comparison CISCO_H225_CommonParam::Compare(const PObject & obj) const -{ -#ifndef PASN_LEANANDMEAN - PAssert(PIsDescendant(&obj, CISCO_H225_CommonParam), PInvalidCast); -#endif - const CISCO_H225_CommonParam & other = (const CISCO_H225_CommonParam &)obj; - - Comparison result; - - if ((result = m_redirectIEinfo.Compare(other.m_redirectIEinfo)) != EqualTo) - return result; - - return PASN_Sequence::Compare(other); -} - - -PINDEX CISCO_H225_CommonParam::GetDataLength() const -{ - PINDEX length = 0; - length += m_redirectIEinfo.GetObjectLength(); - return length; -} - - -PBoolean CISCO_H225_CommonParam::Decode(PASN_Stream & strm) -{ - if (!PreambleDecode(strm)) - return FALSE; - - if (!m_redirectIEinfo.Decode(strm)) - return FALSE; - - return UnknownExtensionsDecode(strm); -} - - -void CISCO_H225_CommonParam::Encode(PASN_Stream & strm) const -{ - PreambleEncode(strm); - - m_redirectIEinfo.Encode(strm); - - UnknownExtensionsEncode(strm); -} - - -PObject * CISCO_H225_CommonParam::Clone() const -{ -#ifndef PASN_LEANANDMEAN - PAssert(IsClass(CISCO_H225_CommonParam::Class()), PInvalidCast); -#endif - return new CISCO_H225_CommonParam(*this); -} - - -// -// ProgIndParam -// - -CISCO_H225_ProgIndParam::CISCO_H225_ProgIndParam(unsigned tag, PASN_Object::TagClass tagClass) - : PASN_Sequence(tag, tagClass, 0, TRUE, 0) -{ -} - - -#ifndef PASN_NOPRINTON -void CISCO_H225_ProgIndParam::PrintOn(ostream & strm) const -{ - int indent = strm.precision() + 2; - strm << "{\n"; - strm << setw(indent+16) << "progIndIEinfo = " << setprecision(indent) << m_progIndIEinfo << '\n'; - strm << setw(indent-1) << setprecision(indent-2) << "}"; -} -#endif - - -PObject::Comparison CISCO_H225_ProgIndParam::Compare(const PObject & obj) const -{ -#ifndef PASN_LEANANDMEAN - PAssert(PIsDescendant(&obj, CISCO_H225_ProgIndParam), PInvalidCast); -#endif - const CISCO_H225_ProgIndParam & other = (const CISCO_H225_ProgIndParam &)obj; - - Comparison result; - - if ((result = m_progIndIEinfo.Compare(other.m_progIndIEinfo)) != EqualTo) - return result; - - return PASN_Sequence::Compare(other); -} - - -PINDEX CISCO_H225_ProgIndParam::GetDataLength() const -{ - PINDEX length = 0; - length += m_progIndIEinfo.GetObjectLength(); - return length; -} - - -PBoolean CISCO_H225_ProgIndParam::Decode(PASN_Stream & strm) -{ - if (!PreambleDecode(strm)) - return FALSE; - - if (!m_progIndIEinfo.Decode(strm)) - return FALSE; - - return UnknownExtensionsDecode(strm); -} - - -void CISCO_H225_ProgIndParam::Encode(PASN_Stream & strm) const -{ - PreambleEncode(strm); - - m_progIndIEinfo.Encode(strm); - - UnknownExtensionsEncode(strm); -} - - -PObject * CISCO_H225_ProgIndParam::Clone() const -{ -#ifndef PASN_LEANANDMEAN - PAssert(IsClass(CISCO_H225_ProgIndParam::Class()), PInvalidCast); -#endif - return new CISCO_H225_ProgIndParam(*this); -} - - -// -// ProtoParam -// - -CISCO_H225_ProtoParam::CISCO_H225_ProtoParam(unsigned tag, PASN_Object::TagClass tagClass) - : PASN_Sequence(tag, tagClass, 0, TRUE, 0) -{ -} - - -#ifndef PASN_NOPRINTON -void CISCO_H225_ProtoParam::PrintOn(ostream & strm) const -{ - int indent = strm.precision() + 2; - strm << "{\n"; - strm << setw(indent+17) << "qsigNonStdInfo = " << setprecision(indent) << m_qsigNonStdInfo << '\n'; - strm << setw(indent-1) << setprecision(indent-2) << "}"; -} -#endif - - -PObject::Comparison CISCO_H225_ProtoParam::Compare(const PObject & obj) const -{ -#ifndef PASN_LEANANDMEAN - PAssert(PIsDescendant(&obj, CISCO_H225_ProtoParam), PInvalidCast); -#endif - const CISCO_H225_ProtoParam & other = (const CISCO_H225_ProtoParam &)obj; - - Comparison result; - - if ((result = m_qsigNonStdInfo.Compare(other.m_qsigNonStdInfo)) != EqualTo) - return result; - - return PASN_Sequence::Compare(other); -} - - -PINDEX CISCO_H225_ProtoParam::GetDataLength() const -{ - PINDEX length = 0; - length += m_qsigNonStdInfo.GetObjectLength(); - return length; -} - - -PBoolean CISCO_H225_ProtoParam::Decode(PASN_Stream & strm) -{ - if (!PreambleDecode(strm)) - return FALSE; - - if (!m_qsigNonStdInfo.Decode(strm)) - return FALSE; - - return UnknownExtensionsDecode(strm); -} - - -void CISCO_H225_ProtoParam::Encode(PASN_Stream & strm) const -{ - PreambleEncode(strm); - - m_qsigNonStdInfo.Encode(strm); - - UnknownExtensionsEncode(strm); -} - - -PObject * CISCO_H225_ProtoParam::Clone() const -{ -#ifndef PASN_LEANANDMEAN - PAssert(IsClass(CISCO_H225_ProtoParam::Class()), PInvalidCast); -#endif - return new CISCO_H225_ProtoParam(*this); -} - - -// -// H323_UU_NonStdInfo -// - -CISCO_H225_H323_UU_NonStdInfo::CISCO_H225_H323_UU_NonStdInfo(unsigned tag, PASN_Object::TagClass tagClass) - : PASN_Sequence(tag, tagClass, 3, TRUE, 6) -{ -} - - -#ifndef PASN_NOPRINTON -void CISCO_H225_H323_UU_NonStdInfo::PrintOn(ostream & strm) const -{ - int indent = strm.precision() + 2; - strm << "{\n"; - if (HasOptionalField(e_version)) - strm << setw(indent+10) << "version = " << setprecision(indent) << m_version << '\n'; - if (HasOptionalField(e_protoParam)) - strm << setw(indent+13) << "protoParam = " << setprecision(indent) << m_protoParam << '\n'; - if (HasOptionalField(e_commonParam)) - strm << setw(indent+14) << "commonParam = " << setprecision(indent) << m_commonParam << '\n'; - if (HasOptionalField(e_dummy1)) - strm << setw(indent+9) << "dummy1 = " << setprecision(indent) << m_dummy1 << '\n'; - if (HasOptionalField(e_progIndParam)) - strm << setw(indent+15) << "progIndParam = " << setprecision(indent) << m_progIndParam << '\n'; - if (HasOptionalField(e_callMgrParam)) - strm << setw(indent+15) << "callMgrParam = " << setprecision(indent) << m_callMgrParam << '\n'; - if (HasOptionalField(e_callSignallingParam)) - strm << setw(indent+22) << "callSignallingParam = " << setprecision(indent) << m_callSignallingParam << '\n'; - if (HasOptionalField(e_dummy2)) - strm << setw(indent+9) << "dummy2 = " << setprecision(indent) << m_dummy2 << '\n'; - if (HasOptionalField(e_callPreserveParam)) - strm << setw(indent+20) << "callPreserveParam = " << setprecision(indent) << m_callPreserveParam << '\n'; - strm << setw(indent-1) << setprecision(indent-2) << "}"; -} -#endif - - -PObject::Comparison CISCO_H225_H323_UU_NonStdInfo::Compare(const PObject & obj) const -{ -#ifndef PASN_LEANANDMEAN - PAssert(PIsDescendant(&obj, CISCO_H225_H323_UU_NonStdInfo), PInvalidCast); -#endif - const CISCO_H225_H323_UU_NonStdInfo & other = (const CISCO_H225_H323_UU_NonStdInfo &)obj; - - Comparison result; - - if ((result = m_version.Compare(other.m_version)) != EqualTo) - return result; - if ((result = m_protoParam.Compare(other.m_protoParam)) != EqualTo) - return result; - if ((result = m_commonParam.Compare(other.m_commonParam)) != EqualTo) - return result; - - return PASN_Sequence::Compare(other); -} - - -PINDEX CISCO_H225_H323_UU_NonStdInfo::GetDataLength() const -{ - PINDEX length = 0; - if (HasOptionalField(e_version)) - length += m_version.GetObjectLength(); - if (HasOptionalField(e_protoParam)) - length += m_protoParam.GetObjectLength(); - if (HasOptionalField(e_commonParam)) - length += m_commonParam.GetObjectLength(); - return length; -} - - -PBoolean CISCO_H225_H323_UU_NonStdInfo::Decode(PASN_Stream & strm) -{ - if (!PreambleDecode(strm)) - return FALSE; - - if (HasOptionalField(e_version) && !m_version.Decode(strm)) - return FALSE; - if (HasOptionalField(e_protoParam) && !m_protoParam.Decode(strm)) - return FALSE; - if (HasOptionalField(e_commonParam) && !m_commonParam.Decode(strm)) - return FALSE; - if (!KnownExtensionDecode(strm, e_dummy1, m_dummy1)) - return FALSE; - if (!KnownExtensionDecode(strm, e_progIndParam, m_progIndParam)) - return FALSE; - if (!KnownExtensionDecode(strm, e_callMgrParam, m_callMgrParam)) - return FALSE; - if (!KnownExtensionDecode(strm, e_callSignallingParam, m_callSignallingParam)) - return FALSE; - if (!KnownExtensionDecode(strm, e_dummy2, m_dummy2)) - return FALSE; - if (!KnownExtensionDecode(strm, e_callPreserveParam, m_callPreserveParam)) - return FALSE; - - return UnknownExtensionsDecode(strm); -} - - -void CISCO_H225_H323_UU_NonStdInfo::Encode(PASN_Stream & strm) const -{ - PreambleEncode(strm); - - if (HasOptionalField(e_version)) - m_version.Encode(strm); - if (HasOptionalField(e_protoParam)) - m_protoParam.Encode(strm); - if (HasOptionalField(e_commonParam)) - m_commonParam.Encode(strm); - KnownExtensionEncode(strm, e_dummy1, m_dummy1); - KnownExtensionEncode(strm, e_progIndParam, m_progIndParam); - KnownExtensionEncode(strm, e_callMgrParam, m_callMgrParam); - KnownExtensionEncode(strm, e_callSignallingParam, m_callSignallingParam); - KnownExtensionEncode(strm, e_dummy2, m_dummy2); - KnownExtensionEncode(strm, e_callPreserveParam, m_callPreserveParam); - - UnknownExtensionsEncode(strm); -} - - -PObject * CISCO_H225_H323_UU_NonStdInfo::Clone() const -{ -#ifndef PASN_LEANANDMEAN - PAssert(IsClass(CISCO_H225_H323_UU_NonStdInfo::Class()), PInvalidCast); -#endif - return new CISCO_H225_H323_UU_NonStdInfo(*this); -} - - -#endif // if ! H323_DISABLE_CISCO_H225 - - -// End of cisco-h225.cxx diff --git a/channels/h323/cisco-h225.h b/channels/h323/cisco-h225.h deleted file mode 100644 index 55ed47e3e59..00000000000 --- a/channels/h323/cisco-h225.h +++ /dev/null @@ -1,300 +0,0 @@ -// -// cisco-h225.h -// -// Code automatically generated by asnparse. -// - -#if ! H323_DISABLE_CISCO_H225 - -#ifndef __CISCO_H225_H -#define __CISCO_H225_H - -#ifdef P_USE_PRAGMA -#pragma interface -#endif - -#include -#include "ast_ptlib.h" - -// -// RedirectIEinfo -// - -class CISCO_H225_RedirectIEinfo : public PASN_Sequence -{ -#ifndef PASN_LEANANDMEAN - PCLASSINFO(CISCO_H225_RedirectIEinfo, PASN_Sequence); -#endif - public: - CISCO_H225_RedirectIEinfo(unsigned tag = UniversalSequence, TagClass tagClass = UniversalTagClass); - - PASN_OctetString m_redirectIE; - - PINDEX GetDataLength() const; - PBoolean Decode(PASN_Stream & strm); - void Encode(PASN_Stream & strm) const; -#ifndef PASN_NOPRINTON - void PrintOn(ostream & strm) const; -#endif - Comparison Compare(const PObject & obj) const; - PObject * Clone() const; -}; - - -// -// ProgIndIEinfo -// - -class CISCO_H225_ProgIndIEinfo : public PASN_Sequence -{ -#ifndef PASN_LEANANDMEAN - PCLASSINFO(CISCO_H225_ProgIndIEinfo, PASN_Sequence); -#endif - public: - CISCO_H225_ProgIndIEinfo(unsigned tag = UniversalSequence, TagClass tagClass = UniversalTagClass); - - PASN_OctetString m_progIndIE; - - PINDEX GetDataLength() const; - PBoolean Decode(PASN_Stream & strm); - void Encode(PASN_Stream & strm) const; -#ifndef PASN_NOPRINTON - void PrintOn(ostream & strm) const; -#endif - Comparison Compare(const PObject & obj) const; - PObject * Clone() const; -}; - - -// -// QsigNonStdInfo -// - -class CISCO_H225_QsigNonStdInfo : public PASN_Sequence -{ -#ifndef PASN_LEANANDMEAN - PCLASSINFO(CISCO_H225_QsigNonStdInfo, PASN_Sequence); -#endif - public: - CISCO_H225_QsigNonStdInfo(unsigned tag = UniversalSequence, TagClass tagClass = UniversalTagClass); - - PASN_Integer m_iei; - PASN_OctetString m_rawMesg; - - PINDEX GetDataLength() const; - PBoolean Decode(PASN_Stream & strm); - void Encode(PASN_Stream & strm) const; -#ifndef PASN_NOPRINTON - void PrintOn(ostream & strm) const; -#endif - Comparison Compare(const PObject & obj) const; - PObject * Clone() const; -}; - - -// -// CallMgrParam -// - -class CISCO_H225_CallMgrParam : public PASN_Sequence -{ -#ifndef PASN_LEANANDMEAN - PCLASSINFO(CISCO_H225_CallMgrParam, PASN_Sequence); -#endif - public: - CISCO_H225_CallMgrParam(unsigned tag = UniversalSequence, TagClass tagClass = UniversalTagClass); - - PASN_Integer m_interclusterVersion; - PASN_OctetString m_enterpriseID; - - PINDEX GetDataLength() const; - PBoolean Decode(PASN_Stream & strm); - void Encode(PASN_Stream & strm) const; -#ifndef PASN_NOPRINTON - void PrintOn(ostream & strm) const; -#endif - Comparison Compare(const PObject & obj) const; - PObject * Clone() const; -}; - - -// -// CallPreserveParam -// - -class CISCO_H225_CallPreserveParam : public PASN_Sequence -{ -#ifndef PASN_LEANANDMEAN - PCLASSINFO(CISCO_H225_CallPreserveParam, PASN_Sequence); -#endif - public: - CISCO_H225_CallPreserveParam(unsigned tag = UniversalSequence, TagClass tagClass = UniversalTagClass); - - PASN_Boolean m_callPreserveIE; - - PINDEX GetDataLength() const; - PBoolean Decode(PASN_Stream & strm); - void Encode(PASN_Stream & strm) const; -#ifndef PASN_NOPRINTON - void PrintOn(ostream & strm) const; -#endif - Comparison Compare(const PObject & obj) const; - PObject * Clone() const; -}; - - -// -// CallSignallingParam -// - -class CISCO_H225_CallSignallingParam : public PASN_Sequence -{ -#ifndef PASN_LEANANDMEAN - PCLASSINFO(CISCO_H225_CallSignallingParam, PASN_Sequence); -#endif - public: - CISCO_H225_CallSignallingParam(unsigned tag = UniversalSequence, TagClass tagClass = UniversalTagClass); - - enum OptionalFields { - e_connectedNumber - }; - - PASN_OctetString m_connectedNumber; - - PINDEX GetDataLength() const; - PBoolean Decode(PASN_Stream & strm); - void Encode(PASN_Stream & strm) const; -#ifndef PASN_NOPRINTON - void PrintOn(ostream & strm) const; -#endif - Comparison Compare(const PObject & obj) const; - PObject * Clone() const; -}; - - -// -// CommonParam -// - -class CISCO_H225_CommonParam : public PASN_Sequence -{ -#ifndef PASN_LEANANDMEAN - PCLASSINFO(CISCO_H225_CommonParam, PASN_Sequence); -#endif - public: - CISCO_H225_CommonParam(unsigned tag = UniversalSequence, TagClass tagClass = UniversalTagClass); - - CISCO_H225_RedirectIEinfo m_redirectIEinfo; - - PINDEX GetDataLength() const; - PBoolean Decode(PASN_Stream & strm); - void Encode(PASN_Stream & strm) const; -#ifndef PASN_NOPRINTON - void PrintOn(ostream & strm) const; -#endif - Comparison Compare(const PObject & obj) const; - PObject * Clone() const; -}; - - -// -// ProgIndParam -// - -class CISCO_H225_ProgIndParam : public PASN_Sequence -{ -#ifndef PASN_LEANANDMEAN - PCLASSINFO(CISCO_H225_ProgIndParam, PASN_Sequence); -#endif - public: - CISCO_H225_ProgIndParam(unsigned tag = UniversalSequence, TagClass tagClass = UniversalTagClass); - - CISCO_H225_ProgIndIEinfo m_progIndIEinfo; - - PINDEX GetDataLength() const; - PBoolean Decode(PASN_Stream & strm); - void Encode(PASN_Stream & strm) const; -#ifndef PASN_NOPRINTON - void PrintOn(ostream & strm) const; -#endif - Comparison Compare(const PObject & obj) const; - PObject * Clone() const; -}; - - -// -// ProtoParam -// - -class CISCO_H225_ProtoParam : public PASN_Sequence -{ -#ifndef PASN_LEANANDMEAN - PCLASSINFO(CISCO_H225_ProtoParam, PASN_Sequence); -#endif - public: - CISCO_H225_ProtoParam(unsigned tag = UniversalSequence, TagClass tagClass = UniversalTagClass); - - CISCO_H225_QsigNonStdInfo m_qsigNonStdInfo; - - PINDEX GetDataLength() const; - PBoolean Decode(PASN_Stream & strm); - void Encode(PASN_Stream & strm) const; -#ifndef PASN_NOPRINTON - void PrintOn(ostream & strm) const; -#endif - Comparison Compare(const PObject & obj) const; - PObject * Clone() const; -}; - - -// -// H323_UU_NonStdInfo -// - -class CISCO_H225_H323_UU_NonStdInfo : public PASN_Sequence -{ -#ifndef PASN_LEANANDMEAN - PCLASSINFO(CISCO_H225_H323_UU_NonStdInfo, PASN_Sequence); -#endif - public: - CISCO_H225_H323_UU_NonStdInfo(unsigned tag = UniversalSequence, TagClass tagClass = UniversalTagClass); - - enum OptionalFields { - e_version, - e_protoParam, - e_commonParam, - e_dummy1, - e_progIndParam, - e_callMgrParam, - e_callSignallingParam, - e_dummy2, - e_callPreserveParam - }; - - PASN_Integer m_version; - CISCO_H225_ProtoParam m_protoParam; - CISCO_H225_CommonParam m_commonParam; - PASN_OctetString m_dummy1; - CISCO_H225_ProgIndParam m_progIndParam; - CISCO_H225_CallMgrParam m_callMgrParam; - CISCO_H225_CallSignallingParam m_callSignallingParam; - PASN_OctetString m_dummy2; - CISCO_H225_CallPreserveParam m_callPreserveParam; - - PINDEX GetDataLength() const; - PBoolean Decode(PASN_Stream & strm); - void Encode(PASN_Stream & strm) const; -#ifndef PASN_NOPRINTON - void PrintOn(ostream & strm) const; -#endif - Comparison Compare(const PObject & obj) const; - PObject * Clone() const; -}; - - -#endif // __CISCO_H225_H - -#endif // if ! H323_DISABLE_CISCO_H225 - - -// End of cisco-h225.h diff --git a/channels/h323/compat_h323.cxx b/channels/h323/compat_h323.cxx deleted file mode 100644 index 609d18e8a58..00000000000 --- a/channels/h323/compat_h323.cxx +++ /dev/null @@ -1,139 +0,0 @@ -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif -/* - * ast_h323.cpp - * - * OpenH323 Channel Driver for ASTERISK PBX. - * By Jeremy McNamara - * For The NuFone Network - * - * chan_h323 has been derived from code created by - * Michael Manousos and Mark Spencer - * - * This file is part of the chan_h323 driver for Asterisk - * - * chan_h323 is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * chan_h323 is distributed WITHOUT ANY WARRANTY; without even - * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Version Info: $Id$ - */ -#include -#include -#include - -#include "ast_h323.h" -#include "compat_h323.h" - -#if VERSION(OPENH323_MAJOR,OPENH323_MINOR,OPENH323_BUILD) < VERSION(1,17,3) -MyH323TransportTCP::MyH323TransportTCP( - H323EndPoint & endpoint, - PIPSocket::Address binding, - PBoolean listen) - : H323TransportTCP(endpoint, binding, listen) -{ -} - -PBoolean MyH323TransportTCP::Connect() -{ - if (IsListening()) - return TRUE; - - PTCPSocket * socket = new PTCPSocket(remotePort); - Open(socket); - - channelPointerMutex.StartRead(); - - socket->SetReadTimeout(10000/*endpoint.GetSignallingChannelConnectTimeout()*/); - - localPort = endpoint.GetNextTCPPort(); - WORD firstPort = localPort; - for (;;) { - PTRACE(4, "H323TCP\tConnecting to " - << remoteAddress << ':' << remotePort - << " (local port=" << localPort << ')'); - if (socket->Connect(localAddress, localPort, remoteAddress)) - break; - - int errnum = socket->GetErrorNumber(); - if (localPort == 0 || (errnum != EADDRINUSE && errnum != EADDRNOTAVAIL)) { - PTRACE(1, "H323TCP\tCould not connect to " - << remoteAddress << ':' << remotePort - << " (local port=" << localPort << ") - " - << socket->GetErrorText() << '(' << errnum << ')'); - channelPointerMutex.EndRead(); - return SetErrorValues(socket->GetErrorCode(), errnum); - } - - localPort = endpoint.GetNextTCPPort(); - if (localPort == firstPort) { - PTRACE(1, "H323TCP\tCould not bind to any port in range " << - endpoint.GetTCPPortBase() << " to " << endpoint.GetTCPPortMax()); - channelPointerMutex.EndRead(); - return SetErrorValues(socket->GetErrorCode(), errnum); - } - } - - socket->SetReadTimeout(PMaxTimeInterval); - - channelPointerMutex.EndRead(); - - return OnOpen(); -} -#endif - -PBoolean MyH323TransportUDP::DiscoverGatekeeper(H323Gatekeeper &gk, H323RasPDU &pdu, const H323TransportAddress &address) -{ - PThread *thd = PThread::Current(); - - /* If we run in OpenH323's thread use it instead of creating new one */ - if (thd) - return H323TransportUDP::DiscoverGatekeeper(gk, pdu, address); - - /* Make copy of arguments to pass them into thread */ - discoverGatekeeper = &gk; - discoverPDU = &pdu; - discoverAddress = &address; - - /* Assume discovery thread isn't finished */ - discoverReady = FALSE; - - /* Create discovery thread */ - thd = PThread::Create(PCREATE_NOTIFIER(DiscoverMain), 0, - PThread::NoAutoDeleteThread, - PThread::NormalPriority, - "GkDiscovery:%x"); - - /* Wait until discovery thread signal us its finished */ - for(;;) { - discoverMutex.Wait(); - if (discoverReady) /* Thread has been finished */ - break; - discoverMutex.Signal(); - } - discoverMutex.Signal(); - - /* Cleanup/delete thread */ - thd->WaitForTermination(); - delete thd; - - return discoverResult; -} - -void MyH323TransportUDP::DiscoverMain(PThread &thread, INT arg) -{ - PWaitAndSignal m(discoverMutex); - - discoverResult = H323TransportUDP::DiscoverGatekeeper(*discoverGatekeeper, *discoverPDU, *discoverAddress); - discoverReady = TRUE; -} diff --git a/channels/h323/compat_h323.h b/channels/h323/compat_h323.h deleted file mode 100644 index 61076f1be9e..00000000000 --- a/channels/h323/compat_h323.h +++ /dev/null @@ -1,96 +0,0 @@ -#ifndef COMPAT_H323_H -#define COMPAT_H323_H - -#include "ast_ptlib.h" - -#if VERSION(OPENH323_MAJOR,OPENH323_MINOR,OPENH323_BUILD) < VERSION(1,17,3) -/** - * Workaround for broken (less than 1.17.3) OpenH323 stack to be able to - * make TCP connections from specific address - */ -class MyH323TransportTCP : public H323TransportTCP -{ - PCLASSINFO(MyH323TransportTCP, H323TransportTCP); - -public: - MyH323TransportTCP( - H323EndPoint & endpoint, ///< H323 End Point object - PIPSocket::Address binding = PIPSocket::GetDefaultIpAny(), ///< Local interface to use - PBoolean listen = FALSE ///< Flag for need to wait for remote to connect - ); - /**Connect to the remote party. - */ - virtual PBoolean Connect(); -}; -#else -#define MyH323TransportTCP H323TransportTCP -#endif /* -class MyPFactory: public PFactory<_Abstract_T, _Key_T> -{ -public: - template class Worker: public PFactory<_Abstract_T, _Key_T>::WorkerBase - { - public: - Worker(const _Key_T &_key, bool singleton = false) - :PFactory<_Abstract_T, _Key_T>::WorkerBase(singleton), key(_key) - { - PFactory<_Abstract_T, _Key_T>::Register(key, this); - } - ~Worker() - { - PFactory<_Abstract_T, _Key_T>::Unregister(key); - } - protected: - virtual _Abstract_T *Create(const _Key_T &) const { return new _Concrete_T; } - - private: - PString key; - }; -}; - -#ifdef H323_REGISTER_CAPABILITY -#undef H323_REGISTER_CAPABILITY -#endif -#define H323_REGISTER_CAPABILITY(cls, capName) static MyPFactory::Worker cls##Factory(capName, true) - -#ifdef OPAL_MEDIA_FORMAT_DECLARE -#undef OPAL_MEDIA_FORMAT_DECLARE -#endif - -#define OPAL_MEDIA_FORMAT_DECLARE(classname, _fullName, _defaultSessionID, _rtpPayloadType, _needsJitter,_bandwidth, _frameSize, _frameTime, _timeUnits, _timeStamp) \ -class classname : public OpalMediaFormat \ -{ \ - public: \ - classname() \ - : OpalMediaFormat(_fullName, _defaultSessionID, _rtpPayloadType, _needsJitter, _bandwidth, \ - _frameSize, _frameTime, _timeUnits, _timeStamp){} \ -}; \ -static MyPFactory::Worker classname##Factory(_fullName, true) - -#endif /* !defined AST_H323_H */ diff --git a/channels/h323/noexport.map b/channels/h323/noexport.map deleted file mode 100644 index b51f8426370..00000000000 --- a/channels/h323/noexport.map +++ /dev/null @@ -1,5 +0,0 @@ -{ - global: - _Z11PAssertFuncPKc; - local: *; -}; \ No newline at end of file diff --git a/configs/asterisk.conf.sample b/configs/asterisk.conf.sample index e10385fbd62..e4883ec97a1 100644 --- a/configs/asterisk.conf.sample +++ b/configs/asterisk.conf.sample @@ -95,8 +95,3 @@ documentation_language = en_US ; Set the language you want documentation ;astctlowner = root ;astctlgroup = apache ;astctl = asterisk.ctl - -[compat] -pbx_realtime=1.6 -res_agi=1.6 -app_set=1.6 diff --git a/configs/gtalk.conf.sample b/configs/gtalk.conf.sample deleted file mode 100644 index d15a58d617e..00000000000 --- a/configs/gtalk.conf.sample +++ /dev/null @@ -1,27 +0,0 @@ -[general] -;context=default ; Context to dump call into -;bindaddr=0.0.0.0 ; Address to bind to -;externip=127.0.0.1 ; Set your external ip if you are behind a NAT. -;stunaddr=mystunserver.com ; Get your external ip from a STUN server. - ; Note, if the STUN query is successful, this will - ; replace any value placed in externip; -;allowguest=yes ; Allow calls from people not in list of peers -;disallow=all -;allow=gsm -;allow=ulaw -;parkinglot=soccer ; Sets the default parking lot for call parking - ; Parkinglots are configured in features.conf - -;[guest] ; special account for options on guest account -;disallow=all -;allow=ulaw -;context=guest - -;[ogorman] -;username=ogorman@gmail.com ; username of the peer your - ; calling or accepting calls from -;disallow=all -;allow=ulaw -;context=default -;connection=asterisk ; client or component in jabber.conf for the - ; call to leave on. diff --git a/configs/jabber.conf.sample b/configs/jabber.conf.sample deleted file mode 100644 index a8385686784..00000000000 --- a/configs/jabber.conf.sample +++ /dev/null @@ -1,39 +0,0 @@ -[general] -;debug=yes ; Enable debugging (disabled by default). -;autoprune=yes ; Auto remove users from buddy list. Depending on your - ; setup (ie, using your personal Gtalk account for a test) - ; you might lose your contacts list. Default is 'no'. -;autoregister=yes ; Auto register users from buddy list. -;collection_nodes=yes ; Enable support for XEP-0248 for use with - ; distributed device state. Default is 'no'. -;pubsub_autocreate=yes ; Whether or not the PubSub server supports/is using - ; auto-create for nodes. If it is, we have to - ; explicitly pre-create nodes before publishing them. - ; Default is 'no'. -;auth_policy=accept ; Auto accept users' subscription requests (default). - ; Set to deny for auto denial. -;[asterisk] -;type=client ; Client or Component connection -;serverhost=astjab.org ; Route to server for example, talk.google.com -;pubsub_node=pubsub.astjab.org ; Node to use for publishing events via PubSub -;username=asterisk@astjab.org/asterisk ; Username with optional resource. -;secret=blah ; Password -;priority=1 ; Resource priority -;port=5222 ; Port to use defaults to 5222 -;usetls=yes ; Use tls or not -;usesasl=yes ; Use sasl or not -;buddy=mogorman@astjab.org ; Manual addition of buddy to list. - ; For distributed events, these buddies are - ; automatically added in the whitelist as - ; 'owners' of the node(s). -;distribute_events=yes ; Whether or not to distribute events using - ; this connection. Default is 'no'. -;status=available ; One of: chat, available, away, xaway, or dnd -;statusmessage="I am available" ; Have custom status message for Asterisk -;timeout=5 ; Timeout (in seconds) on the message stack, defaults to 5. - ; Messages stored longer than this value will be deleted by Asterisk. - ; This option applies to incoming messages only, which are intended to - ; be processed by the JABBER_RECEIVE dialplan function. -;sendtodialplan=yes ; Send incoming messages into the dialplan. Off by default. -;context=messages ; Dialplan context to send incoming messages to. If not set, - ; "default" will be used. diff --git a/configs/jingle.conf.sample b/configs/jingle.conf.sample deleted file mode 100644 index 8873d0678f9..00000000000 --- a/configs/jingle.conf.sample +++ /dev/null @@ -1,20 +0,0 @@ -;[general] -;context=default ;;Context to dump call into -;bindaddr=0.0.0.0 ;;Address to bind to -;allowguest=yes ;;Allow calls from people not in - ;;list of peers -; -;[guest] ;;special account for options on guest account -;disallow=all -;allow=ulaw -;context=guest -; -;[ogorman] -;username=ogorman@gmail.com ;;username of the peer your - ;;calling or accepting calls from -;disallow=all -;allow=ulaw -;context=default -;connection=asterisk ;;client or component in jabber.conf - ;;for the call to leave on. -; diff --git a/include/asterisk/options.h b/include/asterisk/options.h index 1b35b3666d3..0da5799aee6 100644 --- a/include/asterisk/options.h +++ b/include/asterisk/options.h @@ -134,18 +134,6 @@ enum ast_option_flags { extern struct ast_flags ast_options; -enum ast_compat_flags { - AST_COMPAT_DELIM_PBX_REALTIME = (1 << 0), - AST_COMPAT_DELIM_RES_AGI = (1 << 1), - AST_COMPAT_APP_SET = (1 << 2), -}; - -#define ast_compat_pbx_realtime ast_test_flag(&ast_compat, AST_COMPAT_DELIM_PBX_REALTIME) -#define ast_compat_res_agi ast_test_flag(&ast_compat, AST_COMPAT_DELIM_RES_AGI) -#define ast_compat_app_set ast_test_flag(&ast_compat, AST_COMPAT_APP_SET) - -extern struct ast_flags ast_compat; - extern int option_verbose; extern int ast_option_maxfiles; /*!< Max number of open file handles (files, sockets) */ extern int option_debug; /*!< Debugging */ diff --git a/main/asterisk.c b/main/asterisk.c index 213828c0390..a8b687a485e 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -317,7 +317,6 @@ int daemon(int, int); /* defined in libresolv of all places */ /*! @{ */ struct ast_flags ast_options = { AST_DEFAULT_OPTIONS }; -struct ast_flags ast_compat = { 0 }; /*! Maximum active system verbosity level. */ int ast_verb_sys_level; @@ -3646,20 +3645,7 @@ static void ast_readconfig(void) if (!ast_opt_remote) { pbx_live_dangerously(live_dangerously); } - for (v = ast_variable_browse(cfg, "compat"); v; v = v->next) { - float version; - if (sscanf(v->value, "%30f", &version) != 1) { - fprintf(stderr, "Compatibility version for option '%s' is not a number: '%s'\n", v->name, v->value); - continue; - } - if (!strcasecmp(v->name, "app_set")) { - ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_APP_SET); - } else if (!strcasecmp(v->name, "res_agi")) { - ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_DELIM_RES_AGI); - } else if (!strcasecmp(v->name, "pbx_realtime")) { - ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_DELIM_PBX_REALTIME); - } - } + ast_config_destroy(cfg); } diff --git a/main/pbx.c b/main/pbx.c index 2f0c06405b1..389a4c0f50d 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -11465,10 +11465,6 @@ int pbx_builtin_setvar(struct ast_channel *chan, const char *data) { char *name, *value, *mydata; - if (ast_compat_app_set) { - return pbx_builtin_setvar_multiple(chan, data); - } - if (ast_strlen_zero(data)) { ast_log(LOG_WARNING, "Set requires one variable name/value pair.\n"); return 0; diff --git a/pbx/pbx_realtime.c b/pbx/pbx_realtime.c index 7624d597962..1143fb45a5e 100644 --- a/pbx/pbx_realtime.c +++ b/pbx/pbx_realtime.c @@ -303,7 +303,7 @@ static int realtime_exec(struct ast_channel *chan, const char *context, const ch struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_MATCH); if (var) { - char *tmp=""; + char *appdata_tmp = ""; char *app = NULL; struct ast_variable *v; @@ -311,31 +311,7 @@ static int realtime_exec(struct ast_channel *chan, const char *context, const ch if (!strcasecmp(v->name, "app")) app = ast_strdupa(v->value); else if (!strcasecmp(v->name, "appdata")) { - if (ast_compat_pbx_realtime) { - char *ptr; - int in = 0; - tmp = ast_alloca(strlen(v->value) * 2 + 1); - for (ptr = tmp; *v->value; v->value++) { - if (*v->value == ',') { - *ptr++ = '\\'; - *ptr++ = ','; - } else if (*v->value == '|' && !in) { - *ptr++ = ','; - } else { - *ptr++ = *v->value; - } - - /* Don't escape '|', meaning 'or', inside expressions ($[ ]) */ - if (v->value[0] == '[' && v->value[-1] == '$') { - in++; - } else if (v->value[0] == ']' && in) { - in--; - } - } - *ptr = '\0'; - } else { - tmp = ast_strdupa(v->value); - } + appdata_tmp = ast_strdupa(v->value); } } ast_variables_destroy(var); @@ -350,8 +326,8 @@ static int realtime_exec(struct ast_channel *chan, const char *context, const ch RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup); appdata[0] = 0; /* just in case the substitute var func isn't called */ - if(!ast_strlen_zero(tmp)) - pbx_substitute_variables_helper(chan, tmp, appdata, sizeof(appdata) - 1); + if(!ast_strlen_zero(appdata_tmp)) + pbx_substitute_variables_helper(chan, appdata_tmp, appdata, sizeof(appdata) - 1); ast_verb(3, "Executing [%s@%s:%d] %s(\"%s\", \"%s\")\n", ast_channel_exten(chan), ast_channel_context(chan), ast_channel_priority(chan), term_color(tmp1, app, COLOR_BRCYAN, 0, sizeof(tmp1)), diff --git a/res/ael/pval.c b/res/ael/pval.c index c0da0f03ff7..d72ef0d59ac 100644 --- a/res/ael/pval.c +++ b/res/ael/pval.c @@ -56,7 +56,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #endif #include "asterisk/utils.h" -extern struct ast_flags ast_compat; extern int localized_pbx_load_module(void); static char expr_output[2096]; @@ -3384,11 +3383,7 @@ static int gen_prios(struct ael_extension *exten, char *label, pval *statement, for (first = 1; first >= 0; first--) { switch_set = new_prio(); switch_set->type = AEL_APPCALL; - if (!ast_compat_app_set) { - switch_set->app = strdup("MSet"); - } else { - switch_set->app = strdup("Set"); - } + switch_set->app = strdup("MSet"); /* Are we likely inside a gosub subroutine? */ if (!strcmp(mother_exten->name, "~~s~~") && first) { /* If we're not actually within a gosub, this will fail, but the @@ -3413,11 +3408,7 @@ static int gen_prios(struct ael_extension *exten, char *label, pval *statement, for (first = 1; first >= 0; first--) { switch_set = new_prio(); switch_set->type = AEL_APPCALL; - if (!ast_compat_app_set) { - switch_set->app = strdup("MSet"); - } else { - switch_set->app = strdup("Set"); - } + switch_set->app = strdup("MSet"); /* Are we likely inside a gosub subroutine? */ if (!strcmp(exten->name, "~~s~~")) { /* If we're not actually within a gosub, this will fail, but the @@ -3453,11 +3444,7 @@ static int gen_prios(struct ael_extension *exten, char *label, pval *statement, pr = new_prio(); pr->type = AEL_APPCALL; snprintf(buf1, BUF_SIZE, "%s=$[%s]", p->u1.str, p->u2.val); - if (!ast_compat_app_set) { - pr->app = strdup("MSet"); - } else { - pr->app = strdup("Set"); - } + pr->app = strdup("MSet"); remove_spaces_before_equals(buf1); pr->appargs = strdup(buf1); pr->origin = p; @@ -3468,11 +3455,7 @@ static int gen_prios(struct ael_extension *exten, char *label, pval *statement, pr = new_prio(); pr->type = AEL_APPCALL; snprintf(buf1, BUF_SIZE, "LOCAL(%s)=$[%s]", p->u1.str, p->u2.val); - if (!ast_compat_app_set) { - pr->app = strdup("MSet"); - } else { - pr->app = strdup("Set"); - } + pr->app = strdup("MSet"); remove_spaces_before_equals(buf1); pr->appargs = strdup(buf1); pr->origin = p; @@ -3535,11 +3518,7 @@ static int gen_prios(struct ael_extension *exten, char *label, pval *statement, for_test->goto_false = for_end; for_loop->type = AEL_CONTROL1; /* simple goto */ for_end->type = AEL_APPCALL; - if (!ast_compat_app_set) { - for_init->app = strdup("MSet"); - } else { - for_init->app = strdup("Set"); - } + for_init->app = strdup("MSet"); strcpy(buf2,p->u1.for_init); remove_spaces_before_equals(buf2); @@ -3600,11 +3579,7 @@ static int gen_prios(struct ael_extension *exten, char *label, pval *statement, strncat(buf2,strp2+1, BUF_SIZE-strlen(strp2+1)-2); strcat(buf2,"]"); for_inc->appargs = strdup(buf2); - if (!ast_compat_app_set) { - for_inc->app = strdup("MSet"); - } else { - for_inc->app = strdup("Set"); - } + for_inc->app = strdup("MSet"); } else { strp2 = p->u3.for_inc; while (*strp2 && isspace(*strp2)) @@ -4489,11 +4464,7 @@ int ast_compile_ael2(struct ast_context **local_contexts, struct ast_hashtab *lo /* for each arg, set up a "Set" command */ struct ael_priority *np2 = new_prio(); np2->type = AEL_APPCALL; - if (!ast_compat_app_set) { - np2->app = strdup("MSet"); - } else { - np2->app = strdup("Set"); - } + np2->app = strdup("MSet"); snprintf(buf,sizeof(buf),"LOCAL(%s)=${ARG%d}", lp->u1.str, argc++); remove_spaces_before_equals(buf); np2->appargs = strdup(buf); diff --git a/res/res_agi.c b/res/res_agi.c index 3adf36bacc4..67a213f8da7 100644 --- a/res/res_agi.c +++ b/res/res_agi.c @@ -2767,24 +2767,7 @@ static int handle_exec(struct ast_channel *chan, AGI *agi, int argc, const char if (!(workaround = ast_test_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_WORKAROUNDS))) { ast_set_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_WORKAROUNDS); } - if (ast_compat_res_agi && argc >= 3 && !ast_strlen_zero(argv[2])) { - char *compat = ast_alloca(strlen(argv[2]) * 2 + 1), *cptr; - const char *vptr; - for (cptr = compat, vptr = argv[2]; *vptr; vptr++) { - if (*vptr == ',') { - *cptr++ = '\\'; - *cptr++ = ','; - } else if (*vptr == '|') { - *cptr++ = ','; - } else { - *cptr++ = *vptr; - } - } - *cptr = '\0'; - res = pbx_exec(chan, app_to_exec, compat); - } else { - res = pbx_exec(chan, app_to_exec, argc == 2 ? "" : argv[2]); - } + res = pbx_exec(chan, app_to_exec, argc == 2 ? "" : argv[2]); if (!workaround) { ast_clear_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_WORKAROUNDS); } diff --git a/res/res_jabber.c b/res/res_jabber.c deleted file mode 100644 index d5079a6b56d..00000000000 --- a/res/res_jabber.c +++ /dev/null @@ -1,4815 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 1999 - 2010, Digium, Inc. - * - * Matt O'Gorman - * - * 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 A resource for interfacing Asterisk directly as a client - * or a component to a XMPP/Jabber compliant server. - * - * References: - * - http://www.xmpp.org - The XMPP standards foundation - * - * Iksemel http://code.google.com/p/iksemel/ - * - * \todo If you unload this module, chan_gtalk/jingle will be dead. How do we handle that? - * \todo Dialplan applications need RETURN variable, like JABBERSENDSTATUS - * - */ - -/*! \li \ref res_jabber.c uses the configuration file \ref jabber.conf - * \addtogroup configuration_file Configuration Files - */ - -/*! - * \page jabber.conf jabber.conf - * \verbinclude jabber.conf.sample - */ - -/*** MODULEINFO - no - iksemel - openssl - deprecated - res_xmpp - ***/ - -#include "asterisk.h" - -ASTERISK_FILE_VERSION(__FILE__, "$Revision$") - -#include -#include - -#include "asterisk/channel.h" -#include "asterisk/jabber.h" -#include "asterisk/file.h" -#include "asterisk/config.h" -#include "asterisk/callerid.h" -#include "asterisk/lock.h" -#include "asterisk/cli.h" -#include "asterisk/app.h" -#include "asterisk/pbx.h" -#include "asterisk/md5.h" -#include "asterisk/acl.h" -#include "asterisk/utils.h" -#include "asterisk/module.h" -#include "asterisk/astobj.h" -#include "asterisk/astdb.h" -#include "asterisk/manager.h" -#include "asterisk/devicestate.h" -#include "asterisk/message.h" - -/*** DOCUMENTATION - - - Sends an XMPP message to a buddy. - - - - The local named account to listen on (specified in - jabber.conf) - - - Jabber ID of the buddy to send the message to. It can be a - bare JID (username@domain) or a full JID (username@domain/resource). - - - The message to send. - - - - Sends the content of message as text message - from the given account to the buddy identified by - jid - Example: JabberSend(asterisk,bob@domain.com,Hello world) sends "Hello world" - to bob@domain.com as an XMPP message from the account - asterisk, configured in jabber.conf. - - - JABBER_STATUS - JABBER_RECEIVE - - - - - Reads XMPP messages. - - - - The local named account to listen on (specified in - jabber.conf) - - - Jabber ID of the buddy to receive message from. It can be a - bare JID (username@domain) or a full JID (username@domain/resource). - - - In seconds, defaults to 20. - - - - Receives a text message on the given account - from the buddy identified by jid and returns the contents. - Example: ${JABBER_RECEIVE(asterisk,bob@domain.com)} returns an XMPP message - sent from bob@domain.com (or nothing in case of a time out), to - the asterisk XMPP account configured in jabber.conf. - - - JABBER_STATUS - JabberSend - - - - - Retrieves a buddy's status. - - - - The local named account to listen on (specified in - jabber.conf) - - - Jabber ID of the buddy to receive message from. It can be a - bare JID (username@domain) or a full JID (username@domain/resource). - - - - Retrieves the numeric status associated with the buddy identified - by jid. - If the buddy does not exist in the buddylist, returns 7. - Status will be 1-7. - 1=Online, 2=Chatty, 3=Away, 4=XAway, 5=DND, 6=Offline - If not in roster variable will be set to 7. - Example: ${JABBER_STATUS(asterisk,bob@domain.com)} returns 1 if - bob@domain.com is online. asterisk is - the associated XMPP account configured in jabber.conf. - - - JABBER_RECEIVE - JabberSend - - - - - Send a Jabber Message to a specified chat room - - - - Client or transport Asterisk uses to connect to Jabber. - - - XMPP/Jabber JID (Name) of chat room. - - - Message to be sent to the chat room. - - - The nickname Asterisk uses in the chat room. - - - - Allows user to send a message to a chat room via XMPP. - To be able to send messages to a chat room, a user must have previously joined it. Use the JabberJoin function to do so. - - - - - Join a chat room - - - - Client or transport Asterisk uses to connect to Jabber. - - - XMPP/Jabber JID (Name) of chat room. - - - The nickname Asterisk will use in the chat room. - If a different nickname is supplied to an already joined room, the old nick will be changed to the new one. - - - - Allows Asterisk to join a chat room. - - - - - Leave a chat room - - - - Client or transport Asterisk uses to connect to Jabber. - - - XMPP/Jabber JID (Name) of chat room. - - - The nickname Asterisk uses in the chat room. - - - - Allows Asterisk to leave a chat room. - - - - - Retrieve the status of a jabber list member - - - - Client or transport Asterisk users to connect to Jabber. - - - XMPP/Jabber JID (Name) of recipient. - - - Variable to store the status of requested user. - - - - This application is deprecated. Please use the JABBER_STATUS() function instead. - Retrieves the numeric status associated with the specified buddy JID. - The return value in the Variablewill be one of the following. - - - Online. - - - Chatty. - - - Away. - - - Extended Away. - - - Do Not Disturb. - - - Offline. - - - Not In Roster. - - - - - - - Sends a message to a Jabber Client. - - - - - Client or transport Asterisk uses to connect to JABBER. - - - XMPP/Jabber JID (Name) of recipient. - - - Message to be sent to the buddy. - - - - Sends a message to a Jabber Client. - - - ***/ - -/*!\todo This should really be renamed to xmpp.conf. For backwards compatibility, we - * need to read both files */ -#define JABBER_CONFIG "jabber.conf" - -/*-- Forward declarations */ -static void aji_message_destroy(struct aji_message *obj); -static int aji_is_secure(struct aji_client *client); -#ifdef HAVE_OPENSSL -static int aji_start_tls(struct aji_client *client); -static int aji_tls_handshake(struct aji_client *client); -#endif -static int aji_io_recv(struct aji_client *client, char *buffer, size_t buf_len, int timeout); -static int aji_recv(struct aji_client *client, int timeout); -static int aji_send_header(struct aji_client *client, const char *to); -static int aji_send_raw(struct aji_client *client, const char *xmlstr); -static void aji_log_hook(void *data, const char *xmpp, size_t size, int is_incoming); -static int aji_start_sasl(struct aji_client *client, enum ikssasltype type, char *username, char *pass); -static int aji_act_hook(void *data, int type, iks *node); -static void aji_handle_iq(struct aji_client *client, iks *node); -static void aji_handle_message(struct aji_client *client, ikspak *pak); -static void aji_handle_presence(struct aji_client *client, ikspak *pak); -static void aji_handle_subscribe(struct aji_client *client, ikspak *pak); -static int aji_send_raw_chat(struct aji_client *client, int groupchat, const char *nick, const char *address, const char *message); -static void *aji_recv_loop(void *data); -static int aji_initialize(struct aji_client *client); -static int aji_client_connect(void *data, ikspak *pak); -static void aji_set_presence(struct aji_client *client, char *to, char *from, int level, char *desc); -static int aji_set_group_presence(struct aji_client *client, char *room, int level, char *nick, char *desc); -static char *aji_do_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a); -static char *aji_do_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a); -static char *aji_show_clients(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a); -static char *aji_show_buddies(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a); -static int aji_create_client(char *label, struct ast_variable *var, int debug); -static int aji_create_buddy(char *label, struct aji_client *client); -static int aji_reload(int reload); -static int aji_load_config(int reload); -static void aji_pruneregister(struct aji_client *client); -static int aji_filter_roster(void *data, ikspak *pak); -static int aji_get_roster(struct aji_client *client); -static int aji_client_info_handler(void *data, ikspak *pak); -static int aji_dinfo_handler(void *data, ikspak *pak); -static int aji_ditems_handler(void *data, ikspak *pak); -static int aji_register_query_handler(void *data, ikspak *pak); -static int aji_register_approve_handler(void *data, ikspak *pak); -static int aji_reconnect(struct aji_client *client); -static char *aji_cli_create_collection(struct ast_cli_entry *e, int cmd, - struct ast_cli_args *a); -static char *aji_cli_list_pubsub_nodes(struct ast_cli_entry *e, int cmd, - struct ast_cli_args *a); -static char *aji_cli_delete_pubsub_node(struct ast_cli_entry *e, int cmd, struct - ast_cli_args *a); -static char *aji_cli_purge_pubsub_nodes(struct ast_cli_entry *e, int cmd, struct - ast_cli_args *a); -static iks *jabber_make_auth(iksid * id, const char *pass, const char *sid); -static int aji_receive_node_list(void *data, ikspak* pak); -static void aji_init_event_distribution(struct aji_client *client); -static iks* aji_create_pubsub_node(struct aji_client *client, const char *node_type, - const char *name, const char *collection_name); -static iks* aji_build_node_config(iks *pubsub, const char *node_type, - const char *collection_name); -static void aji_create_pubsub_collection(struct aji_client *client, - const char *collection_name); -static void aji_create_pubsub_leaf(struct aji_client *client, const char *collection_name, - const char *leaf_name); -static char *aji_cli_create_leafnode(struct ast_cli_entry *e, int cmd, - struct ast_cli_args *a); -static void aji_create_affiliations(struct aji_client *client, const char *node); -static iks* aji_pubsub_iq_create(struct aji_client *client, const char *type); -static void aji_publish_device_state(struct aji_client *client, const char * device, - const char *device_state, unsigned int cachable); -static int aji_handle_pubsub_error(void *data, ikspak *pak); -static int aji_handle_pubsub_event(void *data, ikspak *pak); -static void aji_pubsub_subscribe(struct aji_client *client, const char *node); -static void aji_delete_pubsub_node(struct aji_client *client, const char *node_name); -static iks* aji_build_node_request(struct aji_client *client, const char *collection); -static int aji_delete_node_list(void *data, ikspak* pak); -static void aji_pubsub_purge_nodes(struct aji_client *client, - const char* collection_name); -static void aji_publish_mwi(struct aji_client *client, const char *mailbox, - const char *oldmsgs, const char *newmsgs); -static void aji_devstate_cb(void *data, struct stasis_subscription *sub, struct stasis_message *msg); -static void aji_mwi_cb(void *data, struct stasis_subscription *sub, struct stasis_message *msg); -static iks* aji_build_publish_skeleton(struct aji_client *client, const char *node, - const char *event_type, unsigned int cachable); -/* No transports in this version */ -/* -static int aji_create_transport(char *label, struct aji_client *client); -static int aji_register_transport(void *data, ikspak *pak); -static int aji_register_transport2(void *data, ikspak *pak); -*/ - -static int msg_send_cb(const struct ast_msg *msg, const char *to, const char *from); - -static const struct ast_msg_tech msg_tech = { - .name = "xmpp", - .msg_send = msg_send_cb, -}; - -static struct ast_cli_entry aji_cli[] = { - AST_CLI_DEFINE(aji_do_set_debug, "Enable/Disable Jabber debug"), - AST_CLI_DEFINE(aji_do_reload, "Reload Jabber configuration"), - AST_CLI_DEFINE(aji_show_clients, "Show state of clients and components"), - AST_CLI_DEFINE(aji_show_buddies, "Show buddy lists of our clients"), - AST_CLI_DEFINE(aji_cli_create_collection, "Creates a PubSub node collection."), - AST_CLI_DEFINE(aji_cli_list_pubsub_nodes, "Lists PubSub nodes"), - AST_CLI_DEFINE(aji_cli_create_leafnode, "Creates a PubSub leaf node"), - AST_CLI_DEFINE(aji_cli_delete_pubsub_node, "Deletes a PubSub node"), - AST_CLI_DEFINE(aji_cli_purge_pubsub_nodes, "Purges PubSub nodes"), -}; - -static char *app_ajisend = "JabberSend"; -static char *app_ajisendgroup = "JabberSendGroup"; -static char *app_ajistatus = "JabberStatus"; -static char *app_ajijoin = "JabberJoin"; -static char *app_ajileave = "JabberLeave"; - -static struct aji_client_container clients; -static struct aji_capabilities *capabilities = NULL; -static struct stasis_subscription *mwi_sub = NULL; -static struct stasis_subscription *device_state_sub = NULL; -static ast_cond_t message_received_condition; -static ast_mutex_t messagelock; - -/*! \brief Global flags, initialized to default values */ -static struct ast_flags globalflags = { AJI_AUTOREGISTER | AJI_AUTOACCEPT }; - -/*! \brief PubSub flags, initialized to default values */ -static struct ast_flags pubsubflags = { 0 }; -/*! - * \internal - * \brief Deletes the aji_client data structure. - * \param obj aji_client The structure we will delete. - * \return void. - */ -void ast_aji_client_destroy(struct aji_client *obj) -{ - struct aji_message *tmp; - ASTOBJ_CONTAINER_DESTROYALL(&obj->buddies, ast_aji_buddy_destroy); - ASTOBJ_CONTAINER_DESTROY(&obj->buddies); - iks_filter_delete(obj->f); - iks_parser_delete(obj->p); - iks_stack_delete(obj->stack); - AST_LIST_LOCK(&obj->messages); - while ((tmp = AST_LIST_REMOVE_HEAD(&obj->messages, list))) { - aji_message_destroy(tmp); - } - AST_LIST_HEAD_DESTROY(&obj->messages); - ast_free(obj); -} - -/*! - * \internal - * \brief Deletes the aji_buddy data structure. - * \param obj aji_buddy The structure we will delete. - * \return void. - */ -void ast_aji_buddy_destroy(struct aji_buddy *obj) -{ - struct aji_resource *tmp; - - while ((tmp = obj->resources)) { - obj->resources = obj->resources->next; - ast_free(tmp->description); - ast_free(tmp); - } - - ast_free(obj); -} - -/*! - * \internal - * \brief Deletes the aji_message data structure. - * \param obj aji_message The structure we will delete. - * \return void. - */ -static void aji_message_destroy(struct aji_message *obj) -{ - if (obj->from) { - ast_free(obj->from); - } - if (obj->message) { - ast_free(obj->message); - } - ast_free(obj); -} - -/*! - * \internal - * \brief Find version in XML stream and populate our capabilities list - * \param node the node attribute in the caps element we'll look for or add to - * our list - * \param version the version attribute in the caps element we'll look for or - * add to our list - * \param pak struct The XML stanza we're processing - * \return a pointer to the added or found aji_version structure - */ -static struct aji_version *aji_find_version(char *node, char *version, ikspak *pak) -{ - struct aji_capabilities *list = NULL; - struct aji_version *res = NULL; - - list = capabilities; - - if (!node) { - node = pak->from->full; - } - if (!version) { - version = "none supplied."; - } - while (list) { - if (!strcasecmp(list->node, node)) { - res = list->versions; - while(res) { - if (!strcasecmp(res->version, version)) { - return res; - } - res = res->next; - } - /* Specified version not found. Let's add it to - this node in our capabilities list */ - if (!res) { - res = ast_malloc(sizeof(*res)); - if (!res) { - ast_log(LOG_ERROR, "Out of memory!\n"); - return NULL; - } - res->jingle = 0; - res->parent = list; - ast_copy_string(res->version, version, sizeof(res->version)); - res->next = list->versions; - list->versions = res; - return res; - } - } - list = list->next; - } - /* Specified node not found. Let's add it our capabilities list */ - if (!list) { - list = ast_malloc(sizeof(*list)); - if (!list) { - ast_log(LOG_ERROR, "Out of memory!\n"); - return NULL; - } - res = ast_malloc(sizeof(*res)); - if (!res) { - ast_log(LOG_ERROR, "Out of memory!\n"); - ast_free(list); - return NULL; - } - ast_copy_string(list->node, node, sizeof(list->node)); - ast_copy_string(res->version, version, sizeof(res->version)); - res->jingle = 0; - res->parent = list; - res->next = NULL; - list->versions = res; - list->next = capabilities; - capabilities = list; - } - return res; -} - -/*! - * \internal - * \brief Find the aji_resource we want - * \param buddy aji_buddy A buddy - * \param name - * \return aji_resource object -*/ -static struct aji_resource *aji_find_resource(struct aji_buddy *buddy, char *name) -{ - struct aji_resource *res = NULL; - if (!buddy || !name) { - return res; - } - res = buddy->resources; - while (res) { - if (!strcasecmp(res->resource, name)) { - break; - } - res = res->next; - } - return res; -} - -/*! - * \internal - * \brief Jabber GTalk function - * \param node iks - * \return 1 on success, 0 on failure. -*/ -static int gtalk_yuck(iks *node) -{ - if (iks_find_with_attrib(node, "c", "node", "http://www.google.com/xmpp/client/caps")) { - ast_debug(1, "Found resource with Googletalk voice capabilities\n"); - return 1; - } else if (iks_find_with_attrib(node, "caps:c", "ext", "pmuc-v1 sms-v1 camera-v1 video-v1 voice-v1")) { - ast_debug(1, "Found resource with Gmail voice/video chat capabilities\n"); - return 1; - } else if (iks_find_with_attrib(node, "caps:c", "ext", "pmuc-v1 sms-v1 video-v1 voice-v1")) { - ast_debug(1, "Found resource with Gmail voice/video chat capabilities (no camera)\n"); - return 1; - } - - return 0; -} - -/*! - * \internal - * \brief Setup the authentication struct - * \param id iksid - * \param pass password - * \param sid - * \return x iks -*/ -static iks *jabber_make_auth(iksid * id, const char *pass, const char *sid) -{ - iks *x, *y; - x = iks_new("iq"); - iks_insert_attrib(x, "type", "set"); - y = iks_insert(x, "query"); - iks_insert_attrib(y, "xmlns", IKS_NS_AUTH); - iks_insert_cdata(iks_insert(y, "username"), id->user, 0); - iks_insert_cdata(iks_insert(y, "resource"), id->resource, 0); - if (sid) { - char buf[41]; - char sidpass[100]; - snprintf(sidpass, sizeof(sidpass), "%s%s", sid, pass); - ast_sha1_hash(buf, sidpass); - iks_insert_cdata(iks_insert(y, "digest"), buf, 0); - } else { - iks_insert_cdata(iks_insert(y, "password"), pass, 0); - } - return x; -} - -/*! - * \internal - * \brief Dial plan function status(). puts the status of watched user - * into a channel variable. - * \param chan ast_channel - * \param data - * \retval 0 success - * \retval -1 error - */ -static int aji_status_exec(struct ast_channel *chan, const char *data) -{ - struct aji_client *client = NULL; - struct aji_buddy *buddy = NULL; - struct aji_resource *r = NULL; - char *s = NULL; - int stat = 7; - char status[2]; - static int deprecation_warning = 0; - AST_DECLARE_APP_ARGS(args, - AST_APP_ARG(sender); - AST_APP_ARG(jid); - AST_APP_ARG(variable); - ); - AST_DECLARE_APP_ARGS(jid, - AST_APP_ARG(screenname); - AST_APP_ARG(resource); - ); - - if (deprecation_warning++ % 10 == 0) { - ast_log(LOG_WARNING, "JabberStatus is deprecated. Please use the JABBER_STATUS dialplan function in the future.\n"); - } - - if (!data) { - ast_log(LOG_ERROR, "Usage: JabberStatus(,[/],\n"); - return 0; - } - s = ast_strdupa(data); - AST_STANDARD_APP_ARGS(args, s); - - if (args.argc != 3) { - ast_log(LOG_ERROR, "JabberStatus() requires 3 arguments.\n"); - return -1; - } - - AST_NONSTANDARD_APP_ARGS(jid, args.jid, '/'); - if (jid.argc < 1 || jid.argc > 2) { - ast_log(LOG_WARNING, "Wrong JID %s, exiting\n", args.jid); - return -1; - } - - if (!(client = ast_aji_get_client(args.sender))) { - ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender); - return -1; - } - buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, jid.screenname); - if (!buddy) { - ast_log(LOG_WARNING, "Could not find buddy in list: '%s'\n", jid.screenname); - ASTOBJ_UNREF(client, ast_aji_client_destroy); - return -1; - } - r = aji_find_resource(buddy, jid.resource); - if (!r && buddy->resources) { - r = buddy->resources; - } - ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy); - ASTOBJ_UNREF(client, ast_aji_client_destroy); - if (!r) { - ast_log(LOG_NOTICE, "Resource '%s' of buddy '%s' was not found\n", jid.resource, jid.screenname); - } else { - stat = r->status; - } - snprintf(status, sizeof(status), "%d", stat); - pbx_builtin_setvar_helper(chan, args.variable, status); - return 0; -} - -/*! - * \internal - * \brief Dial plan funtcion to retrieve the status of a buddy. - * \param channel The associated ast_channel, if there is one - * \param data The account, buddy JID, and optional timeout - * timeout. - * \retval 0 success - * \retval -1 failure - */ -static int acf_jabberstatus_read(struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen) -{ - struct aji_client *client = NULL; - struct aji_buddy *buddy = NULL; - struct aji_resource *r = NULL; - int stat = 7; - AST_DECLARE_APP_ARGS(args, - AST_APP_ARG(sender); - AST_APP_ARG(jid); - ); - AST_DECLARE_APP_ARGS(jid, - AST_APP_ARG(screenname); - AST_APP_ARG(resource); - ); - - if (!data) { - ast_log(LOG_ERROR, "Usage: JABBER_STATUS(,[/])\n"); - return 0; - } - AST_STANDARD_APP_ARGS(args, data); - - if (args.argc != 2) { - ast_log(LOG_ERROR, "JABBER_STATUS requires 2 arguments: sender and jid.\n"); - return -1; - } - - AST_NONSTANDARD_APP_ARGS(jid, args.jid, '/'); - if (jid.argc < 1 || jid.argc > 2) { - ast_log(LOG_WARNING, "Wrong JID %s, exiting\n", args.jid); - return -1; - } - - if (!(client = ast_aji_get_client(args.sender))) { - ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender); - return -1; - } - buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, jid.screenname); - if (!buddy) { - ast_log(LOG_WARNING, "Could not find buddy in list: '%s'\n", jid.screenname); - ASTOBJ_UNREF(client, ast_aji_client_destroy); - return -1; - } - r = aji_find_resource(buddy, jid.resource); - if (!r && buddy->resources) { - r = buddy->resources; - } - ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy); - ASTOBJ_UNREF(client, ast_aji_client_destroy); - if (!r) { - ast_log(LOG_NOTICE, "Resource %s of buddy %s was not found.\n", jid.resource, jid.screenname); - } else { - stat = r->status; - } - snprintf(buf, buflen, "%d", stat); - return 0; -} - -static struct ast_custom_function jabberstatus_function = { - .name = "JABBER_STATUS", - .read = acf_jabberstatus_read, -}; - -/*! - * \internal - * \brief Dial plan function to receive a message. - * \param channel The associated ast_channel, if there is one - * \param data The account, JID, and optional timeout - * timeout. - * \retval 0 success - * \retval -1 failure - */ -static int acf_jabberreceive_read(struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen) -{ - char *parse = NULL; - int timeout; - int jidlen, resourcelen; - struct timeval start; - long diff = 0; - struct aji_client *client = NULL; - int found = 0; - struct aji_message *tmp = NULL; - AST_DECLARE_APP_ARGS(args, - AST_APP_ARG(account); - AST_APP_ARG(jid); - AST_APP_ARG(timeout); - ); - AST_DECLARE_APP_ARGS(jid, - AST_APP_ARG(screenname); - AST_APP_ARG(resource); - ); - - if (ast_strlen_zero(data)) { - ast_log(LOG_WARNING, "%s requires arguments (account,jid[,timeout])\n", name); - return -1; - } - - parse = ast_strdupa(data); - AST_STANDARD_APP_ARGS(args, parse); - - if (args.argc < 2 || args.argc > 3) { - ast_log(LOG_WARNING, "%s requires arguments (account,jid[,timeout])\n", name); - return -1; - } - - parse = ast_strdupa(args.jid); - AST_NONSTANDARD_APP_ARGS(jid, parse, '/'); - if (jid.argc < 1 || jid.argc > 2 || strlen(args.jid) > AJI_MAX_JIDLEN) { - ast_log(LOG_WARNING, "Invalid JID : %s\n", parse); - return -1; - } - - if (ast_strlen_zero(args.timeout)) { - timeout = 20; - } else { - sscanf(args.timeout, "%d", &timeout); - if (timeout <= 0) { - ast_log(LOG_WARNING, "Invalid timeout specified: '%s'\n", args.timeout); - return -1; - } - } - - jidlen = strlen(jid.screenname); - resourcelen = ast_strlen_zero(jid.resource) ? 0 : strlen(jid.resource); - - client = ast_aji_get_client(args.account); - if (!client) { - ast_log(LOG_WARNING, "Could not find client %s, exiting\n", args.account); - return -1; - } - - ast_debug(3, "Waiting for an XMPP message from %s\n", args.jid); - - start = ast_tvnow(); - - if (chan && ast_autoservice_start(chan) < 0) { - ast_log(LOG_WARNING, "Cannot start autoservice for channel %s\n", ast_channel_name(chan)); - ASTOBJ_UNREF(client, ast_aji_client_destroy); - return -1; - } - - /* search the messages list, grab the first message that matches with - * the from JID we're expecting, and remove it from the messages list */ - while (diff < timeout) { - struct timespec ts = { 0, }; - struct timeval wait; - int res; - - wait = ast_tvadd(start, ast_tv(timeout, 0)); - ts.tv_sec = wait.tv_sec; - ts.tv_nsec = wait.tv_usec * 1000; - - /* wait up to timeout seconds for an incoming message */ - ast_mutex_lock(&messagelock); - res = ast_cond_timedwait(&message_received_condition, &messagelock, &ts); - ast_mutex_unlock(&messagelock); - if (res == ETIMEDOUT) { - ast_debug(3, "No message received from %s in %d seconds\n", args.jid, timeout); - break; - } - - AST_LIST_LOCK(&client->messages); - AST_LIST_TRAVERSE_SAFE_BEGIN(&client->messages, tmp, list) { - if (jid.argc == 1) { - /* no resource provided, compare bare JIDs */ - if (strncasecmp(jid.screenname, tmp->from, jidlen)) { - continue; - } - } else { - /* resource appended, compare bare JIDs and resources */ - char *resource = strchr(tmp->from, '/'); - if (!resource || strlen(resource) == 0) { - ast_log(LOG_WARNING, "Remote JID has no resource : %s\n", tmp->from); - if (strncasecmp(jid.screenname, tmp->from, jidlen)) { - continue; - } - } else { - resource ++; - if (strncasecmp(jid.screenname, tmp->from, jidlen) || strncmp(jid.resource, resource, resourcelen)) { - continue; - } - } - } - /* check if the message is not too old */ - if (ast_tvdiff_sec(ast_tvnow(), tmp->arrived) >= client->message_timeout) { - ast_debug(3, "Found old message from %s, deleting it\n", tmp->from); - AST_LIST_REMOVE_CURRENT(list); - aji_message_destroy(tmp); - continue; - } - found = 1; - ast_copy_string(buf, tmp->message, buflen); - AST_LIST_REMOVE_CURRENT(list); - aji_message_destroy(tmp); - break; - } - AST_LIST_TRAVERSE_SAFE_END; - AST_LIST_UNLOCK(&client->messages); - if (found) { - break; - } - - /* check timeout */ - diff = ast_tvdiff_ms(ast_tvnow(), start); - } - - ASTOBJ_UNREF(client, ast_aji_client_destroy); - if (chan && ast_autoservice_stop(chan) < 0) { - ast_log(LOG_WARNING, "Cannot stop autoservice for channel %s\n", ast_channel_name(chan)); - } - - /* return if we timed out */ - if (!found) { - ast_log(LOG_NOTICE, "Timed out : no message received from %s\n", args.jid); - return -1; - } - - return 0; -} - -static struct ast_custom_function jabberreceive_function = { - .name = "JABBER_RECEIVE", - .read = acf_jabberreceive_read, -}; - -/*! - * \internal - * \brief Delete old messages from a given JID - * Messages stored during more than client->message_timeout are deleted - * \param client Asterisk's XMPP client - * \param from the JID we received messages from - * \retval the number of deleted messages - * \retval -1 failure - */ -static int delete_old_messages(struct aji_client *client, char *from) -{ - int deleted = 0; - int isold = 0; - struct aji_message *tmp = NULL; - if (!client) { - ast_log(LOG_ERROR, "Cannot find our XMPP client\n"); - return -1; - } - - /* remove old messages */ - AST_LIST_LOCK(&client->messages); - if (AST_LIST_EMPTY(&client->messages)) { - AST_LIST_UNLOCK(&client->messages); - return 0; - } - - AST_LIST_TRAVERSE_SAFE_BEGIN(&client->messages, tmp, list) { - if (isold) { - if (!from || !strncasecmp(from, tmp->from, strlen(from))) { - AST_LIST_REMOVE_CURRENT(list); - aji_message_destroy(tmp); - deleted ++; - } - } else if (ast_tvdiff_sec(ast_tvnow(), tmp->arrived) >= client->message_timeout) { - isold = 1; - if (!from || !strncasecmp(from, tmp->from, strlen(from))) { - AST_LIST_REMOVE_CURRENT(list); - aji_message_destroy(tmp); - deleted ++; - } - } - } - AST_LIST_TRAVERSE_SAFE_END; - AST_LIST_UNLOCK(&client->messages); - - return deleted; -} - -/*! - * \internal - * \brief Delete old messages - * Messages stored during more than client->message_timeout are deleted - * \param client Asterisk's XMPP client - * \retval the number of deleted messages - * \retval -1 failure - */ -static int delete_old_messages_all(struct aji_client *client) -{ - return delete_old_messages(client, NULL); -} - -/*! -* \brief Application to join a chat room -* \param chan ast_channel -* \param data Data is sender|jid|nickname. -* \retval 0 success -* \retval -1 error -*/ -static int aji_join_exec(struct ast_channel *chan, const char *data) -{ - struct aji_client *client = NULL; - char *s; - char nick[AJI_MAX_RESJIDLEN]; - - AST_DECLARE_APP_ARGS(args, - AST_APP_ARG(sender); - AST_APP_ARG(jid); - AST_APP_ARG(nick); - ); - - if (!data) { - ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajijoin); - return -1; - } - s = ast_strdupa(data); - - AST_STANDARD_APP_ARGS(args, s); - if (args.argc < 2 || args.argc > 3) { - ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajijoin); - return -1; - } - - if (strchr(args.jid, '/')) { - ast_log(LOG_ERROR, "Invalid room name : resource must not be appended\n"); - return -1; - } - - if (!(client = ast_aji_get_client(args.sender))) { - ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender); - return -1; - } - - if (!ast_strlen_zero(args.nick)) { - snprintf(nick, AJI_MAX_RESJIDLEN, "%s", args.nick); - } else { - if (client->component) { - sprintf(nick, "asterisk"); - } else { - snprintf(nick, AJI_MAX_RESJIDLEN, "%s", client->jid->user); - } - } - - if (!ast_strlen_zero(args.jid) && strchr(args.jid, '@')) { - ast_aji_join_chat(client, args.jid, nick); - } else { - ast_log(LOG_ERROR, "Problem with specified jid of '%s'\n", args.jid); - } - - ASTOBJ_UNREF(client, ast_aji_client_destroy); - return 0; -} - -/*! -* \brief Application to leave a chat room -* \param chan ast_channel -* \param data Data is sender|jid|nickname. -* \retval 0 success -* \retval -1 error -*/ -static int aji_leave_exec(struct ast_channel *chan, const char *data) -{ - struct aji_client *client = NULL; - char *s; - char nick[AJI_MAX_RESJIDLEN]; - AST_DECLARE_APP_ARGS(args, - AST_APP_ARG(sender); - AST_APP_ARG(jid); - AST_APP_ARG(nick); - ); - - if (!data) { - ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajileave); - return -1; - } - s = ast_strdupa(data); - - AST_STANDARD_APP_ARGS(args, s); - if (args.argc < 2 || args.argc > 3) { - ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajileave); - return -1; - } - - if (strchr(args.jid, '/')) { - ast_log(LOG_ERROR, "Invalid room name, resource must not be appended\n"); - return -1; - } - - if (!(client = ast_aji_get_client(args.sender))) { - ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender); - return -1; - } - - if (!ast_strlen_zero(args.nick)) { - snprintf(nick, AJI_MAX_RESJIDLEN, "%s", args.nick); - } else { - if (client->component) { - sprintf(nick, "asterisk"); - } else { - snprintf(nick, AJI_MAX_RESJIDLEN, "%s", client->jid->user); - } - } - - if (!ast_strlen_zero(args.jid) && strchr(args.jid, '@')) { - ast_aji_leave_chat(client, args.jid, nick); - } - ASTOBJ_UNREF(client, ast_aji_client_destroy); - return 0; -} - -/*! - * \internal - * \brief Dial plan function to send a message. - * \param chan ast_channel - * \param data Data is account,jid,message. - * \retval 0 success - * \retval -1 failure - */ -static int aji_send_exec(struct ast_channel *chan, const char *data) -{ - struct aji_client *client = NULL; - char *s; - AST_DECLARE_APP_ARGS(args, - AST_APP_ARG(sender); - AST_APP_ARG(recipient); - AST_APP_ARG(message); - ); - - if (!data) { - ast_log(LOG_WARNING, "%s requires arguments (account,jid,message)\n", app_ajisend); - return -1; - } - s = ast_strdupa(data); - - AST_STANDARD_APP_ARGS(args, s); - if (args.argc < 3) { - ast_log(LOG_WARNING, "%s requires arguments (account,jid,message)\n", app_ajisend); - return -1; - } - - if (!(client = ast_aji_get_client(args.sender))) { - ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender); - return -1; - } - if (strchr(args.recipient, '@') && !ast_strlen_zero(args.message)) { - ast_aji_send_chat(client, args.recipient, args.message); - } - ASTOBJ_UNREF(client, ast_aji_client_destroy); - return 0; -} - -static int msg_send_cb(const struct ast_msg *msg, const char *to, const char *from) -{ - struct aji_client *client; - char *sender; - char *dest; - int res; - - sender = ast_strdupa(from); - strsep(&sender, ":"); - dest = ast_strdupa(to); - strsep(&dest, ":"); - - if (ast_strlen_zero(sender)) { - ast_log(LOG_ERROR, "MESSAGE(from) of '%s' invalid for xmpp\n", from); - return -1; - } - - if (!(client = ast_aji_get_client(sender))) { - ast_log(LOG_WARNING, "Could not finder account to send from as '%s'\n", sender); - return -1; - } - - ast_debug(1, "Sending message to '%s' from '%s'\n", dest, client->name); - - res = ast_aji_send_chat(client, dest, ast_msg_get_body(msg)); - if (res != IKS_OK) { - ast_log(LOG_WARNING, "Failed to send xmpp message (%d).\n", res); - } - - ASTOBJ_UNREF(client, ast_aji_client_destroy); - return res == IKS_OK ? 0 : -1; -} - -/*! -* \brief Application to send a message to a groupchat. -* \param chan ast_channel -* \param data Data is sender|groupchat|message. -* \retval 0 success -* \retval -1 error -*/ -static int aji_sendgroup_exec(struct ast_channel *chan, const char *data) -{ - struct aji_client *client = NULL; - char *s; - char nick[AJI_MAX_RESJIDLEN]; - int res = 0; - AST_DECLARE_APP_ARGS(args, - AST_APP_ARG(sender); - AST_APP_ARG(groupchat); - AST_APP_ARG(message); - AST_APP_ARG(nick); - ); - - if (!data) { - ast_log(LOG_ERROR, "%s requires arguments (sender,groupchatid,message[,nickname])\n", app_ajisendgroup); - return -1; - } - s = ast_strdupa(data); - - AST_STANDARD_APP_ARGS(args, s); - if (args.argc < 3 || args.argc > 4) { - ast_log(LOG_ERROR, "%s requires arguments (sender,groupchatid,message[,nickname])\n", app_ajisendgroup); - return -1; - } - - if (!(client = ast_aji_get_client(args.sender))) { - ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender); - return -1; - } - - if (ast_strlen_zero(args.nick) || args.argc == 3) { - if (client->component) { - sprintf(nick, "asterisk"); - } else { - snprintf(nick, AJI_MAX_RESJIDLEN, "%s", client->jid->user); - } - } else { - snprintf(nick, AJI_MAX_RESJIDLEN, "%s", args.nick); - } - - if (strchr(args.groupchat, '@') && !ast_strlen_zero(args.message)) { - res = ast_aji_send_groupchat(client, nick, args.groupchat, args.message); - } - - ASTOBJ_UNREF(client, ast_aji_client_destroy); - if (res != IKS_OK) { - return -1; - } - return 0; -} - -/*! - * \internal - * \brief Tests whether the connection is secured or not - * \return 0 if the connection is not secured - */ -static int aji_is_secure(struct aji_client *client) -{ -#ifdef HAVE_OPENSSL - return client->stream_flags & SECURE; -#else - return 0; -#endif -} - -#ifdef HAVE_OPENSSL -/*! - * \internal - * \brief Starts the TLS procedure - * \param client the configured XMPP client we use to connect to a XMPP server - * \return IKS_OK on success, an error code if sending failed, IKS_NET_TLSFAIL - * if OpenSSL is not installed - */ -static int aji_start_tls(struct aji_client *client) -{ - int ret; - - /* This is sent not encrypted */ - if ((ret = iks_send_raw(client->p, ""))) { - return ret; - } - - client->stream_flags |= TRY_SECURE; - return IKS_OK; -} - -/*! - * \internal - * \brief TLS handshake, OpenSSL initialization - * \param client the configured XMPP client we use to connect to a XMPP server - * \return IKS_OK on success, IKS_NET_TLSFAIL on failure - */ -static int aji_tls_handshake(struct aji_client *client) -{ - int sock; - - ast_debug(1, "Starting TLS handshake\n"); - - /* Choose an SSL/TLS protocol version, create SSL_CTX */ - client->ssl_method = SSLv3_method(); - if (!(client->ssl_context = SSL_CTX_new((SSL_METHOD *) client->ssl_method))) { - return IKS_NET_TLSFAIL; - } - - /* Create new SSL session */ - if (!(client->ssl_session = SSL_new(client->ssl_context))) { - return IKS_NET_TLSFAIL; - } - - /* Enforce TLS on our XMPP connection */ - sock = iks_fd(client->p); - if (!SSL_set_fd(client->ssl_session, sock)) { - return IKS_NET_TLSFAIL; - } - - /* Perform SSL handshake */ - if (!SSL_connect(client->ssl_session)) { - return IKS_NET_TLSFAIL; - } - - client->stream_flags &= (~TRY_SECURE); - client->stream_flags |= SECURE; - - /* Sent over the established TLS connection */ - if (aji_send_header(client, client->jid->server) != IKS_OK) { - return IKS_NET_TLSFAIL; - } - - ast_debug(1, "TLS started with server\n"); - - return IKS_OK; -} -#endif /* HAVE_OPENSSL */ - -/*! - * \internal - * \brief Secured or unsecured IO socket receiving function - * \param client the configured XMPP client we use to connect to a XMPP server - * \param buffer the reception buffer - * \param buf_len the size of the buffer - * \param timeout the select timer - * \retval the number of read bytes - * \retval 0 timeout expiration - * \retval -1 error - */ -static int aji_io_recv(struct aji_client *client, char *buffer, size_t buf_len, int timeout) -{ - struct pollfd pfd = { .events = POLLIN }; - int len, res; - -#ifdef HAVE_OPENSSL - if (aji_is_secure(client)) { - pfd.fd = SSL_get_fd(client->ssl_session); - if (pfd.fd < 0) { - return -1; - } - } else -#endif /* HAVE_OPENSSL */ - pfd.fd = iks_fd(client->p); - - res = ast_poll(&pfd, 1, timeout > 0 ? timeout * 1000 : -1); - if (res > 0) { -#ifdef HAVE_OPENSSL - if (aji_is_secure(client)) { - len = SSL_read(client->ssl_session, buffer, buf_len); - } else -#endif /* HAVE_OPENSSL */ - len = recv(pfd.fd, buffer, buf_len, 0); - - if (len > 0) { - return len; - } else if (len <= 0) { - return -1; - } - } - return res; -} - -/*! - * \internal - * \brief Tries to receive data from the Jabber server - * \param client the configured XMPP client we use to connect to a XMPP server - * \param timeout the timeout value - * This function receives (encrypted or unencrypted) data from the XMPP server, - * and passes it to the parser. - * \retval IKS_OK success - * \retval IKS_NET_RWERR IO error - * \retval IKS_NET_NOCONN no connection available - * \retval IKS_NET_EXPIRED timeout expiration - */ -static int aji_recv (struct aji_client *client, int timeout) -{ - int len, ret; - char buf[NET_IO_BUF_SIZE - 1]; - char newbuf[NET_IO_BUF_SIZE - 1]; - int pos = 0; - int newbufpos = 0; - unsigned char c; - - memset(buf, 0, sizeof(buf)); - memset(newbuf, 0, sizeof(newbuf)); - - while (1) { - len = aji_io_recv(client, buf, NET_IO_BUF_SIZE - 2, timeout); - if (len < 0) return IKS_NET_RWERR; - if (len == 0) return IKS_NET_EXPIRED; - buf[len] = '\0'; - - /* our iksemel parser won't work as expected if we feed - it with XML packets that contain multiple whitespace - characters between tags */ - while (pos < len) { - c = buf[pos]; - /* if we stumble on the ending tag character, - we skip any whitespace that follows it*/ - if (c == '>') { - while (isspace(buf[pos+1])) { - pos++; - } - } - newbuf[newbufpos] = c; - newbufpos ++; - pos++; - } - pos = 0; - newbufpos = 0; - - /* Log the message here, because iksemel's logHook is - unaccessible */ - aji_log_hook(client, buf, len, 1); - - /* let iksemel deal with the string length, - and reset our buffer */ - ret = iks_parse(client->p, newbuf, 0, 0); - memset(newbuf, 0, sizeof(newbuf)); - - switch (ret) { - case IKS_NOMEM: - ast_log(LOG_WARNING, "Parsing failure: Out of memory.\n"); - break; - case IKS_BADXML: - ast_log(LOG_WARNING, "Parsing failure: Invalid XML.\n"); - break; - case IKS_HOOK: - ast_log(LOG_WARNING, "Parsing failure: Hook returned an error.\n"); - break; - } - if (ret != IKS_OK) { - return ret; - } - ast_debug(3, "XML parsing successful\n"); - } - return IKS_OK; -} - -/*! - * \internal - * \brief Sends XMPP header to the server - * \param client the configured XMPP client we use to connect to a XMPP server - * \param to the target XMPP server - * \return IKS_OK on success, any other value on failure - */ -static int aji_send_header(struct aji_client *client, const char *to) -{ - char *msg; - int len, err; - - len = 91 + strlen(client->name_space) + 6 + strlen(to) + 16 + 1; - msg = iks_malloc(len); - if (!msg) - return IKS_NOMEM; - sprintf(msg, "" - "", client->name_space, to); - err = aji_send_raw(client, msg); - iks_free(msg); - if (err != IKS_OK) - return err; - - return IKS_OK; -} - -/*! - * \brief Wraps raw sending - * \param client the configured XMPP client we use to connect to a XMPP server - * \param x the XMPP packet to send - * \return IKS_OK on success, any other value on failure - */ -int ast_aji_send(struct aji_client *client, iks *x) -{ - return aji_send_raw(client, iks_string(iks_stack(x), x)); -} - -/*! - * \internal - * \brief Sends an XML string over an XMPP connection - * \param client the configured XMPP client we use to connect to a XMPP server - * \param xmlstr the XML string to send - * The XML data is sent whether the connection is secured or not. In the - * latter case, we just call iks_send_raw(). - * \return IKS_OK on success, any other value on failure - */ -static int aji_send_raw(struct aji_client *client, const char *xmlstr) -{ - int ret; -#ifdef HAVE_OPENSSL - int len = strlen(xmlstr); - - if (aji_is_secure(client)) { - ret = SSL_write(client->ssl_session, xmlstr, len); - if (ret) { - /* Log the message here, because iksemel's logHook is - unaccessible */ - aji_log_hook(client, xmlstr, len, 0); - return IKS_OK; - } - } -#endif - /* If needed, data will be sent unencrypted, and logHook will - be called inside iks_send_raw */ - ret = iks_send_raw(client->p, xmlstr); - if (ret != IKS_OK) { - return ret; - } - - return IKS_OK; -} - -/*! - * \internal - * \brief the debug loop. - * \param data void - * \param xmpp xml data as string - * \param size size of string - * \param is_incoming direction of packet 1 for inbound 0 for outbound. - */ -static void aji_log_hook(void *data, const char *xmpp, size_t size, int is_incoming) -{ - struct aji_client *client = ASTOBJ_REF((struct aji_client *) data); - - if (client->debug) { - if (is_incoming) { - ast_verbose("\nJABBER: %s INCOMING: %s\n", client->name, xmpp); - } else { - if (strlen(xmpp) == 1) { - if (option_debug > 2 && xmpp[0] == ' ') { - ast_verbose("\nJABBER: Keep alive packet\n"); - } - } else { - ast_verbose("\nJABBER: %s OUTGOING: %s\n", client->name, xmpp); - } - } - - } - ASTOBJ_UNREF(client, ast_aji_client_destroy); -} - -/*! - * \internal - * \brief A wrapper function for iks_start_sasl - * \param client the configured XMPP client we use to connect to a XMPP server - * \param type the SASL authentication type. Supported types are PLAIN and MD5 - * \param username - * \param pass password. - * - * \return IKS_OK on success, IKSNET_NOTSUPP on failure. - */ -static int aji_start_sasl(struct aji_client *client, enum ikssasltype type, char *username, char *pass) -{ - iks *x = NULL; - int len; - char *s; - char *base64; - - /* trigger SASL DIGEST-MD5 only over an unsecured connection. - iks_start_sasl is an iksemel API function and relies on GnuTLS, - whereas we use OpenSSL */ - if ((type & IKS_STREAM_SASL_MD5) && !aji_is_secure(client)) - return iks_start_sasl(client->p, IKS_SASL_DIGEST_MD5, username, pass); - if (!(type & IKS_STREAM_SASL_PLAIN)) { - ast_log(LOG_ERROR, "Server does not support SASL PLAIN authentication\n"); - return IKS_NET_NOTSUPP; - } - - x = iks_new("auth"); - if (!x) { - ast_log(LOG_ERROR, "Out of memory.\n"); - return IKS_NET_NOTSUPP; - } - - iks_insert_attrib(x, "xmlns", IKS_NS_XMPP_SASL); - len = strlen(username) + strlen(pass) + 3; - s = ast_alloca(len); - base64 = ast_alloca((len + 2) * 4 / 3); - iks_insert_attrib(x, "mechanism", "PLAIN"); - snprintf(s, len, "%c%s%c%s", 0, username, 0, pass); - - /* exclude the NULL training byte from the base64 encoding operation - as some XMPP servers will refuse it. - The format for authentication is [authzid]\0authcid\0password - not [authzid]\0authcid\0password\0 */ - ast_base64encode(base64, (const unsigned char *) s, len - 1, (len + 2) * 4 / 3); - iks_insert_cdata(x, base64, 0); - ast_aji_send(client, x); - iks_delete(x); - - return IKS_OK; -} - -/*! - * \internal - * \brief The action hook parses the inbound packets, constantly running. - * \param data aji client structure - * \param type type of packet - * \param node the actual packet. - * \return IKS_OK or IKS_HOOK . - */ -static int aji_act_hook(void *data, int type, iks *node) -{ - struct aji_client *client = ASTOBJ_REF((struct aji_client *) data); - ikspak *pak = NULL; - iks *auth = NULL; - int features = 0; - - if (!node) { - ast_log(LOG_ERROR, "aji_act_hook was called with out a packet\n"); /* most likely cause type is IKS_NODE_ERROR lost connection */ - ASTOBJ_UNREF(client, ast_aji_client_destroy); - return IKS_HOOK; - } - - if (client->state == AJI_DISCONNECTING) { - ASTOBJ_UNREF(client, ast_aji_client_destroy); - return IKS_HOOK; - } - - pak = iks_packet(node); - - /* work around iksemel's impossibility to recognize node names - * containing a semicolon. Set the namespace of the corresponding - * node accordingly. */ - if (iks_has_children(node) && strchr(iks_name(iks_child(node)), ':')) { - char *node_ns = NULL; - char attr[AJI_MAX_ATTRLEN]; - char *node_name = iks_name(iks_child(node)); - char *aux = strchr(node_name, ':') + 1; - snprintf(attr, strlen("xmlns:") + (strlen(node_name) - strlen(aux)), "xmlns:%s", node_name); - node_ns = iks_find_attrib(iks_child(node), attr); - if (node_ns) { - pak->ns = node_ns; - pak->query = iks_child(node); - } - } - - - if (!client->component) { /*client */ - switch (type) { - case IKS_NODE_START: - if (client->usetls && !aji_is_secure(client)) { -#ifndef HAVE_OPENSSL - ast_log(LOG_ERROR, "TLS connection cannot be established. Please install OpenSSL and its development libraries on this system, or disable the TLS option in your configuration file\n"); - ASTOBJ_UNREF(client, ast_aji_client_destroy); - return IKS_HOOK; -#else - if (aji_start_tls(client) == IKS_NET_TLSFAIL) { - ast_log(LOG_ERROR, "Could not start TLS\n"); - ASTOBJ_UNREF(client, ast_aji_client_destroy); - return IKS_HOOK; - } - break; -#endif - } - if (!client->usesasl) { - iks_filter_add_rule(client->f, aji_client_connect, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, client->mid, IKS_RULE_DONE); - auth = jabber_make_auth(client->jid, client->password, iks_find_attrib(node, "id")); - if (auth) { - iks_insert_attrib(auth, "id", client->mid); - iks_insert_attrib(auth, "to", client->jid->server); - ast_aji_increment_mid(client->mid); - ast_aji_send(client, auth); - iks_delete(auth); - } else { - ast_log(LOG_ERROR, "Out of memory.\n"); - } - } - break; - - case IKS_NODE_NORMAL: -#ifdef HAVE_OPENSSL - if (client->stream_flags & TRY_SECURE) { - if (!strcmp("proceed", iks_name(node))) { - return aji_tls_handshake(client); - } - } -#endif - if (!strcmp("stream:features", iks_name(node))) { - features = iks_stream_features(node); - if (client->usesasl) { - if (client->usetls && !aji_is_secure(client)) { - break; - } - if (client->authorized) { - if (features & IKS_STREAM_BIND) { - iks_filter_add_rule(client->f, aji_client_connect, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_DONE); - auth = iks_make_resource_bind(client->jid); - if (auth) { - iks_insert_attrib(auth, "id", client->mid); - ast_aji_increment_mid(client->mid); - ast_aji_send(client, auth); - iks_delete(auth); - } else { - ast_log(LOG_ERROR, "Out of memory.\n"); - break; - } - } - if (features & IKS_STREAM_SESSION) { - iks_filter_add_rule (client->f, aji_client_connect, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, "auth", IKS_RULE_DONE); - auth = iks_make_session(); - if (auth) { - iks_insert_attrib(auth, "id", "auth"); - ast_aji_increment_mid(client->mid); - ast_aji_send(client, auth); - iks_delete(auth); - } else { - ast_log(LOG_ERROR, "Out of memory.\n"); - } - } - } else { - int ret; - if (!client->jid->user) { - ast_log(LOG_ERROR, "Malformed Jabber ID : %s (domain missing?)\n", client->jid->full); - break; - } - - ret = aji_start_sasl(client, features, client->jid->user, client->password); - if (ret != IKS_OK) { - ASTOBJ_UNREF(client, ast_aji_client_destroy); - return IKS_HOOK; - } - break; - } - } - } else if (!strcmp("failure", iks_name(node))) { - ast_log(LOG_ERROR, "JABBER: encryption failure. possible bad password.\n"); - } else if (!strcmp("success", iks_name(node))) { - client->authorized = 1; - aji_send_header(client, client->jid->server); - } - break; - case IKS_NODE_ERROR: - ast_log(LOG_ERROR, "JABBER: Node Error\n"); - ASTOBJ_UNREF(client, ast_aji_client_destroy); - return IKS_HOOK; - break; - case IKS_NODE_STOP: - ast_log(LOG_WARNING, "JABBER: Disconnected\n"); - ASTOBJ_UNREF(client, ast_aji_client_destroy); - return IKS_HOOK; - break; - } - } else if (client->state != AJI_CONNECTED && client->component) { - switch (type) { - case IKS_NODE_START: - if (client->state == AJI_DISCONNECTED) { - char secret[160], shasum[320], *handshake; - - sprintf(secret, "%s%s", pak->id, client->password); - ast_sha1_hash(shasum, secret); - if (ast_asprintf(&handshake, "%s", shasum) >= 0) { - aji_send_raw(client, handshake); - ast_free(handshake); - } - client->state = AJI_CONNECTING; - if (aji_recv(client, 1) == 2) /*XXX proper result for iksemel library on iks_recv of XXX*/ - client->state = AJI_CONNECTED; - else - ast_log(LOG_WARNING, "Jabber didn't seem to handshake, failed to authenticate.\n"); - break; - } - break; - - case IKS_NODE_NORMAL: - break; - - case IKS_NODE_ERROR: - ast_log(LOG_ERROR, "JABBER: Node Error\n"); - ASTOBJ_UNREF(client, ast_aji_client_destroy); - return IKS_HOOK; - - case IKS_NODE_STOP: - ast_log(LOG_WARNING, "JABBER: Disconnected\n"); - ASTOBJ_UNREF(client, ast_aji_client_destroy); - return IKS_HOOK; - } - } - - switch (pak->type) { - case IKS_PAK_NONE: - ast_debug(1, "JABBER: I don't know what to do with paktype NONE.\n"); - break; - case IKS_PAK_MESSAGE: - aji_handle_message(client, pak); - ast_debug(1, "JABBER: Handling paktype MESSAGE.\n"); - break; - case IKS_PAK_PRESENCE: - aji_handle_presence(client, pak); - ast_debug(1, "JABBER: Handling paktype PRESENCE\n"); - break; - case IKS_PAK_S10N: - aji_handle_subscribe(client, pak); - ast_debug(1, "JABBER: Handling paktype S10N\n"); - break; - case IKS_PAK_IQ: - ast_debug(1, "JABBER: Handling paktype IQ\n"); - aji_handle_iq(client, node); - break; - default: - ast_debug(1, "JABBER: I don't know anything about paktype '%u'\n", pak->type); - break; - } - - iks_filter_packet(client->f, pak); - - if (node) - iks_delete(node); - - ASTOBJ_UNREF(client, ast_aji_client_destroy); - return IKS_OK; -} -/*! - * \internal - * \brief Unknown - * \param data void - * \param pak ikspak - * \return IKS_FILTER_EAT. -*/ -static int aji_register_approve_handler(void *data, ikspak *pak) -{ - struct aji_client *client = ASTOBJ_REF((struct aji_client *) data); - iks *iq = NULL, *presence = NULL, *x = NULL; - - iq = iks_new("iq"); - presence = iks_new("presence"); - x = iks_new("x"); - if (client && iq && presence && x) { - if (!iks_find(pak->query, "remove")) { - iks_insert_attrib(iq, "from", client->jid->full); - iks_insert_attrib(iq, "to", pak->from->full); - iks_insert_attrib(iq, "id", pak->id); - iks_insert_attrib(iq, "type", "result"); - ast_aji_send(client, iq); - - iks_insert_attrib(presence, "from", client->jid->full); - iks_insert_attrib(presence, "to", pak->from->partial); - iks_insert_attrib(presence, "id", client->mid); - ast_aji_increment_mid(client->mid); - iks_insert_attrib(presence, "type", "subscribe"); - iks_insert_attrib(x, "xmlns", "vcard-temp:x:update"); - iks_insert_node(presence, x); - ast_aji_send(client, presence); - } - } else { - ast_log(LOG_ERROR, "Out of memory.\n"); - } - - iks_delete(iq); - iks_delete(presence); - iks_delete(x); - - ASTOBJ_UNREF(client, ast_aji_client_destroy); - return IKS_FILTER_EAT; -} -/*! - * \internal - * \brief register handler for incoming querys (IQ's) - * \param data incoming aji_client request - * \param pak ikspak - * \return IKS_FILTER_EAT. -*/ -static int aji_register_query_handler(void *data, ikspak *pak) -{ - struct aji_client *client = ASTOBJ_REF((struct aji_client *) data); - struct aji_buddy *buddy = NULL; - iks *iq = NULL, *query = NULL; - - client = (struct aji_client *) data; - - buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial); - if (!buddy) { - iks *error = NULL, *notacceptable = NULL; - - ast_log(LOG_ERROR, "Someone.... %s tried to register but they aren't allowed\n", pak->from->partial); - iq = iks_new("iq"); - query = iks_new("query"); - error = iks_new("error"); - notacceptable = iks_new("not-acceptable"); - if (iq && query && error && notacceptable) { - iks_insert_attrib(iq, "type", "error"); - iks_insert_attrib(iq, "from", client->user); - iks_insert_attrib(iq, "to", pak->from->full); - iks_insert_attrib(iq, "id", pak->id); - iks_insert_attrib(query, "xmlns", "jabber:iq:register"); - iks_insert_attrib(error, "code" , "406"); - iks_insert_attrib(error, "type", "modify"); - iks_insert_attrib(notacceptable, "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas"); - iks_insert_node(iq, query); - iks_insert_node(iq, error); - iks_insert_node(error, notacceptable); - ast_aji_send(client, iq); - } else { - ast_log(LOG_ERROR, "Out of memory.\n"); - } - - iks_delete(error); - iks_delete(notacceptable); - } else if (!iks_find_attrib(pak->query, "node")) { - iks *instructions = NULL; - char *explain = "Welcome to Asterisk - the Open Source PBX.\n"; - iq = iks_new("iq"); - query = iks_new("query"); - instructions = iks_new("instructions"); - if (iq && query && instructions && client) { - iks_insert_attrib(iq, "from", client->user); - iks_insert_attrib(iq, "to", pak->from->full); - iks_insert_attrib(iq, "id", pak->id); - iks_insert_attrib(iq, "type", "result"); - iks_insert_attrib(query, "xmlns", "jabber:iq:register"); - iks_insert_cdata(instructions, explain, 0); - iks_insert_node(iq, query); - iks_insert_node(query, instructions); - ast_aji_send(client, iq); - } else { - ast_log(LOG_ERROR, "Out of memory.\n"); - } - - iks_delete(instructions); - } - iks_delete(iq); - iks_delete(query); - ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy); - ASTOBJ_UNREF(client, ast_aji_client_destroy); - return IKS_FILTER_EAT; -} - -/*! - * \internal - * \brief Handles stuff - * \param data void - * \param pak ikspak - * \return IKS_FILTER_EAT. -*/ -static int aji_ditems_handler(void *data, ikspak *pak) -{ - struct aji_client *client = ASTOBJ_REF((struct aji_client *) data); - char *node = NULL; - - if (!(node = iks_find_attrib(pak->query, "node"))) { - iks *iq = NULL, *query = NULL, *item = NULL; - iq = iks_new("iq"); - query = iks_new("query"); - item = iks_new("item"); - - if (iq && query && item) { - iks_insert_attrib(iq, "from", client->user); - iks_insert_attrib(iq, "to", pak->from->full); - iks_insert_attrib(iq, "id", pak->id); - iks_insert_attrib(iq, "type", "result"); - iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items"); - iks_insert_attrib(item, "node", "http://jabber.org/protocol/commands"); - iks_insert_attrib(item, "name", "Million Dollar Asterisk Commands"); - iks_insert_attrib(item, "jid", client->user); - - iks_insert_node(iq, query); - iks_insert_node(query, item); - ast_aji_send(client, iq); - } else { - ast_log(LOG_ERROR, "Out of memory.\n"); - } - - iks_delete(iq); - iks_delete(query); - iks_delete(item); - - } else if (!strcasecmp(node, "http://jabber.org/protocol/commands")) { - iks *iq, *query, *confirm; - iq = iks_new("iq"); - query = iks_new("query"); - confirm = iks_new("item"); - if (iq && query && confirm && client) { - iks_insert_attrib(iq, "from", client->user); - iks_insert_attrib(iq, "to", pak->from->full); - iks_insert_attrib(iq, "id", pak->id); - iks_insert_attrib(iq, "type", "result"); - iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items"); - iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands"); - iks_insert_attrib(confirm, "node", "confirmaccount"); - iks_insert_attrib(confirm, "name", "Confirm AIM account"); - iks_insert_attrib(confirm, "jid", "blog.astjab.org"); - - iks_insert_node(iq, query); - iks_insert_node(query, confirm); - ast_aji_send(client, iq); - } else { - ast_log(LOG_ERROR, "Out of memory.\n"); - } - - iks_delete(iq); - iks_delete(query); - iks_delete(confirm); - - } else if (!strcasecmp(node, "confirmaccount")) { - iks *iq = NULL, *query = NULL, *feature = NULL; - - iq = iks_new("iq"); - query = iks_new("query"); - feature = iks_new("feature"); - - if (iq && query && feature && client) { - iks_insert_attrib(iq, "from", client->user); - iks_insert_attrib(iq, "to", pak->from->full); - iks_insert_attrib(iq, "id", pak->id); - iks_insert_attrib(iq, "type", "result"); - iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items"); - iks_insert_attrib(feature, "var", "http://jabber.org/protocol/commands"); - iks_insert_node(iq, query); - iks_insert_node(query, feature); - ast_aji_send(client, iq); - } else { - ast_log(LOG_ERROR, "Out of memory.\n"); - } - - iks_delete(iq); - iks_delete(query); - iks_delete(feature); - } - - ASTOBJ_UNREF(client, ast_aji_client_destroy); - return IKS_FILTER_EAT; - -} - -/*! - * \internal - * \brief Handle add extra info - * \param data void - * \param pak ikspak - * \return IKS_FILTER_EAT -*/ -static int aji_client_info_handler(void *data, ikspak *pak) -{ - struct aji_client *client = ASTOBJ_REF((struct aji_client *) data); - struct aji_resource *resource = NULL; - struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial); - - if (!buddy) { - ast_log(LOG_NOTICE, "JABBER: Received client info from unknown buddy: %s.\n", pak->from->full); - ASTOBJ_UNREF(client, ast_aji_client_destroy); - return IKS_FILTER_EAT; - } - - resource = aji_find_resource(buddy, pak->from->resource); - if (pak->subtype == IKS_TYPE_RESULT) { - if (!resource) { - ast_log(LOG_NOTICE, "JABBER: Received client info from %s when not requested.\n", pak->from->full); - ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy); - ASTOBJ_UNREF(client, ast_aji_client_destroy); - return IKS_FILTER_EAT; - } - if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) { - resource->cap->jingle = 1; - } else { - resource->cap->jingle = 0; - } - } else if (pak->subtype == IKS_TYPE_GET) { - iks *iq, *disco, *ident, *google, *query; - iq = iks_new("iq"); - query = iks_new("query"); - ident = iks_new("identity"); - disco = iks_new("feature"); - google = iks_new("feature"); - if (iq && ident && disco && google) { - iks_insert_attrib(iq, "from", client->jid->full); - iks_insert_attrib(iq, "to", pak->from->full); - iks_insert_attrib(iq, "type", "result"); - iks_insert_attrib(iq, "id", pak->id); - iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info"); - iks_insert_attrib(ident, "category", "client"); - iks_insert_attrib(ident, "type", "pc"); - iks_insert_attrib(ident, "name", "asterisk"); - iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco#info"); - iks_insert_attrib(google, "var", "http://www.google.com/xmpp/protocol/voice/v1"); - iks_insert_node(iq, query); - iks_insert_node(query, ident); - iks_insert_node(query, google); - iks_insert_node(query, disco); - ast_aji_send(client, iq); - } else { - ast_log(LOG_ERROR, "Out of Memory.\n"); - } - - iks_delete(iq); - iks_delete(query); - iks_delete(ident); - iks_delete(google); - iks_delete(disco); - } else if (pak->subtype == IKS_TYPE_ERROR) { - ast_log(LOG_NOTICE, "User %s does not support discovery.\n", pak->from->full); - } - ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy); - ASTOBJ_UNREF(client, ast_aji_client_destroy); - return IKS_FILTER_EAT; -} - -/*! - * \internal - * \brief Handler of the return info packet - * \param data aji_client - * \param pak ikspak - * \return IKS_FILTER_EAT -*/ -static int aji_dinfo_handler(void *data, ikspak *pak) -{ - struct aji_client *client = ASTOBJ_REF((struct aji_client *) data); - char *node = NULL; - struct aji_resource *resource = NULL; - struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial); - - if (!buddy) { - ast_log(LOG_NOTICE, "JABBER: Received client info from unknown buddy: %s.\n", pak->from->full); - ASTOBJ_UNREF(client, ast_aji_client_destroy); - return IKS_FILTER_EAT; - } - - if (pak->subtype == IKS_TYPE_ERROR) { - ast_log(LOG_WARNING, "Received error from a client, turn on jabber debug!\n"); - ASTOBJ_UNREF(client, ast_aji_client_destroy); - return IKS_FILTER_EAT; - } - resource = aji_find_resource(buddy, pak->from->resource); - if (pak->subtype == IKS_TYPE_RESULT) { - if (!resource) { - ast_log(LOG_NOTICE, "JABBER: Received client info from %s when not requested.\n", pak->from->full); - ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy); - ASTOBJ_UNREF(client, ast_aji_client_destroy); - return IKS_FILTER_EAT; - } - if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) { - resource->cap->jingle = 1; - } else { - resource->cap->jingle = 0; - } - } else if (pak->subtype == IKS_TYPE_GET && !(node = iks_find_attrib(pak->query, "node"))) { - iks *iq, *query, *identity, *disco, *reg, *commands, *gateway, *version, *vcard, *search; - - iq = iks_new("iq"); - query = iks_new("query"); - identity = iks_new("identity"); - disco = iks_new("feature"); - reg = iks_new("feature"); - commands = iks_new("feature"); - gateway = iks_new("feature"); - version = iks_new("feature"); - vcard = iks_new("feature"); - search = iks_new("feature"); - if (iq && query && identity && disco && reg && commands && gateway && version && vcard && search && client) { - iks_insert_attrib(iq, "from", client->user); - iks_insert_attrib(iq, "to", pak->from->full); - iks_insert_attrib(iq, "id", pak->id); - iks_insert_attrib(iq, "type", "result"); - iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info"); - iks_insert_attrib(identity, "category", "gateway"); - iks_insert_attrib(identity, "type", "pstn"); - iks_insert_attrib(identity, "name", "Asterisk The Open Source PBX"); - iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco"); - iks_insert_attrib(reg, "var", "jabber:iq:register"); - iks_insert_attrib(commands, "var", "http://jabber.org/protocol/commands"); - iks_insert_attrib(gateway, "var", "jabber:iq:gateway"); - iks_insert_attrib(version, "var", "jabber:iq:version"); - iks_insert_attrib(vcard, "var", "vcard-temp"); - iks_insert_attrib(search, "var", "jabber:iq:search"); - - iks_insert_node(iq, query); - iks_insert_node(query, identity); - iks_insert_node(query, disco); - iks_insert_node(query, reg); - iks_insert_node(query, commands); - iks_insert_node(query, gateway); - iks_insert_node(query, version); - iks_insert_node(query, vcard); - iks_insert_node(query, search); - ast_aji_send(client, iq); - } else { - ast_log(LOG_ERROR, "Out of memory.\n"); - } - - iks_delete(iq); - iks_delete(query); - iks_delete(identity); - iks_delete(disco); - iks_delete(reg); - iks_delete(commands); - iks_delete(gateway); - iks_delete(version); - iks_delete(vcard); - iks_delete(search); - } else if (pak->subtype == IKS_TYPE_GET && !strcasecmp(node, "http://jabber.org/protocol/commands")) { - iks *iq, *query, *confirm; - iq = iks_new("iq"); - query = iks_new("query"); - confirm = iks_new("item"); - - if (iq && query && confirm && client) { - iks_insert_attrib(iq, "from", client->user); - iks_insert_attrib(iq, "to", pak->from->full); - iks_insert_attrib(iq, "id", pak->id); - iks_insert_attrib(iq, "type", "result"); - iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items"); - iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands"); - iks_insert_attrib(confirm, "node", "confirmaccount"); - iks_insert_attrib(confirm, "name", "Confirm AIM account"); - iks_insert_attrib(confirm, "jid", client->user); - iks_insert_node(iq, query); - iks_insert_node(query, confirm); - ast_aji_send(client, iq); - } else { - ast_log(LOG_ERROR, "Out of memory.\n"); - } - - iks_delete(iq); - iks_delete(query); - iks_delete(confirm); - - } else if (pak->subtype == IKS_TYPE_GET && !strcasecmp(node, "confirmaccount")) { - iks *iq, *query, *feature; - - iq = iks_new("iq"); - query = iks_new("query"); - feature = iks_new("feature"); - - if (iq && query && feature && client) { - iks_insert_attrib(iq, "from", client->user); - iks_insert_attrib(iq, "to", pak->from->full); - iks_insert_attrib(iq, "id", pak->id); - iks_insert_attrib(iq, "type", "result"); - iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info"); - iks_insert_attrib(feature, "var", "http://jabber.org/protocol/commands"); - iks_insert_node(iq, query); - iks_insert_node(query, feature); - ast_aji_send(client, iq); - } else { - ast_log(LOG_ERROR, "Out of memory.\n"); - } - - iks_delete(iq); - iks_delete(query); - iks_delete(feature); - } - - ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy); - ASTOBJ_UNREF(client, ast_aji_client_destroy); - return IKS_FILTER_EAT; -} - -/*! - * \internal - * \brief Handles \verbatim \endverbatim stanzas. - * \param client the configured XMPP client we use to connect to a XMPP server - * \param node iks - * \return void. - */ -static void aji_handle_iq(struct aji_client *client, iks *node) -{ - /*Nothing to see here */ -} - -/*! - * \internal - * \brief Handles \verbatim \endverbatim stanzas. - * Adds the incoming message to the client's message list. - * \param client the configured XMPP client we use to connect to a XMPP server - * \param pak ikspak the node - */ -static void aji_handle_message(struct aji_client *client, ikspak *pak) -{ - struct aji_message *insert; - int deleted = 0; - struct ast_msg *msg; - - ast_debug(3, "client %s received a message\n", client->name); - - if (!(insert = ast_calloc(1, sizeof(*insert)))) { - return; - } - - insert->arrived = ast_tvnow(); - - /* wake up threads waiting for messages */ - ast_mutex_lock(&messagelock); - ast_cond_broadcast(&message_received_condition); - ast_mutex_unlock(&messagelock); - - if (iks_find_cdata(pak->x, "body")) { - insert->message = ast_strdup(iks_find_cdata(pak->x, "body")); - } - if (pak->id) { - ast_copy_string(insert->id, pak->id, sizeof(insert->id)); - } - if (pak->from){ - /* insert will furtherly be added to message list */ - insert->from = ast_strdup(pak->from->full); - if (!insert->from) { - ast_free(insert); - ast_log(LOG_ERROR, "Memory allocation failure\n"); - return; - } - ast_debug(3, "message comes from %s\n", insert->from); - } - - if (client->send_to_dialplan) { - if ((msg = ast_msg_alloc())) { - int res; - - res = ast_msg_set_to(msg, "xmpp:%s", client->user); - res |= ast_msg_set_from(msg, "xmpp:%s", insert->from); - res |= ast_msg_set_body(msg, "%s", insert->message); - res |= ast_msg_set_context(msg, "%s", client->context); - - if (res) { - ast_msg_destroy(msg); - } else { - ast_msg_queue(msg); - } - - msg = NULL; - } - } - - /* remove old messages received from this JID - * and insert received message */ - deleted = delete_old_messages(client, pak->from->partial); - ast_debug(3, "Deleted %d messages for client %s from JID %s\n", deleted, client->name, pak->from->partial); - AST_LIST_LOCK(&client->messages); - AST_LIST_INSERT_HEAD(&client->messages, insert, list); - AST_LIST_UNLOCK(&client->messages); -} - -/*! - * \internal - * \brief handles \verbatim \endverbatim stanzas. - * \param client the configured XMPP client we use to connect to a XMPP server - * \param pak ikspak - */ -static void aji_handle_presence(struct aji_client *client, ikspak *pak) -{ - int status, priority; - struct aji_buddy *buddy; - struct aji_resource *tmp = NULL, *last = NULL, *found = NULL; - char *ver, *node, *descrip, *type; - - if (client->state != AJI_CONNECTED) - aji_create_buddy(pak->from->partial, client); - - buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial); - if (!buddy && pak->from->partial) { - /* allow our jid to be used to log in with another resource */ - if (!strcmp((const char *)pak->from->partial, (const char *)client->jid->partial)) - aji_create_buddy(pak->from->partial, client); - else - ast_log(LOG_NOTICE, "Got presence packet from %s, someone not in our roster!!!!\n", pak->from->partial); - return; - } - type = iks_find_attrib(pak->x, "type"); - if (client->component && type &&!strcasecmp("probe", type)) { - aji_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), client->status, client->statusmessage); - ast_verbose("what i was looking for \n"); - } - ASTOBJ_WRLOCK(buddy); - status = (pak->show) ? pak->show : 6; - priority = atoi((iks_find_cdata(pak->x, "priority")) ? iks_find_cdata(pak->x, "priority") : "0"); - tmp = buddy->resources; - descrip = ast_strdup(iks_find_cdata(pak->x, "status")); - - while (tmp && pak->from->resource) { - if (!strcasecmp(tmp->resource, pak->from->resource)) { - tmp->status = status; - if (tmp->description) { - ast_free(tmp->description); - } - tmp->description = descrip; - found = tmp; - if (status == 6) { /* Sign off Destroy resource */ - if (last && found->next) { - last->next = found->next; - } else if (!last) { - if (found->next) { - buddy->resources = found->next; - } else { - buddy->resources = NULL; - } - } else if (!found->next) { - if (last) { - last->next = NULL; - } else { - buddy->resources = NULL; - } - } - ast_free(found); - found = NULL; - break; - } - /* resource list is sorted by descending priority */ - if (tmp->priority != priority) { - found->priority = priority; - if (!last && !found->next) { - /* resource was found to be unique, - leave loop */ - break; - } - /* search for resource in our list - and take it out for the moment */ - if (last) { - last->next = found->next; - } else { - buddy->resources = found->next; - } - - last = NULL; - tmp = buddy->resources; - if (!buddy->resources) { - buddy->resources = found; - } - /* priority processing */ - while (tmp) { - /* insert resource back according to - its priority value */ - if (found->priority > tmp->priority) { - if (last) { - /* insert within list */ - last->next = found; - } - found->next = tmp; - if (!last) { - /* insert on top */ - buddy->resources = found; - } - break; - } - if (!tmp->next) { - /* insert at the end of the list */ - tmp->next = found; - found->next = NULL; - break; - } - last = tmp; - tmp = tmp->next; - } - } - break; - } - last = tmp; - tmp = tmp->next; - } - - /* resource not found in our list, create it */ - if (!found && status != 6 && pak->from->resource) { - found = ast_calloc(1, sizeof(*found)); - - if (!found) { - ast_log(LOG_ERROR, "Out of memory!\n"); - ASTOBJ_UNLOCK(buddy); - ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy); - return; - } - ast_copy_string(found->resource, pak->from->resource, sizeof(found->resource)); - found->status = status; - found->description = descrip; - found->priority = priority; - found->next = NULL; - last = NULL; - tmp = buddy->resources; - while (tmp) { - if (found->priority > tmp->priority) { - if (last) { - last->next = found; - } - found->next = tmp; - if (!last) { - buddy->resources = found; - } - break; - } - if (!tmp->next) { - tmp->next = found; - break; - } - last = tmp; - tmp = tmp->next; - } - if (!tmp) { - buddy->resources = found; - } - } - - ASTOBJ_UNLOCK(buddy); - ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy); - - node = iks_find_attrib(iks_find(pak->x, "c"), "node"); - ver = iks_find_attrib(iks_find(pak->x, "c"), "ver"); - - /* handle gmail client's special caps:c tag */ - if (!node && !ver) { - node = iks_find_attrib(iks_find(pak->x, "caps:c"), "node"); - ver = iks_find_attrib(iks_find(pak->x, "caps:c"), "ver"); - } - - /* retrieve capabilites of the new resource */ - if (status != 6 && found && !found->cap) { - found->cap = aji_find_version(node, ver, pak); - if (gtalk_yuck(pak->x)) { /* gtalk should do discover */ - found->cap->jingle = 1; - } - if (found->cap->jingle) { - ast_debug(1, "Special case for google till they support discover.\n"); - } else { - iks *iq, *query; - iq = iks_new("iq"); - query = iks_new("query"); - if (query && iq) { - iks_insert_attrib(iq, "type", "get"); - iks_insert_attrib(iq, "to", pak->from->full); - iks_insert_attrib(iq, "from", client->jid->full); - iks_insert_attrib(iq, "id", client->mid); - ast_aji_increment_mid(client->mid); - iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info"); - iks_insert_node(iq, query); - ast_aji_send(client, iq); - } else { - ast_log(LOG_ERROR, "Out of memory.\n"); - } - iks_delete(query); - iks_delete(iq); - } - } - switch (pak->subtype) { - case IKS_TYPE_AVAILABLE: - ast_debug(3, "JABBER: I am available ^_* %u\n", pak->subtype); - break; - case IKS_TYPE_UNAVAILABLE: - ast_debug(3, "JABBER: I am unavailable ^_* %u\n", pak->subtype); - break; - default: - ast_debug(3, "JABBER: Ohh sexy and the wrong type: %u\n", pak->subtype); - } - switch (pak->show) { - case IKS_SHOW_UNAVAILABLE: - ast_debug(3, "JABBER: type: %u subtype %u\n", pak->subtype, pak->show); - break; - case IKS_SHOW_AVAILABLE: - ast_debug(3, "JABBER: type is available\n"); - break; - case IKS_SHOW_CHAT: - ast_debug(3, "JABBER: type: %u subtype %u\n", pak->subtype, pak->show); - break; - case IKS_SHOW_AWAY: - ast_debug(3, "JABBER: type is away\n"); - break; - case IKS_SHOW_XA: - ast_debug(3, "JABBER: type: %u subtype %u\n", pak->subtype, pak->show); - break; - case IKS_SHOW_DND: - ast_debug(3, "JABBER: type: %u subtype %u\n", pak->subtype, pak->show); - break; - default: - ast_debug(3, "JABBER: Kinky! how did that happen %u\n", pak->show); - } - - if (found) { - manager_event(EVENT_FLAG_USER, "JabberStatus", - "Account: %s\r\nJID: %s\r\nResource: %s\r\nStatus: %d\r\nPriority: %d" - "\r\nDescription: %s\r\n", - client->name, pak->from->partial, found->resource, found->status, - found->priority, S_OR(found->description, "")); - } else { - manager_event(EVENT_FLAG_USER, "JabberStatus", - "Account: %s\r\nJID: %s\r\nStatus: %u\r\n", - client->name, pak->from->partial, pak->show ? pak->show : IKS_SHOW_UNAVAILABLE); - } -} - -/*! - * \internal - * \brief handles subscription requests. - * \param client the configured XMPP client we use to connect to a XMPP server - * \param pak ikspak iksemel packet. - * \return void. - */ -static void aji_handle_subscribe(struct aji_client *client, ikspak *pak) -{ - iks *presence = NULL, *status = NULL; - struct aji_buddy* buddy = NULL; - - switch (pak->subtype) { - case IKS_TYPE_SUBSCRIBE: - if (ast_test_flag(&client->flags, AJI_AUTOACCEPT)) { - presence = iks_new("presence"); - status = iks_new("status"); - if (presence && status) { - iks_insert_attrib(presence, "type", "subscribed"); - iks_insert_attrib(presence, "to", pak->from->full); - iks_insert_attrib(presence, "from", client->jid->full); - if (pak->id) - iks_insert_attrib(presence, "id", pak->id); - iks_insert_cdata(status, "Asterisk has approved subscription", 0); - iks_insert_node(presence, status); - ast_aji_send(client, presence); - } else { - ast_log(LOG_ERROR, "Unable to allocate nodes\n"); - } - - iks_delete(presence); - iks_delete(status); - } - - if (client->component) - aji_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), client->status, client->statusmessage); - case IKS_TYPE_SUBSCRIBED: - buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial); - if (!buddy && pak->from->partial) { - aji_create_buddy(pak->from->partial, client); - } else if (buddy) { - ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy); - } - default: - ast_debug(3, "JABBER: This is a subcription of type %i\n", pak->subtype); - } -} - -/*! - * \brief sends messages. - * \param client the configured XMPP client we use to connect to a XMPP server - * \param address - * \param message - * \retval IKS_OK success - * \retval -1 failure - */ -int ast_aji_send_chat(struct aji_client *client, const char *address, const char *message) -{ - return aji_send_raw_chat(client, 0, NULL, address, message); -} - -/*! -* \brief sends message to a groupchat -* Prior to sending messages to a groupchat, one must be connected to it. -* \param client the configured XMPP client we use to connect to a XMPP server -* \param nick the nickname we use in the chatroom -* \param address the user the messages must be sent to -* \param message the message to send -* \return IKS_OK on success, any other value on failure -*/ -int ast_aji_send_groupchat(struct aji_client *client, const char *nick, const char *address, const char *message) { - return aji_send_raw_chat(client, 1, nick, address, message); -} - -/*! -* \brief sends messages. -* \param client the configured XMPP client we use to connect to a XMPP server -* \param groupchat -* \param nick the nickname we use in chatrooms -* \param address -* \param message -* \return IKS_OK on success, any other value on failure -*/ -static int aji_send_raw_chat(struct aji_client *client, int groupchat, const char *nick, const char *address, const char *message) -{ - int res = 0; - iks *message_packet = NULL; - char from[AJI_MAX_JIDLEN]; - /* the nickname is used only in component mode */ - if (nick && client->component) { - snprintf(from, AJI_MAX_JIDLEN, "%s@%s/%s", nick, client->jid->full, nick); - } else { - snprintf(from, AJI_MAX_JIDLEN, "%s", client->jid->full); - } - - if (client->state != AJI_CONNECTED) { - ast_log(LOG_WARNING, "JABBER: Not connected can't send\n"); - return -1; - } - - message_packet = iks_make_msg(groupchat ? IKS_TYPE_GROUPCHAT : IKS_TYPE_CHAT, address, message); - if (!message_packet) { - ast_log(LOG_ERROR, "Out of memory.\n"); - return -1; - } - iks_insert_attrib(message_packet, "from", from); - res = ast_aji_send(client, message_packet); - iks_delete(message_packet); - - return res; -} - -/*! - * \brief create a chatroom. - * \param client the configured XMPP client we use to connect to a XMPP server - * \param room name of room - * \param server name of server - * \param topic topic for the room. - * \return 0. - */ -int ast_aji_create_chat(struct aji_client *client, char *room, char *server, char *topic) -{ - int res = 0; - iks *iq = NULL; - iq = iks_new("iq"); - - if (iq && client) { - iks_insert_attrib(iq, "type", "get"); - iks_insert_attrib(iq, "to", server); - iks_insert_attrib(iq, "id", client->mid); - ast_aji_increment_mid(client->mid); - ast_aji_send(client, iq); - } else { - ast_log(LOG_ERROR, "Out of memory.\n"); - } - - iks_delete(iq); - - return res; -} - -/*! - * \brief join a chatroom. - * \param client the configured XMPP client we use to connect to a XMPP server - * \param room room to join - * \param nick the nickname to use in this room - * \return IKS_OK on success, any other value on failure. - */ -int ast_aji_join_chat(struct aji_client *client, char *room, char *nick) -{ - return aji_set_group_presence(client, room, IKS_SHOW_AVAILABLE, nick, NULL); -} - -/*! - * \brief leave a chatroom. - * \param client the configured XMPP client we use to connect to a XMPP server - * \param room room to leave - * \param nick the nickname used in this room - * \return IKS_OK on success, any other value on failure. - */ -int ast_aji_leave_chat(struct aji_client *client, char *room, char *nick) -{ - return aji_set_group_presence(client, room, IKS_SHOW_UNAVAILABLE, nick, NULL); -} -/*! - * \brief invite to a chatroom. - * \param client the configured XMPP client we use to connect to a XMPP server - * \param user - * \param room - * \param message - * \return res. - */ -int ast_aji_invite_chat(struct aji_client *client, char *user, char *room, char *message) -{ - int res = 0; - iks *invite, *body, *namespace; - - invite = iks_new("message"); - body = iks_new("body"); - namespace = iks_new("x"); - if (client && invite && body && namespace) { - iks_insert_attrib(invite, "to", user); - iks_insert_attrib(invite, "id", client->mid); - ast_aji_increment_mid(client->mid); - iks_insert_cdata(body, message, 0); - iks_insert_attrib(namespace, "xmlns", "jabber:x:conference"); - iks_insert_attrib(namespace, "jid", room); - iks_insert_node(invite, body); - iks_insert_node(invite, namespace); - res = ast_aji_send(client, invite); - } else { - ast_log(LOG_ERROR, "Out of memory.\n"); - } - - iks_delete(body); - iks_delete(namespace); - iks_delete(invite); - - return res; -} - -/*! - * \internal - * \brief receive message loop. - * \param data void - * \return void. - */ -static void *aji_recv_loop(void *data) -{ - struct aji_client *client = ASTOBJ_REF((struct aji_client *) data); - int res = IKS_HOOK; - - while (res != IKS_OK) { - ast_debug(3, "JABBER: Connecting.\n"); - res = aji_reconnect(client); - sleep(4); - } - - do { - if (res == IKS_NET_RWERR || client->timeout == 0) { - while (res != IKS_OK) { - ast_debug(3, "JABBER: reconnecting.\n"); - res = aji_reconnect(client); - sleep(4); - } - } - - res = aji_recv(client, 1); - - if (client->state == AJI_DISCONNECTING) { - ast_debug(2, "Ending our Jabber client's thread due to a disconnect\n"); - pthread_exit(NULL); - } - - /* Decrease timeout if no data received, and delete - * old messages globally */ - if (res == IKS_NET_EXPIRED) { - client->timeout--; - delete_old_messages_all(client); - } - if (res == IKS_HOOK) { - ast_log(LOG_WARNING, "JABBER: Got hook event.\n"); - } else if (res == IKS_NET_TLSFAIL) { - ast_log(LOG_ERROR, "JABBER: Failure in TLS.\n"); - } else if (client->timeout == 0 && client->state == AJI_CONNECTED) { - res = client->keepalive ? aji_send_raw(client, " ") : IKS_OK; - if (res == IKS_OK) { - client->timeout = 50; - } else { - ast_log(LOG_WARNING, "JABBER: Network Timeout\n"); - } - } else if (res == IKS_NET_RWERR) { - ast_log(LOG_WARNING, "JABBER: socket read error\n"); - } - } while (client); - ASTOBJ_UNREF(client, ast_aji_client_destroy); - return 0; -} - -/*! - * \brief increments the mid field for messages and other events. - * \param mid char. - * \return void. - */ -void ast_aji_increment_mid(char *mid) -{ - int i = 0; - - for (i = strlen(mid) - 1; i >= 0; i--) { - if (mid[i] != 'z') { - mid[i] = mid[i] + 1; - i = 0; - } else - mid[i] = 'a'; - } -} - -#if 0 -/*! - * \brief attempts to register to a transport. - * \param aji_client struct, and xml packet. - * \return IKS_FILTER_EAT. - */ -/*allows for registering to transport , was too sketch and is out for now. */ -static int aji_register_transport(void *data, ikspak *pak) -{ - struct aji_client *client = ASTOBJ_REF((struct aji_client *) data); - int res = 0; - struct aji_buddy *buddy = NULL; - iks *send = iks_make_iq(IKS_TYPE_GET, "jabber:iq:register"); - - if (client && send) { - ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, { - ASTOBJ_RDLOCK(iterator); - if (iterator->btype == AJI_TRANS) { - buddy = iterator; - } - ASTOBJ_UNLOCK(iterator); - }); - iks_filter_remove_hook(client->f, aji_register_transport); - iks_filter_add_rule(client->f, aji_register_transport2, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_NS, IKS_NS_REGISTER, IKS_RULE_DONE); - iks_insert_attrib(send, "to", buddy->host); - iks_insert_attrib(send, "id", client->mid); - ast_aji_increment_mid(client->mid); - iks_insert_attrib(send, "from", client->user); - res = ast_aji_send(client, send); - } else - ast_log(LOG_ERROR, "Out of memory.\n"); - - if (send) - iks_delete(send); - ASTOBJ_UNREF(client, ast_aji_client_destroy); - return IKS_FILTER_EAT; - -} -/*! - * \brief attempts to register to a transport step 2. - * \param aji_client struct, and xml packet. - * \return IKS_FILTER_EAT. - */ -/* more of the same blob of code, too wonky for now*/ -static int aji_register_transport2(void *data, ikspak *pak) -{ - struct aji_client *client = ASTOBJ_REF((struct aji_client *) data); - int res = 0; - struct aji_buddy *buddy = NULL; - - iks *regiq = iks_new("iq"); - iks *regquery = iks_new("query"); - iks *reguser = iks_new("username"); - iks *regpass = iks_new("password"); - - if (client && regquery && reguser && regpass && regiq) { - ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, { - ASTOBJ_RDLOCK(iterator); - if (iterator->btype == AJI_TRANS) - buddy = iterator; ASTOBJ_UNLOCK(iterator); - }); - iks_filter_remove_hook(client->f, aji_register_transport2); - iks_insert_attrib(regiq, "to", buddy->host); - iks_insert_attrib(regiq, "type", "set"); - iks_insert_attrib(regiq, "id", client->mid); - ast_aji_increment_mid(client->mid); - iks_insert_attrib(regiq, "from", client->user); - iks_insert_attrib(regquery, "xmlns", "jabber:iq:register"); - iks_insert_cdata(reguser, buddy->user, 0); - iks_insert_cdata(regpass, buddy->pass, 0); - iks_insert_node(regiq, regquery); - iks_insert_node(regquery, reguser); - iks_insert_node(regquery, regpass); - res = ast_aji_send(client, regiq); - } else - ast_log(LOG_ERROR, "Out of memory.\n"); - if (regiq) - iks_delete(regiq); - if (regquery) - iks_delete(regquery); - if (reguser) - iks_delete(reguser); - if (regpass) - iks_delete(regpass); - ASTOBJ_UNREF(client, ast_aji_client_destroy); - return IKS_FILTER_EAT; -} -#endif - -/*! - * \internal - * \brief goes through roster and prunes users not needed in list, or adds them accordingly. - * \param client the configured XMPP client we use to connect to a XMPP server - * \return void. - * \note The messages here should be configurable. - */ -static void aji_pruneregister(struct aji_client *client) -{ - iks *removeiq = iks_new("iq"); - iks *removequery = iks_new("query"); - iks *removeitem = iks_new("item"); - iks *send = iks_make_iq(IKS_TYPE_GET, "http://jabber.org/protocol/disco#items"); - if (!client || !removeiq || !removequery || !removeitem || !send) { - ast_log(LOG_ERROR, "Out of memory.\n"); - goto safeout; - } - - iks_insert_node(removeiq, removequery); - iks_insert_node(removequery, removeitem); - ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, { - ASTOBJ_RDLOCK(iterator); - /* For an aji_buddy, both AUTOPRUNE and AUTOREGISTER will never - * be called at the same time */ - if (ast_test_flag(&iterator->flags, AJI_AUTOPRUNE)) { /* If autoprune is set on jabber.conf */ - ast_aji_send(client, iks_make_s10n(IKS_TYPE_UNSUBSCRIBE, iterator->name, - "GoodBye. Your status is no longer needed by Asterisk the Open Source PBX" - " so I am no longer subscribing to your presence.\n")); - ast_aji_send(client, iks_make_s10n(IKS_TYPE_UNSUBSCRIBED, iterator->name, - "GoodBye. You are no longer in the Asterisk config file so I am removing" - " your access to my presence.\n")); - iks_insert_attrib(removeiq, "from", client->jid->full); - iks_insert_attrib(removeiq, "type", "set"); - iks_insert_attrib(removequery, "xmlns", "jabber:iq:roster"); - iks_insert_attrib(removeitem, "jid", iterator->name); - iks_insert_attrib(removeitem, "subscription", "remove"); - ast_aji_send(client, removeiq); - } else if (ast_test_flag(&iterator->flags, AJI_AUTOREGISTER)) { - ast_aji_send(client, iks_make_s10n(IKS_TYPE_SUBSCRIBE, iterator->name, - "Greetings! I am the Asterisk Open Source PBX and I want to subscribe to your presence\n")); - ast_clear_flag(&iterator->flags, AJI_AUTOREGISTER); - } - ASTOBJ_UNLOCK(iterator); - }); - - safeout: - iks_delete(removeiq); - iks_delete(removequery); - iks_delete(removeitem); - iks_delete(send); - - ASTOBJ_CONTAINER_PRUNE_MARKED(&client->buddies, ast_aji_buddy_destroy); -} - -/*! - * \internal - * \brief filters the roster packet we get back from server. - * \param data void - * \param pak ikspak iksemel packet. - * \return IKS_FILTER_EAT. - */ -static int aji_filter_roster(void *data, ikspak *pak) -{ - struct aji_client *client = ASTOBJ_REF((struct aji_client *) data); - int flag = 0; - iks *x = NULL; - struct aji_buddy *buddy; - - client->state = AJI_CONNECTED; - ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, { - ASTOBJ_RDLOCK(iterator); - x = iks_child(pak->query); - flag = 0; - while (x) { - if (!iks_strcmp(iks_name(x), "item")) { - if (!strcasecmp(iterator->name, iks_find_attrib(x, "jid"))) { - flag = 1; - ast_clear_flag(&iterator->flags, AJI_AUTOPRUNE | AJI_AUTOREGISTER); - } - } - x = iks_next(x); - } - if (!flag) { - ast_copy_flags(&iterator->flags, &client->flags, AJI_AUTOREGISTER); - } - iks_delete(x); - - ASTOBJ_UNLOCK(iterator); - }); - - x = iks_child(pak->query); - while (x) { - flag = 0; - if (iks_strcmp(iks_name(x), "item") == 0) { - ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, { - ASTOBJ_RDLOCK(iterator); - if (!strcasecmp(iterator->name, iks_find_attrib(x, "jid"))) - flag = 1; - ASTOBJ_UNLOCK(iterator); - }); - - if (flag) { - /* found buddy, don't create a new one */ - x = iks_next(x); - continue; - } - - buddy = ast_calloc(1, sizeof(*buddy)); - if (!buddy) { - ast_log(LOG_WARNING, "Out of memory\n"); - ASTOBJ_UNREF(client, ast_aji_client_destroy); - return 0; - } - ASTOBJ_INIT(buddy); - ASTOBJ_WRLOCK(buddy); - ast_copy_string(buddy->name, iks_find_attrib(x, "jid"), sizeof(buddy->name)); - ast_clear_flag(&buddy->flags, AST_FLAGS_ALL); - if (ast_test_flag(&client->flags, AJI_AUTOPRUNE)) { - ast_set_flag(&buddy->flags, AJI_AUTOPRUNE); - ASTOBJ_MARK(buddy); - } else if (ast_test_flag(&client->flags, AJI_AUTOREGISTER)) { - if (!iks_strcmp(iks_find_attrib(x, "subscription"), "none") || !iks_strcmp(iks_find_attrib(x, "subscription"), "from")) { - /* subscribe to buddy's presence only - if we really need to */ - ast_set_flag(&buddy->flags, AJI_AUTOREGISTER); - } - } - ASTOBJ_UNLOCK(buddy); - if (buddy) { - ASTOBJ_CONTAINER_LINK(&client->buddies, buddy); - ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy); - } - } - x = iks_next(x); - } - - iks_delete(x); - aji_pruneregister(client); - - ASTOBJ_UNREF(client, ast_aji_client_destroy); - return IKS_FILTER_EAT; -} - -/*! - * \internal - * \brief reconnect to jabber server - * \param client the configured XMPP client we use to connect to a XMPP server - * \return res. -*/ -static int aji_reconnect(struct aji_client *client) -{ - int res = 0; - - if (client->state) { - client->state = AJI_DISCONNECTED; - } - client->timeout = 50; - if (client->p) { - iks_parser_reset(client->p); - } - if (client->authorized) { - client->authorized = 0; - } - - res = aji_initialize(client); - - return res; -} - -/*! - * \internal - * \brief Get the roster of jabber users - * \param client the configured XMPP client we use to connect to a XMPP server - * \return 1. -*/ -static int aji_get_roster(struct aji_client *client) -{ - iks *roster = NULL; - roster = iks_make_iq(IKS_TYPE_GET, IKS_NS_ROSTER); - - if (roster) { - iks_insert_attrib(roster, "id", "roster"); - aji_set_presence(client, NULL, client->jid->full, client->status, client->statusmessage); - ast_aji_send(client, roster); - } - - iks_delete(roster); - - return 1; -} - -/*! - * \internal - * \brief connects as a client to jabber server. - * \param data void - * \param pak ikspak iksemel packet - * \return res. - */ -static int aji_client_connect(void *data, ikspak *pak) -{ - struct aji_client *client = ASTOBJ_REF((struct aji_client *) data); - int res = IKS_FILTER_PASS; - - if (client) { - if (client->state == AJI_DISCONNECTED) { - iks_filter_add_rule(client->f, aji_filter_roster, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, "roster", IKS_RULE_DONE); - client->state = AJI_CONNECTING; - client->jid = (iks_find_cdata(pak->query, "jid")) ? iks_id_new(client->stack, iks_find_cdata(pak->query, "jid")) : client->jid; - if (!client->component) { /*client*/ - aji_get_roster(client); - } - if (client->distribute_events) { - aji_init_event_distribution(client); - } - - iks_filter_remove_hook(client->f, aji_client_connect); - /* Once we remove the hook for this routine, we must return EAT or we will crash or corrupt memory */ - res = IKS_FILTER_EAT; - } - } else { - ast_log(LOG_ERROR, "Out of memory.\n"); - } - - ASTOBJ_UNREF(client, ast_aji_client_destroy); - return res; -} - -/*! - * \internal - * \brief prepares client for connect. - * \param client the configured XMPP client we use to connect to a XMPP server - * \return 1. - */ -static int aji_initialize(struct aji_client *client) -{ - int connected = IKS_NET_NOCONN; - -#ifdef HAVE_OPENSSL - /* reset stream flags */ - client->stream_flags = 0; -#endif - /* If it's a component, connect to user, otherwise, connect to server */ - connected = iks_connect_via(client->p, S_OR(client->serverhost, client->jid->server), client->port, client->component ? client->user : client->jid->server); - - if (connected == IKS_NET_NOCONN) { - ast_log(LOG_ERROR, "JABBER ERROR: No Connection\n"); - return IKS_HOOK; - } else if (connected == IKS_NET_NODNS) { - ast_log(LOG_ERROR, "JABBER ERROR: No DNS %s for client to %s\n", client->name, - S_OR(client->serverhost, client->jid->server)); - return IKS_HOOK; - } - - return IKS_OK; -} - -/*! - * \brief disconnect from jabber server. - * \param client the configured XMPP client we use to connect to a XMPP server - * \return 1. - */ -int ast_aji_disconnect(struct aji_client *client) -{ - if (client) { - ast_verb(4, "JABBER: Disconnecting\n"); -#ifdef HAVE_OPENSSL - if (client->stream_flags & SECURE) { - SSL_shutdown(client->ssl_session); - SSL_CTX_free(client->ssl_context); - SSL_free(client->ssl_session); - } -#endif - iks_disconnect(client->p); - iks_parser_delete(client->p); - ASTOBJ_UNREF(client, ast_aji_client_destroy); - } - - return 1; -} - -/*! - * \brief Callback function for MWI events - * \param ast_event - * \param data void pointer to ast_client structure - * \return void - */ -static void aji_mwi_cb(void *data, struct stasis_subscription *sub, struct stasis_message *msg) -{ - char oldmsgs[10]; - char newmsgs[10]; - struct aji_client *client = data; - struct ast_mwi_state *mwi_state; - - if (!stasis_subscription_is_subscribed(sub) || ast_mwi_state_type() != stasis_message_type(msg)) { - return; - } - - mwi_state = stasis_message_data(msg); - - if (ast_eid_cmp(&ast_eid_default, &mwi_state->eid)) { - /* If the event didn't originate from this server, don't send it back out. */ - return; - } - - snprintf(oldmsgs, sizeof(oldmsgs), "%d", mwi_state->old_msgs); - snprintf(newmsgs, sizeof(newmsgs), "%d", mwi_state->new_msgs); - aji_publish_mwi(client, mwi_state->uniqueid, oldmsgs, newmsgs); -} -/*! - * \brief Callback function for device state events - * \param ast_event - * \param data void pointer to ast_client structure - * \return void - */ -static void aji_devstate_cb(void *data, struct stasis_subscription *sub, struct stasis_message *msg) -{ - struct aji_client *client = data; - struct ast_device_state_message *dev_state; - - if (!stasis_subscription_is_subscribed(sub) || ast_device_state_message_type() != stasis_message_type(msg)) { - return; - } - - dev_state = stasis_message_data(msg); - if (!dev_state->eid || ast_eid_cmp(&ast_eid_default, dev_state->eid)) { - /* If the event is aggregate or didn't originate from this server, don't send it out. */ - return; - } - - aji_publish_device_state(client, dev_state->device, ast_devstate_str(dev_state->state), dev_state->cachable); -} - -static int cached_devstate_cb(void *obj, void *arg, int flags) -{ - struct stasis_message *msg = obj; - struct aji_client *client = arg; - aji_devstate_cb(client, device_state_sub, msg); - return 0; -} - -/*! - * \brief Initialize collections for event distribution - * \param client the configured XMPP client we use to connect to a XMPP server - * \return void - */ -static void aji_init_event_distribution(struct aji_client *client) -{ - if (!mwi_sub) { - mwi_sub = stasis_subscribe(ast_mwi_topic_all(), aji_mwi_cb, client); - } - if (!device_state_sub) { - RAII_VAR(struct ao2_container *, cached, NULL, ao2_cleanup); - device_state_sub = stasis_subscribe(ast_device_state_topic_all(), - aji_devstate_cb, client); - cached = stasis_cache_dump(ast_device_state_cache(), NULL); - ao2_callback(cached, OBJ_NODATA, cached_devstate_cb, client); - } - - aji_pubsub_subscribe(client, "device_state"); - aji_pubsub_subscribe(client, "message_waiting"); - iks_filter_add_rule(client->f, aji_handle_pubsub_event, client, IKS_RULE_TYPE, - IKS_PAK_MESSAGE, IKS_RULE_FROM, client->pubsub_node, IKS_RULE_DONE); - iks_filter_add_rule(client->f, aji_handle_pubsub_error, client, IKS_RULE_TYPE, - IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_ERROR, IKS_RULE_DONE); - -} - -/*! - * \brief Callback for handling PubSub events - * \param data void pointer to aji_client structure - * \param pak A pak - * \return IKS_FILTER_EAT - */ -static int aji_handle_pubsub_event(void *data, ikspak *pak) -{ - char *item_id, *device_state, *mailbox, *cachable_str; - int oldmsgs, newmsgs; - iks *item, *item_content; - struct ast_eid pubsub_eid; - unsigned int cachable = AST_DEVSTATE_CACHABLE; - - item = iks_find(iks_find(iks_find(pak->x, "event"), "items"), "item"); - if (!item) { - ast_log(LOG_ERROR, "Could not parse incoming PubSub event\n"); - return IKS_FILTER_EAT; - } - item_id = iks_find_attrib(item, "id"); - item_content = iks_child(item); - ast_str_to_eid(&pubsub_eid, iks_find_attrib(item_content, "eid")); - if (!ast_eid_cmp(&ast_eid_default, &pubsub_eid)) { - ast_debug(1, "Returning here, eid of incoming event matches ours!\n"); - return IKS_FILTER_EAT; - } - if (!strcasecmp(iks_name(item_content), "state")) { - if ((cachable_str = iks_find_attrib(item_content, "cachable"))) { - sscanf(cachable_str, "%30u", &cachable); - } - device_state = iks_find_cdata(item, "state"); - ast_publish_device_state_full(item_id, - ast_devstate_val(device_state), - cachable == AST_DEVSTATE_CACHABLE ? AST_DEVSTATE_CACHABLE : AST_DEVSTATE_NOT_CACHABLE, - &pubsub_eid); - return IKS_FILTER_EAT; - } else if (!strcasecmp(iks_name(item_content), "mailbox")) { - mailbox = strsep(&item_id, "@"); - sscanf(iks_find_cdata(item_content, "OLDMSGS"), "%10d", &oldmsgs); - sscanf(iks_find_cdata(item_content, "NEWMSGS"), "%10d", &newmsgs); - - ast_publish_mwi_state_full(mailbox, item_id, newmsgs, oldmsgs, NULL, &pubsub_eid); - - return IKS_FILTER_EAT; - } else { - ast_debug(1, "Don't know how to handle PubSub event of type %s\n", - iks_name(item_content)); - return IKS_FILTER_EAT; - } - - return IKS_FILTER_EAT; -} - -/*! - * \brief Add Owner affiliations for pubsub node - * \param client the configured XMPP client we use to connect to a XMPP server - * \param node the name of the node to which to add affiliations - * \return void - */ -static void aji_create_affiliations(struct aji_client *client, const char *node) -{ - iks *modify_affiliates = aji_pubsub_iq_create(client, "set"); - iks *pubsub, *affiliations, *affiliate; - pubsub = iks_insert(modify_affiliates, "pubsub"); - iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub#owner"); - affiliations = iks_insert(pubsub, "affiliations"); - iks_insert_attrib(affiliations, "node", node); - ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, { - ASTOBJ_RDLOCK(iterator); - affiliate = iks_insert(affiliations, "affiliation"); - iks_insert_attrib(affiliate, "jid", iterator->name); - iks_insert_attrib(affiliate, "affiliation", "owner"); - ASTOBJ_UNLOCK(iterator); - }); - ast_aji_send(client, modify_affiliates); - iks_delete(modify_affiliates); -} - -/*! - * \brief Subscribe to a PubSub node - * \param client the configured XMPP client we use to connect to a XMPP server - * \param node the name of the node to which to subscribe - * \return void - */ -static void aji_pubsub_subscribe(struct aji_client *client, const char *node) -{ - iks *request = aji_pubsub_iq_create(client, "set"); - iks *pubsub, *subscribe; - - pubsub = iks_insert(request, "pubsub"); - iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub"); - subscribe = iks_insert(pubsub, "subscribe"); - iks_insert_attrib(subscribe, "jid", client->jid->partial); - iks_insert_attrib(subscribe, "node", node); - if (ast_test_flag(&globalflags, AJI_XEP0248)) { - iks *options, *x, *sub_options, *sub_type, *sub_depth; - options = iks_insert(pubsub, "options"); - x = iks_insert(options, "x"); - iks_insert_attrib(x, "xmlns", "jabber:x:data"); - iks_insert_attrib(x, "type", "submit"); - sub_options = iks_insert(x, "field"); - iks_insert_attrib(sub_options, "var", "FORM_TYPE"); - iks_insert_attrib(sub_options, "type", "hidden"); - iks_insert_cdata(iks_insert(sub_options, "value"), - "http://jabber.org/protocol/pubsub#subscribe_options", 51); - sub_type = iks_insert(x, "field"); - iks_insert_attrib(sub_type, "var", "pubsub#subscription_type"); - iks_insert_cdata(iks_insert(sub_type, "value"), "items", 5); - sub_depth = iks_insert(x, "field"); - iks_insert_attrib(sub_type, "var", "pubsub#subscription_depth"); - iks_insert_cdata(iks_insert(sub_depth, "value"), "all", 3); - } - ast_aji_send(client, request); - iks_delete(request); -} - -/*! - * \brief Build the skeleton of a publish - * \param client the configured XMPP client we use to connect to a XMPP server - * \param node Name of the node that will be published to - * \param event_type - * \return iks * - */ -static iks* aji_build_publish_skeleton(struct aji_client *client, const char *node, - const char *event_type, unsigned int cachable) -{ - iks *request = aji_pubsub_iq_create(client, "set"); - iks *pubsub, *publish, *item; - pubsub = iks_insert(request, "pubsub"); - iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub"); - publish = iks_insert(pubsub, "publish"); - if (ast_test_flag(&globalflags, AJI_XEP0248)) { - iks_insert_attrib(publish, "node", node); - } else { - iks_insert_attrib(publish, "node", event_type); - } - item = iks_insert(publish, "item"); - iks_insert_attrib(item, "id", node); - - if (cachable == AST_DEVSTATE_NOT_CACHABLE) { - iks *options, *x, *field_form_type, *field_persist; - - options = iks_insert(pubsub, "publish-options"); - x = iks_insert(options, "x"); - iks_insert_attrib(x, "xmlns", "jabber:x:data"); - iks_insert_attrib(x, "type", "submit"); - field_form_type = iks_insert(x, "field"); - iks_insert_attrib(field_form_type, "var", "FORM_TYPE"); - iks_insert_attrib(field_form_type, "type", "hidden"); - iks_insert_cdata(iks_insert(field_form_type, "value"), "http://jabber.org/protocol/pubsub#publish-options", 0); - field_persist = iks_insert(x, "field"); - iks_insert_attrib(field_persist, "var", "pubsub#persist_items"); - iks_insert_cdata(iks_insert(field_persist, "value"), "0", 1); - } - - return item; -} - -/*! - * \brief Publish device state to a PubSub node - * \param client the configured XMPP client we use to connect to a XMPP server - * \param device the name of the device whose state to publish - * \param device_state the state to publish - * \return void - */ -static void aji_publish_device_state(struct aji_client *client, const char *device, - const char *device_state, unsigned int cachable) -{ - iks *request = aji_build_publish_skeleton(client, device, "device_state", cachable); - iks *state; - char eid_str[20], cachable_str[2]; - if (ast_test_flag(&pubsubflags, AJI_PUBSUB_AUTOCREATE)) { - if (ast_test_flag(&pubsubflags, AJI_XEP0248)) { - aji_create_pubsub_node(client, "leaf", device, "device_state"); - } else { - aji_create_pubsub_node(client, NULL, device, NULL); - } - } - ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default); - state = iks_insert(request, "state"); - iks_insert_attrib(state, "xmlns", "http://asterisk.org"); - iks_insert_attrib(state, "eid", eid_str); - snprintf(cachable_str, sizeof(cachable_str), "%u", cachable); - iks_insert_attrib(state, "cachable", cachable_str); - iks_insert_cdata(state, device_state, strlen(device_state)); - ast_aji_send(client, iks_root(request)); - iks_delete(request); -} - -/*! - * \brief Publish MWI to a PubSub node - * \param client the configured XMPP client we use to connect to a XMPP server - * \param mailbox The mailbox identifier - * \param oldmsgs Old messages - * \param newmsgs New messages - * \return void - */ -static void aji_publish_mwi(struct aji_client *client, const char *mailbox, - const char *oldmsgs, const char *newmsgs) -{ - char eid_str[20]; - iks *mailbox_node, *request; - - request = aji_build_publish_skeleton(client, mailbox, "message_waiting", 1); - ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default); - mailbox_node = iks_insert(request, "mailbox"); - iks_insert_attrib(mailbox_node, "xmlns", "http://asterisk.org"); - iks_insert_attrib(mailbox_node, "eid", eid_str); - iks_insert_cdata(iks_insert(mailbox_node, "NEWMSGS"), newmsgs, strlen(newmsgs)); - iks_insert_cdata(iks_insert(mailbox_node, "OLDMSGS"), oldmsgs, strlen(oldmsgs)); - ast_aji_send(client, iks_root(request)); - iks_delete(request); -} - -/*! - * \brief Create an IQ packet - * \param client the configured XMPP client we use to connect to a XMPP server - * \param type the type of IQ packet to create - * \return iks* - */ -static iks* aji_pubsub_iq_create(struct aji_client *client, const char *type) -{ - iks *request = iks_new("iq"); - - iks_insert_attrib(request, "to", client->pubsub_node); - iks_insert_attrib(request, "from", client->jid->full); - iks_insert_attrib(request, "type", type); - ast_aji_increment_mid(client->mid); - iks_insert_attrib(request, "id", client->mid); - return request; -} - -static int aji_handle_pubsub_error(void *data, ikspak *pak) -{ - char *node_name; - char *error; - int error_num; - iks *orig_request; - iks *orig_pubsub = iks_find(pak->x, "pubsub"); - struct aji_client *client; - if (!orig_pubsub) { - ast_debug(1, "Error isn't a PubSub error, why are we here?\n"); - return IKS_FILTER_EAT; - } - orig_request = iks_child(orig_pubsub); - error = iks_find_attrib(iks_find(pak->x, "error"), "code"); - node_name = iks_find_attrib(orig_request, "node"); - if (!sscanf(error, "%30d", &error_num)) { - return IKS_FILTER_EAT; - } - if (error_num > 399 && error_num < 500 && error_num != 404) { - ast_log(LOG_ERROR, - "Error performing operation on PubSub node %s, %s.\n", node_name, error); - return IKS_FILTER_EAT; - } else if (error_num > 499 && error_num < 600) { - ast_log(LOG_ERROR, "PubSub Server error, %s\n", error); - return IKS_FILTER_EAT; - } - - client = ASTOBJ_REF((struct aji_client *) data); - - if (!strcasecmp(iks_name(orig_request), "publish")) { - iks *request; - if (ast_test_flag(&pubsubflags, AJI_XEP0248)) { - if (iks_find(iks_find(orig_request, "item"), "state")) { - aji_create_pubsub_leaf(client, "device_state", node_name); - } else if (iks_find(iks_find(orig_request, "item"), "mailbox")) { - aji_create_pubsub_leaf(client, "message_waiting", node_name); - } - } else { - aji_create_pubsub_node(client, NULL, node_name, NULL); - } - request = aji_pubsub_iq_create(client, "set"); - iks_insert_node(request, orig_pubsub); - ast_aji_send(client, request); - iks_delete(request); - ASTOBJ_UNREF(client, ast_aji_client_destroy); - return IKS_FILTER_EAT; - } else if (!strcasecmp(iks_name(orig_request), "subscribe")) { - if (ast_test_flag(&pubsubflags, AJI_XEP0248)) { - aji_create_pubsub_collection(client, node_name); - } else { - aji_create_pubsub_node(client, NULL, node_name, NULL); - } - } - ASTOBJ_UNREF(client, ast_aji_client_destroy); - return IKS_FILTER_EAT; -} - -/*! - * \brief Request item list from pubsub - * \param client the configured XMPP client we use to connect to a XMPP server - * \param collection name of the collection for request - * \return void - */ -static void aji_request_pubsub_nodes(struct aji_client *client, const char *collection) -{ - iks *request = aji_build_node_request(client, collection); - - iks_filter_add_rule(client->f, aji_receive_node_list, client, IKS_RULE_TYPE, - IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, client->mid, - IKS_RULE_DONE); - ast_aji_send(client, request); - iks_delete(request); - -} - -/*! - * \brief Build the a node request - * \param client the configured XMPP client we use to connect to a XMPP server - * \param collection name of the collection for request - * \return iks* - */ -static iks* aji_build_node_request(struct aji_client *client, const char *collection) -{ - iks *request = aji_pubsub_iq_create(client, "get"); - iks *query; - query = iks_insert(request, "query"); - iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items"); - if (collection) { - iks_insert_attrib(query, "node", collection); - } - return request; -} - -/*! - * \brief Receive pubsub item lists - * \param data pointer to aji_client structure - * \param pak response from pubsub diso#items query - * \return IKS_FILTER_EAT - */ -static int aji_receive_node_list(void *data, ikspak* pak) -{ - - struct aji_client *client = ASTOBJ_REF((struct aji_client *) data); - iks *item = NULL; - if (iks_has_children(pak->query)) { - item = iks_first_tag(pak->query); - ast_verbose("Connection %s: %s\nNode name: %s\n", client->name, client->jid->partial, - iks_find_attrib(item, "node")); - while ((item = iks_next_tag(item))) { - ast_verbose("Node name: %s\n", iks_find_attrib(item, "node")); - } - } - if (item) { - iks_delete(item); - } - ASTOBJ_UNREF(client, ast_aji_client_destroy); - return IKS_FILTER_EAT; -} - - -/*! - * \brief Method to expose PubSub node list via CLI. - * \param e pointer to ast_cli_entry structure - * \param cmd - * \param a pointer to ast_cli_args structure - * \return char * - */ -static char *aji_cli_list_pubsub_nodes(struct ast_cli_entry *e, int cmd, struct -ast_cli_args *a) -{ - struct aji_client *client; - const char *name = NULL; - const char *collection = NULL; - - switch (cmd) { - case CLI_INIT: - e->command = "jabber list nodes"; - e->usage = - "Usage: jabber list nodes [collection]\n" - " Lists the user's nodes on the respective connection\n" - " ([connection] as configured in jabber.conf.)\n"; - return NULL; - case CLI_GENERATE: - return NULL; - } - - if (a->argc > 5 || a->argc < 4) { - return CLI_SHOWUSAGE; - } else if (a->argc == 4 || a->argc == 5) { - name = a->argv[3]; - } - if (a->argc == 5) { - collection = a->argv[4]; - } - if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) { - ast_cli(a->fd, "Unable to find client '%s'!\n", name); - return CLI_FAILURE; - } - - ast_cli(a->fd, "Listing pubsub nodes.\n"); - aji_request_pubsub_nodes(client, collection); - ASTOBJ_UNREF(client, ast_aji_client_destroy); - return CLI_SUCCESS; -} - -/*! - * \brief Method to purge PubSub nodes via CLI. - * \param e pointer to ast_cli_entry structure - * \param cmd - * \param a pointer to ast_cli_args structure - * \return char * - */ -static char *aji_cli_purge_pubsub_nodes(struct ast_cli_entry *e, int cmd, struct - ast_cli_args *a) -{ - struct aji_client *client; - const char *name; - - switch (cmd) { - case CLI_INIT: - e->command = "jabber purge nodes"; - e->usage = - "Usage: jabber purge nodes \n" - " Purges nodes on PubSub server\n" - " as configured in jabber.conf.\n"; - return NULL; - case CLI_GENERATE: - return NULL; - } - - if (a->argc != 5) { - return CLI_SHOWUSAGE; - } - name = a->argv[3]; - - if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) { - ast_cli(a->fd, "Unable to find client '%s'!\n", name); - return CLI_FAILURE; - } - if (ast_test_flag(&pubsubflags, AJI_XEP0248)) { - aji_pubsub_purge_nodes(client, a->argv[4]); - } else { - aji_delete_pubsub_node(client, a->argv[4]); - } - ASTOBJ_UNREF(client, ast_aji_client_destroy); - return CLI_SUCCESS; -} - -static void aji_pubsub_purge_nodes(struct aji_client *client, const char* collection_name) -{ - iks *request = aji_build_node_request(client, collection_name); - ast_aji_send(client, request); - iks_filter_add_rule(client->f, aji_delete_node_list, client, IKS_RULE_TYPE, - IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, client->mid, - IKS_RULE_DONE); - ast_aji_send(client, request); - iks_delete(request); -} - -/*! - * \brief Delete pubsub item lists - * \param data pointer to aji_client structure - * \param pak response from pubsub diso#items query - * \return IKS_FILTER_EAT - */ -static int aji_delete_node_list(void *data, ikspak* pak) -{ - - struct aji_client *client = ASTOBJ_REF((struct aji_client *) data); - iks *item = NULL; - if (iks_has_children(pak->query)) { - item = iks_first_tag(pak->query); - ast_log(LOG_WARNING, "Connection: %s Node name: %s\n", client->jid->partial, - iks_find_attrib(item, "node")); - while ((item = iks_next_tag(item))) { - aji_delete_pubsub_node(client, iks_find_attrib(item, "node")); - } - } - if (item) { - iks_delete(item); - } - return IKS_FILTER_EAT; -} - - -/*! - * \brief Method to expose PubSub node deletion via CLI. - * \param e pointer to ast_cli_entry structure - * \param cmd - * \param a pointer to ast_cli_args structure - * \return char * - */ -static char *aji_cli_delete_pubsub_node(struct ast_cli_entry *e, int cmd, struct - ast_cli_args *a) -{ - struct aji_client *client; - const char *name; - - switch (cmd) { - case CLI_INIT: - e->command = "jabber delete node"; - e->usage = - "Usage: jabber delete node \n" - " Deletes a node on PubSub server\n" - " as configured in jabber.conf.\n"; - return NULL; - case CLI_GENERATE: - return NULL; - } - - if (a->argc != 5) { - return CLI_SHOWUSAGE; - } - name = a->argv[3]; - - if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) { - ast_cli(a->fd, "Unable to find client '%s'!\n", name); - return CLI_FAILURE; - } - aji_delete_pubsub_node(client, a->argv[4]); - ASTOBJ_UNREF(client, ast_aji_client_destroy); - return CLI_SUCCESS; -} - -/*! - * \brief Delete a PubSub node - * \param client the configured XMPP client we use to connect to a XMPP server - * \param node_name the name of the node to delete - * return void - */ -static void aji_delete_pubsub_node(struct aji_client *client, const char *node_name) -{ - iks *request = aji_pubsub_iq_create(client, "set"); - iks *pubsub, *delete; - pubsub = iks_insert(request, "pubsub"); - iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub#owner"); - delete = iks_insert(pubsub, "delete"); - iks_insert_attrib(delete, "node", node_name); - ast_aji_send(client, request); -} - -/*! - * \brief Create a PubSub collection node. - * \param client the configured XMPP client we use to connect to a XMPP server - * \param collection_name The name to use for this collection - * \return void. - */ -static void aji_create_pubsub_collection(struct aji_client *client, const char -*collection_name) -{ - aji_create_pubsub_node(client, "collection", collection_name, NULL); -} - - -/*! - * \brief Create a PubSub leaf node. - * \param client the configured XMPP client we use to connect to a XMPP server - * \param collection_name The name to use for this collection - * \param leaf_name The name to use for this collection - * \return void. - */ -static void aji_create_pubsub_leaf(struct aji_client *client, const char *collection_name, -const char *leaf_name) -{ - aji_create_pubsub_node(client, "leaf", leaf_name, collection_name); -} - -/*! - * \brief Create a pubsub node - * \param client the configured XMPP client we use to connect to a XMPP server - * \param node_type the type of node to create - * \param name the name of the node to create - * \param collection_name The name to use for this collection - * \return iks* - */ -static iks* aji_create_pubsub_node(struct aji_client *client, const char *node_type, const - char *name, const char *collection_name) -{ - iks *node = aji_pubsub_iq_create(client, "set"); - iks *pubsub, *create; - pubsub = iks_insert(node, "pubsub"); - iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub"); - create = iks_insert(pubsub, "create"); - iks_insert_attrib(create, "node", name); - aji_build_node_config(pubsub, node_type, collection_name); - ast_aji_send(client, node); - aji_create_affiliations(client, name); - iks_delete(node); - return 0; -} - - - -static iks* aji_build_node_config(iks *pubsub, const char *node_type, const char *collection_name) -{ - iks *configure, *x, *field_owner, *field_node_type, *field_node_config, - *field_deliver_payload, *field_persist_items, *field_access_model, - *field_pubsub_collection; - configure = iks_insert(pubsub, "configure"); - x = iks_insert(configure, "x"); - iks_insert_attrib(x, "xmlns", "jabber:x:data"); - iks_insert_attrib(x, "type", "submit"); - field_owner = iks_insert(x, "field"); - iks_insert_attrib(field_owner, "var", "FORM_TYPE"); - iks_insert_attrib(field_owner, "type", "hidden"); - iks_insert_cdata(iks_insert(field_owner, "value"), - "http://jabber.org/protocol/pubsub#owner", 39); - if (node_type) { - field_node_type = iks_insert(x, "field"); - iks_insert_attrib(field_node_type, "var", "pubsub#node_type"); - iks_insert_cdata(iks_insert(field_node_type, "value"), node_type, strlen(node_type)); - } - field_node_config = iks_insert(x, "field"); - iks_insert_attrib(field_node_config, "var", "FORM_TYPE"); - iks_insert_attrib(field_node_config, "type", "hidden"); - iks_insert_cdata(iks_insert(field_node_config, "value"), - "http://jabber.org/protocol/pubsub#node_config", 45); - field_deliver_payload = iks_insert(x, "field"); - iks_insert_attrib(field_deliver_payload, "var", "pubsub#deliver_payloads"); - iks_insert_cdata(iks_insert(field_deliver_payload, "value"), "1", 1); - field_persist_items = iks_insert(x, "field"); - iks_insert_attrib(field_persist_items, "var", "pubsub#persist_items"); - iks_insert_cdata(iks_insert(field_persist_items, "value"), "1", 1); - field_access_model = iks_insert(x, "field"); - iks_insert_attrib(field_access_model, "var", "pubsub#access_model"); - iks_insert_cdata(iks_insert(field_access_model, "value"), "whitelist", 9); - if (node_type && !strcasecmp(node_type, "leaf")) { - field_pubsub_collection = iks_insert(x, "field"); - iks_insert_attrib(field_pubsub_collection, "var", "pubsub#collection"); - iks_insert_cdata(iks_insert(field_pubsub_collection, "value"), collection_name, - strlen(collection_name)); - } - return configure; -} - - - -/*! - * \brief Method to expose PubSub collection node creation via CLI. - * \return char *. - */ -static char *aji_cli_create_collection(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) -{ - struct aji_client *client; - const char *name; - const char *collection_name; - - switch (cmd) { - case CLI_INIT: - e->command = "jabber create collection"; - e->usage = - "Usage: jabber create collection \n" - " Creates a PubSub collection node using the account\n" - " as configured in jabber.conf.\n"; - return NULL; - case CLI_GENERATE: - return NULL; - } - - if (a->argc != 5) { - return CLI_SHOWUSAGE; - } - name = a->argv[3]; - collection_name = a->argv[4]; - - if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) { - ast_cli(a->fd, "Unable to find client '%s'!\n", name); - return CLI_FAILURE; - } - - ast_cli(a->fd, "Creating test PubSub node collection.\n"); - aji_create_pubsub_collection(client, collection_name); - ASTOBJ_UNREF(client, ast_aji_client_destroy); - return CLI_SUCCESS; -} - -/*! - * \brief Method to expose PubSub leaf node creation via CLI. - * \return char *. - */ -static char *aji_cli_create_leafnode(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) -{ - struct aji_client *client; - const char *name; - const char *collection_name; - const char *leaf_name; - - switch (cmd) { - case CLI_INIT: - e->command = "jabber create leaf"; - e->usage = - "Usage: jabber create leaf \n" - " Creates a PubSub leaf node using the account\n" - " as configured in jabber.conf.\n"; - return NULL; - case CLI_GENERATE: - return NULL; - } - - if (a->argc != 6) { - return CLI_SHOWUSAGE; - } - name = a->argv[3]; - collection_name = a->argv[4]; - leaf_name = a->argv[5]; - - if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) { - ast_cli(a->fd, "Unable to find client '%s'!\n", name); - return CLI_FAILURE; - } - - ast_cli(a->fd, "Creating test PubSub node collection.\n"); - aji_create_pubsub_leaf(client, collection_name, leaf_name); - ASTOBJ_UNREF(client, ast_aji_client_destroy); - return CLI_SUCCESS; -} - - - -/*! - * \internal - * \brief set presence of client. - * \param client the configured XMPP client we use to connect to a XMPP server - * \param to user send it to - * \param from user it came from - * \param level - * \param desc - * \return void. - */ -static void aji_set_presence(struct aji_client *client, char *to, char *from, int level, char *desc) -{ - iks *presence = iks_make_pres(level, desc); - iks *cnode = iks_new("c"); - iks *priority = iks_new("priority"); - char priorityS[10]; - - if (presence && cnode && client && priority) { - if (to) { - iks_insert_attrib(presence, "to", to); - } - if (from) { - iks_insert_attrib(presence, "from", from); - } - snprintf(priorityS, sizeof(priorityS), "%d", client->priority); - iks_insert_cdata(priority, priorityS, strlen(priorityS)); - iks_insert_node(presence, priority); - iks_insert_attrib(cnode, "node", "http://www.asterisk.org/xmpp/client/caps"); - iks_insert_attrib(cnode, "ver", "asterisk-xmpp"); - iks_insert_attrib(cnode, "ext", "voice-v1"); - iks_insert_attrib(cnode, "xmlns", "http://jabber.org/protocol/caps"); - iks_insert_node(presence, cnode); - ast_aji_send(client, presence); - } else { - ast_log(LOG_ERROR, "Out of memory.\n"); - } - - iks_delete(cnode); - iks_delete(presence); - iks_delete(priority); -} - -/* -* \brief set the presence of the client in a groupchat context. -* \param client the configured XMPP client we use to connect to a XMPP server -* \param room the groupchat identifier in the from roomname@service -* \param from user it came from -* \param level the type of action, i.e. join or leave the chatroom -* \param nick the nickname to use in the chatroom -* \param desc a text that details the action to be taken -* \return res. -*/ -static int aji_set_group_presence(struct aji_client *client, char *room, int level, char *nick, char *desc) -{ - int res = 0; - iks *presence = NULL, *x = NULL; - char from[AJI_MAX_JIDLEN]; - char roomid[AJI_MAX_JIDLEN]; - - presence = iks_make_pres(level, NULL); - x = iks_new("x"); - - if (client->component) { - snprintf(from, AJI_MAX_JIDLEN, "%s@%s/%s", nick, client->jid->full, nick); - snprintf(roomid, AJI_MAX_JIDLEN, "%s/%s", room, nick); - } else { - snprintf(from, AJI_MAX_JIDLEN, "%s", client->jid->full); - snprintf(roomid, AJI_MAX_JIDLEN, "%s/%s", room, nick ? nick : client->jid->user); - } - - if (!presence || !x || !client) { - ast_log(LOG_ERROR, "Out of memory.\n"); - res = -1; - goto safeout; - } else { - iks_insert_attrib(presence, "to", roomid); - iks_insert_attrib(presence, "from", from); - iks_insert_attrib(x, "xmlns", MUC_NS); - iks_insert_node(presence, x); - res = ast_aji_send(client, presence); - } - -safeout: - iks_delete(presence); - iks_delete(x); - return res; -} - -/*! - * \internal - * \brief Turn on/off console debugging. - * \return CLI_SUCCESS. - */ -static char *aji_do_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) -{ - switch (cmd) { - case CLI_INIT: - e->command = "jabber set debug {on|off}"; - e->usage = - "Usage: jabber set debug {on|off}\n" - " Enables/disables dumping of XMPP/Jabber packets for debugging purposes.\n"; - return NULL; - case CLI_GENERATE: - return NULL; - } - - if (a->argc != e->args) { - return CLI_SHOWUSAGE; - } - - if (!strncasecmp(a->argv[e->args - 1], "on", 2)) { - ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, { - ASTOBJ_RDLOCK(iterator); - iterator->debug = 1; - ASTOBJ_UNLOCK(iterator); - }); - ast_cli(a->fd, "Jabber Debugging Enabled.\n"); - return CLI_SUCCESS; - } else if (!strncasecmp(a->argv[e->args - 1], "off", 3)) { - ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, { - ASTOBJ_RDLOCK(iterator); - iterator->debug = 0; - ASTOBJ_UNLOCK(iterator); - }); - ast_cli(a->fd, "Jabber Debugging Disabled.\n"); - return CLI_SUCCESS; - } - return CLI_SHOWUSAGE; /* defaults to invalid */ -} - -/*! - * \internal - * \brief Reload jabber module. - * \return CLI_SUCCESS. - */ -static char *aji_do_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) -{ - switch (cmd) { - case CLI_INIT: - e->command = "jabber reload"; - e->usage = - "Usage: jabber reload\n" - " Reloads the Jabber module.\n"; - return NULL; - case CLI_GENERATE: - return NULL; - } - - aji_reload(1); - ast_cli(a->fd, "Jabber Reloaded.\n"); - return CLI_SUCCESS; -} - -/*! - * \internal - * \brief Show client status. - * \return CLI_SUCCESS. - */ -static char *aji_show_clients(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) -{ - char *status; - int count = 0; - - switch (cmd) { - case CLI_INIT: - e->command = "jabber show connections"; - e->usage = - "Usage: jabber show connections\n" - " Shows state of client and component connections\n"; - return NULL; - case CLI_GENERATE: - return NULL; - } - - ast_cli(a->fd, "Jabber Users and their status:\n"); - ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, { - ASTOBJ_RDLOCK(iterator); - count++; - switch (iterator->state) { - case AJI_DISCONNECTED: - status = "Disconnected"; - break; - case AJI_CONNECTING: - status = "Connecting"; - break; - case AJI_CONNECTED: - status = "Connected"; - break; - default: - status = "Unknown"; - } - ast_cli(a->fd, " [%s] %s - %s\n", iterator->name, iterator->user, status); - ASTOBJ_UNLOCK(iterator); - }); - ast_cli(a->fd, "----\n"); - ast_cli(a->fd, " Number of users: %d\n", count); - return CLI_SUCCESS; -} - -/*! - * \internal - * \brief Show buddy lists - * \return CLI_SUCCESS. - */ -static char *aji_show_buddies(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) -{ - struct aji_resource *resource; - struct aji_client *client; - - switch (cmd) { - case CLI_INIT: - e->command = "jabber show buddies"; - e->usage = - "Usage: jabber show buddies\n" - " Shows buddy lists of our clients\n"; - return NULL; - case CLI_GENERATE: - return NULL; - } - - ast_cli(a->fd, "Jabber buddy lists\n"); - ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, { - ast_cli(a->fd, "Client: %s\n", iterator->user); - client = iterator; - ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, { - ASTOBJ_RDLOCK(iterator); - ast_cli(a->fd, "\tBuddy:\t%s\n", iterator->name); - if (!iterator->resources) - ast_cli(a->fd, "\t\tResource: None\n"); - for (resource = iterator->resources; resource; resource = resource->next) { - ast_cli(a->fd, "\t\tResource: %s\n", resource->resource); - if (resource->cap) { - ast_cli(a->fd, "\t\t\tnode: %s\n", resource->cap->parent->node); - ast_cli(a->fd, "\t\t\tversion: %s\n", resource->cap->version); - ast_cli(a->fd, "\t\t\tJingle capable: %s\n", resource->cap->jingle ? "yes" : "no"); - } - ast_cli(a->fd, "\t\tStatus: %d\n", resource->status); - ast_cli(a->fd, "\t\tPriority: %d\n", resource->priority); - } - ASTOBJ_UNLOCK(iterator); - }); - iterator = client; - }); - return CLI_SUCCESS; -} - -/*! - * \internal - * \brief creates aji_client structure. - * \param label - * \param var ast_variable - * \param debug - * \return 0. - */ -static int aji_create_client(char *label, struct ast_variable *var, int debug) -{ - char *resource; - struct aji_client *client = NULL; - int flag = 0; - - client = ASTOBJ_CONTAINER_FIND(&clients, label); - if (!client) { - flag = 1; - client = ast_calloc(1, sizeof(*client)); - if (!client) { - ast_log(LOG_ERROR, "Out of memory!\n"); - return 0; - } - ASTOBJ_INIT(client); - ASTOBJ_WRLOCK(client); - ASTOBJ_CONTAINER_INIT(&client->buddies); - } else { - ASTOBJ_WRLOCK(client); - ASTOBJ_UNMARK(client); - } - ASTOBJ_CONTAINER_MARKALL(&client->buddies); - ast_copy_string(client->name, label, sizeof(client->name)); - ast_copy_string(client->mid, "aaaaa", sizeof(client->mid)); - ast_copy_string(client->context, "default", sizeof(client->context)); - - /* Set default values for the client object */ - client->debug = debug; - ast_copy_flags(&client->flags, &globalflags, AST_FLAGS_ALL); - client->port = 5222; - client->usetls = 1; - client->usesasl = 1; - client->forcessl = 0; - client->keepalive = 1; - client->timeout = 50; - client->message_timeout = 5; - client->distribute_events = 0; - AST_LIST_HEAD_INIT(&client->messages); - client->component = 0; - ast_copy_string(client->statusmessage, "Online and Available", sizeof(client->statusmessage)); - client->priority = 0; - client->status = IKS_SHOW_AVAILABLE; - client->send_to_dialplan = 0; - - if (flag) { - client->authorized = 0; - client->state = AJI_DISCONNECTED; - } - while (var) { - if (!strcasecmp(var->name, "username")) { - ast_copy_string(client->user, var->value, sizeof(client->user)); - } else if (!strcasecmp(var->name, "serverhost")) { - ast_copy_string(client->serverhost, var->value, sizeof(client->serverhost)); - } else if (!strcasecmp(var->name, "secret")) { - ast_copy_string(client->password, var->value, sizeof(client->password)); - } else if (!strcasecmp(var->name, "statusmessage")) { - ast_copy_string(client->statusmessage, var->value, sizeof(client->statusmessage)); - } else if (!strcasecmp(var->name, "port")) { - client->port = atoi(var->value); - } else if (!strcasecmp(var->name, "timeout")) { - client->message_timeout = atoi(var->value); - } else if (!strcasecmp(var->name, "debug")) { - client->debug = (ast_false(var->value)) ? 0 : 1; - } else if (!strcasecmp(var->name, "type")) { - if (!strcasecmp(var->value, "component")) { - client->component = 1; - if (client->distribute_events) { - ast_log(LOG_ERROR, "Client cannot be configured to be both a component and to distribute events! Event distribution will be disabled.\n"); - client->distribute_events = 0; - } - } - } else if (!strcasecmp(var->name, "distribute_events")) { - if (ast_true(var->value)) { - if (client->component) { - ast_log(LOG_ERROR, "Client cannot be configured to be both a component and to distribute events! Event distribution will be disabled.\n"); - } else { - if (ast_test_flag(&pubsubflags, AJI_PUBSUB)) { - ast_log(LOG_ERROR, "Only one connection can be configured for distributed events.\n"); - } else { - ast_set_flag(&pubsubflags, AJI_PUBSUB); - client->distribute_events = 1; - } - } - } - } else if (!strcasecmp(var->name, "pubsub_node")) { - ast_copy_string(client->pubsub_node, var->value, sizeof(client->pubsub_node)); - } else if (!strcasecmp(var->name, "usetls")) { - client->usetls = (ast_false(var->value)) ? 0 : 1; - } else if (!strcasecmp(var->name, "usesasl")) { - client->usesasl = (ast_false(var->value)) ? 0 : 1; - } else if (!strcasecmp(var->name, "forceoldssl")) { - client->forcessl = (ast_false(var->value)) ? 0 : 1; - } else if (!strcasecmp(var->name, "keepalive")) { - client->keepalive = (ast_false(var->value)) ? 0 : 1; - } else if (!strcasecmp(var->name, "autoprune")) { - ast_set2_flag(&client->flags, ast_true(var->value), AJI_AUTOPRUNE); - } else if (!strcasecmp(var->name, "autoregister")) { - ast_set2_flag(&client->flags, ast_true(var->value), AJI_AUTOREGISTER); - } else if (!strcasecmp(var->name, "auth_policy")) { - if (!strcasecmp(var->value, "accept")) { - ast_set_flag(&client->flags, AJI_AUTOACCEPT); - } else { - ast_clear_flag(&client->flags, AJI_AUTOACCEPT); - } - } else if (!strcasecmp(var->name, "buddy")) { - aji_create_buddy((char *)var->value, client); - } else if (!strcasecmp(var->name, "priority")) { - client->priority = atoi(var->value); - } else if (!strcasecmp(var->name, "status")) { - if (!strcasecmp(var->value, "unavailable")) { - client->status = IKS_SHOW_UNAVAILABLE; - } else if (!strcasecmp(var->value, "available") - || !strcasecmp(var->value, "online")) { - client->status = IKS_SHOW_AVAILABLE; - } else if (!strcasecmp(var->value, "chat") - || !strcasecmp(var->value, "chatty")) { - client->status = IKS_SHOW_CHAT; - } else if (!strcasecmp(var->value, "away")) { - client->status = IKS_SHOW_AWAY; - } else if (!strcasecmp(var->value, "xa") - || !strcasecmp(var->value, "xaway")) { - client->status = IKS_SHOW_XA; - } else if (!strcasecmp(var->value, "dnd")) { - client->status = IKS_SHOW_DND; - } else if (!strcasecmp(var->value, "invisible")) { - #ifdef IKS_SHOW_INVISIBLE - client->status = IKS_SHOW_INVISIBLE; - #else - ast_log(LOG_WARNING, "Your iksemel doesn't support invisible status: falling back to DND\n"); - client->status = IKS_SHOW_DND; - #endif - } else { - ast_log(LOG_WARNING, "Unknown presence status: %s\n", var->value); - } - } else if (!strcasecmp(var->name, "context")) { - ast_copy_string(client->context, var->value, sizeof(client->context)); - } else if (!strcasecmp(var->name, "sendtodialplan")) { - client->send_to_dialplan = ast_true(var->value) ? 1 : 0; - } - /* no transport support in this version */ - /* else if (!strcasecmp(var->name, "transport")) - aji_create_transport(var->value, client); - */ - var = var->next; - } - if (!flag) { - ASTOBJ_UNLOCK(client); - ASTOBJ_UNREF(client, ast_aji_client_destroy); - return 1; - } - - ast_copy_string(client->name_space, (client->component) ? "jabber:component:accept" : "jabber:client", sizeof(client->name_space)); - client->p = iks_stream_new(client->name_space, client, aji_act_hook); - if (!client->p) { - ast_log(LOG_ERROR, "Failed to create stream for client '%s'!\n", client->name); - return 0; - } - client->stack = iks_stack_new(8192, 8192); - if (!client->stack) { - ast_log(LOG_ERROR, "Failed to allocate stack for client '%s'\n", client->name); - return 0; - } - client->f = iks_filter_new(); - if (!client->f) { - ast_log(LOG_ERROR, "Failed to create filter for client '%s'\n", client->name); - return 0; - } - if (!strchr(client->user, '/') && !client->component) { /*client */ - if (ast_asprintf(&resource, "%s/asterisk", client->user) >= 0) { - client->jid = iks_id_new(client->stack, resource); - ast_free(resource); - } - } else { - client->jid = iks_id_new(client->stack, client->user); - } - if (client->component) { - iks_filter_add_rule(client->f, aji_dinfo_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE); - iks_filter_add_rule(client->f, aji_ditems_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#items", IKS_RULE_DONE); - iks_filter_add_rule(client->f, aji_register_query_handler, client, IKS_RULE_SUBTYPE, IKS_TYPE_GET, IKS_RULE_NS, "jabber:iq:register", IKS_RULE_DONE); - iks_filter_add_rule(client->f, aji_register_approve_handler, client, IKS_RULE_SUBTYPE, IKS_TYPE_SET, IKS_RULE_NS, "jabber:iq:register", IKS_RULE_DONE); - } else { - iks_filter_add_rule(client->f, aji_client_info_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE); - } - - iks_set_log_hook(client->p, aji_log_hook); - ASTOBJ_UNLOCK(client); - ASTOBJ_CONTAINER_LINK(&clients, client); - return 1; -} - - - -#if 0 -/*! - * \brief creates transport. - * \param label, buddy to dump it into. - * \return 0. - */ -/* no connecting to transports today */ -static int aji_create_transport(char *label, struct aji_client *client) -{ - char *server = NULL, *buddyname = NULL, *user = NULL, *pass = NULL; - struct aji_buddy *buddy = NULL; - int needs_unref = 1; - - buddy = ASTOBJ_CONTAINER_FIND(&client->buddies,label); - if (!buddy) { - needs_unref = 0; - buddy = ast_calloc(1, sizeof(*buddy)); - if (!buddy) { - ast_log(LOG_WARNING, "Out of memory\n"); - return 0; - } - ASTOBJ_INIT(buddy); - } - ASTOBJ_WRLOCK(buddy); - server = label; - if ((buddyname = strchr(label, ','))) { - *buddyname = '\0'; - buddyname++; - if (buddyname && buddyname[0] != '\0') { - if ((user = strchr(buddyname, ','))) { - *user = '\0'; - user++; - if (user && user[0] != '\0') { - if ((pass = strchr(user, ','))) { - *pass = '\0'; - pass++; - ast_copy_string(buddy->pass, pass, sizeof(buddy->pass)); - ast_copy_string(buddy->user, user, sizeof(buddy->user)); - ast_copy_string(buddy->name, buddyname, sizeof(buddy->name)); - ast_copy_string(buddy->server, server, sizeof(buddy->server)); - if (needs_unref) { - ASTOBJ_UNMARK(buddy); - ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy); - } - return 1; - } - } - } - } - } - ASTOBJ_UNLOCK(buddy); - if (needs_unref) { - ASTOBJ_UNMARK(buddy); - ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy); - } else { - ASTOBJ_CONTAINER_LINK(&client->buddies, buddy); - } - return 0; -} -#endif - -/*! - * \internal - * \brief creates buddy. - * \param label char. - * \param client the configured XMPP client we use to connect to a XMPP server - * \return 1 on success, 0 on failure. - */ -static int aji_create_buddy(char *label, struct aji_client *client) -{ - struct aji_buddy *buddy = NULL; - int needs_unref = 1; - buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, label); - if (!buddy) { - needs_unref = 0; - buddy = ast_calloc(1, sizeof(*buddy)); - if (!buddy) { - ast_log(LOG_WARNING, "Out of memory\n"); - return 0; - } - ASTOBJ_INIT(buddy); - } - ASTOBJ_WRLOCK(buddy); - ast_copy_string(buddy->name, label, sizeof(buddy->name)); - ASTOBJ_UNLOCK(buddy); - if (needs_unref) { - ASTOBJ_UNMARK(buddy); - ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy); - } else { - ASTOBJ_CONTAINER_LINK(&client->buddies, buddy); - } - return 1; -} - -/*!< load config file. \return 1. */ -static int aji_load_config(int reload) -{ - char *cat = NULL; - int debug = 0; - struct ast_config *cfg = NULL; - struct ast_variable *var = NULL; - struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; - - if ((cfg = ast_config_load(JABBER_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) { - return -1; - } - - /* Reset flags to default value */ - ast_set_flag(&globalflags, AJI_AUTOREGISTER | AJI_AUTOACCEPT); - - if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) { - ast_log(LOG_WARNING, "No such configuration file %s\n", JABBER_CONFIG); - return 0; - } - - cat = ast_category_browse(cfg, NULL); - for (var = ast_variable_browse(cfg, "general"); var; var = var->next) { - if (!strcasecmp(var->name, "debug")) { - debug = (ast_false(ast_variable_retrieve(cfg, "general", "debug"))) ? 0 : 1; - } else if (!strcasecmp(var->name, "autoprune")) { - ast_set2_flag(&globalflags, ast_true(var->value), AJI_AUTOPRUNE); - } else if (!strcasecmp(var->name, "autoregister")) { - ast_set2_flag(&globalflags, ast_true(var->value), AJI_AUTOREGISTER); - } else if (!strcasecmp(var->name, "collection_nodes")) { - ast_set2_flag(&pubsubflags, ast_true(var->value), AJI_XEP0248); - } else if (!strcasecmp(var->name, "pubsub_autocreate")) { - ast_set2_flag(&pubsubflags, ast_true(var->value), AJI_PUBSUB_AUTOCREATE); - } else if (!strcasecmp(var->name, "auth_policy")) { - if (!strcasecmp(var->value, "accept")) { - ast_set_flag(&globalflags, AJI_AUTOACCEPT); - } else { - ast_clear_flag(&globalflags, AJI_AUTOACCEPT); - } - } - } - - while (cat) { - if (strcasecmp(cat, "general")) { - var = ast_variable_browse(cfg, cat); - aji_create_client(cat, var, debug); - } - cat = ast_category_browse(cfg, cat); - } - ast_config_destroy(cfg); /* or leak memory */ - return 1; -} - -/*! - * \brief grab a aji_client structure by label name or JID. Bumps the refcount. - * (without the resource string) - * \param name label or JID - * \return aji_client. - */ -struct aji_client *ast_aji_get_client(const char *name) -{ - struct aji_client *client = NULL; - char *aux = NULL; - - client = ASTOBJ_CONTAINER_FIND(&clients, name); - if (!client && strchr(name, '@')) { - ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, { - aux = ast_strdupa(iterator->user); - if (strchr(aux, '/')) { - /* strip resource for comparison */ - aux = strsep(&aux, "/"); - } - if (!strncasecmp(aux, name, strlen(aux))) { - client = ASTOBJ_REF(iterator); - } - }); - } - - return client; -} - -struct aji_client_container *ast_aji_get_clients(void) -{ - return &clients; -} - -/*! - * \internal - * \brief Send a Jabber Message via call from the Manager - * \param s mansession Manager session - * \param m message Message to send - * \return 0 -*/ -static int manager_jabber_send(struct mansession *s, const struct message *m) -{ - struct aji_client *client = NULL; - const char *id = astman_get_header(m, "ActionID"); - const char *jabber = astman_get_header(m, "Jabber"); - const char *screenname = astman_get_header(m, "ScreenName"); - const char *message = astman_get_header(m, "Message"); - - if (ast_strlen_zero(jabber)) { - astman_send_error(s, m, "No transport specified"); - return 0; - } - if (ast_strlen_zero(screenname)) { - astman_send_error(s, m, "No ScreenName specified"); - return 0; - } - if (ast_strlen_zero(message)) { - astman_send_error(s, m, "No Message specified"); - return 0; - } - - astman_send_ack(s, m, "Attempting to send Jabber Message"); - client = ast_aji_get_client(jabber); - if (!client) { - astman_send_error(s, m, "Could not find Sender"); - return 0; - } - if (strchr(screenname, '@') && message) { - ast_aji_send_chat(client, screenname, message); - astman_append(s, "Response: Success\r\n"); - } else { - astman_append(s, "Response: Error\r\n"); - } - ASTOBJ_UNREF(client, ast_aji_client_destroy); - if (!ast_strlen_zero(id)) { - astman_append(s, "ActionID: %s\r\n", id); - } - astman_append(s, "\r\n"); - return 0; -} - -/*! - * \internal - * \brief Reload the jabber module - */ -static int aji_reload(int reload) -{ - int res; - - ASTOBJ_CONTAINER_MARKALL(&clients); - if (!(res = aji_load_config(reload))) { - ast_log(LOG_ERROR, "JABBER: Failed to load config.\n"); - return 0; - } else if (res == -1) - return 1; - - ASTOBJ_CONTAINER_PRUNE_MARKED(&clients, ast_aji_client_destroy); - ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, { - ASTOBJ_RDLOCK(iterator); - if (iterator->state == AJI_DISCONNECTED) { - if (!iterator->thread) - ast_pthread_create_background(&iterator->thread, NULL, aji_recv_loop, iterator); - } else if (iterator->state == AJI_CONNECTING) { - aji_get_roster(iterator); - if (iterator->distribute_events) { - aji_init_event_distribution(iterator); - } - } - - ASTOBJ_UNLOCK(iterator); - }); - - return 1; -} - -/*! - * \internal - * \brief Unload the jabber module - */ -static int unload_module(void) -{ - ast_msg_tech_unregister(&msg_tech); - ast_cli_unregister_multiple(aji_cli, ARRAY_LEN(aji_cli)); - ast_unregister_application(app_ajisend); - ast_unregister_application(app_ajisendgroup); - ast_unregister_application(app_ajistatus); - ast_unregister_application(app_ajijoin); - ast_unregister_application(app_ajileave); - ast_manager_unregister("JabberSend"); - ast_custom_function_unregister(&jabberstatus_function); - mwi_sub = stasis_unsubscribe_and_join(mwi_sub); - device_state_sub = stasis_unsubscribe_and_join(device_state_sub); - ast_custom_function_unregister(&jabberreceive_function); - - ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, { - ASTOBJ_WRLOCK(iterator); - ast_debug(3, "JABBER: Releasing and disconnecting client: %s\n", iterator->name); - iterator->state = AJI_DISCONNECTING; - ASTOBJ_UNLOCK(iterator); - pthread_join(iterator->thread, NULL); - ast_aji_disconnect(iterator); - }); - - ASTOBJ_CONTAINER_DESTROYALL(&clients, ast_aji_client_destroy); - ASTOBJ_CONTAINER_DESTROY(&clients); - - ast_cond_destroy(&message_received_condition); - ast_mutex_destroy(&messagelock); - - return 0; -} - -/*! - * \internal - * \brief Unload the jabber module - */ -static int load_module(void) -{ - ASTOBJ_CONTAINER_INIT(&clients); - if (!aji_reload(0)) - return AST_MODULE_LOAD_DECLINE; - ast_manager_register_xml("JabberSend", EVENT_FLAG_SYSTEM, manager_jabber_send); - ast_register_application_xml(app_ajisend, aji_send_exec); - ast_register_application_xml(app_ajisendgroup, aji_sendgroup_exec); - ast_register_application_xml(app_ajistatus, aji_status_exec); - ast_register_application_xml(app_ajijoin, aji_join_exec); - ast_register_application_xml(app_ajileave, aji_leave_exec); - ast_cli_register_multiple(aji_cli, ARRAY_LEN(aji_cli)); - ast_custom_function_register(&jabberstatus_function); - ast_custom_function_register(&jabberreceive_function); - ast_msg_tech_register(&msg_tech); - - ast_mutex_init(&messagelock); - ast_cond_init(&message_received_condition, NULL); - return 0; -} - -/*! - * \internal - * \brief Wrapper for aji_reload - */ -static int reload(void) -{ - aji_reload(1); - return 0; -} - -AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "AJI - Asterisk Jabber Interface", - .load = load_module, - .unload = unload_module, - .reload = reload, - .load_pri = AST_MODPRI_CHANNEL_DEPEND, - ); diff --git a/res/res_musiconhold.c b/res/res_musiconhold.c index 40f6ef10ff2..1d05f0daa00 100644 --- a/res/res_musiconhold.c +++ b/res/res_musiconhold.c @@ -98,36 +98,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") an application such as Answer() or Progress(). - - - Wait, playing Music On Hold. - - - - - - !!! DEPRECATED. Use MusicOnHold instead !!! - Plays hold music specified number of seconds. Returns 0 when done, - or -1 on hangup. If no hold music is available, the delay will still occur - with no sound. - !!! DEPRECATED. Use MusicOnHold instead !!! - - - - - Set default Music On Hold class. - - - - - - !!! DEPRECATED. USe Set(CHANNEL(musicclass)=...) instead !!! - Sets the default class for music on hold for a given channel. - When music on hold is activated, this class will be used to select which - music is played. - !!! DEPRECATED. USe Set(CHANNEL(musicclass)=...) instead !!! - - Play Music On Hold. @@ -153,8 +123,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") ***/ static const char play_moh[] = "MusicOnHold"; -static const char wait_moh[] = "WaitMusicOnHold"; -static const char set_moh[] = "SetMusicOnHold"; static const char start_moh[] = "StartMusicOnHold"; static const char stop_moh[] = "StopMusicOnHold"; @@ -862,46 +830,6 @@ static int play_moh_exec(struct ast_channel *chan, const char *data) return res; } -static int wait_moh_exec(struct ast_channel *chan, const char *data) -{ - static int deprecation_warning = 0; - int res; - - if (!deprecation_warning) { - deprecation_warning = 1; - ast_log(LOG_WARNING, "WaitMusicOnHold application is deprecated and will be removed. Use MusicOnHold with duration parameter instead\n"); - } - - if (!data || !atoi(data)) { - ast_log(LOG_WARNING, "WaitMusicOnHold requires an argument (number of seconds to wait)\n"); - return -1; - } - if (ast_moh_start(chan, NULL, NULL)) { - ast_log(LOG_WARNING, "Unable to start music on hold for %d seconds on channel %s\n", atoi(data), ast_channel_name(chan)); - return 0; - } - res = ast_safe_sleep(chan, atoi(data) * 1000); - ast_moh_stop(chan); - return res; -} - -static int set_moh_exec(struct ast_channel *chan, const char *data) -{ - static int deprecation_warning = 0; - - if (!deprecation_warning) { - deprecation_warning = 1; - ast_log(LOG_WARNING, "SetMusicOnHold application is deprecated and will be removed. Use Set(CHANNEL(musicclass)=...) instead\n"); - } - - if (ast_strlen_zero(data)) { - ast_log(LOG_WARNING, "SetMusicOnHold requires an argument (class)\n"); - return -1; - } - ast_channel_musicclass_set(chan, data); - return 0; -} - static int start_moh_exec(struct ast_channel *chan, const char *data) { char *parse; @@ -2008,10 +1936,6 @@ static int load_module(void) res = ast_register_application_xml(play_moh, play_moh_exec); ast_register_atexit(ast_moh_destroy); ast_cli_register_multiple(cli_moh, ARRAY_LEN(cli_moh)); - if (!res) - res = ast_register_application_xml(wait_moh, wait_moh_exec); - if (!res) - res = ast_register_application_xml(set_moh, set_moh_exec); if (!res) res = ast_register_application_xml(start_moh, start_moh_exec); if (!res) @@ -2058,8 +1982,6 @@ static int unload_module(void) ast_moh_destroy(); res = ast_unregister_application(play_moh); - res |= ast_unregister_application(wait_moh); - res |= ast_unregister_application(set_moh); res |= ast_unregister_application(start_moh); res |= ast_unregister_application(stop_moh); ast_cli_unregister_multiple(cli_moh, ARRAY_LEN(cli_moh)); diff --git a/utils/ael_main.c b/utils/ael_main.c index b4245c8b45a..86588ee4b0b 100644 --- a/utils/ael_main.c +++ b/utils/ael_main.c @@ -37,8 +37,6 @@ void ast_register_file_version(const char *file, const char *version) { } void ast_unregister_file_version(const char *file) { } #endif -struct ast_flags ast_compat = { 7 }; - /*** MODULEINFO res_ael_share ***/ diff --git a/utils/conf2ael.c b/utils/conf2ael.c index ef5225352dd..d0f4c6e1365 100644 --- a/utils/conf2ael.c +++ b/utils/conf2ael.c @@ -56,7 +56,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/pval.h" #include "asterisk/extconf.h" -struct ast_flags ast_compat = { 7 }; const char *ast_config_AST_CONFIG_DIR = "/etc/asterisk"; /* placeholder */ void get_start_stop(unsigned int *word, int bitsperword, int totalbits, int *start, int *end);