(bug 796) trackback support
authorRiver Tarnell <kateturner@users.mediawiki.org>
Sat, 23 Jul 2005 05:47:25 +0000 (05:47 +0000)
committerRiver Tarnell <kateturner@users.mediawiki.org>
Sat, 23 Jul 2005 05:47:25 +0000 (05:47 +0000)
16 files changed:
RELEASE-NOTES
includes/Article.php
includes/DefaultSettings.php
includes/OutputPage.php
includes/Skin.php
includes/SkinTemplate.php
includes/SpecialPage.php
includes/Title.php
languages/Language.php
maintenance/archives/patch-trackbacks.sql [new file with mode: 0644]
maintenance/tables.sql
maintenance/updaters.inc
skins/MonoBook.php
skins/common/common.css
skins/monobook/main.css
trackback.php [new file with mode: 0644]

index 8069d8f..bfa7b44 100644 (file)
@@ -595,6 +595,7 @@ of MediaWiki:Newpagetext) to &action=edit, if page is new.
 * (bug 740) Messages from extensions now appear in Special:Allmessages
 * (bug 2857) fixed parsing of lists in <pre> sections
 * Now sorting interwiki links by iw_prefix and avoiding duplicates
+* (bug 796) Trackback support
 
 === Caveats ===
 
index 3c1c3eb..75cd20c 100644 (file)
@@ -94,10 +94,10 @@ class Article {
                if ( 0 == $this->getID() ) {
                        if ( 'edit' == $action ) {
                                wfProfileOut( $fname );
-                               
+
                                # If requested, preload some text.
                                $text=$this->getPreloadedText($preload);
-                               
+
                                # We used to put MediaWiki:Newarticletext here if
                                # $text was empty at this point.
                                # This is now shown above the edit box instead.
@@ -154,7 +154,7 @@ class Article {
                }
                return '';
        }
-       
+
        /**
         * This function returns the text of a section, specified by a number ($section).
         * A section is text under a heading like == Heading == or <h1>Heading</h1>, or
@@ -678,7 +678,7 @@ class Article {
        function view() {
                global $wgUser, $wgOut, $wgRequest, $wgOnlySysopsCanPatrol, $wgLang;
                global $wgLinkCache, $IP, $wgEnableParserCache, $wgStylePath, $wgUseRCPatrol;
-               global $wgEnotif, $wgParser, $wgParserCache;
+               global $wgEnotif, $wgParser, $wgParserCache, $wgUseTrackbacks;
                $sk = $wgUser->getSkin();
 
                $fname = 'Article::view';
@@ -835,6 +835,10 @@ class Article {
                         );
                }
 
+               # Trackbacks
+               if ($wgUseTrackbacks)
+                       $this->addTrackbacks();
+
                # Put link titles into the link cache
                $wgOut->transformBuffer();
 
@@ -845,6 +849,30 @@ class Article {
                wfProfileOut( $fname );
        }
 
+       function addTrackbacks() {
+               global $wgOut;
+
+               $dbr = wfGetDB(DB_SLAVE);
+               $tbs = $dbr->select(
+                               /* FROM   */ 'trackbacks',
+                               /* SELECT */ array('tb_title', 'tb_url', 'tb_ex', 'tb_name'),
+                               /* WHERE  */ array('tb_id' => $this->getID())
+               );
+
+               if (!$dbr->numrows($tbs))
+                       return;
+
+               $tbtext = "";
+               while ($o = $dbr->fetchObject($tbs)) {
+                       $tbtext .= wfMsg(strlen($o->tb_ex) ? 'trackbackexcerpt' : 'trackback',
+                                       $o->tb_title,
+                                       $o->tb_url,
+                                       $o->tb_ex,
+                                       $o->tb_name);
+               }
+               $wgOut->addWikitext(wfMsg('trackbackbox', $tbtext));
+       }
+
        function render() {
                global $wgOut;
 
@@ -979,7 +1007,7 @@ class Article {
 
                $ns = $this->mTitle->getNamespace();
                $ttl = $this->mTitle->getDBkey();
-               
+
                # If this is a comment, add the summary as headline
                if($comment && $summary!="") {
                        $text="== {$summary} ==\n\n".$text;
@@ -1233,7 +1261,7 @@ class Article {
                                array_push( $wgPostCommitUpdateList, $u );
                        }
 
-                       # File cache    
+                       # File cache
                        if ( $wgUseFileCache ) {
                                $cm = new CacheManager($this->mTitle);
                                @unlink($cm->fileCacheName());
@@ -2403,9 +2431,6 @@ class Article {
                $db->freeResult( $res );
                return $result;
        }
-
-
 }
 
-
 ?>
index c571df2..cacbf1d 100644 (file)
@@ -1588,4 +1588,10 @@ $wgHTTPProxy = false;
  */
 $wgEnableScaryTranscluding = false;
 
+/**
+ * Support blog-style "trackbacks" for articles.  See
+ * http://www.sixapart.com/pronet/docs/trackback_spec for details.
+ */
+$wgUseTrackbacks = false;
+
 ?>
index 36e5871..8ebde39 100644 (file)
@@ -791,7 +791,7 @@ class OutputPage {
         */
        function headElement() {
                global $wgDocType, $wgDTD, $wgContLanguageCode, $wgOutputEncoding, $wgMimeType;
-               global $wgUser, $wgContLang, $wgRequest;
+               global $wgUser, $wgContLang, $wgRequest, $wgUseTrackbacks, $wgTitle;
 
                if( $wgMimeType == 'text/xml' || $wgMimeType == 'application/xhtml+xml' || $wgMimeType == 'application/xml' ) {
                        $ret = "<?xml version=\"1.0\" encoding=\"$wgOutputEncoding\" ?>\n";
@@ -825,6 +825,9 @@ class OutputPage {
                $ret .= $this->mScripts;
                $ret .= $sk->getUserStyles();
 
+               if ($wgUseTrackbacks && $this->isArticleRelated())
+                       $ret .= $wgTitle->trackbackRDF();
+
                $ret .= "</head>\n";
                return $ret;
        }
index d2de740..712a216 100644 (file)
@@ -108,7 +108,7 @@ class Skin extends Linker {
 
        function addMetadataLinks( &$out ) {
                global $wgTitle, $wgEnableDublinCoreRdf, $wgEnableCreativeCommonsRdf, $wgRdfMimeType, $action;
-               global $wgRightsPage, $wgRightsUrl;
+               global $wgRightsPage, $wgRightsUrl, $wgUseTrackbacks;
 
                if( $out->isArticleRelated() ) {
                        # note: buggy CC software only reads first "meta" link
@@ -732,7 +732,7 @@ END;
        }
 
        function bottomLinks() {
-               global $wgOut, $wgUser, $wgTitle;
+               global $wgOut, $wgUser, $wgTitle, $wgUseTrackbacks;
                $sep = " |\n";
 
                $s = '';
@@ -746,6 +746,9 @@ END;
                          . $sep . $this->whatLinksHere()
                          . $sep . $this->watchPageLinksLink();
 
+                       if ($wgUseTrackbacks)
+                               $s .= $sep . $this->trackbackLink();
+
                        if ( $wgTitle->getNamespace() == NS_USER
                            || $wgTitle->getNamespace() == NS_USER_TALK )
 
@@ -1113,6 +1116,13 @@ END;
                }
        }
 
+       function trackbackLink() {
+               global $wgTitle;
+
+               return "<a href=\"" . $wgTitle->trackbackURL() . "\">"
+                       . wfMsg('trackbacklink') . "</a>";
+       }
+
        function otherLanguages() {
                global $wgOut, $wgContLang, $wgTitle, $wgHideInterlanguageLinks;
 
index 775c778..5ea7c37 100644 (file)
@@ -149,6 +149,7 @@ class SkinTemplate extends Skin {
                global $wgDisableCounters, $wgLogo, $action, $wgFeedClasses, $wgHideInterlanguageLinks;
                global $wgMaxCredits, $wgShowCreditsIfMax;
                global $wgPageShowWatchingUsers;
+               global $wgUseTrackbacks;
 
                $fname = 'SkinTemplate::outputPage';
                wfProfileIn( $fname );
@@ -217,6 +218,9 @@ class SkinTemplate extends Skin {
                } else {
                        $tpl->set( 'feeds', false );
                }
+               if ($wgUseTrackbacks && $out->isArticleRelated())
+                       $tpl->set( 'trackbackhtml', $wgTitle->trackbackRDF());
+
                $tpl->setRef( 'mimetype', $wgMimeType );
                $tpl->setRef( 'jsmimetype', $wgJsMimeType );
                $tpl->setRef( 'charset', $wgOutputEncoding );
@@ -721,6 +725,8 @@ class SkinTemplate extends Skin {
         * @access private
         */
        function buildNavUrls () {
+               global $wgUseTrackbacks, $wgTitle;
+
                $fname = 'SkinTemplate::buildNavUrls';
                wfProfileIn( $fname );
 
@@ -768,6 +774,10 @@ class SkinTemplate extends Skin {
                        $nav_urls['recentchangeslinked'] = array(
                                'href' => $this->makeSpecialUrl("Recentchangeslinked/$this->thispage")
                        );
+                       if ($wgUseTrackbacks)
+                               $nav_urls['trackbacklink'] = array(
+                                       'href' => $wgTitle->trackbackURL()
+                               );
                }
 
                if( $this->mTitle->getNamespace() == NS_USER || $this->mTitle->getNamespace() == NS_USER_TALK ) {
index 64bf918..869ccaf 100644 (file)
@@ -33,7 +33,7 @@ $wgSpecialPages = array(
        'Userlogout'        => new UnlistedSpecialPage( 'Userlogout' ),
        'Preferences'       => new SpecialPage( 'Preferences' ),
        'Watchlist'         => new SpecialPage( 'Watchlist' ),
-       
+
        'Recentchanges'     => new IncludableSpecialPage( 'Recentchanges' ),
        'Upload'            => new SpecialPage( 'Upload' ),
        'Imagelist'         => new SpecialPage( 'Imagelist' ),
@@ -134,11 +134,11 @@ class SpecialPage
         * Whether the special page can be included in an article
         */
        var $mIncludable;
-       
+
 
        /**#@-*/
 
-       
+
        /**
         * Add a page to the list of valid special pages
         * $obj->execute() must send HTML to $wgOut then return
@@ -173,7 +173,7 @@ class SpecialPage
                        return NULL;
                }
        }
-       
+
        /**
         * @static
         * @param string $name
@@ -223,7 +223,7 @@ class SpecialPage
         * The path     may contain parameters, e.g. Special:Name/Params
         * Extracts the special page name and call the execute method, passing the parameters
         *
-        * Returns a title object if the page is redirected, false if there was no such special 
+        * Returns a title object if the page is redirected, false if there was no such special
         * page, and true if it was successful.
         *
         * @param $title          a title object
@@ -247,7 +247,7 @@ class SpecialPage
                        } else {
                                $redir =& SpecialPage::getRedirect( $name );
                                if ( isset( $redir ) ) {
-                                       if ( isset( $par ) ) 
+                                       if ( isset( $par ) )
                                                $wgOut->redirect( $redir->getFullURL() . '/' . $par );
                                        else
                                                $wgOut->redirect( $redir->getFullURL() );
@@ -288,7 +288,7 @@ class SpecialPage
                $oldTitle = $wgTitle;
                $oldOut = $wgOut;
                $wgOut = new OutputPage;
-               
+
                $ret = SpecialPage::executePath( $title, true );
                if ( $ret === true ) {
                        $ret = $wgOut->getHTML();
@@ -337,7 +337,7 @@ class SpecialPage
        function isListed() { return $this->mListed; }
        function getFile() { return $this->mFile; }
        function including( $x = NULL ) { return wfSetVar( $this->mIncluding, $x ); }
-       function includable( $x = NULL ) { return wfSetVar( $this->mIncludable, $x ); } 
+       function includable( $x = NULL ) { return wfSetVar( $this->mIncludable, $x ); }
 
        /**
         * Checks if the given user (identified by an object) can execute this
index 0eadae6..f0a4c9d 100644 (file)
@@ -2079,5 +2079,29 @@ class Title {
                $dbw->update( 'page', /* SET */ array( 'page_touched' => $dbw->timestamp() ),
                                                        /* WHERE */ array( 'page_id' => $toucharr ),$fname);
        }
+
+       function trackbackURL() {
+               global $wgTitle, $wgScriptPath, $wgServer;
+
+               return "$wgServer$wgScriptPath/trackback.php?article="
+                       . htmlspecialchars(urlencode($wgTitle->getPrefixedDBkey()));
+       }
+
+       function trackbackRDF() {
+               $url = htmlspecialchars($this->getFullURL());
+               $title = htmlspecialchars($this->getText());
+               $tburl = $this->trackbackURL();
+
+               return "
+<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=\"$url\"
+   dc:identifier=\"$url\"
+   dc:title=\"$title\"
+   trackback:ping=\"$tburl\" />
+</rdf:RDF>";
+       }
 }
 ?>
index bd99de1..8841083 100644 (file)
@@ -637,10 +637,10 @@ to confirm that the account is actually yours.",
 'emailauthenticated'        => 'Your email address was authenticated on $1.',
 'emailnotauthenticated'     => 'Your email address is <strong>not yet authenticated</strong>. No email
 will be sent for any of the following features.',
-'noemailprefs'              => '<strong>No email address has been specified</strong>, the following 
+'noemailprefs'              => '<strong>No email address has been specified</strong>, the following
 features will not work.',
 'emailconfirmlink' => 'Confirm your e-mail address',
-'invalidemailaddress'  => 'The email address cannot be accepted as it appears to have an invalid 
+'invalidemailaddress'  => 'The email address cannot be accepted as it appears to have an invalid
 format. Please enter a well-formatted address or empty that field.',
 
 # Edit page toolbar
@@ -2121,6 +2121,15 @@ will expire at $4.
 'scarytranscludefailed' => '[Template fetch failed for $1; sorry]',
 'scarytranscludetoolong' => '[URL is too long; sorry]',
 
+# Trackbacks
+'trackbackbox' => "<div id='mw_trackbacks'>
+Trackbacks for this article:<br/>
+$1
+</div>
+",
+'trackback' => "; $4 : [$2 $1]</li>\n",
+'trackbackexcerpt' => "; $4 : [$2 $1]: <nowiki>$3</nowiki></li>\n",
+'trackbacklink' => 'Trackback',
 );
 
 /* a fake language converter */
diff --git a/maintenance/archives/patch-trackbacks.sql b/maintenance/archives/patch-trackbacks.sql
new file mode 100644 (file)
index 0000000..93e3662
--- /dev/null
@@ -0,0 +1,9 @@
+CREATE TABLE /*$wgDBprefix*/trackbacks (
+       tb_id           INTEGER REFERENCES page(page_id) ON DELETE CASCADE,
+       tb_title        VARCHAR(255) NOT NULL,
+       tb_url          VARCHAR(255) NOT NULL,
+       tb_ex           TEXT,
+       tb_name         VARCHAR(255),
+
+       INDEX (tb_id)
+);
index dc508b8..fc17533 100644 (file)
@@ -829,3 +829,14 @@ CREATE TABLE /*$wgDBprefix*/logging (
 --  PRIMARY KEY  (gr_id)
 --
 --) TYPE=InnoDB;
+
+CREATE TABLE /*$wgDBprefix*/trackbacks (
+        tb_id           INTEGER REFERENCES page(page_id) ON DELETE CASCADE,
+        tb_title        VARCHAR(255) NOT NULL,
+        tb_url          VARCHAR(255) NOT NULL,
+        tb_ex           TEXT,
+        tb_name         VARCHAR(255),
+
+        INDEX (tb_id)
+);
+
index 82b1301..c2034ce 100644 (file)
@@ -25,6 +25,7 @@ $wgNewTables = array(
        array( 'validate',      'patch-validate.sql' ),
        array( 'user_newtalk',  'patch-usernewtalk2.sql' ),
        array( 'transcache',    'patch-transcache.sql' ),
+       array( 'trackbacks',    'patch-trackbacks.sql' ),
 );
 
 $wgNewFields = array(
index 5d94cff..17a952d 100644 (file)
@@ -68,6 +68,7 @@ class MonoBookTemplate extends QuickTemplate {
     <?php if($this->data['usercss'   ]) { ?><style type="text/css"><?php              $this->html('usercss'   ) ?></style><?php    } ?>
     <?php if($this->data['userjs'    ]) { ?><script type="<?php $this->text('jsmimetype') ?>" src="<?php $this->text('userjs'    ) ?>"></script><?php } ?>
     <?php if($this->data['userjsprev']) { ?><script type="<?php $this->text('jsmimetype') ?>"><?php      $this->html('userjsprev') ?></script><?php   } ?>
+    <?php if($this->data['trackbackhtml']) print $this->data['trackbackhtml']; ?>
   </head>
   <body <?php if($this->data['body_ondblclick']) { ?>ondblclick="<?php $this->text('body_ondblclick') ?>"<?php } ?>
         <?php if($this->data['body_onload'    ]) { ?>onload="<?php     $this->text('body_onload')     ?>"<?php } ?>
@@ -158,9 +159,14 @@ class MonoBookTemplate extends QuickTemplate {
            <ul>
                  <?php if($this->data['notspecialpage']) { foreach( array( 'whatlinkshere', 'recentchangeslinked' ) as $special ) { ?>
                  <li id="t-<?php echo $special?>"><a href="<?php
-                   echo htmlspecialchars($this->data['nav_urls'][$special]['href']) 
+                   echo htmlspecialchars($this->data['nav_urls'][$special]['href'])
                    ?>"><?php echo $this->msg($special) ?></a></li>
                  <?php } } ?>
+              <?php if(isset($this->data['nav_urls']['trackbacklink'])) { ?>
+                 <li id="t-trackbacklink"><a href="<?php
+                   echo htmlspecialchars($this->data['nav_urls']['trackbacklink']['href'])
+                   ?>"><?php echo $this->msg('trackbacklink') ?></a></li>
+             <?php } ?>
              <?php if($this->data['feeds']) { ?><li id="feedlinks"><?php foreach($this->data['feeds'] as $key => $feed) {
                ?><span id="feed-<?php echo htmlspecialchars($key) ?>"><a href="<?php
                echo htmlspecialchars($feed['href']) ?>"><?php echo htmlspecialchars($feed['text'])?></a>&nbsp;</span>
@@ -172,7 +178,7 @@ class MonoBookTemplate extends QuickTemplate {
              <?php } ?>
              <?php if(!empty($this->data['nav_urls']['print']['href'])) { ?>
              <li id="t-print"><a href="<?php
-                   echo htmlspecialchars($this->data['nav_urls']['print']['href']) 
+                   echo htmlspecialchars($this->data['nav_urls']['print']['href'])
                    ?>"><?php echo $this->msg('printableversion') ?></a></li>
              <?php } ?>
            </ul>
index 71bed99..d73d139 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * common.css
  * This file contains CSS settings common to Wikistandard, Nostalgia and CologneBlue
  */
@@ -38,7 +38,7 @@ div.thumb div {
     text-align: center;
     overflow: hidden;
 }
-div.thumb div * { 
+div.thumb div * {
     border: none;
     background: none;
 }
@@ -68,13 +68,13 @@ div.tleft {
 /* Page history styling */
 /* the auto-generated edit comments */
 .autocomment { color: #4b4b4b; }
-#pagehistory span.user { 
+#pagehistory span.user {
     margin-left: 1.4em;
     margin-right: 0.4em;
 }
 #pagehistory span.minor { font-weight: bold; }
 #pagehistory li { border: 1px solid White; }
-#pagehistory li.selected { 
+#pagehistory li.selected {
     background-color:#f9f9f9;
     border:1px dashed #aaaaaa;
 }
@@ -82,11 +82,11 @@ div.tleft {
 table.diff { background:white; }
 td.diff-otitle { background:#cccccc; }
 td.diff-ntitle { background:#cccccc; }
-td.diff-addedline { 
+td.diff-addedline {
     background:#ccffcc;
     font-size: 94%;
 }
-td.diff-deletedline { 
+td.diff-deletedline {
     background:#ffffaa;
     font-size: 94%;
 }
@@ -141,13 +141,13 @@ span.texhtml { font-family: serif; }
 }
 
 /* preference page with js-genrated toc */
-#preftoc { 
+#preftoc {
     float: left;
     margin: 1em 1em 1em 1em;
     width: 13em;
 }
 #preftoc li { border: 1px solid White; }
-#preftoc li.selected { 
+#preftoc li.selected {
     background-color:#f9f9f9;
     border:1px dashed #aaaaaa;
 }
@@ -156,12 +156,12 @@ span.texhtml { font-family: serif; }
     display: block;
     color: #005189;
 }
-#prefcontrol { 
+#prefcontrol {
     clear: left;
     float: left;
     margin-top: 1em;
 }
-div.prefsectiontip { 
+div.prefsectiontip {
     font-size: 94%;
     margin-top: 1em;
 }
@@ -194,7 +194,7 @@ div.townBox {
 }
 div.townBox dl {
     padding: 0;
-    margin: 0 0 0.3em 0; 
+    margin: 0 0 0.3em 0;
     font-size: 96%;
 }
 div.townBox dl dt {
@@ -206,7 +206,7 @@ div.townBox dl dd {
     background-color: #f3f3f3;
 }
 /* use this instead of #toc for page content */
-.toccolours { 
+.toccolours {
     border:1px solid #aaaaaa;
     background-color:#f9f9f9;
     padding:5px;
@@ -254,7 +254,7 @@ table.gallery {
         background-color:#ffffff;
 }
 
-table.gallery tr { 
+table.gallery tr {
         vertical-align:top;
 }
 
@@ -273,12 +273,12 @@ div.gallerybox div.thumb {
         text-align: center;
         border: 1px solid #cccccc;
         margin: 2px;
-}       
+}
 
 div.gallerytext {
         font-size: 94%;
         padding: 2px 4px;
-}       
+}
 
 span.comment {
        font-style: italic;
@@ -348,3 +348,9 @@ table.exif td.spacer {
 .visualClear {
     clear: both;
 }
+
+#mw_trackbacks {
+       border: solid 1px #bbbbff;
+       background-color: #eeeeff;
+       padding: 0.2em;
+}
index 318b16c..ff04c7d 100644 (file)
@@ -219,7 +219,7 @@ pre {
 */
 
 #siteSub {
-    display: none; 
+    display: none;
 }
 #contentSub {
     font-size: 84%;
@@ -1078,7 +1078,7 @@ span.changedby {
        float: left;
        font-size: small;
        text-align: center;
-}    
+}
 .editExternallyHelp {
        font-style: italic;
        color: gray;
@@ -1181,3 +1181,9 @@ p.revision_saved {
        color: green;
        font-weight:bold;
 }
+
+#mw_trackbacks {
+       border: solid 1px #bbbbff;
+       background-color: #eeeeff;
+       padding: 0.2em;
+}
diff --git a/trackback.php b/trackback.php
new file mode 100644 (file)
index 0000000..726cacb
--- /dev/null
@@ -0,0 +1,75 @@
+<?php
+/**
+ * Provide functions to handle article trackbacks.
+ * @package MediaWiki
+ * @subpackage SpecialPage
+ */
+
+unset($IP);
+define('MEDIAWIKI', true);
+require_once('./includes/Defines.php');
+
+if (!file_exists('LocalSettings.php'))
+       exit;
+
+require_once('./LocalSettings.php');
+require_once('includes/Setup.php');
+
+require_once('Title.php');
+require_once('DatabaseFunctions.php');
+
+/**
+ *
+ */
+function XMLsuccess() {
+       echo "
+<?xml version=\"1.0\" encoding=\"utf-8\"?>
+<response>
+<error>0</error>
+</response>
+       ";
+       exit;
+}
+
+function XMLerror($err = "Invalid request.") {
+       header("HTTP/1.0 400 Bad Request");
+       echo "
+<?xml version=\"1.0\" encoding=\"utf-8\"?>
+<response>
+<error>1</error>
+<message>Invalid request: $err</message>
+</response>
+";
+               exit;
+}
+
+if (!$wgUseTrackbacks)
+       XMLerror("Trackbacks are disabled.");
+
+if (   !isset($_POST['url'])
+    || !isset($_POST['blog_name'])
+    || !isset($_REQUEST['article']))
+       XMLerror("Required field not specified");
+
+$dbw =& wfGetDB(DB_MASTER);
+
+$tbtitle = $_POST['title'];
+$tbex = $_POST['excerpt'];
+$tburl = $_POST['url'];
+$tbname = $_POST['blog_name'];
+$tbarticle = $_REQUEST['article'];
+
+$title = Title::newFromText($tbarticle);
+if (!$title->exists())
+       XMLerror("Specified article does not exist.");
+
+$dbw->insert('trackbacks', array(
+       'tb_id' => $title->getArticleID(),
+       'tb_title' => $tbtitle,
+       'tb_url' => $tburl,
+       'tb_ex' => $tbex,
+       'tb_name' => $tbname
+));
+
+XMLsuccess();
+exit;