diff --git quota/hosting.feature.quota.inc quota/hosting.feature.quota.inc
new file mode 100644
index 0000000..36ef6e9
--- /dev/null
+++ quota/hosting.feature.quota.inc
@@ -0,0 +1,13 @@
+<?php
+
+function hosting_quota_hosting_feature() {
+  $features['quota'] = array(
+    'title' => t('Client Quota'),
+    'description' => t('Manage the allocation of hosting resources by client (e.g. sites, bandwidth, storage).'),
+    'status' => HOSTING_FEATURE_ENABLED,
+    'module' => 'hosting_quota',
+    'group' => 'experimental',
+  );
+  return $features;
+}
+
diff --git quota/hosting_quota.info quota/hosting_quota.info
new file mode 100755
index 0000000..78764a0
--- /dev/null
+++ quota/hosting_quota.info
@@ -0,0 +1,7 @@
+name = Client Quota
+description = Allow Hostmaster to configure quotas.
+package = Hosting
+dependencies[] = hosting
+dependencies[] = hosting_client
+
+core = 6.x
diff --git quota/hosting_quota.install quota/hosting_quota.install
new file mode 100644
index 0000000..c5c58c9
--- /dev/null
+++ quota/hosting_quota.install
@@ -0,0 +1,43 @@
+<?php
+// $Id:$
+
+/**
+ * Implementation of hook_schema().
+ */
+function hosting_quota_schema() {
+  $schema['hosting_client_quota'] = array(
+    'fields' => array(
+      'client' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'resource' => array(
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'value' => array(
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+    ),
+    'primary key' => array('client', 'resource'),
+  );
+
+  return $schema;
+}
+
+function hosting_quota_install() {
+  // Create tables.
+  drupal_install_schema('hosting_quota');
+}
+
+function hosting_quota_uninstall() {
+  // Create tables.
+  drupal_uninstall_schema('hosting_quota');
+}
diff --git quota/hosting_quota.module quota/hosting_quota.module
new file mode 100644
index 0000000..aa6b20f
--- /dev/null
+++ quota/hosting_quota.module
@@ -0,0 +1,279 @@
+<?php
+/**
+ * @file Implement quota's for the resource used by client.
+ */
+
+/**
+ * Implements hook_perm().
+ */
+function hosting_quota_perm() {
+  return array('edit quota', 'view quota');
+}
+
+/**
+ * Implements hook_nodeapi().
+ */
+function hosting_quota_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
+  if ($node->type == 'client') {
+    switch ($op) {
+      case 'insert':
+      case 'update':
+        if (user_access('edit quota')) {
+          foreach ($node as $field => $value) {
+            if (substr($field, 0, 6) == 'quota-') {
+              $quota = substr($field, 6);
+              hosting_quota_save_quota($node->nid, $quota, $value);
+            }
+          }
+        }
+      case 'load':
+        $node->quota = hosting_quota_get_client_quota($node->nid);
+      case 'view':
+        if (user_access('view quota')) {
+           $node->content['info']['quota'] = array(
+             '#type' => 'item',
+             '#title' => 'Quota',
+             '#value' => theme('hosting_quota_client', $node),
+             '#weight' => 5,
+          );
+        }
+        break;
+    }
+  }
+
+  // Display form error if client site quota reached. 
+  if ($node->type == 'site') {
+    switch ($op) {
+      case 'validate':
+        if (empty($node->nid)) {
+          $client_node = node_load($node->client); 
+          $usage = hosting_quota_sites_usage($node->client);
+          $limit = $client_node->quota['sites']['limit'];
+
+          if ($usage >= $limit && !empty($limit)) {
+            form_set_error('client', t('@client has reached their site quota of @sites. No new sites can be added unless an existing site is deleted or the site quota is increased.', array('@client' => $client_node->title, '@sites' => $limit)));
+          }
+        }
+    }
+  }
+}
+
+/**
+ *
+ */
+function hosting_quota_form_alter(&$form, $form_state, $form_id) {
+  if (isset($form['type']) && isset($form['#node']) && 'client_node_form' == $form_id) {
+    $node = $form['#node'];
+
+    $quota_info = hosting_quota_get_quota_resource();
+
+    if (!empty($quota_info)) {
+      $form['quota'] = array(
+        '#type' => 'fieldset',
+        '#title' => t('Client quota settings'),
+        '#access' => user_access('edit quota'),
+        '#collapsible' => TRUE,
+        '#collapsed' => TRUE,
+      );
+
+      foreach ($quota_info as $resource => $quota) {
+        $form['quota']['quota-'. $resource] = array(
+          '#title' => $quota['title'],
+          '#description' => $quota['description'],
+          '#type' => 'textfield',
+          '#default_value' => $node->quota[$resource] ? $node->quota[$resource]['limit'] : 0,
+        );
+        if (!empty($node->quota[$resource]['#value'])) {
+          $form['quota']['quota-'. $resource]['#default_value'] = $node->quota[$resource]['#value'];
+        }
+      }
+    }
+  }
+
+  // Display error message if client site quota reached.
+  if ($form_id == 'site_node_form') {
+    if ($form['client']['#type'] == 'hidden') {
+      $client = arg(1);
+      $node = node_load($client);
+      $usage = hosting_quota_sites_usage($client);
+      $limit = $node->quota['sites']['limit'];
+
+      if ($usage >= $limit && !empty($limit)) {
+        drupal_set_message(t('@client has reached their site quota of @sites. No new sites can be added unless an existing site is deleted or the site quota is increased.', array('@client' => $node->title, '@sites' => $limit)), 'error');
+      }
+    }
+  }
+}
+
+/**
+ * Gets the quota information for client.
+ *
+ * @param $client
+ *   The client node id.
+ */
+function hosting_quota_get_client_quota($client) {
+  $quotas = hosting_quota_get_quota_resource();
+
+  $result = db_query("SELECT * from {hosting_client_quota} WHERE client=%d", $client);
+  while ($quota = db_fetch_object($result)) {
+    $quotas[$quota->resource]['limit'] = $quota->value;
+  }
+  return $quotas;
+}
+
+/**
+ * Save the quota.
+ *
+ * @param $client
+ *   The client node id.
+ * @param $resource
+ *   The resource being limited.
+ * @param $value
+ *   The value to save as the quota limit.
+ */
+function hosting_quota_save_quota($client, $resource, $value) {
+  $result = db_query("UPDATE {hosting_client_quota} SET value='%s' WHERE client=%d AND resource='%s'", $value, $client, $resource);
+  if (db_affected_rows() == 0) {
+    $result = db_query("INSERT INTO {hosting_client_quota} (client, resource, value) VALUES (%d, '%s', '%s')", $client, $resource, $value);
+  }
+}
+
+/**
+ * Implements hook_theme().
+ */
+function hosting_quota_theme($existing, $resource, $theme, $path) {
+  return array(
+    'hosting_quota_client' => array(
+      'arguments' => array('node' => NULL),
+    ),
+  );
+}
+
+/**
+ * Theme the client quota information.
+ *
+ * @param $node
+ *   The client node object being themed.
+ */
+function theme_hosting_quota_client($node) {
+  if (!empty($node->quota)) {
+    $header = array(t('Resource'), t('Used'), t('Quota'));
+    foreach($node->quota as $resource => $value) {
+      $row = array();
+      $row[] = $value['title'];
+      $row[] = hosting_quota_usage($node->nid, $resource);
+      $row[] = (empty($value['limit']) ? 'unlimited' : check_plain($value['limit']));
+      $rows[] = $row;
+    }
+    return theme('table', $header, $rows);
+  }
+  return '';
+}
+
+/**
+ * Retrieve the details of resources that have a quota.
+ *
+ * @param $resource
+ *   If specified then it just returns details on this specific resource.
+ */
+function hosting_quota_get_quota_resource($resource = NULL) {
+  static $quota_info;
+
+  if (!isset($quota_info)) {
+    $quota_info = array();
+    foreach (module_implements('client_quota') as $module) {
+      if ($result = module_invoke($module, 'client_quota')) {
+        foreach ($result as $id => $quota) {
+          $quota_info[$id] = $quota;
+        }
+      }
+    }
+  }
+
+  if ($resource !==  NULL) {
+    return isset($quota_info[$resource]) ? $quota_info[$resource] : array();
+  }
+  return $quota_info;
+}
+
+/**
+ * 
+ */
+function hosting_quota_client_quota() {
+  $quota['sites'] = array(
+    'title' => t('Sites'),
+    'description' => t('The number of sites this client can have provisioned under them at any one time. Set to 0 for unlimited.'),
+    'usage callback' => 'hosting_quota_sites_usage',
+  );
+  $quota['bandwidth'] = array(
+    'title' => t('Bandwidth'),
+    'description' => t('Enter the monthly bandwidth allocation for this client, the value can be entered in MB or GB (e.g. 50GB). Set to 0 for unlimited.'),
+    'usage callback' => 'hosting_quota_bandwidth_usage',
+  );
+  $quota['storage'] = array(
+    'title' => t('Storage'),
+    'description' => t('Enter the storage allocation for this client, the value can be entered in MB or GB (e.g. 5GB). Set to 0 for unlimited.'),
+    'usage callback' => 'hosting_quota_storage_usage',
+  );
+
+  return $quota;
+}
+
+/**
+ * Get the current quota usage for the specific client and resource.
+ *
+ * @param $client
+ *   The client node id.
+ * @param $resource
+ *   The resource being limited.
+ */
+function hosting_quota_usage($client, $resource) {
+  $quota_info = hosting_quota_get_quota_resource($resource);
+  $function = $quota_info['usage callback'];
+  if (function_exists($function)) {
+    return call_user_func_array($function, array($client));
+  }
+  return t('unknown'); 
+}
+
+/**
+ * Get site usage.
+ *
+ * @param $client
+ *   The client node id.
+ */
+function hosting_quota_sites_usage($client) {
+  return db_result(db_query("SELECT count(*) from {hosting_site} WHERE client=%d", $client));
+}
+
+/**
+ * Implements hook_allow_domain().
+ */
+function hosting_quota_allow_domain($url, $params) {
+  if (isset($params['client'])) {
+    $client = node_load($params['client']); 
+    $usage = hosting_quota_sites_usage($params['client']);
+    $limit = $client->quota['sites']['#value'];
+
+    if ($usage < $limit || empty($client->quota['sites']['#value'])) {
+      return TRUE;
+    }
+
+    drupal_set_message(t('@client has reached their site quota of @sites. No new sites can be added unless an existing site is deleted or the site quota is increased.', array('@client' => $client->title, '@sites' => $limit)), 'error');
+  }
+  return FALSE;
+}
+
+/**
+ * Get file storage usage.
+ *
+ * @param $client
+ *   The client node id.
+ *
+ * TODO: this is going to have to done by drush.
+ */
+function hosting_quota_storage_usage($client) {
+  // This is not correct as its giving the size of all the databases that the hostmaster db user has access to
+  $db_size = db_result(db_query("SELECT sum( data_length + index_length) / 1024 / 1024 FROM information_schema.TABLES"));
+  return sprintf("%0.1fMB", $db_size);
+}
