1 /*****************************************************************************\
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg **
8 ** match processing of routing configuration **
10 \*****************************************************************************/
19 struct route_ruleset *ruleset_first; /* first entry */
20 struct route_ruleset *ruleset_main; /* pointer to main ruleset */
22 struct cond_defs cond_defs[] = {
24 { "extern", MATCH_EXTERN, COND_TYPE_NULL,
25 "extern", "Matches if call is from external port."},
26 { "intern", MATCH_INTERN, COND_TYPE_NULL,
27 "intern", "Matches if call is from internal port."},
29 { "h323", MATCH_H323, COND_TYPE_NULL,
30 "h323", "Matches if call is received via H.323."},
31 // { "ip", MATCH_IP, COND_TYPE_IP,
32 // "ip=<ip>[-<ip>|/<mask>][,...]", "Matches if caller matches given source IP address(es) / range(s) / block(s)."},
33 { "port", MATCH_PORT, COND_TYPE_INTEGER,
34 "port=<number>[-<number>][,...]", "Matches if call is received from given port(s). NOT INTERFACE!"},
35 { "interface", MATCH_INTERFACE,COND_TYPE_STRING,
36 "interface=<interface>[,...]", "Matches if call is received from given interface(s). NOT PORTS!"},
37 { "callerid", MATCH_CALLERID, COND_TYPE_STRING,
38 "callerid=<digits>[-<digits>][,...]", "Matches if caller ID matches or begins with the given (range(s) of) prefixes(s)."},
39 { "extension", MATCH_EXTENSION,COND_TYPE_STRING,
40 "extension=<digits>[-<digits>][,...]", "Matches if caller calls from given (range(s) of) extension(s)."},
41 { "dialing", MATCH_DIALING, COND_TYPE_STRING,
42 "dialing=<digits>[-<digits>][,...]", "Matches if caller has dialed the given (range(s) of) digits at least."},
43 { "enblock", MATCH_ENBLOCK, COND_TYPE_NULL,
44 "enblock", "Matches if caller dialed en block. (Dial the number before pick up.)"},
45 { "overlap", MATCH_OVERLAP, COND_TYPE_NULL,
46 "overlap", "Matches if caller dialed digit by digit. (Dial the number after pick up.)"},
47 { "anonymous", MATCH_ANONYMOUS,COND_TYPE_NULL,
48 "anonymous", "Matches if caller uses restricted caller ID or if not available."},
49 { "visible", MATCH_VISIBLE, COND_TYPE_NULL,
50 "visible", "Matches if caller ID is presented and if available."},
51 { "unknown", MATCH_UNKNOWN, COND_TYPE_NULL,
52 "unknown", "Matches if no ID is available from caller."},
53 { "available", MATCH_AVAILABLE,COND_TYPE_NULL,
54 "available", "Matches if ID is available from caller."},
55 { "fake", MATCH_FAKE, COND_TYPE_NULL,
56 "fake", "Matches if caller ID is not screened and may be faked by caller."},
57 { "real", MATCH_REAL, COND_TYPE_NULL,
58 "real", "Matches if caller ID is screend and so it is the real caller's ID."},
59 { "redirected", MATCH_REDIRECTED,COND_TYPE_NULL,
60 "redirected", "Matches if caller has been redirected."},
61 { "direct", MATCH_DIRECT ,COND_TYPE_NULL,
62 "direct", "Matches if caller did not come from an redirection."},
63 { "redirid", MATCH_REDIRID ,COND_TYPE_STRING,
64 "redirid=<digits>[-<digits>][,...]", "Matches if the caller has been redirected by the given (range(s) of) ID(s) or prefix(es))"},
65 { "time", MATCH_TIME, COND_TYPE_TIME,
66 "time=<minutes>[-<minutes>][,...]", "Matches if the caller calls within the given (range(s) of) time(s). (e.g. 0700-1900)"},
67 { "mday", MATCH_MDAY, COND_TYPE_MDAY,
68 "mday=<day>[-<day>][,...]", "Matches if the caller calls within the given (range(s) of) day(s) of the month. (1..31)"},
69 { "month", MATCH_MONTH, COND_TYPE_MONTH,
70 "month=<month>[-<month>][,...]", "Matches if the caller calls within the given (range(s) of) month(s). (1=January..12=December)"},
71 { "year", MATCH_YEAR, COND_TYPE_YEAR,
72 "year=<year>[-<year>][,...]", "Matches if the caller calls within the given (range(s) of) year(s). (1970..2106)"},
73 { "wday", MATCH_WDAY, COND_TYPE_WDAY,
74 "wday=<day>[-<day>][,...]", "Matches if the caller calls within the given (range(s) of) weekday(s). (1=Monday..7=Sunday)"},
75 { "capability", MATCH_CAPABILITY, COND_TYPE_CAPABILITY,
76 "capability=speech|audio|video|digital-restricted|digital-unrestricted|digital-unrestricted-tones[,...]", "Matches the given bearer capability(s)."},
77 { "infolayer1", MATCH_INFOLAYER1, COND_TYPE_INTEGER,
78 "infolayer1=<value>[,...]", "Matches the given information layer 1. (2=u-Law, 3=a-law, see info layer 1 in bearer capability.)"},
79 { "hlc", MATCH_HLC, COND_TYPE_INTEGER,
80 "hlc=<value>[,...]", "Matches the high layer capability(s)."},
81 { "file", MATCH_FILE, COND_TYPE_STRING,
82 "file=<path>[,...]", "Mathes is the given file exists and if the first character is '1'."},
83 { "execute", MATCH_EXECUTE, COND_TYPE_STRING,
84 "execute=<command>[,...]","Matches if the return value of the given command is greater 0."},
85 { "default", MATCH_DEFAULT, COND_TYPE_NULL,
86 "default","Matches if no further dialing could match."},
87 { "timeout", MATCH_TIMEOUT, COND_TYPE_INTEGER,
88 "timeout=<seconds>","Matches if the ruleset was entered AFTER given seconds."},
89 { "free", MATCH_FREE, COND_TYPE_IFATTR,
90 "free=<interface>:<channel>","Matches if the given minimum of channels are free."},
91 { "notfree", MATCH_NOTFREE, COND_TYPE_IFATTR,
92 "notfree=<interface>:<channel>","Matches if NOT the given minimum of channels are free."},
93 { "blocked", MATCH_DOWN, COND_TYPE_STRING,
94 "blocked=<interfaces>[,...]","Matches if all of the given interfaces are blocked."},
95 { "idle", MATCH_UP, COND_TYPE_STRING,
96 "idle=<interface>[,...]","Matches if any of the given interfaces is idle."},
97 { "busy", MATCH_BUSY, COND_TYPE_STRING,
98 "busy=<extension>[,...]","Matches if any of the given extension is busy."},
99 { "notbusy", MATCH_IDLE, COND_TYPE_STRING,
100 "notbusy<extension>[,...]","Matches if any of the given extension is not busy."},
104 struct param_defs param_defs[] = {
106 "proceeding", PARAM_TYPE_NULL,
107 "proceeding", "Will set the call into 'proceeding' state to prevent dial timeout."},
109 "alerting", PARAM_TYPE_NULL,
110 "alerting", "Will set the call into 'altering' state."},
112 "connect", PARAM_TYPE_NULL,
113 "connect", "Will complete the call before processing the action. Audio path for external calls will be established."},
116 "extension", PARAM_TYPE_STRING,
117 "extension=<digits>", "Give extension name (digits) to relate this action to."},
119 "extensions", PARAM_TYPE_STRING,
120 "extensions=<extension>[,<extension>[,...]]", "One or more extensions may be given."},
123 "prefix", PARAM_TYPE_STRING,
124 "prefix=<digits>", "Add prefix in front of the dialed number."},
126 "capability", PARAM_TYPE_CAPABILITY,
127 "capability=speech|audio|video|digital-restricted|digital-unrestricted|digital-unrestricted-tones", "Alter the service type of the call."},
129 "bmode", PARAM_TYPE_BMODE,
130 "capability=transparent|hdlc", "Alter the bchannel mode of the call. Use hdlc for data calls."},
132 "infolayer1", PARAM_TYPE_INTEGER,
133 "infolayer1=<value>", "Alter the layer 1 information of a call. Use 3 for ALAW or 2 for uLAW."},
135 "hlc", PARAM_TYPE_INTEGER,
136 "hlc=<value>", "Alter the HLC identification. Use 1 for telephony or omit."},
138 "exthlc", PARAM_TYPE_INTEGER,
139 "exthlc=<value>", "Alter extended HLC value. (Mainenance only, don't use it.)"},
141 "present", PARAM_TYPE_YESNO,
142 "present=yes|no", "Allow or restrict caller ID regardless what the caller wants."},
144 "diversion", PARAM_TYPE_DIVERSION,
145 "diversion=cfu|cfnr|cfb|cfp", "Set diversion type."},
147 "dest", PARAM_TYPE_DESTIN,
148 "dest=<string>", "Destination number to divert to. Use 'vbox' to divert to vbox. (cfu,cfnr,cfb only)"},
150 "select", PARAM_TYPE_NULL,
151 "select", "Lets the caller select the history of calls using keys '1'/'3' or '*'/'#'."},
153 "delay", PARAM_TYPE_INTEGER,
154 "delay=<seconds>", "Number of seconds to delay."},
156 "limit", PARAM_TYPE_INTEGER,
157 "limit=<retries>", "Number of maximum retries."},
159 "host", PARAM_TYPE_STRING,
160 "host=<string>", "Name of remote VoIP host."},
162 "port", PARAM_TYPE_STRING,
163 "port=<value>", "Alternate port to use if 'host' is given."},
165 "interfaces", PARAM_TYPE_STRING,
166 "interfaces=<interface>[,<interface>[,...]]", "Give one or a list of Interfaces to select a free channel from."},
168 "address", PARAM_TYPE_STRING,
169 "address=<string>", "Complete VoIP address. ( [user@]host[:port] )"},
171 "sample", PARAM_TYPE_STRING,
172 "sample=<file prefix>", "Filename of sample (current tone's dir) or full path to sample. ('.wav'/'.wave'/'.isdn' is added automatically."},
174 { PARAM_ANNOUNCEMENT,
175 "announcement",PARAM_TYPE_STRING,
176 "announcement=<file prefix>", "Filename of announcement (inside vbox recording dir) or full path to sample. ('.wav'/'.wave'/'.isdn' is added automatically."},
179 "ruleset", PARAM_TYPE_STRING,
180 "ruleset=<name>", "Ruleset to go to."},
182 "cause", PARAM_TYPE_INTEGER,
183 "cause=<cause value>", "Cause value when disconnecting. (21=reject 1=unassigned 63=service not available)"},
185 "location", PARAM_TYPE_INTEGER,
186 "location=<location value>", "Location of cause value when disconnecting. (0=user 1=private network sering local user)"},
188 "display", PARAM_TYPE_STRING,
189 "display=<text>", "Message to display on the caller's telephone. (internal only)"},
191 "ports", PARAM_TYPE_INTEGER,
192 "ports=<port>[,<port>[,...]]", "ISDN port[s] to use."},
194 "tpreset", PARAM_TYPE_INTEGER,
195 "tpreset=<seconds>", "Preset of countdown timer."},
197 "file", PARAM_TYPE_STRING,
198 "file=<full path>", "Full path to file name."},
200 "content", PARAM_TYPE_STRING,
201 "content=<string>", "Content to write into file."},
203 "append", PARAM_TYPE_NULL,
204 "append", "Will append to given file, rather than overwriting it."},
206 "execute", PARAM_TYPE_STRING,
207 "execute=<full path>", "Full path to script/command name. (Dialed digits are the argument 1.)"},
209 "param", PARAM_TYPE_STRING,
210 "param=<string>", "Optionally this parameter can be inserted as argument 1, others are shifted."},
212 "type", PARAM_TYPE_TYPE,
213 "type=unknown|subscriber|national|international", "Type of number to dial, default is 'unknown'."},
215 "complete", PARAM_TYPE_NULL,
216 "complete", "Indicates complete number as given by prefix. Proceeding of long distance calls may be faster."},
218 "callerid", PARAM_TYPE_STRING,
219 "callerid=<digits>", "Change caller ID to given string."},
220 { PARAM_CALLERIDTYPE,
221 "calleridtype",PARAM_TYPE_CALLERIDTYPE,
222 "calleridtype=[unknown|subscriber|national|international]", "Type of caller ID. For normal MSN use 'unknown'"},
224 "callto", PARAM_TYPE_STRING,
225 "callto=<digits>", "Where to call back. By default the caller ID is used."},
227 "room", PARAM_TYPE_INTEGER,
228 "room=<digits>", "Conference room number, must be greater 0, as in real life."},
230 "timeout", PARAM_TYPE_INTEGER,
231 "timeout=<seconds>", "Timeout before continue with next action."},
234 "nopassword", PARAM_TYPE_NULL,
235 "nopassword", "Don't ask for password. Be sure to authenticate right via real caller ID."},
237 { 0, NULL, 0, NULL, NULL}
240 struct action_defs action_defs[] = {
242 "extern", &EndpointAppPBX::action_init_call, &EndpointAppPBX::action_dialing_external, &EndpointAppPBX::action_hangup_call,
243 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,
244 "Call is routed to extern number as dialed."},
246 "intern", &EndpointAppPBX::action_init_call, &EndpointAppPBX::action_dialing_internal, &EndpointAppPBX::action_hangup_call,
247 PARAM_CONNECT | PARAM_EXTENSION | PARAM_TYPE | PARAM_CAPA | PARAM_BMODE | PARAM_INFO1 | PARAM_HLC | PARAM_EXTHLC | PARAM_PRESENT | PARAM_TIMEOUT,
248 "Call is routed to intern extension as given by the dialed number or specified by option."},
250 "outdial", &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,
254 "h323", &EndpointAppPBX::action_init_call, &EndpointAppPBX::action_dialing_h323, &EndpointAppPBX::action_hangup_call,
255 PARAM_CONNECT | PARAM_PREFIX | PARAM_HOST | PARAM_PORT | PARAM_ADDRESS | PARAM_TIMEOUT,
256 "Call is routed to H.323 host/gateway."},
258 "asterisk", &EndpointAppPBX::action_init_chan, &EndpointAppPBX::action_dialing_chan, &EndpointAppPBX::action_hangup_call,
259 PARAM_CONNECT | PARAM_TIMEOUT,
260 "Call is routed to Asterisk via channel driver."},
261 { ACTION_VBOX_RECORD,
262 "vbox-record",&EndpointAppPBX::action_init_call, &EndpointAppPBX::action_dialing_vbox_record, &EndpointAppPBX::action_hangup_call,
263 PARAM_CONNECT | PARAM_EXTENSION | PARAM_ANNOUNCEMENT | PARAM_TIMEOUT,
264 "Caller is routed to the voice box of given extension."},
266 "partyline",&EndpointAppPBX::action_init_partyline, NULL, &EndpointAppPBX::action_hangup_call,
268 "Caller is participating the conference with the given room number."},
270 "login", NULL, &EndpointAppPBX::action_dialing_login, NULL,
271 PARAM_CONNECT | PARAM_EXTENSION | PARAM_NOPASSWORD,
272 "Log into the given extension. Password required."},
274 "callerid", &EndpointAppPBX::action_init_change_callerid, &EndpointAppPBX::action_dialing_callerid, NULL,
275 PARAM_CONNECT | PARAM_CALLERID | PARAM_CALLERIDTYPE | PARAM_PRESENT,
276 "Caller changes the caller ID for all calls."},
277 { ACTION_CALLERIDNEXT,
278 "calleridnext",&EndpointAppPBX::action_init_change_callerid, &EndpointAppPBX::action_dialing_calleridnext, NULL,
279 PARAM_CONNECT | PARAM_CALLERID | PARAM_CALLERIDTYPE | PARAM_PRESENT,
280 "Caller changes the caller ID for the next call."},
282 "forward", &EndpointAppPBX::action_init_change_forward, &EndpointAppPBX::action_dialing_forward, NULL,
283 PARAM_CONNECT | PARAM_DIVERSION | PARAM_DEST | PARAM_DELAY,
284 "Caller changes the diversion of given type to the given destination or voice box."},
286 "redial", &EndpointAppPBX::action_init_redial_reply, &EndpointAppPBX::action_dialing_redial, NULL,
287 PARAM_CONNECT | PARAM_SELECT,
288 "Caller redials. (last outgoing call(s))"},
290 "reply", &EndpointAppPBX::action_init_redial_reply, &EndpointAppPBX::action_dialing_reply, NULL,
291 PARAM_CONNECT | PARAM_SELECT,
292 "Caller replies. (last incomming call(s))"},
294 "powerdial", NULL, &EndpointAppPBX::action_dialing_powerdial, NULL,
295 PARAM_CONNECT | PARAM_DELAY | PARAM_LIMIT | PARAM_TIMEOUT,
296 "Caller redials using powerdialing."},
298 "callback", NULL, &EndpointAppPBX::action_dialing_callback, &EndpointAppPBX::action_hangup_callback,
299 PARAM_PROCEEDING | PARAM_ALERTING | PARAM_CONNECT | PARAM_EXTENSION | PARAM_DELAY | PARAM_CALLTO | PARAM_PREFIX,
300 "Caller will use the callback service. After disconnecting, the callback is triggered."},
302 "abbrev", NULL, &EndpointAppPBX::action_dialing_abbrev, NULL,
304 "Caller dials abbreviation."},
306 "test", NULL, &EndpointAppPBX::action_dialing_test, NULL,
307 PARAM_CONNECT | PARAM_PREFIX | PARAM_TIMEOUT,
308 "Caller dials test mode."},
310 "play", &EndpointAppPBX::action_init_play, NULL, NULL,
311 PARAM_PROCEEDING | PARAM_ALERTING | PARAM_CONNECT | PARAM_SAMPLE | PARAM_TIMEOUT,
312 "Plays the given sample."},
314 "vbox-play", &EndpointAppPBX::action_init_vbox_play, &EndpointAppPBX::action_dialing_vbox_play, NULL,
316 "Caller listens to her voice box or to given extension."},
318 "calculator", NULL, &EndpointAppPBX::action_dialing_calculator, NULL,
320 "Caller calls the calculator."},
322 "timer", NULL, &EndpointAppPBX::action_dialing_timer, NULL,
323 PARAM_CONNECT | PARAM_TPRESET | PARAM_TIMEOUT,
325 // "Caller calls the timer."},
327 "goto", NULL, &EndpointAppPBX::action_dialing_goto, NULL,
328 PARAM_CONNECT | PARAM_RULESET | PARAM_SAMPLE,
329 "Jump to given ruleset and optionally play sample. Dialed digits are not flushed."},
331 "menu", NULL, &EndpointAppPBX::action_dialing_menu, NULL,
332 PARAM_CONNECT | PARAM_RULESET | PARAM_SAMPLE,
333 "Same as 'goto', but flushes all digits dialed so far."},
335 "disconnect", NULL, &EndpointAppPBX::action_dialing_disconnect, NULL,
336 PARAM_CONNECT | PARAM_CAUSE | PARAM_LOCATION | PARAM_SAMPLE | PARAM_DISPLAY,
337 "Caller gets disconnected optionally with given cause and given sample and given display text."},
339 "help", NULL, &EndpointAppPBX::action_dialing_help, NULL,
340 PARAM_CONNECT | PARAM_TIMEOUT,
342 // "Caller will be able to select from current rules that would match. (using * and #)"},
344 "deflect", NULL, &EndpointAppPBX::action_dialing_deflect, NULL,
347 // "External call is deflected to the given destination within the telephone network."},
349 "setforward", NULL, &EndpointAppPBX::action_dialing_setforward, NULL,
350 PARAM_CONNECT | PARAM_DIVERSION | PARAM_DEST | PARAM_PORT,
352 // "The call forward is set within the telephone network of the external line."},
354 "execute", NULL, NULL, &EndpointAppPBX::action_hangup_execute,
355 PARAM_CONNECT | PARAM_EXECUTE | PARAM_PARAM,
356 "Executes the given script file. The file must terminate quickly, because it will halt the PBX."},
358 "file", NULL, NULL, &EndpointAppPBX::action_hangup_file,
359 PARAM_CONNECT | PARAM_FILE | PARAM_CONTENT | PARAM_APPEND,
360 "Writes givent content to given file. If content is not given, the dialed digits are written."},
362 "pick", &EndpointAppPBX::action_init_pick, NULL, NULL,
364 "Pick up a call that is ringing on any phone. Extensions may be given to limit the picking ability."},
366 "password", NULL, &EndpointAppPBX::action_dialing_password, NULL,
369 { ACTION_PASSWORD_WRITE,
370 "password_wr",NULL, &EndpointAppPBX::action_dialing_password_wr, NULL,
374 "nothing", NULL, NULL, NULL,
375 PARAM_PROCEEDING | PARAM_ALERTING | PARAM_CONNECT | PARAM_TIMEOUT,
376 "does nothing. Usefull to wait for calls to be released completely, by giving timeout value."},
378 "efi", &EndpointAppPBX::action_init_efi, NULL, NULL,
379 PARAM_PROCEEDING | PARAM_ALERTING | PARAM_CONNECT,
380 "Elektronische Fernsprecher Identifikation."},
382 NULL, NULL, NULL, NULL, 0, NULL}
386 /* display documentation of rules */
388 void doc_rules(const char *name)
395 while(action_defs[i].name)
397 if (!strcasecmp(action_defs[i].name, name))
401 if (!action_defs[i].name)
403 fprintf(stderr, "Given action '%s' unknown.\n", name);
406 name = action_defs[i].name;
409 printf("Syntax overview:\n");
410 printf("----------------\n\n");
411 printf("[ruleset]\n");
412 printf("<condition> ... : <action> [parameter ...] [timeout=X : <action> ...]\n");
414 printf("Please refer to the documentation for description on rule format.\n\n");
418 printf("Available conditions to match:\n");
419 printf("------------------------------\n\n");
421 while(cond_defs[i].name)
423 printf("Usage: %s\n", cond_defs[i].doc);
424 printf("%s\n\n", cond_defs[i].help);
428 printf("Available actions with their parameters:\n");
429 printf("----------------------------------------\n\n");
432 printf("Detailes parameter description of action:\n");
433 printf("-----------------------------------------\n\n");
436 while(action_defs[i].name)
438 if (name && !!strcmp(action_defs[i].name,name)) /* not selected */
443 if (!action_defs[i].help) /* not internal actions */
448 printf("Usage: %s", action_defs[i].name);
452 if ((1LL<<j) & action_defs[i].params)
453 printf(" [%s]", param_defs[j].doc);
456 printf("\n%s\n\n", action_defs[i].help);
457 if (name) /* only show parameter help for specific action */
462 if ((1LL<<j) & action_defs[i].params)
463 printf("%s:\n\t%s\n", param_defs[j].doc, param_defs[j].help);
472 void ruleset_free(struct route_ruleset *ruleset_start)
474 struct route_ruleset *ruleset;
475 struct route_rule *rule;
476 struct route_cond *cond;
477 struct route_action *action;
478 struct route_param *param;
482 ruleset = ruleset_start;
483 ruleset_start = ruleset->next;
484 while(ruleset->rule_first)
486 rule = ruleset->rule_first;
487 ruleset->rule_first = rule->next;
488 while(rule->cond_first)
490 cond = rule->cond_first;
491 if (cond->string_value)
493 free(cond->string_value);
496 if (cond->string_value_to)
498 free(cond->string_value_to);
501 rule->cond_first = cond->next;
505 while(rule->action_first)
507 action = rule->action_first;
508 rule->action_first = action->next;
509 while(action->param_first)
511 param = action->param_first;
512 action->param_first = param->next;
513 if (param->string_value)
515 free(param->string_value);
532 void ruleset_debug(struct route_ruleset *ruleset_start)
534 struct route_ruleset *ruleset;
535 struct route_rule *rule;
536 struct route_cond *cond;
537 struct route_action *action;
538 struct route_param *param;
541 ruleset = ruleset_start;
544 printf("Ruleset: '%s'\n", ruleset->name);
545 rule = ruleset->rule_first;
550 cond = rule->cond_first;
554 printf(" Condition:");
558 printf(" %s", cond_defs[cond->index].name);
559 if (cond->value_type != VALUE_TYPE_NULL)
562 switch(cond->value_type)
564 case VALUE_TYPE_NULL:
567 case VALUE_TYPE_INTEGER:
568 printf("%d", cond->integer_value);
571 case VALUE_TYPE_INTEGER_RANGE:
572 printf("%d-%d", cond->integer_value, cond->integer_value_to);
575 case VALUE_TYPE_STRING:
576 printf("'%s'", cond->string_value);
579 case VALUE_TYPE_STRING_RANGE:
580 printf("'%s'-'%s'", cond->string_value, cond->string_value_to);
584 printf("Software error: VALUE_TYPE_* %d not known in function '%s' line=%d", cond->value_type, __FUNCTION__, __LINE__);
586 if (cond->value_extension && cond->next)
590 goto next_cond_value;
598 action = rule->action_first;
601 printf(" Action: %s\n", action_defs[action->index].name);
604 param = action->param_first;
612 printf(" %s", param_defs[param->index].name);
613 if (param->value_type != VALUE_TYPE_NULL)
615 switch(param->value_type)
617 case VALUE_TYPE_NULL:
620 case VALUE_TYPE_INTEGER:
621 if (param_defs[param->index].type == PARAM_TYPE_CALLERIDTYPE)
623 switch(param->integer_value)
625 case INFO_NTYPE_UNKNOWN:
628 case INFO_NTYPE_SUBSCRIBER:
629 printf("subscriber");
631 case INFO_NTYPE_NATIONAL:
634 case INFO_NTYPE_INTERNATIONAL:
635 printf("international");
638 printf("unknown(%d)", param->integer_value);
642 if (param_defs[param->index].type == PARAM_TYPE_CAPABILITY)
644 switch(param->integer_value)
655 case INFO_BC_DATARESTRICTED:
656 printf("digital-restricted");
658 case INFO_BC_DATAUNRESTRICTED:
659 printf("digital-unrestricted");
661 case INFO_BC_DATAUNRESTRICTED_TONES:
662 printf("digital-unrestricted-tones");
665 printf("unknown(%d)", param->integer_value);
669 if (param_defs[param->index].type == PARAM_TYPE_DIVERSION)
671 switch(param->integer_value)
673 case INFO_DIVERSION_CFU:
676 case INFO_DIVERSION_CFNR:
679 case INFO_DIVERSION_CFB:
682 case INFO_DIVERSION_CFP:
686 printf("unknown(%d)", param->integer_value);
690 if (param_defs[param->index].type == PARAM_TYPE_TYPE)
692 switch(param->integer_value)
694 case INFO_NTYPE_UNKNOWN:
697 case INFO_NTYPE_SUBSCRIBER:
698 printf("subscriber");
700 case INFO_NTYPE_NATIONAL:
703 case INFO_NTYPE_INTERNATIONAL:
704 printf("international");
707 printf("unknown(%d)", param->integer_value);
711 if (param_defs[param->index].type == PARAM_TYPE_YESNO)
713 switch(param->integer_value)
722 printf("unknown(%d)", param->integer_value);
726 if (param_defs[param->index].type == PARAM_TYPE_NULL)
730 printf("%d", param->integer_value);
733 case VALUE_TYPE_STRING:
734 printf("'%s'", param->string_value);
738 printf("Software error: VALUE_TYPE_* %d not known in function '%s' line=%d", param->value_type, __FUNCTION__, __LINE__);
745 printf(" Timeout: %d\n", action->timeout);
746 action = action->next;
752 ruleset = ruleset->next;
760 static char *read_string(char *p, char *key, int key_size, char *special)
786 UPRINT(key, "\001String too long.");
791 UPRINT(key, "\001Unexpected end of line inside quotes.");
798 if (strchr(special, *p))
808 UPRINT(key, "\001Unexpected end of line.");
814 UPRINT(key, "\001String too long.");
822 char ruleset_error[256];
823 struct route_ruleset *ruleset_parse(void)
828 unsigned long long j;
832 FILE *fp[MAXNESTING];
833 char filename[MAXNESTING][256];
834 int line[MAXNESTING];
841 int expecting = 1; /* 1 = expecting ruleset */
845 integer_to; /* condition index, .. */
846 struct route_ruleset *ruleset_start = NULL, *ruleset;
847 struct route_ruleset **ruleset_pointer = &ruleset_start;
848 struct route_rule *rule;
849 struct route_rule **rule_pointer = NULL;
850 struct route_cond *cond;
851 struct route_cond **cond_pointer = NULL;
852 struct route_action *action;
853 struct route_action **action_pointer = NULL;
854 struct route_param *param;
855 struct route_param **param_pointer = NULL;
858 /* check the integrity of IDs for ACTION_* and PARAM_* */
860 while(action_defs[i].name)
862 if (action_defs[i].id != i)
864 PERROR("Software Error action '%s' must have id of %d, but has %d.\n",
865 action_defs[i].name, i, action_defs[i].id);
871 while(param_defs[i].name)
873 if (param_defs[i].id != j)
875 PERROR("Software Error param '%s' must have id of 0x%llx, but has 0x%llx.\n",
876 param_defs[i].name, j, param_defs[i].id);
883 SPRINT(filename[0], "%s/routing.conf", INSTALL_DATA);
885 if (!(fp[0]=fopen(filename[0],"r")))
887 PERROR("Cannot open %s\n",filename[0]);
896 while((fgets(buffer,sizeof(buffer),fp[nesting])))
899 buffer[sizeof(buffer)-1]=0;
900 if (buffer[0]) buffer[strlen(buffer)-1]=0;
911 /* skip spaces, if any */
923 /* don't skip "define" */
924 if (!!strncmp(p, "define", 6))
937 p = read_string(p, key, sizeof(key), " ");
938 if (key[0] == 1) /* error */
940 SPRINT(failure, "Parsing Filename failed: %s", key+1);
943 if (nesting == MAXNESTING-1)
945 SPRINT(failure, "'include' is nesting too deep.\n");
949 SCPY(filename[nesting+1], key);
951 SPRINT(filename[nesting+1], "%s/%s", INSTALL_DATA, key);
952 if (!(fp[nesting+1]=fopen(filename[nesting+1],"r")))
954 PERROR("Cannot open %s\n", filename[nesting+1]);
961 if (*p == '/') if (p[1] == '/')
964 /* skip empty lines */
968 /* expecting ruleset */
975 SPRINT(failure, "Expecting ruleset name starting with '['.");
980 /* reading ruleset name text */
982 while((*p>='a' && *p<='z') || (*p>='A' && *p<='Z') || (*p>='0' && *p<='9'))
984 if (*p>='A' && *p<='Z') *p = *p-'A'+'a'; /* lower case */
986 if (i == sizeof(key)) i--; /* limit */
989 if (key[0] == '\0') {
990 SPRINT(failure, "Missing ruleset name after '['.");
994 /* expecting ] and nothing more */
996 SPRINT(failure, "Expecting ']' after ruleset name.");
1001 SPRINT(failure, "Unexpected character after ruleset name.");
1005 /* check for duplicate rulesets */
1006 ruleset = ruleset_start;
1009 if (!strcmp(ruleset->name, key))
1011 SPRINT(failure, "Duplicate ruleset '%s', already defined in file '%s' line %d.", key, ruleset->file, ruleset->line);
1014 ruleset = ruleset->next;
1017 /* create ruleset */
1018 ruleset = (struct route_ruleset *)malloc(sizeof(struct route_ruleset));
1019 if (ruleset == NULL)
1021 SPRINT(failure, "Out of memory.");
1025 memset(ruleset, 0, sizeof(struct route_ruleset));
1026 *ruleset_pointer = ruleset;
1027 ruleset_pointer = &(ruleset->next);
1028 SCPY(ruleset->name, key);
1029 SCPY(ruleset->file, filename[nesting]);
1030 ruleset->line = line[nesting];
1031 rule_pointer = &(ruleset->rule_first);
1036 /* for new ruleset [ */
1042 /* alloc memory for rule */
1043 rule = (struct route_rule *)malloc(sizeof(struct route_rule));
1046 SPRINT(failure, "Out of memory.");
1050 memset(rule, 0, sizeof(struct route_rule));
1051 *rule_pointer = rule;
1052 rule_pointer = &(rule->next);
1053 cond_pointer = &(rule->cond_first);
1054 action_pointer = &(rule->action_first);
1055 SCPY(rule->file, filename[nesting]);
1056 rule->line = line[nesting];
1058 /* loop CONDITIONS */
1059 while(*p!=':' && *p!='\0')
1061 /* read item text */
1063 while((*p>='a' && *p<='z') || (*p>='A' && *p<='Z') || (*p>='0' && *p<='9'))
1065 if (*p>='A' && *p<='Z') *p = *p-'A'+'a'; /* lower case */
1067 if (i == sizeof(key)) i--; /* limit */
1072 SPRINT(failure, "Expecting condition item name or ':' for end of condition list.");
1075 if (*p!=' ' && *p!='=')
1077 SPRINT(failure, "Illegal character '%c' after condition name '%s'. Expecting '=' for equation or ' ' to seperate condition items.", *p, key);
1081 /* check if condition exists */
1083 while(cond_defs[index].name)
1085 if (!strcmp(cond_defs[index].name, key))
1089 if (cond_defs[index].name == NULL)
1091 SPRINT(failure, "Unknown condition item name '%s'.", key);
1095 /* items without values must not have any parameter */
1096 if (cond_defs[index].type == COND_TYPE_NULL)
1100 SPRINT(failure, "Condition item '%s' must not have any value. Don't use '=' for this type of condition.", key);
1105 SPRINT(failure, "Condition item '%s' must not have any value. Expecting ' ' or tab after item name.", key);
1113 SPRINT(failure, "Condition item '%s' must have at least one value, '=' expected, and not a space.", key);
1118 SPRINT(failure, "Condition item '%s' must have at least one value, '=' expected.", key);
1124 /* check for duplicate condition */
1125 cond = rule->cond_first;
1128 if (cond->index == index)
1130 SPRINT(failure, "Duplicate condition '%s', use ',' to give multiple values.", key);
1137 /* alloc memory for item */
1138 cond = (struct route_cond *)malloc(sizeof(struct route_cond));
1141 SPRINT(failure, "Out of memory.");
1145 memset(cond, 0, sizeof(struct route_cond));
1146 *cond_pointer = cond;
1147 cond_pointer = &(cond->next);
1148 cond->index = index;
1149 cond->match = cond_defs[index].match;
1150 switch(cond_defs[index].type)
1152 case COND_TYPE_NULL:
1155 SPRINT(failure, "Expecting no value.");
1158 value_type = VALUE_TYPE_NULL;
1161 /* parse all integer values/ranges */
1162 case COND_TYPE_INTEGER:
1163 case COND_TYPE_TIME:
1164 case COND_TYPE_MDAY:
1165 case COND_TYPE_MONTH:
1166 case COND_TYPE_WDAY:
1167 case COND_TYPE_YEAR:
1168 integer = integer_to = 0;
1169 if (*p==',' || *p==' ' || *p=='\0')
1171 SPRINT(failure, "Missing integer value.");
1174 while(*p>='0' && *p<='9')
1176 integer = integer*10 + *p-'0';
1179 value_type = VALUE_TYPE_INTEGER;
1183 if (*p==',' || *p==' ' || *p=='\0')
1185 SPRINT(failure, "Missing integer value.");
1188 while(*p>='0' && *p<='9')
1190 integer_to = integer_to*10 + *p-'0';
1193 value_type = VALUE_TYPE_INTEGER_RANGE;
1195 if (cond_defs[index].type == COND_TYPE_TIME)
1197 // Simon: i store the time as decimal, later i compare it correctly:
1198 // hours * 100 + minutes
1199 if (integer == 2400)
1201 if (integer >= 2400)
1204 SPRINT(failure, "Given time '%d' not in range 0000..2359 (or 2400 for 0000)", integer);
1207 if (integer%100 >= 60)
1208 goto timeoutofrange1;
1209 if (value_type == VALUE_TYPE_INTEGER)
1211 if (integer_to == 2400)
1213 if (integer_to >= 2400)
1216 SPRINT(failure, "Given time '%d' not in range 0000..2359 (or 2400 for 0000)", integer_to);
1219 if (integer_to%100 >= 60)
1220 goto timeoutofrange2;
1222 if (cond_defs[index].type == COND_TYPE_MDAY)
1224 if (integer<1 || integer>31)
1226 SPRINT(failure, "Given day-of-month '%d' not in range 1..31", integer);
1229 if (value_type == VALUE_TYPE_INTEGER)
1231 if (integer_to<1 || integer_to>31)
1233 SPRINT(failure, "Given day-of-month '%d' not in range 1..31", integer_to);
1237 if (cond_defs[index].type == COND_TYPE_WDAY)
1239 if (integer<1 || integer>7)
1241 SPRINT(failure, "Given day-of-week '%d' not in range 1..7", integer);
1244 if (value_type == VALUE_TYPE_INTEGER)
1246 if (integer_to<1 || integer_to>7)
1248 SPRINT(failure, "Given day-of-week '%d' not in range 1..7", integer_to);
1252 if (cond_defs[index].type == COND_TYPE_MONTH)
1254 if (integer<1 || integer>12)
1256 SPRINT(failure, "Given month '%d' not in range 1..12", integer);
1259 if (value_type == VALUE_TYPE_INTEGER)
1261 if (integer_to<1 || integer_to>12)
1263 SPRINT(failure, "Given month '%d' not in range 1..12", integer_to);
1267 if (cond_defs[index].type == COND_TYPE_YEAR)
1269 if (integer<1970 || integer>2106)
1271 SPRINT(failure, "Given year '%d' not in range 1970..2106", integer);
1274 if (value_type == VALUE_TYPE_INTEGER)
1276 if (integer_to<1970 || integer_to>2106)
1278 SPRINT(failure, "Given year '%d' not in range 1970..2106", integer_to);
1283 cond->integer_value = integer;
1284 cond->integer_value_to = integer_to;
1285 cond->value_type = value_type;
1288 /* parse all string values/ranges */
1289 case COND_TYPE_STRING:
1290 key[0] = key_to[0] = '\0';
1291 if (*p==',' || *p==' ' || *p=='\0')
1293 SPRINT(failure, "Missing string value, use \"\" for empty string.");
1296 p = read_string(p, key, sizeof(key), "-, ");
1297 if (key[0] == 1) /* error */
1299 SPRINT(failure, "Parsing String failed: %s", key+1);
1302 value_type = VALUE_TYPE_STRING;
1306 if (*p==',' || *p==' ' || *p=='\0')
1308 SPRINT(failure, "Missing string value, use \"\" for empty string.");
1311 p = read_string(p, key_to, sizeof(key_to), "-, ");
1312 if (key_to[0] == 1) /* error */
1314 SPRINT(failure, "Parsing string failed: %s", key_to+1);
1317 value_type = VALUE_TYPE_STRING_RANGE;
1318 if (strlen(key) != strlen(key_to))
1320 SPRINT(failure, "Given range of strings \"%s\"-\"%s\" have unequal length.", key, key_to);
1325 SPRINT(failure, "Given range has no length.");
1330 cond->string_value = (char *)malloc(strlen(key)+1);
1331 if (cond->string_value == NULL)
1333 SPRINT(failure, "Out of memory.");
1337 UCPY(cond->string_value, key);
1338 if (value_type == VALUE_TYPE_STRING_RANGE)
1340 cond->string_value_to = (char *)malloc(strlen(key_to)+1);
1341 if (cond->string_value_to == NULL)
1343 SPRINT(failure, "Out of memory.");
1347 UCPY(cond->string_value_to, key_to);
1348 cond->comp_string = strcmp(key, key_to);
1350 cond->value_type = value_type;
1353 /* parse service value */
1354 case COND_TYPE_CAPABILITY:
1355 if (!strncasecmp("speech", p, 6))
1356 cond->integer_value = INFO_BC_SPEECH;
1357 else if (!strncasecmp("audio", p, 5))
1358 cond->integer_value = INFO_BC_AUDIO;
1359 else if (!strncasecmp("video", p, 5))
1360 cond->integer_value = INFO_BC_VIDEO;
1361 else if (!strncasecmp("digital-restricted", p, 18))
1362 cond->integer_value = INFO_BC_DATARESTRICTED;
1363 else if (!strncasecmp("digital-unrestricted", p, 20))
1364 cond->integer_value = INFO_BC_DATAUNRESTRICTED;
1365 else if (!strncasecmp("digital-unrestricted-tones", p, 26))
1366 cond->integer_value = INFO_BC_DATAUNRESTRICTED_TONES;
1369 SPRINT(failure, "Given service type is invalid or misspelled.");
1372 cond->value_type = VALUE_TYPE_INTEGER;
1375 /* parse bmode value */
1376 case COND_TYPE_BMODE:
1377 if (!strncasecmp("transparent", p, 11))
1378 cond->integer_value = INFO_BMODE_CIRCUIT;
1379 else if (!strncasecmp("hdlc", p, 4))
1380 cond->integer_value = INFO_BMODE_PACKET;
1383 SPRINT(failure, "Given bchannel mode is invalid or misspelled.");
1386 cond->value_type = VALUE_TYPE_INTEGER;
1389 /* parse interface attribute <if>:<value> */
1390 case COND_TYPE_IFATTR:
1391 key[0] = key_to[0] = '\0';
1392 if (*p==':' || *p==',' || *p==' ' || *p=='\0')
1394 SPRINT(failure, "Missing interface name.");
1397 p = read_string(p, key, sizeof(key), ":-, ");
1398 if (key[0] == 1) /* error */
1400 SPRINT(failure, "Parsing interface failed: %s", key+1);
1405 SPRINT(failure, "Expeciting kolon to seperate value behind interface name.");
1409 while(*p>='0' && *p<='9')
1413 if (*p!=',' && *p!=' ' && *p!='\0')
1415 SPRINT(failure, "Invalid characters behind value.");
1418 value_type = VALUE_TYPE_STRING;
1423 SPRINT(failure, "Software error: COND_TYPE_* %d not parsed in function '%s'", cond_defs[index].type, __FUNCTION__);
1426 /* if we have another value for that item, we attach it */
1431 cond->value_extension = 1;
1434 /* to seperate the items, a space is required */
1437 SPRINT(failure, "Character '%c' not expected here. Use ',' to seperate multiple possible values.", *p);
1449 /* we are done with CONDITIONS, so we expect the ACTION */
1452 SPRINT(failure, "Expecting ':' after condition item(s).");
1458 /* skip spaces, if any */
1466 /* read action name */
1468 while((*p>='a' && *p<='z') || (*p>='A' && *p<='Z') || (*p>='0' && *p<='9') || *p == '-')
1470 if (*p>='A' && *p<='Z') *p = *p-'A'+'a'; /* lower case */
1472 if (i == sizeof(key)) i--; /* limit */
1475 if (key[0] == '\0') {
1476 SPRINT(failure, "Expecting action name.");
1480 /* check if item exists */
1482 while(action_defs[index].name)
1484 if (!action_defs[index].help) /* not internal actions */
1489 if (!strcmp(action_defs[index].name, key))
1493 if (action_defs[index].name == NULL)
1495 SPRINT(failure, "Unknown action name '%s'.", key);
1499 /* alloc memory for action */
1500 action = (struct route_action *)malloc(sizeof(struct route_action));
1503 SPRINT(failure, "Out of memory.");
1507 memset(action, 0, sizeof(struct route_action));
1508 *action_pointer = action;
1509 action_pointer = &(action->next);
1510 param_pointer = &(action->param_first);
1511 action->index = index;
1512 action->line = line[nesting];
1514 /* skip spaces after param name */
1525 /* read param text */
1527 while((*p>='a' && *p<='z') || (*p>='A' && *p<='Z') || (*p>='0' && *p<='9'))
1529 if (*p>='A' && *p<='Z') *p = *p-'A'+'a'; /* lower case */
1531 if (i == sizeof(key)) i--; /* limit */
1534 if (key[0] == '\0') {
1535 SPRINT(failure, "Expecting parameter name.");
1539 /* check if item exists */
1541 while(param_defs[index].name)
1543 if (!strcmp(param_defs[index].name, key))
1547 if (param_defs[index].name == NULL)
1549 SPRINT(failure, "Unknown param name '%s'.", key);
1553 /* params without values must not have any parameter */
1554 if (param_defs[index].type == PARAM_TYPE_NULL)
1556 if (*p!=' ' && *p!='\0')
1558 SPRINT(failure, "Parameter '%s' must not have any value.", key);
1565 SPRINT(failure, "Parameter '%s' must have at least one value, '=' expected and not a space.", key);
1570 SPRINT(failure, "Parameter '%s' must have at least one value, '=' expected.", key);
1576 /* special timeout value */
1577 if (!strcmp("timeout", key))
1579 if (action->timeout)
1581 SPRINT(failure, "Duplicate timeout value.");
1584 if (*p==',' || *p==' ' || *p=='\0')
1586 SPRINT(failure, "Missing integer value.");
1590 while(*p>='0' && *p<='9')
1592 integer = integer*10 + *p-'0';
1597 SPRINT(failure, "Expecting timeout value greater 0.");
1600 if (*p!=' ' && *p!='\0')
1602 SPRINT(failure, "Character '%c' not expected here. Use ' ' to seperate parameters.", *p);
1612 action->timeout = integer;
1613 /* check for next ACTION */
1622 /* check for duplicate parameters */
1623 param = action->param_first;
1626 if (param->index == index)
1628 SPRINT(failure, "Duplicate parameter '%s', use ',' to give multiple values.", key);
1631 param = param->next;
1635 /* alloc memory for param */
1636 param = (struct route_param *)malloc(sizeof(struct route_param));
1639 SPRINT(failure, "Out of memory.");
1643 memset(param, 0, sizeof(struct route_param));
1644 *param_pointer = param;
1645 param_pointer = &(param->next);
1646 param->index = index;
1647 param->id = param_defs[index].id;
1649 switch(param_defs[index].type)
1651 /* parse null value */
1652 case PARAM_TYPE_NULL:
1653 param->value_type = VALUE_TYPE_NULL;
1656 /* parse integer value */
1657 case PARAM_TYPE_INTEGER:
1659 if (*p==',' || *p==' ' || *p=='\0')
1661 SPRINT(failure, "Missing integer value.");
1664 while(*p>='0' && *p<='9')
1666 integer = integer*10 + *p-'0';
1669 param->integer_value = integer;
1670 param->value_type = VALUE_TYPE_INTEGER;
1674 /* parse ports value */
1675 case PARAM_TYPE_PORTS:
1677 if (*p==',' || *p==' ' || *p=='\0')
1679 SPRINT(failure, "Missing port number, omit parameter or give port number.");
1685 while(*p>='0' && *p<='9')
1687 if (i < (int)sizeof(key)-1)
1692 integer = integer*10 + *p-'0';
1697 SPRINT(failure, "Port number too high.");
1702 if (i < (int)sizeof(key)-1)
1713 /* parse string value */
1714 case PARAM_TYPE_STRING:
1715 case PARAM_TYPE_CALLERIDTYPE:
1716 case PARAM_TYPE_CAPABILITY:
1717 case PARAM_TYPE_BMODE:
1718 case PARAM_TYPE_DIVERSION:
1719 case PARAM_TYPE_DESTIN:
1720 case PARAM_TYPE_TYPE:
1721 case PARAM_TYPE_YESNO:
1723 if (*p==',' || *p==' ' || *p=='\0')
1725 SPRINT(failure, "Missing string value, use \"\" for empty string.");
1728 p = read_string(p, key, sizeof(key), " ");
1729 if (key[0] == 1) /* error */
1731 SPRINT(failure, "Parsing string failed: %s", key+1);
1734 if (param_defs[index].type == PARAM_TYPE_CALLERIDTYPE)
1736 param->value_type = VALUE_TYPE_INTEGER;
1737 if (!strcasecmp(key, "unknown"))
1739 param->integer_value = INFO_NTYPE_UNKNOWN;
1742 if (!strcasecmp(key, "subscriber"))
1744 param->integer_value = INFO_NTYPE_SUBSCRIBER;
1747 if (!strcasecmp(key, "national"))
1749 param->integer_value = INFO_NTYPE_NATIONAL;
1752 if (!strcasecmp(key, "international"))
1754 param->integer_value = INFO_NTYPE_INTERNATIONAL;
1757 SPRINT(failure, "Caller ID type '%s' unknown.", key);
1760 if (param_defs[index].type == PARAM_TYPE_CAPABILITY)
1762 param->value_type = VALUE_TYPE_INTEGER;
1763 if (!strcasecmp(key, "speech"))
1765 param->integer_value = INFO_BC_SPEECH;
1768 if (!strcasecmp(key, "audio"))
1770 param->integer_value = INFO_BC_AUDIO;
1773 if (!strcasecmp(key, "video"))
1775 param->integer_value = INFO_BC_VIDEO;
1778 if (!strcasecmp(key, "digital-restricted"))
1780 param->integer_value = INFO_BC_DATARESTRICTED;
1783 if (!strcasecmp(key, "digital-unrestricted"))
1785 param->integer_value = INFO_BC_DATAUNRESTRICTED;
1788 if (!strcasecmp(key, "digital-unrestricted-tones"))
1790 param->integer_value = INFO_BC_DATAUNRESTRICTED_TONES;
1793 SPRINT(failure, "Service type '%s' unknown.", key);
1796 if (param_defs[index].type == PARAM_TYPE_BMODE)
1798 param->value_type = VALUE_TYPE_INTEGER;
1799 if (!strcasecmp(key, "transparent"))
1801 param->integer_value = INFO_BMODE_CIRCUIT;
1804 if (!strcasecmp(key, "hdlc"))
1806 param->integer_value = INFO_BMODE_PACKET;
1809 SPRINT(failure, "Bchannel mode '%s' unknown.", key);
1812 if (param_defs[index].type == PARAM_TYPE_DIVERSION)
1814 param->value_type = VALUE_TYPE_INTEGER;
1815 if (!strcasecmp(key, "cfu"))
1817 param->integer_value = INFO_DIVERSION_CFU;
1820 if (!strcasecmp(key, "cfb"))
1822 param->integer_value = INFO_DIVERSION_CFB;
1825 if (!strcasecmp(key, "cfnr"))
1827 param->integer_value = INFO_DIVERSION_CFNR;
1830 if (!strcasecmp(key, "cfp"))
1832 param->integer_value = INFO_DIVERSION_CFP;
1835 SPRINT(failure, "Diversion type '%s' unknown.", key);
1838 if (param_defs[index].type == PARAM_TYPE_TYPE)
1840 param->value_type = VALUE_TYPE_INTEGER;
1841 if (!strcasecmp(key, "unknown"))
1843 param->integer_value = INFO_NTYPE_UNKNOWN;
1846 if (!strcasecmp(key, "subscriber"))
1848 param->integer_value = INFO_NTYPE_SUBSCRIBER;
1851 if (!strcasecmp(key, "national"))
1853 param->integer_value = INFO_NTYPE_NATIONAL;
1856 if (!strcasecmp(key, "international"))
1858 param->integer_value = INFO_NTYPE_INTERNATIONAL;
1861 SPRINT(failure, "Number type '%s' unknown.", key);
1864 if (param_defs[index].type == PARAM_TYPE_YESNO)
1866 param->value_type = VALUE_TYPE_INTEGER;
1867 if (!strcasecmp(key, "yes"))
1869 param->integer_value = 1;
1872 if (!strcasecmp(key, "no"))
1874 param->integer_value = 0;
1877 SPRINT(failure, "Value '%s' unknown. ('yes' or 'no')", key);
1880 param->string_value = (char *)malloc(strlen(key)+1);
1881 if (param->string_value == NULL)
1883 SPRINT(failure, "Out of memory.");
1887 UCPY(param->string_value, key);
1888 param->value_type = VALUE_TYPE_STRING;
1892 SPRINT(failure, "Software error: PARAM_TYPE_* %d not parsed in function '%s'", param_defs[index].type, __FUNCTION__);
1900 param->value_extension = 1;
1901 goto nextparamvalue;
1908 /* to seperate the items, a space is required */
1911 SPRINT(failure, "Character '%c' not expected here. Use ' ' to seperate parameters, or ',' for multiple values.", *p);
1922 /* check for next ACTION */
1931 fclose(fp[nesting--]);
1939 SPRINT(failure, "No ruleset defined.");
1941 return(ruleset_start);
1944 printf("While parsing %s, an error occurred in line %d:\n", filename[nesting], line[nesting]);
1945 printf("-> %s\n", buffer);
1946 memset(pointer, ' ', sizeof(pointer));
1947 pointer[p-buffer] = '^';
1948 pointer[p-buffer+1] = '\0';
1949 printf(" %s\n", pointer);
1950 printf("%s\n", failure);
1951 SPRINT(ruleset_error, "Error in file %s, line %d: %s", filename[nesting], line[nesting], failure);
1956 fclose(fp[nesting--]);
1960 ruleset_free(ruleset_start);
1965 * return ruleset by name
1967 struct route_ruleset *getrulesetbyname(char *name)
1969 struct route_ruleset *ruleset = ruleset_first;
1973 if (!strcasecmp(name, ruleset->name))
1977 ruleset = ruleset->next;
1979 PDEBUG(DEBUG_ROUTE, "ruleset %s %s.\n", name, ruleset?"found":"not found");
1984 * parses the current ruleset and returns action
1986 struct route_action *EndpointAppPBX::route(struct route_ruleset *ruleset)
1989 couldmatch = 0, /* any rule could match */
1996 struct route_rule *rule = ruleset->rule_first;
1997 struct route_cond *cond;
1998 struct route_action *action = NULL;
1999 unsigned long comp_len;
2001 char callerid[64], redirid[64];
2006 struct mISDNport *mISDNport;
2008 /* reset timeout action */
2009 e_match_timeout = 0; /* no timeout */
2010 e_match_to_action = NULL;
2012 SCPY(callerid, numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype));
2013 SCPY(redirid, numberrize_callerinfo(e_redirinfo.id, e_redirinfo.ntype));
2015 PDEBUG(DEBUG_ROUTE, "parsing ruleset '%s'\n", ruleset->name);
2018 PDEBUG(DEBUG_ROUTE, "checking rule in line %d\n", rule->line);
2019 match = 1; /* this rule matches */
2020 dialing_required = 0;
2021 timeout = 0; /* timeout time */
2022 cond = rule->cond_first;
2025 condition = 0; /* any condition element is true (1) or could be true (2) */
2027 istrue = 0; /* this condition-element is true */
2028 couldbetrue = 0; /* this conditions-element could be true */
2042 // printf("\n\n\nport-type %x\n\n\n\n", ea_endpoint->ep_portlist->port_type);
2043 if (ea_endpoint->ep_portlist)
2044 if (ea_endpoint->ep_portlist->port_type == PORT_TYPE_H323_IN)
2049 if (ea_endpoint->ep_portlist)
2050 if ((ea_endpoint->ep_portlist->port_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_mISDN_DSS1)
2052 integer = e_callerinfo.isdn_port;
2055 case MATCH_INTERFACE:
2056 if (!e_callerinfo.interface[0])
2058 string = e_callerinfo.interface;
2059 goto match_string_prefix;
2061 case MATCH_CALLERID:
2063 goto match_string_prefix;
2065 case MATCH_EXTENSION:
2066 string = e_ext.name;
2070 string = e_dialinginfo.number;
2071 goto match_string_prefix;
2083 case MATCH_ANONYMOUS:
2084 if (e_callerinfo.present != INFO_PRESENT_ALLOWED)
2089 if (e_callerinfo.present == INFO_PRESENT_ALLOWED)
2094 if (e_callerinfo.present == INFO_PRESENT_NOTAVAIL)
2098 case MATCH_AVAILABLE:
2099 if (e_callerinfo.present != INFO_PRESENT_NOTAVAIL)
2104 if (e_callerinfo.screen == INFO_SCREEN_USER)
2109 if (e_callerinfo.screen != INFO_SCREEN_USER)
2113 case MATCH_REDIRECTED:
2114 if (e_redirinfo.present != INFO_PRESENT_NULL)
2119 if (e_redirinfo.present == INFO_PRESENT_NULL)
2125 goto match_string_prefix;
2128 integer = now_tm->tm_hour*100 + now_tm->tm_min;
2132 integer = now_tm->tm_mday;
2136 integer = now_tm->tm_mon+1;
2140 integer = now_tm->tm_year + 1900;
2144 integer = now_tm->tm_wday;
2145 integer = integer?integer:7; /* correct sunday */
2148 case MATCH_CAPABILITY:
2149 integer = e_capainfo.bearer_capa;
2152 case MATCH_INFOLAYER1:
2153 integer = e_capainfo.bearer_info1;
2157 integer = e_capainfo.hlc;
2161 tfp = fopen(cond->string_value, "r");
2166 if (fgetc(tfp) == '1')
2172 if (system(cond->string_value) == 0)
2182 timeout = now_d + cond->integer_value;
2188 if (!(comp_len = (unsigned long)strchr(cond->string_value, ':')))
2190 comp_len = comp_len-(unsigned long)cond->string_value;
2192 mISDNport = mISDNport_first;
2195 if (mISDNport->ifport)
2196 if (strlen(mISDNport->ifport->interface->name) == comp_len)
2197 if (!strncasecmp(mISDNport->ifport->interface->name, cond->string_value, comp_len))
2198 if (!mISDNport->ptp || mISDNport->l2link)
2201 jj = mISDNport->b_num;
2205 if (mISDNport->b_state[j])
2210 mISDNport = mISDNport->next;
2212 if (cond->match == MATCH_FREE)
2214 if (avail >= atoi(cond->string_value + comp_len + 1))
2218 if (avail < atoi(cond->string_value + comp_len + 1))
2225 mISDNport = mISDNport_first;
2228 if (mISDNport->ifport)
2229 if (!strcasecmp(mISDNport->ifport->interface->name, cond->string_value))
2230 if (!mISDNport->ptp || mISDNport->l2link) /* break if one is up */
2232 mISDNport = mISDNport->next;
2234 if (!mISDNport) /* all down */
2239 mISDNport = mISDNport_first;
2242 if (mISDNport->ifport)
2243 if (!strcasecmp(mISDNport->ifport->interface->name, cond->string_value))
2244 if (!mISDNport->ptp || mISDNport->l2link) /* break if one is up */
2247 mISDNport = mISDNport->next;
2249 if (mISDNport) /* one link at least */
2255 mISDNport = mISDNport_first;
2258 if (mISDNport->ifport)
2259 if (!strcasecmp(mISDNport->ifport->interface->name, cond->string_value))
2260 if (mISDNport->use) /* break if in use */
2262 mISDNport = mISDNport->next;
2269 mISDNport = mISDNport_first;
2272 if (mISDNport->ifport)
2273 if (!strcasecmp(mISDNport->ifport->interface->name, cond->string_value))
2274 if (mISDNport->use) /* break if in use */
2276 mISDNport = mISDNport->next;
2283 PERROR("Software error: MATCH_* %d not parsed in function '%s'", cond->match, __FUNCTION__);
2287 if (cond->value_type == VALUE_TYPE_INTEGER)
2289 if (integer != cond->integer_value)
2294 if (cond->value_type == VALUE_TYPE_INTEGER_RANGE)
2296 /* check if negative range (2100 - 700 o'clock) */
2297 if (cond->integer_value > cond->integer_value_to)
2299 if (integer>=cond->integer_value && integer<=cond->integer_value_to)
2303 /* range is positive */
2304 if (integer>=cond->integer_value && integer<=cond->integer_value_to)
2311 if (strlen(cond->string_value) != strlen(string))
2314 match_string_prefix:
2315 comp_len = strlen(cond->string_value); /* because we must reach value's length */
2316 /* we must have greater or equal length to values */
2317 if ((unsigned long)strlen(string) < comp_len)
2319 /* special case for unfinished dialing */
2320 if (cond->match == MATCH_DIALING)
2322 couldbetrue = 1; /* could match */
2323 comp_len = strlen(string);
2329 /* on single string match */
2330 if (cond->value_type == VALUE_TYPE_STRING)
2332 if (!strncmp(string, cond->string_value, comp_len))
2335 /* must be set for changing 'e_extdialing' */
2336 if (cond->match == MATCH_DIALING)
2337 dialing_required = comp_len;
2342 /* on range match */
2343 if (cond->value_type == VALUE_TYPE_STRING_RANGE)
2345 /* check if negative range ("55"-"22") */
2346 if (cond->comp_string > 0)
2348 if (strncmp(string, cond->string_value, comp_len) >= 0)
2351 /* must be set for changing 'e_extdialing' */
2352 if (cond->match == MATCH_DIALING)
2353 dialing_required = comp_len;
2356 if (strncmp(string, cond->string_value_to, comp_len) <= 0)
2358 /* must be set for changing 'e_extdialing' */
2360 if (cond->match == MATCH_DIALING)
2361 dialing_required = comp_len;
2366 /* range is positive */
2367 if (strncmp(string, cond->string_value, comp_len) < 0)
2369 if (strncmp(string, cond->string_value_to, comp_len) > 0)
2372 if (cond->match == MATCH_DIALING)
2373 dialing_required = comp_len;
2379 /* set current condition */
2380 if (istrue && !couldbetrue)
2381 condition = 1; /* element matches, so condition matches */
2382 if (istrue && couldbetrue && !condition)
2383 condition = 2; /* element could match and other elements don't match, so condition could match */
2385 /* if not matching or could match */
2388 /* if we have more values to check */
2389 if (cond->value_extension && cond->next)
2392 goto checkextension;
2398 /* skip exteded values, beacuse we already have one matching value */
2399 while(cond->value_extension && cond->next)
2404 if (timeout>now_d && match==1) /* the matching rule with timeout in the future */
2405 if (e_match_timeout<1 || timeout<e_match_timeout) /* first timeout or lower */
2407 /* set timeout in the furture */
2408 e_match_timeout = timeout;
2409 e_match_to_action = rule->action_first;
2410 e_match_to_extdialing = e_dialinginfo.number + dialing_required;
2411 match = 0; /* matches in the future */
2415 /* matching, we return first action */
2416 action = rule->action_first;
2417 e_match_timeout = 0; /* no timeout */
2418 e_match_to_action = NULL;
2419 e_extdialing = e_dialinginfo.number + dialing_required;
2424 /* rule could match if more is dialed */
2433 * parses the current action's parameters and return them
2435 struct route_param *EndpointAppPBX::routeparam(struct route_action *action, unsigned long long id)
2437 struct route_param *param = action->param_first;
2441 if (param->id == id)
2443 param = param->next;
2450 * internal rules that are not defined by route.conf
2452 struct route_action action_password = {
2460 struct route_action action_password_write = {
2463 ACTION_PASSWORD_WRITE,
2468 struct route_action action_external = {
2476 struct route_action action_internal = {
2484 struct route_action action_h323 = {
2492 struct route_action action_chan = {
2500 struct route_action action_vbox = {
2508 struct route_action action_partyline = {
2516 struct route_action action_disconnect = {