[asterisk-commits] seanbright: branch seanbright/issue5014-1.4 r143884 - /team/seanbright/issue5...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Sun Sep 21 17:17:08 CDT 2008
Author: seanbright
Date: Sun Sep 21 17:17:08 2008
New Revision: 143884
URL: http://svn.digium.com/view/asterisk?view=rev&rev=143884
Log:
Manually merge in changes from team/seanbright/issue5014.
Modified:
team/seanbright/issue5014-1.4/channels/chan_sip.c
Modified: team/seanbright/issue5014-1.4/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/team/seanbright/issue5014-1.4/channels/chan_sip.c?view=diff&rev=143884&r1=143883&r2=143884
==============================================================================
--- team/seanbright/issue5014-1.4/channels/chan_sip.c (original)
+++ team/seanbright/issue5014-1.4/channels/chan_sip.c Sun Sep 21 17:17:08 2008
@@ -873,6 +873,13 @@
REFER_200OK, /*!< Answered by transfer target */
REFER_FAILED, /*!< REFER declined - go on */
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 {
@@ -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,6 +14096,36 @@
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
@@ -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);
+ }
}
More information about the asterisk-commits
mailing list