2
0
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:
justme-1968 2013-09-11 21:12:08 +00:00
parent 18c5fb9123
commit 4b3f5267fe
3 changed files with 414 additions and 0 deletions

View File

@ -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
View 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 &lt;name&gt; mailcheck &lt;host&gt; &lt;user&gt; [&lt;folder&gt;]</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

View File

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