1 ################################
3 ################################
4 # this is really an RSS module, not an RDF module.
7 package BotModules::RDF;
10 @ISA = qw(BotModules);
13 # RegisterConfig - Called when initialised, should call registerVariables
16 $self->SUPER::RegisterConfig(@_);
17 $self->registerVariables(
18 # [ name, save?, settable? ]
20 ['updateDelay', 1, 1, 600],
21 ['preferredLineLength', 1, 1, 80],
22 ['maxInChannel', 1, 1, 5],
23 ['maxLines', 1, 1, 20],
24 ['trimTitles', 1, 1, '0'],
25 ['data', 0, 0, {}], # data -> uri -> (title, link, last, items -> uri)
26 ['mutes', 1, 1, {}], # uri -> "channel channel channel"
30 # Schedule - called when bot connects to a server, to install any schedulers
31 # use $self->schedule($event, $delay, $times, $data)
32 # where $times is 1 for a single event, -1 for recurring events,
33 # and a +ve number for an event that occurs that many times.
37 $self->schedule($event, \$self->{'updateDelay'}, -1, 'rdf');
38 $self->SUPER::Schedule($event);
45 if ($self->isAdmin($event)) {
46 $commands{''} = "The RDF module monitors various websites. Add new RDF channels to the 'sites' hash. Duplicates with different nicknames are fine. For example, \"vars $self->{'_name'} sites '+|slashdot|http://...'\" and \"vars $self->{'_name'} sites '+|/.|http://...'\" is fine. To remove a site from the RDF 'sites' hash, use this syntax \"vars $self->{_name} sites '-slashdot'";
47 $commands{'mute'} = 'Disable reporting of a site in a channel. (Only does something if the given site exists.) Syntax: mute <site> in <channel>';
48 $commands{'unmute'} = 'Enable reporting of a site in a channel. By default, sites are reported in all channels that the module is active in. Syntax: unmute <site> in <channel>';
50 $commands{''} = 'The RDF module monitors various websites.';
52 foreach my $site (keys(%{$self->{'sites'}})) {
53 if ($self->{'data'}->{$self->{'sites'}->{$site}}) {
54 $commands{$site} = "Reports the headlines listed in $self->{'data'}->{$self->{'sites'}->{$site}}->{'title'}";
56 # -- #mozilla was here --
57 # <Hixie> anyway, $self->{'data'}->{$self->{'sites'}->{$site}}->{'title'} is
58 # another nice piece of perl (embedded in a quoted string in this case)
59 # <moogle> yeah, that's a bit more familiar
60 # <jag> Oooh, nice one
61 # <jag> Reminds me of Java, a bit :-)
62 # <jag> Without all the casting about from Object to Hashtable
63 # <Hixie> all this, BTW, is from the RDF module (the one that mozbot uses to
64 # report changes in mozillazine and so on)
65 # <moogle> I still tend to comment these things a bit just for maintainability
66 # by others who might not wish to do mental gymnastics :)
70 $commands{$site} = "Reports the headlines listed in $self->{'sites'}->{$site}";
79 my ($event, $message) = @_;
80 foreach my $site (keys(%{$self->{'sites'}})) {
81 if ($message =~ /^\s*(\Q$site\E)\s*$/si) {
82 $self->GetSite($event, $1, 'request');
83 return 0; # dealt with it...
86 if ($self->isAdmin($event)) {
87 if ($message =~ /^\s*mute\s+(\S+?)\s+in\s+(\S+?)\s*$/osi) {
88 my $site = $1 eq 'RDF' ? '' : $self->{'sites'}->{$1};
89 my $siteName = $site eq '' ? 'all sites' : $site;
91 $self->{'mutes'}->{$site} .= " $2";
93 $self->say($event, "$event->{'from'}: RDF notifications for $siteName muted in channel $2.");
95 # can't say this, other modules might recognise it: $self->say($event, "$event->{'from'}: I don't know about any '$1' site...");
97 } elsif ($message =~ /^\s*unmute\s+(\S+?)\s+in\s+(\S+?)\s*$/osi) {
98 my $site = $1 eq 'RDF' ? '' : $self->{'sites'}->{$1};
99 my $siteName = $site eq '' ? 'all sites' : $site;
100 if (defined($site)) {
101 my %mutedChannels = map { lc($_) => 1 } split(/ /o, $self->{'mutes'}->{$site});
102 delete($mutedChannels{lc($2)}); # get rid of any mentions of that channel
103 $self->{'mutes'}->{$site} = join(' ', keys(%mutedChannels));
105 $self->say($event, "$event->{'from'}: RDF notifications for $siteName resumed in channel $2.");
107 # can't say this, other modules might recognise it: $self->say($event, "$event->{'from'}: I don't know about any '$1' site...");
110 return $self->SUPER::Told(@_);
113 return $self->SUPER::Told(@_);
120 my ($event, $site, $intent) = @_;
121 if (defined($self->{'sites'}->{$site})) {
122 my $uri = $self->{'sites'}->{$site};
123 $self->getURI($event, $uri, $intent);
131 my ($event, $uri, $output, $intent) = @_;
133 $self->{'data'}->{$uri}->{'ready'} = defined($self->{'data'}->{$uri});
138 my $last = $event->{'time'};
139 $self->{'data'}->{$uri}->{'last'} = $last;
142 my $rss = XML::RSS->new();
143 eval { $rss->parse($output) };
145 $self->debug("$uri is not a valid RSS file");
146 if ($intent eq 'request') {
147 $self->say($event, "$event->{'from'}: Dude, the file is not valid RSS! ($uri)");
153 $self->{data}->{$uri}->{'link'} = $rss->{'channel'}->{'link'};
154 $self->{data}->{$uri}->{'title'} = $rss->{'channel'}->{'title'};
156 foreach my $item (@{$rss->{'items'}}) {
157 unless (($item->{title} =~ /^last update/osi) ||
158 (defined($self->{'data'}->{$uri}->{'items'}->{$item->{'title'}}))) {
159 $self->{'data'}->{$uri}->{'items'}->{$item->{'title'}} = $last;
163 $self->ReportDiffs($event, $uri, $intent);
164 if ($intent eq 'request') {
165 $self->ReportAll($event, $uri);
170 if ($intent eq 'request') {
171 $self->say($event, "$event->{'from'}: Dude, the file was empty! ($uri)");
180 my ($event, @data) = @_;
181 if ($data[0] eq 'rdf') {
182 my %sites = map { $_ => 1 } values(%{$self->{'sites'}});
183 foreach (keys(%sites)) {
184 $self->getURI($event, $_, 'update');
187 $self->SUPER::Scheduled($event, @data);
193 my ($event, $uri, $request) = @_;
194 return unless $self->{'data'}->{$uri}->{'ready'};
195 my $last = $self->{'data'}->{$uri}->{'last'};
197 foreach (keys(%{$self->{'data'}->{$uri}->{'items'}})) {
198 push(@output, $_) if ($self->{'data'}->{$uri}->{'items'}->{$_} == $last);
201 # -- #mrt was here --
202 # <mozbot> Friday's security advisories -- The first stable
203 # Xen release -- Linux Gazette #95
204 # <mozbot> KDE Under The Microscope -- Additional OpenSSL info
206 # <mozbot> Just appeared in jbisbee.com -
207 # http://www.jbisbee.com/ : PoCo::RSS::Aggregator
208 # <Hixie> why is it repeating the same thing over and over
209 # <mozbot> PoCo::RSSAggregator & XML::RSS::Feed Uploaded to
210 # CPAN -- More PoCo::RSSAggregator
211 # <Hixie> mozbot: shutup please
212 # <mozbot> Ok, threw away 2558 messages.
214 # Ahem. So now we limit the diff reporting code to maxInChannel
217 if (@output and @output < $self->{'maxInChannel'}) {
218 my %mutedChannels = ();
219 if (defined($self->{'mutes'}->{$uri})) {
220 %mutedChannels = map { lc($_) => 1 } split(/\s+/os, $self->{'mutes'}->{$uri});
222 if (defined($self->{'mutes'}->{''})) {
223 %mutedChannels = (%mutedChannels, map { lc($_) => 1 } split(/\s+/os, $self->{'mutes'}->{''}));
225 if ($request eq 'request') {
226 $mutedChannels{$event->{'channel'}} = 1;
228 foreach (@{$self->{'channels'}}) {
229 unless ($mutedChannels{$_}) {
230 local $event->{'target'} = $_;
231 $self->say($event, "Just appeared in $self->{'data'}->{$uri}->{'title'} - $self->{'data'}->{$uri}->{'link'} :");
233 $self->say($event, " " . $_);
242 my ($event, $uri) = @_;
244 foreach (keys(%{$self->{'data'}->{$uri}->{'items'}})) {
248 @output = $self->prettyPrint($self->{'preferredLineLength'},
249 "Items in $self->{'data'}->{$uri}->{'title'} - $self->{'data'}->{$uri}->{'link'}: ",
250 "$event->{'from'}: ", ' -- ', @output);
252 if (@output > $self->{'maxLines'}) {
253 splice(@output, $self->{'maxLines'} + 1);
254 unshift(@output, "The list is longer than $self->{'maxLines'}"
255 . " lines, only the first $self->{'maxLines'} will be shown.");
258 if (@output > $self->{'maxInChannel'}) {
260 $self->directSay($event, $_);
262 $self->channelSay($event, "$event->{'from'}: /msg'ed");
265 $self->say($event, $_);