-# This is the database configuration for Insipid. The "dbtype" parameter\r
-# can be either "mysql" for the MySQL database or "Pg" for PostgreSQL.\r
-dbname = insipid_luke\r
-dbuser = luke\r
-dbpass = dbpass\r
-dbtype = mysql\r
-\r
-# If you'd like the Insipid database tables to use a prefix, uncomment\r
-# this line.\r
-#dbprefix = insipid_\r
-\r
-# The base URI to your installation.\r
-pagepath = /Luke\r
-\r
-# If your webserver is not running on port 80 and it doesn't properly set\r
-# the SERVER_PORT variable, set it here.\r
-#server_port = 8080\r
-\r
-# The login name and password for using the Insipid interface.\r
-username = luke\r
-userpass = yourpassword\r
-\r
+# This is the database configuration for Insipid.
+dbname = insipid_luke
+dbuser = luke
+dbpass = dbpass
+
+# If you'd like the Insipid database tables to use a prefix, uncomment
+# this line.
+#dbprefix = insipid_
+
+# The base URI to your installation.
+pagepath = /Luke
+
+# If your webserver is not running on port 80 and it doesn't properly set
+# the SERVER_PORT variable, set it here.
+#server_port = 8080
+
+# The login name and password for using the Insipid interface.
+username = luke
+userpass = yourpassword
+
$dbpass = getconfig('dbpass');
$dbhost = getconfig('dbhost');
- if(defined(getconfig('dbtype'))) {
- $dbtype = getconfig('dbtype');
- } else {
- $dbtype = 'mysql';
- }
+ $dbtype = 'mysql';
$dsn = "DBI:$dbtype:dbname=$dbname;host=$dbhost";
$dbh = DBI->connect($dsn, $dbuser, $dbpass, { 'RaiseError' => 0}) or die $DBI::errstr;
print "<p>Creating tables...";
- if($dbtype eq 'mysql') {
- @creates = split(/\;/, $createMySQL);
- } else {
- @creates = split(/\;/, $createPostgres);
- }
+ @creates = split(/\;/, $createMySQL);
foreach(@creates) {
my $sql = $_;
$dbpass = getconfig('dbpass');
$dbhost = getconfig('dbhost');
-if(defined(getconfig('dbtype'))) {
- $dbtype = getconfig('dbtype');
-} else {
- $dbtype = 'mysql';
-}
+$dbtype = 'mysql';
$dsn = "DBI:$dbtype:dbname=$dbname;host=$dbhost";
$dbh = DBI->connect($dsn, $dbuser, $dbpass, { 'RaiseError' => 0}) or die $DBI::errstr;
-#!/usr/bin/perl\r
-#\r
-# Copyright (C) 2008 Luke Reeves\r
-#\r
-# This program is free software; you can redistribute it and/or modify\r
-# it under the terms of the GNU General Public License as published by\r
-# the Free Software Foundation; either version 2 of the License, or\r
-# (at your option) any later version.\r
-#\r
-# This program is distributed in the hope that it will be useful,\r
-# but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-# GNU General Public License for more details.\r
-#\r
-# You should have received a copy of the GNU General Public License\r
-# along with this program; if not, write to the Free Software\r
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307\r
-# USA\r
-#\r
-\r
-package Insipid::JSON;\r
-\r
-use strict;\r
-use warnings;\r
-\r
-use vars qw(@ISA @EXPORT @EXPORT_OK);\r
-use CGI qw/:standard/;\r
-use CGI::Carp qw(fatalsToBrowser);\r
-use Insipid::Config;\r
-use Insipid::Database;\r
-use Insipid::Sessions;\r
-use Date::Format;\r
-use Date::Parse;\r
-\r
-require Exporter;\r
-\r
-@ISA = qw(Exporter);\r
-\r
-@EXPORT = qw(\r
-send_json_tags\r
-send_json_posts\r
-);\r
-\r
-my $query = '';\r
-my $last_page = 0;\r
-\r
-\r
-\r
-sub send_json_tags {\r
- my ($sql, $sth);\r
- \r
- # Building up JSON structure before parsing the data:\r
- my ($json_prefix,$json_suffix);\r
- # limiting url_param('callback') to a reasonable length (100): \r
- if((defined(url_param('callback'))) && (length(url_param('callback')) < 100)){\r
- $json_prefix = ''.url_param('callback').'({';\r
- $json_suffix = '})';\r
- } elsif(url_param('raw') eq 1) {\r
- $json_prefix = '{';\r
- $json_suffix = '}';\r
- } else {\r
- $json_prefix = 'if(typeof(Insipid) == \'undefined\') Insipid = {}; Insipid.tags = {';\r
- $json_suffix = '}';\r
- }\r
- #limiting tags count, only if url_param('count') is a valid integer:\r
- my $limit ;\r
- if (url_param('count') =~ /^[+-]?\d+$/) {\r
- $limit = ' limit '.url_param('count') ;\r
- }\r
-\r
-\r
-\r
- # If the user has already chosen a tag, get the intersection list\r
- if((url_param('tag')) && (logged_in() eq 1)) {\r
- $sql = "select $tbl_tags.name,count(*) from $tbl_bookmarks\r
- inner join $tbl_bookmark_tags as bt1 on\r
- ($tbl_bookmarks.id = bt1.bookmark_id)\r
- inner join $tbl_tags on\r
- ($tbl_tags.id = bt1.tag_id)\r
- inner join $tbl_bookmark_tags as bt2 on\r
- ($tbl_bookmarks.id = bt2.bookmark_id)\r
- inner join $tbl_tags as t2 on\r
- (t2.id = bt2.tag_id and t2.name = ?)\r
- where ($tbl_tags.name != ?)\r
- group by $tbl_tags.name $limit";\r
- $sth = $dbh->prepare($sql);\r
- $sth->execute(url_param('tag'), url_param('tag'));\r
- print $json_prefix ;\r
- if($sth->rows ne 0) {\r
- my $icount = 1 ;\r
- while(my @r = $sth->fetchrow_array()) {\r
- json_show_tag($icount, $sth->rows, $r[0], $r[1]);\r
- $icount++ ;\r
- }\r
- }\r
- print $json_suffix ; \r
- return ;\r
- } else {\r
-\r
- # Access_spec contains a where clause to count only public bookmarks\r
- # if the user is not logged in\r
- my $access_where = "";\r
- if(logged_in() eq 0) {\r
- $access_where = " where ($tbl_bookmarks.access_level = 1) ";\r
- }\r
-\r
- my $order_clause;\r
- if($dbtype eq "Pg") {\r
- $order_clause = "order by upper($tbl_tags.name)";\r
- } else {\r
- $order_clause = "order by $tbl_tags.name";\r
- }\r
-\r
- $sql = "select $tbl_tags.name, count(*)\r
- from $tbl_bookmarks\r
- inner join $tbl_bookmark_tags on\r
- ($tbl_bookmarks.id = $tbl_bookmark_tags.bookmark_id)\r
- inner join $tbl_tags on\r
- ($tbl_tags.id = $tbl_bookmark_tags.tag_id)\r
- $access_where\r
- group by $tbl_tags.name\r
- $order_clause \r
- $limit";\r
-\r
- $sth = $dbh->prepare($sql);\r
- $sth->execute;\r
- print $json_prefix;\r
- if($sth->rows ne 0) {\r
- my $icount = 1;\r
- while(my @r = $sth->fetchrow_array()) {\r
- json_show_tag($icount, $sth->rows, $r[0], $r[1]); \r
- $icount++;\r
- }\r
- }\r
- print $json_suffix;\r
- return;\r
- }\r
-}\r
-\r
-sub json_show_tag {\r
- my($icount, $rowscount, $tag, $tagcount) = (@_);\r
- $tag =~ s/\"/\\"/g ;\r
- my $json_txt = '';\r
- $json_txt = $json_txt.'"'.$tag.'":'.$tagcount;\r
- if ($icount ne $rowscount){\r
- $json_txt = $json_txt.',';\r
- }\r
- print $json_txt ;\r
-}\r
-\r
-sub send_json_posts {\r
- \r
- # Building up JSON structure before parsing the data:\r
- my ($json_prefix,$json_suffix);\r
- # limiting url_param('callback') to a reasonable length: \r
- if((defined(url_param('callback'))) && (length(url_param('callback')) < 100)){\r
- $json_prefix = ''.url_param('callback').'([';\r
- $json_suffix = '])';\r
- } elsif(url_param('raw') eq 1) {\r
- $json_prefix = '[';\r
- $json_suffix = ']';\r
- } else {\r
- $json_prefix = 'if(typeof(Insipid) == \'undefined\') Insipid = {}; Insipid.posts = [';\r
- $json_suffix = ']';\r
- }\r
- #limiting posts count to url_param('count') , setting hard limit to 100 and default limit to 50 :\r
- my $limit ;\r
- if ((url_param('count') =~ /^[+-]?\d+$/) && (url_param('count') < 101)) {\r
- $limit = url_param('count') ;\r
- } else {\r
- $limit = 50 ;\r
- }\r
- \r
- my ($subquery, $sql, $sth, @parms, @wheres, @hr);\r
-\r
- # this first query will be used to select from a set, like when a user\r
- # drills in on a specific tag or to get a smaller view of the entire\r
- # dataset (for paging purposes).\r
-\r
- # MySQL and postgres have slightly different syntax here...\r
- if ($dbtype eq 'mysql') {\r
- $sql = "select $tbl_bookmarks.id from $tbl_bookmarks";\r
- } elsif ($dbtype eq 'Pg') {\r
- $sql = "select $tbl_bookmarks.id, $tbl_bookmarks.date\r
- from $tbl_bookmarks";\r
- }\r
-\r
- # Limit to tags\r
- if(defined(url_param('tag'))) {\r
- # Join the tag tables only when necessary\r
-\r
- if(url_param('tag') =~ / /) {\r
- my @tags = split(/ /, url_param('tag'));\r
- my $icount = 1;\r
-\r
- foreach(@tags) {\r
- push(@parms, $_);\r
- $sql = "$sql inner join $tbl_bookmark_tags\r
- as bt$icount on\r
- ($tbl_bookmarks.id =\r
- bt$icount.bookmark_id)\r
- inner join $tbl_tags as t$icount on\r
- (t$icount.id = bt$icount.tag_id\r
- and t$icount.name = ?) ";\r
- $icount++;\r
- }\r
- } else {\r
- $sql = "$sql\r
- left join $tbl_bookmark_tags on\r
- ($tbl_bookmarks.id =\r
- $tbl_bookmark_tags.bookmark_id)\r
- inner join $tbl_tags on\r
- ($tbl_tags.id = $tbl_bookmark_tags.tag_id)\r
- where ($tbl_tags.name = ?)";\r
- push(@parms, url_param('tag'));\r
- }\r
-\r
- }\r
-\r
- # Search \r
- # ?q=\r
- $query = url_param('q');\r
- if($query ne "") {\r
- if((get_option("public_searches") eq "yes") || (logged_in() eq 1)) {\r
- my $sparm = $query;\r
- if(length($sparm) > 2) {\r
- $sql = "$sql where ($tbl_bookmarks.title like ?)";\r
- $sparm =~ s/\%//;\r
- $sparm = "\%$sparm\%";\r
- push(@parms, $sparm);\r
- }\r
- }\r
- }\r
-\r
- # order\r
- $sql = "$sql order by $tbl_bookmarks.date desc";\r
-\r
- # paging functionality\r
- $sql = "$sql limit $limit";\r
- \r
- \r
- if(url_param('page')) {\r
- my $offset = ((url_param('page') - 1) * $limit);\r
- $sql = "$sql offset $offset";\r
- }\r
-\r
- $sth = $dbh->prepare($sql);\r
- $sth->execute(@parms);\r
-\r
- $subquery = "";\r
- if($sth->rows > 0) {\r
- if($sth->rows ne $limit) { $last_page = 1; }\r
-\r
- $subquery = " $tbl_bookmarks.id in (";\r
-\r
- while(@hr = $sth->fetchrow_array) {\r
- $subquery = $subquery . "$hr[0],";\r
- }\r
- chop($subquery); # Strip off the last delimiter\r
-\r
- $subquery = $subquery . ")";\r
- } else {\r
- # no bookmarks found:\r
- ###################\r
- print $json_prefix ;\r
- print $json_suffix ;\r
- ###################\r
- return;\r
- }\r
-\r
- @parms = ();\r
- @wheres = ();\r
-\r
- $sql = "select\r
- $tbl_bookmarks.id,\r
- $tbl_bookmarks.title,\r
- $tbl_bookmarks.description,\r
- $tbl_bookmarks.access_level,\r
- $tbl_bookmarks.url,\r
- $tbl_tags.name,\r
- $tbl_bookmarks.date,\r
- $tbl_pagecache.date as cache_date,\r
- $tbl_bookmarks.md5\r
- from $tbl_bookmarks\r
- left join $tbl_bookmark_tags on\r
- ($tbl_bookmarks.id = $tbl_bookmark_tags.bookmark_id)\r
- left join $tbl_tags on\r
- ($tbl_tags.id = $tbl_bookmark_tags.tag_id)\r
- left join $tbl_pagecache on\r
- ($tbl_bookmarks.md5 = $tbl_pagecache.md5)";\r
-\r
- # Don't show private marks for non-logged in users\r
- if(logged_in() eq 0) {\r
- push(@wheres, "$tbl_bookmarks.access_level");\r
- push(@parms, "1");\r
- }\r
-\r
- my $max = @wheres;\r
- if($max ne 0) {\r
- $sql = "$sql where (";\r
- my $count = 1;\r
-\r
- foreach (@wheres) {\r
- $sql = "$sql $_ = ?";\r
- if($count < $max) {\r
- $sql = "$sql and ";\r
- }\r
- $count++;\r
- }\r
-\r
- $sql = "$sql )";\r
- if($subquery ne "") { $sql = "$sql and $subquery"; }\r
- } else {\r
- if($subquery ne "") { $sql = "$sql where $subquery "; }\r
- }\r
-\r
- # append sort order.\r
- $sql = "$sql order by $tbl_bookmarks.date desc";\r
-\r
- $sth = $dbh->prepare($sql);\r
- $sth->execute(@parms);\r
-\r
- my %last;\r
- $last{id} = -1;\r
- \r
- \r
- ###################\r
- print $json_prefix ;\r
- ###################\r
- \r
- while(@hr = $sth->fetchrow_array) {\r
- if($last{id} eq -1) {\r
- $last{id} = $hr[0];\r
- $last{title} = $hr[1];\r
- $last{description} = $hr[2];\r
- $last{access_level} = $hr[3];\r
- $last{url} = $hr[4];\r
- $last{tags} = "";\r
- $last{timestamp} = $hr[6];\r
- }\r
-\r
- if($hr[0] ne $last{id}) {\r
- # the id changed, so show the last mark.\r
- json_show_post(0,$last{id}, $last{title}, $last{description}, $last{access_level}, $last{url}, $last{tags}, $last{timestamp});\r
-\r
- # Swap the new one in.\r
- $last{id} = $hr[0];\r
- $last{title} = $hr[1];\r
- $last{description} = $hr[2];\r
- $last{access_level} = $hr[3];\r
- $last{url} = $hr[4];\r
- $last{tags} = $hr[5];\r
- $last{timestamp} = $hr[6];\r
- } else {\r
- # Add tag to the current bookmark\r
- if(defined($hr[5])) {\r
- $last{tags} = "$last{tags} $hr[5]";\r
- }\r
- }\r
- }\r
-\r
- if($last{id} ne -1) {\r
- json_show_post(1,$last{id}, $last{title}, $last{description}, $last{access_level}, $last{url}, $last{tags}, $last{timestamp});\r
- }\r
-\r
- ###################\r
- print $json_suffix ;\r
- ###################\r
-}\r
-\r
-\r
-sub json_show_post {\r
- my($last_mark, $id, $title, $description, $access_level, $url,\r
- $tags, $timestamp) = (@_);\r
- $title =~ s/\"/\\"/g ;\r
- $description =~ s/\"/\\"/g ;\r
- $tags =~ s/\"/\\"/g ;\r
- my $json_txt = '{';\r
- \r
- if($access_level eq 0) {\r
- $json_txt = $json_txt.'"u":"'.$site_url.'/insipid.cgi?go='.$id.'",';\r
- $json_txt = $json_txt.'"d":"'.$title.'",';\r
- } else {\r
- $json_txt = $json_txt.'"u":"'.$url.'",';\r
- $json_txt = $json_txt.'"d":"'.$title.'",';\r
- }\r
-\r
- if($description){\r
- $json_txt = $json_txt.'"n":"'.$description.'",';\r
- }\r
- \r
- my $timestr = '';\r
- if(logged_in() eq 1) {\r
- $timestr = time2str('%Y-%m-%d %T EST', $timestamp, 'EST');\r
- } else {\r
- $timestr = time2str('%Y-%m-%d', $timestamp, 'EST');\r
- }\r
-\r
- $json_txt = $json_txt.'"dt":"'.$timestr.'"';\r
-\r
- if($tags) {\r
- $json_txt = $json_txt.',"t":[';\r
- my $cur;\r
- my @tags = split(/\ /, $tags);\r
- my $icount = 1 ;\r
- foreach my $tag (@tags) {\r
- if($tag){\r
- $json_txt = $json_txt.'"'.$tag.'"';\r
- if ($icount ne @tags){\r
- $json_txt = $json_txt.',';\r
- }\r
- }\r
- $icount++ ;\r
- }\r
- $json_txt = $json_txt.']'; \r
- }\r
- \r
- $json_txt = $json_txt.'}';\r
- \r
- if($last_mark ne 1){\r
- $json_txt = $json_txt.','; \r
- }\r
- \r
- print $json_txt ;\r
-}\r
-1;\r
-__END__\r
+#!/usr/bin/perl
+#
+# Copyright (C) 2008 Luke Reeves
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+# USA
+#
+
+package Insipid::JSON;
+
+use strict;
+use warnings;
+
+use vars qw(@ISA @EXPORT @EXPORT_OK);
+use CGI qw/:standard/;
+use CGI::Carp qw(fatalsToBrowser);
+use Insipid::Config;
+use Insipid::Database;
+use Insipid::Sessions;
+use Date::Format;
+use Date::Parse;
+
+require Exporter;
+
+@ISA = qw(Exporter);
+
+@EXPORT = qw(
+send_json_tags
+send_json_posts
+);
+
+my $query = '';
+my $last_page = 0;
+
+
+
+sub send_json_tags {
+ my ($sql, $sth);
+
+ # Building up JSON structure before parsing the data:
+ my ($json_prefix,$json_suffix);
+ # limiting url_param('callback') to a reasonable length (100):
+ if((defined(url_param('callback'))) && (length(url_param('callback')) < 100)){
+ $json_prefix = ''.url_param('callback').'({';
+ $json_suffix = '})';
+ } elsif(url_param('raw') eq 1) {
+ $json_prefix = '{';
+ $json_suffix = '}';
+ } else {
+ $json_prefix = 'if(typeof(Insipid) == \'undefined\') Insipid = {}; Insipid.tags = {';
+ $json_suffix = '}';
+ }
+ #limiting tags count, only if url_param('count') is a valid integer:
+ my $limit ;
+ if (url_param('count') =~ /^[+-]?\d+$/) {
+ $limit = ' limit '.url_param('count') ;
+ }
+
+
+
+ # If the user has already chosen a tag, get the intersection list
+ if((url_param('tag')) && (logged_in() eq 1)) {
+ $sql = "select $tbl_tags.name,count(*) from $tbl_bookmarks
+ inner join $tbl_bookmark_tags as bt1 on
+ ($tbl_bookmarks.id = bt1.bookmark_id)
+ inner join $tbl_tags on
+ ($tbl_tags.id = bt1.tag_id)
+ inner join $tbl_bookmark_tags as bt2 on
+ ($tbl_bookmarks.id = bt2.bookmark_id)
+ inner join $tbl_tags as t2 on
+ (t2.id = bt2.tag_id and t2.name = ?)
+ where ($tbl_tags.name != ?)
+ group by $tbl_tags.name $limit";
+ $sth = $dbh->prepare($sql);
+ $sth->execute(url_param('tag'), url_param('tag'));
+ print $json_prefix ;
+ if($sth->rows ne 0) {
+ my $icount = 1 ;
+ while(my @r = $sth->fetchrow_array()) {
+ json_show_tag($icount, $sth->rows, $r[0], $r[1]);
+ $icount++ ;
+ }
+ }
+ print $json_suffix ;
+ return ;
+ } else {
+
+ # Access_spec contains a where clause to count only public bookmarks
+ # if the user is not logged in
+ my $access_where = "";
+ if(logged_in() eq 0) {
+ $access_where = " where ($tbl_bookmarks.access_level = 1) ";
+ }
+
+ my $order_clause;
+ $order_clause = "order by $tbl_tags.name";
+
+ $sql = "select $tbl_tags.name, count(*)
+ from $tbl_bookmarks
+ inner join $tbl_bookmark_tags on
+ ($tbl_bookmarks.id = $tbl_bookmark_tags.bookmark_id)
+ inner join $tbl_tags on
+ ($tbl_tags.id = $tbl_bookmark_tags.tag_id)
+ $access_where
+ group by $tbl_tags.name
+ $order_clause
+ $limit";
+
+ $sth = $dbh->prepare($sql);
+ $sth->execute;
+ print $json_prefix;
+ if($sth->rows ne 0) {
+ my $icount = 1;
+ while(my @r = $sth->fetchrow_array()) {
+ json_show_tag($icount, $sth->rows, $r[0], $r[1]);
+ $icount++;
+ }
+ }
+ print $json_suffix;
+ return;
+ }
+}
+
+sub json_show_tag {
+ my($icount, $rowscount, $tag, $tagcount) = (@_);
+ $tag =~ s/\"/\\"/g ;
+ my $json_txt = '';
+ $json_txt = $json_txt.'"'.$tag.'":'.$tagcount;
+ if ($icount ne $rowscount){
+ $json_txt = $json_txt.',';
+ }
+ print $json_txt ;
+}
+
+sub send_json_posts {
+
+ # Building up JSON structure before parsing the data:
+ my ($json_prefix,$json_suffix);
+ # limiting url_param('callback') to a reasonable length:
+ if((defined(url_param('callback'))) && (length(url_param('callback')) < 100)){
+ $json_prefix = ''.url_param('callback').'([';
+ $json_suffix = '])';
+ } elsif(url_param('raw') eq 1) {
+ $json_prefix = '[';
+ $json_suffix = ']';
+ } else {
+ $json_prefix = 'if(typeof(Insipid) == \'undefined\') Insipid = {}; Insipid.posts = [';
+ $json_suffix = ']';
+ }
+ #limiting posts count to url_param('count') , setting hard limit to 100 and default limit to 50 :
+ my $limit ;
+ if ((url_param('count') =~ /^[+-]?\d+$/) && (url_param('count') < 101)) {
+ $limit = url_param('count') ;
+ } else {
+ $limit = 50 ;
+ }
+
+ my ($subquery, $sql, $sth, @parms, @wheres, @hr);
+
+ # this first query will be used to select from a set, like when a user
+ # drills in on a specific tag or to get a smaller view of the entire
+ # dataset (for paging purposes).
+
+ $sql = "select $tbl_bookmarks.id from $tbl_bookmarks";
+
+ # Limit to tags
+ if(defined(url_param('tag'))) {
+ # Join the tag tables only when necessary
+
+ if(url_param('tag') =~ / /) {
+ my @tags = split(/ /, url_param('tag'));
+ my $icount = 1;
+
+ foreach(@tags) {
+ push(@parms, $_);
+ $sql = "$sql inner join $tbl_bookmark_tags
+ as bt$icount on
+ ($tbl_bookmarks.id =
+ bt$icount.bookmark_id)
+ inner join $tbl_tags as t$icount on
+ (t$icount.id = bt$icount.tag_id
+ and t$icount.name = ?) ";
+ $icount++;
+ }
+ } else {
+ $sql = "$sql
+ left join $tbl_bookmark_tags on
+ ($tbl_bookmarks.id =
+ $tbl_bookmark_tags.bookmark_id)
+ inner join $tbl_tags on
+ ($tbl_tags.id = $tbl_bookmark_tags.tag_id)
+ where ($tbl_tags.name = ?)";
+ push(@parms, url_param('tag'));
+ }
+
+ }
+
+ # Search
+ # ?q=
+ $query = url_param('q');
+ if($query ne "") {
+ if((get_option("public_searches") eq "yes") || (logged_in() eq 1)) {
+ my $sparm = $query;
+ if(length($sparm) > 2) {
+ $sql = "$sql where ($tbl_bookmarks.title like ?)";
+ $sparm =~ s/\%//;
+ $sparm = "\%$sparm\%";
+ push(@parms, $sparm);
+ }
+ }
+ }
+
+ # order
+ $sql = "$sql order by $tbl_bookmarks.date desc";
+
+ # paging functionality
+ $sql = "$sql limit $limit";
+
+
+ if(url_param('page')) {
+ my $offset = ((url_param('page') - 1) * $limit);
+ $sql = "$sql offset $offset";
+ }
+
+ $sth = $dbh->prepare($sql);
+ $sth->execute(@parms);
+
+ $subquery = "";
+ if($sth->rows > 0) {
+ if($sth->rows ne $limit) { $last_page = 1; }
+
+ $subquery = " $tbl_bookmarks.id in (";
+
+ while(@hr = $sth->fetchrow_array) {
+ $subquery = $subquery . "$hr[0],";
+ }
+ chop($subquery); # Strip off the last delimiter
+
+ $subquery = $subquery . ")";
+ } else {
+ # no bookmarks found:
+ ###################
+ print $json_prefix ;
+ print $json_suffix ;
+ ###################
+ return;
+ }
+
+ @parms = ();
+ @wheres = ();
+
+ $sql = "select
+ $tbl_bookmarks.id,
+ $tbl_bookmarks.title,
+ $tbl_bookmarks.description,
+ $tbl_bookmarks.access_level,
+ $tbl_bookmarks.url,
+ $tbl_tags.name,
+ $tbl_bookmarks.date,
+ $tbl_pagecache.date as cache_date,
+ $tbl_bookmarks.md5
+ from $tbl_bookmarks
+ left join $tbl_bookmark_tags on
+ ($tbl_bookmarks.id = $tbl_bookmark_tags.bookmark_id)
+ left join $tbl_tags on
+ ($tbl_tags.id = $tbl_bookmark_tags.tag_id)
+ left join $tbl_pagecache on
+ ($tbl_bookmarks.md5 = $tbl_pagecache.md5)";
+
+ # Don't show private marks for non-logged in users
+ if(logged_in() eq 0) {
+ push(@wheres, "$tbl_bookmarks.access_level");
+ push(@parms, "1");
+ }
+
+ my $max = @wheres;
+ if($max ne 0) {
+ $sql = "$sql where (";
+ my $count = 1;
+
+ foreach (@wheres) {
+ $sql = "$sql $_ = ?";
+ if($count < $max) {
+ $sql = "$sql and ";
+ }
+ $count++;
+ }
+
+ $sql = "$sql )";
+ if($subquery ne "") { $sql = "$sql and $subquery"; }
+ } else {
+ if($subquery ne "") { $sql = "$sql where $subquery "; }
+ }
+
+ # append sort order.
+ $sql = "$sql order by $tbl_bookmarks.date desc";
+
+ $sth = $dbh->prepare($sql);
+ $sth->execute(@parms);
+
+ my %last;
+ $last{id} = -1;
+
+
+ ###################
+ print $json_prefix ;
+ ###################
+
+ while(@hr = $sth->fetchrow_array) {
+ if($last{id} eq -1) {
+ $last{id} = $hr[0];
+ $last{title} = $hr[1];
+ $last{description} = $hr[2];
+ $last{access_level} = $hr[3];
+ $last{url} = $hr[4];
+ $last{tags} = "";
+ $last{timestamp} = $hr[6];
+ }
+
+ if($hr[0] ne $last{id}) {
+ # the id changed, so show the last mark.
+ json_show_post(0,$last{id}, $last{title}, $last{description}, $last{access_level}, $last{url}, $last{tags}, $last{timestamp});
+
+ # Swap the new one in.
+ $last{id} = $hr[0];
+ $last{title} = $hr[1];
+ $last{description} = $hr[2];
+ $last{access_level} = $hr[3];
+ $last{url} = $hr[4];
+ $last{tags} = $hr[5];
+ $last{timestamp} = $hr[6];
+ } else {
+ # Add tag to the current bookmark
+ if(defined($hr[5])) {
+ $last{tags} = "$last{tags} $hr[5]";
+ }
+ }
+ }
+
+ if($last{id} ne -1) {
+ json_show_post(1,$last{id}, $last{title}, $last{description}, $last{access_level}, $last{url}, $last{tags}, $last{timestamp});
+ }
+
+ ###################
+ print $json_suffix ;
+ ###################
+}
+
+
+sub json_show_post {
+ my($last_mark, $id, $title, $description, $access_level, $url,
+ $tags, $timestamp) = (@_);
+ $title =~ s/\"/\\"/g ;
+ $description =~ s/\"/\\"/g ;
+ $tags =~ s/\"/\\"/g ;
+ my $json_txt = '{';
+
+ if($access_level eq 0) {
+ $json_txt = $json_txt.'"u":"'.$site_url.'/insipid.cgi?go='.$id.'",';
+ $json_txt = $json_txt.'"d":"'.$title.'",';
+ } else {
+ $json_txt = $json_txt.'"u":"'.$url.'",';
+ $json_txt = $json_txt.'"d":"'.$title.'",';
+ }
+
+ if($description){
+ $json_txt = $json_txt.'"n":"'.$description.'",';
+ }
+
+ my $timestr = '';
+ if(logged_in() eq 1) {
+ $timestr = time2str('%Y-%m-%d %T EST', $timestamp, 'EST');
+ } else {
+ $timestr = time2str('%Y-%m-%d', $timestamp, 'EST');
+ }
+
+ $json_txt = $json_txt.'"dt":"'.$timestr.'"';
+
+ if($tags) {
+ $json_txt = $json_txt.',"t":[';
+ my $cur;
+ my @tags = split(/\ /, $tags);
+ my $icount = 1 ;
+ foreach my $tag (@tags) {
+ if($tag){
+ $json_txt = $json_txt.'"'.$tag.'"';
+ if ($icount ne @tags){
+ $json_txt = $json_txt.',';
+ }
+ }
+ $icount++ ;
+ }
+ $json_txt = $json_txt.']';
+ }
+
+ $json_txt = $json_txt.'}';
+
+ if($last_mark ne 1){
+ $json_txt = $json_txt.',';
+ }
+
+ print $json_txt ;
+}
+1;
+__END__
my ($omd5, $ourl, $otype, $olength, $odate, $sql, $oadd, $omod, $otags);
my $ispec = '';
- if ($dbtype eq 'mysql') {$ispec = " ignore ";}
+ $ispec = " ignore ";
$sql = "insert $ispec into pagecache_references
(md5_parent, md5_child) values(?,?)";
$insert_snapshot->bind_param(3, $otype);
$insert_snapshot->bind_param(4, $olength);
- if ($dbtype eq "Pg") {
- $insert_snapshot->bind_param(5, decode_base64($cbuffer),
- SQL_VARBINARY);
- } else {
- $insert_snapshot->bind_param(5, decode_base64($cbuffer));
- }
+ $insert_snapshot->bind_param(5, decode_base64($cbuffer));
$insert_snapshot->bind_param(6, $odate);
$insert_snapshot->execute;
# drills in on a specific tag or to get a smaller view of the entire
# dataset (for paging purposes).
- # MySQL and postgres have slightly different syntax here...
- if ($dbtype eq 'mysql') {
- $sql = "select $tbl_bookmarks.id from $tbl_bookmarks";
- } elsif ($dbtype eq 'Pg') {
- $sql = "select $tbl_bookmarks.id, $tbl_bookmarks.date
- from $tbl_bookmarks";
- }
+ $sql = "select $tbl_bookmarks.id from $tbl_bookmarks";
# Limit to tags
if (defined(url_param('tag'))) {
-#!/usr/bin/perl\r
-#\r
-# Copyright (C) 2008 Luke Reeves\r
-#\r
-# This program is free software; you can redistribute it and/or modify\r
-# it under the terms of the GNU General Public License as published by\r
-# the Free Software Foundation; either version 2 of the License, or\r
-# (at your option) any later version.\r
-#\r
-# This program is distributed in the hope that it will be useful,\r
-# but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-# GNU General Public License for more details.\r
-#\r
-# You should have received a copy of the GNU General Public License\r
-# along with this program; if not, write to the Free Software\r
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307\r
-# USA\r
-#\r
-\r
-package Insipid::Schemas;\r
-\r
-use strict;\r
-use warnings;\r
-use Insipid::Config;\r
-\r
-use vars qw(\r
-@ISA\r
-@EXPORT\r
-$createMySQL\r
-$createPostgres\r
-);\r
-\r
-use Exporter;\r
-\r
-@ISA = qw(Exporter);\r
-\r
-@EXPORT = qw(\r
-$version\r
-$createMySQL\r
-$createPostgres\r
-);\r
-\r
-# Insipid will check the database version number on each initialization of\r
-# the options table (every hit essentially) and upgrade the tables if there's\r
-# any mismatch.\r
-our $version = "0.9.20";\r
-\r
-our $createPostgres = <<CPOSTGRES;\r
-CREATE TABLE $tbl_authentication (\r
- session_id CHAR(32) NOT NULL UNIQUE,\r
- create_time INT,\r
- PRIMARY KEY(session_id)\r
-);\r
-\r
-CREATE TABLE $tbl_bookmarks (\r
- id SERIAL,\r
- url TEXT NOT NULL,\r
- md5 CHAR(32) NOT NULL UNIQUE,\r
- date INT NOT NULL DEFAULT 0,\r
- title VARCHAR(255) NOT NULL,\r
- description TEXT NOT NULL,\r
- access_level INT NOT NULL DEFAULT 0,\r
- PRIMARY KEY(id)\r
-);\r
-\r
-\r
-CREATE TABLE $tbl_tags (\r
- id SERIAL,\r
- name VARCHAR(255) NOT NULL UNIQUE,\r
- PRIMARY KEY(id),\r
- UNIQUE(name)\r
-);\r
-\r
-CREATE TABLE $tbl_bookmark_tags (\r
- bookmark_id SERIAL,\r
- tag_id INT NOT NULL,\r
- PRIMARY KEY(bookmark_id, tag_id)\r
-);\r
-\r
-CREATE TABLE $tbl_options (\r
- name VARCHAR(255) NOT NULL UNIQUE,\r
- description TEXT NOT NULL,\r
- value TEXT NOT NULL,\r
- PRIMARY KEY(name)\r
-);\r
-\r
-CREATE TABLE $tbl_pagecache (\r
- md5 CHAR(32) NOT NULL DEFAULT '',\r
- url TEXT NOT NULL DEFAULT '',\r
- content_type VARCHAR(50),\r
- content_length INT NOT NULL DEFAULT 0,\r
- content bytea,\r
- date INT NOT NULL DEFAULT 0,\r
- PRIMARY KEY(md5)\r
-);\r
-\r
-CREATE TABLE $tbl_pagecache_references (\r
- md5_parent CHAR(32) NOT NULL DEFAULT '',\r
- md5_child CHAR(32) NOT NULL DEFAULT '',\r
- PRIMARY KEY(md5_parent, md5_child)\r
-);\r
-\r
-INSERT INTO $tbl_options VALUES (\r
- 'feed_name',\r
- 'The title of your feed (e.g. My Bookmarks)',\r
- 'Bookmarks'\r
-);\r
-\r
-INSERT INTO $tbl_options VALUES (\r
- 'site_name',\r
- 'The title of the main page (e.g. My Bookmarks)',\r
- 'My Bookmarks'\r
-);\r
-\r
-\r
-INSERT INTO $tbl_options VALUES (\r
- 'public_searches',\r
- 'Allow public searches - when set to yes, any visitor can search your bookmarks.',\r
- 'no'\r
-);\r
-\r
-INSERT INTO $tbl_options VALUES(\r
- 'version',\r
- 'Internal Insipid version number',\r
- '$version'\r
-);\r
-\r
-INSERT INTO $tbl_options VALUES(\r
- 'proxy_host',\r
- 'The proxy server (if any) to use when making page snapshots.',\r
- ''\r
-);\r
-\r
-INSERT INTO $tbl_options VALUES(\r
- 'proxy_port',\r
- 'Your proxy port number.',\r
- '3128'\r
-);\r
-\r
-INSERT INTO $tbl_options VALUES(\r
- 'use_rewrite',\r
- 'Use mod_rewrite - disable this if you do not want .htaccess-controlled URLs, or if your Apache does not have the rewrite module installed.',\r
- 'no'\r
-);\r
-\r
-CPOSTGRES\r
-\r
-\r
-our $createMySQL = <<CMYSQL;\r
-CREATE TABLE IF NOT EXISTS $tbl_authentication (\r
- session_id CHAR(32) NOT NULL UNIQUE,\r
- create_time INT,\r
- PRIMARY KEY(session_id)\r
-);\r
-\r
-CREATE TABLE IF NOT EXISTS $tbl_bookmarks (\r
- id INT AUTO_INCREMENT NOT NULL,\r
- url TEXT NOT NULL DEFAULT '',\r
- md5 CHAR(32) NOT NULL DEFAULT '' UNIQUE,\r
- date INT NOT NULL DEFAULT 0,\r
- title VARCHAR(255) NOT NULL DEFAULT '',\r
- description TEXT NOT NULL DEFAULT '',\r
- access_level INT NOT NULL DEFAULT 0,\r
- PRIMARY KEY(id)\r
-);\r
-\r
-\r
-CREATE TABLE IF NOT EXISTS $tbl_tags (\r
- id INT AUTO_INCREMENT NOT NULL,\r
- name VARCHAR(255) NOT NULL DEFAULT '' UNIQUE,\r
- PRIMARY KEY(id)\r
-);\r
-\r
-CREATE TABLE IF NOT EXISTS $tbl_bookmark_tags (\r
- bookmark_id INT NOT NULL,\r
- tag_id INT NOT NULL,\r
- PRIMARY KEY(bookmark_id, tag_id),\r
- INDEX(bookmark_id),\r
- INDEX(tag_id)\r
-);\r
-\r
-\r
-CREATE TABLE IF NOT EXISTS $tbl_options (\r
- name VARCHAR(255) NOT NULL UNIQUE,\r
- description TEXT NOT NULL DEFAULT '',\r
- value TEXT NOT NULL DEFAULT '',\r
- PRIMARY KEY(name)\r
-);\r
-\r
-CREATE TABLE IF NOT EXISTS $tbl_pagecache (\r
- md5 CHAR(32) NOT NULL DEFAULT '',\r
- url TEXT NOT NULL DEFAULT '',\r
- content_type VARCHAR(50),\r
- content_length INT NOT NULL DEFAULT 0,\r
- content LONGBLOB,\r
- date INT NOT NULL DEFAULT 0,\r
- PRIMARY KEY(md5)\r
-);\r
-\r
-CREATE TABLE IF NOT EXISTS $tbl_pagecache_references (\r
- md5_parent CHAR(32) NOT NULL DEFAULT '',\r
- md5_child CHAR(32) NOT NULL DEFAULT '',\r
- PRIMARY KEY(md5_parent, md5_child)\r
-);\r
-\r
-INSERT IGNORE INTO $tbl_options VALUES(\r
- 'feed_name',\r
- 'The title of your feed (e.g. My Bookmarks)',\r
- 'Bookmarks'\r
-);\r
-\r
-INSERT IGNORE INTO $tbl_options VALUES(\r
- 'site_name',\r
- 'The title of the main page (e.g. My Bookmarks)',\r
- 'My Bookmarks'\r
-);\r
-\r
-INSERT IGNORE INTO $tbl_options VALUES(\r
- 'public_searches',\r
- 'Allow public searches - when set to yes, any visitor can search your bookmarks.',\r
- 'no'\r
-);\r
-\r
-INSERT IGNORE INTO $tbl_options VALUES(\r
- 'proxy_host',\r
- 'The proxy server (if any) to use when making page snapshots.',\r
- ''\r
-);\r
-\r
-\r
-INSERT IGNORE INTO $tbl_options VALUES(\r
- 'proxy_port',\r
- 'Your proxy port number.',\r
- '3128'\r
-);\r
-\r
-INSERT IGNORE INTO $tbl_options VALUES(\r
- 'version',\r
- 'Internal Insipid version number',\r
- '$version'\r
-);\r
-\r
-INSERT IGNORE INTO $tbl_options VALUES(\r
- 'use_rewrite',\r
- 'Use mod_rewrite - disable this if you do not want .htaccess-controlled URLs, or if your Apache does not have the rewrite module installed.',\r
- 'no'\r
-);\r
-CMYSQL\r
-\r
-1;\r
-__END__\r
+#!/usr/bin/perl
+#
+# Copyright (C) 2008 Luke Reeves
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+# USA
+#
+
+package Insipid::Schemas;
+
+use strict;
+use warnings;
+use Insipid::Config;
+
+use vars qw(
+@ISA
+@EXPORT
+$createMySQL
+);
+
+use Exporter;
+
+@ISA = qw(Exporter);
+
+@EXPORT = qw(
+$version
+$createMySQL
+);
+
+# Insipid will check the database version number on each initialization of
+# the options table (every hit essentially) and upgrade the tables if there's
+# any mismatch.
+our $version = "1.0";
+
+our $createMySQL = <<CMYSQL;
+CREATE TABLE IF NOT EXISTS $tbl_authentication (
+ session_id CHAR(32) NOT NULL UNIQUE,
+ create_time INT,
+ PRIMARY KEY(session_id)
+);
+
+CREATE TABLE IF NOT EXISTS $tbl_bookmarks (
+ id INT AUTO_INCREMENT NOT NULL,
+ url TEXT NOT NULL DEFAULT '',
+ md5 CHAR(32) NOT NULL DEFAULT '' UNIQUE,
+ date INT NOT NULL DEFAULT 0,
+ title VARCHAR(255) NOT NULL DEFAULT '',
+ description TEXT NOT NULL DEFAULT '',
+ access_level INT NOT NULL DEFAULT 0,
+ PRIMARY KEY(id)
+);
+
+
+CREATE TABLE IF NOT EXISTS $tbl_tags (
+ id INT AUTO_INCREMENT NOT NULL,
+ name VARCHAR(255) NOT NULL DEFAULT '' UNIQUE,
+ PRIMARY KEY(id)
+);
+
+CREATE TABLE IF NOT EXISTS $tbl_bookmark_tags (
+ bookmark_id INT NOT NULL,
+ tag_id INT NOT NULL,
+ PRIMARY KEY(bookmark_id, tag_id),
+ INDEX(bookmark_id),
+ INDEX(tag_id)
+);
+
+
+CREATE TABLE IF NOT EXISTS $tbl_options (
+ name VARCHAR(255) NOT NULL UNIQUE,
+ description TEXT NOT NULL DEFAULT '',
+ value TEXT NOT NULL DEFAULT '',
+ PRIMARY KEY(name)
+);
+
+CREATE TABLE IF NOT EXISTS $tbl_pagecache (
+ md5 CHAR(32) NOT NULL DEFAULT '',
+ url TEXT NOT NULL DEFAULT '',
+ content_type VARCHAR(50),
+ content_length INT NOT NULL DEFAULT 0,
+ content LONGBLOB,
+ date INT NOT NULL DEFAULT 0,
+ PRIMARY KEY(md5)
+);
+
+CREATE TABLE IF NOT EXISTS $tbl_pagecache_references (
+ md5_parent CHAR(32) NOT NULL DEFAULT '',
+ md5_child CHAR(32) NOT NULL DEFAULT '',
+ PRIMARY KEY(md5_parent, md5_child)
+);
+
+INSERT IGNORE INTO $tbl_options VALUES(
+ 'feed_name',
+ 'The title of your feed (e.g. My Bookmarks)',
+ 'Bookmarks'
+);
+
+INSERT IGNORE INTO $tbl_options VALUES(
+ 'site_name',
+ 'The title of the main page (e.g. My Bookmarks)',
+ 'My Bookmarks'
+);
+
+INSERT IGNORE INTO $tbl_options VALUES(
+ 'public_searches',
+ 'Allow public searches - when set to yes, any visitor can search your bookmarks.',
+ 'no'
+);
+
+INSERT IGNORE INTO $tbl_options VALUES(
+ 'proxy_host',
+ 'The proxy server (if any) to use when making page snapshots.',
+ ''
+);
+
+
+INSERT IGNORE INTO $tbl_options VALUES(
+ 'proxy_port',
+ 'Your proxy port number.',
+ '3128'
+);
+
+INSERT IGNORE INTO $tbl_options VALUES(
+ 'version',
+ 'Internal Insipid version number',
+ '$version'
+);
+
+INSERT IGNORE INTO $tbl_options VALUES(
+ 'use_rewrite',
+ 'Use mod_rewrite - disable this if you do not want .htaccess-controlled URLs, or if your Apache does not have the rewrite module installed.',
+ 'no'
+);
+CMYSQL
+
+1;
+__END__
-#!/usr/bin/perl\r
-#\r
-# Copyright (C) 2008 Luke Reeves\r
-#\r
-# This program is free software; you can redistribute it and/or modify\r
-# it under the terms of the GNU General Public License as published by\r
-# the Free Software Foundation; either version 2 of the License, or\r
-# (at your option) any later version.\r
-#\r
-# This program is distributed in the hope that it will be useful,\r
-# but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-# GNU General Public License for more details.\r
-#\r
-# You should have received a copy of the GNU General Public License\r
-# along with this program; if not, write to the Free Software\r
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307\r
-# USA\r
-#\r
-\r
-package Insipid::Snapshots;\r
-\r
-use strict;\r
-use warnings;\r
-\r
-use vars qw(@ISA @EXPORT);\r
-use Insipid::Config;\r
-use Insipid::Database;\r
-use Insipid::Util;\r
-use Insipid::LinkExtractor;\r
-use Insipid::Parser;\r
-use CGI qw/:standard/;\r
-use CGI::Carp qw(fatalsToBrowser);\r
-use Date::Format;\r
-use Date::Parse;\r
-use Date::Parse;\r
-use Digest::MD5 qw(md5 md5_hex);\r
-use DBI qw/:sql_types/;;\r
-use LWP::UserAgent;\r
-use HTTP::Request;\r
-use MIME::Base64;\r
-use XML::Writer;\r
-\r
-require Exporter;\r
-\r
-\r
-@ISA = qw(Exporter);\r
-\r
-@EXPORT = qw(\r
-show_snapshots\r
-do_snapshot\r
-delete_snapshot\r
-export_snapshots\r
-show_snapshot\r
-fetch_related\r
-parsepage\r
-fetch_url\r
-);\r
-\r
-my $ua = LWP::UserAgent->new(timeout=>30);\r
-if(get_option('proxy_host') ne '') {\r
- my $proxy_host = get_option('proxy_host');\r
- my $proxy_port = get_option('proxy_port');\r
- $ua->proxy(['http', 'ftp'], "http://$proxy_host:$proxy_port/");\r
-}\r
- \r
-\r
-my $referer = "";\r
-\r
-sub export_snapshots {\r
- my ($writer) = (@_);\r
- my ($sql, $sth, @rs);\r
-\r
- # Export the objects\r
- $writer->startTag('objects');\r
- $sql = "select md5, url, content_type, content_length, date, content\r
- from $tbl_pagecache";\r
- $sth = $dbh->prepare($sql);\r
- $sth->execute();\r
- \r
- while(@rs = $sth->fetchrow_array()) {\r
- $writer->startTag('object',\r
- 'md5' => $rs[0],\r
- 'url' => $rs[1],\r
- 'type' => $rs[2],\r
- 'length' => $rs[3],\r
- 'date' => $rs[4]\r
- );\r
- $writer->characters(encode_base64($rs[5]));\r
- $writer->endTag("object");\r
- }\r
- $writer->endTag('objects'); \r
-\r
- # Export the relationships \r
- $writer->startTag('relationships');\r
-\r
- $sql = "select md5_parent, md5_child from $tbl_pagecache_references";\r
- $sth = $dbh->prepare($sql);\r
- $sth->execute();\r
-\r
- while(@rs = $sth->fetchrow_array()) {\r
- $writer->startTag("relationship",\r
- "parent" => $rs[0],\r
- "child" => $rs[1]);\r
- $writer->endTag("relationship");\r
- }\r
- \r
- $writer->endTag("relationships");\r
-\r
-}\r
-\r
-# TODO: Make the insert_snapshot callable by this and the import method.\r
-sub fetch_url {\r
- my ($url, $roverride) = (@_);\r
-\r
- # TODO: No.\r
- if(defined($roverride)) { $referer = $roverride; }\r
- my $md5 = md5_hex($url);\r
-\r
- my $req = HTTP::Request->new(GET => $url) or die "Can't fetch page: $!\n";\r
-\r
- if($referer ne '') { $req->header( referer => $referer ); }\r
-\r
- my $res = $ua->request($req);\r
-\r
- if($res->is_success) {\r
- my $content = $res->content;\r
-\r
- # Shove the unparsed page into the cache.\r
- my $sql = "insert into $tbl_pagecache(md5, url, content_type, \r
- content_length, content, date)\r
- values ( ? , ? , ? , ? , ? , ? )";\r
-\r
- my $sth = $dbh->prepare($sql);\r
- my $ct = $res->header('Content-Type');\r
- if(length($ct) > 50) { $ct = substr($ct, 0, 50); }\r
-\r
- $sth->bind_param(1, $md5);\r
- $sth->bind_param(2, $url);\r
- $sth->bind_param(3, $ct);\r
- $sth->bind_param(4, length($content));\r
-\r
- # Postgres needs escaping for the binary data.\r
- if($dbtype eq 'Pg') {\r
- $sth->bind_param(5, $content, SQL_VARBINARY);\r
- } else {\r
- $sth->bind_param(5, $content);\r
- }\r
- $sth->bind_param(6, time());\r
- $sth->execute;\r
-\r
- if($sth->err) {\r
- # print $sth->errstr;\r
- # print "<br />";\r
- return 1; \r
- } else {\r
- if($ct =~ /text\/html/i) {\r
- print '<br />Parsing page... ';\r
- parsepage($url, $content, $ct);\r
- print 'done.';\r
- }\r
-\r
- return 0;\r
- }\r
- } else {\r
- my $err = $res->status_line;\r
- print "$err<br />";\r
-\r
- return 1;\r
- }\r
-}\r
-\r
-sub show_snapshot {\r
- my ($md5) = (@_);\r
- my ($sql, $sth, @row);\r
- my %internalLinks = ();\r
-\r
- $sql = "select content_type,content,url,date,content_length\r
- from $tbl_pagecache where (md5 = ?)";\r
- \r
- $sth = $dbh->prepare($sql);\r
- $sth->execute($md5);\r
- \r
- @row = $sth->fetchrow_array;\r
- \r
- if(!@row) {\r
- print 'Content-Type: text/plain\r\n\r\n';\r
- print "Can't find cached item \"$md5\"";\r
- return;\r
- }\r
-\r
-\r
- # Check for IMS request.\r
- my $ims = http('If-Modified-Since');\r
- if($ims) { \r
-\r
- my $t = str2time($ims);\r
-\r
- if($row[3] <= $t) {\r
- # Return a 304 not modified.\r
- print 'Status: 304 Not Modified\r\n';\r
- return;\r
- }\r
- }\r
- \r
- my $dt = ims_time($row[3]);\r
- print "Last-Modified: $dt\r\n";\r
- print "Content-Type: $row[0]\r\n";\r
-\r
- if($row[0] =~ /text\/html/i) {\r
- # Now we get a list of URLs that can be redirected to our \r
- # local snapshot cache. We'll use that to build a hash of \r
- # URL->MD5 values and match outputted links against that.\r
- my ($resql, $resth, @rerow);\r
- $resql = "select $tbl_pagecache_references.md5_child,\r
- $tbl_pagecache.url\r
- from $tbl_pagecache_references\r
- inner join $tbl_pagecache on \r
- ($tbl_pagecache_references.md5_child = \r
- $tbl_pagecache.md5)\r
- where (md5_parent = ?)";\r
- $resth = $dbh->prepare($resql);\r
- $resth->execute($md5);\r
-\r
- while(@rerow = $resth->fetchrow_array()) {\r
- $internalLinks{$rerow[1]} = $rerow[0];\r
- }\r
-\r
- print "\r\n";\r
- my $p = Insipid::Parser->new($row[2], undef);\r
- $p->setSnapshotMap(\%internalLinks);\r
- \r
- if($row[0] =~ /utf/i) {\r
- $p->utf8_mode(1);\r
- }\r
- $p->parse($row[1]);\r
- } else {\r
- print "Content-Length: $row[4]\r\n";\r
- print "\r\n";\r
- print $row[1];\r
- }\r
-\r
- exit;\r
-}\r
-\r
-sub show_details {\r
- my ($md5) = @_;\r
- my ($sth, $sql);\r
- \r
- $sql = "select $tbl_bookmarks.title from $tbl_bookmarks\r
- where ($tbl_bookmarks.md5 = ?)";\r
- $sth = $dbh->prepare($sql);\r
- $sth->execute($md5);\r
- my @row = $sth->fetchrow_array();\r
-\r
- print '<h3>Cache Details for "';\r
- print escapeHTML($row[0]);\r
- print '"</h3>';\r
- print '<br /><center><table cellpadding="5"><tr><th>View</th><th>URL</th><th>';\r
- print 'Type</th><th>Size</th><th>Ref Count</th></tr>';\r
-\r
- $sql = "select $tbl_pagecache.md5, $tbl_pagecache.url, \r
- $tbl_pagecache.content_type,\r
- $tbl_pagecache.content_length, \r
- pg2.md5_parent, count(*)\r
- from $tbl_pagecache_references\r
- inner join $tbl_pagecache on \r
- ($tbl_pagecache_references.md5_child = \r
- $tbl_pagecache.md5)\r
- left join $tbl_pagecache_references as pg2 on \r
- (pg2.md5_child = $tbl_pagecache.md5)\r
- where ($tbl_pagecache_references.md5_parent = ?)\r
- group by $tbl_pagecache.md5, $tbl_pagecache.url, \r
- $tbl_pagecache.content_type, pg2.md5_parent, \r
- $tbl_pagecache.content_length, pg2.md5_child\r
- order by $tbl_pagecache.url";\r
- \r
- $sth = $dbh->prepare($sql);\r
- $sth->execute($md5);\r
-\r
- while(my @rs = $sth->fetchrow_array()) {\r
- print '<tr><td>';\r
- my $ss = "$snapshot_url$rs[0]";\r
- \r
- print "<a href=\"$rs[1]\">live</a>/<a href=\"$ss\">snapshot</a>";\r
- print '</td><td>';\r
- print $rs[1];\r
- print '</td><td>';\r
- print $rs[2];\r
- print '</td><td>';\r
- print $rs[3];\r
- print '</td><td>';\r
- print $rs[5];\r
- print '</td></tr>';\r
- }\r
-\r
- print '</table></center>';\r
-}\r
-\r
-#\r
-# Show a nice menu of the users snapshots.\r
-#\r
-sub show_snapshots {\r
-\r
- # If a snapshot was asked to be deleted\r
- if(defined(param('delete'))) {\r
- delete_snapshot(param('delete'));\r
- }\r
-\r
- if(defined(param('md5'))) {\r
- show_details(param('md5'));\r
- return;\r
- }\r
-\r
- my $tcount = 0;\r
- my $tsize = 0;\r
- \r
- my $sql = "select $tbl_pagecache.md5, $tbl_bookmarks.title, \r
- $tbl_pagecache.date,\r
- $tbl_pagecache.content_length + \r
- coalesce(sum(p2.content_length), 0), \r
- count(*) - 1, $tbl_bookmarks.access_level\r
- from $tbl_pagecache \r
- inner join $tbl_bookmarks on \r
- ($tbl_bookmarks.md5 = $tbl_pagecache.md5)\r
- left join $tbl_pagecache_references on \r
- ($tbl_pagecache.md5 = $tbl_pagecache_references.md5_parent) \r
- left join $tbl_pagecache as p2 on\r
- (p2.md5 = $tbl_pagecache_references.md5_child)\r
- group by \r
- $tbl_bookmarks.access_level,\r
- $tbl_pagecache.md5, $tbl_bookmarks.title,\r
- $tbl_pagecache.date, $tbl_pagecache.content_length\r
- order by $tbl_pagecache.date desc";\r
- my $sth = $dbh->prepare($sql);\r
- $sth->execute;\r
- \r
- print '<br /><center><table cellpadding=\"5\"><tr><th>Page</th><th>';\r
- print 'Date</th><th>Size</th><th>Objects</th><th>Functions</th></tr>';\r
-\r
- my $count = 0;\r
-\r
- while(my @r = $sth->fetchrow_array) {\r
-\r
- $count++;\r
- \r
- my $color;\r
- if(($count % 2) eq 1) {\r
- $color = ' bgcolor="#EEEEEE" ';\r
- } else {\r
- $color = '';\r
- }\r
- \r
- print "<tr $color>";\r
- print '<td>';\r
- \r
- print "<a href=\"$snapshot_url$r[0]\">";\r
- if($r[5] eq 0) { print '<i>'; }\r
- print $r[1];\r
- if($r[5] eq 0) { print '</i>'; }\r
- print '</a></td>';\r
- my $timestr = time2str('%Y-%m-%d', $r[2], 'EST');\r
- my $count = $r[4] + 1; $tcount += $count;\r
- $tsize += $r[3];\r
- print "<td align=\"center\">$timestr</td>";\r
- print "<td align=\"center\">$r[3]</td>";\r
-\r
- my $link = "$site_url/insipid.cgi?op=snapshots&md5=$r[0]";\r
-\r
- if($count ne 1) {\r
- print "<td align=\"center\"><a href=\"$link\">$count</a></td>";\r
- } else {\r
- print "<td align=\"center\">$count</td>";\r
- }\r
- \r
- print '<td>';\r
- print "<a href=\"insipid.cgi?op=snapshots&delete=$r[0]\">delete</a>,";\r
- print " <a href=\"insipid.cgi?op=fetchrelated&id=$r[0]\">";\r
- print "fetch linked objects</a></td>";\r
- print '</tr>';\r
- }\r
-\r
- print '<tr><td><b>Total</b></td><td> </td>';\r
- print "<td align=\"center\"><b>$tsize</b></td>";\r
- print "<td align=\"center\"><b>$tcount</b></td><td> </td></tr>";\r
- \r
- print "</table></center>";\r
-}\r
-\r
-# This fetches all linked-to objects (specifically images for now)\r
-# for a cached page.\r
-sub fetch_related {\r
- my ($md5) = (@_);\r
-\r
- my $sql = "select content, url\r
- from $tbl_pagecache where (md5 = ?)";\r
- my $sth = $dbh->prepare($sql);\r
- $sth->execute($md5);\r
-\r
- my @r = $sth->fetchrow_array();\r
-\r
- my $p = Insipid::LinkExtractor->new($r[1]);\r
- $p->parse($r[0]);\r
-\r
-}\r
-\r
-# Deletes a snapshot and all orphan cache children, taking into\r
-# account the fact that items can be shared across cached pages.\r
-#\r
-# This is horribly expensive, and someday I'll replace it with\r
-# a much nicer function.\r
-sub delete_snapshot {\r
- my ($md5) = (@_);\r
- \r
- # The snapshot\r
- my $sql = "delete from $tbl_pagecache where (md5 = ?)";\r
- my $delstatement = $dbh->prepare($sql);\r
- $delstatement->execute($md5);\r
-\r
- # References\r
- $sql = "delete from $tbl_pagecache_references where (md5_parent = ?)";\r
- my $sth = $dbh->prepare($sql);\r
- $sth->execute($md5);\r
- \r
- # Orpans - blow away any md5s in the pagecache table that aren't \r
- # referenced as a child in the references table. First, get a list\r
- # of valid MD5s.\r
- $sql = "select distinct md5_child from $tbl_pagecache_references";\r
- $sth = $dbh->prepare($sql);\r
- $sth->execute();\r
-\r
- my $subquery = '';\r
- while(my @r = $sth->fetchrow_array) {\r
- if($subquery ne '') { $subquery = $subquery . ','; }\r
- $subquery = "$subquery '$r[0]'";\r
- }\r
- \r
- $sql = "select distinct md5_parent from $tbl_pagecache_references";\r
- $sth = $dbh->prepare($sql);\r
- $sth->execute();\r
- while(my @r = $sth->fetchrow_array) {\r
- if($subquery ne '') { $subquery = $subquery . ','; }\r
- $subquery = "$subquery '$r[0]'";\r
- }\r
-\r
- if($subquery eq '') {\r
- $sql = "delete from $tbl_pagecache;";\r
- } else {\r
- $sql = "delete from $tbl_pagecache where md5 not in ($subquery)";\r
- }\r
- \r
- $sth = $dbh->prepare($sql);\r
- $sth->execute();\r
-}\r
-\r
-sub do_snapshot {\r
- # Save the page.\r
- print '<br /><br />';\r
- \r
- my ($bookmark_id) = (@_);\r
- my $sql = "select url,md5,title from $tbl_bookmarks where (id = ?)";\r
- my $sth = $dbh->prepare($sql);\r
- $sth->execute($bookmark_id);\r
- my @row = $sth->fetchrow_array;\r
-\r
- if(@row) {\r
- print "<p>Fetching \"<b>$row[2]</b>\"...</p>\n";\r
- $referer = $row[0];\r
- fetch_url(@row); \r
- } else {\r
- die "Couldn't find the row for id $bookmark_id!";\r
- }\r
-}\r
-\r
-sub parsepage {\r
- my ($url, $content, $content_type) = (@_);\r
-\r
- my $p = Insipid::Parser->new($url, \&fetch_url);\r
- if($content_type =~ /utf/i) { \r
- $p->utf8_mode(1);\r
- }\r
-\r
- $p->parse($content);\r
-}\r
-\r
-1;\r
-__END__\r
+#!/usr/bin/perl
+#
+# Copyright (C) 2008 Luke Reeves
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+# USA
+#
+
+package Insipid::Snapshots;
+
+use strict;
+use warnings;
+
+use vars qw(@ISA @EXPORT);
+use Insipid::Config;
+use Insipid::Database;
+use Insipid::Util;
+use Insipid::LinkExtractor;
+use Insipid::Parser;
+use CGI qw/:standard/;
+use CGI::Carp qw(fatalsToBrowser);
+use Date::Format;
+use Date::Parse;
+use Date::Parse;
+use Digest::MD5 qw(md5 md5_hex);
+use DBI qw/:sql_types/;;
+use LWP::UserAgent;
+use HTTP::Request;
+use MIME::Base64;
+use XML::Writer;
+
+require Exporter;
+
+
+@ISA = qw(Exporter);
+
+@EXPORT = qw(
+show_snapshots
+do_snapshot
+delete_snapshot
+export_snapshots
+show_snapshot
+fetch_related
+parsepage
+fetch_url
+);
+
+my $ua = LWP::UserAgent->new(timeout=>30);
+if(get_option('proxy_host') ne '') {
+ my $proxy_host = get_option('proxy_host');
+ my $proxy_port = get_option('proxy_port');
+ $ua->proxy(['http', 'ftp'], "http://$proxy_host:$proxy_port/");
+}
+
+
+my $referer = "";
+
+sub export_snapshots {
+ my ($writer) = (@_);
+ my ($sql, $sth, @rs);
+
+ # Export the objects
+ $writer->startTag('objects');
+ $sql = "select md5, url, content_type, content_length, date, content
+ from $tbl_pagecache";
+ $sth = $dbh->prepare($sql);
+ $sth->execute();
+
+ while(@rs = $sth->fetchrow_array()) {
+ $writer->startTag('object',
+ 'md5' => $rs[0],
+ 'url' => $rs[1],
+ 'type' => $rs[2],
+ 'length' => $rs[3],
+ 'date' => $rs[4]
+ );
+ $writer->characters(encode_base64($rs[5]));
+ $writer->endTag("object");
+ }
+ $writer->endTag('objects');
+
+ # Export the relationships
+ $writer->startTag('relationships');
+
+ $sql = "select md5_parent, md5_child from $tbl_pagecache_references";
+ $sth = $dbh->prepare($sql);
+ $sth->execute();
+
+ while(@rs = $sth->fetchrow_array()) {
+ $writer->startTag("relationship",
+ "parent" => $rs[0],
+ "child" => $rs[1]);
+ $writer->endTag("relationship");
+ }
+
+ $writer->endTag("relationships");
+
+}
+
+# TODO: Make the insert_snapshot callable by this and the import method.
+sub fetch_url {
+ my ($url, $roverride) = (@_);
+
+ # TODO: No.
+ if(defined($roverride)) { $referer = $roverride; }
+ my $md5 = md5_hex($url);
+
+ my $req = HTTP::Request->new(GET => $url) or die "Can't fetch page: $!\n";
+
+ if($referer ne '') { $req->header( referer => $referer ); }
+
+ my $res = $ua->request($req);
+
+ if($res->is_success) {
+ my $content = $res->content;
+
+ # Shove the unparsed page into the cache.
+ my $sql = "insert into $tbl_pagecache(md5, url, content_type,
+ content_length, content, date)
+ values ( ? , ? , ? , ? , ? , ? )";
+
+ my $sth = $dbh->prepare($sql);
+ my $ct = $res->header('Content-Type');
+ if(length($ct) > 50) { $ct = substr($ct, 0, 50); }
+
+ $sth->bind_param(1, $md5);
+ $sth->bind_param(2, $url);
+ $sth->bind_param(3, $ct);
+ $sth->bind_param(4, length($content));
+
+ $sth->bind_param(5, $content);
+
+ $sth->bind_param(6, time());
+ $sth->execute;
+
+ if($sth->err) {
+ # print $sth->errstr;
+ # print "<br />";
+ return 1;
+ } else {
+ if($ct =~ /text\/html/i) {
+ print '<br />Parsing page... ';
+ parsepage($url, $content, $ct);
+ print 'done.';
+ }
+
+ return 0;
+ }
+ } else {
+ my $err = $res->status_line;
+ print "$err<br />";
+
+ return 1;
+ }
+}
+
+sub show_snapshot {
+ my ($md5) = (@_);
+ my ($sql, $sth, @row);
+ my %internalLinks = ();
+
+ $sql = "select content_type,content,url,date,content_length
+ from $tbl_pagecache where (md5 = ?)";
+
+ $sth = $dbh->prepare($sql);
+ $sth->execute($md5);
+
+ @row = $sth->fetchrow_array;
+
+ if(!@row) {
+ print 'Content-Type: text/plain\r\n\r\n';
+ print "Can't find cached item \"$md5\"";
+ return;
+ }
+
+
+ # Check for IMS request.
+ my $ims = http('If-Modified-Since');
+ if($ims) {
+
+ my $t = str2time($ims);
+
+ if($row[3] <= $t) {
+ # Return a 304 not modified.
+ print 'Status: 304 Not Modified\r\n';
+ return;
+ }
+ }
+
+ my $dt = ims_time($row[3]);
+ print "Last-Modified: $dt\r\n";
+ print "Content-Type: $row[0]\r\n";
+
+ if($row[0] =~ /text\/html/i) {
+ # Now we get a list of URLs that can be redirected to our
+ # local snapshot cache. We'll use that to build a hash of
+ # URL->MD5 values and match outputted links against that.
+ my ($resql, $resth, @rerow);
+ $resql = "select $tbl_pagecache_references.md5_child,
+ $tbl_pagecache.url
+ from $tbl_pagecache_references
+ inner join $tbl_pagecache on
+ ($tbl_pagecache_references.md5_child =
+ $tbl_pagecache.md5)
+ where (md5_parent = ?)";
+ $resth = $dbh->prepare($resql);
+ $resth->execute($md5);
+
+ while(@rerow = $resth->fetchrow_array()) {
+ $internalLinks{$rerow[1]} = $rerow[0];
+ }
+
+ print "\r\n";
+ my $p = Insipid::Parser->new($row[2], undef);
+ $p->setSnapshotMap(\%internalLinks);
+
+ if($row[0] =~ /utf/i) {
+ $p->utf8_mode(1);
+ }
+ $p->parse($row[1]);
+ } else {
+ print "Content-Length: $row[4]\r\n";
+ print "\r\n";
+ print $row[1];
+ }
+
+ exit;
+}
+
+sub show_details {
+ my ($md5) = @_;
+ my ($sth, $sql);
+
+ $sql = "select $tbl_bookmarks.title from $tbl_bookmarks
+ where ($tbl_bookmarks.md5 = ?)";
+ $sth = $dbh->prepare($sql);
+ $sth->execute($md5);
+ my @row = $sth->fetchrow_array();
+
+ print '<h3>Cache Details for "';
+ print escapeHTML($row[0]);
+ print '"</h3>';
+ print '<br /><center><table cellpadding="5"><tr><th>View</th><th>URL</th><th>';
+ print 'Type</th><th>Size</th><th>Ref Count</th></tr>';
+
+ $sql = "select $tbl_pagecache.md5, $tbl_pagecache.url,
+ $tbl_pagecache.content_type,
+ $tbl_pagecache.content_length,
+ pg2.md5_parent, count(*)
+ from $tbl_pagecache_references
+ inner join $tbl_pagecache on
+ ($tbl_pagecache_references.md5_child =
+ $tbl_pagecache.md5)
+ left join $tbl_pagecache_references as pg2 on
+ (pg2.md5_child = $tbl_pagecache.md5)
+ where ($tbl_pagecache_references.md5_parent = ?)
+ group by $tbl_pagecache.md5, $tbl_pagecache.url,
+ $tbl_pagecache.content_type, pg2.md5_parent,
+ $tbl_pagecache.content_length, pg2.md5_child
+ order by $tbl_pagecache.url";
+
+ $sth = $dbh->prepare($sql);
+ $sth->execute($md5);
+
+ while(my @rs = $sth->fetchrow_array()) {
+ print '<tr><td>';
+ my $ss = "$snapshot_url$rs[0]";
+
+ print "<a href=\"$rs[1]\">live</a>/<a href=\"$ss\">snapshot</a>";
+ print '</td><td>';
+ print $rs[1];
+ print '</td><td>';
+ print $rs[2];
+ print '</td><td>';
+ print $rs[3];
+ print '</td><td>';
+ print $rs[5];
+ print '</td></tr>';
+ }
+
+ print '</table></center>';
+}
+
+#
+# Show a nice menu of the users snapshots.
+#
+sub show_snapshots {
+
+ # If a snapshot was asked to be deleted
+ if(defined(param('delete'))) {
+ delete_snapshot(param('delete'));
+ }
+
+ if(defined(param('md5'))) {
+ show_details(param('md5'));
+ return;
+ }
+
+ my $tcount = 0;
+ my $tsize = 0;
+
+ my $sql = "select $tbl_pagecache.md5, $tbl_bookmarks.title,
+ $tbl_pagecache.date,
+ $tbl_pagecache.content_length +
+ coalesce(sum(p2.content_length), 0),
+ count(*) - 1, $tbl_bookmarks.access_level
+ from $tbl_pagecache
+ inner join $tbl_bookmarks on
+ ($tbl_bookmarks.md5 = $tbl_pagecache.md5)
+ left join $tbl_pagecache_references on
+ ($tbl_pagecache.md5 = $tbl_pagecache_references.md5_parent)
+ left join $tbl_pagecache as p2 on
+ (p2.md5 = $tbl_pagecache_references.md5_child)
+ group by
+ $tbl_bookmarks.access_level,
+ $tbl_pagecache.md5, $tbl_bookmarks.title,
+ $tbl_pagecache.date, $tbl_pagecache.content_length
+ order by $tbl_pagecache.date desc";
+ my $sth = $dbh->prepare($sql);
+ $sth->execute;
+
+ print '<br /><center><table cellpadding=\"5\"><tr><th>Page</th><th>';
+ print 'Date</th><th>Size</th><th>Objects</th><th>Functions</th></tr>';
+
+ my $count = 0;
+
+ while(my @r = $sth->fetchrow_array) {
+
+ $count++;
+
+ my $color;
+ if(($count % 2) eq 1) {
+ $color = ' bgcolor="#EEEEEE" ';
+ } else {
+ $color = '';
+ }
+
+ print "<tr $color>";
+ print '<td>';
+
+ print "<a href=\"$snapshot_url$r[0]\">";
+ if($r[5] eq 0) { print '<i>'; }
+ print $r[1];
+ if($r[5] eq 0) { print '</i>'; }
+ print '</a></td>';
+ my $timestr = time2str('%Y-%m-%d', $r[2], 'EST');
+ my $count = $r[4] + 1; $tcount += $count;
+ $tsize += $r[3];
+ print "<td align=\"center\">$timestr</td>";
+ print "<td align=\"center\">$r[3]</td>";
+
+ my $link = "$site_url/insipid.cgi?op=snapshots&md5=$r[0]";
+
+ if($count ne 1) {
+ print "<td align=\"center\"><a href=\"$link\">$count</a></td>";
+ } else {
+ print "<td align=\"center\">$count</td>";
+ }
+
+ print '<td>';
+ print "<a href=\"insipid.cgi?op=snapshots&delete=$r[0]\">delete</a>,";
+ print " <a href=\"insipid.cgi?op=fetchrelated&id=$r[0]\">";
+ print "fetch linked objects</a></td>";
+ print '</tr>';
+ }
+
+ print '<tr><td><b>Total</b></td><td> </td>';
+ print "<td align=\"center\"><b>$tsize</b></td>";
+ print "<td align=\"center\"><b>$tcount</b></td><td> </td></tr>";
+
+ print "</table></center>";
+}
+
+# This fetches all linked-to objects (specifically images for now)
+# for a cached page.
+sub fetch_related {
+ my ($md5) = (@_);
+
+ my $sql = "select content, url
+ from $tbl_pagecache where (md5 = ?)";
+ my $sth = $dbh->prepare($sql);
+ $sth->execute($md5);
+
+ my @r = $sth->fetchrow_array();
+
+ my $p = Insipid::LinkExtractor->new($r[1]);
+ $p->parse($r[0]);
+
+}
+
+# Deletes a snapshot and all orphan cache children, taking into
+# account the fact that items can be shared across cached pages.
+#
+# This is horribly expensive, and someday I'll replace it with
+# a much nicer function.
+sub delete_snapshot {
+ my ($md5) = (@_);
+
+ # The snapshot
+ my $sql = "delete from $tbl_pagecache where (md5 = ?)";
+ my $delstatement = $dbh->prepare($sql);
+ $delstatement->execute($md5);
+
+ # References
+ $sql = "delete from $tbl_pagecache_references where (md5_parent = ?)";
+ my $sth = $dbh->prepare($sql);
+ $sth->execute($md5);
+
+ # Orpans - blow away any md5s in the pagecache table that aren't
+ # referenced as a child in the references table. First, get a list
+ # of valid MD5s.
+ $sql = "select distinct md5_child from $tbl_pagecache_references";
+ $sth = $dbh->prepare($sql);
+ $sth->execute();
+
+ my $subquery = '';
+ while(my @r = $sth->fetchrow_array) {
+ if($subquery ne '') { $subquery = $subquery . ','; }
+ $subquery = "$subquery '$r[0]'";
+ }
+
+ $sql = "select distinct md5_parent from $tbl_pagecache_references";
+ $sth = $dbh->prepare($sql);
+ $sth->execute();
+ while(my @r = $sth->fetchrow_array) {
+ if($subquery ne '') { $subquery = $subquery . ','; }
+ $subquery = "$subquery '$r[0]'";
+ }
+
+ if($subquery eq '') {
+ $sql = "delete from $tbl_pagecache;";
+ } else {
+ $sql = "delete from $tbl_pagecache where md5 not in ($subquery)";
+ }
+
+ $sth = $dbh->prepare($sql);
+ $sth->execute();
+}
+
+sub do_snapshot {
+ # Save the page.
+ print '<br /><br />';
+
+ my ($bookmark_id) = (@_);
+ my $sql = "select url,md5,title from $tbl_bookmarks where (id = ?)";
+ my $sth = $dbh->prepare($sql);
+ $sth->execute($bookmark_id);
+ my @row = $sth->fetchrow_array;
+
+ if(@row) {
+ print "<p>Fetching \"<b>$row[2]</b>\"...</p>\n";
+ $referer = $row[0];
+ fetch_url(@row);
+ } else {
+ die "Couldn't find the row for id $bookmark_id!";
+ }
+}
+
+sub parsepage {
+ my ($url, $content, $content_type) = (@_);
+
+ my $p = Insipid::Parser->new($url, \&fetch_url);
+ if($content_type =~ /utf/i) {
+ $p->utf8_mode(1);
+ }
+
+ $p->parse($content);
+}
+
+1;
+__END__
}
my $order_clause;
- if($dbtype eq "Pg") {
- $order_clause = "order by upper($tbl_tags.name)";
- } else {
- $order_clause = "order by $tbl_tags.name";
- }
+ $order_clause = "order by $tbl_tags.name";
$sql = "select $tbl_tags.name, count(*)
from $tbl_bookmarks