From c29dc6e4219a920b505ef667b82d4f601b34e52b Mon Sep 17 00:00:00 2001
From: Andreas Gohr <andi@splitbrain.org>
Date: Sat, 16 Sep 2006 23:02:29 +0200
Subject: [PATCH] updatecheck feature

This patch adds a feature to let DokuWiki automatically check if updates are
available or any other important messages (like security warnings) and then
display this info to the admin user.

DokuWiki will contact the URL http://www.splitbrain.org/lib/exe/msg.php
with a parameter telling it which messages it already know (read from
conf/msg) - the server side script then will return all new messages.

The messages will be displayed until DokuWiki was upgraded or conf/msg
was updated manually. Messages are cached and only checked once a day.

The messenger URL will probably change before the next release.

darcs-hash:20060916210229-7ad00-7ac592650e171ae4144b0eb47a751a4ca480f031.gz
---
 conf/dokuwiki.php                             |   5 +
 doku.php                                      |   3 +
 inc/common.php                                | 218 +--------------
 inc/infoutils.php                             | 250 ++++++++++++++++++
 lib/images/notify.png                         | Bin 0 -> 789 bytes
 lib/plugins/config/lang/en/lang.php           |   1 +
 .../config/settings/config.metadata.php       |   1 +
 lib/styles/style.css                          |  11 +
 8 files changed, 279 insertions(+), 210 deletions(-)
 create mode 100644 inc/infoutils.php
 create mode 100644 lib/images/notify.png

diff --git a/conf/dokuwiki.php b/conf/dokuwiki.php
index 542431029..972c4f57e 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 d2be871b2..48ac56682 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 016c7922d..271446f55 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 000000000..fcaba23cf
--- /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
GIT binary patch
literal 789
zcmV+w1M2*VP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00004XF*Lt006JZ
zHwB960000PbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU!r%6OXR5;6(
zl3PgAVHn1Ru7ZMY3W6PN`&(`;PpO4Pnzgcvps0-SLV~CZBQZ$DvSvkiDo3UXOG$Ak
zo0B=`)D7u0W)n4!n>w3Y+732PG_{dW-vWnGW?ek+eegcN?|t9z2?7xGKN@MGRD*J^
z&rlky@ZUE!D5>oxB^64H+e}Jso>dhAcXJ|I^4Pu&0hSi(IWgLX71SJg^}9{IANt4a
z6@3vO@*Gyvx&UJ2j;g6eXHOcITv{wUTQS>}4p&n=2Fk;r%w^@S*8a(S*4l9Z?xB2q
zbEz@ceIA}S32-WSa5Toip*ae*h-LZ>K#V(y+NX@kSg_V%$^H^^#w5(VjmNa^Al#Zr
zxKskTv?tM3%<%;PqbiC^j8kOR6?gv~_-2jxYPk=$UI?e|FeaO0Fjl)4b{QYeM$$#=
z33NONUJd|;<y@`1?;MsL5_l&v;WedVvHuKQui`OUAC93)9zK*&uu4OIjxnV^j>c@3
zEdc1N;!Mt4u3_FH!uuLNdh0_mSQm{kBBv%A#u5&?pX`FYmIHU&F-*wfP<N9l3jjKw
z23L%z;@~moV4&eNRQF<`6CZ)LfQ^qb0X(f?=o7PHkuc$CNkq>x9%`;Lgug8DbunAt
zBaI+kWJ7UF0I#(WUwSj4$>*c9h=G}AiU3$-A0$Ax*`Bq(7C5v$WSb3D;V`_ofN@<0
zyyGH_s4k);Wh-=dcVI!ug{|Qbq&Jv@e+2kN0@9!>-iNlrSST`i(3d5k^wJhQO4^KW
zF%1@J6soS$C)Ne{CC_FF<ylPVN#g8=Q~3N&2!mt~KB;%3w@iSF%k<8_0#+r>V2Y&a
z4Co4YFjq&xTp5X`tPqr@&_w?P@T)qFu}N};o>QJmcZySJ(<RBYc5yO|wYKI5>R-Md
ToJi+(00000NkvXXu0mjf*@atu

literal 0
HcmV?d00001

diff --git a/lib/plugins/config/lang/en/lang.php b/lib/plugins/config/lang/en/lang.php
index d92e930f2..db8c270b9 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 b55c0e930..09d3736f3 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 cb39516c4..209e5654c 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;
-- 
GitLab