Index: flag.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/flag/Attic/flag.inc,v
retrieving revision 1.1.2.30.2.1
diff -u -p -r1.1.2.30.2.1 flag.inc
--- flag.inc	13 Sep 2009 22:26:42 -0000	1.1.2.30.2.1
+++ flag.inc	14 Sep 2009 11:38:57 -0000
@@ -156,6 +156,11 @@ class flag_flag {
    * Create a complete flag (except an FID) from an array definition.
    */
   function factory_by_array($config) {
+    // Unset the flag ID so it doesn't override existing flags.
+    // This might happen if flag was exported by CTools, as we don't have a
+    // chance to remove the FID from the exported code.
+    unset($config['fid']);
+
     $flag = flag_create_handler($config['content_type']);

     foreach ($config as $option => $value) {
@@ -237,23 +242,29 @@ class flag_flag {

   /**
    * Validates a flag settings
+   *
+   * @return
+   *   TRUE if flag settings are valid.
    */
   function validate() {
-    $this->validate_name();
+    return $this->validate_name();
   }

   function validate_name() {
     // Ensure a safe machine name.
     if (!preg_match('/^[a-z_][a-z0-9_]*$/', $this->name)) {
       form_set_error('name', t('The flag name may only contain lowercase letters, underscores, and numbers.'));
+      return FALSE;
     }
     // Ensure the machine name is unique.
     if (!isset($this->fid)) {
       $flag = flag_get_flag($this->name);
       if (!empty($flag)) {
         form_set_error('name', t('Flag names must be unique. This flag name is already in use.'));
+        return FALSE;
       }
     }
+    return TRUE;
   }

   /**
Index: flag.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/flag/Attic/flag.module,v
retrieving revision 1.11.2.72.2.2
diff -u -p -r1.11.2.72.2.2 flag.module
--- flag.module	13 Sep 2009 22:42:47 -0000	1.11.2.72.2.2
+++ flag.module	14 Sep 2009 11:38:58 -0000
@@ -58,6 +58,25 @@ function flag_menu() {
     'file' => 'includes/flag.admin.inc',
     'type' => MENU_LOCAL_TASK,
   );
+
+  $items['admin/build/flags/%flag/export'] = array(
+    'title' => 'Export',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('flag_export_flag', 3),
+    'access arguments' => array('administer flags'),
+    'type' => MENU_CALLBACK,
+    'file' => 'includes/flag.admin.inc',
+  );
+
+  $items['admin/build/flags/import'] = array(
+    'title' => 'Import',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('flag_import_flag'),
+    'access arguments' => array('administer flags'),
+    'type' => MENU_LOCAL_TASK,
+    'file' => 'includes/flag.admin.inc',
+  );
+
   $items['flag'] = array(
     'title' => 'Flag',
     'page callback' => 'flag_page',
@@ -428,6 +447,14 @@ function flag_node_type($op, $info) {
 }

 /**
+* Menu callback; Load a flag object.
+*/
+function flag_load($name) {
+  return flag_get_flag($name);
+}
+
+
+/**
  * Menu callback for (un)flagging a node.
  *
  * Used both for the regular callback as well as the JS version.
@@ -670,6 +697,19 @@ function flag_theme() {
 }

 /**
+ * Implementation of hook_features_api().
+ */
+function flag_features_api() {
+  return array(
+    'flag' => array(
+      'feature_source' => TRUE,
+      'default_hook' => 'flag_default_flags',
+      'file' => drupal_get_path('module', 'flag') .'/includes/flag.export.inc',
+    ),
+  );
+}
+
+/**
  * A preprocess function for our theme('flag'). It generates the
  * variables needed there.
  *
@@ -868,6 +933,7 @@ function flag_get_flag($name = NULL, $fi
       }
     }
   }
+  return FALSE;
 }

 /**
Index: includes/flag.admin.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/flag/includes/Attic/flag.admin.inc,v
retrieving revision 1.1.4.2
diff -u -p -r1.1.4.2 flag.admin.inc
--- includes/flag.admin.inc	17 Mar 2009 02:05:24 -0000	1.1.4.2
+++ includes/flag.admin.inc	14 Sep 2009 11:38:58 -0000
@@ -26,6 +26,7 @@ function theme_flag_admin_page($flags, $
     $ops = theme('links', array(
       'flags_edit' =>  array('title' => t('edit'), 'href' => "admin/build/flags/edit/". $flag->name),
       'flags_delete' =>  array('title' => t('delete'), 'href' => "admin/build/flags/delete/". $flag->name),
+      'flags_export' =>  array('title' => t('export'), 'href' => "admin/build/flags/". $flag->name ."/export"),
     ));

     $roles = array_flip(array_intersect(array_flip(user_roles()), $flag->roles));
@@ -53,6 +54,7 @@ function theme_flag_admin_page($flags, $
     if (!isset($flags[$name])) {
       $ops = theme('links', array(
         'flags_enable' =>  array('title' => t('enable'), 'href' => "admin/build/flags/edit/". $flag->name),
+        'flags_export' =>  array('title' => t('export'), 'href' => "admin/build/flags/". $flag->name ."/export"),
       ));

       $roles = array_flip(array_intersect(array_flip(user_roles()), $flag->roles));
@@ -444,3 +446,91 @@ function _flag_clear_cache() {
   // changed.
   menu_rebuild();
 }
+
+/**
+ * Import a flag form.
+ */
+function flag_import_flag() {
+  if (!module_exists('ctools')) {
+    $form['ctools'] = array('#value' => t('You must install the <a href="@ctools-drupal-project">CTools</a> module in order to import a flag.', array('@ctools-drupal-project' => url('http://drupal.org/project/ctools'))));
+  }
+  else {
+    $form['import'] = array(
+      '#title' => t('Import flag'),
+      '#type' => 'textarea',
+      '#default_value' => '',
+      '#rows' => 15,
+      '#required' => TRUE,
+    );
+    $form['submit'] = array(
+      '#value' => t('Import'),
+      '#type' => 'submit',
+    );
+  }
+
+  return $form;
+}
+
+/**
+ * Validate handler; Import a flag.
+ */
+function flag_import_flag_validate($form, &$form_state) {
+  ob_start();
+  eval($form_state['values']['import']);
+  ob_end_clean();
+  // Create the flag object.
+  foreach ($flags as $flag) {
+    $new_flag = flag_flag::factory_by_content_type($flag['content_type']);
+    foreach ($flag as $key => $value) {
+      $new_flag->{$key} = $value;
+    }
+    unset($new_flag->fid);
+    if ($new_flag->validate()) {
+      // save the new flag for the submit handler.
+      $form_state['storage']['flag'][] = $new_flag;
+    }
+  }
+}
+
+/**
+ * Submit handler; Import a flag.
+ */
+function flag_import_flag_submit($form, $form_state) {
+  foreach ($form_state['storage']['flag'] as $flag) {
+    // Prepare the flag to be saved.
+    foreach ($flag as $key => $value) {
+      $flag->{$key} = $value;
+    }
+    $flag->save();
+    if (!empty($flag->status)) {
+      $flag->enable();
+    }
+    drupal_set_message(t('Flag @name has been imported.', array('@name' => $flag->name)));
+  }
+  _flag_clear_cache();
+}
+
+
+/**
+* Export a flag and display it in a form.
+*/
+function flag_export_flag(&$form_state, $flag) {
+  module_load_include('inc', 'flag', '/includes/flag.export');
+
+  drupal_set_title(check_plain($flag->title));
+  $code = flag_export_flags(array($flag));
+
+  // Link to the features admin if module is present, or to the drupal project
+  // page.
+  $features_link = module_exists('features') ? url('admin/build/features') : url('http://drupal.org/project/features');
+
+  $form['export'] = array(
+    '#type' => 'textarea',
+    '#title' => t('Export flag'),
+    '#description' => t('Use the exported code to later <a href="@import-flag">import</a> it, or use the <a href="@features-drupal-project">Features</a> module to pack your flags in code.', array('@import-flag' => url('admin/build/flags/import'), '@features-drupal-project' => $features_link)),
+    '#value' => $code,
+    '#rows' => 15,
+  );
+
+  return $form;
+}
\ No newline at end of file
Index: includes/flag.export.inc
===================================================================
RCS file: includes/flag.export.inc
diff -N includes/flag.export.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ includes/flag.export.inc	14 Sep 2009 11:38:58 -0000
@@ -0,0 +1,140 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Provides export functionality and integrates with the features module.
+ */
+
+/**
+* Export a flag to code.
+*
+* @param $flag
+*   Array of flag objects.
+* @param $module
+*   Optional; The name of the module that will be created by features.
+*/
+function flag_export_flags($flags = array(), $module = '') {
+  if (!empty($flags[0]->name)) {
+    // We got here from a menu callback.
+    $flags = array($flags[0]->name);
+  }
+  $output = array();
+  $output = '$flags = array();'. "\n";
+  foreach ($flags as $flag) {
+    $flag = flag_get_flag($flag);
+    $new_flag = array();
+    foreach ($flag as $key => $value) {
+      $new_flag[$key] = $value;
+    }
+
+    if (!empty($module)) {
+      // Add the module name, so features will not mark an un-altered flag as
+      // overriden.
+      $new_flag['module'] = $module;
+      // Lock the flag name, as this is our connection to the features.
+      $new_flag['locked'] = array('name');
+
+    }
+    // Allow other modules to change the exported flag.
+    drupal_alter('flag_export', $new_flag);
+
+    // Remove the flag ID.
+    unset($new_flag['fid']);
+
+    $output .= '// Exported flag: '. check_plain($flag->title) .".\n";
+    $output .= '$flags[] = '. var_export($new_flag, TRUE). ";\n";
+  }
+  $output .= 'return $flags;';
+  return $output;
+}
+
+/**
+ * Implementation of hook_features_export().
+ */
+function flag_features_export($data, &$export, $module_name = '') {
+  $pipe = array();
+
+  // Add flag module as a dependency.
+  $export['dependencies']['features'] = 'flag';
+
+  // Ensure the modules that provide the flag are included as dependencies.
+  $modules = flag_features_providing_module();
+  foreach ($data as $key => $flag) {
+    // Get the module that provided the flag definition.
+    $flag = flag_get_flag($flag);
+    $module = $modules[$flag->content_type];
+    $export['dependencies'][$module] = $module;
+    $export['features']['flag'][$flag->name] = $flag->name;
+
+    // Add the content types related to the flag.
+    if (!empty($flag->types)) {
+      foreach ($flag->types as $type) {
+        // Add a pipe for dependencies.
+        $pipe[$flag->content_type][] = $type;
+      }
+    }
+  }
+
+  return $pipe;
+}
+
+/**
+ * Implementation of hook_features_export_options().
+ */
+function flag_features_export_options() {
+  $options = array();
+  // Get all flags.
+  foreach (flag_get_flags() as $name => $flag) {
+    $options[$name] = ucfirst(check_plain($flag->content_type)) .': '. check_plain($flag->title);
+  }
+  return $options;
+}
+
+/**
+ * Implementation of hook_features_export_render().
+ */
+function flag_features_export_render($module = 'foo', $data, $features_export) {
+  $code = flag_export_flags($data, $features_export['name']);
+  return array('flag_default_flags' => $code);
+}
+
+/**
+ * Implementation of hook_features_revert().
+ *
+ * @param $module
+ * name of module to revert content for
+ */
+function flag_features_revert($module = NULL) {
+  // Get default flags from features.
+  if (module_hook($module, 'flag_default_flags')) {
+    module_load_include('inc', 'flag', '/includes/flag.admin');
+    $default_flags = module_invoke($module, 'flag_default_flags');
+
+    // Delete flags that are defined in code
+    foreach ($default_flags as $default_flag) {
+      $current_flag = flag_get_flag($default_flag['name']);
+      $current_flag->delete();
+    }
+    _flag_clear_cache();
+  }
+  else {
+    drupal_set_message(t('Could not load default flag.'), 'error');
+    return FALSE;
+  }
+  return TRUE;
+}
+
+/**
+ * Helper function; Retrieve the providing modules defining the flags.
+ */
+function flag_features_providing_module() {
+  $modules = array();
+  $hook = 'flag_definitions';
+  foreach (module_implements($hook) as $module) {
+    foreach (module_invoke($module, $hook) as $key => $value) {
+      $modules[$key] = $module;
+    }
+  }
+  return $modules;
+}
\ No newline at end of file

