]> git.donarmstrong.com Git - infobot.git/blob - src/Modules/Freshmeat.pl
Initial revision
[infobot.git] / src / Modules / Freshmeat.pl
1 #
2 # Freshmeat.pl: Frontend to www.freshmeat.net
3 #       Author: xk <xk@leguin.openprojects.net>
4 #      Version: v0.7c (20000606)
5 #      Created: 19990930
6 #
7
8 package Freshmeat;
9
10 use strict;
11
12 ### download compressed version instead?
13
14 my %urls = (
15         'public'  => 'http://core.freshmeat.net/backend/appindex.txt',
16         'private' => 'http://feed.freshmeat.net/appindex/appindex.txt',
17 );
18
19 ####
20 # Usage: &Freshmeat($string);
21 sub Freshmeat {
22     my $sstr    = lc($_[0]);
23     my $refresh = $main::param{'freshmeatRefreshInterval'} * 60 * 60;
24
25     my $last_refresh = &main::dbGet("freshmeat", "name","_","stable");
26     my $renewtable   = 0;
27
28     if (defined $last_refresh) {
29         $renewtable++ if (time() - $last_refresh > $refresh);
30     } else {
31         $renewtable++;
32     }
33     $renewtable++ if (&main::countKeys("freshmeat") < 10);
34
35     if ($renewtable and $$ == $main::infobot_pid) {
36         &main::Forker("freshmeat", sub {
37                 &downloadIndex();
38                 &Freshmeat($sstr);
39         } );
40         return if ($$ == $main::infobot_pid);
41     }
42
43     if (!&showPackage($sstr)) {         # no exact match.
44         my $start_time = &main::gettimeofday();
45         my %hash;
46
47         # search by key first.
48         foreach (&main::searchTable("freshmeat", "name","name",$sstr)) {
49             $hash{$_} = 1 unless exists $hash{$_};
50         }
51
52         foreach (&main::searchTable("freshmeat", "name","oneliner", $sstr)) {
53             $hash{$_} = 1 unless exists $hash{$_};
54             last if (scalar keys %hash > 15);
55         }
56
57         my @list = keys %hash;
58         # search by value, if we have enough room to do it.
59         if (scalar @list == 1) {
60             &main::DEBUG("only one partial match found; showing full info.");
61             &showPackage($list[0]);
62             return;
63         }
64
65         # show how long it took.
66         my $delta_time = &main::gettimeofday() - $start_time;
67         &main::status(sprintf("freshmeat: %.02f sec to complete query.", $delta_time)) if ($delta_time > 0);
68
69         for (@list) {
70             tr/A-Z/a-z/;
71             s/([\,\;]+)/\037$1\037/g;
72         }
73
74         &main::performStrictReply( &main::formListReply(1, "Freshmeat ", @list) );
75     }
76 }
77
78 sub showPackage {
79     my ($pkg)   = @_;
80     my @fm      = &main::dbGet("freshmeat", "name",$pkg,"*");
81
82     if (scalar @fm) {           #1: perfect match of name.
83         my $retval;
84         $retval  = "$fm[0] \002(\002$fm[11]\002)\002, ";
85         $retval .= "section $fm[3], ";
86         $retval .= "is $fm[4]. ";
87         $retval .= "Stable: \002$fm[1]\002, ";
88         $retval .= "Development: \002$fm[2]\002. ";
89         $retval .= $fm[5] || $fm[6];             # fallback to 'download'.
90         $retval .= " deb: ".$fm[8] if ($fm[8] ne ""); # 'deb'.
91         &main::performStrictReply($retval);
92         return 1;
93     } else {
94         return 0;
95     }
96 }
97
98 sub downloadIndex {
99     my $start_time      = &main::gettimeofday(); # set the start time.
100     my $idx             = "$main::infobot_base_dir/Temp/fm_index.txt";
101
102     &main::msg($main::who, "Updating freshmeat index... please wait");
103
104     if (&main::isStale($idx, 1)) {
105         &main::status("Freshmeat: fetching data.");
106         foreach (keys %urls) {
107             &main::DEBUG("FM: urls{$_} => '$urls{$_}'.");
108             my $retval = &main::getURLAsFile($urls{$_}, $idx);
109             next if ($retval eq "403");
110             &main::DEBUG("FM: last! retval => '$retval'.");
111             last;
112         }
113     } else {
114         &main::status("Freshmeat: local file hack.");
115     }
116
117     if (! -e $idx) {
118         &main::msg($main::who, "the freshmeat butcher is closed.");
119         return;
120     }
121
122     if ( -s $idx < 100000) {
123         &main::DEBUG("FM: index too small?");
124         unlink $idx;
125         &main::msg($main::who, "internal error?");
126         return;
127     }
128
129     ### TODO: do not dump full contents to an array.
130     ###         => process on the fly instead but how?
131     open(IN, $idx);
132
133     # delete the table before we redo it.
134     &main::deleteTable("freshmeat");
135
136     ### lets get on with business.
137     # set the last refresh time. fixes multiple spawn bug.
138     &main::dbSet("freshmeat", "name","_","stable",time());
139
140     my $i = 0;
141     while (my $line = <IN>) {
142         chop $line;
143         $i++ if ($line eq "%%");
144         last if ($i == 2);
145     }
146
147     &main::dbRaw("LOCK", "LOCK TABLES freshmeat WRITE");
148     my @data;
149     while (my $line = <IN>) {
150         chop $line;
151         if ($line ne "%%") {
152             push(@data,$line);
153             next;
154         }
155
156         if ($i % 100 == 0 and $i != 0) {
157             &main::DEBUG("FM: unlocking and locking.");
158             &main::dbRaw("UNLOCK", "UNLOCK TABLES");
159             sleep 1;    # another lame hack to "prevent" errors.
160             &main::dbRaw("LOCK", "LOCK TABLES freshmeat WRITE");
161         }
162
163         $i++;
164         pop @data;
165         $data[1] ||= "none";
166         $data[2] ||= "none";
167         &main::dbSetRow("freshmeat", @data);
168         @data = ();
169     }
170     close IN;
171     &main::DEBUG("FM: data ".scalar(@data) );
172     &main::dbRaw("UNLOCK", "UNLOCK TABLES");
173
174     my $delta_time = &main::gettimeofday() - $start_time;
175     &main::status(sprintf("Freshmeat: %.02f sec to complete.", $delta_time)) if ($delta_time > 0);
176
177     my $count = &main::countKeys("freshmeat");
178     &main::status("Freshmeat: $count entries loaded.");
179 }
180
181 sub freshmeatAnnounce {
182     my $file = "$main::infobot_base_dir/Temp/fm_recent.txt";
183     my @old;
184
185     if ( -f $file) {
186         open(IN, $file);
187         while (<IN>) {
188             chop;
189             push(@old,$_);
190         }
191         close IN;
192     }
193
194     my @array = &main::getURL("http://core.freshmeat.net/backend/recentnews.txt");
195     my @now;
196
197     while (@array) {
198         my($what,$date,$url) = splice(@array,0,3);
199         push(@now, $what);
200     }
201
202     ### ...
203
204     if (! -f $file) {
205         open(OUT, ">$file");
206         foreach (@now) {
207             print OUT "$_\n";
208         }
209         close OUT;
210
211         return;
212     }
213
214     my @new;
215     for(my $i=0; $i<scalar(@old); $i++) {
216         last if ($now[$i] eq $old[0]);
217         push(@new, $now[$i]);
218     }
219
220     if (!scalar @new) {
221         &main::DEBUG("fA: no new items.");
222         return;
223     }
224
225     my $chan;
226     my @chans = split(/[\s\t]+/, lc $main::param{'freshmeatAnnounce'});
227     @chans    = keys(%main::channels) unless (scalar @chans);
228
229     my $line = "Freshmeat update: ".join(" \002::\002 ", @new);
230     foreach (@chans) {
231         next unless (&main::validChan($_));
232
233         &main::status("sending freshmeat update to $_.");
234         &main::notice($_, $line);
235     }
236
237     open(OUT, ">$file");
238     foreach (@now) {
239         print OUT "$_\n";
240     }
241     close OUT;
242 }
243
244 1;