Skip to content
Snippets Groups Projects
sig_analog.c 121 KiB
Newer Older
  • Learn to ignore specific revisions
  • /*
     * Asterisk -- An open source telephony toolkit.
     *
     * Copyright (C) 1999 - 2009, Digium, Inc.
     *
     * Mark Spencer <markster@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@digium.com>
     */
    
    
    /*** MODULEINFO
    	<support_level>core</support_level>
     ***/
    
    
    #include "asterisk.h"
    
    #include <errno.h>
    #include <ctype.h>
    
    #include "asterisk/utils.h"
    #include "asterisk/options.h"
    
    #include "asterisk/pickup.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 "asterisk/causes.h"
    
    #include "asterisk/features_config.h"
    
    #include "asterisk/bridge.h"
    
    /*! \note
     * Define if you want to check the hook state for an FXO (FXS signalled) interface
     * before dialing on it.  Certain FXO interfaces always think they're out of
     * service with this method however.
     */
    /* #define DAHDI_CHECK_HOOKSTATE */
    
    
    #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. */
    };
    
    
    #define ISTRUNK(p) ((p->sig == ANALOG_SIG_FXSLS) || (p->sig == ANALOG_SIG_FXSKS) || \
    					(p->sig == ANALOG_SIG_FXSGS))
    
    
    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 (analog_callbacks.start_cid_detect) {
    		return analog_callbacks.start_cid_detect(p->chan_pvt, cid_signalling);
    
    }
    
    static int analog_stop_cid_detect(struct analog_pvt *p)
    {
    
    	if (analog_callbacks.stop_cid_detect) {
    		return analog_callbacks.stop_cid_detect(p->chan_pvt);
    
    }
    
    static int analog_get_callerid(struct analog_pvt *p, char *name, char *number, enum analog_event *ev, size_t timeout)
    {
    
    	if (analog_callbacks.get_callerid) {
    		return analog_callbacks.get_callerid(p->chan_pvt, name, number, ev, timeout);
    
    static const char *analog_get_orig_dialstring(struct analog_pvt *p)
    {
    
    	if (analog_callbacks.get_orig_dialstring) {
    		return analog_callbacks.get_orig_dialstring(p->chan_pvt);
    
    static int analog_get_event(struct analog_pvt *p)
    {
    
    	if (analog_callbacks.get_event) {
    		return analog_callbacks.get_event(p->chan_pvt);
    
    }
    
    static int analog_wait_event(struct analog_pvt *p)
    {
    
    	if (analog_callbacks.wait_event) {
    		return analog_callbacks.wait_event(p->chan_pvt);
    
    static int analog_have_progressdetect(struct analog_pvt *p)
    {
    
    	if (analog_callbacks.have_progressdetect) {
    		return analog_callbacks.have_progressdetect(p->chan_pvt);
    
    	}
    	/* Don't have progress detection. */
    	return 0;
    }
    
    
    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;
    
    	} else if (!strcasecmp(value, "dtmf")) {
    		return ANALOG_CID_START_DTMF_NOALERT;
    
    	}
    
    	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";
    
    	case ANALOG_CID_START_DTMF_NOALERT:
    		return "DTMF";
    
    	}
    
    	return "Unknown";
    }
    
    static char *analog_event2str(enum analog_event event)
    {
    	char *res;
    	switch (event) {
    	case ANALOG_EVENT_ONHOOK:
    		res = "ANALOG_EVENT_ONHOOK";
    		break;
    	case ANALOG_EVENT_RINGOFFHOOK:
    		res = "ANALOG_EVENT_RINGOFFHOOK";
    		break;
    
    	case ANALOG_EVENT_WINKFLASH:
    		res = "ANALOG_EVENT_WINKFLASH";
    		break;
    
    	case ANALOG_EVENT_ALARM:
    		res = "ANALOG_EVENT_ALARM";
    		break;
    	case ANALOG_EVENT_NOALARM:
    		res = "ANALOG_EVENT_NOALARM";
    		break;
    
    	case ANALOG_EVENT_DIALCOMPLETE:
    		res = "ANALOG_EVENT_DIALCOMPLETE";
    		break;
    
    	case ANALOG_EVENT_HOOKCOMPLETE:
    		res = "ANALOG_EVENT_HOOKCOMPLETE";
    		break;
    
    	case ANALOG_EVENT_PULSE_START:
    		res = "ANALOG_EVENT_PULSE_START";
    		break;
    
    	case ANALOG_EVENT_POLARITY:
    		res = "ANALOG_EVENT_POLARITY";
    		break;
    
    	case ANALOG_EVENT_RINGBEGIN:
    		res = "ANALOG_EVENT_RINGBEGIN";
    		break;
    	case ANALOG_EVENT_EC_DISABLED:
    		res = "ANALOG_EVENT_EC_DISABLED";
    		break;
    
    	case ANALOG_EVENT_RINGERON:
    		res = "ANALOG_EVENT_RINGERON";
    		break;
    	case ANALOG_EVENT_RINGEROFF:
    		res = "ANALOG_EVENT_RINGEROFF";
    		break;
    
    	case ANALOG_EVENT_REMOVED:
    		res = "ANALOG_EVENT_REMOVED";
    		break;
    
    	case ANALOG_EVENT_NEONMWI_ACTIVE:
    		res = "ANALOG_EVENT_NEONMWI_ACTIVE";
    		break;
    	case ANALOG_EVENT_NEONMWI_INACTIVE:
    		res = "ANALOG_EVENT_NEONMWI_INACTIVE";
    		break;
    
    #ifdef HAVE_DAHDI_ECHOCANCEL_FAX_MODE
    	case ANALOG_EVENT_TX_CED_DETECTED:
    		res = "ANALOG_EVENT_TX_CED_DETECTED";
    		break;
    	case ANALOG_EVENT_RX_CED_DETECTED:
    		res = "ANALOG_EVENT_RX_CED_DETECTED";
    		break;
    	case ANALOG_EVENT_EC_NLP_DISABLED:
    		res = "ANALOG_EVENT_EC_NLP_DISABLED";
    		break;
    	case ANALOG_EVENT_EC_NLP_ENABLED:
    		res = "ANALOG_EVENT_EC_NLP_ENABLED";
    		break;
    #endif
    	case ANALOG_EVENT_PULSEDIGIT:
    		res = "ANALOG_EVENT_PULSEDIGIT";
    		break;
    	case ANALOG_EVENT_DTMFDOWN:
    		res = "ANALOG_EVENT_DTMFDOWN";
    		break;
    	case ANALOG_EVENT_DTMFUP:
    		res = "ANALOG_EVENT_DTMFUP";
    		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 %u and %u\n", a, b);
    
    
    	towner = p->subs[a].owner;
    	p->subs[a].owner = p->subs[b].owner;
    	p->subs[b].owner = towner;
    
    
    	tinthreeway = p->subs[a].inthreeway;
    	p->subs[a].inthreeway = p->subs[b].inthreeway;
    
    	p->subs[b].inthreeway = tinthreeway;
    
    
    	if (analog_callbacks.swap_subs) {
    		analog_callbacks.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)
    {
    
    	if (analog_callbacks.allocate_sub) {
    
    		res = analog_callbacks.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 (analog_callbacks.unallocate_sub) {
    		return analog_callbacks.unallocate_sub(p->chan_pvt, x);
    
    static int analog_send_callerid(struct analog_pvt *p, int cwcid, struct ast_party_caller *caller)
    
    	ast_debug(1, "Sending callerid.  CID_NAME: '%s' CID_NUM: '%s'\n",
    		caller->id.name.str,
    		caller->id.number.str);
    
    	if (analog_callbacks.send_callerid) {
    		return analog_callbacks.send_callerid(p->chan_pvt, cwcid, caller);
    
    #define analog_get_index(ast, p, nullok)	_analog_get_index(ast, p, nullok, __PRETTY_FUNCTION__, __LINE__)
    static int _analog_get_index(struct ast_channel *ast, struct analog_pvt *p, int nullok, const char *fname, unsigned long line)
    
    	if (p->subs[ANALOG_SUB_REAL].owner == ast) {
    
    	} 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;
    
    			ast_log(LOG_WARNING,
    				"Unable to get index for '%s' on channel %d (%s(), line %lu)\n",
    
    				ast ? ast_channel_name(ast) : "", p->channel, fname, line);
    
    	}
    	return res;
    }
    
    static int analog_dsp_reset_and_flush_digits(struct analog_pvt *p)
    {
    
    	if (analog_callbacks.dsp_reset_and_flush_digits) {
    		return analog_callbacks.dsp_reset_and_flush_digits(p->chan_pvt);
    
    	}
    
    	/* 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 (analog_callbacks.play_tone) {
    		return analog_callbacks.play_tone(p->chan_pvt, sub, tone);
    
    static void analog_set_new_owner(struct analog_pvt *p, struct ast_channel *new_owner)
    {
    	p->owner = new_owner;
    
    	if (analog_callbacks.set_new_owner) {
    		analog_callbacks.set_new_owner(p->chan_pvt, new_owner);
    
    static struct ast_channel * analog_new_ast_channel(struct analog_pvt *p, int state, int startpbx, enum analog_sub sub, const struct ast_channel *requestor)
    
    	if (!analog_callbacks.new_ast_channel) {
    
    	c = analog_callbacks.new_ast_channel(p->chan_pvt, state, startpbx, sub, requestor);
    
    		ast_channel_call_forward_set(c, p->call_forward);
    
    		analog_set_new_owner(p, c);
    
    	return c;
    }
    
    static int analog_set_echocanceller(struct analog_pvt *p, int enable)
    {
    
    	if (analog_callbacks.set_echocanceller) {
    		return analog_callbacks.set_echocanceller(p->chan_pvt, enable);
    
    }
    
    static int analog_train_echocanceller(struct analog_pvt *p)
    {
    
    	if (analog_callbacks.train_echocanceller) {
    		return analog_callbacks.train_echocanceller(p->chan_pvt);
    
    }
    
    static int analog_is_off_hook(struct analog_pvt *p)
    {
    
    	if (analog_callbacks.is_off_hook) {
    		return analog_callbacks.is_off_hook(p->chan_pvt);
    
    }
    
    static int analog_ring(struct analog_pvt *p)
    {
    
    	if (analog_callbacks.ring) {
    		return analog_callbacks.ring(p->chan_pvt);
    
    static int analog_flash(struct analog_pvt *p)
    {
    
    	if (analog_callbacks.flash) {
    		return analog_callbacks.flash(p->chan_pvt);
    
    static int analog_start(struct analog_pvt *p)
    {
    
    	if (analog_callbacks.start) {
    		return analog_callbacks.start(p->chan_pvt);
    
    }
    
    static int analog_dial_digits(struct analog_pvt *p, enum analog_sub sub, struct analog_dialoperation *dop)
    {
    
    	if (analog_callbacks.dial_digits) {
    		return analog_callbacks.dial_digits(p->chan_pvt, sub, dop);
    
    }
    
    static int analog_on_hook(struct analog_pvt *p)
    {
    
    	if (analog_callbacks.on_hook) {
    		return analog_callbacks.on_hook(p->chan_pvt);
    
    static void analog_set_outgoing(struct analog_pvt *p, int is_outgoing)
    {
    	p->outgoing = is_outgoing;
    
    	if (analog_callbacks.set_outgoing) {
    		analog_callbacks.set_outgoing(p->chan_pvt, is_outgoing);
    
    static int analog_check_for_conference(struct analog_pvt *p)
    {
    
    	if (analog_callbacks.check_for_conference) {
    		return analog_callbacks.check_for_conference(p->chan_pvt);
    
    }
    
    static void analog_all_subchannels_hungup(struct analog_pvt *p)
    {
    
    	if (analog_callbacks.all_subchannels_hungup) {
    		analog_callbacks.all_subchannels_hungup(p->chan_pvt);
    
    }
    
    static void analog_unlock_private(struct analog_pvt *p)
    {
    
    	if (analog_callbacks.unlock_private) {
    		analog_callbacks.unlock_private(p->chan_pvt);
    
    }
    
    static void analog_lock_private(struct analog_pvt *p)
    {
    
    	if (analog_callbacks.lock_private) {
    		analog_callbacks.lock_private(p->chan_pvt);
    
    
    static void analog_deadlock_avoidance_private(struct analog_pvt *p)
    {
    
    	if (analog_callbacks.deadlock_avoidance_private) {
    		analog_callbacks.deadlock_avoidance_private(p->chan_pvt);
    
    	} else {
    		/* Fallback to manual avoidance if callback not present. */
    		analog_unlock_private(p);
    		usleep(1);
    		analog_lock_private(p);
    	}
    }
    
    
    /*!
     * \internal
     * \brief Obtain the specified subchannel owner lock if the owner exists.
     *
     * \param pvt Analog private struct.
     * \param sub_idx Subchannel owner to lock.
     *
     * \note Assumes the analog_lock_private(pvt->chan_pvt) is already obtained.
     *
     * \note
     * Because deadlock avoidance may have been necessary, you need to confirm
     * the state of things before continuing.
     *
     * \return Nothing
     */
    static void analog_lock_sub_owner(struct analog_pvt *pvt, enum analog_sub sub_idx)
    {
    	for (;;) {
    		if (!pvt->subs[sub_idx].owner) {
    			/* No subchannel owner pointer */
    			break;
    		}
    		if (!ast_channel_trylock(pvt->subs[sub_idx].owner)) {
    			/* Got subchannel owner lock */
    			break;
    		}
    		/* We must unlock the private to avoid the possibility of a deadlock */
    
    		analog_deadlock_avoidance_private(pvt);
    
    
    static int analog_off_hook(struct analog_pvt *p)
    {
    
    	if (analog_callbacks.off_hook) {
    		return analog_callbacks.off_hook(p->chan_pvt);
    
    static void analog_set_needringing(struct analog_pvt *p, int value)
    {
    
    	if (analog_callbacks.set_needringing) {
    		analog_callbacks.set_needringing(p->chan_pvt, value);
    
    #if 0
    static void analog_set_polarity(struct analog_pvt *p, int value)
    {
    
    	if (analog_callbacks.set_polarity) {
    		analog_callbacks.set_polarity(p->chan_pvt, value);
    
    	}
    }
    #endif
    
    static void analog_start_polarityswitch(struct analog_pvt *p)
    {
    
    	if (analog_callbacks.start_polarityswitch) {
    		analog_callbacks.start_polarityswitch(p->chan_pvt);
    
    	}
    }
    static void analog_answer_polarityswitch(struct analog_pvt *p)
    {
    
    	if (analog_callbacks.answer_polarityswitch) {
    		analog_callbacks.answer_polarityswitch(p->chan_pvt);
    
    	}
    }
    
    static void analog_hangup_polarityswitch(struct analog_pvt *p)
    {
    
    	if (analog_callbacks.hangup_polarityswitch) {
    		analog_callbacks.hangup_polarityswitch(p->chan_pvt);
    
    static int analog_dsp_set_digitmode(struct analog_pvt *p, enum analog_dsp_digitmode mode)
    {
    
    	if (analog_callbacks.dsp_set_digitmode) {
    		return analog_callbacks.dsp_set_digitmode(p->chan_pvt, mode);
    
    static void analog_cb_handle_dtmf(struct analog_pvt *p, struct ast_channel *ast, enum analog_sub analog_index, struct ast_frame **dest)
    
    	if (analog_callbacks.handle_dtmf) {
    		analog_callbacks.handle_dtmf(p->chan_pvt, ast, analog_index, dest);
    
    }
    
    static int analog_wink(struct analog_pvt *p, enum analog_sub index)
    {
    
    	if (analog_callbacks.wink) {
    		return analog_callbacks.wink(p->chan_pvt, index);
    
    }
    
    static int analog_has_voicemail(struct analog_pvt *p)
    {
    
    	if (analog_callbacks.has_voicemail) {
    		return analog_callbacks.has_voicemail(p->chan_pvt);
    
    }
    
    static int analog_is_dialing(struct analog_pvt *p, enum analog_sub index)
    {
    
    	if (analog_callbacks.is_dialing) {
    		return analog_callbacks.is_dialing(p->chan_pvt, index);
    
    /*!
     * \internal
     * \brief Attempt to transfer 3-way call.
     *
     * \param p Analog private structure.
     *
    
     * \note On entry these locks are held: real-call, private, 3-way call.
     * \note On exit these locks are held: real-call, private.
    
    static int analog_attempt_transfer(struct analog_pvt *p)
    
    {
    	struct ast_channel *owner_real;
    	struct ast_channel *owner_3way;
    
    	owner_real = ast_channel_ref(p->subs[ANALOG_SUB_REAL].owner);
    	owner_3way = ast_channel_ref(p->subs[ANALOG_SUB_THREEWAY].owner);
    
    	ast_verb(3, "TRANSFERRING %s to %s\n",
    		ast_channel_name(owner_3way), ast_channel_name(owner_real));
    
    	ast_channel_unlock(owner_real);
    	ast_channel_unlock(owner_3way);
    	analog_unlock_private(p);
    
    	xfer_res = ast_bridge_transfer_attended(owner_3way, owner_real);
    	if (xfer_res != AST_BRIDGE_TRANSFER_SUCCESS) {
    		ast_softhangup(owner_3way, AST_SOFTHANGUP_DEV);
    		res = -1;
    
    
    	/* Must leave with these locked. */
    	ast_channel_lock(owner_real);
    	analog_lock_private(p);
    
    	ast_channel_unref(owner_real);
    	ast_channel_unref(owner_3way);
    
    	return res;
    
    }
    
    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 (analog_callbacks.conf_add) {
    				analog_callbacks.conf_add(p->chan_pvt, x);
    
    			if (analog_callbacks.conf_del) {
    				analog_callbacks.conf_del(p->chan_pvt, x);
    
    		}
    	}
    	ast_debug(1, "Updated conferencing on %d, with %d conference users\n", p->channel, needconf);
    
    
    	if (analog_callbacks.complete_conference_update) {
    		analog_callbacks.complete_conference_update(p->chan_pvt, needconf);
    
    struct ast_channel * analog_request(struct analog_pvt *p, int *callwait, const struct ast_channel *requestor)
    
    	ast_debug(1, "%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;
    		}
    	}
    
    
    	analog_set_outgoing(p, 1);
    
    	ast = analog_new_ast_channel(p, AST_STATE_RESERVED, 0,
    		p->owner ? ANALOG_SUB_CALLWAIT : ANALOG_SUB_REAL, requestor);
    	if (!ast) {
    
    		analog_set_outgoing(p, 0);
    
    int analog_available(struct analog_pvt *p)
    
    	ast_debug(1, "%s %d\n", __FUNCTION__, p->channel);
    
    
    	/* If do not disturb, definitely not */
    
    	/* If guard time, definitely not */
    
    	if (p->guardtime && (time(NULL) < p->guardtime)) {
    
    
    	/* If no owner definitely available */
    	if (!p->owner) {
    		offhook = analog_is_off_hook(p);
    
    
    		/* TDM FXO card, "onhook" means out of service (no battery on the line) */
    		if ((p->sig == ANALOG_SIG_FXSLS) || (p->sig == ANALOG_SIG_FXSKS) || (p->sig == ANALOG_SIG_FXSGS)) {
    #ifdef DAHDI_CHECK_HOOKSTATE
    
    #endif
    		/* TDM FXS card, "offhook" means someone took the hook off so it's unavailable! */
    
    		} 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)) {
    
    
    	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 ((ast_channel_state(p->owner) != AST_STATE_UP) &&
    	    ((ast_channel_state(p->owner) != 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)
    {
    
    	p->callwaitcas = 0;
    
    	if (analog_callbacks.stop_callwait) {
    		return analog_callbacks.stop_callwait(p->chan_pvt);
    
    }
    
    static int analog_callwait(struct analog_pvt *p)
    {
    
    	p->callwaitcas = p->callwaitingcallerid;
    
    	if (analog_callbacks.callwait) {
    		return analog_callbacks.callwait(p->chan_pvt);
    
    static void analog_set_callwaiting(struct analog_pvt *p, int callwaiting_enable)
    {
    	p->callwaiting = callwaiting_enable;
    
    	if (analog_callbacks.set_callwaiting) {
    		analog_callbacks.set_callwaiting(p->chan_pvt, callwaiting_enable);
    
    static void analog_set_cadence(struct analog_pvt *p, struct ast_channel *chan)
    {
    
    	if (analog_callbacks.set_cadence) {
    		analog_callbacks.set_cadence(p->chan_pvt, &p->cidrings, chan);
    
    static void analog_set_dialing(struct analog_pvt *p, int is_dialing)
    
    	if (analog_callbacks.set_dialing) {
    		analog_callbacks.set_dialing(p->chan_pvt, is_dialing);
    
    	}
    }
    
    static void analog_set_alarm(struct analog_pvt *p, int in_alarm)
    {
    	p->inalarm = in_alarm;
    
    	if (analog_callbacks.set_alarm) {
    		analog_callbacks.set_alarm(p->chan_pvt, in_alarm);
    
    static void analog_set_ringtimeout(struct analog_pvt *p, int ringt)
    {
    	p->ringt = ringt;
    
    	if (analog_callbacks.set_ringtimeout) {
    		analog_callbacks.set_ringtimeout(p->chan_pvt, ringt);
    
    static void analog_set_waitingfordt(struct analog_pvt *p, struct ast_channel *ast)
    {
    
    	if (analog_callbacks.set_waitingfordt) {
    		analog_callbacks.set_waitingfordt(p->chan_pvt, ast);
    
    	}
    }
    
    static int analog_check_waitingfordt(struct analog_pvt *p)
    {
    
    	if (analog_callbacks.check_waitingfordt) {
    		return analog_callbacks.check_waitingfordt(p->chan_pvt);
    
    	}
    
    	return 0;
    }
    
    static void analog_set_confirmanswer(struct analog_pvt *p, int flag)
    {
    
    	if (analog_callbacks.set_confirmanswer) {
    		analog_callbacks.set_confirmanswer(p->chan_pvt, flag);
    
    	}
    }
    
    static int analog_check_confirmanswer(struct analog_pvt *p)
    {
    
    	if (analog_callbacks.check_confirmanswer) {
    		return analog_callbacks.check_confirmanswer(p->chan_pvt);
    
    static void analog_cancel_cidspill(struct analog_pvt *p)
    {
    
    	if (analog_callbacks.cancel_cidspill) {
    		analog_callbacks.cancel_cidspill(p->chan_pvt);
    
    static int analog_confmute(struct analog_pvt *p, int mute)
    {
    
    	if (analog_callbacks.confmute) {
    		return analog_callbacks.confmute(p->chan_pvt, mute);
    
    	}
    	return 0;
    }
    
    static void analog_set_pulsedial(struct analog_pvt *p, int flag)
    {
    
    	if (analog_callbacks.set_pulsedial) {
    		analog_callbacks.set_pulsedial(p->chan_pvt, flag);
    
    static int analog_set_linear_mode(struct analog_pvt *p, enum analog_sub sub, int linear_mode)
    
    	if (analog_callbacks.set_linear_mode) {
    
    		/* Return provides old linear_mode setting or error indication */
    
    		return analog_callbacks.set_linear_mode(p->chan_pvt, sub, linear_mode);
    
    static void analog_set_inthreeway(struct analog_pvt *p, enum analog_sub sub, int inthreeway)
    {
    	p->subs[sub].inthreeway = inthreeway;
    
    	if (analog_callbacks.set_inthreeway) {
    		analog_callbacks.set_inthreeway(p->chan_pvt, sub, inthreeway);
    
    int analog_call(struct analog_pvt *p, struct ast_channel *ast, const char *rdest, int timeout)
    
    	int res, idx, mysig;
    
    	char *c, *n, *l;
    	char dest[256]; /* must be same length as p->dialdest */
    
    
    	ast_debug(1, "CALLING CID_NAME: %s CID_NUM:: %s\n",
    
    		S_COR(ast_channel_connected(ast)->id.name.valid, ast_channel_connected(ast)->id.name.str, ""),
    		S_COR(ast_channel_connected(ast)->id.number.valid, ast_channel_connected(ast)->id.number.str, ""));
    
    
    	ast_copy_string(dest, rdest, sizeof(dest));
    	ast_copy_string(p->dialdest, rdest, sizeof(p->dialdest));
    
    
    	if ((ast_channel_state(ast) == AST_STATE_BUSY)) {
    
    		ast_queue_control(p->subs[ANALOG_SUB_REAL].owner, AST_CONTROL_BUSY);
    		return 0;
    	}
    
    
    	if ((ast_channel_state(ast) != AST_STATE_DOWN) && (ast_channel_state(ast) != AST_STATE_RESERVED)) {
    
    		ast_log(LOG_WARNING, "analog_call called on %s, neither down nor reserved\n", ast_channel_name(ast));
    
    	analog_set_outgoing(p, 1);