Bump version and update Changes
[app-fonbot-daemon.git] / lib / App / FonBot / Plugin / Email.pm
CommitLineData
2f9aba44
MG
1package App::FonBot::Plugin::Email;
2
b8d4a547 3our $VERSION = '0.001';
2f9aba44
MG
4
5use v5.14;
6use strict;
7use warnings;
8
9use Apache2::Authen::Passphrase qw/pwcheck/;
10use Email::Sender::Simple qw/sendmail/;
11use Email::Simple;
12use Email::MIME;
13use Linux::Inotify2 qw/IN_MOVED_TO/;
14use File::Slurp qw/read_file/;
15use POE;
16use Log::Log4perl qw//;
17
18use File::Glob qw/bsd_glob GLOB_NOSORT/;
19use Text::ParseWords qw/shellwords/;
20
21use App::FonBot::Plugin::Common;
22use App::FonBot::Plugin::Config qw/$email_batch_seconds $email_from $email_subject/;
23
24##################################################
25
26my $log=Log::Log4perl->get_logger(__PACKAGE__);
27
28my %queues;
29my %queue_alarms;
30my $session;
31my $inotify;
32
33sub init{
34 return unless $email_from && $email_subject;
35 $log->info('initializing '.__PACKAGE__);
36 $session = POE::Session->create(
37 inline_states => {
38 _start => \&email_start,
39 send_message => \&email_send_message,
40 flush_queue => \&email_flush_queue,
41 inotify_readable => sub{
42 $_[HEAP]{inotify}->poll
43 },
44 shutdown => sub{
45 $_[KERNEL]->select_read($inotify)
46 }
47 },
48 );
49}
50
51sub fini{
52 $log->info('finishing '.__PACKAGE__);
53 POE::Kernel->post($session, 'shutdown')
54}
55
56
57sub email_handle_new{
58 for my $file (bsd_glob 'Maildir/new/*', GLOB_NOSORT) {
59 my $email=Email::MIME->new(scalar read_file $file);
60
61 #untaint $file
62 $file =~ /^(.*)$/;
63 $file = $1;
64
65 unlink $file;
66 return unless defined $email;
67
68 my $replyto=$email->header('From');
69 return unless defined $replyto;
70
71 my ($user,$password)=split ' ', $email->header('Subject'), 2;
72 chomp $password;
73
74 $log->debug("Processing email from $user");
75
76 eval { pwcheck $user, $password };
77 if ($@) {
78 $log->debug("Incorrect credentials in email subject from user $user. Exception: $@");
79 POE::Kernel->yield(send_message => $replyto, "Incorrect credentials");
80 return
81 }
82
83 $ok_user_addresses{"$user EMAIL $replyto"}=1;
84
85 my $process_email_part = sub {
86 local *__ANON__ = "process_email_part"; #Name this sub. See http://www.perlmonks.org/?node_id=304883
87
88 my $part=$_[0];
89 return unless $part->content_type =~ /text\/plain/;
90
91 my @lines=split '\n', $part->body;
92
93 for my $line (@lines) {
94 last if $line =~ /^--/;
95 $log->debug("Command received via email from $user: $line");
96 sendmsg $user, undef, "EMAIL '$replyto'", shellwords $line
97 }
98 };
99
100 $email->walk_parts($process_email_part);
101 }
102}
103
104sub email_start{
105 $_[KERNEL]->alias_set('EMAIL');
106 $_[HEAP]{inotify} = Linux::Inotify2->new;
107 $_[HEAP]{inotify}->watch('Maildir/new/',IN_MOVED_TO,\&email_handle_new);
108
109 open $inotify,'<&=',$_[HEAP]{inotify}->fileno;
110 $_[KERNEL]->select_read($inotify, 'inotify_readable');
111 email_handle_new
112}
113
114sub email_send_message{
115 my ($address, $message) = @_[ARG0,ARG1];
116
117 $queues{$address}.=$message."\n";
118 if (defined $queue_alarms{$address}) {
119 $_[KERNEL]->delay_adjust($queue_alarms{$address}, $email_batch_seconds)
120 } else {
121 $queue_alarms{$address}=$_[KERNEL]->delay_set(flush_queue => $email_batch_seconds, $address)
122 }
123}
124
125sub email_flush_queue{
126 my ($queue) = $_[ARG0];
127 return unless exists $queues{$queue};
128
129 my $email=Email::Simple->create(
130 header => [
131 From => $email_from,
132 To => $queue,
133 Subject => $email_subject,
134 ],
135 body => $queues{$queue}
136 );
137
138 delete $queues{$queue};
139 delete $queue_alarms{$queue};
140
141 $log->debug("Sending email to $queue");
142
143 eval {
144 sendmail $email
145 } or $log->error("Could not send email: " . $@->message);
146}
147
1481;
149__END__
150
151=encoding utf-8
152
153=head1 NAME
154
155App::FonBot::Plugin::Email - FonBot plugin for receiving commands and sending messages through emails
156
157=head1 SYNOPSIS
158
159 use App::FonBot::Plugin::Email;
160 App::FonBot::Plugin::Email->init;
161 ...
162 App::FonBot::Plugin::Email->fini;
163
164=head1 DESCRIPTION
165
166This FonBot plugin provides email receiving/sending features to B<fonbotd>. Emails are read from F<Maildir/> and are sent through C<Email::Sender::Simple>.
167
168=head1 CONFIGURATION VARIABLES
169
170These are the L<App::FonBot::Plugin::Config> configuration variables used in this module
171
172=over
173
174=item C<$email_batch_seconds>
175
176When receiving an email send request, C<App::FonBot::Plugin::Email> waits this many seconds for further email send requests to the same email address. The timer is reset for each email send request. When the timer expires, all pending send requests are batched and sent as one email.
177
178=item C<$email_from>
179
180C<From:> header of all emails sent by this plugin. If not set the email plugin is disabled.
181
182=item C<$email_subject>
183
184C<Subject:> header of all emails sent by this plugin. If not set the email plugin is disabled.
185
186=back
187
188=head1 AUTHOR
189
190Marius Gavrilescu C<< marius@ieval.ro >>
191
192=head1 COPYRIGHT AND LICENSE
193
b8d4a547 194Copyright 2013-2015 Marius Gavrilescu
2f9aba44
MG
195
196This file is part of fonbotd.
197
198fonbotd is free software: you can redistribute it and/or modify
199it under the terms of the GNU Affero General Public License as published by
200the Free Software Foundation, either version 3 of the License, or
201(at your option) any later version.
202
203fonbotd is distributed in the hope that it will be useful,
204but WITHOUT ANY WARRANTY; without even the implied warranty of
205MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
206GNU Affero General Public License for more details.
207
208You should have received a copy of the GNU Affero General Public License
209along with fonbotd. If not, see <http://www.gnu.org/licenses/>
This page took 0.021053 seconds and 4 git commands to generate.