| <?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. | 
 | */ | 
 |  | 
 | /** | 
 |  * \file | 
 |  * The functions listed here are for making VCL requests from other applications. | 
 |  * They are implemented according to the XML RPC spec defined at  | 
 |  * http://www.xmlrpc.com/ \n | 
 |  * There is one function called \b XMLRPCtest() that can be used during  | 
 |  * initial development to get started without actually making a request.\n | 
 |  * \n | 
 |  * The URL you will use to submit RPC calls is the URL for your VCL site | 
 |  * followed by\n\n | 
 |  * index.php?mode=xmlrpccall\n\n | 
 |  * for example if the URL for your VCL site is\n\n | 
 |  * https://vcl.mysite.org/vcl/\n\n | 
 |  * the RPC URL would be\n\n | 
 |  * https://vcl.mysite.org/vcl/index.php?mode=xmlrpccall\n\n | 
 |  * There is one exception - when calling the XMLRPCaffiliations function, the | 
 |  * mode is xmlrpcaffiliations, for example:\n\n | 
 |  * https://vcl.mysite.org/vcl/index.php?mode=xmlrpcaffiliations\n\n | 
 |  * Your application must connect using HTTPS.\n\n | 
 |  * Internal to the VCL code, "Reservations" are called "Requests"; therefore, | 
 |  * "request" is used instead of "reservation" in this documentation and in the | 
 |  * RPC functions. | 
 |  * \n | 
 |  * <h2>API Version 2</h2> | 
 |  * This is the current version of the API. It should be used for any new code | 
 |  * development. Any older code needs to be migrated to this version.\n\n | 
 |  * Authentication is handled by 2 additional HTTP headers you will need to | 
 |  * send:\n | 
 |  * \b X-User - the userid you would use to log in to the VCL site, followed | 
 |  * by the at sign (@), followed by your affiliation\n | 
 |  * example: myuserid\@NCSU\n | 
 |  * You can obtain a list of the affiliations by using the XMLRPCaffiliations() | 
 |  * call\n\n | 
 |  * \b X-Pass - the password you would use to log in to the VCL site\n | 
 |  * \n | 
 |  * There is one other additional HTTP header you must send:\n | 
 |  * \b X-APIVERSION - set this to 2\n\n | 
 |  * The X-User and X-Pass HTTP headers do not need to be passed to call the | 
 |  * XMLRPCaffiliations() function. | 
 |  */ | 
 |  | 
 | /// \example xmlrpc_example.php | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCaffiliations() | 
 | /// | 
 | /// \return an array of affiliation arrays, each with 2 indices:\n | 
 | /// \b id - id of the affiliation\n | 
 | /// \b name - name of the affiliation | 
 | /// | 
 | /// \brief gets all of the affilations for which users can log in to VCL\n | 
 | /// \b NOTE: This is the only function available for which the X-User and X-Pass | 
 | /// HTTP headers do not need to be passed | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCaffiliations() { | 
 | 	$affils = getAffiliations(); | 
 | 	$return = array(); | 
 | 	foreach($affils as $key => $val) { | 
 | 		$tmp = array('id' => $key, 'name' => $val); | 
 | 		array_push($return, $tmp); | 
 | 	} | 
 | 	return $return; | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCtest($string) | 
 | /// | 
 | /// \param $string - a string | 
 | /// | 
 | /// \return an array with 3 indices:\n | 
 | /// \b status - will be 'success'\n | 
 | /// \b message - will be 'RPC call worked successfully'\n | 
 | /// \b string - contents of $string (after being sanatized) | 
 | /// | 
 | /// \brief this is a test function that call be called when getting XML RPC | 
 | /// calls to this site to work | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCtest($string) { | 
 | 	$string = processInputData($string, ARG_STRING); | 
 | 	return array('status' => 'success', | 
 | 	             'message' => 'RPC call worked successfully', | 
 | 	             'string' => $string); | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCgetImages() | 
 | /// | 
 | /// \return an array of image arrays, each with these indices:\n | 
 | /// \b id - id of the image\n | 
 | /// \b name - name of the image\n | 
 | /// \b description - description of image\n | 
 | /// \b usage - usage instructions for image | 
 | /// | 
 | /// \brief gets the images to which the user has access | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCgetImages() { | 
 | 	$resources = getUserResources(array("imageAdmin", "imageCheckOut")); | 
 | 	$resources["image"] = removeNoCheckout($resources["image"]); | 
 | 	$return = array(); | 
 | 	$images = getImages(); | 
 | 	foreach($resources['image'] as $key => $val) { | 
 | 		$notes = getImageNotes($key); | 
 | 		$tmp = array('id' => $key, | 
 | 		             'name' => $val, | 
 | 		             'description' => $notes['description'], | 
 | 		             'usage' => $notes['usage'], | 
 | 		             'ostype' => $images[$key]['ostype']); | 
 | 		array_push($return, $tmp); | 
 | 	} | 
 | 	return $return; | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCaddRequest($imageid, $start, $length, $foruser, $nousercheck) | 
 | /// | 
 | /// \param $imageid - id of an image | 
 | /// \param $start - "now" or unix timestamp for start of reservation; will | 
 | /// use a floor function to round down to the nearest 15 minute increment | 
 | /// for actual reservation | 
 | /// \param $length - length of reservation in minutes (must be in 15 minute | 
 | /// increments) | 
 | /// \param $foruser - (optional) login to be used when setting up the account | 
 | /// on the reserved machine - CURRENTLY, THIS IS UNSUPPORTED | 
 | /// \param $nousercheck - (optional, default=0) set to 1 to disable timeout | 
 | /// when user is disconnected for too long | 
 | /// | 
 | /// \return an array with at least one index named '\b status' which will have | 
 | /// one of these values:\n | 
 | /// \b error - error occurred; there will be 2 additional elements in the array: | 
 | /// \li \b errorcode - error number\n | 
 | /// \li \b errormsg - error string\n | 
 | /// | 
 | /// \b notavailable - no computers were available for the request\n | 
 | /// \b success - there will be an additional element in the array: | 
 | /// \li \b requestid - identifier that should be passed to later calls when | 
 | /// acting on the request | 
 | /// | 
 | /// \brief tries to make a request | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCaddRequest($imageid, $start, $length, $foruser='', | 
 |                           $nousercheck=0) { | 
 | 	global $user; | 
 | 	$imageid = processInputData($imageid, ARG_NUMERIC); | 
 | 	$start = processInputData($start, ARG_STRING, 1); | 
 | 	$length = processInputData($length, ARG_NUMERIC); | 
 | 	#$foruser = processInputData($foruser, ARG_STRING, 1); | 
 |  | 
 | 	// make sure user didn't submit a request for an image he  | 
 | 	// doesn't have access to | 
 | 	$resources = getUserResources(array("imageAdmin", "imageCheckOut")); | 
 | 	$validImageids = array_keys($resources['image']); | 
 | 	if(! in_array($imageid, $validImageids)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 3, | 
 | 		             'errormsg' => "access denied to $imageid"); | 
 | 	} | 
 |  | 
 | 	# validate $start | 
 | 	if($start != 'now' && ! is_numeric($start)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 4, | 
 | 		             'errormsg' => "received invalid input for start"); | 
 | 	} | 
 |  | 
 | 	# validate $length | 
 | 	$maxtimes = getUserMaxTimes(); | 
 | 	if($maxtimes['initial'] < $length) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 6, | 
 | 		             'errormsg' => "max allowed initial length is {$maxtimes['initial']} minutes"); | 
 | 	} | 
 |  | 
 | 	$nowfuture = 'future'; | 
 | 	if($start == 'now') { | 
 | 		$start = time(); | 
 | 		$nowfuture = 'now'; | 
 | 	} | 
 | 	else | 
 | 		if($start < (time() - 30)) | 
 | 			return array('status' => 'error', | 
 | 			             'errorcode' => 5, | 
 | 			             'errormsg' => "start time is in the past"); | 
 | 	$start = unixFloor15($start); | 
 | 	$end = $start + $length * 60; | 
 | 	if($end % (15 * 60)) | 
 | 		$end = unixFloor15($end) + (15 * 60); | 
 |  | 
 | 	$max = getMaxOverlap($user['id']); | 
 | 	if(checkOverlap($start, $end, $max)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 7, | 
 | 		             'errormsg' => "reservation overlaps with another one you " | 
 | 		                         . "have, and you are allowed $max " | 
 | 		                         . "overlapping reservations at a time"); | 
 | 	} | 
 |  | 
 | 	if($nousercheck == 1) { | 
 | 		$groupid = getUserGroupID('Allow No User Check', 1); | 
 | 		$members = getUserGroupMembers($groupid); | 
 | 		if(! array_key_exists($user['id'], $members)) | 
 | 			$nousercheck = 0; | 
 | 	} | 
 | 	else | 
 | 		$nousercheck = 0; | 
 |  | 
 | 	$images = getImages(); | 
 | 	$revisionid = getProductionRevisionid($imageid); | 
 | 	$rc = isAvailable($images, $imageid, $revisionid, $start, $end, 1); | 
 | 	if($rc < 1) { | 
 | 		addLogEntry($nowfuture, unixToDatetime($start),  | 
 | 		            unixToDatetime($end), 0, $imageid); | 
 | 		return array('status' => 'notavailable'); | 
 | 	} | 
 | 	$return['requestid']= addRequest(0, array(), (1 - $nousercheck)); | 
 | 	$return['status'] = 'success'; | 
 | 	return $return; | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCaddRequestWithEnding($imageid, $start, $end, $foruser, | 
 | ///                                $nousercheck) | 
 | /// | 
 | /// \param $imageid - id of an image | 
 | /// \param $start - "now" or unix timestamp for start of reservation; will | 
 | /// use a floor function to round down to the nearest 15 minute increment | 
 | /// for actual reservation | 
 | /// \param $end - unix timestamp for end of reservation; will be rounded up to | 
 | /// the nearest 15 minute increment | 
 | /// \param $foruser - (optional) login to be used when setting up the account | 
 | /// on the reserved machine - CURRENTLY, THIS IS UNSUPPORTED | 
 | /// \param $nousercheck - (optional, default=0) set to 1 to disable timeout | 
 | /// when user is disconnected for too long | 
 | /// | 
 | /// \return an array with at least one index named '\b status' which will have | 
 | /// one of these values:\n | 
 | /// \b error - error occurred; there will be 2 additional elements in the array: | 
 | /// \li \b errorcode - error number\n | 
 | /// \li \b errormsg - error string\n | 
 | /// | 
 | /// \b notavailable - no computers were available for the request\n | 
 | /// \b success - there will be an additional element in the array: | 
 | /// \li \b requestid - identifier that should be passed to later calls when | 
 | /// acting on the request | 
 | /// | 
 | /// \brief tries to make a request with the specified ending time | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCaddRequestWithEnding($imageid, $start, $end, $foruser='', | 
 |                                     $nousercheck=0) { | 
 | 	global $user; | 
 | 	$imageid = processInputData($imageid, ARG_NUMERIC); | 
 | 	$start = processInputData($start, ARG_STRING, 1); | 
 | 	$end = processInputData($end, ARG_STRING); | 
 | 	#$foruser = processInputData($foruser, ARG_STRING, 1); | 
 |  | 
 | 	// make sure user is a member of the 'Specify End Time' group | 
 | 	$groupid = getUserGroupID('Specify End Time'); | 
 | 	$members = getUserGroupMembers($groupid); | 
 | 	if(! array_key_exists($user['id'], $members)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 35, | 
 | 		             'errormsg' => "access denied to specify end time"); | 
 | 	} | 
 |  | 
 | 	// make sure user didn't submit a request for an image he | 
 | 	// doesn't have access to | 
 | 	$resources = getUserResources(array("imageAdmin", "imageCheckOut")); | 
 | 	$validImageids = array_keys($resources['image']); | 
 | 	if(! in_array($imageid, $validImageids)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 3, | 
 | 		             'errormsg' => "access denied to $imageid"); | 
 | 	} | 
 |  | 
 | 	# validate $start | 
 | 	if($start != 'now' && ! is_numeric($start)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 4, | 
 | 		             'errormsg' => "received invalid input for start"); | 
 | 	} | 
 |  | 
 | 	# validate $end | 
 | 	if(! is_numeric($end)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 36, | 
 | 		             'errormsg' => "received invalid input for end"); | 
 | 	} | 
 | 	if($start != 'now' && $start >= $end) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 37, | 
 | 		             'errormsg' => "start must be less than end"); | 
 | 	} | 
 |  | 
 | 	$nowfuture = 'future'; | 
 | 	if($start == 'now') { | 
 | 		$start = time(); | 
 | 		$nowfuture = 'now'; | 
 | 	} | 
 | 	else | 
 | 		if($start < (time() - 30)) | 
 | 			return array('status' => 'error', | 
 | 			             'errorcode' => 5, | 
 | 			             'errormsg' => "start time is in the past"); | 
 | 	$start = unixFloor15($start); | 
 | 	if($end % (15 * 60)) | 
 | 		$end = unixFloor15($end) + (15 * 60); | 
 |  | 
 | 	$max = getMaxOverlap($user['id']); | 
 | 	if(checkOverlap($start, $end, $max)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 7, | 
 | 		             'errormsg' => "reservation overlaps with another one you " | 
 | 		                         . "have, and you are allowed $max " | 
 | 		                         . "overlapping reservations at a time"); | 
 | 	} | 
 |  | 
 | 	if($nousercheck == 1) { | 
 | 		$groupid = getUserGroupID('Allow No User Check', 1); | 
 | 		$members = getUserGroupMembers($groupid); | 
 | 		if(! array_key_exists($user['id'], $members)) | 
 | 			$nousercheck = 0; | 
 | 	} | 
 | 	else | 
 | 		$nousercheck = 0; | 
 |  | 
 | 	$images = getImages(); | 
 | 	$revisionid = getProductionRevisionid($imageid); | 
 | 	$rc = isAvailable($images, $imageid, $revisionid, $start, $end, 1); | 
 | 	if($rc < 1) { | 
 | 		addLogEntry($nowfuture, unixToDatetime($start),  | 
 | 		            unixToDatetime($end), 0, $imageid); | 
 | 		return array('status' => 'notavailable'); | 
 | 	} | 
 | 	$return['requestid']= addRequest(0, array(), (1 - $nousercheck)); | 
 | 	$return['status'] = 'success'; | 
 | 	return $return; | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCdeployServer($imageid, $start, $end, $admingroup, $logingroup, | 
 | ///                        $ipaddr, $macaddr, $monitored, $foruser, $name, | 
 | ///                        $userdata) | 
 | /// | 
 | /// \param $imageid - id of an image | 
 | /// \param $start - "now" or unix timestamp for start of reservation; will | 
 | /// use a floor function to round down to the nearest 15 minute increment | 
 | /// for actual reservation | 
 | /// \param $end - "indefinite" or unix timestamp for end of reservation; will | 
 | /// use a floor function to round up to the nearest 15 minute increment | 
 | /// for actual reservation | 
 | /// \param $admingroup - (optional, default='') admin user group for reservation | 
 | /// \param $logingroup - (optional, default='') login user group for reservation | 
 | /// \param $ipaddr - (optional, default='') IP address to use for public IP of | 
 | /// server | 
 | /// \param $macaddr - (optional, default='') MAC address to use for public NIC | 
 | /// of server | 
 | /// \param $monitored - (optional, default=0) whether or not the server should | 
 | /// be monitored - CURRENTLY, THIS IS UNSUPPORTED | 
 | /// \param $foruser - (optional) login to be used when setting up the account | 
 | /// on the reserved machine - CURRENTLY, THIS IS UNSUPPORTED | 
 | /// \param $name - (optional) name for reservation | 
 | /// \param $userdata - (optional) text that will be placed in  | 
 | /// /root/.vclcontrol/post_reserve_userdata on the reserved node | 
 | /// | 
 | /// \return an array with at least one index named '\b status' which will have | 
 | /// one of these values:\n | 
 | /// \b error - error occurred; there will be 2 additional elements in the array: | 
 | /// \li \b errorcode - error number\n | 
 | /// \li \b errormsg - error string\n | 
 | /// | 
 | /// \b notavailable - no computers were available for the request\n | 
 | /// \b success - there will be an additional element in the array: | 
 | /// \li \b requestid - identifier that should be passed to later calls when | 
 | /// acting on the request | 
 | /// | 
 | /// \brief tries to make a server request | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCdeployServer($imageid, $start, $end, $admingroup='', | 
 |                             $logingroup='', $ipaddr='', $macaddr='', | 
 |                             $monitored=0, $foruser='', $name='', | 
 |                             $userdata='') { | 
 | 	global $user, $remoteIP; | 
 | 	if(! in_array("serverCheckOut", $user["privileges"])) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 60, | 
 | 		             'errormsg' => "access denied to deploy server"); | 
 | 	} | 
 | 	$imageid = processInputData($imageid, ARG_NUMERIC); | 
 | 	$resources = getUserResources(array("imageAdmin", "imageCheckOut")); | 
 | 	$images = removeNoCheckout($resources["image"]); | 
 | 	#$extraimages = getServerProfileImages($user['id']); | 
 | 	if(! array_key_exists($imageid, $images) /*&& | 
 | 		! array_key_exists($imageid, $extraimages)*/) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 3, | 
 | 		             'errormsg' => "access denied to $imageid"); | 
 | 	} | 
 | 	if($admingroup != '') { | 
 | 		$admingroup = processInputData($admingroup, ARG_STRING); | 
 | 		if(get_magic_quotes_gpc()) | 
 | 			$admingroup = stripslashes($admingroup); | 
 | 		if(preg_match('/@/', $admingroup)) { | 
 | 			$tmp = explode('@', $admingroup); | 
 | 			$escadmingroup = mysql_real_escape_string($tmp[0]); | 
 | 			$affilid = getAffiliationID($tmp[1]); | 
 | 			if(is_null($affilid)) { | 
 | 				return array('status' => 'error', | 
 | 				             'errorcode' => 51, | 
 | 				             'errormsg' => "unknown affiliation for admin user group: {$tmp[1]}"); | 
 | 			} | 
 | 		} | 
 | 		else { | 
 | 			$escadmingroup = mysql_real_escape_string($admingroup); | 
 | 			$affilid = DEFAULT_AFFILID; | 
 | 		} | 
 | 		$admingroupid = getUserGroupID($escadmingroup, $affilid, 1); | 
 | 		if(is_null($admingroupid)) { | 
 | 			return array('status' => 'error', | 
 | 			             'errorcode' => 52, | 
 | 			             'errormsg' => "unknown admin user group: $admingroup"); | 
 | 		} | 
 | 	} | 
 | 	else | 
 | 		$admingroupid = ''; | 
 | 	if($logingroup != '') { | 
 | 		$logingroup = processInputData($logingroup, ARG_STRING); | 
 | 		if(get_magic_quotes_gpc()) | 
 | 			$logingroup = stripslashes($logingroup); | 
 | 		if(preg_match('/@/', $logingroup)) { | 
 | 			$tmp = explode('@', $logingroup); | 
 | 			$esclogingroup = mysql_real_escape_string($tmp[0]); | 
 | 			$affilid = getAffiliationID($tmp[1]); | 
 | 			if(is_null($affilid)) { | 
 | 				return array('status' => 'error', | 
 | 				             'errorcode' => 54, | 
 | 				             'errormsg' => "unknown affiliation for login user group: {$tmp[1]}"); | 
 | 			} | 
 | 		} | 
 | 		else { | 
 | 			$esclogingroup = mysql_real_escape_string($logingroup); | 
 | 			$affilid = DEFAULT_AFFILID; | 
 | 		} | 
 | 		$logingroupid = getUserGroupID($esclogingroup, $affilid, 1); | 
 | 		if(is_null($logingroupid)) { | 
 | 			return array('status' => 'error', | 
 | 			             'errorcode' => 55, | 
 | 			             'errormsg' => "unknown login user group: $logingroup"); | 
 | 		} | 
 | 	} | 
 | 	else | 
 | 		$logingroupid = ''; | 
 | 	$ipaddr = processInputData($ipaddr, ARG_STRING); | 
 | 	$ipaddrArr = explode('.', $ipaddr); | 
 | 	if($ipaddr != '' && (! preg_match('/^(([0-9]){1,3}\.){3}([0-9]){1,3}$/', $ipaddr) || | 
 | 		$ipaddrArr[0] < 1 || $ipaddrArr[0] > 255 || | 
 | 		$ipaddrArr[1] < 0 || $ipaddrArr[1] > 255 || | 
 | 		$ipaddrArr[2] < 0 || $ipaddrArr[2] > 255 || | 
 | 		$ipaddrArr[3] < 0 || $ipaddrArr[3] > 255)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 57, | 
 | 		             'errormsg' => "Invalid IP address. Must be w.x.y.z with each of " | 
 | 		                         . "w, x, y, and z being between 1 and 255 (inclusive)"); | 
 | 	} | 
 | 	$macaddr = processInputData($macaddr, ARG_STRING); | 
 | 	if($macaddr != '' && ! preg_match('/^(([A-Fa-f0-9]){2}:){5}([A-Fa-f0-9]){2}$/', $macaddr)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 58, | 
 | 		             'errormsg' => "Invalid MAC address.  Must be XX:XX:XX:XX:XX:XX " | 
 | 		                         . "with each pair of XX being from 00 to FF (inclusive)"); | 
 | 	} | 
 | 	$monitored = processInputData($monitored, ARG_NUMERIC); | 
 | 	if($monitored != 0 && $monitored != 1) | 
 | 		$monitored = 0; | 
 | 	$start = processInputData($start, ARG_STRING, 1); | 
 | 	$end = processInputData($end, ARG_STRING, 1); | 
 | 	#$foruser = processInputData($foruser, ARG_STRING, 1); | 
 |  | 
 | 	$name = processInputData($name, ARG_STRING); | 
 | 	if(get_magic_quotes_gpc()) | 
 | 		$name = stripslashes($name); | 
 | 	if(! preg_match('/^([-a-zA-Z0-9_\. ]){0,255}$/', $name)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 58, | 
 | 						 'errormsg' => "Invalid name. Can only contain letters, numbers, " | 
 | 		                         . "spaces, dashes(-), underscores(_), and periods(.) " | 
 | 		                         . "and be up to 255 characters long"); | 
 | 	} | 
 | 	$name = mysql_real_escape_string($name); | 
 |  | 
 | 	# validate $start | 
 | 	if($start != 'now' && ! is_numeric($start)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 4, | 
 | 		             'errormsg' => "received invalid input for start"); | 
 | 	} | 
 | 	# validate $end | 
 | 	if($end != 'indefinite' && ! is_numeric($end)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 59, | 
 | 		             'errormsg' => "received invalid input for end"); | 
 | 	} | 
 |  | 
 | 	$nowfuture = 'future'; | 
 | 	if($start == 'now') { | 
 | 		$start = unixFloor15(time()); | 
 | 		$nowfuture = 'now'; | 
 | 	} | 
 | 	else | 
 | 		if($start < (time() - 30)) | 
 | 			return array('status' => 'error', | 
 | 			             'errorcode' => 5, | 
 | 			             'errormsg' => "start time is in the past"); | 
 | 	if($end == 'indefinite') | 
 | 		$end = datetimeToUnix("2038-01-01 00:00:00"); | 
 | 	elseif($end % (15 * 60)) | 
 | 		$end = unixFloor15($end) + (15 * 60); | 
 | 	elseif($end < ($start + 900)) | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 88, | 
 | 		             'errormsg' => "end time must be at least 15 minutes after start time"); | 
 |  | 
 | 	$max = getMaxOverlap($user['id']); | 
 | 	if(checkOverlap($start, $end, $max)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 7, | 
 | 		             'errormsg' => "reservation overlaps with another one you " | 
 | 		                         . "have, and you are allowed $max " | 
 | 		                         . "overlapping reservations at a time"); | 
 | 	} | 
 |  | 
 | 	$images = getImages(); | 
 | 	$revisionid = getProductionRevisionid($imageid); | 
 | 	$rc = isAvailable($images, $imageid, $revisionid, $start, $end, | 
 | 	                  1, 0, 0, 0, 0, $ipaddr, $macaddr); | 
 | 	if($rc < 1) { | 
 | 		addLogEntry($nowfuture, unixToDatetime($start),  | 
 | 		            unixToDatetime($end), 0, $imageid); | 
 | 		return array('status' => 'notavailable'); | 
 | 	} | 
 | 	$return['requestid']= addRequest(); | 
 | 	$query = "UPDATE reservation " | 
 | 	       . "SET remoteIP = '$remoteIP' " | 
 | 	       . "WHERE requestid = {$return['requestid']}"; | 
 | 	doQuery($query); | 
 | 	if($userdata != '') { | 
 | 		if(get_magic_quotes_gpc()) | 
 | 			$userdata = stripslashes($userdata); | 
 | 		$esc_userdata = mysql_real_escape_string($userdata); | 
 | 		$query = "INSERT INTO variable " | 
 | 		       .        "(name, " | 
 | 		       .        "serialization, " | 
 | 		       .        "value, " | 
 | 		       .        "setby, " | 
 | 		       .        "timestamp) " | 
 | 		       . "SELECT CONCAT('userdata|', id), " | 
 | 		       .        "'none', " | 
 | 		       .        "'$esc_userdata', " | 
 | 		       .        "'webcode', " | 
 | 		       .        "NOW() " | 
 | 		       . "FROM reservation " | 
 | 		       . "WHERE requestid = {$return['requestid']}"; | 
 | 		doQuery($query); | 
 | 	} | 
 | 	$fields = array('requestid'); | 
 | 	$values = array($return['requestid']); | 
 | 	if($name != '') { | 
 | 		$fields[] = 'name'; | 
 | 		$values[] = "'$name'"; | 
 | 	} | 
 | 	if($ipaddr != '') { | 
 | 		$fields[] = 'fixedIP'; | 
 | 		$values[] = "'$ipaddr'"; | 
 | 	} | 
 | 	if($macaddr != '') { | 
 | 		$fields[] = 'fixedMAC'; | 
 | 		$values[] = "'$macaddr'"; | 
 | 	} | 
 | 	if($admingroupid != 0) { | 
 | 		$fields[] = 'admingroupid'; | 
 | 		$values[] = $admingroupid; | 
 | 	} | 
 | 	if($logingroupid != 0) { | 
 | 		$fields[] = 'logingroupid'; | 
 | 		$values[] = $logingroupid; | 
 | 	} | 
 | 	if($monitored != 0) { | 
 | 		$fields[] = 'monitored'; | 
 | 		$values[] = 1; | 
 | 	} | 
 | 	$allfields = implode(',', $fields); | 
 | 	$allvalues = implode(',', $values); | 
 | 	$query = "INSERT INTO serverrequest ($allfields) VALUES ($allvalues)"; | 
 | 	doQuery($query, 101); | 
 | 	$return['status'] = 'success'; | 
 | 	return $return; | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCgetRequestIds() | 
 | /// | 
 | /// \return an array with at least one index named 'status' which will have | 
 | /// one of these values\n | 
 | /// \b error - error occurred; there will be 2 additional elements in the array: | 
 | /// \li \b errorcode - error number\n | 
 | /// \li \b errormsg - error string\n | 
 | /// | 
 | /// \b success - request was successfully found; there will be an additional | 
 | /// element whose index is 'requests' which is an array of arrays, each having | 
 | /// these elements (or empty if no existing requests):\n | 
 | /// \li \b requestid - id of the request\n | 
 | /// \li \b imageid - id of the image\n | 
 | /// \li \b imagename - name of the image\n | 
 | /// \li \b start - unix timestamp of start time\n | 
 | /// \li \b end - unix timestamp of end time\n | 
 | /// \li \b OS - name of OS used in image\n | 
 | /// \li \b isserver - 0 or 1 - whether or not this is a server reservation\n | 
 | /// \li \b state - current state of reservation\n | 
 | /// \li \b servername - only included if isserver == 1 - name of the reservation | 
 | /// | 
 | /// \brief gets information about all of user's requests | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCgetRequestIds() { | 
 | 	global $user; | 
 | 	$requests = getUserRequests("all"); | 
 | 	if(empty($requests)) | 
 | 		return array('status' => 'success', 'requests' => array()); | 
 | 	$states = getStates(); | 
 | 	$ret = array(); | 
 | 	foreach($requests as $req) { | 
 | 		$start = datetimeToUnix($req['start']); | 
 | 		$end = datetimeToUnix($req['end']); | 
 | 		$tmp = array('requestid' => $req['id'], | 
 | 		             'imageid' => $req['imageid'], | 
 | 		             'imagename' => $req['prettyimage'], | 
 | 		             'start' => $start, | 
 | 		             'end' => $end, | 
 | 		             'OS' => $req['OS'], | 
 | 		             'ostype' => $req['ostype'], | 
 | 		             'isserver' => $req['server'], | 
 | 		             'admin' => $req['serveradmin'], | 
 | 		             'serverowner' => $req['serverowner']); | 
 | 		if($req['currstateid'] == 14) | 
 | 			$tmp['state'] = $states[$req['laststateid']]; | 
 | 		else | 
 | 			$tmp['state'] = $states[$req['currstateid']]; | 
 | 		if($req['server']) | 
 | 			$tmp['servername'] = $req['servername']; | 
 | 		array_push($ret, $tmp); | 
 | 	} | 
 | 	return array('status' => 'success', 'requests' => $ret); | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCgetRequestStatus($requestid) | 
 | /// | 
 | /// \param $requestid - id of a request | 
 | /// | 
 | /// \return an array with at least one index named '\b status' which will have | 
 | /// one of these values:\n | 
 | /// \b error - error occurred; there will be 2 additional elements in the array: | 
 | /// \li \b errorcode - error number\n | 
 | /// \li \b errormsg - error string\n | 
 | /// | 
 | /// \b ready - request is ready\n | 
 | /// \b failed - request failed to load properly\n | 
 | /// \b timedout - request timed out (user didn't connect before timeout | 
 | /// expired)\n | 
 | /// \b loading - request is still loading; there will be an additional element | 
 | /// in the array: | 
 | /// \li \b time - the estimated wait time (in minutes) for loading to complete\n | 
 | /// | 
 | /// \b future - start time of request is in the future\n | 
 | /// | 
 | /// \brief determines and returns the status of the request | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCgetRequestStatus($requestid) { | 
 | 	global $user; | 
 | 	$requestid = processInputData($requestid, ARG_NUMERIC); | 
 | 	$userRequests = getUserRequests('all', $user['id']); | 
 | 	$found = 0; | 
 | 	foreach($userRequests as $req) { | 
 | 		if($req['id'] == $requestid) { | 
 | 			$request = $req; | 
 | 			$found = 1; | 
 | 			break; | 
 | 		} | 
 | 	} | 
 | 	if(! $found) | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 1, | 
 | 		             'errormsg' => 'unknown requestid'); | 
 |  | 
 | 	$now = time(); | 
 | 	# request is ready | 
 | 	if(requestIsReady($request)) | 
 | 		return array('status' => 'ready'); | 
 | 	# request failed | 
 | 	elseif($request["currstateid"] == 5) | 
 | 		return array('status' => 'failed'); | 
 | 	# request maintenance | 
 | 	elseif($request["currstateid"] == 10) | 
 | 		return array('status' => 'maintenance'); | 
 | 	# request image | 
 | 	elseif($request["currstateid"] == 16 || | 
 | 	       $request["currstateid"] == 24 || | 
 | 	       ($request["currstateid"] == 14 && | 
 | 	       ($request["laststateid"] == 16 || | 
 | 	       $request["laststateid"] == 24))) | 
 | 		return array('status' => 'image'); | 
 | 	# other cases where the reservation start time has been reached | 
 | 	elseif(datetimeToUnix($request["start"]) < $now) { | 
 | 		# request has timed out | 
 | 		if($request["currstateid"] == 12 || | 
 | 		   $request["currstateid"] == 11 || | 
 | 		   ($request["currstateid"] == 14 && | 
 | 		   $request["laststateid"] == 11)) { | 
 | 			return array('status' => 'timedout'); | 
 | 		} | 
 | 		# computer is loading | 
 | 		else { | 
 | 			$imageid = $request['imageid']; | 
 | 			$images = getImages(0, $imageid); | 
 | 			$remaining = 1; | 
 | 			$computers = getComputers(0, 0, $request['computerid']); | 
 | 			if(isComputerLoading($request, $computers)) { | 
 | 				if(datetimeToUnix($request["daterequested"]) >= | 
 | 					datetimeToUnix($request["start"])) | 
 | 					$startload = datetimeToUnix($request["daterequested"]); | 
 | 				else | 
 | 					$startload = datetimeToUnix($request["start"]); | 
 | 				$imgLoadTime = getImageLoadEstimate($imageid); | 
 | 				if($imgLoadTime == 0) | 
 | 					$imgLoadTime = $images[$imageid]['reloadtime'] * 60; | 
 | 				$tmp = ($imgLoadTime - ($now - $startload)) / 60; | 
 | 				$remaining = sprintf("%d", $tmp) + 1; | 
 | 				if($remaining < 1) { | 
 | 					$remaining = 1; | 
 | 				} | 
 | 			} | 
 | 			return array('status' => 'loading', 'time' => $remaining); | 
 | 		} | 
 | 	} | 
 | 	# reservation is in the future | 
 | 	else | 
 | 		return array('status' => 'future'); | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCgetRequestConnectData($requestid, $remoteIP) | 
 | /// | 
 | /// \param $requestid - id of a request | 
 | /// \param $remoteIP - ip address of connecting user's computer | 
 | /// | 
 | /// \return an array with at least one index named '\b status' which will have | 
 | /// one of these values\n | 
 | /// \b error - error occurred; there will be 2 additional elements in the array: | 
 | /// \li \b errorcode - error number\n | 
 | /// \li \b errormsg - error string\n | 
 | /// | 
 | /// \b ready - request is ready; there will be 3 additional elements in the | 
 | /// array:\n | 
 | /// \li \b serverIP - address of the reserved machine | 
 | /// \li \b user - user to use when connecting to the machine | 
 | /// \li \b password - password to use when connecting to the machine | 
 | /// | 
 | /// \b notready - request is not ready for connection | 
 | /// | 
 | /// \brief if request is ready, adds the connecting user's computer to the | 
 | /// request and returns info about how to connect to the computer | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCgetRequestConnectData($requestid, $remoteIP) { | 
 | 	global $user; | 
 | 	$requestid = processInputData($requestid, ARG_NUMERIC); | 
 | 	$remoteIP = processInputData($remoteIP, ARG_STRING, 1); | 
 | 	if(! preg_match('/^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/', $remoteIP, $matches) || | 
 | 	   $matches[1] < 1 || $matches[1] > 223 || | 
 | 	   $matches[2] > 255 || | 
 | 	   $matches[3] > 255 || | 
 | 	   $matches[4] > 255) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 2, | 
 | 		             'errormsg' => 'invalid IP address'); | 
 | 	} | 
 | 	$userRequests = getUserRequests('all', $user['id']); | 
 | 	$found = 0; | 
 | 	foreach($userRequests as $req) { | 
 | 		if($req['id'] == $requestid) { | 
 | 			$request = $req; | 
 | 			$found = 1; | 
 | 			break; | 
 | 		} | 
 | 	} | 
 | 	if(! $found) | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 1, | 
 | 		             'errormsg' => 'unknown requestid'); | 
 |  | 
 | 	// FIXME - add support for cluster requests | 
 | 	if(requestIsReady($request)) { | 
 | 		$requestData = getRequestInfo($requestid); | 
 | 		$query = "UPDATE reservation " | 
 | 		       . "SET remoteIP = '$remoteIP' " | 
 | 		       . "WHERE requestid = $requestid"; | 
 | 		$qh = doQuery($query, 101); | 
 | 		addChangeLogEntry($requestData["logid"], $remoteIP); | 
 | 		$serverIP = $requestData["reservations"][0]["connectIP"]; | 
 | 		$passwd = $requestData["reservations"][0]["password"]; | 
 | 		$connectMethods = getImageConnectMethodTexts( | 
 | 		                     $requestData["reservations"][0]["imageid"], | 
 | 		                     $requestData["reservations"][0]["imagerevisionid"]); | 
 | 		if(preg_match('/(.*)@(.*)/', $user['unityid'], $matches)) | 
 | 			$thisuser = $matches[1]; | 
 | 		else | 
 | 			$thisuser = $user['unityid']; | 
 | 		$natports = getNATports($requestData['reservations'][0]['reservationid']); | 
 | 		$portdata = array(); | 
 | 		foreach($connectMethods as $key => $cm) { | 
 | 			$connecttext = $cm["connecttext"]; | 
 | 			$connecttext = preg_replace("/#userid#/", $thisuser, $connecttext);  | 
 | 			$connecttext = preg_replace("/#password#/", $passwd, $connecttext);  | 
 | 			$connecttext = preg_replace("/#connectIP#/", $serverIP, $connecttext);  | 
 | 			foreach($cm['ports'] as $port) { | 
 | 				if(! empty($natports) && array_key_exists($port['key'], $natports[$key])) { | 
 | 					$connecttext = preg_replace("/{$port['key']}/", $natports[$key][$port['key']]['publicport'], $connecttext);  | 
 | 					$connectMethods[$key]['connectports'][] = "{$port['protocol']}:{$port['port']}:{$natports[$key][$port['key']]['publicport']}"; | 
 | 				} | 
 | 				else { | 
 | 					if((preg_match('/remote desktop/i', $cm['description']) || | 
 | 					   preg_match('/RDP/i', $cm['description'])) &&  | 
 | 					   $port['key'] == '#Port-TCP-3389#') { | 
 | 						$connecttext = preg_replace("/{$port['key']}/", $user['rdpport'], $connecttext);  | 
 | 						$connectMethods[$key]['connectports'][] = "{$port['protocol']}:{$port['port']}:{$user['rdpport']}"; | 
 | 					} | 
 | 					else { | 
 | 						$connecttext = preg_replace("/{$port['key']}/", $port['port'], $connecttext);  | 
 | 						$connectMethods[$key]['connectports'][] = "{$port['protocol']}:{$port['port']}:{$port['port']}"; | 
 | 					} | 
 | 				} | 
 | 			} | 
 | 			$connectMethods[$key]["connecttext"] = $connecttext; | 
 | 			$portdata[$key] = $connectMethods[$key]['ports']; | 
 | 			unset($connectMethods[$key]['ports']); | 
 | 		} | 
 | 		$tmp = array_keys($portdata); | 
 | 		$cmid = $tmp[0]; | 
 | 		if(empty($natports)) | 
 | 			if((preg_match('/remote desktop/i', $connectMethods[$cmid]['description']) || | 
 | 			   preg_match('/RDP/i', $connectMethods[$cmid]['description'])) &&  | 
 | 				$portdata[$cmid][0]['port'] == 3389) | 
 | 				$connectport = $user['rdpport']; | 
 | 			else | 
 | 				$connectport = $portdata[$cmid][0]['port']; | 
 | 		else { | 
 | 			$key = $portdata[$cmid][0]['key']; | 
 | 			$connectport = $natports[$cmid][$key]['publicport']; | 
 | 		} | 
 | 		return array('status' => 'ready', | 
 | 		             'serverIP' => $serverIP, | 
 | 		             'user' => $thisuser, | 
 | 		             'password' => $passwd, | 
 | 		             'connectport' => $connectport, | 
 | 		             'connectMethods' => $connectMethods); | 
 | 	} | 
 | 	return array('status' => 'notready'); | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCextendRequest($requestid, $extendtime) | 
 | /// | 
 | /// \param $requestid - id of a request | 
 | /// \param $extendtime - time in minutes to extend reservation | 
 | /// | 
 | /// \return an array with at least one index named 'status' which will have | 
 | /// one of these values\n | 
 | /// \b error - error occurred; there will be 2 additional elements in the array: | 
 | /// \li \b errorcode - error number\n | 
 | /// \li \b errormsg - error string\n | 
 | /// | 
 | /// \b success - request was successfully extended\n | 
 | /// | 
 | /// \brief extends the length of an active request; if a request that has not | 
 | /// started needs to be extended, delete the request and submit a new one | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCextendRequest($requestid, $extendtime) { | 
 | 	global $user; | 
 | 	$requestid = processInputData($requestid, ARG_NUMERIC); | 
 | 	$extendtime = processInputData($extendtime, ARG_NUMERIC); | 
 |  | 
 | 	$userRequests = getUserRequests('all', $user['id']); | 
 | 	$found = 0; | 
 | 	foreach($userRequests as $req) { | 
 | 		if($req['id'] == $requestid) { | 
 | 			$request = getRequestInfo($requestid); | 
 | 			$found = 1; | 
 | 			break; | 
 | 		} | 
 | 	} | 
 | 	if(! $found) | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 1, | 
 | 		             'errormsg' => 'unknown requestid'); | 
 |  | 
 | 	$startts = datetimeToUnix($request['start']); | 
 | 	$endts = datetimeToUnix($request['end']); | 
 | 	$newendts = $endts + ($extendtime * 60); | 
 | 	if($newendts % (15 * 60)) | 
 | 		$newendts= unixFloor15($newendts) + (15 * 60); | 
 |  | 
 | 	// check for maintenance state | 
 | 	if($request['stateid'] == 10 || | 
 | 	   ($request['stateid'] == 14 && | 
 | 	   $request['laststateid'] == 10)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 103, | 
 | 		             'errormsg' => 'reservation in maintenance state'); | 
 | 	} | 
 |  | 
 | 	// check for image state | 
 | 	if($request['stateid'] == 16 || | 
 | 	   $request['stateid'] == 24 || | 
 | 	   ($request['stateid'] == 14 && | 
 | 	   ($request['laststateid'] == 16 || | 
 | 	   $request['laststateid'] == 24))) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 104, | 
 | 		             'errormsg' => 'reservation being captured'); | 
 | 	} | 
 |  | 
 | 	// check that reservation has started | 
 | 	if($startts > time()) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 38, | 
 | 		             'errormsg' => 'reservation has not started'); | 
 | 	} | 
 |  | 
 | 	// check for allowed extension length | 
 | 	$maxtimes = getUserMaxTimes(); | 
 | 	if($extendtime > $maxtimes['extend']) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 39, | 
 | 		             'errormsg' => 'extendtime exceeds allowable extension', | 
 | 		             'allowed' => $maxtimes['extend']); | 
 | 	} | 
 | 	$newlength = ($endts - $startts) / 60 + $extendtime; | 
 | 	if($newlength > $maxtimes['total']) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 40, | 
 | 		             'errormsg' => 'new reservation length exceeds allowable length', | 
 | 		             'allowed' => $maxtimes['total']); | 
 | 	} | 
 |  | 
 | 	// check for overlap | 
 | 	$max = getMaxOverlap($user['id']); | 
 | 	if(checkOverlap($startts, $newendts, $max, $requestid)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 41, | 
 | 		             'errormsg' => 'overlapping reservation restriction', | 
 | 		             'maxoverlap' => $max); | 
 | 	} | 
 |  | 
 | 	// check for computer being available for extended time? | 
 | 	$timeToNext = timeToNextReservation($request); | 
 | 	$movedall = 1; | 
 | 	$resources = getUserResources(array("imageAdmin", "imageCheckOut")); | 
 | 	$tmp = array_keys($resources['image']); | 
 | 	$semimageid = $tmp[0]; | 
 | 	$semrevid = getProductionRevisionid($semimageid); | 
 | 	if($timeToNext > -1) { | 
 | 		$lockedall = 1; | 
 | 		if(count($request['reservations']) > 1) { | 
 | 			# get semaphore on each existing node in cluster so that nothing  | 
 | 			# can get moved to the nodes during this process | 
 | 			$checkend = unixToDatetime($endts + 900); | 
 | 			foreach($request["reservations"] as $res) { | 
 | 				if(! retryGetSemaphore($semimageid, $semrevid, $res['managementnodeid'], $res['computerid'], $request['start'], $checkend, $requestid)) { | 
 | 					$lockedall = 0; | 
 | 					break; | 
 | 				} | 
 | 			} | 
 | 		} | 
 | 		if($lockedall) { | 
 | 			foreach($request["reservations"] as $res) { | 
 | 				if(! moveReservationsOffComputer($res["computerid"])) { | 
 | 					$movedall = 0; | 
 | 					break; | 
 | 				} | 
 | 			} | 
 | 		} | 
 | 		else { | 
 | 			cleanSemaphore(); | 
 | 			return array('status' => 'error', | 
 | 			             'errorcode' => 42, | 
 | 			             'errormsg' => 'cannot extend due to another reservation immediately after this one'); | 
 | 		} | 
 | 		cleanSemaphore(); | 
 | 	} | 
 | 	if(! $movedall) { | 
 | 		$timeToNext = timeToNextReservation($request); | 
 | 		if($timeToNext >= 15) | 
 | 			$timeToNext -= 15; | 
 | 		// reservation immediately after this one, cannot extend | 
 | 		if($timeToNext < 15) { | 
 | 			return array('status' => 'error', | 
 | 			             'errorcode' => 42, | 
 | 			             'errormsg' => 'cannot extend due to another reservation immediately after this one'); | 
 | 		} | 
 | 		// check that requested extension < $timeToNext | 
 | 		elseif($extendtime > $timeToNext) { | 
 | 			$extra = $timeToNext - ($timeToNext % 15); | 
 | 			return array('status' => 'error', | 
 | 			             'errorcode' => 43, | 
 | 			             'errormsg' => 'cannot extend by requested amount', | 
 | 			             'availablelength' => $extra); | 
 | 		} | 
 | 	} | 
 | 	$rc = isAvailable(getImages(), $request['reservations'][0]["imageid"], | 
 | 	                  $request['reservations'][0]['imagerevisionid'], | 
 | 	                  $startts, $newendts, 1, $requestid); | 
 | 	// conflicts with scheduled maintenance | 
 | 	if($rc == -2) { | 
 | 		addChangeLogEntry($request["logid"], NULL, unixToDatetime($newendts), | 
 | 		                  $request['start'], NULL, NULL, 0); | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 46, | 
 | 		             'errormsg' => 'requested time is during a maintenance window'); | 
 | 	} | 
 | 	// concurrent license overlap | 
 | 	elseif($rc == -1) { | 
 | 		addChangeLogEntry($request["logid"], NULL, unixToDatetime($newendts), | 
 | 		                  $request['start'], NULL, NULL, 0); | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 44, | 
 | 		             'errormsg' => 'concurrent license restriction'); | 
 | 	} | 
 | 	// could not extend for some other reason | 
 | 	elseif($rc == 0) { | 
 | 		addChangeLogEntry($request["logid"], NULL, unixToDatetime($newendts), | 
 | 		                  $request['start'], NULL, NULL, 0); | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 45, | 
 | 		             'errormsg' => 'cannot extend at this time'); | 
 | 	} | 
 | 	// success | 
 | 	updateRequest($requestid, 'now'); | 
 | 	cleanSemaphore(); | 
 | 	return array('status' => 'success'); | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCsetRequestEnding($requestid, $end) | 
 | /// | 
 | /// \param $requestid - id of a request | 
 | /// \param $end - unix timestamp for end of reservation; will be rounded up to | 
 | /// the nearest 15 minute increment | 
 | /// | 
 | /// \return an array with at least one index named 'status' which will have | 
 | /// one of these values\n | 
 | /// \b error - error occurred; there will be 2 additional elements in the array: | 
 | /// \li \b errorcode - error number\n | 
 | /// \li \b errormsg - error string\n | 
 | /// | 
 | /// \b success - request was successfully extended\n | 
 | /// | 
 | /// \brief modifies the end time of an active request; if a request that has not | 
 | /// started needs to be modifed, delete the request and submit a new one | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCsetRequestEnding($requestid, $end) { | 
 | 	global $user; | 
 |  | 
 | 	$requestid = processInputData($requestid, ARG_NUMERIC); | 
 | 	$userRequests = getUserRequests('all', $user['id']); | 
 | 	$found = 0; | 
 | 	foreach($userRequests as $req) { | 
 | 		if($req['id'] == $requestid) { | 
 | 			$request = getRequestInfo($requestid); | 
 | 			$found = 1; | 
 | 			break; | 
 | 		} | 
 | 	} | 
 | 	if(! $found) | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 1, | 
 | 		             'errormsg' => 'unknown requestid'); | 
 |  | 
 | 	// make sure user is a member of the 'Specify End Time' group | 
 | 	$groupid = getUserGroupID('Specify End Time'); | 
 | 	$members = getUserGroupMembers($groupid); | 
 | 	if(! $request['serverrequest'] && ! array_key_exists($user['id'], $members)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 35, | 
 | 		             'errormsg' => "access denied to specify end time"); | 
 | 	} | 
 |  | 
 | 	$end = processInputData($end, ARG_NUMERIC); | 
 |  | 
 | 	$maxend = datetimeToUnix("2038-01-01 00:00:00"); | 
 | 	if($end < 0 || $end > $maxend) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 36, | 
 | 		             'errormsg' => "received invalid input for end"); | 
 | 	} | 
 |  | 
 | 	// check for maintenance state | 
 | 	if($request['stateid'] == 10 || | 
 | 	   ($request['stateid'] == 14 && | 
 | 	   $request['laststateid'] == 10)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 103, | 
 | 		             'errormsg' => 'reservation in maintenance state'); | 
 | 	} | 
 |  | 
 | 	// check for image state | 
 | 	if($request['stateid'] == 16 || | 
 | 	   $request['stateid'] == 24 || | 
 | 	   ($request['stateid'] == 14 && | 
 | 	   ($request['laststateid'] == 16 || | 
 | 	   $request['laststateid'] == 24))) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 104, | 
 | 		             'errormsg' => 'reservation being captured'); | 
 | 	} | 
 |  | 
 | 	$startts = datetimeToUnix($request['start']); | 
 | 	if($end % (15 * 60)) | 
 | 		$end= unixFloor15($end) + (15 * 60); | 
 |  | 
 | 	// check that reservation has started | 
 | 	if($startts > time()) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 38, | 
 | 		             'errormsg' => 'reservation has not started'); | 
 | 	} | 
 |  | 
 | 	// check for overlap | 
 | 	$max = getMaxOverlap($user['id']); | 
 | 	if(checkOverlap($startts, $end, $max, $requestid)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 41, | 
 | 		             'errormsg' => 'overlapping reservation restriction', | 
 | 		             'maxoverlap' => $max); | 
 | 	} | 
 |  | 
 | 	// check for computer being available for extended time? | 
 | 	$timeToNext = timeToNextReservation($request); | 
 | 	$movedall = 1; | 
 | 	if($timeToNext > -1) { | 
 | 		$lockedall = 1; | 
 | 		if(count($request['reservations']) > 1) { | 
 | 			# get semaphore on each existing node in cluster so that nothing  | 
 | 			# can get moved to the nodes during this process | 
 | 			$unixend = datetimeToUnix($request['end']); | 
 | 			$checkend = unixToDatetime($unixend + 900); | 
 | 			$resources = getUserResources(array("imageAdmin", "imageCheckOut")); | 
 | 			$tmp = array_keys($resources['image']); | 
 | 			$semimageid = $tmp[0]; | 
 | 			$semrevid = getProductionRevisionid($semimageid); | 
 | 			foreach($request["reservations"] as $res) { | 
 | 				if(! retryGetSemaphore($semimageid, $semrevid, $res['managementnodeid'], $res['computerid'], $request['start'], $checkend, $requestid)) { | 
 | 					$lockedall = 0; | 
 | 					break; | 
 | 				} | 
 | 			} | 
 | 		} | 
 | 		if($lockedall) { | 
 | 			foreach($request["reservations"] as $res) { | 
 | 				if(! moveReservationsOffComputer($res["computerid"])) { | 
 | 					$movedall = 0; | 
 | 					break; | 
 | 				} | 
 | 			} | 
 | 		} | 
 | 		else { | 
 | 			cleanSemaphore(); | 
 | 			return array('status' => 'error', | 
 | 			             'errorcode' => 42, | 
 | 			             'errormsg' => 'cannot extend due to another reservation immediately after this one'); | 
 | 		} | 
 | 		cleanSemaphore(); | 
 | 	} | 
 | 	if(! $movedall) { | 
 | 		$timeToNext = timeToNextReservation($request); | 
 | 		if($timeToNext >= 15) | 
 | 			$timeToNext -= 15; | 
 | 		$oldendts = datetimeToUnix($request['end']); | 
 | 		// reservation immediately after this one, cannot extend | 
 | 		if($timeToNext < 15) { | 
 | 			return array('status' => 'error', | 
 | 			             'errorcode' => 42, | 
 | 			             'errormsg' => 'cannot extend due to another reservation immediately after this one'); | 
 | 		} | 
 | 		// check that requested extension < $timeToNext | 
 | 		elseif((($end - $oldendts) / 60) > $timeToNext) { | 
 | 			$maxend = $oldendts + ($timeToNext * 60); | 
 | 			return array('status' => 'error', | 
 | 			             'errorcode' => 43, | 
 | 			             'errormsg' => 'cannot extend by requested amount due to another reservation', | 
 | 			             'maxend' => $maxend); | 
 | 		} | 
 | 	} | 
 | 	$rc = isAvailable(getImages(), $request['reservations'][0]["imageid"], | 
 | 	                  $request['reservations'][0]['imagerevisionid'], | 
 | 	                  $startts, $end, 1, $requestid); | 
 | 	// conflicts with scheduled maintenance | 
 | 	if($rc == -2) { | 
 | 		addChangeLogEntry($request["logid"], NULL, unixToDatetime($end), | 
 | 		                  $request['start'], NULL, NULL, 0); | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 46, | 
 | 		             'errormsg' => 'requested time is during a maintenance window'); | 
 | 	} | 
 | 	// concurrent license overlap | 
 | 	elseif($rc == -1) { | 
 | 		addChangeLogEntry($request["logid"], NULL, unixToDatetime($end), | 
 | 		                  $request['start'], NULL, NULL, 0); | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 44, | 
 | 		             'errormsg' => 'concurrent license restriction'); | 
 | 	} | 
 | 	// could not extend for some other reason | 
 | 	elseif($rc == 0) { | 
 | 		addChangeLogEntry($request["logid"], NULL, unixToDatetime($end), | 
 | 		                  $request['start'], NULL, NULL, 0); | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 45, | 
 | 		             'errormsg' => 'cannot extend at this time'); | 
 | 	} | 
 | 	// success | 
 | 	updateRequest($requestid, 'now'); | 
 | 	cleanSemaphore(); | 
 | 	return array('status' => 'success'); | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCendRequest($requestid) | 
 | /// | 
 | /// \param $requestid - id of a request | 
 | /// | 
 | /// \return an array with at least one index named 'status' which will have | 
 | /// one of these values\n | 
 | /// \b error - error occurred; there will be 2 additional elements in the array: | 
 | /// \li \b errorcode - error number\n | 
 | /// \li \b errormsg - error string\n | 
 | /// | 
 | /// \b success - request was successfully ended\n | 
 | /// | 
 | /// \brief ends/deletes a request | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCendRequest($requestid) { | 
 | 	global $user; | 
 | 	$requestid = processInputData($requestid, ARG_NUMERIC); | 
 | 	$userRequests = getUserRequests('all', $user['id']); | 
 | 	$found = 0; | 
 | 	foreach($userRequests as $req) { | 
 | 		if($req['id'] == $requestid) { | 
 | 			$request = getRequestInfo($requestid); | 
 | 			$found = 1; | 
 | 			break; | 
 | 		} | 
 | 	} | 
 | 	if(! $found) | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 1, | 
 | 		             'errormsg' => 'unknown requestid'); | 
 |  | 
 | 	deleteRequest($request); | 
 | 	return array('status' => 'success'); | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCautoCapture($requestid) | 
 | /// | 
 | /// \param $requestid - id of request to be captured | 
 | /// | 
 | /// \return an array with at least one index named 'status' which will have | 
 | /// one of these values:\n | 
 | /// \b error - error occurred; there will be 2 additional elements in the array: | 
 | /// \li \b errorcode - error number | 
 | /// \li \b errormsg - error string | 
 | /// | 
 | /// \b success - image was successfully set to be captured | 
 | /// | 
 | /// \brief creates entries in appropriate tables to capture an image and sets | 
 | /// the request state to image | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCautoCapture($requestid) { | 
 | 	global $user, $xmlrpcBlockAPIUsers; | 
 | 	if(! in_array($user['id'], $xmlrpcBlockAPIUsers)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 47, | 
 | 		             'errormsg' => 'access denied to XMLRPCautoCapture'); | 
 | 	} | 
 | 	$query = "SELECT id FROM request WHERE id = $requestid"; | 
 | 	$qh = doQuery($query, 101); | 
 | 	if(! mysql_num_rows($qh)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 52, | 
 | 		             'errormsg' => 'specified request does not exist'); | 
 | 	} | 
 | 	$reqData = getRequestInfo($requestid); | 
 | 	# check state of reservation | 
 | 	if($reqData['stateid'] != 14 || $reqData['laststateid'] != 8) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 51, | 
 | 		             'errormsg' => 'reservation not in valid state'); | 
 | 	} | 
 | 	# check that not a cluster reservation | 
 | 	if(count($reqData['reservations']) > 1) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 48, | 
 | 		             'errormsg' => 'cannot image a cluster reservation'); | 
 | 	} | 
 | 	require_once(".ht-inc/image.php"); | 
 | 	$imageid = $reqData['reservations'][0]['imageid']; | 
 | 	$imageData = getImages(0, $imageid); | 
 | 	$captime = unixToDatetime(time()); | 
 | 	$comments = "start: {$reqData['start']}<br>" | 
 | 	          . "end: {$reqData['end']}<br>" | 
 | 	          . "computer: {$reqData['reservations'][0]['reservedIP']}<br>" | 
 | 	          . "capture time: $captime"; | 
 | 	# create new revision if requestor is owner and not a kickstart image | 
 | 	if($imageData[$imageid]['installtype'] != 'kickstart' && | 
 | 	   $reqData['userid'] == $imageData[$imageid]['ownerid']) { | 
 | 		$rc = Image::AJupdateImage($requestid, $reqData['userid'], $comments, 1); | 
 | 		if($rc == 0) { | 
 | 			return array('status' => 'error', | 
 | 			             'errorcode' => 49, | 
 | 			             'errormsg' => 'error encountered while attempting to create new revision'); | 
 | 		} | 
 | 	} | 
 | 	# create a new image if requestor is not owner or a kickstart image | 
 | 	else { | 
 | 		$ownerdata = getUserInfo($reqData['userid'], 1, 1); | 
 | 		$desc = "This is an autocaptured image.<br>" | 
 | 		      . "captured from image: {$reqData['reservations'][0]['prettyimage']}<br>" | 
 | 		      . "captured on: $captime<br>" | 
 | 		      . "owner: {$ownerdata['unityid']}@{$ownerdata['affiliation']}<br>"; | 
 | 		$connectmethods = getImageConnectMethods($imageid, $reqData['reservations'][0]['imagerevisionid']); | 
 | 		$data = array('requestid' => $requestid, | 
 | 		              'desc' => $desc, | 
 | 		              'usage' => '', | 
 | 		              'owner' => "{$ownerdata['unityid']}@{$ownerdata['affiliation']}", | 
 | 		              'name' => "Autocaptured ({$ownerdata['unityid']} - $requestid)", | 
 | 		              'ram' => 64, | 
 | 		              'cores' => 1, | 
 | 		              'cpuspeed' => 500, | 
 | 		              'networkspeed' => 10, | 
 | 		              'concurrent' => '', | 
 | 		              'checkuser' => 1, | 
 | 		              'rootaccess' => 1, | 
 | 		              'checkout' => 1, | 
 | 		              'sysprep' => 1, | 
 | 		              'basedoffrevisionid' => $reqData['reservations'][0]['imagerevisionid'], | 
 | 		              'platformid' => $imageData[$imageid]['platformid'], | 
 | 		              'osid' => $imageData[$imageid]["osid"], | 
 | 		              'ostype' => $imageData[$imageid]["ostype"], | 
 | 		              'sethostname' => $imageData[$imageid]["sethostname"], | 
 | 		              'reload' => 20, | 
 | 		              'comments' => $comments, | 
 | 		              'connectmethodids' => implode(',', array_keys($connectmethods)), | 
 | 		              'adauthenabled' => $imageData[$imageid]['adauthenabled'], | 
 | 		              'autocaptured' => 1); | 
 | 		if($data['adauthenabled']) { | 
 | 			$data['addomainid'] = $imageData[$imageid]['addomainid']; | 
 | 			$data['baseou'] = $imageData[$imageid]['baseOU']; | 
 | 		} | 
 | 		$obj = new Image(); | 
 | 		$imageid = $obj->addResource($data); | 
 | 		if($imageid == 0) { | 
 | 			return array('status' => 'error', | 
 | 			             'errorcode' => 50, | 
 | 			             'errormsg' => 'error encountered while attempting to create image'); | 
 | 		} | 
 |  | 
 | 		$query = "UPDATE request rq, " | 
 | 		       .        "reservation rs " | 
 | 		       . "SET rs.imageid = $imageid, " | 
 | 		       .     "rs.imagerevisionid = {$obj->imagerevisionid}, " | 
 | 		       .     "rq.stateid = 16  " | 
 | 		       . "WHERE rq.id = $requestid AND " | 
 | 		       .       "rq.id = rs.requestid"; | 
 | 		doQuery($query); | 
 | 	} | 
 | 	return array('status' => 'success'); | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCgetGroupImages($name) | 
 | /// | 
 | /// \param $name - the name of an imageGroup | 
 | /// | 
 | /// \return an array with at least one index named 'status' which will have | 
 | /// one of these values\n | 
 | /// \b error - error occurred; there will be 2 additional elements in the array: | 
 | /// \li \b errorcode - error number\n | 
 | /// \li \b errormsg - error string\n | 
 | /// | 
 | /// \b success - returns an array of images; there will be an additional element | 
 | /// in the array with an index of 'images' that is an array of images with | 
 | /// each element having the following two keys:\n | 
 | /// \li \b id - id of the image\n | 
 | /// \li \b name - name of the image | 
 | /// | 
 | /// \brief gets a list of all images in a particular group | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCgetGroupImages($name) { | 
 | 	if($groupid = getResourceGroupID("image/$name")) { | 
 | 		$membership = getResourceGroupMemberships('image'); | 
 | 		$resources = getUserResources(array("imageAdmin"), array("manageGroup")); | 
 |  | 
 | 		$images = array(); | 
 | 		foreach($resources['image'] as $imageid => $image) { | 
 | 			if(array_key_exists($imageid, $membership['image']) && | 
 | 			   in_array($groupid, $membership['image'][$imageid])) | 
 | 				array_push($images, array('id' => $imageid, 'name' => $image)); | 
 | 		} | 
 | 		return array('status' => 'success', | 
 | 		             'images' => $images); | 
 |  | 
 | 	} | 
 | 	else { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 83, | 
 | 		             'errormsg' => 'invalid resource group name'); | 
 | 	} | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCaddImageToGroup($name, $imageid) | 
 | /// | 
 | /// \param $name - the name of an imageGroup | 
 | /// \param $imageid - the id of an image | 
 | /// | 
 | /// \return an array with at least one index named 'status' which will have | 
 | /// one of these values\n | 
 | /// \b error - error occurred; there will be 2 additional elements in the array: | 
 | /// \li \b errorcode - error number\n | 
 | /// \li \b errormsg - error string\n | 
 | /// | 
 | /// \b success - image was added to the group\n | 
 | /// | 
 | /// \brief adds an image to a resource group | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCaddImageToGroup($name, $imageid) { | 
 | 	if($groupid = getResourceGroupID("image/$name")) { | 
 | 		$groups = getUserResources(array("imageAdmin"), array("manageGroup"), 1); | 
 | 		if(! array_key_exists($groupid, $groups['image'])) { | 
 | 			return array('status' => 'error', | 
 | 			             'errorcode' => 46, | 
 | 			             'errormsg' => 'Unable to access image group'); | 
 | 		} | 
 | 		$resources = getUserResources(array("imageAdmin"), array("manageGroup")); | 
 | 		if(! array_key_exists($imageid, $resources['image'])) { | 
 | 			return array('status' => 'error', | 
 | 			             'errorcode' => 47, | 
 | 			             'errormsg' => 'Unable to access image'); | 
 | 		} | 
 |  | 
 | 		$allimages = getImages(0, $imageid); | 
 | 		$query = "INSERT IGNORE INTO resourcegroupmembers " | 
 | 		       .        "(resourceid, " | 
 | 		       .        "resourcegroupid) " | 
 | 		       . "VALUES " | 
 | 		       .       "({$allimages[$imageid]['resourceid']}, " | 
 | 		       .       "$groupid)"; | 
 | 		doQuery($query); | 
 | 		return array('status' => 'success'); | 
 | 	} | 
 | 	else { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 83, | 
 | 		             'errormsg' => 'invalid resource group name'); | 
 | 	} | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCremoveImageFromGroup($name, $imageid) | 
 | /// | 
 | /// \param $name - the name of an imageGroup | 
 | /// \param $imageid - the id of an image | 
 | /// | 
 | /// \return an array with at least one index named 'status' which will have | 
 | /// one of these values\n | 
 | /// \b error - error occurred; there will be 2 additional elements in the array: | 
 | /// \li \b errorcode - error number\n | 
 | /// \li \b errormsg - error string\n | 
 | /// | 
 | /// \b success - image was removed from the group\n | 
 | /// | 
 | /// \brief removes an image from a resource group | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCremoveImageFromGroup($name, $imageid) { | 
 | 	if($groupid = getResourceGroupID("image/$name")) { | 
 | 		$groups = getUserResources(array("imageAdmin"), array("manageGroup"), 1); | 
 | 		if(! array_key_exists($groupid, $groups['image'])) { | 
 | 			return array('status' => 'error', | 
 | 			             'errorcode' => 46, | 
 | 			             'errormsg' => 'Unable to access image group'); | 
 | 		} | 
 | 		$resources = getUserResources(array("imageAdmin"), array("manageGroup")); | 
 | 		if(! array_key_exists($imageid, $resources['image'])) { | 
 | 			return array('status' => 'error', | 
 | 			             'errorcode' => 47, | 
 | 			             'errormsg' => 'Unable to access image'); | 
 | 		} | 
 |  | 
 | 		$allimages = getImages(0, $imageid); | 
 | 		$query = "DELETE FROM resourcegroupmembers " | 
 | 		       . "WHERE resourceid = {$allimages[$imageid]['resourceid']} AND " | 
 | 		       .       "resourcegroupid = $groupid"; | 
 | 		doQuery($query); | 
 | 		return array('status' => 'success'); | 
 | 	} | 
 | 	else { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 83, | 
 | 		             'errormsg' => 'invalid resource group name'); | 
 | 	} | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCaddImageGroupToComputerGroup($imageGroup, $computerGroup) | 
 | /// | 
 | /// \param $imageGroup - the name of an imageGroup | 
 | /// \param $computerGroup - the name of a computerGroup | 
 | /// | 
 | /// \return an array with at least one index named 'status' which will have | 
 | /// one of these values\n | 
 | /// \b error - error occurred; there will be 2 additional elements in the array: | 
 | /// \li \b errorcode - error number\n | 
 | /// \li \b errormsg - error string\n | 
 | /// | 
 | /// \b success - successfully mapped an image group to a computer group\n | 
 | /// | 
 | /// \brief map an image group to a computer group | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCaddImageGroupToComputerGroup($imageGroup, $computerGroup) { | 
 | 	$imageid = getResourceGroupID("image/$imageGroup"); | 
 | 	$compid = getResourceGroupID("computer/$computerGroup"); | 
 | 	if($imageid && $compid) { | 
 | 		$tmp = getUserResources(array("imageAdmin"), | 
 | 		                        array("manageMapping"), 1); | 
 | 		$imagegroups = $tmp['image']; | 
 | 		$tmp = getUserResources(array("computerAdmin"), | 
 | 		                        array("manageMapping"), 1); | 
 | 		$computergroups = $tmp['computer']; | 
 |  | 
 | 		if(array_key_exists($compid, $computergroups) && | 
 | 			array_key_exists($imageid, $imagegroups)) { | 
 | 			$mapping = getResourceMapping("image", "computer", | 
 | 			                              $imageid, $compid); | 
 | 			if(! array_key_exists($imageid, $mapping) || | 
 | 			   ! in_array($compid, $mapping[$imageid])) { | 
 | 				$query = "INSERT INTO resourcemap " | 
 | 				       .        "(resourcegroupid1, " | 
 | 				       .        "resourcetypeid1, " | 
 | 				       .        "resourcegroupid2, " | 
 | 				       .        "resourcetypeid2) " | 
 | 				       . "VALUES ($imageid, " | 
 | 				       .         "13, " | 
 | 				       .         "$compid, " | 
 | 				       .         "12)"; | 
 | 				doQuery($query, 101); | 
 | 			} | 
 | 			return array('status' => 'success'); | 
 | 		} | 
 | 		else { | 
 | 			return array('status' => 'error', | 
 | 			             'errorcode' => 84, | 
 | 			             'errormsg' => 'cannot access computer and/or image group'); | 
 | 		} | 
 | 	} | 
 | 	else { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 83, | 
 | 		             'errormsg' => 'invalid resource group name'); | 
 | 	} | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCremoveImageGroupFromComputerGroup($imageGroup, $computerGroup) | 
 | /// | 
 | /// \param $imageGroup - the name of an imageGroup | 
 | /// \param $computerGroup - the name of a computerGroup | 
 | /// | 
 | /// \return an array with at least one index named 'status' which will have | 
 | /// one of these values\n | 
 | /// \b error - error occurred; there will be 2 additional elements in the array: | 
 | /// \li \b errorcode - error number\n | 
 | /// \li \b errormsg - error string\n | 
 | /// | 
 | /// \b success - successfully removed the mapping from an image group to a | 
 | /// computer group\n | 
 | /// | 
 | /// \brief remove the mapping of an image group to a computer group | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCremoveImageGroupFromComputerGroup($imageGroup, $computerGroup) { | 
 | 	$imageid = getResourceGroupID("image/$imageGroup"); | 
 | 	$compid = getResourceGroupID("computer/$computerGroup"); | 
 | 	if($imageid && $compid) { | 
 | 		$tmp = getUserResources(array("imageAdmin"), | 
 | 		                        array("manageMapping"), 1); | 
 | 		$imagegroups = $tmp['image']; | 
 | 		$tmp = getUserResources(array("computerAdmin"), | 
 | 		                        array("manageMapping"), 1); | 
 | 		$computergroups = $tmp['computer']; | 
 |  | 
 | 		if(array_key_exists($compid, $computergroups) && | 
 | 			array_key_exists($imageid, $imagegroups)) { | 
 | 			$mapping = getResourceMapping("image", "computer", | 
 | 			                              $imageid, $compid); | 
 | 			if(array_key_exists($imageid, $mapping) && | 
 | 			   in_array($compid, $mapping[$imageid])) { | 
 | 				$query = "DELETE FROM resourcemap " | 
 | 				       . "WHERE resourcegroupid1 = $imageid AND " | 
 | 				       .       "resourcetypeid1 = 13 AND " | 
 | 				       .       "resourcegroupid2 = $compid AND " | 
 | 				       .       "resourcetypeid2 = 12"; | 
 | 				doQuery($query, 101); | 
 | 			} | 
 | 			return array('status' => 'success'); | 
 | 		} | 
 | 		else { | 
 | 			return array('status' => 'error', | 
 | 			             'errorcode' => 84, | 
 | 			             'errormsg' => 'cannot access computer and/or image group'); | 
 | 		} | 
 | 	} | 
 | 	else { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 83, | 
 | 		             'errormsg' => 'invalid resource group name'); | 
 | 	} | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCgetNodes($root) | 
 | /// | 
 | /// \param $root - (optional, default=top of tree) the ID of the node forming | 
 | /// the root of the hierarchy | 
 | /// | 
 | /// \return an array with at least one index named 'status' which will have | 
 | /// one of these values\n | 
 | /// \b error - error occurred; there will be 2 additional elements in the array: | 
 | /// \li \b errorcode - error number\n | 
 | /// \li \b errormsg - error string\n | 
 | /// | 
 | /// \b success - returns an array of nodes; there will be an additional element | 
 | /// in the array with an index of 'nodes' that is an array of nodes with each | 
 | /// element having the following three keys:\n | 
 | /// \li \b id - id of the node\n | 
 | /// \li \b name - name of the node\n | 
 | /// \li \b parent - id of the parent node | 
 | /// | 
 | /// \brief gets a list of all nodes in the privilege tree | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCgetNodes($root=NULL) { | 
 | 	global $user; | 
 | 	if(in_array("userGrant", $user["privileges"]) || | 
 | 		in_array("resourceGrant", $user["privileges"]) || | 
 | 		in_array("nodeAdmin", $user["privileges"])) { | 
 | 		$root = processInputData($root, ARG_NUMERIC); | 
 | 		$topNodes = $root ? getChildNodes($root) : getChildNodes(); | 
 | 		$nodes = array(); | 
 | 		$stack = array(); | 
 | 		foreach($topNodes as $id => $node) { | 
 | 			$node['id'] = $id; | 
 | 			array_push($nodes, $node); | 
 | 			array_push($stack, $node); | 
 | 		}  | 
 | 		while(count($stack)) { | 
 | 			$item = array_shift($stack); | 
 | 			$children = getChildNodes($item['id']); | 
 | 			foreach($children as $id => $node) { | 
 | 				$node['id'] = $id; | 
 | 				array_push($nodes, $node); | 
 | 				array_push($stack, $node); | 
 | 			} | 
 | 		} | 
 | 		return array('status' => 'success', | 
 | 		             'nodes' => $nodes); | 
 | 	} | 
 | 	else { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 70, | 
 | 		             'errormsg' => 'User cannot access node content'); | 
 | 	} | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCnodeExists($nodeName, $parentNode) | 
 | /// | 
 | /// \param $nodeName - the name of a node | 
 | /// \param $parentNode - the ID of the parent node | 
 | /// | 
 | /// \return an array with at least one index named 'status' which will have | 
 | /// one of these values\n | 
 | /// \b error - error occurred; there will be 2 additional elements in the array: | 
 | /// \li \b errorcode - error number\n | 
 | /// \li \b errormsg - error string\n | 
 | /// | 
 | /// \b success - returns an 'exists' element set to either 1 or 0\n | 
 | /// | 
 | /// \brief indicates whether a node with that name already exists at this | 
 | /// location in the privilege tree | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCnodeExists($nodeName, $parentNode) { | 
 | 	global $user; | 
 | 	if(! is_numeric($parentNode)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 78, | 
 | 		             'errormsg' => 'Invalid nodeid specified'); | 
 | 	} | 
 | 	if(in_array("userGrant", $user["privileges"]) || | 
 | 		in_array("resourceGrant", $user["privileges"]) || | 
 | 		in_array("nodeAdmin", $user["privileges"])) { | 
 | 		if(get_magic_quotes_gpc()) | 
 | 			$nodeName = stripslashes($nodeName); | 
 | 		$nodeName = mysql_real_escape_string($nodeName); | 
 | 		// does a node with this name already exist? | 
 | 		$query = "SELECT id " | 
 | 		       . "FROM privnode " | 
 | 		       . "WHERE name = '$nodeName' AND parent = $parentNode"; | 
 | 		$qh = doQuery($query, 335); | 
 | 		if(mysql_num_rows($qh)) | 
 | 			return array('status' => 'success', 'exists' => TRUE); | 
 | 		else | 
 | 			return array('status' => 'success', 'exists' => FALSE); | 
 | 	} | 
 | 	else { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 70, | 
 | 		             'errormsg' => 'User cannot access node content'); | 
 | 	} | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCaddNode($nodeName, $parentNode) | 
 | /// | 
 | /// \param $nodeName - the name of the new node | 
 | /// \param $parentNode - the ID of the node parent | 
 | /// | 
 | /// \return an array with at least one index named 'status' which will have | 
 | /// one of these values\n | 
 | /// \b error - error occurred; there will be 2 additional elements in the array: | 
 | /// \li \b errorcode - error number\n | 
 | /// \li \b errormsg - error string\n | 
 | /// | 
 | /// \b success - node was successfully added | 
 | /// | 
 | /// \brief add a node to the privilege tree as a child of the specified parent | 
 | /// node | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCaddNode($nodeName, $parentNode) { | 
 | 	require_once(".ht-inc/privileges.php"); | 
 | 	global $user; | 
 | 	if(! is_numeric($parentNode)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 78, | 
 | 		             'errormsg' => 'Invalid nodeid specified'); | 
 | 	} | 
 | 	if(in_array("nodeAdmin", $user['privileges'])) { | 
 | 		$nodeInfo = getNodeInfo($parentNode); | 
 | 		if(is_null($nodeInfo)) { | 
 | 			return array('status' => 'error', | 
 | 			             'errorcode' => 78, | 
 | 			             'errormsg' => 'Invalid nodeid specified'); | 
 | 		} | 
 |  | 
 | 		if(! validateNodeName($nodeName, $tmp)) { | 
 | 			return array('status' => 'error', | 
 | 			             'errorcode' => 81, | 
 | 			             'errormsg' => 'Invalid node name'); | 
 | 		} | 
 |  | 
 | 		if(checkUserHasPriv("nodeAdmin", $user['id'], $parentNode)) { | 
 | 			$query = "SELECT id " | 
 | 			       . "FROM privnode " | 
 | 			       . "WHERE name = '$nodeName' AND parent = $parentNode"; | 
 | 			$qh = doQuery($query); | 
 | 			if(mysql_num_rows($qh)) { | 
 | 				return array('status' => 'error', | 
 | 				             'errorcode' => 82, | 
 | 				             'errormsg' => 'A node of that name already exists under ' . $nodeInfo['name']); | 
 | 			} | 
 | 			$query = "INSERT IGNORE INTO privnode " | 
 | 			       .        "(parent, name) " | 
 | 			       . "VALUES " | 
 | 			       .        "($parentNode, '$nodeName')"; | 
 | 			doQuery($query); | 
 | 			$qh = doQuery("SELECT LAST_INSERT_ID() FROM privnode", 101); | 
 | 			if(! $row = mysql_fetch_row($qh)) { | 
 | 				return array('status' => 'error', | 
 | 				             'errorcode' => 85, | 
 | 				             'errormsg' => 'Could not add node to database'); | 
 | 			} | 
 | 			$nodeid = $row[0]; | 
 | 			return array('status' => 'success', | 
 | 			             'nodeid' => $nodeid); | 
 | 		} | 
 | 		else { | 
 | 			return array('status' => 'error', | 
 | 			             'errorcode' => 49, | 
 | 			             'errormsg' => 'Unable to add node at this location'); | 
 | 		} | 
 | 	} | 
 | 	else { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 70, | 
 | 		             'errormsg' => 'User cannot access node content'); | 
 | 	} | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCremoveNode($nodeID) | 
 | /// | 
 | /// \param $nodeID - the ID of a node | 
 | /// | 
 | /// \return an array with at least one index named 'status' which will have | 
 | /// one of these values\n | 
 | /// \b error - error occurred; there will be 2 additional elements in the array: | 
 | /// \li \b errorcode - error number\n | 
 | /// \li \b errormsg - error string\n | 
 | /// | 
 | /// \b success - node was successfully deleted | 
 | /// | 
 | /// \brief delete a node from the privilege tree | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCremoveNode($nodeID) { | 
 | 	require_once(".ht-inc/privileges.php"); | 
 | 	global $user; | 
 | 	if(! is_numeric($nodeID)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 78, | 
 | 		             'errormsg' => 'Invalid nodeid specified'); | 
 | 	} | 
 | 	if(! in_array("nodeAdmin", $user['privileges'])) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 70, | 
 | 		             'errormsg' => 'User cannot administer nodes'); | 
 | 	} | 
 | 	if(! checkUserHasPriv("nodeAdmin", $user['id'], $nodeID)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 57, | 
 | 		             'errormsg' => 'User cannot edit this node'); | 
 | 	} | 
 | 	$nodes = recurseGetChildren($nodeID); | 
 | 	array_push($nodes, $nodeID); | 
 | 	$deleteNodes = implode(',', $nodes); | 
 | 	$query = "DELETE FROM privnode " | 
 | 	       . "WHERE id IN ($deleteNodes)"; | 
 | 	doQuery($query, 345); | 
 | 	return array('status' => 'success'); | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCgetUserGroupPrivs($name, $affiliation, $nodeid) | 
 | /// | 
 | /// \param $name - the name of the user group | 
 | /// \param $affiliation - the affiliation of the group | 
 | /// \param $nodeid - the ID of the node in the privilege tree | 
 | /// | 
 | /// \return an array with at least one index named 'status' which will have | 
 | /// one of these values\n | 
 | /// \b error - error occurred; there will be 2 additional elements in the array: | 
 | /// \li \b errorcode - error number\n | 
 | /// \li \b errormsg - error string\n | 
 | /// | 
 | /// \b success - an additional element is returned:\n | 
 | /// \li \b privileges - array of privileges assigned at the node | 
 | /// | 
 | /// \brief get a list of privileges for a user group at a particular node in the | 
 | /// privilege tree | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCgetUserGroupPrivs($name, $affiliation, $nodeid) { | 
 | 	require_once(".ht-inc/privileges.php"); | 
 | 	global $user; | 
 |  | 
 | 	if(! is_numeric($nodeid)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 78, | 
 | 		             'errormsg' => 'Invalid nodeid specified'); | 
 | 	} | 
 |  | 
 | 	if(! in_array("userGrant", $user["privileges"]) && | 
 | 		! in_array("resourceGrant", $user["privileges"]) && | 
 | 		! in_array("nodeAdmin", $user["privileges"])) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 62, | 
 | 		             'errormsg' => 'Unable to view user group privileges'); | 
 | 	} | 
 |  | 
 | 	$validate = array('name' => $name, | 
 | 	                  'affiliation' => $affiliation); | 
 | 	$rc = validateAPIgroupInput($validate, 1); | 
 | 	if($rc['status'] == 'error') | 
 | 		return $rc; | 
 |  | 
 | 	$groupid = $rc['id']; | 
 |  | 
 | 	$privileges = array(); | 
 | 	$nodePrivileges = getNodePrivileges($nodeid, 'usergroups'); | 
 | 	$cascadedNodePrivileges = getNodeCascadePrivileges($nodeid, 'usergroups');  | 
 | 	$cngp = $cascadedNodePrivileges['usergroups']; | 
 | 	$ngp = $nodePrivileges['usergroups']; | 
 | 	if(array_key_exists($groupid, $cngp)) { | 
 | 		foreach($cngp[$groupid]['privs'] as $p) { | 
 | 			if(! array_key_exists($groupid, $ngp) || | 
 | 			   ! in_array("block", $ngp[$groupid]['privs'])) | 
 | 				array_push($privileges, $p); | 
 | 		} | 
 | 	} | 
 | 	if(array_key_exists($groupid, $ngp)) { | 
 | 		foreach($ngp[$groupid]['privs'] as $p) { | 
 | 			if($p != "block") | 
 | 				array_push($privileges, $p); | 
 | 		} | 
 | 	} | 
 |  | 
 | 	return array('status' => 'success', | 
 | 	              'privileges' => array_unique($privileges)); | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCaddUserGroupPriv($name, $affiliation, $nodeid, $permissions) | 
 | /// | 
 | /// \param $name - the name of the user group | 
 | /// \param $affiliation - the affiliation of the user group | 
 | /// \param $nodeid - the ID of the node in the privilege tree | 
 | /// \param $permissions - a colon (:) delimited list of privileges to add | 
 | /// | 
 | /// \return an array with at least one index named 'status' which will have | 
 | /// one of these values\n | 
 | /// \b error - error occurred; there will be 2 additional elements in the array: | 
 | /// \li \b errorcode - error number\n | 
 | /// \li \b errormsg - error string\n | 
 | /// | 
 | /// \b success - privileges were successfully added | 
 | /// | 
 | /// \brief add privileges for a user group at a particular node in the | 
 | /// privilege tree | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCaddUserGroupPriv($name, $affiliation, $nodeid, $permissions) { | 
 | 	require_once(".ht-inc/privileges.php"); | 
 | 	global $user; | 
 |  | 
 | 	if(! is_numeric($nodeid)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 78, | 
 | 		             'errormsg' => 'Invalid nodeid specified'); | 
 | 	} | 
 |  | 
 | 	if(! checkUserHasPriv("userGrant", $user['id'], $nodeid)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 52, | 
 | 		             'errormsg' => 'Unable to add a user group to this node'); | 
 | 	} | 
 |  | 
 | 	$validate = array('name' => $name, | 
 | 	                  'affiliation' => $affiliation); | 
 | 	$rc = validateAPIgroupInput($validate, 1); | 
 | 	if($rc['status'] == 'error') | 
 | 		return $rc; | 
 |  | 
 | 	$groupid = $rc['id']; | 
 | 	$perms = explode(':', $permissions); | 
 | 	$usertypes = getTypes('users'); | 
 | 	array_push($usertypes["users"], "block"); | 
 | 	array_push($usertypes["users"], "cascade"); | 
 |  | 
 | 	$diff = array_diff($perms, $usertypes['users']); | 
 | 	if(! count($perms) || count($diff) || | 
 | 	   (count($perms) == 1 && $perms[0] == 'cascade')) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 66, | 
 | 		             'errormsg' => 'Invalid or missing permissions list supplied'); | 
 | 	} | 
 |  | 
 | 	$cnp = getNodeCascadePrivileges($nodeid, "usergroups"); | 
 | 	$np = getNodePrivileges($nodeid, "usergroups", $cnp); | 
 |  | 
 | 	if(array_key_exists($groupid, $np['usergroups'])) { | 
 | 		$diff = array_diff($perms, $np['usergroups'][$groupid]['privs']); | 
 | 		if(empty($diff)) | 
 | 			return array('status' => 'success'); | 
 | 	} | 
 | 	else | 
 | 		$diff = $perms; | 
 |  | 
 | 	updateUserOrGroupPrivs($groupid, $nodeid, $diff, array(), "group"); | 
 | 	return array('status' => 'success'); | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCremoveUserGroupPriv($name, $affiliation, $nodeid, | 
 | ///                                   $permissions) | 
 | /// | 
 | /// \param $name - the name of the user group | 
 | /// \param $affiliation - the affiliation of the user group | 
 | /// \param $nodeid - the ID of the node in the privilege tree | 
 | /// \param $permissions - a colon (:) delimited list of privileges to remove | 
 | /// | 
 | /// \return an array with at least one index named 'status' which will have | 
 | /// one of these values\n | 
 | /// \b error - error occurred; there will be 2 additional elements in the array: | 
 | /// \li \b errorcode - error number\n | 
 | /// \li \b errormsg - error string\n | 
 | /// | 
 | /// \b success - privileges were successfully removed | 
 | /// | 
 | /// \brief remove privileges for a resource group at a particular node in the | 
 | /// privilege tree | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCremoveUserGroupPriv($name, $affiliation, $nodeid, $permissions) { | 
 | 	require_once(".ht-inc/privileges.php"); | 
 | 	global $user; | 
 |  | 
 | 	if(! is_numeric($nodeid)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 78, | 
 | 		             'errormsg' => 'Invalid nodeid specified'); | 
 | 	} | 
 |  | 
 | 	if(! checkUserHasPriv("userGrant", $user['id'], $nodeid)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 65, | 
 | 		             'errormsg' => 'Unable to remove user group privileges on this node'); | 
 | 	} | 
 |  | 
 | 	$validate = array('name' => $name, | 
 | 	                  'affiliation' => $affiliation); | 
 | 	$rc = validateAPIgroupInput($validate, 1); | 
 | 	if($rc['status'] == 'error') | 
 | 		return $rc; | 
 |  | 
 | 	$groupid = $rc['id']; | 
 | 	$perms = explode(':', $permissions); | 
 | 	$usertypes = getTypes('users'); | 
 | 	array_push($usertypes["users"], "block"); | 
 | 	array_push($usertypes["users"], "cascade"); | 
 |  | 
 | 	$diff = array_diff($perms, $usertypes['users']); | 
 | 	if(count($diff)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 66, | 
 | 		             'errormsg' => 'Invalid or missing permissions list supplied'); | 
 | 	} | 
 |  | 
 | 	$cnp = getNodeCascadePrivileges($nodeid, "usergroups"); | 
 | 	$np = getNodePrivileges($nodeid, "usergroups"); | 
 |  | 
 | 	if(array_key_exists($groupid, $cnp['usergroups']) && | 
 | 	   (! array_key_exists($groupid, $np['usergroups']) || | 
 | 	   ! in_array('block', $np['usergroups'][$groupid]['privs']))) { | 
 | 		$intersect = array_intersect($cnp['usergroups'][$groupid]['privs'], $perms); | 
 | 		if(count($intersect)) { | 
 | 			return array('status' => 'error', | 
 | 			             'errorcode' => 80, | 
 | 			             'errormsg' => 'Unable to modify privileges cascaded to this node'); | 
 | 		} | 
 | 	} | 
 |  | 
 | 	$diff = array_diff($np['usergroups'][$groupid]['privs'], $perms); | 
 | 	if(count($diff) == 1 && in_array("cascade", $diff)) | 
 | 		array_push($perms, "cascade"); | 
 |  | 
 | 	updateUserOrGroupPrivs($groupid, $nodeid, array(), $perms, "group"); | 
 | 	return array('status' => 'success'); | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCgetResourceGroupPrivs($name, $type, $nodeid) | 
 | /// | 
 | /// \param $name - the name of the resource group | 
 | /// \param $type - the resource group type | 
 | /// \param $nodeid - the ID of the node in the privilege tree | 
 | /// | 
 | /// \return an array with at least one index named 'status' which will have | 
 | /// one of these values\n | 
 | /// \b error - error occurred; there will be 2 additional elements in the array: | 
 | /// \li \b errorcode - error number\n | 
 | /// \li \b errormsg - error string\n | 
 | /// | 
 | /// \b success - an additional element is returned:\n | 
 | /// \li \b privileges - array of privileges assigned at the node | 
 | /// | 
 | /// \brief get a list of privileges for a resource group at a particular node in | 
 | /// the privilege tree | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCgetResourceGroupPrivs($name, $type, $nodeid) { | 
 | 	require_once(".ht-inc/privileges.php"); | 
 | 	global $user; | 
 |  | 
 | 	if(! is_numeric($nodeid)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 78, | 
 | 		             'errormsg' => 'Invalid nodeid specified'); | 
 | 	} | 
 |  | 
 | 	if(! in_array("userGrant", $user["privileges"]) && | 
 | 		! in_array("resourceGrant", $user["privileges"]) && | 
 | 		! in_array("nodeAdmin", $user["privileges"])) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 63, | 
 | 		             'errormsg' => 'Unable to view resource group privileges'); | 
 | 	} | 
 |  | 
 | 	if($typeid = getResourceTypeID($type)) { | 
 | 		if(! $groupid = getResourceGroupID("$type/$name")) { | 
 | 			return array('status' => 'error', | 
 | 			             'errorcode' => 74, | 
 | 			             'errormsg' => 'resource group does not exist'); | 
 | 		} | 
 | 		$np = getNodePrivileges($nodeid, 'resources'); | 
 | 		$cnp = getNodeCascadePrivileges($nodeid, 'resources');  | 
 | 		$key = "$type/$name/$groupid"; | 
 | 		if(isset($np['resources'][$key]['block']) || ! isset($cnp['resources'][$key])) | 
 | 			$privs = array_keys($np['resources'][$key]); | 
 | 		elseif(isset($cnp['resources'][$key]) && isset($np['resources'][$key])) { | 
 | 			$allprivs = array_merge($cnp['resources'][$key], $np['resources'][$key]); | 
 | 			$privs = array_keys($allprivs); | 
 | 		} | 
 | 		elseif(isset($cnp['resources'][$key])) | 
 | 			$privs = array_keys($cnp['resources'][$key]); | 
 | 		else | 
 | 			$privs = array(); | 
 | 		return array('status' => 'success', | 
 | 		             'privileges' => $privs); | 
 | 	} | 
 | 	else { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 71, | 
 | 		             'errormsg' => 'Invalid resource type'); | 
 | 	} | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCaddResourceGroupPriv($name, $type, $nodeid, $permissions) | 
 | /// | 
 | /// \param $name - the name of the resource group | 
 | /// \param $type - the resource group type | 
 | /// \param $nodeid - the ID of the node in the privilege tree | 
 | /// \param $permissions - a colon (:) delimited list of privileges to add | 
 | /// | 
 | /// \return an array with at least one index named 'status' which will have | 
 | /// one of these values\n | 
 | /// \b error - error occurred; there will be 2 additional elements in the array: | 
 | /// \li \b errorcode - error number\n | 
 | /// \li \b errormsg - error string\n | 
 | /// | 
 | /// \b success - privileges were successfully added | 
 | /// | 
 | /// \brief add privileges for a resource group at a particular node in the | 
 | /// privilege tree | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCaddResourceGroupPriv($name, $type, $nodeid, $permissions) { | 
 | 	return _XMLRPCchangeResourceGroupPriv_sub('add', $name, $type, $nodeid, | 
 | 	                                          $permissions); | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCremoveResourceGroupPriv($name, $type, $nodeid, $permissions) | 
 | /// | 
 | /// \param $name - the name of the resource group | 
 | /// \param $type - the resource type | 
 | /// \param $nodeid - the ID of the node in the privilege tree | 
 | /// \param $permissions - a colon (:) delimited list of privileges to remove | 
 | /// | 
 | /// \return an array with at least one index named 'status' which will have | 
 | /// one of these values\n | 
 | /// \b error - error occurred; there will be 2 additional elements in the array: | 
 | /// \li \b errorcode - error number\n | 
 | /// \li \b errormsg - error string\n | 
 | /// | 
 | /// \b success - privileges were successfully removed | 
 | /// | 
 | /// \brief remove privileges for a resource group from a node in the privilege | 
 | /// tree | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCremoveResourceGroupPriv($name, $type, $nodeid, $permissions) { | 
 | 	return _XMLRPCchangeResourceGroupPriv_sub('remove', $name, $type, $nodeid, | 
 | 	                                          $permissions); | 
 | } | 
 |  | 
 | ################################################################################## | 
 | ### | 
 | ### fn _XMLRPCchangeResourceGroupPriv_sub($mode, $name, $type, $nodeid, | 
 | ###                                       $permissions) | 
 | ### | 
 | ### param $mode - 'add' or 'remove' | 
 | ### param $name - the name of the resource group | 
 | ### param $type - the resource type | 
 | ### param $nodeid - the ID of the node in the privilege tree | 
 | ### param $permissions - a colon (:) delimited list of privileges to remove | 
 | ### | 
 | ### return an array with at least one index named 'status' which will have | 
 | ### one of these values\n | 
 | ### error - error occurred; there will be 2 additional elements in the array: | 
 | ### * errorcode - error number\n | 
 | ### * errormsg - error string\n | 
 | ### | 
 | ### success - privileges were successfully added or removed | 
 | ### | 
 | ### brief internal function to be called from XMLRPCremoveResourceGroupPriv and | 
 | ### XMLRPCaddResourceGroupPriv - adds or removes privileges for a resource group | 
 | ### from a node in the privilege tree | 
 | ### | 
 | ################################################################################ | 
 | function _XMLRPCchangeResourceGroupPriv_sub($mode, $name, $type, $nodeid, | 
 |                                             $permissions) { | 
 | 	require_once(".ht-inc/privileges.php"); | 
 | 	global $user; | 
 |  | 
 | 	if(! is_numeric($nodeid)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 78, | 
 | 		             'errormsg' => 'Invalid nodeid specified'); | 
 | 	} | 
 |  | 
 | 	if(! checkUserHasPriv("resourceGrant", $user['id'], $nodeid)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 61, | 
 | 		             'errormsg' => 'Unable to remove resource group privileges on this node'); | 
 | 	} | 
 |  | 
 | 	$resourcetypes = getTypes('resources'); | 
 | 	if(! in_array($type, $resourcetypes['resources'])) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 71, | 
 | 		             'errormsg' => 'Invalid resource type'); | 
 | 	} | 
 |  | 
 | 	$groupid = getResourceGroupID("$type/$name"); | 
 | 	if(is_null($groupid)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 74, | 
 | 		             'errormsg' => 'resource group does not exist'); | 
 | 	} | 
 |  | 
 | 	$changeperms = explode(':', $permissions); | 
 | 	$allperms = getResourcePrivs(); | 
 | 	$diff = array_diff($changeperms, $allperms); | 
 | 	if(count($diff)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 66, | 
 | 		             'errormsg' => 'Invalid or missing permissions list supplied'); | 
 | 	} | 
 |  | 
 | 	$nocheckperms = array('block', 'cascade', 'available'); | 
 | 	$checkperms = array_diff($changeperms, $nocheckperms); | 
 |  | 
 | 	$groupdata = getResourceGroups($type, $groupid); | 
 | 	if(count($checkperms) && | 
 | 	   ! array_key_exists($groupdata[$groupid]["ownerid"], $user["groups"])) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 79, | 
 | 		             'errormsg' => 'Unable to modify privilege set for resource group'); | 
 | 	} | 
 |  | 
 | 	$key = "$type/$name/$groupid"; | 
 | 	$cnp = getNodeCascadePrivileges($nodeid, "resources"); | 
 | 	$np = getNodePrivileges($nodeid, 'resources'); | 
 | 	if(isset($cnp['resources'][$key]) && ! isset($np['resources'][$key]['block'])) { | 
 | 		$intersect = array_intersect(array_keys($cnp['resources'][$key]), $changeperms); | 
 | 		if(count($intersect)) { | 
 | 			return array('status' => 'error', | 
 | 			             'errorcode' => 80, | 
 | 			             'errormsg' => 'Unable to modify privileges cascaded to this node'); | 
 | 		} | 
 | 	} | 
 |  | 
 | 	if($mode == 'remove') { | 
 | 		if(! isset($np['resources'][$key])) | 
 | 			return array('status' => 'success'); | 
 | 		$diff = array_diff(array_keys($np['resources'][$key]), $changeperms); | 
 | 		if(count($diff) == 1 && in_array("cascade", $diff)) | 
 | 			$changeperms[] = 'cascade'; | 
 | 	} | 
 |  | 
 | 	if($mode == 'add') | 
 | 		updateResourcePrivs("$groupid", $nodeid, $changeperms, array()); | 
 | 	elseif($mode == 'remove') | 
 | 		updateResourcePrivs("$groupid", $nodeid, array(), $changeperms); | 
 | 	return array('status' => 'success'); | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCgetUserGroups($groupType, $affiliationid) | 
 | /// | 
 | /// \param $groupType - (optional, default=0) specify 0 for all groups, 1 for | 
 | /// only custom groups, 2 for only courseroll groups | 
 | /// \param $affiliationid - (optional, default=0) specifiy an affiliationid to | 
 | /// limit returned groups to only those matching the affiliation; pass 0 for | 
 | /// all affiliations | 
 | /// | 
 | /// \return an array with two indices, one named 'status' which will have a | 
 | /// value of 'success', the other named 'groups' which will be an array of | 
 | /// arrays, each one having the following keys:\n | 
 | /// \li id\n | 
 | /// \li name\n | 
 | /// \li groupaffiliation\n | 
 | /// \li groupaffiliationid\n | 
 | /// \li ownerid\n | 
 | /// \li owner\n | 
 | /// \li affiliation\n | 
 | /// \li editgroupid\n | 
 | /// \li editgroup\n | 
 | /// \li editgroupaffiliationid\n | 
 | /// \li editgroupaffiliation\n | 
 | /// \li custom\n | 
 | /// \li courseroll\n | 
 | /// \li initialmaxtime\n | 
 | /// \li maxextendtime\n | 
 | /// \li overlapResCount | 
 | /// | 
 | /// \brief builds a list of user groups | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCgetUserGroups($groupType=0, $affiliationid=0) { | 
 | 	global $user; | 
 | 	$groupType = processInputData($groupType, ARG_NUMERIC, 0, 0); | 
 | 	$affiliationid = processInputData($affiliationid, ARG_NUMERIC, 0, 0); | 
 |  | 
 | 	$groups = getUserGroups($groupType, $affiliationid); | 
 |  | 
 | 	// Filter out any groups to which the user does not have access. | 
 | 	$usergroups = array(); | 
 | 	foreach($groups as $id => $group) { | 
 | 		if($group['ownerid'] == $user['id'] ||  | 
 | 		   (array_key_exists("editgroupid", $group) && | 
 | 		   array_key_exists($group['editgroupid'], $user["groups"])) ||  | 
 | 		   (array_key_exists($id, $user["groups"]))) { | 
 | 			array_push($usergroups, $group); | 
 | 		} | 
 | 	} | 
 | 	return array("status" => "success", | 
 | 	             "groups" => $usergroups); | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCgetUserGroupAttributes($name, $affiliation) | 
 | /// | 
 | /// \param $name - name of user group | 
 | /// \param $affiliation - affiliation of user group | 
 | /// | 
 | /// \return an array with at least one index named 'status' which will have | 
 | /// one of these values:\n | 
 | /// \b error - error occurred; there will be 2 additional elements in the array: | 
 | /// \li \b errorcode - error number | 
 | /// \li \b errormsg - error string | 
 | /// | 
 | /// \b success - there will be six additional elements in this case: | 
 | /// \li \b owner - user that will be the owner of the group in | 
 | ///                username\@affiliation form | 
 | /// \li \b managingGroup - user group that can manage membership of this one in | 
 | ///                        groupname\@affiliation form | 
 | /// \li \b initialMaxTime - (minutes) max initial time users in this group can | 
 | ///                         select for length of reservations | 
 | /// \li \b totalMaxTime - (minutes) total length users in the group can have for | 
 | ///                       a reservation (including all extensions) | 
 | /// \li \b maxExtendTime - (minutes) max length of time users can request as an | 
 | ///                        extension to a reservation at a time | 
 | /// \li \b overlapResCount - maximum allowed number of overlapping reservations | 
 | /// allowed for users in this group | 
 | /// | 
 | /// \brief gets information about a user group | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCgetUserGroupAttributes($name, $affiliation) { | 
 | 	global $user; | 
 | 	if(! in_array('groupAdmin', $user['privileges'])) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 16, | 
 | 		             'errormsg' => 'access denied for managing groups'); | 
 | 	} | 
 | 	$validate = array('name' => $name, | 
 | 	                  'affiliation' => $affiliation); | 
 | 	$rc = validateAPIgroupInput($validate, 1); | 
 | 	if($rc['status'] == 'error') | 
 | 		return $rc; | 
 | 	$query = "SELECT ug.id, " | 
 | 	       .        "ug.ownerid, " | 
 | 	       .        "CONCAT(u.unityid, '@', a.name) AS owner, " | 
 | 	       .        "ug.editusergroupid AS editgroupid, " | 
 | 	       .        "eug.name AS editgroup, " | 
 | 	       .        "eug.affiliationid AS editgroupaffiliationid, " | 
 | 	       .        "euga.name AS editgroupaffiliation, " | 
 | 	       .        "ug.initialmaxtime, " | 
 | 	       .        "ug.totalmaxtime, " | 
 | 	       .        "ug.maxextendtime, " | 
 | 	       .        "ug.overlapResCount " | 
 | 	       . "FROM usergroup ug " | 
 | 	       . "LEFT JOIN user u ON (ug.ownerid = u.id) " | 
 | 	       . "LEFT JOIN affiliation a ON (u.affiliationid = a.id) " | 
 | 	       . "LEFT JOIN usergroup eug ON (ug.editusergroupid = eug.id) " | 
 | 	       . "LEFT JOIN affiliation euga ON (eug.affiliationid = euga.id) " | 
 | 	       . "WHERE ug.id = {$rc['id']}"; | 
 | 	$qh = doQuery($query, 101); | 
 | 	if(! $row = mysql_fetch_assoc($qh)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 18, | 
 | 		             'errormsg' => 'user group with submitted name and affiliation does not exist'); | 
 | 	} | 
 | 	// if not owner and not member of managing group, no access | 
 | 	if($user['id'] != $row['ownerid'] &&  | 
 | 	   ! array_key_exists($row['editgroupid'], $user['groups'])) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 69, | 
 | 		             'errormsg' => 'access denied to user group with submitted name and affiliation'); | 
 | 	} | 
 | 	$ret = array('status' => 'success', | 
 | 	             'owner' => $row['owner'], | 
 | 	             'managingGroup' => "{$row['editgroup']}@{$row['editgroupaffiliation']}", | 
 | 	             'initialMaxTime' => $row['initialmaxtime'], | 
 | 	             'totalMaxTime' => $row['totalmaxtime'], | 
 | 	             'maxExtendTime' => $row['maxextendtime'], | 
 | 	             'overlapResCount' => $row['overlapResCount']); | 
 | 	return $ret; | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCaddUserGroup($name, $affiliation, $owner, $managingGroup, | 
 | ///                        $initialMaxTime, $totalMaxTime, $maxExtendTime, | 
 | ///                        $custom) | 
 | /// | 
 | /// \param $name - name of user group | 
 | /// \param $affiliation - affiliation of user group | 
 | /// \param $owner - user that will be the owner of the group in | 
 | ///                 username\@affiliation form | 
 | /// \param $managingGroup - user group that can manage membership of this one | 
 | /// \param $initialMaxTime - (minutes) max initial time users in this group can | 
 | ///                          select for length of reservations | 
 | /// \param $totalMaxTime - (minutes) total length users in the group can have | 
 | ///                        for a reservation (including all extensions) | 
 | /// \param $maxExtendTime - (minutes) max length of time users can request as an | 
 | ///                         extension to a reservation at a time | 
 | /// \param $custom - (optional, default=1) set custom flag for user group; if | 
 | ///                set to 0, $owner and $managingGroup will be ignored and group | 
 | ///                membership will be managed via authentication protocol | 
 | /// | 
 | /// \return an array with at least one index named 'status' which will have | 
 | /// one of these values:\n | 
 | /// \b error - error occurred; there will be 2 additional elements in the array: | 
 | /// \li \b errorcode - error number\n | 
 | /// \li \b errormsg - error string | 
 | /// | 
 | /// \b success - user group was successfully created | 
 | /// | 
 | /// \brief creates a new user group with the specified parameters | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCaddUserGroup($name, $affiliation, $owner, $managingGroup, | 
 |                             $initialMaxTime, $totalMaxTime, $maxExtendTime, | 
 |                             $custom=1) { | 
 | 	global $user; | 
 | 	if(! in_array('groupAdmin', $user['privileges'])) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 16, | 
 | 		             'errormsg' => 'access denied for managing groups'); | 
 | 	} | 
 | 	$validate = array('name' => $name, | 
 | 	                  'affiliation' => $affiliation, | 
 | 	                  'owner' => $owner, | 
 | 	                  'managingGroup' => $managingGroup, | 
 | 	                  'initialMaxTime' => $initialMaxTime, | 
 | 	                  'totalMaxTime' => $totalMaxTime, | 
 | 	                  'maxExtendTime' => $maxExtendTime, | 
 | 	                  'custom' => $custom); | 
 | 	$rc = validateAPIgroupInput($validate, 0); | 
 | 	if($rc['status'] == 'error') | 
 | 		return $rc; | 
 | 	if($custom != 0 && $custom != 1) | 
 | 		$custom = 1; | 
 | 	if(! $custom) | 
 | 		$rc['managingGroupID'] = NULL; | 
 | 	$data = array('type' => 'user', | 
 | 	              'owner' => $owner, | 
 | 	              'name' => $name, | 
 | 	              'affiliationid' => $rc['affiliationid'], | 
 | 	              'editgroupid' => $rc['managingGroupID'], | 
 | 	              'initialmax' => $initialMaxTime, | 
 | 	              'totalmax' => $totalMaxTime, | 
 | 	              'maxextend' => $maxExtendTime, | 
 | 	              'overlap' => 0, | 
 | 	              'custom' => $custom); | 
 | 	if(! addGroup($data)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 26, | 
 | 		             'errormsg' => 'failure while adding group to database'); | 
 | 	} | 
 | 	return array('status' => 'success'); | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCeditUserGroup($name, $affiliation, $newName, $newAffiliation, | 
 | ///                         $newOwner, $newManagingGroup, $newInitialMaxTime, | 
 | ///                         $newTotalMaxTime, $newMaxExtendTime) | 
 | /// | 
 | /// \param $name - name of user group | 
 | /// \param $affiliation - affiliation of user group | 
 | /// \param $newName - new name for user group | 
 | /// \param $newAffiliation - new affiliation for user group | 
 | /// \param $newOwner - (optional, default='') user that will be the owner of | 
 | ///                    the group in username\@affiliation form | 
 | /// \param $newManagingGroup - (optional, default='') user group that can | 
 | ///                            manage membership of this one | 
 | /// \param $newInitialMaxTime - (optional, default='') (minutes) max initial | 
 | ///                             time users in this group can select for length | 
 | ///                             of reservations | 
 | /// \param $newTotalMaxTime - (optional, default='') (minutes) total length | 
 | ///                           users in the group can have for a reservation | 
 | ///                           (including all extensions) | 
 | /// \param $newMaxExtendTime - (optional, default='') (minutes) max length of | 
 | ///                            time users can request as an extension to a | 
 | ///                            reservation at a time | 
 | /// | 
 | /// \return an array with at least one index named 'status' which will have | 
 | /// one of these values:\n | 
 | /// \b error - error occurred; there will be 2 additional elements in the array: | 
 | /// \li \b errorcode - error number | 
 | /// \li \b errormsg - error string | 
 | /// | 
 | /// \b success - user group was successfully updated | 
 | /// | 
 | /// \brief modifies attributes of a user group\n | 
 | /// \b NOTE: an empty string may be passed for any of the new* fields to leave | 
 | /// that item unchanged | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCeditUserGroup($name, $affiliation, $newName, $newAffiliation, | 
 |                              $newOwner='', $newManagingGroup='', | 
 |                              $newInitialMaxTime='', $newTotalMaxTime='', | 
 |                              $newMaxExtendTime='') { | 
 | 	global $user, $mysql_link_vcl; | 
 | 	if(! in_array('groupAdmin', $user['privileges'])) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 16, | 
 | 		             'errormsg' => 'access denied for managing groups'); | 
 | 	} | 
 |  | 
 | 	$updates = array(); | 
 |  | 
 | 	# validate group exists and new values other than newName and newAffiliation | 
 | 	#   are valid | 
 | 	$validate = array('name' => $name, | 
 | 	                  'affiliation' => $affiliation); | 
 | 	if(get_magic_quotes_gpc()) | 
 | 		$newOwner = stripslashes($newOwner); | 
 | 	if(! empty($newOwner)) | 
 | 		$validate['owner'] = $newOwner; | 
 | 	if(! empty($newManagingGroup)) | 
 | 		$validate['managingGroup'] = $newManagingGroup; | 
 | 	if(! empty($newInitialMaxTime)) { | 
 | 		$validate['initialMaxTime'] = $newInitialMaxTime; | 
 | 		$updates[] = "initialmaxtime = $newInitialMaxTime"; | 
 | 	} | 
 | 	if(! empty($newTotalMaxTime)) { | 
 | 		$validate['totalMaxTime'] = $newTotalMaxTime; | 
 | 		$updates[] = "totalmaxtime = $newTotalMaxTime"; | 
 | 	} | 
 | 	if(! empty($newMaxExtendTime)) { | 
 | 		$validate['maxExtendTime'] = $newMaxExtendTime; | 
 | 		$updates[] = "maxextendtime = $newMaxExtendTime"; | 
 | 	} | 
 | 	$rc = validateAPIgroupInput($validate, 1); | 
 | 	if($rc['status'] == 'error') | 
 | 		return $rc; | 
 |  | 
 | 	# get info about group | 
 | 	$query = "SELECT ownerid, " | 
 | 	       .        "affiliationid, " | 
 | 	       .        "custom, " | 
 | 	       .        "courseroll " | 
 | 	       . "FROM usergroup " | 
 | 	       . "WHERE id = {$rc['id']}"; | 
 | 	$qh = doQuery($query, 101); | 
 | 	if(! $row = mysql_fetch_assoc($qh)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 18, | 
 | 		             'errormsg' => 'user group with submitted name and affiliation does not exist'); | 
 | 	} | 
 | 	// if custom and not owner or custom/courseroll and no federated user group access, no access to edit group | 
 | 	if(($row['custom'] == 1 && $user['id'] != $row['ownerid']) || | 
 | 	   (($row['custom'] == 0 || $row['courseroll'] == 1) && | 
 | 	   ! checkUserHasPerm('Manage Federated User Groups (global)') && | 
 | 	   (! checkUserHasPerm('Manage Federated User Groups (affiliation only)') || | 
 | 	   $row['affiliationid'] != $user['affiliationid']))) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 32, | 
 | 		             'errormsg' => 'access denied to modify attributes for user group with submitted name and affiliation'); | 
 | 	} | 
 |  | 
 | 	# validate that newName and newAffiliation are valid | 
 | 	if(($name != $newName || $affiliation != $newAffiliation) && | 
 | 	   (! empty($newName) || ! empty($newAffiliation))) { | 
 | 		$validate = array('name' => $name, | 
 | 		                  'affiliation' => $affiliation); | 
 | 		if(! empty($newName)) { | 
 | 			if(get_magic_quotes_gpc()) | 
 | 				$newName = stripslashes($newName); | 
 | 			$validate['name'] = $newName; | 
 | 			$tmp = mysql_real_escape_string($newName); | 
 | 			$updates[] = "name = '$tmp'"; | 
 | 		} | 
 | 		if(! empty($newAffiliation)) | 
 | 			$validate['affiliation'] = $newAffiliation; | 
 | 		$rc2 = validateAPIgroupInput($validate, 0); | 
 | 		if($rc2['status'] == 'error') { | 
 | 			if($rc2['errorcode'] == 27) { | 
 | 				$rc2['errorcode'] = 31; | 
 | 				$rc2['errormsg'] = 'existing user group with new form of name@affiliation'; | 
 | 			} | 
 | 			return $rc2; | 
 | 		} | 
 | 		if(! empty($newAffiliation)) | 
 | 			$updates[] = "affiliationid = {$rc2['affiliationid']}"; | 
 | 	} | 
 |  | 
 | 	if($row['custom']) { | 
 | 		if(! empty($newOwner)) { | 
 | 			$newownerid = getUserlistID(mysql_real_escape_string($newOwner)); | 
 | 			$updates[] = "ownerid = $newownerid"; | 
 | 		} | 
 | 		if(! empty($newManagingGroup)) | 
 | 			$updates[] = "editusergroupid = {$rc['managingGroupID']}"; | 
 | 	} | 
 | 	$sets = implode(',', $updates); | 
 | 	if(count($updates) == 0) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 33, | 
 | 		             'errormsg' => 'no new values submitted'); | 
 | 	} | 
 | 	$query = "UPDATE usergroup " | 
 | 	       . "SET $sets " | 
 | 	       . "WHERE id = {$rc['id']}"; | 
 | 	doQuery($query, 101); | 
 | 	return array('status' => 'success'); | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCremoveUserGroup($name, $affiliation) | 
 | /// | 
 | /// \param $name - name of user group | 
 | /// \param $affiliation - affiliation of user group | 
 | /// | 
 | /// \return an array with at least one index named 'status' which will have | 
 | /// one of these values:\n | 
 | /// \b error - error occurred; there will be 2 additional elements in the array: | 
 | /// \li \b errorcode - error number | 
 | /// \li \b errormsg - error string | 
 | /// | 
 | /// \b success - user group was successfully removed | 
 | /// | 
 | /// \brief removes a user group along with all of its privileges | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCremoveUserGroup($name, $affiliation) { | 
 | 	global $user, $mysql_link_vcl; | 
 | 	if(! in_array('groupAdmin', $user['privileges'])) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 16, | 
 | 		             'errormsg' => 'access denied for managing groups'); | 
 | 	} | 
 | 	$validate = array('name' => $name, | 
 | 	                  'affiliation' => $affiliation); | 
 | 	$rc = validateAPIgroupInput($validate, 1); | 
 | 	if($rc['status'] == 'error') | 
 | 		return $rc; | 
 | 	$query = "SELECT ownerid, " | 
 | 	       .        "affiliationid, " | 
 | 	       .        "custom, " | 
 | 	       .        "courseroll " | 
 | 	       . "FROM usergroup " | 
 | 	       . "WHERE id = {$rc['id']}"; | 
 | 	$qh = doQuery($query, 101); | 
 | 	if(! $row = mysql_fetch_assoc($qh)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 18, | 
 | 		             'errormsg' => 'user group with submitted name and affiliation does not exist'); | 
 | 	} | 
 |  | 
 | 	// if custom and not owner or custom/courseroll and no federated user group access, no access to delete group | 
 | 	if(($row['custom'] == 1 && $user['id'] != $row['ownerid']) || | 
 | 	   (($row['custom'] == 0 || $row['courseroll'] == 1) && | 
 | 	   ! checkUserHasPerm('Manage Federated User Groups (global)') && | 
 | 	   (! checkUserHasPerm('Manage Federated User Groups (affiliation only)') || | 
 | 	   $row['affiliationid'] != $user['affiliationid']))) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 29, | 
 | 		             'errormsg' => 'access denied to delete user group with submitted name and affiliation'); | 
 | 	} | 
 | 	if(checkForGroupUsage($rc['id'], 'user')) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 72, | 
 | 		             'errormsg' => 'group currently in use and cannot be removed'); | 
 | 	} | 
 | 	$query = "DELETE FROM usergroup " | 
 | 	       . "WHERE id = {$rc['id']}"; | 
 | 	doQuery($query, 101); | 
 | 	# validate something deleted | 
 | 	if(mysql_affected_rows($mysql_link_vcl) == 0) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 30, | 
 | 		             'errormsg' => 'failure while deleting group from database'); | 
 | 	} | 
 | 	return array('status' => 'success'); | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCdeleteUserGroup($name, $affiliation) | 
 | /// | 
 | /// \param $name - name of user group | 
 | /// \param $affiliation - affiliation of user group | 
 | /// | 
 | /// \return an array with at least one index named 'status' which will have | 
 | /// one of these values:\n | 
 | /// \b error - error occurred; there will be 2 additional elements in the array: | 
 | /// \li \b errorcode - error number | 
 | /// \li \b errormsg - error string | 
 | /// | 
 | /// \b success - user group was successfully removed | 
 | /// | 
 | /// \brief alias for XMLRPCremoveUserGroup | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCdeleteUserGroup($name, $affiliation) { | 
 | 	# This was the original function. All other functions use 'remove' rather | 
 | 	# than 'delete'. The function was renamed to XMLRPCremoveUserGroup. This was | 
 | 	# kept for compatibility reasons | 
 | 	return XMLRPCremoveUserGroup($name, $affiliation); | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCgetUserGroupMembers($name, $affiliation) | 
 | /// | 
 | /// \param $name - name of user group | 
 | /// \param $affiliation - affiliation of user group | 
 | /// | 
 | /// \return an array with at least one index named 'status' which will have | 
 | /// one of these values:\n | 
 | /// \b error - error occurred; there will be 2 additional elements in the array: | 
 | /// \li \b errorcode - error number | 
 | /// \li \b errormsg - error string | 
 | /// | 
 | /// \b success - there will be one additional element in this case: | 
 | /// \li \b members - array of members of the group in username\@affiliation form | 
 | /// | 
 | /// \brief gets members of a user group\n | 
 | /// \b NOTE: it is possible to have a group with no members in which case | 
 | /// success will be returned with an empty array for members | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCgetUserGroupMembers($name, $affiliation) { | 
 | 	global $user; | 
 | 	if(! in_array('groupAdmin', $user['privileges'])) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 16, | 
 | 		             'errormsg' => 'access denied for managing groups'); | 
 | 	} | 
 | 	$validate = array('name' => $name, | 
 | 	                  'affiliation' => $affiliation); | 
 | 	$rc = validateAPIgroupInput($validate, 1); | 
 | 	if($rc['status'] == 'error') | 
 | 		return $rc; | 
 | 	$query = "SELECT ownerid, " | 
 | 	       .        "editusergroupid AS editgroupid, " | 
 | 	       .        "affiliationid, " | 
 | 	       .        "custom, " | 
 | 	       .        "courseroll " | 
 | 	       . "FROM usergroup " | 
 | 	       . "WHERE id = {$rc['id']}"; | 
 | 	$qh = doQuery($query, 101); | 
 | 	if(! $row = mysql_fetch_assoc($qh)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 18, | 
 | 		             'errormsg' => 'user group with submitted name and affiliation does not exist'); | 
 | 	} | 
 | 	// if custom and not owner and not member of managing group or  | 
 | 	//    custom/courseroll and no federated user group access, no access to delete group | 
 | 	if(($row['custom'] == 1 && $user['id'] != $row['ownerid'] && | 
 | 	   ! array_key_exists($row['editgroupid'], $user['groups'])) || | 
 | 	   (($row['custom'] == 0 || $row['courseroll'] == 1) && | 
 | 	   ! checkUserHasPerm('Manage Federated User Groups (global)') && | 
 | 	   (! checkUserHasPerm('Manage Federated User Groups (affiliation only)') || | 
 | 	   $row['affiliationid'] != $user['affiliationid']))) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 28, | 
 | 		             'errormsg' => 'access denied to user group with submitted name and affiliation'); | 
 | 	} | 
 | 	$query = "SELECT CONCAT(u.unityid, '@', a.name) AS member " | 
 | 	       . "FROM usergroupmembers ugm, " | 
 | 	       .      "user u, " | 
 | 	       .      "affiliation a " | 
 | 	       . "WHERE ugm.usergroupid = {$rc['id']} AND " | 
 | 	       .       "ugm.userid = u.id AND " | 
 | 	       .       "u.affiliationid = a.id"; | 
 | 	$qh = doQuery($query, 101); | 
 | 	$members = array(); | 
 | 	while($row = mysql_fetch_assoc($qh)) | 
 | 		$members[] = $row['member']; | 
 | 	return array('status' => 'success', | 
 | 	             'members' => $members); | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCaddUsersToGroup($name, $affiliation, $users) | 
 | /// | 
 | /// \param $name - name of user group | 
 | /// \param $affiliation - affiliation of user group | 
 | /// \param $users - array of users in username\@affiliation form to be added to | 
 | ///                 the group | 
 | /// | 
 | /// \return an array with at least one index named 'status' which will have | 
 | /// one of these values:\n | 
 | /// \b error - error occurred; there will be 2 additional elements in the array: | 
 | /// \li \b errorcode - error number | 
 | /// \li \b errormsg - error string | 
 | /// | 
 | /// \b success - users successfully added to the group\n | 
 | /// \b warning - there was a non-fatal issue that occurred while processing | 
 | /// the call; there will be three additional elements in this case: | 
 | /// \li \b warningcode - warning number | 
 | /// \li \b warningmsg - warning string | 
 | /// \li \b failedusers - array of users in username\@affiliation form that could | 
 | ///                      not be added | 
 | /// | 
 | /// \brief adds users to a group | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCaddUsersToGroup($name, $affiliation, $users) { | 
 | 	global $user; | 
 | 	if(! in_array('groupAdmin', $user['privileges'])) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 16, | 
 | 		             'errormsg' => 'access denied for managing groups'); | 
 | 	} | 
 | 	$validate = array('name' => $name, | 
 | 	                  'affiliation' => $affiliation); | 
 | 	$rc = validateAPIgroupInput($validate, 1); | 
 | 	if($rc['status'] == 'error') | 
 | 		return $rc; | 
 | 	$query = "SELECT ownerid, " | 
 | 	       .        "editusergroupid AS editgroupid " | 
 | 	       . "FROM usergroup " | 
 | 	       . "WHERE id = {$rc['id']}"; | 
 | 	$qh = doQuery($query, 101); | 
 | 	if(! $row = mysql_fetch_assoc($qh)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 18, | 
 | 		             'errormsg' => 'user group with submitted name and affiliation does not exist'); | 
 | 	} | 
 | 	// if not owner and not member of managing group, no access | 
 | 	if($user['id'] != $row['ownerid'] &&  | 
 | 	   ! array_key_exists($row['editgroupid'], $user['groups'])) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 28, | 
 | 		             'errormsg' => 'access denied to user group with submitted name and affiliation'); | 
 | 	} | 
 | 	$fails = array(); | 
 | 	foreach($users as $_user) { | 
 | 		if(empty($_user)) | 
 | 			continue; | 
 | 		if(get_magic_quotes_gpc()) | 
 | 			$_user = stripslashes($_user); | 
 | 		$esc_user = mysql_real_escape_string($_user); | 
 | 		if(validateUserid($_user) == 1) | 
 | 			addUserGroupMember($esc_user, $rc['id']); | 
 | 		else | 
 | 			$fails[] = $_user; | 
 | 	} | 
 | 	if(count($fails)) { | 
 | 		$cnt = 'some'; | 
 | 		$code = 34; | 
 | 		if(count($fails) == count($users)) { | 
 | 			$cnt = 'all submitted'; | 
 | 			$code = 35; | 
 | 		} | 
 | 		return array('status' => 'warning', | 
 | 		             'failedusers' => $fails, | 
 | 		             'warningcode' => $code, | 
 | 		             'warningmsg' => "failed to add $cnt users to user group"); | 
 | 	} | 
 | 	return array('status' => 'success'); | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCremoveUsersFromGroup($name, $affiliation, $users) | 
 | /// | 
 | /// \param $name - name of user group | 
 | /// \param $affiliation - affiliation of user group | 
 | /// \param $users - array of users in username\@affiliation form to be removed | 
 | ///                 from the group | 
 | /// | 
 | /// \return an array with at least one index named 'status' which will have | 
 | /// one of these values:\n | 
 | /// \b error - error occurred; there will be 2 additional elements in the array: | 
 | /// \li \b errorcode - error number | 
 | /// \li \b errormsg - error string | 
 | /// | 
 | /// \b success - users successfully removed from the group\n | 
 | /// \b warning - there was a non-fatal issue that occurred while processing | 
 | /// the call; there will be three additional elements in this case: | 
 | /// \li \b warningcode - warning number | 
 | /// \li \b warningmsg - warning string | 
 | /// \li \b failedusers - array of users in username\@affiliation form that could | 
 | ///                      not be removed | 
 | /// | 
 | /// \brief removes users from a group | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCremoveUsersFromGroup($name, $affiliation, $users) { | 
 | 	global $user, $findAffilFuncs; | 
 | 	if(! in_array('groupAdmin', $user['privileges'])) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 16, | 
 | 		             'errormsg' => 'access denied for managing groups'); | 
 | 	} | 
 | 	$validate = array('name' => $name, | 
 | 	                  'affiliation' => $affiliation); | 
 | 	$rc = validateAPIgroupInput($validate, 1); | 
 | 	if($rc['status'] == 'error') | 
 | 		return $rc; | 
 | 	$query = "SELECT ownerid, " | 
 | 	       .        "editusergroupid AS editgroupid " | 
 | 	       . "FROM usergroup " | 
 | 	       . "WHERE id = {$rc['id']}"; | 
 | 	$qh = doQuery($query, 101); | 
 | 	if(! $row = mysql_fetch_assoc($qh)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 18, | 
 | 		             'errormsg' => 'user group with submitted name and affiliation does not exist'); | 
 | 	} | 
 | 	// if not owner and not member of managing group, no access | 
 | 	if($user['id'] != $row['ownerid'] &&  | 
 | 	   ! array_key_exists($row['editgroupid'], $user['groups'])) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 28, | 
 | 		             'errormsg' => 'access denied to user group with submitted name and affiliation'); | 
 | 	} | 
 | 	$fails = array(); | 
 | 	foreach($users as $_user) { | 
 | 		if(empty($_user)) | 
 | 			continue; | 
 | 		if(get_magic_quotes_gpc()) | 
 | 			$_user = stripslashes($_user); | 
 | 		$esc_user = mysql_real_escape_string($_user); | 
 | 		# check that affiliation of user can be determined because getUserlistID | 
 | 		#   will abort if it cannot find it | 
 | 		$affilok = 0; | 
 | 		foreach($findAffilFuncs as $func) { | 
 | 			if($func($_user, $dump)) | 
 | 				$affilok = 1; | 
 | 		} | 
 | 		if(! $affilok) { | 
 | 			$fails[] = $_user; | 
 | 			continue; | 
 | 		} | 
 | 		$userid = getUserlistID($esc_user, 1); | 
 | 		if(is_null($userid)) | 
 | 			$fails[] = $_user; | 
 | 		else | 
 | 			deleteUserGroupMember($userid, $rc['id']); | 
 | 	} | 
 | 	if(count($fails)) { | 
 | 		$cnt = 'some'; | 
 | 		$code = 36; | 
 | 		if(count($fails) == count($users)) { | 
 | 			$cnt = 'any'; | 
 | 			$code = 37; | 
 | 		} | 
 | 		return array('status' => 'warning', | 
 | 		             'failedusers' => $fails, | 
 | 		             'warningcode' => $code, | 
 | 		             'warningmsg' => "failed to remove $cnt users from user group"); | 
 | 	} | 
 | 	return array('status' => 'success'); | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCgetResourceGroups($type) | 
 | /// | 
 | /// \param $type - the resource group type | 
 | /// | 
 | /// \return an array with at least one index named 'status' which will have | 
 | /// one of these values\n | 
 | /// \b error - error occurred; there will be 2 additional elements in the array: | 
 | /// \li \b errorcode - error number\n | 
 | /// \li \b errormsg - error string\n | 
 | /// | 
 | /// \b success - a 'groups' element will contain an array of groups of the given | 
 | /// type\n | 
 | /// | 
 | /// \brief get a list of resource groups of a particular type | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCgetResourceGroups($type) { | 
 | 	global $user; | 
 | 	$resources = getUserResources(array("groupAdmin"), array("manageGroup"), 1); | 
 | 	if(array_key_exists($type, $resources)) { | 
 | 		return array('status' => 'success', | 
 | 		             'groups' => $resources[$type]); | 
 | 	} | 
 | 	else { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 73, | 
 | 		             'errormsg' => 'invalid resource group type'); | 
 | 	} | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCaddResourceGroup($name, $managingGroup, $type) | 
 | /// | 
 | /// \param $name - the name of the resource group | 
 | /// \param $managingGroup - the name of the managing group | 
 | /// \param $type - the type of resource group | 
 | /// | 
 | /// \return an array with at least one index named 'status' which will have | 
 | /// one of these values\n | 
 | /// \b error - error occurred; there will be 2 additional elements in the array: | 
 | /// \li \b errorcode - error number\n | 
 | /// \li \b errormsg - error string\n | 
 | /// | 
 | /// \b success - the resource group was added | 
 | /// | 
 | /// \brief add a resource group | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCaddResourceGroup($name, $managingGroup, $type) { | 
 | 	global $user; | 
 | 	if(! in_array("groupAdmin", $user['privileges'])) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 16, | 
 | 		             'errormsg' => 'access denied for managing groups'); | 
 | 	} | 
 |  | 
 | 	$validate = array('managingGroup' => $managingGroup); | 
 |  | 
 | 	$rc = validateAPIgroupInput($validate, 0); | 
 | 	if($rc['status'] == 'error') | 
 | 		return $rc; | 
 |  | 
 | 	if($typeid = getResourceTypeID($type)) { | 
 | 		if(checkForGroupName($name, 'resource', '', $typeid)) { | 
 | 			return array('status' => 'error', | 
 | 			             'errorcode' => 76, | 
 | 			             'errormsg' => 'resource group already exists'); | 
 | 		} | 
 | 		if(get_magic_quotes_gpc()) | 
 | 			$name = stripslashes($name); | 
 | 		if(! preg_match('/^[-a-zA-Z0-9_\. ]{3,30}$/', $name)) { | 
 | 			return array('status' => 'error', | 
 | 			             'errorcode' => 87, | 
 | 			             'errormsg' => 'Name must be between 3 and 30 characters and can only contain letters, numbers, spaces, and these characters: - . _'); | 
 | 		} | 
 | 		$name = mysql_real_escape_string($name); | 
 | 		$data = array('type' => 'resource', | 
 | 		              'ownergroup' => $rc['managingGroupID'], | 
 | 		              'resourcetypeid' => $typeid, | 
 | 		              'name' => $name); | 
 | 		if(! addGroup($data)) { | 
 | 			return array('status' => 'error', | 
 | 			             'errorcode' => 26, | 
 | 			             'errormsg' => 'failure while adding group to database'); | 
 | 		} | 
 | 	} | 
 | 	else { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 68, | 
 | 		             'errormsg' => 'invalid resource type'); | 
 | 	} | 
 | 	return array('status' => 'success'); | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCremoveResourceGroup($name, $type) | 
 | /// | 
 | /// \param $name - the name of the resource group | 
 | /// \param $type - the resource group type | 
 | /// | 
 | /// \return an array with at least one index named 'status' which will have | 
 | /// one of these values\n | 
 | /// \b error - error occurred; there will be 2 additional elements in the array: | 
 | /// \li \b errorcode - error number\n | 
 | /// \li \b errormsg - error string\n | 
 | /// | 
 | /// \b success - the resource group was removed\n | 
 | /// | 
 | /// \brief remove a resource group | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCremoveResourceGroup($name, $type) { | 
 | 	global $user; | 
 | 	if(! in_array("groupAdmin", $user['privileges'])) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 16, | 
 | 		             'errormsg' => 'access denied for managing groups'); | 
 | 	} | 
 |  | 
 | 	if($groupid = getResourceGroupID("$type/$name")) { | 
 | 		$userresources = getUserResources(array("groupAdmin"), | 
 | 		                                  array("manageGroup"), 1); | 
 | 		if(array_key_exists($type, $userresources)) { | 
 | 			if(array_key_exists($groupid, $userresources[$type])) { | 
 | 				if(checkForGroupUsage($groupid, 'resource')) { | 
 | 					return array('status' => 'error', | 
 | 					             'errorcode' => 72, | 
 | 					             'errormsg' => 'group currently in use and cannot be removed'); | 
 | 				} | 
 | 				$query = "DELETE FROM resourcegroup " | 
 | 				       . "WHERE id = $groupid"; | 
 | 				doQuery($query, 315); | 
 | 				return array('status' => 'success'); | 
 | 			} | 
 | 			else | 
 | 				return array('status' => 'error', | 
 | 				             'errorcode' => 75, | 
 | 				             'errormsg' => 'access denied to specified resource group'); | 
 | 		} | 
 | 	} | 
 | 	return array('status' => 'error', | 
 | 	             'errorcode' => 83, | 
 | 	             'errormsg' => 'invalid resource group name'); | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCblockAllocation($imageid, $start, $end, $numMachines, | 
 | ///                           $usergroupid, $ignoreprivileges) | 
 | /// | 
 | /// \param $imageid - id of the image to be used | 
 | /// \param $start - mysql datetime for the start time (i.e. machines should be | 
 | /// prep'd and ready by this time) | 
 | /// \param $end - mysql datetime for the end time | 
 | /// \param $numMachines - number of computers to allocate | 
 | /// \param $usergroupid - id of user group for checking user access to machines | 
 | /// \param $ignoreprivileges  - (optional, default=0) 0 (false) or 1 (true) - set | 
 | /// to 1 to select computers from any that are mapped to be able to run the | 
 | /// image; set to 0 to only select computers from ones that are both mapped and | 
 | /// that users in the usergroup assigned to this block allocation have been | 
 | /// granted access to through the privilege tree | 
 | /// | 
 | /// \return an array with blockTimesid as an index with the value of the newly | 
 | /// created block time and at least one other index named 'status' which will | 
 | /// have one of these values:\n | 
 | /// \b error - error occurred; there will be 2 additional elements in the | 
 | /// array:\n | 
 | /// \li \b errorcode - error number\n | 
 | /// \li \b errormsg - error string\n | 
 | /// | 
 | /// \b success - blockTimesid was processed; there will be two additional | 
 | /// elements in this case:\n | 
 | /// \li \b allocated - total number of desired allocations that have been | 
 | /// processed\n | 
 | /// \li \b unallocated - total number of desired allocations that have not been | 
 | /// processed\n | 
 | /// | 
 | /// \b warning - there was a non-fatal issue that occurred while processing | 
 | /// the call; there will be four additional elements in this case:\n | 
 | /// \li \b warningcode - warning number\n | 
 | /// \li \b warningmsg - warning string\n | 
 | /// \li \b allocated - total number of desired allocations that have been | 
 | /// processed\n | 
 | /// \li \b unallocated - total number of desired allocations that have not been | 
 | /// processed\n\n | 
 | /// | 
 | /// \b NOTE: status may be warning, but allocated may be 0 indicating there | 
 | /// were no errors that occurred, but there simply were not any machines | 
 | /// available | 
 | /// | 
 | /// \brief creates and processes a block allocation according to the passed | 
 | /// in criteria | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCblockAllocation($imageid, $start, $end, $numMachines, | 
 |                                $usergroupid, $ignoreprivileges=0) { | 
 | 	global $user, $xmlrpcBlockAPIUsers; | 
 | 	if(! in_array($user['id'], $xmlrpcBlockAPIUsers)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 34, | 
 | 		             'errormsg' => 'access denied for managing block allocations'); | 
 | 	} | 
 |  | 
 | 	# valid $imageid | 
 | 	$resources = getUserResources(array("imageAdmin", "imageCheckOut")); | 
 | 	$resources["image"] = removeNoCheckout($resources["image"]); | 
 | 	if(! array_key_exists($imageid, $resources['image'])) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 3, | 
 | 		             'errormsg' => "access denied to $imageid"); | 
 | 	} | 
 |  | 
 | 	# validate $start and $end | 
 | 	$dtreg = '([0-9]{4})-([0-9]{2})-([0-9]{2}) ([0-9]{2}):([0-9]{2}):([0-9]{2})'; | 
 | 	$startts = datetimeToUnix($start); | 
 | 	$endts = datetimeToUnix($end); | 
 | 	$maxend = datetimeToUnix("2038-01-01 00:00:00"); | 
 | 	if(! preg_match("/^$dtreg$/", $start) || $startts < 0 || | 
 | 	   $startts > $maxend) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 4, | 
 | 		             'errormsg' => "received invalid input for start"); | 
 | 	} | 
 | 	if(! preg_match("/^$dtreg$/", $end) || $endts < 0 || | 
 | 	   $endts > $maxend) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 36, | 
 | 		             'errormsg' => "received invalid input for end"); | 
 | 	} | 
 |  | 
 | 	# validate $numMachines | 
 | 	if(! is_numeric($numMachines) || $numMachines < MIN_BLOCK_MACHINES || | 
 | 	   $numMachines > MAX_BLOCK_MACHINES) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 64, | 
 | 		             'errormsg' => 'The submitted number of seats must be between ' . MIN_BLOCK_MACHINES . ' and ' . MAX_BLOCK_MACHINES . '.'); | 
 | 	} | 
 |  | 
 | 	# validate $usergroupid | 
 | 	$groups = getUserGroups(); | 
 | 	if(! array_key_exists($usergroupid, $groups)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 67, | 
 | 		             'errormsg' => 'Submitted user group does not exist'); | 
 | 	} | 
 |  | 
 | 	# validate ignoreprivileges | 
 | 	if(! is_numeric($ignoreprivileges) || | 
 | 	   $ignoreprivileges < 0 || | 
 | 		$ignoreprivileges > 1) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 86, | 
 | 		             'errormsg' => 'ignoreprivileges must be 0 or 1'); | 
 | 	} | 
 |  | 
 | 	$ownerid = getUserlistID('vclreload@Local'); | 
 | 	$name = "API:$start"; | 
 | 	$managementnodes = getManagementNodes('future'); | 
 | 	if(empty($managementnodes)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 12, | 
 | 		             'errormsg' => 'could not allocate a management node to handle block allocation'); | 
 | 	} | 
 | 	$mnid = array_rand($managementnodes); | 
 | 	$query = "INSERT INTO blockRequest " | 
 | 	       .        "(name, " | 
 | 	       .        "imageid, " | 
 | 	       .        "numMachines, " | 
 | 	       .        "groupid, " | 
 | 	       .        "repeating, " | 
 | 	       .        "ownerid, " | 
 | 	       .        "managementnodeid, " | 
 | 	       .        "expireTime, " | 
 | 	       .        "status) " | 
 | 	       . "VALUES " | 
 | 	       .        "('$name', " | 
 | 	       .        "$imageid, " | 
 | 	       .        "$numMachines, " | 
 | 	       .        "$usergroupid, " | 
 | 	       .        "'list', " | 
 | 	       .        "$ownerid, " | 
 | 	       .        "$mnid, " | 
 | 	       .        "'$end', " | 
 | 	       .        "'accepted')"; | 
 | 	doQuery($query, 101); | 
 | 	$brid = dbLastInsertID(); | 
 | 	$query = "INSERT INTO blockTimes " | 
 | 	       .        "(blockRequestid, " | 
 | 	       .        "start, " | 
 | 	       .        "end) " | 
 | 	       . "VALUES " | 
 | 	       .        "($brid, " | 
 | 	       .        "'$start', " | 
 | 	       .        "'$end')"; | 
 | 	doQuery($query, 101); | 
 | 	$btid = dbLastInsertID(); | 
 | 	$query = "INSERT INTO blockWebDate " | 
 | 	       .        "(blockRequestid, " | 
 | 	       .        "start, " | 
 | 	       .        "end, " | 
 | 	       .        "days) " | 
 | 	       . "VALUES " | 
 | 	       .        "($brid, " | 
 | 	       .        "'$start', " | 
 | 	       .        "'$end', " | 
 | 	       .        "0)"; | 
 | 	doQuery($query); | 
 | 	$sh = date('g', $startts); | 
 | 	$smi = date('i', $startts); | 
 | 	$sme = date('a', $startts); | 
 | 	$eh = date('g', $startts); | 
 | 	$emi = date('i', $startts); | 
 | 	$eme = date('a', $startts); | 
 | 	$query = "INSERT INTO blockWebTime " | 
 | 	       .        "(blockRequestid, " | 
 | 	       .        "starthour, " | 
 | 	       .        "startminute, " | 
 | 	       .        "startmeridian, " | 
 | 	       .        "endhour, " | 
 | 	       .        "endminute, " | 
 | 	       .        "endmeridian, " | 
 | 	       .        "`order`) " | 
 | 	       . "VALUES " | 
 | 	       .        "($brid, " | 
 | 	       .        "$sh," | 
 | 	       .        "$smi," | 
 | 	       .        "'$sme'," | 
 | 	       .        "$eh," | 
 | 	       .        "$emi," | 
 | 	       .        "'$eme'," | 
 | 	       .        "0)"; | 
 | 	doQuery($query); | 
 | 	$return = XMLRPCprocessBlockTime($btid, $ignoreprivileges); | 
 | 	$return['blockTimesid'] = $btid; | 
 | 	return $return; | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCprocessBlockTime($blockTimesid, $ignoreprivileges) | 
 | /// | 
 | /// \param $blockTimesid - id from the blockTimes table | 
 | /// \param $ignoreprivileges - (optional, default=0) 0 (false) or 1 (true) - set | 
 | /// to 1 to select computers from any that are mapped to be able to run the | 
 | /// image; set to 0 to only select computers from ones that are both mapped and | 
 | /// that users in the usergroup assigned to this block allocation have been | 
 | /// granted access to through the privilege tree | 
 | /// | 
 | /// \return an array with at least one index named 'status' which will have | 
 | /// one of these values:\n | 
 | /// \b error - error occurred; there will be 2 additional elements in the array: | 
 | /// \li \b errorcode - error number | 
 | /// \li \b errormsg - error string | 
 | /// | 
 | /// \b completed - blockTimesid was previously successfully processed\n | 
 | /// \b success - blockTimesid was processed; there will be two additional | 
 | /// elements in this case:\n | 
 | /// \li \b allocated - total number of desired allocations that have been | 
 | /// processed\n | 
 | /// \li \b unallocated - total number of desired allocations that have not been | 
 | /// processed\n | 
 | /// | 
 | /// \b warning - there was a non-fatal issue that occurred while processing | 
 | /// the call; there will be four additional elements in this case:\n | 
 | /// \li \b warningcode - warning number\n | 
 | /// \li \b warningmsg - warning string\n | 
 | /// \li \b allocated - total number of desired allocations that have been | 
 | /// processed\n | 
 | /// \li \b unallocated - total number of desired allocations that have not been | 
 | /// processed\n\n | 
 | /// | 
 | /// \b NOTE: status may be warning, but allocated may be 0 indicating there | 
 | /// were no errors that occurred, but there simply were not any machines | 
 | /// available | 
 | /// | 
 | /// \brief processes a block allocation for the blockTimes entry associated | 
 | /// with blockTimesid | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCprocessBlockTime($blockTimesid, $ignoreprivileges=0) { | 
 | 	global $requestInfo, $user, $xmlrpcBlockAPIUsers; | 
 | 	if(! in_array($user['id'], $xmlrpcBlockAPIUsers)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 34, | 
 | 		             'errormsg' => 'access denied for managing block allocations'); | 
 | 	} | 
 |  | 
 | 	# validate $blockTimesid | 
 | 	if(! is_numeric($blockTimesid)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 77, | 
 | 		             'errormsg' => 'Invalid blockTimesid specified'); | 
 | 	} | 
 |  | 
 | 	# validate ignoreprivileges | 
 | 	if(! is_numeric($ignoreprivileges) || | 
 | 	   $ignoreprivileges < 0 || | 
 | 		$ignoreprivileges > 1) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 86, | 
 | 		             'errormsg' => 'ignoreprivileges must be 0 or 1'); | 
 | 	} | 
 |  | 
 | 	$return = array('status' => 'success'); | 
 | 	$query = "SELECT bt.start, " | 
 | 	       .        "bt.end, " | 
 | 	       .        "br.imageid, " | 
 | 	       .        "br.numMachines, " | 
 | 	       .        "br.groupid, " | 
 | 	       .        "br.expireTime " | 
 | 	       . "FROM blockRequest br, " | 
 | 	       .      "blockTimes bt " | 
 | 	       . "WHERE bt.blockRequestid = br.id AND " | 
 | 	       .       "bt.id = $blockTimesid"; | 
 | 	$qh = doQuery($query, 101); | 
 | 	if(! $rqdata = mysql_fetch_assoc($qh)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 8, | 
 | 		             'errormsg' => 'unknown blockTimesid'); | 
 | 	} | 
 | 	if(datetimeToUnix($rqdata['expireTime']) < time()) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 9, | 
 | 		             'errormsg' => 'expired block allocation'); | 
 | 	} | 
 |  | 
 | 	$images = getImages(0, $rqdata['imageid']); | 
 | 	if(empty($images)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 10, | 
 | 		             'errormsg' => 'invalid image associated with block allocation'); | 
 | 	} | 
 |  | 
 | 	$unixstart = datetimeToUnix($rqdata['start']); | 
 | 	$unixend = datetimeToUnix($rqdata['end']); | 
 | 	$revisionid = getProductionRevisionid($rqdata['imageid']); | 
 | 	$imgLoadTime = getImageLoadEstimate($rqdata['imageid']); | 
 | 	if($imgLoadTime == 0) | 
 | 		$imgLoadTime = $images[$rqdata['imageid']]['reloadtime'] * 60; | 
 | 	$vclreloadid = getUserlistID('vclreload@Local'); | 
 | 	$groupmembers = getUserGroupMembers($rqdata['groupid']); | 
 | 	$userids = array_keys($groupmembers); | 
 |  | 
 | 	# add any computers from future reservations users in the group made | 
 | 	if(! empty($groupmembers)) { | 
 | 		## find reservations by users | 
 | 		$allids = implode(',', $userids); | 
 | 		$query = "SELECT rq.id AS reqid, " | 
 | 		       .        "UNIX_TIMESTAMP(rq.start) AS start, " | 
 | 		       .        "rq.userid " | 
 | 		       . "FROM request rq, " | 
 | 		       .      "reservation rs " | 
 | 		       . "WHERE rs.requestid = rq.id AND " | 
 | 		       .       "rq.userid IN ($allids) AND " | 
 | 		       .       "rq.start < '{$rqdata['end']}' AND " | 
 | 		       .       "rq.end > '{$rqdata['start']}' AND " | 
 | 		       .       "rs.imageid = {$rqdata['imageid']} AND " | 
 | 		       .       "rs.computerid NOT IN (SELECT computerid " | 
 | 		       .                             "FROM blockComputers " | 
 | 		       .                             "WHERE blockTimeid = $blockTimesid)"; | 
 | 		$qh = doQuery($query); | 
 | 		$donereqids = array(); | 
 | 		$blockCompVals = array(); | 
 | 		$checkstartbase = $unixstart - $imgLoadTime - 300; | 
 | 		$reloadstartbase = unixToDatetime($checkstartbase); | 
 | 		$rows = mysql_num_rows($qh); | 
 | 		while($row = mysql_fetch_assoc($qh)) { | 
 | 			if(array_key_exists($row['reqid'], $donereqids)) | 
 | 				continue; | 
 | 			$donereqids[$row['reqid']] = 1; | 
 | 			if($row['start'] < datetimeToUnix($rqdata['start'])) { | 
 | 				$checkstart = $row['start'] - $imgLoadTime - 300; | 
 | 				$reloadstart = unixToDatetime($checkstart); | 
 | 				$reloadend = unixToDatetime($row['start']); | 
 | 			} | 
 | 			else { | 
 | 				$checkstart = $checkstartbase; | 
 | 				$reloadstart = $reloadstartbase; | 
 | 				$reloadend = $rqdata['start']; | 
 | 			} | 
 | 			# check to see if computer is available for whole block | 
 | 			$rc = isAvailable($images, $rqdata['imageid'], $revisionid, $checkstart, | 
 | 			                  $unixend, 1, $row['reqid'], $row['userid'], | 
 | 			                  $ignoreprivileges, 0, '', '', 1); | 
 | 			// if not available for whole block, just skip this one | 
 | 			if($rc < 1) | 
 | 				continue; | 
 | 			$compid = $requestInfo['computers'][0]; | 
 | 			# create reload reservation | 
 | 			$reqid = simpleAddRequest($compid, $rqdata['imageid'], $revisionid, | 
 | 			                          $reloadstart, $reloadend, 19, $vclreloadid); | 
 | 			if($reqid == 0) | 
 | 				continue; | 
 | 			# add to blockComputers | 
 | 			$blockCompVals[] = "($blockTimesid, $compid, {$rqdata['imageid']}, $reqid)"; | 
 | 			# process any subimages | 
 | 			for($key = 1; $key < count($requestInfo['computers']); $key++) { | 
 | 				$subimageid = $requestInfo['images'][$key]; | 
 | 				$subrevid = getProductionRevisionid($subimageid); | 
 | 				$compid = $requestInfo['computers'][$key]; | 
 | 				$mgmtnodeid = $requestInfo['mgmtnodes'][$key]; | 
 | 				$blockCompVals[] = "($blockTimesid, $compid, $subimageid, $reqid)"; | 
 |  | 
 | 				$query = "INSERT INTO reservation " | 
 | 				       .        "(requestid, " | 
 | 				       .        "computerid, " | 
 | 				       .        "imageid, " | 
 | 				       .        "imagerevisionid, " | 
 | 				       .        "managementnodeid) " | 
 | 				       . "VALUES " | 
 | 				       .       "($reqid, " | 
 | 				       .       "$compid, " | 
 | 				       .       "$subimageid, " | 
 | 				       .       "$subrevid, " | 
 | 				       .       "$mgmtnodeid)"; | 
 | 				doQuery($query, 101); | 
 | 			} | 
 | 		} | 
 | 		if(count($blockCompVals)) { | 
 | 			$blockComps = implode(',', $blockCompVals); | 
 | 			$query = "INSERT INTO blockComputers " | 
 | 			       .        "(blockTimeid, computerid, imageid, reloadrequestid) " | 
 | 			       . "VALUES $blockComps"; | 
 | 			doQuery($query); | 
 | 		} | 
 | 		cleanSemaphore(); | 
 | 	} | 
 |  | 
 | 	# check to see if all computers have been allocated | 
 | 	$query = "SELECT COUNT(computerid) AS allocated " | 
 | 	       . "FROM blockComputers " | 
 | 	       . "WHERE blockTimeid = $blockTimesid"; | 
 | 	$qh = doQuery($query, 101); | 
 | 	if(! $row = mysql_fetch_assoc($qh)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 15, | 
 | 		             'errormsg' => 'failure to communicate with database'); | 
 | 	} | 
 | 	$compCompleted = $row['allocated']; | 
 | 	if(array_key_exists('subimages', $images[$rqdata['imageid']])) | 
 | 		$compsPerAlloc = 1 + count($images[$rqdata['imageid']]['subimages']); | 
 | 	else | 
 | 		$compsPerAlloc = 1; | 
 | 	$toallocate = ($rqdata['numMachines'] * $compsPerAlloc) - $compCompleted; | 
 | 	if($toallocate == 0) { | 
 | 		if(count($blockCompVals)) { | 
 | 			return array('status' => 'success', | 
 | 			             'allocated' => $rqdata['numMachines'], | 
 | 			             'unallocated' => 0); | 
 | 		} | 
 | 		return array('status' => 'completed'); | 
 | 	} | 
 | 	$reqToAlloc = $toallocate / $compsPerAlloc; | 
 |  | 
 | 	if(! $ignoreprivileges) { | 
 | 		# get userids in user group | 
 | 		if(empty($groupmembers)) { | 
 | 			return array('status' => 'error', | 
 | 			             'errorcode' => 11, | 
 | 			             'errormsg' => 'empty user group and ignoreprivileges set to 0'); | 
 | 		} | 
 | 		# make length of $userids match $reqToAlloc by duplicating or trimming some users | 
 | 		while($reqToAlloc > count($userids)) | 
 | 			$userids = array_merge($userids, $userids); | 
 | 		if($reqToAlloc < count($userids)) | 
 | 			$userids = array_splice($userids, 0, $reqToAlloc); | 
 | 	} | 
 |  | 
 | 	# staggering: stagger start times for this round (ie, do not worry about | 
 | 	#   previous processing of this block time) such that there is 1 minute | 
 | 	#   between the start times for each allocation | 
 | 	$stagExtra = $reqToAlloc * 60; | 
 |  | 
 | 	# determine estimated load time | 
 | 	$loadtime = $imgLoadTime + (10 * 60); # add 10 minute fudge factor | 
 | 	if((time() + $loadtime + $stagExtra) > $unixstart) { | 
 | 		$return['status'] = 'warning'; | 
 | 		$return['warningcode'] = 13; | 
 | 		$return['warningmsg'] = 'possibly insufficient time to load machines'; | 
 | 	} | 
 | 	$start = unixToDatetime($unixstart - $loadtime); | 
 |  | 
 | 	$userid = 0; | 
 | 	$allocated = 0; | 
 | 	$blockCompVals = array(); | 
 | 	# FIXME (maybe) - if some subset of users in the user group have available | 
 | 	# computers, but others do not, $allocated will be less than the desired | 
 | 	# number of machines; however, calling this function enough times will | 
 | 	# result in enough machines being allocated because they will continue to be | 
 | 	# allocated based on the ones with machines available; this seems like odd | 
 | 	# behavior | 
 | 	$stagCnt = 0; | 
 | 	$stagTime = 60;        # stagger reload reservations by 1 min | 
 | 	if($imgLoadTime > 840) // if estimated load time is > 14 min | 
 | 		$stagTime = 120;    #    stagger reload reservations by 2 min  | 
 | 	for($i = 0; $i < $reqToAlloc; $i++) { | 
 | 		$stagunixstart = $unixstart - $loadtime - ($stagCnt * $stagTime); | 
 | 		$stagstart = unixToDatetime($stagunixstart); | 
 | 		if(! $ignoreprivileges) | 
 | 			$userid = array_pop($userids); | 
 | 		# use end of block time to find available computers, but... | 
 | 		$rc = isAvailable($images, $rqdata['imageid'], $revisionid, $stagunixstart, | 
 | 		                  $unixend, 1, 0, $userid, $ignoreprivileges); | 
 | 		if($rc < 1) | 
 | 			continue; | 
 |  | 
 | 		$compid = $requestInfo['computers'][0]; | 
 | 		# ...use start of block time as end of reload reservation | 
 | 		$reqid = simpleAddRequest($compid, $rqdata['imageid'], $revisionid, | 
 | 		                          $stagstart, $rqdata['start'], 19, $vclreloadid); | 
 | 		if($reqid == 0) | 
 | 			continue; | 
 |  | 
 | 		$stagCnt++; | 
 | 		$allocated++; | 
 | 		$blockCompVals[] = "($blockTimesid, $compid, {$rqdata['imageid']}, $reqid)"; | 
 |  | 
 | 		# process any subimages | 
 | 		for($key = 1; $key < count($requestInfo['computers']); $key++) { | 
 | 			$subimageid = $requestInfo['images'][$key]; | 
 | 			$subrevid = getProductionRevisionid($subimageid); | 
 | 			$compid = $requestInfo['computers'][$key]; | 
 | 			$mgmtnodeid = $requestInfo['mgmtnodes'][$key]; | 
 | 			$blockCompVals[] = "($blockTimesid, $compid, $subimageid, $reqid)"; | 
 |  | 
 | 			$query = "INSERT INTO reservation " | 
 | 			       .        "(requestid, " | 
 | 			       .        "computerid, " | 
 | 			       .        "imageid, " | 
 | 			       .        "imagerevisionid, " | 
 | 			       .        "managementnodeid) " | 
 | 			       . "VALUES " | 
 | 			       .       "($reqid, " | 
 | 			       .       "$compid, " | 
 | 			       .       "$subimageid, " | 
 | 			       .       "$subrevid, " | 
 | 			       .       "$mgmtnodeid)"; | 
 | 			doQuery($query, 101); | 
 | 		} | 
 | 		$blockComps = implode(',', $blockCompVals); | 
 | 		$query = "INSERT INTO blockComputers " | 
 | 		       .        "(blockTimeid, computerid, imageid, reloadrequestid) " | 
 | 		       . "VALUES $blockComps"; | 
 | 		doQuery($query, 101); | 
 | 		cleanSemaphore(); | 
 | 		$blockCompVals = array(); | 
 | 	} | 
 | 	if($allocated == 0) { | 
 | 		$return['status'] = 'warning'; | 
 | 		$return['warningcode'] = 14; | 
 | 		$return['warningmsg'] = 'unable to allocate any machines'; | 
 | 	} | 
 | 	$return['allocated'] = ($compCompleted / $compsPerAlloc) + $allocated; | 
 | 	$return['unallocated'] = $rqdata['numMachines'] - $return['allocated']; | 
 | 	return $return; | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCfinishBaseImageCapture($ownerid, $resourceid, $virtual=1) | 
 | /// | 
 | /// \param $ownerid - id of owner of image | 
 | /// \param $resourceid - id from resource table for the image | 
 | /// \param $virtual - (bool) 0 if bare metal image, 1 if virtual | 
 | /// | 
 | /// \return an array with at least one index named 'status' which will have | 
 | /// one of these values\n | 
 | /// \b error - error occurred; there will be 2 additional elements in the array: | 
 | /// \li \b errorcode - error number\n | 
 | /// \li \b errormsg - error string\n | 
 | /// | 
 | /// \b success - the permissions, groupings, and mappings were set up | 
 | /// successfully | 
 | /// | 
 | /// \brief calls addImagePermissions to create and set up permissions, | 
 | /// groupings, and mappings so that the owner of a new base image will be able | 
 | /// to make a reservation for it after capturing it using 'vcld -setup'; | 
 | /// specifically designed to be called by vcld as part of the process of | 
 | /// capturing a new base image | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCfinishBaseImageCapture($ownerid, $resourceid, $virtual=1) { | 
 | 	global $user, $xmlrpcBlockAPIUsers; | 
 | 	if(! in_array($user['id'], $xmlrpcBlockAPIUsers)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 89, | 
 | 		             'errormsg' => 'access denied for call to XMLRPCfinishBaseImageCapture'); | 
 | 	} | 
 | 	if(! is_numeric($ownerid)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 90, | 
 | 		             'errormsg' => 'Invalid ownerid submitted'); | 
 | 	} | 
 | 	if(! is_numeric($resourceid)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 91, | 
 | 		             'errormsg' => 'Invalid resourceid submitted'); | 
 | 	} | 
 | 	$ownerdata = getUserInfo($ownerid, 1, 1); | 
 | 	if(is_null($ownerdata) || empty($ownerdata)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 90, | 
 | 		             'errormsg' => 'Invalid ownerid passed as second argument'); | 
 | 	} | 
 | 	$query = "SELECT i.id " | 
 | 	       . "FROM image i, " | 
 | 	       .      "resource r " | 
 | 	       . "WHERE r.id = $resourceid AND " | 
 | 	       .       "r.subid = i.id AND " | 
 | 	       .       "r.resourcetypeid = 13"; | 
 | 	$qh = doQuery($query); | 
 | 	if(mysql_num_rows($qh) != 1) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 91, | 
 | 		             'errormsg' => 'Invalid resourceid submitted'); | 
 | 	} | 
 | 	require_once(".ht-inc/resource.php"); | 
 | 	require_once(".ht-inc/image.php"); | 
 | 	$obj = new Image(); | 
 | 	$obj->addImagePermissions($ownerdata, $resourceid, $virtual); | 
 | 	return array('status' => 'success'); | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCcheckCryptSecrets($reservationid) | 
 | /// | 
 | /// \param $reservationid - id from reservation table | 
 | /// | 
 | /// \return an array with at least one index named 'status' which will have | 
 | /// one of these values:\n | 
 | /// \b error - error occurred; there will be 2 additional elements in the array:\n | 
 | /// \li \b errorcode - error number\n | 
 | /// \li \b errormsg - error string\n | 
 | /// \b success - indicates all secrets were successfully | 
 | /// updated\n | 
 | /// \b partial - indicates only some needed secrets were successfully updates\n | 
 | /// \b noupdate - indicates no missing values were found to be added to | 
 | /// cryptsecret table | 
 | /// | 
 | /// \brief generates any missing entries in cryptsecret for calling management | 
 | /// node to be able to process $reservationid | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCcheckCryptSecrets($reservationid) { | 
 | 	global $user, $xmlrpcBlockAPIUsers; | 
 |  | 
 | 	if(! in_array($user['id'], $xmlrpcBlockAPIUsers)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 99, | 
 | 		             'errormsg' => 'access denied for call to XMLRPCcheckCryptSecrets'); | 
 | 	} | 
 | 	# query to find any cryptkeys that don't have values in cryptsecret | 
 | 	$mycryptkeyid = getCryptKeyID(); | 
 | 	if($mycryptkeyid === NULL) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 100, | 
 | 		             'errormsg' => 'Encryption key missing for this web server'); | 
 | 	} | 
 | 	# check for existance of $reservationid | 
 | 	$query = "SELECT id FROM reservation WHERE id = $reservationid"; | 
 | 	$qh = doQuery($query); | 
 | 	if(! ($row = mysql_fetch_assoc($qh))) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 101, | 
 | 		             'errormsg' => 'Specified reservation does not exist'); | 
 | 	} | 
 | 	# determine any secretids needed from addomain | 
 | 	$secretids = array(); | 
 | 	$mnid = 0; | 
 | 	$query = "SELECT ad.secretid, " | 
 | 	       .        "rs.managementnodeid " | 
 | 	       . "FROM reservation rs " | 
 | 	       . "LEFT JOIN imageaddomain ia ON (rs.imageid = ia.imageid) " | 
 | 	       . "LEFT JOIN addomain ad ON (ia.addomainid = ad.id) " | 
 | 	       . "WHERE rs.id = $reservationid AND " | 
 | 	       .       "ad.secretid IS NOT NULL"; | 
 | 	$qh = doQuery($query); | 
 | 	while($row = mysql_fetch_assoc($qh)) { | 
 | 		$secretids[] = $row['secretid']; | 
 | 		$mnid = $row['managementnodeid']; | 
 | 	} | 
 | 	# determine any secretids needed from vmprofile | 
 | 	$query = "SELECT vp.secretid, " | 
 | 	       .        "rs.managementnodeid " | 
 | 	       . "FROM reservation rs " | 
 | 	       . "JOIN computer c ON (rs.computerid = c.id) " | 
 | 	       . "LEFT JOIN vmhost vh ON (c.vmhostid = vh.id) " | 
 | 	       . "LEFT JOIN vmprofile vp ON (vh.vmprofileid = vp.id) " | 
 | 	       . "WHERE rs.id = $reservationid AND " | 
 | 	       .       "vp.secretid IS NOT NULL"; | 
 | 	$qh = doQuery($query); | 
 | 	while($row = mysql_fetch_assoc($qh)) { | 
 | 		$secretids[] = $row['secretid']; | 
 | 		$mnid = $row['managementnodeid']; | 
 | 	} | 
 |  | 
 | 	if(empty($secretids)) | 
 | 		return array('status' => 'noupdate'); | 
 |  | 
 | 	# find any missing secrets for management nodes | 
 | 	$values = array(); | 
 | 	$fails = array(); | 
 | 	$secret1 = array_shift($secretids); | 
 | 	$subquery = "SELECT $secret1 AS id"; | 
 | 	if(count($secretids) == 1) | 
 | 		$subquery .= " UNION SELECT {$secretids[0]}"; | 
 | 	elseif(count($secretids) > 1) | 
 | 		$subquery .= " UNION SELECT " . implode(' UNION SELECT ', $secretids); | 
 | 	$query = "SELECT ck.id as cryptkeyid, " | 
 | 	       .        "ck.pubkey as cryptkey, " | 
 | 	       .        "s.id as secretid, " | 
 | 	       .        "mycs.cryptsecret AS mycryptsecret " | 
 | 	       . "FROM cryptkey ck " | 
 | 	       . "JOIN ($subquery) AS s " | 
 | 	       . "LEFT JOIN (SELECT cryptsecret, secretid " | 
 | 	       .            "FROM cryptsecret " | 
 | 	       .            "WHERE cryptkeyid = $mycryptkeyid) AS mycs ON (s.id = mycs.secretid) " | 
 | 	       . "LEFT JOIN cryptsecret cs ON (s.id = cs.secretid AND ck.id = cs.cryptkeyid) " | 
 | 	       . "WHERE ck.hostid = $mnid AND " | 
 | 	       .       "ck.hosttype = 'managementnode' AND " | 
 | 	       .       "cs.id IS NULL"; | 
 | 	$qh = doQuery($query); | 
 | 	while($row = mysql_fetch_assoc($qh)) { | 
 | 		if($row['mycryptsecret'] == NULL) { | 
 | 			$fails[] = $row['secretid']; | 
 | 			continue; | 
 | 		} | 
 | 		$secret = decryptSecretKey($row['mycryptsecret']); | 
 | 		$encsecret = encryptSecretKey($secret, $row['cryptkey']); | 
 | 		$values[] = "({$row['cryptkeyid']}, {$row['secretid']}, '$encsecret', '" | 
 | 		          . SYMALGO . "', '" . SYMOPT . "', " . SYMLEN . ")"; | 
 | 	} | 
 | 	if(empty($values) && empty($fails)) | 
 | 		return array('status' => 'noupdate'); | 
 |  | 
 | 	addCryptSecretKeyUpdates($values); | 
 |  | 
 | 	if(count($values) && count($fails)) | 
 | 		return array('status' => 'partial'); | 
 | 	elseif(count($fails)) | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 102, | 
 | 		             'errormsg' => 'Encryption secret missing for this web server'); | 
 |  | 
 | 	return array('status' => 'success'); | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCgetOneClickParams($oneclickid) | 
 | /// | 
 | /// \param $oneclickid - id of the one click | 
 | /// | 
 | /// \return an array with at least one index named 'status' which will have | 
 | /// one of these values:\n | 
 | /// \b error - error occurred; there will be 2 additional elements in the array: | 
 | /// \li \b errorcode - error number | 
 | /// \li \b errormsg - error string | 
 | /// | 
 | /// \b success - there will be these additional elements: | 
 | /// \li \b name - name of one click | 
 | /// \li \b imageid - id of image | 
 | /// \li \b imagename - name of image | 
 | /// \li \b ostype - type of OS in image | 
 | /// \li \b duration - duration for reservations for this one click | 
 | /// \li \b autologin - whether or not autologin should be used with this one | 
 | /// click | 
 | /// | 
 | /// \brief returns the parameters for a one click configuration | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCgetOneClickParams($oneclickid) { | 
 | 	global $user; | 
 | 	$oneclickid = processInputData($oneclickid, ARG_NUMERIC); | 
 | 	$query = "SELECT o.id, " | 
 | 	       .        "o.userid, " | 
 | 	       .        "o.imageid, " | 
 | 	       .        "i.prettyname AS imagename, " | 
 | 	       .        "os.`type` AS ostype, " | 
 | 	       .        "o.name, " | 
 | 	       .        "o.duration, " | 
 | 	       .        "o.autologin " | 
 | 	       . "FROM oneclick o " | 
 | 	       . "LEFT JOIN image i ON (o.imageid = i.id) " | 
 | 	       . "LEFT JOIN OS os ON (i.OSid = os.id) " | 
 | 	       . "WHERE o.id = $oneclickid AND " | 
 | 	       .       "o.status = 1 AND " | 
 | 	       .       "o.userid = {$user['id']}"; | 
 | 	$qh = doQuery($query); | 
 | 	//if nothing returned, oneclick does not exist | 
 | 	if(! $row = mysql_fetch_assoc($qh)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 95, | 
 | 		             'errormsg' => "The OneClick with ID $oneclickid does not exist."); | 
 | 	} | 
 | 	elseif($row['userid'] != $user['id']) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 90, | 
 | 		             'errormsg' => "The OneClick with ID $oneclickid does not belong to the user that requested it."); | 
 | 	} | 
 |  | 
 | 	return array('status' => 'success', | 
 | 	             'name' => $row['name'], | 
 | 	             'imageid' => $row['imageid'], | 
 | 	             'imagename' => $row['imagename'], | 
 | 	             'ostype' => $row['ostype'], | 
 | 	             'duration' => $row['duration'], | 
 | 	             'autologin' => $row['autologin']); | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCgetOneClicks() | 
 | /// | 
 | /// \return an array with 2 indices:\n | 
 | /// \b status - will be 'success'\n | 
 | /// \b oneclicks - will be an array of oneclicks | 
 | /// | 
 | /// \brief builds an array of one clicks belonging to user | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCgetOneClicks() { | 
 | 	global $user; | 
 | 	$states = "8,28,26,27,19,6,3,25,29"; | 
 | 	$query = "SELECT o.id oneclickid, " | 
 | 	        .       "rq.requestid, " | 
 | 	        .       "COALESCE(rq.reqcount, 0) AS reqcount, " | 
 | 	        .       "o.userid, " | 
 | 	        .       "o.imageid, " | 
 | 	        .       "i.prettyname imagename, " | 
 | 	        .       "os.`type` ostype, " | 
 | 	        .       "o.name, " | 
 | 	        .       "o.duration, " | 
 | 	        .       "o.autologin, " | 
 | 	        .       "rq2.stateid AS currstateid, " | 
 | 	        .       "rq2.laststateid " | 
 | 	        . "FROM oneclick o " | 
 | 	        . "LEFT JOIN image i ON (o.imageid = i.id) " | 
 | 	        . "LEFT JOIN OS os ON (i.OSid = os.id) " | 
 | 	        . "LEFT JOIN (" | 
 | 	        .      "SELECT rs.imageid, " | 
 | 	        .             "MAX(rq.id) AS requestid, "  | 
 | 	        .             "COUNT(rq.id) AS reqcount "  | 
 | 	        .      "FROM reservation rs, " | 
 | 	        .           "request rq " | 
 | 	        .      "WHERE rs.requestid = rq.id AND " | 
 | 	        .            "rq.userid = {$user['id']} AND " | 
 | 	        .            "(rq.stateid IN ($states) OR " | 
 | 	        .            "(rq.stateid = 14 AND " | 
 | 	        .             "rq.laststateid IN (13,$states))) " // also include new state if in pending | 
 | 	        .      "GROUP BY rs.imageid) AS rq ON (rq.imageid = i.id) " | 
 | 	        . "LEFT JOIN request rq2 ON (rq.requestid = rq2.id) " | 
 | 	        . "WHERE o.status = 1 AND " | 
 | 	        .       "o.userid = {$user['id']} " | 
 | 	        . "ORDER BY o.name"; | 
 | 	$qh = doQuery($query, 101); | 
 | 	if(! $qh) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 94, | 
 | 		             'errormsg' => "Unable to retrieve user's OneClicks."); | 
 | 	} | 
 | 	$result = array(); | 
 | 	$result['status'] = 'success'; | 
 | 	$result['oneclicks'] = array(); | 
 | 	#$allstates = getStates(); | 
 | 	while($row = mysql_fetch_assoc($qh)) { | 
 | 		/*if($row['currstateid'] == 14) | 
 | 			$state = $allstates[$row['laststateid']]; | 
 | 		elseif(! is_null($row['currstateid'])) | 
 | 			$state = $allstates[$row['currstateid']]; | 
 | 		else | 
 | 			$state = 'none';*/ | 
 | 		$result['oneclicks'][] = array('oneclickid' => $row['oneclickid'], | 
 | 		                               'name' => $row['name'], | 
 | 		                               'imageid' => $row['imageid'], | 
 | 		                               'imagename' => $row['imagename'], | 
 | 		                               'ostype' => $row['ostype'], | 
 | 		                               'duration' => $row['duration'], | 
 | 		                               'autologin' => $row['autologin'], | 
 | 		                               'requestid' => $row['requestid'], | 
 | 		                               'reqcount' => $row['reqcount']/*, | 
 | 		                               'state' => $state*/); | 
 | 	} | 
 | 	return $result; | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCaddOneClick($name, $imageid, $duration, $autologin) | 
 | /// | 
 | /// \param $name - name of new one click | 
 | /// \param $imageid - id of image for new one click | 
 | /// \param $duration - duration for reservations made for this one click | 
 | /// \param $autologin - (?) 1 for autologin, 0 to skip autologin | 
 | /// | 
 | /// \return an array with at least one index named 'status' which will have | 
 | /// one of these values:\n | 
 | /// \b error - error occurred; there will be 2 additional elements in the array: | 
 | /// \li \b errorcode - error number | 
 | /// \li \b errormsg - error string | 
 | /// | 
 | /// \b success - there will be one additional element in this case: | 
 | /// \li \b oneclickid - id of new one click | 
 | /// | 
 | /// \brief adds a new one click to VCL | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCaddOneClick($name, $imageid, $duration, $autologin) { | 
 | 	global $user; | 
 | 	$userid = $user['id']; | 
 | 	$imageid = processInputData($imageid, ARG_NUMERIC); | 
 | 	$name = processInputData($name, ARG_STRING); | 
 | 	$duration = processInputData($duration, ARG_NUMERIC); | 
 | 	$autologin = processInputData($autologin, ARG_NUMERIC) == 1 ? 1 : 0; | 
 |  | 
 | 	# validate $imageid | 
 | 	$resources = getUserResources(array("imageAdmin", "imageCheckOut")); | 
 | 	$images = removeNoCheckout($resources["image"]); | 
 | 	if(! array_key_exists($imageid, $images)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 93, | 
 | 		             'errormsg' => "Unable to create OneClick."); | 
 | 	} | 
 |  | 
 | 	# validate $name | 
 | 	if(! preg_match('/^([-a-zA-Z0-9\. \(\)]){3,70}$/', $name)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 93, | 
 | 		             'errormsg' => "Unable to create OneClick."); | 
 | 	} | 
 |  | 
 | 	# validate $duration | 
 | 	$images = getImages(0, $imageid); | 
 | 	$maxlength = $images[$imageid]['maxinitialtime']; | 
 | 	$maxtimes = getUserMaxTimes(); | 
 | 	if($maxlength && $maxlength < $maxtimes['initial']) | 
 | 		$maxduration = $maxlength; | 
 | 	else | 
 | 		$maxduration = $maxtimes['initial']; | 
 | 	if($duration > $maxduration) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 93, | 
 | 		             'errormsg' => "Unable to create OneClick."); | 
 | 	} | 
 |  | 
 | 	$query = "INSERT INTO oneclick" | 
 | 	       .        "(userid, " | 
 | 	       .        "imageid, " | 
 | 	       .        "name, " | 
 | 	       .        "duration, " | 
 | 	       .        "autologin, " | 
 | 	       .        "status) " | 
 | 	       . "VALUES " | 
 | 	       .        "($userid, " | 
 | 	       .        "$imageid, " | 
 | 	       .        "'$name', " | 
 | 	       .        "$duration, " | 
 | 	       .        "$autologin, " | 
 | 	       .        "1) "; | 
 | 	$qh = doQuery($query, 101); | 
 | 	if(! $qh) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 93, | 
 | 		             'errormsg' => "Unable to create OneClick."); | 
 | 	} | 
 | 	$return = array(); | 
 | 	$return['oneclickid']= dbLastInsertID(); | 
 | 	$return['status'] = 'success'; | 
 | 	return $return; | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCeditOneClick($oneclickid, $name, $imageid, $duration, $autologin) | 
 | /// | 
 | /// \param $oneclickid - id of the one click | 
 | /// \param $name - name of new one click | 
 | /// \param $imageid - id of image for new one click | 
 | /// \param $duration - duration for reservations made for this one click | 
 | /// \param $autologin - (?) 1 for autologin, 0 to skip autologin | 
 | /// | 
 | /// \return an array with at least one index named 'status' which will have | 
 | /// one of these values:\n | 
 | /// \b error - error occurred; there will be 2 additional elements in the array: | 
 | /// \li \b errorcode - error number | 
 | /// \li \b errormsg - error string | 
 | /// | 
 | /// \b success - there will be these additional elements: | 
 | /// \li \b name - name of one click | 
 | /// \li \b imageid - id of image | 
 | /// \li \b imagename - name of image | 
 | /// \li \b ostype - type of OS in image | 
 | /// \li \b duration - duration for reservations for this one click | 
 | /// \li \b autologin - whether or not autologin should be used with this one | 
 | /// click | 
 | /// | 
 | /// \brief edits the configuration of a one click | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCeditOneClick($oneclickid, $name, $imageid, $duration, $autologin) { | 
 | 	global $user; | 
 | 	$oneclickid = processInputData($oneclickid, ARG_NUMERIC); | 
 | 	$imageid = processInputData($imageid, ARG_NUMERIC); | 
 | 	$name = processInputData($name, ARG_STRING); | 
 | 	$duration = processInputData($duration, ARG_NUMERIC); | 
 | 	$autologin = processInputData($autologin, ARG_NUMERIC) == 1 ? 1 : 0; | 
 |  | 
 | 	# validate $imageid | 
 | 	$resources = getUserResources(array("imageAdmin", "imageCheckOut")); | 
 | 	$images = removeNoCheckout($resources["image"]); | 
 | 	if(! array_key_exists($imageid, $images)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 92, | 
 | 		             'errormsg' => "Invalid image specified"); | 
 | 	} | 
 |  | 
 | 	# validate $name | 
 | 	if(! preg_match('/^([-a-zA-Z0-9\. \(\)]){3,70}$/', $name)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 96, | 
 | 		             'errormsg' => "Invalid name specified - name can be from 3 to 70 characters long and can only contain letters, numbers, spaces, and these characters: - . ( )"); | 
 | 	} | 
 |  | 
 | 	# validate $duration | 
 | 	$images = getImages(0, $imageid); | 
 | 	$maxlength = $images[$imageid]['maxinitialtime']; | 
 | 	$maxtimes = getUserMaxTimes(); | 
 | 	if($maxlength && $maxlength < $maxtimes['initial']) | 
 | 		$maxduration = $maxlength; | 
 | 	else | 
 | 		$maxduration = $maxtimes['initial']; | 
 | 	if($duration > $maxduration) { | 
 | 		$allowed = prettyLength($maxduration); | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 97, | 
 | 		             'errormsg' => "Specified duration is too long", | 
 | 		             'maxduration' => $allowed); | 
 | 	} | 
 | 	 | 
 | 	$query = "SELECT id " | 
 | 	       . "FROM oneclick " | 
 | 	       . "WHERE id = $oneclickid AND " | 
 | 	       .       "status = 1 AND " | 
 | 	       .       "userid = {$user['id']}"; | 
 | 	$qh = doQuery($query, 101); | 
 | 	//if nothing returned, oneclick does not exist or belongs to another user | 
 | 	if(! $row = mysql_fetch_assoc($qh)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 95, | 
 | 		             'errormsg' => "The OneClick with ID $oneclickid does not exist."); | 
 | 	} | 
 | 	/*elseif($row['userid'] != $user['id']) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 90, | 
 | 		             'errormsg' => "The OneClick with ID $oneclickid does not belong to the user that requested it."); | 
 | 	}*/ | 
 | 	 | 
 | 	$query = "UPDATE oneclick " | 
 | 	       . "SET imageid = $imageid, " | 
 | 	       .     "name = '$name', " | 
 | 	       .     "duration = $duration, " | 
 | 	       .     "autologin = $autologin " | 
 | 	       . "WHERE id = $oneclickid AND " | 
 | 	       .       "userid = {$user['id']}"; | 
 | 	$qh = doQuery($query, 101); | 
 | 	if(! $qh) | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 98, | 
 | 		             'errormsg' => "Unable to update OneClick."); | 
 |  | 
 | 	return XMLRPCgetOneClickParams($oneclickid); | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCdeleteOneClick($oneclickid) { | 
 | /// | 
 | /// \param $oneclickid - id of the one click | 
 | /// | 
 | /// \return an array with at least one index named 'status' which will have | 
 | /// one of these values:\n | 
 | /// \b error - error occurred; there will be 2 additional elements in the array: | 
 | /// \li \b errorcode - error number | 
 | /// \li \b errormsg - error string | 
 | /// | 
 | /// \b success - one click was successfully deleted | 
 | /// | 
 | /// \brief deletes a one click | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCdeleteOneClick($oneclickid) { | 
 | 	global $user; | 
 | 	$oneclickid = processInputData($oneclickid, ARG_NUMERIC); | 
 | 	 | 
 | 	$query = "SELECT id " | 
 | 	       . "FROM oneclick " | 
 | 	       . "WHERE id = $oneclickid AND " | 
 | 	       .       "userid = {$user['id']}"; | 
 | 	$qh = doQuery($query, 101); | 
 | 	//if nothing returned, oneclick does not exist or belongs to another user | 
 | 	if(! $row = mysql_fetch_assoc($qh)) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 95, | 
 | 		             'errormsg' => "The OneClick with ID $oneclickid does not exist."); | 
 | 	} | 
 |  | 
 | 	$query = "UPDATE oneclick " | 
 | 	       . "SET status = 0 " | 
 | 	       . "WHERE id = $oneclickid AND " | 
 | 	       .       "userid = {$user['id']}"; | 
 | 	$qh = doQuery($query, 101); | 
 | 	if(! $qh) { | 
 | 		return array('status' => 'error', | 
 | 		             'errorcode' => 91, | 
 | 		             'errormsg' => "Unable to delete OneClick."); | 
 | 	} | 
 | 	$return = array(); | 
 | 	$return['status'] = 'success'; | 
 | 	return $return; | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | /// | 
 | /// \fn XMLRPCgetIP() | 
 | /// | 
 | /// \return an array with 2 indices:\n | 
 | /// \b status - will be 'success'\n | 
 | /// \b ip - will be the client's IP address as seen by the server\n | 
 | /// | 
 | /// \brief this is a function that returns the client's IP address as seen by | 
 | /// the server | 
 | /// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | function XMLRPCgetIP() { | 
 | 	return array('status' => 'success', 'ip' => $_SERVER['REMOTE_ADDR']); | 
 | } | 
 | ?> |