static int pickup_exec(struct ast_channel *chan, void *data) { int res = 0; struct localuser *u = NULL; struct ast_channel *origin = NULL, *target = NULL; char *tmp = NULL, *exten = NULL, *context = NULL, *rest=data; char workspace[256] = ""; const char *tmp2 = NULL; if (ast_strlen_zero(data)) { ast_log(LOG_WARNING, "Pickup requires an argument (extension) !\n"); return -1; } LOCAL_USER_ADD(u); while (!target && (exten = rest) ) { res = 0; rest = strchr(exten, '&'); if (rest) *rest++ = 0; /* Get the extension and context if present */ context = strchr(exten, '@'); if (context) *context++ = '\0'; /* If the context is the pickup mark, iterate through all channels finding the right origin one */ if (!strcmp(context, PICKUPMARK)) { while ((origin = ast_channel_walk_locked(origin))) { if (origin) { tmp2 = pbx_builtin_getvar_helper(origin, PICKUPMARK); if (tmp2 && !strcmp(tmp2, exten)) break; ast_mutex_unlock(&origin->lock); } } } else { /* Use the classic mode of searching */ origin = ast_get_channel_by_exten_locked(exten, context); } if (origin) { ast_cdr_getvar(origin->cdr, "dstchannel", &tmp, workspace, sizeof(workspace), 0, 0); if (tmp) { /* We have a possible channel... now we need to find it! */ target = ast_get_channel_by_name_locked(tmp); } else { ast_log(LOG_NOTICE, "No target channel found for %s.\n", exten); res = -1; } ast_mutex_unlock(&origin->lock); } else { ast_log(LOG_DEBUG, "No originating channel found.\n"); } if (res) continue; if (target && (!target->pbx) && ((target->_state == AST_STATE_RINGING) || (target->_state == AST_STATE_RING) ) ) { ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n", target->name, chan->name); res = ast_answer(chan); if (res) { ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name); res = -1; break; } res = ast_queue_control(chan, AST_CONTROL_ANSWER); if (res) { ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name); res = -1; break; } res = ast_channel_masquerade(target, chan); if (res) { ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, target->name); res = -1; break; } } else { ast_log(LOG_NOTICE, "No call pickup possible for %s...\n", exten); res = -1; } } if (target) ast_mutex_unlock(&target->lock); LOCAL_USER_REMOVE(u); return res; }
static int pickup_exec(struct ast_channel *chan, void *data) { int res = 0; struct localuser *u = NULL; struct ast_channel *origin = NULL, *target = NULL; char *tmp = NULL, *exten = NULL, *context = NULL; char workspace[256] = ""; if (ast_strlen_zero(data)) { ast_log(LOG_WARNING, "Pickup requires an argument (extension) !\n"); return -1; } LOCAL_USER_ADD(u); /* Get the extension and context if present */ exten = data; context = strchr(data, '@'); if (context) { *context = '\0'; context++; } /* Find a channel to pickup */ origin = ast_get_channel_by_exten_locked(exten, context); if (origin && origin->cdr) { ast_cdr_getvar(origin->cdr, "dstchannel", &tmp, workspace, sizeof(workspace), 0); if (tmp) { /* We have a possible channel... now we need to find it! */ target = ast_get_channel_by_name_locked(tmp); } else { ast_log(LOG_DEBUG, "No target channel found.\n"); res = -1; } ast_mutex_unlock(&origin->lock); } else { if (origin) ast_mutex_unlock(&origin->lock); ast_log(LOG_DEBUG, "No originating channel found.\n"); } if (res) goto out; if (target && (!target->pbx) && ((target->_state == AST_STATE_RINGING) || (target->_state == AST_STATE_RING))) { ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n", target->name, chan->name); res = ast_answer(chan); if (res) { ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name); res = -1; goto out; } res = ast_queue_control(chan, AST_CONTROL_ANSWER); if (res) { ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name); res = -1; goto out; } res = ast_channel_masquerade(target, chan); if (res) { ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, target->name); res = -1; goto out; } } else { ast_log(LOG_DEBUG, "No call pickup possible...\n"); res = -1; } /* Done */ out: if (target) ast_mutex_unlock(&target->lock); LOCAL_USER_REMOVE(u); return res; }