diff --git a/checkin_notes b/checkin_notes
index feff535114..d195a4abce 100644
--- a/checkin_notes
+++ b/checkin_notes
@@ -11092,3 +11092,16 @@ Charlie 16 Nov 2007
boinc.xcodeproj/
project.pbxproj
BuildMacBOINC.sh
+
+David 16 Nov 2007
+ - added optional code for user-submitted jobs (from M.F. Somers)
+ - added some scripts in ops/ for managing HR, and for blocking hosts.
+ (from M.F. Somers; these should be documented in the WIki
+ and perhaps added to ops/index.php)
+
+ html/
+ ops/
+ hrclass_summary.php
+ reset_hrclass.php
+ block_host.php
+ queue/*
diff --git a/html/ops/block_host.php b/html/ops/block_host.php
new file mode 100644
index 0000000000..6046ecbced
--- /dev/null
+++ b/html/ops/block_host.php
@@ -0,0 +1,34 @@
+ 0) {
+ $result = mysql_query("UPDATE host SET max_results_day=1 WHERE id=".$hostid);
+}
+
+echo $title;
+
+admin_page_tail();
+
+?>
diff --git a/html/ops/hrclass_summary.php b/html/ops/hrclass_summary.php
new file mode 100644
index 0000000000..86a08264e3
--- /dev/null
+++ b/html/ops/hrclass_summary.php
@@ -0,0 +1,84 @@
+count;
+}
+
+function make_reset_url( $hr_class ) {
+ return ("".$hr_class."");
+}
+
+db_init();
+
+$timestr = time_str(time(0));
+$title = "hr_class summary list at ".$timestr;
+
+admin_page_head( $title );
+
+start_table();
+
+row4( "hr_class", "System", "CPU", "# unsent results" );
+
+$unsentresults = get_mysql_count( 0 );
+row4( make_reset_url( 0 ), $system_string[ 128 ], $cpu_string[ 0 ], $unsentresults );
+
+for( $system = 2; $system < 6; ++$system ) {
+ for( $cpu = 1; $cpu < 22; ++$cpu ) {
+ $hr_class=128*$system+$cpu;
+
+ $unsentresults = get_mysql_count( $hr_class );
+
+ row4( make_reset_url( $hr_class ), $system_string[ $system * 128 ], $cpu_string[ $cpu ], $unsentresults );
+ }
+}
+
+end_table();
+
+admin_page_tail();
+
+?>
diff --git a/html/ops/reset_hrclass.php b/html/ops/reset_hrclass.php
new file mode 100644
index 0000000000..6007d0b1e1
--- /dev/null
+++ b/html/ops/reset_hrclass.php
@@ -0,0 +1,35 @@
+
diff --git a/html/queue/README b/html/queue/README
new file mode 100644
index 0000000000..810b9b4e59
--- /dev/null
+++ b/html/queue/README
@@ -0,0 +1,8 @@
+// This directory contains a system that allows
+// users to submit jobs to a BOINC project.
+//
+// Major revisions may be required to make this work
+// (and to make it secure) on your project.
+// Please read and understand all the code before using it.
+//
+// Contributed by Dr. M.F. Somers, Leiden University
diff --git a/html/queue/create_queue.sql b/html/queue/create_queue.sql
new file mode 100644
index 0000000000..d6d02b83ee
--- /dev/null
+++ b/html/queue/create_queue.sql
@@ -0,0 +1,20 @@
+CREATE TABLE q_list (
+ id integer NOT NULL auto_increment,
+ user integer NOT NULL default '0',
+ workunit integer NOT NULL default '0',
+ PRIMARY KEY (id)
+) TYPE=MyISAM;
+
+CREATE TABLE q_restricted_apps (
+ id integer NOT NULL auto_increment,
+ appid integer NOT NULL default '0',
+ PRIMARY KEY (id)
+) TYPE=MyISAM;
+
+CREATE TABLE q_users (
+ id integer NOT NULL auto_increment,
+ user integer NOT NULL default '0',
+ app integer NOT NULL default '0',
+ qmax integer NOT NULL default '0',
+ PRIMARY KEY (id)
+) TYPE=MyISAM;
diff --git a/html/queue/inc/queue.inc b/html/queue/inc/queue.inc
new file mode 100644
index 0000000000..d54cc76ad1
--- /dev/null
+++ b/html/queue/inc/queue.inc
@@ -0,0 +1,145 @@
+ id );
+ return $alljobs;
+}
+
+function nr_of_jobs_of_user( $user )
+{
+ $njobs = mysql_num_rows( all_jobs_of_user( $user ) );
+ return $njobs;
+}
+
+function workunit_name( $workunit )
+{
+ if( ( $pos = strpos( $workunit -> name, "_queue" ) ) === false )
+ $workunitname = $workunit -> name;
+ else
+ $workunitname = substr( $workunit -> name, 0, $pos );
+ return $workunitname;
+}
+
+function workunit_status_string( $workunit )
+{
+ $status = "UNKNOWN";
+ if( $workunit -> canonical_resultid )
+ $status = "finished";
+ else
+ {
+ if( $workunit -> hr_class )
+ $status = "running";
+ else
+ $status = "queued";
+ }
+ if( $workunit -> error_mask )
+ {
+ $status = "ERROR";
+ if( $workunit -> error_mask & 16 )
+ $status = "CANCELED";
+ }
+ return $status;
+}
+
+function max_nr_of_jobs_of_user( $user )
+{
+ $allapps = mysql_query( "SELECT * FROM q_users WHERE user=".$user -> id );
+ $napps = mysql_num_rows( $allapps );
+
+ if( $napps > 0 )
+ for( $count = $index = 0; $index < $napps; ++$index )
+ {
+ $row = mysql_fetch_object( $allapps );
+ if( $row )
+ $count += $row -> qmax;
+ }
+ else
+ $count = 5;
+
+ mysql_free_result( $allapps );
+ return $count;
+}
+
+function nr_of_jobs_for_user_for_app( $user, $app )
+{
+ $qmaxresult = mysql_query( "SELECT qmax FROM q_users WHERE user=".$user -> id." AND app=".$app -> id );
+ if( mysql_num_rows( $qmaxresult ) < 1 )
+ {
+ $qrestrictedapps = mysql_query( "SELECT * FROM q_restricted_apps WHERE appid=".$app -> id );
+ if( mysql_num_rows( $qrestrictedapps ) < 1 )
+ $nr = 5;
+ else
+ $nr = 0;
+ mysql_free_result( $qrestrictedapps );
+ }
+ else
+ {
+ $object = mysql_fetch_object( $qmaxresult );
+ $nr = $object -> qmax;
+ }
+ mysql_free_result( $qmaxresult );
+ return $nr;
+}
+
+function nr_of_submitted_jobs_for_user_for_app( $user, $app )
+{
+ $alljobs = mysql_query( "SELECT * FROM q_list WHERE user=".$user -> id );
+ $nrofjobs = mysql_num_rows( $alljobs );
+
+ for( $nr = $index = 0; $index < $nrofjobs; ++$index )
+ {
+ $job = mysql_fetch_object( $alljobs );
+ $workunit = mysql_fetch_object( mysql_query( "SELECT * FROM workunit WHERE id=".$job -> workunit ) );
+
+ if( $workunit -> appid == $app -> id )
+ $nr = $nr + 1;
+ }
+
+ mysql_free_result( $alljobs );
+ return $nr;
+}
+
+function exit_with_text( $text )
+{
+ start_table();
+ row1( "".$text."" );
+ row1( "Commands" );
+ row2( "", 'Go back to your queue' );
+ row2( "", 'Log out' );
+ end_table();
+ page_tail();
+ exit;
+}
+
+function fan_out_dir( $filename, $fanoutnr )
+{
+ $dir = dechex( hexdec( substr( md5( $filename ), 1, 7 ) ) % $fanoutnr );
+ return $dir;
+}
+
+function row5($xx, $xy, $yx, $yy, $zz ) {
+ echo "
$xx | $xy | "
+ . "$yx | $yy | $zz |
+ ";
+}
+
+function row6($xx, $xy, $yx, $yy, $zz, $xz ) {
+ echo "$xx | $xy | "
+ . "$yx | $yy | $zz | "
+ . "$xz |
";
+}
+
+function remove_tags( $xml, $tag )
+{
+ $newxml = $xml;
+ while( ( $pos = strpos( $newxml, $tag ) ) !== false )
+ $newxml = substr( $newxml, 0, $pos ).substr( $newxml, $pos + strlen( $tag ) );
+ return $newxml;
+}
+
+?>
diff --git a/html/queue/inc/user.inc b/html/queue/inc/user.inc
new file mode 100644
index 0000000000..57c5b16b17
--- /dev/null
+++ b/html/queue/inc/user.inc
@@ -0,0 +1,364 @@
+total_credit = 0.0;
+ $p->expavg_credit = 0.0;
+ while (!feof($f)) {
+ $buf = fgets($f);
+ if (strstr($buf, "")) break;
+ if ($x = parse_element($buf, "")) {
+ $p->name = $x;
+ }
+ if ($x = parse_element($buf, "")) {
+ $p->name = $x;
+ }
+ if ($x = parse_element($buf, "")) {
+ $p->url = $x;
+ }
+ if ($x = parse_element($buf, "")) {
+ $p->total_credit = $x;
+ }
+ if ($x = parse_element($buf, "")) {
+ $p->expavg_credit = $x;
+ }
+ if ($x = parse_element($buf, "")) {
+ $p->id = $x;
+ }
+ if ($x = parse_element($buf, "")) {
+ $p->country = $x;
+ }
+ if ($x = parse_element($buf, "")) {
+ $p->team_id = $x;
+ }
+ if ($x = parse_element($buf, "")) {
+ $p->team_name = $x;
+ }
+ if ($x = parse_element($buf, "")) {
+ $p->create_time = $x;
+ }
+ }
+ return $p;
+}
+
+function parse_user($f, $user) {
+ $user->projects = array();
+ while (!feof($f)) {
+ $buf = fgets($f);
+ if (strstr($buf, "")) break;
+ if (strstr($buf, "")) {
+ $user->projects[] = parse_project($f);
+ }
+ }
+ return $user;
+}
+
+function get_other_projects($user) {
+ $cpid = md5($user->cross_project_id . $user->email_addr);
+ $url = "http://boinc.netsoft-online.com/get_user.php?cpid=$cpid";
+ $f = fopen($url, "r");
+ if (!$f) {
+ return $user;
+ }
+ $u = parse_user($f, $user);
+ fclose($f);
+ return $u;
+}
+
+function show_project($project) {
+ if ($project->url == "http://www.worldcommunitygrid.org/") {
+ $x = $project->name;
+ } else {
+ $x = "url"."show_user.php?userid=$project->id\">$project->name";
+ }
+ echo "
+ $x |
+ ".number_format($project->total_credit, 0)." |
+ ".number_format($project->expavg_credit, 0)." |
+ ".date_str($project->create_time)." |
+
+ ";
+}
+
+function cmp($a, $b) {
+ if ($a->expavg_credit == $b->expavg_credit) return 0;
+ return ($a->expavg_credit < $b->expavg_credit)? 1 : -1;
+}
+
+function show_other_projects($user, $personal) {
+ if (count($user->projects) > 1) {
+ usort($user->projects, "cmp");
+ if ($personal) {
+ echo "Projects in which you are participating
";
+ } else {
+ echo "Projects in which $user->name is participating
";
+ }
+ start_table();
+ row_heading_array(array(
+ "Project
Click for user page", "Total credit", "Average credit", "Since"
+ ));
+ foreach($user->projects as $project) {
+ show_project($project);
+ }
+ end_table();
+ }
+}
+
+function pending_credit($user) {
+ $result = mysql_query("select sum(claimed_credit) as total from result where userid=$user->id and (validate_state=0 or validate_state=4)");
+ $foobar = mysql_fetch_object($result);
+ if (!$foobar) return 0;
+ mysql_free_result($result);
+ return $foobar->total;
+}
+
+function total_posts($user) {
+ $result = mysql_query(
+ "select count(id) as total from post where user=$user->id"
+ );
+ if (!$result) return 0;
+ $foobar = mysql_fetch_object($result);
+ mysql_free_result($result);
+ return $foobar->total;
+}
+
+function show_credit($user) {
+ row2(tr(TOTAL_CREDIT), format_credit($user->total_credit));
+ row2(tr(EXPAVG_CREDIT), format_credit($user->expavg_credit));
+ project_user_credit($user);
+}
+
+require_once("../inc/stats_sites.inc");
+// show dynamic user info (private)
+//
+function show_user_stats_private($user) {
+ global $cpid_stats_sites;
+ row1("Work done");
+ row2(PROJECT." member since", date_str($user->create_time));
+ show_credit($user);
+ $config = get_config();
+ if (parse_bool($config, "show_results")) {
+ row2("Pending credit", "View");
+ }
+ row2("Computers on this account",
+ "View"
+ );
+ row2("Results", "id>View");
+ $cpid = md5($user->cross_project_id . $user->email_addr);
+ $x = "";
+ shuffle($cpid_stats_sites);
+ foreach ($cpid_stats_sites as $site) {
+ $name = $site[0];
+ $y = sprintf($site[1], $cpid);
+ $x .= "$name
";
+ }
+ $x .= "
Cross-project ID: $cpid\n";
+ row2("Cross-project statistics", $x);
+ row2("Stats on your cell phone", URL_BASE."userw.php?id=$user->id");
+ row2("Account number
Used in URLs", $user->id);
+}
+
+// show static user info (private)
+//
+function show_user_info_private($user) {
+ if (is_valid_email_addr($user->email_addr)) {
+ $email_text = $user->email_addr;
+ } else {
+ $email_text = "Verification pending";
+ }
+
+ row1("Account information");
+ row2("Email address
", $email_text);
+ row2("Name", $user->name);
+ if (strlen($user->url)) {
+ $x = "http://$user->url";
+ } else {
+ $x = "none";
+ }
+ row2("URL", $x);
+ row2("Country", $user->country);
+ row2("Postal code", $user->postal_code);
+ row2("Change", "email address | password | other account info");
+ row2("", "Show private queue");
+ row2("", "authenticator).">Log out");
+
+ row1("Community");
+
+ $sql = "SELECT * FROM profile WHERE userid = ".$user->id;
+ $result = mysql_query($sql);
+ if (mysql_num_rows($result) != 0) {
+ $x = "id>View or edit | Delete";
+ } else {
+ $x = "Create";
+ }
+ row2("Profile", $x);
+ $tot = total_posts($user);
+ if ($tot) {
+ row2("Message boards", "id>$tot posts");
+ }
+
+ row2("Private messages", pm_notification($user));
+
+ row1("Teams");
+ if ($user->teamid) {
+ $team = lookup_team($user->teamid);
+ $x = "id>$team->name
+ | Quit team";
+ if ($team->userid == $user->id) {
+ $x .= " | management functions";
+ }
+ row2("Team", $x);
+ } else {
+ row2("Team", "None (find a team)");
+ }
+
+ $team_founder = lookup_team_founder($user->id);
+ if ($team_founder) {
+ while ($res = mysql_fetch_object($team_founder)) {
+ if ($res->id != $user->teamid) {
+ row2("founder of", "id>$res->name | id."\">Change team founder");
+ }
+ }
+ }
+
+ row1("Preferences");
+ row2(
+ "General preferences
specify when and how BOINC uses your computer",
+ "View or edit"
+ );
+ row2(PROJECT." preferences
control resource share and customize graphics",
+ "View or edit"
+ );
+ row2("Message board preferences
configure features and appearance of message boards",
+ "View or edit"
+ );
+}
+
+// show summary of dynamic and static info (public)
+//
+function show_user_summary_public($user) {
+ row2(PROJECT." member since", date_str($user->create_time));
+ row2("Country", $user->country);
+ if (strlen($user->url)) {
+ row2("URL", "url\">http://$user->url");
+ }
+ show_credit($user);
+
+ if ($user->teamid && ($team = lookup_team($user->teamid))) {
+ row2("Team", "id\">$team->name");
+ } else {
+ row2("Team", "None");
+ }
+ if ($user->show_hosts) {
+ row2("Computers", "id\">View");
+ } else {
+ row2("Computers", "hidden");
+ }
+ $tot = total_posts($user);
+ if ($tot) {
+ row2("Message boards", "id\">$tot posts");
+ }
+
+ if ($user->donated == 1) {
+ if (file_exists("../project/donations.inc")) {
+ require_once("../project/donations.inc");
+ $x .= DONATION_LINK;
+ row2("Donor",$x);
+ }
+ }
+
+ row2("Contact", "id."\">Send private message");
+}
+
+function show_profile_link($user) {
+ if ($user->has_profile) {
+ row2("Profile", "id\">View");
+ }
+}
+
+// show a summary of the user.
+// NOTE: This is intended to be shown only to that user.
+// it has info that other users aren't supposed to see
+
+function show_user_page_private($user) {
+ $config = get_config();
+ start_table("width=100%");
+ show_user_info_private($user);
+ show_user_stats_private($user);
+
+ // Does this project accept donations? Then put in a project specific
+ // function to show user donation information in ../project/donations.inc
+ //
+ if (parse_bool($config, "donations_accepted")) {
+ if (file_exists("../project/donations.inc")) {
+ require_once("../project/donations.inc");
+ show_user_donations_private($user);
+ }
+ }
+ end_table();
+}
+
+function user_table_start($sort_by) {
+ start_table();
+ echo "
+
+ ".tr(USER_TABLE_RANK)." |
+ ".tr(USER_TABLE_NAME)." |
+ ";
+ if ($sort_by == "total_credit") {
+ echo "
+ ".tr(EXPAVG_CREDIT)." |
+ ".tr(TOTAL_CREDIT)." |
+ ";
+ } else {
+ echo "
+ ".tr(EXPAVG_CREDIT)." |
+ ".tr(TOTAL_CREDIT)." |
+ ";
+ }
+ echo "
+ ".tr(USER_TABLE_COUNTRY)." |
+ ".tr(USER_TABLE_PTIME)." |
+
+ ";
+}
+
+function show_user_row($user, $i) {
+ echo "
+
+ $i |
+ ", user_links($user), " |
+ ", format_credit($user->expavg_credit), " |
+ ", format_credit($user->total_credit), " |
+ ", $user->country, " |
+ ", time_str($user->create_time)," |
+
+ ";
+}
+
+// decay a user's average credit
+//
+function user_decay_credit($user) {
+ $avg = $user->expavg_credit;
+ $avg_time = $user->expavg_time;
+ $now = time(0);
+ update_average($now, 0, 0, $avg, $avg_time);
+ mysql_query("update user set expavg_credit=$avg, expavg_time=$now where id=$user->id");
+
+}
+// if the user hasn't received new credit for ndays,
+// decay its average and return true
+//
+function user_inactive_ndays($user, $ndays) {
+ $diff = time() - $user->expavg_time;
+ if ($diff > $ndays*86400) {
+ user_decay_credit($user);
+ return true;
+ }
+ return false;
+}
+
+?>
diff --git a/html/queue/ops/ops_queue_remove_job.php b/html/queue/ops/ops_queue_remove_job.php
new file mode 100644
index 0000000000..9d85cb6374
--- /dev/null
+++ b/html/queue/ops/ops_queue_remove_job.php
@@ -0,0 +1,67 @@
+id ) );
+$user = mysql_fetch_object( mysql_query( "SELECT * FROM user WHERE id=".$job -> user ) );
+$title = "Deleting job '".workunit_name( $workunit )."' (".$workunitid.") of ".$user -> name." at ".$timestr;
+
+$jobname = workunit_name( $workunit );
+
+$config = get_config();
+
+$jobstatusstring = workunit_status_string( $workunit );
+$jobsubmittime = time_str( $workunit -> create_time );
+
+admin_page_head( $title );
+start_table();
+row1( "Job speciffics" );
+row2( "Job submit time: ", $jobsubmittime );
+row2( "Job name: ", $jobname );
+row2( "Old job status: ", $jobstatusstring );
+
+$allresults = mysql_query( "SELECT * FROM result WHERE workunitid=".$workunitid );
+$nrofresults = mysql_num_rows( $allresults );
+
+for( $resultindex = 0; $resultindex < $nrofresults; ++$resultindex )
+{
+ $result = mysql_fetch_object( $allresults );
+ $result -> xml_doc_in = remove_tags( $result -> xml_doc_in, "" );
+ $query = "UPDATE result SET xml_doc_in='".$result -> xml_doc_in."' WHERE id=".$result -> id;
+ mysql_query( $query );
+}
+
+$query = "UPDATE result SET server_state=5,outcome=5 WHERE server_state=2 AND workunitid=".$workunit -> id;
+mysql_query( $query );
+
+$workunit -> xml_doc = remove_tags( $workunit -> xml_doc, "" );
+$query = "UPDATE workunit SET xml_doc='".$workunit -> xml_doc."' WHERE id=".$workunit -> id;
+mysql_query( $query );
+
+$query = "UPDATE workunit SET error_mask=error_mask|16,transition_time=".time(0)." WHERE id=".$workunit -> id;
+mysql_query( $query );
+
+$query = "DELETE FROM q_list WHERE id=".$job -> id;
+mysql_query( $query );
+
+row2( "New job status: ", "deleted" );
+
+row1( "Commands" );
+row2( "", 'Go back to queue' );
+
+end_table();
+admin_page_tail();
+
+?>
diff --git a/html/queue/ops/ops_queue_show_job.php b/html/queue/ops/ops_queue_show_job.php
new file mode 100644
index 0000000000..57201f30b6
--- /dev/null
+++ b/html/queue/ops/ops_queue_show_job.php
@@ -0,0 +1,126 @@
+id ) );
+$user = mysql_fetch_object( mysql_query( "SELECT * FROM user WHERE id=".$job -> user ) );
+$title = "Job '".workunit_name( $workunit )."' (".$workunitid.") of ".$user -> name." at ".$timestr;
+
+$jobname = workunit_name( $workunit );
+
+$config = get_config();
+
+$jobapplication = mysql_fetch_object( mysql_query( "SELECT * FROM app WHERE id=".$workunit -> appid ) );
+$jobapplicationname = $jobapplication -> name;
+$jobapplicationfriendlyname = $jobapplication -> user_friendly_name;
+$jobfops = $workunit -> rsc_fpops_est;
+$jobmem = $workunit -> rsc_memory_bound;
+$jobdisk = $workunit -> rsc_disk_bound;
+$jobstatusstring = workunit_status_string( $workunit );
+
+$coloredjobstatusstring = $jobstatusstring;
+if( $jobstatusstring == "running" ) $coloredjobstatusstring = "".$jobstatusstring."";
+if( $jobstatusstring == "queued" ) $coloredjobstatusstring = "".$jobstatusstring."";
+if( $jobstatusstring == "ERROR" ) $coloredjobstatusstring = "".$jobstatusstring."";
+
+$jobsubmittime = time_str( $workunit -> create_time );
+
+$workunitidstring = " workunit.">".$job -> workunit."";
+
+$jobinputurl = parse_element( $workunit -> xml_doc, "" );
+$jobinputurl = parse_element( $jobinputurl, "" );
+$jobinput = parse_element( $workunit -> xml_doc, "" );
+$jobinput = parse_element( $jobinput, "" );
+
+admin_page_head( $title );
+start_table();
+
+row1( "Job speciffics" );
+row2( "Job status: ", $coloredjobstatusstring );
+row2( "Job application: ", $jobapplicationfriendlyname );
+row2( "Job submit time: ", $jobsubmittime );
+row2( "Job name: ", $jobname );
+row2( "Job id: ", $workunitidstring );
+row2( "Job estimated time to complete: ", floor((float)($jobfops)/92254963740)." min. " );
+row2( "Job estimated memory usage: ", floor((float)($jobmem)/1048576)." Mb. " );
+row2( "Job estimated disk usage: ", floor((float)($jobdisk)/1048576)." Mb. " );
+row2( "Job input file:", ' '.$jobinput.'' );
+
+if( ( $jobstatusstring == "finished" ) || ( $jobstatusstring == "ERROR" ) )
+{
+ if( $jobstatusstring != "finished" )
+ {
+ $resultunitquery = mysql_query( "SELECT * FROM result WHERE workunitid=".$workunit -> id );
+ $nrofresults = mysql_num_rows( $resultunitquery );
+
+ for( $index = 0; $index < $nrofresults; ++$index )
+ {
+ $resultunit = mysql_fetch_object( $resultunitquery );
+
+ $jobstderr = parse_element( $resultunit -> stderr_out, "" );
+
+ if( $jobstderr )
+ {
+ row1( "Error output of this job" );
+ row2( "", $jobstderr );
+ }
+ }
+ }
+ else
+ {
+ $resultunit = mysql_fetch_object( mysql_query( "SELECT * FROM result WHERE id=".$workunit -> canonical_resultid ) );
+
+ $xmldoc = $resultunit -> xml_doc_out;
+
+ $nroffiles = 0;
+ $cursor = 0;
+ while( $tempfileinfo = parse_next_element( $xmldoc, "", &$cursor ) )
+ $outputfiles[ $nroffiles++ ] = parse_element( $tempfileinfo, "" );
+
+ if( $nroffiles >= 1 )
+ {
+ $fanoutnr = parse_config( $config, "" );
+ row1( "Output of this job" );
+ row2( "Number of output files of job: ", $nroffiles );
+ for( $index = 0; $index < $nroffiles; ++$index )
+ {
+ $filename = $outputfiles[ $index ];
+ $url = "upload/".fan_out_dir( $filename, $fanoutnr )."/".$filename;
+ $outputfilelink = ''.$filename.'';
+ row2( "Output file ".($index+1).": ", $outputfilelink );
+ }
+ }
+
+ $jobstderr = parse_element( $resultunit -> stderr_out, "" );
+
+ if( $jobstderr )
+ {
+ row1( "Error output of this job" );
+ row2( "", $jobstderr );
+ }
+ }
+}
+
+$max_jobs = max_nr_of_jobs_of_user( $user );
+$njobs = nr_of_jobs_of_user( $user );
+
+row1( "Commands" );
+row2( "", 'Kill or Remove this job' );
+row2( "", 'Go back to queue' );
+
+end_table();
+
+admin_page_tail();
+?>
diff --git a/html/queue/ops/ops_queue_show_queue.php b/html/queue/ops/ops_queue_show_queue.php
new file mode 100644
index 0000000000..8f35d4dd16
--- /dev/null
+++ b/html/queue/ops/ops_queue_show_queue.php
@@ -0,0 +1,71 @@
+ 1 )
+ row1( "There are ".$njobs." jobs listed !
" );
+ else
+ row1( "There is only one job listed !
" );
+
+ end_table();
+ start_table();
+
+ row6( "Job #", "User", "Job submit time", "Job status", "Job name", "Job ID" );
+
+ for( $jobindex = 0; $jobindex < $njobs; ++$jobindex )
+ {
+ $workunit = mysql_fetch_object( $alljobs );
+
+ $prefix = '';
+ $workunitname = $prefix.workunit_name( $workunit ).'';
+ $workunitidstr = "".$workunit -> id."";
+ $status = workunit_status_string( $workunit );
+ $jobsubmittime = time_str( $workunit -> create_time );
+
+ if( $status != "CANCELED" )
+ {
+ if( $status == "running" ) $status = "".$status."";
+ if( $status == "queued" ) $status = "".$status."";
+
+ $job = mysql_fetch_object( mysql_query( "SELECT * FROM q_list WHERE workunit=".$workunit->id ) );
+ $user = mysql_fetch_object( mysql_query( "SELECT * FROM user WHERE id=".$job -> user ) );
+ $jobusername = "".$user -> name."";
+ }
+ else
+ {
+ $jobusername = "UNKNOWN";
+ $status = "CANCELED";
+ $workunitname = workunit_name( $workunit );
+ }
+
+ row6( $jobindex+1, $jobusername, $jobsubmittime, $status, $workunitname, $workunitidstr );
+ }
+
+}
+else
+ row1("There are NO jobs listed !
");
+
+end_table();
+
+admin_page_tail();
+
+?>
diff --git a/html/queue/user/queue_new_job_form.php b/html/queue/user/queue_new_job_form.php
new file mode 100644
index 0000000000..36d658516b
--- /dev/null
+++ b/html/queue/user/queue_new_job_form.php
@@ -0,0 +1,90 @@
+ name." at ".$timestr;
+
+page_head( $title );
+
+$appresult = mysql_query( "SELECT * FROM app" );
+$nrofapps = mysql_num_rows( $appresult );
+
+if( $nrofapps )
+{
+
+ $selection = "";
+ for( $appindex = 0; $appindex < $nrofapps; ++$appindex )
+ {
+ $app = mysql_fetch_object( $appresult );
+
+ $appqmax = nr_of_jobs_for_user_for_app( $user, $app );
+ $appsubmitted = nr_of_submitted_jobs_for_user_for_app( $user, $app );
+
+ if( $appqmax > $appsubmitted )
+ $selection = $selection.'';
+ }
+
+ if( $selection != "" )
+ {
+
+ echo '';
+
+ }
+ else
+ exit_with_text( "You are not allowed to submit any jobs !" );
+
+}
+
+page_tail();
+
+?>
diff --git a/html/queue/user/queue_new_job_form_action.php b/html/queue/user/queue_new_job_form_action.php
new file mode 100644
index 0000000000..9b0345c1e1
--- /dev/null
+++ b/html/queue/user/queue_new_job_form_action.php
@@ -0,0 +1,154 @@
+" );
+$user = get_logged_in_user();
+
+$jobapplicationname = mysql_fetch_object( mysql_query( "SELECT * FROM app WHERE id=".$jobapplication ) );
+$app = $jobapplicationname;
+$jobapplicationfriendlyname = $jobapplicationname -> user_friendly_name;
+$jobapplicationname = $jobapplicationname -> name;
+
+$title = "New job for '".$jobname."' ".$user -> name." at ".$timestr;
+page_head( $title );
+
+start_table();
+row1( "Job speciffics" );
+row2( "Job application: ", $jobapplicationfriendlyname );
+row2( "Job name: ", $jobname );
+row2( "Job estimated time to complete: ", floor( ( float )( $jobfops ) / 92254963740 )." min. " );
+row2( "Job estimated memory usage: ", floor( ( float )( $jobmem ) / 1048576 )." Mb. " );
+row2( "Job estimated disk usage: ", floor( ( float )( $jobdisk ) / 1048576 )." Mb. " );
+row2( "Job input:", '' );
+end_table();
+
+if( ( $jobname == "" ) || strpos( $jobname, "queue" ) || strpos( $jobname, " " ) ||
+ strpos( $jobname, '"' ) || strpos( $jobname, "'" ) || strpos( $jobname, "`" ) ||
+ strpos( $jobname, "\\" ) )
+ exit_with_text( "The job name is invalid !" );
+
+if( $jobinput == "" )
+ exit_with_text( "There was no input !" );
+
+$appqmax = nr_of_jobs_for_user_for_app( $user, $app );
+$appsubmitted = nr_of_submitted_jobs_for_user_for_app( $user, $app );
+if( $appqmax <= $appsubmitted )
+ exit_with_text( "Job limit would be exceeded!" );
+
+$bin_dir = parse_config( $config, "" );
+$download_dir = parse_config( $config, "" );
+$upload_dir = parse_config( $config, "" );
+$template_dir = parse_config( $config, "" );
+$config_dir = parse_config( $config, "" );
+$createworkprogram = parse_config( $config, "" );
+
+$extendedjobname = $jobname."_queue_".$jobapplication."_".time(0)."_".random_string();
+$extendedjobname = escapeshellcmd( $extendedjobname );
+
+$wu_template = $template_dir."/queue_".$jobapplicationname."_work_unit_template";
+$result_template = $template_dir."/queue_".$jobapplicationname."_result_unit_template";
+$temporaryinputfile = $extendedjobname;
+
+$command_to_submit = $bin_dir."/".$createworkprogram;
+$command_to_submit .= " -config_dir ".$config_dir;
+$command_to_submit .= " -appname ".$jobapplicationname;
+$command_to_submit .= " -wu_name ".$extendedjobname;
+$command_to_submit .= " -wu_template ".$wu_template;
+$command_to_submit .= " -result_template ".$result_template;
+$command_to_submit .= " -rsc_fpops_est ".floor( ( float )( $jobfops ) );
+$command_to_submit .= " -rsc_fpops_bound ".floor( 3.0 * ( float )( $jobfops ) );
+$command_to_submit .= " -rsc_memory_bound ".floor( ( float )( $jobmem ) );
+$command_to_submit .= " -rsc_disk_bound ".floor( ( float )( $jobdisk ) );
+$command_to_submit .= " -priority 10 -batch ".$user -> id;
+$command_to_submit .= " ".$temporaryinputfile;
+$command_to_submit = escapeshellcmd( $command_to_submit );
+$command_to_submit = "cd ".$config_dir."; ".$command_to_submit;
+
+$temporaryinputfile = $download_dir."/".$temporaryinputfile;
+
+$filehandle = fopen( $temporaryinputfile, "w" );
+if( !$filehandle )
+ exit_with_text( "Cannot create the temporary input file !" );
+
+if( !fwrite( $filehandle, $jobinput ) )
+{
+ fclose( $filehandle );
+ exit_with_text( "Cannot write to the temporary input file !" );
+}
+
+fclose( $filehandle );
+
+if( strpos( $jobapplicationname, "classical" ) !== false )
+{
+ $testinputcommand = $bin_dir."/verify_classical_input ".$temporaryinputfile." /dev/null /dev/stdout /dev/stdout";
+ $testinputcommand = escapeshellcmd( $testinputcommand );
+ $testinputcommand = "cd ".$config_dir."; ".$testinputcommand;
+ $errorline = 0;
+ exec( $testinputcommand, &$outputoftest, &$errorline );
+ if( $errorline != 0 )
+ {
+ $errorstring = "Your input had an error on line ".$errorline." ! The job was not submitted !";
+ unlink( $temporaryinputfile );
+ exit_with_text( $errorstring );
+ }
+}
+
+system( $command_to_submit );
+
+unlink( $temporaryinputfile );
+
+$workunit = mysql_fetch_object( mysql_query( "SELECT * FROM workunit WHERE name='".$extendedjobname."'" ) );
+
+if( !$workunit )
+ exit_with_text( "Error during submition of the workunit associated with your job !" );
+
+$qlistentry = mysql_query( "INSERT INTO q_list VALUES('','".$user->id."','".$workunit->id."')" );
+
+if( !$qlistentry )
+ exit_with_text( "Error during submition of your job !" );
+
+$jobidlink = ''.$jobname.' ('.$workunit -> id.')';
+
+start_table();
+row1( "Your job has been submitted !" );
+row2( "Job status: ", workunit_status_string( $workunit ) );
+row2( "Job id: ", $jobidlink );
+
+row1( "Commands" );
+row2( "Status of this job: ", 'Show job status' );
+$max_jobs = max_nr_of_jobs_of_user( $user );
+$njobs = nr_of_jobs_of_user( $user );
+if( $njobs < $max_jobs )
+{
+ if( $max_jobs - $njobs > 1 )
+ $line = "You can submit ".($max_jobs-$njobs)." more jobs: ";
+ else
+ $line = "You can submit one more job: ";
+ row2( $line, 'Submit another job' );
+}
+row2( "", 'Go back to your queue' );
+row2( "", 'Log out' );
+
+end_table();
+page_tail();
+
+?>
diff --git a/html/queue/user/queue_remove_job.php b/html/queue/user/queue_remove_job.php
new file mode 100644
index 0000000000..45c9e6b008
--- /dev/null
+++ b/html/queue/user/queue_remove_job.php
@@ -0,0 +1,82 @@
+ name." at ".$timestr;
+
+$jobname = workunit_name( $workunit );
+
+if( $user -> id != $job -> user )
+{
+ $title = "Job '".$jobname."' (".$workunitid.")";
+ page_head( $title );
+ exit_with_text( "You are not the owner of this job !" );
+}
+
+$config = get_config();
+
+$jobstatusstring = workunit_status_string( $workunit );
+$jobsubmittime = time_str( $workunit -> create_time );
+
+page_head( $title );
+start_table();
+row1( "Job speciffics" );
+row2( "Job submit time: ", $jobsubmittime );
+row2( "Job name: ", $jobname );
+row2( "Old job status: ", $jobstatusstring );
+
+$allresults = mysql_query( "SELECT * FROM result WHERE workunitid=".$workunitid );
+$nrofresults = mysql_num_rows( $allresults );
+
+for( $resultindex = 0; $resultindex < $nrofresults; ++$resultindex )
+{
+ $result = mysql_fetch_object( $allresults );
+ $result -> xml_doc_in = remove_tags( $result -> xml_doc_in, "" );
+ $query = "UPDATE result SET xml_doc_in='".$result -> xml_doc_in."' WHERE id=".$result -> id;
+ mysql_query( $query );
+}
+
+$query = "UPDATE result SET server_state=5,outcome=5 WHERE server_state=2 AND workunitid=".$workunit -> id;
+mysql_query( $query );
+
+$workunit -> xml_doc = remove_tags( $workunit -> xml_doc, "" );
+$query = "UPDATE workunit SET xml_doc='".$workunit -> xml_doc."' WHERE id=".$workunit -> id;
+mysql_query( $query );
+
+$query = "UPDATE workunit SET error_mask=error_mask|16,transition_time=".time(0)." WHERE id=".$workunit -> id;
+mysql_query( $query );
+
+$query = "DELETE FROM q_list WHERE id=".$job -> id;
+mysql_query( $query );
+
+row2( "New job status: ", "deleted" );
+
+$max_jobs = max_nr_of_jobs_of_user( $user );
+$njobs = nr_of_jobs_of_user( $user );
+
+row1( "Commands" );
+if( $njobs < $max_jobs )
+{
+ if( $max_jobs - $njobs > 1 )
+ $line = "You can submit ".($max_jobs-$njobs)." more jobs: ";
+ else
+ $line = "You can submit one more job: ";
+ row2( $line, 'Submit a job' );
+}
+row2( "", 'Go back to your queue' );
+row2( "", 'Log out' );
+
+end_table();
+
+?>
diff --git a/html/queue/user/queue_show_job.php b/html/queue/user/queue_show_job.php
new file mode 100644
index 0000000000..fd79194513
--- /dev/null
+++ b/html/queue/user/queue_show_job.php
@@ -0,0 +1,138 @@
+ name." at ".$timestr;
+
+$jobname = workunit_name( $workunit );
+
+if( $user -> id != $job -> user )
+{
+ $title = "Job '".$jobname."' (".$workunitid.")";
+ page_head( $title );
+ exit_with_text( "You are not the owner of this job !" );
+}
+
+$config = get_config();
+
+$jobapplication = mysql_fetch_object( mysql_query( "SELECT * FROM app WHERE id=".$workunit -> appid ) );
+$jobapplicationname = $jobapplication -> name;
+$jobapplicationfriendlyname = $jobapplication -> user_friendly_name;
+$jobfops = $workunit -> rsc_fpops_est;
+$jobmem = $workunit -> rsc_memory_bound;
+$jobdisk = $workunit -> rsc_disk_bound;
+$jobstatusstring = workunit_status_string( $workunit );
+
+$coloredjobstatusstring = $jobstatusstring;
+if( $jobstatusstring == "running" ) $coloredjobstatusstring = "".$jobstatusstring."";
+if( $jobstatusstring == "queued" ) $coloredjobstatusstring = "".$jobstatusstring."";
+if( $jobstatusstring == "ERROR" ) $coloredjobstatusstring = "".$jobstatusstring."";
+
+$jobsubmittime = time_str( $workunit -> create_time );
+
+$workunitidstring = " workunit.">".$job -> workunit."";
+
+$jobinputurl = parse_element( $workunit -> xml_doc, "" );
+$jobinputurl = parse_element( $jobinputurl, "" );
+$jobinput = parse_element( $workunit -> xml_doc, "" );
+$jobinput = parse_element( $jobinput, "" );
+
+page_head( $title );
+start_table();
+
+row1( "Job speciffics" );
+row2( "Job status: ", $coloredjobstatusstring );
+row2( "Job application: ", $jobapplicationfriendlyname );
+row2( "Job submit time: ", $jobsubmittime );
+row2( "Job name: ", $jobname );
+row2( "Job id: ", $workunitidstring );
+row2( "Job estimated time to complete: ", floor((float)($jobfops)/92254963740)." min. " );
+row2( "Job estimated memory usage: ", floor((float)($jobmem)/1048576)." Mb. " );
+row2( "Job estimated disk usage: ", floor((float)($jobdisk)/1048576)." Mb. " );
+row2( "Job input file:", ' '.$jobinput.'' );
+
+if( ( $jobstatusstring == "finished" ) || ( $jobstatusstring == "ERROR" ) )
+{
+ if( $jobstatusstring != "finished" )
+ {
+ $resultunitquery = mysql_query( "SELECT * FROM result WHERE workunitid=".$workunit -> id );
+ $nrofresults = mysql_num_rows( $resultunitquery );
+
+ for( $index = 0; $index < $nrofresults; ++$index )
+ {
+ $resultunit = mysql_fetch_object( $resultunitquery );
+
+ $jobstderr = parse_element( $resultunit -> stderr_out, "" );
+
+ if( $jobstderr )
+ {
+ row1( "Error output of this job" );
+ row2( "", $jobstderr );
+ }
+ }
+ }
+ else
+ {
+ $resultunit = mysql_fetch_object( mysql_query( "SELECT * FROM result WHERE id=".$workunit -> canonical_resultid ) );
+
+ $xmldoc = $resultunit -> xml_doc_out;
+ $jobstderr = parse_element( $resultunit -> stderr_out, "" );
+
+ $nroffiles = 0;
+ $cursor = 0;
+ while( $tempfileinfo = parse_next_element( $xmldoc, "", &$cursor ) )
+ $outputfiles[ $nroffiles++ ] = parse_element( $tempfileinfo, "" );
+
+ if( $nroffiles >= 1 )
+ {
+ $fanoutnr = parse_config( $config, "" );
+ row1( "Output of this job" );
+ row2( "Number of output files of job: ", $nroffiles );
+ for( $index = 0; $index < $nroffiles; ++$index )
+ {
+ $filename = $outputfiles[ $index ];
+ $url = "upload/".fan_out_dir( $filename, $fanoutnr )."/".$filename;
+ $outputfilelink = ''.$filename.'';
+ row2( "Output file ".($index+1).": ", $outputfilelink );
+ }
+ }
+
+ if( $jobstderr )
+ {
+ row1( "Error output of this job" );
+ row2( "", $jobstderr );
+ }
+ }
+}
+
+$max_jobs = max_nr_of_jobs_of_user( $user );
+$njobs = nr_of_jobs_of_user( $user );
+
+row1( "Commands" );
+if( $njobs < $max_jobs )
+{
+ if( $max_jobs - $njobs > 1 )
+ $line = "You can submit ".($max_jobs-$njobs)." more jobs: ";
+ else
+ $line = "You can submit one more job: ";
+ row2( $line, 'Submit a job' );
+}
+row2( "", 'Kill or Remove this job' );
+row2( "", 'Go back to your queue' );
+row2( "", 'Log out' );
+
+end_table();
+
+page_tail();
+?>
diff --git a/html/queue/user/queue_show_queue.php b/html/queue/user/queue_show_queue.php
new file mode 100644
index 0000000000..af2211031c
--- /dev/null
+++ b/html/queue/user/queue_show_queue.php
@@ -0,0 +1,93 @@
+ name." at ".$timestr;
+
+page_head( $title );
+
+$alljobs = all_jobs_of_user( $user );
+$njobs = mysql_num_rows( $alljobs );
+
+start_table();
+
+if( $njobs )
+{
+ if( $njobs > 1 )
+ row1( "You have ".$njobs." jobs listed !
" );
+ else
+ row1( "You have ".$njobs." job listed !
" );
+
+ end_table();
+ start_table();
+
+ row5( "Job #", "Job submit time", "Job status", "Job name", "Job ID" );
+
+ for( $jobindex = 0; $jobindex < $njobs; ++$jobindex )
+ {
+ $job = mysql_fetch_object( $alljobs );
+
+ $workunitquery = mysql_query( "SELECT * FROM workunit WHERE id=".$job -> workunit );
+ if( $workunitquery )
+ {
+ $workunit = mysql_fetch_object( $workunitquery );
+
+ if( $workunit )
+ {
+ $prefix = '';
+ $workunitname = $prefix.workunit_name( $workunit ).'';
+ $status = workunit_status_string( $workunit );
+ if( $status == "running" ) $status = "".$status."";
+ if( $status == "queued" ) $status = "".$status."";
+ if( $status == "ERROR" ) $status = "".$status."";
+ $jobsubmittime = time_str( $workunit -> create_time );
+ }
+ else
+ {
+ $workunitname = "WORKUNIT NOT FOUND IN DATABASE";
+ $status = "UNKNOWN";
+ $jobsubmittime = "UNKNOWN";
+ }
+
+ mysql_free_result( $workunitquery );
+ }
+
+ $workunitstring = " workunit.">".$job -> workunit."";
+ row5( $jobindex+1, $jobsubmittime, $status, $workunitname, $workunitstring );
+ }
+
+}
+else
+ row1("You have NO jobs listed !
");
+
+end_table();
+
+$max_jobs = max_nr_of_jobs_of_user( $user );
+
+if( $max_jobs > $njobs )
+{
+ if( $max_jobs - $njobs > 1 )
+ $line = 'You can submit '.( $max_jobs - $njobs ).' more jobs: ';
+ else
+ $line = 'You can submit one more job: ';
+
+ start_table();
+ row1( "Commands" );
+ row2( $line, 'Submit a job' );
+ row2( "", 'Your account' );
+ row2( "", 'Your computers' );
+ row2( "", 'Log out' );
+ end_table();
+}
+else
+ exit_with_text( "You cannot submit any more jobs, you have reached your limit, clean up first !" );
+
+page_tail();
+?>