38f1f7ea1b653c72ed26076f25d289164804f195
[lcr.git] / route.c
1 /*****************************************************************************\ 
2 **                                                                           **
3 ** PBX4Linux                                                                 **
4 **                                                                           **
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg                                              **
7 **                                                                           **
8 ** match processing of routing configuration                                 **
9 **                                                                           **
10 \*****************************************************************************/ 
11
12 #include <stdio.h>
13 #include <string.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include "main.h"
17
18
19 struct route_ruleset    *ruleset_first;         /* first entry */
20 struct route_ruleset    *ruleset_main;          /* pointer to main ruleset */
21
22 struct cond_defs cond_defs[] = {
23 #ifdef PBX
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."},
28 #endif
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."},
101         { NULL, 0, 0, NULL}
102 };
103
104 struct param_defs param_defs[] = {
105         { PARAM_PROCEEDING,
106           "proceeding", PARAM_TYPE_NULL,
107           "proceeding", "Will set the call into 'proceeding' state to prevent dial timeout."},
108         { PARAM_ALERTING,
109           "alerting",   PARAM_TYPE_NULL,
110           "alerting", "Will set the call into 'altering' state."},
111         { PARAM_CONNECT,
112           "connect",    PARAM_TYPE_NULL,
113           "connect", "Will complete the call before processing the action. Audio path for external calls will be established."},
114 #ifdef PBX
115         { PARAM_EXTENSION,
116           "extension",  PARAM_TYPE_STRING,
117           "extension=<digits>", "Give extension name (digits) to relate this action to."},
118         { PARAM_EXTENSIONS,
119           "extensions", PARAM_TYPE_STRING,
120           "extensions=<extension>[,<extension>[,...]]", "One or more extensions may be given."},
121 #endif
122         { PARAM_PREFIX,
123           "prefix",     PARAM_TYPE_STRING,
124           "prefix=<digits>", "Add prefix in front of the dialed number."},
125         { PARAM_CAPA,
126           "capability", PARAM_TYPE_CAPABILITY,
127           "capability=speech|audio|video|digital-restricted|digital-unrestricted|digital-unrestricted-tones", "Alter the service type of the call."},
128         { PARAM_BMODE,
129           "bmode",      PARAM_TYPE_BMODE,
130           "capability=transparent|hdlc", "Alter the bchannel mode of the call. Use hdlc for data calls."},
131         { PARAM_INFO1,
132           "infolayer1", PARAM_TYPE_INTEGER,
133           "infolayer1=<value>", "Alter the layer 1 information of a call. Use 3 for ALAW or 2 for uLAW."},
134         { PARAM_HLC,
135           "hlc",        PARAM_TYPE_INTEGER,
136           "hlc=<value>", "Alter the HLC identification. Use 1 for telephony or omit."},
137         { PARAM_EXTHLC,
138           "exthlc",     PARAM_TYPE_INTEGER,
139           "exthlc=<value>", "Alter extended HLC value. (Mainenance only, don't use it.)"},
140         { PARAM_PRESENT,
141           "present",    PARAM_TYPE_YESNO,
142           "present=yes|no", "Allow or restrict caller ID regardless what the caller wants."},
143         { PARAM_DIVERSION,
144           "diversion",  PARAM_TYPE_DIVERSION,
145           "diversion=cfu|cfnr|cfb|cfp", "Set diversion type."},
146         { PARAM_DEST,
147           "dest",       PARAM_TYPE_DESTIN,
148           "dest=<string>", "Destination number to divert to. Use 'vbox' to divert to vbox. (cfu,cfnr,cfb only)"},
149         { PARAM_SELECT,
150           "select",     PARAM_TYPE_NULL,
151           "select", "Lets the caller select the history of calls using keys '1'/'3' or '*'/'#'."},
152         { PARAM_DELAY,
153           "delay",      PARAM_TYPE_INTEGER,
154           "delay=<seconds>", "Number of seconds to delay."},
155         { PARAM_LIMIT,
156           "limit",      PARAM_TYPE_INTEGER,
157           "limit=<retries>", "Number of maximum retries."},
158         { PARAM_HOST,
159           "host",       PARAM_TYPE_STRING,
160           "host=<string>", "Name of remote VoIP host."},
161         { PARAM_PORT,
162           "port",       PARAM_TYPE_STRING,
163           "port=<value>", "Alternate port to use if 'host' is given."},
164         { PARAM_INTERFACES,
165           "interfaces", PARAM_TYPE_STRING,
166           "interfaces=<interface>[,<interface>[,...]]", "Give one or a list of Interfaces to select a free channel from."},
167         { PARAM_ADDRESS,
168           "address",    PARAM_TYPE_STRING,
169           "address=<string>", "Complete VoIP address. ( [user@]host[:port] )"},
170         { PARAM_SAMPLE,
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."},
173 #ifdef PBX
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."},
177 #endif
178         { PARAM_RULESET,
179           "ruleset",    PARAM_TYPE_STRING,
180           "ruleset=<name>", "Ruleset to go to."},
181         { PARAM_CAUSE,
182           "cause",      PARAM_TYPE_INTEGER,
183           "cause=<cause value>", "Cause value when disconnecting. (21=reject 1=unassigned 63=service not available)"},
184         { PARAM_LOCATION,
185           "location",   PARAM_TYPE_INTEGER,
186           "location=<location value>", "Location of cause value when disconnecting. (0=user 1=private network sering local user)"},
187         { PARAM_DISPLAY,
188           "display",    PARAM_TYPE_STRING,
189           "display=<text>", "Message to display on the caller's telephone. (internal only)"},
190         { PARAM_PORTS,
191           "ports",      PARAM_TYPE_INTEGER,
192           "ports=<port>[,<port>[,...]]", "ISDN port[s] to use."},
193         { PARAM_TPRESET,
194           "tpreset",    PARAM_TYPE_INTEGER,
195           "tpreset=<seconds>", "Preset of countdown timer."},
196         { PARAM_FILE,
197           "file",       PARAM_TYPE_STRING,
198           "file=<full path>", "Full path to file name."},
199         { PARAM_CONTENT,
200           "content",    PARAM_TYPE_STRING,
201           "content=<string>", "Content to write into file."},
202         { PARAM_APPEND,
203           "append",     PARAM_TYPE_NULL,
204           "append", "Will append to given file, rather than overwriting it."},
205         { PARAM_EXECUTE,
206           "execute",    PARAM_TYPE_STRING,
207           "execute=<full path>", "Full path to script/command name. (Dialed digits are the argument 1.)"},
208         { PARAM_PARAM,
209           "param",      PARAM_TYPE_STRING,
210           "param=<string>", "Optionally this parameter can be inserted as argument 1, others are shifted."},
211         { PARAM_TYPE,
212           "type",       PARAM_TYPE_TYPE,
213           "type=unknown|subscriber|national|international", "Type of number to dial, default is 'unknown'."},
214         { PARAM_COMPLETE,
215           "complete",   PARAM_TYPE_NULL,
216           "complete", "Indicates complete number as given by prefix. Proceeding of long distance calls may be faster."},
217         { PARAM_CALLERID,
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'"},
223         { PARAM_CALLTO,
224           "callto",     PARAM_TYPE_STRING,
225           "callto=<digits>", "Where to call back. By default the caller ID is used."},
226         { PARAM_ROOM,
227           "room",       PARAM_TYPE_INTEGER,
228           "room=<digits>", "Conference room number, must be greater 0, as in real life."},
229         { PARAM_TIMEOUT,
230           "timeout",    PARAM_TYPE_INTEGER,
231           "timeout=<seconds>", "Timeout before continue with next action."},
232 #ifdef PBX
233         { PARAM_NOPASSWORD,
234           "nopassword", PARAM_TYPE_NULL,
235           "nopassword", "Don't ask for password. Be sure to authenticate right via real caller ID."},
236 #endif
237         { 0, NULL, 0, NULL, NULL}
238 };
239
240 struct action_defs action_defs[] = {
241         { ACTION_EXTERNAL,
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."},
245         { ACTION_INTERNAL,
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."},
249         { ACTION_OUTDIAL,
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,
252           "Same as 'extern'"},
253         { ACTION_H323,
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."},
257         { ACTION_CHAN,
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."},
265         { ACTION_PARTYLINE,
266           "partyline",&EndpointAppPBX::action_init_partyline, NULL, &EndpointAppPBX::action_hangup_call,
267           PARAM_ROOM,
268           "Caller is participating the conference with the given room number."},
269         { ACTION_LOGIN,
270           "login",      NULL, &EndpointAppPBX::action_dialing_login, NULL,
271           PARAM_CONNECT | PARAM_EXTENSION | PARAM_NOPASSWORD,
272           "Log into the given extension. Password required."},
273         { ACTION_CALLERID,
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."},
281         { ACTION_FORWARD,
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."},
285         { ACTION_REDIAL,
286           "redial",     &EndpointAppPBX::action_init_redial_reply, &EndpointAppPBX::action_dialing_redial, NULL,
287           PARAM_CONNECT | PARAM_SELECT,
288           "Caller redials. (last outgoing call(s))"},
289         { ACTION_REPLY,
290           "reply",      &EndpointAppPBX::action_init_redial_reply, &EndpointAppPBX::action_dialing_reply, NULL,
291           PARAM_CONNECT | PARAM_SELECT,
292           "Caller replies. (last incomming call(s))"},
293         { ACTION_POWERDIAL,
294           "powerdial",  NULL, &EndpointAppPBX::action_dialing_powerdial, NULL,
295           PARAM_CONNECT | PARAM_DELAY | PARAM_LIMIT | PARAM_TIMEOUT,
296           "Caller redials using powerdialing."},
297         { ACTION_CALLBACK,
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."},
301         { ACTION_ABBREV,
302           "abbrev",     NULL, &EndpointAppPBX::action_dialing_abbrev, NULL,
303           PARAM_CONNECT,
304           "Caller dials abbreviation."},
305         { ACTION_TEST,
306           "test",       NULL, &EndpointAppPBX::action_dialing_test, NULL,
307           PARAM_CONNECT | PARAM_PREFIX | PARAM_TIMEOUT,
308           "Caller dials test mode."},
309         { ACTION_PLAY,
310           "play",       &EndpointAppPBX::action_init_play, NULL, NULL,
311           PARAM_PROCEEDING | PARAM_ALERTING | PARAM_CONNECT | PARAM_SAMPLE | PARAM_TIMEOUT,
312           "Plays the given sample."},
313         { ACTION_VBOX_PLAY,
314           "vbox-play",  &EndpointAppPBX::action_init_vbox_play, &EndpointAppPBX::action_dialing_vbox_play, NULL,
315           PARAM_EXTENSION,
316           "Caller listens to her voice box or to given extension."},
317         { ACTION_CALCULATOR,
318           "calculator", NULL, &EndpointAppPBX::action_dialing_calculator, NULL,
319           PARAM_CONNECT,
320           "Caller calls the calculator."},
321         { ACTION_TIMER,
322           "timer",      NULL, &EndpointAppPBX::action_dialing_timer, NULL,
323           PARAM_CONNECT | PARAM_TPRESET | PARAM_TIMEOUT,
324           NULL},
325 //        "Caller calls the timer."},
326         { ACTION_GOTO,
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."},
330         { ACTION_MENU,
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."},
334         { ACTION_DISCONNECT,
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."},
338         { ACTION_HELP,
339           "help",       NULL, &EndpointAppPBX::action_dialing_help, NULL,
340           PARAM_CONNECT | PARAM_TIMEOUT,
341           NULL},
342 //        "Caller will be able to select from current rules that would match. (using * and #)"},
343         { ACTION_DEFLECT,
344           "deflect",    NULL, &EndpointAppPBX::action_dialing_deflect, NULL,
345           PARAM_DEST,
346           NULL},
347 //        "External call is deflected to the given destination within the telephone network."},
348         { ACTION_SETFORWARD,
349           "setforward", NULL, &EndpointAppPBX::action_dialing_setforward, NULL,
350           PARAM_CONNECT | PARAM_DIVERSION | PARAM_DEST | PARAM_PORT,
351           NULL},
352 //        "The call forward is set within the telephone network of the external line."},
353         { ACTION_EXECUTE,
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."},
357         { ACTION_FILE,
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."},
361         { ACTION_PICK,
362           "pick",       &EndpointAppPBX::action_init_pick, NULL, NULL,
363           PARAM_EXTENSIONS,
364           "Pick up a call that is ringing on any phone. Extensions may be given to limit the picking ability."},
365         { ACTION_PASSWORD,
366           "password",   NULL, &EndpointAppPBX::action_dialing_password, NULL,
367           0,
368           NULL},
369         { ACTION_PASSWORD_WRITE,
370           "password_wr",NULL, &EndpointAppPBX::action_dialing_password_wr, NULL,
371           0,
372           NULL},
373         { ACTION_NOTHING,
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."},
377         { ACTION_EFI,
378           "efi",        &EndpointAppPBX::action_init_efi, NULL, NULL,
379           PARAM_PROCEEDING | PARAM_ALERTING | PARAM_CONNECT,
380           "Elektronische Fernsprecher Identifikation."},
381         { -1,
382           NULL, NULL, NULL, NULL, 0, NULL}
383 };
384
385
386 /* display documentation of rules */
387
388 void doc_rules(const char *name)
389 {
390         int i, j;
391
392         if (name)
393         {
394                 i = 0;
395                 while(action_defs[i].name)
396                 {
397                         if (!strcasecmp(action_defs[i].name, name))
398                                 break;
399                         i++;
400                 }
401                 if (!action_defs[i].name)
402                 {
403                         fprintf(stderr, "Given action '%s' unknown.\n", name);
404                         return;
405                 }
406                 name = action_defs[i].name;
407         }
408
409         printf("Syntax overview:\n");
410         printf("----------------\n\n");
411         printf("[ruleset]\n");
412         printf("<condition> ...   : <action> [parameter ...]   [timeout=X : <action> ...]\n");
413         printf("...\n");
414         printf("Please refer to the documentation for description on rule format.\n\n");
415
416         if (!name)
417         {
418                 printf("Available conditions to match:\n");
419                 printf("------------------------------\n\n");
420                 i = 0;
421                 while(cond_defs[i].name)
422                 {
423                         printf("Usage: %s\n", cond_defs[i].doc);
424                         printf("%s\n\n", cond_defs[i].help);
425                         i++;
426                 }
427
428                 printf("Available actions with their parameters:\n");
429                 printf("----------------------------------------\n\n");
430         } else
431         {
432                 printf("Detailes parameter description of action:\n");
433                 printf("-----------------------------------------\n\n");
434         }
435         i = 0;
436         while(action_defs[i].name)
437         {
438                 if (name && !!strcmp(action_defs[i].name,name)) /* not selected */
439                 {
440                         i++;
441                         continue;
442                 }
443                 if (!action_defs[i].help) /* not internal actions */
444                 {
445                         i++;
446                         continue;
447                 }
448                 printf("Usage: %s", action_defs[i].name);
449                 j = 0;
450                 while(j < 64)
451                 {
452                         if ((1LL<<j) & action_defs[i].params)
453                                 printf(" [%s]", param_defs[j].doc);
454                         j++;
455                 }
456                 printf("\n%s\n\n", action_defs[i].help);
457                 if (name) /* only show parameter help for specific action */
458                 {
459                         j = 0;
460                         while(j < 64)
461                         {
462                                 if ((1LL<<j) & action_defs[i].params)
463                                         printf("%s:\n\t%s\n", param_defs[j].doc, param_defs[j].help);
464                                 j++;
465                         }
466                         printf("\n");
467                 }
468                 i++;
469         }
470 }
471
472 void ruleset_free(struct route_ruleset *ruleset_start)
473 {
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;
479
480         while(ruleset_start)
481         {
482                 ruleset = ruleset_start;
483                 ruleset_start = ruleset->next;
484                 while(ruleset->rule_first)
485                 {
486                         rule = ruleset->rule_first;
487                         ruleset->rule_first = rule->next;
488                         while(rule->cond_first)
489                         {
490                                 cond = rule->cond_first;
491                                 if (cond->string_value)
492                                 {
493                                         free(cond->string_value);
494                                         rmemuse--;
495                                 }
496                                 if (cond->string_value_to)
497                                 {
498                                         free(cond->string_value_to);
499                                         rmemuse--;
500                                 }
501                                 rule->cond_first = cond->next;
502                                 free(cond);
503                                 rmemuse--;
504                         }
505                         while(rule->action_first)
506                         {
507                                 action = rule->action_first;
508                                 rule->action_first = action->next;
509                                 while(action->param_first)
510                                 {
511                                         param = action->param_first;
512                                         action->param_first = param->next;
513                                         if (param->string_value)
514                                         {
515                                                 free(param->string_value);
516                                                 rmemuse--;
517                                         }
518                                         free(param);
519                                         rmemuse--;
520                                 }
521                                 free(action);
522                                 rmemuse--;
523                         }
524                         free(rule);
525                         rmemuse--;
526                 }
527                 free(ruleset);
528                 rmemuse--;
529         }
530 }
531
532 void ruleset_debug(struct route_ruleset *ruleset_start)
533 {
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;
539         int                     first;
540
541         ruleset = ruleset_start;
542         while(ruleset)
543         {
544                 printf("Ruleset: '%s'\n", ruleset->name);
545                 rule = ruleset->rule_first;
546                 while(rule)
547                 {
548                         /* CONDITION */
549                         first = 1;
550                         cond = rule->cond_first;
551                         while(cond)
552                         {
553                                 if (first)
554                                         printf("    Condition:");
555                                 else
556                                         printf("    and       ");
557                                 first = 0;
558                                 printf(" %s", cond_defs[cond->index].name);
559                                 if (cond->value_type != VALUE_TYPE_NULL)
560                                         printf(" = ");
561                                 next_cond_value:
562                                 switch(cond->value_type)
563                                 {
564                                         case VALUE_TYPE_NULL:
565                                         break;
566
567                                         case VALUE_TYPE_INTEGER:
568                                         printf("%d", cond->integer_value);
569                                         break;
570
571                                         case VALUE_TYPE_INTEGER_RANGE:
572                                         printf("%d-%d", cond->integer_value, cond->integer_value_to);
573                                         break;
574
575                                         case VALUE_TYPE_STRING:
576                                         printf("'%s'", cond->string_value);
577                                         break;
578
579                                         case VALUE_TYPE_STRING_RANGE:
580                                         printf("'%s'-'%s'", cond->string_value, cond->string_value_to);
581                                         break;
582
583                                         default:
584                                         printf("Software error: VALUE_TYPE_* %d not known in function '%s' line=%d", cond->value_type, __FUNCTION__, __LINE__);
585                                 }
586                                 if (cond->value_extension && cond->next)
587                                 {
588                                         cond = cond->next;
589                                         printf(" or ");
590                                         goto next_cond_value;
591                                 }
592
593                                 cond = cond->next;
594                                 printf("\n");
595                         }
596
597                         /* ACTION */
598                         action = rule->action_first;
599                         while(action)
600                         {
601                                 printf("    Action: %s\n", action_defs[action->index].name);
602                                 /* PARAM */
603                                 first = 1;
604                                 param = action->param_first;
605                                 while(param)
606                                 {
607                                         if (first)
608                                                 printf("    Param:");
609                                         else
610                                                 printf("          ");
611                                         first = 0;
612                                         printf(" %s", param_defs[param->index].name);
613                                         if (param->value_type != VALUE_TYPE_NULL)
614                                                 printf(" = ");
615                                         switch(param->value_type)
616                                         {
617                                                 case VALUE_TYPE_NULL:
618                                                 break;
619
620                                                 case VALUE_TYPE_INTEGER:
621                                                 if (param_defs[param->index].type == PARAM_TYPE_CALLERIDTYPE)
622                                                 {
623                                                         switch(param->integer_value)
624                                                         {
625                                                                 case INFO_NTYPE_UNKNOWN:
626                                                                 printf("unknown");
627                                                                 break;
628                                                                 case INFO_NTYPE_SUBSCRIBER:
629                                                                 printf("subscriber");
630                                                                 break;
631                                                                 case INFO_NTYPE_NATIONAL:
632                                                                 printf("national");
633                                                                 break;
634                                                                 case INFO_NTYPE_INTERNATIONAL:
635                                                                 printf("international");
636                                                                 break;
637                                                                 default:
638                                                                 printf("unknown(%d)", param->integer_value);
639                                                         }
640                                                         break;
641                                                 }
642                                                 if (param_defs[param->index].type == PARAM_TYPE_CAPABILITY)
643                                                 {
644                                                         switch(param->integer_value)
645                                                         {
646                                                                 case INFO_BC_SPEECH:
647                                                                 printf("speech");
648                                                                 break;
649                                                                 case INFO_BC_AUDIO:
650                                                                 printf("audio");
651                                                                 break;
652                                                                 case INFO_BC_VIDEO:
653                                                                 printf("video");
654                                                                 break;
655                                                                 case INFO_BC_DATARESTRICTED:
656                                                                 printf("digital-restricted");
657                                                                 break;
658                                                                 case INFO_BC_DATAUNRESTRICTED:
659                                                                 printf("digital-unrestricted");
660                                                                 break;
661                                                                 case INFO_BC_DATAUNRESTRICTED_TONES:
662                                                                 printf("digital-unrestricted-tones");
663                                                                 break;
664                                                                 default:
665                                                                 printf("unknown(%d)", param->integer_value);
666                                                         }
667                                                         break;
668                                                 }
669                                                 if (param_defs[param->index].type == PARAM_TYPE_DIVERSION)
670                                                 {
671                                                         switch(param->integer_value)
672                                                         {
673                                                                 case INFO_DIVERSION_CFU:
674                                                                 printf("cfu");
675                                                                 break;
676                                                                 case INFO_DIVERSION_CFNR:
677                                                                 printf("cfnr");
678                                                                 break;
679                                                                 case INFO_DIVERSION_CFB:
680                                                                 printf("cfb");
681                                                                 break;
682                                                                 case INFO_DIVERSION_CFP:
683                                                                 printf("cfp");
684                                                                 break;
685                                                                 default:
686                                                                 printf("unknown(%d)", param->integer_value);
687                                                         }
688                                                         break;
689                                                 }
690                                                 if (param_defs[param->index].type == PARAM_TYPE_TYPE)
691                                                 {
692                                                         switch(param->integer_value)
693                                                         {
694                                                                 case INFO_NTYPE_UNKNOWN:
695                                                                 printf("unknown");
696                                                                 break;
697                                                                 case INFO_NTYPE_SUBSCRIBER:
698                                                                 printf("subscriber");
699                                                                 break;
700                                                                 case INFO_NTYPE_NATIONAL:
701                                                                 printf("national");
702                                                                 break;
703                                                                 case INFO_NTYPE_INTERNATIONAL:
704                                                                 printf("international");
705                                                                 break;
706                                                                 default:
707                                                                 printf("unknown(%d)", param->integer_value);
708                                                         }
709                                                         break;
710                                                 }
711                                                 if (param_defs[param->index].type == PARAM_TYPE_YESNO)
712                                                 {
713                                                         switch(param->integer_value)
714                                                         {
715                                                                 case 1:
716                                                                 printf("yes");
717                                                                 break;
718                                                                 case 0:
719                                                                 printf("no");
720                                                                 break;
721                                                                 default:
722                                                                 printf("unknown(%d)", param->integer_value);
723                                                         }
724                                                         break;
725                                                 }
726                                                 if (param_defs[param->index].type == PARAM_TYPE_NULL)
727                                                 {
728                                                         break;
729                                                 }
730                                                 printf("%d", param->integer_value);
731                                                 break;
732
733                                                 case VALUE_TYPE_STRING:
734                                                 printf("'%s'", param->string_value);
735                                                 break;
736
737                                                 default:
738                                                 printf("Software error: VALUE_TYPE_* %d not known in function '%s' line=%d", param->value_type, __FUNCTION__, __LINE__);
739                                         }
740                                         param = param->next;
741                                         printf("\n");
742                                 }
743                                 /* TIMEOUT */
744                                 if (action->timeout)
745                                         printf("    Timeout: %d\n", action->timeout);
746                                 action = action->next;
747                         }
748                         printf("\n");
749                         rule = rule->next;
750                 }
751                 printf("\n");
752                 ruleset = ruleset->next;
753         }
754 }
755
756
757 /*
758  * parse ruleset
759  */
760 static char *read_string(char *p, char *key, int key_size, char *special)
761 {
762         key[0] = 0;
763
764         if (*p == '\"')
765         {
766                 p++;
767                 /* quote */
768                 while(*p)
769                 {
770                         if (*p == '\"')
771                         {
772                                 p++;
773                                 *key = '\0';
774                                 return(p);
775                         }
776                         if (*p == '\\')
777                         {
778                                 p++;
779                                 if (*p == '\0')
780                                 {
781                                         break;
782                                 }
783                         }
784                         if (--key_size == 0)
785                         {
786                                 UPRINT(key, "\001String too long.");
787                                 return(p);
788                         }
789                         *key++ = *p++;
790                 }
791                 UPRINT(key, "\001Unexpected end of line inside quotes.");
792                 return(p);
793         }
794
795         /* no quote */
796         while(*p)
797         {
798                 if (strchr(special, *p))
799                 {
800                         *key = '\0';
801                         return(p);
802                 }
803                 if (*p == '\\')
804                 {
805                         p++;
806                         if (*p == '\0')
807                         {
808                                 UPRINT(key, "\001Unexpected end of line.");
809                                 return(p);
810                         }
811                 }
812                 if (--key_size == 0)
813                 {
814                         UPRINT(key, "\001String too long.");
815                         return(p);
816                 }
817                 *key++ = *p++;
818         }
819         *key = '\0';
820         return(p);
821 }
822 char ruleset_error[256];
823 struct route_ruleset *ruleset_parse(void)
824 {
825 //      char                    from[128];
826 //      char                    to[128];
827         int                     i;
828         unsigned long long      j;
829 //      int                     a,
830 //                              b;
831         #define                 MAXNESTING 8
832         FILE                    *fp[MAXNESTING];
833         char                    filename[MAXNESTING][256];
834         int                     line[MAXNESTING];
835         int                     nesting = -1;
836         char                    buffer[1024],
837                                 key[1024],
838                                 key_to[1024],
839                                 pointer[1024+1],
840                                 *p;
841         int                     expecting = 1; /* 1 = expecting ruleset */
842         int                     index,
843                                 value_type,
844                                 integer,
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;
856         char                    failure[256];
857
858         /* check the integrity of IDs for ACTION_* and PARAM_* */
859         i = 0;
860         while(action_defs[i].name)
861         {
862                 if (action_defs[i].id != i)
863                 {
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);
866                         goto openerror;
867                 }
868                 i++;
869         }
870         i = 0; j = 1;
871         while(param_defs[i].name)
872         {
873                 if (param_defs[i].id != j)
874                 {
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);
877                         goto openerror;
878                 }
879                 i++;
880                 j<<=1;
881         }
882
883         SPRINT(filename[0], "%s/routing.conf", INSTALL_DATA);
884
885         if (!(fp[0]=fopen(filename[0],"r")))
886         {
887                 PERROR("Cannot open %s\n",filename[0]);
888                 goto openerror;
889         }
890         nesting++;
891         fduse++;
892
893         go_leaf:
894         line[nesting]=0;
895         go_root:
896         while((fgets(buffer,sizeof(buffer),fp[nesting])))
897         {
898                 line[nesting]++;
899                 buffer[sizeof(buffer)-1]=0;
900                 if (buffer[0]) buffer[strlen(buffer)-1]=0;
901                 p = buffer;
902
903                 /* remove tabs */
904                 while(*p) {
905                         if (*p < 32)
906                                 *p = 32;
907                         p++;
908                 } 
909                 p = buffer;
910
911                 /* skip spaces, if any */
912                 while(*p == 32)
913                 {
914                         if (*p == 0)
915                                 break;
916                         p++;
917                 }
918
919                 /* skip comments */
920                 if (*p == '#')
921                 {
922                         p++;
923                         /* don't skip "define" */
924                         if (!!strncmp(p, "define", 6))
925                                 continue;
926                         p+=6;
927                         if (*p != 32)
928                                 continue;
929                         /* skip spaces */
930                         while(*p == 32)
931                         {
932                                 if (*p == 0)
933                                         break;
934                                 p++;
935                         }
936                         p++;
937                         p = read_string(p, key, sizeof(key), " ");
938                         if (key[0] == 1) /* error */
939                         {
940                                 SPRINT(failure, "Parsing Filename failed: %s", key+1);
941                                 goto parse_error;
942                         }
943                         if (nesting == MAXNESTING-1)
944                         {
945                                 SPRINT(failure, "'include' is nesting too deep.\n");
946                                 goto parse_error;
947                         }
948                         if (key[0] == '/')
949                                 SCPY(filename[nesting+1], key);
950                         else
951                                 SPRINT(filename[nesting+1], "%s/%s", INSTALL_DATA, key);
952                         if (!(fp[nesting+1]=fopen(filename[nesting+1],"r")))
953                         {
954                                 PERROR("Cannot open %s\n", filename[nesting+1]);
955                                 goto parse_error;
956                         }
957                         fduse++;
958                         nesting++;
959                         goto go_leaf;
960                 }
961                 if (*p == '/') if (p[1] == '/')
962                         continue;
963
964                 /* skip empty lines */
965                 if (*p == 0)
966                         continue;
967
968                 /* expecting ruleset */
969                 if (expecting)
970                 {
971                         new_ruleset:
972                         /* expecting [ */
973                         if (*p != '[')
974                         {
975                                 SPRINT(failure, "Expecting ruleset name starting with '['.");
976                                 goto parse_error;
977                         }
978                         p++;
979
980                         /* reading ruleset name text */
981                         i = 0;
982                         while((*p>='a' && *p<='z') || (*p>='A' && *p<='Z') || (*p>='0' && *p<='9'))
983                         {
984                                 if (*p>='A' && *p<='Z') *p = *p-'A'+'a'; /* lower case */
985                                 key[i++] = *p++;
986                                 if (i == sizeof(key)) i--; /* limit */
987                         }
988                         key[i] = 0;
989                         if (key[0] == '\0') {
990                                 SPRINT(failure, "Missing ruleset name after '['.");
991                                 goto parse_error;
992                         }
993
994                         /* expecting ] and nothing more */
995                         if (*p != ']') {
996                                 SPRINT(failure, "Expecting ']' after ruleset name.");
997                                 goto parse_error;
998                         }
999                         p++;
1000                         if (*p != 0) {
1001                                 SPRINT(failure, "Unexpected character after ruleset name.");
1002                                 goto parse_error;
1003                         }
1004
1005                         /* check for duplicate rulesets */
1006                         ruleset = ruleset_start;
1007                         while(ruleset)
1008                         {
1009                                 if (!strcmp(ruleset->name, key))
1010                                 {
1011                                         SPRINT(failure, "Duplicate ruleset '%s', already defined in file '%s' line %d.", key, ruleset->file, ruleset->line);
1012                                         goto parse_error;
1013                                 }
1014                                 ruleset = ruleset->next;
1015                         }
1016
1017                         /* create ruleset */
1018                         ruleset = (struct route_ruleset *)malloc(sizeof(struct route_ruleset));
1019                         if (ruleset == NULL)
1020                         {
1021                                 SPRINT(failure, "Out of memory.");
1022                                 goto parse_error;
1023                         }
1024                         rmemuse++;
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);
1032                         expecting = 0;
1033                         continue;
1034                 }
1035
1036                 /* for new ruleset [ */
1037                 if (*p == '[')
1038                 {
1039                         goto new_ruleset;
1040                 }
1041
1042                 /* alloc memory for rule */
1043                 rule = (struct route_rule *)malloc(sizeof(struct route_rule));
1044                 if (rule == NULL)
1045                 {
1046                         SPRINT(failure, "Out of memory.");
1047                         goto parse_error;
1048                 }
1049                 rmemuse++;
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];
1057
1058                 /* loop CONDITIONS */
1059                 while(*p!=':' && *p!='\0')
1060                 {
1061                         /* read item text */
1062                         i = 0;
1063                         while((*p>='a' && *p<='z') || (*p>='A' && *p<='Z') || (*p>='0' && *p<='9'))
1064                         {
1065                                 if (*p>='A' && *p<='Z') *p = *p-'A'+'a'; /* lower case */
1066                                 key[i++] = *p++;
1067                                 if (i == sizeof(key)) i--; /* limit */
1068                         }
1069                         key[i] = 0;
1070                         if (key[0] == '\0')
1071                         {
1072                                 SPRINT(failure, "Expecting condition item name or ':' for end of condition list.");
1073                                 goto parse_error;
1074                         }
1075                         if (*p!=' ' && *p!='=')
1076                         {
1077                                 SPRINT(failure, "Illegal character '%c' after condition name '%s'. Expecting '=' for equation or ' ' to seperate condition items.", *p, key);
1078                                 goto parse_error;
1079                         }
1080
1081                         /* check if condition exists */
1082                         index = 0;
1083                         while(cond_defs[index].name)
1084                         {
1085                                 if (!strcmp(cond_defs[index].name, key))
1086                                         break;
1087                                 index++;
1088                         }
1089                         if (cond_defs[index].name == NULL)
1090                         {
1091                                 SPRINT(failure, "Unknown condition item name '%s'.", key);
1092                                 goto parse_error;
1093                         }
1094
1095                         /* items without values must not have any parameter */
1096                         if (cond_defs[index].type == COND_TYPE_NULL)
1097                         {
1098                                 if (*p == '=')
1099                                 {
1100                                         SPRINT(failure, "Condition item '%s' must not have any value. Don't use '=' for this type of condition.", key);
1101                                         goto parse_error;
1102                                 }
1103                                 if (*p != ' ')
1104                                 {
1105                                         SPRINT(failure, "Condition item '%s' must not have any value. Expecting ' ' or tab after item name.", key);
1106                                         goto parse_error;
1107                                 }
1108 //                              p++;
1109                         } else
1110                         {
1111                                 if (*p == ' ')
1112                                 {
1113                                         SPRINT(failure, "Condition item '%s' must have at least one value, '=' expected, and not a space.", key);
1114                                         goto parse_error;
1115                                 }
1116                                 if (*p != '=')
1117                                 {
1118                                         SPRINT(failure, "Condition item '%s' must have at least one value, '=' expected.", key);
1119                                         goto parse_error;
1120                                 }
1121                                 p++;
1122                         }
1123
1124                         /* check for duplicate condition */
1125                         cond = rule->cond_first;
1126                         while(cond)
1127                         {
1128                                 if (cond->index == index)
1129                                 {
1130                                         SPRINT(failure, "Duplicate condition '%s', use ',' to give multiple values.", key);
1131                                         goto parse_error;
1132                                 }
1133                                 cond = cond->next;
1134                         }
1135
1136                         nextcondvalue:
1137                         /* alloc memory for item */
1138                         cond = (struct route_cond *)malloc(sizeof(struct route_cond));
1139                         if (cond == NULL)
1140                         {
1141                                 SPRINT(failure, "Out of memory.");
1142                                 goto parse_error;
1143                         }
1144                         rmemuse++;
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)
1151                         {
1152                                 case COND_TYPE_NULL:
1153                                 if (*p=='=')
1154                                 {
1155                                         SPRINT(failure, "Expecting no value.");
1156                                         goto parse_error;
1157                                 }
1158                                 value_type = VALUE_TYPE_NULL;
1159                                 break;
1160
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')
1170                                 {
1171                                         SPRINT(failure, "Missing integer value.");
1172                                         goto parse_error;
1173                                 }
1174                                 while(*p>='0' && *p<='9')
1175                                 {
1176                                         integer = integer*10 + *p-'0';
1177                                         p++;
1178                                 }
1179                                 value_type = VALUE_TYPE_INTEGER;
1180                                 if (*p == '-')
1181                                 {
1182                                         p++;
1183                                         if (*p==',' || *p==' ' || *p=='\0')
1184                                         {
1185                                                 SPRINT(failure, "Missing integer value.");
1186                                                 goto parse_error;
1187                                         }
1188                                         while(*p>='0' && *p<='9')
1189                                         {
1190                                                 integer_to = integer_to*10 + *p-'0';
1191                                                 p++;
1192                                         }
1193                                         value_type = VALUE_TYPE_INTEGER_RANGE;
1194                                 }
1195                                 if (cond_defs[index].type == COND_TYPE_TIME)
1196                                 {
1197                                         // Simon: i store the time as decimal, later i compare it correctly:
1198                                         // hours * 100 + minutes
1199                                         if (integer == 2400)
1200                                                 integer = 0;
1201                                         if (integer >= 2400)
1202                                         {
1203                                                 timeoutofrange1:
1204                                                 SPRINT(failure, "Given time '%d' not in range 0000..2359 (or 2400 for 0000)", integer);
1205                                                 goto parse_error;
1206                                         }
1207                                         if (integer%100 >= 60)
1208                                                 goto timeoutofrange1;
1209                                         if (value_type == VALUE_TYPE_INTEGER)
1210                                                 goto integer_done;
1211                                         if (integer_to == 2400)
1212                                                 integer_to = 0;
1213                                         if (integer_to >= 2400)
1214                                         {
1215                                                 timeoutofrange2:
1216                                                 SPRINT(failure, "Given time '%d' not in range 0000..2359 (or 2400 for 0000)", integer_to);
1217                                                 goto parse_error;
1218                                         }
1219                                         if (integer_to%100 >= 60)
1220                                                 goto timeoutofrange2;
1221                                 }
1222                                 if (cond_defs[index].type == COND_TYPE_MDAY)
1223                                 {
1224                                         if (integer<1 || integer>31)
1225                                         {
1226                                                 SPRINT(failure, "Given day-of-month '%d' not in range 1..31", integer);
1227                                                 goto parse_error;
1228                                         } 
1229                                         if (value_type == VALUE_TYPE_INTEGER)
1230                                                 goto integer_done;
1231                                         if (integer_to<1 || integer_to>31)
1232                                         {
1233                                                 SPRINT(failure, "Given day-of-month '%d' not in range 1..31", integer_to);
1234                                                 goto parse_error;
1235                                         } 
1236                                 }
1237                                 if (cond_defs[index].type == COND_TYPE_WDAY)
1238                                 {
1239                                         if (integer<1 || integer>7)
1240                                         {
1241                                                 SPRINT(failure, "Given day-of-week '%d' not in range 1..7", integer);
1242                                                 goto parse_error;
1243                                         } 
1244                                         if (value_type == VALUE_TYPE_INTEGER)
1245                                                 goto integer_done;
1246                                         if (integer_to<1 || integer_to>7)
1247                                         {
1248                                                 SPRINT(failure, "Given day-of-week '%d' not in range 1..7", integer_to);
1249                                                 goto parse_error;
1250                                         } 
1251                                 }
1252                                 if (cond_defs[index].type == COND_TYPE_MONTH)
1253                                 {
1254                                         if (integer<1 || integer>12)
1255                                         {
1256                                                 SPRINT(failure, "Given month '%d' not in range 1..12", integer);
1257                                                 goto parse_error;
1258                                         } 
1259                                         if (value_type == VALUE_TYPE_INTEGER)
1260                                                 goto integer_done;
1261                                         if (integer_to<1 || integer_to>12)
1262                                         {
1263                                                 SPRINT(failure, "Given month '%d' not in range 1..12", integer_to);
1264                                                 goto parse_error;
1265                                         } 
1266                                 }
1267                                 if (cond_defs[index].type == COND_TYPE_YEAR)
1268                                 {
1269                                         if (integer<1970 || integer>2106)
1270                                         {
1271                                                 SPRINT(failure, "Given year '%d' not in range 1970..2106", integer);
1272                                                 goto parse_error;
1273                                         } 
1274                                         if (value_type == VALUE_TYPE_INTEGER)
1275                                                 goto integer_done;
1276                                         if (integer_to<1970 || integer_to>2106)
1277                                         {
1278                                                 SPRINT(failure, "Given year '%d' not in range 1970..2106", integer_to);
1279                                                 goto parse_error;
1280                                         } 
1281                                 }
1282                                 integer_done:
1283                                 cond->integer_value = integer;
1284                                 cond->integer_value_to = integer_to;
1285                                 cond->value_type = value_type;
1286                                 break;
1287
1288                                 /* parse all string values/ranges */
1289                                 case COND_TYPE_STRING:
1290                                 key[0] = key_to[0] = '\0';
1291                                 if (*p==',' || *p==' ' || *p=='\0')
1292                                 {
1293                                         SPRINT(failure, "Missing string value, use \"\" for empty string.");
1294                                         goto parse_error;
1295                                 }
1296                                 p = read_string(p, key, sizeof(key), "-, ");
1297                                 if (key[0] == 1) /* error */
1298                                 {
1299                                         SPRINT(failure, "Parsing String failed: %s", key+1);
1300                                         goto parse_error;
1301                                 }
1302                                 value_type = VALUE_TYPE_STRING;
1303                                 if (*p == '-')
1304                                 {
1305                                         p++;
1306                                         if (*p==',' || *p==' ' || *p=='\0')
1307                                         {
1308                                                 SPRINT(failure, "Missing string value, use \"\" for empty string.");
1309                                                 goto parse_error;
1310                                         }
1311                                         p = read_string(p, key_to, sizeof(key_to), "-, ");
1312                                         if (key_to[0] == 1) /* error */
1313                                         {
1314                                                 SPRINT(failure, "Parsing string failed: %s", key_to+1);
1315                                                 goto parse_error;
1316                                         }
1317                                         value_type = VALUE_TYPE_STRING_RANGE;
1318                                         if (strlen(key) != strlen(key_to))
1319                                         {
1320                                                 SPRINT(failure, "Given range of strings \"%s\"-\"%s\" have unequal length.", key, key_to);
1321                                                 goto parse_error;
1322                                         }
1323                                         if (key[0] == '\0')
1324                                         {
1325                                                 SPRINT(failure, "Given range has no length.");
1326                                                 goto parse_error;
1327                                         }
1328                                 }
1329                                 alloc_string:
1330                                 cond->string_value = (char *)malloc(strlen(key)+1);
1331                                 if (cond->string_value == NULL)
1332                                 {
1333                                         SPRINT(failure, "Out of memory.");
1334                                         goto parse_error;
1335                                 }
1336                                 rmemuse++;
1337                                 UCPY(cond->string_value, key);
1338                                 if (value_type == VALUE_TYPE_STRING_RANGE)
1339                                 {
1340                                         cond->string_value_to = (char *)malloc(strlen(key_to)+1);
1341                                         if (cond->string_value_to == NULL)
1342                                         {
1343                                                 SPRINT(failure, "Out of memory.");
1344                                                 goto parse_error;
1345                                         }
1346                                         rmemuse++;
1347                                         UCPY(cond->string_value_to, key_to);
1348                                         cond->comp_string = strcmp(key, key_to);
1349                                 }
1350                                 cond->value_type = value_type;
1351                                 break;
1352
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;
1367                                 else
1368                                 {
1369                                         SPRINT(failure, "Given service type is invalid or misspelled.");
1370                                         goto parse_error;
1371                                 }
1372                                 cond->value_type = VALUE_TYPE_INTEGER;
1373                                 break;
1374
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;
1381                                 else
1382                                 {
1383                                         SPRINT(failure, "Given bchannel mode is invalid or misspelled.");
1384                                         goto parse_error;
1385                                 }
1386                                 cond->value_type = VALUE_TYPE_INTEGER;
1387                                 break;
1388
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')
1393                                 {
1394                                         SPRINT(failure, "Missing interface name.");
1395                                         goto parse_error;
1396                                 }
1397                                 p = read_string(p, key, sizeof(key), ":-, ");
1398                                 if (key[0] == 1) /* error */
1399                                 {
1400                                         SPRINT(failure, "Parsing interface failed: %s", key+1);
1401                                         goto parse_error;
1402                                 }
1403                                 if (*p != ':')
1404                                 {
1405                                         SPRINT(failure, "Expeciting kolon to seperate value behind interface name.");
1406                                         goto parse_error;
1407                                 }
1408                                 SCCAT(key, *p++);
1409                                 while(*p>='0' && *p<='9')
1410                                 {
1411                                         SCCAT(key, *p++);
1412                                 }
1413                                 if (*p!=',' && *p!=' ' && *p!='\0')
1414                                 {
1415                                         SPRINT(failure, "Invalid characters behind value.");
1416                                         goto parse_error;
1417                                 }
1418                                 value_type = VALUE_TYPE_STRING;
1419                                 goto alloc_string;
1420                                 break;
1421
1422                                 default:
1423                                 SPRINT(failure, "Software error: COND_TYPE_* %d not parsed in function '%s'", cond_defs[index].type, __FUNCTION__);
1424                                 goto parse_error;
1425                         }
1426                         /* if we have another value for that item, we attach it */
1427                         if (*p == ',')
1428                         {
1429                                 p++;
1430                                 /* next item */
1431                                 cond->value_extension = 1;
1432                                 goto nextcondvalue;
1433                         }
1434                         /* to seperate the items, a space is required */
1435                         if (*p != ' ')
1436                         {
1437                                 SPRINT(failure, "Character '%c' not expected here. Use ',' to seperate multiple possible values.", *p);
1438                                 goto parse_error;
1439                         }
1440                         /* skip spaces */
1441                         while(*p == 32)
1442                         {
1443                                 if (*p == 0)
1444                                         break;
1445                                 p++;
1446                         }
1447                 }
1448
1449                 /* we are done with CONDITIONS, so we expect the ACTION */
1450                 if (*p != ':')
1451                 {
1452                         SPRINT(failure, "Expecting ':' after condition item(s).");
1453                         goto parse_error;
1454                 }
1455                 p++;
1456
1457                 nextaction:
1458                 /* skip spaces, if any */
1459                 while(*p == 32)
1460                 {
1461                         if (*p == 0)
1462                                 break;
1463                         p++;
1464                 }
1465
1466                 /* read action name */
1467                 i = 0;
1468                 while((*p>='a' && *p<='z') || (*p>='A' && *p<='Z') || (*p>='0' && *p<='9') || *p == '-')
1469                 {
1470                         if (*p>='A' && *p<='Z') *p = *p-'A'+'a'; /* lower case */
1471                         key[i++] = *p++;
1472                         if (i == sizeof(key)) i--; /* limit */
1473                 }
1474                 key[i] = 0;
1475                 if (key[0] == '\0') {
1476                         SPRINT(failure, "Expecting action name.");
1477                         goto parse_error;
1478                 }
1479
1480                 /* check if item exists */
1481                 index = 0;
1482                 while(action_defs[index].name)
1483                 {
1484                         if (!action_defs[index].help) /* not internal actions */
1485                         {
1486                                 index++;
1487                                 continue;
1488                         }
1489                         if (!strcmp(action_defs[index].name, key))
1490                                 break;
1491                         index++;
1492                 }
1493                 if (action_defs[index].name == NULL)
1494                 {
1495                         SPRINT(failure, "Unknown action name '%s'.", key);
1496                         goto parse_error;
1497                 }
1498
1499                 /* alloc memory for action */
1500                 action = (struct route_action *)malloc(sizeof(struct route_action));
1501                 if (action == NULL)
1502                 {
1503                         SPRINT(failure, "Out of memory.");
1504                         goto parse_error;
1505                 }
1506                 rmemuse++;
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];
1513
1514                 /* skip spaces after param name */
1515                 while(*p == 32)
1516                 {
1517                         if (*p == 0)
1518                                 break;
1519                         p++;
1520                 }
1521
1522                 /* loop PARAMS */
1523                 while(*p != 0)
1524                 {
1525                         /* read param text */
1526                         i = 0;
1527                         while((*p>='a' && *p<='z') || (*p>='A' && *p<='Z') || (*p>='0' && *p<='9'))
1528                         {
1529                                 if (*p>='A' && *p<='Z') *p = *p-'A'+'a'; /* lower case */
1530                                 key[i++] = *p++;
1531                                 if (i == sizeof(key)) i--; /* limit */
1532                         }
1533                         key[i] = 0;
1534                         if (key[0] == '\0') {
1535                                 SPRINT(failure, "Expecting parameter name.");
1536                                 goto parse_error;
1537                         }
1538
1539                         /* check if item exists */
1540                         index = 0;
1541                         while(param_defs[index].name)
1542                         {
1543                                 if (!strcmp(param_defs[index].name, key))
1544                                         break;
1545                                 index++;
1546                         }
1547                         if (param_defs[index].name == NULL)
1548                         {
1549                                 SPRINT(failure, "Unknown param name '%s'.", key);
1550                                 goto parse_error;
1551                         }
1552
1553                         /* params without values must not have any parameter */
1554                         if (param_defs[index].type == PARAM_TYPE_NULL)
1555                         {
1556                                 if (*p!=' ' && *p!='\0')
1557                                 {
1558                                         SPRINT(failure, "Parameter '%s' must not have any value.", key);
1559                                         goto parse_error;
1560                                 }
1561                         } else
1562                         {
1563                                 if (*p == ' ')
1564                                 {
1565                                         SPRINT(failure, "Parameter '%s' must have at least one value, '=' expected and not a space.", key);
1566                                         goto parse_error;
1567                                 }
1568                                 if (*p != '=')
1569                                 {
1570                                         SPRINT(failure, "Parameter '%s' must have at least one value, '=' expected.", key);
1571                                         goto parse_error;
1572                                 }
1573                                 p++;
1574                         }
1575
1576                         /* special timeout value */
1577                         if (!strcmp("timeout", key))
1578                         {
1579                                 if (action->timeout)
1580                                 {
1581                                         SPRINT(failure, "Duplicate timeout value.");
1582                                         goto parse_error;
1583                                 }
1584                                 if (*p==',' || *p==' ' || *p=='\0')
1585                                 {
1586                                         SPRINT(failure, "Missing integer value.");
1587                                         goto parse_error;
1588                                 }
1589                                 integer = 0;
1590                                 while(*p>='0' && *p<='9')
1591                                 {
1592                                         integer = integer*10 + *p-'0';
1593                                         p++;
1594                                 }
1595                                 if (integer < 1)
1596                                 {
1597                                         SPRINT(failure, "Expecting timeout value greater 0.");
1598                                         goto parse_error;
1599                                 }
1600                                 if (*p!=' ' && *p!='\0')
1601                                 {
1602                                         SPRINT(failure, "Character '%c' not expected here. Use ' ' to seperate parameters.", *p);
1603                                         goto parse_error;
1604                                 }
1605                                 /* skip spaces */
1606                                 while(*p == 32)
1607                                 {
1608                                         if (*p == 0)
1609                                                 break;
1610                                         p++;
1611                                 }
1612                                 action->timeout = integer;
1613                                 /* check for next ACTION */
1614                                 if (*p == ':')
1615                                 {
1616                                         p++;
1617                                         goto nextaction;
1618                                 }
1619                                 continue;
1620                         }
1621
1622                         /* check for duplicate parameters */
1623                         param = action->param_first;
1624                         while(param)
1625                         {
1626                                 if (param->index == index)
1627                                 {
1628                                         SPRINT(failure, "Duplicate parameter '%s', use ',' to give multiple values.", key);
1629                                         goto parse_error;
1630                                 }
1631                                 param = param->next;
1632                         }
1633
1634                         nextparamvalue:
1635                         /* alloc memory for param */
1636                         param = (struct route_param *)malloc(sizeof(struct route_param));
1637                         if (param == NULL)
1638                         {
1639                                 SPRINT(failure, "Out of memory.");
1640                                 goto parse_error;
1641                         }
1642                         rmemuse++;
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;
1648
1649                         switch(param_defs[index].type)
1650                         {
1651                                 /* parse null value */
1652                                 case PARAM_TYPE_NULL:
1653                                 param->value_type = VALUE_TYPE_NULL;
1654                                 break;
1655
1656                                 /* parse integer value */
1657                                 case PARAM_TYPE_INTEGER:
1658                                 integer = 0;
1659                                 if (*p==',' || *p==' ' || *p=='\0')
1660                                 {
1661                                         SPRINT(failure, "Missing integer value.");
1662                                         goto parse_error;
1663                                 }
1664                                 while(*p>='0' && *p<='9')
1665                                 {
1666                                         integer = integer*10 + *p-'0';
1667                                         p++;
1668                                 }
1669                                 param->integer_value = integer;
1670                                 param->value_type = VALUE_TYPE_INTEGER;
1671                                 break;
1672
1673 #if 0
1674                                 /* parse ports value */
1675                                 case PARAM_TYPE_PORTS:
1676                                 key[0] = '\0';
1677                                 if (*p==',' || *p==' ' || *p=='\0')
1678                                 {
1679                                         SPRINT(failure, "Missing port number, omit parameter or give port number.");
1680                                         goto parse_error;
1681                                 }
1682                                 i = 0;
1683                                 nextport:
1684                                 integer = 0;
1685                                 while(*p>='0' && *p<='9')
1686                                 {
1687                                         if (i < (int)sizeof(key)-1)
1688                                         {
1689                                                 key[i] = *p;
1690                                                 key[i++] = '\0';
1691                                         }
1692                                         integer = integer*10 + *p-'0';
1693                                         p++;
1694                                 }
1695                                 if (integer > 255)
1696                                 {
1697                                         SPRINT(failure, "Port number too high.");
1698                                         goto parse_error;
1699                                 }
1700                                 if (*p==',')
1701                                 {
1702                                         if (i < (int)sizeof(key)-1)
1703                                         {
1704                                                 key[i] = *p;
1705                                                 key[i++] = '\0';
1706                                         }
1707                                         p++;
1708                                         goto nextport;
1709                                 }
1710                                 goto mallocstring;
1711 #endif
1712
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:
1722                                 key[0] = '\0';
1723                                 if (*p==',' || *p==' ' || *p=='\0')
1724                                 {
1725                                         SPRINT(failure, "Missing string value, use \"\" for empty string.");
1726                                         goto parse_error;
1727                                 }
1728                                 p = read_string(p, key, sizeof(key), " ");
1729                                 if (key[0] == 1) /* error */
1730                                 {
1731                                         SPRINT(failure, "Parsing string failed: %s", key+1);
1732                                         goto parse_error;
1733                                 }
1734                                 if (param_defs[index].type == PARAM_TYPE_CALLERIDTYPE)
1735                                 {
1736                                         param->value_type = VALUE_TYPE_INTEGER;
1737                                         if (!strcasecmp(key, "unknown"))
1738                                         {
1739                                                 param->integer_value = INFO_NTYPE_UNKNOWN;
1740                                                 break;
1741                                         }
1742                                         if (!strcasecmp(key, "subscriber"))
1743                                         {
1744                                                 param->integer_value = INFO_NTYPE_SUBSCRIBER;
1745                                                 break;
1746                                         }
1747                                         if (!strcasecmp(key, "national"))
1748                                         {
1749                                                 param->integer_value = INFO_NTYPE_NATIONAL;
1750                                                 break;
1751                                         }
1752                                         if (!strcasecmp(key, "international"))
1753                                         {
1754                                                 param->integer_value = INFO_NTYPE_INTERNATIONAL;
1755                                                 break;
1756                                         }
1757                                         SPRINT(failure, "Caller ID type '%s' unknown.", key);
1758                                         goto parse_error;
1759                                 }
1760                                 if (param_defs[index].type == PARAM_TYPE_CAPABILITY)
1761                                 {
1762                                         param->value_type = VALUE_TYPE_INTEGER;
1763                                         if (!strcasecmp(key, "speech"))
1764                                         {
1765                                                 param->integer_value = INFO_BC_SPEECH;
1766                                                 break;
1767                                         }
1768                                         if (!strcasecmp(key, "audio"))
1769                                         {
1770                                                 param->integer_value = INFO_BC_AUDIO;
1771                                                 break;
1772                                         }
1773                                         if (!strcasecmp(key, "video"))
1774                                         {
1775                                                 param->integer_value = INFO_BC_VIDEO;
1776                                                 break;
1777                                         }
1778                                         if (!strcasecmp(key, "digital-restricted"))
1779                                         {
1780                                                 param->integer_value = INFO_BC_DATARESTRICTED;
1781                                                 break;
1782                                         }
1783                                         if (!strcasecmp(key, "digital-unrestricted"))
1784                                         {
1785                                                 param->integer_value = INFO_BC_DATAUNRESTRICTED;
1786                                                 break;
1787                                         }
1788                                         if (!strcasecmp(key, "digital-unrestricted-tones"))
1789                                         {
1790                                                 param->integer_value = INFO_BC_DATAUNRESTRICTED_TONES;
1791                                                 break;
1792                                         }
1793                                         SPRINT(failure, "Service type '%s' unknown.", key);
1794                                         goto parse_error;
1795                                 }
1796                                 if (param_defs[index].type == PARAM_TYPE_BMODE)
1797                                 {
1798                                         param->value_type = VALUE_TYPE_INTEGER;
1799                                         if (!strcasecmp(key, "transparent"))
1800                                         {
1801                                                 param->integer_value = INFO_BMODE_CIRCUIT;
1802                                                 break;
1803                                         }
1804                                         if (!strcasecmp(key, "hdlc"))
1805                                         {
1806                                                 param->integer_value = INFO_BMODE_PACKET;
1807                                                 break;
1808                                         }
1809                                         SPRINT(failure, "Bchannel mode '%s' unknown.", key);
1810                                         goto parse_error;
1811                                 }
1812                                 if (param_defs[index].type == PARAM_TYPE_DIVERSION)
1813                                 {
1814                                         param->value_type = VALUE_TYPE_INTEGER;
1815                                         if (!strcasecmp(key, "cfu"))
1816                                         {
1817                                                 param->integer_value = INFO_DIVERSION_CFU;
1818                                                 break;
1819                                         }
1820                                         if (!strcasecmp(key, "cfb"))
1821                                         {
1822                                                 param->integer_value = INFO_DIVERSION_CFB;
1823                                                 break;
1824                                         }
1825                                         if (!strcasecmp(key, "cfnr"))
1826                                         {
1827                                                 param->integer_value = INFO_DIVERSION_CFNR;
1828                                                 break;
1829                                         }
1830                                         if (!strcasecmp(key, "cfp"))
1831                                         {
1832                                                 param->integer_value = INFO_DIVERSION_CFP;
1833                                                 break;
1834                                         }
1835                                         SPRINT(failure, "Diversion type '%s' unknown.", key);
1836                                         goto parse_error;
1837                                 }
1838                                 if (param_defs[index].type == PARAM_TYPE_TYPE)
1839                                 {
1840                                         param->value_type = VALUE_TYPE_INTEGER;
1841                                         if (!strcasecmp(key, "unknown"))
1842                                         {
1843                                                 param->integer_value = INFO_NTYPE_UNKNOWN;
1844                                                 break;
1845                                         }
1846                                         if (!strcasecmp(key, "subscriber"))
1847                                         {
1848                                                 param->integer_value = INFO_NTYPE_SUBSCRIBER;
1849                                                 break;
1850                                         }
1851                                         if (!strcasecmp(key, "national"))
1852                                         {
1853                                                 param->integer_value = INFO_NTYPE_NATIONAL;
1854                                                 break;
1855                                         }
1856                                         if (!strcasecmp(key, "international"))
1857                                         {
1858                                                 param->integer_value = INFO_NTYPE_INTERNATIONAL;
1859                                                 break;
1860                                         }
1861                                         SPRINT(failure, "Number type '%s' unknown.", key);
1862                                         goto parse_error;
1863                                 }
1864                                 if (param_defs[index].type == PARAM_TYPE_YESNO)
1865                                 {
1866                                         param->value_type = VALUE_TYPE_INTEGER;
1867                                         if (!strcasecmp(key, "yes"))
1868                                         {
1869                                                 param->integer_value = 1;
1870                                                 break;
1871                                         }
1872                                         if (!strcasecmp(key, "no"))
1873                                         {
1874                                                 param->integer_value = 0;
1875                                                 break;
1876                                         }
1877                                         SPRINT(failure, "Value '%s' unknown. ('yes' or 'no')", key);
1878                                         goto parse_error;
1879                                 }
1880                                 param->string_value = (char *)malloc(strlen(key)+1);
1881                                 if (param->string_value == NULL)
1882                                 {
1883                                         SPRINT(failure, "Out of memory.");
1884                                         goto parse_error;
1885                                 }
1886                                 rmemuse++;
1887                                 UCPY(param->string_value, key);
1888                                 param->value_type = VALUE_TYPE_STRING;
1889                                 break;
1890
1891                                 default:
1892                                 SPRINT(failure, "Software error: PARAM_TYPE_* %d not parsed in function '%s'", param_defs[index].type, __FUNCTION__);
1893                                 goto parse_error;
1894                         }
1895
1896                         if (*p == ',')
1897                         {
1898                                 p++;
1899                                 /* next item */
1900                                 param->value_extension = 1;
1901                                 goto nextparamvalue;
1902                         }
1903
1904                         /* end of line */
1905                         if (*p == '\0')
1906                                 break;
1907
1908                         /* to seperate the items, a space is required */
1909                         if (*p != ' ')
1910                         {
1911                                 SPRINT(failure, "Character '%c' not expected here. Use ' ' to seperate parameters, or ',' for multiple values.", *p);
1912                                 goto parse_error;
1913                         }
1914                         /* skip spaces */
1915                         while(*p == 32)
1916                         {
1917                                 if (*p == 0)
1918                                         break;
1919                                 p++;
1920                         }
1921
1922                         /* check for next ACTION */
1923                         if (*p == ':')
1924                         {
1925                                 p++;
1926                                 goto nextaction;
1927                         }
1928                 }
1929         }
1930
1931         fclose(fp[nesting--]);
1932         fduse--;
1933
1934         if (nesting >= 0)
1935                 goto go_root;
1936
1937         if (!ruleset_start)
1938         {
1939                 SPRINT(failure, "No ruleset defined.");
1940         }
1941         return(ruleset_start);
1942
1943         parse_error:
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);
1952
1953         openerror:
1954         while(nesting >= 0)
1955         {
1956                 fclose(fp[nesting--]);
1957                 fduse--;
1958         }
1959
1960         ruleset_free(ruleset_start);
1961         return(NULL);
1962 }
1963
1964 /*
1965  * return ruleset by name
1966  */
1967 struct route_ruleset *getrulesetbyname(char *name)
1968 {
1969         struct route_ruleset *ruleset = ruleset_first;
1970
1971         while(ruleset)
1972         {
1973                 if (!strcasecmp(name, ruleset->name))
1974                 {
1975                         break;
1976                 }
1977                 ruleset = ruleset->next;
1978         }
1979         PDEBUG(DEBUG_ROUTE, "ruleset %s %s.\n", name, ruleset?"found":"not found");
1980         return(ruleset);
1981 }
1982
1983 /*
1984  * parses the current ruleset and returns action
1985  */
1986 struct route_action *EndpointAppPBX::route(struct route_ruleset *ruleset)
1987 {
1988         int                     match,
1989                                 couldmatch = 0, /* any rule could match */
1990                                 istrue,
1991                                 couldbetrue,
1992                                 condition,
1993                                 dialing_required,
1994                                 avail,
1995                                 any;
1996         struct route_rule       *rule = ruleset->rule_first;
1997         struct route_cond       *cond;
1998         struct route_action     *action = NULL;
1999         unsigned long           comp_len;
2000         int                     j, jj;
2001         char                    callerid[64],   redirid[64];
2002         int                     integer;
2003         char                    *string;
2004         FILE                    *tfp;
2005         double                  timeout;
2006         struct mISDNport        *mISDNport;
2007
2008         /* reset timeout action */
2009         e_match_timeout = 0; /* no timeout */
2010         e_match_to_action = NULL;
2011
2012         SCPY(callerid, numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype));
2013         SCPY(redirid, numberrize_callerinfo(e_redirinfo.id, e_redirinfo.ntype));
2014         
2015         PDEBUG(DEBUG_ROUTE, "parsing ruleset '%s'\n", ruleset->name);
2016         while(rule)
2017         {
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;
2023                 while(cond)
2024                 {
2025                         condition = 0; /* any condition element is true (1) or could be true (2) */
2026                         checkextension:
2027                         istrue = 0; /* this condition-element is true */
2028                         couldbetrue = 0; /* this conditions-element could be true */
2029                         switch(cond->match)
2030                         {
2031                                 case MATCH_EXTERN:
2032                                 if (!e_terminal[0])
2033                                         istrue = 1;      
2034                                 break;
2035
2036                                 case MATCH_INTERN:
2037                                 if (e_terminal[0])
2038                                         istrue = 1;      
2039                                 break;
2040
2041                                 case MATCH_H323:
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)
2045                                         istrue = 1;      
2046                                 break;
2047
2048                                 case MATCH_PORT:
2049                                 if (ea_endpoint->ep_portlist)
2050                                 if ((ea_endpoint->ep_portlist->port_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_mISDN_DSS1)
2051                                         break;
2052                                 integer = e_callerinfo.isdn_port;
2053                                 goto match_integer;
2054
2055                                 case MATCH_INTERFACE:
2056                                 if (!e_callerinfo.interface[0])
2057                                         break;
2058                                 string = e_callerinfo.interface;
2059                                 goto match_string_prefix;
2060
2061                                 case MATCH_CALLERID:
2062                                 string = callerid;
2063                                 goto match_string_prefix;
2064
2065                                 case MATCH_EXTENSION:
2066                                 string = e_ext.name;
2067                                 goto match_string;
2068
2069                                 case MATCH_DIALING:
2070                                 string = e_dialinginfo.number;
2071                                 goto match_string_prefix;
2072
2073                                 case MATCH_ENBLOCK:
2074                                 if (!e_overlap)
2075                                         istrue = 1;
2076                                 break;
2077
2078                                 case MATCH_OVERLAP:
2079                                 if (e_overlap)
2080                                         istrue = 1;
2081                                 break;
2082
2083                                 case MATCH_ANONYMOUS:
2084                                 if (e_callerinfo.present != INFO_PRESENT_ALLOWED)
2085                                         istrue = 1;
2086                                 break;
2087
2088                                 case MATCH_VISIBLE:
2089                                 if (e_callerinfo.present == INFO_PRESENT_ALLOWED)
2090                                         istrue = 1;
2091                                 break;
2092
2093                                 case MATCH_UNKNOWN:
2094                                 if (e_callerinfo.present == INFO_PRESENT_NOTAVAIL)
2095                                         istrue = 1;
2096                                 break;
2097
2098                                 case MATCH_AVAILABLE:
2099                                 if (e_callerinfo.present != INFO_PRESENT_NOTAVAIL)
2100                                         istrue = 1;
2101                                 break;
2102
2103                                 case MATCH_FAKE:
2104                                 if (e_callerinfo.screen == INFO_SCREEN_USER)
2105                                         istrue = 1;
2106                                 break;
2107
2108                                 case MATCH_REAL:
2109                                 if (e_callerinfo.screen != INFO_SCREEN_USER)
2110                                         istrue = 1;
2111                                 break;
2112
2113                                 case MATCH_REDIRECTED:
2114                                 if (e_redirinfo.present != INFO_PRESENT_NULL)
2115                                         istrue = 1;
2116                                 break;
2117
2118                                 case MATCH_DIRECT:
2119                                 if (e_redirinfo.present == INFO_PRESENT_NULL)
2120                                         istrue = 1;
2121                                 break;
2122
2123                                 case MATCH_REDIRID:
2124                                 string = redirid;
2125                                 goto match_string_prefix;
2126
2127                                 case MATCH_TIME:
2128                                 integer = now_tm->tm_hour*100 + now_tm->tm_min;
2129                                 goto match_integer;
2130
2131                                 case MATCH_MDAY:
2132                                 integer = now_tm->tm_mday;
2133                                 goto match_integer;
2134
2135                                 case MATCH_MONTH:
2136                                 integer = now_tm->tm_mon+1;
2137                                 goto match_integer;
2138
2139                                 case MATCH_YEAR:
2140                                 integer = now_tm->tm_year + 1900;
2141                                 goto match_integer;
2142
2143                                 case MATCH_WDAY:
2144                                 integer = now_tm->tm_wday;
2145                                 integer = integer?integer:7; /* correct sunday */
2146                                 goto match_integer;
2147
2148                                 case MATCH_CAPABILITY:
2149                                 integer = e_capainfo.bearer_capa;
2150                                 goto match_integer;
2151         
2152                                 case MATCH_INFOLAYER1:
2153                                 integer = e_capainfo.bearer_info1;
2154                                 goto match_integer;
2155
2156                                 case MATCH_HLC:
2157                                 integer = e_capainfo.hlc;
2158                                 goto match_integer;
2159
2160                                 case MATCH_FILE:
2161                                 tfp = fopen(cond->string_value, "r");
2162                                 if (!tfp)
2163                                 {
2164                                         break;
2165                                 }
2166                                 if (fgetc(tfp) == '1')
2167                                         istrue = 1;
2168                                 fclose(tfp);
2169                                 break;
2170
2171                                 case MATCH_EXECUTE:
2172                                 if (system(cond->string_value) == 0)
2173                                         istrue = 1;
2174                                 break;
2175
2176                                 case MATCH_DEFAULT:
2177                                 if (!couldmatch)
2178                                         istrue = 1;
2179                                 break;
2180
2181                                 case MATCH_TIMEOUT:
2182                                 timeout = now_d + cond->integer_value;
2183                                 istrue = 1;
2184                                 break;
2185
2186                                 case MATCH_FREE:
2187                                 case MATCH_NOTFREE:
2188                                 if (!(comp_len = (unsigned long)strchr(cond->string_value, ':')))
2189                                         break;
2190                                 comp_len = comp_len-(unsigned long)cond->string_value;
2191                                 avail = 0;
2192                                 mISDNport = mISDNport_first;
2193                                 while(mISDNport)
2194                                 {
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)
2199                                         {
2200                                                 j = 0;
2201                                                 jj = mISDNport->b_num;
2202                                                 avail += jj;
2203                                                 while(j < jj)
2204                                                 {
2205                                                         if (mISDNport->b_state[j])
2206                                                                 avail--;
2207                                                         j++;
2208                                                 }
2209                                         }
2210                                         mISDNport = mISDNport->next;
2211                                 }
2212                                 if (cond->match == MATCH_FREE)
2213                                 {
2214                                         if (avail >= atoi(cond->string_value + comp_len + 1))
2215                                                 istrue = 1;
2216                                 } else
2217                                 {
2218                                         if (avail < atoi(cond->string_value + comp_len + 1))
2219                                                 istrue = 1;
2220                                 }
2221                                 break;
2222
2223
2224                                 case MATCH_DOWN:
2225                                 mISDNport = mISDNport_first;
2226                                 while(mISDNport)
2227                                 {
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 */
2231                                                 break;
2232                                         mISDNport = mISDNport->next;
2233                                 }
2234                                 if (!mISDNport) /* all down */
2235                                         istrue = 1;
2236                                 break;
2237
2238                                 case MATCH_UP:
2239                                 mISDNport = mISDNport_first;
2240                                 while(mISDNport)
2241                                 {
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 */
2245                                                 break;
2246                                         
2247                                         mISDNport = mISDNport->next;
2248                                 }
2249                                 if (mISDNport) /* one link at least */
2250                                         istrue = 1;
2251                                 break;
2252
2253                                 case MATCH_BUSY:
2254                                 any = 0;
2255                                 mISDNport = mISDNport_first;
2256                                 while(mISDNport)
2257                                 {
2258                                         if (mISDNport->ifport)
2259                                         if (!strcasecmp(mISDNport->ifport->interface->name, cond->string_value)) 
2260                                         if (mISDNport->use) /* break if in use */
2261                                                 break;
2262                                         mISDNport = mISDNport->next;
2263                                 }
2264                                 if (mISDNport)
2265                                         istrue = 1;
2266                                 break;
2267
2268                                 case MATCH_IDLE:
2269                                 mISDNport = mISDNport_first;
2270                                 while(mISDNport)
2271                                 {
2272                                         if (mISDNport->ifport)
2273                                         if (!strcasecmp(mISDNport->ifport->interface->name, cond->string_value)) 
2274                                         if (mISDNport->use) /* break if in use */
2275                                                 break;
2276                                         mISDNport = mISDNport->next;
2277                                 }
2278                                 if (!mISDNport)
2279                                         istrue = 1;
2280                                 break;
2281
2282                                 default:
2283                                 PERROR("Software error: MATCH_* %d not parsed in function '%s'", cond->match, __FUNCTION__);
2284                                 break;
2285
2286                                 match_integer:
2287                                 if (cond->value_type == VALUE_TYPE_INTEGER)
2288                                 {
2289                                         if (integer != cond->integer_value)
2290                                                 break;
2291                                         istrue = 1;
2292                                         break;
2293                                 }
2294                                 if (cond->value_type == VALUE_TYPE_INTEGER_RANGE)
2295                                 {
2296                                         /* check if negative range (2100 - 700 o'clock) */
2297                                         if (cond->integer_value > cond->integer_value_to)
2298                                         {
2299                                                 if (integer>=cond->integer_value && integer<=cond->integer_value_to)
2300                                                         istrue = 1;
2301                                                 break;
2302                                         }
2303                                         /* range is positive */
2304                                         if (integer>=cond->integer_value && integer<=cond->integer_value_to)
2305                                                 istrue = 1;
2306                                         break;
2307                                 }
2308                                 break;
2309
2310                                 match_string:
2311                                 if (strlen(cond->string_value) != strlen(string))
2312                                         break;
2313                                 /* fall through */
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)
2318                                 {
2319                                         /* special case for unfinished dialing */
2320                                         if (cond->match == MATCH_DIALING)
2321                                         {
2322                                                 couldbetrue = 1; /* could match */
2323                                                 comp_len = strlen(string);
2324                                         } else
2325                                         {
2326                                                 break;
2327                                         }
2328                                 }
2329                                 /* on single string match */
2330                                 if (cond->value_type == VALUE_TYPE_STRING)
2331                                 {
2332                                         if (!strncmp(string, cond->string_value, comp_len))
2333                                         {
2334                                                 istrue = 1;
2335                                                 /* must be set for changing 'e_extdialing' */
2336                                                 if (cond->match == MATCH_DIALING)
2337                                                         dialing_required = comp_len;
2338                                                 break;
2339                                         }
2340                                         break;
2341                                 }
2342                                 /* on range match */
2343                                 if (cond->value_type == VALUE_TYPE_STRING_RANGE)
2344                                 {
2345                                         /* check if negative range ("55"-"22") */
2346                                         if (cond->comp_string > 0)
2347                                         {
2348                                                 if (strncmp(string, cond->string_value, comp_len) >= 0)
2349                                                 {
2350                                                         istrue = 1;
2351                                                         /* must be set for changing 'e_extdialing' */
2352                                                         if (cond->match == MATCH_DIALING)
2353                                                                 dialing_required = comp_len;
2354                                                         break;
2355                                                 }
2356                                                 if (strncmp(string, cond->string_value_to, comp_len) <= 0)
2357                                                 {
2358                                                         /* must be set for changing 'e_extdialing' */
2359                                                         istrue = 1;
2360                                                         if (cond->match == MATCH_DIALING)
2361                                                                 dialing_required = comp_len;
2362                                                         break;
2363                                                 }
2364                                                 break;
2365                                         }
2366                                         /* range is positive */
2367                                         if (strncmp(string, cond->string_value, comp_len) < 0)
2368                                                 break;
2369                                         if (strncmp(string, cond->string_value_to, comp_len) > 0)
2370                                                 break;
2371                                         istrue = 1;
2372                                         if (cond->match == MATCH_DIALING)
2373                                                 dialing_required = comp_len;
2374                                         break;
2375                                 }
2376                                 break;
2377                         }
2378
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 */
2384
2385                         /* if not matching or could match */
2386                         if (condition != 1)
2387                         {
2388                                 /* if we have more values to check */
2389                                 if (cond->value_extension && cond->next)
2390                                 {
2391                                         cond = cond->next;
2392                                         goto checkextension;
2393                                 }
2394                                 match = condition;
2395                                 break;
2396                         }
2397                         
2398                         /* skip exteded values, beacuse we already have one matching value */
2399                         while(cond->value_extension && cond->next)
2400                                 cond = cond->next;
2401
2402                         cond = cond->next;
2403                 }
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 */
2406                 {
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 */
2412                 }
2413                 if (match == 1)
2414                 {
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;
2420                         break;
2421                 }
2422                 if (match == 2)
2423                 {
2424                         /* rule could match if more is dialed */
2425                         couldmatch = 1;
2426                 }
2427                 rule = rule->next;
2428         }
2429         return(action);
2430 }
2431
2432 /*
2433  * parses the current action's parameters and return them
2434  */
2435 struct route_param *EndpointAppPBX::routeparam(struct route_action *action, unsigned long long id)
2436 {
2437         struct route_param *param = action->param_first;
2438
2439         while(param)
2440         {
2441                 if (param->id == id)
2442                         break;
2443                 param = param->next;
2444         }
2445         return(param);
2446 }
2447
2448
2449 /*
2450  * internal rules that are not defined by route.conf
2451  */
2452 struct route_action action_password = {
2453         NULL,
2454         NULL,
2455         ACTION_PASSWORD,
2456         0,
2457         0,
2458 };
2459
2460 struct route_action action_password_write = {
2461         NULL,
2462         NULL,
2463         ACTION_PASSWORD_WRITE,
2464         0,
2465         0,
2466 };
2467
2468 struct route_action action_external = {
2469         NULL,
2470         NULL,
2471         ACTION_EXTERNAL,
2472         0,
2473         0,
2474 };
2475
2476 struct route_action action_internal = {
2477         NULL,
2478         NULL,
2479         ACTION_INTERNAL,
2480         0,
2481         0,
2482 };
2483
2484 struct route_action action_h323 = {
2485         NULL,
2486         NULL,
2487         ACTION_H323,
2488         0,
2489         0,
2490 };
2491
2492 struct route_action action_chan = {
2493         NULL,
2494         NULL,
2495         ACTION_CHAN,
2496         0,
2497         0,
2498 };
2499
2500 struct route_action action_vbox = {
2501         NULL,
2502         NULL,
2503         ACTION_VBOX_RECORD,
2504         0,
2505         0,
2506 };
2507
2508 struct route_action action_partyline = {
2509         NULL,
2510         NULL,
2511         ACTION_PARTYLINE,
2512         0,
2513         0,
2514 };
2515
2516 struct route_action action_disconnect = {
2517         NULL,
2518         NULL,
2519         ACTION_DISCONNECT,
2520         0,
2521         0,
2522 };
2523
2524