Implement call pickup on SIP, override context if appropriate
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@791 f38db490-d61c-443f-a65b-d21fe96a405b
This commit is contained in:
parent
6275b6092f
commit
689c55ac51
1
CHANGES
1
CHANGES
|
@ -1,3 +1,4 @@
|
|||
-- Support call pickup on SIP and compatibly with ZAP
|
||||
-- Support 302 Redirect on SIP
|
||||
-- Management interface improvements
|
||||
-- Add "hint" support
|
||||
|
|
|
@ -1684,6 +1684,7 @@ int ast_channel_masquerade(struct ast_channel *original, struct ast_channel *clo
|
|||
/* XXX can't really hold the lock here, but at the same time, it' s
|
||||
not really safe not to XXX */
|
||||
ast_queue_frame(original, &null, 0);
|
||||
ast_queue_frame(clone, &null, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include <asterisk/app.h>
|
||||
#include <asterisk/musiconhold.h>
|
||||
#include <asterisk/dsp.h>
|
||||
#include <asterisk/parking.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
|
@ -156,6 +157,8 @@ static struct sip_pvt {
|
|||
char randdata[80]; /* Random data */
|
||||
unsigned int ocseq; /* Current outgoing seqno */
|
||||
unsigned int icseq; /* Current incoming seqno */
|
||||
unsigned int callgroup;
|
||||
unsigned int pickupgroup;
|
||||
int lastinvite; /* Last Cseq of invite */
|
||||
int alreadygone; /* Whether or not we've already been destroyed by or peer */
|
||||
int needdestroy; /* if we need to be destroyed */
|
||||
|
@ -235,6 +238,8 @@ struct sip_user {
|
|||
char callerid[80];
|
||||
char methods[80];
|
||||
char accountcode[80];
|
||||
unsigned int callgroup;
|
||||
unsigned int pickupgroup;
|
||||
int nat;
|
||||
int hascallerid;
|
||||
int amaflags;
|
||||
|
@ -262,6 +267,8 @@ struct sip_peer {
|
|||
int insecure;
|
||||
int nat;
|
||||
int canreinvite;
|
||||
unsigned int callgroup;
|
||||
unsigned int pickupgroup;
|
||||
int dtmfmode;
|
||||
struct sockaddr_in addr;
|
||||
struct in_addr mask;
|
||||
|
@ -583,6 +590,8 @@ static int create_addr(struct sip_pvt *r, char *peer)
|
|||
r->insecure = p->insecure;
|
||||
r->canreinvite = p->canreinvite;
|
||||
r->maxtime = p->maxms;
|
||||
r->callgroup = p->callgroup;
|
||||
r->pickupgroup = p->pickupgroup;
|
||||
if (p->dtmfmode) {
|
||||
r->dtmfmode = p->dtmfmode;
|
||||
if (r->dtmfmode & SIP_DTMF_RFC2833)
|
||||
|
@ -1109,6 +1118,8 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, char *title)
|
|||
tmp->pvt->fixup = sip_fixup;
|
||||
tmp->pvt->send_digit = sip_senddigit;
|
||||
tmp->pvt->bridge = ast_rtp_bridge;
|
||||
tmp->callgroup = i->callgroup;
|
||||
tmp->pickupgroup = i->pickupgroup;
|
||||
if (strlen(i->language))
|
||||
strncpy(tmp->language, i->language, sizeof(tmp->language)-1);
|
||||
i->owner = tmp;
|
||||
|
@ -2971,13 +2982,15 @@ static int get_destination(struct sip_pvt *p, struct sip_request *oreq)
|
|||
}
|
||||
if (sipdebug)
|
||||
ast_verbose("Looking for %s in %s\n", c, p->context);
|
||||
if (ast_exists_extension(NULL, p->context, c, 1, NULL)) {
|
||||
if (ast_exists_extension(NULL, p->context, c, 1, NULL) ||
|
||||
!strcmp(c, ast_pickup_ext())) {
|
||||
if (!oreq)
|
||||
strncpy(p->exten, c, sizeof(p->exten) - 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ast_canmatch_extension(NULL, p->context, c, 1, NULL)) {
|
||||
if (ast_canmatch_extension(NULL, p->context, c, 1, NULL) ||
|
||||
!strncmp(c, ast_pickup_ext(),strlen(c))) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -3178,13 +3191,16 @@ static int check_user(struct sip_pvt *p, struct sip_request *req, char *cmd, cha
|
|||
}
|
||||
if (!(res = check_auth(p, req, p->randdata, sizeof(p->randdata), user->name, user->secret, cmd, uri, reliable))) {
|
||||
sip_cancel_destroy(p);
|
||||
strncpy(p->context, user->context, sizeof(p->context) - 1);
|
||||
if (strlen(user->context))
|
||||
strncpy(p->context, user->context, sizeof(p->context) - 1);
|
||||
if (strlen(user->callerid) && strlen(p->callerid))
|
||||
strncpy(p->callerid, user->callerid, sizeof(p->callerid) - 1);
|
||||
strncpy(p->username, user->name, sizeof(p->username) - 1);
|
||||
strncpy(p->accountcode, user->accountcode, sizeof(p->accountcode) -1);
|
||||
p->canreinvite = user->canreinvite;
|
||||
p->amaflags = user->amaflags;
|
||||
p->callgroup = user->callgroup;
|
||||
p->pickupgroup = user->pickupgroup;
|
||||
if (user->dtmfmode) {
|
||||
p->dtmfmode = user->dtmfmode;
|
||||
if (p->dtmfmode & SIP_DTMF_RFC2833)
|
||||
|
@ -3212,6 +3228,10 @@ static int check_user(struct sip_pvt *p, struct sip_request *req, char *cmd, cha
|
|||
}
|
||||
p->canreinvite = peer->canreinvite;
|
||||
strncpy(p->username, peer->name, sizeof(p->username) - 1);
|
||||
if (strlen(peer->context))
|
||||
strncpy(p->context, peer->context, sizeof(p->context) - 1);
|
||||
p->callgroup = peer->callgroup;
|
||||
p->pickupgroup = peer->pickupgroup;
|
||||
if (peer->dtmfmode) {
|
||||
p->dtmfmode = peer->dtmfmode;
|
||||
if (p->dtmfmode & SIP_DTMF_RFC2833)
|
||||
|
@ -4138,10 +4158,20 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
|
|||
case AST_STATE_DOWN:
|
||||
transmit_response(p, "100 Trying", req);
|
||||
ast_setstate(c, AST_STATE_RING);
|
||||
if (ast_pbx_start(c)) {
|
||||
ast_log(LOG_WARNING, "Failed to start PBX :(\n");
|
||||
if (strcmp(p->exten, ast_pickup_ext())) {
|
||||
if (ast_pbx_start(c)) {
|
||||
ast_log(LOG_WARNING, "Failed to start PBX :(\n");
|
||||
sip_hangup(c);
|
||||
transmit_response_reliable(p, "503 Unavailable", req);
|
||||
c = NULL;
|
||||
}
|
||||
} else if (ast_pickup_call(c)) {
|
||||
ast_log(LOG_WARNING, "Nothing to pick up\n");
|
||||
sip_hangup(c);
|
||||
transmit_response_reliable(p, "503 Unavailable", req);
|
||||
} else {
|
||||
ast_pthread_mutex_unlock(&c->lock);
|
||||
ast_hangup(c);
|
||||
c = NULL;
|
||||
}
|
||||
break;
|
||||
|
@ -4719,6 +4749,10 @@ static struct sip_user *build_user(char *name, struct ast_variable *v)
|
|||
} else if (!strcasecmp(v->name, "callerid")) {
|
||||
strncpy(user->callerid, v->value, sizeof(user->callerid)-1);
|
||||
user->hascallerid=1;
|
||||
} else if (!strcasecmp(v->name, "callgroup")) {
|
||||
user->callgroup = ast_get_group(v->value);
|
||||
} else if (!strcasecmp(v->name, "pickupgroup")) {
|
||||
user->pickupgroup = ast_get_group(v->value);
|
||||
} else if (!strcasecmp(v->name, "accountcode")) {
|
||||
strncpy(user->accountcode, v->value, sizeof(user->accountcode)-1);
|
||||
} else if (!strcasecmp(v->name, "amaflags")) {
|
||||
|
@ -4867,6 +4901,10 @@ static struct sip_peer *build_peer(char *name, struct ast_variable *v)
|
|||
ast_log(LOG_WARNING, "Cannot allow unknown format '%s'\n", v->value);
|
||||
else
|
||||
peer->capability |= format;
|
||||
} else if (!strcasecmp(v->name, "callgroup")) {
|
||||
peer->callgroup = ast_get_group(v->value);
|
||||
} else if (!strcasecmp(v->name, "pickupgroup")) {
|
||||
peer->pickupgroup = ast_get_group(v->value);
|
||||
} else if (!strcasecmp(v->name, "disallow")) {
|
||||
format = ast_getformatbyname(v->value);
|
||||
if (format < 1)
|
||||
|
|
|
@ -134,9 +134,9 @@ static int use_callerid = 1;
|
|||
|
||||
static int cur_signalling = -1;
|
||||
|
||||
static int cur_group = 0;
|
||||
static int cur_callergroup = 0;
|
||||
static int cur_pickupgroup = 0;
|
||||
static unsigned int cur_group = 0;
|
||||
static unsigned int cur_callergroup = 0;
|
||||
static unsigned int cur_pickupgroup = 0;
|
||||
static int relaxdtmf = 0;
|
||||
|
||||
static int immediate = 0;
|
||||
|
@ -370,13 +370,13 @@ static struct zt_pvt {
|
|||
char lastcallerid[AST_MAX_EXTENSION];
|
||||
char callwaitcid[AST_MAX_EXTENSION];
|
||||
char rdnis[AST_MAX_EXTENSION];
|
||||
int group;
|
||||
unsigned int group;
|
||||
int law;
|
||||
int confno; /* Our conference */
|
||||
int confusers; /* Who is using our conference */
|
||||
int propconfno; /* Propagated conference number */
|
||||
int callgroup;
|
||||
int pickupgroup;
|
||||
unsigned int callgroup;
|
||||
unsigned int pickupgroup;
|
||||
int immediate; /* Answer before getting digits? */
|
||||
int channel; /* Channel Number */
|
||||
int span; /* Span number */
|
||||
|
@ -475,32 +475,6 @@ static int cidrings[] = {
|
|||
#define CANBUSYDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_SF)) /* || (p->sig & __ZT_SIG_FXO) */)
|
||||
#define CANPROGRESSDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_SF)) /* || (p->sig & __ZT_SIG_FXO) */)
|
||||
|
||||
#if 0
|
||||
/* return non-zero if clear dtmf is appropriate */
|
||||
static int CLEARDTMF(struct ast_channel *chan) {
|
||||
struct zt_pvt *p = chan->pvt->pvt,*themp;
|
||||
struct ast_channel *them;
|
||||
if (!p)
|
||||
return 0;
|
||||
/* if not in a 3 way, we should be okay */
|
||||
if (p->thirdcallindex == -1) return 1;
|
||||
/* get the other side of the call's channel pointer */
|
||||
if (p->owners[p->normalindex] == chan)
|
||||
them = p->owners[p->thirdcallindex];
|
||||
else
|
||||
them = p->owners[p->normalindex];
|
||||
if (!them)
|
||||
return 0;
|
||||
if (!them->bridge) return 1;
|
||||
/* get their private structure, too */
|
||||
themp = them->pvt->pvt;
|
||||
/* if does not use zt bridge code, return 0 */
|
||||
if (them->pvt->bridge != zt_bridge) return 0;
|
||||
if (them->bridge->pvt->bridge != zt_bridge) return 0;
|
||||
return 1; /* okay, I guess we are okay to be clear */
|
||||
}
|
||||
#endif
|
||||
|
||||
static int zt_get_index(struct ast_channel *ast, struct zt_pvt *p, int nullok)
|
||||
{
|
||||
int res;
|
||||
|
@ -3449,6 +3423,11 @@ static struct ast_channel *zt_new(struct zt_pvt *i, int state, int startpbx, int
|
|||
tmp->pvt->indicate = zt_indicate;
|
||||
tmp->pvt->fixup = zt_fixup;
|
||||
tmp->pvt->setoption = zt_setoption;
|
||||
if ((i->sig == SIG_FXOKS) || (i->sig == SIG_FXOGS) || (i->sig == SIG_FXOLS)) {
|
||||
/* Only FXO signalled stuff can be picked up */
|
||||
tmp->callgroup = i->callgroup;
|
||||
tmp->pickupgroup = i->pickupgroup;
|
||||
}
|
||||
if (strlen(i->language))
|
||||
strncpy(tmp->language, i->language, sizeof(tmp->language)-1);
|
||||
if (strlen(i->musicclass))
|
||||
|
@ -3814,46 +3793,34 @@ static void *ss_thread(void *data)
|
|||
memset(exten, 0, sizeof(exten));
|
||||
timeout = firstdigittimeout;
|
||||
|
||||
} else if (!strcmp(exten,"*8#")){
|
||||
} else if (!strcmp(exten,ast_pickup_ext())) {
|
||||
/* Scan all channels and see if any there
|
||||
* ringing channqels with that have call groups
|
||||
* that equal this channels pickup group
|
||||
*/
|
||||
struct zt_pvt *chan_pvt=iflist;
|
||||
while(chan_pvt!=NULL){
|
||||
if((p!=chan_pvt) &&
|
||||
(p->pickupgroup & chan_pvt->callgroup) &&
|
||||
(chan_pvt->owner && (chan_pvt->owner->_state==AST_STATE_RING || chan_pvt->owner->_state == AST_STATE_RINGING)) &&
|
||||
chan_pvt->dialing
|
||||
){
|
||||
if (index == SUB_REAL) {
|
||||
if (p->subs[SUB_THREEWAY].owner) {
|
||||
/* If you make a threeway call and the *8# a call, it should actually
|
||||
look like a callwait */
|
||||
alloc_sub(p, SUB_CALLWAIT);
|
||||
swap_subs(p, SUB_CALLWAIT, SUB_THREEWAY);
|
||||
unalloc_sub(p, SUB_THREEWAY);
|
||||
}
|
||||
/* Switch us from Third call to Call Wait */
|
||||
ast_log(LOG_DEBUG, "Call pickup on chan %s\n",chan_pvt->owner->name);
|
||||
p->subs[index].needanswer=1;
|
||||
zt_enable_ec(p);
|
||||
if(ast_channel_masquerade(chan_pvt->owner,p->owner))
|
||||
printf("Error Masquerade failed on call-pickup\n");
|
||||
ast_hangup(p->owner);
|
||||
} else {
|
||||
ast_log(LOG_WARNING, "Huh? Got *8# on call not on real\n");
|
||||
ast_hangup(p->owner);
|
||||
}
|
||||
return NULL;
|
||||
if (index == SUB_REAL) {
|
||||
/* Switch us from Third call to Call Wait */
|
||||
if (p->subs[SUB_THREEWAY].owner) {
|
||||
/* If you make a threeway call and the *8# a call, it should actually
|
||||
look like a callwait */
|
||||
alloc_sub(p, SUB_CALLWAIT);
|
||||
swap_subs(p, SUB_CALLWAIT, SUB_THREEWAY);
|
||||
unalloc_sub(p, SUB_THREEWAY);
|
||||
}
|
||||
chan_pvt=chan_pvt->next;
|
||||
zt_enable_ec(p);
|
||||
if (ast_pickup_call(chan)) {
|
||||
ast_log(LOG_DEBUG, "No call pickup possible...\n");
|
||||
res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_CONGESTION);
|
||||
zt_wait_event(p->subs[index].zfd);
|
||||
}
|
||||
ast_hangup(chan);
|
||||
return NULL;
|
||||
} else {
|
||||
ast_log(LOG_WARNING, "Huh? Got *8# on call not on real\n");
|
||||
ast_hangup(chan);
|
||||
return NULL;
|
||||
}
|
||||
ast_log(LOG_DEBUG, "No call pickup possible...\n");
|
||||
res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_CONGESTION);
|
||||
zt_wait_event(p->subs[index].zfd);
|
||||
ast_hangup(chan);
|
||||
return NULL;
|
||||
|
||||
} else if (!p->hidecallerid && !strcmp(exten, "*67")) {
|
||||
if (option_verbose > 2)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "Disabling Caller*ID on %s\n", chan->name);
|
||||
|
@ -5095,42 +5062,6 @@ static struct ast_channel *zt_request(char *type, int format, void *data)
|
|||
}
|
||||
|
||||
|
||||
static int get_group(char *s)
|
||||
{
|
||||
char *copy;
|
||||
char *piece;
|
||||
char *c=NULL;
|
||||
int start=0, finish=0,x;
|
||||
int group = 0;
|
||||
copy = strdup(s);
|
||||
if (!copy) {
|
||||
ast_log(LOG_ERROR, "Out of memory\n");
|
||||
return 0;
|
||||
}
|
||||
c = copy;
|
||||
piece = strsep(&c, ",");
|
||||
while(piece) {
|
||||
if (sscanf(piece, "%d-%d", &start, &finish) == 2) {
|
||||
/* Range */
|
||||
} else if (sscanf(piece, "%d", &start)) {
|
||||
/* Just one */
|
||||
finish = start;
|
||||
} else {
|
||||
ast_log(LOG_ERROR, "Syntax error parsing '%s' at '%s'. Using '0'\n", s,piece);
|
||||
return 0;
|
||||
}
|
||||
piece = strsep(&c, ",");
|
||||
for (x=start;x<=finish;x++) {
|
||||
if ((x > 31) || (x < 0)) {
|
||||
ast_log(LOG_WARNING, "Ignoring invalid group %d\n", x);
|
||||
} else
|
||||
group |= (1 << x);
|
||||
}
|
||||
}
|
||||
free(copy);
|
||||
return group;
|
||||
}
|
||||
|
||||
#ifdef ZAPATA_PRI
|
||||
|
||||
static int pri_find_empty_chan(struct zt_pri *pri)
|
||||
|
@ -6283,11 +6214,11 @@ int load_module()
|
|||
} else if (!strcasecmp(v->name, "stripmsd")) {
|
||||
stripmsd = atoi(v->value);
|
||||
} else if (!strcasecmp(v->name, "group")) {
|
||||
cur_group = get_group(v->value);
|
||||
cur_group = ast_get_group(v->value);
|
||||
} else if (!strcasecmp(v->name, "callgroup")) {
|
||||
cur_callergroup = get_group(v->value);
|
||||
cur_callergroup = ast_get_group(v->value);
|
||||
} else if (!strcasecmp(v->name, "pickupgroup")) {
|
||||
cur_pickupgroup = get_group(v->value);
|
||||
cur_pickupgroup = ast_get_group(v->value);
|
||||
} else if (!strcasecmp(v->name, "immediate")) {
|
||||
immediate = ast_true(v->value);
|
||||
} else if (!strcasecmp(v->name, "rxgain")) {
|
||||
|
|
4
cli.c
4
cli.c
|
@ -405,6 +405,8 @@ static int handle_showchan(int fd, int argc, char *argv[])
|
|||
" Context: %s\n"
|
||||
" Extension: %s\n"
|
||||
" Priority: %d\n"
|
||||
" Call Group: %d\n"
|
||||
" Pickup Group: %d\n"
|
||||
" Application: %s\n"
|
||||
" Data: %s\n"
|
||||
" Stack: %d\n"
|
||||
|
@ -414,7 +416,7 @@ static int handle_showchan(int fd, int argc, char *argv[])
|
|||
(c->dnid ? c->dnid : "(N/A)" ), ast_state2str(c->_state), c->_state, c->rings, c->nativeformats, c->writeformat, c->readformat,
|
||||
c->fds[0], c->fin & 0x7fffffff, (c->fin & 0x80000000) ? " (DEBUGGED)" : "",
|
||||
c->fout & 0x7fffffff, (c->fout & 0x80000000) ? " (DEBUGGED)" : "", c->whentohangup,
|
||||
c->context, c->exten, c->priority, ( c->appl ? c->appl : "(N/A)" ),
|
||||
c->context, c->exten, c->priority, c->callgroup, c->pickupgroup, ( c->appl ? c->appl : "(N/A)" ),
|
||||
( c-> data ? (strlen(c->data) ? c->data : "(Empty)") : "(None)"),
|
||||
c->stack, (c->blocking ? c->blockproc : "(Not Blocking)"));
|
||||
|
||||
|
|
|
@ -27,6 +27,8 @@ context = default ; Default for incoming calls
|
|||
;secret=blah
|
||||
;host=dynamic
|
||||
;qualify=1000 ; Consider it down if it's 1 second to reply
|
||||
;callgroup=1,3-4
|
||||
;pickupgroup=1,3-4
|
||||
;defaultip=192.168.0.60
|
||||
|
||||
;[cisco]
|
||||
|
|
|
@ -186,6 +186,9 @@ struct ast_channel {
|
|||
/* A linked list for variables */
|
||||
struct ast_var_t *vars;
|
||||
AST_LIST_HEAD(varshead,ast_var_t) varshead;
|
||||
|
||||
unsigned int callgroup;
|
||||
unsigned int pickupgroup;
|
||||
|
||||
/*! For easy linking */
|
||||
struct ast_channel *next;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Call Parking API
|
||||
* Call Parking and Pickup API
|
||||
*
|
||||
* Copyright (C) 1999, Mark Spencer
|
||||
*
|
||||
|
@ -42,10 +42,15 @@ extern int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *hos
|
|||
/*! Returns the call parking extension for drivers that provide special
|
||||
call parking help */
|
||||
extern char *ast_parking_ext(void);
|
||||
extern char *ast_pickup_ext(void);
|
||||
|
||||
//! Bridge a call, optionally allowing redirection
|
||||
|
||||
extern int ast_bridge_call(struct ast_channel *chan, struct ast_channel *peer, int allowredirect, int allowdisconnect);
|
||||
|
||||
extern unsigned int ast_get_group(char *s);
|
||||
|
||||
extern int ast_pickup_call(struct ast_channel *chan);
|
||||
|
||||
|
||||
#endif /* _PARKING_H */
|
||||
|
|
|
@ -49,6 +49,8 @@ static char parking_con[AST_MAX_EXTENSION] = "parkedcalls";
|
|||
/* Extension you type to park the call */
|
||||
static char parking_ext[AST_MAX_EXTENSION] = "700";
|
||||
|
||||
static char pickup_ext[AST_MAX_EXTENSION] = "*8";
|
||||
|
||||
/* First available extension for parking */
|
||||
static int parking_start = 701;
|
||||
|
||||
|
@ -93,6 +95,11 @@ char *ast_parking_ext(void)
|
|||
return parking_ext;
|
||||
}
|
||||
|
||||
char *ast_pickup_ext(void)
|
||||
{
|
||||
return pickup_ext;
|
||||
}
|
||||
|
||||
int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
|
||||
{
|
||||
/* We put the user in the parking list, then wake up the parking thread to be sure it looks
|
||||
|
@ -565,6 +572,72 @@ int load_module(void)
|
|||
return res;
|
||||
}
|
||||
|
||||
int ast_pickup_call(struct ast_channel *chan)
|
||||
{
|
||||
struct ast_channel *cur;
|
||||
int res = -1;
|
||||
cur = ast_channel_walk(NULL);
|
||||
while(cur) {
|
||||
if (!cur->pbx &&
|
||||
(cur != chan) &&
|
||||
(chan->pickupgroup & cur->callgroup) &&
|
||||
((cur->_state == AST_STATE_RINGING) ||
|
||||
(cur->_state == AST_STATE_RING))) {
|
||||
break;
|
||||
}
|
||||
cur = ast_channel_walk(cur);
|
||||
}
|
||||
if (cur) {
|
||||
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, 0);
|
||||
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 */
|
||||
} else {
|
||||
ast_log(LOG_DEBUG, "No call pickup possible...\n");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
unsigned int ast_get_group(char *s)
|
||||
{
|
||||
char *copy;
|
||||
char *piece;
|
||||
char *c=NULL;
|
||||
int start=0, finish=0,x;
|
||||
unsigned int group = 0;
|
||||
copy = strdupa(s);
|
||||
if (!copy) {
|
||||
ast_log(LOG_ERROR, "Out of memory\n");
|
||||
return 0;
|
||||
}
|
||||
c = copy;
|
||||
|
||||
while((piece = strsep(&c, ","))) {
|
||||
if (sscanf(piece, "%d-%d", &start, &finish) == 2) {
|
||||
/* Range */
|
||||
} else if (sscanf(piece, "%d", &start)) {
|
||||
/* Just one */
|
||||
finish = start;
|
||||
} else {
|
||||
ast_log(LOG_ERROR, "Syntax error parsing '%s' at '%s'. Using '0'\n", s,piece);
|
||||
return 0;
|
||||
}
|
||||
for (x=start;x<=finish;x++) {
|
||||
if ((x > 31) || (x < 0)) {
|
||||
ast_log(LOG_WARNING, "Ignoring invalid group %d\n", x);
|
||||
} else
|
||||
group |= (1 << x);
|
||||
}
|
||||
}
|
||||
return group;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
|
Reference in New Issue