Data-Over-Voice
[lcr.git] / route.c
diff --git a/route.c b/route.c
index e8bf896..925bfe8 100644 (file)
--- a/route.c
+++ b/route.c
@@ -9,10 +9,6 @@
 **                                                                           **
 \*****************************************************************************/ 
 
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
 #include "main.h"
 
 
@@ -30,6 +26,8 @@ struct cond_defs cond_defs[] = {
          "interface=<interface>[,...]", "Matches if call is received from given interface(s). NOT PORTS!"},
        { "callerid",   MATCH_CALLERID, COND_TYPE_STRING,
          "callerid=<digits>[-<digits>][,...]", "Matches if caller ID matches or begins with the given (range(s) of) prefixes(s)."},
+       { "callerid2",  MATCH_CALLERID2,COND_TYPE_STRING,
+         "callerid2=<digits>[-<digits>][,...]", "Matches the second caller ID (network provided)."},
        { "extension",  MATCH_EXTENSION,COND_TYPE_STRING,
          "extension=<digits>[-<digits>][,...]", "Matches if caller calls from given (range(s) of) extension(s)."},
        { "dialing",    MATCH_DIALING,  COND_TYPE_STRING,
@@ -70,8 +68,8 @@ struct cond_defs cond_defs[] = {
          "capability=speech|audio|video|digital-restricted|digital-unrestricted|digital-unrestricted-tones[,...]", "Matches the given bearer capability(s)."},
        { "infolayer1", MATCH_INFOLAYER1, COND_TYPE_INTEGER,
          "infolayer1=<value>[,...]", "Matches the given information layer 1. (2=u-Law, 3=a-law, see info layer 1 in bearer capability.)"},
-       { "hlc",        MATCH_HLC,      COND_TYPE_INTEGER,
-         "hlc=<value>[,...]", "Matches the high layer capability(s)."},
+       { "hlc",        MATCH_HLC,      COND_TYPE_HLC,
+         "hlc=telephony|faxg2g3|faxg4|teletex1|teletex2|teletex3|videotex1|videotex2|telex|mhs|osi|maintenance|management|audiovisual[,...]", "Matches the high layer capability(s)."},
        { "file",       MATCH_FILE,     COND_TYPE_STRING,
          "file=<path>[,...]", "Mathes is the given file exists and if the first character is '1'."},
        { "execute",    MATCH_EXECUTE,  COND_TYPE_STRING,
@@ -94,8 +92,16 @@ struct cond_defs cond_defs[] = {
          "notbusy=<extension>[,...]","Matches if any of the given extension is not busy."},
        { "remote",     MATCH_REMOTE,   COND_TYPE_STRING,
          "remote=<application name>","Matches if remote application is running."},
-       { "notremote",  MATCH_NOTREMOTE,COND_TYPE_NULL,
+       { "notremote",  MATCH_NOTREMOTE,COND_TYPE_STRING,
          "notremote=<application name>","Matches if remote application is not running."},
+       { "pots-flash", MATCH_POTS_FLASH,COND_TYPE_NULL,
+         "pots-flash","When using POTS: Matches if call was invoked by flash/earth button."},
+       { "pots-cw",    MATCH_POTS_CW,  COND_TYPE_NULL,
+         "pots-cw","When using POTS: Matches if a call is waiting."},
+       { "pots-calls", MATCH_POTS_CALLS,COND_TYPE_INTEGER,
+         "pots-calls=<total number>","When using POTS: Matches if given number of calls are held."},
+       { "pots-last",  MATCH_POTS_LAST,COND_TYPE_INTEGER,
+         "pots-last=<call number>","When using POTS: Matches if given call number (1=oldest) was the last active call."},
        { NULL, 0, 0, NULL}
 };
 
@@ -123,16 +129,16 @@ struct param_defs param_defs[] = {
          "capability=speech|audio|video|digital-restricted|digital-unrestricted|digital-unrestricted-tones", "Alter the service type of the call."},
        { PARAM_BMODE,
          "bmode",      PARAM_TYPE_BMODE,
-         "capability=transparent|hdlc", "Alter the bchannel mode of the call. Use hdlc for data calls."},
+         "bmode=transparent|hdlc", "Alter the bchannel mode of the call. Use hdlc for data calls."},
        { PARAM_INFO1,
          "infolayer1", PARAM_TYPE_INTEGER,
          "infolayer1=<value>", "Alter the layer 1 information of a call. Use 3 for ALAW or 2 for uLAW."},
        { PARAM_HLC,
-         "hlc",        PARAM_TYPE_INTEGER,
-         "hlc=<value>", "Alter the HLC identification. Use 1 for telephony or omit."},
+         "hlc",        PARAM_TYPE_HLC,
+         "hlc=telephony|faxg2g3|faxg4|teletex1|teletex2|teletex3|videotex1|videotex2|telex|mhs|osi|maintenance|management|audiovisual", "Alter the HLC identification."},
        { PARAM_EXTHLC,
-         "exthlc",     PARAM_TYPE_INTEGER,
-         "exthlc=<value>", "Alter extended HLC value. (Mainenance only, don't use it.)"},
+         "exthlc",     PARAM_TYPE_HLC,
+         "exthlc=<value>", "Alter extended HLC value, see hlc. (Mainenance only, don't use it.)"},
        { PARAM_PRESENT,
          "present",    PARAM_TYPE_YESNO,
          "present=yes|no", "Allow or restrict caller ID regardless what the caller wants."},
@@ -220,6 +226,9 @@ struct param_defs param_defs[] = {
        { PARAM_ROOM,
          "room",       PARAM_TYPE_INTEGER,
          "room=<digits>", "Conference room number, must be greater 0, as in real life."},
+       { PARAM_JINGLE,
+         "jingle",     PARAM_TYPE_NULL,
+         "jingle", "Conference members will hear a jingle if a member joins."},
        { PARAM_TIMEOUT,
          "timeout",    PARAM_TYPE_INTEGER,
          "timeout=<seconds>", "Timeout before continue with next action."},
@@ -231,14 +240,29 @@ struct param_defs param_defs[] = {
          "strip", "Remove digits that were required to match this rule."},
        { PARAM_APPLICATION,
          "application",PARAM_TYPE_STRING,
-         "application", "Name of remote application to make call to."},
+         "application=<name>", "Name of remote application to make call to."},
+       { PARAM_CONTEXT,
+         "context",    PARAM_TYPE_STRING,
+         "context=<context>", "Give context parameter to the remote application."},
+       { PARAM_EXTEN,
+         "exten",      PARAM_TYPE_STRING,
+         "exten=<extension>", "Give exten parameter to the remote application. (overrides dialed number)"},
+       { PARAM_ON,
+         "on", PARAM_TYPE_STRING,
+         "on=[init|hangup]", "Defines if the action is executed on call init or on hangup."},
+       { PARAM_KEYPAD,
+         "keypad",     PARAM_TYPE_NULL,
+         "keypad", "Use 'keypad facility' for dialing, instead of 'called number'."},
+       { PARAM_POTS_CALL,
+         "pots-call",  PARAM_TYPE_INTEGER,
+         "pots-call=<call #>", "Select call number. The oldest call is number 1."},
        { 0, NULL, 0, NULL, NULL}
 };
 
 struct action_defs action_defs[] = {
        { ACTION_EXTERNAL,
          "extern",     &EndpointAppPBX::action_init_call, &EndpointAppPBX::action_dialing_external, &EndpointAppPBX::action_hangup_call,
-         PARAM_CONNECT | PARAM_PREFIX | PARAM_COMPLETE | PARAM_TYPE | PARAM_CAPA | PARAM_BMODE | PARAM_INFO1 | PARAM_HLC | PARAM_EXTHLC | PARAM_PRESENT | PARAM_INTERFACES | PARAM_CALLERID | PARAM_CALLERIDTYPE | PARAM_TIMEOUT,
+         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_KEYPAD | PARAM_CONTEXT | PARAM_TIMEOUT,
          "Call is routed to extern number as dialed."},
        { ACTION_INTERNAL,
          "intern",     &EndpointAppPBX::action_init_call, &EndpointAppPBX::action_dialing_internal, &EndpointAppPBX::action_hangup_call,
@@ -246,19 +270,15 @@ struct action_defs action_defs[] = {
          "Call is routed to intern extension as given by the dialed number or specified by option."},
        { ACTION_OUTDIAL,
          "outdial",    &EndpointAppPBX::action_init_call, &EndpointAppPBX::action_dialing_external, &EndpointAppPBX::action_hangup_call,
-         PARAM_CONNECT | PARAM_PREFIX | PARAM_COMPLETE | PARAM_TYPE | PARAM_CAPA | PARAM_BMODE | PARAM_INFO1 | PARAM_HLC | PARAM_EXTHLC | PARAM_PRESENT | PARAM_INTERFACES | PARAM_CALLERID | PARAM_CALLERIDTYPE | PARAM_TIMEOUT,
+         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_KEYPAD | PARAM_TIMEOUT,
          "Same as 'extern'"},
-       { ACTION_REMOTE,
-         "remote",     &EndpointAppPBX::action_init_remote, &EndpointAppPBX::action_dialing_remote, &EndpointAppPBX::action_hangup_call,
-         PARAM_CONNECT | PARAM_APPLICATION | PARAM_TIMEOUT,
-         "Call is routed to Remote application, like Asterisk."},
        { ACTION_VBOX_RECORD,
          "vbox-record",&EndpointAppPBX::action_init_call, &EndpointAppPBX::action_dialing_vbox_record, &EndpointAppPBX::action_hangup_call,
          PARAM_CONNECT | PARAM_EXTENSION | PARAM_ANNOUNCEMENT | PARAM_TIMEOUT,
          "Caller is routed to the voice box of given extension."},
        { ACTION_PARTYLINE,
          "partyline",&EndpointAppPBX::action_init_partyline, NULL, &EndpointAppPBX::action_hangup_call,
-         PARAM_ROOM,
+         PARAM_ROOM | PARAM_JINGLE,
          "Caller is participating the conference with the given room number."},
        { ACTION_LOGIN,
          "login",      NULL, &EndpointAppPBX::action_dialing_login, NULL,
@@ -283,7 +303,7 @@ struct action_defs action_defs[] = {
        { ACTION_REPLY,
          "reply",      &EndpointAppPBX::action_init_redial_reply, &EndpointAppPBX::action_dialing_reply, NULL,
          PARAM_CONNECT | PARAM_SELECT,
-         "Caller replies. (last incomming call(s))"},
+         "Caller replies. (last incoming call(s))"},
        { ACTION_POWERDIAL,
          "powerdial",  NULL, &EndpointAppPBX::action_dialing_powerdial, NULL,
          PARAM_CONNECT | PARAM_DELAY | PARAM_LIMIT | PARAM_TIMEOUT,
@@ -319,7 +339,7 @@ struct action_defs action_defs[] = {
 //       "Caller calls the timer."},
        { ACTION_GOTO,
          "goto",       NULL, &EndpointAppPBX::action_dialing_goto, NULL,
-         PARAM_CONNECT | PARAM_RULESET | PARAM_STRIP | PARAM_SAMPLE,
+         PARAM_PROCEEDING | PARAM_ALERTING | PARAM_CONNECT | PARAM_RULESET | PARAM_STRIP | PARAM_SAMPLE,
          "Jump to given ruleset and optionally play sample. Dialed digits are not flushed."},
        { ACTION_MENU,
          "menu",       NULL, &EndpointAppPBX::action_dialing_menu, NULL,
@@ -329,11 +349,10 @@ struct action_defs action_defs[] = {
          "disconnect", NULL, &EndpointAppPBX::action_dialing_disconnect, NULL,
          PARAM_CONNECT | PARAM_CAUSE | PARAM_LOCATION | PARAM_SAMPLE | PARAM_DISPLAY,
          "Caller gets disconnected optionally with given cause and given sample and given display text."},
-       { ACTION_HELP,
-         "help",       NULL, &EndpointAppPBX::action_dialing_help, NULL,
-         PARAM_CONNECT | PARAM_TIMEOUT,
-         NULL},
-//       "Caller will be able to select from current rules that would match. (using * and #)"},
+       { ACTION_RELEASE,
+         "release",    NULL, &EndpointAppPBX::action_dialing_release, NULL,
+         PARAM_CONNECT | PARAM_CAUSE | PARAM_LOCATION | PARAM_DISPLAY,
+         "Same as 'disconnect', but using RELEASE message on ISDN."},
        { ACTION_DEFLECT,
          "deflect",    NULL, &EndpointAppPBX::action_dialing_deflect, NULL,
          PARAM_DEST,
@@ -345,8 +364,8 @@ struct action_defs action_defs[] = {
          NULL},
 //       "The call forward is set within the telephone network of the external line."},
        { ACTION_EXECUTE,
-         "execute",    NULL, NULL, &EndpointAppPBX::action_hangup_execute,
-         PARAM_CONNECT | PARAM_EXECUTE | PARAM_PARAM,
+         "execute",    &EndpointAppPBX::action_init_execute, NULL, &EndpointAppPBX::action_hangup_execute,
+         PARAM_CONNECT | PARAM_EXECUTE | PARAM_PARAM | PARAM_ON | PARAM_TIMEOUT,
          "Executes the given script file. The file must terminate quickly, because it will halt the PBX."},
        { ACTION_FILE,
          "file",       NULL, NULL, &EndpointAppPBX::action_hangup_file,
@@ -372,6 +391,30 @@ struct action_defs action_defs[] = {
          "efi",        &EndpointAppPBX::action_init_efi, NULL, NULL,
          PARAM_PROCEEDING | PARAM_ALERTING | PARAM_CONNECT,
          "Elektronische Fernsprecher Identifikation - announces caller ID."},
+       { ACTION_POTS_RETRIEVE,
+         "pots-retrieve",      &EndpointAppPBX::action_init_pots_retrieve, NULL, NULL,
+         PARAM_POTS_CALL,
+         "When using POTS: Select call on hold to retrieve."},
+       { ACTION_POTS_RELEASE,
+         "pots-release",       &EndpointAppPBX::action_init_pots_release, NULL, NULL,
+         PARAM_POTS_CALL,
+         "When using POTS: Select call on hold to release."},
+       { ACTION_POTS_REJECT,
+         "pots-reject",        &EndpointAppPBX::action_init_pots_reject, NULL, NULL,
+         0,
+         "When using POTS: Reject incomming waiting call."},
+       { ACTION_POTS_ANSWER,
+         "pots-answer",        &EndpointAppPBX::action_init_pots_answer, NULL, NULL,
+         0,
+         "When using POTS: Answer incomming waiting call."},
+       { ACTION_POTS_3PTY,
+         "pots-3pty",          &EndpointAppPBX::action_init_pots_3pty, NULL, NULL,
+         0,
+         "When using POTS: Invoke 3PTY call of two calls on hold"},
+       { ACTION_POTS_TRANSFER,
+         "pots-transfer",      &EndpointAppPBX::action_init_pots_transfer, NULL, NULL,
+         0,
+         "When using POTS: Interconnect two calls on hold"},
        { -1,
          NULL, NULL, NULL, NULL, 0, NULL}
 };
@@ -383,17 +426,14 @@ void doc_rules(const char *name)
 {
        int i, j;
 
-       if (name)
-       {
+       if (name) {
                i = 0;
-               while(action_defs[i].name)
-               {
+               while(action_defs[i].name) {
                        if (!strcasecmp(action_defs[i].name, name))
                                break;
                        i++;
                }
-               if (!action_defs[i].name)
-               {
+               if (!action_defs[i].name) {
                        fprintf(stderr, "Given action '%s' unknown.\n", name);
                        return;
                }
@@ -407,13 +447,11 @@ void doc_rules(const char *name)
        printf("...\n");
        printf("Please refer to the documentation for description on rule format.\n\n");
 
-       if (!name)
-       {
+       if (!name) {
                printf("Available conditions to match:\n");
                printf("------------------------------\n\n");
                i = 0;
-               while(cond_defs[i].name)
-               {
+               while(cond_defs[i].name) {
                        printf("Usage: %s\n", cond_defs[i].doc);
                        printf("%s\n\n", cond_defs[i].help);
                        i++;
@@ -421,38 +459,31 @@ void doc_rules(const char *name)
 
                printf("Available actions with their parameters:\n");
                printf("----------------------------------------\n\n");
-       } else
-       {
+       } else {
                printf("Detailes parameter description of action:\n");
                printf("-----------------------------------------\n\n");
        }
        i = 0;
-       while(action_defs[i].name)
-       {
-               if (name && !!strcmp(action_defs[i].name,name)) /* not selected */
-               {
+       while(action_defs[i].name) {
+               if (name && !!strcmp(action_defs[i].name,name)) { /* not selected */
                        i++;
                        continue;
                }
-               if (!action_defs[i].help) /* not internal actions */
-               {
+               if (!action_defs[i].help) { /* not internal actions */
                        i++;
                        continue;
                }
                printf("Usage: %s", action_defs[i].name);
                j = 0;
-               while(j < 64)
-               {
+               while(j < 64) {
                        if ((1LL<<j) & action_defs[i].params)
                                printf(" [%s]", param_defs[j].doc);
                        j++;
                }
                printf("\n%s\n\n", action_defs[i].help);
-               if (name) /* only show parameter help for specific action */
-               {
+               if (name) { /* only show parameter help for specific action */
                        j = 0;
-                       while(j < 64)
-                       {
+                       while(j < 64) {
                                if ((1LL<<j) & action_defs[i].params)
                                        printf("%s:\n\t%s\n", param_defs[j].doc, param_defs[j].help);
                                j++;
@@ -471,24 +502,19 @@ void ruleset_free(struct route_ruleset *ruleset_start)
        struct route_action *action;
        struct route_param *param;
 
-       while(ruleset_start)
-       {
+       while(ruleset_start) {
                ruleset = ruleset_start;
                ruleset_start = ruleset->next;
-               while(ruleset->rule_first)
-               {
+               while(ruleset->rule_first) {
                        rule = ruleset->rule_first;
                        ruleset->rule_first = rule->next;
-                       while(rule->cond_first)
-                       {
+                       while(rule->cond_first) {
                                cond = rule->cond_first;
-                               if (cond->string_value)
-                               {
+                               if (cond->string_value) {
                                        FREE(cond->string_value, 0);
                                        rmemuse--;
                                }
-                               if (cond->string_value_to)
-                               {
+                               if (cond->string_value_to) {
                                        FREE(cond->string_value_to, 0);
                                        rmemuse--;
                                }
@@ -496,16 +522,13 @@ void ruleset_free(struct route_ruleset *ruleset_start)
                                FREE(cond, sizeof(struct route_cond));
                                rmemuse--;
                        }
-                       while(rule->action_first)
-                       {
+                       while(rule->action_first) {
                                action = rule->action_first;
                                rule->action_first = action->next;
-                               while(action->param_first)
-                               {
+                               while(action->param_first) {
                                        param = action->param_first;
                                        action->param_first = param->next;
-                                       if (param->string_value)
-                                       {
+                                       if (param->string_value) {
                                                FREE(param->string_value, 0);
                                                rmemuse--;
                                        }
@@ -533,17 +556,14 @@ void ruleset_debug(struct route_ruleset *ruleset_start)
        int                     first;
 
        ruleset = ruleset_start;
-       while(ruleset)
-       {
+       while(ruleset) {
                printf("Ruleset: '%s'\n", ruleset->name);
                rule = ruleset->rule_first;
-               while(rule)
-               {
+               while(rule) {
                        /* CONDITION */
                        first = 1;
                        cond = rule->cond_first;
-                       while(cond)
-                       {
+                       while(cond) {
                                if (first)
                                        printf("    Condition:");
                                else
@@ -553,8 +573,7 @@ void ruleset_debug(struct route_ruleset *ruleset_start)
                                if (cond->value_type != VALUE_TYPE_NULL)
                                        printf(" = ");
                                next_cond_value:
-                               switch(cond->value_type)
-                               {
+                               switch(cond->value_type) {
                                        case VALUE_TYPE_NULL:
                                        break;
 
@@ -577,8 +596,7 @@ void ruleset_debug(struct route_ruleset *ruleset_start)
                                        default:
                                        printf("Software error: VALUE_TYPE_* %d not known in function '%s' line=%d", cond->value_type, __FUNCTION__, __LINE__);
                                }
-                               if (cond->value_extension && cond->next)
-                               {
+                               if (cond->value_extension && cond->next) {
                                        cond = cond->next;
                                        printf(" or ");
                                        goto next_cond_value;
@@ -590,14 +608,12 @@ void ruleset_debug(struct route_ruleset *ruleset_start)
 
                        /* ACTION */
                        action = rule->action_first;
-                       while(action)
-                       {
+                       while(action) {
                                printf("    Action: %s\n", action_defs[action->index].name);
                                /* PARAM */
                                first = 1;
                                param = action->param_first;
-                               while(param)
-                               {
+                               while(param) {
                                        if (first)
                                                printf("    Param:");
                                        else
@@ -606,16 +622,13 @@ void ruleset_debug(struct route_ruleset *ruleset_start)
                                        printf(" %s", param_defs[param->index].name);
                                        if (param->value_type != VALUE_TYPE_NULL)
                                                printf(" = ");
-                                       switch(param->value_type)
-                                       {
+                                       switch(param->value_type) {
                                                case VALUE_TYPE_NULL:
                                                break;
 
                                                case VALUE_TYPE_INTEGER:
-                                               if (param_defs[param->index].type == PARAM_TYPE_CALLERIDTYPE)
-                                               {
-                                                       switch(param->integer_value)
-                                                       {
+                                               if (param_defs[param->index].type == PARAM_TYPE_CALLERIDTYPE) {
+                                                       switch(param->integer_value) {
                                                                case INFO_NTYPE_UNKNOWN:
                                                                printf("unknown");
                                                                break;
@@ -633,10 +646,8 @@ void ruleset_debug(struct route_ruleset *ruleset_start)
                                                        }
                                                        break;
                                                }
-                                               if (param_defs[param->index].type == PARAM_TYPE_CAPABILITY)
-                                               {
-                                                       switch(param->integer_value)
-                                                       {
+                                               if (param_defs[param->index].type == PARAM_TYPE_CAPABILITY) {
+                                                       switch(param->integer_value) {
                                                                case INFO_BC_SPEECH:
                                                                printf("speech");
                                                                break;
@@ -660,10 +671,8 @@ void ruleset_debug(struct route_ruleset *ruleset_start)
                                                        }
                                                        break;
                                                }
-                                               if (param_defs[param->index].type == PARAM_TYPE_DIVERSION)
-                                               {
-                                                       switch(param->integer_value)
-                                                       {
+                                               if (param_defs[param->index].type == PARAM_TYPE_DIVERSION) {
+                                                       switch(param->integer_value) {
                                                                case INFO_DIVERSION_CFU:
                                                                printf("cfu");
                                                                break;
@@ -681,10 +690,8 @@ void ruleset_debug(struct route_ruleset *ruleset_start)
                                                        }
                                                        break;
                                                }
-                                               if (param_defs[param->index].type == PARAM_TYPE_TYPE)
-                                               {
-                                                       switch(param->integer_value)
-                                                       {
+                                               if (param_defs[param->index].type == PARAM_TYPE_TYPE) {
+                                                       switch(param->integer_value) {
                                                                case INFO_NTYPE_UNKNOWN:
                                                                printf("unknown");
                                                                break;
@@ -702,10 +709,8 @@ void ruleset_debug(struct route_ruleset *ruleset_start)
                                                        }
                                                        break;
                                                }
-                                               if (param_defs[param->index].type == PARAM_TYPE_YESNO)
-                                               {
-                                                       switch(param->integer_value)
-                                                       {
+                                               if (param_defs[param->index].type == PARAM_TYPE_YESNO) {
+                                                       switch(param->integer_value) {
                                                                case 1:
                                                                printf("yes");
                                                                break;
@@ -717,8 +722,7 @@ void ruleset_debug(struct route_ruleset *ruleset_start)
                                                        }
                                                        break;
                                                }
-                                               if (param_defs[param->index].type == PARAM_TYPE_NULL)
-                                               {
+                                               if (param_defs[param->index].type == PARAM_TYPE_NULL) {
                                                        break;
                                                }
                                                printf("%d", param->integer_value);
@@ -751,32 +755,26 @@ void ruleset_debug(struct route_ruleset *ruleset_start)
 /*
  * parse ruleset
  */
-static char *read_string(char *p, char *key, int key_size, char *special)
+static char *read_string(char *p, char *key, int key_size, const char *special)
 {
        key[0] = 0;
 
-       if (*p == '\"')
-       {
+       if (*p == '\"') {
                p++;
                /* quote */
-               while(*p)
-               {
-                       if (*p == '\"')
-                       {
+               while(*p) {
+                       if (*p == '\"') {
                                p++;
                                *key = '\0';
                                return(p);
                        }
-                       if (*p == '\\')
-                       {
+                       if (*p == '\\') {
                                p++;
-                               if (*p == '\0')
-                               {
+                               if (*p == '\0') {
                                        break;
                                }
                        }
-                       if (--key_size == 0)
-                       {
+                       if (--key_size == 0) {
                                UPRINT(key, "\001String too long.");
                                return(p);
                        }
@@ -787,24 +785,19 @@ static char *read_string(char *p, char *key, int key_size, char *special)
        }
 
        /* no quote */
-       while(*p)
-       {
-               if (strchr(special, *p))
-               {
+       while(*p) {
+               if (strchr(special, *p)) {
                        *key = '\0';
                        return(p);
                }
-               if (*p == '\\')
-               {
+               if (*p == '\\') {
                        p++;
-                       if (*p == '\0')
-                       {
+                       if (*p == '\0') {
                                UPRINT(key, "\001Unexpected end of line.");
                                return(p);
                        }
                }
-               if (--key_size == 0)
-               {
+               if (--key_size == 0) {
                        UPRINT(key, "\001String too long.");
                        return(p);
                }
@@ -848,13 +841,12 @@ struct route_ruleset *ruleset_parse(void)
        struct route_param      *param;
        struct route_param      **param_pointer = NULL;
        char                    failure[256];
+       unsigned long long      allowed_params;
 
        /* check the integrity of IDs for ACTION_* and PARAM_* */
        i = 0;
-       while(action_defs[i].name)
-       {
-               if (action_defs[i].id != i)
-               {
+       while(action_defs[i].name) {
+               if (action_defs[i].id != i) {
                        PERROR("Software Error action '%s' must have id of %d, but has %d.\n",
                                action_defs[i].name, i, action_defs[i].id);
                        goto openerror;
@@ -862,10 +854,8 @@ struct route_ruleset *ruleset_parse(void)
                i++;
        }
        i = 0; j = 1;
-       while(param_defs[i].name)
-       {
-               if (param_defs[i].id != j)
-               {
+       while(param_defs[i].name) {
+               if (param_defs[i].id != j) {
                        PERROR("Software Error param '%s' must have id of 0x%llx, but has 0x%llx.\n",
                                param_defs[i].name, j, param_defs[i].id);
                        goto openerror;
@@ -874,7 +864,7 @@ struct route_ruleset *ruleset_parse(void)
                j<<=1;
        }
 
-        SPRINT(filename[0], "%s/routing.conf", INSTALL_DATA);
+        SPRINT(filename[0], "%s/routing.conf", CONFIG_DATA);
 
         if (!(fp[0]=fopen(filename[0],"r")))
         {
@@ -887,11 +877,9 @@ struct route_ruleset *ruleset_parse(void)
        go_leaf:
         line[nesting]=0;
        go_root:
-        while((fgets(buffer,sizeof(buffer),fp[nesting])))
+        while((GETLINE(buffer, fp[nesting])))
         {
                 line[nesting]++;
-                buffer[sizeof(buffer)-1]=0;
-                if (buffer[0]) buffer[strlen(buffer)-1]=0;
                 p = buffer;
 
                /* remove tabs */
@@ -911,8 +899,7 @@ struct route_ruleset *ruleset_parse(void)
                }
 
                /* skip comments */
-               if (*p == '#')
-               {
+               if (*p == '#') {
                        p++;
                        /* don't skip "define" */
                        if (!!strncmp(p, "define", 6))
@@ -921,30 +908,26 @@ struct route_ruleset *ruleset_parse(void)
                        if (*p != 32)
                                continue;
                        /* skip spaces */
-                       while(*p == 32)
-                       {
+                       while(*p == 32) {
                                if (*p == 0)
                                        break;
                                p++;
                        }
                        p++;
                        p = read_string(p, key, sizeof(key), " ");
-                       if (key[0] == 1) /* error */
-                       {
+                       if (key[0] == 1) { /* error */
                                SPRINT(failure, "Parsing Filename failed: %s", key+1);
                                goto parse_error;
                        }
-                       if (nesting == MAXNESTING-1)
-                       {
+                       if (nesting == MAXNESTING-1) {
                                SPRINT(failure, "'include' is nesting too deep.\n");
                                goto parse_error;
                        }
                        if (key[0] == '/')
                                SCPY(filename[nesting+1], key);
                        else
-                               SPRINT(filename[nesting+1], "%s/%s", INSTALL_DATA, key);
-                       if (!(fp[nesting+1]=fopen(filename[nesting+1],"r")))
-                       {
+                               SPRINT(filename[nesting+1], "%s/%s", CONFIG_DATA, key);
+                       if (!(fp[nesting+1]=fopen(filename[nesting+1],"r"))) {
                                PERROR("Cannot open %s\n", filename[nesting+1]);
                                goto parse_error;
                        }
@@ -960,12 +943,10 @@ struct route_ruleset *ruleset_parse(void)
                        continue;
 
                /* expecting ruleset */
-               if (expecting)
-               {
+               if (expecting) {
                        new_ruleset:
                        /* expecting [ */
-                       if (*p != '[')
-                       {
+                       if (*p != '[') {
                                SPRINT(failure, "Expecting ruleset name starting with '['.");
                                goto parse_error;
                        }
@@ -973,8 +954,7 @@ struct route_ruleset *ruleset_parse(void)
 
                        /* reading ruleset name text */
                        i = 0;
-                       while((*p>='a' && *p<='z') || (*p>='A' && *p<='Z') || (*p>='0' && *p<='9'))
-                       {
+                       while(*p>' ' && *p<127 && *p!=']') {
                                if (*p>='A' && *p<='Z') *p = *p-'A'+'a'; /* lower case */
                                key[i++] = *p++;
                                if (i == sizeof(key)) i--; /* limit */
@@ -998,10 +978,8 @@ struct route_ruleset *ruleset_parse(void)
 
                        /* check for duplicate rulesets */
                        ruleset = ruleset_start;
-                       while(ruleset)
-                       {
-                               if (!strcmp(ruleset->name, key))
-                               {
+                       while(ruleset) {
+                               if (!strcmp(ruleset->name, key)) {
                                        SPRINT(failure, "Duplicate ruleset '%s', already defined in file '%s' line %d.", key, ruleset->file, ruleset->line);
                                        goto parse_error;
                                }
@@ -1022,8 +1000,7 @@ struct route_ruleset *ruleset_parse(void)
                }
 
                /* for new ruleset [ */
-               if (*p == '[')
-               {
+               if (*p == '[') {
                        goto new_ruleset;
                }
 
@@ -1038,65 +1015,53 @@ struct route_ruleset *ruleset_parse(void)
                rule->line = line[nesting];
 
                /* loop CONDITIONS */
-               while(*p!=':' && *p!='\0')
-               {
+               while(*p!=':' && *p!='\0') {
                        /* read item text */
                        i = 0;
-                       while((*p>='a' && *p<='z') || (*p>='A' && *p<='Z') || (*p>='0' && *p<='9'))
-                       {
+                       while((*p>='a' && *p<='z') || (*p>='A' && *p<='Z') || (*p>='0' && *p<='9') || *p == '-') {
                                if (*p>='A' && *p<='Z') *p = *p-'A'+'a'; /* lower case */
                                key[i++] = *p++;
                                if (i == sizeof(key)) i--; /* limit */
                        }
                        key[i] = 0;
-                       if (key[0] == '\0')
-                       {
+                       if (key[0] == '\0') {
                                SPRINT(failure, "Expecting condition item name or ':' for end of condition list.");
                                goto parse_error;
                        }
-                       if (*p!=' ' && *p!='=')
-                       {
+                       if (*p!=' ' && *p!='=') {
                                SPRINT(failure, "Illegal character '%c' after condition name '%s'. Expecting '=' for equation or ' ' to seperate condition items.", *p, key);
                                goto parse_error;
                        }
 
                        /* check if condition exists */
                        index = 0;
-                       while(cond_defs[index].name)
-                       {
+                       while(cond_defs[index].name) {
                                if (!strcmp(cond_defs[index].name, key))
                                        break;
                                index++;
                        }
-                       if (cond_defs[index].name == NULL)
-                       {
+                       if (cond_defs[index].name == NULL) {
                                SPRINT(failure, "Unknown condition item name '%s'.", key);
                                goto parse_error;
                        }
 
                        /* items without values must not have any parameter */
-                       if (cond_defs[index].type == COND_TYPE_NULL)
-                       {
-                               if (*p == '=')
-                               {
+                       if (cond_defs[index].type == COND_TYPE_NULL) {
+                               if (*p == '=') {
                                        SPRINT(failure, "Condition item '%s' must not have any value. Don't use '=' for this type of condition.", key);
                                        goto parse_error;
                                }
-                               if (*p != ' ')
-                               {
+                               if (*p != ' ') {
                                        SPRINT(failure, "Condition item '%s' must not have any value. Expecting ' ' or tab after item name.", key);
                                        goto parse_error;
                                }
 //                             p++;
-                       } else
-                       {
-                               if (*p == ' ')
-                               {
+                       } else {
+                               if (*p == ' ') {
                                        SPRINT(failure, "Condition item '%s' must have at least one value, '=' expected, and not a space.", key);
                                        goto parse_error;
                                }
-                               if (*p != '=')
-                               {
+                               if (*p != '=') {
                                        SPRINT(failure, "Condition item '%s' must have at least one value, '=' expected.", key);
                                        goto parse_error;
                                }
@@ -1105,10 +1070,8 @@ struct route_ruleset *ruleset_parse(void)
 
                        /* check for duplicate condition */
                        cond = rule->cond_first;
-                       while(cond)
-                       {
-                               if (cond->index == index)
-                               {
+                       while(cond) {
+                               if (cond->index == index) {
                                        SPRINT(failure, "Duplicate condition '%s', use ',' to give multiple values.", key);
                                        goto parse_error;
                                }
@@ -1123,11 +1086,9 @@ struct route_ruleset *ruleset_parse(void)
                        cond_pointer = &(cond->next);
                        cond->index = index;
                        cond->match = cond_defs[index].match;
-                       switch(cond_defs[index].type)
-                       {
+                       switch(cond_defs[index].type) {
                                case COND_TYPE_NULL:
-                               if (*p=='=')
-                               {
+                               if (*p=='=') {
                                        SPRINT(failure, "Expecting no value.");
                                        goto parse_error;
                                }
@@ -1142,40 +1103,33 @@ struct route_ruleset *ruleset_parse(void)
                                case COND_TYPE_WDAY:
                                case COND_TYPE_YEAR:
                                integer = integer_to = 0;
-                               if (*p==',' || *p==' ' || *p=='\0')
-                               {
+                               if (*p==',' || *p==' ' || *p=='\0') {
                                        SPRINT(failure, "Missing integer value.");
                                        goto parse_error;
                                }
-                               while(*p>='0' && *p<='9')
-                               {
+                               while(*p>='0' && *p<='9') {
                                        integer = integer*10 + *p-'0';
                                        p++;
                                }
                                value_type = VALUE_TYPE_INTEGER;
-                               if (*p == '-')
-                               {
+                               if (*p == '-') {
                                        p++;
-                                       if (*p==',' || *p==' ' || *p=='\0')
-                                       {
+                                       if (*p==',' || *p==' ' || *p=='\0') {
                                                SPRINT(failure, "Missing integer value.");
                                                goto parse_error;
                                        }
-                                       while(*p>='0' && *p<='9')
-                                       {
+                                       while(*p>='0' && *p<='9') {
                                                integer_to = integer_to*10 + *p-'0';
                                                p++;
                                        }
                                        value_type = VALUE_TYPE_INTEGER_RANGE;
                                }
-                               if (cond_defs[index].type == COND_TYPE_TIME)
-                               {
+                               if (cond_defs[index].type == COND_TYPE_TIME) {
                                        // Simon: i store the time as decimal, later i compare it correctly:
                                        // hours * 100 + minutes
                                        if (integer == 2400)
                                                integer = 0;
-                                       if (integer >= 2400)
-                                       {
+                                       if (integer >= 2400) {
                                                timeoutofrange1:
                                                SPRINT(failure, "Given time '%d' not in range 0000..2359 (or 2400 for 0000)", integer);
                                                goto parse_error;
@@ -1186,8 +1140,7 @@ struct route_ruleset *ruleset_parse(void)
                                                goto integer_done;
                                        if (integer_to == 2400)
                                                integer_to = 0;
-                                       if (integer_to >= 2400)
-                                       {
+                                       if (integer_to >= 2400) {
                                                timeoutofrange2:
                                                SPRINT(failure, "Given time '%d' not in range 0000..2359 (or 2400 for 0000)", integer_to);
                                                goto parse_error;
@@ -1195,62 +1148,50 @@ struct route_ruleset *ruleset_parse(void)
                                        if (integer_to%100 >= 60)
                                                goto timeoutofrange2;
                                }
-                               if (cond_defs[index].type == COND_TYPE_MDAY)
-                               {
-                                       if (integer<1 || integer>31)
-                                       {
+                               if (cond_defs[index].type == COND_TYPE_MDAY) {
+                                       if (integer<1 || integer>31) {
                                                SPRINT(failure, "Given day-of-month '%d' not in range 1..31", integer);
                                                goto parse_error;
                                        } 
                                        if (value_type == VALUE_TYPE_INTEGER)
                                                goto integer_done;
-                                       if (integer_to<1 || integer_to>31)
-                                       {
+                                       if (integer_to<1 || integer_to>31) {
                                                SPRINT(failure, "Given day-of-month '%d' not in range 1..31", integer_to);
                                                goto parse_error;
                                        } 
                                }
-                               if (cond_defs[index].type == COND_TYPE_WDAY)
-                               {
-                                       if (integer<1 || integer>7)
-                                       {
+                               if (cond_defs[index].type == COND_TYPE_WDAY) {
+                                       if (integer<1 || integer>7) {
                                                SPRINT(failure, "Given day-of-week '%d' not in range 1..7", integer);
                                                goto parse_error;
                                        } 
                                        if (value_type == VALUE_TYPE_INTEGER)
                                                goto integer_done;
-                                       if (integer_to<1 || integer_to>7)
-                                       {
+                                       if (integer_to<1 || integer_to>7) {
                                                SPRINT(failure, "Given day-of-week '%d' not in range 1..7", integer_to);
                                                goto parse_error;
                                        } 
                                }
-                               if (cond_defs[index].type == COND_TYPE_MONTH)
-                               {
-                                       if (integer<1 || integer>12)
-                                       {
+                               if (cond_defs[index].type == COND_TYPE_MONTH) {
+                                       if (integer<1 || integer>12) {
                                                SPRINT(failure, "Given month '%d' not in range 1..12", integer);
                                                goto parse_error;
                                        } 
                                        if (value_type == VALUE_TYPE_INTEGER)
                                                goto integer_done;
-                                       if (integer_to<1 || integer_to>12)
-                                       {
+                                       if (integer_to<1 || integer_to>12) {
                                                SPRINT(failure, "Given month '%d' not in range 1..12", integer_to);
                                                goto parse_error;
                                        } 
                                }
-                               if (cond_defs[index].type == COND_TYPE_YEAR)
-                               {
-                                       if (integer<1970 || integer>2106)
-                                       {
+                               if (cond_defs[index].type == COND_TYPE_YEAR) {
+                                       if (integer<1970 || integer>2106) {
                                                SPRINT(failure, "Given year '%d' not in range 1970..2106", integer);
                                                goto parse_error;
                                        } 
                                        if (value_type == VALUE_TYPE_INTEGER)
                                                goto integer_done;
-                                       if (integer_to<1970 || integer_to>2106)
-                                       {
+                                       if (integer_to<1970 || integer_to>2106) {
                                                SPRINT(failure, "Given year '%d' not in range 1970..2106", integer_to);
                                                goto parse_error;
                                        } 
@@ -1264,40 +1205,33 @@ struct route_ruleset *ruleset_parse(void)
                                /* parse all string values/ranges */
                                case COND_TYPE_STRING:
                                key[0] = key_to[0] = '\0';
-                               if (*p==',' || *p==' ' || *p=='\0')
-                               {
+                               if (*p==',' || *p==' ' || *p=='\0') {
                                        SPRINT(failure, "Missing string value, use \"\" for empty string.");
                                        goto parse_error;
                                }
                                p = read_string(p, key, sizeof(key), "-, ");
-                               if (key[0] == 1) /* error */
-                               {
+                               if (key[0] == 1) { /* error */
                                        SPRINT(failure, "Parsing String failed: %s", key+1);
                                        goto parse_error;
                                }
                                value_type = VALUE_TYPE_STRING;
-                               if (*p == '-')
-                               {
+                               if (*p == '-') {
                                        p++;
-                                       if (*p==',' || *p==' ' || *p=='\0')
-                                       {
+                                       if (*p==',' || *p==' ' || *p=='\0') {
                                                SPRINT(failure, "Missing string value, use \"\" for empty string.");
                                                goto parse_error;
                                        }
                                        p = read_string(p, key_to, sizeof(key_to), "-, ");
-                                       if (key_to[0] == 1) /* error */
-                                       {
+                                       if (key_to[0] == 1) { /* error */
                                                SPRINT(failure, "Parsing string failed: %s", key_to+1);
                                                goto parse_error;
                                        }
                                        value_type = VALUE_TYPE_STRING_RANGE;
-                                       if (strlen(key) != strlen(key_to))
-                                       {
+                                       if (strlen(key) != strlen(key_to)) {
                                                SPRINT(failure, "Given range of strings \"%s\"-\"%s\" have unequal length.", key, key_to);
                                                goto parse_error;
                                        }
-                                       if (key[0] == '\0')
-                                       {
+                                       if (key[0] == '\0') {
                                                SPRINT(failure, "Given range has no length.");
                                                goto parse_error;
                                        }
@@ -1306,8 +1240,7 @@ struct route_ruleset *ruleset_parse(void)
                                cond->string_value = (char *)MALLOC(strlen(key)+1);
                                rmemuse++;
                                UCPY(cond->string_value, key);
-                               if (value_type == VALUE_TYPE_STRING_RANGE)
-                               {
+                               if (value_type == VALUE_TYPE_STRING_RANGE) {
                                        cond->string_value_to = (char *)MALLOC(strlen(key_to)+1);
                                        rmemuse++;
                                        UCPY(cond->string_value_to, key_to);
@@ -1318,20 +1251,25 @@ struct route_ruleset *ruleset_parse(void)
 
                                /* parse service value */
                                case COND_TYPE_CAPABILITY:
-                               if (!strncasecmp("speech", p, 6))
+                               if (!strncasecmp("speech", p, 6)) {
                                        cond->integer_value = INFO_BC_SPEECH;
-                               else if (!strncasecmp("audio", p, 5))
+                                       p += 6;
+                               } else if (!strncasecmp("audio", p, 5)) {
                                        cond->integer_value = INFO_BC_AUDIO;
-                               else if (!strncasecmp("video", p, 5))
+                                       p += 5;
+                               } else if (!strncasecmp("video", p, 5)) {
                                        cond->integer_value = INFO_BC_VIDEO;
-                               else if (!strncasecmp("digital-restricted", p, 18))
+                                       p += 5;
+                               } else if (!strncasecmp("digital-restricted", p, 18)) {
                                        cond->integer_value = INFO_BC_DATARESTRICTED;
-                               else if (!strncasecmp("digital-unrestricted", p, 20))
+                                       p += 18;
+                               } else if (!strncasecmp("digital-unrestricted", p, 20)) {
                                        cond->integer_value = INFO_BC_DATAUNRESTRICTED;
-                               else if (!strncasecmp("digital-unrestricted-tones", p, 26))
+                                       p += 20;
+                               } else if (!strncasecmp("digital-unrestricted-tones", p, 26)) {
                                        cond->integer_value = INFO_BC_DATAUNRESTRICTED_TONES;
-                               else
-                               {
+                                       p += 26;
+                               } else {
                                        SPRINT(failure, "Given service type is invalid or misspelled.");
                                        goto parse_error;
                                }
@@ -1340,44 +1278,91 @@ struct route_ruleset *ruleset_parse(void)
 
                                /* parse bmode value */
                                case COND_TYPE_BMODE:
-                               if (!strncasecmp("transparent", p, 11))
+                               if (!strncasecmp("transparent", p, 11)) {
                                        cond->integer_value = INFO_BMODE_CIRCUIT;
-                               else if (!strncasecmp("hdlc", p, 4))
+                                       p += 11;
+                               } else if (!strncasecmp("hdlc", p, 4)) {
                                        cond->integer_value = INFO_BMODE_PACKET;
-                               else
-                               {
+                                       p += 4;
+                               } else {
                                        SPRINT(failure, "Given bchannel mode is invalid or misspelled.");
                                        goto parse_error;
                                }
                                cond->value_type = VALUE_TYPE_INTEGER;
                                break;
 
+                               /* parse service value */
+                               case COND_TYPE_HLC:
+                               if (!strncasecmp("telephony", p, 9)) {
+                                       cond->integer_value = INFO_HLC_TELEPHONY;
+                                       p += 9;
+                               } else if (!strncasecmp("faxg2g3", p, 7)) {
+                                       cond->integer_value = INFO_HLC_FAXG2G3;
+                                       p += 7;
+                               } else if (!strncasecmp("faxg4", p, 5)) {
+                                       cond->integer_value = INFO_HLC_FAXG4;
+                                       p += 5;
+                               } else if (!strncasecmp("teletex1", p, 8)) {
+                                       cond->integer_value = INFO_HLC_TELETEX1;
+                                       p += 8;
+                               } else if (!strncasecmp("teletex2", p, 8)) {
+                                       cond->integer_value = INFO_HLC_TELETEX2;
+                                       p += 8;
+                               } else if (!strncasecmp("teletex3", p, 8)) {
+                                       cond->integer_value = INFO_HLC_TELETEX3;
+                                       p += 8;
+                               } else if (!strncasecmp("videotex1", p, 9)) {
+                                       cond->integer_value = INFO_HLC_VIDEOTEX1;
+                                       p += 9;
+                               } else if (!strncasecmp("videotex2", p, 9)) {
+                                       cond->integer_value = INFO_HLC_VIDEOTEX2;
+                                       p += 9;
+                               } else if (!strncasecmp("telex", p, 5)) {
+                                       cond->integer_value = INFO_HLC_TELEX;
+                                       p += 5;
+                               } else if (!strncasecmp("mhs", p, 3)) {
+                                       cond->integer_value = INFO_HLC_MHS;
+                                       p += 3;
+                               } else if (!strncasecmp("osi", p, 3)) {
+                                       cond->integer_value = INFO_HLC_OSI;
+                                       p += 3;
+                               } else if (!strncasecmp("maintenance", p, 11)) {
+                                       cond->integer_value = INFO_HLC_MAINTENANCE;
+                                       p += 11;
+                               } else if (!strncasecmp("management", p, 10)) {
+                                       cond->integer_value = INFO_HLC_MANAGEMENT;
+                                       p += 10;
+                               } else if (!strncasecmp("audiovisual", p, 11)) {
+                                       cond->integer_value = INFO_HLC_AUDIOVISUAL;
+                                       p += 11;
+                               } else {
+                                       SPRINT(failure, "Given HLC type is invalid or misspelled.");
+                                       goto parse_error;
+                               }
+                               cond->value_type = VALUE_TYPE_INTEGER;
+                               break;
+
                                /* parse interface attribute <if>:<value> */
                                case COND_TYPE_IFATTR:
                                key[0] = key_to[0] = '\0';
-                               if (*p==':' || *p==',' || *p==' ' || *p=='\0')
-                               {
+                               if (*p==':' || *p==',' || *p==' ' || *p=='\0') {
                                        SPRINT(failure, "Missing interface name.");
                                        goto parse_error;
                                }
                                p = read_string(p, key, sizeof(key), ":-, ");
-                               if (key[0] == 1) /* error */
-                               {
+                               if (key[0] == 1) { /* error */
                                        SPRINT(failure, "Parsing interface failed: %s", key+1);
                                        goto parse_error;
                                }
-                               if (*p != ':')
-                               {
+                               if (*p != ':') {
                                        SPRINT(failure, "Expeciting kolon to seperate value behind interface name.");
                                        goto parse_error;
                                }
                                SCCAT(key, *p++);
-                               while(*p>='0' && *p<='9')
-                               {
+                               while(*p>='0' && *p<='9') {
                                        SCCAT(key, *p++);
                                }
-                               if (*p!=',' && *p!=' ' && *p!='\0')
-                               {
+                               if (*p!=',' && *p!=' ' && *p!='\0') {
                                        SPRINT(failure, "Invalid characters behind value.");
                                        goto parse_error;
                                }
@@ -1390,16 +1375,14 @@ struct route_ruleset *ruleset_parse(void)
                                goto parse_error;
                        }
                        /* if we have another value for that item, we attach it */
-                       if (*p == ',')
-                       {
+                       if (*p == ',') {
                                p++;
                                /* next item */
                                cond->value_extension = 1;
                                goto nextcondvalue;
                        }
                        /* to seperate the items, a space is required */
-                       if (*p != ' ')
-                       {
+                       if (*p != ' ') {
                                SPRINT(failure, "Character '%c' not expected here. Use ',' to seperate multiple possible values.", *p);
                                goto parse_error;
                        }
@@ -1413,8 +1396,7 @@ struct route_ruleset *ruleset_parse(void)
                }
 
                /* we are done with CONDITIONS, so we expect the ACTION */
-               if (*p != ':')
-               {
+               if (*p != ':') {
                        SPRINT(failure, "Expecting ':' after condition item(s).");
                        goto parse_error;
                }
@@ -1431,8 +1413,7 @@ struct route_ruleset *ruleset_parse(void)
 
                /* read action name */
                i = 0;
-               while((*p>='a' && *p<='z') || (*p>='A' && *p<='Z') || (*p>='0' && *p<='9') || *p == '-')
-               {
+               while((*p>='a' && *p<='z') || (*p>='A' && *p<='Z') || (*p>='0' && *p<='9') || *p == '-') {
                        if (*p>='A' && *p<='Z') *p = *p-'A'+'a'; /* lower case */
                        key[i++] = *p++;
                        if (i == sizeof(key)) i--; /* limit */
@@ -1445,10 +1426,8 @@ struct route_ruleset *ruleset_parse(void)
 
                /* check if item exists */
                index = 0;
-               while(action_defs[index].name)
-               {
-                       if (!action_defs[index].help) /* not internal actions */
-                       {
+               while(action_defs[index].name) {
+                       if (!action_defs[index].help) { /* not internal actions */
                                index++;
                                continue;
                        }
@@ -1456,11 +1435,11 @@ struct route_ruleset *ruleset_parse(void)
                                break;
                        index++;
                }
-               if (action_defs[index].name == NULL)
-               {
+               if (action_defs[index].name == NULL) {
                        SPRINT(failure, "Unknown action name '%s'.", key);
                        goto parse_error;
                }
+               allowed_params = action_defs[index].params;
 
                /* alloc memory for action */
                action = (struct route_action *)MALLOC(sizeof(struct route_action));
@@ -1480,16 +1459,18 @@ struct route_ruleset *ruleset_parse(void)
                }
 
                /* loop PARAMS */
-               while(*p != 0)
-               {
+               while(*p != 0) {
                        /* read param text */
                        i = 0;
-                       while((*p>='a' && *p<='z') || (*p>='A' && *p<='Z') || (*p>='0' && *p<='9'))
-                       {
+                       while((*p>='a' && *p<='z') || (*p>='A' && *p<='Z') || (*p>='0' && *p<='9') || *p == '-') {
                                if (*p>='A' && *p<='Z') *p = *p-'A'+'a'; /* lower case */
                                key[i++] = *p++;
                                if (i == sizeof(key)) i--; /* limit */
                        }
+                       if (*p == ':') {
+                               p++;
+                               goto nextaction;
+                       }
                        key[i] = 0;
                        if (key[0] == '\0') {
                                SPRINT(failure, "Expecting parameter name.");
@@ -1498,35 +1479,34 @@ struct route_ruleset *ruleset_parse(void)
 
                        /* check if item exists */
                        index = 0;
-                       while(param_defs[index].name)
-                       {
+                       while(param_defs[index].name) {
                                if (!strcmp(param_defs[index].name, key))
                                        break;
                                index++;
                        }
-                       if (param_defs[index].name == NULL)
-                       {
+                       if (param_defs[index].name == NULL) {
                                SPRINT(failure, "Unknown param name '%s'.", key);
                                goto parse_error;
                        }
 
+                       /* check if item is allowed for the action */
+                       if (!(param_defs[index].id & allowed_params)) {
+                               SPRINT(failure, "Param name '%s' exists, but not for this action.", key);
+                               goto parse_error;
+                       }
+
                        /* params without values must not have any parameter */
-                       if (param_defs[index].type == PARAM_TYPE_NULL)
-                       {
-                               if (*p!=' ' && *p!='\0')
-                               {
+                       if (param_defs[index].type == PARAM_TYPE_NULL) {
+                               if (*p!=' ' && *p!='\0') {
                                        SPRINT(failure, "Parameter '%s' must not have any value.", key);
                                        goto parse_error;
                                }
-                       } else
-                       {
-                               if (*p == ' ')
-                               {
+                       } else {
+                               if (*p == ' ') {
                                        SPRINT(failure, "Parameter '%s' must have at least one value, '=' expected and not a space.", key);
                                        goto parse_error;
                                }
-                               if (*p != '=')
-                               {
+                               if (*p != '=') {
                                        SPRINT(failure, "Parameter '%s' must have at least one value, '=' expected.", key);
                                        goto parse_error;
                                }
@@ -1534,45 +1514,37 @@ struct route_ruleset *ruleset_parse(void)
                        }
 
                        /* special timeout value */
-                       if (!strcmp("timeout", key))
-                       {
-                               if (action->timeout)
-                               {
+                       if (!strcmp("timeout", key)) {
+                               if (action->timeout) {
                                        SPRINT(failure, "Duplicate timeout value.");
                                        goto parse_error;
                                }
-                               if (*p==',' || *p==' ' || *p=='\0')
-                               {
+                               if (*p==',' || *p==' ' || *p=='\0') {
                                        SPRINT(failure, "Missing integer value.");
                                        goto parse_error;
                                }
                                integer = 0;
-                               while(*p>='0' && *p<='9')
-                               {
+                               while(*p>='0' && *p<='9') {
                                        integer = integer*10 + *p-'0';
                                        p++;
                                }
-                               if (integer < 1)
-                               {
+                               if (integer < 1) {
                                        SPRINT(failure, "Expecting timeout value greater 0.");
                                        goto parse_error;
                                }
-                               if (*p!=' ' && *p!='\0')
-                               {
+                               if (*p!=' ' && *p!='\0') {
                                        SPRINT(failure, "Character '%c' not expected here. Use ' ' to seperate parameters.", *p);
                                        goto parse_error;
                                }
                                /* skip spaces */
-                               while(*p == 32)
-                               {
+                               while(*p == 32) {
                                        if (*p == 0)
                                                break;
                                        p++;
                                }
                                action->timeout = integer;
                                /* check for next ACTION */
-                               if (*p == ':')
-                               {
+                               if (*p == ':') {
                                        p++;
                                        goto nextaction;
                                }
@@ -1581,10 +1553,8 @@ struct route_ruleset *ruleset_parse(void)
 
                        /* check for duplicate parameters */
                        param = action->param_first;
-                       while(param)
-                       {
-                               if (param->index == index)
-                               {
+                       while(param) {
+                               if (param->index == index) {
                                        SPRINT(failure, "Duplicate parameter '%s', use ',' to give multiple values.", key);
                                        goto parse_error;
                                }
@@ -1600,8 +1570,7 @@ struct route_ruleset *ruleset_parse(void)
                        param->index = index;
                        param->id = param_defs[index].id;
 
-                       switch(param_defs[index].type)
-                       {
+                       switch(param_defs[index].type) {
                                /* parse null value */
                                case PARAM_TYPE_NULL:
                                param->value_type = VALUE_TYPE_NULL;
@@ -1610,13 +1579,11 @@ struct route_ruleset *ruleset_parse(void)
                                /* parse integer value */
                                case PARAM_TYPE_INTEGER:
                                integer = 0;
-                               if (*p==',' || *p==' ' || *p=='\0')
-                               {
+                               if (*p==',' || *p==' ' || *p=='\0') {
                                        SPRINT(failure, "Missing integer value.");
                                        goto parse_error;
                                }
-                               while(*p>='0' && *p<='9')
-                               {
+                               while(*p>='0' && *p<='9') {
                                        integer = integer*10 + *p-'0';
                                        p++;
                                }
@@ -1628,33 +1595,27 @@ struct route_ruleset *ruleset_parse(void)
                                /* parse ports value */
                                case PARAM_TYPE_PORTS:
                                key[0] = '\0';
-                               if (*p==',' || *p==' ' || *p=='\0')
-                               {
+                               if (*p==',' || *p==' ' || *p=='\0') {
                                        SPRINT(failure, "Missing port number, omit parameter or give port number.");
                                        goto parse_error;
                                }
                                i = 0;
                                nextport:
                                integer = 0;
-                               while(*p>='0' && *p<='9')
-                               {
-                                       if (i < (int)sizeof(key)-1)
-                                       {
+                               while(*p>='0' && *p<='9') {
+                                       if (i < (int)sizeof(key)-1) {
                                                key[i] = *p;
                                                key[i++] = '\0';
                                        }
                                        integer = integer*10 + *p-'0';
                                        p++;
                                }
-                               if (integer > 255)
-                               {
+                               if (integer > 255) {
                                        SPRINT(failure, "Port number too high.");
                                        goto parse_error;
                                }
-                               if (*p==',')
-                               {
-                                       if (i < (int)sizeof(key)-1)
-                                       {
+                               if (*p==',') {
+                                       if (i < (int)sizeof(key)-1) {
                                                key[i] = *p;
                                                key[i++] = '\0';
                                        }
@@ -1669,162 +1630,208 @@ struct route_ruleset *ruleset_parse(void)
                                case PARAM_TYPE_CALLERIDTYPE:
                                case PARAM_TYPE_CAPABILITY:
                                case PARAM_TYPE_BMODE:
+                               case PARAM_TYPE_HLC:
                                case PARAM_TYPE_DIVERSION:
                                case PARAM_TYPE_DESTIN:
                                case PARAM_TYPE_TYPE:
                                case PARAM_TYPE_YESNO:
+                               case PARAM_TYPE_ON:
                                key[0] = '\0';
-                               if (*p==',' || *p==' ' || *p=='\0')
-                               {
+                               if (*p==',' || *p==' ' || *p=='\0') {
                                        SPRINT(failure, "Missing string value, use \"\" for empty string.");
                                        goto parse_error;
                                }
                                p = read_string(p, key, sizeof(key), " ");
-                               if (key[0] == 1) /* error */
-                               {
+                               if (key[0] == 1) { /* error */
                                        SPRINT(failure, "Parsing string failed: %s", key+1);
                                        goto parse_error;
                                }
-                               if (param_defs[index].type == PARAM_TYPE_CALLERIDTYPE)
-                               {
+                               if (param_defs[index].type == PARAM_TYPE_CALLERIDTYPE) {
                                        param->value_type = VALUE_TYPE_INTEGER;
-                                       if (!strcasecmp(key, "unknown"))
-                                       {
+                                       if (!strcasecmp(key, "unknown")) {
                                                param->integer_value = INFO_NTYPE_UNKNOWN;
                                                break;
                                        }
-                                       if (!strcasecmp(key, "subscriber"))
-                                       {
+                                       if (!strcasecmp(key, "subscriber")) {
                                                param->integer_value = INFO_NTYPE_SUBSCRIBER;
                                                break;
                                        }
-                                       if (!strcasecmp(key, "national"))
-                                       {
+                                       if (!strcasecmp(key, "national")) {
                                                param->integer_value = INFO_NTYPE_NATIONAL;
                                                break;
                                        }
-                                       if (!strcasecmp(key, "international"))
-                                       {
+                                       if (!strcasecmp(key, "international")) {
                                                param->integer_value = INFO_NTYPE_INTERNATIONAL;
                                                break;
                                        }
                                        SPRINT(failure, "Caller ID type '%s' unknown.", key);
                                        goto parse_error;
                                }
-                               if (param_defs[index].type == PARAM_TYPE_CAPABILITY)
-                               {
+                               if (param_defs[index].type == PARAM_TYPE_ON) {
+                                       param->value_type = VALUE_TYPE_INTEGER;
+                                       if (!strcasecmp(key, "init")) {
+                                               param->integer_value = INFO_ON_INIT;
+                                               break;
+                                       }
+                                       if (!strcasecmp(key, "hangup")) {
+                                               param->integer_value = INFO_ON_HANGUP;
+                                               break;
+                                       }
+                                       SPRINT(failure, "Execute on '%s' unknown.", key);
+                                       goto parse_error;
+                               }
+                               if (param_defs[index].type == PARAM_TYPE_CAPABILITY) {
                                        param->value_type = VALUE_TYPE_INTEGER;
-                                       if (!strcasecmp(key, "speech"))
-                                       {
+                                       if (!strcasecmp(key, "speech")) {
                                                param->integer_value = INFO_BC_SPEECH;
                                                break;
                                        }
-                                       if (!strcasecmp(key, "audio"))
-                                       {
+                                       if (!strcasecmp(key, "audio")) {
                                                param->integer_value = INFO_BC_AUDIO;
                                                break;
                                        }
-                                       if (!strcasecmp(key, "video"))
-                                       {
+                                       if (!strcasecmp(key, "video")) {
                                                param->integer_value = INFO_BC_VIDEO;
                                                break;
                                        }
-                                       if (!strcasecmp(key, "digital-restricted"))
-                                       {
+                                       if (!strcasecmp(key, "digital-restricted")) {
                                                param->integer_value = INFO_BC_DATARESTRICTED;
                                                break;
                                        }
-                                       if (!strcasecmp(key, "digital-unrestricted"))
-                                       {
+                                       if (!strcasecmp(key, "digital-unrestricted")) {
                                                param->integer_value = INFO_BC_DATAUNRESTRICTED;
                                                break;
                                        }
-                                       if (!strcasecmp(key, "digital-unrestricted-tones"))
-                                       {
+                                       if (!strcasecmp(key, "digital-unrestricted-tones")) {
                                                param->integer_value = INFO_BC_DATAUNRESTRICTED_TONES;
                                                break;
                                        }
                                        SPRINT(failure, "Service type '%s' unknown.", key);
                                        goto parse_error;
                                }
-                               if (param_defs[index].type == PARAM_TYPE_BMODE)
-                               {
+                               if (param_defs[index].type == PARAM_TYPE_BMODE) {
                                        param->value_type = VALUE_TYPE_INTEGER;
-                                       if (!strcasecmp(key, "transparent"))
-                                       {
+                                       if (!strcasecmp(key, "transparent")) {
                                                param->integer_value = INFO_BMODE_CIRCUIT;
                                                break;
                                        }
-                                       if (!strcasecmp(key, "hdlc"))
-                                       {
+                                       if (!strcasecmp(key, "hdlc")) {
                                                param->integer_value = INFO_BMODE_PACKET;
                                                break;
                                        }
                                        SPRINT(failure, "Bchannel mode '%s' unknown.", key);
                                        goto parse_error;
                                }
-                               if (param_defs[index].type == PARAM_TYPE_DIVERSION)
-                               {
+                               if (param_defs[index].type == PARAM_TYPE_HLC) {
+                                       param->value_type = VALUE_TYPE_INTEGER;
+                                       if (!strcasecmp(key, "telephony")) {
+                                               param->integer_value = INFO_HLC_TELEPHONY;
+                                               break;
+                                       }
+                                       if (!strcasecmp(key, "faxg2g3")) {
+                                               param->integer_value = INFO_HLC_FAXG2G3;
+                                               break;
+                                       }
+                                       if (!strcasecmp(key, "faxg4")) {
+                                               param->integer_value = INFO_HLC_FAXG4;
+                                               break;
+                                       }
+                                       if (!strcasecmp(key, "teletex1")) {
+                                               param->integer_value = INFO_HLC_TELETEX1;
+                                               break;
+                                       }
+                                       if (!strcasecmp(key, "teletex2")) {
+                                               param->integer_value = INFO_HLC_TELETEX2;
+                                               break;
+                                       }
+                                       if (!strcasecmp(key, "teletex3")) {
+                                               param->integer_value = INFO_HLC_TELETEX3;
+                                               break;
+                                       }
+                                       if (!strcasecmp(key, "videotex1")) {
+                                               param->integer_value = INFO_HLC_VIDEOTEX1;
+                                               break;
+                                       }
+                                       if (!strcasecmp(key, "videotex2")) {
+                                               param->integer_value = INFO_HLC_VIDEOTEX2;
+                                               break;
+                                       }
+                                       if (!strcasecmp(key, "telex")) {
+                                               param->integer_value = INFO_HLC_TELEX;
+                                               break;
+                                       }
+                                       if (!strcasecmp(key, "mhs")) {
+                                               param->integer_value = INFO_HLC_MHS;
+                                               break;
+                                       }
+                                       if (!strcasecmp(key, "osi")) {
+                                               param->integer_value = INFO_HLC_OSI;
+                                               break;
+                                       }
+                                       if (!strcasecmp(key, "maintenance")) {
+                                               param->integer_value = INFO_HLC_MAINTENANCE;
+                                               break;
+                                       }
+                                       if (!strcasecmp(key, "management")) {
+                                               param->integer_value = INFO_HLC_MANAGEMENT;
+                                               break;
+                                       }
+                                       if (!strcasecmp(key, "audiovisual")) {
+                                               param->integer_value = INFO_HLC_AUDIOVISUAL;
+                                               break;
+                                       }
+                                       SPRINT(failure, "HLC type '%s' unknown.", key);
+                                       goto parse_error;
+                               }
+                               if (param_defs[index].type == PARAM_TYPE_DIVERSION) {
                                        param->value_type = VALUE_TYPE_INTEGER;
-                                       if (!strcasecmp(key, "cfu"))
-                                       {
+                                       if (!strcasecmp(key, "cfu")) {
                                                param->integer_value = INFO_DIVERSION_CFU;
                                                break;
                                        }
-                                       if (!strcasecmp(key, "cfb"))
-                                       {
+                                       if (!strcasecmp(key, "cfb")) {
                                                param->integer_value = INFO_DIVERSION_CFB;
                                                break;
                                        }
-                                       if (!strcasecmp(key, "cfnr"))
-                                       {
+                                       if (!strcasecmp(key, "cfnr")) {
                                                param->integer_value = INFO_DIVERSION_CFNR;
                                                break;
                                        }
-                                       if (!strcasecmp(key, "cfp"))
-                                       {
+                                       if (!strcasecmp(key, "cfp")) {
                                                param->integer_value = INFO_DIVERSION_CFP;
                                                break;
                                        }
                                        SPRINT(failure, "Diversion type '%s' unknown.", key);
                                        goto parse_error;
                                }
-                               if (param_defs[index].type == PARAM_TYPE_TYPE)
-                               {
+                               if (param_defs[index].type == PARAM_TYPE_TYPE) {
                                        param->value_type = VALUE_TYPE_INTEGER;
-                                       if (!strcasecmp(key, "unknown"))
-                                       {
+                                       if (!strcasecmp(key, "unknown")) {
                                                param->integer_value = INFO_NTYPE_UNKNOWN;
                                                break;
                                        }
-                                       if (!strcasecmp(key, "subscriber"))
-                                       {
+                                       if (!strcasecmp(key, "subscriber")) {
                                                param->integer_value = INFO_NTYPE_SUBSCRIBER;
                                                break;
                                        }
-                                       if (!strcasecmp(key, "national"))
-                                       {
+                                       if (!strcasecmp(key, "national")) {
                                                param->integer_value = INFO_NTYPE_NATIONAL;
                                                break;
                                        }
-                                       if (!strcasecmp(key, "international"))
-                                       {
+                                       if (!strcasecmp(key, "international")) {
                                                param->integer_value = INFO_NTYPE_INTERNATIONAL;
                                                break;
                                        }
                                        SPRINT(failure, "Number type '%s' unknown.", key);
                                        goto parse_error;
                                }
-                               if (param_defs[index].type == PARAM_TYPE_YESNO)
-                               {
+                               if (param_defs[index].type == PARAM_TYPE_YESNO) {
                                        param->value_type = VALUE_TYPE_INTEGER;
-                                       if (!strcasecmp(key, "yes"))
-                                       {
+                                       if (!strcasecmp(key, "yes")) {
                                                param->integer_value = 1;
                                                break;
                                        }
-                                       if (!strcasecmp(key, "no"))
-                                       {
+                                       if (!strcasecmp(key, "no")) {
                                                param->integer_value = 0;
                                                break;
                                        }
@@ -1842,8 +1849,7 @@ struct route_ruleset *ruleset_parse(void)
                                goto parse_error;
                        }
 
-                       if (*p == ',')
-                       {
+                       if (*p == ',') {
                                p++;
                                /* next item */
                                param->value_extension = 1;
@@ -1855,8 +1861,7 @@ struct route_ruleset *ruleset_parse(void)
                                break;
 
                        /* to seperate the items, a space is required */
-                       if (*p != ' ')
-                       {
+                       if (*p != ' ') {
                                SPRINT(failure, "Character '%c' not expected here. Use ' ' to seperate parameters, or ',' for multiple values.", *p);
                                goto parse_error;
                        }
@@ -1869,8 +1874,7 @@ struct route_ruleset *ruleset_parse(void)
                        }
 
                        /* check for next ACTION */
-                       if (*p == ':')
-                       {
+                       if (*p == ':') {
                                p++;
                                goto nextaction;
                        }
@@ -1883,8 +1887,7 @@ struct route_ruleset *ruleset_parse(void)
        if (nesting >= 0)
                goto go_root;
 
-       if (!ruleset_start)
-       {
+       if (!ruleset_start) {
                SPRINT(failure, "No ruleset defined.");
        }
        return(ruleset_start);
@@ -1900,8 +1903,7 @@ struct route_ruleset *ruleset_parse(void)
        SPRINT(ruleset_error, "Error in file %s, line %d: %s",  filename[nesting], line[nesting], failure);
 
        openerror:
-       while(nesting >= 0)
-       {
+       while(nesting >= 0) {
                fclose(fp[nesting--]);
                fduse--;
        }
@@ -1913,14 +1915,12 @@ struct route_ruleset *ruleset_parse(void)
 /*
  * return ruleset by name
  */
-struct route_ruleset *getrulesetbyname(char *name)
+struct route_ruleset *getrulesetbyname(const char *name)
 {
        struct route_ruleset *ruleset = ruleset_first;
 
-       while(ruleset)
-       {
-               if (!strcasecmp(name, ruleset->name))
-               {
+       while(ruleset) {
+               if (!strcasecmp(name, ruleset->name)) {
                        break;
                }
                ruleset = ruleset->next;
@@ -1939,45 +1939,54 @@ struct route_action *EndpointAppPBX::route(struct route_ruleset *ruleset)
                                istrue,
                                couldbetrue,
                                condition,
-                               dialing_required,
-                               avail,
-                               any;
+                               dialing_required;
        struct route_rule       *rule = ruleset->rule_first;
        struct route_cond       *cond;
        struct route_action     *action = NULL;
        unsigned long           comp_len;
-       int                     j, jj;
-       char                    callerid[64],   redirid[64];
+       int                     j;
+       char                    isdn_port[10];
+       char                    *argv[11]; /* check also number of args below */
+       char                    callerid[64], callerid2[64], redirid[64];
        int                     integer;
        char                    *string;
        FILE                    *tfp;
-       double                  timeout;
+       long long               timeout, now_ll = 0, match_timeout = 0;
+       struct timeval          current_time;
+#ifdef WITH_MISDN
        struct mISDNport        *mISDNport;
+       int                     avail;
+       int                     jj;
+       class Port              *port;
+       class Pfxs              *ourfxs, *fxs;
+       int                     fxs_count;
+       int                     fxs_age;
+#endif
        struct admin_list       *admin;
+       time_t                  now;
+       struct tm               *now_tm;
+       int                     pid, status;
 
        /* reset timeout action */
-       e_match_timeout = 0; /* no timeout */
        e_match_to_action = NULL;
 
-       SCPY(callerid, numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype));
-       SCPY(redirid, numberrize_callerinfo(e_redirinfo.id, e_redirinfo.ntype));
+       SCPY(callerid, numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype, options.national, options.international));
+       SCPY(callerid2, numberrize_callerinfo(e_callerinfo.id2, e_callerinfo.ntype2, options.national, options.international));
+       SCPY(redirid, numberrize_callerinfo(e_redirinfo.id, e_redirinfo.ntype, options.national, options.international));
        
        PDEBUG(DEBUG_ROUTE, "parsing ruleset '%s'\n", ruleset->name);
-       while(rule)
-       {
+       while(rule) {
                PDEBUG(DEBUG_ROUTE, "checking rule in line %d\n", rule->line);
                match = 1; /* this rule matches */
                dialing_required = 0;
                timeout = 0; /* timeout time */
                cond = rule->cond_first;
-               while(cond)
-               {
+               while(cond) {
                        condition = 0; /* any condition element is true (1) or could be true (2) */
                        checkextension:
                        istrue = 0; /* this condition-element is true */
                        couldbetrue = 0; /* this conditions-element could be true */
-                       switch(cond->match)
-                       {
+                       switch(cond->match) {
                                case MATCH_EXTERN:
                                if (!e_ext.number[0])
                                        istrue = 1;      
@@ -1989,24 +1998,31 @@ struct route_action *EndpointAppPBX::route(struct route_ruleset *ruleset)
                                break;
 
                                case MATCH_PORT:
+#ifdef WITH_MISDN
                                if (ea_endpoint->ep_portlist)
-                               if ((ea_endpoint->ep_portlist->port_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_mISDN_DSS1)
+                               if ((ea_endpoint->ep_portlist->port_type & PORT_CLASS_MASK) != PORT_CLASS_mISDN)
                                        break;
                                integer = e_callerinfo.isdn_port;
                                goto match_integer;
+#endif
+                               break;
 
                                case MATCH_INTERFACE:
                                if (!e_callerinfo.interface[0])
                                        break;
                                string = e_callerinfo.interface;
-                               goto match_string_prefix;
+                               goto match_string;
 
                                case MATCH_CALLERID:
                                string = callerid;
                                goto match_string_prefix;
 
+                               case MATCH_CALLERID2:
+                               string = callerid2;
+                               goto match_string_prefix;
+
                                case MATCH_EXTENSION:
-                               string = e_ext.name;
+                               string = e_ext.number;
                                goto match_string;
 
                                case MATCH_DIALING:
@@ -2054,12 +2070,12 @@ struct route_action *EndpointAppPBX::route(struct route_ruleset *ruleset)
                                break;
 
                                case MATCH_REDIRECTED:
-                               if (e_redirinfo.present != INFO_PRESENT_NULL)
+                               if (e_redirinfo.ntype != INFO_NTYPE_NOTPRESENT)
                                        istrue = 1;
                                break;
 
                                case MATCH_DIRECT:
-                               if (e_redirinfo.present == INFO_PRESENT_NULL)
+                               if (e_redirinfo.ntype == INFO_NTYPE_NOTPRESENT)
                                        istrue = 1;
                                break;
 
@@ -2068,22 +2084,32 @@ struct route_action *EndpointAppPBX::route(struct route_ruleset *ruleset)
                                goto match_string_prefix;
 
                                case MATCH_TIME:
+                               time(&now);
+                               now_tm = localtime(&now);
                                integer = now_tm->tm_hour*100 + now_tm->tm_min;
                                goto match_integer;
 
                                case MATCH_MDAY:
+                               time(&now);
+                               now_tm = localtime(&now);
                                integer = now_tm->tm_mday;
                                goto match_integer;
 
                                case MATCH_MONTH:
+                               time(&now);
+                               now_tm = localtime(&now);
                                integer = now_tm->tm_mon+1;
                                goto match_integer;
 
                                case MATCH_YEAR:
+                               time(&now);
+                               now_tm = localtime(&now);
                                integer = now_tm->tm_year + 1900;
                                goto match_integer;
 
                                case MATCH_WDAY:
+                               time(&now);
+                               now_tm = localtime(&now);
                                integer = now_tm->tm_wday;
                                integer = integer?integer:7; /* correct sunday */
                                goto match_integer;
@@ -2102,8 +2128,7 @@ struct route_action *EndpointAppPBX::route(struct route_ruleset *ruleset)
 
                                case MATCH_FILE:
                                tfp = fopen(cond->string_value, "r");
-                               if (!tfp)
-                               {
+                               if (!tfp) {
                                        break;
                                }
                                if (fgetc(tfp) == '1')
@@ -2112,8 +2137,33 @@ struct route_action *EndpointAppPBX::route(struct route_ruleset *ruleset)
                                break;
 
                                case MATCH_EXECUTE:
-                               if (system(cond->string_value) == 0)
-                                       istrue = 1;
+                               j = 0;
+#if 0
+                               argv[j++] = (char *)"/bin/sh";
+                               argv[j++] = (char *)"-c";
+                               argv[j++] = cond->string_value;
+#endif
+                               argv[j++] = cond->string_value;
+                               argv[j++] = e_extdialing;
+                               argv[j++] = (char *)numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype, options.national, options.international);
+                               argv[j++] = e_callerinfo.extension;
+                               argv[j++] = e_callerinfo.name;
+                               SPRINT(isdn_port, "%d", e_callerinfo.isdn_port);
+                               argv[j++] = isdn_port;
+                               argv[j++] = e_callerinfo.imsi;
+                               argv[j++] = NULL; /* check also number of args above */
+                               switch ((pid = fork())) {
+                               case 0:
+                                       execve(cond->string_value, argv, environ);
+                                       perror("execve");
+                                       exit(1);
+                               case -1:
+                                       break;
+                               default:
+                                       waitpid(pid, &status, 0);
+                                       if (0 == WEXITSTATUS(status))
+                                               istrue = 1;
+                               }
                                break;
 
                                case MATCH_DEFAULT:
@@ -2122,29 +2172,31 @@ struct route_action *EndpointAppPBX::route(struct route_ruleset *ruleset)
                                break;
 
                                case MATCH_TIMEOUT:
-                               timeout = now_d + cond->integer_value;
+                               if (!now_ll) {
+                                       gettimeofday(&current_time, NULL);
+                                       now_ll = current_time.tv_sec * MICRO_SECONDS + current_time.tv_usec;
+                               }
+                               timeout = now_ll + (cond->integer_value * MICRO_SECONDS);
                                istrue = 1;
                                break;
 
                                case MATCH_FREE:
                                case MATCH_NOTFREE:
+#ifdef WITH_MISDN
                                if (!(comp_len = (unsigned long)strchr(cond->string_value, ':')))
                                        break;
                                comp_len = comp_len-(unsigned long)cond->string_value;
                                avail = 0;
                                mISDNport = mISDNport_first;
-                               while(mISDNport)
-                               {
+                               while(mISDNport) {
                                        if (mISDNport->ifport)
                                        if (strlen(mISDNport->ifport->interface->name) == comp_len)
                                        if (!strncasecmp(mISDNport->ifport->interface->name, cond->string_value, comp_len)) 
-                                       if (!mISDNport->ptp || mISDNport->l2link)
-                                       {
+                                       if (!mISDNport->l2hold || mISDNport->l2link>0) {
                                                j = 0;
                                                jj = mISDNport->b_num;
                                                avail += jj;
-                                               while(j < jj)
-                                               {
+                                               while(j < jj) {
                                                        if (mISDNport->b_state[j])
                                                                avail--;
                                                        j++;
@@ -2152,53 +2204,53 @@ struct route_action *EndpointAppPBX::route(struct route_ruleset *ruleset)
                                        }
                                        mISDNport = mISDNport->next;
                                }
-                               if (cond->match == MATCH_FREE)
-                               {
+                               if (cond->match == MATCH_FREE) {
                                        if (avail >= atoi(cond->string_value + comp_len + 1))
                                                istrue = 1;
-                               } else
-                               {
+                               } else {
                                        if (avail < atoi(cond->string_value + comp_len + 1))
                                                istrue = 1;
                                }
+#endif
                                break;
 
 
                                case MATCH_DOWN:
+#ifdef WITH_MISDN
                                mISDNport = mISDNport_first;
-                               while(mISDNport)
-                               {
+                               while(mISDNport) {
                                        if (mISDNport->ifport)
                                        if (!strcasecmp(mISDNport->ifport->interface->name, cond->string_value)) 
-                                       if (!mISDNport->ptp || mISDNport->l2link) /* break if one is up */
+                                       if (!mISDNport->l2hold || mISDNport->l2link>0)
                                                break;
                                        mISDNport = mISDNport->next;
                                }
                                if (!mISDNport) /* all down */
                                        istrue = 1;
+#endif
                                break;
 
                                case MATCH_UP:
+#ifdef WITH_MISDN
                                mISDNport = mISDNport_first;
-                               while(mISDNport)
-                               {
+                               while(mISDNport) {
                                        if (mISDNport->ifport)
                                        if (!strcasecmp(mISDNport->ifport->interface->name, cond->string_value)) 
-                                       if (!mISDNport->ptp || mISDNport->l2link) /* break if one is up */
+                                       if (!mISDNport->l2hold || mISDNport->l2link>0)
                                                break;
                                        
                                        mISDNport = mISDNport->next;
                                }
                                if (mISDNport) /* one link at least */
                                        istrue = 1;
+#endif
                                break;
 
                                case MATCH_BUSY:
                                case MATCH_IDLE:
-                               any = 0;
+#ifdef WITH_MISDN
                                mISDNport = mISDNport_first;
-                               while(mISDNport)
-                               {
+                               while(mISDNport) {
                                        if (mISDNport->ifport)
                                        if (!strcasecmp(mISDNport->ifport->interface->name, cond->string_value)) 
                                        if (mISDNport->use) /* break if in use */
@@ -2209,13 +2261,13 @@ struct route_action *EndpointAppPBX::route(struct route_ruleset *ruleset)
                                        istrue = 1;
                                if (!mISDNport && cond->match==MATCH_IDLE)
                                        istrue = 1;
+#endif
                                break;
 
                                case MATCH_REMOTE:
                                case MATCH_NOTREMOTE:
                                admin = admin_first;
-                               while(admin)
-                               {
+                               while(admin) {
                                        if (admin->remote_name[0] && !strcmp(cond->string_value, admin->remote_name))
                                                break;
                                        admin = admin->next;
@@ -2226,23 +2278,100 @@ struct route_action *EndpointAppPBX::route(struct route_ruleset *ruleset)
                                        istrue = 1;
                                break;
 
+#ifdef WITH_MISDN
+                               case MATCH_POTS_FLASH:
+                               if (e_dialinginfo.flash)
+                                       istrue = 1;
+                               break;
+
+                               case MATCH_POTS_CW:
+                               port = find_port_id(ea_endpoint->ep_portlist->port_id);
+                               if (!port)
+                                       break;
+                               if ((port->p_type & PORT_CLASS_POTS_MASK) != PORT_CLASS_POTS_FXS)
+                                       break;
+                               ourfxs = (class Pfxs *)port;
+                               port = port_first;
+                               while(port) {
+                                       if ((port->p_type & PORT_CLASS_POTS_MASK) == PORT_CLASS_POTS_FXS) {
+                                               fxs = (class Pfxs *)port;
+                                               if (fxs->p_m_mISDNport == ourfxs->p_m_mISDNport && fxs != ourfxs) {
+                                                       if (fxs->p_state == PORT_STATE_OUT_ALERTING) {
+                                                               istrue = 1;
+                                                               break;
+                                                       }
+                                               }
+                                       }
+                                       port = port->next;
+                               }
+                               break;
+
+                               case MATCH_POTS_CALLS:
+                               port = find_port_id(ea_endpoint->ep_portlist->port_id);
+                               if (!port)
+                                       break;
+                               if ((port->p_type & PORT_CLASS_POTS_MASK) != PORT_CLASS_POTS_FXS)
+                                       break;
+                               ourfxs = (class Pfxs *)port;
+                               integer = 0;
+                               port = port_first;
+                               while(port) {
+                                       if ((port->p_type & PORT_CLASS_POTS_MASK) == PORT_CLASS_POTS_FXS) {
+                                               fxs = (class Pfxs *)port;
+                                               if (fxs->p_m_mISDNport == ourfxs->p_m_mISDNport && fxs != ourfxs) {
+                                                       if (fxs->p_state == PORT_STATE_CONNECT) {
+                                                               integer++;
+                                                       }
+                                               }
+                                       }
+                                       port = port->next;
+                               }
+                               goto match_integer;
+
+                               case MATCH_POTS_LAST:
+                               port = find_port_id(ea_endpoint->ep_portlist->port_id);
+                               if (!port)
+                                       break;
+                               if ((port->p_type & PORT_CLASS_POTS_MASK) != PORT_CLASS_POTS_FXS)
+                                       break;
+                               ourfxs = (class Pfxs *)port;
+                               /* integer gets the call number that has been the least active call on hold */ 
+                               fxs_age = -1;
+                               fxs_count = 0;
+                               integer = 0;
+                               port = port_first;
+                               while(port) {
+                                       if ((port->p_type & PORT_CLASS_POTS_MASK) == PORT_CLASS_POTS_FXS) {
+                                               fxs = (class Pfxs *)port;
+                                               if (fxs->p_m_mISDNport == ourfxs->p_m_mISDNport && fxs != ourfxs) {
+                                                       if (fxs->p_state == PORT_STATE_CONNECT) {
+                                                               fxs_count++;
+                                                               if (fxs->p_m_fxs_age > fxs_age) {
+                                                                       fxs_age = fxs->p_m_fxs_age;
+                                                                       integer = fxs_count;
+                                                               }
+                                                       }
+                                               }
+                                       }
+                                       port = port->next;
+                               }
+                               goto match_integer;
+#endif
+
                                default:
                                PERROR("Software error: MATCH_* %d not parsed in function '%s'", cond->match, __FUNCTION__);
                                break;
 
                                match_integer:
-                               if (cond->value_type == VALUE_TYPE_INTEGER)
-                               {
+                               if (cond->value_type == VALUE_TYPE_INTEGER) {
                                        if (integer != cond->integer_value)
                                                break;
                                        istrue = 1;
                                        break;
                                }
-                               if (cond->value_type == VALUE_TYPE_INTEGER_RANGE)
-                               {
+                               if (cond->value_type == VALUE_TYPE_INTEGER_RANGE) {
                                        /* check if negative range (2100 - 700 o'clock) */
-                                       if (cond->integer_value > cond->integer_value_to)
-                                       {
+                                       if (cond->integer_value > cond->integer_value_to) {
                                                if (integer>=cond->integer_value && integer<=cond->integer_value_to)
                                                        istrue = 1;
                                                break;
@@ -2261,23 +2390,18 @@ struct route_action *EndpointAppPBX::route(struct route_ruleset *ruleset)
                                match_string_prefix:
                                comp_len = strlen(cond->string_value); /* because we must reach value's length */
                                /* we must have greater or equal length to values */
-                               if ((unsigned long)strlen(string) < comp_len)
-                               {
+                               if ((unsigned long)strlen(string) < comp_len) {
                                        /* special case for unfinished dialing */
-                                       if (cond->match == MATCH_DIALING)
-                                       {
+                                       if (cond->match == MATCH_DIALING && !e_dialinginfo.sending_complete) {
                                                couldbetrue = 1; /* could match */
                                                comp_len = strlen(string);
-                                       } else
-                                       {
+                                       } else {
                                                break;
                                        }
                                }
                                /* on single string match */
-                               if (cond->value_type == VALUE_TYPE_STRING)
-                               {
-                                       if (!strncmp(string, cond->string_value, comp_len))
-                                       {
+                               if (cond->value_type == VALUE_TYPE_STRING) {
+                                       if (!strncmp(string, cond->string_value, comp_len)) {
                                                istrue = 1;
                                                /* must be set for changing 'e_extdialing' */
                                                if (cond->match == MATCH_DIALING)
@@ -2287,21 +2411,17 @@ struct route_action *EndpointAppPBX::route(struct route_ruleset *ruleset)
                                        break;
                                }
                                /* on range match */
-                               if (cond->value_type == VALUE_TYPE_STRING_RANGE)
-                               {
+                               if (cond->value_type == VALUE_TYPE_STRING_RANGE) {
                                        /* check if negative range ("55"-"22") */
-                                       if (cond->comp_string > 0)
-                                       {
-                                               if (strncmp(string, cond->string_value, comp_len) >= 0)
-                                               {
+                                       if (cond->comp_string > 0) {
+                                               if (strncmp(string, cond->string_value, comp_len) >= 0) {
                                                        istrue = 1;
                                                        /* must be set for changing 'e_extdialing' */
                                                        if (cond->match == MATCH_DIALING)
                                                                dialing_required = comp_len;
                                                        break;
                                                }
-                                               if (strncmp(string, cond->string_value_to, comp_len) <= 0)
-                                               {
+                                               if (strncmp(string, cond->string_value_to, comp_len) <= 0) {
                                                        /* must be set for changing 'e_extdialing' */
                                                        istrue = 1;
                                                        if (cond->match == MATCH_DIALING)
@@ -2330,11 +2450,9 @@ struct route_action *EndpointAppPBX::route(struct route_ruleset *ruleset)
                                condition = 2; /* element could match and other elements don't match, so condition could match */
 
                        /* if not matching or could match */
-                       if (condition != 1)
-                       {
+                       if (condition != 1) {
                                /* if we have more values to check */
-                               if (cond->value_extension && cond->next)
-                               {
+                               if (cond->value_extension && cond->next) {
                                        cond = cond->next;
                                        goto checkextension;
                                }
@@ -2348,31 +2466,35 @@ struct route_action *EndpointAppPBX::route(struct route_ruleset *ruleset)
 
                        cond = cond->next;
                }
-               if (timeout>now_d && match==1) /* the matching rule with timeout in the future */
-               if (e_match_timeout<1 || timeout<e_match_timeout) /* first timeout or lower */
-               {
-                       /* set timeout in the furture */
-                       e_match_timeout = timeout;
-                       e_match_to_action = rule->action_first;
-                       e_match_to_extdialing = e_dialinginfo.id + dialing_required;
+               /* if sending complete, we use future match now, since waiting does not make sense anymore */
+               if (timeout>now_ll && match==1 && !e_dialinginfo.sending_complete) { /* the matching rule with timeout in the future */
+                       if (match_timeout == 0 || timeout < match_timeout) { /* first timeout or lower */
+                               /* set timeout in the furture */
+                               match_timeout = timeout;
+                               e_match_to_action = rule->action_first;
+                               e_match_to_extdialing = e_dialinginfo.id + dialing_required;
+                       }
                        match = 0; /* matches in the future */
                }
-               if (match == 1)
-               {
+               if (match == 1) {
                        /* matching, we return first action */
                        action = rule->action_first;
-                       e_match_timeout = 0; /* no timeout */
+                       match_timeout = 0; /* no timeout */
                        e_match_to_action = NULL;
                        e_extdialing = e_dialinginfo.id + dialing_required;
                        break;
                }
-               if (match == 2)
-               {
+               if (match == 2) {
                        /* rule could match if more is dialed */
                        couldmatch = 1;
                }
                rule = rule->next;
        }
+       if (match_timeout == 0)
+               unsched_timer(&e_match_timeout); /* no timeout */
+       else {
+               schedule_timer(&e_match_timeout, (match_timeout-now_ll) / 1000000, (match_timeout-now_ll) % 1000000);
+       }
        return(action);
 }
 
@@ -2383,8 +2505,7 @@ struct route_param *EndpointAppPBX::routeparam(struct route_action *action, unsi
 {
        struct route_param *param = action->param_first;
 
-       while(param)
-       {
+       while(param) {
                if (param->id == id)
                        break;
                param = param->next;
@@ -2428,14 +2549,6 @@ struct route_action action_internal = {
        0,
 };
 
-struct route_action action_remote = {
-       NULL,
-       NULL,
-       ACTION_REMOTE,
-       0,
-       0,
-};
-
 struct route_action action_vbox = {
        NULL,
        NULL,