? .settings
? kompare
Index: server/pifr_server.xmlrpc.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/project_issue_file_review/server/pifr_server.xmlrpc.inc,v
retrieving revision 1.41
diff -u -p -r1.41 pifr_server.xmlrpc.inc
--- server/pifr_server.xmlrpc.inc	10 Feb 2010 22:14:10 -0000	1.41
+++ server/pifr_server.xmlrpc.inc	21 Feb 2010 01:16:34 -0000
@@ -76,6 +76,15 @@ function pifr_server_xmlrpc_queue($clien
       pifr_debug('XML-RPC batch(): server is not active, request denied.');
       return array(
         'response' => PIFR_RESPONSE_DENIED,
+        'errors' => array(t('Server is not active.')),
+      );
+    }
+
+    // Validate and clean the incoming batch.
+    if (!($batch = pifr_server_xmlrpc_validate('queue', $batch))) {
+      return array(
+        'response' => PIFR_RESPONSE_DENIED,
+        'errors' => pifr_server_xmlrpc_error(),
       );
     }
 
@@ -116,6 +125,7 @@ function pifr_server_xmlrpc_queue($clien
     pifr_debug('XML-RPC batch(): invalid project client.');
     return array(
       'response' => PIFR_RESPONSE_INVALID_SERVER,
+      'errors' => array(t('Invalid project client, check key and ensure that client is enabled.')),
     );
   }
 }
@@ -483,3 +493,222 @@ function pifr_server_xmlrpc_time_gmt($ti
   $offset = $now - $timestamp;
   return gmmktime() - $offset;
 }
+
+/**
+ * Validate the arguments for a given XML-RPC method.
+ *
+ * @param string $method XML-RPC method without the 'pifr.' prefix.
+ * @param ... Additional arguments to validate.
+ * @return mixed Validated and cleaned data.
+ */
+function pifr_server_xmlrpc_validate($method) {
+  // Get all the arguments after the first argument ($method).
+  $args = func_get_args();
+  array_shift($args);
+
+  // Call the related validation function and return the cleaned data.
+  $return = call_user_func_array('pifr_server_xmlrpc_validate_' . $method, $args);
+
+  // If an error occured return FALSE, execution should stop and the errors
+  // should be returned, as reported by pifr_server_xmlrpc_error().
+  if (pifr_server_xmlrpc_error()) {
+    return FALSE;
+  }
+  return $return;
+}
+
+/**
+ * Validate pifr.queue() batch.
+ *
+ * @param array $batch Queue batch to validate.
+ * @return array Cleaned data.
+ */
+function pifr_server_xmlrpc_validate_queue(array $batch) {
+  // Ensure every base key is present.
+  $default = array(
+    'branches' => array(),
+    'files' => array(),
+    'projects' => array(),
+  );
+  $batch += $default;
+
+  if (count(array_keys($batch)) > 3) {
+    pifr_server_xmlrpc_error('Only keys [branches, files, projects] are allowed.');
+    pifr_server_xmlrpc_error(print_r($batch, TRUE));
+  }
+
+  // Get a list of supported vcs backends.
+  $includes = file_scan_directory(drupal_get_path('module', 'pifr_client') . '/review/vcs', '.*');
+  $backends = array();
+  foreach ($includes as $include) {
+    $backend = str_replace('.inc', '', $include->basename);
+    if ($backend != 'vcs') {
+      $backends[] = $backend;
+    }
+  }
+
+  // Validate each project.
+  $required_keys = array('client_identifier', 'name', 'repository_type', 'repository_url');
+  $i = 1;
+  $project_identifiers = array();
+  foreach ($batch['projects'] as &$project) {
+    // Ensure that all required keys are found.
+    if ($errors = pifr_server_xmlrpc_required_check($project, $required_keys)) {
+      pifr_server_xmlrpc_error_list('project', $i, $errors);
+      continue;
+    }
+
+    if (!pifr_server_xmlrpc_is_int($project['client_identifier'])) {
+      $errors[] = t('[client_identifier] must be an integer');
+    }
+    elseif (in_array($project['client_identifier'], $project_identifiers)) {
+      $errors[] = t('[client_identifier] must be unique');
+    }
+    if (!in_array($project['repository_type'], $backends)) {
+      $errors[] = t('[repository_type] must be one of [@list]', array('@list' => implode(', ', $backends)));
+    }
+
+    // Keep a list of project identifiers for validation.
+    $project_identifiers[] = $project['client_identifier'];
+
+    // If any errors where found then register an error for the file.
+    pifr_server_xmlrpc_error_list('project', $i, $errors);
+
+    $i++;
+  }
+
+  // Validate each branch.
+  $required_keys = array('project_identifier', 'client_identifier', 'vcs_identifier');
+  $default = array(
+    'dependency' => '',
+    'plugin_argument' => array(),
+    'test' => FALSE,
+  );
+  $i = 1;
+  $branch_identifiers = array();
+  foreach ($batch['branches'] as &$branch) {
+    // Ensure that all required keys are found.
+    if ($errors = pifr_server_xmlrpc_required_check($branch, $required_keys)) {
+      pifr_server_xmlrpc_error_list('branch', $i, $errors);
+      continue;
+    }
+
+    // Provide default values for optional keys.
+    $branch += $default;
+
+    // Validate fields.
+    if (!pifr_server_xmlrpc_is_int($branch['project_identifier'])) {
+      $errors[] = t('[project_identifier] must be an integer');
+    }
+    if (!pifr_server_xmlrpc_is_int($branch['client_identifier'])) {
+      $errors[] = t('[client_identifier] must be an integer');
+    }
+    elseif (in_array($branch['client_identifier'], $branch_identifiers)) {
+      $errors[] = t('[client_identifier] must be unique');
+    }
+    if (!empty($branch['dependency'])) {
+      $dependencies = explode(',', $branch['dependency']);
+      foreach ($dependencies as $dependency) {
+        if (!pifr_server_xmlrpc_is_int($dependency)) {
+          $errors[] = t('all dependencies must be integers');
+          break;
+        }
+      }
+    }
+
+    // Keep a list of branch identifiers for validation.
+    $branch_identifiers[] = $branch['client_identifier'];
+
+    // If any errors where found then register an error for the branch.
+    pifr_server_xmlrpc_error_list('branch', $i, $errors);
+
+    $i++;
+  }
+
+  // Validate each file.
+  $required_keys = array('branch_identifier', 'client_identifier', 'file_url');
+  $i = 1;
+  foreach ($batch['files'] as &$file) {
+    // Ensure that all required keys are found.
+    if ($errors = pifr_server_xmlrpc_required_check($file, $required_keys)) {
+      pifr_server_xmlrpc_error_list('file', $i, $errors);
+      continue;
+    }
+
+    if (!pifr_server_xmlrpc_is_int($file['branch_identifier'])) {
+      $errors[] = t('[branch_identifier] must be an integer');
+    }
+    if (!in_array($file['branch_identifier'], $branch_identifiers)) {
+      $errors[] = t('[branch_identifier] not found in branch list');
+    }
+    if (!pifr_server_xmlrpc_is_int($file['client_identifier'])) {
+      $errors[] = t('[client_identifier] must be an integer');
+    }
+
+    // If any errors where found then register an error for the file.
+    pifr_server_xmlrpc_error_list('file', $i, $errors);
+
+    $i++;
+  }
+
+  return $batch;
+}
+
+/**
+ * Store and retrieve XML-RPC errors.
+ *
+ * @param string $error (Optional) XML-RPC error, or NULL to simply retrieve.
+ * @return array List of errors.
+ */
+function pifr_server_xmlrpc_error($error = NULL) {
+  static $errors = array();
+
+  if ($error) {
+    $errors[] = $error;
+  }
+  return $errors;
+}
+
+/**
+ * Generate a string from a list of errors for a particular field.
+ *
+ * @param string $key Field key.
+ * @param integer $number Entry number of the field that triggered the errors.
+ * @param array $errors List of errors.
+ */
+function pifr_server_xmlrpc_error_list($key, $number, array $errors) {
+  if ($errors) {
+    pifr_server_xmlrpc_error(t('Error(s) found in @key #@number: !list.', array(
+      '@key' => $key,
+      '@number' => $number,
+      '!list' => implode(', ', $errors),
+    )));
+  }
+}
+
+/**
+ * Generate errors for if required keys are not found.
+ *
+ * @param array Data to check for required keys in.
+ * @param array $required_keys List required keys.
+ * @return array List of errors generated by missing keys.
+ */
+function pifr_server_xmlrpc_required_check(array $data, array $required_keys) {
+  $errors = array();
+  foreach ($required_keys as $required_key) {
+    if (empty($data[$required_key])) {
+      $errors[] = t('required key [@key] not found', array('@key' => $required_key));
+    }
+  }
+  return $errors;
+}
+
+/**
+ * Check if a value is an integer.
+ *
+ * @param mixed $value Value to check.
+ * @return boolean TRUE if value is an integer, otherwise FALSE.
+ */
+function pifr_server_xmlrpc_is_int($value) {
+  return is_numeric($value) && (int) $value == (float) $value;
+}
