Plane commits (a.k.a. the Delta deltas): 1) Make muted reconnect 2) Add "X" option to meetme and add ${MEETME_EXIT_CONTEXT}, 3) Allow SIP call parking with supervised transfer, 4) Only create parking entries when calls actually get parked, 5) Add "sunshine" song, 6) Update hardware documentation, 7) Don't load empty strings from history file

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@3572 65c4cc65-6c06-0410-ace0-fbb531ad65f3
1.0
Mark Spencer 21 years ago
parent 437f625786
commit f3522b6c01

@ -1,3 +1,10 @@
-- Additional CDR backends
-- Allow muted to reconnect
-- Call parking improvements (including SIP parking support)
-- Added licensed hold music from FreePlayMusic
-- GR-303 and Zap improvements
-- More bug fixes from the bug tracker
-- Improved FreeBSD/OpenBSD/MacOS X support
Asterisk 1.0-RC1 Asterisk 1.0-RC1
-- Innumerable bug fixes and features from the bug tracker -- Innumerable bug fixes and features from the bug tracker
-- Added Open Settlement Protocol (OSP) support -- Added Open Settlement Protocol (OSP) support

@ -16,11 +16,11 @@ Zaptel compatible hardware
* Wildcard X100P - Single FXO interface connects to Loopstart phone * Wildcard X100P - Single FXO interface connects to Loopstart phone
line line
* Wildcard T400P - Quad T1 interface connects to four T1/PRI * Wildcard T400P (obsolete) - Quad T1 interface connects to four T1/PRI
interfaces. Supports RBS and PRI voice and PPP, FR, and HDLC data. interfaces. Supports RBS and PRI voice and PPP, FR, and HDLC data.
* Wildcard E400P - Quad E1 interface connects to four E1/PRI (or PRA) * Wildcard E400P (obsolete)- Quad E1 interface connects to four E1/PRI
interfaces. Supports PRA/PRI, EuroISDN voice and PPP, FR, HDLC data. (or PRA) interfaces. Supports PRA/PRI, EuroISDN voice and data.
* Wildcard T100P - Single T1 interface connects to a single T1/PRI * Wildcard T100P - Single T1 interface connects to a single T1/PRI
interface. Supports RBS and PRI voice and PPP, FR, and HDLC data. interface. Supports RBS and PRI voice and PPP, FR, and HDLC data.

@ -59,6 +59,9 @@ static char *descrip =
" 'm' -- set monitor only mode (Listen only, no talking)\n" " 'm' -- set monitor only mode (Listen only, no talking)\n"
" 't' -- set talk only mode. (Talk only, no listening)\n" " 't' -- set talk only mode. (Talk only, no listening)\n"
" 'p' -- allow user to exit the conference by pressing '#'\n" " 'p' -- allow user to exit the conference by pressing '#'\n"
" 'X' -- allow user to exit the conference by entering a valid single\n"
" digit extension ${MEETME_EXIT_CONTEXT} or the current context\n"
" if that variable is not defined.\n"
" 'd' -- dynamically add conference\n" " 'd' -- dynamically add conference\n"
" 'D' -- dynamically add conference, prompting for a PIN\n" " 'D' -- dynamically add conference, prompting for a PIN\n"
" 'e' -- select an empty conference\n" " 'e' -- select an empty conference\n"
@ -148,6 +151,7 @@ static int admin_exec(struct ast_channel *chan, void *data);
#define CONFFLAG_MOH (1 << 9) /* Set to have music on hold when user is alone in conference */ #define CONFFLAG_MOH (1 << 9) /* Set to have music on hold when user is alone in conference */
#define CONFFLAG_ADMINEXIT (1 << 10) /* If set the MeetMe will return if all marked with this flag left */ #define CONFFLAG_ADMINEXIT (1 << 10) /* If set the MeetMe will return if all marked with this flag left */
#define CONFFLAG_WAITMARKED (1 << 11) /* If set, the MeetMe will wait until a marked user enters */ #define CONFFLAG_WAITMARKED (1 << 11) /* If set, the MeetMe will wait until a marked user enters */
#define CONFFLAG_EXIT_CONTEXT (1 << 12) /* If set, the MeetMe will wait until a marked user enters */
static int careful_write(int fd, unsigned char *data, int len) static int careful_write(int fd, unsigned char *data, int len)
@ -504,6 +508,7 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int c
char *agifile; char *agifile;
char *agifiledefault = "conf-background.agi"; char *agifiledefault = "conf-background.agi";
char meetmesecs[30] = ""; char meetmesecs[30] = "";
char exitcontext[AST_MAX_EXTENSION] = "";
ZT_BUFFERINFO bi; ZT_BUFFERINFO bi;
char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET]; char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
@ -560,6 +565,14 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int c
user->adminflags = 0; user->adminflags = 0;
ast_mutex_unlock(&conflock); ast_mutex_unlock(&conflock);
origquiet = confflags & CONFFLAG_QUIET; origquiet = confflags & CONFFLAG_QUIET;
if (confflags & CONFFLAG_EXIT_CONTEXT) {
if ((agifile = pbx_builtin_getvar_helper(chan, "MEETME_EXIT_CONTEXT")))
strncpy(exitcontext, agifile, sizeof(exitcontext) - 1);
else if (!ast_strlen_zero(chan->macrocontext))
strncpy(exitcontext, chan->macrocontext, sizeof(exitcontext) - 1);
else
strncpy(exitcontext, chan->context, sizeof(exitcontext) - 1);
}
while((confflags & CONFFLAG_WAITMARKED) && (conf->markedusers < 0)) { while((confflags & CONFFLAG_WAITMARKED) && (conf->markedusers < 0)) {
confflags &= ~CONFFLAG_QUIET; confflags &= ~CONFFLAG_QUIET;
confflags |= origquiet; confflags |= origquiet;
@ -806,7 +819,18 @@ zapretry:
f = ast_read(c); f = ast_read(c);
if (!f) if (!f)
break; break;
if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#') && (confflags & CONFFLAG_POUNDEXIT)) { if ((f->frametype == AST_FRAME_DTMF) && (confflags & CONFFLAG_EXIT_CONTEXT)) {
char tmp[2];
tmp[0] = f->subclass;
tmp[1] = '\0';
if (ast_exists_extension(chan, exitcontext, tmp, 1, chan->callerid)) {
strncpy(chan->context, exitcontext, sizeof(chan->context) - 1);
strncpy(chan->exten, tmp, sizeof(chan->exten) - 1);
chan->priority = 0;
ret = 0;
break;
}
} else if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#') && (confflags & CONFFLAG_POUNDEXIT)) {
ret = 0; ret = 0;
break; break;
} else if (((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*') && (confflags & CONFFLAG_STARMENU)) || ((f->frametype == AST_FRAME_DTMF) && menu_active)) { } else if (((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*') && (confflags & CONFFLAG_STARMENU)) || ((f->frametype == AST_FRAME_DTMF) && menu_active)) {
@ -1187,6 +1211,8 @@ static int conf_exec(struct ast_channel *chan, void *data)
confflags |= CONFFLAG_MOH; confflags |= CONFFLAG_MOH;
if (strchr(inflags, 'x')) if (strchr(inflags, 'x'))
confflags |= CONFFLAG_ADMINEXIT; confflags |= CONFFLAG_ADMINEXIT;
if (strchr(inflags, 'X'))
confflags |= CONFFLAG_EXIT_CONTEXT;
if (strchr(inflags, 'b')) if (strchr(inflags, 'b'))
confflags |= CONFFLAG_AGI; confflags |= CONFFLAG_AGI;
if (strchr(inflags, 'w')) if (strchr(inflags, 'w'))

@ -689,7 +689,7 @@ static int remoteconsolehandler(char *s)
{ {
int ret = 0; int ret = 0;
/* Called when readline data is available */ /* Called when readline data is available */
if (s && !ast_strlen_zero(s)) if (s && !ast_all_zeros(s))
ast_el_add_history(s); ast_el_add_history(s);
/* Give the console access to the shell */ /* Give the console access to the shell */
if (s) { if (s) {
@ -1341,6 +1341,8 @@ static int ast_el_read_history(char *filename)
fgets(buf, sizeof(buf), f); fgets(buf, sizeof(buf), f);
if (!strcmp(buf, "_HiStOrY_V2_\n")) if (!strcmp(buf, "_HiStOrY_V2_\n"))
continue; continue;
if (ast_all_zeros(buf))
continue;
if ((ret = ast_el_add_history(buf)) == -1) if ((ret = ast_el_add_history(buf)) == -1)
break; break;
} }

@ -2808,9 +2808,9 @@ static void handle_hd_hf(struct mgcp_subchannel *sub, char *ev)
} }
} else { } else {
if (p->hookstate == MGCP_OFFHOOK) { if (p->hookstate == MGCP_OFFHOOK) {
ast_log(LOG_WARNING, "Off hook, but alreaedy have owner on %s@%s\n", p->name, p->parent->name); ast_log(LOG_WARNING, "Off hook, but already have owner on %s@%s\n", p->name, p->parent->name);
} else { } else {
ast_log(LOG_WARNING, "On hook, but alreaedy have owner on %s@%s\n", p->name, p->parent->name); ast_log(LOG_WARNING, "On hook, but already have owner on %s@%s\n", p->name, p->parent->name);
ast_log(LOG_WARNING, "If we're onhook why are we here trying to handle a hd or hf?"); ast_log(LOG_WARNING, "If we're onhook why are we here trying to handle a hd or hf?");
} }
if (sub->owner->bridge) { if (sub->owner->bridge) {

@ -535,8 +535,16 @@ int main(int argc, char *argv[])
if (needfork) if (needfork)
daemon(0,0); daemon(0,0);
for(;;) { for(;;) {
if (wait_event()) if (wait_event()) {
fclose(astf);
while(connect_asterisk()) {
sleep(5);
}
if (login_asterisk()) {
fclose(astf);
exit(1); exit(1);
} }
}
}
exit(0); exit(0);
} }

12
pbx.c

@ -1,4 +1,4 @@
/* /*
* Asterisk -- A telephony toolkit for Linux. * Asterisk -- A telephony toolkit for Linux.
* *
* Core PBX routines. * Core PBX routines.
@ -2044,7 +2044,7 @@ int ast_context_remove_include2(struct ast_context *con, char *include, char *re
while (i) { while (i) {
/* find our include */ /* find our include */
if (!strcmp(i->name, include) && if (!strcmp(i->name, include) &&
(!strcmp(i->registrar, registrar) || !registrar)) { (!registrar || !strcmp(i->registrar, registrar))) {
/* remove from list */ /* remove from list */
if (pi) if (pi)
pi->next = i->next; pi->next = i->next;
@ -2116,7 +2116,7 @@ int ast_context_remove_switch2(struct ast_context *con, char *sw, char *data, ch
while (i) { while (i) {
/* find our switch */ /* find our switch */
if (!strcmp(i->name, sw) && !strcmp(i->data, data) && if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
(!strcmp(i->registrar, registrar) || !registrar)) { (!registrar || !strcmp(i->registrar, registrar))) {
/* remove from list */ /* remove from list */
if (pi) if (pi)
pi->next = i->next; pi->next = i->next;
@ -2189,7 +2189,7 @@ int ast_context_remove_extension2(struct ast_context *con, char *extension, int
/* look for right extension */ /* look for right extension */
if (!strcmp(exten->exten, extension) && if (!strcmp(exten->exten, extension) &&
(!strcmp(exten->registrar, registrar) || !registrar)) { (!registrar || !strcmp(exten->registrar, registrar))) {
struct ast_exten *peer; struct ast_exten *peer;
/* should we free all peers in this extension? (priority == 0)? */ /* should we free all peers in this extension? (priority == 0)? */
@ -2224,7 +2224,7 @@ int ast_context_remove_extension2(struct ast_context *con, char *extension, int
while (peer) { while (peer) {
/* is this our extension? */ /* is this our extension? */
if (peer->priority == priority && if (peer->priority == priority &&
(!strcmp(peer->registrar, registrar) || !registrar)) { (!registrar || !strcmp(peer->registrar, registrar) )) {
/* we are first priority extension? */ /* we are first priority extension? */
if (!previous_peer) { if (!previous_peer) {
/* exists previous extension here? */ /* exists previous extension here? */
@ -3459,7 +3459,7 @@ int ast_context_remove_ignorepat2(struct ast_context *con, char *ignorepat, char
ip = con->ignorepats; ip = con->ignorepats;
while (ip) { while (ip) {
if (!strcmp(ip->pattern, ignorepat) && if (!strcmp(ip->pattern, ignorepat) &&
(registrar == ip->registrar || !registrar)) { (!registrar || (registrar == ip->registrar))) {
if (ipl) { if (ipl) {
ipl->next = ip->next; ipl->next = ip->next;
free(ip); free(ip);

@ -62,7 +62,7 @@ static int parking_stop = 750;
static int transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; static int transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
/* Registrar for operations */ /* Registrar for operations */
static char *registrar = "res_parking"; static char *registrar = "res_features";
static char *synopsis = "Answer a parked call"; static char *synopsis = "Answer a parked call";
@ -72,6 +72,18 @@ static char *descrip = "ParkedCall(exten):"
"into the dialplan, although you should include the 'parkedcalls'\n" "into the dialplan, although you should include the 'parkedcalls'\n"
"context.\n"; "context.\n";
static char *parkcall = "Park";
static char *synopsis2 = "Park yourself";
static char *descrip2 = "Park(exten):"
"Used to park yourself (typically in combination with a supervised\n"
"transfer to know the parking space. This Application is always\n"
"registered internally and does not need to be explicitly added\n"
"into the dialplan, although you should include the 'parkedcalls'\n"
"context.\n";
struct parkeduser { struct parkeduser {
struct ast_channel *chan; struct ast_channel *chan;
struct timeval start; struct timeval start;
@ -81,6 +93,7 @@ struct parkeduser {
char exten[AST_MAX_EXTENSION]; char exten[AST_MAX_EXTENSION];
int priority; int priority;
int parkingtime; int parkingtime;
int notquiteyet;
struct parkeduser *next; struct parkeduser *next;
}; };
@ -110,6 +123,8 @@ int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeou
after these channels too */ after these channels too */
struct parkeduser *pu, *cur; struct parkeduser *pu, *cur;
int x; int x;
char exten[AST_MAX_EXTENSION];
struct ast_context *con;
pu = malloc(sizeof(struct parkeduser)); pu = malloc(sizeof(struct parkeduser));
if (pu) { if (pu) {
ast_mutex_lock(&parking_lock); ast_mutex_lock(&parking_lock);
@ -129,6 +144,7 @@ int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeou
pu->chan = chan; pu->chan = chan;
/* Start music on hold */ /* Start music on hold */
if (chan != peer)
ast_moh_start(pu->chan, NULL); ast_moh_start(pu->chan, NULL);
gettimeofday(&pu->start, NULL); gettimeofday(&pu->start, NULL);
pu->parkingnum = x; pu->parkingnum = x;
@ -154,6 +170,9 @@ int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeou
pu->priority = chan->priority; pu->priority = chan->priority;
pu->next = parkinglot; pu->next = parkinglot;
parkinglot = pu; parkinglot = pu;
/* If parking a channel directly, don't quiet yet get parking running on it */
if (peer == chan)
pu->notquiteyet = 1;
ast_mutex_unlock(&parking_lock); ast_mutex_unlock(&parking_lock);
/* Wake up the (presumably select()ing) thread */ /* Wake up the (presumably select()ing) thread */
pthread_kill(parking_thread, SIGURG); pthread_kill(parking_thread, SIGURG);
@ -171,8 +190,26 @@ int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeou
,(pu->chan->callerid ? pu->chan->callerid : "") ,(pu->chan->callerid ? pu->chan->callerid : "")
); );
if (peer) if (peer) {
ast_say_digits(peer, pu->parkingnum, "", peer->language); ast_say_digits(peer, pu->parkingnum, "", peer->language);
if (pu->notquiteyet) {
/* Wake up parking thread if we're really done */
ast_moh_start(pu->chan, NULL);
pu->notquiteyet = 0;
pthread_kill(parking_thread, SIGURG);
}
}
con = ast_context_find(parking_con);
if (!con) {
con = ast_context_create(NULL,parking_con, registrar);
if (!con) {
ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
}
}
if (con) {
snprintf(exten, sizeof(exten), "%d", x);
ast_add_extension2(con, 1, exten, 1, NULL, parkedcall, strdup(exten), free, registrar);
}
return 0; return 0;
} else { } else {
ast_log(LOG_WARNING, "No more parking spaces\n"); ast_log(LOG_WARNING, "No more parking spaces\n");
@ -441,6 +478,8 @@ static void *do_parking_thread(void *ignore)
struct parkeduser *pu, *pl, *pt = NULL; struct parkeduser *pu, *pl, *pt = NULL;
struct timeval tv; struct timeval tv;
struct ast_frame *f; struct ast_frame *f;
char exten[AST_MAX_EXTENSION];
struct ast_context *con;
int x; int x;
fd_set rfds, efds; fd_set rfds, efds;
fd_set nrfds, nefds; fd_set nrfds, nefds;
@ -456,6 +495,12 @@ static void *do_parking_thread(void *ignore)
FD_ZERO(&nrfds); FD_ZERO(&nrfds);
FD_ZERO(&nefds); FD_ZERO(&nefds);
while(pu) { while(pu) {
if (pu->notquiteyet) {
/* Pretend this one isn't here yet */
pl = pu;
pu = pu->next;
continue;
}
tms = (tv.tv_sec - pu->start.tv_sec) * 1000 + (tv.tv_usec - pu->start.tv_usec) / 1000; tms = (tv.tv_sec - pu->start.tv_sec) * 1000 + (tv.tv_usec - pu->start.tv_usec) / 1000;
if (tms > pu->parkingtime) { if (tms > pu->parkingtime) {
/* They've been waiting too long, send them back to where they came. Theoretically they /* They've been waiting too long, send them back to where they came. Theoretically they
@ -477,6 +522,13 @@ static void *do_parking_thread(void *ignore)
parkinglot = pu->next; parkinglot = pu->next;
pt = pu; pt = pu;
pu = pu->next; pu = pu->next;
con = ast_context_find(parking_con);
if (con) {
snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
if (ast_context_remove_extension2(con, exten, 1, NULL))
ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
} else
ast_log(LOG_WARNING, "Whoa, no parking context?\n");
free(pt); free(pt);
} else { } else {
for (x=0;x<AST_MAX_FDS;x++) { for (x=0;x<AST_MAX_FDS;x++) {
@ -498,6 +550,13 @@ static void *do_parking_thread(void *ignore)
parkinglot = pu->next; parkinglot = pu->next;
pt = pu; pt = pu;
pu = pu->next; pu = pu->next;
con = ast_context_find(parking_con);
if (con) {
snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
if (ast_context_remove_extension2(con, exten, 1, NULL))
ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
} else
ast_log(LOG_WARNING, "Whoa, no parking context?\n");
free(pt); free(pt);
break; break;
} else { } else {
@ -537,12 +596,37 @@ std: for (x=0;x<AST_MAX_FDS;x++) {
return NULL; /* Never reached */ return NULL; /* Never reached */
} }
static int park_call_exec(struct ast_channel *chan, void *data)
{
/* Data is unused at the moment but could contain a parking
lot context eventually */
int res=0;
struct localuser *u;
LOCAL_USER_ADD(u);
/* Setup the exten/priority to be s/1 since we don't know
where this call should return */
strcpy(chan->exten, "s");
chan->priority = 1;
if (chan->_state != AST_STATE_UP)
res = ast_answer(chan);
if (!res)
res = ast_safe_sleep(chan, 1000);
if (!res)
res = ast_park_call(chan, chan, 0, NULL);
LOCAL_USER_REMOVE(u);
if (!res)
res = AST_PBX_KEEPALIVE;
return res;
}
static int park_exec(struct ast_channel *chan, void *data) static int park_exec(struct ast_channel *chan, void *data)
{ {
int res=0; int res=0;
struct localuser *u; struct localuser *u;
struct ast_channel *peer=NULL; struct ast_channel *peer=NULL;
struct parkeduser *pu, *pl=NULL; struct parkeduser *pu, *pl=NULL;
char exten[AST_MAX_EXTENSION];
struct ast_context *con;
int park; int park;
int dres; int dres;
struct ast_bridge_config config; struct ast_bridge_config config;
@ -569,6 +653,13 @@ static int park_exec(struct ast_channel *chan, void *data)
ast_mutex_unlock(&parking_lock); ast_mutex_unlock(&parking_lock);
if (pu) { if (pu) {
peer = pu->chan; peer = pu->chan;
con = ast_context_find(parking_con);
if (con) {
snprintf(exten, sizeof(exten), "%d", pu->parkingnum);
if (ast_context_remove_extension2(con, exten, 1, NULL))
ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
} else
ast_log(LOG_WARNING, "Whoa, no parking context?\n");
free(pu); free(pu);
} }
/* JK02: it helps to answer the channel if not already up */ /* JK02: it helps to answer the channel if not already up */
@ -696,10 +787,8 @@ static int manager_parking_status( struct mansession *s, struct message *m )
int load_module(void) int load_module(void)
{ {
int res; int res;
int x;
int start, end; int start, end;
struct ast_context *con; struct ast_context *con;
char exten[AST_MAX_EXTENSION];
struct ast_config *cfg; struct ast_config *cfg;
struct ast_variable *var; struct ast_variable *var;
@ -750,12 +839,11 @@ int load_module(void)
return -1; return -1;
} }
} }
for(x=parking_start; x<=parking_stop;x++) { ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, parkcall, strdup(""),free, registrar);
snprintf(exten, sizeof(exten), "%d", x);
ast_add_extension2(con, 1, exten, 1, NULL, parkedcall, strdup(exten), free, registrar);
}
pthread_create(&parking_thread, NULL, do_parking_thread, NULL); pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
res = ast_register_application(parkedcall, park_exec, synopsis, descrip); res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
if (!res)
res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
if (!res) { if (!res) {
ast_manager_register( "ParkedCalls", 0, manager_parking_status, "List parked calls" ); ast_manager_register( "ParkedCalls", 0, manager_parking_status, "List parked calls" );
} }
@ -802,7 +890,7 @@ int unload_module(void)
ast_manager_unregister( "ParkedCalls" ); ast_manager_unregister( "ParkedCalls" );
ast_cli_unregister(&showparked); ast_cli_unregister(&showparked);
ast_unregister_application(parkcall);
return ast_unregister_application(parkedcall); return ast_unregister_application(parkedcall);
} }

Binary file not shown.
Loading…
Cancel
Save