From 70b06687ffe79f0be4c7fbabd8ab524f01f17215 Mon Sep 17 00:00:00 2001 From: jowiemann <> Date: Tue, 31 Jan 2023 12:47:21 +0000 Subject: [PATCH] 72_FB_CALLMONITOR: tellows.de integriert / commandREF git-svn-id: https://svn.fhem.de/fhem/trunk@27156 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/FHEM/72_FB_CALLMONITOR.pm | 2028 ++++++++++++++++++-------------- 1 file changed, 1158 insertions(+), 870 deletions(-) diff --git a/fhem/FHEM/72_FB_CALLMONITOR.pm b/fhem/FHEM/72_FB_CALLMONITOR.pm index 653208d42..37913c9e4 100755 --- a/fhem/FHEM/72_FB_CALLMONITOR.pm +++ b/fhem/FHEM/72_FB_CALLMONITOR.pm @@ -1,11 +1,14 @@ +############################################################### # $Id$ -############################################################################## +############################################################### # # 72_FB_CALLMONITOR.pm # Connects to a FritzBox Fon via network. # When a call is received or takes place it creates an event with further call informations. # This module has no sets or gets as it is only used for event triggering. # +# Additional Rating-Search from tellows.de (experimental) https://forum.fhem.de/index.php/topic,49603.0.html ### tellows +# # Copyright by Markus Bloch # e-mail: Notausstieg0309@googlemail.com # @@ -24,7 +27,7 @@ # You should have received a copy of the GNU General Public License # along with fhem. If not, see . # -############################################################################## +############################################################### package main; @@ -37,21 +40,82 @@ use HttpUtils; use DevIo; use FritzBoxUtils; +my $ModulVersion = "07.50.1"; +my %tellows = (); +my %connection_type = ( + 0 => "FON1", + 1 => "FON2", + 2 => "FON3", + 3 => "Callthrough", + 4 => "ISDN", + 5 => "FAX", + 6 => "Answering_Machine", -##################################### -sub -FB_CALLMONITOR_Initialize($) + 10 => "DECT_1", + 11 => "DECT_2", + 12 => "DECT_3", + 13 => "DECT_4", + 14 => "DECT_5", + 15 => "DECT_6", + + 20 => "VoIP_1", + 21 => "VoIP_2", + 22 => "VoIP_3", + 23 => "VoIP_4", + 24 => "VoIP_5", + 25 => "VoIP_6", + 26 => "VoIP_7", + 27 => "VoIP_8", + 28 => "VoIP_9", + 29 => "VoIP_10", + + 36 => "ISDN_data", + 37 => "FAX_data", + + 40 => "Answering_Machine_1", + 41 => "Answering_Machine_2", + 42 => "Answering_Machine_3", + 43 => "Answering_Machine_4", + 44 => "Answering_Machine_5" +); + + +####################################################################### +sub FB_CALLMONITOR_Log($$$) +{ + my ( $hash, $loglevel, $text ) = @_; + my $xline = ( caller(0) )[2]; + + my $xsubroutine = ( caller(1) )[3]; + my $sub = ( split( ':', $xsubroutine ) )[2]; + $sub =~ s/FB_CALLMONITOR_//; + + if ($loglevel <= 2) { + $text = "ERROR: " . $text; + } elsif ($loglevel >= 5) { + $text = "DEBUG: " . $text; + } else { + $text = "INFO: " . $text; + } + + my $instName = ( ref($hash) eq "HASH" ) ? $hash->{NAME} : $hash; + Log3 $hash, $loglevel, "FB_CALLMONITOR [$instName: $sub.$xline] - " . $text; +} +# End FB_CALLMONITOR_Log + +####################################################################### +sub FB_CALLMONITOR_Initialize($) { my ($hash) = @_; # Provider - $hash->{ReadFn} = "FB_CALLMONITOR_Read"; + $hash->{ReadFn} = "FB_CALLMONITOR_Read"; $hash->{ReadyFn} = "FB_CALLMONITOR_Ready"; $hash->{GetFn} = "FB_CALLMONITOR_Get"; $hash->{SetFn} = "FB_CALLMONITOR_Set"; $hash->{DefFn} = "FB_CALLMONITOR_Define"; - $hash->{RenameFn} = "FB_CALLMONITOR_Rename"; - $hash->{DeleteFn} = "FB_CALLMONITOR_Delete"; + $hash->{RenameFn} = "FB_CALLMONITOR_Rename"; + $hash->{DeleteFn} = "FB_CALLMONITOR_Delete"; $hash->{UndefFn} = "FB_CALLMONITOR_Undef"; $hash->{AttrFn} = "FB_CALLMONITOR_Attr"; $hash->{NotifyFn} = "FB_CALLMONITOR_Notify"; @@ -66,10 +130,12 @@ FB_CALLMONITOR_Initialize($) "answMachine-is-missed-call:0,1 ". "check-deflections:0,1 ". "reverse-search-cache-file ". - "reverse-search:sortable-strict,phonebook,textfile,dasoertliche.de,11880.com,search.ch,dasschnelle.at,herold.at ". + "reverse-search:sortable-strict,phonebook,textfile,tellows.de,dasoertliche.de,11880.com,search.ch,dasschnelle.at,herold.at ". "reverse-search-cache:0,1 ". "reverse-search-phonebook-file ". "reverse-search-text-file ". + "reverse-search-tellows-api-key ". + "reverse-search-tellows-api-partner ". "fritzbox-remote-phonebook:0,1 ". "fritzbox-remote-phonebook-via:web,tr064,telnet ". "fritzbox-remote-phonebook-exclude ". @@ -83,87 +149,87 @@ FB_CALLMONITOR_Initialize($) $readingFnAttributes; } -##################################### -sub -FB_CALLMONITOR_Define($$) +####################################################################### +sub FB_CALLMONITOR_Define($$) { - my ($hash, $def) = @_; - my @a = split("[ \t][ \t]*", $def); + my ($hash, $def) = @_; + my @a = split("[ \t][ \t]*", $def); - if(@a != 3) - { - my $msg = "wrong syntax: define FB_CALLMONITOR ip[:port]"; - Log 2, $msg; - return $msg; - } - - $hash->{NOTIFYDEV} = "global"; - - DevIo_CloseDev($hash); - delete($hash->{NEXT_OPEN}); - - my $dev = $a[2]; + if(@a != 3) + { + my $msg = "wrong syntax: define FB_CALLMONITOR ip[:port]"; + Log 2, $msg; + return $msg; + } - $dev .= ":1012" if($dev !~ m/:/ && $dev ne "none" && $dev !~ m/\@/); + my $name = $a[0]; - $hash->{DeviceName} = $dev; + $hash->{NAME} = $name; + $hash->{VERSION} = $ModulVersion; - return DevIo_OpenDev($hash, 0, undef, \&FB_CALLMONITOR_DevIoCallback) + $hash->{NOTIFYDEV} = "global"; + + DevIo_CloseDev($hash); + delete($hash->{NEXT_OPEN}); + + my $dev = $a[2]; + + $dev .= ":1012" if($dev !~ m/:/ && $dev ne "none" && $dev !~ m/\@/); + + $hash->{DeviceName} = $dev; + + return DevIo_OpenDev($hash, 0, undef, \&FB_CALLMONITOR_DevIoCallback) } -##################################### +####################################################################### # closing the connection on undefinition (shutdown/delete) -sub -FB_CALLMONITOR_Undef($$) +sub FB_CALLMONITOR_Undef($$) { my ($hash, $arg) = @_; - + RemoveInternalTimer($hash, "FB_CALLMONITOR_sendKeepAlive"); - DevIo_CloseDev($hash); - + DevIo_CloseDev($hash); + return undef; } -##################################### +####################################################################### # If Device is deleted, delete the password dataIf Device is renamed, copy the password data -sub -FB_CALLMONITOR_Delete($$) +sub FB_CALLMONITOR_Delete($$) { - my ($hash, $name) = @_; - - my $index = "FB_CALLMONITOR_".$name."_passwd"; - + my ($hash, $name) = @_; + + my $index = "FB_CALLMONITOR_".$name."_passwd"; + setKeyValue($index, undef); - + return undef; } -##################################### +####################################################################### # If Device is renamed, copy the password data -sub -FB_CALLMONITOR_Rename($$) +sub FB_CALLMONITOR_Rename($$) { - my ($new, $old) = @_; - - my $old_index = "FB_CALLMONITOR_".$old."_passwd"; - my $new_index = "FB_CALLMONITOR_".$new."_passwd"; - - my $old_key =getUniqueId().$old_index; - my $new_key =getUniqueId().$new_index; - + my ($new, $old) = @_; + + my $old_index = "FB_CALLMONITOR_" . $old . "_passwd"; + my $new_index = "FB_CALLMONITOR_" . $new . "_passwd"; + + my $old_key =getUniqueId() . $old_index; + my $new_key =getUniqueId() . $new_index; + my ($err, $old_pwd) = getKeyValue($old_index); - + return undef unless(defined($old_pwd)); - + setKeyValue($new_index, FB_CALLMONITOR_encrypt(FB_CALLMONITOR_decrypt($old_pwd,$old_key), $new_key)); setKeyValue($old_index, undef); } -##################################### +####################################################################### # Get function for returning a reverse search name -sub -FB_CALLMONITOR_Get($@) +sub FB_CALLMONITOR_Get($@) { my ($hash, @arguments) = @_; @@ -172,8 +238,8 @@ FB_CALLMONITOR_Get($@) if($arguments[1] eq "search" and int(@arguments) >= 3) { my $number = FB_CALLMONITOR_normalizePhoneNumber($hash, join '', @arguments[2..$#arguments]); - my $result = FB_CALLMONITOR_reverseSearch($hash, $number); - + my $result = FB_CALLMONITOR_reverseSearch($hash, $number, 1); + return $result if(defined($result)); return "no reverse search result found for $number"; } @@ -185,29 +251,29 @@ FB_CALLMONITOR_Get($@) foreach my $phonebookId (sort keys %{$hash->{helper}{PHONEBOOK_NAMES}}) { - my $string = sprintf("%-3s", $phonebookId)." - ".$hash->{helper}{PHONEBOOK_NAMES}{$phonebookId}; + my $string = sprintf("%-3s", $phonebookId)." - ".$hash->{helper}{PHONEBOOK_NAMES}{$phonebookId}; $width = length($string) if(length($string) > $width); $table .= $string."\n"; } - + return $head."\n".("-" x $width)."\n".$table; } elsif($arguments[1] eq "showPhonebookEntries" and (exists($hash->{helper}{PHONEBOOK}) or exists($hash->{helper}{PHONEBOOKS})) and int(@arguments) <= 3) { return "given argument is not a valid phonebook id: ".$arguments[2] if(int(@arguments) == 3 and ($arguments[2] !~ /^\d+$/ or !exists($hash->{helper}{PHONEBOOKS}{$arguments[2]}) ) ); - - my $return = ""; - + + my $return = ""; + if(exists($hash->{helper}{PHONEBOOKS})) { foreach my $pb_id (sort keys %{$hash->{helper}{PHONEBOOKS}}) { next if(int(@arguments) == 3 and int($arguments[2]) != $pb_id); - + my $number_width = 0; my $name_width = 0; my $table = ""; - + if(defined($hash->{helper}{PHONEBOOKS}{$pb_id}) and scalar(keys(%{$hash->{helper}{PHONEBOOKS}{$pb_id}})) > 0) { foreach my $number (keys %{$hash->{helper}{PHONEBOOKS}{$pb_id}}) @@ -215,118 +281,117 @@ FB_CALLMONITOR_Get($@) $number_width = length($number) if($number_width < length($number)); $name_width = length($hash->{helper}{PHONEBOOKS}{$pb_id}{$number}) if($name_width < length($hash->{helper}{PHONEBOOKS}{$pb_id}{$number})); } - - my $head = "Phonebook: ".$hash->{helper}{PHONEBOOK_NAMES}{$pb_id}." / Id: $pb_id\n\n ".sprintf("%-".$number_width."s %s" ,"Number", "Name"); - + + my $head = "Phonebook: ".$hash->{helper}{PHONEBOOK_NAMES}{$pb_id}." / Id: $pb_id\n\n ".sprintf("%-".$number_width."s %s" ,"Number", "Name"); + 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}); + my $string = sprintf(" %-".$number_width."s - %s" , $number,$hash->{helper}{PHONEBOOKS}{$pb_id}{$number}); $table .= $string."\n"; } - + $return .= $head."\n ".("-" x ($number_width + $name_width + 3))."\n".$table."\n"; } } } - + if(exists($hash->{helper}{PHONEBOOK}) and int(@arguments) == 2) { my $number_width = 0; my $name_width = 0; my $table = ""; - + foreach my $number (keys %{$hash->{helper}{PHONEBOOK}}) { $number_width = length($number) if($number_width < length($number)); $name_width = length($hash->{helper}{PHONEBOOK}{$number}) if($name_width < length($hash->{helper}{PHONEBOOK}{$number})); } - - my $head = sprintf("Phonebook file\n\n %-".$number_width."s %s" ,"Number", "Name"); - + + my $head = sprintf("Phonebook file\n\n %-".$number_width."s %s" ,"Number", "Name"); + foreach my $number (sort { lc($hash->{helper}{PHONEBOOK}{$a}) cmp lc($hash->{helper}{PHONEBOOK}{$b}) } keys %{$hash->{helper}{PHONEBOOK}}) { - my $string = sprintf(" %-".$number_width."s - %s" , $number,$hash->{helper}{PHONEBOOK}{$number}); + my $string = sprintf(" %-".$number_width."s - %s" , $number,$hash->{helper}{PHONEBOOK}{$number}); $table .= $string."\n"; } - + $return .= $head."\n ".("-" x ($number_width + $name_width + 3))."\n".$table } - + return $return; } elsif($arguments[1] eq "showCacheEntries" and exists($hash->{helper}{CACHE})) { my $table = ""; - + my $number_width = 0; my $name_width = 0; - + foreach my $number (keys %{$hash->{helper}{CACHE}}) { $number_width = length($number) if($number_width < length($number)); $name_width = length($hash->{helper}{CACHE}{$number}) if($name_width < length($hash->{helper}{CACHE}{$number})); } - - my $head = sprintf("%-".$number_width."s %s" ,"Number", "Name"); - + + my $head = sprintf("%-".$number_width."s %s" ,"Number", "Name"); + foreach my $number (sort { lc($hash->{helper}{CACHE}{$a}) cmp lc($hash->{helper}{CACHE}{$b}) } keys %{$hash->{helper}{CACHE}}) - { - my $string = sprintf("%-".$number_width."s - %s" , $number,$hash->{helper}{CACHE}{$number}); + { + my $string = sprintf("%-".$number_width."s - %s" , $number,$hash->{helper}{CACHE}{$number}); $table .= $string."\n"; } - + return $head."\n".("-" x ($number_width + $name_width + 3))."\n".$table; } elsif($arguments[1] eq "showTextfileEntries" and exists($hash->{helper}{TEXTFILE})) { my $table = ""; - + my $number_width = 0; my $name_width = 0; - + foreach my $number (keys %{$hash->{helper}{TEXTFILE}}) { $number_width = length($number) if($number_width < length($number)); $name_width = length($hash->{helper}{TEXTFILE}{$number}) if($name_width < length($hash->{helper}{TEXTFILE}{$number})); } - - my $head = sprintf("%-".$number_width."s %s" ,"Number", "Name"); - + + my $head = sprintf("%-".$number_width."s %s" ,"Number", "Name"); + foreach my $number (sort { lc($hash->{helper}{TEXTFILE}{$a}) cmp lc($hash->{helper}{TEXTFILE}{$b}) } keys %{$hash->{helper}{TEXTFILE}}) { - my $string = sprintf("%-".$number_width."s - %s" , $number,$hash->{helper}{TEXTFILE}{$number}); + my $string = sprintf("%-".$number_width."s - %s" , $number,$hash->{helper}{TEXTFILE}{$number}); $table .= $string."\n"; } - + return $head."\n".("-" x ($number_width + $name_width + 3))."\n".$table; } else { - return "unknown argument ".$arguments[1].", choose one of search".(exists($hash->{helper}{PHONEBOOK_NAMES}) ? " showPhonebookIds" : ""). + return "unknown argument ".$arguments[1].", choose one of search".(exists($hash->{helper}{PHONEBOOK_NAMES}) ? " showPhonebookIds:noArg" : ""). ((exists($hash->{helper}{PHONEBOOK}) or exists($hash->{helper}{PHONEBOOKS})) ? " showPhonebookEntries" : ""). - (exists($hash->{helper}{CACHE}) ? " showCacheEntries" : ""). - (exists($hash->{helper}{TEXTFILE}) ? " showTextfileEntries" : ""); + (exists($hash->{helper}{CACHE}) ? " showCacheEntries:noArg" : ""). + (exists($hash->{helper}{TEXTFILE}) ? " showTextfileEntries:noArg" : ""); } } -##################################### +####################################################################### # Set function for executing a reread of the internal phonebook -sub -FB_CALLMONITOR_Set($@) +sub FB_CALLMONITOR_Set($@) { my ($hash, @a) = @_; my $name = $hash->{NAME}; my $usage; my @sets = (); - - push @sets, "rereadPhonebook" if(defined($hash->{helper}{PHONEBOOK}) or AttrVal($name, "reverse-search" , "") =~ /(all|phonebook|internal)/); - push @sets, "rereadCache" if(defined(AttrVal($name, "reverse-search-cache-file" , undef))); - push @sets, "rereadTextfile" if(defined(AttrVal($name, "reverse-search-text-file" , undef))); + + push @sets, "rereadPhonebook:noArg" if(defined($hash->{helper}{PHONEBOOK}) or AttrVal($name, "reverse-search" , "") =~ /(all|phonebook|internal)/); + push @sets, "rereadCache:noArg" if(defined(AttrVal($name, "reverse-search-cache-file" , undef))); + push @sets, "rereadTextfile:noArg" if(defined(AttrVal($name, "reverse-search-text-file" , undef))); push @sets, "password" if($hash->{helper}{PWD_NEEDED}); - push @sets, "reopen" if($hash->{FD}); - + push @sets, "reopen:noArg" if($hash->{FD}); + $usage = "Unknown argument ".$a[1].", choose one of ".join(" ", @sets) if(scalar @sets > 0); - + if($a[1] eq "rereadPhonebook") { FB_CALLMONITOR_readPhonebook($hash); @@ -345,7 +410,7 @@ FB_CALLMONITOR_Set($@) elsif($a[1] eq "password") { return FB_CALLMONITOR_storePassword($hash, $a[2]) if($hash->{helper}{PWD_NEEDED}); - Log3 $name, 2, "FB_CALLMONITOR ($name) - SOMEONE UNWANTED TRIED TO SET A NEW FRITZBOX PASSWORD!!!"; + FB_CALLMONITOR_Log $name, 2, "SOMEONE UNWANTED TRIED TO SET A NEW FRITZBOX PASSWORD!!!"; return "I didn't ask for a password, so go away!!!" } elsif($a[1] eq "reopen") @@ -361,99 +426,61 @@ FB_CALLMONITOR_Set($@) } -##################################### +####################################################################### # Receives an event and creates several readings for event triggering -sub -FB_CALLMONITOR_Read($) +sub FB_CALLMONITOR_Read($) { my ($hash) = @_; - my %connection_type = ( - 0 => "FON1", - 1 => "FON2", - 2 => "FON3", - 3 => "Callthrough", - 4 => "ISDN", - 5 => "FAX", - 6 => "Answering_Machine", - - 10 => "DECT_1", - 11 => "DECT_2", - 12 => "DECT_3", - 13 => "DECT_4", - 14 => "DECT_5", - 15 => "DECT_6", - - 20 => "VoIP_1", - 21 => "VoIP_2", - 22 => "VoIP_3", - 23 => "VoIP_4", - 24 => "VoIP_5", - 25 => "VoIP_6", - 26 => "VoIP_7", - 27 => "VoIP_8", - 28 => "VoIP_9", - 29 => "VoIP_10", - - 36 => "ISDN_data", - 37 => "FAX_data", - - 40 => "Answering_Machine_1", - 41 => "Answering_Machine_2", - 42 => "Answering_Machine_3", - 43 => "Answering_Machine_4", - 44 => "Answering_Machine_5" - ); - my $received = DevIo_SimpleRead($hash); my $buffer = $hash->{PARTIAL}; - + return "" if(!defined($received) or IsDisabled($hash->{NAME})); - + my $name = $hash->{NAME}; my @array; - + my $area_code = AttrVal($name, "local-area-code", ""); my $country_code = AttrVal($name, "country-code", "0049"); - + $buffer .= $received; - + while($buffer =~ m/\n/) { my $data; - + ($data, $buffer) = split("\n", $buffer, 2); - + chomp $data; - + my $external_number = undef; my $reverse_search = undef; - Log3 $name, 5, "FB_CALLMONITOR ($name) - received data: $data"; - + FB_CALLMONITOR_Log $name, 5, "received data: $data"; + @array = split(";", $data); - + $external_number = $array[3] if(not $array[3] eq "0" and $array[1] eq "RING" and $array[3] ne ""); $external_number = $array[5] if($array[1] eq "CALL" and $array[3] ne ""); - - Log3 $name, 4, "FB_CALLMONITOR ($name) - received event ".$array[1]." for call id ".$array[2].(defined($external_number) ? " (external number: $external_number)" : ""); - + + FB_CALLMONITOR_Log $name, 4, "received event ".$array[1]." for call id ".$array[2].(defined($external_number) ? " (external number: $external_number)" : ""); + if(defined($external_number)) { $external_number =~ s/^0// if(AttrVal($name, "remove-leading-zero", "0") eq "1"); - + if($array[1] eq "CALL") { # Remove Call-By-Call number (Germany) $external_number =~ s/^(010[1-9]\d|0100[1-9]\d)//g if($country_code eq "0049"); - + # Remove Call-By-Call number (Austria) $external_number =~ s/^10\d\d//g if($country_code eq "0043"); - + # Remove Call-By-Call number (Swiss) $external_number =~ s/^(107\d\d|108\d\d)//g if($country_code eq "0041"); } - + if($external_number =~ /^\d/ and $external_number !~ /^0/ and $external_number !~ /^11/ and $area_code ne "") { if($area_code =~ /^0[1-9]\d+$/ and $external_number =~ /^[1-9].+$/) @@ -462,22 +489,23 @@ FB_CALLMONITOR_Read($) } elsif($area_code !~ /^0[1-9]\d+$/) { - Log3 $name, 2, "FB_CALLMONITOR ($name) - given local area code '$area_code' is not an area code. therefore will be ignored"; + FB_CALLMONITOR_Log $name, 2, "given local area code '$area_code' is not an area code. therefore will be ignored"; } } - + # Remove trailing hash sign and everything afterwards $external_number =~ s/#.*$// if($external_number !~ /^\*/); # Forum #85761 - - $reverse_search = FB_CALLMONITOR_reverseSearch($hash, $external_number) if(AttrVal($name, "reverse-search", "none") ne "none"); - - Log3 $name, 4, "FB_CALLMONITOR ($name) - reverse search returned: $reverse_search" if(defined($reverse_search)); + + $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($array[1] =~ /^CALL|RING$/) { delete($hash->{helper}{TEMP}{$array[2]}); - + if(AttrVal($name, "unique-call-ids", "0") eq "1") { $hash->{helper}{TEMP}{$array[2]}{call_id} = Digest::MD5::md5_hex($data); @@ -490,41 +518,58 @@ FB_CALLMONITOR_Read($) $hash->{helper}{TEMP}{$array[2]}{external_number} = (defined($external_number) ? $external_number : "unknown"); $hash->{helper}{TEMP}{$array[2]}{external_name} = (defined($reverse_search) ? $reverse_search : "unknown"); $hash->{helper}{TEMP}{$array[2]}{internal_number} = $array[4]; - + if(my $contact_image = FB_CALLMONITOR_getContactImage($hash, $hash->{helper}{TEMP}{$array[2]}{external_number})) { $hash->{helper}{TEMP}{$array[2]}{contact_image} = $contact_image; - } - + } + if(FB_CALLMONITOR_checkNumberIsFiltered($hash, $hash->{helper}{TEMP}{$array[2]}{internal_number})) { - $hash->{helper}{TEMP}{$array[2]}{".filtered"} = 1 + $hash->{helper}{TEMP}{$array[2]}{".filtered"} = 1 } } - + if($array[1] eq "CALL") { $hash->{helper}{TEMP}{$array[2]}{external_connection} = $array[6]; - $hash->{helper}{TEMP}{$array[2]}{".internal_connection_id"} = $array[3]; + $hash->{helper}{TEMP}{$array[2]}{internal_connection} = $connection_type{$array[3]} if(defined($connection_type{$array[3]})); $hash->{helper}{TEMP}{$array[2]}{direction} = "outgoing"; } - + if($array[1] eq "RING") { $hash->{helper}{TEMP}{$array[2]}{external_connection} = $array[5]; $hash->{helper}{TEMP}{$array[2]}{direction} = "incoming"; $hash->{helper}{TEMP}{$array[2]}{".deflected"} = FB_CALLMONITOR_checkNumberForDeflection($hash, $external_number); + + my @attr_list = split(/,|\|/, AttrVal($name, "reverse-search", "")); + + ### tellows only if enabled + if (grep { /^(tellows\.de)$/ } @attr_list) { + $hash->{helper}{TEMP}{$array[2]}{tellows_score} = (defined($tellows{score}) ? $tellows{score} : "unknown"); ### tellows + $hash->{helper}{TEMP}{$array[2]}{tellows_searches} = (defined($tellows{searches}) ? $tellows{searches} : "unknown"); ### tellows + $hash->{helper}{TEMP}{$array[2]}{tellows_comments} = (defined($tellows{comments}) ? $tellows{comments} : "unknown"); ### tellows + $hash->{helper}{TEMP}{$array[2]}{tellows_scoreColor} = (defined($tellows{scoreColor}) ? $tellows{scoreColor} : "unknown"); ### tellows + $hash->{helper}{TEMP}{$array[2]}{tellows_scorePath} = (defined($tellows{scorePath}) ? $tellows{scorePath} : "unknown"); ### tellows + $hash->{helper}{TEMP}{$array[2]}{tellows_location} = (defined($tellows{location}) ? $tellows{location} : "unknown"); ### tellows + $hash->{helper}{TEMP}{$array[2]}{tellows_country} = (defined($tellows{country}) ? $tellows{country} : "unknown"); ### tellows + $hash->{helper}{TEMP}{$array[2]}{tellows_mostCritic} = (defined($tellows{mostCritic}) ? $tellows{mostCritic} : "unknown"); ### tellows + $hash->{helper}{TEMP}{$array[2]}{tellows_mostCriticCount} = (defined($tellows{mostCriticCount}) ? $tellows{mostCriticCount} : "unknown"); ### tellows + $hash->{helper}{TEMP}{$array[2]}{tellows_text} = (defined($tellows{text}) ? $tellows{text} : "unknown"); ### tellows + } } - - if($array[1] eq "CONNECT" and not exists($hash->{helper}{TEMP}{$array[2]}{".internal_connection_id"})) + + if($array[1] eq "CONNECT" and not exists($hash->{helper}{TEMP}{$array[2]}{internal_connection})) { - $hash->{helper}{TEMP}{$array[2]}{".internal_connection_id"} = $array[3]; - } - + $hash->{helper}{TEMP}{$array[2]}{internal_connection} = $connection_type{$array[3]} if(defined($connection_type{$array[3]})); + $hash->{helper}{TEMP}{$array[2]}{".internal_connection_id"} = $array[3] if(defined($connection_type{$array[3]})); + } + if($array[1] eq "DISCONNECT") { $hash->{helper}{TEMP}{$array[2]}{call_duration} = $array[3]; - + if(exists($hash->{helper}{TEMP}{$array[2]}{direction}) and $hash->{helper}{TEMP}{$array[2]}{direction} eq "incoming") { if(($hash->{helper}{TEMP}{$array[2]}{".last-event"} eq "RING") or (AttrVal($name, "answMachine-is-missed-call", "0") eq "1" and exists($hash->{helper}{TEMP}{$array[2]}{internal_connection}) and $hash->{helper}{TEMP}{$array[2]}{".internal_connection_id"} =~/^4[0-4]$/)) @@ -532,122 +577,126 @@ FB_CALLMONITOR_Read($) $hash->{helper}{TEMP}{$array[2]}{missed_call} = $hash->{helper}{TEMP}{$array[2]}{external_number}.(exists($hash->{helper}{TEMP}{$array[2]}{external_name}) and $hash->{helper}{TEMP}{$array[2]}{external_name} ne "unknown" ? " (".$hash->{helper}{TEMP}{$array[2]}{external_name}.")" : ""); } } - } - - if($array[1] eq "CONNECT" or $array[1] eq "CALL") - { - my $connection_id = $hash->{helper}{TEMP}{$array[2]}{".internal_connection_id"}; - - if(defined($connection_type{$connection_id})) { - $hash->{helper}{TEMP}{$array[2]}{internal_connection} = $connection_type{$connection_id} - } - else - { - $hash->{helper}{TEMP}{$array[2]}{internal_connection} = $connection_id; - Log3 $name, 3 , "FB_CALLMONITOR ($name) - internal connection value '".$connection_id."' not known. Please report this value to FHEM community together with a description how exactly you have taken this call (via VoIP/ISDN/FON/DECT/...)" - } } - + $hash->{helper}{TEMP}{$array[2]}{".last-event"} = $array[1]; - + # skip readings/event generation if call does not matched a configured internal number filter if($hash->{helper}{TEMP}{$array[2]}{".filtered"}) { - Log3 $name, 4, "FB_CALLMONITOR ($name) - skipped creating readings/events because number does not match configured attribute internal-number-filter"; - + FB_CALLMONITOR_Log $name, 4, "skipped creating readings/events because number does not match configured attribute internal-number-filter"; + if($array[1] eq "DISCONNECT") { delete($hash->{helper}{TEMP}{$array[2]}); - } - + } + next; } - + # skip readings/event generation if call is deflected if($hash->{helper}{TEMP}{$array[2]}{".deflected"}) { - Log3 $name, 4, "FB_CALLMONITOR ($name) - skipped creating readings/events due to deflection match"; - + FB_CALLMONITOR_Log $name, 4, "skipped creating readings/events due to deflection match"; + if($array[1] eq "DISCONNECT") { delete($hash->{helper}{TEMP}{$array[2]}); - } - + } + next; } - + # create readings/events readingsBeginUpdate($hash); readingsBulkUpdate($hash, "event", lc($array[1])); - + foreach my $key (keys %{$hash->{helper}{TEMP}{$array[2]}}) { readingsBulkUpdate($hash, $key, $hash->{helper}{TEMP}{$array[2]}{$key}) unless($key =~ /^\./); } - + if($array[1] eq "DISCONNECT") { delete($hash->{helper}{TEMP}{$array[2]}); - } + } readingsBulkUpdate($hash, "calls_count", scalar grep { not ($hash->{helper}{TEMP}{$_}{".filtered"} or $hash->{helper}{TEMP}{$_}{".deflected"}) } keys %{$hash->{helper}{TEMP}}); readingsEndUpdate($hash, 1); } - + $hash->{PARTIAL} = $buffer; } -##################################### +####################################################################### # catches error message during connection setup -sub -FB_CALLMONITOR_DevIoCallback($$) +sub FB_CALLMONITOR_DevIoCallback($$) { my ($hash, $err) = @_; my $name = $hash->{NAME}; - + if($err) { - Log3 $name, 4, "FB_CALLMONITOR ($name) - unable to connect to Fritz!Box: $err"; + FB_CALLMONITOR_Log $name, 4, "unable to connect to Fritz!Box: $err"; } } -##################################### +####################################################################### # Reconnects to FritzBox in case of disconnects -sub -FB_CALLMONITOR_Ready($) +sub FB_CALLMONITOR_Ready($) { my ($hash) = @_; - + return DevIo_OpenDev($hash, 1, undef, \&FB_CALLMONITOR_DevIoCallback); } -##################################### +####################################################################### # Handles Attribute Changes -sub -FB_CALLMONITOR_Attr($@) +sub FB_CALLMONITOR_Attr($@) { my ($cmd, $name, $attrib, $value) = @_; my $hash = $defs{$name}; - + if($cmd eq "set") - { - if((($attrib eq "reverse-search" and $value =~ /phonebook/) or $attrib eq "reverse-search-phonebook-file" or $attrib eq "fritzbox-remote-phonebook") and $init_done) + { + if((($attrib eq "reverse-search" and $value =~ /phonebook|tellows/) or $attrib eq "reverse-search-phonebook-file" or $attrib eq "fritzbox-remote-phonebook") and $init_done) { - $attr{$name}{$attrib} = $value; - return FB_CALLMONITOR_readPhonebook($hash); + if($value =~ /tellows/) { + if ($attr{$name}{"reverse-search-tellows-api-key"} && $attr{$name}{"reverse-search-tellows-api-partner"}) { + my $result = GetFileFromURL("http://www.tellows.de/basic/num/0221?xml=1&partner=".AttrVal($name, "reverse-search-tellows-api-partner","")."&apikey=".AttrVal($name,"reverse-search-tellows-api-key",""), 5); + + if($result =~ /ERROR(.*?)/) { + return "tellows: $1"; + } + if(not defined($result)){ + return "tellows api and/or api-partner not valid"; + } + } else { + return "tellows api-key and/or api-partner not defined."; + } + } else { + foreach (keys %{ $hash->{READINGS} }) { + readingsDelete($hash, $_) if $_ =~ /^tellows_/ && defined $hash->{READINGS}{$_}{VAL}; + } + } + + if($value =~ /phonebook/) { + $attr{$name}{$attrib} = $value; + return FB_CALLMONITOR_readPhonebook($hash); + } } - + if($attrib eq "reverse-search-cache-file") { return FB_CALLMONITOR_loadCacheFile($hash, $value); } - + if($attrib eq "reverse-search-text-file") { return FB_CALLMONITOR_loadTextFile($hash, $value); } - + if($attrib eq "disable" and $value eq "1") { DevIo_CloseDev($hash); @@ -658,59 +707,63 @@ FB_CALLMONITOR_Attr($@) { DevIo_OpenDev($hash, 0, undef, \&FB_CALLMONITOR_DevIoCallback); } - + if($attrib eq "sendKeepAlives" and $value !~ /^none|(?:5|10|15|30)m|1h$/) { return "invalid value $value for $attrib. Allowed values are: none,5m,10m,15m,30m,1h"; } - + if($attrib eq "internal-number-filter") { if($value !~ /^\d+(?:,\d+)*$/) { return 'invalid value $value for $attrib. It should contain a single internal number or a comma separated list of multiple internal numbers. (e.g. "12345" or "12345,56789")'; } - + delete($hash->{helper}{INTERNAL_FILTER}); foreach my $item (split("[ \t,][ \t,]*",$value)) { $hash->{helper}{INTERNAL_FILTER}{$item} = 1; } - } + } } elsif($cmd eq "del") { if($attrib eq "reverse-search" or $attrib eq "reverse-search-phonebook-file") { - delete($hash->{helper}{PHONEBOOK}); - } - + delete($hash->{helper}{PHONEBOOK}); + + foreach (keys %{ $hash->{READINGS} }) { + readingsDelete($hash, $_) if $_ =~ /^tellows_/ && defined $hash->{READINGS}{$_}{VAL}; + } + } + if($attrib eq "reverse-search-cache") { delete($hash->{helper}{CACHE}); - } - + } + if($attrib eq "reverse-search-text-file") { delete($hash->{helper}{TEXTFILE}); } - + if($attrib eq "internal-number-filter") { delete($hash->{helper}{INTERNAL_FILTER}); } - + if($attrib eq "disable") { DevIo_OpenDev($hash, 0, undef, \&FB_CALLMONITOR_DevIoCallback); } } - + return undef; } -##################################### +####################################################################### # receives events, waits for global INITIALIZED or REREADCFG # to initiate the phonebook initialization sub @@ -718,112 +771,136 @@ FB_CALLMONITOR_Notify($$) { my ($hash, $device) = @_; my $name = $hash->{NAME}; - + my $events = deviceEvents($device, undef); - + return if($device->{NAME} ne "global"); - + FB_CALLMONITOR_sendKeepAlive($hash) if(grep(m/(?:DELETE)?ATTR $name sendKeepAlives/, @{$events})); - + return if(!grep(m/^INITIALIZED|REREADCFG$/, @{$events})); - + FB_CALLMONITOR_readPhonebook($hash); - + return undef; } -############################################################################################################ +####################################################################### # # Begin of helper functions # -############################################################################################################ +####################################################################### -##################################### +####################################################################### # Performs a reverse search of a phone number -sub -FB_CALLMONITOR_reverseSearch($$) -{ - my ($hash, $number) = @_; - my $name = $hash->{NAME}; - my $result; - my $status; - my $invert_match = undef; - my $country_code = AttrVal($name, "country-code", "0049"); - my @attr_list = split(/,|\|/, AttrVal($name, "reverse-search", "")); - - foreach my $method (@attr_list) - { - # Using internal phonebook if available and enabled - if($method eq "phonebook") - { - if(exists($hash->{helper}{PHONEBOOK})) - { - if(defined($hash->{helper}{PHONEBOOK}{$number})) - { - Log3 $name, 4, "FB_CALLMONITOR ($name) - using internal phonebook for reverse search of $number"; - return $hash->{helper}{PHONEBOOK}{$number}; - } - elsif(my $result = FB_CALLMONITOR_searchPhonebookWildcards($hash->{helper}{PHONEBOOK}, $number)) - { - Log3 $name, 4, "FB_CALLMONITOR ($name) - using internal phonebook for reverse search of $number"; - return $result; - } - } - - if(exists($hash->{helper}{PHONEBOOKS})) - { - foreach my $pb_id (keys %{$hash->{helper}{PHONEBOOKS}}) - { - if(defined($hash->{helper}{PHONEBOOKS}{$pb_id}{$number})) - { - Log3 $name, 4, "FB_CALLMONITOR ($name) - using internal phonebook for reverse search of $number"; - return $hash->{helper}{PHONEBOOKS}{$pb_id}{$number}; - } - elsif(my $result = FB_CALLMONITOR_searchPhonebookWildcards($hash->{helper}{PHONEBOOKS}{$pb_id}, $number)) - { - Log3 $name, 4, "FB_CALLMONITOR ($name) - using internal phonebook for reverse search of $number"; - return $result; - } - } - } - } +sub FB_CALLMONITOR_reverseSearch($$$) { + my ($hash, $number, $ring) = @_; + my $name = $hash->{NAME}; + my $result; + my $status; + my $invert_match = undef; + my $country_code = AttrVal($name, "country-code", "0049"); + my @attr_list = split(/,|\|/, AttrVal($name, "reverse-search", "")); - # Using user defined textfile - elsif($method eq "textfile") - { - if(exists($hash->{helper}{TEXTFILE}) and defined($hash->{helper}{TEXTFILE}{$number})) - { - Log3 $name, 4, "FB_CALLMONITOR ($name) - using textfile for reverse search of $number"; - return $hash->{helper}{TEXTFILE}{$number}; - } - } - - else - { - # Using Cache if enabled - if(AttrVal($name, "reverse-search-cache", "0") eq "1" and defined($hash->{helper}{CACHE}{$number})) - { - Log3 $name, 4, "FB_CALLMONITOR ($name) - using cache for reverse search of $number"; - if($hash->{helper}{CACHE}{$number} ne "timeout" or $hash->{helper}{CACHE}{$number} ne "unknown") - { - return $hash->{helper}{CACHE}{$number}; - } - } + foreach my $method (@attr_list) { - # Ask dasoertliche.de - if($method eq "dasoertliche.de") + FB_CALLMONITOR_Log $name, 4, "methode: $method"; + + # Ask tellows.de at first + if($method eq "tellows.de" and $ring == 1) { + + FB_CALLMONITOR_Log $name, 4, "reverse search for $number at tellows.de."; + unless (AttrVal($name, "reverse-search-tellows-api-key", undef) || AttrVal($name, "reverse-search-tellows-api-partner", undef)) { + FB_CALLMONITOR_Log $name, 4, "reverse search cancled for $number at tellows.de."; + $status = "login missing"; + } else { + $result = FB_CALLMONITOR_tellowsRating($hash, $number); ### tellows !!! $external_number --> $number !!! + + if(not defined($result)) { + if(AttrVal($name, "reverse-search-cache", "0") eq "1") { + $status = "timeout"; + undef($result); + } + } else { + #Debug($result); + if( $result =~ /([^"].*?){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}; + } 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; + } + } + + if(exists($hash->{helper}{PHONEBOOKS})) { + 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}; + } 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; + } + } + } + } + + # Using user defined textfile + elsif($method eq "textfile") + { + if(exists($hash->{helper}{TEXTFILE}) and defined($hash->{helper}{TEXTFILE}{$number})) + { + FB_CALLMONITOR_Log $name, 4, "using textfile for reverse search of $number"; + return $hash->{helper}{TEXTFILE}{$number}; + } + } + + else { + + # Using Cache if enabled + if(AttrVal($name, "reverse-search-cache", "0") eq "1" and defined($hash->{helper}{CACHE}{$number})) + { + FB_CALLMONITOR_Log $name, 4, "using cache for reverse search of $number"; + if($hash->{helper}{CACHE}{$number} ne "timeout" or $hash->{helper}{CACHE}{$number} ne "unknown") { + return $hash->{helper}{CACHE}{$number}; + } + } + + # Ask dasoertliche.de + if($method eq "dasoertliche.de") + { unless(($number =~ /^0?[1-9]/ and $country_code eq "0049") or $number =~ /^0049/) { - Log3 $name, 4, "FB_CALLMONITOR ($name) - skip using dasoertliche.de for reverse search of $number because of non-german number"; + FB_CALLMONITOR_Log $name, 4, "skip using dasoertliche.de for reverse search of $number because of non-german number"; } else - { + { $number =~ s/^0049/0/; # remove country code - Log3 $name, 4, "FB_CALLMONITOR ($name) - using dasoertliche.de for reverse search of $number"; + FB_CALLMONITOR_Log $name, 4, "using dasoertliche.de for reverse search of $number"; - $result = GetFileFromURL("https://www.dasoertliche.de/?form_name=search_inv&ph=".$number, 5, undef, 1); + $result = GetFileFromURL("http://www1.dasoertliche.de/?form_name=search_inv&ph=".$number, 5, undef, 1); if(not defined($result)) { if(AttrVal($name, "reverse-search-cache", "0") eq "1") @@ -835,7 +912,7 @@ FB_CALLMONITOR_reverseSearch($$) else { #Debug($result); - if($result =~ m,\@type":.+?"name":"(.+?)",) + if($result =~ m,(.+?),) { $invert_match = $1; $invert_match = FB_CALLMONITOR_html2txt($invert_match); @@ -845,31 +922,31 @@ FB_CALLMONITOR_reverseSearch($$) } elsif(not $result =~ /wir konnten keine Treffer finden/) { - Log3 $name, 3, "FB_CALLMONITOR ($name) - the reverse search result for $number could not be extracted from dasoertliche.de. Please contact the FHEM community."; + FB_CALLMONITOR_Log $name, 3, "the reverse search result for $number could not be extracted from dasoertliche.de. Please contact the FHEM community."; } - + $status = "unknown"; } } } - + # Ask 11880.com elsif($method eq "11880.com") { unless(($number =~ /^0?[1-9]/ and $country_code eq "0049") or $number =~ /^0049/) { - Log3 $name, 4, "FB_CALLMONITOR ($name) - skip using 11880.com for reverse search of $number because of non-german number"; + FB_CALLMONITOR_Log $name, 4, "skip using 11880.com for reverse search of $number because of non-german number"; } else - { + { $number =~ s/^0049/0/; # remove country code - Log3 $name, 4, "FB_CALLMONITOR ($name) - using 11880.com for reverse search of $number"; + FB_CALLMONITOR_Log $name, 4, "using 11880.com for reverse search of $number"; $result = GetFileFromURL("https://www.11880.com/suche/".$number."/deutschland", 5, undef, 1); - + if(not defined($result)) - { - Log3 $name, 4, "FB_CALLMONITOR ($name) - unable to retrieve result for reverse search of $number via $method"; + { + FB_CALLMONITOR_Log $name, 4, "unable to retrieve result for reverse search of $number via $method"; if(AttrVal($name, "reverse-search-cache", "0") eq "1") { $status = "timeout"; @@ -889,37 +966,37 @@ FB_CALLMONITOR_reverseSearch($$) } elsif(not $result =~ /Leider nichts gefunden/i) { - Log3 $name, 3, "FB_CALLMONITOR ($name) - the reverse search result for $number could not be extracted from 11880.com. Please contact the FHEM community."; + FB_CALLMONITOR_Log $name, 3, "the reverse search result for $number could not be extracted from 11880.com. Please contact the FHEM community."; } - + $status = "unknown"; } } } - + # SWITZERLAND ONLY!!! Ask search.ch elsif($method eq "search.ch") { unless(($number =~ /^0?[1-9]/ and $country_code eq "0041") or $number =~ /^0041/) { - Log3 $name, 4, "FB_CALLMONITOR ($name) - skip using search.ch for reverse search of $number because of non-swiss number"; + FB_CALLMONITOR_Log $name, 4, "skip using search.ch for reverse search of $number because of non-swiss number"; } else - { + { my $api_key = AttrVal($name, "apiKeySearchCh", undef); - + unless(defined($api_key)) { - Log3 $name, 1, "FB_CALLMONITOR ($name) - WARNING! no API key for swiss.ch configured. Please obtain an API key from https://tel.search.ch/api/getkey and set attribute apiKeySearchCh with your key"; - - # use old key - Log3 $name, 1, "FB_CALLMONITOR ($name) - using generic API key for reverse search via search.ch. WILL BE REMOVED IN A FUTURE RELEASE"; + FB_CALLMONITOR_Log $name, 1, "WARNING! no API key for swiss.ch configured. Please obtain an API key from https://tel.search.ch/api/getkey and set attribute apiKeySearchCh with your key"; + + # use old key + FB_CALLMONITOR_Log $name, 1, "using generic API key for reverse search via search.ch. WILL BE REMOVED IN A FUTURE RELEASE"; $api_key = "b0b1207cb7c9d0048867de887aa9a4fd"; } - + $number =~ s/^0041/0/; # remove country code - - Log3 $name, 4, "FB_CALLMONITOR ($name) - using search.ch for reverse search of $number"; + + FB_CALLMONITOR_Log $name, 4, "using search.ch for reverse search of $number"; $result = GetFileFromURL("http://tel.search.ch/api/?key=".urlEncode($api_key)."&maxnum=1&was=".$number, 5, undef, 1); if(not defined($result)) @@ -936,30 +1013,30 @@ FB_CALLMONITOR_reverseSearch($$) if($result =~ m,(.+?),s) { my $xml = $1; - + $invert_match = ""; - + if($xml =~ m,(.+?),) { $invert_match .= $1; } - + if($xml =~ m,(.+?),) { $invert_match .= " $1"; } - + if($xml =~ m,(.+?),) { $invert_match .= ", $1"; } - + $invert_match = FB_CALLMONITOR_html2txt($invert_match); FB_CALLMONITOR_writeToCache($hash, $number, $invert_match); undef($result); return $invert_match; } - + $status = "unknown"; } } @@ -970,12 +1047,12 @@ FB_CALLMONITOR_reverseSearch($$) { unless(($number =~ /^0?[1-9]/ and $country_code eq "0043") or $number =~ /^0043/) { - Log3 $name, 4, "FB_CALLMONITOR ($name) - skip using dasschnelle.at for reverse search of $number because of non-austrian number"; + FB_CALLMONITOR_Log $name, 4, "skip using dasschnelle.at for reverse search of $number because of non-austrian number"; } else - { + { $number =~ s/^0043/0/; # remove country code - Log3 $name, 4, "FB_CALLMONITOR ($name) - using dasschnelle.at for reverse search of $number"; + FB_CALLMONITOR_Log $name, 4, "using dasschnelle.at for reverse search of $number"; $result = GetFileFromURL("http://www.dasschnelle.at/ergebnisse?what=".$number."&where=&rubrik=0&bezirk=0&orderBy=Standard&mapsearch=false", 5, undef, 1); if(not defined($result)) @@ -1005,31 +1082,31 @@ FB_CALLMONITOR_reverseSearch($$) } elsif(not $result =~ /Ihre Suche nach .* war erfolglos/) { - Log3 $name, 3, "FB_CALLMONITOR ($name) - the reverse search result for $number could not be extracted from dasschnelle.at. Please contact the FHEM community."; + FB_CALLMONITOR_Log $name, 3, "the reverse search result for $number could not be extracted from dasschnelle.at. Please contact the FHEM community."; } - + $status = "unknown"; } } } - + # Austria ONLY!!! Ask herold.at elsif($method eq "herold.at") { unless(($number =~ /^0?[1-9]/ and $country_code eq "0043") or $number =~ /^0043/) { - Log3 $name, 4, "FB_CALLMONITOR ($name) - skip using herold.at for reverse search of $number because of non-austrian number"; + FB_CALLMONITOR_Log $name, 4, "skip using herold.at for reverse search of $number because of non-austrian number"; } else - { + { $number =~ s/^0043/0/; # remove country code - Log3 $name, 4, "FB_CALLMONITOR ($name) - using herold.at for reverse search of $number"; + FB_CALLMONITOR_Log $name, 4, "using herold.at for reverse search of $number"; $result = GetFileFromURL("https://www.herold.at/gelbe-seiten/telefon_".$number."/", 5, undef, 1); - + if(not defined($result)) { - Log3 $name, 4, "FB_CALLMONITOR ($name) - unable to retrieve result for reverse search of $number via $method"; + FB_CALLMONITOR_Log $name, 4, "unable to retrieve result for reverse search of $number via $method"; if(AttrVal($name, "reverse-search-cache", "0") eq "1") { $status = "timeout"; @@ -1049,77 +1126,168 @@ FB_CALLMONITOR_reverseSearch($$) } elsif($result !~ /Wir konnten zu den eingegebenen Suchkriterien keine Ergebnisse finden/) { - Log3 $name, 3, "FB_CALLMONITOR ($name) - the reverse search result for $number could not be extracted from herold.at. Please contact the FHEM community."; + FB_CALLMONITOR_Log $name, 3, "the reverse search result for $number could not be extracted from herold.at. Please contact the FHEM community."; } - + $status = "unknown"; } } } else { - Log3 $name, 3, "FB_CALLMONITOR ($name) - unknown reverse search method $method"; + FB_CALLMONITOR_Log $name, 3, "unknown reverse search method $method" if ($method ne "tellows.de"); } - } + } } - + if(AttrVal($name, "reverse-search-cache", "0") eq "1" and defined($status)) - { - # If no result is available set cache result and return undefined + { + # If no result is available set cache result and return undefined $hash->{helper}{CACHE}{$number} = $status; } return undef; -} +} -##################################### +####################################################################### +# calls tellows api +# +# 0781968053101 +# 0781-968053101 +# 7 +# 1077 +# 5 +# #f79a01 +# https://www.tellows.de/images/score/score7.png +# Offenburg +# Deutschland +# +# +# Unbekannt +# 2 +# +# +# Gewinnspiel +# 1 +# +# +# Meinungsforschung +# 1 +# +# +# Vermarkter Hotline +# 1 +# +# +# +#http://www.tellows.de/basic/num/0781968053101?xml=1&partner=test&apikey=test123 +# +sub FB_CALLMONITOR_tellowsRating($$){ + my ($hash, $number) = @_; + my $name = $hash->{NAME}; + my $result = GetFileFromURL("http://www.tellows.de/basic/num/".$number."?xml=1&partner=".AttrVal($name, "reverse-search-tellows-api-partner","")."&apikey=".AttrVal($name,"reverse-search-tellows-api-key",""), 5); + + FB_CALLMONITOR_Log $name, 5, "reverse search tellows: $number"; + + %tellows = (); + + if(not defined($result)){ + return undef; + } else { + $result =~ /(\d)/; + $tellows{'score'} = $1; + + $result =~ /([\d]+)/; + $tellows{'searches'} = $1; + + $result =~ /([\d]+)/; + $tellows{'comments'} = $1; + + $result =~ /([^"]*?)([^"]*?)([^"]*?)([^"]*?)([^"]*?)([\d]+)/; + $tellows{'mostCriticCount'} = $1; + } else { + $tellows{'mostCritic'} = 0; + $tellows{'mostCriticCount'} = 0; + } + + $tellows{'location'} = $tellows{'location'} . ", " . $tellows{'country'} if ($tellows{'country'} ne "Deutschland"); + + if($tellows{'score'} == 5){ + $tellows{'text'} = "aus ".$tellows{'location'}.", Tellows-Score: neutral"; + } elsif($tellows{'score'} < 5) { + $tellows{'text'} = "aus ".$tellows{'location'}.", Tellows-Score: positiv (".$tellows{'score'}."), häufigster Lob: ".$tellows{'mostCritic'}." (".$tellows{'mostCriticCount'}." x)"; + } else { + $tellows{'text'} = "aus ".$tellows{'location'}.", Tellows-Score: negativ (".$tellows{'score'}."), häufigster Reklamegrund: ".$tellows{'mostCritic'}." (".$tellows{'mostCriticCount'}." x)"; + } + + return $result; + } + +} ### tellows + + +############################################################################################################ # check a number against wildcard entries in a given phonebook list sub FB_CALLMONITOR_searchPhonebookWildcards($$) { my ($list, $number) = @_; - + foreach my $key (keys %{$list}) { next if($key !~ /^\+?\d+\*$/); - + if(defined($list->{$key})) { my $test = $key; $test =~ s/\*$//; - + if(index($number,$test) == 0) { return $list->{$key}.substr($number,length($test)); } } } - + return undef; } -##################################### +####################################################################### # replaces all HTML entities to their utf-8 counter parts. sub FB_CALLMONITOR_html2txt($) { my ($string) = @_; - + $string =~ s/ / /g; $string =~ s/&/&/g; $string =~ s/&pos;/'/g; - - $string =~ s/(\xe4|ä)/ä/g; - $string =~ s/(\xc4|Ä)/Ä/g; - $string =~ s/(\xf6|ö)/ö/g; - $string =~ s/(\xd6|Ö)/Ö/g; - $string =~ s/(\xfc|ü)/ü/g; - $string =~ s/(\xdc|Ü)/Ãœ/g; - $string =~ s/(\xdf|ß)/ß/g; - $string =~ s/(\xdf|ß)/ß/g; - $string =~ s/(\xe1|á)/á/g; - $string =~ s/(\xe9|é)/é/g; - $string =~ s/(\xc1|Á)/Ã/g; - $string =~ s/(\xc9|É)/É/g; + + $string =~ s/(\xe4|ä)/ä/g; + $string =~ s/(\xc4|Ä)/Ä/g; + $string =~ s/(\xf6|ö)/ö/g; + $string =~ s/(\xd6|Ö)/Ö/g; + $string =~ s/(\xfc|ü)/ü/g; + $string =~ s/(\xdc|Ü)/Ü/g; + $string =~ s/(\xdf|ß)/ß/g; + $string =~ s/(\xdf|ß)/ß/g; + $string =~ s/(\xe1|á)/á/g; + $string =~ s/(\xe9|é)/é/g; + $string =~ s/(\xc1|Á)/Á/g; + $string =~ s/(\xc9|É)/É/g; $string =~ s/\\u([a-f\d]{4})/encode('UTF-8',chr(hex($1)))/eig; $string =~ s/<[^>]+>//g; $string =~ s/</{helper}{CACHE}{$number} = $txt; - + if($file ne "") { - Log3 $name, 4, "FB_CALLMONITOR ($name) - opening cache file $file for writing $number ($txt)"; - + FB_CALLMONITOR_Log $name, 4, "opening cache file $file for writing $number ($txt)"; + foreach my $key (keys %{$hash->{helper}{CACHE}}) { push @cachefile, "$key|".$hash->{helper}{CACHE}{$key}; } - - $err = FileWrite($file,@cachefile); - + + $err = FileWrite($file, @cachefile); + if(defined($err) && $err) { - Log3 $name, 2, "FB_CALLMONITOR ($name) - could not write cache file: $err"; + FB_CALLMONITOR_Log $name, 2, "could not write cache file: $err"; } } } } -##################################### +####################################################################### # get and reads a FritzBox phonebook sub FB_CALLMONITOR_readPhonebook($;$) { my ($hash, $testPassword) = @_; - + my $name = $hash->{NAME}; my ($err, $count_contacts, @lines, $phonebook, $pb_hash); - + delete($hash->{helper}{PHONEBOOK}); 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") { ($err, $phonebook) = FB_CALLMONITOR_readRemotePhonebookViaTelnet($hash, $testPassword); - + if(defined($err)) { - Log3 $name, 2, "FB_CALLMONITOR ($name) - could not read remote FritzBox phonebook file - $err"; - return "Could not read remote FritzBox phonebook file - $err"; + FB_CALLMONITOR_Log $name, 2, "could not read remote FritzBox phonebook file - $err"; + return "Could not read remote FritzBox phonebook file - $err"; } - - Log3 $name, 2, "FB_CALLMONITOR ($name) - found remote FritzBox phonebook via telnet"; - + + 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)) { - Log3 $name, 2, "FB_CALLMONITOR ($name) - could not parse remote phonebook - $err"; + FB_CALLMONITOR_Log $name, 2, "could not parse remote phonebook - $err"; return "Could not parse remote phonebook - $err"; } else { - Log3 $name, 2, "FB_CALLMONITOR ($name) - read $count_contacts contact".($count_contacts == 1 ? "" : "s")." from remote phonebook via telnet"; + 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)$/) @@ -1211,102 +1379,102 @@ sub FB_CALLMONITOR_readPhonebook($;$) 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)) { - Log3 $name, 2, "FB_CALLMONITOR ($name) - could not identify remote phonebooks - $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})) { - Log3 $name, 2, "FB_CALLMONITOR ($name) - no phonebooks could be found"; + 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}})) { - Log3 $name, 4, "FB_CALLMONITOR ($name) - skipping excluded phonebook id $phonebookId (".$hash->{helper}{PHONEBOOK_NAMES}{$phonebookId}.")"; + FB_CALLMONITOR_Log $name, 4, "skipping excluded phonebook id $phonebookId (".$hash->{helper}{PHONEBOOK_NAMES}{$phonebookId}.")"; next; } - - Log3 $name, 4, "FB_CALLMONITOR ($name) - requesting phonebook id $phonebookId (".$hash->{helper}{PHONEBOOK_NAMES}{$phonebookId}.")"; - + + 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)) { - Log3 $name, 2, 'FB_CALLMONITOR ($name) - 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 { ($err, $count_contacts, $pb_hash) = FB_CALLMONITOR_parsePhonebook($hash, $phonebook); - + $hash->{helper}{PHONEBOOKS}{$phonebookId} = $pb_hash; if(defined($err)) { - Log3 $name, 2, "FB_CALLMONITOR ($name) - 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 { - Log3 $name, 2, "FB_CALLMONITOR ($name) - 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}); - + FB_CALLMONITOR_downloadImageURLs($hash, $testPassword); } } else { - Log3 $name, 4, "FB_CALLMONITOR ($name) - skipping remote phonebook"; + 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"); - - ($err, @lines) = FileRead({FileName => $phonebook_file, ForceType => "file"}); - + + ($err, @lines) = FileRead({FileName => $phonebook_file, ForceType => "file"}); + if(defined($err) && $err) { - Log3 $name, 2, "FB_CALLMONITOR ($name) - could not read FritzBox phonebook file - $err"; + FB_CALLMONITOR_Log $name, 2, "could not read FritzBox phonebook file - $err"; return "Could not read FritzBox phonebook file - $err"; } - - $phonebook = join("", @lines); - - Log3 $name, 2, "FB_CALLMONITOR ($name) - found FritzBox phonebook $phonebook_file"; - + + $phonebook = join("", @lines); + + FB_CALLMONITOR_Log $name, 2, "found FritzBox phonebook $phonebook_file"; + ($err, $count_contacts, $pb_hash) = FB_CALLMONITOR_parsePhonebook($hash, $phonebook); - + if(defined($err)) { - Log3 $name, 2, "FB_CALLMONITOR ($name) - could not parse $phonebook_file - $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; - Log3 $name, 2, "FB_CALLMONITOR ($name) - read $count_contacts contact".($count_contacts == 1 ? "" : "s")." from $phonebook_file"; + FB_CALLMONITOR_Log $name, 2, "read $count_contacts contact".($count_contacts == 1 ? "" : "s")." from $phonebook_file"; } - } + } else { - Log3 $name, 4, "FB_CALLMONITOR ($name) - skipping local phonebook file"; + FB_CALLMONITOR_Log $name, 4, "skipping local phonebook file"; } } -##################################### +####################################################################### # reads the FritzBox phonebook file and parses the entries sub FB_CALLMONITOR_parsePhonebook($$) { @@ -1316,56 +1484,56 @@ sub FB_CALLMONITOR_parsePhonebook($$) my $contact_name; my $number; my $count_contacts = 0; - + my $out; - - if($phonebook =~ /,) + + if($phonebook =~ /,) { if($phonebook =~ // and $phonebook =~ /]*>(.+?),gcs) + while($phonebook =~ m,]*>(.+?),gcs) { $contact = $1; - + my $imageURL; - + if($contact =~ m,([^<>]+),) { $imageURL = $1; - + $hash->{helper}{IMAGE_URLS}{$imageURL} = [] unless(exists($hash->{helper}{IMAGE_URLS}{$imageURL})); } - - if($contact =~ m,(.+?),) + + if($contact =~ m,(.+?),) { - $contact_name = $1; - - while($contact =~ m,]*?type="([^<>"]+?)"[^<>]*?>([^<>"]+?),gs) + $contact_name = $1; + + while($contact =~ m,]*?type="([^<>"]+?)"[^<>]*?>([^<>"]+?),gs) { - if($1 ne "intern" and $1 ne "memo") + if($1 ne "intern" and $1 ne "memo") { $number = FB_CALLMONITOR_normalizePhoneNumber($hash, $2); - + $count_contacts++; - Log3 $name, 4, "FB_CALLMONITOR ($name) - found $contact_name with number $number"; + FB_CALLMONITOR_Log $name, 4, "found $contact_name with number $number"; $out->{$number} = FB_CALLMONITOR_html2txt($contact_name); - + if($imageURL) { - Log3 $name, 5, "FB_CALLMONITOR ($name) - found image for $contact_name with number $number"; + FB_CALLMONITOR_Log $name, 5, "found image for $contact_name with number $number"; push @{$hash->{helper}{IMAGE_URLS}{$imageURL}}, $number; } - + undef $number; } } undef $contact_name; } - - + + } } - + return (undef, $count_contacts, $out); } else @@ -1374,7 +1542,7 @@ sub FB_CALLMONITOR_parsePhonebook($$) } } -##################################### +####################################################################### # loads the reverse search cache from file sub FB_CALLMONITOR_loadCacheFile($;$) { @@ -1388,22 +1556,22 @@ sub FB_CALLMONITOR_loadCacheFile($;$) $file = AttrVal($hash->{NAME}, "reverse-search-cache-file", "") unless(defined($file)); if($file ne "" and -r $file) - { + { delete($hash->{helper}{CACHE}); - - Log3 $hash->{NAME}, 3, "FB_CALLMONITOR ($name) - loading cache file $file"; - + + FB_CALLMONITOR_Log $hash->{NAME}, 3, "loading cache file $file"; + ($err, @cachefile) = FileRead($file); - + unless(defined($err) and $err) - { + { foreach my $line (@cachefile) { if(not $line =~ /^\s*$/) { chomp $line; @tmpline = split("\\|", $line, 2); - + if(@tmpline == 2) { $hash->{helper}{CACHE}{$tmpline[0]} = $tmpline[1]; @@ -1412,20 +1580,20 @@ sub FB_CALLMONITOR_loadCacheFile($;$) } $count_contacts = scalar keys %{$hash->{helper}{CACHE}}; - Log3 $name, 2, "FB_CALLMONITOR ($name) - read ".($count_contacts > 0 ? $count_contacts : "no")." contact".($count_contacts == 1 ? "" : "s")." from Cache"; + FB_CALLMONITOR_Log $name, 3, "read ".($count_contacts > 0 ? $count_contacts : "no")." contact".($count_contacts == 1 ? "" : "s")." from Cache"; } else { - Log3 $name, 3, "FB_CALLMONITOR ($name) - could not open cache file: $err"; + FB_CALLMONITOR_Log $name, 2, "could not open cache file: $err"; } } else { - Log3 $name, 3, "FB_CALLMONITOR ($name) - unable to access cache file: $file"; + FB_CALLMONITOR_Log $name, 2, "unable to access cache file: $file"; } } -##################################### +####################################################################### # loads the reverse search cache from file sub FB_CALLMONITOR_loadTextFile($;$) { @@ -1437,22 +1605,22 @@ sub FB_CALLMONITOR_loadTextFile($;$) my $name = $hash->{NAME}; my $err; $file = AttrVal($hash->{NAME}, "reverse-search-text-file", "") unless(defined($file)); - + if($file ne "" and -r $file) - { + { delete($hash->{helper}{TEXTFILE}); - - Log3 $hash->{NAME}, 3, "FB_CALLMONITOR ($name) - loading textfile $file"; - + + FB_CALLMONITOR_Log $hash->{NAME}, 3, "loading textfile $file"; + ($err, @file) = FileRead({FileName => $file, ForceType => "file"}); - + unless(defined($err) and $err) - { + { foreach my $line (@file) { $line =~ s/(,.*?)#.*$/$1/g; $line =~ s,//.*$,,g; - + if((not $line =~ /^\s*$/) and $line =~ /,/) { chomp $line; @@ -1465,11 +1633,11 @@ sub FB_CALLMONITOR_loadTextFile($;$) } $count_contacts = scalar keys %{$hash->{helper}{TEXTFILE}}; - Log3 $name, 2, "FB_CALLMONITOR ($name) - read ".($count_contacts > 0 ? $count_contacts : "no")." contact".($count_contacts == 1 ? "" : "s")." from textfile"; + FB_CALLMONITOR_Log $name, 3, "read ".($count_contacts > 0 ? $count_contacts : "no")." contact".($count_contacts == 1 ? "" : "s")." from textfile"; } else { - Log3 $name, 3, "FB_CALLMONITOR ($name) - could not open textfile: $err"; + FB_CALLMONITOR_Log $name, 2, "could not open textfile: $err"; } } else @@ -1487,14 +1655,14 @@ sub FB_CALLMONITOR_loadTextFile($;$) "# +49 123 45 67 8,Dad", "# 45678,Boss", "####" - ); + ); $err = FileWrite({FileName => $file, ForceType => "file"},@tmpline); - - Log3 $name, 3, "FB_CALLMONITOR ($name) - unable to create textfile $file: $err" if(defined($err) and $err ne ""); + + FB_CALLMONITOR_Log $name, 2, "unable to create textfile $file: $err" if(defined($err) and $err ne ""); } } -##################################### +####################################################################### # loads phonebook from extern FritzBox sub FB_CALLMONITOR_readRemotePhonebookViaTelnet($;$) { @@ -1512,49 +1680,49 @@ sub FB_CALLMONITOR_readRemotePhonebookViaTelnet($;$) { 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; } - - Log3 $name, 4, "FB_CALLMONITOR ($name) - connected to FritzBox via telnet"; - + + 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)) + + 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)) { - Log3 $name, 4, "FB_CALLMONITOR ($name) - setting user to FritzBox: $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; - } - - Log3 $name, 4, "FB_CALLMONITOR ($name) - giving password to FritzBox"; - $telnet->print($fb_pw); + } + + FB_CALLMONITOR_Log $name, 4, "giving password to FritzBox"; + $telnet->print($fb_pw); } elsif($match =~ /(login|user):/i and not defined($fb_user)) { @@ -1563,11 +1731,11 @@ sub FB_CALLMONITOR_readRemotePhonebookViaTelnet($;$) } elsif($match =~ /password:/i) { - Log3 $name, 4, "FB_CALLMONITOR ($name) - giving password to FritzBox"; + FB_CALLMONITOR_Log $name, 4, "giving password to FritzBox"; $telnet->print($fb_pw); } - - unless($telnet->waitfor('/#\s*$/')) + + unless($telnet->waitfor('/#\s*$/')) { $telnet->close; my $err = $telnet->errmsg; @@ -1575,48 +1743,48 @@ sub FB_CALLMONITOR_readRemotePhonebookViaTelnet($;$) return "wrong password, please provide the right password" if($err =~ /\s*eof/i); return "Could'nt recognize shell prompt: $err"; } - - Log3 $name, 4, "FB_CALLMONITOR ($name) - requesting $phonebook_file via telnet"; - + + 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 + } + else { - Log3 $name, 3, "FB_CALLMONITOR ($name) - Getting phonebook from FritzBox: $phonebook_file"; + FB_CALLMONITOR_Log $name, 3, "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($$$$;$$) { my ($hash, $url, $data, $header, $auth, $testPassword) = @_; my $name = $hash->{NAME}; - + my ($fb_ip,undef) = split(/:/, ($hash->{DeviceName}), 2); my ($fb_user, $fb_pw); my $param; my ($err, $response); - + if($auth) { $fb_user = AttrVal($name, "fritzbox-user", "admin"); - + $hash->{helper}{READ_PWD} = 1; $fb_pw = FB_CALLMONITOR_readPassword($hash, $testPassword); delete($hash->{helper}{READ_PWD}); @@ -1628,7 +1796,7 @@ sub FB_CALLMONITOR_requestHTTPviaTR064($$$$;$$) } } my $tr064_base_url = "http://".($auth ? urlEncode($fb_user).":".urlEncode($fb_pw)."\@" : "") ."$fb_ip:49000"; - + $param->{noshutdown} = 1; $param->{timeout} = AttrVal($name, "fritzbox-remote-timeout", 5); $param->{loglevel} = 4; @@ -1647,25 +1815,25 @@ sub FB_CALLMONITOR_requestHTTPviaTR064($$$$;$$) $param->{url} = "$tr064_base_url/upnp/control/deviceinfo"; $param->{header} = "SOAPACTION: urn:dslforum-org:service:DeviceInfo:1#GetSecurityPort\r\nContent-Type: text/xml; charset=utf-8"; - $param->{data} = $get_security_port; + $param->{data} = $get_security_port; + + FB_CALLMONITOR_Log $name, 4, "request SSL port for TR-064 access via method GetSecurityPort:\n$get_security_port"; + my ($err, $response) = HttpUtils_BlockingGet($param); - Log3 $name, 4, "FB_CALLMONITOR ($name) - request SSL port for TR-064 access via method GetSecurityPort:\n$get_security_port"; - my ($err, $response) = HttpUtils_BlockingGet($param); - if($err ne "") { - Log3 $name, 3, "FB_CALLMONITOR ($name) - error while requesting security port: $err"; + FB_CALLMONITOR_Log $name, 3, "error while requesting security port: $err"; return "error while requesting phonebooks: $err"; } if($response eq "" and exists($param->{code})) { - Log3 $name, 3, "FB_CALLMONITOR ($name) - received http code ".$param->{code}." without any data after requesting security port via TR-064"; + FB_CALLMONITOR_Log $name, 3, "received http code ".$param->{code}." without any data after requesting security port via TR-064"; return "received no data after requesting security port via TR-064"; } - - Log3 $name, 5, "FB_CALLMONITOR ($name) - received TR-064 method GetSecurityPort response:\n$response"; - + + FB_CALLMONITOR_Log $name, 5, "received TR-064 method GetSecurityPort response:\n$response"; + if($response =~ /(\d+)<\/NewSecurityPort>/) { $tr064_base_url = "https://".($auth ? urlEncode($fb_user).":".urlEncode($fb_pw)."\@" : "")."$fb_ip:$1"; @@ -1676,76 +1844,76 @@ sub FB_CALLMONITOR_requestHTTPviaTR064($$$$;$$) { $tr064_base_url = "https://".($auth ? urlEncode($fb_user).":".urlEncode($fb_pw)."\@" : "")."$fb_ip:".$hash->{helper}{TR064}{SECURITY_PORT}; } - + $param->{url} = "$tr064_base_url$url"; $param->{header} = $header if($header); - + if($data) { $param->{data} = $data if($data); - Log3 $name, 4, "FB_CALLMONITOR ($name) - sending TR-064 request:\n$data"; + FB_CALLMONITOR_Log $name, 4, "sending TR-064 request:\n$data"; } else { - Log3 $name, 4, "FB_CALLMONITOR ($name) - requesting TR-064 URL: $url"; + FB_CALLMONITOR_Log $name, 4, "requesting TR-064 URL: $url"; } - + ($err, $response) = HttpUtils_BlockingGet($param); - + if($err ne "") { if(exists($param->{code}) and $param->{code} eq "401") { $hash->{helper}{PWD_NEEDED} = 1; - Log3 $name, 3, "FB_CALLMONITOR ($name) - unable to login via TR-064, wrong user/password"; + FB_CALLMONITOR_Log $name, 3, "unable to login via TR-064, wrong user/password"; return "unable to login via TR-064, wrong user/password"; } else { - Log3 $name, 3, "FB_CALLMONITOR ($name) - error while requesting TR-064 URL $url: $err"; + FB_CALLMONITOR_Log $name, 3, "error while requesting TR-064 URL $url: $err"; return "error while requesting TR-064 URL $url: $err"; } } if($response eq "" and exists($param->{code})) { - Log3 $name, 3, "FB_CALLMONITOR ($name) - received http code ".$param->{code}." without any data after requesting TR-064 URL $url"; + FB_CALLMONITOR_Log $name, 3, "received http code ".$param->{code}." without any data after requesting TR-064 URL $url"; return "received no data after requesting TR-064 URL $url"; } if($param->{httpheader} =~ m,^Content-Type:\s*text,mi) { - Log3 $name, 5, "FB_CALLMONITOR ($name) - received TR-064 response for URL $url:\n$response"; + FB_CALLMONITOR_Log $name, 5, "received TR-064 response for URL $url:\n$response"; } else { - Log3 $name, 5, "FB_CALLMONITOR ($name) - received TR-064 response for URL $url"; + FB_CALLMONITOR_Log $name, 5, "received TR-064 response for URL $url"; } - + return (undef, $response, $param); } -##################################### +####################################################################### # execute TR-064 methods via HTTP/SOAP request sub FB_CALLMONITOR_requestTR064($$$$;$$) { my ($hash, $path, $command, $type, $command_arg, $testPassword) = @_; - + my $name = $hash->{NAME}; - # éxecute the TR-064 request + # éxecute the TR-064 request my $soap_request = ''. ''. ''. "".($command_arg ? $command_arg : "")."". ''. ''; - + my $header = "SOAPACTION: $type#$command\r\nContent-Type: text/xml; charset=utf-8"; - + return FB_CALLMONITOR_requestHTTPviaTR064($hash, $path, $soap_request, $header, 1, $testPassword); } @@ -1757,20 +1925,20 @@ sub FB_CALLMONITOR_identifyPhoneBooksViaTR064($;$) my $name = $hash->{NAME}; my ($err, $data) = FB_CALLMONITOR_requestTR064($hash, "/upnp/control/x_contact", "GetPhonebookList", "urn:dslforum-org:service:X_AVM-DE_OnTel:1", undef, $testPassword); - + return "unable to identify phonebooks via TR-064: $err" if($err); - + my @phonebooks; # read list response (TR-064 id's: "0,1,2,...") if($data =~ m,(.+?),si) { @phonebooks = split(",",$1); - Log3 $name, 3, "FB_CALLMONITOR ($name) - found ".scalar @phonebooks." phonebooks"; - } + FB_CALLMONITOR_Log $name, 3, "found ".scalar @phonebooks." phonebooks"; + } else { - Log3 $name, 3, "FB_CALLMONITOR ($name) - no phonebooks found"; + FB_CALLMONITOR_Log $name, 3, "no phonebooks found"; return "no phonebooks could be found"; } @@ -1778,79 +1946,79 @@ sub FB_CALLMONITOR_identifyPhoneBooksViaTR064($;$) delete($hash->{helper}{PHONEBOOK_URL}); # request name and FritzBox phone id for each list item - foreach (@phonebooks) + foreach (@phonebooks) { my $item_id = $_; - + my $phb_id; - - Log3 $name, 5, "FB_CALLMONITOR ($name) - requesting phonebook description for id $item_id"; - + + FB_CALLMONITOR_Log $name, 5, "requesting phonebook description for id $item_id"; + ($err, $data) = FB_CALLMONITOR_requestTR064($hash, "/upnp/control/x_contact", "GetPhonebook", "urn:dslforum-org:service:X_AVM-DE_OnTel:1", "$item_id", $testPassword); - + if ($err) { - Log3 $name, 3, "FB_CALLMONITOR ($name) - error while requesting phonebook description for id $item_id: $err"; + FB_CALLMONITOR_Log $name, 3, "error while requesting phonebook description for id $item_id: $err"; return "error while requesting phonebook description for id $item_id: $err"; } - Log3 $name, 5, "FB_CALLMONITOR ($name) - received response with phonebook description for id $item_id:\n$data"; + FB_CALLMONITOR_Log $name, 5, "received response with phonebook description for id $item_id:\n$data"; if($data =~ m,(.+?).*?.*?pbid=(\d+)\D*?,si) { $phb_id = $2; $hash->{helper}{PHONEBOOK_NAMES}{$phb_id} = $1; - Log3 $name, 4, "FB_CALLMONITOR ($name) - found phonebook: $1 - $2"; + FB_CALLMONITOR_Log $name, 4, "found phonebook: $1 - $2"; } if($data =~ m,(.*?),i) { $hash->{helper}{PHONEBOOK_URL}{$phb_id} = $1; $hash->{helper}{PHONEBOOK_URL}{$phb_id} =~ s/&/&/g; - Log3 $name, 4, "FB_CALLMONITOR ($name) - found phonebook url for id $phb_id: ".$hash->{helper}{PHONEBOOK_URL}{$phb_id}; + FB_CALLMONITOR_Log $name, 4, "found phonebook url for id $phb_id: ".$hash->{helper}{PHONEBOOK_URL}{$phb_id}; } } - - Log3 $name, 4, "FB_CALLMONITOR ($name) - phonebooks found: ".join(", ", map { $hash->{helper}{PHONEBOOK_NAMES}{$_}." (id: $_)" } sort keys %{$hash->{helper}{PHONEBOOK_NAMES}}) if(exists($hash->{helper}{PHONEBOOK_NAMES})); - + + FB_CALLMONITOR_Log $name, 4, "phonebooks found: ".join(", ", map { $hash->{helper}{PHONEBOOK_NAMES}{$_}." (id: $_)" } sort keys %{$hash->{helper}{PHONEBOOK_NAMES}}) if(exists($hash->{helper}{PHONEBOOK_NAMES})); + # get deflections - + delete($hash->{helper}{DEFLECTIONS}); - - Log3 $name, 5, "FB_CALLMONITOR ($name) - requesting deflection list"; + + FB_CALLMONITOR_Log $name, 5, "requesting deflection list"; ($err, $data) = FB_CALLMONITOR_requestTR064($hash, "/upnp/control/x_contact", "GetDeflections", "urn:dslforum-org:service:X_AVM-DE_OnTel:1",undef, $testPassword); - + if ($err) { - Log3 $name, 3, "FB_CALLMONITOR ($name) - error while requesting deflection list: $err"; + FB_CALLMONITOR_Log $name, 3, "error while requesting deflection list: $err"; return "error while requesting deflection list: $err"; } $data =~ s/<//g; - + # extract deflection list while($data =~ /(.*?)<\/Item>/gcs) { my $deflection_item = $1; my %values; - + while($deflection_item =~ m,<(?:\w+:)?(\w+)>([^<]+),gcs) { $values{$1} = $2; } - + $hash->{helper}{DEFLECTIONS}{$values{DeflectionId}} = \%values; } - - Log3 $name, 3, "FB_CALLMONITOR ($name) - found ".(scalar keys %{$hash->{helper}{DEFLECTIONS}})." blocking rules (deflections)" if(exists($hash->{helper}{DEFLECTIONS})); - + + FB_CALLMONITOR_Log $name, 3, "found ".(scalar keys %{$hash->{helper}{DEFLECTIONS}})." blocking rules (deflections)" if(exists($hash->{helper}{DEFLECTIONS})); + delete($hash->{helper}{PWD_NEEDED}); return undef; } -##################################### +####################################################################### # loads internal and online phonebooks from extern FritzBox via web interface (http) sub FB_CALLMONITOR_readRemotePhonebookViaTR064($$;$) { @@ -1858,10 +2026,10 @@ sub FB_CALLMONITOR_readRemotePhonebookViaTR064($$;$) my $name = $hash->{NAME}; my ($fb_ip,undef) = split(/:/, ($hash->{DeviceName}), 2); - + return "unknown phonebook id: $phonebookId" unless(exists($hash->{helper}{PHONEBOOK_NAMES}{$phonebookId})); return "unknown phonebook url:" unless(exists($hash->{helper}{PHONEBOOK_URL}{$phonebookId})); - + my $phb_url = $hash->{helper}{PHONEBOOK_URL}{$phonebookId}; my $param; @@ -1869,31 +2037,31 @@ sub FB_CALLMONITOR_readRemotePhonebookViaTR064($$;$) $param->{noshutdown} = 1; $param->{timeout} = AttrVal($name, "fritzbox-remote-timeout", 5); $param->{loglevel} = 4; - - Log3 $name, 4, "FB_CALLMONITOR ($name) - get export for phonebook: $phonebookId"; - + + FB_CALLMONITOR_Log $name, 4, "get export for phonebook: $phonebookId"; + my ($err, $phonebook) = HttpUtils_BlockingGet($param); - - Log3 $name, 5, "FB_CALLMONITOR ($name) - received http response code ".$param->{code} if(exists($param->{code})); - - if ($err ne "") + + FB_CALLMONITOR_Log $name, 5, "received http response code ".$param->{code} if(exists($param->{code})); + + if ($err ne "") { - Log3 $name, 3, "FB_CALLMONITOR ($name) - got error while requesting phonebook: $err"; + FB_CALLMONITOR_Log $name, 3, "got error while requesting phonebook: $err"; return "got error while requesting phonebook: $err"; } if($phonebook eq "" and exists($param->{code})) { - Log3 $name, 3, "FB_CALLMONITOR ($name) - received http code ".$param->{code}." without any data"; + FB_CALLMONITOR_Log $name, 3, "received http code ".$param->{code}." without any data"; return "received http code ".$param->{code}." without any data"; } - - return (undef, $phonebook); + + return (undef, $phonebook); } -##################################### +####################################################################### # retrieves a session id to download files via TR-064 (phonebook contact images) -sub FB_CALLMONITOR_getSIDviaTR064($) +sub FB_CALLMONITOR_getSIDviaTR064($) { @@ -1904,7 +2072,7 @@ sub FB_CALLMONITOR_getSIDviaTR064($) if($err) { - Log3 $name, 3, "FB_CALLMONITOR ($name) - error while requesting session id via TR064: $err"; + FB_CALLMONITOR_Log $name, 3, "error while requesting session id via TR064: $err"; return undef; } @@ -1912,89 +2080,89 @@ sub FB_CALLMONITOR_getSIDviaTR064($) { return $1; } - + return undef; } -##################################### +####################################################################### # downloads all available image URL's via TR-064 sub FB_CALLMONITOR_downloadImageURLs($$) { my ($hash, $testPassword) = @_; my $name = $hash->{NAME}; - + if($hash->{helper}{IMAGE_URLS} and AttrVal($name,"contactImageViaTR064", "1") eq "1") { my $sid = FB_CALLMONITOR_getSIDviaTR064($hash); my $local_path = AttrVal($name,"contactImageDirectory", undef); - + return unless(defined($sid) and defined($local_path)); - + if(! -d $local_path) { eval { use File::Path }; if($@) { - Log3 $name, 3, "FB_CALLMONITOR ($name) - unable to load File::Path perl module to create contact images directory '$local_path'. Please create it by yourself"; + FB_CALLMONITOR_Log $name, 3, "unable to load File::Path perl module to create contact images directory '$local_path'. Please create it by yourself"; return undef; } - + eval {File::Path::make_path($local_path) }; if($@) { - Log3 $name, 3, "FB_CALLMONITOR ($name) - unable to create contact images directory '$local_path': $@"; + FB_CALLMONITOR_Log $name, 3, "unable to create contact images directory '$local_path': $@"; return undef; } } - + foreach my $url (keys %{$hash->{helper}{IMAGE_URLS}}) { my ($err, $file, $param) = FB_CALLMONITOR_requestHTTPviaTR064($hash, $url."&".$sid, undef, undef, 0, $testPassword); - + if($err) { - Log3 $name, 3, "FB_CALLMONITOR ($name) - error while requesting image URL $url via TR064: $err"; + FB_CALLMONITOR_Log $name, 3, "error while requesting image URL $url via TR064: $err"; next; } if($param->{httpheader} =~ /Content-Disposition: attachment; filename="[^"\s]+(\.\w+)"$/m) { my $suffix = $1; - + foreach my $number (@{$hash->{helper}{IMAGE_URLS}{$url}}) { - + my $filename = $local_path."/".$number.$suffix; my $result = FileWrite({FileName => $local_path."/".$number.$suffix, ForceType=> "file", NoNL=> 1}, $file); - + if($result) { - Log3 $name, 3, "FB_CALLMONITOR ($name) - error while writing image $filename: $result"; + FB_CALLMONITOR_Log $name, 3, "error while writing image $filename: $result"; } } } } - - Log3 $name, 2, "FB_CALLMONITOR ($name) - downloaded ".(scalar keys %{$hash->{helper}{IMAGE_URLS}})." contact images from all phonebooks"; - + + FB_CALLMONITOR_Log $name, 2, "downloaded ".(scalar keys %{$hash->{helper}{IMAGE_URLS}})." contact images from all phonebooks"; + } } -##################################### +####################################################################### # returns the filename of a corresponding contact image if exist. sub FB_CALLMONITOR_getContactImage($$) { my ($hash, $number) = @_; - + my $name = $hash->{NAME}; - + my $local_path = AttrVal($name,"contactImageDirectory", undef); - + return undef unless(defined($local_path)); - + $local_path =~ s,/+$,,; - + opendir(DIR, $local_path) or return undef; while (my $file = readdir(DIR)) { @@ -2005,11 +2173,11 @@ sub FB_CALLMONITOR_getContactImage($$) return $file; } - + return AttrVal($name,"contactDefaultImage", "none"); } -##################################### +####################################################################### # identifys the phonebooks defined on the FritzBox via web interface (http) sub FB_CALLMONITOR_identifyPhoneBooksViaWeb($;$) { @@ -2028,14 +2196,14 @@ sub FB_CALLMONITOR_identifyPhoneBooksViaWeb($;$) return "no password available to access FritzBox. Please set your FRITZ!Box password via 'set ".$hash->{NAME}." password '" unless(defined($fb_pw)); $fb_sid = FB_doCheckPW($fb_ip, $fb_user, $fb_pw); - + unless(defined($fb_sid)) { $hash->{helper}{PWD_NEEDED} = 1; - return "unable to login via webinterface, maybe wrong user/password?" + return "unable to login via webinterface, maybe wrong user/password?" } - - Log3 $name, 4, "FB_CALLMONITOR ($name) - identifying available phonebooks"; + + FB_CALLMONITOR_Log $name, 4, "identifying available phonebooks"; my $param; $param->{url} = "http://$fb_ip/fon_num/fonbook_select.lua?sid=$fb_sid"; @@ -2047,39 +2215,39 @@ sub FB_CALLMONITOR_identifyPhoneBooksViaWeb($;$) if ($err ne "") { - Log3 $name, 3, "FB_CALLMONITOR ($name) - error while requesting phonebooks: $err"; + FB_CALLMONITOR_Log $name, 3, "error while requesting phonebooks: $err"; return "error while requesting phonebooks: $err"; } if($data eq "" and exists($param->{code})) { - Log3 $name, 3, "FB_CALLMONITOR ($name) - received http code ".$param->{code}." without any data after requesting available phonebooks"; + FB_CALLMONITOR_Log $name, 3, "received http code ".$param->{code}." without any data after requesting available phonebooks"; return "received no data after requesting available phonebooks"; } - Log3 $name, 4, "FB_CALLMONITOR ($name) - phonebooks successfully identified"; - + FB_CALLMONITOR_Log $name, 4, "phonebooks successfully identified"; + if($data =~ m,]*name="mainform"[^>]*>(.+?),s) { $data = $1; } delete($hash->{helper}{PHONEBOOK_NAMES}); - + while($data =~ m,]*for="uiBookid:(\d+)"[^>]*>\s*(.+?)\s*,gcs) { $hash->{helper}{PHONEBOOK_NAMES}{$1} = $2; - Log3 $name, 4, "FB_CALLMONITOR ($name) - found phonebook: $2"; + FB_CALLMONITOR_Log $name, 4, "found phonebook: $2"; } - - Log3 $name, 3, "FB_CALLMONITOR ($name) - phonebooks found: ".join(", ", map { $hash->{helper}{PHONEBOOK_NAMES}{$_}." (id: $_)" } sort keys %{$hash->{helper}{PHONEBOOK_NAMES}}) if(exists($hash->{helper}{PHONEBOOK_NAMES})); + + FB_CALLMONITOR_Log $name, 3, "phonebooks found: ".join(", ", map { $hash->{helper}{PHONEBOOK_NAMES}{$_}." (id: $_)" } sort keys %{$hash->{helper}{PHONEBOOK_NAMES}}) if(exists($hash->{helper}{PHONEBOOK_NAMES})); delete($hash->{helper}{PWD_NEEDED}); return undef; } -##################################### +####################################################################### # loads internal and online phonebooks from extern FritzBox via web interface (http) sub FB_CALLMONITOR_readRemotePhonebookViaWeb($$;$) { @@ -2090,24 +2258,24 @@ sub FB_CALLMONITOR_readRemotePhonebookViaWeb($$;$) my $fb_user = AttrVal($name, "fritzbox-user", ''); my $fb_pw; my $fb_sid; - + return "unknown phonebook id: $phonebookId" unless(exists($hash->{helper}{PHONEBOOK_NAMES}{$phonebookId})); - + $hash->{helper}{READ_PWD} = 1; $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)); - + $fb_sid = FB_doCheckPW($fb_ip, $fb_user, $fb_pw); - + unless(defined($fb_sid)) { $hash->{helper}{PWD_NEEDED} = 1; - return "no session id available to access FritzBox. Maybe wrong user/password?" + return "no session id available to access FritzBox. Maybe wrong user/password?" } - + my $param; $param->{url} = "http://$fb_ip/cgi-bin/firmwarecfg"; $param->{noshutdown} = 1; @@ -2115,7 +2283,7 @@ sub FB_CALLMONITOR_readRemotePhonebookViaWeb($$;$) $param->{loglevel} = 4; $param->{method} = "POST"; $param->{header} = "Content-Type: multipart/form-data; boundary=boundary"; - + $param->{data} = "--boundary\r\n". "Content-Disposition: form-data; name=\"sid\"\r\n". "\r\n". @@ -2133,126 +2301,126 @@ sub FB_CALLMONITOR_readRemotePhonebookViaWeb($$;$) "\r\n". "\r\n". "--boundary--"; - - Log3 $name, 4, "FB_CALLMONITOR ($name) - get export for phonebook: $phonebookId"; - + + FB_CALLMONITOR_Log $name, 4, "get export for phonebook: $phonebookId"; + my ($err, $phonebook) = HttpUtils_BlockingGet($param); - - Log3 $name, 5, "FB_CALLMONITOR ($name) - received http response code ".$param->{code} if(exists($param->{code})); - - if ($err ne "") + + FB_CALLMONITOR_Log $name, 5, "received http response code ".$param->{code} if(exists($param->{code})); + + if ($err ne "") { - Log3 $name, 3, "FB_CALLMONITOR ($name) - got error while requesting phonebook: $err"; + FB_CALLMONITOR_Log $name, 3, "got error while requesting phonebook: $err"; return "got error while requesting phonebook: $err"; } if($phonebook eq "" and exists($param->{code})) { - Log3 $name, 3, "FB_CALLMONITOR ($name) - received http code ".$param->{code}." without any data"; + FB_CALLMONITOR_Log $name, 3, "received http code ".$param->{code}." without any data"; return "received http code ".$param->{code}." without any data"; } delete($hash->{helper}{PWD_NEEDED}); - return (undef, $phonebook); + return (undef, $phonebook); } -##################################### +####################################################################### # checks and store FritzBox password used for telnet connection sub FB_CALLMONITOR_storePassword($$) { my ($hash, $password) = @_; - + my $index = $hash->{TYPE}."_".$hash->{NAME}."_passwd"; my $key = getUniqueId().$index; - + my (undef, $enc_pwd) = FB_CALLMONITOR_encrypt($password, $key); - + my $err = FB_CALLMONITOR_readPhonebook($hash, $enc_pwd); - + return "unable to check password - $err" if(defined($err)); - + $err = setKeyValue($index, $enc_pwd); - + return "error while saving the password - $err" if(defined($err)); - + return "password successfully saved"; } - -##################################### + +####################################################################### # reads the FritzBox password sub FB_CALLMONITOR_readPassword($;$) { my ($hash, $testPassword) = @_; my $name = $hash->{NAME}; - + my $index = $hash->{TYPE}."_".$hash->{NAME}."_passwd"; my $key = getUniqueId().$index; - + my ($password, $err); - + if(defined($testPassword)) { $password = $testPassword; } else - { + { ($err, $password) = getKeyValue($index); - + if(defined($err)) { $hash->{helper}{PWD_NEEDED} = 1; - Log3 $name, 4, "FB_CALLMONITOR ($name) - unable to read FritzBox password from file: $err"; + FB_CALLMONITOR_Log $name, 4, "unable to read FritzBox password from file: $err"; return undef; - } - } - + } + } + if(defined($password)) { my (undef, $dec_pwd) = FB_CALLMONITOR_decrypt($password, $key); - + return $dec_pwd if($hash->{helper}{READ_PWD}); } else { $hash->{helper}{PWD_NEEDED} = 1; - + return undef; } } -##################################### +####################################################################### # normalizes a formated phone number sub FB_CALLMONITOR_normalizePhoneNumber($$) { my ($hash, $number) = @_; my $name = $hash->{NAME}; - + my $area_code = AttrVal($name, "local-area-code", ""); my $country_code = AttrVal($name, "country-code", "0049"); - + $number =~ s/\s//g; # Remove spaces $number =~ s/^(\#[0-9]{1,10}\#)//g; # Remove phone control codes $number =~ s/^\+/00/g; # Convert leading + to 00 country extension $number =~ s/[^\d\*#]//g if(not $number =~ /@/); # Remove anything else isn't a number if it is no VoIP number $number =~ s/^$country_code/0/g; # Replace own country code with leading 0 - if($number =~ /^\d/ and $number !~ /^0/ and $number !~ /^11/ and $number !~ /@/ and $area_code =~ /^0[1-9]\d+$/) + if($number =~ /^\d/ and $number !~ /^0/ and $number !~ /^11/ and $number !~ /@/ and $area_code =~ /^0[1-9]\d+$/) { $number = $area_code.$number; } - + return $number; } -##################################### +####################################################################### # decrypt an encrypted password sub FB_CALLMONITOR_decrypt($$) { my ($password, $key) = @_; - + return undef unless(defined($password)); - + if(eval "use Digest::MD5;1") { $key = Digest::MD5::md5_hex(unpack "H*", $key); @@ -2260,61 +2428,62 @@ sub FB_CALLMONITOR_decrypt($$) } my $dec_pwd = ''; - + for my $char (map { pack('C', hex($_)) } ($password =~ /(..)/g)) { my $decode=chop($key); $dec_pwd.=chr(ord($char)^ord($decode)); $key=$decode.$key; } - + return (undef, $dec_pwd); } -##################################### +####################################################################### # encrypts a password sub FB_CALLMONITOR_encrypt($$) { my ($password, $key) = @_; - + return undef unless(defined($password)); - + if(eval "use Digest::MD5;1") { $key = Digest::MD5::md5_hex(unpack "H*", $key); $key .= Digest::MD5::md5_hex($key); } - + my $enc_pwd = ''; - + for my $char (split //, $password) { my $encode=chop($key); $enc_pwd.=sprintf("%.2x",ord($char)^ord($encode)); $key=$encode.$key; } - + return (undef, $enc_pwd); } +####################################################################### sub FB_CALLMONITOR_checkNumberForDeflection($$) { my ($hash, $number) = @_; my $name = $hash->{NAME}; - + my $ret = 0; - + if(exists($hash->{helper}{DEFLECTIONS}) and AttrVal($name,"check-deflections",0)) { my $deflection_count = scalar keys %{$hash->{helper}{DEFLECTIONS}}; - - Log3 $name, 4, "FB_CALLMONITOR ($name) - check ".(defined($number) ? $number : "unknown number")." against deflection rules (".$deflection_count." rule".($deflection_count ==1 ? "" : "s").")"; - - foreach my $item (values %{$hash->{helper}{DEFLECTIONS}}) + + FB_CALLMONITOR_Log $name, 4, "check ".(defined($number) ? $number : "unknown number")." against deflection rules (".$deflection_count." rule".($deflection_count ==1 ? "" : "s").")"; + + foreach my $item (values %{$hash->{helper}{DEFLECTIONS}}) { next unless($item->{Enable}); # next if rule not enabled next if(!$item->{Type}); - + if($item->{Type} eq "fromNumber" and $item->{Number} and $number) { my $tmp = $item->{Number}; @@ -2330,24 +2499,26 @@ sub FB_CALLMONITOR_checkNumberForDeflection($$) } } } - - Log3 $name, 4, "FB_CALLMONITOR ($name) - found matching deflection. call will be ignored" if($ret); + + FB_CALLMONITOR_Log $name, 4, "found matching deflection. call will be ignored" if($ret); return $ret; } +####################################################################### sub FB_CALLMONITOR_checkNumberIsFiltered($$) { my ($hash, $number) = @_; my $name = $hash->{NAME}; - + if(exists($hash->{helper}{INTERNAL_FILTER}) and not exists($hash->{helper}{INTERNAL_FILTER}{$number})) { return 1; } - - return 0; + + return 0; } +####################################################################### sub FB_CALLMONITOR_sendKeepAlive($) { my ($hash) = @_; @@ -2360,30 +2531,29 @@ sub FB_CALLMONITOR_sendKeepAlive($) "30m" => 1800, "1h" => 3600 }; - + if($sendKeepAlives ne "none" and DevIo_IsOpen($hash)) { - Log3 $name, 5, "FB_CALLMONITOR ($name) - sending keep-alive"; + FB_CALLMONITOR_Log $name, 5, "sending keep-alive"; DevIo_SimpleWrite($hash, "\n", 2); - + if($values->{$sendKeepAlives}) { InternalTimer(gettimeofday()+$values->{$sendKeepAlives}, "FB_CALLMONITOR_sendKeepAlive", $hash); } else { - Log3 $name, 3, "FB_CALLMONITOR ($name) - unsupported value for attribute sendKeepAlives: $sendKeepAlives. discard sending keep-alive"; + FB_CALLMONITOR_Log $name, 3, "unsupported value for attribute sendKeepAlives: $sendKeepAlives. discard sending keep-alive"; } } else { RemoveInternalTimer($hash, "FB_CALLMONITOR_sendKeepAlive"); } - + return undef; } - 1; =pod @@ -2392,28 +2562,29 @@ sub FB_CALLMONITOR_sendKeepAlive($) =item summary_DE stellt Telefonereignisse einer AVM FRITZ!Box via LAN zur Verfügung =begin html +

FB_CALLMONITOR

    The FB_CALLMONITOR module connects to a AVM FritzBox Fon and listens for telephone events (Receiving incoming call, Making a call)

    - In order to use this module with fhem you must enable the Callmonitor feature via + In order to use this module with fhem you must enable the Callmonitor feature via telephone shortcode.

      #96*5* - for activating
      #96*4* - for deactivating
    - +
    Just dial the shortcode for activating on one of your phones, after 3 seconds just hang up. The feature is now activated.

    - 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.

    This module work with any FritzBox Fon model.

    - - + + Define
      define <name> FB_CALLMONITOR <ip-address>[:port]
      @@ -2422,70 +2593,110 @@ sub FB_CALLMONITOR_sendKeepAlive($)

    - + + Set
      -
    • reopen - close and reopen the connection
    • -
    • rereadCache - Reloads the cache file if configured (see attribute: reverse-search-cache-file)
    • -
    • rereadPhonebook - Reloads the FritzBox phonebook (from given file, via telnet or directly if available)
    • -
    • rereadTextfile - Reloads the user given textfile if configured (see attribute: reverse-search-text-file)
    • -
    • password - set the FritzBox password (only available when password is really needed for network access to FritzBox phonebook, see attribute fritzbox-remote-phonebook)
    • +
    • +
      set <name> reopen
      + close and reopen the connection +
    • +
    • +
      set <name> rereadCache
      + Reloads the cache file if configured (see attribute: reverse-search-cache-file) +
    • +
    • +
      set <name> rereadPhonebook
      + Reloads the FritzBox phonebook (from given file, via telnet or directly if available) +
    • +
    • +
      set <name> rereadTextfile
      + Reloads the user given textfile if configured (see attribute: reverse-search-text-file) +
    • +
    • +
      set <name> password <password>
      + set the FritzBox password (only available when password is really needed for network access to FritzBox phonebook, see attribute fritzbox-remote-phonebook) +

    - + Get
      -
    • search <phone-number> - returns the name of the given number via reverse-search (internal phonebook, cache or internet lookup)
    • -
    • showPhonebookIds - returns a list of all available phonebooks on the FritzBox (not available when using telnet to retrieve remote phonebook)
    • -
    • showPhonebookEntries [phonebook-id] - returns a list of all currently known phonebook entries, or just for a spefific phonebook id (only available when using phonebook funktionality)
    • -
    • showCacheEntries - returns a list of all currently known cache entries (only available when using reverse search caching funktionality)
    • -
    • showTextfileEntries - returns a list of all known entries from user given textfile (only available when using reverse search caching funktionality)
    • +
    • +
      get <name> search <phone-number>
      + returns the name of the given number via reverse-search (internal phonebook, cache or internet lookup) +
    • +
    • +
      get <name> showPhonebookIds
      + returns a list of all available phonebooks on the FritzBox (not available when using telnet to retrieve remote phonebook) +
    • +
    • +
      get <name> [phonebook-id]
      + returns a list of all currently known phonebook entries, or just for a spefific phonebook id (only available when using phonebook funktionality) +
    • +
    • +
      get <name> showCacheEntries
      + returns a list of all currently known cache entries (only available when using reverse search caching funktionality) +
    • +
    • +
      get <name> showTextfileEntries
      + returns a list of all known entries from user given textfile (only available when using reverse search caching funktionality) +

    - + Attributes

    • do_not_notify
    • +
    • readingFnAttributes 0,1

    • -
    • disable 0,1
    • + +
    • disable 0,1
    • Optional attribute to disable the Callmonitor. When disabled, no phone events can be detected.

      Possible values: 0 => Callmonitor is activated, 1 => Callmonitor is deactivated.
      Default Value is 0 (activated)

      -
    • disabledForIntervals HH:MM-HH:MM HH:MM-HH-MM...
    • + +
    • disabledForIntervals HH:MM-HH:MM HH:MM-HH-MM...
    • Optional attribute to disable FB_CALLMONITOR during specific time intervals. The attribute contains a space separated list of HH:MM tupels. If the current time is between any of these time specifications, no phone events will be processed. - Instead of HH:MM you can also specify HH or HH:MM:SS. + Instead of HH:MM you can also specify HH or HH:MM:SS.

      To specify an interval spawning midnight, you have to specify two intervals, e.g.:
      23:00-24:00 00:00-01:00
      Default Value is empty (no intervals defined, FB_CALLMONITOR is always active)

      -
    • answMachine-is-missed-call 0,1
    • - If activated, a incoming call, which is answered by an answering machine, will be treated as missed call (see Generated Events). + +
    • answMachine-is-missed-call 0,1
    • + If activated, a incoming call, which is answered by an answering machine, will be treated as missed call (see Generated Events).

      Possible values: 0 => disabled, 1 => enabled (answering machine calls will be treated as "missed call").
      Default Value is 0 (disabled)

      -
    • internal-number-filter <number>[,<number>,...]
    • + +
    • internal-number-filter <number>[,<number>,...]
    • If set, only calls for the configured internal number (according to reading "internal_number") will be processed. - Valid values are one particular internal number or a comma separated list of multiple internal numbers. + Valid values are one particular internal number or a comma separated list of multiple internal numbers. Calls internal numbers, which are not listed here, will be ignored and not processed. If this attribute is not set, all calls will be processed (no filtering).

      per default, internal number filtering is disabled.

      -
    • reverse-search (phonebook,textfile,dasoertliche.de,11880.com,search.ch,dasschnelle.at,herold.at)
    • + +
    • reverse-search (phonebook,textfile,tellows.de,dasoertliche.de,11880.com,search.ch,dasschnelle.at,herold.at)
    • Enables the reverse searching of the external number (at dial and call receiving). - This attribute contains a comma separated list of providers which should be used to reverse search a name to a specific phone number. + This attribute contains a comma separated list of providers which should be used to reverse search a name to a specific phone number. The reverse search process will try to lookup the name according to the order of providers given in this attribute (from left to right). The first valid result from the given provider order will be used as reverse search result.

      per default, reverse search is disabled.

      -
    • reverse-search-cache 0,1
    • + +
    • reverse-search-cache 0,1
    • If this attribute is activated each reverse-search result from an internet provider is saved in an internal cache and will be used instead of requesting each internet provider every time with the same number. The cache only contains reverse-search results from internet providers.

      Possible values: 0 => off , 1 => on
      Default Value is 0 (off)

      -
    • reverse-search-cache-file <file>
    • + +
    • reverse-search-cache-file <file>
    • Write the internal reverse-search-cache to the given file and use it next time FHEM starts. So all reverse search results are persistent written to disk and will be used instantly after FHEM starts.

      -
    • reverse-search-text-file <file>
    • + +
    • reverse-search-text-file <file>
    • Define a custom list of numbers and their according names in a textfile. This file uses comma separated values per line in form of:
           <number1>,<name1>
      @@ -2495,65 +2706,84 @@ sub FB_CALLMONITOR_sendKeepAlive($)
           
      You can use the hash sign to comment entries in this file. If the specified file does not exists, it will be created by FHEM.

      -
    • reverse-search-phonebook-file <file>
    • + +
    • reverse-search-phonebook-file <file>
    • This attribute can be used to specify the (full) path to a phonebook file in FritzBox format (XML structure). Using this option it is possible to use the phonebook of a FritzBox even without FHEM running on a Fritzbox. The phonebook file can be obtained by an export via FritzBox web UI

      Default value is /var/flash/phonebook (phonebook filepath on FritzBox)

      -
    • remove-leading-zero 0,1
    • + +
    • reverse-search-tellows-api-key <api-key>
    • + tellows api-key. For test cases you can use the api-key -test123-

      + +
    • reverse-search-tellows-api-partner <api-partner>
    • + tellows api-partner. For test cases you can use the api-partner -test-

      + +
    • remove-leading-zero 0,1
    • If this attribute is activated, a leading zero will be removed from the external number (e.g. in telefon systems).

      Possible values: 0 => off , 1 => on
      Default Value is 0 (off)

      -
    • unique-call-ids 0,1
    • + +
    • unique-call-ids 0,1
    • If this attribute is activated, each call will use a biunique call id. So each call can be separated from previous calls in the past.

      Possible values: 0 => off , 1 => on
      Default Value is 0 (off)

      -
    • local-area-code <number>
    • + +
    • local-area-code <number>
    • Use the given local area code for reverse search in case of a local call (e.g. 0228 for Bonn, Germany)

      -
    • country-code <number>
    • + +
    • country-code <number>
    • Your local country code. This is needed to identify phonenumbers in your phonebook with your local country code as a national phone number instead of an international one as well as handling Call-By-Call numbers in german speaking countries (e.g. 0049 for Germany, 0043 for Austria or 001 for USA)

      Default Value is 0049 (Germany)

      -
    • check-deflections 0,1
    • - If this attribute is activated, each incoming call is checked against the configured blocking rules (deflections) of the FritzBox. If an incoming call matches any of these rules, the call will be blocked and no reading/revent will be created for this call. This is only possible, if the phonebook is obtained via TR-064 from the FritzBox (see attributes fritzbox-remote-phonebook and fritzbox-remote-phonebook-via

      + +
    • check-deflections 0,1
    • + If this attribute is activated, each incoming call is checked against the configured blocking rules (deflections) of the FritzBox. If an incoming call matches any of these rules, the call will be blocked and no reading/revent will be created for this call. This is only possible, if the phonebook is obtained via TR-064 from the FritzBox (see attributes fritzbox-remote-phonebook and fritzbox-remote-phonebook-via

      Possible values: 0 => off , 1 => on
      Default Value is 0 (off)

      -
    • fritzbox-remote-phonebook 0,1
    • + +
    • fritzbox-remote-phonebook 0,1
    • If this attribute is activated, the phonebook should be obtained direct from the FritzBox via remote network connection (in case FHEM is not running on a FritzBox). This is only possible if a password (and depending on configuration a username as well) is configured.

      Possible values: 0 => off , 1 => on (use remote connection to obtain FritzBox phonebook)
      Default Value is 0 (off)

      -
    • fritzbox-remote-phonebook-via tr064,web,telnet
    • + +
    • fritzbox-remote-phonebook-via tr064,web,telnet
    • Set the method how the phonebook should be requested via network. When set to "web", the phonebook is obtained from the web interface via HTTP. When set to "telnet", it uses a telnet connection to login and retrieve the phonebook (telnet must be activated via dial shortcode #96*7*). When set to "tr064" the phonebook is obtained via TR-064 SOAP request.

      Possible values: tr064,web,telnet
      Default Value is tr064 (retrieve phonebooks via TR-064 interface)

      -
    • fritzbox-remote-phonebook-exclude <list>
    • - A comma separated list of phonebook id's or names which should be excluded when retrieving all possible phonebooks via web or tr064 method (see attribute fritzbox-remote-phonebook-via). All list possible values is provided by get command showPhonebookIds. This attribute is not applicable when using telnet method to obtain remote phonebook.

      + +
    • fritzbox-remote-phonebook-exclude <list>
    • + A comma separated list of phonebook id's or names which should be excluded when retrieving all possible phonebooks via web or tr064 method (see attribute fritzbox-remote-phonebook-via). All list possible values is provided by get command showPhonebookIds. This attribute is not applicable when using telnet method to obtain remote phonebook.

      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.

      -
    • 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

      -
    • sendKeepAlives (none,5m,10m,15m,30m,1h)
    • + +
    • 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.

      + +
    • 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

      + +
    • sendKeepAlives (none,5m,10m,15m,30m,1h)
    • If activated, FB_CALLMONITOR sends a keep-alive on a regularly basis depending on the configured value. This ensures a working connection when the connected FritzBox is operating behind another NAT-based router (e.g. another FritzBox) so the connection will not be detected as "dead" and therefore blocked.

      Possible values: none,5m,10m,15m,30m,1h
      Default value: none (no keep-alives will be sent)

      - -
    • contactImageDirectory <directory>
    • + +
    • contactImageDirectory <directory>
    • If set, FB_CALLMONITOR generates the reading "contact_image" if a file with the external number as filename is found in this directory (e.g. "0123456567.jpg"). - If no matching file exist in this directory or the external number is unknown, the reading "contact_image" is set to "none" (can be override by attribute contactDefaultImage). + If no matching file exist in this directory or the external number is unknown, the reading "contact_image" is set to "none" (can be override by attribute contactDefaultImage).

      - -
    • contactDefaultImage <filename>
    • + +
    • contactDefaultImage <filename>
    • If set, FB_CALLMONITOR uses the given filename instead of "none" in case no image exists in the configured contact image directory or the external number is unknown.

      -
    • contactImageViaTR064 0,1
    • - If this attribute is activated, FB_CALLMONITOR will download all available contact images from the FritzBox phonebook(s) via TR-064 (if attribute fritzbox-remote-phonebook-via is set to tr064) and will store them in the directory configured by attribute contactImageDirectory. + +
    • contactImageViaTR064 0,1
    • + If this attribute is activated, FB_CALLMONITOR will download all available contact images from the FritzBox phonebook(s) via TR-064 (if attribute fritzbox-remote-phonebook-via is set to tr064) and will store them in the directory configured by attribute contactImageDirectory. The downloaded images will then be used as contact images for the reading "contact_image".

      Possible values: 0 => off , 1 => on
      - Default value is 1 (contact images will be downloaded via TR-064 from FritzBox) + Default value is 1 (contact images will be downloaded via TR-064 from FritzBox)


    - + Generated Events:

    • event (call|ring|connect|disconnect) - which event in detail was triggerd
    • @@ -2567,36 +2797,37 @@ sub FB_CALLMONITOR_sendKeepAlive($)
    • call_duration - The call duration in seconds. Is only generated at a disconnect event. The value 0 means, the call was not taken by anybody.
    • call_id - The call identification number to separate events of two or more different calls at the same time. This id number is equal for all events relating to one specific call.
    • missed_call - This event will be raised in case of a incoming call, which is not answered. If available, also the name of the calling number will be displayed.
    • -
    • contact_image - This event will be raised if attribute contactImageDirectory is configured. It contains the filename of the corresponding contact image filename or "none" if no file exist or external number is unknown.
    • +
    • contact_image - This event will be raised if attribute contactImageDirectory is configured. It contains the filename of the corresponding contact image filename or "none" if no file exist or external number is unknown.
- - +
=end html + =begin html_DE +

FB_CALLMONITOR

    Das Modul FB_CALLMONITOR verbindet sich zu einer AVM FritzBox Fon und verarbeitet - Telefonie-Ereignisse.(eingehende & ausgehende Telefonate) + Telefonie-Ereignisse.(eingehende & ausgehende Telefonate)

    Um dieses Modul nutzen zu können, muss der Callmonitor via Kurzwahl mit einem Telefon aktiviert werden. - .

    +

      #96*5* - Callmonitor aktivieren
      #96*4* - Callmonitor deaktivieren

    - Einfach die entsprechende Kurzwahl auf irgend einem Telefon eingeben, welches an die Fritz!Box angeschlossen ist. + Einfach die entsprechende Kurzwahl auf irgend einem Telefon eingeben, welches an die Fritz!Box angeschlossen ist. 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.

    Dieses Modul funktioniert mit allen Fritz!Box Modellen, welche Telefonie unterstützen (Namenszusatz: Fon).

    - - - Definition + + + Define
      define <name> FB_CALLMONITOR <IP-Addresse>[:Port]

      @@ -2604,58 +2835,94 @@ sub FB_CALLMONITOR_sendKeepAlive($)

    - - Set-Kommandos + + + Set
      -
    • reopen - schliesst die Verbindung zur FritzBox und öffnet sie erneut
    • -
    • rereadCache - Liest den Cache aus der Datei neu ein (sofern konfiguriert, siehe dazu Attribut reverse-search-cache-file)
    • -
    • rereadPhonebook - Liest das Telefonbuch der FritzBox neu ein (per Datei, Telnet oder direkt lokal)
    • -
    • rereadTextfile - Liest die nutzereigene Textdatei neu ein (sofern konfiguriert, siehe dazu Attribut reverse-search-text-file)
    • -
    • password - speichert das FritzBox Passwort, welches für das Einlesen aller Telefonbücher direkt von der FritzBox benötigt wird. Dieses Kommando ist nur verfügbar, wenn ein Passwort benötigt wird um das Telefonbuch via Netzwerk einzulesen, siehe dazu Attribut fritzbox-remote-phonebook.
    • +
    • +
      set <name> reopen
      + schliesst die Verbindung zur FritzBox und öffnet sie erneut +
    • +
    • +
      set <name> rereadCache
      + Liest den Cache aus der Datei neu ein (sofern konfiguriert, siehe dazu Attribut reverse-search-cache-file) +
    • +
    • +
      set <name> rereadPhonebook
      + Liest das Telefonbuch der FritzBox neu ein (per Datei, Telnet oder direkt lokal) +
    • +
    • +
      set <name> rereadTextfile
      + Liest die nutzereigene Textdatei neu ein (sofern konfiguriert, siehe dazu Attribut reverse-search-text-file) +
    • +
    • +
      set <name> password <Passwort>
      + speichert das FritzBox Passwort, welches für das Einlesen aller Telefonbücher direkt von der FritzBox benötigt wird. Dieses Kommando ist nur verfügbar, wenn ein Passwort benötigt wird um das Telefonbuch via Netzwerk einzulesen, siehe dazu Attribut fritzbox-remote-phonebook. +

    - - Get-Kommandos + + Get
      -
    • search <Rufnummer> - gibt den Namen der Telefonnummer zurück (aus Cache, Telefonbuch oder Rückwärtssuche)
    • -
    • showPhonebookIds - gibt eine Liste aller verfügbaren Telefonbücher auf der FritzBox zurück (nicht verfügbar wenn das Telefonbuch via Telnet-Verbindung eingelesen wird)
    • -
    • showPhonebookEntries [Phonebook-ID] - gibt eine Liste aller bekannten Telefonbucheinträge, oder nur eines bestimmten Telefonbuchs, zurück (nur verfügbar, wenn eine Rückwärtssuche via Telefonbuch aktiviert ist)
    • -
    • showCacheEntries - gibt eine Liste aller bekannten Cacheeinträge zurück (nur verfügbar, wenn die Cache-Funktionalität der Rückwärtssuche aktiviert ist))
    • -
    • showTextEntries - gibt eine Liste aller Einträge aus der nutzereigenen Textdatei zurück (nur verfügbar, wenn eine Textdatei als Attribut definiert ist))
    • +
    • +
      get <name> search <phone-number>
      + gibt den Namen der Telefonnummer zurück (aus Cache, Telefonbuch oder Rückwärtssuche) +
    • +
    • +
      get <name> showPhonebookIds
      + gibt eine Liste aller verfügbaren Telefonbücher auf der FritzBox zurück (nicht verfügbar wenn das Telefonbuch via Telnet-Verbindung eingelesen wird) +
    • +
    • +
      get <name> showPhonebookEntries [Phonebook-ID]
      + gibt eine Liste aller bekannten Telefonbucheinträge, oder nur eines bestimmten Telefonbuchs, zurück (nur verfügbar, wenn eine Rückwärtssuche via Telefonbuch aktiviert ist)
    • +
    • +
      get <name> showCacheEntries
      + gibt eine Liste aller bekannten Cacheeinträge zurück (nur verfügbar, wenn die Cache-Funktionalität der Rückwärtssuche aktiviert ist)) +
    • +
    • +
      get <name> showTextEntries
      + gibt eine Liste aller Einträge aus der nutzereigenen Textdatei zurück (nur verfügbar, wenn eine Textdatei als Attribut definiert ist)) +

    - + Attribute

    • do_not_notify
    • +
    • readingFnAttributes

    • -
    • disable 0,1
    • - Optionales Attribut zur Deaktivierung des Callmonitors. Es können dann keine Anruf-Events mehr erkannt und erzeugt werden. -

      - Mögliche Werte: 0 => Callmonitor ist aktiv, 1 => Callmonitor ist deaktiviert.
      - Standardwert ist 0 (aktiv)

      -
    • disabledForIntervals HH:MM-HH:MM HH:MM-HH-MM...
    • + +
    • disable 0,1
    • + Optionales Attribut zur Deaktivierung des Callmonitors. Es können dann keine Anruf-Events mehr erkannt und erzeugt werden. +

      + Mögliche Werte: 0 => Callmonitor ist aktiv, 1 => Callmonitor ist deaktiviert.
      + Standardwert ist 0 (aktiv)

      + +
    • disabledForIntervals HH:MM-HH:MM HH:MM-HH-MM...
    • Optionales Attribut zur Deaktivierung des Callmonitors innerhalb von bestimmten Zeitintervallen. Das Argument ist eine Leerzeichen-getrennte Liste von Minuszeichen-getrennten HH:MM Pärchen (Stunde : Minute). - Falls die aktuelle Uhrzeit zwischen diese Werte fällt, dann wird die Verarbeitung, wie bei disable, ausgesetzt. + Falls die aktuelle Uhrzeit zwischen diese Werte fällt, dann wird die Verarbeitung, wie bei disable, ausgesetzt. Statt HH:MM kann man auch HH oder HH:MM:SS angeben.

      Um einen Intervall um Mitternacht zu spezifizieren, muss man zwei einzelne Intervalle angeben, z.Bsp.:
      23:00-24:00 00:00-01:00
      Standardwert ist nicht gesetzt (dauerhaft aktiv)

      -
    • answMachine-is-missed-call 0,1
    • - Sofern aktiviert, werden Anrufe, welche durch einen internen Anrufbeantworter beantwortet werden, als "unbeantworteter Anruf" gewertet (siehe Reading "missed_call" unter Generated Events). + +
    • answMachine-is-missed-call 0,1
    • + Sofern aktiviert, werden Anrufe, welche durch einen internen Anrufbeantworter beantwortet werden, als "unbeantworteter Anruf" gewertet (siehe Reading "missed_call" unter Generated Events).

      Mögliche Werte: 0 => deaktiviert, 1 => aktiviert (Anrufbeantworter gilt als "unbeantworteter Anruf").

      Standardwert ist 0 (deaktiviert)

      -
    • internal-number-filter <Nummer>[<Nummer>,...]
    • - Sofern gesetzt, werden nur Gespräche für die konfigurierten internen Rufnummern verarbeitet. + +
    • internal-number-filter <Nummer>[<Nummer>,...]
    • + Sofern gesetzt, werden nur Gespräche für die konfigurierten internen Rufnummern verarbeitet. Gültige Werte sind eine einzelne interne Rufnummer oder eine komma-separierte Liste von mehreren internen Rufnummern. - Gespräche für interne Rufnummern, welche nicht in dieser Liste enthalten sind, werden ignoriert und nicht verarbeitet. + Gespräche für interne Rufnummern, welche nicht in dieser Liste enthalten sind, werden ignoriert und nicht verarbeitet. Wenn dieses Attribut nicht konfiguriert ist, werden alle Gespräche regulär verarbeitet.

      Standardmäßig ist diese Funktion deaktiviert (nicht gesetzt)

      -
    • reverse-search (phonebook,dasoertliche.de,11880.com,search.ch,dasschnelle.at,herold.at)
    • + +
    • reverse-search (phonebook,textfile,tellows.de,dasoertliche.de,11880.com,search.ch,dasschnelle.at,herold.at)
    • Aktiviert die Rückwärtssuche der externen Rufnummer (bei eingehenden/ausgehenden Anrufen). Dieses Attribut enthält eine komma-separierte Liste mit allen Anbietern die für eine Rückwärtssuche benutzt werden sollen. Die Rückwärtssuche prüft in der gegebenen Reihenfolge (von links nach rechts) ob der entsprechende Anbieter (Telefonbuch, Textdatei oder Internetanbieter) die Rufnummer auflösen können. @@ -2664,18 +2931,21 @@ sub FB_CALLMONITOR_sendKeepAlive($) Der Anbieter "textfile" verwendet die nutzereigene Textdatei, sofern definiert (siehe Attribut reverse-search-text-file). Der Anbieter "phonebook" verwendet das Telefonbuch der FritzBox (siehe Attribut reverse-search-phonebook-file oder fritzbox-remote-phonebook).

      Standardmäßig ist diese Funktion deaktiviert (nicht gesetzt)

      -
    • reverse-search-cache 0,1
    • + +
    • reverse-search-cache 0,1
    • Wenn dieses Attribut gesetzt ist, werden alle Ergebisse von Internetanbietern in einem modul-internen Cache gespeichert - und alle existierenden Ergebnisse aus dem Cache genutzt anstatt eine erneute Anfrage bei einem Internet-Anbieter durchzuführen. + und alle existierenden Ergebnisse aus dem Cache genutzt anstatt eine erneute Anfrage bei einem Internet-Anbieter durchzuführen. Der Cache ist immer an die Internetanbieter gekoppelt und speichert nur Ergebnisse von Internetanbietern.

      Mögliche Werte: 0 => deaktiviert , 1 => aktiviert
      Standardwert ist 0 (deaktiviert)

      -
    • reverse-search-cache-file <Dateipfad>
    • + +
    • reverse-search-cache-file <Dateipfad>
    • Da der Cache nur im Arbeitsspeicher existiert, ist er nicht persistent und geht beim stoppen von FHEM verloren. - Mit diesem Parameter werden alle Cache-Ergebnisse in eine Textdatei geschrieben (z.B. /usr/share/fhem/telefonbuch.txt) + Mit diesem Parameter werden alle Cache-Ergebnisse in eine Textdatei geschrieben (z.B. /usr/share/fhem/telefonbuch.txt) und beim nächsten Start von FHEM wieder in den Cache geladen und genutzt.

      -
    • reverse-search-text-file <Dateipfad>
    • + +
    • reverse-search-text-file <Dateipfad>
    • Lädt eine nutzereigene Textdatei welche eine eigene Namenszuordnungen für Rufnummern enthält. Diese Datei enthält zeilenweise komma-separierte Werte nach folgendem Schema:
           <Nummer1>,<Name1>
      @@ -2685,85 +2955,103 @@ sub FB_CALLMONITOR_sendKeepAlive($)
           
      Die Datei kann dabei auch Kommentar-Zeilen enthalten mit # vorangestellt. Sollte die Datei nicht existieren, wird sie durch FHEM erstellt.

      -
    • reverse-search-phonebook-file <Dateipfad>
    • + +
    • reverse-search-phonebook-file <Dateipfad>
    • Mit diesem Attribut kann man optional den Pfad zu einer Datei angeben, welche ein Telefonbuch im FritzBox-Format (XML-Struktur) enthält. Dadurch ist es möglich ein FritzBox-Telefonbuch zu verwenden, ohne das FHEM auf einer FritzBox laufen muss. Sofern FHEM auf einer FritzBox läuft (und nichts abweichendes angegeben wurde), wird das interne File /var/flash/phonebook verwendet. Alternativ kann man das Telefonbuch in der FritzBox-Weboberfläche exportieren und dieses verwenden

      Standardwert ist /var/flash/phonebook (entspricht dem Pfad auf einer FritzBox)

      -
    • remove-leading-zero 0,1
    • + +
    • reverse-search-tellows-api-key <api-key>
    • + tellows api-key. Für Tests kann der api-key -test123- eingetragen werden

      + +
    • reverse-search-tellows-api-partner <api-partner>
    • + tellows api-partner. Für Tests kann der api-partner -test- eingetragen werden

      + +
    • remove-leading-zero 0,1
    • Wenn dieses Attribut aktiviert ist, wird die führende Null aus der externen Rufnummer (bei eingehenden & abgehenden Anrufen) entfernt. Dies ist z.B. notwendig bei Telefonanlagen.

      Mögliche Werte: 0 => deaktiviert , 1 => aktiviert
      Standardwert ist 0 (deaktiviert)

      -
    • unique-call-ids 0,1
    • + +
    • unique-call-ids 0,1
    • Wenn dieses Attribut aktiviert ist, wird für jedes Gespräch eine eineindeutige Identifizierungsnummer verwendet. Dadurch lassen sich auch bereits beendete Gespräche voneinander unterscheiden. Dies ist z.B. notwendig bei der Verarbeitung der Events durch eine Datenbank.

      Mögliche Werte: 0 => deaktiviert , 1 => aktiviert
      Standardwert ist 0 (deaktiviert)

      -
    • local-area-code <Ortsvorwahl>
    • + +
    • local-area-code <Ortsvorwahl>
    • Verwendet die gesetze Vorwahlnummer bei Rückwärtssuchen von Ortsgesprächen (z.B. 0228 für Bonn)

      -
    • country-code <Landesvorwahl>
    • + +
    • country-code <Landesvorwahl>
    • Die Landesvorwahl wird benötigt um Telefonbucheinträge mit lokaler Landesvorwahl als Inlands-Rufnummern, als auch um Call-By-Call-Vorwahlen richtig zu erkennen (z.B. 0049 für Deutschland, 0043 für Österreich oder 001 für USA).

      Standardwert ist 0049 (Deutschland)

      -
    • check-deflections 0,1
    • - Wenn dieses Attribut aktiviert ist, werden eingehende Anrufe gegen die konfigurierten Rufsperren-Regeln aus der FritzBox geprüft. Wenn ein Anruf auf eine dieser Regeln passt, wird der Anruf ignoriert und es werden keinerlei Readings/Events für diesen Anruf generiert. Dies funktioniert nur, wenn man das Telefonbuch aus der FritzBox via TR-064 einliest (siehe Attribute fritzbox-remote-phonebook und fritzbox-remote-phonebook-via).

      + +
    • check-deflections 0,1
    • + Wenn dieses Attribut aktiviert ist, werden eingehende Anrufe gegen die konfigurierten Rufsperren-Regeln aus der FritzBox geprüft. Wenn ein Anruf auf eine dieser Regeln passt, wird der Anruf ignoriert und es werden keinerlei Readings/Events für diesen Anruf generiert. Dies funktioniert nur, wenn man das Telefonbuch aus der FritzBox via TR-064 einliest (siehe Attribute fritzbox-remote-phonebook und fritzbox-remote-phonebook-via).

      Mögliche Werte: 0 => deaktiviert , 1 => aktiviert
      Standardwert ist 0 (deaktiviert)

      -
    • fritzbox-remote-phonebook 0,1
    • + +
    • fritzbox-remote-phonebook 0,1
    • Wenn dieses Attribut aktiviert ist, wird das FritzBox Telefonbuch direkt von der FritzBox gelesen. Dazu ist das FritzBox Passwort und je nach FritzBox Konfiguration auch ein Username notwendig, der in den entsprechenden Attributen konfiguriert sein muss.

      Mögliche Werte: 0 => deaktiviert , 1 => aktiviert
      - Standardwert ist 0 (deaktiviert)

      -
    • fritzbox-remote-phonebook-via tr064,web,telnet
    • + Standardwert ist 0 (deaktiviert)

      + +
    • fritzbox-remote-phonebook-via tr064,web,telnet
    • Setzt die Methode mit der das Telefonbuch von der FritzBox abgefragt werden soll. Bei der Methode "web", werden alle verfügbaren Telefonbücher (lokales sowie alle konfigurierten Online-Telefonbücher) über die Web-Oberfläche eingelesen. Bei der Methode "telnet" wird eine Telnet-Verbindung zur FritzBox aufgebaut um das lokale Telefonbuch abzufragen (keine Online-Telefonbücher). Dazu muss die Telnet-Funktion aktiviert sein (Telefon Kurzwahl: #96*7*). Bei der Methode "tr064" werden alle verfügbaren Telefonbücher über die TR-064 SOAP Schnittstelle ausgelesen.

      Mögliche Werte: tr064,web,telnet
      Standardwert ist "tr064" (Abfrage aller verfügbaren Telefonbücher über die TR-064-Schnittstelle)

      -
    • fritzbox-remote-phonebook-exclude <Liste>
    • - Eine komma-separierte Liste von Telefonbuch-ID's oder Namen welche beim einlesen übersprungen werden sollen. Dieses Attribut greift nur beim einlesen der Telefonbücher via "web"- oder "tr064"-Methode (siehe Attribut fritzbox-remote-phonebook-via). Eine Liste aller möglichen Werte kann über das Get-Kommando showPhonebookIds angezeigt werden.

      + +
    • fritzbox-remote-phonebook-exclude <Liste>
    • + Eine komma-separierte Liste von Telefonbuch-ID's oder Namen welche beim einlesen übersprungen werden sollen. Dieses Attribut greift nur beim einlesen der Telefonbücher via "web"- oder "tr064"-Methode (siehe Attribut fritzbox-remote-phonebook-via). Eine Liste aller möglichen Werte kann über das Get-Kommando showPhonebookIds angezeigt werden.

      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.

      -
    • 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

      -
    • sendKeepAlives (none,5m,10m,15m,30m,1h)
    • + +
    • 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.

      +
    • 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

      + +
    • sendKeepAlives (none,5m,10m,15m,30m,1h)
    • Wenn dieses Attribut gesetzt ist, wird ein zyklisches Keep-Alive im konfigurierten Zeitabstand an die FritzBox gesendet um die Verbindung aktiv zu halten. Dadurch bleibt die Verbindung bestehen, insbesondere wenn die verbundene FritzBox sich hinter einem weiteren NAT-Router befindet (z.B. einer weiteren FritzBox). Dadurch wird die Verbindung in so einem Fall nicht fälschlicherweise als "tot" erkannt und geblockt.

      Mögliche Werte: none,5m,10m,15m,30m,1h
      Standardwert ist "none" (es werden keine Keep-Alives gesendet)

      - -
    • contactImageDirectory <Verzeichnis>
    • + +
    • contactImageDirectory <Verzeichnis>
    • Sofern gesetzt, generiert FB_CALLMONITOR das Reading "contact_image" sofern eine Datei mit der externen Rufnummer als Dateinamen (z.B. "012323456.jpg") in diesem Verzeichnis existiert. - Wenn keine passende Datei in dem Verzeichnis existiert oder die externe Rufnummer unterdrückt ist, wird das Reading "contact_image" auf den Wert "none" gesetzt (kann mit dem Attribut contactDefaultImage geändert werden) + Wenn keine passende Datei in dem Verzeichnis existiert oder die externe Rufnummer unterdrückt ist, wird das Reading "contact_image" auf den Wert "none" gesetzt (kann mit dem Attribut contactDefaultImage geändert werden)

      - -
    • contactDefaultImage <Dateiname>
    • + +
    • contactDefaultImage <Dateiname>
    • Sofern gesetzt, verwendet FB_CALLMONITOR den gesetzten Dateinamen anstelle von "none", sollte keine passende Datei zu einer Rufnummer existieren oder die Rufnummer unterdrückt sein.

      - -
    • contactImageViaTR064 0,1
    • - Wenn dieses Attribut aktiviert ist, lädt FB_CALLMONITOR alle verfügbaren Kontaktbilder aus dem FritzBox Telefonbüchern via TR-064 (if attribute fritzbox-remote-phonebook-via is set to tr064) und speichert diese in dem Verzeichnis contactImageDirectory. + +
    • contactImageViaTR064 0,1
    • + Wenn dieses Attribut aktiviert ist, lädt FB_CALLMONITOR alle verfügbaren Kontaktbilder aus dem FritzBox Telefonbüchern via TR-064 (if attribute fritzbox-remote-phonebook-via is set to tr064) und speichert diese in dem Verzeichnis contactImageDirectory. Die heruntergeladenen Kontaktbilder werden dann automatisch für das Reading "contact_image" verwendet.

      Mögliche Werte: 0 => deaktiviert , 1 => aktiviert
      - Standardwert ist 1 (aktiviert)

      -
    + Standardwert ist 1 (aktiviert)

    +
+

- + + Generierte Events:

    -
  • event (call|ring|connect|disconnect) - Welches Event wurde genau ausgelöst. ("call" => ausgehender Rufversuch, "ring" => eingehender Rufversuch, "connect" => Gespräch ist zustande gekommen, "disconnect" => es wurde aufgelegt)
  • -
  • direction (incoming|outgoing) - Die Anruf-Richtung ("incoming" => eingehender Anruf, "outgoing" => ausgehender Anruf)
  • -
  • external_number - Die Rufnummer des Gegenübers, welcher anruft (event: ring) oder angerufen wird (event: call)
  • -
  • external_name - Das Ergebniss der Rückwärtssuche (sofern aktiviert). Im Fehlerfall kann diese Reading auch den Inhalt "unknown" (keinen Eintrag gefunden) enthalten. Im Falle einer Zeitüberschreitung bei der Rückwärtssuche und aktiviertem Caching, wird die Rufnummer beim nächsten Mal erneut gesucht.
  • -
  • internal_number - Die interne Rufnummer (Festnetz, VoIP-Nummer, ...) auf welcher man angerufen wird (event: ring) oder die man gerade nutzt um jemanden anzurufen (event: call)
  • -
  • internal_connection - Der interne Anschluss an der Fritz!Box welcher genutzt wird um das Gespräch durchzuführen (FON1, FON2, ISDN, DECT, ...)
  • -
  • external_connection - Der externe Anschluss welcher genutzt wird um das Gespräch durchzuführen ("POTS" => analoges Festnetz, "SIPx" => VoIP Nummer, "ISDN", "GSM" => Mobilfunk via GSM/UMTS-Stick)
  • -
  • calls_count - Die Anzahl aller aktiven Verbindungen (gleichzeitig). Ist der Wert 0, so wird gerade kein Gespräch geführt.
  • -
  • call_duration - Die Gesprächsdauer in Sekunden. Dieser Wert wird nur bei einem disconnect-Event erzeugt. Ist der Wert 0, so wurde das Gespräch von niemandem angenommen.
  • -
  • call_id - Die Identifizierungsnummer eines einzelnen Gesprächs. Dient der Zuordnung bei zwei oder mehr parallelen Gesprächen, damit alle Events eindeutig einem Gespräch zugeordnet werden können
  • -
  • missed_call - Dieses Event wird nur generiert, wenn ein eingehender Anruf nicht beantwortet wird. Sofern der Name dazu bekannt ist, wird dieser ebenfalls mit angezeigt.
  • -
  • contact_image - Dieses Event wird nur generiert, wenn das Attribut contactImageDirectory gesetzt ist. Es enthält das zugehörige Kontaktfoto als Dateiname oder "none", falls kein entsprechendes Kontaktfoto existiert, oder die Rufnummer unterdrückt ist.
  • - -
+
  • event (call|ring|connect|disconnect) - Welches Event wurde genau ausgelöst. ("call" => ausgehender Rufversuch, "ring" => eingehender Rufversuch, "connect" => Gespräch ist zustande gekommen, "disconnect" => es wurde aufgelegt)
  • +
  • direction (incoming|outgoing) - Die Anruf-Richtung ("incoming" => eingehender Anruf, "outgoing" => ausgehender Anruf)
  • +
  • external_number - Die Rufnummer des Gegenübers, welcher anruft (event: ring) oder angerufen wird (event: call)
  • +
  • external_name - Das Ergebniss der Rückwärtssuche (sofern aktiviert). Im Fehlerfall kann diese Reading auch den Inhalt "unknown" (keinen Eintrag gefunden) enthalten. Im Falle einer Zeitüberschreitung bei der Rückwärtssuche und aktiviertem Caching, wird die Rufnummer beim nächsten Mal erneut gesucht.
  • +
  • internal_number - Die interne Rufnummer (Festnetz, VoIP-Nummer, ...) auf welcher man angerufen wird (event: ring) oder die man gerade nutzt um jemanden anzurufen (event: call)
  • +
  • internal_connection - Der interne Anschluss an der Fritz!Box welcher genutzt wird um das Gespräch durchzuführen (FON1, FON2, ISDN, DECT, ...)
  • +
  • external_connection - Der externe Anschluss welcher genutzt wird um das Gespräch durchzuführen ("POTS" => analoges Festnetz, "SIPx" => VoIP Nummer, "ISDN", "GSM" => Mobilfunk via GSM/UMTS-Stick)
  • +
  • calls_count - Die Anzahl aller aktiven Verbindungen (gleichzeitig). Ist der Wert 0, so wird gerade kein Gespräch geführt.
  • +
  • call_duration - Die Gesprächsdauer in Sekunden. Dieser Wert wird nur bei einem disconnect-Event erzeugt. Ist der Wert 0, so wurde das Gespräch von niemandem angenommen.
  • +
  • call_id - Die Identifizierungsnummer eines einzelnen Gesprächs. Dient der Zuordnung bei zwei oder mehr parallelen Gesprächen, damit alle Events eindeutig einem Gespräch zugeordnet werden können
  • +
  • missed_call - Dieses Event wird nur generiert, wenn ein eingehender Anruf nicht beantwortet wird. Sofern der Name dazu bekannt ist, wird dieser ebenfalls mit angezeigt.
  • +
  • contact_image - Dieses Event wird nur generiert, wenn das Attribut contactImageDirectory gesetzt ist. Es enthält das zugehörige Kontaktfoto als Dateiname oder "none", falls kein entsprechendes Kontaktfoto existiert, oder die Rufnummer unterdrückt ist.
  • + - +
    =end html_DE =cut