Binary files leech-orig/geekomatik-logo.png and leech/geekomatik-logo.png differ
Binary files leech-orig/headbg.gif and leech/headbg.gif differ
diff -urpN leech-orig/leech.css leech/leech.css
--- leech-orig/leech.css 1970-01-01 01:00:00.000000000 +0100
+++ leech/leech.css 2007-11-27 09:50:10.000000000 +0100
@@ -0,0 +1,131 @@
+#leech_overlay {
+ position: fixed;
+ z-index:100;
+ top: 0px;
+ left: 0px;
+ background-color:#000;
+ filter:alpha(opacity=75);
+ -moz-opacity: 0.75;
+ opacity: 0.75;
+ height:100%;
+ width:100%;
+}
+
+* html #leech_overlay { /* ie6 hack */
+ position: absolute;
+ height: expression(document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px');
+}
+
+#leech_popup {
+ position: fixed;
+ background: #ffffff;
+ z-index: 102;
+ color:#000000;
+ display:none;
+ border: 4px solid #525252;
+ text-align:left;
+ top:50%;
+ left:50%;
+}
+
+* html #leech_popup { /* ie6 hack */
+position: absolute;
+margin-top: expression(0 - parseInt(this.offsetHeight / 2) + (TBWindowMargin = document.documentElement && document.documentElement.scrollTop || document.body.scrollTop) + 'px');
+}
+
+#leech_popup {
+ display:block;
+ margin: 15px 0 0 15px;
+ border-right: 1px solid #ccc;
+ border-bottom: 1px solid #ccc;
+ border-top: 1px solid #666;
+ border-left: 1px solid #666;
+}
+
+#leech_HideSelect{
+ z-index:99;
+ position:fixed;
+ top: 0;
+ left: 0;
+ background-color:#fff;
+ border:none;
+ filter:alpha(opacity=0);
+ -moz-opacity: 0;
+ opacity: 0;
+ height:100%;
+ width:100%;
+}
+
+* html #leech_HideSelect { /* ie6 hack */
+ position: absolute;
+ height: expression(document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px');
+}
+
+#leech_popup {
+ text-align: center;
+}
+
+div.leech_content {
+}
+
+div.leech_content_iframe {
+ border: none;
+}
+
+div.leech_buttons {
+ height: 150px;
+ text-align: center;
+}
+
+div.leech_buttons div.vote-up-down-widget {
+ text-align: center;
+}
+
+div.leech_buttons a {
+ padding-right : 10px;
+ padding-left : 10px;
+}
+
+div.leech_loading_animation {
+ text-align: center;
+ padding-top: 65px;
+ height: 150px;
+}
+
+div.leech_vote_up_down {
+ width: 100px;
+ text-align: center;
+ float: left;
+}
+
+div.leech_community_tags_inline {
+ width: 300px;
+ text-align: left;
+ float: left;
+}
+
+div.leech_community_tags_inline form div div.form-item label {
+ display: inline;
+}
+
+div.leech_community_tags_inline form div div.form-item {
+ display: block;
+}
+
+td.leech_header {
+ width: 200px;
+ text-align: left;
+}
+
+td.leech_vote_up_down {
+ width: 100px;
+ text-align: left;
+}
+
+td.leech_community_tags_inline {
+ text-align: left;
+}
+
+table.leech_buttons tbody {
+ border: none;
+}
diff -urpN leech-orig/leech.info leech/leech.info
--- leech-orig/leech.info 2007-07-30 19:10:07.000000000 +0200
+++ leech/leech.info 2007-10-15 11:20:19.000000000 +0200
@@ -4,7 +4,7 @@ description = "Feed aggretagor, creates
dependencies = node_template
package = Leech
; Information added by drupal.org packaging script on 2007-07-30
-version = "5.x-1.9"
+version = "5.x-1.9-geekomatik"
project = "leech"
datestamp = "1185815407"
diff -urpN leech-orig/leech.js leech/leech.js
--- leech-orig/leech.js 1970-01-01 01:00:00.000000000 +0100
+++ leech/leech.js 2007-11-28 08:45:05.000000000 +0100
@@ -0,0 +1,221 @@
+function leech_show_nodebody(sender, nid) {
+ sender_position = leech_get_position(sender);
+ var top = sender_position[0];
+ var left = sender_position[1];
+ var p = $("div[@id=leech_popup]");
+ p.empty();
+ p.css("position", "absolute");
+ p.css("left", left + "px");
+ p.css("top", top + "px");
+ p.append('
');
+ p.show();
+
+ $.ajax({
+ type: "GET",
+ async: true,
+ url: Drupal.settings.leech.nodebody_url,
+ dataType: "html",
+ data: "nid=" + nid,
+ success: function (html) {
+ p.empty();
+ p.append(html);
+ }
+ });
+
+ return false;
+};
+
+function leech_show_articleoriginal(sender, nid) {
+ leech_showOverlay();
+
+ var pagesize = leech_getPageSize();
+ var width = pagesize[0] - 60;
+ var height = pagesize[1] - 60;
+
+ var p = $("div[@id=leech_popup]");
+ p.empty();
+
+ p.css({marginLeft: '-' + parseInt((width / 2),10) + 'px', width: width + 'px'});
+ if ( !(jQuery.browser.msie && typeof XMLHttpRequest == 'function')) { // take away IE6
+ p.css({marginTop: '-' + parseInt((height / 2),10) + 'px'});
+ }
+ p.css('height', height + 'px');
+ p.css('width', width + 'px');
+
+ p.append(' ');
+ p.show();
+
+ $.ajax({
+ type: "GET",
+ async: true,
+ url: Drupal.settings.leech.articleoriginal_url,
+ dataType: "html",
+ data: "nid=" + nid,
+ success: function (html) {
+ p.empty();
+ p.append(html);
+
+ var lb = $("div.leech_buttons");
+ var lc = $("div.leech_content");
+ lc.css('height', (height-parseInt(lb.css('height'))) + 'px');
+
+ leech_community_tags_inline_form_js(nid);
+ }
+ });
+
+ return false;
+};
+
+function leech_close_popup() {
+ leech_hideOverlay();
+};
+
+function leech_get_position(element) {
+ var position_top = 0;
+ var position_left = 0;
+
+ while(element != null) {
+ position_top += element.offsetTop;
+ position_left += element.offsetLeft;
+ element = element.offsetParent
+ }
+
+ return [position_top, position_left];
+};
+
+function leech_getPageSize(){
+ var de = document.documentElement;
+ var w = window.innerWidth || self.innerWidth || (de&&de.clientWidth) || document.body.clientWidth;
+ var h = window.innerHeight || self.innerHeight || (de&&de.clientHeight) || document.body.clientHeight;
+ arrayPageSize = [w,h];
+ return arrayPageSize;
+};
+
+function leech_showOverlay() {
+ if (typeof document.body.style.maxHeight === "undefined") {//if IE 6
+ $("body","html").css({height: "100%", width: "100%"});
+ $("html").css("overflow","hidden");
+ if (document.getElementById("leech_HideSelect") === null) {//iframe to hide select elements in ie6
+ $("body").append("
");
+ $("#leech_overlay").click(leech_hideOverlay);
+ }
+ }else{//all others
+ if(document.getElementById("TB_overlay") === null){
+ $("body").append("
");
+ $("#leech_overlay").click(leech_hideOverlay);
+ }
+ }
+};
+
+function leech_hideOverlay() {
+ var p = $("div[@id=leech_popup]");
+ p.hide();
+
+ $("#leech_overlay").unbind("click");
+ $('#leech_window,#leech_overlay,#leech_HideSelect').remove();
+ if (typeof document.body.style.maxHeight == "undefined") {//if IE 6
+ $("body","html").css({height: "auto", width: "auto"});
+ $("html").css("overflow","");
+ }
+ document.onkeydown = "";
+ return false;
+};
+
+function leech_community_tags_inline_form_js(nid) {
+ $.ajax({
+ type: "GET",
+ async: true,
+ url: Drupal.settings.leech_communityTagsInline.urlJS + Drupal.encodeURIComponent(nid),
+ dataType: "string",
+ success: function (js_data) {
+ if(Drupal.settings) {
+ if(Drupal.settings.communityTags) {
+ Drupal.settings.communityTags = null;
+ }
+ }
+ eval(js_data);
+ leech_community_tags_inline_activate_box(nid);
+ }
+ });
+}
+
+function leech_community_tags_inline_activate_box (nid) {
+if (Drupal.jsEnabled) {
+ $(document).ready(function () {
+ // Note: all tag fields are autocompleted, and have already been initialized at this point.
+ $('input.form-tags').each(function () {
+ // Hide submit buttons.
+ $('input[@type=submit]', this.form).hide();
+
+ // Fetch settings.
+ var o = Drupal.settings.communityTags;
+ var sequence = 0;
+
+ // Show the textfield and empty its value.
+ var textfield = $(this).val('').css('display', 'inline');
+
+ // Prepare the add Ajax handler and add the button.
+ var addHandler = function () {
+ // Send existing tags and new tag string.
+ $.post(o.url, Drupal.serialize({ sequence: ++sequence, tags: o.tags, add: textfield[0].value }), function (data) {
+ data = Drupal.parseJson(data);
+ if (data.status && sequence == data.sequence) {
+ o.tags = data.tags;
+ updateList();
+ }
+ });
+
+ // Add tag to local list
+ if(!o.tags[0]) {
+ o.tags = new Array;
+ }
+ o.tags.push(textfield[0].value);
+ o.tags.sort();
+ updateList();
+
+ // Clear field and focus it.
+ textfield.val('').focus();
+ };
+ var button = $(' ').click(addHandler);
+ $(this.form).submit(function () { addHandler(); return false; });
+
+ // Prepare the delete Ajax handler.
+ var deleteHandler = function () {
+ // Remove tag from local list.
+ var i = $(this).attr('key');
+ o.tags.splice(i, 1);
+ updateList();
+
+ // Send new tag list.
+ $.post(o.url, Drupal.serialize({ sequence: ++sequence, tags: o.tags, add: '' }), function (data) {
+ data = Drupal.parseJson(data);
+ if (data.status && sequence == data.sequence) {
+ o.tags = data.tags;
+ updateList();
+ }
+ });
+
+ // Clear textfield and focus it.
+ textfield.val('').focus();
+ };
+
+ // Callback to update the tag list.
+ function updateList() {
+ list.empty();
+ for (i in o.tags) {
+ list.append(''+ Drupal.checkPlain(o.tags[i]) +' ');
+ }
+ $('li', list).click(deleteHandler);
+ }
+
+ // Create widget markup.
+ var widget = $('');
+ textfield.before(widget);
+ widget.append(textfield).append(button);
+ var list = $('ul', widget);
+ updateList();
+
+ });
+ });
+}
+}
\ No newline at end of file
diff -urpN leech-orig/leech.module leech/leech.module
--- leech-orig/leech.module 2007-07-30 19:02:38.000000000 +0200
+++ leech/leech.module 2008-01-23 18:46:47.000000000 +0100
@@ -64,6 +64,43 @@ function leech_perm() {
* @todo move deprecated paths to bottom of page, remove not used paths
*/
function leech_menu($may_cache) {
+ drupal_add_js('misc/drupal.js', 'core', 'header', FALSE);
+ drupal_add_js('misc/jquery.js', 'core', 'header', FALSE);
+ drupal_add_js(drupal_get_path('module', 'leech') .'/leech.js', 'module', 'header', FALSE);
+ drupal_add_css(drupal_get_path('module', 'leech') .'/leech.css', 'module');
+
+ static $pass = FALSE;
+ if(!$pass) {
+ if(module_exists('community_tags_inline') && $format == 'custom') {
+ drupal_add_js('misc/jquery.js', 'core', 'header', FALSE);
+ drupal_add_js('misc/autocomplete.js', 'core', 'header', FALSE);
+ drupal_add_css(drupal_get_path('module', 'tagadelic') .'/tagadelic.css', 'module');
+ drupal_add_css(drupal_get_path('module', 'community_tags') .'/community_tags.css', 'module');
+ drupal_add_js(drupal_get_path('module', 'community_tags_inline') . '/js/community_tags_inline.js', 'module', 'header', FALSE);
+ }
+
+ if(module_exists('vote_up_down') && $format == 'custom') {
+ drupal_add_css(drupal_get_path('module', 'vote_up_down') .'/vote_up_down.css');
+ drupal_add_js(drupal_get_path('module', 'vote_up_down') . '/ajax_vote_up_down.js');
+ }
+
+ $settings = array('leech_communityTagsInline' =>
+ array(
+ 'urlForm' => url('community_tags_inline/tag_form/'),
+ 'urlJS' => url('community_tags_inline/tag_form_js/'),
+ ),
+ 'leech' =>
+ array(
+ 'loading_animation' => base_path() . drupal_get_path('module', 'leech') .'/loading_animation.gif',
+ 'nodebody_url' => url('leech/nodebody/'),
+ 'articleoriginal_url' => url('leech/articleoriginal/'),
+ )
+ );
+ drupal_add_js($settings, 'setting');
+
+ $pass = TRUE;
+ }
+
$items = array();
if ($may_cache) {
@@ -109,6 +146,34 @@ function leech_menu($may_cache) {
'type' => MENU_CALLBACK);
$items[] = array('path' => 'admin/settings/leech', 'title' => t('Leech'),
'callback' => 'drupal_get_form', 'callback arguments' => array('leech_admin_settings'), 'description' => t('Configure leech module.'),);
+
+ $items[] = array(
+ 'path' => 'leech/nodebody',
+ 'title' => t('Leech node body'),
+ 'callback' => 'leech_nodebody',
+ 'access' => user_access('access content'),
+ 'type' => MENU_CALLBACK);
+
+ $items[] = array(
+ 'path' => 'leech/articleoriginal',
+ 'title' => t('Leech article original'),
+ 'callback' => 'leech_articleoriginal',
+ 'access' => user_access('access content'),
+ 'type' => MENU_CALLBACK);
+
+ $items[] = array(
+ 'path' => 'leech/articlepreview',
+ 'title' => t('Leech article preview'),
+ 'callback' => 'leech_articlepreview',
+ 'access' => user_access('access content'),
+ 'type' => MENU_CALLBACK);
+
+ $items[] = array(
+ 'path' => 'leech/articlepreviewheader',
+ 'title' => t('Leech article preview header'),
+ 'callback' => 'leech_articlepreviewheader',
+ 'access' => user_access('access content'),
+ 'type' => MENU_CALLBACK);
}
return $items;
@@ -346,6 +411,46 @@ function leech_admin_settings() {
}
}
+ $formats = array (
+ 'teaser' => t('Teaser'),
+ 'custom' => t('Custom'),
+ );
+ $form['leech_page_items_format'] = array (
+ '#type' => 'select',
+ '#options' => $formats,
+ '#default_value' => variable_get('leech_page_items_format', 'full'),
+ '#title' => t('Items format for default page'),
+ );
+
+ $form['leech_page_items_custom_length_teaser'] = array (
+ '#type' => 'textfield',
+ '#default_value' => variable_get('leech_page_items_custom_length_teaser', 600),
+ '#title' => t('Item length (number of chars) for custom format teaser'),
+ );
+
+ $form['leech_page_items_custom_length_body'] = array (
+ '#type' => 'textfield',
+ '#default_value' => variable_get('leech_page_items_custom_length_body', 600),
+ '#title' => t('Item length (number of chars) for custom format body'),
+ );
+
+ $form['leech_originalarticle_popup'] = array (
+ '#type' => 'checkbox',
+ '#default_value' => variable_get('leech_originalarticle_popup', FALSE),
+ '#title' => t('Show the original article in a popup window'),
+ );
+
+ $formats = array (
+ 'popup' => t('In a popup'),
+ 'window' => t('In a window'),
+ );
+ $form['leech_originalwebsite_preview'] = array (
+ '#type' => 'select',
+ '#options' => $formats,
+ '#default_value' => variable_get('leech_originalwebsite_preview', 'popup'),
+ '#title' => t('How to show the preview of the original website'),
+ );
+
return system_settings_form($form);
}
@@ -405,7 +510,12 @@ function theme_leech_link_full_article($
if (variable_get('leech_news_original_links', 0) && $node->leech_news->source_link) {
$link = $node->leech_news->source_link;
}
- return ''. t('original article') .' ';
+ if(variable_get('leech_originalarticle_popup', FALSE)) {
+ return ''. t('original article') .' ';
+ }
+ else {
+ return ''. t('original article') .' ';
+ }
}
/**
@@ -420,8 +530,15 @@ function leech_news_page_default($nid =
if ($feed && $feed->leech_news) {
$output .= node_view($feed, 1);
$result = pager_query(db_rewrite_sql('SELECT n.nid, n.sticky, n.created FROM {node} n INNER JOIN {leech_news_item} i ON i.nid = n.nid WHERE i.fid = %d AND n.status = 1 ORDER BY n.sticky DESC, n.created DESC'), variable_get('default_nodes_main', 10), 0, NULL, $feed->nid);
+ $format = variable_get('leech_page_items_format', 'full');
+
while ($node = db_fetch_object($result)) {
- $output .= node_view(node_load($node->nid), 1);
+ if($format == 'teaser') {
+ $output .= node_view(node_load($node->nid), true, false);
+ }
+ else if($format == 'custom') {
+ $output .= leech_item_custom_format($node->nid);
+ }
}
$output .= theme('pager', NULL, variable_get('default_nodes_main', 10));
}
@@ -441,6 +558,222 @@ function leech_news_page_default($nid =
return $output;
}
+function theme_leech_item_custom_format($node, $node_content) {
+ $output = '';
+
+ if (!$node->status) {
+ $output = '
';
+ }
+
+ if (module_exists('taxonomy')) {
+ $terms = taxonomy_link('taxonomy terms', $node);
+ }
+
+ if(variable_get('leech_originalwebsite_preview', 'popup')=='popup') {
+ $node_link = l($node->title, drupal_get_path_alias('node/' . $node->nid), array('onclick'=>"return leech_show_articleoriginal(this, " . $node->nid . ");"), NULL, NULL, FALSE, TRUE);
+ }
+ else {
+ $node_link = l($node->title, 'leech/articlepreview/' . $node->nid, NULL, NULL, NULL, FALSE, TRUE);
+ }
+ $output .= t('!title by !name', array('!title' => '
'. $node_link .' ', '!name' => theme('username', $node)));
+
+ if (count($terms)) {
+ $output .= '
('. theme('links', $terms) .') ';
+ }
+
+ $node->content['body']['#value'] = $node_content;
+ $output .= '
' . drupal_render($node->content) . '
';
+
+ if ($node->links) {
+ $output .= '
'. theme('links', $node->links) .'
';
+ }
+
+ if (!$node->status) {
+ $output .= '
';
+ }
+
+ $output .= '
';
+
+ return $output;
+}
+
+function leech_item_custom_format($nid) {
+ $item = node_load($nid);
+ $item = node_build_content($item, true, false);
+ $item_content = _leech_htmlcorrector($item->body);
+ $item_content = _leech_truncate_text($item_content, variable_get(leech_page_items_custom_length_teaser, 600), '', false);
+ $item_content = _leech_htmlcorrector($item_content);
+ $item->links['leech_fullnode'] = array (
+ 'title' => t('Read more'),
+ 'href' => drupal_get_path_alias('node/'. $item->nid));
+ $item->links = array_merge($item->links, module_invoke_all('link', 'node', $item, true));
+ return theme('leech_item_custom_format', $item, $item_content);
+}
+
+/**
+ * Truncates text.
+ *
+ * Cuts a string to the length of $length and replaces the last characters
+ * with the ending if the text is longer than length.
+ *
+ * @param string $text String to truncate.
+ * @param integer $length Length of returned string, including ellipsis.
+ * @param string $ending Ending to be appended to the trimmed string.
+ * @param boolean $exact If false, $text will not be cut mid-word
+ * @return string Trimmed string.
+ */
+function _leech_truncate_text($text, $length = 600, $ending = '', $exact = false) {
+ if (strlen(preg_replace('/<.*?>/', '', $text)) <= $length) {
+ return $text;
+ }
+
+ preg_match_all('/(<.+?>)?([^<>]*)/s', $text, $lines, PREG_SET_ORDER);
+ $total_length = 0;
+ $open_tags = array();
+ $truncate = '';
+ foreach ($lines as $line_matchings) {
+ if (!empty($line_matchings[1])) {
+ if (preg_match('/^<(\s*.+?\/\s*|\s*(img|br|input|hr|area|base|basefont|col|frame|isindex|link|meta|param)(\s.+?)?)>$/is', $line_matchings[1])) {
+ } elseif (preg_match('/^<\s*\/([^\s]+?)\s*>$/s', $line_matchings[1], $tag_matchings)) {
+ $pos = array_search($tag_matchings[1], $open_tags);
+ if ($pos !== false) {
+ unset($open_tags[$pos]);
+ }
+ } elseif (preg_match('/^<\s*([^\s>!]+).*?>$/s', $line_matchings[1], $tag_matchings)) {
+ array_unshift($open_tags, strtolower($tag_matchings[1]));
+ }
+ $truncate .= $line_matchings[1];
+ }
+
+ $content_length = strlen(preg_replace('/&[0-9a-z]{2,8};|[0-9]{1,7};|[0-9a-f]{1,6};/i', ' ', $line_matchings[2]));
+ if ($total_length + $content_length > $length) {
+ $left = $length - $total_length;
+ $entities_length = 0;
+ if (preg_match_all('/&[0-9a-z]{2,8};|[0-9]{1,7};|[0-9a-f]{1,6};/i', $line_matchings[2], $entities, PREG_OFFSET_CAPTURE|PREG_PATTERN_ORDER)) {
+ foreach ($entities[0] as $entity) {
+ if ($entity[1] + 1 - $entities_length <= $left) {
+ $left--;
+ $entities_length += strlen($entity[0]);
+ } else {
+ break;
+ }
+ }
+ }
+ $truncate .= substr($line_matchings[2], 0, $left + $entities_length);
+ break;
+ } else {
+ $truncate .= $line_matchings[2];
+ $total_length += $content_length;
+ }
+ if ($total_length >= $length) {
+ break;
+ }
+ }
+
+ if (!$exact) {
+ $periodpos = strrpos($truncate, '. ');
+ if ($periodpos === FALSE ) {
+ $periodpos = strpos($text, '.');
+ if($periosdpos !== FALSE) {
+ $truncate = substr($text, 0, $periodpos+1);
+ }
+ else {
+ $truncate = $text;
+ }
+ }
+ else {
+ $truncate = substr($truncate, 0, $periodpos+1);
+ }
+ }
+
+ $truncate = rtrim($truncate);
+
+ if (!empty($inline)) {
+ $truncate .= " " . $inline;
+ }
+
+ foreach ($open_tags as $tag) {
+ $truncate .= '' . $tag . '>';
+ }
+
+ if ( !empty($ending) ) {
+ $truncate .= $ending;
+ }
+
+ return $truncate;
+}
+
+function _leech_htmlcorrector($text) {
+ // Prepare tag lists.
+ static $no_nesting, $single_use;
+ if (!isset($no_nesting)) {
+ // Tags which cannot be nested but are typically left unclosed.
+ $no_nesting = drupal_map_assoc(array('li', 'p', 'div'));
+
+ // Single use tags in HTML4
+ $single_use = drupal_map_assoc(array('base', 'meta', 'link', 'hr', 'br', 'param', 'img', 'area', 'input', 'col', 'frame'));
+ }
+
+ // Properly entify angles.
+ $text = preg_replace('!<([^a-zA-Z/])!', '<\1', $text);
+
+ // Split tags from text.
+ $split = preg_split('/<([^>]+?)>/', $text, -1, PREG_SPLIT_DELIM_CAPTURE);
+ // Note: PHP ensures the array consists of alternating delimiters and literals
+ // and begins and ends with a literal (inserting $null as required).
+
+ $tag = false; // Odd/even counter. Tag or no tag.
+ $stack = array();
+ $output = '';
+ foreach ($split as $value) {
+ // Process HTML tags.
+ if ($tag) {
+ list($tagname) = explode(' ', strtolower($value), 2);
+ // Closing tag
+ if ($tagname{0} == '/') {
+ $tagname = substr($tagname, 1);
+ // Discard XHTML closing tags for single use tags.
+ if (!isset($single_use[$tagname])) {
+ // See if we possibly have a matching opening tag on the stack.
+ if (in_array($tagname, $stack)) {
+ // Close other tags lingering first.
+ do {
+ $output .= ''. $stack[0] .'>';
+ } while (array_shift($stack) != $tagname);
+ }
+ // Otherwise, discard it.
+ }
+ }
+ // Opening tag
+ else {
+ // See if we have an identical 'no nesting' tag already open and close it if found.
+ if (count($stack) && ($stack[0] == $tagname) && isset($no_nesting[$stack[0]])) {
+ $output .= ''. array_shift($stack) .'>';
+ }
+ // Push non-single-use tags onto the stack
+ if (!isset($single_use[$tagname])) {
+ array_unshift($stack, $tagname);
+ }
+ // Add trailing slash to single-use tags as per X(HT)ML.
+ else {
+ $value = rtrim($value, ' /') .' /';
+ }
+ $output .= '<'. $value .'>';
+ }
+ }
+ else {
+ // Passthrough all text.
+ $output .= $value;
+ }
+ $tag = !$tag;
+ }
+ // Close remaining tags.
+ while (count($stack) > 0) {
+ $output .= ''. array_shift($stack) .'>';
+ }
+ return $output;
+}
+
/**
* Menu callback; Remove items.
*/
@@ -714,7 +1047,7 @@ function leech_form_alter($form_id, &$fo
if (user_access('administer nodes')) {
// don't allow regular user's to "steal fame" :)
$feeds = array();
- $result = db_query(db_rewrite_sql('SELECT n.nid, n.title FROM {node} n, {leech_news_feed} f WHERE f.nid = n.nid'));
+ $result = db_query(db_rewrite_sql('SELECT n.nid, n.title FROM {node} n INNER JOIN {leech_news_feed} f ON f.nid = n.nid'));
while ($temp = db_fetch_array($result)) {
$feeds[$temp['nid']] = $temp['title'];
}
@@ -994,8 +1327,14 @@ function leech_link($type, $node = NULL,
($teaser && $show == LEECH_SHOW_LINK_TEASER_ONLY) ||
(!$teaser && $show == LEECH_SHOW_LINK_PAGE_ONLY)) {
if ($node->leech_news_item) {
+ if(variable_get('leech_originalarticle_popup', FALSE)) {
+ $links['leech_link_full_article'] = array('title' => t('Read original article.'), 'href' => $node->leech_news_item->link, 'attributes'=>array('onclick'=>'return leech_show_articleoriginal(this, ' . $node->nid . ')'));
+ }
+ else {
$links['leech_link_full_article'] = array('title' => t('Read original article.'), 'href' => $node->leech_news_item->link);
}
+
+ }
if ($node->leech_news) {
$links['leech_visit_site'] = array('title' => t('Visit site'), 'href' => $node->leech_news->link);
}
@@ -1071,11 +1410,10 @@ function leech_cron() {
}
// Delete too old items
- $result = db_query("SELECT f.items_delete, n.created, i.nid
- FROM {node} AS n, {leech_news_item} AS i, {leech_news_feed} AS f
- WHERE ( n.nid = i.nid AND
- f.nid = i.fid)"
- );
+ $sql = 'SELECT f.items_delete, n.created, i.nid FROM {node} n ';
+ $sql .= 'INNER JOIN {leech_news_item} i ON n.nid = i.nid ';
+ $sql .= 'INNER JOIN {leech_news_feed} f ON f.nid = i.fid ';
+ $result = db_query($sql);
$now = time();
while ($node = db_fetch_object($result)) {
if (abs($now - $node->created) > $node->items_delete) {
@@ -1240,7 +1578,7 @@ function leech_validate(&$node, $form =
if (trim($form['leech']['url']['#value']) == '') {
return;
}
- $result = db_query("SELECT l.nid, n.title FROM {node} n, {leech} l WHERE l.url = '%s' AND l.nid = n.nid", $form['leech']['url']['#value']);
+ $result = db_query("SELECT l.nid, n.title FROM {node} n INNER JOIN {leech} l ON l.nid = n.nid WHERE l.url = '%s' ", $form['leech']['url']['#value']);
while ($leech = db_fetch_object($result)) {
if ($leech->nid != $node->nid) {
$link = l($leech->title, "node/{$leech->nid}");
@@ -1433,6 +1771,22 @@ function leech_view(&$node, $teaser = FA
$node->content['leech_links'] = array('#value' => $themed_links, '#weight' => 10);
}
}
+ if(variable_get('leech_page_items_format', 'full')=='custom') {
+ $truncated_text = $node->content['body']['#value'];
+ if($teaser) {
+ $truncated_text = _leech_htmlcorrector($node->body);
+ $truncated_text = _leech_truncate_text($truncated_text, variable_get('leech_page_items_custom_length_teaser', 600), '', false);
+ $truncated_text = _leech_htmlcorrector($truncated_text);
+ }
+ else if($page) {
+ $truncated_text = _leech_htmlcorrector($node->body);
+ $truncated_text = _leech_truncate_text($truncated_text, variable_get('leech_page_items_custom_length_body', 600), '', false);
+ $truncated_text = _leech_htmlcorrector($truncated_text);
+ }
+ $node->content['body']['#value'] = $truncated_text;
+ $node->teaser = $truncated_text;
+ $node->body = $truncated_text;
+ }
}
if (!isset($node->leech)) {
@@ -1448,6 +1802,7 @@ function leech_view(&$node, $teaser = FA
$output .= theme('table', array(), $rows);
$node->content['leech_stat'] = array('#value' => $output, '#weight' => 10);
$teaser->content['leech_stat'] = array('#value' => $output, '#weight' => 10);
+
}
/**
@@ -1523,7 +1878,7 @@ function leech_page_feed_list() {
* Menu callback; Generates an OPML representation of all feeds.
*/
function leech_page_opml() {
- $result = db_query(db_rewrite_sql('SELECT n.nid, n.title, l.url FROM {node} n, {leech} l WHERE l.nid = n.nid ORDER BY n.title ASC'));
+ $result = db_query(db_rewrite_sql('SELECT n.nid, n.title, l.url FROM {node} n INNER JOIN {leech} l ON l.nid = n.nid ORDER BY n.title ASC'));
// should we do this?: $result = db_query(db_rewrite_sql('SELECT n.nid, n.title, l.url FROM {node} n, {leech} l, {leech_news_feed} f WHERE f.nid = n.nid AND l.nid = f.nid ORDER BY n.title ASC'));
$output = '';
while ($leech = db_fetch_object($result)) {
@@ -2202,7 +2557,7 @@ function _leech_news_save_items(&$node)
$promoted = array();
$promoted_changed = FALSE;
if ($node->leech_news->items_promote != 1000000000 && $node->leech_news->items_promote != 0) {
- $result = db_query('SELECT i.nid AS nid, n.created AS created FROM {node} n, {leech_news_item} i WHERE i.fid = %d AND i.nid = n.nid AND n.status = 1 AND n.promote = 1 ORDER BY n.created ASC', $node->nid);
+ $result = db_query('SELECT i.nid AS nid, n.created AS created FROM {node} n INNER JOIN {leech_news_item} i ON i.nid = n.nid WHERE i.fid = %d AND n.status = 1 AND n.promote = 1 ORDER BY n.created ASC', $node->nid);
while ($temp = db_fetch_array($result)) {
$promoted[$temp['nid']] = $temp['created'];
}
@@ -2259,7 +2614,7 @@ function _leech_news_save_items(&$node)
$entry = db_fetch_object(db_query("SELECT nid FROM {leech_news_item} WHERE link = '%s' AND fid = %d", $item->link, $node->nid));
}
else {
- $entry = db_fetch_object(db_query("SELECT n.nid AS nid FROM {node} n, {leech_news_item} i WHERE i.fid = %d AND i.nid = n.nid AND n.title = '%s'", $node->nid, $item->title));
+ $entry = db_fetch_object(db_query("SELECT n.nid AS nid FROM {node} n INNER JOIN {leech_news_item} i ON i.nid = n.nid WHERE i.fid = %d AND n.title = '%s'", $node->nid, $item->title));
}
if (isset($entry) && isset($entry->nid)) {
if (!$node->leech_news->items_update) {
@@ -2344,6 +2699,11 @@ function _leech_news_save_items(&$node)
// Temporary properties
$edit->leech_news_item->feed_data = &$node->leech->connection->news_feed;
+ if(module_exists('localizernode')) {
+ $feed_language = localizernode_findbynid($node->nid);
+ unset($edit->localizernode_pid);
+ $edit->localizernode_locale = $feed_language['locale'];
+ }
if ($errors = node_template_save($edit)) {
watchdog('leech', t('Could not save %type node %title from feed: %feed.', array('%type' => t($edit->type), '%title' => $edit->title, '%feed' => $node->title)), WATCHDOG_ERROR, l(t('view'), 'node/'. $node->nid));
}
@@ -2401,7 +2761,7 @@ function _leech_news_save_items(&$node)
$range = count($promoted) - $node->leech_news->items_promote;
// If there is less promoted items than needed we have to create new list of promoted
if ($range < 0) {
- $result = db_query_range('SELECT n.nid, n.created FROM {node} n, {leech_news_item} i WHERE n.status = 1 AND n.nid = i.nid AND i.fid = %d ORDER BY n.created DESC', $node->nid, 0, $node->leech_news->items_promote);
+ $result = db_query_range('SELECT n.nid, n.created FROM {node} n INNER JOIN {leech_news_item} i ON n.nid = i.nid WHERE n.status = 1 AND i.fid = %d ORDER BY n.created DESC', $node->nid, 0, $node->leech_news->items_promote);
while ($temp = db_fetch_object($result)) {
$promoted[$temp->nid] = $temp->created;
}
@@ -2805,3 +3165,110 @@ function _leech_news_pass_on_taxonomy(&$
drupal_set_message("Taxonomy of ".count($updated)." child feed item(s) updated in ".timer_read("taxpass")." ms", "status");
timer_stop("taxpass");
}
+
+function leech_nodebody() {
+ $nid = $_GET['nid'];
+ $node = node_load($nid);
+ echo '' . $node->body . '
';
+ echo '';
+ exit;
+}
+
+function leech_articleoriginal() {
+ $nid = $_GET['nid'];
+ $node = node_load($nid);
+ leech_statistic($nid);
+ echo '';
+ echo '';
+ echo '';
+ echo '
';
+ exit;
+}
+
+function leech_statistic($nid) {
+ global $user;
+
+ if (variable_get('statistics_count_content_views', 0)) {
+ // We are counting content views.
+ if (is_numeric($nid)) {
+ // A node has been viewed, so update the node's counters.
+ db_query('UPDATE {node_counter} SET daycount = daycount + 1, totalcount = totalcount + 1, timestamp = %d WHERE nid = %d', time(), $nid);
+ // If we affected 0 rows, this is the first time viewing the node.
+ if (!db_affected_rows()) {
+ // We must create a new row to store counters for the new node.
+ db_query('INSERT INTO {node_counter} (nid, daycount, totalcount, timestamp) VALUES (%d, 1, 1, %d)', $nid, time());
+ }
+ }
+ }
+ if ((variable_get('statistics_enable_access_log', 0)) && (module_invoke('throttle', 'status') == 0)) {
+ // Log this page access.
+ db_query("INSERT INTO {accesslog} (title, path, url, hostname, uid, sid, timer, timestamp) values('%s', '%s', '%s', '%s', %d, '%s', %d, %d)", strip_tags(drupal_get_title()), 'node/' . $nid, referer_uri(), $_SERVER['REMOTE_ADDR'], $user->uid, session_id(), timer_read('page'), time());
+ }
+}
+
+
+function leech_articlepreview($nid) {
+ $node = node_load($nid);
+
+ $o = '';
+ $o .= '' . drupal_get_title() . ' ';
+ $o .= '';
+ $o .= ' ';
+ $o .= ' ';
+ $o .= ' ';
+ $o .= ' ';
+ $o .= '';
+
+ echo $o;
+ exit();
+}
+
+function leech_articlepreviewheader($nid) {
+ $o = '';
+ $o .= '' . drupal_get_title() . ' ';
+ $o .= '';
+ $o .= 'Logo, links, tools';
+ $o .= '';
+ $o .= '';
+ echo $o;
+ exit();
+}
\ No newline at end of file
diff -urpN leech-orig/leech.module~ leech/leech.module~
--- leech-orig/leech.module~ 1970-01-01 01:00:00.000000000 +0100
+++ leech/leech.module~ 2007-12-31 15:26:10.000000000 +0100
@@ -0,0 +1,3281 @@
+
+ Based on parts of Aggregator2 module,
+ Also depends on other modules from Drupal basic distribution and, in some cases, contains parts of their code.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License.
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY.
+
+ See the LICENSE file for more details.
+*/
+
+// Permissions
+define('LEECH_PERM_CREATE', 'create feed');
+define('LEECH_PERM_EDIT_OWN', 'edit own feeds');
+define('LEECH_PERM_REFRESH_OWN', 'manually leech data');
+define('LEECH_PERM_ACCESS', 'access feeds');
+define('LEECH_NEWS_PERM_EDIT_OWN_ITEM', 'edit own news items');
+
+define("LEECH_SHOW_LINK_ALWAYS", 0);
+define("LEECH_SHOW_LINK_NEVER", 1);
+define("LEECH_SHOW_LINK_TEASER_ONLY", 2);
+define("LEECH_SHOW_LINK_PAGE_ONLY", 3);
+define("LEECH_SHOW_LINK_IN_LINKS", 1);
+define("LEECH_SHOW_LINK_INLINE", 2);
+
+/**
+ * Implementation of hook_help().
+ */
+function leech_help($section) {
+ switch ($section) {
+ case 'admin/help#leech':
+ return t('Feed aggretagor, creates nodes from RSS or ATOM feeds.');
+ }
+}
+
+/**
+ * Implementation of hook_perm().
+ */
+function leech_perm() {
+ return array(LEECH_PERM_CREATE,
+ LEECH_PERM_EDIT_OWN,
+ LEECH_PERM_REFRESH_OWN,
+ LEECH_PERM_ACCESS,
+ LEECH_NEWS_PERM_EDIT_OWN_ITEM);
+}
+
+/**
+ * Implementation of hook_menu().
+ * heads up: there are a couple of renamed paths here, old paths are kept
+ * for a while for backwards compatibility. check out what's new and change your
+ * site accordingly.
+ * @todo move deprecated paths to bottom of page, remove not used paths
+ */
+function leech_menu($may_cache) {
+ drupal_add_js('misc/drupal.js', 'core', 'header', FALSE);
+ drupal_add_js('misc/jquery.js', 'core', 'header', FALSE);
+ drupal_add_js(drupal_get_path('module', 'leech') .'/leech.js', 'module', 'header', FALSE);
+ drupal_add_css(drupal_get_path('module', 'leech') .'/leech.css', 'module');
+
+ static $pass = FALSE;
+ if(!$pass) {
+ if(module_exists('community_tags_inline') && $format == 'custom') {
+ drupal_add_js('misc/jquery.js', 'core', 'header', FALSE);
+ drupal_add_js('misc/autocomplete.js', 'core', 'header', FALSE);
+ drupal_add_css(drupal_get_path('module', 'tagadelic') .'/tagadelic.css', 'module');
+ drupal_add_css(drupal_get_path('module', 'community_tags') .'/community_tags.css', 'module');
+ drupal_add_js(drupal_get_path('module', 'community_tags_inline') . '/js/community_tags_inline.js', 'module', 'header', FALSE);
+ }
+
+ if(module_exists('vote_up_down') && $format == 'custom') {
+ drupal_add_css(drupal_get_path('module', 'vote_up_down') .'/vote_up_down.css');
+ drupal_add_js(drupal_get_path('module', 'vote_up_down') . '/ajax_vote_up_down.js');
+ }
+
+ $settings = array('leech_communityTagsInline' =>
+ array(
+ 'urlForm' => url('community_tags_inline/tag_form/'),
+ 'urlJS' => url('community_tags_inline/tag_form_js/'),
+ ),
+ 'leech' =>
+ array(
+ 'loading_animation' => base_path() . drupal_get_path('module', 'leech') .'/loading_animation.gif',
+ 'nodebody_url' => url('leech/nodebody/'),
+ 'articleoriginal_url' => url('leech/articleoriginal/'),
+ )
+ );
+ drupal_add_js($settings, 'setting');
+
+ $pass = TRUE;
+ }
+
+ $items = array();
+
+ if ($may_cache) {
+ // DEPRECATED, use leech/feed instead
+ $items[] = array('path' => 'leech/list', 'title' => t('Leech'),
+ 'callback' => 'leech_page_feed_list', 'access' => user_access(LEECH_PERM_ACCESS),
+ 'type' => MENU_CALLBACK);
+ $items[] = array('path' => 'admin/content/leech', 'title' => t('Manage feeds'),
+ 'callback' => 'leech_page_admin', 'description' => t('Manage leech module feed subscriptions.'),);
+ // DEPRECATED, use leech/feed without any further argument instead
+ $items[] = array('path' => 'leech/sources', 'title' => t('sources'),
+ 'callback' => 'leech_news_page_default', 'access' => user_access(LEECH_PERM_ACCESS),
+ 'type' => MENU_CALLBACK);
+ // DEPRECATED, use leech/feed/opml instead
+ $items[] = array('path' => 'leech/sources/opml', 'title' => t('opml'),
+ 'callback' => 'leech_page_opml', 'access' => user_access(LEECH_PERM_ACCESS),
+ 'type' => MENU_CALLBACK);
+ $items[] = array('path' => 'leech/feed/opml', 'title' => t('opml'),
+ 'callback' => 'leech_page_opml', 'access' => user_access(LEECH_PERM_ACCESS),
+ 'type' => MENU_CALLBACK);
+ // TODO: find a nice way to allow refresh only to feed owner
+ $items[] = array('path' => 'leech/refresh', 'title' => t('refresh data'),
+ 'callback' => 'leech_page_refresh', 'access' => user_access(LEECH_PERM_REFRESH_OWN),
+ 'type' => MENU_CALLBACK);
+ $items[] = array('path' => 'leech/get/form', 'title' => t('get addons form'),
+ 'callback' => 'leech_get_form', 'access' => user_access(LEECH_PERM_CREATE),
+ 'type' => MENU_CALLBACK);
+ $items[] = array('path' => 'leech.js', 'title' => t('javascript file'),
+ 'callback' => 'leech_javascript', 'access' => user_access(LEECH_PERM_CREATE),
+ 'type' => MENU_CALLBACK);
+ // DEPRECATED, use leech/feed instead
+ $items[] = array('path' => 'leech_news/feed', 'title' => t('All feeds'),
+ 'callback' => 'leech_news_page_default', 'access' => user_access(LEECH_PERM_ACCESS),
+ 'type' => MENU_CALLBACK);
+ $items[] = array('path' => 'leech/feed', 'title' => t('All feeds'),
+ 'callback' => 'leech_news_page_default', 'access' => user_access(LEECH_PERM_ACCESS));
+ // DEPRECATED, use leech/remove_items instead
+ $items[] = array('path' => 'leech_news/remove', 'title' => t('leech news'),
+ 'callback' => 'leech_news_page_delete_confirm_page', 'access' => user_access(LEECH_NEWS_PERM_EDIT_OWN_ITEM),
+ 'type' => MENU_CALLBACK);
+ $items[] = array('path' => 'leech/remove_items', 'title' => t('leech news'),
+ 'callback' => 'leech_news_page_delete_confirm_page', 'access' => user_access(LEECH_NEWS_PERM_EDIT_OWN_ITEM),
+ 'type' => MENU_CALLBACK);
+ $items[] = array('path' => 'admin/settings/leech', 'title' => t('Leech'),
+ 'callback' => 'drupal_get_form', 'callback arguments' => array('leech_admin_settings'), 'description' => t('Configure leech module.'),);
+
+ $items[] = array(
+ 'path' => 'leech/nodebody',
+ 'title' => t('Leech node body'),
+ 'callback' => 'leech_nodebody',
+ 'access' => user_access('access content'),
+ 'type' => MENU_CALLBACK);
+
+ $items[] = array(
+ 'path' => 'leech/articleoriginal',
+ 'title' => t('Leech article original'),
+ 'callback' => 'leech_articleoriginal',
+ 'access' => user_access('access content'),
+ 'type' => MENU_CALLBACK);
+
+ $items[] = array(
+ 'path' => 'leech/articlepreview',
+ 'title' => t('Leech article preview'),
+ 'callback' => 'leech_articlepreview',
+ 'access' => user_access('access content'),
+ 'type' => MENU_CALLBACK);
+
+ $items[] = array(
+ 'path' => 'leech/articlepreviewheader',
+ 'title' => t('Leech article preview header'),
+ 'callback' => 'leech_articlepreviewheader',
+ 'access' => user_access('access content'),
+ 'type' => MENU_CALLBACK);
+ }
+
+ return $items;
+}
+
+/**
+ * prints view of latest cron times
+ */
+function _leech_cron_times_view($crontimes = array()) {
+ $output = '';
+
+ $last_time = 0;
+ if (count($crontimes) > 1) {
+ $output .= '
'.t('Latest').' '.(count($crontimes)-1).' '.t('cron runs').'
';
+ foreach ($crontimes as $t) {
+ if ($last_time != 0) {
+ $output .= '
';
+ $output .= format_date($t, 'large');
+ $output .= ', '.t('after').' '.format_interval($t-$last_time);
+ $output .= '
';
+ }
+ $last_time = $t;
+ }
+ }
+ else {
+ $output .= '
'.t('Latest').' '.t('cron runs').'
';
+ $output .= t('Cron has not been run.');
+ }
+ $output .= '
';
+
+ return $output;
+}
+
+/**
+ * Implementation of hook_settings().
+ */
+function leech_admin_settings() {
+ $form = array();
+
+ if (!function_exists('curl_init')) {
+ drupal_set_message(t('Some features may be disabled because the cURL module for PHP is not available.', array('@curl' => url('http://php.net/curl'))), 'error');
+ }
+
+ $form['leech_display'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Display settings'),
+ '#tree' => FALSE,
+ );
+ $form['leech_display']['leech_news_show_feed_link'] = array(
+ '#type' => 'select',
+ '#title' => t('Show link to feed with each item'),
+ '#default_value' => variable_get('leech_news_show_feed_link', 0),
+ '#options' => array(0 => t('Don\'t show'),
+ LEECH_SHOW_LINK_IN_LINKS => t('In links list'),
+ LEECH_SHOW_LINK_INLINE => t('Inline in body/teaser')),
+ '#description' => t('If "In links list" selected, Leech News will show link to source feed on each item in links list, if "Inline in body/teaser" selected, it will show this link in the feed item\'s body.'));
+
+ $form['leech_display']['leech_news_show_items_link'] = array(
+ '#type' => 'select',
+ '#title' => t('Show link to items with each feed'),
+ '#default_value' => variable_get('leech_news_show_items_link', 0),
+ '#options' => array(0 => t('Don\'t show'),
+ LEECH_SHOW_LINK_IN_LINKS => t('In links list')) ,
+ '#description' => t('If "In links list" selected, Leech News will show "items" link with each feed. It will point to list of all items created by that feed.'));
+
+ $form['leech_blacklist'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Blacklist'),
+ '#tree' => FALSE,
+ );
+ $form['leech_blacklist']['leech_blacklist_url'] = array(
+ '#type' => 'textarea',
+ '#title' => t('Blacklist URLs'),
+ '#default_value' => variable_get('leech_blacklist_url', ''),
+ '#rows' => 5,
+ '#description' => t('One entry per line. You can enter full URLs or domain names only. You can also enter regular expression (find out more about what it is at %link. more examples can be found also at %link2). For example "http://some.url.com/some/page.html" will blacklist that specific URL. ".url.com" will blacklist all URLs from url.com domain, and all it\'s subdomains. "some.url.com" will blacklist all URLs from "some" subdomain. "/^ftp\:\/\//" will blacklist any ftp:// URL. Leech module will not download any data from URL which matches any of the rules on blacklist.', array('%link' => l('http://www.php.net/manual/en/reference.pcre.pattern.syntax.php', 'http://www.php.net/manual/en/reference.pcre.pattern.syntax.php'), '%link2' => l('http://www.php.net/manual/en/function.preg-match.php', 'http://www.php.net/manual/en/function.preg-match.php'))));
+
+ $form['leech_url_profile'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('URL profile'),
+ '#tree' => FALSE,
+ );
+ $msg = ''.t('The URL profile module allows you to surf feed items per original source and optionally retrieve information from third parties such as Alexa or Technorati.').'
';
+ if (module_exists('url_profile')) {
+ $msg .= ''.t('URL profile module detected. Leech feed item URLs are being profiled.').'
';
+ }
+ else {
+ $msg .= ''.t('URL profile module not installed. ').'
';
+ }
+ $form['leech_url_profile']['detected'] = array(
+ '#type' => 'markup',
+ '#value' => $msg,
+ );
+
+ $form['leech_og'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Organic groups'),
+ '#tree' => FALSE,
+ );
+ if (module_exists('og')) {
+ $msg = ''.t('Organic groups (og) module detected. Leech feeds are passing on their group association to their feed items.').'
';
+ }
+ else {
+ $msg = ''.t('Organic groups (og) module not installed. ').'
';
+ }
+ $form['leech_og']['detected'] = array(
+ '#type' => 'markup',
+ '#value' => $msg,
+ );
+
+ $form['leech_advanced'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Advanced leech settings'),
+ '#collapsible' => TRUE,
+ '#collapsed' => TRUE,
+ '#tree' => FALSE,
+ );
+ $parsers = array('leech_news' => 'leech_news');
+ foreach (module_implements('parse_news_feed') as $name) {
+ $parsers[$name] = $name;
+ }
+ $form['leech_advanced']['leech_news_parser'] = array(
+ '#type' => 'select',
+ '#title' => t('Select parser'),
+ '#default_value' => variable_get('leech_news_parser', 'leech_news'),
+ '#options' => $parsers,
+ '#description' => t('Select which parser to use to parse RSS/ATOM feed.'));
+ $form['leech_advanced']['leech_news_original_links'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Use source link'),
+ '#default_value' => variable_get('leech_news_original_links', 1),
+ '#description' => t('Use link to original source of article when possible - usually the source link is preferrable.'),
+ );
+ $form['leech_advanced']['leech_news_verbose'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Verbose output to watchdog'),
+ '#default_value' => variable_get('leech_news_verbose', 0),
+ '#description' => t('Check if you would like to have more verbose output about leech on the %watchdoglink.', array('%watchdoglink' => l('watchdog', 'admin', array('title' => 'watchdog')))),
+ );
+ if (module_exists('taxonomy')) {
+ $form['leech_advanced']['leech_news_pass_on_taxonomy'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Pass on taxonomy from feed to feed items'),
+ '#default_value' => variable_get('leech_news_pass_on_taxonomy', 0),
+ '#description' => t('If enabled, taxonomy of a feed node will be passed on
+ to its existing and future child feed items. Only those
+ taxonomies will get passed on, that are enabled for both,
+ feed and feed item.'),
+ );
+ }
+ $form['leech_advanced']['cron'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Cron settings'),
+ '#tree' => FALSE,
+ );
+
+ // list last n times cron was called
+ $form['leech_advanced']['cron']['leech_cron_times_overview'] = array(
+ '#type' => 'markup',
+ '#value' => _leech_cron_times_view(variable_get('leech_cron_times', array())),
+ );
+
+ // how many leeches to update at one cron run
+ $leech_count['9999999'] = t('All');
+ $leech_count = drupal_map_assoc(array(0, 1, 2, 3, 4, 5, 10, 15, 20, 25, 50, 100));
+ $form['leech_advanced']['cron']['leech_cron_count'] = array(
+ '#type' => 'select',
+ '#title' => t('Update count'),
+ '#default_value' => variable_get('leech_cron_count', 5),
+ '#options' => $leech_count,
+ '#description' => t('Select how many leeches can be updated at one cron run.'));
+ // how long sleep interval should be
+ $interval = drupal_map_assoc(array(0, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15));
+ $form['leech_advanced']['cron']['leech_sleep_interval'] = array(
+ '#type' => 'select',
+ '#title' => t('Sleep time'),
+ '#default_value' => variable_get('leech_sleep_interval', 0),
+ '#options' => $leech_count,
+ '#description' => t('Seconds that module waits between updating feeds and between saving feed items.'));
+
+ $modules = module_implements("node_assign_keywords");
+ foreach ($modules as $module) {
+ $list .= $module .", ";
+ }
+ $modules = $list;
+ $form['leech_advanced']['leech_term_extraction'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Term extraction'),
+ '#tree' => FALSE,
+ "#description" => t("Currently the following modules do term extraction: %mod", array("%mod" => $modules)),
+ '#collapsible' => TRUE,
+ '#collapsed' => TRUE,
+ '#tree' => TRUE,
+ );
+
+ if (count($modules) > 0) {
+ $form['leech_advanced']['leech_term_extraction']['leech_terms_per_feed'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Select a vocabulary and query string for each leech'),
+ '#description' => t('The relevant terms in leech items will be added to the selected vocabulary'),
+ '#collapsible' => FALSE,
+ '#collapsed' => FALSE,
+ '#tree' => TRUE,
+ );
+ $select_voc = _yahoo_terms_vocab_select();
+ $current = variable_get('leech_term_extraction', 0);
+ $current = $current['leech_terms_per_feed'];
+ if (!is_array($current)) {
+ $current = array();
+ }
+ $result = db_query("SELECT n.nid, n.title, l.url FROM {node} n INNER JOIN {leech} l ON n.nid = l.nid ORDER BY n.title ASC");
+ while ($leech = db_fetch_object($result)) {
+ if (!isset($current[$leech->nid])) {
+ $current[$leech->nid] = array();
+ }
+ if (!isset($current[$leech->nid]['vocab'])) {
+ $current[$leech->nid]['vocab'] = variable_get('default_vocab_for_leech', FALSE);
+ }
+ $form['leech_advanced']['leech_term_extraction']['leech_terms_per_feed'][$leech->nid] = array(
+ '#type' => 'fieldset',
+ '#title' => $leech->title,
+ '#tree' => TRUE,
+ );
+ $form['leech_advanced']['leech_term_extraction']['leech_terms_per_feed'][$leech->nid]['vocab'] = array(
+ '#type' => 'select',
+ '#options' => $select_voc,
+ '#default_value' => $current[$leech->nid]['vocab'],
+ '#description' => $leech->url,
+ );
+ $form['leech_advanced']['leech_term_extraction']['leech_terms_per_feed'][$leech->nid]['query'] = array(
+ '#type' => 'textfield',
+ '#default_value' => isset($current[$leech->nid]['query']) ? $current[$leech->nid]['query'] : '',
+ '#description' => 'Query string for ' . $leech->url,
+ );
+ }
+ }
+
+ $formats = array (
+ 'teaser' => t('Teaser'),
+ 'custom' => t('Custom'),
+ );
+ $form['leech_page_items_format'] = array (
+ '#type' => 'select',
+ '#options' => $formats,
+ '#default_value' => variable_get('leech_page_items_format', 'full'),
+ '#title' => t('Items format for default page'),
+ );
+
+ $form['leech_page_items_custom_length_teaser'] = array (
+ '#type' => 'textfield',
+ '#default_value' => variable_get('leech_page_items_custom_length_teaser', 600),
+ '#title' => t('Item length (number of chars) for custom format teaser'),
+ );
+
+ $form['leech_page_items_custom_length_body'] = array (
+ '#type' => 'textfield',
+ '#default_value' => variable_get('leech_page_items_custom_length_body', 600),
+ '#title' => t('Item length (number of chars) for custom format body'),
+ );
+
+ $form['leech_originalarticle_popup'] = array (
+ '#type' => 'checkbox',
+ '#default_value' => variable_get('leech_originalarticle_popup', FALSE),
+ '#title' => t('Show the original article in a popup window'),
+ );
+
+ $formats = array (
+ 'popup' => t('In a popup'),
+ 'window' => t('In a window'),
+ );
+ $form['leech_originalwebsite_preview'] = array (
+ '#type' => 'select',
+ '#options' => $formats,
+ '#default_value' => variable_get('leech_originalwebsite_preview', 'popup'),
+ '#title' => t('How to show the preview of the original website'),
+ );
+
+ return system_settings_form($form);
+}
+
+/**
+ * url_profile hook - list urls to be url_profiled. interface to url_profile.module
+ */
+function leech_url_profile(&$object, $op, $arg = NULL) {
+
+ switch ($op) {
+ case 'list':
+
+
+ /*
+ no profiling for leech feeds - we could make this optional
+ if ($node->leech_news && $node->leech_news->link) {
+ $list[] = $node->leech_news->link;
+ }
+ */
+ $list = array();
+ // sometimes stuff comes in as array - todo: clean this up
+ if ($object->leech_news_item) {
+ if (isset($object->leech_news_item->link)) {
+ $list[] = $object->leech_news_item->link;
+ }
+ else if (isset($object->leech_news_item['link'])) {
+ $list[] = $object->leech_news_item['link'];
+ }
+ if (isset($object->leech_news_item->source_link)) {
+ $list[] = $object->leech_news_item->source_link;
+ }
+ else if (isset($object->leech_news_item['source_link'])) {
+ if (isset($object->leech_news_item['source_link'])) {
+ $list[] = $object->leech_news_item['source_link'];
+ }
+ }
+ }
+ return $list;
+ case 'list_matches':
+ $result = db_query ('SELECT DISTINCT li.nid, li.link as url
+ FROM {leech_news_item} li
+ JOIN {node} n ON n.nid = li.nid
+ WHERE li.link LIKE "%s%%"
+ AND li.link LIKE "%%%s%%" ',
+ $object->url, $object->criteria);
+ while ($feed_item = db_fetch_object($result)) {
+ $list[] = $feed_item;
+ }
+ return $list;
+ }
+}
+
+/**
+ * This function gives control of contents and functions on the link of 'full article'.
+ */
+function theme_leech_link_full_article($node) {
+ $link = $node->leech_news_item->link;
+ if (variable_get('leech_news_original_links', 0) && $node->leech_news->source_link) {
+ $link = $node->leech_news->source_link;
+ }
+ if(variable_get('leech_originalarticle_popup', FALSE)) {
+ return ''. t('original article') .' ';
+ }
+ else {
+ return ''. t('original article') .' ';
+ }
+}
+
+/**
+ * Menu callback; Generate a listing of feed items.
+ */
+function leech_news_page_default($nid = NULL) {
+ $output = '';
+
+ if ($nid != NULL && is_numeric($nid)) {
+ drupal_set_title(t('Feed'));
+ $feed = node_load($nid);
+ if ($feed && $feed->leech_news) {
+ $output .= node_view($feed, 1);
+ $result = pager_query(db_rewrite_sql('SELECT n.nid, n.sticky, n.created FROM {node} n INNER JOIN {leech_news_item} i ON i.nid = n.nid WHERE i.fid = %d AND n.status = 1 ORDER BY n.sticky DESC, n.created DESC'), variable_get('default_nodes_main', 10), 0, NULL, $feed->nid);
+ $format = variable_get('leech_page_items_format', 'full');
+
+ while ($node = db_fetch_object($result)) {
+ if($format == 'teaser') {
+ $output .= node_view(node_load($node->nid), true, false);
+ }
+ else if($format == 'custom') {
+ $output .= leech_item_custom_format($node->nid);
+ }
+ }
+ $output .= theme('pager', NULL, variable_get('default_nodes_main', 10));
+ }
+ else {
+ drupal_goto('node/'. $nid);
+ }
+ }
+ else {
+ // If there's no nid given, then show page with feed nodes
+ $result = pager_query(db_rewrite_sql('SELECT n.nid, n.sticky, n.created FROM {node} n INNER JOIN {leech_news_feed} f ON f.nid = n.nid WHERE n.status = 1 ORDER BY n.sticky DESC, n.created DESC'), variable_get('default_nodes_main', 10), 0, NULL);
+ while ($node = db_fetch_object($result)) {
+ $output .= node_view(node_load($node->nid), 1);
+ }
+ $output .= theme('pager', NULL, variable_get('default_nodes_main', 10));
+ }
+
+ return $output;
+}
+
+function theme_leech_item_custom_format($node, $node_content) {
+ $output = '';
+
+ if (!$node->status) {
+ $output = '
';
+ }
+
+ if (module_exists('taxonomy')) {
+ $terms = taxonomy_link('taxonomy terms', $node);
+ }
+
+ if(variable_get('leech_originalwebsite_preview', 'popup')=='popup') {
+ $node_link = l($node->title, drupal_get_path_alias('node/' . $node->nid), array('onclick'=>"return leech_show_articleoriginal(this, " . $node->nid . ");"), NULL, NULL, FALSE, TRUE);
+ }
+ else {
+ $node_link = l($node->title, 'leech/articlepreview/' . $node->nid, NULL, NULL, NULL, FALSE, TRUE);
+ }
+ $output .= t('!title by !name', array('!title' => '
'. $node_link .' ', '!name' => theme('username', $node)));
+
+ if (count($terms)) {
+ $output .= '
('. theme('links', $terms) .') ';
+ }
+
+ $node->content['body']['#value'] = $node_content;
+ $output .= '
' . drupal_render($node->content) . '
';
+
+ if ($node->links) {
+ $output .= '
'. theme('links', $node->links) .'
';
+ }
+
+ if (!$node->status) {
+ $output .= '
';
+ }
+
+ $output .= '
';
+
+ return $output;
+}
+
+function leech_item_custom_format($nid) {
+ $item = node_load($nid);
+ $item = node_build_content($item, true, false);
+ $item_content = _leech_htmlcorrector($item->body);
+ $item_content = _leech_truncate_text($item_content, variable_get(leech_page_items_custom_length_teaser, 600), '', false);
+ $item_content = _leech_htmlcorrector($item_content);
+ $item->links['leech_fullnode'] = array (
+ 'title' => t('Read more'),
+ 'href' => drupal_get_path_alias('node/'. $item->nid));
+ $item->links = array_merge($item->links, module_invoke_all('link', 'node', $item, true));
+ return theme('leech_item_custom_format', $item, $item_content);
+}
+
+/**
+ * Truncates text.
+ *
+ * Cuts a string to the length of $length and replaces the last characters
+ * with the ending if the text is longer than length.
+ *
+ * @param string $text String to truncate.
+ * @param integer $length Length of returned string, including ellipsis.
+ * @param string $ending Ending to be appended to the trimmed string.
+ * @param boolean $exact If false, $text will not be cut mid-word
+ * @return string Trimmed string.
+ */
+function _leech_truncate_text($text, $length = 600, $ending = '', $exact = false) {
+ if($text == "France is hit by transport upheavals as workers strike against President Nicolas Sarkozy's pension reforms.") {
+ $d=1;
+ }
+ else {
+ $d=0;
+ }
+
+ if (strlen(preg_replace('/<.*?>/', '', $text)) <= $length) {
+ return $text;
+ }
+
+ preg_match_all('/(<.+?>)?([^<>]*)/s', $text, $lines, PREG_SET_ORDER);
+ $total_length = 0;
+ $open_tags = array();
+ $truncate = '';
+ foreach ($lines as $line_matchings) {
+ if (!empty($line_matchings[1])) {
+ if (preg_match('/^<(\s*.+?\/\s*|\s*(img|br|input|hr|area|base|basefont|col|frame|isindex|link|meta|param)(\s.+?)?)>$/is', $line_matchings[1])) {
+ } elseif (preg_match('/^<\s*\/([^\s]+?)\s*>$/s', $line_matchings[1], $tag_matchings)) {
+ $pos = array_search($tag_matchings[1], $open_tags);
+ if ($pos !== false) {
+ unset($open_tags[$pos]);
+ }
+ } elseif (preg_match('/^<\s*([^\s>!]+).*?>$/s', $line_matchings[1], $tag_matchings)) {
+ array_unshift($open_tags, strtolower($tag_matchings[1]));
+ }
+ $truncate .= $line_matchings[1];
+ }
+
+ $content_length = strlen(preg_replace('/&[0-9a-z]{2,8};|[0-9]{1,7};|[0-9a-f]{1,6};/i', ' ', $line_matchings[2]));
+ if ($total_length + $content_length > $length) {
+ $left = $length - $total_length;
+ $entities_length = 0;
+ if (preg_match_all('/&[0-9a-z]{2,8};|[0-9]{1,7};|[0-9a-f]{1,6};/i', $line_matchings[2], $entities, PREG_OFFSET_CAPTURE|PREG_PATTERN_ORDER)) {
+ foreach ($entities[0] as $entity) {
+ if ($entity[1] + 1 - $entities_length <= $left) {
+ $left--;
+ $entities_length += strlen($entity[0]);
+ } else {
+ break;
+ }
+ }
+ }
+ $truncate .= substr($line_matchings[2], 0, $left + $entities_length);
+ break;
+ } else {
+ $truncate .= $line_matchings[2];
+ $total_length += $content_length;
+ }
+ if ($total_length >= $length) {
+ break;
+ }
+ }
+
+ if (!$exact) {
+ $periodpos = strrpos($truncate, '. ');
+ if ($periodpos === FALSE ) {
+ $periodpos = strpos($text, '.');
+ if($periosdpos !== FALSE) {
+ $truncate = substr($text, 0, $periodpos+1);
+ }
+ else {
+ $truncate = $text;
+ }
+ }
+ else {
+ $truncate = substr($truncate, 0, $periodpos+1);
+ }
+ }
+
+ $truncate = rtrim($truncate);
+
+ if (!empty($inline)) {
+ $truncate .= " " . $inline;
+ }
+
+ foreach ($open_tags as $tag) {
+ $truncate .= '' . $tag . '>';
+ }
+
+ if ( !empty($ending) ) {
+ $truncate .= $ending;
+ }
+
+ return $truncate;
+}
+
+function _leech_htmlcorrector($text) {
+ // Prepare tag lists.
+ static $no_nesting, $single_use;
+ if (!isset($no_nesting)) {
+ // Tags which cannot be nested but are typically left unclosed.
+ $no_nesting = drupal_map_assoc(array('li', 'p', 'div'));
+
+ // Single use tags in HTML4
+ $single_use = drupal_map_assoc(array('base', 'meta', 'link', 'hr', 'br', 'param', 'img', 'area', 'input', 'col', 'frame'));
+ }
+
+ // Properly entify angles.
+ $text = preg_replace('!<([^a-zA-Z/])!', '<\1', $text);
+
+ // Split tags from text.
+ $split = preg_split('/<([^>]+?)>/', $text, -1, PREG_SPLIT_DELIM_CAPTURE);
+ // Note: PHP ensures the array consists of alternating delimiters and literals
+ // and begins and ends with a literal (inserting $null as required).
+
+ $tag = false; // Odd/even counter. Tag or no tag.
+ $stack = array();
+ $output = '';
+ foreach ($split as $value) {
+ // Process HTML tags.
+ if ($tag) {
+ list($tagname) = explode(' ', strtolower($value), 2);
+ // Closing tag
+ if ($tagname{0} == '/') {
+ $tagname = substr($tagname, 1);
+ // Discard XHTML closing tags for single use tags.
+ if (!isset($single_use[$tagname])) {
+ // See if we possibly have a matching opening tag on the stack.
+ if (in_array($tagname, $stack)) {
+ // Close other tags lingering first.
+ do {
+ $output .= ''. $stack[0] .'>';
+ } while (array_shift($stack) != $tagname);
+ }
+ // Otherwise, discard it.
+ }
+ }
+ // Opening tag
+ else {
+ // See if we have an identical 'no nesting' tag already open and close it if found.
+ if (count($stack) && ($stack[0] == $tagname) && isset($no_nesting[$stack[0]])) {
+ $output .= ''. array_shift($stack) .'>';
+ }
+ // Push non-single-use tags onto the stack
+ if (!isset($single_use[$tagname])) {
+ array_unshift($stack, $tagname);
+ }
+ // Add trailing slash to single-use tags as per X(HT)ML.
+ else {
+ $value = rtrim($value, ' /') .' /';
+ }
+ $output .= '<'. $value .'>';
+ }
+ }
+ else {
+ // Passthrough all text.
+ $output .= $value;
+ }
+ $tag = !$tag;
+ }
+ // Close remaining tags.
+ while (count($stack) > 0) {
+ $output .= ''. array_shift($stack) .'>';
+ }
+ return $output;
+}
+
+/**
+ * Menu callback; Remove items.
+ */
+function leech_news_page_delete_confirm_page() {
+ return drupal_get_form('leech_news_page_delete_confirm', arg(2));
+}
+
+function leech_news_page_delete_confirm($nid) {
+ $feed = node_load($nid);
+ $form = array();
+ $result = db_query('SELECT n.title, n.nid FROM {node} n LEFT JOIN {leech_news_item} i ON i.nid = n.nid WHERE i.fid = %d ORDER BY n.title', $feed->nid);
+ $items = array();
+ while ($item = db_fetch_object($result)) {
+ $items[$item->nid] = $item->title;
+ }
+ $form['nodes'] = array(
+ '#type' => 'checkboxes',
+ '#title' => t('Delete following items:'),
+ '#default_value' => array_keys($items),
+ '#options' => $items);
+ return confirm_form($form,
+ t('Please confirm which items You really want to delete'),
+ 'node/'. $feed->nid, t('This action cannot be undone.'),
+ t('Delete'), t('Cancel') );
+}
+
+function leech_news_page_delete_confirm_submit() {
+ global $form_values;
+ foreach ($form_values['nodes'] as $nid => $value) {
+ if ($value == $nid) {
+ node_delete($nid);
+ }
+ }
+ return "/node";
+}
+
+/**
+ * Create an XML document header and tail for opml
+ */
+function _opml_skeleton($content) {
+ $output = "\n";
+ $output .= "\n";
+ $output .= "\n";
+ $output .= ''. variable_get('site_name', 'drupal') .' - '. variable_get('site_slogan', '') ." \n";
+ $output .= ''. gmdate('r') ." \n";
+ $output .= "\n";
+ $output .= "\n";
+ $output .= $content;
+ $output .= "\n";
+ $output .= " \n";
+ return $output;
+}
+
+/**
+ * Parse xml into feed data
+ */
+function _leech_news_parse($xml) {
+ $parser = variable_get('leech_news_parser', 'leech_news');
+ if ($parser == 'leech_news') {
+ include_once('leech_news_parser.inc');
+ }
+
+ if ($parser) {
+ $function = $parser .'_parse_news_feed';
+ return $function($xml);
+ }
+}
+
+/**
+ * Implementation of hook_form_alter().
+ */
+function leech_form_alter($form_id, &$form) {
+
+ // Add leech fields to node edit form
+ if ((strstr($form_id, "_node_form") !== FALSE || strstr($form_id, "leech") !== FALSE) && variable_get('leech_for_'. $form['#node']->type, 0)) {
+ $node = $form['#node'];
+ if (isset($form['body_filter']['body'])) {
+ $form['body_filter']['body']['#required'] = 0;
+ }
+ $form['leech'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Leech'),
+ '#collapsible' => TRUE,
+ '#collapsed' => FALSE,
+ '#tree' => TRUE
+ );
+ $form['leech']['nid'] = array(
+ '#type' => 'hidden',
+ '#value' => $node->nid,
+ '#attributes' => array('id' => 'edit-leech-nid')
+ );
+ drupal_add_js('?q=leech.js');
+ $form['leech']['url'] = array(
+ '#type' => 'textfield',
+ '#title' => t('URL'),
+ '#default_value' => $node->leech->url,
+ '#size' => 60,
+ '#maxlength' => 2048,
+ '#description' => t('URL from which data will be downloaded.'),
+ '#weight' => -99,
+ '#attributes' => array('onFocus' => 'leech_prepare_check_url(this)', 'onBlur' => 'leech_close_check_url(this)')
+ );
+ $period = drupal_map_assoc(array(0, 900, 1800, 3600, 7200, 10800, 21600, 32400, 43200, 64800, 86400, 172800, 259200, 604800, 1209600, 2419200), 'format_interval');
+ $period[0] = t('Freezed');
+ if (isset($node->leech->adaptive) && $node->leech->adaptive == TRUE) {
+ $form['leech']['refresh'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Frequency'),
+ '#default_value' => $node->leech->refresh,
+ '#description' => t('The current frequency at which new data will be downloaded. This is not editable while Adaptive mode is turned on.'),
+ '#attributes' => array('disabled' => 'true'),
+ '#weight' => -97
+ );
+ }
+ else {
+ $form['leech']['refresh'] = array(
+ '#type' => 'select',
+ '#title' => t('Frequency'),
+ '#default_value' => (isset($node->leech->refresh) ? $node->leech->refresh : 10800),
+ '#options' => $period,
+ '#description' => t('Frequency at which new data will be downloaded.'),
+ '#weight' => -97
+ );
+ }
+ $form['leech']['adaptive'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Adaptive'),
+ '#default_value' => isset($node->leech->adaptive) ? $node->leech->adaptive : TRUE,
+ '#description' => t('The module modifies continously the leech frequency according to the behaviour of the feed. More active feeds will be leeched more often and reverse too.')
+ );
+ // Add fields from other modules which want to work with us through leechapi
+ $form['leech']['addons'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Additional options'),
+ '#collapsible' => TRUE,
+ '#collapsed' => FALSE,
+ '#weight' => 1,
+ '#attributes' => array('id' => 'leech-fieldset'),
+ '#prefix' => '',
+ '#suffix' => '
'
+ );
+
+ // Mark if there was leech data with node or not
+ if (!$node->leech->nid) {
+ $form['leech']['is_new'] = array(
+ '#type' => 'hidden',
+ '#value' => 1
+ );
+ }
+
+ // since 4.7.2 (or .3) there is no easy way to get node type html field cause now it's ID is like: node-[type]-node-form
+ // so just create our own ;p
+ $form['leech']['node_type'] = array(
+ '#type' => 'hidden',
+ '#value' => $node->type
+ );
+
+
+ // Some values we may want to use
+ if (isset($node->leech->connection)) {
+ $form['leech']['mime'] = array('#type' => 'value', '#value' => $node->leech->mime);
+ $form['leech']['connection'] = array('#type' => 'value', '#value' => $node->leech->connection);
+ }
+
+ if ($node->leech->_prerender_id) {
+ // Hookup prerendering of addons part for our ajax magic ;]
+ if (!is_array($form['#pre_render'])) {
+ $form['#pre_render'] = array();
+ }
+ $form['#pre_render'][] = 'leech_pre_render_addons';
+ }
+ }
+ // "Workflow" form
+ if (isset($form['#node_type']) && 'node_type_form' == $form_id) {
+ $node_type = $form['old_type']['#value'];
+ $form['workflow']['leech_defs'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Default leech options'),
+ '#collapsible' => TRUE,
+ '#collapsed' => FALSE
+ );
+ $form['workflow']['leech_defs']['leech_for'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Enable leech'),
+ '#default_value' => variable_get('leech_for_'. $node_type, 0),
+ /*'#attributes' => array(
+ 'onclick' => 'Drupal.toggleClass(this.parentNode.parentNode.parentNode, "collapsed");',
+ )*/
+ );
+ /*if (!variable_get('leech_for_'. $node_type, 0)) {
+ $form['workflow']['leech_defs']['#attributes']['class'] = 'collapsed';
+ }*/
+ $period = drupal_map_assoc(array(0, 900, 1800, 3600, 7200, 10800, 21600, 32400, 43200, 64800, 86400, 172800, 259200, 604800, 1209600, 2419200), 'format_interval');
+ $period[0] = t('Freezed');
+ $form['workflow']['leech_defs']['leech_refresh'] = array (
+ '#type' => 'select',
+ '#title' => t('Update interval'),
+ '#default_value' => variable_get('leech_refresh_'.$node_type, 900),
+ '#options' => $period,
+ '#description' => t('The refresh interval indicating how often you want leech to download data.')
+ );
+ $form['workflow']['leech_defs']['leech_news_template'] = array(
+ '#type' => 'select',
+ '#title' => t('Template'),
+ '#options' => node_template_list(),
+ '#default_value' => variable_get('leech_news_template_'. $node_type, 0),
+ '#description' => t('Select which node template should be used as template for new items')
+ );
+ $form['workflow']['leech_defs']['leech_news_items_guid'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Generate GUIDs'),
+ '#default_value' => variable_get('leech_news_items_guid_'. $node_type, 0)
+ );
+ $form['workflow']['leech_defs']['leech_news_items_status'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Publish news items'),
+ '#default_value' => variable_get('leech_news_items_status_'. $node_type, 1)
+ );
+ $form['workflow']['leech_defs']['leech_news_items_update'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Update already existing news items'),
+ '#default_value' => variable_get('leech_news_items_update_' . $node_type, 0)
+ );
+ $period = drupal_map_assoc(array(3600, 10800, 21600, 32400, 43200, 86400, 172800, 259200, 604800, 1209600, 2419200, 3628800, 4838400, 7257600, 15724800, 31536000), 'format_interval');
+ $period['1000000000'] = t('Never');
+ $form['workflow']['leech_defs']['leech_news_items_delete'] = array(
+ '#type' => 'select',
+ '#title' => t('Delete news items older than'),
+ '#options' => $period,
+ '#default_value' => variable_get('leech_news_items_delete_'. $node_type, 15724800)
+ );
+ $promote = drupal_map_assoc(array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30));
+ $promote['0'] = t('None');
+ $promote['1000000000'] = t('All');
+ $form['workflow']['leech_defs']['leech_news_items_promote'] = array(
+ '#type' => 'select',
+ '#title' => t('Promote items'),
+ '#options' => $promote,
+ '#default_value' => variable_get('leech_news_items_promote_'. $node_type, 3)
+ );
+ $form['workflow']['leech_defs']['leech_news_items_date'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Use dates found in feed (if possible)'),
+ '#default_value' => variable_get('leech_news_items_date_'. $node_type, 1)
+ );
+ $form['workflow']['leech_defs']['leech_news_links'] = array (
+ '#type' => 'select',
+ '#title' => t('Show "original article"/"visit site" link'),
+ '#options' => array(
+ LEECH_SHOW_LINK_ALWAYS => t('Always'),
+ LEECH_SHOW_LINK_NEVER => t('Do not display'),
+ LEECH_SHOW_LINK_TEASER_ONLY => t('Only with teaser'),
+ LEECH_SHOW_LINK_PAGE_ONLY => t('Only on full page')
+ ),
+ '#default_value' => variable_get('leech_news_links_'. $node_type, LEECH_SHOW_LINK_ALWAYS),
+ '#description' => t('Select place(s) where link to original article (for news items) or visit site (for news feeds) will be shown.')
+ );
+ /*$form['#after_build'][] = 'leech_after_build_defs';*/
+ }
+ // Add item's data to node edit form
+ if (isset($form['type']) && $form['#node']->leech_news_item) {
+ $node = $form['#node'];
+
+ $form['leech_news_item'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Leeched news item'),
+ '#collapsible' => TRUE,
+ '#collapsed' => FALSE,
+ '#tree' => TRUE
+ );
+ if (user_access('administer nodes')) {
+ // don't allow regular user's to "steal fame" :)
+ $feeds = array();
+ $result = db_query(db_rewrite_sql('SELECT n.nid, n.title FROM {node} n INNER JOIN {leech_news_feed} f ON f.nid = n.nid'));
+ while ($temp = db_fetch_array($result)) {
+ $feeds[$temp['nid']] = $temp['title'];
+ }
+ $form['leech_news_item']['fid'] = array (
+ '#type' => 'select',
+ '#title' => t('Feed Name'),
+ '#default_value' => $node->leech_news_item->fid,
+ '#options' => $feeds,
+ '#required' => TRUE,
+ '#description' => t('The RSS/ATOM feed which this item belongs to.')
+ );
+ $form['leech_news_item']['link'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Link'),
+ '#default_value' => $node->leech_news_item->link,
+ '#size' => 60,
+ '#maxlength' => 250
+ );
+ $form['leech_news_item']['author'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Original author'),
+ '#default_value' => $node->leech_news_item->author,
+ '#size' => 60,
+ '#maxlength' => 60
+ );
+ }
+ else {
+ // don't allow regular user's to "steal fame" :)
+ $form['leech_news_item']['fid'] = array(
+ '#type' => 'hidden',
+ '#value' => $node->leech_news_item->fid
+ );
+ $form['leech_news_item']['link'] = array(
+ '#type' => 'hidden',
+ '#value' => $node->leech_news_item->link
+ );
+ $form['leech_news_item']['author'] = array(
+ '#type' => 'hidden',
+ '#value' => $node->leech_news_item->author
+ );
+ }
+
+ $form['leech_news_item']['source_link'] = array(
+ '#value' => $node->leech_news_item->source_link
+ );
+ $form['leech_news_item']['source_xml'] = array(
+ '#value' => $node->leech_news_item->source_xml
+ );
+ $form['leech_news_item']['source_title'] = array(
+ '#value' => $node->leech_news_item->source_title
+ );
+ }
+
+ // Add leech fields to node edit form
+ if (isset($form['#type']) && ($form_id == $form['#node']->type .'_node_form' || $form_id == 'leech_addons') && variable_get('leech_for_'. $form['#node']->type, 0)) {
+ $node = $form['#node'];
+
+ if (!isset($node->leech->connection) || !isset($node->leech->connection->news_feed)) {
+ return;
+ }
+
+ // Shortcut to make things more readable ;)
+ $feed = &$node->leech->connection->news_feed;
+/*
+ // All seems ok, we can present additional settings to user
+ $form['leech']['addons']['news'] = array(
+ '#type' => 'fieldset'
+ //,'#title' => t('News feed options'),
+ //'#collapsible' => TRUE,
+ //'#collapsed' => FALSE
+ );
+*/
+ if (user_access('administer nodes')) {
+ $form['leech']['addons']['news']['template'] = array(
+ '#type' => 'select',
+ '#title' => t('Template'),
+ '#options' => node_template_list(),
+ '#default_value' => $node->leech_news->template,
+ '#description' => t('Select which node template should be used as template for new items')
+ );
+ }
+ $form['leech']['addons']['news']['logo'] = array(
+ '#type' => 'textfield',
+ '#title' => t('URL of logo image'),
+ '#default_value' => (isset($node->leech_news->logo) ? $node->leech_news->logo : $feed->logo)
+ );
+ $form['leech']['addons']['news']['link'] = array(
+ '#type' => 'textfield',
+ '#title' => t('URL of site'),
+ '#default_value' => (isset($node->leech_news->link) ? $node->leech_news->link : $feed->link)
+ );
+ $form['leech']['addons']['news']['author'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Author of feed'),
+ '#default_value' => (isset($node->leech_news->author) ? $node->leech_news->author : $feed->author),
+ '#autocomplete_path' => 'user/autocomplete'
+ );
+ $form['leech']['addons']['news']['title'] = array(
+ '#type' => 'textfield',
+ '#default_value' => (!$node->title ? $feed->channel[TITLE][0][VALUE] : $node->title),
+ '#attributes' => array('style' => 'display:none')
+ );
+ if (user_access('administer nodes')) {
+ $form['leech']['addons']['news']['items_guid'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Generate GUIDs'),
+ '#default_value' => (isset($node->leech_news->items_guid) ? $node->leech_news->items_guid : (($feed->has_guids || $feed->has_unique_links) ? FALSE : variable_get('leech_news_items_guid_'.$form['type']['#value'], 0)))
+ );
+ $form['leech']['addons']['news']['items_status'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Publish news items'),
+ '#default_value' => (isset($node->leech_news->items_status) ? $node->leech_news->items_status : variable_get('leech_news_items_status_' . $form['type']['#value'], 1))
+ );
+ $form['leech']['addons']['news']['items_update'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Update already existing news items'),
+ '#default_value' => (isset($node->leech_news->items_update) ? $node->leech_news->items_update : variable_get('leech_news_items_update_'.$form['type']['#value'], 0))
+ );
+ $period = drupal_map_assoc(array(3600, 10800, 21600, 32400, 43200, 86400, 172800, 259200, 604800, 1209600, 2419200, 3628800, 4838400, 7257600, 15724800, 31536000), 'format_interval');
+ $period['1000000000'] = t('Never');
+ $form['leech']['addons']['news']['items_delete'] = array(
+ '#type' => 'select',
+ '#title' => t('Delete news items older than'),
+ '#options' => $period,
+ '#default_value' => (isset($node->leech_news->items_delete) ? $node->leech_news->items_delete : variable_get('leech_news_items_delete_'.$form['type']['#value'], 15724800))
+ );
+ $promote = drupal_map_assoc(array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30));
+ $promote['0'] = t('None');
+ $promote['1000000000'] = t('All');
+ $form['leech']['addons']['news']['items_promote'] = array(
+ '#type' => 'select',
+ '#title' => t('Promote items'),
+ '#options' => $promote,
+ '#default_value' => (isset($node->leech_news->items_promote) ? $node->leech_news->items_promote : variable_get('leech_news_items_promote_'.$form['type']['#value'], 3))
+ );
+ $form['leech']['addons']['news']['items_date'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Use dates found in feed if available'),
+ '#default_value' => ($node->leech_news->items_date ? $node->leech_news->items_date : ($feed->has_dates && variable_get('leech_news_items_date_'.$form['type']['#value'], 0) ? TRUE : FALSE))
+ );
+ $form['leech']['addons']['news']['links_display_mode'] = array (
+ '#type' => 'select',
+ '#title' => t('Show "original article"/"visit site" link'),
+ '#options' => array(
+ LEECH_SHOW_LINK_ALWAYS => t('Always'),
+ LEECH_SHOW_LINK_NEVER => t('Do not display'),
+ LEECH_SHOW_LINK_TEASER_ONLY => t('Only with teaser'),
+ LEECH_SHOW_LINK_PAGE_ONLY => t('Only on full page')
+ ),
+ '#default_value' => (isset($node->leech_news->links_display_mode) ? $node->leech_news->links_display_mode : variable_get('leech_news_links_'.$form['type']['#value'], LEECH_SHOW_LINK_ALWAYS)),
+ '#description' => t('Select place(s) where link to original article (for news items) or visit site (for news feeds) will be shown.')
+ );
+ }
+ // Mark if there was leech_news data with node or not
+ if ($node->leech_news->nid) {
+ $form['leech']['addons']['news']['nid'] = array(
+ '#type' => 'hidden',
+ '#value' => $node->leech_news->nid
+ );
+ }
+ }
+ // For OPML
+ if (isset($form['type']) && $form['type']['#value'] .'_node_settings' == $form_id) {
+ $form['workflow']['leech_defs']['opml'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Default leech opml options'),
+ '#collapsible' => FALSE,
+ '#collapsed' => FALSE
+ );
+ $form['workflow']['leech_defs']['opml']['leech_opml_template_'. $form['#node']->type] = array(
+ '#type' => 'select',
+ '#title' => t('Template'),
+ '#options' => node_template_list(),
+ '#default_value' => variable_get('leech_opml_template_'. $form['type']['#value'], 0),
+ '#description' => t('Select which node template should be used as template for opml items')
+ );
+ }
+}
+
+function leech_pre_render_addons($form_id, $form) {
+ global $LEECH_PRERENDERED_ADDONS;
+ if (is_array($LEECH_PRERENDERED_ADDONS) && isset($form['#node']) && isset($form['leech']['addons'])) {
+ $node = $form['#node'];
+ if (isset($node->leech->_prerender_id)) {
+ $LEECH_PRERENDERED_ADDONS[$node->leech->_prerender_id] = str_replace(array('', '
'), '', drupal_render_form('leech-addons', $form['leech']['addons']));
+ }
+ }
+}
+
+/**
+ * Move "Enable leech" checkbox to be used as a legend for leech defs fieldset
+ */
+function leech_after_build_defs($form, $form_values) {
+ // To do that first we render checkbox field and remove divs around it (so we have label and input left)
+ preg_match('%\%U', drupal_render_form('leech_enable', $form['workflow']['leech_defs']['leech_for_'.$form['#node']->type]), $matches);
+ // Finally we put it as title of fieldset :)
+ $form['workflow']['leech_defs']['#title'] = $matches[0];
+
+ return $form;
+}
+
+
+/**
+ * Implementation of hook_nodeapi().
+ */
+function leech_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
+
+ switch ($op) {
+ case 'insert':
+ if (leech_access('create', $node)) {
+ leech_insert($node);
+ }
+ break;
+ case 'update':
+ if (leech_access('update', $node)) {
+ leech_update($node);
+ }
+ break;
+ case 'delete':
+ if (leech_access('delete', $node)) {
+ leech_delete($node);
+ }
+ break;
+ case 'load':
+ return leech_load($node);
+ break;
+ case 'prepare':
+ leech_prepare($node, $teaser);
+ break;
+ case 'validate':
+ leech_validate($node, $teaser);
+ break;
+ case 'submit':
+ leech_submit($node);
+ break;
+ case 'view':
+ if (leech_access('view', $node)) {
+ leech_view($node, $teaser, $page);
+ }
+ break;
+ case 'rss item':
+ if ($node->leech_news_item) {
+ return array(array('key' => 'source',
+ 'attributes' => array('url' => ($node->leech_news_item->source_xml ? $node->leech_news_item->source_xml : $node->leech_news_item->feed_url)),
+ 'value' => check_plain(($node->leech_news_item->source_title ? $node->leech_news_item->source_title : $node->leech_news_item->feed_title))),
+ array('key' => 'dc:source',
+ 'value' => check_plain(($node->leech_news_item->source_link ? $node->leech_news_item->source_link : $node->leech_news_item->link))));
+ }
+ if ($node->leech_news) {
+ return array(array('key' => 'source',
+ 'attributes' => array('url' => $node->leech->url),
+ 'value' => check_plain($node->title)),
+ array('key' => 'dc:source',
+ 'value' => check_plain($node->leech_news->link)));
+ }
+ break;
+ }
+}
+
+/**
+ * Implementation of hook_link().
+ */
+function leech_link($type, $node = NULL, $teaser = FALSE) {
+ $links = array();
+ global $user;
+
+ if ($type == 'node' && $node != NULL) {
+
+ if (variable_get('leech_for_'.$node->type, 0) && isset($node->leech)) {
+ if ((user_access(LEECH_PERM_REFRESH_OWN) && ($user->uid == $node->uid)) || user_access('administer nodes')) {
+ $links['leech_leech_now'] = array('title' => t('Retrieve feed items'), 'href' => "leech/refresh/{$node->nid}", 'query' => 'destination='.$_GET['q']);
+ }
+ }
+
+ $show = ($node->leech_news_item ? $node->leech_news_item->links_display_mode : $node->leech_news->links_display_mode);
+ if (($show == LEECH_SHOW_LINK_ALWAYS) ||
+ ($teaser && $show == LEECH_SHOW_LINK_TEASER_ONLY) ||
+ (!$teaser && $show == LEECH_SHOW_LINK_PAGE_ONLY)) {
+ if ($node->leech_news_item) {
+ if(variable_get('leech_originalarticle_popup', FALSE)) {
+ $links['leech_link_full_article'] = array('title' => t('Read original article.'), 'href' => $node->leech_news_item->link, 'attributes'=>array('onclick'=>'return leech_show_articleoriginal(this, ' . $node->nid . ')'));
+ }
+ else {
+ $links['leech_link_full_article'] = array('title' => t('Read original article.'), 'href' => $node->leech_news_item->link);
+ }
+
+ }
+ if ($node->leech_news) {
+ $links['leech_visit_site'] = array('title' => t('Visit site'), 'href' => $node->leech_news->link);
+ }
+ }
+ if ($node->leech_news) {
+ if ((user_access(LEECH_NEWS_PERM_EDIT_OWN_ITEM) && ($user->uid == $node->uid)) || user_access('administer nodes')) {
+ $links['leech_remove_items'] = array('title' => t('Remove feed items'), 'href' => "leech/remove_items/{$node->nid}");
+ }
+ if (variable_get('leech_news_show_items_link', 0) && arg(1) != 'sources') {
+ $links['leech_view_items'] = array('title' => t('View items'), 'href' => "leech/feed/{$node->nid}");
+ }
+ }
+ else if ($node->leech_news_item && arg(1) != 'feed') {
+ if (variable_get('leech_news_show_feed_link', 0) == LEECH_SHOW_LINK_IN_LINKS) {
+ $links['leech_feed'] = array('title' => t('feed'), 'href' => "leech/feed/{$node->leech_news_item->fid}", array('title' => t('view other articles from %title', array('%title' => $node->leech_news_item->feed_title))));
+ }
+ }
+ }
+
+ return $links;
+}
+
+/**
+ * Implementation of hook_cron().
+ *
+ * Checks news feeds for updates once their refresh interval has elapsed.
+ */
+function leech_cron() {
+ global $user;
+ $old_user = $user;
+
+ timer_start("leech_cron");
+
+ $crontimes = variable_get('leech_cron_times', array());
+ $crontimes[] = time();
+ if (count($crontimes) > 6) {
+ array_shift($crontimes);
+ }
+ variable_set('leech_cron_times', $crontimes);
+
+ $result = db_query_range('SELECT l.nid, n.uid
+ FROM {leech} l
+ JOIN {node} n ON l.nid = n.nid
+ WHERE l.refresh > 0 AND l.checked + l.refresh <= %d ORDER BY l.checked ASC',
+ time(), 0, variable_get('leech_cron_count', 5));
+ $leeches = array();
+ $nids_to_update = array();
+ while ($temp = db_fetch_object($result)) {
+ $leeches[] = $temp;
+ $nids_to_update[] = $temp->nid;
+ }
+ if (count($leeches) > 0) {
+ // Update checked field of leeches right away - this assures that there is a minimum time window
+ // in that another cron processes could come and update the same feeds. The problem with this approach is,
+ // that if cron does not finish on these leeches they will not be checked until their check time elapses again.
+ db_query('UPDATE {leech} SET checked = %d WHERE nid IN (%s)', time(), implode(', ', $nids_to_update));
+
+ foreach ($leeches as $temp) {
+ if ($temp->uid != $user->uid) {
+ // Fake login
+ if ($account = user_load(array('uid' => $temp->uid, 'status' => 1))) {
+ $user = $account;
+ }
+ }
+
+ // Check again if it's correct uid and only then refresh feed
+ if ($temp->uid == $user->uid) {
+ if ($leech = node_load($temp->nid)) {
+ leech_refresh($leech);
+ }
+ }
+ }
+ }
+
+ // Delete too old items
+ $sql = 'SELECT f.items_delete, n.created, i.nid FROM {node} n ';
+ $sql .= 'INNER JOIN {leech_news_item} i ON n.nid = i.nid ';
+ $sql .= 'INNER JOIN {leech_news_feed} f ON f.nid = i.fid ';
+ $result = db_query($sql);
+ $now = time();
+ while ($node = db_fetch_object($result)) {
+ if (abs($now - $node->created) > $node->items_delete) {
+ node_delete($node->nid);
+ }
+ }
+
+ // Now "logout"
+ if ($user->uid != $old_user->uid) {
+ $user = $old_user;
+ }
+}
+
+/**
+ * Implementation of hook_prepare().
+ */
+function leech_prepare(&$node) {
+ // Overwrite only if it's not saved from cron run, so it not gets freezed after each update :)
+ // TODO: if there will be some other module saving nodes, it will trigger overwriting values. Find way to workaround that?
+
+ // Set default values
+ if (!$node->leech->_refresh_running && (!user_access('administer nodes') || !$node->nid)) {
+ if (variable_get('leech_for_'. $node->type, 0)) {
+ $node->leech->refresh = variable_get('leech_refresh_'.$node->type, 900);
+ }
+ }
+
+ // check user access here too?
+ if (variable_get('leech_for_'. $node->type, 0)) {
+ // Forms API doesn't offer a way to check values BEFORE form is build.
+ // And we need it for addon modules to add their options after we check what type of data
+ // URL points to.
+ // TODO: this is BAD. If there are more nodes prepared this will add leech data to EACH of them :(
+ if (isset($_POST['form_id']) && $_POST['form_id'] == $node->type . '_node_form') {
+ $url = trim($_POST['leech']['url']);
+ if ($url) {
+ $node->leech->url = $url;
+ }
+ }
+ // hook_prepare() seems to be used only when showing edit form, so we can download data each time
+ // If it is called in other cases, we have TODO something to prevent downloading data
+ // Also downloading whole file each time is not too wise in case of large files (video?)
+ if (isset($node->leech) && $node->leech->url) {
+
+ // Prepare connection object
+ $connection = array('url' => $node->leech->url);
+ if ($node->leech->_refresh_running) {
+ // Generate conditional GET headers.
+ $connection['headers'] = array();
+ if ($node->leech->etag) {
+ $connection['headers']['If-None-Match'] = $node->leech->etag;
+ }
+ if ($node->leech->modified) {
+ $connection['headers']['If-Modified-Since'] = gmdate('D, d M Y H:i:s', $node->leech->modified) .' GMT';
+ }
+ }
+
+ // If it's already existing node, let other modules know about it when leechapi is called
+ if ($node->nid) {
+ $connection['node'] = &$node;
+ }
+
+ // Setup connection data
+ $connection = leech_connection($connection);
+
+ // Setup values based on connection data
+ if (in_array($connection->result->code, array(200, 206, 301, 302, 304, 307))) {
+ $node->leech->checked = time();
+ $node->leech->etag = $connection->result->headers['etag'];
+ $node->leech->mime = $connection->result->headers['content-type'];
+ if ($connection->result->headers['last-modified']) {
+ $node->leech->modified = strtotime($connection->result->headers['last-modified']);
+ }
+ }
+
+ // Remove reference to node to prevent recursive referencing
+ unset($connection->node);
+
+ // Let other modules know about connection too :)
+ $node->leech->connection = $connection;
+ }
+ }
+
+ if (isset($node->leech_news) && isset($node->leech->connection->news_feed)) {
+ $feed = &$node->leech->connection->news_feed;
+ $node->leech_news->link = $feed->link;
+ if (!$node->leech_news->logo && $feed->logo) {
+ $node->leech_news->logo = $feed->logo;
+ }
+ if (!$node->leech_news->author && $feed->author) {
+ $node->leech_news->author = $feed->author;
+ }
+ if (!$node->body && $feed->description) {
+ $node->body = $feed->description;
+ }
+ }
+
+ // Set default values
+ if (!$node->leech->_refresh_running && !$node->nid) {
+ if ($node->leech->connection->news_feed) {
+ $feed = &$node->leech->connection->news_feed;
+ $node->leech_news->template = variable_get('leech_news_template_'.$node->type, 0);
+ $node->leech_news->items_guid = variable_get('leech_news_items_guid_'.$node->type, 0);
+ $node->leech_news->items_status = variable_get('leech_news_items_status_'.$node->type, 1);
+ $node->leech_news->items_update = variable_get('leech_news_items_update_'.$node->type, 0);
+ $node->leech_news->items_delete = variable_get('leech_news_items_delete_'.$node->type, 15724800);
+ $node->leech_news->items_promote = variable_get('leech_news_items_promote_'.$node->type, 3);
+ $node->leech_news->items_date = variable_get('leech_news_items_date_'.$node->type, 1);
+ $node->leech_news->links_display_mode = variable_get('leech_news_links_'.$node->type, LEECH_SHOW_LINK_ALWAYS);
+ // Autopopulate title field
+ if (strlen($feed->channel[TITLE][0][VALUE]) > 1) {
+ $node->title = $feed->channel[TITLE][0][VALUE];
+ }
+ }
+ }
+
+ // For OPML
+ if (isset($node->leech) && isset($node->leech->connection->result->dataXML)) {
+ $opml = &$node->leech->connection->result->dataXML;
+ $title = leech_opml_parse_value($opml, $opml['opml'][0]['head'][0]['title'][0]);
+ if (!$node->title && $title) {
+ $node->title = $title;
+ }
+ }
+
+ // Set default values
+ if (!$node->leech->_refresh_running && (!user_access('administer nodes') || !$node->nid)) {
+ if (variable_get('leech_for_'.$node->type, 0) && $node->leech->connection->result->dataXML) {
+ $node->leech_opml->template = variable_get('leech_opml_template_'.$node->type, 0);
+ }
+ }
+ return $node;
+}
+
+/**
+ * Implementation of hook_access().
+ */
+function leech_access($op, $node) {
+ global $user;
+
+ switch ($op) {
+ case 'create':
+ return user_access(LEECH_PERM_CREATE);
+ break;
+ case 'update':
+ case 'delete':
+ if ($node->leech->_refresh_running || user_access('administer nodes') || (user_access(LEECH_PERM_EDIT_OWN) && ($user->uid == $node->uid))) {
+ return TRUE;
+ }
+ break;
+ case 'view':
+ return user_access(LEECH_PERM_ACCESS);
+ break;
+ }
+}
+
+/**
+ * Implementation of hook_validate().
+ */
+function leech_validate(&$node, $form = array()) {
+ if (isset($form['leech']) && isset($form['leech']['url']) && isset($form['leech']['url']['#value'])) {
+ if (trim($form['leech']['url']['#value']) == '') {
+ return;
+ }
+ $result = db_query("SELECT l.nid, n.title FROM {node} n INNER JOIN {leech} l ON l.nid = n.nid WHERE l.url = '%s' ", $form['leech']['url']['#value']);
+ while ($leech = db_fetch_object($result)) {
+ if ($leech->nid != $node->nid) {
+ $link = l($leech->title, "node/{$leech->nid}");
+ form_set_error('leech][url', t('Duplicate URL: %link already uses that URL.', array('%link' => $link)));
+ return;
+ }
+ }
+
+ if (!leech_is_valid_url($form['leech']['url']['#value'])) {
+ form_set_error('leech][url', t('URL not allowed (blacklisted).'));
+ return;
+ }
+
+ if (isset($form['leech']['connection']['#value'])) {
+ $connection = $form['leech']['connection']['#value'];
+ switch ($connection->result->code) {
+ case 200:
+ case 206:
+ case 302:
+ case 307:
+ // Data was downloaded successfully
+ break;
+
+ case 401: // Unauthorized
+ break;
+
+ default:
+ form_set_error('leech][url', t('Error while checking URL: %code', array('%code' => $connection->result->code .', '. $connection->result->error)));
+ break;
+ }
+ }
+ }
+}
+
+/**
+ * Implementation of hook_submit().
+ */
+function leech_submit(&$node) {
+ if (isset($node->leech)) {
+ $node->leech = (object)$node->leech;
+ if (!trim($node->leech->url)) {
+ unset($node->leech);
+ }
+ }
+ if (isset($node->leech) && !isset($node->leech_news) && isset($node->leech->addons['news'])) {
+ $node->leech_news = (object)$node->leech->addons['news'];
+ unset($node->leech->addons['news']);
+ }
+
+ // Create items after we know feed was validated ok (submit is called after validate)
+ if ($node->leech->_refresh_running && isset($node->leech_news) && isset($node->leech->connection->news_feed)) {
+ _leech_news_save_items($node);
+ }
+
+ if (isset($node->leech_news)) {
+ if (variable_get('leech_news_pass_on_taxonomy', 0)) {
+ _leech_news_pass_on_taxonomy($node);
+ }
+ _leech_news_pass_on_groups($node);
+ }
+
+ // For OPML
+ if (isset($node->leech) && !isset($node->leech_opml) && isset($node->leech->addons['opml'])) {
+ $node->leech_opml = (object)$node->leech->addons['opml'];
+ unset($node->leech->addons['opml']);
+ }
+
+ // Create items after we know feed was validated ok (submit is called after validate)
+ if ($node->leech->_refresh_running && isset($node->leech_opml) && isset($node->leech->connection->result->dataXML)) {
+ leech_opml_save_items($node);
+ }
+}
+
+
+/**
+ * Implementation of hook_insert().
+ */
+function leech_insert($node) {
+ if (isset($node->leech)) {
+ db_query("INSERT INTO {leech} (nid, url, refresh, news_last_arrived, adaptive) VALUES (%d, '%s', %d, %d, %d)", $node->nid, $node->leech->url, $node->leech->refresh, time(), $node->leech->adaptive);
+ }
+ if (isset($node->leech_news)) {
+ db_query("INSERT INTO {leech_news_feed} (nid, template, logo, link, author, items_guid, items_status, items_update, items_delete, items_promote, items_date, links_display_mode) VALUES (%d, %d, '%s', '%s', '%s', %d, %d, %d, %d, %d, %d, %d)", $node->nid, $node->leech_news->template, $node->leech_news->logo, $node->leech_news->link, $node->leech_news->author, $node->leech_news->items_guid, $node->leech_news->items_status, $node->leech_news->items_update, $node->leech_news->items_delete, $node->leech_news->items_promote, $node->leech_news->items_date, $node->leech_news->links_display_mode);
+ }
+ if (isset($node->leech_news_item)) {
+ db_query("INSERT INTO {leech_news_item} (nid, fid, link, author, guid, source_link, source_xml, source_title) VALUES (%d, %d, '%s', '%s', '%s', '%s', '%s', '%s')", $node->nid, $node->leech_news_item->fid, $node->leech_news_item->link, $node->leech_news_item->author, $node->leech_news_item->guid, $node->leech_news_item->source_link, $node->leech_news_item->source_xml, $node->leech_news_item->source_title);
+ }
+ if (isset($node->leech_opml)) {
+ db_query("INSERT INTO {leech_opml} (nid, template) VALUES (%d, %d)", $node->nid, $node->leech_opml->template);
+ }
+}
+
+/**
+ * Implementation of hook_update().
+ */
+function leech_update($node) {
+ if (isset($node->leech)) {
+ if ($node->leech->is_new) {
+ leech_insert($node);
+ }
+ else {
+ db_query("UPDATE {leech} SET url = '%s', refresh = %d, checked = %d, modified = %d, etag = '%s', mime = '%s', adaptive = %d WHERE nid = %d", $node->leech->url, $node->leech->refresh, $node->leech->checked, $node->leech->modified, $node->leech->etag, $node->leech->mime, $node->leech->adaptive, $node->nid);
+ }
+ }
+ else {
+ db_query('DELETE FROM {leech} WHERE nid = %d', $node->nid);
+ }
+ if (isset($node->leech_news)) {
+ if ($node->leech_news->nid) {
+ db_query("UPDATE {leech_news_feed} SET template = %d, logo = '%s', link = '%s', author = '%s', items_guid = %d, items_status = %d, items_update = %d, items_delete = %d, items_promote = %d, items_date = %d, links_display_mode = %d WHERE nid = %d", $node->leech_news->template, $node->leech_news->logo, $node->leech_news->link, $node->leech_news->author, $node->leech_news->items_guid, $node->leech_news->items_status, $node->leech_news->items_update, $node->leech_news->items_delete, $node->leech_news->items_promote, $node->leech_news->items_date, $node->leech_news->links_display_mode, $node->leech_news->nid);
+ }
+ else {
+ leech_insert($node);
+ }
+ }
+ if (isset($node->leech_news_item)) {
+ db_query("UPDATE {leech_news_item} SET fid = %d, link = '%s', author = '%s' WHERE nid = %d", $node->leech_news_item->fid, $node->leech_news_item->link, $node->leech_news_item->author, $node->leech_news_item->nid);
+ }
+ if (isset($node->leech_opml)) {
+ if ($node->leech_opml->nid) {
+ db_query("UPDATE {leech_opml} SET template = %d WHERE nid = %d", $node->leech_opml->template, $node->leech_opml->nid);
+ }
+ /*else {
+ leech_opml_insert($node);
+ }*/
+ }
+}
+
+/**
+ * Implementation of hook_delete().
+ */
+function leech_delete(&$node) {
+ db_query('DELETE FROM {leech} WHERE nid = %d', $node->nid);
+ db_query('DELETE FROM {leech_news_feed} WHERE nid = %d', $node->nid);
+ db_query('DELETE FROM {leech_news_item} WHERE nid = %d', $node->nid);
+ db_query('DELETE FROM {leech_opml} WHERE nid = %d', $node->nid);
+}
+
+/**
+ * Implementation of hook_load().
+ */
+function leech_load($node) {
+ $temp = array();
+ $result = db_fetch_object(db_query('SELECT * FROM {leech_news_feed} WHERE nid = %d', $node->nid));
+ if ($result) {
+ $temp['leech_news'] = $result;
+ }
+ $result = db_fetch_object(db_query('SELECT i.*, n.title AS feed_title, f.links_display_mode, f.link AS feed_link, l.url AS feed_url FROM {leech_news_item} i LEFT JOIN {node} n ON n.nid = i.fid LEFT JOIN {leech_news_feed} f ON f.nid = i.fid LEFT JOIN {leech} l ON l.nid = i.fid WHERE i.nid = %d', $node->nid));
+ if ($result) {
+ $temp['leech_news_item'] = $result;
+ }
+ $result = db_fetch_object(db_query('SELECT * FROM {leech} WHERE nid = %d', $node->nid));
+ if ($result) {
+ $temp['leech'] = $result;
+ }
+ $result = db_fetch_object(db_query('SELECT * FROM {leech_opml} WHERE nid = %d', $node->nid));
+ if ($result) {
+ $temp['leech_opml'] = $result;
+ }
+ if (count($temp) > 0) {
+ return $temp;
+ }
+}
+
+/**
+ * theme function for inline links from feed items to feeds
+ *
+ * @param unknown_type $links
+ */
+function theme_leech_inline_link_to_feed($links) {
+ foreach ($links as $link) {
+ $formatted_links[] = l($link['text'], 'leech/feed/'.$link['fid'], array('title' => $link['text']));
+ }
+ return ''.t('Feed').": ".implode(', ', $formatted_links).'
';
+}
+
+/**
+ * Implementation of hook_view().
+ */
+function leech_view(&$node, $teaser = FALSE, $page = FALSE) {
+
+ if (isset($node->leech_news_item->feed_title)) {
+ if (variable_get('leech_news_show_feed_link', 0) == LEECH_SHOW_LINK_INLINE) {
+ $links[] = array('fid' => $node->leech_news_item->fid, 'text' => $node->leech_news_item->feed_title);
+ $themed_links = theme('leech_inline_link_to_feed', $links);
+ if (isset($node->teaser)) {
+ $teaser->content['leech_links'] = array('#value' => $themed_links, '#weight' => 10);
+ }
+ if (isset($node->body)) {
+ $node->content['leech_links'] = array('#value' => $themed_links, '#weight' => 10);
+ }
+ }
+ if(variable_get('leech_page_items_format', 'full')=='custom') {
+ $truncated_text = $node->content['body']['#value'];
+ if($teaser) {
+ $truncated_text = _leech_htmlcorrector($node->body);
+ $truncated_text = _leech_truncate_text($truncated_text, variable_get('leech_page_items_custom_length_teaser', 600), '', false);
+ $truncated_text = _leech_htmlcorrector($truncated_text);
+ }
+ else if($page) {
+ $truncated_text = _leech_htmlcorrector($node->body);
+ $truncated_text = _leech_truncate_text($truncated_text, variable_get('leech_page_items_custom_length_body', 600), '', false);
+ $truncated_text = _leech_htmlcorrector($truncated_text);
+ }
+ $node->content['body']['#value'] = $truncated_text;
+ $node->teaser = $truncated_text;
+ $node->body = $truncated_text;
+ }
+ }
+
+ if (!isset($node->leech)) {
+ return;
+ }
+
+ // Provide some statistics
+ $rows = array();
+ $rows[] = array(t('Feed URL'), l(truncate_utf8($node->leech->url, 40, FALSE, TRUE), $node->leech->url));
+ $rows[] = array(t('Last checked'), ($node->leech->checked ? t('%time ago', array('%time' => format_interval(time() - $node->leech->checked))) : t('never')) );
+ $rows[] = array(t('Time until next refresh'), ($node->leech->checked ? t('%time left', array('%time' => format_interval($node->leech->checked + $node->leech->refresh - time()))) : ($node->leech->refresh > 0 ? t('immediately') : t('never') )) );
+
+ $output .= theme('table', array(), $rows);
+ $node->content['leech_stat'] = array('#value' => $output, '#weight' => 10);
+ $teaser->content['leech_stat'] = array('#value' => $output, '#weight' => 10);
+
+}
+
+/**
+ * Implementation of hook_leechapi().
+ */
+/*
+function leech_leechapi(&$connection, $op) {
+
+ if ($op != 'resolve' || !isset($connection->result)
+ || !in_array($connection->result->code, array(200, 206, 301, 302, 304, 307))) {
+ return;
+ }
+
+ // Check MIME
+ $mime = explode(';', $connection->result->headers['content-type'], 2);
+ if ($mime[0]) $mime = $mime[0];
+ if (!in_array($mime, array('text/xml', 'application/xml', 'text/html', 'application/rss+xml', 'application/atom+xml', 'application/rdf+xml', 'application/opml+xml'))) {
+ return;
+ }
+
+ // Check if data contains format we can handle
+ if (preg_match('%<(rss|rdf:rdf|feed|channel)[^>]*>(?=.*\1>)%siU', $connection->result->data, $matches) < 1) {
+ return;
+ }
+
+ // We can also do some format specific settings. $matches[1] contains tag name (rss, rdf:rdf, feed or channel :).
+ // ...
+
+ if (!isset($connection->news_feed)) {
+ $connection->news_feed = _leech_news_parse($connection->result->data);
+ }
+ $connection->result->dataXML = leech_opml_parse($connection->result->data);
+
+}
+*/
+
+/**
+ * Menu callback; displays the leech administration page.
+ */
+function leech_page_admin() {
+ global $user;
+ if (!user_access('administer nodes')) {
+ $uid = '';
+ $can_edit = user_access(LEECH_PERM_EDIT_OWN);
+ $can_refresh = user_access(LEECH_PERM_REFRESH_OWN);
+ }
+ else {
+ $uid = '';
+ $can_edit = TRUE;
+ $can_refresh = TRUE;
+ }
+
+ $result = db_query("SELECT n.nid, n.title, l.checked, l.refresh FROM {node} n INNER JOIN {leech} l ON n.nid = l.nid $uid ORDER BY n.title ASC");
+
+ $header = array(t('Title'), t('Last checked'), t('Next check'), array('data' => t('Operations'), 'colspan' => '3'));
+ $rows = array();
+ while ($leech = db_fetch_object($result)) {
+ $rows[] = array(l($leech->title, "leech/feed/$leech->nid"), ($leech->checked ? t('%time ago', array('%time' => format_interval(time() - $leech->checked))) : t('never')), ($leech->refresh < 1 ? t('Freezed') : t('%time left', array('%time' => format_interval($leech->checked + $leech->refresh - time())))), ($can_edit ? l(t('edit'), "node/$leech->nid/edit") : ''), ($can_refresh ? l(t('Leech'), "leech/refresh/{$leech->nid}") : ''));
+ }
+ $output .= theme('table', $header, $rows);
+
+ return $output;
+}
+
+/**
+ * Menu callback; Generate a listing of feed items.
+ */
+function leech_page_feed_list() {
+ return leech_page_admin();
+}
+
+/**
+ * Menu callback; Generates an OPML representation of all feeds.
+ */
+function leech_page_opml() {
+ $result = db_query(db_rewrite_sql('SELECT n.nid, n.title, l.url FROM {node} n INNER JOIN {leech} l ON l.nid = n.nid ORDER BY n.title ASC'));
+ // should we do this?: $result = db_query(db_rewrite_sql('SELECT n.nid, n.title, l.url FROM {node} n, {leech} l, {leech_news_feed} f WHERE f.nid = n.nid AND l.nid = f.nid ORDER BY n.title ASC'));
+ $output = '';
+ while ($leech = db_fetch_object($result)) {
+ $output .= ' '."\n";
+ }
+ drupal_set_header('Content-Type: text/xml; charset=utf-8');
+ print _opml_skeleton($output);
+}
+
+/**
+ * Menu callback; refresh feed.
+ */
+function leech_page_refresh($nid = NULL) {
+ if ($nid == NULL && is_numeric(arg(1))) {
+ $nid = arg(1);
+ }
+
+ $leech = node_load($nid);
+ if ($leech && variable_get('leech_for_'.$leech->type, 0) && isset($leech->leech)) {
+ global $user;
+ $old_user = FALSE;
+ if ($leech->uid != $user->uid || !user_access(LEECH_PERM_REFRESH_OWN)) {
+ if (!user_access('administer nodes')) {
+ drupal_access_denied();
+ return;
+ }
+ else if ($leech->uid != $user->uid) {
+ // Fake owner user
+ $old_user = $user;
+ $user = user_load(array('uid' => $leech->uid));
+ }
+ }
+
+ // Reset modified date to "really" refresh
+ $leech->leech->modified = 0;
+ $leech->leech->etag = 0;
+ $leech->leech->checked = 0;
+ leech_refresh($leech);
+
+ // If needed, back to "real" user
+ if ($old_user !== FALSE) {
+ $user = $old_user;
+ }
+ }
+
+ if ($_GET['destination']) {
+ drupal_goto($_GET['destination']);
+ }
+ else {
+ drupal_goto('node/'. $nid);
+ }
+}
+
+/**
+ * Menu callback; return html for addons part of the node form.
+ */
+function leech_get_form() {
+ $url = $_POST['url'];
+ $nid = $_POST['nid'];
+ $type = $_POST['type'];
+
+ if (!$url) {
+ echo t('No URL received');
+ return;
+ }
+
+ // prepare $node, get form for it, and output [leech][addons] part of it
+ if (!$nid) {
+ // From node_add()
+ global $user;
+ $node = array('uid' => $user->uid, 'name' => $user->name, 'type' => $type, 'leech' => new StdClass());
+ $node['leech']->url = $url;
+ $node['leech']->_prerender_id = time();
+ $node = (object)$node;
+ }
+ else {
+ $node = node_load($nid);
+ $node->leech->url = $url;
+ $node->leech->_prerender_id = time();
+ }
+ // Make it array, just in case some internal mechanism starts new rendering, of other node
+ // In alter_form we'll check for _prerender_id and at #pre_render time we'll setup
+ // $LEECH_PRERENDERED_ADDONS[_prerender_id] = render_form($form['leech']['addons']);
+ global $LEECH_PRERENDERED_ADDONS;
+ $LEECH_PRERENDERED_ADDONS = array();
+ $output = node_form($node);
+ drupal_prepare_form('leech_addons', $output);
+ drupal_render_form('leech_addons', $output);
+ if (isset($LEECH_PRERENDERED_ADDONS[$node->leech->_prerender_id])) {
+ echo $LEECH_PRERENDERED_ADDONS[$node->leech->_prerender_id];
+ exit();
+ }
+ else {
+ echo t('Could not read feed');
+ exit();
+ }
+}
+
+/**
+ * Menu callback; generate javascript.
+ */
+function leech_javascript() {
+ global $base_url;
+ // This is leech.js
+ echo '
+ function leech_prepare_check_url(field) {
+ field.old_value = field.value;
+ $(this).addClass(field, "form-autocomplete");
+ field.onkeyup = function (event) { leech_keyup(field, event); };
+}
+
+function leech_close_check_url(field) {
+ leech_check_url(field);
+ $(this).removeClass(field, "form-autocomplete");
+ $(this).removeClass(field, "throbbing");
+}
+
+function leech_keyup(field, e) {
+ if (!e) {
+ e = window.event;
+ }
+ switch (e.keyCode) {
+ case 16: // shift
+ case 17: // ctrl
+ case 18: // alt
+ case 20: // caps lock
+ case 33: // page up
+ case 34: // page down
+ case 35: // end
+ case 36: // home
+ case 37: // left arrow
+ case 38: // up arrow
+ case 39: // right arrow
+ case 40: // down arrow
+ return true;
+
+ case 9: // tab
+ case 13: // enter
+ case 27: // esc
+ return true;
+
+ default: // all other keys
+ clearTimeout(field.timer);
+ field.timer = setTimeout(function() { leech_check_url(field); }, 500);
+ return true;
+ }
+}
+
+function leech_check_url(field) {
+ if (field.old_value == field.value) {
+ return;
+ }
+ field.old_value = field.value;
+
+ if (field.value.length < 1) {
+ $("edit-leech-addons").innerHTML = "";
+ return;
+ }
+
+ $(this).addClass(field, "throbbing");
+
+ var param = new Array();
+ param["url"] = field.value;
+ if ($("#edit-leech-nid").val()) {
+ param["nid"] = $("#edit-leech-nid").val();
+ }
+ var node_type = $("#edit-leech-node-type");
+ param["type"] = node_type.val();
+ HTTPPost("'. $base_url .'/?q=/leech/get/form", leech_update_addons, field, param);
+}
+
+function leech_update_addons(string, xmlhttp, field) {
+ if (xmlhttp.status != 200 && typeof xmlhttp.status != "undefined") {
+ alert("An HTTP error "+ xmlhttp.status +" occured.\n"+ field.value);
+ }
+ var node = $("#edit-leech-addons");
+ node.html(string);
+ var nodetitle = $("#edit-title").val();
+ var feedtitle = $("#edit-leech-addons-news-title");
+ if (nodetitle.length == 0) {
+ $("#edit-title").val(feedtitle.val());
+ }
+
+
+
+ collapseAttach(node);
+ $(this).removeClass(field, "throbbing");
+
+ // Now animate scroll page to additional options
+ var h = self.innerHeight || document.documentElement.clientHeight || document.body.clientHeight || 0;
+ var offset = self.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
+ var pos = Drupal.absolutePosition($("edit-leech-addons"));
+ var nh = $("edit-leech-addons").scrollHeight;
+
+ if (pos.y + nh > h + offset) {
+ var scrollto = pos.y;
+ if (nh <= h) scrollto = pos.y + nh - h;
+ var count = 0;
+ for (var i=offset;i<=scrollto;i=i+((scrollto+2-i)/2)) {setTimeout("window.scrollTo(0, "+i+")",70*(count++));} // from quirksmode.org
+ for (var i=0;i<=10;i++) {setTimeout("setBG("+(155+(10*i))+")",70*i);}
+ for (var i=10;i<=20;i++) {setTimeout("setBG("+(355-(10*i))+")",70*i);}
+ for (var i=20;i<=30;i++) {setTimeout("setBG("+(-45+(10*i))+")",70*i);}
+
+ setBG = function (c) {
+ var n = $("#edit-leech-addons");
+ n.style.backgroundColor = "rgb("+c+","+c+","+c+")";
+ }
+ }
+}
+
+function collapseAttach(element) {
+ var fieldsets = $("leech-fieldset");
+ var legend, fieldset;
+ for (var i = 0; fieldset = fieldsets[i]; i++) {
+ if (!Drupal.hasClass(fieldset, "collapsible")) {
+ continue;
+ }
+ legend = fieldset.getElementsByTagName("legend");
+ if (legend.length == 0) {
+ continue;
+ }
+ legend = legend[0];
+ var a = document.createElement("a");
+ a.href = "#";
+ a.onclick = function() {
+ toggleClass(this.parentNode.parentNode, "collapsed");
+ if (!Drupal.hasClass(this.parentNode.parentNode, "collapsed")) {
+ Drupal.collapseScrollIntoView(this.parentNode.parentNode);
+ if (typeof textAreaAutoAttach != "undefined") {
+ // Add the grippie to a textarea in a collapsed fieldset.
+ Drupal.textAreaAutoAttach(null, this.parentNode.parentNode);
+ }
+ }
+ this.blur();
+ return false;
+ };
+ a.innerHTML = legend.innerHTML;
+ while (legend.hasChildNodes()) {
+ $(this).removeNode(legend.childNodes[0]);
+ }
+ legend.appendChild(a);
+ Drupal.collapseEnsureErrorsVisible(fieldset);
+ }
+}
+
+function HTTPPost(uri, callbackFunction, callbackParameter, object) {
+ var xmlHttp = new XMLHttpRequest();
+ var bAsync = true;
+ if (!callbackFunction) {
+ bAsync = false;
+ }
+ xmlHttp.open("POST", uri, bAsync);
+ var toSend = "";
+ if (typeof object == "object") {
+ xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
+ for (var i in object) {
+ toSend += (toSend ? "&" : "") + i + "=" + encodeURIComponent(object[i]);
+ }
+ }
+ else {
+ toSend = object;
+ }
+ xmlHttp.send(toSend);
+
+ if (bAsync) {
+ if (callbackFunction) {
+ xmlHttp.onreadystatechange = function() {
+ if (xmlHttp.readyState == 4) {
+ callbackFunction(xmlHttp.responseText, xmlHttp, callbackParameter);
+ }
+ }
+ }
+ return xmlHttp;
+ }
+ else {
+ return xmlHttp.responseText;
+ }
+}
+
+ ';
+}
+
+/**
+ * Invoke a hook_leechapi() operation in all modules.
+ *
+ * @param &$connection
+ * A connection object.
+ * @param $op
+ * A string containing the name of the leechapi operation.
+ * @return
+ * The returned value of the invoked hooks.
+ */
+function leech_invoke_leechapi(&$connection, $op) {
+ $return = array();
+ foreach (module_implements('leechapi') as $name) {
+ $function = $name .'_leechapi';
+ $result = $function($connection, $op);
+ if (isset($result) && is_array($result)) {
+ $return = array_merge($return, $result);
+ }
+ else if (isset($result)) {
+ $return[] = $result;
+ }
+ }
+ return $return;
+}
+
+/**
+ * Private function; If URL is ok returns 1. If it's blacklisted returns 0. If expression contains error returns FALSE.
+ */
+function leech_is_valid_url($url) {
+ static $blacklist = NULL;
+
+ // Prepare pattern string
+ if ($blacklist == NULL) {
+ $temp = variable_get('leech_blacklist_url', '');
+ $blacklist = array();
+ if ($temp) {
+ $temp = explode("\n", $temp);
+ foreach ($temp as $line) {
+ // Simple comparision
+ if (preg_match('/^\w+:\/\//', $line)) {
+ $blacklist[] = '^'.preg_replace('/[^\w]/', '\\\$0', $line).'$';
+ }
+ // Check by domain and subdomain
+ else if ($line[0] != '/') {
+ if ($line[0] == '.') {
+ $blacklist[] = '^\w+:\/\/(?:\w+\.|\.)*'.preg_replace('/[^\w]/', '\\\$0', substr($line, 1)).'.*?$';
+ }
+ else {
+ $blacklist[] = '^\w+:\/\/'.preg_replace('/[^\w]/', '\\\$0', $line).'.*$';
+ }
+ }
+ // Use pattern
+ else {
+ $blacklist[] = substr($line, 1, -1);
+ }
+ }
+ if (count($blacklist) > 0) {
+ $blacklist = '/'.implode('|', $blacklist).'/';
+ }
+ else {
+ $blacklist = '';
+ }
+ }
+ }
+
+ if ($blacklist) {
+ return !preg_match($blacklist, $url, $matches);;
+ }
+
+ return 1;
+}
+
+/**
+ * Private function; Leech data.
+ *
+ * @param $connection
+ * Array with connection parameters, simple url string, or already existing connection object.
+ * @return
+ * Connection object with $connection->result containing data and http code downloaded from $connection->url.
+ */
+function leech_connection($connection) {
+ // Validate connection data
+ /*
+ $connection = array (
+ 'url' => $node->leech->url, // required
+ 'headers' => array(), // optional
+ 'method' => 'GET', // optional, default: GET
+ 'data' => NULL, // optional
+ 'follow' => 5, // optional, default: 3
+ 'timeout' => 15, // optional, default: 15
+ 'cookie' => NULL, // optional
+ 'onlyHeaders' => FALSE, // optional, default: FALSE
+ 'username' => NULL, // optional
+ 'password' => NULL // optional
+ );
+ */
+ $connection = (object)$connection;
+
+ if (!isset($connection->url) && isset($connection->scalar) && is_string($connection->scalar)) {
+ $connection->url = $connection->scalar;
+ unset($connection->scalar);
+ }
+
+ if (!isset($connection->url)) {
+ return;
+ }
+ if (!is_array($connection->headers)) {
+ $connection->headers = array();
+ }
+ if (!isset($connection->method)) {
+ $connection->method = 'GET';
+ }
+ if (!isset($connection->follow)) {
+ $connection->follow = '3';
+ }
+ if (!isset($connection->timeout)) {
+ $connection->timeout = '15';
+ }
+ if (!isset($connection->onlyHeaders)) {
+ $connection->onlyHeaders = FALSE;
+ }
+
+ leech_invoke_leechapi($connection, 'prepare');
+
+ // Check if it's legal url
+ if (!leech_is_valid_url($connection->url)) {
+ return $connection;
+ }
+
+ // Connect and download data
+ $connection->result = leech_http_request($connection->url, $connection->headers, $connection->data, $connection->follow, $connection->timeout, $connection->cookie, $connection->onlyHeaders, $connection->username, $connection->password);
+
+ // this was what was before in leech_news_leechapi() and leech_opml_leechapi()
+ if (in_array($connection->result->code, array(200, 206, 301, 302, 304, 307))) {
+ // Check MIME
+ $mime = isset($connection->result->headers['content-type']) ?
+ explode(';', $connection->result->headers['content-type'], 2) :
+ explode(';', $connection->result->headers['Content-Type'], 2);
+ if ($mime[0]) $mime = $mime[0];
+ if (!in_array($mime, array('text/xml', 'application/xml', 'text/html', 'application/rss+xml', 'application/atom+xml', 'application/rdf+xml', 'application/opml+xml', 'text/plain'))) {
+ return;
+ }
+
+ // Check if data contains format we can handle
+ //if (preg_match('%<(rss|rdf:rdf|feed|channel)[^>]*>(?=.*\1>)%siU', $connection->result->data, $matches) < 1) {
+ // I use this less strict checking because of some PHP4 - PHP5 annoyance
+ if (preg_match('%<(rss|rdf:rdf|feed|channel)[^>]*>%siU', $connection->result->data, $matches) < 1) {
+ return;
+ }
+
+ // We can also do some format specific settings. $matches[1] contains tag name (rss, rdf:rdf, feed or channel :).
+ // ...
+
+ if (!isset($connection->news_feed)) {
+ $connection->news_feed = _leech_news_parse($connection->result->data);
+ }
+ $connection->result->dataXML = leech_opml_parse($connection->result->data);
+ }
+
+ leech_invoke_leechapi($connection, 'resolve');
+
+ return $connection;
+}
+
+/**
+ * Private function; Checks a news feed for new items.
+ */
+function leech_refresh(&$leech) {
+ if (!isset($leech->leech)) {
+ return;
+ }
+
+ $leech->leech->_refresh_running = TRUE;
+
+ // Download and prepare data
+ node_object_prepare($leech);
+ $result = &$leech->leech->connection->result;
+
+ // If moved permanently update URL
+ if ($result->code == 301 && $result->redirect_url) {
+ $leech->leech->url = $result->redirect_url;
+ watchdog('leech', t('Updated URL for leech %title to %url.', array('%title' => $leech->title, '%url' => $leech->leech->url)), WATCHDOG_NOTICE, l(t('view'), 'node/'.$leech->nid));
+ }
+
+ // If response was ok, save it :)
+ if (in_array($result->code, array(200, 301, 302, 307))) {
+ $node->changed = time();
+ $_POST['edit']['changed'] = time();
+ node_validate($leech);
+ if (!($errors = form_get_errors())) {
+ leech_submit($leech);
+ leech_update($leech);
+ watchdog('leech', t('Leeched content from %site.', array('%site' => $leech->title)), WATCHDOG_NOTICE, l(t('view'), 'node/'.$leech->nid));
+
+ sleep(variable_get('leech_sleep_interval', 0));
+ }
+ else {
+ watchdog('leech', t('Failed to validate %site: %error.', array('%site' => $leech->title, '%error' => implode(" \n", $errors))), WATCHDOG_ERROR, l(t('view'), 'node/'.$leech->nid));
+ }
+ }
+ // Update checked time and adaptive infos,
+ //so it won't be checked each on cron run, and thus block other feeds (outside of limit count) to be checked.
+ db_query('UPDATE {leech}
+ SET checked = %d, avg_btw_news = %d, deviation = %d,
+ num_of_tests = %d, news_last_arrived = %d, refresh = %d
+ WHERE nid = %d',
+ time(),
+ $leech->leech->avg_btw_news,
+ $leech->leech->deviation,
+ $leech->leech->num_of_tests,
+ $leech->leech->news_last_arrived,
+ $leech->leech->refresh,
+ $leech->nid
+ );
+ unset($leech->leech->_refresh_running);
+}
+
+
+
+
+
+/**
+ * Private function; Parse HTTP headers from data retreived with cURL
+ * from: http://pl2.php.net/manual/en/function.curl-setopt.php#42009
+ */
+function leech_parse_http_response($response) {
+ /*
+ ***original code extracted from examples at
+ ***http://www.webreference.com/programming/php/cookbook/chap11/1/3.html
+
+ ***returns an array in the following format which varies depending on headers returned
+
+ [0] => the HTTP error or response code such as 404
+ [1] => Array
+ (
+ [Server] => Microsoft-IIS/5.0
+ [Date] => Wed, 28 Apr 2004 23:29:20 GMT
+ [X-Powered-By] => ASP.NET
+ [Connection] => close
+ [Set-Cookie] => COOKIESTUFF
+ [Expires] => Thu, 01 Dec 1994 16:00:00 GMT
+ [Content-Type] => text/html
+ [Content-Length] => 4040
+ )
+ [2] => Response body (string)
+ */
+
+ do {
+ list($response_headers, $response) = explode("\r\n\r\n", $response, 2);
+ $response_header_lines = explode("\r\n", $response_headers);
+
+ // first line of headers is the HTTP response code
+ $http_response_line = array_shift($response_header_lines);
+ if (preg_match('@^HTTP/[0-9]\.[0-9] ([0-9]{3})@', $http_response_line, $matches)) {
+ $response_code = $matches[1];
+ }
+ else {
+ $response_code = "Error";
+ }
+ }
+ while (substr($response_code, 0, 1) == "1");
+
+ $response_body = $response;
+
+ // put the rest of the headers in an array
+ $response_header_array = array();
+ foreach ($response_header_lines as $header_line) {
+ list($header, $value) = explode(':', $header_line, 2);
+ $response_header_array[strtolower($header)] = trim($value);
+ }
+
+ return array($response_code, $response_header_array, $response_body, $http_response_line);
+}
+
+/**
+ * Downloads data from given url, follow redirects and provides coherent UTF-8 output for feeds
+ */
+function leech_http_request($url, $headers = array(), $data = NULL, $follow = 3, $timeout = 15, $cookie = NULL, $onlyHeaders = FALSE, $username = NULL, $password = NULL) {
+ $method = 'GET';
+ if (!function_exists('curl_init')) {
+ if ($onlyHeaders) {
+ $headers['Range'] = 'bytes=0-1';
+ }
+ if ($username != NULL && $password != NULL) {
+ $headers['Authorization'] = 'Basic: '. base64_encode("$username:$password");
+ }
+ return drupal_http_request($url, $headers, $method, $data, $follow);
+ }
+
+ // Convert headers array to format used by cURL
+ $temp = array();
+ if (is_array($headers)) {
+ foreach ($headers as $header => $value) {
+ $temp[] = $header .': '. $value;
+ }
+ }
+ $headers = $temp;
+
+ $result = new StdClass();
+
+ $ch = curl_init();
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+ curl_setopt($ch, CURLOPT_URL, $url);
+ curl_setopt($ch, CURLOPT_HEADER, 1);
+ curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
+ curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0);
+ curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
+ curl_setopt($ch, CURLOPT_USERAGENT, 'Drupal');
+
+ if ($onlyHeaders) {
+ curl_setopt($ch, CURLOPT_NOBODY, TRUE);
+ }
+
+ if (strlen($username) > 0 && strlen($password) > 0) {
+ curl_setopt($ch, CURLOPT_USERPWD, "$username:$password");
+ }
+
+ if ($cookie != NULL) {
+ curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie);
+ curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie);
+ }
+
+ $temp = curl_exec($ch);
+ if (($result->code = curl_errno($ch)) != 0) {
+ $result->error = curl_error($ch);
+ curl_close($ch);
+ unset($ch);
+ return $result;
+ }
+
+ curl_close($ch);
+ unset($ch);
+
+ $response = leech_parse_http_response($temp);
+ $result->code = $response[0];
+ $result->headers = $response[1];
+ $result->data = $response[2];
+
+ // Workaround for xml w/ single quotes. drupal_xml_create_parser don't handle it well
+ $result->data = ereg_replace("^(<\?xml[^>]+encoding=)'([^'\"]+)'", '\\1"\\2"', $result->data);
+
+ $error = $response[3];
+ switch ($result->code) {
+ case 200: // OK
+ case 206: // Partial content returned (we asked for range of bytes)
+ case 304: // Not modified
+ break;
+ case 301: // Moved permanently
+ case 302: // Moved temporarily
+ case 307: // Moved temporarily
+ $location = $result->headers['location'];
+
+ if ($follow) {
+ $result = leech_http_request($result->headers['location'], $headers, $data, --$follow, $timeout, $cookie, $onlyHeaders, $username, $password);
+ $result->redirect_code = $result->code;
+ }
+ $result->redirect_url = $location;
+ break;
+ default:
+ $result->error = $error;
+ break;
+ }
+
+ $result->code = $response[0];
+ return $result;
+}
+
+/**
+ * Update feed node and create news items
+ *
+ * @param $node ... feed node
+ */
+function _leech_news_save_items(&$node) {
+ if (!is_array($node->leech->connection->news_feed->items) || count($node->leech->connection->news_feed->items) < 1) {
+ return;
+ }
+
+ $edit = (object) node_template_load($node->leech_news->template);
+ if ($edit == NULL) {
+ return;
+ }
+
+ // Don't add items older than allowed age for items
+ if ($node->leech_news->items_delete != 1000000000) {
+ // calculate time horizont converted to user's timezone
+ $time_horizont = time() - $node->leech_news->items_delete;
+ }
+ else {
+ $time_horizont = 0;
+ }
+
+ // Prepare data needed for promoting items
+ // TODO: maybe select just those which will not be deleted? so update at the end of this funtion would have less nodes to update :)
+ $promoted = array();
+ $promoted_changed = FALSE;
+ if ($node->leech_news->items_promote != 1000000000 && $node->leech_news->items_promote != 0) {
+ $result = db_query('SELECT i.nid AS nid, n.created AS created FROM {node} n INNER JOIN {leech_news_item} i ON i.nid = n.nid WHERE i.fid = %d AND n.status = 1 AND n.promote = 1 ORDER BY n.created ASC', $node->nid);
+ while ($temp = db_fetch_array($result)) {
+ $promoted[$temp['nid']] = $temp['created'];
+ }
+ if (count($promoted) != $node->leech_news->items_promote) {
+ $promoted_changed = TRUE;
+ }
+ }
+
+ // if og installed, feed items should inherit feed's og settings
+ if (module_exists('og')) {
+ $inheritgroup = true;
+ }
+ if (module_exists('taxonomy')) {
+ $inherittaxonomy = variable_get('leech_news_pass_on_taxonomy', 0);
+ }
+
+ global $user;
+ $duplicate_count = 0;
+ $items_added = 0;
+ $unique_links = $node->leech->connection->news_feed->has_unique_links;
+ foreach ($node->leech->connection->news_feed->items as $item) {
+ if (!$item->guid && $node->leech_news->items_guid) {
+ $item->guid = md5("$item->title - $item->body");
+ }
+ if (!$node->leech_news->items_date) {
+ $item->date = time();
+ }
+
+ // Ignore items older than allowed for feed
+ if ($item->date < $time_horizont) {
+ continue;
+ }
+
+ // check for duplicates
+ if (trim($item->link)) {
+ $result = db_result(db_query("SELECT COUNT(nid) FROM {leech_news_item} WHERE link = '%s' AND fid = %d", $item->link, $node->nid));
+ if ($result > 0) {
+ $duplicate_count++;
+ if (variable_get('leech_news_verbose', FALSE) === 1) {
+ watchdog('leech', t('Found duplicate. Link: !link', array('!link' => l($item->link, $item->link))));
+ }
+ continue;
+ }
+ }
+ else {
+ watchdog('leech', t('Feed item has no link. Title: %title', array('%title' => $item->title)));
+ }
+
+ $entry = NULL;
+ if (isset($item->guid) && strlen($item->guid) > 0) {
+ $entry = db_fetch_object(db_query("SELECT nid FROM {leech_news_item} WHERE guid = '%s' AND fid = %d", $item->guid, $node->nid));
+ }
+ else if (isset($unique_links) && isset($item->link) && $item->link != $node->leech_news->link && $item->link != $node->leech->url) {
+ $entry = db_fetch_object(db_query("SELECT nid FROM {leech_news_item} WHERE link = '%s' AND fid = %d", $item->link, $node->nid));
+ }
+ else {
+ $entry = db_fetch_object(db_query("SELECT n.nid AS nid FROM {node} n INNER JOIN {leech_news_item} i ON i.nid = n.nid WHERE i.fid = %d AND n.title = '%s'", $node->nid, $item->title));
+ }
+ if (isset($entry) && isset($entry->nid)) {
+ if (!$node->leech_news->items_update) {
+ continue;
+ }
+ $edit = node_load($entry->nid);
+ }
+ else {
+ $edit = (object) node_template_load($node->leech_news->template);
+ }
+
+ // avoid overwriting user's changes
+ if (!isset($edit->nid)) {
+ // From node.module
+ $node_options = variable_get('node_options_'. $node->type, array('status', 'promote'));
+ foreach (array('moderate', 'sticky', 'revision') as $key) {
+ $node->$key = in_array($key, $node_options);
+ }
+
+ $edit->status = $node->leech_news->items_status;// in_array('status', $node_options);
+ if ($node->leech_news->items_promote == 0) {
+ $edit->promote = 0;
+ }
+ else {
+ $edit->promote = 1;
+ }
+ $edit->date = format_date($item->date, 'custom', 'Y-m-d H:i O');
+ $edit->created = strtotime($edit->date);
+
+ $edit->leech_news_item->guid = ($item->guid ? $item->guid : '');
+ }
+
+ $edit->leech_news_item->fid = $node->nid;
+ $edit->leech_news_item->link = ($item->link ? $item->link : '');
+ if (!$edit->leech_news_item->author) {
+ $edit->leech_news_item->author = ($item->author ? $item->author : '');
+ }
+ $edit->leech_news_item->source_link = ($item->source_link ? $item->source_link : '');
+ $edit->leech_news_item->source_xml = ($item->source_xml ? $item->source_xml : '');
+ $edit->leech_news_item->source_title = ($item->source_title ? $item->source_title : '');
+ $edit->title = $item->title;
+ $edit->body = $item->body;
+ $edit->teaser = ($item->teaser ? $item->teaser : node_teaser($edit->body, isset($edit->format) ? $edit->format : NULL));
+
+ // copy group properties from feed node - note: groups present here
+ // pass on group properties from feed to item
+ if ($inheritgroup == TRUE) {
+ if (isset($node->og_public) ) {
+ if (!isset($edit->og_public)) {
+ $edit->og_public = 1;
+ }
+ $edit->og_public = $edit->og_public & $node->og_public;
+ }
+ if (isset($node->og_groups)) {
+ if (!is_array($edit->og_groups)) {
+ $edit->og_groups = array();
+ }
+ $edit->og_groups = array_merge($node->og_groups, $edit->og_groups);
+ }
+ if (isset($node->og_groups_names)) {
+ if (!is_array($edit->og_groups_names)) {
+ $edit->og_groups_names = array();
+ }
+ $edit->og_groups_names = array_merge($node->og_groups_names, $edit->og_groups_names);
+ }
+ }
+ // pass on taxonomy from feed to item
+ if ($inherittaxonomy == TRUE) {
+ if (isset($node->taxonomy)) {
+ if (!is_array($edit->taxonomy)) {
+ $edit->taxonomy = array();
+ }
+ $edit->taxonomy = array_merge($node->taxonomy, $edit->taxonomy);
+ }
+ if (isset($node->taxonomy_user)) {
+ if (!is_array($edit->taxonomy_user)) {
+ $edit->taxonomy_user = array();
+ }
+ $edit->taxonomy = array_merge($node->taxonomy_user, $edit->taxonomy_user);
+ }
+ }
+
+ // Temporary properties
+ $edit->leech_news_item->feed_data = &$node->leech->connection->news_feed;
+ if(module_exists('localizernode')) {
+ $feed_language = localizernode_findbynid($node->nid);
+ unset($edit->localizernode_pid);
+ $edit->localizernode_locale = $feed_language['locale'];
+ }
+ if ($errors = node_template_save($edit)) {
+ watchdog('leech', t('Could not save %type node %title from feed: %feed.', array('%type' => t($edit->type), '%title' => $edit->title, '%feed' => $node->title)), WATCHDOG_ERROR, l(t('view'), 'node/'. $node->nid));
+ }
+ else {
+ // Call the term extraction if enabled
+ $current = variable_get('leech_term_extraction', 0);
+ $current = $current['leech_terms_per_feed'];
+ if ($current != 0) {
+ $vid = $current[$edit->leech_news_item->fid]['vocab'];
+ $query = $current[$edit->leech_news_item->fid]['query'];
+ }
+ if (!is_numeric($vid)) {
+ $vid = NULL;
+ }
+ if (strlen($query) < 1) {
+ $query = NULL;
+ }
+ node_invoke_nodeapi($edit, "terms_tagging", $vid, $query);
+
+ if ($edit->is_new) {
+ if ($edit->promote && $node->leech_news->items_promote != 1000000000) {
+ $promoted[$edit->nid] = $edit->created;
+ $promoted_changed = TRUE;
+ }
+ $items_added++;
+ watchdog('leech', t('%type: added %title from feed: %feed.', array('%type' => t($edit->type), '%title' => $edit->title , '%feed' => $node->title )), WATCHDOG_NOTICE, l(t('view'), 'node/'. $edit->nid));
+ }
+ else {
+ watchdog('leech', t('%type: updated %title from feed: %feed.', array('%type' => t($edit->type) , '%title' => $edit->title , '%feed' => $node->title )), WATCHDOG_NOTICE, l(t('view'), 'node/'. $edit->nid));
+ }
+
+ sleep(variable_get('leech_sleep_interval', 0));
+ }
+
+ }
+
+ // Update adaptive informations
+ if ($node->leech->adaptive) {
+ _leech_compute_adaptive_values(
+ $node->leech->refresh,
+ $node->leech->avg_btw_news,
+ $node->leech->deviation,
+ $node->leech->num_of_tests,
+ $node->leech->news_last_arrived,
+ $items_added
+ );
+ }
+
+ watchdog('leech', "$items_added item(s) added, $duplicate_count duplicate(s) found. Leech node: {$node->nid}, {$node->title}");
+ drupal_set_message("$items_added item(s) added, $duplicate_count duplicate(s) found.");
+
+ // Handle promotion stuff
+ if ($node->leech_news->items_promote != 1000000000 && $node->leech_news->items_promote != 0 && $promoted_changed == TRUE) {
+ $temp = array();
+ $range = count($promoted) - $node->leech_news->items_promote;
+ // If there is less promoted items than needed we have to create new list of promoted
+ if ($range < 0) {
+ $result = db_query_range('SELECT n.nid, n.created FROM {node} n INNER JOIN {leech_news_item} i ON n.nid = i.nid WHERE n.status = 1 AND i.fid = %d ORDER BY n.created DESC', $node->nid, 0, $node->leech_news->items_promote);
+ while ($temp = db_fetch_object($result)) {
+ $promoted[$temp->nid] = $temp->created;
+ }
+ }
+ asort($promoted);
+ $promoted = array_unique(array_keys($promoted));
+
+ $range = count($promoted) - $node->leech_news->items_promote;
+ if ($range > 0) {
+ $demoted = array_slice($promoted, 0, $range);
+ $promoted = array_slice($promoted, $range);
+ }
+ // Promote those which should be promoted
+ if (count($promoted) > 0) {
+ db_query('UPDATE {node} SET promote = 1 WHERE nid IN (%s)', implode(',', $promoted));
+ }
+ // Demote those which should not be promoted
+ if (count($demoted) > 0) {
+ db_query('UPDATE {node} SET promote = 0 WHERE nid IN (%s)', implode(',', $demoted));
+ }
+ }
+ return $items_added;
+}
+
+/**
+ * Create opml items
+ */
+function leech_opml_save_items(&$node) {
+ if (!is_array($node->leech->connection->result->dataXML['opml'][0]['body'][0]['outline'])) {
+ return;
+ }
+
+ $edit = (object) node_template_load($node->leech_opml->template);
+ if (!$edit) {
+ return;
+ }
+
+ global $user;
+ // TODO: this handles only 1 level of outline. Add handling of nested outlines.
+ foreach ($node->leech->connection->result->dataXML['opml'][0]['body'][0]['outline'] as $item) {
+ $url = $item['xmlUrl'];
+
+ $entry = NULL;
+ if ($url && strlen($url) > 0) {
+ $entry = db_fetch_object(db_query("SELECT nid FROM {leech} WHERE url = '%s'", $url));
+ }
+
+ if ($entry && $entry->nid) {
+ // TODO: add items_update option to OPML edit form :)
+ // allow to select if user wants to alway keep only feeds existing in current OPML data
+ // or add all new (so even if one of the feeds is not in opml data anymore, it will be left working ok here).
+ if (!$node->leech_opml->items_update) {
+ continue;
+ }
+ $edit = node_load($entry->nid);
+ }
+ else {
+ $edit = (object) node_template_load($node->leech_opml->template);
+ }
+
+ // avoid overwriting user's changes
+ if (!$edit->nid) {
+ // From node.module
+ $node_options = variable_get('node_options_'. $node->type, array('status', 'promote'));
+ foreach (array('moderate', 'sticky', 'revision', 'status', 'promote') as $key) {
+ $edit->$key = in_array($key, $node_options);
+ }
+
+ $edit->date = format_date(time(), 'custom', 'Y-m-d H:i O');
+ $edit->created = strtotime($edit->date);
+ }
+
+ $edit->title = $item['text'];
+ $edit->leech->url = $url;
+
+ // Set defaults
+ if (!isset($edit->leech->refresh)) {
+ $edit->leech->refresh = variable_get('leech_refresh#'.$edit->type, 0);
+ }
+ if (!isset($edit->leech_news->template)) {
+ $edit->leech_news->template = variable_get('leech_news_template_'.$edit->type, 0);
+ $edit->leech_news->items_guid = variable_get('leech_news_items_guid_'.$edit->type, 0);
+ $edit->leech_news->items_status = variable_get('leech_news_items_status_'.$edit->type, 1);
+ $edit->leech_news->items_update = variable_get('leech_news_items_update_'.$edit->type, 0);
+ $edit->leech_news->items_delete = variable_get('leech_news_items_delete_'.$edit->type, 15724800);
+ $edit->leech_news->items_promote = variable_get('leech_news_items_promote_'.$edit->type, 3);
+ $edit->leech_news->items_date = variable_get('leech_news_items_date_'.$edit->type, 1);
+ $edit->leech_news->links_display_mode = variable_get('leech_news_links_'.$edit->type, LEECH_SHOW_LINK_ALWAYS);
+ }
+
+ // Temporary properties
+ $edit->leech_opml_item->opml_data = &$node->leech->connection->result->dataXML;
+ $edit->leech_opml_item->item_data = &$item;
+
+ if ($errors = node_template_save($edit)) {
+ watchdog('leech', t('Could not save %type node %title from opml: %feed.', array('%type' => t($edit->type) , '%title' => $edit->title , '%feed' => $node->title)), WATCHDOG_ERROR, l(t('view'), 'node/'. $node->nid));
+ }
+ else {
+ if ($edit->is_new) {
+ watchdog('leech', t('%type: added %title from opml: %feed.', array('%type' => t($edit->type) , '%title' => $edit->title , '%feed' => $node->title)), WATCHDOG_NOTICE, l(t('view'), 'node/'. $edit->nid));
+ }
+ else {
+ watchdog('leech', t('%type: updated %title from opml: %feed.', array('%type' => t($edit->type) , '%title' => $edit->title , '%feed' => $node->title)), WATCHDOG_NOTICE, l(t('view'), 'node/'. $edit->nid));
+ }
+ sleep(variable_get('leech_sleep_interval', 0));
+ }
+ }
+}
+
+
+function leech_opml_parse(&$xml) {
+ // "Parse" tags :)
+ preg_match_all('%(?:\<)((|\w+\:)?\w+)(| .*?)(?=\/>()|\>().*?()\<\/\1\>())%s', $xml, $tags, PREG_SET_ORDER | PREG_OFFSET_CAPTURE);
+ /*
+ Spec:
+ $tags[$i] = Array with info about tag. each "info" is array of 2 elements.
+ 1st may contain text data.
+ 2nd contains offset in document where data (or just taht "point") starts.
+ $tags[$i][1] = Tag name
+ [1] = Name string (may include namespace if such exist).
+ [2] = Offset integer.
+ $tags[$i][2] = Namespace
+ [1] = Namespace string (including ":" sign, like: "rss:")
+ [2] = Offset integer.
+ $tags[$i][3] = Attributes
+ [1] = String containing all attributes data.
+ $tags[$i][4] = End of "open-end" tag
+ [2] = Integer offset if tag was of type " ", else -1
+ Following fields exist only if tag was of type ".. " (ie. had open and end part).
+ $tags[$i][5] = End of "open" part of tag (and start of "value" part at the same time :)
+ [2] = Integer offset
+ $tags[$i][6] = End of "value" part of tag (and start of "end" part at the same time :)
+ [2] = Integer offset
+ $tags[$i][7] = End of "end" part of tag
+ [2] = Integer offset
+ Following fields will be added in loop below.
+ $tags[$i][8] = Integer offset of tag end (ie. value from [4] or [7] depending on type of tag).
+ $tags[$i][9] = Integer key of "parent" tag (ie. 2 means $tags[2] is parent of $tags[$i]).
+ $tags[$i][10] = Integer of depth.
+ $tags[$i][11] = Array of integer keys of "children".
+ */
+ $tags_count = count($tags);
+ $depth = 0;
+ for ($i = 0; $i < $tags_count; $i++) {
+ $name = strtolower($tags[$i][1][0]);
+
+ // Remember end of tag so we don't have to check it each time
+ $tags[$i][8] = ($tags[$i][7] ? $tags[$i][7][1] : $tags[$i][4][1]);
+
+ // Find parent
+ $prev = $i-1;
+ $tags[$i][9] = ($prev > -1 ? $prev : -1);
+ while (isset($tags[$prev][8]) && $tags[$i][0][1] > $tags[$prev][8]) {
+ $tags[$i][9] = $prev-1;
+ $prev--;
+ }
+
+ // Get depth
+ $tags[$i][10] = ($tags[$i][9] > -1 ? $tags[$tags[$i][9]][10]+1 : $depth+1);
+
+ // If depth changed, change stack
+ $depth_change = 0;
+ if ($depth != $tags[$i][10]) {
+ // Calculate difference of depth
+ $depth_change = $tags[$i][10] - $depth;
+ // Remember "current" depth
+ $depth = $tags[$i][10];
+ }
+
+ // Attributes
+ if (trim($tags[$i][3][0])) {
+ preg_match_all('/((\w+\:)?\w+)((\s*=\s*"(.*?)")|(\s*=\s*\'(.*?)\')|(\s*=\s*(\w+))|())/s', $tags[$i][3][0], $attributes, PREG_SET_ORDER);
+ foreach ($attributes as $attr) {
+ $tags[$i][$attr[1]] = end($attr);
+ }
+ }
+
+ // Make "alias" for this tag
+ if ($tags[$i][9] > -1) {
+ if (!$tags[$tags[$i][9]][$name]) {
+ $tags[$tags[$i][9]][$name] = array();
+ }
+ if (is_array($tags[$tags[$i][9]][$name])) {
+ $tags[$tags[$i][9]][$name][] = &$tags[$i];
+ }
+ }
+ else {
+ if (!$tags[$name]) {
+ $tags[$name] = array();
+ }
+ $tags[$name][] = &$tags[$i];
+ }
+ }
+
+ // Remember full xml data as value.
+ $tags['#value'] = $xml;
+
+ return $tags;
+}
+
+/**
+ * Handle the adaptive behaviour of the feed. Feed-refreshing means that the original feed is refreshed.
+ *
+ * @param integer $refresh_frequency
+ *
+ * @param $avg_btw_news
+ * The average value of the statistical sample of how much time is between the feed-refreshing
+ * @param $deviation
+ * The standard deviation of the statistical sample; not exactly, just something approximation
+ * @param $num_of_tests
+ * How many times the feed-refresging interval is measured
+ * @param $news_last_arrived
+ * The last feed-refreshing instant
+ * @param $items_added
+ * Currently added items to the feed
+ *
+ */
+function _leech_compute_adaptive_values(&$refresh_frequency, &$avg_btw_news, &$deviation, &$num_of_tests, &$news_last_arrived, $items_added) {
+ if ($items_added <= 0 || $refresh_frequency == 0) {
+ return;
+ }
+ $now = time();
+ // Computing the new values
+ $curr_diff = abs($now - $news_last_arrived);
+ $prev_total = $num_of_tests * $avg_btw_news;
+ if ($prev_total == 0) {
+ $new_average = ($refresh_frequency + $curr_diff) / 2;
+ } else {
+ $new_average = ($prev_total + $curr_diff) / ($num_of_tests + 1);
+ }
+ $prev_dev_sum = sqrt($deviation) * $num_of_tests;
+ // Not really deviation. But if num_of_test -> infinity then this value -> deviation.
+ $new_deviation = sqrt(($prev_dev_sum + pow($curr_diff - $new_average, 2)) * (1 / ($num_of_tests + 1)));
+
+ // Update the values
+ $news_last_arrived = $now;
+ $deviation = $new_deviation;
+ $avg_btw_news = $new_average;
+ $num_of_tests += 1;
+ // $leech->refresh modifying strategy
+ $refresh_frequency = intval(abs($avg_btw_news * (1 - ($deviation / $avg_btw_news))));
+}
+
+function leech_opml_parse_value(&$tree, &$element) {
+ if ($element[5][1] && $tree['#value']) {
+ return substr($tree['#value'], $element[5][1], $element[6][1]-$element[5][1]);
+ }
+}
+
+/**
+ * private function,
+ * for being called in nodeapi submit hook
+ * passes on group settings of feed node to all related feed items
+ *
+ * @param unknown_type $node
+ */
+function _leech_news_pass_on_groups(&$node) {
+
+ if (!module_exists('og')) {
+ return;
+ }
+
+ if (!is_array($node->og_groups)) {
+ return;
+ }
+
+ if (!isset($node->nid)) {
+ return;
+ }
+
+ timer_start("ogpass");
+
+ $r = db_query("SELECT DISTINCT nid FROM {leech_news_item} WHERE fid = %d", $node->nid);
+ $updated = 0; $total = 0;
+ while ($n = db_fetch_object($r)) {
+
+ db_query("DELETE FROM {node_access} WHERE nid = %d AND realm LIKE '%s'", $n->nid, 'og_%');
+
+ if (is_array($node->og_groups)) {
+ foreach ($node->og_groups as $gid) {
+ if ($gid != 0) {
+ $sql = "INSERT INTO {node_access} (nid, gid, realm, grant_view, grant_update, grant_delete)
+ VALUES (%d, %d, 'og_subscriber', 1, 1, 1)";
+ db_query($sql, $n->nid, $gid);
+
+ $sql = "DELETE FROM {og_ancestry} WHERE nid = $n->nid AND group_nid = $gid";
+ db_query($sql, $n->nid, $gid);
+ $sql = "INSERT INTO {og_ancestry} (nid, group_nid, is_public) VALUES (%d, %d, 1)";
+ db_query($sql, $n->nid, $gid);
+
+ if ($node->og_public) {
+ $sql = "INSERT INTO {node_access} (nid, gid, realm, grant_view) VALUES (%d, 0, 'og_public', %d)";
+ db_query($sql, $n->nid, $gid);
+ }
+ }
+ }
+ }
+
+ // if the public checkbox was selected, give a universal grant for this node
+ if ($node->og_public) {
+ $sql = "INSERT INTO {node_access} (nid, gid, realm, grant_view) VALUES (%d, 0, 'og_all', 1)";
+ db_query($sql, $n->nid);
+ }
+ $updated++;
+ }
+
+ if ($updated > 0) {
+ drupal_set_message("Group settings of ".$updated." child feed item(s) updated in ".timer_read("ogpass")." ms", "status");
+ }
+ // Transform the $node->og_groups according to the og_submit_group taste
+ foreach($node->og_groups as $gid) {
+ $transformed_groups[$gid] = $gid;
+ }
+ $node->og_groups = $transformed_groups;
+ timer_stop("ogpass");
+}
+
+/**
+ * passes on taxonomy _changes_ for a given leech node to all its leech item nodes
+ *
+ * leaves terms unchanged, that were not inherited from this node.
+ *
+ * @param node object $node
+ */
+function _leech_news_pass_on_taxonomy(&$node) {
+
+ if (!is_array($node->taxonomy['tags']))
+ return;
+
+ timer_start("taxpass");
+
+ // 1) get terms that where associated to this node before
+ $result = db_query("SELECT tid FROM {term_node} WHERE nid = %d", $node->nid);
+
+ $now = array();
+ $before = array();
+
+ while ($term = db_fetch_object($result)) {
+ $before[] = $term->tid;
+ }
+
+ // 2) get terms that are associated to this node now
+ foreach ($node->taxonomy['tags'] as $vid => $tagstring) {
+ $tagstring = trim($tagstring);
+ if ($tagstring == "")
+ continue;
+ $tnames = explode(",", $tagstring);
+ foreach ($tnames as $tname) {
+ $len = count($now);
+ $termsbyname = taxonomy_get_term_by_name(trim($tname));
+ foreach ($termsbyname as $tbn) {
+ if ($tbn->vid == $vid) {
+ $now[] = $tbn->tid;
+ break;
+ }
+ }
+ // if term not found, create it
+ if ($len == count($now)) {
+ $edit['name'] = trim($tname);
+ $edit['vid'] = $vid;
+ taxonomy_save_term($edit);
+ if ($edit['tid']) {
+ $now[] = $edit['tid'];
+ watchdog("leech", "error passing on terms to node - error saving new term");
+ }
+ }
+ }
+ }
+
+ // 3) check out, which terms to add and which terms to delete
+ $add_tids = array_diff($now, $before);
+ $del_tids = array_diff($before, $now);
+
+ // 4) get all nodes and apply changes
+ $updated = array();
+ if ((count($add_tids) != 0 || count($del_tids) != 0)) {
+ $result = db_query("SELECT nid
+ FROM {leech_news_item} li
+ WHERE fid = %d
+ GROUP BY nid", $node->nid);
+ while ($feeditem = db_fetch_object($result)) {
+ $result_term_node = db_query("SELECT tid
+ FROM {term_node}
+ WHERE nid = %d", $feeditem->nid);
+ while ($termnode = db_fetch_object($result_term_node)) {
+ $tids[] = $termnode->tid;
+ if (in_array($termnode->tid, $del_tids )) {
+ db_query("DELETE FROM {term_node} WHERE nid = %d AND tid = %d", $feeditem->nid, $termnode->tid);
+ $updated[$feeditem->nid] = 1;
+ }
+ }
+ foreach ($add_tids as $add_tid) {
+ if (!in_array($add_tid, $tids)) {
+ db_query("INSERT INTO {term_node}(nid, tid) VALUES(%d, %d)", $feeditem->nid, $add_tid);
+ $updated[$feeditem->nid] = 1;
+ }
+ }
+ }
+ }
+
+ drupal_set_message("Taxonomy of ".count($updated)." child feed item(s) updated in ".timer_read("taxpass")." ms", "status");
+ timer_stop("taxpass");
+}
+
+function leech_nodebody() {
+ $nid = $_GET['nid'];
+ $node = node_load($nid);
+ echo '' . $node->body . '
';
+ echo '';
+ exit;
+}
+
+function leech_articleoriginal() {
+ $nid = $_GET['nid'];
+ $node = node_load($nid);
+ leech_statistic($nid);
+ echo '';
+ echo '';
+ echo '';
+ echo '
';
+ exit;
+}
+
+function leech_statistic($nid) {
+ global $user;
+
+ if (variable_get('statistics_count_content_views', 0)) {
+ // We are counting content views.
+ if (is_numeric($nid)) {
+ // A node has been viewed, so update the node's counters.
+ db_query('UPDATE {node_counter} SET daycount = daycount + 1, totalcount = totalcount + 1, timestamp = %d WHERE nid = %d', time(), $nid);
+ // If we affected 0 rows, this is the first time viewing the node.
+ if (!db_affected_rows()) {
+ // We must create a new row to store counters for the new node.
+ db_query('INSERT INTO {node_counter} (nid, daycount, totalcount, timestamp) VALUES (%d, 1, 1, %d)', $nid, time());
+ }
+ }
+ }
+ if ((variable_get('statistics_enable_access_log', 0)) && (module_invoke('throttle', 'status') == 0)) {
+ // Log this page access.
+ db_query("INSERT INTO {accesslog} (title, path, url, hostname, uid, sid, timer, timestamp) values('%s', '%s', '%s', '%s', %d, '%s', %d, %d)", strip_tags(drupal_get_title()), 'node/' . $nid, referer_uri(), $_SERVER['REMOTE_ADDR'], $user->uid, session_id(), timer_read('page'), time());
+ }
+}
+
+
+function leech_articlepreview($nid) {
+ $node = node_load($nid);
+
+ $o = '';
+ $o .= '' . drupal_get_title() . ' ';
+ $o .= '';
+ $o .= ' ';
+ $o .= ' ';
+ $o .= ' ';
+ $o .= ' ';
+ $o .= '';
+
+ echo $o;
+ exit();
+}
+
+function leech_articlepreviewheader($nid) {
+ $o = '';
+ $o .= '' . drupal_get_title() . ' ';
+ $o .= '';
+ $o .= 'Logo, links, tools';
+ $o .= '';
+ $o .= '';
+ echo $o;
+ exit();
+}
\ No newline at end of file
diff -urpN leech-orig/leech_views.info leech/leech_views.info
--- leech-orig/leech_views.info 1970-01-01 01:00:00.000000000 +0100
+++ leech/leech_views.info 2007-10-06 09:53:32.000000000 +0200
@@ -0,0 +1,5 @@
+name = Leech views
+description = "Provides views support for Leech"
+dependencies = leech views
+package = Leech
+version = 5.0
\ No newline at end of file
diff -urpN leech-orig/leech_views.module leech/leech_views.module
--- leech-orig/leech_views.module 1970-01-01 01:00:00.000000000 +0100
+++ leech/leech_views.module 2007-09-14 17:12:59.000000000 +0200
@@ -0,0 +1,216 @@
+Requires leech.module and views.module');
+ case 'admin/modules#description':
+ return t('Views for leech. Requires leech.module and views.module ');
+ }
+}
+
+/**
+ * Implementation of hook_views_tables()
+ *
+ * todo - timestamps are GMT
+ * - ability to filter on updated time
+ * - all kinds of sorts
+ */
+function leech_views_views_tables() {
+ $tables ['leech'] = array(
+ 'name' => 'leech',
+ 'provider' => 'leech',
+ 'join' => array(
+ 'left' => array(
+ 'table' => 'node',
+ 'field' => 'nid',
+ ),
+ 'right' => array(
+ 'field' => 'nid',
+ )
+ ),
+ 'fields' => array(
+ 'news_last_arrived' => array(
+ 'name' => t('Leech: Last Arrival'),
+ 'handler' => views_handler_field_dates(),
+ 'option' => 'string',
+ 'help' => t('Display the last time new items were found.'),
+ ),
+ 'refresh' => array(
+ 'name' => t('Leech: Refresh Time'),
+ 'handler' => views_handler_field_dates(),
+ 'option' => 'string',
+ 'help' => t('Display the next refresh time.'),
+ ),
+ 'checked' => array(
+ 'name' => t('Leech: Last Checked'),
+ 'handler' => views_handler_field_dates(),
+ 'option' => 'string',
+ 'help' => t('Display the last time the feed was checked.'),
+ ),
+ 'refresh_link' => array(
+ 'name' => t('Leech: Refresh Link'),
+ 'notafield' => TRUE,
+ 'handler' => 'leech_views_handler_field_refresh_link',
+ 'addlfields' => array('nid'),
+ 'help' => t('Display a refresh link'),
+ ),
+ 'url' => array(
+ 'name' => t('Leech: Source URL'),
+ 'handler' => 'leech_views_handler_field_source_url',
+ 'help' => t('Display a the Feed Source URL')
+ ),
+ ),
+ );
+ $tables ['leech_news_item'] = array(
+ 'name' => 'leech_news_item',
+ 'provider' => 'leech',
+ 'join' => array(
+ 'left' => array(
+ 'table' => 'node',
+ 'field' => 'nid',
+ ),
+ 'right' => array(
+ 'field' => 'nid',
+ )
+ ),
+ 'filters' => array(
+ 'fid' => array(
+ 'name' => t('Leech: Feed'),
+ 'operator' => 'views_handler_operator_andor',
+ 'list' => 'leech_views_handler_feed_filter',
+ 'value-type' => 'array',
+ 'help' => t('Filter by Feed'),
+ )
+ )
+ );
+ $tables ['leech_node'] = array(
+ 'name' => 'node',
+ 'provider' => 'internal',
+ 'join' => array(
+ 'left' => array(
+ 'table' => 'leech_news_item',
+ 'field' => 'fid'
+ ),
+ 'right' => array(
+ 'field' => 'nid'
+ )
+ ),
+ 'fields' => array(
+ 'title' => array(
+ 'name' => t('Leech: Feed Title'),
+ 'handler' => array(
+ 'leech_views_handler_field_feed_title' => t('As Link'),
+ 'leech_views_handler_field_feed_title_nl' => t('Without Link'),
+ ),
+ 'addlfields' => array('nid'),
+ 'help' => t('Display the title of the feed'),
+ ),
+ ),
+ 'sorts' => array(
+ 'title' => array(
+ 'name' => t('Leech: Feed Title'),
+ 'help' => t('Sort by the title of the feed'),
+ ),
+ ),
+ );
+
+ return $tables;
+}
+
+/**
+ * Implementation of hook_views_arguments()
+ */
+function leech_views_views_arguments(){
+ $arguments['leech_feed_id'] = array(
+ 'name' => 'Leech: Feed id',
+ 'help' => t('Select feed id'),
+ 'handler' => 'leech_views_arg_fid'
+ );
+ return $arguments;
+}
+
+/**
+ * Handler for feed ID argument
+ *
+ * todo - complete argument support
+ */
+function leech_views_arg_fid($op, &$query, $argtype, $arg = ''){
+ switch($op) {
+ /*
+ case 'summary':
+ $query->ensure_table('leech');
+ $query->add_field('fid', 'leech_news_item');
+ $fieldinfo['field'] = "leech_news_item.fid";
+ return $fieldinfo;
+ */
+ /*
+ case 'sort':
+ $query->add_orderby('vocabulary', 'weight', $argtype);
+ $query->add_orderby('vocabulary', 'name', $argtype);
+ break;
+ */
+ case 'filter':
+ $query->ensure_table('leech_news_item');
+ $query->add_where('leech_news_item.fid = %d', $arg);
+ $query->set_distinct();
+ break;
+ /*
+ case 'link':
+ return l($query->name, "$arg/" . intval($query->vid));
+ */
+ case 'title':
+ $result = db_query("SELECT title FROM {node} WHERE nid = %d", $arg);
+ $voc = db_fetch_object($result);
+ return check_plain($voc->name);
+ }
+}
+
+/**
+ * Provide filter options for filtering by feed
+ */
+function leech_views_handler_feed_filter(){
+ $result = db_query("SELECT n.nid, n.title FROM {node} n INNER JOIN {leech} l ON n.nid = l.nid ORDER BY n.title ASC");
+
+ $feeds = array();
+ while ($leech = db_fetch_object($result)) {
+ $feeds[$leech->nid] = $leech->title;
+ }
+
+ return $feeds;
+}
+
+/**
+ * Format a field as a link to the feed node
+ */
+function leech_views_handler_field_feed_title($fieldinfo, $fielddata, $value, $data) {
+ return l($value, "node/$data->leech_nodes_nid");
+}
+
+/**
+ * Format a title field without a link
+ */
+function leech_views_handler_field_feed_title_nl($fieldinfo, $fielddata, $value, $data) {
+ return check_plain($value);
+}
+
+/**
+ * Provide a refresh link
+ * todo - proper destination handling
+ */
+function leech_views_handler_field_refresh_link($fieldinfo, $fielddata, $value, $data){
+ return l('Refresh', "leech/refresh/$data->nid");
+}
+
+/**
+ * Format the source url
+ */
+function leech_views_handler_field_source_url($fieldinfo, $fielddata, $value, $data) {
+ return check_plain($value);
+}
\ No newline at end of file
Binary files leech-orig/loading_animation.gif and leech/loading_animation.gif differ