<?php

/**
  * BLOG:CMS: PHP/MySQL Personal Content Management System (CMS)
  * http://blogcms.com/
  * ----------------------------------------------------------------
  *
  * Copyright (C) 2003-2005 Radek HULÁN
  * http://hulan.cz/contact/
  *
  * Based on: 
  * ----------------------------------------------------------------
  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/) 
  * Copyright (C) 2002-2003 The Nucleus Group
  *
  * ----------------------------------------------------------------
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2
  * of the License, or (at your option) any later version.
**/

class NP_TrackBack extends NucleusPlugin {

var $template,$notitle,$noblogname,$noexcerpt,$notificationMail,$notificationMailTitle,$larray;

	function init() {
		$this->template = array(
			'LIST_HEADER' => '',
			'LIST_ITEM' => '<li><a href="<%url%>"><%blogname%>: <%title%></a>: <%excerpt%> <i>[Date: <%timestamp%>]</i> <%delete%></li>',
			'LIST_FOOTER' => '<li>Use this <a href="<%tburl%>">Trackback URL</a> for ping (right mouse click and copy URL).</li>',

			'DELETE' => '[delete]',
			'NO_TRACKBACKS' => '<li>Use this <a href="<%tburl%>">Trackback URL</a> for ping (right mouse click and copy URL).</li>',
		);
		$this->notitle = '[no title]';
		$this->noblogname = '[no name]';
		$this->noexcerpt = '';

		$this->notificationMail = "New trackback for article number <%tb_id%>\n\nURL:\t<%url%>\nTitle:\t<%title%>\nExcerpt:\t<%excerpt%>\nBlog:\t<%blogname%>";
		$this->notificationMailTitle = 'New trackback for <%tb_id%>';
	}

	function getName() { 		return 'TrackBack for Nucleus'; }
	function getAuthor()  {		return 'Wouter Demuynck'; }
	function getURL() {			return 'http://nucleuscms.org/plugins-trackback.php'; }
	function getVersion() {		return '1.5'; }
	function getMinNucleusVersion() {
								return 200;
	}

	function supportsFeature($what) {
		switch($what)
		{
			case 'SqlTablePrefix':
				return 1;
			default:
				return 0;
		}
	}

	function getDescription() {
		return 'This plugin implements the TrackBack (http://www.movabletype.org/trackback/) feature as introduced in MovableType.';
	}

	function getTableList() {	return array( sql_table('plugin_tb') ); }
	function getEventList() {	return array('PostAddItem','AddItemFormExtras','EditItemFormExtras','PreUpdateItem','PrepareItemForEdit', 'BookmarkletExtraHead'); }

	/**
	  * This function installs the TrackBack plugin. It creates a table in which to
	  * store trackback data
	  */
	function install() {
		$this->createOption('CheckIDs','Only allow valid itemids as trackback-ids','yesno','yes');
		$this->createOption('Notify','Send e-mail notification on ping receipt','yesno','no');
		$this->createOption('NotifyEmail','Which e-mail address to send these notification to?','text','');
		$this->createOption('AcceptPing','Accept pings','yesno','yes');
		$this->createOption('SendPings','Allow sending pings','yesno','yes');
	}

	/**
	  * A trackback ping is to be received on the URL
	  * http://yourdomain.com/action.php?action=plugin&name=TrackBack&tb_id=1234
	  *
	  * Extra variables to be passed along are url, title, excerpt, blog_name
	  */
	function doAction($type)
    {
        switch ($type) {
        // when no action type is given, assume it's a ping
        case '':
            $this->handlePingXML();
            break;
        // show a list of trackbacks
        case 'list':
            return $this->showList(intRequestVar('tb_id'));
            break;
        // delete a trackback
        case 'delete':
            return $this->delete();
            break;
        // send a TrackBack ping
        case 'sendping':
            $itemid = intRequestVar('itemid');
            $title = requestVar('title');
            $url = requestVar('url');
            $excerpt = requestVar('excerpt');
            $blog_name = requestVar('blog_name');
            $ping_url = requestVar('ping_url');
            if ($ping_url) {
                $error = $this->sendPing($itemid, $title, $url, $excerpt, $blog_name, $ping_url);
                if ($error)
                    return $error;
            }
            $tb_url_amount = requestVar('tb_url_amount');
            if ($tb_url_amount > 0) {
                for ($i = 0;$i < $tb_url_amount;$i++) {
                    $tb_temp_url = requestVar('tb_url_' . $i);
                    if ($tb_temp_url)
                        $error = $this->sendPing($itemid, $title, $url, $excerpt, $blog_name, $tb_temp_url);
                    if ($error)
                        return $error;
                }
            }

            header('Location: ' . requestVar('redirectTo'));
            break;

        case 'manualping':
            return $this->handlePingManual();
            // show a 'Send Ping' form
        case 'pingform':
            return $this->showPingForm();
            // show a 'Manual Ping' form (allows bloggers that don't have trackback to manually add one)
        case 'manualpingform':
            return $this->showManualPingForm();
            // other actions result in an error
        default:
            return 'Unexisting action: ' . $type;
        }
        exit;
    }

	/**
	  * TrackBack data can be inserted using skinvars (or templatevars)
	  */
	function doSkinVar($skinType, $what = '', $tb_id = '') {
		global $itemid;
		if ($tb_id == '') $tb_id = $itemid;

		switch ($what) {

			// insert RDF code
			case 'code':
				$this->insertCode($tb_id);
				break;

			// insert TrackBack URL
			case 'tburl':
				echo $this->getTrackBackUrl($tb_id);
				break;

			// insert TrackBack count
			case 'count':
				echo $this->getTrackBackCount($tb_id);
				break;

			// insert a link to the PingForm
			case 'pingformlink':
			  global $member;
				if ($member->isAdmin() && $member->isLoggedIn()) echo " - <a href='".$this->getPingFormLink($tb_id)."'>TB Ping</a>";
				break;

			// insert a link to the ManualPingForm
			case 'manualpingformlink':
			  global $member;
				if ($member->isAdmin() && $member->isLoggedIn())  echo " - <a href='".$this->getManualPingFormLink($tb_id)."'>TB Add</a>";
				break;

      //Auto-Discovery of TrackBack Ping URLs Implementation
      case 'tbcode':
          if($skinType == 'item' || $skinType == 'template') $this->insertTBCode($tb_id);
          break;

			// shows the TrackBack list
			case 'list':
			case '':
				$this->showList($tb_id);
				break;
			default:
				return;
		}
	}

	/**
	  * When used in templates, the tb_id will be determined by the itemid there
	  */
	function doTemplateVar(&$item, $what = '') {
		$this->doSkinVar('template',$what, $item->itemid);
	}

    function event_BookmarkletExtraHead($data)
    {
        global $NP_TB_URL;
        $loglink = requestVar('loglink');
        $autoDiscoveryRes = $this->autoDiscovery('<a href="'.$loglink.'"></a>');
        $NP_TB_URL = $autoDiscoveryRes[0];
    }

	/**
	  * Add trackback options to add item form/bookmarklet
	  */
	function event_AddItemFormExtras($data)
    {
        global $NP_TB_URL;
		?>
			<h3>TrackBack</h3>

			<p>
				<label for="plug_tb_url">TrackBack Ping URL:</label>
				<input type="text" value="<?php if (isSet($NP_TB_URL)) {echo $NP_TB_URL;} ?>" id="plug_tb_url" name="trackback_ping_url" size="60" />
			</p>
		<?php
	}

    /**
     * Add trackback options to edit item form/bookmarklet
     */
   function event_EditItemFormExtras($data) {
      ?>
         <h3>TrackBack</h3>
         <p>
            <label for="plug_tb_url">TrackBack Ping URL:</label>
            <input type="text" value="" id="plug_tb_url" name="trackback_ping_url" size="60" /><br />
<?php
        // We do not want to print the header is no URL auto discovered.....
        if (count($this->larray) > 0) {
?>
                Auto Discovered Ping URL's:<br />
<?php
         echo '<input type="hidden" name="tb_url_amount" value="'.count($this->larray).'" />';
         for($i=0;$i<count($this->larray);$i++){
            echo '<input type="checkbox" name="tb_url_'.$i.'" value="'.$this->larray[$i].'" id="tb_url_'.$i.'" /><label for="tb_url_'.$i.'">'.$this->larray[$i].'</label><br />';
         }
        }
        echo "</p>";
   }


   function event_PrepareItemForEdit($data) {
      return;
      // ED$ The space between body and more is to make sure we didn't join 2 words accidently....
      $this->larray = $this->autoDiscovery($data['item']['body'].' '.$data['item']['more']);
   }

	/**
	  * After an item has been added to the database, send out a ping if requested
	  * (trackback_ping_url variable in request)
	  */
	function event_PostAddItem($data) {
		global $manager, $CONF;

		// no trackback_ping_url => nothing to do
		$ping_url = requestVar('trackback_ping_url');
		if (!$ping_url) return;

		// do not ping on draft and future items
		$itemid = $data['itemid'];
		$item =& $manager->getItem($itemid, 0, 0);
		if (!$item) return; // don't ping for draft & future
		if ($item['draft']) return;	// don't ping on draft items

		// gather some more information, needed to send the ping (blog name, etc)
		$blog =& $manager->getBlog(getBlogIDFromItemID($itemid));
		$blog_name = $blog->getName();
		$title = strip_tags($item['title']);
		$excerpt = shorten(preg_replace('/<%(.*?)%>/','',strip_tags($item['body'])),200,'...');

		// a little hack to get a working permanent URL for the item
		if (!$CONF['ItemURL'])
			$CONF['ItemURL'] = $blog->getURL();
		$url = createItemLink($itemid);

		// send the ping (add errors to actionlog)
		$res = $this->sendPing($itemid, $title, $url, $excerpt, $blog_name, $ping_url);
		if ($res) ACTIONLOG::add(WARNING, 'TrackBack Error:', $res, ' (',$ping_url,')');
	}


    function event_PreUpdateItem($data) {
      global $manager, $CONF;

      //first request the vars to detect if a trackback needs to be sent
      $ping_urls_count = 0;
      $ping_urls = array();
      $ping_url = requestVar('trackback_ping_url'); //from the input box
      if ($ping_url) {
          $ping_urls[0] = $ping_url;
          $ping_urls_count++;
      }

      $tb_url_amount = requestVar('tb_url_amount'); //from the checkboxes
      for ($i=0;$i<$tb_url_amount;$i++) {
          $tb_temp_url = requestVar('tb_url_'.$i);
          if ($tb_temp_url) {
              //we have a winner ;-)
              $ping_urls[$ping_urls_count] = $tb_temp_url;
              $ping_urls_count++;
          }
      }

      //now that we have collected all the ping_url's we can check to see if
      //we need to send any ping
      if ($ping_urls_count <= 0) {
        //we don't need to send any ping, exit the function
        return;
      }

      // do not ping on draft and future items
      $itemid = $data['itemid'];
      $item = &$manager->getItem($itemid, 0, 0);
      if (!$item) return; // don't ping for draft & future
      if ($item['draft']) return;   // don't ping on draft items

      // gather some more information, needed to send the ping (blog name, etc)
      $blog =& $manager->getBlog(getBlogIDFromItemID($itemid));
      $blog_name = $blog->getName();
      $title = strip_tags($data['title']);
      $excerpt = shorten(preg_replace('/<%(.*?)%>/','',strip_tags($data['body'])),200,'...');

      // a little hack to get a working permanent URL for the item
      if (!$CONF['ItemURL'])
         $CONF['ItemURL'] = $blog->getURL();
      $url = createItemLink($itemid);

      // send the ping(s) (add errors to actionlog)
      for ($i=0; $i<count($ping_urls); $i++) {
          $res = $this->sendPing($itemid, $title, $url, $excerpt, $blog_name, $ping_urls[$i]);
          if ($res) ACTIONLOG::add(WARNING, 'TrackBack Error:', $res, ' (',$ping_urls[$i],')');
      }
   }

    // -----------------------------------------------------------------------------
	// helper functions below

	function handlePingXML() {
		$errorMsg = $this->handlePing();
		if ($errorMsg != '')
			$this->xmlResponse($errorMsg);
		else
			$this->xmlResponse();
	}
	function handlePingManual() {
		$errorMsg = $this->handlePing();
		if ($errorMsg != '')
			return $errorMsg;
		else
			header('Location: ' . requestVar('redirectTo'));
	}
	/**
	  * Handle an incoming TrackBack ping and save the data in the database
	  */
	function handlePing() {
		global $manager;

		// check if we are allowed to accept pings
		if ($this->getOption('AcceptPing') == 'no')
			return 'Sorry, no trackback pings are accepted';

		// 1. get attributes
		$tb_id 		= requestVar('tb_id');
		$url 		= requestVar('url');
		$title 		= requestVar('title');
		$excerpt 	= requestVar('excerpt');
		$blog_name 	= requestVar('blog_name');
    $rss = requestVar('__mode');

		// 2. check for errors
		if (!$tb_id)	return 'TrackBack ID is missing (tb_id)';
    if ($rss == 'rss'){
      $this->rssResponse($tb_id);
      return ;
    }
		if (!$url)	return 'URL is missing (url)';

    if (!$title) $blog_name = $this->notitle;
    if (!$blog_name) $title = $this->noblogname;
		if (!$excerpt) $excerpt = $this->noexcerpt;

		$tb_id = intval($tb_id);
		if ((!$manager->existsItem($tb_id,0,0)) && ($this->getOption('CheckIDs') == 'yes')) return _NOSUCH_ITEM;

		// 3. save data in the DB

    // first check to see if it is a new TB or an update
    $query = 'SELECT tb_id FROM '.sql_table('plugin_tb')." WHERE url = '".sql_escape($url). "' and tb_id = ".$tb_id;
    $res = sql_query($query);
    if (sql_num_rows($res) != 0) {
      //existing TB, update it
      $query = 'UPDATE '.sql_table('plugin_tb')." SET title = '".sql_escape($title)."', excerpt = '".sql_escape($excerpt)."', blog_name = '".sql_escape($blog_name)."', timestamp = ".mysqldate(time())." WHERE url = '".sql_escape($url)."' and tb_id = ".$tb_id;
      $res = sql_query($query);
      if (!$res)
        return 'Could not update trackback data...:'.sql_error();
    } else {
      //new TB, insert it
      $query = 'INSERT INTO ' . sql_table('plugin_tb') . " (tb_id, url, title, excerpt, blog_name, timestamp) VALUES ('".$tb_id."','".sql_escape($url)."','".sql_escape($title)."','".sql_escape($excerpt)."','".sql_escape($blog_name)."',".mysqldate(time()).")";
      $res = sql_query($query);
      if (!$res) return 'Could not save trackback data, possibly because of a double entry: ' . sql_error();
    }

		// send notification e-mail if needed
		if ($this->getOption('Notify') == 'yes') {
			$destAddress = $this->getOption('NotifyEmail');

			$vars = array(
				'tb_id' => $tb_id,
				'url' => $url,
				'title' => $title,
				'excerpt' => $excerpt,
				'blogname' => $blog_name
			);

			$mailto_title = TEMPLATE::fill($this->notificationMailTitle,$vars);
			$mailto_msg = TEMPLATE::fill($this->notificationMail,$vars);

			global $CONF, $DIR_LIBS;
			if (!is_dir($DIR_LIBS)) die('System is not configured properly');
			// make sure notification class is loaded
			if (!class_exists('notification')) include($DIR_LIBS . 'NOTIFICATION.php');
			$notify = new NOTIFICATION($destAddress);
			$notify->notify($mailto_title, $mailto_msg , $CONF['AdminEmail']);

		}

		return '';
	}


	/**
	  * Show a 'ping site' form, where a ping URL can be entered for an item
	  */
	function showPingForm()
{
    global $manager, $CONF;
    // get values to put in the fields
    $ping_url = requestVar('ping_url');
    $itemid = intRequestVar('itemid');
    $item = &$manager->getItem($itemid, 0, 0);
    if ($item) {
        $blog = &$manager->getBlog(getBlogIDFromItemID($itemid));

        $blog_name = $blog->getName();
        $title = strip_tags($item['title']);
        $excerpt = shorten(preg_replace('/<%(.*?)%>/','',strip_tags($item['body'])), 200, '...');
        if (!$CONF['ItemURL']) $CONF['ItemURL'] = $blog->getURL();
        $url = createItemLink($itemid);
    }
    // generate the page

    ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
        <title>TrackBack Ping</title>
        <link rel="stylesheet" type="text/css" href="<?php echo $CONF['AdminURL']?>styles/bookmarklet.css" />
</head>
<body>
<h1>TrackBack Ping</h1>
<form method="post" action="<?php echo $CONF['ActionURL'] ?>"><div>
<input type="hidden" name="itemid" value="<?php echo $itemid?>" />
<input type="hidden" name="action" value="plugin" />
<input type="hidden" name="name" value="TrackBack" />
<input type="hidden" name="type" value="sendping" />
<input type="hidden" name="redirectTo" value="<?php echo htmlspecialchars(serverVar('HTTP_REFERER'))?>" />
<table><tr>
        <td>URL</td>
        <td><input type="text" value="<?php echo htmlspecialchars($url)?>" name="url" size="60" /></td></tr><tr>
        <td>Title</td>
        <td><input type="text" value="<?php echo htmlspecialchars($title)?>" name="title" size="60" /></td></tr><tr>
        <td>Excerpt</td>
        <td><textarea name="excerpt" cols="40" rows="5"><?php echo htmlspecialchars($excerpt)?></textarea></td>
</tr><tr>
        <td>Blog Name</td>
        <td><input type="text" value="<?php echo htmlspecialchars($blog_name)?>" name="blog_name" size="60" /></td>
</tr><tr>
        <td>Ping URL</td>
        <td><input type="text" value="<?php echo htmlspecialchars($ping_url)?>" name="ping_url" size="60" /></td>
</tr><tr>
<?php
    $autoDiscoveryRes = $this->autoDiscovery($item['body'].$item['more']);
    if (count($autoDiscoveryRes) > 0) {

        ?>
        <td>Auto Discovered URL</td>
        <td>
<?php
        echo '<input type="hidden" name="tb_url_amount" value="' . count($autoDiscoveryRes) . '" />';
        for($i = 0;$i < count($autoDiscoveryRes);$i++) {
            echo '<input type="checkbox" name="tb_url_' . $i . '" value="' . $autoDiscoveryRes[$i] . '" id="tb_url_' . $i . '" /><label for="tb_url_' . $i . '">' . $autoDiscoveryRes[$i] . '</label><br />';
        }

        ?>
        </td>
<?php
    }

    ?>
</tr><tr>
        <td>Send Ping</td>
        <td><input type="submit" value="Send Ping" />
</tr></table>
</div></form>

</body>
</html>
<?php

}



	/**
	  * Show a 'manual ping site' form. This form can be made available to all your visitors,
	  * so they can manually add a trackback for their own blog item (e.g. Blogger blogs, since
	  * Blogger does not support trackback)
	  */
	function showManualPingForm() {
		global $manager, $CONF;

		// check if we are allowed to accept pings
		if ($this->getOption('AcceptPing') == 'no')
			return 'Sorry, no trackback pings are accepted';

		$tb_id = intRequestVar('tb_id');

		// check if the ID to be pinged is valid
		if ((!$manager->existsItem($tb_id,0,0)) && ($this->getOption('CheckIDs') == 'yes'))
			return _NOSUCH_ITEM;

		// generate the page

?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
	<title>Add TrackBack</title>
	<link rel="stylesheet" type="text/css" href="<?php echo $CONF['AdminURL']?>styles/bookmarklet.css" />
</head>
<body>

<h1>TrackBack Ping</h1>
<form method="post" action="<?php echo $CONF['ActionURL'] ?>"><div>
<input type="hidden" name="tb_id" value="<?php echo $tb_id?>" />
<input type="hidden" name="action" value="plugin" />
<input type="hidden" name="name" value="TrackBack" />
<input type="hidden" name="type" value="manualping" />
<input type="hidden" name="redirectTo" value="<?php echo htmlspecialchars(serverVar('HTTP_REFERER'))?>" />
<table><tr>
	<td>Article URL</td>
	<td><input type="text" value="" name="url" size="60" /></td>
</tr><tr>
	<td>Article Title</td>
	<td><input type="text" value="" name="title" size="60" /></td>
</tr><tr>
	<td>Excerpt from article</td>
	<td><textarea name="excerpt" cols="40" rows="5"></textarea></td>
</tr><tr>
	<td>Your Blog Name</td>
	<td><input type="text" value="" name="blog_name" size="60" /></td>
</tr><tr>
	<td>Add TrackBack</td>
	<td><input type="submit" value="Add TrackBack" />
</tr></table>
</div></form>

</body>
</html>
<?php

	}

	/**
	  * Sends the ping for real, and returns an error when something goes wrong
	  */
	function sendPing($itemid, $title, $url, $excerpt, $blog_name, $ping_url) {
      // check some things
      if ( ! $this->canSendPing() )
         return 'You\'re not allowed to send pings';
      if ( $this->getOption( 'SendPings' ) == 'no' )
         return 'Sending trackback pings is disabled';
      if ( $ping_url == '' )
         return 'No ping URL';

      $parsed_url = parse_url( $ping_url );

      // error: bad url
      if ( $parsed_url['scheme'] != 'http' ||   $parsed_url['host'] == '' )
         return 'Bad ping URL';

      // guess port number
      $port = ( $parsed_url['port'] ) ? $parsed_url['port'] : 80;

      // create contents
      $content  = 'title=' . urlencode( $title );
      $content .= '&url=' . urlencode( $url );
      $content .= '&excerpt=' . urlencode( $excerpt );
      $content .= '&blog_name=' . urlencode( $blog_name );

      $user_agent = 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)';

      // create HTTP request
      $request  = 'POST ' . $parsed_url['path'];
      if ( $parsed_url['query'] != '' )
         $request .= '?' . $parsed_url['query'];
      $request .= " HTTP/1.1\r\n";
      $request .= "Accept: */*\r\n";
      $request .= "User-Agent: " . $user_agent . "\r\n";
      $request .=   "Host: " . $parsed_url['host'] . ":" . $port . "\r\n";
      $request .= "Connection: Keep-Alive\r\n";
      $request .= "Cache-Control: no-cache\r\n";
      $request .= "Connection: Close\r\n";
      $request .=   "Content-Length: " . strlen( $content ) . "\r\n";
      $request .= "Content-Type: application/x-www-form-urlencoded\r\n";
      $request .= "\r\n";
      $request .= $content;

      $socket = fsockopen( $parsed_url['host'], $port, $errno, $errstr );
      if ( ! $socket )
         return 'Could not send ping: '.$errstr.' ('.$errno.')';

      // send request
      fputs( $socket, $request );

      // recieve response
      $result = '';
      while ( ! feof ( $socket ) ) {
         $result .= fgets( $socket, 4096 );
      }
      fclose( $socket );

      // instead of parsing the XML, just check for the error string
      // [TODO] extract real error message and return that
      if ( strstr($result,'<error>1</error>') )
         return 'An error occurred: '.htmlspecialchars($result);
   }

	/**
	  * Returns true if the member is allowed to delete a trackback item
	  */
	function canDelete($tb_id) {
		global $member, $manager;

		if (!$member->isLoggedIn()) return 0;

		$checkIDs = $this->getOption('CheckIDs');
		$itemExists =& $manager->existsItem($tb_id,0,0);

		// if CheckIDs option is set, check if member canEdit($tb_id)
		// if CheckIDs option is not set, and item exists, check if member canEdit($tb_id)
		// if CheckIDs option is not set, and item does not exists, check if member isAdmin()

		if (($checkIDs == 'yes') || ($itemExists))
			return $member->canAlterItem($tb_id);
		else
			return $member->isAdmin();
	}

	/**
	  * Check if member may send ping (check if logged in)
	  */
	function canSendPing() {
		global $member;
		return $member->isLoggedIn();
	}

	/**
	  * Delete a TrackBack item, redirect to referer
	  */
	function delete() {
		$tb_id = intRequestVar('tb_id');
		$url = requestVar('url');

		if (!$this->canDelete($tb_id))
			return 'You\'re not allowed to delete this trackback item';

		$query = 'DELETE FROM ' . sql_table('plugin_tb') . " WHERE tb_id='$tb_id' and url='".sql_escape($url)."'";
		sql_query($query);
		header('Location: ' . serverVar('HTTP_REFERER'));
	}

	/**
	  * Returns the trackback URL
	  */
	function getTrackBackUrl($itemid) {
		global $CONF;
		return $CONF['ActionURL'] . '?action=plugin&amp;name=TrackBack&amp;tb_id='.$itemid;
	}

	/**
	  * Returns the PingForm URL
	  */
	function getPingFormLink($itemid) {
		global $CONF;
		return $CONF['ActionURL'] . '?action=plugin&amp;name=TrackBack&amp;type=pingform&amp;itemid='.$itemid;
	}

	/**
	  * Returns the ManualPingForm URL
	  */
	function getManualPingFormLink($tb_id) {
		global $CONF;
		return $CONF['ActionURL'] . '?action=plugin&amp;name=TrackBack&amp;type=manualpingform&amp;tb_id='.$tb_id;
	}

	/**
	  * Returns the TrackBack count for a TrackBack item
	  */
	function getTrackBackCount($tb_id) {
		return quickQuery('SELECT COUNT(*) as result FROM ' . sql_table('plugin_tb') . ' WHERE tb_id='.$tb_id);
	}

	/**
	  * Insert RDF code for item
	  */
	function insertCode($itemid) {
		global $manager, $CONF;
		$item =& $manager->getItem($itemid, 0, 0);
?>
<!--
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
         xmlns:dc="http://purl.org/dc/elements/1.1/"
         xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
<rdf:Description
    rdf:about="<?php echo createItemLink($itemid)?>"
    dc:identifier="<?php echo createItemLink($itemid)?>"
    dc:title="<?php echo htmlspecialchars($item['title'])?>"
    dc:description="<?php echo htmlspecialchars(shorten($item['body'],'200','...'))?>"
    trackback:ping="<?php echo $this->getTrackBackUrl($itemid)?>"
    dc:date="<?php echo strftime('%Y-%m-%dT%H:%M:%S')?>"
     />
</rdf:RDF>
-->
<?php
	}

	/**
	  * Generate XML response (when receiving pings)
	  */
	function xmlResponse($errorMessage = '') {
		Header('Content-Type: text/xml');
		echo '<','?xml version="1.0" encoding="'._CHARSET.'"?','><response>';
		if ($errorMessage)
        	echo '<error>1</error><message>',htmlspecialchars($errorMessage),'</message>';
        else
        	echo '<error>0</error>';
		echo '</response>';
		exit;
	}

	/**
	  * Show the list of TrackBack pings for a certain Trackback ID
	  */
	function showList($tb_id) {
		global $CONF;

		// create SQL query
		$query = 'SELECT url, blog_name, excerpt, title, UNIX_TIMESTAMP(timestamp) as timestamp FROM '.sql_table('plugin_tb').' WHERE tb_id='.$tb_id .' ORDER BY timestamp DESC';
		$res = sql_query($query);

		// when no TrackBack pings are found
		if (sql_num_rows($res) == 0) {
			$data = array(
				'tburl' => $this->getTrackBackUrl($tb_id)
			);
			echo TEMPLATE::fill($this->template['NO_TRACKBACKS'], $data);
			return;
		}

		// when TrackBack pings are found
		$vars = array(
			'tburl' => $this->getTrackBackUrl($tb_id)
		);
		echo TEMPLATE::fill($this->template['LIST_HEADER'],$vars);
		while ($o = sql_fetch_object($res)) {
			$canDelete = $this->canDelete($tb_id);
			$data = array(
  			'url' => htmlspecialchars(SEOlink($o->url)),
				'blogname' => htmlspecialchars($o->blog_name),
				'timestamp' => strftime('%Y-%m-%d',$o->timestamp),
				'title' => htmlspecialchars($o->title),
				'excerpt' => htmlspecialchars(preg_replace('/<%(.*?)%>/','',strip_tags($o->excerpt))),
				'delete' => $canDelete?'<a href="'.$CONF['ActionURL'].'?action=plugin&amp;name=TrackBack&amp;type=delete&amp;tb_id='.$tb_id.'&amp;url='.urlencode($o->url).'">'.$this->template['DELETE'].'</a>':'',
				'tburl' => $this->getTrackBackUrl($tb_id)
			);
			echo TEMPLATE::fill($this->template['LIST_ITEM'], $data);	// old style template parsing
		}
		echo TEMPLATE::fill($this->template['LIST_FOOTER'],$vars);
	}

    /**
     * Retrieving TrackBack Pings (when __mode=rss)
     */
   function rssResponse($tb_id) {
      global $manager, $CONF;
      $item =& $manager->getItem($tb_id, 0, 0);

      if($item){
         $blog =& $manager->getBlog(getBlogIDFromItemID($item['itemid']));
         $blog_name = $blog->getName();
         $title = strip_tags($item['title']);
         $excerpt = shorten(preg_replace('/<%(.*?)%>/','',strip_tags($item['body'])),200,'...');
         if (!$CONF['ItemURL']) $CONF['ItemURL'] = $blog->getURL();
         $url = createItemLink($item['itemid'],'');

         Header('Content-Type: text/xml');
         echo '<','?xml version="1.0" encoding="'._CHARSET.'"?','><response>';
         echo '<error>0</error>';
         echo '<rss version="0.91">';
         echo '<channel>';
         echo '<title>'.$title.'</title>';
         echo '<link>'.$url.'</link>';
         echo '<description>'.$excerpt.'</description>';
         echo '<language>en</language>';

         $query = 'SELECT url, blog_name, excerpt, title, UNIX_TIMESTAMP(timestamp) as timestamp FROM '.sql_table('plugin_tb').' WHERE tb_id='.$tb_id .' ORDER BY timestamp DESC';
         $res = sql_query($query);
         while ($o = sql_fetch_object($res)) {
            $data = array(
               'url' => htmlspecialchars($o->url),
               'blogname' => htmlspecialchars($o->blog_name),
               'timestamp' => strftime('%Y-%m-%d',$o->timestamp),
               'title' => htmlspecialchars($o->title),
               'excerpt' => htmlspecialchars($o->excerpt),
               'tburl' => $this->getTrackBackUrl($tb_id)
            );
            echo '<item>';
            echo '<title>'.$data['title'].'</title>';
            echo '<link>'.$data['url'].'</link>';
            echo '<description>'.$data['excerpt'].'</description>';
            echo '</item>';
         }
         echo '</channel>';
         echo '</rss>';
         echo '</response>';
         exit;
      }else{
         $this->xmlResponse(_ERROR_NOSUCHITEM);
      }

   }

   /**
     * Insert RDF code for Auto-Discovery of TrackBack Ping URLs
     */
   function insertTBCode($itemid) {
      global $manager, $CONF;
      $item =& $manager->getItem($itemid, 0, 0);
      $uri = sprintf("%s%s%s","http://",serverVar("HTTP_HOST"),serverVar("REQUEST_URI"));
?>
<!--
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
         xmlns:dc="http://purl.org/dc/elements/1.1/"
         xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
<rdf:Description
    rdf:about="<?php echo $uri?>"
    dc:identifier="<?php echo $uri?>"
    dc:title="<?php echo htmlspecialchars($item['title'])?>"
    trackback:ping="<?php echo $this->getTrackBackUrl($itemid)?>" />
</rdf:RDF>
-->
<?php
   }

   function autoDiscovery($text) {
      $uriArray = $this->getPermaLinksFromText($text);
      $res = array();

      for ($i=0;$i<count($uriArray);$i++){
         if (($infoRDF = $this->getRDFFromLink($uriArray[$i])) !== false) {
            if (($tburi = $this->getURIFromRDF($infoRDF, 'trackback:ping')) !== false) {
               $res[] = $tburi;
            }
         }
      }
      return $res;
   }

   function getPermaLinksFromText($text){
      $linkArray = array();
      if (preg_match_all('/<a ([^>]+)>/', $text, $array, PREG_SET_ORDER)){
         for ($i = 0; $i<count($array); $i++){
            preg_match('/href="http:\/\/(.+)"/', $array[$i][1], $matches);
            $linkArray[$matches[1]] = 1;
         }
      }
      return array_keys($linkArray);
   }

   function getRDFFromLink($link){
      $result = @file('http://'.$link);
      if(!$result){
         return false;
      }
      $pageContents = @join( "", $result );
      preg_match_all('/(<rdf:RDF.*?<\/rdf:RDF>)/sm', $pageContents, $rdf_all, PREG_SET_ORDER);

      for ($i=0; $i<count($rdf_all); $i++){
         if (preg_match('|dc:identifier="http://'.preg_quote($link).'"|ms',$rdf_all[$i][1])){
            return $rdf_all[$i][1];
         }
      }
      return false;
   }

   function getURIFromRDF($rdf, $attribute){
      if (preg_match('/'.$attribute.'="([^"]+)"/', $rdf, $matches)) {
         return $matches[1];
      }
      return false;
   }

}
?>