Index: channels/chan_sip.c===================================================================--- channels/chan_sip.c (.../branches/1.4) (revision 143963)+++ channels/chan_sip.c (.../team/seanbright/issue5014-1.4) (revision 143963)@@ -875,6 +875,13 @@ REFER_NOAUTH /*!< We had no auth for REFER */ };+/*! \brief struct to store off exten and contact for tech independent pickup.+ */+struct pickup_target {+ char *exten;+ char *context;+};+ static const struct c_referstatusstring { enum referstatus status; char *text;@@ -1355,6 +1362,7 @@ static int sip_refer_allocate(struct sip_pvt *p); static void ast_quiet_chan(struct ast_channel *chan); static int attempt_transfer(struct sip_dual *transferer, struct sip_dual *target);+static int do_magic_pickup(struct ast_channel *channel, const char *exten, const char *context); /*--- Device monitoring and Device/extension state handling */ static int cb_extensionstate(char *context, char* exten, int state, void *data);@@ -7382,11 +7390,25 @@ break; case DIALOG_INFO_XML: /* SNOM subscribes in this format */ ast_build_string(&t, &maxbytes, "<?xml version=\"1.0\"?>\n");- ast_build_string(&t, &maxbytes, "<dialog-info xmlns=\"urn:ietf:params:xml:ns:dialog-info\" version=\"%d\" state=\"%s\" entity=\"%s\">\n", p->dialogver++, full ? "full":"partial", mto);- if ((state & AST_EXTENSION_RINGING) && global_notifyringing)- ast_build_string(&t, &maxbytes, "<dialog id=\"%s\" direction=\"recipient\">\n", p->exten);- else+ ast_build_string(&t, &maxbytes, "<dialog-info xmlns=\"urn:ietf:params:xml:ns:dialog-info\" version=\"%d\" state=\"%s\" entity=\"%s\">\n", p->dialogver++, full ? "full" : "partial", mto);+ if ((state & AST_EXTENSION_RINGING) && global_notifyringing) {+ /* We create a fake call-id which the phone will send back in an INVITE+ Replaces header which we can grab and do some magic with. */+ ast_build_string(&t, &maxbytes, "<dialog id=\"%s\" call-id=\"pickup-%s\" direction=\"recipient\">\n", p->exten, p->callid);+ ast_build_string(&t, &maxbytes, "<remote>\n");+ /* Note that the identity and target elements for the local participant are currently+ (and may forever be) incorrect since we have no reliable way to get at that information+ at the moment. Luckily the phone seems to still live happily without it being correct */+ ast_build_string(&t, &maxbytes, "<identity>%s</identity>\n", mto);+ ast_build_string(&t, &maxbytes, "<target uri=\"%s\"/>\n", mto);+ ast_build_string(&t, &maxbytes, "</remote>\n");+ ast_build_string(&t, &maxbytes, "<local>\n");+ ast_build_string(&t, &maxbytes, "<identity>%s</identity>\n", mto);+ ast_build_string(&t, &maxbytes, "<target uri=\"%s\"/>\n", mto);+ ast_build_string(&t, &maxbytes, "</local>\n");+ } else { ast_build_string(&t, &maxbytes, "<dialog id=\"%s\">\n", p->exten);+ } ast_build_string(&t, &maxbytes, "<state>%s</state>\n", statestring); if (state == AST_EXTENSION_ONHOLD) { ast_build_string(&t, &maxbytes, "<local>\n<target uri=\"%s\">\n"@@ -14074,7 +14096,37 @@ return sip_uri_params_cmp(params1, params2); }+static int do_magic_pickup(struct ast_channel *channel, const char *extension, const char *context)+{+ char *argument = NULL;+ int length;+ struct ast_app *pickup = pbx_findapp("Pickup");+ if (!pickup) {+ ast_log(LOG_ERROR, "Unable to perform pickup: Application 'Pickup' not loaded (app_directed_pickup.so).\n");+ return -1;+ }++ /* Enough room for 'extension', 'context', and '@' (and \0) */+ length = strlen(extension) + strlen(context) + 2;++ if (!(argument = ast_malloc(length))) {+ ast_log(LOG_ERROR, "Failed to allocate memory for pickup extension.\n");+ return -1;+ }++ snprintf(argument, length, "%s@%s", extension, context);++ /* There is no point in capturing the return value since pickup_exec+ doesn't return anything meaningful unless the passed data is an empty+ string (which in our case it will not be) */+ pbx_exec(channel, pickup, argument);++ ast_free(argument);++ return 0; +}+ /*! \brief Handle incoming INVITE request \note If the INVITE has a Replaces header, it is part of an * attended transfer. If so, we do not go through the dial@@ -14091,6 +14143,7 @@ unsigned int required_profile = 0; struct ast_channel *c = NULL; /* New channel */ int reinvite = 0;+ struct pickup_target *pickup = NULL; /* Find out what they support */ if (!p->sipoptions) {@@ -14227,10 +14280,35 @@ ast_log(LOG_DEBUG,"Invite/replaces: Will use Replace-Call-ID : %s Fromtag: %s Totag: %s\n", replace_id, fromtag ? fromtag : "<no from tag>", totag ? totag : "<no to tag>");- /* Try to find call that we are replacing - If we have a Replaces header, we need to cancel that call if we succeed with this call - */- if ((p->refer->refer_call = get_sip_pvt_byid_locked(replace_id, totag, fromtag)) == NULL) {+ /* Try to find the call that we are replacing.+ If we have a Replaces header, we need to cancel that call if we succeed with this call.+ First we cheat a little and look for a magic call-id from phones that support+ dialog-info+xml so we can do technology independent pickup... */+ if (strncmp(replace_id, "pickup-", 7) == 0) {+ struct sip_pvt *subscription = NULL;+ replace_id += 7; /* Worst case we are looking at \0 */++ if ((subscription = get_sip_pvt_byid_locked(replace_id, NULL, NULL)) == NULL) {+ ast_log(LOG_NOTICE, "Unable to find subscription with call-id: %s\n", replace_id);+ transmit_response_reliable(p, "481 Call Leg Does Not Exist (Replaces)", req);+ error = 1;+ } else {+ if (!(pickup = ast_calloc(1, sizeof(*pickup)))) {+ ast_log(LOG_ERROR, "Memory allocation failed.\n");+ error = 1;+ } else {+ ast_log(LOG_NOTICE, "Trying to pick up %s@%s\n", subscription->exten, subscription->context);+ pickup->exten = ast_strdup(subscription->exten);+ pickup->context = ast_strdup(subscription->context);+ ast_mutex_unlock(&subscription->lock);+ if (subscription->owner) {+ ast_channel_unlock(subscription->owner);+ }+ }+ }+ }++ if (!error && !pickup && (p->refer->refer_call = get_sip_pvt_byid_locked(replace_id, totag, fromtag)) == NULL) { ast_log(LOG_NOTICE, "Supervised transfer attempted to replace non-existent call id (%s)!\n", replace_id); transmit_response_reliable(p, "481 Call Leg Does Not Exist (Replaces)", req); error = 1;@@ -14249,7 +14327,7 @@ error = 1; }- if (!error && !p->refer->refer_call->owner) {+ if (!error && !pickup && !p->refer->refer_call->owner) { /* Oops, someting wrong anyway, no owner, no call */ ast_log(LOG_NOTICE, "Supervised transfer attempted to replace non-existing call id (%s)!\n", replace_id); /* Check for better return code */@@ -14257,7 +14335,7 @@ error = 1; }- if (!error && p->refer->refer_call->owner->_state != AST_STATE_RINGING && p->refer->refer_call->owner->_state != AST_STATE_RING && p->refer->refer_call->owner->_state != AST_STATE_UP ) {+ if (!error && !pickup && p->refer->refer_call->owner->_state != AST_STATE_RINGING && p->refer->refer_call->owner->_state != AST_STATE_RING && p->refer->refer_call->owner->_state != AST_STATE_UP ) { ast_log(LOG_NOTICE, "Supervised transfer attempted to replace non-ringing or active call id (%s)!\n", replace_id); transmit_response_reliable(p, "603 Declined (Replaces)", req); error = 1;@@ -14447,10 +14525,27 @@ p->lastinvite = seqno; if (replace_id) { /* Attended transfer or call pickup - we're the target */- /* Go and take over the target call */- if (sipdebug && option_debug > 3)- ast_log(LOG_DEBUG, "Sending this call to the invite/replcaes handler %s\n", p->callid);- return handle_invite_replaces(p, req, debug, ast_test_flag(req, SIP_PKT_IGNORE), seqno, sin);+ if (pickup) {+ append_history(p, "Xfer", "INVITE/Replace received");++ /* Let the caller know we're giving it a shot */+ transmit_response(p, "100 Trying", req);+ ast_setstate(c, AST_STATE_RING);++ /* Do the pickup itself */+ do_magic_pickup(c, pickup->exten, pickup->context);++ /* Do a bit of cleanup */+ ast_free(pickup->exten);+ ast_free(pickup->context);+ ast_free(pickup);+ return 0;+ } else {+ /* Go and take over the target call */+ if (sipdebug && option_debug > 3)+ ast_log(LOG_DEBUG, "Sending this call to the invite/replcaes handler %s\n", p->callid);+ return handle_invite_replaces(p, req, debug, ast_test_flag(req, SIP_PKT_IGNORE), seqno, sin);+ } }Property changes on: .___________________________________________________________________Added: automerge + *Added: svnmerge-integrated + /branches/1.4:1-143955Added: automerge-email + sean.bright+$branch@gmail.com