diff --git a/conf/dokuwiki.php b/conf/dokuwiki.php
index 54243102986a8d68003ac6f27834c5a89ceb0124..972c4f57e6a1316357fcdfe80f97b5398b34922a 100644
--- a/conf/dokuwiki.php
+++ b/conf/dokuwiki.php
@@ -1,6 +1,10 @@
 <?php
 /**
  * This is DokuWiki's Main Configuration file
+ *
+ * All the default values are kept here, you should not modify it but use
+ * a local.conf.php file instaed to override the settings from here.
+ *
  * This is a piece of PHP code so PHP syntax applies!
  *
  * For help with the configuration see http://www.splitbrain.org/dokuwiki/wiki:config
@@ -62,6 +66,7 @@ $conf['profileconfirm'] = '1';           //Require current password to confirm c
 $conf['disableactions'] = '';            //comma separated list of actions to disable
 
 /* Advanced Options */
+$conf['updatecheck'] = 1;                //automatically check for new releases?
 $conf['userewrite']  = 0;                //this makes nice URLs: 0: off 1: .htaccess 2: internal
 $conf['useslash']    = 0;                //use slash instead of colon? only when rewrite is on
 $conf['usedraft']    = 1;                //automatically save a draft while editing (0|1)
diff --git a/doku.php b/doku.php
index d2be871b2092ee064006a46db9ff459eb4eb0b74..48ac566828128ac4219c08e4163ecd4f291c06e6 100644
--- a/doku.php
+++ b/doku.php
@@ -63,6 +63,9 @@
   //prepare breadcrumbs (initialize a static var)
   breadcrumbs();
 
+  // check upstream
+  checkUpdateMessages();
+
   trigger_event('DOKUWIKI_STARTED',$tmp=array());
 
   //close session
diff --git a/inc/common.php b/inc/common.php
index 016c7922daad010f06742630ee48e967dc08dc42..271446f554681d99db7352197768ef778901bd65 100644
--- a/inc/common.php
+++ b/inc/common.php
@@ -6,13 +6,14 @@
  * @author     Andreas Gohr <andi@splitbrain.org>
  */
 
-  if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../').'/');
-  require_once(DOKU_CONF.'dokuwiki.php');
-  require_once(DOKU_INC.'inc/io.php');
-  require_once(DOKU_INC.'inc/changelog.php');
-  require_once(DOKU_INC.'inc/utf8.php');
-  require_once(DOKU_INC.'inc/mail.php');
-  require_once(DOKU_INC.'inc/parserutils.php');
+if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../').'/');
+require_once(DOKU_CONF.'dokuwiki.php');
+require_once(DOKU_INC.'inc/io.php');
+require_once(DOKU_INC.'inc/changelog.php');
+require_once(DOKU_INC.'inc/utf8.php');
+require_once(DOKU_INC.'inc/mail.php');
+require_once(DOKU_INC.'inc/parserutils.php');
+require_once(DOKU_INC.'inc/infoutils.php');
 
 /**
  * These constants are used with the recents function
@@ -168,45 +169,6 @@ function buildAttributes($params){
 }
 
 
-/**
- * print a message
- *
- * If HTTP headers were not sent yet the message is added
- * to the global message array else it's printed directly
- * using html_msgarea()
- *
- *
- * Levels can be:
- *
- * -1 error
- *  0 info
- *  1 success
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- * @see    html_msgarea
- */
-function msg($message,$lvl=0,$line='',$file=''){
-  global $MSG;
-  $errors[-1] = 'error';
-  $errors[0]  = 'info';
-  $errors[1]  = 'success';
-
-  if($line || $file) $message.=' ['.basename($file).':'.$line.']';
-
-  if(!headers_sent()){
-    if(!isset($MSG)) $MSG = array();
-    $MSG[]=array('lvl' => $errors[$lvl], 'msg' => $message);
-  }else{
-    $MSG = array();
-    $MSG[]=array('lvl' => $errors[$lvl], 'msg' => $message);
-    if(function_exists('html_msgarea')){
-      html_msgarea();
-    }else{
-      print "ERROR($lvl) $message";
-    }
-  }
-}
-
 /**
  * This builds the breadcrumb trail and returns it as array
  *
@@ -695,34 +657,6 @@ function con($pre,$text,$suf,$pretty=false){
   return $pre.$text.$suf;
 }
 
-/**
- * print debug messages
- *
- * little function to print the content of a var
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- */
-function dbg($msg,$hidden=false){
-  (!$hidden) ? print '<pre class="dbg">' : print "<!--\n";
-  print_r($msg);
-  (!$hidden) ? print '</pre>' : print "\n-->";
-}
-
-/**
- * Print info to a log file
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- */
-function dbglog($msg){
-  global $conf;
-  $file = $conf['cachedir'].'/debug.log';
-  $fh = fopen($file,'a');
-  if($fh){
-    fwrite($fh,date('H:i:s ').$_SERVER['REMOTE_ADDR'].': '.$msg."\n");
-    fclose($fh);
-  }
-}
-
 /**
  * Saves a wikitext by calling io_writeWikiPage
  *
@@ -968,142 +902,6 @@ function obfuscate($email) {
   }
 }
 
-/**
- * Return DokuWikis version
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- */
-function getVersion(){
-  //import version string
-  if(@file_exists('VERSION')){
-    //official release
-    return 'Release '.trim(io_readfile(DOKU_INC.'/VERSION'));
-  }elseif(is_dir('_darcs')){
-    //darcs checkout - read last 2000 bytes of inventory
-    $sz   = filesize('_darcs/inventory');
-    $seek = max(0,$sz-2000);
-    $fh   = fopen('_darcs/inventory','rb');
-    fseek($fh,$seek);
-    $chunk = fread($fh,2000);
-    fclose($fh);
-    $inv = preg_grep('#\*\*\d{14}[\]$]#',explode("\n",$chunk));
-    $cur = array_pop($inv);
-    preg_match('#\*\*(\d{4})(\d{2})(\d{2})#',$cur,$matches);
-    return 'Darcs '.$matches[1].'-'.$matches[2].'-'.$matches[3];
-  }else{
-    return 'snapshot?';
-  }
-}
-
-/**
- * Run a few sanity checks
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- */
-function check(){
-  global $conf;
-  global $INFO;
-
-  msg('DokuWiki version: '.getVersion(),1);
-
-  if(version_compare(phpversion(),'4.3.0','<')){
-    msg('Your PHP version is too old ('.phpversion().' vs. 4.3.+ recommended)',-1);
-  }elseif(version_compare(phpversion(),'4.3.10','<')){
-    msg('Consider upgrading PHP to 4.3.10 or higher for security reasons (your version: '.phpversion().')',0);
-  }else{
-    msg('PHP version '.phpversion(),1);
-  }
-
-  if(is_writable($conf['changelog'])){
-    msg('Changelog is writable',1);
-  }else{
-    if (@file_exists($conf['changelog'])) {
-      msg('Changelog is not writable',-1);
-    }
-  }
-
-  if (isset($conf['changelog_old']) && @file_exists($conf['changelog_old'])) {
-    msg('Old changelog exists.', 0);
-  }
-
-  if (@file_exists($conf['changelog'].'_failed')) {
-    msg('Importing old changelog failed.', -1);
-  } else if (@file_exists($conf['changelog'].'_importing')) {
-    msg('Importing old changelog now.', 0);
-  } else if (@file_exists($conf['changelog'].'_import_ok')) {
-    msg('Old changelog imported.', 1);
-    if (!plugin_isdisabled('importoldchangelog')) {
-      msg('Importoldchangelog plugin not disabled after import.', -1);
-    }
-  }
-
-  if(is_writable($conf['datadir'])){
-    msg('Datadir is writable',1);
-  }else{
-    msg('Datadir is not writable',-1);
-  }
-
-  if(is_writable($conf['olddir'])){
-    msg('Attic is writable',1);
-  }else{
-    msg('Attic is not writable',-1);
-  }
-
-  if(is_writable($conf['mediadir'])){
-    msg('Mediadir is writable',1);
-  }else{
-    msg('Mediadir is not writable',-1);
-  }
-
-  if(is_writable($conf['cachedir'])){
-    msg('Cachedir is writable',1);
-  }else{
-    msg('Cachedir is not writable',-1);
-  }
-
-  if(is_writable($conf['lockdir'])){
-    msg('Lockdir is writable',1);
-  }else{
-    msg('Lockdir is not writable',-1);
-  }
-
-  if(is_writable(DOKU_CONF.'users.auth.php')){
-    msg('conf/users.auth.php is writable',1);
-  }else{
-    msg('conf/users.auth.php is not writable',0);
-  }
-
-  if(function_exists('mb_strpos')){
-    if(defined('UTF8_NOMBSTRING')){
-      msg('mb_string extension is available but will not be used',0);
-    }else{
-      msg('mb_string extension is available and will be used',1);
-    }
-  }else{
-    msg('mb_string extension not available - PHP only replacements will be used',0);
-  }
-
-  if($conf['allowdebug']){
-    msg('Debugging support is enabled. If you don\'t need it you should set $conf[\'allowdebug\'] = 0',-1);
-  }else{
-    msg('Debugging support is disabled',1);
-  }
-
-  msg('Your current permission for this page is '.$INFO['perm'],0);
-
-  if(is_writable($INFO['filepath'])){
-    msg('The current page is writable by the webserver',0);
-  }else{
-    msg('The current page is not writable by the webserver',0);
-  }
-
-  if($INFO['writable']){
-    msg('The current page is writable by you',0);
-  }else{
-    msg('The current page is not writable you',0);
-  }
-}
-
 /**
  * Let us know if a user is tracking a page
  *
diff --git a/inc/infoutils.php b/inc/infoutils.php
new file mode 100644
index 0000000000000000000000000000000000000000..fcaba23cf996497ae2acfea5029298766a1cb89b
--- /dev/null
+++ b/inc/infoutils.php
@@ -0,0 +1,250 @@
+<?php
+/**
+ * Information and debugging functions
+ *
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author     Andreas Gohr <andi@splitbrain.org>
+ */
+if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../').'/');
+if(!defined('DOKU_MESSAGEURL')) define('DOKU_MESSAGEURL','http://www.splitbrain.org/lib/exe/msg.php?msg=');
+require_once(DOKU_INC.'inc/HTTPClient.php');
+
+/**
+ * Check for new messages from upstream
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+function checkUpdateMessages(){
+    global $conf;
+    global $INFO;
+    if(!$conf['updatecheck']) return;
+    if($INFO['perm'] < AUTH_ADMIN) return;
+
+    $cf = $conf['cachedir'].'/messages.txt';
+    $lm = @filemtime($cf);
+
+    // check if new messages needs to be fetched
+    if($lm < time()-(60*60*24) || $lm < @filemtime(DOKU_CONF.'msg')){
+        $num = file(DOKU_CONF.'msg');
+        $num = (int) $num[0];
+        $http = new DokuHTTPClient();
+        $http->timeout = 8;
+        $data = $http->get(DOKU_MESSAGEURL.$num);
+        io_saveFile($cf,$data);
+    }else{
+        $data = io_readFile($cf);
+    }
+
+    // show messages through the usual message mechanism
+    $msgs = explode("\n%\n",$data);
+    foreach($msgs as $msg){
+        if($msg) msg($msg,2);
+    }
+}
+
+
+/**
+ * Return DokuWikis version
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+function getVersion(){
+  //import version string
+  if(@file_exists('VERSION')){
+    //official release
+    return 'Release '.trim(io_readfile(DOKU_INC.'/VERSION'));
+  }elseif(is_dir('_darcs')){
+    //darcs checkout - read last 2000 bytes of inventory
+    $sz   = filesize('_darcs/inventory');
+    $seek = max(0,$sz-2000);
+    $fh   = fopen('_darcs/inventory','rb');
+    fseek($fh,$seek);
+    $chunk = fread($fh,2000);
+    fclose($fh);
+    $inv = preg_grep('#\*\*\d{14}[\]$]#',explode("\n",$chunk));
+    $cur = array_pop($inv);
+    preg_match('#\*\*(\d{4})(\d{2})(\d{2})#',$cur,$matches);
+    return 'Darcs '.$matches[1].'-'.$matches[2].'-'.$matches[3];
+  }else{
+    return 'snapshot?';
+  }
+}
+
+/**
+ * Run a few sanity checks
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+function check(){
+  global $conf;
+  global $INFO;
+
+  msg('DokuWiki version: '.getVersion(),1);
+
+  if(version_compare(phpversion(),'4.3.0','<')){
+    msg('Your PHP version is too old ('.phpversion().' vs. 4.3.+ recommended)',-1);
+  }elseif(version_compare(phpversion(),'4.3.10','<')){
+    msg('Consider upgrading PHP to 4.3.10 or higher for security reasons (your version: '.phpversion().')',0);
+  }else{
+    msg('PHP version '.phpversion(),1);
+  }
+
+  if(is_writable($conf['changelog'])){
+    msg('Changelog is writable',1);
+  }else{
+    if (@file_exists($conf['changelog'])) {
+      msg('Changelog is not writable',-1);
+    }
+  }
+
+  if (isset($conf['changelog_old']) && @file_exists($conf['changelog_old'])) {
+    msg('Old changelog exists.', 0);
+  }
+
+  if (@file_exists($conf['changelog'].'_failed')) {
+    msg('Importing old changelog failed.', -1);
+  } else if (@file_exists($conf['changelog'].'_importing')) {
+    msg('Importing old changelog now.', 0);
+  } else if (@file_exists($conf['changelog'].'_import_ok')) {
+    msg('Old changelog imported.', 1);
+    if (!plugin_isdisabled('importoldchangelog')) {
+      msg('Importoldchangelog plugin not disabled after import.', -1);
+    }
+  }
+
+  if(is_writable($conf['datadir'])){
+    msg('Datadir is writable',1);
+  }else{
+    msg('Datadir is not writable',-1);
+  }
+
+  if(is_writable($conf['olddir'])){
+    msg('Attic is writable',1);
+  }else{
+    msg('Attic is not writable',-1);
+  }
+
+  if(is_writable($conf['mediadir'])){
+    msg('Mediadir is writable',1);
+  }else{
+    msg('Mediadir is not writable',-1);
+  }
+
+  if(is_writable($conf['cachedir'])){
+    msg('Cachedir is writable',1);
+  }else{
+    msg('Cachedir is not writable',-1);
+  }
+
+  if(is_writable($conf['lockdir'])){
+    msg('Lockdir is writable',1);
+  }else{
+    msg('Lockdir is not writable',-1);
+  }
+
+  if(is_writable(DOKU_CONF.'users.auth.php')){
+    msg('conf/users.auth.php is writable',1);
+  }else{
+    msg('conf/users.auth.php is not writable',0);
+  }
+
+  if(function_exists('mb_strpos')){
+    if(defined('UTF8_NOMBSTRING')){
+      msg('mb_string extension is available but will not be used',0);
+    }else{
+      msg('mb_string extension is available and will be used',1);
+    }
+  }else{
+    msg('mb_string extension not available - PHP only replacements will be used',0);
+  }
+
+  if($conf['allowdebug']){
+    msg('Debugging support is enabled. If you don\'t need it you should set $conf[\'allowdebug\'] = 0',-1);
+  }else{
+    msg('Debugging support is disabled',1);
+  }
+
+  msg('Your current permission for this page is '.$INFO['perm'],0);
+
+  if(is_writable($INFO['filepath'])){
+    msg('The current page is writable by the webserver',0);
+  }else{
+    msg('The current page is not writable by the webserver',0);
+  }
+
+  if($INFO['writable']){
+    msg('The current page is writable by you',0);
+  }else{
+    msg('The current page is not writable you',0);
+  }
+}
+
+/**
+ * print a message
+ *
+ * If HTTP headers were not sent yet the message is added
+ * to the global message array else it's printed directly
+ * using html_msgarea()
+ *
+ *
+ * Levels can be:
+ *
+ * -1 error
+ *  0 info
+ *  1 success
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @see    html_msgarea
+ */
+function msg($message,$lvl=0,$line='',$file=''){
+  global $MSG;
+  $errors[-1] = 'error';
+  $errors[0]  = 'info';
+  $errors[1]  = 'success';
+  $errors[2]  = 'notify';
+
+  if($line || $file) $message.=' ['.basename($file).':'.$line.']';
+
+  if(!headers_sent()){
+    if(!isset($MSG)) $MSG = array();
+    $MSG[]=array('lvl' => $errors[$lvl], 'msg' => $message);
+  }else{
+    $MSG = array();
+    $MSG[]=array('lvl' => $errors[$lvl], 'msg' => $message);
+    if(function_exists('html_msgarea')){
+      html_msgarea();
+    }else{
+      print "ERROR($lvl) $message";
+    }
+  }
+}
+
+/**
+ * print debug messages
+ *
+ * little function to print the content of a var
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+function dbg($msg,$hidden=false){
+  (!$hidden) ? print '<pre class="dbg">' : print "<!--\n";
+  print_r($msg);
+  (!$hidden) ? print '</pre>' : print "\n-->";
+}
+
+/**
+ * Print info to a log file
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+function dbglog($msg){
+  global $conf;
+  $file = $conf['cachedir'].'/debug.log';
+  $fh = fopen($file,'a');
+  if($fh){
+    fwrite($fh,date('H:i:s ').$_SERVER['REMOTE_ADDR'].': '.$msg."\n");
+    fclose($fh);
+  }
+}
+
+
diff --git a/lib/images/notify.png b/lib/images/notify.png
new file mode 100644
index 0000000000000000000000000000000000000000..6e0015df4f737ded7e7e14b546616e704f023226
Binary files /dev/null and b/lib/images/notify.png differ
diff --git a/lib/plugins/config/lang/en/lang.php b/lib/plugins/config/lang/en/lang.php
index d92e930f2898bdf765614652007de1fc41524360..db8c270b957896a4b19068bebec6d3e658ac9f32 100644
--- a/lib/plugins/config/lang/en/lang.php
+++ b/lib/plugins/config/lang/en/lang.php
@@ -96,6 +96,7 @@ $lang['disableactions_wikicode'] = 'View source/Export Raw';
 $lang['disableactions_other'] = 'Other actions (comma separated)';
 
 /* Advanced Options */
+$lang['updatecheck'] = 'Check for updates and security warnings? DokuWiki needs to contact splitbrain.org for this feature.';
 $lang['userewrite']  = 'Use nice URLs';
 $lang['useslash']    = 'Use slash as namespace separator in URLs';
 $lang['usedraft']    = 'Automatically save a draft while editing';
diff --git a/lib/plugins/config/settings/config.metadata.php b/lib/plugins/config/settings/config.metadata.php
index b55c0e930f5aecf784e283d21a0e03fdd8ab6e03..09d3736f34ce3c41883b7b8e1dc81bef9991578f 100644
--- a/lib/plugins/config/settings/config.metadata.php
+++ b/lib/plugins/config/settings/config.metadata.php
@@ -147,6 +147,7 @@ $meta['jpg_quality'] = array('numeric','_pattern' => '/^100$|^[1-9]?[0-9]$/');
 $meta['fetchsize']   = array('numeric');
 
 $meta['_advanced']   = array('fieldset');
+$meta['updatecheck'] = array('onoff');
 $meta['userewrite']  = array('multichoice','_choices' => array(0,1,2));
 $meta['useslash']    = array('onoff');
 $meta['sepchar']     = array('sepchar');
diff --git a/lib/styles/style.css b/lib/styles/style.css
index cb39516c49f5481561591ed931f7f2c75adf2acd..209e5654c1c4e26a5e8da090c29bd37cbf8f7f73 100644
--- a/lib/styles/style.css
+++ b/lib/styles/style.css
@@ -46,6 +46,17 @@ div.success {
   overflow: hidden;
 }
 
+div.notify {
+  background: #ffc url(../images/notify.png) 0.5em 0px no-repeat;
+  color: #000;
+  border-bottom: 1px solid #ffa;
+  font-size: 90%;
+  margin: 0;
+  padding-left: 3em;
+  overflow: hidden;
+}
+
+
 /* image alignment */
 .medialeft {
   float: left;