diff --git a/README.txt b/README.txt
old mode 100644
new mode 100755
diff --git a/multiping.info b/multiping.info
old mode 100644
new mode 100755
index 1b5391f..452383e
--- a/multiping.info
+++ b/multiping.info
@@ -1,6 +1,7 @@
 name = Multiping
 description = A ping module for pinging multiple sites
-core = 6.x
-; version = VERSION
-version = 6.x-dev
+core = 7.x
+version = 7.x-dev
 
+files[] = multiping.module
+files[] = pages/multiping.admin.inc
\ No newline at end of file
diff --git a/multiping.install b/multiping.install
old mode 100644
new mode 100755
index db12732..ab525f4
--- a/multiping.install
+++ b/multiping.install
@@ -1,64 +1,84 @@
 <?php
-
+/**
+ * @file
+ */
+/**
+ * Implements hook_schema().
+ * @return array
+ */
 function multiping_schema() {
-  $schema['multiping'] = array(
-    'fields' => array(
-      'id' => array('type'=>'serial', 'unsigned'=>TRUE, 'not null'=>TRUE),
-      'name' => array('type'=>'varchar', 'length'=>100, 'not null'=>TRUE),
-      'url' => array('type'=>'varchar', 'length'=>255, 'not null'=>TRUE),
-      'method' => array('type'=>'varchar', 'length'=>50),
-      'lastping' => array('type'=>'int', 'unsigned'=>TRUE, 'default'=>0),
-      'whentoping' => array('type'=>'int', 'unsigned'=>TRUE, 'default'=>1),
-      'submitmainrss' => array('type'=>'int', 'unsigned'=>TRUE, 'default'=>0),
-      'voc' => array('type'=>'text', 'length'=>4000),
-      'nodetypes' => array('type'=>'text', 'length'=>4000),
-      'failcount' => array('type'=>'int', 'unsigned'=>TRUE, 'default'=>0),
+  return array(
+    'multiping' => array(
+      'fields' => array(
+        'id' => array(
+          'type' => 'serial', 
+          'unsigned' => TRUE, 
+          'not null' => TRUE,
+        ),
+        'name' => array(
+          'type' => 'varchar',
+          'length' => 100, 
+          'not null' => TRUE,
+        ),
+        'url' => array(
+          'type' => 'varchar', 
+          'length' => 255, 
+          'not null' => TRUE,
+        ),
+        'method' => array(
+          'type' => 'varchar', 
+          'length' => 50
+        ),
+        'lastping' => array(
+          'type' => 'int', 
+          'unsigned' => TRUE, 
+          'default' => 0,
+        ),
+        'whentoping' => array(
+          'type' => 'int', 
+          'unsigned' => TRUE, 
+          'default' => 1,
+        ),
+        'submitmainrss' => array(
+          'type' => 'int', 
+          'unsigned' => TRUE, 
+          'default' => 0,
+        ),
+        'voc' => array(
+          'type' => 'text', 
+          'length' => 4000,
+        ),
+        'nodetypes' => array(
+          'type' => 'text', 
+          'length' => 4000,
+        ),
+        'failcount' => array(
+          'type' => 'int', 
+          'unsigned' => TRUE, 
+          'default' => 0
+        ),
+      ),
+      'primary key' => array('id'),
     ),
-    'primary key' => array('id'),
   );
-  return $schema;
 }
 
+/**
+ * Implements hook_install().
+ */
 function multiping_install() {
-  drupal_install_schema('multiping');
-  db_query("INSERT INTO {multiping} (id,name,url,method,lastping,whentoping,submitmainrss,voc,nodetypes,failcount) VALUES (1, 'Ping-o-matic', 'http://rpc.pingomatic.com', 'weblogUpdates.ping', 0, 9, 1, 'N;', 'N;', 0);");
-}
-
-function multiping_uninstall() {
-  drupal_uninstall_schema('multiping');
-}
-
-/*
-function multiping_update_1() {
-  $result = db_query('SELECT * FROM {multiping} LIMIT 1');
-  if (db_num_rows($result) == 0) {
-    $items[] = update_sql('DROP TABLE {multiping}');
-    $items[] = _multiping_create_table1();
-  } else {
-    $row = db_fetch_array($result);
-    if (!isset($row['whentoping'])) {
-      $items[] = _system_update_utf8(array('multiping'));
-      $items[] = update_sql("ALTER TABLE `multiping` ADD `whentoping` INT NOT NULL DEFAULT '1' AFTER `lastping`");
-      $items[] = update_sql("ALTER TABLE `multiping` ADD `submitmainrss` INT NOT NULL DEFAULT '0' AFTER `whentoping`");
-      $items[] = update_sql("ALTER TABLE `multiping` ADD `voc` text AFTER `submitmainrss`");
-      $items[] = update_sql("ALTER TABLE `multiping` ADD `failcount` INT default 0 AFTER `voc`");
-    }
-  }
-  return $items;
-}
-
-function multiping_update_2() {
-  $items=multiping_update_1();
-  $result = db_query('SELECT * FROM {multiping} LIMIT 1');
-  $row = db_fetch_array($result);
-  if (!isset($row['nodetypes'])) {
-    // Add new column
-    $items[] = update_sql("ALTER TABLE `multiping` ADD `nodetypes` text AFTER `voc`");
-    // New semantics of field whentoping
-    $items[] = update_sql("UPDATE `multiping` SET whentoping=3 WHERE whentoping=2");
-  }
-  return $items;
+  db_insert('multiping')
+  ->fields(array(
+    'id' => 1,
+    'name' => 'Ping-o-matic',
+    'url' => 'http://rpc.pingomatic.com',
+    'method' => 'weblogUpdates.ping',
+    'lastping' => 0,
+    'whentoping' => 9,
+    'submitmainrss' => 1,
+    'voc' => 'N;',
+    'nodetypes' => 'N;',
+    'failcount' => 0,
+  ))
+  ->execute();
 }
-*/
-
-?>
diff --git a/multiping.module b/multiping.module
old mode 100644
new mode 100755
index 6ecd47a..0be1f9e
--- a/multiping.module
+++ b/multiping.module
@@ -1,167 +1,108 @@
 <?php
+/**
+ * @file
+ */
 
-define("_multiping_when_active", 1);
-define("_multiping_when_taxonomy", 2);
-define("_multiping_when_nodetype", 4);
-define("_multiping_when_frontpage", 8);
-
-
-function _multiping_get_settings($defaults = FALSE) {
-  static $settings = NULL;
-  static $default_settings = array(
-  'global' => array(
-    'time_between_pings' => '10',
-    'pingatonce' => false,
-    ),
-  );
-  // Defaults requested?
-  if ($defaults) {
-    return $default_settings;
-  }
-  // merge settings from variable table with defaults
-  if ($settings == NULL) {
-    $settings = variable_get('multiping', array());
-    foreach ($default_settings as $key => $value) {
-      if (is_array($value)) {
-        $settings[$key] = isset($settings[$key]) ? array_merge($value, $settings[$key]) : $value;
-      }
-      else if (!isset($settings[$key])) {
-        $settings[$key] = $value;
-      }
-    }
-  }
-  // Return result
-  return $settings;
-}
-
-
+define('MULTIPING_PATH', 'admin/config/services/multiping');
+define('MULTIPING_WHEN_ACTIVE', 1);
+define('MULTIPING_WHEN_TAXONOMY', 2);
+define('MULTIPING_WHEN_NODETYPE', 4);
+define('MULTIPING_WHEN_FRONTPAGE', 8);
 /**
  * Implementation of hook_menu().
  */
 function multiping_menu() {
-  $items = array();
-  $items['admin/settings/multiping'] = array( 
-    'title' => 'Ping services',
-    'description' => 'Configure when to ping which sites',
-    'page callback' => 'multiping_admin',
-    'page arguments' => array(),
-    'access callback' => 'user_access',
-    'access arguments' => array('admin pings'),
-    'type' => MENU_NORMAL_ITEM,
-  );
-  $items['admin/settings/multiping/pingall'] = array(
-    'title' => 'Ping all',
-    'page callback' => 'multiping_pingall',
-    'access arguments' => array('admin pings'),
-    'type' => MENU_NORMAL_ITEM,
-  );
-  $items['admin/settings/multiping/new'] = array(
-    'title' => 'New ping service',
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('multiping_edit_service', '0'),
-    'access arguments' => array('admin pings'),
-    'type' => MENU_CALLBACK,
-  );
-  $items['admin/settings/multiping/%/edit'] = array(
-    'title' => 'Edit ping service',
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('multiping_edit_service', 3),
-    'access arguments' => array('admin pings'),
-    'type' => MENU_CALLBACK,
-  );
-  $items['admin/settings/multiping/%/ping'] = array(
-    'title' => 'Ping service',
-    'page arguments' => array(3),
-    'page callback' => 'multiping_ping',
-    'access arguments' => array('admin pings'),
-    'type' => MENU_CALLBACK,
-  );
-  $items['admin/settings/multiping/%/delete'] = array(
-    'title' => 'Delete ping service',
-    'page arguments' => array(3),
-    'page callback' => 'multiping_delete',
-    'access arguments' => array('admin pings'),
-    'type' => MENU_CALLBACK,
+  return array(
+    MULTIPING_PATH => array(
+      'title' => 'Multiping Settings',
+      'description' => 'Configure when to ping which sites',
+      'page callback' => 'drupal_get_form',
+      'page arguments' => array('multiping_admin'),
+      'access callback' => 'user_access',
+      'access arguments' => array('admin pings'),
+      'file' => 'pages/multiping.admin.inc',
+      'type' => MENU_NORMAL_ITEM,
+      'weight' => -10,
+    ),
+    MULTIPING_PATH . '/services' => array( 
+      'title' => 'Services',
+      'description' => 'Configure when to ping which sites',
+      'page callback' => 'multiping_admin_services',
+      'page arguments' => array(),
+      'access callback' => 'user_access',
+      'access arguments' => array('admin pings'),
+      'file' => 'pages/multiping.admin.inc',
+      'type' => MENU_LOCAL_TASK,
+    ),
+    MULTIPING_PATH . '/pingall' => array(
+      'title' => 'Ping all',
+      'page callback' => 'multiping_pingall',
+      'access arguments' => array('admin pings'),
+      'type' => MENU_LOCAL_TASK,
+    ),
+    MULTIPING_PATH . '/new' => array(
+      'title' => 'New ping service',
+      'page callback' => 'drupal_get_form',
+      'page arguments' => array('multiping_edit'),
+      'access arguments' => array('admin pings'),
+      'type' => MENU_CALLBACK,
+    ),
+    MULTIPING_PATH . '/%/edit' => array(
+      'title' => 'Edit ping service',
+      'page callback' => 'drupal_get_form',
+      'page arguments' => array('multiping_edit'),
+      'access arguments' => array('admin pings'),
+      'type' => MENU_CALLBACK,
+    ),
+    MULTIPING_PATH . '/%/ping' => array(
+      'title' => 'Ping service',
+      'page arguments' => array(),
+      'page callback' => 'multiping_ping',
+      'access arguments' => array('admin pings'),
+      'type' => MENU_CALLBACK,
+    ),
+    MULTIPING_PATH . '/%/delete' => array(
+      'title' => 'Delete ping service',
+      'page arguments' => array(),
+      'page callback' => 'multiping_delete',
+      'access arguments' => array('admin pings'),
+      'type' => MENU_CALLBACK,
+    ),
   );
-  return $items;
 }
 
 /**
   * Implementation of hook_perm().
   */
-function multiping_perm() {
-  return array('admin pings');
+function multiping_permission() {
+  return array('admin pings' => t('Administer Multiping'));
 }
 
-function _multiping_doping($pingservice) {
-  global $base_url;
 
-  // Assemble site name
-  $name=variable_get('site_name', '');
-  $slogan=variable_get('site_slogan', '');
-  if (strlen($slogan)>0)
-    $name="$name - $slogan";
-  // Determine rss url
-  if (module_exists('taxonomy') 
-    && ($pingservice->whentoping & _multiping_when_taxonomy)
-    && count($pingservice->voc)>0 && $pingservice->submitmainrss==0) {
-    // Taxonomy module exists, "ping only for nodes with taxonomy",
-    // Some taxonomy elements are actually selected, "main rss" override is off
-    $voc=unserialize($pingservice->voc);
-    $rss_url="$base_url/taxonomy/term/".implode("+", $voc)."/0/feed";
-  } 
-  else {
-    $rss_url="$base_url/rss.xml";
-  }
-  // Ping! Check service method
-  if ($pingservice->method && strlen($pingservice->method)>0) {
-    //watchdog("Multiping","XML ping: ".$pingservice->url);
-    $result = xmlrpc($pingservice->url, $pingservice->method, $name, $base_url, $rss_url);
-  } 
-  else {
-    $pingurl=strtr($pingservice->url, array(
-      "%name" => urlencode($name),
-      "%url" => urlencode("$base_url/"),
-      "%rss" => urlencode($rss_url))
-    );
-    $result = drupal_http_request($pingurl);
-    //watchdog("Multiping","Non-XML ping: ".$pingurl." Result: ".$result->code." Data: '".$result->data."'");
-    if ($result->code==200) {
-      if (strpos($result->data, "1")==0)
-        $result = TRUE; else
-        $result = FALSE;
-    } 
-    else $result = FALSE;
-  }
-  // On success: Update timestamp
-  if ($result)
-    db_query("UPDATE {multiping} SET lastping=%d WHERE id=%d", time(), $pingservice->id);
-  return $result;
-}
 
 
 function _multiping_checkpings() {
-  $settings=_multiping_get_settings();
-  $result = db_query('SELECT * FROM {multiping}');
-  while ($row = db_fetch_object($result)) {
+  $result = db_select('multiping', 'm')
+              ->fields('m')
+              ->execute();
+  foreach ($result as $row) {
     // Ping service active?
     if (! ($row->whentoping & _multiping_when_active)) {
       continue;
     }
-    // Default query: Published nodes only
-    $sql_from="{node} n";
-    $sql_where="n.status>0";
+        $sql_from = "SELECT * FROM {node} n ";
+        $sql_where = " n.status>0 ";
     // Taxonomy selection
-    if (module_exists('taxonomy') && ($row->whentoping & _multiping_when_taxonomy)) {
+    if (module_exists('taxonomy') && ($row->whentoping & MULTIPING_WHEN_TAXONOMY)) {
       // Find most recent date for nodes with given taxonomy
       $voc=unserialize($row->voc);
-      $sql_from="$sql_from, {term_node} t";
-      $sql_where="$sql_where AND t.nid=n.nid AND (t.tid=" . implode(" OR t.tid=", $voc) . ")";
+      $sql_from = "$sql_from, {term_node} t";
+      $sql_where = "$sql_where AND t.nid=n.nid AND (t.tid=" . implode(" OR t.tid=", $voc) . ")";
     }
     // Nodetype selection
     if ($row->whentoping & _multiping_when_nodetype) {
       $nodetype=unserialize($row->nodetypes);
-      $sql_where="$sql_where AND (n.type='".implode("' OR n.type='", $nodetype)."')";
+      $sql_where = "$sql_where AND (n.type='" . implode("' OR n.type='", $nodetype) . "')";
     }
     // Promoted to front page?
     if ($row->whentoping & _multiping_when_frontpage) {
@@ -170,33 +111,33 @@ function _multiping_checkpings() {
     //watchdog("debug","Multiping ".$row->name.": SELECT * FROM ".$sql_from." WHERE ".$sql_where);
     // Get max creation and modification time
     $max_created = 0;
-    $res_time = db_query('SELECT max(created) FROM {'.$sql_from.'} WHERE '.$sql_where);
+    $res_time = db_query('SELECT max(created) FROM {' . $sql_from . '} WHERE ' . $sql_where);
     $row_time = db_fetch_array($res_time);
     if ($row_time) $max_created=$row_time['max(created)'];
     $max_changed = 0;
-    $res_time = db_query('SELECT max(changed) FROM {'.$sql_from.'} WHERE '.$sql_where);
+    $res_time = db_query('SELECT max(changed) FROM {' . $sql_from . '} WHERE ' . $sql_where);
     $row_time = db_fetch_array($res_time);
-    if ($row_time) $max_changed=$row_time['max(changed)'];
-    if ($max_created>$max_changed)
-      $lastmodified = $max_created; else
-      $lastmodified = $max_changed;
-    //watchdog("Multiping","lastmodified=".$lastmodified);
-    // Check wether to ping service
-    if ($lastmodified>$row->lastping) {
+    if ($row_time) $max_changed = $row_time['max(changed)'];
+      
+    ($max_created > $max_changed) ? $lastmodified = $max_created : $lastmodified = $max_changed;
+
+    if ($lastmodified > $row->lastping) {
       // With every failure, exponentially increase retry time
-      $retry_time=$settings['global']['time_between_pings']*pow(1.5,$row->failcount);
-      if ($retry_time>24*60)  // Retry at least once a day
-	$retry_time=24*60;
-      if ($row->lastping+60*$retry_time>time()) {
-	// Timeout not yet reached
-	watchdog("Multiping", "Timeout for service @name not yet reached", array('@name' => $row->name));
-      } elseif (_multiping_doping($row)) {
-	watchdog("Multiping", 'Successfully notified %site.', array('%site' => $row->name));
-	db_query("UPDATE {multiping} SET failcount='0' WHERE id=%d",$row->id);
-      } else {
-	watchdog("Multiping", 'Failed to notify %site.', array('%site' => $row->name), WATCHDOG_WARNING);
-	db_query("UPDATE {multiping} SET failcount='%d' WHERE id=%d",
-	  ($row->failcount)+1,$row->id);
+      $retry_time = variable_get('multiping_time_between_pings', 10) * pow(1.5, $row->failcount);
+      if ($retry_time > 24*60) {  // Retry at least once a day
+        $retry_time = 24*60;
+      }
+      if ($row->lastping+60*$retry_time > REQUEST_TIME) {
+        // Timeout not yet reached
+        watchdog("Multiping", "Timeout for service @name not yet reached", array('@name' => $row->name));
+      } 
+      elseif (_multiping_doping($row)) {
+        watchdog("Multiping", 'Successfully notified %site.', array('%site' => $row->name));
+        db_query("UPDATE {multiping} SET failcount='0' WHERE id=%d", $row->id);
+      } 
+      else {
+        watchdog("Multiping", 'Failed to notify %site.', array('%site' => $row->name), WATCHDOG_WARNING);
+        db_query("UPDATE {multiping} SET failcount='%d' WHERE id=%d", ($row->failcount)+1, $row->id);
       }
     }
   }
@@ -208,294 +149,426 @@ function _multiping_checkpings() {
   * Check if sites need to be pinged.
   */
 function multiping_cron() {
-  watchdog("Multiping","Cron run",array(),WATCHDOG_DEBUG);
+  watchdog("Multiping", "Cron run", array(), WATCHDOG_DEBUG);
   _multiping_checkpings();
 }
 
 
 /**
-  * Implementation of hook_nodeapi().
+  * Implementation of hook_node_insert().
+  * If pingatonce is set, check pings.
+  */
+function multiping_node_insert(&$node) {
+  if (variable_get('multiping_pingatonce', FALSE)) {
+     _multiping_checkpings();
+  }
+}
+
+/**
+  * Implementation of hook_node_update().
   * If pingatonce is set, check pings.
   */
-function multiping_nodeapi(&$node, $op, $a3=NULL, $a4=NULL) {
-  //drupal_set_message("op=".$op);
-  //watchdog("Multiping","op=$op");
-  switch ($op) {
-    case 'insert':
-    case 'update':
-      $settings=_multiping_get_settings();
-      if ($settings['global']['pingatonce'])
-	_multiping_checkpings();
-      break;
+function multiping_node_update(&$node) {
+  if (variable_get('multiping_pingatonce', FALSE)) {
+     _multiping_checkpings();
   }
 }
 
+/**
+ * Provide service settings form
+ * @return string
+ */
+function multiping_edit() {
+  return _multiping_form();
+  
+}
 
-function multiping_edit_service($form_state, $id) {
-  $edit=array();
-  $edit['id']=$id;
-  $edit['name']='';
-  $edit['url']='http://';
-  $edit['method']='weblogUpdates.ping';
-  $edit['when_active']=1;
-  $edit['when_taxonomy']=0;
-  $edit['when_nodetype']=0;
-  $edit['when_frontpage']=0;
-  $edit['submitmainrss']=1;
-  $edit['voc']='';
-  $edit['nodetype']='';
-  if ($id>0) {
-    $result = db_query('SELECT * FROM {multiping} WHERE id=%d',$id);
-    $row = db_fetch_object($result);
-    if ($row) {
-      $edit['name']=$row->name;
-      $edit['url']=$row->url;
-      $edit['method']=$row->method;
-      $edit['when_active']=(($row->whentoping & _multiping_when_active) > 0);
-      $edit['when_taxonomy']=(($row->whentoping & _multiping_when_taxonomy) > 0);
-      $edit['when_nodetype']=(($row->whentoping & _multiping_when_nodetype) > 0);
-      $edit['when_frontpage']=(($row->whentoping & _multiping_when_frontpage) > 0);
-      $edit['submitmainrss']=$row->submitmainrss;
-      $edit['voc']=unserialize($row->voc);
-      $edit['nodetype']=unserialize($row->nodetypes);
-    } else {
-      watchdog("Multiping","Query for id=@id returned 0 rows", array('@id' => $id), WATCHDOG_WARNING);
-      $id=0;
-    }
+/**
+ * Save service settings
+ * @param string $form_id
+ * @param array $form_state 
+ */
+function multiping_edit_submit($form_id, &$form_state) {
+  $edit = $form_state['values'];
+  $edit['id'] = ($edit['id'] && is_numeric($edit['id'])) ? $edit['id'] : 0;
+  $edit['name'] = ($edit['name']) ? $edit['name'] : '(no name)';
+  $edit['url'] = ($edit['url']) ? $edit['url'] : 'http://localhost/';
+  $edit['method'] = ($edit['method']) ? $edit['method'] : '';
+  $edit['submitmainrss'] = ($edit['submitmainrss']) ? $edit['submitmainrss'] : 0; // Not present if false!
+  if ($edit['submitmainrss'] > 0) {
+    $edit['submitmainrss'] = 1;
   }
-  $form=array();
-  $form['id'] = array(
-    '#type' => 'hidden',
-    '#value' => $id,
-  );
-  $form['name'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Site name'),
-    '#default_value' => $edit['name'],
-    '#size' => 50,
-    '#maxlength' => 100,
-    '#description' => t('Displayed name of the site to be pinged'),
-    '#attributes' => NULL,
-    '#required' => TRUE,
+  $edit['whentoping'] = $edit['when_active'] * MULTIPING_WHEN_ACTIVE +
+      $edit['when_taxonomy'] * MULTIPING_WHEN_TAXONOMY +
+      $edit['when_nodetype'] * MULTIPING_WHEN_NODETYPE +
+      $edit['when_frontpage'] * MULTIPING_WHEN_FRONTPAGE;
+  
+  if ($edit['id'] == 0) {
+    db_insert('multiping')
+      ->fields(
+        array(
+          'name' => $edit['name'],
+          'url' => $edit['url'],
+          'method' => $edit['method'],
+          'whentoping' => $edit['whentoping'],
+          'submitmainrss' => $edit['submitmainrss'],
+          'voc' => serialize($edit['voc']),
+          'nodetypes' => serialize($edit['nodetype']),
+        )
+      )
+      ->execute();
+  }
+  else {
+    db_update('multiping')
+      ->fields(
+        array(
+          'name' => $edit['name'],
+          'url' => $edit['url'],
+          'method' => $edit['method'],
+          'whentoping' => $edit['whentoping'],
+          'submitmainrss' => $edit['submitmainrss'],
+          'voc' => serialize($edit['voc']),
+          'nodetypes' => serialize($edit['nodetype']),
+        )
+      )
+      ->condition('id', $edit['id'])
+      ->execute();
+  }
+  drupal_set_message(t('Changes saved.'));
+  $form_state['redirect'] = MULTIPING_PATH . '/services';
+}
+
+function multiping_pingall() {
+  $html = '<p>' . t('Running all pings...') . '</p>';
+  
+  $header = array(
+    array(
+      'data' => t('Name'),
+      'field' => 'name',
+    ),
+    array(
+      'data' => t('Status'),
+    ),
   );
-  $form['url'] = array(
-    '#type' => 'textfield',
-    '#title' => t('URL'),
-    '#default_value' => $edit['url'],
-    '#size' => 50,
-    '#maxlength' => 255,
-    '#description' => t('URL of the ping service. '.
-      'The following replacements will be done:<br />'.
-      '%name - Site name (and slogan)<br />'.
-      '%url - Site base URL<br />'.
-      '%rss - URL of RSS feed'),
-    '#attributes' => NULL,
-    '#required' => TRUE,
+  
+  $results = db_select('multiping', 'm')
+              ->fields('m')
+              ->extend('TableSort')
+              ->orderByHeader($header)
+              ->execute();
+  
+  $rows = array();
+  
+  foreach ($results as $item) {
+    $rows[] = array(
+      'data' => array(
+        $item->name,
+        (_multiping_doping($item)) ? t('Updated') : t('Failed'),
+      ),
+    );
+  }
+  
+  $html = theme('table',
+    array(
+      'header' => $header,
+      'rows' => $rows,
+      'sticky' => TRUE,
+    )
   );
-  /* Todo: Submit which RSS feed? Whole feed or a feed containing only
-     items of the selected taxonomies? */
-  $form['method'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Method name'),
-    '#default_value' => $edit['method'],
-    '#size' => 50,
-    '#maxlength' => 50,
-    '#description' => t('If this is an XML service: Name of the method to be called'),
-    '#attributes' => NULL,
-    '#required' => FALSE,
+  
+  $html .= theme('pager',
+    array(
+      'tags' => array(),
+    )
   );
-  $options = array('1' => t('Always ping'), '0' => t('Don\'t ping'));
-  if (module_exists('taxonomy')) {
-   $options['2']=t('Ping only for nodes with the following taxonomy');
+  
+  $html .= '<p>' . l(t('Return'), MULTIPING_PATH) . '</p>';
+  
+  return $html;
+}
+
+
+function multiping_ping() {
+  $id = arg(4);
+  watchdog("Multiping", "ping @id", array('@id' => $id));
+  if (!is_numeric($id)) {
+    drupal_not_found();
+    return;
   }
-  $form['when_active'] = array(
-    '#type' => 'checkbox',
-    '#title' => t('Service active'),
-    '#default_value' => $edit['when_active'],
-    '#description' => t('Activate or deactivate this service'),
+  $service = db_select('multiping', 'm')
+              ->fields('m')
+              ->condition('id', $id)
+              ->execute()
+              ->fetchObject();
+  _multiping_doping($service);
+  drupal_set_message(t('Service updated'));
+  drupal_goto(MULTIPING_PATH . '/services');
+}
+
+
+function multiping_delete() {
+  $id = arg(4);
+  watchdog("Multiping", "delete @id", array('@id' => $id));
+  if (!is_numeric($id)) {
+    drupal_not_found();
+    return;
+  }
+  db_delete('multiping')
+    ->condition('id', $id)
+    ->execute();
+  drupal_set_message(t('Service deleted.'));
+  drupal_goto(MULTIPING_PATH . '/services');
+}
+
+
+function _multiping_form() {
+  $itemid = (arg(4)!=='new') ? arg(4) : 0;
+  $defaults = _multiping_get_service_defaults($itemid);
+  $options_ping = _multiping_get_options_ping(); 
+
+  $return = array(
+    'id' => array(
+      '#type' => 'hidden',
+      '#value' => $defaults['id'],
+    ),
+    'name' => array(
+      '#type' => 'textfield',
+      '#title' => t('Site name'),
+      '#default_value' => $defaults['name'],
+      '#size' => 50,
+      '#maxlength' => 100,
+      '#description' => t('Displayed name of the site to be pinged'),
+      '#attributes' => NULL,
+      '#required' => TRUE,
+    ),
+    'url' => array(
+      '#type' => 'textfield',
+      '#title' => t('URL'),
+      '#default_value' => $defaults['url'],
+      '#size' => 50,
+      '#maxlength' => 255,
+      '#description' => t('URL of the ping service. ' . 
+        'The following replacements will be done:<br />' . 
+        '%name - Site name (and slogan)<br />' . 
+        '%url - Site base URL<br />' . 
+        '%rss - URL of RSS feed'),
+      '#attributes' => NULL,
+      '#required' => TRUE,
+    ),
+    'method' => array(
+      '#type' => 'textfield',
+      '#title' => t('Method name'),
+      '#default_value' => $defaults['method'],
+      '#size' => 50,
+      '#maxlength' => 50,
+      '#description' => t('If this is an XML service: Name of the method to be called'),
+      '#attributes' => NULL,
+      '#required' => FALSE,
+    ),
+    'when_active' => array(
+      '#type' => 'checkbox',
+      '#title' => t('Service active'),
+      '#default_value' => $defaults['when_active'],
+      '#description' => t('Activate or deactivate this service'),
+    ),
   );
   if (module_exists('taxonomy')) {
-    $form['when_taxonomy'] = array(
+    $return['when_taxonomy'] = array(
       '#type' => 'checkbox',
       '#title' => t('Ping only for selected taxonomies'),
-      '#default_value' => $edit['when_taxonomy'],
+      '#default_value' => $defaults['when_taxonomy'],
       '#description' => t('Send a ping only if the node belongs to one of the follwing categories'),
     );
-    $form['voc'] = array(
+    $return['voc'] = array(
       '#type' => 'select',
       '#title' => t('Taxonomy terms when to ping'),
-      '#default_value' => $edit['voc'],
-      '#options' => taxonomy_form_all(),
-      '#multiple' => true,
+      '#default_value' => $defaults['voc'],
+      '#options' => _multiping_get_options_taxonomy(),
+      '#multiple' => TRUE,
       '#description' => t('Ping this service if any of the taxonomy terms selected above matches the respective node'),
     );
-    $form['submitmainrss'] = array(
+    $return['submitmainrss'] = array(
       '#type' => 'checkbox',
       '#title' => t('Send main RSS feed in ping'),
-      '#default_value' => $edit['submitmainrss'],
+      '#default_value' => $defaults['submitmainrss'],
       '#description' => t('If checked, the main RSS feed is sent; otherwise, an RSS feed containing only articles from the selected taxonomies is used.'),
     );
   }
-  $form['when_nodetype'] = array(
+  $return['when_nodetype'] = array(
     '#type' => 'checkbox',
     '#title' => t('Ping only for selected node types'),
-    '#default_value' => $edit['when_nodetype'],
+    '#default_value' => $defaults['when_nodetype'],
     '#description' => t('Send a ping only if the node is one of the following node types'),
   );
-  $form['nodetype'] = array(
+  $return['nodetype'] = array(
     '#type' => 'select',
     '#title' => t('Node types when to ping'),
-    '#default_value' => $edit['nodetype'],
-    '#options' => node_get_types('names'),
-    '#multiple' => true,
+    '#default_value' => $defaults['nodetypes'],
+    '#options' => _multiping_get_options_nodetypes(),
+    '#multiple' => TRUE,
     '#description' => t('Ping this service if any of the node types selected above matches the respective node'),
   );
-  $form['when_frontpage'] = array(
+  $return['when_frontpage'] = array(
     '#type' => 'checkbox',
     '#title' => t('Ping only for nodes promoted to front page'),
-    '#default_value' => $edit['when_frontpage'],
+    '#default_value' => $defaults['when_frontpage'],
     '#description' => t('Send a ping only if the node is promoted to the front page'),
   );
-  $form['submit'] = array(
+  $return['submit'] = array(
     '#type' => 'submit',
     '#value' => t('Submit'),
   );
-  return $form;
+  return $return;
 }
 
 
-function multiping_edit_service_submit($form_id, &$form_state) {
-  $edit = $form_state['values']; // TODO: Is this ok? http://drupal.org/node/144132#process-params
-  if ($edit['form_id']=='multiping_edit_service') {
-    $edit['id'] = ($edit['id'] && is_numeric($edit['id'])) ? $edit['id'] : 0;
-    $edit['name'] = ($edit['name']) ? $edit['name'] : '(no name)';
-    $edit['url'] = ($edit['url']) ? $edit['url'] : 'http://localhost/';
-    $edit['method'] = ($edit['method']) ? $edit['method'] : '';
-    $edit['submitmainrss'] = ($edit['submitmainrss']) ? $edit['submitmainrss'] : 0; // Not present if false!
-    if ($edit['submitmainrss']>0) $edit['submitmainrss']=1;
-    $whentoping=$edit['when_active']*_multiping_when_active+
-      $edit['when_taxonomy']*_multiping_when_taxonomy+
-      $edit['when_nodetype']*_multiping_when_nodetype+
-      $edit['when_frontpage']*_multiping_when_frontpage;
-    if ($edit['id']==0) {
-      db_query("INSERT INTO {multiping} (name,url,method,whentoping,submitmainrss,voc,nodetypes) ".
-	"VALUES ('%s','%s','%s','%s','%s','%s','%s')",$edit['name'],$edit['url'],
-	$edit['method'],$whentoping,$edit['submitmainrss'],
-	serialize($edit['voc']),serialize($edit['nodetype']));
-    } else {
-      db_query("UPDATE {multiping} SET name='%s',url='%s',method='%s',whentoping='%s',submitmainrss='%s',voc='%s',nodetypes='%s' ".
-	"WHERE id=%d",$edit['name'],$edit['url'],$edit['method'],$whentoping,$edit['submitmainrss'],serialize($edit['voc']),serialize($edit['nodetype']),$edit['id']);
-    }
+/**
+ * Returns defaults for given service id
+ * @param int $id
+ * @return array
+ */
+function _multiping_get_service_defaults($id = 0) {
+  if ($id == 0) {
+    return array(
+      'id' => $id,
+      'name' => '',
+      'url' => 'http://',
+      'method' => 'weblogUpdates.ping',
+      'when_active' => 0,
+      'when_taxonomy' => 0,
+      'when_nodetype' => 0,
+      'when_frontpage' => 0,
+      'submitmainrss' => 1,
+      'voc' => '',
+      'nodetypes' => '',
+    );
   }
-  drupal_set_message("Changes saved.");
-  #drupal_goto("admin/settings/multiping");
-  $form_state['redirect']="admin/settings/multiping";
-}
-
-
-function multiping_settings() {
-  $form=array();
-  $settings=_multiping_get_settings();
-  $form['global']['time_between_pings'] = array(
-     '#type' => 'textfield',
-     '#title' => t('Time between pings'),
-     '#default_value' => $settings['global']['time_between_pings'],
-     '#size' => 8,
-     '#maxlength' => 4,
-     '#description' => t('Minimum number of minutes between two pings to same site'),
-     '#attributes' => NULL,
-     '#required' => TRUE,
-  );
-  $form['pingatonce'] = array(
-    '#type' => 'checkbox',
-    '#title' => t('Ping after post'),
-    '#default_value' => $settings['global']['pingatonce'],
-    '#description' => t('Ping directly after post/update (instead of pinging during the cron job runs)'),
-  );
-  $form['submit'] = array(
-    '#type' => 'submit',
-    '#value' => t('Submit'),
-  );
-  return $form;
-}
-
+  else {
+    $results = db_select('multiping', 'm')
+                ->fields('m')
+                ->execute()
+                ->fetchAssoc();
 
-function multiping_settings_submit($form_id, &$form_state) {
-  $edit = $form_state['values']; // TODO: Is this ok? http://drupal.org/node/144132#process-params
-  if ($edit['form_id']=='multiping_settings') {
-    $settings=_multiping_get_settings();
-    $settings['global']['time_between_pings']=$edit['time_between_pings'];
-    $settings['global']['pingatonce']=$edit['pingatonce'];
-    variable_set('multiping', $settings);
+    $return = array();
+    
+    foreach ($results as $key => $val) {
+      $return[$key] = $val;
+    }
+    
+    $return['when_active'] = ($return['whentoping'] & MULTIPING_WHEN_ACTIVE) ? 1 : 0;
+    $return['when_taxonomy'] = ($return['whentoping'] & MULTIPING_WHEN_TAXONOMY) ? 1 : 0;
+    $return['when_nodetype'] = ($return['whentoping'] & MULTIPING_WHEN_NODETYPE) ? 1 : 0;
+    $return['when_frontpage'] = ($return['whentoping'] & MULTIPING_WHEN_FRONTPAGE) ? 1 : 0;
+    
+    return $return;
   }
-  drupal_set_message("Changes saved.");
-  #drupal_goto("admin/settings/multiping");
-  $form_state['redirect']="admin/settings/multiping";
 }
 
 
 /**
-  * Menu callback: Admin page
-  */
-function multiping_admin() {
-  $output = "";
-  // General settings
-  $output .= drupal_get_form('multiping_settings', $form);
-  // Table with services
-  $header = array(t('Name'), t('Last update'), array('data' => t('Operations'), 'colspan' => '3'));
-  $result = db_query('SELECT * FROM {multiping} ORDER BY id');
-  while ($row = db_fetch_object($result)) {
-    if ($row->lastping==0)
-      $lastping=t('never'); else
-      $lastping=format_date($row->lastping,'small');
-    $rows[] = array(
-      $row->name,
-      $lastping,
-      l(t('edit'),"admin/settings/multiping/".$row->id."/edit"),
-      l(t('ping'),"admin/settings/multiping/".$row->id."/ping"),
-      l(t('delete'),"admin/settings/multiping/".$row->id."/delete")
-    );
+ * Returns options for Ping-Selection
+ * @return array
+ */
+function _multiping_get_options_ping() {
+  $return = array('1' => t('Always ping'), '0' => t('Don\'t ping'));
+  if (module_exists('taxonomy')) {
+   $return['2']=t('Ping only for nodes with the following taxonomy');
   }
-  $output .= theme('table',$header,$rows);
-  // Links
-  $output .= "<p>".l(t('Add service'),"admin/settings/multiping/new")."</p>";
-  return $output;
+  return $return;
 }
 
-
-function multiping_pingall() {
-  $output = "<p>".t("Running all pings...")."</p>";
-  $header = array(t('Name'), t('Status'));
-  $result = db_query('SELECT * FROM {multiping} ORDER BY id');
-  while ($row = db_fetch_object($result)) {
-    $rows[] = array($row->name,_multiping_doping($row) ? t('Ok') : t('Failed'));
+/**
+ * Returns all nodetypes in current setup
+ * @return array
+ */
+function _multiping_get_options_nodetypes() {
+  $types = _node_types_build()->types;
+  $return = array();
+  foreach ($types as $type) {
+    $return[$type->type] = $type->name;
   }
-  $output .= theme('table',$header,$rows);
-  $output .= "<p>".l(t('Return'),"admin/settings/multiping")."</p>";
-  return $output;
+  return $return;
 }
 
-
-function multiping_ping($id) {
-  watchdog("Multiping","ping @id", array('@id' => $id));
-  if (!is_numeric($id)) {
-    drupal_not_found();
-    return;
+/**
+ * Returns options for taxonomy-terms selector
+ * @return array
+ */
+function _multiping_get_options_taxonomy() {
+  $terms = array();
+  if (module_exists('taxonomy')) {
+    $taxonomies = taxonomy_get_vocabularies();
+    foreach ($taxonomies as $taxonomy) {
+      $termsobject = taxonomy_get_tree($taxonomy->vid);
+      foreach ($termsobject as $term) {
+        $terms[$term->tid] = $term->name;
+      }
+    }
   }
-  drupal_set_message("Not yet implemented","warning");
-  drupal_goto("admin/settings/multiping");
+  return $terms;
 }
 
-
-function multiping_delete($id) {
-  watchdog("Multiping","delete @id", array('@id' => $id));
-  if (!is_numeric($id)) {
-    drupal_not_found();
-    return;
+/**
+ * Ping given service
+ * @global type $base_url
+ * @param type $pingservice
+ * @return boolean 
+ */
+function _multiping_doping($pingservice) {
+  global $base_url;
+  // Assemble site name
+  $name = variable_get('site_name', '');
+  $slogan = variable_get('site_slogan', '');
+  if (strlen($slogan)>0) {
+    $name = $name . ' - ' . $slogan;
   }
-  db_query("DELETE FROM {multiping} WHERE id=%d",intval($id));
-  drupal_set_message("Service deleted.");
-  drupal_goto("admin/settings/multiping");
-}
-
-?>
+  // Determine rss url
+  if (module_exists('taxonomy') 
+    && ($pingservice->whentoping & MULTIPING_WHEN_TAXONOMY)
+    && count($pingservice->voc) > 0 && $pingservice->submitmainrss == 0) {
+    // Taxonomy module exists, "ping only for nodes with taxonomy",
+    // Some taxonomy elements are actually selected, "main rss" override is off
+    $voc = unserialize($pingservice->voc);
+    $rss_url = $base_url . '/taxonomy/term/' . implode('+', $voc) . '/0/feed';
+  } 
+  else {
+    $rss_url = $base_url . '/rss.xml';
+  }
+  // Ping! Check service method
+  if ($pingservice->method && strlen($pingservice->method) > 0) {
+    //watchdog("Multiping","XML ping: ".$pingservice->url);
+    $result = xmlrpc($pingservice->url, array($pingservice->method => array($name, $base_url, $rss_url)));
+  } 
+  else {
+    $pingurl=strtr($pingservice->url, array(
+      "%name" => urlencode($name),
+      "%url" => urlencode("$base_url/"),
+      "%rss" => urlencode($rss_url))
+    );
+    $result = drupal_http_request($pingurl);
+    //watchdog("Multiping","Non-XML ping: ".$pingurl." Result: ".$result->code." Data: '".$result->data."'"
+    if ($result->code==200) {
+      if (strpos($result->data, "1")==0) {
+        $result = TRUE;
+      }
+      else { 
+        $result = FALSE;
+      }
+    } 
+    else {
+      $result = FALSE;
+    }
+  }
+  // On success: Update timestamp
+  if ($result) {
+    db_update('multiping')
+      ->fields(
+        array(
+          'lastping' => REQUEST_TIME
+        )
+      )
+      ->condition('id', $pingservice->id)
+      ->execute();
+    }
+  return $result;
+}
\ No newline at end of file
