Created announceEmail.pl
[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.0 $
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 =hade1 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    -s|leep:    Number of minutes to sleep inbetween checking mail (Default: 5)
48
49 =head1 DESCRIPTION
50
51 This script will connect to an IMAP server, login and then monitor the user's
52 INBOX. When new messages arrive it will extract the From address and Subject
53 from the message and compose a message to be used by "Google Talk" to announce
54 the email. The message will be similar to:
55
56   "<From> emailed <Subject>"
57
58 =cut
59
60 use strict;
61 use warnings;
62
63 use FindBin;
64 use Getopt::Long;
65 use Pod::Usage;
66 use Net::IMAP::Simple;
67 use Email::Simple;
68 use MIME::Base64;
69
70 use lib "$FindBin::Bin/../lib";
71
72 use Display;
73 use Logger;
74 use Utils;
75
76 my $defaultIMAPServer = 'defaria.com';
77 my $defaultSleeptime  = 1;
78 my $IMAP;
79 my %unseen;
80 my $log;
81
82 my %opts = (
83   usage    => sub { pod2usage },
84   help     => sub { pod2usage(-verbose => 2)},
85   verbose  => sub { set_verbose },
86   debug    => sub { set_debug },
87   daemon   => 1,
88   username => $ENV{USER},
89   password => $ENV{PASSWORD},
90   imap     => $defaultIMAPServer,
91   sleep    => $defaultSleeptime,
92 );
93
94 sub unseenMsgs() {
95   my %unseenMsgs;
96
97   for (my $i = 1; $i <= $IMAP->status; $i++) {
98     $unseenMsgs{$i} = 0 unless $IMAP->seen($i);
99   } # for
100
101   return %unseenMsgs;
102 } # unseenMsgs 
103
104 sub Connect2IMAP() {
105   $log->msg("Connecting to $opts{imap} as $opts{username}");
106
107   $IMAP = Net::IMAP::Simple->new($opts{imap}) ||
108     error("Unable to connect to IMAP server $opts{imap}: " . $Net::IMAP::Simple::errstr, 1);
109
110   $log->msg("Connected");
111
112   $log->msg("Logging onto $opts{imap} as $opts{username}");
113
114   unless ($IMAP->login($opts{username}, $opts{password})) {
115     $log->err("Login to $opts{imap} as $opts{username} failed: " . $IMAP->errstr, 1);
116   } # unless
117
118   $log->msg("Logged on");
119
120   # Focus on INBOX only
121   $IMAP->select('INBOX');
122
123   # Setup %unseen to have each unseen message index set to 0 meaning not read
124   # aloud yet
125   %unseen = unseenMsgs;
126 } # Connect2IMAP
127
128 sub MonitorMail() {
129   $log->msg("Monitoring email");
130
131   while () {
132     # First close and reselect the INBOX to get its current status
133     $IMAP->close;
134     $IMAP->select('INBOX');
135
136     # Go through all of the unseen messages and add them to %unseen if they were
137     # not there already from a prior run and read
138     my %newUnseen = unseenMsgs;
139
140     # Now clean out any messages in %unseen that were not in the %newUnseen and
141     # marked as previously read
142     for (keys %unseen) {
143       if (defined $newUnseen{$_}) {
144         if ($unseen{$_}) {
145           delete $newUnseen{$_};
146         } # if
147       } else {
148         delete $unseen{$_}
149       } # if
150     } # for
151
152     for (keys %newUnseen) {
153       next if $unseen{$_};
154
155       my $email = Email::Simple->new(join '', @{$IMAP->top($_)});
156
157       my $from = $email->header('From');
158
159       # Extract the name only when the email is of the format "name <email>"
160       if ($from =~ /^(.*)\<(\S*)>/) {
161         $from = $1 if $1 ne '';
162       } # if
163
164       my $subject = $email->header('Subject');
165
166       if ($subject =~ /=?\S+?(Q|B)\?(.+)\?=/) {
167         $subject = decode_base64($2);
168       } # if
169
170       # Now speak it!
171       my $msg = "Message from $from... " . quotemeta $subject;
172       $msg =~ s/\"/\\"/g;
173
174       if (get_verbose) {
175         $log->msg("Announcing $msg");
176       } else {
177         $log->log("Announcing $msg")
178       }
179
180       my $cmd = "/usr/local/bin/gt \"$msg\"";
181
182       my ($status, @output) = Execute $cmd;
183
184       if ($status) {
185         $log->err("Unable to execute $cmd" . join("\n", @output));
186       } # if
187
188       $unseen{$_} = 1;
189     } # for
190
191     verbose "Sleeping for $opts{sleep} minutes";
192     sleep 60 * $opts{sleep};
193     verbose "Ah that was refreshing!";
194   } # while
195 } # MonitorMail
196
197 END {
198   $IMAP->quit if $IMAP;
199 } # END
200
201 ## Main
202 GetOptions(
203   \%opts,
204   'usage',
205   'help',
206   'verbose',
207   'debug',
208   'daemon!',
209   'username=s',
210   'password=s',
211   'imap=s',
212   'sleep',
213 );
214
215 unless ($opts{password}) {
216   verbose "I need $opts{username}'s password";
217   $opts{password} = GetPassword;
218 } # unless
219
220 EnterDaemonMode if $opts{daemon};
221
222 $log = Logger->new(
223   path        => '/var/log',
224   timestamped => 'yes',
225   append      => 'yes',
226 );
227
228 Connect2IMAP;
229 MonitorMail;