Files
asterisk/funcs/func_callerid.c
Mark Michelson b5d5cc565f Enhancements to connected line and redirecting work.
From reviewboard:

Digium has a commercial customer who has made extensive use of the connected party and
redirecting information present in later versions of Asterisk Business Edition and which
is to be in the upcoming 1.8 release. Through their use of the feature, new problems and solutions
have come about. This patch adds several enhancements to maximize usage of the connected party
and redirecting information functionality.

First, Asterisk trunk already had connected line interception macros. These macros allow you to
manipulate connected line information before it was sent out to its target. This patch adds the
same feature except for redirecting information instead.

Second, the ast_callerid and ast_party_id structures have been enhanced to provide a "tag." This
tag can be set with func_callerid, func_connectedline, func_redirecting, and in the case of DAHDI,
mISDN, and SIP channels, can be set in a configuration file. The idea behind the callerid tag is
that it can be set to whatever value the administrator likes. Later, when running connected line
and redirecting macros, the admin can read the tag off the appropriate structure to determine what
action to take. You can think of this sort of like a channel variable, except that instead of having
the variable associated with a channel, the variable is associated with a specific identity within
Asterisk.

Third, app_dial has two new options, s and u. The s option lets a dialplan writer force a specific
caller ID tag to be placed on the outgoing channel. The u option allows the dialplan writer to force
a specific calling presentation value on the outgoing channel.

Fourth, there is a new control frame subclass called AST_CONTROL_READ_ACTION added. This was added
to correct a very specific situation. In the case of SIP semi-attended (blond) transfers, the party
being transferred would not have the opportunity to run a connected line interception macro to
possibly alter the transfer target's connected line information. The issue here was that during a
blond transfer, the SIP transfer code has no bridged channel on which to queue the connected line
update. The way this was corrected was to add this new control frame subclass. Now, we queue an
AST_CONTROL_READ_ACTION frame on the channel on which the connected line interception macro should
be run. When ast_read is called to read the frame, ast_read responds by calling a callback function
associated with the specific read action the control frame describes. In this case, the action taken
is to run the connected line interception macro on the transferee's channel.

Review: https://reviewboard.asterisk.org/r/652/


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@263541 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2010-05-17 15:36:31 +00:00

388 lines
12 KiB
C

/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 1999-2006, Digium, Inc.
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
/*! \file
*
* \brief Caller ID related dialplan functions
*
* \ingroup functions
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/module.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/utils.h"
#include "asterisk/app.h"
#include "asterisk/callerid.h"
/*** DOCUMENTATION
<function name="CALLERID" language="en_US">
<synopsis>
Gets or sets Caller*ID data on the channel.
</synopsis>
<syntax>
<parameter name="datatype" required="true">
<para>The allowable datatypes are:</para>
<enumlist>
<enum name="all" />
<enum name="num" />
<enum name="name" />
<enum name="tag" />
<enum name="ANI" />
<enum name="DNID" />
<enum name="RDNIS" />
<enum name="pres" />
<enum name="ton" />
<enum name="subaddr[-valid]|[-type]|[-odd]">
<para>ISDN Calling Subaddress</para>
</enum>
<enum name="dnid-subaddr[-valid]|[-type]|[-odd]">
<para>ISDN Called Subaddress</para>
</enum>
</enumlist>
</parameter>
<parameter name="CID">
<para>Optional Caller*ID</para>
</parameter>
</syntax>
<description>
<para>Gets or sets Caller*ID data on the channel. Uses channel callerid by default or optional
callerid, if specified.</para>
</description>
</function>
<function name="CALLERPRES" language="en_US">
<synopsis>
Gets or sets Caller*ID presentation on the channel.
</synopsis>
<syntax />
<description>
<para>Gets or sets Caller*ID presentation on the channel. The following values
are valid:</para>
<enumlist>
<enum name="allowed_not_screened">
<para>Presentation Allowed, Not Screened.</para>
</enum>
<enum name="allowed_passed_screen">
<para>Presentation Allowed, Passed Screen.</para>
</enum>
<enum name="allowed_failed_screen">
<para>Presentation Allowed, Failed Screen.</para>
</enum>
<enum name="allowed">
<para>Presentation Allowed, Network Number.</para>
</enum>
<enum name="prohib_not_screened">
<para>Presentation Prohibited, Not Screened.</para>
</enum>
<enum name="prohib_passed_screen">
<para>Presentation Prohibited, Passed Screen.</para>
</enum>
<enum name="prohib_failed_screen">
<para>Presentation Prohibited, Failed Screen.</para>
</enum>
<enum name="prohib">
<para>Presentation Prohibited, Network Number.</para>
</enum>
<enum name="unavailable">
<para>Number Unavailable.</para>
</enum>
</enumlist>
</description>
</function>
***/
static int callerpres_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
{
ast_copy_string(buf, ast_named_caller_presentation(chan->cid.cid_pres), len);
return 0;
}
static int callerpres_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
{
int pres = ast_parse_caller_presentation(value);
if (pres < 0)
ast_log(LOG_WARNING, "'%s' is not a valid presentation (see 'show function CALLERPRES')\n", value);
else
chan->cid.cid_pres = pres;
return 0;
}
static int callerid_read(struct ast_channel *chan, const char *cmd, char *data,
char *buf, size_t len)
{
char *opt = data;
/* Ensure that the buffer is empty */
*buf = 0;
if (!chan)
return -1;
if (strchr(opt, ',')) {
char name[80], num[80];
data = strsep(&opt, ",");
ast_callerid_split(opt, name, sizeof(name), num, sizeof(num));
if (!strncasecmp("all", data, 3)) {
snprintf(buf, len, "\"%s\" <%s>", name, num);
} else if (!strncasecmp("name", data, 4)) {
ast_copy_string(buf, name, len);
} else if (!strncasecmp("num", data, 3)) {
/* also matches "number" */
ast_copy_string(buf, num, len);
} else {
ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
}
} else {
ast_channel_lock(chan);
if (!strncasecmp("all", data, 3)) {
snprintf(buf, len, "\"%s\" <%s>",
S_OR(chan->cid.cid_name, ""),
S_OR(chan->cid.cid_num, ""));
} else if (!strncasecmp("name", data, 4)) {
if (chan->cid.cid_name) {
ast_copy_string(buf, chan->cid.cid_name, len);
}
} else if (!strncasecmp("tag", data, 3)) {
if (chan->cid.cid_tag) {
ast_copy_string(buf, chan->cid.cid_tag, len);
}
} else if (!strncasecmp("num", data, 3)) {
/* also matches "number" */
if (chan->cid.cid_num) {
ast_copy_string(buf, chan->cid.cid_num, len);
}
} else if (!strncasecmp("ani", data, 3)) {
if (!strncasecmp(data + 3, "2", 1)) {
snprintf(buf, len, "%d", chan->cid.cid_ani2);
} else if (chan->cid.cid_ani) {
ast_copy_string(buf, chan->cid.cid_ani, len);
}
} else if (!strncasecmp("dnid", data, 4)) {
/* Called parties info */
/* also matches dnid-subaddr-valid, dnid-subaddr-type, dnid-subaddr-odd, dnid-subaddr */
if (!strncasecmp(data + 4 ,"-subaddr", 8)) {
if (!strncasecmp(data + 12 ,"-valid", 6)) { /* dnid-subaddr-valid */
snprintf(buf, len, "%d", chan->cid.dialed_subaddress.valid);
} else if (!strncasecmp(data + 12 ,"-type", 5)) { /* dnid-subaddr-type */
snprintf(buf, len, "%d", chan->cid.dialed_subaddress.type);
} else if (!strncasecmp(data + 12 ,"-odd", 4)) { /* dnid-subaddr-odd */
snprintf(buf, len, "%d", chan->cid.dialed_subaddress.odd_even_indicator);
} else { /* dnid-subaddr */
if (chan->cid.dialed_subaddress.str) {
ast_copy_string(buf, chan->cid.dialed_subaddress.str, len);
}
}
} else { /* dnid */
if (chan->cid.cid_dnid) {
ast_copy_string(buf, chan->cid.cid_dnid, len);
}
}
} else if (!strncasecmp("subaddr", data, 7)) {
/* Calling parties info */
/* also matches subaddr-valid, subaddr-type, subaddr-odd, subaddr */
if (!strncasecmp(data + 7 ,"-valid", 6)) { /* subaddr-valid */
snprintf(buf, len, "%d", chan->cid.subaddress.valid);
} else if (!strncasecmp(data + 7 ,"-type", 5)) { /* subaddr-type */
snprintf(buf, len, "%d", chan->cid.subaddress.type);
} else if (!strncasecmp(data + 7 ,"-odd", 4)) { /* subaddr-odd */
snprintf(buf, len, "%d", chan->cid.subaddress.odd_even_indicator);
} else { /* subaddr */
if (chan->cid.subaddress.str) {
ast_copy_string(buf, chan->cid.subaddress.str, len);
}
}
} else if (!strncasecmp("rdnis", data, 5)) {
if (chan->redirecting.from.number) {
ast_copy_string(buf, chan->redirecting.from.number, len);
}
} else if (!strncasecmp("pres", data, 4)) {
ast_copy_string(buf, ast_named_caller_presentation(chan->cid.cid_pres), len);
} else if (!strncasecmp("ton", data, 3)) {
snprintf(buf, len, "%d", chan->cid.cid_ton);
} else {
ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
}
ast_channel_unlock(chan);
}
return 0;
}
static int callerid_write(struct ast_channel *chan, const char *cmd, char *data,
const char *value)
{
if (!value || !chan)
return -1;
value = ast_skip_blanks(value);
if (!strncasecmp("all", data, 3)) {
char name[256];
char num[256];
ast_callerid_split(value, name, sizeof(name), num, sizeof(num));
ast_set_callerid(chan, num, name, num);
if (chan->cdr) {
ast_cdr_setcid(chan->cdr, chan);
}
} else if (!strncasecmp("name", data, 4)) {
ast_set_callerid(chan, NULL, value, NULL);
if (chan->cdr) {
ast_cdr_setcid(chan->cdr, chan);
}
} else if (!strncasecmp("num", data, 3)) {
/* also matches "number" */
ast_set_callerid(chan, value, NULL, NULL);
if (chan->cdr) {
ast_cdr_setcid(chan->cdr, chan);
}
} else if (!strncasecmp("tag", data, 3)) {
ast_channel_lock(chan);
if (chan->cid.cid_tag) {
ast_free(chan->cid.cid_tag);
}
chan->cid.cid_tag = ast_strdup(value);
ast_channel_unlock(chan);
} else if (!strncasecmp("ani", data, 3)) {
if (!strncasecmp(data + 3, "2", 1)) {
chan->cid.cid_ani2 = atoi(value);
} else {
ast_set_callerid(chan, NULL, NULL, value);
}
if (chan->cdr) {
ast_cdr_setcid(chan->cdr, chan);
}
} else if (!strncasecmp("dnid", data, 4)) {
ast_channel_lock(chan);
/* also matches dnid-subaddr-valid, dnid-subaddr-type, dnid-subaddr-odd, dnid-subaddr */
if (!strncasecmp(data + 4 ,"-subaddr", 8)) {
if (!strncasecmp(data + 12 ,"-valid", 6)) { /* dnid-subaddr-valid */
chan->cid.dialed_subaddress.valid = atoi(value) ? 1 : 0;
} else if (!strncasecmp(data + 12 ,"-type", 5)) { /* dnid-subaddr-type */
chan->cid.dialed_subaddress.type = atoi(value) ? 2 : 0;
} else if (!strncasecmp(data + 12 ,"-odd", 4)) { /* dnid-subaddr-odd */
chan->cid.dialed_subaddress.odd_even_indicator = atoi(value) ? 1 : 0;
} else { /* dnid-subaddr */
if (chan->cid.dialed_subaddress.str) {
ast_free(chan->cid.dialed_subaddress.str);
}
chan->cid.dialed_subaddress.str = ast_strdup(value);
}
} else { /* dnid */
if (chan->cid.cid_dnid) {
ast_free(chan->cid.cid_dnid);
}
chan->cid.cid_dnid = ast_strdup(value);
}
if (chan->cdr) {
ast_cdr_setcid(chan->cdr, chan);
}
ast_channel_unlock(chan);
} else if (!strncasecmp("subaddr", data, 7)) {
ast_channel_lock(chan);
/* also matches subaddr-valid, subaddr-type, subaddr-odd, subaddr */
if (!strncasecmp(data + 7 ,"-valid", 6)) { /* subaddr-valid */
chan->cid.subaddress.valid = atoi(value) ? 1 : 0;
} else if (!strncasecmp(data + 7 ,"-type", 5)) { /* subaddr-type */
chan->cid.subaddress.type = atoi(value) ? 2 : 0;
} else if (!strncasecmp(data + 7 ,"-odd", 4)) { /* subaddr-odd */
chan->cid.subaddress.odd_even_indicator = atoi(value) ? 1 : 0;
} else { /* subaddr */
if (chan->cid.subaddress.str) {
ast_free(chan->cid.subaddress.str);
}
chan->cid.subaddress.str = ast_strdup(value);
}
if (chan->cdr) {
ast_cdr_setcid(chan->cdr, chan);
}
ast_channel_unlock(chan);
} else if (!strncasecmp("rdnis", data, 5)) {
ast_channel_lock(chan);
ast_free(chan->redirecting.from.number);
chan->redirecting.from.number = ast_strdup(value);
if (chan->cdr) {
ast_cdr_setcid(chan->cdr, chan);
}
ast_channel_unlock(chan);
} else if (!strncasecmp("pres", data, 4)) {
int i;
char *val;
val = ast_strdupa(value);
ast_trim_blanks(val);
if ((val[0] >= '0') && (val[0] <= '9')) {
i = atoi(val);
} else {
i = ast_parse_caller_presentation(val);
}
if (i < 0) {
ast_log(LOG_ERROR, "Unknown calling number presentation '%s', value unchanged\n", val);
} else {
chan->cid.cid_pres = i;
}
} else if (!strncasecmp("ton", data, 3)) {
chan->cid.cid_ton = atoi(value);
} else {
ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data);
}
return 0;
}
static struct ast_custom_function callerid_function = {
.name = "CALLERID",
.read = callerid_read,
.read_max = 256,
.write = callerid_write,
};
static struct ast_custom_function callerpres_function = {
.name = "CALLERPRES",
.read = callerpres_read,
.read_max = 50,
.write = callerpres_write,
};
static int unload_module(void)
{
int res = ast_custom_function_unregister(&callerpres_function);
res |= ast_custom_function_unregister(&callerid_function);
return res;
}
static int load_module(void)
{
int res = ast_custom_function_register(&callerpres_function);
res |= ast_custom_function_register(&callerid_function);
return res;
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Caller ID related dialplan functions");