2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-01-31 18:59:33 +00:00

MSG: Replace file and mail related code with delegates

MSGFile: Assimilate file related code from 75_MSG 
         to make it standalone, without requiring MSG device
MSGMail: Assimilate mail related code from 75_MSG
         to make it standalone, without requiring MSG device


git-svn-id: https://svn.fhem.de/fhem/trunk@8546 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
gandy92 2015-05-08 19:04:39 +00:00
parent 9f18e906a1
commit 6835b464c3
4 changed files with 389 additions and 376 deletions

View File

@ -1,5 +1,10 @@
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
# Do not insert empty lines here, update check depends on it.
- change: MSG: Replace file and mail related code with delegates
- change: MSGFile: Assimilate file related code from 75_MSG
to make it standalone, without requiring MSG device
- change: MSGMail: Assimilate mail related code from 75_MSG
to make it standalone, without requiring MSG device
- bugfix: MSG: Determine which SSL implementation to use for sending mail
(required for libnet-3.06)
- change: MilightDevice/MilightBridge: Fixes, features, changes (by MarkusM)

View File

@ -4,6 +4,9 @@
#
# History:
#
# 2015-05-09: Move mail related code to MSGMail,
# and file related code to MSGFile,
# rewrite to use delegates for compatibility
# 2015-05-07: Determine which SSL implementation to use
# 2015-05-06: Tidy up code for restructuring
# 2015-05-05: Remove dependency on Switch
@ -13,19 +16,12 @@ package main;
use strict;
use warnings;
use MIME::Lite;
#use Net::SMTP::SSL;
use Net::SMTP; # libnet-3.06 has SSL included, so we need to check the version
my %sets = (
"send" => "MSG",
"write" => "MSG",
);
my $MSGMail_SSL = 0;
my $MSGMail_SMTP = 0;
sub MSG_Initialize($)
{
my ($hash) = @_;
@ -33,54 +29,6 @@ sub MSG_Initialize($)
$hash->{SetFn} = "MSG_Set";
$hash->{DefFn} = "MSG_Define";
$hash->{AttrList} = "loglevel:0,1,2,3,4,5,6";
my $name = "MSG";
# check version of libnet - if < 3.00, try to load Net::SMTP::SSL
$MSGMail_SMTP = $Net::SMTP::VERSION;
if ($Net::SMTP::VERSION >= 3)
{
$MSGMail_SSL = 1;
}
else
{
eval "use Net::SMTP::SSL";
if ($@)
{
Log 0, $@ if($@);
$MSGMail_SSL = 0;
}
else
{
$MSGMail_SSL = 1;
}
}
Log 2, "$name: SSL is ".(($MSGMail_SSL) ? ("available, provided by Net::SMTP".(($MSGMail_SMTP<3.00)?"::SSL":"")):"not available");
}
sub MSGMail_conn($)
{
my ($hash) = @_;
my ($name) = $hash->{NAME};
my $smtphost = AttrVal($name, "smtphost", "");
my $smtpport = AttrVal($name, "smtpport", "465"); # 465 is the default port
if ($MSGMail_SSL)
{
if ($MSGMail_SMTP < 3.00)
{
Log3 $name, 3, "$name: try to connect with Net::SMTP::SSL";
return Net::SMTP::SSL->new($smtphost, Port => $smtpport);
}
else
{
Log3 $name, 3, "$name: try to connect with Net::SMTP";
return Net::SMTP->new(Host=>$smtphost, Port=>$smtpport, SSL=>1);
}
}
Log3 $name, 0, "$name: SSL not available. Connection will fail";
return undef;
}
sub MSG_Set($@)
@ -106,126 +54,14 @@ sub MSG_Set($@)
{
return "TYPE for $defs{$a[1]} not defined";
}
####################################################################################################
##
## M S G F i l e
##
####################################################################################################
elsif ($defs{ $a[1] }{TYPE} eq "MSGFile")
{
return "No filename specified, use attr <name> filename <filename> $a[1] $defs{$a[1]}{TYPE}"
if (!AttrVal($a[1], "filename", ""));
# open the file, new = delete file before create it
# append = add lines to the existing file contents
if (AttrVal($a[1], "filemode", "") eq "new")
{
open(FHEMMSGFILE, ">" . AttrVal($a[1], "filename", ""))
|| return "Can not open the file: $!";
}
else
{
open(FHEMMSGFILE, ">>" . AttrVal($a[1], "filename", ""))
|| return "Can not open the file: $!";
}
# loop thru the stored lines and write them to the file
# number of lines are in the Readings / msgcount
my $i;
if (ReadingsVal($a[1], "msgcount", 0) > 0)
{
for ($i = 0 ; $i < ReadingsVal($a[1], "msgcount", 0) ; $i++)
{
print FHEMMSGFILE $data{ $a[1] }{$i}
|| return "Can not write to the file: $!";
}
}
# close the file and send a message to the log
close(FHEMMSGFILE);
Log 1, "<MSG> write to File: " . AttrVal($a[1], "filename", "");
} # END MSGFile
####################################################################################################
##
## M S G M a i l
##
## We use MAIL::Lite to compose the message, because it works very well at this and
## we use Net::SMTP::SSL to connect to the smtp host and manage the authenification,
## because MAIL:Lite is not very easy to manage with SSL connections
####################################################################################################
fhem("set $a[1] write");
}
elsif ($defs{ $a[1] }{TYPE} eq "MSGMail")
{
# check all required data
my $from = AttrVal($a[1], "from", "");
return "No <from> address specified, use attr $a[1] from <mail-address>"
if (!$from);
my $to = AttrVal($a[1], "to", "");
return "No <to> address specified, use attr $a[1] to <mail-address>"
if (!$to);
my $subject = AttrVal($a[1], "subject", "");
return "No <subject> specified, use attr $a[1] subject <text>"
if (!$subject);
my $authfile = AttrVal($a[1], "authfile", "");
return "No <authfile> specified, use attr $a[1] authfile <filename>"
if (!$authfile);
my $smtphost = AttrVal($a[1], "smtphost", "");
return "No <smtphost> name specified, use attr $a[1] sntphost <hostname>"
if (!$smtphost);
my $smtpport = AttrVal($a[1], "smtpport", "465"); # 465 is the default port
my $cc = AttrVal($a[1], "cc", ""); # Carbon Copy
open(FHEMAUTHFILE, "<" . $authfile)
|| return "Can not open authfile $authfile: $!";
my @auth = <FHEMAUTHFILE>;
close(FHEMAUTHFILE);
chomp(@auth);
# Log 1, "MSG User = <" . @auth[0] . "> Passwort = <" . @auth[1] . ">";
# compose message
my $i;
my $mess = "";
for ($i = 0 ; $i < ReadingsVal($a[1], "msgcount", 0) ; $i++)
{
$mess .= $data{ $a[1] }{$i};
}
my $mailmsg = MIME::Lite->new(
From => $from,
To => $to,
Subject => $subject,
Type => 'text/plain; charset=UTF-8', #'multipart/mixed', # was 'text/plain'
Data => $mess
);
# login to the SMTP Host using SSL and send the message
my $smtp;
my $smtperrmsg = "SMTP Error: ";
#$smtp = Net::SMTP::SSL->new($smtphost, Port => $smtpport)
$smtp = MSGMail_conn($defs{ $a[1] })
or return $smtperrmsg . " Can't connect to host $smtphost";
$smtp->auth($auth[0], $auth[1])
or return $smtperrmsg . " Can't authenticate: " . $smtp->message();
$smtp->mail($from) or return $smtperrmsg . $smtp->message();
$smtp->to($to) or return $smtperrmsg . $smtp->message();
if ($cc ne '')
{
Log 1, "CC = $cc";
$smtp->cc($cc) or return $smtperrmsg . $smtp->message();
}
$smtp->data() or return $smtperrmsg . $smtp->message();
$smtp->datasend($mailmsg->as_string)
or return $smtperrmsg . $smtp->message();
$smtp->dataend() or return $smtperrmsg . $smtp->message();
$smtp->quit() or return $smtperrmsg . $smtp->message();
Log 1, "<MSG> send EMail: <$subject>";
} ###> END MSGMail
fhem("set $a[1] send");
}
else
{
return "MSG Filetype $defs{$a[1]}{TYPE} unknown";
@ -263,16 +99,22 @@ sub MSG_Define($$)
<a name="MSG"></a>
<h3>MSG</h3>
<ul>
The MSG device is the backend device for all the message handling (I/O-engine).
Under normal conditions only one MSG device is needed to serve multiple frontend
message devices like file or email.
The MSG device is deprecated.<br><br>
It used to be the backend device for I/O-handling of <a href="#MSGMail">MSGMail</a>
and <a href="#MSGFile">MSGFile</a> devices.
The MSG device can still be used for this purpose, but actually delegates send and
write commands to the <a href="#MSGMail">MSGMail</a> and <a href="#MSGFile">MSGFile</a>
devices, respectively.<br><br>
Before removing a deprecated MSG device from an installation, make sure to change
code in user functions, accordingly.
<br><br>
<a name="MSGdefine"></a>
<b>Define</b>
<ul>
<code>define &lt;name&gt; MSG </code><br><br>
Specifies the MSG device. A single MSG device could serve multiple MSG frontends.
But, for special conditions there could be defined more than one MSG device.
Specifies the MSG device. This is no longer required since
<a href="#MSGFile">MSGFile</a> and <a href="#MSGMail">MSGMail</a>
devices provide all necessary functionality.
</ul>
<br>
<a name="MSGset"></a>
@ -282,18 +124,12 @@ sub MSG_Define($$)
</ul>
Notes:
<ul>
To send the data, both send or write could be used.<br>
The devicename is the name of a frontenddevice previously
defined. Based on the type of the frontend device, the MSG device
will send out the lines of data.
To process the data, both 'send' and 'write' can be used.<br>
The MSG device will delegate the command to the device specified
by 'devicename' and automatically use 'send' for
<a href="#MSGMail">MSGMail</a> and 'write' for
<a href="#MSGFile">MSGFile</a> devices.
<br>
Frontend devices are available for:<br>
<ul><li><a href="#MSGFile">File</a></li>
<li><a href="#MSGMail">EMail with SSL Authentification</a></li></ul>
For details about this devices, please review the device-definitions.<br>
After sending/writing the data, the data stills exists with the
frontend device, MSG do not delete/purge any data, this must be done
by the frontend device.
<br><br>
Examples:
<ul>
@ -302,12 +138,8 @@ sub MSG_Define($$)
</ul>
<a name="MSGVattr"></a>
<b>Attributes</b>
<ul>
<li><a href="#IODev">IODev</a></li>
<li><a href="#dummy">dummy</a></li>
<li><a href="#ignore">ignore</a></li>
<ul>
<li><a href="#loglevel">loglevel</a></li>
<li><a href="#eventMap">eventMap</a></li><br>
</ul>
</ul>
<br><br>

View File

@ -2,15 +2,12 @@
# $Id$
########################################################
#
# Created 2012 by rbente
#
########################################################
#
# History:
#
# 2015-05-06: tidy up code for restructuring
# 2015-05-05: remove dependency on Switch
#
# 2015-05-09: Assimilate file related code from 75_MSG
# 2015-05-06: Tidy up code for restructuring
# 2015-05-05: Remove dependency on Switch
# 2012 : Created by rbente
#
package main;
@ -19,7 +16,8 @@ use warnings;
my %sets = (
"add" => "MSGFile",
"clear" => "MSGFile",
"list" => "MSGFile"
"list" => "MSGFile",
"write" => "MSGFile"
);
##############################################
@ -41,78 +39,6 @@ sub MSGFile_Initialize($)
$hash->{AttrList} = "loglevel:0,1,2,3,4,5,6 filename filemode:new,append CR:0,1";
}
##############################################
# Set Function
# all the data are stored in the global array @data
# as counter we use a READING named msgcount
##############################################
sub MSGFile_Set($@)
{
my ($hash, @a) = @_;
return "Unknown argument $a[1], choose one of -> " . join(" ", sort keys %sets)
if (!defined($sets{ $a[1] }));
my $name = shift @a;
return "no set value specified" if (int(@a) < 1);
return "Unknown argument ?" if ($a[0] eq "?");
my $v = join(" ", @a);
# we like to add another line of data
if ($a[0] eq "add")
{
# split the line in command and data
my $mx = shift @a;
my $my = join(" ", @a);
# check if we like to have and CR at the end of the line
if (AttrVal($name, "CR", "0") eq "1")
{
$my = $my . "\n";
}
# get the highest number of lines, store the line in @data and increase
# the counter, at the end set the status
my $count = $hash->{READINGS}{msgcount}{VAL};
$data{$name}{$count} = $my;
$hash->{READINGS}{msgcount}{TIME} = TimeNow();
$hash->{READINGS}{msgcount}{VAL} = $count + 1;
$hash->{STATE} = "addmsg";
}
# we like to clear our buffer, first clear all lines of @data
# and then set the counter to 0 and the status to clear
elsif ($a[0] eq "clear")
{
my $i;
for ($i = 0 ; $i < ReadingsVal($name, "msgcount", 0) ; $i++)
{
$data{$name}{$i} = "";
}
$hash->{READINGS}{msgcount}{TIME} = TimeNow();
$hash->{READINGS}{msgcount}{VAL} = 0;
$hash->{STATE} = "clear";
}
# we like to see the buffer
elsif ($a[0] eq "list")
{
my $i;
my $mess = "---- Lines of data for $name ----\n";
for ($i = 0 ; $i < ReadingsVal($name, "msgcount", 0) ; $i++)
{
$mess .= $data{$name}{$i};
}
return "$mess---- End of data for $name ----";
}
Log GetLogLevel($name, 2), "messenger set $name $v";
# set stats
# $hash->{CHANGED}[0] = $v;
$hash->{READINGS}{state}{TIME} = TimeNow();
$hash->{READINGS}{state}{VAL} = $v;
return undef;
}
##############################################
# Define Function
# set the counter to 0
@ -155,6 +81,117 @@ sub MSGFile_Undef($$)
delete($modules{MSGFile}{defptr}{ $hash->{CODE} }) if ($hash && $hash->{CODE});
return undef;
}
##############################################
# Set Function
# all the data are stored in the global array @data
# as counter we use a READING named msgcount
##############################################
sub MSGFile_Set($@)
{
my ($hash, @a) = @_;
return "Unknown argument $a[1], choose one of -> " . join(" ", sort keys %sets)
if (!defined($sets{ $a[1] }));
my $name = shift @a;
return "no set value specified" if (int(@a) < 1);
return "Unknown argument ?" if ($a[0] eq "?");
my $v = join(" ", @a);
# we like to add another line of data
if ($a[0] eq "add")
{
# split the line in command and data
my $mx = shift @a;
my $my = join(" ", @a);
# check if we like to have and CR at the end of the line
if (AttrVal($name, "CR", "0") eq "1")
{
$my = $my . "\n";
}
# get the highest number of lines, store the line in @data and increase
# the counter, at the end set the status
my $count = $hash->{READINGS}{msgcount}{VAL};
$data{$name}{$count} = $my;
$hash->{READINGS}{msgcount}{TIME} = TimeNow();
$hash->{READINGS}{msgcount}{VAL} = $count + 1;
$hash->{STATE} = "addmsg";
}
# we like to clear our buffer, first clear all lines of @data
# and then set the counter to 0 and the status to clear
elsif ($a[0] eq "clear")
{
my $i;
for ($i = 0 ; $i < ReadingsVal($name, "msgcount", 0) ; $i++)
{
$data{$name}{$i} = "";
}
$hash->{READINGS}{msgcount}{TIME} = TimeNow();
$hash->{READINGS}{msgcount}{VAL} = 0;
$hash->{STATE} = "clear";
}
# we like to see the buffer
elsif ($a[0] eq "list")
{
my $i;
my $mess = "---- Lines of data for $name ----\n";
for ($i = 0 ; $i < ReadingsVal($name, "msgcount", 0) ; $i++)
{
$mess .= $data{$name}{$i};
}
return "$mess---- End of data for $name ----";
}
elsif ($a[0] eq "write")
{
return "No filename specified, use attr <name> filename <filename> $name $defs{$name}{TYPE}"
if (!AttrVal($name, "filename", ""));
# open the file, new = delete file before create it
# append = add lines to the existing file contents
if (AttrVal($name, "filemode", "") eq "new")
{
open(FHEMMSGFILE, ">" . AttrVal($name, "filename", ""))
|| return "Can not open the file: $!";
}
else
{
open(FHEMMSGFILE, ">>" . AttrVal($name, "filename", ""))
|| return "Can not open the file: $!";
}
# loop thru the stored lines and write them to the file
# number of lines are in the Readings / msgcount
my $i;
if (ReadingsVal($name, "msgcount", 0) > 0)
{
for ($i = 0 ; $i < ReadingsVal($name, "msgcount", 0) ; $i++)
{
print FHEMMSGFILE $data{ $name }{$i}
|| return "Can not write to the file: $!";
}
}
# close the file and send a message to the log
close(FHEMMSGFILE);
Log 1, "<MSG> write to File: " . AttrVal($name, "filename", "");
} # END MSGFile
Log GetLogLevel($name, 2), "messenger set $name $v";
# set stats
# $hash->{CHANGED}[0] = $v;
$hash->{READINGS}{state}{TIME} = TimeNow();
$hash->{READINGS}{state}{VAL} = $v;
return undef;
}
1;
=pod
@ -163,15 +200,13 @@ sub MSGFile_Undef($$)
<a name="MSGFile"></a>
<h3>MSGFile</h3>
<ul>
The MSGFile device is a frontend device for message handling.
With a MSGFile device data is written to disk (or other media).
Multiple MSGFile devices could be defined.
To write the data to disk, a MSG device is necessary.
A MSGFile device needs the operating systems rights to write to the filesystem.
The MSGFile device is used to write arbitrary data to a file on disk
or other media accessable through the filesystem. In order to write to a file,
the access rights of the FHEM process to the specified file and path are relevant.
To set the rights for a directory, please use OS related commands.
<br><br>
<a name="MSGFileDefine"></a>
<a name="MSGFileDefine"></a>
<b>Define</b>
<ul><br>
<code>define &lt;name&gt; MSGFile &lt;filename&gt;</code><br><br>
@ -186,33 +221,38 @@ sub MSGFile_Undef($$)
<a name="MSGFileSet"></a>
<b>Set</b><br>
<ul><code>set &lt;name&gt; add|clear|list [text]</code><br>
<ul><code>set &lt;name&gt; add|clear|list|write [text]</code><br>
Set is used to manipulate the message buffer of the device. The message
buffer is an array of lines of data, stored serial based on the incoming
time into the buffer. Lines of data inside the buffer could not be deleted
anymore, except of flashing the whole buffer.<br>
<ul><b>add</b><br> to add lines of data to the message buffer. All data behind
"add" will be interpreted as text message. To add a carriage return to the data,
please use the CR attribute.
</ul>
<ul><b>clear</b><br> to flash the message buffer and set the line counter to 0.
All the lines of data are deleted and the buffer is flushed.</ul>
<ul><b>list</b><br> to list the message buffer.</ul><br>
</ul><br>
Examples:
<ul>
<code>set myFile add Dies ist Textzeile 1</code><br>
<code>set myFile add Dies ist Textzeile 2</code><br>
<code>set myFile clear</code><br><br>
Full working example to write two lines of data to a file:<br>
<code>define myMsg MSG</code><br>
<code>define myFile MSGFile /tmp/fhemtest.txt</code><br>
<code>attr myFile filemode append</code><br>
<code>set myFile add Textzeile 1</code><br>
<code>set myFile add Textzeile 2</code><br>
<code>set myMsg write myFile</code><br>
<code>set myFile clear</code><br>
</ul><br>
<ul><b>write</b><br> to write the message buffer to the associated file.</ul><br>
</ul><br>
Examples:
<ul>
<code>set myFile add Dies ist Textzeile 1</code><br>
<code>set myFile add Dies ist Textzeile 2</code><br>
<code>set myFile clear</code><br>
<br>
Full working example to write two lines of data to a file:<br>
<code>define myFile MSGFile /tmp/fhemtest.txt</code><br>
<code>attr myFile filemode append</code><br>
<code>set myFile add Textzeile 1</code><br>
<code>set myFile add Textzeile 2</code><br>
<code>set myFile write</code><br>
<code>set myFile clear</code><br>
</ul><br>
<a name="MSGFileVattr"></a>
<b>Attributes</b>

View File

@ -2,26 +2,30 @@
# $Id$
########################################################
#
# Created 2012 by rbente
#
########################################################
#
# History:
#
# 2015-05-06: tidy up code for restructuring
# 2015-05-05: remove dependency on Switch
#
# 2015-05-09: Assimilate mail related code from 75_MSG
# 2015-05-06: Tidy up code for restructuring
# 2015-05-05: Remove dependency on Switch
# 2012 : Created by rbente
#
package main;
use strict;
use warnings;
use MIME::Lite;
use Net::SMTP; # libnet-3.06 has SSL included, so we need to check the version
my %sets = (
"add" => "MSGMail",
"clear" => "MSGMail",
"list" => "MSGMail"
"list" => "MSGMail",
"send" => "MSGMail"
);
my $MSGMail_SSL = 0;
my $MSGMail_SMTP = 0;
##############################################
# Initialize Function
# Attributes are:
@ -43,79 +47,33 @@ sub MSGMail_Initialize($)
$hash->{DefFn} = "MSGMail_Define";
$hash->{UndefFn} = "MSGMail_Undef";
$hash->{AttrList} = "loglevel:0,1,2,3,4,5,6 authfile smtphost smtpport subject from to cc CR:0,1";
}
##############################################
# Set Function
# all the data are stored in the global array @data
# as counter we use a READING named msgcount
##############################################
sub MSGMail_Set($@)
{
my ($hash, @a) = @_;
return "Unknown argument $a[1], choose one of -> " . join(" ", sort keys %sets)
if (!defined($sets{ $a[1] }));
my $name = shift @a;
my $name = "MSGMail";
return "no set value specified" if (int(@a) < 1);
# return "Unknown argument ?" if($a[0] eq "?");
my $v = join(" ", @a);
# we like to add another line of data
if ($a[0] eq "add")
# check version of libnet - if < 3.00, try to load Net::SMTP::SSL
$MSGMail_SMTP = $Net::SMTP::VERSION;
if ($Net::SMTP::VERSION >= 3)
{
# split the line in command and data
my $mx = shift @a;
my $my = join(" ", @a);
# check if we like to have and CR at the end of the line
if (AttrVal($name, "CR", "0") eq "1")
{
$my = $my . "\n";
}
# get the highest number of lines, stored the line in @data and increase
# the counter, at the end set the status
my $count = $hash->{READINGS}{msgcount}{VAL};
$data{$name}{$count} = $my;
$hash->{READINGS}{msgcount}{TIME} = TimeNow();
$hash->{READINGS}{msgcount}{VAL} = $count + 1;
$hash->{STATE} = "addmsg";
$MSGMail_SSL = 1;
}
# we like to clear our buffer, first clear all lines of @data
# and then set the counter to 0 and the status to clear
elsif ($a[0] eq "clear")
else
{
my $i;
for ($i = 0 ; $i < ReadingsVal($name, "msgcount", 0) ; $i++)
eval "use Net::SMTP::SSL";
if ($@)
{
$data{$name}{$i} = "";
Log 0, $@ if ($@);
$MSGMail_SSL = 0;
}
$hash->{READINGS}{msgcount}{TIME} = TimeNow();
$hash->{READINGS}{msgcount}{VAL} = 0;
$hash->{STATE} = "clear";
}
# we like to see the buffer
elsif ($a[0] eq "list")
{
my $i;
my $mess = "---- Lines of data for $name ----\n";
for ($i = 0 ; $i < ReadingsVal($name, "msgcount", 0) ; $i++)
else
{
$mess .= $data{$name}{$i};
$MSGMail_SSL = 1;
}
return "$mess---- End of data for $name ----";
}
Log GetLogLevel($name, 2), "messenger set $name $v";
# set stats
# $hash->{CHANGED}[0] = $v;
$hash->{READINGS}{state}{TIME} = TimeNow();
$hash->{READINGS}{state}{VAL} = $v;
return undef;
Log 2,
"$name: SSL is "
. ( ($MSGMail_SSL)
? ("available, provided by Net::SMTP" . (($MSGMail_SMTP < 3.00) ? "::SSL" : ""))
: "not available");
}
##############################################
@ -130,6 +88,7 @@ sub MSGMail_Define($$)
my $name = $hash->{NAME};
return $errmsg if (@a != 6);
# set all the Attributes
$attr{$name}{from} = $a[2];
$attr{$name}{to} = $a[3];
@ -153,6 +112,7 @@ sub MSGMail_Undef($$)
{
my ($hash, $name) = @_;
my $i;
# flush the data
for ($i = 0 ; $i < ReadingsVal($name, "msgcount", 0) ; $i++)
{
@ -163,6 +123,183 @@ sub MSGMail_Undef($$)
return undef;
}
##############################################
# Set Function
# all the data are stored in the global array @data
# as counter we use a READING named msgcount
##############################################
sub MSGMail_Set($@)
{
my ($hash, @a) = @_;
return "Unknown argument $a[1], choose one of -> " . join(" ", sort keys %sets)
if (!defined($sets{ $a[1] }));
my $name = shift @a;
return "no set value specified" if (int(@a) < 1);
# return "Unknown argument ?" if($a[0] eq "?");
my $v = join(" ", @a);
# we like to add another line of data
if ($a[0] eq "add")
{
# split the line in command and data
my $mx = shift @a;
my $my = join(" ", @a);
# check if we like to have and CR at the end of the line
if (AttrVal($name, "CR", "0") eq "1")
{
$my = $my . "\n";
}
# get the highest number of lines, stored the line in @data and increase
# the counter, at the end set the status
my $count = $hash->{READINGS}{msgcount}{VAL};
$data{$name}{$count} = $my;
$hash->{READINGS}{msgcount}{TIME} = TimeNow();
$hash->{READINGS}{msgcount}{VAL} = $count + 1;
$hash->{STATE} = "addmsg";
}
# we like to clear our buffer, first clear all lines of @data
# and then set the counter to 0 and the status to clear
elsif ($a[0] eq "clear")
{
my $i;
for ($i = 0 ; $i < ReadingsVal($name, "msgcount", 0) ; $i++)
{
$data{$name}{$i} = "";
}
$hash->{READINGS}{msgcount}{TIME} = TimeNow();
$hash->{READINGS}{msgcount}{VAL} = 0;
$hash->{STATE} = "clear";
}
# we like to see the buffer
elsif ($a[0] eq "list")
{
my $i;
my $mess = "---- Lines of data for $name ----\n";
for ($i = 0 ; $i < ReadingsVal($name, "msgcount", 0) ; $i++)
{
$mess .= $data{$name}{$i};
}
return "$mess---- End of data for $name ----";
}
elsif ($a[0] eq "send")
{
# check all required data
my $from = AttrVal($name, "from", "");
my $to = AttrVal($name, "to", "");
my $subject = AttrVal($name, "subject", "");
my $authfile = AttrVal($name, "authfile", "");
my $smtphost = AttrVal($name, "smtphost", "");
my $smtpport = AttrVal($name, "smtpport", "465"); # 465 is the default port
my $cc = AttrVal($name, "cc", ""); # Carbon Copy
return "No <from> address specified, use attr $name from <mail-address>"
if (!$from);
return "No <to> address specified, use attr $name to <mail-address>"
if (!$to);
return "No <subject> specified, use attr $name subject <text>"
if (!$subject);
return "No <authfile> specified, use attr $name authfile <filename>"
if (!$authfile);
return "No <smtphost> name specified, use attr $name sntphost <hostname>"
if (!$smtphost);
open(FHEMAUTHFILE, "<" . $authfile)
|| return "Can not open authfile $authfile: $!";
my @auth = <FHEMAUTHFILE>;
close(FHEMAUTHFILE);
chomp(@auth);
# Log 1, "MSG User = <" . @auth[0] . "> Passwort = <" . @auth[1] . ">";
# compose message
my $i;
my $mess = "";
for ($i = 0 ; $i < ReadingsVal($name, "msgcount", 0) ; $i++)
{
$mess .= $data{ $name }{$i};
}
my $mailmsg = MIME::Lite->new(
From => $from,
To => $to,
Subject => $subject,
Type => 'text/plain; charset=UTF-8', #'multipart/mixed', # was 'text/plain'
Data => $mess
);
# login to the SMTP Host using SSL and send the message
my $smtp;
my $smtperrmsg = "SMTP Error: ";
#$smtp = Net::SMTP::SSL->new($smtphost, Port => $smtpport)
$smtp = MSGMail_conn($defs{ $name })
or return $smtperrmsg . " Can't connect to host $smtphost";
$smtp->auth($auth[0], $auth[1])
or return $smtperrmsg . " Can't authenticate: " . $smtp->message();
$smtp->mail($from) or return $smtperrmsg . $smtp->message();
$smtp->to($to) or return $smtperrmsg . $smtp->message();
if ($cc ne '')
{
Log 1, "CC = $cc";
$smtp->cc($cc) or return $smtperrmsg . $smtp->message();
}
$smtp->data() or return $smtperrmsg . $smtp->message();
$smtp->datasend($mailmsg->as_string)
or return $smtperrmsg . $smtp->message();
$smtp->dataend() or return $smtperrmsg . $smtp->message();
$smtp->quit() or return $smtperrmsg . $smtp->message();
Log 1, "<MSG> send EMail: <$subject>";
} ###> END MSGMail
Log GetLogLevel($name, 2), "messenger set $name $v";
# set stats
# $hash->{CHANGED}[0] = $v;
$hash->{READINGS}{state}{TIME} = TimeNow();
$hash->{READINGS}{state}{VAL} = $v;
return undef;
}
##############################################
# Helper Function to connect to mail server
# Returns a smtp connection (see Net:SMTP)
##############################################
sub MSGMail_conn($)
{
my ($hash) = @_;
my ($name) = $hash->{NAME};
my $smtphost = AttrVal($name, "smtphost", "");
my $smtpport = AttrVal($name, "smtpport", "465"); # 465 is the default port
if ($MSGMail_SSL)
{
if ($MSGMail_SMTP < 3.00)
{
Log3 $name, 3, "$name: try to connect with Net::SMTP::SSL";
return Net::SMTP::SSL->new($smtphost, Port => $smtpport);
}
else
{
Log3 $name, 3, "$name: try to connect with Net::SMTP";
return Net::SMTP->new(Host => $smtphost, Port => $smtpport, SSL => 1);
}
}
Log3 $name, 0, "$name: SSL not available. Connection will fail";
return undef;
}
1;
=pod
@ -171,13 +308,12 @@ sub MSGMail_Undef($$)
<a name="MSGMail"></a>
<h3>MSGMail</h3>
<ul>
The MSGMail device is a frontend device for mail message handling.
With a MSGMaildevice data is fowarded to a mail provider and send to a recipent.
Multiple MSGMail devices could be defined.
MSGMail supports by the moment only mail provider, which uses SSL secured connection
like Googlemail, GMX, Yahoo or 1und1 for example.
To send an email, a MSG device is necessary.<br>
<b>MAIL::Lite</b> and <b>Net::SMTP::SSL</b> from CPAN is needed to use MSGMail!!
The MSGMail device is used to send mail messages to a recipient by connecting
to a SMTP server. Currently MSGMail supports only servers, that allow SSL secured connections
like Googlemail, GMX, Yahoo or 1und1.
MSGMail requires the perl pacakge <b>MAIL::Lite</b>.
For SSL support, Net::SMTP version 3.06 is required. On systems with an older version of Net::SMTP,
MSGMail requires the package <b>Net::SMTP::SSL</b>.
<br><br>
<a name="MSGMailDefine"></a>
@ -196,7 +332,7 @@ sub MSGMail_Undef($$)
<a name="MSGMailSet"></a>
<b>Set</b><br>
<ul><code>set &lt;name&gt; add|clear|list [text]</code><br>
<ul><code>set &lt;name&gt; add|clear|list|send [text]</code><br>
Set is used to manipulate the message buffer of the device. The message
buffer is an array of lines of data, stored serial based on the incoming
time into the buffer. Lines of data inside the buffer could not be deleted
@ -205,9 +341,10 @@ sub MSGMail_Undef($$)
"add" will be interpreted as text message. To add a carriage return to the data,
please use the CR attribute.
</ul>
<ul><b>clear</b><br> to flash the message buffer and set the line counter to 0.
<ul><b>clear</b><br> to flush the message buffer and set the line counter to 0.
All the lines of data are deleted and the buffer is flushed.</ul>
<ul><b>list</b><br> to list the message buffer.<br></ul><br>
<ul><b>send</b><br> to send the message buffer.<br></ul><br>
<br>
Examples:
<ul>
@ -215,14 +352,13 @@ sub MSGMail_Undef($$)
<code>set myMail add Dies ist Textzeile 2</code><br>
<code>set myMail clear</code><br><br>
Full working example to send two lines of data to a recipent:<br>
<code>define myMsg MSG</code><br>
<code>define myMail MSGMail donald.duck@entenhausen.com dagobert.duck@duck-banking.com smtp.entenhausen.net /etc/fhem/msgmailauth</code><br>
<code>attr myMail smtpport 9999</code><br>
<code>attr myMail subject i need more money</code><br>
<code>attr myMail CR 0</code><br>
<code>set myMail add Please send me </code><br>
<code>set myMail add 1.000.000 Taler</code><br>
<code>set myMsg send myMail</code><br>
<code>set myMail send</code><br>
<code>set myMail clear</code><br>
</ul><br>
</ul>