** **
\*****************************************************************************/
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
#include "main.h"
"interface=<interface>[,...]", "Matches if call is received from given interface(s). NOT PORTS!"},
{ "callerid", MATCH_CALLERID, COND_TYPE_STRING,
"callerid=<digits>[-<digits>][,...]", "Matches if caller ID matches or begins with the given (range(s) of) prefixes(s)."},
+ { "callerid2", MATCH_CALLERID2,COND_TYPE_STRING,
+ "callerid2=<digits>[-<digits>][,...]", "Matches the second caller ID (network provided)."},
{ "extension", MATCH_EXTENSION,COND_TYPE_STRING,
"extension=<digits>[-<digits>][,...]", "Matches if caller calls from given (range(s) of) extension(s)."},
{ "dialing", MATCH_DIALING, COND_TYPE_STRING,
{ "busy", MATCH_BUSY, COND_TYPE_STRING,
"busy=<extension>[,...]","Matches if any of the given extension is busy."},
{ "notbusy", MATCH_IDLE, COND_TYPE_STRING,
- "notbusy<extension>[,...]","Matches if any of the given extension is not busy."},
+ "notbusy=<extension>[,...]","Matches if any of the given extension is not busy."},
+ { "remote", MATCH_REMOTE, COND_TYPE_STRING,
+ "remote=<application name>","Matches if remote application is running."},
+ { "notremote", MATCH_NOTREMOTE,COND_TYPE_STRING,
+ "notremote=<application name>","Matches if remote application is not running."},
{ NULL, 0, 0, NULL}
};
"capability=speech|audio|video|digital-restricted|digital-unrestricted|digital-unrestricted-tones", "Alter the service type of the call."},
{ PARAM_BMODE,
"bmode", PARAM_TYPE_BMODE,
- "capability=transparent|hdlc", "Alter the bchannel mode of the call. Use hdlc for data calls."},
+ "bmode=transparent|hdlc", "Alter the bchannel mode of the call. Use hdlc for data calls."},
{ PARAM_INFO1,
"infolayer1", PARAM_TYPE_INTEGER,
"infolayer1=<value>", "Alter the layer 1 information of a call. Use 3 for ALAW or 2 for uLAW."},
{ PARAM_ROOM,
"room", PARAM_TYPE_INTEGER,
"room=<digits>", "Conference room number, must be greater 0, as in real life."},
+ { PARAM_JINGLE,
+ "jingle", PARAM_TYPE_NULL,
+ "jingle", "Conference members will hear a jingle if a member joins."},
{ PARAM_TIMEOUT,
"timeout", PARAM_TYPE_INTEGER,
"timeout=<seconds>", "Timeout before continue with next action."},
{ PARAM_NOPASSWORD,
"nopassword", PARAM_TYPE_NULL,
"nopassword", "Don't ask for password. Be sure to authenticate right via real caller ID."},
+ { PARAM_STRIP,
+ "strip", PARAM_TYPE_NULL,
+ "strip", "Remove digits that were required to match this rule."},
+ { PARAM_APPLICATION,
+ "application",PARAM_TYPE_STRING,
+ "application=<name>", "Name of remote application to make call to."},
+ { PARAM_CONTEXT,
+ "context", PARAM_TYPE_STRING,
+ "context=<context>", "Give context parameter to the remote application."},
+ { PARAM_EXTEN,
+ "exten", PARAM_TYPE_STRING,
+ "exten=<extension>", "Give exten parameter to the remote application. (overrides dialed number)"},
{ 0, NULL, 0, NULL, NULL}
};
"outdial", &EndpointAppPBX::action_init_call, &EndpointAppPBX::action_dialing_external, &EndpointAppPBX::action_hangup_call,
PARAM_CONNECT | PARAM_PREFIX | PARAM_COMPLETE | PARAM_TYPE | PARAM_CAPA | PARAM_BMODE | PARAM_INFO1 | PARAM_HLC | PARAM_EXTHLC | PARAM_PRESENT | PARAM_INTERFACES | PARAM_CALLERID | PARAM_CALLERIDTYPE | PARAM_TIMEOUT,
"Same as 'extern'"},
- { ACTION_CHAN,
- "asterisk", &EndpointAppPBX::action_init_chan, &EndpointAppPBX::action_dialing_chan, &EndpointAppPBX::action_hangup_call,
- PARAM_CONNECT | PARAM_TIMEOUT,
- "Call is routed to Asterisk via channel driver."},
+ { ACTION_REMOTE,
+ "remote", &EndpointAppPBX::action_init_remote, &EndpointAppPBX::action_dialing_remote, &EndpointAppPBX::action_hangup_call,
+ PARAM_CONNECT | PARAM_APPLICATION | PARAM_CONTEXT | PARAM_EXTEN | PARAM_TIMEOUT,
+ "Call is routed to Remote application, like Asterisk."},
{ ACTION_VBOX_RECORD,
"vbox-record",&EndpointAppPBX::action_init_call, &EndpointAppPBX::action_dialing_vbox_record, &EndpointAppPBX::action_hangup_call,
PARAM_CONNECT | PARAM_EXTENSION | PARAM_ANNOUNCEMENT | PARAM_TIMEOUT,
"Caller is routed to the voice box of given extension."},
{ ACTION_PARTYLINE,
"partyline",&EndpointAppPBX::action_init_partyline, NULL, &EndpointAppPBX::action_hangup_call,
- PARAM_ROOM,
+ PARAM_ROOM | PARAM_JINGLE,
"Caller is participating the conference with the given room number."},
{ ACTION_LOGIN,
"login", NULL, &EndpointAppPBX::action_dialing_login, NULL,
{ ACTION_REPLY,
"reply", &EndpointAppPBX::action_init_redial_reply, &EndpointAppPBX::action_dialing_reply, NULL,
PARAM_CONNECT | PARAM_SELECT,
- "Caller replies. (last incomming call(s))"},
+ "Caller replies. (last incoming call(s))"},
{ ACTION_POWERDIAL,
"powerdial", NULL, &EndpointAppPBX::action_dialing_powerdial, NULL,
PARAM_CONNECT | PARAM_DELAY | PARAM_LIMIT | PARAM_TIMEOUT,
// "Caller calls the timer."},
{ ACTION_GOTO,
"goto", NULL, &EndpointAppPBX::action_dialing_goto, NULL,
- PARAM_CONNECT | PARAM_RULESET | PARAM_SAMPLE,
+ PARAM_CONNECT | PARAM_RULESET | PARAM_STRIP | PARAM_SAMPLE,
"Jump to given ruleset and optionally play sample. Dialed digits are not flushed."},
{ ACTION_MENU,
"menu", NULL, &EndpointAppPBX::action_dialing_menu, NULL,
"disconnect", NULL, &EndpointAppPBX::action_dialing_disconnect, NULL,
PARAM_CONNECT | PARAM_CAUSE | PARAM_LOCATION | PARAM_SAMPLE | PARAM_DISPLAY,
"Caller gets disconnected optionally with given cause and given sample and given display text."},
- { ACTION_HELP,
- "help", NULL, &EndpointAppPBX::action_dialing_help, NULL,
- PARAM_CONNECT | PARAM_TIMEOUT,
- NULL},
-// "Caller will be able to select from current rules that would match. (using * and #)"},
{ ACTION_DEFLECT,
"deflect", NULL, &EndpointAppPBX::action_dialing_deflect, NULL,
PARAM_DEST,
{ ACTION_EFI,
"efi", &EndpointAppPBX::action_init_efi, NULL, NULL,
PARAM_PROCEEDING | PARAM_ALERTING | PARAM_CONNECT,
- "Elektronische Fernsprecher Identifikation."},
+ "Elektronische Fernsprecher Identifikation - announces caller ID."},
{ -1,
NULL, NULL, NULL, NULL, 0, NULL}
};
cond = rule->cond_first;
if (cond->string_value)
{
- free(cond->string_value);
+ FREE(cond->string_value, 0);
rmemuse--;
}
if (cond->string_value_to)
{
- free(cond->string_value_to);
+ FREE(cond->string_value_to, 0);
rmemuse--;
}
rule->cond_first = cond->next;
- free(cond);
+ FREE(cond, sizeof(struct route_cond));
rmemuse--;
}
while(rule->action_first)
action->param_first = param->next;
if (param->string_value)
{
- free(param->string_value);
+ FREE(param->string_value, 0);
rmemuse--;
}
- free(param);
+ FREE(param, sizeof(struct route_param));
rmemuse--;
}
- free(action);
+ FREE(action, sizeof(struct route_action));
rmemuse--;
}
- free(rule);
+ FREE(rule, sizeof(struct route_rule));
rmemuse--;
}
- free(ruleset);
+ FREE(ruleset, sizeof(struct route_ruleset));
rmemuse--;
}
}
/*
* parse ruleset
*/
-static char *read_string(char *p, char *key, int key_size, char *special)
+static char *read_string(char *p, char *key, int key_size, const char *special)
{
key[0] = 0;
struct route_param *param;
struct route_param **param_pointer = NULL;
char failure[256];
+ unsigned long long allowed_params;
/* check the integrity of IDs for ACTION_* and PARAM_* */
i = 0;
j<<=1;
}
- SPRINT(filename[0], "%s/routing.conf", INSTALL_DATA);
+ SPRINT(filename[0], "%s/routing.conf", CONFIG_DATA);
if (!(fp[0]=fopen(filename[0],"r")))
{
if (key[0] == '/')
SCPY(filename[nesting+1], key);
else
- SPRINT(filename[nesting+1], "%s/%s", INSTALL_DATA, key);
+ SPRINT(filename[nesting+1], "%s/%s", CONFIG_DATA, key);
if (!(fp[nesting+1]=fopen(filename[nesting+1],"r")))
{
PERROR("Cannot open %s\n", filename[nesting+1]);
/* reading ruleset name text */
i = 0;
- while((*p>='a' && *p<='z') || (*p>='A' && *p<='Z') || (*p>='0' && *p<='9'))
+ while(*p>' ' && *p<127 && *p!=']')
{
if (*p>='A' && *p<='Z') *p = *p-'A'+'a'; /* lower case */
key[i++] = *p++;
}
/* create ruleset */
- ruleset = (struct route_ruleset *)malloc(sizeof(struct route_ruleset));
- if (ruleset == NULL)
- {
- SPRINT(failure, "Out of memory.");
- goto parse_error;
- }
+ ruleset = (struct route_ruleset *)MALLOC(sizeof(struct route_ruleset));
rmemuse++;
- memset(ruleset, 0, sizeof(struct route_ruleset));
*ruleset_pointer = ruleset;
ruleset_pointer = &(ruleset->next);
SCPY(ruleset->name, key);
goto new_ruleset;
}
- /* alloc memory for rule */
- rule = (struct route_rule *)malloc(sizeof(struct route_rule));
- if (rule == NULL)
- {
- SPRINT(failure, "Out of memory.");
- goto parse_error;
- }
+ /* Alloc memory for rule */
+ rule = (struct route_rule *)MALLOC(sizeof(struct route_rule));
rmemuse++;
- memset(rule, 0, sizeof(struct route_rule));
*rule_pointer = rule;
rule_pointer = &(rule->next);
cond_pointer = &(rule->cond_first);
}
nextcondvalue:
- /* alloc memory for item */
- cond = (struct route_cond *)malloc(sizeof(struct route_cond));
- if (cond == NULL)
- {
- SPRINT(failure, "Out of memory.");
- goto parse_error;
- }
+ /* Alloc memory for item */
+ cond = (struct route_cond *)MALLOC(sizeof(struct route_cond));
rmemuse++;
- memset(cond, 0, sizeof(struct route_cond));
*cond_pointer = cond;
cond_pointer = &(cond->next);
cond->index = index;
}
}
alloc_string:
- cond->string_value = (char *)malloc(strlen(key)+1);
- if (cond->string_value == NULL)
- {
- SPRINT(failure, "Out of memory.");
- goto parse_error;
- }
+ cond->string_value = (char *)MALLOC(strlen(key)+1);
rmemuse++;
UCPY(cond->string_value, key);
if (value_type == VALUE_TYPE_STRING_RANGE)
{
- cond->string_value_to = (char *)malloc(strlen(key_to)+1);
- if (cond->string_value_to == NULL)
- {
- SPRINT(failure, "Out of memory.");
- goto parse_error;
- }
+ cond->string_value_to = (char *)MALLOC(strlen(key_to)+1);
rmemuse++;
UCPY(cond->string_value_to, key_to);
cond->comp_string = strcmp(key, key_to);
SPRINT(failure, "Unknown action name '%s'.", key);
goto parse_error;
}
+ allowed_params = action_defs[index].params;
/* alloc memory for action */
- action = (struct route_action *)malloc(sizeof(struct route_action));
- if (action == NULL)
- {
- SPRINT(failure, "Out of memory.");
- goto parse_error;
- }
+ action = (struct route_action *)MALLOC(sizeof(struct route_action));
rmemuse++;
- memset(action, 0, sizeof(struct route_action));
*action_pointer = action;
action_pointer = &(action->next);
param_pointer = &(action->param_first);
goto parse_error;
}
+ /* check if item is allowed for the action */
+ if (!(param_defs[index].id & allowed_params))
+ {
+ SPRINT(failure, "Param name '%s' exists, but not for this action.", key);
+ goto parse_error;
+ }
+
/* params without values must not have any parameter */
if (param_defs[index].type == PARAM_TYPE_NULL)
{
}
nextparamvalue:
- /* alloc memory for param */
- param = (struct route_param *)malloc(sizeof(struct route_param));
- if (param == NULL)
- {
- SPRINT(failure, "Out of memory.");
- goto parse_error;
- }
+ /* Alloc memory for param */
+ param = (struct route_param *)MALLOC(sizeof(struct route_param));
rmemuse++;
- memset(param, 0, sizeof(struct route_param));
*param_pointer = param;
param_pointer = &(param->next);
param->index = index;
SPRINT(failure, "Value '%s' unknown. ('yes' or 'no')", key);
goto parse_error;
}
- param->string_value = (char *)malloc(strlen(key)+1);
- if (param->string_value == NULL)
- {
- SPRINT(failure, "Out of memory.");
- goto parse_error;
- }
+ param->string_value = (char *)MALLOC(strlen(key)+1);
rmemuse++;
UCPY(param->string_value, key);
param->value_type = VALUE_TYPE_STRING;
/*
* return ruleset by name
*/
-struct route_ruleset *getrulesetbyname(char *name)
+struct route_ruleset *getrulesetbyname(const char *name)
{
struct route_ruleset *ruleset = ruleset_first;
struct route_action *action = NULL;
unsigned long comp_len;
int j, jj;
- char callerid[64], redirid[64];
+ char callerid[64], callerid2[64], redirid[64];
int integer;
char *string;
FILE *tfp;
double timeout;
struct mISDNport *mISDNport;
+ struct admin_list *admin;
/* reset timeout action */
e_match_timeout = 0; /* no timeout */
e_match_to_action = NULL;
- SCPY(callerid, numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype));
- SCPY(redirid, numberrize_callerinfo(e_redirinfo.id, e_redirinfo.ntype));
+ SCPY(callerid, numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype, options.national, options.international));
+ SCPY(callerid2, numberrize_callerinfo(e_callerinfo.id2, e_callerinfo.ntype2, options.national, options.international));
+ SCPY(redirid, numberrize_callerinfo(e_redirinfo.id, e_redirinfo.ntype, options.national, options.international));
PDEBUG(DEBUG_ROUTE, "parsing ruleset '%s'\n", ruleset->name);
while(rule)
string = callerid;
goto match_string_prefix;
+ case MATCH_CALLERID2:
+ string = callerid2;
+ goto match_string_prefix;
+
case MATCH_EXTENSION:
string = e_ext.name;
goto match_string;
case MATCH_DIALING:
- string = e_dialinginfo.number;
+ string = e_dialinginfo.id;
goto match_string_prefix;
case MATCH_ENBLOCK:
break;
case MATCH_REDIRECTED:
- if (e_redirinfo.present != INFO_PRESENT_NULL)
+ if (e_redirinfo.ntype != INFO_NTYPE_NOTPRESENT)
istrue = 1;
break;
case MATCH_DIRECT:
- if (e_redirinfo.present == INFO_PRESENT_NULL)
+ if (e_redirinfo.ntype == INFO_NTYPE_NOTPRESENT)
istrue = 1;
break;
if (mISDNport->ifport)
if (strlen(mISDNport->ifport->interface->name) == comp_len)
if (!strncasecmp(mISDNport->ifport->interface->name, cond->string_value, comp_len))
- if (!mISDNport->ptp || mISDNport->l2link)
+ if (!mISDNport->l2hold || mISDNport->l2link>0)
{
j = 0;
jj = mISDNport->b_num;
{
if (mISDNport->ifport)
if (!strcasecmp(mISDNport->ifport->interface->name, cond->string_value))
- if (!mISDNport->ptp || mISDNport->l2link) /* break if one is up */
+ if (!mISDNport->l2hold || mISDNport->l2link>0)
break;
mISDNport = mISDNport->next;
}
{
if (mISDNport->ifport)
if (!strcasecmp(mISDNport->ifport->interface->name, cond->string_value))
- if (!mISDNport->ptp || mISDNport->l2link) /* break if one is up */
+ if (!mISDNport->l2hold || mISDNport->l2link>0)
break;
mISDNport = mISDNport->next;
break;
case MATCH_BUSY:
+ case MATCH_IDLE:
any = 0;
mISDNport = mISDNport_first;
while(mISDNport)
break;
mISDNport = mISDNport->next;
}
- if (mISDNport)
+ if (mISDNport && cond->match==MATCH_BUSY)
+ istrue = 1;
+ if (!mISDNport && cond->match==MATCH_IDLE)
istrue = 1;
break;
- case MATCH_IDLE:
- mISDNport = mISDNport_first;
- while(mISDNport)
+ case MATCH_REMOTE:
+ case MATCH_NOTREMOTE:
+ admin = admin_first;
+ while(admin)
{
- if (mISDNport->ifport)
- if (!strcasecmp(mISDNport->ifport->interface->name, cond->string_value))
- if (mISDNport->use) /* break if in use */
+ if (admin->remote_name[0] && !strcmp(cond->string_value, admin->remote_name))
break;
- mISDNport = mISDNport->next;
+ admin = admin->next;
}
- if (!mISDNport)
+ if (admin && cond->match==MATCH_REMOTE)
+ istrue = 1;
+ if (!admin && cond->match==MATCH_NOTREMOTE)
istrue = 1;
break;
/* set timeout in the furture */
e_match_timeout = timeout;
e_match_to_action = rule->action_first;
- e_match_to_extdialing = e_dialinginfo.number + dialing_required;
+ e_match_to_extdialing = e_dialinginfo.id + dialing_required;
match = 0; /* matches in the future */
}
if (match == 1)
action = rule->action_first;
e_match_timeout = 0; /* no timeout */
e_match_to_action = NULL;
- e_extdialing = e_dialinginfo.number + dialing_required;
+ e_extdialing = e_dialinginfo.id + dialing_required;
break;
}
if (match == 2)
0,
};
-struct route_action action_chan = {
+struct route_action action_remote = {
NULL,
NULL,
- ACTION_CHAN,
+ ACTION_REMOTE,
0,
0,
};