Index: feedapi.admin.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/feedapi/Attic/feedapi.admin.inc,v
retrieving revision 1.1.2.1
diff -u -p -r1.1.2.1 feedapi.admin.inc
--- feedapi.admin.inc	17 Feb 2009 14:58:40 -0000	1.1.2.1
+++ feedapi.admin.inc	17 Feb 2009 16:03:39 -0000
@@ -10,6 +10,8 @@
  * Provide a UI for overviewing the existing feeds
  */
 function feedapi_admin_overview() {
+  module_load_include('inc', 'feedapi', 'feedapi');
+  
   $header = array(
     t('Title'),
     t('Last refresh'),
Index: feedapi.inc
===================================================================
RCS file: feedapi.inc
diff -N feedapi.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ feedapi.inc	17 Feb 2009 16:03:40 -0000
@@ -0,0 +1,385 @@
+<?php
+
+/**
+ * @file
+ * Feed-processing related parts of FeedAPI
+ */
+
+/**
+ * Insert feedapi data to the DB when it's a new for for FeedAPI
+ */
+function _feedapi_insert(&$node, $teaser, $page) {
+  if (isset($node->feed->url) && isset($node->feed->feed_type)) {
+    db_query("INSERT INTO {feedapi} (
+            nid, url, link, feed_type, processors,
+            parsers, checked, settings) VALUES
+            (%d, '%s', '%s', '%s', '%s', '%s', %d, '%s')",
+      $node->nid,
+      $node->feed->url,
+      $node->feed->options->link,
+      $node->feed->feed_type,
+      serialize($node->feed->processors),
+      serialize($node->feed->parsers),
+      0,
+      serialize(array())
+    );
+    // Store add on module's settings if user has permission to do so.
+    if (user_access('advanced feedapi options')) {
+      _feedapi_store_settings(array('nid' => $node->nid), $node->feedapi);
+    }
+    // Refresh feed if the user would like to do that
+    $settings = feedapi_get_settings($node->type, $node->nid);
+    if ($settings['refresh_on_create'] == TRUE) {
+      $node->feed->nid = $node->nid;
+      $node->feed->settings = $settings;
+      feedapi_invoke('refresh', $node->feed);
+    }
+  }
+}
+
+/**
+ * Update feed data of an existing feed
+ */
+function _feedapi_update(&$node, $teaser, $page) {
+  if (isset($node->feed)) {
+    $old_config = node_load($node->nid);
+    // In that case this feed has never have feed data. Should be created then, this is not really an update
+    if (!is_numeric($old_config->feed->nid)) {
+      $node->feed = _feedapi_build_feed_object($node->type, $node->feed->url);
+      _feedapi_insert($node, 'insert', $teaser, $page);
+      return;
+    }
+    db_query("UPDATE {feedapi} SET
+            url = '%s', feed_type = '%s', processors = '%s',
+            parsers = '%s', link = '%s' WHERE nid = %d",
+      isset($node->feed->url) ? $node->feed->url : $node->feedapi['feedapi_url'],
+      isset($node->feed->feed_type) ? $node->feed->feed_type : '',
+      isset($node->feed->processors) ? serialize($node->feed->processors) : serialize($old_config->feed->processors),
+      isset($node->feed->parsers) ? serialize($node->feed->parsers) : serialize($old_config->feed->parsers),
+      $node->feed->options->link,
+      $node->nid
+    );
+    // Store add on module's settings if user has permission to do so.
+    if (user_access('advanced feedapi options')) {
+      _feedapi_store_settings(array('nid' => $node->nid), $node->feedapi);
+    }
+  }
+}
+
+/**
+ * Execute the enabled parsers and create an unified output
+ *
+ * @param $feed
+ *  Feed object
+ * @param $parsers
+ *  Structure: array(
+ *    "primary" => "parser_primary",
+ *    "secondary" => array("parser1", "parser2", "parserN")
+ *  );
+ * @return
+ *  The object of the parser data
+ */
+function _feedapi_call_parsers($feed, $parsers, $settings) {
+  $nid = isset($feed->nid) ? $feed->nid : '';
+  $parser_primary = array_shift($parsers);
+  $parsers_secondary = $parsers;
+  if (module_exists($parser_primary)) {
+    $feed->feed_type =  module_invoke($parser_primary, 'feedapi_feed', 'compatible', $feed, $settings[$parser_primary]);
+    $parser_output =  module_invoke($parser_primary, 'feedapi_feed', 'parse', $feed, $settings[$parser_primary]);
+    if ($parser_output === FALSE) {
+      return $parser_output;
+    }
+    $feed = (object) array_merge((array) $feed, (array) $parser_output);
+  }
+  // Call the turned on parsers, create a union of returned options
+  $parsers_secondary = is_array($parsers_secondary) ? $parsers_secondary : array();
+  foreach ($parsers_secondary as $parser) {
+    $feed_ext = module_invoke($parser, 'feedapi_feed', 'parse', $feed, FALSE);
+    $feed->options = (object) ((array) $feed->options + (array) $feed_ext->options);
+    // Merge items' options
+    if (is_array($feed_ext->items)) {
+      foreach ($feed_ext->items as $key => $item) {
+        $feed->items[$key]->options = (object) ((array) $feed->items[$key]->options + (array) $item->options);
+      }
+    }
+  }
+  $feed->nid = $nid;
+  foreach (module_implements('feedapi_after_parse') as $module) {
+    $func = $module .'_feedapi_after_parse';
+    $func($feed);
+  }
+  // Filter bad or not allowed tags, sanitize data (currently timestamp checking)
+  if (!variable_get('feedapi_allow_html_all', FALSE)) {
+    $allowed = preg_split('/\s+|<|>/', variable_get('feedapi_allowed_html_tags', '<a> <b> <br> <dd> <dl> <dt> <em> <i> <li> <ol> <p> <strong> <u> <ul>'), -1, PREG_SPLIT_NO_EMPTY);
+    foreach (array('title', 'description') as $property) {
+      if (isset($feed->{$property})) {
+        if (is_string($feed->{$property})) {
+          $feed->{$property} = _feedapi_process_text($feed->{$property}, $allowed);
+        }
+      }
+    }
+    for ($i = 0; $i < count($feed->items); $i++) {
+      $feed->items[$i]->title = _feedapi_process_text($feed->items[$i]->title, array());
+      $feed->items[$i]->description = _feedapi_process_text($feed->items[$i]->description, $allowed);
+      if ($feed->items[$i]->options->timestamp == 0) {
+        $feed->items[$i]->options->timestamp = time();
+      }
+    }
+  }
+  return $feed;
+}
+
+/**
+ * Builds feed object ready to be sticked onto node.
+ */
+function _feedapi_build_feed_object($node_type, $url) {
+  $feed = new stdClass();
+  $feed->url = $url;
+  $node_type_settings = feedapi_get_settings($node_type);
+  $feed->processors = _feedapi_format_settings($node_type_settings, 'processors');
+  $feed->parsers = _feedapi_format_settings($node_type_settings, 'parsers');
+  if (isset($feed->url)) {
+    $feed = _feedapi_call_parsers($feed, $feed->parsers, $node_type_settings['parsers']);
+  }
+  $feed->link = isset($feed->options->link) ? $feed->options->link : '';
+  return $feed;
+}
+
+/**
+ * Helper function for feedapi_invoke().
+ * Delete all feed items of a feed.
+ */
+function _feedapi_invoke_purge(&$feed, $param) {
+  $node = node_load($feed->nid);
+  
+  if ($param == 'items') {
+    return drupal_get_form('feedapi_purge_confirm', $node);
+  }
+
+  // Delete items from the processors
+  foreach ($feed->processors as $processor) {
+    // FIXME: it's possible now to accidentally delete an item from another processor
+    module_invoke($processor, 'feedapi_item', 'purge', $feed);
+  }
+  // Reset hash.
+  db_query("UPDATE {feedapi} SET hash = 0 WHERE nid = %d", $feed->nid);
+}
+
+/**
+ * Helper function for feedapi_invoke().
+ * Refresh the feed, call the proper parsers and processors' hooks.
+ * Don't call this function directly, use feedapi_refresh() instead.
+ * 
+ * @ TODO Fix: This may loop forever when a feed has no processors
+ */
+function _feedapi_invoke_refresh(&$feed, $param) {
+  $timestamp = variable_get('cron_semaphore', FALSE) !== FALSE ? variable_get('cron_semaphore', FALSE) : time();
+  
+  $counter = array();
+  timer_start('feedapi_'. $feed->nid);
+  $cron = $param;
+  
+  // Step 0: Check processors and grab settings
+  if (!is_array($feed->processors) || count($feed->processors) == 0) {
+    if (!$cron) {
+      drupal_set_message(t("No processors specified for URL %url. Could not refresh.", array('%url' => $feed->url)), "error");
+      drupal_goto('node/'. $feed->nid);
+    }
+    return 0;
+  }
+  $settings = feedapi_get_settings(NULL, $feed->nid);
+  
+  // Step 1: Force processors to delete old items and determine the max. create elements.
+  $counter['expired'] = feedapi_expire($feed);
+
+  // Step 2: Get feed.
+  $nid = $feed->nid;
+  $hash_old = $feed->hash;
+  $feed = _feedapi_call_parsers($feed, $feed->parsers, $settings['parsers']);
+  if (is_object($feed)) {
+    $feed->hash = md5(serialize($feed->items));
+  }
+  
+  // Step 3: See, whether feed has been modified.
+  if ($feed === FALSE || $hash_old == $feed->hash) {
+    // Updated the checked field in any case.
+    db_query("UPDATE {feedapi} SET checked = %d, half_done = %d WHERE nid = %d", time(), FALSE, $nid);
+    if (!$cron) {
+      if ($hash_old == $feed->hash && is_object($feed)) {
+        drupal_set_message(t('There are no new items in the feed.'), 'status');
+      }
+      else {
+        drupal_set_message(t('Could not refresh feed.'), 'error');
+      }
+    }
+    return $counter;
+  }
+
+  // Step 4: Walk through the items and check duplicates, then save or update
+  $items = $feed->items;
+  $updated = 0;
+  $new = 0;
+  $half_done = FALSE;
+
+  // We check for time-out after each item
+  foreach ($items as $index => $item) {
+    // Call each item parser.
+    $item->is_updated = FALSE;
+    $item->is_new = FALSE;
+    foreach ($feed->processors as $processor) {
+      if (!module_invoke($processor, 'feedapi_item', 'unique', $item, $feed->nid, $settings['processors'][$processor])) {
+        if ($settings['update_existing'] == TRUE) {
+          module_invoke($processor, 'feedapi_item', 'update', $item, $feed->nid, $settings['processors'][$processor]);
+          $item->is_updated = TRUE;
+        }
+      }
+      else {
+        // We have checked before for expired items, so just save it.
+        // if the item is already expired then do nothing
+        $items_delete = $settings['items_delete'];
+        $diff = abs(time() - (isset($item->options->timestamp) ? $item->options->timestamp : time()));
+        if ($diff > $items_delete && ($items_delete > FEEDAPI_NEVER_DELETE_OLD)) {
+          break;
+        }
+        $result = module_invoke($processor, 'feedapi_item', 'save', $item, $feed->nid, $settings['processors'][$processor]);
+        if ($result !== FALSE) {
+          $item->is_new = TRUE;
+        }
+      }
+    }
+    $new = $item->is_new ? $new + 1 : $new;
+    $updated = ($item->is_updated && !$item->is_new) ? $updated + 1 : $updated;
+    
+    // Decision on time. If the exec time is greather than the user-set percentage of php max execution time
+    if ($cron && !feedapi_cron_time()) {
+      $half_done = ($new + $updated) == count($items) ? FALSE : TRUE;
+      break;
+    }
+    // Save the item status for further processing
+    $feed->items[$index] = $item;
+  }
+  
+  // Closing step: Call after refresh and update feed statistics
+  foreach (module_implements('feedapi_after_refresh') as $module) {
+    $func = $module .'_feedapi_after_refresh';
+    $func($feed);
+  }
+  if ($new > 0) {
+    _feedapi_store_stat($nid, 'update_times', time(), $timestamp);
+    _feedapi_store_stat($nid, 'new', $new, $timestamp);
+    _feedapi_store_stat($nid, 'download_num', count($items), $timestamp);
+    _feedapi_store_stat($nid, 'process_time', timer_read('feedapi_'. $feed->nid), $timestamp);
+  }
+  db_query("UPDATE {feedapi} SET checked = %d, half_done = %d, hash = '%s' WHERE nid = %d", time(), $half_done, $feed->hash, $feed->nid);
+  
+  if (!$cron) {
+    if ($new == 0 && $updated == 0) {
+      drupal_set_message(t('There are no new items in the feed.'), 'status');
+    }
+    else {
+      drupal_set_message(t("%new new item(s) were saved. %updated existing item(s) were updated.", array("%new" => $new, "%updated" => $updated)));
+    }
+    // @ TODO what value to return here?
+  }
+  else {
+    // Update and return counter
+    $counter['new'] = $new;
+    $counter['updated'] = $updated;
+    return $counter;
+  }
+}
+
+
+/**
+ * Helper function for feedapi_invoke().
+ * 
+ * Generic operations, collects results and returns array
+ */
+function _feedapi_invoke($op, &$feed, $param) {
+  $output = array();
+  foreach ($feed->processors as $processor) {
+    $result = module_invoke($processor, 'feedapi_item', $op, $feed, $param);
+    // Result may be a list of items or single values (count)
+    if ($result) {
+      if (is_array($result)) {
+        $output = array_merge($output, $result);
+      }
+      else {
+        $output[] = $result;
+      }
+    }
+  }
+  return $output;
+}
+
+/**
+ * Helper function for feedapi_invoke().
+ * Load a list of feed items into the feed object from the processors.
+ */
+function _feedapi_invoke_load(&$feed, $param) {
+  $feed->items = array();
+  foreach ($feed->processors as $processor) {
+    $items = module_invoke($processor, 'feedapi_item', 'fetch', $feed);
+    if (is_array($items)) {
+      foreach ($items as $item) {
+        $feed->items[] = $item;
+      }
+    }
+  }
+}
+
+/**
+ * Store statistics information
+ *
+ * @param $id
+ *  A numerical id
+ * @param $type
+ *  A string which describes what we want to store. This is an identifier, think of as a variable name
+ * @param $val
+ *  This is the variable value
+ * @param $timestamp
+ *  Timestamp for the value
+ * @param $time
+ *  Optional, a string equivalent to the $timestamp
+ * @param $update
+ *  Boolean, TRUE if you'd like to modify an existing entry in the stat table
+ */
+function _feedapi_store_stat($id, $type, $val, $timestamp, $time = NULL, $update = FALSE) {
+  if (!$time) {
+    $time = date("Y-m-d H:i", $timestamp);
+  }
+  if ($update) {
+    db_query("UPDATE {feedapi_stat} SET value = %d, timestamp = %d WHERE time = '%s' AND type = '%s' AND id = %d", $val, $timestamp, $time, $type, $id);
+  }
+  if (!$update || !db_affected_rows()) {
+    db_query("INSERT INTO {feedapi_stat} (id, value, time, timestamp, type) VALUES (%d, %d, '%s', %d, '%s')", $id, $val, $time, $timestamp, $type);
+  }
+}
+
+/**
+ * Return the type-specific statistics data
+ *
+ * @param $id
+ *  A numerical id
+ * @param $type
+ *  Name of the type (variable)
+ * @name $only_val
+ *  If TRUE, only the values are returned, no more.
+ * @return
+ *  $only_val = FALSE -> array("timestamp" => array(), "time" => array(), "value" => array());
+ */
+function _feedapi_get_stat($id, $type, $only_val = FALSE) {
+  $stat = array();
+  $result = db_query("SELECT timestamp, time, value FROM {feedapi_stat} WHERE type = '%s' AND id = %d", $type, $id);
+  while ($row = db_fetch_array($result)) {
+    if ($only_val) {
+      $stat[] = $row['value'];
+    }
+    else {
+      foreach (array('timestamp', 'time', 'value') as $member) {
+        $stat[$member][] = $row[$member];
+      }
+    }
+  }
+  return $stat;
+}
Index: feedapi.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/feedapi/feedapi.module,v
retrieving revision 1.23.2.119.2.39
diff -u -p -r1.23.2.119.2.39 feedapi.module
--- feedapi.module	17 Feb 2009 14:58:40 -0000	1.23.2.119.2.39
+++ feedapi.module	17 Feb 2009 16:03:40 -0000
@@ -260,6 +260,7 @@ function feedapi_views_api() {
  *  Depends on the $op value.
  */
 function feedapi_invoke($op, &$feed, $param = NULL) {
+  module_load_include('inc', 'feedapi', 'feedapi');
   if (!is_object($feed)) {
     return FALSE;
   }
@@ -539,6 +540,7 @@ function feedapi_form_alter(&$form, $for
  * See feedapi_form_alter on finding out how it is called (via FormAPI)
  */
 function feedapi_node_validate($form, &$form_state) {
+  module_load_include('inc', 'feedapi', 'feedapi');
   $feed = _feedapi_build_feed_object($form_state['values']['type'], $form_state['values']['feedapi']['feedapi_url']);
   // Stick feed object into feedapi form snippet - store it in submit.
   $form_state['values']['feedapi_object'] = $feed;
@@ -724,6 +726,7 @@ function feedapi_get_natural_name($modul
  *  URI of feed.
  */
 function feedapi_create_node($param, $url) {
+  module_load_include('inc', 'feedapi', 'feedapi');
   if (is_object($param)) {
     $node = $param;
   }
@@ -788,130 +791,6 @@ function feedapi_refresh($node, $destina
 }
 
 /**
- * Insert feedapi data to the DB when it's a new for for FeedAPI
- */
-function _feedapi_insert(&$node, $teaser, $page) {
-  if (isset($node->feed->url) && isset($node->feed->feed_type)) {
-    db_query("INSERT INTO {feedapi} (
-            nid, url, link, feed_type, processors,
-            parsers, checked, settings) VALUES
-            (%d, '%s', '%s', '%s', '%s', '%s', %d, '%s')",
-      $node->nid,
-      $node->feed->url,
-      $node->feed->options->link,
-      $node->feed->feed_type,
-      serialize($node->feed->processors),
-      serialize($node->feed->parsers),
-      0,
-      serialize(array())
-    );
-    // Store add on module's settings if user has permission to do so.
-    if (user_access('advanced feedapi options')) {
-      _feedapi_store_settings(array('nid' => $node->nid), $node->feedapi);
-    }
-    // Refresh feed if the user would like to do that
-    $settings = feedapi_get_settings($node->type, $node->nid);
-    if ($settings['refresh_on_create'] == TRUE) {
-      $node->feed->nid = $node->nid;
-      $node->feed->settings = $settings;
-      feedapi_invoke('refresh', $node->feed);
-    }
-  }
-}
-
-/**
- * Update feed data of an existing feed
- */
-function _feedapi_update(&$node, $teaser, $page) {
-  if (isset($node->feed)) {
-    $old_config = node_load($node->nid);
-    // In that case this feed has never have feed data. Should be created then, this is not really an update
-    if (!is_numeric($old_config->feed->nid)) {
-      $node->feed = _feedapi_build_feed_object($node->type, $node->feed->url);
-      _feedapi_insert($node, 'insert', $teaser, $page);
-      return;
-    }
-    db_query("UPDATE {feedapi} SET
-            url = '%s', feed_type = '%s', processors = '%s',
-            parsers = '%s', link = '%s' WHERE nid = %d",
-      isset($node->feed->url) ? $node->feed->url : $node->feedapi['feedapi_url'],
-      isset($node->feed->feed_type) ? $node->feed->feed_type : '',
-      isset($node->feed->processors) ? serialize($node->feed->processors) : serialize($old_config->feed->processors),
-      isset($node->feed->parsers) ? serialize($node->feed->parsers) : serialize($old_config->feed->parsers),
-      $node->feed->options->link,
-      $node->nid
-    );
-    // Store add on module's settings if user has permission to do so.
-    if (user_access('advanced feedapi options')) {
-      _feedapi_store_settings(array('nid' => $node->nid), $node->feedapi);
-    }
-  }
-}
-
-/**
- * Execute the enabled parsers and create an unified output
- *
- * @param $feed
- *  Feed object
- * @param $parsers
- *  Structure: array(
- *    "primary" => "parser_primary",
- *    "secondary" => array("parser1", "parser2", "parserN")
- *  );
- * @return
- *  The object of the parser data
- */
-function _feedapi_call_parsers($feed, $parsers, $settings) {
-  $nid = isset($feed->nid) ? $feed->nid : '';
-  $parser_primary = array_shift($parsers);
-  $parsers_secondary = $parsers;
-  if (module_exists($parser_primary)) {
-    $feed->feed_type =  module_invoke($parser_primary, 'feedapi_feed', 'compatible', $feed, $settings[$parser_primary]);
-    $parser_output =  module_invoke($parser_primary, 'feedapi_feed', 'parse', $feed, $settings[$parser_primary]);
-    if ($parser_output === FALSE) {
-      return $parser_output;
-    }
-    $feed = (object) array_merge((array) $feed, (array) $parser_output);
-  }
-  // Call the turned on parsers, create a union of returned options
-  $parsers_secondary = is_array($parsers_secondary) ? $parsers_secondary : array();
-  foreach ($parsers_secondary as $parser) {
-    $feed_ext = module_invoke($parser, 'feedapi_feed', 'parse', $feed, FALSE);
-    $feed->options = (object) ((array) $feed->options + (array) $feed_ext->options);
-    // Merge items' options
-    if (is_array($feed_ext->items)) {
-      foreach ($feed_ext->items as $key => $item) {
-        $feed->items[$key]->options = (object) ((array) $feed->items[$key]->options + (array) $item->options);
-      }
-    }
-  }
-  $feed->nid = $nid;
-  foreach (module_implements('feedapi_after_parse') as $module) {
-    $func = $module .'_feedapi_after_parse';
-    $func($feed);
-  }
-  // Filter bad or not allowed tags, sanitize data (currently timestamp checking)
-  if (!variable_get('feedapi_allow_html_all', FALSE)) {
-    $allowed = preg_split('/\s+|<|>/', variable_get('feedapi_allowed_html_tags', '<a> <b> <br> <dd> <dl> <dt> <em> <i> <li> <ol> <p> <strong> <u> <ul>'), -1, PREG_SPLIT_NO_EMPTY);
-    foreach (array('title', 'description') as $property) {
-      if (isset($feed->{$property})) {
-        if (is_string($feed->{$property})) {
-          $feed->{$property} = _feedapi_process_text($feed->{$property}, $allowed);
-        }
-      }
-    }
-    for ($i = 0; $i < count($feed->items); $i++) {
-      $feed->items[$i]->title = _feedapi_process_text($feed->items[$i]->title, array());
-      $feed->items[$i]->description = _feedapi_process_text($feed->items[$i]->description, $allowed);
-      if ($feed->items[$i]->options->timestamp == 0) {
-        $feed->items[$i]->options->timestamp = time();
-      }
-    }
-  }
-  return $feed;
-}
-
-/**
  * Filter texts from parsers
  *
  * @param $text
@@ -982,204 +861,6 @@ function feedapi_enabled_type($node_type
 }
 
 /**
- * Helper function for feedapi_invoke().
- * 
- * Generic operations, collects results and returns array
- */
-function _feedapi_invoke($op, &$feed, $param) {
-  $output = array();
-  foreach ($feed->processors as $processor) {
-    $result = module_invoke($processor, 'feedapi_item', $op, $feed, $param);
-    // Result may be a list of items or single values (count)
-    if ($result) {
-      if (is_array($result)) {
-        $output = array_merge($output, $result);
-      }
-      else {
-        $output[] = $result;
-      }
-    }
-  }
-  return $output;
-}
-
-/**
- * Helper function for feedapi_invoke().
- * Load a list of feed items into the feed object from the processors.
- */
-function _feedapi_invoke_load(&$feed, $param) {
-  $feed->items = array();
-  foreach ($feed->processors as $processor) {
-    $items = module_invoke($processor, 'feedapi_item', 'fetch', $feed);
-    if (is_array($items)) {
-      foreach ($items as $item) {
-        $feed->items[] = $item;
-      }
-    }
-  }
-}
-
-/**
- * Helper function for feedapi_invoke().
- * Refresh the feed, call the proper parsers and processors' hooks.
- * Don't call this function directly, use feedapi_refresh() instead.
- * 
- * @ TODO Fix: This may loop forever when a feed has no processors
- */
-function _feedapi_invoke_refresh(&$feed, $param) {
-  $timestamp = variable_get('cron_semaphore', FALSE) !== FALSE ? variable_get('cron_semaphore', FALSE) : time();
-  
-  $counter = array();
-  timer_start('feedapi_'. $feed->nid);
-  $cron = $param;
-  
-  // Step 0: Check processors and grab settings
-  if (!is_array($feed->processors) || count($feed->processors) == 0) {
-    if (!$cron) {
-      drupal_set_message(t("No processors specified for URL %url. Could not refresh.", array('%url' => $feed->url)), "error");
-      drupal_goto('node/'. $feed->nid);
-    }
-    return 0;
-  }
-  $settings = feedapi_get_settings(NULL, $feed->nid);
-  
-  // Step 1: Force processors to delete old items and determine the max. create elements.
-  $counter['expired'] = feedapi_expire($feed);
-
-  // Step 2: Get feed.
-  $nid = $feed->nid;
-  $hash_old = $feed->hash;
-  $feed = _feedapi_call_parsers($feed, $feed->parsers, $settings['parsers']);
-  if (is_object($feed)) {
-    $feed->hash = md5(serialize($feed->items));
-  }
-  
-  // Step 3: See, whether feed has been modified.
-  if ($feed === FALSE || $hash_old == $feed->hash) {
-    // Updated the checked field in any case.
-    db_query("UPDATE {feedapi} SET checked = %d, half_done = %d WHERE nid = %d", time(), FALSE, $nid);
-    if (!$cron) {
-      if ($hash_old == $feed->hash && is_object($feed)) {
-        drupal_set_message(t('There are no new items in the feed.'), 'status');
-      }
-      else {
-        drupal_set_message(t('Could not refresh feed.'), 'error');
-      }
-    }
-    return $counter;
-  }
-
-  // Step 4: Walk through the items and check duplicates, then save or update
-  $items = $feed->items;
-  $updated = 0;
-  $new = 0;
-  $half_done = FALSE;
-
-  // We check for time-out after each item
-  foreach ($items as $index => $item) {
-    // Call each item parser.
-    $item->is_updated = FALSE;
-    $item->is_new = FALSE;
-    foreach ($feed->processors as $processor) {
-      if (!module_invoke($processor, 'feedapi_item', 'unique', $item, $feed->nid, $settings['processors'][$processor])) {
-        if ($settings['update_existing'] == TRUE) {
-          module_invoke($processor, 'feedapi_item', 'update', $item, $feed->nid, $settings['processors'][$processor]);
-          $item->is_updated = TRUE;
-        }
-      }
-      else {
-        // We have checked before for expired items, so just save it.
-        // if the item is already expired then do nothing
-        $items_delete = $settings['items_delete'];
-        $diff = abs(time() - (isset($item->options->timestamp) ? $item->options->timestamp : time()));
-        if ($diff > $items_delete && ($items_delete > FEEDAPI_NEVER_DELETE_OLD)) {
-          break;
-        }
-        $result = module_invoke($processor, 'feedapi_item', 'save', $item, $feed->nid, $settings['processors'][$processor]);
-        if ($result !== FALSE) {
-          $item->is_new = TRUE;
-        }
-      }
-    }
-    $new = $item->is_new ? $new + 1 : $new;
-    $updated = ($item->is_updated && !$item->is_new) ? $updated + 1 : $updated;
-    
-    // Decision on time. If the exec time is greather than the user-set percentage of php max execution time
-    if ($cron && !feedapi_cron_time()) {
-      $half_done = ($new + $updated) == count($items) ? FALSE : TRUE;
-      break;
-    }
-    // Save the item status for further processing
-    $feed->items[$index] = $item;
-  }
-  
-  // Closing step: Call after refresh and update feed statistics
-  foreach (module_implements('feedapi_after_refresh') as $module) {
-    $func = $module .'_feedapi_after_refresh';
-    $func($feed);
-  }
-  if ($new > 0) {
-    _feedapi_store_stat($nid, 'update_times', time(), $timestamp);
-    _feedapi_store_stat($nid, 'new', $new, $timestamp);
-    _feedapi_store_stat($nid, 'download_num', count($items), $timestamp);
-    _feedapi_store_stat($nid, 'process_time', timer_read('feedapi_'. $feed->nid), $timestamp);
-  }
-  db_query("UPDATE {feedapi} SET checked = %d, half_done = %d, hash = '%s' WHERE nid = %d", time(), $half_done, $feed->hash, $feed->nid);
-  
-  if (!$cron) {
-    if ($new == 0 && $updated == 0) {
-      drupal_set_message(t('There are no new items in the feed.'), 'status');
-    }
-    else {
-      drupal_set_message(t("%new new item(s) were saved. %updated existing item(s) were updated.", array("%new" => $new, "%updated" => $updated)));
-    }
-    // @ TODO what value to return here?
-  }
-  else {
-    // Update and return counter
-    $counter['new'] = $new;
-    $counter['updated'] = $updated;
-    return $counter;
-  }
-}
-
-/**
- * Helper function for feedapi_invoke().
- * Delete all feed items of a feed.
- */
-function _feedapi_invoke_purge(&$feed, $param) {
-  $node = node_load($feed->nid);
-  
-  if ($param == 'items') {
-    return drupal_get_form('feedapi_purge_confirm', $node);
-  }
-
-  // Delete items from the processors
-  foreach ($feed->processors as $processor) {
-    // FIXME: it's possible now to accidentally delete an item from another processor
-    module_invoke($processor, 'feedapi_item', 'purge', $feed);
-  }
-  // Reset hash.
-  db_query("UPDATE {feedapi} SET hash = 0 WHERE nid = %d", $feed->nid);
-}
-
-/**
- * Builds feed object ready to be sticked onto node.
- */
-function _feedapi_build_feed_object($node_type, $url) {
-  $feed = new stdClass();
-  $feed->url = $url;
-  $node_type_settings = feedapi_get_settings($node_type);
-  $feed->processors = _feedapi_format_settings($node_type_settings, 'processors');
-  $feed->parsers = _feedapi_format_settings($node_type_settings, 'parsers');
-  if (isset($feed->url)) {
-    $feed = _feedapi_call_parsers($feed, $feed->parsers, $node_type_settings['parsers']);
-  }
-  $feed->link = isset($feed->options->link) ? $feed->options->link : '';
-  return $feed;
-}
-
-/**
  * Returns per content type settings ordered by weight
  * and only those that are turned on.
  * @param $node_type_settings
@@ -1321,62 +1002,6 @@ function _feedapi_sanitize_processors(&$
 }
 
 /**
- * Store statistics information
- *
- * @param $id
- *  A numerical id
- * @param $type
- *  A string which describes what we want to store. This is an identifier, think of as a variable name
- * @param $val
- *  This is the variable value
- * @param $timestamp
- *  Timestamp for the value
- * @param $time
- *  Optional, a string equivalent to the $timestamp
- * @param $update
- *  Boolean, TRUE if you'd like to modify an existing entry in the stat table
- */
-function _feedapi_store_stat($id, $type, $val, $timestamp, $time = NULL, $update = FALSE) {
-  if (!$time) {
-    $time = date("Y-m-d H:i", $timestamp);
-  }
-  if ($update) {
-    db_query("UPDATE {feedapi_stat} SET value = %d, timestamp = %d WHERE time = '%s' AND type = '%s' AND id = %d", $val, $timestamp, $time, $type, $id);
-  }
-  if (!$update || !db_affected_rows()) {
-    db_query("INSERT INTO {feedapi_stat} (id, value, time, timestamp, type) VALUES (%d, %d, '%s', %d, '%s')", $id, $val, $time, $timestamp, $type);
-  }
-}
-
-/**
- * Return the type-specific statistics data
- *
- * @param $id
- *  A numerical id
- * @param $type
- *  Name of the type (variable)
- * @name $only_val
- *  If TRUE, only the values are returned, no more.
- * @return
- *  $only_val = FALSE -> array("timestamp" => array(), "time" => array(), "value" => array());
- */
-function _feedapi_get_stat($id, $type, $only_val = FALSE) {
-  $stat = array();
-  $result = db_query("SELECT timestamp, time, value FROM {feedapi_stat} WHERE type = '%s' AND id = %d", $type, $id);
-  while ($row = db_fetch_array($result)) {
-    if ($only_val) {
-      $stat[] = $row['value'];
-    }
-    else {
-      foreach (array('timestamp', 'time', 'value') as $member) {
-        $stat[$member][] = $row[$member];
-      }
-    }
-  }
-  return $stat;
-}
-
-/**
  * Return a list of FeedAPI-enabled content-types list, ready-to-use for #options at FormsAPI
  */
 function feedapi_get_types() {
