diff --git a/doku.php b/doku.php
index 56197db81d829964a2726351986572d6576529c6..113c2c7c2762044af6ad8620ab24501c39d7a9e6 100644
--- a/doku.php
+++ b/doku.php
@@ -11,6 +11,7 @@
   if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__)).'/');
   require_once(DOKU_INC.'inc/init.php');
   require_once(DOKU_INC.'inc/common.php');
+  require_once(DOKU_INC.'inc/pageutils.php');
   require_once(DOKU_INC.'inc/html.php');
   require_once(DOKU_INC.'inc/parser.php');
   require_once(DOKU_INC.'lang/en/lang.php');
diff --git a/fetch.php b/fetch.php
index b991f14ec3c16fc5a525a28181fd18a5d3e1e224..4f3381bbbdc634fc4c83336177598e567e106e3b 100644
--- a/fetch.php
+++ b/fetch.php
@@ -9,7 +9,8 @@
 	if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__)).'/');
 	require_once(DOKU_INC.'inc/init.php');
 	require_once(DOKU_INC.'inc/common.php');
-  require_once(DOKU_INC.'inc/utils.php');
+  require_once(DOKU_INC.'inc/pageutils.php');
+  require_once(DOKU_INC.'inc/confutils.php');
   require_once(DOKU_INC.'inc/auth.php');
   $mimetypes = getMimeTypes();
 
@@ -59,7 +60,6 @@
     exit;
   }
 
-
   //handle image resizing
   if((substr($MIME,0,5) == 'image') && $WIDTH){
     $FILE = get_resized($FILE,$EXT,$WIDTH,$HEIGHT);
@@ -93,6 +93,7 @@ function get_resized($file, $ext, $w, $h=0){
   $info  = getimagesize($file);
   if(!$h) $h = round(($w * $info[1]) / $info[0]);
 
+
   //cache
   $local = $conf['mediadir'].'/_cache/'.$md5.'.'.$w.'x'.$h.'.'.$ext;
   $mtime = @filemtime($local); // 0 if not exists
@@ -140,7 +141,7 @@ function get_from_URL($url,$ext,$cache){
 
   //  never cache     exists but no endless cache     not exists or expired
   if( $cache == 0 || ($mtime != 0 && $cache != -1) || $mtime < time()-$cache ){
-    if(download($url,$local)){
+    if(io_download($url,$local)){
       return $local;
     }else{
       return false;
@@ -167,7 +168,7 @@ function resize_image($ext,$from,$from_w,$from_h,$to,$to_w,$to_h){
   // create an image of the given filetype
   if ($ext == 'jpg' || $ext == 'jpeg'){
     if(!function_exists("imagecreatefromjpeg")) return false;
-    $image = @imagecreateFromjpeg($from);
+    $image = @imagecreatefromjpeg($from);
   }elseif($ext == 'png') {
     if(!function_exists("imagecreatefrompng")) return false;
     $image = @imagecreatefrompng($from);
diff --git a/inc/common.php b/inc/common.php
index 871196dd54db6e9b2cf50e4af76ab440b3dcbd03..9223b22e44b89f414c3ff306d4163b7f0eb86691 100644
--- a/inc/common.php
+++ b/inc/common.php
@@ -218,27 +218,6 @@ function script($script='doku.php'){
   return DOKU_BASE.DOKU_SCRIPT;
 }
 
-/**
- * Return namespacepart of a wiki ID
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- */
-function getNS($id){
- if(strpos($id,':')!==false){
-   return substr($id,0,strrpos($id,':'));
- }
- return false;
-}
-
-/**
- * Returns the ID without the namespace
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- */
-function noNS($id){
-  return preg_replace('/.*:/','',$id);
-}
-
 /**
  * Spamcheck against wordlist
  *
@@ -355,97 +334,6 @@ function unlock($id){
   return false;
 }
 
-/**
- * Remove unwanted chars from ID
- *
- * Cleans a given ID to only use allowed characters. Accented characters are
- * converted to unaccented ones
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- */
-function cleanID($id){
-  global $conf;
-  global $lang;
-  $id = trim($id);
-  $id = utf8_strtolower($id);
-
-  //alternative namespace seperator
-  $id = strtr($id,';',':');
-  if($conf['useslash']){
-    $id = strtr($id,'/',':');
-  }else{
-    $id = strtr($id,'/','_');
-  }
-
-  if($conf['deaccent']) $id = utf8_deaccent($id,-1);
-
-  //remove specials
-  $id = utf8_stripspecials($id,'_','_:.-');
-
-  //clean up
-  $id = preg_replace('#__#','_',$id);
-  $id = preg_replace('#:+#',':',$id);
-  $id = trim($id,':._-');
-  $id = preg_replace('#:[:\._\-]+#',':',$id);
-
-  return($id);
-}
-
-/**
- * returns the full path to the datafile specified by ID and
- * optional revision
- *
- * The filename is URL encoded to protect Unicode chars
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- */
-function wikiFN($id,$rev=''){
-  global $conf;
-  $id = cleanID($id);
-  $id = str_replace(':','/',$id);
-  if(empty($rev)){
-    $fn = $conf['datadir'].'/'.utf8_encodeFN($id).'.txt';
-  }else{
-    $fn = $conf['olddir'].'/'.utf8_encodeFN($id).'.'.$rev.'.txt';
-    if($conf['usegzip'] && !@file_exists($fn)){
-      //return gzip if enabled and plaintext doesn't exist
-      $fn .= '.gz';
-    }
-  }
-  return $fn;
-}
-
-/**
- * returns the full path to the mediafile specified by ID
- *
- * The filename is URL encoded to protect Unicode chars
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- */
-function mediaFN($id){
-  global $conf;
-  $id = cleanID($id);
-  $id = str_replace(':','/',$id);
-    $fn = $conf['mediadir'].'/'.utf8_encodeFN($id);
-  return $fn;
-}
-
-/**
- * Returns the full filepath to a localized textfile if local
- * version isn't found the english one is returned
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- */
-function localeFN($id){
-  global $conf;
-  $file = './lang/'.$conf['lang'].'/'.$id.'.txt';
-  if(!@file_exists($file)){
-    //fall back to english
-    $file = './lang/en/'.$id.'.txt';
-  }
-  return cleanText($file);
-}
-
 /**
  * convert line ending to unix format
  *
@@ -824,27 +712,6 @@ function getRevisions($id){
   return $revs;
 }
 
-/**
- * downloads a file from the net and saves it to the given location
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- */
-function download($url,$file){
-  $fp = @fopen($url,"rb");
-  if(!$fp) return false;
-
-  while(!feof($fp)){
-    $cont.= fread($fp,1024);
-  }
-  fclose($fp);
-
-  $fp2 = @fopen($file,"w");
-  if(!$fp2) return false;
-  fwrite($fp2,$cont);
-  fclose($fp2);
-  return true;
-} 
-
 /**
  * extracts the query from a google referer
  *
diff --git a/inc/utils.php b/inc/confutils.php
similarity index 100%
rename from inc/utils.php
rename to inc/confutils.php
diff --git a/inc/format.php b/inc/format.php
index 0be51c12d52c01e0a87abc20bc9b1f9fe9420507..d703d78ad2f9bc7a37dea78ae9111343c6183e57 100644
--- a/inc/format.php
+++ b/inc/format.php
@@ -4,6 +4,7 @@
  *
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  * @author     Andreas Gohr <andi@splitbrain.org>
+ * @deprecated part of the XHTML renderer
  */
 
   if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../').'/');
@@ -486,8 +487,8 @@ function img_cache(&$csrc,&$src,&$w,&$h,$cachemode){
   //download external images if allowed
   if($isurl && $isimg && $cachemode != 'nocache'){
     $cache = $conf['mediadir']."/_cache/$md5.$ext";
-    if ( ($cachemode == 'recache' && download($src,$cache)) ||
-         @file_exists($cache) || download($src,$cache)){
+    if ( ($cachemode == 'recache' && io_download($src,$cache)) ||
+         @file_exists($cache) || io_download($src,$cache)){
       $f['full']['web'] = $conf['mediaweb']."/_cache/$md5.$ext";
       $f['resz']['web'] = $conf['mediaweb']."/_cache/$md5.$ext";
       $f['full']['fs']  = $conf['mediadir']."/_cache/$md5.$ext";
diff --git a/inc/io.php b/inc/io.php
index 81247a59016a03ed255ae726e58fca4b785322ee..b0b834f9d7321a44948eb4e0cc9905271e6c48c0 100644
--- a/inc/io.php
+++ b/inc/io.php
@@ -200,6 +200,28 @@ function io_mkdir_ftp($dir){
   return $ok;
 }
 
+/**
+ * downloads a file from the net and saves it to the given location
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @todo   Add size limit
+ */
+function io_download($url,$file){
+  $fp = @fopen($url,"rb");
+  if(!$fp) return false;
+
+  while(!feof($fp)){
+    $cont.= fread($fp,1024);
+  }
+  fclose($fp);
+
+  $fp2 = @fopen($file,"w");
+  if(!$fp2) return false;
+  fwrite($fp2,$cont);
+  fclose($fp2);
+  return true;
+} 
+
 /**
  * Runs an external command and returns it's output as string
  *
diff --git a/inc/pageutils.php b/inc/pageutils.php
new file mode 100644
index 0000000000000000000000000000000000000000..367e53625bc9a71bebb11f32e6e919469fe77e45
--- /dev/null
+++ b/inc/pageutils.php
@@ -0,0 +1,200 @@
+<?php
+/**
+ * Utilities for handling pagenames
+ * 
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author     Andreas Gohr <andi@splitbrain.org>
+ */
+
+
+/**
+ * Remove unwanted chars from ID
+ *
+ * Cleans a given ID to only use allowed characters. Accented characters are
+ * converted to unaccented ones
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+function cleanID($id){
+  global $conf;
+  global $lang;
+  $id = trim($id);
+  $id = utf8_strtolower($id);
+
+  //alternative namespace seperator
+  $id = strtr($id,';',':');
+  if($conf['useslash']){
+    $id = strtr($id,'/',':');
+  }else{
+    $id = strtr($id,'/','_');
+  }
+
+  if($conf['deaccent']) $id = utf8_deaccent($id,-1);
+
+  //remove specials
+  $id = utf8_stripspecials($id,'_','_:.-');
+
+  //clean up
+  $id = preg_replace('#__#','_',$id);
+  $id = preg_replace('#:+#',':',$id);
+  $id = trim($id,':._-');
+  $id = preg_replace('#:[:\._\-]+#',':',$id);
+
+  return($id);
+}
+
+/**
+ * Return namespacepart of a wiki ID
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+function getNS($id){
+ if(strpos($id,':')!==false){
+   return substr($id,0,strrpos($id,':'));
+ }
+ return false;
+}
+
+/**
+ * Returns the ID without the namespace
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+function noNS($id){
+  return preg_replace('/.*:/','',$id);
+}
+
+/**
+ * returns the full path to the datafile specified by ID and
+ * optional revision
+ *
+ * The filename is URL encoded to protect Unicode chars
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+function wikiFN($id,$rev=''){
+  global $conf;
+  $id = cleanID($id);
+  $id = str_replace(':','/',$id);
+  if(empty($rev)){
+    $fn = $conf['datadir'].'/'.utf8_encodeFN($id).'.txt';
+  }else{
+    $fn = $conf['olddir'].'/'.utf8_encodeFN($id).'.'.$rev.'.txt';
+    if($conf['usegzip'] && !@file_exists($fn)){
+      //return gzip if enabled and plaintext doesn't exist
+      $fn .= '.gz';
+    }
+  }
+  return $fn;
+}
+
+/**
+ * returns the full path to the mediafile specified by ID
+ *
+ * The filename is URL encoded to protect Unicode chars
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+function mediaFN($id){
+  global $conf;
+  $id = cleanID($id);
+  $id = str_replace(':','/',$id);
+    $fn = $conf['mediadir'].'/'.utf8_encodeFN($id);
+  return $fn;
+}
+
+/**
+ * Returns the full filepath to a localized textfile if local
+ * version isn't found the english one is returned
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+function localeFN($id){
+  global $conf;
+  $file = './lang/'.$conf['lang'].'/'.$id.'.txt';
+  if(!@file_exists($file)){
+    //fall back to english
+    $file = './lang/en/'.$id.'.txt';
+  }
+  return $file;
+}
+
+/**
+ * Returns a full media id
+ *
+ * uses global $ID to resolve relative pages
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+function resolve_mediaid(&$page,&$exists){
+  global $ID;
+  global $conf;
+  $ns = getNS($ID);
+  //if links starts with . add current namespace
+  if($page{0} == '.'){
+    $page = $ns.':'.substr($page,1);
+  }
+
+  //if link contains no namespace. add current namespace (if any)
+  if($ns !== false && strpos($page,':') === false){
+    $page = $ns.':'.$page;
+  }
+
+  $page   = cleanID($page);
+  $file   = mediaFN($page);
+  $exists = @file_exists($file);
+}
+
+/**
+ * Returns a full page id
+ *
+ * uses global $ID to resolve relative pages
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+function resolve_pageid(&$page,&$exists){
+  global $ID;
+  global $conf;
+  $ns = getNS($ID);
+
+  //if links starts with . add current namespace
+  if($page{0} == '.'){
+    $page = $ns.':'.substr($page,1);
+  }
+
+  //if link contains no namespace. add current namespace (if any)
+  if($ns !== false && strpos($page,':') === false){
+    $page = $ns.':'.$page;
+  }
+
+  //keep hashlink if exists then clean both parts
+  list($page,$hash) = split('#',$page,2);
+  $page = cleanID($page);
+  $hash = cleanID($hash);
+
+  $file = wikiFN($page);
+
+  $exists = false;
+
+  //check alternative plural/nonplural form
+  if(!@file_exists($file)){
+    if( $conf['autoplural'] ){
+      if(substr($page,-1) == 's'){
+        $try = substr($page,0,-1);
+      }else{
+        $try = $page.'s';
+      }
+      if(@file_exists(wikiFN($try))){
+        $page   = $try;
+        $exists = true;
+      }
+    }
+  }else{
+    $exists = true;
+  }
+
+  //add hash if any
+  if(!empty($hash)) $page.'#'.$hash;
+}
+
+//Setup VIM: ex: et ts=2 enc=utf-8 :
diff --git a/inc/parser.php b/inc/parser.php
index c9d7b2220efeda6917ff717b6aeee2ccb083c755..4854ac0fbe825d2091bf3cc4b3682ceda445136d 100644
--- a/inc/parser.php
+++ b/inc/parser.php
@@ -4,6 +4,7 @@
  *
  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  * @author     Andreas Gohr <andi@splitbrain.org>
+ * @deprecated replaced by the new parser
  */
 
   if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../').'/');
diff --git a/inc/parser/action.php b/inc/parser/action.php
index 3935bbeaef21f3dc7ce445d2b192574d1939a2fb..4426c1ac59c278ba6f74f4a20f9669e829b80e9a 100644
--- a/inc/parser/action.php
+++ b/inc/parser/action.php
@@ -7,8 +7,14 @@
 
 if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
 
-require_once(DOKU_INC.'inc/utils.php');
+require_once(DOKU_INC.'inc/confutils.php');
 
+/**
+ * turns a page into a list of instructions
+ *
+ * @author Harry Fuecks <hfuecks@gmail.com>
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
 function parse_to_instructions($text){
   global $conf;
 
@@ -46,7 +52,6 @@ function parse_to_instructions($text){
   $Parser->addMode('file',new Doku_Parser_Mode_File());
   $Parser->addMode('quote',new Doku_Parser_Mode_Quote());
   
-  // FIXME These need data files...
   $Parser->addMode('smiley',new Doku_Parser_Mode_Smiley(array_keys(getSmileys())));
   $Parser->addMode('acronym',new Doku_Parser_Mode_Acronym(array_keys(getAcronyms())));
   #$Parser->addMode('wordblock',new Doku_Parser_Mode_Wordblock(getBadWords()));
@@ -60,6 +65,7 @@ function parse_to_instructions($text){
   }
 
   $Parser->addMode('internallink',new Doku_Parser_Mode_InternalLink());
+  $Parser->addMode('rss',new Doku_Parser_Mode_RSS());
   $Parser->addMode('media',new Doku_Parser_Mode_Media());
   $Parser->addMode('externallink',new Doku_Parser_Mode_ExternalLink());
   $Parser->addMode('email',new Doku_Parser_Mode_Email());
@@ -71,6 +77,12 @@ function parse_to_instructions($text){
   return $Parser->parse($text);
 }  
 
+/**
+ * Renders a list of instruction to XHTML
+ *
+ * @author Harry Fuecks <hfuecks@gmail.com>
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
 function render_as_xhtml($instructions){
 
 #dbg($instructions);
@@ -79,7 +91,6 @@ function render_as_xhtml($instructions){
   require_once DOKU_INC . 'inc/parser/xhtml.php';
   $Renderer = & new Doku_Renderer_XHTML();
 
-  //FIXME add data
   $Renderer->smileys = getSmileys();
   $Renderer->entities = getEntities();
   $Renderer->acronyms = getAcronyms();
@@ -95,80 +106,4 @@ function render_as_xhtml($instructions){
   return $Renderer->doc;
 }
 
-/**
- * Returns a full media id
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- * @todo move to utils? 
- */
-function resolve_mediaid(&$page,&$exists){
-  global $ID;
-  global $conf;
-  $ns = getNS($ID);
-  //if links starts with . add current namespace
-  if($page{0} == '.'){
-    $page = $ns.':'.substr($page,1);
-  }
-
-  //if link contains no namespace. add current namespace (if any)
-  if($ns !== false && strpos($page,':') === false){
-    $page = $ns.':'.$page;
-  }
-
-  $page   = cleanID($page);
-  $file   = mediaFN($page);
-  $exists = @file_exists($file);
-}
-
-/**
- * Returns a full page id
- *
- * @todo move to utils? 
- */
-function resolve_pageid(&$page,&$exists){
-  global $ID;
-  global $conf;
-  $ns = getNS($ID);
-
-  //if links starts with . add current namespace
-  if($page{0} == '.'){
-    $page = $ns.':'.substr($page,1);
-  }
-
-  //if link contains no namespace. add current namespace (if any)
-  if($ns !== false && strpos($page,':') === false){
-    $page = $ns.':'.$page;
-  }
-
-  //keep hashlink if exists then clean both parts
-  list($page,$hash) = split('#',$page,2);
-  $page = cleanID($page);
-  $hash = cleanID($hash);
-
-  $file = wikiFN($page);
-
-  $exists = false;
-
-  //check alternative plural/nonplural form
-  if(!@file_exists($file)){
-    if( $conf['autoplural'] ){
-      if(substr($page,-1) == 's'){
-        $try = substr($page,0,-1);
-      }else{
-        $try = $page.'s';
-      }
-      if(@file_exists(wikiFN($try))){
-        $page   = $try;
-        $exists = true;
-      }
-    }
-  }else{
-    $exists = true;
-  }
-
-  //add hash if any
-  if(!empty($hash)) $page.'#'.$hash;
-}
-
-
 //Setup VIM: ex: et ts=2 enc=utf-8 :
diff --git a/inc/parser/handler.php b/inc/parser/handler.php
index 108a522a5154c98cbfc04b37d44c8c05985ed38c..f36a4f151b5614661a11e770a6f26eef076206d8 100644
--- a/inc/parser/handler.php
+++ b/inc/parser/handler.php
@@ -357,12 +357,7 @@ class Doku_Handler {
         
         // If the title is an image, convert it to an array containing the image details
         } else if ( preg_match('/^\{\{[^\}]+\}\}$/',$link[1]) ) {
-            $media = Doku_Handler_Parse_Media($link[1]);
-            
-            // Check it's really an image, not a link to a file
-            if ( !strpos($media['type'], 'link') ) {
-                $link[1] = $media;
-            }
+            $link[1] = Doku_Handler_Parse_Media($link[1]);
         }
 
         //decide which kind of link it is
@@ -421,18 +416,18 @@ class Doku_Handler {
     function media($match, $state, $pos) {
         $p = Doku_Handler_Parse_Media($match);
         
-        // If it's not an image, build a normal link
-        if ( strpos($p['type'], 'link') ) {
-            $this->__addCall($p['type'],array($p['src'], $p['title']), $pos);
-        } else {
-            $this->__addCall(
-                $p['type'],
-                array($p['src'], $p['title'], $p['align'], $p['width'], $p['height'], $p['cache']),
-                $pos
-                );
-        }
+        $this->__addCall(
+              $p['type'],
+              array($p['src'], $p['title'], $p['align'], $p['width'], $p['height'], $p['cache']),
+              $pos
+             );
         return TRUE;
     }
+
+    function rss($match, $state, $pos) {
+        $link = preg_replace(array('/^\{\{rss>/','/\}\}$/'),'',$match);
+        $this->__addCall('rss',array($link),$pos);
+    }
     
     function externallink($match, $state, $pos) {
         // Prevent use of multibyte strings in URLs
diff --git a/inc/parser/parser.php b/inc/parser/parser.php
index d1d039ad747dfe9880681fb3986735d7004413d3..7e122bffcecb02117a4a10d7e083a11fc2691f94 100644
--- a/inc/parser/parser.php
+++ b/inc/parser/parser.php
@@ -659,6 +659,15 @@ class Doku_Parser_Mode_Media extends Doku_Parser_Mode {
     
 }
 
+//-------------------------------------------------------------------
+class Doku_Parser_Mode_RSS extends Doku_Parser_Mode {
+
+    function connectTo($mode) {
+        $this->Lexer->addSpecialPattern("\{\{rss>[^\}]+\}\}",$mode,'rss');
+    }
+
+}
+
 //-------------------------------------------------------------------
 class Doku_Parser_Mode_ExternalLink extends Doku_Parser_Mode {    
     var $schemes = array('http','https','telnet','gopher','wais','ftp','ed2k','irc');
@@ -801,7 +810,7 @@ function Doku_Parser_Substition() {
         'acronym','smiley','wordblock','entity','camelcaselink',
         'internallink','media','externallink','linebreak','email',
         'windowssharelink','filelink','notoc','multiplyentity',
-        'quotes',
+        'quotes','rss'
         
     );
     return $modes;
@@ -826,4 +835,4 @@ function Doku_Parser_Disabled() {
 }
 
 
-//Setup VIM: ex: et ts=2 enc=utf-8 :
+//Setup VIM: ex: et ts=4 enc=utf-8 :
diff --git a/inc/parser/xhtml.php b/inc/parser/xhtml.php
index 377b514be7ab5104935af16076b91116002b7ace..83d498b473f71f0477933cf278adb63758fb05e8 100644
--- a/inc/parser/xhtml.php
+++ b/inc/parser/xhtml.php
@@ -1,4 +1,11 @@
 <?php
+/**
+ * Renderer for XHTML output
+ *
+ * @author Harry Fuecks <hfuecks@gmail.com>
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+
 if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
 
 if ( !defined('DOKU_LF') ) {
@@ -14,8 +21,8 @@ if ( !defined('DOKU_TAB') ) {
 require_once DOKU_INC . 'inc/parser/renderer.php';
 
 /**
-* @TODO Probably useful for have constant for linefeed formatting
-*/
+ * The Renderer 
+ */
 class Doku_Renderer_XHTML extends Doku_Renderer {
 
     var $doc = '';
@@ -381,10 +388,6 @@ class Doku_Renderer_XHTML extends Doku_Renderer {
       $this->internallink($link,$link); 
     }
     
-    /**
-    * @TODO Support media
-    * @TODO correct attributes
-    */
     function internallink($id, $name = NULL) {
         global $conf;
 
@@ -416,37 +419,38 @@ class Doku_Renderer_XHTML extends Doku_Renderer {
         echo $this->__formatLink($link);
     }
     
-    
-    /**
-    * @TODO Should list assume blacklist check already made?
-    * @TODO External link icon
-    * @TODO correct attributes
-    */
-    function externallink($link, $title = NULL) {
-        
-        echo '<a';
-        
-        $title = $this->__getLinkTitle($title, $link, $isImage);
+    function externallink($url, $name = NULL) {
+        global $conf;
+
+        $name = $this->__getLinkTitle($name, $url, $isImage);
         
         if ( !$isImage ) {
-            echo ' class="urlextern"';
+            $class='urlextern';
         } else {
-            echo ' class="media"';
+            $class='media';
         }
         
-        echo ' target="_blank" href="'.$this->__xmlEntities($link).'"';
-        
-        echo ' onclick="return svchk()" onkeypress="return svchk()">';
-        
-        echo $title;
-        
-        echo '</a>';
+        //prepare for formating
+        $link['target'] = $conf['target']['extern'];
+        $link['style']  = '';
+        $link['pre']    = '';
+        $link['suf']    = '';
+        $link['more']   = 'onclick="return svchk()" onkeypress="return svchk()"';
+        $link['class']  = $class;
+        $link['url']    = $url;
+        $link['name']   = $name;
+        $link['title']  = $this->__xmlEntities($url);
+        if($conf['relnofollow']) $link['more'] .= ' rel="nofollow"';
+
+        //output formatted
+        echo $this->__formatLink($link);
     }
     
     /**
     * @TODO Remove hard coded link to splitbrain.org on style
     */
     function interwikilink($link, $title = NULL, $wikiName, $wikiUri) {
+        global $conf;
         
         // RESOLVE THE URL
         if ( isset($this->interwiki[$wikiName]) ) {
@@ -614,11 +618,45 @@ class Doku_Renderer_XHTML extends Doku_Renderer {
                                            'link'   => $link ));
     }
 
+    /**
+     * Renders an RSS feed using magpie
+     * 
+     * @author Andreas Gohr <andi@splitbrain.org>
+     */
+    function rss ($url){
+        global $lang;
+        define('MAGPIE_CACHE_ON', false); //we do our own caching
+        define('MAGPIE_DIR', DOKU_INC.'inc/magpie/');
+        define('MAGPIE_OUTPUT_ENCODING','UTF-8'); //return all feeds as UTF-8
+        require_once(MAGPIE_DIR.'/rss_fetch.inc');
+
+        //disable warning while fetching
+        $elvl = error_reporting(E_ERROR);
+        $rss  = fetch_rss($url);
+        error_reporting($elvl);
+
+        print '<ul class="rss">';
+        if($rss){
+            foreach ($rss->items as $item ) {
+                print '<li>';
+                $this->externallink($item['link'],$item['title']);
+                print '</li>';
+            }
+        }else{
+            print '<li>';
+            print '<em>'.$lang['rssfailed'].'</em>';
+            $this->externallink($url);
+            print '</li>';
+        }
+        print '</ul>';
+    }
+
     /**
      * Renders internal and external media
      * 
      * @author Andreas Gohr <andi@splitbrain.org>
      * @todo   handle center align
+     * @todo   move to bottom
      */
     function __media ($src, $title=NULL, $align=NULL, $width=NULL,
                       $height=NULL, $cache=NULL) {
@@ -629,9 +667,8 @@ class Doku_Renderer_XHTML extends Doku_Renderer {
         if(substr($mime,0,5) == 'image'){
             //add image tag
             $ret .= '<img class="media" src="'.
-                    DOKU_BASE.'fetch.php?media='.urlencode($src).
-                    '&amp;w='.$width.'&amp;h='.$height.
-                    '&amp;cache='.$cache.'"';
+                    DOKU_BASE.'fetch.php?w='.$width.'&amp;h='.$height.
+                    '&amp;cache='.$cache.'&amp;media='.urlencode($src).'"';
         
             if (!is_null($title))
                 $ret .= ' title="'.$this->__xmlEntities($title).'"';