1 /*****************************************************************************\
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg **
8 ** match processing of routing configuration **
10 \*****************************************************************************/
15 struct route_ruleset *ruleset_first; /* first entry */
16 struct route_ruleset *ruleset_main; /* pointer to main ruleset */
18 struct cond_defs cond_defs[] = {
19 { "extern", MATCH_EXTERN, COND_TYPE_NULL,
20 "extern", "Matches if call is from external port (no extension)."},
21 { "intern", MATCH_INTERN,COND_TYPE_NULL,
22 "intern", "Matches if call is from an extension."},
23 { "port", MATCH_PORT, COND_TYPE_INTEGER,
24 "port=<number>[-<number>][,...]", "Matches if call is received from given port(s). NOT INTERFACE!"},
25 { "interface", MATCH_INTERFACE,COND_TYPE_STRING,
26 "interface=<interface>[,...]", "Matches if call is received from given interface(s). NOT PORTS!"},
27 { "callerid", MATCH_CALLERID, COND_TYPE_STRING,
28 "callerid=<digits>[-<digits>][,...]", "Matches if caller ID matches or begins with the given (range(s) of) prefixes(s)."},
29 { "callerid2", MATCH_CALLERID2,COND_TYPE_STRING,
30 "callerid2=<digits>[-<digits>][,...]", "Matches the second caller ID (network provided)."},
31 { "extension", MATCH_EXTENSION,COND_TYPE_STRING,
32 "extension=<digits>[-<digits>][,...]", "Matches if caller calls from given (range(s) of) extension(s)."},
33 { "dialing", MATCH_DIALING, COND_TYPE_STRING,
34 "dialing=<digits>[-<digits>][,...]", "Matches if caller has dialed the given (range(s) of) digits at least."},
35 { "enblock", MATCH_ENBLOCK, COND_TYPE_NULL,
36 "enblock", "Matches if caller dialed en block. (Dial the number before pick up.)"},
37 { "overlap", MATCH_OVERLAP, COND_TYPE_NULL,
38 "overlap", "Matches if caller dialed digit by digit. (Dial the number after pick up.)"},
39 { "anonymous", MATCH_ANONYMOUS,COND_TYPE_NULL,
40 "anonymous", "Matches if caller uses restricted caller ID or if not available."},
41 { "visible", MATCH_VISIBLE, COND_TYPE_NULL,
42 "visible", "Matches if caller ID is presented and if available."},
43 { "unknown", MATCH_UNKNOWN, COND_TYPE_NULL,
44 "unknown", "Matches if no ID is available from caller."},
45 { "available", MATCH_AVAILABLE,COND_TYPE_NULL,
46 "available", "Matches if ID is available from caller."},
47 { "fake", MATCH_FAKE, COND_TYPE_NULL,
48 "fake", "Matches if caller ID is not screened and may be faked by caller."},
49 { "real", MATCH_REAL, COND_TYPE_NULL,
50 "real", "Matches if caller ID is screend and so it is the real caller's ID."},
51 { "redirected", MATCH_REDIRECTED,COND_TYPE_NULL,
52 "redirected", "Matches if caller has been redirected."},
53 { "direct", MATCH_DIRECT ,COND_TYPE_NULL,
54 "direct", "Matches if caller did not come from an redirection."},
55 { "redirid", MATCH_REDIRID ,COND_TYPE_STRING,
56 "redirid=<digits>[-<digits>][,...]", "Matches if the caller has been redirected by the given (range(s) of) ID(s) or prefix(es))"},
57 { "time", MATCH_TIME, COND_TYPE_TIME,
58 "time=<minutes>[-<minutes>][,...]", "Matches if the caller calls within the given (range(s) of) time(s). (e.g. 0700-1900)"},
59 { "mday", MATCH_MDAY, COND_TYPE_MDAY,
60 "mday=<day>[-<day>][,...]", "Matches if the caller calls within the given (range(s) of) day(s) of the month. (1..31)"},
61 { "month", MATCH_MONTH, COND_TYPE_MONTH,
62 "month=<month>[-<month>][,...]", "Matches if the caller calls within the given (range(s) of) month(s). (1=January..12=December)"},
63 { "year", MATCH_YEAR, COND_TYPE_YEAR,
64 "year=<year>[-<year>][,...]", "Matches if the caller calls within the given (range(s) of) year(s). (1970..2106)"},
65 { "wday", MATCH_WDAY, COND_TYPE_WDAY,
66 "wday=<day>[-<day>][,...]", "Matches if the caller calls within the given (range(s) of) weekday(s). (1=Monday..7=Sunday)"},
67 { "capability", MATCH_CAPABILITY, COND_TYPE_CAPABILITY,
68 "capability=speech|audio|video|digital-restricted|digital-unrestricted|digital-unrestricted-tones[,...]", "Matches the given bearer capability(s)."},
69 { "infolayer1", MATCH_INFOLAYER1, COND_TYPE_INTEGER,
70 "infolayer1=<value>[,...]", "Matches the given information layer 1. (2=u-Law, 3=a-law, see info layer 1 in bearer capability.)"},
71 { "hlc", MATCH_HLC, COND_TYPE_INTEGER,
72 "hlc=<value>[,...]", "Matches the high layer capability(s)."},
73 { "file", MATCH_FILE, COND_TYPE_STRING,
74 "file=<path>[,...]", "Mathes is the given file exists and if the first character is '1'."},
75 { "execute", MATCH_EXECUTE, COND_TYPE_STRING,
76 "execute=<command>[,...]","Matches if the return value of the given command is greater 0."},
77 { "default", MATCH_DEFAULT, COND_TYPE_NULL,
78 "default","Matches if no further dialing could match."},
79 { "timeout", MATCH_TIMEOUT, COND_TYPE_INTEGER,
80 "timeout=<seconds>","Matches if the ruleset was entered AFTER given seconds."},
81 { "free", MATCH_FREE, COND_TYPE_IFATTR,
82 "free=<interface>:<channel>","Matches if the given minimum of channels are free."},
83 { "notfree", MATCH_NOTFREE, COND_TYPE_IFATTR,
84 "notfree=<interface>:<channel>","Matches if NOT the given minimum of channels are free."},
85 { "blocked", MATCH_DOWN, COND_TYPE_STRING,
86 "blocked=<interfaces>[,...]","Matches if all of the given interfaces are blocked."},
87 { "idle", MATCH_UP, COND_TYPE_STRING,
88 "idle=<interface>[,...]","Matches if any of the given interfaces is idle."},
89 { "busy", MATCH_BUSY, COND_TYPE_STRING,
90 "busy=<extension>[,...]","Matches if any of the given extension is busy."},
91 { "notbusy", MATCH_IDLE, COND_TYPE_STRING,
92 "notbusy=<extension>[,...]","Matches if any of the given extension is not busy."},
93 { "remote", MATCH_REMOTE, COND_TYPE_STRING,
94 "remote=<application name>","Matches if remote application is running."},
95 { "notremote", MATCH_NOTREMOTE,COND_TYPE_STRING,
96 "notremote=<application name>","Matches if remote application is not running."},
100 struct param_defs param_defs[] = {
102 "proceeding", PARAM_TYPE_NULL,
103 "proceeding", "Will set the call into 'proceeding' state to prevent dial timeout."},
105 "alerting", PARAM_TYPE_NULL,
106 "alerting", "Will set the call into 'altering' state."},
108 "connect", PARAM_TYPE_NULL,
109 "connect", "Will complete the call before processing the action. Audio path for external calls will be established."},
111 "extension", PARAM_TYPE_STRING,
112 "extension=<digits>", "Give extension name (digits) to relate this action to."},
114 "extensions", PARAM_TYPE_STRING,
115 "extensions=<extension>[,<extension>[,...]]", "One or more extensions may be given."},
117 "prefix", PARAM_TYPE_STRING,
118 "prefix=<digits>", "Add prefix in front of the dialed number."},
120 "capability", PARAM_TYPE_CAPABILITY,
121 "capability=speech|audio|video|digital-restricted|digital-unrestricted|digital-unrestricted-tones", "Alter the service type of the call."},
123 "bmode", PARAM_TYPE_BMODE,
124 "bmode=transparent|hdlc", "Alter the bchannel mode of the call. Use hdlc for data calls."},
126 "infolayer1", PARAM_TYPE_INTEGER,
127 "infolayer1=<value>", "Alter the layer 1 information of a call. Use 3 for ALAW or 2 for uLAW."},
129 "hlc", PARAM_TYPE_INTEGER,
130 "hlc=<value>", "Alter the HLC identification. Use 1 for telephony or omit."},
132 "exthlc", PARAM_TYPE_INTEGER,
133 "exthlc=<value>", "Alter extended HLC value. (Mainenance only, don't use it.)"},
135 "present", PARAM_TYPE_YESNO,
136 "present=yes|no", "Allow or restrict caller ID regardless what the caller wants."},
138 "diversion", PARAM_TYPE_DIVERSION,
139 "diversion=cfu|cfnr|cfb|cfp", "Set diversion type."},
141 "dest", PARAM_TYPE_DESTIN,
142 "dest=<string>", "Destination number to divert to. Use 'vbox' to divert to vbox. (cfu,cfnr,cfb only)"},
144 "select", PARAM_TYPE_NULL,
145 "select", "Lets the caller select the history of calls using keys '1'/'3' or '*'/'#'."},
147 "delay", PARAM_TYPE_INTEGER,
148 "delay=<seconds>", "Number of seconds to delay."},
150 "limit", PARAM_TYPE_INTEGER,
151 "limit=<retries>", "Number of maximum retries."},
153 "host", PARAM_TYPE_STRING,
154 "host=<string>", "Name of remote VoIP host."},
156 "port", PARAM_TYPE_STRING,
157 "port=<value>", "Alternate port to use if 'host' is given."},
159 "interfaces", PARAM_TYPE_STRING,
160 "interfaces=<interface>[,<interface>[,...]]", "Give one or a list of Interfaces to select a free channel from."},
162 "address", PARAM_TYPE_STRING,
163 "address=<string>", "Complete VoIP address. ( [user@]host[:port] )"},
165 "sample", PARAM_TYPE_STRING,
166 "sample=<file prefix>", "Filename of sample (current tone's dir) or full path to sample. ('.wav'/'.wave'/'.isdn' is added automatically."},
167 { PARAM_ANNOUNCEMENT,
168 "announcement",PARAM_TYPE_STRING,
169 "announcement=<file prefix>", "Filename of announcement (inside vbox recording dir) or full path to sample. ('.wav'/'.wave'/'.isdn' is added automatically."},
171 "ruleset", PARAM_TYPE_STRING,
172 "ruleset=<name>", "Ruleset to go to."},
174 "cause", PARAM_TYPE_INTEGER,
175 "cause=<cause value>", "Cause value when disconnecting. (21=reject 1=unassigned 63=service not available)"},
177 "location", PARAM_TYPE_INTEGER,
178 "location=<location value>", "Location of cause value when disconnecting. (0=user 1=private network sering local user)"},
180 "display", PARAM_TYPE_STRING,
181 "display=<text>", "Message to display on the caller's telephone. (internal only)"},
183 "ports", PARAM_TYPE_INTEGER,
184 "ports=<port>[,<port>[,...]]", "ISDN port[s] to use."},
186 "tpreset", PARAM_TYPE_INTEGER,
187 "tpreset=<seconds>", "Preset of countdown timer."},
189 "file", PARAM_TYPE_STRING,
190 "file=<full path>", "Full path to file name."},
192 "content", PARAM_TYPE_STRING,
193 "content=<string>", "Content to write into file."},
195 "append", PARAM_TYPE_NULL,
196 "append", "Will append to given file, rather than overwriting it."},
198 "execute", PARAM_TYPE_STRING,
199 "execute=<full path>", "Full path to script/command name. (Dialed digits are the argument 1.)"},
201 "param", PARAM_TYPE_STRING,
202 "param=<string>", "Optionally this parameter can be inserted as argument 1, others are shifted."},
204 "type", PARAM_TYPE_TYPE,
205 "type=unknown|subscriber|national|international", "Type of number to dial, default is 'unknown'."},
207 "complete", PARAM_TYPE_NULL,
208 "complete", "Indicates complete number as given by prefix. Proceeding of long distance calls may be faster."},
210 "callerid", PARAM_TYPE_STRING,
211 "callerid=<digits>", "Change caller ID to given string."},
212 { PARAM_CALLERIDTYPE,
213 "calleridtype",PARAM_TYPE_CALLERIDTYPE,
214 "calleridtype=[unknown|subscriber|national|international]", "Type of caller ID. For normal MSN use 'unknown'"},
216 "callto", PARAM_TYPE_STRING,
217 "callto=<digits>", "Where to call back. By default the caller ID is used."},
219 "room", PARAM_TYPE_INTEGER,
220 "room=<digits>", "Conference room number, must be greater 0, as in real life."},
222 "jingle", PARAM_TYPE_NULL,
223 "jingle", "Conference members will hear a jingle if a member joins."},
225 "timeout", PARAM_TYPE_INTEGER,
226 "timeout=<seconds>", "Timeout before continue with next action."},
228 "nopassword", PARAM_TYPE_NULL,
229 "nopassword", "Don't ask for password. Be sure to authenticate right via real caller ID."},
231 "strip", PARAM_TYPE_NULL,
232 "strip", "Remove digits that were required to match this rule."},
234 "application",PARAM_TYPE_STRING,
235 "application=<name>", "Name of remote application to make call to."},
237 "context", PARAM_TYPE_STRING,
238 "context=<context>", "Give context parameter to the remote application."},
240 "exten", PARAM_TYPE_STRING,
241 "exten=<extension>", "Give exten parameter to the remote application. (overrides dialed number)"},
243 "on", PARAM_TYPE_STRING,
244 "on=[init|hangup]", "Defines if the action is executed on call init or on hangup."},
245 { 0, NULL, 0, NULL, NULL}
248 struct action_defs action_defs[] = {
250 "extern", &EndpointAppPBX::action_init_call, &EndpointAppPBX::action_dialing_external, &EndpointAppPBX::action_hangup_call,
251 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,
252 "Call is routed to extern number as dialed."},
254 "intern", &EndpointAppPBX::action_init_call, &EndpointAppPBX::action_dialing_internal, &EndpointAppPBX::action_hangup_call,
255 PARAM_CONNECT | PARAM_EXTENSION | PARAM_TYPE | PARAM_CAPA | PARAM_BMODE | PARAM_INFO1 | PARAM_HLC | PARAM_EXTHLC | PARAM_PRESENT | PARAM_TIMEOUT,
256 "Call is routed to intern extension as given by the dialed number or specified by option."},
258 "outdial", &EndpointAppPBX::action_init_call, &EndpointAppPBX::action_dialing_external, &EndpointAppPBX::action_hangup_call,
259 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,
262 "remote", &EndpointAppPBX::action_init_remote, &EndpointAppPBX::action_dialing_remote, &EndpointAppPBX::action_hangup_call,
263 PARAM_CONNECT | PARAM_APPLICATION | PARAM_CONTEXT | PARAM_EXTEN | PARAM_TIMEOUT,
264 "Call is routed to Remote application, like Asterisk."},
265 { ACTION_VBOX_RECORD,
266 "vbox-record",&EndpointAppPBX::action_init_call, &EndpointAppPBX::action_dialing_vbox_record, &EndpointAppPBX::action_hangup_call,
267 PARAM_CONNECT | PARAM_EXTENSION | PARAM_ANNOUNCEMENT | PARAM_TIMEOUT,
268 "Caller is routed to the voice box of given extension."},
270 "partyline",&EndpointAppPBX::action_init_partyline, NULL, &EndpointAppPBX::action_hangup_call,
271 PARAM_ROOM | PARAM_JINGLE,
272 "Caller is participating the conference with the given room number."},
274 "login", NULL, &EndpointAppPBX::action_dialing_login, NULL,
275 PARAM_CONNECT | PARAM_EXTENSION | PARAM_NOPASSWORD,
276 "Log into the given extension. Password required."},
278 "callerid", &EndpointAppPBX::action_init_change_callerid, &EndpointAppPBX::action_dialing_callerid, NULL,
279 PARAM_CONNECT | PARAM_CALLERID | PARAM_CALLERIDTYPE | PARAM_PRESENT,
280 "Caller changes the caller ID for all calls."},
281 { ACTION_CALLERIDNEXT,
282 "calleridnext",&EndpointAppPBX::action_init_change_callerid, &EndpointAppPBX::action_dialing_calleridnext, NULL,
283 PARAM_CONNECT | PARAM_CALLERID | PARAM_CALLERIDTYPE | PARAM_PRESENT,
284 "Caller changes the caller ID for the next call."},
286 "forward", &EndpointAppPBX::action_init_change_forward, &EndpointAppPBX::action_dialing_forward, NULL,
287 PARAM_CONNECT | PARAM_DIVERSION | PARAM_DEST | PARAM_DELAY,
288 "Caller changes the diversion of given type to the given destination or voice box."},
290 "redial", &EndpointAppPBX::action_init_redial_reply, &EndpointAppPBX::action_dialing_redial, NULL,
291 PARAM_CONNECT | PARAM_SELECT,
292 "Caller redials. (last outgoing call(s))"},
294 "reply", &EndpointAppPBX::action_init_redial_reply, &EndpointAppPBX::action_dialing_reply, NULL,
295 PARAM_CONNECT | PARAM_SELECT,
296 "Caller replies. (last incoming call(s))"},
298 "powerdial", NULL, &EndpointAppPBX::action_dialing_powerdial, NULL,
299 PARAM_CONNECT | PARAM_DELAY | PARAM_LIMIT | PARAM_TIMEOUT,
300 "Caller redials using powerdialing."},
302 "callback", NULL, &EndpointAppPBX::action_dialing_callback, &EndpointAppPBX::action_hangup_callback,
303 PARAM_PROCEEDING | PARAM_ALERTING | PARAM_CONNECT | PARAM_EXTENSION | PARAM_DELAY | PARAM_CALLTO | PARAM_PREFIX,
304 "Caller will use the callback service. After disconnecting, the callback is triggered."},
306 "abbrev", NULL, &EndpointAppPBX::action_dialing_abbrev, NULL,
308 "Caller dials abbreviation."},
310 "test", NULL, &EndpointAppPBX::action_dialing_test, NULL,
311 PARAM_CONNECT | PARAM_PREFIX | PARAM_TIMEOUT,
312 "Caller dials test mode."},
314 "play", &EndpointAppPBX::action_init_play, NULL, NULL,
315 PARAM_PROCEEDING | PARAM_ALERTING | PARAM_CONNECT | PARAM_SAMPLE | PARAM_TIMEOUT,
316 "Plays the given sample."},
318 "vbox-play", &EndpointAppPBX::action_init_vbox_play, &EndpointAppPBX::action_dialing_vbox_play, NULL,
320 "Caller listens to her voice box or to given extension."},
322 "calculator", NULL, &EndpointAppPBX::action_dialing_calculator, NULL,
324 "Caller calls the calculator."},
326 "timer", NULL, &EndpointAppPBX::action_dialing_timer, NULL,
327 PARAM_CONNECT | PARAM_TPRESET | PARAM_TIMEOUT,
329 // "Caller calls the timer."},
331 "goto", NULL, &EndpointAppPBX::action_dialing_goto, NULL,
332 PARAM_PROCEEDING | PARAM_ALERTING | PARAM_CONNECT | PARAM_RULESET | PARAM_STRIP | PARAM_SAMPLE,
333 "Jump to given ruleset and optionally play sample. Dialed digits are not flushed."},
335 "menu", NULL, &EndpointAppPBX::action_dialing_menu, NULL,
336 PARAM_CONNECT | PARAM_RULESET | PARAM_SAMPLE,
337 "Same as 'goto', but flushes all digits dialed so far."},
339 "disconnect", NULL, &EndpointAppPBX::action_dialing_disconnect, NULL,
340 PARAM_CONNECT | PARAM_CAUSE | PARAM_LOCATION | PARAM_SAMPLE | PARAM_DISPLAY,
341 "Caller gets disconnected optionally with given cause and given sample and given display text."},
343 "deflect", NULL, &EndpointAppPBX::action_dialing_deflect, NULL,
346 // "External call is deflected to the given destination within the telephone network."},
348 "setforward", NULL, &EndpointAppPBX::action_dialing_setforward, NULL,
349 PARAM_CONNECT | PARAM_DIVERSION | PARAM_DEST | PARAM_PORT,
351 // "The call forward is set within the telephone network of the external line."},
353 "execute", &EndpointAppPBX::action_init_execute, NULL, &EndpointAppPBX::action_hangup_execute,
354 PARAM_CONNECT | PARAM_EXECUTE | PARAM_PARAM | PARAM_ON,
355 "Executes the given script file. The file must terminate quickly, because it will halt the PBX."},
357 "file", NULL, NULL, &EndpointAppPBX::action_hangup_file,
358 PARAM_CONNECT | PARAM_FILE | PARAM_CONTENT | PARAM_APPEND,
359 "Writes givent content to given file. If content is not given, the dialed digits are written."},
361 "pick", &EndpointAppPBX::action_init_pick, NULL, NULL,
363 "Pick up a call that is ringing on any phone. Extensions may be given to limit the picking ability."},
365 "password", NULL, &EndpointAppPBX::action_dialing_password, NULL,
368 { ACTION_PASSWORD_WRITE,
369 "password_wr",NULL, &EndpointAppPBX::action_dialing_password_wr, NULL,
373 "nothing", NULL, NULL, NULL,
374 PARAM_PROCEEDING | PARAM_ALERTING | PARAM_CONNECT | PARAM_TIMEOUT,
375 "does nothing. Usefull to wait for calls to be released completely, by giving timeout value."},
377 "efi", &EndpointAppPBX::action_init_efi, NULL, NULL,
378 PARAM_PROCEEDING | PARAM_ALERTING | PARAM_CONNECT,
379 "Elektronische Fernsprecher Identifikation - announces caller ID."},
381 NULL, NULL, NULL, NULL, 0, NULL}
385 /* display documentation of rules */
387 void doc_rules(const char *name)
393 while(action_defs[i].name) {
394 if (!strcasecmp(action_defs[i].name, name))
398 if (!action_defs[i].name) {
399 fprintf(stderr, "Given action '%s' unknown.\n", name);
402 name = action_defs[i].name;
405 printf("Syntax overview:\n");
406 printf("----------------\n\n");
407 printf("[ruleset]\n");
408 printf("<condition> ... : <action> [parameter ...] [timeout=X : <action> ...]\n");
410 printf("Please refer to the documentation for description on rule format.\n\n");
413 printf("Available conditions to match:\n");
414 printf("------------------------------\n\n");
416 while(cond_defs[i].name) {
417 printf("Usage: %s\n", cond_defs[i].doc);
418 printf("%s\n\n", cond_defs[i].help);
422 printf("Available actions with their parameters:\n");
423 printf("----------------------------------------\n\n");
425 printf("Detailes parameter description of action:\n");
426 printf("-----------------------------------------\n\n");
429 while(action_defs[i].name) {
430 if (name && !!strcmp(action_defs[i].name,name)) { /* not selected */
434 if (!action_defs[i].help) { /* not internal actions */
438 printf("Usage: %s", action_defs[i].name);
441 if ((1LL<<j) & action_defs[i].params)
442 printf(" [%s]", param_defs[j].doc);
445 printf("\n%s\n\n", action_defs[i].help);
446 if (name) { /* only show parameter help for specific action */
449 if ((1LL<<j) & action_defs[i].params)
450 printf("%s:\n\t%s\n", param_defs[j].doc, param_defs[j].help);
459 void ruleset_free(struct route_ruleset *ruleset_start)
461 struct route_ruleset *ruleset;
462 struct route_rule *rule;
463 struct route_cond *cond;
464 struct route_action *action;
465 struct route_param *param;
467 while(ruleset_start) {
468 ruleset = ruleset_start;
469 ruleset_start = ruleset->next;
470 while(ruleset->rule_first) {
471 rule = ruleset->rule_first;
472 ruleset->rule_first = rule->next;
473 while(rule->cond_first) {
474 cond = rule->cond_first;
475 if (cond->string_value) {
476 FREE(cond->string_value, 0);
479 if (cond->string_value_to) {
480 FREE(cond->string_value_to, 0);
483 rule->cond_first = cond->next;
484 FREE(cond, sizeof(struct route_cond));
487 while(rule->action_first) {
488 action = rule->action_first;
489 rule->action_first = action->next;
490 while(action->param_first) {
491 param = action->param_first;
492 action->param_first = param->next;
493 if (param->string_value) {
494 FREE(param->string_value, 0);
497 FREE(param, sizeof(struct route_param));
500 FREE(action, sizeof(struct route_action));
503 FREE(rule, sizeof(struct route_rule));
506 FREE(ruleset, sizeof(struct route_ruleset));
511 void ruleset_debug(struct route_ruleset *ruleset_start)
513 struct route_ruleset *ruleset;
514 struct route_rule *rule;
515 struct route_cond *cond;
516 struct route_action *action;
517 struct route_param *param;
520 ruleset = ruleset_start;
522 printf("Ruleset: '%s'\n", ruleset->name);
523 rule = ruleset->rule_first;
527 cond = rule->cond_first;
530 printf(" Condition:");
534 printf(" %s", cond_defs[cond->index].name);
535 if (cond->value_type != VALUE_TYPE_NULL)
538 switch(cond->value_type) {
539 case VALUE_TYPE_NULL:
542 case VALUE_TYPE_INTEGER:
543 printf("%d", cond->integer_value);
546 case VALUE_TYPE_INTEGER_RANGE:
547 printf("%d-%d", cond->integer_value, cond->integer_value_to);
550 case VALUE_TYPE_STRING:
551 printf("'%s'", cond->string_value);
554 case VALUE_TYPE_STRING_RANGE:
555 printf("'%s'-'%s'", cond->string_value, cond->string_value_to);
559 printf("Software error: VALUE_TYPE_* %d not known in function '%s' line=%d", cond->value_type, __FUNCTION__, __LINE__);
561 if (cond->value_extension && cond->next) {
564 goto next_cond_value;
572 action = rule->action_first;
574 printf(" Action: %s\n", action_defs[action->index].name);
577 param = action->param_first;
584 printf(" %s", param_defs[param->index].name);
585 if (param->value_type != VALUE_TYPE_NULL)
587 switch(param->value_type) {
588 case VALUE_TYPE_NULL:
591 case VALUE_TYPE_INTEGER:
592 if (param_defs[param->index].type == PARAM_TYPE_CALLERIDTYPE) {
593 switch(param->integer_value) {
594 case INFO_NTYPE_UNKNOWN:
597 case INFO_NTYPE_SUBSCRIBER:
598 printf("subscriber");
600 case INFO_NTYPE_NATIONAL:
603 case INFO_NTYPE_INTERNATIONAL:
604 printf("international");
607 printf("unknown(%d)", param->integer_value);
611 if (param_defs[param->index].type == PARAM_TYPE_CAPABILITY) {
612 switch(param->integer_value) {
622 case INFO_BC_DATARESTRICTED:
623 printf("digital-restricted");
625 case INFO_BC_DATAUNRESTRICTED:
626 printf("digital-unrestricted");
628 case INFO_BC_DATAUNRESTRICTED_TONES:
629 printf("digital-unrestricted-tones");
632 printf("unknown(%d)", param->integer_value);
636 if (param_defs[param->index].type == PARAM_TYPE_DIVERSION) {
637 switch(param->integer_value) {
638 case INFO_DIVERSION_CFU:
641 case INFO_DIVERSION_CFNR:
644 case INFO_DIVERSION_CFB:
647 case INFO_DIVERSION_CFP:
651 printf("unknown(%d)", param->integer_value);
655 if (param_defs[param->index].type == PARAM_TYPE_TYPE) {
656 switch(param->integer_value) {
657 case INFO_NTYPE_UNKNOWN:
660 case INFO_NTYPE_SUBSCRIBER:
661 printf("subscriber");
663 case INFO_NTYPE_NATIONAL:
666 case INFO_NTYPE_INTERNATIONAL:
667 printf("international");
670 printf("unknown(%d)", param->integer_value);
674 if (param_defs[param->index].type == PARAM_TYPE_YESNO) {
675 switch(param->integer_value) {
683 printf("unknown(%d)", param->integer_value);
687 if (param_defs[param->index].type == PARAM_TYPE_NULL) {
690 printf("%d", param->integer_value);
693 case VALUE_TYPE_STRING:
694 printf("'%s'", param->string_value);
698 printf("Software error: VALUE_TYPE_* %d not known in function '%s' line=%d", param->value_type, __FUNCTION__, __LINE__);
705 printf(" Timeout: %d\n", action->timeout);
706 action = action->next;
712 ruleset = ruleset->next;
720 static char *read_string(char *p, char *key, int key_size, const char *special)
739 if (--key_size == 0) {
740 UPRINT(key, "\001String too long.");
745 UPRINT(key, "\001Unexpected end of line inside quotes.");
751 if (strchr(special, *p)) {
758 UPRINT(key, "\001Unexpected end of line.");
762 if (--key_size == 0) {
763 UPRINT(key, "\001String too long.");
771 char ruleset_error[256];
772 struct route_ruleset *ruleset_parse(void)
777 unsigned long long j;
781 FILE *fp[MAXNESTING];
782 char filename[MAXNESTING][256];
783 int line[MAXNESTING];
790 int expecting = 1; /* 1 = expecting ruleset */
794 integer_to; /* condition index, .. */
795 struct route_ruleset *ruleset_start = NULL, *ruleset;
796 struct route_ruleset **ruleset_pointer = &ruleset_start;
797 struct route_rule *rule;
798 struct route_rule **rule_pointer = NULL;
799 struct route_cond *cond;
800 struct route_cond **cond_pointer = NULL;
801 struct route_action *action;
802 struct route_action **action_pointer = NULL;
803 struct route_param *param;
804 struct route_param **param_pointer = NULL;
806 unsigned long long allowed_params;
808 /* check the integrity of IDs for ACTION_* and PARAM_* */
810 while(action_defs[i].name) {
811 if (action_defs[i].id != i) {
812 PERROR("Software Error action '%s' must have id of %d, but has %d.\n",
813 action_defs[i].name, i, action_defs[i].id);
819 while(param_defs[i].name) {
820 if (param_defs[i].id != j) {
821 PERROR("Software Error param '%s' must have id of 0x%llx, but has 0x%llx.\n",
822 param_defs[i].name, j, param_defs[i].id);
829 SPRINT(filename[0], "%s/routing.conf", CONFIG_DATA);
831 if (!(fp[0]=fopen(filename[0],"r")))
833 PERROR("Cannot open %s\n",filename[0]);
842 while((fgets(buffer,sizeof(buffer),fp[nesting])))
845 buffer[sizeof(buffer)-1]=0;
846 if (buffer[0]) buffer[strlen(buffer)-1]=0;
857 /* skip spaces, if any */
868 /* don't skip "define" */
869 if (!!strncmp(p, "define", 6))
881 p = read_string(p, key, sizeof(key), " ");
882 if (key[0] == 1) { /* error */
883 SPRINT(failure, "Parsing Filename failed: %s", key+1);
886 if (nesting == MAXNESTING-1) {
887 SPRINT(failure, "'include' is nesting too deep.\n");
891 SCPY(filename[nesting+1], key);
893 SPRINT(filename[nesting+1], "%s/%s", CONFIG_DATA, key);
894 if (!(fp[nesting+1]=fopen(filename[nesting+1],"r"))) {
895 PERROR("Cannot open %s\n", filename[nesting+1]);
902 if (*p == '/') if (p[1] == '/')
905 /* skip empty lines */
909 /* expecting ruleset */
914 SPRINT(failure, "Expecting ruleset name starting with '['.");
919 /* reading ruleset name text */
921 while(*p>' ' && *p<127 && *p!=']') {
922 if (*p>='A' && *p<='Z') *p = *p-'A'+'a'; /* lower case */
924 if (i == sizeof(key)) i--; /* limit */
927 if (key[0] == '\0') {
928 SPRINT(failure, "Missing ruleset name after '['.");
932 /* expecting ] and nothing more */
934 SPRINT(failure, "Expecting ']' after ruleset name.");
939 SPRINT(failure, "Unexpected character after ruleset name.");
943 /* check for duplicate rulesets */
944 ruleset = ruleset_start;
946 if (!strcmp(ruleset->name, key)) {
947 SPRINT(failure, "Duplicate ruleset '%s', already defined in file '%s' line %d.", key, ruleset->file, ruleset->line);
950 ruleset = ruleset->next;
954 ruleset = (struct route_ruleset *)MALLOC(sizeof(struct route_ruleset));
956 *ruleset_pointer = ruleset;
957 ruleset_pointer = &(ruleset->next);
958 SCPY(ruleset->name, key);
959 SCPY(ruleset->file, filename[nesting]);
960 ruleset->line = line[nesting];
961 rule_pointer = &(ruleset->rule_first);
966 /* for new ruleset [ */
971 /* Alloc memory for rule */
972 rule = (struct route_rule *)MALLOC(sizeof(struct route_rule));
974 *rule_pointer = rule;
975 rule_pointer = &(rule->next);
976 cond_pointer = &(rule->cond_first);
977 action_pointer = &(rule->action_first);
978 SCPY(rule->file, filename[nesting]);
979 rule->line = line[nesting];
981 /* loop CONDITIONS */
982 while(*p!=':' && *p!='\0') {
985 while((*p>='a' && *p<='z') || (*p>='A' && *p<='Z') || (*p>='0' && *p<='9')) {
986 if (*p>='A' && *p<='Z') *p = *p-'A'+'a'; /* lower case */
988 if (i == sizeof(key)) i--; /* limit */
991 if (key[0] == '\0') {
992 SPRINT(failure, "Expecting condition item name or ':' for end of condition list.");
995 if (*p!=' ' && *p!='=') {
996 SPRINT(failure, "Illegal character '%c' after condition name '%s'. Expecting '=' for equation or ' ' to seperate condition items.", *p, key);
1000 /* check if condition exists */
1002 while(cond_defs[index].name) {
1003 if (!strcmp(cond_defs[index].name, key))
1007 if (cond_defs[index].name == NULL) {
1008 SPRINT(failure, "Unknown condition item name '%s'.", key);
1012 /* items without values must not have any parameter */
1013 if (cond_defs[index].type == COND_TYPE_NULL) {
1015 SPRINT(failure, "Condition item '%s' must not have any value. Don't use '=' for this type of condition.", key);
1019 SPRINT(failure, "Condition item '%s' must not have any value. Expecting ' ' or tab after item name.", key);
1025 SPRINT(failure, "Condition item '%s' must have at least one value, '=' expected, and not a space.", key);
1029 SPRINT(failure, "Condition item '%s' must have at least one value, '=' expected.", key);
1035 /* check for duplicate condition */
1036 cond = rule->cond_first;
1038 if (cond->index == index) {
1039 SPRINT(failure, "Duplicate condition '%s', use ',' to give multiple values.", key);
1046 /* Alloc memory for item */
1047 cond = (struct route_cond *)MALLOC(sizeof(struct route_cond));
1049 *cond_pointer = cond;
1050 cond_pointer = &(cond->next);
1051 cond->index = index;
1052 cond->match = cond_defs[index].match;
1053 switch(cond_defs[index].type) {
1054 case COND_TYPE_NULL:
1056 SPRINT(failure, "Expecting no value.");
1059 value_type = VALUE_TYPE_NULL;
1062 /* parse all integer values/ranges */
1063 case COND_TYPE_INTEGER:
1064 case COND_TYPE_TIME:
1065 case COND_TYPE_MDAY:
1066 case COND_TYPE_MONTH:
1067 case COND_TYPE_WDAY:
1068 case COND_TYPE_YEAR:
1069 integer = integer_to = 0;
1070 if (*p==',' || *p==' ' || *p=='\0') {
1071 SPRINT(failure, "Missing integer value.");
1074 while(*p>='0' && *p<='9') {
1075 integer = integer*10 + *p-'0';
1078 value_type = VALUE_TYPE_INTEGER;
1081 if (*p==',' || *p==' ' || *p=='\0') {
1082 SPRINT(failure, "Missing integer value.");
1085 while(*p>='0' && *p<='9') {
1086 integer_to = integer_to*10 + *p-'0';
1089 value_type = VALUE_TYPE_INTEGER_RANGE;
1091 if (cond_defs[index].type == COND_TYPE_TIME) {
1092 // Simon: i store the time as decimal, later i compare it correctly:
1093 // hours * 100 + minutes
1094 if (integer == 2400)
1096 if (integer >= 2400) {
1098 SPRINT(failure, "Given time '%d' not in range 0000..2359 (or 2400 for 0000)", integer);
1101 if (integer%100 >= 60)
1102 goto timeoutofrange1;
1103 if (value_type == VALUE_TYPE_INTEGER)
1105 if (integer_to == 2400)
1107 if (integer_to >= 2400) {
1109 SPRINT(failure, "Given time '%d' not in range 0000..2359 (or 2400 for 0000)", integer_to);
1112 if (integer_to%100 >= 60)
1113 goto timeoutofrange2;
1115 if (cond_defs[index].type == COND_TYPE_MDAY) {
1116 if (integer<1 || integer>31) {
1117 SPRINT(failure, "Given day-of-month '%d' not in range 1..31", integer);
1120 if (value_type == VALUE_TYPE_INTEGER)
1122 if (integer_to<1 || integer_to>31) {
1123 SPRINT(failure, "Given day-of-month '%d' not in range 1..31", integer_to);
1127 if (cond_defs[index].type == COND_TYPE_WDAY) {
1128 if (integer<1 || integer>7) {
1129 SPRINT(failure, "Given day-of-week '%d' not in range 1..7", integer);
1132 if (value_type == VALUE_TYPE_INTEGER)
1134 if (integer_to<1 || integer_to>7) {
1135 SPRINT(failure, "Given day-of-week '%d' not in range 1..7", integer_to);
1139 if (cond_defs[index].type == COND_TYPE_MONTH) {
1140 if (integer<1 || integer>12) {
1141 SPRINT(failure, "Given month '%d' not in range 1..12", integer);
1144 if (value_type == VALUE_TYPE_INTEGER)
1146 if (integer_to<1 || integer_to>12) {
1147 SPRINT(failure, "Given month '%d' not in range 1..12", integer_to);
1151 if (cond_defs[index].type == COND_TYPE_YEAR) {
1152 if (integer<1970 || integer>2106) {
1153 SPRINT(failure, "Given year '%d' not in range 1970..2106", integer);
1156 if (value_type == VALUE_TYPE_INTEGER)
1158 if (integer_to<1970 || integer_to>2106) {
1159 SPRINT(failure, "Given year '%d' not in range 1970..2106", integer_to);
1164 cond->integer_value = integer;
1165 cond->integer_value_to = integer_to;
1166 cond->value_type = value_type;
1169 /* parse all string values/ranges */
1170 case COND_TYPE_STRING:
1171 key[0] = key_to[0] = '\0';
1172 if (*p==',' || *p==' ' || *p=='\0') {
1173 SPRINT(failure, "Missing string value, use \"\" for empty string.");
1176 p = read_string(p, key, sizeof(key), "-, ");
1177 if (key[0] == 1) { /* error */
1178 SPRINT(failure, "Parsing String failed: %s", key+1);
1181 value_type = VALUE_TYPE_STRING;
1184 if (*p==',' || *p==' ' || *p=='\0') {
1185 SPRINT(failure, "Missing string value, use \"\" for empty string.");
1188 p = read_string(p, key_to, sizeof(key_to), "-, ");
1189 if (key_to[0] == 1) { /* error */
1190 SPRINT(failure, "Parsing string failed: %s", key_to+1);
1193 value_type = VALUE_TYPE_STRING_RANGE;
1194 if (strlen(key) != strlen(key_to)) {
1195 SPRINT(failure, "Given range of strings \"%s\"-\"%s\" have unequal length.", key, key_to);
1198 if (key[0] == '\0') {
1199 SPRINT(failure, "Given range has no length.");
1204 cond->string_value = (char *)MALLOC(strlen(key)+1);
1206 UCPY(cond->string_value, key);
1207 if (value_type == VALUE_TYPE_STRING_RANGE) {
1208 cond->string_value_to = (char *)MALLOC(strlen(key_to)+1);
1210 UCPY(cond->string_value_to, key_to);
1211 cond->comp_string = strcmp(key, key_to);
1213 cond->value_type = value_type;
1216 /* parse service value */
1217 case COND_TYPE_CAPABILITY:
1218 if (!strncasecmp("speech", p, 6))
1219 cond->integer_value = INFO_BC_SPEECH;
1220 else if (!strncasecmp("audio", p, 5))
1221 cond->integer_value = INFO_BC_AUDIO;
1222 else if (!strncasecmp("video", p, 5))
1223 cond->integer_value = INFO_BC_VIDEO;
1224 else if (!strncasecmp("digital-restricted", p, 18))
1225 cond->integer_value = INFO_BC_DATARESTRICTED;
1226 else if (!strncasecmp("digital-unrestricted", p, 20))
1227 cond->integer_value = INFO_BC_DATAUNRESTRICTED;
1228 else if (!strncasecmp("digital-unrestricted-tones", p, 26))
1229 cond->integer_value = INFO_BC_DATAUNRESTRICTED_TONES;
1231 SPRINT(failure, "Given service type is invalid or misspelled.");
1234 cond->value_type = VALUE_TYPE_INTEGER;
1237 /* parse bmode value */
1238 case COND_TYPE_BMODE:
1239 if (!strncasecmp("transparent", p, 11))
1240 cond->integer_value = INFO_BMODE_CIRCUIT;
1241 else if (!strncasecmp("hdlc", p, 4))
1242 cond->integer_value = INFO_BMODE_PACKET;
1244 SPRINT(failure, "Given bchannel mode is invalid or misspelled.");
1247 cond->value_type = VALUE_TYPE_INTEGER;
1250 /* parse interface attribute <if>:<value> */
1251 case COND_TYPE_IFATTR:
1252 key[0] = key_to[0] = '\0';
1253 if (*p==':' || *p==',' || *p==' ' || *p=='\0') {
1254 SPRINT(failure, "Missing interface name.");
1257 p = read_string(p, key, sizeof(key), ":-, ");
1258 if (key[0] == 1) { /* error */
1259 SPRINT(failure, "Parsing interface failed: %s", key+1);
1263 SPRINT(failure, "Expeciting kolon to seperate value behind interface name.");
1267 while(*p>='0' && *p<='9') {
1270 if (*p!=',' && *p!=' ' && *p!='\0') {
1271 SPRINT(failure, "Invalid characters behind value.");
1274 value_type = VALUE_TYPE_STRING;
1279 SPRINT(failure, "Software error: COND_TYPE_* %d not parsed in function '%s'", cond_defs[index].type, __FUNCTION__);
1282 /* if we have another value for that item, we attach it */
1286 cond->value_extension = 1;
1289 /* to seperate the items, a space is required */
1291 SPRINT(failure, "Character '%c' not expected here. Use ',' to seperate multiple possible values.", *p);
1303 /* we are done with CONDITIONS, so we expect the ACTION */
1305 SPRINT(failure, "Expecting ':' after condition item(s).");
1311 /* skip spaces, if any */
1319 /* read action name */
1321 while((*p>='a' && *p<='z') || (*p>='A' && *p<='Z') || (*p>='0' && *p<='9') || *p == '-') {
1322 if (*p>='A' && *p<='Z') *p = *p-'A'+'a'; /* lower case */
1324 if (i == sizeof(key)) i--; /* limit */
1327 if (key[0] == '\0') {
1328 SPRINT(failure, "Expecting action name.");
1332 /* check if item exists */
1334 while(action_defs[index].name) {
1335 if (!action_defs[index].help) { /* not internal actions */
1339 if (!strcmp(action_defs[index].name, key))
1343 if (action_defs[index].name == NULL) {
1344 SPRINT(failure, "Unknown action name '%s'.", key);
1347 allowed_params = action_defs[index].params;
1349 /* alloc memory for action */
1350 action = (struct route_action *)MALLOC(sizeof(struct route_action));
1352 *action_pointer = action;
1353 action_pointer = &(action->next);
1354 param_pointer = &(action->param_first);
1355 action->index = index;
1356 action->line = line[nesting];
1358 /* skip spaces after param name */
1368 /* read param text */
1370 while((*p>='a' && *p<='z') || (*p>='A' && *p<='Z') || (*p>='0' && *p<='9')) {
1371 if (*p>='A' && *p<='Z') *p = *p-'A'+'a'; /* lower case */
1373 if (i == sizeof(key)) i--; /* limit */
1376 if (key[0] == '\0') {
1377 SPRINT(failure, "Expecting parameter name.");
1381 /* check if item exists */
1383 while(param_defs[index].name) {
1384 if (!strcmp(param_defs[index].name, key))
1388 if (param_defs[index].name == NULL) {
1389 SPRINT(failure, "Unknown param name '%s'.", key);
1393 /* check if item is allowed for the action */
1394 if (!(param_defs[index].id & allowed_params)) {
1395 SPRINT(failure, "Param name '%s' exists, but not for this action.", key);
1399 /* params without values must not have any parameter */
1400 if (param_defs[index].type == PARAM_TYPE_NULL) {
1401 if (*p!=' ' && *p!='\0') {
1402 SPRINT(failure, "Parameter '%s' must not have any value.", key);
1407 SPRINT(failure, "Parameter '%s' must have at least one value, '=' expected and not a space.", key);
1411 SPRINT(failure, "Parameter '%s' must have at least one value, '=' expected.", key);
1417 /* special timeout value */
1418 if (!strcmp("timeout", key)) {
1419 if (action->timeout) {
1420 SPRINT(failure, "Duplicate timeout value.");
1423 if (*p==',' || *p==' ' || *p=='\0') {
1424 SPRINT(failure, "Missing integer value.");
1428 while(*p>='0' && *p<='9') {
1429 integer = integer*10 + *p-'0';
1433 SPRINT(failure, "Expecting timeout value greater 0.");
1436 if (*p!=' ' && *p!='\0') {
1437 SPRINT(failure, "Character '%c' not expected here. Use ' ' to seperate parameters.", *p);
1446 action->timeout = integer;
1447 /* check for next ACTION */
1455 /* check for duplicate parameters */
1456 param = action->param_first;
1458 if (param->index == index) {
1459 SPRINT(failure, "Duplicate parameter '%s', use ',' to give multiple values.", key);
1462 param = param->next;
1466 /* Alloc memory for param */
1467 param = (struct route_param *)MALLOC(sizeof(struct route_param));
1469 *param_pointer = param;
1470 param_pointer = &(param->next);
1471 param->index = index;
1472 param->id = param_defs[index].id;
1474 switch(param_defs[index].type) {
1475 /* parse null value */
1476 case PARAM_TYPE_NULL:
1477 param->value_type = VALUE_TYPE_NULL;
1480 /* parse integer value */
1481 case PARAM_TYPE_INTEGER:
1483 if (*p==',' || *p==' ' || *p=='\0') {
1484 SPRINT(failure, "Missing integer value.");
1487 while(*p>='0' && *p<='9') {
1488 integer = integer*10 + *p-'0';
1491 param->integer_value = integer;
1492 param->value_type = VALUE_TYPE_INTEGER;
1496 /* parse ports value */
1497 case PARAM_TYPE_PORTS:
1499 if (*p==',' || *p==' ' || *p=='\0') {
1500 SPRINT(failure, "Missing port number, omit parameter or give port number.");
1506 while(*p>='0' && *p<='9') {
1507 if (i < (int)sizeof(key)-1) {
1511 integer = integer*10 + *p-'0';
1514 if (integer > 255) {
1515 SPRINT(failure, "Port number too high.");
1519 if (i < (int)sizeof(key)-1) {
1529 /* parse string value */
1530 case PARAM_TYPE_STRING:
1531 case PARAM_TYPE_CALLERIDTYPE:
1532 case PARAM_TYPE_CAPABILITY:
1533 case PARAM_TYPE_BMODE:
1534 case PARAM_TYPE_DIVERSION:
1535 case PARAM_TYPE_DESTIN:
1536 case PARAM_TYPE_TYPE:
1537 case PARAM_TYPE_YESNO:
1540 if (*p==',' || *p==' ' || *p=='\0') {
1541 SPRINT(failure, "Missing string value, use \"\" for empty string.");
1544 p = read_string(p, key, sizeof(key), " ");
1545 if (key[0] == 1) { /* error */
1546 SPRINT(failure, "Parsing string failed: %s", key+1);
1549 if (param_defs[index].type == PARAM_TYPE_CALLERIDTYPE) {
1550 param->value_type = VALUE_TYPE_INTEGER;
1551 if (!strcasecmp(key, "unknown")) {
1552 param->integer_value = INFO_NTYPE_UNKNOWN;
1555 if (!strcasecmp(key, "subscriber")) {
1556 param->integer_value = INFO_NTYPE_SUBSCRIBER;
1559 if (!strcasecmp(key, "national")) {
1560 param->integer_value = INFO_NTYPE_NATIONAL;
1563 if (!strcasecmp(key, "international")) {
1564 param->integer_value = INFO_NTYPE_INTERNATIONAL;
1567 SPRINT(failure, "Caller ID type '%s' unknown.", key);
1570 if (param_defs[index].type == PARAM_TYPE_ON) {
1571 param->value_type = VALUE_TYPE_INTEGER;
1572 if (!strcasecmp(key, "init")) {
1573 param->integer_value = INFO_ON_INIT;
1576 if (!strcasecmp(key, "hangup")) {
1577 param->integer_value = INFO_ON_HANGUP;
1580 SPRINT(failure, "Execute on '%s' unknown.", key);
1583 if (param_defs[index].type == PARAM_TYPE_CAPABILITY) {
1584 param->value_type = VALUE_TYPE_INTEGER;
1585 if (!strcasecmp(key, "speech")) {
1586 param->integer_value = INFO_BC_SPEECH;
1589 if (!strcasecmp(key, "audio")) {
1590 param->integer_value = INFO_BC_AUDIO;
1593 if (!strcasecmp(key, "video")) {
1594 param->integer_value = INFO_BC_VIDEO;
1597 if (!strcasecmp(key, "digital-restricted")) {
1598 param->integer_value = INFO_BC_DATARESTRICTED;
1601 if (!strcasecmp(key, "digital-unrestricted")) {
1602 param->integer_value = INFO_BC_DATAUNRESTRICTED;
1605 if (!strcasecmp(key, "digital-unrestricted-tones")) {
1606 param->integer_value = INFO_BC_DATAUNRESTRICTED_TONES;
1609 SPRINT(failure, "Service type '%s' unknown.", key);
1612 if (param_defs[index].type == PARAM_TYPE_BMODE) {
1613 param->value_type = VALUE_TYPE_INTEGER;
1614 if (!strcasecmp(key, "transparent")) {
1615 param->integer_value = INFO_BMODE_CIRCUIT;
1618 if (!strcasecmp(key, "hdlc")) {
1619 param->integer_value = INFO_BMODE_PACKET;
1622 SPRINT(failure, "Bchannel mode '%s' unknown.", key);
1625 if (param_defs[index].type == PARAM_TYPE_DIVERSION) {
1626 param->value_type = VALUE_TYPE_INTEGER;
1627 if (!strcasecmp(key, "cfu")) {
1628 param->integer_value = INFO_DIVERSION_CFU;
1631 if (!strcasecmp(key, "cfb")) {
1632 param->integer_value = INFO_DIVERSION_CFB;
1635 if (!strcasecmp(key, "cfnr")) {
1636 param->integer_value = INFO_DIVERSION_CFNR;
1639 if (!strcasecmp(key, "cfp")) {
1640 param->integer_value = INFO_DIVERSION_CFP;
1643 SPRINT(failure, "Diversion type '%s' unknown.", key);
1646 if (param_defs[index].type == PARAM_TYPE_TYPE) {
1647 param->value_type = VALUE_TYPE_INTEGER;
1648 if (!strcasecmp(key, "unknown")) {
1649 param->integer_value = INFO_NTYPE_UNKNOWN;
1652 if (!strcasecmp(key, "subscriber")) {
1653 param->integer_value = INFO_NTYPE_SUBSCRIBER;
1656 if (!strcasecmp(key, "national")) {
1657 param->integer_value = INFO_NTYPE_NATIONAL;
1660 if (!strcasecmp(key, "international")) {
1661 param->integer_value = INFO_NTYPE_INTERNATIONAL;
1664 SPRINT(failure, "Number type '%s' unknown.", key);
1667 if (param_defs[index].type == PARAM_TYPE_YESNO) {
1668 param->value_type = VALUE_TYPE_INTEGER;
1669 if (!strcasecmp(key, "yes")) {
1670 param->integer_value = 1;
1673 if (!strcasecmp(key, "no")) {
1674 param->integer_value = 0;
1677 SPRINT(failure, "Value '%s' unknown. ('yes' or 'no')", key);
1680 param->string_value = (char *)MALLOC(strlen(key)+1);
1682 UCPY(param->string_value, key);
1683 param->value_type = VALUE_TYPE_STRING;
1687 SPRINT(failure, "Software error: PARAM_TYPE_* %d not parsed in function '%s'", param_defs[index].type, __FUNCTION__);
1694 param->value_extension = 1;
1695 goto nextparamvalue;
1702 /* to seperate the items, a space is required */
1704 SPRINT(failure, "Character '%c' not expected here. Use ' ' to seperate parameters, or ',' for multiple values.", *p);
1715 /* check for next ACTION */
1723 fclose(fp[nesting--]);
1729 if (!ruleset_start) {
1730 SPRINT(failure, "No ruleset defined.");
1732 return(ruleset_start);
1735 printf("While parsing %s, an error occurred in line %d:\n", filename[nesting], line[nesting]);
1736 printf("-> %s\n", buffer);
1737 memset(pointer, ' ', sizeof(pointer));
1738 pointer[p-buffer] = '^';
1739 pointer[p-buffer+1] = '\0';
1740 printf(" %s\n", pointer);
1741 printf("%s\n", failure);
1742 SPRINT(ruleset_error, "Error in file %s, line %d: %s", filename[nesting], line[nesting], failure);
1745 while(nesting >= 0) {
1746 fclose(fp[nesting--]);
1750 ruleset_free(ruleset_start);
1755 * return ruleset by name
1757 struct route_ruleset *getrulesetbyname(const char *name)
1759 struct route_ruleset *ruleset = ruleset_first;
1762 if (!strcasecmp(name, ruleset->name)) {
1765 ruleset = ruleset->next;
1767 PDEBUG(DEBUG_ROUTE, "ruleset %s %s.\n", name, ruleset?"found":"not found");
1772 * parses the current ruleset and returns action
1774 struct route_action *EndpointAppPBX::route(struct route_ruleset *ruleset)
1777 couldmatch = 0, /* any rule could match */
1784 struct route_rule *rule = ruleset->rule_first;
1785 struct route_cond *cond;
1786 struct route_action *action = NULL;
1787 unsigned long comp_len;
1789 char callerid[64], callerid2[64], redirid[64];
1794 struct mISDNport *mISDNport;
1795 struct admin_list *admin;
1797 /* reset timeout action */
1798 e_match_timeout = 0; /* no timeout */
1799 e_match_to_action = NULL;
1801 SCPY(callerid, numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype, options.national, options.international));
1802 SCPY(callerid2, numberrize_callerinfo(e_callerinfo.id2, e_callerinfo.ntype2, options.national, options.international));
1803 SCPY(redirid, numberrize_callerinfo(e_redirinfo.id, e_redirinfo.ntype, options.national, options.international));
1805 PDEBUG(DEBUG_ROUTE, "parsing ruleset '%s'\n", ruleset->name);
1807 PDEBUG(DEBUG_ROUTE, "checking rule in line %d\n", rule->line);
1808 match = 1; /* this rule matches */
1809 dialing_required = 0;
1810 timeout = 0; /* timeout time */
1811 cond = rule->cond_first;
1813 condition = 0; /* any condition element is true (1) or could be true (2) */
1815 istrue = 0; /* this condition-element is true */
1816 couldbetrue = 0; /* this conditions-element could be true */
1817 switch(cond->match) {
1819 if (!e_ext.number[0])
1824 if (e_ext.number[0])
1829 if (ea_endpoint->ep_portlist)
1830 if ((ea_endpoint->ep_portlist->port_type & PORT_CLASS_MASK) != PORT_CLASS_mISDN)
1832 integer = e_callerinfo.isdn_port;
1835 case MATCH_INTERFACE:
1836 if (!e_callerinfo.interface[0])
1838 string = e_callerinfo.interface;
1839 goto match_string_prefix;
1841 case MATCH_CALLERID:
1843 goto match_string_prefix;
1845 case MATCH_CALLERID2:
1847 goto match_string_prefix;
1849 case MATCH_EXTENSION:
1850 string = e_ext.name;
1854 string = e_dialinginfo.id;
1855 goto match_string_prefix;
1867 case MATCH_ANONYMOUS:
1868 if (e_callerinfo.present != INFO_PRESENT_ALLOWED)
1873 if (e_callerinfo.present == INFO_PRESENT_ALLOWED)
1878 if (e_callerinfo.present == INFO_PRESENT_NOTAVAIL)
1882 case MATCH_AVAILABLE:
1883 if (e_callerinfo.present != INFO_PRESENT_NOTAVAIL)
1888 if (e_callerinfo.screen == INFO_SCREEN_USER)
1893 if (e_callerinfo.screen != INFO_SCREEN_USER)
1897 case MATCH_REDIRECTED:
1898 if (e_redirinfo.ntype != INFO_NTYPE_NOTPRESENT)
1903 if (e_redirinfo.ntype == INFO_NTYPE_NOTPRESENT)
1909 goto match_string_prefix;
1912 integer = now_tm->tm_hour*100 + now_tm->tm_min;
1916 integer = now_tm->tm_mday;
1920 integer = now_tm->tm_mon+1;
1924 integer = now_tm->tm_year + 1900;
1928 integer = now_tm->tm_wday;
1929 integer = integer?integer:7; /* correct sunday */
1932 case MATCH_CAPABILITY:
1933 integer = e_capainfo.bearer_capa;
1936 case MATCH_INFOLAYER1:
1937 integer = e_capainfo.bearer_info1;
1941 integer = e_capainfo.hlc;
1945 tfp = fopen(cond->string_value, "r");
1949 if (fgetc(tfp) == '1')
1955 if (system(cond->string_value) == 0)
1965 timeout = now_d + cond->integer_value;
1971 if (!(comp_len = (unsigned long)strchr(cond->string_value, ':')))
1973 comp_len = comp_len-(unsigned long)cond->string_value;
1975 mISDNport = mISDNport_first;
1977 if (mISDNport->ifport)
1978 if (strlen(mISDNport->ifport->interface->name) == comp_len)
1979 if (!strncasecmp(mISDNport->ifport->interface->name, cond->string_value, comp_len))
1980 if (!mISDNport->l2hold || mISDNport->l2link>0) {
1982 jj = mISDNport->b_num;
1985 if (mISDNport->b_state[j])
1990 mISDNport = mISDNport->next;
1992 if (cond->match == MATCH_FREE) {
1993 if (avail >= atoi(cond->string_value + comp_len + 1))
1996 if (avail < atoi(cond->string_value + comp_len + 1))
2003 mISDNport = mISDNport_first;
2005 if (mISDNport->ifport)
2006 if (!strcasecmp(mISDNport->ifport->interface->name, cond->string_value))
2007 if (!mISDNport->l2hold || mISDNport->l2link>0)
2009 mISDNport = mISDNport->next;
2011 if (!mISDNport) /* all down */
2016 mISDNport = mISDNport_first;
2018 if (mISDNport->ifport)
2019 if (!strcasecmp(mISDNport->ifport->interface->name, cond->string_value))
2020 if (!mISDNport->l2hold || mISDNport->l2link>0)
2023 mISDNport = mISDNport->next;
2025 if (mISDNport) /* one link at least */
2032 mISDNport = mISDNport_first;
2034 if (mISDNport->ifport)
2035 if (!strcasecmp(mISDNport->ifport->interface->name, cond->string_value))
2036 if (mISDNport->use) /* break if in use */
2038 mISDNport = mISDNport->next;
2040 if (mISDNport && cond->match==MATCH_BUSY)
2042 if (!mISDNport && cond->match==MATCH_IDLE)
2047 case MATCH_NOTREMOTE:
2048 admin = admin_first;
2050 if (admin->remote_name[0] && !strcmp(cond->string_value, admin->remote_name))
2052 admin = admin->next;
2054 if (admin && cond->match==MATCH_REMOTE)
2056 if (!admin && cond->match==MATCH_NOTREMOTE)
2061 PERROR("Software error: MATCH_* %d not parsed in function '%s'", cond->match, __FUNCTION__);
2065 if (cond->value_type == VALUE_TYPE_INTEGER) {
2066 if (integer != cond->integer_value)
2071 if (cond->value_type == VALUE_TYPE_INTEGER_RANGE) {
2072 /* check if negative range (2100 - 700 o'clock) */
2073 if (cond->integer_value > cond->integer_value_to) {
2074 if (integer>=cond->integer_value && integer<=cond->integer_value_to)
2078 /* range is positive */
2079 if (integer>=cond->integer_value && integer<=cond->integer_value_to)
2086 if (strlen(cond->string_value) != strlen(string))
2089 match_string_prefix:
2090 comp_len = strlen(cond->string_value); /* because we must reach value's length */
2091 /* we must have greater or equal length to values */
2092 if ((unsigned long)strlen(string) < comp_len) {
2093 /* special case for unfinished dialing */
2094 if (cond->match == MATCH_DIALING) {
2095 couldbetrue = 1; /* could match */
2096 comp_len = strlen(string);
2101 /* on single string match */
2102 if (cond->value_type == VALUE_TYPE_STRING) {
2103 if (!strncmp(string, cond->string_value, comp_len)) {
2105 /* must be set for changing 'e_extdialing' */
2106 if (cond->match == MATCH_DIALING)
2107 dialing_required = comp_len;
2112 /* on range match */
2113 if (cond->value_type == VALUE_TYPE_STRING_RANGE) {
2114 /* check if negative range ("55"-"22") */
2115 if (cond->comp_string > 0) {
2116 if (strncmp(string, cond->string_value, comp_len) >= 0) {
2118 /* must be set for changing 'e_extdialing' */
2119 if (cond->match == MATCH_DIALING)
2120 dialing_required = comp_len;
2123 if (strncmp(string, cond->string_value_to, comp_len) <= 0) {
2124 /* must be set for changing 'e_extdialing' */
2126 if (cond->match == MATCH_DIALING)
2127 dialing_required = comp_len;
2132 /* range is positive */
2133 if (strncmp(string, cond->string_value, comp_len) < 0)
2135 if (strncmp(string, cond->string_value_to, comp_len) > 0)
2138 if (cond->match == MATCH_DIALING)
2139 dialing_required = comp_len;
2145 /* set current condition */
2146 if (istrue && !couldbetrue)
2147 condition = 1; /* element matches, so condition matches */
2148 if (istrue && couldbetrue && !condition)
2149 condition = 2; /* element could match and other elements don't match, so condition could match */
2151 /* if not matching or could match */
2152 if (condition != 1) {
2153 /* if we have more values to check */
2154 if (cond->value_extension && cond->next) {
2156 goto checkextension;
2162 /* skip exteded values, beacuse we already have one matching value */
2163 while(cond->value_extension && cond->next)
2168 if (timeout>now_d && match==1) /* the matching rule with timeout in the future */
2169 if (e_match_timeout<1 || timeout<e_match_timeout) { /* first timeout or lower */
2170 /* set timeout in the furture */
2171 e_match_timeout = timeout;
2172 e_match_to_action = rule->action_first;
2173 e_match_to_extdialing = e_dialinginfo.id + dialing_required;
2174 match = 0; /* matches in the future */
2177 /* matching, we return first action */
2178 action = rule->action_first;
2179 e_match_timeout = 0; /* no timeout */
2180 e_match_to_action = NULL;
2181 e_extdialing = e_dialinginfo.id + dialing_required;
2185 /* rule could match if more is dialed */
2194 * parses the current action's parameters and return them
2196 struct route_param *EndpointAppPBX::routeparam(struct route_action *action, unsigned long long id)
2198 struct route_param *param = action->param_first;
2201 if (param->id == id)
2203 param = param->next;
2210 * internal rules that are not defined by route.conf
2212 struct route_action action_password = {
2220 struct route_action action_password_write = {
2223 ACTION_PASSWORD_WRITE,
2228 struct route_action action_external = {
2236 struct route_action action_internal = {
2244 struct route_action action_remote = {
2252 struct route_action action_vbox = {
2260 struct route_action action_partyline = {
2268 struct route_action action_disconnect = {