Index: captcha.admin.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/captcha/captcha.admin.inc,v
retrieving revision 1.32.2.4
diff -u -b -u -p -r1.32.2.4 captcha.admin.inc
--- captcha.admin.inc	1 Dec 2010 00:14:55 -0000	1.32.2.4
+++ captcha.admin.inc	1 Dec 2010 00:36:52 -0000
@@ -65,11 +65,11 @@ function captcha_admin_settings(&$form_s
   );
   $form['captcha_form_protection']['captcha_form_id_overview']['captcha_captcha_points'] = array();
   $captcha_type_options = _captcha_available_challenge_types();
-  // TODO: make a wrapper for this query to make it a bit cleaner?
-  $result = db_query("SELECT * FROM {captcha_points} ORDER BY form_id");
-  while ($captcha_point = db_fetch_object($result)) {
-    $form['captcha_form_protection']['captcha_form_id_overview']['captcha_captcha_points'][$captcha_point->form_id] = array();
-    $form['captcha_form_protection']['captcha_form_id_overview']['captcha_captcha_points'][$captcha_point->form_id]['form_id'] = array(
+
+  $captcha_points = captcha_get_captcha_points();
+  foreach ($captcha_points as $captcha_point) {
+    $elem = array();
+    $elem['form_id'] = array(
       '#value' => $captcha_point->form_id,
     );
     // Select widget for CAPTCHA type.
@@ -82,17 +82,25 @@ function captcha_admin_settings(&$form_s
     else {
       $captcha_type = 'none';
     }
-    $form['captcha_form_protection']['captcha_form_id_overview']['captcha_captcha_points'][$captcha_point->form_id]['captcha_type'] = array(
+    $elem['captcha_type'] = array(
       '#type' => 'select',
       '#default_value' => $captcha_type,
       '#options' => $captcha_type_options,
     );
     // Additional operations.
-    $form['captcha_form_protection']['captcha_form_id_overview']['captcha_captcha_points'][$captcha_point->form_id]['operations'] = array(
-      '#value' => implode(", ", array(
-        l(t('delete'), "admin/user/captcha/captcha/captcha_point/{$captcha_point->form_id}/delete"),
-      ))
-    );
+    $ops = array();
+    if (module_exists('ctools') && $captcha_point->export_type & EXPORT_IN_CODE) {
+      if ($captcha_point->export_type & EXPORT_IN_DATABASE) {
+        $ops[] = l(t('revert'), "admin/user/captcha/captcha/captcha_point/{$captcha_point->form_id}/delete");
+      }
+      // TODO Disable exported points.
+    }
+    else {
+      $ops[] = l(t('delete'), "admin/user/captcha/captcha/captcha_point/{$captcha_point->form_id}/delete");
+    }
+    $elem['operations'] = array('#value' => implode(", ", $ops));
+
+    $form['captcha_form_protection']['captcha_form_id_overview']['captcha_captcha_points'][$captcha_point->form_id] = $elem;
   }
 
   // Form items for new form_id.
@@ -275,7 +283,30 @@ function captcha_admin_settings_submit($
 
   // Process CAPTCHA points
   if (isset($form_state['values']['captcha_form_id_overview']['captcha_captcha_points'])) {
+    // Load existing data.
+    $captcha_points = captcha_get_captcha_points();
+     
+
     foreach ($form_state['values']['captcha_form_id_overview']['captcha_captcha_points'] as $captcha_point_form_id => $data) {
+
+      // If this is an in-code captcha point and its settings are unchanged,
+      // don't save to the database.
+      if (module_exists('ctools') && isset($captcha_points[$captcha_point_form_id])) {
+        // Parse module and captcha_type from submitted values.
+        if (is_string($data['captcha_type']) && substr_count($data['captcha_type'], '/') == 1) {
+          list($module, $captcha_type) = explode('/', $data['captcha_type']);
+        }
+        else {
+          $module = '';
+          $captcha_type = $data['captcha_type'];
+        }
+
+        $point = $captcha_points[$captcha_point_form_id];
+        if ($point->export_type & EXPORT_IN_CODE && !($point->export_type & EXPORT_IN_DATABASE) && $point->module == $module && $point->captcha_type == $captcha_type) {
+          continue;
+        }
+      }
+
       captcha_set_form_id_setting($captcha_point_form_id, $data['captcha_type']);
     }
   }
Index: captcha.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/captcha/captcha.inc,v
retrieving revision 1.11.2.6
diff -u -b -u -p -r1.11.2.6 captcha.inc
--- captcha.inc	1 Dec 2010 00:14:57 -0000	1.11.2.6
+++ captcha.inc	1 Dec 2010 00:36:53 -0000
@@ -57,11 +57,18 @@ function captcha_set_form_id_setting($fo
  *   or in the form 'captcha/Math'.
  */
 function captcha_get_form_id_setting($form_id, $symbolic=FALSE) {
+  if (module_exists('ctools')) {
+    ctools_include('export');
+    $captcha_point = array_pop(ctools_export_load_object('captcha_points', 'names', array($form_id)));
+  }
+  else {
   $result = db_query("SELECT module, captcha_type FROM {captcha_points} WHERE form_id = '%s'", $form_id);
   if (!$result) {
     return NULL;
   }
   $captcha_point = db_fetch_object($result);
+  }
+
   if (!$captcha_point) {
     $captcha_point = NULL;
   }
@@ -84,7 +91,25 @@ function captcha_get_form_id_setting($fo
   return $captcha_point;
 }
 
-
+/**
+ * Helper function to load all captcha points.
+ *
+ * @return array of all captcha_points
+ */
+function captcha_get_captcha_points() {
+  if (module_exists('ctools')) {
+    ctools_include('export');
+    $captcha_points = ctools_export_load_object('captcha_points', 'all');
+  }
+  else {
+    $captcha_points = array();
+    $result = db_query("SELECT * FROM {captcha_points} ORDER BY form_id");
+    while ($captcha_point = db_fetch_object($result)) {
+      $captcha_points[] = $captcha_point;
+    }
+  }
+  return $captcha_points;
+}
 /**
  * Helper function for generating a new CAPTCHA session.
  *
Index: captcha.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/captcha/captcha.install,v
retrieving revision 1.11.2.6
diff -u -b -u -p -r1.11.2.6 captcha.install
--- captcha.install	1 Dec 2010 00:14:58 -0000	1.11.2.6
+++ captcha.install	1 Dec 2010 00:36:53 -0000
@@ -13,6 +13,18 @@ function captcha_schema() {
   // Table for positions and types of the challenges.
   $schema['captcha_points'] = array(
     'description' => 'This table describes which challenges should be added to which forms.',
+    'export' => array(
+      'key' => 'form_id',
+      'identifier' => 'captcha',
+      'default hook' => 'captcha_default_points',  // Function hook name.
+      'status' => 'mark_status',
+      'api' => array(
+        'owner' => 'captcha',
+        'api' => 'captcha',  // Base name for api include files.
+        'minimum_version' => 1,
+        'current_version' => 1,
+      ),
+    ),
     'fields' => array(
       'form_id' => array(
         'description' => 'The form_id of the form to add a CAPTCHA to.',
@@ -136,17 +148,6 @@ function captcha_install() {
   $t = get_t();
   drupal_install_schema('captcha');
 
-  // insert some defaults
-  $form_ids = array(
-    'comment_form',
-    'contact_mail_user', 'contact_mail_page',
-    'user_register', 'user_pass', 'user_login', 'user_login_block',
-    'forum_node_form'
-  );
-  foreach ($form_ids as $form_id) {
-    db_query("INSERT INTO {captcha_points} (form_id, module, captcha_type) VALUES ('%s', NULL, NULL)", $form_id);
-  }
-
   // what to do after install?
   drupal_set_message($t('You can now <a href="!captcha_admin">configure the CAPTCHA module</a> for your site.',
     array('!captcha_admin' => url('admin/user/captcha'))), 'status');
Index: captcha.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/captcha/captcha.module,v
retrieving revision 1.103.2.13
diff -u -b -u -p -r1.103.2.13 captcha.module
--- captcha.module	1 Dec 2010 00:14:59 -0000	1.103.2.13
+++ captcha.module	1 Dec 2010 00:36:53 -0000
@@ -273,6 +273,49 @@ function captcha_process($element, $edit
   return $element;
 }
 
+/**
+ * Implementation of hook_captcha_default_points_alter().
+ *
+ * Provide some default captchas only if defaults are not already
+ * provided by other modules.
+ */
+function captcha_captcha_default_points_alter(&$items)  {
+  $modules = array(
+    'comment' => array(
+      'comment_form',
+    ),
+    'contact' => array(
+      'contact_mail_user',
+      'contact_mail_page',
+    ),
+    'forum' => array(
+      'forum_node_form',
+    ),
+    'user' => array(
+      'user_register',
+      'user_pass',
+      'user_login',
+      'user_login_block',
+    ),
+  );
+  foreach ($modules as $module => $form_ids) {
+    // Only give defaults if the module exists.
+    if (module_exists($module)) {
+      foreach ($form_ids as $form_id) {
+        // Ensure a default has not been provided already.
+        if (!isset($items[$form_id])) {
+          $captcha = new stdClass;
+          $captcha->disabled = FALSE;
+          $captcha->api_version = 1;
+          $captcha->form_id = $form_id;
+          $captcha->module = '';
+          $captcha->captcha_type = 'default';
+          $items[$form_id] = $captcha;
+        }
+      }
+    }
+  }
+}
 
 /**
  * Theme function for a CAPTCHA element.
