| 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
|
|
2718
|
use 5.014; |
|
|
1
|
|
|
|
|
4
|
|
|
5
|
1
|
|
|
1
|
|
8
|
use exact; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
7
|
|
|
6
|
|
|
|
|
|
|
|
|
7
|
1
|
|
|
1
|
|
924
|
use Date::Format 'time2str'; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
49
|
|
|
8
|
1
|
|
|
1
|
|
493
|
use Date::Parse 'str2time'; |
|
|
1
|
|
|
|
|
2971
|
|
|
|
1
|
|
|
|
|
108
|
|
|
9
|
1
|
|
|
1
|
|
590
|
use Email::Mailer; |
|
|
1
|
|
|
|
|
359890
|
|
|
|
1
|
|
|
|
|
47
|
|
|
10
|
1
|
|
|
1
|
|
580
|
use Email::Valid; |
|
|
1
|
|
|
|
|
58104
|
|
|
|
1
|
|
|
|
|
164
|
|
|
11
|
1
|
|
|
1
|
|
538
|
use File::Grep 'fgrep'; |
|
|
1
|
|
|
|
|
1548
|
|
|
|
1
|
|
|
|
|
1821
|
|
|
12
|
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
our $VERSION = '1.40'; # VERSION |
|
14
|
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
sub init { |
|
16
|
1
|
|
|
1
|
0
|
6441
|
my ($bot) = @_; |
|
17
|
1
|
|
|
|
|
11
|
my $vars = $bot->vars; |
|
18
|
1
|
50
|
|
|
|
7
|
my @filter = ( ref $vars->{filter} ) ? @{ $vars->{filter} } : ( $vars->{filter} ); |
|
|
0
|
|
|
|
|
0
|
|
|
19
|
1
|
|
|
|
|
6
|
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
|
|
|
|
|
19
|
); |
|
133
|
|
|
|
|
|
|
|
|
134
|
1
|
|
|
|
|
19
|
$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.40 |
|
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-2050 by Gryphon Shafer. |
|
210
|
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
This is free software, licensed under: |
|
212
|
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
The Artistic License 2.0 (GPL Compatible) |
|
214
|
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
=cut |