mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-01-31 12:49:34 +00:00
new module 32_mailcheck.pm
git-svn-id: https://svn.fhem.de/fhem/trunk@3894 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
18c5fb9123
commit
4b3f5267fe
@ -1,4 +1,5 @@
|
|||||||
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
|
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
|
||||||
|
- feature: new module 32_mailcheck.pm (by justme1968)
|
||||||
- feature: TCM: new commands added
|
- feature: TCM: new commands added
|
||||||
- bugfix: TCM: TCM_ReadAnswer(): response error corrected
|
- bugfix: TCM: TCM_ReadAnswer(): response error corrected
|
||||||
- feature: readingsGroup: new attribute nolinks
|
- feature: readingsGroup: new attribute nolinks
|
||||||
|
412
fhem/FHEM/32_mailcheck.pm
Executable file
412
fhem/FHEM/32_mailcheck.pm
Executable file
@ -0,0 +1,412 @@
|
|||||||
|
|
||||||
|
# $Id$
|
||||||
|
|
||||||
|
# basic idea from https://github.com/justinribeiro/idlemailcheck
|
||||||
|
|
||||||
|
package main;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use Mail::IMAPClient;
|
||||||
|
use IO::Socket::SSL;
|
||||||
|
use IO::File;
|
||||||
|
use IO::Handle;
|
||||||
|
|
||||||
|
sub
|
||||||
|
mailcheck_Initialize($)
|
||||||
|
{
|
||||||
|
my ($hash) = @_;
|
||||||
|
|
||||||
|
$hash->{ReadFn} = "mailcheck_Read";
|
||||||
|
|
||||||
|
$hash->{DefFn} = "mailcheck_Define";
|
||||||
|
$hash->{NotifyFn} = "mailcheck_Notify";
|
||||||
|
$hash->{UndefFn} = "mailcheck_Undefine";
|
||||||
|
#$hash->{SetFn} = "mailcheck_Set";
|
||||||
|
$hash->{GetFn} = "mailcheck_Get";
|
||||||
|
$hash->{AttrFn} = "mailcheck_Attr";
|
||||||
|
$hash->{AttrList} = "debug:1 ".
|
||||||
|
"delete_message:1 ".
|
||||||
|
"disable:1 ".
|
||||||
|
"intervall ".
|
||||||
|
"logfile ".
|
||||||
|
$readingFnAttributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
#####################################
|
||||||
|
|
||||||
|
sub
|
||||||
|
mailcheck_Define($$)
|
||||||
|
{
|
||||||
|
my ($hash, $def) = @_;
|
||||||
|
|
||||||
|
my @a = split("[ \t][ \t]*", $def);
|
||||||
|
|
||||||
|
return "Usage: define <name> mailcheck host user password [folder]" if(@a < 5);
|
||||||
|
|
||||||
|
my $name = $a[0];
|
||||||
|
|
||||||
|
my $host = $a[2];
|
||||||
|
my $user = $a[3];
|
||||||
|
my $password = $a[4];
|
||||||
|
my $folder = $a[5];
|
||||||
|
|
||||||
|
$hash->{tag} = undef;
|
||||||
|
|
||||||
|
$hash->{NAME} = $name;
|
||||||
|
|
||||||
|
$hash->{Host} = $host;
|
||||||
|
$hash->{User} = $user;
|
||||||
|
$hash->{helper}{PASS} = $password;
|
||||||
|
|
||||||
|
$hash->{Folder} = "INBOX";
|
||||||
|
$hash->{Folder} = $folder if( $folder );
|
||||||
|
|
||||||
|
if( $hash->{STATE} eq "???" ) {
|
||||||
|
$hash->{STATE} = "Initialized";
|
||||||
|
} elsif( $hash->{STATE} ne "???" ) {
|
||||||
|
mailcheck_Disconnect($hash);
|
||||||
|
mailcheck_Connect($hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub
|
||||||
|
mailcheck_Notify($$)
|
||||||
|
{
|
||||||
|
my ($hash,$dev) = @_;
|
||||||
|
|
||||||
|
if( grep(m/^INITIALIZED$/, @{$dev->{CHANGED}}) ) {
|
||||||
|
delete $hash->{NotifyFn};
|
||||||
|
|
||||||
|
mailcheck_Connect($hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub
|
||||||
|
mailcheck_Connect($)
|
||||||
|
{
|
||||||
|
my ($hash) = @_;
|
||||||
|
my $name = $hash->{NAME};
|
||||||
|
|
||||||
|
return undef if( AttrVal($name, "disable", 0 ) == 1 );
|
||||||
|
|
||||||
|
my $socket = IO::Socket::SSL->new(
|
||||||
|
PeerAddr => $hash->{Host},
|
||||||
|
PeerPort => 993, #AttrVal($name, "port", 993).
|
||||||
|
);
|
||||||
|
|
||||||
|
if($socket) {
|
||||||
|
$hash->{STATE} = "Connected";
|
||||||
|
$hash->{LAST_CONNECT} = FmtDateTime( gettimeofday() );
|
||||||
|
|
||||||
|
$hash->{FD} = $socket->fileno();
|
||||||
|
$hash->{CD} = $socket; # sysread / close won't work on fileno
|
||||||
|
$hash->{CONNECTS}++;
|
||||||
|
$selectlist{$name} = $hash;
|
||||||
|
Log3 $name, 3, "$name: connected to $hash->{Host}";
|
||||||
|
|
||||||
|
my $client = Mail::IMAPClient->new(
|
||||||
|
Socket => $socket,
|
||||||
|
KeepAlive => 'true',
|
||||||
|
User => $hash->{User},
|
||||||
|
Password => $hash->{helper}{PASS},
|
||||||
|
);
|
||||||
|
|
||||||
|
$client->Debug(AttrVal($name, "debug", 0)) if( $client );
|
||||||
|
$client->Debug_fh($hash->{FH}) if( $client && defined($hash->{FH}) );
|
||||||
|
|
||||||
|
if( $client && $client->IsConnected && $client->IsAuthenticated ) {
|
||||||
|
$hash->{STATE} = "Logged in";
|
||||||
|
$hash->{LAST_LOGIN} = FmtDateTime( gettimeofday() );
|
||||||
|
|
||||||
|
$hash->{CLIENT} = $client;
|
||||||
|
Log3 $name, 3, "$name: logged in to $hash->{User}";
|
||||||
|
|
||||||
|
$hash->{HAS_IDLE} = $client->has_capability("IDLE");
|
||||||
|
|
||||||
|
my $intervall = AttrVal($name, "intervall", 0);
|
||||||
|
$intervall = $hash->{HAS_IDLE}?60*10:60*1 if( !$intervall );
|
||||||
|
$hash->{INTERVAL} = $intervall;
|
||||||
|
|
||||||
|
RemoveInternalTimer($hash);
|
||||||
|
InternalTimer(gettimeofday()+$hash->{INTERVAL}, "mailcheck_poll", $hash, 1);
|
||||||
|
|
||||||
|
#if( !$client->has_capability("IDLE") ) {
|
||||||
|
#mailcheck_Disconnect($hash);
|
||||||
|
#$hash->{STATE} = "IDLE not supported";
|
||||||
|
#return undef;
|
||||||
|
#}
|
||||||
|
|
||||||
|
$client->Uid(0);
|
||||||
|
$client->select($hash->{Folder});
|
||||||
|
|
||||||
|
$hash->{tag} = $client->idle;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
mailcheck_Disconnect($hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sub
|
||||||
|
mailcheck_Disconnect($)
|
||||||
|
{
|
||||||
|
my ($hash) = @_;
|
||||||
|
my $name = $hash->{NAME};
|
||||||
|
|
||||||
|
RemoveInternalTimer($hash);
|
||||||
|
|
||||||
|
return if( !$hash->{CD} );
|
||||||
|
|
||||||
|
my $client = $hash->{CLIENT};
|
||||||
|
$client->done if($client && $client->IsAuthenticated );
|
||||||
|
$client->logout if($client && $client->IsConnected);
|
||||||
|
delete $hash->{CLIENT};
|
||||||
|
$hash->{tag} = undef;
|
||||||
|
Log3 $name, 3, "$name: logged out";
|
||||||
|
|
||||||
|
close($hash->{CD}) if($hash->{CD});
|
||||||
|
delete($hash->{FD});
|
||||||
|
delete($hash->{CD});
|
||||||
|
delete($selectlist{$name});
|
||||||
|
$hash->{STATE} = "Disconnected";
|
||||||
|
Log3 $name, 3, "$name: Disconnected";
|
||||||
|
$hash->{LAST_DISCONNECT} = FmtDateTime( gettimeofday() );
|
||||||
|
}
|
||||||
|
|
||||||
|
sub
|
||||||
|
mailcheck_Undefine($$)
|
||||||
|
{
|
||||||
|
my ($hash, $arg) = @_;
|
||||||
|
|
||||||
|
mailcheck_Disconnect($hash);
|
||||||
|
close( $hash->{FH} );
|
||||||
|
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub
|
||||||
|
mailcheck_Set($$@)
|
||||||
|
{
|
||||||
|
my ($hash, $name, $cmd) = @_;
|
||||||
|
|
||||||
|
my $list = "";
|
||||||
|
return "Unknown argument $cmd, choose one of $list";
|
||||||
|
}
|
||||||
|
|
||||||
|
sub
|
||||||
|
mailcheck_poll($)
|
||||||
|
{
|
||||||
|
my ($hash) = @_;
|
||||||
|
|
||||||
|
RemoveInternalTimer($hash);
|
||||||
|
InternalTimer(gettimeofday()+$hash->{INTERVAL}, "mailcheck_poll", $hash, 1);
|
||||||
|
|
||||||
|
my $client = $hash->{CLIENT};
|
||||||
|
if( $client && $client->IsConnected && $client->IsAuthenticated ) {
|
||||||
|
$client->done;
|
||||||
|
$client->select($hash->{Folder});
|
||||||
|
$hash->{tag} = $client->idle;
|
||||||
|
$hash->{LAST_POLL} = FmtDateTime( gettimeofday() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub
|
||||||
|
mailcheck_Get($$@)
|
||||||
|
{
|
||||||
|
my ($hash, $name, $cmd) = @_;
|
||||||
|
|
||||||
|
my $list = "folders:noArg update:noArg";
|
||||||
|
|
||||||
|
my $client = $hash->{CLIENT};
|
||||||
|
if( $cmd eq "folders" ) {
|
||||||
|
if( $client && $client->IsConnected && $client->IsAuthenticated ) {
|
||||||
|
$client->done;
|
||||||
|
my @folders = $client->folders;
|
||||||
|
$hash->{tag} = $client->idle;
|
||||||
|
return join( "\n", @folders );
|
||||||
|
}
|
||||||
|
return "not connected";
|
||||||
|
} elsif( $cmd eq "update" ) {
|
||||||
|
mailcheck_poll($hash);
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "Unknown argument $cmd, choose one of $list";
|
||||||
|
}
|
||||||
|
|
||||||
|
sub
|
||||||
|
mailcheck_Attr($$$)
|
||||||
|
{
|
||||||
|
my ($cmd, $name, $attrName, $attrVal) = @_;
|
||||||
|
|
||||||
|
my $orig = $attrVal;
|
||||||
|
$attrVal = int($attrVal) if($attrName eq "intervall");
|
||||||
|
$attrVal = 60 if($attrName eq "intervall" && $attrVal < 60 && $attrVal != 0);
|
||||||
|
|
||||||
|
if( $attrName eq "debug" ) {
|
||||||
|
$attrVal = 1 if($attrVal);
|
||||||
|
|
||||||
|
my $hash = $defs{$name};
|
||||||
|
my $client = $hash->{CLIENT};
|
||||||
|
$client->Debug($attrVal) if( $client );
|
||||||
|
} elsif( $attrName eq "logfile" ) {
|
||||||
|
my $hash = $defs{$name};
|
||||||
|
|
||||||
|
close( $hash->{FH} );
|
||||||
|
delete $hash->{FH};
|
||||||
|
delete $hash->{currentlogfile};
|
||||||
|
|
||||||
|
if( $cmd eq "set" ) {
|
||||||
|
my @t = localtime;
|
||||||
|
my $f = ResolveDateWildcards($attrVal, @t);
|
||||||
|
my $fh = new IO::File ">>$f";
|
||||||
|
if( defined($fh) ) {
|
||||||
|
Log3 $name, 3, "$name: logging to $f";
|
||||||
|
|
||||||
|
$fh->autoflush(1);
|
||||||
|
|
||||||
|
$hash->{FH} = $fh;
|
||||||
|
$hash->{currentlogfile} = $f;
|
||||||
|
|
||||||
|
my $client = $hash->{CLIENT};
|
||||||
|
$client->Debug_fh($fh) if( $client );
|
||||||
|
} else {
|
||||||
|
Log3 $name, 3, "$name: can't open log file $f";
|
||||||
|
|
||||||
|
my $client = $hash->{CLIENT};
|
||||||
|
$client->Debug_fh(*STDERR) if( $client );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( $cmd eq "set" ) {
|
||||||
|
if( $orig ne $attrVal ) {
|
||||||
|
$attr{$name}{$attrName} = $attrVal;
|
||||||
|
return $attrName ." set to ". $attrVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub
|
||||||
|
mailcheck_Read($)
|
||||||
|
{
|
||||||
|
my ($hash) = @_;
|
||||||
|
my $name = $hash->{NAME};
|
||||||
|
|
||||||
|
my $client = $hash->{CLIENT};
|
||||||
|
|
||||||
|
my $ret = $client->idle_data();
|
||||||
|
#Log3 $name, 4, Dumper $ret;
|
||||||
|
|
||||||
|
if( !defined($ret) || !$ret ) {
|
||||||
|
$hash->{tag} = undef;
|
||||||
|
$ret = $client->done;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach my $resp (@$ret) {
|
||||||
|
$resp =~ s/\015?\012$//;
|
||||||
|
if ( $resp =~ /^\*\s+(\d+)\s+(EXISTS)\b/ ) {
|
||||||
|
$resp =~ s/\D//g;
|
||||||
|
|
||||||
|
$client->done;
|
||||||
|
|
||||||
|
my $msg_count = $client->unseen_count||0;
|
||||||
|
if ($msg_count > 0) {
|
||||||
|
my $from = $client->get_header($resp, "From");
|
||||||
|
$from =~ s/<[^>]*>//g; #strip the email, only display the sender's name
|
||||||
|
|
||||||
|
my $subject = $client->get_header($resp, "Subject");
|
||||||
|
|
||||||
|
readingsSingleUpdate($hash, "Subject", $subject, 1 );
|
||||||
|
|
||||||
|
$client->delete_message( $resp ) if( AttrVal($name, "delete_message", 0) == 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
$client->idle;
|
||||||
|
|
||||||
|
} elsif ( $resp =~ /^\*\s+(BYE)/ ) {
|
||||||
|
mailcheck_Disconnect($hash);
|
||||||
|
mailcheck_Connect($hash);
|
||||||
|
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$hash->{tag} ||= $client->idle;
|
||||||
|
|
||||||
|
unless ( $client->IsConnected ) {
|
||||||
|
mailcheck_Disconnect($hash);
|
||||||
|
mailcheck_Connect($hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
1;
|
||||||
|
|
||||||
|
=pod
|
||||||
|
=begin html
|
||||||
|
|
||||||
|
<a name="mailcheck"></a>
|
||||||
|
<h3>mailcheck</h3>
|
||||||
|
<ul>
|
||||||
|
Watches a mailbox with imap idle.<br><br>
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
<ul>
|
||||||
|
<li>Mail::IMAPClient and IO::Socket::SSL hast to be installed on the FHEM host.</li>
|
||||||
|
<li>Probably only works reliably if no other mail programm is marking messages as read at the same time.</li>
|
||||||
|
</ul><br>
|
||||||
|
|
||||||
|
<a name="mailcheck_Define"></a>
|
||||||
|
<b>Define</b>
|
||||||
|
<ul>
|
||||||
|
<code>define <name> mailcheck <host> <user> [<folder>]</code><br>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
Defines a mailcheck device that waits for new messages and triggers an event with the mail subject.<br><br>
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
<ul>
|
||||||
|
<code>define mailcheck mailcheck imap.mail.me.com x.y@me.com</code><br>
|
||||||
|
</ul>
|
||||||
|
</ul><br>
|
||||||
|
|
||||||
|
<a name="mailcheck_Readings"></a>
|
||||||
|
<b>Readings</b>
|
||||||
|
<ul>
|
||||||
|
<li>Subject</br>
|
||||||
|
the subject of the last mail received</li>
|
||||||
|
</ul><br>
|
||||||
|
|
||||||
|
<a name="mailcheck_Set"></a>
|
||||||
|
<b>Get</b>
|
||||||
|
<ul>
|
||||||
|
<li>update<br>
|
||||||
|
trigger an update</li>
|
||||||
|
<li>folders<br>
|
||||||
|
list available folders</li>
|
||||||
|
</ul><br>
|
||||||
|
|
||||||
|
<a name="mailcheck_Attr"></a>
|
||||||
|
<b>Attributes</b>
|
||||||
|
<ul>
|
||||||
|
<li>delete_message<br>
|
||||||
|
1 -> delete message after Subject reading is created</li>
|
||||||
|
<li>intervall<br>
|
||||||
|
the intervall in seconds used to trigger an update on the connection.
|
||||||
|
if idle is supported the defailt is 600, without idle support the default is 60. the minimum is 60.</li><br>
|
||||||
|
<li>debug<br>
|
||||||
|
1 -> enables debug output. default target is stdout.</li>
|
||||||
|
<li>logfile<br>
|
||||||
|
set the target for debug messages if debug is enabled.</li>
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
=end html
|
||||||
|
=cut
|
@ -85,6 +85,7 @@ FHEM/30_HUEBridge.pm justme1968 http://forum.fhem.de Sonstige
|
|||||||
FHEM/31_HUEDevice.pm justme1968 http://forum.fhem.de Sonstige Systeme
|
FHEM/31_HUEDevice.pm justme1968 http://forum.fhem.de Sonstige Systeme
|
||||||
FHEM/31_LightScene.pm justme1968 http://forum.fhem.de Automatisierung
|
FHEM/31_LightScene.pm justme1968 http://forum.fhem.de Automatisierung
|
||||||
FHEM/32_SYSSTAT.pm justme1968 http://forum.fhem.de Unterstützende Dienste
|
FHEM/32_SYSSTAT.pm justme1968 http://forum.fhem.de Unterstützende Dienste
|
||||||
|
FHEM/32_mailcheck.pm justme1968 http://forum.fhem.de Automatisierung
|
||||||
FHEM/33_readingsGroup.pm justme1968 http://forum.fhem.de Frontends
|
FHEM/33_readingsGroup.pm justme1968 http://forum.fhem.de Frontends
|
||||||
FHEM/32_speedtest.pm justme1968 http://forum.fhem.de Sonstiges
|
FHEM/32_speedtest.pm justme1968 http://forum.fhem.de Sonstiges
|
||||||
FHEM/34_panStamp.pm justme1968 http://forum.fhem.de Sonstiges Systeme
|
FHEM/34_panStamp.pm justme1968 http://forum.fhem.de Sonstiges Systeme
|
||||||
|
Loading…
Reference in New Issue
Block a user