/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include #include "cpr_stdio.h" #include "cpr_stdlib.h" #include "cpr_string.h" #include "xml_defs.h" #include "logger.h" #include "logmsg.h" #include "util_parse.h" #include "debug.h" #include "phone_types.h" #include "regmgrapi.h" #include "upgrade.h" #include "dialplan.h" extern char DirectoryBuffer[DIALPLAN_MAX_SIZE]; /* * Tones with Bellcore- are Bellcore defined tones. * Tones with Cisco- are our tones. * The order of these names MUST match the order of * the vcm_tones_t type in vcm.h */ const char *tone_names[] = { "Bellcore-Inside", "Bellcore-Outside", "Bellcore-Busy", "Bellcore-Alerting", "Bellcore-BusyVerify", "Bellcore-Stutter", "Bellcore-MsgWaiting", "Bellcore-Reorder", "Bellcore-CallWaiting", "Bellcore-Cw2", "Bellcore-Cw3", "Bellcore-Cw4", "Bellcore-Hold", "Bellcore-Confirmation", "Bellcore-Permanent", "Bellcore-Reminder", "Bellcore-None", "Cisco-ZipZip", "Cisco-Zip", "Cisco-BeepBonk" }; static struct DialTemplate *basetemplate; char DialTemplateFile[MAX_TEMPLATE_LENGTH]; char g_dp_version_stamp[MAX_DP_VERSION_STAMP_LEN]; /* * Function: addbytes() * * Parameters: * * Description: * * Returns: None */ static void addbytes (char **output, int *outlen, const char *input, int inlen) { char *target = *output; if (inlen == -1) { inlen = strlen(input); } if (inlen >= *outlen) { inlen = *outlen - 1; } memcpy(target, input, inlen); target += inlen; *outlen += inlen; *output = target; /* * Null terminate the result */ *target = '\0'; } /* * Function: poundDialingEnabled() * * Parameters: None * * Description: Determines if '#' is treated as a "dial now" character * * Returns: TRUE if # is treated as end of dial signal * FALSE if # is treated as a dialed digit */ static boolean poundDialingEnabled (void) { if (sip_regmgr_get_cc_mode(1) == REG_MODE_NON_CCM) { /* * Operating in Peer-to-Peer SIP mode, allow # dialing */ return (TRUE); } else { return (FALSE); } } /* * Function: isDialedDigit() * * Parameters: input - single char * * Description: Determine if the char is 0-9 or +, * * # is matched here unless it is set to * be used as "dial immediately" * * Returns: DialMatchAction */ boolean isDialedDigit (char input) { boolean result = FALSE; if (!isdigit(input)) { if ((input == '*') || (input == '+') || ((input == '#') && (!poundDialingEnabled()))) { result = TRUE; } } else { result = TRUE; } return (result); } /* * Function: MatchLineNumber() * * Parameters: templateLine - line number specified in Dial Plan * line - line number to match * * Description: The template line numbers are initialized to zero. * Zero means that all lines match. If the Line parm * is specified in the Dial Plan template, then its * value must match the specified line. *^M * Returns: boolean */ static boolean MatchLineNumber (const line_t templateLine, const line_t line) { /* Zero in the template matches any line. */ return (boolean) ((templateLine == line) || (templateLine == 0)); } /* * Function: MatchDialTemplate() * * Parameters: pattern - pattern string to match * line - line number to match * (May be 0 to match all lines) * timeout - returned dial timeout in seconds * (May be NULL to not get a timeout) * rewrite - buffer to hold rewritten string * (May be NULL for no rewrite) * rewritelen - Bytes available in the buffer to write to * routemode - pointer to location to hold route mode returned * (May be NULL to not get a routemode) * tone - pointer to location to hold tone returned * * Description: Find the best template to match a pattern * * Returns: DialMatchAction */ DialMatchAction MatchDialTemplate (const char *pattern, const line_t line, int *timeout, char *rewrite, int rewritelen, RouteMode *pRouteMode, vcm_tones_t *pTone) { DialMatchAction result = DIAL_NOMATCH; struct DialTemplate *ptempl = basetemplate; struct DialTemplate *pbestmatch = NULL; boolean bestmatch_dialnow = FALSE; int best_comma_count = 0; DialMatchAction partialmatch_type = DIAL_NOMATCH; boolean partialmatch = FALSE; int matchlen = 0; int partialmatchlen = 0; int givedialtone = 0; int comma_counter = 0; /* * We need to provide a default rewrite string in case we do not have any template matches. * This happens when there is no template match (such as no * pattern) and when they have * no dial plan file at all */ if (rewrite != NULL) { char *output = rewrite; int room = rewritelen; addbytes(&output, &room, pattern, -1); } /* * If the dialplan is empty, check to see if a # is in the pattern * and return DIAL_IMMEDIATELY. If not go ahead and return * DIAL_NOMATCH since there will be no template match in * an empty dialplan. */ if (ptempl == NULL) { if (strchr(pattern, '#') && (poundDialingEnabled())) { return DIAL_IMMEDIATELY; } else { return DIAL_NOMATCH; } } /* * Iterate through all the templates. Skip the this template if it's not * for this line or all lines. */ while (ptempl != NULL) { if (MatchLineNumber(ptempl->line, line)) { char *pinput = (char *) pattern; char *pmatch = ptempl->pattern; int thismatchlen = 0; DialMatchAction thismatch = DIAL_FULLMATCH; char *subs[MAX_SUBTITUTIONS]; int subslen[MAX_SUBTITUTIONS]; int subscount = -1; boolean dialnow = FALSE; while (*pinput) { int idx; /* Since the code below combines multiple , * in a row into "one" , only increment * comma counter once instead of once * for each comma combined. */ if (pmatch[0] == ',') { comma_counter++; } /* * Skip over any dial tone characters */ while (pmatch[0] == ',') { pmatch++; } /* * If this is a pattern character, we need to capture the digits for the * substitution strings */ if (((pmatch[0] == '.') && isDialedDigit(pinput[0])) || (pmatch[0] == '*')) { /* * Get the next index in the substitution array (if any) * Note that if they have more pattern sections in the pattern string * the last one will get the counts for the characters. So for example * with the MAX_SUBSTITUTIONS of 5 and a pattern of * 1.2.3.4.5.6.7. * and an input string of * 1a2b3c4d5e6f7g * the arrays of substitions would come out as follows: * %0 = 1a2b3c4d5e6f7g (as expected) * %1 = a (as expected) * %2 = b (as expected) * %3 = c (as expected) * %4 = d (as expected) * %5 = e6f NOT what they really wanted, but predictable from the algorithm */ if (subscount < (MAX_SUBTITUTIONS - 1)) { subscount++; subs[subscount] = pinput; subslen[subscount] = 1; } if (pmatch[0] == '.') { thismatch = DIAL_FULLPATTERN; /* * . in the pattern will match anything but doesn't contribute * to our matching length for finding the best template */ while (isdigit(pinput[1]) && (pmatch[1] == '.')) { pinput++; pmatch++; subslen[subscount]++; } } else { thismatch = DIAL_WILDPATTERN; /* * '*' is a wild card to match 1 or more characters * Do a hungry first match * * Note: If match is currently pointing to an escape character, * we need to go past it to match the actual character. */ if (pmatch[1] == DIAL_ESCAPE) { idx = 2; } else { idx = 1; } /* * The '*' will not match the '#' character since its' default use * causes the phone to "dial immediately" */ if ((pinput[0] == '#') && (poundDialingEnabled())) { dialnow = TRUE; } else { while ((pinput[1] != '\0') && (pinput[1] != pmatch[idx])) { /* * If '#' is found and pound dialing is enabled, break out of the loop. */ if ((pinput[1] == '#') && (poundDialingEnabled())) { break; } pinput++; subslen[subscount]++; } } } /* * Any other character must match exactly */ } else { /* * Look for the Escape character '\' and remove it * Right now, the only character that needs to be escaped is '*' * Note that we treat \ at the end of a line as a non-special * character */ if ((pmatch[0] == DIAL_ESCAPE) && (pmatch[1] != '\0')) { pmatch++; } if (pmatch[0] != pinput[0]) { /* * We found a '#' that doesn't match the current match template * This means that the '#" should be interpreted as the dial * termination character. */ if ((pinput[0] == '#') && (poundDialingEnabled())) { dialnow = TRUE; break; } /* * No match, so abandon with no pattern to select */ thismatchlen = -1; thismatch = DIAL_NOMATCH; break; } else { /* * We matched one character, count it for the overall template match */ thismatchlen++; } } pmatch++; pinput++; } /* * *pinput = NULL means we matched everything that * was dialed in this template * Partial never matches * rules * Since 97. should have precendence over 9.. * also check matchlen. * Since fullmatches (exact digits) have precendence * over fullpattern (.) check matchtype */ if ((*pinput == NUL) || (dialnow)) { if ((thismatchlen > partialmatchlen) || ((thismatchlen == partialmatchlen) && (thismatch > partialmatch_type))) { partialmatch_type = thismatch; partialmatchlen = thismatchlen; pbestmatch = ptempl; partialmatch = TRUE; bestmatch_dialnow = dialnow; best_comma_count = comma_counter; result = DIAL_NOMATCH; } } /* * If we exhausted the match string, then the template is a perfect match * However, we don't want to take this as the best template unless it matched * more digits than any other pattern. For example if we have a pattern of * 9011* * 9.11 * We would want 9011 to match against the first one even though it is not complete * * We also have to be careful that a pattern such as * * * does not beat something like * 9....... * when you have 94694210 */ if (pmatch[0] == '\0') { /* * If this pattern is better, we want to adopt it */ if ((thismatchlen > matchlen) || ((thismatchlen == matchlen) && (thismatch > result)) || ((thismatch == DIAL_WILDPATTERN) && ((result == DIAL_NOMATCH) && (partialmatch == FALSE)))) { /* * this is a better match than what we found before */ pbestmatch = ptempl; bestmatch_dialnow = dialnow; matchlen = thismatchlen; result = thismatch; /* * Generate a rewrite string * *