From c094f400ac215bf973f5c49048bf74904054c8dc Mon Sep 17 00:00:00 2001
From: jowiemann <>
Date: Tue, 14 Nov 2023 13:38:31 +0000
Subject: [PATCH] 72_FB_CALLMONITOR.pm: commandRef
git-svn-id: https://svn.fhem.de/fhem/trunk@28165 2b470e98-0d58-463d-a4d8-8e2adae1ed80
---
fhem/FHEM/72_FB_CALLMONITOR.pm | 347 ++++++++++++---------------------
1 file changed, 126 insertions(+), 221 deletions(-)
diff --git a/fhem/FHEM/72_FB_CALLMONITOR.pm b/fhem/FHEM/72_FB_CALLMONITOR.pm
index b3a4bca05..f83ca9b18 100755
--- a/fhem/FHEM/72_FB_CALLMONITOR.pm
+++ b/fhem/FHEM/72_FB_CALLMONITOR.pm
@@ -40,7 +40,7 @@ use HttpUtils;
use DevIo;
use FritzBoxUtils;
-my $ModulVersion = "07.50.3e";
+my $ModulVersion = "07.50.3f";
my %tellows = ();
my %connection_type = (
0 => "FON1",
@@ -252,10 +252,21 @@ sub FB_CALLMONITOR_Get($@)
if($arguments[1] eq "search" and int(@arguments) >= 3)
{
FB_CALLMONITOR_Log $name, 3, "get $name $arguments[1] " . join ' ', @arguments[2..$#arguments];
- my $number = FB_CALLMONITOR_normalizePhoneNumber($hash, join '', @arguments[2..$#arguments]);
- my $result = FB_CALLMONITOR_reverseSearch($hash, $number, 1);
- return $result if(defined($result));
+ my $number;
+
+ if (lc($arguments[2]) eq "uid") {
+ $number = FB_CALLMONITOR_normalizePhoneNumber($hash, join '', @arguments[3..$#arguments]);
+ } else {
+ $number = FB_CALLMONITOR_normalizePhoneNumber($hash, join '', @arguments[2..$#arguments]);
+ }
+
+ my $result = FB_CALLMONITOR_reverseSearch($hash, $number, 1);
+ if(defined($result)) {
+ $result =~ s/ \[\<.*?\>\]// if lc($arguments[2]) ne "uid";
+ return $result;
+ }
+
return "no reverse search result found for $number";
}
elsif($arguments[1] eq "showPhonebookIds" and exists($hash->{helper}{PHONEBOOK_NAMES}))
@@ -304,7 +315,7 @@ sub FB_CALLMONITOR_Get($@)
foreach my $number (sort { lc($hash->{helper}{PHONEBOOKS}{$pb_id}{$a}) cmp lc($hash->{helper}{PHONEBOOKS}{$pb_id}{$b}) } keys %{$hash->{helper}{PHONEBOOKS}{$pb_id}})
{
my $string = sprintf(" %-".$number_width."s - %s" , $number,$hash->{helper}{PHONEBOOKS}{$pb_id}{$number});
- $table .= $string."\n";
+ $table .= $string . "\n";
}
$return .= $head."\n ".("-" x ($number_width + $name_width + 3))."\n".$table."\n";
@@ -521,9 +532,10 @@ sub FB_CALLMONITOR_Read($)
$external_number =~ s/#.*$// if($external_number !~ /^\*/); # Forum #85761
$reverse_search = FB_CALLMONITOR_reverseSearch($hash, $external_number, ($array[1] eq "RING")) if(AttrVal($name, "reverse-search", "none") ne "none");
-
- FB_CALLMONITOR_Log $name, 4, "reverse search returned: $reverse_search" if(defined($reverse_search));
-
+ if(defined($reverse_search)) {
+ $reverse_search =~ s/ \[\<.*?\>\]//;
+ FB_CALLMONITOR_Log $name, 4, "reverse search returned: $reverse_search";
+ }
}
if($array[1] =~ /^CALL|RING$/)
@@ -879,7 +891,9 @@ sub FB_CALLMONITOR_reverseSearch($$$) {
if(exists($hash->{helper}{PHONEBOOK})) {
if(defined($hash->{helper}{PHONEBOOK}{$number})) {
FB_CALLMONITOR_Log $name, 4, "using internal phonebook for reverse search of $number";
- return $hash->{helper}{PHONEBOOK}{$number};
+ my $number = $hash->{helper}{PHONEBOOK}{$number};
+ # $number =~ s/ \[\<.*?\>\]//;
+ return $number;
} elsif(my $result = FB_CALLMONITOR_searchPhonebookWildcards($hash->{helper}{PHONEBOOK}, $number)) {
FB_CALLMONITOR_Log $name, 4, "using internal phonebook for reverse search of $number";
return $result;
@@ -890,7 +904,9 @@ sub FB_CALLMONITOR_reverseSearch($$$) {
foreach my $pb_id (keys %{$hash->{helper}{PHONEBOOKS}}) {
if(defined($hash->{helper}{PHONEBOOKS}{$pb_id}{$number})) {
FB_CALLMONITOR_Log $name, 4, "using internal phonebook for reverse search of $number";
- return $hash->{helper}{PHONEBOOKS}{$pb_id}{$number};
+ my $number = $hash->{helper}{PHONEBOOKS}{$pb_id}{$number};
+ # $number =~ s/ \[\<.*?\>\]//;
+ return $number;
} elsif(my $result = FB_CALLMONITOR_searchPhonebookWildcards($hash->{helper}{PHONEBOOKS}{$pb_id}, $number)) {
FB_CALLMONITOR_Log $name, 4, "using internal phonebook for reverse search of $number";
return $result;
@@ -1345,128 +1361,96 @@ sub FB_CALLMONITOR_readPhonebook($;$)
delete($hash->{helper}{PHONEBOOKS});
delete($hash->{helper}{IMAGE_URLS});
- if(AttrVal($name, "fritzbox-remote-phonebook", "0") eq "1")
- {
- if(AttrVal($name, "fritzbox-remote-phonebook-via", "tr064") eq "telnet")
+ if(AttrVal($name, "fritzbox-remote-phonebook", "0") eq "1") {
+
+ if(AttrVal($name, "fritzbox-remote-phonebook-via", "tr064") =~ /^(web|tr064)$/) {
+ my $do_with = $1;
+ $err = FB_CALLMONITOR_identifyPhoneBooksViaWeb($hash, $testPassword) if($do_with eq "web");
+ $err = FB_CALLMONITOR_identifyPhoneBooksViaTR064($hash, $testPassword) if($do_with eq "tr064");
+
+ if(defined($err)) {
+ FB_CALLMONITOR_Log $name, 2, "could not identify remote phonebooks - $err";
+ return "could not identify remote phonebooks - $err";
+ }
+
+ unless(exists($hash->{helper}{PHONEBOOK_NAMES})) {
+
+ FB_CALLMONITOR_Log $name, 2, "no phonebooks could be found";
+ return "no phonebooks could be found";
+ }
+
+ my %excludedIds = map { trim($_) => 1 } split(",",AttrVal($name, "fritzbox-remote-phonebook-exclude", ""));
+
+ foreach my $phonebookId (sort keys %{$hash->{helper}{PHONEBOOK_NAMES}})
{
- ($err, $phonebook) = FB_CALLMONITOR_readRemotePhonebookViaTelnet($hash, $testPassword);
+ if(exists($excludedIds{$phonebookId}) or exists($excludedIds{$hash->{helper}{PHONEBOOK_NAMES}{$phonebookId}}))
+ {
+ FB_CALLMONITOR_Log $name, 4, "skipping excluded phonebook id $phonebookId (".$hash->{helper}{PHONEBOOK_NAMES}{$phonebookId}.")";
+ next;
+ }
- if(defined($err))
- {
- FB_CALLMONITOR_Log $name, 2, "could not read remote FritzBox phonebook file - $err";
- return "Could not read remote FritzBox phonebook file - $err";
- }
+ FB_CALLMONITOR_Log $name, 4, "requesting phonebook id $phonebookId (".$hash->{helper}{PHONEBOOK_NAMES}{$phonebookId}.")";
- FB_CALLMONITOR_Log $name, 3, "found remote FritzBox phonebook via telnet";
+ ($err, $phonebook) = FB_CALLMONITOR_readRemotePhonebookViaWeb($hash, $phonebookId, $testPassword) if($do_with eq "web");
+ ($err, $phonebook) = FB_CALLMONITOR_readRemotePhonebookViaTR064($hash, $phonebookId, $testPassword) if($do_with eq "tr064");
+
+ if(defined($err)) {
+
+ FB_CALLMONITOR_Log $name, 2, 'unable to retrieve phonebook "'.$hash->{helper}{PHONEBOOK_NAMES}{$phonebookId}.'" from FritzBox - '.$err;
+
+ } else {
($err, $count_contacts, $pb_hash) = FB_CALLMONITOR_parsePhonebook($hash, $phonebook);
- $hash->{helper}{PHONEBOOK} = $pb_hash;
- if(defined($err))
- {
- FB_CALLMONITOR_Log $name, 2, "could not parse remote phonebook - $err";
- return "Could not parse remote phonebook - $err";
- }
- else
- {
- FB_CALLMONITOR_Log $name, 3, "read $count_contacts contact".($count_contacts == 1 ? "" : "s")." from remote phonebook via telnet";
+ $hash->{helper}{PHONEBOOKS}{$phonebookId} = $pb_hash;
+
+ if(defined($err)) {
+ FB_CALLMONITOR_Log $name, 2, "could not parse remote phonebook ".$hash->{helper}{PHONEBOOK_NAMES}{$phonebookId}." - $err";
+ } else {
+ FB_CALLMONITOR_Log $name, 3, "read $count_contacts contact".($count_contacts == 1 ? "" : "s").' from remote phonebook "'.$hash->{helper}{PHONEBOOK_NAMES}{$phonebookId}.'"';
}
+ }
+
}
- elsif(AttrVal($name, "fritzbox-remote-phonebook-via", "tr064") =~ /^(web|tr064)$/)
- {
- my $do_with = $1;
- $err = FB_CALLMONITOR_identifyPhoneBooksViaWeb($hash, $testPassword) if($do_with eq "web");
- $err = FB_CALLMONITOR_identifyPhoneBooksViaTR064($hash, $testPassword) if($do_with eq "tr064");
- if(defined($err))
- {
- FB_CALLMONITOR_Log $name, 2, "could not identify remote phonebooks - $err";
- return "could not identify remote phonebooks - $err";
- }
+ delete($hash->{helper}{PHONEBOOK_URL});
+ FB_CALLMONITOR_downloadImageURLs($hash, $testPassword);
+ }
- unless(exists($hash->{helper}{PHONEBOOK_NAMES}))
- {
- FB_CALLMONITOR_Log $name, 2, "no phonebooks could be found";
- return "no phonebooks could be found";
- }
-
- my %excludedIds = map { trim($_) => 1 } split(",",AttrVal($name, "fritzbox-remote-phonebook-exclude", ""));
-
- foreach my $phonebookId (sort keys %{$hash->{helper}{PHONEBOOK_NAMES}})
- {
- if(exists($excludedIds{$phonebookId}) or exists($excludedIds{$hash->{helper}{PHONEBOOK_NAMES}{$phonebookId}}))
- {
- FB_CALLMONITOR_Log $name, 4, "skipping excluded phonebook id $phonebookId (".$hash->{helper}{PHONEBOOK_NAMES}{$phonebookId}.")";
- next;
- }
-
- FB_CALLMONITOR_Log $name, 4, "requesting phonebook id $phonebookId (".$hash->{helper}{PHONEBOOK_NAMES}{$phonebookId}.")";
-
- ($err, $phonebook) = FB_CALLMONITOR_readRemotePhonebookViaWeb($hash, $phonebookId, $testPassword) if($do_with eq "web");
- ($err, $phonebook) = FB_CALLMONITOR_readRemotePhonebookViaTR064($hash, $phonebookId, $testPassword) if($do_with eq "tr064");
-
- if(defined($err))
- {
- FB_CALLMONITOR_Log $name, 2, 'unable to retrieve phonebook "'.$hash->{helper}{PHONEBOOK_NAMES}{$phonebookId}.'" from FritzBox - '.$err;
- }
- else
- {
- ($err, $count_contacts, $pb_hash) = FB_CALLMONITOR_parsePhonebook($hash, $phonebook);
-
- $hash->{helper}{PHONEBOOKS}{$phonebookId} = $pb_hash;
-
- if(defined($err))
- {
- FB_CALLMONITOR_Log $name, 2, "could not parse remote phonebook ".$hash->{helper}{PHONEBOOK_NAMES}{$phonebookId}." - $err";
- }
- else
- {
- FB_CALLMONITOR_Log $name, 3, "read $count_contacts contact".($count_contacts == 1 ? "" : "s").' from remote phonebook "'.$hash->{helper}{PHONEBOOK_NAMES}{$phonebookId}.'"';
- }
- }
- }
-
- delete($hash->{helper}{PHONEBOOK_URL});
-
- FB_CALLMONITOR_downloadImageURLs($hash, $testPassword);
- }
- }
- else
- {
- FB_CALLMONITOR_Log $name, 4, "skipping remote phonebook";
+ } else {
+ FB_CALLMONITOR_Log $name, 4, "skipping remote phonebook";
}
if(-e "/usr/bin/ctlmgr_ctl" or ((not -e "/usr/bin/ctlmgr_ctl") and defined(AttrVal($name, "reverse-search-phonebook-file", undef))))
{
- my $phonebook_file = AttrVal($name, "reverse-search-phonebook-file", "/var/flash/phonebook");
+ my $phonebook_file = AttrVal($name, "reverse-search-phonebook-file", "/var/flash/phonebook");
- ($err, @lines) = FileRead({FileName => $phonebook_file, ForceType => "file"});
+ ($err, @lines) = FileRead({FileName => $phonebook_file, ForceType => "file"});
- if(defined($err) && $err)
- {
- FB_CALLMONITOR_Log $name, 2, "could not read FritzBox phonebook file - $err";
- return "Could not read FritzBox phonebook file - $err";
- }
+ if(defined($err) && $err)
+ {
+ FB_CALLMONITOR_Log $name, 2, "could not read FritzBox phonebook file - $err";
+ return "Could not read FritzBox phonebook file - $err";
+ }
- $phonebook = join("", @lines);
+ $phonebook = join("", @lines);
- FB_CALLMONITOR_Log $name, 4, "found FritzBox phonebook $phonebook_file";
+ FB_CALLMONITOR_Log $name, 4, "found FritzBox phonebook $phonebook_file";
- ($err, $count_contacts, $pb_hash) = FB_CALLMONITOR_parsePhonebook($hash, $phonebook);
+ ($err, $count_contacts, $pb_hash) = FB_CALLMONITOR_parsePhonebook($hash, $phonebook);
- if(defined($err))
- {
- FB_CALLMONITOR_Log $name, 2, "could not parse $phonebook_file - $err";
- return "Could not parse $phonebook_file - $err";
- }
- else
- {
- $hash->{helper}{PHONEBOOK} = $pb_hash;
- FB_CALLMONITOR_Log $name, 4, "read $count_contacts contact".($count_contacts == 1 ? "" : "s")." from $phonebook_file";
- }
- }
- else
- {
+ if(defined($err))
+ {
+ FB_CALLMONITOR_Log $name, 2, "could not parse $phonebook_file - $err";
+ return "Could not parse $phonebook_file - $err";
+ }
+ else
+ {
+ $hash->{helper}{PHONEBOOK} = $pb_hash;
+ FB_CALLMONITOR_Log $name, 4, "read $count_contacts contact".($count_contacts == 1 ? "" : "s")." from $phonebook_file";
+ }
+
+ } else {
FB_CALLMONITOR_Log $name, 4, "skipping local phonebook file";
}
}
@@ -1481,10 +1465,25 @@ sub FB_CALLMONITOR_parsePhonebook($$)
my $contact;
my $contact_name;
my $number;
+ my $uniqueID;
my $count_contacts = 0;
my $out;
+ FB_CALLMONITOR_Log $name, 5, "phoneBook: \n" . $phonebook;
+
+#
+#
+#
+# 1&1 Kundenservice
+#
+# 0721 9600
+#
+#
+#
+# 29
+#
+
if($phonebook =~ /,)
{
if($phonebook =~ // and $phonebook =~ /(.+?),) {
+ $uniqueID = $1;
+ } else {
+ $uniqueID = "nil";
+ }
+
while($contact =~ m,]*?type="([^<>"]+?)"[^<>]*?>([^<>"]+?),gs)
{
if($1 ne "intern" and $1 ne "memo")
@@ -1514,7 +1519,7 @@ sub FB_CALLMONITOR_parsePhonebook($$)
$count_contacts++;
FB_CALLMONITOR_Log $name, 5, "found $contact_name with number $number";
- $out->{$number} = FB_CALLMONITOR_html2txt($contact_name);
+ $out->{$number} = FB_CALLMONITOR_html2txt($contact_name) . " [<$uniqueID>]";
if($imageURL)
{
@@ -1660,112 +1665,6 @@ sub FB_CALLMONITOR_loadTextFile($;$)
}
}
-#######################################################################
-# loads phonebook from extern FritzBox
-sub FB_CALLMONITOR_readRemotePhonebookViaTelnet($;$)
-{
- my ($hash, $testPassword) = @_;
-
- my $name = $hash->{NAME};
-
- my $rc = eval {
- require Net::Telnet;
- Net::Telnet->import();
- 1;
- };
-
- unless($rc)
- {
- return "Error loading Net::Telnet. Maybe this module is not installed?";
- }
-
- my $phonebook_file = "/var/flash/phonebook";
-
- my ($fb_ip,undef) = split(/:/, ($hash->{DeviceName}), 2);
-
- $hash->{helper}{READ_PWD} = 1;
-
- my $fb_user = AttrVal($name, "fritzbox-user", undef);
- my $fb_pw = FB_CALLMONITOR_readPassword($hash, $testPassword);
-
- delete($hash->{helper}{READ_PWD});
- return "no password available to access FritzBox. Please set your FRITZ!Box password via 'set ".$hash->{NAME}." password '" unless(defined($fb_pw));
-
- my $telnet = Net::Telnet->new(Timeout => 10, Errmode => 'return');
-
- unless($telnet->open($fb_ip))
- {
- return "Error Connecting to FritzBox: ".$telnet->errmsg;
- }
-
- FB_CALLMONITOR_Log $name, 4, "connected to FritzBox via telnet";
-
- my ($prematch, $match) = $telnet->waitfor('/(?:login|user|password):\s*$/i');
-
- unless(defined($prematch) and defined($match))
- {
- $telnet->close;
- return "Couldn't recognize login prompt: ".$telnet->errmsg;
- }
-
- if($match =~ /(login|user):/i and defined($fb_user))
- {
- FB_CALLMONITOR_Log $name, 4, "setting user to FritzBox: $fb_user";
- $telnet->print($fb_user);
-
- unless($telnet->waitfor('/password:\s*$/i'))
- {
- $telnet->close;
- return "Error giving password to FritzBox: ".$telnet->errmsg;
- }
-
- FB_CALLMONITOR_Log $name, 4, "giving password to FritzBox";
- $telnet->print($fb_pw);
- }
- elsif($match =~ /(login|user):/i and not defined($fb_user))
- {
- $telnet->close;
- return "FritzBox needs a username to login via telnet. Please provide a valid username/password combination";
- }
- elsif($match =~ /password:/i)
- {
- FB_CALLMONITOR_Log $name, 4, "giving password to FritzBox";
- $telnet->print($fb_pw);
- }
-
- unless($telnet->waitfor('/#\s*$/'))
- {
- $telnet->close;
- my $err = $telnet->errmsg;
- $hash->{helper}{PWD_NEEDED} = 1;
- return "wrong password, please provide the right password" if($err =~ /\s*eof/i);
- return "Could'nt recognize shell prompt: $err";
- }
-
- FB_CALLMONITOR_Log $name, 4, "requesting $phonebook_file via telnet";
-
- my $command = "cat ".$phonebook_file;
-
- my @FBPhoneBook = $telnet->cmd($command);
-
- unless(@FBPhoneBook)
- {
- $telnet->close;
- return "Error getting phonebook FritzBox: ".$telnet->errmsg;
- }
- else
- {
- FB_CALLMONITOR_Log $name, 4, "Getting phonebook from FritzBox: $phonebook_file";
- }
-
- $telnet->print('exit');
- $telnet->close;
-
- delete($hash->{helper}{PWD_NEEDED});
-
- return (undef, join('', @FBPhoneBook));
-}
-
#######################################################################
# performs a HTTP based request via TR-064 port with authentication
sub FB_CALLMONITOR_requestHTTPviaTR064($$$$;$$)
@@ -2590,6 +2489,8 @@ sub FB_CALLMONITOR_sendKeepAlive($)
After activating the Callmonitor-Support in your FritzBox, this module is able to
generate an event for each external call. Internal calls were not be detected by the Callmonitor.
+
+ It is recommendet to set the attribute fritzbox-user after defining the device.
This module work with any FritzBox Fon model.
@@ -2765,7 +2666,7 @@ sub FB_CALLMONITOR_sendKeepAlive($)
Default Value: empty (all phonebooks should be used, no exclusions)
fritzbox-user <username>
- Use the given username to obtain the phonebook via network connection (see fritzbox-remote-phonebook). This attribute is only needed, if you use multiple users on your FritzBox.
+ Username for TR064 or other web-based access. The current FritzOS versions require a user name for login.
apiKeySearchCh <API-Key>
A private API key from tel.search.ch to perform a reverse search via search.ch (see attribute reverse-search). Without an API key, no reverse search via search.ch is not possible
@@ -2832,6 +2733,8 @@ sub FB_CALLMONITOR_sendKeepAlive($)
Nach ca. 3 Sekunden kann man einfach wieder auflegen. Nun ist der Callmonitor aktiviert.
Sobald der Callmonitor auf der Fritz!Box aktiviert wurde erzeugt das Modul entsprechende Events (s.u.) für alle externen Anrufe. Interne Anrufe werden nicht durch den Callmonitor erfasst.
+
+ Es muss zwingend das Attribut fritzbox-user nach der Definition des Device gesetzt werden.
Dieses Modul funktioniert mit allen Fritz!Box Modellen, welche Telefonie unterstützen (Namenszusatz: Fon).
@@ -3015,7 +2918,9 @@ sub FB_CALLMONITOR_sendKeepAlive($)
Standardmäßig ist diese Funktion deaktiviert (alle Telefonbücher werden eingelesen)
fritzbox-user <Username>
- Der Username, sofern das Telefonbuch direkt von der FritzBox via Netzwerk geladen werden soll (siehe Attribut: fritzbox-remote-phonebook). Dieses Attribut ist nur notwendig, wenn verschiedene Benutzernamen auf der FritzBox konfiguriert sind.
+ Benutzername für den TR064- oder einen anderen webbasierten Zugang. Die aktuellen FritzOS Versionen verlangen zwingend einen Benutzername für das Login.
+
+
apiKeySearchCh <API-Key>
Der private API-Key von tel.search.ch um eine Rückwärtssuche via search.ch durchzuführen (siehe Attribut reverse-search). Ohne einen solchen API-Key ist eine Rückwärtssuche via search.ch nicht möglich