init
This commit is contained in:
206
local/bin/checkconfig.pl
Executable file
206
local/bin/checkconfig.pl
Executable file
@@ -0,0 +1,206 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
|
||||
my @errors;
|
||||
my $err = sub {
|
||||
return unless @_;
|
||||
die "Problem:\n" . join('', map { " * $_\n" } @_);
|
||||
};
|
||||
|
||||
my %dochecks; # these are the ones we'll actually do
|
||||
my @checks = ( # put these in the order they should be checked in
|
||||
"modules",
|
||||
"modules_print",
|
||||
"env",
|
||||
"database"
|
||||
);
|
||||
foreach my $check (@checks) { $dochecks{$check} = 1; }
|
||||
|
||||
my $only = 0;
|
||||
|
||||
arg: foreach my $arg (@ARGV) {
|
||||
($w, $c) = ($arg =~ /^-(no|only)(.*)/) or die "unknown option $arg";
|
||||
die "only one '-onlyfoo' option may be specified" if $w eq "only" and $only++;
|
||||
foreach my $check (@checks) {
|
||||
if ($check eq $c) {
|
||||
if ($w eq "only") { %dochecks = ( $check => 1 ); }
|
||||
else { $dochecks{$check} = 0 }
|
||||
next arg;
|
||||
}
|
||||
}
|
||||
die "unknown check '$c' (known checks: " . join(", ", @checks) . ")\n";
|
||||
}
|
||||
|
||||
my %modules = (
|
||||
"DBI" => { 'deb' => 'libdbi-perl', },
|
||||
"DBD::mysql" => { 'deb' => 'libdbd-mysql-perl', },
|
||||
"Digest::MD5" => { 'deb' => 'libdigest-md5-perl', },
|
||||
"Digest::SHA1" => { 'deb' => 'libdigest-sha1-perl', },
|
||||
"Image::Size" => { 'deb' => 'libimage-size-perl', },
|
||||
"MIME::Lite" => { 'deb' => 'libmime-lite-perl', },
|
||||
"MIME::Words" => { 'deb' => 'libmime-perl', },
|
||||
"Compress::Zlib" => { 'deb' => 'libcompress-zlib-perl', },
|
||||
"Net::SMTP" => {
|
||||
'deb' => 'libnet-perl',
|
||||
'opt' => "Alternative to piping into sendmail to send mail.",
|
||||
},
|
||||
"Net::DNS" => {
|
||||
'deb' => 'libnet-dns-perl',
|
||||
},
|
||||
"MIME::Base64" => { 'deb' => 'libmime-base64-perl' },
|
||||
"URI::URL" => { 'deb' => 'liburi-perl' },
|
||||
"HTML::Tagset" => { 'deb' => 'libhtml-tagset-perl' },
|
||||
"HTML::Parser" => { 'deb' => 'libhtml-parser-perl', },
|
||||
"LWP::Simple" => { 'deb' => 'libwww-perl', },
|
||||
"LWP::UserAgent" => { 'deb' => 'libwww-perl', },
|
||||
"GD" => { 'deb' => 'libgd-perl' },
|
||||
"GD::Graph" => {
|
||||
'deb' => 'libgd-graph-perl',
|
||||
'opt' => 'Required to make graphs for the statistics page.',
|
||||
},
|
||||
"Mail::Address" => { 'deb' => 'libmailtools-perl', },
|
||||
"Proc::ProcessTable" => {
|
||||
'deb' => 'libproc-process-perl',
|
||||
'opt' => "Better reliability for starting daemons necessary for high-traffic installations.",
|
||||
},
|
||||
"RPC::XML" => {
|
||||
'deb' => 'librpc-xml-perl',
|
||||
'opt' => 'Required for outgoing XMLRPC support',
|
||||
},
|
||||
"SOAP::Lite" => {
|
||||
'deb' => 'libsoap-lite-perl',
|
||||
'opt' => 'Required for XML-RPC support.',
|
||||
},
|
||||
"Unicode::MapUTF8" => { 'deb' => 'libunicode-maputf8-perl', },
|
||||
"Storable" => {
|
||||
'deb' => 'libstorable-perl',
|
||||
},
|
||||
"XML::RSS" => {
|
||||
'deb' => 'libxml-rss-perl',
|
||||
'opt' => 'Required for retrieving RSS off of other sites (syndication).',
|
||||
},
|
||||
"XML::Simple" => {
|
||||
'deb' => 'libxml-simple-perl',
|
||||
'ver' => 2.12,
|
||||
},
|
||||
"String::CRC32" => {
|
||||
'deb' => 'libstring-crc32-perl',
|
||||
'opt' => 'Required for palette-altering of PNG files. Only necessary if you plan to make your own S2 styles that use PNGs, not GIFs.',
|
||||
},
|
||||
"Time::HiRes" => { 'deb' => 'libtime-hires-perl' },
|
||||
"IO::WrapTie" => { 'deb' => 'libio-stringy-perl' },
|
||||
"XML::Atom" => {
|
||||
'deb' => 'libxml-atom-perl',
|
||||
'opt' => 'Required for AtomAPI support.',
|
||||
},
|
||||
"Math::BigInt::GMP" => {
|
||||
'opt' => 'Aides Crypt::DH so it isn\'t crazy slow.',
|
||||
},
|
||||
"URI::Fetch" => {
|
||||
'opt' => 'Required for OpenID support.',
|
||||
},
|
||||
"Crypt::DH" => {
|
||||
'opt' => 'Required for OpenID support.',
|
||||
},
|
||||
);
|
||||
|
||||
sub check_modules_print {
|
||||
print "[Printing required Perl Modules...]\n";
|
||||
foreach my $mod (sort keys %modules) {
|
||||
print $mod .
|
||||
($modules{$mod}->{'ver'} ? " >= " . $modules{$mod}->{'ver'} : "") .
|
||||
($modules{$mod}->{'opt'} ? " -- " . $modules{$mod}->{'opt'} : "") .
|
||||
"\n";
|
||||
}
|
||||
}
|
||||
|
||||
sub check_modules {
|
||||
print "[Checking for Perl Modules....]\n";
|
||||
|
||||
my @debs;
|
||||
|
||||
foreach my $mod (sort keys %modules) {
|
||||
my $rv = eval "use $mod;";
|
||||
if ($@) {
|
||||
my $dt = $modules{$mod};
|
||||
if ($dt->{'opt'}) {
|
||||
print STDERR "Missing optional module $mod: $dt->{'opt'}\n";
|
||||
} else {
|
||||
push @errors, "Missing perl module: $mod";
|
||||
}
|
||||
push @debs, $dt->{'deb'} if $dt->{'deb'};
|
||||
next;
|
||||
}
|
||||
|
||||
my $ver_want = $modules{$mod}{ver};
|
||||
my $ver_got = $mod->VERSION;
|
||||
if ($ver_want && $ver_got && $ver_got < $ver_want) {
|
||||
push @errors, "Out of date module: $mod (need $ver_want, $ver_got installed)";
|
||||
}
|
||||
}
|
||||
if (@debs && -e '/etc/debian_version') {
|
||||
print STDERR "\n# apt-get install ", join(' ', @debs), "\n\n";
|
||||
}
|
||||
|
||||
$err->(@errors);
|
||||
}
|
||||
|
||||
sub check_env {
|
||||
print "[Checking LJ Environment...]\n";
|
||||
|
||||
$err->("\$LJHOME environment variable not set.")
|
||||
unless $ENV{'LJHOME'};
|
||||
$err->("\$LJHOME directory doesn't exist ($ENV{'LJHOME'})")
|
||||
unless -d $ENV{'LJHOME'};
|
||||
|
||||
# before ljconfig.pl is called, we want to call the site-local checkconfig,
|
||||
# otherwise ljconfig.pl might load ljconfig-local.pl, which maybe load
|
||||
# new modules to implement site-specific hooks.
|
||||
my $local_config = "$ENV{'LJHOME'}/bin/checkconfig-local.pl";
|
||||
if (-e $local_config) {
|
||||
my $good = eval { require $local_config; };
|
||||
exit 1 unless $good;
|
||||
}
|
||||
|
||||
$err->("No ljconfig.pl file found at $ENV{'LJHOME'}/cgi-bin/ljconfig.pl")
|
||||
unless -e "$ENV{'LJHOME'}/cgi-bin/ljconfig.pl";
|
||||
|
||||
eval { require "$ENV{'LJHOME'}/cgi-bin/ljlib.pl"; };
|
||||
$err->("Failed to load ljlib.pl: $@") if $@;
|
||||
|
||||
# if SMTP_SERVER is set, then Net::SMTP is required, not optional.
|
||||
if ($LJ::SMTP_SERVER && ! defined $Net::SMTP::VERSION) {
|
||||
$err->("Net::SMTP isn't available, and you have \$LJ::SMTP_SERVER set.");
|
||||
}
|
||||
}
|
||||
|
||||
sub check_database {
|
||||
print "[Checking Database...]\n";
|
||||
|
||||
require "$ENV{'LJHOME'}/cgi-bin/ljlib.pl";
|
||||
my $dbh = LJ::get_dbh("master");
|
||||
unless ($dbh) {
|
||||
$err->("Couldn't get master database handle.");
|
||||
}
|
||||
foreach my $c (@LJ::CLUSTERS) {
|
||||
my $dbc = LJ::get_cluster_master($c);
|
||||
next if $dbc;
|
||||
$err->("Couldn't get db handle for cluster \#$c");
|
||||
}
|
||||
|
||||
if (%LJ::MOGILEFS_CONFIG && $LJ::MOGILEFS_CONFIG{hosts}) {
|
||||
print "[Checking MogileFS client.]\n";
|
||||
my $mog = LJ::mogclient();
|
||||
die "Couldn't create mogilefs client." unless $mog;
|
||||
}
|
||||
}
|
||||
|
||||
foreach my $check (@checks) {
|
||||
next unless $dochecks{$check};
|
||||
my $cn = "check_".$check;
|
||||
&$cn;
|
||||
}
|
||||
print "All good.\n";
|
||||
print "NOTE: checkconfig.pl doesn't check everything yet\n";
|
||||
|
||||
|
||||
84
local/bin/ljr-tools/clean_cached_comments.pl
Executable file
84
local/bin/ljr-tools/clean_cached_comments.pl
Executable file
@@ -0,0 +1,84 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
# remote user id of user to clean
|
||||
my $ru_id = 491;
|
||||
|
||||
# database connection
|
||||
my $queue_db = "livejournal";
|
||||
my $queue_host = "localhost";
|
||||
my $queue_login = "lj";
|
||||
my $queue_pass = "lj-upyri";
|
||||
|
||||
|
||||
use strict; # preventing my program from doing bad things
|
||||
use DBI; # http://dbi.perl.org
|
||||
|
||||
$| = 1; # unbuffered (almost) output
|
||||
|
||||
my $dbh = DBI->connect(
|
||||
"DBI:mysql:$queue_db:$queue_host",
|
||||
$queue_login, $queue_pass,
|
||||
{RaiseError => 0, AutoCommit => 1}
|
||||
) || die "Can't open database connection: $DBI::errstr";
|
||||
|
||||
my $sth = $dbh->prepare("select * from ljr_remote_users where ru_id = $ru_id");
|
||||
$sth->execute;
|
||||
while (my $row = $sth->fetchrow_hashref) {
|
||||
if ($row->{created_comments_maxid} > 0) {
|
||||
die "User has created comments. Cannot clean cached comments (IMPLEMENT THIS!)\n";
|
||||
}
|
||||
|
||||
my $sth1 = $dbh->prepare("select * from ljr_cached_users where ru_id = $ru_id");
|
||||
$sth1->execute();
|
||||
my $row1 = $sth1->fetchrow_hashref;
|
||||
|
||||
print
|
||||
"You're about to delete cached comments for user [" .
|
||||
$row1->{remote_username} . "].\n" .
|
||||
"Please confirm by typing their username: "
|
||||
;
|
||||
while (<>) {
|
||||
my $iu = $_;
|
||||
|
||||
if ($iu =~ /\s*(.*)\s*/) {
|
||||
$iu = $1;
|
||||
}
|
||||
|
||||
if ($iu ne $row1->{remote_username}) {
|
||||
die "You have to learn to type letters to use this tool.\n";
|
||||
}
|
||||
last;
|
||||
}
|
||||
$sth1->finish;
|
||||
|
||||
print "deleting cached comprops...\n";
|
||||
$sth1 = $dbh->prepare("select * from ljr_cached_comments where ru_id = $ru_id");
|
||||
$sth1->execute();
|
||||
while ($row1 = $sth1->fetchrow_hashref) {
|
||||
my $sth2 = $dbh->prepare(
|
||||
"delete from ljr_cached_comprops where cc_id = " . $row1->{cc_id}
|
||||
);
|
||||
$sth2->execute();
|
||||
$sth2->finish;
|
||||
print ".";
|
||||
}
|
||||
$sth1->finish;
|
||||
|
||||
print "deleting cached comments...\n";
|
||||
$sth1 = $dbh->prepare(
|
||||
"delete from ljr_cached_comments where ru_id = " . $ru_id
|
||||
);
|
||||
$sth1->execute();
|
||||
$sth1->finish;
|
||||
|
||||
print "resetting cached counters...\n";
|
||||
$sth1 = $dbh->prepare(
|
||||
"update ljr_cached_users
|
||||
set remote_meta_maxid = 0, cached_comments_maxid = 0
|
||||
where ru_id = " . $ru_id);
|
||||
$sth1->execute();
|
||||
$sth1->finish;
|
||||
}
|
||||
$sth->finish;
|
||||
|
||||
$dbh->disconnect;
|
||||
94
local/bin/ljr-tools/copy_openid_infos.pl
Executable file
94
local/bin/ljr-tools/copy_openid_infos.pl
Executable file
@@ -0,0 +1,94 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
# database connection
|
||||
my $queue_db = "livejournal";
|
||||
my $queue_host = "localhost";
|
||||
my $queue_login = "lj";
|
||||
my $queue_pass = "lj-upyri";
|
||||
|
||||
|
||||
use strict; # preventing my program from doing bad things
|
||||
use DBI; # http://dbi.perl.org
|
||||
|
||||
$| = 1; # unbuffered (almost) output
|
||||
|
||||
my $dbh = DBI->connect(
|
||||
"DBI:mysql:$queue_db:$queue_host",
|
||||
$queue_login, $queue_pass,
|
||||
{RaiseError => 0, AutoCommit => 1}
|
||||
) || die "Can't open database connection: $DBI::errstr";
|
||||
|
||||
|
||||
my $username;
|
||||
my $new_identity;
|
||||
|
||||
my $sth = $dbh->prepare(
|
||||
"select * from identitymap where idtype='O' and identity like 'http://www.livejournal.com/%'");
|
||||
$sth->execute;
|
||||
while (my $row = $sth->fetchrow_hashref) {
|
||||
$username = "";
|
||||
|
||||
if ($row->{"identity"} =~ /\/users\/(.+[^\/])\/??/ || $row->{"identity"} =~ /\/\~(.+[^\/])\/??/) {
|
||||
my $new_id;
|
||||
my $old_email;
|
||||
my $new_email;
|
||||
my $sth2;
|
||||
|
||||
$username = $1;
|
||||
$new_identity = "";
|
||||
|
||||
if ($username =~ /^_/ || $username =~ /_$/) {
|
||||
$new_identity = "http://users.livejournal.com/" . $username . "/";
|
||||
}
|
||||
else {
|
||||
$new_identity = "http://" . $username . ".livejournal.com/";
|
||||
}
|
||||
|
||||
$sth2 = $dbh->prepare("select email from user where userid = " . $row->{"userid"});
|
||||
$sth2->execute;
|
||||
if (my $row1 = $sth2->fetchrow_hashref) {
|
||||
$old_email = $row1->{"email"};
|
||||
}
|
||||
$sth2->finish;
|
||||
|
||||
$sth2 = $dbh->prepare(
|
||||
"select * from identitymap where idtype='O' and identity ='" . $new_identity . "'");
|
||||
$sth2->execute();
|
||||
if (my $row1 = $sth2->fetchrow_hashref) {
|
||||
$new_id = $row1->{"userid"};
|
||||
|
||||
my $sth3 = $dbh->prepare("select email from user where userid = " . $new_id);
|
||||
$sth3->execute;
|
||||
if (my $row2 = $sth3->fetchrow_hashref) {
|
||||
$new_email = $row2->{"email"};
|
||||
}
|
||||
$sth3->finish;
|
||||
|
||||
print
|
||||
$username . "(" .
|
||||
$row->{"userid"} . ", " . $old_email . "):(" .
|
||||
$new_id . "," . $new_email . ")\n";
|
||||
}
|
||||
$sth2->finish;
|
||||
|
||||
if (!$new_id) {
|
||||
$sth2 = $dbh->prepare(
|
||||
"update identitymap set identity = '" . $new_identity . "' " .
|
||||
"where idtype='O' and userid = " . $row->{"userid"}
|
||||
);
|
||||
$sth2->execute();
|
||||
$sth2->finish;
|
||||
}
|
||||
else {
|
||||
if (!$new_email) {
|
||||
$sth2 = $dbh->prepare("update user set email = '" . $old_email . "' " .
|
||||
"where userid = " . $new_id);
|
||||
$sth2->execute();
|
||||
$sth2->finish;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$sth->finish;
|
||||
|
||||
$dbh->disconnect;
|
||||
113
local/bin/ljr-tools/delete_imported.pl
Executable file
113
local/bin/ljr-tools/delete_imported.pl
Executable file
@@ -0,0 +1,113 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
|
||||
require "$ENV{'LJHOME'}/cgi-bin/ljlib.pl";
|
||||
require "$ENV{'LJHOME'}/cgi-bin/talklib.pl";
|
||||
|
||||
|
||||
# remote user id of user to clean
|
||||
my $ru_id = 27850;
|
||||
|
||||
# database connection
|
||||
my $queue_db = "livejournal";
|
||||
my $queue_host = "localhost";
|
||||
my $queue_login = "lj";
|
||||
my $queue_pass = "lj-upyri";
|
||||
|
||||
|
||||
use strict; # preventing my program from doing bad things
|
||||
use DBI; # http://dbi.perl.org
|
||||
|
||||
$| = 1; # unbuffered (almost) output
|
||||
|
||||
my $dbh = DBI->connect(
|
||||
"DBI:mysql:$queue_db:$queue_host",
|
||||
$queue_login, $queue_pass,
|
||||
{RaiseError => 0, AutoCommit => 1}
|
||||
) || die "Can't open database connection: $DBI::errstr";
|
||||
|
||||
my $sth = $dbh->prepare("select * from ljr_remote_users where ru_id = $ru_id");
|
||||
$sth->execute;
|
||||
while (my $row = $sth->fetchrow_hashref) {
|
||||
if (! $row->{ru_id}) {
|
||||
die "User not found.\n";
|
||||
}
|
||||
|
||||
my $sth1 = $dbh->prepare("select * from ljr_cached_users where ru_id = $ru_id");
|
||||
$sth1->execute();
|
||||
my $row1 = $sth1->fetchrow_hashref;
|
||||
|
||||
print
|
||||
"You're about to delete user [" .
|
||||
$row1->{remote_username} . "].\n" .
|
||||
"Please confirm by typing their username: "
|
||||
;
|
||||
while (<>) {
|
||||
my $iu = $_;
|
||||
if ($iu =~ /\s*(.*)\s*/) { $iu = $1; }
|
||||
if ($iu ne $row1->{remote_username}) {
|
||||
die "You have to learn to type letters to use this tool.\n";
|
||||
}
|
||||
last;
|
||||
}
|
||||
$sth1->finish;
|
||||
|
||||
print "deleting cached comprops and remote comments...\n";
|
||||
$sth1 = $dbh->prepare("select * from ljr_cached_comments where ru_id = $ru_id");
|
||||
$sth1->execute();
|
||||
while ($row1 = $sth1->fetchrow_hashref) {
|
||||
my $sth2 = $dbh->prepare("delete from ljr_cached_comprops where cc_id = " . $row1->{cc_id});
|
||||
$sth2->execute();
|
||||
$sth2->finish;
|
||||
|
||||
$sth2 = $dbh->prepare("delete from ljr_remote_comments where cc_id = " . $row1->{cc_id});
|
||||
$sth2->execute();
|
||||
$sth2->finish;
|
||||
|
||||
print ".";
|
||||
}
|
||||
$sth1->finish;
|
||||
|
||||
print "deleting cached comments...\n";
|
||||
$sth1 = $dbh->prepare("delete from ljr_cached_comments where ru_id = $ru_id");
|
||||
$sth1->execute();
|
||||
$sth1->finish;
|
||||
|
||||
print "deleting ljr_cached_userpics...\n";
|
||||
$sth1 = $dbh->prepare("delete from ljr_cached_userpics where ru_id = $ru_id");
|
||||
$sth1->execute();
|
||||
$sth1->finish;
|
||||
|
||||
print "deleting ljr_cached_users...\n";
|
||||
$sth1 = $dbh->prepare("delete from ljr_cached_users where ru_id = $ru_id");
|
||||
$sth1->execute();
|
||||
$sth1->finish;
|
||||
|
||||
print "deleting local entries...\n";
|
||||
my $lu;
|
||||
$sth1 = $dbh->prepare("select * from ljr_remote_entries where ru_id = $ru_id");
|
||||
$sth1->execute();
|
||||
while ($row1 = $sth1->fetchrow_hashref) {
|
||||
$lu = LJ::load_userid($row1->{"local_journalid"}) unless $lu;
|
||||
LJ::delete_entry($lu, $row1->{"local_jitemid"});
|
||||
}
|
||||
$sth1->finish;
|
||||
|
||||
print "deleting ljr_remote_entries...\n";
|
||||
$sth1 = $dbh->prepare("delete from ljr_remote_entries where ru_id = $ru_id");
|
||||
$sth1->execute();
|
||||
$sth1->finish;
|
||||
|
||||
print "deleting ljr_remote_userpics...\n";
|
||||
$sth1 = $dbh->prepare("delete from ljr_remote_userpics where ru_id = $ru_id");
|
||||
$sth1->execute();
|
||||
$sth1->finish;
|
||||
}
|
||||
$sth->finish;
|
||||
|
||||
$sth = $dbh->prepare("delete from ljr_remote_users where ru_id = $ru_id");
|
||||
$sth->execute;
|
||||
$sth->finish;
|
||||
|
||||
$dbh->disconnect;
|
||||
26
local/bin/ljr-tools/import_pics_for_user.pl
Executable file
26
local/bin/ljr-tools/import_pics_for_user.pl
Executable file
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/perl -w
|
||||
|
||||
use strict;
|
||||
use Simple; # corrected LJ::Simple
|
||||
use XML::Parser;
|
||||
|
||||
require "$ENV{'LJHOME'}/cgi-bin/ljlib.pl";
|
||||
require "$ENV{'LJHOME'}/cgi-bin/talklib.pl";
|
||||
|
||||
require "ljr-defaults.pl";
|
||||
require "ljr-links.pl";
|
||||
require LJR::Distributed;
|
||||
require "ipics.pl";
|
||||
|
||||
#require "ijournal.pl";
|
||||
#require "icomments.pl";
|
||||
|
||||
|
||||
my $e = import_pics(
|
||||
"http://www.livejournal.com",
|
||||
"sharlei",
|
||||
"",
|
||||
"imp_5204",
|
||||
"", 1);
|
||||
|
||||
print $e->{errtext} ."\n" if $e->{err};
|
||||
50
local/bin/ljr-tools/mass_update_journal.pl
Executable file
50
local/bin/ljr-tools/mass_update_journal.pl
Executable file
@@ -0,0 +1,50 @@
|
||||
#!/usr/bin/perl -w
|
||||
#
|
||||
# replaces text in all journal entries. use with caution.
|
||||
#
|
||||
|
||||
BEGIN {
|
||||
$ENV{'LJHOME'} = "/home/lj-admin/lj";
|
||||
};
|
||||
|
||||
use strict;
|
||||
use lib $ENV{'LJHOME'}."/cgi-bin";
|
||||
require "$ENV{'LJHOME'}/cgi-bin/ljlib.pl";
|
||||
|
||||
my $dbh = LJ::get_dbh("master");
|
||||
|
||||
my ($journal, $from_text, $to_text, $do) = @ARGV;
|
||||
|
||||
die("usage: $0 journal_name from_text to_text")
|
||||
unless $journal && $from_text && $to_text;
|
||||
|
||||
$do = 'no' unless $do;
|
||||
|
||||
my $u = LJ::load_user($journal);
|
||||
|
||||
die("Invalid journal [$journal]") unless $u;
|
||||
|
||||
print "Loaded: $u->{'name'} [$u->{'userid'}] \n";
|
||||
|
||||
my $sth = $dbh->prepare("select * from logtext2 where journalid = ?");
|
||||
$sth->execute($u->{'userid'});
|
||||
|
||||
while (my $r = $sth->fetchrow_hashref()) {
|
||||
if ($r->{'event'} =~ /$from_text/) {
|
||||
print "journal entry [$r->{'jitemid'}] matches\n";
|
||||
# print "journal entry [$r->{'jitemid'}] matches:\n$r->{'event'}\n";
|
||||
$r->{'event'} =~ s/$from_text/$to_text/g;
|
||||
# print "replaced:\n$r->{'event'}\n\n";
|
||||
|
||||
if ($do eq 'process') {
|
||||
$dbh->do("UPDATE logtext2 set event = ? where journalid=? and jitemid=?",
|
||||
undef, $r->{'event'}, $r->{'journalid'}, $r->{'jitemid'});
|
||||
if ($dbh->err) {
|
||||
die("Error while updating entry [$r->{'jitemid'}]: " . $dbh->errstr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
print "do not forget to restart memcache" if $do eq 'process';
|
||||
print "finished\n";
|
||||
53
local/bin/ljr-tools/mysql-convert-storable.pl
Executable file
53
local/bin/ljr-tools/mysql-convert-storable.pl
Executable file
@@ -0,0 +1,53 @@
|
||||
#!/usr/bin/perl -w
|
||||
#
|
||||
# converts s1usercache and s1stylecache blob fields
|
||||
# which store Storable::freeze data from ::freeze to ::nfreeze
|
||||
#
|
||||
# 14oct07 petya@nigilist.ru
|
||||
# initial revision
|
||||
#
|
||||
|
||||
sub convert {
|
||||
my ($dbh, $table, $unique, $field) = @_;
|
||||
|
||||
print "convert $table.$field ($unique)\n";
|
||||
|
||||
my $sql = "select * from $table;";
|
||||
|
||||
my $sth = $dbh->prepare($sql) or die "preparing: ", $dbh->errstr;
|
||||
$sth->execute or die "executing: ", $dbh->errstr;
|
||||
|
||||
while (my $row = $sth->fetchrow_hashref) {
|
||||
if ($row->{"$field"}) {
|
||||
my $obj = Storable::thaw($row->{"$field"});
|
||||
if ($obj) {
|
||||
print $row->{"$unique"} . "\n";
|
||||
$dbh->do("UPDATE $table SET $field=? WHERE $unique=?", undef,
|
||||
Storable::nfreeze($obj), $row->{"$unique"}) ||
|
||||
die "Error updating $table. Unique id: " . $row->{"$unique"} . "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
print "\n";
|
||||
}
|
||||
|
||||
use strict;
|
||||
use DBI;
|
||||
use Storable;
|
||||
|
||||
$ENV{'LJHOME'} = "/home/lj-admin";
|
||||
do $ENV{'LJHOME'} . "/lj/cgi-bin/ljconfig.pl";
|
||||
my $host = $LJ::DBINFO{'master'}->{'host'};
|
||||
my $user = $LJ::DBINFO{'master'}->{'user'};
|
||||
my $pwd = $LJ::DBINFO{'master'}->{'pass'};
|
||||
my $db = "prod_livejournal";
|
||||
|
||||
$| = 1; # turn off buffered output
|
||||
|
||||
# connect to the database.
|
||||
my $dbh = DBI->connect( "DBI:mysql:mysql_socket=/tmp/mysql.sock;hostname=$host;port=3306;database=$db", $user, $pwd)
|
||||
or die "Connecting : $DBI::errstr\n ";
|
||||
|
||||
#convert ($dbh, "s1stylecache", "styleid", "vars_stor");
|
||||
#convert ($dbh, "s1usercache", "userid", "color_stor");
|
||||
#convert ($dbh, "s1usercache", "userid", "override_stor");
|
||||
128
local/bin/ljr-tools/rlj2-ljrgate.pl
Executable file
128
local/bin/ljr-tools/rlj2-ljrgate.pl
Executable file
@@ -0,0 +1,128 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
use XMLRPC::Lite;
|
||||
use Digest::MD5 qw(md5_hex);
|
||||
use DBI;
|
||||
use Time::Local;
|
||||
use lib "$ENV{'LJHOME'}/cgi-bin";
|
||||
|
||||
do $ENV{'LJHOME'} . "/cgi-bin/ljconfig.pl";
|
||||
require "$ENV{'LJHOME'}/cgi-bin/ljlib.pl";
|
||||
use LJR::Viewuserstandalone;
|
||||
use LJR::Gate;
|
||||
use LJR::Distributed;
|
||||
|
||||
#
|
||||
#îÁÓÔÒÏÊËÉ
|
||||
#
|
||||
|
||||
#ó×ÏÊÓÔ×Á ÓÏÅÄÉÎÅÎÉÑ Ó ÂÁÚÏÊ
|
||||
my $qhost = $LJ::DBINFO{'master'}->{'host'};
|
||||
my $quser = $LJ::DBINFO{'master'}->{'user'};
|
||||
my $qpass = $LJ::DBINFO{'master'}->{'pass'};
|
||||
my $qsock = $LJ::DBINFO{'master'}->{'sock'};
|
||||
my $qport = $LJ::DBINFO{'master'}->{'port'};
|
||||
|
||||
my $dbh = DBI->connect(
|
||||
"DBI:mysql:mysql_socket=$qsock;hostname=$qhost;port=$qport;database=prod_ljgate",
|
||||
$quser, $qpass, ) || die localtime(time) . ": Can't connect to database\n";
|
||||
|
||||
my $dbhljr = DBI->connect(
|
||||
"DBI:mysql:mysql_socket=$qsock;hostname=$qhost;port=$qport;database=prod_livejournal",
|
||||
$quser, $qpass, ) || die localtime(time) . ": Can't connect to database\n";
|
||||
|
||||
my $get_our = sub {
|
||||
my ($userid) = @_;
|
||||
my $sqh = $dbh->prepare("SELECT * FROM our_user where userid=?");
|
||||
$sqh->execute($userid);
|
||||
my $res = $sqh->fetchrow_hashref;
|
||||
$sqh->finish;
|
||||
return $res;
|
||||
};
|
||||
|
||||
my $get_alien = sub {
|
||||
my ($userid) = @_;
|
||||
my $sqh = $dbh->prepare("SELECT * FROM alien where alienid=?");
|
||||
$sqh->execute($userid);
|
||||
my $res = $sqh->fetchrow_hashref;
|
||||
$sqh->finish;
|
||||
return $res;
|
||||
};
|
||||
|
||||
my $get_lj_user = sub {
|
||||
my ($user) = @_;
|
||||
$user =~ s/\-/\_/g;
|
||||
my $sqh = $dbhljr->prepare("SELECT * FROM user where user=?");
|
||||
$sqh->execute($user);
|
||||
my $res = $sqh->fetchrow_hashref;
|
||||
$sqh->finish;
|
||||
return $res;
|
||||
};
|
||||
|
||||
my $count_gated_records = sub {
|
||||
my ($userid) = @_;
|
||||
my $sqh = $dbh->prepare("SELECT count(*) FROM rlj_lj_id where userid=?");
|
||||
$sqh->execute($userid);
|
||||
my ($res) = $sqh->fetchrow_array;
|
||||
$sqh->finish;
|
||||
return $res;
|
||||
};
|
||||
|
||||
my $sqh = $dbh->prepare("SELECT userid,alienid FROM rlj2lj");
|
||||
$sqh->execute;
|
||||
my $result;
|
||||
while ($result = $sqh->fetchrow_hashref) {
|
||||
my $our = $get_our->($result->{'userid'});
|
||||
my $alien = $get_alien->($result->{'alienid'});
|
||||
|
||||
if ($our && $alien && $alien->{'alienpass'}) {
|
||||
my $ljuser = $get_lj_user->($our->{'our_user'});
|
||||
|
||||
my $ru = LJR::Distributed::get_remote_server("www.livejournal.com");
|
||||
die $ru->{"errtext"} if $ru->{"err"};
|
||||
$ru->{'username'} = $alien->{'alien'};
|
||||
$ru = LJR::Distributed::get_cached_user($ru);
|
||||
die $ru->{"errtext"} if $ru->{"err"};
|
||||
|
||||
print
|
||||
$our->{'our_user'} .
|
||||
" -> " .
|
||||
$alien->{'alien'} . " ($ru->{'ru_id'}) " . "pass: " . $alien->{'alienpass'} .
|
||||
"\n"
|
||||
;
|
||||
|
||||
my $r = LJR::Distributed::update_export_settings($our->{'our_user'}, $ru->{'ru_id'}, $alien->{'alienpass'});
|
||||
die $r->{'errtext'} if $r->{'err'};
|
||||
|
||||
if ($ljuser) {
|
||||
print "ljr id: " . $ljuser->{'userid'};
|
||||
}
|
||||
else {
|
||||
print "ljr id: error";
|
||||
}
|
||||
print "; ";
|
||||
|
||||
my $gated_records = $count_gated_records->($our->{'userid'});
|
||||
print $gated_records;
|
||||
|
||||
print "\n";
|
||||
# my $xmlrpc = LJR::Gate::Authenticate ("www.livejournal.com",
|
||||
# $alien->{'alien'}, $alien->{'alienpass'});
|
||||
# if ($xmlrpc->{'err_text'}) {
|
||||
# print "err\n";
|
||||
# }
|
||||
# else {
|
||||
# print "ok\n";
|
||||
# }
|
||||
}
|
||||
else {
|
||||
print
|
||||
$result->{'userid'} . "($our->{'our_user'})" . " -> " .
|
||||
$result->{'alienid'} . "($alien->{'alien'})" . "\n"
|
||||
;
|
||||
}
|
||||
}
|
||||
$sqh->finish;
|
||||
$dbh->disconnect;
|
||||
$dbhljr->disconnect;
|
||||
4596
local/bin/ljrimport/Simple.pm
Executable file
4596
local/bin/ljrimport/Simple.pm
Executable file
File diff suppressed because it is too large
Load Diff
647
local/bin/ljrimport/icomments.pl
Executable file
647
local/bin/ljrimport/icomments.pl
Executable file
@@ -0,0 +1,647 @@
|
||||
#!/usr/bin/perl -w
|
||||
|
||||
use strict;
|
||||
use Simple; # corrected LJ::Simple
|
||||
use XML::Parser;
|
||||
use POSIX;
|
||||
|
||||
require "$ENV{'LJHOME'}/cgi-bin/ljlib.pl";
|
||||
require "ljr-defaults.pl";
|
||||
require "ljr-links.pl";
|
||||
require LJR::Distributed;
|
||||
require LJR::unicode;
|
||||
require "$ENV{'LJHOME'}/cgi-bin/talklib.pl";
|
||||
require "ipics.pl";
|
||||
|
||||
my $err = sub {
|
||||
my %res = ();
|
||||
|
||||
$res{"err"} = 1;
|
||||
$res{"errtext"} = join ("\n", @_);
|
||||
return \%res;
|
||||
};
|
||||
my $xmlerrt;
|
||||
my $xmlerr = sub {
|
||||
my $expat = shift;
|
||||
|
||||
my $cstack = "\ncallstack:";
|
||||
my $i = 0;
|
||||
while ( 1 ) {
|
||||
my $tfunc = (caller($i))[3];
|
||||
if ($tfunc && $tfunc ne "") {
|
||||
if ($tfunc !~ /\_\_ANON\_\_/) {
|
||||
$cstack .= " " . $tfunc;
|
||||
}
|
||||
$i = $i + 1;
|
||||
}
|
||||
else {
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
$xmlerrt = join("\n", @_);
|
||||
$xmlerrt .= $cstack;
|
||||
$expat->finish();
|
||||
};
|
||||
|
||||
my $dumpxml = sub {
|
||||
my ($xdata, $username) = @_;
|
||||
|
||||
my $t = `date +"%T"`;
|
||||
$t = substr($t, 0, length($t) - 1);
|
||||
open(my $outfile, ">$ENV{'LJHOME'}/logs/err_" . $username . "_" . $t . ".xml");
|
||||
print $outfile "$xdata";
|
||||
close($outfile);
|
||||
};
|
||||
|
||||
# kind of global variables
|
||||
my $DEBUG=1;
|
||||
|
||||
my $got_max_commentid;
|
||||
my $empty_num = 0;
|
||||
|
||||
my $ru; # current remote user (the one being cached and imported)
|
||||
my $cmode;
|
||||
my $xml_maxid = 0;
|
||||
my $soft_cached_default_pics;
|
||||
my $soft_cached_keyworded_pics;
|
||||
my $posters_without_names; # lj bug workaround: http://rt.livejournal.org/Ticket/Display.html?id=762
|
||||
|
||||
sub cstatus_print {
|
||||
my $statustr = join("", @_);
|
||||
|
||||
eval { LJR::Import::import_log($statustr); };
|
||||
|
||||
if ($@) {
|
||||
print $@ . "\n";
|
||||
}
|
||||
|
||||
if ($DEBUG) {
|
||||
eval { LJR::Import::log_print($statustr); };
|
||||
|
||||
if ($@) {
|
||||
print $statustr . "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# comment processing
|
||||
my $skip_tags = qr/^(livejournal|comments|usermaps|nextid)$/;
|
||||
my $maxid = qr/^(maxid)$/;
|
||||
my $comment_tag = qr/^(comment)$/;
|
||||
my $usermap_tag = qr/^(usermap)$/;
|
||||
my $data_tags = qr/^(subject|body|date)$/;
|
||||
my $prop_tag = qr/^(property)$/;
|
||||
|
||||
LJ::load_props("talk");
|
||||
return $err->("Can't load talkprops.") unless $LJ::CACHE_PROP{talk};
|
||||
my @tprops;
|
||||
foreach my $k (keys %{$LJ::CACHE_PROP{talk}}) {
|
||||
push(@tprops, $k);
|
||||
}
|
||||
my $tprops = join("|", @tprops);
|
||||
my $known_props = qr/^($tprops)$/;
|
||||
|
||||
my %comment = (); # current comment structure
|
||||
my $cid = ""; # current tag (inside comment tag)
|
||||
my $ctext = ""; # current value of $cid
|
||||
|
||||
|
||||
# export_comments.bml xml handling routines
|
||||
sub xmlh_comment_start() {
|
||||
my $expat = shift;
|
||||
my @params = @_;
|
||||
|
||||
if ($params[0] =~ /$skip_tags/) {
|
||||
# skip valid but meaningless tags
|
||||
}
|
||||
elsif ($cmode eq "comment_meta" && $params[0] =~ /$usermap_tag/) {
|
||||
shift @params; # skip "usermap"
|
||||
|
||||
my %usermap = ();
|
||||
%usermap = @params;
|
||||
|
||||
if ($usermap{id} && $usermap{user}) {
|
||||
my $r = {
|
||||
serverid => $ru->{serverid},
|
||||
userid => $usermap{id},
|
||||
username => $usermap{user},
|
||||
};
|
||||
|
||||
$r = LJR::Distributed::get_cached_user($r);
|
||||
return $xmlerr->($expat, $r->{errtext}) if $r->{err};
|
||||
|
||||
$r = LJR::Distributed::get_imported_user($r);
|
||||
return $xmlerr->($expat, $r->{errtext}) if $r->{err};
|
||||
|
||||
$r = LJR::Distributed::set_cu_field($r, "local_commenterid", $r->{commenterid});
|
||||
return $xmlerr->($expat, $r->{errtext}) if $r->{err};
|
||||
|
||||
if (!$soft_cached_default_pics->{$usermap{id}}) {
|
||||
my $iu = LJ::load_userid ($r->{local_commenterid});
|
||||
# cstatus_print(
|
||||
# "caching default userpic for " . $r->{username} .
|
||||
# " (" . $r->{local_commenterid} . ":" . $iu->{user} . ")"
|
||||
# );
|
||||
|
||||
my $e = import_pics(
|
||||
$ru->{servername},
|
||||
$usermap{user},
|
||||
"",
|
||||
$iu->{user},
|
||||
"", 1);
|
||||
return $xmlerr->($expat, "importing default userpic for [" . $usermap{user} . "]:", $e->{errtext})
|
||||
if $e->{err};
|
||||
|
||||
$soft_cached_default_pics->{$usermap{id}} = 1;
|
||||
}
|
||||
}
|
||||
elsif ($usermap{id} && !$usermap{user}) {
|
||||
$posters_without_names->{$usermap{id}} = 1;
|
||||
}
|
||||
else {
|
||||
return $xmlerr->($expat,
|
||||
"Unknown XML-structure: " . join (" ", @params),
|
||||
"at line " . $expat->current_line);
|
||||
}
|
||||
}
|
||||
elsif ($params[0] =~ /$comment_tag/) {
|
||||
# we're starting to process new comment
|
||||
shift @params;
|
||||
|
||||
%comment = ();
|
||||
%comment = @params; # grab all comment attributes
|
||||
}
|
||||
elsif ($cmode eq "comment_body" && $params[0] =~ /$data_tags/) {
|
||||
$cid = $params[0];
|
||||
$ctext = "";
|
||||
}
|
||||
elsif ($cmode eq "comment_body" && $params[0] =~ /$prop_tag/) {
|
||||
shift @params; # skip "property"
|
||||
|
||||
# skip "name" attribute name
|
||||
if (shift @params && $params[0] =~ /$known_props/) {
|
||||
$cid = $params[0];
|
||||
$ctext = "";
|
||||
}
|
||||
}
|
||||
elsif ($params[0] =~ /$maxid/) {
|
||||
$ctext = "";
|
||||
}
|
||||
else {
|
||||
return $xmlerr->($expat,
|
||||
"Unknown XML-structure: " . join (" ", @params),
|
||||
"at line " . $expat->current_line);
|
||||
}
|
||||
}
|
||||
sub xmlh_comment_end() {
|
||||
my $expat = shift;
|
||||
my @params = @_;
|
||||
|
||||
if ($params[0] =~ /$skip_tags/) {
|
||||
# almost finished
|
||||
}
|
||||
elsif ($cmode eq "comment_meta" && $params[0] =~ /$usermap_tag/) {
|
||||
# nop
|
||||
}
|
||||
elsif ($params[0] =~ /$comment_tag/) {
|
||||
if ($cmode eq "comment_body") {
|
||||
|
||||
# print $comment{"id"} . "\n";
|
||||
# print "COMMENT\n";
|
||||
# while ((my $k, my $v) = each(%comment)) {
|
||||
# print $k . ":" . $v . "\n";
|
||||
# }
|
||||
# print "/COMMENT\n";
|
||||
|
||||
$comment{ru_id} = $ru->{ru_id};
|
||||
|
||||
if (
|
||||
$comment{props} &&
|
||||
$comment{props}->{"picture_keyword"} &&
|
||||
$comment{posterid} &&
|
||||
!$soft_cached_keyworded_pics->{$comment{posterid}}->{$comment{props}->{"picture_keyword"}}
|
||||
) {
|
||||
|
||||
my $r = {
|
||||
serverid => $ru->{serverid},
|
||||
userid => $comment{posterid},
|
||||
};
|
||||
|
||||
$r = LJR::Distributed::get_cached_user($r);
|
||||
return $xmlerr->($expat, $r->{errtext}) if $r->{err};
|
||||
|
||||
$r = LJR::Distributed::get_imported_user($r);
|
||||
return $xmlerr->($expat, $r->{errtext} . "(userid: " . $comment{'posterid'} . ")") if $r->{err};
|
||||
|
||||
$r = LJR::Distributed::get_cu_field($r, "local_commenterid");
|
||||
return $xmlerr->($expat, $r->{errtext}) if $r->{err};
|
||||
|
||||
my $iu = LJ::load_userid ($r->{local_commenterid});
|
||||
#cstatus_print ("caching userpic " . $comment{props}->{"picture_keyword"} . " for " . $r->{username} . ":" . $iu->{user});
|
||||
|
||||
my $e = import_pics (
|
||||
$ru->{servername},
|
||||
$r->{username},
|
||||
"",
|
||||
$iu->{user},
|
||||
$comment{props}->{"picture_keyword"},
|
||||
0);
|
||||
return $xmlerr->($expat, $e->{errtext}) if $e->{err};
|
||||
|
||||
$soft_cached_keyworded_pics->{$comment{posterid}}->{$comment{props}->{"picture_keyword"}} = 1;
|
||||
}
|
||||
|
||||
LJR::Links::make_ljr_hrefs(
|
||||
LJR::Links::get_server_url($ru->{"servername"}, "base"),
|
||||
$ru->{"servername"}, \$comment{body}
|
||||
);
|
||||
|
||||
if ($comment{'posterid'} && $posters_without_names->{$comment{'posterid'}}) {
|
||||
$comment{'posterid'} = undef;
|
||||
}
|
||||
if (!$comment{'body'} && $comment{'state'} ne "D") {
|
||||
$comment{'body'} = "LJR::Import warning: no comment body during import.";
|
||||
}
|
||||
|
||||
my $c = LJR::Distributed::cache_comment (\%comment);
|
||||
return $xmlerr->($expat, $c->{'errtext'}) if $c->{'err'};
|
||||
|
||||
if (!$ru->{cached_comments_maxid} ||
|
||||
$comment{id} > $ru->{cached_comments_maxid}) {
|
||||
$ru->{cached_comments_maxid} = $comment{id};
|
||||
}
|
||||
}
|
||||
|
||||
$got_max_commentid++;
|
||||
$empty_num = 0;
|
||||
}
|
||||
elsif ($params[0] =~ /$data_tags/) {
|
||||
$comment{$cid} = $ctext;
|
||||
}
|
||||
elsif ($params[0] =~ /$prop_tag/) {
|
||||
$comment{props}->{$cid} = $ctext;
|
||||
}
|
||||
elsif ($params[0] =~ /$maxid/) {
|
||||
$xml_maxid = $ctext;
|
||||
|
||||
if ($cmode eq "comment_body" && $xml_maxid > $ru->{remote_meta_maxid}) {
|
||||
my $tmid = $got_max_commentid;
|
||||
my $txid = $xml_maxid;
|
||||
my $tempty = $empty_num;
|
||||
|
||||
$got_max_commentid = $ru->{remote_meta_maxid};
|
||||
my $e = get_usermaps_cycled(
|
||||
$ru->{servername},
|
||||
$ru->{username},
|
||||
$ru->{pass},
|
||||
$got_max_commentid + 1);
|
||||
return $xmlerr->($expat, $e->{errtext}) if $e->{err};
|
||||
|
||||
# restore comment_body xml-parsing mode
|
||||
$xml_maxid = $txid;
|
||||
$got_max_commentid = $tmid;
|
||||
$empty_num = $tempty;
|
||||
$cmode = "comment_body";
|
||||
}
|
||||
}
|
||||
else {
|
||||
return $xmlerr->($expat,
|
||||
"Unknown tag: " . join (" ", @params),
|
||||
"at line " . $expat->current_line
|
||||
);
|
||||
}
|
||||
}
|
||||
sub xmlh_comment_char() {
|
||||
my $expat = shift;
|
||||
my $tt = join("", @_);
|
||||
$ctext = $ctext . $tt;
|
||||
}
|
||||
|
||||
sub get_usermaps_cycled {
|
||||
my ($server, $username, $pass, $startid) = @_;
|
||||
|
||||
my $comments_map = {};
|
||||
my $do_login = 1;
|
||||
|
||||
$LJ::Simple::network_retries = $LJR::NETWORK_RETRIES;
|
||||
$LJ::Simple::network_sleep = $LJR::NETWORK_SLEEP;
|
||||
$LJ::Simple::LJ_Client = $LJR::LJ_CLIENT;
|
||||
$LJ::Simple::UserAgent = $LJR::USER_AGENT;
|
||||
|
||||
my $i = 0;
|
||||
my $remote_lj;
|
||||
|
||||
while (1) {
|
||||
if ($do_login) {
|
||||
$remote_lj = new LJ::Simple ({
|
||||
site => $server,
|
||||
user => $username,
|
||||
pass => $pass,
|
||||
pics => 0,
|
||||
moods => 0,
|
||||
});
|
||||
return $err->("Can't login to remote site.", $LJ::Simple::error) unless defined $remote_lj;
|
||||
|
||||
if (!$remote_lj->GenerateCookie()) {
|
||||
if (!$remote_lj->GenerateCookie()) {
|
||||
return $err->("Can't generate login cookie.", $LJ::Simple::error);
|
||||
}
|
||||
}
|
||||
|
||||
$do_login = 0;
|
||||
}
|
||||
|
||||
# do not process those which were processed once
|
||||
if ($comments_map->{$startid}) {
|
||||
$startid++;
|
||||
next;
|
||||
}
|
||||
|
||||
my $res = $remote_lj->GetRawData(
|
||||
{"url" => "/export_comments.bml?get=comment_meta&startid=" . $startid}
|
||||
);
|
||||
|
||||
if ($res && $res->{content}) {
|
||||
$cmode = "comment_meta";
|
||||
|
||||
my $xdata = $res->{content};
|
||||
LJR::unicode::force_utf8(\$xdata);
|
||||
eval { LJ::text_out(\$xdata); };
|
||||
|
||||
my $p1 = new XML::Parser (
|
||||
Handlers => {
|
||||
Start => \&xmlh_comment_start,
|
||||
End => \&xmlh_comment_end,
|
||||
Char => \&xmlh_comment_char
|
||||
});
|
||||
|
||||
$xml_maxid = 0;
|
||||
$xmlerrt = "";
|
||||
|
||||
eval { $p1->parse($xdata); };
|
||||
if ($@) {
|
||||
if ($i < $LJR::NETWORK_RETRIES) {
|
||||
if ($xdata =~ /Login Required/) {
|
||||
$do_login = 1;
|
||||
}
|
||||
|
||||
$i++;
|
||||
LJR::NETWORK_SLEEP;
|
||||
next;
|
||||
}
|
||||
else {
|
||||
$dumpxml->($xdata, $username);
|
||||
return $err->("Runtime error parsing XML (meta, $startid): ", $@);
|
||||
}
|
||||
}
|
||||
if ($xmlerrt) {
|
||||
$dumpxml->($xdata, $username);
|
||||
return $err->("Error parsing XML (meta, $startid): ", $xmlerrt);
|
||||
}
|
||||
|
||||
# xml was processed successfully
|
||||
$comments_map->{$startid} = 1;
|
||||
|
||||
cstatus_print ("prefetched $got_max_commentid (skipped $empty_num) of $xml_maxid comments");
|
||||
if ($got_max_commentid + $empty_num < $xml_maxid) {
|
||||
$empty_num++;
|
||||
$startid = $got_max_commentid + $empty_num;
|
||||
next;
|
||||
}
|
||||
else {
|
||||
$got_max_commentid = 0 unless $got_max_commentid;
|
||||
$ru = LJR::Distributed::set_cu_field($ru, "remote_meta_maxid", $got_max_commentid);
|
||||
return $err->($ru->{errtext}) if $ru->{err};
|
||||
return undef;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ($i < $LJR::NETWORK_RETRIES) {
|
||||
LJR::NETWORK_SLEEP; $i++; next;
|
||||
}
|
||||
else {
|
||||
return $err->("can't get comments metadata: " . $LJ::Simple::error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub get_usermaps {
|
||||
my ($server, $username, $pass, $startid) = @_;
|
||||
|
||||
$ru = LJR::Distributed::get_remote_server($server);
|
||||
return $err->($ru->{"errtext"}) if $ru->{"err"};
|
||||
$ru->{username} = $username;
|
||||
$ru->{pass} = $pass;
|
||||
$ru = LJR::Distributed::get_cached_user($ru);
|
||||
return $err->($ru->{"errtext"}) if $ru->{"err"};
|
||||
|
||||
$got_max_commentid = $startid - 1;
|
||||
|
||||
cstatus_print ("caching commented users.");
|
||||
|
||||
my $e = get_usermaps_cycled($server, $username, $pass, $startid);
|
||||
return $err->($e->{errtext}) if $e->{err};
|
||||
}
|
||||
|
||||
sub get_comments_cycled {
|
||||
my ($server, $username, $pass, $startid) = @_;
|
||||
|
||||
my $comments_map = {};
|
||||
my $do_login = 1;
|
||||
|
||||
$ru = LJR::Distributed::get_remote_server($server) unless $ru->{serverid};
|
||||
return $err->($ru->{"errtext"}) if $ru->{"err"};
|
||||
|
||||
$ru->{username} = $username;
|
||||
|
||||
$ru = LJR::Distributed::get_cached_user($ru);
|
||||
return $err->($ru->{"errtext"}) if $ru->{"err"};
|
||||
|
||||
$LJ::Simple::network_retries = $LJR::NETWORK_RETRIES;
|
||||
$LJ::Simple::network_sleep = $LJR::NETWORK_SLEEP;
|
||||
$LJ::Simple::LJ_Client = $LJR::LJ_CLIENT;
|
||||
$LJ::Simple::UserAgent = $LJR::USER_AGENT;
|
||||
|
||||
my $i = 0;
|
||||
my $h_counter;
|
||||
my $remote_lj;
|
||||
|
||||
while (1) {
|
||||
if ($do_login) {
|
||||
$remote_lj = new LJ::Simple ({
|
||||
site => $server,
|
||||
user => $username,
|
||||
pass => $pass,
|
||||
pics => 0,
|
||||
moods => 0,
|
||||
});
|
||||
return $err->("Can't login to remote site.", $LJ::Simple::error) unless defined $remote_lj;
|
||||
|
||||
if (!$remote_lj->GenerateCookie()) {
|
||||
if (!$remote_lj->GenerateCookie()) {
|
||||
return $err->("Can't generate login cookie.", $LJ::Simple::error);
|
||||
}
|
||||
}
|
||||
|
||||
$do_login = 0;
|
||||
}
|
||||
|
||||
# do not process those which were processed once
|
||||
if ($comments_map->{$startid}) {
|
||||
$startid++;
|
||||
next;
|
||||
}
|
||||
|
||||
my $res = $remote_lj->GetRawData(
|
||||
{"url" => "/export_comments.bml?get=comment_body&props=1&startid=" . $startid}
|
||||
);
|
||||
|
||||
if ($res && $res->{content}) {
|
||||
my $xdata = $res->{content};
|
||||
LJR::unicode::force_utf8(\$xdata);
|
||||
eval { LJ::text_out(\$xdata); };
|
||||
|
||||
$cmode = "comment_body";
|
||||
my $p1 = new XML::Parser (
|
||||
Handlers => {
|
||||
Start => \&xmlh_comment_start,
|
||||
End => \&xmlh_comment_end,
|
||||
Char => \&xmlh_comment_char
|
||||
});
|
||||
|
||||
$xmlerrt = "";
|
||||
eval { $p1->parse($xdata); };
|
||||
if ($@) {
|
||||
if ($i < $LJR::NETWORK_RETRIES) {
|
||||
if ($xdata =~ /Login Required/) {
|
||||
$do_login = 1;
|
||||
}
|
||||
|
||||
$i++;
|
||||
LJR::NETWORK_SLEEP;
|
||||
next;
|
||||
}
|
||||
else {
|
||||
$dumpxml->($xdata, $username);
|
||||
return $err->("Runtime error parsing XML (body, $startid): ", $@);
|
||||
}
|
||||
}
|
||||
if ($xmlerrt) {
|
||||
$dumpxml->($xdata, $username);
|
||||
return $err->("Error parsing XML (body, $startid): ", $xmlerrt);
|
||||
}
|
||||
|
||||
# remember last cached comment number (which is equal to its id)
|
||||
$ru = LJR::Distributed::set_cu_field(
|
||||
$ru, "cached_comments_maxid",
|
||||
$ru->{cached_comments_maxid});
|
||||
return $err->($ru->{errtext}) if $ru->{err};
|
||||
|
||||
# xml was processed successfully
|
||||
$comments_map->{$startid} = 1;
|
||||
|
||||
cstatus_print ("getting comments. last id: $ru->{cached_comments_maxid}, skipping: $empty_num, just walked: $startid, max: $ru->{remote_meta_maxid}");
|
||||
if ($ru->{cached_comments_maxid} + $empty_num < $ru->{remote_meta_maxid}) {
|
||||
if ($empty_num > 0) {
|
||||
$empty_num =
|
||||
(POSIX::floor($ru->{cached_comments_maxid} / 100) + 1) * 100 -
|
||||
$ru->{cached_comments_maxid} +
|
||||
$h_counter * 100;
|
||||
|
||||
$h_counter++;
|
||||
}
|
||||
else {
|
||||
$empty_num++;
|
||||
$h_counter = 0;
|
||||
}
|
||||
|
||||
$startid = $ru->{cached_comments_maxid} + $empty_num;
|
||||
next;
|
||||
}
|
||||
else {
|
||||
return undef;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ($i < $LJR::NETWORK_RETRIES) {
|
||||
LJR::NETWORK_SLEEP; $i++; next;
|
||||
}
|
||||
else {
|
||||
return $err->("can't get comments: " . $LJ::Simple::error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub get_comments {
|
||||
my ($server, $username, $pass, $startid) = @_;
|
||||
|
||||
cstatus_print ("caching comments");
|
||||
|
||||
LJ::disconnect_dbs();
|
||||
|
||||
$soft_cached_keyworded_pics = {};
|
||||
$soft_cached_default_pics = {};
|
||||
$posters_without_names = {};
|
||||
|
||||
$ru = LJR::Distributed::get_remote_server($server);
|
||||
return $err->($ru->{"errtext"}) if $ru->{"err"};
|
||||
$ru->{username} = $username;
|
||||
$ru->{pass} = $pass;
|
||||
$ru = LJR::Distributed::get_cached_user($ru);
|
||||
return $err->($ru->{"errtext"}) if $ru->{"err"};
|
||||
|
||||
my $e; # for possible errors
|
||||
|
||||
$ru = LJR::Distributed::get_cu_field($ru, "cached_comments_maxid");
|
||||
$ru->{cached_comments_maxid} = 0 if not defined $ru->{cached_comments_maxid};
|
||||
|
||||
# don't want to download cached comments again
|
||||
$startid = $ru->{cached_comments_maxid} + 1
|
||||
if $ru->{cached_comments_maxid} > $startid;
|
||||
|
||||
$ru = LJR::Distributed::get_cu_field($ru, "remote_meta_maxid");
|
||||
$ru->{remote_meta_maxid} = 0 if not defined $ru->{remote_meta_maxid};
|
||||
|
||||
# try to minimize possible further delays
|
||||
$got_max_commentid = $ru->{remote_meta_maxid};
|
||||
$e = get_usermaps_cycled($server, $username, $pass, $got_max_commentid + 1);
|
||||
return $err->($e->{errtext}) if $e->{err};
|
||||
|
||||
# get remote comments and cache them
|
||||
$got_max_commentid = $startid - 1;
|
||||
$e = get_comments_cycled($server, $username, $pass, $startid);
|
||||
return $err->($e->{errtext}) if $e->{err};
|
||||
|
||||
$soft_cached_keyworded_pics = {};
|
||||
$soft_cached_default_pics = {};
|
||||
$posters_without_names = {};
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub create_imported_comments {
|
||||
my ($remote_site, $remote_user, $local_user) = @_;
|
||||
|
||||
LJ::disconnect_dbs();
|
||||
|
||||
my $ru = LJR::Distributed::get_remote_server($remote_site);
|
||||
return $err->($ru->{"errtext"}) if $ru->{"err"};
|
||||
|
||||
$ru->{username} = $remote_user;
|
||||
$ru = LJR::Distributed::get_cached_user($ru);
|
||||
return $err->($ru->{"errtext"}) if $ru->{"err"};
|
||||
|
||||
cstatus_print("creating comments.");
|
||||
|
||||
$ru = LJR::Distributed::create_imported_comments($ru, $local_user);
|
||||
return $err->($ru->{"errtext"}) if $ru->{"err"};
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
|
||||
return 1;
|
||||
839
local/bin/ljrimport/ijournal.pl
Executable file
839
local/bin/ljrimport/ijournal.pl
Executable file
@@ -0,0 +1,839 @@
|
||||
#!/usr/bin/perl -w
|
||||
|
||||
use strict;
|
||||
use Simple; # corrected LJ::Simple
|
||||
use POSIX;
|
||||
use XML::Parser;
|
||||
use Unicode::String;
|
||||
use Unicode::MapUTF8 qw(to_utf8 from_utf8 utf8_supported_charset);
|
||||
|
||||
require "$ENV{'LJHOME'}/cgi-bin/ljlib.pl";
|
||||
require "ljr-defaults.pl";
|
||||
require "ljr-links.pl";
|
||||
require LJR::Distributed;
|
||||
require LJR::unicode;
|
||||
require LWPx::ParanoidAgent;
|
||||
require "ipics.pl";
|
||||
require "$ENV{'LJHOME'}/cgi-bin/ljprotocol.pl";
|
||||
|
||||
my $DEBUG=1;
|
||||
|
||||
# shared variables (between flat and xml mode)
|
||||
my $ru; # remote user
|
||||
my %rfg=(); # remote friend groups
|
||||
my ($ritem_id, $ranum, $rhtml_id); # remote entry ids
|
||||
my $local_u; # local user being imported into
|
||||
my $flags; # ljprotocol.pl flags
|
||||
my $do_overwrite; # overwrite entries
|
||||
|
||||
my $warns;
|
||||
|
||||
# flat mode parameters
|
||||
my $REMOTE_MAX_GET = 50; # livejournal.com lets us download no more than 50 events for a given day
|
||||
|
||||
# XML mode functions and variables
|
||||
my $xmlerrt;
|
||||
my $xmlerr = sub {
|
||||
my $expat = shift;
|
||||
|
||||
my $cstack = "\ncallstack:";
|
||||
my $i = 0;
|
||||
while ( 1 ) {
|
||||
my $tfunc = (caller($i))[3];
|
||||
if ($tfunc && $tfunc ne "") {
|
||||
if ($tfunc !~ /\_\_ANON\_\_/) {
|
||||
$cstack .= " " . $tfunc;
|
||||
}
|
||||
$i = $i + 1;
|
||||
}
|
||||
else {
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
$xmlerrt = join("\n", @_);
|
||||
$xmlerrt .= $cstack;
|
||||
$expat->finish();
|
||||
};
|
||||
|
||||
my $dumptofile = sub {
|
||||
my ($fdata, $filename, $ext) = @_;
|
||||
|
||||
my $t = `date +"%T"`;
|
||||
$t = substr($t, 0, length($t) - 1);
|
||||
open(my $outfile, ">$ENV{'LJHOME'}/logs/" . $filename . "_" . $t . $ext);
|
||||
print $outfile "$fdata";
|
||||
close($outfile);
|
||||
};
|
||||
|
||||
my %xentry = (); # current entry
|
||||
my $ctext = ""; # current field value
|
||||
|
||||
my $root_tags = qr/^(livejournal)$/;
|
||||
my $entry_tag = qr/^(entry)$/;
|
||||
my $entry_data_tag = qr/^(itemid|eventtime|logtime|subject|event|security|allowmask|current_music|current_mood)$/;
|
||||
|
||||
|
||||
# error handling
|
||||
my $err = sub {
|
||||
my %res = ();
|
||||
|
||||
$res{"err"} = 1;
|
||||
$res{"errtext"} = join ("\n", @_);
|
||||
|
||||
if ($warns) {
|
||||
$res{"warns"} = $warns;
|
||||
}
|
||||
|
||||
return \%res;
|
||||
};
|
||||
|
||||
my $warn = sub {
|
||||
print "WARNING: " . join ("\n", @_);
|
||||
print "\n";
|
||||
|
||||
if (!$warns || length($warns) < 255) {
|
||||
$warns .= $warns . join(" ", @_);
|
||||
if (substr($warns, 0, 244) ne $warns) {
|
||||
$warns = substr($warns, 0, 244) + "; and more";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
sub jstatus_print {
|
||||
my $statustr = join("", @_);
|
||||
|
||||
if ($DEBUG) {
|
||||
eval { LJR::Import::import_log($statustr); };
|
||||
|
||||
if ($@) {
|
||||
print $@ . "\n";
|
||||
print $statustr . "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# overwrite entry
|
||||
sub check_overwrite {
|
||||
my ($local_u, $ru_id, $ritem_id, $overwrite) = @_;
|
||||
|
||||
my $r = LJR::Distributed::get_local_itemid ($local_u, $ru_id, $ritem_id. "I");
|
||||
return $err->($r->{"errtext"}) if $r->{"err"};
|
||||
|
||||
if ($r->{"itemid"} && $overwrite eq "1") {
|
||||
my %req = (
|
||||
'username' => $local_u->{'user'},
|
||||
'ownerid' => $local_u->{'user'},
|
||||
'clientversion' => $LJR::LJ_CLIENT,
|
||||
'ver' => $LJ::PROTOCOL_VER,
|
||||
'selecttype' => 'one',
|
||||
'itemid' => $r->{"itemid"},
|
||||
'getmenus' => 0,
|
||||
'lineendings' => "unix",
|
||||
'truncate' => 0,
|
||||
);
|
||||
|
||||
my $err1;
|
||||
my $items = LJ::Protocol::do_request("getevents", \%req, \$err1, $flags);
|
||||
if ($err1) {
|
||||
my $errstr = LJ::Protocol::error_message($err1);
|
||||
return $err->($errstr);
|
||||
}
|
||||
|
||||
my $h = @{$items->{events}}[0];
|
||||
LJ::delete_entry($local_u, $h->{itemid});
|
||||
|
||||
$r = LJR::Distributed::get_local_itemid ($local_u, $ru_id, $ritem_id, "I");
|
||||
return $err->($r->{"errtext"}) if $r->{"err"};
|
||||
}
|
||||
elsif ($r->{"itemid"} && $overwrite eq "0") {
|
||||
return {"continue" => 0};
|
||||
}
|
||||
|
||||
return {"continue" => 1};
|
||||
}
|
||||
|
||||
# XML handlers
|
||||
sub xmlh_entry_start() {
|
||||
my $expat = shift;
|
||||
my @params = @_;
|
||||
|
||||
if ($params[0] =~ /$root_tags/) {
|
||||
# skip valid but meaningless tags
|
||||
}
|
||||
elsif ($params[0] =~ /$entry_tag/) {
|
||||
# we're starting to process new entry
|
||||
shift @params;
|
||||
|
||||
%xentry = ();
|
||||
}
|
||||
elsif ($params[0] =~ /$entry_data_tag/) {
|
||||
$ctext = "";
|
||||
}
|
||||
else {
|
||||
return $xmlerr->($expat,
|
||||
"Unknown XML-structure: " . join (" ", @params),
|
||||
"at line " . $expat->current_line);
|
||||
}
|
||||
}
|
||||
sub xmlh_entry_end() {
|
||||
my $expat = shift;
|
||||
my @params = @_;
|
||||
|
||||
if ($params[0] =~ /$root_tags/) {
|
||||
# almost finished
|
||||
}
|
||||
elsif ($params[0] =~ /$entry_tag/) {
|
||||
my $xe = xml_create_entry(\%xentry);
|
||||
return $xmlerr->($expat, "xml_create_entry: " . $xe->{errtext}) if $xe && $xe->{err};
|
||||
}
|
||||
elsif ($params[0] =~ /$entry_data_tag/) {
|
||||
$xentry{$params[0]} = $ctext;
|
||||
# print $params[0] . " => " . $ctext . "\n";
|
||||
}
|
||||
else {
|
||||
return $xmlerr->($expat,
|
||||
"Unknown tag: " . join (" ", @params),
|
||||
"at line " . $expat->current_line
|
||||
);
|
||||
}
|
||||
}
|
||||
sub xmlh_entry_char() {
|
||||
my $expat = shift;
|
||||
my $tt = join("", @_);
|
||||
$ctext = $ctext . $tt;
|
||||
}
|
||||
|
||||
# should be called after populating shared variables (see section above)
|
||||
sub xml_create_entry {
|
||||
my ($xentry) = @_;
|
||||
|
||||
return $err->("XML import: can't extract remote itemid.") unless $xentry->{"itemid"};
|
||||
$ritem_id = int($xentry->{"itemid"} / 256); # export.bml returns html_id instead of item_id
|
||||
|
||||
my $is_gated = LJR::Distributed::get_local_itemid($local_u, $ru->{'ru_id'}, $ritem_id, "E");
|
||||
return $err->($is_gated->{"errtext"}) if $is_gated->{"err"};
|
||||
return {"err" => 0} if $is_gated->{'itemid'};
|
||||
|
||||
my $r = check_overwrite($local_u, $ru->{'ru_id'}, $ritem_id, $do_overwrite);
|
||||
return $err->($r->{"errtext"}) if $r->{"err"};
|
||||
return unless $r->{"continue"};
|
||||
|
||||
my ($min,$hour,$mday,$mon,$year);
|
||||
|
||||
if ($xentry->{"eventtime"} =~ /(\d\d\d\d)\-(\d\d)\-(\d\d)\ (\d\d)\:(\d\d)/o) {
|
||||
$year = $1;
|
||||
$mon = $2;
|
||||
$mday = $3;
|
||||
$hour = $4;
|
||||
$min = $5;
|
||||
}
|
||||
else {
|
||||
return $err->("XML import: can't extract eventtime. remote itemid = " . $ritem_id);
|
||||
}
|
||||
|
||||
my $moodid;
|
||||
if ($xentry->{"current_mood"}) {
|
||||
$moodid = LJ::mood_id($xentry->{"current_mood"});
|
||||
}
|
||||
|
||||
LJR::Links::make_ljr_hrefs(
|
||||
LJR::Links::get_server_url($ru->{"servername"}, "base"),
|
||||
$ru->{"servername"}, \$xentry->{"event"}
|
||||
);
|
||||
|
||||
# LJR::unicode::utf8ize(\$xentry->{"event"});
|
||||
# LJR::unicode::utf8ize(\$xentry->{"subject"});
|
||||
# LJR::unicode::utf8ize(\$xentry->{"current_mood"});
|
||||
# LJR::unicode::utf8ize(\$xentry->{"current_music"});
|
||||
|
||||
# LJ now exports lj-polls (previously
|
||||
# they exported only links to polls)
|
||||
$xentry->{'event'} =~ s/<lj-poll>.+<\/lj-poll>//sog;
|
||||
|
||||
my %req = (
|
||||
'mode' => 'postevent',
|
||||
'ljr-import' => 1,
|
||||
'ver' => $LJ::PROTOCOL_VER,
|
||||
'clientversion' => $LJR::LJ_CLIENT,
|
||||
'user' => $local_u->{'user'},
|
||||
'username' => $local_u->{'user'},
|
||||
'usejournal' => $local_u->{'user'},
|
||||
'getmenus' => 0,
|
||||
'lineendings' => "unix",
|
||||
'event' => $xentry->{"event"},
|
||||
'subject' => $xentry->{"subject"},
|
||||
'year' => $year,
|
||||
'mon' => $mon,
|
||||
'day' => $mday,
|
||||
'hour' => $hour,
|
||||
'min' => $min,
|
||||
'props' => {
|
||||
'current_moodid' => $moodid,
|
||||
'current_mood' => $xentry->{"current_mood"},
|
||||
'current_music' => $xentry->{"current_music"},
|
||||
'opt_preformatted' => 0,
|
||||
'opt_nocomments' => 0,
|
||||
'taglist' => "",
|
||||
'picture_keyword' => "",
|
||||
'opt_noemail' => 0,
|
||||
'unknown8bit' => 0,
|
||||
'opt_backdated' => 1,
|
||||
},
|
||||
);
|
||||
|
||||
if ($xentry->{"security"} eq "public" || $xentry->{"security"} eq "private") {
|
||||
$req{'security'} = $xentry->{"security"};
|
||||
$req{'allowmask'} = 0;
|
||||
}
|
||||
elsif ($xentry->{"security"} eq "usemask" && $xentry->{"allowmask"} == 1) {
|
||||
$req{'security'} = 'usemask';
|
||||
$req{'allowmask'} = 1;
|
||||
}
|
||||
else {
|
||||
$req{'security'} = 'usemask';
|
||||
|
||||
my @groups = ();
|
||||
foreach my $grp_id (keys %rfg) {
|
||||
if ($xentry->{"allowmask"}+0 & 1 << $grp_id) {
|
||||
push @groups, $rfg{$grp_id}->{name};
|
||||
}
|
||||
}
|
||||
|
||||
my $mask = 0;
|
||||
while (my $grpname = shift @groups) {
|
||||
my $group = LJ::get_friend_group($local_u, {'name' => $grpname});
|
||||
if ($group) {
|
||||
$mask = $mask | (1 << $group->{groupnum});
|
||||
}
|
||||
}
|
||||
$req{'allowmask'} = $mask;
|
||||
}
|
||||
|
||||
my %res = ();
|
||||
LJ::do_request(\%req, \%res, $flags);
|
||||
if ($res{"success"} ne "OK" && $res{"errmsg"} =~ "Missing required argument") {
|
||||
$warn->($res{"errmsg"} . " while processing " . $xentry->{"eventtime"});
|
||||
return;
|
||||
}
|
||||
if ($res{"success"} ne "OK" && $res{"errmsg"} =~ "Post too large") {
|
||||
$dumptofile->($req{'event'}, "large_" . $local_u->{'user'}, ".raw");
|
||||
}
|
||||
|
||||
return $err->($xentry->{"eventtime"} . ": " . $res{"errmsg"}) unless $res{"success"} eq "OK";
|
||||
|
||||
$r = LJR::Distributed::store_remote_itemid(
|
||||
$local_u,
|
||||
$res{"itemid"},
|
||||
$ru->{ru_id},
|
||||
$ritem_id,
|
||||
$xentry->{"itemid"});
|
||||
return $err->($xentry->{"eventtime"} . ": " . $r->{"errtext"}) if $r->{"err"};
|
||||
|
||||
return {"err" => 0};
|
||||
}
|
||||
|
||||
# do the actual import
|
||||
sub import_journal {
|
||||
my (
|
||||
$throttle_speed,
|
||||
$remote_site, $remote_protocol, $remote_user, $remote_pass, $remote_shared_journal,
|
||||
$local_user, $local_shared_journal, $overwrite
|
||||
) = @_;
|
||||
|
||||
$do_overwrite = $overwrite;
|
||||
LJ::disconnect_dbs(); # force reconnection to the database
|
||||
|
||||
if ($remote_shared_journal eq "") {
|
||||
$remote_shared_journal = undef;
|
||||
}
|
||||
if ($local_shared_journal eq "") {
|
||||
$local_shared_journal = undef;
|
||||
}
|
||||
|
||||
my %gdc_hr = ();
|
||||
my %req = ();
|
||||
my %lfg = ();
|
||||
my %res = ();
|
||||
|
||||
if ($remote_protocol ne "flat" && $remote_protocol ne "xml") {
|
||||
return $err->("Unsupported remote protocol $remote_protocol.");
|
||||
}
|
||||
|
||||
$LJ::Simple::network_retries = $LJR::NETWORK_RETRIES;
|
||||
$LJ::Simple::network_sleep = $LJR::NETWORK_SLEEP;
|
||||
$LJ::Simple::LJ_Client = $LJR::LJ_CLIENT;
|
||||
$LJ::Simple::UserAgent = $LJR::USER_AGENT;
|
||||
|
||||
# login to the remote site
|
||||
my $remote_lj = new LJ::Simple ({
|
||||
site => $remote_site,
|
||||
user => $remote_user,
|
||||
pass => $remote_pass,
|
||||
pics => 0,
|
||||
moods => 0,
|
||||
});
|
||||
if (! defined $remote_lj) {
|
||||
return $err->("Can't login to remote site.", $LJ::Simple::error);
|
||||
}
|
||||
|
||||
if (!$remote_lj->GenerateCookie()) {
|
||||
if (!$remote_lj->GenerateCookie()) {
|
||||
return $err->("Can't generate login cookie.", $LJ::Simple::error);
|
||||
}
|
||||
}
|
||||
|
||||
# since we're able to login with supplied credentials --
|
||||
# get and/or cache remote server and remote user ident
|
||||
$ru = LJR::Distributed::get_remote_server($remote_site);
|
||||
return $err->($ru->{"errtext"}) if $ru->{"err"};
|
||||
|
||||
# try to get userid
|
||||
my $idres;
|
||||
my $i1 = 0;
|
||||
while(1) {
|
||||
my $ua = LWPx::ParanoidAgent->new(timeout => 60);
|
||||
$ua->agent($LJR::USER_AGENT);
|
||||
# TODO: parameterize allpics.bml
|
||||
my $url = $ru->{"servername"} . "/users/" . $remote_user . "/info/" ;
|
||||
$idres = $ua->get($url);
|
||||
|
||||
if (!($idres && ($idres->is_success || $idres->code == 403)) && $i1 < $LJR::NETWORK_RETRIES) {
|
||||
my $txt;
|
||||
#foreach my $k (keys %$idres) {
|
||||
# $txt .= $k . "->(" . $idres->{$k} ."), ";
|
||||
#}
|
||||
###_content->(500 DNS lookup timeout), _rc->(500), _headers->(HTTP::Headers=HASH(0x2d2ec70)), _msg->(DNS lookup timeout), _request->(HTTP::Request=HASH(0x2c61ac0)),
|
||||
|
||||
$txt .= "_msg->" . $idres->{'_msg'} . ", ";
|
||||
foreach my $k (keys %{$idres->{'_headers'}}) {
|
||||
$txt .= "\n" . $k . ": " . $idres->{'_headers'}->{$k} ;
|
||||
}
|
||||
print STDERR "*** $url $txt\n";
|
||||
|
||||
LJR::NETWORK_SLEEP(); $i1++; next;
|
||||
}
|
||||
else { last; }
|
||||
}
|
||||
|
||||
if (!($idres && ($idres->is_success || $idres->code == 403))) {
|
||||
return $err->("LWPx: Can't get remote user id: $remote_user\n");
|
||||
}
|
||||
if ($idres->content && $idres->content =~ /\<b\>$remote_user\<\/b\>\<\/a\>\ \((\d+)\)/s) {
|
||||
$ru->{"userid"} = $1;
|
||||
}
|
||||
|
||||
$ru->{"username"} = $remote_user;
|
||||
$ru = LJR::Distributed::get_cached_user($ru); # populates $ru->{ru_id}
|
||||
return $err->($ru->{"errtext"}) if $ru->{"err"};
|
||||
|
||||
# get local user object for user being imported into
|
||||
$local_u = LJ::load_user($local_user, 1);
|
||||
return $err->("Can't load local user $local_user.") unless $local_u;
|
||||
|
||||
$ru = LJR::Distributed::remote_local_assoc($ru, $local_u);
|
||||
return $err->("error while getting remote-local association: " . $ru->{errtext})
|
||||
if $ru->{err};
|
||||
|
||||
jstatus_print ("getting userpics");
|
||||
my $e = import_pics(
|
||||
$ru->{servername},
|
||||
$ru->{username},
|
||||
$remote_pass,
|
||||
$local_user,
|
||||
"", 0);
|
||||
return $err->("Can't import " . $ru->{username} . ": " . $e->{errtext})
|
||||
if $e->{err};
|
||||
|
||||
# clear duplicate protection
|
||||
LJ::set_userprop($local_u, "dupsig_post", undef);
|
||||
|
||||
# needed everywhere
|
||||
$flags = {
|
||||
'u' => $local_u,
|
||||
'noauth' => 1,
|
||||
'BMAX_EVENT' => 150000,
|
||||
'CMAX_EVENT' => 150000,
|
||||
'no-cache' => 1,
|
||||
'omit_underscore_check' => 1,
|
||||
};
|
||||
|
||||
%req = ( 'mode' => 'login',
|
||||
'ver' => $LJ::PROTOCOL_VER,
|
||||
'clientversion' => $LJR::LJ_CLIENT,
|
||||
'user' => $local_u->{'user'},
|
||||
'getmenus' => 0,
|
||||
);
|
||||
%res = ();
|
||||
LJ::do_request(\%req, \%res, $flags);
|
||||
return $err->($res{'errmsg'}) unless $res{'success'} eq 'OK';
|
||||
|
||||
jstatus_print ("getting friend groups");
|
||||
|
||||
# get remote and local friend groups, mix them up, update on local server
|
||||
if (! defined $remote_lj->GetFriendGroups(\%rfg)) {
|
||||
return $err->("Failed to get groups on the remote site.", $LJ::Simple::error);
|
||||
}
|
||||
|
||||
LJ::Protocol::do_request(
|
||||
{
|
||||
'mode' => 'getfriendgroups',
|
||||
'user' => $local_u->{'user'},
|
||||
'ver' => $LJ::PROTOCOL_VER,
|
||||
'clientversion' => $LJR::LJ_CLIENT,
|
||||
'includegroups' => 1,
|
||||
'getmenus' => 0,
|
||||
},
|
||||
\%res,
|
||||
$flags
|
||||
);
|
||||
if (! $res{'success'} eq "OK") {
|
||||
return $err->("Unable to get local user" . $local_u->{'user'} . "groups",
|
||||
$res{'success'} . ":" . $res{'errmsg'});
|
||||
}
|
||||
|
||||
# convert it to LJ::Simple hash
|
||||
while((my $k, my $v) = each %res) {
|
||||
$k=~/^frgrp_([0-9]+)_(.*)$/o || next;
|
||||
my ($id, $name) = ($1, $2);
|
||||
if (!exists $lfg{$id}) {
|
||||
$lfg{$id}={
|
||||
id => $id,
|
||||
public => 0,
|
||||
};
|
||||
}
|
||||
($name eq "sortorder") && ($name="sort");
|
||||
$lfg{$id}->{$name}=$v;
|
||||
}
|
||||
|
||||
# add nonexisting remote groups (identified by name) to local server
|
||||
foreach my $grp_id (keys %rfg) {
|
||||
my $e = 0;
|
||||
foreach my $lg (values %lfg) {
|
||||
if ($lg->{name} eq $rfg{$grp_id}->{name}) {
|
||||
$e = 1;
|
||||
}
|
||||
if ($lg->{name} =~ /default view/i) {
|
||||
$e = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$e) {
|
||||
my $egroup = 1;
|
||||
foreach my $cgroup (sort { $a <=> $b } keys %lfg) {
|
||||
if ($egroup == $cgroup) {
|
||||
$egroup++;
|
||||
}
|
||||
}
|
||||
if ($egroup < 31) {
|
||||
$lfg{$egroup} = $rfg{$grp_id};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# create local friend groups (existing + copied)
|
||||
my $i = 0;
|
||||
%req = (
|
||||
'mode' => "editfriendgroups",
|
||||
'user' => $local_u->{'user'},
|
||||
'clientversion' => $LJR::LJ_CLIENT,
|
||||
'ver' => $LJ::PROTOCOL_VER,
|
||||
);
|
||||
|
||||
# convert LJ::Simple hash back to ljprotocol hash
|
||||
foreach my $grpid (keys %lfg) {
|
||||
if ($grpid > 0 && $grpid < 31) {
|
||||
|
||||
my $pname = "efg_set_" . $grpid . "_name";
|
||||
$req{$pname} = $lfg{$grpid}->{name};
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
|
||||
# do the actual request
|
||||
LJ::do_request(\%req, \%res, $flags);
|
||||
if (! $res{'success'} eq "OK") {
|
||||
return $err->(
|
||||
"Unable to update local user" . $local_u->{'user'} . "groups",
|
||||
$res{'success'} . ":" . $res{'errmsg'}
|
||||
);
|
||||
}
|
||||
|
||||
# get remote days with entries
|
||||
if (! defined $remote_lj->GetDayCounts(\%gdc_hr, undef)) {
|
||||
return $err->("can't get day counts: ", $LJ::Simple::error);
|
||||
}
|
||||
|
||||
# import entries by means of export.bml (XML format)
|
||||
if ($remote_protocol eq "xml") {
|
||||
my $mydc = {};
|
||||
|
||||
foreach (sort {$a<=>$b} keys %gdc_hr) {
|
||||
my $timestamp = $_;
|
||||
|
||||
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
|
||||
localtime($timestamp);
|
||||
|
||||
$mon++;
|
||||
$year = $year + 1900;
|
||||
|
||||
$mydc->{$year}->{$mon} = 0;
|
||||
$mydc->{$year}->{$mon} = $mydc->{$year}->{$mon} + $gdc_hr{$timestamp};
|
||||
}
|
||||
|
||||
foreach (sort {$a <=> $b} keys %{$mydc}) {
|
||||
my $y = $_;
|
||||
|
||||
foreach (sort {$a <=> $b} keys %{$mydc->{$y}}) {
|
||||
jstatus_print ("getting XML data and creating local entries for " . $_ . "/" . $y);
|
||||
|
||||
my $do_login = 0;
|
||||
|
||||
while (1) {
|
||||
if ($do_login) {
|
||||
$remote_lj = new LJ::Simple ({
|
||||
site => $remote_site,
|
||||
user => $remote_user,
|
||||
pass => $remote_pass,
|
||||
pics => 0,
|
||||
moods => 0,
|
||||
});
|
||||
if (! defined $remote_lj) {
|
||||
return $err->("Can't login to remote site.", $LJ::Simple::error);
|
||||
}
|
||||
if (!$remote_lj->GenerateCookie()) {
|
||||
if (!$remote_lj->GenerateCookie()) {
|
||||
return $err->("Can't generate login cookie.", $LJ::Simple::error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
my $res = $remote_lj->GetRawData({
|
||||
"url" => "/export_do.bml",
|
||||
"post-data" => {
|
||||
"authas" => $remote_user, # "nit",
|
||||
"format" => "xml",
|
||||
"encid" => 2, # utf-8; for full listing see htdocs/export.bml
|
||||
"header" => 1,
|
||||
"year" => $y,
|
||||
"month" => $_,
|
||||
"field_itemid" => 1,
|
||||
"field_eventtime" => 1,
|
||||
"field_logtime" => 1,
|
||||
"field_subject" => 1,
|
||||
"field_event" => 1,
|
||||
"field_security" => 1,
|
||||
"field_allowmask" => 1,
|
||||
"field_currents" => 1,
|
||||
}});
|
||||
|
||||
if ($res && $res->{content}) {
|
||||
my $xdata = $res->{content};
|
||||
LJR::unicode::force_utf8(\$xdata);
|
||||
|
||||
my $p1 = new XML::Parser (
|
||||
Handlers => {
|
||||
Start => \&xmlh_entry_start,
|
||||
End => \&xmlh_entry_end,
|
||||
Char => \&xmlh_entry_char
|
||||
});
|
||||
|
||||
eval { $p1->parse($xdata); };
|
||||
if ($@) {
|
||||
if ($i < $LJR::NETWORK_RETRIES) {
|
||||
if ($@ =~ /not\ well\-formed\ \(invalid\ token\)/) {
|
||||
# $xdata <?xml version="1.0" encoding='windows-1251'?>
|
||||
}
|
||||
|
||||
if ($xdata =~ /Login Required/) {
|
||||
$do_login = 1;
|
||||
}
|
||||
|
||||
LJR::NETWORK_SLEEP(); $i++; next;
|
||||
}
|
||||
else {
|
||||
$dumptofile->($xdata, "err_" . $remote_user, ".xml");
|
||||
return $err->("Runtime error while parsing XML data: ", $@);
|
||||
}
|
||||
}
|
||||
|
||||
if ($xmlerrt) {
|
||||
$dumptofile->($xdata, "err_" . $remote_user, ".xml");
|
||||
return $err->("Error while parsing XML data: ", $xmlerrt);
|
||||
}
|
||||
|
||||
last;
|
||||
}
|
||||
else {
|
||||
return $err->("Can't get XML data..");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# import entries by means of flat protocol
|
||||
if ($remote_protocol eq "flat") {
|
||||
# process them, day by day, sleeping a little
|
||||
foreach (sort {$a<=>$b} keys %gdc_hr) {
|
||||
my $timestamp = $_;
|
||||
|
||||
# download all the entries for a day
|
||||
if ($gdc_hr{$timestamp} < $REMOTE_MAX_GET) {
|
||||
jstatus_print (
|
||||
"getting remote and creating local entries for " .
|
||||
strftime ("%a %b %e %Y", localtime($timestamp))
|
||||
);
|
||||
|
||||
my %r_entries=(); # remote entries
|
||||
|
||||
if (! defined $remote_lj->GetEntries(\%r_entries,$remote_shared_journal,"day",($timestamp))) {
|
||||
if ($LJ::Simple::error =~ "Cannot display this post") {
|
||||
$warn->(strftime ("%a %b %e %Y", localtime($timestamp)) . ":" . $LJ::Simple::error);
|
||||
next;
|
||||
}
|
||||
return $err->("can't get remote entries: " . strftime ("%a %b %e %Y", localtime($timestamp)) . ": ",
|
||||
$LJ::Simple::error);
|
||||
}
|
||||
|
||||
my $rkey=undef;
|
||||
my $rentry=undef;
|
||||
my $r;
|
||||
|
||||
ENTRIES: while (($rkey, $rentry) = each(%r_entries)) {
|
||||
($ritem_id, $ranum, $rhtml_id) = $remote_lj->GetItemId($rentry);
|
||||
my $tevent = $remote_lj->GetEntry($rentry);
|
||||
|
||||
my $is_gated = LJR::Distributed::get_local_itemid($local_u, $ru->{'ru_id'}, $ritem_id, "E");
|
||||
return $err->($is_gated->{"errtext"}) if $is_gated->{"err"};
|
||||
next ENTRIES if $is_gated->{'itemid'};
|
||||
|
||||
$r = check_overwrite($local_u, $ru->{'ru_id'}, $ritem_id, $do_overwrite);
|
||||
return $err->($r->{"errtext"}) if $r->{"err"};
|
||||
|
||||
next ENTRIES unless $r->{"continue"};
|
||||
|
||||
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
|
||||
localtime($remote_lj->GetDate($rentry));
|
||||
|
||||
$mon++;
|
||||
$year = $year + 1900;
|
||||
|
||||
LJR::Links::make_ljr_hrefs(
|
||||
LJR::Links::get_server_url($ru->{"servername"}, "base"),
|
||||
$ru->{"servername"},
|
||||
\$tevent
|
||||
);
|
||||
|
||||
my $tsubject = $remote_lj->GetSubject($rentry);
|
||||
my $tcurrent_mood = $remote_lj->Getprop_current_mood($rentry);
|
||||
my $tcurrent_music = $remote_lj->Getprop_current_music($rentry);
|
||||
my $ttaglist = $remote_lj->Getprop_taglist($rentry);
|
||||
$ttaglist = LJ::trim($ttaglist);
|
||||
|
||||
my $tpicture_keyword = $remote_lj->Getprop_picture_keyword($rentry);
|
||||
|
||||
# LJR::unicode::utf8ize(\$tevent);
|
||||
# LJR::unicode::utf8ize(\$tsubject);
|
||||
# LJR::unicode::utf8ize(\$tcurrent_mood);
|
||||
# LJR::unicode::utf8ize(\$tcurrent_music);
|
||||
# LJR::unicode::utf8ize(\$ttaglist);
|
||||
# LJR::unicode::utf8ize(\$tpicture_keyword);
|
||||
|
||||
%req = ( 'mode' => 'postevent',
|
||||
'ljr-import' => 1,
|
||||
'ver' => $LJ::PROTOCOL_VER,
|
||||
'clientversion' => $LJR::LJ_CLIENT,
|
||||
'user' => $local_u->{'user'},
|
||||
'username' => $local_u->{'user'},
|
||||
'usejournal' => $local_u->{'user'},
|
||||
'getmenus' => 0,
|
||||
'lineendings' => "unix",
|
||||
'event' => $tevent,
|
||||
'subject' => $tsubject,
|
||||
'year' => $year,
|
||||
'mon' => $mon,
|
||||
'day' => $mday,
|
||||
'hour' => $hour,
|
||||
'min' => $min,
|
||||
'props' => {
|
||||
'current_moodid' => $rentry->{prop_current_moodid},
|
||||
'current_mood' => $tcurrent_mood,
|
||||
'current_music' => $tcurrent_music,
|
||||
'opt_preformatted' => $remote_lj->Getprop_preformatted($rentry),
|
||||
'opt_nocomments' => $remote_lj->Getprop_nocomments($rentry),
|
||||
'taglist' => $ttaglist,
|
||||
'picture_keyword' => $tpicture_keyword,
|
||||
'opt_noemail' => $remote_lj->Getprop_noemail($rentry),
|
||||
'unknown8bit' => $remote_lj->Getprop_unknown8bit($rentry),
|
||||
'opt_backdated' => 1,
|
||||
},
|
||||
);
|
||||
|
||||
my @r_protection = $remote_lj->GetProtect($rentry);
|
||||
if ($r_protection[0] eq "public" || $r_protection[0] eq "private") {
|
||||
$req{'security'} = $r_protection[0];
|
||||
$req{'allowmask'} = 0;
|
||||
}
|
||||
elsif ($r_protection[0] eq "friends") {
|
||||
$req{'security'} = 'usemask';
|
||||
$req{'allowmask'} = 1;
|
||||
}
|
||||
elsif ($r_protection[0] eq "groups") {
|
||||
$req{'security'} = 'usemask';
|
||||
shift @r_protection;
|
||||
|
||||
my $mask=0;
|
||||
while (my $grpname = shift @r_protection) {
|
||||
my $group = LJ::get_friend_group($local_u, {'name' => $grpname});
|
||||
$mask = $mask | (1 << $group->{groupnum});
|
||||
}
|
||||
$req{'allowmask'} = $mask;
|
||||
}
|
||||
|
||||
%res = ();
|
||||
LJ::do_request(\%req, \%res, $flags);
|
||||
if ($res{"success"} ne "OK" && $res{"errmsg"} =~ "Post too large") {
|
||||
$dumptofile->($req{'event'}, "large_" . $local_u->{'user'}, ".raw");
|
||||
}
|
||||
if ($res{"success"} ne "OK" && $res{"errmsg"} =~ "Invalid text encoding") {
|
||||
$warn->($res{"errmsg"});
|
||||
next;
|
||||
}
|
||||
|
||||
if ($res{"success"} ne "OK" && $res{"errmsg"} =~ "Invalid or malformed tag list") {
|
||||
return $err->($res{"errmsg"} . ": [$ttaglist]");
|
||||
}
|
||||
|
||||
return $err->($res{'errmsg'}) unless $res{'success'} eq 'OK';
|
||||
|
||||
$r = LJR::Distributed::store_remote_itemid(
|
||||
$local_u,
|
||||
$res{"itemid"},
|
||||
$ru->{ru_id},
|
||||
$ritem_id,
|
||||
$rhtml_id);
|
||||
return $err->($r->{"errtext"}) if $r->{"err"};
|
||||
}
|
||||
|
||||
sleep($throttle_speed);
|
||||
}
|
||||
else {
|
||||
$warn->("Too much entries for a day. " . $local_u->{'user'} . " " .
|
||||
strftime ("%a %b %e %Y", localtime($timestamp))
|
||||
);
|
||||
}
|
||||
} # process them day by day
|
||||
}
|
||||
|
||||
if ($warns) {
|
||||
my %warns = ('warns' => $warns);
|
||||
return \%warns;
|
||||
}
|
||||
else {
|
||||
return undef;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return 1;
|
||||
533
local/bin/ljrimport/ipics.pl
Executable file
533
local/bin/ljrimport/ipics.pl
Executable file
@@ -0,0 +1,533 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
use Image::Size ();
|
||||
use Simple; # corrected LJ::Simple
|
||||
require "$ENV{'LJHOME'}/cgi-bin/ljlib.pl";
|
||||
require "ljr-defaults.pl";
|
||||
require "ljr-links.pl";
|
||||
require LJR::Distributed;
|
||||
require LWPx::ParanoidAgent;
|
||||
|
||||
# error handling
|
||||
my $err = sub {
|
||||
my %res = ();
|
||||
|
||||
my $cstack = "\ncallstack:";
|
||||
my $i = 0;
|
||||
while ( 1 ) {
|
||||
my $tfunc = (caller($i))[3];
|
||||
if ($tfunc && $tfunc ne "") {
|
||||
if ($tfunc !~ /\_\_ANON\_\_/) {
|
||||
$cstack .= " " . $tfunc;
|
||||
}
|
||||
$i = $i + 1;
|
||||
}
|
||||
else {
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
$res{"err"} = 1;
|
||||
$res{"errtext"} = join ("\n", @_);
|
||||
$res{"errtext"} .= $cstack;
|
||||
|
||||
return \%res;
|
||||
};
|
||||
|
||||
# example:
|
||||
my $DEBUG = 0;
|
||||
|
||||
sub cache_remote_pics {
|
||||
my ($remote_site, $remote_user, $remote_pass, $local_userid) = @_;
|
||||
my $ua;
|
||||
my $res;
|
||||
my %remote_urls = ();
|
||||
my %remote_keywords = ();
|
||||
my %remote_comments = ();
|
||||
my $default_pic = "";
|
||||
|
||||
my $i = 0;
|
||||
my $content;
|
||||
|
||||
# get remote pictures list with keywords
|
||||
if ($remote_pass ne "") {
|
||||
$LJ::Simple::network_retries = $LJR::NETWORK_RETRIES;
|
||||
$LJ::Simple::network_sleep = $LJR::NETWORK_SLEEP;
|
||||
$LJ::Simple::LJ_Client = $LJR::LJ_CLIENT;
|
||||
$LJ::Simple::UserAgent = $LJR::USER_AGENT;
|
||||
|
||||
my $ljs_site = $remote_site;
|
||||
if ($ljs_site =~ /^http\:\/\/(.*)/) {
|
||||
$ljs_site = $1;
|
||||
}
|
||||
|
||||
my $remote_lj = new LJ::Simple ({
|
||||
site => $ljs_site,
|
||||
user => $remote_user,
|
||||
pass => $remote_pass,
|
||||
pics => 0,
|
||||
moods => 0,
|
||||
});
|
||||
return $err->("Can't login to remote site.", $LJ::Simple::error)
|
||||
unless defined($remote_lj);
|
||||
|
||||
if (!$remote_lj->GenerateCookie()) {
|
||||
return $err->("Can't generate login cookie.", $LJ::Simple::error);
|
||||
}
|
||||
|
||||
$res = $remote_lj->GetRawData({
|
||||
"url" => "/allpics.bml",
|
||||
});
|
||||
if (!($res && $res->{content})) {
|
||||
return $err->("LJ::Simple: Can't get remote user pictures: $remote_user\n");
|
||||
}
|
||||
|
||||
$content = $res->{content};
|
||||
}
|
||||
else {
|
||||
while(1) {
|
||||
$ua = LWPx::ParanoidAgent->new(timeout => 60);
|
||||
$ua->agent($LJR::USER_AGENT);
|
||||
# TODO: parameterize allpics.bml
|
||||
$res = $ua->get($remote_site . "/allpics.bml?user=" . $remote_user);
|
||||
|
||||
if (!($res && $res->is_success) && $i < $LJR::NETWORK_RETRIES) {
|
||||
LJR::NETWORK_SLEEP(); $i++; next;
|
||||
}
|
||||
else {
|
||||
last;
|
||||
}
|
||||
}
|
||||
if (!($res && $res->is_success)) {
|
||||
return $err->("LWPx: Can't get remote user pictures: $remote_user\n");
|
||||
}
|
||||
|
||||
$content = $res->content;
|
||||
}
|
||||
|
||||
my $ru = LJR::Distributed::get_remote_server($remote_site);
|
||||
return $err->($ru->{"errtext"}) if $ru->{"err"};
|
||||
|
||||
$ru->{username} = $remote_user;
|
||||
$ru = LJR::Distributed::get_cached_user($ru);
|
||||
|
||||
$i = 0;
|
||||
|
||||
my $dbh = LJ::get_db_writer();
|
||||
return $err->("Can't get database writer!") unless $dbh;
|
||||
|
||||
$dbh->do("DELETE FROM ljr_cached_userpics WHERE ru_id=?", undef, $ru->{ru_id});
|
||||
return $err->($dbh->errstr) if $dbh->err;
|
||||
|
||||
my $iru;
|
||||
my $userpic_base = LJR::Links::get_server_url($remote_site, "userpic_base");
|
||||
|
||||
# extract pic urls and keywords
|
||||
|
||||
if ($content =~ m!<\s*?body.*?>(.+)</body>!si) {
|
||||
$content = $1;
|
||||
|
||||
while ($content =~
|
||||
/\G.*?($userpic_base\/(\d+)\/(\d+))(.*?)($userpic_base\/(\d+)\/(\d+)|$)(.*)/sg
|
||||
) {
|
||||
my $picurl = $1;
|
||||
my $props = $4;
|
||||
my $cuserid = $3;
|
||||
my $cpicid = $2;
|
||||
$content = $5 . $8;
|
||||
|
||||
my $is_default = 0;
|
||||
|
||||
# save userid
|
||||
if (!$iru->{ru_id}) {
|
||||
$iru = LJR::Distributed::get_remote_server($remote_site);
|
||||
return $err->($ru->{"errtext"}) if $ru->{"err"};
|
||||
|
||||
$iru->{username} = $remote_user;
|
||||
$iru->{userid} = $cuserid;
|
||||
|
||||
$iru = LJR::Distributed::get_cached_user($iru);
|
||||
return $err->($ru->{"errtext"}) if $ru->{"err"};
|
||||
}
|
||||
|
||||
if ($props =~ /(.*?)Keywords\:\<\/b\>\ (.*?)\<br\ \/\>(.*?)\<\/td\>/s) {
|
||||
$remote_keywords{$picurl} = $2;
|
||||
$remote_comments{$picurl} = $3;
|
||||
$remote_comments{$picurl} =~ s/^\s+|\s+$//;
|
||||
}
|
||||
if ($props =~ /\<u\>Default\<\/u\>/s) {
|
||||
$default_pic = $picurl;
|
||||
$is_default = 1;
|
||||
}
|
||||
|
||||
my @keywords = "";
|
||||
if ($remote_keywords{$picurl}) {
|
||||
@keywords = split(/\s*,\s*/, $remote_keywords{$picurl});
|
||||
@keywords = grep { s/^\s+//; s/\s+$//; $_; } @keywords;
|
||||
}
|
||||
elsif ($is_default) {
|
||||
@keywords = ("");
|
||||
}
|
||||
|
||||
foreach my $kw (@keywords) {
|
||||
if($remote_urls{$cpicid}) {
|
||||
$dbh->do("UPDATE ljr_cached_userpics set keyword=?, is_default=?, comments=?
|
||||
where ru_id=? and remote_picid=?",
|
||||
undef, $kw, $is_default, $remote_comments{$picurl},
|
||||
$ru->{ru_id}, $cpicid);
|
||||
return $err->($dbh->errstr) if $dbh->err;
|
||||
}
|
||||
else {
|
||||
$dbh->do("INSERT INTO ljr_cached_userpics VALUES (?,?,?,?,?)",
|
||||
undef, $ru->{ru_id}, $cpicid, $kw,
|
||||
$is_default, $remote_comments{$picurl});
|
||||
return $err->($dbh->errstr) if $dbh->err;
|
||||
}
|
||||
}
|
||||
$remote_urls{$cpicid} = $picurl;
|
||||
}
|
||||
}
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub import_pics {
|
||||
my (
|
||||
$remote_site, $remote_user, $remote_pass,
|
||||
$local_user, $o_keyword, $o_default
|
||||
) = @_;
|
||||
|
||||
my $MAX_UPLOAD = 40960;
|
||||
|
||||
my %remote_ids = ();
|
||||
my %remote_urls = ();
|
||||
my %remote_keywords = ();
|
||||
my %remote_comments = ();
|
||||
my $default_pic = "";
|
||||
|
||||
my $ru = LJR::Distributed::get_remote_server($remote_site);
|
||||
return $err->($ru->{"errtext"}) if $ru->{"err"};
|
||||
|
||||
$ru->{username} = $remote_user;
|
||||
$ru = LJR::Distributed::get_cached_user($ru);
|
||||
|
||||
# load user object (force, otherwise get error outside of apache)
|
||||
my $u = LJ::load_user($local_user, 1);
|
||||
return $err->("Invalid local user: " . $local_user) unless $u;
|
||||
|
||||
# prepare database connections (for different versions of user objects)
|
||||
my ($dbcm, $dbcr, $sth);
|
||||
$dbcm = LJ::get_cluster_master($u);
|
||||
return $err->("Can't get cluster master!") unless $dbcm;
|
||||
$dbcr = LJ::get_cluster_def_reader($u);
|
||||
return $err->("Can't get cluster reader!") unless $dbcr;
|
||||
my $dbh = LJ::get_db_writer();
|
||||
return $err->("Can't get database writer!") unless $dbh;
|
||||
my $dbr = LJ::get_db_reader();
|
||||
return $err->("Can't get database reader!") unless $dbr;
|
||||
|
||||
my $e;
|
||||
|
||||
if (!$o_keyword && !$o_default) {
|
||||
$e = cache_remote_pics($remote_site, $remote_user, $remote_pass, $u->{userid});
|
||||
return $e if $e->{err};
|
||||
}
|
||||
else {
|
||||
$sth = $dbr->prepare(
|
||||
"SELECT ru_id FROM ljr_cached_userpics WHERE ru_id=? GROUP BY ru_id");
|
||||
$sth->execute($ru->{ru_id});
|
||||
my $ruid = $sth->fetchrow_hashref;
|
||||
$sth->finish;
|
||||
|
||||
if (!$ruid) {
|
||||
$e = cache_remote_pics($remote_site, $remote_user, $remote_pass, $u->{userid});
|
||||
return $e if $e->{err};
|
||||
}
|
||||
}
|
||||
|
||||
# get ru->{userid} which should come up after caching remote pic props
|
||||
$ru = LJR::Distributed::get_cached_user($ru);
|
||||
|
||||
if ($o_keyword) {
|
||||
$sth = $dbr->prepare(
|
||||
"SELECT remote_picid, keyword, is_default, comments " .
|
||||
"FROM ljr_cached_userpics WHERE ru_id=? and keyword=?");
|
||||
$sth->execute($ru->{ru_id}, $o_keyword);
|
||||
}
|
||||
elsif ($o_default) {
|
||||
$sth = $dbr->prepare(
|
||||
"SELECT remote_picid, keyword, is_default, comments " .
|
||||
"FROM ljr_cached_userpics WHERE ru_id=? and is_default=1");
|
||||
$sth->execute($ru->{ru_id});
|
||||
}
|
||||
else {
|
||||
$sth = $dbr->prepare(
|
||||
"SELECT remote_picid, keyword, is_default, comments " .
|
||||
"FROM ljr_cached_userpics WHERE ru_id=?");
|
||||
$sth->execute($ru->{ru_id});
|
||||
}
|
||||
|
||||
my $i = 0;
|
||||
while (my $rpic = $sth->fetchrow_hashref) {
|
||||
my $picurl = $remote_site . "/userpic/" . $rpic->{remote_picid} . "/" . $ru->{userid};
|
||||
|
||||
$remote_ids{$i} = $rpic->{remote_picid};
|
||||
$remote_urls{$rpic->{remote_picid}} = $picurl;
|
||||
|
||||
$remote_comments{$picurl} = $rpic->{comments};
|
||||
$remote_keywords{$picurl} =
|
||||
(($remote_keywords{$picurl}) ? $remote_keywords{$picurl} . "," : "") .
|
||||
$rpic->{keyword};
|
||||
|
||||
if ($rpic->{is_default}) {
|
||||
$default_pic = $picurl;
|
||||
}
|
||||
|
||||
print
|
||||
$picurl . ":" .
|
||||
$remote_ids{$i} . ":" .
|
||||
$remote_comments{$picurl} . ":" .
|
||||
$remote_keywords{$picurl} . "\n"
|
||||
if $DEBUG;
|
||||
|
||||
$i++;
|
||||
}
|
||||
$sth->finish;
|
||||
|
||||
RPICID: foreach my $rpicid (sort {$a <=> $b} values %remote_ids) {
|
||||
my $local_picid = $dbr->selectrow_array(
|
||||
"SELECT local_picid FROM ljr_remote_userpics " .
|
||||
"WHERE ru_id=? and remote_picid=? and local_userid = ?",
|
||||
undef, $ru->{ru_id}, $rpicid, $u->{userid});
|
||||
|
||||
if ($local_picid) {
|
||||
my $r_picid = $dbr->selectrow_array(
|
||||
"SELECT picid FROM userpic2 WHERE picid=?",
|
||||
undef, $local_picid);
|
||||
|
||||
if (!$r_picid) {
|
||||
$u->do("DELETE FROM ljr_remote_userpics WHERE local_picid=?", undef, $local_picid);
|
||||
$local_picid = undef;
|
||||
}
|
||||
else {
|
||||
next RPICID;
|
||||
}
|
||||
}
|
||||
|
||||
my %POST = ();
|
||||
|
||||
$POST{urlpic} = $remote_urls{$rpicid};
|
||||
$POST{keywords} = $remote_keywords{$remote_urls{$rpicid}};
|
||||
$POST{comments} = $remote_comments{$remote_urls{$rpicid}};
|
||||
$POST{url} = "";
|
||||
if ($default_pic eq $remote_urls{$rpicid}) {
|
||||
$POST{make_default} = 1;
|
||||
}
|
||||
|
||||
# get remote picture and validate it
|
||||
my $ua;
|
||||
my $res;
|
||||
my ($sx, $sy, $filetype);
|
||||
|
||||
$i = 0;
|
||||
while(1) {
|
||||
$ua = LWPx::ParanoidAgent->new(
|
||||
timeout => 60,
|
||||
max_size => $MAX_UPLOAD + 1024);
|
||||
$ua->agent($LJR::USER_AGENT);
|
||||
$res = $ua->get($POST{urlpic});
|
||||
|
||||
# if the picture doesn't exist on the remote server
|
||||
# then we get 404 http error and remove it from our cache
|
||||
if ($res &&
|
||||
($res->{"_rc"} eq 404 || $res->{"_rc"} eq 503)
|
||||
) {
|
||||
$dbh->do("DELETE FROM ljr_cached_userpics WHERE ru_id=? and remote_picid=?",
|
||||
undef, $ru->{ru_id}, $rpicid);
|
||||
return $err->($dbh->errstr) if $dbh->err;
|
||||
|
||||
next RPICID;
|
||||
}
|
||||
|
||||
$POST{userpic} = $res->content if $res && $res->is_success;
|
||||
|
||||
($sx, $sy, $filetype) = Image::Size::imgsize(\$POST{'userpic'});
|
||||
|
||||
if (!(
|
||||
$res && $res->is_success && defined($sx) &&
|
||||
length($POST{'userpic'}) <= $MAX_UPLOAD &&
|
||||
($filetype eq "GIF" || $filetype eq "JPG" || $filetype eq "PNG") &&
|
||||
$sx <= 100 && $sy <= 100
|
||||
) &&
|
||||
$i < $LJR::NETWORK_RETRIES) {
|
||||
LJR::NETWORK_SLEEP(); $i++; next;
|
||||
}
|
||||
else {
|
||||
last;
|
||||
}
|
||||
}
|
||||
if (!($res && $res->is_success)) {
|
||||
return $err->("Can't get remote user picture: ",
|
||||
$remote_user, $local_user, $o_keyword, $o_default, $POST{urlpic},
|
||||
$res->status_line);
|
||||
}
|
||||
if (!defined $sx) {
|
||||
print ("Invalid image: " . $POST{urlpic} . "\n");
|
||||
next RPICID;
|
||||
}
|
||||
|
||||
if (length($POST{'userpic'}) > $MAX_UPLOAD) {
|
||||
return $err->("Picture " . $POST{urlpic} . "is too large");
|
||||
}
|
||||
|
||||
return $err->("Unsupported filetype: " . $POST{urlpic})
|
||||
unless ($filetype eq "GIF" || $filetype eq "JPG" || $filetype eq "PNG");
|
||||
return $err->("Image too large: " . $POST{urlpic}) if ($sx > 150 || $sy > 150);
|
||||
|
||||
my $base64 = Digest::MD5::md5_base64($POST{'userpic'});
|
||||
|
||||
# see if it's a duplicate
|
||||
my $picid;
|
||||
my $contenttype;
|
||||
if ($filetype eq "GIF") { $contenttype = 'G'; }
|
||||
elsif ($filetype eq "PNG") { $contenttype = 'P'; }
|
||||
elsif ($filetype eq "JPG") { $contenttype = 'J'; }
|
||||
|
||||
$picid = $dbcr->selectrow_array(
|
||||
"SELECT picid FROM userpic2 WHERE userid=? AND fmt=? AND md5base64=?",
|
||||
undef, $u->{'userid'}, $contenttype, $base64);
|
||||
$picid = 0 unless defined($picid);
|
||||
|
||||
print "trying to insert into db\n" if $DEBUG;
|
||||
|
||||
# if picture isn't a duplicate, insert it
|
||||
if ($picid == 0) {
|
||||
|
||||
# Make a new global picid
|
||||
$picid = LJ::alloc_global_counter('P') or
|
||||
return $err->('Unable to allocate new picture id');
|
||||
|
||||
$u->do(
|
||||
"INSERT INTO userpic2 (picid, userid, fmt, width, height, " .
|
||||
"picdate, md5base64, location, state) " .
|
||||
"VALUES (?, ?, ?, ?, ?, NOW(), ?, ?, 'N')",
|
||||
undef, $picid, $u->{'userid'}, $contenttype, $sx, $sy, $base64, undef);
|
||||
return $err->($u->errstr) if $u->err;
|
||||
|
||||
my $clean_err = sub {
|
||||
if ($picid) {
|
||||
$u->do(
|
||||
"DELETE FROM userpic2 WHERE userid=? AND picid=?",
|
||||
undef, $u->{'userid'}, $picid);
|
||||
|
||||
$u->do(
|
||||
"DELETE FROM userpicblob2 WHERE userid=? AND picid=?",
|
||||
undef, $u->{'userid'}, $picid);
|
||||
}
|
||||
return $err->(@_);
|
||||
};
|
||||
|
||||
### insert the blob
|
||||
$u->do(
|
||||
"INSERT INTO userpicblob2 (userid, picid, imagedata) VALUES (?,?,?)",
|
||||
undef, $u->{'userid'}, $picid, $POST{'userpic'});
|
||||
return $clean_err->($u->errstr) if $u->err;
|
||||
|
||||
# make it their default pic?
|
||||
if ($POST{'make_default'}) {
|
||||
LJ::update_user($u, { defaultpicid => $picid });
|
||||
$u->{'defaultpicid'} = $picid;
|
||||
}
|
||||
|
||||
# set default keywords?
|
||||
if ($POST{'keywords'} && $POST{'keywords'} ne '') {
|
||||
print "storing keywords\n" if $DEBUG;
|
||||
|
||||
$sth = $dbcr->prepare("SELECT kwid, picid FROM userpicmap2 WHERE userid=?");
|
||||
$sth->execute($u->{'userid'});
|
||||
|
||||
my @exist_kwids;
|
||||
while (my ($kwid, $picid) = $sth->fetchrow_array) {
|
||||
$exist_kwids[$kwid] = $picid;
|
||||
}
|
||||
|
||||
my @keywords = split(/\s*,\s*/, $POST{'keywords'});
|
||||
@keywords = grep { s/^\s+//; s/\s+$//; $_; } @keywords;
|
||||
|
||||
my (@bind, @data);
|
||||
my $c = 0;
|
||||
|
||||
foreach my $kw (@keywords) {
|
||||
my $kwid = LJ::get_keyword_id($u, $kw);
|
||||
next unless $kwid; # Houston we have a problem! This should always return an id.
|
||||
|
||||
if ($c > $LJ::MAX_USERPIC_KEYWORDS) {
|
||||
return $clean_err->("Too many userpic keywords: " . LJ::ehtml($kw));
|
||||
}
|
||||
|
||||
if ($exist_kwids[$kwid]) { # Already used on another picture
|
||||
# delete existing pic while there's newer one
|
||||
$u->do("
|
||||
delete ljr_remote_userpics, ljr_cached_userpics
|
||||
from ljr_cached_userpics, ljr_remote_userpics
|
||||
where
|
||||
ljr_cached_userpics.ru_id = ljr_remote_userpics.ru_id and
|
||||
ljr_cached_userpics.remote_picid = ljr_remote_userpics.remote_picid and
|
||||
ljr_remote_userpics.local_userid = ? and local_picid = ?",
|
||||
undef, $u->{'userid'}, $exist_kwids[$kwid]);
|
||||
|
||||
$u->do("DELETE FROM userpicmap2 WHERE userid=? AND picid=?",
|
||||
undef, $u->{'userid'}, $exist_kwids[$kwid]);
|
||||
|
||||
$u->do("DELETE FROM userpicblob2 WHERE userid=? AND picid=?",
|
||||
undef, $u->{'userid'}, $exist_kwids[$kwid]);
|
||||
|
||||
$u->do("DELETE FROM userpic2 WHERE userid=? AND picid=?",
|
||||
undef, $u->{'userid'}, $exist_kwids[$kwid]);
|
||||
}
|
||||
|
||||
push @bind, '(?, ?, ?)';
|
||||
push @data, $u->{'userid'}, $kwid, $picid;
|
||||
|
||||
$c++;
|
||||
}
|
||||
|
||||
if (@data && @bind) {
|
||||
my $bind = join(',', @bind);
|
||||
|
||||
$u->do(
|
||||
"INSERT INTO userpicmap2 (userid, kwid, picid) VALUES $bind",
|
||||
undef, @data);
|
||||
}
|
||||
}
|
||||
|
||||
# set default comments and the url
|
||||
my (@data, @set);
|
||||
if ($POST{'comments'} && $POST{'comments'} ne '') {
|
||||
push @set, 'comment=?';
|
||||
push @data, LJ::text_trim($POST{'comments'}, $LJ::BMAX_UPIC_COMMENT, $LJ::CMAX_UPIC_COMMENT);
|
||||
}
|
||||
|
||||
if ($POST{'url'} ne '') {
|
||||
push @set, 'url=?';
|
||||
push @data, $POST{'url'};
|
||||
}
|
||||
|
||||
if (@set) {
|
||||
my $set = join(',', @set);
|
||||
|
||||
$u->do("UPDATE userpic2 SET $set WHERE userid=? AND picid=?",
|
||||
undef, @data, $u->{'userid'}, $picid);
|
||||
return $err->($u->errstr) if $u->err;
|
||||
}
|
||||
|
||||
$u->do("INSERT INTO ljr_remote_userpics VALUES (?,?,?,?)",
|
||||
undef, $ru->{ru_id}, $rpicid, $u->{userid}, $picid);
|
||||
return $err->($u->errstr) if $u->err;
|
||||
}
|
||||
}
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
return 1;
|
||||
35
local/bin/ljrimport/ljr-defaults.pl
Executable file
35
local/bin/ljrimport/ljr-defaults.pl
Executable file
@@ -0,0 +1,35 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
package LJR;
|
||||
|
||||
$LJ_CLIENT = "LJR::Import/0.01";
|
||||
$USER_AGENT = "LJR::Import/0.01; http://lj.rossia.org/; lj-admin\@rossia.org";
|
||||
|
||||
# How much times to retry if any network related error occurs
|
||||
$NETWORK_RETRIES = 10; #was: 20
|
||||
|
||||
# Hom much seconds to wait before each retry
|
||||
$NETWORK_SLEEP = 30; #was: 5
|
||||
|
||||
$DEBUG = 1;
|
||||
|
||||
sub NETWORK_SLEEP {
|
||||
my $msg = shift;
|
||||
|
||||
if ($msg) {
|
||||
$msg = " (" . $msg . ")";
|
||||
}
|
||||
else {
|
||||
$msg = "";
|
||||
}
|
||||
|
||||
my $t = `date +"%D %T"`;
|
||||
print
|
||||
substr($t, 0, length($t) - 1) .
|
||||
" sleeping $NETWORK_SLEEP seconds due to network related error" . $msg . ".\n"
|
||||
if $DEBUG;
|
||||
|
||||
sleep $NETWORK_SLEEP;
|
||||
};
|
||||
|
||||
return 1;
|
||||
106
local/bin/ljrimport/ljr-import.pl
Executable file
106
local/bin/ljrimport/ljr-import.pl
Executable file
@@ -0,0 +1,106 @@
|
||||
#!/usr/bin/perl -w
|
||||
|
||||
package LJR::Import;
|
||||
|
||||
use strict; # preventing my program from doing bad things
|
||||
use DBI; # http://dbi.perl.org
|
||||
use POSIX ();
|
||||
|
||||
do $ENV{'LJHOME'} . "/cgi-bin/ljconfig.pl";
|
||||
|
||||
my $qhost = $LJ::DBINFO{'master'}->{'host'};
|
||||
my $quser = $LJ::DBINFO{'master'}->{'user'};
|
||||
my $qpass = $LJ::DBINFO{'master'}->{'pass'};
|
||||
my $qdb = $LJ::DBINFO{'master'}->{'dbname'};
|
||||
my $qsock = $LJ::DBINFO{'master'}->{'sock'};
|
||||
my $qport = $LJ::DBINFO{'master'}->{'port'};
|
||||
|
||||
$| = 1; # unbuffered (almost) output
|
||||
|
||||
# global database handle
|
||||
$LJR::Import::global_dbh = 0;
|
||||
# global shutdown request received flag
|
||||
$LJR::Import::cool_stop = 0;
|
||||
|
||||
my $history_id;
|
||||
|
||||
# POSIX unmasks the sigprocmask properly
|
||||
my $sigset = POSIX::SigSet->new();
|
||||
my $action = POSIX::SigAction->new(
|
||||
'LJR::Import::sigTERM_handler', $sigset, &POSIX::SA_NODEFER);
|
||||
|
||||
POSIX::sigaction(&POSIX::SIGTERM, $action);
|
||||
|
||||
sub log_print {
|
||||
my $msg = shift;
|
||||
my $t = `date +"%D %T"`;
|
||||
print substr($t, 0, length($t) - 1) . " $msg\n";
|
||||
}
|
||||
|
||||
sub sigTERM_handler {
|
||||
my $t = `date +"%D %T"`;
|
||||
print substr($t, 0, length($t) - 1) . " ljr-import.pl: received shutdown request\n";
|
||||
$LJR::Import::cool_stop = 1;
|
||||
}
|
||||
|
||||
# configuration
|
||||
my $speed_throttle = 10; # seconds
|
||||
|
||||
print "\n";
|
||||
|
||||
LJR::Import::log_print("started");
|
||||
|
||||
# main loop, throttled
|
||||
while (!process_exit()) {
|
||||
process_queue(); # process new requests for import if any
|
||||
sleep ($speed_throttle); # sleep for a while
|
||||
}
|
||||
|
||||
LJR::Import::log_print("ljr-import.pl: shutting down due to safe shutdown request");
|
||||
|
||||
sub import_log {
|
||||
my ($istatus) = @_;
|
||||
|
||||
my $sth2 = $LJR::Import::global_dbh->prepare (
|
||||
"update ljr_ihistory set
|
||||
istatus = ?,
|
||||
idate = now()
|
||||
where importid = ?");
|
||||
$sth2->execute($istatus, $history_id);
|
||||
$sth2->finish;
|
||||
}
|
||||
|
||||
sub process_exit {
|
||||
return ($LJR::Import::cool_stop);
|
||||
}
|
||||
|
||||
sub process_queue {
|
||||
my $row;
|
||||
my $row1;
|
||||
my $sth2;
|
||||
my $e;
|
||||
|
||||
$LJR::Import::global_dbh = DBI->connect(
|
||||
"DBI:mysql:mysql_socket=$qsock;hostname=$qhost;port=$qport;database=$qdb",
|
||||
$quser, $qpass,
|
||||
{RaiseError => 0, AutoCommit => 1}
|
||||
) || die "Can't open database connection: $DBI::errstr";
|
||||
|
||||
my $sth = $LJR::Import::global_dbh->prepare("SELECT * from ljr_iqueue order by priority, importid");
|
||||
$sth->execute;
|
||||
|
||||
while (($row = $sth->fetchrow_hashref) && !process_exit()) {
|
||||
my $r = system ("nice -n 19 ./ljr-importdo.pl");
|
||||
if ($r != 0) {
|
||||
$sth->finish;
|
||||
$LJR::Import::global_dbh->disconnect;
|
||||
return;
|
||||
}
|
||||
|
||||
sleep($speed_throttle); # do not hurry
|
||||
$sth->execute; # refresh the query
|
||||
}
|
||||
$sth->finish;
|
||||
|
||||
$LJR::Import::global_dbh->disconnect;
|
||||
}
|
||||
218
local/bin/ljrimport/ljr-importdo.pl
Executable file
218
local/bin/ljrimport/ljr-importdo.pl
Executable file
@@ -0,0 +1,218 @@
|
||||
#!/usr/bin/perl -w
|
||||
|
||||
package LJR::Import;
|
||||
|
||||
use strict; # preventing my program from doing bad things
|
||||
use DBI; # http://dbi.perl.org
|
||||
use POSIX ();
|
||||
|
||||
do $ENV{'LJHOME'} . "/cgi-bin/ljconfig.pl";
|
||||
|
||||
my $qhost = $LJ::DBINFO{'master'}->{'host'};
|
||||
my $quser = $LJ::DBINFO{'master'}->{'user'};
|
||||
my $qpass = $LJ::DBINFO{'master'}->{'pass'};
|
||||
my $qdb = $LJ::DBINFO{'master'}->{'dbname'};
|
||||
my $qsock = $LJ::DBINFO{'master'}->{'sock'};
|
||||
my $qport = $LJ::DBINFO{'master'}->{'port'};
|
||||
|
||||
|
||||
require "ijournal.pl";
|
||||
require "icomments.pl";
|
||||
|
||||
$| = 1; # unbuffered (almost) output
|
||||
|
||||
# global database handle
|
||||
$LJR::Import::global_dbh = 0;
|
||||
# global shutdown request received flag
|
||||
$LJR::Import::cool_stop = 0;
|
||||
|
||||
my $history_id;
|
||||
|
||||
# POSIX unmasks the sigprocmask properly
|
||||
my $sigset = POSIX::SigSet->new();
|
||||
my $action = POSIX::SigAction->new(
|
||||
'LJR::Import::sigTERM_handler', $sigset, &POSIX::SA_NODEFER);
|
||||
|
||||
POSIX::sigaction(&POSIX::SIGTERM, $action);
|
||||
|
||||
sub log_print {
|
||||
my $msg = shift;
|
||||
my $t = `date +"%D %T"`;
|
||||
print substr($t, 0, length($t) - 1) . " $msg\n";
|
||||
}
|
||||
|
||||
sub sigTERM_handler {
|
||||
my $t = `date +"%D %T"`;
|
||||
print substr($t, 0, length($t) - 1) . " ljr-import-do.pl: received shutdown request\n";
|
||||
$LJR::Import::cool_stop = 1;
|
||||
}
|
||||
|
||||
# configuration
|
||||
my $speed_throttle = 10; # seconds
|
||||
|
||||
|
||||
process_queue_alone(); # there must be something there!
|
||||
if (process_exit()) {
|
||||
exit 1;
|
||||
}
|
||||
else {
|
||||
exit 0;
|
||||
}
|
||||
|
||||
sub import_log {
|
||||
my ($istatus) = @_;
|
||||
|
||||
my $sth2 = $LJR::Import::global_dbh->prepare (
|
||||
"update ljr_ihistory set
|
||||
istatus = ?,
|
||||
idate = now()
|
||||
where importid = ?");
|
||||
$sth2->execute($istatus, $history_id);
|
||||
$sth2->finish;
|
||||
}
|
||||
|
||||
sub process_exit {
|
||||
return ($LJR::Import::cool_stop);
|
||||
}
|
||||
|
||||
sub process_queue_alone {
|
||||
my $row;
|
||||
my $row1;
|
||||
my $sth2;
|
||||
my $e;
|
||||
|
||||
$LJR::Import::global_dbh = DBI->connect(
|
||||
"DBI:mysql:mysql_socket=$qsock;hostname=$qhost;port=$qport;database=$qdb",
|
||||
$quser, $qpass,
|
||||
{RaiseError => 0, AutoCommit => 1}
|
||||
) || die "Can't open database connection: $DBI::errstr";
|
||||
|
||||
my $sth = $LJR::Import::global_dbh->prepare("SELECT * from ljr_iqueue order by priority, importid");
|
||||
$sth->execute;
|
||||
|
||||
while (($row = $sth->fetchrow_hashref) && !process_exit()) {
|
||||
my $sth1 = $LJR::Import::global_dbh->prepare (
|
||||
"SELECT * from ljr_iqueue where
|
||||
local_user = '" . $row->{'local_user'} . "'
|
||||
order by local_user desc, importid desc limit 1");
|
||||
$sth1->execute; # find last user request for import
|
||||
$row = $sth1->fetchrow_hashref;
|
||||
|
||||
# create history record
|
||||
$sth2 = $LJR::Import::global_dbh->prepare (
|
||||
"insert into ljr_ihistory values ('',?,?,'',?,?,?,?,now(),'STARTED',now())");
|
||||
$sth2->execute (
|
||||
$row->{'remote_site'}, $row->{'remote_user'}, $row->{'remote_protocol'},
|
||||
$row->{'local_user'}, $row->{'opt_overwrite'}, $row->{'opt_comments'}
|
||||
); # save import history (parameters, time when started)
|
||||
|
||||
$history_id = $LJR::Import::global_dbh->selectrow_array("SELECT LAST_INSERT_ID()");
|
||||
$sth2->finish;
|
||||
|
||||
LJR::Import::log_print(
|
||||
$row->{'local_user'} . " <- " .
|
||||
$row->{'remote_site'} . "::" . $row->{'remote_user'} .
|
||||
" (entries)"
|
||||
);
|
||||
|
||||
$e = "";
|
||||
$e = import_journal(
|
||||
0, # throttle_speed (seconds)
|
||||
$row->{'remote_site'}, # remote_site
|
||||
$row->{'remote_protocol'},# remote_protocol
|
||||
$row->{'remote_user'}, # remote_user
|
||||
$row->{'remote_pass'}, # remote_pass
|
||||
"", # remote shared journal (if any)
|
||||
$row->{'local_user'}, # local_user
|
||||
"", # local shared journal (if any)
|
||||
$row->{'opt_overwrite'} # overwrite entries
|
||||
);
|
||||
|
||||
if ($row->{'opt_comments'} && (!$e || !$e->{'err'})) {
|
||||
LJR::Import::log_print(
|
||||
$row->{'local_user'} . " <- " .
|
||||
$row->{'remote_site'} . "::" . $row->{'remote_user'} .
|
||||
" (caching comments)"
|
||||
);
|
||||
|
||||
$e = get_comments(
|
||||
$row->{'remote_site'},
|
||||
$row->{'remote_user'},
|
||||
$row->{'remote_pass'},
|
||||
1);
|
||||
|
||||
if (!$e || !$e->{'err'}) {
|
||||
LJR::Import::log_print(
|
||||
$row->{'local_user'} . " <- " .
|
||||
$row->{'remote_site'} . "::" . $row->{'remote_user'} .
|
||||
" (creating comments)");
|
||||
|
||||
$e = create_imported_comments (
|
||||
$row->{'remote_site'},
|
||||
$row->{'remote_user'},
|
||||
$row->{'local_user'});
|
||||
}
|
||||
}
|
||||
|
||||
if ($e->{'err'}) {
|
||||
$sth2 = $LJR::Import::global_dbh->prepare (
|
||||
"update ljr_ihistory " .
|
||||
"set remote_pass = '" . $row->{'remote_pass'} . "' " .
|
||||
"where importid = " . $history_id . " ;"
|
||||
);
|
||||
$sth2->execute; # save remote pass for debugging purposes
|
||||
$sth2->finish;
|
||||
|
||||
my $boo = $e->{errtext};
|
||||
$boo =~ s/\n//;
|
||||
|
||||
LJR::Import::log_print(
|
||||
$row->{'local_user'} . " <- " .
|
||||
$row->{'remote_site'} . "::" . $row->{'remote_user'} . " " . $boo
|
||||
);
|
||||
|
||||
import_log($e->{errtext});
|
||||
}
|
||||
else {
|
||||
$sth2 = $LJR::Import::global_dbh->prepare (
|
||||
"update ljr_ihistory " .
|
||||
"set remote_pass = '' " .
|
||||
"where remote_site = '" . $row->{'remote_site'} . "' and " .
|
||||
"remote_user = '" . $row->{'remote_user'} . "' ;"
|
||||
);
|
||||
$sth2->execute; # remove remote pass since the journal was imported successfully
|
||||
$sth2->finish;
|
||||
|
||||
LJR::Import::log_print(
|
||||
$row->{'local_user'} . " <- " .
|
||||
$row->{'remote_site'} . "::" . $row->{'remote_user'} .
|
||||
": successful"
|
||||
);
|
||||
|
||||
if ($e->{'warns'}) {
|
||||
import_log("SUCCESSFUL, but " . $e->{'warns'});
|
||||
}
|
||||
else {
|
||||
import_log("SUCCESSFUL");
|
||||
}
|
||||
}
|
||||
|
||||
$sth1 = $LJR::Import::global_dbh->prepare (
|
||||
"delete from ljr_iqueue " .
|
||||
"where local_user = '" . $row->{'local_user'} . "'"
|
||||
); # empty all the user's request after processing last one
|
||||
$sth1->execute;
|
||||
$sth1->finish;
|
||||
|
||||
$sth->finish;
|
||||
|
||||
# we're quitting!
|
||||
# if (process_exit()) {
|
||||
$LJR::Import::global_dbh->disconnect;
|
||||
return;
|
||||
# }
|
||||
}
|
||||
$sth->finish;
|
||||
|
||||
$LJR::Import::global_dbh->disconnect;
|
||||
}
|
||||
117
local/bin/ljrimport/ljr-links.pl
Executable file
117
local/bin/ljrimport/ljr-links.pl
Executable file
@@ -0,0 +1,117 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
|
||||
package LJR::Links;
|
||||
|
||||
sub get_server_url {
|
||||
my ($canonical_url, $type) = @_;
|
||||
|
||||
if ($canonical_url eq "http://www.livejournal.com") {
|
||||
if ($type eq "base") {
|
||||
return "livejournal.com";
|
||||
}
|
||||
if ($type eq "userpic_base") {
|
||||
return "http://userpic.livejournal.com";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub make_ljr_hrefs {
|
||||
my ($server_patt, $server_full, $text) = @_;
|
||||
|
||||
my $content = $$text;
|
||||
$$text = "";
|
||||
my $url;
|
||||
my $orig_url;
|
||||
my $orig_url_text;
|
||||
|
||||
return unless $content;
|
||||
|
||||
# replace valid html hyperlinks (<a href=http://www.livejournal.com/users/username/111.html>url_text</a>)
|
||||
# with <ljr-href url="/users/username/111.html" site="http://www.livejournal.com">url_text</ljr-href>
|
||||
#
|
||||
while ($content =~
|
||||
/\G(.*?)(\<a.*?href.*?=(\s?\"\s?)?(.*?)(\s?\"\s?)?\>(.*?)\<\/a\>)(.*)/sgi
|
||||
) {
|
||||
$$text .= $1;
|
||||
$orig_url = $2;
|
||||
$orig_url_text = $6;
|
||||
$url = $4;
|
||||
$content = $7;
|
||||
|
||||
# relative link (to the server from which we're importing)
|
||||
if ($url =~ /^(\/users\/.*?\/\d*?\.html(.*?$))/) { # (\?thread=\d*\#t\d*)|$
|
||||
$$text .= "<ljr-href url=\"$1\" site=\"$server_full\">$orig_url_text</ljr-href>";
|
||||
}
|
||||
# relative link to oldstyle talkread.bml
|
||||
elsif ($url =~ /^\/talkread.bml?\?journal=(.*?)\&itemid=(\d+)/) {
|
||||
$$text .= "<ljr-href url=\"/users/$1/$2.html\" site=\"$server_full\">$orig_url_text</ljr-href>";
|
||||
}
|
||||
# absolute link to oldstyle talkread.bml
|
||||
elsif ($url =~ /^http:\/\/(www\.|)$server_patt\/talkread.bml\?journal=(.*?)\&itemid=(\d+)/) {
|
||||
$$text .= "<ljr-href url=\"/users/$2/$3.html\" site=\"$server_full\">$orig_url_text</ljr-href>";
|
||||
}
|
||||
# free users own two types of urls (first is canonical)
|
||||
# http://www.livejournal.com/users/free_user/123456.html
|
||||
# http://www.livejournal.com/~free_user/123456.html
|
||||
elsif ($url =~ /^http:\/\/(www\.|)$server_patt(((\/~(\w*?)\/)|(\/users\/.*?\/))(\d*?\.html(.*?$)))/) { # (\?thread=\d*\#t\d*)|$
|
||||
if ($5) {
|
||||
$$text .= "<ljr-href url=\"/users/$5/$7\" site=\"$server_full\">$orig_url_text</ljr-href>";
|
||||
}
|
||||
else {
|
||||
$$text .= "<ljr-href url=\"$2\" site=\"$server_full\">$orig_url_text</ljr-href>";
|
||||
}
|
||||
}
|
||||
# payed users might own http://payeduser.livejournal.com/123456.html urls
|
||||
elsif ($url =~ /^http:\/\/(\w*?)\.$server_patt\/(\d*?\.html(.*?$))/) { # (\?thread=\d*\#t\d*)|$
|
||||
$$text .= "<ljr-href url=\"/users/$1/$2\" site=\"$server_full\">$orig_url_text</ljr-href>";
|
||||
}
|
||||
else {
|
||||
$$text .= $orig_url;
|
||||
}
|
||||
}
|
||||
$$text .= $content;
|
||||
|
||||
$content = $$text;
|
||||
$$text = "";
|
||||
|
||||
|
||||
# replace strings like http://www.livejournal.com/users/lookslikeentry/123456.html with
|
||||
# <ljr-href url="/users/lookslikeentry/123456.html" site="http://www.livejournal.com">http://www.livejournal.com/users/lookslikeentry/123456.html</ljr-href>
|
||||
#
|
||||
# now these can be only absolute links starting with http://
|
||||
while ($content =~
|
||||
/\G(.*?(^|[\ \t\r\n\f]))(http:\/\/.*?)(($|[\ \t\r\n\f]).*)/sg
|
||||
) {
|
||||
$$text .= $1;
|
||||
$orig_url = $3;
|
||||
$orig_url_text = $3;
|
||||
$url = $3;
|
||||
$content = $4;
|
||||
|
||||
# free users (copied from above)
|
||||
if ($url =~ /^http:\/\/(www\.|)$server_patt(((\/~(\w*?)\/)|(\/users\/.*?\/))(\d*?\.html(.*?$)))/) { # (\?thread=\d*\#t\d*)|$
|
||||
if ($5) {
|
||||
$$text .= "<ljr-href url=\"/users/$5/$7\" site=\"$server_full\">$orig_url_text</ljr-href>";
|
||||
}
|
||||
else {
|
||||
$$text .= "<ljr-href url=\"$2\" site=\"$server_full\">$orig_url_text</ljr-href>";
|
||||
}
|
||||
}
|
||||
# oldstyle talkread.bml
|
||||
elsif ($url =~ /^http:\/\/(www\.|)$server_patt\/talkread.bml\?journal=(.*?)\&itemid=(\d+)/) {
|
||||
$$text .= "<ljr-href url=\"/users/$2/$3.html\" site=\"$server_full\">$orig_url_text</ljr-href>";
|
||||
}
|
||||
# payed users (copied from above)
|
||||
elsif ($url =~ /^http:\/\/(\w*?)\.$server_patt\/(\d*?\.html(.*?$))/) { # (\?thread=\d*\#t\d*)|$
|
||||
$$text .= "<ljr-href url=\"/users/$1/$2\" site=\"$server_full\">$orig_url_text</ljr-href>";
|
||||
}
|
||||
else {
|
||||
$$text .= $orig_url;
|
||||
}
|
||||
}
|
||||
$$text .= $content;
|
||||
}
|
||||
|
||||
return 1;
|
||||
17
local/bin/ljrimport/ljr-start.sh
Executable file
17
local/bin/ljrimport/ljr-start.sh
Executable file
@@ -0,0 +1,17 @@
|
||||
#!/bin/bash
|
||||
|
||||
export LJHOME=/home/lj-admin/lj
|
||||
IMPORT_NAME=ljr-import
|
||||
|
||||
ipid=`ps -e --format=pid,cmd | grep $IMPORT_NAME | grep -v grep | cut --bytes=1-5`
|
||||
|
||||
if [ ! "$ipid" == "" ]; then
|
||||
echo "LJR::Import found, PID: $ipid; shutdown with ljr-stop.sh first."
|
||||
else
|
||||
if [ "$LJHOME" != "" ]; then
|
||||
cd $LJHOME/bin/ljrimport
|
||||
./ljr-import.pl >> $LJHOME/logs/ljr-import.log 2>&1 &
|
||||
else
|
||||
echo \$LJHOME is not set.
|
||||
fi
|
||||
fi
|
||||
12
local/bin/ljrimport/ljr-stop.sh
Executable file
12
local/bin/ljrimport/ljr-stop.sh
Executable file
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
|
||||
IMPORT_NAME=ljr-import
|
||||
|
||||
ipid=`ps -e --format=pid,cmd | grep $IMPORT_NAME | grep -v grep | cut --bytes=1-5`
|
||||
|
||||
if [ ! "$ipid" == "" ]; then
|
||||
echo "LJR::Import found, PID: $ipid; sending shutdown signal."
|
||||
kill $ipid
|
||||
else
|
||||
echo "LJR::Import is not running."
|
||||
fi
|
||||
21
local/bin/maint/clean_challenges.pl
Executable file
21
local/bin/maint/clean_challenges.pl
Executable file
@@ -0,0 +1,21 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
|
||||
$maint{'clean_challenges'} = sub
|
||||
{
|
||||
my $dbh = LJ::get_db_writer();
|
||||
my $sth;
|
||||
|
||||
my $ctime = time();
|
||||
my $deltime = $ctime - 60*60*24*14; # two weeks
|
||||
|
||||
print "current time: $ctime\n";
|
||||
print "deleting challenges older than: $deltime\n";
|
||||
$sth = $dbh->prepare("delete from challenges where challenge < 'c0:$deltime'");
|
||||
$sth->execute();
|
||||
if ($dbh->err) { die $dbh->errstr; }
|
||||
|
||||
print "done.\n";
|
||||
};
|
||||
|
||||
1;
|
||||
548
local/bin/maint/stats.pl
Executable file
548
local/bin/maint/stats.pl
Executable file
@@ -0,0 +1,548 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
|
||||
use strict;
|
||||
use vars qw(%maint);
|
||||
|
||||
require "$ENV{'LJHOME'}/cgi-bin/statslib.pl";
|
||||
|
||||
# filled in by ljmaint.pl, 0=quiet, 1=normal, 2=verbose
|
||||
$LJ::Stats::VERBOSE = $LJ::LJMAINT_VERBOSE >= 2 ? 1 : 0;
|
||||
|
||||
$maint{'genstats'} = sub
|
||||
{
|
||||
my @which = @_ || qw(users countries
|
||||
states gender clients
|
||||
pop_interests meme pop_faq);
|
||||
|
||||
# popular faq items
|
||||
LJ::Stats::register_stat
|
||||
({ 'type' => "global",
|
||||
'jobname' => "popfaq",
|
||||
'statname' => "pop_faq",
|
||||
'handler' =>
|
||||
sub {
|
||||
my $db_getter = shift;
|
||||
return undef unless ref $db_getter eq 'CODE';
|
||||
my $db = $db_getter->();
|
||||
return undef unless $db;
|
||||
|
||||
my $sth = $db->prepare("SELECT faqid, COUNT(*) FROM faquses WHERE " .
|
||||
"faqid<>0 GROUP BY 1 ORDER BY 2 DESC LIMIT 50");
|
||||
$sth->execute;
|
||||
die $db->errstr if $db->err;
|
||||
|
||||
my %ret;
|
||||
while (my ($id, $count) = $sth->fetchrow_array) {
|
||||
$ret{$id} = $count;
|
||||
}
|
||||
|
||||
return \%ret;
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
# popular interests
|
||||
LJ::Stats::register_stat
|
||||
({ 'type' => "global",
|
||||
'jobname' => "pop_interests",
|
||||
'statname' => "pop_interests",
|
||||
'handler' =>
|
||||
sub {
|
||||
my $db_getter = shift;
|
||||
return undef unless ref $db_getter eq 'CODE';
|
||||
my $db = $db_getter->();
|
||||
return undef unless $db;
|
||||
|
||||
return {} if $LJ::DISABLED{'interests-popular'};
|
||||
|
||||
# see what the previous min was, then subtract 20% of max from it
|
||||
my ($prev_min, $prev_max) = $db->selectrow_array("SELECT MIN(statval), MAX(statval) " .
|
||||
"FROM stats WHERE statcat='pop_interests'");
|
||||
my $stat_min = int($prev_min - (0.2*$prev_max));
|
||||
$stat_min = 1 if $stat_min < 1;
|
||||
|
||||
my $sth = $db->prepare("SELECT interest, intcount FROM interests WHERE intcount>? " .
|
||||
"ORDER BY intcount DESC, interest ASC LIMIT 400");
|
||||
$sth->execute($stat_min);
|
||||
die $db->errstr if $db->err;
|
||||
|
||||
my %ret;
|
||||
while (my ($int, $count) = $sth->fetchrow_array) {
|
||||
$ret{$int} = $count;
|
||||
}
|
||||
|
||||
return \%ret;
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
# popular memes
|
||||
LJ::Stats::register_stat
|
||||
({ 'type' => "global",
|
||||
'jobname' => "meme",
|
||||
'statname' => "popmeme",
|
||||
'handler' =>
|
||||
sub {
|
||||
my $db_getter = shift;
|
||||
return undef unless ref $db_getter eq 'CODE';
|
||||
my $db = $db_getter->();
|
||||
return undef unless $db;
|
||||
|
||||
return {} if $LJ::DISABLED{'meme'};
|
||||
|
||||
my $sth = $db->prepare("SELECT url, count(*) FROM meme " .
|
||||
"GROUP BY 1 ORDER BY 2 DESC LIMIT 100");
|
||||
$sth->execute;
|
||||
die $db->errstr if $db->err;
|
||||
|
||||
my %ret;
|
||||
while (my ($url, $count) = $sth->fetchrow_array) {
|
||||
$ret{$url} = $count;
|
||||
}
|
||||
|
||||
return \%ret;
|
||||
},
|
||||
});
|
||||
|
||||
# clients
|
||||
LJ::Stats::register_stat
|
||||
({ 'type' => "global",
|
||||
'jobname' => "clients",
|
||||
'statname' => "client",
|
||||
'handler' =>
|
||||
sub {
|
||||
my $db_getter = shift;
|
||||
return undef unless ref $db_getter eq 'CODE';
|
||||
my $db = $db_getter->();
|
||||
return undef unless $db;
|
||||
|
||||
return {} if $LJ::DISABLED{'clientversionlog'};
|
||||
|
||||
my $tsql = "SELECT MAX(userid) FROM user";
|
||||
$tsql .= " where userid < " . $LJ::LJR_IMPORTED_USERIDS if $LJ::LJR_IMPORTED_USERIDS;
|
||||
|
||||
my $usertotal = $db->selectrow_array($tsql);
|
||||
my $blocks = LJ::Stats::num_blocks($usertotal);
|
||||
|
||||
my %ret;
|
||||
foreach my $block (1..$blocks) {
|
||||
my ($low, $high) = LJ::Stats::get_block_bounds($block);
|
||||
|
||||
$db = $db_getter->(); # revalidate connection
|
||||
my $sth = $db->prepare("SELECT c.client, COUNT(*) AS 'count' FROM clients c, clientusage cu " .
|
||||
"WHERE c.clientid=cu.clientid AND cu.userid BETWEEN $low AND $high " .
|
||||
"AND cu.lastlogin > DATE_SUB(NOW(), INTERVAL 30 DAY) GROUP BY 1 ORDER BY 2");
|
||||
$sth->execute;
|
||||
die $db->errstr if $db->err;
|
||||
|
||||
while ($_ = $sth->fetchrow_hashref) {
|
||||
$ret{$_->{'client'}} += $_->{'count'};
|
||||
}
|
||||
|
||||
print LJ::Stats::block_status_line($block, $blocks);
|
||||
}
|
||||
|
||||
return \%ret;
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
# user table analysis
|
||||
LJ::Stats::register_stat
|
||||
({ 'type' => "global",
|
||||
'jobname' => "users",
|
||||
'statname' => ["account", "newbyday", "age", "userinfo"],
|
||||
'handler' =>
|
||||
sub {
|
||||
my $db_getter = shift;
|
||||
return undef unless ref $db_getter eq 'CODE';
|
||||
my $db = $db_getter->();
|
||||
return undef unless $db;
|
||||
|
||||
my $tsql = "SELECT MAX(userid) FROM user";
|
||||
$tsql .= " where userid < " . $LJ::LJR_IMPORTED_USERIDS if $LJ::LJR_IMPORTED_USERIDS;
|
||||
|
||||
my $usertotal = $db->selectrow_array($tsql);
|
||||
my $blocks = LJ::Stats::num_blocks($usertotal);
|
||||
|
||||
my %ret; # return hash, (statname => { arg => val } since 'statname' is arrayref above
|
||||
|
||||
# iterate over user table in batches
|
||||
foreach my $block (1..$blocks) {
|
||||
|
||||
my ($low, $high) = LJ::Stats::get_block_bounds($block);
|
||||
|
||||
# user query: gets user,caps,age,status,allow_getljnews
|
||||
$db = $db_getter->(); # revalidate connection
|
||||
my $sth = $db->prepare
|
||||
("SELECT user, caps, " .
|
||||
"FLOOR((TO_DAYS(NOW())-TO_DAYS(bdate))/365.25) AS 'age', " .
|
||||
"status, allow_getljnews " .
|
||||
"FROM user WHERE userid BETWEEN $low AND $high");
|
||||
$sth->execute;
|
||||
die $db->errstr if $db->err;
|
||||
while (my $rec = $sth->fetchrow_hashref) {
|
||||
|
||||
# account types
|
||||
my $capnameshort = LJ::name_caps_short($rec->{'caps'});
|
||||
$ret{'account'}->{$capnameshort}++;
|
||||
|
||||
# ages
|
||||
$ret{'age'}->{$rec->{'age'}}++
|
||||
if $rec->{'age'} > 4 && $rec->{'age'} < 110;
|
||||
|
||||
# users receiving news emails
|
||||
$ret{'userinfo'}->{'allow_getljnews'}++
|
||||
if $rec->{'status'} eq "A" && $rec->{'allow_getljnews'} eq "Y";
|
||||
}
|
||||
|
||||
# userusage query: gets timeupdate,datereg,nowdate
|
||||
my $sth = $db->prepare
|
||||
("SELECT DATE_FORMAT(timecreate, '%Y-%m-%d') AS 'datereg', " .
|
||||
"DATE_FORMAT(NOW(), '%Y-%m-%d') AS 'nowdate', " .
|
||||
"UNIX_TIMESTAMP(timeupdate) AS 'timeupdate' " .
|
||||
"FROM userusage WHERE userid BETWEEN $low AND $high");
|
||||
$sth->execute;
|
||||
die $db->errstr if $db->err;
|
||||
|
||||
while (my $rec = $sth->fetchrow_hashref) {
|
||||
|
||||
# date registered
|
||||
$ret{'newbyday'}->{$rec->{'datereg'}}++
|
||||
unless $rec->{'datereg'} eq $rec->{'nowdate'};
|
||||
|
||||
# total user/activity counts
|
||||
$ret{'userinfo'}->{'total'}++;
|
||||
if (my $time = $rec->{'timeupdate'}) {
|
||||
my $now = time();
|
||||
$ret{'userinfo'}->{'updated'}++;
|
||||
$ret{'userinfo'}->{'updated_last30'}++ if $time > $now-60*60*24*30;
|
||||
$ret{'userinfo'}->{'updated_last7'}++ if $time > $now-60*60*24*7;
|
||||
$ret{'userinfo'}->{'updated_last1'}++ if $time > $now-60*60*24*1;
|
||||
}
|
||||
}
|
||||
|
||||
print LJ::Stats::block_status_line($block, $blocks);
|
||||
}
|
||||
|
||||
return \%ret;
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
LJ::Stats::register_stat
|
||||
({ 'type' => "clustered",
|
||||
'jobname' => "countries",
|
||||
'statname' => "country",
|
||||
'handler' =>
|
||||
sub {
|
||||
my $db_getter = shift;
|
||||
return undef unless ref $db_getter eq 'CODE';
|
||||
my $db = $db_getter->();
|
||||
my $cid = shift;
|
||||
return undef unless $db && $cid;
|
||||
|
||||
my $upc = LJ::get_prop("user", "country");
|
||||
die "Can't find country userprop. Database populated?\n" unless $upc;
|
||||
|
||||
my $tsql = "SELECT MAX(userid) FROM userproplite2";
|
||||
$tsql .= " where userid < " . $LJ::LJR_IMPORTED_USERIDS if $LJ::LJR_IMPORTED_USERIDS;
|
||||
|
||||
my $usertotal = $db->selectrow_array($tsql);
|
||||
my $blocks = LJ::Stats::num_blocks($usertotal);
|
||||
|
||||
my %ret;
|
||||
foreach my $block (1..$blocks) {
|
||||
my ($low, $high) = LJ::Stats::get_block_bounds($block);
|
||||
|
||||
$db = $db_getter->(); # revalidate connection
|
||||
my $sth = $db->prepare("SELECT u.value, COUNT(*) AS 'count' FROM userproplite2 u " .
|
||||
"LEFT JOIN clustertrack2 c ON u.userid=c.userid " .
|
||||
"WHERE u.upropid=? AND u.value<>'' AND u.userid=c.userid " .
|
||||
"AND u.userid BETWEEN $low AND $high " .
|
||||
"AND (c.clusterid IS NULL OR c.clusterid=?)" .
|
||||
"GROUP BY 1 ORDER BY 2");
|
||||
$sth->execute($upc->{'id'}, $cid);
|
||||
die "clusterid: $cid, " . $db->errstr if $db->err;
|
||||
|
||||
while ($_ = $sth->fetchrow_hashref) {
|
||||
$ret{$_->{'value'}} += $_->{'count'};
|
||||
}
|
||||
|
||||
print LJ::Stats::block_status_line($block, $blocks);
|
||||
}
|
||||
|
||||
return \%ret;
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
LJ::Stats::register_stat
|
||||
({ 'type' => "clustered",
|
||||
'jobname' => "states",
|
||||
'statname' => "stateus",
|
||||
'handler' =>
|
||||
sub {
|
||||
my $db_getter = shift;
|
||||
return undef unless ref $db_getter eq 'CODE';
|
||||
my $db = $db_getter->();
|
||||
my $cid = shift;
|
||||
return undef unless $db && $cid;
|
||||
|
||||
my $upc = LJ::get_prop("user", "country");
|
||||
die "Can't find country userprop. Database populated?\n" unless $upc;
|
||||
|
||||
my $ups = LJ::get_prop("user", "state");
|
||||
die "Can't find state userprop. Database populated?\n" unless $ups;
|
||||
|
||||
my $tsql = "SELECT MAX(userid) FROM userproplite2";
|
||||
$tsql .= " where userid < " . $LJ::LJR_IMPORTED_USERIDS if $LJ::LJR_IMPORTED_USERIDS;
|
||||
|
||||
my $usertotal = $db->selectrow_array($tsql);
|
||||
my $blocks = LJ::Stats::num_blocks($usertotal);
|
||||
|
||||
my %ret;
|
||||
foreach my $block (1..$blocks) {
|
||||
my ($low, $high) = LJ::Stats::get_block_bounds($block);
|
||||
|
||||
$db = $db_getter->(); # revalidate connection
|
||||
my $sth = $db->prepare("SELECT ua.value, COUNT(*) AS 'count' " .
|
||||
"FROM userproplite2 ua, userproplite2 ub " .
|
||||
"WHERE ua.userid=ub.userid AND ua.upropid=? AND " .
|
||||
"ub.upropid=? and ub.value='US' AND ub.value<>'' " .
|
||||
"AND ua.userid BETWEEN $low AND $high " .
|
||||
"GROUP BY 1 ORDER BY 2");
|
||||
$sth->execute($ups->{'id'}, $upc->{'id'});
|
||||
die $db->errstr if $db->err;
|
||||
|
||||
while ($_ = $sth->fetchrow_hashref) {
|
||||
$ret{$_->{'value'}} += $_->{'count'};
|
||||
}
|
||||
|
||||
print LJ::Stats::block_status_line($block, $blocks);
|
||||
}
|
||||
|
||||
return \%ret;
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
|
||||
LJ::Stats::register_stat
|
||||
({ 'type' => "clustered",
|
||||
'jobname' => "gender",
|
||||
'statname' => "gender",
|
||||
'handler' =>
|
||||
sub {
|
||||
my $db_getter = shift;
|
||||
return undef unless ref $db_getter eq 'CODE';
|
||||
my $db = $db_getter->();
|
||||
my $cid = shift;
|
||||
return undef unless $db && $cid;
|
||||
|
||||
my $upg = LJ::get_prop("user", "gender");
|
||||
die "Can't find gender userprop. Database populated?\n" unless $upg;
|
||||
|
||||
my $tsql = "SELECT MAX(userid) FROM userproplite2";
|
||||
$tsql .= " where userid < " . $LJ::LJR_IMPORTED_USERIDS if $LJ::LJR_IMPORTED_USERIDS;
|
||||
|
||||
my $usertotal = $db->selectrow_array($tsql);
|
||||
my $blocks = LJ::Stats::num_blocks($usertotal);
|
||||
|
||||
my %ret;
|
||||
foreach my $block (1..$blocks) {
|
||||
my ($low, $high) = LJ::Stats::get_block_bounds($block);
|
||||
|
||||
$db = $db_getter->(); # revalidate connection
|
||||
my $sth = $db->prepare("SELECT value, COUNT(*) AS 'count' FROM userproplite2 up " .
|
||||
"LEFT JOIN clustertrack2 c ON up.userid=c.userid " .
|
||||
"WHERE up.upropid=? AND up.userid BETWEEN $low AND $high " .
|
||||
"AND (c.clusterid IS NULL OR c.clusterid=?) GROUP BY 1");
|
||||
$sth->execute($upg->{'id'}, $cid);
|
||||
die "clusterid: $cid, " . $db->errstr if $db->err;
|
||||
|
||||
while ($_ = $sth->fetchrow_hashref) {
|
||||
$ret{$_->{'value'}} += $_->{'count'};
|
||||
}
|
||||
|
||||
print LJ::Stats::block_status_line($block, $blocks);
|
||||
}
|
||||
|
||||
return \%ret;
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
# run stats
|
||||
LJ::Stats::run_stats(@which);
|
||||
|
||||
#### dump to text file
|
||||
print "-I- Dumping to a text file.\n";
|
||||
|
||||
{
|
||||
my $dbh = LJ::Stats::get_db("dbh");
|
||||
my $sth = $dbh->prepare("SELECT statcat, statkey, statval FROM stats ORDER BY 1, 2");
|
||||
$sth->execute;
|
||||
die $dbh->errstr if $dbh->err;
|
||||
|
||||
open (OUT, ">$LJ::HTDOCS/stats/stats.txt");
|
||||
while (my @row = $sth->fetchrow_array) {
|
||||
next if grep { $row[0] eq $_ } @LJ::PRIVATE_STATS;
|
||||
print OUT join("\t", @row), "\n";
|
||||
}
|
||||
close OUT;
|
||||
}
|
||||
|
||||
print "-I- Done.\n";
|
||||
|
||||
};
|
||||
|
||||
$maint{'genstats_size'} = sub {
|
||||
|
||||
LJ::Stats::register_stat
|
||||
({ 'type' => "global",
|
||||
'jobname' => "size-accounts",
|
||||
'statname' => "size",
|
||||
'handler' =>
|
||||
sub {
|
||||
my $db_getter = shift;
|
||||
return undef unless ref $db_getter eq 'CODE';
|
||||
my $db = $db_getter->();
|
||||
return undef unless $db;
|
||||
|
||||
my $tsql = "SELECT MAX(userid) FROM user";
|
||||
$tsql .= " where userid < " . $LJ::LJR_IMPORTED_USERIDS if $LJ::LJR_IMPORTED_USERIDS;
|
||||
|
||||
# not that this isn't a total of current accounts (some rows may have
|
||||
# been deleted), but rather a total of accounts ever created
|
||||
my $size = $db->selectrow_array($tsql);
|
||||
return { 'accounts' => $size };
|
||||
},
|
||||
});
|
||||
|
||||
LJ::Stats::register_stat
|
||||
({ 'type' => "clustered",
|
||||
'jobname' => "size-accounts_active",
|
||||
'statname' => "size",
|
||||
'handler' =>
|
||||
sub {
|
||||
my $db_getter = shift;
|
||||
return undef unless ref $db_getter eq 'CODE';
|
||||
my $db = $db_getter->();
|
||||
return undef unless $db;
|
||||
|
||||
my $period = 30; # one month is considered active
|
||||
my $active = $db->selectrow_array
|
||||
("SELECT COUNT(*) FROM clustertrack2 WHERE ".
|
||||
"timeactive > UNIX_TIMESTAMP()-86400*$period");
|
||||
|
||||
return { 'accounts_active' => $active };
|
||||
},
|
||||
});
|
||||
|
||||
print "-I- Generating account size stats.\n";
|
||||
LJ::Stats::run_stats("size-accounts", "size-accounts_active");
|
||||
print "-I- Done.\n";
|
||||
};
|
||||
|
||||
|
||||
$maint{'genstats_weekly'} = sub
|
||||
{
|
||||
LJ::Stats::register_stat
|
||||
({ 'type' => "global",
|
||||
'jobname' => "supportrank",
|
||||
'statname' => "supportrank",
|
||||
'handler' =>
|
||||
sub {
|
||||
my $db_getter = shift;
|
||||
return undef unless ref $db_getter eq 'CODE';
|
||||
my $db = $db_getter->();
|
||||
return undef unless $db;
|
||||
|
||||
my %supportrank;
|
||||
my $rank = 0;
|
||||
my $lastpoints = 0;
|
||||
my $buildup = 0;
|
||||
|
||||
my $sth = $db->prepare
|
||||
("SELECT u.userid, SUM(sp.points) AS 'points' " .
|
||||
"FROM user u, supportpoints sp " .
|
||||
"WHERE u.userid=sp.userid GROUP BY 1 ORDER BY 2 DESC");
|
||||
$sth->execute;
|
||||
die $db->errstr if $db->err;
|
||||
|
||||
while ($_ = $sth->fetchrow_hashref) {
|
||||
if ($lastpoints != $_->{'points'}) {
|
||||
$lastpoints = $_->{'points'};
|
||||
$rank += (1 + $buildup);
|
||||
$buildup = 0;
|
||||
} else {
|
||||
$buildup++;
|
||||
}
|
||||
$supportrank{$_->{'userid'}} = $rank;
|
||||
}
|
||||
|
||||
# move old 'supportrank' stat to supportrank_prev
|
||||
# no API for this :-/
|
||||
{
|
||||
my $dbh = LJ::Stats::get_db("dbh");
|
||||
$dbh->do("DELETE FROM stats WHERE statcat='supportrank_prev'");
|
||||
$dbh->do("UPDATE stats SET statcat='supportrank_prev' WHERE statcat='supportrank'");
|
||||
}
|
||||
|
||||
return \%supportrank;
|
||||
}
|
||||
});
|
||||
|
||||
print "-I- Generating weekly stats.\n";
|
||||
LJ::Stats::run_stats('supportrank');
|
||||
print "-I- Done.\n";
|
||||
};
|
||||
|
||||
$maint{'build_randomuserset'} = sub
|
||||
{
|
||||
## this sets up the randomuserset table daily (or whenever) that htdocs/random.bml uses to
|
||||
## find a random user that is both 1) publicly listed in the directory, and 2) updated
|
||||
## within the past 24 hours.
|
||||
|
||||
## note that if a user changes their privacy setting to not be in the database, it'll take
|
||||
## up to 24 hours for them to be removed from the random.bml listing, but that's acceptable.
|
||||
|
||||
my $dbh = LJ::get_db_writer();
|
||||
|
||||
print "-I- Building randomuserset.\n";
|
||||
$dbh->do("TRUNCATE TABLE randomuserset");
|
||||
$dbh->do("REPLACE INTO randomuserset (userid) " .
|
||||
"SELECT uu.userid FROM userusage uu, user u " .
|
||||
"WHERE u.userid=uu.userid AND u.allow_infoshow='Y' " .
|
||||
"AND uu.timeupdate > DATE_SUB(NOW(), INTERVAL 1 DAY) ORDER BY RAND() LIMIT 5000");
|
||||
my $num = $dbh->selectrow_array("SELECT MAX(rid) FROM randomuserset");
|
||||
$dbh->do("REPLACE INTO stats (statcat, statkey, statval) " .
|
||||
"VALUES ('userinfo', 'randomcount', $num)");
|
||||
|
||||
print "-I- Done.\n";
|
||||
};
|
||||
|
||||
$maint{'memeclean'} = sub
|
||||
{
|
||||
my $dbh = LJ::get_db_writer();
|
||||
|
||||
print "-I- Cleaning memes.\n";
|
||||
my $sth = $dbh->prepare("SELECT statkey FROM stats WHERE statcat='popmeme'");
|
||||
$sth->execute;
|
||||
die $dbh->errstr if $dbh->err;
|
||||
|
||||
while (my $url = $sth->fetchrow_array) {
|
||||
my $copy = $url;
|
||||
LJ::run_hooks("canonicalize_url", \$copy);
|
||||
unless ($copy) {
|
||||
my $d = $dbh->quote($url);
|
||||
$dbh->do("DELETE FROM stats WHERE statcat='popmeme' AND statkey=$d");
|
||||
print " deleting: $url\n";
|
||||
}
|
||||
}
|
||||
print "-I- Done.\n";
|
||||
};
|
||||
|
||||
1;
|
||||
655
local/bin/maint/synsuck.pl
Executable file
655
local/bin/maint/synsuck.pl
Executable file
@@ -0,0 +1,655 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
|
||||
use strict;
|
||||
use vars qw(%maint %maintinfo);
|
||||
use lib "$ENV{'LJHOME'}/cgi-bin"; # extra XML::Encoding files in cgi-bin/XML/*
|
||||
use LWP::UserAgent;
|
||||
use XML::RSS;
|
||||
use HTTP::Status;
|
||||
use Image::Size;
|
||||
require "ljprotocol.pl";
|
||||
require "parsefeed.pl";
|
||||
require "cleanhtml.pl";
|
||||
require "talklib.pl";
|
||||
require LWPx::ParanoidAgent;
|
||||
require LJR::unicode;
|
||||
|
||||
use utf8;
|
||||
binmode STDOUT, ":utf8";
|
||||
|
||||
my $dumpxml = sub {
|
||||
my ($xdata, $username) = @_;
|
||||
|
||||
open(my $outfile, ">$ENV{'LJHOME'}/logs/syn_err_" . $username . ".xml");
|
||||
print $outfile "$xdata";
|
||||
close($outfile);
|
||||
};
|
||||
|
||||
my $err = sub {
|
||||
my ($msg) = @_;
|
||||
print $msg . "\n";
|
||||
return;
|
||||
};
|
||||
|
||||
my $get_picture = sub {
|
||||
my ($userid, $url) = @_;
|
||||
|
||||
my $MAX_UPLOAD = 102400;
|
||||
|
||||
my $ua = LWPx::ParanoidAgent->new(timeout => 30, max_size => $MAX_UPLOAD + 1024);
|
||||
$ua->agent("Synsuck::Userpic; $LJ::SITENAME; $LJ::ADMIN_EMAIL");
|
||||
|
||||
my $res = $ua->get($url);
|
||||
my $picdata = $res->content;
|
||||
|
||||
return $err->("some error while getting userpic") if !($res && $res->is_success);
|
||||
return $err->("404 while getting userpic") if ($res && $res->{"_rc"} eq 404);
|
||||
return $err->("userpic size is bigger than we want") if length($picdata) > $MAX_UPLOAD;
|
||||
|
||||
my ($sx, $sy, $filetype) = Image::Size::imgsize(\$picdata);
|
||||
return $err->("can't ge userpic size") unless defined $sx;
|
||||
return $err->("unknown userpic filetype") unless $filetype eq "GIF" || $filetype eq "JPG" || $filetype eq "PNG";
|
||||
return $err->("userpic is bigger than we want") if $sx > 150 || $sy > 150;
|
||||
|
||||
my $contenttype;
|
||||
if ($filetype eq "GIF") { $contenttype = 'G'; }
|
||||
elsif ($filetype eq "PNG") { $contenttype = 'P'; }
|
||||
elsif ($filetype eq "JPG") { $contenttype = 'J'; }
|
||||
|
||||
my $base64 = Digest::MD5::md5_base64($picdata);
|
||||
|
||||
my $picid = LJ::alloc_global_counter('P') or return;
|
||||
|
||||
my $dbh = LJ::get_db_writer();
|
||||
$dbh->do(
|
||||
"INSERT INTO userpic2" .
|
||||
"(picid, userid, fmt, width, height, picdate, md5base64, location, state, url) " .
|
||||
"VALUES (?, ?, ?, ?, ?, NOW(), ?, ?, 'N', ?)",
|
||||
undef, $picid, $userid, $contenttype, $sx, $sy, $base64, undef, $url);
|
||||
$dbh->do(
|
||||
"INSERT INTO userpicblob2 (userid, picid, imagedata) VALUES (?,?,?)",
|
||||
undef, $userid, $picid, $picdata);
|
||||
|
||||
my $su = LJ::load_userid($userid);
|
||||
LJ::update_user($su, { defaultpicid => $picid });
|
||||
};
|
||||
|
||||
$maintinfo{'synsuck'}{opts}{locking} = "per_host";
|
||||
$maint{'synsuck'} = sub
|
||||
{
|
||||
my $maxcount = shift || 0;
|
||||
my $verbose = $LJ::LJMAINT_VERBOSE;
|
||||
|
||||
my %child_jobs; # child pid => [ userid, lock ]
|
||||
|
||||
my $process_user = sub {
|
||||
my $urow = shift;
|
||||
return unless $urow;
|
||||
|
||||
my ($user, $userid, $synurl, $lastmod, $etag, $lastmod_feed, $readers) =
|
||||
map { $urow->{$_} } qw(user userid synurl lastmod etag lastmod_feed numreaders);
|
||||
|
||||
# we're a child process now, need to invalidate caches and
|
||||
# get a new database handle
|
||||
LJ::start_request();
|
||||
|
||||
my $dbh = LJ::get_db_writer();
|
||||
|
||||
# see if things have changed since we last looked and acquired the lock.
|
||||
# otherwise we could 1) check work, 2) get lock, and between 1 and 2 another
|
||||
# process could do both steps. we don't want to duplicate work already done.
|
||||
my $now_checknext = $dbh->selectrow_array("SELECT checknext FROM syndicated ".
|
||||
"WHERE userid=?", undef, $userid);
|
||||
return if $now_checknext ne $urow->{checknext};
|
||||
|
||||
my $ua = LWP::UserAgent->new("timeout" => 30);
|
||||
my $reader_info = $readers ? "; $readers readers" : "";
|
||||
$ua->agent("$LJ::SITENAME ($LJ::ADMIN_EMAIL; for $LJ::SITEROOT/users/$user/" . $reader_info . ")");
|
||||
|
||||
my $delay = sub {
|
||||
my $minutes = shift;
|
||||
my $status = shift;
|
||||
|
||||
# add some random backoff to avoid waves building up
|
||||
$minutes += int(rand(5));
|
||||
|
||||
$dbh->do("UPDATE syndicated SET lastcheck=NOW(), checknext=DATE_ADD(NOW(), ".
|
||||
"INTERVAL ? MINUTE), laststatus=? WHERE userid=?",
|
||||
undef, $minutes, $status, $userid);
|
||||
};
|
||||
|
||||
print "[$$] Synsuck: fetching $user ($synurl)\n" if $verbose;
|
||||
|
||||
my $req = HTTP::Request->new("GET", $synurl);
|
||||
$req->header('If-Modified-Since', $lastmod)
|
||||
if $lastmod;
|
||||
$req->header('If-None-Match', $etag)
|
||||
if $etag;
|
||||
|
||||
my ($content, $too_big);
|
||||
my $max_size = $LJ::SYNSUCK_MAX_SIZE || 500; # in kb
|
||||
my $res = eval {
|
||||
$ua->request($req, sub {
|
||||
if (length($content) > 1024*$max_size) { $too_big = 1; return; }
|
||||
$content .= $_[0];
|
||||
}, 4096);
|
||||
};
|
||||
if ($@) { $delay->(120, "lwp_death"); return; }
|
||||
if ($too_big) { $delay->(60, "toobig"); return; }
|
||||
|
||||
if ($res->is_error()) {
|
||||
# http error
|
||||
print " HTTP error! " . $res->status_line() . "\n" if $verbose;
|
||||
|
||||
$delay->(3*60, "httperror");
|
||||
|
||||
# overload rssparseerror here because it's already there -- we'll
|
||||
# never have both an http error and a parse error on the
|
||||
# same request
|
||||
|
||||
LJ::set_userprop($userid, "rssparseerror", $res->status_line());
|
||||
return;
|
||||
}
|
||||
|
||||
# check if not modified
|
||||
if ($res->code() == RC_NOT_MODIFIED) {
|
||||
print " not modified.\n" if $verbose;
|
||||
$delay->($readers ? 30 : 12*60, "notmodified");
|
||||
return;
|
||||
}
|
||||
|
||||
my $r_lastmod = $res->header('Last-Modified');
|
||||
my $r_etag = $res->header('ETag');
|
||||
|
||||
# check again (feedburner.com, blogspot.com, etc.)
|
||||
if (($etag && $etag eq $r_etag) || ($lastmod && $lastmod eq $r_lastmod)) {
|
||||
print " not modified.\n" if $verbose;
|
||||
$delay->($readers ? 30 : 12*60, "notmodified");
|
||||
return;
|
||||
}
|
||||
|
||||
# force utf8; this helps from time to time ???
|
||||
LJR::unicode::force_utf8(\$content);
|
||||
|
||||
# parsing time...
|
||||
my ($feed, $error) = LJ::ParseFeed::parse_feed($content);
|
||||
if ($error) {
|
||||
# parse error!
|
||||
print "Parse error! $error\n" if $verbose;
|
||||
$delay->(3*60, "parseerror");
|
||||
$error =~ s! at /.*!!;
|
||||
$error =~ s/^\n//; # cleanup of newline at the beggining of the line
|
||||
LJ::set_userprop($userid, "rssparseerror", $error);
|
||||
$dumpxml->($content, $user);
|
||||
return;
|
||||
}
|
||||
|
||||
my $r_lastmod_feed = $feed->{'lastmod'};
|
||||
my $r_lastmod_lastBuildDate = $feed->{'lastBuildDate'};
|
||||
|
||||
print " $lastmod \n $r_lastmod \n $etag \n $r_etag \n $lastmod_feed \n $r_lastmod_feed \n $r_lastmod_lastBuildDate \n ";
|
||||
|
||||
# check last-modified for bogus web-servers
|
||||
if ($lastmod_feed && $lastmod_feed eq $r_lastmod_feed) {
|
||||
print " not modified..\n" if $verbose;
|
||||
$delay->($readers ? 30 : 12*60, "notmodified");
|
||||
return;
|
||||
}
|
||||
|
||||
# print " $lastmod \n $r_lastmod \n $etag \n $r_etag \n $lastmod_feed \n $r_lastmod_feed \n $r_lastmod_lastBuildDate \n ";
|
||||
|
||||
# another sanity check
|
||||
unless (ref $feed->{'items'} eq "ARRAY") {
|
||||
$delay->(3*60, "noitems");
|
||||
return;
|
||||
}
|
||||
|
||||
# update userpic
|
||||
my $cur_pic = $dbh->selectrow_array(
|
||||
"SELECT url FROM userpic2, user WHERE user.userid=? and
|
||||
userpic2.userid=user.userid and userpic2.picid=user.defaultpicid",
|
||||
undef, $userid);
|
||||
if (
|
||||
($feed->{'image'} && $cur_pic && $cur_pic ne $feed->{'image'}) ||
|
||||
($feed->{'image'} && !$cur_pic)
|
||||
) {
|
||||
$dbh->do("delete from userpic2 WHERE userid=?", undef, $userid);
|
||||
$dbh->do("delete from userpicblob2 WHERE userid=?", undef, $userid);
|
||||
$dbh->do("update user set user.defaultpicid=NULL where userid=?", undef, $userid);
|
||||
|
||||
print "[$$] Synsuck: $user -- trying to fetch userpic from: " .
|
||||
$feed->{'image'} . " \n" if $verbose;
|
||||
|
||||
$get_picture->($userid, $feed->{'image'});
|
||||
}
|
||||
|
||||
my @items = reverse @{$feed->{'items'}};
|
||||
|
||||
|
||||
# delete existing items older than the age which can show on a
|
||||
# friends view.
|
||||
my $su = LJ::load_userid($userid);
|
||||
my $udbh = LJ::get_cluster_master($su);
|
||||
unless ($udbh) {
|
||||
$delay->(15, "nodb");
|
||||
return;
|
||||
}
|
||||
|
||||
# TAG:LOG2:synsuck_delete_olderitems
|
||||
# my $secs = ($LJ::MAX_FRIENDS_VIEW_AGE || 3600*24*14)+0; # 2 week default.
|
||||
# my $sth = $udbh->prepare("SELECT jitemid, anum FROM log2 WHERE journalid=? AND ".
|
||||
# "logtime < DATE_SUB(NOW(), INTERVAL $secs SECOND)");
|
||||
# $sth->execute($userid);
|
||||
# die $udbh->errstr if $udbh->err;
|
||||
# while (my ($jitemid, $anum) = $sth->fetchrow_array) {
|
||||
# print "DELETE itemid: $jitemid, anum: $anum... \n" if $verbose;
|
||||
# if (LJ::delete_entry($su, $jitemid, 0, $anum)) {
|
||||
# print "success.\n" if $verbose;
|
||||
# } else {
|
||||
# print "fail.\n" if $verbose;
|
||||
# }
|
||||
# }
|
||||
|
||||
|
||||
my $count = $udbh->selectrow_array("SELECT COUNT(*) FROM log2 WHERE journalid=$userid");
|
||||
print "count = $count \n";
|
||||
|
||||
my $extra = $count - $LJ::MAX_SCROLLBACK_FRIENDS_SINGLE_USER_ACTIVITY;
|
||||
if ($extra > 0) {
|
||||
my $sth = $udbh->prepare("SELECT jitemid FROM logprop2 WHERE journalid=$userid".
|
||||
" ORDER BY jitemid ASC LIMIT $extra");
|
||||
$sth->execute();
|
||||
while (my ($jitemid) = $sth->fetchrow_array) {
|
||||
|
||||
print "DELETE itemid: $jitemid... \n" if $verbose;
|
||||
if (LJ::delete_entry($su, $jitemid)) {
|
||||
print "success.\n" if $verbose;
|
||||
} else {
|
||||
print "fail.\n" if $verbose;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# determine if link tags are good or not, where good means
|
||||
# "likely to be a unique per item". some feeds have the same
|
||||
# <link> element for each item, which isn't good.
|
||||
# if we have unique ids, we don't compare link tags
|
||||
|
||||
my ($compare_links, $have_ids) = 0;
|
||||
{
|
||||
my %link_seen;
|
||||
foreach my $it (@items) {
|
||||
$have_ids = 1 if $it->{'id'};
|
||||
next unless $it->{'link'};
|
||||
$link_seen{$it->{'link'}} = 1;
|
||||
}
|
||||
$compare_links = 1 if !$have_ids and $feed->{'type'} eq 'rss' and
|
||||
scalar(keys %link_seen) == scalar(@items);
|
||||
}
|
||||
|
||||
# if we have unique links/ids, load them for syndicated
|
||||
# items we already have on the server. then, if we have one
|
||||
# already later and see it's changed, we'll do an editevent
|
||||
# instead of a new post.
|
||||
my %existing_item = ();
|
||||
if ($have_ids || $compare_links) {
|
||||
my $p = $have_ids ? LJ::get_prop("log", "syn_id") :
|
||||
LJ::get_prop("log", "syn_link");
|
||||
my $sth = $udbh->prepare("SELECT jitemid, value FROM logprop2 WHERE ".
|
||||
"journalid=? AND propid=? ORDER BY jitemid DESC LIMIT 1000"); # need last 100
|
||||
$sth->execute($su->{'userid'}, $p->{'id'});
|
||||
|
||||
while (my ($jitemid, $id) = $sth->fetchrow_array) {
|
||||
|
||||
if (!defined $existing_item{$id}) {
|
||||
$existing_item{$id} = $jitemid;
|
||||
# print "Got it: $jitemid, $id\n" if $verbose;
|
||||
} else {
|
||||
# remove duplicates - if any:
|
||||
print "DELETE duplicated itemid: $jitemid, $id ...\n" if $verbose;
|
||||
if (LJ::delete_entry($su, $jitemid)) {
|
||||
print "success.\n" if $verbose;
|
||||
} else {
|
||||
print "fail.\n" if $verbose;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# post these items
|
||||
my $newcount = 0;
|
||||
my $errorflag = 0;
|
||||
my $mindate; # "yyyy-mm-dd hh:mm:ss";
|
||||
my $notedate = sub {
|
||||
my $date = shift;
|
||||
$mindate = $date if ! $mindate || $date lt $mindate;
|
||||
};
|
||||
|
||||
LJ::load_user_props($su, { use_master => 1 }, "newesteventtime");
|
||||
### if ($su->{'newesteventtime'} eq $oldevent->{'eventtime'}) {
|
||||
### LJ::set_userprop($su, "newesteventtime", undef);
|
||||
### }
|
||||
|
||||
foreach my $it (@items) {
|
||||
|
||||
if ($it->{'time'} && $it->{'time'} lt $su->{'newesteventtime'}) {
|
||||
## print "---- " . $it->{'subject'} . "\n" if $verbose;
|
||||
next;
|
||||
} elsif ($it->{'time'} && $it->{'time'} eq $su->{'newesteventtime'}) {
|
||||
print "==== " . $it->{'subject'} . "\n" if $verbose;
|
||||
} else {
|
||||
print "++++ " . $it->{'subject'} . "\n" if $verbose;
|
||||
}
|
||||
|
||||
|
||||
my $dig = LJ::md5_struct($it)->b64digest;
|
||||
my $prevadd = $dbh->selectrow_array("SELECT MAX(dateadd) FROM synitem WHERE ".
|
||||
"userid=? AND item=?", undef,
|
||||
$userid, $dig);
|
||||
if ($prevadd) {
|
||||
$notedate->($prevadd);
|
||||
next;
|
||||
}
|
||||
|
||||
my $now_dateadd = $dbh->selectrow_array("SELECT NOW()");
|
||||
die "unexpected format" unless $now_dateadd =~ /^\d\d\d\d\-\d\d\-\d\d \d\d:\d\d:\d\d$/;
|
||||
|
||||
$dbh->do("INSERT INTO synitem (userid, item, dateadd) VALUES (?,?,?)",
|
||||
undef, $userid, $dig, $now_dateadd);
|
||||
$notedate->($now_dateadd);
|
||||
|
||||
$newcount++;
|
||||
print "[$$] $dig - $it->{'subject'}\n" if $verbose;
|
||||
$it->{'text'} =~ s/^\s+//;
|
||||
$it->{'text'} =~ s/\s+$//;
|
||||
|
||||
# process lj-cuts
|
||||
while ($it->{'text'} =~ /\G(.*?)<a\ name\=\"cutid(\d+)\"\>\<\/a\>(.*)/sg) {
|
||||
my $before = $1;
|
||||
my $cutid = $2;
|
||||
my $rcut = $3;
|
||||
$rcut =~ s/<a\ name\=\"cutid$cutid\"\>\<\/a\>/\<\/lj\-cut\>/;
|
||||
$it->{'text'} = $before . "<lj-cut>" . $rcut;
|
||||
}
|
||||
|
||||
my $htmllink;
|
||||
if (defined $it->{'link'}) {
|
||||
$htmllink = "<p class='ljsyndicationlink'>" .
|
||||
"<a href='$it->{'link'}'>$it->{'link'}</a></p>";
|
||||
}
|
||||
|
||||
# Show the <guid> link if it's present and different than the
|
||||
# <link>.
|
||||
# [zilla: 267] Patch: Chaz Meyers <lj-zilla@thechaz.net>
|
||||
if ( defined $it->{'id'} && $it->{'id'} ne $it->{'link'}
|
||||
&& $it->{'id'} =~ m!^http://! )
|
||||
{
|
||||
$htmllink .= "<p class='ljsyndicationlink'>" .
|
||||
"<a href='$it->{'id'}'>$it->{'id'}</a></p>";
|
||||
}
|
||||
|
||||
# rewrite relative URLs to absolute URLs, but only invoke the HTML parser
|
||||
# if we see there's some image or link tag, to save us some work if it's
|
||||
# unnecessary (the common case)
|
||||
if ($it->{'text'} =~ /<(?:img|a)\b/i) {
|
||||
# TODO: support XML Base? http://www.w3.org/TR/xmlbase/
|
||||
my $base_href = $it->{'link'} || $synurl;
|
||||
LJ::CleanHTML::resolve_relative_urls(\$it->{'text'}, $base_href);
|
||||
}
|
||||
|
||||
|
||||
|
||||
# $own_time==1 means we took the time from the feed rather than localtime
|
||||
my ($own_time, $year, $mon, $day, $hour, $min);
|
||||
|
||||
if ($it->{'time'} &&
|
||||
$it->{'time'} =~ m!^(\d\d\d\d)-(\d\d)-(\d\d) (\d\d):(\d\d)!) {
|
||||
$own_time = 1;
|
||||
($year, $mon, $day, $hour, $min) = ($1,$2,$3,$4,$5);
|
||||
} else {
|
||||
$own_time = 0;
|
||||
my @now = localtime();
|
||||
($year, $mon, $day, $hour, $min) =
|
||||
($now[5]+1900, $now[4]+1, $now[3], $now[2], $now[1]);
|
||||
}
|
||||
|
||||
|
||||
my $command = "postevent";
|
||||
my $req = {
|
||||
'username' => $user,
|
||||
'ver' => 1,
|
||||
'subject' => $it->{'subject'},
|
||||
'event' => "$it->{'text'}",
|
||||
'year' => $year,
|
||||
'mon' => $mon,
|
||||
'day' => $day,
|
||||
'hour' => $hour,
|
||||
'min' => $min,
|
||||
'props' => {
|
||||
'syn_link' => $it->{'link'},
|
||||
'opt_nocomments' => 1,
|
||||
},
|
||||
};
|
||||
$req->{'props'}->{'syn_id'} = $it->{'id'}
|
||||
if $it->{'id'};
|
||||
|
||||
my $flags = {
|
||||
'nopassword' => 1,
|
||||
};
|
||||
|
||||
# if the post contains html linebreaks, assume it's preformatted.
|
||||
if ($it->{'text'} =~ /<(?:p|br)\b/i) {
|
||||
$req->{'props'}->{'opt_preformatted'} = 1;
|
||||
}
|
||||
|
||||
# do an editevent if we've seen this item before
|
||||
my $id = $have_ids ? $it->{'id'} : $it->{'link'};
|
||||
my $old_itemid = $existing_item{$id};
|
||||
if ($id && $old_itemid) {
|
||||
$newcount--; # cancel increment above
|
||||
$command = "editevent";
|
||||
$req->{'itemid'} = $old_itemid;
|
||||
|
||||
# the editevent requires us to resend the date info, which
|
||||
# we have to go fetch first, in case the feed doesn't have it
|
||||
|
||||
# TAG:LOG2:synsuck_fetch_itemdates
|
||||
unless($own_time) {
|
||||
my $origtime =
|
||||
$udbh->selectrow_array("SELECT eventtime FROM log2 WHERE ".
|
||||
"journalid=? AND jitemid=?", undef,
|
||||
$su->{'userid'}, $old_itemid);
|
||||
$origtime =~ /(\d\d\d\d)-(\d\d)-(\d\d) (\d\d):(\d\d)/;
|
||||
$req->{'year'} = $1;
|
||||
$req->{'mon'} = $2;
|
||||
$req->{'day'} = $3;
|
||||
$req->{'hour'} = $4;
|
||||
$req->{'min'} = $5;
|
||||
}
|
||||
}
|
||||
|
||||
my $err;
|
||||
|
||||
my $res = LJ::Protocol::do_request($command, $req, \$err, $flags);
|
||||
|
||||
unless ($res && ! $err) {
|
||||
print " Error: $err\n" if $verbose;
|
||||
$errorflag = 1;
|
||||
}
|
||||
}
|
||||
|
||||
# delete some unneeded synitems. the limit 1000 is because
|
||||
# historically we never deleted and there are accounts with
|
||||
# 222,000 items on a myisam table, and that'd be quite the
|
||||
# delete hit.
|
||||
# the 14 day interval is because if a remote site deleted an
|
||||
# entry, it's possible for the oldest item that was previously
|
||||
# gone to reappear, and we want to protect against that a
|
||||
# little.
|
||||
if ($LJ::SYNITEM_CLEAN) {
|
||||
$dbh->do("DELETE FROM synitem WHERE userid=? AND ".
|
||||
"dateadd < ? - INTERVAL 14 DAY LIMIT 1000",
|
||||
undef, $userid, $mindate);
|
||||
}
|
||||
$dbh->do("UPDATE syndicated SET oldest_ourdate=? WHERE userid=?",
|
||||
undef, $mindate, $userid);
|
||||
|
||||
# bail out if errors, and try again shortly
|
||||
if ($errorflag) {
|
||||
$delay->(30, "posterror");
|
||||
return;
|
||||
}
|
||||
|
||||
# update syndicated account's userinfo if necessary
|
||||
LJ::load_user_props($su, "url", "urlname");
|
||||
{
|
||||
my $title = $feed->{'title'};
|
||||
$title = $su->{'user'} unless LJ::is_utf8($title);
|
||||
$title =~ s/[\n\r]//g;
|
||||
if ($title && $title ne $su->{'name'}) {
|
||||
LJ::update_user($su, { name => $title });
|
||||
}
|
||||
if ($title) {
|
||||
LJ::set_userprop($su, "urlname", $title);
|
||||
} else {
|
||||
LJ::set_userprop($su, "urlname", $su->{'url'});
|
||||
}
|
||||
|
||||
my $link = $feed->{'link'};
|
||||
if ($link && $link ne $su->{'url'}) {
|
||||
LJ::set_userprop($su, "url", $link);
|
||||
}
|
||||
|
||||
my $des = $feed->{'description'};
|
||||
if ($des) {
|
||||
my $bio;
|
||||
if ($su->{'has_bio'} eq "Y") {
|
||||
$bio = $udbh->selectrow_array("SELECT bio FROM userbio WHERE userid=?", undef,
|
||||
$su->{'userid'});
|
||||
}
|
||||
if ($bio ne $des && $bio !~ /\[LJ:KEEP\]/) {
|
||||
if ($des) {
|
||||
$su->do("REPLACE INTO userbio (userid, bio) VALUES (?,?)", undef,
|
||||
$su->{'userid'}, $des);
|
||||
} else {
|
||||
$su->do("DELETE FROM userbio WHERE userid=?", undef, $su->{'userid'});
|
||||
}
|
||||
LJ::update_user($su, { has_bio => ($des ? "Y" : "N") });
|
||||
LJ::MemCache::delete([$su->{'userid'}, "bio:$su->{'userid'}"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# decide when to poll next (in minutes).
|
||||
# FIXME: this is super lame. (use hints in RSS file!)
|
||||
my $int = $newcount ? 15 : 30;
|
||||
my $status = $newcount ? "ok" : "nonew";
|
||||
my $updatenew = $newcount ? ", lastnew=NOW()" : "";
|
||||
|
||||
# update reader count while we're changing things, but not
|
||||
# if feed is stale (minimize DB work for inactive things)
|
||||
if ($newcount || ! defined $readers) {
|
||||
$readers = $dbh->selectrow_array("SELECT COUNT(*) FROM friends WHERE ".
|
||||
"friendid=?", undef, $userid);
|
||||
}
|
||||
|
||||
# if readers are gone, don't check for a whole day
|
||||
$int = 60*24 if $readers && $readers < 2 || !$readers;
|
||||
|
||||
$dbh->do("UPDATE syndicated SET checknext=DATE_ADD(NOW(), INTERVAL $int MINUTE), ".
|
||||
"lastcheck=NOW(), lastmod=?, etag=?, lastmod_feed=? , laststatus=?, numreaders=? $updatenew ".
|
||||
"WHERE userid=$userid", undef, $r_lastmod, $r_etag, $r_lastmod_feed, $status, $readers);
|
||||
};
|
||||
|
||||
###
|
||||
### child process management
|
||||
###
|
||||
|
||||
# get the next user to be processed
|
||||
my @all_users;
|
||||
my $get_next_user = sub {
|
||||
return shift @all_users if @all_users;
|
||||
|
||||
# need to get some more rows
|
||||
my $dbh = LJ::get_db_writer();
|
||||
my $current_jobs = join(",", map { $dbh->quote($_->[0]) } values %child_jobs);
|
||||
my $in_sql = " AND u.userid NOT IN ($current_jobs)" if $current_jobs;
|
||||
my $sth = $dbh->prepare("SELECT u.user, s.userid, s.synurl, s.lastmod, " .
|
||||
" s.etag, s.lastmod_feed, s.numreaders, s.checknext " .
|
||||
"FROM user u, syndicated s " .
|
||||
"WHERE u.userid=s.userid AND u.statusvis='V' " .
|
||||
"AND s.checknext < NOW()$in_sql " .
|
||||
"ORDER BY RAND() LIMIT 500");
|
||||
$sth->execute;
|
||||
while (my $urow = $sth->fetchrow_hashref) {
|
||||
push @all_users, $urow;
|
||||
}
|
||||
|
||||
return undef unless @all_users;
|
||||
return shift @all_users;
|
||||
};
|
||||
|
||||
# fork and manage child processes
|
||||
my $max_threads = $LJ::SYNSUCK_MAX_THREADS || 1;
|
||||
print "[$$] PARENT -- using $max_threads workers\n" if $verbose;
|
||||
|
||||
my $threads = 0;
|
||||
my $userct = 0;
|
||||
my $keep_forking = 1;
|
||||
while ( $maxcount == 0 || $userct < $maxcount ) {
|
||||
|
||||
if ($threads < $max_threads && $keep_forking) {
|
||||
my $urow = $get_next_user->();
|
||||
unless ($urow) {
|
||||
$keep_forking = 0;
|
||||
next;
|
||||
}
|
||||
|
||||
my $lockname = "synsuck-user-" . $urow->{user};
|
||||
my $lock = LJ::locker()->trylock($lockname);
|
||||
next unless $lock;
|
||||
print "Got lock on '$lockname'. Running\n" if $verbose;
|
||||
|
||||
# spawn a new process
|
||||
if (my $pid = fork) {
|
||||
# we are a parent, nothing to do?
|
||||
$child_jobs{$pid} = [$urow->{'userid'}, $lock];
|
||||
$threads++;
|
||||
$userct++;
|
||||
} else {
|
||||
# handles won't survive the fork
|
||||
LJ::disconnect_dbs();
|
||||
$process_user->($urow);
|
||||
exit 0;
|
||||
}
|
||||
|
||||
# wait for child(ren) to die
|
||||
} else {
|
||||
my $child = wait();
|
||||
last if $child == -1;
|
||||
delete $child_jobs{$child};
|
||||
$threads--;
|
||||
}
|
||||
}
|
||||
|
||||
# Now wait on any remaining children so we don't leave zombies behind.
|
||||
while ( %child_jobs ) {
|
||||
my $child = wait();
|
||||
last if $child == -1;
|
||||
delete $child_jobs{ $child };
|
||||
$threads--;
|
||||
}
|
||||
|
||||
print "[$$] $userct users processed\n" if $verbose;
|
||||
return;
|
||||
};
|
||||
|
||||
1;
|
||||
|
||||
|
||||
# Local Variables:
|
||||
# mode: perl
|
||||
# c-basic-indent: 4
|
||||
# indent-tabs-mode: nil
|
||||
# End:
|
||||
30
local/bin/maint/taskinfo.txt
Executable file
30
local/bin/maint/taskinfo.txt
Executable file
@@ -0,0 +1,30 @@
|
||||
bday.pl:
|
||||
bdaymail - Sends people birthday wishes & notifications
|
||||
|
||||
stats.pl:
|
||||
build_randomuserset - builds/cleans table of users applicable for inclusion in random listings
|
||||
genstats - Generates the nightly statistics
|
||||
genstats_size - Generates the site size stats
|
||||
genstats_weekly - Generates the weekly statistics
|
||||
memeclean - Removes things from meme summary that are excluded by new URL cleaner rules
|
||||
|
||||
statspics.pl:
|
||||
genstatspics - Makes a bunch of graphs to show on the statistics page.
|
||||
|
||||
clean_caches.pl:
|
||||
clean_caches - removes old cache files
|
||||
|
||||
synsuck.pl:
|
||||
synsuck - Polls needed remote, syndicated RSS/etc and updates journals.
|
||||
|
||||
captcha.pl:
|
||||
gen_audio_captchas - Generate any needed new audio challenges.
|
||||
gen_image_captchas - Generate any needed new graphical challenges.
|
||||
clean_captchas - Purge old challenges from the database.
|
||||
|
||||
generic.pl:
|
||||
joinmail - Generates daily email digests for community join requests
|
||||
clean_spamreports - Clean out data from the spamreports table older than 90 days.
|
||||
|
||||
clean_challenges.pl:
|
||||
clean_challenges - Deletes old records from challenges table
|
||||
254
local/bin/qbufferd.pl
Executable file
254
local/bin/qbufferd.pl
Executable file
@@ -0,0 +1,254 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
# <LJDEP>
|
||||
# lib: Proc::ProcessTable, cgi-bin/ljlib.pl
|
||||
# </LJDEP>
|
||||
|
||||
use strict;
|
||||
use Getopt::Long
|
||||
require "$ENV{'LJHOME'}/cgi-bin/ljlib.pl";
|
||||
require "$ENV{'LJHOME'}/cgi-bin/supportlib.pl";
|
||||
require "$ENV{'LJHOME'}/cgi-bin/ljcmdbuffer.pl";
|
||||
require "$ENV{'LJHOME'}/cgi-bin/talklib.pl";
|
||||
|
||||
my $opt_foreground;
|
||||
my $opt_debug;
|
||||
my $opt_stop;
|
||||
exit 1 unless GetOptions('foreground' => \$opt_foreground,
|
||||
'debug' => \$opt_debug,
|
||||
'stop' => \$opt_stop,
|
||||
);
|
||||
|
||||
BEGIN {
|
||||
$LJ::OPTMOD_PROCTABLE = eval "use Proc::ProcessTable; 1;";
|
||||
}
|
||||
|
||||
my $DELAY = $LJ::QBUFFERD_DELAY || 15;
|
||||
|
||||
my $pidfile = $LJ::QBUFFERD_PIDFILE || "$ENV{'LJHOME'}/var/qbufferd.pid";
|
||||
my $pid;
|
||||
if (-e $pidfile) {
|
||||
open (PID, $pidfile);
|
||||
chomp ($pid = <PID>);
|
||||
close PID;
|
||||
if ($opt_stop) {
|
||||
if (kill 15, $pid) {
|
||||
print "Shutting down qbufferd.\n";
|
||||
} else {
|
||||
print "qbufferd not running?\n";
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($LJ::OPTMOD_PROCTABLE) {
|
||||
my $processes = Proc::ProcessTable->new()->table;
|
||||
if (grep { $_->cmndline =~ /perl.+qbufferd/ && $_->pid != $$ } @$processes) {
|
||||
exit;
|
||||
}
|
||||
} else {
|
||||
if (kill 0, $pid) {
|
||||
# seems to still be running (at least something is with that pid)
|
||||
exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($opt_stop) {
|
||||
print "qbufferd not running?\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
$SIG{'INT'} = \&stop_qbufferd;
|
||||
$SIG{'TERM'} = \&stop_qbufferd;
|
||||
$SIG{'HUP'} = sub {
|
||||
# nothing. maybe later make a HUP force a flush?
|
||||
};
|
||||
|
||||
if (!$opt_foreground && ($pid = fork))
|
||||
{
|
||||
unless (open (PID, ">$pidfile")) {
|
||||
kill 15, $pid;
|
||||
die "Couldn't write PID file. Exiting.\n";
|
||||
}
|
||||
print PID $pid, "\n";
|
||||
close PID;
|
||||
print "qbufferd started with pid $pid\n";
|
||||
if (-s $pidfile) { print "pid file written ($pidfile)\n"; }
|
||||
exit;
|
||||
}
|
||||
|
||||
# Close filehandles unless running in --debug or --foreground mode.
|
||||
unless ( $opt_debug || $opt_foreground ) {
|
||||
close STDIN && open STDIN, "</dev/null";
|
||||
close STDOUT && open STDOUT, "+>&STDIN";
|
||||
close STDERR && open STDERR, "+>&STDIN";
|
||||
}
|
||||
|
||||
# fork off a separate qbufferd process for all specified
|
||||
# job types in @LJ::QBUFFERD_ISOLATE, and then
|
||||
# another process for all other job types. The current process
|
||||
# will keep tabs on all of those
|
||||
|
||||
my %isolated;
|
||||
my %pids; # job -> pid
|
||||
my %jobs; # pid -> job
|
||||
my $working = 0; # 1 for processes that do actual work
|
||||
|
||||
my $my_job;
|
||||
|
||||
foreach my $job (@LJ::QBUFFERD_ISOLATE) {
|
||||
$isolated{$job} = 1;
|
||||
}
|
||||
|
||||
foreach my $job (@LJ::QBUFFERD_ISOLATE, "_others_") {
|
||||
if (my $child = fork) {
|
||||
# parent.
|
||||
$pids{$job} = $child;
|
||||
$jobs{$child} = $job;
|
||||
next;
|
||||
} else {
|
||||
# child.
|
||||
$0 .= " [$job]";
|
||||
$my_job = $job;
|
||||
$working = 1;
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
# at this point, $my_job is either the specialized 'cmd' to run, or
|
||||
# '_others_' to mean everything besides stuff with their own processes.
|
||||
# $working is 1 for nonempty values of $my_job .
|
||||
|
||||
sub stop_qbufferd
|
||||
{
|
||||
# stop children
|
||||
unless ($working) {
|
||||
foreach my $job (keys %pids) {
|
||||
my $child = $pids{$job};
|
||||
print "Killing child pid $child job: $job\n" if $opt_debug;
|
||||
kill 15, $child;
|
||||
}
|
||||
|
||||
unlink $pidfile;
|
||||
}
|
||||
|
||||
print "Quitting: " . ($working ? "job $my_job" : "parent") . "\n" if $opt_debug;
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
while(not $working) {
|
||||
# controlling process's cycle
|
||||
my $pid;
|
||||
|
||||
$pid = wait();
|
||||
|
||||
print "Child exited, pid $pid, job $jobs{$pid}\n" if $opt_debug;
|
||||
if ($jobs{$pid}) {
|
||||
my $job = $jobs{$pid};
|
||||
print "Restarting job $job\n" if $opt_debug;
|
||||
delete $pids{$job};
|
||||
delete $jobs{$pid};
|
||||
if (my $child = fork) {
|
||||
# parent.
|
||||
$pids{$job} = $child;
|
||||
$jobs{$child} = $job;
|
||||
} else {
|
||||
# child.
|
||||
$0 .= " [$job]";
|
||||
$my_job = $job;
|
||||
$working = 1; # go work
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# the actual work begins here
|
||||
my @all_jobs = qw(delitem weblogscom send_mail support_notify dirty);
|
||||
foreach my $hook (keys %LJ::HOOKS) {
|
||||
next unless $hook =~ /^cmdbuf:(\w+):run$/;
|
||||
push @all_jobs, $1;
|
||||
}
|
||||
|
||||
while (LJ::start_request())
|
||||
{
|
||||
my $cycle_start = time();
|
||||
print "Starting cycle. Job $my_job\n" if $opt_debug;
|
||||
|
||||
# syndication (checks RSS that need to be checked)
|
||||
if ($my_job eq "synsuck") {
|
||||
system("$ENV{'LJHOME'}/bin/ljmaint.pl", "-v0", "synsuck");
|
||||
print "Sleeping. Job $my_job\n" if $opt_debug;
|
||||
my $elapsed = time() - $cycle_start;
|
||||
sleep ($DELAY-$elapsed) if $elapsed < $DELAY;
|
||||
next;
|
||||
}
|
||||
|
||||
# do main cluster updates
|
||||
my $dbh = LJ::get_dbh("master");
|
||||
unless ($dbh) {
|
||||
sleep 10;
|
||||
next;
|
||||
}
|
||||
|
||||
# keep track of what commands we've run the start hook for
|
||||
my %started;
|
||||
|
||||
# handle clusters
|
||||
foreach my $c (@LJ::CLUSTERS) {
|
||||
print "Cluster: $c Job: $my_job\n" if $opt_debug;
|
||||
my $db = LJ::get_cluster_master($c);
|
||||
next unless $db;
|
||||
|
||||
my @check_jobs = ($my_job);
|
||||
if ($my_job eq "_others_") { @check_jobs = grep { ! $isolated{$_} } @all_jobs; }
|
||||
|
||||
foreach my $cmd (@check_jobs) {
|
||||
my $have_jobs = $db->selectrow_array("SELECT cbid FROM cmdbuffer WHERE cmd=? LIMIT 1",
|
||||
undef, $cmd);
|
||||
next unless $have_jobs;
|
||||
|
||||
print " Starting $cmd...\n" if $opt_debug;
|
||||
unless ($started{$cmd}++) {
|
||||
LJ::Cmdbuffer::flush($dbh, undef, "$cmd:start");
|
||||
}
|
||||
LJ::Cmdbuffer::flush($dbh, $db, $cmd);
|
||||
print " Finished $cmd.\n" if $opt_debug;
|
||||
|
||||
# monitor process size and job counts to suicide if necessary
|
||||
my $size = 0;
|
||||
if (open(S, "/proc/$$/status")) {
|
||||
my $file;
|
||||
{ local $/ = undef; $file = <S>; }
|
||||
$size = $1 if $file =~ /VmSize:.+?(\d+)/;
|
||||
close S;
|
||||
}
|
||||
|
||||
# is it our time to go?
|
||||
my $kill_job_ct = LJ::Cmdbuffer::get_property($cmd, 'kill_job_ct') || 0;
|
||||
my $kill_mem_size = LJ::Cmdbuffer::get_property($cmd, 'kill_mem_size') || 0;
|
||||
if ($kill_job_ct && $started{$cmd} >= $kill_job_ct ||
|
||||
$kill_mem_size && $size >= $kill_mem_size)
|
||||
{
|
||||
|
||||
# trigger reload of current child process
|
||||
print "Job suicide: $cmd. (size=$size, rpcs=" . ($started{dirty}+0) . ")\n"
|
||||
if $opt_debug;
|
||||
|
||||
# run end hooks before dying
|
||||
foreach my $cmd (keys %started) {
|
||||
LJ::Cmdbuffer::flush($dbh, undef, "$cmd:finish");
|
||||
}
|
||||
|
||||
exit 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# run the end hook for all commands we've run
|
||||
foreach my $cmd (keys %started) {
|
||||
LJ::Cmdbuffer::flush($dbh, undef, "$cmd:finish");
|
||||
}
|
||||
|
||||
print "Sleeping. Job $my_job\n" if $opt_debug;
|
||||
my $elapsed = time() - $cycle_start;
|
||||
sleep ($DELAY-$elapsed) if $elapsed < $DELAY;
|
||||
};
|
||||
5240
local/bin/upgrading/en.dat
Executable file
5240
local/bin/upgrading/en.dat
Executable file
File diff suppressed because it is too large
Load Diff
2103
local/bin/upgrading/en_LJ.dat
Executable file
2103
local/bin/upgrading/en_LJ.dat
Executable file
File diff suppressed because it is too large
Load Diff
5072
local/bin/upgrading/ru.dat
Executable file
5072
local/bin/upgrading/ru.dat
Executable file
File diff suppressed because it is too large
Load Diff
39
local/bin/upgrading/s2layers-local.dat
Executable file
39
local/bin/upgrading/s2layers-local.dat
Executable file
@@ -0,0 +1,39 @@
|
||||
################################################################
|
||||
# LiveJournal.com's non-free (not GPL) layers. You can use the
|
||||
# source to learn from, but not copy.
|
||||
################################################################
|
||||
# base filename layer type parent
|
||||
|
||||
3column/layout layout core1
|
||||
3column/themes theme+ 3column/layout
|
||||
|
||||
anovelconundrum/layout layout core1
|
||||
anovelconundrum/themes theme+ anovelconundrum/layout
|
||||
|
||||
boxer/layout layout core1
|
||||
boxer/themes theme+ boxer/layout
|
||||
|
||||
component/layout layout core1
|
||||
component/themes theme+ component/layout
|
||||
|
||||
cuteness/layout layout core1
|
||||
|
||||
flexiblesquares/layout layout core1
|
||||
flexiblesquares/themes theme+ flexiblesquares/layout
|
||||
|
||||
nebula/layout layout core1
|
||||
nebula/themes theme+ nebula/layout
|
||||
|
||||
opal/layout layout core1
|
||||
opal/themes theme+ opal/layout
|
||||
|
||||
smoothsailing/layout layout core1
|
||||
smoothsailing/themes theme+ smoothsailing/layout
|
||||
|
||||
tranquilityii/layout layout core1
|
||||
tranquilityii/themes theme+ tranquilityii/layout
|
||||
|
||||
unearthed/layout layout core1
|
||||
unearthed/themes theme+ unearthed/layout
|
||||
|
||||
s2layers-ljcomint.dat INCLUDE
|
||||
1102
local/bin/upgrading/s2layers/3column/layout.s2
Executable file
1102
local/bin/upgrading/s2layers/3column/layout.s2
Executable file
File diff suppressed because it is too large
Load Diff
233
local/bin/upgrading/s2layers/3column/themes.s2
Executable file
233
local/bin/upgrading/s2layers/3column/themes.s2
Executable file
@@ -0,0 +1,233 @@
|
||||
#NEWLAYER: 3column/blue
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Blue";
|
||||
layerinfo "redist_uniq" = "3column/blue";
|
||||
|
||||
set color_bg = "#e9f3fa";
|
||||
set font_color = "#0d446b";
|
||||
set link_color = "#0d446b";
|
||||
set link_hover = "#0d446b";
|
||||
set link_side = "#0d446b";
|
||||
set link_side_h = "#0d446b";
|
||||
set side_bg = "#e9f3fa";
|
||||
set entries_bg = "#e9f3fa";
|
||||
set entries_border = "#0d446b";
|
||||
set side_t_color = "#0d446b";
|
||||
set button_bg = "#e9f3fa";
|
||||
set button_bg_h = "#b0cce0";
|
||||
set entries_font_color = "#0d446b";
|
||||
set side_border = "#0d446b";
|
||||
set c_sub_color = "#b0cce0";
|
||||
set c_sub_bg = "#0d446b";
|
||||
set side_h_color = "#0d446b";
|
||||
set side_h_border = "#0d446b";
|
||||
set side_h_bg = "#b0cce0";
|
||||
set sub_color = "#0d446b";
|
||||
|
||||
#NEWLAYER: 3column/dark
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Dark";
|
||||
layerinfo "redist_uniq" = "3column/dark";
|
||||
|
||||
set color_bg = "#000000";
|
||||
set font_color = "#c0c0c0";
|
||||
set link_color = "#202020";
|
||||
set link_hover = "#FFFFFF";
|
||||
set link_side = "#95432D";
|
||||
set link_side_h = "#BA7625";
|
||||
set side_bg = "#000000";
|
||||
set side_t_color = "C0C0C0";
|
||||
set side_border = "#000000";
|
||||
set side_h_color = "#C0C0C0";
|
||||
set side_h_border = "#C0C0C0";
|
||||
set side_h_bg = "#000000";
|
||||
set entries_bg = "#58494E";
|
||||
set entries_border = "#FFFFFF";
|
||||
set button_bg = "#FFFFFF";
|
||||
set button_bg_h = "#c0c0c0";
|
||||
set entries_font_color = "#000000";
|
||||
set c_sub_color = "#000000";
|
||||
set c_sub_bg = "#ffffff";
|
||||
set sub_color = "#C0C0C0";
|
||||
|
||||
#NEWLAYER: 3column/earth
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Earth";
|
||||
layerinfo "redist_uniq" = "3column/earth";
|
||||
|
||||
set color_bg = "#ECECEA";
|
||||
set font_color = "#4F4637";
|
||||
set link_color = "#4F4637";
|
||||
set link_hover = "#1D4629";
|
||||
set link_side = "#7B6E59";
|
||||
set link_side_h = "#1D4629";
|
||||
set side_bg = "#DBCEB9";
|
||||
set side_t_color = "4F4637";
|
||||
set side_border = "#7B6E59";
|
||||
set side_h_color = "#ECECEA";
|
||||
set side_h_border = "#ECECEA";
|
||||
set side_h_bg = "#7B6E59";
|
||||
set entries_bg = "#AB9F8B";
|
||||
set entries_border = "#7B6E59";
|
||||
set button_bg = "#ECECEA";
|
||||
set button_bg_h = "#4F4637";
|
||||
set entries_font_color = "#4F4637";
|
||||
set c_sub_color = "#4F4637";
|
||||
set c_sub_bg = "#ECECEA";
|
||||
set sub_color = "#4F4637";
|
||||
|
||||
#NEWLAYER: 3column/unnamed
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Unnamed";
|
||||
layerinfo "redist_uniq" = "3column/unnamed";
|
||||
|
||||
set color_bg = "#E5D5C6";
|
||||
set font_color = "#000000";
|
||||
set link_color = "#202020";
|
||||
set link_hover = "#000000";
|
||||
set link_side = "#95432D";
|
||||
set link_side_h = "#D63C3C";
|
||||
set side_bg = "#E5D5C6";
|
||||
set side_t_color = "#000000";
|
||||
set side_border = "#E5D5C6";
|
||||
set side_h_color = "#000000";
|
||||
set side_h_border = "#000000";
|
||||
set side_h_bg = "#E5D5C6";
|
||||
set entries_bg = "#E5D5C6";
|
||||
set entries_border = "#E5D5C6";
|
||||
set button_bg = "#E5D5C6";
|
||||
set button_bg_h = "#ccab8a";
|
||||
set entries_font_color = "#000000";
|
||||
set c_sub_color = "#ccab8a";
|
||||
set c_sub_bg = "#E5D5C6";
|
||||
set sub_color = "#000000";
|
||||
|
||||
#NEWLAYER: 3column/greenenvy
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Green of Envy";
|
||||
layerinfo "redist_uniq" = "3column/greenenvy";
|
||||
|
||||
set color_bg = "#d8ece7";
|
||||
set font_color = "#1b2d29";
|
||||
set link_color = "#1b2d29";
|
||||
set link_hover = "#1b2d29";
|
||||
set link_side = "#1b2d29";
|
||||
set link_side_h = "#1b2d29";
|
||||
set side_bg = "#d8ece7";
|
||||
set entries_bg = "#d8ece7";
|
||||
set entries_border = "#1b2d29";
|
||||
set side_t_color = "#1b2d29";
|
||||
set button_bg = "#d8ece7";
|
||||
set button_bg_h = "#b1d5cb";
|
||||
set entries_font_color = "#1b2d29";
|
||||
set side_border = "#1b2d29";
|
||||
set c_sub_color = "#b1d5cb";
|
||||
set c_sub_bg = "#1b2d29";
|
||||
set side_h_color = "#1b2d29";
|
||||
set side_h_border = "#1b2d29";
|
||||
set side_h_bg = "#b1d5cb";
|
||||
set sub_color = "#1b2d29";
|
||||
|
||||
#NEWLAYER: 3column/blackwhite
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Black and White";
|
||||
layerinfo "redist_uniq" = "3column/blackwhite";
|
||||
|
||||
set color_bg = "#FFFFFF";
|
||||
set font_color = "#808080";
|
||||
set link_color = "#808080";
|
||||
set link_hover = "#202020";
|
||||
set link_side = "#c0c0c0";
|
||||
set link_side_h = "#FFFFFF";
|
||||
set side_bg = "#000000";
|
||||
set side_t_color = "808080";
|
||||
set side_border = "#ffffff";
|
||||
set side_h_color = "#c0c0c0";
|
||||
set side_h_border = "#c0c0c0";
|
||||
set side_h_bg = "#808080";
|
||||
set entries_bg = "#ffffff";
|
||||
set entries_border = "#000000";
|
||||
set button_bg = "#c0c0c0";
|
||||
set button_bg_h = "#808080";
|
||||
set entries_font_color = "#000000";
|
||||
set c_sub_color = "#ffffff";
|
||||
set c_sub_bg = "#000000";
|
||||
set sub_color = "#202020";
|
||||
|
||||
#NEWLAYER: 3column/agentorange
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Agent Orange";
|
||||
layerinfo "redist_uniq" = "3column/agentorange";
|
||||
|
||||
set color_bg = "#f7e6d3";
|
||||
set font_color = "#582604";
|
||||
set link_color = "#582604";
|
||||
set link_hover = "#582604";
|
||||
set link_side = "#582604";
|
||||
set link_side_h = "#582604";
|
||||
set side_bg = "#f7e6d3";
|
||||
set entries_bg = "#f7e6d3";
|
||||
set entries_border = "#582604";
|
||||
set side_t_color = "#582604";
|
||||
set button_bg = "#f7e6d3";
|
||||
set button_bg_h = "#e0c7aa";
|
||||
set entries_font_color = "#582604";
|
||||
set side_border = "#582604";
|
||||
set c_sub_color = "#e0c7aa";
|
||||
set c_sub_bg = "#582604";
|
||||
set side_h_color = "#582604";
|
||||
set side_h_border = "#582604";
|
||||
set side_h_bg = "#e0c7aa";
|
||||
set sub_color = "#b64c06";
|
||||
|
||||
#NEWLAYER: 3column/purple
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Purple";
|
||||
layerinfo "redist_uniq" = "3column/purple";
|
||||
|
||||
set color_bg = "#e8cff1";
|
||||
set font_color = "#410458";
|
||||
set link_color = "#410458";
|
||||
set link_hover = "#410458";
|
||||
set link_side = "#410458";
|
||||
set link_side_h = "#410458";
|
||||
set side_bg = "#e8cff1";
|
||||
set entries_bg = "#e8cff1";
|
||||
set entries_border = "#410458";
|
||||
set side_t_color = "#410458";
|
||||
set button_bg = "#e8cff1";
|
||||
set button_bg_h = "#d1aae0";
|
||||
set entries_font_color = "#410458";
|
||||
set side_border = "#410458";
|
||||
set c_sub_color = "#d1aae0";
|
||||
set c_sub_bg = "#410458";
|
||||
set side_h_color = "#410458";
|
||||
set side_h_border = "#410458";
|
||||
set side_h_bg = "#d1aae0";
|
||||
set sub_color = "#410458";
|
||||
|
||||
#NEWLAYER: 3column/mellowyellow
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Mellow Yellow";
|
||||
layerinfo "redist_uniq" = "3column/mellowyellow";
|
||||
|
||||
set color_bg = "#f8f6da";
|
||||
set font_color = "#42331e";
|
||||
set link_color = "#42331e";
|
||||
set link_hover = "#8d452f";
|
||||
set link_side = "#8d452f";
|
||||
set link_side_h = "#42331e";
|
||||
set side_bg = "#f2c98e";
|
||||
set entries_bg = "#f8f6da";
|
||||
set entries_border = "#42331e";
|
||||
set side_t_color = "#42331e";
|
||||
set button_bg = "#f2c98e";
|
||||
set button_bg_h = "#e8c098";
|
||||
set entries_font_color = "#42331e";
|
||||
set side_border = "#42331e";
|
||||
set c_sub_color = "#42331e";
|
||||
set c_sub_bg = "#f2c98e";
|
||||
set side_h_color = "#333333";
|
||||
set side_h_border = "#333333";
|
||||
set side_h_bg = "#f8f6da";
|
||||
set sub_color = "#d39945";
|
||||
999
local/bin/upgrading/s2layers/anovelconundrum/layout.s2
Executable file
999
local/bin/upgrading/s2layers/anovelconundrum/layout.s2
Executable file
@@ -0,0 +1,999 @@
|
||||
# -*-s2-*-
|
||||
|
||||
layerinfo "type" = "layout";
|
||||
layerinfo "name" = "A Novel Conundrum";
|
||||
layerinfo "source_viewable" = 1;
|
||||
layerinfo "redist_uniq" = "anovelconundrum/layout";
|
||||
layerinfo "author_name" = "taion";
|
||||
|
||||
propgroup colors {
|
||||
property Color page_back {
|
||||
des = "Page background";
|
||||
}
|
||||
property Color entry_text {
|
||||
des = "Entry text color";
|
||||
}
|
||||
property Color text_weaker {
|
||||
des = "Weaker text color";
|
||||
}
|
||||
property Color page_link {
|
||||
des = "Link color";
|
||||
}
|
||||
property Color page_vlink {
|
||||
des = "Visited link color";
|
||||
}
|
||||
property Color page_alink {
|
||||
des = "Active link color";
|
||||
}
|
||||
}
|
||||
|
||||
# From my last e-mail with Taion, the plan was to rasterize the leading fonts so that
|
||||
# appearance issues could be avoided. However, I don't have access to many of the fonts
|
||||
# that he tested with, so I'll have to put that off for later.
|
||||
|
||||
# You will need access to Microsoft provided fonts for most accurate rendering, but
|
||||
# we are working on specifying usable alternatives that are cross platform friendly.
|
||||
propgroup fonts {
|
||||
property use font_base;
|
||||
property string font_fallback {
|
||||
des = "Alternative font style";
|
||||
}
|
||||
property string font_type {
|
||||
des = "Body font type";
|
||||
note = "General font class for body text";
|
||||
}
|
||||
property int font_size {
|
||||
des = "Body font size (points)";
|
||||
}
|
||||
property int font_leading {
|
||||
des = "Body font leading (points)";
|
||||
}
|
||||
property string title_letterspacing {
|
||||
des = "Letterspacing in titles";
|
||||
}
|
||||
property bool title_smallcaps {
|
||||
des = "Smallcaps in titles";
|
||||
}
|
||||
property bool title_underline {
|
||||
des = "Underlined titles";
|
||||
}
|
||||
property string font_flourish_base {
|
||||
des = "Font face for decorative flourishes";
|
||||
}
|
||||
property string font_flourish_fallback {
|
||||
des = "Alternate font face for decorative flourishes";
|
||||
}
|
||||
property string font_flourish_type {
|
||||
des = "Font type for decorative flourishes";
|
||||
}
|
||||
property string font_secondary_base {
|
||||
des = "Font face for secondary text";
|
||||
}
|
||||
property string font_secondary_fallback {
|
||||
des = "Alternate font face for secondary text";
|
||||
}
|
||||
property string font_secondary_type {
|
||||
des = "Font type for secondary text";
|
||||
}
|
||||
property int font_secondary_size {
|
||||
des = "Secondary font size (points)";
|
||||
note = "For best results, match optical x-height with the body font";
|
||||
}
|
||||
property string flourish_rm {
|
||||
des = "Right margin for flourishes";
|
||||
}
|
||||
property string dc_rm {
|
||||
des = "Right margin for drop caps";
|
||||
}
|
||||
}
|
||||
|
||||
propgroup presentation {
|
||||
property string dingbar_url {
|
||||
des = "URL to spacer image between portions of content";
|
||||
note = "A default will be chosen for you if left blank.";
|
||||
}
|
||||
|
||||
property use page_recent_items;
|
||||
property use page_friends_items;
|
||||
|
||||
property string body_width {
|
||||
des = "Text body width";
|
||||
}
|
||||
|
||||
property int dcLen {
|
||||
des = "Minimum length in characters before using drop caps";
|
||||
}
|
||||
|
||||
property use view_entry_disabled;
|
||||
property use use_shared_pic;
|
||||
property use comment_userpic_style;
|
||||
property bool show_entrynav_icons {
|
||||
des = "Toggle to show the next, memory, edit, etc icons on the entry view page";
|
||||
}
|
||||
property string page_background_image {
|
||||
des = "URL to an image to be used for the page background";
|
||||
}
|
||||
property use external_stylesheet;
|
||||
}
|
||||
|
||||
propgroup text {
|
||||
property use text_post_comment;
|
||||
property use text_read_comments;
|
||||
property use text_post_comment_friends;
|
||||
property use text_read_comments_friends;
|
||||
property use text_meta_music;
|
||||
property use text_meta_mood;
|
||||
property string text_dingbar_alt {
|
||||
des = "Alternative text for dingbar images";
|
||||
noui = 1;
|
||||
}
|
||||
}
|
||||
|
||||
# Set default colors
|
||||
set entry_text = "#000000";
|
||||
set text_weaker = "#666666";
|
||||
set page_link = "#000000";
|
||||
set page_vlink = "#666666";
|
||||
set page_alink = "#333333";
|
||||
set page_back = "#F5F5DC";
|
||||
|
||||
set body_width = "35em";
|
||||
set dcLen = 200;
|
||||
set show_entrynav_icons = true;
|
||||
set page_background_image = "";
|
||||
|
||||
set font_base = "Palatino Linotype";
|
||||
set font_fallback = "Book Antiqua";
|
||||
set font_type = "serif";
|
||||
set font_flourish_base = "Edwardian Script ITC\", \"Edwardian Script ITC Semi-Expanded";
|
||||
set font_flourish_fallback = "Zapfino\", \"Viner Hand ITC";
|
||||
set font_flourish_type = "cursive";
|
||||
set font_secondary_base = "Frutiger Linotype";
|
||||
set font_secondary_fallback = "Tahoma";
|
||||
set font_secondary_type = "sans-serif";
|
||||
set font_size = 10;
|
||||
set font_leading = 14;
|
||||
set title_smallcaps = true;
|
||||
set title_underline = false;
|
||||
set title_letterspacing = "0.08em";
|
||||
set font_secondary_size = 9;
|
||||
set flourish_rm = "0.093em";
|
||||
set dc_rm = "0.2em";
|
||||
set dingbar_url = "";
|
||||
|
||||
set text_poster_anonymous = "an anonymous reader";
|
||||
set text_dingbar_alt = "* * *";
|
||||
set text_view_recent = "Entries";
|
||||
set text_view_friends = "Friends";
|
||||
set text_view_archive = "Archive";
|
||||
set text_view_userinfo = "Profile";
|
||||
|
||||
function prop_init() {
|
||||
var PalItem start = PalItem(0, $*entry_text);
|
||||
var PalItem end = PalItem(13, $*page_back);
|
||||
if ($*dingbar_url == "") { $*dingbar_url = palimg_gradient("anovelconundrum/dingbar.gif", $start, $end); }
|
||||
}
|
||||
|
||||
function print_stylesheet() {
|
||||
print clean_url($*page_background_image) != "" ? "body { background-image: url($*page_background_image); }" : "";
|
||||
"""
|
||||
body {
|
||||
margin-top: 1in;
|
||||
margin-bottom: 0.6in;
|
||||
}
|
||||
|
||||
body, td, h2, .caption, h1, h3 {
|
||||
""";
|
||||
if ($*font_base != "" or $*font_fallback != "" or $*font_type != "") {
|
||||
"font-family: ";
|
||||
if ($*font_base != "") {
|
||||
"\"$*font_base\"";
|
||||
if ($*font_fallback != "" or $*font_type != "") {
|
||||
", ";
|
||||
}
|
||||
}
|
||||
if ($*font_fallback != "") {
|
||||
"\"$*font_fallback\"";
|
||||
if ($*font_type != "") {
|
||||
", ";
|
||||
}
|
||||
}
|
||||
if ($*font_type != "") {
|
||||
"$*font_type";
|
||||
}
|
||||
";\n";
|
||||
}
|
||||
"""
|
||||
font-size: ${*font_size}pt;
|
||||
line-height: ${*font_leading}pt;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.caption, h1, h3 {
|
||||
"""; if($*title_smallcaps) {"""
|
||||
font-variant: small-caps;
|
||||
text-transform: lowercase;
|
||||
"""; }
|
||||
""" letter-spacing: $*title_letterspacing;
|
||||
}
|
||||
h1 { font-size: 16pt; }
|
||||
h3 { font-size: 12pt; }
|
||||
h2, .noul, .ult {
|
||||
font-style: italic;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
.caption {
|
||||
"""; if($*title_underline) {"""
|
||||
text-decoration: underline;
|
||||
"""; }
|
||||
""" }
|
||||
|
||||
.flourish, .bodyl:first-letter {
|
||||
""";
|
||||
if ($*font_flourish_base != "" or $*font_flourish_fallback != "" or $*font_flourish_type != "") {
|
||||
"font-family: ";
|
||||
if ($*font_flourish_base != "") {
|
||||
"\"$*font_flourish_base\"";
|
||||
if ($*font_flourish_fallback != "" or $*font_flourish_type != "") {
|
||||
", ";
|
||||
}
|
||||
}
|
||||
if ($*font_flourish_fallback != "") {
|
||||
"\"$*font_flourish_fallback\"";
|
||||
if ($*font_flourish_type != "") {
|
||||
", ";
|
||||
}
|
||||
}
|
||||
if ($*font_flourish_type != "") {
|
||||
"$*font_flourish_type";
|
||||
}
|
||||
";\n";
|
||||
}
|
||||
"""
|
||||
}
|
||||
|
||||
.flourish {
|
||||
margin-right: ${*flourish_rm};
|
||||
z-index: 1;
|
||||
font-size: 34pt;
|
||||
position: relative;
|
||||
top: 0.1em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.sfon, .index, .author, select, input {
|
||||
""";
|
||||
if ($*font_secondary_base != "" or $*font_secondary_fallback != "" or $*font_secondary_type != "") {
|
||||
"font-family: ";
|
||||
if ($*font_secondary_base != "") {
|
||||
"\"$*font_secondary_base\"";
|
||||
if ($*font_secondary_fallback != "" or $*font_secondary_type != "") {
|
||||
", ";
|
||||
}
|
||||
}
|
||||
if ($*font_secondary_fallback != "") {
|
||||
"\"$*font_secondary_fallback\"";
|
||||
if ($*font_secondary_type != "") {
|
||||
", ";
|
||||
}
|
||||
}
|
||||
if ($*font_secondary_type != "") {
|
||||
"$*font_secondary_type";
|
||||
}
|
||||
";\n";
|
||||
}
|
||||
""" font-size: ${*font_secondary_size}pt;
|
||||
line-height: ${*font_leading}pt;
|
||||
}
|
||||
|
||||
.index {
|
||||
width: 10em;
|
||||
margin-right: 1.2em;
|
||||
}
|
||||
|
||||
.bodybox { width: $*body_width; }
|
||||
|
||||
.body, .bodyl, .bodyns {
|
||||
text-align: justify;
|
||||
}
|
||||
.bodyl:first-letter {
|
||||
font-size: """ + (2* $*font_leading) + """pt;
|
||||
margin-bottom: -""" + $*font_size + """pt;
|
||||
margin-right: ${*dc_rm};
|
||||
float: left;
|
||||
border-bottom: none;
|
||||
text-transform: uppercase;
|
||||
line-height: """ + (2* $*font_leading) + """pt;
|
||||
}
|
||||
.bodyns:first-line, .sc, small, .sct {
|
||||
"""; if($*title_smallcaps) {"""
|
||||
font-variant: small-caps;
|
||||
text-transform: lowercase;
|
||||
"""; }
|
||||
if($*title_underline) {"""
|
||||
text-decoration: underline;
|
||||
"""; }
|
||||
""" letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
.sct {
|
||||
letter-spacing: $*title_letterspacing;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.author {
|
||||
float: right;
|
||||
text-align: center;
|
||||
margin-left: 1.5em;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.ywp {
|
||||
width: 2em;
|
||||
margin-left: 0.5em;
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin-top: ${*font_leading}pt;
|
||||
margin-bottom: ${*font_leading}pt;
|
||||
margin-left: 2em;
|
||||
}
|
||||
|
||||
tt, pre, textarea {
|
||||
font-family: "Lucida Console", monospace;
|
||||
font-size:"""+ ((${*font_size}*4)/5) + """pt;
|
||||
}
|
||||
|
||||
a {text-decoration: none;}
|
||||
.body a, .bodyl a, .bodyns a, .bodynsl a, .author a, .ult a, .uts a { border-bottom: 1px dotted; }
|
||||
.ljuser a, a img, .smallbar a, .noul a { border-bottom: none; }
|
||||
a:hover, .ljuser a:hover { border-bottom: 1px solid; }
|
||||
|
||||
p {
|
||||
text-indent: 1.5em;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
blockquote + p { text-indent: 0px; }
|
||||
|
||||
.uts {
|
||||
font-size: 80%;
|
||||
font-style: italic;
|
||||
text-align: center;
|
||||
line-height: """ + $*font_size + """pt;
|
||||
margin-bottom: """ + ($*font_leading-$*font_size) + """pt;
|
||||
}
|
||||
|
||||
.smallbar {
|
||||
font-size: 80%;
|
||||
font-style: italic;
|
||||
text-align: center;
|
||||
line-height: """ + (2*$*font_leading) + """pt;
|
||||
clear: right;
|
||||
}
|
||||
|
||||
.ljcomsel {
|
||||
position: relative;
|
||||
top: 0.75pt;
|
||||
height: 7.5pt;
|
||||
padding-left: 1pt;
|
||||
}
|
||||
input#username, input#password { margin-right: 0.5em; }
|
||||
|
||||
.bs {
|
||||
margin-top: """ + (2*$*font_leading) + """pt;
|
||||
margin-bottom: """ + (2*$*font_leading) + """pt;
|
||||
text-align: center;
|
||||
line-height: ${*font_leading}pt;
|
||||
}
|
||||
""";
|
||||
}
|
||||
|
||||
function find_lpar(string t) : int {
|
||||
foreach var int i (reverse (0 .. ($t->length()-1))) {
|
||||
if($t->substr($i,1)=="(") { return $i; }
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
function render_title(string t, int len) {
|
||||
foreach var int i (0 .. ($len-1)) {
|
||||
var string pc = $t->substr($i-1,1);
|
||||
var string cc = $t->substr($i,1);
|
||||
if($cc==" ") { " · "; }
|
||||
elseif( $i > 0 and $pc != " ") { "$cc"; }
|
||||
elseif ($cc=="A" or $cc=="B" or $cc=="C" or $cc=="D" or $cc=="E" or $cc=="F" or $cc=="G" or $cc=="H" or $cc=="I" or $cc=="J" or $cc=="K" or $cc=="L" or $cc=="M" or $cc=="N" or $cc=="O" or $cc=="P" or $cc=="Q" or $cc=="R" or $cc=="S" or $cc=="T" or $cc=="U" or $cc=="V" or $cc=="W" or $cc=="X" or $cc=="Y" or $cc=="Z") {
|
||||
"<span class='flourish'>$cc</span>";
|
||||
}
|
||||
else { "$cc"; }
|
||||
}
|
||||
}
|
||||
|
||||
function render_body(string t) {
|
||||
var int str=0;
|
||||
var bool par=false;
|
||||
var bool pars=false;
|
||||
$str = ($t->substr(0,6) == "<br />" ? 6 : 0);
|
||||
if($t->substr(0,3) == "<p>") { $str = 3; $pars=true; }
|
||||
foreach var int i ($str .. ($t->length()-1)) {
|
||||
if($t->substr($i,12) == "<br /><br />") {
|
||||
$str=$i+12;
|
||||
if($par) { "</p><p>"; }
|
||||
else { "<p>"; $par=true; }
|
||||
}
|
||||
elseif($pars and $t->substr($i,4) == "</p>") { $str=$i+4; $pars=false; }
|
||||
elseif($i >= $str) { print $t->substr($i,1); }
|
||||
}
|
||||
if($par) { "</p>"; }
|
||||
}
|
||||
|
||||
function display_title(Page p) {
|
||||
var string dtitle = $p.global_title;
|
||||
var string stitle = $p->view_title();
|
||||
$stitle = ($p.view == "recent" ? $p.global_subtitle : $stitle);
|
||||
var int lenm=$stitle->length()-1;
|
||||
var int i=$dtitle->length()+1;
|
||||
if ($dtitle == "") {
|
||||
$dtitle = $p.journal.name;
|
||||
$i=$dtitle->length()+1;
|
||||
}
|
||||
if ($p.view == "friends") {
|
||||
$dtitle = $p->view_title();
|
||||
$i=find_lpar($dtitle);
|
||||
if($i==-1) { $i = $lenm+2; }
|
||||
}
|
||||
|
||||
"""<div align="center">
|
||||
<h1>"""; render_title($dtitle,$i-1); """</h1>""";
|
||||
if($p.view != "friends" and $stitle != "") { """<br /><h3 style="margin-top:-1em;">$stitle</h3>"""; }
|
||||
elseif($p.view == "friends" and $i<$lenm) { "<br /><h3 style='margin-top:-1em;'>" + $dtitle->substr($i+1,($lenm-$i)-1) + "</h3>"; }
|
||||
"""</div>""";
|
||||
}
|
||||
|
||||
function Page::print() {
|
||||
var string title = $this->title();
|
||||
|
||||
var string links;
|
||||
var bool firstlink = true;
|
||||
foreach var string v ($.views_order) {
|
||||
if ($firstlink == false) {
|
||||
$links = "$links · ";
|
||||
}
|
||||
else {
|
||||
$firstlink = false;
|
||||
}
|
||||
$links = $links + ("<a href='$.view_url{$v}'>"+lang_viewname($v)+"</a>");
|
||||
}
|
||||
|
||||
"""<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">\n<html>\n<head>\n""";
|
||||
|
||||
if ($*external_stylesheet) {
|
||||
println """<link rel="stylesheet" href="$.stylesheet_url" type="text/css" />""";
|
||||
} else {
|
||||
println """<style type="text/css">"""; print_stylesheet(); "</style>";
|
||||
}
|
||||
$this->print_head();
|
||||
|
||||
"""<title>$title</title>
|
||||
</head>
|
||||
<body bgcolor="$*page_back" text="$*entry_text" link="$*page_link" vlink="$*page_vlink" alink="$*page_alink">""";
|
||||
display_title($this);
|
||||
"""<div style="text-align:center; margin-bottom: ${*font_leading}pt;">
|
||||
<h2>$links</h2>
|
||||
</div>
|
||||
""";
|
||||
$this->print_body();
|
||||
"""
|
||||
</body>
|
||||
</html>
|
||||
""";
|
||||
}
|
||||
|
||||
function print_entry(Page p, Entry e) {
|
||||
var string date=$e.time->date_format("short");
|
||||
var string time=$e.time->time_format();
|
||||
"""
|
||||
<table cellpadding='0' cellspacing='0' border='0' align='center'>
|
||||
<tr><td align="center" colspan="2"><img
|
||||
src="$*dingbar_url" alt="$*text_dingbar_alt" class="bs"/></td></tr>
|
||||
<tr>
|
||||
<td align="right" valign="top" width="100"><div class="index">""";
|
||||
""" <a href="$e.permalink_url">$time<br />
|
||||
$date</a><br /><br />
|
||||
""";
|
||||
$e.comments->print();
|
||||
|
||||
""" </div></td>
|
||||
<td valign="top">
|
||||
<div class="bodybox">
|
||||
<div class="author">""";
|
||||
|
||||
if (defined $e.userpic) {
|
||||
"""<img border="0" src="$e.userpic.url" width="$e.userpic.width" height="$e.userpic.height" alt=""><br />""";
|
||||
}
|
||||
elseif ($e.poster.journal_type == "C") {
|
||||
"""<img border="0" src="$*IMGDIR/community.gif" alt="" /><br />""";
|
||||
|
||||
}
|
||||
elseif ($e.poster.journal_type == "Y") {
|
||||
"""<img border="0" src="$*IMGDIR/syndicated.gif" alt="" /><br />""";
|
||||
}
|
||||
else {
|
||||
"""<img border="0" src="$*IMGDIR/userinfo.gif" alt="" /><br />""";
|
||||
}
|
||||
"<a href=\"" +
|
||||
$e.poster->base_url() + "/\">$e.poster.username</a>";
|
||||
if ($e.security != "") {
|
||||
$e.security_icon->print();
|
||||
}
|
||||
if ($e.poster.username != $e.journal.username and $e.journal.journal_type =="C") {
|
||||
""",<br />
|
||||
<img border="0" src="$*IMGDIR/community.gif" alt="" align="absmiddle" />
|
||||
<a href=\"""" + $e.journal->base_url() + """/">$e.journal.username</a>""";
|
||||
}
|
||||
|
||||
var string subject=$e.subject;
|
||||
if($p.view=="entry") { $subject=""; }
|
||||
"""</div>
|
||||
<div class="caption">
|
||||
$subject
|
||||
</div>""";
|
||||
if ($subject == "" and $p.view!="entry") {"<div class='bodyns'>";}
|
||||
elseif ($e.text->length() > $*dcLen) {"<div class='bodyl'>";}
|
||||
else {"<div class='body'>";}
|
||||
render_body($e.text);
|
||||
var string metadata;
|
||||
if ($e.metadata) {
|
||||
$metadata = "<div style='margin-top:${*font_leading}pt;'><table cellspacing='0' cellpadding='0' border='0'>";
|
||||
foreach var string k ($e.metadata) {
|
||||
var string text = $k;
|
||||
var string val = $e.metadata{$k};
|
||||
if ($k == "mood") {
|
||||
$text = $*text_meta_mood;
|
||||
} elseif ($k == "music") {
|
||||
$text = $*text_meta_music;
|
||||
}
|
||||
if ($k == "mood" and defined $e.mood_icon) {
|
||||
var Image i = $e.mood_icon;
|
||||
$val = "<img src='$i.url' width='$i.width' height='$i.height' align='middle' alt='$val'> $val";
|
||||
}
|
||||
$metadata = """$metadata\n<tr><td align="right"><div class="sc" style="margin-right:1em;">$text:</div></td>
|
||||
<td align="left">$val</td></tr>""";
|
||||
}
|
||||
$metadata = """$metadata</table></div>""";
|
||||
}
|
||||
"""$metadata</div></div></td>
|
||||
</tr>""";
|
||||
|
||||
if ($p.view == "entry" and $*show_entrynav_icons)
|
||||
{
|
||||
"""<tr><td align="center" colspan="2" style="line-height:${*font_leading}pt;"><img
|
||||
src="$*dingbar_url" alt="$*text_dingbar_alt" class="bs" /></td></tr>
|
||||
<tr><td colspan="2"><div style='text-align: center; margin-top: 0px;'>""";
|
||||
$e->print_linkbar();
|
||||
"""</div></td></tr>""";
|
||||
}
|
||||
"</table>";
|
||||
} # print_entry(Page,Entry,Color,Color)
|
||||
|
||||
function Entry::print_linkbar() {
|
||||
## There's no point in showing previous/next links on pages which show
|
||||
## multiple entries anyway, so we only print them on EntryPage and ReplyPage.
|
||||
|
||||
var Page p = get_page();
|
||||
var Link link;
|
||||
var bool show_interentry = ($p.view == "entry" or $p.view == "reply");
|
||||
|
||||
"<h2>";
|
||||
if ($show_interentry) {
|
||||
var Link prev = $this->get_link("nav_prev");
|
||||
"""<a href="$prev.url">$prev.caption</a> · """;
|
||||
}
|
||||
|
||||
if ($p.view == "entry" and $.comments.enabled) {
|
||||
if ($.comments.maxcomments) {
|
||||
"Maximum Comments Reached";
|
||||
} else {
|
||||
"<a href=\"$.comments.post_url\">Leave a Comment</a>";
|
||||
}
|
||||
" · ";
|
||||
}
|
||||
|
||||
var int i=0;
|
||||
foreach var string k ($.link_keyseq) {
|
||||
$link = $this->get_link($k);
|
||||
if($link.caption != "") {
|
||||
if($i>0) { " · "; }
|
||||
"<a href='$link.url'>$link.caption</a>";
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
|
||||
if ($show_interentry) {
|
||||
var Link next = $this->get_link("nav_next");
|
||||
""" · <a href="$next.url">$next.caption</a>""";
|
||||
}
|
||||
"</h2>";
|
||||
}
|
||||
|
||||
function Page::print_entry(Entry e) {
|
||||
print_entry($this, $e);
|
||||
}
|
||||
|
||||
function FriendsPage::print_entry(Entry e) {
|
||||
print_entry($this, $e);
|
||||
}
|
||||
|
||||
|
||||
function RecentPage::print_body() {
|
||||
foreach var Entry e ($.entries) {
|
||||
$this->print_entry($e);
|
||||
}
|
||||
"""
|
||||
<div align="center" class="bs" style="line-height: ${*font_leading}pt;"><img
|
||||
src="$*dingbar_url" style="text-align:center;" alt="$*text_dingbar_alt" /></div>
|
||||
<div align="center"><h2>
|
||||
""";
|
||||
|
||||
# go forward/backward if possible
|
||||
if ($.nav.forward_url != "" or $.nav.backward_url != "") {
|
||||
var string sep;
|
||||
var string back;
|
||||
var string forward;
|
||||
if ($.nav.backward_url != "") {
|
||||
$back = """<a href="$.nav.backward_url">Previous</a>""";
|
||||
}
|
||||
if ($.nav.forward_url != "") {
|
||||
$forward = """<a href="$.nav.forward_url">Next</a>""";
|
||||
}
|
||||
if ($back != "" and $forward != "") { $sep = " · "; }
|
||||
"$back$sep$forward";
|
||||
}
|
||||
"</h2></div>";
|
||||
}
|
||||
|
||||
function CommentInfo::print() {
|
||||
if (not $.enabled) { return; }
|
||||
if ($.count > 0 or $.screened) {
|
||||
$this->print_readlink(); "<br />";
|
||||
}
|
||||
$this->print_postlink();
|
||||
}
|
||||
|
||||
function YearPage::print_year_links() {
|
||||
"""<div class="bs">
|
||||
<img src="$*dingbar_url" alt="$*text_dingbar_alt" />
|
||||
</div><div class="sct">Years</div><h2 style="text-align:center;">""";
|
||||
|
||||
var bool d=false;
|
||||
foreach var YearYear y ($.years) {
|
||||
if($d) { " · "; }
|
||||
else { $d=true; }
|
||||
if ($y.displayed) {
|
||||
"$y.year";
|
||||
} else {
|
||||
"<a href=\"$y.url\">$y.year</a>";
|
||||
}
|
||||
}
|
||||
"</h2>";
|
||||
}
|
||||
|
||||
function YearPage::print_month(YearMonth m) {
|
||||
if (not $m.has_entries) { return; }
|
||||
|
||||
"""<div class="bs">
|
||||
<table cellpadding="0" cellspacing="0" border="0" summary="" align="center">
|
||||
<tr><center class="noul">
|
||||
<a href="$m.url">""";
|
||||
print $m->month_format();
|
||||
"""</a>
|
||||
<!-- now the headings for the week -->
|
||||
<table align="center" cellpadding="0" cellspacing="0" border="0" summary="">
|
||||
<tr align="center">
|
||||
""";
|
||||
foreach var int d (weekdays()) {
|
||||
"<td align='center'>"+$*lang_dayname_short[$d]+"</td>\n";
|
||||
}
|
||||
"</tr>";
|
||||
foreach var YearWeek w ($m.weeks) {
|
||||
$w->print();
|
||||
}
|
||||
|
||||
"""</table></center>""";
|
||||
}
|
||||
|
||||
function YearWeek::print() {
|
||||
"<tr valign='top'>";
|
||||
if ($.pre_empty) { "<td colspan='$.pre_empty'></td>"; }
|
||||
foreach var YearDay d ($.days) {
|
||||
"""<td><div class="ywp"><div class="sfon">$d.day</div>""";
|
||||
if ($d.num_entries) {
|
||||
"""<div class="uts"><a href="$d.url">$d.num_entries</a></div>""";
|
||||
} else {
|
||||
" ";
|
||||
}
|
||||
"</div></td>";
|
||||
}
|
||||
if ($.post_empty) { "<td colspan='$.post_empty'></td>"; }
|
||||
"</tr>";
|
||||
}
|
||||
|
||||
function DayPage::print_body() {
|
||||
if (not $.has_entries) { print "<div class='sct'>" + ehtml($*text_noentries_day) + "</div>"; }
|
||||
|
||||
foreach var Entry e ($.entries) {
|
||||
$this->print_entry($e);
|
||||
}
|
||||
|
||||
"""<div class="bs">
|
||||
<img src="$*dingbar_url" alt="$*text_dingbar_alt" />
|
||||
</div>""";
|
||||
var string tprev = ehtml($*text_day_prev);
|
||||
var string tnext = ehtml($*text_day_next);
|
||||
"""<center><h2><a href="$.prev_url">$tprev</a> · <a href="$.next_url">$tnext</a></h2></center>""";
|
||||
|
||||
}
|
||||
|
||||
function MonthPage::print_body() {
|
||||
"""<div class="bs">
|
||||
<img src="$*dingbar_url" alt="$*text_dingbar_alt" />
|
||||
</div>""";
|
||||
"<center><div class='bodybox'><center><table border='0' cellspacing='0' cellpadding='0'><tr><td><dl>";
|
||||
foreach var MonthDay d ($.days) {
|
||||
if ($d.has_entries) {
|
||||
"<dt><a href=\"$d.url\"><i>";
|
||||
print lang_ordinal($d.day);
|
||||
"</i></a>:</dt>\n<dd>";
|
||||
$d->print_subjectlist();
|
||||
"</dd>\n";
|
||||
}
|
||||
}
|
||||
"</dl></td></tr></table></center></div></center>\n";
|
||||
"""<div class="bs">
|
||||
<img src="$*dingbar_url" alt="$*text_dingbar_alt" />
|
||||
</div>""";
|
||||
"<form method='post' action='$.redir.url'><center>";
|
||||
$.redir->print_hiddens();
|
||||
if ($.prev_url != "") { "<a href='$.prev_url' style='font-size:12pt;'>☜</a> "; }
|
||||
if (size $.months > 1) {
|
||||
"<select name='redir_key'>\n";
|
||||
foreach var MonthEntryInfo mei ($.months) {
|
||||
var string sel;
|
||||
if ($mei.date.year == $.date.year and $mei.date.month == $.date.month) {
|
||||
$sel = " selected='selected'";
|
||||
}
|
||||
"<option value='$mei.redir_key'$sel>" + $mei.date->date_format($*lang_fmt_month_long) + "</option>";
|
||||
}
|
||||
"</select>\n<input type='submit' value='View' />";
|
||||
}
|
||||
if ($.next_url != "") { " <a href='$.next_url' style='font-size:12pt;'>☞</a>\n"; }
|
||||
"</center></form>";
|
||||
}
|
||||
|
||||
function EntryPage::print_body() {
|
||||
print_entry($this, $.entry);
|
||||
|
||||
if ($.entry.comments.enabled and $.comment_pages.total_subitems > 0) {
|
||||
$.comment_pages->print();
|
||||
|
||||
$this->print_multiform_start();
|
||||
"<div style='margin-top: 7pt;'></div>";
|
||||
"<table align='center' cellspacing='0' border='0' cellpadding='0' style='display: none;'><tr><td>";
|
||||
$this->print_comments($.comments);
|
||||
"</td></tr></table>";
|
||||
|
||||
$.comment_pages->print();
|
||||
|
||||
if ($*show_entrynav_icons) {
|
||||
"""<div class="bs">
|
||||
<img src="$*dingbar_url" alt="$*text_dingbar_alt" />
|
||||
</div>""";
|
||||
"""<div class="bs">""";
|
||||
$.entry->print_linkbar();
|
||||
"""</div>""";
|
||||
}
|
||||
|
||||
if ($this.multiform_on) {"""
|
||||
<div class="bs">
|
||||
<img src="$*dingbar_url" alt="$*text_dingbar_alt" />
|
||||
</div>
|
||||
<div style="text-align: center;">""";
|
||||
$this->print_multiform_actionline();
|
||||
$this->print_multiform_end();
|
||||
"</div>";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function ItemRange::print() {
|
||||
if ($.all_subitems_displayed) { return; }
|
||||
"""<div class="bs">
|
||||
<img src="$*dingbar_url" alt="$*text_dingbar_alt" />
|
||||
</div>""";
|
||||
"<center>";
|
||||
"<a name='comments'></a><div style='width: $*body_width; text-align:center;'>";
|
||||
"<h2>" + lang_page_of_pages($.current, $.total) + "</h2>";
|
||||
var string url_prev = $this->url_of($.current - 1);
|
||||
"<table cellspacing='0' cellpadding='0' border='0' align='center'><tr><td align='center' style='font-size: 14pt'>";
|
||||
if ($.current != 1) {
|
||||
print "<a href='$url_prev#comments'>☜</a>";
|
||||
} else {
|
||||
print "☜";
|
||||
}
|
||||
print " </td><td align='center'>";
|
||||
foreach var int i (1..$.total) {
|
||||
if ($i == $.current) { "$i"; }
|
||||
else {
|
||||
var string url_of = $this->url_of($i);
|
||||
"<a href='$url_of#comments'>$i</a>";
|
||||
}
|
||||
if ($i != $.total) { ", "; }
|
||||
}
|
||||
"</td><td align='center' style='font-size: 14pt'> ";
|
||||
var string url_next = $this->url_of($.current + 1);
|
||||
if ($.current != $.total) {
|
||||
print "<a href='$url_next#comments'>☞</a>";
|
||||
} else {
|
||||
print "☞";
|
||||
}
|
||||
"</td></tr></table></div></center>";
|
||||
}
|
||||
|
||||
function EntryPage::print_comments(Comment[] cs) {
|
||||
if (size $cs == 0) { return; }
|
||||
foreach var Comment c ($cs) {
|
||||
if($c.depth==1) {
|
||||
"</td></tr></table>";
|
||||
"""<div class="bs">
|
||||
<img src="$*dingbar_url" alt="$*text_dingbar_alt" />
|
||||
</div>""";
|
||||
"<table align='center' cellspacing='0' border='0' cellpadding='0'><tr><td>";
|
||||
}
|
||||
var int indent = ($c.depth - 1) * 21;
|
||||
"<div style='margin-left: ${indent}pt;'>\n";
|
||||
if ($c.full) {
|
||||
$this->print_comment($c);
|
||||
} else {
|
||||
$this->print_comment_partial($c);
|
||||
}
|
||||
"</div>";
|
||||
$this->print_comments($c.replies);
|
||||
}
|
||||
}
|
||||
|
||||
function EntryPage::print_comment(Comment c) {
|
||||
var string poster = defined $c.poster ? $c.poster->as_string() : $*text_poster_anonymous;
|
||||
var string sub_icon;
|
||||
if (defined $c.subject_icon) {
|
||||
$sub_icon = $c.subject_icon->as_string();
|
||||
}
|
||||
"<a name='$c.anchor'></a>";
|
||||
"<div class='bodybox'" + ($c.depth>1? " style='margin-top:${*font_leading}pt;'" : "") + ">";
|
||||
if (defined $c.userpic and $*comment_userpic_style != "off") {
|
||||
var int w = $c.userpic.width;
|
||||
var int h = $c.userpic.height;
|
||||
# WARNING: this will later be done by the system (it'll be a
|
||||
# constructional property), so don't copy this hack into your
|
||||
# layout layers or you'll be messed up later.
|
||||
if ($*comment_userpic_style == "small") {
|
||||
$w = $w / 2;
|
||||
$h = $h / 2;
|
||||
}
|
||||
"<img src='$c.userpic.url' width='$w' height='$h' alt='[User Picture]' style='float: right;' class='author' />";
|
||||
}
|
||||
|
||||
### From, date, etc
|
||||
"<div class='noul'>";
|
||||
if ($c.screened) { "<span style='color:$*text_weaker;'>(Screened) </span>"; }
|
||||
"On " + $c.time->date_format("long") + ", " + $c.time->time_format() + ", $poster ";
|
||||
if ($c.metadata{"poster_ip"}) { "(" + $c.metadata{"poster_ip"} + ") "; }
|
||||
"<a href='$c.permalink_url'>";
|
||||
if ($c.depth == 1) { "commented"; }
|
||||
else { "replied"; }
|
||||
"</a>:</div>";
|
||||
|
||||
print (defined $c.subject_icon or $c.subject != "") ? "<div class='caption'>$c.subject_icon $c.subject</div>" : "";
|
||||
|
||||
"<div class='body'>";
|
||||
render_body($c.text);
|
||||
print "</div><div class='smallbar'>";
|
||||
if ($c.frozen) {
|
||||
"Replies Frozen";
|
||||
} else {
|
||||
"<a href='$c.reply_url'>Reply</a>";
|
||||
}
|
||||
if ($c.parent_url != "") { " · <a href='$c.parent_url'>Parent</a>"; }
|
||||
if ($c.thread_url != "") { " · <a href='$c.thread_url'>Thread</a>"; }
|
||||
$c->print_linkbar();
|
||||
if ($this.multiform_on) {
|
||||
" · ";
|
||||
"<label for='ljcomsel_$c.talkid'>$*text_multiform_check</label>";
|
||||
$c->print_multiform_check();
|
||||
}
|
||||
"</div></div>";
|
||||
}
|
||||
|
||||
|
||||
function EntryPage::print_comment_partial(Comment c) {
|
||||
var string poster = defined $c.poster ? $c.poster->as_string() : $*text_poster_anonymous;
|
||||
var bool subj = $c.subject != "";
|
||||
"<div class='ult' style='width:$*body_width; margin-top:${*font_leading}pt;'>";
|
||||
"— On " + $c.time->date_format("long") + ", " + $c.time->time_format() + ", $poster ";
|
||||
if ($c.metadata{"poster_ip"}) { "(" + $c.metadata{"poster_ip"} + ") "; }
|
||||
if($subj) { """replied, <a href="$c.permalink_url">“$c.subject”</a>"""; }
|
||||
else { """posted <a href="$c.permalink_url">a reply</a>"""; }
|
||||
".</div>";
|
||||
}
|
||||
|
||||
function Comment::print_linkbar() {
|
||||
var Link link;
|
||||
foreach var string k ($.link_keyseq) {
|
||||
$link = $this->get_link($k);
|
||||
($link.caption != "") ? " · <a href='$link.url'>$link.caption</a>" : "";
|
||||
}
|
||||
}
|
||||
|
||||
function ReplyPage::print_body() {
|
||||
var bool ent = $.replyto.permalink_url == $.entry.permalink_url;
|
||||
|
||||
if($ent) {
|
||||
print_entry($this, $.entry);
|
||||
}
|
||||
else {
|
||||
"""<div class="bs">
|
||||
<img src="$*dingbar_url" alt="$*text_dingbar_alt" />
|
||||
</div>""";
|
||||
|
||||
var EntryLite c = $.replyto;
|
||||
var string poster = defined $c.poster ? $c.poster->as_string() : $*text_poster_anonymous;
|
||||
"<center><div style='width: $*body_width;'>";
|
||||
|
||||
if (defined $c.userpic and $*comment_userpic_style != "off") {
|
||||
var int w = $c.userpic.width;
|
||||
var int h = $c.userpic.height;
|
||||
# WARNING: this will later be done by the system (it'll be a
|
||||
# constructional property), so don't copy this hack into your
|
||||
# layout layers or you'll be messed up later.
|
||||
if ($*comment_userpic_style == "small") {
|
||||
$w = $w / 2;
|
||||
$h = $h / 2;
|
||||
}
|
||||
"<img src='$c.userpic.url' width='$w' height='$h' alt='[User Picture]' style='float: right;' class='author' />";
|
||||
|
||||
}
|
||||
|
||||
### From, date, etc
|
||||
|
||||
"<div class='noul'>";
|
||||
"On " + $c.time->date_format("long") + ", " + $c.time->time_format() + ", $poster ";
|
||||
if ($c.metadata{"poster_ip"}) { "(" + $c.metadata{"poster_ip"} + ") "; }
|
||||
"<a href='$c.permalink_url'>commented:</a></div>";
|
||||
|
||||
print ($c.subject != "") ? "<div class='caption'>$c.subject</div>" : "";
|
||||
|
||||
"<div class='body'>";
|
||||
render_body($c.text);
|
||||
"</div></div></center>";
|
||||
}
|
||||
|
||||
"""<div class="bs">
|
||||
<img src="$*dingbar_url" alt="$*text_dingbar_alt" />
|
||||
</div>""";
|
||||
"<div style='text-align:center;'><h2><a href='$.entry.comments.read_url'>Read Comments</a></h2></div>";
|
||||
"""<div class="bs">
|
||||
<img src="$*dingbar_url" alt="$*text_dingbar_alt" />
|
||||
</div>""";
|
||||
|
||||
if (not $.entry.comments.enabled) {
|
||||
print "<div class='sct'>$*text_reply_nocomments</div>";
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
"<center><h3 style='margin-top:0px; line-height:" + (2*$*font_leading) + "pt;'>Reply " + ($ent ? "to this entry" : "to this comment") + ":</h3>";
|
||||
$.form->print();
|
||||
"</center>";
|
||||
}
|
||||
179
local/bin/upgrading/s2layers/anovelconundrum/themes.s2
Executable file
179
local/bin/upgrading/s2layers/anovelconundrum/themes.s2
Executable file
@@ -0,0 +1,179 @@
|
||||
#NEWLAYER: anovelconundrum/renaissance
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Renaissance";
|
||||
layerinfo "redist_uniq" = "anovelconundrum/renaissance";
|
||||
|
||||
set font_secondary_fallback = "";
|
||||
set font_secondary_size = 10;
|
||||
set font_secondary_type = "serif";
|
||||
set font_leading = 12;
|
||||
set page_back = "#FAF2C8";
|
||||
set font_fallback = "";
|
||||
set font_secondary_base = "Garamond";
|
||||
set font_base = "Garamond";
|
||||
|
||||
#NEWLAYER: anovelconundrum/modern
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Modern";
|
||||
layerinfo "redist_uniq" = "anovelconundrum/modern";
|
||||
|
||||
set font_leading = 14;
|
||||
set page_back = "#F5F5E8";
|
||||
set font_fallback = "";
|
||||
set font_base = "Georgia";
|
||||
set font_flourish_base = "";
|
||||
set font_flourish_fallback = "";
|
||||
set font_flourish_type = "";
|
||||
set flourish_rm = "0.05em";
|
||||
set dc_rm = "0.1em";
|
||||
set dcLen = 5000;
|
||||
|
||||
#NEWLAYER: anovelconundrum/clippy
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Clippy";
|
||||
layerinfo "redist_uniq" = "anovelconundrum/clippy";
|
||||
|
||||
set font_leading = 13;
|
||||
set page_back = "#FFFFFF";
|
||||
set font_fallback = "Times";
|
||||
set font_base = "Times New Roman";
|
||||
set font_secondary_base = "Helvetica";
|
||||
set font_secondary_fallback = "Arial";
|
||||
set font_secondary_type = "sans-serif";
|
||||
set font_secondary_size = 8;
|
||||
set font_flourish_base = "";
|
||||
set font_flourish_fallback = "";
|
||||
set font_flourish_type = "";
|
||||
set flourish_rm = "0.05em";
|
||||
set dc_rm = "0.1em";
|
||||
set flourish_rm = "0.08em";
|
||||
set dcLen = 99999;
|
||||
set body_width = "65ex";
|
||||
|
||||
#NEWLAYER: anovelconundrum/childsplay
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Child's Play";
|
||||
layerinfo "redist_uniq" = "anovelconundrum/childsplay";
|
||||
|
||||
set page_back = "#FFE6FF";
|
||||
set font_base = "Comic Sans";
|
||||
set font_fallback = "Chalkboard";
|
||||
set font_type = "cursive";
|
||||
set font_secondary_base = "";
|
||||
set font_secondary_fallback = "";
|
||||
set font_secondary_type = "";
|
||||
set font_flourish_base = "";
|
||||
set font_flourish_fallback = "";
|
||||
set font_flourish_type = "";
|
||||
set flourish_rm = "0.05em";
|
||||
set dc_rm = "0.12em";
|
||||
set flourish_rm = "0.08em";
|
||||
set dcLen = 1000;
|
||||
|
||||
#NEWLAYER: anovelconundrum/laketahoe
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Lake Tahoe";
|
||||
layerinfo "redist_uniq" = "anovelconundrum/laketahoe";
|
||||
|
||||
set page_back = "#E6E6FF";
|
||||
set font_base = "Tahoma";
|
||||
set font_fallback = "Verdana";
|
||||
set font_type = "sans-serif";
|
||||
set font_secondary_base = "";
|
||||
set font_secondary_fallback = "";
|
||||
set font_secondary_type = "";
|
||||
set font_flourish_base = "";
|
||||
set font_flourish_fallback = "";
|
||||
set font_flourish_type = "";
|
||||
set flourish_rm = "0.05em";
|
||||
set dc_rm = "0.14em";
|
||||
set flourish_rm = "0.08em";
|
||||
set dcLen = 500;
|
||||
|
||||
#NEWLAYER: anovelconundrum/deardiary
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Dear Diary";
|
||||
layerinfo "redist_uniq" = "anovelconundrum/deardiary";
|
||||
|
||||
set page_back = "#f9f7d6";
|
||||
set font_base = "Lucida Handwriting";
|
||||
set font_fallback = "";
|
||||
set font_type = "cursive";
|
||||
set font_leading = 16;
|
||||
set body_width = "38em";
|
||||
set font_secondary_base = "";
|
||||
set font_secondary_fallback = "";
|
||||
set font_secondary_type = "";
|
||||
set font_flourish_base = "";
|
||||
set font_flourish_fallback = "";
|
||||
set font_flourish_type = "";
|
||||
set flourish_rm = "0.05em";
|
||||
set dc_rm = "0.12em";
|
||||
set flourish_rm = "0.05em";
|
||||
set dcLen = 500;
|
||||
|
||||
#NEWLAYER: anovelconundrum/scribal
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Scribal";
|
||||
layerinfo "redist_uniq" = "anovelconundrum/scribal";
|
||||
|
||||
set page_back = "#FAF2C8";
|
||||
set font_base = "Lucida Calligraphy";
|
||||
set font_fallback = "";
|
||||
set font_type = "cursive";
|
||||
set font_leading = 15;
|
||||
set title_smallcaps = false;
|
||||
set title_underline = true;
|
||||
set font_secondary_base = "";
|
||||
set font_secondary_fallback = "";
|
||||
set font_secondary_type = "";
|
||||
set font_flourish_base = "";
|
||||
set font_flourish_fallback = "";
|
||||
set font_flourish_type = "";
|
||||
set flourish_rm = "0.05em";
|
||||
set dc_rm = "0.12em";
|
||||
set flourish_rm = "0.05em";
|
||||
set dcLen = 500;
|
||||
|
||||
#NEWLAYER: anovelconundrum/glossy
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Glossy Magazine";
|
||||
layerinfo "redist_uniq" = "anovelconundrum/glossy";
|
||||
|
||||
set page_back = "#F4FBFF";
|
||||
set font_base = "Lucida Bright";
|
||||
set font_fallback = "Georgia";
|
||||
set font_type = "serif";
|
||||
set font_secondary_base = "Lucida Sans";
|
||||
set font_secondary_fallback = "";
|
||||
set font_secondary_type = "sans-serif";
|
||||
set font_secondary_size = 9;
|
||||
set font_flourish_base = "Agency FB";
|
||||
set font_flourish_fallback = "";
|
||||
set font_flourish_type = "";
|
||||
set flourish_rm = "0.05em";
|
||||
set dc_rm = "0.08em";
|
||||
set flourish_rm = "0.02em";
|
||||
set dcLen = 1200;
|
||||
|
||||
#NEWLAYER: anovelconundrum/retro
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Retrossential";
|
||||
layerinfo "redist_uniq" = "anovelconundrum/retro";
|
||||
|
||||
set page_back = "#f9f9e3";
|
||||
set font_base = "Rockwell";
|
||||
set font_fallback = "";
|
||||
set font_type = "serif";
|
||||
set font_size = 11;
|
||||
set font_secondary_base = "";
|
||||
set font_secondary_fallback = "";
|
||||
set font_secondary_type = "";
|
||||
set font_secondary_size = 10;
|
||||
set font_flourish_base = "";
|
||||
set font_flourish_fallback = "";
|
||||
set font_flourish_type = "";
|
||||
set flourish_rm = "0.05em";
|
||||
set dc_rm = "0.12em";
|
||||
set flourish_rm = "0.05em";
|
||||
set dcLen = 500;
|
||||
BIN
local/bin/upgrading/s2layers/boxer/boxer.jpg
Executable file
BIN
local/bin/upgrading/s2layers/boxer/boxer.jpg
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
1997
local/bin/upgrading/s2layers/boxer/layout.s2
Executable file
1997
local/bin/upgrading/s2layers/boxer/layout.s2
Executable file
File diff suppressed because it is too large
Load Diff
225
local/bin/upgrading/s2layers/boxer/themes.s2
Executable file
225
local/bin/upgrading/s2layers/boxer/themes.s2
Executable file
@@ -0,0 +1,225 @@
|
||||
#NEWLAYER: boxer/lipstick
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Lipstick";
|
||||
layerinfo redist_uniq = "boxer/lipstick";
|
||||
layerinfo "source_viewable" = 0;
|
||||
set color_nav_bg = "#B46F60";
|
||||
set entry_link = "#ffeae5";
|
||||
set entry_bg = "#eebbaf";
|
||||
set nav_scale = "darker";
|
||||
set info_font = "#A55745";
|
||||
set bg_color = "#fac7bb";
|
||||
set entry_font = "#A55745";
|
||||
set info_link_visited = "#ffeae5";
|
||||
set page_background_pattern = "background-hearts.gif";
|
||||
set entry_link_visited = "#ffffff";
|
||||
set info_bg = "#e5a799";
|
||||
set info_link = "#FFF9F8";
|
||||
|
||||
|
||||
#NEWLAYER: boxer/greyskies
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Grey Skies";
|
||||
layerinfo redist_uniq = "boxer/greyskies";
|
||||
layerinfo "source_viewable" = 0;
|
||||
set color_nav_bg = "#9aaeb6";
|
||||
set entry_link = "#997D63";
|
||||
set entry_bg = "#f2eae2";
|
||||
set nav_scale = "lighter";
|
||||
set info_font = "#627a84";
|
||||
set bg_color = "#dde1e3";
|
||||
set entry_font = "#7f97a0";
|
||||
set info_link_visited = "#CEDBDF";
|
||||
set page_background_pattern = "background-vert-stripes.gif";
|
||||
set entry_link_visited = "#b4a18f";
|
||||
set info_bg = "#8c9ca2";
|
||||
set info_link = "#b9c7cc";
|
||||
|
||||
#NEWLAYER: boxer/eggplant
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Eggplant";
|
||||
layerinfo redist_uniq = "boxer/eggplant";
|
||||
layerinfo "source_viewable" = 0;
|
||||
set color_nav_bg = "#4e6559";
|
||||
set entry_link = "#9FAE8D";
|
||||
set entry_bg = "#635A48";
|
||||
set nav_scale = "lighter";
|
||||
set info_font = "#899BA3";
|
||||
set bg_color = "#9fae8d";
|
||||
set entry_font = "#E7DFCF";
|
||||
set info_link_visited = "#b9c7cc";
|
||||
set entry_link_visited = "#A6B2AC";
|
||||
set info_bg = "#464640";
|
||||
set info_link = "#b9c7cc";
|
||||
|
||||
|
||||
#NEWLAYER: boxer/lonelyturquoise
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Lonely Turquoise";
|
||||
layerinfo redist_uniq = "boxer/lonelyturquoise";
|
||||
layerinfo "source_viewable" = 0;
|
||||
set page_background_pattern = "background-lg-boxes.gif";
|
||||
set color_nav_bg = "#7f7f7f";
|
||||
set entry_link_visited = "#ededed";
|
||||
set entry_link = "#ffffff";
|
||||
set entry_bg = "#ABABAB";
|
||||
set info_font = "#000000";
|
||||
set info_bg = "#00b1ae";
|
||||
set bg_color = "#ffffff";
|
||||
set entry_font = "#363636";
|
||||
set info_link = "#006260";
|
||||
|
||||
|
||||
#NEWLAYER: boxer/legallypink
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Legally Pink";
|
||||
layerinfo redist_uniq = "boxer/legallypink";
|
||||
layerinfo "source_viewable" = 0;
|
||||
set color_nav_bg = "#ff089b";
|
||||
set entry_link_visited = "#70086F";
|
||||
set entry_link = "#4D0870";
|
||||
set entry_bg = "#ec008c";
|
||||
set nav_scale = "lighter";
|
||||
set info_font = "#ec008c";
|
||||
set bg_color = "#f49ac1";
|
||||
set entry_font = "#fbdbee";
|
||||
set info_link_visited = "#CE1182";
|
||||
set page_background_pattern = "background-hearts.gif";
|
||||
set info_bg = "#ffadde";
|
||||
set info_link = "#E3026A";
|
||||
|
||||
#NEWLAYER: boxer/greybrowngreen
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Grey Brown Green";
|
||||
layerinfo redist_uniq = "boxer/greybrowngreen";
|
||||
layerinfo "source_viewable" = 0;
|
||||
set color_nav_bg = "#2f372e";
|
||||
set entry_link = "#212919";
|
||||
set entry_bg = "#586C44";
|
||||
set nav_scale = "lighter";
|
||||
set info_font = "#A1926C";
|
||||
set bg_color = "#000000";
|
||||
set entry_font = "#D9E1D2";
|
||||
set info_link_visited = "#B1AD9B";
|
||||
set entry_link_visited = "#2C3F28";
|
||||
set info_bg = "#433a1e";
|
||||
set info_link = "#B1AD9B";
|
||||
|
||||
#NEWLAYER: boxer/precious
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Precious";
|
||||
layerinfo redist_uniq = "boxer/precious";
|
||||
layerinfo "source_viewable" = 0;
|
||||
set color_nav_bg = "#A17682";
|
||||
set entry_link = "#0F486E";
|
||||
set entry_bg = "#c6cfd5";
|
||||
set nav_scale = "lighter";
|
||||
set info_font = "#F7FDFC";
|
||||
set bg_color = "#d9e1d9";
|
||||
set entry_font = "#6C7982";
|
||||
set info_link_visited = "#E4ECEB";
|
||||
set entry_link_visited = "#3F6A86";
|
||||
set info_bg = "#a2b2b1";
|
||||
set info_link = "#E4ECEB";
|
||||
|
||||
#NEWLAYER: boxer/purple
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Purple";
|
||||
layerinfo redist_uniq = "boxer/purple";
|
||||
layerinfo "source_viewable" = 0;
|
||||
set color_nav_bg = "#78629C";
|
||||
set entry_link = "#F9F5FC";
|
||||
set entry_bg = "#62536C";
|
||||
set nav_scale = "lighter";
|
||||
set info_font = "#A38FA3";
|
||||
set bg_color = "#8B77A9";
|
||||
set entry_font = "#DCD3E2";
|
||||
set info_link_visited = "#A799BF";
|
||||
set entry_link_visited = "#ffffff";
|
||||
set info_bg = "#472B47";
|
||||
set info_link = "#A799BF";
|
||||
|
||||
#NEWLAYER: boxer/green
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Green";
|
||||
layerinfo redist_uniq = "boxer/green";
|
||||
layerinfo "source_viewable" = 0;
|
||||
set color_nav_bg = "#748A25";
|
||||
set entry_link = "#EAF9D4";
|
||||
set entry_bg = "#748A25";
|
||||
set nav_scale = "lighter";
|
||||
set info_font = "#004C3C";
|
||||
set bg_color = "#254634";
|
||||
set entry_font = "#E2EED0";
|
||||
set info_link_visited = "#00EEBC";
|
||||
set entry_link_visited = "#EAF9D4";
|
||||
set info_bg = "#0E9B7D";
|
||||
set info_link = "#61EFD1";
|
||||
|
||||
#NEWLAYER: boxer/purpange
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Purpange";
|
||||
layerinfo redist_uniq = "boxer/purpange";
|
||||
layerinfo "source_viewable" = 0;
|
||||
set color_nav_bg = "#151e1a";
|
||||
set nav_scale = "lighter";
|
||||
set entry_link = "#ffffff";
|
||||
set entry_bg = "#E7513E";
|
||||
set info_font = "#f6cab7";
|
||||
set bg_color = "#ffffff";
|
||||
set entry_font = "#FDE9E6";
|
||||
set info_link_visited = "#afe900";
|
||||
set page_background_pattern = "background-stitched.gif";
|
||||
set entry_link_visited = "#ffffff";
|
||||
set info_bg = "#91125f";
|
||||
set info_link = "#afe900";
|
||||
|
||||
#NEWLAYER: boxer/purplesalmon
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Purple Salmon";
|
||||
layerinfo redist_uniq = "boxer/purplesalmon";
|
||||
layerinfo "source_viewable" = 0;
|
||||
set color_nav_bg = "#AA6B90";
|
||||
set entry_link = "#633F4B";
|
||||
set entry_bg = "#CEADB8";
|
||||
set nav_scale = "same";
|
||||
set info_font = "#F0B4AA";
|
||||
set bg_color = "#151E1A";
|
||||
set entry_font = "#6D5B61";
|
||||
set info_link_visited = "#7E3D33";
|
||||
set entry_link_visited = "#633F4B";
|
||||
set info_bg = "#D26E5E";
|
||||
set info_link = "#7E3D33";
|
||||
|
||||
#NEWLAYER: boxer/refriedtribute
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Refried Tribute";
|
||||
layerinfo redist_uniq = "boxer/refriedtribute";
|
||||
layerinfo "source_viewable" = 0;
|
||||
set color_nav_bg = "#666666";
|
||||
set entry_link = "#336699";
|
||||
set entry_bg = "#e6e6e6";
|
||||
set info_font = "#999966";
|
||||
set bg_color = "#ffffff";
|
||||
set entry_font = "#656565";
|
||||
set info_link_visited = "#4d4d4d";
|
||||
set page_background_pattern = "none";
|
||||
set entry_link_visited = "#336699";
|
||||
set info_bg = "#cccc99";
|
||||
set info_link = "#666666";
|
||||
|
||||
#NEWLAYER: boxer/blue
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Blue";
|
||||
layerinfo redist_uniq = "boxer/blue";
|
||||
layerinfo "source_viewable" = 0;
|
||||
set color_nav_bg = "#3A6A74";
|
||||
set entry_link = "#E0DFCE";
|
||||
set entry_bg = "#4F7B8A";
|
||||
set info_font = "#908F78";
|
||||
set bg_color = "#435754";
|
||||
set entry_font = "#E7EEF0";
|
||||
set info_link_visited = "#5D5C50";
|
||||
set entry_link_visited = "#E0DFCE";
|
||||
set info_bg = "#E0DFCE";
|
||||
set info_link = "#4E5964";
|
||||
BIN
local/bin/upgrading/s2layers/component/component.jpg
Executable file
BIN
local/bin/upgrading/s2layers/component/component.jpg
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 9.4 KiB |
2806
local/bin/upgrading/s2layers/component/layout.s2
Executable file
2806
local/bin/upgrading/s2layers/component/layout.s2
Executable file
File diff suppressed because it is too large
Load Diff
187
local/bin/upgrading/s2layers/component/themes.s2
Executable file
187
local/bin/upgrading/s2layers/component/themes.s2
Executable file
@@ -0,0 +1,187 @@
|
||||
#NEWLAYER: component/aquatic
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Aquatic";
|
||||
layerinfo redist_uniq = "component/aquatic";
|
||||
layerinfo "source_viewable" = 0;
|
||||
set entry_fgcolor = "#515151";
|
||||
set comp_bgcolor = "#51ada6";
|
||||
set header_link = "#ffffff";
|
||||
set entry_link = "#0C5D57";
|
||||
set entry_bgcolor = "#ffffff";
|
||||
set header_fgcolor = "#c7d1cc";
|
||||
set main_bgcolor = "#51ada6";
|
||||
set calendar_active = "#318D86";
|
||||
set header_bgcolor = "#0e3b4a";
|
||||
set calendar_inactive = "#ffffff";
|
||||
set comp_fgcolor = "#F7FEFF";
|
||||
|
||||
#NEWLAYER: component/bluetiful
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Bluetiful";
|
||||
layerinfo redist_uniq = "component/bluetiful";
|
||||
layerinfo "source_viewable" = 0;
|
||||
set entry_fgcolor = "#606060";
|
||||
set comp_bgcolor = "#f4f4f4";
|
||||
set header_link = "#f7fcfb";
|
||||
set entry_link = "#2d3679";
|
||||
set entry_bgcolor = "#eff5ff";
|
||||
set header_fgcolor = "#327192";
|
||||
set main_bgcolor = "#a2c5e3";
|
||||
set header_bgcolor = "#6da6c4";
|
||||
set comments_bgcolor = "#84b5d2";
|
||||
|
||||
#NEWLAYER: component/darkness
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Darkness";
|
||||
layerinfo redist_uniq = "component/darkness";
|
||||
layerinfo "source_viewable" = 0;
|
||||
set comments_screened_bgcolor = "#22620e";
|
||||
set calendar_fgcolor = "#5b6c7a";
|
||||
set calendar_active = "#5b6c7a";
|
||||
set calendar_inactive = "#adbac5";
|
||||
set comp_fgcolor = "#dadde0";
|
||||
set entry_fgcolor = "#dddcd6";
|
||||
set comp_bgcolor = "#758491";
|
||||
set entry_link = "#adb6be";
|
||||
set header_link = "#c7ccd1";
|
||||
set entry_bgcolor = "#32343d";
|
||||
set main_bgcolor = "#71837A";
|
||||
set header_fgcolor = "#c7d1cc";
|
||||
set header_bgcolor = "#728d80";
|
||||
set comments_bgcolor = "#5a5a5a";
|
||||
|
||||
#NEWLAYER: component/jedicloak
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Jedi Cloak";
|
||||
layerinfo redist_uniq = "component/jedicloak";
|
||||
layerinfo "source_viewable" = 0;
|
||||
set entry_fgcolor = "#F1EDE5";
|
||||
set comp_bgcolor = "#988b67";
|
||||
set header_link = "#dddbd6";
|
||||
set entry_link = "#615020";
|
||||
set entry_bgcolor = "#ada386";
|
||||
set comments_screened_bgcolor = "#a29f97";
|
||||
set header_fgcolor = "#bcb59f";
|
||||
set main_bgcolor = "#6e5845";
|
||||
set calendar_active = "#817452";
|
||||
set header_bgcolor = "#6e6449";
|
||||
set calendar_inactive = "#988b67";
|
||||
set comp_fgcolor = "#383325";
|
||||
set comments_bgcolor = "#948B6F";
|
||||
|
||||
#NEWLAYER: component/mellow
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Mellow";
|
||||
layerinfo redist_uniq = "component/mellow";
|
||||
layerinfo "source_viewable" = 0;
|
||||
set comments_screened_bgcolor = "#D6C8CC";
|
||||
set page_background_image = "";
|
||||
set calendar_active = "#D9E1D9";
|
||||
set calendar_inactive = "#A2B2B1";
|
||||
set comp_fgcolor = "878D8D";
|
||||
set entry_fgcolor = "#355351";
|
||||
set comp_bgcolor = "#C6CFD5";
|
||||
set entry_link = "#6B7F8D";
|
||||
set header_link = "6B7F8D";
|
||||
set entry_bgcolor = "#A2B2B1";
|
||||
set main_bgcolor = "#D6C8CC";
|
||||
set header_fgcolor = "#96A891";
|
||||
set header_bgcolor = "#D9E1D9";
|
||||
set comments_bgcolor = "#BCC4C3";
|
||||
|
||||
#NEWLAYER: component/mocha
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Mocha";
|
||||
layerinfo redist_uniq = "component/mocha";
|
||||
layerinfo "source_viewable" = 0;
|
||||
set page_background_image = "";
|
||||
set entry_fgcolor = "#807C75";
|
||||
set comp_bgcolor = "#b1bbb4";
|
||||
set comp_fgcolor = "#78746e";
|
||||
set header_link = "#716C53";
|
||||
set entry_link = "#67716a";
|
||||
set entry_bgcolor = "#ebe6d1";
|
||||
set comments_screened_bgcolor = "#b2c9b9";
|
||||
set header_fgcolor = "#7a6f43";
|
||||
set main_bgcolor = "#d8d0ae";
|
||||
set calendar_active = "#8da193";
|
||||
set header_bgcolor = "#d8d0ae";
|
||||
set calendar_inactive = "#d3e1d7";
|
||||
set comments_bgcolor = "#dbdedc";
|
||||
|
||||
#NEWLAYER: component/orangesoda
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Orange Soda";
|
||||
layerinfo redist_uniq = "component/orangesoda";
|
||||
layerinfo "source_viewable" = 0;
|
||||
set entry_fgcolor = "#8a5b33";
|
||||
set comp_bgcolor = "#c4bd8e";
|
||||
set header_link = "#FFFFFF";
|
||||
set entry_link = "#613815";
|
||||
set entry_bgcolor = "#dbd7b9";
|
||||
set comments_screened_bgcolor = "#cbc9b9";
|
||||
set header_fgcolor = "#d7d2af";
|
||||
set main_bgcolor = "#cd9338";
|
||||
set calendar_active = "#cd9338";
|
||||
set header_bgcolor = "#c6710a";
|
||||
set calendar_inactive = "#dbd7b9";
|
||||
set comments_bgcolor = "#e4deb5";
|
||||
|
||||
#NEWLAYER: component/pinkelephants
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Pink Elephants";
|
||||
layerinfo redist_uniq = "component/pinkelephants";
|
||||
layerinfo "source_viewable" = 0;
|
||||
set comments_screened_bgcolor = "#e29994";
|
||||
set page_background_image = "";
|
||||
set calendar_active = "#a8a8a7";
|
||||
set calendar_inactive = "#e29994";
|
||||
set comp_fgcolor = "#ad5a55";
|
||||
set entry_fgcolor = "#ffffff";
|
||||
set comp_bgcolor = "#f7b3ae";
|
||||
set entry_link = "#777776";
|
||||
set header_link = "#FFFFFF";
|
||||
set entry_bgcolor = "#a8a8a7";
|
||||
set main_bgcolor = "#e29994";
|
||||
set header_fgcolor = "#ad5a55";
|
||||
set header_bgcolor = "#e29994";
|
||||
set comments_bgcolor = "#9c9c9c";
|
||||
|
||||
#NEWLAYER: component/sugarspice
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Sugar and Spice";
|
||||
layerinfo redist_uniq = "component/sugarspice";
|
||||
layerinfo "source_viewable" = 0;
|
||||
set entry_fgcolor = "#927DAD";
|
||||
set comp_bgcolor = "#D5EBFA";
|
||||
set header_link = "#6e5593";
|
||||
set entry_link = "#759EBA";
|
||||
set entry_bgcolor = "#D5E9D7";
|
||||
set comments_screened_bgcolor = "#BEC9BF";
|
||||
set header_fgcolor = "#6E5593";
|
||||
set main_bgcolor = "#FCD9C4";
|
||||
set calendar_active = "#FCD9C4";
|
||||
set header_bgcolor = "#D4CAE1";
|
||||
set calendar_inactive = "#D4CAE1";
|
||||
set comp_fgcolor = "AA9ABF";
|
||||
set comments_bgcolor = "#B9DABC";
|
||||
|
||||
#NEWLAYER: component/greensuperhero
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "That Green Superhero";
|
||||
layerinfo redist_uniq = "component/greensuperhero";
|
||||
layerinfo "source_viewable" = 0;
|
||||
set comments_screened_bgcolor = "#c99bd7";
|
||||
set page_background_image = "";
|
||||
set calendar_active = "#bc6ed4";
|
||||
set calendar_inactive = "#c99bd7";
|
||||
set comp_fgcolor = "#bc87cb";
|
||||
set entry_fgcolor = "#424242";
|
||||
set comp_bgcolor = "#efefe1";
|
||||
set entry_link = "#027040";
|
||||
set header_link = "#ffffff";
|
||||
set entry_bgcolor = "#e4ede9";
|
||||
set main_bgcolor = "#16b16c";
|
||||
set header_fgcolor = "#d0efe2";
|
||||
set header_bgcolor = "#049957";
|
||||
set comments_bgcolor = "#bed8cc";
|
||||
1507
local/bin/upgrading/s2layers/cuteness/layout.s2
Executable file
1507
local/bin/upgrading/s2layers/cuteness/layout.s2
Executable file
File diff suppressed because it is too large
Load Diff
2076
local/bin/upgrading/s2layers/flexiblesquares/layout.s2
Executable file
2076
local/bin/upgrading/s2layers/flexiblesquares/layout.s2
Executable file
File diff suppressed because it is too large
Load Diff
615
local/bin/upgrading/s2layers/flexiblesquares/themes.s2
Executable file
615
local/bin/upgrading/s2layers/flexiblesquares/themes.s2
Executable file
@@ -0,0 +1,615 @@
|
||||
#NEWLAYER: flexiblesquares/autumn
|
||||
layerinfo "redist_uniq" = "flexiblesquares/autumn";
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Autumn";
|
||||
layerinfo author_name = "sub_divided/cyrnelle";
|
||||
|
||||
set page_bgcolor = "#351805";
|
||||
set page_fgcolor = "#000000";
|
||||
|
||||
set content_bgcolor = "#6a3106";
|
||||
|
||||
set entry_bgcolor = "#eee293";
|
||||
set entry_fgcolor = "#661f0c";
|
||||
|
||||
set border_color = "#000000";
|
||||
|
||||
set entrytitle_bgcolor = "#8b4e1d";
|
||||
|
||||
set outer_table_bgcolor = "#c47b51";
|
||||
|
||||
set sidebar_header_bgcolor = "#8b4e1d";
|
||||
set sidebar_fgcolor = "#000000";
|
||||
|
||||
set header_footer_bgcolor = "#eee293";
|
||||
set header_footer_fgcolor = "#661f0c";
|
||||
|
||||
set link_color = "#608729";
|
||||
set link_hover_color = "#661f0c";
|
||||
|
||||
set comments_link_color = "#FFFFFF";
|
||||
set comments_link_hover = "#c47b51";
|
||||
|
||||
set sidebar_link_color = "#608729";
|
||||
set sidebar_link_hover = "#eee293";
|
||||
|
||||
set header_footer_link_color = "#608729";
|
||||
set header_footer_link_hover = "#661f0c";
|
||||
|
||||
#NEWLAYER: flexiblesquares/blackwhite
|
||||
layerinfo "redist_uniq" = "flexiblesquares/blackwhite";
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Black and White and Red All Over";
|
||||
layerinfo author_name = "sub_divided/cyrnelle";
|
||||
|
||||
set page_bgcolor = "#cccccc";
|
||||
set page_fgcolor = "#ff0000";
|
||||
|
||||
set content_bgcolor = "#000000";
|
||||
|
||||
set entry_bgcolor = "#ffffff";
|
||||
set entry_fgcolor = "#000000";
|
||||
|
||||
set border_color = "#ffffff";
|
||||
|
||||
set entrytitle_bgcolor = "#cc0000";
|
||||
|
||||
set outer_table_bgcolor = "#666666";
|
||||
|
||||
set sidebar_header_bgcolor = "#cc0000";
|
||||
set sidebar_fgcolor = "#ffffff";
|
||||
|
||||
set header_footer_bgcolor = "#000000";
|
||||
set header_footer_fgcolor = "#cc0000";
|
||||
|
||||
set date_fgcolor = "#000000";
|
||||
set subject_fgcolor = "#000000";
|
||||
|
||||
set link_color = "#999999";
|
||||
set link_hover_color = "#000000";
|
||||
|
||||
set comments_link_color = "#FFFFFF";
|
||||
set comments_link_hover = "#000000";
|
||||
|
||||
set sidebar_link_color = "#999999";
|
||||
set sidebar_link_hover = "#ffffff";
|
||||
|
||||
set header_footer_link_color = "#ffffff";
|
||||
set header_footer_link_hover = "#999999";
|
||||
|
||||
#NEWLAYER: flexiblesquares/freshpaint
|
||||
layerinfo "redist_uniq" = "flexiblesquares/freshpaint";
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Fresh Paint";
|
||||
layerinfo author_name = "sub_divided/cyrnelle";
|
||||
|
||||
set page_bgcolor = "#993366";
|
||||
set page_fgcolor = "#006633";
|
||||
|
||||
set content_bgcolor = "#ff9933";
|
||||
|
||||
set entry_bgcolor = "#ffff99";
|
||||
set entry_fgcolor = "#000000";
|
||||
|
||||
set border_color = "#6699cc";
|
||||
|
||||
set entrytitle_bgcolor = "#ccff66";
|
||||
|
||||
set outer_table_bgcolor = "#330033";
|
||||
|
||||
set sidebar_header_bgcolor = "#ccff66";
|
||||
set sidebar_fgcolor = "#000000";
|
||||
|
||||
set header_footer_bgcolor = "#ffff99";
|
||||
set header_footer_fgcolor = "#006633";
|
||||
|
||||
set date_fgcolor = "#000000";
|
||||
set subject_fgcolor = "#000000";
|
||||
|
||||
set link_color = "#993333";
|
||||
set link_hover_color = "#330033";
|
||||
|
||||
set comments_link_color = "#993333";
|
||||
set comments_link_hover = "#330033";
|
||||
|
||||
set sidebar_link_color = "#993333";
|
||||
set sidebar_link_hover = "#330033";
|
||||
|
||||
set header_footer_link_color = "#993333";
|
||||
set header_footer_link_hover = "#330033";
|
||||
|
||||
#NEWLAYER: flexiblesquares/nautical
|
||||
layerinfo "redist_uniq" = "flexiblesquares/nautical";
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Nautical";
|
||||
layerinfo author_name = "sub_divided/cyrnelle";
|
||||
|
||||
set page_bgcolor = "#bad2f6";
|
||||
set page_fgcolor = "#000000";
|
||||
|
||||
set content_bgcolor = "#213659";
|
||||
|
||||
set entry_bgcolor = "#ffffff";
|
||||
set entry_fgcolor = "#000000";
|
||||
|
||||
set border_color = "#d4e2f8";
|
||||
|
||||
set entrytitle_bgcolor = "#f0ef8e";
|
||||
|
||||
set outer_table_bgcolor = "#335288";
|
||||
|
||||
set sidebar_header_bgcolor = "#f0ef8e";
|
||||
set sidebar_fgcolor = "#7fa1d5";
|
||||
|
||||
set header_footer_bgcolor = "#213659";
|
||||
set header_footer_fgcolor = "#f0ef8e";
|
||||
|
||||
set date_fgcolor = "#000000";
|
||||
set subject_fgcolor = "#000000";
|
||||
|
||||
set link_color = "#7fa1d5";
|
||||
set link_hover_color = "#000000";
|
||||
|
||||
set comments_link_color = "#335288";
|
||||
set comments_link_hover = "#7fa1d5";
|
||||
|
||||
set sidebar_link_color = "#f0ef8e";
|
||||
set sidebar_link_hover = "#000000";
|
||||
|
||||
set header_footer_link_color = "#7fa1d5";
|
||||
set header_footer_link_hover = "#ffffff";
|
||||
|
||||
#NEWLAYER: flexiblesquares/machine
|
||||
layerinfo "redist_uniq" = "flexiblesquares/machine";
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Machine";
|
||||
layerinfo author_name = "sub_divided/cyrnelle";
|
||||
|
||||
set page_bgcolor = "#000000";
|
||||
set page_fgcolor = "#C1C1C1";
|
||||
|
||||
set content_bgcolor = "#000000";
|
||||
|
||||
set entry_bgcolor = "#000000";
|
||||
set entry_fgcolor = "#cbd3d8";
|
||||
|
||||
set border_color = "#7e8997";
|
||||
|
||||
set entrytitle_bgcolor = "#555a60";
|
||||
|
||||
set outer_table_bgcolor = "#000000";
|
||||
|
||||
set sidebar_header_bgcolor = "#555a60";
|
||||
set sidebar_fgcolor = "#C1C1C1";
|
||||
|
||||
set header_footer_bgcolor = "#000000";
|
||||
set header_footer_fgcolor = "#C1C1C1";
|
||||
|
||||
set date_fgcolor = "#C1C1C1";
|
||||
set subject_fgcolor = "#C1C1C1";
|
||||
|
||||
set link_color = "#8797a0";
|
||||
set link_hover_color = "#ffffff";
|
||||
|
||||
set comments_link_color = "#8797a0";
|
||||
set comments_link_hover = "#ffffff";
|
||||
|
||||
set sidebar_link_color = "#8797a0";
|
||||
set sidebar_link_hover = "#ffffff";
|
||||
|
||||
set header_footer_link_color = "#8797a0";
|
||||
set header_footer_link_hover = "#ffffff";
|
||||
|
||||
#NEWLAYER: flexiblesquares/pastelspring
|
||||
layerinfo "redist_uniq" = "flexiblesquares/pastelspring";
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Pastel Spring";
|
||||
layerinfo author_name = "sub_divided/cyrnelle";
|
||||
|
||||
set page_bgcolor = "#ffffff";
|
||||
set page_fgcolor = "#993333";
|
||||
|
||||
set content_bgcolor = "#ffffcc";
|
||||
|
||||
set entry_bgcolor = "#ffffff";
|
||||
set entry_fgcolor = "#000000";
|
||||
|
||||
set border_color = "#ebccb1";
|
||||
|
||||
set entrytitle_bgcolor = "#ebccb1";
|
||||
|
||||
set outer_table_bgcolor = "#dae3b2";
|
||||
|
||||
set sidebar_header_bgcolor = "#ebccb1";
|
||||
set sidebar_fgcolor = "#993333";
|
||||
|
||||
set header_footer_bgcolor = "#ffffff";
|
||||
set header_footer_fgcolor = "#9FA876";
|
||||
|
||||
set date_fgcolor = "#993333";
|
||||
set subject_fgcolor = "#993333";
|
||||
|
||||
set link_color = "#9d7980";
|
||||
set link_hover_color = "#000000";
|
||||
|
||||
set comments_link_color = "#993333";
|
||||
set comments_link_hover = "#ffffff";
|
||||
|
||||
set sidebar_link_color = "#9d7980";
|
||||
set sidebar_link_hover = "#9FA876";
|
||||
|
||||
set header_footer_link_color = "#9F3E3E";
|
||||
set header_footer_link_hover = "#ebccb1";
|
||||
|
||||
#NEWLAYER: flexiblesquares/pinkpunk
|
||||
layerinfo "redist_uniq" = "flexiblesquares/pinkpunk";
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Pink Punk";
|
||||
layerinfo author_name = "sub_divided/cyrnelle";
|
||||
|
||||
set page_bgcolor = "#000000";
|
||||
set page_fgcolor = "#cc0066";
|
||||
|
||||
set content_bgcolor = "#000000";
|
||||
|
||||
set entry_bgcolor = "#ffccff";
|
||||
set entry_fgcolor = "#000000";
|
||||
|
||||
set border_color = "#000000";
|
||||
|
||||
set entrytitle_bgcolor = "#ff6699";
|
||||
|
||||
set outer_table_bgcolor = "#cc0066";
|
||||
|
||||
|
||||
set sidebar_header_bgcolor = "#ff6699";
|
||||
set sidebar_fgcolor = "#ffccff";
|
||||
|
||||
set header_footer_bgcolor = "#ffccff";
|
||||
set header_footer_fgcolor = "#000000";
|
||||
|
||||
set date_fgcolor = "#000000";
|
||||
set subject_fgcolor = "#000000";
|
||||
|
||||
set link_color = "#6666cc";
|
||||
set link_hover_color = "#ff6699";
|
||||
|
||||
set comments_link_color = "#ffccff";
|
||||
set comments_link_hover = "#6666cc";
|
||||
|
||||
set sidebar_link_color = "#6666cc";
|
||||
set sidebar_link_hover = "#ff6699";
|
||||
|
||||
set header_footer_link_color = "#6666cc";
|
||||
set header_footer_link_hover = "#ff6699";
|
||||
|
||||
#NEWLAYER: flexiblesquares/purpleperiwinkle
|
||||
layerinfo "redist_uniq" = "flexiblesquares/purpleperiwinkle";
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Purple Periwinkle";
|
||||
layerinfo author_name = "sub_divided/cyrnelle";
|
||||
|
||||
set page_bgcolor = "#2f0b31";
|
||||
set page_fgcolor = "#2f0b31";
|
||||
|
||||
set content_bgcolor = "#671368";
|
||||
|
||||
set entry_bgcolor = "#f4a3e9";
|
||||
set entry_fgcolor = "#2f0b31";
|
||||
|
||||
set border_color = "#2f0b31";
|
||||
|
||||
set entrytitle_bgcolor = "#9488d8";
|
||||
|
||||
set outer_table_bgcolor = "#a13ea7";
|
||||
|
||||
set sidebar_header_bgcolor = "#9488d8";
|
||||
set sidebar_fgcolor = "#DADADA";
|
||||
|
||||
set header_footer_bgcolor = "#f4a3e9";
|
||||
set header_footer_fgcolor = "#2f0b31";
|
||||
|
||||
set date_fgcolor = "#2f0b31";
|
||||
set subject_fgcolor = "#2f0b31";
|
||||
|
||||
set link_color = "#dc039d";
|
||||
set link_hover_color = "#7e025a";
|
||||
|
||||
set comments_link_color = "#7e025a";
|
||||
set comments_link_hover = "#f4a3e9";
|
||||
|
||||
set sidebar_link_color = "#dc039d";
|
||||
set sidebar_link_hover = "#FFCCCC";
|
||||
|
||||
set header_footer_link_color = "#dc039d";
|
||||
set header_footer_link_hover = "#7e025a";
|
||||
|
||||
#NEWLAYER: flexiblesquares/grays
|
||||
layerinfo "redist_uniq" = "flexiblesquares/grays";
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Grays";
|
||||
layerinfo author_name = "sub_divided/cyrnelle";
|
||||
|
||||
set page_bgcolor = "#111111";
|
||||
set page_fgcolor = "#ffffff";
|
||||
|
||||
set content_bgcolor = "#333333";
|
||||
|
||||
set entry_bgcolor = "#666666";
|
||||
set entry_fgcolor = "#ffffff";
|
||||
|
||||
set border_color = "#ffffff";
|
||||
|
||||
set entrytitle_bgcolor = "#000000";
|
||||
|
||||
set outer_table_bgcolor = "#222222";
|
||||
|
||||
set sidebar_header_bgcolor = "#000000";
|
||||
set sidebar_fgcolor = "#ffffff";
|
||||
|
||||
set header_footer_bgcolor = "#666666";
|
||||
set header_footer_fgcolor = "#ffffff";
|
||||
|
||||
set date_fgcolor = "#ffffff";
|
||||
set subject_fgcolor = "#ffffff";
|
||||
|
||||
set link_color = "#ffcc33";
|
||||
set link_hover_color = "#ff9933";
|
||||
|
||||
set comments_link_color = "#ffcc33";
|
||||
set comments_link_hover = "#ff9933";
|
||||
|
||||
set sidebar_link_color = "#ffcc33";
|
||||
set sidebar_link_hover = "#ff9933";
|
||||
|
||||
set header_footer_link_color = "#ffcc33";
|
||||
set header_footer_link_hover = "#ff9933";
|
||||
|
||||
#NEWLAYER: flexiblesquares/lemongrapetang
|
||||
layerinfo "redist_uniq" = "flexiblesquares/lemongrapetang";
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Lemon Grapefruit Tangerine";
|
||||
layerinfo author_name = "sub_divided/cyrnelle";
|
||||
|
||||
set page_bgcolor = "#ffff66";
|
||||
set page_fgcolor = "#993333";
|
||||
|
||||
set content_bgcolor = "#cc3333";
|
||||
|
||||
set entry_bgcolor = "#ffffcc";
|
||||
set entry_fgcolor = "#000000";
|
||||
|
||||
set border_color = "#ff9999";
|
||||
|
||||
set entrytitle_bgcolor = "#ff9933";
|
||||
|
||||
set outer_table_bgcolor = "#ffcc33";
|
||||
|
||||
set sidebar_header_bgcolor = "#ff9933";
|
||||
set sidebar_fgcolor = "#000000";
|
||||
|
||||
set header_footer_bgcolor = "#ffffcc";
|
||||
set header_footer_fgcolor = "#993333";
|
||||
|
||||
set date_fgcolor = "#000000";
|
||||
set subject_fgcolor = "#000000";
|
||||
|
||||
set link_color = "#ff9999";
|
||||
set link_hover_color = "#993333";
|
||||
|
||||
set comments_link_color = "#993333";
|
||||
set comments_link_hover = "#000000";
|
||||
|
||||
set sidebar_link_color = "#ff9999";
|
||||
set sidebar_link_hover = "#000000";
|
||||
|
||||
set header_footer_link_color = "#ff9999";
|
||||
set header_footer_link_hover = "#993333";
|
||||
|
||||
#NEWLAYER: flexiblesquares/tanteal
|
||||
layerinfo "redist_uniq" = "flexiblesquares/tanteal";
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Tan and Teal";
|
||||
layerinfo author_name = "sub_divided/cyrnelle";
|
||||
|
||||
set page_bgcolor = "#003333";
|
||||
set page_fgcolor = "#000000";
|
||||
|
||||
set content_bgcolor = "#cc9966";
|
||||
|
||||
set entry_bgcolor = "#ffffcc";
|
||||
set entry_fgcolor = "#000000";
|
||||
|
||||
set border_color = "#ffffff";
|
||||
|
||||
set entrytitle_bgcolor = "#996633";
|
||||
|
||||
set outer_table_bgcolor = "#ffcc99";
|
||||
|
||||
set sidebar_header_bgcolor = "#996633";
|
||||
set sidebar_fgcolor = "#000000";
|
||||
|
||||
set header_footer_bgcolor = "#ffffcc";
|
||||
set header_footer_fgcolor = "#000000";
|
||||
|
||||
set date_fgcolor = "#000000";
|
||||
set subject_fgcolor = "#000000";
|
||||
|
||||
set link_color = "#993333";
|
||||
set link_hover_color = "#603913";
|
||||
|
||||
set comments_link_color = "#ffffcc";
|
||||
set comments_link_hover = "#000000";
|
||||
|
||||
set sidebar_link_color = "#993333";
|
||||
set sidebar_link_hover = "#000000";
|
||||
|
||||
set header_footer_link_color = "#993333";
|
||||
set header_footer_link_hover = "#000000";
|
||||
|
||||
#NEWLAYER: flexiblesquares/gentledawn
|
||||
layerinfo "redist_uniq" = "flexiblesquares/gentledawn";
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Gentle Dawn";
|
||||
layerinfo author_name = "Yati Mansor";
|
||||
|
||||
set page_bgcolor = "#747D86";
|
||||
set page_fgcolor = "#605734";
|
||||
|
||||
set content_bgcolor = "#FCCA7D";
|
||||
|
||||
set entry_bgcolor = "#FFD3B9";
|
||||
set entry_fgcolor = "#605734";
|
||||
|
||||
set border_color = "#908350";
|
||||
|
||||
set entrytitle_bgcolor = "#BAA969";
|
||||
|
||||
set outer_table_bgcolor = "#DABD63";
|
||||
|
||||
set sidebar_header_bgcolor = "#BAA969";
|
||||
set sidebar_fgcolor = "#605734";
|
||||
|
||||
set header_footer_bgcolor = "#FFD3B9";
|
||||
set header_footer_fgcolor = "#605734";
|
||||
|
||||
|
||||
set link_color = "#7E858D";
|
||||
set link_hover_color = "#C68DA5";
|
||||
|
||||
set comments_link_color = "#FFFFFF";
|
||||
set comments_link_hover = "#605734";
|
||||
|
||||
set sidebar_link_color = "#7E858D";
|
||||
set sidebar_link_hover = "#C68DA5";
|
||||
|
||||
set header_footer_link_color = "#7E858D";
|
||||
set header_footer_link_hover = "#C68DA5";
|
||||
|
||||
#NEWLAYER: flexiblesquares/icyblue
|
||||
layerinfo "redist_uniq" = "flexiblesquares/icyblue";
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Icy Blue";
|
||||
layerinfo author_name = "Yati Mansor";
|
||||
|
||||
set page_bgcolor = "#C6C2F8";
|
||||
set page_fgcolor = "#4F4D65";
|
||||
|
||||
set content_bgcolor = "#D3DCFC";
|
||||
|
||||
set entry_bgcolor = "#DDEFFF";
|
||||
set entry_fgcolor = "#4F4D65";
|
||||
|
||||
set border_color = "#FFFFFF";
|
||||
|
||||
set entrytitle_bgcolor = "#FFFFFF";
|
||||
set date_fgcolor = "#4F4D65";
|
||||
set subject_fgcolor = "#4F4D65";
|
||||
|
||||
|
||||
set outer_table_bgcolor = "#CED2FA";
|
||||
|
||||
set sidebar_header_bgcolor = "#FFFFFF";
|
||||
set sidebar_fgcolor = "#4F4D65";
|
||||
|
||||
set header_footer_bgcolor = "#FFFFFF";
|
||||
set header_footer_fgcolor = "#4F4D65";
|
||||
|
||||
|
||||
set link_color = "#5DABAA";
|
||||
set link_hover_color = "#779595";
|
||||
|
||||
set comments_link_color = "#5DABAA";
|
||||
set comments_link_hover = "#779595";
|
||||
|
||||
set sidebar_link_color = "#5DABAA";
|
||||
set sidebar_link_hover = "#779595";
|
||||
|
||||
set header_footer_link_color = "#5DABAA";
|
||||
set header_footer_link_hover = "#779595";
|
||||
|
||||
#NEWLAYER: flexiblesquares/chocolatemilkshake
|
||||
layerinfo "redist_uniq" = "flexiblesquares/chocolatemilkshake";
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Chocolate Milkshake";
|
||||
layerinfo author_name = "Yati Mansor";
|
||||
|
||||
set page_bgcolor = "#746E4A";
|
||||
set page_fgcolor = "#000000";
|
||||
|
||||
set content_bgcolor = "#BEA16D";
|
||||
|
||||
set entry_bgcolor = "#ECD6B2";
|
||||
set entry_fgcolor = "#000000";
|
||||
|
||||
set border_color = "#FFFFFF";
|
||||
|
||||
set entrytitle_bgcolor = "#867A52";
|
||||
set date_fgcolor = "#000000";
|
||||
set subject_fgcolor = "#000000";
|
||||
|
||||
|
||||
set outer_table_bgcolor = "#A18D5F";
|
||||
|
||||
set sidebar_header_bgcolor = "#867A52";
|
||||
set sidebar_fgcolor = "#000000";
|
||||
|
||||
set header_footer_bgcolor = "#ECD6B2";
|
||||
set header_footer_fgcolor = "#000000";
|
||||
|
||||
|
||||
set link_color = "#867A52";
|
||||
set link_hover_color = "#790000";
|
||||
|
||||
set comments_link_color = "#ECD6B2";
|
||||
set comments_link_hover = "#790000";
|
||||
|
||||
set sidebar_link_color = "#790000";
|
||||
set sidebar_link_hover = "#ECD6B2";
|
||||
|
||||
set header_footer_link_color = "#867A52";
|
||||
set header_footer_link_hover = "#790000";
|
||||
|
||||
|
||||
|
||||
#NEWLAYER: flexiblesquares/eclipse
|
||||
layerinfo "redist_uniq" = "flexiblesquares/eclipse";
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Eclipse";
|
||||
layerinfo author_name = "Yati Mansor";
|
||||
|
||||
set page_bgcolor = "#000000";
|
||||
set page_fgcolor = "#000000";
|
||||
|
||||
set content_bgcolor = "#EEA802";
|
||||
|
||||
set entry_bgcolor = "#FBE274";
|
||||
set entry_fgcolor = "#000000";
|
||||
|
||||
set border_color = "#000000";
|
||||
|
||||
set entrytitle_bgcolor = "#CA5D00";
|
||||
set date_fgcolor = "#000000";
|
||||
set subject_fgcolor = "#000000";
|
||||
|
||||
|
||||
set outer_table_bgcolor = "#921800";
|
||||
|
||||
set sidebar_header_bgcolor = "#CA5D00";
|
||||
set sidebar_fgcolor = "#000000";
|
||||
|
||||
set header_footer_bgcolor = "#EEA802";
|
||||
set header_footer_fgcolor = "#000000";
|
||||
|
||||
|
||||
set link_color = "#790000";
|
||||
set link_hover_color = "#000000";
|
||||
|
||||
set comments_link_color = "#ECD6B2";
|
||||
set comments_link_hover = "#790000";
|
||||
|
||||
set sidebar_link_color = "#790000";
|
||||
set sidebar_link_hover = "#ffffff";
|
||||
|
||||
set header_footer_link_color = "#790000";
|
||||
set header_footer_link_hover = "#ffffff";
|
||||
1690
local/bin/upgrading/s2layers/nebula/layout.s2
Executable file
1690
local/bin/upgrading/s2layers/nebula/layout.s2
Executable file
File diff suppressed because it is too large
Load Diff
269
local/bin/upgrading/s2layers/nebula/themes.s2
Executable file
269
local/bin/upgrading/s2layers/nebula/themes.s2
Executable file
@@ -0,0 +1,269 @@
|
||||
#NEWLAYER: nebula/ohblue
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Oh blue";
|
||||
layerinfo "redist_uniq" = "nebula/ohblue";
|
||||
|
||||
set col_entry_bg = "#44366d";
|
||||
set col_stronger_fg = "#1b0c66";
|
||||
set col_cmtbarscrn_bg = "#ffffff";
|
||||
set col_cmtbarone_bg = "#9f9cfd";
|
||||
set col_neutral_fg = "#2f2e55";
|
||||
set col_cmtbartwo_bg = "#adb3e5";
|
||||
set col_sidebar_link = "#2f2e55";
|
||||
set col_weaker_bg = "#d9dcff";
|
||||
set col_strong_fg = "#2f2e55";
|
||||
set col_neutral_bg = "#ab5c90";
|
||||
set col_cmtbarscrn_fg = "#1b0c66";
|
||||
set col_stronger_bg = "#b8bef8";
|
||||
set col_cmtbartwo_fg = "#000000";
|
||||
set col_weak_bg = "#404380";
|
||||
set col_cmtbarone_fg = "#000000";
|
||||
set col_weaker_fg = "#04025a";
|
||||
set col_entry_link = "#000000";
|
||||
set col_entry_vlink = "#000000";
|
||||
set col_strong_bg = "#7e7cb1";
|
||||
set col_weak_fg = "#9ba2e8";
|
||||
set col_sidebar_vlink = "#1f1d46";
|
||||
|
||||
#NEWLAYER: nebula/ohgreen
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Oh green";
|
||||
layerinfo "redist_uniq" = "nebula/ohgreen";
|
||||
|
||||
set col_entry_bg = "#4ca65b";
|
||||
set col_stronger_fg = "#12661a";
|
||||
set col_cmtbarscrn_bg = "#ffffff";
|
||||
set col_cmtbarone_bg = "#bffdbe";
|
||||
set col_neutral_fg = "#12661a";
|
||||
set col_cmtbartwo_bg = "#72e580";
|
||||
set col_sidebar_link = "#12661a";
|
||||
set col_weaker_bg = "#0d6315";
|
||||
set col_strong_fg = "#12661a";
|
||||
set col_neutral_bg = "#000000";
|
||||
set col_cmtbarscrn_fg = "#000000";
|
||||
set col_stronger_bg = "#9df89f";
|
||||
set col_cmtbartwo_fg = "#000000";
|
||||
set col_weak_bg = "#08390b";
|
||||
set col_cmtbarone_fg = "#000000";
|
||||
set col_weaker_fg = "#0e2a05";
|
||||
set col_entry_link = "#000000";
|
||||
set col_entry_vlink = "#000000";
|
||||
set col_strong_bg = "#4f9f58";
|
||||
set col_weak_fg = "#08390b";
|
||||
set col_sidebar_vlink = "#12661a";
|
||||
|
||||
#NEWLAYER: nebula/ohpurple
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Oh purple";
|
||||
layerinfo "redist_uniq" = "nebula/ohpurple";
|
||||
|
||||
set col_cmtbartwo_bg = "#D89EE5";
|
||||
set col_cmtbarscrn_fg = "#000000";
|
||||
set col_entry_bg = "#eebfed";
|
||||
set col_weaker_bg = "#eebfed";
|
||||
set col_stronger_bg = "#efd5f8";
|
||||
set col_cmtbartwo_fg = "#000000";
|
||||
set col_sidebar_link = "#592b7d";
|
||||
set col_strong_bg = "#9c6e9f";
|
||||
set col_cmtbarone_bg = "#EECCFD";
|
||||
set col_stronger_fg = "#c459d1";
|
||||
set col_weaker_fg = "#0e2a05";
|
||||
set col_entry_link = "#000000";
|
||||
set col_entry_vlink = "#000000";
|
||||
set col_sidebar_vlink = "#2d1e41";
|
||||
set col_strong_fg = "#614a62";
|
||||
set col_weak_bg = "#614a62";
|
||||
set col_neutral_bg = "#000000";
|
||||
set col_cmtbarone_fg = "#000000";
|
||||
set col_cmtbarscrn_bg = "#ffffff";
|
||||
set col_weak_fg = "#a1319a";
|
||||
set col_neutral_fg = "#614a62";
|
||||
|
||||
#NEWLAYER: nebula/ohblack
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Oh black";
|
||||
layerinfo "redist_uniq" = "nebula/ohblack";
|
||||
|
||||
set col_cmtbartwo_bg = "#ffffff";
|
||||
set col_cmtbarscrn_fg = "#000000";
|
||||
set col_entry_bg = "#ffffff";
|
||||
set col_weaker_bg = "#ffffff";
|
||||
set col_stronger_bg = "#ffffff";
|
||||
set col_cmtbartwo_fg = "#000000";
|
||||
set col_sidebar_link = "#606060";
|
||||
set col_strong_bg = "#ffffff";
|
||||
set col_cmtbarone_bg = "#ffffff";
|
||||
set col_stronger_fg = "#000000";
|
||||
set col_weaker_fg = "#000000";
|
||||
set col_entry_link = "#606060";
|
||||
set col_entry_vlink = "#606060";
|
||||
set col_sidebar_vlink = "#606060";
|
||||
set col_strong_fg = "#000000";
|
||||
set col_weak_bg = "#ffffff";
|
||||
set col_neutral_bg = "#ffffff";
|
||||
set col_cmtbarone_fg = "#000000";
|
||||
set col_cmtbarscrn_bg = "#ffffff";
|
||||
set col_weak_fg = "#000000";
|
||||
set col_neutral_fg = "#000000";
|
||||
|
||||
#NEWLAYER: nebula/ohcontrast
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Oh contrast";
|
||||
layerinfo "redist_uniq" = "nebula/ohcontrast";
|
||||
|
||||
set col_cmtbartwo_bg = "#000000";
|
||||
set col_cmtbarscrn_fg = "#ffffff";
|
||||
set col_entry_bg = "#000000";
|
||||
set col_weaker_bg = "#000000";
|
||||
set col_stronger_bg = "#000000";
|
||||
set col_cmtbartwo_fg = "#ffffff";
|
||||
set col_sidebar_link = "#c0c0c0";
|
||||
set col_strong_bg = "#000000";
|
||||
set col_cmtbarone_bg = "#000000";
|
||||
set col_stronger_fg = "#ffffff";
|
||||
set col_weaker_fg = "#000000";
|
||||
set col_entry_link = "#c0c0c0";
|
||||
set col_entry_vlink = "#c0c0c0";
|
||||
set col_sidebar_vlink = "#c0c0c0";
|
||||
set col_strong_fg = "#ffffff";
|
||||
set col_weak_bg = "#000000";
|
||||
set col_neutral_bg = "#000000";
|
||||
set col_cmtbarone_fg = "#ffffff";
|
||||
set col_cmtbarscrn_bg = "#000000";
|
||||
set col_weak_fg = "#ffffff";
|
||||
set col_neutral_fg = "#ffffff";
|
||||
|
||||
#NEWLAYER: nebula/ohbedtime
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Oh bed time";
|
||||
layerinfo "redist_uniq" = "nebula/ohbedtime";
|
||||
|
||||
set col_cmtbartwo_bg = "#5c60b6";
|
||||
set col_cmtbarscrn_fg = "#ffffff";
|
||||
set col_entry_bg = "#ffffff";
|
||||
set col_weaker_bg = "#5e5b7d";
|
||||
set col_stronger_bg = "#8381da";
|
||||
set col_cmtbartwo_fg = "#ffffff";
|
||||
set col_sidebar_link = "#000000";
|
||||
set col_strong_bg = "#8381da";
|
||||
set col_cmtbarone_bg = "#605f9a";
|
||||
set col_stronger_fg = "#ffffff";
|
||||
set col_weaker_fg = "#000000";
|
||||
set col_entry_link = "#000000";
|
||||
set col_entry_vlink = "#000000";
|
||||
set col_sidebar_vlink = "#000000";
|
||||
set col_strong_fg = "#ffffff";
|
||||
set col_weak_bg = "#ffffff";
|
||||
set col_neutral_bg = "#000000";
|
||||
set col_cmtbarone_fg = "#ffffff";
|
||||
set col_cmtbarscrn_bg = "#879afa";
|
||||
set col_weak_fg = "#3c3c60";
|
||||
set col_neutral_fg = "#080255";
|
||||
|
||||
#NEWLAYER: nebula/ohgreenywhite
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Oh greeny white";
|
||||
layerinfo "redist_uniq" = "nebula/ohgreenywhite";
|
||||
|
||||
set col_entry_bg = "#ffffff";
|
||||
set col_stronger_fg = "#ffffff";
|
||||
set col_cmtbarscrn_bg = "#93f390";
|
||||
set col_cmtbarone_bg = "#7fe278";
|
||||
set col_neutral_fg = "#550301";
|
||||
set col_cmtbartwo_bg = "#4a8f41";
|
||||
set col_sidebar_link = "#000000";
|
||||
set col_weaker_bg = "#546847";
|
||||
set col_strong_fg = "#ffffff";
|
||||
set col_neutral_bg = "#000000";
|
||||
set col_cmtbarscrn_fg = "#ffffff";
|
||||
set col_stronger_bg = "#69ac59";
|
||||
set col_cmtbartwo_fg = "#ffffff";
|
||||
set col_weak_bg = "#ffffff";
|
||||
set col_cmtbarone_fg = "#ffffff";
|
||||
set col_weaker_fg = "#000000";
|
||||
set col_entry_link = "#000000";
|
||||
set col_entry_vlink = "#000000";
|
||||
set col_strong_bg = "#69ac59";
|
||||
set col_weak_fg = "#366030";
|
||||
set col_sidebar_vlink = "#000000";
|
||||
|
||||
#NEWLAYER: nebula/ohchocchip
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Oh choc chip";
|
||||
layerinfo "redist_uniq" = "nebula/ohchocchip";
|
||||
|
||||
set col_cmtbartwo_bg = "#4A8F41";
|
||||
set col_cmtbarscrn_fg = "#ffffff";
|
||||
set col_entry_bg = "#977e3b";
|
||||
set col_weaker_bg = "#546847";
|
||||
set col_stronger_bg = "#69ac59";
|
||||
set col_cmtbartwo_fg = "#ffffff";
|
||||
set col_sidebar_link = "#000000";
|
||||
set col_strong_bg = "#69ac59";
|
||||
set col_cmtbarone_bg = "#7FE278";
|
||||
set col_stronger_fg = "#5b4b26";
|
||||
set col_weaker_fg = "#000000";
|
||||
set col_entry_link = "#000000";
|
||||
set col_entry_vlink = "#000000";
|
||||
set col_sidebar_vlink = "#000000";
|
||||
set col_strong_fg = "#5b4b26";
|
||||
set col_weak_bg = "#5b4b26";
|
||||
set col_neutral_bg = "#000000";
|
||||
set col_cmtbarone_fg = "#ffffff";
|
||||
set col_cmtbarscrn_bg = "#93F390";
|
||||
set col_weak_fg = "#ffffff";
|
||||
set col_neutral_fg = "#550301";
|
||||
|
||||
#NEWLAYER: nebula/ohcoffee
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Oh coffee";
|
||||
layerinfo "redist_uniq" = "nebula/ohcoffee";
|
||||
|
||||
set col_cmtbartwo_bg = "#AFB13E";
|
||||
set col_cmtbarscrn_fg = "#ffffff";
|
||||
set col_entry_bg = "#977e3b";
|
||||
set col_weaker_bg = "#effe8f";
|
||||
set col_stronger_bg = "#fbe46a";
|
||||
set col_cmtbartwo_fg = "#ffffff";
|
||||
set col_sidebar_link = "#000000";
|
||||
set col_strong_bg = "#fbe46a";
|
||||
set col_cmtbarone_bg = "#E2C956";
|
||||
set col_stronger_fg = "#5b4b26";
|
||||
set col_weaker_fg = "#000000";
|
||||
set col_entry_link = "#000000";
|
||||
set col_entry_vlink = "#000000";
|
||||
set col_sidebar_vlink = "#000000";
|
||||
set col_strong_fg = "#5b4b26";
|
||||
set col_weak_bg = "#5b4b26";
|
||||
set col_neutral_bg = "#000000";
|
||||
set col_cmtbarone_fg = "#ffffff";
|
||||
set col_cmtbarscrn_bg = "#FCDA3E";
|
||||
set col_weak_fg = "#ffffff";
|
||||
set col_neutral_fg = "#550301";
|
||||
|
||||
#NEWLAYER: nebula/ohred
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Oh red";
|
||||
layerinfo "redist_uniq" = "nebula/ohred";
|
||||
|
||||
set col_cmtbartwo_bg = "#983035";
|
||||
set col_cmtbarscrn_fg = "#ffffff";
|
||||
set col_entry_bg = "#d90d12";
|
||||
set col_weaker_bg = "#fe0410";
|
||||
set col_stronger_bg = "#dd6568";
|
||||
set col_cmtbartwo_fg = "#ffffff";
|
||||
set col_sidebar_link = "#000000";
|
||||
set col_strong_bg = "#dd6568";
|
||||
set col_cmtbarone_bg = "#d25c64";
|
||||
set col_stronger_fg = "#ffffff";
|
||||
set col_weaker_fg = "#000000";
|
||||
set col_entry_link = "#000000";
|
||||
set col_entry_vlink = "#000000";
|
||||
set col_sidebar_vlink = "#000000";
|
||||
set col_strong_fg = "#ffffff";
|
||||
set col_weak_bg = "#bc0811";
|
||||
set col_neutral_bg = "#000000";
|
||||
set col_cmtbarone_fg = "#ffffff";
|
||||
set col_cmtbarscrn_bg = "#D38086";
|
||||
set col_weak_fg = "#ffffff";
|
||||
set col_neutral_fg = "#550301";
|
||||
1625
local/bin/upgrading/s2layers/opal/layout.s2
Executable file
1625
local/bin/upgrading/s2layers/opal/layout.s2
Executable file
File diff suppressed because it is too large
Load Diff
BIN
local/bin/upgrading/s2layers/opal/opal.jpg
Executable file
BIN
local/bin/upgrading/s2layers/opal/opal.jpg
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
105
local/bin/upgrading/s2layers/opal/themes.s2
Executable file
105
local/bin/upgrading/s2layers/opal/themes.s2
Executable file
@@ -0,0 +1,105 @@
|
||||
#NEWLAYER: opal/irishluck
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "The Luck of the Irish";
|
||||
layerinfo redist_uniq = "opal/irishluck";
|
||||
layerinfo "source_viewable" = 1;
|
||||
set color_med = "#8BA485";
|
||||
set color_fg_font = "#01331E";
|
||||
set color_fg = "#A1CB78";
|
||||
set color_med_font = "#E5FCDE";
|
||||
set color_bg = "#0B4107";
|
||||
|
||||
#NEWLAYER: opal/undersea
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo redist_uniq = "opal/undersea";
|
||||
layerinfo "source_viewable" = 1;
|
||||
layerinfo "name" = "Under the Sea";
|
||||
set color_med = "#98A3A4";
|
||||
set color_fg = "#93CBCA";
|
||||
set color_med_font = "#526160";
|
||||
set color_bg = "#124D51";
|
||||
|
||||
#NEWLAYER: opal/forest
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo redist_uniq = "opal/forest";
|
||||
layerinfo "source_viewable" = 1;
|
||||
layerinfo "name" = "Natural Forest";
|
||||
set color_link = "#4C6502";
|
||||
set color_med = "#90a47a";
|
||||
set color_bg_font = "#ffeabf";
|
||||
set color_fg = "#cacba9";
|
||||
set color_med_font = "#eaf2cc";
|
||||
set color_bg = "#514541";
|
||||
set color_visited = "#846D06";
|
||||
|
||||
#NEWLAYER: opal/greybeard
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo redist_uniq = "opal/greybeard";
|
||||
layerinfo "source_viewable" = 1;
|
||||
layerinfo "name" = "Greybeard";
|
||||
set color_link = "#05445C";
|
||||
set color_med = "#6a6a6a";
|
||||
set color_fg_font = "#dddddd";
|
||||
set color_bg = "#424242";
|
||||
set color_visited = "#390856";
|
||||
set color_fg = "#7c7c7c";
|
||||
set color_med_font = "#E2E2E2";
|
||||
|
||||
#NEWLAYER: opal/desert
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo redist_uniq = "opal/desert";
|
||||
layerinfo "source_viewable" = 1;
|
||||
layerinfo "name" = "Spring Desert";
|
||||
set color_link = "#4c6502";
|
||||
set color_med = "#bc7f48";
|
||||
set color_fg_font = "#794234";
|
||||
set color_fg = "#cea36f";
|
||||
set color_med_font = "#F2E6C8";
|
||||
set color_bg = "#795021";
|
||||
|
||||
|
||||
#NEWLAYER: opal/carnvial
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo redist_uniq = "opal/carnvial";
|
||||
layerinfo "source_viewable" = 1;
|
||||
layerinfo "name" = "Carnvial";
|
||||
set color_med = "#9681b7";
|
||||
set color_fg = "#E9973F";
|
||||
set color_bg = "#2d4b9b";
|
||||
|
||||
#NEWLAYER: opal/snowcone
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo redist_uniq = "opal/snowcone";
|
||||
layerinfo "source_viewable" = 1;
|
||||
layerinfo "name" = "Snow Cone";
|
||||
set color_med = "#7c9bc1";
|
||||
set color_fg_font = "#4F6C9C";
|
||||
set color_fg = "#bfe2f8";
|
||||
set color_bg = "#8d54a0";
|
||||
|
||||
#NEWLAYER: opal/adobeclay
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo redist_uniq = "opal/adobeclay";
|
||||
layerinfo "source_viewable" = 1;
|
||||
layerinfo "name" = "Adobe Clay";
|
||||
set color_link = "#FF9422";
|
||||
set color_med = "#a4562b";
|
||||
set color_fg_font = "#33100b";
|
||||
set color_fg = "#c1643b";
|
||||
set color_med_font = "#fce7d5";
|
||||
set color_bg = "#7b4832";
|
||||
set color_visited = "#FFC437";
|
||||
|
||||
#NEWLAYER: opal/gentle
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo redist_uniq = "opal/gentle";
|
||||
layerinfo "source_viewable" = 1;
|
||||
layerinfo "name" = "Gentle";
|
||||
set color_bg_font = "#616568";
|
||||
set color_fg = "#ebdbd0";
|
||||
set color_visited = "#A97F63";
|
||||
set color_link = "#bd9a82";
|
||||
set color_med = "#b3c5c5";
|
||||
set color_bg = "#a2b2b1";
|
||||
set color_med_font = "#878894";
|
||||
set color_fg_font = "#757575";
|
||||
2285
local/bin/upgrading/s2layers/smoothsailing/layout.s2
Executable file
2285
local/bin/upgrading/s2layers/smoothsailing/layout.s2
Executable file
File diff suppressed because it is too large
Load Diff
612
local/bin/upgrading/s2layers/smoothsailing/themes.s2
Executable file
612
local/bin/upgrading/s2layers/smoothsailing/themes.s2
Executable file
@@ -0,0 +1,612 @@
|
||||
#NEWLAYER: smoothsailing/starry
|
||||
layerinfo "redist_uniq" = "smoothsailing/starry";
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Starry Night";
|
||||
layerinfo author_name = "Michael Raffoul";
|
||||
layerinfo author_email = "masterslacker@livejournal.com";
|
||||
|
||||
set color_header_title_background = "#000000";
|
||||
set color_header_title_text = "#FFFFB9";
|
||||
set color_header_subtitle_text = "#dddddd";
|
||||
set color_header_menubar_background = "#000044";
|
||||
set color_header_menubar_text = "#FFFFB9";
|
||||
set color_header_menubar_background_hover = "#000000";
|
||||
set color_header_menubar_text_hover = "#dddddd";
|
||||
set color_header_borders = "#89a2be";
|
||||
|
||||
set color_body_links = "#ffffb9";
|
||||
set color_body_links_visited = "#dddddd";
|
||||
set color_body_titlebar_background = "#aaaaaa";
|
||||
set color_body_titlebar_text = "#000044";
|
||||
set color_body_footer_background = "#000000";
|
||||
set color_body_footer_text = "#ffffb9";
|
||||
set color_body_background = "#000044";
|
||||
set color_body_text = "#FFFFB9";
|
||||
|
||||
set color_body_entrytitle_background = "#000000";
|
||||
set color_body_entrytitle_background_alternate = "#aaaaaa";
|
||||
set color_body_entrytitle_border = "#89A2BE";
|
||||
set color_body_entrytitle_text = "#89a2be";
|
||||
set color_body_entrytitle_links = "#89a2be";
|
||||
set color_body_entry_background = "#000044";
|
||||
set color_body_entry_userinfo_background = "#000044";
|
||||
set color_body_entry_text = "#FFFFB9";
|
||||
|
||||
set color_month_borders = "#89A2BE";
|
||||
set color_month_title_background = "#aaaaaa";
|
||||
set color_month_title_text = "#000000";
|
||||
set color_month_dates = "#aaaaaa";
|
||||
set color_month_postcount = "#FFFFB9";
|
||||
|
||||
|
||||
|
||||
#NEWLAYER: smoothsailing/pink
|
||||
layerinfo "redist_uniq" = "smoothsailing/pink";
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Pretty in Pink";
|
||||
layerinfo author_name = "Michael Raffoul";
|
||||
layerinfo author_email = "masterslacker@livejournal.com";
|
||||
|
||||
set color_header_title_background = "#CC4E5C";
|
||||
set color_header_title_text = "#FFEEFF";
|
||||
set color_header_subtitle_text = "#FFB6C1";
|
||||
set color_header_menubar_background = "#e6828f";
|
||||
set color_header_menubar_text = "#FFEEFF";
|
||||
set color_header_menubar_background_hover = "#CC4E5C";
|
||||
set color_header_menubar_text_hover = "#FFEEFF";
|
||||
set color_header_borders = "#FFEEFF";
|
||||
|
||||
set color_body_links = "#CC4E5C";
|
||||
set color_body_links_visited = "#CC4E5C";
|
||||
set color_body_titlebar_background = "#FFB6C1";
|
||||
set color_body_titlebar_text = "#CC4E5C";
|
||||
set color_body_footer_background = "#FFB6C1";
|
||||
set color_body_footer_text = "#CC4E5C";
|
||||
set color_body_background = "#FFEEFF";
|
||||
set color_body_text = "#CC4E5C";
|
||||
set color_body_entrytitle_background = "#FFB6C1";
|
||||
set color_body_entrytitle_background_alternate = "#e6828f";
|
||||
set color_body_entrytitle_border = "#CC4E5C";
|
||||
set color_body_entrytitle_text = "#CC4E5C";
|
||||
set color_body_entrytitle_links = "#CC4E5C";
|
||||
set color_body_entry_text = "#CC4E5C";
|
||||
set color_body_entry_background = "#FFEEFF";
|
||||
set color_body_entry_userinfo_background = "#FFEEFF";
|
||||
|
||||
set color_month_borders = "#CC4E5C";
|
||||
set color_month_title_background = "#FFB6C1";
|
||||
set color_month_title_text = "#CC4E5C";
|
||||
set color_month_dates = "#CC4E5C";
|
||||
set color_month_postcount = "#e6828f";
|
||||
|
||||
|
||||
|
||||
|
||||
#NEWLAYER: smoothsailing/easter
|
||||
layerinfo "redist_uniq" = "smoothsailing/easter";
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Easter Basket";
|
||||
layerinfo author_name = "Michael Raffoul";
|
||||
layerinfo author_email = "masterslacker@livejournal.com";
|
||||
|
||||
set color_header_title_background = "#00B789";
|
||||
set color_header_title_text = "#FFFF82";
|
||||
set color_header_subtitle_text = "#005100";
|
||||
set color_header_menubar_background = "#FFFF82";
|
||||
set color_header_menubar_text = "#005100";
|
||||
set color_header_menubar_background_hover = "#C7A0CB";
|
||||
set color_header_menubar_text_hover = "#005100";
|
||||
set color_header_borders = "#009300";
|
||||
|
||||
set color_body_links = "#005100";
|
||||
set color_body_links_visited = "#005100";
|
||||
set color_body_titlebar_background = "#C7A0CB";
|
||||
set color_body_titlebar_text = "#005100";
|
||||
set color_body_footer_background = "#C7A0CB";
|
||||
set color_body_footer_text = "#005100";
|
||||
set color_body_background = "#DDDFF0";
|
||||
set color_body_text = "#005100";
|
||||
set color_body_entrytitle_background = "#FFFF82";
|
||||
set color_body_entrytitle_background_alternate = "#C7A0CB";
|
||||
set color_body_entrytitle_border = "#009300";
|
||||
set color_body_entrytitle_text = "#005100";
|
||||
set color_body_entrytitle_links = "#005100";
|
||||
set color_body_entry_text = "#005100";
|
||||
set color_body_entry_background = "#DDDFF0";
|
||||
set color_body_entry_userinfo_background = "#DDDFF0";
|
||||
|
||||
set color_month_borders = "#00B789";
|
||||
set color_month_title_background = "#FFFF82";
|
||||
set color_month_title_text = "#005100";
|
||||
set color_month_dates = "#C7A0CB";
|
||||
set color_month_postcount = "#005100";
|
||||
|
||||
|
||||
|
||||
|
||||
#NEWLAYER: smoothsailing/mocha
|
||||
layerinfo "redist_uniq" = "smoothsailing/mocha";
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Mochachino";
|
||||
layerinfo author_name = "Michael Raffoul";
|
||||
layerinfo author_email = "masterslacker@livejournal.com";
|
||||
|
||||
set color_header_title_background = "#666666";
|
||||
set color_header_title_text = "#e6e6e6";
|
||||
set color_header_subtitle_text = "#B1A68B";
|
||||
set color_header_menubar_background = "#635a48";
|
||||
set color_header_menubar_text = "#b1a68b";
|
||||
set color_header_menubar_background_hover = "#b1a68b";
|
||||
set color_header_menubar_text_hover = "#666666";
|
||||
set color_header_borders = "#e6e6e6";
|
||||
|
||||
set color_body_links = "#464640";
|
||||
set color_body_links_visited = "#000000";
|
||||
set color_body_titlebar_background = "#B1A68B";
|
||||
set color_body_titlebar_text = "#e6e6e6";
|
||||
set color_body_footer_background = "#b1a68b";
|
||||
set color_body_footer_text = "#e6e6e6";
|
||||
set color_body_background = "#e6e6e6";
|
||||
set color_body_entrytitle_background = "#b1a68b";
|
||||
set color_body_entrytitle_background_alternate = "#796D51";
|
||||
set color_body_entrytitle_border = "#666666";
|
||||
set color_body_entrytitle_text = "#e6e6e6";
|
||||
set color_body_entrytitle_links = "#e6e6e6";
|
||||
set color_body_entry_text = "#464640";
|
||||
set color_body_entry_background = "#e6e6e6";
|
||||
set color_body_entry_userinfo_background = "#e6e6e6";
|
||||
|
||||
set color_month_borders = "#666666";
|
||||
set color_month_title_background = "#e6e6e6";
|
||||
set color_month_title_text = "#464640";
|
||||
set color_month_dates = "#464640";
|
||||
set color_month_postcount = "#796D51";
|
||||
|
||||
#NEWLAYER: smoothsailing/yellow
|
||||
layerinfo "redist_uniq" = "smoothsailing/yellow";
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Insane Yellow";
|
||||
layerinfo author_name = "Michael Raffoul";
|
||||
layerinfo author_email = "masterslacker@livejournal.com";
|
||||
|
||||
set color_header_title_background = "#202020";
|
||||
set color_header_title_text = "#FFFF04";
|
||||
set color_header_subtitle_text = "#dddddd";
|
||||
set color_header_menubar_background = "#000000";
|
||||
set color_header_menubar_text = "#FFFFB9";
|
||||
set color_header_menubar_background_hover = "#202020";
|
||||
set color_header_menubar_text_hover = "#FFFFB9";
|
||||
set color_header_borders = "#FFFF04";
|
||||
|
||||
set color_body_links = "#aaaaaa";
|
||||
set color_body_links_visited = "#dddddd";
|
||||
set color_body_titlebar_background = "#aaaaaa";
|
||||
set color_body_titlebar_text = "#000000";
|
||||
set color_body_footer_background = "#202020";
|
||||
set color_body_footer_text = "#ffffb9";
|
||||
set color_body_background = "#000000";
|
||||
set color_body_text = "#FFFFB9";
|
||||
|
||||
set color_body_entrytitle_background = "#202020";
|
||||
set color_body_entrytitle_background_alternate = "#aaaaaa";
|
||||
set color_body_entrytitle_border = "#FFFF04";
|
||||
set color_body_entrytitle_text = "#FFFF04";
|
||||
set color_body_entrytitle_links = "#FFFF04";
|
||||
set color_body_entry_background = "#000000";
|
||||
set color_body_entry_userinfo_background = "#000000";
|
||||
set color_body_entry_text = "#aaaaaa";
|
||||
|
||||
set color_month_borders = "#FFFFB9";
|
||||
set color_month_title_background = "#aaaaaa";
|
||||
set color_month_title_text = "#000000";
|
||||
set color_month_dates = "#aaaaaa";
|
||||
set color_month_postcount = "#FFFFB9";
|
||||
|
||||
|
||||
#NEWLAYER: smoothsailing/forest
|
||||
layerinfo "redist_uniq" = "smoothsailing/forest";
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "In the Forest";
|
||||
layerinfo author_name = "Michael Raffoul";
|
||||
layerinfo author_email = "masterslacker@livejournal.com";
|
||||
|
||||
set color_header_title_background = "#635a48";
|
||||
set color_header_title_text = "#e7dfcf";
|
||||
set color_header_subtitle_text = "#607c6d";
|
||||
set color_header_menubar_background = "#899ba3";
|
||||
set color_header_menubar_text = "#464640";
|
||||
set color_header_menubar_background_hover = "#e7dfcf";
|
||||
set color_header_menubar_text_hover = "#464640";
|
||||
set color_header_borders = "#464640";
|
||||
|
||||
set color_body_links = "#e7dfcf";
|
||||
set color_body_links_visited = "#e7dfcf";
|
||||
set color_body_titlebar_background = "#e7dfcf";
|
||||
set color_body_titlebar_text = "#464640";
|
||||
set color_body_footer_background = "#e7dfcf";
|
||||
set color_body_footer_text = "#464640";
|
||||
set color_body_background = "#607c6d";
|
||||
set color_body_text = "#e7dfcf";
|
||||
|
||||
set color_body_entrytitle_background = "#635a48";
|
||||
set color_body_entrytitle_background_alternate = "#464640";
|
||||
set color_body_entrytitle_border = "#e7dfcf";
|
||||
set color_body_entrytitle_text = "#e7dfcf";
|
||||
set color_body_entrytitle_links = "#e7dfcf";
|
||||
set color_body_entry_userinfo_background = "#626b5b";
|
||||
set color_body_entry_background = "#626b5b";
|
||||
set color_body_entry_text = "#e7dfcf";
|
||||
|
||||
set color_month_borders = "#464640";
|
||||
set color_month_title_background = "#e7dfcf";
|
||||
set color_month_title_text = "#464640";
|
||||
set color_month_dates = "#899ba3";
|
||||
set color_month_postcount = "#e7dfcf";
|
||||
|
||||
|
||||
|
||||
#NEWLAYER: smoothsailing/red
|
||||
layerinfo "redist_uniq" = "smoothsailing/red";
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Seeing Red";
|
||||
layerinfo author_name = "Michael Raffoul";
|
||||
layerinfo author_email = "masterslacker@livejournal.com";
|
||||
|
||||
set color_header_title_background = "#bb0000";
|
||||
set color_header_title_text = "#ffffff";
|
||||
set color_header_subtitle_text = "#ffffff";
|
||||
set color_header_menubar_background = "#880000";
|
||||
set color_header_menubar_text = "#ffffff";
|
||||
set color_header_menubar_background_hover = "#ffffff";
|
||||
set color_header_menubar_text_hover = "#bb0000";
|
||||
set color_header_borders = "#ffffff";
|
||||
set color_body_links = "#880000";
|
||||
set color_body_links_visited = "#000000";
|
||||
set color_body_titlebar_background = "#bb0000";
|
||||
set color_body_titlebar_text = "#ffffff";
|
||||
set color_body_footer_background = "#bb0000";
|
||||
set color_body_footer_text = "#ffffff";
|
||||
set color_body_background = "#f6f6f6";
|
||||
set color_body_text = "#880000";
|
||||
set color_body_entrytitle_background = "#bb0000";
|
||||
set color_body_entrytitle_background_alternate = "#880000";
|
||||
set color_body_entrytitle_border = "#000000";
|
||||
set color_body_entrytitle_text = "#ffffff";
|
||||
set color_body_entrytitle_links = "#ffffff";
|
||||
set color_body_entry_background = "#f6f6f6";
|
||||
set color_body_entry_text = "#880000";
|
||||
set color_month_borders = "#880000";
|
||||
set color_month_title_background = "#bb0000";
|
||||
set color_month_title_text = "#ffffff";
|
||||
set color_month_dates = "#880000";
|
||||
set color_month_postcount = "#bb0000";
|
||||
|
||||
|
||||
|
||||
#NEWLAYER: smoothsailing/army
|
||||
layerinfo "redist_uniq" = "smoothsailing/army";
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Army Attire";
|
||||
layerinfo author_name = "Michael Raffoul";
|
||||
layerinfo author_email = "masterslacker@livejournal.com";
|
||||
|
||||
set color_header_title_background = "#444444";
|
||||
set color_header_title_text = "#cccc99";
|
||||
set color_header_subtitle_text = "#e6e6e6";
|
||||
set color_header_menubar_background = "#665d34";
|
||||
set color_header_menubar_text = "#cccc99";
|
||||
set color_header_menubar_background_hover = "#cccc99";
|
||||
set color_header_menubar_text_hover = "#444444";
|
||||
set color_header_borders = "#e6e6e6";
|
||||
|
||||
set color_body_links = "#444444";
|
||||
set color_body_links_visited = "#000000";
|
||||
set color_body_titlebar_background = "#cccc99";
|
||||
set color_body_titlebar_text = "#665d34";
|
||||
set color_body_footer_background = "#cccc99";
|
||||
set color_body_footer_text = "#665d34";
|
||||
set color_body_background = "#e6e6e6";
|
||||
|
||||
set color_body_entrytitle_background = "#cccc99";
|
||||
set color_body_entrytitle_background_alternate = "#665d34";
|
||||
set color_body_entrytitle_border = "#444444";
|
||||
set color_body_entrytitle_text = "#665d34";
|
||||
set color_body_entrytitle_links = "#665d34";
|
||||
set color_body_entry_text = "#444444";
|
||||
set color_body_entry_background = "#e6e6e6";
|
||||
set color_body_entry_userinfo_background = "#e6e6e6";
|
||||
|
||||
set color_month_borders = "#444444";
|
||||
set color_month_title_background = "#e6e6e6";
|
||||
set color_month_title_text = "#444444";
|
||||
set color_month_dates = "#444444";
|
||||
set color_month_postcount = "#665d34";
|
||||
|
||||
|
||||
|
||||
#NEWLAYER: smoothsailing/midnight
|
||||
layerinfo "redist_uniq" = "smoothsailing/midnight";
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Midnight";
|
||||
layerinfo author_name = "Michael Raffoul";
|
||||
layerinfo author_email = "masterslacker@livejournal.com";
|
||||
|
||||
set color_header_title_background = "#000000";
|
||||
set color_header_title_text = "#BEAA61";
|
||||
set color_header_subtitle_text = "#76456B";
|
||||
set color_header_menubar_background = "#76456B";
|
||||
set color_header_menubar_text = "#dddddd";
|
||||
set color_header_menubar_background_hover = "#000000";
|
||||
set color_header_menubar_text_hover = "#dddddd";
|
||||
set color_header_borders = "#dddddd";
|
||||
|
||||
set color_body_links = "#aaaaaa";
|
||||
set color_body_links_visited = "#dddddd";
|
||||
set color_body_titlebar_background = "#BEAA61";
|
||||
set color_body_titlebar_text = "#000000";
|
||||
set color_body_footer_background = "#76456B";
|
||||
set color_body_footer_text = "#dddddd";
|
||||
set color_body_background = "#000000";
|
||||
set color_body_text = "#aaaaaa";
|
||||
|
||||
set color_body_entrytitle_background = "#76456B";
|
||||
set color_body_entrytitle_background_alternate = "#888888";
|
||||
set color_body_entrytitle_border = "#cccccc";
|
||||
set color_body_entrytitle_text = "#dddddd";
|
||||
set color_body_entrytitle_links = "#dddddd";
|
||||
set color_body_entry_userinfo_background = "#000000";
|
||||
set color_body_entry_background = "#000000";
|
||||
set color_body_entry_text = "#aaaaaa";
|
||||
|
||||
set color_month_borders = "#dddddd";
|
||||
set color_month_title_background = "#aaaaaa";
|
||||
set color_month_title_text = "#000000";
|
||||
set color_month_dates = "#aaaaaa";
|
||||
set color_month_postcount = "#BEAA61";
|
||||
|
||||
|
||||
|
||||
#NEWLAYER: smoothsailing/violet
|
||||
layerinfo "redist_uniq" = "smoothsailing/violet";
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Very Violet";
|
||||
layerinfo author_name = "Michael Raffoul";
|
||||
layerinfo author_email = "masterslacker@livejournal.com";
|
||||
|
||||
set color_header_title_background = "#7c52ab";
|
||||
set color_header_subtitle_text = "#dbcfe9";
|
||||
set color_header_menubar_background = "#bfaad7";
|
||||
set color_header_menubar_background_hover = "#7c52ab";
|
||||
set color_body_links_visited = "#563976";
|
||||
set color_body_titlebar_background = "#dbcfe9";
|
||||
set color_body_footer_background = "#bfaad7";
|
||||
set color_body_entrytitle_background = "#dbcfe9";
|
||||
|
||||
#NEWLAYER: smoothsailing/purple
|
||||
layerinfo "redist_uniq" = "smoothsailing/purple";
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Bruised Purple";
|
||||
layerinfo author_name = "Michael Raffoul";
|
||||
layerinfo author_email = "masterslacker@livejournal.com";
|
||||
|
||||
set color_body_entrytitle_border = "#d4ddee";
|
||||
set color_body_footer_text = "#454b74";
|
||||
set color_month_title_text = "#8792bd";
|
||||
set color_header_borders = "#8792bd";
|
||||
set color_body_links_visited = "#dddddd";
|
||||
set color_header_menubar_text_hover = "#ffffff";
|
||||
set color_body_titlebar_text = "#454b74";
|
||||
set color_body_entrytitle_background_alternate = "#d4ddee";
|
||||
set color_body_entrytitle_links = "#6b7da6";
|
||||
set color_body_entry_background = "#454b74";
|
||||
set color_header_title_background = "#454b74";
|
||||
set color_body_entry_userinfo_background = "#454b74";
|
||||
set color_month_dates = "#8792bd";
|
||||
set color_body_links = "#ececec";
|
||||
set color_body_background = "#6b7da6";
|
||||
set color_month_postcount = "#8792bd";
|
||||
set color_body_entry_text = "#8792bd";
|
||||
set color_body_text = "#ffffff";
|
||||
set color_body_entrytitle_background = "#d4ddee";
|
||||
set color_header_menubar_text = "#ffffff";
|
||||
set color_body_entrytitle_text = "#454b74";
|
||||
|
||||
#NEWLAYER: smoothsailing/parrot
|
||||
layerinfo "redist_uniq" = "smoothsailing/parrot";
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Parrot Feathers";
|
||||
layerinfo author_name = "Michael Raffoul";
|
||||
layerinfo author_email = "masterslacker@livejournal.com";
|
||||
|
||||
set color_header_title_background = "#009900";
|
||||
set color_header_title_text = "#f8f8f8";
|
||||
set color_header_subtitle_text = "#66ff66";
|
||||
set color_header_menubar_background = "#33cc33";
|
||||
set color_header_menubar_text = "#ffffff";
|
||||
set color_header_menubar_background_hover = "#66ff66";
|
||||
set color_header_menubar_text_hover = "#ffffff";
|
||||
set color_header_borders = "#ffffff";
|
||||
|
||||
set color_body_links = "#006600";
|
||||
set color_body_links_visited = "#000000";
|
||||
set color_body_titlebar_background = "#66cc66";
|
||||
set color_body_titlebar_text = "#ffffff";
|
||||
set color_body_footer_background = "#66cc66";
|
||||
set color_body_footer_text = "#ffffff";
|
||||
set color_body_background = "#f8f8f8";
|
||||
set color_body_text = "#000000";
|
||||
|
||||
set color_body_entrytitle_background = "#66cc66";
|
||||
set color_body_entrytitle_background_alternate = "#66ff66";
|
||||
set color_body_entrytitle_border = "#006600";
|
||||
set color_body_entrytitle_text = "#000000";
|
||||
set color_body_entrytitle_links = "#000000";
|
||||
set color_body_entry_background = "#f8f8f8";
|
||||
set color_body_entry_userinfo_background = "#f8f8f8";
|
||||
set color_body_entry_text = "#000000";
|
||||
|
||||
set color_month_borders = "#006600";
|
||||
set color_month_title_background = "#f8f8f8";
|
||||
set color_month_title_text = "#000000";
|
||||
set color_month_dates = "#000000";
|
||||
set color_month_postcount = "#006600";
|
||||
|
||||
#NEWLAYER: smoothsailing/toxic
|
||||
layerinfo "redist_uniq" = "smoothsailing/toxic";
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Toxic Teal";
|
||||
layerinfo author_name = "Michael Raffoul";
|
||||
layerinfo author_email = "masterslacker@livejournal.com";
|
||||
|
||||
set color_header_title_background = "#7cb3b0";
|
||||
set color_header_title_text = "#496a68";
|
||||
set color_header_subtitle_text = "#c9eae8";
|
||||
set color_header_menubar_background = "#aededb";
|
||||
set color_header_menubar_text = "#496a68";
|
||||
set color_header_menubar_background_hover = "#c9eae8";
|
||||
set color_header_menubar_text_hover = "#496a68";
|
||||
set color_header_borders = "#496a68";
|
||||
|
||||
set color_body_links = "#496a68";
|
||||
set color_body_links_visited = "#000000";
|
||||
set color_body_titlebar_background = "#c9eae8";
|
||||
set color_body_titlebar_text = "#496a68";
|
||||
set color_body_footer_background = "#c9eae8";
|
||||
set color_body_footer_text = "#496a68";
|
||||
set color_body_background = "#496a68";
|
||||
set color_body_text = "#aededb";
|
||||
|
||||
set color_body_entrytitle_background = "#7cb3b0";
|
||||
set color_body_entrytitle_background_alternate = "#6e9e9b";
|
||||
set color_body_entrytitle_border = "#c9eae8";
|
||||
set color_body_entrytitle_text = "#000000";
|
||||
set color_body_entrytitle_links = "#000000";
|
||||
set color_body_entry_background = "#aededb";
|
||||
set color_body_entry_userinfo_background = "#aededb";
|
||||
set color_body_entry_text = "#000000";
|
||||
|
||||
set color_month_borders = "#496a68";
|
||||
set color_month_title_background = "#c9eae8";
|
||||
set color_month_title_text = "#000000";
|
||||
set color_month_dates = "#000000";
|
||||
set color_month_postcount = "#496a68";
|
||||
|
||||
#NEWLAYER: smoothsailing/banana
|
||||
layerinfo "redist_uniq" = "smoothsailing/banana";
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Banana Tree";
|
||||
layerinfo author_name = "Michael Raffoul";
|
||||
layerinfo author_email = "masterslacker@livejournal.com";
|
||||
|
||||
set color_header_title_background = "#3D5D2E";
|
||||
set color_header_title_text = "#F6F6BB";
|
||||
set color_header_subtitle_text = "#E1D751";
|
||||
set color_header_menubar_background = "#E1D751";
|
||||
set color_header_menubar_text = "#3D5D2E";
|
||||
set color_header_menubar_background_hover = "#9A722E";
|
||||
set color_header_menubar_text_hover = "#F6F6BB";
|
||||
set color_header_borders = "#F6F6BB";
|
||||
|
||||
set color_body_links = "#3D5D2E";
|
||||
set color_body_links_visited = "#000000";
|
||||
set color_body_titlebar_background = "#9A722E";
|
||||
set color_body_titlebar_text = "#F6F6BB";
|
||||
set color_body_footer_background = "#3D5D2E";
|
||||
set color_body_footer_text = "#F6F6BB";
|
||||
set color_body_background = "#F6F6BB";
|
||||
set color_body_text = "#3D5D2E";
|
||||
|
||||
set color_body_entrytitle_background = "#3D5D2E";
|
||||
set color_body_entrytitle_background_alternate = "#9A722E";
|
||||
set color_body_entrytitle_border = "#9A722E";
|
||||
set color_body_entrytitle_text = "#E1D751";
|
||||
set color_body_entrytitle_links = "#E1D751";
|
||||
set color_body_entry_background = "#F6F6BB";
|
||||
set color_body_entry_userinfo_background = "#F6F6BB";
|
||||
set color_body_entry_text = "#000000";
|
||||
|
||||
set color_month_borders = "#9A722E";
|
||||
set color_month_title_background = "#F6F6BB";
|
||||
set color_month_title_text = "#3D5D2E";
|
||||
set color_month_dates = "#000000";
|
||||
set color_month_postcount = "#3D5D2E";
|
||||
|
||||
#NEWLAYER: smoothsailing/fire
|
||||
layerinfo "redist_uniq" = "smoothsailing/fire";
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Under Fire";
|
||||
layerinfo author_name = "Michael Raffoul";
|
||||
layerinfo author_email = "masterslacker@livejournal.com";
|
||||
|
||||
set color_header_title_background = "#95261F";
|
||||
set color_header_title_text = "#F5EBC2";
|
||||
set color_header_subtitle_text = "#CA6036";
|
||||
set color_header_menubar_background = "#CA6036";
|
||||
set color_header_menubar_text = "#F5EBC2";
|
||||
set color_header_menubar_background_hover = "#DEB450";
|
||||
set color_header_menubar_text_hover = "#95261F";
|
||||
set color_header_borders = "#F5EBC2";
|
||||
|
||||
set color_body_links = "#95261F";
|
||||
set color_body_links_visited = "#000000";
|
||||
set color_body_titlebar_background = "#DEB450";
|
||||
set color_body_titlebar_text = "#95261F";
|
||||
set color_body_footer_background = "#95261F";
|
||||
set color_body_footer_text = "#F5EBC2";
|
||||
set color_body_background = "#F5EBC2";
|
||||
set color_body_text = "#000000";
|
||||
|
||||
set color_body_entrytitle_background = "#95261F";
|
||||
set color_body_entrytitle_background_alternate = "#CA6036";
|
||||
set color_body_entrytitle_border = "#DEB450";
|
||||
set color_body_entrytitle_text = "#F5EBC2";
|
||||
set color_body_entrytitle_links = "#F5EBC2";
|
||||
set color_body_entry_background = "#F5EBC2";
|
||||
set color_body_entry_userinfo_background = "#F5EBC2";
|
||||
set color_body_entry_text = "#000000";
|
||||
|
||||
set color_month_borders = "#95261F";
|
||||
set color_month_title_background = "#F5EBC2";
|
||||
set color_month_title_text = "#95261F";
|
||||
set color_month_dates = "#95261F";
|
||||
set color_month_postcount = "#CA6036";
|
||||
|
||||
#NEWLAYER: smoothsailing/chocolate
|
||||
layerinfo "redist_uniq" = "smoothsailing/chocolate";
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Chocolate Caramel Creme";
|
||||
layerinfo author_name = "Michael Raffoul";
|
||||
layerinfo author_email = "masterslacker@livejournal.com";
|
||||
|
||||
set color_header_title_background = "#6D4506";
|
||||
set color_header_title_text = "#E1D6C0";
|
||||
set color_header_subtitle_text = "#CF9B48";
|
||||
set color_header_menubar_background = "#A2701F";
|
||||
set color_header_menubar_text = "#E1D6C0";
|
||||
set color_header_menubar_background_hover = "#CF9B48";
|
||||
set color_header_menubar_text_hover = "#E1D6C0";
|
||||
set color_header_borders = "#E1D6C0";
|
||||
|
||||
set color_body_links = "#6D4506";
|
||||
set color_body_links_visited = "#000000";
|
||||
set color_body_titlebar_background = "#CF9B48";
|
||||
set color_body_titlebar_text = "#E1D6C0";
|
||||
set color_body_footer_background = "#6D4506";
|
||||
set color_body_footer_text = "#E1D6C0";
|
||||
set color_body_background = "#E1D6C0";
|
||||
set color_body_text = "#000000";
|
||||
|
||||
set color_body_entrytitle_background = "#A2701F";
|
||||
set color_body_entrytitle_background_alternate = "#CF9B48";
|
||||
set color_body_entrytitle_border = "#6D4506";
|
||||
set color_body_entrytitle_text = "#E1D6C0";
|
||||
set color_body_entrytitle_links = "#E1D6C0";
|
||||
set color_body_entry_background = "#E1D6C0";
|
||||
set color_body_entry_userinfo_background = "#E1D6C0";
|
||||
set color_body_entry_text = "#000000";
|
||||
|
||||
set color_month_borders = "#A2701F";
|
||||
set color_month_title_background = "#E1D6C0";
|
||||
set color_month_title_text = "#6D4506";
|
||||
set color_month_dates = "#6D4506";
|
||||
set color_month_postcount = "#A2701F";
|
||||
1342
local/bin/upgrading/s2layers/tranquility2/layout.s2
Executable file
1342
local/bin/upgrading/s2layers/tranquility2/layout.s2
Executable file
File diff suppressed because it is too large
Load Diff
1341
local/bin/upgrading/s2layers/tranquilityii/layout.s2
Executable file
1341
local/bin/upgrading/s2layers/tranquilityii/layout.s2
Executable file
File diff suppressed because it is too large
Load Diff
707
local/bin/upgrading/s2layers/tranquilityii/themes.s2
Executable file
707
local/bin/upgrading/s2layers/tranquilityii/themes.s2
Executable file
@@ -0,0 +1,707 @@
|
||||
#NEWLAYER: tranquilityii/plain
|
||||
layerinfo "redist_uniq" = "tranquilityii/plain";
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Tranquility II - Plain Theme";
|
||||
layerinfo "author_name" = "Matthew Vince";
|
||||
|
||||
set c_main_border = "#fff";
|
||||
set c_menu_border = "#fff";
|
||||
set c_header_background = "#fff";
|
||||
set c_header_border = "#fff";
|
||||
set c_page_title = "#000";
|
||||
set c_page_background = "#fff";
|
||||
set c_page_text = "#333";
|
||||
set c_page_link = "#036";
|
||||
set c_page_link_visited = "#036";
|
||||
set c_page_link_hover = "#069";
|
||||
set c_page_link_active = "#069";
|
||||
set c_menu_background = "#fff";
|
||||
set c_menu_link = "#000";
|
||||
set c_menu_link_visited = "#000";
|
||||
set c_menu_link_hover = "#f00";
|
||||
set c_menu_link_active = "#f00";
|
||||
set c_menu_text_color = "#000";
|
||||
set c_menu_header_color = "#000";
|
||||
set c_menu_current = "#000";
|
||||
set c_entry_background = "#fff";
|
||||
set c_entry_link = "#000";
|
||||
set c_entry_link_visited = "#000";
|
||||
set c_entry_link_hover = "#000";
|
||||
set c_entry_link_active = "#000";
|
||||
set c_entry_text_color = "#000";
|
||||
set c_entry_title_color = "#000";
|
||||
set c_entry_border = "#999";
|
||||
set c_meta_background = "#fff";
|
||||
set c_meta_link = "#000";
|
||||
set c_meta_link_visited = "#000";
|
||||
set c_meta_link_hover = "#000";
|
||||
set c_meta_link_active = "#000";
|
||||
set c_meta_text_color = "#000";
|
||||
set c_footer_background = "#fff";
|
||||
set c_footer_link = "#000";
|
||||
set c_footer_link_visited = "#000";
|
||||
set c_footer_link_hover = "#000";
|
||||
set c_footer_link_active = "#000";
|
||||
set c_footer_text_color = "#000";
|
||||
set c_comment_one_link = "#000";
|
||||
set c_comment_one_link_visited = "#000";
|
||||
set c_comment_one_link_hover = "#000";
|
||||
set c_comment_one_link_active = "#000";
|
||||
set c_comment_one_text_color = "#000";
|
||||
set c_comment_one_title_color = "#000";
|
||||
set c_comment_one_background = "#fff";
|
||||
set c_comment_one_border = "#999";
|
||||
set c_comment_two_link = "#000";
|
||||
set c_comment_two_link_visited = "#000";
|
||||
set c_comment_two_link_hover = "#000";
|
||||
set c_comment_two_link_active = "#000";
|
||||
set c_comment_two_text_color = "#000";
|
||||
set c_comment_two_title_color = "#000";
|
||||
set c_comment_two_background = "#f2f2f2";
|
||||
set c_comment_two_border = "#999";
|
||||
set c_comment_screened_link = "#000";
|
||||
set c_comment_screened_link_visited = "#000";
|
||||
set c_comment_screened_link_hover = "#000";
|
||||
set c_comment_screened_link_active = "#000";
|
||||
set c_comment_screened_text_color = "#000";
|
||||
set c_comment_screened_title_color = "#000";
|
||||
set c_comment_screened_background = "#ccc";
|
||||
set c_comment_screened_border = "#999";
|
||||
|
||||
#NEWLAYER: tranquilityii/earth
|
||||
layerinfo "redist_uniq" = "tranquilityii/earth";
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Tranquility II - Earth Theme";
|
||||
layerinfo "author_name" = "Matthew Vince";
|
||||
|
||||
set c_main_border = "#424B15";
|
||||
set c_header_background = "#667320";
|
||||
set c_header_border = "#667320";
|
||||
set c_page_title = "#fff";
|
||||
set c_page_background = "#667320";
|
||||
set c_page_text = "#333";
|
||||
set c_page_link = "#000";
|
||||
set c_page_link_visited = "#666";
|
||||
set c_page_link_hover = "#999";
|
||||
set c_page_link_active = "#999";
|
||||
set c_menu_border = "#424B15";
|
||||
set c_menu_background = "#88992B";
|
||||
set c_menu_link = "#fff";
|
||||
set c_menu_link_visited = "#424B15";
|
||||
set c_menu_link_hover = "#424B15";
|
||||
set c_menu_link_active = "#f00";
|
||||
set c_menu_text_color = "#fff";
|
||||
set c_menu_header_color = "#fff";
|
||||
set c_menu_current = "#fff";
|
||||
set f_menu_header_size = "140%";
|
||||
set c_entry_background = "#fff";
|
||||
set c_entry_link = "#99602B";
|
||||
set c_entry_link_visited = "#BF7836";
|
||||
set c_entry_link_hover = "#734820";
|
||||
set c_entry_link_active = "#734820";
|
||||
set c_entry_text_color = "#333";
|
||||
set c_entry_title_color = "#000";
|
||||
set c_entry_border = "#BFBFBF";
|
||||
set c_meta_background = "#fff";
|
||||
set c_meta_link = "#99602B";
|
||||
set c_meta_link_visited = "#BF7836";
|
||||
set c_meta_link_hover = "#734820";
|
||||
set c_meta_link_active = "#734820";
|
||||
set c_meta_text_color = "#666";
|
||||
set c_footer_background = "#667320";
|
||||
set c_footer_link = "#000";
|
||||
set c_footer_link_visited = "#000";
|
||||
set c_footer_link_hover = "#fff";
|
||||
set c_footer_link_active = "#000";
|
||||
set c_footer_text_color = "#000";
|
||||
set c_comment_one_link = "#99602B";
|
||||
set c_comment_one_link_visited = "#BF7836";
|
||||
set c_comment_one_link_hover = "#734820";
|
||||
set c_comment_one_link_active = "#734820";
|
||||
set c_comment_one_text_color = "#333";
|
||||
set c_comment_one_title_color = "#000";
|
||||
set c_comment_one_background = "#fff";
|
||||
set c_comment_one_border = "#999";
|
||||
set c_comment_two_link = "#99602B";
|
||||
set c_comment_two_link_visited = "#BF7836";
|
||||
set c_comment_two_link_hover = "#734820";
|
||||
set c_comment_two_link_active = "#734820";
|
||||
set c_comment_two_text_color = "#333";
|
||||
set c_comment_two_title_color = "#000";
|
||||
set c_comment_two_background = "#f2f2f2";
|
||||
set c_comment_two_border = "#999";
|
||||
set c_comment_screened_link = "#99602B";
|
||||
set c_comment_screened_link_visited = "#BF7836";
|
||||
set c_comment_screened_link_hover = "#734820";
|
||||
set c_comment_screened_link_active = "#734820";
|
||||
set c_comment_screened_text_color = "#333";
|
||||
set c_comment_screened_title_color = "#000";
|
||||
set c_comment_screened_background = "#ccc";
|
||||
set c_comment_screened_border = "#999";
|
||||
|
||||
#NEWLAYER: tranquilityii/money
|
||||
layerinfo "redist_uniq" = "tranquilityii/money";
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Tranquility II - Money Theme";
|
||||
layerinfo "author_name" = "Matthew Vince";
|
||||
|
||||
set c_main_border = "#68754D";
|
||||
set c_header_background = "#ACC280";
|
||||
set c_header_border = "#ACC280";
|
||||
set c_page_title = "#3D3D3D";
|
||||
set c_page_background = "#ACC280";
|
||||
set c_page_text = "#3D3D3D";
|
||||
set c_page_link = "#000";
|
||||
set c_page_link_visited = "#666";
|
||||
set c_page_link_hover = "#999";
|
||||
set c_page_link_active = "#999";
|
||||
set c_menu_border = "#68754D";
|
||||
set c_menu_background = "#8A9C67";
|
||||
set c_menu_link = "#000";
|
||||
set c_menu_link_visited = "#000";
|
||||
set c_menu_link_hover = "#EBF7D4";
|
||||
set c_menu_link_active = "#ebf7d4";
|
||||
set c_menu_text_color = "#000";
|
||||
set c_menu_header_color = "#000";
|
||||
set c_menu_current = "#EBF7D4";
|
||||
set f_menu_header_size = "140%";
|
||||
set c_entry_background = "#fff";
|
||||
set c_entry_link = "#679C67";
|
||||
set c_entry_link_visited = "#80C280";
|
||||
set c_entry_link_hover = "#4D754D";
|
||||
set c_entry_link_active = "#4D754D";
|
||||
set c_entry_text_color = "#000";
|
||||
set c_entry_title_color = "#000";
|
||||
set c_entry_border = "#3D3D3D";
|
||||
set c_meta_background = "#fff";
|
||||
set c_meta_link = "#679C67";
|
||||
set c_meta_link_visited = "#80C280";
|
||||
set c_meta_link_hover = "#4D754D";
|
||||
set c_meta_link_active = "#4D754D";
|
||||
set c_meta_text_color = "#3D3D3D";
|
||||
set c_footer_background = "#ACC280";
|
||||
set c_footer_link = "#000";
|
||||
set c_footer_link_visited = "#000";
|
||||
set c_footer_link_hover = "#fff";
|
||||
set c_footer_link_active = "#000";
|
||||
set c_footer_text_color = "#000";
|
||||
set c_comment_one_link = "#679C67";
|
||||
set c_comment_one_link_visited = "#80C280";
|
||||
set c_comment_one_link_hover = "#4D754D";
|
||||
set c_comment_one_link_active = "#4D754D";
|
||||
set c_comment_one_text_color = "#000";
|
||||
set c_comment_one_title_color = "#000";
|
||||
set c_comment_one_background = "#fff";
|
||||
set c_comment_one_border = "#999";
|
||||
set c_comment_two_link = "#679C67";
|
||||
set c_comment_two_link_visited = "#80C280";
|
||||
set c_comment_two_link_hover = "#4D754D";
|
||||
set c_comment_two_link_active = "#4D754D";
|
||||
set c_comment_two_text_color = "#000";
|
||||
set c_comment_two_title_color = "#000";
|
||||
set c_comment_two_background = "#f2f2f2";
|
||||
set c_comment_two_border = "#999";
|
||||
set c_comment_screened_link = "#679C67";
|
||||
set c_comment_screened_link_visited = "#80C280";
|
||||
set c_comment_screened_link_hover = "#4D754D";
|
||||
set c_comment_screened_link_active = "#4D754D";
|
||||
set c_comment_screened_text_color = "#000";
|
||||
set c_comment_screened_title_color = "#000";
|
||||
set c_comment_screened_background = "#ccc";
|
||||
set c_comment_screened_border = "#999";
|
||||
set f_page = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_page_title = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_page_link = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_menu_link = "Verdana, Helvetica, sans-serif";
|
||||
set f_menu = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_menu_header = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_menu_current = "Verdana, Helvetica, sans-serif";
|
||||
set f_entry = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_entry_link = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_entry_title = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_meta = "Verdana, Helvetica, sans-serif";
|
||||
set f_meta_link = "Verdana, Helvetica, sans-serif";
|
||||
set f_footer = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_footer_link = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_comment = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_comment_title = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_comment_link = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
|
||||
#NEWLAYER: tranquilityii/winterice
|
||||
layerinfo "redist_uniq" = "tranquilityii/winterice";
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Tranquility II - WinterIce Theme";
|
||||
layerinfo "author_name" = "Matthew Vince";
|
||||
|
||||
set c_main_border = "#000";
|
||||
set c_header_background = "#694D73";
|
||||
set c_header_border = "#694D73";
|
||||
set c_page_title = "#000";
|
||||
set c_page_background = "#694D73";
|
||||
set c_page_text = "#3D3D3D";
|
||||
set c_page_link = "#000";
|
||||
set c_page_link_visited = "#666";
|
||||
set c_page_link_hover = "#999";
|
||||
set c_page_link_active = "#999";
|
||||
set c_menu_border = "#694D73";
|
||||
set c_menu_background = "#694D73";
|
||||
set c_menu_link = "#fff";
|
||||
set c_menu_link_visited = "#fff";
|
||||
set c_menu_link_hover = "#C5A2D0";
|
||||
set c_menu_link_active = "#C5A2D0";
|
||||
set c_menu_text_color = "#fff";
|
||||
set c_menu_header_color = "#fff";
|
||||
set c_menu_current = "#C5A2D0";
|
||||
set f_menu_header_size = "140%";
|
||||
set c_entry_background = "#fff";
|
||||
set c_entry_link = "#5E71AE";
|
||||
set c_entry_link_visited = "#5E71AE";
|
||||
set c_entry_link_hover = "#808FBF";
|
||||
set c_entry_link_active = "#808FBF";
|
||||
set c_entry_text_color = "#000";
|
||||
set c_entry_title_color = "#000";
|
||||
set c_entry_border = "#3D3D3D";
|
||||
set c_meta_background = "#fff";
|
||||
set c_meta_link = "#B080BF";
|
||||
set c_meta_link_visited = "#C29FCB";
|
||||
set c_meta_link_hover = "#854D93";
|
||||
set c_meta_link_active = "#854D93";
|
||||
set c_meta_text_color = "#3D3D3D";
|
||||
set c_footer_background = "#694D73";
|
||||
set c_footer_link = "#fff";
|
||||
set c_footer_link_visited = "#fff";
|
||||
set c_footer_link_hover = "#fff";
|
||||
set c_footer_link_active = "#fff";
|
||||
set c_footer_text_color = "#fff";
|
||||
set c_comment_one_link = "#5E71AE";
|
||||
set c_comment_one_link_visited = "#5E71AE";
|
||||
set c_comment_one_link_hover = "#808FBF";
|
||||
set c_comment_one_link_active = "#808FBF";
|
||||
set c_comment_one_text_color = "#000";
|
||||
set c_comment_one_title_color = "#000";
|
||||
set c_comment_one_background = "#fff";
|
||||
set c_comment_one_border = "#999";
|
||||
set c_comment_two_link = "#5E71AE";
|
||||
set c_comment_two_link_visited = "#5E71AE";
|
||||
set c_comment_two_link_hover = "#808FBF";
|
||||
set c_comment_two_link_active = "#808FBF";
|
||||
set c_comment_two_text_color = "#000";
|
||||
set c_comment_two_title_color = "#000";
|
||||
set c_comment_two_background = "#f2f2f2";
|
||||
set c_comment_two_border = "#999";
|
||||
set c_comment_screened_link = "#5E71AE";
|
||||
set c_comment_screened_link_visited = "#5E71AE";
|
||||
set c_comment_screened_link_hover = "#808FBF";
|
||||
set c_comment_screened_link_active = "#808FBF";
|
||||
set c_comment_screened_text_color = "#000";
|
||||
set c_comment_screened_title_color = "#000";
|
||||
set c_comment_screened_background = "#ccc";
|
||||
set c_comment_screened_border = "#999";
|
||||
set f_page = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_page_title = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_page_link = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_menu_link = "Verdana, Helvetica, sans-serif";
|
||||
set f_menu = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_menu_header = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_menu_current = "Verdana, Helvetica, sans-serif";
|
||||
set f_entry = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_entry_link = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_entry_title = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_meta = "Verdana, Helvetica, sans-serif";
|
||||
set f_meta_link = "Verdana, Helvetica, sans-serif";
|
||||
set f_footer = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_footer_link = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_comment = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_comment_title = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_comment_link = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
|
||||
#NEWLAYER: tranquilityii/fire
|
||||
layerinfo "redist_uniq" = "tranquilityii/fire";
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Tranquility II - Fire Theme";
|
||||
layerinfo "author_name" = "Matthew Vince";
|
||||
|
||||
set c_main_border = "#A65000";
|
||||
set c_header_background = "#A65000";
|
||||
set c_header_border = "#A65000";
|
||||
set c_page_title = "#000";
|
||||
set c_page_background = "#A65000";
|
||||
set c_page_text = "#3D3D3D";
|
||||
set c_page_link = "#000";
|
||||
set c_page_link_visited = "#666";
|
||||
set c_page_link_hover = "#999";
|
||||
set c_page_link_active = "#999";
|
||||
set c_menu_border = "#A68700";
|
||||
set c_menu_background = "#CCA700";
|
||||
set c_menu_link = "#fff";
|
||||
set c_menu_link_visited = "#FFD100";
|
||||
set c_menu_link_hover = "#CC4100";
|
||||
set c_menu_link_active = "#CC4100";
|
||||
set c_menu_text_color = "#fff";
|
||||
set c_menu_header_color = "#fff";
|
||||
set c_menu_current = "#CC4100";
|
||||
set f_menu_header_size = "140%";
|
||||
set c_entry_background = "#fff";
|
||||
set c_entry_link = "#CC6300";
|
||||
set c_entry_link_visited = "#F27500";
|
||||
set c_entry_link_hover = "#A65000";
|
||||
set c_entry_link_active = "#A65000";
|
||||
set c_entry_text_color = "#333";
|
||||
set c_entry_title_color = "#333";
|
||||
set c_entry_border = "#666";
|
||||
set c_meta_background = "#fff";
|
||||
set c_meta_link = "#CCA700";
|
||||
set c_meta_link_visited = "#F2C600";
|
||||
set c_meta_link_hover = "#A68700";
|
||||
set c_meta_link_active = "#A68700";
|
||||
set c_meta_text_color = "#3D3D3D";
|
||||
set c_footer_background = "#A65000";
|
||||
set c_footer_link = "#fff";
|
||||
set c_footer_link_visited = "#fff";
|
||||
set c_footer_link_hover = "#fff";
|
||||
set c_footer_link_active = "#fff";
|
||||
set c_footer_text_color = "#fff";
|
||||
set c_comment_one_link = "#CC6300";
|
||||
set c_comment_one_link_visited = "#F27500";
|
||||
set c_comment_one_link_hover = "#A65000";
|
||||
set c_comment_one_link_active = "#A65000";
|
||||
set c_comment_one_text_color = "#333";
|
||||
set c_comment_one_title_color = "#000";
|
||||
set c_comment_one_background = "#fff";
|
||||
set c_comment_one_border = "#999";
|
||||
set c_comment_two_link = "#CC6300";
|
||||
set c_comment_two_link_visited = "#F27500";
|
||||
set c_comment_two_link_hover = "#A65000";
|
||||
set c_comment_two_link_active = "#A65000";
|
||||
set c_comment_two_text_color = "#333";
|
||||
set c_comment_two_title_color = "#000";
|
||||
set c_comment_two_background = "#f2f2f2";
|
||||
set c_comment_two_border = "#999";
|
||||
set c_comment_screened_link = "#CC6300";
|
||||
set c_comment_screened_link_visited = "#F27500";
|
||||
set c_comment_screened_link_hover = "#A65000";
|
||||
set c_comment_screened_link_active = "#A65000";
|
||||
set c_comment_screened_text_color = "#333";
|
||||
set c_comment_screened_title_color = "#000";
|
||||
set c_comment_screened_background = "#ccc";
|
||||
set c_comment_screened_border = "#999";
|
||||
|
||||
#NEWLAYER: tranquilityii/mobile
|
||||
layerinfo "redist_uniq" = "tranquilityii/mobile";
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Tranquility II - Mobile Theme";
|
||||
layerinfo "author_name" = "Matthew Vince";
|
||||
|
||||
set c_main_border = "#fff";
|
||||
set c_header_background = "#fff";
|
||||
set c_header_border = "#fff";
|
||||
set c_page_title = "#000";
|
||||
set c_page_background = "#fff";
|
||||
set c_page_text = "#000";
|
||||
set c_page_link = "#00f";
|
||||
set c_page_link_visited = "#999";
|
||||
set c_page_link_hover = "#f00";
|
||||
set c_page_link_active = "#f00";
|
||||
set c_menu_border = "#fff";
|
||||
set c_menu_background = "#fff";
|
||||
set c_menu_link = "#00f";
|
||||
set c_menu_link_visited = "#999";
|
||||
set c_menu_link_hover = "#f00";
|
||||
set c_menu_link_active = "#f00";
|
||||
set c_menu_text_color = "#000";
|
||||
set c_menu_header_color = "#00";
|
||||
set c_menu_current = "#000";
|
||||
set f_menu_header_size = "140%";
|
||||
set c_entry_background = "#fff";
|
||||
set c_entry_link = "#00f";
|
||||
set c_entry_link_visited = "#999";
|
||||
set c_entry_link_hover = "#f00";
|
||||
set c_entry_link_active = "#f00";
|
||||
set c_entry_text_color = "#000";
|
||||
set c_entry_title_color = "#000";
|
||||
set c_entry_border = "#fff";
|
||||
set c_meta_background = "#fff";
|
||||
set c_meta_link = "#00f";
|
||||
set c_meta_link_visited = "#999";
|
||||
set c_meta_link_hover = "#f00";
|
||||
set c_meta_link_active = "#f00";
|
||||
set c_meta_text_color = "#000";
|
||||
set c_footer_background = "#fff";
|
||||
set c_footer_link = "#00f";
|
||||
set c_footer_link_visited = "#999";
|
||||
set c_footer_link_hover = "#f00";
|
||||
set c_footer_link_active = "#f00";
|
||||
set c_footer_text_color = "#000";
|
||||
set c_comment_one_link = "#00f";
|
||||
set c_comment_one_link_visited = "#999";
|
||||
set c_comment_one_link_hover = "#f00";
|
||||
set c_comment_one_link_active = "#f00";
|
||||
set c_comment_one_text_color = "#000";
|
||||
set c_comment_one_title_color = "#000";
|
||||
set c_comment_one_background = "#fff";
|
||||
set c_comment_one_border = "#fff";
|
||||
set c_comment_two_link = "#00f";
|
||||
set c_comment_two_link_visited = "#999";
|
||||
set c_comment_two_link_hover = "#f00";
|
||||
set c_comment_two_link_active = "#f00";
|
||||
set c_comment_two_text_color = "#000";
|
||||
set c_comment_two_title_color = "#000";
|
||||
set c_comment_two_background = "#f2f2f2";
|
||||
set c_comment_two_border = "#fff";
|
||||
set c_comment_screened_link = "#00f";
|
||||
set c_comment_screened_link_visited = "#999";
|
||||
set c_comment_screened_link_hover = "#f00";
|
||||
set c_comment_screened_link_active = "#f00";
|
||||
set c_comment_screened_text_color = "#000";
|
||||
set c_comment_screened_title_color = "#000";
|
||||
set c_comment_screened_background = "#999";
|
||||
set c_comment_screened_border = "#fff";
|
||||
set menu_disable_summary = true;
|
||||
set css_style_overrides = "hr { display: block; } #menu { float: none; width: auto; } #content { margin-left: 0; } #container { margin: 0; padding: 0; text-align: left; width: 100%; }";
|
||||
|
||||
#NEWLAYER: tranquilityii/pinky
|
||||
layerinfo "redist_uniq" = "tranquilityii/pinky";
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Tranquility II - Pinky Theme";
|
||||
layerinfo "author_name" = "Matthew Vince";
|
||||
|
||||
set c_main_border = "#242E35";
|
||||
set c_header_background = "#242E35";
|
||||
set c_header_border = "#242E35";
|
||||
set c_page_title = "#fff";
|
||||
set c_page_background = "#242E35";
|
||||
set c_page_text = "#fff";
|
||||
set c_page_link = "#f0c";
|
||||
set c_page_link_visited = "#FF82E5";
|
||||
set c_page_link_hover = "#B30090";
|
||||
set c_page_link_active = "#B30090";
|
||||
set c_menu_border = "#B4A361";
|
||||
set c_menu_background = "#ECE9D8";
|
||||
set c_menu_link = "#000";
|
||||
set c_menu_link_visited = "#999";
|
||||
set c_menu_link_hover = "#000";
|
||||
set c_menu_link_active = "#000";
|
||||
set c_menu_text_color = "#333";
|
||||
set c_menu_header_color = "#333";
|
||||
set c_menu_current = "#000";
|
||||
set f_menu_header_size = "140%";
|
||||
set c_entry_background = "#F8F7F1";
|
||||
set c_entry_link = "#f0c";
|
||||
set c_entry_link_visited = "#FF82E5";
|
||||
set c_entry_link_hover = "#B30090";
|
||||
set c_entry_link_active = "#B30090";
|
||||
set c_entry_text_color = "#333";
|
||||
set c_entry_title_color = "#666";
|
||||
set c_entry_border = "000";
|
||||
set c_meta_background = "#F8F7F1";
|
||||
set c_meta_link = "#f0c";
|
||||
set c_meta_link_visited = "#FF82E5";
|
||||
set c_meta_link_hover = "#B30090";
|
||||
set c_meta_link_active = "#B30090";
|
||||
set c_meta_text_color = "#666";
|
||||
set c_footer_background = "#242E35";
|
||||
set c_footer_link = "#fff";
|
||||
set c_footer_link_visited = "#fff";
|
||||
set c_footer_link_hover = "#fff";
|
||||
set c_footer_link_active = "#fff";
|
||||
set c_footer_text_color = "#fff";
|
||||
set c_comment_one_link = "#f0c";
|
||||
set c_comment_one_link_visited = "#FF82E5";
|
||||
set c_comment_one_link_hover = "#B30090";
|
||||
set c_comment_one_link_active = "#B30090";
|
||||
set c_comment_one_text_color = "#333";
|
||||
set c_comment_one_title_color = "#666";
|
||||
set c_comment_one_background = "#fff";
|
||||
set c_comment_one_border = "#999";
|
||||
set c_comment_two_link = "#f0c";
|
||||
set c_comment_two_link_visited = "#FF82E5";
|
||||
set c_comment_two_link_hover = "#B30090";
|
||||
set c_comment_two_link_active = "#B30090";
|
||||
set c_comment_two_text_color = "#333";
|
||||
set c_comment_two_title_color = "#666";
|
||||
set c_comment_two_background = "#f2f2f2";
|
||||
set c_comment_two_border = "#999";
|
||||
set c_comment_screened_link = "#f0c";
|
||||
set c_comment_screened_link_visited = "#FF82E5";
|
||||
set c_comment_screened_link_hover = "#B30090";
|
||||
set c_comment_screened_link_active = "#B30090";
|
||||
set c_comment_screened_text_color = "#333";
|
||||
set c_comment_screened_title_color = "#666";
|
||||
set c_comment_screened_background = "#ccc";
|
||||
set c_comment_screened_border = "#999";
|
||||
set f_page = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_page_title = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_page_link = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_menu_link = "Verdana, Helvetica, sans-serif";
|
||||
set f_menu = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_menu_header = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_menu_current = "Verdana, Helvetica, sans-serif";
|
||||
set f_entry = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_entry_link = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_entry_title = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_meta = "Verdana, Helvetica, sans-serif";
|
||||
set f_meta_link = "Verdana, Helvetica, sans-serif";
|
||||
set f_footer = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_footer_link = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_comment = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_comment_title = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_comment_link = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
|
||||
#NEWLAYER: tranquilityii/fresh
|
||||
layerinfo "redist_uniq" = "tranquilityii/fresh";
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Tranquility II - Fresh Theme";
|
||||
layerinfo "author_name" = "Matthew Vince";
|
||||
|
||||
set c_main_border = "#7A97B2";
|
||||
set c_header_background = "#7A97B2";
|
||||
set c_header_border = "#7A97B2";
|
||||
set c_page_title = "#273849";
|
||||
set c_page_background = "#242E35";
|
||||
set c_page_text = "#fff";
|
||||
set c_page_link = "#036";
|
||||
set c_page_link_visited = "#036";
|
||||
set c_page_link_hover = "#069";
|
||||
set c_page_link_active = "#069";
|
||||
set c_menu_border = "#CFE0E6";
|
||||
set c_menu_background = "#CFE0E6";
|
||||
set c_menu_link = "#000";
|
||||
set c_menu_link_visited = "#999";
|
||||
set c_menu_link_hover = "#000";
|
||||
set c_menu_link_active = "#000";
|
||||
set c_menu_text_color = "#333";
|
||||
set c_menu_header_color = "#333";
|
||||
set c_menu_current = "#000";
|
||||
set f_menu_header_size = "140%";
|
||||
set c_entry_background = "#fff";
|
||||
set c_entry_link = "#036";
|
||||
set c_entry_link_visited = "#036";
|
||||
set c_entry_link_hover = "#069";
|
||||
set c_entry_link_active = "#069";
|
||||
set c_entry_text_color = "#333";
|
||||
set c_entry_title_color = "#999";
|
||||
set c_entry_border = "000";
|
||||
set c_meta_background = "#fff";
|
||||
set c_meta_link = "#036";
|
||||
set c_meta_link_visited = "#036";
|
||||
set c_meta_link_hover = "#069";
|
||||
set c_meta_link_active = "#069";
|
||||
set c_meta_text_color = "#999";
|
||||
set c_footer_background = "#7A97B2";
|
||||
set c_footer_link = "#fff";
|
||||
set c_footer_link_visited = "#fff";
|
||||
set c_footer_link_hover = "#fff";
|
||||
set c_footer_link_active = "#fff";
|
||||
set c_footer_text_color = "#fff";
|
||||
set c_comment_one_link = "#036";
|
||||
set c_comment_one_link_visited = "#036";
|
||||
set c_comment_one_link_hover = "#069";
|
||||
set c_comment_one_link_active = "#069";
|
||||
set c_comment_one_text_color = "#333";
|
||||
set c_comment_one_title_color = "#999";
|
||||
set c_comment_one_background = "#fff";
|
||||
set c_comment_one_border = "#999";
|
||||
set c_comment_two_link = "#036";
|
||||
set c_comment_two_link_visited = "#036";
|
||||
set c_comment_two_link_hover = "#069";
|
||||
set c_comment_two_link_active = "#069";
|
||||
set c_comment_two_text_color = "#333";
|
||||
set c_comment_two_title_color = "#999";
|
||||
set c_comment_two_background = "#f2f2f2";
|
||||
set c_comment_two_border = "#999";
|
||||
set c_comment_screened_link = "#036";
|
||||
set c_comment_screened_link_visited = "#036";
|
||||
set c_comment_screened_link_hover = "#069";
|
||||
set c_comment_screened_link_active = "#069";
|
||||
set c_comment_screened_text_color = "#333";
|
||||
set c_comment_screened_title_color = "#999";
|
||||
set c_comment_screened_background = "#ccc";
|
||||
set c_comment_screened_border = "#999";
|
||||
set f_page = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_page_title = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_page_link = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_menu_link = "Verdana, Helvetica, sans-serif";
|
||||
set f_menu = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_menu_header = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_menu_current = "Verdana, Helvetica, sans-serif";
|
||||
set f_entry = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_entry_link = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_entry_title = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_meta = "Verdana, Helvetica, sans-serif";
|
||||
set f_meta_link = "Verdana, Helvetica, sans-serif";
|
||||
set f_footer = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_footer_link = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_comment = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_comment_title = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
set f_comment_link = "Tahoma, Verdana, Helvetica, sans-serif";
|
||||
|
||||
#NEWLAYER: tranquilityii/auto
|
||||
layerinfo "redist_uniq" = "tranquilityii/auto";
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Tranquility II - Auto Theme";
|
||||
layerinfo "author_name" = "Matthew Vince";
|
||||
|
||||
set c_main_border = "#515151";
|
||||
set c_header_background = "#515151";
|
||||
set c_header_border = "#515151";
|
||||
set c_page_title = "#fff";
|
||||
set c_page_background = "#515151";
|
||||
set c_page_text = "#333";
|
||||
set c_page_link = "#00B4FF";
|
||||
set c_page_link_visited = "#00B4FF";
|
||||
set c_page_link_hover = "#006894";
|
||||
set c_page_link_active = "#006894";
|
||||
set c_menu_border = "#ccc";
|
||||
set c_menu_background = "#eee";
|
||||
set c_menu_link = "#000";
|
||||
set c_menu_link_visited = "#999";
|
||||
set c_menu_link_hover = "#000";
|
||||
set c_menu_link_active = "#000";
|
||||
set c_menu_text_color = "#333";
|
||||
set c_menu_header_color = "#333";
|
||||
set c_menu_current = "#000";
|
||||
set f_menu_header_size = "140%";
|
||||
set c_entry_background = "#fff";
|
||||
set c_entry_link = "#00B4FF";
|
||||
set c_entry_link_visited = "#00B4FF";
|
||||
set c_entry_link_hover = "#006894";
|
||||
set c_entry_link_active = "#006894";
|
||||
set c_entry_text_color = "#333";
|
||||
set c_entry_title_color = "#999";
|
||||
set c_entry_border = "000";
|
||||
set c_meta_background = "#fff";
|
||||
set c_meta_link = "#036";
|
||||
set c_meta_link_visited = "#036";
|
||||
set c_meta_link_hover = "#069";
|
||||
set c_meta_link_active = "#069";
|
||||
set c_meta_text_color = "#999";
|
||||
set c_footer_background = "#515151";
|
||||
set c_footer_link = "#fff";
|
||||
set c_footer_link_visited = "#fff";
|
||||
set c_footer_link_hover = "#fff";
|
||||
set c_footer_link_active = "#fff";
|
||||
set c_footer_text_color = "#fff";
|
||||
set c_comment_one_link = "#00B4FF";
|
||||
set c_comment_one_link_visited = "#00B4FF";
|
||||
set c_comment_one_link_hover = "#006894";
|
||||
set c_comment_one_link_active = "#006894";
|
||||
set c_comment_one_text_color = "#333";
|
||||
set c_comment_one_title_color = "#999";
|
||||
set c_comment_one_background = "#fff";
|
||||
set c_comment_one_border = "#999";
|
||||
set c_comment_two_link = "#00B4FF";
|
||||
set c_comment_two_link_visited = "#00B4FF";
|
||||
set c_comment_two_link_hover = "#006894";
|
||||
set c_comment_two_link_active = "#006894";
|
||||
set c_comment_two_text_color = "#333";
|
||||
set c_comment_two_title_color = "#999";
|
||||
set c_comment_two_background = "#f2f2f2";
|
||||
set c_comment_two_border = "#999";
|
||||
set c_comment_screened_link = "#00B4FF";
|
||||
set c_comment_screened_link_visited = "#00B4FF";
|
||||
set c_comment_screened_link_hover = "#006894";
|
||||
set c_comment_screened_link_active = "#006894";
|
||||
set c_comment_screened_text_color = "#333";
|
||||
set c_comment_screened_title_color = "#999";
|
||||
set c_comment_screened_background = "#ccc";
|
||||
set c_comment_screened_border = "#999";
|
||||
1555
local/bin/upgrading/s2layers/unearthed/layout.s2
Executable file
1555
local/bin/upgrading/s2layers/unearthed/layout.s2
Executable file
File diff suppressed because it is too large
Load Diff
118
local/bin/upgrading/s2layers/unearthed/themes.s2
Executable file
118
local/bin/upgrading/s2layers/unearthed/themes.s2
Executable file
@@ -0,0 +1,118 @@
|
||||
#NEWLAYER: unearthed/rampant
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Rampant Tenderfoot";
|
||||
layerinfo redist_uniq = "unearthed/rampant";
|
||||
|
||||
set stronger_bgcolor = "#ff3300";
|
||||
set strong_bgcolor = "#ff8000";
|
||||
set neutral_bgcolor = "#ffb200";
|
||||
set weak_bgcolor = "#ffb380";
|
||||
set weaker_bgcolor = "#ffcc80";
|
||||
|
||||
#NEWLAYER: unearthed/acrid
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Acrid Slide";
|
||||
layerinfo redist_uniq = "unearthed/acrid";
|
||||
|
||||
set title_texture = "rough";
|
||||
set stronger_bgcolor = "#33ff00";
|
||||
set strong_bgcolor = "#0066b2";
|
||||
set neutral_bgcolor = "#00B266";
|
||||
set weak_bgcolor = "#99ff80";
|
||||
set weaker_bgcolor = "#ccffbf";
|
||||
|
||||
#NEWLAYER: unearthed/leisure
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Leisure Renewal";
|
||||
layerinfo redist_uniq = "unearthed/leisure";
|
||||
|
||||
set title_texture = "camouflage";
|
||||
set stronger_bgcolor = "#285577";
|
||||
set strong_bgcolor = "#3c3773";
|
||||
set neutral_bgcolor = "#287755";
|
||||
set weak_bgcolor = "#c0c0ec";
|
||||
set weaker_bgcolor = "#b1ecd3";
|
||||
|
||||
#NEWLAYER: unearthed/craftis
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Craftis";
|
||||
layerinfo redist_uniq = "unearthed/craftis";
|
||||
|
||||
set title_texture = "camouflage";
|
||||
set stronger_bgcolor = "#dd0000";
|
||||
set strong_bgcolor = "#aa4f39";
|
||||
set neutral_bgcolor = "#d2d2d2";
|
||||
set weak_bgcolor = "#fcffcf";
|
||||
set weaker_bgcolor = "#eeeeee";
|
||||
|
||||
#NEWLAYER: unearthed/unveiled
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Unveiled Metal";
|
||||
layerinfo redist_uniq = "unearthed/unveiled";
|
||||
|
||||
set title_texture = "brushed_metal";
|
||||
set stronger_bgcolor = "#666666";
|
||||
set strong_bgcolor = "#999999";
|
||||
set neutral_bgcolor = "#333333";
|
||||
set weak_bgcolor = "#cccccc";
|
||||
set weaker_bgcolor = "#eeeeee";
|
||||
|
||||
#NEWLAYER: unearthed/wait
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Wait Screw";
|
||||
layerinfo redist_uniq = "unearthed/wait";
|
||||
|
||||
set title_texture = "chalk";
|
||||
set stronger_bgcolor = "#009999";
|
||||
set strong_bgcolor = "#ff6600";
|
||||
set neutral_bgcolor = "#66cccc";
|
||||
set weak_bgcolor = "#ffb380";
|
||||
set weaker_bgcolor = "#eeeeee";
|
||||
|
||||
#NEWLAYER: unearthed/drinkdna
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Drinking DNA";
|
||||
layerinfo redist_uniq = "unearthed/drinkdna";
|
||||
|
||||
set title_texture = "cork";
|
||||
set stronger_bgcolor = "#4C9978";
|
||||
set strong_bgcolor = "#468C8C";
|
||||
set neutral_bgcolor = "#53A653";
|
||||
set weak_bgcolor = "#ACE6E6";
|
||||
set weaker_bgcolor = "#eeeeee";
|
||||
|
||||
#NEWLAYER: unearthed/gainful
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Gainful Magic";
|
||||
layerinfo redist_uniq = "unearthed/gainful";
|
||||
|
||||
set title_texture = "fibers";
|
||||
set stronger_bgcolor = "#DFDFA7";
|
||||
set strong_bgcolor = "#FFFF80";
|
||||
set neutral_bgcolor = "#AAAA39";
|
||||
set weak_bgcolor = "#eeeeee";
|
||||
set weaker_bgcolor = "#FFFFBF";
|
||||
|
||||
#NEWLAYER: unearthed/inaccurate
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Inaccurate Lingo";
|
||||
layerinfo redist_uniq = "unearthed/inaccurate";
|
||||
|
||||
set title_texture = "stucco";
|
||||
set stronger_bgcolor = "#FF8080";
|
||||
set strong_bgcolor = "#FF9980";
|
||||
set neutral_bgcolor = "#E572A5";
|
||||
set weak_bgcolor = "#F2B6D0";
|
||||
set weaker_bgcolor = "#eeeeee";
|
||||
|
||||
#NEWLAYER: unearthed/current
|
||||
layerinfo "type" = "theme";
|
||||
layerinfo "name" = "Current Protector";
|
||||
layerinfo redist_uniq = "unearthed/current";
|
||||
|
||||
set title_texture = "type";
|
||||
set stronger_bgcolor = "#B5D9D9";
|
||||
set strong_bgcolor = "#285577";
|
||||
set neutral_bgcolor = "#226666";
|
||||
set weak_bgcolor = "#7DA0BB";
|
||||
set weaker_bgcolor = "#B5D9D9";
|
||||
25
local/bin/upgrading/sb.dat
Normal file
25
local/bin/upgrading/sb.dat
Normal file
@@ -0,0 +1,25 @@
|
||||
;; -*- coding: utf-8 -*-
|
||||
/manage/siteopts.bml.btn.lang=Сменити язык
|
||||
|
||||
dystopia.hello_loggedin=Здорово буть
|
||||
|
||||
langname.en=Аглицкий
|
||||
|
||||
langname.ru=Руской
|
||||
|
||||
langname.sb=Сибирской
|
||||
|
||||
ljrlook.nav.editfriends=Тамыри
|
||||
|
||||
ljrlook.nav.friends=Тамыри
|
||||
|
||||
ljrlook.nav.hello=Здорово буть
|
||||
|
||||
lynx.nav.friends=Тамыри
|
||||
|
||||
poll.security.friends=Тамыри
|
||||
|
||||
xcolibur.nav.journal.friends=Тамыри
|
||||
|
||||
xcolibur.nav.manage.friends=Тамыри
|
||||
|
||||
29
local/bin/upgrading/text-local.dat
Executable file
29
local/bin/upgrading/text-local.dat
Executable file
@@ -0,0 +1,29 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
domain:100:faq
|
||||
domain:101:journal/news
|
||||
|
||||
# EnglishLJ is child of English for general domain:
|
||||
#lang:100:en_LJ:English (LJ):sim:en
|
||||
#langdomain:en_LJ:general
|
||||
|
||||
# EnglishLJ is root of FAQ & news journal:
|
||||
#langdomain:en_LJ:faq:1
|
||||
#langdomain:en_LJ:journal/news:1
|
||||
|
||||
# Russian
|
||||
lang:106:ru:Russian:diff:en
|
||||
langdomain:ru:general
|
||||
langdomain:ru:journal/news
|
||||
langdomain:ru:faq
|
||||
|
||||
# Ukrainian
|
||||
lang:131:uk:Ukrainian:diff:en
|
||||
langdomain:uk:general
|
||||
langdomain:uk:journal/news
|
||||
langdomain:uk:faq
|
||||
|
||||
# Siberian
|
||||
lang:206:sb:Siberian:diff:en
|
||||
langdomain:sb:general
|
||||
langdomain:sb:journal/news
|
||||
langdomain:sb:faq
|
||||
84
local/bin/upgrading/texttool-overrides
Normal file
84
local/bin/upgrading/texttool-overrides
Normal file
@@ -0,0 +1,84 @@
|
||||
#
|
||||
# texttool.pl newitems override
|
||||
# format:
|
||||
# <code calculated by texttool.pl><space><actual code which should be used>
|
||||
#
|
||||
|
||||
/modify.bml.colortheme.defaulttheme /modify_do.bml.colortheme.defaulttheme
|
||||
/modify.bml.colortheme.color.head2 /modify_do.bml.colortheme.color.head2
|
||||
/modify.bml.colortheme.customcolors /modify_do.bml.colortheme.customcolors
|
||||
/modify.bml.overrides.warning /modify_do.bml.overrides.warning
|
||||
/modify.bml.moodicons.head /modify_do.bml.moodicons.head
|
||||
/modify.bml.availablestyles.userstyles /modify_do.bml.availablestyles.userstyles
|
||||
/modify.bml.overrides.head /modify_do.bml.overrides.head
|
||||
/modify.bml.moodicons.personal /modify_do.bml.moodicons.personal
|
||||
/modify.bml.domainalias.example /modify_do.bml.domainalias.example
|
||||
/modify.bml.friends.opt.usesharedpic.about /modify_do.bml.friends.opt.usesharedpic.about
|
||||
/modify.bml.overrides.note /modify_do.bml.overrides.note
|
||||
/modify.bml.colortheme.about /modify_do.bml.colortheme.about
|
||||
/modify.bml.done.text /modify_do.bml.done.text
|
||||
/modify.bml.success.head /modify_do.bml.success.head
|
||||
/modify.bml.pagelayoutstyle.warning /modify_do.bml.pagelayoutstyle.warning
|
||||
/modify.bml.friends.head /modify_do.bml.friends.head
|
||||
/modify.bml.error.stylenotavailable /modify_do.bml.error.stylenotavailable
|
||||
/modify.bml.colortheme.color.head1 /modify_do.bml.colortheme.color.head1
|
||||
/modify.bml.friends.opt.usesharedpic.head /modify_do.bml.friends.opt.usesharedpic.head
|
||||
/modify.bml.pagelayoutstyle.about /modify_do.bml.pagelayoutstyle.about
|
||||
/modify.bml.domainalias.head /modify_do.bml.domainalias.head
|
||||
/modify.bml.moodicons.opt.forcefriends.about /modify_do.bml.moodicons.opt.forcefriends.about
|
||||
/modify.bml.colortheme.head /modify_do.bml.colortheme.head
|
||||
/modify.bml.moodicons.preview /modify_do.bml.moodicons.preview
|
||||
/modify.bml.pagelayoutstyle.head /modify_do.bml.pagelayoutstyle.head
|
||||
/modify.bml.moodicons.about /modify_do.bml.moodicons.about
|
||||
/modify.bml.friends.about /modify_do.bml.friends.about
|
||||
/modify.bml.colortheme.area.head /modify_do.bml.colortheme.area.head
|
||||
/modify.bml.availablestyles.head /modify_do.bml.availablestyles.head
|
||||
/modify.bml.success.text /modify_do.bml.success.text
|
||||
/modify.bml.domainalias.about /modify_do.bml.domainalias.about
|
||||
/modify.bml.error.dupdomainalias /modify_do.bml.error.dupdomainalias
|
||||
/modify.bml.journaloptions.about /modify_do.bml.journaloptions.about
|
||||
/modify.bml.moodicons.select /modify_do.bml.moodicons.select
|
||||
/modify.bml.domainalias.domainname /modify_do.bml.domainalias.domainname
|
||||
/modify.bml.done.head /modify_do.bml.done.head
|
||||
/modify.bml.overrides.about /modify_do.bml.overrides.about
|
||||
/modify.bml.overrides.box.head /modify_do.bml.overrides.box.head
|
||||
/modify.bml.journaloptions.head /modify_do.bml.journaloptions.head
|
||||
/modify.bml.availablestyles.disabledstyles /modify_do.bml.availablestyles.disabledstyles
|
||||
/modify.bml.domainalias.helptext /modify_do.bml.domainalias.helptext
|
||||
/modify.bml.done.btn.savechanges /modify_do.bml.done.btn.savechanges
|
||||
|
||||
/friends/edit.bml.opt.delete /friends/edit_do.bml.opt.delete
|
||||
/friends/edit.bml.name /friends/edit_do.bml.name
|
||||
/friends/edit.bml.friend /friends/edit_do.bml.friend
|
||||
/friends/edit.bml.needmore /friends/edit_do.bml.needmore
|
||||
/friends/edit.bml.success.text /friends/edit_do.bml.success.text
|
||||
/friends/edit.bml.btn.toggle /friends/edit_do.bml.btn.toggle
|
||||
/friends/edit.bml.success.head /friends/edit_do.bml.success.head
|
||||
/friends/edit.bml.error.updating /friends/edit_do.bml.error.updating
|
||||
/friends/edit.bml.yourfriends.text /friends/edit_do.bml.yourfriends.text
|
||||
/friends/edit.bml.user /friends/edit_do.bml.user
|
||||
/friends/edit.bml.nofriends.head /friends/edit_do.bml.nofriends.head
|
||||
/friends/edit.bml.fellowfriends.head /friends/edit_do.bml.fellowfriends.head
|
||||
/friends/edit.bml.foreground /friends/edit_do.bml.foreground
|
||||
/friends/edit.bml.done.text /friends/edit_do.bml.done.text
|
||||
/friends/edit.bml.addfriends.text /friends/edit_do.bml.addfriends.text
|
||||
/friends/edit.bml.addfriends.head /friends/edit_do.bml.addfriends.head
|
||||
/friends/edit.bml.fellowfriends.text /friends/edit_do.bml.fellowfriends.text
|
||||
/friends/edit.bml.btn.save /friends/edit_do.bml.btn.save
|
||||
/friends/edit.bml.hover /friends/edit_do.bml.hover
|
||||
/friends/edit.bml.opt.addtolist /friends/edit_do.bml.opt.addtolist
|
||||
/friends/edit.bml.yourfriends.head /friends/edit_do.bml.yourfriends.head
|
||||
/friends/edit.bml.background /friends/edit_do.bml.background
|
||||
/friends/edit.bml.done.head /friends/edit_do.bml.done.head
|
||||
/friends/edit.bml.nofriends.text /friends/edit_do.bml.nofriends.text
|
||||
|
||||
.opt.bannedfrom /talkpost.bml.opt.bannedfrom
|
||||
.opt.loggedin /talkpost.bml.opt.loggedin
|
||||
.label.picturetouse2 /talkpost.bml.label.picturetouse2
|
||||
.noaccount /talkpost.bml.noaccount
|
||||
|
||||
/editjournal.bml.pickentry.head /editjournal_do.bml.pickentry.head
|
||||
/editjournal.bml.error.modify /editjournal_do.bml.error.modify
|
||||
/editjournal.bml.pickentry.text /editjournal_do.bml.pickentry.text
|
||||
/editjournal.bml.error.nofind /editjournal_do.bml.error.nofind
|
||||
/editjournal.bml.error.getting /editjournal_do.bml.error.getting
|
||||
758
local/bin/upgrading/texttool.pl
Executable file
758
local/bin/upgrading/texttool.pl
Executable file
@@ -0,0 +1,758 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
# This program deals with inserting/extracting text/language data
|
||||
# from the database.
|
||||
#
|
||||
|
||||
use strict;
|
||||
use Getopt::Long;
|
||||
|
||||
my $opt_help = 0;
|
||||
my $opt_local_lang;
|
||||
my $opt_extra;
|
||||
my $opt_only;
|
||||
my $opt_override;
|
||||
my $opt_verbose;
|
||||
my $opt_do;
|
||||
my @additems;
|
||||
exit 1 unless
|
||||
GetOptions(
|
||||
"help" => \$opt_help,
|
||||
"local-lang=s" => \$opt_local_lang,
|
||||
"extra=s" => \$opt_extra,
|
||||
"override|r" => \$opt_override,
|
||||
"verbose" => \$opt_verbose,
|
||||
"only=s" => \$opt_only,
|
||||
"do" => \$opt_do,
|
||||
"additems:s{,}" => \@additems,
|
||||
);
|
||||
|
||||
my $mode = shift @ARGV;
|
||||
|
||||
help() if $opt_help or not defined $mode;
|
||||
|
||||
sub help
|
||||
{
|
||||
die "Usage: texttool.pl <command> [options]
|
||||
|
||||
Where 'command' is one of:
|
||||
load Runs the following four commands in order:
|
||||
popstruct Populate lang data from text[-local].dat into db
|
||||
poptext Populate text from en.dat, etc into database.
|
||||
--extra=<file> specifies an alternative input file
|
||||
--override (-v) specifies existing values should be overwritten
|
||||
for all languages. (for developer use only)
|
||||
copyfaq If site is translating FAQ, copy FAQ data into trans area
|
||||
loadcrumbs Load crumbs from ljcrumbs.pl and ljcrumbs-local.pl.
|
||||
makeusable Setup internal indexes necessary after loading text
|
||||
dumptext Dump lang text based on text[-local].dat information
|
||||
check Check validity of text[-local].dat files
|
||||
wipedb Remove all language/text data from database, including crumbs.
|
||||
wipecrumbs Remove all crumbs from the database, leaving other text alone.
|
||||
newitems Search files in htdocs, cgi-bin, & bin and insert
|
||||
necessary text item codes in database
|
||||
remove takes two extra arguments: domain name and code, and removes
|
||||
that code and its text in all languages
|
||||
|
||||
Optional `options`:
|
||||
--help The page you're looking at
|
||||
--verbose More output
|
||||
--local-lang=.. If given, works on local site files too
|
||||
--do If given, lets newitems actually create items in database
|
||||
--additems Takes multiple parameters. If given specifies
|
||||
what exactly new items should be added.
|
||||
";
|
||||
}
|
||||
|
||||
## make sure $LJHOME is set so we can load & run everything
|
||||
unless (-d $ENV{'LJHOME'}) {
|
||||
die "LJHOME environment variable is not set, or is not a directory.\n".
|
||||
"You must fix this before you can run this database update script.";
|
||||
}
|
||||
require "$ENV{'LJHOME'}/cgi-bin/ljlib.pl";
|
||||
require "$ENV{'LJHOME'}/cgi-bin/ljlang.pl";
|
||||
require "$ENV{'LJHOME'}/cgi-bin/weblib.pl";
|
||||
|
||||
my %dom_id; # number -> {}
|
||||
my %dom_code; # name -> {}
|
||||
my %lang_id; # number -> {}
|
||||
my %lang_code; # name -> {}
|
||||
my @lang_domains;
|
||||
|
||||
my $set = sub {
|
||||
my ($hash, $key, $val, $errmsg) = @_;
|
||||
die "$errmsg$key\n" if exists $hash->{$key};
|
||||
$hash->{$key} = $val;
|
||||
};
|
||||
|
||||
foreach my $scope ("general", "local")
|
||||
{
|
||||
my $file = $scope eq "general" ? "text.dat" : "text-local.dat";
|
||||
my $ffile = "$ENV{'LJHOME'}/bin/upgrading/$file";
|
||||
unless (-e $ffile) {
|
||||
next if $scope eq "local";
|
||||
die "$file file not found; odd: did you delete it?\n";
|
||||
}
|
||||
open (F, $ffile) or die "Can't open file: $file: $!\n";
|
||||
while (<F>) {
|
||||
s/\s+$//; s/^\#.+//;
|
||||
next unless /\S/;
|
||||
my @vals = split(/:/, $_);
|
||||
my $what = shift @vals;
|
||||
|
||||
# language declaration
|
||||
if ($what eq "lang") {
|
||||
my $lang = {
|
||||
'scope' => $scope,
|
||||
'lnid' => $vals[0],
|
||||
'lncode' => $vals[1],
|
||||
'lnname' => $vals[2],
|
||||
'parentlnid' => 0, # default. changed later.
|
||||
'parenttype' => 'diff',
|
||||
};
|
||||
$lang->{'parenttype'} = $vals[3] if defined $vals[3];
|
||||
if (defined $vals[4]) {
|
||||
unless (exists $lang_code{$vals[4]}) {
|
||||
die "Can't declare language $lang->{'lncode'} with missing parent language $vals[4].\n";
|
||||
}
|
||||
$lang->{'parentlnid'} = $lang_code{$vals[4]}->{'lnid'};
|
||||
}
|
||||
$set->(\%lang_id, $lang->{'lnid'}, $lang, "Language already defined with ID: ");
|
||||
$set->(\%lang_code, $lang->{'lncode'}, $lang, "Language already defined with code: ");
|
||||
}
|
||||
|
||||
# domain declaration
|
||||
if ($what eq "domain") {
|
||||
my $dcode = $vals[1];
|
||||
my ($type, $args) = split(m!/!, $dcode);
|
||||
my $dom = {
|
||||
'scope' => $scope,
|
||||
'dmid' => $vals[0],
|
||||
'type' => $type,
|
||||
'args' => $args || "",
|
||||
};
|
||||
$set->(\%dom_id, $dom->{'dmid'}, $dom, "Domain already defined with ID: ");
|
||||
$set->(\%dom_code, $dcode, $dom, "Domain already defined with parameters: ");
|
||||
}
|
||||
|
||||
# langdomain declaration
|
||||
if ($what eq "langdomain") {
|
||||
my $ld = {
|
||||
'lnid' =>
|
||||
(exists $lang_code{$vals[0]} ? $lang_code{$vals[0]}->{'lnid'} :
|
||||
die "Undefined language: $vals[0]\n"),
|
||||
'dmid' =>
|
||||
(exists $dom_code{$vals[1]} ? $dom_code{$vals[1]}->{'dmid'} :
|
||||
die "Undefined domain: $vals[1]\n"),
|
||||
'dmmaster' => $vals[2] ? "1" : "0",
|
||||
};
|
||||
push @lang_domains, $ld;
|
||||
}
|
||||
}
|
||||
close F;
|
||||
}
|
||||
|
||||
if ($mode eq "check") {
|
||||
print "all good.\n";
|
||||
exit 0;
|
||||
}
|
||||
|
||||
## make sure we can connect
|
||||
my $dbh = LJ::get_dbh("master");
|
||||
my $sth;
|
||||
unless ($dbh) {
|
||||
die "Can't connect to the database.\n";
|
||||
}
|
||||
|
||||
# indenter
|
||||
my $idlev = 0;
|
||||
my $out = sub {
|
||||
my @args = @_;
|
||||
while (@args) {
|
||||
my $a = shift @args;
|
||||
if ($a eq "+") { $idlev++; }
|
||||
elsif ($a eq "-") { $idlev--; }
|
||||
elsif ($a eq "x") { $a = shift @args; die " "x$idlev . $a . "\n"; }
|
||||
else { print " "x$idlev, $a, "\n"; }
|
||||
}
|
||||
};
|
||||
|
||||
my @good = qw(load popstruct poptext dumptext newitems wipedb makeusable copyfaq remove
|
||||
wipecrumbs loadcrumbs);
|
||||
|
||||
popstruct() if $mode eq "popstruct" or $mode eq "load";
|
||||
poptext(@ARGV) if $mode eq "poptext" or $mode eq "load";
|
||||
copyfaq() if $mode eq "copyfaq" or $mode eq "load";
|
||||
loadcrumbs() if $mode eq "loadcrumbs" or $mode eq "load";
|
||||
makeusable() if $mode eq "makeusable" or $mode eq "load";
|
||||
dumptext(@ARGV) if $mode eq "dumptext";
|
||||
newitems() if $mode eq "newitems";
|
||||
wipedb() if $mode eq "wipedb";
|
||||
wipecrumbs() if $mode eq "wipecrumbs";
|
||||
remove(@ARGV) if $mode eq "remove" and scalar(@ARGV) == 2;
|
||||
help() unless grep { $mode eq $_ } @good;
|
||||
exit 0;
|
||||
|
||||
sub makeusable
|
||||
{
|
||||
$out->("Making usable...", '+');
|
||||
my $rec = sub {
|
||||
my ($lang, $rec) = @_;
|
||||
my $l = $lang_code{$lang};
|
||||
$out->("x", "Bogus language: $lang") unless $l;
|
||||
my @children = grep { $_->{'parentlnid'} == $l->{'lnid'} } values %lang_code;
|
||||
foreach my $cl (@children) {
|
||||
$out->("$l->{'lncode'} -- $cl->{'lncode'}");
|
||||
|
||||
my %need;
|
||||
# push downwards everything that has some valid text in some language (< 4)
|
||||
$sth = $dbh->prepare("SELECT dmid, itid, txtid FROM ml_latest WHERE lnid=$l->{'lnid'} AND staleness < 4");
|
||||
$sth->execute;
|
||||
while (my ($dmid, $itid, $txtid) = $sth->fetchrow_array) {
|
||||
$need{"$dmid:$itid"} = $txtid;
|
||||
}
|
||||
$sth = $dbh->prepare("SELECT dmid, itid, txtid FROM ml_latest WHERE lnid=$cl->{'lnid'}");
|
||||
$sth->execute;
|
||||
while (my ($dmid, $itid, $txtid) = $sth->fetchrow_array) {
|
||||
delete $need{"$dmid:$itid"};
|
||||
}
|
||||
while (my $k = each %need) {
|
||||
my ($dmid, $itid) = split(/:/, $k);
|
||||
my $txtid = $need{$k};
|
||||
my $stale = $cl->{'parenttype'} eq "diff" ? 3 : 0;
|
||||
$dbh->do("INSERT INTO ml_latest (lnid, dmid, itid, txtid, chgtime, staleness) VALUES ".
|
||||
"($cl->{'lnid'}, $dmid, $itid, $txtid, NOW(), $stale)");
|
||||
die $dbh->errstr if $dbh->err;
|
||||
}
|
||||
$rec->($cl->{'lncode'}, $rec);
|
||||
}
|
||||
};
|
||||
$rec->("en", $rec);
|
||||
$out->("-", "done.");
|
||||
}
|
||||
|
||||
sub copyfaq
|
||||
{
|
||||
my $faqd = LJ::Lang::get_dom("faq");
|
||||
my $ll = LJ::Lang::get_root_lang($faqd);
|
||||
unless ($ll) { return; }
|
||||
|
||||
my $domid = $faqd->{'dmid'};
|
||||
|
||||
$out->("Copying FAQ...", '+');
|
||||
|
||||
my %existing;
|
||||
$sth = $dbh->prepare("SELECT i.itcode FROM ml_items i, ml_latest l ".
|
||||
"WHERE l.lnid=$ll->{'lnid'} AND l.dmid=$domid AND l.itid=i.itid AND i.dmid=$domid");
|
||||
$sth->execute;
|
||||
$existing{$_} = 1 while $_ = $sth->fetchrow_array;
|
||||
|
||||
# faq category
|
||||
$sth = $dbh->prepare("SELECT faqcat, faqcatname FROM faqcat");
|
||||
$sth->execute;
|
||||
while (my ($cat, $name) = $sth->fetchrow_array) {
|
||||
next if exists $existing{"cat.$cat"};
|
||||
my $opts = { 'childrenlatest' => 1 };
|
||||
LJ::Lang::set_text($dbh, $domid, $ll->{'lncode'}, "cat.$cat", $name, $opts);
|
||||
}
|
||||
|
||||
# faq items
|
||||
$sth = $dbh->prepare("SELECT faqid, question, answer FROM faq");
|
||||
$sth->execute;
|
||||
while (my ($faqid, $q, $a) = $sth->fetchrow_array) {
|
||||
next if
|
||||
exists $existing{"$faqid.1question"} and
|
||||
exists $existing{"$faqid.2answer"};
|
||||
my $opts = { 'childrenlatest' => 1 };
|
||||
LJ::Lang::set_text($dbh, $domid, $ll->{'lncode'}, "$faqid.1question", $q, $opts);
|
||||
LJ::Lang::set_text($dbh, $domid, $ll->{'lncode'}, "$faqid.2answer", $a, $opts);
|
||||
}
|
||||
|
||||
$out->('-', "done.");
|
||||
}
|
||||
|
||||
sub wipedb
|
||||
{
|
||||
$out->("Wiping DB...", '+');
|
||||
foreach (qw(domains items langdomains langs latest text)) {
|
||||
$out->("deleting from $_");
|
||||
$dbh->do("DELETE FROM ml_$_");
|
||||
}
|
||||
$out->("-", "done.");
|
||||
}
|
||||
|
||||
sub wipecrumbs
|
||||
{
|
||||
$out->('Wiping DB of all crumbs...', '+');
|
||||
|
||||
# step 1: get all items that are crumbs. [from ml_items]
|
||||
my $genid = $dom_code{'general'}->{'dmid'};
|
||||
my @crumbs;
|
||||
my $sth = $dbh->prepare("SELECT itcode FROM ml_items
|
||||
WHERE dmid = $genid AND itcode LIKE 'crumb.\%'");
|
||||
$sth->execute;
|
||||
while (my ($itcode) = $sth->fetchrow_array) {
|
||||
# push onto list
|
||||
push @crumbs, $itcode;
|
||||
}
|
||||
|
||||
# step 2: remove the items that have these unique dmid/itids
|
||||
foreach my $code (@crumbs) {
|
||||
$out->("deleting $code");
|
||||
remove("general", $code);
|
||||
}
|
||||
|
||||
# done
|
||||
$out->('-', 'done.');
|
||||
}
|
||||
|
||||
sub loadcrumbs
|
||||
{
|
||||
$out->('Loading all crumbs into DB...', '+');
|
||||
|
||||
# get domain id of 'general' and language id of 'en'
|
||||
my $genid = $dom_code{'general'}->{'dmid'};
|
||||
my $loclang = $LJ::LANGS[0] || 'en';
|
||||
|
||||
# list of crumbs
|
||||
my @crumbs;
|
||||
foreach (keys %LJ::CRUMBS_LOCAL) { push @crumbs, $_; }
|
||||
foreach (keys %LJ::CRUMBS) { push @crumbs, $_; }
|
||||
|
||||
# begin iterating, order doesn't matter...
|
||||
foreach my $crumbkey (@crumbs) {
|
||||
$out->("inserting crumb.$crumbkey");
|
||||
my $crumb = LJ::get_crumb($crumbkey);
|
||||
my $local = $LJ::CRUMBS_LOCAL{$crumbkey} ? 1 : 0;
|
||||
|
||||
# see if it exists
|
||||
my $itid = $dbh->selectrow_array("SELECT itid FROM ml_items
|
||||
WHERE dmid = $genid AND itcode = 'crumb.$crumbkey'")+0;
|
||||
LJ::Lang::set_text($genid, $local ? $loclang : 'en', "crumb.$crumbkey", $crumb->[0])
|
||||
unless $itid;
|
||||
}
|
||||
|
||||
# done
|
||||
$out->('-', 'done.');
|
||||
}
|
||||
|
||||
sub popstruct
|
||||
{
|
||||
$out->("Populating structure...", '+');
|
||||
foreach my $l (values %lang_id) {
|
||||
$out->("Inserting language: $l->{'lnname'}");
|
||||
$dbh->do("INSERT INTO ml_langs (lnid, lncode, lnname, parenttype, parentlnid) ".
|
||||
"VALUES (" . join(",", map { $dbh->quote($l->{$_}) } qw(lnid lncode lnname parenttype parentlnid)) . ")");
|
||||
}
|
||||
|
||||
foreach my $d (values %dom_id) {
|
||||
$out->("Inserting domain: $d->{'type'}\[$d->{'args'}\]");
|
||||
$dbh->do("INSERT INTO ml_domains (dmid, type, args) ".
|
||||
"VALUES (" . join(",", map { $dbh->quote($d->{$_}) } qw(dmid type args)) . ")");
|
||||
}
|
||||
|
||||
$out->("Inserting language domains ...");
|
||||
foreach my $ld (@lang_domains) {
|
||||
$dbh->do("INSERT IGNORE INTO ml_langdomains (lnid, dmid, dmmaster) VALUES ".
|
||||
"(" . join(",", map { $dbh->quote($ld->{$_}) } qw(lnid dmid dmmaster)) . ")");
|
||||
}
|
||||
$out->("-", "done.");
|
||||
}
|
||||
|
||||
sub poptext
|
||||
{
|
||||
my @langs = @_;
|
||||
push @langs, (keys %lang_code) unless @langs;
|
||||
|
||||
$out->("Populating text...", '+');
|
||||
my %source; # lang -> file, or "[extra]" when given by --extra= argument
|
||||
if ($opt_extra) {
|
||||
$source{'[extra]'} = $opt_extra;
|
||||
} else {
|
||||
foreach my $lang (@langs) {
|
||||
my $file = "$ENV{'LJHOME'}/bin/upgrading/${lang}.dat";
|
||||
next if $opt_only && $lang ne $opt_only;
|
||||
next unless -e $file;
|
||||
$source{$lang} = $file;
|
||||
}
|
||||
}
|
||||
|
||||
my %existing_item; # langid -> code -> 1
|
||||
|
||||
foreach my $source (keys %source)
|
||||
{
|
||||
$out->("$source", '+');
|
||||
my $file = $source{$source};
|
||||
open (D, $file)
|
||||
or $out->('x', "Can't open $source data file");
|
||||
|
||||
# fixed language in *.dat files, but in extra files
|
||||
# it switches as it goes.
|
||||
my $l;
|
||||
if ($source ne "[extra]") { $l = $lang_code{$source}; }
|
||||
|
||||
my $bml_prefix = "";
|
||||
|
||||
my $addcount = 0;
|
||||
my $lnum = 0;
|
||||
my ($code, $text);
|
||||
my %metadata;
|
||||
while (my $line = <D>) {
|
||||
$lnum++;
|
||||
my $del;
|
||||
my $action_line;
|
||||
|
||||
if ($line =~ /^==(LANG|BML):\s*(\S+)/) {
|
||||
$out->('x', "Bogus directives in non-extra file.")
|
||||
if $source ne "[extra]";
|
||||
my ($what, $val) = ($1, $2);
|
||||
if ($what eq "LANG") {
|
||||
$l = $lang_code{$val};
|
||||
$out->('x', 'Bogus ==LANG switch to: $what') unless $l;
|
||||
$bml_prefix = "";
|
||||
} elsif ($what eq "BML") {
|
||||
$out->('x', 'Bogus ==BML switch to: $what')
|
||||
unless $val =~ m!^/.+\.bml$!;
|
||||
$bml_prefix = $val;
|
||||
}
|
||||
} elsif ($line =~ /^(\S+?)=(.*)/) {
|
||||
($code, $text) = ($1, $2);
|
||||
$action_line = 1;
|
||||
} elsif ($line =~ /^\!\s*(\S+)/) {
|
||||
$del = $code;
|
||||
$action_line = 1;
|
||||
} elsif ($line =~ /^(\S+?)\<\<\s*$/) {
|
||||
($code, $text) = ($1, "");
|
||||
while (<D>) {
|
||||
$lnum++;
|
||||
last if $_ eq ".\n";
|
||||
s/^\.//;
|
||||
$text .= $_;
|
||||
}
|
||||
chomp $text; # remove file new-line (we added it)
|
||||
$action_line = 1;
|
||||
} elsif ($line =~ /^[\#\;]/) {
|
||||
# comment line
|
||||
next;
|
||||
} elsif ($line =~ /\S/) {
|
||||
$out->('x', "$source:$lnum: Bogus format.");
|
||||
}
|
||||
|
||||
if ($code =~ m!^\.!) {
|
||||
$out->('x', "Can't use code with leading dot: $code")
|
||||
unless $bml_prefix;
|
||||
$code = "$bml_prefix$code";
|
||||
}
|
||||
|
||||
if ($code =~ /\|(.+)/) {
|
||||
$metadata{$1} = $text;
|
||||
next;
|
||||
}
|
||||
|
||||
next unless $action_line;
|
||||
|
||||
$out->('x', 'No language defined!') unless $l;
|
||||
|
||||
# load existing items for target language
|
||||
unless (exists $existing_item{$l->{'lnid'}}) {
|
||||
$existing_item{$l->{'lnid'}} = {};
|
||||
my $sth = $dbh->prepare(qq{
|
||||
SELECT i.itcode
|
||||
FROM ml_latest l, ml_items i
|
||||
WHERE i.dmid=1 AND l.dmid=1 AND i.itid=l.itid AND l.lnid=$l->{'lnid'}
|
||||
});
|
||||
$sth->execute;
|
||||
$existing_item{$l->{'lnid'}}->{$_} = 1
|
||||
while $_ = $sth->fetchrow_array;
|
||||
}
|
||||
|
||||
# do deletes
|
||||
if (defined $del) {
|
||||
remove("general", $del)
|
||||
if delete $existing_item{$l->{'lnid'}}->{$del};
|
||||
next;
|
||||
}
|
||||
|
||||
# if override is set (development option) then delete
|
||||
if ($opt_override && $existing_item{$l->{'lnid'}}->{$code}) {
|
||||
remove("general", $code);
|
||||
delete $existing_item{$l->{'lnid'}}->{$code};
|
||||
}
|
||||
|
||||
unless ($existing_item{$l->{'lnid'}}->{$code}) {
|
||||
$addcount++;
|
||||
my $staleness = $metadata{'staleness'}+0;
|
||||
my $res = LJ::Lang::set_text($dbh, 1, $l->{'lncode'}, $code, $text,
|
||||
{ 'staleness' => $staleness,
|
||||
'notes' => $metadata{'notes'}, });
|
||||
$out->("set: $code") if $opt_verbose;
|
||||
unless ($res) {
|
||||
$out->('x', "ERROR: " . LJ::Lang::last_error());
|
||||
}
|
||||
}
|
||||
%metadata = ();
|
||||
}
|
||||
close D;
|
||||
$out->("added: $addcount", '-');
|
||||
}
|
||||
$out->("-", "done.");
|
||||
|
||||
# dead phrase removal
|
||||
$out->("Removing dead phrases...", '+');
|
||||
foreach my $file ("deadphrases.dat", "deadphrases-local.dat") {
|
||||
my $ffile = "$ENV{'LJHOME'}/bin/upgrading/$file";
|
||||
next unless -s $ffile;
|
||||
$out->("File: $file");
|
||||
open (DP, $ffile) or die;
|
||||
while (my $li = <DP>) {
|
||||
$li =~ s/\#.*//;
|
||||
next unless $li =~ /\S/;
|
||||
$li =~ s/\s+$//;
|
||||
my ($dom, $it) = split(/\s+/, $li);
|
||||
next unless exists $dom_code{$dom};
|
||||
my $dmid = $dom_code{$dom}->{'dmid'};
|
||||
|
||||
my @items;
|
||||
if ($it =~ s/\*$/\%/) {
|
||||
my $sth = $dbh->prepare("SELECT itcode FROM ml_items WHERE dmid=? AND itcode LIKE ?");
|
||||
$sth->execute($dmid, $it);
|
||||
push @items, $_ while $_ = $sth->fetchrow_array;
|
||||
} else {
|
||||
@items = ($it);
|
||||
}
|
||||
foreach (@items) {
|
||||
remove($dom, $_, 1);
|
||||
}
|
||||
}
|
||||
close DP;
|
||||
}
|
||||
$out->('-', "Done.");
|
||||
}
|
||||
|
||||
sub dumptext
|
||||
{
|
||||
my @langs = @_;
|
||||
unless (@langs) { @langs = keys %lang_code; }
|
||||
|
||||
$out->('Dumping text...', '+');
|
||||
foreach my $lang (@langs)
|
||||
{
|
||||
$out->("$lang");
|
||||
my $l = $lang_code{$lang};
|
||||
open (D, ">$ENV{'LJHOME'}/bin/upgrading/${lang}.dat")
|
||||
or $out->('x', "Can't open $lang.dat");
|
||||
print D ";; -*- coding: utf-8 -*-\n";
|
||||
my $sth = $dbh->prepare("SELECT i.itcode, t.text, l.staleness, i.notes FROM ".
|
||||
"ml_items i, ml_latest l, ml_text t ".
|
||||
"WHERE l.lnid=$l->{'lnid'} AND l.dmid=1 ".
|
||||
"AND i.dmid=1 AND l.itid=i.itid AND ".
|
||||
"t.dmid=1 AND t.txtid=l.txtid AND ".
|
||||
# only export mappings that aren't inherited:
|
||||
"t.lnid=$l->{'lnid'} ".
|
||||
"ORDER BY i.itcode");
|
||||
$sth->execute;
|
||||
die $dbh->errstr if $dbh->err;
|
||||
my $writeline = sub {
|
||||
my ($k, $v) = @_;
|
||||
if ($v =~ /\n/) {
|
||||
$v =~ s/\n\./\n\.\./g;
|
||||
print D "$k<<\n$v\n.\n";
|
||||
} else {
|
||||
print D "$k=$v\n";
|
||||
}
|
||||
};
|
||||
while (my ($itcode, $text, $staleness, $notes) = $sth->fetchrow_array) {
|
||||
$writeline->("$itcode|staleness", $staleness)
|
||||
if $staleness;
|
||||
$writeline->("$itcode|notes", $notes)
|
||||
if $notes =~ /\S/;
|
||||
$writeline->($itcode, $text);
|
||||
print D "\n";
|
||||
}
|
||||
close D;
|
||||
}
|
||||
$out->('-', 'done.');
|
||||
}
|
||||
|
||||
sub newitems
|
||||
{
|
||||
$out->("Searching for referenced text codes...", '+');
|
||||
my $top = $ENV{'LJHOME'};
|
||||
|
||||
my %overrides;
|
||||
if (open (O, "$top/bin/upgrading/texttool-overrides")) {
|
||||
while (<O>) {
|
||||
my $l = $_;
|
||||
if ($l !~ /^#/ && $l !~ /^[\s]*$/) {
|
||||
$l =~ s/[\r\n]//;
|
||||
my @a = split ,$l;
|
||||
$overrides{$a[0]} = $a[1];
|
||||
}
|
||||
}
|
||||
close O;
|
||||
}
|
||||
|
||||
my @files;
|
||||
push @files, qw(htdocs cgi-bin bin);
|
||||
my %items; # $scope -> $key -> 1;
|
||||
while (@files)
|
||||
{
|
||||
my $file = shift @files;
|
||||
my $ffile = "$top/$file";
|
||||
next unless -e $ffile;
|
||||
if (-d $ffile) {
|
||||
$out->("dir: $file") if $opt_verbose;
|
||||
opendir (MD, $ffile) or die "Can't open $file";
|
||||
while (my $f = readdir(MD)) {
|
||||
next if $f eq "." || $f eq ".." ||
|
||||
$f =~ /^\.\#/ || $f =~ /(\.png|\.gif|~|\#)$/;
|
||||
unshift @files, "$file/$f";
|
||||
}
|
||||
closedir MD;
|
||||
}
|
||||
if (-f $ffile) {
|
||||
my $scope = "general";
|
||||
# $scope = "general" if -e "$top/cvs/livejournal/$file";
|
||||
|
||||
open (F, $ffile) or die "Can't open $file";
|
||||
my $line = 0;
|
||||
|
||||
my $correct_code = sub {
|
||||
my ($code, $file) = @_;
|
||||
|
||||
if ($code =~ /^\./ && $file =~ m!^htdocs/!) {
|
||||
$code = "$file$code";
|
||||
$code =~ s!^htdocs!!;
|
||||
}
|
||||
if ($overrides{$code}) {
|
||||
$code = $overrides{$code};
|
||||
}
|
||||
return $code;
|
||||
};
|
||||
my $valid_code = sub {
|
||||
my ($code, $file) = @_;
|
||||
|
||||
if ($code =~ /\$/ || $file eq "bin/upgrading/texttool.pl") {
|
||||
print STDERR "SKIPPING: $file [$code]\n";
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
};
|
||||
|
||||
while (<F>) {
|
||||
$line++;
|
||||
|
||||
if (/^#/) {
|
||||
next;
|
||||
}
|
||||
|
||||
while (/BML::ml\([\"\'](.+?)[\"\']/g) {
|
||||
my $code = $1;
|
||||
$code = $correct_code->($code, $file);
|
||||
$out->("BML::ml: $file $code") if $opt_verbose;
|
||||
$items{$scope}->{$code} = 1 if $valid_code->($code, $file);
|
||||
}
|
||||
while (/\(=_ML\s+(.+?)\s+_ML=\)/g) {
|
||||
my $code = $1;
|
||||
$code = $correct_code->($code, $file);
|
||||
$out->("_ML: $code") if $opt_verbose;
|
||||
$items{$scope}->{$code} = 1 if $valid_code->($code, $file);
|
||||
}
|
||||
while (/\$ML{'(.+?)'}/g) {
|
||||
my $code = $1;
|
||||
$code = $correct_code->($code, $file);
|
||||
$out->("\$ML: $file $code") if $opt_verbose;
|
||||
$items{$scope}->{$code} = 1 if $valid_code->($code, $file);
|
||||
}
|
||||
}
|
||||
close F;
|
||||
}
|
||||
}
|
||||
|
||||
$out->(sprintf("%d general and %d local found.",
|
||||
scalar keys %{$items{'general'}},
|
||||
scalar keys %{$items{'local'}}));
|
||||
|
||||
# [ General ]
|
||||
my %e_general; # code -> 1
|
||||
$out->("Checking which general items already exist in database...");
|
||||
my $sth = $dbh->prepare("SELECT i.itcode FROM ml_items i, ml_latest l WHERE ".
|
||||
"l.dmid=1 AND l.lnid=1 AND i.dmid=1 AND i.itid=l.itid ");
|
||||
$sth->execute;
|
||||
while (my $it = $sth->fetchrow_array) { $e_general{$it} = 1; }
|
||||
$out->(sprintf("%d found", scalar keys %e_general));
|
||||
foreach my $it (keys %{$items{'general'}}) {
|
||||
next if exists $e_general{$it};
|
||||
|
||||
if (@additems && grep(/^$it$/, @additems)) {
|
||||
if ($opt_do) {
|
||||
my $res = LJ::Lang::set_text($dbh, 1, "en", $it, undef, { 'staleness' => 4 });
|
||||
$out->("Adding general: $it ... $res");
|
||||
}
|
||||
else {
|
||||
$out->("Would add general: $it");
|
||||
}
|
||||
}
|
||||
else {
|
||||
$out->("Skipped: $it");
|
||||
}
|
||||
}
|
||||
|
||||
if ($opt_local_lang) {
|
||||
my $ll = $lang_code{$opt_local_lang};
|
||||
die "Bogus --local-lang argument\n" unless $ll;
|
||||
die "Local-lang '$ll->{'lncode'}' parent isn't 'en'\n"
|
||||
unless $ll->{'parentlnid'} == 1;
|
||||
$out->("Checking which local items already exist in database...");
|
||||
|
||||
my %e_local;
|
||||
$sth = $dbh->prepare("SELECT i.itcode FROM ml_items i, ml_latest l WHERE ".
|
||||
"l.dmid=1 AND l.lnid=$ll->{'lnid'} AND i.dmid=1 AND i.itid=l.itid ");
|
||||
$sth->execute;
|
||||
while (my $it = $sth->fetchrow_array) { $e_local{$it} = 1; }
|
||||
$out->(sprintf("%d found\n", scalar keys %e_local));
|
||||
foreach my $it (keys %{$items{'local'}}) {
|
||||
next if exists $e_general{$it};
|
||||
next if exists $e_local{$it};
|
||||
my $res = LJ::Lang::set_text($dbh, 1, $ll->{'lncode'}, $it, undef, { 'staleness' => 4 });
|
||||
$out->("Adding local: $it ... $res");
|
||||
}
|
||||
}
|
||||
$out->('-', 'done.');
|
||||
}
|
||||
|
||||
sub remove {
|
||||
my ($dmcode, $itcode, $no_error) = @_;
|
||||
my $dmid;
|
||||
if (exists $dom_code{$dmcode}) {
|
||||
$dmid = $dom_code{$dmcode}->{'dmid'};
|
||||
} else {
|
||||
$out->("x", "Unknown domain code $dmcode.");
|
||||
}
|
||||
|
||||
my $qcode = $dbh->quote($itcode);
|
||||
my $itid = $dbh->selectrow_array("SELECT itid FROM ml_items WHERE dmid=$dmid AND itcode=$qcode");
|
||||
return if $no_error && !$itid;
|
||||
$out->("x", "Unknown item code $itcode.") unless $itid;
|
||||
|
||||
$out->("Removing item $itcode from domain $dmcode ($itid)...", "+");
|
||||
|
||||
# need to delete everything from: ml_items ml_latest ml_text
|
||||
|
||||
$dbh->do("DELETE FROM ml_items WHERE dmid=$dmid AND itid=$itid");
|
||||
|
||||
my $txtids = "";
|
||||
my $sth = $dbh->prepare("SELECT txtid FROM ml_latest WHERE dmid=$dmid AND itid=$itid");
|
||||
$sth->execute;
|
||||
while (my $txtid = $sth->fetchrow_array) {
|
||||
$txtids .= "," if $txtids;
|
||||
$txtids .= $txtid;
|
||||
}
|
||||
$dbh->do("DELETE FROM ml_latest WHERE dmid=$dmid AND itid=$itid");
|
||||
$dbh->do("DELETE FROM ml_text WHERE dmid=$dmid AND txtid IN ($txtids)");
|
||||
|
||||
$out->("-","done.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
15252
local/bin/upgrading/uk.dat
Normal file
15252
local/bin/upgrading/uk.dat
Normal file
File diff suppressed because it is too large
Load Diff
2587
local/bin/upgrading/update-db-general.pl
Executable file
2587
local/bin/upgrading/update-db-general.pl
Executable file
File diff suppressed because it is too large
Load Diff
2068
local/cgi-bin/Apache/BML.pm
Executable file
2068
local/cgi-bin/Apache/BML.pm
Executable file
File diff suppressed because it is too large
Load Diff
1618
local/cgi-bin/Apache/LiveJournal.pm
Executable file
1618
local/cgi-bin/Apache/LiveJournal.pm
Executable file
File diff suppressed because it is too large
Load Diff
152
local/cgi-bin/CSS/Cleaner.pm
Normal file
152
local/cgi-bin/CSS/Cleaner.pm
Normal file
@@ -0,0 +1,152 @@
|
||||
#
|
||||
# Note: this is a very early version of a CSS cleaner. The plan is to eventually
|
||||
# make it a white-listing CSS cleaner (deny by default) with a nice
|
||||
# interface where you can build policy about what's allowed, like
|
||||
# HTML::Sanitize/::Scrub/etc, but for now this is almost a null cleaner,
|
||||
# just parsing and reserializing the CSS, removing two trivial ways to
|
||||
# inject javascript.
|
||||
#
|
||||
# The plan now is to integrate this interface into LiveJournal, then improve
|
||||
# this module over time.
|
||||
#
|
||||
# Note2: we tried 4 different CSS parsers for this module to use, and all 4 sucked.
|
||||
# so for now this module sucks, until we can find a suitable parser. for the
|
||||
# record, CSS::Tiny, CSS, and CSS::SAC all didn't work. and csstidy wasn't
|
||||
# incredibly hot either. CSS.pm's grammar was buggy, and CSS::SAC had the
|
||||
# best interface (SAC) but terrible parsing of selectors. we'll probably
|
||||
# have to write our own, based on the Mozilla CSS parsing code.
|
||||
|
||||
|
||||
package CSS::Cleaner;
|
||||
use strict;
|
||||
use vars qw($VERSION);
|
||||
$VERSION = '0.01';
|
||||
|
||||
sub new {
|
||||
my $class = shift;
|
||||
my %opts = @_;
|
||||
|
||||
my $self = bless {}, $class;
|
||||
|
||||
if (defined( $opts{rule_handler} )) {
|
||||
my $rule_handler = $opts{rule_handler};
|
||||
die "rule_handler needs to be a coderef if supplied" unless ref( $rule_handler ) eq 'CODE';
|
||||
$self->{rule_handler} = $rule_handler;
|
||||
}
|
||||
|
||||
if (defined( $opts{pre_hook} )) {
|
||||
my $pre_hook = $opts{pre_hook};
|
||||
die "pre_hook needs to be a coderef if supplied" unless ref( $pre_hook ) eq 'CODE';
|
||||
$self->{pre_hook} = $pre_hook;
|
||||
}
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
# cleans CSS
|
||||
sub clean {
|
||||
my ($self, $target) = @_;
|
||||
$self->_stupid_clean(\$target);
|
||||
return $target;
|
||||
}
|
||||
|
||||
# cleans CSS properties, as if it were in a style="" attribute
|
||||
sub clean_property {
|
||||
my ($self, $target) = @_;
|
||||
$self->_stupid_clean(\$target);
|
||||
return $target;
|
||||
}
|
||||
|
||||
# this is so stupid. see notes at top.
|
||||
# returns 1 if it was okay, 0 if possibly malicious
|
||||
sub _stupid_clean {
|
||||
my ($self, $ref) = @_;
|
||||
|
||||
my $reduced = $$ref;
|
||||
if (defined( $self->{pre_hook} )) {
|
||||
$self->{pre_hook}->( \$reduced );
|
||||
}
|
||||
|
||||
$reduced =~ s/&\#(\d+);?/chr($1)/eg;
|
||||
$reduced =~ s/&\#x(\w+);?/chr(hex($1))/eg;
|
||||
|
||||
if ($reduced =~ /[\x00-\x08\x0B\x0C\x0E-\x1F]/) {
|
||||
$$ref = "/* suspect CSS: low bytes */";
|
||||
return;
|
||||
}
|
||||
|
||||
if ($reduced =~ /[\x7f-\xff]/) {
|
||||
$$ref = "/* suspect CSS: high bytes */";
|
||||
return;
|
||||
}
|
||||
|
||||
# returns 1 if something bad was found
|
||||
my $check_for_bad = sub {
|
||||
if ($reduced =~ m!<\w!) {
|
||||
$$ref = "/* suspect CSS: start HTML tag? */";
|
||||
return 1;
|
||||
}
|
||||
|
||||
my $with_white = $reduced;
|
||||
$reduced =~ s/[\s\x0b]+//g;
|
||||
|
||||
if ($reduced =~ m!\\[a-f0-9]!i) {
|
||||
$$ref = "/* suspect CSS: backslash hex */";
|
||||
return;
|
||||
}
|
||||
|
||||
$reduced =~ s/\\//g;
|
||||
|
||||
if ($reduced =~ /\@(import|charset)([\s\x0A\x0D]*[^\x0A\x0D]*)/i) {
|
||||
my $what = $1;
|
||||
my $value = $2;
|
||||
if (defined( $self->{rule_handler} )) {
|
||||
return $self->{rule_handler}->( $ref, $what, $value );
|
||||
} else {
|
||||
$$ref = "/* suspect CSS: $what rule */";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ($reduced =~ /&\#/) {
|
||||
$$ref = "/* suspect CSS: found irregular &# */";
|
||||
return;
|
||||
}
|
||||
|
||||
if ($reduced =~ m!</!) {
|
||||
$$ref = "/* suspect CSS: close HTML tag */";
|
||||
return;
|
||||
}
|
||||
|
||||
# returns 1 if bad phrases found
|
||||
my $check_phrases = sub {
|
||||
my $str = shift;
|
||||
if ($$str =~ m/(\bdata:\b|javascript|jscript|livescript|vbscript|expression|eval|cookie
|
||||
|\bwindow\b|\bparent\b|\bthis\b|behaviou?r|moz-binding)/ix) {
|
||||
my $what = lc $1;
|
||||
$$ref = "/* suspect CSS: potential scripting: $what */";
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
return 1 if $check_phrases->(\$reduced);
|
||||
|
||||
# restore whitespace
|
||||
$reduced = $with_white;
|
||||
$reduced =~ s!/\*.*?\*/!!sg;
|
||||
$reduced =~ s!\<\!--.*?--\>!!sg;
|
||||
$reduced =~ s/[\s\x0b]+//g;
|
||||
$reduced =~ s/\\//g;
|
||||
return 1 if $check_phrases->(\$reduced);
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
# check for bad stuff before/after removing comment lines
|
||||
return 0 if $check_for_bad->();
|
||||
$reduced =~ s!//.*!!g;
|
||||
return 0 if $check_for_bad->();
|
||||
return 1;
|
||||
}
|
||||
|
||||
1;
|
||||
1164
local/cgi-bin/Cache/Memcached.pm
Executable file
1164
local/cgi-bin/Cache/Memcached.pm
Executable file
File diff suppressed because it is too large
Load Diff
94
local/cgi-bin/Golem.pm
Normal file
94
local/cgi-bin/Golem.pm
Normal file
@@ -0,0 +1,94 @@
|
||||
#!/usr/bin/perl -w
|
||||
|
||||
package Golem;
|
||||
|
||||
use strict;
|
||||
|
||||
require "$ENV{'LJHOME'}/cgi-bin/Golem/dblib.pl";
|
||||
require "$ENV{'LJHOME'}/cgi-bin/Golem/loglib.pl";
|
||||
require "$ENV{'LJHOME'}/cgi-bin/Golem/netlib.pl";
|
||||
require "$ENV{'LJHOME'}/cgi-bin/Golem/proplib.pl";
|
||||
require "$ENV{'LJHOME'}/cgi-bin/Golem/textlib.pl";
|
||||
|
||||
# *** LJR apis conversion layer
|
||||
#
|
||||
# check out
|
||||
|
||||
our $on = 1;
|
||||
our $counter_prefix = "golem_";
|
||||
|
||||
sub get_db {
|
||||
return LJ::get_db_writer();
|
||||
}
|
||||
|
||||
# Golem tags are not ported to LJR
|
||||
sub unset_row_tag {
|
||||
return 1;
|
||||
}
|
||||
# *** LJR apis conversion layer
|
||||
|
||||
sub get_callstack {
|
||||
my $cstack;
|
||||
my $i = 0;
|
||||
while ( 1 ) {
|
||||
my $tfunc = (caller($i))[3];
|
||||
if ($tfunc && $tfunc ne "") {
|
||||
if ($tfunc !~ /\_\_ANON\_\_/ &&
|
||||
$tfunc !~ /.*::get_callstack/) {
|
||||
$cstack .= "\t" . $tfunc . "\n";
|
||||
}
|
||||
$i = $i + 1;
|
||||
}
|
||||
else {
|
||||
last;
|
||||
}
|
||||
}
|
||||
return "\nCallstack:\n" . $cstack . "\n";
|
||||
}
|
||||
|
||||
sub err {
|
||||
if (ref($_[0])) {
|
||||
my $dbh = shift;
|
||||
$dbh->rollback;
|
||||
}
|
||||
|
||||
my $errstr = shift || "";
|
||||
my $previous_object;
|
||||
|
||||
if (ref($_[0]) eq 'HASH') {
|
||||
$previous_object = shift;
|
||||
}
|
||||
|
||||
if ($previous_object) {
|
||||
$previous_object->{'err'} = 1;
|
||||
$previous_object->{'errstr'} = $errstr . Golem::get_callstack();
|
||||
|
||||
return $previous_object;
|
||||
}
|
||||
else {
|
||||
my %res = (
|
||||
"err" => 1,
|
||||
"errstr" => $errstr . Golem::get_callstack(),
|
||||
);
|
||||
|
||||
return \%res;
|
||||
}
|
||||
}
|
||||
|
||||
sub die {
|
||||
my ($message, $suppress_callstack) = @_;
|
||||
|
||||
print STDERR "$message";
|
||||
|
||||
unless ($suppress_callstack) {
|
||||
print STDERR Golem::get_callstack();
|
||||
}
|
||||
else {
|
||||
print "\n";
|
||||
}
|
||||
|
||||
exit 1;
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
746
local/cgi-bin/Golem/dblib.pl
Normal file
746
local/cgi-bin/Golem/dblib.pl
Normal file
@@ -0,0 +1,746 @@
|
||||
#!/usr/bin/perl -w
|
||||
#
|
||||
# Generic database routines
|
||||
#
|
||||
|
||||
|
||||
package Golem;
|
||||
use strict;
|
||||
|
||||
use Golem;
|
||||
|
||||
# courtesy of LiveJournal.org
|
||||
sub disconnect_dbs {
|
||||
foreach my $h (($Golem::DB, $Golem::PlanerDB, $Golem::CalendarDB, $Golem::OtrsDB, $Golem::SwerrsDB)) {
|
||||
if ($h) {
|
||||
$h->disconnect();
|
||||
$h = undef;
|
||||
}
|
||||
}
|
||||
|
||||
print STDERR localtime() . " [$$]: closed db connections\n" if $ENV{'GOLEM_DEBUG'};
|
||||
}
|
||||
|
||||
# build DSN connection string based on database info hashref,
|
||||
# courtesy of livejournal.org
|
||||
#
|
||||
# $DBINFO = {
|
||||
# 'master' => {
|
||||
# 'dbname' => "golem_kohts",
|
||||
# 'host' => "localhost",
|
||||
# 'port' => 3306,
|
||||
# 'user' => "root",
|
||||
# 'pass' => "",
|
||||
# 'sock' => "",
|
||||
# 'encoding' => "utf8",
|
||||
# },
|
||||
# };
|
||||
#
|
||||
sub make_dbh_fdsn {
|
||||
my ($db) = @_;
|
||||
|
||||
my $fdsn = "DBI:mysql";
|
||||
$fdsn .= ":$db->{'dbname'}";
|
||||
$fdsn .= ";host=$db->{'host'}" if $db->{'host'};
|
||||
$fdsn .= ";port=$db->{'port'}" if $db->{'port'};
|
||||
$fdsn .= ";mysql_socket=$db->{'sock'}" if $db->{'sock'};
|
||||
$fdsn .= "|$db->{'user'}|$db->{'pass'}";
|
||||
|
||||
return $fdsn;
|
||||
}
|
||||
|
||||
# test if connection is still available
|
||||
# (should check for replication, etc. here)
|
||||
#
|
||||
sub connection_bad {
|
||||
my ($dbh, $try) = @_;
|
||||
|
||||
return 1 unless $dbh;
|
||||
|
||||
my $ss = eval {
|
||||
#
|
||||
# $dbh->selectrow_hashref("SHOW SLAVE STATUS");
|
||||
#
|
||||
# on a real slave
|
||||
#
|
||||
# $ss = {
|
||||
# 'Skip_counter' => '0',
|
||||
# 'Master_Log_File' => 'ararita-bin.882',
|
||||
# 'Connect_retry' => '60',
|
||||
# 'Master_Host' => 'ararita.lenin.ru',
|
||||
# 'Relay_Master_Log_File' => 'ararita-bin.882',
|
||||
# 'Relay_Log_File' => 'laylah-relay-bin.323',
|
||||
# 'Slave_IO_Running' => 'Yes',
|
||||
# 'Slave_SQL_Running' => 'Yes',
|
||||
# 'Master_Port' => '3306',
|
||||
# 'Exec_master_log_pos' => '17720151',
|
||||
# 'Relay_log_space' => '19098333',
|
||||
# 'Relay_Log_Pos' => '19098333',
|
||||
# 'Last_errno' => '0',
|
||||
# 'Last_error' => '',
|
||||
# 'Replicate_do_db' => 'prod_livejournal,prod_livejournal',
|
||||
# 'Read_Master_Log_Pos' => '17720151',
|
||||
# 'Master_User' => 'replication',
|
||||
# 'Replicate_ignore_db' => ''
|
||||
# };
|
||||
|
||||
$dbh->selectrow_hashref("select name from _dbi");
|
||||
};
|
||||
|
||||
if ($dbh->err && $dbh->err != 1227) {
|
||||
print STDERR localtime() . " [$$]: " . $dbh->errstr . "\n" if $ENV{'GOLEM_DEBUG'};
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ($ss && $ss->{'name'} ne '??') {
|
||||
return 0;
|
||||
}
|
||||
elsif ($ss && $ss->{'name'} eq '??') {
|
||||
print STDERR localtime() . " [$$]: DBI returned garbage: $ss->{'name'}\n" if $ENV{'GOLEM_DEBUG'};
|
||||
return 1;
|
||||
}
|
||||
elsif (!$ss) {
|
||||
print STDERR localtime() . " [$$]: DBI returned nothing\n" if $ENV{'GOLEM_DEBUG'};
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
# LJR modification; redefined in cgi-bin/Golem.pmGolem.pm
|
||||
# so it works correctly with original LJ code
|
||||
#
|
||||
sub golem_get_db {
|
||||
my ($params, $opts) = @_;
|
||||
|
||||
$opts = {} unless $opts;
|
||||
$params = {} unless $params;
|
||||
|
||||
if ($Golem::DB) {
|
||||
if (! connection_bad($Golem::DB)) {
|
||||
return $Golem::DB;
|
||||
}
|
||||
else {
|
||||
print STDERR localtime() . " [$$]: new connection: was bad\n" if $ENV{'GOLEM_DEBUG'};
|
||||
$Golem::DB->disconnect;
|
||||
}
|
||||
}
|
||||
else {
|
||||
print STDERR localtime() . " [$$]: new connection: had none\n" if $ENV{'GOLEM_DEBUG'};
|
||||
}
|
||||
undef $Golem::DB;
|
||||
|
||||
# DB connection defaults (unless programmer specified them)
|
||||
#
|
||||
$params->{'RaiseError'} = 0 unless defined($params->{'RaiseError'});
|
||||
$params->{'PrintError'} = 1 unless defined($params->{'PrintError'});
|
||||
$params->{'AutoCommit'} = 1 unless defined($params->{'AutoCommit'});
|
||||
|
||||
Golem::die("No Golem::DBINFO master defined")
|
||||
unless $Golem::DBINFO->{'master'};
|
||||
|
||||
my $dbinfo = $Golem::DBINFO->{'master'};
|
||||
my $fdsn = make_dbh_fdsn($dbinfo);
|
||||
|
||||
$Golem::DB = DBI->connect($fdsn, $dbinfo->{'user'}, $dbinfo->{'pass'}, $params);
|
||||
while (!$Golem::DB && $opts->{'retry_forever'}) {
|
||||
Golem::do_log("database not available, retrying", {"stderr" => 1});
|
||||
sleep 1;
|
||||
$Golem::DB = DBI->connect($fdsn, $dbinfo->{'user'}, $dbinfo->{'pass'}, $params);
|
||||
}
|
||||
Golem::die("Unable to connect to database: " . DBI->errstr)
|
||||
unless $Golem::DB;
|
||||
|
||||
$Golem::DB->do("SET NAMES " . $dbinfo->{'encoding'})
|
||||
if $dbinfo->{'encoding'};
|
||||
|
||||
if (connection_bad($Golem::DB)) {
|
||||
print STDERR "got fresh new bad handle, retrying\n" if $ENV{'GOLEM_DEBUG'};
|
||||
$Golem::DB = undef;
|
||||
$Golem::DB = Golem::get_db();
|
||||
}
|
||||
|
||||
$Golem::default_dc_obj = Golem::get_dc($Golem::default_dc);
|
||||
return $Golem::DB;
|
||||
}
|
||||
|
||||
sub get_planer_db {
|
||||
my ($params) = @_;
|
||||
|
||||
return $Golem::PlanerDB if $Golem::PlanerDB;
|
||||
|
||||
$params = {RaiseError => 0, PrintError => 1, AutoCommit => 1}
|
||||
unless $params;
|
||||
|
||||
$Golem::PlanerDB = DBI->connect("DBI:Sybase:server=argo3.yandex.ru;database=planer;",
|
||||
"helpdesk", "gkfyshfcnfvfys123", $params);
|
||||
|
||||
return $Golem::PlanerDB;
|
||||
}
|
||||
|
||||
sub get_calendar_db {
|
||||
my ($params) = @_;
|
||||
|
||||
return $Golem::CalendarDB if $Golem::CalendarDB;
|
||||
|
||||
$params = {RaiseError => 0, PrintError =>1, AutoCommit => 1}
|
||||
unless $params;
|
||||
|
||||
$Golem::CalendarDB = DBI->connect("DBI:Sybase:server=argo3.yandex.ru;database=momdb;",
|
||||
"staffreader", "cegthgfhjkm678", $params);
|
||||
|
||||
return $Golem::CalendarDB;
|
||||
}
|
||||
|
||||
sub get_otrs_db {
|
||||
my ($params) = @_;
|
||||
|
||||
return $Golem::OtrsDB if $Golem::OtrsDB;
|
||||
|
||||
$params = {RaiseError => 0, PrintError =>1, AutoCommit => 1}
|
||||
unless $params;
|
||||
|
||||
$Golem::OtrsDB = DBI->connect("DBI:mysql:database=otrs_utf8:host=casa.yandex.ru:port=3306",
|
||||
"userorder", "xuo9Bahf", $params);
|
||||
|
||||
return $Golem::OtrsDB;
|
||||
}
|
||||
|
||||
sub get_swerrs_db {
|
||||
my ($params) = @_;
|
||||
|
||||
return $Golem::SwerrsDB if $Golem::SwerrsDB;
|
||||
|
||||
$params = { RaiseError => 0, PrintError => 1, AutoCommit => 1 }
|
||||
unless $params;
|
||||
|
||||
$Golem::SwerrsDB = DBI->connect("DBI:mysql:racktables:localhost:3306", "swerrs", "V7Hl}O]Usr", $params);
|
||||
|
||||
return $Golem::SwerrsDB;
|
||||
}
|
||||
|
||||
|
||||
sub sth_bind_array {
|
||||
my ($sth, $bound_values) = @_;
|
||||
|
||||
my $i = 0;
|
||||
foreach my $b (@{$bound_values}) {
|
||||
$i++;
|
||||
|
||||
Golem::die("error binding params")
|
||||
unless $sth->bind_param($i, $b) ;
|
||||
}
|
||||
}
|
||||
|
||||
# courtesy of LiveJournal.org
|
||||
# see also: http://dev.mysql.com/doc/refman/5.0/en/information-functions.html#function_last-insert-id
|
||||
#
|
||||
sub alloc_global_counter {
|
||||
my ($tag, $recurse) = @_;
|
||||
|
||||
my $dbh = Golem::get_db();
|
||||
my $newmax;
|
||||
|
||||
# in case name `counter` is already occupied
|
||||
# by some user table
|
||||
my $counter_prefix = "";
|
||||
$counter_prefix = $Golem::counter_prefix
|
||||
if defined($Golem::counter_prefix);
|
||||
|
||||
my $rs = $dbh->do("UPDATE ${counter_prefix}counter SET max=LAST_INSERT_ID(max+1) WHERE tag=?", undef, $tag);
|
||||
if ($rs > 0) {
|
||||
$newmax = $dbh->selectrow_array("SELECT LAST_INSERT_ID()");
|
||||
return $newmax;
|
||||
}
|
||||
|
||||
return undef if $recurse;
|
||||
|
||||
# no prior counter rows - initialize one.
|
||||
|
||||
# if this is a table then trying default id column
|
||||
if ($Golem::SCHEMA_CACHE->{'tables'}->{$tag}) {
|
||||
$newmax = $dbh->selectrow_array("SELECT MAX(id) FROM `$tag`");
|
||||
}
|
||||
else {
|
||||
Golem::die("alloc_global_counter: unknown tag [$tag], unable to get max value.");
|
||||
}
|
||||
|
||||
$newmax += 0;
|
||||
|
||||
$dbh->do("INSERT IGNORE INTO ${counter_prefix}counter (tag, max) VALUES (?,?)",
|
||||
undef, $tag, $newmax) || return undef;
|
||||
|
||||
return Golem::alloc_global_counter($tag, 1);
|
||||
}
|
||||
|
||||
# get schema table definition,
|
||||
# prepare in-memory table structure
|
||||
#
|
||||
sub get_schema_table {
|
||||
my ($table_name, $opts) = @_;
|
||||
|
||||
return $Golem::SCHEMA_CACHE->{'tables'}->{$table_name}
|
||||
if $Golem::SCHEMA_CACHE->{'tables'}->{$table_name} &&
|
||||
!$opts->{'force'};
|
||||
|
||||
delete($Golem::SCHEMA_CACHE->{'tables'}->{$table_name})
|
||||
if $Golem::SCHEMA_CACHE->{'tables'}->{$table_name};
|
||||
|
||||
$Golem::SCHEMA_CACHE->{'tables'}->{$table_name}->{'fields'} = {};
|
||||
my $t = $Golem::SCHEMA_CACHE->{'tables'}->{$table_name};
|
||||
|
||||
my $dbh = Golem::get_db();
|
||||
Golem::debug_sql("describe `$table_name`");
|
||||
my $sth = $dbh->prepare("describe `$table_name`");
|
||||
$sth->execute();
|
||||
Golem::die("Error describing table [$table_name]: " . $dbh->errstr)
|
||||
if $dbh->err;
|
||||
|
||||
my $select_all_sql = "";
|
||||
while (my $r = $sth->fetchrow_hashref) {
|
||||
my $field_name = $r->{'Field'};
|
||||
|
||||
$t->{'fields'}->{$field_name} = $r;
|
||||
|
||||
if ($r->{'Type'} =~ /^enum\((.+)\)/o) {
|
||||
my $enums = $1;
|
||||
foreach my $etype (split(/,/o, $enums)) {
|
||||
$etype =~ s/'//go;
|
||||
$t->{'fields'}->{$field_name}->{'enum'}->{$etype} = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ($r->{'Type'} eq 'timestamp') {
|
||||
$select_all_sql .= "UNIX_TIMESTAMP(`$field_name`) as `$field_name`, ";
|
||||
}
|
||||
else {
|
||||
$select_all_sql .= "`$field_name`, ";
|
||||
}
|
||||
|
||||
if ($r->{'Key'} eq 'PRI') {
|
||||
$t->{'primary_key'}->{$field_name} = 1;
|
||||
}
|
||||
}
|
||||
chop($select_all_sql);
|
||||
chop($select_all_sql);
|
||||
|
||||
$Golem::SCHEMA_CACHE->{'tables'}->{$table_name}->{'select_all_sql'} = $select_all_sql;
|
||||
|
||||
return $Golem::SCHEMA_CACHE->{'tables'}->{$table_name};
|
||||
}
|
||||
|
||||
# function tells whether field is data field or some special field
|
||||
# like host.id (incremented with alloc_global_counter) or
|
||||
# like host.last_updated (automatically updated when record is updated)
|
||||
# maybe we should filter them by name instead of using db structure hints?
|
||||
sub is_data_field {
|
||||
my ($table_name, $field_name, $opts) = @_;
|
||||
|
||||
$opts = {} unless $opts;
|
||||
|
||||
my $table = Golem::get_schema_table($table_name);
|
||||
my $table_fields = $table->{'fields'};
|
||||
|
||||
if ($table_fields->{$field_name}) {
|
||||
if ($table_fields->{$field_name}->{'Default'} &&
|
||||
$table_fields->{$field_name}->{'Default'} eq 'CURRENT_TIMESTAMP' &&
|
||||
!$opts->{'ignore_default_current_timestamp'} ) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
# if ($table_fields->{$field_name}->{'Key'} &&
|
||||
# $table_fields->{$field_name}->{'Key'} eq 'PRI') {
|
||||
#
|
||||
# return 0;
|
||||
# }
|
||||
|
||||
# we have to distinguish between host.id and host_rackmap.host;
|
||||
# both are PRIMARY keys, but
|
||||
# 1) we shouldn't ever update host.id
|
||||
# 2) we have to update host_rackmap.host with host.id
|
||||
# when creating record corresponding to host record
|
||||
if ($field_name eq "id" && !$opts->{'manual_id_management'}) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
sub __insert {
|
||||
my ($table_name, $record_hashref, $opts) = @_;
|
||||
|
||||
Golem::die("Severe programmer error: __insert expects table name as first parameter!")
|
||||
unless $table_name;
|
||||
Golem::die("Severe programmer error: __insert expects record hashref as second parameter!")
|
||||
unless ref($record_hashref) eq 'HASH';
|
||||
|
||||
$opts = {} unless ref($opts) eq 'HASH';
|
||||
|
||||
my $dbh;
|
||||
if ($opts->{'dbh'}) {
|
||||
$dbh = $opts->{'dbh'};
|
||||
}
|
||||
else {
|
||||
$dbh = Golem::get_db();
|
||||
}
|
||||
|
||||
$dbh->{'PrintError'} = $opts->{'PrintError'}
|
||||
if defined($opts->{'PrintError'});
|
||||
|
||||
my $sth;
|
||||
|
||||
my $table = Golem::get_schema_table($table_name);
|
||||
my $table_fields = $table->{'fields'};
|
||||
|
||||
# continue only if there's data for the table
|
||||
# or if there's a flag saying we should create
|
||||
# empty record with defaults
|
||||
my $have_data_for_the_table = 0;
|
||||
while (my ($o, $v) = each(%{$record_hashref})) {
|
||||
if (Golem::is_data_field($table_name, $o, $opts)) {
|
||||
$have_data_for_the_table = 1;
|
||||
}
|
||||
}
|
||||
unless ($have_data_for_the_table || $opts->{'create_empty_record'}) {
|
||||
return $dbh;
|
||||
}
|
||||
|
||||
my @record_fields;
|
||||
my @record_values;
|
||||
|
||||
foreach my $o (keys %{$record_hashref}) {
|
||||
# $record_hashref might contain more fields than present in database.
|
||||
# we only choose those which are in db
|
||||
|
||||
if ($table_fields->{$o} && Golem::is_data_field($table_name, $o, $opts)) {
|
||||
|
||||
# enum validation
|
||||
if ($table_fields->{$o}->{'enum'}) {
|
||||
Golem::die("Enum [$table_name.$o] value is not specified and doesn't have default value")
|
||||
if !defined($record_hashref->{$o}) && $table_fields->{$o}->{'Default'} eq '';
|
||||
|
||||
Golem::die("Enum [$table_name.$o] can't be [$record_hashref->{$o}]")
|
||||
if $record_hashref->{$o} && !$table_fields->{$o}->{'enum'}->{$record_hashref->{$o}};
|
||||
|
||||
# if they passed empty value for enum
|
||||
# and there's some default -- silently
|
||||
# decide to use it
|
||||
unless ($record_hashref->{$o}) {
|
||||
delete($record_hashref->{$o});
|
||||
next;
|
||||
}
|
||||
}
|
||||
|
||||
push @record_fields, $o;
|
||||
push @record_values, $record_hashref->{$o};
|
||||
}
|
||||
}
|
||||
|
||||
if ($table_fields->{"id"} && !$opts->{'manual_id_management'}) {
|
||||
if ($record_hashref->{"id"}) {
|
||||
Golem::die("Severe database structure or programmer error: __insert got id [$record_hashref->{'id'}]
|
||||
when creating record for table [$table_name]; won't overwrite.\n");
|
||||
}
|
||||
|
||||
$record_hashref->{"id"} = Golem::alloc_global_counter($table_name);
|
||||
|
||||
# check that id is not taken and
|
||||
# die with severe error otherwise
|
||||
#
|
||||
|
||||
my $t_id = $dbh->selectrow_array("select id from `$table_name` where id = ?",
|
||||
undef, $record_hashref->{"id"});
|
||||
if ($t_id && $t_id eq $record_hashref->{"id"}) {
|
||||
Golem::die("Severe database error: __insert got [$t_id] for table [$table_name] " .
|
||||
"from alloc_global_counter which already exists!\n" .
|
||||
"Probable somebody is populating [$table_name] without Golem::__insert()\n");
|
||||
}
|
||||
|
||||
push @record_fields, "id";
|
||||
push @record_values, $record_hashref->{"id"};
|
||||
}
|
||||
|
||||
my $sql;
|
||||
my @bound_values;
|
||||
|
||||
$sql = "INSERT INTO `$table_name` ( ";
|
||||
foreach my $o (@record_fields) {
|
||||
$sql = $sql . " `$o`,";
|
||||
}
|
||||
chop($sql);
|
||||
|
||||
$sql .= " ) VALUES ( ";
|
||||
|
||||
my $i = 0;
|
||||
foreach my $o (@record_values) {
|
||||
|
||||
# we represent timestamp datatype as unixtime (http://en.wikipedia.org/wiki/Unix_time)
|
||||
# doing all the conversions almost invisible to the end user
|
||||
#
|
||||
# if the value being written is 0 then we're not using FROM_UNIXTIME(value)
|
||||
# (which generates warnings) just value
|
||||
#
|
||||
if ($table_fields->{$record_fields[$i]}->{'Type'} eq 'timestamp' && $o && $o != 0) {
|
||||
Golem::die("Programmer error: __insert got hashref with invalid data for $table_name.$record_fields[$i] (should be unixtime)")
|
||||
unless $o =~ /^[0-9]+$/o;
|
||||
|
||||
$sql = $sql . "FROM_UNIXTIME(?),";
|
||||
}
|
||||
else {
|
||||
$sql = $sql . "?,";
|
||||
}
|
||||
|
||||
push @bound_values, $o;
|
||||
$i++;
|
||||
}
|
||||
chop($sql);
|
||||
$sql .= " )";
|
||||
|
||||
Golem::debug_sql($sql, \@bound_values);
|
||||
|
||||
$sth = $dbh->prepare($sql);
|
||||
Golem::sth_bind_array($sth, \@bound_values);
|
||||
$sth->execute();
|
||||
|
||||
if ($dbh->err && $dbh->{'PrintError'}) {
|
||||
Golem::do_log("got error [" . $dbh->err . "] [" . $dbh->errstr . "]" .
|
||||
" while executing [$sql] with values (" . join(",", @bound_values) . ")",
|
||||
{'stderr' => 1});
|
||||
}
|
||||
|
||||
return $dbh;
|
||||
}
|
||||
|
||||
sub __update {
|
||||
my ($table_name, $record_hashref, $opts) = @_;
|
||||
|
||||
Golem::die("Severe programmer error: __update expects table name as first parameter!")
|
||||
unless $table_name;
|
||||
Golem::die("Severe programmer error: __update expects record hashref as second parameter!")
|
||||
unless ref($record_hashref) eq 'HASH';
|
||||
|
||||
$opts = {} unless ref($opts) eq 'HASH';
|
||||
|
||||
my $dbh;
|
||||
if ($opts->{'dbh'}) {
|
||||
$dbh = $opts->{'dbh'};
|
||||
}
|
||||
else {
|
||||
$dbh = Golem::get_db();
|
||||
}
|
||||
|
||||
my $sth;
|
||||
|
||||
my $table = Golem::get_schema_table($table_name);
|
||||
my $table_fields = $table->{'fields'};
|
||||
my $unique_fields_arrayref = [keys %{$table->{'primary_key'}}];
|
||||
|
||||
if ($opts->{'unique_fields'}) {
|
||||
$unique_fields_arrayref = $opts->{'unique_fields'};
|
||||
}
|
||||
|
||||
# continue only if there's data for the table
|
||||
# in the in-memory hash or if there's a flag
|
||||
# saying we should create empty record with defaults
|
||||
#
|
||||
my $have_data_for_the_table = 0;
|
||||
while (my ($o, $v) = each(%{$record_hashref})) {
|
||||
if (Golem::is_data_field($table_name, $o)) {
|
||||
my $is_unique = 0;
|
||||
|
||||
foreach my $u (@{$unique_fields_arrayref}) {
|
||||
if ($u eq $o) {
|
||||
$is_unique = 1;
|
||||
}
|
||||
}
|
||||
next if $is_unique;
|
||||
|
||||
$have_data_for_the_table = 1;
|
||||
}
|
||||
}
|
||||
unless ($have_data_for_the_table || $opts->{'create_empty_record'}) {
|
||||
return $dbh;
|
||||
}
|
||||
|
||||
my $sql;
|
||||
my @bound_values;
|
||||
|
||||
$sql = "SELECT " . $table->{'select_all_sql'} . " from `$table_name` WHERE ";
|
||||
foreach my $f (@{$unique_fields_arrayref}) {
|
||||
if ($table_fields->{$f}->{'Type'} eq 'timestamp' && $record_hashref->{$f} != 0) {
|
||||
Golem::die("Programmer error: __update got hashref with invalid data for $table_name.$f (should be unixtime)")
|
||||
unless $record_hashref->{$f} =~ /^[0-9]+$/o;
|
||||
|
||||
$sql .= " `$f` = FROM_UNIXTIME(?) and ";
|
||||
}
|
||||
else {
|
||||
$sql .= " `$f` = ? and ";
|
||||
}
|
||||
push @bound_values, $record_hashref->{$f};
|
||||
}
|
||||
# remove last "and "
|
||||
chop($sql);
|
||||
chop($sql);
|
||||
chop($sql);
|
||||
chop($sql);
|
||||
|
||||
$sth = $dbh->prepare($sql);
|
||||
Golem::sth_bind_array($sth, \@bound_values);
|
||||
$sth->execute();
|
||||
|
||||
# create record if it doesn't exist: useful when updating
|
||||
# records in dependent tables (hosts_resps, hosts_netmap, host_rackmap)
|
||||
# when master table exists.
|
||||
unless ($sth->rows) {
|
||||
if ($opts->{"create_nonexistent"}) {
|
||||
$dbh = Golem::__insert($table_name, $record_hashref, $opts);
|
||||
return $dbh;
|
||||
}
|
||||
else {
|
||||
Golem::die("Programmer error: requested to update non-existent record with no create_nonexistent option");
|
||||
}
|
||||
}
|
||||
|
||||
my $existing_row;
|
||||
while(my $r = $sth->fetchrow_hashref()) {
|
||||
Golem::debug_sql($sql, \@bound_values);
|
||||
Golem::die("more than 1 record fetched with should-be-unique lookup")
|
||||
if $existing_row;
|
||||
|
||||
$existing_row = $r;
|
||||
}
|
||||
|
||||
# check that existing record differs somehow from record to be written
|
||||
my $records_differ = 0;
|
||||
while (my ($k, $v) = each %{$existing_row}) {
|
||||
if (Golem::is_data_field($table_name, $k)) {
|
||||
|
||||
# what a mess!
|
||||
utf8::decode($record_hashref->{$k});
|
||||
utf8::decode($v);
|
||||
|
||||
if (
|
||||
($record_hashref->{$k} && $v && $v ne $record_hashref->{$k}) ||
|
||||
(! $record_hashref->{$k} && $v) ||
|
||||
($record_hashref->{$k} && ! $v)
|
||||
) {
|
||||
|
||||
Golem::debug_sql("in-memory [$table_name] object field [$k] differs: [" .
|
||||
($record_hashref->{$k} ? $record_hashref->{$k} : "") . "
|
||||
] -- [" .
|
||||
($v ? $v : "") .
|
||||
"]");
|
||||
|
||||
$records_differ = 1;
|
||||
last;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# don't update database if that wouldn't actually
|
||||
# change any data; we should save A LOT of time here
|
||||
#
|
||||
return $dbh unless $records_differ;
|
||||
|
||||
@bound_values = ();
|
||||
$sql = "";
|
||||
while (my ($o, $v) = each(%{$record_hashref})) {
|
||||
# $record_hashref might contain more fields than present in database.
|
||||
# we only choose those which are in db
|
||||
if ($table_fields->{$o} && Golem::is_data_field($table_name, $o)) {
|
||||
if ($table_fields->{$o}->{'Type'} eq 'timestamp' && $record_hashref->{$o} && $record_hashref->{$o} != 0) {
|
||||
Golem::die("Programmer error: __update got hashref with invalid data for $table_name.$o (should be unixtime)")
|
||||
unless $record_hashref->{$o} =~ /^[0-9]+$/o;
|
||||
|
||||
$sql = $sql . " `$o` = FROM_UNIXTIME(?),";
|
||||
}
|
||||
else {
|
||||
$sql = $sql . " `$o` = ?,";
|
||||
}
|
||||
push @bound_values, $record_hashref->{$o};
|
||||
}
|
||||
}
|
||||
chop($sql);
|
||||
|
||||
$sql = "UPDATE `$table_name` SET " . $sql . " WHERE ";
|
||||
foreach my $f (@{$unique_fields_arrayref}) {
|
||||
$sql .= " `$f` = ? and ";
|
||||
push @bound_values, $record_hashref->{$f};
|
||||
}
|
||||
# remove last "and "
|
||||
chop($sql);
|
||||
chop($sql);
|
||||
chop($sql);
|
||||
chop($sql);
|
||||
|
||||
Golem::debug_sql($sql, \@bound_values);
|
||||
|
||||
$sth = $dbh->prepare($sql);
|
||||
Golem::sth_bind_array($sth, \@bound_values);
|
||||
$sth->execute();
|
||||
|
||||
if ($dbh->err) {
|
||||
Golem::do_log("error executing: $sql; bound values: " . join(",", @bound_values), {"stderr" => 1});
|
||||
}
|
||||
|
||||
return $dbh;
|
||||
}
|
||||
|
||||
|
||||
sub __delete {
|
||||
my ($table_name, $record_hashref, $opts) = @_;
|
||||
|
||||
Golem::die("Severe programmer error: __delete expects table name as first parameter!")
|
||||
unless $table_name;
|
||||
Golem::die("Severe programmer error: __delete expects record hashref as second parameter!")
|
||||
unless ref($record_hashref) eq 'HASH';
|
||||
|
||||
$opts = {} unless ref($opts) eq 'HASH';
|
||||
|
||||
my $dbh;
|
||||
if ($opts->{'dbh'}) {
|
||||
$dbh = $opts->{'dbh'};
|
||||
}
|
||||
else {
|
||||
$dbh = Golem::get_db();
|
||||
}
|
||||
|
||||
my $sth;
|
||||
|
||||
my $table = Golem::get_schema_table($table_name);
|
||||
my $table_fields = $table->{'fields'};
|
||||
my $unique_fields_arrayref = [keys %{$table->{'primary_key'}}];
|
||||
|
||||
if ($opts->{'unique_fields'}) {
|
||||
$unique_fields_arrayref = $opts->{'unique_fields'};
|
||||
}
|
||||
|
||||
my @bound_values = ();
|
||||
my $sql = "DELETE FROM `$table_name` WHERE ";
|
||||
|
||||
foreach my $f (@{$unique_fields_arrayref}) {
|
||||
$sql .= " `$f` = ? and ";
|
||||
push @bound_values, $record_hashref->{$f};
|
||||
}
|
||||
# remove last "and "
|
||||
chop($sql);
|
||||
chop($sql);
|
||||
chop($sql);
|
||||
chop($sql);
|
||||
|
||||
$sth = $dbh->prepare($sql);
|
||||
Golem::sth_bind_array($sth, \@bound_values);
|
||||
$sth->execute();
|
||||
|
||||
if ($dbh->err) {
|
||||
Golem::do_log("error executing: $sql; bound values: " . join(",", @bound_values), {"stderr" => 1});
|
||||
}
|
||||
|
||||
return $dbh;
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
197
local/cgi-bin/Golem/loglib.pl
Normal file
197
local/cgi-bin/Golem/loglib.pl
Normal file
@@ -0,0 +1,197 @@
|
||||
#!/usr/bin/perl -w
|
||||
#
|
||||
# Logging related routines
|
||||
#
|
||||
|
||||
|
||||
package Golem;
|
||||
use strict;
|
||||
|
||||
use Golem;
|
||||
use Data::Dumper;
|
||||
|
||||
|
||||
sub dumper {
|
||||
my ($v) = @_;
|
||||
|
||||
return Dumper($v);
|
||||
}
|
||||
|
||||
sub debug_sql {
|
||||
my ($text, $bound_values, $opts) = @_;
|
||||
|
||||
if ($Golem::debug_sql) {
|
||||
$opts = {} unless $opts;
|
||||
|
||||
$text = "SQL: [" . ($text ? $text : "") . "]";
|
||||
|
||||
if ($bound_values && ref($bound_values) eq 'ARRAY') {
|
||||
$text .= " bound_values [" . Golem::safe_join(",", @{$bound_values}) . "]";
|
||||
}
|
||||
|
||||
if ($opts->{'stderr'}) {
|
||||
print STDERR localtime() . " " . $text . "\n";
|
||||
}
|
||||
else {
|
||||
print localtime() . " " . $text . "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub debug2 {
|
||||
my ($text, $opts) = @_;
|
||||
|
||||
if ($Golem::debug2) {
|
||||
debug($text, $opts);
|
||||
}
|
||||
}
|
||||
|
||||
sub debug {
|
||||
my ($text, $opts) = @_;
|
||||
|
||||
$opts = {} unless $opts;
|
||||
|
||||
if ($Golem::debug) {
|
||||
my $stamp = localtime() . ": ";
|
||||
|
||||
utf8::encode($text) if utf8::is_utf8($text);
|
||||
|
||||
if ($opts->{'stderr'}) {
|
||||
if (ref($text)) {
|
||||
print STDERR join("", map { "$stamp$_\n" } Dumper($text));
|
||||
}
|
||||
else {
|
||||
print STDERR $stamp . ($text ? $text : "") . "\n";
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (ref($text)) {
|
||||
print join("", map { "$stamp$_\n" } Dumper($text));
|
||||
}
|
||||
else {
|
||||
print $stamp . ($text ? $text : "") . "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# safe_open and safe_close are copied
|
||||
# from ps_farm.pm (should be one library actually)
|
||||
sub safe_open {
|
||||
my ($filename, $mode, $timeout) = @_;
|
||||
|
||||
$timeout = 30 unless $timeout;
|
||||
$mode = "open" unless $mode;
|
||||
|
||||
if ($mode eq "overwrite" || $mode eq ">") {
|
||||
$mode = ">";
|
||||
}
|
||||
elsif ($mode eq "append" || $mode eq ">>") {
|
||||
$mode = ">>";
|
||||
}
|
||||
else {
|
||||
$mode = "";
|
||||
}
|
||||
|
||||
my $fh;
|
||||
my $i=0;
|
||||
while (! open($fh, "${mode}${filename}")) {
|
||||
if ($i > $timeout) {
|
||||
print STDERR "Unable to open $filename\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
print STDERR "still trying to open $filename\n";
|
||||
$i = $i + 1;
|
||||
sleep 1;
|
||||
}
|
||||
|
||||
while (! flock($fh, 2)) {
|
||||
if ($i > $timeout) {
|
||||
print STDERR "Unable to lock $filename\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
print STDERR "still trying to lock $filename\n";
|
||||
$i = $i + 1;
|
||||
sleep 1;
|
||||
}
|
||||
|
||||
my $fh1;
|
||||
if (!open($fh1, "${mode}${filename}")) {
|
||||
$i = $i + 1;
|
||||
|
||||
if ($i > $timeout) {
|
||||
print STDERR "Unable to open and lock $filename\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
print STDERR "Locked $filename, but it's gone. Retrying...\n";
|
||||
return safe_open($filename, $mode, $timeout - 1);
|
||||
}
|
||||
else {
|
||||
close($fh1);
|
||||
return $fh;
|
||||
}
|
||||
}
|
||||
|
||||
sub safe_close {
|
||||
my ($fh) = @_;
|
||||
return flock($fh, 8) && close($fh);
|
||||
}
|
||||
|
||||
sub do_log {
|
||||
my ($message, $opts) = @_;
|
||||
|
||||
my $module;
|
||||
my $stderr = 0;
|
||||
|
||||
if (ref($opts) eq 'HASH') {
|
||||
if ($opts->{'module'}) {
|
||||
$module = "[$opts->{'module'}] ";
|
||||
}
|
||||
if ($opts->{'stderr'}) {
|
||||
$stderr = $opts->{'stderr'};
|
||||
}
|
||||
}
|
||||
else {
|
||||
$module = $opts;
|
||||
$module = "[$module] " if $module;
|
||||
}
|
||||
|
||||
$message = "" unless $message;
|
||||
|
||||
utf8::encode($message) if utf8::is_utf8($message);
|
||||
|
||||
$module = "[" . $0 . "] " unless $module;
|
||||
|
||||
my $message_eol = chop($message);
|
||||
|
||||
my $message_formatted =
|
||||
localtime() . " " . $module .
|
||||
$message .
|
||||
$message_eol .
|
||||
($message_eol eq "\n" ? "" : "\n");
|
||||
|
||||
if ($stderr) {
|
||||
print STDERR $message_formatted;
|
||||
}
|
||||
elsif ($Golem::debug) {
|
||||
print $message_formatted;
|
||||
}
|
||||
|
||||
if (defined($Golem::LOG)) {
|
||||
my $fh = safe_open($Golem::LOG, ">>");
|
||||
Golem::die ("Unable to open $Golem::LOG\n") unless $fh;
|
||||
# binmode($fh, ":utf8");
|
||||
print $fh $message_formatted;
|
||||
safe_close($fh);
|
||||
}
|
||||
else {
|
||||
print STDERR "No Golem::LOG is configured. Logging to STDERR\n";
|
||||
print STDERR $message_formatted;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
330
local/cgi-bin/Golem/netlib.pl
Normal file
330
local/cgi-bin/Golem/netlib.pl
Normal file
@@ -0,0 +1,330 @@
|
||||
#!/usr/bin/perl -w
|
||||
#
|
||||
# networking related routines
|
||||
#
|
||||
|
||||
|
||||
package Golem;
|
||||
use strict;
|
||||
|
||||
use Golem;
|
||||
|
||||
sub get_external_ipinfo {
|
||||
my ($ip) = @_;
|
||||
|
||||
return undef unless $ip && $Golem::noc_nets_cgi;
|
||||
|
||||
my $ipinfo;
|
||||
my @net_info;
|
||||
|
||||
my $wget_options = "";
|
||||
$wget_options = "--timeout=${Golem::noc_nets_cgi_timeout}"
|
||||
if $Golem::noc_nets_cgi_timeout;
|
||||
|
||||
open(NOCNET,"wget $wget_options -q -O - ${Golem::noc_nets_cgi}?name=$ip |");
|
||||
|
||||
Golem::debug("wget $wget_options -q -O - ${Golem::noc_nets_cgi}?name=$ip |");
|
||||
|
||||
my $line;
|
||||
while($line=<NOCNET>) {
|
||||
if ($line=~/^<tr align=center>/) {
|
||||
chomp($line);
|
||||
$line =~ s/<\/td><td>/\|/g;
|
||||
$line =~ s/(<td>|<tr align=center>|<\/tr>|<\/td>)//g;
|
||||
@net_info= split(/\|/,$line,5);
|
||||
}
|
||||
}
|
||||
close(NOCNET);
|
||||
|
||||
if (@net_info) {
|
||||
$ipinfo->{'ip'} = $net_info[0];
|
||||
$ipinfo->{'subnet'} = $net_info[1];
|
||||
$ipinfo->{'router'} = $net_info[2];
|
||||
$ipinfo->{'iface'} = $net_info[3];
|
||||
|
||||
$ipinfo->{'vlan'} = $ipinfo->{'iface'};
|
||||
$ipinfo->{'vlan'} =~ /(\d+)/;
|
||||
$ipinfo->{'vlan'} = $1;
|
||||
|
||||
$ipinfo->{'router_if_addr'} = $net_info[4];
|
||||
}
|
||||
|
||||
return $ipinfo;
|
||||
}
|
||||
|
||||
# --- ghetto code
|
||||
sub int2maskpart {
|
||||
my ($i) = @_;
|
||||
return "0" unless defined($i);
|
||||
|
||||
my $j = 0;
|
||||
my $bits = "";
|
||||
while ($j < 8) {
|
||||
if ($i <= $j) {
|
||||
$bits .= "0";
|
||||
}
|
||||
else {
|
||||
$bits .= "1";
|
||||
}
|
||||
$j++;
|
||||
}
|
||||
return oct("0b" . $bits);
|
||||
}
|
||||
|
||||
|
||||
sub mask2netmask {
|
||||
my ($j) = @_;
|
||||
|
||||
my @ip;
|
||||
my $i;
|
||||
for ($i = 1; $i <= int($j / 8); $i++) {
|
||||
push @ip, int2maskpart(8);
|
||||
}
|
||||
while ($i < 5) {
|
||||
push @ip, int2maskpart($j % 8);
|
||||
$j = 0;
|
||||
$i++;
|
||||
}
|
||||
|
||||
return join(".", @ip);
|
||||
}
|
||||
|
||||
|
||||
# convert string representation of ipv4 address into integer
|
||||
sub ipv4_str2int {
|
||||
my ($ip_string) = @_;
|
||||
|
||||
if ($ip_string =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)/) {
|
||||
return (16777216 * $1) + (65536 * $2) + (256 * $3) + $4;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
# convert integer representation of ipv4 address into string
|
||||
sub ipv4_int2str {
|
||||
my ($ip_int) = @_;
|
||||
|
||||
if ($ip_int >= 0 && $ip_int <= 4294967295) {
|
||||
my $w = ($ip_int / 16777216) % 256;
|
||||
my $x = ($ip_int / 65536) % 256;
|
||||
my $y = ($ip_int / 256) % 256;
|
||||
my $z = $ip_int % 256;
|
||||
|
||||
return $w . "." . $x . "." . $y . "." . $z;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
# /24 -> +255
|
||||
# /27 -> +31
|
||||
# /28 -> +15
|
||||
# /29 -> +7
|
||||
sub ipv4_mask2offset {
|
||||
my ($mask) = @_;
|
||||
$mask ||= 0;
|
||||
my $offset = 2 ** (32 - $mask);
|
||||
return $offset - 1;
|
||||
}
|
||||
|
||||
sub get_net {
|
||||
my ($ip, $mask, $opts) = @_;
|
||||
|
||||
Golem::trim(\$ip);
|
||||
|
||||
Golem::die("Programmer error: get_net expects net and mask")
|
||||
unless
|
||||
($ip && $mask && Golem::is_digital($mask)) ||
|
||||
($ip =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\/\d{1,2}$/);
|
||||
|
||||
if ($ip =~ /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\/(\d{1,2})$/o) {
|
||||
$ip = ipv4_str2int($1);
|
||||
$mask = $2;
|
||||
}
|
||||
elsif ($ip =~ /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/o) {
|
||||
$ip = ipv4_str2int($1);
|
||||
}
|
||||
|
||||
my $dbh = Golem::get_db();
|
||||
my $sth = $dbh->prepare("SELECT * FROM net_v4 WHERE ip = ? and mask = ?");
|
||||
$sth->execute($ip, $mask);
|
||||
my $net = $sth->fetchrow_hashref();
|
||||
$sth->finish();
|
||||
|
||||
if ($net->{'id'}) {
|
||||
return Golem::get_net_by_id($net->{'id'}, $opts);
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
sub get_net_by_id {
|
||||
my ($id, $opts) = @_;
|
||||
|
||||
Golem::die("Programmer error: get_net_by_id expects network id")
|
||||
unless $id;
|
||||
|
||||
$opts = {} unless $opts;
|
||||
|
||||
my $dbh = Golem::get_db();
|
||||
my $sth = $dbh->prepare("SELECT * FROM net_v4 WHERE id = ?");
|
||||
|
||||
$sth->execute($id);
|
||||
|
||||
my $r = $sth->fetchrow_hashref();
|
||||
if ($r->{'id'}) {
|
||||
$r->{'ip_str'} = Golem::ipv4_int2str($r->{'ip'});
|
||||
$r->{'net_with_mask'} = $r->{'ip_str'} . "/" . $r->{'mask'};
|
||||
if ($r->{'name'} =~ /VLAN([\d]+)/o) {
|
||||
$r->{'vlan'} = $1;
|
||||
}
|
||||
else {
|
||||
$r->{'vlan'} = "";
|
||||
}
|
||||
|
||||
if ($opts->{'with_props'} || $opts->{'with_all'}) {
|
||||
$r = Golem::load_props("net_v4", $r);
|
||||
}
|
||||
|
||||
return $r;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
sub insert_net {
|
||||
my ($net) = @_;
|
||||
|
||||
Golem::die("Programmer error: insert_net expects net object")
|
||||
unless $net && ($net->{'ip_str'} || $net->{'ip'}) &&
|
||||
$net->{'mask'} && $net->{'name'};
|
||||
|
||||
if ($net->{'ip_str'}) {
|
||||
$net->{'ip'} = Golem::ipv4_str2int($net->{'ip_str'});
|
||||
}
|
||||
|
||||
my $enet = Golem::get_net($net->{'ip'}, $net->{'mask'});
|
||||
return Golem::err("net already exists [$enet->{'ip_str'}/$enet->{'$mask'} ($enet->{'id'})]")
|
||||
if $enet;
|
||||
|
||||
my $dbh = Golem::__insert("net_v4", $net);
|
||||
return Golem::err($dbh->errstr, $net)
|
||||
if $dbh->err;
|
||||
|
||||
$net->{'id'} = $dbh->selectrow_array("SELECT LAST_INSERT_ID()");
|
||||
|
||||
return Golem::get_net_by_id($net->{'id'});
|
||||
}
|
||||
|
||||
sub save_net {
|
||||
my ($net) = @_;
|
||||
|
||||
Golem::die("Programmer error: save_net expects net object")
|
||||
unless $net && $net->{'id'} &&
|
||||
($net->{'ip_str'} || $net->{'ip'}) &&
|
||||
$net->{'mask'} && $net->{'name'};
|
||||
|
||||
if ($net->{'ip_str'}) {
|
||||
$net->{'ip'} = Golem::ipv4_str2int($net->{'ip_str'});
|
||||
}
|
||||
|
||||
my $enet = Golem::get_net($net->{'ip'}, $net->{'mask'}, {"with_all" => 1});
|
||||
|
||||
if ($enet) {
|
||||
my $dbh = Golem::__update("net_v4", $net);
|
||||
return Golem::err($dbh->errstr, $net)
|
||||
if $dbh->err;
|
||||
|
||||
$net = Golem::save_props("net_v4", $net);
|
||||
}
|
||||
else {
|
||||
return Golem::insert_net($net);
|
||||
}
|
||||
|
||||
return $net;
|
||||
}
|
||||
|
||||
sub delete_net {
|
||||
my ($net) = @_;
|
||||
|
||||
Golem::die("Programmer error: delete_net expects net object")
|
||||
unless $net && $net->{'id'};
|
||||
|
||||
my $dbh = Golem::get_db();
|
||||
|
||||
Golem::unset_row_tag("net_v4", $net->{'id'});
|
||||
$dbh->do("DELETE from net_v4prop where net_v4id = ?", undef, $net->{'id'});
|
||||
$dbh->do("DELETE from net_v4propblob where net_v4id = ?", undef, $net->{'id'});
|
||||
|
||||
$dbh->do("DELETE FROM net_v4 WHERE net_v4.id = ?", undef, $net->{'id'});
|
||||
return Golem::err($dbh->errstr, $net)
|
||||
if $dbh->err;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
sub get_containing_net {
|
||||
my ($ip, $opts) = @_;
|
||||
|
||||
Golem::die("Programmer error: get_containing_net expects ip address")
|
||||
unless $ip;
|
||||
|
||||
Golem::trim(\$ip);
|
||||
if ($ip =~ /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/o) {
|
||||
$ip = Golem::ipv4_str2int($1);
|
||||
}
|
||||
|
||||
my $dbh = Golem::get_db();
|
||||
|
||||
# choose nearest (by ip desc) and smallest (by mask desc) known network
|
||||
my $sth = $dbh->prepare("SELECT * FROM net_v4 WHERE ip < ? and mask <> 32
|
||||
order by ip desc, mask desc");
|
||||
|
||||
$sth->execute($ip);
|
||||
|
||||
my $net;
|
||||
|
||||
while(my $r = $sth->fetchrow_hashref()) {
|
||||
# choose first network that includes tested ip address if any
|
||||
if ($r->{'ip'} + ipv4_mask2offset($r->{'mask'}) ge $ip) {
|
||||
return Golem::get_net_by_id($r->{'id'}, $opts);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub get_net_by_vlan {
|
||||
my ($vlan, $opts) = @_;
|
||||
|
||||
Golem::die("Programmer error: get_net_by_vlan expects vlan name")
|
||||
unless $vlan;
|
||||
|
||||
$vlan =~ s/vlan//go;
|
||||
$vlan =~ s/\s//go;
|
||||
|
||||
my $dbh = Golem::get_db();
|
||||
my $sth = $dbh->prepare("SELECT * FROM net_v4 WHERE mask <> 32 and name like ? order by name");
|
||||
$sth->execute("VLAN${vlan}%");
|
||||
|
||||
while (my $r = $sth->fetchrow_hashref()) {
|
||||
if ($r->{'name'} =~ /VLAN${vlan}\s/o) {
|
||||
return Golem::get_net($r->{'ip'}, $r->{'mask'}, $opts);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub is_ipv4 {
|
||||
my ($str) = @_;
|
||||
return $str =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/o;
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
393
local/cgi-bin/Golem/proplib.pl
Normal file
393
local/cgi-bin/Golem/proplib.pl
Normal file
@@ -0,0 +1,393 @@
|
||||
#!/usr/bin/perl -w
|
||||
#
|
||||
# Properties manipulation routines
|
||||
#
|
||||
#
|
||||
# This is an object property library which
|
||||
# implements DB -> MEMORY (load_props)
|
||||
# and MEMORY -> DB (save_props) transition
|
||||
# of object properties
|
||||
#
|
||||
# Object is defined as a record in some TABLE
|
||||
# (called owner). To be able to use properties
|
||||
# for the given TABLE you should create
|
||||
# another two tables: TABLEprop and TABLEpropblob
|
||||
#
|
||||
# Example for host object:
|
||||
#
|
||||
# CREATE TABLE `hostprop` (
|
||||
# `hostid` int(11) NOT NULL,
|
||||
# `propid` smallint(6) NOT NULL default '0',
|
||||
# `propseq` int(11) NOT NULL default '0',
|
||||
# `value` varchar(1024) default NULL,
|
||||
# PRIMARY KEY (`hostid`,`propid`,`propseq`),
|
||||
# KEY `prop` (`propid`)
|
||||
# ) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
||||
#
|
||||
# CREATE TABLE `hostpropblob` (
|
||||
# `hostid` int(11) NOT NULL,
|
||||
# `propid` smallint(6) NOT NULL default '0',
|
||||
# `propseq` int(11) NOT NULL default '0',
|
||||
# `value` blob,
|
||||
# PRIMARY KEY (`hostid`,`propid`,`propseq`),
|
||||
# KEY `prop` (`propid`)
|
||||
# ) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
||||
#
|
||||
# After that you should create "allowed" properties
|
||||
# for the owner using `gconsole.pl --create-proplist`
|
||||
#
|
||||
# You could see all the defined properties for the owner
|
||||
# using gconsole.pl --list-proplist OWNER
|
||||
#
|
||||
#
|
||||
# For the owner (tables) which primary key is not simple
|
||||
# id auto_increment (as in the example above) the following
|
||||
# TABLEprop and TABLEpropblob structure should be used:
|
||||
#
|
||||
|
||||
package Golem;
|
||||
use strict;
|
||||
|
||||
use Golem;
|
||||
|
||||
use Storable;
|
||||
|
||||
|
||||
# check that given property owner is valid
|
||||
# currently there are two valid property owners: host, user
|
||||
#
|
||||
sub check_prop_owner {
|
||||
my ($owner) = @_;
|
||||
|
||||
Golem::die("Programmer error: check_prop_owner got empty prop owner")
|
||||
unless $owner;
|
||||
|
||||
my $props = {
|
||||
"eventhistory" => 1,
|
||||
"host" => 1,
|
||||
"user" => 1,
|
||||
"net_v4" => 1,
|
||||
};
|
||||
|
||||
Golem::die("Programmer error: not valid property owner [$owner]")
|
||||
unless defined($props->{$owner});
|
||||
}
|
||||
|
||||
# get property definition record(s) from database
|
||||
# for the specified owner
|
||||
#
|
||||
sub get_proplist {
|
||||
my ($owner, $hpname) = @_;
|
||||
|
||||
Golem::die("Programmer error: get_proplist expects at least owner")
|
||||
unless $owner;
|
||||
|
||||
Golem::check_prop_owner($owner);
|
||||
|
||||
my $dbh = Golem::get_db();
|
||||
my $sth;
|
||||
my $ret;
|
||||
|
||||
if ($hpname) {
|
||||
$sth = $dbh->prepare("SELECT * FROM proplist WHERE owner = ? and name = ?");
|
||||
$sth->execute($owner, $hpname);
|
||||
$ret = $sth->fetchrow_hashref();
|
||||
$ret = 0 unless $ret->{'id'};
|
||||
}
|
||||
else {
|
||||
$sth = $dbh->prepare("SELECT * FROM proplist where owner = ?");
|
||||
$sth->execute($owner);
|
||||
while (my $r = $sth->fetchrow_hashref()) {
|
||||
$ret->{$r->{'name'}} = $r;
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
sub create_proplist {
|
||||
my ($owner, $op) = @_;
|
||||
|
||||
Golem::die("Programmer error: create_proplist expects at least owner and property name")
|
||||
unless $owner && $op && $op->{'name'};
|
||||
|
||||
Golem::check_prop_owner($owner);
|
||||
|
||||
my $eop = Golem::get_proplist($owner, $op->{'name'});
|
||||
Golem::die("proplist record already exists [$eop->{'name'} ($eop->{'id'})]")
|
||||
if $eop;
|
||||
|
||||
$op->{'owner'} = $owner;
|
||||
|
||||
my $dbh = Golem::__insert("proplist", $op);
|
||||
Golem::die("Error creating proplist: " . $dbh->errstr, $op)
|
||||
if $dbh->err;
|
||||
|
||||
$op->{'id'} = $dbh->selectrow_array("SELECT LAST_INSERT_ID()");
|
||||
|
||||
Golem::do_log("new proplist record: [$op->{'owner'}/$op->{'name'}] ($op->{'id'})");
|
||||
|
||||
return $op;
|
||||
}
|
||||
|
||||
sub delete_proplist {
|
||||
my ($owner, $op) = @_;
|
||||
|
||||
Golem::die("Programmer error: delete_proplist expects proplist record")
|
||||
unless $op && $op->{'id'} && $op->{'name'};
|
||||
|
||||
Golem::check_prop_owner($owner);
|
||||
|
||||
my $eop = Golem::get_proplist($owner, $op->{'name'});
|
||||
|
||||
return Golem::err("delete_proplist: invalid proplist record")
|
||||
unless $eop;
|
||||
|
||||
my $dbh = Golem::get_db();
|
||||
my $objs_with_prop =
|
||||
$dbh->selectrow_array("select count(*) from ${owner}prop where propid = ?", undef, $op->{'id'}) +
|
||||
$dbh->selectrow_array("select count(*) from ${owner}propblob where propid = ?", undef, $op->{'id'})
|
||||
;
|
||||
|
||||
return Golem::err("delete_proplist: unable to delete proplist record; $objs_with_prop records are using it")
|
||||
if $objs_with_prop;
|
||||
|
||||
$dbh->do("delete from proplist where id = ?", undef, $op->{'id'});
|
||||
|
||||
return Golem::err("error while deleting from proplist: " . $dbh->errstr)
|
||||
if $dbh->err;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
# read object properties for the given owner
|
||||
# (exactly matches table name)
|
||||
#
|
||||
sub load_props {
|
||||
my ($owner, $o) = @_;
|
||||
|
||||
Golem::die("Programmer error: load_props expects owner name and object")
|
||||
unless $owner && ref($o);
|
||||
|
||||
Golem::check_prop_owner($owner);
|
||||
|
||||
my $table = Golem::get_schema_table($owner);
|
||||
my $pk = $table->{'primary_key'};
|
||||
|
||||
my $dbh = Golem::get_db();
|
||||
my $sth;
|
||||
|
||||
$o->{'props'}->{'data'} = {};
|
||||
|
||||
foreach my $t ("${owner}prop", "${owner}propblob") {
|
||||
my $sql = "select * from $t inner join proplist on proplist.id = $t.propid WHERE 1 ";
|
||||
my @bound_values = ();
|
||||
while (my ($pk_field, $dummy) = each %{$table->{'primary_key'}}) {
|
||||
if ($pk_field eq 'id') {
|
||||
$sql .= " and `${owner}id` = ? ";
|
||||
}
|
||||
else {
|
||||
$sql .= " and `$pk_field` = ? ";
|
||||
}
|
||||
|
||||
Golem::die("Programmer error: load_props got empty value for primary key field [$pk_field] of table [$owner]")
|
||||
unless defined($o->{$pk_field});
|
||||
|
||||
push (@bound_values, $o->{$pk_field});
|
||||
}
|
||||
$sth = $dbh->prepare($sql);
|
||||
Golem::sth_bind_array($sth, \@bound_values);
|
||||
$sth->execute();
|
||||
|
||||
while (my $r = $sth->fetchrow_hashref()) {
|
||||
my $v;
|
||||
|
||||
if ($t eq "${owner}prop") {
|
||||
$v = $r->{'value'};
|
||||
}
|
||||
if ($t eq "${owner}propblob") {
|
||||
# print STDERR Storable::thaw($r->{'value'});
|
||||
$v = Storable::thaw($r->{'value'});
|
||||
}
|
||||
|
||||
if ($r->{'datatype'} eq 'array' || $r->{'datatype'} eq 'arrayblob') {
|
||||
$o->{'props'}->{'data'}->{$r->{'name'}} = []
|
||||
unless defined($o->{'props'}->{'data'}->{$r->{'name'}});
|
||||
|
||||
push (@{$o->{'props'}->{'data'}->{$r->{'name'}}}, $v);
|
||||
}
|
||||
else {
|
||||
$o->{'props'}->{'data'}->{$r->{'name'}} = $v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$o->{'props'}->{'loaded'} = 1;
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
||||
# save properties from memory into database
|
||||
# checks that properties were loaded using load_props
|
||||
# (for advanced users: "loaded" is the key of check,
|
||||
# it is set by load_props which could be emulated)
|
||||
#
|
||||
sub save_props {
|
||||
my ($owner, $o) = @_;
|
||||
|
||||
Golem::die("Programmer error: save_props expects owner name and object")
|
||||
unless $owner && ref($o);
|
||||
|
||||
Golem::check_prop_owner($owner);
|
||||
|
||||
return Golem::err("Programmer error: save_props should be called only after calling load_props")
|
||||
unless $o->{'props'}->{'loaded'};
|
||||
|
||||
my $table = Golem::get_schema_table($owner);
|
||||
my $pk = $table->{'primary_key'};
|
||||
|
||||
my $dbh = Golem::get_db();
|
||||
|
||||
while (my ($k, $v) = each %{$o->{'props'}->{'data'}}) {
|
||||
my $op = Golem::get_proplist($owner, $k);
|
||||
|
||||
unless ($op) {
|
||||
Golem::do_log("Non-existent $owner property name [$k], skipping.", {"stderr" => 1});
|
||||
next;
|
||||
}
|
||||
|
||||
my $do_save = sub {
|
||||
my ($value, $seq) = @_;
|
||||
|
||||
$seq = 0 unless defined($seq);
|
||||
|
||||
my $tpref = "";
|
||||
my $db_value;
|
||||
|
||||
if ($op->{'datatype'} eq 'blob' || $op->{'datatype'} eq 'arrayblob') {
|
||||
$db_value = Storable::nfreeze($value);
|
||||
$tpref = "blob";
|
||||
}
|
||||
else {
|
||||
$db_value = $value;
|
||||
|
||||
if ($op->{'datatype'} eq 'bool') {
|
||||
$db_value = $value ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
my $prop_ref = {
|
||||
"propid" => $op->{'id'},
|
||||
"propseq" => $seq,
|
||||
"value" => $db_value,
|
||||
};
|
||||
|
||||
while (my ($pk_field, $dummy) = each %{$table->{'primary_key'}}) {
|
||||
if ($pk_field eq 'id') {
|
||||
$prop_ref->{"${owner}id"} = $o->{$pk_field};
|
||||
}
|
||||
else {
|
||||
$prop_ref->{$pk_field} = $o->{$pk_field};
|
||||
}
|
||||
}
|
||||
|
||||
$dbh = Golem::__update("${owner}prop${tpref}", $prop_ref, {"create_nonexistent" => 1});
|
||||
Golem::die("save_props: error while replacing ${owner} props: " . $dbh->errstr)
|
||||
if $dbh->err;
|
||||
};
|
||||
|
||||
if ($op->{'datatype'} eq 'array' || $op->{'datatype'} eq 'arrayblob') {
|
||||
my $i = 0;
|
||||
foreach my $array_value (@{$v}) {
|
||||
$do_save->($array_value, $i);
|
||||
$i = $i + 1;
|
||||
}
|
||||
|
||||
my $tpref = "";
|
||||
if ($op->{'datatype'} eq 'arrayblob') {
|
||||
$tpref = "blob";
|
||||
}
|
||||
|
||||
my $sql = "delete from ${owner}prop${tpref} where 1 ";
|
||||
my @bound_values = ();
|
||||
while (my ($pk_field, $dummy) = each %{$table->{'primary_key'}}) {
|
||||
if ($pk_field eq 'id') {
|
||||
$sql .= " and ${owner}id = ? ";
|
||||
}
|
||||
else {
|
||||
$sql .= " and $pk_field = ? ";
|
||||
}
|
||||
push (@bound_values, $o->{$pk_field});
|
||||
}
|
||||
$sql .= " and propid = ? and propseq >= ?";
|
||||
push (@bound_values, $op->{'id'});
|
||||
push (@bound_values, $i);
|
||||
|
||||
my $sth = $dbh->prepare($sql);
|
||||
Golem::sth_bind_array($sth, \@bound_values);
|
||||
$sth->execute();
|
||||
}
|
||||
else {
|
||||
$do_save->($v, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
||||
# deletes object property if no objects
|
||||
# are associated with the property
|
||||
#
|
||||
# input
|
||||
# owner type (for the listing see check_prop_owner)
|
||||
# object (with $obj->{'id'} defined)
|
||||
# property name to delete
|
||||
#
|
||||
sub delete_prop {
|
||||
my ($owner, $obj, $propname) = @_;
|
||||
|
||||
Golem::die("Programmer error: delete_prop expects owner and object")
|
||||
unless $owner && ref($obj);
|
||||
|
||||
Golem::check_prop_owner($owner);
|
||||
|
||||
my $op = Golem::get_proplist($owner, $propname);
|
||||
return Golem::err("delete_prop: invalid propname [$propname]")
|
||||
unless $op;
|
||||
|
||||
my $table = Golem::get_schema_table($owner);
|
||||
my $pk = $table->{'primary_key'};
|
||||
|
||||
my $dbh = Golem::get_db();
|
||||
|
||||
my $tpref = "";
|
||||
if ($op->{'datatype'} eq 'blob' || $op->{'datatype'} eq 'blobarray') {
|
||||
$tpref = "blob";
|
||||
}
|
||||
|
||||
my $sql = "delete from ${owner}prop${tpref} where 1 ";
|
||||
my @bound_values = ();
|
||||
while (my ($pk_field, $dummy) = each %{$table->{'primary_key'}}) {
|
||||
if ($pk_field eq 'id') {
|
||||
$sql .= " and ${owner}id = ? ";
|
||||
}
|
||||
else {
|
||||
$sql .= " and $pk_field = ? ";
|
||||
}
|
||||
push (@bound_values, $obj->{$pk_field});
|
||||
}
|
||||
$sql .= " and propid = ? ";
|
||||
push (@bound_values, $op->{'id'});
|
||||
|
||||
my $sth = $dbh->prepare($sql);
|
||||
Golem::sth_bind_array($sth, \@bound_values);
|
||||
$sth->execute();
|
||||
|
||||
Golem::die("delete_prop: error deleting $owner [$obj->{'id'}] property [$propname]: " . $dbh->errstr)
|
||||
if $dbh->err;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
222
local/cgi-bin/Golem/textlib.pl
Normal file
222
local/cgi-bin/Golem/textlib.pl
Normal file
@@ -0,0 +1,222 @@
|
||||
#!/usr/bin/perl -w
|
||||
#
|
||||
# Text manipulation routines
|
||||
#
|
||||
# parts courtesy of LiveJournal.org
|
||||
#
|
||||
|
||||
package Golem;
|
||||
use strict;
|
||||
|
||||
use Golem;
|
||||
|
||||
# <LJFUNC>
|
||||
# name: LJ::decode_url_string
|
||||
# class: web
|
||||
# des: Parse URL-style arg/value pairs into a hash.
|
||||
# args: buffer, hashref
|
||||
# des-buffer: Scalar or scalarref of buffer to parse.
|
||||
# des-hashref: Hashref to populate.
|
||||
# returns: boolean; true.
|
||||
# </LJFUNC>
|
||||
sub decode_url_string
|
||||
{
|
||||
my $a = shift;
|
||||
my $buffer = ref $a ? $a : \$a;
|
||||
my $hashref = shift; # output hash
|
||||
my $keyref = shift; # array of keys as they were found
|
||||
|
||||
my $pair;
|
||||
my @pairs = split(/&/, $$buffer);
|
||||
@$keyref = @pairs;
|
||||
my ($name, $value);
|
||||
foreach $pair (@pairs)
|
||||
{
|
||||
($name, $value) = split(/=/, $pair);
|
||||
$value =~ tr/+/ /;
|
||||
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
|
||||
$name =~ tr/+/ /;
|
||||
$name =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
|
||||
$hashref->{$name} .= $hashref->{$name} ? ",$value" : $value;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
# <LJFUNC>
|
||||
# name: LJ::ehtml
|
||||
# class: text
|
||||
# des: Escapes a value before it can be put in HTML.
|
||||
# args: string
|
||||
# des-string: string to be escaped
|
||||
# returns: string escaped.
|
||||
# </LJFUNC>
|
||||
sub ehtml
|
||||
{
|
||||
# fast path for the commmon case:
|
||||
return $_[0] unless $_[0] =~ /[&\"\'<>]/o;
|
||||
|
||||
# this is faster than doing one substitution with a map:
|
||||
my $a = $_[0];
|
||||
$a =~ s/\&/&/g;
|
||||
$a =~ s/\"/"/g;
|
||||
$a =~ s/\'/&\#39;/g;
|
||||
$a =~ s/</</g;
|
||||
$a =~ s/>/>/g;
|
||||
return $a;
|
||||
}
|
||||
|
||||
sub esql {
|
||||
return $_[0] unless $_[0] =~ /[\'\"\\]/o;
|
||||
|
||||
my $a = $_[0];
|
||||
$a =~ s/\'//go;
|
||||
$a =~ s/\"//go;
|
||||
$a =~ s/\\//go;
|
||||
return $a;
|
||||
}
|
||||
|
||||
# <LJFUNC>
|
||||
# name: LJ::is_ascii
|
||||
# des: checks if text is pure ASCII.
|
||||
# args: text
|
||||
# des-text: text to check for being pure 7-bit ASCII text.
|
||||
# returns: 1 if text is indeed pure 7-bit, 0 otherwise.
|
||||
# </LJFUNC>
|
||||
sub is_ascii {
|
||||
my $text = shift;
|
||||
return ($text !~ m/[^\x01-\x7f]/o);
|
||||
}
|
||||
|
||||
sub is_digital {
|
||||
my $text = shift;
|
||||
return ( $text =~ /\d+/o );
|
||||
}
|
||||
|
||||
# tests if there's data in configuration file string:
|
||||
# i.e. if it's not empty and is not commented
|
||||
#
|
||||
sub have_data {
|
||||
my ($line) = @_;
|
||||
|
||||
if ($line =~ /^\s*#/o || $line =~ /^[\s]*$/o) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# fixes user input strings (passed as array of references),
|
||||
# currently only trims
|
||||
#
|
||||
# used when importing:
|
||||
# - 1C data
|
||||
#
|
||||
sub fix_input {
|
||||
my (@i) = @_;
|
||||
|
||||
foreach my $v (@i) {
|
||||
Golem::die("Programmer error: check_input expects only scalar references")
|
||||
unless ref($v) eq 'SCALAR';
|
||||
|
||||
Golem::do_log("Inaccurate spacing trimmed [$$v]", {"stderr" => 1})
|
||||
if Golem::trim($v);
|
||||
}
|
||||
}
|
||||
|
||||
# given scalar string trims white space
|
||||
# at the beginning and in the end and
|
||||
# returns trimmed string
|
||||
#
|
||||
# given scalar reference trims white space
|
||||
# at the beginning and in the end and
|
||||
# returns true if trimming occured and false otherwise
|
||||
# NOTE: modifies the original string
|
||||
# reference to which was given as input parameter
|
||||
sub trim {
|
||||
my ($string) = @_;
|
||||
|
||||
if (ref($string) eq 'SCALAR') {
|
||||
my $tstr = $$string;
|
||||
|
||||
return 0 if $tstr eq ''; # nothing to trim, do not waste cpu cycles
|
||||
|
||||
$tstr =~ s/^\s+//so;
|
||||
$tstr =~ s/\s+$//so;
|
||||
|
||||
if ($tstr ne $$string) {
|
||||
$$string = $tstr;
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return "" if $string eq ''; # nothing to trim, do not waste cpu cycles
|
||||
|
||||
$string =~ s/^\s+//so;
|
||||
$string =~ s/\s+$//so;
|
||||
return $string;
|
||||
}
|
||||
}
|
||||
|
||||
# same as standard perl join except for it doesn't
|
||||
# output "uninitialized value in join" when joining
|
||||
# list with undef values; and we use those lists
|
||||
# when binding params to DBI query
|
||||
#
|
||||
sub safe_join {
|
||||
my ($delimiter, @arr) = @_;
|
||||
|
||||
my $joined_text = "";
|
||||
$delimiter = "" unless $delimiter;
|
||||
|
||||
foreach my $bv (@arr) {
|
||||
$joined_text .= ($bv ? $bv : "") . $delimiter;
|
||||
}
|
||||
|
||||
my $i;
|
||||
for ($i = 0; $i < length($delimiter); $i++) {
|
||||
chop($joined_text);
|
||||
}
|
||||
|
||||
return $joined_text;
|
||||
}
|
||||
|
||||
# should be used when you need to concatenate string
|
||||
# which might be undefined and you want empty string ("")
|
||||
# instead of perl warnings about uninitialized values
|
||||
#
|
||||
sub safe_string {
|
||||
my ($str) = @_;
|
||||
|
||||
if ($str) {
|
||||
return $str;
|
||||
}
|
||||
else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
# inserts $symbol every $range characters in a $line
|
||||
sub div_line {
|
||||
my ($line, $range, $symbol) = @_;
|
||||
|
||||
Golem::die("Programmer error: div_line expects at least string")
|
||||
unless $line;
|
||||
|
||||
$range = 70 unless $range;
|
||||
$symbol = ' ' unless $symbol;
|
||||
|
||||
my $result = '';
|
||||
for (my $i = 0 ; $i <= int(length($line)/$range) ; $i++) {
|
||||
$result .= substr($line,$i*$range,$range) . $symbol;
|
||||
}
|
||||
chop($result);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
207
local/cgi-bin/HTMLCleaner.pm
Normal file
207
local/cgi-bin/HTMLCleaner.pm
Normal file
@@ -0,0 +1,207 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
|
||||
package HTMLCleaner;
|
||||
|
||||
use strict;
|
||||
use base 'HTML::Parser';
|
||||
use CSS::Cleaner;
|
||||
|
||||
sub new {
|
||||
my ($class, %opts) = @_;
|
||||
|
||||
my $p = new HTML::Parser('api_version' => 3);
|
||||
$p->handler('start' => \&start, 'self, tagname, attr, attrseq, text' );
|
||||
$p->handler('end' => \&end, 'self, tagname' );
|
||||
$p->handler('text' => \&text, 'self, text' );
|
||||
$p->handler('declaration' => \&decl, 'self, tokens' );
|
||||
|
||||
$p->{'output'} = $opts{'output'} || sub {};
|
||||
$p->{'cleaner'} = CSS::Cleaner->new;
|
||||
$p->{'valid_stylesheet'} = $opts{'valid_stylesheet'} || sub { 1 };
|
||||
$p->{'allow_password_input'} = $opts{'allow_password_input'} || 0;
|
||||
|
||||
bless $p, $class;
|
||||
}
|
||||
|
||||
my %bad_attr = (map { $_ => 1 }
|
||||
qw(datasrc datafld));
|
||||
|
||||
my %eat_tag = (map { $_ => 1 }
|
||||
qw(script iframe object applet embed param));
|
||||
|
||||
my @eating; # push tagname whenever we start eating a tag
|
||||
|
||||
sub start {
|
||||
my ($self, $tagname, $attr, $seq, $text) = @_;
|
||||
$tagname =~ s/<//;
|
||||
|
||||
my $slashclose = 0; # xml-style
|
||||
if ($tagname =~ s!/(.*)!!) {
|
||||
if (length($1)) { push @eating, "$tagname/$1"; } # basically halt parsing
|
||||
else { $slashclose = 1; }
|
||||
}
|
||||
|
||||
my @allowed_tags = ('lj-embed');
|
||||
|
||||
push @eating, $tagname if
|
||||
$eat_tag{$tagname} && ! grep { lc $tagname eq $_ } @allowed_tags;
|
||||
|
||||
return if @eating;
|
||||
|
||||
my $clean_res = eval {
|
||||
my $cleantag = $tagname;
|
||||
$cleantag =~ s/^.*://s;
|
||||
$cleantag =~ s/[^\w]//g;
|
||||
no strict 'subs';
|
||||
my $meth = "CLEAN_$cleantag";
|
||||
my $code = $self->can($meth)
|
||||
or return 1; # don't clean, if no element-specific cleaner method
|
||||
return $code->($self, $seq, $attr);
|
||||
};
|
||||
return if !$@ && !$clean_res;
|
||||
|
||||
my $ret = "<$tagname";
|
||||
foreach (@$seq) {
|
||||
if ($_ eq "/") { $slashclose = 1; next; }
|
||||
next if $bad_attr{lc($_)};
|
||||
next if /^on/i;
|
||||
next if /(?:^=)|[\x0b\x0d]/;
|
||||
|
||||
if ($_ eq "style") {
|
||||
$attr->{$_} = $self->{cleaner}->clean_property($attr->{$_});
|
||||
}
|
||||
|
||||
if ($tagname eq 'input' && $_ eq 'type' && $attr->{'type'} =~ /^password$/i && !$self->{'allow_password_input'}) {
|
||||
delete $attr->{'type'};
|
||||
}
|
||||
|
||||
my $nospace = $attr->{$_};
|
||||
$nospace =~ s/[\s\0]//g;
|
||||
|
||||
# IE is brain-dead and lets javascript:, vbscript:, and about: have spaces mixed in
|
||||
if ($nospace =~ /(?:(?:(?:vb|java)script)|about):/i) {
|
||||
delete $attr->{$_};
|
||||
}
|
||||
$ret .= " $_=\"" . ehtml($attr->{$_}) . "\"";
|
||||
}
|
||||
$ret .= " /" if $slashclose;
|
||||
$ret .= ">";
|
||||
|
||||
if ($tagname eq "style") {
|
||||
$self->{'_eating_style'} = 1;
|
||||
$self->{'_style_contents'} = "";
|
||||
}
|
||||
|
||||
$self->{'output'}->($ret);
|
||||
}
|
||||
|
||||
sub CLEAN_meta {
|
||||
my ($self, $seq, $attr) = @_;
|
||||
|
||||
# don't allow refresh because it can refresh to javascript URLs
|
||||
# don't allow content-type because they can set charset to utf-7
|
||||
# why do we even allow meta tags?
|
||||
my $equiv = lc $attr->{"http-equiv"};
|
||||
if ($equiv) {
|
||||
$equiv =~ s/[\s\x0b]//;
|
||||
return 0 if $equiv =~ /refresh|content-type|link|set-cookie/;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub CLEAN_link {
|
||||
my ($self, $seq, $attr) = @_;
|
||||
|
||||
if ($attr->{rel} =~ /\bstylesheet\b/i) {
|
||||
my $href = $attr->{href};
|
||||
return 0 unless $href =~ m!^https?://([^/]+?)(/.*)$!;
|
||||
my ($host, $path) = ($1, $2);
|
||||
|
||||
my $rv = $self->{'valid_stylesheet'}->($href, $host, $path);
|
||||
if ($rv == 1) {
|
||||
return 1;
|
||||
}
|
||||
if ($rv) {
|
||||
$attr->{href} = $rv;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
# Allow blank <link> tags through so RSS S2 styles can work again without the 'rel="alternate"' hack
|
||||
return 1 if (keys( %$attr ) == 0);
|
||||
|
||||
return 1 if $attr->{rel} =~ /^(?:service|openid)\.\w+$/;
|
||||
my %okay = map { $_ => 1 } (qw(icon shortcut alternate next prev index made start search top help up author edituri file-list previous home contents bookmark chapter section subsection appendix glossary copyright child));
|
||||
return 1 if $okay{lc($attr->{rel})};
|
||||
|
||||
# Allow link tags with only an href tag. This is an implied rel="alternate"
|
||||
return 1 if (exists( $attr->{href} ) and (keys( %$attr ) == 1));
|
||||
|
||||
# Allow combinations of rel attributes through as long as all of them are valid, most notably "shortcut icon"
|
||||
return 1 unless grep { !$okay{$_} } split( /\s+/, $attr->{rel} );
|
||||
|
||||
# unknown link tag
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub end {
|
||||
my ($self, $tagname) = @_;
|
||||
if (@eating) {
|
||||
pop @eating if $eating[-1] eq $tagname;
|
||||
return;
|
||||
}
|
||||
|
||||
if ($self->{'_eating_style'}) {
|
||||
$self->{'_eating_style'} = 0;
|
||||
$self->{'output'}->($self->{cleaner}->clean($self->{'_style_contents'}));
|
||||
}
|
||||
|
||||
$self->{'output'}->("</$tagname>");
|
||||
}
|
||||
|
||||
sub text {
|
||||
my ($self, $text) = @_;
|
||||
return if @eating;
|
||||
|
||||
if ($self->{'_eating_style'}) {
|
||||
$self->{'_style_contents'} .= $text;
|
||||
return;
|
||||
}
|
||||
|
||||
# this string is magic [hack]. (See $out_straight in
|
||||
# cgi-bin/LJ/S2.pm) callers can print "<!-- -->" to HTML::Parser
|
||||
# just to make it flush, since HTML::Parser has no
|
||||
# ->flush_outstanding text tag.
|
||||
return if $text eq "<!-- -->";
|
||||
|
||||
# the parser gives us back text whenever it's confused
|
||||
# on really broken input. sadly, IE parses really broken
|
||||
# input, so let's escape anything going out this way.
|
||||
$self->{'output'}->(eangles($text));
|
||||
}
|
||||
|
||||
sub decl {
|
||||
my ($self, $tokens) = @_;
|
||||
$self->{'output'}->("<!" . join(" ", map { eangles($_) } @$tokens) . ">");
|
||||
}
|
||||
|
||||
sub eangles {
|
||||
my $a = shift;
|
||||
$a =~ s/</</g;
|
||||
$a =~ s/>/>/g;
|
||||
return $a;
|
||||
}
|
||||
|
||||
sub ehtml {
|
||||
my $a = shift;
|
||||
$a =~ s/\&/&/g;
|
||||
$a =~ s/\"/"/g;
|
||||
$a =~ s/\'/&\#39;/g;
|
||||
$a =~ s/</</g;
|
||||
$a =~ s/>/>/g;
|
||||
return $a;
|
||||
}
|
||||
|
||||
1;
|
||||
124
local/cgi-bin/LJ/Auth.pm
Normal file
124
local/cgi-bin/LJ/Auth.pm
Normal file
@@ -0,0 +1,124 @@
|
||||
# This is the LiveJournal Authentication module.
|
||||
# It contains useful authentication methods.
|
||||
|
||||
package LJ::Auth;
|
||||
use strict;
|
||||
use Digest::HMAC_SHA1 qw(hmac_sha1_hex);
|
||||
use Digest::SHA1 qw(sha1_hex);
|
||||
use Carp qw (croak);
|
||||
|
||||
# Generate an auth token for AJAX requests to use.
|
||||
# Arguments: ($remote, $action, %postvars)
|
||||
# $remote: remote user object
|
||||
# $uri: what uri this is for
|
||||
# %postvars: the expected post variables
|
||||
# Returns: Auth token good for the current hour
|
||||
sub ajax_auth_token {
|
||||
my ($class, $remote, $uri, %postvars) = @_;
|
||||
|
||||
$remote = LJ::want_user($remote) || LJ::get_remote();
|
||||
|
||||
croak "No URI specified" unless $uri;
|
||||
|
||||
my ($stime, $secret) = LJ::get_secret();
|
||||
my $postvars = join('&', map { $postvars{$_} } sort keys %postvars);
|
||||
my $remote_session_id = $remote && $remote->session ? $remote->session->id : LJ::UniqCookie->current_uniq;
|
||||
my $remote_userid = $remote ? $remote->id : 0;
|
||||
|
||||
my $chalbare = qq {ajax:$stime:$remote_userid:$remote_session_id:$uri:$postvars};
|
||||
my $chalsig = sha1_hex($chalbare, $secret);
|
||||
return qq{$chalbare:$chalsig};
|
||||
}
|
||||
|
||||
# Checks an auth token sent by an ajax request
|
||||
# Arguments: $remote, $uri, %POST variables
|
||||
# Returns: bool whether or not key is good
|
||||
sub check_ajax_auth_token {
|
||||
my ($class, $remote, $uri, %postvars) = @_;
|
||||
|
||||
$remote = LJ::want_user($remote) || LJ::get_remote();
|
||||
|
||||
# get auth token out of post vars
|
||||
my $auth_token = delete $postvars{auth_token} or return 0;
|
||||
|
||||
# recompute post vars
|
||||
my $postvars = join('&', map { $postvars{$_} } sort keys %postvars);
|
||||
|
||||
# get vars out of token string
|
||||
my ($c_ver, $stime, $remoteid, $sessid, $chal_uri, $chal_postvars, $chalsig) = split(':', $auth_token);
|
||||
|
||||
# get secret based on $stime
|
||||
my $secret = LJ::get_secret($stime);
|
||||
|
||||
# no time?
|
||||
return 0 unless $stime && $secret;
|
||||
|
||||
# right version?
|
||||
return 0 unless $c_ver eq 'ajax';
|
||||
|
||||
# in logged-out case $remoteid is 0 and $sessid is uniq_cookie
|
||||
my $req_remoteid = $remoteid > 0 ? $remote->id : 0;
|
||||
my $req_sessid = $remoteid > 0 ? $remote->session->id : LJ::UniqCookie->current_uniq;
|
||||
|
||||
|
||||
# do signitures match?
|
||||
my $chalbare = qq {$c_ver:$stime:$remoteid:$sessid:$chal_uri:$chal_postvars};
|
||||
my $realsig = sha1_hex($chalbare, $secret);
|
||||
return 0 unless $realsig eq $chalsig;
|
||||
|
||||
return 0 unless
|
||||
$remoteid == $req_remoteid && # remote id matches or logged-out 0=0
|
||||
$sessid == $req_sessid && # remote sessid or logged-out uniq cookie match
|
||||
$uri eq $chal_uri && # uri matches
|
||||
$postvars eq $chal_postvars; # post vars to uri
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# this is similar to the above methods but doesn't require a session or remote
|
||||
sub sessionless_auth_token {
|
||||
my ($class, $uri, %reqvars) = @_;
|
||||
|
||||
croak "No URI specified" unless $uri;
|
||||
|
||||
my ($stime, $secret) = LJ::get_secret();
|
||||
my $reqvars = join('&', map { $reqvars{$_} } sort keys %reqvars);
|
||||
|
||||
my $chalbare = qq {sessionless:$stime:$uri:$reqvars};
|
||||
my $chalsig = sha1_hex($chalbare, $secret);
|
||||
return qq{$chalbare:$chalsig};
|
||||
}
|
||||
|
||||
sub check_sessionless_auth_token {
|
||||
my ($class, $uri, %reqvars) = @_;
|
||||
|
||||
# get auth token out of post vars
|
||||
my $auth_token = delete $reqvars{auth_token} or return 0;
|
||||
|
||||
# recompute post vars
|
||||
my $reqvars = join('&', map { $reqvars{$_} } sort keys %reqvars);
|
||||
|
||||
# get vars out of token string
|
||||
my ($c_ver, $stime, $chal_uri, $chal_reqvars, $chalsig) = split(':', $auth_token);
|
||||
|
||||
# get secret based on $stime
|
||||
my $secret = LJ::get_secret($stime);
|
||||
|
||||
# no time?
|
||||
return 0 unless $stime && $secret;
|
||||
|
||||
# right version?
|
||||
return 0 unless $c_ver eq 'sessionless';
|
||||
|
||||
# do signitures match?
|
||||
my $chalbare = qq {$c_ver:$stime:$chal_uri:$chal_reqvars};
|
||||
my $realsig = sha1_hex($chalbare, $secret);
|
||||
return 0 unless $realsig eq $chalsig;
|
||||
|
||||
# do other vars match?
|
||||
return 0 unless $uri eq $chal_uri && $reqvars eq $chal_reqvars;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
1;
|
||||
21
local/cgi-bin/LJ/CSS/Cleaner.pm
Normal file
21
local/cgi-bin/LJ/CSS/Cleaner.pm
Normal file
@@ -0,0 +1,21 @@
|
||||
package LJ::CSS::Cleaner;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
no warnings 'redefine';
|
||||
|
||||
use base 'CSS::Cleaner';
|
||||
|
||||
sub new {
|
||||
my $class = shift;
|
||||
return $class->SUPER::new( @_,
|
||||
pre_hook => sub {
|
||||
my $rref = shift;
|
||||
|
||||
$$rref =~ s/comment-bake-cookie/CLEANED/g;
|
||||
return;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
1;
|
||||
47
local/cgi-bin/LJ/ConvUTF8.pm
Normal file
47
local/cgi-bin/LJ/ConvUTF8.pm
Normal file
@@ -0,0 +1,47 @@
|
||||
# this is a small wrapper around Unicode::MapUTF8, just so we can lazily-load it easier
|
||||
# with Class::Autouse, and so we have a central place to init its charset aliases.
|
||||
# and in the future if we switch transcoding packages, we can just do it here.
|
||||
package LJ::ConvUTF8;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Unicode::MapUTF8 ();
|
||||
|
||||
BEGIN {
|
||||
# declare some charset aliases
|
||||
# we need this at least for cases when the only name supported
|
||||
# by MapUTF8.pm isn't recognized by browsers
|
||||
# note: newer versions of MapUTF8 know these
|
||||
{
|
||||
my %alias = ( 'windows-1251' => 'cp1251',
|
||||
'windows-1252' => 'cp1252',
|
||||
'windows-1253' => 'cp1253', );
|
||||
foreach (keys %alias) {
|
||||
next if Unicode::MapUTF8::utf8_supported_charset($_);
|
||||
Unicode::MapUTF8::utf8_charset_alias($_, $alias{$_});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub load {
|
||||
1;
|
||||
}
|
||||
|
||||
sub supported_charset {
|
||||
my ($class, $charset) = @_;
|
||||
return Unicode::MapUTF8::utf8_supported_charset($charset);
|
||||
}
|
||||
|
||||
sub from_utf8 {
|
||||
my ($class, $from_enc, $str) = @_;
|
||||
return Unicode::MapUTF8::from_utf8({ -string=> $str, -charset => $from_enc });
|
||||
}
|
||||
|
||||
sub to_utf8 {
|
||||
my ($class, $to_enc, $str) = @_;
|
||||
return Unicode::MapUTF8::to_utf8({ -string=> $str, -charset => $to_enc });
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
|
||||
466
local/cgi-bin/LJ/EmbedModule.pm
Normal file
466
local/cgi-bin/LJ/EmbedModule.pm
Normal file
@@ -0,0 +1,466 @@
|
||||
#!/usr/bin/perl
|
||||
package LJ::EmbedModule;
|
||||
use strict;
|
||||
use Carp qw (croak);
|
||||
use Class::Autouse qw (
|
||||
LJ::Auth
|
||||
HTML::TokeParser
|
||||
);
|
||||
|
||||
# states for a finite-state machine we use in parse()
|
||||
use constant {
|
||||
# reading plain html without <object>, <embed> or <lj-embed>
|
||||
REGULAR => 1,
|
||||
# inside <object> or <embed> tag
|
||||
IMPLICIT => 2,
|
||||
# inside explicit <lj-embed> tag
|
||||
EXPLICIT => 3,
|
||||
# maximum embed width and height
|
||||
MAX_WIDTH => 800,
|
||||
MAX_HEIGHT => 800,
|
||||
};
|
||||
|
||||
# can optionally pass in an id of a module to change its contents
|
||||
# returns module id
|
||||
sub save_module {
|
||||
my ($class, %opts) = @_;
|
||||
|
||||
my $contents = $opts{contents} || '';
|
||||
my $id = $opts{id};
|
||||
my $journal = $opts{journal}
|
||||
or croak "No journal passed to LJ::EmbedModule::save_module";
|
||||
my $preview = $opts{preview};
|
||||
|
||||
# are we creating a new entry?
|
||||
unless (defined $id) {
|
||||
$id = LJ::alloc_user_counter($journal, 'D')
|
||||
or die "Could not allocate embed module ID";
|
||||
}
|
||||
|
||||
my $cmptext = 'C-' . LJ::text_compress($contents);
|
||||
|
||||
## embeds for preview are stored in a special table,
|
||||
## where new items overwrites old ones
|
||||
my $table_name = ($preview) ? 'embedcontent_preview' : 'embedcontent';
|
||||
$journal->do("REPLACE INTO $table_name (userid, moduleid, content) VALUES ".
|
||||
"(?, ?, ?)", undef, $journal->{'userid'}, $id, $cmptext);
|
||||
die $journal->errstr if $journal->err;
|
||||
|
||||
# save in memcache
|
||||
my $memkey = $class->memkey($journal->{'userid'}, $id, $preview);
|
||||
LJ::MemCache::set($memkey, $contents);
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
# changes <div class="ljembed"... tags from the RTE into proper lj-embed tags
|
||||
sub transform_rte_post {
|
||||
my ($class, $txt) = @_;
|
||||
return $txt unless $txt && $txt =~ /ljembed/i;
|
||||
# ghetto... shouldn't use regexes to parse this
|
||||
$txt =~ s/<div\s*class="ljembed"\s*(embedid="(\d+)")?\s*>(((?!<\/div>).)*)<\/div>/<lj-embed id="$2">$3<\/lj-embed>/ig;
|
||||
$txt =~ s/<div\s*(embedid="(\d+)")?\s*class="ljembed"\s*>(((?!<\/div>).)*)<\/div>/<lj-embed id="$2">$3<\/lj-embed>/ig;
|
||||
return $txt;
|
||||
}
|
||||
|
||||
# takes a scalarref to entry text and expands lj-embed tags
|
||||
# REPLACE
|
||||
sub expand_entry {
|
||||
my ($class, $journal, $entryref, %opts) = @_;
|
||||
|
||||
$$entryref =~ s/(<lj\-embed[^>]+\/>)/$class->_expand_tag($journal, $1, $opts{edit}, %opts)/ge;
|
||||
}
|
||||
|
||||
sub _expand_tag {
|
||||
my $class = shift;
|
||||
my $journal = shift;
|
||||
my $tag = shift;
|
||||
my $edit = shift;
|
||||
my %opts = @_;
|
||||
|
||||
my %attrs = $tag =~ /(\w+)="?(\-?\d+)"?/g;
|
||||
|
||||
return '[invalid lj-embed, id is missing]' unless $attrs{id};
|
||||
|
||||
if ($edit) {
|
||||
return '<lj-embed ' . join(' ', map {"$_=\"$attrs{$_}\""} keys %attrs) . ">\n" .
|
||||
$class->module_content(moduleid => $attrs{id}, journalid => $journal->id) .
|
||||
"\n<\/lj-embed>";
|
||||
}
|
||||
elsif ($opts{'content_only'}) {
|
||||
return $class->module_content(moduleid => $attrs{id}, journalid => $journal->{'userid'});
|
||||
}
|
||||
else {
|
||||
@opts{qw /width height/} = @attrs{qw/width height/};
|
||||
return $class->module_iframe_tag($journal, $attrs{id}, %opts)
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
# take a scalarref to a post, parses any lj-embed tags, saves the contents
|
||||
# of the tags and replaces them with a module tag with the id.
|
||||
# REPLACE
|
||||
sub parse_module_embed {
|
||||
my ($class, $journal, $postref, %opts) = @_;
|
||||
|
||||
return unless $postref && $$postref;
|
||||
|
||||
return if LJ::conf_test($LJ::DISABLED{embed_module});
|
||||
|
||||
# fast track out if we don't have to expand anything
|
||||
return unless $$postref =~ /lj\-embed|embed|object/i;
|
||||
|
||||
# do we want to replace with the lj-embed tags or iframes?
|
||||
my $expand = $opts{expand};
|
||||
|
||||
# if this is editing mode, then we want to expand embed tags for editing
|
||||
my $edit = $opts{edit};
|
||||
|
||||
# previews are a special case (don't want to permanantly save to db)
|
||||
my $preview = $opts{preview};
|
||||
|
||||
# deal with old-fashion calls
|
||||
if (($edit || $expand) && ! $preview) {
|
||||
return $class->expand_entry($journal, $postref, %opts);
|
||||
}
|
||||
|
||||
# ok, we can safely parse post text
|
||||
# machine state
|
||||
my $state = REGULAR;
|
||||
my $p = HTML::TokeParser->new($postref);
|
||||
my $newtxt = '';
|
||||
my %embed_attrs = (); # ($eid, $ewidth, $eheight);
|
||||
my $embed = '';
|
||||
my @stack = ();
|
||||
my $next_preview_id = 1;
|
||||
|
||||
while (my $token = $p->get_token) {
|
||||
my ($type, $tag, $attr) = @$token;
|
||||
$tag = lc $tag;
|
||||
my $newstate = undef;
|
||||
my $reconstructed = $class->reconstruct($token);
|
||||
|
||||
if ($state == REGULAR) {
|
||||
if ($tag eq 'lj-embed' && $type eq 'S' && ! $attr->{'/'}) {
|
||||
# <lj-embed ...>, not self-closed
|
||||
# switch to EXPLICIT state
|
||||
$newstate = EXPLICIT;
|
||||
# save embed id, width and height if they do exist in attributes
|
||||
$embed_attrs{id} = $attr->{id} if $attr->{id};
|
||||
$embed_attrs{width} = ($attr->{width} > MAX_WIDTH ? MAX_WIDTH : $attr->{width}) if $attr->{width};
|
||||
$embed_attrs{height} = ($attr->{height} > MAX_HEIGHT ? MAX_HEIGHT : $attr->{height}) if $attr->{height};
|
||||
} elsif (($tag eq 'object' || $tag eq 'embed') && $type eq 'S') {
|
||||
# <object> or <embed>
|
||||
# switch to IMPLICIT state unless it is a self-closed tag
|
||||
unless ($attr->{'/'}) {
|
||||
$newstate = IMPLICIT;
|
||||
# tag balance
|
||||
push @stack, $tag;
|
||||
}
|
||||
# append the tag contents to new embed buffer, so we can convert in to lj-embed later
|
||||
$embed .= $reconstructed;
|
||||
} else {
|
||||
# otherwise stay in REGULAR
|
||||
$newtxt .= $reconstructed;
|
||||
}
|
||||
} elsif ($state == IMPLICIT) {
|
||||
if ($tag eq 'object' || $tag eq 'embed') {
|
||||
if ($type eq 'E') {
|
||||
# </object> or </embed>
|
||||
# update tag balance, but only if we have a valid balance up to this moment
|
||||
pop @stack if $stack[-1] eq $tag;
|
||||
# switch to REGULAR if tags are balanced (stack is empty), stay in IMPLICIT otherwise
|
||||
$newstate = REGULAR unless @stack;
|
||||
} elsif ($type eq 'S') {
|
||||
# <object> or <embed>
|
||||
# mind the tag balance, do not update it in case of a self-closed tag
|
||||
push @stack, $tag unless $attr->{'/'};
|
||||
}
|
||||
}
|
||||
# append to embed buffer
|
||||
$embed .= $reconstructed;
|
||||
|
||||
} elsif ($state == EXPLICIT) {
|
||||
|
||||
if ($tag eq 'lj-embed' && $type eq 'E') {
|
||||
# </lj-embed> - that's the end of explicit embed block, switch to REGULAR
|
||||
$newstate = REGULAR;
|
||||
} else {
|
||||
# continue appending contents to embed buffer
|
||||
$embed .= $reconstructed;
|
||||
}
|
||||
} else {
|
||||
# let's be paranoid
|
||||
die "Invalid state: '$state'";
|
||||
}
|
||||
|
||||
# we decided to switch back to REGULAR and have something in embed buffer
|
||||
# so let's save buffer as an embed module and start all over again
|
||||
if (defined($newstate) && $newstate == REGULAR && $embed) {
|
||||
$embed_attrs{id} = $class->save_module(
|
||||
id => ($preview ? $next_preview_id++ : $embed_attrs{id}),
|
||||
contents => $embed,
|
||||
journal => $journal,
|
||||
preview => $preview,
|
||||
);
|
||||
|
||||
$newtxt .= "<lj-embed " . join(' ', map { exists $embed_attrs{$_} ? "$_=\"$embed_attrs{$_}\"" : () } qw / id width height /) . "/>";
|
||||
|
||||
$embed = '';
|
||||
%embed_attrs = ();
|
||||
}
|
||||
|
||||
# switch the state if we have a new one
|
||||
$state = $newstate if defined $newstate;
|
||||
|
||||
}
|
||||
|
||||
# update passed text
|
||||
$$postref = $newtxt;
|
||||
}
|
||||
|
||||
sub module_iframe_tag {
|
||||
my ($class, $u, $moduleid, %opts) = @_;
|
||||
|
||||
return '' if $LJ::DISABLED{embed_module};
|
||||
|
||||
my $journalid = $u->{'userid'};
|
||||
$moduleid += 0;
|
||||
|
||||
# parse the contents of the module and try to come up with a guess at the width and height of the content
|
||||
my $content = $class->module_content(moduleid => $moduleid, journalid => $journalid);
|
||||
my $preview = $opts{preview};
|
||||
my $width = 0;
|
||||
my $height = 0;
|
||||
my $p = HTML::TokeParser->new(\$content);
|
||||
my $embedcodes;
|
||||
|
||||
# if the content only contains a whitelisted embedded video
|
||||
# then we can skip the placeholders (in some cases)
|
||||
my $no_whitelist = 0;
|
||||
my $found_embed = 0;
|
||||
|
||||
# we don't need to estimate the dimensions if they are provided in tag attributes
|
||||
unless ($opts{width} && $opts{height}) {
|
||||
while (my $token = $p->get_token) {
|
||||
my $type = $token->[0];
|
||||
my $tag = $token->[1] ? lc $token->[1] : '';
|
||||
my $attr = $token->[2]; # hashref
|
||||
|
||||
if ($type eq "S") {
|
||||
my ($elewidth, $eleheight);
|
||||
|
||||
if ($attr->{width}) {
|
||||
$elewidth = $attr->{width}+0;
|
||||
$width = $elewidth if $elewidth > $width;
|
||||
}
|
||||
if ($attr->{height}) {
|
||||
$eleheight = $attr->{height}+0;
|
||||
$height = $eleheight if $eleheight > $height;
|
||||
}
|
||||
|
||||
my $flashvars = $attr->{flashvars};
|
||||
|
||||
if ($tag eq 'object' || $tag eq 'embed') {
|
||||
my $src;
|
||||
next unless $src = $attr->{src};
|
||||
|
||||
# we have an object/embed tag with src, make a fake lj-template object
|
||||
my @tags = (
|
||||
['S', 'lj-template', {
|
||||
name => 'video',
|
||||
(defined $elewidth ? ( width => $width ) : ()),
|
||||
(defined $eleheight ? ( height => $height ) : ()),
|
||||
(defined $flashvars ? ( flashvars => $flashvars ) : ()),
|
||||
}],
|
||||
[ 'T', $src, {}],
|
||||
['E', 'lj-template', {}],
|
||||
);
|
||||
|
||||
$embedcodes = LJ::run_hook('expand_template_video', \@tags);
|
||||
|
||||
$found_embed = 1 if $embedcodes;
|
||||
$found_embed &&= $embedcodes !~ /Invalid video/i;
|
||||
|
||||
$no_whitelist = !$found_embed;
|
||||
} elsif ($tag ne 'param') {
|
||||
$no_whitelist = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# add padding
|
||||
$width += 50 if $width;
|
||||
$height += 50 if $height;
|
||||
}
|
||||
|
||||
# use explicit values if we have them
|
||||
$width = $opts{width} if $opts{width};
|
||||
$height = $opts{height} if $opts{height};
|
||||
|
||||
$width ||= 240;
|
||||
$height ||= 200;
|
||||
|
||||
# some dimension min/maxing
|
||||
$width = 50 if $width < 50;
|
||||
$width = MAX_WIDTH if $width > MAX_WIDTH;
|
||||
$height = 50 if $height < 50;
|
||||
$height = MAX_HEIGHT if $height > MAX_HEIGHT;
|
||||
|
||||
# safari caches state of sub-resources aggressively, so give
|
||||
# each iframe a unique 'name' attribute
|
||||
my $id = qq(name="embed_${journalid}_$moduleid");
|
||||
|
||||
my $auth_token = LJ::eurl(LJ::Auth->sessionless_auth_token('embedcontent', moduleid => $moduleid, journalid => $journalid, preview => $preview,));
|
||||
my $iframe_url = qq {http://$LJ::EMBED_MODULE_DOMAIN/tools/embedcontent.bml?journalid=$journalid&moduleid=$moduleid&preview=$preview&auth_token=$auth_token};
|
||||
my $iframe_tag = qq {<iframe src="$iframe_url" } .
|
||||
qq{width="$width" height="$height" allowtransparency="true" frameborder="0" class="lj_embedcontent" $id></iframe>};
|
||||
|
||||
my $remote = LJ::get_remote();
|
||||
my $do_placeholder;
|
||||
|
||||
if ($remote) {
|
||||
return $iframe_tag if $opts{edit};
|
||||
|
||||
# show placeholder instead of iframe?
|
||||
LJ::load_user_props($remote, "opt_embedplaceholders");
|
||||
my $placeholder_prop = $remote->prop('opt_embedplaceholders');
|
||||
$do_placeholder = $placeholder_prop && $placeholder_prop ne 'N';
|
||||
|
||||
# if placeholder_prop is not set, then show placeholder on a friends
|
||||
# page view UNLESS the embedded content is only one embed/object
|
||||
# tag and it's whitelisted video.
|
||||
my $r = eval { Apache->request };
|
||||
my $view = $r ? $r->notes("view") : '';
|
||||
if (! $placeholder_prop && $view eq 'friends') {
|
||||
# show placeholder if this is not whitelisted video
|
||||
$do_placeholder = 1 if $no_whitelist;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$do_placeholder = $BML::COOKIE{'flashpref'};
|
||||
$do_placeholder = 0 unless $do_placeholder eq "0" || $do_placeholder eq "1";
|
||||
}
|
||||
|
||||
return $iframe_tag unless $do_placeholder;
|
||||
|
||||
my $tmpcontent = $class->module_content(
|
||||
journalid => $journalid,
|
||||
moduleid => $moduleid,
|
||||
0
|
||||
);
|
||||
$tmpcontent =~ s/.+param\s+name\s*?=\s*?"?movie"?\s*value\s*?=\s*?"?//sg; #"
|
||||
$tmpcontent =~ s/("|\s).+//sg; #"
|
||||
$tmpcontent = LJ::ehtml($tmpcontent);
|
||||
|
||||
# placeholder
|
||||
return LJ::placeholder_link(
|
||||
placeholder_html => $iframe_tag,
|
||||
placeholder_link => $iframe_url,
|
||||
width => $width,
|
||||
height => $height,
|
||||
img => "$LJ::IMGPREFIX/videoplaceholder.png",
|
||||
img_title => $tmpcontent,
|
||||
);
|
||||
}
|
||||
|
||||
sub module_content {
|
||||
my ($class, %opts) = @_;
|
||||
|
||||
my $moduleid = $opts{moduleid};
|
||||
croak "No moduleid" unless defined $moduleid;
|
||||
$moduleid += 0;
|
||||
|
||||
my $journalid = $opts{journalid}+0 or croak "No journalid";
|
||||
my $journal = LJ::load_userid($journalid) or die "Invalid userid $journalid";
|
||||
my $preview = $opts{preview};
|
||||
|
||||
# try memcache
|
||||
my $memkey = $class->memkey($journalid, $moduleid, $preview);
|
||||
my $content = LJ::MemCache::get($memkey);
|
||||
my ($dbload, $dbid); # module id from the database
|
||||
unless (defined $content) {
|
||||
my $table_name = ($preview) ? 'embedcontent_preview' : 'embedcontent';
|
||||
($content, $dbid) = $journal->selectrow_array("SELECT content, moduleid FROM $table_name WHERE " .
|
||||
"moduleid=? AND userid=?",
|
||||
undef, $moduleid, $journalid);
|
||||
die $journal->errstr if $journal->err;
|
||||
$dbload = 1;
|
||||
}
|
||||
|
||||
$content ||= '';
|
||||
|
||||
LJ::text_uncompress(\$content) if $content =~ s/^C-//;
|
||||
|
||||
# clean js out of content
|
||||
unless ($LJ::DISABLED{'embedmodule-cleancontent'}) {
|
||||
LJ::CleanHTML::clean(\$content, {
|
||||
addbreaks => 0,
|
||||
tablecheck => 0,
|
||||
mode => 'allow',
|
||||
allow => [qw(object embed)],
|
||||
deny => [qw(script iframe)],
|
||||
remove => [qw(script iframe)],
|
||||
ljcut_disable => 1,
|
||||
cleancss => 0,
|
||||
extractlinks => 0,
|
||||
noautolinks => 1,
|
||||
extractimages => 0,
|
||||
noexpandembedded => 1,
|
||||
transform_embed_nocheck => 1,
|
||||
});
|
||||
}
|
||||
|
||||
# if we got stuff out of database
|
||||
if ($dbload) {
|
||||
# save in memcache
|
||||
LJ::MemCache::set($memkey, $content);
|
||||
|
||||
# if we didn't get a moduleid out of the database then this entry is not valid
|
||||
return defined $dbid ? $content : "[Invalid lj-embed id $moduleid]";
|
||||
}
|
||||
|
||||
# get rid of whitespace around the content
|
||||
return LJ::trim($content) || '';
|
||||
}
|
||||
|
||||
sub memkey {
|
||||
my ($class, $journalid, $moduleid, $preview) = @_;
|
||||
my $pfx = $preview ? 'embedcontpreview' : 'embedcont';
|
||||
return [$journalid, "$pfx:$journalid:$moduleid"];
|
||||
}
|
||||
|
||||
# create a tag string from HTML::TokeParser token
|
||||
sub reconstruct {
|
||||
my $class = shift;
|
||||
my $token = shift;
|
||||
my ($type, $tag, $attr, $attord) = @$token;
|
||||
if ($type eq 'S') {
|
||||
my $txt = "<$tag";
|
||||
my $selfclose;
|
||||
|
||||
# preserve order of attributes. the original order is
|
||||
# in element 4 of $token
|
||||
foreach my $name (@$attord) {
|
||||
if ($name eq '/') {
|
||||
$selfclose = 1;
|
||||
next;
|
||||
}
|
||||
|
||||
# FIXME: ultra ghetto.
|
||||
$attr->{$name} = LJ::no_utf8_flag($attr->{$name});
|
||||
|
||||
$txt .= " $name=\"" . LJ::ehtml($attr->{$name}) . "\"";
|
||||
}
|
||||
$txt .= $selfclose ? " />" : ">";
|
||||
|
||||
} elsif ($type eq 'E') {
|
||||
return "</$tag>";
|
||||
} else { # C, T, D or PI
|
||||
return $tag;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
|
||||
1138
local/cgi-bin/LJ/Entry.pm
Normal file
1138
local/cgi-bin/LJ/Entry.pm
Normal file
File diff suppressed because it is too large
Load Diff
184
local/cgi-bin/LJ/OpenID.pm
Executable file
184
local/cgi-bin/LJ/OpenID.pm
Executable file
@@ -0,0 +1,184 @@
|
||||
package LJ::OpenID;
|
||||
|
||||
use strict;
|
||||
use Digest::SHA1 qw(sha1 sha1_hex);
|
||||
use LWPx::ParanoidAgent;
|
||||
|
||||
BEGIN {
|
||||
$LJ::OPTMOD_OPENID_CONSUMER = $LJ::OPENID_CONSUMER ? eval "use Net::OpenID::Consumer; 1;" : 0;
|
||||
$LJ::OPTMOD_OPENID_SERVER = $LJ::OPENID_SERVER ? eval "use Net::OpenID::Server; 1;" : 0;
|
||||
}
|
||||
|
||||
# returns boolean whether consumer support is enabled and available
|
||||
sub consumer_enabled {
|
||||
return 0 unless $LJ::OPENID_CONSUMER;
|
||||
return $LJ::OPTMOD_OPENID_CONSUMER || eval "use Net::OpenID::Consumer; 1;";
|
||||
}
|
||||
|
||||
# returns boolean whether consumer support is enabled and available
|
||||
sub server_enabled {
|
||||
return 0 unless $LJ::OPENID_SERVER;
|
||||
return $LJ::OPTMOD_OPENID_CONSUMER || eval "use Net::OpenID::Server; 1;";
|
||||
}
|
||||
|
||||
sub server {
|
||||
my ($get, $post) = @_;
|
||||
|
||||
return Net::OpenID::Server->new(
|
||||
compat => $LJ::OPENID_COMPAT,
|
||||
get_args => $get || {},
|
||||
post_args => $post || {},
|
||||
|
||||
get_user => \&LJ::get_remote,
|
||||
is_identity => sub {
|
||||
my ($u, $ident) = @_;
|
||||
return LJ::OpenID::is_identity($u, $ident, $get);
|
||||
},
|
||||
is_trusted => \&LJ::OpenID::is_trusted,
|
||||
|
||||
setup_url => "$LJ::SITEROOT/openid/approve.bml",
|
||||
|
||||
server_secret => \&LJ::OpenID::server_secret,
|
||||
secret_gen_interval => 3600,
|
||||
secret_expire_age => 86400 * 14,
|
||||
);
|
||||
}
|
||||
|
||||
# Returns a Consumer object
|
||||
# When planning to verify identity, needs GET
|
||||
# arguments passed in
|
||||
sub consumer {
|
||||
my $get_args = shift || {};
|
||||
|
||||
my $ua;
|
||||
unless ($LJ::IS_DEV_SERVER) {
|
||||
$ua = LWPx::ParanoidAgent->new(
|
||||
timeout => 10,
|
||||
max_size => 1024*300,
|
||||
);
|
||||
}
|
||||
|
||||
my $csr = Net::OpenID::Consumer->new(
|
||||
ua => $ua,
|
||||
args => $get_args,
|
||||
cache => eval { LJ::MemCache::get_memcache() },
|
||||
consumer_secret => \&LJ::OpenID::consumer_secret,
|
||||
debug => $LJ::IS_DEV_SERVER || 0,
|
||||
required_root => $LJ::SITEROOT,
|
||||
);
|
||||
|
||||
return $csr;
|
||||
}
|
||||
|
||||
sub consumer_secret {
|
||||
my $time = shift;
|
||||
return server_secret($time - $time % 3600);
|
||||
}
|
||||
|
||||
sub server_secret {
|
||||
my $time = shift;
|
||||
my ($t2, $secret) = LJ::get_secret($time);
|
||||
die "ASSERT: didn't get t2 (t1=$time)" unless $t2;
|
||||
die "ASSERT: didn't get secret (t2=$t2)" unless $secret;
|
||||
die "ASSERT: time($time) != t2($t2)\n" unless $t2 == $time;
|
||||
return $secret;
|
||||
}
|
||||
|
||||
sub is_trusted {
|
||||
my ($u, $trust_root, $is_identity) = @_;
|
||||
return 0 unless $u;
|
||||
# we always look up $is_trusted, even if $is_identity is false, to avoid timing attacks
|
||||
|
||||
my $dbh = LJ::get_db_writer();
|
||||
my ($endpointid, $duration) = $dbh->selectrow_array("SELECT t.endpoint_id, t.duration ".
|
||||
"FROM openid_trust t, openid_endpoint e ".
|
||||
"WHERE t.userid=? AND t.endpoint_id=e.endpoint_id AND e.url=?",
|
||||
undef, $u->{userid}, $trust_root);
|
||||
return 0 unless $endpointid;
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub is_identity {
|
||||
my ($u, $ident, $get) = @_;
|
||||
return 0 unless $u && $u->{journaltype} eq "P";
|
||||
|
||||
my $user = $u->{user};
|
||||
return 1 if
|
||||
$ident eq "$LJ::SITEROOT/users/$user/" ||
|
||||
$ident eq "$LJ::SITEROOT/~$user/" ||
|
||||
$ident eq "http://$user.$LJ::USER_DOMAIN/";
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub getmake_endpointid {
|
||||
my $site = shift;
|
||||
|
||||
my $dbh = LJ::get_db_writer()
|
||||
or return undef;
|
||||
|
||||
my $rv = $dbh->do("INSERT IGNORE INTO openid_endpoint (url) VALUES (?)", undef, $site);
|
||||
my $end_id;
|
||||
if ($rv > 0) {
|
||||
$end_id = $dbh->{'mysql_insertid'};
|
||||
} else {
|
||||
$end_id = $dbh->selectrow_array("SELECT endpoint_id FROM openid_endpoint WHERE url=?",
|
||||
undef, $site);
|
||||
}
|
||||
return $end_id;
|
||||
}
|
||||
|
||||
sub add_trust {
|
||||
my ($u, $site) = @_;
|
||||
|
||||
my $end_id = LJ::OpenID::getmake_endpointid($site)
|
||||
or return 0;
|
||||
|
||||
my $dbh = LJ::get_db_writer()
|
||||
or return undef;
|
||||
|
||||
my $rv = $dbh->do("REPLACE INTO openid_trust (userid, endpoint_id, duration, trust_time) ".
|
||||
"VALUES (?,?,?,UNIX_TIMESTAMP())", undef, $u->{userid}, $end_id, "always");
|
||||
return $rv;
|
||||
}
|
||||
|
||||
# From Digest::HMAC
|
||||
sub hmac_sha1_hex {
|
||||
unpack("H*", &hmac_sha1);
|
||||
}
|
||||
sub hmac_sha1 {
|
||||
hmac($_[0], $_[1], \&sha1, 64);
|
||||
}
|
||||
sub hmac {
|
||||
my($data, $key, $hash_func, $block_size) = @_;
|
||||
$block_size ||= 64;
|
||||
$key = &$hash_func($key) if length($key) > $block_size;
|
||||
|
||||
my $k_ipad = $key ^ (chr(0x36) x $block_size);
|
||||
my $k_opad = $key ^ (chr(0x5c) x $block_size);
|
||||
|
||||
&$hash_func($k_opad, &$hash_func($k_ipad, $data));
|
||||
}
|
||||
|
||||
# Returns 1 if destination identity server
|
||||
# is blocked
|
||||
sub blocked_hosts {
|
||||
my $csr = shift;
|
||||
|
||||
return do { my $dummy = 0; \$dummy; } if $LJ::IS_DEV_SERVER;
|
||||
|
||||
my $tried_local_id = 0;
|
||||
$csr->ua->blocked_hosts(
|
||||
sub {
|
||||
my $dest = shift;
|
||||
|
||||
if ($dest =~ /((^|\.)\Q$LJ::DOMAIN\E$|demotivation\.me|anonymity\.com)/i) {
|
||||
$tried_local_id = 1;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
return \$tried_local_id;
|
||||
}
|
||||
|
||||
1;
|
||||
2739
local/cgi-bin/LJ/S2.pm
Executable file
2739
local/cgi-bin/LJ/S2.pm
Executable file
File diff suppressed because it is too large
Load Diff
232
local/cgi-bin/LJ/S2/DayPage.pm
Executable file
232
local/cgi-bin/LJ/S2/DayPage.pm
Executable file
@@ -0,0 +1,232 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
|
||||
use strict;
|
||||
package LJ::S2;
|
||||
|
||||
sub DayPage
|
||||
{
|
||||
my ($u, $remote, $opts) = @_;
|
||||
|
||||
my $p = Page($u, $opts);
|
||||
$p->{'_type'} = "DayPage";
|
||||
$p->{'view'} = "day";
|
||||
$p->{'entries'} = [];
|
||||
|
||||
my $user = $u->{'user'};
|
||||
my $journalbase = LJ::journal_base($user, $opts->{'vhost'});
|
||||
|
||||
if ($u->{'journaltype'} eq "R" && $u->{'renamedto'} ne "") {
|
||||
$opts->{'redir'} = LJ::journal_base($u->{'renamedto'}, $opts->{'vhost'}) .
|
||||
"/calendar" . $opts->{'pathextra'};
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ($u->{'opt_blockrobots'}) {
|
||||
$p->{'head_content'} .= LJ::robot_meta_tags();
|
||||
}
|
||||
|
||||
my $get = $opts->{'getargs'};
|
||||
|
||||
my $month = $get->{'month'};
|
||||
my $day = $get->{'day'};
|
||||
my $year = $get->{'year'};
|
||||
my @errors = ();
|
||||
|
||||
if ($opts->{'pathextra'} =~ m!^/(\d\d\d\d)/(\d\d)/(\d\d)\b!) {
|
||||
($month, $day, $year) = ($2, $3, $1);
|
||||
}
|
||||
|
||||
$opts->{'errors'} = [];
|
||||
if ($year !~ /^\d+$/) { push @{$opts->{'errors'}}, "Corrupt or non-existant year."; }
|
||||
if ($month !~ /^\d+$/) { push @{$opts->{'errors'}}, "Corrupt or non-existant month."; }
|
||||
if ($day !~ /^\d+$/) { push @{$opts->{'errors'}}, "Corrupt or non-existant day."; }
|
||||
if ($month < 1 || $month > 12 || int($month) != $month) { push @{$opts->{'errors'}}, "Invalid month."; }
|
||||
if ($year < 1970 || $year > 2038 || int($year) != $year) { push @{$opts->{'errors'}}, "Invalid year: $year"; }
|
||||
if ($day < 1 || $day > 31 || int($day) != $day) { push @{$opts->{'errors'}}, "Invalid day."; }
|
||||
if (scalar(@{$opts->{'errors'}})==0 && $day > LJ::days_in_month($month, $year)) { push @{$opts->{'errors'}}, "That month doesn't have that many days."; }
|
||||
return if @{$opts->{'errors'}};
|
||||
|
||||
$p->{'date'} = Date($year, $month, $day);
|
||||
# mysqldate_to_time(): ^(\d\d\d\d)-(\d\d)-(\d\d)(?: (\d\d):(\d\d)(?::(\d\d))?)?$/ -> unixtime, with check.
|
||||
# why not using get_recent_items() ?
|
||||
|
||||
#use Time::HiRes qw(gettimeofday tv_interval);
|
||||
#my $t0 = [gettimeofday];
|
||||
#my @elapsed;
|
||||
#push @elapsed, (tv_interval ($t0));
|
||||
#print STDERR "@elapsed \n";
|
||||
|
||||
my $secwhere = "AND security='public'";
|
||||
my $viewall = 0;
|
||||
my $viewsome = 0; # see public posts from suspended users
|
||||
if ($remote) {
|
||||
|
||||
# do they have the viewall priv?
|
||||
if ($get->{'viewall'} && LJ::check_priv($remote, "canview")) {
|
||||
LJ::statushistory_add($u->{'userid'}, $remote->{'userid'},
|
||||
"viewall", "day: $user, statusvis: $u->{'statusvis'}");
|
||||
$viewall = LJ::check_priv($remote, 'canview', '*');
|
||||
$viewsome = $viewall || LJ::check_priv($remote, 'canview', 'suspended');
|
||||
}
|
||||
|
||||
if ($remote->{'userid'} == $u->{'userid'} || $viewall) {
|
||||
$secwhere = ""; # see everything
|
||||
} elsif ($remote->{'journaltype'} eq 'P' || $remote->{'journaltype'} eq 'I') {
|
||||
my $gmask = LJ::get_groupmask($u, $remote);
|
||||
$secwhere = "AND (security='public' OR (security='usemask' AND allowmask & $gmask))"
|
||||
if $gmask;
|
||||
}
|
||||
}
|
||||
|
||||
my $dbcr = LJ::get_cluster_reader($u);
|
||||
unless ($dbcr) {
|
||||
push @{$opts->{'errors'}}, "Database temporarily unavailable";
|
||||
return;
|
||||
}
|
||||
|
||||
# load the log items
|
||||
my $dateformat = "%Y %m %d %H %i %s %w"; # yyyy mm dd hh mm ss day_of_week
|
||||
my $sth = $dbcr->prepare("SELECT jitemid AS itemid, posterid, security, DATE_FORMAT(eventtime, \"$dateformat\") AS 'alldatepart', anum ".
|
||||
"FROM log2 " .
|
||||
"WHERE journalid=$u->{'userid'} AND year=$year AND month=$month AND day=$day $secwhere " .
|
||||
"ORDER BY eventtime, logtime LIMIT 200");
|
||||
$sth->execute;
|
||||
|
||||
my @items;
|
||||
push @items, $_ while $_ = $sth->fetchrow_hashref;
|
||||
#push @elapsed, (tv_interval ($t0));
|
||||
|
||||
LJ::fill_items_with_text_props(\@items, $u);
|
||||
|
||||
# load 'opt_ljcut_disable_lastn' prop for $remote.
|
||||
LJ::load_user_props($remote, "opt_ljcut_disable_lastn");
|
||||
|
||||
my (%apu, %apu_lite); # alt poster users; UserLite objects
|
||||
foreach (@items) {
|
||||
next unless $_->{'posterid'} != $u->{'userid'};
|
||||
$apu{$_->{'posterid'}} = undef;
|
||||
}
|
||||
if (%apu) {
|
||||
LJ::load_userids_multiple([map { $_, \$apu{$_} } keys %apu], [$u]);
|
||||
$apu_lite{$_} = UserLite($apu{$_}) foreach keys %apu;
|
||||
}
|
||||
|
||||
my $userlite_journal = UserLite($u);
|
||||
#push @elapsed, (tv_interval ($t0));
|
||||
|
||||
ENTRY:
|
||||
foreach my $item (@items)
|
||||
{
|
||||
my ($posterid, $itemid, $security, $alldatepart, $anum) =
|
||||
map { $item->{$_} } qw(posterid itemid security alldatepart anum);
|
||||
|
||||
my $props = $item->{'props'};
|
||||
|
||||
my $replycount = $props->{'replycount'};
|
||||
my $subject = $item->{'text'}->[0];
|
||||
my $text = $item->{'text'}->[1];
|
||||
if ($get->{'nohtml'}) {
|
||||
# quote all non-LJ tags
|
||||
$subject =~ s{<(?!/?lj)(.*?)>} {<$1>}gi;
|
||||
$text =~ s{<(?!/?lj)(.*?)>} {<$1>}gi;
|
||||
}
|
||||
|
||||
# don't show posts from suspended users
|
||||
next ENTRY if $apu{$posterid} && $apu{$posterid}->{'statusvis'} eq 'S' && ! $viewsome;
|
||||
|
||||
LJ::CleanHTML::clean_subject(\$subject) if $subject;
|
||||
|
||||
my $ditemid = $itemid*256 + $anum;
|
||||
|
||||
LJ::CleanHTML::clean_event(\$text, { 'preformatted' => $props->{'opt_preformatted'},
|
||||
'cuturl' => LJ::item_link($u, $itemid, $anum),
|
||||
'ljcut_disable' => $remote->{'opt_ljcut_disable_lastn'}, });
|
||||
LJ::expand_embedded($u, $ditemid, $remote, \$text);
|
||||
|
||||
my $nc = "";
|
||||
$nc .= "nc=$replycount" if $replycount; # && $remote && $remote->{'opt_nctalklinks'};
|
||||
|
||||
my $permalink = "$journalbase/$ditemid.html";
|
||||
my $readurl = $permalink;
|
||||
$readurl .= "?$nc" if $nc;
|
||||
my $posturl = $permalink . "?mode=reply";
|
||||
|
||||
my $comments = CommentInfo({
|
||||
'read_url' => $readurl,
|
||||
'post_url' => $posturl,
|
||||
'count' => $replycount,
|
||||
'maxcomments' => ($replycount >= LJ::get_cap($u, 'maxcomments')) ? 1 : 0,
|
||||
'enabled' => ($u->{'opt_showtalklinks'} eq "Y" && ! $props->{'opt_nocomments'}) ? 1 : 0,
|
||||
'screened' => ($props->{'hasscreened'} && $remote &&
|
||||
($remote->{'user'} eq $u->{'user'} || LJ::can_manage($remote, $u))) ? 1 : 0,
|
||||
});
|
||||
|
||||
my $userlite_poster = $userlite_journal;
|
||||
my $pu = $u;
|
||||
if ($u->{'userid'} != $posterid) {
|
||||
$userlite_poster = $apu_lite{$posterid} or die "No apu_lite for posterid=$posterid";
|
||||
$pu = $apu{$posterid};
|
||||
}
|
||||
my $userpic = Image_userpic($pu, 0, $props->{'picture_keyword'});
|
||||
|
||||
my $entry = Entry($u, {
|
||||
'subject' => $subject,
|
||||
'text' => $text,
|
||||
'dateparts' => $alldatepart,
|
||||
'security' => $security,
|
||||
'props' => $props,
|
||||
'itemid' => $ditemid,
|
||||
'journal' => $userlite_journal,
|
||||
'poster' => $userlite_poster,
|
||||
'comments' => $comments,
|
||||
'userpic' => $userpic,
|
||||
'permalink_url' => $permalink,
|
||||
'enable_tags_compatibility' => [$opts->{enable_tags_compatibility}, $opts->{ctx}],
|
||||
});
|
||||
|
||||
push @{$p->{'entries'}}, $entry;
|
||||
}
|
||||
#push @elapsed, (tv_interval ($t0));
|
||||
#print STDERR "@elapsed \n";
|
||||
|
||||
|
||||
if (@{$p->{'entries'}}) {
|
||||
$p->{'has_entries'} = 1;
|
||||
$p->{'entries'}->[0]->{'new_day'} = 1;
|
||||
$p->{'entries'}->[-1]->{'end_day'} = 1;
|
||||
}
|
||||
|
||||
# calculate previous day
|
||||
my $pdyear = $year;
|
||||
my $pdmonth = $month;
|
||||
my $pdday = $day-1;
|
||||
if ($pdday < 1)
|
||||
{
|
||||
if (--$pdmonth < 1)
|
||||
{
|
||||
$pdmonth = 12;
|
||||
$pdyear--;
|
||||
}
|
||||
$pdday = LJ::days_in_month($pdmonth, $pdyear);
|
||||
}
|
||||
|
||||
# calculate next day
|
||||
my $nxyear = $year;
|
||||
my $nxmonth = $month;
|
||||
my $nxday = $day+1;
|
||||
if ($nxday > LJ::days_in_month($nxmonth, $nxyear))
|
||||
{
|
||||
$nxday = 1;
|
||||
if (++$nxmonth > 12) { ++$nxyear; $nxmonth=1; }
|
||||
}
|
||||
|
||||
$p->{'prev_url'} = "$u->{'_journalbase'}/" . sprintf("%04d/%02d/%02d/", $pdyear, $pdmonth, $pdday);
|
||||
$p->{'prev_date'} = Date($pdyear, $pdmonth, $pdday);
|
||||
$p->{'next_url'} = "$u->{'_journalbase'}/" . sprintf("%04d/%02d/%02d/", $nxyear, $nxmonth, $nxday);
|
||||
$p->{'next_date'} = Date($nxyear, $nxmonth, $nxday);
|
||||
|
||||
return $p;
|
||||
}
|
||||
|
||||
1;
|
||||
432
local/cgi-bin/LJ/S2/EntryPage.pm
Executable file
432
local/cgi-bin/LJ/S2/EntryPage.pm
Executable file
@@ -0,0 +1,432 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
|
||||
use strict;
|
||||
package LJ::S2;
|
||||
|
||||
sub EntryPage
|
||||
{
|
||||
my ($u, $remote, $opts) = @_;
|
||||
|
||||
my $get = $opts->{'getargs'};
|
||||
|
||||
my $p = Page($u, $opts);
|
||||
$p->{'_type'} = "EntryPage";
|
||||
$p->{'view'} = "entry";
|
||||
$p->{'comments'} = [];
|
||||
$p->{'comment_pages'} = undef;
|
||||
|
||||
# setup viewall options
|
||||
my ($viewall, $viewsome) = (0, 0);
|
||||
if ($get->{viewall} && LJ::check_priv($remote, 'canview')) {
|
||||
# we don't log here, as we don't know what entry we're viewing yet. the logging
|
||||
# is done when we call EntryPage_entry below.
|
||||
$viewall = LJ::check_priv($remote, 'canview', '*');
|
||||
$viewsome = $viewall || LJ::check_priv($remote, 'canview', 'suspended');
|
||||
}
|
||||
|
||||
my ($entry, $s2entry) = EntryPage_entry($u, $remote, $opts);
|
||||
return if $opts->{'suspendeduser'};
|
||||
return if $opts->{'handler_return'};
|
||||
|
||||
$p->{'multiform_on'} = $remote &&
|
||||
($remote->{'userid'} == $u->{'userid'} ||
|
||||
$remote->{'userid'} == $entry->{'posterid'} ||
|
||||
LJ::can_manage($remote, $u));
|
||||
|
||||
my $itemid = $entry->{'itemid'};
|
||||
my $ditemid = $entry->{'itemid'} * 256 + $entry->{'anum'};
|
||||
my $permalink = LJ::journal_base($u) . "/$ditemid.html";
|
||||
my $stylemine = $get->{'style'} eq "mine" ? "style=mine" : "";
|
||||
|
||||
if ($u->{'journaltype'} eq "R" && $u->{'renamedto'} ne "") {
|
||||
$opts->{'redir'} = LJ::journal_base($u->{'renamedto'}, $opts->{'vhost'}) .
|
||||
"/$ditemid.html" . $opts->{'pathextra'};
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ($u->{'opt_blockrobots'}) {
|
||||
$p->{'head_content'} .= LJ::robot_meta_tags();
|
||||
}
|
||||
if ($LJ::UNICODE) {
|
||||
$p->{'head_content'} .= '<meta http-equiv="Content-Type" content="text/html; charset='.$opts->{'saycharset'}."\" />\n";
|
||||
}
|
||||
|
||||
$p->{'entry'} = $s2entry;
|
||||
|
||||
# add the comments
|
||||
my %userpic;
|
||||
my %user;
|
||||
my $copts = {
|
||||
'thread' => ($get->{'thread'} >> 8),
|
||||
'page' => $get->{'page'},
|
||||
'view' => $get->{'view'},
|
||||
'userpicref' => \%userpic,
|
||||
'userref' => \%user,
|
||||
# user object is cached from call just made in EntryPage_entry
|
||||
'up' => LJ::load_user($s2entry->{'poster'}->{'username'}),
|
||||
'viewall' => $viewall,
|
||||
|
||||
# Okuklivanie tredov - daem upravlenie pol'zovatelyu -
|
||||
'page_size' => $get->{'page_size'},
|
||||
'max_subjects' => $get->{'max_subjects'},
|
||||
'threading_point' => $get->{'threading_point'},
|
||||
'uncollapse' => $get->{'uncollapse'},
|
||||
};
|
||||
|
||||
my $userlite_journal = UserLite($u);
|
||||
|
||||
my @comments = LJ::Talk::load_comments($u, $remote, "L", $itemid, $copts);
|
||||
|
||||
my $pics = LJ::Talk::get_subjecticons()->{'pic'}; # hashref of imgname => { w, h, img }
|
||||
my $convert_comments = sub {
|
||||
my ($self, $destlist, $srclist, $depth) = @_;
|
||||
|
||||
foreach my $com (@$srclist) {
|
||||
my $dtalkid = $com->{'talkid'} * 256 + $entry->{'anum'};
|
||||
my $text = $com->{'body'};
|
||||
if ($get->{'nohtml'}) {
|
||||
# quote all non-LJ tags
|
||||
$text =~ s{<(?!/?lj)(.*?)>} {<$1>}gi;
|
||||
}
|
||||
LJ::CleanHTML::clean_comment(\$text, { 'preformatted' => $com->{'props'}->{'opt_preformatted'},
|
||||
'anon_comment' => !$com->{posterid}});
|
||||
|
||||
# local time in mysql format to gmtime
|
||||
my $datetime = DateTime_unix(LJ::mysqldate_to_time($com->{'datepost'}));
|
||||
if ($datetime == 0) {
|
||||
$datetime = "Invalid date";
|
||||
}
|
||||
|
||||
my $subject_icon = undef;
|
||||
if (my $si = $com->{'props'}->{'subjecticon'}) {
|
||||
my $pic = $pics->{$si};
|
||||
$subject_icon = Image("$LJ::IMGPREFIX/talk/$pic->{'img'}",
|
||||
$pic->{'w'}, $pic->{'h'}) if $pic;
|
||||
}
|
||||
|
||||
my $comment_userpic;
|
||||
if (my $pic = $userpic{$com->{'picid'}}) {
|
||||
$comment_userpic = Image("$LJ::USERPIC_ROOT/$com->{'picid'}/$pic->{'userid'}",
|
||||
$pic->{'width'}, $pic->{'height'});
|
||||
}
|
||||
|
||||
my $reply_url = LJ::Talk::talkargs($permalink, "replyto=$dtalkid", $stylemine);
|
||||
|
||||
my $par_url;
|
||||
if ($com->{'parenttalkid'}) {
|
||||
my $dparent = ($com->{'parenttalkid'} << 8) + $entry->{'anum'};
|
||||
$par_url = LJ::Talk::talkargs($permalink, "thread=$dparent", $stylemine) . "#t$dparent";
|
||||
}
|
||||
|
||||
my $poster;
|
||||
if ($com->{'posterid'}) {
|
||||
if ($user{$com->{'posterid'}}) {
|
||||
$poster = UserLite($user{$com->{'posterid'}});
|
||||
} else {
|
||||
$poster = {
|
||||
'_type' => 'UserLite',
|
||||
'username' => $com->{'userpost'},
|
||||
'name' => $com->{'userpost'}, # we don't have this, so fake it
|
||||
'journal_type' => 'P', # fake too, but only people can post, so correct
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
my $s2com = {
|
||||
'_type' => 'Comment',
|
||||
'journal' => $userlite_journal,
|
||||
'metadata' => {
|
||||
'picture_keyword' => $com->{'props'}->{'picture_keyword'},
|
||||
},
|
||||
'permalink_url' => "$permalink?thread=$dtalkid#t$dtalkid",
|
||||
'reply_url' => $reply_url,
|
||||
'poster' => $poster,
|
||||
'replies' => [],
|
||||
'subject' => LJ::ehtml($com->{'subject'}),
|
||||
'subject_icon' => $subject_icon,
|
||||
'talkid' => $dtalkid,
|
||||
'text' => $text,
|
||||
'userpic' => $comment_userpic,
|
||||
'time' => $datetime,
|
||||
'tags' => [],
|
||||
'full' => $com->{'_loaded'} ? 1 : 0,
|
||||
'depth' => $depth,
|
||||
'parent_url' => $par_url,
|
||||
'screened' => $com->{'state'} eq "S" ? 1 : 0,
|
||||
'frozen' => $com->{'state'} eq "F" ? 1 : 0,
|
||||
'link_keyseq' => [ 'delete_comment' ],
|
||||
'anchor' => "t$dtalkid",
|
||||
'dom_id' => "ljcmt$dtalkid",
|
||||
};
|
||||
|
||||
# don't show info from suspended users
|
||||
# FIXME: ideally the load_comments should only return these
|
||||
# items if there are children, otherwise they should be hidden entirely
|
||||
my $pu = $com->{'posterid'} ? $user{$com->{'posterid'}} : undef;
|
||||
if ($pu && $pu->{'statusvis'} eq "S" && !$viewsome) {
|
||||
$s2com->{'text'} = "";
|
||||
$s2com->{'subject'} = "";
|
||||
$s2com->{'full'} = 0;
|
||||
$s2com->{'subject_icon'} = undef;
|
||||
$s2com->{'userpic'} = undef;
|
||||
}
|
||||
|
||||
# Conditionally add more links to the keyseq
|
||||
my $link_keyseq = $s2com->{'link_keyseq'};
|
||||
push @$link_keyseq, $s2com->{'screened'} ? 'unscreen_comment' : 'screen_comment';
|
||||
push @$link_keyseq, $s2com->{'frozen'} ? 'unfreeze_thread' : 'freeze_thread';
|
||||
|
||||
if (@{$com->{'children'}}) {
|
||||
$s2com->{'thread_url'} = LJ::Talk::talkargs($permalink, "thread=$dtalkid", $stylemine) . "#t$dtalkid";
|
||||
}
|
||||
|
||||
# add the poster_ip metadata if remote user has
|
||||
# access to see it.
|
||||
$s2com->{'metadata'}->{'poster_ip'} = $com->{'props'}->{'poster_ip'} if
|
||||
($com->{'props'}->{'poster_ip'} && $remote &&
|
||||
($remote->{'userid'} == $entry->{'posterid'} ||
|
||||
LJ::can_manage($remote, $u) || $viewall));
|
||||
|
||||
push @$destlist, $s2com;
|
||||
|
||||
$self->($self, $s2com->{'replies'}, $com->{'children'}, $depth+1);
|
||||
}
|
||||
};
|
||||
$p->{'comments'} = [];
|
||||
$convert_comments->($convert_comments, $p->{'comments'}, \@comments, 1);
|
||||
|
||||
# prepare the javascript data structure to put in the top of the page
|
||||
# if the remote user is a manager of the comments
|
||||
my $do_commentmanage_js = $p->{'multiform_on'};
|
||||
if ($LJ::DISABLED{'commentmanage'}) {
|
||||
if (ref $LJ::DISABLED{'commentmanage'} eq "CODE") {
|
||||
$do_commentmanage_js = $LJ::DISABLED{'commentmanage'}->($remote);
|
||||
} else {
|
||||
$do_commentmanage_js = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ($do_commentmanage_js) {
|
||||
my $js = "<script>\n// don't crawl this. read http://www.livejournal.com/developer/exporting.bml\n";
|
||||
$js .= "var LJ_cmtinfo = {\n";
|
||||
my $canAdmin = LJ::can_manage($remote, $u) ? 1 : 0;
|
||||
$js .= "\tjournal: '$u->{user}',\n";
|
||||
$js .= "\tcanAdmin: $canAdmin,\n";
|
||||
$js .= "\tremote: '$remote->{user}',\n" if $remote;
|
||||
my $recurse = sub {
|
||||
my ($self, $array) = @_;
|
||||
foreach my $i (@$array) {
|
||||
my $has_threads = scalar @{$i->{'replies'}};
|
||||
my $poster = $i->{'poster'} ? $i->{'poster'}{'username'} : "";
|
||||
my $child_ids = join(',', map { $_->{'talkid'} } @{$i->{'replies'}});
|
||||
$js .= "\t$i->{'talkid'}: { rc: [$child_ids], u: '$poster' },\n";
|
||||
$self->($self, $i->{'replies'}) if $has_threads;
|
||||
}
|
||||
};
|
||||
$recurse->($recurse, $p->{'comments'});
|
||||
chop $js; chop $js; # remove final ",\n". stupid javascript.
|
||||
$js .= "\n};\n" .
|
||||
"var LJVAR;\n".
|
||||
"if (!LJVAR) LJVAR = new Object();\n".
|
||||
"LJVAR.imgprefix = \"$LJ::IMGPREFIX\";\n".
|
||||
"</script>\n";
|
||||
$p->{'head_content'} .= $js;
|
||||
$p->{'head_content'} .= "<script src='$LJ::SITEROOT/js/commentmanage.js'></script>\n";
|
||||
|
||||
}
|
||||
|
||||
|
||||
$p->{'viewing_thread'} = $get->{'thread'} ? 1 : 0;
|
||||
|
||||
# default values if there were no comments, because
|
||||
# LJ::Talk::load_comments() doesn't provide them.
|
||||
if ($copts->{'out_error'} eq 'noposts') {
|
||||
$copts->{'out_pages'} = $copts->{'out_page'} = 1;
|
||||
$copts->{'out_items'} = 0;
|
||||
$copts->{'out_itemfirst'} = $copts->{'out_itemlast'} = undef;
|
||||
}
|
||||
|
||||
$p->{'comment_pages'} = ItemRange({
|
||||
'all_subitems_displayed' => ($copts->{'out_pages'} == 1),
|
||||
'current' => $copts->{'out_page'},
|
||||
'from_subitem' => $copts->{'out_itemfirst'},
|
||||
'num_subitems_displayed' => scalar @comments,
|
||||
'to_subitem' => $copts->{'out_itemlast'},
|
||||
'total' => $copts->{'out_pages'},
|
||||
'total_subitems' => $copts->{'out_items'},
|
||||
'_url_of' => sub { return "$permalink?page=" . int($_[0]) .
|
||||
($stylemine ? "&$stylemine" : ''); },
|
||||
});
|
||||
|
||||
return $p;
|
||||
}
|
||||
|
||||
sub EntryPage_fast_check
|
||||
{
|
||||
my ($u, $view, $remote, $opts) = @_;
|
||||
|
||||
return unless ($view eq "entry" || $view eq "reply");
|
||||
|
||||
my $get = $opts->{'getargs'};
|
||||
|
||||
my $r = $opts->{'r'};
|
||||
my $uri = $r->uri;
|
||||
|
||||
my ($ditemid, $itemid, $anum);
|
||||
unless ($uri =~ /(\d+)\.html/) {
|
||||
$opts->{'handler_return'} = 404;
|
||||
return;
|
||||
}
|
||||
|
||||
$ditemid = $1;
|
||||
$anum = $ditemid % 256;
|
||||
$itemid = $ditemid >> 8;
|
||||
|
||||
my $entry = LJ::Talk::get_journal_item($u, $itemid, "props_only");
|
||||
unless ($entry && $entry->{'anum'} == $anum) {
|
||||
$opts->{'handler_return'} = 404;
|
||||
return;
|
||||
}
|
||||
my $props = $entry->{'props'};
|
||||
|
||||
# do they have the viewall priv?
|
||||
my $viewall = 0;
|
||||
my $viewsome = 0;
|
||||
if ($get->{'viewall'} && LJ::check_priv($remote, "canview")) {
|
||||
LJ::statushistory_add($u->{'userid'}, $remote->{'userid'},
|
||||
"viewall", "entry: $u->{'user'}, itemid: $itemid, statusvis: $u->{'statusvis'}");
|
||||
$viewall = LJ::check_priv($remote, 'canview', '*');
|
||||
$viewsome = $viewall || LJ::check_priv($remote, 'canview', 'suspended');
|
||||
}
|
||||
|
||||
# check using normal rules
|
||||
unless (LJ::can_view($remote, $entry) || $viewall) {
|
||||
$opts->{'handler_return'} = 403;
|
||||
return;
|
||||
}
|
||||
|
||||
my $pu = $u;
|
||||
if ($entry->{'posterid'} != $entry->{'ownerid'}) {
|
||||
$pu = LJ::load_userid($entry->{'posterid'});
|
||||
}
|
||||
if (($pu && $pu->{'statusvis'} eq 'S') && !$viewsome) {
|
||||
$opts->{'suspendeduser'} = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
# check If-Modified-Since
|
||||
my $lastmod = $props->{'commentalter'};
|
||||
my $revisiontime = $props->{' revtime'};
|
||||
$lastmod = $revisiontime if $revisiontime && $revisiontime > $lastmod;
|
||||
|
||||
my $ims = $r->header_in('If-Modified-Since');
|
||||
if ($ims) {
|
||||
my $theirtime = LJ::http_to_time($ims);
|
||||
if ($theirtime >= $lastmod && !$remote) {
|
||||
# only for anonymous: logged users will be checked by Etag for exact match
|
||||
# reply special: uniq challange string for regular users
|
||||
if ($view eq "entry" || ($view eq "reply" && $r->header_in('User-Agent') =~ /$LJ::ROBOTS_REGEXP/)) {
|
||||
|
||||
$opts->{'notmodified'} = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
$r->header_out("Last-Modified", LJ::time_to_http($lastmod));
|
||||
}
|
||||
|
||||
sub EntryPage_entry
|
||||
{
|
||||
my ($u, $remote, $opts) = @_;
|
||||
|
||||
### NB! EntryPage_fast_check was previously called, so all checks passed.
|
||||
|
||||
my $get = $opts->{'getargs'};
|
||||
|
||||
my $r = $opts->{'r'};
|
||||
my $uri = $r->uri;
|
||||
|
||||
my ($ditemid, $itemid, $anum);
|
||||
unless ($uri =~ /(\d+)\.html/) {
|
||||
$opts->{'handler_return'} = 404;
|
||||
return;
|
||||
}
|
||||
|
||||
$ditemid = $1;
|
||||
$anum = $ditemid % 256;
|
||||
$itemid = $ditemid >> 8;
|
||||
|
||||
my $entry = LJ::Talk::get_journal_item($u, $itemid);
|
||||
unless ($entry && $entry->{'anum'} == $anum) {
|
||||
$opts->{'handler_return'} = 404;
|
||||
return;
|
||||
}
|
||||
### more checks skipped ###
|
||||
|
||||
my $props = $entry->{'props'};
|
||||
|
||||
my $userlite_journal = UserLite($u);
|
||||
my $userlite_poster = $userlite_journal;
|
||||
my $pu = $u;
|
||||
if ($entry->{'posterid'} != $entry->{'ownerid'}) {
|
||||
$pu = LJ::load_userid($entry->{'posterid'});
|
||||
$userlite_poster = UserLite($pu);
|
||||
}
|
||||
|
||||
my $replycount = $props->{'replycount'};
|
||||
my $nc = "";
|
||||
$nc .= "nc=$replycount" if $replycount; # && $remote && $remote->{'opt_nctalklinks'};
|
||||
|
||||
my $stylemine = $get->{'style'} eq "mine" ? "style=mine" : "";
|
||||
|
||||
my $userpic = Image_userpic($pu, 0, $props->{'picture_keyword'});
|
||||
|
||||
my $permalink = LJ::journal_base($u) . "/$ditemid.html";
|
||||
my $readurl = LJ::Talk::talkargs($permalink, $nc, $stylemine);
|
||||
my $posturl = LJ::Talk::talkargs($permalink, "mode=reply", $stylemine);
|
||||
|
||||
my $comments = CommentInfo({
|
||||
'read_url' => $readurl,
|
||||
'post_url' => $posturl,
|
||||
'count' => $replycount,
|
||||
'maxcomments' => ($replycount >= LJ::get_cap($u, 'maxcomments')) ? 1 : 0,
|
||||
'enabled' => ($u->{'opt_showtalklinks'} eq "Y" && !
|
||||
$props->{'opt_nocomments'}) ? 1 : 0,
|
||||
'screened' => ($props->{'hasscreened'} && $remote &&
|
||||
LJ::can_manage($remote, $u)) ? 1 : 0,
|
||||
});
|
||||
|
||||
# format it
|
||||
if ($opts->{'getargs'}->{'nohtml'}) {
|
||||
# quote all non-LJ tags
|
||||
$entry->{'subject'} =~ s{<(?!/?lj)(.*?)>} {<$1>}gi;
|
||||
$entry->{'event'} =~ s{<(?!/?lj)(.*?)>} {<$1>}gi;
|
||||
}
|
||||
my $raw_subj = $entry->{'subject'};
|
||||
LJ::CleanHTML::clean_subject(\$entry->{'subject'});
|
||||
LJ::CleanHTML::clean_event(\$entry->{'event'}, $props->{'opt_preformatted'});
|
||||
LJ::expand_embedded($u, $ditemid, $remote, \$entry->{'event'});
|
||||
|
||||
my $s2entry = Entry($u, {
|
||||
'_rawsubject' => $raw_subj,
|
||||
'subject' => $entry->{'subject'},
|
||||
'text' => $entry->{'event'},
|
||||
'dateparts' => $entry->{'alldatepart'},
|
||||
'security' => $entry->{'security'},
|
||||
'props' => $props,
|
||||
'itemid' => $ditemid,
|
||||
'comments' => $comments,
|
||||
'journal' => $userlite_journal,
|
||||
'poster' => $userlite_poster,
|
||||
'new_day' => 0,
|
||||
'end_day' => 0,
|
||||
'userpic' => $userpic,
|
||||
'permalink_url' => $permalink,
|
||||
'enable_tags_compatibility' => [$opts->{enable_tags_compatibility}, $opts->{ctx}],
|
||||
});
|
||||
|
||||
return ($entry, $s2entry);
|
||||
}
|
||||
|
||||
1;
|
||||
444
local/cgi-bin/LJ/S2/FriendsPage.pm
Executable file
444
local/cgi-bin/LJ/S2/FriendsPage.pm
Executable file
@@ -0,0 +1,444 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
|
||||
use strict;
|
||||
package LJ::S2;
|
||||
|
||||
eval "use LJR::Distributed;";
|
||||
my $ljr = $@ ? 0 : 1;
|
||||
|
||||
if ($ljr) {
|
||||
use LJR::Distributed;
|
||||
}
|
||||
|
||||
sub FriendsPage
|
||||
{
|
||||
my ($u, $remote, $opts) = @_;
|
||||
|
||||
my $p = Page($u, $opts);
|
||||
$p->{'_type'} = "FriendsPage";
|
||||
$p->{'view'} = "friends";
|
||||
$p->{'entries'} = [];
|
||||
$p->{'friends'} = {};
|
||||
$p->{'friends_title'} = LJ::ehtml($u->{'friendspagetitle'});
|
||||
$p->{'filter_active'} = 0;
|
||||
$p->{'filter_name'} = "";
|
||||
|
||||
my $sth;
|
||||
my $user = $u->{'user'};
|
||||
|
||||
# see how often the remote user can reload this page.
|
||||
# "friendsviewupdate" time determines what granularity time
|
||||
# increments by for checking for new updates
|
||||
my $nowtime = time();
|
||||
|
||||
# update delay specified by "friendsviewupdate"
|
||||
my $newinterval = LJ::get_cap_min($remote, "friendsviewupdate") || 1;
|
||||
|
||||
# when are we going to say page was last modified? back up to the
|
||||
# most recent time in the past where $time % $interval == 0
|
||||
my $lastmod = $nowtime;
|
||||
$lastmod -= $lastmod % $newinterval;
|
||||
|
||||
# see if they have a previously cached copy of this page they
|
||||
# might be able to still use.
|
||||
my $ims = $opts->{'r'}->header_in('If-Modified-Since');
|
||||
if ($ims) {
|
||||
my $theirtime = LJ::http_to_time($ims);
|
||||
|
||||
# send back a 304 Not Modified if they say they've reloaded this
|
||||
# document in the last $newinterval seconds:
|
||||
unless ($theirtime < $lastmod) {
|
||||
$opts->{'handler_return'} = 304;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
$opts->{'r'}->header_out('Last-Modified', LJ::time_to_http($lastmod));
|
||||
|
||||
my $get = $opts->{'getargs'};
|
||||
|
||||
my $ret;
|
||||
|
||||
if ($get->{'mode'} eq "live") {
|
||||
$ret .= "<html><head><title>${user}'s friends: live!</title></head>\n";
|
||||
$ret .= "<frameset rows=\"100%,0%\" border=0>\n";
|
||||
$ret .= " <frame name=livetop src=\"friends?mode=framed\">\n";
|
||||
$ret .= " <frame name=livebottom src=\"friends?mode=livecond&lastitemid=0\">\n";
|
||||
$ret .= "</frameset></html>\n";
|
||||
return $ret;
|
||||
}
|
||||
|
||||
if ($u->{'journaltype'} eq "R" && $u->{'renamedto'} ne "") {
|
||||
$opts->{'redir'} = LJ::journal_base($u->{'renamedto'}, $opts->{'vhost'}) . "/friends";
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJ::load_user_props($remote, "opt_nctalklinks", "opt_stylemine", "opt_imagelinks", "opt_ljcut_disable_friends");
|
||||
|
||||
# load options for image links
|
||||
my ($maximgwidth, $maximgheight) = (undef, undef);
|
||||
($maximgwidth, $maximgheight) = ($1, $2)
|
||||
if ($remote && $remote->{'userid'} == $u->{'userid'} &&
|
||||
$remote->{'opt_imagelinks'} =~ m/^(\d+)\|(\d+)$/);
|
||||
|
||||
## never have spiders index friends pages (change too much, and some
|
||||
## people might not want to be indexed)
|
||||
$p->{'head_content'} .= LJ::robot_meta_tags();
|
||||
|
||||
my $itemshow = S2::get_property_value($opts->{'ctx'}, "page_friends_items")+0;
|
||||
if ($itemshow < 1) { $itemshow = 20; }
|
||||
elsif ($itemshow > 50) { $itemshow = 50; }
|
||||
|
||||
my $skip = $get->{'skip'}+0;
|
||||
my $maxskip = ($LJ::MAX_SCROLLBACK_FRIENDS || 1000) - $itemshow;
|
||||
if ($skip > $maxskip) { $skip = $maxskip; }
|
||||
if ($skip < 0) { $skip = 0; }
|
||||
my $itemload = $itemshow+$skip;
|
||||
|
||||
my $dayskip = $get->{'dayskip'}+0;
|
||||
|
||||
my $filter;
|
||||
my $group;
|
||||
my $common_filter = 1;
|
||||
|
||||
if (defined $get->{'filter'} && $remote && $remote->{'user'} eq $user) {
|
||||
$filter = $get->{'filter'};
|
||||
$common_filter = 0;
|
||||
$p->{'filter_active'} = 1;
|
||||
$p->{'filter_name'} = "";
|
||||
} else {
|
||||
if ($opts->{'pathextra'}) {
|
||||
$group = $opts->{'pathextra'};
|
||||
$group =~ s!^/!!;
|
||||
$group =~ s!/$!!;
|
||||
if ($group) { $group = LJ::durl($group); $common_filter = 0; }
|
||||
}
|
||||
if ($group) {
|
||||
$p->{'filter_active'} = 1;
|
||||
$p->{'filter_name'} = LJ::ehtml($group);
|
||||
}
|
||||
my $grp = LJ::get_friend_group($u, { 'name' => $group || "Default View" });
|
||||
my $bit = $grp->{'groupnum'};
|
||||
my $public = $grp->{'is_public'};
|
||||
if ($bit && ($public || ($remote && $remote->{'user'} eq $user))) {
|
||||
$filter = (1 << $bit);
|
||||
} elsif ($group) {
|
||||
$opts->{'badfriendgroup'} = 1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ($opts->{'view'} eq "friendsfriends") {
|
||||
$p->{'friends_mode'} = "friendsfriends";
|
||||
}
|
||||
|
||||
if ($get->{'mode'} eq "livecond")
|
||||
{
|
||||
## load the itemids
|
||||
my @items = LJ::get_friend_items({
|
||||
'u' => $u,
|
||||
'remote' => $remote,
|
||||
'itemshow' => 1,
|
||||
'skip' => 0,
|
||||
'filter' => $filter,
|
||||
'common_filter' => $common_filter,
|
||||
});
|
||||
my $first = @items ? $items[0]->{'itemid'} : 0;
|
||||
|
||||
$ret .= "time = " . scalar(time()) . "<br />";
|
||||
$opts->{'headers'}->{'Refresh'} = "30;URL=$LJ::SITEROOT/users/$user/friends?mode=livecond&lastitemid=$first";
|
||||
if ($get->{'lastitemid'} == $first) {
|
||||
$ret .= "nothing new!";
|
||||
} else {
|
||||
if ($get->{'lastitemid'}) {
|
||||
$ret .= "<b>New stuff!</b>\n";
|
||||
$ret .= "<script language=\"JavaScript\">\n";
|
||||
$ret .= "window.parent.livetop.location.reload(true);\n";
|
||||
$ret .= "</script>\n";
|
||||
$opts->{'trusted_html'} = 1;
|
||||
} else {
|
||||
$ret .= "Friends Live! started.";
|
||||
}
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
## load the itemids
|
||||
my %friends;
|
||||
my %friends_row;
|
||||
my @items = LJ::get_friend_items({
|
||||
'u' => $u,
|
||||
'remote' => $remote,
|
||||
'itemshow' => $itemshow,
|
||||
'skip' => $skip,
|
||||
'dayskip' => $dayskip,
|
||||
'filter' => $filter,
|
||||
'common_filter' => $common_filter,
|
||||
'friends_u' => \%friends,
|
||||
'friends' => \%friends_row,
|
||||
'showtypes' => $get->{'show'},
|
||||
'friendsoffriends' => $opts->{'view'} eq "friendsfriends",
|
||||
'dateformat' => 'S2',
|
||||
});
|
||||
|
||||
while ($_ = each %friends) {
|
||||
# we expect fgcolor/bgcolor to be in here later
|
||||
$friends{$_}->{'fgcolor'} = $friends_row{$_}->{'fgcolor'} || '#ffffff';
|
||||
$friends{$_}->{'bgcolor'} = $friends_row{$_}->{'bgcolor'} || '#000000';
|
||||
}
|
||||
|
||||
return $p unless %friends;
|
||||
|
||||
my %posters;
|
||||
{
|
||||
my @posterids;
|
||||
foreach my $item (@items) {
|
||||
next if $friends{$item->{'posterid'}};
|
||||
push @posterids, $item->{'posterid'};
|
||||
}
|
||||
LJ::load_userids_multiple([ map { $_ => \$posters{$_} } @posterids ])
|
||||
if @posterids;
|
||||
}
|
||||
|
||||
my %objs_of_picid;
|
||||
my @userpic_load;
|
||||
|
||||
my %lite; # posterid -> s2_UserLite
|
||||
my $get_lite = sub {
|
||||
my $id = shift;
|
||||
return $lite{$id} if $lite{$id};
|
||||
return $lite{$id} = UserLite($posters{$id} || $friends{$id});
|
||||
};
|
||||
|
||||
my $eventnum = 0;
|
||||
my $hiddenentries = 0;
|
||||
ENTRY:
|
||||
foreach my $item (@items)
|
||||
{
|
||||
my ($friendid, $posterid, $itemid, $security, $alldatepart) =
|
||||
map { $item->{$_} } qw(ownerid posterid itemid security alldatepart);
|
||||
|
||||
my $fru = $friends{$friendid};
|
||||
my ($friend, $poster);
|
||||
$friend = $poster = $fru->{'user'};
|
||||
$p->{'friends'}->{$fru->{'user'}} ||= Friend($fru);
|
||||
|
||||
my $clusterid = $item->{'clusterid'}+0;
|
||||
|
||||
my $props = $item->{'props'};
|
||||
|
||||
my $replycount = $props->{'replycount'};
|
||||
my $subject = $item->{'text'}->[0];
|
||||
my $text = $item->{'text'}->[1];
|
||||
if ($get->{'nohtml'}) {
|
||||
# quote all non-LJ tags
|
||||
$subject =~ s{<(?!/?lj)(.*?)>} {<$1>}gi;
|
||||
$text =~ s{<(?!/?lj)(.*?)>} {<$1>}gi;
|
||||
}
|
||||
|
||||
LJ::CleanHTML::clean_subject(\$subject) if $subject;
|
||||
|
||||
my $ditemid = $itemid * 256 + $item->{'anum'};
|
||||
|
||||
my $stylemine = "";
|
||||
$stylemine .= "style=mine" if $remote && $remote->{'opt_stylemine'} &&
|
||||
$remote->{'userid'} != $friendid;
|
||||
|
||||
LJ::CleanHTML::clean_event(\$text, { 'preformatted' => $props->{'opt_preformatted'},
|
||||
'cuturl' => LJ::item_link($fru, $itemid, $item->{'anum'}, $stylemine),
|
||||
'maximgwidth' => $maximgwidth,
|
||||
'maximgheight' => $maximgheight,
|
||||
'ljcut_disable' => $remote->{'opt_ljcut_disable_friends'}, });
|
||||
LJ::expand_embedded($fru, $ditemid, $remote, \$text);
|
||||
|
||||
my $userlite_poster = $get_lite->($posterid);
|
||||
my $userlite_journal = $get_lite->($friendid);
|
||||
|
||||
# get the poster user
|
||||
my $po = $posters{$posterid} || $friends{$posterid};
|
||||
|
||||
# don't allow posts from suspended users
|
||||
if ($po->{'statusvis'} eq 'S') {
|
||||
$hiddenentries++; # Remember how many we've skipped for later
|
||||
next ENTRY;
|
||||
}
|
||||
|
||||
# do the picture
|
||||
my $picid = 0;
|
||||
my $picu = undef;
|
||||
if ($friendid != $posterid && S2::get_property_value($opts->{ctx}, 'use_shared_pic')) {
|
||||
# using the community, the user wants to see shared pictures
|
||||
$picu = $fru;
|
||||
|
||||
# use shared pic for community
|
||||
$picid = $fru->{defaultpicid};
|
||||
} else {
|
||||
# we're using the poster for this picture
|
||||
$picu = $po;
|
||||
|
||||
# check if they specified one
|
||||
$picid = LJ::get_picid_from_keyword($po, $props->{picture_keyword})
|
||||
if $props->{picture_keyword};
|
||||
|
||||
# fall back on the poster's default
|
||||
$picid ||= $po->{defaultpicid};
|
||||
}
|
||||
|
||||
my $nc = "";
|
||||
$nc .= "nc=$replycount" if $replycount; # && $remote && $remote->{'opt_nctalklinks'};
|
||||
|
||||
my $journalbase = LJ::journal_base($fru);
|
||||
my $permalink = "$journalbase/$ditemid.html";
|
||||
my $readurl = LJ::Talk::talkargs($permalink, $nc, $stylemine);
|
||||
my $posturl = LJ::Talk::talkargs($permalink, "mode=reply", $stylemine);
|
||||
my $synurl = "";
|
||||
|
||||
if ($ljr && $props->{'syn_link'}) {
|
||||
my $rs = LJR::Distributed::match_remote_server($props->{'syn_link'});
|
||||
if ($rs->{"servertype"} eq "lj") {
|
||||
$readurl = $props->{'syn_link'};
|
||||
$posturl = $props->{'syn_link'} . "?mode=reply";
|
||||
$replycount = 'Read';
|
||||
}
|
||||
else {
|
||||
$posturl = $props->{'syn_link'};
|
||||
$replycount = undef;
|
||||
}
|
||||
$synurl = $props->{'syn_link'};
|
||||
}
|
||||
|
||||
my $comments = CommentInfo({
|
||||
'read_url' => $readurl,
|
||||
'post_url' => $posturl,
|
||||
'syn_url' => $synurl,
|
||||
'count' => $replycount,
|
||||
'maxcomments' => ($replycount >= LJ::get_cap($u, 'maxcomments')) ? 1 : 0,
|
||||
'enabled' => ($fru->{'opt_showtalklinks'} eq "Y" &&
|
||||
! $props->{'opt_nocomments'} ||
|
||||
$props->{'syn_link'}
|
||||
) ? 1 : 0,
|
||||
'screened' => ($remote && LJ::can_manage($remote, $fru) && $props->{'hasscreened'}) ? 1 : 0,
|
||||
});
|
||||
|
||||
my $moodthemeid = $u->{'opt_forcemoodtheme'} eq 'Y' ?
|
||||
$u->{'moodthemeid'} : $fru->{'moodthemeid'};
|
||||
|
||||
my $entry = Entry($u, {
|
||||
'subject' => $subject,
|
||||
'text' => $text,
|
||||
'dateparts' => $alldatepart,
|
||||
'security' => $security,
|
||||
'props' => $props,
|
||||
'itemid' => $ditemid,
|
||||
'journal' => $userlite_journal,
|
||||
'poster' => $userlite_poster,
|
||||
'comments' => $comments,
|
||||
'new_day' => 0, # setup below
|
||||
'end_day' => 0, # setup below
|
||||
'userpic' => undef,
|
||||
'permalink_url' => $permalink,
|
||||
'base_url' => $journalbase,
|
||||
'moodthemeid' => $moodthemeid,
|
||||
'enable_tags_compatibility' => [$opts->{enable_tags_compatibility}, $opts->{ctx}],
|
||||
});
|
||||
$entry->{'_ymd'} = join('-', map { $entry->{'time'}->{$_} } qw(year month day));
|
||||
|
||||
if ($picid && $picu) {
|
||||
push @userpic_load, [ $picu, $picid ];
|
||||
push @{$objs_of_picid{$picid}}, \$entry->{'userpic'};
|
||||
}
|
||||
|
||||
push @{$p->{'entries'}}, $entry;
|
||||
$eventnum++;
|
||||
|
||||
} # end while
|
||||
|
||||
# set the new_day and end_day members.
|
||||
if ($eventnum) {
|
||||
for (my $i = 0; $i < $eventnum; $i++) {
|
||||
my $entry = $p->{'entries'}->[$i];
|
||||
$entry->{'new_day'} = 1;
|
||||
my $last = $i;
|
||||
for (my $j = $i+1; $j < $eventnum; $j++) {
|
||||
my $ej = $p->{'entries'}->[$j];
|
||||
if ($ej->{'_ymd'} eq $entry->{'_ymd'}) {
|
||||
$last = $j;
|
||||
}
|
||||
}
|
||||
$p->{'entries'}->[$last]->{'end_day'} = 1;
|
||||
$i = $last;
|
||||
}
|
||||
}
|
||||
|
||||
# load the pictures that were referenced, then retroactively populate
|
||||
# the userpic fields of the Entries above
|
||||
my %userpics;
|
||||
LJ::load_userpics(\%userpics, \@userpic_load);
|
||||
|
||||
foreach my $picid (keys %userpics) {
|
||||
my $up = Image("$LJ::USERPIC_ROOT/$picid/$userpics{$picid}->{'userid'}",
|
||||
$userpics{$picid}->{'width'},
|
||||
$userpics{$picid}->{'height'});
|
||||
foreach (@{$objs_of_picid{$picid}}) { $$_ = $up; }
|
||||
}
|
||||
|
||||
# make the skip links
|
||||
my $nav = {
|
||||
'_type' => 'RecentNav',
|
||||
'version' => 1,
|
||||
'skip' => $skip,
|
||||
'count' => $eventnum,
|
||||
};
|
||||
|
||||
my $base = "$u->{'_journalbase'}/$opts->{'view'}";
|
||||
if ($group) {
|
||||
$base .= "/" . LJ::eurl($group);
|
||||
}
|
||||
|
||||
# $linkfilter is distinct from $filter: if user has a default view,
|
||||
# $filter is now set according to it but we don't want it to show in the links.
|
||||
# $incfilter may be true even if $filter is 0: user may use filter=0 to turn
|
||||
# off the default group
|
||||
my $linkfilter = $get->{'filter'} + 0;
|
||||
my $incfilter = defined $get->{'filter'};
|
||||
|
||||
# if we've skipped down, then we can skip back up
|
||||
if ($skip) {
|
||||
my %linkvars;
|
||||
$linkvars{'filter'} = $linkfilter if $incfilter;
|
||||
$linkvars{'show'} = $get->{'show'} if $get->{'show'} =~ /^\w+$/;
|
||||
my $newskip = $skip - $itemshow;
|
||||
if ($newskip > 0) { $linkvars{'skip'} = $newskip; }
|
||||
else { $newskip = 0; }
|
||||
$linkvars{'dayskip'} = $dayskip if $dayskip;
|
||||
$nav->{'forward_url'} = LJ::make_link($base, \%linkvars);
|
||||
$nav->{'forward_skip'} = $newskip;
|
||||
$nav->{'forward_count'} = $itemshow;
|
||||
}
|
||||
|
||||
## unless we didn't even load as many as we were expecting on this
|
||||
## page, then there are more (unless there are exactly the number shown
|
||||
## on the page, but who cares about that)
|
||||
# Must remember to count $hiddenentries or we'll have no skiplinks when > 1
|
||||
unless (($eventnum + $hiddenentries) != $itemshow || $skip == $maxskip) {
|
||||
my %linkvars;
|
||||
$linkvars{'filter'} = $linkfilter if $incfilter;
|
||||
$linkvars{'show'} = $get->{'show'} if $get->{'show'} =~ /^\w+$/;
|
||||
my $newskip = $skip + $itemshow;
|
||||
$linkvars{'skip'} = $newskip;
|
||||
$linkvars{'dayskip'} = $dayskip if $dayskip;
|
||||
$nav->{'backward_url'} = LJ::make_link($base, \%linkvars);
|
||||
$nav->{'backward_skip'} = $newskip;
|
||||
$nav->{'backward_count'} = $itemshow;
|
||||
}
|
||||
|
||||
$p->{'nav'} = $nav;
|
||||
|
||||
if ($get->{'mode'} eq "framed") {
|
||||
$p->{'head_content'} .= "<base target='_top' />";
|
||||
}
|
||||
|
||||
return $p;
|
||||
}
|
||||
|
||||
1;
|
||||
224
local/cgi-bin/LJ/S2/MonthPage.pm
Executable file
224
local/cgi-bin/LJ/S2/MonthPage.pm
Executable file
@@ -0,0 +1,224 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
|
||||
use strict;
|
||||
package LJ::S2;
|
||||
|
||||
sub MonthPage
|
||||
{
|
||||
my ($u, $remote, $opts) = @_;
|
||||
|
||||
my $get = $opts->{'getargs'};
|
||||
|
||||
my $p = Page($u, $opts);
|
||||
$p->{'_type'} = "MonthPage";
|
||||
$p->{'view'} = "month";
|
||||
$p->{'days'} = [];
|
||||
|
||||
my $ctx = $opts->{'ctx'};
|
||||
|
||||
my $dbcr = LJ::get_cluster_reader($u);
|
||||
|
||||
my $user = $u->{'user'};
|
||||
my $journalbase = LJ::journal_base($user, $opts->{'vhost'});
|
||||
|
||||
if ($u->{'journaltype'} eq "R" && $u->{'renamedto'} ne "") {
|
||||
$opts->{'redir'} = LJ::journal_base($u->{'renamedto'}, $opts->{'vhost'}) .
|
||||
"/" . $opts->{'pathextra'};
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ($u->{'opt_blockrobots'}) {
|
||||
$p->{'head_content'} .= LJ::robot_meta_tags();
|
||||
}
|
||||
|
||||
my ($year, $month);
|
||||
if ($opts->{'pathextra'} =~ m!^/(\d\d\d\d)/(\d\d)\b!) {
|
||||
($year, $month) = ($1, $2);
|
||||
}
|
||||
|
||||
$opts->{'errors'} = [];
|
||||
if ($month < 1 || $month > 12) { push @{$opts->{'errors'}}, "Invalid month: $month"; }
|
||||
if ($year < 1970 || $year > 2038) { push @{$opts->{'errors'}}, "Invalid year: $year"; }
|
||||
unless ($dbcr) { push @{$opts->{'errors'}}, "Database temporarily unavailable"; }
|
||||
return if @{$opts->{'errors'}};
|
||||
|
||||
$p->{'date'} = Date($year, $month, 0);
|
||||
|
||||
# load the log items
|
||||
my $dateformat = "%Y %m %d %H %i %s %w"; # yyyy mm dd hh mm ss day_of_week
|
||||
my $sth;
|
||||
|
||||
my $secwhere = "AND l.security='public'";
|
||||
my $viewall = 0;
|
||||
my $viewsome = 0;
|
||||
if ($remote) {
|
||||
|
||||
# do they have the viewall priv?
|
||||
if ($get->{'viewall'} && LJ::check_priv($remote, "canview")) {
|
||||
LJ::statushistory_add($u->{'userid'}, $remote->{'userid'},
|
||||
"viewall", "month: $user, statusvis: $u->{'statusvis'}");
|
||||
$viewall = LJ::check_priv($remote, 'canview', '*');
|
||||
$viewsome = $viewall || LJ::check_priv($remote, 'canview', 'suspended');
|
||||
}
|
||||
|
||||
if ($remote->{'userid'} == $u->{'userid'} || $viewall) {
|
||||
$secwhere = ""; # see everything
|
||||
} elsif ($remote->{'journaltype'} eq 'P' || $remote->{'journaltype'} eq 'I') {
|
||||
my $gmask = LJ::get_groupmask($u, $remote);
|
||||
$secwhere = "AND (l.security='public' OR (l.security='usemask' AND l.allowmask & $gmask))"
|
||||
if $gmask;
|
||||
}
|
||||
}
|
||||
|
||||
$sth = $dbcr->prepare("SELECT l.jitemid AS 'itemid', l.posterid, l.anum, l.day, ".
|
||||
" DATE_FORMAT(l.eventtime, '$dateformat') AS 'alldatepart', ".
|
||||
" l.replycount, l.security ".
|
||||
"FROM log2 l ".
|
||||
"WHERE l.journalid=? AND l.year=? AND l.month=? ".
|
||||
"$secwhere LIMIT 2000");
|
||||
$sth->execute($u->{'userid'}, $year, $month);
|
||||
|
||||
my @items;
|
||||
push @items, $_ while $_ = $sth->fetchrow_hashref;
|
||||
@items = sort { $a->{'alldatepart'} cmp $b->{'alldatepart'} } @items;
|
||||
|
||||
LJ::fill_items_with_text_props(\@items, $u, {'only_subject' => 1});
|
||||
|
||||
my (%pu, %pu_lite); # poster users; UserLite objects
|
||||
foreach (@items) {
|
||||
$pu{$_->{'posterid'}} = undef;
|
||||
}
|
||||
LJ::load_userids_multiple([map { $_, \$pu{$_} } keys %pu], [$u]);
|
||||
$pu_lite{$_} = UserLite($pu{$_}) foreach keys %pu;
|
||||
|
||||
my %day_entries; # <day> -> [ Entry+ ]
|
||||
|
||||
my $opt_text_subjects = S2::get_property_value($ctx, "page_month_textsubjects");
|
||||
my $userlite_journal = UserLite($u);
|
||||
|
||||
ENTRY:
|
||||
foreach my $item (@items)
|
||||
{
|
||||
my ($posterid, $itemid, $security, $alldatepart, $replycount, $anum) =
|
||||
map { $item->{$_} } qw(posterid itemid security alldatepart replycount anum);
|
||||
my $day = $item->{'day'};
|
||||
|
||||
# don't show posts from suspended users
|
||||
next unless $pu{$posterid};
|
||||
next ENTRY if $pu{$posterid}->{'statusvis'} eq 'S' && !$viewsome;
|
||||
|
||||
my $subject = $item->{'text'}->[0];
|
||||
my $props = $item->{'props'};
|
||||
|
||||
if ($opt_text_subjects) {
|
||||
LJ::CleanHTML::clean_subject_all(\$subject);
|
||||
} else {
|
||||
LJ::CleanHTML::clean_subject(\$subject);
|
||||
}
|
||||
|
||||
my $ditemid = $itemid*256 + $anum;
|
||||
my $nc = "";
|
||||
$nc .= "nc=$replycount" if $replycount; # && $remote && $remote->{'opt_nctalklinks'};
|
||||
my $permalink = "$journalbase/$ditemid.html";
|
||||
my $readurl = $permalink;
|
||||
$readurl .= "?$nc" if $nc;
|
||||
my $posturl = $permalink . "?mode=reply";
|
||||
|
||||
my $comments = CommentInfo({
|
||||
'read_url' => $readurl,
|
||||
'post_url' => $posturl,
|
||||
'count' => $replycount,
|
||||
'maxcomments' => ($replycount >= LJ::get_cap($u, 'maxcomments')) ? 1 : 0,
|
||||
'enabled' => ($u->{'opt_showtalklinks'} eq "Y" && ! $props->{'opt_nocomments'}) ? 1 : 0,
|
||||
'screened' => ($props->{'hasscreened'} && $remote &&
|
||||
($remote->{'user'} eq $u->{'user'} || LJ::can_manage($remote, $u))) ? 1 : 0,
|
||||
});
|
||||
|
||||
my $userlite_poster = $userlite_journal;
|
||||
my $userpic = $p->{'journal'}->{'default_pic'};
|
||||
if ($u->{'userid'} != $posterid) {
|
||||
$userlite_poster = $pu_lite{$posterid};
|
||||
$userpic = Image_userpic($pu{$posterid}, 0, $props->{'picture_keyword'});
|
||||
}
|
||||
|
||||
my $entry = Entry($u, {
|
||||
'subject' => $subject,
|
||||
'text' => "",
|
||||
'dateparts' => $alldatepart,
|
||||
'security' => $security,
|
||||
'props' => $props,
|
||||
'itemid' => $ditemid,
|
||||
'journal' => $userlite_journal,
|
||||
'poster' => $userlite_poster,
|
||||
'comments' => $comments,
|
||||
'userpic' => $userpic,
|
||||
'permalink_url' => $permalink,
|
||||
});
|
||||
|
||||
push @{$day_entries{$day}}, $entry;
|
||||
}
|
||||
|
||||
my $days_month = LJ::days_in_month($month, $year);
|
||||
for my $day (1..$days_month) {
|
||||
my $entries = $day_entries{$day} || [];
|
||||
my $month_day = {
|
||||
'_type' => 'MonthDay',
|
||||
'date' => Date($year, $month, $day),
|
||||
'day' => $day,
|
||||
'has_entries' => scalar @$entries > 0,
|
||||
'num_entries' => scalar @$entries,
|
||||
'url' => $journalbase . sprintf("/%04d/%02d/%02d/", $year, $month, $day),
|
||||
'entries' => $entries,
|
||||
};
|
||||
push @{$p->{'days'}}, $month_day;
|
||||
}
|
||||
|
||||
# populate redirector
|
||||
my $vhost = $opts->{'vhost'};
|
||||
$vhost =~ s/:.*//;
|
||||
$p->{'redir'} = {
|
||||
'_type' => "Redirector",
|
||||
'user' => $u->{'user'},
|
||||
'vhost' => $vhost,
|
||||
'type' => 'monthview',
|
||||
'url' => "$LJ::SITEROOT/go.bml",
|
||||
};
|
||||
|
||||
# figure out what months have been posted into
|
||||
my $nowval = $year*12 + $month;
|
||||
|
||||
$p->{'months'} = [];
|
||||
|
||||
my $days = LJ::get_daycounts($u, $remote) || [];
|
||||
my $lastmo;
|
||||
foreach my $day (@$days) {
|
||||
my ($oy, $om) = ($day->[0], $day->[1]);
|
||||
my $mo = "$oy-$om";
|
||||
next if $mo eq $lastmo;
|
||||
$lastmo = $mo;
|
||||
|
||||
my $date = Date($oy, $om, 0);
|
||||
my $url = $journalbase . sprintf("/%04d/%02d/", $oy, $om);
|
||||
push @{$p->{'months'}}, {
|
||||
'_type' => "MonthEntryInfo",
|
||||
'date' => $date,
|
||||
'url' => $url,
|
||||
'redir_key' => sprintf("%04d%02d", $oy, $om),
|
||||
};
|
||||
|
||||
my $val = $oy*12+$om;
|
||||
if ($val < $nowval) {
|
||||
$p->{'prev_url'} = $url;
|
||||
$p->{'prev_date'} = $date;
|
||||
}
|
||||
if ($val > $nowval && ! $p->{'next_date'}) {
|
||||
$p->{'next_url'} = $url;
|
||||
$p->{'next_date'} = $date;
|
||||
}
|
||||
}
|
||||
|
||||
return $p;
|
||||
}
|
||||
|
||||
1;
|
||||
216
local/cgi-bin/LJ/S2/RecentPage.pm
Executable file
216
local/cgi-bin/LJ/S2/RecentPage.pm
Executable file
@@ -0,0 +1,216 @@
|
||||
use strict;
|
||||
package LJ::S2;
|
||||
|
||||
sub RecentPage
|
||||
{
|
||||
my ($u, $remote, $opts) = @_;
|
||||
|
||||
my $p = Page($u, $opts);
|
||||
$p->{'_type'} = "RecentPage";
|
||||
$p->{'view'} = "recent";
|
||||
$p->{'entries'} = [];
|
||||
|
||||
my $user = $u->{'user'};
|
||||
my $journalbase = LJ::journal_base($user, $opts->{'vhost'});
|
||||
|
||||
if ($u->{'journaltype'} eq "R" && $u->{'renamedto'} ne "") {
|
||||
$opts->{'redir'} = LJ::journal_base($u->{'renamedto'}, $opts->{'vhost'});
|
||||
return;
|
||||
}
|
||||
|
||||
LJ::load_user_props($remote, "opt_nctalklinks", "opt_ljcut_disable_lastn");
|
||||
|
||||
my $get = $opts->{'getargs'};
|
||||
|
||||
if ($opts->{'pathextra'}) {
|
||||
$opts->{'badargs'} = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ($u->{'opt_blockrobots'} || $get->{'skip'}) {
|
||||
$p->{'head_content'} .= LJ::robot_meta_tags();
|
||||
}
|
||||
|
||||
$p->{'head_content'} .= qq{<link rel="openid.server" href="$LJ::OPENID_SERVER" />\n}
|
||||
if LJ::OpenID::server_enabled();
|
||||
|
||||
my $itemshow = S2::get_property_value($opts->{'ctx'}, "page_recent_items")+0;
|
||||
if ($itemshow < 1) { $itemshow = 20; }
|
||||
elsif ($itemshow > 50) { $itemshow = 50; }
|
||||
|
||||
my $skip = $get->{'skip'}+0;
|
||||
my $maxskip = $LJ::MAX_HINTS_LASTN-$itemshow;
|
||||
if ($skip < 0) { $skip = 0; }
|
||||
if ($skip > $maxskip) { $skip = $maxskip; }
|
||||
|
||||
my $dayskip = $get->{'dayskip'}+0;
|
||||
|
||||
# do they want to view all entries, regardless of security?
|
||||
my $viewall = 0;
|
||||
my $viewsome = 0;
|
||||
if ($get->{'viewall'} && LJ::check_priv($remote, "canview")) {
|
||||
LJ::statushistory_add($u->{'userid'}, $remote->{'userid'},
|
||||
"viewall", "lastn: $user, statusvis: $u->{'statusvis'}");
|
||||
$viewall = LJ::check_priv($remote, 'canview', '*');
|
||||
$viewsome = $viewall || LJ::check_priv($remote, 'canview', 'suspended');
|
||||
}
|
||||
|
||||
## load the items
|
||||
my $err;
|
||||
my @items = LJ::get_recent_items({
|
||||
'u' => $u,
|
||||
'clustersource' => 'slave',
|
||||
'viewall' => $viewall,
|
||||
'remote' => $remote,
|
||||
'itemshow' => $itemshow,
|
||||
'skip' => $skip,
|
||||
'dayskip' => $dayskip,
|
||||
'tags' => $opts->{tags},
|
||||
'dateformat' => 'S2',
|
||||
'order' => ($u->{'journaltype'} eq "C" || $u->{'journaltype'} eq "Y") # community or syndicated
|
||||
? "logtime" : "",
|
||||
'err' => \$err,
|
||||
});
|
||||
|
||||
die $err if $err;
|
||||
|
||||
my $lastdate = "";
|
||||
my $itemnum = 0;
|
||||
my $lastentry = undef;
|
||||
|
||||
my (%apu, %apu_lite); # alt poster users; UserLite objects
|
||||
foreach (@items) {
|
||||
next unless $_->{'posterid'} != $u->{'userid'};
|
||||
$apu{$_->{'posterid'}} = undef;
|
||||
}
|
||||
if (%apu) {
|
||||
LJ::load_userids_multiple([map { $_, \$apu{$_} } keys %apu], [$u]);
|
||||
$apu_lite{$_} = UserLite($apu{$_}) foreach keys %apu;
|
||||
}
|
||||
|
||||
my $userlite_journal = UserLite($u);
|
||||
|
||||
ENTRY:
|
||||
foreach my $item (@items)
|
||||
{
|
||||
my ($posterid, $itemid, $security, $alldatepart) =
|
||||
map { $item->{$_} } qw(posterid itemid security alldatepart);
|
||||
|
||||
my $props = $item->{'props'};
|
||||
|
||||
my $replycount = $props->{'replycount'};
|
||||
my $subject = $item->{'text'}->[0];
|
||||
my $text = $item->{'text'}->[1];
|
||||
if ($get->{'nohtml'}) {
|
||||
# quote all non-LJ tags
|
||||
$subject =~ s{<(?!/?lj)(.*?)>} {<$1>}gi;
|
||||
$text =~ s{<(?!/?lj)(.*?)>} {<$1>}gi;
|
||||
}
|
||||
|
||||
# don't show posts from suspended users unless the user doing the viewing says to (and is allowed)
|
||||
next ENTRY if $apu{$posterid} && $apu{$posterid}->{'statusvis'} eq 'S' && !$viewsome;
|
||||
|
||||
my $date = substr($alldatepart, 0, 10);
|
||||
my $new_day = 0;
|
||||
if ($date ne $lastdate) {
|
||||
$new_day = 1;
|
||||
$lastdate = $date;
|
||||
$lastentry->{'end_day'} = 1 if $lastentry;
|
||||
}
|
||||
|
||||
$itemnum++;
|
||||
LJ::CleanHTML::clean_subject(\$subject) if $subject;
|
||||
|
||||
my $ditemid = $itemid * 256 + $item->{'anum'};
|
||||
LJ::CleanHTML::clean_event(\$text, { 'preformatted' => $props->{'opt_preformatted'},
|
||||
'cuturl' => LJ::item_link($u, $itemid, $item->{'anum'}),
|
||||
'ljcut_disable' => $remote->{"opt_ljcut_disable_lastn"}, });
|
||||
LJ::expand_embedded($u, $ditemid, $remote, \$text);
|
||||
|
||||
my $nc = "";
|
||||
$nc .= "nc=$replycount" if $replycount; # && $remote && $remote->{'opt_nctalklinks'};
|
||||
|
||||
my $permalink = "$journalbase/$ditemid.html";
|
||||
my $readurl = $permalink;
|
||||
$readurl .= "?$nc" if $nc;
|
||||
my $posturl = $permalink . "?mode=reply";
|
||||
|
||||
my $comments = CommentInfo({
|
||||
'read_url' => $readurl,
|
||||
'post_url' => $posturl,
|
||||
'count' => $replycount,
|
||||
'maxcomments' => ($replycount >= LJ::get_cap($u, 'maxcomments')) ? 1 : 0,
|
||||
'enabled' => ($u->{'opt_showtalklinks'} eq "Y" && ! $props->{'opt_nocomments'}) ? 1 : 0,
|
||||
'screened' => ($props->{'hasscreened'} && ($remote->{'user'} eq $u->{'user'}|| LJ::can_manage($remote, $u))) ? 1 : 0,
|
||||
});
|
||||
|
||||
my $userlite_poster = $userlite_journal;
|
||||
my $pu = $u;
|
||||
if ($u->{'userid'} != $posterid) {
|
||||
$userlite_poster = $apu_lite{$posterid} or die "No apu_lite for posterid=$posterid";
|
||||
$pu = $apu{$posterid};
|
||||
}
|
||||
my $userpic = Image_userpic($pu, 0, $props->{'picture_keyword'});
|
||||
|
||||
my $entry = $lastentry = Entry($u, {
|
||||
'subject' => $subject,
|
||||
'text' => $text,
|
||||
'dateparts' => $alldatepart,
|
||||
'security' => $security,
|
||||
'props' => $props,
|
||||
'itemid' => $ditemid,
|
||||
'journal' => $userlite_journal,
|
||||
'poster' => $userlite_poster,
|
||||
'comments' => $comments,
|
||||
'new_day' => $new_day,
|
||||
'end_day' => 0, # if true, set later
|
||||
'userpic' => $userpic,
|
||||
'permalink_url' => $permalink,
|
||||
'enable_tags_compatibility' => [$opts->{enable_tags_compatibility}, $opts->{ctx}],
|
||||
});
|
||||
|
||||
push @{$p->{'entries'}}, $entry;
|
||||
|
||||
} # end huge while loop
|
||||
|
||||
# mark last entry as closing.
|
||||
$p->{'entries'}->[-1]->{'end_day'} = 1 if $itemnum;
|
||||
|
||||
#### make the skip links
|
||||
my $nav = {
|
||||
'_type' => 'RecentNav',
|
||||
'version' => 1,
|
||||
'skip' => $skip,
|
||||
'count' => $itemnum,
|
||||
};
|
||||
|
||||
# if we've skipped down, then we can skip back up
|
||||
if ($skip) {
|
||||
my $newskip = $skip - $itemshow;
|
||||
$newskip = 0 if $newskip <= 0;
|
||||
$nav->{'forward_skip'} = $newskip;
|
||||
$nav->{'forward_url'} = LJ::make_link("$p->{base_url}/", { skip => ($newskip || ""), tag => (LJ::eurl($get->{tag}) || ""), dayskip => ($dayskip || "") });
|
||||
$nav->{'forward_count'} = $itemshow;
|
||||
}
|
||||
|
||||
# unless we didn't even load as many as we were expecting on this
|
||||
# page, then there are more (unless there are exactly the number shown
|
||||
# on the page, but who cares about that)
|
||||
unless ($itemnum != $itemshow) {
|
||||
$nav->{'backward_count'} = $itemshow;
|
||||
if ($skip == $maxskip) {
|
||||
my $date_slashes = $lastdate; # "yyyy mm dd";
|
||||
$date_slashes =~ s! !/!g;
|
||||
$nav->{'backward_url'} = "$p->{'base_url'}/day/$date_slashes";
|
||||
} else {
|
||||
my $newskip = $skip + $itemshow;
|
||||
$nav->{'backward_url'} = LJ::make_link("$p->{'base_url'}/", { skip => ($newskip || ""), tag => (LJ::eurl($get->{tag}) || ""), dayskip => ($dayskip || "") });
|
||||
$nav->{'backward_skip'} = $newskip;
|
||||
}
|
||||
}
|
||||
|
||||
$p->{'nav'} = $nav;
|
||||
return $p;
|
||||
}
|
||||
|
||||
1;
|
||||
139
local/cgi-bin/LJ/S2/ReplyPage.pm
Executable file
139
local/cgi-bin/LJ/S2/ReplyPage.pm
Executable file
@@ -0,0 +1,139 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
|
||||
use strict;
|
||||
package LJ::S2;
|
||||
|
||||
sub ReplyPage
|
||||
{
|
||||
my ($u, $remote, $opts) = @_;
|
||||
|
||||
my $p = Page($u, $opts);
|
||||
$p->{'_type'} = "ReplyPage";
|
||||
$p->{'view'} = "reply";
|
||||
|
||||
my $get = $opts->{'getargs'};
|
||||
|
||||
my ($entry, $s2entry) = EntryPage_entry($u, $remote, $opts);
|
||||
return if $opts->{'suspendeduser'};
|
||||
return if $opts->{'handler_return'};
|
||||
my $ditemid = $entry->{'itemid'}*256 + $entry->{'anum'};
|
||||
$p->{'head_content'} .= $LJ::COMMON_CODE{'chalresp_js'};
|
||||
|
||||
if ($u->{'opt_blockrobots'}) {
|
||||
$p->{'head_content'} .= LJ::robot_meta_tags();
|
||||
}
|
||||
|
||||
$p->{'entry'} = $s2entry;
|
||||
|
||||
# setup the replying item
|
||||
my $replyto = $s2entry;
|
||||
my $parpost;
|
||||
if ($get->{'replyto'}) {
|
||||
my $re_talkid = int($get->{'replyto'} >> 8);
|
||||
my $re_anum = $get->{'replyto'} % 256;
|
||||
unless ($re_anum == $entry->{'anum'}) {
|
||||
$opts->{'handler_return'} = 404;
|
||||
return;
|
||||
}
|
||||
|
||||
my $sql = "SELECT jtalkid, posterid, state, datepost FROM talk2 ".
|
||||
"WHERE journalid=$u->{'userid'} AND jtalkid=$re_talkid ".
|
||||
"AND nodetype='L' AND nodeid=$entry->{'jitemid'}";
|
||||
foreach my $pass (1, 2) {
|
||||
my $db = $pass == 1 ? LJ::get_cluster_reader($u) : LJ::get_cluster_def_reader($u);
|
||||
$parpost = $db->selectrow_hashref($sql);
|
||||
last if $parpost;
|
||||
}
|
||||
unless ($parpost and $parpost->{'state'} ne 'D') {
|
||||
$opts->{'handler_return'} = 404;
|
||||
return;
|
||||
}
|
||||
if ($parpost->{'state'} eq 'S' && !LJ::Talk::can_unscreen($remote, $u, $s2entry->{'poster'}->{'username'}, undef)) {
|
||||
$opts->{'handler_return'} = 403;
|
||||
return;
|
||||
}
|
||||
if ($parpost->{'state'} eq 'F') {
|
||||
# frozen comment, no replies allowed
|
||||
|
||||
# FIXME: eventually have S2 ErrorPage to handle this and similar
|
||||
# For now, this hack will work; this error is pretty uncommon anyway.
|
||||
$opts->{status} = "403 Forbidden";
|
||||
return "<p>This thread has been frozen; no more replies are allowed.</p>";
|
||||
}
|
||||
|
||||
my $tt = LJ::get_talktext2($u, $re_talkid);
|
||||
$parpost->{'subject'} = $tt->{$re_talkid}->[0];
|
||||
$parpost->{'body'} = $tt->{$re_talkid}->[1];
|
||||
$parpost->{'props'} =
|
||||
LJ::load_talk_props2($u, [ $re_talkid ])->{$re_talkid} || {};
|
||||
|
||||
if($LJ::UNICODE && $parpost->{'props'}->{'unknown8bit'}) {
|
||||
LJ::item_toutf8($u, \$parpost->{'subject'}, \$parpost->{'body'}, {});
|
||||
}
|
||||
|
||||
LJ::CleanHTML::clean_comment(\$parpost->{'body'},
|
||||
{ 'preformatted' => $parpost->{'props'}->{'opt_preformatted'},
|
||||
'anon_comment' => !$parpost->{posterid} });
|
||||
|
||||
my $datetime = DateTime_unix(LJ::mysqldate_to_time($parpost->{'datepost'}));
|
||||
|
||||
my ($s2poster, $pu);
|
||||
my $comment_userpic;
|
||||
if ($parpost->{'posterid'}) {
|
||||
$pu = LJ::load_userid($parpost->{'posterid'});
|
||||
return $opts->{handler_return} = 403 if $pu->{statusvis} eq 'S'; # do not show comments by suspended users
|
||||
$s2poster = UserLite($pu);
|
||||
|
||||
# FIXME: this is a little heavy:
|
||||
$comment_userpic = Image_userpic($pu, 0, $parpost->{'props'}->{'picture_keyword'});
|
||||
}
|
||||
|
||||
my $dtalkid = $re_talkid * 256 + $entry->{'anum'};
|
||||
$replyto = {
|
||||
'_type' => 'EntryLite',
|
||||
'subject' => LJ::ehtml($parpost->{'subject'}),
|
||||
'text' => $parpost->{'body'},
|
||||
'userpic' => $comment_userpic,
|
||||
'poster' => $s2poster,
|
||||
'journal' => $s2entry->{'journal'},
|
||||
'metadata' => {},
|
||||
'permalink_url' => $u->{'_journalbase'} . "/$ditemid.html?view=$dtalkid#t$dtalkid",
|
||||
'depth' => 1,
|
||||
'time' => $datetime,
|
||||
};
|
||||
}
|
||||
|
||||
$p->{'replyto'} = $replyto;
|
||||
|
||||
$p->{'form'} = {
|
||||
'_type' => "ReplyForm",
|
||||
'_remote' => $remote,
|
||||
'_u' => $u,
|
||||
'_ditemid' => $ditemid,
|
||||
'_parpost' => $parpost,
|
||||
};
|
||||
|
||||
return $p;
|
||||
}
|
||||
|
||||
package S2::Builtin::LJ;
|
||||
|
||||
sub ReplyForm__print
|
||||
{
|
||||
my ($ctx, $form) = @_;
|
||||
my $remote = $form->{'_remote'};
|
||||
my $u = $form->{'_u'};
|
||||
my $parpost = $form->{'_parpost'};
|
||||
my $parent = $parpost ? $parpost->{'jtalkid'} : 0;
|
||||
|
||||
$S2::pout->(LJ::Talk::talkform({ 'remote' => $remote,
|
||||
'journalu' => $u,
|
||||
'parpost' => $parpost,
|
||||
'replyto' => $parent,
|
||||
'ditemid' => $form->{'_ditemid'},
|
||||
'form' => $form }));
|
||||
|
||||
}
|
||||
|
||||
1;
|
||||
181
local/cgi-bin/LJ/S2/YearPage.pm
Executable file
181
local/cgi-bin/LJ/S2/YearPage.pm
Executable file
@@ -0,0 +1,181 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
|
||||
use strict;
|
||||
package LJ::S2;
|
||||
|
||||
sub YearPage
|
||||
{
|
||||
my ($u, $remote, $opts) = @_;
|
||||
|
||||
my $p = Page($u, $opts);
|
||||
$p->{'_type'} = "YearPage";
|
||||
$p->{'view'} = "archive";
|
||||
|
||||
my $user = $u->{'user'};
|
||||
|
||||
if ($u->{'journaltype'} eq "R" && $u->{'renamedto'} ne "") {
|
||||
$opts->{'redir'} = LJ::journal_base($u->{'renamedto'}, $opts->{'vhost'}) .
|
||||
"/calendar" . $opts->{'pathextra'};
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ($u->{'opt_blockrobots'}) {
|
||||
$p->{'head_content'} .= LJ::robot_meta_tags();
|
||||
}
|
||||
if ($LJ::UNICODE) {
|
||||
$p->{'head_content'} .= '<meta http-equiv="Content-Type" content="text/html; charset='.$opts->{'saycharset'}."\" />\n";
|
||||
}
|
||||
|
||||
my $get = $opts->{'getargs'};
|
||||
|
||||
my $count = LJ::S2::get_journal_day_counts($p);
|
||||
my @years = sort { $a <=> $b } keys %$count;
|
||||
my $maxyear = @years ? $years[-1] : undef;
|
||||
my $year = $get->{'year'}; # old form was /users/<user>/calendar?year=1999
|
||||
|
||||
# but the new form is purtier: */calendar/2001
|
||||
if (! $year && $opts->{'pathextra'} =~ m!^/(\d\d\d\d)/?\b!) {
|
||||
$year = $1;
|
||||
}
|
||||
|
||||
# else... default to the year they last posted.
|
||||
$year ||= $maxyear;
|
||||
|
||||
$p->{'year'} = $year;
|
||||
$p->{'years'} = [];
|
||||
foreach (@years) {
|
||||
push @{$p->{'years'}}, YearYear($_, "$p->{'base_url'}/$_/", $_ == $p->{'year'});
|
||||
}
|
||||
|
||||
$p->{'months'} = [];
|
||||
|
||||
for my $month (1..12) {
|
||||
push @{$p->{'months'}}, YearMonth($p, {
|
||||
'month' => $month,
|
||||
'year' => $year,
|
||||
});
|
||||
}
|
||||
|
||||
return $p;
|
||||
}
|
||||
|
||||
sub YearMonth {
|
||||
my ($p, $calmon) = @_;
|
||||
|
||||
my ($month, $year) = ($calmon->{'month'}, $calmon->{'year'});
|
||||
$calmon->{'_type'} = 'YearMonth';
|
||||
$calmon->{'weeks'} = [];
|
||||
$calmon->{'url'} = sprintf("$p->{'_u'}->{'_journalbase'}/$year/%02d/", $month);
|
||||
|
||||
my $count = LJ::S2::get_journal_day_counts($p);
|
||||
my $has_entries = $count->{$year} && $count->{$year}->{$month} ? 1 : 0;
|
||||
$calmon->{'has_entries'} = $has_entries;
|
||||
|
||||
my $start_monday = 0; # FIXME: check some property to see if weeks start on monday
|
||||
my $week = undef;
|
||||
|
||||
my $flush_week = sub {
|
||||
my $end_month = shift;
|
||||
return unless $week;
|
||||
push @{$calmon->{'weeks'}}, $week;
|
||||
if ($end_month) {
|
||||
$week->{'post_empty'} =
|
||||
7 - $week->{'pre_empty'} - @{$week->{'days'}};
|
||||
}
|
||||
$week = undef;
|
||||
};
|
||||
|
||||
my $push_day = sub {
|
||||
my $d = shift;
|
||||
unless ($week) {
|
||||
my $leading = $d->{'date'}->{'_dayofweek'}-1;
|
||||
if ($start_monday) {
|
||||
$leading = 6 if --$leading < 0;
|
||||
}
|
||||
$week = {
|
||||
'_type' => 'YearWeek',
|
||||
'days' => [],
|
||||
'pre_empty' => $leading,
|
||||
'post_empty' => 0,
|
||||
};
|
||||
}
|
||||
push @{$week->{'days'}}, $d;
|
||||
if ($week->{'pre_empty'} + @{$week->{'days'}} == 7) {
|
||||
$flush_week->();
|
||||
my $size = scalar @{$calmon->{'weeks'}};
|
||||
}
|
||||
};
|
||||
|
||||
my $day_of_week = LJ::day_of_week($year, $month, 1);
|
||||
|
||||
my $daysinmonth = LJ::days_in_month($month, $year);
|
||||
|
||||
for my $day (1..$daysinmonth) {
|
||||
# so we don't auto-vivify years/months
|
||||
my $daycount = $has_entries ? $count->{$year}->{$month}->{$day} : 0;
|
||||
my $d = YearDay($p->{'_u'}, $year, $month, $day,
|
||||
$daycount, $day_of_week+1);
|
||||
$push_day->($d);
|
||||
$day_of_week = ($day_of_week + 1) % 7;
|
||||
}
|
||||
$flush_week->(1); # end of month flag
|
||||
|
||||
my $nowval = $year * 12 + $month;
|
||||
|
||||
# determine the most recent month with posts that is older than
|
||||
# the current time $month/$year. gives calendars the ability to
|
||||
# provide smart next/previous links.
|
||||
my $maxbefore;
|
||||
while (my ($iy, $h) = each %$count) {
|
||||
next if $iy > $year;
|
||||
while (my $im = each %$h) {
|
||||
next if $im >= $month;
|
||||
my $val = $iy * 12 + $im;
|
||||
if ($val < $nowval && $val > $maxbefore) {
|
||||
$maxbefore = $val;
|
||||
$calmon->{'prev_url'} = $p->{'_u'}->{'_journalbase'} . sprintf("/%04d/%02d/", $iy, $im);
|
||||
$calmon->{'prev_date'} = Date($iy, $im, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# same, except inverse: next month after current time with posts
|
||||
my $minafter;
|
||||
while (my ($iy, $h) = each %$count) {
|
||||
next if $iy < $year;
|
||||
while (my $im = each %$h) {
|
||||
next if $im <= $month;
|
||||
my $val = $iy * 12 + $im;
|
||||
if ($val > $nowval && (!$minafter || $val < $minafter)) {
|
||||
$minafter = $val;
|
||||
$calmon->{'next_url'} = $p->{'_u'}->{'_journalbase'} . sprintf("/%04d/%02d/", $iy, $im);
|
||||
$calmon->{'next_date'} = Date($iy, $im, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $calmon;
|
||||
}
|
||||
|
||||
sub YearYear {
|
||||
my ($year, $url, $displayed) = @_;
|
||||
return { '_type' => "YearYear",
|
||||
'year' => $year, 'url' => $url, 'displayed' => $displayed };
|
||||
}
|
||||
|
||||
sub YearDay {
|
||||
my ($u, $year, $month, $day, $count, $dow) = @_;
|
||||
my $d = {
|
||||
'_type' => 'YearDay',
|
||||
'day' => $day,
|
||||
'date' => Date($year, $month, $day, $dow),
|
||||
'num_entries' => $count
|
||||
};
|
||||
if ($count) {
|
||||
$d->{'url'} = sprintf("$u->{'_journalbase'}/$year/%02d/%02d/",
|
||||
$month, $day);
|
||||
}
|
||||
return $d;
|
||||
}
|
||||
|
||||
1;
|
||||
2164
local/cgi-bin/LJ/TextMessage.pm
Executable file
2164
local/cgi-bin/LJ/TextMessage.pm
Executable file
File diff suppressed because it is too large
Load Diff
3712
local/cgi-bin/LJ/User.pm
Executable file
3712
local/cgi-bin/LJ/User.pm
Executable file
File diff suppressed because it is too large
Load Diff
1458
local/cgi-bin/LJR/Distributed.pm
Executable file
1458
local/cgi-bin/LJR/Distributed.pm
Executable file
File diff suppressed because it is too large
Load Diff
51
local/cgi-bin/LJR/GD.pm
Normal file
51
local/cgi-bin/LJR/GD.pm
Normal file
@@ -0,0 +1,51 @@
|
||||
use strict;
|
||||
use GD::Simple;
|
||||
|
||||
package LJR::GD;
|
||||
|
||||
sub generate_number {
|
||||
my ($num, $fontname, $fontcolor, $stuff) = @_;
|
||||
|
||||
$num =~ s/^(\ +)//g;
|
||||
$num =~ s/(\ +)$//g;
|
||||
|
||||
my $font;
|
||||
if ($fontname eq "gdTinyFont") {
|
||||
$font = GD::Font->Tiny();
|
||||
}
|
||||
elsif ($fontname eq "gdSmallFont") {
|
||||
$font = GD::Font->Small();
|
||||
}
|
||||
elsif ($fontname eq "gdLargeFont") {
|
||||
$font = GD::Font->Large();
|
||||
}
|
||||
elsif ($fontname eq "gdMediumBoldFont") {
|
||||
$font = GD::Font->MediumBold();
|
||||
}
|
||||
elsif ($fontname eq "gdGiantFont") {
|
||||
$font = GD::Font->Giant();
|
||||
}
|
||||
else {
|
||||
$font = GD::Font->Small();
|
||||
}
|
||||
|
||||
my $cell_width = $font->width;
|
||||
my $cell_height = $font->height;
|
||||
my $cols = length($stuff) > length($num) ? length($stuff) : length($num);
|
||||
my $width = int($cols * $cell_width + $cell_width / 3);
|
||||
my $height = $cell_height + 1;
|
||||
my $img = GD::Simple->new($width,$height);
|
||||
$img->font($font);
|
||||
$img->moveTo(1,$font->height + 1);
|
||||
$img->transparent("white");
|
||||
$img->bgcolor("white");
|
||||
$img->fgcolor($fontcolor);
|
||||
|
||||
my $str = (length($num) < length($stuff) ?
|
||||
substr($stuff, 0, length($stuff) - length($num)) :
|
||||
"") . $num;
|
||||
$img->string($str);
|
||||
return $img;
|
||||
}
|
||||
|
||||
return 1;
|
||||
234
local/cgi-bin/LJR/Gate.pm
Normal file
234
local/cgi-bin/LJR/Gate.pm
Normal file
@@ -0,0 +1,234 @@
|
||||
use strict;
|
||||
|
||||
use XMLRPC::Lite;
|
||||
use Digest::MD5;
|
||||
use Time::Local;
|
||||
|
||||
use LJR::Distributed;
|
||||
use LJR::xmlrpc;
|
||||
use LJR::Viewuserstandalone;
|
||||
|
||||
require "$ENV{'LJHOME'}/cgi-bin/ljpoll.pl";
|
||||
|
||||
package LJR::Gate;
|
||||
|
||||
$LJR::Gate::clientver = 'LJR::Gate/0.02';
|
||||
|
||||
sub Authenticate {
|
||||
my ($server, $user, $pass) = @_;
|
||||
|
||||
my $xmlrpc = new XMLRPC::Lite;
|
||||
$xmlrpc->proxy("http://" . $server . "/interface/xmlrpc", timeout => 60);
|
||||
|
||||
my $xmlrpc_ret = LJR::xmlrpc::xmlrpc_call($xmlrpc, "LJ.XMLRPC.getchallenge");
|
||||
return $xmlrpc_ret if $xmlrpc_ret->{"err_text"};
|
||||
|
||||
my $challenge = $xmlrpc_ret->{'result'}->{'challenge'};
|
||||
my $response = Digest::MD5::md5_hex($challenge . Digest::MD5::md5_hex($pass));
|
||||
|
||||
my $xmlrpc_req = {
|
||||
'username' => $user,
|
||||
'auth_method' => 'challenge',
|
||||
'auth_challenge' => $challenge,
|
||||
'auth_response' => $response,
|
||||
'ver' => 1,
|
||||
'clientver' => $LJR::Gate::clientver,
|
||||
};
|
||||
|
||||
$xmlrpc_ret = LJR::xmlrpc::xmlrpc_call($xmlrpc, "LJ.XMLRPC.login", $xmlrpc_req);
|
||||
return $xmlrpc_ret if $xmlrpc_ret->{"err_text"};
|
||||
|
||||
return $xmlrpc;
|
||||
}
|
||||
|
||||
sub ExportEntry {
|
||||
my ($u, $req, $security, $jitemid, $anum) = @_;
|
||||
|
||||
return "User [" . $u->{'user'} . "] is not gated." unless LJR::Distributed::is_gated_local($u->{'user'});
|
||||
|
||||
my $dbr = LJ::get_db_reader();
|
||||
return "Can't get database reader!" unless $dbr;
|
||||
|
||||
my $r;
|
||||
$r = $dbr->selectrow_hashref (
|
||||
"SELECT * FROM ljr_export_settings WHERE user=?",
|
||||
undef, $u->{'user'});
|
||||
|
||||
my $ru;
|
||||
$ru = LJR::Distributed::get_cached_user({ 'ru_id' => $r->{'ru_id'}});
|
||||
$ru = LJR::Distributed::get_remote_server_byid($ru);
|
||||
|
||||
my $xmlrpc = new XMLRPC::Lite;
|
||||
$xmlrpc->proxy($ru->{'servername'} . "/interface/xmlrpc", timeout => 60);
|
||||
|
||||
my $xmlrpc_ret;
|
||||
my $xmlrpc_req;
|
||||
my $challenge;
|
||||
my $response;
|
||||
|
||||
my $real_event;
|
||||
my $real_subject;
|
||||
|
||||
my $last_status;
|
||||
|
||||
if ($req->{'event'} !~ /\S/) {
|
||||
$last_status = "removed entry.";
|
||||
|
||||
$real_event = $req->{'event'};
|
||||
$real_subject = $req->{'subject'};
|
||||
}
|
||||
else {
|
||||
my $item_url = LJ::item_link($u, $jitemid, $anum);
|
||||
$last_status = "exported <a href=$item_url>entry</a>";
|
||||
|
||||
$real_event = LJR::Viewuserstandalone::expand_ljuser_tags($req->{'event'});
|
||||
$real_subject = LJR::Viewuserstandalone::expand_ljuser_tags($req->{'subject'});
|
||||
|
||||
my $i=0;
|
||||
while ($real_event =~ /lj-cut/ig) { $i++ };
|
||||
while ($real_event =~ /\/lj-cut/ig) { $i-- };
|
||||
if ($i gt 0) {
|
||||
$real_event .= "</lj-cut>";
|
||||
}
|
||||
LJ::Poll::replace_polls_with_links(\$real_event);
|
||||
LJ::EmbedModule->expand_entry($u, \$real_event, ('content_only' => 1));
|
||||
|
||||
unless ($req->{'props'}->{'opt_nocomments'}) {
|
||||
LJR::Distributed::sign_exported_gate_entry($u, $jitemid, $anum, \$real_event);
|
||||
}
|
||||
}
|
||||
|
||||
$security = $req->{'sequrity'} if !$security && $req->{'security'};
|
||||
$security = "public" unless $security;
|
||||
|
||||
$xmlrpc_req = {
|
||||
'username' => $ru->{'username'},
|
||||
'auth_method' => 'challenge',
|
||||
'ver' => 1,
|
||||
'clientver' => $LJR::Gate::clientver,
|
||||
'subject' => $real_subject,
|
||||
'event' => $real_event,
|
||||
'year' => $req->{'year'},
|
||||
'mon' => $req->{'mon'},
|
||||
'day' => $req->{'day'},
|
||||
'hour' => $req->{'hour'},
|
||||
'min' => $req->{'min'},
|
||||
'security' => $security,
|
||||
'allowmask' => $req->{'allowmask'},
|
||||
'props' => {
|
||||
'current_moodid' => $req->{'props'}->{'current_moodid'},
|
||||
'current_mood' => $req->{'props'}->{'current_mood'},
|
||||
'current_music' => $req->{'props'}->{'current_music'},
|
||||
'picture_keyword' => $req->{'props'}->{'picture_keyword'},
|
||||
'taglist' => $req->{'props'}->{'taglist'},
|
||||
'opt_backdated' => $req->{'props'}->{'opt_backdated'},
|
||||
'opt_preformatted' => $req->{'props'}->{'opt_preformatted'},
|
||||
'opt_nocomments' => 1,
|
||||
},
|
||||
};
|
||||
|
||||
my $is_invalid_remote_journal = sub {
|
||||
my ($error_message) = @_;
|
||||
if (
|
||||
$error_message =~ /Invalid password/ ||
|
||||
$error_message =~ /Selected journal no longer exists/ ||
|
||||
$error_message =~ /account is suspended/ ||
|
||||
$error_message =~ /Invalid username/
|
||||
) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
my $is_invalid_remote_entry = sub {
|
||||
my ($error_message) = @_;
|
||||
if ($error_message =~ /Can\'t edit post from requested journal/) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
my $post_new_event = sub {
|
||||
$xmlrpc_ret = LJR::xmlrpc::xmlrpc_call($xmlrpc, "LJ.XMLRPC.getchallenge");
|
||||
return $xmlrpc_ret->{"err_text"} if $xmlrpc_ret->{"err_text"};
|
||||
$challenge = $xmlrpc_ret->{'result'}->{'challenge'};
|
||||
$response = Digest::MD5::md5_hex($challenge . Digest::MD5::md5_hex($r->{'remote_password'}));
|
||||
$xmlrpc_req->{'auth_challenge'} = $challenge;
|
||||
$xmlrpc_req->{'auth_response'} = $response;
|
||||
|
||||
my $item_time = Time::Local::timelocal(0, $req->{'min'}, $req->{'hour'},
|
||||
$req->{'day'}, $req->{'mon'} - 1, $req->{'year'});
|
||||
|
||||
if ((time - $item_time) > 60*60*24) {
|
||||
$xmlrpc_req->{'props'}->{'opt_backdated'} = 1;
|
||||
}
|
||||
|
||||
$xmlrpc_ret = LJR::xmlrpc::xmlrpc_call($xmlrpc, "LJ.XMLRPC.postevent", $xmlrpc_req);
|
||||
if ($xmlrpc_ret->{'err_text'}) {
|
||||
if ($is_invalid_remote_journal->($xmlrpc_ret->{'err_text'})) {
|
||||
$r = LJR::Distributed::update_export_status($u->{'user'}, 0, "ERROR: " . $xmlrpc_ret->{'err_text'});
|
||||
}
|
||||
else {
|
||||
$r = LJR::Distributed::update_export_status($u->{'user'}, 1, "ERROR: " . $xmlrpc_ret->{'err_text'});
|
||||
}
|
||||
return $xmlrpc_ret->{"err_text"} . " " . ($r->{'err'} ? $r->{'errtext'} : "");
|
||||
}
|
||||
|
||||
my $rhtml_id = $xmlrpc_ret->{'result'}->{'itemid'} * 256 +
|
||||
$xmlrpc_ret->{'result'}->{'anum'};
|
||||
|
||||
$r = LJR::Distributed::store_remote_itemid(
|
||||
$u,
|
||||
$jitemid,
|
||||
$ru->{'ru_id'},
|
||||
$xmlrpc_ret->{'result'}->{'itemid'},
|
||||
$rhtml_id,
|
||||
"E"
|
||||
);
|
||||
return
|
||||
"store_remote_itemid: " . $u->{'user'} . "," .
|
||||
$jitemid . "," . $ru->{'ru_id'} . "," .
|
||||
$xmlrpc_ret->{'result'}->{'itemid'} . "," . $rhtml_id . ": " .
|
||||
$r->{"errtext"} if $r->{"err"};
|
||||
};
|
||||
|
||||
my $ritem = LJR::Distributed::get_remote_itemid($u->{'userid'}, $jitemid, "E");
|
||||
if ($ritem && ($req->{'props'}->{'revnum'} || $req->{'event'} !~ /\S/)) {
|
||||
$xmlrpc_ret = LJR::xmlrpc::xmlrpc_call($xmlrpc, "LJ.XMLRPC.getchallenge");
|
||||
return $xmlrpc_ret->{"err_text"} if $xmlrpc_ret->{"err_text"};
|
||||
$challenge = $xmlrpc_ret->{'result'}->{'challenge'};
|
||||
$response = Digest::MD5::md5_hex($challenge . Digest::MD5::md5_hex($r->{'remote_password'}));
|
||||
$xmlrpc_req->{'auth_challenge'} = $challenge;
|
||||
$xmlrpc_req->{'auth_response'} = $response;
|
||||
|
||||
$xmlrpc_req->{'itemid'} = $ritem->{'ritemid'};
|
||||
|
||||
$xmlrpc_ret = LJR::xmlrpc::xmlrpc_call($xmlrpc, "LJ.XMLRPC.editevent", $xmlrpc_req);
|
||||
if ($xmlrpc_ret->{'err_text'}) {
|
||||
if ($is_invalid_remote_entry->($xmlrpc_ret->{'err_text'})) {
|
||||
LJR::Distributed::remove_remote_itemid($u, $jitemid, $ru->{'ru_id'}, $ritem->{'ritemid'}, "E");
|
||||
my $errmsg = $post_new_event->();
|
||||
return $errmsg if $errmsg;
|
||||
}
|
||||
elsif ($is_invalid_remote_journal->($xmlrpc_ret->{'err_text'})) {
|
||||
$r = LJR::Distributed::update_export_status($u->{'user'}, 0, "ERROR: " . $xmlrpc_ret->{'err_text'});
|
||||
return $xmlrpc_ret->{"err_text"} . " " . ($r->{'err'} ? $r->{'errtext'} : "");
|
||||
}
|
||||
$r = LJR::Distributed::update_export_status($u->{'user'}, 1, "ERROR: " . $xmlrpc_ret->{'err_text'});
|
||||
return $xmlrpc_ret->{"err_text"} . " " . ($r->{'err'} ? $r->{'errtext'} : "");
|
||||
}
|
||||
if ($req->{'event'} !~ /\S/) {
|
||||
LJR::Distributed::remove_remote_itemid($u, $jitemid, $ru->{'ru_id'}, $ritem->{'ritemid'}, "E");
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
my $errmsg = $post_new_event->();
|
||||
return $errmsg if $errmsg;
|
||||
}
|
||||
|
||||
$r = LJR::Distributed::update_export_status($u->{'user'}, 1, "OK: $last_status");
|
||||
return $r->{'errtext'} if $r->{'err'};
|
||||
|
||||
return;
|
||||
}
|
||||
241
local/cgi-bin/LJR/Viewuser.pm
Executable file
241
local/cgi-bin/LJR/Viewuser.pm
Executable file
@@ -0,0 +1,241 @@
|
||||
package LJR::Viewuser;
|
||||
|
||||
use strict;
|
||||
use Carp;
|
||||
use lib "$ENV{'LJHOME'}/cgi-bin";
|
||||
use DBI;
|
||||
use DBI::Role;
|
||||
use DBIx::StateKeeper;
|
||||
|
||||
# A function to canonicalize sitename: take one of the possible
|
||||
# abbreviations for a given known site, and returns the siteid
|
||||
# from the list. Otherwise, assume that abbreivation is actually the
|
||||
# full URL, and return it "as is", without the possible leading http://.
|
||||
#
|
||||
# We check the known servers database for "site=servername" or "site
|
||||
# contains serverurl without the leading www"; make additional
|
||||
# explicit matchings if necessary (presently none are necessary), et
|
||||
# voila.
|
||||
#
|
||||
|
||||
sub canonical_sitenum {
|
||||
my ($site)=@_;
|
||||
|
||||
# Cut away leading http://
|
||||
$site =~ s|http://(.*)|$1|;
|
||||
|
||||
my $dbh = LJ::get_db_reader();
|
||||
my $sth = $dbh->prepare(
|
||||
"SELECT serverid FROM alienservers WHERE servername=?"
|
||||
);
|
||||
|
||||
$sth->execute($site);
|
||||
return LJ::error($dbh) if $dbh->err;
|
||||
#
|
||||
# Match $site=servername (e.g. "LJ")
|
||||
#
|
||||
if ($sth->rows) {
|
||||
my ($guu) = $sth->fetchrow_array;
|
||||
return $guu;
|
||||
}
|
||||
$sth->finish;
|
||||
|
||||
$sth = $dbh->prepare(
|
||||
"SELECT serverid, REPLACE(serverurl, 'www.', '') FROM alienservers"
|
||||
);
|
||||
$sth->execute;
|
||||
return LJ::error($dbh) if $dbh->err;
|
||||
#
|
||||
# Scan all known servers and match "serverurl without www is
|
||||
# contained in $site"
|
||||
#
|
||||
while (my ($hale, $guu) = $sth->fetchrow_array) {
|
||||
if (index ($site, $guu) !=-1) {
|
||||
return $hale;
|
||||
}
|
||||
}
|
||||
|
||||
if ( (lc($site) eq "ljr") || ($site =~ m/.*${LJ::DOMAIN}.*/) )
|
||||
#
|
||||
# 0 means ourselves
|
||||
#
|
||||
{return 0;}
|
||||
# elsif ( ($site eq "LJ") || ($site =~ m/.*livejournal\.com.*/) )
|
||||
# {return 1;}
|
||||
# elsif ( ($site eq "GJ") || ($site =~ m/.*greatestjournal\.com.*/) )
|
||||
# {return 2;}
|
||||
# elsif ( ($site eq "NPJ") || ($site =~ m/.*npj\.ru.*/) )
|
||||
# {return 3;}
|
||||
else {return $site};
|
||||
|
||||
}
|
||||
|
||||
#
|
||||
# Provides a representation of a user.
|
||||
#
|
||||
# Format: we receive a username and a site, where site is either a
|
||||
# number or a string. If a non-zero number, this is a known site; we take
|
||||
# information about it from the alianservers table in the db. If
|
||||
# zero, site is ourselves. If a string, we do not know anything about
|
||||
# the site and treat it as an OpenID guest; we assume site is the URL.
|
||||
#
|
||||
# We return the HTML code.
|
||||
#
|
||||
# <lj user="username" site="sitename"> should be expand to
|
||||
# ljuser( $username, {'site'=> canonical_sitenum($sitename),
|
||||
# 'type'=>'P'} )
|
||||
#
|
||||
# For lj comm, replace 'P' with 'C'
|
||||
#
|
||||
|
||||
sub ljuser {
|
||||
# we assume $opts->{'site'} to be a siteid of a known site or a full
|
||||
# URL of a site we do not have in db
|
||||
my $user = shift;
|
||||
my $opts = shift;
|
||||
my $u;
|
||||
my $native=0;
|
||||
my $known=0;
|
||||
|
||||
my $name="";
|
||||
my $url;
|
||||
my $uicon;
|
||||
my $cicon;
|
||||
my $commdir;
|
||||
my $udir;
|
||||
my $lj_type;
|
||||
|
||||
# If site is not given, assume native (siteid=0)
|
||||
unless ($opts->{'site'}) {$opts->{'site'}=0;}
|
||||
|
||||
# Check if site is a number
|
||||
if($opts->{'site'} =~ m/(\d+)/)
|
||||
{ $known=1; }
|
||||
|
||||
if($known) {
|
||||
|
||||
# Site a number (known site)
|
||||
|
||||
$opts->{'site'} = $opts->{'site'}+0;
|
||||
|
||||
# now we've got default - $LJ::DOMAIN
|
||||
|
||||
if ($opts->{'site'}==0){
|
||||
|
||||
# local
|
||||
$url=$LJ::DOMAIN;
|
||||
$cicon='community.gif'; # default local commicon
|
||||
$uicon='userinfo.gif'; # default local usericon
|
||||
$commdir='community/';
|
||||
$udir='users/';
|
||||
$lj_type='Y';
|
||||
|
||||
$native=1;
|
||||
} else {
|
||||
|
||||
# alien but known --
|
||||
# go to db to get $name
|
||||
|
||||
my $dbh = LJ::get_db_writer();
|
||||
my $sth = $dbh->prepare("SELECT serverurl, servername, udir, uicon, cdir, cicon, ljtype FROM alienservers WHERE serverid=?");
|
||||
$sth->execute($opts->{'site'});
|
||||
($url, $name, $udir, $uicon, $commdir, $cicon, $lj_type) = $sth->fetchrow_array;
|
||||
$native=0;
|
||||
}
|
||||
} else {
|
||||
|
||||
# site is not a number -- unknown alien site
|
||||
|
||||
$name=$opts->{'site'};
|
||||
$url=$opts->{'site'};
|
||||
$uicon='openid-profile.gif'; # default unknown alien usericon
|
||||
$cicon='openid-profile.gif'; # default unknown alien commicon
|
||||
$commdir='';
|
||||
$udir='';
|
||||
$lj_type='N';
|
||||
$native=0;
|
||||
|
||||
}
|
||||
|
||||
if ($native){
|
||||
|
||||
# If the user is local, we do some processing: check validity, check
|
||||
# whether user or community, etc.
|
||||
|
||||
# my $do_dynamic = $LJ::DYNAMIC_LJUSER || ($user =~ /^ext_/);
|
||||
# if ($do_dynamic && ! isu($user) && ! $opts->{'type'}) {
|
||||
# Try to automatically pick the user type, but still
|
||||
# make something if we can't (user doesn't exist?)
|
||||
$user = LJ::load_user($user) || $user;
|
||||
|
||||
my $hops = 0;
|
||||
|
||||
# Traverse the renames to the final journal
|
||||
while (ref $user and $user->{'journaltype'} eq 'R'
|
||||
and ! $opts->{'no_follow'} && $hops++ < 5) {
|
||||
|
||||
LJ::load_user_props($user, 'renamedto');
|
||||
last unless length $user->{'renamedto'};
|
||||
$user = LJ::load_user($user->{'renamedto'});
|
||||
|
||||
}
|
||||
# }
|
||||
|
||||
if (LJ::isu($user)) {
|
||||
$u = $user;
|
||||
$opts->{'type'} = $user->{'journaltype'};
|
||||
# Mark accounts as deleted that aren't visible, memorial, or locked
|
||||
$opts->{'del'} = $user->{'statusvis'} ne 'V' &&
|
||||
$user->{'statusvis'} ne 'M' &&
|
||||
$user->{'statusvis'} ne 'L';
|
||||
$user = $user->{'user'};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# End of local-specific part
|
||||
|
||||
my $andfull = $opts->{'full'} ? "&mode=full" : "";
|
||||
my $img = $opts->{'imgroot'} || $LJ::IMGPREFIX;
|
||||
my $strike = $opts->{'del'} ? ' text-decoration: line-through;' : '';
|
||||
my $make_tag = sub {
|
||||
my ($s, $n, $fil, $dir) = @_;
|
||||
$n = lc ($n);
|
||||
|
||||
if ($n eq ""){
|
||||
return "<span class='ljruser' style='white-space: nowrap;$strike'><a href='http://$s/userinfo.bml?user=$user$andfull'><img src='$img/$fil' alt='[info]' style='vertical-align: bottom; border: 0;' /></a><a href='http://$s/$dir$user/'><b>$user</b></a></span>";
|
||||
} else {
|
||||
if ($lj_type eq 'Y') {
|
||||
|
||||
# If the site is known and has an lj-type engine, then we now how to
|
||||
# refer to userinfo; make the info icon link to this
|
||||
|
||||
return "<span class='ljruser' style='white-space: nowrap;$strike'><a href='http://$s/userinfo.bml?user=$user$andfull'><img src='$img/$fil' alt='[info]' style='vertical-align: bottom; border: 0;' /></a><a href='http://$s/$dir$user/'><b>$user\@$n</b></a></span>";
|
||||
} elsif ($known) {
|
||||
|
||||
# If not lj-type, but known, let the info icon link to the user journal
|
||||
|
||||
return "<span class='ljruser' style='white-space: nowrap;$strike'><a href='http://$s/$dir$user/'><img src='$img/$fil' alt='[info]' style='vertical-align: bottom; border: 0;' /></a><a href='http://$s/$dir$user/'><b>$user\@$n</b></a></span>";
|
||||
} else {
|
||||
|
||||
# Unknown site. Treat as openid
|
||||
|
||||
return "<span class='ljruser' style='white-space: nowrap;$strike'><a href='http://$s/$dir$user/'><img src='$img/$fil' alt='[info]' style='vertical-align: bottom; border: 0;' /></a><a href='http://$s/$dir$user/'><b>$user</b> [$n]</a></span>";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if ($opts->{'type'} eq 'C') {
|
||||
return $make_tag->( $url, $name, $cicon, $commdir);
|
||||
} elsif ($opts->{'type'} eq 'Y') {
|
||||
return $make_tag->( $url, $name, 'syndicated.gif', 'users/');
|
||||
} elsif ($opts->{'type'} eq 'N') {
|
||||
return $make_tag->( $url, $name, 'newsinfo.gif', 'users/');
|
||||
} elsif ($opts->{'type'} eq 'I') {
|
||||
return $u->ljuser_display($opts);
|
||||
} else {
|
||||
return $make_tag->( $url, $name, $uicon, $udir);
|
||||
}
|
||||
};
|
||||
|
||||
1;
|
||||
210
local/cgi-bin/LJR/Viewuserstandalone.pm
Executable file
210
local/cgi-bin/LJR/Viewuserstandalone.pm
Executable file
@@ -0,0 +1,210 @@
|
||||
package LJR::Viewuserstandalone;
|
||||
|
||||
use strict;
|
||||
|
||||
# A function to canonicalize sitename: take one of the possible
|
||||
# abbreviations for a given known site, and returns the siteid
|
||||
# from the list. Otherwise, assume that abbreivation is actually the
|
||||
# full URL, and return it "as is", without the possible leading http://.
|
||||
# Right now we work case-by-case, since the number of known
|
||||
# abbreviations is small.
|
||||
#
|
||||
#
|
||||
# Known sites:
|
||||
#
|
||||
# 0 -- local
|
||||
# 1 -- www.livejournal.com
|
||||
# 2 -- greatestjournal.com
|
||||
# 3 -- npj.ru
|
||||
# 4 -- dreamwidth.org
|
||||
# TODO: add third level domains
|
||||
|
||||
sub canonical_sitenum {
|
||||
my ($site)=@_;
|
||||
|
||||
if ( ($site eq "LJR") || ($site =~ m/.*lj\.rossia\.org.*/) )
|
||||
{return 0;}
|
||||
elsif ( ($site eq "LJ") || ($site =~ m/.*livejournal\.com.*/) )
|
||||
{return 1;}
|
||||
elsif ( ($site eq "GJ") || ($site =~ m/.*greatestjournal\.com.*/) )
|
||||
{return 2;}
|
||||
elsif ( ($site eq "NPJ") || ($site =~ m/.*npj\.ru.*/) )
|
||||
{return 3;}
|
||||
elsif ( ($site eq "DW") || ($site eq "dw") || ($site =~ m/.*dreamwidth\.org.*/) )
|
||||
{return 4;}
|
||||
else {return $site;}
|
||||
}
|
||||
|
||||
#
|
||||
# Provides a representation of a user.
|
||||
#
|
||||
# Format: we receive a username and a site, where site is either a
|
||||
# number or a string. If a non-zero number, this is a known site; we take
|
||||
# information about it from the alianservers table in the db. If
|
||||
# zero, site is ourselves. If a string, we do not know anything about
|
||||
# the site and treat it as an OpenID guest; we assume site is the URL.
|
||||
#
|
||||
# We return the HTML code.
|
||||
#
|
||||
# <lj user="username" site="sitename"> should be expand to
|
||||
# ljuser( $username, {'site'=> canonical_sitenum($sitename),
|
||||
# 'type'=>'P','imgroot'=>''} )
|
||||
#
|
||||
# For lj comm, replace 'P' with 'C'; 'imgroot' should be equal to the
|
||||
# current value of $LJ::IMGPREFIX -- right now it is differs
|
||||
# between test and production!!
|
||||
#
|
||||
|
||||
sub ljuser {
|
||||
# we assume $opts->{'site'} to be a siteid of a known site or a full
|
||||
# URL of a site we do not have in db
|
||||
my $user = shift;
|
||||
my $opts = shift;
|
||||
my $u;
|
||||
|
||||
my $name="";
|
||||
my $url;
|
||||
my $uicon;
|
||||
my $cicon;
|
||||
my $commdir;
|
||||
my $udir;
|
||||
my $lj_type;
|
||||
|
||||
# If site is not given, assume native (siteid=0)
|
||||
unless ($opts->{'site'}) {$opts->{'site'}=0;}
|
||||
|
||||
# Check if site is a number
|
||||
if($opts->{'site'} =~ m/(\d+)/) {
|
||||
|
||||
# Site a number (known site)
|
||||
|
||||
$opts->{'site'} = $opts->{'site'}+0;
|
||||
|
||||
# now we've got default - $LJ::DOMAIN
|
||||
|
||||
if ($opts->{'site'}==0){
|
||||
|
||||
# local
|
||||
$url='lj.rossia.org';
|
||||
$cicon='community.gif'; # default local commicon
|
||||
$uicon='userinfo.gif'; # default local usericon
|
||||
$commdir='community/';
|
||||
$udir='users/';
|
||||
$lj_type='Y';
|
||||
} elsif ($opts->{'site'}==1) {
|
||||
# LJ
|
||||
$name="LJ";
|
||||
$url='www.livejournal.com';
|
||||
$cicon='community-lj.gif';
|
||||
$uicon='userinfo-lj.gif';
|
||||
$commdir='community/';
|
||||
$udir='users/';
|
||||
$lj_type='Y';
|
||||
} elsif ($opts->{'site'}==2) {
|
||||
# GJ
|
||||
$name="GJ";
|
||||
$url='www.greatestjournal.com';
|
||||
$cicon='community-lj.gif';
|
||||
$uicon='userinfo-lj.gif';
|
||||
$commdir='community/';
|
||||
$udir='users/';
|
||||
$lj_type='Y';
|
||||
} elsif ($opts->{'site'}==3) {
|
||||
# LJ
|
||||
$name="NPJ";
|
||||
$url='www.npj.ru';
|
||||
$cicon='community-npj.gif';
|
||||
$uicon='userinfo-npj.gif';
|
||||
$commdir='';
|
||||
$udir='';
|
||||
$lj_type='N';
|
||||
} elsif ($opts->{'site'}==4) {
|
||||
# DW
|
||||
$name="DW";
|
||||
$url='www.dreamwidth.org';
|
||||
$cicon='community-dw.gif';
|
||||
$uicon='userinfo-dw.gif';
|
||||
$commdir='community/';
|
||||
$udir='users/';
|
||||
$lj_type='Y';
|
||||
} else { return "[Unknown LJ user tag]"; }
|
||||
|
||||
} else {
|
||||
|
||||
# site is not a number -- unknown alien site
|
||||
|
||||
$name=$opts->{'site'};
|
||||
$url=$opts->{'site'};
|
||||
$uicon=''; # default unknown alien usericon
|
||||
$cicon=''; # default unknown alien commicon
|
||||
$commdir='community';
|
||||
$udir='users';
|
||||
$lj_type='N';
|
||||
}
|
||||
|
||||
|
||||
my $andfull = $opts->{'full'} ? "&mode=full" : "";
|
||||
|
||||
my $img = $opts->{'imgroot'};
|
||||
my $make_tag = sub {
|
||||
my ($s, $n, $fil, $dir) = @_;
|
||||
if ($n eq ""){
|
||||
return "<span class='ljruser' style='white-space: nowrap;'><a href='http://$s/userinfo.bml?user=$user$andfull'><img src='$img/$fil' alt='[info]' style='vertical-align: bottom; border: 0;' /></a><a href='http://$s/$dir$user/'><b>$user</b></a></span>";
|
||||
} else {
|
||||
if ($lj_type eq 'Y') {
|
||||
|
||||
# If the site is known and has an lj-type engine, then we now how to
|
||||
# refer to userinfo; make the info icon link to this
|
||||
|
||||
return "<span class='ljruser' style='white-space: nowrap;'><a href='http://$s/userinfo.bml?user=$user$andfull'><img src='$img/$fil' alt='[info]' style='vertical-align: bottom; border: 0;' /></a><a href='http://$s/$dir$user/'><b>$user</b> [$n]</a></span>";
|
||||
} else {
|
||||
|
||||
# If not lj-type, let the info icon link to the user journal
|
||||
|
||||
return "<span class='ljruser' style='white-space: nowrap;'><a href='http://$s/$dir$user/'><img src='$img/$fil' alt='[info]' style='vertical-align: bottom; border: 0;' /></a><a href='http://$s/$dir$user/'><b>$user</b> [$n]</a></span>";
|
||||
}
|
||||
}
|
||||
};
|
||||
if ($opts->{'type'} eq 'C') {
|
||||
return $make_tag->( $url, $name, $cicon, $commdir);
|
||||
} else {
|
||||
return $make_tag->( $url, $name, $uicon, $udir);
|
||||
}
|
||||
}
|
||||
|
||||
sub expand_ljuser_tags {
|
||||
|
||||
my ($string)=@_;
|
||||
|
||||
return "" unless $string;
|
||||
|
||||
my $imgroot='http://lj.rossia.org/img';
|
||||
|
||||
$string=~ s/<lj\s+user=\"?(\w+)\"?\s+site=\"?([^"]+)\"?\s*\/?>/
|
||||
ljuser($1,{
|
||||
'site'=>canonical_sitenum($2),
|
||||
'type'=>'P','imgroot'=>$imgroot,
|
||||
})
|
||||
/egxi;
|
||||
$string=~ s/<lj\s+comm=\"?(\w+)\"?\s+site=\"?([^"]+)\"?\s*\/?>/
|
||||
ljuser($1,{
|
||||
'site'=>canonical_sitenum($2),
|
||||
'type'=>'C','imgroot'=>$imgroot,
|
||||
})
|
||||
/egxi;
|
||||
$string=~ s/<ljr\s+user=\"?(\w+)\"?\s*\/?>/
|
||||
ljuser($1,{
|
||||
'site'=>0,
|
||||
'type'=>'P','imgroot'=>$imgroot,
|
||||
})
|
||||
/egxi;
|
||||
$string=~ s/<ljr\s+comm=\"?(\w+)\"?\s*\/?>/
|
||||
ljuser($1,{
|
||||
'site'=>0,
|
||||
'type'=>'C','imgroot'=>$imgroot,
|
||||
})
|
||||
/egxi;
|
||||
return $string;
|
||||
}
|
||||
|
||||
1;
|
||||
25
local/cgi-bin/LJR/ljpoll-local.pl
Normal file
25
local/cgi-bin/LJR/ljpoll-local.pl
Normal file
@@ -0,0 +1,25 @@
|
||||
package LJ::Poll;
|
||||
|
||||
use strict;
|
||||
|
||||
sub replace_polls_with_links {
|
||||
my ($event) = @_;
|
||||
|
||||
my $dbr = LJ::get_db_reader();
|
||||
|
||||
while ($$event =~ /<lj-poll-(\d+)>/g) {
|
||||
my $pollid = $1;
|
||||
my $name = $dbr->selectrow_array("SELECT name FROM poll WHERE pollid=?",
|
||||
undef, $pollid);
|
||||
|
||||
if ($name) {
|
||||
LJ::Poll::clean_poll(\$name);
|
||||
} else {
|
||||
$name = "#$pollid";
|
||||
}
|
||||
|
||||
$$event =~ s!<lj-poll-$pollid>!<div><a href="$LJ::SITEROOT/poll/?id=$pollid">View Poll: $name</a></div>!g;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
53
local/cgi-bin/LJR/unicode.pm
Normal file
53
local/cgi-bin/LJR/unicode.pm
Normal file
@@ -0,0 +1,53 @@
|
||||
use strict;
|
||||
|
||||
package LJR::unicode;
|
||||
|
||||
use XML::Parser;
|
||||
use Unicode::MapUTF8 qw(to_utf8 from_utf8 utf8_supported_charset);
|
||||
|
||||
|
||||
sub utf8ize {
|
||||
my $text_in = shift;
|
||||
$$text_in = pack("C*", unpack("C*", $$text_in)) if $$text_in;
|
||||
}
|
||||
|
||||
|
||||
sub force_utf8 {
|
||||
my $xdata = shift;
|
||||
my %error_lines;
|
||||
my $finished = 0;
|
||||
my @xlines;
|
||||
my $orig_xdata = $$xdata;
|
||||
|
||||
my $p1 = new XML::Parser ();
|
||||
|
||||
while (!$finished) {
|
||||
eval { $p1->parse($$xdata); };
|
||||
|
||||
if ($@ && $@ =~ /not\ well\-formed\ \(invalid\ token\)\ at\ line\ (\d+)\,/) {
|
||||
my $error_line = $1;
|
||||
$error_lines{$error_line} ++;
|
||||
|
||||
if ($error_lines{$error_line} > 1) {
|
||||
$$xdata = $orig_xdata;
|
||||
$finished = 1;
|
||||
}
|
||||
else {
|
||||
@xlines = split(/\n/, $$xdata);
|
||||
my $output = to_utf8({ -string => $xlines[$error_line - 1], -charset => 'latin1' });
|
||||
$xlines[$error_line - 1] = $output;
|
||||
$$xdata = join("\n", @xlines);
|
||||
}
|
||||
}
|
||||
# unknown error or no error, doesn't matter
|
||||
elsif ($@) {
|
||||
$$xdata = $orig_xdata;
|
||||
$finished = 1;
|
||||
}
|
||||
else {
|
||||
$finished = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
28
local/cgi-bin/LJR/xmlrpc.pm
Normal file
28
local/cgi-bin/LJR/xmlrpc.pm
Normal file
@@ -0,0 +1,28 @@
|
||||
use strict;
|
||||
|
||||
package LJR::xmlrpc;
|
||||
|
||||
sub xmlrpc_call {
|
||||
my ($xmlrpc, $method, $request) = @_;
|
||||
my $res;
|
||||
|
||||
if ($xmlrpc) {
|
||||
$res = $xmlrpc->call ($method, $request);
|
||||
|
||||
if ($res && $res->fault) {
|
||||
$res->{"err_text"} = $method . ": " . "XML-RPC Error [" . $res->faultcode . "]: " . $res->faultstring;
|
||||
}
|
||||
elsif (!$res) {
|
||||
$res->{"err_text"} = $method . ": " . "Unknown XML-RPC Error.";
|
||||
}
|
||||
|
||||
$res->{"result"} = $res->result;
|
||||
}
|
||||
else {
|
||||
$res->{"err_text"} = "Invalid xmlrpc object";
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
return 1;
|
||||
585
local/cgi-bin/LWPx/ParanoidAgent.pm
Executable file
585
local/cgi-bin/LWPx/ParanoidAgent.pm
Executable file
@@ -0,0 +1,585 @@
|
||||
package LWPx::ParanoidAgent;
|
||||
require LWP::UserAgent;
|
||||
|
||||
use vars qw(@ISA $VERSION);
|
||||
@ISA = qw(LWP::UserAgent);
|
||||
$VERSION = '1.02';
|
||||
|
||||
require HTTP::Request;
|
||||
require HTTP::Response;
|
||||
|
||||
use HTTP::Status ();
|
||||
use strict;
|
||||
use Net::DNS;
|
||||
use LWP::Debug;
|
||||
|
||||
sub new {
|
||||
my $class = shift;
|
||||
my %opts = @_;
|
||||
|
||||
my $blocked_hosts = delete $opts{blocked_hosts} || [];
|
||||
my $whitelisted_hosts = delete $opts{whitelisted_hosts} || [];
|
||||
my $resolver = delete $opts{resolver};
|
||||
$opts{timeout} ||= 15;
|
||||
|
||||
my $self = LWP::UserAgent->new( %opts );
|
||||
|
||||
$self->{'blocked_hosts'} = $blocked_hosts;
|
||||
$self->{'whitelisted_hosts'} = $whitelisted_hosts;
|
||||
$self->{'resolver'} = $resolver;
|
||||
|
||||
$self = bless $self, $class;
|
||||
return $self;
|
||||
}
|
||||
|
||||
# returns seconds remaining given a request
|
||||
sub _time_remain {
|
||||
my $self = shift;
|
||||
my $req = shift;
|
||||
|
||||
my $now = time();
|
||||
my $start_time = $req->{_time_begin} || $now;
|
||||
return $start_time + $self->{timeout} - $now;
|
||||
}
|
||||
|
||||
sub _resolve {
|
||||
my ($self, $host, $request, $timeout, $depth) = @_;
|
||||
my $res = $self->resolver;
|
||||
$depth ||= 0;
|
||||
|
||||
die "CNAME recursion depth limit exceeded.\n" if $depth > 10;
|
||||
die "Suspicious results from DNS lookup" if $self->_bad_host($host);
|
||||
|
||||
# return the IP address if it looks like one and wasn't marked bad
|
||||
return ($host) if $host =~ /^\d+\.\d+\.\d+\.\d+$/;
|
||||
|
||||
my $sock = $res->bgsend($host)
|
||||
or die "No sock from bgsend";
|
||||
|
||||
my $rin = '';
|
||||
vec($rin, fileno($sock), 1) = 1;
|
||||
my $nf = select($rin, undef, undef, $self->_time_remain($request));
|
||||
die "DNS lookup timeout" unless $nf;
|
||||
|
||||
my $packet = $res->bgread($sock)
|
||||
or die "DNS bgread failure";
|
||||
$sock = undef;
|
||||
|
||||
my @addr;
|
||||
my $cname;
|
||||
foreach my $rr ($packet->answer) {
|
||||
if ($rr->type eq "A") {
|
||||
die "Suspicious DNS results from A record\n" if $self->_bad_host($rr->address);
|
||||
push @addr, $rr->address;
|
||||
} elsif ($rr->type eq "CNAME") {
|
||||
# will be checked for validity in the recursion path
|
||||
$cname = $rr->cname;
|
||||
}
|
||||
}
|
||||
|
||||
return @addr if @addr;
|
||||
return () unless $cname;
|
||||
return $self->_resolve($cname, $request, $timeout, $depth + 1);
|
||||
}
|
||||
|
||||
sub _host_list_match {
|
||||
my $self = shift;
|
||||
my $list_name = shift;
|
||||
my $host = shift;
|
||||
|
||||
foreach my $rule (@{ $self->{$list_name} }) {
|
||||
if (ref $rule eq "CODE") {
|
||||
return 1 if $rule->($host);
|
||||
} elsif (ref $rule) {
|
||||
# assume regexp
|
||||
return 1 if $host =~ /$rule/;
|
||||
} else {
|
||||
return 1 if $host eq $rule;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub _bad_host {
|
||||
my $self = shift;
|
||||
my $host = lc(shift);
|
||||
|
||||
return 0 if $self->_host_list_match("whitelisted_hosts", $host);
|
||||
return 1 if $self->_host_list_match("blocked_hosts", $host);
|
||||
return 1 if
|
||||
$host =~ /^localhost$/i || # localhost is bad. even though it'd be stopped in
|
||||
# a later call to _bad_host with the IP address
|
||||
$host =~ /\s/i; # any whitespace is questionable
|
||||
|
||||
# Let's assume it's an IP address now, and get it into 32 bits.
|
||||
# Uf at any time something doesn't look like a number, then it's
|
||||
# probably a hostname and we've already either whitelisted or
|
||||
# blacklisted those, so we'll just say it's okay and it'll come
|
||||
# back here later when the resolver finds an IP address.
|
||||
my @parts = split(/\./, $host);
|
||||
return 0 if @parts > 4;
|
||||
|
||||
# un-octal/un-hex the parts, or return if there's a non-numeric part
|
||||
my $overflow_flag = 0;
|
||||
foreach (@parts) {
|
||||
return 0 unless /^\d+$/ || /^0x[a-f\d]+$/;
|
||||
local $SIG{__WARN__} = sub { $overflow_flag = 1; };
|
||||
$_ = oct($_) if /^0/;
|
||||
}
|
||||
|
||||
# a purely numeric address shouldn't overflow.
|
||||
return 1 if $overflow_flag;
|
||||
|
||||
my $addr; # network order packed IP address
|
||||
|
||||
if (@parts == 1) {
|
||||
# a - 32 bits
|
||||
return 1 if
|
||||
$parts[0] > 0xffffffff;
|
||||
$addr = pack("N", $parts[0]);
|
||||
} elsif (@parts == 2) {
|
||||
# a.b - 8.24 bits
|
||||
return 1 if
|
||||
$parts[0] > 0xff ||
|
||||
$parts[1] > 0xffffff;
|
||||
$addr = pack("N", $parts[0] << 24 | $parts[1]);
|
||||
} elsif (@parts == 3) {
|
||||
# a.b.c - 8.8.16 bits
|
||||
return 1 if
|
||||
$parts[0] > 0xff ||
|
||||
$parts[1] > 0xff ||
|
||||
$parts[2] > 0xffff;
|
||||
$addr = pack("N", $parts[0] << 24 | $parts[1] << 16 | $parts[2]);
|
||||
} else {
|
||||
# a.b.c.d - 8.8.8.8 bits
|
||||
return 1 if
|
||||
$parts[0] > 0xff ||
|
||||
$parts[1] > 0xff ||
|
||||
$parts[2] > 0xff ||
|
||||
$parts[3] > 0xff;
|
||||
$addr = pack("N", $parts[0] << 24 | $parts[1] << 16 | $parts[2] << 8 | $parts[3]);
|
||||
}
|
||||
|
||||
my $haddr = unpack("N", $addr); # host order IP address
|
||||
return 1 if
|
||||
($haddr & 0xFF000000) == 0x00000000 || # 0.0.0.0/8
|
||||
($haddr & 0xFF000000) == 0x0A000000 || # 10.0.0.0/8
|
||||
($haddr & 0xFF000000) == 0x7F000000 || # 127.0.0.0/8
|
||||
($haddr & 0xFFF00000) == 0xAC100000 || # 172.16.0.0/12
|
||||
($haddr & 0xFFFF0000) == 0xA9FE0000 || # 169.254.0.0/16
|
||||
($haddr & 0xFFFF0000) == 0xC0A80000 || # 192.168.0.0/16
|
||||
$haddr == 0xFFFFFFFF || # 255.255.255.255
|
||||
($haddr & 0xF0000000) == 0xE0000000; # multicast addresses
|
||||
|
||||
# as final IP address check, pass in the canonical a.b.c.d decimal form
|
||||
# to the blacklisted host check to see if matches as bad there.
|
||||
my $can_ip = join(".", map { ord } split //, $addr);
|
||||
return 1 if $self->_host_list_match("blocked_hosts", $can_ip);
|
||||
|
||||
# looks like an okay IP address
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub request {
|
||||
my ($self, $req, $arg, $size, $previous) = @_;
|
||||
|
||||
# walk back to the first request, and set our _time_begin to its _time_begin, or if
|
||||
# we're the first, then use current time. used by LWPx::Protocol::http_paranoid
|
||||
my $first_res = $previous; # previous is the previous response that invoked this request
|
||||
$first_res = $first_res->previous while $first_res && $first_res->previous;
|
||||
$req->{_time_begin} = $first_res ? $first_res->request->{_time_begin} : time();
|
||||
|
||||
my $host = $req->uri->host;
|
||||
if ($self->_bad_host($host)) {
|
||||
my $err_res = HTTP::Response->new(403, "Unauthorized access to blocked host");
|
||||
$err_res->request($req);
|
||||
$err_res->header("Client-Date" => HTTP::Date::time2str(time));
|
||||
$err_res->header("Client-Warning" => "Internal response");
|
||||
$err_res->header("Content-Type" => "text/plain");
|
||||
$err_res->content("403 Unauthorized access to blocked host\n");
|
||||
return $err_res;
|
||||
}
|
||||
|
||||
return $self->SUPER::request($req, $arg, $size, $previous);
|
||||
}
|
||||
|
||||
sub redirect_ok
|
||||
{
|
||||
# RFC 2616, section 10.3.2 and 10.3.3 say:
|
||||
# If the 30[12] status code is received in response to a request other
|
||||
# than GET or HEAD, the user agent MUST NOT automatically redirect the
|
||||
# request unless it can be confirmed by the user, since this might
|
||||
# change the conditions under which the request was issued.
|
||||
|
||||
# Note that this routine used to be just:
|
||||
# return 0 if $_[1]->method eq "POST"; return 1;
|
||||
|
||||
my($self, $new_request, $response) = @_;
|
||||
my $method = $response->request->method;
|
||||
return 0 unless grep $_ eq $method,
|
||||
@{ $self->requests_redirectable || [] };
|
||||
|
||||
if ($new_request->url->scheme eq 'file') {
|
||||
$response->header("Client-Warning" =>
|
||||
"Can't redirect to a file:// URL!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
$self->{'final_url'} = $new_request->uri;
|
||||
|
||||
# Otherwise it's apparently okay...
|
||||
return 1;
|
||||
}
|
||||
|
||||
# taken from LWP::UserAgent and modified slightly. (proxy support removed,
|
||||
# and map http and https schemes to separate protocol handlers)
|
||||
sub send_request
|
||||
{
|
||||
my ($self, $request, $arg, $size) = @_;
|
||||
$self->_request_sanity_check($request);
|
||||
|
||||
my ($method, $url) = ($request->method, $request->uri);
|
||||
|
||||
local($SIG{__DIE__}); # protect against user defined die handlers
|
||||
|
||||
# Check that we have a METHOD and a URL first
|
||||
return _new_response($request, &HTTP::Status::RC_BAD_REQUEST, "Method missing")
|
||||
unless $method;
|
||||
return _new_response($request, &HTTP::Status::RC_BAD_REQUEST, "URL missing")
|
||||
unless $url;
|
||||
return _new_response($request, &HTTP::Status::RC_BAD_REQUEST, "URL must be absolute")
|
||||
unless $url->scheme;
|
||||
return _new_response($request, &HTTP::Status::RC_BAD_REQUEST,
|
||||
"ParanoidAgent doesn't support going through proxies. ".
|
||||
"In that case, do your paranoia at your proxy instead.")
|
||||
if $self->_need_proxy($url);
|
||||
|
||||
my $scheme = $url->scheme;
|
||||
return _new_response($request, &HTTP::Status::RC_BAD_REQUEST, "Only http and https are supported by ParanoidAgent")
|
||||
unless $scheme eq "http" || $scheme eq "https";
|
||||
|
||||
LWP::Debug::trace("$method $url");
|
||||
|
||||
my $protocol;
|
||||
|
||||
{
|
||||
# Honor object-specific restrictions by forcing protocol objects
|
||||
# into class LWP::Protocol::nogo.
|
||||
my $x;
|
||||
if($x = $self->protocols_allowed) {
|
||||
if(grep lc($_) eq $scheme, @$x) {
|
||||
LWP::Debug::trace("$scheme URLs are among $self\'s allowed protocols (@$x)");
|
||||
}
|
||||
else {
|
||||
LWP::Debug::trace("$scheme URLs aren't among $self\'s allowed protocols (@$x)");
|
||||
require LWP::Protocol::nogo;
|
||||
$protocol = LWP::Protocol::nogo->new;
|
||||
}
|
||||
}
|
||||
elsif ($x = $self->protocols_forbidden) {
|
||||
if(grep lc($_) eq $scheme, @$x) {
|
||||
LWP::Debug::trace("$scheme URLs are among $self\'s forbidden protocols (@$x)");
|
||||
require LWP::Protocol::nogo;
|
||||
$protocol = LWP::Protocol::nogo->new;
|
||||
}
|
||||
else {
|
||||
LWP::Debug::trace("$scheme URLs aren't among $self\'s forbidden protocols (@$x)");
|
||||
}
|
||||
}
|
||||
# else fall thru and create the protocol object normally
|
||||
}
|
||||
|
||||
unless ($protocol) {
|
||||
LWP::Protocol::implementor("${scheme}_paranoid", "LWPx::Protocol::${scheme}_paranoid");
|
||||
eval "require LWPx::Protocol::${scheme}_paranoid;";
|
||||
if ($@) {
|
||||
$@ =~ s/ at .* line \d+.*//s; # remove file/line number
|
||||
my $response = _new_response($request, &HTTP::Status::RC_NOT_IMPLEMENTED, $@);
|
||||
return $response;
|
||||
}
|
||||
|
||||
$protocol = eval { LWP::Protocol::create($scheme eq "http" ? "http_paranoid" : "https_paranoid", $self) };
|
||||
if ($@) {
|
||||
$@ =~ s/ at .* line \d+.*//s; # remove file/line number
|
||||
my $response = _new_response($request, &HTTP::Status::RC_NOT_IMPLEMENTED, $@);
|
||||
if ($scheme eq "https") {
|
||||
$response->message($response->message . " (Crypt::SSLeay not installed)");
|
||||
$response->content_type("text/plain");
|
||||
$response->content(<<EOT);
|
||||
LWP will support https URLs if the Crypt::SSLeay module is installed.
|
||||
More information at <http://www.linpro.no/lwp/libwww-perl/README.SSL>.
|
||||
EOT
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
||||
# Extract fields that will be used below
|
||||
my ($timeout, $cookie_jar, $use_eval, $parse_head, $max_size) =
|
||||
@{$self}{qw(timeout cookie_jar use_eval parse_head max_size)};
|
||||
|
||||
my $response;
|
||||
my $proxy = undef;
|
||||
if ($use_eval) {
|
||||
# we eval, and turn dies into responses below
|
||||
eval {
|
||||
$response = $protocol->request($request, $proxy,
|
||||
$arg, $size, $timeout);
|
||||
};
|
||||
if ($@) {
|
||||
$@ =~ s/ at .* line \d+.*//s; # remove file/line number
|
||||
$response = _new_response($request,
|
||||
&HTTP::Status::RC_INTERNAL_SERVER_ERROR,
|
||||
$@);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$response = $protocol->request($request, $proxy,
|
||||
$arg, $size, $timeout);
|
||||
# XXX: Should we die unless $response->is_success ???
|
||||
}
|
||||
|
||||
$response->request($request); # record request for reference
|
||||
$cookie_jar->extract_cookies($response) if $cookie_jar;
|
||||
$response->header("Client-Date" => HTTP::Date::time2str(time));
|
||||
return $response;
|
||||
}
|
||||
|
||||
# blocked hostnames, compiled patterns, or subrefs
|
||||
sub blocked_hosts
|
||||
{
|
||||
my $self = shift;
|
||||
if (@_) {
|
||||
my @hosts = @_;
|
||||
$self->{'blocked_hosts'} = \@hosts;
|
||||
return;
|
||||
}
|
||||
return @{ $self->{'blocked_hosts'} };
|
||||
}
|
||||
|
||||
# whitelisted hostnames, compiled patterns, or subrefs
|
||||
sub whitelisted_hosts
|
||||
{
|
||||
my $self = shift;
|
||||
if (@_) {
|
||||
my @hosts = @_;
|
||||
$self->{'whitelisted_hosts'} = \@hosts;
|
||||
return;
|
||||
}
|
||||
return @{ $self->{'whitelisted_hosts'} };
|
||||
}
|
||||
|
||||
# get/set Net::DNS resolver object
|
||||
sub resolver
|
||||
{
|
||||
my $self = shift;
|
||||
if (@_) {
|
||||
$self->{'resolver'} = shift;
|
||||
require UNIVERSAL ;
|
||||
die "Not a Net::DNS::Resolver object" unless
|
||||
UNIVERSAL::isa($self->{'resolver'}, "Net::DNS::Resolver");
|
||||
}
|
||||
return $self->{'resolver'} ||= Net::DNS::Resolver->new;
|
||||
}
|
||||
|
||||
# Taken directly from LWP::UserAgent because it was private there, and we can't depend on it
|
||||
# staying there in future versions: needed by our modified version of send_request
|
||||
sub _need_proxy
|
||||
{
|
||||
my($self, $url) = @_;
|
||||
$url = $HTTP::URI_CLASS->new($url) unless ref $url;
|
||||
|
||||
my $scheme = $url->scheme || return;
|
||||
if (my $proxy = $self->{'proxy'}{$scheme}) {
|
||||
if (@{ $self->{'no_proxy'} }) {
|
||||
if (my $host = eval { $url->host }) {
|
||||
for my $domain (@{ $self->{'no_proxy'} }) {
|
||||
if ($host =~ /\Q$domain\E$/) {
|
||||
LWP::Debug::trace("no_proxy configured");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
LWP::Debug::debug("Proxied to $proxy");
|
||||
return $HTTP::URI_CLASS->new($proxy);
|
||||
}
|
||||
LWP::Debug::debug('Not proxied');
|
||||
undef;
|
||||
}
|
||||
|
||||
# Taken directly from LWP::UserAgent because it was private there, and we can't depend on it
|
||||
# staying there in future versions: needed by our modified version of send_request
|
||||
sub _request_sanity_check {
|
||||
my($self, $request) = @_;
|
||||
# some sanity checking
|
||||
if (defined $request) {
|
||||
if (ref $request) {
|
||||
Carp::croak("You need a request object, not a " . ref($request) . " object")
|
||||
if ref($request) eq 'ARRAY' or ref($request) eq 'HASH' or
|
||||
!$request->can('method') or !$request->can('uri');
|
||||
}
|
||||
else {
|
||||
Carp::croak("You need a request object, not '$request'");
|
||||
}
|
||||
}
|
||||
else {
|
||||
Carp::croak("No request object passed in");
|
||||
}
|
||||
}
|
||||
|
||||
# Taken directly from LWP::UserAgent because it was private there, and we can't depend on it
|
||||
# staying there in future versions: needed by our modified version of send_request
|
||||
sub _new_response {
|
||||
my($request, $code, $message) = @_;
|
||||
my $response = HTTP::Response->new($code, $message);
|
||||
$response->request($request);
|
||||
$response->header("Client-Date" => HTTP::Date::time2str(time));
|
||||
$response->header("Client-Warning" => "Internal response");
|
||||
$response->header("Content-Type" => "text/plain");
|
||||
$response->content("$code $message\n");
|
||||
return $response;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
LWPx::ParanoidAgent - subclass of LWP::UserAgent that protects you from harm
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
require LWPx::ParanoidAgent;
|
||||
|
||||
my $ua = LWPx::ParanoidAgent->new;
|
||||
|
||||
# this is 10 seconds overall, from start to finish. not just between
|
||||
# socket reads. and it includes all redirects. so attackers telling
|
||||
# you to download from a malicious tarpit webserver can only stall
|
||||
# you for $n seconds
|
||||
|
||||
$ua->timeout(10);
|
||||
|
||||
# setup extra block lists, in addition to the always-enforced blocking
|
||||
# of private IP addresses, loopbacks, and multicast addresses
|
||||
|
||||
$ua->blocked_hosts(
|
||||
"foo.com",
|
||||
qr/\.internal\.company\.com$/i,
|
||||
sub { my $host = shift; return 1 if is_bad($host); },
|
||||
);
|
||||
|
||||
$ua->whitelisted_hosts(
|
||||
"brad.lj",
|
||||
qr/^192\.168\.64\.3?/,
|
||||
sub { ... },
|
||||
);
|
||||
|
||||
# get/set the DNS resolver object that's used
|
||||
my $resolver = $ua->resolver;
|
||||
$ua->resolver(Net::DNS::Resolver->new(...));
|
||||
|
||||
# and then just like a normal LWP::UserAgent, because it is one.
|
||||
my $response = $ua->get('http://search.cpan.org/');
|
||||
...
|
||||
if ($response->is_success) {
|
||||
print $response->content; # or whatever
|
||||
}
|
||||
else {
|
||||
die $response->status_line;
|
||||
}
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
The C<LWPx::ParanoidAgent> is a class subclassing C<LWP::UserAgent>,
|
||||
but paranoid against attackers. It's to be used when you're fetching
|
||||
a remote resource on behalf of a possibly malicious user.
|
||||
|
||||
This class can do whatever C<LWP::UserAgent> can (callbacks, uploads from
|
||||
files, etc), except proxy support is explicitly removed, because in
|
||||
that case you should do your paranoia at your proxy.
|
||||
|
||||
Also, the schemes are limited to http and https, which are mapped to
|
||||
C<LWPx::Protocol::http_paranoid> and
|
||||
C<LWPx::Protocol::https_paranoid>, respectively, which are forked
|
||||
versions of the same ones without the "_paranoid". Subclassing them
|
||||
didn't look possible, as they were essentially just one huge function.
|
||||
|
||||
This class protects you from connecting to internal IP ranges (unless you
|
||||
whitelist them), hostnames/IPs that you blacklist, remote webserver
|
||||
tarpitting your process (the timeout parameter is changed to be a global
|
||||
timeout over the entire process), and all combinations of redirects and
|
||||
DNS tricks to otherwise tarpit and/or connect to internal resources.
|
||||
|
||||
=head1 CONSTRUCTOR
|
||||
|
||||
=over 4
|
||||
|
||||
=item C<new>
|
||||
|
||||
my $ua = LWPx::ParanoidAgent->new([ %opts ]);
|
||||
|
||||
In addition to any constructor options from L<LWP::UserAgent>, you may
|
||||
also set C<blocked_hosts> (to an arrayref), C<whitelisted_hosts> (also
|
||||
an arrayref), and C<resolver>, a Net::DNS::Resolver object.
|
||||
|
||||
=back
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
=over 4
|
||||
|
||||
=item $csr->B<resolver>($net_dns_resolver)
|
||||
|
||||
=item $csr->B<resolver>
|
||||
|
||||
Get/set the L<Net::DNS::Resolver> object used to lookup hostnames.
|
||||
|
||||
=item $csr->B<blocked_hosts>(@host_list)
|
||||
|
||||
=item $csr->B<blocked_hosts>
|
||||
|
||||
Get/set the the list of blocked hosts. The items in @host_list may be
|
||||
compiled regular expressions (with qr//), code blocks, or scalar
|
||||
literals. In any case, the thing that is match, passed in, or
|
||||
compared (respectively), is all of the given hostname, given IP
|
||||
address, and IP address in canonical a.b.c.d decimal notation. So if
|
||||
you want to block "1.2.3.4" and the user entered it in a mix of
|
||||
network/host form in a mix of decimal/octal/hex, you need only block
|
||||
"1.2.3.4" and not worry about the details.
|
||||
|
||||
=item $csr->B<whitelisted_hosts>(@host_list)
|
||||
|
||||
=item $csr->B<whitelisted_hosts>
|
||||
|
||||
Like blocked hosts, but matching the hosts/IPs that bypass blocking
|
||||
checks. The only difference is the IP address isn't canonicalized
|
||||
before being whitelisted-matched, mostly because it doesn't make sense
|
||||
for somebody to enter in a good address in a subversive way.
|
||||
|
||||
=back
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
See L<LWP::UserAgent> to see how to use this class.
|
||||
|
||||
=head1 WARRANTY
|
||||
|
||||
This module is supplied "as-is" and comes with no warranty, expressed
|
||||
or implied. It tries to protect you from harm, but maybe it will.
|
||||
Maybe it will destroy your data and your servers. You'd better audit
|
||||
it and send me bug reports.
|
||||
|
||||
=head1 BUGS
|
||||
|
||||
Maybe. See the warranty above.
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright 2005 Brad Fitzpatrick
|
||||
|
||||
Lot of code from the the base class, copyright 1995-2004 Gisle Aas.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the same terms as Perl itself.
|
||||
231
local/cgi-bin/Net/OpenID/Association.pm
Executable file
231
local/cgi-bin/Net/OpenID/Association.pm
Executable file
@@ -0,0 +1,231 @@
|
||||
use strict;
|
||||
use Carp ();
|
||||
|
||||
############################################################################
|
||||
package Net::OpenID::Association;
|
||||
use fields (
|
||||
'server', # author-identity identity server endpoint
|
||||
'secret', # the secret for this association
|
||||
'handle', # the 255-character-max ASCII printable handle (33-126)
|
||||
'expiry', # unixtime, adjusted, of when this association expires
|
||||
'type', # association type
|
||||
);
|
||||
|
||||
use Storable ();
|
||||
use Digest::SHA1 qw(sha1);
|
||||
|
||||
sub new {
|
||||
my Net::OpenID::Association $self = shift;
|
||||
$self = fields::new( $self ) unless ref $self;
|
||||
my %opts = @_;
|
||||
for my $f (qw( server secret handle expiry type )) {
|
||||
$self->{$f} = delete $opts{$f};
|
||||
}
|
||||
Carp::croak("unknown options: " . join(", ", keys %opts)) if %opts;
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub handle {
|
||||
my $self = shift;
|
||||
die if @_;
|
||||
$self->{'handle'};
|
||||
}
|
||||
|
||||
sub secret {
|
||||
my $self = shift;
|
||||
die if @_;
|
||||
$self->{'secret'};
|
||||
}
|
||||
|
||||
sub server {
|
||||
my Net::OpenID::Association $self = shift;
|
||||
Carp::croak("Too many parameters") if @_;
|
||||
return $self->{server};
|
||||
}
|
||||
|
||||
sub expired {
|
||||
my Net::OpenID::Association $self = shift;
|
||||
return time() > $self->{'expiry'};
|
||||
}
|
||||
|
||||
sub usable {
|
||||
my Net::OpenID::Association $self = shift;
|
||||
return 0 unless $self->{'handle'} =~ /^[\x21-\x7e]{1,255}$/;
|
||||
return 0 unless $self->{'expiry'} =~ /^\d+$/;
|
||||
return 0 unless $self->{'secret'};
|
||||
return 0 if $self->expired;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
# return a handle for an identity server, or undef if
|
||||
# no local storage/cache is available, in which case the caller
|
||||
# goes into dumb consumer mode. will do a POST and allocate
|
||||
# a new assoc_handle if none is found, or has expired
|
||||
sub server_assoc {
|
||||
my ($csr, $server) = @_;
|
||||
|
||||
# closure to return undef (dumb consumer mode) and log why
|
||||
my $dumb = sub {
|
||||
$csr->_debug("server_assoc: dumb mode: $_[0]");
|
||||
return undef;
|
||||
};
|
||||
|
||||
my $cache = $csr->cache;
|
||||
return $dumb->("no_cache") unless $cache;
|
||||
|
||||
# try first from cached association handle
|
||||
if (my $handle = $cache->get("shandle:$server")) {
|
||||
my $assoc = handle_assoc($csr, $server, $handle);
|
||||
|
||||
if ($assoc && $assoc->usable) {
|
||||
$csr->_debug("Found association from cache (handle=$handle)");
|
||||
return $assoc;
|
||||
}
|
||||
}
|
||||
|
||||
# make a new association
|
||||
my $dh = _default_dh();
|
||||
|
||||
my %post = (
|
||||
"openid.mode" => "associate",
|
||||
"openid.assoc_type" => "HMAC-SHA1",
|
||||
"openid.session_type" => "DH-SHA1",
|
||||
"openid.dh_consumer_public" => OpenID::util::bi2arg($dh->pub_key),
|
||||
);
|
||||
|
||||
my $req = HTTP::Request->new(POST => $server);
|
||||
$req->header("Content-Type" => "application/x-www-form-urlencoded");
|
||||
$req->content(join("&", map { "$_=" . OpenID::util::eurl($post{$_}) } keys %post));
|
||||
|
||||
$csr->_debug("Associate mode request: " . $req->content);
|
||||
|
||||
my $ua = $csr->ua;
|
||||
my $res = $ua->request($req);
|
||||
|
||||
# uh, some failure, let's go into dumb mode?
|
||||
return $dumb->("http_failure_no_associate") unless $res && $res->is_success;
|
||||
|
||||
my $recv_time = time();
|
||||
my $content = $res->content;
|
||||
my %args = OpenID::util::parse_keyvalue($content);
|
||||
$csr->_debug("Response to associate mode: [$content] parsed = " . join(",", %args));
|
||||
|
||||
return $dumb->("unknown_assoc_type") unless $args{'assoc_type'} eq "HMAC-SHA1";
|
||||
|
||||
my $stype = $args{'session_type'};
|
||||
return $dumb->("unknown_session_type") if $stype && $stype ne "DH-SHA1";
|
||||
|
||||
# protocol version 1.1
|
||||
my $expires_in = $args{'expires_in'};
|
||||
|
||||
# protocol version 1.0 (DEPRECATED)
|
||||
if (! $expires_in) {
|
||||
if (my $issued = OpenID::util::w3c_to_time($args{'issued'})) {
|
||||
my $expiry = OpenID::util::w3c_to_time($args{'expiry'});
|
||||
my $replace_after = OpenID::util::w3c_to_time($args{'replace_after'});
|
||||
|
||||
# seconds ahead (positive) or behind (negative) the server is
|
||||
$expires_in = ($replace_after || $expiry) - $issued;
|
||||
}
|
||||
}
|
||||
|
||||
# between 1 second and 2 years
|
||||
return $dumb->("bogus_expires_in") unless $expires_in > 0 && $expires_in < 63072000;
|
||||
|
||||
my $ahandle = $args{'assoc_handle'};
|
||||
|
||||
my $secret;
|
||||
if ($stype ne "DH-SHA1") {
|
||||
$secret = OpenID::util::d64($args{'mac_key'});
|
||||
} else {
|
||||
my $server_pub = OpenID::util::arg2bi($args{'dh_server_public'});
|
||||
my $dh_sec = $dh->compute_secret($server_pub);
|
||||
$secret = OpenID::util::d64($args{'enc_mac_key'}) ^ sha1(OpenID::util::bi2bytes($dh_sec));
|
||||
}
|
||||
return $dumb->("secret_not_20_bytes") unless length($secret) == 20;
|
||||
|
||||
my %assoc = (
|
||||
handle => $ahandle,
|
||||
server => $server,
|
||||
secret => $secret,
|
||||
type => $args{'assoc_type'},
|
||||
expiry => $recv_time + $expires_in,
|
||||
);
|
||||
|
||||
my $assoc = Net::OpenID::Association->new( %assoc );
|
||||
return $dumb->("assoc_undef") unless $assoc;
|
||||
|
||||
$cache->set("hassoc:$server:$ahandle", Storable::nfreeze(\%assoc));
|
||||
$cache->set("shandle:$server", $ahandle);
|
||||
|
||||
return $assoc;
|
||||
}
|
||||
|
||||
# returns association, or undef if it can't be found
|
||||
sub handle_assoc {
|
||||
my ($csr, $server, $handle) = @_;
|
||||
|
||||
# closure to return undef (dumb consumer mode) and log why
|
||||
my $dumb = sub {
|
||||
$csr->_debug("handle_assoc: dumb mode: $_[0]");
|
||||
return undef;
|
||||
};
|
||||
|
||||
return $dumb->("no_handle") unless $handle;
|
||||
|
||||
my $cache = $csr->cache;
|
||||
return $dumb->("no_cache") unless $cache;
|
||||
|
||||
my $frozen = $cache->get("hassoc:$server:$handle");
|
||||
return $dumb->("not_in_cache") unless $frozen;
|
||||
|
||||
my $param = eval { Storable::thaw($frozen) };
|
||||
return $dumb->("not_a_hashref") unless ref $param eq "HASH";
|
||||
|
||||
return Net::OpenID::Association->new( %$param );
|
||||
}
|
||||
|
||||
sub invalidate_handle {
|
||||
my ($csr, $server, $handle) = @_;
|
||||
my $cache = $csr->cache
|
||||
or return;
|
||||
$cache->set("hassoc:$server:$handle", "");
|
||||
}
|
||||
|
||||
sub _default_dh {
|
||||
my $dh = Crypt::DH->new;
|
||||
$dh->p("155172898181473697471232257763715539915724801966915404479707795314057629378541917580651227423698188993727816152646631438561595825688188889951272158842675419950341258706556549803580104870537681476726513255747040765857479291291572334510643245094715007229621094194349783925984760375594985848253359305585439638443");
|
||||
$dh->g("2");
|
||||
$dh->generate_keys;
|
||||
return $dh;
|
||||
}
|
||||
|
||||
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Net::OpenID::Association - a relationship with an identity server
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Internal class.
|
||||
|
||||
=head1 COPYRIGHT, WARRANTY, AUTHOR
|
||||
|
||||
See L<Net::OpenID::Consumer> for author, copyrignt and licensing information.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Net::OpenID::Consumer>
|
||||
|
||||
L<Net::OpenID::VerifiedIdentity>
|
||||
|
||||
L<Net::OpenID::Server>
|
||||
|
||||
Website: L<http://www.danga.com/openid/>
|
||||
|
||||
952
local/cgi-bin/Net/OpenID/Consumer.pm
Executable file
952
local/cgi-bin/Net/OpenID/Consumer.pm
Executable file
@@ -0,0 +1,952 @@
|
||||
# LICENSE: You're free to distribute this under the same terms as Perl itself.
|
||||
|
||||
use strict;
|
||||
use Carp ();
|
||||
use LWP::UserAgent;
|
||||
use URI::Fetch 0.02;
|
||||
|
||||
############################################################################
|
||||
package Net::OpenID::Consumer;
|
||||
|
||||
use vars qw($VERSION);
|
||||
$VERSION = "0.12";
|
||||
|
||||
use fields (
|
||||
'cache', # the Cache object sent to URI::Fetch
|
||||
'ua', # LWP::UserAgent instance to use
|
||||
'args', # how to get at your args
|
||||
'consumer_secret', # scalar/subref
|
||||
'required_root', # the default required_root value, or undef
|
||||
'last_errcode', # last error code we got
|
||||
'last_errtext', # last error code we got
|
||||
'debug', # debug flag or codeblock
|
||||
);
|
||||
|
||||
use Net::OpenID::ClaimedIdentity;
|
||||
use Net::OpenID::VerifiedIdentity;
|
||||
use Net::OpenID::Association;
|
||||
|
||||
use MIME::Base64 ();
|
||||
use Digest::SHA1 ();
|
||||
use Crypt::DH 0.05;
|
||||
use Time::Local;
|
||||
use HTTP::Request;
|
||||
|
||||
sub new {
|
||||
my Net::OpenID::Consumer $self = shift;
|
||||
$self = fields::new( $self ) unless ref $self;
|
||||
my %opts = @_;
|
||||
|
||||
$self->{ua} = delete $opts{ua};
|
||||
$self->args ( delete $opts{args} );
|
||||
$self->cache ( delete $opts{cache} );
|
||||
$self->consumer_secret ( delete $opts{consumer_secret} );
|
||||
$self->required_root ( delete $opts{required_root} );
|
||||
|
||||
$self->{debug} = delete $opts{debug};
|
||||
|
||||
Carp::croak("Unknown options: " . join(", ", keys %opts)) if %opts;
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub cache { &_getset; }
|
||||
sub consumer_secret { &_getset; }
|
||||
sub required_root { &_getset; }
|
||||
|
||||
sub _getset {
|
||||
my Net::OpenID::Consumer $self = shift;
|
||||
my $param = (caller(1))[3];
|
||||
$param =~ s/.+:://;
|
||||
|
||||
if (@_) {
|
||||
my $val = shift;
|
||||
Carp::croak("Too many parameters") if @_;
|
||||
$self->{$param} = $val;
|
||||
}
|
||||
return $self->{$param};
|
||||
}
|
||||
|
||||
sub _debug {
|
||||
my Net::OpenID::Consumer $self = shift;
|
||||
return unless $self->{debug};
|
||||
|
||||
if (ref $self->{debug} eq "CODE") {
|
||||
$self->{debug}->($_[0]);
|
||||
} else {
|
||||
print STDERR "[DEBUG Net::OpenID::Consumer] $_[0]\n";
|
||||
}
|
||||
}
|
||||
|
||||
# given something that can have GET arguments, returns a subref to get them:
|
||||
# Apache
|
||||
# Apache::Request
|
||||
# CGI
|
||||
# HASH of get args
|
||||
# CODE returning get arg, given key
|
||||
|
||||
# ...
|
||||
|
||||
sub args {
|
||||
my Net::OpenID::Consumer $self = shift;
|
||||
|
||||
if (my $what = shift) {
|
||||
Carp::croak("Too many parameters") if @_;
|
||||
my $getter;
|
||||
if (! ref $what){
|
||||
Carp::croak("No args defined") unless $self->{args};
|
||||
return $self->{args}->($what);
|
||||
} elsif (ref $what eq "HASH") {
|
||||
$getter = sub { $what->{$_[0]}; };
|
||||
} elsif (ref $what eq "CGI") {
|
||||
$getter = sub { scalar $what->param($_[0]); };
|
||||
} elsif (ref $what eq "Apache") {
|
||||
my %get = $what->args;
|
||||
$getter = sub { $get{$_[0]}; };
|
||||
} elsif (ref $what eq "Apache::Request") {
|
||||
$getter = sub { scalar $what->param($_[0]); };
|
||||
} elsif (ref $what eq "CODE") {
|
||||
$getter = $what;
|
||||
} else {
|
||||
Carp::croak("Unknown parameter type ($what)");
|
||||
}
|
||||
if ($getter) {
|
||||
$self->{args} = $getter;
|
||||
}
|
||||
}
|
||||
$self->{args};
|
||||
}
|
||||
|
||||
sub ua {
|
||||
my Net::OpenID::Consumer $self = shift;
|
||||
$self->{ua} = shift if @_;
|
||||
Carp::croak("Too many parameters") if @_;
|
||||
|
||||
# make default one on first access
|
||||
unless ($self->{ua}) {
|
||||
my $ua = $self->{ua} = LWP::UserAgent->new;
|
||||
$ua->timeout(10);
|
||||
}
|
||||
|
||||
$self->{ua};
|
||||
}
|
||||
|
||||
sub _fail {
|
||||
my Net::OpenID::Consumer $self = shift;
|
||||
my ($code, $text) = @_;
|
||||
|
||||
$text ||= {
|
||||
'no_identity_server' => "The provided URL doesn't declare its OpenID identity server.",
|
||||
'empty_url' => "No URL entered.",
|
||||
'bogus_url' => "Invalid URL.",
|
||||
'no_head_tag' => "URL provided doesn't seem to have a head tag.",
|
||||
'url_fetch_err' => "Error fetching the provided URL.",
|
||||
}->{$code};
|
||||
|
||||
$self->{last_errcode} = $code;
|
||||
$self->{last_errtext} = $text;
|
||||
|
||||
$self->_debug("fail($code) $text");
|
||||
wantarray ? () : undef;
|
||||
}
|
||||
|
||||
sub json_err {
|
||||
my Net::OpenID::Consumer $self = shift;
|
||||
return OpenID::util::js_dumper({
|
||||
err_code => $self->{last_errcode},
|
||||
err_text => $self->{last_errtext},
|
||||
});
|
||||
}
|
||||
|
||||
sub err {
|
||||
my Net::OpenID::Consumer $self = shift;
|
||||
$self->{last_errcode} . ": " . $self->{last_errtext};
|
||||
}
|
||||
|
||||
sub errcode {
|
||||
my Net::OpenID::Consumer $self = shift;
|
||||
$self->{last_errcode};
|
||||
}
|
||||
|
||||
sub errtext {
|
||||
my Net::OpenID::Consumer $self = shift;
|
||||
$self->{last_errtext};
|
||||
}
|
||||
|
||||
|
||||
sub _get_url_contents {
|
||||
my Net::OpenID::Consumer $self = shift;
|
||||
my ($url, $final_url_ref, $hook) = @_;
|
||||
$final_url_ref ||= do { my $dummy; \$dummy; };
|
||||
|
||||
my $ures = URI::Fetch->fetch($url,
|
||||
UserAgent => $self->ua,
|
||||
Cache => $self->cache,
|
||||
ContentAlterHook => $hook,
|
||||
)
|
||||
or return $self->_fail("url_fetch_error", "Error fetching URL: " . URI::Fetch->errstr);
|
||||
|
||||
# who actually uses HTTP gone response status? uh, nobody.
|
||||
if ($ures->status == URI::Fetch::URI_GONE()) {
|
||||
return $self->_fail("url_gone", "URL is no longer available");
|
||||
}
|
||||
|
||||
my $res = $ures->http_response;
|
||||
$$final_url_ref = $res->request->uri->as_string;
|
||||
|
||||
return $ures->content;
|
||||
}
|
||||
|
||||
sub _find_semantic_info {
|
||||
my Net::OpenID::Consumer $self = shift;
|
||||
my $url = shift;
|
||||
my $final_url_ref = shift;
|
||||
|
||||
my $trim_hook = sub {
|
||||
my $htmlref = shift;
|
||||
# trim everything past the body. this is in case the user doesn't
|
||||
# have a head document and somebody was able to inject their own
|
||||
# head. -- brad choate
|
||||
$$htmlref =~ s/<body\b.*//is;
|
||||
};
|
||||
|
||||
my $doc = $self->_get_url_contents($url, $final_url_ref, $trim_hook) or
|
||||
return;
|
||||
|
||||
# find <head> content of document (notably: the first head, if an attacker
|
||||
# has added others somehow)
|
||||
return $self->_fail("no_head_tag", "Couldn't find OpenID servers due to no head tag")
|
||||
unless $doc =~ m!<head[^>]*>(.*?)</head>!is;
|
||||
my $head = $1;
|
||||
|
||||
my $ret = {
|
||||
'openid.server' => undef,
|
||||
'openid.delegate' => undef,
|
||||
'foaf' => undef,
|
||||
'foaf.maker' => undef,
|
||||
'rss' => undef,
|
||||
'atom' => undef,
|
||||
};
|
||||
|
||||
# analyze link/meta tags
|
||||
while ($head =~ m!<(link|meta)\b([^>]+)>!g) {
|
||||
my ($type, $val) = ($1, $2);
|
||||
my $temp;
|
||||
|
||||
# OpenID servers / delegated identities
|
||||
# <link rel="openid.server" href="http://www.livejournal.com/misc/openid.bml" />
|
||||
if ($type eq "link" &&
|
||||
$val =~ /\brel=.openid\.(server|delegate)./i && ($temp = $1) &&
|
||||
$val =~ m!\bhref=[\"\']([^\"\']+)[\"\']!i) {
|
||||
$ret->{"openid.$temp"} = $1;
|
||||
next;
|
||||
}
|
||||
|
||||
# FOAF documents
|
||||
#<link rel="meta" type="application/rdf+xml" title="FOAF" href="http://brad.livejournal.com/data/foaf" />
|
||||
if ($type eq "link" &&
|
||||
$val =~ m!title=.foaf.!i &&
|
||||
$val =~ m!rel=.meta.!i &&
|
||||
$val =~ m!type=.application/rdf\+xml.!i &&
|
||||
$val =~ m!href=[\"\']([^\"\']+)[\"\']!i) {
|
||||
$ret->{"foaf"} = $1;
|
||||
next;
|
||||
}
|
||||
|
||||
# FOAF maker info
|
||||
# <meta name="foaf:maker" content="foaf:mbox_sha1sum '4caa1d6f6203d21705a00a7aca86203e82a9cf7a'" />
|
||||
if ($type eq "meta" &&
|
||||
$val =~ m!name=.foaf:maker.!i &&
|
||||
$val =~ m!content=([\'\"])(.*?)\1!i) {
|
||||
$ret->{"foaf.maker"} = $2;
|
||||
next;
|
||||
}
|
||||
|
||||
if ($type eq "meta" &&
|
||||
$val =~ m!name=.foaf:maker.!i &&
|
||||
$val =~ m!content=([\'\"])(.*?)\1!i) {
|
||||
$ret->{"foaf.maker"} = $2;
|
||||
next;
|
||||
}
|
||||
|
||||
# RSS
|
||||
# <link rel="alternate" type="application/rss+xml" title="RSS" href="http://www.livejournal.com/~brad/data/rss" />
|
||||
if ($type eq "link" &&
|
||||
$val =~ m!rel=.alternate.!i &&
|
||||
$val =~ m!type=.application/rss\+xml.!i &&
|
||||
$val =~ m!href=[\"\']([^\"\']+)[\"\']!i) {
|
||||
$ret->{"rss"} = $1;
|
||||
next;
|
||||
}
|
||||
|
||||
# Atom
|
||||
# <link rel="alternate" type="application/atom+xml" title="Atom" href="http://www.livejournal.com/~brad/data/rss" />
|
||||
if ($type eq "link" &&
|
||||
$val =~ m!rel=.alternate.!i &&
|
||||
$val =~ m!type=.application/atom\+xml.!i &&
|
||||
$val =~ m!href=[\"\']([^\"\']+)[\"\']!i) {
|
||||
$ret->{"atom"} = $1;
|
||||
next;
|
||||
}
|
||||
}
|
||||
|
||||
# map the 4 entities that the spec asks for
|
||||
my $emap = {
|
||||
'lt' => '<',
|
||||
'gt' => '>',
|
||||
'quot' => '"',
|
||||
'amp' => '&',
|
||||
};
|
||||
foreach my $k (keys %$ret) {
|
||||
next unless $ret->{$k};
|
||||
$ret->{$k} =~ s/&(\w+);/$emap->{$1} || ""/eg;
|
||||
}
|
||||
|
||||
$self->_debug("semantic info ($url) = " . join(", ", %$ret));
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
sub _find_openid_server {
|
||||
my Net::OpenID::Consumer $self = shift;
|
||||
my $url = shift;
|
||||
my $final_url_ref = shift;
|
||||
|
||||
my $sem_info = $self->_find_semantic_info($url, $final_url_ref) or
|
||||
return;
|
||||
|
||||
return $self->_fail("no_identity_server") unless $sem_info->{"openid.server"};
|
||||
$sem_info->{"openid.server"};
|
||||
}
|
||||
|
||||
# returns Net::OpenID::ClaimedIdentity
|
||||
sub claimed_identity {
|
||||
my Net::OpenID::Consumer $self = shift;
|
||||
my $url = shift;
|
||||
Carp::croak("Too many parameters") if @_;
|
||||
|
||||
# trim whitespace
|
||||
$url =~ s/^\s+//;
|
||||
$url =~ s/\s+$//;
|
||||
return $self->_fail("empty_url", "Empty URL") unless $url;
|
||||
|
||||
# do basic canonicalization
|
||||
$url = "http://$url" if $url && $url !~ m!^\w+://!;
|
||||
return $self->_fail("bogus_url", "Invalid URL") unless $url =~ m!^https?://!i;
|
||||
# add a slash, if none exists
|
||||
$url .= "/" unless $url =~ m!^http://.+/!i;
|
||||
|
||||
my $final_url;
|
||||
|
||||
my $sem_info = $self->_find_semantic_info($url, \$final_url) or
|
||||
return;
|
||||
|
||||
my $id_server = $sem_info->{"openid.server"} or
|
||||
return $self->_fail("no_identity_server");
|
||||
|
||||
return Net::OpenID::ClaimedIdentity->new(
|
||||
identity => $final_url,
|
||||
server => $id_server,
|
||||
consumer => $self,
|
||||
delegate => $sem_info->{'openid.delegate'},
|
||||
);
|
||||
}
|
||||
|
||||
sub user_cancel {
|
||||
my Net::OpenID::Consumer $self = shift;
|
||||
return $self->args("openid.mode") eq "cancel";
|
||||
}
|
||||
|
||||
sub user_setup_url {
|
||||
my Net::OpenID::Consumer $self = shift;
|
||||
my %opts = @_;
|
||||
my $post_grant = delete $opts{'post_grant'};
|
||||
Carp::croak("Unknown options: " . join(", ", keys %opts)) if %opts;
|
||||
return $self->_fail("bad_mode") unless $self->args("openid.mode") eq "id_res";
|
||||
|
||||
my $setup_url = $self->args("openid.user_setup_url");
|
||||
|
||||
OpenID::util::push_url_arg(\$setup_url, "openid.post_grant", $post_grant)
|
||||
if $setup_url && $post_grant;
|
||||
|
||||
return $setup_url;
|
||||
}
|
||||
|
||||
sub verified_identity {
|
||||
my Net::OpenID::Consumer $self = shift;
|
||||
my %opts = @_;
|
||||
|
||||
my $rr = delete $opts{'required_root'} || $self->{required_root};
|
||||
Carp::croak("Unknown options: " . join(", ", keys %opts)) if %opts;
|
||||
|
||||
return $self->_fail("bad_mode") unless $self->args("openid.mode") eq "id_res";
|
||||
|
||||
# the asserted identity (the delegated one, if there is one, since the protocol
|
||||
# knows nothing of the original URL)
|
||||
my $a_ident = $self->args("openid.identity") or return $self->_fail("no_identity");
|
||||
|
||||
my $sig64 = $self->args("openid.sig") or return $self->_fail("no_sig");
|
||||
my $returnto = $self->args("openid.return_to") or return $self->_fail("no_return_to");
|
||||
my $signed = $self->args("openid.signed");
|
||||
|
||||
my $real_ident = $self->args("oic.identity") || $a_ident;
|
||||
|
||||
# check that returnto is for the right host
|
||||
return $self->_fail("bogus_return_to") if $rr && $returnto !~ /^\Q$rr\E/;
|
||||
|
||||
# check age/signature of return_to
|
||||
my $now = time();
|
||||
{
|
||||
my ($sig_time, $sig) = split(/\-/, $self->args("oic.time") || "");
|
||||
# complain if more than an hour since we sent them off
|
||||
return $self->_fail("time_expired") if $sig_time < $now - 3600;
|
||||
# also complain if the signature is from the future by more than 30 seconds,
|
||||
# which compensates for potential clock drift between nodes in a web farm.
|
||||
return $self->_fail("time_in_future") if $sig_time - 30 > $now;
|
||||
# and check that the time isn't faked
|
||||
my $c_secret = $self->_get_consumer_secret($sig_time);
|
||||
my $good_sig = substr(OpenID::util::hmac_sha1_hex($sig_time, $c_secret), 0, 20);
|
||||
return $self->_fail("time_bad_sig") unless $sig eq $good_sig;
|
||||
}
|
||||
|
||||
my $final_url;
|
||||
my $sem_info = $self->_find_semantic_info($real_ident, \$final_url);
|
||||
return $self->_fail("unexpected_url_redirect") unless $final_url eq $real_ident;
|
||||
|
||||
my $server = $sem_info->{"openid.server"} or
|
||||
return $self->_fail("no_identity_server");
|
||||
|
||||
# if openid.delegate was used, check that it was done correctly
|
||||
if ($a_ident ne $real_ident) {
|
||||
return $self->_fail("bogus_delegation") unless $sem_info->{"openid.delegate"} eq $a_ident;
|
||||
}
|
||||
|
||||
my $assoc_handle = $self->args("openid.assoc_handle");
|
||||
|
||||
$self->_debug("verified_identity: assoc_handle: $assoc_handle");
|
||||
my $assoc = Net::OpenID::Association::handle_assoc($self, $server, $assoc_handle);
|
||||
|
||||
if ($assoc) {
|
||||
$self->_debug("verified_identity: verifying with found association");
|
||||
|
||||
return $self->_fail("expired_association")
|
||||
if $assoc->expired;
|
||||
|
||||
# verify the token
|
||||
my $token = "";
|
||||
foreach my $p (split(/,/, $signed)) {
|
||||
$token .= "$p:" . $self->args("openid.$p") . "\n";
|
||||
}
|
||||
|
||||
my $good_sig = OpenID::util::b64(OpenID::util::hmac_sha1($token, $assoc->secret));
|
||||
return $self->_fail("signature_mismatch") unless $sig64 eq $good_sig;
|
||||
|
||||
} else {
|
||||
$self->_debug("verified_identity: verifying using HTTP (dumb mode)");
|
||||
# didn't find an association. have to do dumb consumer mode
|
||||
# and check it with a POST
|
||||
my %post = (
|
||||
"openid.mode" => "check_authentication",
|
||||
"openid.assoc_handle" => $assoc_handle,
|
||||
"openid.signed" => $signed,
|
||||
"openid.sig" => $sig64,
|
||||
);
|
||||
|
||||
# and copy in all signed parameters that we don't already have into %post
|
||||
foreach my $param (split(/,/, $signed)) {
|
||||
next unless $param =~ /^\w+$/;
|
||||
next if $post{"openid.$param"};
|
||||
$post{"openid.$param"} = $self->args("openid.$param");
|
||||
}
|
||||
|
||||
# if the server told us our handle as bogus, let's ask in our
|
||||
# check_authentication mode whether that's true
|
||||
if (my $ih = $self->args("openid.invalidate_handle")) {
|
||||
$post{"openid.invalidate_handle"} = $ih;
|
||||
}
|
||||
|
||||
my $req = HTTP::Request->new(POST => $server);
|
||||
$req->header("Content-Type" => "application/x-www-form-urlencoded");
|
||||
$req->content(join("&", map { "$_=" . OpenID::util::eurl($post{$_}) } keys %post));
|
||||
|
||||
my $ua = $self->ua;
|
||||
my $res = $ua->request($req);
|
||||
|
||||
# uh, some failure, let's go into dumb mode?
|
||||
return $self->_fail("naive_verify_failed_network") unless $res && $res->is_success;
|
||||
|
||||
my $content = $res->content;
|
||||
my %args = OpenID::util::parse_keyvalue($content);
|
||||
|
||||
# delete the handle from our cache
|
||||
if (my $ih = $args{'invalidate_handle'}) {
|
||||
Net::OpenID::Association::invalidate_handle($self, $server, $ih);
|
||||
}
|
||||
|
||||
# bad but works. check out
|
||||
# http://www.livejournal.com/community/lj_everywhere/194480.html?thread=724400#t724400
|
||||
#
|
||||
if ($content !~ /error:bad_handle/) {
|
||||
return $self->_fail("naive_verify_failed_return: $content") unless
|
||||
$args{'is_valid'} eq "true" || # protocol 1.1
|
||||
$args{'lifetime'} > 0; # DEPRECATED protocol 1.0
|
||||
}
|
||||
}
|
||||
|
||||
$self->_debug("verified identity! = $real_ident");
|
||||
|
||||
# verified!
|
||||
return Net::OpenID::VerifiedIdentity->new(
|
||||
identity => $real_ident,
|
||||
foaf => $sem_info->{"foaf"},
|
||||
foafmaker => $sem_info->{"foaf.maker"},
|
||||
rss => $sem_info->{"rss"},
|
||||
atom => $sem_info->{"atom"},
|
||||
consumer => $self,
|
||||
);
|
||||
}
|
||||
|
||||
sub supports_consumer_secret { 1; }
|
||||
|
||||
sub _get_consumer_secret {
|
||||
my Net::OpenID::Consumer $self = shift;
|
||||
my $time = shift;
|
||||
|
||||
my $ss;
|
||||
if (ref $self->{consumer_secret} eq "CODE") {
|
||||
$ss = $self->{consumer_secret};
|
||||
} elsif ($self->{consumer_secret}) {
|
||||
$ss = sub { return $self->{consumer_secret}; };
|
||||
} else {
|
||||
Carp::croak("You haven't defined a consumer_secret value or subref.\n");
|
||||
}
|
||||
|
||||
my $sec = $ss->($time);
|
||||
Carp::croak("Consumer secret too long") if length($sec) > 255;
|
||||
return $sec;
|
||||
}
|
||||
|
||||
package OpenID::util;
|
||||
|
||||
# From Digest::HMAC
|
||||
sub hmac_sha1_hex {
|
||||
unpack("H*", &hmac_sha1);
|
||||
}
|
||||
sub hmac_sha1 {
|
||||
hmac($_[0], $_[1], \&Digest::SHA1::sha1, 64);
|
||||
}
|
||||
sub hmac {
|
||||
my($data, $key, $hash_func, $block_size) = @_;
|
||||
$block_size ||= 64;
|
||||
$key = &$hash_func($key) if length($key) > $block_size;
|
||||
|
||||
my $k_ipad = $key ^ (chr(0x36) x $block_size);
|
||||
my $k_opad = $key ^ (chr(0x5c) x $block_size);
|
||||
|
||||
&$hash_func($k_opad, &$hash_func($k_ipad, $data));
|
||||
}
|
||||
|
||||
sub parse_keyvalue {
|
||||
my $reply = shift;
|
||||
my %ret;
|
||||
$reply =~ s/\r//g;
|
||||
foreach (split /\n/, $reply) {
|
||||
next unless /^(\S+?):(.*)/;
|
||||
$ret{$1} = $2;
|
||||
}
|
||||
return %ret;
|
||||
}
|
||||
|
||||
sub ejs
|
||||
{
|
||||
my $a = $_[0];
|
||||
$a =~ s/[\"\'\\]/\\$&/g;
|
||||
$a =~ s/\r?\n/\\n/gs;
|
||||
$a =~ s/\r//;
|
||||
return $a;
|
||||
}
|
||||
|
||||
# Data::Dumper for JavaScript
|
||||
sub js_dumper {
|
||||
my $obj = shift;
|
||||
if (ref $obj eq "HASH") {
|
||||
my $ret = "{";
|
||||
foreach my $k (keys %$obj) {
|
||||
$ret .= "$k: " . js_dumper($obj->{$k}) . ",";
|
||||
}
|
||||
chop $ret;
|
||||
$ret .= "}";
|
||||
return $ret;
|
||||
} elsif (ref $obj eq "ARRAY") {
|
||||
my $ret = "[" . join(", ", map { js_dumper($_) } @$obj) . "]";
|
||||
return $ret;
|
||||
} else {
|
||||
return $obj if $obj =~ /^\d+$/;
|
||||
return "\"" . ejs($obj) . "\"";
|
||||
}
|
||||
}
|
||||
|
||||
sub eurl
|
||||
{
|
||||
my $a = $_[0];
|
||||
$a =~ s/([^a-zA-Z0-9_\,\-.\/\\\: ])/uc sprintf("%%%02x",ord($1))/eg;
|
||||
$a =~ tr/ /+/;
|
||||
return $a;
|
||||
}
|
||||
|
||||
sub push_url_arg {
|
||||
my $uref = shift;
|
||||
$$uref =~ s/[&?]$//;
|
||||
my $got_qmark = ($$uref =~ /\?/);
|
||||
|
||||
while (@_) {
|
||||
my $key = shift;
|
||||
my $value = shift;
|
||||
$$uref .= $got_qmark ? "&" : ($got_qmark = 1, "?");
|
||||
$$uref .= eurl($key) . "=" . eurl($value);
|
||||
}
|
||||
}
|
||||
|
||||
sub time_to_w3c {
|
||||
my $time = shift || time();
|
||||
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime($time);
|
||||
$mon++;
|
||||
$year += 1900;
|
||||
|
||||
return sprintf("%04d-%02d-%02dT%02d:%02d:%02dZ",
|
||||
$year, $mon, $mday,
|
||||
$hour, $min, $sec);
|
||||
}
|
||||
|
||||
sub w3c_to_time {
|
||||
my $hms = shift;
|
||||
return 0 unless
|
||||
$hms =~ /^(\d{4,4})-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)Z$/;
|
||||
|
||||
my $time;
|
||||
eval {
|
||||
$time = Time::Local::timegm($6, $5, $4, $3, $2 - 1, $1);
|
||||
};
|
||||
return 0 if $@;
|
||||
return $time;
|
||||
}
|
||||
|
||||
sub bi2bytes {
|
||||
my $bigint = shift;
|
||||
die "Can't deal with negative numbers" if $bigint->is_negative;
|
||||
|
||||
my $bits = $bigint->as_bin;
|
||||
die unless $bits =~ s/^0b//;
|
||||
|
||||
# prepend zeros to round to byte boundary, or to unset high bit
|
||||
my $prepend = (8 - length($bits) % 8) || ($bits =~ /^1/ ? 8 : 0);
|
||||
$bits = ("0" x $prepend) . $bits if $prepend;
|
||||
|
||||
return pack("B*", $bits);
|
||||
}
|
||||
|
||||
sub bi2arg {
|
||||
return b64(bi2bytes($_[0]));
|
||||
}
|
||||
|
||||
sub b64 {
|
||||
my $val = MIME::Base64::encode_base64($_[0]);
|
||||
$val =~ s/\s+//g;
|
||||
return $val;
|
||||
}
|
||||
|
||||
sub d64 {
|
||||
return MIME::Base64::decode_base64($_[0]);
|
||||
}
|
||||
|
||||
sub bytes2bi {
|
||||
return Math::BigInt->new("0b" . unpack("B*", $_[0]));
|
||||
}
|
||||
|
||||
sub arg2bi {
|
||||
return undef unless defined $_[0] and $_[0] ne "";
|
||||
# don't acccept base-64 encoded numbers over 700 bytes. which means
|
||||
# those over 4200 bits.
|
||||
return Math::BigInt->new("0") if length($_[0]) > 700;
|
||||
return bytes2bi(MIME::Base64::decode_base64($_[0]));
|
||||
}
|
||||
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Net::OpenID::Consumer - library for consumers of OpenID identities
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use Net::OpenID::Consumer;
|
||||
|
||||
my $csr = Net::OpenID::Consumer->new(
|
||||
ua => LWPx::ParanoidAgent->new,
|
||||
cache => Some::Cache->new,
|
||||
args => $cgi,
|
||||
consumer_secret => ...,
|
||||
required_root => "http://site.example.com/",
|
||||
);
|
||||
|
||||
# a user entered, say, "bradfitz.com" as their identity. The first
|
||||
# step is to fetch that page, parse it, and get a
|
||||
# Net::OpenID::ClaimedIdentity object:
|
||||
|
||||
my $claimed_identity = $csr->claimed_identity("bradfitz.com");
|
||||
|
||||
# now your app has to send them at their identity server's endpoint
|
||||
# to get redirected to either a positive assertion that they own
|
||||
# that identity, or where they need to go to login/setup trust/etc.
|
||||
|
||||
my $check_url = $claimed_identity->check_url(
|
||||
return_to => "http://example.com/openid-check.app?yourarg=val",
|
||||
trust_root => "http://example.com/",
|
||||
);
|
||||
|
||||
# so you send the user off there, and then they come back to
|
||||
# openid-check.app, then you see what the identity server said;
|
||||
|
||||
if (my $setup_url = $csr->user_setup_url) {
|
||||
# redirect/link/popup user to $setup_url
|
||||
} elsif ($csr->user_cancel) {
|
||||
# restore web app state to prior to check_url
|
||||
} elsif (my $vident = $csr->verified_identity) {
|
||||
my $verified_url = $vident->url;
|
||||
print "You are $verified_url !";
|
||||
} else {
|
||||
die "Error validating identity: " . $csr->err;
|
||||
}
|
||||
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This is the Perl API for (the consumer half of) OpenID, a distributed
|
||||
identity system based on proving you own a URL, which is then your
|
||||
identity. More information is available at:
|
||||
|
||||
http://www.danga.com/openid/
|
||||
|
||||
=head1 CONSTRUCTOR
|
||||
|
||||
=over 4
|
||||
|
||||
=item C<new>
|
||||
|
||||
my $csr = Net::OpenID::Consumer->new([ %opts ]);
|
||||
|
||||
You can set the C<ua>, C<cache>, C<consumer_secret>, C<required_root>,
|
||||
and C<args> in the constructor. See the corresponding method
|
||||
descriptions below.
|
||||
|
||||
=back
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
=over 4
|
||||
|
||||
=item $csr->B<ua>($user_agent)
|
||||
|
||||
=item $csr->B<ua>
|
||||
|
||||
Getter/setter for the LWP::UserAgent (or subclass) instance which will
|
||||
be used when web donwloads are needed. It's highly recommended that
|
||||
you use LWPx::ParanoidAgent, or at least read its documentation so
|
||||
you're aware of why you should care.
|
||||
|
||||
=item $csr->B<cache>($cache)
|
||||
|
||||
=item $csr->B<cache>
|
||||
|
||||
Getter/setter for the optional (but recommended!) cache instance you
|
||||
want to use for storing fetched parts of pages. (identity server
|
||||
public keys, and the E<lt>headE<gt> section of user's HTML pages)
|
||||
|
||||
The $cache object can be anything that has a -E<gt>get($key) and
|
||||
-E<gt>set($key,$value) methods. See L<URI::Fetch> for more
|
||||
information. This cache object is just passed to L<URI::Fetch>
|
||||
directly.
|
||||
|
||||
=item $nos->B<consumer_secret>($scalar)
|
||||
|
||||
=item $nos->B<consumer_secret>($code)
|
||||
|
||||
=item $code = $nos->B<consumer_secret>; ($secret) = $code->($time);
|
||||
|
||||
The consumer secret is used to generate self-signed nonces for the
|
||||
return_to URL, to prevent spoofing.
|
||||
|
||||
In the simplest (and least secure) form, you configure a static secret
|
||||
value with a scalar. If you use this method and change the scalar
|
||||
value, any outstanding requests from the last 30 seconds or so will fail.
|
||||
|
||||
The more robust (but more complicated) form is to supply a subref that
|
||||
returns a secret based on the provided I<$time>, a unix timestamp.
|
||||
And if one doesn't exist for that time, create, store and return it
|
||||
(with appropriate locking so you never return different secrets for
|
||||
the same time.)
|
||||
|
||||
Your secret may not exceed 255 characters.
|
||||
|
||||
=item $csr->B<args>($ref)
|
||||
|
||||
=item $csr->B<args>($param)
|
||||
|
||||
=item $csr->B<args>
|
||||
|
||||
Can be used in 1 of 3 ways:
|
||||
|
||||
1. Setting the way which the Consumer instances obtains GET parameters:
|
||||
|
||||
$csr->args( $reference )
|
||||
|
||||
Where $reference is either a HASH ref, CODE ref, Apache $r,
|
||||
Apache::Request $apreq, or CGI.pm $cgi. If a CODE ref, the subref
|
||||
must return the value given one argument (the parameter to retrieve)
|
||||
|
||||
2. Get a paramater:
|
||||
|
||||
my $foo = $csr->args("foo");
|
||||
|
||||
When given an unblessed scalar, it retrieves the value. It croaks if
|
||||
you haven't defined a way to get at the parameters.
|
||||
|
||||
3. Get the getter:
|
||||
|
||||
my $code = $csr->args;
|
||||
|
||||
Without arguments, returns a subref that returns the value given a
|
||||
parameter name.
|
||||
|
||||
=item $nos->B<required_root>($url_prefix)
|
||||
|
||||
=item $url_prefix = $nos->B<required_root>
|
||||
|
||||
If provided, this is the required string that all return_to URLs must
|
||||
start with. If it doesn't match, it'll be considered invalid (spoofed
|
||||
from another site)
|
||||
|
||||
=item $csr->B<claimed_identity>($url)
|
||||
|
||||
Given a user-entered $url (which could be missing http://, or have
|
||||
extra whitespace, etc), returns either a Net::OpenID::ClaimedIdentity
|
||||
object, or undef on failure.
|
||||
|
||||
Note that this identity is NOT verified yet. It's only who the user
|
||||
claims they are, but they could be lying.
|
||||
|
||||
If this method returns undef, you can rely on the following errors
|
||||
codes (from $csr->B<errcode>) to decide what to present to the user:
|
||||
|
||||
=over 8
|
||||
|
||||
=item no_identity_server
|
||||
|
||||
=item empty_url
|
||||
|
||||
=item bogus_url
|
||||
|
||||
=item no_head_tag
|
||||
|
||||
=item url_fetch_err
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=item $csr->B<user_setup_url>( [ %opts ] )
|
||||
|
||||
Returns the URL the user must return to in order to login, setup trust,
|
||||
or do whatever the identity server needs them to do in order to make
|
||||
the identity assertion which they previously initiated by entering
|
||||
their claimed identity URL. Returns undef if this setup URL isn't
|
||||
required, in which case you should ask for the verified_identity.
|
||||
|
||||
The base URL this this function returns can be modified by using the
|
||||
following options in %opts:
|
||||
|
||||
=over
|
||||
|
||||
=item C<post_grant>
|
||||
|
||||
What you're asking the identity server to do with the user after they
|
||||
setup trust. Can be either C<return> or C<close> to return the user
|
||||
back to the return_to URL, or close the browser window with
|
||||
JavaScript. If you don't specify, the behavior is undefined (probably
|
||||
the user gets a dead-end page with a link back to the return_to URL).
|
||||
In any case, the identity server can do whatever it wants, so don't
|
||||
depend on this.
|
||||
|
||||
=back
|
||||
|
||||
=item $csr->B<user_cancel>
|
||||
|
||||
Returns true if the user declined to share their identity, false
|
||||
otherwise. (This function is literally one line: returns true if
|
||||
"openid.mode" eq "cancel")
|
||||
|
||||
It's then your job to restore your app to where it was prior to
|
||||
redirecting them off to the user_setup_url, using the other query
|
||||
parameters that you'd sent along in your return_to URL.
|
||||
|
||||
=item $csr->B<verified_identity>( [ %opts ] )
|
||||
|
||||
Returns a Net::OpenID::VerifiedIdentity object, or undef.
|
||||
Verification includes double-checking the reported identity URL
|
||||
declares the identity server, verifying the signature, etc.
|
||||
|
||||
The options in %opts may contain:
|
||||
|
||||
=over
|
||||
|
||||
=item C<required_root>
|
||||
|
||||
Sets the required_root just for this request. Values returns to its
|
||||
previous value afterwards.
|
||||
|
||||
=back
|
||||
|
||||
=item $csr->B<err>
|
||||
|
||||
Returns the last error, in form "errcode: errtext"
|
||||
|
||||
=item $csr->B<errcode>
|
||||
|
||||
Returns the last error code.
|
||||
|
||||
=item $csr->B<errtext>
|
||||
|
||||
Returns the last error text.
|
||||
|
||||
=item $csr->B<json_err>
|
||||
|
||||
Returns the last error code/text in JSON format.
|
||||
|
||||
=back
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
This module is Copyright (c) 2005 Brad Fitzpatrick.
|
||||
All rights reserved.
|
||||
|
||||
You may distribute under the terms of either the GNU General Public
|
||||
License or the Artistic License, as specified in the Perl README file.
|
||||
If you need more liberal licensing terms, please contact the
|
||||
maintainer.
|
||||
|
||||
=head1 WARRANTY
|
||||
|
||||
This is free software. IT COMES WITHOUT WARRANTY OF ANY KIND.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
OpenID website: http://www.danga.com/openid/
|
||||
|
||||
L<Net::OpenID::ClaimedIdentity> -- part of this module
|
||||
|
||||
L<Net::OpenID::VerifiedIdentity> -- part of this module
|
||||
|
||||
L<Net::OpenID::Server> -- another module, for acting like an OpenID server
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
Brad Fitzpatrick <brad@danga.com>
|
||||
32
local/cgi-bin/bml/scheme/added.variables
Executable file
32
local/cgi-bin/bml/scheme/added.variables
Executable file
@@ -0,0 +1,32 @@
|
||||
ljrlook.nav.create
|
||||
ljrlook.nav.update
|
||||
ljrlook.nav.fullupdate
|
||||
ljrlook.nav.site
|
||||
ljrlook.nav.news
|
||||
ljrlook.nav.paidaccounts
|
||||
ljrlook.nav.edit
|
||||
ljrlook.nav.modify
|
||||
ljrlook.nav.editinfo
|
||||
ljrlook.nav.editfriends
|
||||
ljrlook.nav.editjournal
|
||||
ljrlook.nav.editpics
|
||||
ljrlook.nav.changepassword
|
||||
ljrlook.nav.communities.manage
|
||||
ljrlook.nav.frills
|
||||
ljrlook.nav.customize
|
||||
ljrlook.nav.createstyle
|
||||
ljrlook.nav.editstyle
|
||||
ljrlook.nav.needhelp
|
||||
ljrlook.nav.lostinfo
|
||||
ljrlook.nav.support.faq
|
||||
ljrlook.nav.support
|
||||
|
||||
ljrlook.nav.hello
|
||||
ljrlook.nav.yourjournal
|
||||
ljrlook.nav.recent
|
||||
ljrlook.nav.calendar
|
||||
ljrlook.nav.friends
|
||||
ljrlook.nav.userinfo
|
||||
ljrlook.nav.memories
|
||||
ljrlook.nav.logout
|
||||
ljrlook.nav.login
|
||||
267
local/cgi-bin/bml/scheme/bluewhite.look
Executable file
267
local/cgi-bin/bml/scheme/bluewhite.look
Executable file
@@ -0,0 +1,267 @@
|
||||
#
|
||||
# Welcome to GENERIC.LOOK for the WhiteBlue scheme
|
||||
#
|
||||
# by....
|
||||
# Brad Fitzpatrick
|
||||
# brad@danga.com
|
||||
#
|
||||
|
||||
######################### little stuff
|
||||
|
||||
_parent=>global.look
|
||||
|
||||
AL=>{P}<I><A HREF="%%DATA1%%">%%DATA2%%</A></I> <IMG SRC="/img/external_link.gif" WIDTH=16 HEIGHT=11 ALIGN=ABSMIDDLE>
|
||||
AWAYLINK=>{P}<I><A HREF="%%DATA1%%">%%DATA2%%</A></I> <IMG SRC="/img/external_link.gif" WIDTH=16 HEIGHT=11 ALIGN=ABSMIDDLE>
|
||||
|
||||
H1=>{D}<P><FONT FACE="Arial,Helvetica" COLOR="#CC0000"><B>%%DATA%%</B></FONT>
|
||||
H1/FOLLOW_CHOICES=>{D}<FONT FACE="Arial,Helvetica" COLOR="#CC0000"><B>%%DATA%%</B></FONT>
|
||||
HEAD1=>{D}<P><FONT FACE="Arial,Helvetica" COLOR="#CC0000"><B>%%DATA%%</B></FONT>
|
||||
|
||||
H2=>{D}<P><FONT FACE="Arial,Helvetica" COLOR="#CC0000" SIZE=-1><B>%%DATA%%</B></FONT>
|
||||
HEAD2=>{D}<P><FONT FACE="Arial,Helvetica" COLOR="#CC0000" SIZE=-1><B>%%DATA%%</B></FONT>
|
||||
|
||||
# Banner Header: search results banner, content desriptor, etc...
|
||||
BH=>{D}<P ALIGN=CENTER><FONT FACE="Arial,Helvetica" COLOR="#CC0000" SIZE=-1><B>%%DATA%%</B></FONT>
|
||||
|
||||
GRIN=><grin>
|
||||
HR=><P ALIGN="CENTER"><FONT COLOR=BLUE>*</FONT></P>
|
||||
|
||||
NEWLINE=>{D}<BR>
|
||||
P=>{D}<BR>%%DATA%%
|
||||
P/FOLLOW_P=>{D}<BR><IMG SRC="/img/dot.gif" WIDTH=1 VSPACE=6 HEIGHT=1><BR>%%DATA%%
|
||||
|
||||
STANDOUTO<=
|
||||
{D}<CENTER><FONT SIZE=1><BR></FONT><TABLE ALIGN=CENTER CELLPADDING=8 BORDER=1 BGCOLOR=#CCCCFF BORDERCOLORLIGHT=#DDDDFF
|
||||
BORDERCOLORDARK=#BBBBFF><TR><TD VALIGN=CENTER>
|
||||
%%DATA%%
|
||||
|
||||
</TD></TR></TABLE></CENTER>
|
||||
<=STANDOUTO
|
||||
|
||||
STANDOUT<=
|
||||
{D}<CENTER><FONT SIZE=1><BR></FONT>
|
||||
<table cellspacing=0 cellpadding=0 border=0 bgcolor="#ccccff">
|
||||
<tr>
|
||||
<td width=7 align=left valign=top>
|
||||
<img width=7 height=7 src="/img/corn_nw.gif" alt=""></td>
|
||||
<td height=7>
|
||||
<img height=7 src="/img/dot.gif" alt=""></td>
|
||||
<td width=7 valign=top align=right>
|
||||
<img height=7 src="/img/corn_ne.gif" alt=""></td>
|
||||
</tr><tr>
|
||||
<td width=7>
|
||||
<img width=7 height=1 src="/img/dot.gif" alt=""></td>
|
||||
<td valign=top>
|
||||
%%DATA%%
|
||||
|
||||
</td>
|
||||
<td width=7>
|
||||
<img width=7 height=1 src="/img/dot.gif" alt=""></td>
|
||||
</tr><tr>
|
||||
<td width=7 align=left valign=top>
|
||||
<img width=7 height=7 src="/img/corn_sw.gif" alt=""></td>
|
||||
<td height=7>
|
||||
<img height=7 src="/img/dot.gif" alt=""></td>
|
||||
<td width=7 valign=top align=right>
|
||||
<img height=7 src="/img/corn_se.gif" alt=""></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</CENTER>
|
||||
<=STANDOUT
|
||||
SOERROR=><div style='background-color:#f3f4fe; color:red; font-weight:bold; text-align:center'>%%data%%</div>
|
||||
EMAILEX=><div style='width: 50%; font-family: courier; background-color: #efefef; border: dotted #cdcdcd 2px; padding: 5px;'>%%data%%</div>
|
||||
|
||||
######################### choices stuff
|
||||
|
||||
CHOICE=>{P}<DT><A HREF="%%DATA2%%"><FONT FACE="Arial,Helvetica"><B>%%DATA1%%</B></FONT></A><DD><FONT SIZE="2">%%DATA3%%</FONT>
|
||||
|
||||
CHOICES<=
|
||||
{F}<P><DIV CLASS="choice"><TABLE WIDTH="100%" CELLPADDING="2" CELLSPACING="5">
|
||||
<TR>
|
||||
<TD VALIGN=TOP WIDTH="50%">
|
||||
<DL>
|
||||
%%ITEMS%%
|
||||
</DL>
|
||||
</TD>
|
||||
<TD VALIGN=TOP WIDTH="50%">
|
||||
<DL>
|
||||
%%ITEMSB%%
|
||||
</DL>
|
||||
</TD>
|
||||
</TR>
|
||||
</TABLE></DIV>
|
||||
<=CHOICES
|
||||
|
||||
##################################################################################
|
||||
################################### MAIN PAGE ####################################
|
||||
##################################################################################
|
||||
|
||||
PAGE<=
|
||||
{Fps}<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
|
||||
<HTML><?load_page_info?>
|
||||
<HEAD>
|
||||
<title><?_code {
|
||||
my $elhash = $_[2];
|
||||
return $elhash->{'WINDOWTITLE'} || $elhash->{'TITLE'};
|
||||
} _code?></title>
|
||||
%%head%%
|
||||
<?_code
|
||||
use strict;
|
||||
my $crumb_up;
|
||||
if(LJ::get_active_crumb() ne '')
|
||||
{
|
||||
my $parentcrumb = LJ::get_parent_crumb();
|
||||
$crumb_up = "<link rel='up' title='$parentcrumb->[0]' href='$parentcrumb->[1]' />";
|
||||
}
|
||||
return $crumb_up;
|
||||
_code?>
|
||||
</HEAD>
|
||||
|
||||
<BODY BGCOLOR=#FFFFFF TOPMARGIN="0" LEFTMARGIN="0" MARGINHEIGHT="0" MARGINWIDTH="0" LINK=#0000C0 VLINK=#600060 %%bodyopts%%>
|
||||
|
||||
<TABLE WIDTH=100% BORDER=0 CELLPADDING=0 CELLSPACING=0 BACKGROUND="/img/bluewhite/bluefade.jpg">
|
||||
<TR WIDTH=100%>
|
||||
<TD VALIGN=BOTTOM ALIGN=LEFT HEIGHT=100>
|
||||
|
||||
<TABLE BACKGROUND="" HEIGHT=95 WIDTH=100% BORDER=0>
|
||||
<TR>
|
||||
<TD WIDTH=3> </TD>
|
||||
<TD HEIGHT=53 WIDTH=406 VALIGN=BOTTOM>
|
||||
<?_code
|
||||
$is_home = (BML::get_uri() =~ m!^/(index\.bml)?!);
|
||||
if (0 && $is_home)
|
||||
{
|
||||
return '<IMG SRC="/img/bluewhite/title.gif" WIDTH=600 HEIGHT=53><!-- ';
|
||||
}
|
||||
return "";
|
||||
_code?>
|
||||
|
||||
<FONT SIZE=6 COLOR="#000a3f" FACE="Arial, Helvetica"><B>%%TITLE%%</B></FONT>
|
||||
|
||||
<?_code
|
||||
if (0 && $is_home)
|
||||
{
|
||||
return ' -->';
|
||||
}
|
||||
return "";
|
||||
_code?>
|
||||
|
||||
</TD>
|
||||
<TD VALIGN=TOP ALIGN=RIGHT>
|
||||
<?_code
|
||||
unless ($is_home) {
|
||||
return "<A HREF=\"/\"><IMG SRC=\"/img/bluewhite/home.gif\" WIDTH=35 HEIGHT=36 BORDER=0></A> ";
|
||||
}
|
||||
return "";
|
||||
_code?>
|
||||
</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
|
||||
</TD></TR>
|
||||
<TR><TD bgcolor="#FFFFFF"><?breadcrumbs?></TD></TR>
|
||||
</TABLE>
|
||||
|
||||
<TABLE BORDER=0 CELLPADDING=0 CELLSPACING=0>
|
||||
<TR VALIGN=TOP>
|
||||
<TD WIDTH=155 BGCOLOR=#d7d9e8 NOWRAP><IMG SRC="/img/bluewhite/hline.gif" WIDTH=155 HEIGHT=25 ALT="">
|
||||
|
||||
<TABLE WIDTH=153 BORDER=0 CELLSPACING=0 CELLPADDING=0>
|
||||
<TR><TD>
|
||||
|
||||
<FONT FACE="Arial,Helvetica" SIZE=-1>
|
||||
<?_code
|
||||
|
||||
$ret = "";
|
||||
|
||||
sub dump_entry
|
||||
{
|
||||
my ($ret, $listref, $depth) = @_;
|
||||
|
||||
foreach my $mi (@$listref)
|
||||
{
|
||||
if ($depth==0) {
|
||||
$$ret .= "<P><IMG SRC=\"/img/bluewhite/bullet.gif\" WIDTH=10 HEIGHT=10 HSPACE=2 ALIGN=ABSMIDDLE>";
|
||||
} else {
|
||||
$$ret .= " " x ($depth*3+1);
|
||||
$$ret .= $mi->{'cont'} ? " " : "- ";
|
||||
}
|
||||
|
||||
my $name = $mi->{'name'};
|
||||
$name =~ s/ / /g;
|
||||
if (! defined $mi->{'uri'}) {
|
||||
if ($depth == 0) {
|
||||
$$ret .= "<B>$name</B><BR>";
|
||||
} else {
|
||||
$$ret .= "$name<BR>";
|
||||
}
|
||||
} elsif ($mi->{'match'} ?
|
||||
(BML::get_uri() =~ /$mi->{'match'}/) :
|
||||
(BML::get_uri() eq $mi->{'uri'})
|
||||
){
|
||||
$$ret .= "<B><SPAN style=\"background-color: #FFFFFF\"><FONT COLOR=#0000D0>$name</FONT></SPAN></B><BR>";
|
||||
} else {
|
||||
$$ret .= "<A HREF=\"$mi->{'uri'}\">$name</A><BR>";
|
||||
}
|
||||
|
||||
if ($mi->{'children'} &&
|
||||
($mi->{'recursematch'} ? BML::get_uri() =~ /$mi->{'recursematch'}/ : 1)) {
|
||||
&dump_entry($ret, $mi->{'children'}, $depth+1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
&dump_entry(\$ret, \@sidebar, 0);
|
||||
|
||||
return $ret;
|
||||
|
||||
_code?>
|
||||
</FONT>
|
||||
|
||||
</TD></TR></TABLE>
|
||||
</TD>
|
||||
<TD ALIGN=LEFT BACKGROUND="/img/bluewhite/vline.gif" WIDTH=25 NOWRAP>
|
||||
<IMG SRC="/img/bluewhite/linetop.gif" WIDTH=25 HEIGHT=25 ALT=""><BR>
|
||||
<IMG SRC="/img/bluewhite/vline.gif" WIDTH=25 HEIGHT=800 ALT="">
|
||||
</TD>
|
||||
<TD>
|
||||
|
||||
<IMG SRC="/img/dot.gif" WIDTH=1 HEIGHT=3><BR>
|
||||
%%BODY%%
|
||||
|
||||
</TD>
|
||||
<TD WIDTH=20> </TD>
|
||||
</TR>
|
||||
|
||||
<!-- table closure row -->
|
||||
<TR>
|
||||
<TD WIDTH=155 NOWRAP><IMG SRC="/img/bluewhite/sidebarfade.gif" WIDTH=155 HEIGHT=25 ALT=""></TD>
|
||||
<TD WIDTH=25 NOWRAP><IMG SRC="/img/bluewhite/sidebarfade_line.gif" WIDTH=25 HEIGHT=25 ALT=""></TD></TD>
|
||||
<TD>
|
||||
|
||||
</TD>
|
||||
<TD WIDTH=20> </TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
<!-- /table closure row -->
|
||||
|
||||
<!--<TABLE WIDTH=100%>
|
||||
<TR>
|
||||
<TD ALIGN=RIGHT>
|
||||
<FONT FACE="Arial, Helvetica" SIZE="-2">
|
||||
<A HREF="/privacy.bml">Privacy Policy</A> -
|
||||
<A HREF="/coppa.bml">COPPA</A><BR>
|
||||
<A HREF="/disclaimer.bml">Legal Disclaimer</A> -
|
||||
<A HREF="/sitemap.bml">Site Map</A><BR>
|
||||
</FONT>
|
||||
</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
-->
|
||||
|
||||
</BODY>
|
||||
</HTML>
|
||||
<=PAGE
|
||||
|
||||
622
local/cgi-bin/bml/scheme/dystopia.look
Executable file
622
local/cgi-bin/bml/scheme/dystopia.look
Executable file
@@ -0,0 +1,622 @@
|
||||
# LiveJournal.com-specific library
|
||||
#
|
||||
# This file is NOT licensed under the GPL. As with everything in the
|
||||
# "ljcom" CVS repository, this file is the property of Danga
|
||||
# Interactive and is made available to the public only as a reference
|
||||
# as to the best way to modify/extend the base LiveJournal server code
|
||||
# (which is licensed under the GPL).
|
||||
#
|
||||
# Feel free to read and learn from things in "ljcom", but don't use
|
||||
# our schemes because we don't want your site looking like
|
||||
# LiveJournal.com (our logo and site scheme are our identity and we
|
||||
# don't want to confuse users)
|
||||
#
|
||||
# Instead, use/modify one of the schemes in the "livejournal" repository.
|
||||
# (Ideally you'd make your own entirely)
|
||||
#
|
||||
|
||||
_parent=>global.look
|
||||
|
||||
help=>{Ds}<a href="%%data%%"><img src="<?imgprefix?>/help.gif" alt="(<?_ml Help _ml?>)" title="(<?_ml Help _ml?>)" width='14' height='14' hspace='2' align='absmiddle' border='0'></a>
|
||||
|
||||
h1=>{D}<p><span class="heading">%%data%%</span>
|
||||
h1/follow_choices=>{D}<span class="heading">%%data%%</span>
|
||||
|
||||
h2=>{D}<p><span class="heading2">%%data%%</span>
|
||||
|
||||
# Banner Header: search results banner, content desriptor, etc...
|
||||
bh=>{D}<p align="center"><font face="Arial,Helvetica" color="#cc0000" size="-1"><b>%%data%%</b></font>
|
||||
|
||||
grin=>{S}<grin>
|
||||
hr=>{S}<p align="center"><font color=#660066>*</font></p>
|
||||
|
||||
newline=>{S}<br />
|
||||
p=>{DRp}<br />%%data%%
|
||||
p/follow_p=>{DRps}<br /><img src="<?imgprefix?>/dot.gif" width="1" vspace="6" height="1"><br />%%data%%
|
||||
|
||||
emcolor=>{S}#a7c7e8
|
||||
emcolorlite=>{S}#d9e9f9
|
||||
altcolor1=>{S}#d9e9f9
|
||||
altcolor2=>{S}#a7c7e8
|
||||
|
||||
de=>{DRp}<span style="color:#909090;">%%data%%</span>
|
||||
|
||||
standout<=
|
||||
{DRps}<center><font size="1"><br /></font>
|
||||
<table cellspacing="0" cellpadding="0" border="0" bgcolor="<?emcolor?>">
|
||||
<tr align="left">
|
||||
<td width="7" align="left" valign="top">
|
||||
<img width="7" height="7" src="<?imgprefix?>/dys/corn_nw.gif" alt="/"></td>
|
||||
<td height="7">
|
||||
<img height="7" src="<?imgprefix?>/dot.gif" alt=""></td>
|
||||
<td width="7" valign="top" align="right">
|
||||
<img height="7" src="<?imgprefix?>/dys/corn_ne.gif" alt="\"></td>
|
||||
</tr><tr align="left">
|
||||
<td width="7">
|
||||
<img width="7" height="1" src="<?imgprefix?>/dot.gif" alt=""></td>
|
||||
<td valign="top">
|
||||
%%data%%
|
||||
|
||||
</td>
|
||||
<td width="7">
|
||||
<img width="7" height="1" src="<?imgprefix?>/dot.gif" alt=""></td>
|
||||
</tr><tr>
|
||||
<td width="7" align=left valign=top>
|
||||
<img width="7" height="7" src="<?imgprefix?>/dys/corn_sw.gif" alt="\"></td>
|
||||
<td height="7">
|
||||
<img height="7" src="<?imgprefix?>/dot.gif" alt=""></td>
|
||||
<td width="7" valign=top align=right>
|
||||
<img height="7" src="<?imgprefix?>/dys/corn_se.gif" alt="/"></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</center>
|
||||
<=standout
|
||||
|
||||
warningbar<=
|
||||
{DRps}<div class="warningbar" style="background-image: URL('<?imgprefix?>/message-warning.gif');">
|
||||
%%data%%
|
||||
</div>
|
||||
<=warningbar
|
||||
|
||||
errorbar<=
|
||||
{DRps}<div class="errorbar" style="background-image: URL('<?imgprefix?>/message-error.gif');">
|
||||
%%data%%
|
||||
</div>
|
||||
<=errorbar
|
||||
|
||||
soerror=><div style='background-color:#d0eef9; color:red; font-weight:bold; text-align:center'>%%data%%</div>
|
||||
emailex=><div style='width: 50%; font-family: courier; background-color: #efefef; border: dotted #cdcdcd 2px; padding: 5px;'>%%data%%</div>
|
||||
|
||||
######################### choices stuff
|
||||
|
||||
choice=>{PRps}<dt><img src="<?imgprefix?>/dys/b_purp.gif" align="absmiddle" width="8" height="8"> <a href="%%data2%%"><font face="Arial,Helvetica"><b>%%data1%%</b></font></a><dd><font size="2">%%data3%%</font>
|
||||
|
||||
choices<=
|
||||
{FRp}<p><div class="choice"><table width="100%" cellpadding="2" cellspacing="5">
|
||||
<tr>
|
||||
<td valign="top" width="50%">
|
||||
<dl>
|
||||
%%items%%
|
||||
</dl>
|
||||
</td>
|
||||
<td valign="top" width="50%">
|
||||
<dl>
|
||||
%%itemsb%%
|
||||
</dl>
|
||||
</td>
|
||||
</tr>
|
||||
</table></div>
|
||||
<=choices
|
||||
|
||||
ENTRYFORMCSS<=
|
||||
{Ss}
|
||||
<style type="text/css">
|
||||
#EntryForm #MetaInfo {
|
||||
width: 100%;
|
||||
}
|
||||
#EntryForm th {
|
||||
font-size: .85em;
|
||||
}
|
||||
#EntryForm #SubmitBar {
|
||||
background-color: #dfdfdf;
|
||||
padding: 5px;
|
||||
text-align: center;
|
||||
border: 1px outset #000;
|
||||
margin-left: auto; margin-right: auto;
|
||||
}
|
||||
#MetaInfo tr {
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
#metainfo th {
|
||||
text-align: left;
|
||||
}
|
||||
#mood_preview {
|
||||
display: none;
|
||||
}
|
||||
#datetime_box input, #datetime_box select {
|
||||
margin-right: 2px;
|
||||
}
|
||||
#EntryForm legend {
|
||||
font-weight: bold;
|
||||
}
|
||||
#EntryForm #Options {
|
||||
margin-left: 0; margin-right: 0; padding: 0;
|
||||
background-color: #dfdfdf;
|
||||
border: 1px outset #000;
|
||||
}
|
||||
#EntryForm #Options th {
|
||||
text-align: left;
|
||||
}
|
||||
#EntryForm #infobox {
|
||||
text-align: center;
|
||||
}
|
||||
#EntryForm #infobox table {
|
||||
background-color: #dfdfdf;
|
||||
border: 2px solid <?emcolor?>;
|
||||
}
|
||||
#EntryForm textarea {
|
||||
border: 1px inset #000;
|
||||
padding: 2px;
|
||||
}
|
||||
#EntryForm #Security option {
|
||||
padding-left: 18px;
|
||||
}
|
||||
#EntryForm #security_public {
|
||||
background-image: url("<?imgprefix?>/userinfo.gif");
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
#EntryForm #security_private {
|
||||
background-image: url("<?imgprefix?>/icon_private.gif");
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
#EntryForm #security_friends, #EntryForm #security_custom {
|
||||
background-image: url("<?imgprefix?>/icon_protected.gif");
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
#EntryForm #UserpicPreviewImage {
|
||||
border: 1px solid #000;
|
||||
}
|
||||
#EntryForm {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
<=ENTRYFORMCSS
|
||||
|
||||
##################################################################################
|
||||
################################### MAIN PAGE ####################################
|
||||
##################################################################################
|
||||
|
||||
PAGE<=
|
||||
{Fps}<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
|
||||
<html>
|
||||
<?_code
|
||||
{
|
||||
my $remote = LJ::get_remote(); # will be requested later and returned from cache
|
||||
return LJ::LJcom::expresslane_html_comment($remote, $_[0]->{r});
|
||||
}
|
||||
_code?>
|
||||
<head>
|
||||
<link rel="SHORTCUT ICON" href="<?siteroot?>/favicon.ico">
|
||||
<link rel="home" title="Home" href="/" />
|
||||
<link rel="contents" title="Site Map" href="/site/" />
|
||||
<link rel="help" title="Technical Support" href="/support/" />
|
||||
<title><?_code {
|
||||
my $elhash = $_[2];
|
||||
return $elhash->{'WINDOWTITLE'} || $elhash->{'TITLE'};
|
||||
} _code?></title>
|
||||
<?metactype?>
|
||||
<style type="text/css">
|
||||
<!--
|
||||
p, td { font-size: 12px; font-family: Verdana, Arial, Helvetica, sans-serif; }
|
||||
li { font-size: 12px; font-family: Verdana, Arial, Helvetica, sans-serif; }
|
||||
body { font-size: 12px; font-family: Verdana, Arial, Helvetica, sans-serif; margin: 0px; }
|
||||
.navtext { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 11px; color: #FF9900; font-weight: bold}
|
||||
.navlinks { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 11px; color: #FFFFFF; text-decoration: underline}
|
||||
a:link { font-family: Verdana, Arial, Helvetica, sans-serif; color: #000066; }
|
||||
a:visited { font-family: Verdana, Arial, Helvetica, sans-serif; color: #000066; }
|
||||
a:active { font-family: Verdana, Arial, Helvetica, sans-serif; color: #006699; }
|
||||
.wtext { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 11px; font-weight: bold; color: #FFFFFF}
|
||||
.login { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 11px}
|
||||
.wtextunbld { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 11px; color: #FFFFFF }
|
||||
.copy { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 11px; color: #000000}
|
||||
.heading { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 13px; color: #660066; font-weight: bold}
|
||||
.heading2 { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 13px; color: #660066; font-style: italic }
|
||||
.talk-comment { margin-top: 1em; }
|
||||
.lesstop { margin-top: 2px; }
|
||||
.formitem { color: #343434; font-size: 1em; }
|
||||
.formnumber { font-weight: bold; margin-top: 1.8em; font-size: .9em; }
|
||||
.formitemName { font-weight: bold; font-size: .9em; margin-top: 1.8em; }
|
||||
.formitemDesc { margin-top: .4em; margin-bottom: .4em; color: #505050; }
|
||||
.formitemNote { color: #da6320; font-size: .9em; margin-top: .4em; margin-bottom: .4em; }
|
||||
.formitemFlag { color: #CE0000; font-size: .9em; margin-top: .4em; margin-bottom: .4em; }
|
||||
.borderedtable { border: solid 1px black; }
|
||||
.borderedtable th { background-color: #dddddd; border-bottom: solid 1px black; padding-left: 10px; padding-right: 10px; white-space: nowrap; font-size: 0.8em; }
|
||||
|
||||
#Comments q { padding-left: 2.5em; font-style: italic; }
|
||||
|
||||
.errorbar {
|
||||
color: #000;
|
||||
font: 12px Verdana, Arial, Sans-Serif;
|
||||
background-color: #FFEEEE;
|
||||
background-repeat: repeat-x;
|
||||
border: 1px solid #FF9999;
|
||||
padding: 8px;
|
||||
margin-top: auto; margin-bottom: auto;
|
||||
margin-left: auto; margin-right: auto;
|
||||
width: auto;
|
||||
text-align: left;
|
||||
}
|
||||
.warningbar {
|
||||
color: #000;
|
||||
font: 12px Verdana, Arial, Sans-Serif;
|
||||
background-color: #FFFFDD;
|
||||
background-repeat: repeat-x;
|
||||
border: 1px solid #FFCC33;
|
||||
padding: 8px;
|
||||
margin-top: auto; margin-bottom: auto;
|
||||
margin-left: auto; margin-right: auto;
|
||||
width: auto;
|
||||
text-align: left;
|
||||
}
|
||||
-->
|
||||
</style>
|
||||
|
||||
<script language="JavaScript">
|
||||
window.onerror = null; // damn javascript.
|
||||
</script>
|
||||
<?_code return (! LJ::get_remote() &&
|
||||
! $LJ::IS_SSL &&
|
||||
! $LJ::REQ_HEAD_HAS{'chalresp_js'}++) ?
|
||||
$LJ::COMMON_CODE{'chalresp_js'} : "";
|
||||
_code?>
|
||||
<?_code
|
||||
use strict;
|
||||
my $crumb_up;
|
||||
if(LJ::get_active_crumb() ne '')
|
||||
{
|
||||
my $parentcrumb = LJ::get_parent_crumb();
|
||||
$crumb_up = "<link rel='up' title='$parentcrumb->[0]' href='$parentcrumb->[1]' />";
|
||||
}
|
||||
return $crumb_up;
|
||||
_code?>
|
||||
%%head%%
|
||||
</head>
|
||||
<body bgcolor="#FFFFFF" background="<?imgprefix?>/dys/bg.gif" leftmargin="0" topmargin="0" marginwidth="0" marginheight="0" text="#000000" link="#660066" vlink="#000066" alink="#CC6600" %%bodyopts%%>
|
||||
<basefont face="Verdana,Arial,Helvetica">
|
||||
<table width="100%" border="0" cellspacing="0" cellpadding="0">
|
||||
<tr align="left" valign="top">
|
||||
<td colspan='2'>
|
||||
<table width='100%' border="0" cellspacing="0" cellpadding="0" background="<?imgprefix?>/dys/bg_top.gif">
|
||||
<tr>
|
||||
<td><a href="<?siteroot?>/"><img src="<?imgprefix?>/dys/logo1.gif" width="122" height="51" border="0"></a></td>
|
||||
<td width="163" align="left" valign="top"><a href="<?siteroot?>/"><img src="<?imgprefix?>/dys/logo2.gif" width="170" height="51" border="0"></a></td>
|
||||
<td background="<?imgprefix?>/dys/bg_top.gif" align="left" valign="top" width="244"> </td>
|
||||
<td background="<?imgprefix?>/dys/bg_top.gif" align="left" valign="top" width="100%"> </td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- logo, then search & logged in links bar stack on top of each other -->
|
||||
|
||||
<tr align="left" valign="top">
|
||||
<td width="<?_ml dystopia.nav.width _ml?>" height="49"
|
||||
><?_code
|
||||
unless ($BML::COOKIE{'langpref'}) {
|
||||
return '<img src="<?imgprefix?>/dys/logo3-lang.gif" width="122" height="52" border="0" ismap="ismap" usemap="#setlang"><map name="setlang"><area href="/manage/siteopts.bml" shape="rect" coords="50,25,122,50"></map>';
|
||||
} else {
|
||||
return '<img src="<?imgprefix?>/dys/logo3.gif" width="122" height="52" border="0">';
|
||||
}
|
||||
_code?></td>
|
||||
<td height="49">
|
||||
<table width="100%" border="0" cellspacing="0" cellpadding="0">
|
||||
<colgroup span="3">
|
||||
<col width="19%" />
|
||||
<col width="34%" />
|
||||
<col width="47%" />
|
||||
</colgroup>
|
||||
|
||||
<!-- search bar -->
|
||||
<tr valign="top">
|
||||
<td height="24" width="19%" align="left"> </td>
|
||||
<form action="/multisearch.bml">
|
||||
<td height="24" align="right" valign="middle" colspan="2" nowrap="nowrap">
|
||||
<font face="verdana, arial, sans-serif" color=#333333 size=-2>
|
||||
<span class="wtextunbld"><label for='searchlj'><?_ml dystopia.searchlj _ml?></label> </span>
|
||||
<?_code
|
||||
#BML:cache
|
||||
my $ret;
|
||||
my ($cur, $val) = ("user", "");
|
||||
my ($uri, $args) = (BML::get_uri(), BML::get_query_string());
|
||||
if ($uri eq '/interests.bml' && $args =~ /int=(.+?)(&|$)/) {
|
||||
$cur = "int";
|
||||
$val = LJ::durl($1);
|
||||
}
|
||||
if ($FORM{'s_loc'}) {
|
||||
$cur = "region";
|
||||
}
|
||||
|
||||
my $hval = LJ::ehtml($val);
|
||||
$ret .= "<input id='searchlj' type='text' name='q' size='15' class='login' value='$hval'> ";
|
||||
$ret .= '<select style="FONT-SIZE: 10px; FONT-FAMILY: verdana, arial, helvetica" name=type>';
|
||||
foreach my $it (
|
||||
["user", BML::ml("Username")],
|
||||
["email", BML::ml("Email")],
|
||||
["region", BML::ml("dystopia.search.region")],
|
||||
["int", BML::ml("dystopia.search.int")],
|
||||
["aolim", BML::ml("dystopia.search.aolim")],
|
||||
["icq", BML::ml("dystopia.search.icq")],
|
||||
["yahoo", BML::ml("dystopia.search.yahoo")],
|
||||
["msn", BML::ml("dystopia.search.msn")],
|
||||
["jabber", BML::ml("dystopia.search.jabber")],
|
||||
) {
|
||||
next if ($it->[0] eq "region" && $LJ::DISABLED{'directory'});
|
||||
my $sel = $cur eq $it->[0] ? " SELECTED" : "";
|
||||
$ret .= "<option value=$it->[0]$sel>$it->[1]";
|
||||
}
|
||||
return BML::noparse($ret);
|
||||
_code?>
|
||||
</select>
|
||||
<img src="<?imgprefix?>/dot.gif" width="1" height="5">
|
||||
<input type=submit value="<?_ml btn.search _ml?>" class="login">
|
||||
</font>
|
||||
</td></form>
|
||||
</tr>
|
||||
<!-- /search livejournal bar -->
|
||||
|
||||
|
||||
<!-- logged in bar -->
|
||||
<tr>
|
||||
<td height="27" class="wtext" width="53%" colspan="2" nowrap="nowrap" valign="middle">
|
||||
<?_code
|
||||
#BML:cache
|
||||
if (LJ::get_remote()) {
|
||||
return BML::noparse(BML::ml("dystopia.hello_loggedin", { 'username' => LJ::get_remote()->{'user'} }));
|
||||
} else {
|
||||
return BML::noparse(BML::ml("dystopia.hello_anonymous"))
|
||||
}
|
||||
_code?></td>
|
||||
<td height="27" width="47%" nowrap="nowrap" align="right" valign="middle">
|
||||
<a href="/"><span class="navlinks"><?_ml dystopia.nav.home _ml?></span></a> <span class="navtext">|</span>
|
||||
<a href="/site/"><span class="navlinks"><?_ml dystopia.nav.sitemap _ml?></span></a> <span class="navtext">|</span>
|
||||
<a href="/news.bml"><span class="navlinks"><?_ml dystopia.nav.news _ml?></span></a> <span class="navtext">|</span>
|
||||
<a href="/manage/siteopts.bml"><span class="navlinks"><?_ml dystopia.nav.siteopts _ml?></span></a> <span class="navtext">|</span>
|
||||
<a href="/support/"><span class="navlinks"><?_ml Help _ml?></span></a>
|
||||
<?_code
|
||||
#BML:cache
|
||||
my $r = LJ::get_remote();
|
||||
if ($r) {
|
||||
return BML::noparse(' <span class="navtext">|</span> <a href="/logout.bml?user=' . "$r->{'user'}&sessid=$r->{'_session'}->{'sessid'}" . '"><span class="navlinks">' . BML::ml("dystopia.nav.logout") . '</span></a>');
|
||||
}
|
||||
return;
|
||||
_code?>
|
||||
<img src="<?imgprefix?>/dys/5x5.gif" width="10" height="5"></td>
|
||||
</tr>
|
||||
<!-- /logged in bar -->
|
||||
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- /logo, search, logged in bar -->
|
||||
|
||||
<!-- left sidebar and body -->
|
||||
|
||||
<tr align="left" valign="top">
|
||||
<td bgcolor="#336699" width="<?_ml dystopia.nav.width _ml?>" height="813">
|
||||
<table width="<?_ml dystopia.nav.width _ml?>" border="0" cellspacing="0" cellpadding="10">
|
||||
<?_code
|
||||
#BML:cache
|
||||
my @nav;
|
||||
my $remote = LJ::get_remote();
|
||||
if ($remote) {
|
||||
push @nav, { 'name' => BML::ml('dystopia.navhead.journal'),
|
||||
'links' => [ { 'url' => '/update.bml',
|
||||
'text' => BML::ml('dystopia.nav.updatejournal'), },
|
||||
{ 'url' => "/users/$remote->{'user'}/",
|
||||
'text' => BML::ml('dystopia.nav.journalrecent'), },
|
||||
{ 'url' => "/users/$remote->{'user'}/calendar",
|
||||
'text' => BML::ml('dystopia.nav.journalcalendar'), },
|
||||
{ 'url' => "/users/$remote->{'user'}/friends",
|
||||
'text' => BML::ml('dystopia.nav.journalfriends'),
|
||||
'extra' => '/friends/filter.bml', },
|
||||
{ 'url' => "/userinfo.bml?user=$remote->{'user'}",
|
||||
'text' => BML::ml('dystopia.nav.journalinfo'),
|
||||
'extra' => "/userinfo.bml?user=$remote->{'user'}&mode=full",
|
||||
},
|
||||
{ 'url' => "/tools/memories.bml?user=$remote->{'user'}",
|
||||
'text' => BML::ml('dystopia.nav.memories'), },
|
||||
{ 'url' => "/editjournal.bml",
|
||||
'text' => BML::ml('dystopia.nav.editentries'), },
|
||||
],
|
||||
};
|
||||
push @nav, { 'name' => BML::ml('dystopia.navhead.settings'),
|
||||
'links' => [ { 'url' => '/manage/',
|
||||
'text' => BML::ml('dystopia.nav.manage') },
|
||||
{ 'url' => '/editinfo.bml',
|
||||
'text' => BML::ml('dystopia.nav.personalinfo') },
|
||||
{ 'url' => "/friends/edit.bml",
|
||||
'text' => BML::ml('dystopia.nav.editfriends'), },
|
||||
{ 'url' => "/editpics.bml",
|
||||
'text' => BML::ml('dystopia.nav.editpics'), },
|
||||
{ 'url' => "/changepassword.bml",
|
||||
'text' => BML::ml('dystopia.nav.editpassword'), },
|
||||
{ 'url' => "/modify.bml",
|
||||
'text' => BML::ml('dystopia.nav.modifyjournal'), },
|
||||
{ 'url' => "/styles/edit.bml",
|
||||
'text' => BML::ml('dystopia.nav.editstyle'), },
|
||||
],
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
push @nav, { 'name' => BML::ml('dystopia.navhead.welcome'),
|
||||
'links' => [
|
||||
{ 'url' => '/login.bml',
|
||||
'text' => BML::ml('dystopia.nav.login'), },
|
||||
{ 'url' => '/create.bml',
|
||||
'text' => BML::ml('dystopia.nav.createjournal'), },
|
||||
{ 'url' => "/update.bml",
|
||||
'text' => BML::ml('dystopia.nav.updatejournal'), },
|
||||
],
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
push @nav, { 'name' => BML::ml('dystopia.navhead.findusers'),
|
||||
'links' => [
|
||||
{ 'url' => '/random.bml',
|
||||
'text' => BML::ml('dystopia.nav.findrandom'), },
|
||||
$LJ::DISABLED{'directory'} ? () :
|
||||
(
|
||||
{ 'url' => '/directory.bml',
|
||||
'text' => BML::ml('dystopia.nav.findregion'), }
|
||||
),
|
||||
{ 'url' => '/community/',
|
||||
'text' => BML::ml('dystopia.nav.findcomm'), },
|
||||
{ 'url' => '/interests.bml',
|
||||
'text' => BML::ml('dystopia.nav.findint'), },
|
||||
$LJ::DISABLED{'directory'} ? () :
|
||||
(
|
||||
{ 'url' => '/directorysearch.bml',
|
||||
'text' => BML::ml('dystopia.nav.finddir'), }
|
||||
),
|
||||
],
|
||||
};
|
||||
|
||||
push @nav, { 'name' => 'LiveJournal',
|
||||
'links' => [
|
||||
{ 'url' => '/download/',
|
||||
'text' => BML::ml('dystopia.nav.download'), },
|
||||
{ 'url' => '/paidaccounts/',
|
||||
'text' => BML::ml('dystopia.nav.paidaccts'), },
|
||||
{ 'url' => '/pay/',
|
||||
'text' => BML::ml('dystopia.nav.paymentarea'), },
|
||||
],
|
||||
};
|
||||
|
||||
push @nav, { 'name' => BML::ml('dystopia.navhead.help'),
|
||||
'links' => [ { 'url' => '/support/faq.bml',
|
||||
'text' => BML::ml('dystopia.nav.faq'), },
|
||||
{ 'url' => '/support/',
|
||||
'text' => BML::ml('dystopia.nav.support'), },
|
||||
{ 'url' => '/lostinfo.bml',
|
||||
'text' => BML::ml('dystopia.nav.lostinfo'), },
|
||||
{ 'url' => '/developer/',
|
||||
'text' => BML::ml('dystopia.nav.developer'), },
|
||||
{ 'url' => '/press/staff.bml',
|
||||
'text' => BML::ml('dystopia.nav.contact'), },
|
||||
],
|
||||
};
|
||||
|
||||
push @nav, { 'name' => BML::ml('dystopia.navhead.legal'),
|
||||
'links' => [ { 'url' => '/tos.html',
|
||||
'text' => BML::ml('dystopia.nav.legaltos'), },
|
||||
{ 'url' => '/privacy.bml',
|
||||
'text' => BML::ml('dystopia.nav.legalprivacy'), },
|
||||
# { 'url' => '/legal/dmca.bml',
|
||||
# 'text' => BML::ml('dystopia.nav.legaldmca'), },
|
||||
],
|
||||
};
|
||||
|
||||
|
||||
my $ret = $LJ::DYS_LEFT_TOP;
|
||||
foreach my $sec (@nav) {
|
||||
$ret .= "<tr align=left valign=top><td><p><span class=navtext>$sec->{'name'}</span><br />";
|
||||
foreach my $l (@{$sec->{'links'}}) {
|
||||
$ret .= "<a href=\"$l->{'url'}\"><span class=navlinks>$l->{'text'}</span></a>";
|
||||
if ($l->{'extra'}) {
|
||||
$ret .= " <a href=\"$l->{'extra'}\"><span class=navlinks>...</span></a>";
|
||||
}
|
||||
$ret .= "<br />";
|
||||
}
|
||||
$ret .= "</td></tr>";
|
||||
}
|
||||
return BML::noparse($ret);
|
||||
|
||||
_code?>
|
||||
<tr align="left" valign="top">
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr align="left" valign="top">
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr align="left" valign="top">
|
||||
<td> </td>
|
||||
</tr>
|
||||
</table>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
</td>
|
||||
<td height="813" bgcolor="#FFFFFF">
|
||||
<table width="100%" border="0" cellspacing="0" cellpadding="0">
|
||||
|
||||
<!-- login bar -->
|
||||
<?_code
|
||||
#BML:cache
|
||||
#WITHPORTAL: unless ($remote || BML::get_uri() eq "/") {
|
||||
my $remote = LJ::get_remote();
|
||||
unless ($remote || BML::get_uri eq '/login.bml') {
|
||||
my $button;
|
||||
my $logincaption = BML::ml('dystopia.btn.login');
|
||||
if ($logincaption eq 'LOGIN') {
|
||||
if (! $LJ::IS_SSL) {
|
||||
$button = "<input type=image onclick='return sendForm()' src='$LJ::IMGPREFIX/dys/login_but.gif' width='48' height='15' border='0'>";
|
||||
} else {
|
||||
$button = "<input type=image src='$LJ::IMGPREFIX/dys/login_but.gif' width='48' height='15' border='0'>";
|
||||
}
|
||||
} else {
|
||||
if (! $LJ::IS_SSL) {
|
||||
$button = "<input type='submit' onclick='return sendForm()' value='$ML{'dystopia.btn.login'}' style='margin-top: 0px; margin-bottom: 1px; font-weight: bold; height: 19px; border: 1px solid #ffffff; background: #336699 none; color: #ffffff; padding-left: 0px; padding-right: 0px'></td>";
|
||||
} else {
|
||||
$button = "<input type='submit' value='$ML{'dystopia.btn.login'}' style='margin-top: 0px; margin-bottom: 1px; font-weight: bold; height: 19px; border: 1px solid #ffffff; background: #336699 none; color: #ffffff; padding-left: 0px; padding-right: 0px'></td>";
|
||||
}
|
||||
}
|
||||
|
||||
my $chal = LJ::challenge_generate(300);
|
||||
return <<"END_LOGIN_BAR";
|
||||
<form action="/login.bml" method="post" id='login'>
|
||||
<input type="hidden" name="mode" value="login" />
|
||||
<input type='hidden' name='chal' id='login_chal' value='$chal' />
|
||||
<input type='hidden' name='response' id='login_response' value='' />
|
||||
<tr>
|
||||
<td align="right" valign="top" bgcolor="#FFFFFF">
|
||||
<table border='0' cellspacing='0' cellpadding='0' width='200' align='right'>
|
||||
<tr>
|
||||
<td align="left" valign="bottom" bgcolor="#660066"><img src="<?imgprefix?>/dys/lg_crnrgif.gif" width="14" height="23"></td>
|
||||
<td align="right" valign="middle" bgcolor="#660066" class="wtextunbld" nowrap="nowrap"> $ML{'Username'}: </td>
|
||||
<td align="center" valign="top" bgcolor="#660066" class="wtext" nowrap="nowrap"><input type="text" name="user" size="15" maxlength="15" class="login" style="<?loginboxstyle?>"></td>
|
||||
<td align="right" valign="middle" bgcolor="#660066" class="wtextunbld" nowrap="nowrap"> $ML{'Password'}: </td>
|
||||
<td align="center" valign="top" bgcolor="#660066" class="wtext" nowrap="nowrap"><input type="password" name="password" size="10" id='xc_password' class="login"></td>
|
||||
<td align="center" valign="middle" bgcolor="#660066" nowrap="nowrap"> $button</tr>
|
||||
</table>
|
||||
</td></tr>
|
||||
</form>
|
||||
END_LOGIN_BAR
|
||||
}
|
||||
return;
|
||||
|
||||
_code?>
|
||||
<!-- /login bar -->
|
||||
|
||||
<tr align="left" valign="top" bgcolor="#ffffff">
|
||||
<td height="585" colspan="7">
|
||||
|
||||
<!-- body area -->
|
||||
<table border="0" cellspacing="0" cellpadding="10" width="100%"><tr><td>
|
||||
|
||||
<?breadcrumbs?>
|
||||
|
||||
%%pretitle%%
|
||||
|
||||
<font size="+2" face="Verdana, Arial, Helvetica" color=#000066>%%title%%</font><p>
|
||||
|
||||
%%body%%
|
||||
|
||||
</td></tr></table>
|
||||
<!-- /body area -->
|
||||
</td></tr></table>
|
||||
</td></tr></table>
|
||||
</body></html>
|
||||
<=PAGE
|
||||
|
||||
379
local/cgi-bin/bml/scheme/global.look
Executable file
379
local/cgi-bin/bml/scheme/global.look
Executable file
@@ -0,0 +1,379 @@
|
||||
_parent=>../../lj-bml-blocks.pl
|
||||
|
||||
loginboxstyle=>{Ss}background: url(<?imgprefix?>/userinfo.gif) no-repeat; background-color: #fff; background-position: 0px 1px; padding-left: 18px; color: #00C; font-weight: bold;
|
||||
commloginboxstyle=>{Ss}background: url(<?imgprefix?>/community.gif) no-repeat; background-color: #fff; background-position: 0px 2px; padding-left: 19px; color: #00C; font-weight: bold;
|
||||
|
||||
SECURITYPRIVATE=>{Ss}<img src="<?imgprefix?>/icon_private.gif" width=16 height=16 align=absmiddle>
|
||||
SECURITYPROTECTED=>{Ss}<img src="<?imgprefix?>/icon_protected.gif" width=14 height=15 align=absmiddle>
|
||||
LJUSER=>{DRs}<span class='ljuser' style='white-space:nowrap;'><a href='/userinfo.bml?user=%%data%%'><img src='<?imgprefix?>/userinfo.gif' alt='userinfo' width='17' height='17' style='vertical-align:bottom;border:0;' /></a><a href='/users/%%data%%/'><b>%%data%%</b></a></span>
|
||||
LJCOMM=>{DRs}<span class='ljuser' style='white-space:nowrap;'><a href='/userinfo.bml?user=%%data%%'><img src='<?imgprefix?>/community.gif' alt='userinfo' width='16' height='16' style='vertical-align:bottom;border:0;' /></a><a href='/community/%%data%%/'><b>%%data%%</b></a></span>
|
||||
LJUSERF=>{DRs}<span class='ljuser' style='white-space:nowrap;'><a href='/userinfo.bml?user=%%data%%&mode=full'><img src='<?imgprefix?>/userinfo.gif' alt='userinfo' width='17' height='17' style='vertical-align:bottom;border:0;' /></a><a href='/users/%%data%%/'><b>%%data%%</b></a></span>
|
||||
HELP=>{DR}(<a href="%%data%%"><i>help</i></a>)
|
||||
INERR=>{DR}<font color="#ff0000"><b>%%data%%</b></font>
|
||||
SOERROR=>{DR}<div><b>%%data%%</b></div>
|
||||
EMAILEX=><div style='font-family: courier; border: solid black 1px; padding: 5px;'>%%data%%</div>
|
||||
|
||||
ENTRYFORMCSS<=
|
||||
{Ss}
|
||||
<style type="text/css">
|
||||
#EntryForm #MetaInfo {
|
||||
width: 100%;
|
||||
}
|
||||
#EntryForm th {
|
||||
font-size: 1em;
|
||||
}
|
||||
#EntryForm #SubmitBar {
|
||||
background-color: #dfdfdf;
|
||||
padding: 5px;
|
||||
text-align: center;
|
||||
border: 1px outset #000;
|
||||
margin-left: auto; margin-right: auto;
|
||||
}
|
||||
#MetaInfo tr {
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
#metainfo th {
|
||||
text-align: left;
|
||||
}
|
||||
#mood_preview {
|
||||
display: none;
|
||||
}
|
||||
#datetime_box input, #datetime_box select {
|
||||
margin-right: 2px;
|
||||
}
|
||||
#EntryForm legend {
|
||||
font-weight: bold;
|
||||
}
|
||||
#EntryForm #Options {
|
||||
margin-left: 0; margin-right: 0; padding: 0;
|
||||
background-color: #dfdfdf;
|
||||
border: 1px outset #000;
|
||||
}
|
||||
#EntryForm #Options th {
|
||||
text-align: left;
|
||||
}
|
||||
#EntryForm #infobox {
|
||||
text-align: center;
|
||||
}
|
||||
#EntryForm #infobox table {
|
||||
background-color: #dfdfdf;
|
||||
border: 2px solid <?emcolor?>;
|
||||
}
|
||||
#EntryForm textarea {
|
||||
border: 1px inset #000;
|
||||
padding: 2px;
|
||||
}
|
||||
#EntryForm #Security option {
|
||||
padding-left: 18px;
|
||||
}
|
||||
#EntryForm #security_public {
|
||||
background-image: url("<?imgprefix?>/userinfo.gif");
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
#EntryForm #security_private {
|
||||
background-image: url("<?imgprefix?>/icon_private.gif");
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
#EntryForm #security_friends, #EntryForm #security_custom {
|
||||
background-image: url("<?imgprefix?>/icon_protected.gif");
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
#EntryForm #UserpicPreviewImage {
|
||||
border: 1px solid #000;
|
||||
}
|
||||
#EntryForm {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
<=ENTRYFORMCSS
|
||||
|
||||
NEEDLOGIN<=
|
||||
<?h1 <?_ml bml.needlogin.head _ml?> h1?>
|
||||
<?p <?_ml bml.needlogin.body2 _ml?> p?>
|
||||
<=NEEDLOGIN
|
||||
|
||||
BADINPUT<=
|
||||
<?h1 <?_ml bml.badinput.head _ml?> h1?>
|
||||
<?p <?_ml bml.badinput.body _ml?> p?>
|
||||
<=BADINPUT
|
||||
|
||||
REQUIREPOST=><?_ml bml.requirepost _ml?>
|
||||
|
||||
LOAD_PAGE_INFO<=
|
||||
<?_code
|
||||
#line 3
|
||||
@sidebar = ({ 'name' => 'Home',
|
||||
'uri' => '/',
|
||||
'match' => "^/(index\\.bml)?(\\?.*)?\$",
|
||||
'children' => [
|
||||
{ 'name' => BML::ml('ljrlook.nav.create'),
|
||||
'uri' => '/create.bml', },
|
||||
{ 'name' => BML::ml('ljrlook.nav.update'),
|
||||
'uri' => '/update.bml',
|
||||
'children' => [
|
||||
{ 'name' => BML::ml('ljrlook.nav.fullupdate'),
|
||||
'uri' => '/update.bml?mode=full', }
|
||||
],
|
||||
},
|
||||
# { 'name' => 'Download',
|
||||
# 'uri' => '/download/', },
|
||||
],
|
||||
},
|
||||
{ 'name' => BML::ml('ljrlook.nav.site'),
|
||||
'children' => [
|
||||
{ 'name' => BML::ml('ljrlook.nav.news'),
|
||||
'match' => '^/news\\.bml\$',
|
||||
'uri' => '/community/ljr_news/', },
|
||||
{ 'name' => BML::ml('ljrlook.nav.siteopts'),
|
||||
'uri' => '/manage/siteopts.bml', },
|
||||
{ 'name' => 'Sitemap',
|
||||
'uri' => '/site/', },
|
||||
{ 'name' => BML::ml('ljrlook.nav.paidaccounts'),
|
||||
'uri' => '/paidaccounts/',
|
||||
# 'recursematch' => '^/paidaccounts/',
|
||||
# 'children' => [
|
||||
# { 'name' => 'Is this safe?',
|
||||
# 'uri' => '/paidaccounts/whysafe.bml', },
|
||||
# { 'name' => 'Progress',
|
||||
# 'uri' => '/paidaccounts/progress.bml', },
|
||||
# ],
|
||||
},
|
||||
{ 'name' => BML::ml('ljrlook.nav.ljfif'),
|
||||
'uri' => '/users/ljr_fif/friends', },
|
||||
# { 'name' => 'To-Do list',
|
||||
# 'uri' => '/todo.bml', },
|
||||
# { 'name' => 'Contributors',
|
||||
# 'uri' => '/contributors.bml', },
|
||||
],
|
||||
},
|
||||
# { 'name' => 'Find Users',
|
||||
# 'children' => [
|
||||
# { 'name' => 'Random!',
|
||||
# 'uri' => '/random.bml', },
|
||||
# { 'name' => 'By Region',
|
||||
# 'uri' => '/directory.bml', },
|
||||
# { 'name' => 'By Interest',
|
||||
# 'uri' => '/interests.bml', },
|
||||
# { 'name' => 'Search',
|
||||
# 'uri' => '/directorysearch.bml', }
|
||||
# ], },
|
||||
{ 'name' => BML::ml('ljrlook.nav.edit'),
|
||||
'children' => [
|
||||
{ 'name' => BML::ml('ljrlook.nav.editinfo'),
|
||||
'uri' => '/editinfo.bml', },
|
||||
# { 'name' => 'Settings', cont => 1,
|
||||
# 'uri' => '/editinfo.bml', },
|
||||
{ 'name' => BML::ml('ljrlook.nav.editfriends'),
|
||||
'uri' => '/friends/edit.bml', },
|
||||
{ 'name' => BML::ml('ljrlook.nav.editjournal'),
|
||||
'uri' => '/editjournal.bml', },
|
||||
{ 'name' => BML::ml('ljrlook.nav.editpics'),
|
||||
'uri' => '/editpics.bml', },
|
||||
{ 'name' => BML::ml('ljrlook.nav.changepassword'),
|
||||
'uri' => '/changepassword.bml', },
|
||||
{ 'name' => BML::ml('ljrlook.nav.modify'),
|
||||
'uri' => '/modify.bml', },
|
||||
# { 'name' => 'Import',
|
||||
# 'uri' => '/import.bml' },
|
||||
],
|
||||
},
|
||||
{ 'name' => BML::ml('ljrlook.nav.communities.manage'),
|
||||
'uri' => '/community/manage.bml'
|
||||
},
|
||||
# { 'name' => 'Developer Area',
|
||||
# 'uri' => '/developer/',
|
||||
# 'match' => "^/developer/\$",
|
||||
# 'recursematch' => "^/developer/",
|
||||
# 'children' => [
|
||||
# { 'name' => 'Style System',
|
||||
# 'uri' => '/developer/styles.bml',
|
||||
# 'children' => [
|
||||
# { 'name' => 'View Types',
|
||||
# 'uri' => '/developer/views.bml', },
|
||||
# { 'name' => 'Variable List',
|
||||
# 'uri' => '/developer/varlist.bml', },
|
||||
# ],
|
||||
# },
|
||||
# { 'name' => 'Embedding',
|
||||
# 'uri' => '/developer/embedding.bml', },
|
||||
# { 'name' => 'Protocol',
|
||||
# 'uri' => '/developer/protocol.bml',
|
||||
# 'children' => [
|
||||
# { 'name' => 'Mode List',
|
||||
# 'uri' => '/developer/modelist.bml', }
|
||||
# ],
|
||||
# },
|
||||
# ],
|
||||
# },
|
||||
# { 'name' => BML::ml('ljrlook.nav.frills'),#Styles,customization
|
||||
# 'children' => [
|
||||
{ 'name' => BML::ml('ljrlook.nav.customize'),
|
||||
'uri' => '/customize/', },
|
||||
# { 'name' => BML::ml('ljrlook.nav.createstyle'),
|
||||
# 'uri' => '/createstyle.bml', },
|
||||
# { 'name' => BML::ml('ljrlook.nav.editstyle'),
|
||||
# 'uri' => '/editstyle.bml', },
|
||||
# ],
|
||||
# },
|
||||
{ 'name' => BML::ml('ljrlook.nav.needhelp'),
|
||||
'children' => [
|
||||
{ 'name' => BML::ml('ljrlook.nav.lostinfo'),
|
||||
'uri' => '/lostinfo.bml', },
|
||||
{ 'name' => BML::ml('ljrlook.nav.support.faq'),
|
||||
'uri' => '/support/faq.bml', },
|
||||
# { 'name' => 'Questions',
|
||||
# 'uri' => '/support/faq.bml', cont => 1, },
|
||||
{ 'name' => BML::ml('ljrlook.nav.support'),
|
||||
'uri' => '/support/', },
|
||||
],
|
||||
},
|
||||
);
|
||||
|
||||
my $remote = LJ::get_remote();
|
||||
my $remuser = $remote ? $remote->{'user'} : "";
|
||||
my $hello_name = $remote ? LJ::User::display_name($remote) : "";
|
||||
my $uri = BML::get_uri();
|
||||
if ($remuser ne "" && $uri ne "/logout.bml")
|
||||
{
|
||||
my $subdomain = $remuser;
|
||||
$subdomain =~ s/_/-/g;
|
||||
unshift @sidebar, { 'name' => BML::ml('ljrlook.nav.hello').", ".$hello_name."!",
|
||||
'children' => [
|
||||
{ 'name' => BML::ml('ljrlook.nav.yourjournal'),
|
||||
'children' => [
|
||||
{ 'name' => BML::ml('ljrlook.nav.recent'),
|
||||
'uri' => "/users/$remuser/", },
|
||||
{ 'name' => BML::ml('ljrlook.nav.calendar'),
|
||||
'uri' => "/users/$remuser/calendar", },
|
||||
{ 'name' => BML::ml('ljrlook.nav.friends'),
|
||||
'uri' => "/users/$remuser/friends",
|
||||
'extra' => "/friendsfilter.bml",
|
||||
},
|
||||
],
|
||||
},
|
||||
{ 'name' => BML::ml('ljrlook.nav.userinfo'),
|
||||
'uri' => "/userinfo.bml?user=$remuser", },
|
||||
{ 'name' => BML::ml('ljrlook.nav.memories'),
|
||||
'uri' => "/memories.bml?user=$remuser", },
|
||||
{ 'name' => BML::ml('ljrlook.nav.logout'),
|
||||
'uri' => '/logout.bml', },
|
||||
]
|
||||
};
|
||||
} elsif ($uri ne "/login.bml") {
|
||||
unshift @sidebar, { 'name' => BML::ml('ljrlook.nav.login'),,
|
||||
'uri' => '/login.bml', }
|
||||
}
|
||||
|
||||
return "";
|
||||
_code?>
|
||||
<=LOAD_PAGE_INFO
|
||||
|
||||
AL=>{P}<i><a href="%%data1%%">%%data2%%</a></i> <img src="/img/external_link.gif" width='16' height='11' align='absmiddle' />
|
||||
AWAYLINK=>{P}<i><a href="%%data1%%">%%data2%%</a></i> <img src="/img/external_link.gif" width='16' height='11' align='absmiddle' />
|
||||
|
||||
H1=>{D}<h1>%%data%%</h1>
|
||||
H2=>{D}<h2>%%data%%</h2>
|
||||
|
||||
# Banner Header: search results banner, content desriptor, etc...
|
||||
BH=>{D}<p align='center'><font face="Arial,Helvetica" color="#CC0000" size='-1'><b>%%data%%</b></font>
|
||||
|
||||
GRIN=>{S}<grin>
|
||||
HR=>{S}<hr />
|
||||
|
||||
NEWLINE=>{S}<BR>
|
||||
P=>{D}<P>%%data%%</P>
|
||||
|
||||
STANDOUT<=
|
||||
{D}<blockquote>
|
||||
<hr />
|
||||
%%data%%
|
||||
<hr />
|
||||
</blockquote>
|
||||
<=STANDOUT
|
||||
|
||||
ERRORBAR<=
|
||||
{D}<blockquote>
|
||||
<hr />
|
||||
%%data%%
|
||||
<hr />
|
||||
</blockquote>
|
||||
<=ERRORBAR
|
||||
|
||||
WARNINGBAR<=
|
||||
{D}<blockquote>
|
||||
<hr />
|
||||
%%data%%
|
||||
<hr />
|
||||
</blockquote>
|
||||
<=WARNINGBAR
|
||||
|
||||
BADCONTENT<=
|
||||
<?h1 <?_ml Error _ml?> h1?>
|
||||
<?p <?_ml bml.badcontent.body _ml?> p?>
|
||||
<=BADCONTENT
|
||||
|
||||
DE<=
|
||||
%%data%%
|
||||
<=DE
|
||||
|
||||
EMCOLOR=>{S}#c0c0c0
|
||||
HOTCOLOR=>{S}#ff0000
|
||||
EMCOLORLITE=>{S}#e2e2e2
|
||||
ALTCOLOR1=>{S}#eeeeee
|
||||
ALTCOLOR2=>{S}#dddddd
|
||||
screenedbarcolor=>{S}#d0d0d0
|
||||
|
||||
CHOICE=>{P}<dt><a href="%%data2%%"><font size="+1"><tt><b>%%data1%%</b></tt></font></a><dd><font size="2">%%data3%%</font>
|
||||
|
||||
CHOICES<=
|
||||
{F}<table width="100%" cellpadding="2" cellspacing="5">
|
||||
<tr>
|
||||
<td valign='top' width="50%">
|
||||
<dl>
|
||||
%%items%%
|
||||
</dl>
|
||||
</td>
|
||||
<td valign='top' width="50%">
|
||||
<dl>
|
||||
%%itemsb%%
|
||||
</dl>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<=CHOICES
|
||||
|
||||
PAGE<=
|
||||
{Fp}<html>
|
||||
<head><title>%%title%%</title>%%head%%</head>
|
||||
<body %%bodyopts%%>
|
||||
%%body%%
|
||||
</body>
|
||||
</html>
|
||||
<=PAGE
|
||||
|
||||
BREADCRUMBS<=
|
||||
{Fp}<?_code
|
||||
# where are we
|
||||
my @crumbs = LJ::get_crumb_path();
|
||||
return unless @crumbs;
|
||||
my @ret;
|
||||
my $count = 0;
|
||||
foreach my $crumb (@crumbs) {
|
||||
# put crumbs together
|
||||
next unless $crumb->[3]; # no blank crumbs
|
||||
if ($crumb->[3] eq 'dynamic') {
|
||||
# dynamic
|
||||
unshift @ret, "<b>$crumb->[0]</b>";
|
||||
$count++;
|
||||
} else {
|
||||
# non-dynamic
|
||||
unshift @ret, $count++ == 0 ?
|
||||
"<b>$ML{'crumb.'.$crumb->[3]}</b>" :
|
||||
$crumb->[1] ne '' ?
|
||||
"<a href=\"$crumb->[1]\">$ML{'crumb.'.$crumb->[3]}</a>" :
|
||||
"$ML{'crumb.'.$crumb->[3]}";
|
||||
}
|
||||
}
|
||||
return "<div id='ljbreadcrumbs'>" . join(" : ", @ret) . "</div>";
|
||||
_code?>
|
||||
<=BREADCRUMBS
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user