[asterisk-commits] eliel: branch group/data_api_gsoc2009 r200145 - /team/group/data_api_gsoc2009...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Thu Jun 11 14:59:13 CDT 2009
Author: eliel
Date: Thu Jun 11 14:59:10 2009
New Revision: 200145
URL: http://svn.asterisk.org/svn-view/asterisk?view=rev&rev=200145
Log:
I missed this files in my last manual merge.
Added:
team/group/data_api_gsoc2009/channels/sig_analog.c (with props)
team/group/data_api_gsoc2009/channels/sig_analog.h (with props)
Added: team/group/data_api_gsoc2009/channels/sig_analog.c
URL: http://svn.asterisk.org/svn-view/asterisk/team/group/data_api_gsoc2009/channels/sig_analog.c?view=auto&rev=200145
==============================================================================
--- team/group/data_api_gsoc2009/channels/sig_analog.c (added)
+++ team/group/data_api_gsoc2009/channels/sig_analog.c Thu Jun 11 14:59:10 2009
@@ -1,0 +1,3262 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2009, Digium, Inc.
+ *
+ * Mark Spencer <markster at digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Analog signaling module
+ *
+ * \author Matthew Fredrickson <creslin at digium.com>
+ */
+
+#include "asterisk.h"
+
+#include <errno.h>
+#include <ctype.h>
+
+#include "asterisk/utils.h"
+#include "asterisk/options.h"
+#include "asterisk/pbx.h"
+#include "asterisk/file.h"
+#include "asterisk/callerid.h"
+#include "asterisk/say.h"
+#include "asterisk/manager.h"
+#include "asterisk/astdb.h"
+#include "asterisk/features.h"
+
+#include "sig_analog.h"
+
+#define POLARITY_IDLE 0
+#define POLARITY_REV 1
+#define MIN_MS_SINCE_FLASH ( (2000) ) /*!< 2000 ms */
+static int analog_matchdigittimeout = 3000;
+static int analog_gendigittimeout = 8000;
+static int analog_firstdigittimeout = 16000;
+static char analog_defaultcic[64] = "";
+static char analog_defaultozz[64] = "";
+
+static const struct {
+ enum analog_sigtype sigtype;
+ const char const *name;
+} sigtypes[] = {
+ { ANALOG_SIG_FXOLS, "fxo_ls" },
+ { ANALOG_SIG_FXOKS, "fxo_ks" },
+ { ANALOG_SIG_FXOGS, "fxo_gs" },
+ { ANALOG_SIG_FXSLS, "fxs_ls" },
+ { ANALOG_SIG_FXSKS, "fxs_ks" },
+ { ANALOG_SIG_FXSGS, "fxs_gs" },
+ { ANALOG_SIG_EMWINK, "em_w" },
+ { ANALOG_SIG_EM, "em" },
+ { ANALOG_SIG_EM_E1, "em_e1" },
+ { ANALOG_SIG_FEATD, "featd" },
+ { ANALOG_SIG_FEATDMF, "featdmf" },
+ { ANALOG_SIG_FEATDMF_TA, "featdmf_ta" },
+ { ANALOG_SIG_FEATB, "featb" },
+ { ANALOG_SIG_FGC_CAMA, "fgccama" },
+ { ANALOG_SIG_FGC_CAMAMF, "fgccamamf" },
+ { ANALOG_SIG_SF, "sf" },
+ { ANALOG_SIG_SFWINK, "sf_w" },
+ { ANALOG_SIG_SF_FEATD, "sf_featd" },
+ { ANALOG_SIG_SF_FEATDMF, "sf_featdmf" },
+ { ANALOG_SIG_SF_FEATB, "sf_featb" },
+ { ANALOG_SIG_E911, "e911" },
+};
+
+static const struct {
+ unsigned int cid_type;
+ const char const *name;
+} cidtypes[] = {
+ { CID_SIG_BELL, "bell" },
+ { CID_SIG_V23, "v23" },
+ { CID_SIG_V23_JP, "v23_jp" },
+ { CID_SIG_DTMF, "dtmf" },
+ /* "smdi" is intentionally not supported here, as there is a much better
+ * way to do this in the dialplan now. */
+};
+
+enum analog_sigtype analog_str_to_sigtype(const char *name)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_LEN(sigtypes); i++) {
+ if (!strcasecmp(sigtypes[i].name, name)) {
+ return sigtypes[i].sigtype;
+ }
+ }
+
+ return 0;
+}
+
+const char *analog_sigtype_to_str(enum analog_sigtype sigtype)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_LEN(sigtypes); i++) {
+ if (sigtype == sigtypes[i].sigtype) {
+ return sigtypes[i].name;
+ }
+ }
+
+ return "Unknown";
+}
+
+unsigned int analog_str_to_cidtype(const char *name)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_LEN(cidtypes); i++) {
+ if (!strcasecmp(cidtypes[i].name, name)) {
+ return cidtypes[i].cid_type;
+ }
+ }
+
+ return 0;
+}
+
+const char *analog_cidtype_to_str(unsigned int cid_type)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_LEN(cidtypes); i++) {
+ if (cid_type == cidtypes[i].cid_type) {
+ return cidtypes[i].name;
+ }
+ }
+
+ return "Unknown";
+}
+
+static int analog_start_cid_detect(struct analog_pvt *p, int cid_signalling)
+{
+ if (p->calls->start_cid_detect)
+ return p->calls->start_cid_detect(p->chan_pvt, cid_signalling);
+ else
+ return -1;
+}
+
+static int analog_stop_cid_detect(struct analog_pvt *p)
+{
+ if (p->calls->stop_cid_detect)
+ return p->calls->stop_cid_detect(p->chan_pvt);
+ else
+ return -1;
+}
+
+static int analog_get_callerid(struct analog_pvt *p, char *name, char *number, enum analog_event *ev, size_t timeout)
+{
+ if (p->calls->get_callerid)
+ return p->calls->get_callerid(p->chan_pvt, name, number, ev, timeout);
+ else
+ return -1;
+}
+
+static int analog_get_event(struct analog_pvt *p)
+{
+ if (p->calls->get_event)
+ return p->calls->get_event(p->chan_pvt);
+ else
+ return -1;
+}
+
+static int analog_wait_event(struct analog_pvt *p)
+{
+ if (p->calls->wait_event)
+ return p->calls->wait_event(p->chan_pvt);
+ else
+ return -1;
+}
+
+enum analog_cid_start analog_str_to_cidstart(const char *value)
+{
+ if (!strcasecmp(value, "ring")) {
+ return ANALOG_CID_START_RING;
+ } else if (!strcasecmp(value, "polarity")) {
+ return ANALOG_CID_START_POLARITY;
+ } else if (!strcasecmp(value, "polarity_in")) {
+ return ANALOG_CID_START_POLARITY_IN;
+ }
+
+ return 0;
+}
+
+const char *analog_cidstart_to_str(enum analog_cid_start cid_start)
+{
+ switch (cid_start) {
+ case ANALOG_CID_START_RING:
+ return "Ring";
+ case ANALOG_CID_START_POLARITY:
+ return "Polarity";
+ case ANALOG_CID_START_POLARITY_IN:
+ return "Polarity_In";
+ }
+
+ return "Unknown";
+}
+
+static char *analog_event2str(enum analog_event event)
+{
+ char *res;
+ switch (event) {
+ case ANALOG_EVENT_DIALCOMPLETE:
+ res = "ANALOG_EVENT_DIALCOMPLETE";
+ break;
+ case ANALOG_EVENT_WINKFLASH:
+ res = "ANALOG_EVENT_WINKFLASH";
+ break;
+ case ANALOG_EVENT_ONHOOK:
+ res = "ANALOG_EVENT_ONHOOK";
+ break;
+ case ANALOG_EVENT_RINGOFFHOOK:
+ res = "ANALOG_EVENT_RINGOFFHOOK";
+ break;
+ case ANALOG_EVENT_ALARM:
+ res = "ANALOG_EVENT_ALARM";
+ break;
+ case ANALOG_EVENT_NOALARM:
+ res = "ANALOG_EVENT_NOALARM";
+ break;
+ case ANALOG_EVENT_HOOKCOMPLETE:
+ res = "ANALOG_EVENT_HOOKCOMPLETE";
+ break;
+ case ANALOG_EVENT_POLARITY:
+ res = "ANALOG_EVENT_POLARITY";
+ break;
+ case ANALOG_EVENT_RINGERON:
+ res = "ANALOG_EVENT_RINGERON";
+ break;
+ case ANALOG_EVENT_RINGEROFF:
+ res = "ANALOG_EVENT_RINGEROFF";
+ break;
+ case ANALOG_EVENT_RINGBEGIN:
+ res = "ANALOG_EVENT_RINGBEGIN";
+ break;
+ case ANALOG_EVENT_PULSE_START:
+ res = "ANALOG_EVENT_PULSE_START";
+ break;
+ case ANALOG_EVENT_NEONMWI_ACTIVE:
+ res = "ANALOG_EVENT_NEONMWI_ACTIVE";
+ break;
+ case ANALOG_EVENT_NEONMWI_INACTIVE:
+ res = "ANALOG_EVENT_NEONMWI_INACTIVE";
+ break;
+ default:
+ res = "UNKNOWN/OTHER";
+ break;
+ }
+
+ return res;
+}
+
+static void analog_swap_subs(struct analog_pvt *p, enum analog_sub a, enum analog_sub b)
+{
+ int tinthreeway;
+ struct ast_channel *towner;
+
+ ast_debug(1, "Swapping %d and %d\n", a, b);
+
+ towner = p->subs[a].owner;
+ tinthreeway = p->subs[a].inthreeway;
+
+ p->subs[a].owner = p->subs[b].owner;
+ p->subs[a].inthreeway = p->subs[b].inthreeway;
+
+ p->subs[b].owner = towner;
+ p->subs[b].inthreeway = tinthreeway;
+
+ if (p->calls->swap_subs)
+ p->calls->swap_subs(p->chan_pvt, a, p->subs[a].owner, b, p->subs[b].owner);
+
+}
+
+static int analog_alloc_sub(struct analog_pvt *p, enum analog_sub x)
+{
+ p->subs[x].allocd = 1;
+ if (p->calls->allocate_sub)
+ return p->calls->allocate_sub(p->chan_pvt, x);
+
+ return 0;
+}
+
+static int analog_unalloc_sub(struct analog_pvt *p, enum analog_sub x)
+{
+ p->subs[x].allocd = 0;
+ p->subs[x].owner = NULL;
+ if (p->calls->unallocate_sub)
+ return p->calls->unallocate_sub(p->chan_pvt, x);
+
+ return 0;
+}
+
+static int analog_send_callerid(struct analog_pvt *p, int cwcid, struct ast_callerid *cid)
+{
+ ast_debug(1, "Sending callerid. CID_NAME: '%s' CID_NUM: '%s'\n", cid->cid_name, cid->cid_num);
+
+ if (cwcid) {
+ p->callwaitcas = 0;
+ }
+
+ if (p->calls->send_callerid)
+ return p->calls->send_callerid(p->chan_pvt, cwcid, cid);
+ else
+ return 0;
+}
+
+static int analog_get_index(struct ast_channel *ast, struct analog_pvt *p, int nullok)
+{
+ int res;
+ if (p->subs[ANALOG_SUB_REAL].owner == ast)
+ res = ANALOG_SUB_REAL;
+ else if (p->subs[ANALOG_SUB_CALLWAIT].owner == ast)
+ res = ANALOG_SUB_CALLWAIT;
+ else if (p->subs[ANALOG_SUB_THREEWAY].owner == ast)
+ res = ANALOG_SUB_THREEWAY;
+ else {
+ res = -1;
+ if (!nullok)
+ ast_log(LOG_WARNING, "Unable to get index, and nullok is not asserted\n");
+ }
+ return res;
+}
+
+static int analog_dsp_reset_and_flush_digits(struct analog_pvt *p)
+{
+ if (p->calls->dsp_reset_and_flush_digits)
+ return p->calls->dsp_reset_and_flush_digits(p->chan_pvt);
+ else
+ /* Return 0 since I think this is unnecessary to do in most cases it is used. Mostly only for ast_dsp */
+ return 0;
+}
+
+static int analog_play_tone(struct analog_pvt *p, enum analog_sub sub, enum analog_tone tone)
+{
+ if (p->calls->play_tone)
+ return p->calls->play_tone(p->chan_pvt, sub, tone);
+ else
+ return -1;
+}
+
+static struct ast_channel * analog_new_ast_channel(struct analog_pvt *p, int state, int startpbx, enum analog_sub sub)
+{
+ struct ast_channel *c;
+
+ if (p->calls->new_ast_channel)
+ c = p->calls->new_ast_channel(p->chan_pvt, state, startpbx, sub);
+ else
+ return NULL;
+
+ p->subs[sub].owner = c;
+ if (!p->owner)
+ p->owner = c;
+ return c;
+}
+
+static int analog_set_echocanceller(struct analog_pvt *p, int enable)
+{
+ if (p->calls->set_echocanceller)
+ return p->calls->set_echocanceller(p->chan_pvt, enable);
+ else
+ return -1;
+}
+
+static int analog_train_echocanceller(struct analog_pvt *p)
+{
+ if (p->calls->train_echocanceller)
+ return p->calls->train_echocanceller(p->chan_pvt);
+ else
+ return -1;
+}
+
+static int analog_is_off_hook(struct analog_pvt *p)
+{
+ if (p->calls->is_off_hook)
+ return p->calls->is_off_hook(p->chan_pvt);
+ else
+ return -1;
+}
+
+static int analog_ring(struct analog_pvt *p)
+{
+ if (p->calls->ring)
+ return p->calls->ring(p->chan_pvt);
+ else
+ return -1;
+}
+
+static int analog_start(struct analog_pvt *p)
+{
+ if (p->calls->start)
+ return p->calls->start(p->chan_pvt);
+ else
+ return -1;
+}
+
+static int analog_dial_digits(struct analog_pvt *p, enum analog_sub sub, struct analog_dialoperation *dop)
+{
+ if (p->calls->dial_digits)
+ return p->calls->dial_digits(p->chan_pvt, sub, dop);
+ else
+ return -1;
+}
+
+static int analog_on_hook(struct analog_pvt *p)
+{
+ if (p->calls->on_hook)
+ return p->calls->on_hook(p->chan_pvt);
+ else
+ return -1;
+}
+
+static int analog_check_for_conference(struct analog_pvt *p)
+{
+ if (p->calls->check_for_conference)
+ return p->calls->check_for_conference(p->chan_pvt);
+ else
+ return -1;
+}
+
+static void analog_all_subchannels_hungup(struct analog_pvt *p)
+{
+ if (p->calls->all_subchannels_hungup)
+ p->calls->all_subchannels_hungup(p->chan_pvt);
+}
+
+static void analog_unlock_private(struct analog_pvt *p)
+{
+ if (p->calls->unlock_private)
+ p->calls->unlock_private(p->chan_pvt);
+}
+
+static void analog_lock_private(struct analog_pvt *p)
+{
+ if (p->calls->lock_private)
+ p->calls->lock_private(p->chan_pvt);
+}
+
+static int analog_off_hook(struct analog_pvt *p)
+{
+ if (p->calls->off_hook)
+ return p->calls->off_hook(p->chan_pvt);
+ else
+ return -1;
+}
+
+static int analog_dsp_set_digitmode(struct analog_pvt *p, enum analog_dsp_digitmode mode)
+{
+ if (p->calls->dsp_set_digitmode)
+ return p->calls->dsp_set_digitmode(p->chan_pvt, mode);
+ else
+ return -1;
+}
+
+static void analog_cb_handle_dtmfup(struct analog_pvt *p, struct ast_channel *ast, enum analog_sub analog_index, struct ast_frame **dest)
+{
+ if (p->calls->handle_dtmfup)
+ p->calls->handle_dtmfup(p->chan_pvt, ast, analog_index, dest);
+}
+
+static int analog_wink(struct analog_pvt *p, enum analog_sub index)
+{
+ if (p->calls->wink)
+ return p->calls->wink(p->chan_pvt, index);
+ else
+ return -1;
+}
+
+static int analog_has_voicemail(struct analog_pvt *p)
+{
+ if (p->calls->has_voicemail)
+ return p->calls->has_voicemail(p->chan_pvt);
+ else
+ return -1;
+}
+
+static int analog_is_dialing(struct analog_pvt *p, enum analog_sub index)
+{
+ if (p->calls->is_dialing)
+ return p->calls->is_dialing(p->chan_pvt, index);
+ else
+ return -1;
+}
+
+static int analog_attempt_transfer(struct analog_pvt *p)
+{
+ /* In order to transfer, we need at least one of the channels to
+ actually be in a call bridge. We can't conference two applications
+ together (but then, why would we want to?) */
+ if (ast_bridged_channel(p->subs[ANALOG_SUB_REAL].owner)) {
+ /* The three-way person we're about to transfer to could still be in MOH, so
+ stop if now if appropriate */
+ if (ast_bridged_channel(p->subs[ANALOG_SUB_THREEWAY].owner))
+ ast_queue_control(p->subs[ANALOG_SUB_THREEWAY].owner, AST_CONTROL_UNHOLD);
+ if (p->subs[ANALOG_SUB_REAL].owner->_state == AST_STATE_RINGING) {
+ ast_indicate(ast_bridged_channel(p->subs[ANALOG_SUB_REAL].owner), AST_CONTROL_RINGING);
+ }
+ if (p->subs[ANALOG_SUB_THREEWAY].owner->_state == AST_STATE_RING) {
+ analog_play_tone(p, ANALOG_SUB_THREEWAY, ANALOG_TONE_RINGTONE);
+ }
+ if (ast_channel_masquerade(p->subs[ANALOG_SUB_THREEWAY].owner, ast_bridged_channel(p->subs[ANALOG_SUB_REAL].owner))) {
+ ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
+ ast_bridged_channel(p->subs[ANALOG_SUB_REAL].owner)->name, p->subs[ANALOG_SUB_THREEWAY].owner->name);
+ return -1;
+ }
+ /* Orphan the channel after releasing the lock */
+ ast_channel_unlock(p->subs[ANALOG_SUB_THREEWAY].owner);
+ analog_unalloc_sub(p, ANALOG_SUB_THREEWAY);
+ } else if (ast_bridged_channel(p->subs[ANALOG_SUB_THREEWAY].owner)) {
+ ast_queue_control(p->subs[ANALOG_SUB_REAL].owner, AST_CONTROL_UNHOLD);
+ if (p->subs[ANALOG_SUB_THREEWAY].owner->_state == AST_STATE_RINGING) {
+ ast_indicate(ast_bridged_channel(p->subs[ANALOG_SUB_THREEWAY].owner), AST_CONTROL_RINGING);
+ }
+ if (p->subs[ANALOG_SUB_REAL].owner->_state == AST_STATE_RING) {
+ analog_play_tone(p, ANALOG_SUB_REAL, ANALOG_TONE_RINGTONE);
+ }
+ if (ast_channel_masquerade(p->subs[ANALOG_SUB_REAL].owner, ast_bridged_channel(p->subs[ANALOG_SUB_THREEWAY].owner))) {
+ ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
+ ast_bridged_channel(p->subs[ANALOG_SUB_THREEWAY].owner)->name, p->subs[ANALOG_SUB_REAL].owner->name);
+ return -1;
+ }
+ /* Three-way is now the REAL */
+ analog_swap_subs(p, ANALOG_SUB_THREEWAY, ANALOG_SUB_REAL);
+ ast_channel_unlock(p->subs[ANALOG_SUB_THREEWAY].owner);
+ analog_unalloc_sub(p, ANALOG_SUB_THREEWAY);
+ /* Tell the caller not to hangup */
+ return 1;
+ } else {
+ ast_debug(1, "Neither %s nor %s are in a bridge, nothing to transfer\n",
+ p->subs[ANALOG_SUB_REAL].owner->name, p->subs[ANALOG_SUB_THREEWAY].owner->name);
+ ast_softhangup_nolock(p->subs[ANALOG_SUB_THREEWAY].owner, AST_SOFTHANGUP_DEV);
+ return -1;
+ }
+ return 0;
+}
+
+static int analog_update_conf(struct analog_pvt *p)
+{
+ int x;
+ int needconf = 0;
+
+ /* Start with the obvious, general stuff */
+ for (x = 0; x < 3; x++) {
+ /* Look for three way calls */
+ if ((p->subs[x].allocd) && p->subs[x].inthreeway) {
+ if (p->calls->conf_add)
+ p->calls->conf_add(p->chan_pvt, x);
+ needconf++;
+ } else {
+ if (p->calls->conf_del)
+ p->calls->conf_del(p->chan_pvt, x);
+ }
+ }
+ ast_debug(1, "Updated conferencing on %d, with %d conference users\n", p->channel, needconf);
+
+ if (p->calls->complete_conference_update)
+ p->calls->complete_conference_update(p->chan_pvt, needconf);
+ return 0;
+}
+
+struct ast_channel * analog_request(struct analog_pvt *p, int *callwait)
+{
+ ast_log(LOG_DEBUG, "%s %d\n", __FUNCTION__, p->channel);
+ *callwait = (p->owner != NULL);
+
+ if (p->owner) {
+ if (analog_alloc_sub(p, ANALOG_SUB_CALLWAIT)) {
+ ast_log(LOG_ERROR, "Unable to alloc subchannel\n");
+ return NULL;
+ }
+ }
+
+ return analog_new_ast_channel(p, AST_STATE_RESERVED, 0, p->owner ? ANALOG_SUB_CALLWAIT : ANALOG_SUB_REAL);
+}
+
+int analog_available(struct analog_pvt *p, int channelmatch, ast_group_t groupmatch, int *busy, int *channelmatched, int *groupmatched)
+{
+ int offhook;
+
+ ast_log(LOG_DEBUG, "%s %d\n", __FUNCTION__, p->channel);
+ /* We're at least busy at this point */
+ if (busy) {
+ if ((p->sig == ANALOG_SIG_FXOKS) || (p->sig == ANALOG_SIG_FXOLS) || (p->sig == ANALOG_SIG_FXOGS))
+ *busy = 1;
+ }
+ /* If do not disturb, definitely not */
+ if (p->dnd)
+ return 0;
+ /* If guard time, definitely not */
+ if (p->guardtime && (time(NULL) < p->guardtime))
+ return 0;
+
+ /* If no owner definitely available */
+ if (!p->owner) {
+ if (p->sig == ANALOG_SIG_FXSLS)
+ return 1;
+
+ offhook = analog_is_off_hook(p);
+
+ if ((p->sig == ANALOG_SIG_FXSKS) || (p->sig == ANALOG_SIG_FXSGS)) {
+ /* When "onhook" that means no battery on the line, and thus
+ it is out of service..., if it's on a TDM card... If it's a channel
+ bank, there is no telling... */
+ if (offhook)
+ return 1;
+ else
+ return 0;
+ } else if (offhook) {
+ ast_debug(1, "Channel %d off hook, can't use\n", p->channel);
+ /* Not available when the other end is off hook */
+ return 0;
+ }
+ return 1;
+ }
+
+ /* If it's not an FXO, forget about call wait */
+ if ((p->sig != ANALOG_SIG_FXOKS) && (p->sig != ANALOG_SIG_FXOLS) && (p->sig != ANALOG_SIG_FXOGS))
+ return 0;
+
+ if (!p->callwaiting) {
+ /* If they don't have call waiting enabled, then for sure they're unavailable at this point */
+ return 0;
+ }
+
+ if (p->subs[ANALOG_SUB_CALLWAIT].allocd) {
+ /* If there is already a call waiting call, then we can't take a second one */
+ return 0;
+ }
+
+ if ((p->owner->_state != AST_STATE_UP) &&
+ ((p->owner->_state != AST_STATE_RINGING) || p->outgoing)) {
+ /* If the current call is not up, then don't allow the call */
+ return 0;
+ }
+ if ((p->subs[ANALOG_SUB_THREEWAY].owner) && (!p->subs[ANALOG_SUB_THREEWAY].inthreeway)) {
+ /* Can't take a call wait when the three way calling hasn't been merged yet. */
+ return 0;
+ }
+ /* We're cool */
+ return 1;
+}
+
+static int analog_stop_callwait(struct analog_pvt *p)
+{
+ if (p->callwaitingcallerid)
+ p->callwaitcas = 0;
+
+ if (p->calls->stop_callwait)
+ return p->calls->stop_callwait(p->chan_pvt);
+ else
+ return 0;
+}
+
+static int analog_callwait(struct analog_pvt *p)
+{
+ if (p->callwaitingcallerid)
+ p->callwaitcas = 1;
+ if (p->calls->callwait)
+ return p->calls->callwait(p->chan_pvt);
+ else
+ return 0;
+}
+
+int analog_call(struct analog_pvt *p, struct ast_channel *ast, char *rdest, int timeout)
+{
+ int res, index,mysig;
+ char *c, *n, *l;
+ char dest[256]; /* must be same length as p->dialdest */
+
+ ast_log(LOG_DEBUG, "CALLING CID_NAME: %s CID_NUM:: %s\n", ast->connected.id.name, ast->connected.id.number);
+
+ ast_copy_string(dest, rdest, sizeof(dest));
+ ast_copy_string(p->dialdest, rdest, sizeof(p->dialdest));
+
+ if ((ast->_state == AST_STATE_BUSY)) {
+ ast_queue_control(p->subs[ANALOG_SUB_REAL].owner, AST_CONTROL_BUSY);
+ return 0;
+ }
+
+ if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
+ ast_log(LOG_WARNING, "analog_call called on %s, neither down nor reserved\n", ast->name);
+ return -1;
+ }
+
+ p->dialednone = 0;
+
+ mysig = p->sig;
+ if (p->outsigmod > -1)
+ mysig = p->outsigmod;
+
+ switch (mysig) {
+ case ANALOG_SIG_FXOLS:
+ case ANALOG_SIG_FXOGS:
+ case ANALOG_SIG_FXOKS:
+ if (p->owner == ast) {
+ /* Normal ring, on hook */
+
+ /* Don't send audio while on hook, until the call is answered */
+ p->dialing = 1;
+ /* XXX */
+#if 0
+ /* Choose proper cadence */
+ if ((p->distinctivering > 0) && (p->distinctivering <= num_cadence)) {
+ if (ioctl(p->subs[ANALOG_SUB_REAL].dfd, DAHDI_SETCADENCE, &cadences[p->distinctivering - 1]))
+ ast_log(LOG_WARNING, "Unable to set distinctive ring cadence %d on '%s': %s\n", p->distinctivering, ast->name, strerror(errno));
+ p->cidrings = cidrings[p->distinctivering - 1];
+ } else {
+ if (ioctl(p->subs[ANALOG_SUB_REAL].dfd, DAHDI_SETCADENCE, NULL))
+ ast_log(LOG_WARNING, "Unable to reset default ring on '%s': %s\n", ast->name, strerror(errno));
+ p->cidrings = p->sendcalleridafter;
+ }
+#endif
+ p->cidrings = p->sendcalleridafter;
+
+ /* nick at dccinc.com 4/3/03 mods to allow for deferred dialing */
+ c = strchr(dest, '/');
+ if (c)
+ c++;
+ if (c && (strlen(c) < p->stripmsd)) {
+ ast_log(LOG_WARNING, "Number '%s' is shorter than stripmsd (%d)\n", c, p->stripmsd);
+ c = NULL;
+ }
+ if (c) {
+ p->dop.op = ANALOG_DIAL_OP_REPLACE;
+ snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "Tw%s", c);
+ ast_debug(1, "FXO: setup deferred dialstring: %s\n", c);
+ } else {
+ p->dop.dialstr[0] = '\0';
+ }
+
+ if (analog_ring(p)) {
+ ast_log(LOG_WARNING, "Unable to ring phone: %s\n", strerror(errno));
+ return -1;
+ }
+ p->dialing = 1;
+ } else {
+ if (ast->connected.id.number)
+ ast_copy_string(p->callwait_num, ast->connected.id.number, sizeof(p->callwait_num));
+ else
+ p->callwait_num[0] = '\0';
+ if (ast->connected.id.name)
+ ast_copy_string(p->callwait_name, ast->connected.id.name, sizeof(p->callwait_name));
+ else
+ p->callwait_name[0] = '\0';
+
+ /* Call waiting tone instead */
+ if (analog_callwait(p)) {
+ return -1;
+ }
+ /* Make ring-back */
+ if (analog_play_tone(p, ANALOG_SUB_CALLWAIT, ANALOG_TONE_RINGTONE))
+ ast_log(LOG_WARNING, "Unable to generate call-wait ring-back on channel %s\n", ast->name);
+
+ }
+ n = ast->connected.id.name;
+ l = ast->connected.id.number;
+ if (l)
+ ast_copy_string(p->lastcid_num, l, sizeof(p->lastcid_num));
+ else
+ p->lastcid_num[0] = '\0';
+ if (n)
+ ast_copy_string(p->lastcid_name, n, sizeof(p->lastcid_name));
+ else
+ p->lastcid_name[0] = '\0';
+
+ if (p->use_callerid) {
+ //p->callwaitcas = 0;
+ p->cid.cid_name = p->lastcid_name;
+ p->cid.cid_num = p->lastcid_num;
+ }
+
+
+ ast_setstate(ast, AST_STATE_RINGING);
+ index = analog_get_index(ast, p, 0);
+ if (index > -1) {
+ ast_queue_control(p->subs[index].owner, AST_CONTROL_RINGING);
+ }
+ break;
+ case ANALOG_SIG_FXSLS:
+ case ANALOG_SIG_FXSGS:
+ case ANALOG_SIG_FXSKS:
+ case ANALOG_SIG_EMWINK:
+ case ANALOG_SIG_EM:
+ case ANALOG_SIG_EM_E1:
+ case ANALOG_SIG_FEATD:
+ case ANALOG_SIG_FEATDMF:
+ case ANALOG_SIG_E911:
+ case ANALOG_SIG_FGC_CAMA:
+ case ANALOG_SIG_FGC_CAMAMF:
+ case ANALOG_SIG_FEATB:
+ case ANALOG_SIG_SFWINK:
+ case ANALOG_SIG_SF:
+ case ANALOG_SIG_SF_FEATD:
+ case ANALOG_SIG_SF_FEATDMF:
+ case ANALOG_SIG_FEATDMF_TA:
+ case ANALOG_SIG_SF_FEATB:
+ c = strchr(dest, '/');
+ if (c)
+ c++;
+ else
+ c = "";
+ if (strlen(c) < p->stripmsd) {
+ ast_log(LOG_WARNING, "Number '%s' is shorter than stripmsd (%d)\n", c, p->stripmsd);
+ return -1;
+ }
+ res = analog_start(p);
+ if (res < 0) {
+ if (errno != EINPROGRESS) {
+ return -1;
+ }
+ }
+ ast_log(LOG_DEBUG, "Dialing '%s'\n", c);
+ p->dop.op = ANALOG_DIAL_OP_REPLACE;
+
+ c += p->stripmsd;
+
+ switch (mysig) {
+ case ANALOG_SIG_FEATD:
+ l = ast->connected.id.number;
+ if (l)
+ snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "T*%s*%s*", l, c);
+ else
+ snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "T**%s*", c);
+ break;
+ case ANALOG_SIG_FEATDMF:
+ l = ast->connected.id.number;
+ if (l)
+ snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*00%s#*%s#", l, c);
+ else
+ snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*02#*%s#", c);
+ break;
+ case ANALOG_SIG_FEATDMF_TA:
+ {
+ const char *cic = "", *ozz = "";
+
+ /* If you have to go through a Tandem Access point you need to use this */
+#ifndef STANDALONE
+ ozz = pbx_builtin_getvar_helper(p->owner, "FEATDMF_OZZ");
+ if (!ozz)
+ ozz = analog_defaultozz;
+ cic = pbx_builtin_getvar_helper(p->owner, "FEATDMF_CIC");
+ if (!cic)
+ cic = analog_defaultcic;
+#endif
+ if (!ozz || !cic) {
+ ast_log(LOG_WARNING, "Unable to dial channel of type feature group D MF tandem access without CIC or OZZ set\n");
+ return -1;
+ }
+ snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*%s%s#", ozz, cic);
+ snprintf(p->finaldial, sizeof(p->finaldial), "M*%s#", c);
+ p->whichwink = 0;
+ }
+ break;
+ case ANALOG_SIG_E911:
+ ast_copy_string(p->dop.dialstr, "M*911#", sizeof(p->dop.dialstr));
+ break;
+ case ANALOG_SIG_FGC_CAMA:
+ snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "P%s", c);
+ break;
+ case ANALOG_SIG_FGC_CAMAMF:
+ case ANALOG_SIG_FEATB:
+ snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*%s#", c);
+ break;
+ default:
+ if (p->pulse)
+ snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "P%sw", c);
+ else
+ snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "T%sw", c);
+ break;
+ }
+
+ if (p->echotraining && (strlen(p->dop.dialstr) > 4)) {
+ memset(p->echorest, 'w', sizeof(p->echorest) - 1);
+ strcpy(p->echorest + (p->echotraining / 400) + 1, p->dop.dialstr + strlen(p->dop.dialstr) - 2);
+ p->echorest[sizeof(p->echorest) - 1] = '\0';
+ p->echobreak = 1;
+ p->dop.dialstr[strlen(p->dop.dialstr)-2] = '\0';
+ } else
+ p->echobreak = 0;
+ if (!res) {
+ if (analog_dial_digits(p, ANALOG_SUB_REAL, &p->dop)) {
+ int saveerr = errno;
+
+ analog_on_hook(p);
+ ast_log(LOG_WARNING, "Dialing failed on channel %d: %s\n", p->channel, strerror(saveerr));
+ return -1;
+ }
+ } else
+ ast_debug(1, "Deferring dialing...\n");
+ p->dialing = 1;
+ if (ast_strlen_zero(c))
+ p->dialednone = 1;
+ ast_setstate(ast, AST_STATE_DIALING);
+ break;
+ default:
+ ast_debug(1, "not yet implemented\n");
+ return -1;
+ }
+ return 0;
+}
+
+int analog_hangup(struct analog_pvt *p, struct ast_channel *ast)
+{
+ int res;
+ int index, x;
+
+ ast_log(LOG_DEBUG, "%s %d\n", __FUNCTION__, p->channel);
+ if (!ast->tech_pvt) {
+ ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
+ return 0;
+ }
+
+ index = analog_get_index(ast, p, 1);
+
+ x = 0;
+ if (p->origcid_num) {
+ ast_copy_string(p->cid_num, p->origcid_num, sizeof(p->cid_num));
+ free(p->origcid_num);
+ p->origcid_num = NULL;
+ }
+ if (p->origcid_name) {
+ ast_copy_string(p->cid_name, p->origcid_name, sizeof(p->cid_name));
+ free(p->origcid_name);
+ p->origcid_name = NULL;
+ }
+
+ analog_dsp_set_digitmode(p, ANALOG_DIGITMODE_DTMF);
+
+ ast_debug(1, "Hangup: channel: %d index = %d, normal = %d, callwait = %d, thirdcall = %d\n",
+ p->channel, index, p->subs[ANALOG_SUB_REAL].allocd, p->subs[ANALOG_SUB_CALLWAIT].allocd, p->subs[ANALOG_SUB_THREEWAY].allocd);
+ if (index > -1) {
+ /* Real channel, do some fixup */
+ p->subs[index].owner = NULL;
+ p->subs[index].needcallerid = 0;
+ p->polarity = POLARITY_IDLE;
+ if (index == ANALOG_SUB_REAL) {
+ if (p->subs[ANALOG_SUB_CALLWAIT].allocd && p->subs[ANALOG_SUB_THREEWAY].allocd) {
+ ast_debug(1, "Normal call hung up with both three way call and a call waiting call in place?\n");
+ if (p->subs[ANALOG_SUB_CALLWAIT].inthreeway) {
+ /* We had flipped over to answer a callwait and now it's gone */
+ ast_debug(1, "We were flipped over to the callwait, moving back and unowning.\n");
+ /* Move to the call-wait, but un-own us until they flip back. */
+ analog_swap_subs(p, ANALOG_SUB_CALLWAIT, ANALOG_SUB_REAL);
+ analog_unalloc_sub(p, ANALOG_SUB_CALLWAIT);
+ p->owner = NULL;
+ } else {
+ /* The three way hung up, but we still have a call wait */
+ ast_debug(1, "We were in the threeway and have a callwait still. Ditching the threeway.\n");
+ analog_swap_subs(p, ANALOG_SUB_THREEWAY, ANALOG_SUB_REAL);
+ analog_unalloc_sub(p, ANALOG_SUB_THREEWAY);
+ if (p->subs[ANALOG_SUB_REAL].inthreeway) {
+ /* This was part of a three way call. Immediately make way for
+ another call */
+ ast_debug(1, "Call was complete, setting owner to former third call\n");
+ p->owner = p->subs[ANALOG_SUB_REAL].owner;
+ } else {
+ /* This call hasn't been completed yet... Set owner to NULL */
+ ast_debug(1, "Call was incomplete, setting owner to NULL\n");
+ p->owner = NULL;
+ }
+ p->subs[ANALOG_SUB_REAL].inthreeway = 0;
+ }
+ } else if (p->subs[ANALOG_SUB_CALLWAIT].allocd) {
+ /* Move to the call-wait and switch back to them. */
+ analog_swap_subs(p, ANALOG_SUB_CALLWAIT, ANALOG_SUB_REAL);
+ analog_unalloc_sub(p, ANALOG_SUB_CALLWAIT);
+ p->owner = p->subs[ANALOG_SUB_REAL].owner;
+ if (p->owner->_state != AST_STATE_UP)
+ ast_queue_control(p->subs[ANALOG_SUB_REAL].owner, AST_CONTROL_ANSWER);
+ if (ast_bridged_channel(p->subs[ANALOG_SUB_REAL].owner))
+ ast_queue_control(p->subs[ANALOG_SUB_REAL].owner, AST_CONTROL_UNHOLD);
+ } else if (p->subs[ANALOG_SUB_THREEWAY].allocd) {
+ analog_swap_subs(p, ANALOG_SUB_THREEWAY, ANALOG_SUB_REAL);
+ analog_unalloc_sub(p, ANALOG_SUB_THREEWAY);
+ if (p->subs[ANALOG_SUB_REAL].inthreeway) {
+ /* This was part of a three way call. Immediately make way for
+ another call */
+ ast_debug(1, "Call was complete, setting owner to former third call\n");
+ p->owner = p->subs[ANALOG_SUB_REAL].owner;
+ } else {
+ /* This call hasn't been completed yet... Set owner to NULL */
+ ast_debug(1, "Call was incomplete, setting owner to NULL\n");
+ p->owner = NULL;
+ }
+ p->subs[ANALOG_SUB_REAL].inthreeway = 0;
+ }
+ } else if (index == ANALOG_SUB_CALLWAIT) {
+ /* Ditch the holding callwait call, and immediately make it availabe */
+ if (p->subs[ANALOG_SUB_CALLWAIT].inthreeway) {
+ /* This is actually part of a three way, placed on hold. Place the third part
+ on music on hold now */
+ if (p->subs[ANALOG_SUB_THREEWAY].owner && ast_bridged_channel(p->subs[ANALOG_SUB_THREEWAY].owner)) {
+ ast_queue_control_data(p->subs[ANALOG_SUB_THREEWAY].owner, AST_CONTROL_HOLD,
+ S_OR(p->mohsuggest, NULL),
+ !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
+ }
+ p->subs[ANALOG_SUB_THREEWAY].inthreeway = 0;
+ /* Make it the call wait now */
+ analog_swap_subs(p, ANALOG_SUB_CALLWAIT, ANALOG_SUB_THREEWAY);
+ analog_unalloc_sub(p, ANALOG_SUB_THREEWAY);
+ } else
+ analog_unalloc_sub(p, ANALOG_SUB_CALLWAIT);
+ } else if (index == ANALOG_SUB_THREEWAY) {
+ if (p->subs[ANALOG_SUB_CALLWAIT].inthreeway) {
+ /* The other party of the three way call is currently in a call-wait state.
+ Start music on hold for them, and take the main guy out of the third call */
+ if (p->subs[ANALOG_SUB_CALLWAIT].owner && ast_bridged_channel(p->subs[ANALOG_SUB_CALLWAIT].owner)) {
+ ast_queue_control_data(p->subs[ANALOG_SUB_CALLWAIT].owner, AST_CONTROL_HOLD,
+ S_OR(p->mohsuggest, NULL),
+ !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
+ }
+ p->subs[ANALOG_SUB_CALLWAIT].inthreeway = 0;
+ }
+ p->subs[ANALOG_SUB_REAL].inthreeway = 0;
+ /* If this was part of a three way call index, let us make
+ another three way call */
+ analog_unalloc_sub(p, ANALOG_SUB_THREEWAY);
+ } else {
+ /* This wasn't any sort of call, but how are we an index? */
+ ast_log(LOG_WARNING, "Index found but not any type of call?\n");
+ }
+ }
+
+ if (!p->subs[ANALOG_SUB_REAL].owner && !p->subs[ANALOG_SUB_CALLWAIT].owner && !p->subs[ANALOG_SUB_THREEWAY].owner) {
+ p->owner = NULL;
+#if 0
+ p->ringt = 0;
+#endif
+#if 0 /* Since we set it in _call */
+ p->cidrings = 1;
+#endif
+ p->outgoing = 0;
+
+ /* Perform low level hangup if no owner left */
+ res = analog_on_hook(p);
+ if (res < 0) {
+ ast_log(LOG_WARNING, "Unable to hangup line %s\n", ast->name);
+ }
+ switch (p->sig) {
+ case ANALOG_SIG_FXOGS:
+ case ANALOG_SIG_FXOLS:
+ case ANALOG_SIG_FXOKS:
+ /* If they're off hook, try playing congestion */
+ if (analog_is_off_hook(p))
+ analog_play_tone(p, ANALOG_SUB_REAL, ANALOG_TONE_CONGESTION);
+ else
+ analog_play_tone(p, ANALOG_SUB_REAL, -1);
+ break;
+ case ANALOG_SIG_FXSGS:
+ case ANALOG_SIG_FXSLS:
+ case ANALOG_SIG_FXSKS:
+ /* Make sure we're not made available for at least two seconds assuming
+ we were actually used for an inbound or outbound call. */
+ if (ast->_state != AST_STATE_RESERVED) {
+ time(&p->guardtime);
+ p->guardtime += 2;
+ }
+ break;
+ default:
+ analog_play_tone(p, ANALOG_SUB_REAL, -1);
+ }
+
+
+ analog_set_echocanceller(p, 0);
+
+ x = 0;
+ ast_channel_setoption(ast,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0);
+ ast_channel_setoption(ast,AST_OPTION_TDD,&x,sizeof(char),0);
+ p->callwaitcas = 0;
+ p->callwaiting = p->permcallwaiting;
+ p->hidecallerid = p->permhidecallerid;
+ p->dialing = 0;
+ analog_update_conf(p);
+ analog_all_subchannels_hungup(p);
+ }
+
+ analog_stop_callwait(p);
+ ast->tech_pvt = NULL;
+
+ if (option_verbose > 2) {
+ ast_verbose(VERBOSE_PREFIX_3 "Hanging up on '%s'\n", ast->name);
+ }
+
+ return 0;
+}
+
+int analog_answer(struct analog_pvt *p, struct ast_channel *ast)
+{
+ int res = 0;
+ int index;
+ int oldstate = ast->_state;
+ ast_log(LOG_DEBUG, "%s %d\n", __FUNCTION__, p->channel);
+ ast_setstate(ast, AST_STATE_UP);
+ index = analog_get_index(ast, p, 1);
+ if (index < 0)
+ index = ANALOG_SUB_REAL;
+ switch (p->sig) {
+ case ANALOG_SIG_FXSLS:
+ case ANALOG_SIG_FXSGS:
+ case ANALOG_SIG_FXSKS:
+#if 0
+ p->ringt = 0;
+#endif
+ /* Fall through */
+ case ANALOG_SIG_EM:
+ case ANALOG_SIG_EM_E1:
+ case ANALOG_SIG_EMWINK:
+ case ANALOG_SIG_FEATD:
+ case ANALOG_SIG_FEATDMF:
+ case ANALOG_SIG_FEATDMF_TA:
+ case ANALOG_SIG_E911:
+ case ANALOG_SIG_FGC_CAMA:
+ case ANALOG_SIG_FGC_CAMAMF:
+ case ANALOG_SIG_FEATB:
+ case ANALOG_SIG_SF:
+ case ANALOG_SIG_SFWINK:
+ case ANALOG_SIG_SF_FEATD:
+ case ANALOG_SIG_SF_FEATDMF:
+ case ANALOG_SIG_SF_FEATB:
+ case ANALOG_SIG_FXOLS:
+ case ANALOG_SIG_FXOGS:
+ case ANALOG_SIG_FXOKS:
+ /* Pick up the line */
+ ast_debug(1, "Took %s off hook\n", ast->name);
+ if (p->hanguponpolarityswitch) {
+ gettimeofday(&p->polaritydelaytv, NULL);
+ }
+ res = analog_off_hook(p);
+ analog_play_tone(p, index, -1);
+ p->dialing = 0;
+ if ((index == ANALOG_SUB_REAL) && p->subs[ANALOG_SUB_THREEWAY].inthreeway) {
+ if (oldstate == AST_STATE_RINGING) {
+ ast_debug(1, "Finally swapping real and threeway\n");
+ analog_play_tone(p, ANALOG_SUB_THREEWAY, -1);
+ analog_swap_subs(p, ANALOG_SUB_THREEWAY, ANALOG_SUB_REAL);
+ p->owner = p->subs[ANALOG_SUB_REAL].owner;
+ }
+ }
+ if ((p->sig == ANALOG_SIG_FXSLS) || (p->sig == ANALOG_SIG_FXSKS) || (p->sig == ANALOG_SIG_FXSGS)) {
+ analog_set_echocanceller(p, 1);
+ analog_train_echocanceller(p);
+ }
+ break;
+ default:
+ ast_log(LOG_WARNING, "Don't know how to answer signalling %d (channel %d)\n", p->sig, p->channel);
+ res = -1;
+ }
+ ast_setstate(ast, AST_STATE_UP);
+ return res;
+}
+
+static int analog_handles_digit(struct ast_frame *f)
+{
+ char subclass = toupper(f->subclass);
+
+ switch (subclass) {
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '9':
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+void analog_handle_dtmfup(struct analog_pvt *p, struct ast_channel *ast, enum analog_sub index, struct ast_frame **dest)
+{
+ struct ast_frame *f = *dest;
+
+ if (p->callwaitcas) {
+ if ((f->subclass == 'A') || (f->subclass == 'D')) {
+ ast_log(LOG_ERROR, "Got some DTMF, but it's for the CAS\n");
+ p->cid.cid_name = p->callwait_name;
+ p->cid.cid_num = p->callwait_num;
+ analog_send_callerid(p, 1, &p->cid);
+ }
+ if (analog_handles_digit(f))
+ p->callwaitcas = 0;
+ p->subs[index].f.frametype = AST_FRAME_NULL;
+ p->subs[index].f.subclass = 0;
+ *dest = &p->subs[index].f;
+ } else {
+ analog_cb_handle_dtmfup(p, ast, index, dest);
+ }
+}
+
+static int analog_my_getsigstr(struct ast_channel *chan, char *str, const char *term, int ms)
+{
+ char c;
+
+ *str = 0; /* start with empty output buffer */
+ for (;;)
+ {
+ /* Wait for the first digit (up to specified ms). */
+ c = ast_waitfordigit(chan, ms);
+ /* if timeout, hangup or error, return as such */
+ if (c < 1)
+ return c;
+ *str++ = c;
+ *str = 0;
+ if (strchr(term, c))
+ return 1;
+ }
+}
+
+static int analog_handle_notify_message(struct ast_channel *chan, struct analog_pvt *p, int cid_flags, int neon_mwievent)
+{
+ if (p->calls->handle_notify_message) {
+ p->calls->handle_notify_message(chan, p->chan_pvt, cid_flags, neon_mwievent);
+ return 0;
+ }
+ else
+ return -1;
+}
+
+static int analog_increase_ss_count(struct analog_pvt *p)
+{
+ if (p->calls->increase_ss_count) {
+ p->calls->increase_ss_count();
+ return 0;
+ } else
+ return -1;
+}
+
+static int analog_decrease_ss_count(struct analog_pvt *p)
+{
+ if (p->calls->decrease_ss_count) {
+ p->calls->decrease_ss_count();
+ return 0;
+ } else
+ return -1;
+}
+
+#define ANALOG_NEED_MFDETECT(p) (((p)->sig == ANALOG_SIG_FEATDMF) || ((p)->sig == ANALOG_SIG_FEATDMF_TA) || ((p)->sig == ANALOG_SIG_E911) || ((p)->sig == ANALOG_SIG_FGC_CAMA) || ((p)->sig == ANALOG_SIG_FGC_CAMAMF) || ((p)->sig == ANALOG_SIG_FEATB))
+
+/* Note by jpeeler: This function has a rather large section of code ifdefed
+ * away. I'd like to leave the code there until more testing is done and I
+ * know for sure that nothing got left out. The plan is at the latest for this
+ * comment and code below to be removed shortly after the merging of sig_pri.
+ */
+static void *__analog_ss_thread(void *data)
+{
+ struct analog_pvt *p = data;
+ struct ast_channel *chan = p->ss_astchan;
+ char exten[AST_MAX_EXTENSION] = "";
+ char exten2[AST_MAX_EXTENSION] = "";
+ char dtmfcid[300];
+ char dtmfbuf[300];
+ char namebuf[ANALOG_MAX_CID];
+ char numbuf[ANALOG_MAX_CID];
+ struct callerid_state *cs = NULL;
+ char *name = NULL, *number = NULL;
+ int flags;
+#if 0
+ unsigned char buf[256];
+ int distMatches;
+ int curRingData[3];
+ int receivedRingT;
+ int samples = 0;
+ int counter1;
+ int counter;
+ int i;
+#endif
+ int timeout;
+ int getforward = 0;
+ char *s1, *s2;
+ int len = 0;
+ int res;
+ int index;
+
+ analog_increase_ss_count(p);
+
+ ast_log(LOG_DEBUG, "%s %d\n", __FUNCTION__, p->channel);
+
+ /* in the bizarre case where the channel has become a zombie before we
+ even get started here, abort safely
+ */
+ if (!p) {
+ ast_log(LOG_WARNING, "Channel became a zombie before simple switch could be started (%s)\n", chan->name);
+ ast_hangup(chan);
+ goto quit;
+ }
+
+ ast_verb(3, "Starting simple switch on '%s'\n", chan->name);
+ index = analog_get_index(chan, p, 1);
+ if (index < 0) {
+ ast_log(LOG_WARNING, "Huh?\n");
+ ast_hangup(chan);
+ goto quit;
+ }
+ analog_dsp_reset_and_flush_digits(p);
+ switch (p->sig) {
+ case ANALOG_SIG_FEATD:
+ case ANALOG_SIG_FEATDMF:
+ case ANALOG_SIG_FEATDMF_TA:
+ case ANALOG_SIG_E911:
+ case ANALOG_SIG_FGC_CAMAMF:
+ case ANALOG_SIG_FEATB:
+ case ANALOG_SIG_EMWINK:
+ case ANALOG_SIG_SF_FEATD:
+ case ANALOG_SIG_SF_FEATDMF:
+ case ANALOG_SIG_SF_FEATB:
+ case ANALOG_SIG_SFWINK:
+ if (analog_wink(p, index))
+ goto quit;
+ /* Fall through */
+ case ANALOG_SIG_EM:
+ case ANALOG_SIG_EM_E1:
+ case ANALOG_SIG_SF:
+ case ANALOG_SIG_FGC_CAMA:
+ res = analog_play_tone(p, index, -1);
+
+ analog_dsp_reset_and_flush_digits(p);
+
+ if (ANALOG_NEED_MFDETECT(p)) {
+ analog_dsp_set_digitmode(p, ANALOG_DIGITMODE_MF);
+ } else
+ analog_dsp_set_digitmode(p, ANALOG_DIGITMODE_DTMF);
+
+ memset(dtmfbuf, 0, sizeof(dtmfbuf));
+ /* Wait for the first digit only if immediate=no */
+ if (!p->immediate)
+ /* Wait for the first digit (up to 5 seconds). */
[... 2279 lines stripped ...]
More information about the asterisk-commits
mailing list