? feed_processors_feed_sometimes_empty_debug.patch
? feedapi_parse_pass_feed.patch
? feedapi_presets_as_content_types.patch
? feedapi_validate_pass_form.patch
? feedapi_validate_pass_form_and_feed.patch
Index: feedapi.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/feedapi/feedapi.install,v
retrieving revision 1.5
diff -u -r1.5 feedapi.install
--- feedapi.install	23 Jul 2007 15:37:01 -0000	1.5
+++ feedapi.install	1 Aug 2007 05:52:51 -0000
@@ -7,6 +7,7 @@
     case 'mysql':
       db_query("CREATE TABLE if not exists {feedapi} (
         fid int(10) unsigned NOT NULL auto_increment,
+        nid int(10) unsigned NOT NULL default '0',
         url varchar(255) NOT NULL default '',
         uid int NOT NULL default '0',
         feed_type varchar(50) NOT NULL default '',
@@ -15,11 +16,14 @@
         parsers varchar(255) NOT NULL default '',
         refresh int(10) NOT NULL default '0',
         checked int(10) NOT NULL default '0',
-        PRIMARY KEY(fid))");
+        settings LONGTEXT NOT NULL,
+        PRIMARY KEY(fid),
+        KEY `nid` (`nid`))");   // Todo: test.
       break;
     case 'pgsql':
       db_query("CREATE TABLE {feedapi} (
         fid SERIAL,
+        nid SERIAL,
         url varchar(255) NOT NULL default '',
         uid int NOT NULL default '0',
         feed_type varchar(50) NOT NULL default '',
@@ -28,7 +32,9 @@
         parsers varchar(255) NOT NULL default '',
         refresh integer NOT NULL,
         checked integer NOT NULL,
-        PRIMARY KEY(fid))");   
+        settings LONGTEXT NOT NULL,
+        PRIMARY KEY(fid),
+        KEY nid (nid))");   // Todo: test.
       break;
   }
 }
@@ -42,4 +48,25 @@
     case 'pgsql':
       break;
   }
+}
+
+function feedapi_update_1() {
+  switch ($GLOBALS['db_type']) {
+    case 'mysqli':
+    case 'mysql':
+      db_query("ALTER TABLE {feedapi} ADD nid INT( 10 ) UNSIGNED NOT NULL DEFAULT '0' AFTER fid");
+      db_query("ALTER TABLE {feedapi} ADD INDEX ( nid )");
+      break;
+      // Todo: pgsql.
+  }
+}
+
+function feedapi_update_2() {
+  switch ($GLOBALS['db_type']) {
+    case 'mysqli':
+    case 'mysql':
+      db_query("ALTER TABLE {feedapi} ADD settings LONGTEXT NOT NULL ;");
+      break;
+      // Todo: pgsql.
+  }
 }
\ No newline at end of file
Index: feedapi.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/feedapi/feedapi.module,v
retrieving revision 1.23.2.4
diff -u -r1.23.2.4 feedapi.module
--- feedapi.module	29 Jul 2007 15:35:39 -0000	1.23.2.4
+++ feedapi.module	1 Aug 2007 05:52:52 -0000
@@ -87,6 +87,58 @@
 }
 
 /**
+ * Implementation of hook_nodeapi().
+ */
+function feedapi_nodeapi(&$node, $op, $teaser, $page) {
+  if (isset($node->feed) || _feedapi_is_enabled($node->type)) {
+    switch ($op) {
+    case 'insert':
+      $node->feed->fid = db_next_id('{feedapi}_fid');
+      db_query("INSERT INTO {feedapi} (
+        fid, nid, url, feed_type, processors_item, processors_feed,
+        parsers, refresh, checked) VALUES
+        ('%s', '%s', '%s', '%s', '%s', %d, %d, %d, %d)", 
+        $node->feed->fid, // Todo: fid can be nid - remove fid.
+        $node->nid, 
+        $node->feed->url, 
+        $node->feed->feed_type, 
+        serialize($node->feed->processors_item),
+        serialize($node->feed->processors_feed), 
+        serialize($node->feed->parsers),
+        $node->feed->refresh, 
+        0 
+      );
+      _feedapi_store_settings(array('nid' => $node->nid), $node->feedapi);
+      break;
+    case 'update':
+      db_query("UPDATE {feedapi} SET 
+        url = '%s', feed_type = '%s', processors_item = '%s', processors_feed = '%s',
+        parsers = '%s', refresh = %d, checked =%d WHERE fid = %d AND nid = %d", 
+        $node->feed->url, 
+        $node->feed->feed_type, 
+        serialize($node->feed->processors_item),
+        serialize($node->feed->processors_feed), 
+        serialize($node->feed->parsers),
+        $node->feed->refresh, 
+        0,
+        $node->feed->fid, 
+        $node->nid
+      );
+      _feedapi_store_settings(array('nid' => $node->nid), $node->feedapi);
+      break;
+    case 'load':
+      $node->feed = db_fetch_object(db_query('SELECT * FROM {feedapi} WHERE nid = %d', $node->nid));
+      break;
+    case 'delete':
+      // Could be a performance problem - think of thousands of node feed items.
+      feedapi_invoke_feedapi('purge', $node->feed);
+      db_query("DELETE FROM {feedapi} WHERE nid = %d", $node->nid);
+      break;
+    }
+  }
+}
+
+/**
  * Implementation of hook_perm().
  */
 function feedapi_perm() {
@@ -230,7 +282,7 @@
         }
       }
       // Delete feed from the processors
-      foreach($feed->processors_feed as $processor) {
+      foreach ($feed->processors_feed as $processor) {
         module_invoke($processor, 'feedapi_delete', $feed);
       }
       // Delete core data
@@ -239,38 +291,6 @@
       drupal_goto("admin/content/feed");
       break;
       
-    case 'save':
-      db_query("INSERT INTO {feedapi} (
-        url, feed_type, processors_item, processors_feed,
-        parsers, refresh, checked, uid) VALUES
-        ('%s', '%s', '%s', '%s', '%s', %d, %d, %d)", 
-        $feed->url, $feed->feed_type, serialize($feed->processors_item),
-        serialize($feed->processors_feed), serialize($feed->parsers),
-        $feed->refresh, 0, // Means that the feed have never been refreshed yet
-        $user->uid
-      );
-      $feed->fid = db_result(db_query("SELECT fid FROM {feedapi} WHERE url = '%s'", $feed->url));
-      // Parse the feed with the parsers
-      $title = $feed->title;
-      $description = $feed->description;
-      $feed = _feedapi_call_parsers($feed, $feed->parsers);
-      // If the user provided a title and a description, drop the parsers' extracted
-      $feed->title = !empty($title) ? $title : $feed->title;
-      $feed->description = !empty($description) ? $description : $feed->description;
-      foreach ($feed->processors_feed as $processor) {
-        $feed = module_invoke($processor, 'feedapi_save', $feed);
-      }
-      module_invoke_all('feedapi_after_save', $feed);
-      drupal_set_message(t('The %feed feed (%url) was saved successfully.', array('%feed' => $feed->title, '%url' => $feed->url)));
-      // Tell the user if the feed is currently not usable
-      if (strlen($feed->feed_type) < 1
-          || !module_exists($feed->parsers['primary']) 
-          || !module_exists($feed->processors_feed[0]) 
-          || !module_exists($feed->processors_item[0])) {
-        drupal_set_message(t('The feed is not usable now, because there is no suitable processors and parser in the system'));
-      }
-      break;
-      
     case 'update':
       // Remove the feed and the items from the disabled processors
       $old_config = new stdClass();
@@ -325,6 +345,217 @@
 }
 
 /**
+ * Implementation of hook_form_alter().
+ */
+function feedapi_form_alter($form_id, &$form) {
+  // Content type form.
+  if ($form_id == 'node_type_form' && isset($form['identity']['type'])) {
+    if (isset($form['#post']['feedapi'])) {
+      // TODO: Drupal automatically stores mutilated 'feedapi_'. $form['#node_type']->type - remove.
+      // TODO: Do better validation
+      _feedapi_store_settings(array('node_type' => $form['#node_type']->type), $form['#post']['feedapi']);
+    }
+    if (!$settings = _feedapi_get_settings(array('node_type' => $form['#node_type']->type))) {
+      $settings = array();
+    }
+    // drupal_set_message(dprint_r($settings, TRUE));
+    $form['feedapi'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Feed API'),
+      '#collapsible' => TRUE,
+      '#collapsed' => !$settings['enabled'],
+      '#tree' => TRUE,
+      );
+    $form['feedapi']['enabled'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Is a feed content type'),
+      '#description' => t('Check this box if you want to use this content type for downloading feeds to your site.'),
+      '#default_value' => $settings['enabled'],
+      '#weight' => -15,
+      );
+    $form['feedapi']['parsers'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Parser settings'),
+      '#description' => t('Parsers create an object ready for processing from a feed, choose at least one.'),
+      '#collapsible' => FALSE,
+      '#tree' => TRUE,
+      );
+    $parsers = _feedapi_suitable_parsers('', TRUE);
+    rsort($parsers);
+    foreach ($parsers as $parser) {
+      $form['feedapi']['parsers'][$parser] = array(
+        '#type' => 'fieldset',
+        '#title' => t($parser), // TODO: get natural name
+        '#collapsible' => TRUE,
+        '#collapsed' => !($settings['parsers'][$parser]['enabled'] || (count($parsers) == 1)),
+        '#tree' => TRUE,
+        '#weight' => $settings['parsers'][$parser]['weight'], 
+      );
+      $form['feedapi']['parsers'][$parser]['enabled'] = array(
+        '#type' => 'checkbox',
+        '#title' => t('Enable'),
+        '#description' => t('Check this box if you want to enable the @name parser on this feed.', array('@name' => t($parser))),
+        '#default_value' => $settings['parsers'][$parser]['enabled'] || (count($parsers) == 1),
+        '#weight' => -15,
+        );
+      for ($j = -15; $j <= 15; $j++) { 
+        $options[$j] = $j;
+      }
+      $form['feedapi']['parsers'][$parser]['weight'] = array(
+        '#type' => 'select',
+        '#title' => t('Weight'),
+        '#description' => t('Control the execution order. Parsers with lower weights come before parsers with higher weights.'),
+        '#options' => $options,
+        '#default_value' => $settings['parsers'][$parser]['weight'],
+        '#weight' => -14,
+        );
+    }
+    $form['feedapi']['processors'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Processor settings'),
+      '#description' => t('Processors are any kind of add on modules that hook into the feed handling process on download time - you can decide here what should happen to feed items once they are downloaded and parsed.'),
+      '#collapsible' => FALSE,
+      '#tree' => TRUE,
+      );
+    $processors = _feedapi_suitable_item_processors('', TRUE);
+    rsort($processors);
+    foreach ($processors as $processor) {
+      $form['feedapi']['processors'][$processor] = array(
+        '#type' => 'fieldset',
+        '#title' => t($processor), // TODO: get natural name
+        '#collapsible' => TRUE,
+        '#collapsed' => !($settings['processors'][$processor]['enabled'] || (count($processors) == 1)),
+        '#tree' => TRUE,
+        '#weight' => $settings['processors'][$processor]['weight'],
+      );
+      $form['feedapi']['processors'][$processor]['enabled'] = array(
+        '#type' => 'checkbox',
+        '#title' => t('Enable'),
+        '#description' => t('Check this box if you want to enable the @name processor on this feed.', array('@name' => t($processor))),
+        '#default_value' => $settings['processors'][$processor]['enabled'],
+        '#weight' => -15,
+        );
+      for ($j = -15; $j <= 15; $j++) { 
+        $options[$j] = $j;
+      }
+      $form['feedapi']['processors'][$processor]['weight'] = array(
+        '#type' => 'select',
+        '#title' => t('Weight'),
+        '#description' => t('Control the execution order. Processors with lower weights come before processors with higher weights.'),
+        '#options' => $options,
+        '#default_value' => $settings['processors'][$processor]['weight'],
+        '#weight' => -14,
+        );
+    }
+    $form['feedapi'] = array_merge_recursive($form['feedapi'], _feedapi_invoke_settings_form(array('node_type' => $form['#node_type']->type)));
+  }
+  
+  // FeedAPI-enabled node form.
+  if ($form['type']['#value'] .'_node_form' == $form_id && _feedapi_is_enabled($form['type']['#value'])) {
+    
+    // Modify form - add feedapi form snippet in submit-and-edit and edit mode...
+    if (isset($form['#node']->nid) || $form['#post']['op']) {
+      $form['feedapi'] = array(
+        '#type' => 'fieldset',
+        '#title' => t('Feed API'),
+        '#collapsible' => TRUE,
+        '#collapsed' => FALSE,
+        '#tree' => TRUE,
+        );
+      $form['feedapi']['feedapi_url'] = array(
+        '#type' => 'textfield',
+        '#title' => t('Feed URL'),
+        '#description' => t('Enter feed URL.'),
+        '#default_value' => $form['#node']->feed->url ? $form['#node']->feed->url : $form['#post']['feedapi_url'],
+        );
+      // Retrieve form snippets from add on modules. 
+      // Todo: only let users with "edit own feed settings" permission or "administer feeds" permission meddle with these per-node settings.
+      $form_snippets = _feedapi_invoke_settings_form(array('node_type' => $form['type']['#value'], 'nid' => $form['#node']->nid));
+      // Format snippets - make fieldsets out of them.
+      foreach ($form_snippets as $k => $stage) {
+        $form_snippets[$k]['#type'] = 'fieldset';
+        $form_snippets[$k]['#title'] = t($k); // Todo: human readable name, retrievable by module name.
+        $form_snippets[$k]['#collapsible'] = TRUE;
+        $form_snippets[$k]['#collapsed'] = TRUE;
+        $form_snippets[$k]['#tree'] = TRUE;
+        foreach ($stage as $m => $addon) {
+          $form_snippets[$k][$m]['#type'] = 'fieldset';
+          $form_snippets[$k][$m]['#title'] = t($m); // Todo: human readable name, retrievable by module name.
+          $form_snippets[$k][$m]['#collapsible'] = TRUE;
+          $form_snippets[$k][$m]['#collapsed'] = FALSE;
+          $form_snippets[$k][$m]['#tree'] = TRUE;
+        }
+      }
+      $form_snippets['#tree'] = TRUE;
+      $form['feedapi'] = array_merge_recursive($form['feedapi'], $form_snippets);
+    }
+    // ... or wipe form and replace it by a short form in add mode.
+    else {
+      foreach ($form as $k => $v) {
+        if (strpos($k, '#') !== 0) {
+          unset($form[$k]);
+        }
+      }
+      $form['feedapi']['feedapi_url'] = array(
+        '#type' => 'textfield',
+        '#title' => t('Feed URL'),
+        '#description' => t('Enter feed URL.'),
+        );
+      $form['feedapi']['next'] = array(
+        '#type' => 'button',
+        '#value' => t('Submit and edit'),
+        );
+      $form['feedapi']['submit'] = array(
+        '#type' => 'button',
+        '#value' => t('Submit'),
+        );
+    }
+    
+    // Process posted URL from short form.
+    // Todo: see, how we can move this into hook_nodeapi('submit', ...).
+    if (count($form['#post']) && !isset($form['#node']->nid)) {
+      if (!$form['#post']['feedapi_url']) {
+        form_set_error('feedapi_url', t('Enter a URL'));
+      }
+      else if (in_array($form['#post']['op'], array(t('Submit'), t('Submit and edit'))) ) {
+        // Try to pull title and description directly from feed.
+        // Todo: pull icons and logos in add on module.
+        $settings = _feedapi_get_settings(array('node_type' => $form['type']['#value']));
+        foreach ($settings['parsers'] as $parser => $property) {
+          if ($property['enabled']) { 
+            // Call first parser 
+            // Todo: use lightest first - use weight instead of primary-secondary concept?
+            // Todo: This step downloads and parses entire feed - feed item modules should
+            // provide options to create items right away.
+            $feed = new stdClass();
+            $feed->url = $form['#post']['feedapi_url'];
+            $feed->processors_feed = array(); // Todo: store feed processors per feed.
+            $feed->processors_item = array(); // Todo: store feed item processors per feed.
+            if (!$feed = _feedapi_call_parsers($feed, array('primary' => $parser, 'secondary' => array()))) {
+              form_set_error('feedapi', t('Error parsing feed.'));
+            }
+            break;
+          }
+        }
+        if (!$feed->title) {  
+          form_set_error('feedapi_url', t('Feed information could not be retrieved.'));  
+        }
+        else {
+          $node = _feedapi_create_node($feed, $form['type']['#value']);
+          if ($form['#post']['op'] == t('Submit')) {
+            drupal_goto('node/'. $node->nid);
+          }
+          else if ($form['#post']['op'] == t('Submit and edit')) {
+            drupal_goto('node/'. $node->nid .'/edit');
+          }
+        }
+        
+      }
+    }
+  }
+}
+
+/**
  * Implementation of hook_cron().
  */
 function feedapi_cron() {
@@ -486,7 +717,6 @@
   $feed->processors_feed = array_values($form_values['processors_feed']);
   $feed = (object) array_merge($form_values, (array) $feed);
   feedapi_invoke_feedapi("update", $feed);
-  drupal_goto('admin/content/feed');
 }
 
 /**
@@ -722,6 +952,174 @@
 }
 
 /**
+ * Create a node of a given type from a given feed.
+ */
+function _feedapi_create_node(&$feed, $type) {
+  $node = new stdClass();
+  $node->type = $type;
+  
+  // Todo: user default options
+  $node->status = 1;
+  $node->promote = 0;
+  $node->sticky = 0;
+  
+  global $user;
+  $node->uid = $user->uid;
+  $node->title = $feed->title;
+  $node->created = time();
+  $node->body = $feed->description;
+  $node->feed = $feed;
+  node_save($node);
+  
+  return $node;
+}
+
+/**
+ * Stores settings per content type or per node.
+ */
+function _feedapi_store_settings($args, $settings) {
+  if ($args['nid']) {
+    // Filter - only processors and parsers settings will be stored.
+    $store_settings = array();
+    if ($settings['processors']) {
+      $store_settings['processors'] = $settings['processors'];
+    }
+    if ($settings['parsers']) {
+      $store_settings['parsers'] = $settings['parsers'];
+    }
+    db_query("UPDATE {feedapi} SET settings = '%s' WHERE nid = %d", serialize($store_settings), $args['nid']);
+  }
+  elseif ($args['node_type']) {
+    variable_set('feedapi_settings_'. $args['node_type'], $settings);
+  }
+  else {
+    drupal_set_message(t('Error: wrong _feedapi_store_settings arguments.'));
+  }
+}
+
+/**
+ * Returns TRUE if feedapi is enabled for given node type.
+ */
+function _feedapi_is_enabled($node_type) {
+  if (_feedapi_get_settings(array('node_type' => $node_type))) { 
+    return TRUE; 
+  }
+  return FALSE;
+}
+
+/**
+ * Retrieve settings per content type or per node.
+ * $args = array(
+ *     'node_type' => '<type>',
+ *     'nid' => <id>,
+ *   )
+ * Todo: add caching. Watch out: cache permutations of node_type or node_type+nid or nid seperately.
+ */
+function _feedapi_get_settings($args) {
+  if (isset($args['nid'])) {
+    if ($settings = db_fetch_object(db_query('SELECT settings FROM {feedapi} WHERE nid = %d', $args['nid']))) {
+      if ($settings = unserialize($settings->settings)) {
+        return $settings;
+      }
+    }
+  }
+  // Fallback: node_type.
+  if (isset($args['node_type'])) {
+    if ($settings = variable_get('feedapi_settings_'. $args['node_type'], FALSE)) {
+      return $settings;
+    }
+  }
+  return FALSE;
+}
+
+/**
+ * Set default value of $form elements if present in $settings.
+ */
+function _feedapi_populate($form, $settings) {
+  static $i;
+  $i++;
+  foreach ($form as $k => $v) {
+    if (is_array($v)) {
+      if (array_key_exists('#default_value', $v)) {
+        if (isset($settings[$k])) {
+          $form[$k]['#default_value'] = $settings[$k];
+        }
+      }
+      else if (!array_key_exists('#type', $v)){
+        $form[$k] = _feedapi_populate($form[$k], $settings[$k]);
+      }
+    }
+  }
+  $i--;
+  return $form;
+}
+
+/**
+ * Invokes feedapi_settings_form hook.
+ * $args = array(
+ *     'node_type' => '<type>',
+ *     'nid' => <id>,
+ *   )
+ */
+function _feedapi_invoke_settings_form($args) {
+  $form = array();
+  if (isset($args['nid']) && isset($args['node_type'])) {
+    // 1) Get settings for corresponding content type
+    //    Which parsers / processors are enabled is a per content-type setting.
+    if ($settings = _feedapi_get_settings(array('node_type' => $args['node_type']))) {
+      // 2) retrieve forms.
+      foreach(_feedapi_suitable_parsers('', TRUE) as $module) {
+        if ($settings['parsers'][$module]['enabled']) {
+          $result = array();  
+          $result = module_invoke($module, 'feedapi_settings_form', 'parsers');
+          if (is_array($result)) {
+            $form['parsers'][$module] = $result;
+          }
+        }
+      }
+      foreach(_feedapi_suitable_item_processors('', TRUE) as $module) {
+        if ($settings['processors'][$module]['enabled']) {
+          $result = array();
+          $result = module_invoke($module, 'feedapi_settings_form', 'processors');
+          if (is_array($result)) {
+            $form['processors'][$module] = $result;
+          }
+        }
+      }
+      // Todo: if we keep feed processors we need to call feed processors here, too.
+      
+      // 3. now get per node settings and populate form.
+      if ($settings = _feedapi_get_settings($args)) {
+        $form = _feedapi_populate($form, $settings);
+      }
+    }
+    else {
+      // DEBUG output - can be removed upon release.
+      drupal_set_message(t('Feedapi is not enabled for this content type'));
+    }
+  }
+  else if (isset($args['node_type'])) {
+    foreach(_feedapi_suitable_parsers('', TRUE) as $module) {
+      $result = array();  
+      $result = module_invoke($module, 'feedapi_settings_form', 'parsers');
+      if (is_array($result)) {
+        $form['parsers'][$module] = $result;
+      }
+    }
+    foreach(_feedapi_suitable_item_processors('', TRUE) as $module) {
+      $result = array();
+      $result = module_invoke($module, 'feedapi_settings_form', 'processors');
+      if (is_array($result)) {
+        $form['processors'][$module] = $result;
+      }
+    }
+    if ($settings = _feedapi_get_settings($args)) {
+      $form = _feedapi_populate($form, $settings);
+    }
+  }
+  return $form;
+}
+/**
  * Auto-detect one possible parser and one feed and item processor to the given URL
  * It follows the order of the modules from the module's settings page
  *
Index: feedapi_item/feedapi_item.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/feedapi/feedapi_item/feedapi_item.module,v
retrieving revision 1.12.2.1
diff -u -r1.12.2.1 feedapi_item.module
--- feedapi_item/feedapi_item.module	26 Jul 2007 09:25:01 -0000	1.12.2.1
+++ feedapi_item/feedapi_item.module	1 Aug 2007 05:52:52 -0000
@@ -37,12 +37,14 @@
  * Implementation of hook_menu().
  */
 function feedapi_item_nodeapi(&$node, $op, $teaser, $page) {
-  if ($op == 'delete') {
+  switch ($op) {
+  case 'delete':
     $result = db_query("SELECT fiid FROM {feedapi_node_item} WHERE nid = %d", $node->nid);
     if (db_num_rows($result) > 0) {
       $feed = db_fetch_object($result);
       feedapi_item_feedapi_item_delete($feed);
     }
+    break;
   }
 }
 
@@ -74,20 +76,6 @@
  * Implements hook_form_alter().
  */
 function feedapi_item_form_alter($form_id, &$form) {
-  // Extend the content-type form
-  if ($form_id == 'node_type_form') {
-    $node_type = $form['old_type']['#value'];
-    $form['workflow']['feedapi_item'] = array(
-      '#type' => 'fieldset',
-      '#title' => t('Node-Feed item processor settings'),
-    );
-    $form['workflow']['feedapi_item']['feedapi_item_promote'] = array(
-      '#type' => 'textfield',
-      '#title' => t('Promoted items'),
-      '#description' => t('The newest N items will be promoted on the front page per feed'),
-      '#default_value' => variable_get('feedapi_item_promote_'. $node_type, 15),
-    );
-  }
   // Extend the feed editing form
   if ($form_id == 'feedapi_edit_page') {
     $feed = new stdClass();
@@ -126,6 +114,39 @@
 }
 
 /**
+ * Implementation of hook_feedapi_settings_form().
+ * If a module provides parsers and processors it MUST evaluate the $type variable
+ * to return different forms for parsers and processors.
+ * There might be a better term for parsers and processors than $type.
+ */
+function feedapi_item_feedapi_settings_form($type) { 
+  switch ($type) {
+  case 'processors':
+    $form['content_type'] = array(
+      '#type' => 'select',
+      '#title' => t('The content-type of the items'),
+      '#default_value' => 'story',
+      '#options' => drupal_map_assoc(array_keys(node_get_types())),
+      '#description' => t('All of the items related to this feed will be created with this type.'),
+    );
+    $form['node_date'] = array(
+      '#type' => 'radios',
+      '#title' => t('Date of item nodes'),
+      '#options' => array('feed' => t('Retrieve from feed'), 'current' => t('Use time of download')),
+      '#default_value' => 'feed',
+    );
+    $form['promote'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Promoted items'),
+      '#description' => t('The newest N items will be promoted on the front page per feed'),
+      '#default_value' => 3,
+    );
+    break;
+  }
+  return $form;
+}
+
+/**
  * Tell which feed types are compatible with this submodule.
  * For eg. "XML feed", "FTP", "mailing list"
  * Implementation of hook_feedapi_type().
Index: parser_common_syndication/parser_common_syndication.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/feedapi/parser_common_syndication/parser_common_syndication.module,v
retrieving revision 1.6
diff -u -r1.6 parser_common_syndication.module
--- parser_common_syndication/parser_common_syndication.module	23 Jul 2007 17:27:08 -0000	1.6
+++ parser_common_syndication/parser_common_syndication.module	1 Aug 2007 05:52:52 -0000
@@ -490,4 +490,18 @@
     $parsed_source->items[] = $item;
   }
   return $parsed_source;
+}
+
+/**
+ * Implementation of hook_feedapi_settings_form().
+ * Only for testing.
+ */
+function parser_common_syndication_feedapi_settings_form() {
+  $form['tester'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Test'),
+    '#description' => t('Test setting'),
+    '#default_value' => 3,
+  );
+  return $form;
 }
\ No newline at end of file
Index: parser_simplepie/parser_simplepie.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/feedapi/parser_simplepie/parser_simplepie.module,v
retrieving revision 1.6.2.1
diff -u -r1.6.2.1 parser_simplepie.module
--- parser_simplepie/parser_simplepie.module	29 Jul 2007 15:35:39 -0000	1.6.2.1
+++ parser_simplepie/parser_simplepie.module	1 Aug 2007 05:52:52 -0000
@@ -101,3 +101,17 @@
   }
   return $parsed_source;
 }
+
+/**
+ * Implementation of hook_feedapi_settings_form().
+ * Only for testing.
+ */
+function parser_simplepie_feedapi_settings_form() {
+  $form['test'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Test'),
+    '#description' => t('Test setting'),
+    '#default_value' => 3,
+  );
+  return $form;
+}
\ No newline at end of file
