Index: channels/chan_sip.c =================================================================== --- channels/chan_sip.c (revision 318720) +++ channels/chan_sip.c (working copy) @@ -15867,6 +15867,7 @@ /* Unlock locks so ast_hangup can do its magic */ ast_mutex_unlock(&c->lock); + *nounlock = 1; ast_mutex_unlock(&p->lock); ast_hangup(c); ast_mutex_lock(&p->lock); @@ -15875,7 +15876,9 @@ } else { /* Pickup call in call group */ ast_channel_unlock(c); *nounlock = 1; + ast_mutex_unlock(&p->lock); if (ast_pickup_call(c)) { + ast_mutex_lock(&p->lock); ast_log(LOG_NOTICE, "Nothing to pick up for %s\n", p->callid); if (ast_test_flag(req, SIP_PKT_IGNORE)) transmit_response(p, "503 Unavailable", req); /* OEJ - Right answer? */ @@ -15886,13 +15889,11 @@ ast_mutex_unlock(&p->lock); c->hangupcause = AST_CAUSE_CALL_REJECTED; } else { - ast_mutex_unlock(&p->lock); - ast_setstate(c, AST_STATE_DOWN); c->hangupcause = AST_CAUSE_NORMAL_CLEARING; } - p->invitestate = INV_COMPLETED; ast_hangup(c); ast_mutex_lock(&p->lock); + p->invitestate = INV_COMPLETED; c = NULL; } break; Index: apps/app_directed_pickup.c =================================================================== --- apps/app_directed_pickup.c (revision 318720) +++ apps/app_directed_pickup.c (working copy) @@ -54,39 +54,45 @@ "10@PICKUPMARK, this application tries to find a channel which has defined a channel variable with the same content\n" "as \"extension\"."; -/* Perform actual pickup between two channels */ +/*! + * \internal + * \brief Perform actual pickup between two channels. + * \note Must remain in sync with same function in res/res_features.c. + */ static int pickup_do(struct ast_channel *chan, struct ast_channel *target) { - int res = 0; - if (option_debug) ast_log(LOG_DEBUG, "Call pickup on '%s' by '%s'\n", target->name, chan->name); - if ((res = ast_answer(chan))) { + if (ast_answer(chan)) { ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name); return -1; } - if ((res = ast_queue_control(chan, AST_CONTROL_ANSWER))) { + if (ast_queue_control(chan, AST_CONTROL_ANSWER)) { ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name); return -1; } - if ((res = ast_channel_masquerade(target, chan))) { + if (ast_channel_masquerade(target, chan)) { ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, target->name); return -1; } - return res; + return 0; } /* Helper function that determines whether a channel is capable of being picked up */ static int can_pickup(struct ast_channel *chan) { - if (!chan->pbx && (chan->_state == AST_STATE_RINGING || chan->_state == AST_STATE_RING || chan->_state == AST_STATE_DOWN)) + if (!chan->pbx && !chan->masq && + !ast_test_flag(chan, AST_FLAG_ZOMBIE) && + (chan->_state == AST_STATE_RINGING || + chan->_state == AST_STATE_RING || + chan->_state == AST_STATE_DOWN)) { return 1; - else - return 0; + } + return 0; } /* Attempt to pick up specified extension with context */ Index: res/res_features.c =================================================================== --- res/res_features.c (revision 318720) +++ res/res_features.c (working copy) @@ -3374,6 +3374,34 @@ } +/*! + * \internal + * \brief Perform actual pickup between two channels. + * \note Must remain in sync with same function in apps/app_directed_pickup.c. + */ +static int pickup_do(struct ast_channel *chan, struct ast_channel *target) +{ + if (option_debug) + ast_log(LOG_DEBUG, "Call pickup on '%s' by '%s'\n", target->name, chan->name); + + if (ast_answer(chan)) { + ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name); + return -1; + } + + if (ast_queue_control(chan, AST_CONTROL_ANSWER)) { + ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name); + return -1; + } + + if (ast_channel_masquerade(target, chan)) { + ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, target->name); + return -1; + } + + return 0; +} + int ast_pickup_call(struct ast_channel *chan) { struct ast_channel *cur = NULL; @@ -3385,27 +3413,21 @@ (chan->pickupgroup & cur->callgroup) && ((cur->_state == AST_STATE_RINGING) || (cur->_state == AST_STATE_RING)) && - !cur->masq) { + !cur->masq && + !ast_test_flag(cur, AST_FLAG_ZOMBIE)) { break; } ast_channel_unlock(cur); } if (cur) { - if (option_debug) - ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name); - res = ast_answer(chan); - if (res) - ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name); - res = ast_queue_control(chan, AST_CONTROL_ANSWER); - if (res) - ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name); - res = ast_channel_masquerade(cur, chan); - if (res) - ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */ + res = pickup_do(chan, cur); + if (res) { + ast_log(LOG_WARNING, "pickup %s failed by %s\n", cur->name, chan->name); + } ast_channel_unlock(cur); } else { if (option_debug) - ast_log(LOG_DEBUG, "No call pickup possible...\n"); + ast_log(LOG_DEBUG, "No call pickup possible... for %s\n", chan->name); } return res; }