2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-03-10 03:06:37 +00:00

72_FB_CALLMONITOR.pm: commandRef

git-svn-id: https://svn.fhem.de/fhem/trunk@28165 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
jowiemann 2023-11-14 13:38:31 +00:00
parent c292239ff8
commit c094f400ac

View File

@ -40,7 +40,7 @@ use HttpUtils;
use DevIo; use DevIo;
use FritzBoxUtils; use FritzBoxUtils;
my $ModulVersion = "07.50.3e"; my $ModulVersion = "07.50.3f";
my %tellows = (); my %tellows = ();
my %connection_type = ( my %connection_type = (
0 => "FON1", 0 => "FON1",
@ -252,10 +252,21 @@ sub FB_CALLMONITOR_Get($@)
if($arguments[1] eq "search" and int(@arguments) >= 3) if($arguments[1] eq "search" and int(@arguments) >= 3)
{ {
FB_CALLMONITOR_Log $name, 3, "get $name $arguments[1] " . join ' ', @arguments[2..$#arguments]; 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"; return "no reverse search result found for $number";
} }
elsif($arguments[1] eq "showPhonebookIds" and exists($hash->{helper}{PHONEBOOK_NAMES})) elsif($arguments[1] eq "showPhonebookIds" and exists($hash->{helper}{PHONEBOOK_NAMES}))
@ -521,9 +532,10 @@ sub FB_CALLMONITOR_Read($)
$external_number =~ s/#.*$// if($external_number !~ /^\*/); # Forum #85761 $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"); $reverse_search = FB_CALLMONITOR_reverseSearch($hash, $external_number, ($array[1] eq "RING")) if(AttrVal($name, "reverse-search", "none") ne "none");
if(defined($reverse_search)) {
FB_CALLMONITOR_Log $name, 4, "reverse search returned: $reverse_search" if(defined($reverse_search)); $reverse_search =~ s/ \[\<.*?\>\]//;
FB_CALLMONITOR_Log $name, 4, "reverse search returned: $reverse_search";
}
} }
if($array[1] =~ /^CALL|RING$/) if($array[1] =~ /^CALL|RING$/)
@ -879,7 +891,9 @@ sub FB_CALLMONITOR_reverseSearch($$$) {
if(exists($hash->{helper}{PHONEBOOK})) { if(exists($hash->{helper}{PHONEBOOK})) {
if(defined($hash->{helper}{PHONEBOOK}{$number})) { if(defined($hash->{helper}{PHONEBOOK}{$number})) {
FB_CALLMONITOR_Log $name, 4, "using internal phonebook for reverse search of $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)) { } elsif(my $result = FB_CALLMONITOR_searchPhonebookWildcards($hash->{helper}{PHONEBOOK}, $number)) {
FB_CALLMONITOR_Log $name, 4, "using internal phonebook for reverse search of $number"; FB_CALLMONITOR_Log $name, 4, "using internal phonebook for reverse search of $number";
return $result; return $result;
@ -890,7 +904,9 @@ sub FB_CALLMONITOR_reverseSearch($$$) {
foreach my $pb_id (keys %{$hash->{helper}{PHONEBOOKS}}) { foreach my $pb_id (keys %{$hash->{helper}{PHONEBOOKS}}) {
if(defined($hash->{helper}{PHONEBOOKS}{$pb_id}{$number})) { if(defined($hash->{helper}{PHONEBOOKS}{$pb_id}{$number})) {
FB_CALLMONITOR_Log $name, 4, "using internal phonebook for reverse search of $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)) { } 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"; FB_CALLMONITOR_Log $name, 4, "using internal phonebook for reverse search of $number";
return $result; return $result;
@ -1345,47 +1361,20 @@ sub FB_CALLMONITOR_readPhonebook($;$)
delete($hash->{helper}{PHONEBOOKS}); delete($hash->{helper}{PHONEBOOKS});
delete($hash->{helper}{IMAGE_URLS}); delete($hash->{helper}{IMAGE_URLS});
if(AttrVal($name, "fritzbox-remote-phonebook", "0") eq "1") if(AttrVal($name, "fritzbox-remote-phonebook", "0") eq "1") {
{
if(AttrVal($name, "fritzbox-remote-phonebook-via", "tr064") eq "telnet")
{
($err, $phonebook) = FB_CALLMONITOR_readRemotePhonebookViaTelnet($hash, $testPassword);
if(defined($err)) if(AttrVal($name, "fritzbox-remote-phonebook-via", "tr064") =~ /^(web|tr064)$/) {
{
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, 3, "found remote FritzBox phonebook via telnet";
($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";
}
}
elsif(AttrVal($name, "fritzbox-remote-phonebook-via", "tr064") =~ /^(web|tr064)$/)
{
my $do_with = $1; my $do_with = $1;
$err = FB_CALLMONITOR_identifyPhoneBooksViaWeb($hash, $testPassword) if($do_with eq "web"); $err = FB_CALLMONITOR_identifyPhoneBooksViaWeb($hash, $testPassword) if($do_with eq "web");
$err = FB_CALLMONITOR_identifyPhoneBooksViaTR064($hash, $testPassword) if($do_with eq "tr064"); $err = FB_CALLMONITOR_identifyPhoneBooksViaTR064($hash, $testPassword) if($do_with eq "tr064");
if(defined($err)) if(defined($err)) {
{
FB_CALLMONITOR_Log $name, 2, "could not identify remote phonebooks - $err"; FB_CALLMONITOR_Log $name, 2, "could not identify remote phonebooks - $err";
return "could not identify remote phonebooks - $err"; return "could not identify remote phonebooks - $err";
} }
unless(exists($hash->{helper}{PHONEBOOK_NAMES})) unless(exists($hash->{helper}{PHONEBOOK_NAMES})) {
{
FB_CALLMONITOR_Log $name, 2, "no phonebooks could be found"; FB_CALLMONITOR_Log $name, 2, "no phonebooks could be found";
return "no phonebooks could be found"; return "no phonebooks could be found";
} }
@ -1405,34 +1394,30 @@ sub FB_CALLMONITOR_readPhonebook($;$)
($err, $phonebook) = FB_CALLMONITOR_readRemotePhonebookViaWeb($hash, $phonebookId, $testPassword) if($do_with eq "web"); ($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"); ($err, $phonebook) = FB_CALLMONITOR_readRemotePhonebookViaTR064($hash, $phonebookId, $testPassword) if($do_with eq "tr064");
if(defined($err)) if(defined($err)) {
{
FB_CALLMONITOR_Log $name, 2, 'unable to retrieve phonebook "'.$hash->{helper}{PHONEBOOK_NAMES}{$phonebookId}.'" from FritzBox - '.$err; FB_CALLMONITOR_Log $name, 2, 'unable to retrieve phonebook "'.$hash->{helper}{PHONEBOOK_NAMES}{$phonebookId}.'" from FritzBox - '.$err;
}
else } else {
{
($err, $count_contacts, $pb_hash) = FB_CALLMONITOR_parsePhonebook($hash, $phonebook); ($err, $count_contacts, $pb_hash) = FB_CALLMONITOR_parsePhonebook($hash, $phonebook);
$hash->{helper}{PHONEBOOKS}{$phonebookId} = $pb_hash; $hash->{helper}{PHONEBOOKS}{$phonebookId} = $pb_hash;
if(defined($err)) if(defined($err)) {
{
FB_CALLMONITOR_Log $name, 2, "could not parse remote phonebook ".$hash->{helper}{PHONEBOOK_NAMES}{$phonebookId}." - $err"; FB_CALLMONITOR_Log $name, 2, "could not parse remote phonebook ".$hash->{helper}{PHONEBOOK_NAMES}{$phonebookId}." - $err";
} } else {
else
{
FB_CALLMONITOR_Log $name, 3, "read $count_contacts contact".($count_contacts == 1 ? "" : "s").' from remote phonebook "'.$hash->{helper}{PHONEBOOK_NAMES}{$phonebookId}.'"'; 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}); delete($hash->{helper}{PHONEBOOK_URL});
FB_CALLMONITOR_downloadImageURLs($hash, $testPassword); FB_CALLMONITOR_downloadImageURLs($hash, $testPassword);
} }
}
else } else {
{
FB_CALLMONITOR_Log $name, 4, "skipping remote phonebook"; FB_CALLMONITOR_Log $name, 4, "skipping remote phonebook";
} }
@ -1464,9 +1449,8 @@ sub FB_CALLMONITOR_readPhonebook($;$)
$hash->{helper}{PHONEBOOK} = $pb_hash; $hash->{helper}{PHONEBOOK} = $pb_hash;
FB_CALLMONITOR_Log $name, 4, "read $count_contacts contact".($count_contacts == 1 ? "" : "s")." from $phonebook_file"; FB_CALLMONITOR_Log $name, 4, "read $count_contacts contact".($count_contacts == 1 ? "" : "s")." from $phonebook_file";
} }
}
else } else {
{
FB_CALLMONITOR_Log $name, 4, "skipping local phonebook file"; FB_CALLMONITOR_Log $name, 4, "skipping local phonebook file";
} }
} }
@ -1481,10 +1465,25 @@ sub FB_CALLMONITOR_parsePhonebook($$)
my $contact; my $contact;
my $contact_name; my $contact_name;
my $number; my $number;
my $uniqueID;
my $count_contacts = 0; my $count_contacts = 0;
my $out; my $out;
FB_CALLMONITOR_Log $name, 5, "phoneBook: \n" . $phonebook;
# <contact>
# <category />
# <person>
# <realName>1&amp;1 Kundenservice</realName>
# </person>
# <telephony nid="1"><number prio="1" type="work" id="0">0721 9600</number>
# </telephony>
# <services />
# <setup />
# <uniqueid>29</uniqueid>
# </contact>
if($phonebook =~ /<phonebook/ and $phonebook =~ m,</phonebook>,) if($phonebook =~ /<phonebook/ and $phonebook =~ m,</phonebook>,)
{ {
if($phonebook =~ /<contact/ and $phonebook =~ /<realName>/ and $phonebook =~ /<number/) if($phonebook =~ /<contact/ and $phonebook =~ /<realName>/ and $phonebook =~ /<number/)
@ -1506,6 +1505,12 @@ sub FB_CALLMONITOR_parsePhonebook($$)
{ {
$contact_name = $1; $contact_name = $1;
if($contact =~ m,<uniqueid>(.+?)</uniqueid>,) {
$uniqueID = $1;
} else {
$uniqueID = "nil";
}
while($contact =~ m,<number[^>]*?type="([^<>"]+?)"[^<>]*?>([^<>"]+?)</number>,gs) while($contact =~ m,<number[^>]*?type="([^<>"]+?)"[^<>]*?>([^<>"]+?)</number>,gs)
{ {
if($1 ne "intern" and $1 ne "memo") if($1 ne "intern" and $1 ne "memo")
@ -1514,7 +1519,7 @@ sub FB_CALLMONITOR_parsePhonebook($$)
$count_contacts++; $count_contacts++;
FB_CALLMONITOR_Log $name, 5, "found $contact_name with number $number"; 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) 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 <your 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 # performs a HTTP based request via TR-064 port with authentication
sub FB_CALLMONITOR_requestHTTPviaTR064($$$$;$$) sub FB_CALLMONITOR_requestHTTPviaTR064($$$$;$$)
@ -2590,6 +2489,8 @@ sub FB_CALLMONITOR_sendKeepAlive($)
<br><br> <br><br>
After activating the Callmonitor-Support in your FritzBox, this module is able to 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. generate an event for each external call. Internal calls were not be detected by the Callmonitor.
<br>
It is recommendet to set the attribute fritzbox-user after defining the device.
<br><br> <br><br>
This module work with any FritzBox Fon model. This module work with any FritzBox Fon model.
<br><br> <br><br>
@ -2765,7 +2666,7 @@ sub FB_CALLMONITOR_sendKeepAlive($)
Default Value: <i>empty</i> (all phonebooks should be used, no exclusions)<br><br> Default Value: <i>empty</i> (all phonebooks should be used, no exclusions)<br><br>
<li><a name="fritzbox-user">fritzbox-user</a> &lt;username&gt;</li> <li><a name="fritzbox-user">fritzbox-user</a> &lt;username&gt;</li>
Use the given username to obtain the phonebook via network connection (see <a href="#fritzbox-remote-phonebook">fritzbox-remote-phonebook</a>). This attribute is only needed, if you use multiple users on your FritzBox.<br><br> Username for TR064 or other web-based access. The current FritzOS versions require a user name for login.<br><br>
<li><a name="apiKeySearchCh">apiKeySearchCh</a> &lt;API-Key&gt;</li> <li><a name="apiKeySearchCh">apiKeySearchCh</a> &lt;API-Key&gt;</li>
A private API key from <a href="https://tel.search.ch/api/getkey" target="_new">tel.search.ch</a> to perform a reverse search via search.ch (see attribute <a href=#reverse-search">reverse-search</a>). Without an API key, no reverse search via search.ch is not possible<br><br> A private API key from <a href="https://tel.search.ch/api/getkey" target="_new">tel.search.ch</a> to perform a reverse search via search.ch (see attribute <a href=#reverse-search">reverse-search</a>). Without an API key, no reverse search via search.ch is not possible<br><br>
@ -2832,6 +2733,8 @@ sub FB_CALLMONITOR_sendKeepAlive($)
Nach ca. 3 Sekunden kann man einfach wieder auflegen. Nun ist der Callmonitor aktiviert. Nach ca. 3 Sekunden kann man einfach wieder auflegen. Nun ist der Callmonitor aktiviert.
<br><br> <br><br>
Sobald der Callmonitor auf der Fritz!Box aktiviert wurde erzeugt das Modul entsprechende Events (s.u.) f&uuml;r alle externen Anrufe. Interne Anrufe werden nicht durch den Callmonitor erfasst. Sobald der Callmonitor auf der Fritz!Box aktiviert wurde erzeugt das Modul entsprechende Events (s.u.) f&uuml;r alle externen Anrufe. Interne Anrufe werden nicht durch den Callmonitor erfasst.
<br>
Es muss zwingend das Attribut fritzbox-user nach der Definition des Device gesetzt werden.
<br><br> <br><br>
Dieses Modul funktioniert mit allen Fritz!Box Modellen, welche Telefonie unterst&uuml;tzen (Namenszusatz: Fon). Dieses Modul funktioniert mit allen Fritz!Box Modellen, welche Telefonie unterst&uuml;tzen (Namenszusatz: Fon).
<br><br> <br><br>
@ -3015,7 +2918,9 @@ sub FB_CALLMONITOR_sendKeepAlive($)
Standardm&auml;&szlig;ig ist diese Funktion deaktiviert (alle Telefonb&uuml;cher werden eingelesen)<br><br> Standardm&auml;&szlig;ig ist diese Funktion deaktiviert (alle Telefonb&uuml;cher werden eingelesen)<br><br>
<li><a name="fritzbox-user">fritzbox-user</a> &lt;Username&gt;</li> <li><a name="fritzbox-user">fritzbox-user</a> &lt;Username&gt;</li>
Der Username, sofern das Telefonbuch direkt von der FritzBox via Netzwerk geladen werden soll (siehe Attribut: <a href="#fritzbox-remote-phonebook">fritzbox-remote-phonebook</a>). Dieses Attribut ist nur notwendig, wenn verschiedene Benutzernamen auf der FritzBox konfiguriert sind.<br><br> Benutzername für den TR064- oder einen anderen webbasierten Zugang. Die aktuellen FritzOS Versionen verlangen zwingend einen Benutzername f&uuml;r das Login.
<br><br>
<li><a name="apiKeySearchCh">apiKeySearchCh</a> &lt;API-Key&gt;</li> <li><a name="apiKeySearchCh">apiKeySearchCh</a> &lt;API-Key&gt;</li>
Der private API-Key von <a href="https://tel.search.ch/api/getkey" target="_new">tel.search.ch</a> um eine R&uuml;ckw&auml;rtssuche via search.ch durchzuf&uuml;hren (siehe Attribut <a href=#reverse-search">reverse-search</a>). Ohne einen solchen API-Key ist eine R&uuml;ckw&auml;rtssuche via search.ch nicht m&ouml;glich<br><br> Der private API-Key von <a href="https://tel.search.ch/api/getkey" target="_new">tel.search.ch</a> um eine R&uuml;ckw&auml;rtssuche via search.ch durchzuf&uuml;hren (siehe Attribut <a href=#reverse-search">reverse-search</a>). Ohne einen solchen API-Key ist eine R&uuml;ckw&auml;rtssuche via search.ch nicht m&ouml;glich<br><br>