don't execve() a shell process but always double-fork and then exec the program directly
[lcr.git] / route.c
diff --git a/route.c b/route.c
index 4fecf38..8217ff1 100644 (file)
--- a/route.c
+++ b/route.c
@@ -68,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,
@@ -126,11 +126,11 @@ struct param_defs param_defs[] = {
          "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."},
@@ -242,13 +242,16 @@ struct param_defs param_defs[] = {
        { 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'."},
        { 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_TIMEOUT,
          "Call is routed to extern number as dialed."},
        { ACTION_INTERNAL,
          "intern",     &EndpointAppPBX::action_init_call, &EndpointAppPBX::action_dialing_internal, &EndpointAppPBX::action_hangup_call,
@@ -256,7 +259,7 @@ 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,
@@ -339,6 +342,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_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,
@@ -351,7 +358,7 @@ struct action_defs action_defs[] = {
 //       "The call forward is set within the telephone network of the external line."},
        { ACTION_EXECUTE,
          "execute",    &EndpointAppPBX::action_init_execute, NULL, &EndpointAppPBX::action_hangup_execute,
-         PARAM_CONNECT | PARAM_EXECUTE | PARAM_PARAM | PARAM_ON,
+         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,
@@ -1245,6 +1252,43 @@ struct route_ruleset *ruleset_parse(void)
                                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;
+                               else if (!strncasecmp("faxg2g3", p, 7))
+                                       cond->integer_value = INFO_HLC_FAXG2G3;
+                               else if (!strncasecmp("faxg4", p, 5))
+                                       cond->integer_value = INFO_HLC_FAXG4;
+                               else if (!strncasecmp("teletex1", p, 8))
+                                       cond->integer_value = INFO_HLC_TELETEX1;
+                               else if (!strncasecmp("teletex2", p, 8))
+                                       cond->integer_value = INFO_HLC_TELETEX2;
+                               else if (!strncasecmp("teletex3", p, 8))
+                                       cond->integer_value = INFO_HLC_TELETEX3;
+                               else if (!strncasecmp("videotex1", p, 9))
+                                       cond->integer_value = INFO_HLC_VIDEOTEX1;
+                               else if (!strncasecmp("videotex2", p, 9))
+                                       cond->integer_value = INFO_HLC_VIDEOTEX2;
+                               else if (!strncasecmp("telex", p, 5))
+                                       cond->integer_value = INFO_HLC_TELEX;
+                               else if (!strncasecmp("mhs", p, 3))
+                                       cond->integer_value = INFO_HLC_MHS;
+                               else if (!strncasecmp("osi", p, 3))
+                                       cond->integer_value = INFO_HLC_OSI;
+                               else if (!strncasecmp("maintenance", p, 11))
+                                       cond->integer_value = INFO_HLC_MAINTENANCE;
+                               else if (!strncasecmp("management", p, 10))
+                                       cond->integer_value = INFO_HLC_MANAGEMENT;
+                               else if (!strncasecmp("audiovisual", p, 11))
+                                       cond->integer_value = INFO_HLC_AUDIOVISUAL;
+                               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';
@@ -1529,6 +1573,7 @@ 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:
@@ -1620,6 +1665,67 @@ struct route_ruleset *ruleset_parse(void)
                                        SPRINT(failure, "Bchannel mode '%s' unknown.", key);
                                        goto parse_error;
                                }
+                               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")) {
@@ -1784,16 +1890,21 @@ struct route_action *EndpointAppPBX::route(struct route_ruleset *ruleset)
        struct route_action     *action = NULL;
        unsigned long           comp_len;
        int                     j, jj;
+       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;
        struct mISDNport        *mISDNport;
        struct admin_list       *admin;
+       time_t                  now;
+       struct tm               *now_tm;
+       int                     pid2;
 
        /* reset timeout action */
-       e_match_timeout = 0; /* no timeout */
        e_match_to_action = NULL;
 
        SCPY(callerid, numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype, options.national, options.international));
@@ -1845,7 +1956,7 @@ struct route_action *EndpointAppPBX::route(struct route_ruleset *ruleset)
                                goto match_string_prefix;
 
                                case MATCH_EXTENSION:
-                               string = e_ext.name;
+                               string = e_ext.number;
                                goto match_string;
 
                                case MATCH_DIALING:
@@ -1907,22 +2018,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;
@@ -1950,8 +2071,26 @@ 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 */
+                               if (fork() == 0) {
+                                       if ((pid2 = fork()) == 0) {
+                                               execve(cond->string_value, argv, environ);
+                                       }
+                               }
                                break;
 
                                case MATCH_DEFAULT:
@@ -1960,7 +2099,11 @@ 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;
 
@@ -2163,10 +2306,10 @@ 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 */
+               if (timeout>now_ll && match==1) /* the matching rule with timeout in the future */
+               if (match_timeout == 0 || timeout < match_timeout) { /* first timeout or lower */
                        /* set timeout in the furture */
-                       e_match_timeout = timeout;
+                       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 */
@@ -2174,7 +2317,7 @@ struct route_action *EndpointAppPBX::route(struct route_ruleset *ruleset)
                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;
@@ -2185,6 +2328,11 @@ struct route_action *EndpointAppPBX::route(struct route_ruleset *ruleset)
                }
                rule = rule->next;
        }
+       if (match_timeout == 0)
+               unsched_timer(&e_match_timeout); /* no timeout */
+       else {
+               schedule_timer(&e_match_timeout, match_timeout / 1000000, match_timeout % 1000000);
+       }
        return(action);
 }