Added: vcl/trunk/web/.ht-inc/image.php
URL: 
http://svn.apache.org/viewvc/vcl/trunk/web/.ht-inc/image.php?rev=1624325&view=auto
==============================================================================
--- vcl/trunk/web/.ht-inc/image.php (added)
+++ vcl/trunk/web/.ht-inc/image.php Thu Sep 11 16:01:48 2014
@@ -0,0 +1,1941 @@
+<?php
+/*
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+*/
+
+////////////////////////////////////////////////////////////////////////////////
+///
+/// \class Image
+///
+/// \brief extends Resource class to add things specific to resources of the
+/// image type
+///
+////////////////////////////////////////////////////////////////////////////////
+class Image extends Resource {
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn __construct()
+       ///
+       /// \brief calls parent constructor; initializes things for Image class
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function __construct() {
+               parent::__construct();
+               $this->restype = 'image';
+               $this->restypename = 'Image';
+               $this->namefield = 'prettyname';
+               $this->hasmapping = 1;
+               $this->maptype = 'computer';
+               $this->maptypename = 'Computer';
+               $this->defaultGetDataArgs = array('includedeleted' => 0,
+                                                 'rscid' => 0);
+               $this->basecdata['obj'] = $this;
+               $this->addable = 0;
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn getData($args)
+       ///
+       /// \param $args - array of arguments that determine what data gets 
returned;
+       /// must include:\n
+       /// \b includedeleted - 0 or 1; include deleted images\n
+       /// \b rscid - only return data for resource with this id; pass 0 for 
all
+       /// (from image table)
+       ///
+       /// \return array of data as returned from getImages
+       ///
+       /// \brief wrapper for calling getImages
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function getData($args) {
+               $data = getImages($args['includedeleted'], $args['rscid']);
+               $noimageid = getImageId('noimage');
+               if($noimageid)
+                       unset($data[$noimageid]);
+               return $data;
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn fieldDisplayName($field)
+       ///
+       /// \param $field - name of a resource field
+       ///
+       /// \return display value for $field
+       ///
+       /// \brief generates the display value for $field
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function fieldDisplayName($field) {
+               switch($field) {
+                       case 'os':
+                               return 'OS';
+                       case 'installtype':
+                               return 'Install Type';
+                       case 'ostype':
+                               return 'OS Type';
+                       case 'minram':
+                               return 'Required RAM';
+                       case 'minprocnumber':
+                               return 'Required Cores';
+                       case 'minprocspeed':
+                               return 'Processor Speed';
+                       case 'minnetwork':
+                               return 'Min. Network Speed';
+                       case 'maxconcurrent':
+                               return 'Max Concurrent Usage';
+                       case 'reloadtime':
+                               return 'Est. Reload Time';
+                       case 'lastupdate':
+                               return 'Last Updated';
+                       case 'forcheckout':
+                               return 'Available for checkout';
+                       case 'maxinitialtime':
+                               return 'Max Initial Time';
+                       case 'checkuser':
+                               return 'Check Logged in User';
+                       case 'rootaccess':
+                               return 'Admin. Access';
+               }
+               return ucfirst($field);
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn submitToggleDeleteResourceExtra($rscid, $deleted)
+       ///
+       /// \param $rscid - id of a resource (from image table)
+       /// \param $deleted - (optional, default=0) 1 if resource was previously
+       /// deleted; 0 if not
+       ///
+       /// \brief handles deleted flag for cooresponding entries in 
imagerevision
+       /// table
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function submitToggleDeleteResourceExtra($rscid, $deleted=0) {
+               if($deleted) {
+                       $query = "UPDATE imagerevision i1, "
+                              .        "imagerevision i2 "
+                              . "SET i1.deleted = 0, "
+                              .     "i1.datedeleted = NULL "
+                              . "WHERE i1.imageid = $rscid AND "
+                              .       "i2.imageid = $rscid AND "
+                              .       "i2.production = 1 AND "
+                              .       "i1.datedeleted = i2.datedeleted";
+               }
+               else {
+                       $query = "UPDATE imagerevision "
+                                        . "SET deleted = 1, "
+                                        .     "datedeleted = NOW() "
+                                        . "WHERE imageid = $rscid AND "
+                                        .       "deleted = 0";
+               }
+               doQuery($query);
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn extraSelectAdminOptions()
+       ///
+       /// \return html
+       ///
+       /// \brief generates HTML for option to create/update an image
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function extraSelectAdminOptions() {
+               $h = '';
+               $cdata = array('imaging' => 1);
+               $cont = addContinuationsEntry("viewRequests", $cdata);
+               $h .= "<INPUT type=radio name=\"continuation\" value=\"$cont\" 
id=\"";
+               $h .= "createimage\"><label for=\"createimage\">Create / Update 
an Image ";
+               $h .= "</label><br>\n";
+               return $h;
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn addEditDialogHTML($add)
+       ///
+       /// \param $add (optional, defaul=0) - 0 for edit, 1 for add
+       ///
+       /// \brief generates HTML for dialog used to edit resource
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function addEditDialogHTML($add=0) {
+               global $user;
+               # dialog for on page editing
+               $h = '';
+               $h .= "<div dojoType=dijit.Dialog\n";
+               $h .= "      id=\"addeditdlg\"\n";
+               if($add)
+                       $h .= "      title=\"Add {$this->restypename}\"\n";
+               else
+                       $h .= "      title=\"Edit {$this->restypename}\"\n";
+               $h .= "      duration=250\n";
+               $h .= "      draggable=true>\n";
+               $h .= "<div id=\"addeditdlgcontent\">\n";
+               # id
+               $h .= "<input type=\"hidden\" id=\"editresid\">\n";
+
+               if(! $add)
+                       $h .= "<div style=\"width: 80%; margin-left: 10%; 
overflow: auto; height: 80%;\">\n";
+               # name
+               $errmsg = "Name cannot contain dashes (-), single (') or double 
(&quot;) quotes, "
+                       . "less than (&lt;), or greater than (&gt;) and can be 
from 2 to 60 "
+                       . "characters long";
+               $h .= labeledFormItem('name', 'Name', 'text', 
'^([A-Za-z0-9!@#$%^&\*\(\)_=\+\[\]{}\\\|:;,\./\?~` ]){2,60}$',
+                                     1, '', $errmsg); 
+               # owner
+               $extra = array('onKeyPress' => 'setOwnerChecking');
+               $h .= labeledFormItem('owner', 'Owner', 'text', '', 1, '', 
'Unknown user',
+                                     'checkOwner', $extra);
+               #$h .= labeledFormItem('owner', 'Owner', 'text', 
'{$user['unityid']}@{$user['affiliation']}',
+               #                      1, '', 'Unknown user', 'checkOwner', 
'onKeyPress', 'setOwnerChecking');
+               $cont = addContinuationsEntry('AJvalidateUserid');
+               $h .= "<input type=\"hidden\" id=\"valuseridcont\" 
value=\"$cont\">\n";
+               # description
+               $h .= "<fieldset>\n";
+               $h .= "<legend>Image Description</legend>\n";
+               $h .= "Description of image (required - users will<br>\nsee 
this on the <strong>";
+               $h .= "New Reservations</strong> page):<br>\n";
+               $h .= "<textarea dojoType=\"dijit.form.Textarea\" 
id=\"description\" ";
+               $h .= "style=\"width: 400px; text-align: left;\"></textarea>\n";
+               $h .= "</fieldset>\n";
+               # usage notes
+               $h .= "<fieldset>\n";
+               $h .= "<legend>Usage Notes</legend>\n";
+               $h .= "Optional notes to the user explaining how to use the 
image<br>";
+               $h .= "(users will see this on the <strong>Connect!</strong> 
page):<br>\n";
+               $h .= "<textarea dojoType=\"dijit.form.Textarea\" id=\"usage\" 
";
+               $h .= "style=\"width: 400px; text-align: left;\"></textarea>\n";
+               $h .= "</fieldset>\n";
+               if($add) {
+                       $h .= "<fieldset>\n";
+                       $h .= "<legend>Revision Comments</legend>\n";
+                       $h .= "Notes for yourself and other admins about how 
the image ";
+                       $h .= "was setup/installed.<br>\nThese are optional and 
are not visible ";
+                       $h .= "to end users.<br>\n";
+                       $h .= "<textarea dojoType=\"dijit.form.Textarea\" 
id=\"imgcomments\" ";
+                       $h .= "style=\"width: 400px; text-align: 
left;\"></textarea>";
+                       $h .= "</fieldset>\n";
+               }
+               # advanced options
+               $h .= "<div dojoType=\"dijit.TitlePane\" title=\"Advanced 
Options - leave ";
+               $h .= "default values unless you really know what you are doing 
(click to ";
+               $h .= "expand)\" open=\"false\" style=\"width: 460px\" 
id=\"advancedoptions\" ";
+               $h .= "onShow=\"delayedEditResize();\" 
onHide=\"delayedEditResize();\">\n";
+               # RAM
+               $extra = array('smallDelta' => 256, 'largeDelta' => 1024);
+               $h .= labeledFormItem('ram', 'Required RAM', 'spinner', 
'{min:512, max:8388607}',
+                                     1, 1024, '', '', $extra);
+               # cores
+               $extra = array('smallDelta' => 1, 'largeDelta' => 2);
+               $h .= labeledFormItem('cores', 'Required Cores', 'spinner', 
'{min:1, max:255}',
+                                     1, 1, '', '', $extra);
+               # proc speed
+               $extra = array('smallDelta' => 500, 'largeDelta' => 8000);
+               $h .= labeledFormItem('cpuspeed', 'Processor Speed', 'spinner', 
'{min:500, max:8000}',
+                                     1, 1000, '', '', $extra);
+               # network speed
+               $vals = array('10' => '10 Mbps',
+                             '100' => '100 Mbps',
+                             '1000' => '1 Gbps',
+                             '10000' => '10 Gbps',
+                             '100000' => '100 Gbps');
+               $h .= labeledFormItem('networkspeed', 'Minimum Network Speed', 
'select', $vals);
+               # concurrent usage
+               $extra = array('smallDelta' => 1, 'largeDelta' => 10);
+               $h .= labeledFormItem('concurrent', 'Max Concurrent Usage', 
'spinner','{min:0, max:255}',
+                                      1, 0, '', '', $extra, '', '(0 = 
unlimited)');
+               # reload time
+               if(! $add) {
+                       $extra = array('smallDelta' => 1, 'largeDelta' => 5);
+                       $h .= labeledFormItem('reload', 'Estimated Reload 
Time', 'spinner',
+                                             '{min:1, max:255}', 1, 5, '', '', 
$extra);
+               }
+               # for checkout
+               $yesno = array('1' => 'Yes',
+                             '0' => 'No');
+               $h .= labeledFormItem('checkout', 'Available for checkout', 
'select', $yesno);
+               # check user
+               $h .= labeledFormItem('checkuser', 'Check for logged in user', 
'select', $yesno);
+               # admin access
+               $h .= labeledFormItem('rootaccess', 'Users have administrative 
access', 'select', $yesno);
+               # sysprep
+               if($add)
+                       $h .= labeledFormItem('sysprep', 'Use sysprep', 
'select', $yesno);
+               # connect methods
+               $h .= "<label for=\"connectmethodlist\">Connect 
methods:</label>\n";
+               $h .= "<div class=\"labeledform\"><span 
id=\"connectmethodlist\"></span><br>\n";
+               $h .= "<div dojoType=\"dijit.form.DropDownButton\" 
id=\"connectmethoddlg\">\n";
+               $h .= "  <span>Modify Connection Methods</span>\n";
+               // if leave off the href attribute, inital sizing of popup is 
wrong
+               $h .= "  <div dojoType=\"dijit.TooltipDialog\" 
id=\"connectmethodttd\" href=\"\"></div>\n";
+               $h .= "</div>\n";
+               if($add) {
+                       $h .= "<input type=\"hidden\" name=\"connectmethodids\" 
";
+                       $h .= "id=\"connectmethodids\">\n";
+               }
+               $h .= "</div>\n"; #labeledform
+               # subimages
+               if(! $add) {
+                       $h .= "<br>\n";
+                       $h .= "<div align=\"center\">\n";
+                       $h .= "<div dojoType=\"dijit.form.DropDownButton\" 
id=\"subimagebtn\">";
+                       $h .= "  <span>Manage Subimages</span>\n";
+                       // if leave off the href attribute, inital sizing of 
popup is wrong
+                       $h .= "  <div dojoType=\"dijit.TooltipDialog\" 
id=\"subimagedlg\" href=\"\"></div>\n";
+                       $h .= "</div>\n";
+                       $h .= "</div>\n";
+               }
+
+               if(! $add)
+                       $h .= "</div>\n";
+
+               $h .= "</div>\n";
+
+               $h .= "<div id=\"addeditdlgerrmsg\" 
class=\"nperrormsg\"></div>\n";
+
+               if(! $add) {
+                       $h .= "<div id=revisiondiv>\n";
+                       $h .= "</div>\n";
+               }
+
+               $h .= "</div>\n"; # addeditdlgcontent
+
+               $h .= "<div id=\"editdlgbtns\" align=\"center\">\n";
+               $h .= dijitButton('addeditbtn', "Confirm", "saveResource();");
+               $script  = "    dijit.byId('addeditdlg').hide();\n";
+               $script .= "    dijit.registry.filter(function(widget, 
index){return widget.id.match(/^comments/);}).forEach(function(widget) 
{widget.destroy();});\n";
+               $h .= dijitButton('', "Cancel", $script);
+               $h .= "</div>\n"; # editdlgbtns
+               $h .= "</div>\n"; # addeditdlg
+
+               $h .= "<div dojoType=dijit.Dialog\n";
+               $h .= "      id=\"autoconfirmdlg\"\n";
+               $h .= "      title=\"Confirm Manual Install\"\n";
+               $h .= "      duration=250\n";
+               $h .= "      draggable=true>\n";
+               $h .= "<strong><span 
id=\"autoconfirmcontent\"></span></strong><br><br>\n";
+               $h .= "This method cannot be automatically added to the image 
by VCL. The<br>\n";
+               $h .= "image must be created with the software for this method 
already installed.<br>\n";
+               $h .= "If this image already has software for this method 
installed in it, please<br>\n";
+               $h .= "click <strong>Software is Manually Installed</strong>. 
Otherwise, click cancel.<br><br>\n";
+               $h .= "   <div align=\"center\">\n";
+               $script  = "       dijit.byId('autoconfirmdlg').hide();\n";
+               $script .= "       addConnectMethod3();\n";
+               $script .= "       
dijit.byId('connectmethoddlg').openDropDown();\n";
+               $h .= dijitButton('', "Software is Manually Installed", 
$script);
+               $script  = "       dijit.byId('autoconfirmdlg').hide();\n";
+               $script .= "       
dijit.byId('connectmethoddlg').openDropDown();\n";
+               $h .= dijitButton('', "Cancel", $script);
+               $h .= "   </div>\n";
+               $h .= "</div>\n"; # autoconfirmdlg
+               return $h;
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn connectmethodDialogContent
+       ///
+       /// \brief prints HTML for connect method dialog available when
+       /// editing/adding an image
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function connectmethodDialogContent() {
+               $imageid = getContinuationVar('imageid');
+               $newimage = getContinuationVar('newimage', 0);
+               $curmethods = getContinuationVar('curmethods');
+               $methods = getConnectMethods($imageid);
+               $revisions = getImageRevisions($imageid);
+       
+               $h  = "<h3>Modify Connection Methods</h3>";
+               if(! $newimage && count($revisions) > 1) {
+                       $h .= "Selected Revision ID: ";
+                       $cdata = $this->basecdata;
+                       $cdata['imageid'] = $imageid;
+                       $cdata['revids'] = array_keys($revisions);
+                       $cdata['curmethods'] = $curmethods;
+                       $cdata['newimage'] = $newimage;
+                       $cont = 
addContinuationsEntry('jsonImageConnectMethods', $cdata);
+                       $url = BASEURL . SCRIPT . "?continuation=$cont";
+                       $h .= "<select dojoType=\"dijit.form.Select\" 
id=\"conmethodrevid\" ";
+                       $h .= "onChange=\"selectConMethodRevision('$url');\">";
+                       foreach($revisions as $revid => $revision) {
+                               if($revision['production'])
+                                       $h .= "<option value=\"$revid\" 
selected=\"true\">{$revision['revision']}</option>";
+                               else
+                                       $h .= "<option 
value=\"$revid\">{$revision['revision']}</option>";
+                       }
+                       $h .= "</select>";
+               }
+               $cdata = $this->basecdata;
+               $cdata['imageid'] = $imageid;
+               $cdata['curmethods'] = $curmethods;
+               $cdata['newimage'] = $newimage;
+               $cont = addContinuationsEntry('jsonImageConnectMethods', 
$cdata);
+               $h .= "<div dojoType=\"dojo.data.ItemFileWriteStore\" url=\"" . 
BASEURL;
+               $h .= SCRIPT . "?continuation=$cont\" jsid=\"cmstore\" 
id=\"cmstore\">";
+               $h .= "</div>\n";
+               $h .= "<div dojoType=\"dijit.form.Select\" id=\"addcmsel\" ";
+               $h .= "store=\"cmstore\" query=\"{active: 0}\" ";
+               $h .= "onSetStore=\"updateCurrentConMethods();\"></div>";
+               $h .= dijitButton('addcmbtn', "Add Method", 
"addConnectMethod();");
+               $h .= "<br>";
+               $h .= "<h3>Current Methods</h3>";
+               $h .= "<select id=\"curmethodsel\" multiple size=\"5\">";
+               $h .= "</select><br>";
+               $h .= dijitButton('remcmbtn', "Remove Selected Methods(s)", 
"remConnectMethod();");
+               $h .= "<br>";
+               $h .= "<div id=\"cmerror\" class=\"rederrormsg\"></div>\n";
+               $adminimages = getUserResources(array("imageAdmin"), 
array("administer"));
+               $adminids = array_keys($adminimages["image"]);
+               $cdata = $this->basecdata;
+               $cdata['imageid'] = $imageid;
+               $cdata['methods'] = $methods;
+               $cdata['revids'] = array_keys($revisions);
+               $cdata['newimage'] = $newimage;
+               $cont = addContinuationsEntry('AJaddImageConnectMethod', 
$cdata, 3600, 1, 0);
+               $h .= "<INPUT type=hidden id=addcmcont value=\"$cont\">";
+               $cont = addContinuationsEntry('AJremImageConnectMethod', 
$cdata, 3600, 1, 0);
+               $h .= "<INPUT type=hidden id=remcmcont value=\"$cont\">";
+               if(! $newimage) {
+                       $h .= "NOTE: Connection Method changes take effect 
immediately; you<br>do ";
+                       $h .= "<strong>not</strong> need to click \"Confirm 
Changes\" to submit them.";
+               }
+               print $h;
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn subimageDialogContent()
+       ///
+       /// \brief prints content to fill in the dialog for managing subimages
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function subimageDialogContent() {
+               $imageid = getContinuationVar('imageid');
+               $images = getImages(0);
+               $image = $images[$imageid];
+
+               $resources = getUserResources(array("imageAdmin"));
+               if(empty($resources['image'])) {
+                       print "You do not have access to add any subimages to 
this image.";
+                       return;
+               }
+
+               $h  = "<h3>Add New Subimage</h3>";
+               $h .= "<select dojoType=\"dijit.form.FilteringSelect\" 
id=\"addsubimagesel\">";
+               foreach($resources['image'] as $id => $name) {
+                       if($name == 'No Image')
+                               continue;
+                       $h .= "<option value=$id>$name</option>";
+               }
+               $h .= "</select>";
+               $h .= dijitButton('addbtn', "Add Subimage", "addSubimage();");
+               $h .= "<br>";
+               $h .= "<h3>Current Subimages</h3>";
+               $subimgcnt = 0;
+               if(array_key_exists("subimages", $image) && 
count($image["subimages"])) {
+                       $subimages = array();
+                       foreach($image["subimages"] as $imgid)
+                               $subimages[] = array('id' => $imgid,
+                                                                               
        'name' => $images[$imgid]['prettyname']);
+                       uasort($subimages, "sortKeepIndex");
+                       $h .= "<select id=\"cursubimagesel\" multiple 
size=\"10\">";
+                       foreach($subimages as $img) {
+                               $h .= "<option 
value={$img['id']}>{$img['name']}</option>";
+                               $subimgcnt++;
+                       }
+               }
+               else {
+                       $h .= "<select id=\"cursubimagesel\" multiple 
size=\"10\" disabled>";
+                       $image['subimages'] = array();
+                       $h .= "<option value=\"none\">(None)</option>";
+               }
+               $h .= "</select><br>";
+               $h .= "total subimages: <span 
id=subimgcnt>$subimgcnt</span><br>";
+               $h .= dijitButton('rembtn', "Remove Selected Subimage(s)", 
"remSubimages();");
+               $h .= "<br>";
+               $adminimages = getUserResources(array("imageAdmin"), 
array("administer"));
+               $adminids = array_keys($adminimages["image"]);
+               $cdata = $this->basecdata;
+               $cdata['imageid'] = $imageid;
+               $cdata['adminids'] = $adminids;
+               $cdata['imagemetaid'] = $image['imagemetaid'];
+               $cdata['userimageids'] = array_keys($resources['image']);
+               $cdata['subimages'] = $image['subimages'];
+               $cont = addContinuationsEntry('AJaddSubimage', $cdata, 
SECINDAY, 1, 0);
+               $h .= "<INPUT type=\"hidden\" id=\"addsubimagecont\" 
value=\"$cont\">";
+               $cont = addContinuationsEntry('AJremSubimage', $cdata, 
SECINDAY, 1, 0);
+               $h .= "<INPUT type=\"hidden\" id=\"remsubimagecont\" 
value=\"$cont\">";
+               $h .= "NOTE: Subimage changes take effect immediately; you 
do<br>";
+               $h .= "<strong>not</strong> need to click \"Confirm Changes\" 
to submit them.";
+               print $h;
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn AJeditResource()
+       ///
+       /// \brief sends data for editing a resource
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function AJeditResource() {
+               $imageid = processInputVar('rscid', ARG_NUMERIC);
+               $images = getUserResources(array("imageAdmin"), 
array('administer'), 0, 1);
+               if(! array_key_exists($imageid, $images['image'])) {
+                       $ret = array('status' => 'noaccess');
+                       sendJSON($ret);
+                       return;
+               }
+               $tmp = $this->getData(array('includedeleted' => 0, 'rscid' => 
$imageid));
+               $data = $tmp[$imageid];
+               $extra = getImageNotes($imageid);
+               $data = array_merge($data, $extra);
+               $cdata = $this->basecdata;
+               $cdata['imageid'] = $imageid;
+               $cdata['olddata'] = $data;
+               if($data['minram'] < 512)
+                       $data['minram'] = 512;
+
+               # revisions
+               $data['revisionHTML'] = $this->getRevisionHTML($imageid);
+
+               # subimage url
+               $cdata2 = array('obj' => $this,
+                               'imageid' => $imageid);
+               $cont = addContinuationsEntry('subimageDialogContent', $cdata2);
+               $data['subimageurl'] = BASEURL . SCRIPT . "?continuation=$cont";
+               # connect method url
+               $cdata2['curmethods'] = $data['connectmethods'];
+               #$cdata2['newimage'] = $state;
+               $cont = addContinuationsEntry('connectmethodDialogContent', 
$cdata2);
+               $data['connectmethodurl'] = BASEURL . SCRIPT . 
"?continuation=$cont";
+               $data['connectmethods'] = array_values($data['connectmethods']);
+               # save continuation
+               $cont = addContinuationsEntry('AJsaveResource', $cdata);
+
+               $ret = array('title' => "Edit {$this->restypename}",
+                            'cont' => $cont,
+                            'resid' => $imageid,
+                            'data' => $data,
+                            'status' => 'success');
+               sendJSON($ret);
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn AJsaveResource()
+       ///
+       /// \brief saves changes to resource
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function AJsaveResource() {
+               $add = getContinuationVar('add', 0);
+               if($add) {
+                       $this->createImage();
+                       return;
+               }
+               $data = $this->validateResourceData();
+               if($data['error']) {
+                       $ret = array('status' => 'error', 'msg' => 
$data['errormsg']);
+                       sendJSON($ret);
+                       return;
+               }
+               $olddata = getContinuationVar('olddata');
+               $imagenotes = getImageNotes($data['imageid']);
+               $ownerid = getUserlistID($data['owner']);
+               if(empty($data['concurrent']) || ! 
is_numeric($data['concurrent']))
+                       $data['concurrent'] = 'NULL';
+
+               $updates = array();
+               # name
+               if($data['name'] != $olddata['prettyname'])
+                       $updates[] = "prettyname = '{$data['name']}'";
+               # ownerid
+               if($ownerid != $olddata['ownerid'])
+                       $updates[] = "ownerid = $ownerid";
+               # minram
+               if($data['ram'] != $olddata['minram'])
+                       $updates[] = "minram = {$data['ram']}";
+               # minprocnumber
+               if($data['cores'] != $olddata['minprocnumber'])
+                       $updates[] = "minprocnumber = {$data['cores']}";
+               # minprocspeed
+               if($data['cpuspeed'] != $olddata['minprocspeed'])
+                       $updates[] = "minprocspeed = {$data['cpuspeed']}";
+               # minnetwork
+               if($data['networkspeed'] != $olddata['minnetwork'])
+                       $updates[] = "minnetwork = {$data['networkspeed']}";
+               # maxconcurrent
+               if($data['concurrent'] != $olddata['maxconcurrent'])
+                       $updates[] = "maxconcurrent = {$data['concurrent']}";
+               # reloadtime
+               if($data['reload'] != $olddata['reloadtime'])
+                       $updates[] = "reloadtime = {$data['reload']}";
+               # forcheckout
+               if($data['checkout'] != $olddata['forcheckout'])
+                       $updates[] = "forcheckout = {$data['checkout']}";
+               # description
+               if($data['desc'] != $olddata['description']) {
+                       $escdesc = mysql_real_escape_string($data['desc']);
+                       $updates[] = "description = '$escdesc'";
+               }
+               # usage
+               if($data['usage'] != $olddata['usage']) {
+                       $escusage = mysql_real_escape_string($data['usage']);
+                       $updates[] = "`usage` = '$escusage'";
+               }
+
+               if(count($updates)) {
+                       $query = "UPDATE image SET "
+                              . implode(', ', $updates)
+                              . " WHERE id = {$data['imageid']}";
+                       doQuery($query);
+               }
+               if(empty($olddata[$data['imageid']]['imagemetaid']) &&
+                  ($data['checkuser'] == 0 || $data['rootaccess'] == 0)) {
+                       $query = "INSERT INTO imagemeta "
+                                        .        "(checkuser, "
+                                        .        "rootaccess) "
+                                        . "VALUES ({$data['checkuser']}, "
+                                        .        "{$data['rootaccess']})";
+                       doQuery($query, 101);
+                       $qh = doQuery("SELECT LAST_INSERT_ID() FROM imagemeta", 
101);
+                       if(! $row = mysql_fetch_row($qh))
+                               abort(101);
+                       $imagemetaid = $row[0];
+                       $query = "UPDATE image "
+                                        . "SET imagemetaid = $imagemetaid "
+                                        . "WHERE id = {$data['imageid']}";
+                       doQuery($query, 101);
+               }
+               elseif(! empty($olddata[$data['imageid']]['imagemetaid'])) {
+                       if($data['checkuser'] != 
$olddata[$data['imageid']]['checkuser'] ||
+                          $data['rootaccess'] != 
$olddata[$data['imageid']]['rootaccess']) {
+                               $query = "UPDATE imagemeta "
+                                                . "SET checkuser = 
{$data['checkuser']}, "
+                                                .     "rootaccess = 
{$data['rootaccess']} "
+                                                . "WHERE id = 
{$olddata[$data['imageid']]['imagemetaid']}";
+                               doQuery($query, 101);
+                       }
+                 
checkClearImageMeta($olddata[$data['imageid']]['imagemetaid'], 
$data['imageid']);
+               }
+               $args = $this->defaultGetDataArgs;
+               $args['rscid'] = $data['imageid'];
+               $tmp = $this->getData($args);
+               $image = $tmp[$data['imageid']];
+               $image['description'] = $data['desc'];
+               $image['usage'] = $data['usage'];
+               if(isset($imagemetaid))
+                       $image['imagemetaid'] = $imagemetaid;
+               sendJSON(array('status' => 'success', 'data' => $image));
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn createImage()
+       ///
+       /// \brief redirects user to clickthrough agreement page if it has not 
been 
+       /// submitted; calls addResource to add a new image; updates request and
+       /// reservation tables to put in imaging state
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function createImage() {
+               global $user, $clickThroughText;
+               $fromclickthrough = getContinuationVar('fromclickthrough', 0);
+               $checkpoint = getContinuationVar('checkpoint', 0);
+               if($fromclickthrough)
+                       $data = getContinuationVar('data');
+               else
+                       $data = $this->validateResourceData();
+               if($data['error']) {
+                       $ret = array('status' => 'error', 'msg' => 
$data['errormsg']);
+                       sendJSON($ret);
+                       return;
+               }
+               if(! $fromclickthrough) {
+                       $agree = str_replace("\n", "<br>\n", 
sprintf($clickThroughText, ''));
+                       $agree = str_replace("<br>\n<br>\n", "<br>\n", $agree);
+                       $cdata = array('obj' => $this,
+                                      'data' => $data,
+                                      'agree' => $agree,
+                                      'add' => 1,
+                                      'checkpoint' => $checkpoint,
+                                      'fromclickthrough' => 1);
+                       $cont = addContinuationsEntry('AJsaveResource', $cdata);
+                       $ret = array('status' => 'success',
+                                    'action' => 'clickthrough',
+                                    'agree' => $agree,
+                                    'cont' => $cont);
+                       sendJSON($ret);
+                       return;
+               }
+
+               // get extra data from base image
+               $requestdata = getRequestInfo($data['requestid']);
+               $imagedata = getImages(0, 
$requestdata["reservations"][0]["imageid"]);
+               $data["platformid"] = 
$imagedata[$requestdata["reservations"][0]["imageid"]]["platformid"];
+               $data["osid"] = 
$imagedata[$requestdata["reservations"][0]["imageid"]]["osid"];
+               $data["basedoffrevisionid"] = 
$requestdata["reservations"][0]["imagerevisionid"];
+               $data["reload"] = 10;
+               $data["autocaptured"] = 0;
+
+               # add the image
+               if(! $imageid = $this->addResource($data)) {
+                       sendJSON(array('status' => 'adderror',
+                                      'errormsg' => 'Error encountered while 
trying to create new image.<br>Please contact an admin for assistance.'));
+                       return;
+               }
+
+               $newstateid = 16;
+               if($checkpoint)
+                       $newstateid = 24;
+
+               $query = "UPDATE request rq, "
+                      .        "reservation rs "
+                      . "SET rs.imageid = $imageid, "
+                      .     "rs.imagerevisionid = {$this->imagerevisionid}, "
+                      .     "rq.stateid = $newstateid,"
+                      .     "rq.forimaging = 1 "
+                      . "WHERE rq.id = {$data['requestid']} AND "
+                      .       "rq.id = rs.requestid";
+               doQuery($query, 101);
+
+               $agree = mysql_real_escape_string(getContinuationVar('agree'));
+               $query = "INSERT INTO clickThroughs "
+                      .        "(userid, "
+                      .        "imageid, "
+                      .        "imagerevisionid, "
+                      .        "accepted, "
+                      .        "agreement) "
+                      . "VALUES "
+                      .        "({$user['id']}, "
+                      .        "$imageid, "
+                      .        "{$this->imagerevisionid}, "
+                      .        "NOW(), "
+                      .        "'$agree')";
+               doQuery($query, 101);
+
+               sendJSON(array('status' => 'success', 'action' => 'add'));
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn AJupdateImage($requestid=0, $userid=0, $comments='', 
$autocaptured=0)
+       ///
+       /// \param $requestid - required if $autocaptured = 1; id of request to 
be
+       /// updated
+       /// \param $userid - required if $autocaptured = 1; id of user updating 
image
+       /// \param $comments - required if $autocaptured = 1; comments for image
+       /// revision
+       /// \param $autocaptured - required if $autocaptured = 1; 1 if calling 
from
+       /// XMLRPCautoCapture, 0 otherwise
+       ///
+       /// \brief handles creating a new image revision; if $autocaptured is 0,
+       /// passed in arguments are ignored and obtained from continuation or 
user
+       /// input
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       static function AJupdateImage($requestid=0, $userid=0, $comments='',
+                                     $autocaptured=0) {
+               global $user, $clickThroughText;
+       
+               if($userid == 0)
+                       $userid = $user['id'];
+
+               if(! $autocaptured) {
+                       $imageid = getContinuationVar('imageid');
+                       $imageData = getImages(0, $imageid);
+                       if($imageData[$imageid]['ownerid'] != $userid) {
+                               $ret = array('status' => 'noaccess');
+                               sendJSON($ret);
+                               return 0;
+                       }
+                       $oldrevisionid = getContinuationVar('revisionid');
+               }
+               $fromclickthrough = getContinuationVar('fromclickthrough', 0);
+               if($fromclickthrough)
+                       $comments = getContinuationVar('comments');
+               elseif(! $autocaptured) {
+                       $comments = processInputVar('comments', ARG_STRING, '');
+                       $comments = htmlspecialchars($comments);
+                       if(get_magic_quotes_gpc())
+                               $comments = stripslashes($comments);
+               }
+
+               if(! $autocaptured)
+                       $requestid = getContinuationVar('requestid');
+
+               $checkpoint = getContinuationVar('checkpoint', 0);
+
+               if(! $autocaptured && ! $fromclickthrough) {
+                       $agree = str_replace("\n", "<br>\n", 
sprintf($clickThroughText, ''));
+                       $agree = str_replace("<br>\n<br>\n", "<br>\n", $agree);
+                       $obj = new Image();
+                       $cdata = array('obj' => $obj,
+                                      'comments' => $comments,
+                                      'agree' => $agree,
+                                      'requestid' => $requestid,
+                                      'imageid' => $imageid,
+                                      'revisionid' => $oldrevisionid,
+                                      'checkpoint' => $checkpoint,
+                                      'fromclickthrough' => 1);
+                       $cont = addContinuationsEntry('AJupdateImage', $cdata);
+                       $ret = array('status' => 'success',
+                                    'action' => 'clickthrough',
+                                    'agree' => $agree,
+                                    'cont' => $cont);
+                       sendJSON($ret);
+                       return;
+               }
+       
+               if($autocaptured) {
+                       $data = getRequestInfo($requestid);
+                       if(count($data['reservations']) == 1) {
+                               $imageid = $data['reservations'][0]['imageid'];
+                               $oldrevisionid = 
$data['reservations'][0]['imagerevisionid'];
+                       }
+                       else {
+                               foreach($data["reservations"] as $res) {
+                                       if($res["forcheckout"]) {
+                                               $imageid = $res["imageid"];
+                                               $oldrevisionid = 
$res['imagerevisionid'];
+                                               break;
+                                       }
+                               }
+                       }
+               }
+               // set the test flag on the image in the image table
+               $query = "UPDATE image SET test = 1 WHERE id = $imageid";
+               doQuery($query, 101);
+       
+               # add entry to imagerevision table
+               $query = "SELECT revision, "
+                      .        "imagename "
+                      . "FROM imagerevision "
+                      . "WHERE imageid = $imageid "
+                      . "ORDER BY revision DESC "
+                      . "LIMIT 1";
+               $qh = doQuery($query, 101);
+               $row = mysql_fetch_assoc($qh);
+               $newrevision = $row['revision'] + 1;
+               $newname = preg_replace("/{$row['revision']}$/", $newrevision, 
$row['imagename']);
+               $comments = mysql_real_escape_string($comments);
+               $query = "INSERT INTO imagerevision "
+                      .        "(imageid, "
+                      .        "revision, "
+                      .        "userid, "
+                      .        "datecreated, "
+                      .        "deleted, "
+                      .        "production, "
+                      .        "comments, "
+                      .        "imagename, "
+                      .        "autocaptured) "
+                      . "VALUES ($imageid, "
+                      .        "$newrevision, "
+                      .        "$userid, "
+                      .        "NOW(), "
+                      .        "1, "
+                      .        "0, "
+                      .        "'$comments', "
+                      .        "'$newname', "
+                      .        "$autocaptured)";
+               doQuery($query, 101);
+               $imagerevisionid = dbLastInsertID();
+       
+               # duplicate any entries in connectmethodmap for new revision
+               $query = "INSERT INTO connectmethodmap "
+                      . "SELECT connectmethodid, "
+                      .        "OStypeid, "
+                      .        "OSid, "
+                      .        "$imagerevisionid, "
+                      .        "disabled, "
+                      .        "autoprovisioned "
+                      . "FROM connectmethodmap "
+                      . "WHERE imagerevisionid = $oldrevisionid";
+               doQuery($query, 101);
+
+               $newstateid = 16;
+               if($checkpoint)
+                       $newstateid = 24;
+       
+               # update request and reservation
+               $query = "UPDATE request rq, "
+                      .        "reservation rs "
+                      . "SET rs.imagerevisionid = $imagerevisionid, "
+                      .     "rq.stateid = $newstateid,"
+                      .     "rq.forimaging = 1 "
+                      . "WHERE rq.id = $requestid AND "
+                      .       "rq.id = rs.requestid AND "
+                      .       "rs.imageid = $imageid";
+               doQuery($query, 101);
+
+               if($autocaptured)
+                       return 1;
+       
+               $agree = mysql_real_escape_string(getContinuationVar('agree'));
+               $query = "INSERT INTO clickThroughs "
+                      .        "(userid, "
+                      .        "imageid, "
+                      .        "accepted, "
+                      .        "agreement) "
+                      . "VALUES "
+                      .        "($userid, "
+                      .        "$imageid, "
+                      .        "NOW(), "
+                      .        "'$agree')";
+               doQuery($query, 101);
+       
+               sendJSON(array('status' => 'success', 'action' => 'update'));
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn addResource($data)
+       ///
+       /// \param $data - array of needed data for adding a new resource
+       ///
+       /// \return id of new resource
+       ///
+       /// \brief handles adding a new image and other associated data to the
+       /// database
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function addResource($data) {
+               global $user;
+               $data['desc'] = mysql_real_escape_string($data['desc']);
+               $data['usage'] = mysql_real_escape_string($data['usage']);
+               $data['comments'] = mysql_real_escape_string($data['comments']);
+       
+               # get architecture of base image
+               $query = "SELECT i.architecture "
+                      . "FROM image i, "
+                      .      "imagerevision ir "
+                      . "WHERE ir.imageid = i.id AND "
+                      .       "ir.id = {$data['basedoffrevisionid']}";
+               $qh = doQuery($query);
+               $row = mysql_fetch_assoc($qh);
+               $arch = $row['architecture'];
+       
+               $ownerdata = getUserInfo($data['owner'], 1);
+               $ownerid = $ownerdata['id'];
+               if(empty($data['concurrent']) || ! 
is_numeric($data['concurrent']))
+                       $data['concurrent'] = 'NULL';
+               $query = "INSERT INTO image "
+                      .         "(prettyname, "
+                      .         "ownerid, "
+                      .         "platformid, "
+                      .         "OSid, "
+                      .         "minram, "
+                      .         "minprocnumber, "
+                      .         "minprocspeed, "
+                      .         "minnetwork, "
+                      .         "maxconcurrent, "
+                      .         "reloadtime, "
+                      .         "deleted, "
+                      .         "forcheckout, "
+                      .         "architecture, "
+                      .         "description, "
+                      .         "`usage`, "
+                      .         "basedoffrevisionid) "
+                      . "VALUES ('{$data['name']}', "
+                      .         "$ownerid, "
+                      .         "{$data['platformid']}, "
+                      .         "{$data['osid']}, "
+                      .         "{$data['ram']}, "
+                      .         "{$data['cores']}, "
+                      .         "{$data['cpuspeed']}, "
+                      .         "{$data['networkspeed']}, "
+                      .         "{$data['concurrent']}, "
+                      .         "{$data['reload']}, "
+                      .         "1, "
+                      .         "{$data['checkout']}, "
+                      .         "'$arch', "
+                      .         "'{$data['desc']}', "
+                      .         "'{$data['usage']}', "
+                      .         "{$data['basedoffrevisionid']})";
+               doQuery($query, 205);
+               $imageid = dbLastInsertID();
+       
+               // possibly add entry to imagemeta table
+               $imagemetaid = 0;
+               if($data['checkuser'] == 0 ||
+                  $data['rootaccess'] == 0 ||
+                  $data['sysprep'] == 0) {
+                       $query = "INSERT INTO imagemeta "
+                              .        "(checkuser, "
+                              .        "rootaccess, "
+                              .        "sysprep) "
+                              . "VALUES "
+                              .        "({$data['checkuser']}, "
+                              .        "{$data['rootaccess']}, "
+                              .        "{$data['sysprep']})";
+                       doQuery($query, 101);
+                       $imagemetaid = dbLastInsertID();
+               }
+       
+               // create name from pretty name, os, and last insert id
+               $OSs = getOSList();
+               $name = $OSs[$data['osid']]['name'] . "-" .
+                       preg_replace('/\W/', '', $data['name']) . $imageid . 
"-v0";
+               if($imagemetaid) {
+                       $query = "UPDATE image "
+                              . "SET name = '$name', "
+                              .     "imagemetaid = $imagemetaid "
+                              . "WHERE id = $imageid";
+               }
+               else
+                       $query = "UPDATE image SET name = '$name' WHERE id = 
$imageid";
+               doQuery($query, 208);
+       
+               $query = "INSERT INTO imagerevision "
+                      .        "(imageid, "
+                      .        "userid, "
+                      .        "datecreated, "
+                      .        "production, "
+                      .        "imagename, "
+                      .        "comments, "
+                      .        "autocaptured) "
+                      . "VALUES ($imageid, "
+                      .        "{$user['id']}, "
+                      .        "NOW(), "
+                      .        "1, "
+                      .        "'$name', "
+                      .        "'{$data['comments']}', "
+                      .        "{$data['autocaptured']})";
+               doQuery($query, 101);
+               $this->imagerevisionid = dbLastInsertID();
+       
+               // possibly add entries to connectmethodmap
+               $baseconmethods = getImageConnectMethods($imageid, 0, 1);
+               $baseids = array_keys($baseconmethods);
+               $conmethodids = explode(',', $data['connectmethodids']);
+               $adds = array_diff($conmethodids, $baseids);
+               $rems = array_diff($baseids, $conmethodids);
+               $vals = array();
+               if(count($adds)) {
+                       foreach($adds as $id)
+                               $vals[] = "($id, $this->imagerevisionid, 0)";
+               }
+               if(count($rems)) {
+                       foreach($rems as $id)
+                               $vals[] = "($id, $this->imagerevisionid, 1)";
+               }
+               if(count($vals)) {
+                       $allvals = implode(',', $vals);
+                       $query = "INSERT INTO connectmethodmap "
+                              .        "(connectmethodid, "
+                              .        "imagerevisionid, "
+                              .        "disabled) "
+                              . "VALUES $allvals";
+                       doQuery($query, 101);
+               }
+       
+               // add entry in resource table
+               $query = "INSERT INTO resource "
+                                .        "(resourcetypeid, "
+                                .        "subid) "
+                                . "VALUES (13, "
+                                .         "$imageid)";
+               doQuery($query, 209);
+               $resourceid = dbLastInsertID();
+       
+               $installtype = $OSs[$data['osid']]['installtype'];
+               if($installtype == 'none' ||
+                  $installtype == 'partimage' ||
+                  $installtype == 'kickstart')
+                       $virtual = 0;
+               else
+                       $virtual = 1;
+       
+               $this->addImagePermissions($ownerdata, $resourceid, $virtual);
+       
+               return $imageid;
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn getRevisionHTML($imageid)
+       ///
+       /// \param $imageid - id of an image
+       ///
+       /// \return html
+       ///
+       /// \brief builds HTML table for in place editing of image revision data
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function getRevisionHTML($imageid) {
+               $revisions = getImageRevisions($imageid);
+               $rt = '';
+               $rt .= "<h3>Revisions of this Image</h3>\n";
+               $rt .= "<table summary=\"\"><tr><td>\n";
+               if(count($revisions) > 1 && isImageBlockTimeActive($imageid)) {
+                       $rt .= "<font color=\"red\">WARNING: This image is part 
of an active ";
+                       $rt .= "block allocation. Changing the production 
revision of the image ";
+                       $rt .= "at this time will result in new reservations 
under the block ";
+                       $rt .= "allocation to have full reload times instead of 
a &lt; 1 minutes ";
+                       $rt .= "wait.</font><br><br>\n";
+               }
+               $rt .= "<table summary=\"\" id=\"revisiontable\">\n";
+               $rt .= "  <tr>\n";
+               $rt .= "    <td></td>\n";
+               $rt .= "    <th>Revision</th>\n";
+               $rt .= "    <th>Creator</th>\n";
+               $rt .= "    <th>Created</th>\n";
+               $rt .= "    <th nowrap>In Production</th>\n";
+               $rt .= "    <th>Comments (click to edit)</th>\n";
+               $rt .= "  </tr>\n";
+               foreach($revisions AS $rev) {
+                       if($rev['deleted'] == 1)
+                               continue;
+                       $rt .= "  <tr>\n";
+                       $rt .= "    <td><INPUT type=checkbox\n";
+                       $rt .= "              id=chkrev{$rev['id']}\n";
+                       $rt .= "              name=chkrev[{$rev['id']}]\n";
+                       $rt .= "              value=1></td>\n";
+                       $rt .= "    <td align=center>{$rev['revision']}</td>\n";
+                       $rt .= "    <td>{$rev['creator']}</td>\n";
+                       $created = date('g:ia n/j/Y', 
datetimeToUnix($rev['datecreated']));
+                       $rt .= "    <td>$created</td>\n";
+                       $cdata = $this->basecdata;
+                       $cdata['imageid'] = $imageid;
+                       $cdata['revisionid'] = $rev['id'];
+                       $cont = 
addContinuationsEntry('AJupdateRevisionProduction', $cdata);
+                       $rt .= "    <td align=center><INPUT type=radio\n";
+                       $rt .= "           name=production\n";
+                       $rt .= "           value={$rev['id']}\n";
+                       $rt .= "           id=radrev{$rev['id']}\n";
+                       $rt .= "           
onclick=\"updateRevisionProduction('$cont');\"\n";
+                       if($rev['production'])
+                               $rt .= "           checked\n";
+                       $rt .= "           ></td>\n";
+                       $cont = 
addContinuationsEntry('AJupdateRevisionComments', $cdata);
+                       $rt .= "    <td width=200px><span 
id=comments{$rev['id']} \n";
+                       $rt .= "              
dojoType=\"dijit.InlineEditBox\"\n";
+                       $rt .= "              editor=\"dijit.form.Textarea\"\n";
+                       $rt .= "              
onChange=\"updateRevisionComments('comments{$rev['id']}', '$cont');\"\n";
+                       $rt .= "              noValueIndicator=\"(empty)\">\n";
+                       $rt .= "        {$rev['comments']}</span></td>\n";
+                       $rt .= "  </tr>\n";
+               }
+               $rt .= "</table>\n";
+               $rt .= "<div align=left>\n";
+               $keys = array_keys($revisions);
+               $cdata = $this->basecdata;
+               $cdata['revids'] = $keys;
+               $cdata['imageid'] = $imageid;
+               $cont = addContinuationsEntry('AJdeleteRevisions', $cdata);
+               $ids = implode(',', $keys);
+               $rt .= "<button onclick=\"deleteRevisions('$cont', '$ids'); 
return false;\">Delete selected revisions</button>\n";
+               $rt .= "</div>\n";
+               $rt .= "</td></tr></table>\n";
+               return $rt;
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn AJaddSubimage()
+       ///
+       /// \brief adds a subimage to an image
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function AJaddSubimage() {
+               $imageid = getContinuationVar('imageid');
+               $adminids = getContinuationVar('adminids');
+               $userimageids = getContinuationVar('userimageids');
+               $subimages = getContinuationVar('subimages');
+               $imagemetaid = getContinuationVar('imagemetaid');
+               if(! in_array($imageid, $adminids)) {
+                       $arr = array('error' => 'noimageaccess',
+                               'msg' => 'You do not have access to manage this 
image.');
+                       sendJSON($arr);
+                       return;
+               }
+               $newid = processInputVar('imageid', ARG_NUMERIC);
+               if(! in_array($newid, $userimageids)) {
+                       $arr = array('error' => 'nosubimageaccess',
+                               'msg' => 'You do not have access to add this 
subimage.');
+                       sendJSON($arr);
+                       return;
+               }
+               if(is_null($imagemetaid)) {
+                       $query = "INSERT INTO imagemeta "
+                              .        "(subimages) "
+                              . "VALUES (1)";
+                       doQuery($query, 101);
+                       $imagemetaid = dbLastInsertID();
+                       $query = "UPDATE image "
+                              . "SET imagemetaid = $imagemetaid "
+                              . "WHERE id = $imageid";
+                       doQuery($query, 101);
+               }
+               elseif(! count($subimages)) {
+                       $query = "UPDATE imagemeta "
+                              . "SET subimages = 1 "
+                              . "WHERE id = $imagemetaid";
+                       doQuery($query, 101);
+               }
+               $query = "INSERT INTO subimages "
+                      .        "(imagemetaid, "
+                      .        "imageid) "
+                      . "VALUES ($imagemetaid, "
+                      .        "$newid)";
+               doQuery($query, 101);
+               $subimages[] = $newid;
+               $data = array('imageid' => $imageid,
+                             'adminids' => $adminids,
+                             'imagemetaid' => $imagemetaid,
+                             'userimageids' => $userimageids,
+                             'subimages' => $subimages,
+                             'obj' => $this);
+               $addcont = addContinuationsEntry('AJaddSubimage', $data, 
SECINDAY, 1, 0);
+               $remcont = addContinuationsEntry('AJremSubimage', $data, 
SECINDAY, 1, 0);
+               $image = getImages(0, $newid);
+               $name = $image[$newid]['prettyname'];
+               $arr = array('newid' => $newid,
+                            'name' => $name,
+                            'addcont' => $addcont,
+                            'remcont' => $remcont);
+               sendJSON($arr);
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn AJremSubimage()
+       ///
+       /// \brief removes subimages from an image
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function AJremSubimage() {
+               $imageid = getContinuationVar('imageid');
+               $adminids = getContinuationVar('adminids');
+               $userimageids = getContinuationVar('userimageids');
+               $subimages = getContinuationVar('subimages');
+               $imagemetaid = getContinuationVar('imagemetaid');
+               if(! in_array($imageid, $adminids)) {
+                       $arr = array('error' => 'noimageaccess',
+                               'msg' => 'You do not have access to manage this 
image.');
+                       sendJSON($arr);
+                       return;
+               }
+               $remids = processInputVar('imageids', ARG_STRING);
+               $remids = explode(',', $remids);
+               foreach($remids as $id) {
+                       if(! is_numeric($id)) {
+                               $arr = array('error' => 'invalidinput',
+                                            'msg' => 'Non-numeric data was 
submitted for an image id.');
+                               sendJSON($arr);
+                               return;
+                       }
+               }
+               if(is_null($imagemetaid)) {
+                       $arr = array('error' => 'nullimagemetaid',
+                               'msg' => 'Invalid infomation id database. 
Contact your system administrator.');
+                       sendJSON($arr);
+                       return;
+               }
+               foreach($remids as $id) {
+                       $query = "DELETE FROM subimages "
+                              . "WHERE imagemetaid = $imagemetaid AND "
+                              .       "imageid = $id "
+                              . "LIMIT 1";
+                       doQuery($query, 101);
+               }
+               # check to see if any subimages left; if not, update imagemeta 
table
+               $query = "SELECT COUNT(imageid) "
+                                . "FROM subimages "
+                                . "WHERE imagemetaid = $imagemetaid";
+               $qh = doQuery($query, 101);
+               $row = mysql_fetch_row($qh);
+               if($row[0] == 0) {
+                       $rc = checkClearImageMeta($imagemetaid, $imageid, 
'subimages');
+                       if($rc)
+                               $imagemetaid = NULL;
+                       else {
+                               $query = "UPDATE imagemeta SET subimages = 0 
WHERE id = $imagemetaid";
+                               doQuery($query, 101);
+                       }
+                       $subimages = array();
+               }
+               # rebuild list of subimages
+               else {
+                       $query = "SELECT imageid FROM subimages WHERE 
imagemetaid = $imagemetaid";
+                       $qh = doQuery($query, 101);
+                       $subimages = array();
+                       while($row = mysql_fetch_assoc($qh))
+                               $subimages[] = $row['imageid'];
+               }
+       
+               $data = array('imageid' => $imageid,
+                             'adminids' => $adminids,
+                             'imagemetaid' => $imagemetaid,
+                             'userimageids' => $userimageids,
+                             'subimages' => $subimages,
+                             'obj' => $this);
+               $addcont = addContinuationsEntry('AJaddSubimage', $data, 
SECINDAY, 1, 0);
+               $remcont = addContinuationsEntry('AJremSubimage', $data, 
SECINDAY, 1, 0);
+               $arr = array('addcont' => $addcont,
+                            'remcont' => $remcont);
+               sendJSON($arr);
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn validateResourceData()
+       ///
+       /// \return array with these fields:\n
+       /// \b name\n
+       /// \b owner\n
+       /// \b ram\n
+       /// \b cores\n
+       /// \b cpuspeed\n
+       /// \b networkspeed\n
+       /// \b concurrent - max concurrent allowed users (0 if unlimited)\n
+       /// \b reload - estimated reload time in minutes\n
+       /// \b checkout - image is available for checkout\n
+       /// \b checkuser - reservations should be checked for a logged in user\n
+       /// \b rootaccess\n
+       /// \b sysprep - use sysprep when capturing revisions of this image\n
+       /// \b connectmethodids - ids of assigned connect methods\n
+       /// \b requestid - requestid associated with image capture\n
+       /// \b imageid - id of base image\n
+       /// \b desc - description of image\n
+       /// \b usage - user usage information\n
+       /// \b comments - image revision comments\n
+       /// \b mode - 'add' or 'edit'\n
+       /// \b error - 0 if submitted data validates; 1 if anything is invalid\n
+       /// \b errormsg - if error = 1; string of error messages separated by 
html
+       ///    break tags
+       ///
+       /// \brief validates form input from editing or adding an image
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function validateResourceData() {
+               global $user;
+
+               $return = array('error' => 0);
+
+               $return["name"] = processInputVar("name", ARG_STRING);
+               $return["owner"] = processInputVar("owner", ARG_STRING, 
"{$user["unityid"]}@{$user['affiliation']}");
+               $return["ram"] = processInputVar("ram", ARG_NUMERIC, 512);
+               $return["cores"] = processInputVar("cores", ARG_NUMERIC);
+               $return["cpuspeed"] = processInputVar("cpuspeed", ARG_NUMERIC);
+               $return["networkspeed"] = (int)processInputVar("networkspeed", 
ARG_NUMERIC);
+               $return["concurrent"] = processInputVar("concurrent", 
ARG_NUMERIC, 0);
+               $return["reload"] = processInputVar("reload", ARG_NUMERIC); # 
not in add
+               $return["checkout"] = processInputVar("checkout", ARG_NUMERIC);
+               $return["checkuser"] = processInputVar("checkuser", 
ARG_NUMERIC);
+               $return["rootaccess"] = processInputVar("rootaccess", 
ARG_NUMERIC);
+               $return["sysprep"] = processInputVar("sysprep", ARG_NUMERIC); # 
only in add
+               $return["connectmethodids"] = 
processInputVar("connectmethodids", ARG_STRING); # only in add
+
+               $return['requestid'] = getContinuationVar('requestid'); # only 
in add
+               $return["imageid"] = getContinuationVar('imageid');
+
+               $return["desc"] = processInputVar("desc", ARG_STRING);
+               if(get_magic_quotes_gpc())
+                       $return["desc"] = stripslashes($return['desc']);
+               $return['desc'] = preg_replace("/[\n\s]*$/", '', 
$return['desc']);
+               $return['desc'] = preg_replace("/\r/", '', $return['desc']);
+               $return['desc'] = htmlspecialchars($return['desc']);
+               $return['desc'] = preg_replace("/\n/", '<br>', $return['desc']);
+
+               $return["usage"] = processInputVar("usage", ARG_STRING);
+               if(get_magic_quotes_gpc())
+                       $return["usage"] = stripslashes($return['usage']);
+               $return['usage'] = preg_replace("/[\n\s]*$/", '', 
$return['usage']);
+               $return['usage'] = preg_replace("/\r/", '', $return['usage']);
+               $return['usage'] = htmlspecialchars($return['usage']);
+               $return['usage'] = preg_replace("/\n/", '<br>', 
$return['usage']);
+
+               $return["comments"] = processInputVar("imgcomments", 
ARG_STRING);
+               if(get_magic_quotes_gpc())
+                       $return["comments"] = stripslashes($return['comments']);
+               $return['comments'] = preg_replace("/[\n\s]*$/", '', 
$return['comments']);
+               $return['comments'] = preg_replace("/\r/", '', 
$return['comments']);
+               $return['comments'] = htmlspecialchars($return['comments']);
+               $return['comments'] = preg_replace("/\n/", '<br>', 
$return['comments']);
+
+               if($return['requestid'] != '')
+                       $return['mode'] = 'add';
+               else
+                       $return['mode'] = 'edit';
+
+               $errormsg = array();
+               if(preg_match("/[-'\"]/", $return["name"]) ||
+                       strlen($return["name"]) > 60 || strlen($return["name"]) 
< 2) {
+                       $return['error'] = 1;
+                       $errormsg[] = "Name must be from 2 to 60 characters and 
cannot "
+                                   . "contain any dashes (-), single (') or 
double (\") quotes.";
+               }
+               elseif(! preg_match('/^[\x20-\x7E]+$/', $return["name"])) {
+                       $return['error'] = 1;
+                       $errormsg[] = "Name can only contain alphabets, 
numbers, signs, and spaces.";
+               }
+               else {
+                       if($return['mode'] == 'edit')
+                               $imageid = $return['imageid'];
+                       else
+                               $imageid = '';
+                       if($this->checkForImageName($return["name"], "long", 
$imageid)) {
+                               $return['error'] = 1;
+                               $errormsg[] = "An image already exists with 
this name.";
+                       }
+               }
+               if($return["ram"] < 0 || $return["ram"] > 8388607) {
+                       $return['error'] = 1;
+                       $errormsg[] = "RAM must be between 0 and 8388607";
+               }
+               if($return["cores"] < 0 || $return["cores"] > 255) {
+                       $return['error'] = 1;
+                       $errormsg[] = "Cores must be between 0 and 255";
+               }
+               if($return["cpuspeed"] < 0 || $return["cpuspeed"] > 20000) {
+                       $return['error'] = 1;
+                       $errormsg[] = "Processor Speed must be between 0 and 
20000";
+               }
+               $lognetwork = log10($return['networkspeed']);
+               if($lognetwork < 1 || $lognetwork > 5) {
+                       $return['error'] = 1;
+                       $errormsg[] = "Invalid value submitted for network 
speed";
+               }
+               if((! is_numeric($return['concurrent']) && ! 
empty($return['concurrent'])) ||
+                       (is_numeric($return['concurrent']) && 
($return["concurrent"] < 0 || $return["concurrent"] > 255))) {
+                       $return['error'] = 1;
+                       $errormsg[] = "Max concurrent usage must be 0 or 
between 2 and 255";
+               }
+               if($return['mode'] == 'edit' && 
+                  ($return["reload"] < 0 || $return["reload"] > 120)) {
+                       $return['error'] = 1;
+                       $errormsg[] = "Estimated Reload Time must be between 0 
and 120";
+               }
+               if(! validateUserid($return["owner"])) {
+                       $return['error'] = 1;
+                       $errormsg[] = "Submitted ID is not valid";
+               }
+               if($return['checkout'] != 0 && $return['checkout'] != 1) {
+                       $return['error'] = 1;
+                       $errormsg[] = "Available for checkout must be Yes or 
No";
+               }
+               if($return['checkuser'] != 0 && $return['checkuser'] != 1) {
+                       $return['error'] = 1;
+                       $errormsg[] = "Check for logged in user must be Yes or 
No";
+               }
+               if($return['rootaccess'] != 0 && $return['rootaccess'] != 1) {
+                       $return['error'] = 1;
+                       $errormsg[] = "Users have administrative access must be 
Yes or No";
+               }
+               if($return['mode'] == 'add' && $return['sysprep'] != 0 &&
+                  $return['sysprep'] != 1) {
+                       $return['error'] = 1;
+                       $errormsg[] = "Use sysprep must be Yes or No";
+               }
+               if(empty($return['desc'])) {
+                       $return['error'] = 1;
+                       $errormsg[] = "You must include a description of the 
image<br>";
+               }
+               if($return['mode'] == 'add') {
+                       if(! preg_match('/^[,0-9]+$/', 
$return['connectmethodids'])) {
+                               $tmp = 
getImageConnectMethods($return['imageid'],
+                                        getContinuationVar('baserevisionid', 
0));
+                               $return['connectmethodids'] = implode(',', 
array_keys($tmp));
+                       }
+                       else {
+                               $conmethods = 
getConnectMethods($return['imageid']);
+                               $ids = array();
+                               foreach(explode(',', 
$return['connectmethodids']) as $id) {
+                                       if(array_key_exists($id, $conmethods))
+                                               $ids[$id] = 1;
+                               }
+                               if(empty($ids))
+                                       $ids = 
getImageConnectMethods($return['imageid'],
+                                                
getContinuationVar('baserevisionid', 0));
+                               $return['connectmethodids'] = implode(',', 
array_keys($ids));
+                       }
+               }
+               if($return['error'])
+                       $return['errormsg'] = implode('<br>', $errormsg);
+               return $return;
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn checkForImageName($name, $longshort, $id)
+       ///
+       /// \param $name - the name of an image
+       /// \param $longshort - "long" for long/pretty name, "short" for 
short/name
+       /// \param $id - id of an image to ignore
+       ///
+       /// \return 1 if $name is already in the image table, 0 if not
+       ///
+       /// \brief checks for $name being in the image table except for $id
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function checkForImageName($name, $longshort, $id) {
+               if($longshort == "long")
+                       $field = "prettyname";
+               else
+                       $field = "name";
+               $query = "SELECT id FROM image "
+                                . "WHERE $field = '$name'";
+               if(! empty($id))
+                       $query .= " AND id != $id";
+               $qh = doQuery($query, 101);
+               if(mysql_num_rows($qh))
+                       return 1;
+               return 0;
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn addImagePermissions($ownerdata, $resourceid, $virtual)
+       ///
+       /// \param $ownerdata - array of data returned from getUserInfo for the 
owner
+       /// of the image
+       /// \param $resourceid - id from resource table for the image
+       /// \param $virtual - (bool) 0 if bare metal image, 1 if virtual
+       ///
+       /// \brief sets up permissions, grouping, and mapping for the owner of 
the
+       /// image to be able to make a reservation for it
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function addImagePermissions($ownerdata, $resourceid, $virtual) {
+               $ownerid = $ownerdata['id'];
+               // create new node if it does not exist
+               if($virtual)
+                       $nodename = 'newvmimages';
+               else
+                       $nodename = 'newimages';
+               $query = "SELECT id "
+                       . "FROM privnode "
+                       . "WHERE name = '$nodename' AND "
+                       .       "parent = 3";
+               $qh = doQuery($query, 101);
+               if(! $row = mysql_fetch_assoc($qh)) {
+                       $query2 = "INSERT INTO privnode "
+                               .        "(parent, "
+                               .        "name) "
+                               . "VALUES "
+                               .        "(3, "
+                               .        "'$nodename')";
+                       doQuery($query2, 101);
+                       $qh = doQuery($query, 101);
+                       $row = mysql_fetch_assoc($qh);
+               }
+               $parent = $row['id'];
+               $query = "SELECT id "
+                       . "FROM privnode "
+                       . "WHERE name = '{$ownerdata['login']}-$ownerid' AND "
+                       .       "parent = $parent";
+               $qh = doQuery($query, 101);
+               if($row = mysql_fetch_assoc($qh))
+                       $newnode = $row['id'];
+               else {
+                       $query = "INSERT INTO privnode "
+                              .        "(parent, name) "
+                              . "VALUES ($parent, 
'{$ownerdata['login']}-$ownerid')";
+                       doQuery($query, 101);
+                       $qh = doQuery("SELECT LAST_INSERT_ID() FROM privnode", 
101);
+                       $row = mysql_fetch_row($qh);
+                       $newnode = $row[0];
+               }
+       
+               // give user imageCheckOut and imageAdmin at new node
+               $newprivs = array('imageCheckOut', 'imageAdmin');
+               updateUserOrGroupPrivs($ownerid, $newnode, $newprivs, array(), 
'user');
+       
+               // create new image group if it does not exist
+               $query = "SELECT id "
+                       . "FROM usergroup "
+                       . "WHERE name = 'manageNewImages'";
+               $qh = doQuery($query, 101);
+               $row = mysql_fetch_assoc($qh);
+               $ownergroupid = $row['id'];
+               if($virtual)
+                       $prefix = 'newvmimages';
+               else
+                       $prefix = 'newimages';
+               $query = "SELECT id "
+                      . "FROM resourcegroup "
+                      . "WHERE name = '$prefix-{$ownerdata['login']}-$ownerid' 
AND "
+                      .       "ownerusergroupid = $ownergroupid AND "
+                      .       "resourcetypeid = 13";
+               $qh = doQuery($query, 101);
+               if($row = mysql_fetch_assoc($qh))
+                       $resourcegroupid = $row['id'];
+               else {
+                       $query = "INSERT INTO resourcegroup "
+                              .         "(name, "
+                              .         "ownerusergroupid, "
+                              .         "resourcetypeid) "
+                              . "VALUES 
('$prefix-{$ownerdata['login']}-$ownerid', "
+                              .         "$ownergroupid, "
+                              .         "13)";
+                       doQuery($query, 305);
+                       $qh = doQuery("SELECT LAST_INSERT_ID() FROM 
resourcegroup", 101);
+                       $row = mysql_fetch_row($qh);
+                       $resourcegroupid = $row[0];
+       
+                       // map group to newimages/newvmimages comp group
+                       if($virtual)
+                               $rgroupname = 'newvmimages';
+                       else
+                               $rgroupname = 'newimages';
+                       $query = "SELECT id "
+                              . "FROM resourcegroup "
+                              . "WHERE name = '$rgroupname' AND "
+                              .       "resourcetypeid = 12";
+                       $qh = doQuery($query, 101);
+                       $row = mysql_fetch_assoc($qh);
+                       $compResGrpid = $row['id'];
+                       $query = "INSERT INTO resourcemap "
+                              .        "(resourcegroupid1, "
+                              .        "resourcetypeid1, "
+                              .        "resourcegroupid2, "
+                              .        "resourcetypeid2) "
+                              . "VALUES ($resourcegroupid, "
+                              .         "13, "
+                              .         "$compResGrpid, "
+                              .         "12)";
+                       doQuery($query, 101);
+               }
+       
+               // make image group available at new node
+               $adds = array('available', 'administer');
+               if($virtual)
+                       
updateResourcePrivs("image/newvmimages-{$ownerdata['login']}-$ownerid", 
$newnode, $adds, array());
+               else
+                       
updateResourcePrivs("image/newimages-{$ownerdata['login']}-$ownerid", $newnode, 
$adds, array());
+       
+               // add image to image group
+               $query = "INSERT INTO resourcegroupmembers "
+                      . "(resourceid, resourcegroupid) "
+                      . "VALUES ($resourceid, $resourcegroupid)";
+               doQuery($query, 101);
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn jsonImageConnectMethods()
+       ///
+       /// \brief gets list of connect methods used for specified image and 
sends
+       /// them in json format
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function jsonImageConnectMethods() {
+               $imageid = getContinuationVar('imageid');
+               $newimage = getContinuationVar('newimage');
+               $revid = processInputVar('revid', ARG_NUMERIC, 0);
+               if($revid != 0) {
+                       $revids = getContinuationVar('revids');
+                       if(! in_array($revid, $revids))
+                               $revid = getProductionRevisionid($imageid);
+               }
+               if($newimage)
+                       $curmethods = getContinuationVar('curmethods');
+               else
+                       $curmethods = getImageConnectMethods($imageid, $revid);
+               $methods = getConnectMethods($imageid);
+               $items = array();
+               foreach($methods as $id => $method) {
+                       if(array_key_exists($id, $curmethods))
+                               $active = 1;
+                       else
+                               $active = 0;
+                       $items[] = "{name:'$id', "
+                                .  "display:'{$method['description']}', "
+                                .  
"autoprovisioned:'{$method['autoprovisioned']}', "
+                                .  "active:$active}";
+               }
+               $data = implode(',', $items);
+               header('Content-Type: text/json; charset=utf-8');
+               $data = "{} && 
{label:'display',identifier:'name',items:[$data]}";
+               print $data;
+       }
+       
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn AJaddImageConnectMethod()
+       ///
+       /// \brief adds a subimage to an image
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function AJaddImageConnectMethod() {
+               $imageid = getContinuationVar('imageid');
+               $methods = getContinuationVar('methods');
+               $revids = getContinuationVar('revids');
+               $curmethods = getImageConnectMethods($imageid);
+               $newid = processInputVar('newid', ARG_NUMERIC);
+               $revid = processInputVar('revid', ARG_NUMERIC);
+               $newimage = getContinuationVar('newimage');
+               if(! array_key_exists($newid, $methods)) {
+                       $arr = array('error' => 'invalidmethod',
+                               'msg' => 'Invalid method submitted.');
+                       sendJSON($arr);
+                       return;
+               }
+               if($revid != 0 && ! in_array($revid, $revids)) {
+                       $arr = array('error' => 'invalidrevision',
+                               'msg' => 'Invalid revision id submitted.');
+                       sendJSON($arr);
+                       return;
+               }
+               if(! $newimage) {
+                       if($revid == 0)
+                               $revid = getProductionRevisionid($imageid);
+                       # delete any current entries for method and image 
(including disabled)
+                       $query = "DELETE FROM connectmethodmap "
+                              . "WHERE imagerevisionid = $revid AND "
+                              .       "connectmethodid = $newid AND "
+                              .       "autoprovisioned IS NULL";
+                       doQuery($query, 101);
+               
+                       # check to see if enabled for OStype or OS
+                       $query = "SELECT cm.connectmethodid "
+                              . "FROM connectmethodmap cm, "
+                              .      "image i "
+                              . "LEFT JOIN OS o ON (o.id = i.OSid) "
+                              . "LEFT JOIN OStype ot ON (ot.name = o.type) "
+                              . "WHERE i.id = $imageid AND "
+                              .       "cm.autoprovisioned IS NULL AND "
+                              .       "cm.connectmethodid = $newid AND "
+                              .       "cm.disabled = 0 AND "
+                              .       "(cm.OStypeid = ot.id OR "
+                              .        "cm.OSid = o.id)";
+                       $qh = doQuery($query, 101);
+                       if(! (mysql_num_rows($qh))) {
+                               # not enabled, add entry for method and image 
revision
+                               $query = "INSERT INTO connectmethodmap "
+                                      .        "(connectmethodid, "
+                                      .        "imagerevisionid, "
+                                      .        "disabled) "
+                                      . "VALUES "
+                                      .        "($newid, "
+                                      .        "$revid, "
+                                      .        "0)";
+                               doQuery($query, 101);
+                       }
+               }
+       
+               #   return success
+               $subimages[] = $newid;
+               $cdata = $this->basecdata;
+               $cdata['imageid'] = $imageid;
+               $cdata['methods'] = $methods;
+               $cdata['revids'] = $revids;
+               $cdata['newimage'] = $newimage;
+               $addcont = addContinuationsEntry('AJaddImageConnectMethod', 
$cdata, 3600, 1, 0);
+               $remcont = addContinuationsEntry('AJremImageConnectMethod', 
$cdata, 3600, 1, 0);
+               $name = $methods[$newid]['description'];
+               $arr = array('newid' => $newid,
+                            'name' => $name,
+                            'addcont' => $addcont,
+                            'remcont' => $remcont);
+               sendJSON($arr);
+               $key = getKey(array('getImageConnectMethods', (int)$imageid, 
(int)$revid));
+               if(array_key_exists($key, $_SESSION['usersessiondata']))
+                       unset($_SESSION['usersessiondata'][$key]);
+               $key = getKey(array('getImageConnectMethods', (int)$imageid, 
0));
+               if(array_key_exists($key, $_SESSION['usersessiondata']))
+                       unset($_SESSION['usersessiondata'][$key]);
+       }
+       
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn AJremImageConnectMethod()
+       ///
+       /// \brief removes subimages from an image
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function AJremImageConnectMethod() {
+               $imageid = getContinuationVar('imageid');
+               $methods = getContinuationVar('methods');
+               $revids = getContinuationVar('revids');
+               $curmethods = getImageConnectMethods($imageid);
+               $remidlist = mysql_real_escape_string(processInputVar('ids', 
ARG_STRING));
+               $remids = explode(',', $remidlist);
+               $revid = processInputVar('revid', ARG_NUMERIC);
+               $newimage = getContinuationVar('newimage');
+               foreach($remids as $id) {
+                       if(! is_numeric($id)) {
+                               $arr = array('error' => 'invalidinput',
+                                            'msg' => 'Non-numeric data was 
submitted for a connection method id.');
+                               sendJSON($arr);
+                               return;
+                       }
+               }
+               if($revid != 0 && ! in_array($revid, $revids)) {
+                       $arr = array('error' => 'invalidrevision',
+                               'msg' => 'Invalid revision id submitted.');
+                       sendJSON($arr);
+                       return;
+               }
+               if(! $newimage) {
+                       if($revid == 0)
+                               $revid = getProductionRevisionid($imageid);
+                       # delete any current entries for method and image
+                       $query = "DELETE FROM connectmethodmap "
+                              . "WHERE imagerevisionid = $revid AND "
+                              .       "connectmethodid IN ($remidlist) AND "
+                              .       "autoprovisioned IS NULL";
+                       doQuery($query, 101);
+                       # query to see if enabled for OStype or OS
+                       $insvals = array();
+                       foreach($remids as $id) {
+                               $query = "SELECT cm.connectmethodid "
+                                      . "FROM connectmethodmap cm, "
+                                      .      "image i "
+                                      . "LEFT JOIN OS o ON (o.id = i.OSid) "
+                                      . "LEFT JOIN OStype ot ON (ot.name = 
o.type) "
+                                      . "WHERE i.id = $imageid AND "
+                                      .       "cm.autoprovisioned IS NULL AND "
+                                      .       "cm.connectmethodid = $id AND "
+                                      .       "cm.disabled = 0 AND "
+                                      .       "(cm.OStypeid = ot.id OR "
+                                      .        "cm.OSid = o.id)";
+                               $qh = doQuery($query, 101);
+                               if(mysql_num_rows($qh))
+                                       # if so, add disabled entry for image 
revision and method
+                                       $insvals[] = "($id, $revid, 1)";
+                       }
+                       if(count($insvals)) {
+                               $allinsvals = implode(',', $insvals);
+                               $query = "INSERT INTO connectmethodmap "
+                                      .        "(connectmethodid, " 
+                                      .        "imagerevisionid, "
+                                      .        "disabled) "
+                                      . "VALUES $allinsvals";
+                               doQuery($query, 101);
+                       }
+               }
+       
+               $cdata = $this->basecdata;
+               $cdata['imageid'] = $imageid;
+               $cdata['methods'] = $methods;
+               $cdata['revids'] = $revids;
+               $cdata['newimage'] = $newimage;
+               $addcont = addContinuationsEntry('AJaddImageConnectMethod', 
$cdata, 3600, 1, 0);
+               $remcont = addContinuationsEntry('AJremImageConnectMethod', 
$cdata, 3600, 1, 0);
+               $arr = array('addcont' => $addcont,
+                            'remcont' => $remcont);
+               sendJSON($arr);
+               $key = getKey(array('getImageConnectMethods', (int)$imageid, 
(int)$revid));
+               if(array_key_exists($key, $_SESSION['usersessiondata']))
+                       unset($_SESSION['usersessiondata'][$key]);
+               $key = getKey(array('getImageConnectMethods', (int)$imageid, 
0));
+               if(array_key_exists($key, $_SESSION['usersessiondata']))
+                       unset($_SESSION['usersessiondata'][$key]);
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn AJupdateRevisionComments()
+       ///
+       /// \brief updates the comments for a revision
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function AJupdateRevisionComments() {
+               $imageid = getContinuationVar('imageid');
+               $revisionid = getContinuationVar('revisionid');
+               $comments = processInputVar('comments', ARG_STRING);
+               $comments = htmlspecialchars($comments);
+               if(get_magic_quotes_gpc())
+                       $comments = stripslashes($comments);
+               $comments = mysql_real_escape_string($comments);
+               $query = "UPDATE imagerevision "
+                      . "SET comments = '$comments' "
+                      . "WHERE id = $revisionid";
+               doQuery($query, 101);
+               $arr = array('comments' => $comments, 'id' => $revisionid);
+               sendJSON($arr);
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn AJupdateRevisionProduction()
+       ///
+       /// \brief updates which revision is set as the one in production
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function AJupdateRevisionProduction() {
+               $imageid = getContinuationVar('imageid');
+               $revisionid = getContinuationVar('revisionid');
+               $query = "UPDATE imagerevision "
+                      . "SET production = 0 "
+                      . "WHERE imageid = $imageid";
+               doQuery($query, 101);
+               $query = "UPDATE imagerevision "
+                      . "SET production = 1 "
+                      . "WHERE id = $revisionid";
+               doQuery($query, 101);
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn AJdeleteRevisions()
+       ///
+       /// \brief sets deleted flag for submitted revisions
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function AJdeleteRevisions() {
+               $revids = getContinuationVar('revids');
+               $imageid = getContinuationVar('imageid');
+               $checkedids = processInputVar('checkedids', ARG_STRING);
+               $ids = explode(',', $checkedids);
+               if(empty($ids)) {
+                       sendJSON(array());
+                       return;
+               }
+               foreach($ids as $id) {
+                       if(! is_numeric($id) || ! in_array($id, $revids)) {
+                               sendJSON(array());
+                               return;
+                       }
+               }
+               $query = "SELECT ir.revision "
+                      . "FROM request rq, "
+                      .      "reservation rs, "
+                      .      "imagerevision ir "
+                      . "WHERE rs.requestid = rq.id AND "
+                      .       "rs.imagerevisionid = ir.id AND "
+                      .       "rs.imagerevisionid IN ($checkedids) AND "
+                      .       "rq.stateid NOT IN (1, 5, 11, 12)";
+               $qh = doQuery($query);
+               if(mysql_num_rows($qh)) {
+                       $inuseids = array();
+                       while($row = mysql_fetch_assoc($qh))
+                               $inuseids[] = $row['revision'];
+                       $inuseids = implode(',', $inuseids);
+                       $rc = array('status' => 'error',
+                                   'msg' => "The following revisions are in 
use and cannot be deleted at this time: $inuseids");
+                       sendJSON($rc);
+                       return;
+               }
+               $query = "UPDATE imagerevision "
+                      . "SET deleted = 1, "
+                      .     "datedeleted = NOW() "
+                      . "WHERE id IN ($checkedids) "
+                      .   "AND production != 1";
+               doQuery($query, 101);
+               $html = $this->getRevisionHTML($imageid);
+               $arr = array('html' => $html);
+               sendJSON($arr);
+       }
+}
+?>


Reply via email to