Commit a70c2716 authored by Kevin Atkinson's avatar Kevin Atkinson

Merge branch 'exp-vis'.

This adds experimental support for experiment visualization.  It
currently is a Utah only features and is thus guarded by the
EXP_VIS_SUPPORT site variable, and also requires some changes to
httpd.conf on ops which are not committed.

The experiment visualization support allows users to create basic
per-experiment or per-project web pages by putting an index.html file
in /proj/PROJ/www/exp-vis/EXP, or /proj/PROJ/www/group-vis.  The web
pages can then be accessed via the "(User) Visualization" tab in the
experient or project web page or directly via
https://users.emulab.net/exp-vis/PROJ/EXP, or /proj-vis/PROJ.  A proxy
is used so that only project members can access the web page.  Some
support for per-group vis. is also provided (use
/group-vis/PROJ/GROUP).
parents 231b5953 5f71ab30
......@@ -90,3 +90,5 @@ HAVE_ULXMLRPCPP = @HAVE_ULXMLRPCPP@
STANDALONE_CLEARINGHOUSE = @STANDALONE_CLEARINGHOUSE@
NODE_USAGE_SUPPORT = @NODE_USAGE_SUPPORT@
EXP_VIS_SUPPORT = @EXP_VIS_SUPPORT@
......@@ -12,6 +12,9 @@ SUBDIR = collab
include $(OBJDIR)/Makeconf
SUBDIRS = mailman cvstools jabber trac
ifeq ($(EXP_VIS_SUPPORT),1)
SUBDIRS += exp-vis
endif
all: all-subdirs
......@@ -31,6 +34,9 @@ post-install:
@$(MAKE) -C cvstools post-install
@$(MAKE) -C jabber post-install
@$(MAKE) -C trac post-install
ifeq ($(EXP_VIS_SUPPORT),1)
@$(MAKE) -C exp-vis post-install
endif
# How to recursively descend into subdirectories to make general
# targets such as `all'.
......
#
# EMULAB-COPYRIGHT
# Copyright (c) 2009 University of Utah and the Flux Group.
# All rights reserved.
#
SRCDIR = @srcdir@
TESTBED_SRCDIR = @top_srcdir@
OBJDIR = ../..
SUBDIR = collab/exp-vis
include $(OBJDIR)/Makeconf
CGI_SCRIPTS = fetch-vis
LIBEXEC_SCRIPTS = write-vis-auth
CTRL_LIBEXEC_SCRIPTS = write-vis-auth.proxy
SETUID_LIBX_SCRIPTS = write-vis-auth
#
# Force dependencies on the scripts so that they will be rerun through
# configure if the .in file is changed.
#
all: $(CGI_SCRIPTS) $(LIBEXEC_SCRIPTS) $(CTRL_LIBEXEC_SCRIPTS)
include $(TESTBED_SRCDIR)/GNUmakerules
install: \
$(addprefix $(INSTALL_LIBEXECDIR)/, $(LIBEXEC_SCRIPTS)) \
$(addprefix $(TBROOT)/opsdir/www/cgi-bin/, $(CGI_SCRIPTS)) \
$(addprefix $(INSTALL_DIR)/opsdir/libexec/, $(CTRL_LIBEXEC_SCRIPTS))
$(TBROOT)/opsdir/www/cgi-bin/fetch-vis: fetch-vis
-$(SUDO) mkdir -m 775 $(TBROOT)/opsdir/www/cgi-bin
$(SUDO) $(INSTALL) -o root -m 4775 $< $@
$(INSTALL_DIR)/opsdir/libexec/write-vis-auth.proxy: write-vis-auth.proxy
-mkdir -p $(INSTALL_DIR)/opsdir/libexec
$(INSTALL) $< $@
post-install:
clean:
#!/usr/bin/perl -T
#
#
#
use strict;
use warnings;
use POSIX qw(setuid setgid);
use Cwd qw(realpath);
use CGI;
use CGI::Cookie;
use HTTP::Date;
#use Data::Dumper;
#print "\n\n";
#print STDERR Dumper(\%ENV);
my $FSDIR_PROJ = "@FSDIR_PROJ@";
my $FSDIR_GROUPS = "@FSDIR_GROUPS@";
sub error($) {
print "Content-Type: text/plain\n";
print "Status: 404 Not Found\n\n";
print "$_[0]\n";
#die "$_[0]\n";
exit 1;
}
my $SCRIPT_URL = $ENV{REQUEST_URI};
# Parse URL
my ($proj,$group,$exp,$dir,$file);
local $_ = $SCRIPT_URL;
if (/^\/proj-vis\/([a-zA-Z0-9-]+)\/?(.*)$/) {
$proj = $1;
$group = $1;
$file = $2;
} elsif (/^\/group-vis\/([a-zA-Z0-9-]+)\/?([a-zA-Z0-9-]+)\/?(.*)$/) {
$proj = $1;
$group = $2;
$file = $3;
} elsif (/^\/exp-vis\/([a-zA-Z0-9-]+)\/?([a-zA-Z0-9-]+)\/?(.*)$/) {
$proj = $1;
$exp = $2;
$file = $3;
} else {
error("Malformed URL");
}
if (defined $exp) {
my $exp_dir = "/proj/$proj/exp/$exp";
local $_ = realpath $exp_dir;
if (/^$FSDIR_PROJ\/$proj\//) {
$group = $proj;
} elsif (/^$FSDIR_GROUPS\/$proj\/(.+?)\//) {
$group = $1;
}
$dir = "/groups/$proj/$group/www/exp-vis/$exp";
} else {
$dir = "/groups/$proj/$group/www/group-vis";
}
# Lookup up the Unix GID for the proj and the group
my (undef,undef,undef,undef,undef,$gid) = stat("/proj/$proj") or die;
my ($gid_name,undef,undef,$gid_members) = getgrgid($gid);
die "Error: Bad proj GID: $gid_name != $proj" unless $gid_name eq $proj;
my (undef,undef,undef,undef,undef,$gid2) = stat("/groups/$proj/$group") or die;
my ($gid2_name,undef,undef,$gid2_members) = getgrgid($gid2);
# For security remove any ".." from the path and abort if we would
# leave $dir
my @dirs = split /\//, $file;
my @res;
foreach my $d (@dirs) {
if ($d eq '' || $d eq '.') {
# nothing to do
} elsif ($d eq '..') {
error("Malformed URL") if @res == 0;
pop @res;
} else {
push @res, $d;
}
}
# Create the path
$file = join ('/', @res);
my $path = "$dir/$file";
if (-d $path) {
my $orig_path = $path;
$path .= "/index.html" if -e "$path/index.html";
$path .= "/index.htm" if -e "$path/index.htm";
error("Can't index dir: $path") unless $path ne $orig_path;
}
error("File Doesn't Exist: $path") unless -e $path;
# Make sure that the path, after resolving any symbolic links,
# still resides is /proj/<proj> or /groups/<proj>/<group>
my $realpath = realpath $path;
error("Invalid path: $realpath") unless $realpath =~ /^$FSDIR_PROJ\/$proj|^$FSDIR_GROUPS\/$proj\/$group/;
#
# Special rule for boss. Since we are bypassing authorization, don't
# show anything, just let boss know that the url is valid.
#
if ($ENV{REMOTE_ADDR} eq "@BOSSNODE_IP@") {
print "Content-Type: text/plain\n\n";
print "I exist!\n";
exit(0);
}
#
# Get session cookie and make sure user is logged in and authorized to
# view.
#
my %cookies = raw_fetch CGI::Cookie;
my $session_key = $cookies{exp_vis_session};
error("Not logged in.") unless defined $session_key;
my $user;
open F, "/var/run/exp-vis.auth" or die;
foreach (<F>) {
chop;
my ($key, $u) = split / /;
if ($key eq $session_key) {
$user = $u;
last;
}
}
error("Login Timed Out.") unless defined $user;
my (undef, undef, $uid, $user_gid) = getpwnam($user);
die if $user_gid == 0;
error("You do not have permission to view $proj files")
unless $gid == $user_gid || grep {$_ eq $user} split /\s+/, $gid_members;
error("You do not have permission to view $proj/$group files")
unless $gid2 == $user_gid || grep {$_ eq $user} split /\s+/, $gid2_members;
# OK, Now we are sure the user has permission to view this file.
# Now become a member of the GID for the proj and group and clear out
# any other GIDs
undef $!;
setgid($gid);
$) = "$gid $gid $gid2";
die $! if $!;
# Now drop privileges, using setuid to make sure the saved uid
# is also changes, ie, so that the change is permanent.
setuid($<) or die $!;
my %mime_map =
qw(html text/html htm text/html
txt text/plain
png image/png
gif image/gif
jpg image/jpeg jpeg image/jpeg
zip application/zip);
my ($ext) = $path =~ /\.([^.]+)$/;
$ext = lc $ext;
my $mime_type = $mime_map{$ext};
$/ = undef;
open F, "$path" or error "Can't read file: $path";
my ($dev,$ino,$mode,$nlink,undef,undef,$rdev,$size,
$atime,$mtime,$ctime,$blksize,$blocks) = stat F;
my $if_mod_since = 0;
$if_mod_since = str2time($ENV{HTTP_IF_MODIFIED_SINCE})
if defined $ENV{HTTP_IF_MODIFIED_SINCE};
if ($if_mod_since > 0 && $if_mod_since <= $mtime) {
print "Status: 304 Not Modified\n\n";
} else {
print "Content-Type: $mime_type\n" if defined $mime_type;
print "Content-Length: ", $size, "\n";
print "Last-Modified: ", time2str($mtime), "\n";
print "\n";
print <F> unless $ENV{REQUEST_METHOD} eq 'HEAD';
}
exit 0;
#!/usr/bin/perl -wT
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2007 University of Utah and the Flux Group.
# All rights reserved.
#
use strict;
use Getopt::Std;
#
# Configure variables
#
my $TB = "@prefix@";
my $TBOPS = "@TBOPSEMAIL@";
my $USERNODE = "@USERNODE@";
my $SSH = "$TB/bin/sshtb -l root -host $USERNODE";
my $background = 0;
# un-taint path
$ENV{'PATH'} = '/bin:/usr/bin:/usr/local/bin';
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
# Turn off line buffering on output
$| = 1;
#
# Capture stdout and stderr to a file so if we die we can mail the output to
# testbed-ops
#
# XXX: Don't hardcode
my $logfile = "/tmp/write-vis-auth.$$";
use vars qw(*OLDOUT *OLDERR);
open OLDOUT, ">&STDOUT" or die "Can't dup STDOUT $!";
open OLDERR, ">&STDERR" or die "Can't dup STDERR $!";
open STDOUT, ">$logfile" or die "Can't open $logfile: $!";
open STDERR, ">&STDOUT" or die "Can't dup STDERR $!";
$SIG{__DIE__} = sub {
return unless defined $^S; # In Parser
return if $^S; # In Eval Block
local $_ = $_[0];
open STDOUT, ">&OLDOUT";
open STDERR, ">&OLDERR";
SENDMAIL($TBOPS, "write-vis-auth failed", $_, undef, undef, $logfile);
unlink $logfile;
TBScriptUnlock();
print STDERR "write-vis-auth failed, see testbed-ops mail\n";
exit(1);
};
#
# Load the Testbed support stuff.
#
use lib "@prefix@/lib";
use libdb;
use libtestbed;
if ((my $locked = TBScriptLock("write-vis-auth", 1)) != TBSCRIPTLOCK_OKAY()) {
exit(0)
if ($locked == TBSCRIPTLOCK_IGNORE);
die("Could not get the lock after a long time!\n");
}
# become root, needed for ssh
$< = $>;
my $db_result =
DBQueryFatal("select opskey, uid from login");
open O, "| $SSH $TB/libexec/write-vis-auth.proxy"
or die "ssh to ops failed: $!\n";
my $prev_opskey = '';
while (my ($opskey,$uid) = $db_result->fetchrow_array) {
$opskey = "00000000000000000000000000000000" if $opskey eq '';
print O "$opskey $uid\n";
}
close O;
die "ssh to ops failed: $!\n" if $!;
die "ssh to ops failed with exit code $?\n" if $? != 0;
unlink $logfile;
TBScriptUnlock();
exit(0);
#!/bin/sh
set -e
if [ "$USER" != "root" ]; then
echo "Must be root." 1>&2
exit 1
fi
TEMPFILE=`mktemp /var/run/exp-vis.XXXXXX`
cat > $TEMPFILE
mv $TEMPFILE /var/run/exp-vis.auth
......@@ -1495,6 +1495,8 @@ done
......@@ -1582,6 +1584,7 @@ PROTOGENI_CLEARINGHOUSE=0
PROTOGENI_DOMAIN="unknown"
STANDALONE_CLEARINGHOUSE=0
NODE_USAGE_SUPPORT=0
EXP_VIS_SUPPORT=0
NOSTACKMIB=0
#
......@@ -2192,17 +2195,17 @@ for ac_hdr in ulxmlrpcpp/ulxr_config.h
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
echo "configure:2195: checking for $ac_hdr" >&5
echo "configure:2199: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 2200 "configure"
#line 2204 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:2205: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
{ (eval echo configure:2209: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
......@@ -2241,17 +2244,17 @@ for ac_hdr in linux/videodev.h
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
echo "configure:2244: checking for $ac_hdr" >&5
echo "configure:2248: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 2249 "configure"
#line 2253 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:2254: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
{ (eval echo configure:2258: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
......@@ -2284,7 +2287,7 @@ done
# Extract the first word of "gtk-config", so it can be a program name with args.
set dummy gtk-config; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
echo "configure:2287: checking for $ac_word" >&5
echo "configure:2291: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_GTK_CONFIG'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
......@@ -2341,7 +2344,7 @@ ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftes
cross_compiling=$ac_cv_prog_cxx_cross
echo $ac_n "checking how to run the C++ preprocessor""... $ac_c" 1>&6
echo "configure:2344: checking how to run the C++ preprocessor" >&5
echo "configure:2348: checking how to run the C++ preprocessor" >&5
if test -z "$CXXCPP"; then
if eval "test \"`echo '$''{'ac_cv_prog_CXXCPP'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
......@@ -2354,12 +2357,12 @@ ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftes
cross_compiling=$ac_cv_prog_cxx_cross
CXXCPP="${CXX-g++} -E"
cat > conftest.$ac_ext <<EOF
#line 2357 "configure"
#line 2361 "configure"
#include "confdefs.h"
#include <stdlib.h>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:2362: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
{ (eval echo configure:2366: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
:
......@@ -2385,17 +2388,17 @@ echo "$ac_t""$CXXCPP" 1>&6
ac_safe=`echo "xercesc/dom/DOM.hpp" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for xercesc/dom/DOM.hpp""... $ac_c" 1>&6
echo "configure:2388: checking for xercesc/dom/DOM.hpp" >&5
echo "configure:2392: checking for xercesc/dom/DOM.hpp" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 2393 "configure"
#line 2397 "configure"
#include "confdefs.h"
#include <xercesc/dom/DOM.hpp>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:2398: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
{ (eval echo configure:2402: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
......@@ -2459,7 +2462,7 @@ fi
# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
# ./install, which can be erroneously created by make from ./install.sh.
echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
echo "configure:2462: checking for a BSD compatible install" >&5
echo "configure:2466: checking for a BSD compatible install" >&5
if test -z "$INSTALL"; then
if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
......@@ -2520,7 +2523,7 @@ esac
# Extract the first word of "rsync", so it can be a program name with args.
set dummy rsync; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
echo "configure:2523: checking for $ac_word" >&5
echo "configure:2527: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_path_RSYNC'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
......@@ -2771,6 +2774,7 @@ outfiles="$outfiles Makeconf GNUmakefile \
collab/cvstools/cvs.proxy collab/cvstools/cvs_ctrl \
collab/cvstools/cvsrepo_ctrl.proxy collab/cvstools/cvsrepo_ctrl \
collab/cvstools/webcvsrepo_ctrl \
collab/exp-vis/GNUmakefile collab/exp-vis/fetch-vis \
node_usage/GNUmakefile node_usage/mk-plots \
node_usage/analy node_usage/publish \
node_usage/analy2 node_usage/refresh \
......@@ -3059,6 +3063,7 @@ s%@STANDALONE_CLEARINGHOUSE@%$STANDALONE_CLEARINGHOUSE%g
s%@GMAP_API_KEY@%$GMAP_API_KEY%g
s%@NODE_USAGE_SUPPORT@%$NODE_USAGE_SUPPORT%g
s%@NOSTACKMIB@%$NOSTACKMIB%g
s%@EXP_VIS_SUPPORT@%$EXP_VIS_SUPPORT%g
s%@TBOPSEMAIL@%$TBOPSEMAIL%g
s%@TBOPSEMAIL_NOSLASH@%$TBOPSEMAIL_NOSLASH%g
s%@TBROBOCOPSEMAIL@%$TBROBOCOPSEMAIL%g
......
......@@ -217,6 +217,7 @@ AC_SUBST(STANDALONE_CLEARINGHOUSE)
AC_SUBST(GMAP_API_KEY)
AC_SUBST(NODE_USAGE_SUPPORT)
AC_SUBST(NOSTACKMIB)
AC_SUBST(EXP_VIS_SUPPORT)
#
# Offer both versions of the email addresses that have the @ escaped
......@@ -302,6 +303,7 @@ PROTOGENI_CLEARINGHOUSE=0
PROTOGENI_DOMAIN="unknown"
STANDALONE_CLEARINGHOUSE=0
NODE_USAGE_SUPPORT=0
EXP_VIS_SUPPORT=0
NOSTACKMIB=0
#
......@@ -1017,6 +1019,7 @@ outfiles="$outfiles Makeconf GNUmakefile \
collab/cvstools/cvs.proxy collab/cvstools/cvs_ctrl \
collab/cvstools/cvsrepo_ctrl.proxy collab/cvstools/cvsrepo_ctrl \
collab/cvstools/webcvsrepo_ctrl \
collab/exp-vis/GNUmakefile collab/exp-vis/fetch-vis \
node_usage/GNUmakefile node_usage/mk-plots \
node_usage/analy node_usage/publish \
node_usage/analy2 node_usage/refresh \
......
......@@ -66,6 +66,7 @@ OPSDBSUPPORT=1
PELABSUPPORT=1
PLABSUPPORT=1
PLAB_ROOTBALL="plabroot-21.tar.bz2"
EXP_VIS_SUPPORT=1
# Do not turn this on unless you talk to Utah first!
PROTOGENI_SUPPORT=1
# If you are not the main Emulab site in Utah, change this!
......
......@@ -34,6 +34,7 @@ $CVSSUPPORT = @CVSSUPPORT@;
$MAILMANSUPPORT = @MAILMANSUPPORT@;
$CHATSUPPORT = @CHATSUPPORT@;
$PROTOGENI = @PROTOGENI_SUPPORT@;
$EXP_VIS = @EXP_VIS_SUPPORT@;
$ISOLATEADMINS = @ISOLATEADMINS@;
$CONTROL_NETWORK= "@CONTROL_NETWORK@";
$CONTROL_NETMASK= "@CONTROL_NETMASK@";
......
......@@ -62,6 +62,13 @@ if ($EXPOSETEMPLATES) {
#
# For the Sajax Interface
#
$USER_VIS_URL = "http://$USERNODE/exp-vis/$pid/$eid/";
$HAVE_USER_VIS = 0;
$whocares = null;
if ($EXP_VIS && CHECKURL($USER_VIS_URL, $whocares)) {
$HAVE_USER_VIS = 1;
}
function FreeNodeHtml()
{
global $this_user, $experiment;
......@@ -87,6 +94,7 @@ function ModifyAnno($newtext)
function Show($which, $arg1, $arg2)
{
global $experiment, $instance, $uid, $TBSUEXEC_PATH, $TBADMINGROUP;
global $USER_VIS_URL;
$pid = $experiment->pid();
$eid = $experiment->eid();
$html = "";
......@@ -227,6 +235,11 @@ function Show($which, $arg1, $arg2)
$html .= " onclick=\"SaveNS();\">";
$html .= "Save</button>\n";
}
elseif ($which == "uservis") {
ob_start();
$html .= "<iframe src=\"$USER_VIS_URL\" width=\"100%\" height=600 id=\"vis-iframe\"></iframe>";
ob_end_clean();
}
return $html;
}
......@@ -693,6 +706,12 @@ if ($instance) {
"id=\"li_anno\" onclick=\"Show('anno');\">".
"Annotation</a></li>\n";
}
if ($HAVE_USER_VIS) {
echo "<li>
<a href=\"#E\" class=topnavbar onfocus=\"this.hideFocus=true;\" ".
"id=\"li_uservis\" onclick=\"Show('uservis');\">".
"User Visualization</a></li>\n";
}
echo "</ul>\n";
echo "</div>\n";
echo "<div align=center id=topnavbarbottom>&nbsp</div>\n";
......
......@@ -109,6 +109,12 @@ if ($PUBSUPPORT) {
}
}
$vis_html = null;
$whocares = null;
if ($EXP_VIS && CHECKURL("http://$USERNODE/proj-vis/$pid/", $whocares)) {
$vis_html = "<iframe src=\"http://$USERNODE/proj-vis/$pid/\" width=\"100%\" height=600 id=\"vis-iframe\"></iframe>";
}
#
# Show number of PCS
#
......@@ -200,6 +206,12 @@ if ($papers_html) {
"id=\"li_papers\" onclick=\"Show('papers');\">".
"Publications</a></li>\n";
}
if ($vis_html) {
echo "<li>
<a href=\"#G\" class=topnavbar onfocus=\"this.hideFocus=true;\" ".
"id=\"li_vis\" onclick=\"Show('vis');\">".
"Visualization</a></li>\n";
}
echo "</ul>\n";
echo "</div>\n";
echo "<div align=center id=topnavbarbottom>&nbsp</div>\n";
......@@ -223,6 +235,9 @@ if ($isadmin && $stats_html) {
if ($papers_html) {
echo "<div class=invisible id=\"div_papers\">$papers_html</div>";
}
if ($vis_html) {
echo "<div class=invisible id=\"div_vis\">$vis_html</div>";
}
SUBPAGEEND();
#
......
......@@ -952,6 +952,7 @@ function DOLOGIN_MAGIC($uid, $uid_idx, $email = null, $adminon = 0)
global $TBMAIL_OPS, $TBMAIL_AUDIT, $TBMAIL_WWW;
global $WIKISUPPORT, $WIKICOOKIENAME;
global $BUGDBSUPPORT, $BUGDBCOOKIENAME, $TRACSUPPORT, $TRACCOOKIENAME;
global $TBLIBEXEC_DIR, $EXP_VIS;
# Caller makes these checks too.
if (!TBvalid_uid($uid)) {
......@@ -970,10 +971,11 @@ function DOLOGIN_MAGIC($uid, $uid_idx, $email = null, $adminon = 0)
$timeout = $now + $TBAUTHTIMEOUT;
$hashkey = GENHASH();
$crc = bin2hex(mhash(MHASH_CRC32, $hashkey));
$opskey = GENHASH();
DBQueryFatal("replace into login ".
" (uid,uid_idx,hashkey,hashhash,timeout,adminon) values ".
" ('$uid', $uid_idx, '$hashkey', '$crc', '$timeout', $adminon)");
" (uid,uid_idx,hashkey,hashhash,timeout,adminon,opskey) values ".
" ('$uid', $uid_idx, '