tmp->callwaitingcallerid = conf->chan.callwaitingcallerid;
tmp->threewaycalling = conf->chan.threewaycalling;
tmp->threewaysilenthold = conf->chan.threewaysilenthold;
+ tmp->calledsubscriberheld = conf->chan.calledsubscriberheld; /* Not used in chan_dahdi.c, just analog pvt, but must exist on the DAHDI pvt anyways */
tmp->adsi = conf->chan.adsi;
tmp->use_smdi = conf->chan.use_smdi;
tmp->permhidecallerid = conf->chan.hidecallerid;
analog_p->ani_wink_time = conf->chan.ani_wink_time;
analog_p->hanguponpolarityswitch = conf->chan.hanguponpolarityswitch;
analog_p->permcallwaiting = conf->chan.callwaiting; /* permcallwaiting possibly modified in analog_config_complete */
+ analog_p->calledsubscriberheld = conf->chan.calledsubscriberheld; /* Only actually used in analog pvt, not DAHDI pvt */
analog_p->callreturn = conf->chan.callreturn;
analog_p->cancallforward = conf->chan.cancallforward;
analog_p->canpark = conf->chan.canpark;
confp->chan.busycount = atoi(v->value);
} else if (!strcasecmp(v->name, "busypattern")) {
parse_busy_pattern(v, &confp->chan.busy_cadence);
+ } else if (!strcasecmp(v->name, "calledsubscriberheld")) {
+ confp->chan.calledsubscriberheld = ast_true(v->value);
} else if (!strcasecmp(v->name, "callprogress")) {
confp->chan.callprogress &= ~CALLPROGRESS_PROGRESS;
if (ast_true(v->value))
return 0;
}
+ /* If line is being held, definitely not (don't allow call waitings to an on-hook phone) */
+ if (p->cshactive) {
+ return 0;
+ }
+
/* If no owner definitely available */
if (!p->owner) {
offhook = analog_is_off_hook(p);
p->channel, idx, p->subs[ANALOG_SUB_REAL].allocd, p->subs[ANALOG_SUB_CALLWAIT].allocd, p->subs[ANALOG_SUB_THREEWAY].allocd);
if (idx > -1) {
/* Real channel, do some fixup */
+ p->cshactive = 0;
p->subs[idx].owner = NULL;
p->polarity = POLARITY_IDLE;
analog_set_linear_mode(p, idx, 0);
analog_get_and_handle_alarms(p);
cause_code->ast_cause = AST_CAUSE_NETWORK_OUT_OF_ORDER;
case ANALOG_EVENT_ONHOOK:
+ if (p->calledsubscriberheld && (p->sig == ANALOG_SIG_FXOLS || p->sig == ANALOG_SIG_FXOGS || p->sig == ANALOG_SIG_FXOKS) && idx == ANALOG_SUB_REAL) {
+ ast_debug(4, "Channel state on %s is %d\n", ast_channel_name(ast), ast_channel_state(ast));
+ /* Called Subscriber Held: don't let the called party hang up on an incoming call immediately (if it's the only call). */
+ if (p->subs[ANALOG_SUB_CALLWAIT].owner || p->subs[ANALOG_SUB_THREEWAY].owner) {
+ ast_debug(2, "Letting this call hang up normally, since it's not the only call\n");
+ } else if (!p->owner || !p->subs[ANALOG_SUB_REAL].owner || ast_channel_state(ast) != AST_STATE_UP) {
+ ast_debug(2, "Called Subscriber Held does not apply: channel state is %d\n", ast_channel_state(ast));
+ } else if (!p->owner || !p->subs[ANALOG_SUB_REAL].owner || strcmp(ast_channel_appl(p->subs[ANALOG_SUB_REAL].owner), "AppDial")) {
+ /* Called Subscriber held only applies to incoming calls, not outgoing calls.
+ * We can't use p->outgoing because that is always true, for both incoming and outgoing calls, so it's not accurate.
+ * We can check the channel application/data instead.
+ * For incoming calls to the channel, it will look like: AppDial / (Outgoing Line)
+ * We only want this behavior for regular calls anyways (and not, say, Queue),
+ * so this would actually work great. But accessing ast_channel_appl can cause a crash if there are no calls left,
+ * so this check must occur AFTER we confirm the channel state *is* still UP.
+ */
+ ast_debug(2, "Called Subscriber Held does not apply: not an incoming call\n");
+ } else if (analog_is_off_hook(p)) {
+ ast_log(LOG_WARNING, "Got ONHOOK but channel %d is off hook?\n", p->channel); /* Shouldn't happen */
+ } else {
+ ast_verb(3, "Holding incoming call %s for channel %d\n", ast_channel_name(ast), p->channel);
+ /* Inhibit dahdi_hangup from getting called, and do nothing else now.
+ * When the DAHDI channel goes off hook again, it'll just get reconnected with the incoming call,
+ * to which, as far as its concerned, nothing has happened. */
+ p->cshactive = 1; /* Keep track that this DAHDI channel is currently being held by an incoming call. */
+ break;
+ }
+ }
ast_queue_control_data(ast, AST_CONTROL_PVT_CAUSE_CODE, cause_code, data_size);
ast_channel_hangupcause_hash_set(ast, cause_code, data_size);
switch (p->sig) {
case ANALOG_SIG_FXOKS:
res = analog_off_hook(i);
i->fxsoffhookstate = 1;
+ i->cshactive = 0;
if (res && (errno == EBUSY)) {
break;
}
unsigned int ani_wink_time:16; /* Safe wait time before we wink to start ANI spill */
unsigned int answeronpolarityswitch:1;
+ unsigned int calledsubscriberheld:1; /*!< TRUE if a single incoming call can hold an FXS channel */
unsigned int callreturn:1;
unsigned int cancallforward:1;
unsigned int canpark:1;
/* XXX: All variables after this are internal */
unsigned int callwaiting:1; /*!< TRUE if call waiting is enabled. (Active option) */
+ unsigned int cshactive:1; /*!< TRUE if FXS channel is currently held by an incoming call */
unsigned int dialednone:1;
unsigned int dialing:1; /*!< TRUE if in the process of dialing digits or sending something */
unsigned int dnd:1; /*!< TRUE if Do-Not-Disturb is enabled. */
;
callwaitingcallerid=yes
;
+; Whether or not to allow users to go on-hook when receiving an incoming call
+; without disconnecting it. Users can later resume the call from any phone
+; on the same physical phone line (the same DAHDI channel).
+; This setting only has an effect on FXS (FXO-signalled) channels where there
+; is only a single incoming call to the DAHDI channel, using the Dial application.
+; (This is a convenience mechanism to avoid users wishing to resume a conversation
+; at a different phone from leaving a phone off the hook, resuming elsewhere,
+; and forgetting to restore the original phone on hook afterwards.)
+; Default is no.
+;
+;calledsubscriberheld=yes
+;
; Support three-way calling
;
threewaycalling=yes