ljr/livejournal/htdocs/userinfo.bml

1060 lines
43 KiB
Plaintext
Executable File

<?_code
#line 2
use strict;
use vars qw($title $windowtitle $body $head $bml_okay %GET);
$bml_okay = 1;
$title = $ML{'.title'};
$body = "";
$head = "";
$windowtitle = "";
# Deal with bots
my $sep = "**";
my $pre = "<!-- \n" . ($sep x 40 . "\n") x 2 . "$sep\n" x 10 . $sep;
my $post = "\n" . "$sep\n" x 10 . ($sep x 40 . "\n") x 2 . " -->";
$body .= LJ::run_hook("bot_director", $pre, $post);
if ($LJ::SERVER_DOWN) {
$title = $ML{'Sorry'};
$body = LJ::server_down_html();
return;
}
my $MAX_FRIENDS_SHOW = 500;
my $MAX_FRIENDOF_SHOW = 150;
my $remote = LJ::get_remote();
if ($GET{'user'} eq "" && !$remote) {
$body = "<?h1 $ML{'Error'} h1?><?p $ML{'.error.notloggedin'} p?>";
return;
}
my $sth;
my %countries = ();
my %states = ();
LJ::load_codes({ "country" => \%countries, "state" => \%states });
my $error = sub {
my $e = shift;
$body = "<?h1 $ML{'Error'} h1?><?p $e p?>";
return;
};
my $user = LJ::canonical_username($GET{'user'});
if ($GET{'user'} && ! $user) {
$body = $ML{'.error.malfname'};
return;
}
if ($user eq "" && $remote) {
$user = $remote->{'user'};
}
my $dbr = LJ::get_db_reader();
return $error->($ML{'error.nodb'}) unless $dbr;
my $userid = $GET{'userid'};
my $u;
$userid += 0;
{
if ($userid) {
$u = LJ::load_userid($userid);
} else {
$u = LJ::load_user($user);
}
return $error->($ML{'.label.reqfinduser'})
if $userid && ! LJ::check_priv($remote, "finduser") && ! ($GET{t} eq "I" && $u && $u->{journaltype} eq "I");
# fix accidentally broken ext_nnnn URLs for identity users
if ($u->{journaltype} eq "I" && ! $userid) {
return BML::redirect("$LJ::SITEROOT/userinfo.bml?userid=$u->{'userid'}&t=I");
}
$user = $u->{'user'} if $u;
$userid = $u->{'userid'}+0 if $u;
LJ::text_out(\$u->{'name'}) if $u;
if ($u && ($GET{'mode'} eq "full" || $u->{'journaltype'} eq "Y")) {
$sth = $dbr->prepare("SELECT timeupdate, timecreate, ".
"UNIX_TIMESTAMP()-UNIX_TIMESTAMP(timeupdate) ".
"AS 'secondsold' FROM userusage ".
"WHERE userid=$userid");
$sth->execute;
($u->{'timeupdate'},
$u->{'timecreate'},
$u->{'secondsold'}) = $sth->fetchrow_array;
}
}
unless ($u) {
$title = $ML{'Error'};
$body = "<?h1 $ML{'.nonexist.name'} h1?><?p " . BML::ml('.nonexist.body',{'user'=>$user}) . " p?>";
return;
}
# account purged?
if ($u->{'statusvis'} eq "X") {
$title = $ML{'error.purged.title'};
$body = "<?h1 $ML{'error.purged.name'} h1?><?p $ML{'error.purged.text'} p?>";
BML::set_status(410); # 410 Gone
return;
}
my $dbcr = LJ::get_cluster_reader($u);
return $error->($ML{'error.nodb'}) unless $dbcr;
# option
my %hide_fo; # userid -> 1
if ($LJ::HIDE_FRIENDOF_VIA_BAN) {
if (my $list = LJ::load_rel_user($u, 'B')) {
$hide_fo{$_} = 1 foreach @$list;
}
}
my $remote_isowner = $remote && $remote->{'user'} eq $u->{'user'};
my $remote_isfriend = LJ::is_friend($u, $remote);
my $com = $u->{'journaltype'} eq "C" ? 1 : 0;
my $extid = $u->{'journaltype'} eq "I" ? $u->identity : undef;
my $synd;
if ($u->{'journaltype'} eq "Y") {
$synd = $dbr->selectrow_hashref("SELECT * FROM syndicated WHERE userid=$u->{'userid'}");
}
my $dir = "users";
### load user props. some don't apply to communities
{
my @props = qw(opt_whatemailshow country state city zip renamedto
journaltitle journalsubtitle public_key
url urlname opt_hidefriendofs dont_load_members
opt_showmutualfriends fb_num_pubpics);
unless ($com || $synd) { push @props, qw(aolim icq yahoo msn gender jabber); }
if ($synd) { push @props, qw(rssparseerror); }
if ($u->{'statusvis'} eq 'V') { push @props, qw(opt_blockrobots); }
LJ::run_hooks('userinfo_local_props', {
'props' => \@props
});
LJ::load_user_props($u, @props);
}
if ($u->{'statusvis'} ne 'V' || $u->{'opt_blockrobots'}) {
$head .= LJ::robot_meta_tags();
}
if ($u->{'journaltype'} eq "R" && $u->{'renamedto'}) {
my $extra = $GET{'mode'} eq 'full' ? "&mode=full" : '';
return BML::redirect("$LJ::SITEROOT/userinfo.bml?user=$u->{'renamedto'}$extra");
}
my %friends = ('load'=>1, 'loaded'=>0, 'display'=>1, 'count'=>0);
my %friendsof = ('load'=>1, 'loaded'=>0, 'display'=>1, 'count'=>0);
if ($com) {
$title = $ML{'.title.communityinfo'};
$dir = "community";
} elsif ($synd) {
$title = $ML{'.title.syndicated'};
$u->{'opt_whatemailshow'} = "N"; # don't show email
$friends{'load'} = $friends{'display'} = 0;
}
if ($extid) {
$windowtitle = "External identity profile";
} else {
$windowtitle = "$u->{'user'} - $title";
}
$friends{'load'} = $friendsof{'load'} = 0 if $com && $u->{'dont_load_members'};
# do they have the viewall priv?
# there are no entries on this page, so we just check if they have any viewall, so viewsome
# applies here too. we can't see info they've hidden anyway, but we can see the page.
my $viewall = 0;
if ($GET{'viewall'} && LJ::check_priv($remote, "canview")) {
$viewall = LJ::check_priv($remote, 'canview', '*');
LJ::statushistory_add($u->{'userid'}, $remote->{'userid'},
"viewall", "userinfo: $u->{'user'}, statusvis: $u->{'statusvis'}");
} else {
if ($u->{'statusvis'} eq "S") {
$title = $ML{'error.suspended.title'};
$body = "<?h1 $ML{'error.suspended.name'} h1?><?p " .
BML::ml('error.suspended.text', { 'user' => LJ::ljuser($user),
'sitename' => $LJ::SITENAME }) . " p?>";
BML::set_status(403); # 403 Forbidden
return;
}
if ($u->{'statusvis'} eq "D") {
$title = $ML{'error.deleted.title'};
$body = "<?h1 $ML{'error.deleted.name'} h1?><?p " .
BML::ml('error.deleted.text',{'user'=>$user}) . " p?>";
BML::set_status(404); # 404 Not Found
return;
}
}
$user = $u->{'user'};
$userid = $u->{'userid'};
$u->{'bio'} = LJ::get_bio($u);
LJ::text_out(\$u->{'bio'});
# arrayref of interests rows: [ intid, intname, intcount ]
my $intu = LJ::get_interests($u);
my %remote_interest;
if ($remote && $remote->{'userid'} != $userid) {
if (my $rint = LJ::get_interests($remote, { justids => 1 })) {
$remote_interest{$_} = 1 foreach @$rint;
}
}
if ($u->{'opt_hidefriendofs'} && ! $remote_isowner) {
# at this point, load should be on if viewall is on or if the user
# wants to show their mutual friends
$friendsof{'load'} = $u->{'opt_showmutualfriends'} || $viewall;
$friendsof{'display'} = $viewall;
}
# Add metadata links to <head>
my $digest = Digest::SHA1::sha1_hex('mailto:' . $u->{'email'});
$head .= "<link rel='alternate' type='application/rss+xml' title='RSS' href='$LJ::SITEROOT/$dir/$user/data/rss' />\n";
$head .= "<link rel='alternate' type='application/atom+xml' title='Atom' href='$LJ::SITEROOT/$dir/$user/data/atom' />\n";
$head .= "<link rel='alternate' type='application/rdf+xml' title='FOAF' href='$LJ::SITEROOT/$dir/$user/data/foaf' />\n";
$head .= "<meta name=\"foaf:maker\" content=\"foaf:mbox_sha1sum '$digest'\" />\n";
my @friends;
my $fr_res;
my %fr;
# TAG:FR:userinfo:loadfriends
if ($friends{'load'}) {
$fr_res = LJ::get_friends($u);
my @ids = keys %$fr_res;
$friends{'count'} = @ids;
if (@ids > $MAX_FRIENDS_SHOW) {
@ids = splice(@ids, 0, $MAX_FRIENDS_SHOW);
}
LJ::load_userids_multiple([ map { $_ => \$fr{$_} } @ids ]);
push @friends, sort { $a->{user} cmp $b->{user} } values %fr;
$friends{'loaded'} = 1;
}
my (@friend_of, @member_of, @mutual);
# TAG:FR:userinfo:loadfriendofs
if ($friendsof{'load'}) {
# figure at most 50 people are not statusvis='V' *shrug* (this is lame pending the friend changes)
my @ids = grep { ! $hide_fo{$_} } LJ::get_friendofs($u);
$friendsof{'load_clipped'} = @ids > $LJ::MAX_FRIENDOF_LOAD;
my %fro;
LJ::load_userids_multiple([ map { $_ => \$fro{$_} } @ids ]);
foreach my $ulocal (sort { $a->{'user'} cmp $b->{'user'} } values %fro) {
next unless $ulocal->{'statusvis'} eq 'V';
if ($ulocal->{'journaltype'} eq 'P' || $ulocal->{'journaltype'} eq "I") {
if (!$com && $u->{'opt_showmutualfriends'} && $fr{$ulocal->{userid}}) {
push @mutual, $ulocal;
} else {
push @friend_of, $ulocal;
}
} else {
push @member_of, $ulocal; # 'S' or 'C' (shared or community)
}
}
$friendsof{'count'} = scalar @friend_of;
$friendsof{'count_m'} = scalar @member_of;
$friendsof{'count_b'} = scalar @mutual;
$friendsof{'loaded'} = 1;
}
$u->{'name'} = LJ::ehtml($u->{'name'});
# TAG:FR:userinfo:remotefriends
# who does the remote user list as a friend?
my %remote_friendid;
if ($remote && $friends{'loaded'}) {
if ($remote->{'userid'} == $u->{'userid'}) {
foreach (@friends) { $remote_friendid{$_->{'userid'}} = 1; }
} else {
my $frs = LJ::get_friends($remote) || {};
$remote_friendid{$_} = 1 while $_ = each %$frs;
}
}
# BML helpers. we do BML by hand in this page, so we don't force BML
# to evaluate this huge page looking for non-existent BML. this
# makes it quicker, and prevents us from having to clean out BML in
# the HTML cleaner too.
my $h1 = sub {
return BML::fill_template("h1", { DATA => $_[0] });
};
my $p = sub {
return BML::fill_template("p", { DATA => $_[0] });
};
if ($com) {
$body .= $h1->($ML{'.comminfo.name'});
my $pt = BML::ml('.comminfo.body',{'commname'=>$u->{'name'}}) . " ";
my $userinfo_join_community;
LJ::run_hooks("userinfo_join_community", {
'u' => $u,
'ret' => \$userinfo_join_community,
});
$pt .= $userinfo_join_community ? $userinfo_join_community : BML::ml('.membership.body',{'commname'=>$u->{'user'}});
$pt .= BML::ml('.body.leave',{'commname'=>$u->{'user'}});
$body .= $p->($pt);
} elsif ($synd) {
$body .= $h1->($ML{'.syndinfo.name'}) . $p->(BML::ml('.syndinfo.body', {
'addtofriends' => "$LJ::SITEROOT/friends/add.bml?user=$u->{'user'}",
}));
} elsif ($extid) {
if ($extid->[0] eq "O") {
$body .= $h1->("OpenID user");
$body .= $p->("This is a non-$LJ::SITENAME user that's using their external identity to log in to $LJ::SITENAME using <a href='/openid'>OpenID</a> in order to leave authenticated comments and read friends-only entries.");
}
} else {
$body .= $h1->($ML{'.userinfo.name'}) . $p->(BML::ml('.userinfo.body', {
'username' => $u->{'name'}, 'siteroot'=>$LJ::SITEROOT,
}));
}
## standout bar
{
my @linkele;
my $label = $com ? $ML{'.monitor.comm'} : $ML{'.monitor.user'};
push @linkele, "<a href='/friends/add.bml?user=$user'><img src='$LJ::IMGPREFIX/btn_addfriend.gif' width='22' height='20' alt='$label' title='$label' align='middle' border='0' /></a>";
if (LJ::can_use_journal($remote->{'userid'}, $user) && !$extid) {
if($remote_isowner) {
$label = $ML{'.label.postalt'};
} else {
$label = BML::ml('.label.post', {'journal' => $user});
}
$label = LJ::ehtml("$label");
push @linkele, "<a href='/update.bml?usejournal=$user'><img src='$LJ::IMGPREFIX/btn_edit.gif' width='22' height='20' alt='$label' title='$label' align='middle' border='0' /></a>";
}
$label = $ML{'.label.todo'};
push @linkele, "<a href='/todo/?user=$user'><img src='$LJ::IMGPREFIX/btn_todo.gif' width='22' height='20' alt='$label' title='$label' align='middle' border='0' /></a>" unless $extid;
$label = $ML{'.label.memories'};
push @linkele, "<a href='/tools/memories.bml?user=$user'><img src='$LJ::IMGPREFIX/btn_memories.gif' width='22' height='20' alt='$label' title='$label' align='middle' border='0' /></a>" unless $extid;
unless ($LJ::DISABLED{'tellafriend'} || $extid) {
push @linkele, "<a href='/tools/tellafriend.bml?user=$u->{'user'}'><img align='middle' hspace='2' vspace='2' src='$LJ::IMGPREFIX/btn_tellfriend.gif' width='22' height='20' alt='$ML{'.tellafriend'}' title='$ML{'.tellafriend'}' border='0' /></a>";
}
unless ($LJ::DISABLED{'feedster_search'} || $extid) {
push @linkele, "<a href='/tools/search.bml?journal=$u->{'user'}'><img align='middle' hspace='2' vspace='2' src='$LJ::IMGPREFIX/btn_search.gif' width='22' height='20' alt='$ML{'.label.searchjournal'}' title='$ML{'.label.searchjournal'}' border='0' /></a>";
}
if (@linkele) {
$body .= BML::fill_template("standout", {
DATA => join("&nbsp;&nbsp;", @linkele),
});
}
}
$body .= "<table cellpadding='5' width='100%' border='0'>";
{
my $hook_extra;
LJ::run_hooks("userinfo_html_by_user", {
'u' => $u,
'ret' => \$hook_extra,
});
if ($u->{journaltype} eq "I") {
$body .= "<tr valign='top'><td align='right'><b>OpenID:</b></td><td width='100%'>" . LJ::ljuser($u) . "</td>";
} else {
$body .= "<tr valign='top'><td align='right'><b>$ML{'.label.user'}</b></td><td width='100%'><a href='/$dir/$user/'><b>$user</b></a> ($u->{'userid'}) $hook_extra ";
if ($u->{public_key}) {
$body .= "<a href='/pubkey.bml?user=$user'>";
$body .= "<img src='/img/key.gif' width='16' height='16' border='0' alt='View public key' title='View public key' style='vertical-align: middle; border: 0;' /></a>";
}
$body .= "</td>\n";
}
}
### picture
my $narrow_left = 2; ## rows with smaller colspan to 2
$body .= "<td align='right' rowspan='3'>";
if ($u->{'defaultpicid'}) {
my $picid = $u->{'defaultpicid'};
my %pic;
LJ::load_userpics(\%pic, [ $u, $picid ]);
$body .= "<a href='/allpics.bml?user=$user'><img src='$LJ::USERPIC_ROOT/$picid/$userid' width='$pic{$picid}->{'width'}' height='$pic{$picid}->{'height'}' vspace='3' border='0' alt='$user' /></a>";
} else {
$body .= "&nbsp;";
}
$body .= "</td>";
### /picture
$body .= "</tr>\n";
## journal title
if ($u->{'journaltitle'}) {
my $span = ($narrow_left-- >= 0) ? 1 : 2;
$body .= "<tr valign='top'><td align='right'></td><td colspan='$span'>";
$body .= "<span style='font-size: 1.2em'><b>" . LJ::ehtml($u->{'journaltitle'}) . "</b>";
if ($u->{'journalsubtitle'}) {
$body .= "<br /><i>" . LJ::ehtml($u->{'journalsubtitle'}) . "</i>";
}
$body .= "</span></td></tr>\n";
}
### name or 'syndicated from'
unless ($synd) {
unless ($u->underage || $u->{'name'} eq $u->{'journaltitle'}) {
$narrow_left--;
$body .= "<tr><td align='right'><b>$ML{'.label.name'}</b></td><td>$u->{'name'}</td></tr>\n";
}
} else {
$narrow_left--;
my $link;
if (my $url = $u->{'url'}) {
$link="<a href='" . LJ::ehtml($url) . "'>$u->{'name'}</a>";
} else {
$link=$u->{'name'};
}
my $icon="<a href='" . LJ::ehtml($synd->{'synurl'}) . "'>".
"<img src='$LJ::IMGPREFIX/xml.gif' width='36' height='14' align='middle' border='0' /></a>";
$body .= "<tr valign='top'><td align='right'><b>$ML{'.label.syndicatedfrom'}</b></td>\n".
"<td>$link $icon</td></tr>\n";
# syndication status
$body .= "<tr valign='top'><td align='right'><b>$ML{'.label.syndicatedstatus'}</b></td><td>\n";
$body .= "$ML{'.syn.lastcheck'} ";
$body .= $synd->{'lastcheck'} || $ML{'.syn.last.never'};
my $status = {
'parseerror' => "Parse error",
'notmodified' => "Not Modified",
'toobig' => "Too big",
'posterror' => "Posting error",
'ok' => "", # no status line necessary
'nonew' => "", # no status line necessary
}->{$synd->{'laststatus'}};
$body .= " ($status)" if $status;
if ($synd->{'laststatus'} eq "parseerror") {
$body .= "<br />$ML{'.syn.parseerror'} " . LJ::ehtml($u->{'rssparseerror'});
}
$body .= "<br />$ML{'.syn.nextcheck'} $synd->{'checknext'}";
$body .= "</td></tr>\n";
}
## text message
if ($u->{'txtmsg_status'} eq "on" && LJ::get_cap($u, "textmessaging")) {
my $span = ($narrow_left-- >= 0) ? 1 : 2;
$body .= "<tr valign='top'><td align='right'><b>$ML{'.label.textmessage'}</b></td><td colspan='$span'>" . BML::ml('.sendmessage.body',{'user'=>$u->{'user'}, 'link'=>"/tools/textmessage.bml?user=$u->{'user'}"}) . "</td></tr>";
}
if ( ! $synd && $u->{'url'}) {
my $url = LJ::ehtml($u->{'url'});
my $span = ($narrow_left-- >= 0) ? 1 : 2;
unless ($url =~ /^https?:\/\//) {
$url =~ s/^http\W*//;
$url = "http://$url";
}
my $urlname = LJ::ehtml($u->{'urlname'} || $url);
$url = "<a href='$url'>$urlname</a>";
$body .= "<tr><td align='right'><b>$ML{'.label.website'}</b></td><td colspan='$span'>$url</td></tr>\n" if ($u->{'url'});
}
if ( ! $synd && ($u->{'allow_infoshow'} eq "Y" || $viewall)) {
if ($u->{'city'} || $u->{'state'} || $u->{'country'}) {
my $span = ($narrow_left-- >= 0) ? 1 : 2;
$body .= "<tr><td align='right'><b>$ML{'.label.location'}</b></td><td colspan='$span'>";
my $estate = LJ::eurl($u->{'state'});
my $ecity = LJ::eurl($u->{'city'});
my $ecountry = LJ::eurl($u->{'country'});
my ($state, $city, $country);
if ($u->{'country'}) {
$country = $LJ::DISABLED{'directory'} ? $countries{$u->{'country'}} :
"<a href='/directory.bml?opt_sort=ut&amp;s_loc=1&amp;loc_cn=$u->{'country'}'>".
$countries{$u->{'country'}} . "</a>";
my $estate;
if ($u->{'state'}) {
$state = $u->{'state'};
if ($u->{'country'} eq "US") { $state = $states{$state}; }
$estate = LJ::eurl($state);
$state = $LJ::DISABLED{'directory'} ? $state :
"<a href='/directory.bml?opt_sort=ut&amp;s_loc=1&amp;loc_cn=".
"$u->{'country'}&amp;loc_st=$estate'>$state</a>";
}
if ($u->{'city'}) {
my $ecity = LJ::eurl($u->{'city'});
$city = LJ::ehtml($u->{'city'});
unless ($LJ::DISABLED{'directory'}) {
$city = "<a href='/directory.bml?opt_sort=ut&amp;s_loc=1&amp;loc_cn=".
"$u->{'country'}&amp;loc_st=$estate&amp;loc_ci=$ecity'>$city</a>";
}
}
}
$body .= join(", ", grep { $_ } ($city, $state, $country));
$body .= "</td></tr>";
}
if ($u->{'bdate'} && !$com && $u->{'bdate'} ne "0000-00-00" && !$u->underage) {
my $bdate = $u->{'bdate'};
$bdate =~ s/^0000-//;
my $span = ($narrow_left-- >= 0) ? 1 : 2;
$body .= "<tr><td align='right'><b>$ML{'.label.birthdate'}</b></td><td colspan='$span'>$bdate</td></tr>\n";
}
}
if ( ! $synd && ! $u->underage && ($u->{'allow_contactshow'} eq "Y" ||
($u->{'allow_contactshow'} eq "F" && $remote_isfriend) || $viewall))
{
my $mangleaddress = sub {
my $email = shift;
my $mret = "<table cellpadding='0' cellspacing='0'><tr><td>";
for (my $i = 0; $i < length($email); $i++) {
my $letter = substr($email, $i, 1);
if ($letter eq "\@") { $letter = "</td><td align='center'><i>\@</i></td><td>"; }
$mret .= $letter;
}
$mret .= "</td></tr></table>";
return $mret;
};
# some classes of users we want to have their contact info hidden
# after so much time of activity, to prevent people from bugging
# them for their account or trying to brute force it.
my $hide_contactinfo = sub {
my $hide_after = LJ::get_cap($u, "hide_email_after");
return 0 unless $hide_after;
my $memkey = [$u->{userid}, "timeactive:$u->{userid}"];
my $active;
unless (defined($active = LJ::MemCache::get($memkey))) {
$active = $dbcr->selectrow_array("SELECT timeactive FROM clustertrack2 ".
"WHERE userid=?", undef, $u->{userid});
LJ::MemCache::set($memkey, $active, 86400);
}
return $active && (time() - $active) > $hide_after * 86400;
};
my $useremail_cap = LJ::get_cap($u, 'useremail');
unless ($u->{'opt_whatemailshow'} eq "N" ||
$u->{'journaltype'} eq "I" ||
$u->{'opt_whatemailshow'} eq "L" && ($u->{'no_mail_alias'} || ! $useremail_cap || ! $LJ::USER_EMAIL) ||
$hide_contactinfo->()) {
my $span = ($narrow_left-- >= 0) ? 1 : 2;
$body .= "<tr valign='top'><td align='right'><b>$ML{'.label.email'}</b></td><td colspan='$span'>";
my @emails = ($u->{'email'});
if ($u->{'opt_whatemailshow'} eq "L") {
@emails = ();
}
if ($LJ::USER_EMAIL && $useremail_cap) {
unless ($u->{'opt_whatemailshow'} eq "A" || $u->{'no_mail_alias'}) {
push @emails, "$u->{'user'}\@$LJ::USER_DOMAIN";
}
}
foreach my $email (@emails) {
$body .= ($u->{'opt_mangleemail'} eq "Y" || $email =~ /\@livejournal\.com$/)
? $mangleaddress->($email)
: "<a href='mailto:$email'>$email</a><br />";
}
$body .= "</td></tr>";
}
foreach my $k (qw(aolim icq yahoo msn jabber)) {
$u->{$k} = LJ::ehtml($u->{$k});
}
if ($u->{'aolim'}) {
my $qim = $u->{'aolim'};
$qim =~ s/ //g;
my $span = ($narrow_left-- >= 0) ? 1 : 2;
$body .= "<tr><td align='right'><b style='white-space: nowrap;'>$ML{'.label.aolim'}</b></td><td colspan='$span'><img alt='AIM status' src='http://big.oscar.aol.com/$qim?on_url=http://www.aol.com/aim/gr/online.gif&amp;off_url=http://www.aol.com/aim/gr/offline.gif' height='17' width='14' /> $u->{'aolim'} (<b><a href='aim:addbuddy?screenname=$qim'>$ML{'.label.addbuddy'}</a>, <a href='aim:goim?screenname=$qim&amp;message=Hello+there!+How+are+you?'>$ML{'.label.sendmessage'}</a></b>)</td></tr>\n";
}
if ($u->{'icq'}) {
my $span = ($narrow_left-- >= 0) ? 1 : 2;
$body .= "<tr><td align='right'><b>$ML{'.label.icquin'}</b></td>";
$body .= "<td colspan='$span'><img alt='ICQ status' src='http://web.icq.com/whitepages/online?icq=$u->{'icq'}&amp;img=5' height='18' width='18' /> ";
$body .= "$u->{'icq'} (<b><a href='http://wwp.icq.com/$u->{'icq'}'>";
$body .= "$ML{'.label.userprofile'}</a></b>)";
$body .= "</td></tr>\n";
}
if ($u->{'yahoo'}) {
my $span = ($narrow_left-- >= 0) ? 1 : 2;
$body .= "<tr><td align='right'><b style='white-space: nowrap;'>$ML{'.label.yahooid'}</b></td><td colspan='$span'><img alt='Yahoo status' src='http://opi.yahoo.com/online?u=$u->{'yahoo'}&amp;m=g&amp;t=0' width='12' height='12' /> <a href='http://profiles.yahoo.com/$u->{'yahoo'}'>$u->{'yahoo'}</a> (<b><a href='http://edit.yahoo.com/config/set_buddygrp?.src=&amp;.cmd=a&amp;.bg=Friends&amp;.bdl=$u->{'yahoo'}'>$ML{'.label.adduser'}</a>, <a href='http://edit.yahoo.com/config/send_webmesg?.target=$u->{'yahoo'}'>$ML{'.label.sendmessage'}</a></b>) </td></tr>\n";
}
if ($u->{'msn'}) {
my $span = ($narrow_left-- >= 0) ? 1 : 2;
my $msnname = ($u->{'opt_mangleemail'} eq "Y") ? $mangleaddress->($u->{'msn'}) : $u->{'msn'};
$body .= "<tr><td align='right'><b>$ML{'.label.msnusername'}</b></td><td colspan='$span'>$msnname</td></tr>\n";
}
if ($u->{'jabber'}) {
my $span = ($narrow_left-- >= 0) ? 1 : 2;
my $jabber = $mangleaddress->($u->{'jabber'});
$body .= "<tr><td align='right'><b>$ML{'.label.jabber'}</b></td><td colspan='$span'>$jabber</td></tr>\n";
}
}
if ($u->{'has_bio'} eq "Y") {
my $span = ($narrow_left-- > 0) ? 1 : 2;
my $label = $com ? $ML{'.about.comm'} : $ML{'.about.user'};
LJ::CleanHTML::clean_userbio(\$u->{'bio'});
$body .= "<tr><td align='right' valign='top'><b>$label</b></td><td colspan='$span'>$u->{'bio'}</td></tr>\n";
}
### memories
{
my $memcount = LJ::Memories::count($userid);
if ($memcount) {
my $span = ($narrow_left-- > 0) ? 1 : 2;
my $noun_name = $memcount == 1 ? '.memories.entry' : '.memories.entries';
my $count = BML::ml($noun_name, {'count'=>$memcount});
$body .= "<tr><td align='right' valign='top'><b>$ML{'.label.memories'}</b></td><td colspan='$span'><a href='/tools/memories.bml?user=$user'>$count</a></td></tr>\n";
}
}
### Fotobilder gallery count
{
if (LJ::get_cap($u, 'fb_account') && LJ::get_cap($u, 'fb_can_upload') && $u->{'fb_num_pubpics'}+0 > 0) {
my $span = ($narrow_left-- >= 0) ? 1 : 2;
# what we display is an estimate. to eliminate confusion on the user end, we'll display the
# estimate in a way that makes it clear it's not an exact number. rules are:
#
# * < 10 == "under 10"
# * 10..999 == "at least 150" (rounded down to nearest 10)
# * 1000+ == "at least 1500" (rounded down to nearest 100)
#
my $ct = $u->{fb_num_pubpics};
my $ct_str;
if ($ct < 10) {
$ct_str = BML::ml('.fbpictures.lessthan', { count => 10 });
} else {
my $order = $ct < 100 ? 10 : 100;
my $base = POSIX::floor($ct / $order);
$ct_str = BML::ml('.fbpictures.over', { count => $base * $order });
}
$body .= "<tr><td align='right' valign='top'><b>$ML{'.label.fbpictures'}</b></td><td colspan='$span'><a href='$LJ::FB_SITEROOT/$user/'>$ct_str</a></td></tr>\n";
}
}
if (@$intu) {
my $span = ($narrow_left-- > 0) ? 1 : 2;
$body .= "<tr><td align='right' valign='top'><b><a href='/interests.bml'>$ML{'.label.interests'}</a>:</b></td><td colspan='$span'>";
my $intcount = 0;
my $intlist = "";
foreach my $int (@$intu) {
next if $intcount++ > 150;
LJ::text_out(\$int->[1]); # 1==interest
my $eint = LJ::eurl($int->[1]);
if ($int->[2] > 1) { # 2==intcount
if ($remote_interest{$int->[0]}) { # 0==intid
$intlist .= "<b><a href='/interests.bml?int=$eint'>$int->[1]</a></b>, ";
} else {
$intlist .= "<a href='/interests.bml?int=$eint'>$int->[1]</a>, ";
}
} else {
$intlist .= "$int->[1], ";
}
}
chop $intlist; chop $intlist; # remove trailing ", "
if ($intcount > 150) {
my $notshown = $intcount - 150;
$intlist .= BML::ml('.label.intsnotshown',{'intnotshown'=>$notshown});
}
$body .= "<b>$intcount:</b> " . $intlist;
if ($remote) {
my $link = "/interests.bml?mode=enmasse";
$link .= "&fromuser=$user" unless ($remote->{'userid'} == $userid);
$body .= ". <small>";
my $mlcode = ($remote->{'userid'} == $userid) ? '.label.interests.removesome'
: '.label.interests.modifyyours';
$body .= BML::ml('Actionlink', { 'link' => "<a href='$link'>$ML{$mlcode}</a>" });
$body .= "</a></small>";
}
$body .= "</td></tr>";
}
##
## friends
##
unless ($synd || $LJ::FORCE_EMPTY_FRIENDS{$userid}) {
my $label = $com ? $ML{'.friends.comm'} : $ML{'.friends.user'};
my $span = ($narrow_left-- >= 0) ? 1 : 2;
$body .= "<tr><td align='right' valign='top'><b><a href='$LJ::SITEROOT/$dir/$user/friends'>$label</a>:</b></td><td colspan='$span'>";
$friends{'display'} = 0 if $friends{'count'} > $MAX_FRIENDS_SHOW;
if ($friends{'count'}) {
if (!$friends{'loaded'} || !$friends{'display'}) {
$body .= "<b>" . $friends{'count'} . ":</b> ";
$body .= "<a href='/directory.bml?s_fro=1&amp;fro_user=$u->{'user'}'> " . ($com ? $ML{'.label.viewmembers'} : $ML{'.label.viewfriends'}) . " </a>.";
} elsif ($u->{'journaltype'} eq 'P' or $u->{'journaltype'} eq 'S') {
# personal/shared journals have a special way of showing their friends list, it breaks it down into
# three sublists: personal/shared, community/news, syndication
my (@pfriends, @cfriends, @yfriends);
my $friend_link = sub {
my $f = shift;
my $status = $f->{'statusvis'};
my $frlink = "<a href='/userinfo.bml?user=$f->{'user'}'>$f->{'user'}</a>";
$frlink = "<strike>$frlink</strike>" if $status =~ /[DXS]/;
$frlink = "<b>$frlink</b>" if $remote_friendid{$f->{'userid'}} && $remote->{'userid'} != $u->{'userid'};
return $frlink;
};
foreach my $f (@friends) {
push @pfriends, $friend_link->($f) if $f->{'journaltype'} eq 'P' or $f->{'journaltype'} eq 'S';
push @cfriends, $friend_link->($f) if $f->{'journaltype'} eq 'C' or $f->{'journaltype'} eq 'N';
push @yfriends, $friend_link->($f) if $f->{'journaltype'} eq 'Y';
}
my ($pcount, $ccount, $ycount) = (scalar @pfriends, scalar @cfriends, scalar @yfriends);
my $pfriends = join ', ', @pfriends;
my $yfriends = join ', ', @yfriends;
my $cfriends = join ', ', @cfriends;
# now spit out the HTML
$body .= "<table>";
if ($pfriends) {
my $text = LJ::ehtml($ML{'.label.frpeople'});
$body .= "<tr><td style='text-align: center;font-weight:bold' nowrap valign='top'>" .
"<img src='$LJ::IMGPREFIX/userinfo.gif' title='$text' alt='$text' border='0' align='top' /></td>" .
"<td style='text-align: left;font-weight:bold' nowrap valign='top'>$pcount:</td>".
"<td>$pfriends</td>";
}
if ($cfriends) {
my $text = LJ::ehtml($ML{'.label.frcommunity'});
$body .= "<tr><td style='text-align: center;font-weight:bold' nowrap valign='top'>" .
"<img src='$LJ::IMGPREFIX/community.gif' title='$text' alt='$text' border='0' align='top' /></td>" .
"<td style='text-align: left;font-weight:bold' nowrap valign='top'>$ccount:</td>" .
"<td>$cfriends</td>";
}
if ($yfriends) {
my $text = LJ::ehtml($ML{'.label.frsyndication2'});
$body .= "<tr><td style='text-align: center;font-weight:bold' nowrap valign='top'>" .
"<img src='$LJ::IMGPREFIX/syndicated.gif' title='$text' alt='$text' border='0' align='top' /></td>" .
"<td style='text-align: left;font-weight:bold' nowrap valign='top'>$ycount:</td>" .
"<td>$yfriends</td>";
}
$body .= "</tr></table>";
} else {
$body .= "<b>" . $friends{'count'} . ":</b> ";
foreach my $f (@friends) {
my $status = $f->{'statusvis'};
my $frlink = "<a href='/userinfo.bml?user=$f->{'user'}'>$f->{'user'}</a>";
$frlink = "<strike>$frlink</strike>" if $status =~ /[DXS]/;
$frlink = "<b>$frlink</b>" if $remote_friendid{$f->{'userid'}} && $remote->{'userid'} != $u->{'userid'};
$body .= $frlink;
$body .= ", ";
}
chop $body; chop $body;
}
} else {
$body .= $ML{'.label.nofriends'};
}
$body .= "</td></tr>\n";
}
# friend of and mutual friends display
# there are two options that will affect what gets shown below: opt_hidefriendofs, opt_showmutualfriends
# if the option to show mutual friends is on, then what was known as the friend of list is broken down
# into two lists: mutual friends (people you list and who also list you back) and 'also friend of', which
# lists the people you don't also list as friends. you can hide your friend of list, and leave just
# your mutual friends list showing, or you can not split them and have both be hidden.
unless ($synd) {
if ($friendsof{'loaded'}) {
my $label;
if ($u->{'opt_showmutualfriends'} && @mutual) {
$label = $ML{'.label.mutual'};
$body .= "<tr><td align='right' valign='top'><b style='white-space: nowrap;'>$label</b>";
$body .= "</td>";
my $plus = $friendsof{'load_clipped'} ? "+" : "";
$body .= "<td colspan='2' valign='top'><b>" . $friendsof{'count_b'} . "$plus:</b> ";
my $count = 0;
my $bold_mutual = ! LJ::u_equals($remote, $u);
foreach (@mutual) {
my $frlink = "<a href=\"/userinfo.bml?user=$_->{'user'}\">$_->{'user'}</a>";
$frlink = "<b>$frlink</b>" if $bold_mutual && $remote_friendid{$_->{'userid'}};
$body .= "$frlink, ";
if (++$count == $MAX_FRIENDOF_SHOW && $GET{'mode'} ne "full") {
$friendsof{'clipped'} = 1;
last;
}
}
chop $body; chop $body;
$body .= ", ..."
if $friendsof{'clipped'} || $friendsof{'load_clipped'};
$friendsof{'clipped'} = 0; # reset for @friend_of display
$body .= "</td></tr>\n";
}
if ($friendsof{'display'} && @friend_of) {
$label = $com ? $ML{'.friendof.comm'} :
($u->{'opt_showmutualfriends'} ? $ML{'.label.alsofriendof'} : $ML{'.friendof.user'});
$body .= "<tr><td align='right' valign='top'><b style='white-space: nowrap;'>$label</b>";
if ($u->{'opt_hidefriendofs'}) {
$body .= "<br /><i>$ML{'.friendof.hidden'}</i>";
}
$body .= "</td>";
my $plus = $friendsof{'load_clipped'} ? "+" : "";
$body .= "<td colspan='2' valign='top'><b>" . $friendsof{'count'} . "$plus:</b> ";
my $count = 0;
foreach (@friend_of) {
my $frlink;
if ($_->{'journaltype'} eq "P") {
$frlink = "<a href=\"/userinfo.bml?user=$_->{'user'}\">$_->{'user'}</a>";
} elsif ($_->{'journaltype'} eq "I") {
$frlink = "<a href=\"/userinfo.bml?userid=$_->{'userid'}&amp;t=I\">" . LJ::ehtml($_->{'name'}) . "</a>";
}
$frlink = "<b>$frlink</b>" if $remote_friendid{$_->{'userid'}};
$body .= "$frlink, ";
if (++$count == $MAX_FRIENDOF_SHOW && $GET{'mode'} ne "full") {
$friendsof{'clipped'} = 1;
last;
}
}
chop $body; chop $body;
$body .= ", ..."
if $friendsof{'clipped'} || $friendsof{'load_clipped'};
$body .= "</td></tr>\n";
};
if ($friendsof{'display'} && @member_of) {
$label = $ML{'.label.memberof'};
$body .= "<tr><td align='right' valign='top'><b style='white-space: nowrap;'>$label:</b></td><td colspan='2'>";
my $plus = $friendsof{'load_clipped'} ? "+" : "";
$body .= "<b>" . $friendsof{'count_m'} . "$plus:</b> ";
foreach (@member_of) {
my $frlink = "<a href='/userinfo.bml?user=$_->{'user'}'>$_->{'user'}</a>";
$frlink = "<b>$frlink</b>" if $remote_friendid{$_->{'userid'}};
$body .= "$frlink, ";
}
chop $body; chop $body;
$body .= "</td></tr>\n";
};
}
} else { # Syndication journals are special
$body .= "<tr><td align='right' valign='top'><b style='white-space: nowrap;'>$ML{'.friendof.syndreadcount'}:</b></td>";
$body .= "<td colspan='2'><i>$friendsof{'count'}</i></td></tr>\n";
}
## extra rows generated by hooks
foreach my $row (LJ::run_hooks("userinfo_rows", {
'dbr' => $dbr,
'u' => $u,
'remote' => $remote,
})) {
next unless $row->[0];
$body .= "<tr><td align='right' valign='top'><b style='white-space: nowrap;'>";
$body .= $row->[0];
$body .=":</b></td><td colspan='2'>";
$body .= $row->[1];
$body .= "</td></tr>\n";
}
unless ($synd || $GET{'mode'} eq "full") { # Synd accts are always full, but their full ends early (see below)
$body .= "</table>\n";
$body .= "<p align='center'><i><a href='/userinfo.bml?user=$u->{'user'}&amp;mode=full'>$ML{'.label.moredetails'}</a></i></p>";
$bml_okay = 0;
return;
}
##
## interesting times
##
$body .= "<tr><td align='right' nowrap='nowrap'><b>$ML{'.label.datecreated'}</b></td><td colspan='2'>$u->{'timecreate'}</td></tr>";
$body .= "<tr><td align='right' nowrap='nowrap'><b>$ML{'.label.dateupdated'}</b></td><td colspan='2'>";
if ($u->{'timeupdate'}) {
$body .= "$u->{'timeupdate'}, <i>";
my $secondsold = $u->{'secondsold'};
my $num;
if ($secondsold > 60*60*24*7) {
$num = int($secondsold / (60*60*24*7));
$body .= $num == 1 ? $ML{'.timeupdate.weekago'}
: BML::ml('.timeupdate.weeksago',{'num'=>$num});
} elsif ($secondsold > 60*60*24) {
$num = int($secondsold / (60*60*24));
$body .= $num == 1 ? $ML{'.timeupdate.dayago'}
: BML::ml('.timeupdate.daysago',{'num'=>$num});
} elsif ($secondsold > 60*60) {
$num = int($secondsold / (60*60));
$body .= $num == 1 ? $ML{'.timeupdate.hourago'}
: BML::ml('.timeupdate.hoursago',{'num'=>$num});
} elsif ($secondsold > 60) {
$num = int($secondsold / (60));
$body .= $num == 1 ? $ML{'.timeupdate.minuteago'}
: BML::ml('.timeupdate.minutesago',{'num'=>$num});
} else {
$num = $secondsold;
$body .= $num == 1 ? $ML{'.timeupdate.secondago'}
: BML::ml('.timeupdate.secondsago',{'num'=>$num});
}
$body .= "</i>";
} else {
$body .= $ML{'.date.never'};
}
$body .= "</td></tr>";
if ($synd) { # The rest of the rows are not useful to synd accts
$body .= "</table>\n";
$bml_okay = 0;
return "";
}
unless ($LJ::DISABLED{'userinfo_clientusage'}) {
$body .= "<tr><td align='right' valign='top'><b>" . BML::ml('.label.clientsused',{'siteroot'=>$LJ::SITEROOT}) . "</b></td><td colspan='2'>";
$sth = $dbr->prepare("SELECT DISTINCT c.client FROM clients c, clientusage cu ".
"WHERE cu.userid=$userid AND cu.clientid=c.clientid ORDER BY c.client");
$sth->execute;
my $lastclient = "";
while ($_ = $sth->fetchrow_hashref) {
next unless ($_->{'client'} =~ m!(.+)/(.+)!);
my ($client, $ver) = ($1, $2);
if ($lastclient ne $client)
{
if ($lastclient) { chop $body; chop $body; $body .= "<br />"; }
else { 1; }
$body .= "<b>" . LJ::ehtml($client) ."</b>: ";
$lastclient = $client;
}
$body .= LJ::ehtml($ver) . ", ";
}
if ($lastclient) { chop $body; chop $body; }
$body .= "</td></tr>";
}
# count journal entries
{
my $memkey = [$userid, "log2ct:$userid"];
my $count = LJ::MemCache::get($memkey);
unless ($count) {
my $expire = time() + 3600*24*2; # 2 days
$count = $dbcr->selectrow_array("SELECT COUNT(*) FROM log2 WHERE journalid=?",
undef, $userid);
LJ::MemCache::set($memkey, $count, $expire);
}
$body .= "<tr><td align='right' nowrap='nowrap'><b>$ML{'.label.journalentrs'}</b></td>" .
"<td colspan='2'>" . &comma($count) . "</td></tr>";
}
my $points = $dbr->selectrow_array("SELECT SUM(points) AS 'points' FROM supportpoints WHERE userid=$userid");
if ($points) {
$body .= "<tr><td align='right' nowrap='nowrap'><b><a href='/support/'>$ML{'.label.supportpoints'}</a>:</b></td><td colspan='2'>" . &comma($points) . "</td></tr>";
}
sub comma {
my $num = shift;
if ($num =~ s/(\d)(\d\d\d)$/$1,$2/) {
$num =~ s/(\d)(\d\d\d),/$1,$2/g;
}
return $num;
}
##
## journal comments
{
my ($com_post, $com_got);
unless ($LJ::DISABLED{'show-talkleft'}) {
my $memkey = [$userid, "talkleftct:$userid"];
my $count = LJ::MemCache::get($memkey);
unless ($count) {
my $expire = time() + 3600*24*2; # 2 days
$count = $dbcr->selectrow_array("SELECT COUNT(*) FROM talkleft " .
"WHERE userid=?", undef, $userid);
LJ::MemCache::set($memkey, $count, $expire) if defined $count;
}
$com_post = comma($count);
$com_post = BML::ml('.label.composted', {'num'=>$com_post});
}
my $memkey = [$userid, "talk2ct:$userid"];
my $count = LJ::MemCache::get($memkey);
unless ($count) {
my $expire = time() + 3600*24*2; # 2 days;
$count = $dbcr->selectrow_array("SELECT COUNT(*) FROM talk2 ".
"WHERE journalid=?", undef, $userid);
LJ::MemCache::set($memkey, $count, $expire) if defined $count;
}
$com_got = comma($count);
$com_got = BML::ml('.label.comreceived', {'num'=>$com_got});
$body .= "<tr><td align='right'><b>$ML{'.label.comments'}</b></td><td colspan='2'>$com_post" .
$com_got . "</td></tr>";
}
###
### shared journal access
###
{
my $list;
if ($com || $u->{'journaltype'} eq 'S') {
# load user who can post to this community
$list = LJ::load_rel_user($u, 'P');
} else {
# load communities/accounts this user can post to
$list = LJ::load_rel_target($u, 'P');
}
my %u;
my @ids = @$list;
my $count = @ids;
my $chopped = 0;
my $CHOP_POINT = 500;
if (@ids > $CHOP_POINT) {
@ids = splice(@ids, 0, $CHOP_POINT);
$chopped = 1;
}
LJ::load_userids_multiple([ map { $_ => \$u{$_} } @ids ]);
my @accesslist = sort { $a->{user} cmp $b->{user} } grep { $_->{statusvis} eq 'V' } values %u;
if (my $vcount = @accesslist) {
$count = $vcount if $count < $CHOP_POINT;
$body .= "<tr valign='top'><td align='right'><b>$ML{'.label.shared'}</b></td><td colspan='2'><b>$count</b>: ";
$body .= join(", ", map { "<a href='userinfo.bml?user=$_->{user}'>$_->{user}</a>" } @accesslist);
$body .= ", ..." if $chopped;
$body .= "</td></tr>";
}
}
$body .= "</table>\n";
# removed until we run graphviz locally
# $body .= "<p><a href=\"/friends/graph.bml?user=$user\"><b>Graph of friends</b></a></p>";
$bml_okay = 0;
return;
_code?><?page
windowtitle=><?_code return $windowtitle; _code?>
title=><?_code return $title; _code?>
body=><?_code return $bml_okay ? $body : BML::noparse($body); _code?>
head=><?_code return $head; _code?>
page?><?_c <LJDEP>
lib: cgi-bin/ljlib.pl, cgi-bin/cleanhtml.pl
link: htdocs/editinfo.bml, htdocs/userinfo.bml, htdocs/users
link: htdocs/community/join.bml, htdocs/community/leave.bml, htdocs/friends/add.bml, htdocs/todo/index.bml
link: htdocs/tools/memories.bml, htdocs/tools/tellafriend.bml, htdocs/allpics.bml
link: htdocs/tools/textmessage.bml, htdocs/interests.bml, htdocs/support/faqbrowse.bml, htdocs/download/index.bml
link: htdocs/support/index.bml
img: img/btn_addfriend.gif, img/btn_todo.gif, img/btn_memories.gif, img/btn_tellfriend.gif, img/talk/md10_thumbup.gif, img/xml.gif
hook: userinfo_html_by_user, userinfo_rows
</LJDEP> _c?>