Sun Feb 16 07:00:01 CET 2003
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@616 f38db490-d61c-443f-a65b-d21fe96a405b
This commit is contained in:
parent
dae2009f95
commit
175c755fef
6
CHANGES
6
CHANGES
|
@ -1,3 +1,9 @@
|
|||
-- Make HOLD on SIP make use of asterisk MOH
|
||||
-- Add supervised transfer (tested with Pingtel only)
|
||||
-- Allow maxexpirey and defaultexpirey to be runtime configurable for SIP
|
||||
-- Preliminary codec 13 support (RFC3389)
|
||||
-- Add app_authenticate for general purpose authentication
|
||||
-- Optimize RTP and smoother
|
||||
-- Create special variable "EXTEN-n" where it is extension stripped by n MSD
|
||||
-- Fix uninitialized frame pointer in channel.c
|
||||
-- Add global variables support under [globals] of extensions.conf
|
||||
|
|
2
Makefile
2
Makefile
|
@ -144,7 +144,7 @@ datafiles: all
|
|||
exit 1; \
|
||||
fi; \
|
||||
done
|
||||
for x in sounds/vm-* sounds/transfer* sounds/pbx-* sounds/ss-* sounds/beep* sounds/dir-* sounds/conf-* sounds/agent-* sounds/invalid* sounds/tt-*; do \
|
||||
for x in sounds/vm-* sounds/transfer* sounds/pbx-* sounds/ss-* sounds/beep* sounds/dir-* sounds/conf-* sounds/agent-* sounds/invalid* sounds/tt-* sounds/auth-*; do \
|
||||
if grep -q "^%`basename $$x`%" sounds.txt; then \
|
||||
install $$x $(ASTVARLIBDIR)/sounds ; \
|
||||
else \
|
||||
|
|
|
@ -17,7 +17,8 @@ APPS=app_dial.so app_playback.so app_voicemail.so app_directory.so app_intercom.
|
|||
app_agi.so app_qcall.so app_adsiprog.so app_getcpeid.so app_milliwatt.so \
|
||||
app_zapateller.so app_datetime.so app_setcallerid.so app_festival.so \
|
||||
app_queue.so app_senddtmf.so app_parkandannounce.so app_striplsd.so \
|
||||
app_setcidname.so app_lookupcidname.so app_substring.so app_macro.so
|
||||
app_setcidname.so app_lookupcidname.so app_substring.so app_macro.so \
|
||||
app_authenticate.so
|
||||
|
||||
#APPS+=app_sql_postgres.so
|
||||
#APPS+=app_sql_odbc.so
|
||||
|
|
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Execute arbitrary authenticate commands
|
||||
*
|
||||
* Copyright (C) 1999, Mark Spencer
|
||||
*
|
||||
* Mark Spencer <markster@linux-support.net>
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
#include <asterisk/lock.h>
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/app.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
|
||||
static char *tdesc = "Authentication Application";
|
||||
|
||||
static char *app = "Authenticate";
|
||||
|
||||
static char *synopsis = "Authenticate a user";
|
||||
|
||||
static char *descrip =
|
||||
" Authenticate(password[|options]): Requires a user to enter a"
|
||||
"given password in order to continue execution. If the\n"
|
||||
"password begins with the '/' character, it is interpreted as\n"
|
||||
"a file which contains a list of valid passwords (1 per line).\n"
|
||||
"an optional set of opions may be provided by concatenating any\n"
|
||||
"of the following letters:\n"
|
||||
" a - Set account code to the password that is entered\n"
|
||||
"\n"
|
||||
"Returns 0 if the user enters a valid password within three\n"
|
||||
"tries, or -1 otherwise (or on hangup).\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int auth_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
int retries;
|
||||
struct localuser *u;
|
||||
char password[256]="";
|
||||
char passwd[256];
|
||||
char *opts;
|
||||
char *prompt;
|
||||
if (!data || !strlen(data)) {
|
||||
ast_log(LOG_WARNING, "Authenticate requires an argument(password)\n");
|
||||
return -1;
|
||||
}
|
||||
LOCAL_USER_ADD(u);
|
||||
if (chan->_state != AST_STATE_UP) {
|
||||
res = ast_answer(chan);
|
||||
if (res) {
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
strncpy(password, data, sizeof(password) - 1);
|
||||
opts=strchr(password, '|');
|
||||
if (opts) {
|
||||
*opts = 0;
|
||||
opts++;
|
||||
} else
|
||||
opts = "";
|
||||
/* Start asking for password */
|
||||
prompt = "agent-pass";
|
||||
for (retries = 0; retries < 3; retries++) {
|
||||
res = ast_app_getdata(chan, prompt, passwd, sizeof(passwd) - 2, 0);
|
||||
if (res < 0)
|
||||
break;
|
||||
res = 0;
|
||||
if (password[0] == '/') {
|
||||
/* Compare against a file */
|
||||
char tmp[80];
|
||||
FILE *f;
|
||||
f = fopen(password, "r");
|
||||
if (f) {
|
||||
char buf[256] = "";
|
||||
while(!feof(f)) {
|
||||
fgets(buf, sizeof(buf), f);
|
||||
if (!feof(f) && strlen(buf)) {
|
||||
buf[strlen(buf) - 1] = '\0';
|
||||
if (strlen(buf) && !strcmp(passwd, buf))
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
if (strlen(buf) && !strcmp(passwd, buf))
|
||||
break;
|
||||
} else
|
||||
ast_log(LOG_WARNING, "Unable to open file '%s' for authentication: %s\n", password, strerror(errno));
|
||||
} else {
|
||||
/* Compare against a fixed password */
|
||||
if (!strcmp(passwd, password))
|
||||
break;
|
||||
}
|
||||
prompt="auth-incorrect";
|
||||
}
|
||||
if ((retries < 3) && !res) {
|
||||
if (strchr(opts, 'a'))
|
||||
ast_cdr_setaccount(chan, passwd);
|
||||
} else {
|
||||
if (!res)
|
||||
res = ast_streamfile(chan, "vm-goodbye", chan->language);
|
||||
if (!res)
|
||||
res = ast_waitstream(chan, "");
|
||||
res = -1;
|
||||
}
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, auth_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
|
@ -131,6 +131,7 @@ struct mgcp_endpoint {
|
|||
int outgoing;
|
||||
struct ast_channel *owner;
|
||||
struct ast_rtp *rtp;
|
||||
struct sockaddr_in tmpdest;
|
||||
struct mgcp_endpoint *next;
|
||||
struct mgcp_gateway *parent;
|
||||
};
|
||||
|
@ -317,6 +318,7 @@ static int mgcp_hangup(struct ast_channel *ast)
|
|||
p->owner = NULL;
|
||||
if (strlen(p->cxident))
|
||||
transmit_connection_del(p);
|
||||
strcpy(p->cxident, "");
|
||||
if (!p->alreadygone && (!p->outgoing || (ast->_state == AST_STATE_UP)))
|
||||
transmit_notify_request(p, "ro", 1);
|
||||
else
|
||||
|
@ -324,8 +326,9 @@ static int mgcp_hangup(struct ast_channel *ast)
|
|||
ast->pvt->pvt = NULL;
|
||||
p->alreadygone = 0;
|
||||
p->outgoing = 0;
|
||||
strcpy(p->cxident, "");
|
||||
strcpy(p->callid, "");
|
||||
/* Reset temporary destination */
|
||||
memset(&p->tmpdest, 0, sizeof(p->tmpdest));
|
||||
if (p->rtp) {
|
||||
ast_rtp_destroy(p->rtp);
|
||||
p->rtp = NULL;
|
||||
|
@ -515,6 +518,7 @@ static struct ast_channel *mgcp_new(struct mgcp_endpoint *i, int state)
|
|||
tmp->pvt->indicate = mgcp_indicate;
|
||||
tmp->pvt->fixup = mgcp_fixup;
|
||||
tmp->pvt->send_digit = mgcp_senddigit;
|
||||
tmp->pvt->bridge = ast_rtp_bridge;
|
||||
if (strlen(i->language))
|
||||
strncpy(tmp->language, i->language, sizeof(tmp->language)-1);
|
||||
i->owner = tmp;
|
||||
|
@ -951,8 +955,15 @@ static int add_sdp(struct mgcp_request *resp, struct mgcp_endpoint *p, struct as
|
|||
if (rtp) {
|
||||
ast_rtp_get_peer(rtp, &dest);
|
||||
} else {
|
||||
dest.sin_addr = p->parent->ourip;
|
||||
dest.sin_port = sin.sin_port;
|
||||
if (p->tmpdest.sin_addr.s_addr) {
|
||||
dest.sin_addr = p->tmpdest.sin_addr;
|
||||
dest.sin_port = p->tmpdest.sin_port;
|
||||
/* Reset temporary destination */
|
||||
memset(&p->tmpdest, 0, sizeof(p->tmpdest));
|
||||
} else {
|
||||
dest.sin_addr = p->parent->ourip;
|
||||
dest.sin_port = sin.sin_port;
|
||||
}
|
||||
}
|
||||
printf("We're at %s port %d\n", inet_ntoa(p->parent->ourip), ntohs(sin.sin_port));
|
||||
snprintf(v, sizeof(v), "v=0\r\n");
|
||||
|
@ -991,6 +1002,12 @@ static int transmit_modify_with_sdp(struct mgcp_endpoint *p, struct ast_rtp *rtp
|
|||
char local[256];
|
||||
char tmp[80];
|
||||
int x;
|
||||
if (!strlen(p->cxident) && rtp) {
|
||||
/* We don't have a CXident yet, store the destination and
|
||||
wait a bit */
|
||||
ast_rtp_get_peer(rtp, &p->tmpdest);
|
||||
return 0;
|
||||
}
|
||||
snprintf(local, sizeof(local), "p:20");
|
||||
for (x=1;x<= AST_FORMAT_MAX_AUDIO; x <<= 1) {
|
||||
if (p->capability & x) {
|
||||
|
@ -1003,6 +1020,7 @@ static int transmit_modify_with_sdp(struct mgcp_endpoint *p, struct ast_rtp *rtp
|
|||
add_header(&resp, "L", local);
|
||||
add_header(&resp, "M", "sendrecv");
|
||||
add_header(&resp, "X", p->txident);
|
||||
add_header(&resp, "I", p->cxident);
|
||||
add_header(&resp, "S", "");
|
||||
add_sdp(&resp, p, rtp);
|
||||
p->lastout = oseq;
|
||||
|
@ -1278,8 +1296,14 @@ static int mgcpsock_read(int *id, int fd, short events, void *ignore)
|
|||
p = find_endpoint(NULL, ident, &sin);
|
||||
if (p) {
|
||||
handle_response(p, result, ident);
|
||||
if ((c = get_header(&req, "I")))
|
||||
strncpy(p->cxident, c, sizeof(p->cxident) - 1);
|
||||
if ((c = get_header(&req, "I"))) {
|
||||
if (strlen(c)) {
|
||||
strncpy(p->cxident, c, sizeof(p->cxident) - 1);
|
||||
if (p->tmpdest.sin_addr.s_addr) {
|
||||
transmit_modify_with_sdp(p, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (req.lines)
|
||||
process_sdp(p, &req);
|
||||
}
|
||||
|
@ -1483,6 +1507,31 @@ struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v)
|
|||
return gw;
|
||||
}
|
||||
|
||||
static struct ast_rtp *mgcp_get_rtp_peer(struct ast_channel *chan)
|
||||
{
|
||||
struct mgcp_endpoint *p;
|
||||
p = chan->pvt->pvt;
|
||||
if (p && p->rtp)
|
||||
return p->rtp;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int mgcp_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp)
|
||||
{
|
||||
struct mgcp_endpoint *p;
|
||||
p = chan->pvt->pvt;
|
||||
if (p) {
|
||||
transmit_modify_with_sdp(p, rtp);
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static struct ast_rtp_protocol mgcp_rtp = {
|
||||
get_rtp_info: mgcp_get_rtp_peer,
|
||||
set_rtp_peer: mgcp_set_rtp_peer,
|
||||
};
|
||||
|
||||
int load_module()
|
||||
{
|
||||
struct ast_config *cfg;
|
||||
|
@ -1590,6 +1639,8 @@ int load_module()
|
|||
ast_destroy(cfg);
|
||||
return -1;
|
||||
}
|
||||
mgcp_rtp.type = type;
|
||||
ast_rtp_proto_register(&mgcp_rtp);
|
||||
ast_cli_register(&cli_show_endpoints);
|
||||
/* And start the monitor for the first time */
|
||||
restart_monitor();
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include <asterisk/cli.h>
|
||||
#include <asterisk/md5.h>
|
||||
#include <asterisk/app.h>
|
||||
#include <asterisk/musiconhold.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
|
@ -47,8 +48,12 @@
|
|||
/* #define VOCAL_DATA_HACK */
|
||||
|
||||
#define SIPDUMPER
|
||||
#define DEFAULT_EXPIREY 120
|
||||
#define MAX_EXPIREY 3600
|
||||
#define DEFAULT_DEFAULT_EXPIREY 120
|
||||
#define DEFAULT_MAX_EXPIREY 3600
|
||||
|
||||
static int max_expirey = DEFAULT_MAX_EXPIREY;
|
||||
static int default_expirey = DEFAULT_DEFAULT_EXPIREY;
|
||||
|
||||
#define DEFAULT_MAXMS 2000 /* Must be faster than 2 seconds by default */
|
||||
|
||||
#define DEFAULT_MAXMS 2000 /* Must be faster than 2 seconds by default */
|
||||
|
@ -142,6 +147,7 @@ static struct sip_pvt {
|
|||
char refer_to[AST_MAX_EXTENSION]; /* Place to store REFER-TO extension */
|
||||
char referred_by[AST_MAX_EXTENSION];/* Place to store REFERRED-BY extension */
|
||||
char refer_contact[AST_MAX_EXTENSION];/* Place to store Contact info from a REFER extension */
|
||||
struct sip_pvt *refer_call; /* Call we are referring */
|
||||
char record_route[256];
|
||||
char record_route_info[256];
|
||||
char remote_party_id[256];
|
||||
|
@ -728,6 +734,7 @@ static int sip_indicate(struct ast_channel *ast, int condition)
|
|||
}
|
||||
|
||||
|
||||
#if 0
|
||||
static int sip_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc)
|
||||
{
|
||||
struct sip_pvt *p0, *p1;
|
||||
|
@ -742,6 +749,7 @@ static int sip_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags,
|
|||
ast_pthread_mutex_lock(&c1->lock);
|
||||
p0 = c0->pvt->pvt;
|
||||
p1 = c1->pvt->pvt;
|
||||
ast_log(LOG_DEBUG, "Reinvite? %s: %s, %s: %s\n", c0->name, p0->canreinvite ? "yes" : "no", c1->name, p1->canreinvite ? "yes" : "no");
|
||||
if (!p0->canreinvite || !p1->canreinvite) {
|
||||
/* Not gonna support reinvite */
|
||||
ast_pthread_mutex_unlock(&c0->lock);
|
||||
|
@ -796,6 +804,7 @@ static int sip_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags,
|
|||
}
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct ast_channel *sip_new(struct sip_pvt *i, int state, char *title)
|
||||
{
|
||||
|
@ -808,7 +817,7 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, char *title)
|
|||
tmp->nativeformats = capability;
|
||||
fmt = ast_best_codec(tmp->nativeformats);
|
||||
if (title)
|
||||
snprintf(tmp->name, sizeof(tmp->name), "SIP/%s", title);
|
||||
snprintf(tmp->name, sizeof(tmp->name), "SIP/%s-%04x", title, rand() & 0xffff);
|
||||
else
|
||||
snprintf(tmp->name, sizeof(tmp->name), "SIP/%s:%d", inet_ntoa(i->sa.sin_addr), ntohs(i->sa.sin_port));
|
||||
tmp->type = type;
|
||||
|
@ -830,7 +839,7 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, char *title)
|
|||
tmp->pvt->indicate = sip_indicate;
|
||||
tmp->pvt->fixup = sip_fixup;
|
||||
tmp->pvt->send_digit = sip_senddigit;
|
||||
tmp->pvt->bridge = sip_bridge;
|
||||
tmp->pvt->bridge = ast_rtp_bridge;
|
||||
if (strlen(i->language))
|
||||
strncpy(tmp->language, i->language, sizeof(tmp->language)-1);
|
||||
i->owner = tmp;
|
||||
|
@ -1087,7 +1096,7 @@ static int sip_register(char *value, int lineno)
|
|||
if (secret)
|
||||
strncpy(reg->secret, secret, sizeof(reg->secret)-1);
|
||||
reg->expire = -1;
|
||||
reg->refresh = DEFAULT_EXPIREY;
|
||||
reg->refresh = default_expirey;
|
||||
reg->addr.sin_family = AF_INET;
|
||||
memcpy(®->addr.sin_addr, hp->h_addr, sizeof(®->addr.sin_addr));
|
||||
reg->addr.sin_port = porta ? htons(atoi(porta)) : htons(DEFAULT_SIP_PORT);
|
||||
|
@ -1237,11 +1246,21 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
|
|||
ast_log(LOG_WARNING, "No compatible codecs!\n");
|
||||
return -1;
|
||||
}
|
||||
if (p->owner && !(p->owner->nativeformats & p->capability)) {
|
||||
ast_log(LOG_DEBUG, "Oooh, we need to change our formats since our peer supports only %d and not %d\n", p->capability, p->owner->nativeformats);
|
||||
p->owner->nativeformats = p->capability;
|
||||
ast_set_read_format(p->owner, p->owner->readformat);
|
||||
ast_set_write_format(p->owner, p->owner->writeformat);
|
||||
if (p->owner) {
|
||||
if (p->owner->nativeformats & p->capability) {
|
||||
ast_log(LOG_DEBUG, "Oooh, we need to change our formats since our peer supports only %d and not %d\n", p->capability, p->owner->nativeformats);
|
||||
p->owner->nativeformats = p->capability;
|
||||
ast_set_read_format(p->owner, p->owner->readformat);
|
||||
ast_set_write_format(p->owner, p->owner->writeformat);
|
||||
}
|
||||
if (p->owner->bridge) {
|
||||
/* Turn on/off music on hold if we are holding/unholding */
|
||||
if (sin.sin_addr.s_addr) {
|
||||
ast_moh_stop(p->owner->bridge);
|
||||
} else {
|
||||
ast_moh_start(p->owner->bridge, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
|
@ -1830,7 +1849,7 @@ static int transmit_register(struct sip_registry *r, char *cmd, char *auth)
|
|||
if (auth)
|
||||
add_header(&req, "Authorization", auth);
|
||||
|
||||
snprintf(tmp, sizeof(tmp), "%d", DEFAULT_EXPIREY);
|
||||
snprintf(tmp, sizeof(tmp), "%d", default_expirey);
|
||||
add_header(&req, "Expires", tmp);
|
||||
add_header(&req, "Event", "registration");
|
||||
copy_request(&p->initreq, &req);
|
||||
|
@ -1933,8 +1952,8 @@ static int parse_contact(struct sip_pvt *pvt, struct sip_peer *p, struct sip_req
|
|||
strcpy(p->username, "");
|
||||
if (p->expire > -1)
|
||||
ast_sched_del(sched, p->expire);
|
||||
if ((expirey < 1) || (expirey > MAX_EXPIREY))
|
||||
expirey = DEFAULT_EXPIREY;
|
||||
if ((expirey < 1) || (expirey > max_expirey))
|
||||
expirey = max_expirey;
|
||||
p->expire = ast_sched_add(sched, expirey * 1000, expire_register, p);
|
||||
pvt->expirey = expirey;
|
||||
if (memcmp(&p->addr, &oldsin, sizeof(oldsin))) {
|
||||
|
@ -2130,7 +2149,9 @@ static int get_refer_info(struct sip_pvt *p, struct sip_request *oreq)
|
|||
char tmp2[256] = "", *c2, *a2;
|
||||
char tmp3[256];
|
||||
char tmp4[256];
|
||||
char tmp5[256] = ""; /* CallID to replace */
|
||||
struct sip_request *req;
|
||||
struct sip_pvt *p2;
|
||||
|
||||
req = oreq;
|
||||
if (!req)
|
||||
|
@ -2151,32 +2172,81 @@ static int get_refer_info(struct sip_pvt *p, struct sip_request *oreq)
|
|||
}
|
||||
c += 4;
|
||||
c2 += 4;
|
||||
if ((a = strchr(c, '@')) || (a = strchr(c, ';'))) {
|
||||
if ((a = strchr(c, '?'))) {
|
||||
/* Search for arguemnts */
|
||||
*a = '\0';
|
||||
a++;
|
||||
if (!strncasecmp(a, "REPLACES=", strlen("REPLACES="))) {
|
||||
strncpy(tmp5, a + strlen("REPLACES="), sizeof(tmp5) - 1);
|
||||
if ((a = strchr(tmp5, '%'))) {
|
||||
/* Yuck! Pingtel converts the '@' to a %40, icky icky! Convert
|
||||
back to an '@' */
|
||||
if ((a[1] == '4') && (a[2] == '0')) {
|
||||
*a = '@';
|
||||
memmove(a + 1, a+3, strlen(a + 3));
|
||||
}
|
||||
}
|
||||
if ((a = strchr(tmp5, '%')))
|
||||
*a = '\0';
|
||||
}
|
||||
}
|
||||
if ((a2 = strchr(c2, '@')) || (a2 = strchr(c2, ';'))) {
|
||||
|
||||
if ((a = strchr(c, '@')))
|
||||
*a = '\0';
|
||||
if ((a = strchr(c, ';')))
|
||||
*a = '\0';
|
||||
|
||||
|
||||
if ((a2 = strchr(c2, '@')))
|
||||
*a2 = '\0';
|
||||
}
|
||||
|
||||
if ((a2 = strchr(c2, ';')))
|
||||
*a2 = '\0';
|
||||
|
||||
|
||||
if (sipdebug)
|
||||
ast_verbose("Looking for %s in %s\n", c, p->context);
|
||||
ast_verbose("Looking for %s in %s\n", c2, p->context);
|
||||
|
||||
if (ast_exists_extension(NULL, p->context, c, 1, NULL) && ast_exists_extension(NULL, p->context, c2, 1, NULL)) {
|
||||
if (!oreq)
|
||||
ast_log(LOG_DEBUG,"Something is wrong with this line.\n"); //This line is ignored for some reason....
|
||||
ast_log(LOG_DEBUG,"Assigning Extension %s to REFER-TO\n", c);
|
||||
ast_log(LOG_DEBUG,"Assigning Extension %s to REFERRED-BY\n", c2);
|
||||
ast_log(LOG_DEBUG,"Assigning Contact Info %s to REFER_CONTACT\n", tmp3);
|
||||
ast_log(LOG_DEBUG,"Assigning Remote-Party-ID Info %s to REMOTE_PARTY_ID\n",tmp4);
|
||||
strncpy(p->refer_to, c, sizeof(p->refer_to) - 1);
|
||||
strncpy(p->referred_by, c2, sizeof(p->referred_by) - 1);
|
||||
strncpy(p->refer_contact, tmp3, sizeof(p->refer_contact) - 1);
|
||||
strncpy(p->remote_party_id, tmp4, sizeof(p->remote_party_id) - 1);
|
||||
|
||||
if (strlen(tmp5)) {
|
||||
/* This is a supervised transfer */
|
||||
ast_log(LOG_DEBUG,"Assigning Replace-Call-ID Info %s to REPLACE_CALL_ID\n",tmp5);
|
||||
|
||||
strncpy(p->refer_to, "", sizeof(p->refer_to) - 1);
|
||||
strncpy(p->referred_by, "", sizeof(p->referred_by) - 1);
|
||||
strncpy(p->refer_contact, "", sizeof(p->refer_contact) - 1);
|
||||
strncpy(p->remote_party_id, "", sizeof(p->remote_party_id) - 1);
|
||||
p->refer_call = NULL;
|
||||
ast_pthread_mutex_lock(&iflock);
|
||||
/* Search interfaces and find the match */
|
||||
p2 = iflist;
|
||||
while(p2) {
|
||||
if (!strcmp(p2->callid, tmp5)) {
|
||||
/* Go ahead and lock it before returning */
|
||||
ast_pthread_mutex_lock(&p2->lock);
|
||||
p->refer_call = p2;
|
||||
break;
|
||||
}
|
||||
p2 = p2->next;
|
||||
}
|
||||
ast_pthread_mutex_unlock(&iflock);
|
||||
if (p->refer_call)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ast_canmatch_extension(NULL, p->context, c, 1, NULL)) {
|
||||
else
|
||||
ast_log(LOG_NOTICE, "Supervised transfer requested, but unable to find callid '%s'\n", tmp5);
|
||||
} else if (ast_exists_extension(NULL, p->context, c, 1, NULL) && ast_exists_extension(NULL, p->context, c2, 1, NULL)) {
|
||||
/* This is an unsupervised transfer */
|
||||
ast_log(LOG_DEBUG,"Assigning Extension %s to REFER-TO\n", c);
|
||||
ast_log(LOG_DEBUG,"Assigning Extension %s to REFERRED-BY\n", c2);
|
||||
ast_log(LOG_DEBUG,"Assigning Contact Info %s to REFER_CONTACT\n", tmp3);
|
||||
ast_log(LOG_DEBUG,"Assigning Remote-Party-ID Info %s to REMOTE_PARTY_ID\n",tmp4);
|
||||
strncpy(p->refer_to, c, sizeof(p->refer_to) - 1);
|
||||
strncpy(p->referred_by, c2, sizeof(p->referred_by) - 1);
|
||||
strncpy(p->refer_contact, tmp3, sizeof(p->refer_contact) - 1);
|
||||
strncpy(p->remote_party_id, tmp4, sizeof(p->remote_party_id) - 1);
|
||||
p->refer_call = NULL;
|
||||
return 0;
|
||||
} else if (ast_canmatch_extension(NULL, p->context, c, 1, NULL)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -2735,7 +2805,7 @@ retrylock:
|
|||
if (r->expire != -1)
|
||||
ast_sched_del(sched, r->expire);
|
||||
expires=atoi(get_header(req, "expires"));
|
||||
if (!expires) expires=DEFAULT_EXPIREY;
|
||||
if (!expires) expires=default_expirey;
|
||||
r->expire=ast_sched_add(sched, (expires-2)*1000, sip_reregister, r);
|
||||
|
||||
}
|
||||
|
@ -2879,6 +2949,37 @@ static int determine_firstline_parts( struct sip_request *req ) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int attempt_transfer(struct sip_pvt *p1, struct sip_pvt *p2)
|
||||
{
|
||||
if (!p1->owner || !p2->owner) {
|
||||
ast_log(LOG_WARNING, "Transfer attempted without dual ownership?\n");
|
||||
return -1;
|
||||
}
|
||||
if (p1->owner->bridge) {
|
||||
if (p2->owner->bridge)
|
||||
ast_moh_stop(p2->owner->bridge);
|
||||
ast_moh_stop(p1->owner->bridge);
|
||||
ast_moh_stop(p1->owner);
|
||||
ast_moh_stop(p2->owner);
|
||||
if (ast_channel_masquerade(p2->owner, p1->owner->bridge)) {
|
||||
ast_log(LOG_WARNING, "Failed to masquerade %s into %s\n", p2->owner->name, p1->owner->bridge->name);
|
||||
return -1;
|
||||
}
|
||||
} else if (p2->owner->bridge) {
|
||||
ast_moh_stop(p2->owner->bridge);
|
||||
ast_moh_stop(p2->owner);
|
||||
ast_moh_stop(p1->owner);
|
||||
if (ast_channel_masquerade(p1->owner, p2->owner->bridge)) {
|
||||
ast_log(LOG_WARNING, "Failed to masquerade %s into %s\n", p1->owner->name, p2->owner->bridge->name);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
ast_log(LOG_NOTICE, "Transfer attempted with no bridged calls to transfer\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handle_request(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin)
|
||||
{
|
||||
struct sip_request resp;
|
||||
|
@ -3048,16 +3149,23 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
|
|||
transmit_response_with_allow(p, "404 Not Found", req);
|
||||
else if (res > 0)
|
||||
transmit_response_with_allow(p, "484 Address Incomplete", req);
|
||||
else
|
||||
else {
|
||||
transmit_response(p, "202 Accepted", req);
|
||||
ast_log(LOG_DEBUG,"202 Accepted\n");
|
||||
c = p->owner;
|
||||
if (c) {
|
||||
transfer_to = c->bridge;
|
||||
if (transfer_to)
|
||||
ast_async_goto(transfer_to,"", p->refer_to,1, 1);
|
||||
if (p->refer_call) {
|
||||
ast_log(LOG_DEBUG,"202 Accepted (supervised)\n");
|
||||
attempt_transfer(p, p->refer_call);
|
||||
ast_pthread_mutex_unlock(&p->refer_call->lock);
|
||||
p->refer_call = NULL;
|
||||
} else {
|
||||
ast_log(LOG_DEBUG,"202 Accepted (blind)\n");
|
||||
c = p->owner;
|
||||
if (c) {
|
||||
transfer_to = c->bridge;
|
||||
if (transfer_to)
|
||||
ast_async_goto(transfer_to,"", p->refer_to,1, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if (!strcasecmp(cmd, "CANCEL") || !strcasecmp(cmd, "BYE")) {
|
||||
copy_request(&p->initreq, req);
|
||||
p->alreadygone = 1;
|
||||
|
@ -3140,7 +3248,7 @@ static int sipsock_read(int *id, int fd, short events, void *ignore)
|
|||
/* Must have at least two headers */
|
||||
return 1;
|
||||
}
|
||||
/* Process request, with iflock held */
|
||||
/* Process request, with netlock held */
|
||||
ast_pthread_mutex_lock(&netlock);
|
||||
p = find_call(&req, &sin);
|
||||
if (p) {
|
||||
|
@ -3495,6 +3603,8 @@ static struct sip_peer *build_peer(char *name, struct ast_variable *v)
|
|||
peer->expirey = expirey;
|
||||
}
|
||||
peer->capability = capability;
|
||||
/* Assume can reinvite */
|
||||
peer->canreinvite = 1;
|
||||
while(v) {
|
||||
if (!strcasecmp(v->name, "secret"))
|
||||
strncpy(peer->secret, v->value, sizeof(peer->secret)-1);
|
||||
|
@ -3619,6 +3729,14 @@ static int reload_config()
|
|||
strncpy(context, v->value, sizeof(context)-1);
|
||||
} else if (!strcasecmp(v->name, "language")) {
|
||||
strncpy(language, v->value, sizeof(language)-1);
|
||||
} else if (!strcasecmp(v->name, "maxexpirey")) {
|
||||
max_expirey = atoi(v->value);
|
||||
if (max_expirey < 1)
|
||||
max_expirey = DEFAULT_MAX_EXPIREY;
|
||||
} else if (!strcasecmp(v->name, "defaultexpirey")) {
|
||||
default_expirey = atoi(v->value);
|
||||
if (default_expirey < 1)
|
||||
default_expirey = DEFAULT_DEFAULT_EXPIREY;
|
||||
} else if (!strcasecmp(v->name, "bindaddr")) {
|
||||
if (!(hp = gethostbyname(v->value))) {
|
||||
ast_log(LOG_WARNING, "Invalid address: %s\n", v->value);
|
||||
|
@ -3743,6 +3861,31 @@ static int reload_config()
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct ast_rtp *sip_get_rtp_peer(struct ast_channel *chan)
|
||||
{
|
||||
struct sip_pvt *p;
|
||||
p = chan->pvt->pvt;
|
||||
if (p && p->rtp && p->canreinvite)
|
||||
return p->rtp;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp)
|
||||
{
|
||||
struct sip_pvt *p;
|
||||
p = chan->pvt->pvt;
|
||||
if (p) {
|
||||
transmit_reinvite_with_sdp(p, rtp);
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static struct ast_rtp_protocol sip_rtp = {
|
||||
get_rtp_info: sip_get_rtp_peer,
|
||||
set_rtp_peer: sip_set_rtp_peer,
|
||||
};
|
||||
|
||||
int load_module()
|
||||
{
|
||||
int res;
|
||||
|
@ -3761,6 +3904,8 @@ int load_module()
|
|||
ast_cli_register(&cli_show_registry);
|
||||
ast_cli_register(&cli_debug);
|
||||
ast_cli_register(&cli_no_debug);
|
||||
sip_rtp.type = type;
|
||||
ast_rtp_proto_register(&sip_rtp);
|
||||
sched = sched_context_create();
|
||||
if (!sched) {
|
||||
ast_log(LOG_WARNING, "Unable to create schedule context\n");
|
||||
|
|
|
@ -7,6 +7,8 @@ bindaddr = 0.0.0.0 ; Address to bind to
|
|||
context = default ; Default for incoming calls
|
||||
;tos=lowdelay
|
||||
;tos=184
|
||||
;maxexpirey=3600 ; Max length of incoming registration we allow
|
||||
;defaultexpirey=120 ; Default length of incoming/outoing registration
|
||||
|
||||
;[snomsip]
|
||||
;type=friend
|
||||
|
|
33
frame.c
33
frame.c
|
@ -35,10 +35,12 @@ struct ast_smoother {
|
|||
int size;
|
||||
int format;
|
||||
int readdata;
|
||||
int optimizablestream;
|
||||
float samplesperbyte;
|
||||
struct ast_frame f;
|
||||
char data[SMOOTHER_SIZE];
|
||||
char framedata[SMOOTHER_SIZE + AST_FRIENDLY_OFFSET];
|
||||
struct ast_frame *opt;
|
||||
int len;
|
||||
};
|
||||
|
||||
|
@ -76,6 +78,28 @@ int ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f)
|
|||
ast_log(LOG_WARNING, "Out of smoother space\n");
|
||||
return -1;
|
||||
}
|
||||
if ((f->datalen == s->size) && !s->opt) {
|
||||
if (!s->len) {
|
||||
/* Optimize by sending the frame we just got
|
||||
on the next read, thus eliminating the douple
|
||||
copy */
|
||||
s->opt = f;
|
||||
return 0;
|
||||
} else {
|
||||
s->optimizablestream++;
|
||||
if (s->optimizablestream > 10) {
|
||||
/* For the past 10 rounds, we have input and output
|
||||
frames of the correct size for this smoother, yet
|
||||
we were unable to optimize because there was still
|
||||
some cruft left over. Lets just drop the cruft so
|
||||
we can move to a fully optimized path */
|
||||
s->len = 0;
|
||||
s->opt = f;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} else
|
||||
s->optimizablestream = 0;
|
||||
memcpy(s->data + s->len, f->data, f->datalen);
|
||||
s->len += f->datalen;
|
||||
return 0;
|
||||
|
@ -83,6 +107,15 @@ int ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f)
|
|||
|
||||
struct ast_frame *ast_smoother_read(struct ast_smoother *s)
|
||||
{
|
||||
struct ast_frame *opt;
|
||||
|
||||
/* IF we have an optimization frame, send it */
|
||||
if (s->opt) {
|
||||
opt = s->opt;
|
||||
s->opt = NULL;
|
||||
return opt;
|
||||
}
|
||||
|
||||
/* Make sure we have enough data */
|
||||
if (s->len < s->size) {
|
||||
return NULL;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <asterisk/frame.h>
|
||||
#include <asterisk/io.h>
|
||||
#include <asterisk/sched.h>
|
||||
#include <asterisk/channel.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
|
@ -24,6 +25,14 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct ast_rtp_protocol {
|
||||
struct ast_rtp *(*get_rtp_info)(struct ast_channel *chan); /* Get RTP struct, or NULL if unwilling to transfer */
|
||||
int (*set_rtp_peer)(struct ast_channel *chan, struct ast_rtp *peer); /* Set RTP peer */
|
||||
int (*get_rtp_willing)(struct ast_channel *chan); /* Willing to native bridge */
|
||||
char *type;
|
||||
struct ast_rtp_protocol *next;
|
||||
};
|
||||
|
||||
struct ast_rtp;
|
||||
|
||||
typedef int (*ast_rtp_callback)(struct ast_rtp *rtp, struct ast_frame *f, void *data);
|
||||
|
@ -58,6 +67,12 @@ int rtp2ast(int id);
|
|||
|
||||
char *ast2rtpn(int id);
|
||||
|
||||
int ast_rtp_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc);
|
||||
|
||||
int ast_rtp_proto_register(struct ast_rtp_protocol *proto);
|
||||
|
||||
void ast_rtp_proto_unregister(struct ast_rtp_protocol *proto);
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
}
|
||||
#endif
|
||||
|
|
204
rtp.c
204
rtp.c
|
@ -30,6 +30,7 @@
|
|||
#include <asterisk/logger.h>
|
||||
#include <asterisk/options.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/channel_pvt.h>
|
||||
|
||||
#define TYPE_SILENCE 0x2
|
||||
#define TYPE_HIGH 0x0
|
||||
|
@ -47,6 +48,7 @@ struct ast_rtp {
|
|||
unsigned int lastts;
|
||||
unsigned int lastrxts;
|
||||
int lasttxformat;
|
||||
int lastrxformat;
|
||||
int dtmfcount;
|
||||
struct sockaddr_in us;
|
||||
struct sockaddr_in them;
|
||||
|
@ -61,6 +63,8 @@ struct ast_rtp {
|
|||
ast_rtp_callback callback;
|
||||
};
|
||||
|
||||
static struct ast_rtp_protocol *protos = NULL;
|
||||
|
||||
int ast_rtp_fd(struct ast_rtp *rtp)
|
||||
{
|
||||
return rtp->s;
|
||||
|
@ -151,6 +155,49 @@ static struct ast_frame *process_rfc2833(struct ast_rtp *rtp, unsigned char *dat
|
|||
return f;
|
||||
}
|
||||
|
||||
static struct ast_frame *process_rfc3389(struct ast_rtp *rtp, unsigned char *data, int len)
|
||||
{
|
||||
struct ast_frame *f = NULL;
|
||||
/* Convert comfort noise into audio with various codecs. Unfortunately this doesn't
|
||||
totally help us out becuase we don't have an engine to keep it going and we are not
|
||||
guaranteed to have it every 20ms or anything */
|
||||
#if 0
|
||||
printf("RFC3389: %d bytes, format is %d\n", len, rtp->lastrxformat);
|
||||
#endif
|
||||
ast_log(LOG_NOTICE, "RFC3389 support incomplete. Turn off on client if possible\n");
|
||||
if (!rtp->lastrxformat)
|
||||
return NULL;
|
||||
switch(rtp->lastrxformat) {
|
||||
case AST_FORMAT_ULAW:
|
||||
rtp->f.frametype = AST_FRAME_VOICE;
|
||||
rtp->f.subclass = AST_FORMAT_ULAW;
|
||||
rtp->f.datalen = 160;
|
||||
rtp->f.samples = 160;
|
||||
memset(rtp->f.data, 0x7f, rtp->f.datalen);
|
||||
f = &rtp->f;
|
||||
break;
|
||||
case AST_FORMAT_ALAW:
|
||||
rtp->f.frametype = AST_FRAME_VOICE;
|
||||
rtp->f.subclass = AST_FORMAT_ALAW;
|
||||
rtp->f.datalen = 160;
|
||||
rtp->f.samples = 160;
|
||||
memset(rtp->f.data, 0x7e, rtp->f.datalen); /* XXX Is this right? XXX */
|
||||
f = &rtp->f;
|
||||
break;
|
||||
case AST_FORMAT_SLINEAR:
|
||||
rtp->f.frametype = AST_FRAME_VOICE;
|
||||
rtp->f.subclass = AST_FORMAT_SLINEAR;
|
||||
rtp->f.datalen = 320;
|
||||
rtp->f.samples = 160;
|
||||
memset(rtp->f.data, 0x00, rtp->f.datalen);
|
||||
f = &rtp->f;
|
||||
break;
|
||||
default:
|
||||
ast_log(LOG_NOTICE, "Don't know how to handle RFC3389 for receive codec %d\n", rtp->lastrxformat);
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
static struct ast_frame *process_type121(struct ast_rtp *rtp, unsigned char *data, int len)
|
||||
{
|
||||
char resp = 0;
|
||||
|
@ -247,6 +294,8 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
|
|||
} else if (payloadtype == 100) {
|
||||
/* CISCO's notso proprietary DTMF bridge */
|
||||
f = process_rfc2833(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen);
|
||||
} else if (payloadtype == 13) {
|
||||
f = process_rfc3389(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen);
|
||||
} else {
|
||||
ast_log(LOG_NOTICE, "Unknown RTP codec %d received\n", payloadtype);
|
||||
}
|
||||
|
@ -254,7 +303,8 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
|
|||
return f;
|
||||
else
|
||||
return &null_frame;
|
||||
}
|
||||
} else
|
||||
rtp->lastrxformat = rtp->f.subclass;
|
||||
|
||||
if (!rtp->lastrxts)
|
||||
rtp->lastrxts = timestamp;
|
||||
|
@ -651,3 +701,155 @@ int ast_rtp_write(struct ast_rtp *rtp, struct ast_frame *_f)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ast_rtp_proto_unregister(struct ast_rtp_protocol *proto)
|
||||
{
|
||||
struct ast_rtp_protocol *cur, *prev;
|
||||
cur = protos;
|
||||
prev = NULL;
|
||||
while(cur) {
|
||||
if (cur == proto) {
|
||||
if (prev)
|
||||
prev->next = proto->next;
|
||||
else
|
||||
protos = proto->next;
|
||||
return;
|
||||
}
|
||||
prev = cur;
|
||||
cur = cur->next;
|
||||
}
|
||||
}
|
||||
|
||||
int ast_rtp_proto_register(struct ast_rtp_protocol *proto)
|
||||
{
|
||||
struct ast_rtp_protocol *cur;
|
||||
cur = protos;
|
||||
while(cur) {
|
||||
if (cur->type == proto->type) {
|
||||
ast_log(LOG_WARNING, "Tried to register same protocol '%s' twice\n", cur->type);
|
||||
return -1;
|
||||
}
|
||||
cur = cur->next;
|
||||
}
|
||||
proto->next = protos;
|
||||
protos = proto;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ast_rtp_protocol *get_proto(struct ast_channel *chan)
|
||||
{
|
||||
struct ast_rtp_protocol *cur;
|
||||
cur = protos;
|
||||
while(cur) {
|
||||
if (cur->type == chan->type) {
|
||||
return cur;
|
||||
}
|
||||
cur = cur->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ast_rtp_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc)
|
||||
{
|
||||
struct ast_frame *f;
|
||||
struct ast_channel *who, *cs[3];
|
||||
struct ast_rtp *p0, *p1;
|
||||
struct ast_rtp_protocol *pr0, *pr1;
|
||||
void *pvt0, *pvt1;
|
||||
int to;
|
||||
|
||||
/* XXX Wait a half a second for things to settle up
|
||||
this really should be fixed XXX */
|
||||
ast_autoservice_start(c0);
|
||||
ast_autoservice_start(c1);
|
||||
usleep(500000);
|
||||
ast_autoservice_stop(c0);
|
||||
ast_autoservice_stop(c1);
|
||||
|
||||
/* if need DTMF, cant native bridge */
|
||||
if (flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1))
|
||||
return -2;
|
||||
ast_pthread_mutex_lock(&c0->lock);
|
||||
ast_pthread_mutex_lock(&c1->lock);
|
||||
pr0 = get_proto(c0);
|
||||
pr1 = get_proto(c1);
|
||||
if (!pr0) {
|
||||
ast_log(LOG_WARNING, "Can't find native functions for channel '%s'\n", c0->name);
|
||||
ast_pthread_mutex_unlock(&c0->lock);
|
||||
ast_pthread_mutex_unlock(&c1->lock);
|
||||
return -1;
|
||||
}
|
||||
if (!pr1) {
|
||||
ast_log(LOG_WARNING, "Can't find native functions for channel '%s'\n", c1->name);
|
||||
ast_pthread_mutex_unlock(&c0->lock);
|
||||
ast_pthread_mutex_unlock(&c1->lock);
|
||||
return -1;
|
||||
}
|
||||
pvt0 = c0->pvt->pvt;
|
||||
pvt1 = c1->pvt->pvt;
|
||||
p0 = pr0->get_rtp_info(c0);
|
||||
p1 = pr1->get_rtp_info(c1);
|
||||
if (!p0 || !p1) {
|
||||
/* Somebody doesn't want to play... */
|
||||
ast_pthread_mutex_unlock(&c0->lock);
|
||||
ast_pthread_mutex_unlock(&c1->lock);
|
||||
return -2;
|
||||
}
|
||||
if (pr0->set_rtp_peer(c0, p1))
|
||||
ast_log(LOG_WARNING, "Channel '%s' failed to talk to '%s'\n", c0->name, c1->name);
|
||||
if (pr1->set_rtp_peer(c1, p0))
|
||||
ast_log(LOG_WARNING, "Channel '%s' failed to talk back to '%s'\n", c1->name, c0->name);
|
||||
ast_pthread_mutex_unlock(&c0->lock);
|
||||
ast_pthread_mutex_unlock(&c1->lock);
|
||||
cs[0] = c0;
|
||||
cs[1] = c1;
|
||||
cs[2] = NULL;
|
||||
for (;;) {
|
||||
if ((c0->pvt->pvt != pvt0) ||
|
||||
(c1->pvt->pvt != pvt1) ||
|
||||
(c0->masq || c0->masqr || c1->masq || c1->masqr)) {
|
||||
ast_log(LOG_DEBUG, "Oooh, something is weird, backing out\n");
|
||||
if (c0->pvt->pvt == pvt0) {
|
||||
if (pr0->set_rtp_peer(c0, NULL))
|
||||
ast_log(LOG_WARNING, "Channel '%s' failed to revert\n", c0->name);
|
||||
}
|
||||
if (c1->pvt->pvt == pvt1) {
|
||||
if (pr1->set_rtp_peer(c1, NULL))
|
||||
ast_log(LOG_WARNING, "Channel '%s' failed to revert back\n", c1->name);
|
||||
}
|
||||
/* Tell it to try again later */
|
||||
return -3;
|
||||
}
|
||||
to = -1;
|
||||
who = ast_waitfor_n(cs, 2, &to);
|
||||
if (!who) {
|
||||
ast_log(LOG_DEBUG, "Ooh, empty read...\n");
|
||||
continue;
|
||||
}
|
||||
f = ast_read(who);
|
||||
if (!f || ((f->frametype == AST_FRAME_DTMF) &&
|
||||
(((who == c0) && (flags & AST_BRIDGE_DTMF_CHANNEL_0)) ||
|
||||
((who == c1) && (flags & AST_BRIDGE_DTMF_CHANNEL_1))))) {
|
||||
*fo = f;
|
||||
*rc = who;
|
||||
ast_log(LOG_DEBUG, "Oooh, got a %s\n", f ? "digit" : "hangup");
|
||||
if ((c0->pvt->pvt == pvt0) && (!c0->_softhangup)) {
|
||||
if (pr0->set_rtp_peer(c0, NULL))
|
||||
ast_log(LOG_WARNING, "Channel '%s' failed to revert\n", c0->name);
|
||||
}
|
||||
if ((c1->pvt->pvt == pvt1) && (!c1->_softhangup)) {
|
||||
if (pr1->set_rtp_peer(c1, NULL))
|
||||
ast_log(LOG_WARNING, "Channel '%s' failed to revert back\n", c1->name);
|
||||
}
|
||||
/* That's all we needed */
|
||||
return 0;
|
||||
} else
|
||||
ast_frfree(f);
|
||||
/* Swap priority not that it's a big deal at this point */
|
||||
cs[2] = cs[0];
|
||||
cs[0] = cs[1];
|
||||
cs[1] = cs[2];
|
||||
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
|
||||
%agent-user.gsm%Agent login. Please enter your agent number followed by the pound key.
|
||||
|
||||
%auth-incorrect.gsm%Login incorrect. Please enter your password followed by the pound key.
|
||||
|
||||
%beep.gsm%(this is a simple beep tone)
|
||||
|
||||
%conf-getconfno.gsm%Please enter your conference number followed by the pound key.
|
||||
|
|
Binary file not shown.
Reference in New Issue