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 { "extension", MATCH_EXTENSION,COND_TYPE_STRING,
30 "extension=<digits>[-<digits>][,...]", "Matches if caller calls from given (range(s) of) extension(s)."},
31 { "dialing", MATCH_DIALING, COND_TYPE_STRING,
32 "dialing=<digits>[-<digits>][,...]", "Matches if caller has dialed the given (range(s) of) digits at least."},
33 { "enblock", MATCH_ENBLOCK, COND_TYPE_NULL,
34 "enblock", "Matches if caller dialed en block. (Dial the number before pick up.)"},
35 { "overlap", MATCH_OVERLAP, COND_TYPE_NULL,
36 "overlap", "Matches if caller dialed digit by digit. (Dial the number after pick up.)"},
37 { "anonymous", MATCH_ANONYMOUS,COND_TYPE_NULL,
38 "anonymous", "Matches if caller uses restricted caller ID or if not available."},
39 { "visible", MATCH_VISIBLE, COND_TYPE_NULL,
40 "visible", "Matches if caller ID is presented and if available."},
41 { "unknown", MATCH_UNKNOWN, COND_TYPE_NULL,
42 "unknown", "Matches if no ID is available from caller."},
43 { "available", MATCH_AVAILABLE,COND_TYPE_NULL,
44 "available", "Matches if ID is available from caller."},
45 { "fake", MATCH_FAKE, COND_TYPE_NULL,
46 "fake", "Matches if caller ID is not screened and may be faked by caller."},
47 { "real", MATCH_REAL, COND_TYPE_NULL,
48 "real", "Matches if caller ID is screend and so it is the real caller's ID."},
49 { "redirected", MATCH_REDIRECTED,COND_TYPE_NULL,
50 "redirected", "Matches if caller has been redirected."},
51 { "direct", MATCH_DIRECT ,COND_TYPE_NULL,
52 "direct", "Matches if caller did not come from an redirection."},
53 { "redirid", MATCH_REDIRID ,COND_TYPE_STRING,
54 "redirid=<digits>[-<digits>][,...]", "Matches if the caller has been redirected by the given (range(s) of) ID(s) or prefix(es))"},
55 { "time", MATCH_TIME, COND_TYPE_TIME,
56 "time=<minutes>[-<minutes>][,...]", "Matches if the caller calls within the given (range(s) of) time(s). (e.g. 0700-1900)"},
57 { "mday", MATCH_MDAY, COND_TYPE_MDAY,
58 "mday=<day>[-<day>][,...]", "Matches if the caller calls within the given (range(s) of) day(s) of the month. (1..31)"},
59 { "month", MATCH_MONTH, COND_TYPE_MONTH,
60 "month=<month>[-<month>][,...]", "Matches if the caller calls within the given (range(s) of) month(s). (1=January..12=December)"},
61 { "year", MATCH_YEAR, COND_TYPE_YEAR,
62 "year=<year>[-<year>][,...]", "Matches if the caller calls within the given (range(s) of) year(s). (1970..2106)"},
63 { "wday", MATCH_WDAY, COND_TYPE_WDAY,
64 "wday=<day>[-<day>][,...]", "Matches if the caller calls within the given (range(s) of) weekday(s). (1=Monday..7=Sunday)"},
65 { "capability", MATCH_CAPABILITY, COND_TYPE_CAPABILITY,
66 "capability=speech|audio|video|digital-restricted|digital-unrestricted|digital-unrestricted-tones[,...]", "Matches the given bearer capability(s)."},
67 { "infolayer1", MATCH_INFOLAYER1, COND_TYPE_INTEGER,
68 "infolayer1=<value>[,...]", "Matches the given information layer 1. (2=u-Law, 3=a-law, see info layer 1 in bearer capability.)"},
69 { "hlc", MATCH_HLC, COND_TYPE_INTEGER,
70 "hlc=<value>[,...]", "Matches the high layer capability(s)."},
71 { "file", MATCH_FILE, COND_TYPE_STRING,
72 "file=<path>[,...]", "Mathes is the given file exists and if the first character is '1'."},
73 { "execute", MATCH_EXECUTE, COND_TYPE_STRING,
74 "execute=<command>[,...]","Matches if the return value of the given command is greater 0."},
75 { "default", MATCH_DEFAULT, COND_TYPE_NULL,
76 "default","Matches if no further dialing could match."},
77 { "timeout", MATCH_TIMEOUT, COND_TYPE_INTEGER,
78 "timeout=<seconds>","Matches if the ruleset was entered AFTER given seconds."},
79 { "free", MATCH_FREE, COND_TYPE_IFATTR,
80 "free=<interface>:<channel>","Matches if the given minimum of channels are free."},
81 { "notfree", MATCH_NOTFREE, COND_TYPE_IFATTR,
82 "notfree=<interface>:<channel>","Matches if NOT the given minimum of channels are free."},
83 { "blocked", MATCH_DOWN, COND_TYPE_STRING,
84 "blocked=<interfaces>[,...]","Matches if all of the given interfaces are blocked."},
85 { "idle", MATCH_UP, COND_TYPE_STRING,
86 "idle=<interface>[,...]","Matches if any of the given interfaces is idle."},
87 { "busy", MATCH_BUSY, COND_TYPE_STRING,
88 "busy=<extension>[,...]","Matches if any of the given extension is busy."},
89 { "notbusy", MATCH_IDLE, COND_TYPE_STRING,
90 "notbusy=<extension>[,...]","Matches if any of the given extension is not busy."},
91 { "remote", MATCH_REMOTE, COND_TYPE_STRING,
92 "remote=<application name>","Matches if remote application is running."},
93 { "notremote", MATCH_NOTREMOTE,COND_TYPE_STRING,
94 "notremote=<application name>","Matches if remote application is not running."},
98 struct param_defs param_defs[] = {
100 "proceeding", PARAM_TYPE_NULL,
101 "proceeding", "Will set the call into 'proceeding' state to prevent dial timeout."},
103 "alerting", PARAM_TYPE_NULL,
104 "alerting", "Will set the call into 'altering' state."},
106 "connect", PARAM_TYPE_NULL,
107 "connect", "Will complete the call before processing the action. Audio path for external calls will be established."},
109 "extension", PARAM_TYPE_STRING,
110 "extension=<digits>", "Give extension name (digits) to relate this action to."},
112 "extensions", PARAM_TYPE_STRING,
113 "extensions=<extension>[,<extension>[,...]]", "One or more extensions may be given."},
115 "prefix", PARAM_TYPE_STRING,
116 "prefix=<digits>", "Add prefix in front of the dialed number."},
118 "capability", PARAM_TYPE_CAPABILITY,
119 "capability=speech|audio|video|digital-restricted|digital-unrestricted|digital-unrestricted-tones", "Alter the service type of the call."},
121 "bmode", PARAM_TYPE_BMODE,
122 "bmode=transparent|hdlc", "Alter the bchannel mode of the call. Use hdlc for data calls."},
124 "infolayer1", PARAM_TYPE_INTEGER,
125 "infolayer1=<value>", "Alter the layer 1 information of a call. Use 3 for ALAW or 2 for uLAW."},
127 "hlc", PARAM_TYPE_INTEGER,
128 "hlc=<value>", "Alter the HLC identification. Use 1 for telephony or omit."},
130 "exthlc", PARAM_TYPE_INTEGER,
131 "exthlc=<value>", "Alter extended HLC value. (Mainenance only, don't use it.)"},
133 "present", PARAM_TYPE_YESNO,
134 "present=yes|no", "Allow or restrict caller ID regardless what the caller wants."},
136 "diversion", PARAM_TYPE_DIVERSION,
137 "diversion=cfu|cfnr|cfb|cfp", "Set diversion type."},
139 "dest", PARAM_TYPE_DESTIN,
140 "dest=<string>", "Destination number to divert to. Use 'vbox' to divert to vbox. (cfu,cfnr,cfb only)"},
142 "select", PARAM_TYPE_NULL,
143 "select", "Lets the caller select the history of calls using keys '1'/'3' or '*'/'#'."},
145 "delay", PARAM_TYPE_INTEGER,
146 "delay=<seconds>", "Number of seconds to delay."},
148 "limit", PARAM_TYPE_INTEGER,
149 "limit=<retries>", "Number of maximum retries."},
151 "host", PARAM_TYPE_STRING,
152 "host=<string>", "Name of remote VoIP host."},
154 "port", PARAM_TYPE_STRING,
155 "port=<value>", "Alternate port to use if 'host' is given."},
157 "interfaces", PARAM_TYPE_STRING,
158 "interfaces=<interface>[,<interface>[,...]]", "Give one or a list of Interfaces to select a free channel from."},
160 "address", PARAM_TYPE_STRING,
161 "address=<string>", "Complete VoIP address. ( [user@]host[:port] )"},
163 "sample", PARAM_TYPE_STRING,
164 "sample=<file prefix>", "Filename of sample (current tone's dir) or full path to sample. ('.wav'/'.wave'/'.isdn' is added automatically."},
165 { PARAM_ANNOUNCEMENT,
166 "announcement",PARAM_TYPE_STRING,
167 "announcement=<file prefix>", "Filename of announcement (inside vbox recording dir) or full path to sample. ('.wav'/'.wave'/'.isdn' is added automatically."},
169 "ruleset", PARAM_TYPE_STRING,
170 "ruleset=<name>", "Ruleset to go to."},
172 "cause", PARAM_TYPE_INTEGER,
173 "cause=<cause value>", "Cause value when disconnecting. (21=reject 1=unassigned 63=service not available)"},
175 "location", PARAM_TYPE_INTEGER,
176 "location=<location value>", "Location of cause value when disconnecting. (0=user 1=private network sering local user)"},
178 "display", PARAM_TYPE_STRING,
179 "display=<text>", "Message to display on the caller's telephone. (internal only)"},
181 "ports", PARAM_TYPE_INTEGER,
182 "ports=<port>[,<port>[,...]]", "ISDN port[s] to use."},
184 "tpreset", PARAM_TYPE_INTEGER,
185 "tpreset=<seconds>", "Preset of countdown timer."},
187 "file", PARAM_TYPE_STRING,
188 "file=<full path>", "Full path to file name."},
190 "content", PARAM_TYPE_STRING,
191 "content=<string>", "Content to write into file."},
193 "append", PARAM_TYPE_NULL,
194 "append", "Will append to given file, rather than overwriting it."},
196 "execute", PARAM_TYPE_STRING,
197 "execute=<full path>", "Full path to script/command name. (Dialed digits are the argument 1.)"},
199 "param", PARAM_TYPE_STRING,
200 "param=<string>", "Optionally this parameter can be inserted as argument 1, others are shifted."},
202 "type", PARAM_TYPE_TYPE,
203 "type=unknown|subscriber|national|international", "Type of number to dial, default is 'unknown'."},
205 "complete", PARAM_TYPE_NULL,
206 "complete", "Indicates complete number as given by prefix. Proceeding of long distance calls may be faster."},
208 "callerid", PARAM_TYPE_STRING,
209 "callerid=<digits>", "Change caller ID to given string."},
210 { PARAM_CALLERIDTYPE,
211 "calleridtype",PARAM_TYPE_CALLERIDTYPE,
212 "calleridtype=[unknown|subscriber|national|international]", "Type of caller ID. For normal MSN use 'unknown'"},
214 "callto", PARAM_TYPE_STRING,
215 "callto=<digits>", "Where to call back. By default the caller ID is used."},
217 "room", PARAM_TYPE_INTEGER,
218 "room=<digits>", "Conference room number, must be greater 0, as in real life."},
220 "jingle", PARAM_TYPE_NULL,
221 "jingle", "Conference members will hear a jingle if a member joins."},
223 "timeout", PARAM_TYPE_INTEGER,
224 "timeout=<seconds>", "Timeout before continue with next action."},
226 "nopassword", PARAM_TYPE_NULL,
227 "nopassword", "Don't ask for password. Be sure to authenticate right via real caller ID."},
229 "strip", PARAM_TYPE_NULL,
230 "strip", "Remove digits that were required to match this rule."},
232 "application",PARAM_TYPE_STRING,
233 "application=<name>", "Name of remote application to make call to."},
235 "context", PARAM_TYPE_STRING,
236 "context=<context>", "Give context parameter to the remote application."},
238 "exten", PARAM_TYPE_STRING,
239 "exten=<extension>", "Give exten parameter to the remote application. (overrides dialed number)"},
240 { 0, NULL, 0, NULL, NULL}
243 struct action_defs action_defs[] = {
245 "extern", &EndpointAppPBX::action_init_call, &EndpointAppPBX::action_dialing_external, &EndpointAppPBX::action_hangup_call,
246 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,
247 "Call is routed to extern number as dialed."},
249 "intern", &EndpointAppPBX::action_init_call, &EndpointAppPBX::action_dialing_internal, &EndpointAppPBX::action_hangup_call,
250 PARAM_CONNECT | PARAM_EXTENSION | PARAM_TYPE | PARAM_CAPA | PARAM_BMODE | PARAM_INFO1 | PARAM_HLC | PARAM_EXTHLC | PARAM_PRESENT | PARAM_TIMEOUT,
251 "Call is routed to intern extension as given by the dialed number or specified by option."},
253 "outdial", &EndpointAppPBX::action_init_call, &EndpointAppPBX::action_dialing_external, &EndpointAppPBX::action_hangup_call,
254 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,
257 "remote", &EndpointAppPBX::action_init_remote, &EndpointAppPBX::action_dialing_remote, &EndpointAppPBX::action_hangup_call,
258 PARAM_CONNECT | PARAM_APPLICATION | PARAM_CONTEXT | PARAM_EXTEN | PARAM_TIMEOUT,
259 "Call is routed to Remote application, like Asterisk."},
260 { ACTION_VBOX_RECORD,
261 "vbox-record",&EndpointAppPBX::action_init_call, &EndpointAppPBX::action_dialing_vbox_record, &EndpointAppPBX::action_hangup_call,
262 PARAM_CONNECT | PARAM_EXTENSION | PARAM_ANNOUNCEMENT | PARAM_TIMEOUT,
263 "Caller is routed to the voice box of given extension."},
265 "partyline",&EndpointAppPBX::action_init_partyline, NULL, &EndpointAppPBX::action_hangup_call,
266 PARAM_ROOM | PARAM_JINGLE,
267 "Caller is participating the conference with the given room number."},
269 "login", NULL, &EndpointAppPBX::action_dialing_login, NULL,
270 PARAM_CONNECT | PARAM_EXTENSION | PARAM_NOPASSWORD,
271 "Log into the given extension. Password required."},
273 "callerid", &EndpointAppPBX::action_init_change_callerid, &EndpointAppPBX::action_dialing_callerid, NULL,
274 PARAM_CONNECT | PARAM_CALLERID | PARAM_CALLERIDTYPE | PARAM_PRESENT,
275 "Caller changes the caller ID for all calls."},
276 { ACTION_CALLERIDNEXT,
277 "calleridnext",&EndpointAppPBX::action_init_change_callerid, &EndpointAppPBX::action_dialing_calleridnext, NULL,
278 PARAM_CONNECT | PARAM_CALLERID | PARAM_CALLERIDTYPE | PARAM_PRESENT,
279 "Caller changes the caller ID for the next call."},
281 "forward", &EndpointAppPBX::action_init_change_forward, &EndpointAppPBX::action_dialing_forward, NULL,
282 PARAM_CONNECT | PARAM_DIVERSION | PARAM_DEST | PARAM_DELAY,
283 "Caller changes the diversion of given type to the given destination or voice box."},
285 "redial", &EndpointAppPBX::action_init_redial_reply, &EndpointAppPBX::action_dialing_redial, NULL,
286 PARAM_CONNECT | PARAM_SELECT,
287 "Caller redials. (last outgoing call(s))"},
289 "reply", &EndpointAppPBX::action_init_redial_reply, &EndpointAppPBX::action_dialing_reply, NULL,
290 PARAM_CONNECT | PARAM_SELECT,
291 "Caller replies. (last incoming call(s))"},
293 "powerdial", NULL, &EndpointAppPBX::action_dialing_powerdial, NULL,
294 PARAM_CONNECT | PARAM_DELAY | PARAM_LIMIT | PARAM_TIMEOUT,
295 "Caller redials using powerdialing."},
297 "callback", NULL, &EndpointAppPBX::action_dialing_callback, &EndpointAppPBX::action_hangup_callback,
298 PARAM_PROCEEDING | PARAM_ALERTING | PARAM_CONNECT | PARAM_EXTENSION | PARAM_DELAY | PARAM_CALLTO | PARAM_PREFIX,
299 "Caller will use the callback service. After disconnecting, the callback is triggered."},
301 "abbrev", NULL, &EndpointAppPBX::action_dialing_abbrev, NULL,
303 "Caller dials abbreviation."},
305 "test", NULL, &EndpointAppPBX::action_dialing_test, NULL,
306 PARAM_CONNECT | PARAM_PREFIX | PARAM_TIMEOUT,
307 "Caller dials test mode."},
309 "play", &EndpointAppPBX::action_init_play, NULL, NULL,
310 PARAM_PROCEEDING | PARAM_ALERTING | PARAM_CONNECT | PARAM_SAMPLE | PARAM_TIMEOUT,
311 "Plays the given sample."},
313 "vbox-play", &EndpointAppPBX::action_init_vbox_play, &EndpointAppPBX::action_dialing_vbox_play, NULL,
315 "Caller listens to her voice box or to given extension."},
317 "calculator", NULL, &EndpointAppPBX::action_dialing_calculator, NULL,
319 "Caller calls the calculator."},
321 "timer", NULL, &EndpointAppPBX::action_dialing_timer, NULL,
322 PARAM_CONNECT | PARAM_TPRESET | PARAM_TIMEOUT,
324 // "Caller calls the timer."},
326 "goto", NULL, &EndpointAppPBX::action_dialing_goto, NULL,
327 PARAM_CONNECT | PARAM_RULESET | PARAM_STRIP | PARAM_SAMPLE,
328 "Jump to given ruleset and optionally play sample. Dialed digits are not flushed."},
330 "menu", NULL, &EndpointAppPBX::action_dialing_menu, NULL,
331 PARAM_CONNECT | PARAM_RULESET | PARAM_SAMPLE,
332 "Same as 'goto', but flushes all digits dialed so far."},
334 "disconnect", NULL, &EndpointAppPBX::action_dialing_disconnect, NULL,
335 PARAM_CONNECT | PARAM_CAUSE | PARAM_LOCATION | PARAM_SAMPLE | PARAM_DISPLAY,
336 "Caller gets disconnected optionally with given cause and given sample and given display text."},
338 "deflect", NULL, &EndpointAppPBX::action_dialing_deflect, NULL,
341 // "External call is deflected to the given destination within the telephone network."},
343 "setforward", NULL, &EndpointAppPBX::action_dialing_setforward, NULL,
344 PARAM_CONNECT | PARAM_DIVERSION | PARAM_DEST | PARAM_PORT,
346 // "The call forward is set within the telephone network of the external line."},
348 "execute", NULL, NULL, &EndpointAppPBX::action_hangup_execute,
349 PARAM_CONNECT | PARAM_EXECUTE | PARAM_PARAM,
350 "Executes the given script file. The file must terminate quickly, because it will halt the PBX."},
352 "file", NULL, NULL, &EndpointAppPBX::action_hangup_file,
353 PARAM_CONNECT | PARAM_FILE | PARAM_CONTENT | PARAM_APPEND,
354 "Writes givent content to given file. If content is not given, the dialed digits are written."},
356 "pick", &EndpointAppPBX::action_init_pick, NULL, NULL,
358 "Pick up a call that is ringing on any phone. Extensions may be given to limit the picking ability."},
360 "password", NULL, &EndpointAppPBX::action_dialing_password, NULL,
363 { ACTION_PASSWORD_WRITE,
364 "password_wr",NULL, &EndpointAppPBX::action_dialing_password_wr, NULL,
368 "nothing", NULL, NULL, NULL,
369 PARAM_PROCEEDING | PARAM_ALERTING | PARAM_CONNECT | PARAM_TIMEOUT,
370 "does nothing. Usefull to wait for calls to be released completely, by giving timeout value."},
372 "efi", &EndpointAppPBX::action_init_efi, NULL, NULL,
373 PARAM_PROCEEDING | PARAM_ALERTING | PARAM_CONNECT,
374 "Elektronische Fernsprecher Identifikation - announces caller ID."},
376 NULL, NULL, NULL, NULL, 0, NULL}
380 /* display documentation of rules */
382 void doc_rules(const char *name)
389 while(action_defs[i].name)
391 if (!strcasecmp(action_defs[i].name, name))
395 if (!action_defs[i].name)
397 fprintf(stderr, "Given action '%s' unknown.\n", name);
400 name = action_defs[i].name;
403 printf("Syntax overview:\n");
404 printf("----------------\n\n");
405 printf("[ruleset]\n");
406 printf("<condition> ... : <action> [parameter ...] [timeout=X : <action> ...]\n");
408 printf("Please refer to the documentation for description on rule format.\n\n");
412 printf("Available conditions to match:\n");
413 printf("------------------------------\n\n");
415 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");
426 printf("Detailes parameter description of action:\n");
427 printf("-----------------------------------------\n\n");
430 while(action_defs[i].name)
432 if (name && !!strcmp(action_defs[i].name,name)) /* not selected */
437 if (!action_defs[i].help) /* not internal actions */
442 printf("Usage: %s", action_defs[i].name);
446 if ((1LL<<j) & action_defs[i].params)
447 printf(" [%s]", param_defs[j].doc);
450 printf("\n%s\n\n", action_defs[i].help);
451 if (name) /* only show parameter help for specific action */
456 if ((1LL<<j) & action_defs[i].params)
457 printf("%s:\n\t%s\n", param_defs[j].doc, param_defs[j].help);
466 void ruleset_free(struct route_ruleset *ruleset_start)
468 struct route_ruleset *ruleset;
469 struct route_rule *rule;
470 struct route_cond *cond;
471 struct route_action *action;
472 struct route_param *param;
476 ruleset = ruleset_start;
477 ruleset_start = ruleset->next;
478 while(ruleset->rule_first)
480 rule = ruleset->rule_first;
481 ruleset->rule_first = rule->next;
482 while(rule->cond_first)
484 cond = rule->cond_first;
485 if (cond->string_value)
487 FREE(cond->string_value, 0);
490 if (cond->string_value_to)
492 FREE(cond->string_value_to, 0);
495 rule->cond_first = cond->next;
496 FREE(cond, sizeof(struct route_cond));
499 while(rule->action_first)
501 action = rule->action_first;
502 rule->action_first = action->next;
503 while(action->param_first)
505 param = action->param_first;
506 action->param_first = param->next;
507 if (param->string_value)
509 FREE(param->string_value, 0);
512 FREE(param, sizeof(struct route_param));
515 FREE(action, sizeof(struct route_action));
518 FREE(rule, sizeof(struct route_rule));
521 FREE(ruleset, sizeof(struct route_ruleset));
526 void ruleset_debug(struct route_ruleset *ruleset_start)
528 struct route_ruleset *ruleset;
529 struct route_rule *rule;
530 struct route_cond *cond;
531 struct route_action *action;
532 struct route_param *param;
535 ruleset = ruleset_start;
538 printf("Ruleset: '%s'\n", ruleset->name);
539 rule = ruleset->rule_first;
544 cond = rule->cond_first;
548 printf(" Condition:");
552 printf(" %s", cond_defs[cond->index].name);
553 if (cond->value_type != VALUE_TYPE_NULL)
556 switch(cond->value_type)
558 case VALUE_TYPE_NULL:
561 case VALUE_TYPE_INTEGER:
562 printf("%d", cond->integer_value);
565 case VALUE_TYPE_INTEGER_RANGE:
566 printf("%d-%d", cond->integer_value, cond->integer_value_to);
569 case VALUE_TYPE_STRING:
570 printf("'%s'", cond->string_value);
573 case VALUE_TYPE_STRING_RANGE:
574 printf("'%s'-'%s'", cond->string_value, cond->string_value_to);
578 printf("Software error: VALUE_TYPE_* %d not known in function '%s' line=%d", cond->value_type, __FUNCTION__, __LINE__);
580 if (cond->value_extension && cond->next)
584 goto next_cond_value;
592 action = rule->action_first;
595 printf(" Action: %s\n", action_defs[action->index].name);
598 param = action->param_first;
606 printf(" %s", param_defs[param->index].name);
607 if (param->value_type != VALUE_TYPE_NULL)
609 switch(param->value_type)
611 case VALUE_TYPE_NULL:
614 case VALUE_TYPE_INTEGER:
615 if (param_defs[param->index].type == PARAM_TYPE_CALLERIDTYPE)
617 switch(param->integer_value)
619 case INFO_NTYPE_UNKNOWN:
622 case INFO_NTYPE_SUBSCRIBER:
623 printf("subscriber");
625 case INFO_NTYPE_NATIONAL:
628 case INFO_NTYPE_INTERNATIONAL:
629 printf("international");
632 printf("unknown(%d)", param->integer_value);
636 if (param_defs[param->index].type == PARAM_TYPE_CAPABILITY)
638 switch(param->integer_value)
649 case INFO_BC_DATARESTRICTED:
650 printf("digital-restricted");
652 case INFO_BC_DATAUNRESTRICTED:
653 printf("digital-unrestricted");
655 case INFO_BC_DATAUNRESTRICTED_TONES:
656 printf("digital-unrestricted-tones");
659 printf("unknown(%d)", param->integer_value);
663 if (param_defs[param->index].type == PARAM_TYPE_DIVERSION)
665 switch(param->integer_value)
667 case INFO_DIVERSION_CFU:
670 case INFO_DIVERSION_CFNR:
673 case INFO_DIVERSION_CFB:
676 case INFO_DIVERSION_CFP:
680 printf("unknown(%d)", param->integer_value);
684 if (param_defs[param->index].type == PARAM_TYPE_TYPE)
686 switch(param->integer_value)
688 case INFO_NTYPE_UNKNOWN:
691 case INFO_NTYPE_SUBSCRIBER:
692 printf("subscriber");
694 case INFO_NTYPE_NATIONAL:
697 case INFO_NTYPE_INTERNATIONAL:
698 printf("international");
701 printf("unknown(%d)", param->integer_value);
705 if (param_defs[param->index].type == PARAM_TYPE_YESNO)
707 switch(param->integer_value)
716 printf("unknown(%d)", param->integer_value);
720 if (param_defs[param->index].type == PARAM_TYPE_NULL)
724 printf("%d", param->integer_value);
727 case VALUE_TYPE_STRING:
728 printf("'%s'", param->string_value);
732 printf("Software error: VALUE_TYPE_* %d not known in function '%s' line=%d", param->value_type, __FUNCTION__, __LINE__);
739 printf(" Timeout: %d\n", action->timeout);
740 action = action->next;
746 ruleset = ruleset->next;
754 static char *read_string(char *p, char *key, int key_size, char *special)
780 UPRINT(key, "\001String too long.");
785 UPRINT(key, "\001Unexpected end of line inside quotes.");
792 if (strchr(special, *p))
802 UPRINT(key, "\001Unexpected end of line.");
808 UPRINT(key, "\001String too long.");
816 char ruleset_error[256];
817 struct route_ruleset *ruleset_parse(void)
822 unsigned long long j;
826 FILE *fp[MAXNESTING];
827 char filename[MAXNESTING][256];
828 int line[MAXNESTING];
835 int expecting = 1; /* 1 = expecting ruleset */
839 integer_to; /* condition index, .. */
840 struct route_ruleset *ruleset_start = NULL, *ruleset;
841 struct route_ruleset **ruleset_pointer = &ruleset_start;
842 struct route_rule *rule;
843 struct route_rule **rule_pointer = NULL;
844 struct route_cond *cond;
845 struct route_cond **cond_pointer = NULL;
846 struct route_action *action;
847 struct route_action **action_pointer = NULL;
848 struct route_param *param;
849 struct route_param **param_pointer = NULL;
851 unsigned long long allowed_params;
853 /* check the integrity of IDs for ACTION_* and PARAM_* */
855 while(action_defs[i].name)
857 if (action_defs[i].id != i)
859 PERROR("Software Error action '%s' must have id of %d, but has %d.\n",
860 action_defs[i].name, i, action_defs[i].id);
866 while(param_defs[i].name)
868 if (param_defs[i].id != j)
870 PERROR("Software Error param '%s' must have id of 0x%llx, but has 0x%llx.\n",
871 param_defs[i].name, j, param_defs[i].id);
878 SPRINT(filename[0], "%s/routing.conf", INSTALL_DATA);
880 if (!(fp[0]=fopen(filename[0],"r")))
882 PERROR("Cannot open %s\n",filename[0]);
891 while((fgets(buffer,sizeof(buffer),fp[nesting])))
894 buffer[sizeof(buffer)-1]=0;
895 if (buffer[0]) buffer[strlen(buffer)-1]=0;
906 /* skip spaces, if any */
918 /* don't skip "define" */
919 if (!!strncmp(p, "define", 6))
932 p = read_string(p, key, sizeof(key), " ");
933 if (key[0] == 1) /* error */
935 SPRINT(failure, "Parsing Filename failed: %s", key+1);
938 if (nesting == MAXNESTING-1)
940 SPRINT(failure, "'include' is nesting too deep.\n");
944 SCPY(filename[nesting+1], key);
946 SPRINT(filename[nesting+1], "%s/%s", INSTALL_DATA, key);
947 if (!(fp[nesting+1]=fopen(filename[nesting+1],"r")))
949 PERROR("Cannot open %s\n", filename[nesting+1]);
956 if (*p == '/') if (p[1] == '/')
959 /* skip empty lines */
963 /* expecting ruleset */
970 SPRINT(failure, "Expecting ruleset name starting with '['.");
975 /* reading ruleset name text */
977 while(*p>' ' && *p<127 && *p!=']')
979 if (*p>='A' && *p<='Z') *p = *p-'A'+'a'; /* lower case */
981 if (i == sizeof(key)) i--; /* limit */
984 if (key[0] == '\0') {
985 SPRINT(failure, "Missing ruleset name after '['.");
989 /* expecting ] and nothing more */
991 SPRINT(failure, "Expecting ']' after ruleset name.");
996 SPRINT(failure, "Unexpected character after ruleset name.");
1000 /* check for duplicate rulesets */
1001 ruleset = ruleset_start;
1004 if (!strcmp(ruleset->name, key))
1006 SPRINT(failure, "Duplicate ruleset '%s', already defined in file '%s' line %d.", key, ruleset->file, ruleset->line);
1009 ruleset = ruleset->next;
1012 /* create ruleset */
1013 ruleset = (struct route_ruleset *)MALLOC(sizeof(struct route_ruleset));
1015 *ruleset_pointer = ruleset;
1016 ruleset_pointer = &(ruleset->next);
1017 SCPY(ruleset->name, key);
1018 SCPY(ruleset->file, filename[nesting]);
1019 ruleset->line = line[nesting];
1020 rule_pointer = &(ruleset->rule_first);
1025 /* for new ruleset [ */
1031 /* Alloc memory for rule */
1032 rule = (struct route_rule *)MALLOC(sizeof(struct route_rule));
1034 *rule_pointer = rule;
1035 rule_pointer = &(rule->next);
1036 cond_pointer = &(rule->cond_first);
1037 action_pointer = &(rule->action_first);
1038 SCPY(rule->file, filename[nesting]);
1039 rule->line = line[nesting];
1041 /* loop CONDITIONS */
1042 while(*p!=':' && *p!='\0')
1044 /* read item text */
1046 while((*p>='a' && *p<='z') || (*p>='A' && *p<='Z') || (*p>='0' && *p<='9'))
1048 if (*p>='A' && *p<='Z') *p = *p-'A'+'a'; /* lower case */
1050 if (i == sizeof(key)) i--; /* limit */
1055 SPRINT(failure, "Expecting condition item name or ':' for end of condition list.");
1058 if (*p!=' ' && *p!='=')
1060 SPRINT(failure, "Illegal character '%c' after condition name '%s'. Expecting '=' for equation or ' ' to seperate condition items.", *p, key);
1064 /* check if condition exists */
1066 while(cond_defs[index].name)
1068 if (!strcmp(cond_defs[index].name, key))
1072 if (cond_defs[index].name == NULL)
1074 SPRINT(failure, "Unknown condition item name '%s'.", key);
1078 /* items without values must not have any parameter */
1079 if (cond_defs[index].type == COND_TYPE_NULL)
1083 SPRINT(failure, "Condition item '%s' must not have any value. Don't use '=' for this type of condition.", key);
1088 SPRINT(failure, "Condition item '%s' must not have any value. Expecting ' ' or tab after item name.", key);
1096 SPRINT(failure, "Condition item '%s' must have at least one value, '=' expected, and not a space.", key);
1101 SPRINT(failure, "Condition item '%s' must have at least one value, '=' expected.", key);
1107 /* check for duplicate condition */
1108 cond = rule->cond_first;
1111 if (cond->index == index)
1113 SPRINT(failure, "Duplicate condition '%s', use ',' to give multiple values.", key);
1120 /* Alloc memory for item */
1121 cond = (struct route_cond *)MALLOC(sizeof(struct route_cond));
1123 *cond_pointer = cond;
1124 cond_pointer = &(cond->next);
1125 cond->index = index;
1126 cond->match = cond_defs[index].match;
1127 switch(cond_defs[index].type)
1129 case COND_TYPE_NULL:
1132 SPRINT(failure, "Expecting no value.");
1135 value_type = VALUE_TYPE_NULL;
1138 /* parse all integer values/ranges */
1139 case COND_TYPE_INTEGER:
1140 case COND_TYPE_TIME:
1141 case COND_TYPE_MDAY:
1142 case COND_TYPE_MONTH:
1143 case COND_TYPE_WDAY:
1144 case COND_TYPE_YEAR:
1145 integer = integer_to = 0;
1146 if (*p==',' || *p==' ' || *p=='\0')
1148 SPRINT(failure, "Missing integer value.");
1151 while(*p>='0' && *p<='9')
1153 integer = integer*10 + *p-'0';
1156 value_type = VALUE_TYPE_INTEGER;
1160 if (*p==',' || *p==' ' || *p=='\0')
1162 SPRINT(failure, "Missing integer value.");
1165 while(*p>='0' && *p<='9')
1167 integer_to = integer_to*10 + *p-'0';
1170 value_type = VALUE_TYPE_INTEGER_RANGE;
1172 if (cond_defs[index].type == COND_TYPE_TIME)
1174 // Simon: i store the time as decimal, later i compare it correctly:
1175 // hours * 100 + minutes
1176 if (integer == 2400)
1178 if (integer >= 2400)
1181 SPRINT(failure, "Given time '%d' not in range 0000..2359 (or 2400 for 0000)", integer);
1184 if (integer%100 >= 60)
1185 goto timeoutofrange1;
1186 if (value_type == VALUE_TYPE_INTEGER)
1188 if (integer_to == 2400)
1190 if (integer_to >= 2400)
1193 SPRINT(failure, "Given time '%d' not in range 0000..2359 (or 2400 for 0000)", integer_to);
1196 if (integer_to%100 >= 60)
1197 goto timeoutofrange2;
1199 if (cond_defs[index].type == COND_TYPE_MDAY)
1201 if (integer<1 || integer>31)
1203 SPRINT(failure, "Given day-of-month '%d' not in range 1..31", integer);
1206 if (value_type == VALUE_TYPE_INTEGER)
1208 if (integer_to<1 || integer_to>31)
1210 SPRINT(failure, "Given day-of-month '%d' not in range 1..31", integer_to);
1214 if (cond_defs[index].type == COND_TYPE_WDAY)
1216 if (integer<1 || integer>7)
1218 SPRINT(failure, "Given day-of-week '%d' not in range 1..7", integer);
1221 if (value_type == VALUE_TYPE_INTEGER)
1223 if (integer_to<1 || integer_to>7)
1225 SPRINT(failure, "Given day-of-week '%d' not in range 1..7", integer_to);
1229 if (cond_defs[index].type == COND_TYPE_MONTH)
1231 if (integer<1 || integer>12)
1233 SPRINT(failure, "Given month '%d' not in range 1..12", integer);
1236 if (value_type == VALUE_TYPE_INTEGER)
1238 if (integer_to<1 || integer_to>12)
1240 SPRINT(failure, "Given month '%d' not in range 1..12", integer_to);
1244 if (cond_defs[index].type == COND_TYPE_YEAR)
1246 if (integer<1970 || integer>2106)
1248 SPRINT(failure, "Given year '%d' not in range 1970..2106", integer);
1251 if (value_type == VALUE_TYPE_INTEGER)
1253 if (integer_to<1970 || integer_to>2106)
1255 SPRINT(failure, "Given year '%d' not in range 1970..2106", integer_to);
1260 cond->integer_value = integer;
1261 cond->integer_value_to = integer_to;
1262 cond->value_type = value_type;
1265 /* parse all string values/ranges */
1266 case COND_TYPE_STRING:
1267 key[0] = key_to[0] = '\0';
1268 if (*p==',' || *p==' ' || *p=='\0')
1270 SPRINT(failure, "Missing string value, use \"\" for empty string.");
1273 p = read_string(p, key, sizeof(key), "-, ");
1274 if (key[0] == 1) /* error */
1276 SPRINT(failure, "Parsing String failed: %s", key+1);
1279 value_type = VALUE_TYPE_STRING;
1283 if (*p==',' || *p==' ' || *p=='\0')
1285 SPRINT(failure, "Missing string value, use \"\" for empty string.");
1288 p = read_string(p, key_to, sizeof(key_to), "-, ");
1289 if (key_to[0] == 1) /* error */
1291 SPRINT(failure, "Parsing string failed: %s", key_to+1);
1294 value_type = VALUE_TYPE_STRING_RANGE;
1295 if (strlen(key) != strlen(key_to))
1297 SPRINT(failure, "Given range of strings \"%s\"-\"%s\" have unequal length.", key, key_to);
1302 SPRINT(failure, "Given range has no length.");
1307 cond->string_value = (char *)MALLOC(strlen(key)+1);
1309 UCPY(cond->string_value, key);
1310 if (value_type == VALUE_TYPE_STRING_RANGE)
1312 cond->string_value_to = (char *)MALLOC(strlen(key_to)+1);
1314 UCPY(cond->string_value_to, key_to);
1315 cond->comp_string = strcmp(key, key_to);
1317 cond->value_type = value_type;
1320 /* parse service value */
1321 case COND_TYPE_CAPABILITY:
1322 if (!strncasecmp("speech", p, 6))
1323 cond->integer_value = INFO_BC_SPEECH;
1324 else if (!strncasecmp("audio", p, 5))
1325 cond->integer_value = INFO_BC_AUDIO;
1326 else if (!strncasecmp("video", p, 5))
1327 cond->integer_value = INFO_BC_VIDEO;
1328 else if (!strncasecmp("digital-restricted", p, 18))
1329 cond->integer_value = INFO_BC_DATARESTRICTED;
1330 else if (!strncasecmp("digital-unrestricted", p, 20))
1331 cond->integer_value = INFO_BC_DATAUNRESTRICTED;
1332 else if (!strncasecmp("digital-unrestricted-tones", p, 26))
1333 cond->integer_value = INFO_BC_DATAUNRESTRICTED_TONES;
1336 SPRINT(failure, "Given service type is invalid or misspelled.");
1339 cond->value_type = VALUE_TYPE_INTEGER;
1342 /* parse bmode value */
1343 case COND_TYPE_BMODE:
1344 if (!strncasecmp("transparent", p, 11))
1345 cond->integer_value = INFO_BMODE_CIRCUIT;
1346 else if (!strncasecmp("hdlc", p, 4))
1347 cond->integer_value = INFO_BMODE_PACKET;
1350 SPRINT(failure, "Given bchannel mode is invalid or misspelled.");
1353 cond->value_type = VALUE_TYPE_INTEGER;
1356 /* parse interface attribute <if>:<value> */
1357 case COND_TYPE_IFATTR:
1358 key[0] = key_to[0] = '\0';
1359 if (*p==':' || *p==',' || *p==' ' || *p=='\0')
1361 SPRINT(failure, "Missing interface name.");
1364 p = read_string(p, key, sizeof(key), ":-, ");
1365 if (key[0] == 1) /* error */
1367 SPRINT(failure, "Parsing interface failed: %s", key+1);
1372 SPRINT(failure, "Expeciting kolon to seperate value behind interface name.");
1376 while(*p>='0' && *p<='9')
1380 if (*p!=',' && *p!=' ' && *p!='\0')
1382 SPRINT(failure, "Invalid characters behind value.");
1385 value_type = VALUE_TYPE_STRING;
1390 SPRINT(failure, "Software error: COND_TYPE_* %d not parsed in function '%s'", cond_defs[index].type, __FUNCTION__);
1393 /* if we have another value for that item, we attach it */
1398 cond->value_extension = 1;
1401 /* to seperate the items, a space is required */
1404 SPRINT(failure, "Character '%c' not expected here. Use ',' to seperate multiple possible values.", *p);
1416 /* we are done with CONDITIONS, so we expect the ACTION */
1419 SPRINT(failure, "Expecting ':' after condition item(s).");
1425 /* skip spaces, if any */
1433 /* read action name */
1435 while((*p>='a' && *p<='z') || (*p>='A' && *p<='Z') || (*p>='0' && *p<='9') || *p == '-')
1437 if (*p>='A' && *p<='Z') *p = *p-'A'+'a'; /* lower case */
1439 if (i == sizeof(key)) i--; /* limit */
1442 if (key[0] == '\0') {
1443 SPRINT(failure, "Expecting action name.");
1447 /* check if item exists */
1449 while(action_defs[index].name)
1451 if (!action_defs[index].help) /* not internal actions */
1456 if (!strcmp(action_defs[index].name, key))
1460 if (action_defs[index].name == NULL)
1462 SPRINT(failure, "Unknown action name '%s'.", key);
1465 allowed_params = action_defs[index].params;
1467 /* alloc memory for action */
1468 action = (struct route_action *)MALLOC(sizeof(struct route_action));
1470 *action_pointer = action;
1471 action_pointer = &(action->next);
1472 param_pointer = &(action->param_first);
1473 action->index = index;
1474 action->line = line[nesting];
1476 /* skip spaces after param name */
1487 /* read param text */
1489 while((*p>='a' && *p<='z') || (*p>='A' && *p<='Z') || (*p>='0' && *p<='9'))
1491 if (*p>='A' && *p<='Z') *p = *p-'A'+'a'; /* lower case */
1493 if (i == sizeof(key)) i--; /* limit */
1496 if (key[0] == '\0') {
1497 SPRINT(failure, "Expecting parameter name.");
1501 /* check if item exists */
1503 while(param_defs[index].name)
1505 if (!strcmp(param_defs[index].name, key))
1509 if (param_defs[index].name == NULL)
1511 SPRINT(failure, "Unknown param name '%s'.", key);
1515 /* check if item is allowed for the action */
1516 if (!(param_defs[index].id & allowed_params))
1518 SPRINT(failure, "Param name '%s' exists, but not for this action.", key);
1522 /* params without values must not have any parameter */
1523 if (param_defs[index].type == PARAM_TYPE_NULL)
1525 if (*p!=' ' && *p!='\0')
1527 SPRINT(failure, "Parameter '%s' must not have any value.", key);
1534 SPRINT(failure, "Parameter '%s' must have at least one value, '=' expected and not a space.", key);
1539 SPRINT(failure, "Parameter '%s' must have at least one value, '=' expected.", key);
1545 /* special timeout value */
1546 if (!strcmp("timeout", key))
1548 if (action->timeout)
1550 SPRINT(failure, "Duplicate timeout value.");
1553 if (*p==',' || *p==' ' || *p=='\0')
1555 SPRINT(failure, "Missing integer value.");
1559 while(*p>='0' && *p<='9')
1561 integer = integer*10 + *p-'0';
1566 SPRINT(failure, "Expecting timeout value greater 0.");
1569 if (*p!=' ' && *p!='\0')
1571 SPRINT(failure, "Character '%c' not expected here. Use ' ' to seperate parameters.", *p);
1581 action->timeout = integer;
1582 /* check for next ACTION */
1591 /* check for duplicate parameters */
1592 param = action->param_first;
1595 if (param->index == index)
1597 SPRINT(failure, "Duplicate parameter '%s', use ',' to give multiple values.", key);
1600 param = param->next;
1604 /* Alloc memory for param */
1605 param = (struct route_param *)MALLOC(sizeof(struct route_param));
1607 *param_pointer = param;
1608 param_pointer = &(param->next);
1609 param->index = index;
1610 param->id = param_defs[index].id;
1612 switch(param_defs[index].type)
1614 /* parse null value */
1615 case PARAM_TYPE_NULL:
1616 param->value_type = VALUE_TYPE_NULL;
1619 /* parse integer value */
1620 case PARAM_TYPE_INTEGER:
1622 if (*p==',' || *p==' ' || *p=='\0')
1624 SPRINT(failure, "Missing integer value.");
1627 while(*p>='0' && *p<='9')
1629 integer = integer*10 + *p-'0';
1632 param->integer_value = integer;
1633 param->value_type = VALUE_TYPE_INTEGER;
1637 /* parse ports value */
1638 case PARAM_TYPE_PORTS:
1640 if (*p==',' || *p==' ' || *p=='\0')
1642 SPRINT(failure, "Missing port number, omit parameter or give port number.");
1648 while(*p>='0' && *p<='9')
1650 if (i < (int)sizeof(key)-1)
1655 integer = integer*10 + *p-'0';
1660 SPRINT(failure, "Port number too high.");
1665 if (i < (int)sizeof(key)-1)
1676 /* parse string value */
1677 case PARAM_TYPE_STRING:
1678 case PARAM_TYPE_CALLERIDTYPE:
1679 case PARAM_TYPE_CAPABILITY:
1680 case PARAM_TYPE_BMODE:
1681 case PARAM_TYPE_DIVERSION:
1682 case PARAM_TYPE_DESTIN:
1683 case PARAM_TYPE_TYPE:
1684 case PARAM_TYPE_YESNO:
1686 if (*p==',' || *p==' ' || *p=='\0')
1688 SPRINT(failure, "Missing string value, use \"\" for empty string.");
1691 p = read_string(p, key, sizeof(key), " ");
1692 if (key[0] == 1) /* error */
1694 SPRINT(failure, "Parsing string failed: %s", key+1);
1697 if (param_defs[index].type == PARAM_TYPE_CALLERIDTYPE)
1699 param->value_type = VALUE_TYPE_INTEGER;
1700 if (!strcasecmp(key, "unknown"))
1702 param->integer_value = INFO_NTYPE_UNKNOWN;
1705 if (!strcasecmp(key, "subscriber"))
1707 param->integer_value = INFO_NTYPE_SUBSCRIBER;
1710 if (!strcasecmp(key, "national"))
1712 param->integer_value = INFO_NTYPE_NATIONAL;
1715 if (!strcasecmp(key, "international"))
1717 param->integer_value = INFO_NTYPE_INTERNATIONAL;
1720 SPRINT(failure, "Caller ID type '%s' unknown.", key);
1723 if (param_defs[index].type == PARAM_TYPE_CAPABILITY)
1725 param->value_type = VALUE_TYPE_INTEGER;
1726 if (!strcasecmp(key, "speech"))
1728 param->integer_value = INFO_BC_SPEECH;
1731 if (!strcasecmp(key, "audio"))
1733 param->integer_value = INFO_BC_AUDIO;
1736 if (!strcasecmp(key, "video"))
1738 param->integer_value = INFO_BC_VIDEO;
1741 if (!strcasecmp(key, "digital-restricted"))
1743 param->integer_value = INFO_BC_DATARESTRICTED;
1746 if (!strcasecmp(key, "digital-unrestricted"))
1748 param->integer_value = INFO_BC_DATAUNRESTRICTED;
1751 if (!strcasecmp(key, "digital-unrestricted-tones"))
1753 param->integer_value = INFO_BC_DATAUNRESTRICTED_TONES;
1756 SPRINT(failure, "Service type '%s' unknown.", key);
1759 if (param_defs[index].type == PARAM_TYPE_BMODE)
1761 param->value_type = VALUE_TYPE_INTEGER;
1762 if (!strcasecmp(key, "transparent"))
1764 param->integer_value = INFO_BMODE_CIRCUIT;
1767 if (!strcasecmp(key, "hdlc"))
1769 param->integer_value = INFO_BMODE_PACKET;
1772 SPRINT(failure, "Bchannel mode '%s' unknown.", key);
1775 if (param_defs[index].type == PARAM_TYPE_DIVERSION)
1777 param->value_type = VALUE_TYPE_INTEGER;
1778 if (!strcasecmp(key, "cfu"))
1780 param->integer_value = INFO_DIVERSION_CFU;
1783 if (!strcasecmp(key, "cfb"))
1785 param->integer_value = INFO_DIVERSION_CFB;
1788 if (!strcasecmp(key, "cfnr"))
1790 param->integer_value = INFO_DIVERSION_CFNR;
1793 if (!strcasecmp(key, "cfp"))
1795 param->integer_value = INFO_DIVERSION_CFP;
1798 SPRINT(failure, "Diversion type '%s' unknown.", key);
1801 if (param_defs[index].type == PARAM_TYPE_TYPE)
1803 param->value_type = VALUE_TYPE_INTEGER;
1804 if (!strcasecmp(key, "unknown"))
1806 param->integer_value = INFO_NTYPE_UNKNOWN;
1809 if (!strcasecmp(key, "subscriber"))
1811 param->integer_value = INFO_NTYPE_SUBSCRIBER;
1814 if (!strcasecmp(key, "national"))
1816 param->integer_value = INFO_NTYPE_NATIONAL;
1819 if (!strcasecmp(key, "international"))
1821 param->integer_value = INFO_NTYPE_INTERNATIONAL;
1824 SPRINT(failure, "Number type '%s' unknown.", key);
1827 if (param_defs[index].type == PARAM_TYPE_YESNO)
1829 param->value_type = VALUE_TYPE_INTEGER;
1830 if (!strcasecmp(key, "yes"))
1832 param->integer_value = 1;
1835 if (!strcasecmp(key, "no"))
1837 param->integer_value = 0;
1840 SPRINT(failure, "Value '%s' unknown. ('yes' or 'no')", key);
1843 param->string_value = (char *)MALLOC(strlen(key)+1);
1845 UCPY(param->string_value, key);
1846 param->value_type = VALUE_TYPE_STRING;
1850 SPRINT(failure, "Software error: PARAM_TYPE_* %d not parsed in function '%s'", param_defs[index].type, __FUNCTION__);
1858 param->value_extension = 1;
1859 goto nextparamvalue;
1866 /* to seperate the items, a space is required */
1869 SPRINT(failure, "Character '%c' not expected here. Use ' ' to seperate parameters, or ',' for multiple values.", *p);
1880 /* check for next ACTION */
1889 fclose(fp[nesting--]);
1897 SPRINT(failure, "No ruleset defined.");
1899 return(ruleset_start);
1902 printf("While parsing %s, an error occurred in line %d:\n", filename[nesting], line[nesting]);
1903 printf("-> %s\n", buffer);
1904 memset(pointer, ' ', sizeof(pointer));
1905 pointer[p-buffer] = '^';
1906 pointer[p-buffer+1] = '\0';
1907 printf(" %s\n", pointer);
1908 printf("%s\n", failure);
1909 SPRINT(ruleset_error, "Error in file %s, line %d: %s", filename[nesting], line[nesting], failure);
1914 fclose(fp[nesting--]);
1918 ruleset_free(ruleset_start);
1923 * return ruleset by name
1925 struct route_ruleset *getrulesetbyname(char *name)
1927 struct route_ruleset *ruleset = ruleset_first;
1931 if (!strcasecmp(name, ruleset->name))
1935 ruleset = ruleset->next;
1937 PDEBUG(DEBUG_ROUTE, "ruleset %s %s.\n", name, ruleset?"found":"not found");
1942 * parses the current ruleset and returns action
1944 struct route_action *EndpointAppPBX::route(struct route_ruleset *ruleset)
1947 couldmatch = 0, /* any rule could match */
1954 struct route_rule *rule = ruleset->rule_first;
1955 struct route_cond *cond;
1956 struct route_action *action = NULL;
1957 unsigned int comp_len;
1959 char callerid[64], redirid[64];
1964 struct mISDNport *mISDNport;
1965 struct admin_list *admin;
1967 /* reset timeout action */
1968 e_match_timeout = 0; /* no timeout */
1969 e_match_to_action = NULL;
1971 SCPY(callerid, numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype, options.national, options.international));
1972 SCPY(redirid, numberrize_callerinfo(e_redirinfo.id, e_redirinfo.ntype, options.national, options.international));
1974 PDEBUG(DEBUG_ROUTE, "parsing ruleset '%s'\n", ruleset->name);
1977 PDEBUG(DEBUG_ROUTE, "checking rule in line %d\n", rule->line);
1978 match = 1; /* this rule matches */
1979 dialing_required = 0;
1980 timeout = 0; /* timeout time */
1981 cond = rule->cond_first;
1984 condition = 0; /* any condition element is true (1) or could be true (2) */
1986 istrue = 0; /* this condition-element is true */
1987 couldbetrue = 0; /* this conditions-element could be true */
1991 if (!e_ext.number[0])
1996 if (e_ext.number[0])
2001 if (ea_endpoint->ep_portlist)
2002 if ((ea_endpoint->ep_portlist->port_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_mISDN_DSS1)
2004 integer = e_callerinfo.isdn_port;
2007 case MATCH_INTERFACE:
2008 if (!e_callerinfo.interface[0])
2010 string = e_callerinfo.interface;
2011 goto match_string_prefix;
2013 case MATCH_CALLERID:
2015 goto match_string_prefix;
2017 case MATCH_EXTENSION:
2018 string = e_ext.name;
2022 string = e_dialinginfo.id;
2023 goto match_string_prefix;
2035 case MATCH_ANONYMOUS:
2036 if (e_callerinfo.present != INFO_PRESENT_ALLOWED)
2041 if (e_callerinfo.present == INFO_PRESENT_ALLOWED)
2046 if (e_callerinfo.present == INFO_PRESENT_NOTAVAIL)
2050 case MATCH_AVAILABLE:
2051 if (e_callerinfo.present != INFO_PRESENT_NOTAVAIL)
2056 if (e_callerinfo.screen == INFO_SCREEN_USER)
2061 if (e_callerinfo.screen != INFO_SCREEN_USER)
2065 case MATCH_REDIRECTED:
2066 if (e_redirinfo.present != INFO_PRESENT_NULL)
2071 if (e_redirinfo.present == INFO_PRESENT_NULL)
2077 goto match_string_prefix;
2080 integer = now_tm->tm_hour*100 + now_tm->tm_min;
2084 integer = now_tm->tm_mday;
2088 integer = now_tm->tm_mon+1;
2092 integer = now_tm->tm_year + 1900;
2096 integer = now_tm->tm_wday;
2097 integer = integer?integer:7; /* correct sunday */
2100 case MATCH_CAPABILITY:
2101 integer = e_capainfo.bearer_capa;
2104 case MATCH_INFOLAYER1:
2105 integer = e_capainfo.bearer_info1;
2109 integer = e_capainfo.hlc;
2113 tfp = fopen(cond->string_value, "r");
2118 if (fgetc(tfp) == '1')
2124 if (system(cond->string_value) == 0)
2134 timeout = now_d + cond->integer_value;
2140 if (!(comp_len = (unsigned int)strchr(cond->string_value, ':')))
2142 comp_len = comp_len-(unsigned int)cond->string_value;
2144 mISDNport = mISDNport_first;
2147 if (mISDNport->ifport)
2148 if (strlen(mISDNport->ifport->interface->name) == comp_len)
2149 if (!strncasecmp(mISDNport->ifport->interface->name, cond->string_value, comp_len))
2150 if (!mISDNport->l2hold || mISDNport->l2link)
2153 jj = mISDNport->b_num;
2157 if (mISDNport->b_state[j])
2162 mISDNport = mISDNport->next;
2164 if (cond->match == MATCH_FREE)
2166 if (avail >= atoi(cond->string_value + comp_len + 1))
2170 if (avail < atoi(cond->string_value + comp_len + 1))
2177 mISDNport = mISDNport_first;
2180 if (mISDNport->ifport)
2181 if (!strcasecmp(mISDNport->ifport->interface->name, cond->string_value))
2182 if (!mISDNport->l2hold || mISDNport->l2link)
2184 mISDNport = mISDNport->next;
2186 if (!mISDNport) /* all down */
2191 mISDNport = mISDNport_first;
2194 if (mISDNport->ifport)
2195 if (!strcasecmp(mISDNport->ifport->interface->name, cond->string_value))
2196 if (!mISDNport->l2hold || mISDNport->l2link)
2199 mISDNport = mISDNport->next;
2201 if (mISDNport) /* one link at least */
2208 mISDNport = mISDNport_first;
2211 if (mISDNport->ifport)
2212 if (!strcasecmp(mISDNport->ifport->interface->name, cond->string_value))
2213 if (mISDNport->use) /* break if in use */
2215 mISDNport = mISDNport->next;
2217 if (mISDNport && cond->match==MATCH_BUSY)
2219 if (!mISDNport && cond->match==MATCH_IDLE)
2224 case MATCH_NOTREMOTE:
2225 admin = admin_first;
2228 if (admin->remote_name[0] && !strcmp(cond->string_value, admin->remote_name))
2230 admin = admin->next;
2232 if (admin && cond->match==MATCH_REMOTE)
2234 if (!admin && cond->match==MATCH_NOTREMOTE)
2239 PERROR("Software error: MATCH_* %d not parsed in function '%s'", cond->match, __FUNCTION__);
2243 if (cond->value_type == VALUE_TYPE_INTEGER)
2245 if (integer != cond->integer_value)
2250 if (cond->value_type == VALUE_TYPE_INTEGER_RANGE)
2252 /* check if negative range (2100 - 700 o'clock) */
2253 if (cond->integer_value > cond->integer_value_to)
2255 if (integer>=cond->integer_value && integer<=cond->integer_value_to)
2259 /* range is positive */
2260 if (integer>=cond->integer_value && integer<=cond->integer_value_to)
2267 if (strlen(cond->string_value) != strlen(string))
2270 match_string_prefix:
2271 comp_len = strlen(cond->string_value); /* because we must reach value's length */
2272 /* we must have greater or equal length to values */
2273 if ((unsigned int)strlen(string) < comp_len)
2275 /* special case for unfinished dialing */
2276 if (cond->match == MATCH_DIALING)
2278 couldbetrue = 1; /* could match */
2279 comp_len = strlen(string);
2285 /* on single string match */
2286 if (cond->value_type == VALUE_TYPE_STRING)
2288 if (!strncmp(string, cond->string_value, comp_len))
2291 /* must be set for changing 'e_extdialing' */
2292 if (cond->match == MATCH_DIALING)
2293 dialing_required = comp_len;
2298 /* on range match */
2299 if (cond->value_type == VALUE_TYPE_STRING_RANGE)
2301 /* check if negative range ("55"-"22") */
2302 if (cond->comp_string > 0)
2304 if (strncmp(string, cond->string_value, comp_len) >= 0)
2307 /* must be set for changing 'e_extdialing' */
2308 if (cond->match == MATCH_DIALING)
2309 dialing_required = comp_len;
2312 if (strncmp(string, cond->string_value_to, comp_len) <= 0)
2314 /* must be set for changing 'e_extdialing' */
2316 if (cond->match == MATCH_DIALING)
2317 dialing_required = comp_len;
2322 /* range is positive */
2323 if (strncmp(string, cond->string_value, comp_len) < 0)
2325 if (strncmp(string, cond->string_value_to, comp_len) > 0)
2328 if (cond->match == MATCH_DIALING)
2329 dialing_required = comp_len;
2335 /* set current condition */
2336 if (istrue && !couldbetrue)
2337 condition = 1; /* element matches, so condition matches */
2338 if (istrue && couldbetrue && !condition)
2339 condition = 2; /* element could match and other elements don't match, so condition could match */
2341 /* if not matching or could match */
2344 /* if we have more values to check */
2345 if (cond->value_extension && cond->next)
2348 goto checkextension;
2354 /* skip exteded values, beacuse we already have one matching value */
2355 while(cond->value_extension && cond->next)
2360 if (timeout>now_d && match==1) /* the matching rule with timeout in the future */
2361 if (e_match_timeout<1 || timeout<e_match_timeout) /* first timeout or lower */
2363 /* set timeout in the furture */
2364 e_match_timeout = timeout;
2365 e_match_to_action = rule->action_first;
2366 e_match_to_extdialing = e_dialinginfo.id + dialing_required;
2367 match = 0; /* matches in the future */
2371 /* matching, we return first action */
2372 action = rule->action_first;
2373 e_match_timeout = 0; /* no timeout */
2374 e_match_to_action = NULL;
2375 e_extdialing = e_dialinginfo.id + dialing_required;
2380 /* rule could match if more is dialed */
2389 * parses the current action's parameters and return them
2391 struct route_param *EndpointAppPBX::routeparam(struct route_action *action, unsigned long long id)
2393 struct route_param *param = action->param_first;
2397 if (param->id == id)
2399 param = param->next;
2406 * internal rules that are not defined by route.conf
2408 struct route_action action_password = {
2416 struct route_action action_password_write = {
2419 ACTION_PASSWORD_WRITE,
2424 struct route_action action_external = {
2432 struct route_action action_internal = {
2440 struct route_action action_remote = {
2448 struct route_action action_vbox = {
2456 struct route_action action_partyline = {
2464 struct route_action action_disconnect = {