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