body<= "; } return "" if $u->{'statusvis'} eq "S"; if (LJ::did_post() && $POST{'userid'} != $u->{'userid'}) { return ""; } my $error = sub { return " '/syn/', 'text' => $ML{'.back'}}) . " p?>"; }; # add custom feed if ($POST{'action:addcustom'} || $GET{'url'}) { unless (LJ::check_priv($u, 'syn_edit')) { if ($LJ::LJR_SYNS_PERDAY) { my $today_syns = $dbh->selectrow_array( "select count(*) from user,userusage where timecreate > date_sub(now(), interval 24 hour) and " . "user.userid=userusage.userid and journaltype = 'Y'", undef); if ($today_syns >= $LJ::LJR_SYNS_PERDAY) { return "

Too much syndications for today. Sorry."; } } if ($LJ::LJR_SYNS_PERUSER) { my $today_syns = $dbh->selectrow_array( "select count(*) from syndicated,userusage where creatorid = ? and " . "userusage.userid=syndicated.userid and timecreate > date_sub(now(), interval 24 hour)", undef, $u->{'userid'}); if ($today_syns >= $LJ::LJR_SYNS_PERUSER) { return "

Too much syndications for today. Sorry."; } } if ($LJ::LJR_SYNS_PERWEEK_PERUSER) { my $thisweek_syns = $dbh->selectrow_array( "select count(*) from syndicated,userusage where creatorid = ? and " . "userusage.userid=syndicated.userid and timecreate > date_sub(now(), interval 24*7 hour)", undef, $u->{'userid'}); if ($thisweek_syns >= $LJ::LJR_SYNS_PERWEEK_PERUSER) { return "

Too much syndications for this week. Sorry."; } } } my $acct = LJ::trim($POST{'acct'}); my $url = LJ::trim($POST{'synurl'} || $GET{'url'}); my $pfx = "syn_"; if ($acct ne "") { return $error->($ML{'.invalid.accountname'}) if $acct && $acct !~ /^\w{3,15}$/; # foreach my $re ("^system\$", @LJ::PROTECTED_USERNAMES) { # next unless ($acct =~ /$re/); # return $error->($ML{'.invalid.reserved'}); # } } if ($url ne "") { return $error->($ML{'.invalid.url'}) unless $url =~ m!^http://(.+?)(?::(\d+))?!; my $hostname = $1; my $port = $2; return $error->($ML{'.invalid.cantadd'}) if $hostname =~ /\Q$LJ::DOMAIN\E/i; return $error->($ML{'.invalid.port'}) if defined $port && $port != 80 && $port < 1024; $url =~ s/:80// if $port == 80; } my $su; # account to add if ($url) { while (1) { $su = $dbh->selectrow_hashref( "SELECT u.user, s.* FROM syndicated s, useridmap u ". "WHERE s.synurl=? AND s.userid=u.userid", undef, $url); unless ($su) { my $orig_url = $url; if ($url =~ /(.*)\/$/) { $url = $1; } else { $url .= "/"; } $su = $dbh->selectrow_hashref( "SELECT u.user, s.* FROM syndicated s, useridmap u ". "WHERE s.synurl=? AND s.userid=u.userid", undef, $url); $url = $orig_url unless $su; } unless ($su) { # check cap to create new feeds return $error->($ML{'.error.nocreate'}) unless LJ::get_cap($u, 'synd_create'); # create a safeagent to fetch the feed for validation purposes require LWPx::ParanoidAgent; my $ua = LWPx::ParanoidAgent->new(timeout => 30, max_size => (1024 * 500)); $ua->agent("$LJ::SITENAME ($LJ::ADMIN_EMAIL; Initial check)"); my $res = $ua->get($url); my $content = $res && $res->is_success ? $res->content : undef; return "" unless $content; # if we've been redirected -- start from scratch if ($ua->{'final_url'}) { $url = $ua->{'final_url'}; next; } # Start out with the syn_url being equal to the url # they entered of the resource. If we end up parsing # the resource and finding it has a link to the real # feed, we then want to save the real feed address # to suck from. my $syn_url = $url; my $syn_chosen; # analyze link/meta tags while ($content =~ m!<(link|meta)\b([^>]+)>!g) { my ($type, $val) = ($1, $2); # RSS/Atom # if ($syn_chosen ne "rss" && $type eq "link" && $val =~ m!rel=.alternate.!i && $val =~ m!type=.application/(?:rss|atom)\+xml.!i && $val =~ m!href=[\"\']([^\"\']+)[\"\']!i) { $syn_url = $1; $val =~ m!type=.application/(rss|atom)\+xml.!i; $syn_chosen = $1; } } # Did we find a link to the real feed? If so, start again if ($syn_url ne $url) { $url = $syn_url; next; } # check whatever we did get for validity (or pseudo-validity) return "" unless $content =~ m/<(\w+:)?(?:rss|feed|RDF)/; # Must have a <[?:]rss <[?:]feed (for Atom support) <[?:]RDF my $ljuname; if ( $url =~ m!^http://users.livejournal.com/(.+?)(/|$)! || $url =~ m!^http://community.livejournal.com/(.+?)(/|$)! || $url =~ m!^http://(.+?).livejournal.com! ) { $ljuname = $1; if (length($ljuname) < 13) { $acct = $ljuname; $pfx = "lj_"; } } # if no account name, give them a proper entry form to pick one, but don't reprompt # for the url, just pass that through (we'll recheck it anyway, though) unless ($acct) { my $ret .= ""; $ret .= "

$url

"; $ret .= "
"; $ret .= LJ::html_hidden("userid", $u->{'userid'}, 'synurl', $url); $ret .= "
"; $ret .= "

$ML{'.account'} $pfx"; $ret .= "

"; $ret .= "

"; return $ret; } return "" unless $acct; my $id; my $tu = LJ::load_user($pfx . $acct); if ($tu) { if ($tu->{'statusvis'} == "X") { $id = $tu->{'userid'}; } else { return $error->($ML{'.invalid.inuse.text'}); } } else { # create the feed account $id = LJ::create_account({ 'user' => $pfx . $acct, 'name' => $pfx . $acct, 'password' => '', 'caps' => $LJ::SYND_CAPS, 'cluster' => $LJ::SYND_CLUSTER, }); } return "" unless $id; if ($LJ::LJR_SYN) { my $ljr_syn_id = LJ::get_userid($LJ::LJR_SYN); if ($ljr_syn_id) { $dbh->do("INSERT INTO friends (userid, friendid) VALUES (?, ?)", undef, $ljr_syn_id, $id); } } LJ::update_user($id, { journaltype => 'Y', statusvis => 'V' }); $dbh->do("INSERT INTO syndicated (userid, synurl, checknext, creatorid) VALUES (?,?,NOW(),?)", undef, $id, $syn_url, $u->{'userid'}); LJ::statushistory_add($u->{'userid'}, $id, "synd_create", "acct: $acct"); $su = $dbh->selectrow_hashref("SELECT u.user, s.* FROM syndicated s, useridmap u ". "WHERE s.userid=? AND s.userid=u.userid", undef, $id); # my $suu = LJ::load_userid($id); # LJ::set_userprop($suu, "urlname", ); } last; } # while } elsif ($acct) { # account but no URL, we can add this in any case $su = $dbh->selectrow_hashref("SELECT u.user, s.* FROM syndicated s, useridmap u ". "WHERE u.userid=s.userid AND u.user=?", undef, $acct); unless ($su) { return $error->($ML{'.invalid.notexist'}); } } else { # need at least a URL return $error->($ML{'.invalid.needurl'}); } return $error->($ML{'.error.unknown'}) unless $su; # at this point, we have a new account, or an old account, but we have an account, so # let's redirect them to the add page return BML::redirect("$LJ::SITEROOT/friends/add.bml?user=$su->{user}"); } # get most popular feeds from memcache my $popsyn = LJ::Syn::get_popular_feeds(); # load user's friends so we can strip feeds they already watch my $friends = LJ::get_friends($u) || {}; # populate @pop and add users they've chosen to add my @pop; my %urls; my %names; for (0 .. 99) { next if not defined $popsyn->[$_]; my ($user, $name, $suserid, $url, $count) = @{ $popsyn->[$_] }; $names{$user} = $name; my $suser = LJ::load_userid($suserid); LJ::load_user_props($suser, 'url'); $urls{$user} = $suser->{url}; # skip suspended/deleted accounts, already watched feeds next if $friends->{$suserid} || $suser->{'statusvis'} ne "V"; if ($POST{'action:add'} && $POST{"add_$user"}) { LJ::add_friend($u->{'userid'}, $suserid, { 'defaultview' => 1 }); } else { push @pop, [ $user, $url, $count ]; last if @pop >= 20; } } # intro paragraph my $title = BML::ml('.using.title', {'sitename' => $LJ::SITENAME}); my $ret = ""; $ret .= "
"; $ret .= LJ::html_hidden("userid", $u->{'userid'}); if (@pop) { $ret .= ""; $ret .= "

"; $ret .= ""; $ret .= ""; foreach (@pop) { my ($user, $url, $count) = @$_; $ret .= ""; $ret .= ""; $ret .= ""; } else { $ret .= "$names{$user}"; } $ret .= ""; $ret .= ""; $ret .= ""; } $ret .= ""; $ret .= "
$ML{'.table.account'}$ML{'.table.feed'}$ML{'.table.watchers'}
"; $ret .= LJ::ljuser($user, { 'type' => 'Y' }) . ""; if ($urls{$user}) { my $displayurl = $urls{$user}; $displayurl = substr($urls{$user}, 0, 50) . "..." if length $displayurl > 60; $ret .= "$names{$user}
$displayurl
" . LJ::img('xml', '', { border => 0 }) . "$count
"; $ret .= ""; $ret .= "
"; } $ret .= "

"; $ret .= LJ::html_hidden("userid", $u->{'userid'}); $ret .= ""; $ret .= "
"; $ret .= "

$ML{'.feed.url'} "; $ret .= "

"; $ret .= "

"; $ret .= "
"; return $ret; } _code?> <=body page?>