Add transfer to IAX2, and transfer application
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@1016 f38db490-d61c-443f-a65b-d21fe96a405b
This commit is contained in:
parent
1fbfb13dba
commit
67b5919a15
|
@ -20,7 +20,7 @@ APPS=app_dial.so app_playback.so app_voicemail.so app_directory.so app_intercom.
|
|||
app_setcidname.so app_lookupcidname.so app_substring.so app_macro.so \
|
||||
app_authenticate.so app_softhangup.so app_lookupblacklist.so \
|
||||
app_waitforring.so app_privacy.so app_db.so app_chanisavail.so \
|
||||
app_enumlookup.so app_voicemail2.so
|
||||
app_enumlookup.so app_voicemail2.so app_transfer.so
|
||||
|
||||
#APPS+=app_sql_postgres.so
|
||||
#APPS+=app_sql_odbc.so
|
||||
|
|
|
@ -26,11 +26,11 @@
|
|||
#include <pthread.h>
|
||||
|
||||
|
||||
static char *tdesc = "Date and Time";
|
||||
static char *tdesc = "ENUM Lookup";
|
||||
|
||||
static char *app = "EnumLookup";
|
||||
|
||||
static char *synopsis = "Say the date and time";
|
||||
static char *synopsis = "Lookup number in ENUM";
|
||||
|
||||
static char *descrip =
|
||||
" EnumLookup(exten): Looks up an extension via ENUM and sets\n"
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Time of day - Report the time of day
|
||||
*
|
||||
* 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 <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
|
||||
static char *tdesc = "Transfer";
|
||||
|
||||
static char *app = "Transfer";
|
||||
|
||||
static char *synopsis = "Transfer caller to remote extension";
|
||||
|
||||
static char *descrip =
|
||||
" Transfer(exten): Requests the remote caller be transferred to\n"
|
||||
"a given Returns -1 on hangup, or 0 on completion\n"
|
||||
"regardless of whether the transfer was successful. If the transfer\n"
|
||||
"was *not* supported or successful and there exists a priority n + 101,\n"
|
||||
"then that priority will be taken next.\n" ;
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int transfer_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
struct localuser *u;
|
||||
if (!data || !strlen(data)) {
|
||||
ast_log(LOG_WARNING, "Transfer requires an argument (destination)\n");
|
||||
res = 1;
|
||||
}
|
||||
LOCAL_USER_ADD(u);
|
||||
if (!res) {
|
||||
res = ast_transfer(chan, data);
|
||||
}
|
||||
if (!res) {
|
||||
/* Look for a "busy" place */
|
||||
if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid))
|
||||
chan->priority += 100;
|
||||
}
|
||||
if (res > 0)
|
||||
res = 0;
|
||||
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, transfer_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
20
channel.c
20
channel.c
|
@ -1568,6 +1568,26 @@ int ast_call(struct ast_channel *chan, char *addr, int timeout)
|
|||
return res;
|
||||
}
|
||||
|
||||
int ast_transfer(struct ast_channel *chan, char *dest)
|
||||
{
|
||||
/* Place an outgoing call, but don't wait any longer than timeout ms before returning.
|
||||
If the remote end does not answer within the timeout, then do NOT hang up, but
|
||||
return anyway. */
|
||||
int res = -1;
|
||||
/* Stop if we're a zombie or need a soft hangup */
|
||||
ast_pthread_mutex_lock(&chan->lock);
|
||||
if (!chan->zombie && !ast_check_hangup(chan)) {
|
||||
if (chan->pvt->transfer) {
|
||||
res = chan->pvt->transfer(chan, dest);
|
||||
if (!res)
|
||||
res = 1;
|
||||
} else
|
||||
res = 0;
|
||||
}
|
||||
pthread_mutex_unlock(&chan->lock);
|
||||
return res;
|
||||
}
|
||||
|
||||
int ast_readstring(struct ast_channel *c, char *s, int len, int timeout, int ftimeout, char *enders)
|
||||
{
|
||||
int pos=0;
|
||||
|
|
|
@ -994,7 +994,6 @@ static void iax2_destroy(int callno)
|
|||
retry:
|
||||
ast_pthread_mutex_lock(&iaxsl[callno]);
|
||||
pvt = iaxs[callno];
|
||||
iaxs[callno] = NULL;
|
||||
gettimeofday(&lastused[callno], NULL);
|
||||
|
||||
if (pvt)
|
||||
|
@ -1009,6 +1008,7 @@ retry:
|
|||
goto retry;
|
||||
}
|
||||
}
|
||||
iaxs[callno] = NULL;
|
||||
if (pvt) {
|
||||
pvt->owner = NULL;
|
||||
/* No more pings or lagrq's */
|
||||
|
@ -1918,6 +1918,26 @@ static int iax2_indicate(struct ast_channel *c, int condition)
|
|||
return send_command(pvt, AST_FRAME_CONTROL, condition, 0, NULL, 0, -1);
|
||||
}
|
||||
|
||||
static int iax2_transfer(struct ast_channel *c, char *dest)
|
||||
{
|
||||
struct chan_iax2_pvt *pvt = c->pvt->pvt;
|
||||
struct iax_ie_data ied;
|
||||
char tmp[256] = "", *context;
|
||||
strncpy(tmp, dest, sizeof(tmp) - 1);
|
||||
context = strchr(tmp, '@');
|
||||
if (context) {
|
||||
*context = '\0';
|
||||
context++;
|
||||
}
|
||||
memset(&ied, 0, sizeof(ied));
|
||||
iax_ie_append_str(&ied, IAX_IE_CALLED_NUMBER, tmp);
|
||||
if (context)
|
||||
iax_ie_append_str(&ied, IAX_IE_CALLED_CONTEXT, context);
|
||||
if (option_debug)
|
||||
ast_log(LOG_DEBUG, "Transferring '%s' to '%s'\n", c->name, dest);
|
||||
return send_command(pvt, AST_FRAME_IAX, IAX_COMMAND_TRANSFER, 0, ied.buf, ied.pos, -1);
|
||||
}
|
||||
|
||||
|
||||
static int iax2_write(struct ast_channel *c, struct ast_frame *f);
|
||||
|
||||
|
@ -1966,6 +1986,7 @@ static struct ast_channel *ast_iax2_new(struct chan_iax2_pvt *i, int state, int
|
|||
tmp->pvt->indicate = iax2_indicate;
|
||||
tmp->pvt->setoption = iax2_setoption;
|
||||
tmp->pvt->bridge = iax2_bridge;
|
||||
tmp->pvt->transfer = iax2_transfer;
|
||||
if (strlen(i->callerid))
|
||||
tmp->callerid = strdup(i->callerid);
|
||||
if (strlen(i->ani))
|
||||
|
@ -3973,6 +3994,17 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
|
|||
send_command_immediate(iaxs[fr.callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr.ts, NULL, 0,fr.iseqno);
|
||||
iax2_destroy_nolock(fr.callno);
|
||||
break;
|
||||
case IAX_COMMAND_TRANSFER:
|
||||
if (iaxs[fr.callno]->owner && iaxs[fr.callno]->owner->bridge && ies.called_number) {
|
||||
if (ast_async_goto(iaxs[fr.callno]->owner->bridge, iaxs[fr.callno]->context, ies.called_number, 1, 1))
|
||||
ast_log(LOG_WARNING, "Async goto of '%s' to '%s@%s' failed\n", iaxs[fr.callno]->owner->bridge->name,
|
||||
ies.called_number, iaxs[fr.callno]->context);
|
||||
else
|
||||
ast_log(LOG_DEBUG, "Async goto of '%s' to '%s@%s' started\n", iaxs[fr.callno]->owner->bridge->name,
|
||||
ies.called_number, iaxs[fr.callno]->context);
|
||||
} else
|
||||
ast_log(LOG_DEBUG, "Async goto not applicable on call %d\n", fr.callno);
|
||||
break;
|
||||
case IAX_COMMAND_ACCEPT:
|
||||
/* Ignore if call is already up or needs authentication or is a TBD */
|
||||
if (iaxs[fr.callno]->state & (IAX_STATE_STARTED | IAX_STATE_TBD | IAX_STATE_AUTHENTICATED))
|
||||
|
|
|
@ -116,6 +116,7 @@ static struct iax2_ie {
|
|||
{ IAX_IE_MSGCOUNT, "MESSAGE COUNT", dump_short },
|
||||
{ IAX_IE_AUTOANSWER, "AUTO ANSWER REQ" },
|
||||
{ IAX_IE_TRANSFERID, "TRANSFER ID", dump_int },
|
||||
{ IAX_IE_RDNIS, "REFERRING DNIS", dump_string },
|
||||
};
|
||||
|
||||
const char *iax_ie2str(int ie)
|
||||
|
@ -217,6 +218,7 @@ void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, s
|
|||
"PAGE",
|
||||
"MWI",
|
||||
"UNSUPPORTED",
|
||||
"TRANSFER",
|
||||
};
|
||||
char *cmds[] = {
|
||||
"(0?)",
|
||||
|
@ -420,6 +422,9 @@ int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
|
|||
case IAX_IE_DNID:
|
||||
ies->dnid = data + 2;
|
||||
break;
|
||||
case IAX_IE_RDNIS:
|
||||
ies->rdnis = data + 2;
|
||||
break;
|
||||
case IAX_IE_AUTHMETHODS:
|
||||
if (len != sizeof(unsigned short)) {
|
||||
snprintf(tmp, sizeof(tmp), "Expecting authmethods to be %d bytes long but was %d\n", sizeof(unsigned short), len);
|
||||
|
|
|
@ -28,6 +28,7 @@ struct iax_ies {
|
|||
int version;
|
||||
unsigned short adsicpe;
|
||||
char *dnid;
|
||||
char *rdnis;
|
||||
unsigned int authmethods;
|
||||
char *challenge;
|
||||
char *md5_result;
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
#define IAX_COMMAND_PAGE 31 /* Paging description */
|
||||
#define IAX_COMMAND_MWI 32 /* Stand-alone message waiting indicator */
|
||||
#define IAX_COMMAND_UNSUPPORT 33 /* Unsupported message received */
|
||||
#define IAX_COMMAND_TRANSFER 34 /* Request remote transfer */
|
||||
|
||||
#define IAX_DEFAULT_REG_EXPIRE 60 /* By default require re-registration once per minute */
|
||||
|
||||
|
@ -98,6 +99,7 @@
|
|||
#define IAX_IE_AUTOANSWER 25 /* Request auto-answering -- none */
|
||||
#define IAX_IE_MUSICONHOLD 26 /* Request musiconhold with QUELCH -- none or string */
|
||||
#define IAX_IE_TRANSFERID 27 /* Transfer Request Identifier -- int */
|
||||
#define IAX_IE_RDNIS 28 /* Referring DNIS -- string */
|
||||
|
||||
#define IAX_AUTH_PLAINTEXT (1 << 0)
|
||||
#define IAX_AUTH_MD5 (1 << 1)
|
||||
|
|
|
@ -676,6 +676,10 @@ int ast_autoservice_stop(struct ast_channel *chan);
|
|||
timer fd */
|
||||
int ast_settimeout(struct ast_channel *c, int ms);
|
||||
|
||||
/* Transfer a channel (if supported). Returns -1 on error, 0 if not supported
|
||||
and 1 if supported and requested */
|
||||
int ast_transfer(struct ast_channel *chan, char *dest);
|
||||
|
||||
/* Misc. functions below */
|
||||
|
||||
//! Waits for activity on a group of channels
|
||||
|
|
|
@ -65,6 +65,8 @@ struct ast_channel_pvt {
|
|||
int (*setoption)(struct ast_channel *chan, int option, void *data, int datalen);
|
||||
/*! Query a given option */
|
||||
int (*queryoption)(struct ast_channel *chan, int option, void *data, int *datalen);
|
||||
/*! Blind transfer other side */
|
||||
int (*transfer)(struct ast_channel *chan, char *newdest);
|
||||
};
|
||||
|
||||
//! Create a channel structure
|
||||
|
|
Reference in New Issue