Enhanced setbg
[clearscm.git] / bin / announceEmail.pl
1 #!/usr/bin/perl
2
3 =pod
4
5 =head1 NAME $RCSfile: announceEmail.pl,v $
6
7 Monitors an IMAP Server and announce incoming emails by extracting the subject
8 line and from line and then pushing that into "GoogleTalk".
9
10 =head1 VERSION
11
12 =over
13
14 =item Author
15
16 Andrew DeFaria <Andrew@DeFaria.com>
17
18 =item Revision
19
20 $Revision: 1.1 $
21
22 =item Created:
23
24 Thu Apr  4 13:40:10 MST 2019
25
26 =item Modified:
27
28 $Date: 2019/04/04 13:40:10 $
29
30 =back
31
32 =head1 SYNOPSIS
33
34  Usage: announceEmail.pl [-usa|ge] [-h|elp] [-v|erbose] [-de|bug] [-da|emon]
35                          [-use|rname <username>] [-p|assword <password>]
36                          [-i|map <server]
37
38  Where:
39    -usa|ge:    Print this usage
40    -h|elp:     Detailed help
41    -v|erbose:  Verbose mode (Default: -verbose)
42    -de|bug:    Turn on debugging (Default: Off)
43    -da|emon:   Run in daemon mode (Default: -daemon)
44    -use|rname: User name to log in with (Default: $USER)
45    -p|assword: Password to use (Default: prompted)
46    -i|map:     IMAP server to talk to (Default: defaria.com)
47
48 =head1 DESCRIPTION
49
50 This script will connect to an IMAP server, login and then monitor the user's
51 INBOX. When new messages arrive it will extract the From address and Subject
52 from the message and compose a message to be used by "Google Talk" to announce
53 the email. The message will be similar to:
54
55   "<From> emailed <Subject>"
56
57 =cut
58
59 use strict;
60 use warnings;
61
62 use FindBin;
63 use Getopt::Long;
64 use Pod::Usage;
65 use Mail::IMAPTalk;
66 use MIME::Base64;
67
68 use lib "$FindBin::Bin/../lib";
69
70 use Display;
71 use Logger;
72 use Utils;
73
74 my $defaultIMAPServer = 'defaria.com';
75 my $IMAP;
76 my %unseen;
77 my $log;
78
79 my @greetings = (
80   'Incoming message',
81   'You have received a new message',
82   'Hey I found this in your inbox',
83   'For some unknown reason this guy send you a message',
84   'Did you know you just got a message',
85   'Potential spam',
86   'You received a communique',
87   'I was looking in your inbox and found a message',
88   'Not sure you want to hear this message',
89   'Good news',
90 );
91
92 my %opts = (
93   usage    => sub { pod2usage },
94   help     => sub { pod2usage(-verbose => 2)},
95   verbose  => sub { set_verbose },
96   debug    => sub { set_debug },
97   daemon   => 1,
98   username => $ENV{USER},
99   password => $ENV{PASSWORD},
100   imap     => $defaultIMAPServer,
101 );
102
103 sub interrupted {
104   if (get_debug) {
105     $log->msg("Turning off debugging");
106     set_debug 0;
107   } else {
108     $log->msg("Turning on debugging");
109     set_debug 1;
110   } # if
111
112   return;
113 } # interrupted
114
115 $SIG{USR1} = \&interrupted;
116
117 sub debugit($) {
118   my ($msg) = @_;
119
120   $log->msg($msg) if get_debug;
121
122   return;
123 } # logit
124
125 sub unseenMsgs() {
126   $IMAP->select('inbox') or
127     $log->err("Unable to select inbox: " . get_last_error(), 1);
128
129   return map { $_=> 0 } @{$IMAP->search('not', 'seen')};
130 } # unseenMsgs 
131
132 sub Connect2IMAP() {
133   $log->msg("Connecting to $opts{imap} as $opts{username}");
134
135   $IMAP = Mail::IMAPTalk->new(
136     Server   => $opts{imap},
137     Username => $opts{username},
138     Password => $opts{password},
139   ) or $log->err("Unable to connect to IMAP server $opts{imap}: $@", 1);
140
141   $log->msg('Connected');
142
143   # Focus on INBOX only
144   $IMAP->select('inbox');
145
146   # Setup %unseen to have each unseen message index set to 0 meaning not read
147   # aloud yet
148   %unseen = unseenMsgs;
149
150   return;
151 } # Connect2IMAP
152
153 sub MonitorMail() {
154   while () {
155     # First close and reselect the INBOX to get its current status
156     debugit "Reconnecting to INBOX";
157     $IMAP->close;
158     $IMAP->select('INBOX')
159       or $log->err("Unable to select INBOX - ". $IMAP->errstr(), 1);
160
161     # Go through all of the unseen messages and add them to %unseen if they were
162     # not there already from a prior run and read
163     my %newUnseen = unseenMsgs;
164
165     # Now clean out any messages in %unseen that were not in the %newUnseen and
166     # marked as previously read
167     for (keys %unseen) {
168       if (defined $newUnseen{$_}) {
169         if ($unseen{$_}) {
170           delete $newUnseen{$_};
171         } # if
172       } else {
173         delete $unseen{$_}
174       } # if
175     } # for
176
177     debugit "Processing newUnseen";
178     for (keys %newUnseen) {
179       next if $unseen{$_};
180
181       my $envelope = $IMAP->fetch($_, '(envelope)');
182       my $from     = $envelope->{$_}{envelope}{From};
183       my $subject  = $envelope->{$_}{envelope}{Subject};
184          $subject //= 'Unknown subject';
185
186       # Extract the name only when the email is of the format "name <email>"
187       if ($from =~ /^"?(.*?)"?\s*\<(\S*)>/) {
188         $from = $1 if $1 ne '';
189       } # if
190
191       if ($subject =~ /=?\S+?(Q|B)\?(.+)\?=/) {
192         $subject = decode_base64($2);
193       } # if
194
195       # Google Talk doesn't like #
196       $subject =~ s/\#//g;
197
198       # Now speak it!
199       debugit "Speaking message from $from";
200
201       my $logmsg = "From $from $subject";
202
203       my $greeting = $greetings[int rand $#greetings];
204       my $msg      = "$greeting from $from... " . quotemeta $subject;
205          $msg      =~ s/\"/\\"/g;
206
207       # Log it
208       $log->msg($logmsg);
209
210       debugit $logmsg;
211
212       my $cmd = "/usr/local/bin/gt \"$msg\"";
213
214       my $hour = (localtime)[2];
215
216       # Only announce if after 6 Am. Note this will announce up until
217       # midnight but that's ok. I want midnight to 6 Am as silent time.
218       if ($hour > 6) {
219         my ($status, @output) = Execute $cmd;
220
221         if ($status) {
222           $log->err("Unable to execute $cmd" . join("\n", @output));
223         } # if
224       } # if
225
226       $unseen{$_} = 1;
227     } # for
228   } # while
229
230   return;
231 } # MonitorMail
232
233 END {
234   $IMAP->quit if $IMAP;
235
236   $log->msg("$FindBin::Script ending!");
237 } # END
238
239 ## Main
240 GetOptions(
241   \%opts,
242   'usage',
243   'help',
244   'verbose',
245   'debug',
246   'daemon!',
247   'username=s',
248   'password=s',
249   'imap=s',
250   'sleep',
251 );
252
253 unless ($opts{password}) {
254   verbose "I need $opts{username}'s password";
255   $opts{password} = GetPassword;
256 } # unless
257
258 $opts{debug} = get_debug;
259
260 EnterDaemonMode if $opts{daemon};
261
262 $log = Logger->new(
263   path        => '/var/log',
264   timestamped => 'yes',
265   append      => 'yes',
266 );
267
268 Connect2IMAP;
269
270 my $msg = "Now monitoring email for $opts{username}\@$opts{imap}";
271
272 $log->msg($msg);
273
274 my $cmd = "/usr/local/bin/gt \"$msg\"";
275
276 my ($status, @output) = Execute $cmd;
277
278 $IMAP->idle(\&MonitorMail);
279