==== //ccare/main/LiveJournal/htdocs/userinfo.bml#7 - /u0/jaffray/p4/LiveJournal/htdocs/userinfo.bml ====
--- /tmp/tmp.1775.0	Fri Jun  8 18:47:32 2001
+++ /u0/jaffray/p4/LiveJournal/htdocs/userinfo.bml	Fri Jun  8 18:46:08 2001
@@ -4,6 +4,7 @@
  $body = "";
  $head = "";	
 
+ use LJ::TagGenerator;
  require 'ljlib.pl';
  require 'ljprotocol.pl';
  require 'cleanhtml.pl';
@@ -105,16 +106,6 @@
      }
  }
 
- my %res_fr;
- &LJ::do_request($dbh, 
-		 { 'mode' => 'getfriends',
-		   'includefriendof' => '1',
-		   'user' => $u->{'user'}, }, 
-		 \%res_fr,
-		 { 'userid' => $u->{'userid'},
-		   'noauth' => 1,
-	       }); 
-
 
  $u->{'name'} = &ehtml($u->{'name'});
 
@@ -144,26 +135,72 @@
      $body .= " P=)";
  }
 
- my $add_friend = 0;
- if ($remote->{'user'} && $remote->{'user'} ne $user) {
-     $add_friend = 1;
-     if ($res_fr{'friendof_count'}) {
-	 for (my $i=1; $i<=$res_fr{'friendof_count'}; $i++) {
-	     if ($remote->{'user'} eq $res_fr{"friendof_${i}_user"}) {
-		 $add_friend = 0;
-	     }
-	 }
-     }
- }
-
  $body .= "<P ALIGN=CENTER>";
 
+
+ # given an sql select statement which returns rows of only one column,
+ # returns a hash whose keys are the results of that statement.
+ sub selectall_onecolumn_hashref {
+     my $sql = shift;
+     my %result;
+     my $sth = $dbh->prepare($sql)
+       or return undef;
+     $sth->execute
+       or return undef;
+     while (my $row = $sth->fetch) {
+         $result{$row->[0]} = 1;
+     }
+     return \%result;
+ }
+ # ditto, but returns a sorted array.
+ sub selectall_onecolumn_arrayref {
+     my $sql = shift;
+     my $href = selectall_onecolumn_hashref($sql)
+       or return undef;
+     return [sort keys %$href];
+ }
+
+ # given sql constraints, do the select, return a hash of (friend => 1)
+ sub friend_select {
+     my $constraints = join(" AND ", @_);
+     my $sql = "SELECT u.user FROM user u, friends f WHERE $constraints";
+     return selectall_onecolumn_hashref($sql);
+ }
+
+ # query for all the friend info we'll need later
+ my $friends = friend_select("f.userid = $u->{userid}",
+                             "u.userid = f.friendid",
+                             "u.journaltype = 'P'")
+   or return $dbh->errstr;
+ my $friendofs = friend_select("f.friendid = $u->{userid}",
+                               "u.userid = f.userid",
+                               "u.journaltype = 'P'")
+   or return $dbh->errstr;
+ my $comms_watched = friend_select("f.userid = $u->{userid}",
+                                   "u.userid = f.friendid",
+                                   "u.journaltype = 'C'")
+   or return $dbh->errstr;
+ my $memberships = friend_select("f.friendid = $u->{userid}",
+                                 "u.userid = f.userid",
+                                 "u.journaltype = 'C'")
+   or return $dbh->errstr;
+
+ my $remote_friends = ($remote && $remote->{'userid'} != $u->{'userid'}
+                       ? friend_select("f.userid = $remote->{userid}",
+                                       "u.userid = f.friendid")
+                       : {})
+   or return $dbh->errstr;
+
+
  ## standout bar
  {
+     my $label;
      my @linkele;
     
-     my $label = $com ? "Monitor Community" : "Add this user to your friends list";
-     push @linkele, "<A HREF=\"/friends/add.bml?user=$user\"><IMG SRC=\"(=IMGPREFIX=)/btn_addfriend.gif\" WIDTH=22 HEIGHT=20 alt=\"$label\" title=\"$label\" ALIGN=ABSMIDDLE BORDER=0></A>";
+     if ($remote and not exists $remote_friends{$user}) {
+         $label = $com ? "Monitor Community" : "Add this user to your friends list";
+         push @linkele, "<A HREF=\"/friends/add.bml?user=$user\"><IMG SRC=\"(=IMGPREFIX=)/btn_addfriend.gif\" WIDTH=22 HEIGHT=20 alt=\"$label\" title=\"$label\" ALIGN=ABSMIDDLE BORDER=0></A>";
+     }
 
      $label = "To-Do List";
      push @linkele, "<A HREF=\"/todo/?user=$user\"><IMG SRC=\"(=IMGPREFIX=)/btn_todo.gif\" WIDTH=22 HEIGHT=20 alt=\"$label\" title=\"$label\" ALIGN=ABSMIDDLE BORDER=0></A>";
@@ -193,9 +230,18 @@
      $body .= "<TR VALIGN=TOP><TD ALIGN=RIGHT><B>User:</B></TD><TD WIDTH=100%><A HREF=\"/$dir/$user/\"><B>$user</B></A> ($u->{'userid'})$paid_extra</TD>";
  }
      
-### picture
 
- my $narrow_left = 2;  ## rows with smaller colspan to 2 
+ ### picture
+ {
+     ## how many rows should allow right-column space for the picture?
+     my $narrow_rows = 3;  
+     my $row_num = 0;
+     sub middle_colspan {
+         ++$row_num;
+         return 1 if $row_num <= $narrow_rows;
+         return 2;
+     }
+ }
  $body .= "<TD ALIGN=RIGHT ROWSPAN=3>";
  if ($u->{'defaultpicid'}) {
      my $picid = $u->{'defaultpicid'};
@@ -206,23 +252,30 @@
      $body .= "&nbsp;";
  }
  $body .= "</TD>";
-### /picture
-
  $body .= "</TR>\n";
 
  ### name
- $narrow_left--;
- $body .= "<TR><TD ALIGN=RIGHT><B>Name:</B></TD><TD>$u->{'name'}</TD></TR>\n";
+ $body .= TR(TD({align => "right"},
+                B("Name:")),
+             TD({colspan => middle_colspan()},
+                $u->{name})) . "\n";
 
- ## text mesage
+ ## text message
  if ($u->{'txtmsg_status'} eq "on") {
-     my $span = ($narrow_left-- >= 0) ? 1 : 2;
-     $body .= "<TR VALIGN=TOP><TD ALIGN=RIGHT><B><NOBR>Text<BR>Message</NOBR>:</B></TD><TD COLSPAN=$span><A HREF=\"/tools/textmessage.bml?user=$u->{'user'}\">Send <B>$u->{'user'}</B> a text message</A><BR>on $pronoun cellphone/pager.</TD></TR>";
+     $body .=
+       TR({valign => "top"},
+          TD({align => "right"},
+             B(NOBR("Text<br>Message:"))),
+          TD({colspan => middle_colspan()},
+             A({href => "/tools/textmessage.bml?user=$u->{user}"},
+               "Send <b>$u->{user}</b> a text message"),
+             "<br>on $pronoun cellphone/pager."));
  }
 
+ ## url
  if ($u->{'url'}) {
      my $url = &BMLUtil::ehtml($u->{'url'});
-     my $span = ($narrow_left-- >= 0) ? 1 : 2;
+     my $span = middle_colspan();
      unless ($url =~ /^http:\/\//) {
 	 $url =~ s/^http\W*//;
 	 $url = "http://$url";
@@ -232,10 +285,10 @@
      $body .= "<TR><TD ALIGN=RIGHT><B>Website:</B></TD><TD COLSPAN=$span>$url</TD></TR>\n" if ($u->{'url'});
  }
 
-
+  ## personal info
   if ($u->{'allow_infoshow'} eq "Y") {
       if ($u->{'city'} || $u->{'state'} || $u->{'country'}) {
-	  my $span = ($narrow_left-- >= 0) ? 1 : 2;
+	  my $span = middle_colspan();
 	  $body .= "<TR><TD ALIGN=RIGHT><B>Location:</B></TD><TD COLSPAN=$span>";
 	  my $estate = &BMLUtil::eurl($u->{'state'});
 	  my $ecity = &BMLUtil::eurl($u->{'city'});
@@ -267,14 +320,15 @@
       if ($u->{'bdate'} && !$com && $u->{'bdate'} ne "0000-00-00") {
 	  my $bdate = $u->{'bdate'};
 	  $bdate =~ s/^0000-//;
-	  my $span = ($narrow_left-- >= 0) ? 1 : 2;
+	  my $span = middle_colspan();
 	  $body .= "<TR><TD ALIGN=RIGHT><B>Birthdate:</B></TD><TD COLSPAN=$span>$bdate</TD></TR>\n";
       }
   }
  
+  ## contact info
   if ($u->{'allow_contactshow'} eq "Y") {
       unless ($u->{'opt_whatemailshow'} eq "N") {
-	  my $span = ($narrow_left-- >= 0) ? 1 : 2;
+	  my $span = middle_colspan();
 	  $body .= "<TR VALIGN=TOP><TD ALIGN=RIGHT><B>Email:</B></TD><TD COLSPAN=$span>";
 	  my @emails = ($u->{'email'});
 	  if ($u->{'opt_whatemailshow'} eq "L") {
@@ -308,28 +362,28 @@
       if ($u->{'aolim'}) {
 	  my $qim = $u->{'aolim'};
 	  $qim =~ s/ /+/g;
-	  my $span = ($narrow_left-- >= 0) ? 1 : 2;
+	  my $span = middle_colspan();
 	  $body .= "<TR><TD ALIGN=RIGHT><B><NOBR>AOL IM</NOBR>:</B></TD><TD COLSPAN=$span>$u->{'aolim'} (<B><A HREF=\"aim:addbuddy?screenname=$qim\">Add Buddy</A>, <A HREF=\"aim:goim?screenname=$qim&message=Hello+there!.+How+are+you?\">Send Message</A></B>)</TD></TR>\n";
       }
       if ($u->{'icq'}) {
-	  my $span = ($narrow_left-- >= 0) ? 1 : 2;
+	  my $span = middle_colspan();
 	  $body .= "<TR><TD ALIGN=RIGHT><B><NOBR>ICQ UIN</NOBR>:</B></TD><TD COLSPAN=$span><IMG SRC=\"http://online.mirabilis.com/scripts/online.dll?icq=$u->{'icq'}&img=5\" HEIGHT=18 WIDTH=18> $u->{'icq'} (<B><A HREF=\"http://wwp.icq.com/scripts/search.dll?to=$u->{'icq'}\">Add User</A>, <A HREF=\"http://wwp.icq.com/scripts/contact.dll?msgto=$u->{'icq'}\">Send Message</A></B>) </TD></TR>\n";
       }
       if ($u->{'yahoo'}) {
-	  my $span = ($narrow_left-- >= 0) ? 1 : 2;
+	  my $span = middle_colspan();
 	  $body .= "<tr><td align=right><b><nobr>Yahoo! ID</nobr>:</b></td><td colspan=$span><a href=\"http://profiles.yahoo.com/$u->{'yahoo'}\">$u->{'yahoo'}</a> (<b><a href=\"http://edit.yahoo.com/config/set_buddygrp?.src=&.cmd=a&.bg=Friends&.bdl=$u->{'yahoo'}\">Add User</a>, <a href=\"http://edit.yahoo.com/config/send_webmesg?.target=$u->{'yahoo'}\">Send Message</a></b>) </td></tr>\n";
       }
       if ($u->{'msn'}) {
-	  my $span = ($narrow_left-- >= 0) ? 1 : 2;
+	  my $span = middle_colspan();
 	  $body .= "<tr><td align=right><b><nobr>MSN Username</nobr>:</b></td><td colspan=$span>$u->{'msn'}</td></tr>\n";
       }
       if ($u->{'jabber'}) {
-	  my $span = ($narrow_left-- >= 0) ? 1 : 2;
+	  my $span = middle_colspan();
 	  $body .= "<tr><td align=right><b><nobr>Jabber</nobr>:</b></td><td colspan=$span>$u->{'jabber'}</td></tr>\n";
       }
   }
 
-
+ ## bio
  if ($u->{'has_bio'} eq "Y") {
      my $span = ($narrow_left-- > 0) ? 1 : 2;
      my $label = $com ? "About" : "Bio";
@@ -388,69 +442,130 @@
  ##
  ## friends
  ## 
+ 
+ sub print_friend {
+     my $friend = shift;
+     my $link = A({href => "/userinfo.bml?user=$friend"}, $friend);
+     return B($link) if exists $remote_friends->{$friend};
+     return $link;
+ }
+ sub print_friendlist {
+     my $list = shift;
+     my $LIMIT = 150;
+     return (B(scalar @$list, ": ") .
+             join(",\n",
+                  ((@$list > $LIMIT and $FORM{mode} ne "full")
+                   ? ((map {print_friend($_)} @$list[0..($LIMIT-1)]),
+                      A({href => self_link({mode => "full"})}, "..."))
+                   : (map {print_friend($_)} @$list))));
+ }
+ sub print_friendrow {
+     my ($list, $icon, $alt_text) = @_;
+     @$list or return "";
+     return TR(TD({valign => "top"},
+                            IMG({src   => "$IMGPREFIX/$icon",
+                                 alt   => $alt_text,
+                                 title => $alt_text})),
+               TD(print_friendlist($list)));
+ }
+
+ ## people-friends
  {
-     my $label = $com ? "Members" : "Friends";
-     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>";
-     if ($res_fr{'friend_count'} > 500) {
-	 $body .= "<B>" . $res_fr{'friend_count'} . ":</B> ";
-	 $body .= "<a href=\"$LJ::DIRURI?s_fro=1&fro_user=$u->{'user'}\">View $label</a>.";
-     } elsif ($res_fr{'friend_count'}) {
-	 $body .= "<B>" . $res_fr{'friend_count'} . ":</B> ";
-	 my $count = 0;
-	 for (my $i=1; $i<=$res_fr{'friend_count'}; $i++) {
-	     my $fr = $res_fr{"friend_${i}_user"};
-	     $body .= "<A HREF=\"/userinfo.bml?user=$fr\">$fr</A>, ";
-	 }
-	 chop $body; chop $body;
-     } else {
-	 $body .= "<I>None listed.</I>";
+     my @mutual        = sort grep {exists $friendofs->{$_}}     keys %$friends;
+     my @friend_only   = sort grep {not exists $friendofs->{$_}} keys %$friends;
+     my @friendof_only = sort grep {not exists $friends->{$_}}   keys %$friendofs;
+     my $has_friends  = (@mutual or @friend_only);
+
+     if ($has_friends) {
+         $body .=
+           TR(TD({align => "right", valign => "top"},
+                 B(!$com ? "Friends:" : "Members:")),
+              TD(TABLE(print_friendrow(\@mutual, "doublearrow.gif",
+                                       (!$com
+                                        ? "Mutual friends of $u->{user}"
+                                        : "Members who watch $u->{user}")),
+                       print_friendrow(\@friend_only, "rightarrow.gif",
+                                       (!$com
+                                        ? "Friends who don't list $u->{user} as a friend"
+                                        : "Members who don't watch $u->{user}")),
+                      )));
+     }
+     if (@friendof_only) {
+         $body .=
+           TR(TD({align => "right", valign => "top"},
+                 NOBR(B($has_friends ? "Also watched by:" : "Watched by:"))),
+              TD(TABLE(print_friendrow(\@friendof_only, "leftarrow.gif",
+                                       (!$com
+                                        ? "Non-friends who list $u->{user} as a friend"
+                                        : "Non-members who watch $u->{user}")),
+                      )));
      }
-     $body .= "</TD></TR>\n";
  }
-
- ##
- ## friend of
- ##
+ ## community-friends
  {
-     my @friend_of;
-     my @member_of;
-     my $label;
-     for (my $i=1; $i<=$res_fr{'friendof_count'}; $i++) {
-	 my $fr = $res_fr{"friendof_${i}_user"};
-	 if ($res_fr{"friendof_${i}_type"} eq "community") {
-	     push @member_of, $fr;
-	 } else {
-	     push @friend_of, $fr;
-	 }
+     my @mutual        = sort grep {exists $memberships->{$_}}     keys %$comms_watched;
+     my @friend_only   = sort grep {not exists $memberships->{$_}} keys %$comms_watched;
+     my @friendof_only = sort grep {not exists $comms_watched->{$_}} keys %$memberships;
+     my $has_friends  = (@mutual or @friend_only);
+
+     if ($has_friends) {
+         $body .=
+           TR(TD({align => "right", valign => "top"},
+                 B("Communities:")),
+              TD(TABLE(print_friendrow(\@mutual, "doublearrow.gif",
+                                       "$u->{user} watches and is a member of"),
+                       print_friendrow(\@friend_only, "rightarrow.gif",
+                                       "$u->{user} watches but is not a member of"),
+                      )));
+     }
+     if (@friendof_only) {
+         $body .=
+           TR(TD({align => "right", valign => "top"},
+                 NOBR(B($has_friends ? "Also member of:" : "Member of:"))),
+              TD(TABLE(print_friendrow(\@friendof_only, "leftarrow.gif",
+                                       "$u->{user} is a member but does not watch"),
+                      )));
      }
-     if (@friend_of) {
-	 $label = $com ? "Watched by" : "Friend of";
-	 $body .= "<TR><TD ALIGN=RIGHT VALIGN=TOP><B><nobr>$label:</nobr></B></TD><TD COLSPAN=2>";
-	 $body .= "<B>" . scalar(@friend_of) . ":</B> ";
-	 my $count = 0;
-	 foreach (@friend_of) {
-	     $body .= "<A HREF=\"/userinfo.bml?user=$_\">$_</A>, ";
-	     if (++$count == 150 && $FORM{'mode'} ne "full") {
-		 $body .= "<a href=\"" . &self_link({ 'mode' => 'full' }) . "\">...</a>";
-		 last;
-	     }
-	 }
-	 chop $body; chop $body;
-	 $body .= "</TD></TR>\n";
-     };
-     if (@member_of) {
-	 $label = "Member of";
-	 $body .= "<TR><TD ALIGN=RIGHT VALIGN=TOP><B><nobr>$label:</nobr></B></TD><TD COLSPAN=2>";
-	 $body .= "<B>" . scalar(@member_of) . ":</B> ";
-	 foreach (@member_of) {
-	     $body .= "<A HREF=\"/userinfo.bml?user=$_\">$_</A>, ";
-	 }
-	 chop $body; chop $body;
-	 $body .= "</TD></TR>\n";
-     };
  }
 
+ ### posting access
+ {
+     my $comms = selectall_onecolumn_arrayref(qq(SELECT u.user
+                                                 FROM   logaccess l, user u
+                                                 WHERE  u.userid   = l.ownerid
+                                                 AND    l.posterid = $u->{userid}))
+       or return $dbh->errstr;
+     my $posters = selectall_onecolumn_arrayref(qq(SELECT u.user
+                                                   FROM   logaccess l, user u
+                                                   WHERE  u.userid  = l.posterid
+                                                   AND    l.ownerid = $u->{userid}))
+       or return $dbh->errstr;
+     
+     my @notes = ();
+     if (@$comms > 1) {
+         push @notes, ("$u->{user} can post to the following " .
+                       scalar @$comms . " communities: <br>" .
+                       join(", ", map {print_friend($_)} @$comms));
+     } elsif (@$comms) {
+         push @notes, ("$u->{user} can post to " . print_friend($comms->[0])) . ".";
+     }
+     if (@$posters > 1) {
+         push @notes, ("The following " . scalar @$posters .
+                       " users can post to $u->{user}:<br>" .
+                       join(", ", map {print_friend($_)} @$posters));
+     } elsif (@$posters) {
+         push @notes, (print_friend($comms->[0]) . " can post to $u->{user}.");
+     }
+
+     if (@notes) {
+         $body .=
+           TR(TD({align => "right", valign => "top"},
+                 NOBR(B("Posting Access:"))),
+              TD({colspan => 2},
+                 join("<p>", @notes)));
+     }
+ }
+                           
  ###
  ### account type
  ###
@@ -567,32 +682,8 @@
 $body .= "<TR><TD ALIGN=RIGHT><B>Comments:</B></TD><TD COLSPAN=2><B>Posted:</B> $com_post, <B>Received:</B> $com_got</TD></TR>";
 
 
-###
-### shared journal access
-###
-
-$sth = $dbh->prepare("SELECT uo.user AS 'owner', up.user AS 'poster' FROM logaccess l, user uo, user up WHERE l.ownerid=uo.userid AND l.posterid=up.userid AND (l.ownerid=$u->{'userid'} OR l.posterid=$u->{'userid'})");
-$sth->execute;
-my $shcount = 0;
-while ($_ = $sth->fetchrow_hashref)
-{
-    if (++$shcount == 1) {
-	$body .= "<TR VALIGN=TOP><TD ALIGN=RIGHT><B>Shared Journal Access:</B></TD><TD COLSPAN=2>";
-    }
-    if ($_->{'poster'} eq $u->{'user'}) {
-	$body .= "$u->{'user'} can post to <A HREF=\"userinfo.bml?user=$_->{'owner'}\"><B>$_->{'owner'}</B></A><BR>\n";
-    } 
-    if ($_->{'owner'} eq $u->{'user'}) {
-	$body .= "<A HREF=\"userinfo.bml?user=$_->{'poster'}\"><B>$_->{'poster'}</B></A> can post to $u->{'user'}<BR>\n";
-    } 
-}
-
-if ($shcount) {
-    $body .= "</TD></TR>";
-}
-   
 $body .= "</TABLE>\n";
-$body .= "<P><A HREF=\"/friends/graph.bml?user=$user\"><B>Graph of friends</B></A>";
+# $body .= "<P><A HREF=\"/friends/graph.bml?user=$user\"><B>Graph of friends</B></A>";
 
 return "";
 

