From d87c94d603af0a1495026a8c963720ad8e9a2639 Mon Sep 17 00:00:00 2001 From: maniac103 Date: Thu, 7 Jan 2021 17:38:47 +0100 Subject: [PATCH] [tr064] Normalize numbers in phonebook entries (#9733) * [tr064] Normalize numbers in phone book entries. Phone book numbers and numbers to be looked up might be formatted differently (real world example: '+49 (12345) 67890' vs. '01234567890' (where the former is phonebook formatting and the latter is the format transmitted by the avmfritz binding). Make sure such formatting differences do not cause lookup mismatches. Signed-off-by: Danny Baumann --- bundles/org.openhab.binding.tr064/README.md | 4 +++- .../internal/phonebook/Tr064PhonebookImpl.java | 17 +++++++++++------ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/bundles/org.openhab.binding.tr064/README.md b/bundles/org.openhab.binding.tr064/README.md index e31eb17f5..9df446d1f 100644 --- a/bundles/org.openhab.binding.tr064/README.md +++ b/bundles/org.openhab.binding.tr064/README.md @@ -168,6 +168,7 @@ The default is to use all available phonebooks from the specified thing. In case the format of the number in the phonebook and the format of the number from the channel are different (e.g. regarding country prefixes), the `matchCount` parameter can be used. The configured `matchCount` is counted from the right end and denotes the number of matching characters needed to consider this number as matching. A `matchCount` of `0` is considered as "match everything". +Matching is done on normalized versions of the numbers that have all characters except digits, '+' and '*' removed. ## Rule Action @@ -178,7 +179,8 @@ The phonebooks of a `fritzbox` thing can be used to lookup a number from rules v `phonebook` and `matchCount` are optional parameters. You can omit one or both of these parameters. The configured `matchCount` is counted from the right end and denotes the number of matching characters needed to consider this number as matching. -A `matchCount` of `0` is considered as "match everything" and is used as default if no other value is given. +A `matchCount` of `0` is considered as "match everything" and is used as default if no other value is given. +As in the phonebook profile, matching is done on normalized versions of the numbers that have all characters except digits, '+' and '*' removed. The return value is either the phonebook entry (if found) or the input number. Example (use all phonebooks, match 5 digits from right): diff --git a/bundles/org.openhab.binding.tr064/src/main/java/org/openhab/binding/tr064/internal/phonebook/Tr064PhonebookImpl.java b/bundles/org.openhab.binding.tr064/src/main/java/org/openhab/binding/tr064/internal/phonebook/Tr064PhonebookImpl.java index 35e0fe336..b9e1dc650 100644 --- a/bundles/org.openhab.binding.tr064/src/main/java/org/openhab/binding/tr064/internal/phonebook/Tr064PhonebookImpl.java +++ b/bundles/org.openhab.binding.tr064/src/main/java/org/openhab/binding/tr064/internal/phonebook/Tr064PhonebookImpl.java @@ -31,7 +31,6 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.api.ContentResponse; import org.eclipse.jetty.http.HttpMethod; -import org.openhab.binding.tr064.internal.dto.additions.NumberType; import org.openhab.binding.tr064.internal.dto.additions.PhonebooksType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -73,7 +72,7 @@ public class Tr064PhonebookImpl implements Phonebook { phonebook = phonebooksType.getPhonebook().getContact().stream().map(contact -> { String contactName = contact.getPerson().getRealName(); return contact.getTelephony().getNumber().stream() - .collect(Collectors.toMap(NumberType::getValue, number -> contactName)); + .collect(Collectors.toMap(number -> normalizeNumber(number.getValue()), number -> contactName)); }).collect(HashMap::new, HashMap::putAll, HashMap::putAll); logger.debug("Downloaded phonebook {}: {}", phonebookName, phonebook); } catch (JAXBException | InterruptedException | ExecutionException | TimeoutException e) { @@ -88,10 +87,11 @@ public class Tr064PhonebookImpl implements Phonebook { @Override public Optional lookupNumber(String number, int matchCount) { - String matchString = matchCount > 0 && matchCount < number.length() - ? number.substring(number.length() - matchCount) - : number; - logger.trace("matchString for '{}' is '{}'", number, matchString); + String normalized = normalizeNumber(number); + String matchString = matchCount > 0 && matchCount < normalized.length() + ? normalized.substring(normalized.length() - matchCount) + : normalized; + logger.trace("Normalized '{}' to '{}', matchString is '{}'", number, normalized, matchString); return matchString.isBlank() ? Optional.empty() : phonebook.keySet().stream().filter(n -> n.endsWith(matchString)).findFirst().map(phonebook::get); } @@ -100,4 +100,9 @@ public class Tr064PhonebookImpl implements Phonebook { public String toString() { return "Phonebook{" + "phonebookName='" + phonebookName + "', phonebook=" + phonebook + '}'; } + + private String normalizeNumber(String number) { + // Naive normalization: remove all non-digit characters + return number.replaceAll("[^0-9]\\+\\*", ""); + } }