Skip to content
Snippets Groups Projects
sig_pri.c 295 KiB
Newer Older
  • Learn to ignore specific revisions
  •  * \since 1.8
     *
     * \param p Channel private control structure.
     *
     * \return Nothing
     */
    static void sig_pri_open_media(struct sig_pri_chan *p)
    {
    	if (p->no_b_channel) {
    		return;
    	}
    
    
    	if (sig_pri_callbacks.open_media) {
    		sig_pri_callbacks.open_media(p->chan_pvt);
    
    /*!
     * \internal
     * \brief Post an AMI B channel association event.
     * \since 1.8
     *
     * \param p Channel private control structure.
     *
     * \note Assumes the private and owner are locked.
     *
     * \return Nothing
     */
    static void sig_pri_ami_channel_event(struct sig_pri_chan *p)
    {
    
    	if (sig_pri_callbacks.ami_channel_event) {
    		sig_pri_callbacks.ami_channel_event(p->chan_pvt, p->owner);
    
    struct ast_channel *sig_pri_request(struct sig_pri_chan *p, enum sig_pri_law law, const struct ast_channel *requestor, int transfercapability)
    
    	ast_debug(1, "%s %d\n", __FUNCTION__, p->channel);
    
    	sig_pri_set_outgoing(p, 1);
    
    	ast = sig_pri_new_ast_channel(p, AST_STATE_RESERVED, law, transfercapability, p->exten, requestor);
    
    		sig_pri_set_outgoing(p, 0);
    
    int pri_is_up(struct sig_pri_span *pri)
    
    	for (x = 0; x < SIG_PRI_NUM_DCHANS; x++) {
    
    		if (pri->dchanavail[x] == DCHAN_AVAILABLE)
    			return 1;
    	}
    	return 0;
    }
    
    
    static const char *pri_order(int level)
    
    {
    	switch (level) {
    	case 0:
    		return "Primary";
    	case 1:
    		return "Secondary";
    	case 2:
    		return "Tertiary";
    	case 3:
    		return "Quaternary";
    	default:
    		return "<Unknown>";
    
    }
    
    /* Returns index of the active dchan */
    
    static int pri_active_dchan_index(struct sig_pri_span *pri)
    
    	for (x = 0; x < SIG_PRI_NUM_DCHANS; x++) {
    
    		if ((pri->dchans[x] == pri->pri))
    
    	ast_log(LOG_WARNING, "No active dchan found!\n");
    	return -1;
    
    static void pri_find_dchan(struct sig_pri_span *pri)
    
    	for (idx = 0; idx < SIG_PRI_NUM_DCHANS; ++idx) {
    		if (!pri->dchans[idx]) {
    			/* No more D channels defined on the span. */
    			break;
    		}
    		if (pri->dchans[idx] == old) {
    			oldslot = idx;
    		}
    		if (newslot < 0 && pri->dchanavail[idx] == DCHAN_AVAILABLE) {
    			newslot = idx;
    
    	/* At this point, idx is a count of how many D-channels are defined on the span. */
    
    	if (1 < idx) {
    		/* We have several D-channels defined on the span.  (NFAS PRI setup) */
    		if (newslot < 0) {
    			/* No D-channels available.  Default to the primary D-channel. */
    			newslot = 0;
    
    			if (!pri->no_d_channels) {
    				pri->no_d_channels = 1;
    				if (old && oldslot != newslot) {
    					ast_log(LOG_WARNING,
    						"Span %d: No D-channels up!  Switching selected D-channel from %s to %s.\n",
    						pri->span, pri_order(oldslot), pri_order(newslot));
    				} else {
    					ast_log(LOG_WARNING, "Span %d: No D-channels up!\n", pri->span);
    				}
    			}
    		} else {
    			pri->no_d_channels = 0;
    		}
    		if (old && oldslot != newslot) {
    			ast_log(LOG_NOTICE,
    				"Switching selected D-channel from %s (fd %d) to %s (fd %d)!\n",
    				pri_order(oldslot), pri->fds[oldslot],
    				pri_order(newslot), pri->fds[newslot]);
    
    		if (newslot < 0) {
    			/* The only D-channel is not up. */
    			newslot = 0;
    
    			if (!pri->no_d_channels) {
    				pri->no_d_channels = 1;
    
    				/*
    				 * This is annoying to see on non-persistent layer 2
    				 * connections.  Let's not complain in that case.
    				 */
    				if (pri->sig != SIG_BRI_PTMP) {
    					ast_log(LOG_WARNING, "Span %d: D-channel is down!\n", pri->span);
    				}
    			}
    		} else {
    			pri->no_d_channels = 0;
    		}
    
    /*!
     * \internal
     * \brief Determine if a private channel structure is in use.
     * \since 1.8
     *
     * \param pvt Channel to determine if in use.
     *
     * \return TRUE if the channel is in use.
     */
    static int sig_pri_is_chan_in_use(struct sig_pri_chan *pvt)
    {
    
    	return pvt->owner || pvt->call || pvt->allocated || pvt->inalarm
    		|| pvt->resetting != SIG_PRI_RESET_IDLE;
    
    }
    
    /*!
     * \brief Determine if a private channel structure is available.
     * \since 1.8
     *
     * \param pvt Channel to determine if available.
     *
     * \return TRUE if the channel is available.
     */
    int sig_pri_is_chan_available(struct sig_pri_chan *pvt)
    {
    	return !sig_pri_is_chan_in_use(pvt)
    #if defined(HAVE_PRI_SERVICE_MESSAGES)
    		/* And not out-of-service */
    		&& !pvt->service_status
    #endif	/* defined(HAVE_PRI_SERVICE_MESSAGES) */
    		;
    }
    
    
    /*!
     * \internal
     * \brief Obtain the sig_pri owner channel lock if the owner exists.
     * \since 1.8
     *
    
     * \param pri PRI span control structure.
    
     * \param chanpos Channel position in the span.
     *
     * \note Assumes the pri->lock is already obtained.
     * \note Assumes the sig_pri_lock_private(pri->pvts[chanpos]) is already obtained.
     *
     * \return Nothing
     */
    
    static void sig_pri_lock_owner(struct sig_pri_span *pri, int chanpos)
    
    		if (!pri->pvts[chanpos]->owner) {
    			/* There is no owner lock to get. */
    
    		}
    		if (!ast_channel_trylock(pri->pvts[chanpos]->owner)) {
    			/* We got the lock */
    			break;
    		}
    
    
    		/* Avoid deadlock */
    		sig_pri_unlock_private(pri->pvts[chanpos]);
    		DEADLOCK_AVOIDANCE(&pri->lock);
    		sig_pri_lock_private(pri->pvts[chanpos]);
    
    /*!
     * \internal
     * \brief Queue the given frame onto the owner channel.
     * \since 1.8
     *
    
     * \param pri PRI span control structure.
    
     * \param chanpos Channel position in the span.
     * \param frame Frame to queue onto the owner channel.
     *
     * \note Assumes the pri->lock is already obtained.
     * \note Assumes the sig_pri_lock_private(pri->pvts[chanpos]) is already obtained.
     *
     * \return Nothing
     */
    
    static void pri_queue_frame(struct sig_pri_span *pri, int chanpos, struct ast_frame *frame)
    
    {
    	sig_pri_lock_owner(pri, chanpos);
    	if (pri->pvts[chanpos]->owner) {
    		ast_queue_frame(pri->pvts[chanpos]->owner, frame);
    		ast_channel_unlock(pri->pvts[chanpos]->owner);
    	}
    }
    
    /*!
     * \internal
     * \brief Queue a control frame of the specified subclass onto the owner channel.
     * \since 1.8
     *
    
     * \param pri PRI span control structure.
    
     * \param chanpos Channel position in the span.
     * \param subclass Control frame subclass to queue onto the owner channel.
     *
     * \note Assumes the pri->lock is already obtained.
     * \note Assumes the sig_pri_lock_private(pri->pvts[chanpos]) is already obtained.
     *
     * \return Nothing
     */
    
    static void pri_queue_control(struct sig_pri_span *pri, int chanpos, int subclass)
    
    {
    	struct ast_frame f = {AST_FRAME_CONTROL, };
    
    	struct sig_pri_chan *p = pri->pvts[chanpos];
    
    	if (sig_pri_callbacks.queue_control) {
    		sig_pri_callbacks.queue_control(p->chan_pvt, subclass);
    
    	f.subclass.integer = subclass;
    
    	pri_queue_frame(pri, chanpos, &f);
    
    /*!
     * \internal
     * \brief Queue a PVT_CAUSE_CODE frame onto the owner channel.
     * \since 11
     *
     * \param pri PRI span control structure.
     * \param chanpos Channel position in the span.
     * \param cause String describing the cause to be placed into the frame.
     *
     * \note Assumes the pri->lock is already obtained.
     * \note Assumes the sig_pri_lock_private(pri->pvts[chanpos]) is already obtained.
     *
     * \return Nothing
     */
    
    static void pri_queue_pvt_cause_data(struct sig_pri_span *pri, int chanpos, const char *cause, int ast_cause)
    
    {
    	struct ast_channel *chan;
    	struct ast_control_pvt_cause_code *cause_code;
    
    	sig_pri_lock_owner(pri, chanpos);
    	chan = pri->pvts[chanpos]->owner;
    	if (chan) {
    		int datalen = sizeof(*cause_code) + strlen(cause);
    
    		cause_code = ast_alloca(datalen);
    
    		cause_code->ast_cause = ast_cause;
    
    		ast_copy_string(cause_code->chan_name, ast_channel_name(chan), AST_CHANNEL_NAME);
    		ast_copy_string(cause_code->code, cause, datalen + 1 - sizeof(*cause_code));
    		ast_queue_control_data(chan, AST_CONTROL_PVT_CAUSE_CODE, cause_code, datalen);
    
    		ast_channel_hangupcause_hash_set(chan, cause_code, datalen);
    
    /*!
     * \internal
     * \brief Find the channel associated with the libpri call.
    
     * \param pri PRI span control structure.
    
     * \param call LibPRI opaque call pointer to find.
     *
     * \note Assumes the pri->lock is already obtained.
     *
     * \retval array-index into private pointer array on success.
     * \retval -1 on error.
     */
    static int pri_find_principle_by_call(struct sig_pri_span *pri, q931_call *call)
    {
    	int idx;
    
    	if (!call) {
    		/* Cannot find a call without a call. */
    		return -1;
    	}
    	for (idx = 0; idx < pri->numchans; ++idx) {
    		if (pri->pvts[idx] && pri->pvts[idx]->call == call) {
    			/* Found the principle */
    			return idx;
    		}
    	}
    	return -1;
    }
    
    
    /*!
     * \internal
     * \brief Kill the call.
    
     *
     * \param pri PRI span control structure.
     * \param call LibPRI opaque call pointer to find.
     * \param cause Reason call was killed.
     *
     * \note Assumes the pvt->pri->lock is already obtained.
     *
     * \return Nothing
     */
    static void sig_pri_kill_call(struct sig_pri_span *pri, q931_call *call, int cause)
    {
    	int chanpos;
    
    	chanpos = pri_find_principle_by_call(pri, call);
    	if (chanpos < 0) {
    		pri_hangup(pri->pri, call, cause);
    		return;
    	}
    	sig_pri_lock_private(pri->pvts[chanpos]);
    	if (!pri->pvts[chanpos]->owner) {
    		pri_hangup(pri->pri, call, cause);
    		pri->pvts[chanpos]->call = NULL;
    		sig_pri_unlock_private(pri->pvts[chanpos]);
    		sig_pri_span_devstate_changed(pri);
    		return;
    	}
    
    	ast_channel_hangupcause_set(pri->pvts[chanpos]->owner, cause);
    
    	pri_queue_control(pri, chanpos, AST_CONTROL_HANGUP);
    	sig_pri_unlock_private(pri->pvts[chanpos]);
    }
    
    
    /*!
     * \internal
     * \brief Find the private structure for the libpri call.
     *
    
     * \param pri PRI span control structure.
    
     * \param channel LibPRI encoded channel ID.
     * \param call LibPRI opaque call pointer.
     *
     * \note Assumes the pri->lock is already obtained.
     *
     * \retval array-index into private pointer array on success.
     * \retval -1 on error.
     */
    
    static int pri_find_principle(struct sig_pri_span *pri, int channel, q931_call *call)
    
    	int prioffset;
    
    
    	if (channel < 0) {
    		/* Channel is not picked yet. */
    		return -1;
    	}
    
    
    	prioffset = PRI_CHANNEL(channel);
    	if (!prioffset || (channel & PRI_HELD_CALL)) {
    
    		/* Find the call waiting call or held call. */
    		return pri_find_principle_by_call(pri, call);
    
    	span = PRI_SPAN(channel);
    	if (!(channel & PRI_EXPLICIT)) {
    		int index;
    
    		index = pri_active_dchan_index(pri);
    		if (index == -1) {
    
    		span = pri->dchan_logical_span[index];
    	}
    
    
    	for (x = 0; x < pri->numchans; x++) {
    
    			&& pri->pvts[x]->prioffset == prioffset
    
    			&& pri->pvts[x]->logicalspan == span
    			&& !pri->pvts[x]->no_b_channel) {
    
    /*!
     * \internal
     * \brief Fixup the private structure associated with the libpri call.
     *
    
     * \param pri PRI span control structure.
    
     * \param principle Array-index into private array to move call to if not already there.
     * \param call LibPRI opaque call pointer to find if need to move call.
     *
     * \note Assumes the pri->lock is already obtained.
     *
     * \retval principle on success.
     * \retval -1 on error.
     */
    
    static int pri_fixup_principle(struct sig_pri_span *pri, int principle, q931_call *call)
    
    	if (principle < 0 || pri->numchans <= principle) {
    		/* Out of rannge */
    		return -1;
    	}
    	if (!call) {
    		/* No call */
    
    	if (pri->pvts[principle] && pri->pvts[principle]->call == call) {
    		/* Call is already on the specified principle. */
    
    	for (x = 0; x < pri->numchans; x++) {
    
    		struct sig_pri_chan *new_chan;
    		struct sig_pri_chan *old_chan;
    
    		if (!pri->pvts[x] || pri->pvts[x]->call != call) {
    
    		/* Found our call */
    		new_chan = pri->pvts[principle];
    		old_chan = pri->pvts[x];
    
    		/* Get locks to safely move to the new private structure. */
    		sig_pri_lock_private(old_chan);
    		sig_pri_lock_owner(pri, x);
    		sig_pri_lock_private(new_chan);
    
    		ast_verb(3, "Moving call (%s) from channel %d to %d.\n",
    
    			old_chan->owner ? ast_channel_name(old_chan->owner) : "",
    
    			old_chan->channel, new_chan->channel);
    
    		if (!sig_pri_is_chan_available(new_chan)) {
    
    				"Can't move call (%s) from channel %d to %d.  It is already in use.\n",
    
    				old_chan->owner ? ast_channel_name(old_chan->owner) : "",
    
    				old_chan->channel, new_chan->channel);
    			sig_pri_unlock_private(new_chan);
    			if (old_chan->owner) {
    				ast_channel_unlock(old_chan->owner);
    			}
    			sig_pri_unlock_private(old_chan);
    
    		sig_pri_fixup_chans(old_chan, new_chan);
    
    		/* Fix it all up now */
    		new_chan->owner = old_chan->owner;
    		old_chan->owner = NULL;
    
    		new_chan->call = old_chan->call;
    		old_chan->call = NULL;
    
    		/* Transfer flags from the old channel. */
    
    #if defined(HAVE_PRI_AOC_EVENTS)
    		new_chan->aoc_s_request_invoke_id_valid = old_chan->aoc_s_request_invoke_id_valid;
    		new_chan->waiting_for_aoce = old_chan->waiting_for_aoce;
    		new_chan->holding_aoce = old_chan->holding_aoce;
    #endif	/* defined(HAVE_PRI_AOC_EVENTS) */
    
    		new_chan->alreadyhungup = old_chan->alreadyhungup;
    		new_chan->isidlecall = old_chan->isidlecall;
    		new_chan->progress = old_chan->progress;
    
    		new_chan->allocated = old_chan->allocated;
    
    		new_chan->outgoing = old_chan->outgoing;
    		new_chan->digital = old_chan->digital;
    
    #if defined(HAVE_PRI_CALL_WAITING)
    		new_chan->is_call_waiting = old_chan->is_call_waiting;
    #endif	/* defined(HAVE_PRI_CALL_WAITING) */
    
    #if defined(HAVE_PRI_AOC_EVENTS)
    
    		old_chan->aoc_s_request_invoke_id_valid = 0;
    		old_chan->waiting_for_aoce = 0;
    
    		old_chan->holding_aoce = 0;
    
    #endif	/* defined(HAVE_PRI_AOC_EVENTS) */
    
    		old_chan->alreadyhungup = 0;
    		old_chan->isidlecall = 0;
    		old_chan->progress = 0;
    
    		old_chan->allocated = 0;
    
    		old_chan->outgoing = 0;
    		old_chan->digital = 0;
    
    #if defined(HAVE_PRI_CALL_WAITING)
    		old_chan->is_call_waiting = 0;
    #endif	/* defined(HAVE_PRI_CALL_WAITING) */
    
    
    		/* More stuff to transfer to the new channel. */
    
    		new_chan->call_level = old_chan->call_level;
    		old_chan->call_level = SIG_PRI_CALL_LEVEL_IDLE;
    
    #if defined(HAVE_PRI_REVERSE_CHARGE)
    		new_chan->reverse_charging_indication = old_chan->reverse_charging_indication;
    #endif	/* defined(HAVE_PRI_REVERSE_CHARGE) */
    #if defined(HAVE_PRI_SETUP_KEYPAD)
    		strcpy(new_chan->keypad_digits, old_chan->keypad_digits);
    #endif	/* defined(HAVE_PRI_SETUP_KEYPAD) */
    
    		strcpy(new_chan->deferred_digits, old_chan->deferred_digits);
    
    		strcpy(new_chan->moh_suggested, old_chan->moh_suggested);
    		new_chan->moh_state = old_chan->moh_state;
    		old_chan->moh_state = SIG_PRI_MOH_STATE_IDLE;
    
    
    #if defined(HAVE_PRI_AOC_EVENTS)
    		new_chan->aoc_s_request_invoke_id = old_chan->aoc_s_request_invoke_id;
    		new_chan->aoc_e = old_chan->aoc_e;
    #endif	/* defined(HAVE_PRI_AOC_EVENTS) */
    
    		strcpy(new_chan->user_tag, old_chan->user_tag);
    
    
    		if (new_chan->no_b_channel) {
    			/* Copy the real channel configuration to the no B channel interface. */
    			new_chan->hidecallerid = old_chan->hidecallerid;
    			new_chan->hidecalleridname = old_chan->hidecalleridname;
    			new_chan->immediate = old_chan->immediate;
    			new_chan->priexclusive = old_chan->priexclusive;
    			new_chan->priindication_oob = old_chan->priindication_oob;
    			new_chan->use_callerid = old_chan->use_callerid;
    			new_chan->use_callingpres = old_chan->use_callingpres;
    			new_chan->stripmsd = old_chan->stripmsd;
    			strcpy(new_chan->context, old_chan->context);
    			strcpy(new_chan->mohinterpret, old_chan->mohinterpret);
    
    			/* Become a member of the old channel span/trunk-group. */
    			new_chan->logicalspan = old_chan->logicalspan;
    			new_chan->mastertrunkgroup = old_chan->mastertrunkgroup;
    
    		} else if (old_chan->no_b_channel) {
    			/*
    			 * We are transitioning from a held/call-waiting channel to a
    			 * real channel so we need to make sure that the media path is
    			 * open.  (Needed especially if the channel is natively
    			 * bridged.)
    			 */
    			sig_pri_open_media(new_chan);
    		}
    
    
    		if (new_chan->owner) {
    			sig_pri_ami_channel_event(new_chan);
    		}
    
    
    		sig_pri_unlock_private(old_chan);
    		if (new_chan->owner) {
    			ast_channel_unlock(new_chan->owner);
    
    		sig_pri_unlock_private(new_chan);
    
    	ast_verb(3, "Call specified, but not found.\n");
    
    /*!
     * \internal
     * \brief Find and fixup the private structure associated with the libpri call.
     *
     * \param pri PRI span control structure.
     * \param channel LibPRI encoded channel ID.
     * \param call LibPRI opaque call pointer.
     *
     * \details
     * This is a combination of pri_find_principle() and pri_fixup_principle()
     * to reduce code redundancy and to make handling several PRI_EVENT_xxx's
     * consistent for the current architecture.
     *
     * \note Assumes the pri->lock is already obtained.
     *
     * \retval array-index into private pointer array on success.
     * \retval -1 on error.
     */
    static int pri_find_fixup_principle(struct sig_pri_span *pri, int channel, q931_call *call)
    {
    	int chanpos;
    
    	chanpos = pri_find_principle(pri, channel, call);
    	if (chanpos < 0) {
    		ast_log(LOG_WARNING, "Span %d: PRI requested channel %d/%d is unconfigured.\n",
    			pri->span, PRI_SPAN(channel), PRI_CHANNEL(channel));
    		sig_pri_kill_call(pri, call, PRI_CAUSE_IDENTIFIED_CHANNEL_NOTEXIST);
    		return -1;
    	}
    	chanpos = pri_fixup_principle(pri, chanpos, call);
    	if (chanpos < 0) {
    		ast_log(LOG_WARNING, "Span %d: PRI requested channel %d/%d is not available.\n",
    			pri->span, PRI_SPAN(channel), PRI_CHANNEL(channel));
    		/*
    		 * Using Q.931 section 5.2.3.1 b) as the reason for picking
    		 * PRI_CAUSE_CHANNEL_UNACCEPTABLE.  Receiving a
    		 * PRI_CAUSE_REQUESTED_CHAN_UNAVAIL would cause us to restart
    		 * that channel (which is not specified by Q.931) and kill some
    		 * other call which would be bad.
    		 */
    		sig_pri_kill_call(pri, call, PRI_CAUSE_CHANNEL_UNACCEPTABLE);
    		return -1;
    	}
    	return chanpos;
    }
    
    
    static char * redirectingreason2str(int redirectingreason)
    {
    	switch (redirectingreason) {
    	case 0:
    		return "UNKNOWN";
    	case 1:
    		return "BUSY";
    	case 2:
    		return "NO_REPLY";
    	case 0xF:
    		return "UNCONDITIONAL";
    	default:
    		return "NOREDIRECT";
    	}
    }
    
    static char *dialplan2str(int dialplan)
    {
    	if (dialplan == -1) {
    		return("Dynamically set dialplan in ISDN");
    	}
    	return (pri_plan2str(dialplan));
    }
    
    
    /*!
     * \internal
     * \brief Apply numbering plan prefix to the given number.
     *
     * \param buf Buffer to put number into.
     * \param size Size of given buffer.
     * \param pri PRI span control structure.
     * \param number Number to apply numbering plan.
     * \param plan Numbering plan to apply.
     *
     * \return Nothing
     */
    static void apply_plan_to_number(char *buf, size_t size, const struct sig_pri_span *pri, const char *number, int plan)
    
    {
    	switch (plan) {
    	case PRI_INTERNATIONAL_ISDN:		/* Q.931 dialplan == 0x11 international dialplan => prepend international prefix digits */
    		snprintf(buf, size, "%s%s", pri->internationalprefix, number);
    		break;
    	case PRI_NATIONAL_ISDN:			/* Q.931 dialplan == 0x21 national dialplan => prepend national prefix digits */
    		snprintf(buf, size, "%s%s", pri->nationalprefix, number);
    		break;
    	case PRI_LOCAL_ISDN:			/* Q.931 dialplan == 0x41 local dialplan => prepend local prefix digits */
    		snprintf(buf, size, "%s%s", pri->localprefix, number);
    		break;
    	case PRI_PRIVATE:			/* Q.931 dialplan == 0x49 private dialplan => prepend private prefix digits */
    		snprintf(buf, size, "%s%s", pri->privateprefix, number);
    		break;
    	case PRI_UNKNOWN:			/* Q.931 dialplan == 0x00 unknown dialplan => prepend unknown prefix digits */
    		snprintf(buf, size, "%s%s", pri->unknownprefix, number);
    		break;
    	default:				/* other Q.931 dialplan => don't twiddle with callingnum */
    		snprintf(buf, size, "%s", number);
    		break;
    	}
    }
    
    
    /*!
     * \internal
     * \brief Apply numbering plan prefix to the given number if the number exists.
     *
     * \param buf Buffer to put number into.
     * \param size Size of given buffer.
     * \param pri PRI span control structure.
     * \param number Number to apply numbering plan.
     * \param plan Numbering plan to apply.
     *
     * \return Nothing
     */
    static void apply_plan_to_existing_number(char *buf, size_t size, const struct sig_pri_span *pri, const char *number, int plan)
    {
    	/* Make sure a number exists so the prefix isn't placed on an empty string. */
    	if (ast_strlen_zero(number)) {
    		if (size) {
    			*buf = '\0';
    		}
    		return;
    	}
    	apply_plan_to_number(buf, size, pri, number, plan);
    }
    
    
    /*!
     * \internal
     * \brief Restart the next channel we think is idle on the span.
     *
     * \param pri PRI span control structure.
     *
     * \note Assumes the pri->lock is already obtained.
     *
     * \return Nothing
     */
    static void pri_check_restart(struct sig_pri_span *pri)
    
    #if defined(HAVE_PRI_SERVICE_MESSAGES)
    
    #endif	/* defined(HAVE_PRI_SERVICE_MESSAGES) */
    
    
    	for (++pri->resetpos; pri->resetpos < pri->numchans; ++pri->resetpos) {
    		if (!pri->pvts[pri->resetpos]
    
    			|| pri->pvts[pri->resetpos]->no_b_channel
    
    			|| sig_pri_is_chan_in_use(pri->pvts[pri->resetpos])) {
    			continue;
    		}
    
    #if defined(HAVE_PRI_SERVICE_MESSAGES)
    		why = pri->pvts[pri->resetpos]->service_status;
    		if (why) {
    
    			ast_log(LOG_NOTICE,
    				"Span %d: channel %d out-of-service (reason: %s), not sending RESTART\n",
    				pri->span, pri->pvts[pri->resetpos]->channel,
    				(why & SRVST_FAREND) ? (why & SRVST_NEAREND) ? "both ends" : "far end" : "near end");
    			continue;
    
    #endif	/* defined(HAVE_PRI_SERVICE_MESSAGES) */
    
    		break;
    	}
    	if (pri->resetpos < pri->numchans) {
    
    		/* Mark the channel as resetting and restart it */
    
    		pri->pvts[pri->resetpos]->resetting = SIG_PRI_RESET_ACTIVE;
    
    		pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[pri->resetpos]));
    	} else {
    		pri->resetting = 0;
    		time(&pri->lastreset);
    
    		sig_pri_span_devstate_changed(pri);
    
    #if defined(HAVE_PRI_CALL_WAITING)
    /*!
     * \internal
     * \brief Init the private channel configuration using the span controller.
     * \since 1.8
     *
     * \param pvt Channel to init the configuration.
    
     * \param pri PRI span control structure.
    
     *
     * \note Assumes the pri->lock is already obtained.
     *
     * \return Nothing
     */
    
    static void sig_pri_init_config(struct sig_pri_chan *pvt, struct sig_pri_span *pri)
    
    {
    	pvt->stripmsd = pri->ch_cfg.stripmsd;
    	pvt->hidecallerid = pri->ch_cfg.hidecallerid;
    	pvt->hidecalleridname = pri->ch_cfg.hidecalleridname;
    	pvt->immediate = pri->ch_cfg.immediate;
    	pvt->priexclusive = pri->ch_cfg.priexclusive;
    	pvt->priindication_oob = pri->ch_cfg.priindication_oob;
    	pvt->use_callerid = pri->ch_cfg.use_callerid;
    	pvt->use_callingpres = pri->ch_cfg.use_callingpres;
    	ast_copy_string(pvt->context, pri->ch_cfg.context, sizeof(pvt->context));
    	ast_copy_string(pvt->mohinterpret, pri->ch_cfg.mohinterpret, sizeof(pvt->mohinterpret));
    
    
    	if (sig_pri_callbacks.init_config) {
    		sig_pri_callbacks.init_config(pvt->chan_pvt, pri);
    
    	}
    }
    #endif	/* defined(HAVE_PRI_CALL_WAITING) */
    
    
    /*!
     * \internal
     * \brief Find an empty B-channel interface to use.
     *
     * \param pri PRI span control structure.
     * \param backwards TRUE if the search starts from higher channels.
     *
     * \note Assumes the pri->lock is already obtained.
     *
     * \retval array-index into private pointer array on success.
     * \retval -1 on error.
     */
    
    static int pri_find_empty_chan(struct sig_pri_span *pri, int backwards)
    
    {
    	int x;
    	if (backwards)
    		x = pri->numchans;
    	else
    		x = 0;
    	for (;;) {
    		if (backwards && (x < 0))
    			break;
    		if (!backwards && (x >= pri->numchans))
    			break;
    
    		if (pri->pvts[x]
    			&& !pri->pvts[x]->no_b_channel
    
    			&& sig_pri_is_chan_available(pri->pvts[x])) {
    
    			ast_debug(1, "Found empty available channel %d/%d\n",
    
    				pri->pvts[x]->logicalspan, pri->pvts[x]->prioffset);
    			return x;
    		}
    		if (backwards)
    			x--;
    		else
    			x++;
    	}
    	return -1;
    }
    
    
    #if defined(HAVE_PRI_CALL_HOLD)
    /*!
     * \internal
     * \brief Find or create an empty no-B-channel interface to use.
    
     * \param pri PRI span control structure.
    
     *
     * \note Assumes the pri->lock is already obtained.
     *
     * \retval array-index into private pointer array on success.
     * \retval -1 on error.
     */
    
    static int pri_find_empty_nobch(struct sig_pri_span *pri)
    
    {
    	int idx;
    
    	for (idx = 0; idx < pri->numchans; ++idx) {
    		if (pri->pvts[idx]
    			&& pri->pvts[idx]->no_b_channel
    
    			&& sig_pri_is_chan_available(pri->pvts[idx])) {
    
    			ast_debug(1, "Found empty available no B channel interface\n");
    			return idx;
    		}
    	}
    
    	/* Need to create a new interface. */
    
    	if (sig_pri_callbacks.new_nobch_intf) {
    		idx = sig_pri_callbacks.new_nobch_intf(pri);
    
    	} else {
    		idx = -1;
    	}
    	return idx;
    }
    #endif	/* defined(HAVE_PRI_CALL_HOLD) */
    
    
    static void *do_idle_thread(void *v_pvt)
    
    	struct sig_pri_chan *pvt = v_pvt;
    	struct ast_channel *chan = pvt->owner;
    
    	struct ast_frame *f;
    	char ex[80];
    	/* Wait up to 30 seconds for an answer */
    
    	int timeout_ms = 30000;
    	int ms;
    	struct timeval start;
    
    	struct ast_callid *callid;
    
    	if ((callid = ast_channel_callid(chan))) {
    		ast_callid_threadassoc_add(callid);
    		callid = ast_callid_unref(callid);
    	}
    
    	ast_verb(3, "Initiating idle call on channel %s\n", ast_channel_name(chan));
    
    	snprintf(ex, sizeof(ex), "%d/%s", pvt->channel, pvt->pri->idledial);
    	if (ast_call(chan, ex, 0)) {
    
    		ast_log(LOG_WARNING, "Idle dial failed on '%s' to '%s'\n", ast_channel_name(chan), ex);
    
    	start = ast_tvnow();
    	while ((ms = ast_remaining_ms(start, timeout_ms))) {
    		if (ast_waitfor(chan, ms) <= 0) {
    			break;
    		}
    
    
    		f = ast_read(chan);
    		if (!f) {
    			/* Got hangup */
    			break;
    		}
    		if (f->frametype == AST_FRAME_CONTROL) {
    
    			switch (f->subclass.integer) {
    
    			case AST_CONTROL_ANSWER:
    				/* Launch the PBX */
    
    				ast_channel_exten_set(chan, pvt->pri->idleext);
    				ast_channel_context_set(chan, pvt->pri->idlecontext);
    
    				ast_channel_priority_set(chan, 1);
    
    				ast_verb(4, "Idle channel '%s' answered, sending to %s@%s\n", ast_channel_name(chan), ast_channel_exten(chan), ast_channel_context(chan));
    
    				ast_pbx_run(chan);
    				/* It's already hungup, return immediately */
    				return NULL;
    			case AST_CONTROL_BUSY:
    
    				ast_verb(4, "Idle channel '%s' busy, waiting...\n", ast_channel_name(chan));
    
    				break;
    			case AST_CONTROL_CONGESTION:
    
    				ast_verb(4, "Idle channel '%s' congested, waiting...\n", ast_channel_name(chan));
    
    				break;
    			};
    		}
    		ast_frfree(f);
    	}
    	/* Hangup the channel since nothing happend */
    	ast_hangup(chan);
    	return NULL;
    }
    
    static void *pri_ss_thread(void *data)
    {
    	struct sig_pri_chan *p = data;
    	struct ast_channel *chan = p->owner;
    	char exten[AST_MAX_EXTENSION];
    	int res;
    	int len;
    	int timeout;
    
    	struct ast_callid *callid;
    
    	if (!chan) {
    		/* We lost the owner before we could get started. */
    		return NULL;
    	}
    
    
    	if ((callid = ast_channel_callid(chan))) {
    		ast_callid_threadassoc_add(callid);
    		ast_callid_unref(callid);
    	}
    
    
    	/*
    	 * In the bizarre case where the channel has become a zombie before we
    	 * even get started here, abort safely.
    	 */
    
    	if (!ast_channel_tech_pvt(chan)) {
    
    		ast_log(LOG_WARNING, "Channel became a zombie before simple switch could be started (%s)\n", ast_channel_name(chan));
    
    	ast_verb(3, "Starting simple switch on '%s'\n", ast_channel_name(chan));
    
    	sig_pri_dsp_reset_and_flush_digits(p);
    
    
    	/* Now loop looking for an extension */
    	ast_copy_string(exten, p->exten, sizeof(exten));
    	len = strlen(exten);
    	res = 0;
    
    	while ((len < AST_MAX_EXTENSION-1) && ast_matchmore_extension(chan, ast_channel_context(chan), exten, 1, p->cid_num)) {
    		if (len && !ast_ignore_pattern(ast_channel_context(chan), exten))
    
    			sig_pri_play_tone(p, -1);
    		else
    			sig_pri_play_tone(p, SIG_PRI_TONE_DIALTONE);
    
    		if (ast_exists_extension(chan, ast_channel_context(chan), exten, 1, p->cid_num))
    
    			timeout = pri_matchdigittimeout;
    		else
    			timeout = pri_gendigittimeout;
    		res = ast_waitfordigit(chan, timeout);
    		if (res < 0) {
    
    			ast_debug(1, "waitfordigit returned < 0...\n");
    
    			ast_hangup(chan);
    			return NULL;
    		} else if (res) {
    			exten[len++] = res;
    			exten[len] = '\0';
    		} else
    
    	}
    	/* if no extension was received ('unspecified') on overlap call, use the 's' extension */
    	if (ast_strlen_zero(exten)) {
    		ast_verb(3, "Going to extension s|1 because of empty extension received on overlap call\n");
    		exten[0] = 's';
    		exten[1] = '\0';