diff --git a/.htaccess b/.htaccess index 7e563745cc9c..473a5ec3d078 100644 --- a/.htaccess +++ b/.htaccess @@ -8,11 +8,6 @@ deny from all -# Syndicate content: - - ForceType application/x-httpd-php - - # Customized server error messages: ErrorDocument 400 /error.php ErrorDocument 402 /error.php diff --git a/CHANGELOG b/CHANGELOG index c416ffc414b0..164a321be23a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -7,6 +7,8 @@ drupal x.xx, xx/xx/xxxx (CVS, unstable) - removed ban module and integrated it into account.module as "access control": * access control is based on much more powerful regular expressions (regex) now rather than on MySQL pattern matching. - rewrote watchdog and submission throttle +- rewrote headline code and renamed it to import.module and export.module + * added a various new features compared with the old headline code. - rewrote section code and renamed it to structure.module: * supports both "categories" and "topics" (cfr. Scoop, SlashCode). Topics can be nested to create a multi-level hierarchy. * added "auto-post new submissions" feature versus "moderate new submissions". diff --git a/export b/export.php similarity index 66% rename from export rename to export.php index c11073879d09..5b2142a151ea 100644 --- a/export +++ b/export.php @@ -2,6 +2,8 @@ include_once "includes/common.inc"; -foreach (module_list() as $module) module_invoke($module, "export", explode("/", $REQUEST_URI)); +$uri = parse_url($REQUEST_URI); + +foreach (module_list() as $module) module_invoke($module, "export", $uri["query"]); ?> \ No newline at end of file diff --git a/modules/syndication.module b/modules/aggregator.module similarity index 75% rename from modules/syndication.module rename to modules/aggregator.module index 952088fcb1ea..a4b85041ea7c 100644 --- a/modules/syndication.module +++ b/modules/aggregator.module @@ -2,30 +2,30 @@ include_once "modules/backend.class"; -function syndication_help() { +function import_help() { ?>

TODO - anyone?

$feed[uncache]"); // update feeds: - if ($feed[timestamp] + $feed[refresh] < time()) syndication_update($feed); + if ($feed[timestamp] + $feed[refresh] < time()) import_update($feed); } } -function syndication_bundle($attribute) { +function import_bundle($attribute, $limit = 100) { if ($attribute) { // compose query: $keys = explode(",", $attribute); foreach ($keys as $key) $where[] = "attribute LIKE '%". trim($key) ."%'"; - $result = db_query("SELECT * FROM item WHERE ". implode(" OR ", $where) ." ORDER BY timestamp DESC"); + $result = db_query("SELECT * FROM item WHERE ". implode(" OR ", $where) ." ORDER BY timestamp DESC LIMIT $limit"); while ($item = db_fetch_object($result)) { $output .= "
  • link) ."\">". check_output($item->title) ."
  • "; @@ -35,15 +35,26 @@ function syndication_bundle($attribute) { } } -function syndication_view_bundle() { +function import_view_bundle() { $result = db_query("SELECT * FROM bundle ORDER BY title"); while ($bundle = db_fetch_object($result)) { - $output .= "$bundle->title"; + $output .= "$bundle->title"; } return $output; } -function syndication_update($feed) { +function import_block() { + $result = db_query("SELECT * FROM bundle ORDER BY title"); + while ($bundle = db_fetch_object($result)) { + $i++; + $blocks[$i][subject] = $bundle->title; + $blocks[$i][content] = import_bundle($bundle->attribute, 10); + $blocks[$i][info] = "$bundle->title bundle"; + } + return $blocks; +} + +function import_update($feed) { // open socket: $url = parse_url($feed[link]); @@ -65,7 +76,7 @@ function syndication_update($feed) { $d = eregi("(.*)", $item, $description); if ($l || $t || $a || $d) { - syndication_save_item(array(fid => $feed[fid], title => $title[0], link => $link[0], author => $author[0], description => $description[0], attribute => $feed[attribute])); + import_save_item(array(fid => $feed[fid], title => $title[0], link => $link[0], author => $author[0], description => $description[0], attribute => $feed[attribute])); } } @@ -77,7 +88,7 @@ function syndication_update($feed) { } } -function syndication_save_item($edit) { +function import_save_item($edit) { if ($edit[iid] && $edit[title]) { db_query("UPDATE item SET title = '". check_input($edit[title]) ."', link = '". check_input($edit[link]) ."', author = '". check_input($edit[author]) ."', description = '". check_input($edit[description]) ."', attribute = '". check_input($edit[attribute]) ."' WHERE iid = '$edit[iid]'"); } @@ -91,7 +102,7 @@ function syndication_save_item($edit) { } } -function syndication_form_bundle($edit = array()) { +function import_form_bundle($edit = array()) { global $REQUEST_URI; $form .= form_textfield("Title", "title", $edit[title], 50, 64, "The name of the bundle."); @@ -107,7 +118,7 @@ function syndication_form_bundle($edit = array()) { return form($REQUEST_URI, $form); } -function syndication_save_bundle($edit) { +function import_save_bundle($edit) { if ($edit[bid] && $edit[title]) { db_query("UPDATE bundle SET title = '". check_input($edit[title]) ."', attribute = '". check_input($edit[attribute]) ."' WHERE bid = '". check_input($edit[bid]) ."'"); } @@ -117,9 +128,11 @@ function syndication_save_bundle($edit) { else { db_query("INSERT INTO bundle (title, attribute) VALUES ('". check_input($edit[title]) ."', '". check_input($edit[attribute]) ."')"); } + + module_rehash_blocks("import"); } -function syndication_form_feed($edit = array()) { +function import_form_feed($edit = array()) { global $REQUEST_URI; $period = array(900 => format_interval(900), 1800 => format_interval(1800), 3600 => format_interval(3600), 7200 => format_interval(7200), 10800 => format_interval(10800), 21600 => format_interval(21600), 32400 => format_interval(32400), 43200 => format_interval(43200), 64800 => format_interval(64800), 86400 => format_interval(86400), 172800 => format_interval(172800), 259200 => format_interval(259200), 604800 => format_interval(604800), 1209600 => format_interval(1209600), 2419200 => format_interval(2419200)); @@ -140,7 +153,7 @@ function syndication_form_feed($edit = array()) { return form($REQUEST_URI, $form); } -function syndication_save_feed($edit) { +function import_save_feed($edit) { if ($edit[fid] && $edit[title]) { db_query("UPDATE feed SET title = '". check_input($edit[title]) ."', link = '". check_input($edit[link]) ."', attribute = '". check_input($edit[attribute]) ."', refresh = '". check_input($edit[refresh]) ."', uncache = '". check_input($edit[uncache]) ."' WHERE fid = '". check_input($edit[fid]) ."'"); db_query("DELETE FROM item WHERE fid = '". check_input($edit[fid]) ."'"); @@ -154,29 +167,29 @@ function syndication_save_feed($edit) { } } -function syndication_save_attributes($edit) { +function import_save_attributes($edit) { foreach($edit as $iid => $value) { db_query("UPDATE item SET attribute = '". check_input($value) ."' WHERE iid = '". check_input($iid) ."'"); } return "attributes has been saved"; } -function syndication_get_feed($fid) { +function import_get_feed($fid) { return db_fetch_array(db_query("SELECT * FROM feed WHERE fid = '". check_input($fid) ."'")); } -function syndication_get_bundle($bid) { +function import_get_bundle($bid) { return db_fetch_array(db_query("SELECT * FROM bundle WHERE bid = '". check_input($bid) ."'")); } -function syndication_view_feed() { +function import_view_feed() { $result = db_query("SELECT f.*, COUNT(i.iid) AS items FROM feed f LEFT JOIN item i ON f.fid = i.fid GROUP BY f.fid ORDER BY f.title"); $output .= "

    Feed overview

    "; $output .= "\n"; $output .= " \n"; while ($feed = db_fetch_object($result)) { - $output .= " \n"; + $output .= " \n"; } $output .= "
    titleattributesitemslast updatenext updateoperations
    ". check_output($feed->title) ."". check_output($feed->attribute) ."". format_plural($feed->items, "item", "items") ."". ($feed->timestamp ? format_interval(time() - $feed->timestamp) ." ago" : "never") ."". ($feed->timestamp ? format_interval($feed->timestamp + $feed->refresh - time()) ." left" : "never") ."fid\">edit feedfid\">update items
    ". check_output($feed->title) ."". check_output($feed->attribute) ."". format_plural($feed->items, "item", "items") ."". ($feed->timestamp ? format_interval(time() - $feed->timestamp) ." ago" : "never") ."". ($feed->timestamp ? format_interval($feed->timestamp + $feed->refresh - time()) ." left" : "never") ."fid\">edit feedfid\">update items
    \n"; @@ -186,14 +199,14 @@ function syndication_view_feed() { $output .= "\n"; $output .= " \n"; while ($bundle = db_fetch_object($result)) { - $output .= " \n"; + $output .= " \n"; } $output .= "
    titleattributesoperations
    ". check_output($bundle->title) ."". check_output($bundle->attribute) ."bid\">edit bundle
    ". check_output($bundle->title) ."". check_output($bundle->attribute) ."bid\">edit bundle
    \n"; return $output; } -function syndication_view_item() { +function import_view_item() { global $REQUEST_URI; $result = db_query("SELECT i.*, f.title AS feed FROM item i LEFT JOIN feed f ON i.fid = f.fid ORDER BY i.timestamp DESC LIMIT 50"); @@ -202,7 +215,7 @@ function syndication_view_item() { $output .= "\n"; $output .= " \n"; while ($item = db_fetch_object($result)) { - $output .= " \n"; + $output .= " \n"; } $output .= "
    timefeeditem
    ". format_date($item->timestamp, "custom", "m/d/y") ."
    ".format_date($item->timestamp, "custom", "H:i") ."
    fid\">". check_output($item->feed) ."link) ."\">". check_output($item->title) ."". ($item->description ? "
    ". check_output($item->description) ."" : "") ."
    iid]\" VALUE=\"". check_form($item->attribute) ."\" SIZE=\"50\">
    ". format_date($item->timestamp, "custom", "m/d/y") ."
    ".format_date($item->timestamp, "custom", "H:i") ."
    fid\">". check_output($item->feed) ."link) ."\">". check_output($item->title) ."". ($item->description ? "
    ". check_output($item->description) ."" : "") ."
    iid]\" VALUE=\"". check_form($item->attribute) ."\" SIZE=\"50\">
    \n"; $output .= "\n"; @@ -211,51 +224,51 @@ function syndication_view_item() { return $output; } -function syndication_admin() { +function import_admin() { global $op, $id, $type, $edit; - print "add new bundle | add new feed | available bundles | available items | overview | help
    "; + print "add new bundle | add new feed | available bundles | available items | overview | help
    "; switch($op) { case "help": - print syndication_help(); + print import_help(); break; case "add": if ($type == "bundle") - print syndication_form_bundle(); + print import_form_bundle(); else - print syndication_form_feed(); + print import_form_feed(); break; case "edit": if ($type == "bundle") - print syndication_form_bundle(syndication_get_bundle($id)); + print import_form_bundle(import_get_bundle($id)); else - print syndication_form_feed(syndication_get_feed($id)); + print import_form_feed(import_get_feed($id)); break; case "update": - print syndication_update(syndication_get_feed($id)); - print syndication_view_feed(); + print import_update(import_get_feed($id)); + print import_view_feed(); break; case "Save attributes": - print status(syndication_save_attributes($edit)); - print syndication_view_item(); + print status(import_save_attributes($edit)); + print import_view_item(); break; case "Delete": $edit[title] = 0; // fall through: case "Submit": if ($type == "bundle") - print status(syndication_save_bundle($edit)); + print status(import_save_bundle($edit)); else - print status(syndication_save_feed($edit)); + print status(import_save_feed($edit)); // fall through: default: if ($type == "bundle") - print syndication_view_bundle(); + print import_view_bundle(); else if ($type == "item") - print syndication_view_item(); + print import_view_item(); else - print syndication_view_feed(); + print import_view_feed(); } } diff --git a/modules/aggregator/aggregator.module b/modules/aggregator/aggregator.module new file mode 100644 index 000000000000..a4b85041ea7c --- /dev/null +++ b/modules/aggregator/aggregator.module @@ -0,0 +1,275 @@ + +

    TODO - anyone?

    + $feed[uncache]"); + + // update feeds: + if ($feed[timestamp] + $feed[refresh] < time()) import_update($feed); + } +} + +function import_bundle($attribute, $limit = 100) { + if ($attribute) { + // compose query: + $keys = explode(",", $attribute); + foreach ($keys as $key) $where[] = "attribute LIKE '%". trim($key) ."%'"; + + $result = db_query("SELECT * FROM item WHERE ". implode(" OR ", $where) ." ORDER BY timestamp DESC LIMIT $limit"); + + while ($item = db_fetch_object($result)) { + $output .= "
  • link) ."\">". check_output($item->title) ."
  • "; + } + + return "$output"; + } +} + +function import_view_bundle() { + $result = db_query("SELECT * FROM bundle ORDER BY title"); + while ($bundle = db_fetch_object($result)) { + $output .= "$bundle->title"; + } + return $output; +} + +function import_block() { + $result = db_query("SELECT * FROM bundle ORDER BY title"); + while ($bundle = db_fetch_object($result)) { + $i++; + $blocks[$i][subject] = $bundle->title; + $blocks[$i][content] = import_bundle($bundle->attribute, 10); + $blocks[$i][info] = "$bundle->title bundle"; + } + return $blocks; +} + +function import_update($feed) { + + // open socket: + $url = parse_url($feed[link]); + $fp = fsockopen($url[host], ($url[port] ? $url[port] : 80), $errno, $errstr, 15); + + if ($fp) { + // fetch data: + fputs($fp, "GET $url[path]?$url[query] HTTP/1.0\nUser-Agent: ". variable_get(site_name, "drupal") ."\nHost: $url[host]\nAccept: */*\n\n"); + while(!feof($fp)) $data .= fgets($fp, 128); + + if (strstr($data, "200 OK")) { + + eregi("", $data, $data); + + foreach (explode("", $data[0]) as $item) { + $l = eregi("(.*)", $item, $link); + $t = eregi("(.*)", $item, $title); + $a = eregi("(.*)", $item, $author); + $d = eregi("(.*)", $item, $description); + + if ($l || $t || $a || $d) { + import_save_item(array(fid => $feed[fid], title => $title[0], link => $link[0], author => $author[0], description => $description[0], attribute => $feed[attribute])); + } + } + + db_query("UPDATE feed SET timestamp = '". time() ."' WHERE fid = '". $feed[fid] ."'"); + } + else { + watchdog("error", "failed to syndicate from '$feed[title]'"); + } + } +} + +function import_save_item($edit) { + if ($edit[iid] && $edit[title]) { + db_query("UPDATE item SET title = '". check_input($edit[title]) ."', link = '". check_input($edit[link]) ."', author = '". check_input($edit[author]) ."', description = '". check_input($edit[description]) ."', attribute = '". check_input($edit[attribute]) ."' WHERE iid = '$edit[iid]'"); + } + else if ($edit[iid]) { + db_query("DELETE FROM item WHERE iid = '". check_input($edit[iid]) ."'"); + } + else { + if (!db_fetch_object(db_query("SELECT iid FROM item WHERE link = '". check_input($edit[link]) ."'"))) { + db_query("INSERT INTO item (fid, title, link, author, description, attribute, timestamp) VALUES ('". check_input($edit[fid]) ."', '". check_input($edit[title]) ."', '". check_input($edit[link]) ."', '". check_input($edit[author]) ."', '". check_input($edit[description]) ."', '". check_input($edit[attribute]) ."', '". time() ."')"); + } + } +} + +function import_form_bundle($edit = array()) { + global $REQUEST_URI; + + $form .= form_textfield("Title", "title", $edit[title], 50, 64, "The name of the bundle."); + $form .= form_textfield("Attributes", "attribute", $edit[attribute], 50, 128, "A comma-seperated list of keywords describing the bundle."); + + $form .= form_submit("Submit"); + + if ($edit[bid]) { + $form .= form_submit(t("Delete")); + $form .= form_hidden("bid", $edit[bid]); + } + + return form($REQUEST_URI, $form); +} + +function import_save_bundle($edit) { + if ($edit[bid] && $edit[title]) { + db_query("UPDATE bundle SET title = '". check_input($edit[title]) ."', attribute = '". check_input($edit[attribute]) ."' WHERE bid = '". check_input($edit[bid]) ."'"); + } + else if ($edit[bid]) { + db_query("DELETE FROM bundle WHERE bid = '". check_input($edit[bid]) ."'"); + } + else { + db_query("INSERT INTO bundle (title, attribute) VALUES ('". check_input($edit[title]) ."', '". check_input($edit[attribute]) ."')"); + } + + module_rehash_blocks("import"); +} + +function import_form_feed($edit = array()) { + global $REQUEST_URI; + + $period = array(900 => format_interval(900), 1800 => format_interval(1800), 3600 => format_interval(3600), 7200 => format_interval(7200), 10800 => format_interval(10800), 21600 => format_interval(21600), 32400 => format_interval(32400), 43200 => format_interval(43200), 64800 => format_interval(64800), 86400 => format_interval(86400), 172800 => format_interval(172800), 259200 => format_interval(259200), 604800 => format_interval(604800), 1209600 => format_interval(1209600), 2419200 => format_interval(2419200)); + + $form .= form_textfield("Title", "title", $edit[title], 50, 64, "The name of the feed; typically the name of the website you syndicate content from."); + $form .= form_textfield("Link", "link", $edit[link], 50, 64, "The fully-qualified URL of the feed."); + $form .= form_textfield("Attributes", "attribute", $edit[attribute], 50, 128, "A comma-seperated list of keywords describing the feed."); + $form .= form_select("Update interval", "refresh", $edit[refresh], $period, "The refresh interval indicating how often you want to update this feed. Requires crontab."); + $form .= form_select("Expiration time", "uncache", $edit[uncache], $period, "The time cached items should be kept. Older items will be automatically discarded. Requires crontab."); + + $form .= form_submit("Submit"); + + if ($edit[fid]) { + $form .= form_submit(t("Delete")); + $form .= form_hidden("fid", $edit[fid]); + } + + return form($REQUEST_URI, $form); +} + +function import_save_feed($edit) { + if ($edit[fid] && $edit[title]) { + db_query("UPDATE feed SET title = '". check_input($edit[title]) ."', link = '". check_input($edit[link]) ."', attribute = '". check_input($edit[attribute]) ."', refresh = '". check_input($edit[refresh]) ."', uncache = '". check_input($edit[uncache]) ."' WHERE fid = '". check_input($edit[fid]) ."'"); + db_query("DELETE FROM item WHERE fid = '". check_input($edit[fid]) ."'"); + } + else if ($edit[fid]) { + db_query("DELETE FROM feed WHERE fid = '". check_input($edit[fid]) ."'"); + db_query("DELETE FROM item WHERE fid = '". check_input($edit[fid]) ."'"); + } + else { + db_query("INSERT INTO feed (title, link, attribute, refresh, uncache) VALUES ('". check_input($edit[title]) ."', '". check_input($edit[link]) ."', '". check_input($edit[attribute]) ."', '". check_input($edit[refresh]) ."', '". check_input($edit[uncache]) ."')"); + } +} + +function import_save_attributes($edit) { + foreach($edit as $iid => $value) { + db_query("UPDATE item SET attribute = '". check_input($value) ."' WHERE iid = '". check_input($iid) ."'"); + } + return "attributes has been saved"; +} + +function import_get_feed($fid) { + return db_fetch_array(db_query("SELECT * FROM feed WHERE fid = '". check_input($fid) ."'")); +} + +function import_get_bundle($bid) { + return db_fetch_array(db_query("SELECT * FROM bundle WHERE bid = '". check_input($bid) ."'")); +} + +function import_view_feed() { + $result = db_query("SELECT f.*, COUNT(i.iid) AS items FROM feed f LEFT JOIN item i ON f.fid = i.fid GROUP BY f.fid ORDER BY f.title"); + + $output .= "

    Feed overview

    "; + $output .= "\n"; + $output .= " \n"; + while ($feed = db_fetch_object($result)) { + $output .= " \n"; + } + $output .= "
    titleattributesitemslast updatenext updateoperations
    ". check_output($feed->title) ."". check_output($feed->attribute) ."". format_plural($feed->items, "item", "items") ."". ($feed->timestamp ? format_interval(time() - $feed->timestamp) ." ago" : "never") ."". ($feed->timestamp ? format_interval($feed->timestamp + $feed->refresh - time()) ." left" : "never") ."fid\">edit feedfid\">update items
    \n"; + + $result = db_query("SELECT * FROM bundle ORDER BY title"); + + $output .= "

    Bundle overview

    "; + $output .= "\n"; + $output .= " \n"; + while ($bundle = db_fetch_object($result)) { + $output .= " \n"; + } + $output .= "
    titleattributesoperations
    ". check_output($bundle->title) ."". check_output($bundle->attribute) ."bid\">edit bundle
    \n"; + + return $output; +} + +function import_view_item() { + global $REQUEST_URI; + + $result = db_query("SELECT i.*, f.title AS feed FROM item i LEFT JOIN feed f ON i.fid = f.fid ORDER BY i.timestamp DESC LIMIT 50"); + + $output .= "
    \n"; + $output .= "\n"; + $output .= " \n"; + while ($item = db_fetch_object($result)) { + $output .= " \n"; + } + $output .= "
    timefeeditem
    ". format_date($item->timestamp, "custom", "m/d/y") ."
    ".format_date($item->timestamp, "custom", "H:i") ."
    fid\">". check_output($item->feed) ."link) ."\">". check_output($item->title) ."". ($item->description ? "
    ". check_output($item->description) ."" : "") ."
    iid]\" VALUE=\"". check_form($item->attribute) ."\" SIZE=\"50\">
    \n"; + $output .= "\n"; + $output .= "
    \n"; + + return $output; +} + +function import_admin() { + global $op, $id, $type, $edit; + + print "add new bundle | add new feed | available bundles | available items | overview | help
    "; + + switch($op) { + case "help": + print import_help(); + break; + case "add": + if ($type == "bundle") + print import_form_bundle(); + else + print import_form_feed(); + break; + case "edit": + if ($type == "bundle") + print import_form_bundle(import_get_bundle($id)); + else + print import_form_feed(import_get_feed($id)); + break; + case "update": + print import_update(import_get_feed($id)); + print import_view_feed(); + break; + case "Save attributes": + print status(import_save_attributes($edit)); + print import_view_item(); + break; + case "Delete": + $edit[title] = 0; + // fall through: + case "Submit": + if ($type == "bundle") + print status(import_save_bundle($edit)); + else + print status(import_save_feed($edit)); + // fall through: + default: + if ($type == "bundle") + print import_view_bundle(); + else if ($type == "item") + print import_view_item(); + else + print import_view_feed(); + } +} + +?> diff --git a/modules/backend.class b/modules/backend.class deleted file mode 100644 index c77418e0354a..000000000000 --- a/modules/backend.class +++ /dev/null @@ -1,154 +0,0 @@ -id = $channel->id; - $this->site = $channel->site; - $this->file = $channel->file; - $this->url = $channel->url; - $this->contact = $channel->contact; - $this->timestamp = $channel->timestamp; - - // Check to see whether we have to update our headlines first: - if (time() - $this->timestamp > $timout) $this->url2sql(); - - // Read headlines: - $result = db_query("SELECT * FROM headlines WHERE id = '$this->id' ORDER BY number"); - while ($headline = db_fetch_object($result)) { - array_push($this->headlines, "link\">$headline->title"); - } - } - else { - $this->site = $site; - $this->url = $url; - $this->file = $file; - $this->contact = $contact; - } - } - - function url2sql($timout = 10) { - if ($this->file) { - // Decode URL: - $url = parse_url($this->file); - - // Retrieve data from website: - $fp = fsockopen($url[host], ($url[port] ? $url[port] : 80), $errno, $errstr, $timout); - - if ($fp) { - // Request data via URL: - fputs($fp, "GET $url[path]?$url[query] HTTP/1.0\nUser-Agent: ". variable_get(site_name, "drupal") ."\nHost: $url[host]\nAccept: */*\n\n"); - - // Read data from socket: - while(!feof($fp)) $data .= fgets($fp, 128); - - if (strstr($data, "200 OK")) { - - // Remove existing entries: - $result = db_query("DELETE FROM headlines WHERE id = '$this->id'"); - - // Strip all 'junk': - $data = ereg_replace("", "", $data); - $data = ereg_replace("", $data); - $number = 0; - - for (reset($items); $item = current($items); next($items)) { - // Extract data: - $link = ereg_replace(".*", "", $item); - $link = ereg_replace(".*", "", $link); - $title = ereg_replace(".*", "", $item); - $title = ereg_replace(".*", "", $title); - - // Increase the number of headlines: - $number += 1; - - // Insert item in database: - $result = db_query("INSERT INTO headlines (id, title, link, number) VALUES('". check_input($this->id) ."', '". check_input($title) ."', '". check_input($link) ."', '". check_input($number) ."')"); - } - - // Mark channels as being updated: - $result = db_query("UPDATE channel SET timestamp = '". time() ."' WHERE id = '$this->id'"); - $this->timestamp = time(); - } - else { - watchdog("error", "failed to grab headlines from '$this->site':
    $data
    "); - } - } - } - } - - function displayHeadlines($timout = 1800) { - global $theme; - - // Get channel info: - $result = db_query("SELECT * FROM channel WHERE site = '$this->site'"); - - if ($this->id) { - - // Check to see whether we have to update our headlines first: - if (time() - $this->timestamp > $timout) $this->url2sql(); - - // Grab headlines from database: - $result = db_query("SELECT * FROM headlines WHERE id = '$this->id' ORDER BY number"); - while ($headline = db_fetch_object($result)) { - $content .= "
  • link\">$headline->title
  • "; - } - // Add timestamp: - $update = round((time() - $this->timestamp) / 60); - - // Display box: - $theme->box($this->site, $content); - } - else print "

    Warning: something funky happened: specified channel could not be found in database.

    "; - } - - function add() { - // Add channel: - $result = db_query("INSERT INTO channel (site, file, url, contact, timestamp) VALUES ('". check_input($this->site) ."', '". check_input($this->file) ."', '". check_input($this->url) ."', '". check_input($this->contact) ."', 1)"); - } - - function save() { - // Save channel: - $result = db_query("UPDATE channel SET site='". check_input($this->site) ."', file='". check_input($this->file) ."', url='". check_input($this->url) ."', contact='". check_input($this->contact) ."' WHERE id='". check_input($this->id) ."'"); - } - - function delete() { - // Delete channel: - $result = db_query("DELETE FROM channel WHERE id = '$this->id'"); - - // Delete headlines: - $result = db_query("DELETE FROM headlines WHERE id = '$this->id'"); - } - - function refresh() { - // Delete headlines: - $result = db_query("DELETE FROM headlines WHERE id = '$this->id'"); - - // Mark channel as invalid to enforce an update: - $result = db_query("UPDATE channel SET timestamp = 1 WHERE id = '$this->id'"); - } -} - -?> diff --git a/modules/export.module b/modules/export.module new file mode 100644 index 000000000000..b65fa569b050 --- /dev/null +++ b/modules/export.module @@ -0,0 +1,87 @@ +\n"; + print "\n"; + + print "\n"; + print " ". variable_get(site_name, "drupal") ."\n"; + print " ". path_uri() ."\n"; + print " ". variable_get(site_name, "drupal") ."\n"; + print "\n"; + + $result = db_query("SELECT * FROM node WHERE promote = '1' AND status = '$status[posted]' ORDER BY timestamp DESC LIMIT 10"); + + while ($node = db_fetch_object($result)) { + print "\n"; + print " ". check_export($node->title) ."\n"; + print " ". path_uri() ."node.php?id=$node->nid\n"; + print "\n"; + } + + print "\n"; +} + +function export_export_rss() { + global $status; + + header("Content-Type: text/plain"); + + print "\n"; + print "\n\n"; + + print "\n"; + print " ". variable_get(site_name, "drupal") ."\n"; + print " ". path_uri() ."\n"; + print " ". variable_get(site_name, "drupal") ."\n"; + + print " \n"; + print " \n"; + + $result = db_query("SELECT * FROM node WHERE promote = '1' AND status = '$status[posted]' ORDER BY timestamp DESC LIMIT 10"); + + while ($node = db_fetch_object($result)) { + print " nid\" />\n"; + } + + print " \n"; + print " \n"; + print "\n\n"; + + $result = db_query("SELECT * FROM node WHERE promote = '1' AND status = '$status[posted]' ORDER BY timestamp DESC LIMIT 10"); + + while ($node = db_fetch_object($result)) { + print "nid\">\n"; + print " ". check_export($node->title) ."\n"; + print " ". path_uri() ."node.php?id=$node->nid\n"; + + if ($node->abstract) print " ". check_output($node->abstract, 1) ."\n"; + if ($node->body) print " ". check_output($node->body, 1) ."\n"; + + print "\n"; + } + + print "\n"; +} + +function export_export($query) { + switch ($query) { + case "headlines.rss": + export_export_rss(); + break; + case "headlines.rdf": + case "default": + export_export_rdf(); + } +} + +?> diff --git a/modules/headline.module b/modules/headline.module deleted file mode 100644 index 7d30bae509fe..000000000000 --- a/modules/headline.module +++ /dev/null @@ -1,326 +0,0 @@ - -

    Drupal's headline module both imports and exports RDF/RSS headlines.

    -

    A lot of news-oriented websites are now publishing news (headlines) and making their content available through XML, RSS and RDF backend files. They syndicate free content and allow retrieval and further transmission, aggregation, and online publication. In its current state, drupal's headline module supports RDF and RSS backends.

    -

    RSS was originally developed by Netscape to allow adding news channels to "My Netscape" sites, but it has since become adopted as the de facto net standard for distributing headlines and brief dynamic texts.

    -

    The headline module goes out to a list of configured news sites once an hour or so (driven by cron), downloads new RSS/RDF data and makes it available to your visitors. In addition, your headlines are exported as well and can be retrieved by other sites from export/headlines.rdf.

    - format_interval(900), 1800 => format_interval(1800), 3600 => format_interval(3600), 7200 => format_interval(7200), 10800 => format_interval(10800), 21600 => format_interval(21600), 32400 => format_interval(32400), 43200 => format_interval(43200), 64800 => format_interval(64800), 86400 => format_interval(86400), 1000000000 => t("Never")); - $output .= form_select(t("Update interval"), "headline_cron_time" , variable_get("headline_cron_time", 86400), $period, t("The update interval indicating how often you want to update your headline channels. Requires crontab.")); - return $output; -} - - -function headline_cron() { - if (time() - variable_get("headline_cron_last", 0) > variable_get("headline_cron_time", time())) { - variable_set("headline_cron_last", time()); - - $result = db_query("SELECT * FROM channel"); - while ($channel = db_fetch_object($result)) { - $backend = new Backend($channel->id); - } - } -} - -function headline_blocks() { - global $theme; - - // Get channel info: - $result = db_query("SELECT * FROM channel ORDER BY id"); - - $theme->header(); - - print "\n"; - while ($channel = db_fetch_object($result)) { - if ($state % 3 == 0) print " \n"; - - print " \n"; - - if ($state % 3 == 2) print " \n"; - - $state += 1; - } - print "
    \n"; - - // Load backend from database: - $backend = new backend($channel->id); - - if ($backend->headlines) { - unset($content); - foreach ($backend->headlines as $headline) $content .= "
  • $headline
  • \n"; - } - else { - $content = "no headlines available\n"; - } - - // Print backend box to screen: - $theme->box($backend->site, $content); - print "
    \n"; - - $theme->footer(); -} - -function headline_page() { - global $type; - - switch($type) { - case "rdf": - headline_rdf(); - break; - default: - headline_blocks(); - } -} - - -function headline_block() { - $result = db_query("SELECT * FROM channel"); - while ($channel = db_fetch_object($result)) { - $backend = new Backend($channel->id); - - if ($backend->headlines) { - unset($content); - foreach ($backend->headlines as $headline) { - $content .= "
  • $headline
  • \n"; - } - } - else { - $content = "no headlines available"; - } - - $blocks[$channel->id]["subject"] = $backend->site; - $blocks[$channel->id]["content"] = $content; - $blocks[$channel->id]["info"] = "$backend->site headlines"; - $blocks[$channel->id]["link"] = $backend->url; - } - return $blocks; -} - -function headline_admin_display() { - global $theme; - - // Get channel info: - $result = db_query("SELECT * FROM channel ORDER BY id"); - - $output .= "\n"; - $output .= " \n"; - - while ($channel = db_fetch_object($result)) { - // Load backend from database: - $backend = new backend($channel->id); - - $output .= "\n"; - $output .= " \n"; - $output .= " \n"; - $output .= " \n"; - $output .= " \n"; - $output .= " \n"; - $output .= " \n"; - $output .= "\n"; - } - - $output .= "
    sitecontactlast updateoperations
    ". format_url($backend->url, $backend->site) ."". format_email($backend->contact) ."". ($backend->timestamp == 1 ? "failed" : format_interval(time() - $backend->timestamp) ." ago") ."id\">refreshid\">editid\">delete
    \n"; - - print $output; -} - -function headline_admin_add() { - $output .= "
    \n"; - $output .= "

    \n"; - $output .= " Site name:
    \n"; - $output .= " \n"; - $output .= "

    \n"; - $output .= "

    \n"; - $output .= " URL:
    \n"; - $output .= " \n"; - $output .= "

    \n"; - $output .= "

    \n"; - $output .= " Backend file:
    \n"; - $output .= " \n"; - $output .= "

    \n"; - $output .= "

    \n"; - $output .= " Contact information:
    \n"; - $output .= " \n"; - $output .= "

    \n"; - $output .= " \n"; - $output .= "
    \n"; - - print $output; -} - -function headline_admin_edit($id) { - $result = db_query("SELECT * FROM channel WHERE id='$id' ORDER BY id"); - - if ($channel = db_fetch_object($result)) { - $output .= "
    \n"; - $output .= " \n"; - $output .= "

    \n"; - $output .= " Site name:
    \n"; - $output .= " site\">\n"; - $output .= "

    \n"; - $output .= "

    \n"; - $output .= " URL:
    \n"; - $output .= " url\">\n"; - $output .= "

    \n"; - $output .= "

    \n"; - $output .= " Backend file:
    \n"; - $output .= " file\">\n"; - $output .= "

    \n"; - $output .= "

    \n"; - $output .= " Contact information:
    \n"; - $output .= " contact\">\n"; - $output .= "

    \n"; - $output .= " \n"; - $output .= "
    \n"; - } else { - $output .= "Invalid Channel ID.\n"; - } - print $output; -} - -function headline_admin_rehash() { - module_rehash_blocks("headline"); -} - -function headline_admin() { - global $op, $id, $site, $url, $backend, $contact; - - print "add new channel | overview | help
    "; - - switch($op) { - case "add": - headline_admin_add(); - break; - case "edit": - headline_admin_edit(check_input($id)); - break; - case "delete": - $channel = new backend($id); - $channel->delete(); - headline_admin_rehash(); - headline_admin_display(); - break; - case "help": - headline_help(); - break; - case "refresh": - $channel = new backend($id); - $channel->refresh(); - headline_admin_display(); - break; - case "Add backend": - $channel = new backend(check_input($id), check_input($site), check_input($url), check_input($backend), check_input($contact)); - $channel->add(); - headline_admin_rehash(); - headline_admin_display(); - break; - case "Save backend": - $channel = new backend(check_input($id)); - $channel->site = $site; - $channel->url = $url; - $channel->file = $backend; - $channel->contact = $contact; - $channel->save(); - headline_admin_rehash(); - // fall through: - default: - headline_admin_display(); - } -} - -function headline_export_rdf() { - global $status; - - $uri = substr(path_uri(), 0, strlen(path_uri()) - strlen("export/")); - - header("Content-Type: text/plain"); - - print "\n"; - print "\n"; - - print "\n"; - print " ". variable_get(site_name, "drupal") ."\n"; - print " ". $uri ."\n"; - print " ". variable_get(site_name, "drupal") ."\n"; - print "\n"; - - $result = db_query("SELECT * FROM node WHERE promote = '1' AND status = '$status[posted]' ORDER BY timestamp DESC LIMIT 10"); - - while ($node = db_fetch_object($result)) { - print "\n"; - print " ". check_export($node->title) ."\n"; - print " ". $uri ."node.php?id=$node->nid\n"; - print "\n"; - } - - print "\n"; -} - -function headline_export_rss() { - global $status; - - $uri = substr(path_uri(), 0, strlen(path_uri()) - strlen("export/")); - - header("Content-Type: text/plain"); - - print "\n"; - print "\n\n"; - - print "\n"; - print " ". variable_get(site_name, "drupal") ."\n"; - print " ". $uri ."\n"; - print " ". variable_get(site_name, "drupal") ."\n"; - - print " \n"; - print " \n"; - - $result = db_query("SELECT * FROM node WHERE promote = '1' AND status = '$status[posted]' ORDER BY timestamp DESC LIMIT 10"); - - while ($node = db_fetch_object($result)) { - print " nid\" />\n"; - } - - print " \n"; - print " \n"; - print "\n\n"; - - $result = db_query("SELECT * FROM node WHERE promote = '1' AND status = '$status[posted]' ORDER BY timestamp DESC LIMIT 10"); - - while ($node = db_fetch_object($result)) { - print "nid\">\n"; - print " ". check_export($node->title) ."\n"; - print " ". $uri ."node.php?id=$node->nid\n"; - - if ($node->abstract) print " ". check_output($node->abstract, 1) ."\n"; - if ($node->body) print " ". check_output($node->body, 1) ."\n"; - - print "\n"; - } - - print "\n"; -} - -function headline_export($uri) { - switch ($uri[2]) { - case "headlines.rss": - headline_export_rss(); - break; - case "headlines.rdf": - case "default": - headline_export_rdf(); - } -} - -?> diff --git a/modules/import.module b/modules/import.module new file mode 100644 index 000000000000..a4b85041ea7c --- /dev/null +++ b/modules/import.module @@ -0,0 +1,275 @@ + +

    TODO - anyone?

    + $feed[uncache]"); + + // update feeds: + if ($feed[timestamp] + $feed[refresh] < time()) import_update($feed); + } +} + +function import_bundle($attribute, $limit = 100) { + if ($attribute) { + // compose query: + $keys = explode(",", $attribute); + foreach ($keys as $key) $where[] = "attribute LIKE '%". trim($key) ."%'"; + + $result = db_query("SELECT * FROM item WHERE ". implode(" OR ", $where) ." ORDER BY timestamp DESC LIMIT $limit"); + + while ($item = db_fetch_object($result)) { + $output .= "
  • link) ."\">". check_output($item->title) ."
  • "; + } + + return "$output"; + } +} + +function import_view_bundle() { + $result = db_query("SELECT * FROM bundle ORDER BY title"); + while ($bundle = db_fetch_object($result)) { + $output .= "$bundle->title
      ". import_bundle($bundle->attribute) ."
    "; + } + return $output; +} + +function import_block() { + $result = db_query("SELECT * FROM bundle ORDER BY title"); + while ($bundle = db_fetch_object($result)) { + $i++; + $blocks[$i][subject] = $bundle->title; + $blocks[$i][content] = import_bundle($bundle->attribute, 10); + $blocks[$i][info] = "$bundle->title bundle"; + } + return $blocks; +} + +function import_update($feed) { + + // open socket: + $url = parse_url($feed[link]); + $fp = fsockopen($url[host], ($url[port] ? $url[port] : 80), $errno, $errstr, 15); + + if ($fp) { + // fetch data: + fputs($fp, "GET $url[path]?$url[query] HTTP/1.0\nUser-Agent: ". variable_get(site_name, "drupal") ."\nHost: $url[host]\nAccept: */*\n\n"); + while(!feof($fp)) $data .= fgets($fp, 128); + + if (strstr($data, "200 OK")) { + + eregi("", $data, $data); + + foreach (explode("", $data[0]) as $item) { + $l = eregi("(.*)", $item, $link); + $t = eregi("(.*)", $item, $title); + $a = eregi("(.*)", $item, $author); + $d = eregi("(.*)", $item, $description); + + if ($l || $t || $a || $d) { + import_save_item(array(fid => $feed[fid], title => $title[0], link => $link[0], author => $author[0], description => $description[0], attribute => $feed[attribute])); + } + } + + db_query("UPDATE feed SET timestamp = '". time() ."' WHERE fid = '". $feed[fid] ."'"); + } + else { + watchdog("error", "failed to syndicate from '$feed[title]'"); + } + } +} + +function import_save_item($edit) { + if ($edit[iid] && $edit[title]) { + db_query("UPDATE item SET title = '". check_input($edit[title]) ."', link = '". check_input($edit[link]) ."', author = '". check_input($edit[author]) ."', description = '". check_input($edit[description]) ."', attribute = '". check_input($edit[attribute]) ."' WHERE iid = '$edit[iid]'"); + } + else if ($edit[iid]) { + db_query("DELETE FROM item WHERE iid = '". check_input($edit[iid]) ."'"); + } + else { + if (!db_fetch_object(db_query("SELECT iid FROM item WHERE link = '". check_input($edit[link]) ."'"))) { + db_query("INSERT INTO item (fid, title, link, author, description, attribute, timestamp) VALUES ('". check_input($edit[fid]) ."', '". check_input($edit[title]) ."', '". check_input($edit[link]) ."', '". check_input($edit[author]) ."', '". check_input($edit[description]) ."', '". check_input($edit[attribute]) ."', '". time() ."')"); + } + } +} + +function import_form_bundle($edit = array()) { + global $REQUEST_URI; + + $form .= form_textfield("Title", "title", $edit[title], 50, 64, "The name of the bundle."); + $form .= form_textfield("Attributes", "attribute", $edit[attribute], 50, 128, "A comma-seperated list of keywords describing the bundle."); + + $form .= form_submit("Submit"); + + if ($edit[bid]) { + $form .= form_submit(t("Delete")); + $form .= form_hidden("bid", $edit[bid]); + } + + return form($REQUEST_URI, $form); +} + +function import_save_bundle($edit) { + if ($edit[bid] && $edit[title]) { + db_query("UPDATE bundle SET title = '". check_input($edit[title]) ."', attribute = '". check_input($edit[attribute]) ."' WHERE bid = '". check_input($edit[bid]) ."'"); + } + else if ($edit[bid]) { + db_query("DELETE FROM bundle WHERE bid = '". check_input($edit[bid]) ."'"); + } + else { + db_query("INSERT INTO bundle (title, attribute) VALUES ('". check_input($edit[title]) ."', '". check_input($edit[attribute]) ."')"); + } + + module_rehash_blocks("import"); +} + +function import_form_feed($edit = array()) { + global $REQUEST_URI; + + $period = array(900 => format_interval(900), 1800 => format_interval(1800), 3600 => format_interval(3600), 7200 => format_interval(7200), 10800 => format_interval(10800), 21600 => format_interval(21600), 32400 => format_interval(32400), 43200 => format_interval(43200), 64800 => format_interval(64800), 86400 => format_interval(86400), 172800 => format_interval(172800), 259200 => format_interval(259200), 604800 => format_interval(604800), 1209600 => format_interval(1209600), 2419200 => format_interval(2419200)); + + $form .= form_textfield("Title", "title", $edit[title], 50, 64, "The name of the feed; typically the name of the website you syndicate content from."); + $form .= form_textfield("Link", "link", $edit[link], 50, 64, "The fully-qualified URL of the feed."); + $form .= form_textfield("Attributes", "attribute", $edit[attribute], 50, 128, "A comma-seperated list of keywords describing the feed."); + $form .= form_select("Update interval", "refresh", $edit[refresh], $period, "The refresh interval indicating how often you want to update this feed. Requires crontab."); + $form .= form_select("Expiration time", "uncache", $edit[uncache], $period, "The time cached items should be kept. Older items will be automatically discarded. Requires crontab."); + + $form .= form_submit("Submit"); + + if ($edit[fid]) { + $form .= form_submit(t("Delete")); + $form .= form_hidden("fid", $edit[fid]); + } + + return form($REQUEST_URI, $form); +} + +function import_save_feed($edit) { + if ($edit[fid] && $edit[title]) { + db_query("UPDATE feed SET title = '". check_input($edit[title]) ."', link = '". check_input($edit[link]) ."', attribute = '". check_input($edit[attribute]) ."', refresh = '". check_input($edit[refresh]) ."', uncache = '". check_input($edit[uncache]) ."' WHERE fid = '". check_input($edit[fid]) ."'"); + db_query("DELETE FROM item WHERE fid = '". check_input($edit[fid]) ."'"); + } + else if ($edit[fid]) { + db_query("DELETE FROM feed WHERE fid = '". check_input($edit[fid]) ."'"); + db_query("DELETE FROM item WHERE fid = '". check_input($edit[fid]) ."'"); + } + else { + db_query("INSERT INTO feed (title, link, attribute, refresh, uncache) VALUES ('". check_input($edit[title]) ."', '". check_input($edit[link]) ."', '". check_input($edit[attribute]) ."', '". check_input($edit[refresh]) ."', '". check_input($edit[uncache]) ."')"); + } +} + +function import_save_attributes($edit) { + foreach($edit as $iid => $value) { + db_query("UPDATE item SET attribute = '". check_input($value) ."' WHERE iid = '". check_input($iid) ."'"); + } + return "attributes has been saved"; +} + +function import_get_feed($fid) { + return db_fetch_array(db_query("SELECT * FROM feed WHERE fid = '". check_input($fid) ."'")); +} + +function import_get_bundle($bid) { + return db_fetch_array(db_query("SELECT * FROM bundle WHERE bid = '". check_input($bid) ."'")); +} + +function import_view_feed() { + $result = db_query("SELECT f.*, COUNT(i.iid) AS items FROM feed f LEFT JOIN item i ON f.fid = i.fid GROUP BY f.fid ORDER BY f.title"); + + $output .= "

    Feed overview

    "; + $output .= "\n"; + $output .= " \n"; + while ($feed = db_fetch_object($result)) { + $output .= " \n"; + } + $output .= "
    titleattributesitemslast updatenext updateoperations
    ". check_output($feed->title) ."". check_output($feed->attribute) ."". format_plural($feed->items, "item", "items") ."". ($feed->timestamp ? format_interval(time() - $feed->timestamp) ." ago" : "never") ."". ($feed->timestamp ? format_interval($feed->timestamp + $feed->refresh - time()) ." left" : "never") ."fid\">edit feedfid\">update items
    \n"; + + $result = db_query("SELECT * FROM bundle ORDER BY title"); + + $output .= "

    Bundle overview

    "; + $output .= "\n"; + $output .= " \n"; + while ($bundle = db_fetch_object($result)) { + $output .= " \n"; + } + $output .= "
    titleattributesoperations
    ". check_output($bundle->title) ."". check_output($bundle->attribute) ."bid\">edit bundle
    \n"; + + return $output; +} + +function import_view_item() { + global $REQUEST_URI; + + $result = db_query("SELECT i.*, f.title AS feed FROM item i LEFT JOIN feed f ON i.fid = f.fid ORDER BY i.timestamp DESC LIMIT 50"); + + $output .= "
    \n"; + $output .= "\n"; + $output .= " \n"; + while ($item = db_fetch_object($result)) { + $output .= " \n"; + } + $output .= "
    timefeeditem
    ". format_date($item->timestamp, "custom", "m/d/y") ."
    ".format_date($item->timestamp, "custom", "H:i") ."
    fid\">". check_output($item->feed) ."link) ."\">". check_output($item->title) ."". ($item->description ? "
    ". check_output($item->description) ."" : "") ."
    iid]\" VALUE=\"". check_form($item->attribute) ."\" SIZE=\"50\">
    \n"; + $output .= "\n"; + $output .= "
    \n"; + + return $output; +} + +function import_admin() { + global $op, $id, $type, $edit; + + print "add new bundle | add new feed | available bundles | available items | overview | help
    "; + + switch($op) { + case "help": + print import_help(); + break; + case "add": + if ($type == "bundle") + print import_form_bundle(); + else + print import_form_feed(); + break; + case "edit": + if ($type == "bundle") + print import_form_bundle(import_get_bundle($id)); + else + print import_form_feed(import_get_feed($id)); + break; + case "update": + print import_update(import_get_feed($id)); + print import_view_feed(); + break; + case "Save attributes": + print status(import_save_attributes($edit)); + print import_view_item(); + break; + case "Delete": + $edit[title] = 0; + // fall through: + case "Submit": + if ($type == "bundle") + print status(import_save_bundle($edit)); + else + print status(import_save_feed($edit)); + // fall through: + default: + if ($type == "bundle") + print import_view_bundle(); + else if ($type == "item") + print import_view_item(); + else + print import_view_feed(); + } +} + +?>