File Coverage

blib/lib/Bot/IRC/History.pm
Criterion Covered Total %
statement 26 69 37.6
branch 1 24 4.1
condition 0 8 0.0
subroutine 8 9 88.8
pod 0 1 0.0
total 35 111 31.5


line stmt bran cond sub pod time code
1             # ABSTRACT: Bot::IRC selected channel history dumped to email
2              
3             use 5.014;
4 1     1   1765 use exact;
  1         3  
5 1     1   16  
  1         2  
  1         5  
6             use Date::Format 'time2str';
7 1     1   638 use Date::Parse 'str2time';
  1         2  
  1         35  
8 1     1   347 use Email::Mailer;
  1         2112  
  1         67  
9 1     1   377 use Email::Valid;
  1         255096  
  1         36  
10 1     1   440 use File::Grep 'fgrep';
  1         40791  
  1         92  
11 1     1   352  
  1         1087  
  1         1238  
12             our $VERSION = '1.39'; # VERSION
13              
14             my ($bot) = @_;
15             my $vars = $bot->vars;
16 1     1 0 4976 my @filter = ( ref $vars->{filter} ) ? @{ $vars->{filter} } : ( $vars->{filter} );
17 1         5 my $stdout_file = $bot->settings('daemon')->{stdout_file};
18 1 50       5  
  0         0  
19 1         3 $bot->hook(
20             {
21             to_me => 1,
22             text => qr/
23             ^\s*history\s+(
24             (?:
25             (?<type>on)\s+(?<date>.+?)
26             ) |
27             (?:
28             (?<type>from)\s+(?<date>.+?)\s+to\s+(?<date2>.+?)
29             ) |
30             (?:
31             (?<type>matching)\s+(?<string>.+?)
32             )
33             )\s+(?:to\s+)?(?<email>\S+)\s*$
34             /ix,
35             },
36             sub {
37             my ( $bot, $in, $m ) = @_;
38              
39 0     0   0 if ( not $in->{forum} ) {
40             $bot->reply_to(q{Ask me from within a specific channel.});
41 0 0 0     0 }
    0 0        
    0          
    0          
    0          
    0          
42 0         0 elsif ( grep { lc( $in->{forum} ) eq lc($_) } @filter ) {
43             $bot->reply_to(q{I'm not allowed to return history for this channel.});
44 0         0 }
45 0         0 elsif ( not Email::Valid->address( $m->{email} ) ) {
46             $bot->reply_to('The email address you provided does not appear to be valid.');
47             }
48 0         0 elsif ( not -f $stdout_file ) {
49             $bot->reply_to(q{Sorry. I can't seem to access a log file right now.});
50             }
51 0         0 elsif ( $m->{date} and not $m->{time_date} = str2time( $m->{date} ) ) {
52             $bot->reply_to(qq{I don't understand "$m->{date}" as a date or date/time.});
53             }
54 0         0 elsif ( $m->{date2} and not $m->{time_date2} = str2time( $m->{date2} ) ) {
55             $bot->reply_to(qq{I don't understand "$m->{date2}" as a date or date/time.});
56             }
57 0         0 else {
58             $bot->reply_to('Searching history...');
59              
60 0         0 my @matches =
61             map {
62             my $matches = $_->{matches};
63             map { $matches->{$_} } sort { $a <=> $b } keys %$matches;
64 0         0 } fgrep {
65 0         0 /^\[[^\]]*\]\s\S+\sPRIVMSG\s$in->{forum}/
  0         0  
  0         0  
66             } $stdout_file;
67 0         0  
68 0         0 my $subject;
69             if ( lc $m->{type} eq 'on' ) {
70 0         0 my $date = time2str( '%d/%b/%Y', $m->{time_date} );
71 0 0       0 my $re = qr/^\[$date/;
    0          
    0          
72 0         0 @matches = grep { $_ =~ $re } @matches;
73 0         0 $subject = "on date $m->{date}";
74 0         0 }
  0         0  
75 0         0 elsif ( lc $m->{type} eq 'from' ) {
76             @matches =
77             map { $_->{text} }
78             grep {
79 0         0 $_->{time} >= $m->{time_date} and
80             $_->{time} <= $m->{time_date2}
81             }
82             map {
83 0 0       0 /^\[([^\]]+)\]\s/;
84             +{
85 0         0 time => str2time($1),
  0         0  
86             text => $_,
87 0         0 };
88             } @matches;
89             $subject = "from $m->{date} to $m->{date2}";
90             }
91 0         0 elsif ( lc $m->{type} eq 'matching' ) {
92             @matches = grep { /$m->{string}/i } @matches;
93             $subject = "matching $m->{string}";
94 0         0 }
  0         0  
95 0         0  
96             if ( not @matches ) {
97             $bot->reply_to(q{I didn't find any history matching what you requested.});
98 0 0       0 }
99 0         0 else {
100             my $html = join( "\n", map {
101             /^\[(?<timestamp>[^\]]+)\]\s(?:\:(?<nick>[^!]+)!)?.*?PRIVMSG\s$in->{forum}\s:(?<text>.+)$/;
102             my $parts = {%+};
103 0         0 $parts->{nick} //= 'ME';
  0         0  
104 0         0  
105 0   0     0 qq{
106             <p style="text-indent: -3em; margin: 0; margin-left: 3em">
107 0         0 <i>$parts->{timestamp}</i>
108             <b>$parts->{nick}</b>
109             $parts->{text}
110             </p>
111             };
112             } @matches );
113              
114             $html =~ s|(\w+://[\w\-\.!@#$%^&*-_+=;:,]+)|<a href="$1">$1</a>|g;
115              
116 0         0 Email::Mailer->send(
117             to => $m->{email},
118             from => $m->{email},
119             subject => "IRC $in->{forum} history $subject",
120             html => $html,
121 0         0 );
122              
123             $bot->reply_to(
124             'OK. I just sent ' . $m->{email} . ' an email with ' .
125             scalar(@matches) . ' matching history lines.'
126 0         0 );
127             }
128             }
129             },
130             );
131              
132 1         23 $bot->helps( history =>
133             'Dump selected channel history to email. ' .
134 1         15 'Usage: "history on DATE EMAIL" or "history from DATE to DATE EMAIL" or "history matching STRING EMAIL".'
135             );
136             }
137              
138             1;
139              
140              
141             =pod
142              
143             =encoding UTF-8
144              
145             =head1 NAME
146              
147             Bot::IRC::History - Bot::IRC selected channel history dumped to email
148              
149             =head1 VERSION
150              
151             version 1.39
152              
153             =head1 SYNOPSIS
154              
155             use Bot::IRC;
156              
157             Bot::IRC->new(
158             connect => { server => 'irc.perl.org' },
159             plugins => ['History'],
160             history => { filter => ['#perl'] },
161             )->run;
162              
163             =head1 DESCRIPTION
164              
165             This L<Bot::IRC> plugin gives the bot the capability to dump channel chat
166             history to an email.
167              
168             The bot will only dump history from which the request originates. If you are
169             currently in a channel, the bot will happily dump you anything from that
170             channel's history, even prior to your joining. The idea here being that if
171             you've got access to join a channel, you have access to that channel's history.
172              
173             If you don't like this behavior, don't load this plugin.
174              
175             =head2 Requesting History
176              
177             To request channel history for the channel you're currently in:
178              
179             bot history on DATE EMAIL
180             bot history from DATE to DATE EMAIL
181             bot history matching STRING EMAIL
182              
183             =head2 Filtering Channels
184              
185             You can specify the channels to filter or disallow from history with C<vars>,
186             C<history>, C<filter>, which can be either a string or arrayref.
187              
188             Bot::IRC->new(
189             connect => { server => 'irc.perl.org' },
190             plugins => ['History'],
191             history => { filter => ['#perl'] },
192             )->run;
193              
194             =head2 SEE ALSO
195              
196             L<Bot::IRC>
197              
198             =for Pod::Coverage init
199              
200             =head1 AUTHOR
201              
202             Gryphon Shafer <gryphon@cpan.org>
203              
204             =head1 COPYRIGHT AND LICENSE
205              
206             This software is Copyright (c) 2016-2050 by Gryphon Shafer.
207              
208             This is free software, licensed under:
209              
210             The Artistic License 2.0 (GPL Compatible)
211              
212             =cut