4eb288ac21c436c93fafaaba80b9832518d756b6
[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 Utils;
74
75 my $defaultIMAPServer = 'defaria.com';
76 my $defaultSleeptime  = 5;
77 my $IMAP;
78 my %unseen;
79
80 my %opts = (
81   usage    => sub { pod2usage },
82   help     => sub { pod2usage(-verbose => 2)},
83   verbose  => sub { set_verbose },
84   debug    => sub { set_debug },
85   daemon   => 1,
86   username => $ENV{USER},
87   imap     => $defaultIMAPServer,
88   sleep    => $defaultSleeptime,
89 );
90
91 sub unseenMsgs() {
92   my %unseenMsgs;
93
94   for (my $i = 1; $i <= $IMAP->status; $i++) {
95     $unseenMsgs{$i} = 0 unless $IMAP->seen($i);
96   } # for
97
98   return %unseenMsgs;
99 } # unseenMsgs 
100
101 sub Connect2IMAP() {
102   verbose "Connecting to $opts{imap} as $opts{username}";
103
104   $IMAP = Net::IMAP::Simple->new($opts{imap}) ||
105     error("Unable to connect to IMAP server $opts{imap}: " . $Net::IMAP::Simple::errstr, 1);
106
107   verbose "Connected";
108
109   verbose "Logging onto $opts{imap} as $opts{username}";
110
111   unless ($IMAP->login($opts{username}, $opts{password})) {
112     error("Login to $opts{imap} as $opts{username} failed: " . $IMAP->errstr, 1);
113   } # unless
114
115   verbose "Logged on";
116
117   # Focus on INBOX only
118   $IMAP->select('INBOX');
119
120   # Setup %unseen to have each unseen message index set to 0 meaning not read
121   # aloud yet
122   %unseen = unseenMsgs;
123 } # Connect2IMAP
124
125 sub MonitorMail() {
126   verbose "Monitoring email";
127
128   while () {
129     verbose "Looking for unread messages";
130     # First close and reselect the INBOX to get its current status
131     $IMAP->close;
132     $IMAP->select('INBOX');
133
134     # Go through all of the unseen messages and add them to %unseen if they were
135     # not there already from a prior run and read
136     my %newUnseen = unseenMsgs;
137
138     # Now clean out any messages in %unseen that were not in the %newUnseen and
139     # marked as previously read
140     for (keys %unseen) {
141       if (defined $newUnseen{$_}) {
142         if ($unseen{$_}) {
143           delete $newUnseen{$_};
144         } # if
145       } else {
146         delete $unseen{$_}
147       } # if
148     } # for
149
150     for (keys %newUnseen) {
151       next if $unseen{$_};
152
153       my $email = Email::Simple->new(join '', @{$IMAP->top($_)});
154
155       my $from = $email->header('From');
156
157       # Extract the name only when the email is of the format "name <email>"
158       if ($from =~ /^(.*)\<(\S*)>/) {
159         $from = $1 if $1 ne '';
160       } # if
161
162       my $subject = $email->header('Subject');
163
164       if ($subject =~ /=?\S+?(Q|B)\?(.+)\?=/) {
165         $subject = decode_base64($2);
166       } # if
167
168       # Now speak it!
169       my $msg = "Message from $from... " . quotemeta $subject;
170       $msg =~ s/\"/\\"/g;
171
172       verbose "Announcing $msg";
173
174       Execute "/usr/local/bin/gt \"$msg\"";
175
176       $unseen{$_} = 1;
177     } # for
178
179     verbose "Sleeping for $opts{sleep} minutes";
180     sleep 60 * $opts{sleep};
181     verbose "Ah that was refreshing!";
182   } # while
183 } # MonitorMail
184
185 END {
186   $IMAP->quit;
187 } # END
188
189 ## Main
190 GetOptions(
191   \%opts,
192   'usage',
193   'help',
194   'verbose',
195   'debug',
196   'daemon!',
197   'username=s',
198   'password=s',
199   'imap=s',
200   'sleep',
201 );
202
203 unless ($opts{password}) {
204   verbose "I need $opts{username}'s password";
205   $opts{password} = GetPassword;
206 } # unless
207
208 EnterDaemonMode if $opts{daemon};
209
210 Connect2IMAP;
211 MonitorMail;