Data-Over-Voice
[lcr.git] / route.c
diff --git a/route.c b/route.c
index 959b584..925bfe8 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,
@@ -94,6 +94,14 @@ struct cond_defs cond_defs[] = {
          "remote=<application name>","Matches if remote application is running."},
        { "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}
 };
 
@@ -126,11 +134,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."},
@@ -245,13 +253,16 @@ struct param_defs param_defs[] = {
        { 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_KEYPAD | 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,
@@ -261,10 +272,6 @@ struct action_defs action_defs[] = {
          "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_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_CONTEXT | PARAM_EXTEN | 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,
@@ -384,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}
 };
@@ -987,7 +1018,7 @@ struct route_ruleset *ruleset_parse(void)
                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 */
@@ -1220,19 +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;
                                }
@@ -1241,17 +1278,70 @@ 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';
@@ -1372,11 +1462,15 @@ struct route_ruleset *ruleset_parse(void)
                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.");
@@ -1536,6 +1630,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:
@@ -1627,6 +1722,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")) {
@@ -1783,24 +1939,33 @@ 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;
+       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;
        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_to_action = NULL;
@@ -1833,17 +1998,20 @@ 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_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;
@@ -1854,7 +2022,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:
@@ -1969,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:
@@ -1989,6 +2182,7 @@ struct route_action *EndpointAppPBX::route(struct route_ruleset *ruleset)
 
                                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;
@@ -2017,10 +2211,12 @@ struct route_action *EndpointAppPBX::route(struct route_ruleset *ruleset)
                                        if (avail < atoi(cond->string_value + comp_len + 1))
                                                istrue = 1;
                                }
+#endif
                                break;
 
 
                                case MATCH_DOWN:
+#ifdef WITH_MISDN
                                mISDNport = mISDNport_first;
                                while(mISDNport) {
                                        if (mISDNport->ifport)
@@ -2031,9 +2227,11 @@ struct route_action *EndpointAppPBX::route(struct route_ruleset *ruleset)
                                }
                                if (!mISDNport) /* all down */
                                        istrue = 1;
+#endif
                                break;
 
                                case MATCH_UP:
+#ifdef WITH_MISDN
                                mISDNport = mISDNport_first;
                                while(mISDNport) {
                                        if (mISDNport->ifport)
@@ -2045,11 +2243,12 @@ struct route_action *EndpointAppPBX::route(struct route_ruleset *ruleset)
                                }
                                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) {
                                        if (mISDNport->ifport)
@@ -2062,6 +2261,7 @@ struct route_action *EndpointAppPBX::route(struct route_ruleset *ruleset)
                                        istrue = 1;
                                if (!mISDNport && cond->match==MATCH_IDLE)
                                        istrue = 1;
+#endif
                                break;
 
                                case MATCH_REMOTE:
@@ -2078,6 +2278,86 @@ 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;
@@ -2112,7 +2392,7 @@ struct route_action *EndpointAppPBX::route(struct route_ruleset *ruleset)
                                /* we must have greater or equal length to values */
                                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 {
@@ -2186,12 +2466,14 @@ struct route_action *EndpointAppPBX::route(struct route_ruleset *ruleset)
 
                        cond = cond->next;
                }
-               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 */
-                       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) {
@@ -2211,7 +2493,7 @@ struct route_action *EndpointAppPBX::route(struct route_ruleset *ruleset)
        if (match_timeout == 0)
                unsched_timer(&e_match_timeout); /* no timeout */
        else {
-               schedule_timer(&e_match_timeout, match_timeout / 1000000, match_timeout % 1000000);
+               schedule_timer(&e_match_timeout, (match_timeout-now_ll) / 1000000, (match_timeout-now_ll) % 1000000);
        }
        return(action);
 }
@@ -2267,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,