X-Git-Url: http://git.eversberg.eu/gitweb.cgi?p=lcr.git;a=blobdiff_plain;f=route.c;h=925bfe86e3334f2a7d0a3ed6ff40db20f80d7a49;hp=c1bf079491123e4adc305d0058385284c644f2d4;hb=79bd731c0db3e3202cfeed2af3fb217ae744b70f;hpb=8b70a9a5c2071c587ab4016dcbbb8e4bbf6da181 diff --git a/route.c b/route.c index c1bf079..925bfe8 100644 --- a/route.c +++ b/route.c @@ -94,6 +94,14 @@ struct cond_defs cond_defs[] = { "remote=","Matches if remote application is running."}, { "notremote", MATCH_NOTREMOTE,COND_TYPE_STRING, "notremote=","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=","When using POTS: Matches if given number of calls are held."}, + { "pots-last", MATCH_POTS_LAST,COND_TYPE_INTEGER, + "pots-last=","When using POTS: Matches if given call number (1=oldest) was the last active call."}, { NULL, 0, 0, NULL} }; @@ -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=", "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,11 +1278,13 @@ 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; } @@ -1254,35 +1293,49 @@ struct route_ruleset *ruleset_parse(void) /* parse service value */ case COND_TYPE_HLC: - if (!strncasecmp("telephony", p, 9)) + if (!strncasecmp("telephony", p, 9)) { cond->integer_value = INFO_HLC_TELEPHONY; - else if (!strncasecmp("faxg2g3", p, 7)) + p += 9; + } else if (!strncasecmp("faxg2g3", p, 7)) { cond->integer_value = INFO_HLC_FAXG2G3; - else if (!strncasecmp("faxg4", p, 5)) + p += 7; + } else if (!strncasecmp("faxg4", p, 5)) { cond->integer_value = INFO_HLC_FAXG4; - else if (!strncasecmp("teletex1", p, 8)) + p += 5; + } else if (!strncasecmp("teletex1", p, 8)) { cond->integer_value = INFO_HLC_TELETEX1; - else if (!strncasecmp("teletex2", p, 8)) + p += 8; + } else if (!strncasecmp("teletex2", p, 8)) { cond->integer_value = INFO_HLC_TELETEX2; - else if (!strncasecmp("teletex3", p, 8)) + p += 8; + } else if (!strncasecmp("teletex3", p, 8)) { cond->integer_value = INFO_HLC_TELETEX3; - else if (!strncasecmp("videotex1", p, 9)) + p += 8; + } else if (!strncasecmp("videotex1", p, 9)) { cond->integer_value = INFO_HLC_VIDEOTEX1; - else if (!strncasecmp("videotex2", p, 9)) + p += 9; + } else if (!strncasecmp("videotex2", p, 9)) { cond->integer_value = INFO_HLC_VIDEOTEX2; - else if (!strncasecmp("telex", p, 5)) + p += 9; + } else if (!strncasecmp("telex", p, 5)) { cond->integer_value = INFO_HLC_TELEX; - else if (!strncasecmp("mhs", p, 3)) + p += 5; + } else if (!strncasecmp("mhs", p, 3)) { cond->integer_value = INFO_HLC_MHS; - else if (!strncasecmp("osi", p, 3)) + p += 3; + } else if (!strncasecmp("osi", p, 3)) { cond->integer_value = INFO_HLC_OSI; - else if (!strncasecmp("maintenance", p, 11)) + p += 3; + } else if (!strncasecmp("maintenance", p, 11)) { cond->integer_value = INFO_HLC_MAINTENANCE; - else if (!strncasecmp("management", p, 10)) + p += 11; + } else if (!strncasecmp("management", p, 10)) { cond->integer_value = INFO_HLC_MANAGEMENT; - else if (!strncasecmp("audiovisual", p, 11)) + p += 10; + } else if (!strncasecmp("audiovisual", p, 11)) { cond->integer_value = INFO_HLC_AUDIOVISUAL; - else { + p += 11; + } else { SPRINT(failure, "Given HLC type is invalid or misspelled."); goto parse_error; } @@ -1409,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."); @@ -1882,14 +1939,12 @@ 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]; @@ -1898,7 +1953,15 @@ struct route_action *EndpointAppPBX::route(struct route_ruleset *ruleset) 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; @@ -1935,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; @@ -2116,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; @@ -2144,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) @@ -2158,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) @@ -2172,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) @@ -2189,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: @@ -2205,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; @@ -2239,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 { @@ -2313,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) { @@ -2338,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); } @@ -2394,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,