Commit 89b9c26e authored by Dries's avatar Dries
Browse files

- Patch #52932 by Zen: fapi conversion + fixes

   * fapi conversion.
   * Adds status messages, comments and language fixes.
   * Adds watchdog messages for category and feed additions and deletions.
   * Edit forms: checks for duplicates - title for category, title + url for feeds.
parent 8fe244ff
<
......@@ -38,6 +38,153 @@ function aggregator_help($section) {
}
}
/**
* Implementation of hook_menu().
*/
function aggregator_menu($may_cache) {
$items = array();
$edit = user_access('administer news feeds');
$view = user_access('access news feeds');
if ($may_cache) {
$items[] = array('path' => 'admin/aggregator',
'title' => t('aggregator'),
'callback' => 'aggregator_admin_overview',
'access' => $edit);
$items[] = array('path' => 'admin/aggregator/add/feed',
'title' => t('add feed'),
'callback' => 'aggregator_form_feed',
'access' => $edit,
'type' => MENU_LOCAL_TASK);
$items[] = array('path' => 'admin/aggregator/add/category',
'title' => t('add category'),
'callback' => 'aggregator_form_category',
'access' => $edit,
'type' => MENU_LOCAL_TASK);
$items[] = array('path' => 'admin/aggregator/remove',
'title' => t('remove items'),
'callback' => 'aggregator_admin_remove_feed',
'access' => $edit,
'type' => MENU_CALLBACK);
$items[] = array('path' => 'admin/aggregator/update',
'title' => t('update items'),
'callback' => 'aggregator_admin_refresh_feed',
'access' => $edit,
'type' => MENU_CALLBACK);
$items[] = array('path' => 'admin/aggregator/list',
'title' => t('list'),
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => -10);
$items[] = array('path' => 'aggregator',
'title' => t('news aggregator'),
'callback' => 'aggregator_page_last',
'access' => $view,
'weight' => 5);
$items[] = array('path' => 'aggregator/sources',
'title' => t('sources'),
'callback' => 'aggregator_page_sources',
'access' => $view);
$items[] = array('path' => 'aggregator/categories',
'title' => t('categories'),
'callback' => 'aggregator_page_categories',
'access' => $view,
'type' => MENU_ITEM_GROUPING);
$items[] = array('path' => 'aggregator/rss',
'title' => t('RSS feed'),
'callback' => 'aggregator_page_rss',
'access' => $view,
'type' => MENU_CALLBACK);
$items[] = array('path' => 'aggregator/opml',
'title' => t('OPML feed'),
'callback' => 'aggregator_page_opml',
'access' => $view,
'type' => MENU_CALLBACK);
}
else {
if (arg(0) == 'aggregator' && is_numeric(arg(2))) {
if (arg(1) == 'sources') {
$feed = aggregator_get_feed(arg(2));
if ($feed) {
$items[] = array('path' => 'aggregator/sources/'. $feed['fid'],
'title' => $feed->title,
'callback' => 'aggregator_page_source',
'access' => $view);
$items[] = array('path' => 'aggregator/sources/'. $feed['fid'] .'/view',
'title' => t('view'),
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => -10);
$items[] = array('path' => 'aggregator/sources/'. $feed['fid'] .'/categorize',
'title' => t('categorize'),
'callback' => 'aggregator_page_source',
'access' => $edit,
'type' => MENU_LOCAL_TASK);
$items[] = array('path' => 'aggregator/sources/'. $feed['fid'] .'/configure',
'title' => t('configure'),
'callback' => 'aggregator_form_feed',
'callback arguments' => array($feed),
'access' => $edit,
'type' => MENU_LOCAL_TASK,
'weight' => 1);
}
}
else if (arg(1) == 'categories') {
$category = aggregator_get_category(arg(2));
if ($category) {
$items[] = array('path' => 'aggregator/categories/'. $category['cid'],
'title' => $category->title,
'callback' => 'aggregator_page_category',
'access' => $view);
$items[] = array('path' => 'aggregator/categories/'. $category['cid'] .'/view',
'title' => t('view'),
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => -10);
$items[] = array('path' => 'aggregator/categories/'. $category['cid'] .'/categorize',
'title' => t('categorize'),
'callback' => 'aggregator_page_category',
'access' => $edit,
'type' => MENU_LOCAL_TASK);
$items[] = array('path' => 'aggregator/categories/'. $category['cid'] .'/configure',
'title' => t('configure'),
'callback' => 'aggregator_form_category',
'callback arguments' => array($category),
'access' => $edit,
'type' => MENU_LOCAL_TASK,
'weight' => 1);
}
}
}
else if (arg(1) == 'aggregator' && is_numeric(arg(4))) {
if (arg(3) == 'feed') {
$feed = aggregator_get_feed(arg(4));
if ($feed) {
$items[] = array('path' => 'admin/aggregator/edit/feed/'. $feed['fid'],
'title' => t('edit feed'),
'callback' => 'aggregator_form_feed',
'callback arguments' => array($feed),
'access' => $edit,
'type' => MENU_CALLBACK);
}
}
else {
$category = aggregator_get_category(arg(4));
if ($category) {
$items[] = array('path' => 'admin/aggregator/edit/category/'. $category['cid'],
'title' => t('edit category'),
'callback' => 'aggregator_form_category',
'callback arguments' => array($category),
'access' => $edit,
'type' => MENU_CALLBACK);
}
}
}
}
return $items;
}
/**
* Implementation of hook_settings().
*/
function aggregator_settings() {
$items = array(0 => t('none')) + drupal_map_assoc(array(3, 5, 10, 15, 20, 25), '_aggregator_items');
$period = drupal_map_assoc(array(3600, 10800, 21600, 32400, 43200, 86400, 172800, 259200, 604800, 1209600, 2419200, 4838400, 9676800), 'format_interval');
......@@ -68,13 +215,6 @@ function aggregator_settings() {
return $form;
}
/**
* Helper function for drupal_map_assoc.
*/
function _aggregator_items($count) {
return format_plural($count, '1 item', '%count items');
}
/**
* Implementation of hook_perm().
*/
......@@ -82,94 +222,6 @@ function aggregator_perm() {
return array('administer news feeds', 'access news feeds');
}
/**
* Implementation of hook_menu().
*/
function aggregator_menu($may_cache) {
$items = array();
$edit = user_access('administer news feeds');
$view = user_access('access news feeds');
if ($may_cache) {
$items[] = array('path' => 'admin/aggregator', 'title' => t('aggregator'),
'callback' => 'aggregator_admin_overview', 'access' => $edit);
$items[] = array('path' => 'admin/aggregator/edit/feed', 'title' => t('edit feed'),
'callback' => 'aggregator_admin_edit_feed', 'access' => $edit,
'type' => MENU_CALLBACK);
$items[] = array('path' => 'admin/aggregator/edit/category', 'title' => t('edit category'),
'callback' => 'aggregator_admin_edit_category', 'access' => $edit,
'type' => MENU_CALLBACK);
$items[] = array('path' => 'admin/aggregator/remove', 'title' => t('remove items'),
'callback' => 'aggregator_admin_remove_feed', 'access' => $edit,
'type' => MENU_CALLBACK);
$items[] = array('path' => 'admin/aggregator/update', 'title' => t('update items'),
'callback' => 'aggregator_admin_refresh_feed', 'access' => $edit,
'type' => MENU_CALLBACK);
$items[] = array('path' => 'admin/aggregator/list', 'title' => t('list'),
'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10);
$items[] = array('path' => 'admin/aggregator/add/feed', 'title' => t('add feed'),
'callback' => 'aggregator_admin_edit_feed', 'access' => $edit,
'type' => MENU_LOCAL_TASK);
$items[] = array('path' => 'admin/aggregator/add/category', 'title' => t('add category'),
'callback' => 'aggregator_admin_edit_category', 'access' => $edit,
'type' => MENU_LOCAL_TASK);
$items[] = array('path' => 'aggregator', 'title' => t('news aggregator'),
'callback' => 'aggregator_page_last', 'access' => $view,
'weight' => 5);
$items[] = array('path' => 'aggregator/sources', 'title' => t('sources'),
'callback' => 'aggregator_page_sources', 'access' => $view);
$items[] = array('path' => 'aggregator/categories', 'title' => t('categories'),
'callback' => 'aggregator_page_categories', 'access' => $view,
'type' => MENU_ITEM_GROUPING);
$items[] = array('path' => 'aggregator/rss', 'title' => t('RSS feed'),
'callback' => 'aggregator_page_rss', 'access' => $view,
'type' => MENU_CALLBACK);
$items[] = array('path' => 'aggregator/opml', 'title' => t('OPML feed'),
'callback' => 'aggregator_page_opml', 'access' => $view,
'type' => MENU_CALLBACK);
}
else {
if (arg(0) == 'aggregator' && is_numeric(arg(2))) {
if (arg(1) == 'sources') {
$feed = db_fetch_object(db_query('SELECT title, fid FROM {aggregator_feed} WHERE fid = %d', arg(2)));
if ($feed) {
$items[] = array('path' => 'aggregator/sources/'. $feed->fid, 'title' => $feed->title,
'callback' => 'aggregator_page_source', 'access' => $view);
$items[] = array('path' => 'aggregator/sources/'. $feed->fid .'/view', 'title' => t('view'),
'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10);
$items[] = array('path' => 'aggregator/sources/'. $feed->fid .'/categorize', 'title' => t('categorize'),
'callback' => 'aggregator_page_source', 'access' => $edit,
'type' => MENU_LOCAL_TASK);
$items[] = array('path' => 'aggregator/sources/'. $feed->fid .'/configure', 'title' => t('configure'),
'callback' => 'aggregator_edit', 'access' => $edit,
'type' => MENU_LOCAL_TASK,
'weight' => 1);
}
}
else if (arg(1) == 'categories') {
$category = db_fetch_object(db_query('SELECT title, cid FROM {aggregator_category} WHERE cid = %d', arg(2)));
if ($category) {
$items[] = array('path' => 'aggregator/categories/'. $category->cid, 'title' => $category->title,
'callback' => 'aggregator_page_category', 'access' => $view);
$items[] = array('path' => 'aggregator/categories/'. $category->cid .'/view', 'title' => t('view'),
'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10);
$items[] = array('path' => 'aggregator/categories/'. $category->cid .'/categorize', 'title' => t('categorize'),
'callback' => 'aggregator_page_category', 'access' => $edit,
'type' => MENU_LOCAL_TASK);
$items[] = array('path' => 'aggregator/categories/'. $category->cid .'/configure', 'title' => t('configure'),
'callback' => 'aggregator_edit', 'access' => $edit,
'type' => MENU_LOCAL_TASK,
'weight' => 1);
}
}
}
}
return $items;
}
/**
* Implementation of hook_cron().
*
......@@ -248,6 +300,259 @@ function aggregator_block($op, $delta = 0, $edit = array()) {
}
}
/**
* Generate a form to add/edit/delete aggregator categories.
*/
function aggregator_form_category($edit = array()) {
$form['title'] = array('#type' => 'textfield',
'#title' => t('Title'),
'#default_value' => $edit['title'],
'#maxlength' => 64,
'#required' => TRUE,
);
$form['description'] = array('#type' => 'textarea',
'#title' => t('Description'),
'#default_value' => $edit['description'],
);
$form['submit'] = array('#type' => 'submit', '#value' =>t('Submit'));
if ($edit['cid']) {
$form['delete'] = array('#type' => 'submit', '#value' =>t('Delete'));
$form['cid'] = array('#type' => 'hidden', '#value' => $edit['cid']);
}
return drupal_get_form('aggregator_form_category', $form);
}
/**
* Validate aggregator_form_feed form submissions.
*/
function aggregator_form_category_validate($form_id, $form_values) {
if ($_POST['op'] == t('Submit')) {
// Check for duplicate titles
if (isset($form_values['cid'])) {
$category = db_fetch_object(db_query("SELECT cid FROM {aggregator_category} WHERE title = '%s' AND cid != %d", $form_values['title'], $form_values['cid']));
}
else {
$category = db_fetch_object(db_query("SELECT cid FROM {aggregator_category} WHERE title = '%s'", $form_values['title']));
}
if ($category) {
form_set_error('title', t('A category named %category already exists. Please enter a unique title.', array('%category' => theme('placeholder', $form_values['title']))));
}
}
}
/**
* Process aggregator_form_category form submissions.
* @todo Add delete confirmation dialog.
*/
function aggregator_form_category_submit($form_id, $form_values) {
if ($_POST['op'] == t('Delete')) {
$title = $form_values['title'];
// Unset the title:
unset($form_values['title']);
}
aggregator_save_category($form_values);
menu_rebuild();
if (isset($form_values['cid'])) {
if (isset($form_values['title'])) {
drupal_set_message(t('The category %category has been updated.', array('%category' => theme('placeholder', $form_values['title']))));
if (arg(0) == 'admin') {
return 'admin/aggregator/';
}
else {
return 'aggregator/categories/'. $form_values['cid'];
}
}
else {
watchdog('aggregator', t('Category %category deleted.', array('%category' => theme('placeholder', $title))));
drupal_set_message(t('The category %category has been deleted.', array('%category' => theme('placeholder', $title))));
if (arg(0) == 'admin') {
return 'admin/aggregator/';
}
else {
return 'aggregator/categories/';
}
}
}
else {
watchdog('aggregator', t('Category %category added.', array('%category' => theme('placeholder', $form_values['title']))), WATCHDOG_NOTICE, l(t('view'), 'admin/aggregator'));
drupal_set_message(t('The category %category has been added.', array('%category' => theme('placeholder', $form_values['title']))));
}
}
/**
* Add/edit/delete aggregator categories.
*/
function aggregator_save_category($edit) {
if ($edit['cid'] && $edit['title']) {
db_query("UPDATE {aggregator_category} SET title = '%s', description = '%s' WHERE cid = %d", $edit['title'], $edit['description'], $edit['cid']);
}
else if ($edit['cid']) {
db_query('DELETE FROM {aggregator_category} WHERE cid = %d', $edit['cid']);
}
else if ($edit['title']) {
// A single unique id for bundles and feeds, to use in blocks
$next_id = db_next_id('{aggregator_category}_cid');
db_query("INSERT INTO {aggregator_category} (cid, title, description, block) VALUES (%d, '%s', '%s', 5)", $next_id, $edit['title'], $edit['description']);
}
}
/**
* Generate a form to add/edit feed sources.
*/
function aggregator_form_feed($edit = array()) {
$period = drupal_map_assoc(array(900, 1800, 3600, 7200, 10800, 21600, 32400, 43200, 64800, 86400, 172800, 259200, 604800, 1209600, 2419200), 'format_interval');
if ($edit['refresh'] == '') {
$edit['refresh'] = 3600;
}
$form['title'] = array('#type' => 'textfield',
'#title' => t('Title'),
'#default_value' => $edit['title'],
'#maxlength' => 64,
'#description' => t('The name of the feed; typically the name of the web site you syndicate content from.'),
'#required' => TRUE,
);
$form['url'] = array('#type' => 'textfield',
'#title' => t('URL'),
'#default_value' => $edit['url'],
'#maxlength' => 255,
'#description' => t('The fully-qualified URL of the feed.'),
'#required' => TRUE,
);
$form['refresh'] = array('#type' => 'select',
'#title' => t('Update interval'),
'#default_value' => $edit['refresh'],
'#options' => $period,
'#description' => t('The refresh interval indicating how often you want to update this feed. Requires crontab.'),
);
// Handling of categories:
$options = array();
$values = array();
$categories = db_query('SELECT c.cid, c.title, f.fid FROM {aggregator_category} c LEFT JOIN {aggregator_category_feed} f ON c.cid = f.cid AND f.fid = %d ORDER BY title', $edit['fid']);
while ($category = db_fetch_object($categories)) {
$options[$category->cid] = $category->title;
if ($category->fid) $values[] = check_plain($category->cid);
}
if ($options) {
$form['category'] = array('#type' => 'checkboxes',
'#title' => t('Categorize news items'),
'#default_value' => $values,
'#options' => $options,
'#description' => t('New items in this feed will be automatically filed in the checked categories as they are received.'),
);
}
$form['submit'] = array('#type' => 'submit', '#value' =>t('Submit'));
if ($edit['fid']) {
$form['delete'] = array('#type' => 'submit', '#value' =>t('Delete'));
$form['fid'] = array('#type' => 'hidden', '#value' => $edit['fid']);
}
return drupal_get_form('aggregator_form_feed', $form);
}
/**
* Validate aggregator_form_feed form submissions.
*/
function aggregator_form_feed_validate($form_id, $form_values) {
if ($_POST['op'] == t('Submit')) {
// Check for duplicate titles
if (isset($form_values['fid'])) {
$result = db_query("SELECT title, url FROM {aggregator_feed} WHERE (title = '%s' OR url='%s') AND fid != %d", $form_values['title'], $form_values['url'], $form_values['fid']);
}
else {
$result = db_query("SELECT title, url FROM {aggregator_feed} WHERE title = '%s' OR url='%s'", $form_values['title'], $form_values['url']);
}
while ($feed = db_fetch_object($result)) {
if (strcasecmp($feed->title, $form_values['title']) == 0) {
form_set_error('title', t('A feed named %feed already exists. Please enter a unique title.', array('%feed' => theme('placeholder', $form_values['title']))));
}
}
}
}
/**
* Process aggregator_form_feed form submissions.
* @todo Add delete confirmation dialog.
*/
function aggregator_form_feed_submit($form_id, $form_values) {
if ($_POST['op'] == t('Delete')) {
$title = $form_values['title'];
// Unset the title:
unset($form_values['title']);
}
aggregator_save_feed($form_values);
menu_rebuild();
if (isset($form_values['fid'])) {
if (isset($form_values['title'])) {
drupal_set_message(t('The feed %feed has been updated.', array('%feed' => theme('placeholder', $form_values['title']))));
if (arg(0) == 'admin') {
return 'admin/aggregator/';
}
else {
return 'aggregator/sources/'. $form_values['fid'];
}
}
else {
watchdog('aggregator', t('Feed %feed deleted.', array('%feed' => theme('placeholder', $title))));
drupal_set_message(t('The feed %feed has been deleted.', array('%feed' => theme('placeholder', $title))));
if (arg(0) == 'admin') {
return 'admin/aggregator/';
}
else {
return 'aggregator/sources/';
}
}
}
else {
watchdog('aggregator', t('Feed %feed added.', array('%feed' => theme('placeholder', $form_values['title']))), WATCHDOG_NOTICE, l(t('view'), 'admin/aggregator'));
drupal_set_message(t('The feed %feed has been added.', array('%feed' => theme('placeholder', $form_values['title']))));
}
}
/**
* Add/edit/delete an aggregator feed.
*/
function aggregator_save_feed($edit) {
if ($edit['fid']) {
// An existing feed is being modified, delete the category listings.
db_query('DELETE FROM {aggregator_category_feed} WHERE fid = %d', $edit['fid']);
}
if ($edit['fid'] && $edit['title']) {
db_query("UPDATE {aggregator_feed} SET title = '%s', url = '%s', refresh = %d WHERE fid = %d", $edit['title'], $edit['url'], $edit['refresh'], $edit['fid']);
}
else if ($edit['fid']) {
$result = db_query('SELECT iid FROM {aggregator_item} WHERE fid = %d', $edit['fid']);
while ($item = db_fetch_object($result)) {
$items[] = "iid = $item->iid";
}
if ($items) {
db_query('DELETE FROM {aggregator_category_item} WHERE '. implode(' OR ', $items));
}
db_query('DELETE FROM {aggregator_feed} WHERE fid = %d', $edit['fid']);
db_query('DELETE FROM {aggregator_item} WHERE fid = %d', $edit['fid']);
}
else if ($edit['title']) {
// A single unique id for bundles and feeds, to use in blocks.
$edit['fid'] = db_next_id('{aggregator_feed}_fid');
db_query("INSERT INTO {aggregator_feed} (fid, title, url, refresh, block) VALUES (%d, '%s', '%s', %d, 5)", $edit['fid'], $edit['title'], $edit['url'], $edit['refresh']);
}
if ($edit['title']) {
// The feed is being saved, save the categories as well.
if ($edit['category']) {
foreach ($edit['category'] as $cid => $value) {
if ($value) {
db_query('INSERT INTO {aggregator_category_feed} (fid, cid) VALUES (%d, %d)', $edit['fid'], $cid);
}
}
}
}
}
function aggregator_remove($feed) {
$result = db_query('SELECT iid FROM {aggregator_item} WHERE fid = %d', $feed['fid']);
while ($item = db_fetch_object($result)) {
......@@ -322,10 +627,10 @@ function aggregator_element_end($parser, $name) {
break;
case 'ID':
if ($element == 'ID') {
$element = '';
$element = '';
}
}
}
}
/**
* Call-back function used by the XML parser.
......@@ -623,7 +928,7 @@ function aggregator_parse_feed(&$data, $feed) {
function aggregator_save_item($edit) {
if ($edit['iid'] && $edit['title']) {
db_query('UPDATE {aggregator_item} SET title = \'%s\', link = \'%s\', author = \'%s\', description = \'%s\' WHERE iid = %d', $edit['title'], $edit['link'], $edit['author'], $edit['description'], $edit['iid']);
db_query("UPDATE {aggregator_item} SET title = '%s', link = '%s', author = '%s', description = '%s' WHERE iid = %d", $edit['title'], $edit['link'], $edit['author'], $edit['description'], $edit['iid']);
}
else if ($edit['iid']) {
db_query('DELETE FROM {aggregator_item} WHERE iid = %d', $edit['iid']);
......@@ -631,7 +936,7 @@ function aggregator_save_item($edit) {
}
else if ($edit['title'] && $edit['link']) {
$edit['iid'] = db_next_id('{aggregator_item}_iid');
db_query('INSERT INTO {aggregator_item} (iid, fid, title, link, author, description, timestamp) VALUES (%d, %d, \'%s\', \'%s\', \'%s\', \'%s\', %d)', $edit['iid'], $edit['fid'], $edit['title'], $edit['link'], $edit['author'], $edit['description'], $edit['timestamp']);
db_query("INSERT INTO {aggregator_item} (iid, fid, title, link, author, description, timestamp) VALUES (%d, %d, '%s', '%s', '%s', '%s', %d)", $edit['iid'], $edit['fid'], $edit['title'], $edit['link'], $edit['author'], $edit['description'], $edit['timestamp']);
// file the items in the categories indicated by the feed
$categories = db_query('SELECT cid FROM {aggregator_category_feed} WHERE fid = %d', $edit['fid']);
while ($category = db_fetch_object($categories)) {
......@@ -640,100 +945,6 @@ function aggregator_save_item($edit) {
}
}
function aggregator_form_category($edit = array()) {
$form['title'] = array('#type' => 'textfield', '#title' => t('Title'), '#default_value' => $edit['title'], '#maxlength' => 64);
$form['description'] = array('#type' => 'textarea', '#title' => t('Description'), '#default_value' => $edit['description']);
$form['submit'] = array('#type' => 'submit', '#value' =>t('Submit'));
if ($edit['cid']) {
$form['delete'] = array('#type' => 'submit', '#value' =>t('Delete'));
$form['cid'] = array('#type' => 'hidden', '#value' => $edit['cid']);
}
return drupal_get_form('aggregator_form_category', $form);
}
function aggregator_save_category($edit) {
if ($edit['cid'] && $edit['title']) {
db_query('UPDATE {aggregator_category} SET title = \'%s\', description = \'%s\' WHERE cid = %d', $edit['title'], $edit['description'], $edit['cid']);
}
else if ($edit['cid']) {
db_query('DELETE FROM {aggregator_category} WHERE cid = %d', $edit['cid']);
}
else if ($edit['title']) {
// a single unique id for bundles and feeds, to use in blocks
$next_id = db_next_id('{aggregator_category}_cid');
db_query('INSERT INTO {aggregator_category} (cid, title, description, block) VALUES (%d, \'%s\', \'%s\', 5)', $next_id, $edit['title'], $edit['description']);
}
}
function aggregator_form_feed($edit = array()) {
$period = drupal_map_assoc(array(900, 1800, 3600, 7200, 10800, 21600, 32400, 43200, 64800, 86400, 172800, 259200, 604800, 1209600, 2419200), 'format_interval');
if ($edit['refresh'] == '') {
$edit['refresh'] = 3600;
}
$form['title'] = array('#type' => 'textfield', '#title' => t('Title'), '#default_value' => $edit['title'], '#maxlength' => 64, '#description' => t('The name of the feed; typically the name of the web site you syndicate content from.'));
$form['url'] = array('#type' => 'textfield', '#title' => t('URL'), '#default_value' => $edit['url'], '#maxlength' => 255, '#description' => t('The fully-qualified URL of the feed.'));
$form['refresh'] = array('#type' => 'select', '#title' => t('Update interval'), '#default_value' => $edit['refresh'], '#options' => $period, '#description' => t('The refresh interval indicating how often you want to update this feed. Requires crontab.'));
// Handling of categories:
$options = array();
$values = array();
$categories = db_query('SELECT c.cid, c.title, f.fid FROM {aggregator_category} c LEFT JOIN {aggregator_category_feed} f ON c.cid = f.cid AND f.fid = %d ORDER BY title', $edit['fid']);
while ($category = db_fetch_object($categories)) {