diff --git a/ecrire/inc_cron.php3 b/ecrire/inc_cron.php3
index c994988807353661851ff25a7b000d72a72d6fd3..62e08af17188f24ec3fa3c0eae87ad68d03ef4cd 100644
--- a/ecrire/inc_cron.php3
+++ b/ecrire/inc_cron.php3
@@ -6,8 +6,9 @@ if (defined("_ECRIRE_INC_CRON")) return;
 define("_ECRIRE_INC_CRON", "1");
 
 
-// ---------------------------------------------------------------------------------------------
+// --------------------------
 // Gestion des taches de fond
+// --------------------------
 
 
 //
@@ -55,7 +56,7 @@ function cron_archiver_stats($last_date) {
 //
 // La fonction de base qui distribue les taches
 //
-function spip_cron($use_cache) {
+function spip_cron() {
 	global $flag_ecrire, $dir_ecrire, $db_ok;
 
 	include_ecrire("inc_connect.php3");
@@ -154,10 +155,8 @@ function spip_cron($use_cache) {
 	//
 	// Gerer l'indexation
 	//
-
-	if ($use_cache  &&( lire_meta('activer_moteur') == 'oui')) {
+	if (lire_meta('activer_moteur') == 'oui') {
 		if (timeout('indexation')) {
-		  spip_log('effectuer_une_indexation');
 			include_ecrire("inc_index.php3");
 			effectuer_une_indexation();
 		}
@@ -167,7 +166,6 @@ function spip_cron($use_cache) {
 	//
 	// Mise a jour d'un (ou de zero) site syndique
 	//
-
 	if (lire_meta("activer_syndic") == "oui") {
 		if (timeout()) {
 			include_ecrire("inc_sites.php3");
@@ -183,7 +181,6 @@ function spip_cron($use_cache) {
 	//
 	// Effacement de la poubelle (documents supprimes)
 	//
-
 	if (@file_exists($fichier_poubelle = $dir_ecrire.'data/.poubelle')) {
 		if (timeout('poubelle')) {
 			if ($s = sizeof($suite = file($fichier_poubelle))) {
@@ -191,14 +188,16 @@ function spip_cron($use_cache) {
 				$s = trim($s);
 
 				// Verifier qu'on peut vraiment effacer le fichier...
-				$query = "SELECT id_document FROM spip_documents WHERE fichier='$s'";
+				$query = "SELECT id_document FROM spip_documents
+					WHERE fichier='$s'";
 				$result = spip_query($query);
-				if (spip_num_rows($result) OR !ereg('^IMG/', $s) OR strpos($s, '..')) {
+
+				if (spip_num_rows($result) OR !ereg('^IMG/', $s)
+				OR strpos($s, '..'))
 					spip_log("Tentative d'effacement interdit: $s");
-				}
-				else {
+				else
 					@unlink($s);
-				}
+
 				unset($suite[$n]);
 				$f = fopen($fichier_poubelle, 'wb');
 				fwrite($f, join("", $suite));
diff --git a/ecrire/inc_db_mysql.php3 b/ecrire/inc_db_mysql.php3
index 59607fe13a4973232d6132b57e989edfdc8d849a..9aaaeacf864a797ebb24ed04ef3eadb543cdd066 100644
--- a/ecrire/inc_db_mysql.php3
+++ b/ecrire/inc_db_mysql.php3
@@ -132,7 +132,9 @@ function spip_insert_id() {
 	return mysql_insert_id();
 }
 
+//
 // Poser un verrou local a un SPIP donne
+//
 function spip_get_lock($nom, $timeout = 0) {
 	global $spip_mysql_db, $table_prefix;
 	if ($table_prefix) $nom = "$table_prefix:$nom";
@@ -152,4 +154,21 @@ function spip_release_lock($nom) {
 	spip_query("SELECT RELEASE_LOCK('$nom')");
 }
 
+
+//
+// IN (...) est limite a 255 elements, d'ou cette fonction assistante
+//
+function calcul_mysql_in($val, $valeurs, $not) {
+	$s = split(',', $valeurs, 255);
+	if (count($s) < 255) {
+		return ("($val $not IN ($valeurs))");
+	} else {
+		$valeurs = array_pop($s);
+		return ("($val $not IN (" . join(',',$s) . "))\n" .
+			($not ? "AND\t" : "OR\t") .
+			calcul_mysql_in($val, $valeurs, $not));
+    }
+}
+  
+
 ?>
diff --git a/ecrire/inc_version.php3 b/ecrire/inc_version.php3
index c5028890015c935c7d75ed03aa4d8b48c6977b3e..e5369d8b2ff0af577fe7532fca25c553c4a0d005 100644
--- a/ecrire/inc_version.php3
+++ b/ecrire/inc_version.php3
@@ -154,6 +154,14 @@ $spip_server = array (
 // Produire du TeX ou de MathML ?
 $traiter_math = 'tex';
 
+/* ATTENTION CES VARIABLES NE FONCTIONNENT PAS ENCORE */
+// Extension du fichier du squelette 
+$extension_squelette = 'html';
+// Repertoire des images
+$dossier_images = 'IMG';
+/* / MERCI DE VOTRE ATTENTION */
+
+
 //
 // *** Fin du parametrage ***
 //
@@ -973,4 +981,19 @@ function verif_butineur() {
 	if (!$browser_name) $browser_name = "Mozilla";
 }
 
+//
+// spip_timer : on l'appelle deux fois et on a la difference, affichable
+//
+function spip_timer($t='rien') {
+	static $time;
+	$a=time(); $b=microtime();
+
+	if (isset($time[$t])) {
+		$p = $a + $b - $time[$t];
+		unset($time[$t]);
+		return sprintf("%.2fs", $p);
+	} else
+		$time[$t] = $a + $b;
+}
+
 ?>
diff --git a/inc-admin.php3 b/inc-admin.php3
index 954cbb1056a0bd3394d6d6ec45122fd346fea558..6e78eec1b83e24aa41bd10b4e36be57fed0393c3 100644
--- a/inc-admin.php3
+++ b/inc-admin.php3
@@ -56,8 +56,12 @@ function afficher_boutons_admin($pop) {
 	$ret .= "</form>\n";
 
 	if (lire_meta("activer_statistiques") != "non" AND $id_article AND ($GLOBALS['auteur_session']['statut'] == '0minirezo')) {
-		include_local ("inc-stats.php3");
-		$ret .= bouton_admin(_T('stats_visites_et_popularite', afficher_raccourci_stats($id_article)), "./ecrire/statistiques_visites.php3?id_article=$id_article");
+		if (spip_fetch_array(spip_query("SELECT id_article FROM spip_articles WHERE id_article =".intval($id_article)))) {
+			include_local ("inc-stats.php3");
+			$ret .= bouton_admin(_T('stats_visites_et_popularite',
+			afficher_raccourci_stats($id_article)),
+			"./ecrire/statistiques_visites.php3?id_article=$id_article");
+		}
 	}
 
 	$ret .= "</div>";
diff --git a/inc-cache.php3 b/inc-cache.php3
index be6de1e9ebf1e59482997576dbb898219e1d3b3f..48a371634a64714ecb359351d6ceed1eb3a6bdcc 100644
--- a/inc-cache.php3
+++ b/inc-cache.php3
@@ -1,420 +1,257 @@
 <?php
-# Ce fichier ne sera execute qu'une fois
+
+//
+// Ce fichier ne sera execute qu'une fois
 if (defined("_INC_CACHE")) return;
 define("_INC_CACHE", "1");
 
-include_local('inc-dir.php3');
-
-# Vérif de péremption d'une compil de squelette par rapport à son source
-# et les fonctions utilisateurs agissant sur le compilateur.
-# Ses fonctions internes sont supposées ne changer qu'à l'installation; 
-# sinon vider explicitement par l'interface privée.
-
-function squelette_obsolete($naissance, $source)
-{
-  $e = $GLOBALS['extension_squelette'];
-  $x = (($GLOBALS['recalcul'] == 'oui')
-	  OR ((filemtime($source . ".$e") > $naissance)
-	      OR (file_exists($source . '_fonctions.php3')
-		  AND (filemtime($source . '_fonctions.php3')> $naissance))
-	      OR (file_exists("ecrire/mes_options.php3")
-		  AND (filemtime("ecrire/mes_options.php3") > $naissance))
-	      OR (file_exists("mes_fonctions.php3")
-		  AND (filemtime("mes_fonctions.php3") > $naissance) ) ) );
-#  spip_log("squelette_obsolete $source " . ($x ? 'mauvais' : 'bon'));
-  return $x;
+
+//
+// Calcul du nom du fichier cache
+//
+
+function nettoyer_uri() {
+	$fichier_requete = $GLOBALS['REQUEST_URI'];
+	$fichier_requete = eregi_replace
+		('[?&](submit|valider|PHPSESSID|(var_[^=&]*)|recalcul)=[^&]*',
+		'', $fichier_requete);
+	return $fichier_requete;
 }
 
-# Retourne la fonction principale d'un squelette compilé.
-# En lance la compilation s'il ne l'était pas.
-
-function ramener_squelette($squelette)
-{
-  $e = $GLOBALS['extension_squelette'];
-  $nom = $e . '_' . md5($squelette);
-  $sourcefile = $squelette . ".$e";
-
-  if (function_exists($nom))
-    {
-      spip_log("Squelette $squelette:\t($nom) déjà en mémoire (INCLURE répété)");
-      return $nom;
-    }
-# spip_log("demande verrou $squelette"); 
-  clearstatcache();
-  if (!$lock = fopen($sourcefile, 'rb'))
-      $r = '';
-  else
-    {
-#      spip_log("obtient verrou $squelette"); 
-# empecher un meme calcul par 2 processus différents en se réservant le source
-      while (!flock($lock, LOCK_EX));
-# remplacer la ligne ci-dessus par les 3 suivantes pour démonstration:
-#  while (!flock($lock, LOCK_EX + LOCK_NB))
-# {sleep(1);spip_log("Lock: $nom " . getmypid());}
-#  sleep(3);
-      $phpfile = subdir_skel() . $nom . '.php';
-      if (file_exists($phpfile))
-	{
-	  if (!squelette_obsolete(filemtime($phpfile), $squelette))
-	    {
-	      include($phpfile);
-	      if (function_exists($nom))
-		{
-		  spip_log("Squelette $squelette:\t($nom) chargé");
-		  flock($lock, LOCK_UN);
-		  fclose($lock);
-		  return $nom;
-		}
-	    }
-	  # Cache obsolete ou erroné.
-	  @unlink($phpfile);
+function generer_nom_fichier_cache($contexte='', $fond='') {
+	global $HTTP_POST_VARS;
+
+	if (!$contexte) {
+		$fichier_requete = nettoyer_uri();
+	} else {
+		$fichier_requete = $fond;
+		foreach ($contexte as $var=>$val)
+			$fichier_requete .= "&$var=$val";
 	}
-      include_local("inc-calcul-squel.php3");
-      $timer_a = explode(" ", microtime());
-# si vous n'etes pas sous Windows, vous améliorerez les perfs en 
-# décommentant les 2 lignes suivantes (quant à Windows, il fait: $r =""; !)
-      $r = # function_exists('file_get_contents') ?
-	# file_get_contents($spipfile) : 
-	fread($lock, filesize($sourcefile));
-    }
-  if (!$r)
-    {
-      if ($lock) 
-	{ flock($lock, LOCK_UN); fclose($lock);}
-      include_ecrire ("inc_presentation.php3");
-      install_debut_html(_T('info_erreur_systeme'));
-      echo $sourcefile, _L(' squelette illisible');
-      install_fin_html();
-      exit;
-    }
-
-  $r = calculer_squelette($r, $nom, $e);
-  $timer_b = explode(" ", microtime());
-  $timer = ceil(1000*($timer_b[0] + $timer_b[1]-$timer_a[0]-$timer_a[1]));
-
-	if (file_exists($phpfile)) unlink($phpfile); // eviter tout probleme de duplication de contenu !!
-  $f=fopen($phpfile, "wb"); 
-  fwrite($f,"<?php # $squelette pid: " .  getmypid() ."\n");
-  fwrite($f,$r);
-  fwrite($f,'?'.'>');
-  fclose($f);
-  flock($lock, LOCK_UN);
-  fclose($lock);
-  spip_log("Squelette $squelette: ($nom)"  . strlen($r) . " octets, $timer ms");
-  eval($r); # + rapide qu'un include puisqu'on l'a
-  return $nom;
+
+	$md_cache = md5($fichier_requete);
+
+	$fichier_cache = ereg_replace('^/+', '', $fichier_requete);
+	$fichier_cache = ereg_replace('\.[a-zA-Z0-9]*', '', $fichier_cache);
+	$fichier_cache = ereg_replace('&[^&]+=([^&]+)', '&\1', $fichier_cache);
+	$fichier_cache = rawurlencode(strtr($fichier_cache, '/&-', '--_'));
+	if (strlen($fichier_cache) > 24)
+		$fichier_cache = substr(ereg_replace('([a-zA-Z]{1,3})[^-]*-',
+		'\1-', $fichier_cache), -22);
+
+	// Pour la page d'accueil
+	if (!$fichier_cache)
+		$fichier_cache = 'INDEX-';
+
+	// Cas des POST sur une meme adresse : ne pas melanger (desuet?)
+	if (!empty($HTTP_POST_VARS)) $fichier_cache .= '.'.@getmypid();
+	$fichier_cache .= '.'.substr($md_cache, 1, 8);
+
+	$subdir_cache = substr($md_cache, 0, 1);
+
+	if (creer_repertoire('CACHE', $subdir_cache))
+		$fichier_cache = "$subdir_cache/$fichier_cache";
+
+	return $fichier_cache;
 }
 
-# Teste si le squelette PHP ayant produit un cache est obsolete
-
-function generateur_obsolete($nom)
-{
-#  spip_log("Generateur de $nom");
-  $d = subdir_skel() . $nom . '.php';
-  if (file_exists($d))
-    {
-      $f = fopen($d, 'r');
-      if ($f)
-	{
-	  $l = fgets($f,1024);
-	  fclose($f);
-	  if (preg_match('/<.php #\s(\S*)\s/', $l, $m))
-	    return (squelette_obsolete(filemtime($d), $m[1]));
+
+//
+// Doit-on recalculer le cache ?
+//
+
+function utiliser_cache($chemin_cache, $delais) {
+	global $HTTP_SERVER_VARS, $HTTP_POST_VARS;
+	global $lastmodified;
+
+	// A priori cache
+	$ok_cache = true;
+
+	// Existence du fichier
+	$ok_cache = @file_exists($chemin_cache);
+
+	// Date de creation du fichier
+	if ($ok_cache) {
+		$t = filemtime($chemin_cache);
+		$age = time() - $t;
+		$age_ok = (($age < $delais) AND ($age >= 0));
+
+		// fichier cache trop vieux ?
+		if (!$age_ok)
+			$ok_cache = false;
+
+		// Inclusions multiples : derniere modification
+		if ($lastmodified < $t) $lastmodified = $t;
 	}
-    }
-  return true;
-}
 
-# Controle la validité d'un cache .
-# retourne False ou un tableau de 3 éléments:
-# - texte
-# - date de naissance
-# - présence de php à réexecuter
-# Si présent, on modifie $fraicheur (passé en référence)
-# pour qu'il indique la durée de vie restante
-
-function page_perenne($lock, $file, &$fraicheur, $passer_outre)
-{
-  $naissance = filemtime($file);
-  $t = time() - $naissance;
-  if (($t > $fraicheur) && $passer_outre) return false; 
-#  spip_log("Perenne: fraicheur ok");
-# la ligne 1 contient un commentaire comportant successivement
-# - la longévité du include le plus bref
-# - le  type (html ou php)
-# - le squelette ayant produit la page
-# - d'autres info pour debug seulement
-  $l = fgets($lock,1024);
-  if ((!preg_match("/^<!--\s(\d+)\s(\w+)\s(\S+)\s/", $l, $m)) && $passer_outre)
-# fichier non conforme, on ignore
-    return false; 
-#  spip_log("Perenne: contenu ok");
-  $t =  $m[1] - $t;
-  if (!$passer_outre) 
-    {
-      if ($t < 0) return false;
-#  spip_log("Perenne: include ok");
-      if (generateur_obsolete($m[3])) return false;
-    }
-#  spip_log("Perenne: generateur $m[3] ok");
-  $fraicheur = $t;
-  return array('texte' =>
-# si vous n'etes pas sous Windows, vous améliorerez les perfs en 
-# décommentant les 2 lignes suivantes (quant à Windows, il retourne "" !)
-#        function_exists('file_get_contents') ?
-#        substr(file_get_contents($file), strlen($l)) : 
-	       fread($lock, filesize($file)),
-	       'naissance' => $naissance,
-	       'process_ins' => $m[2]);
+	// recalcul obligatoire
+	$ok_cache &= ($GLOBALS['recalcul'] != 'oui');
+	$ok_cache &= empty($HTTP_POST_VARS);
+
+	// ne jamais recalculer pour les moteurs de recherche, proxies...
+	if ($HTTP_SERVER_VARS['REQUEST_METHOD'] == 'HEAD')
+		$ok_cache = true;
+
+	# spip_log (($ok_cache ? "cache":"calcul")." ($chemin_cache)". ($age ? " age: $age s (reste ".($delais-$age)." s)":''));
+	return $ok_cache;
 }
 
-# Retourne une page, décrite par le tableau de 2 ou 3 éléments:
-# 'texte' => la page
-# 'process_ins' => 'html' ou 'php' si présence d'un '<?php'
-# 'naissance' => heure du calcul si déjà calculé (absent si nouveau)
-
-# Si elle n'est pas dans le cache ou que celui-ci est inemployable,
-# calcul de la page en appliquant la fonction $calcul sur $contexte
-# (tableau de valeurs, hack standard pour langage comme PHP qui
-# permettent toutes les horreurs mais pas les belles et utiles fermetures)
-# et ecriture dans le cache sous le répetoire $fraicheur.
-# Celle-ci est pasée par référence pour être changée
-# $calcul est soit cherche_page_incluse soit cherche_page_incluante
-# qui appelle toute deux cherche_page, qui construit le tableau a 2 éléments
-
-# Les accès concurrents sont gérés par un verrou général, 
-# remplacé rapidement par un verrou spécifique
-
-function ramener_cache($cle, $calcul, $contexte, &$fraicheur)
-{
-  # pas de mise en cache si:
-  # - recherche (trop couteux de mémoriser une recherche précise)
-  # - valeurs hors URL (i.e. POST) sauf Forum qui les traite à part
-  
-  if ($GLOBALS['var_recherche']||
-      ($HTTP_POST_VARS && !$GLOBALS['ajout_forum']))
-      {
-	include_local('inc-calcul.php3');
-	return $calcul('', $contexte);
-      }
-# Bloquer/se faire bloquer par TOUS les créateurs de cache
-# Ce fichier sert de verrou (on est sur qu'il existe!).
-  if (!$lock = fopen('inc-cache.php3', 'rb'))
-    return(array('texte' => 'Cache en panne'));
-  while (!flock($lock, LOCK_EX));
-  $file = file_cache($cle, $fraicheur);
-  if (!file_exists($file))
-    {
-      fclose(fopen($file,'w'));
-      $obsolete = false;
-      $usefile = false;
-    }
-  else
-    {
-      $obsolete = true;
-      $usefile = ($GLOBALS['recalcul'] != 'oui');
-    }
-# Acquérir le verrou spécifique et libérer le précédent
-# pour permettre d'autres calculs (notamment d'éventuels include).
-# Ouvrir par r+ verrouillé pour forcer un 2e processus de même intention
-# à attendre le résulat du premier et s'en servir. 
-# Pour voir, décommenter le sleep ci-dessous,
-# lancer 2 demandes d'une page (surtout à inclusion) et regarder spip_log
-#  sleep(3);
-#  spip_log("demande de verrou pour $cle"); 
-  if (!$lock2 = fopen($file, 'r+b'))
-    {
-      flock($lock, LOCK_UN);
-      return(array('texte' => 'Cache en panne'));
-    }
-  if (!flock($lock2, LOCK_EX + LOCK_NB))
-    {
-# un autre processus s'occupe du bébé; 
-# on se bloque dessus après libération du verrou général
-      flock($lock, LOCK_UN);
-      $usefile = true;
-      while(!flock($lock2, LOCK_EX));
-    }
-  else
-    {
-    flock($lock, LOCK_UN);
-    }
-#  spip_log("obtient verrou $cle et libère le général"); 
-  $passer_outre =  !(timeout(false,false));
-  $r = ((!$usefile) && (!$passer_outre)) ? '' :
-    page_perenne($lock2, $file, $fraicheur, $passer_outre);
-  if ($r)
-    {
-#      spip_log("libère verrou $cle (page perenne)"); 
-      flock($lock2, LOCK_UN);
-      return $r;
-    }
-  if ($obsolete && (file_exists('inc-invalideur.php3')))
-    {
-      include_local('inc-invalideur.php3');
-      supprime_invalideurs_inclus("hache='$file'");
-    }
-  include_local('inc-calcul.php3');
-  if (!function_exists($calcul))
-      {
-	flock($lock2, LOCK_UN);
-#      spip_log("libère verrou $cle (Compilateur absent)");
-	return(array('texte' => 'Compilateur absent'));
-      }
-  $page = $calcul($file, $contexte);
-  $texte = $page['texte'];
-  $n = ($fraicheur ? strlen($texte) : 0);
-  if (!$n)
-    {
-      flock($lock2, LOCK_UN);
-#      spip_log("libère verrou $cle (Page vide)");
-      @unlink($file);
-    }
-  else
-    {
-      spip_log("libère verrou $cle ($n octets, $fraicheur sec de validité.)");
-      ftruncate($lock2,0);
-      fwrite($lock2, "<!-- $fraicheur\t" . 
-	     $page['process_ins'] .
-	     "\t" .
-	     $page['invalideurs']['squelette'] .
-	     "\t$cle  pid: " .  
-	     getmypid() .
-	     " -->\n");
-      fwrite($lock2,$texte);
-      flock($lock2, LOCK_UN);
-      fclose($lock2);
-      if (file_exists('inc-invalideur.php3'))
-	{
-	  include_local('inc-invalideur.php3');
-	  maj_invalideurs($file, $page['invalideurs']);
-	  if ($f = $contexte['cache_incluant'])
-	    insere_invalideur(array($file => true), 'inclure', $f);
+
+function ecrire_fichier_cache ($fichier, $contenu) {
+	$fichier_tmp = $fichier.'_tmp';
+
+	// Essayer de poser un verrou pour proteger l'ecriture du fichier
+	if (!spip_get_lock($fichier_tmp, 1)) {
+		spip_log ("Echec du lock $fichier_tmp !");
+		return;
 	}
-    }
-  return $page;
-}
 
-# retourne la date de naissance ou 0 si inexistant ou obsolete
-# attention: ne controle pas l'obsolescence des includes et du squelette.
-# Pas 100% fiable, donc, mais suffisant en pratique
-
-function cv_du_cache($cle, $fraicheur)
-{
-  $file = file_cache($cle, $fraicheur);
-  if (!file_exists($file))
-    return 0;
-  else
-    {
-      $naissance = filemtime($file);
-      $t = time() - $naissance;
-      return (($t > $fraicheur) ? 0 : $naissance);
-    }
-}
+	// Entrer les donnees et verifier qu'on est alle au bout
+	$f = fopen($fichier_tmp, "wb");
+	if (!$f) {
+		spip_log ("Echec d'ouverture de $fichier_tmp !");
+		return $fichier;
+	} else {
+		$r = fwrite($f, $contenu);
+		if ($r != strlen($contenu))
+			$bug = true;
+		if (!fclose($f))
+			$bug = true;
+	}
 
-# détruit tous les squelettes
-
-function retire_caches_squelette()
-{
-  $i= 0 ;
-  $dir = subdir_skel();
-  if ($handle = @opendir($dir))
-    {
-      while (($fichier = readdir($handle)) != '') {
-	if ($fichier[0] != '.') { @unlink("$dir$fichier"); $i++ ;}
-      }
-    }
-  spip_log("Destruction des $i squelette(s)");
+	// Finaliser
+	if ($bug) {
+		spip_log ("Probleme avec le fichier $fichier_tmp - je meurs");
+		@unlink($fichier_tmp);
+	} else {
+		@rename($fichier_tmp, $fichier);
+	}
+	spip_release_lock($fichier_tmp);
 }
 
-# détruit toutes les pages cachées et leurs invalideurs
-function retire_caches_pages()
-{
-  $j = 0;
-  foreach (alldir_cache() as $dir)
-    { 
-      if ($handle = opendir($dir))
-	{
-	  while (($subdir = readdir($handle)) != '') {
-	    if (($subdir[0] != '.') && ($handle2 = opendir("$dir$subdir")))
-	      {
-		while (($fichier = readdir($handle2)) != '') {
-		  if ($fichier[0] != '.')
-		    { @unlink("$dir$subdir/$fichier"); $j++;}
+
+//
+// Retourne $subdir/ si le sous-repertoire peut etre cree, '' sinon
+//
+
+function creer_repertoire($base, $subdir) {
+	if (@file_exists("$base/.plat")) return '';
+	$path = $base.'/'.$subdir;
+	if (@file_exists($path)) return "$subdir/";
+
+	@mkdir($path, 0777);
+	@chmod($path, 0777);
+	$ok = false;
+	if ($f = @fopen("$path/.test", "w")) {
+		@fputs($f, '<'.'?php $ok = true; ?'.'>');
+		@fclose($f);
+		include("$path/.test");
+	}
+	if (!$ok) {
+		$f = @fopen("$base/.plat", "w");
+		if ($f)
+			fclose($f);
+		else {
+			@header("Location: spip_test_dirs.php3");
+			exit;
 		}
-		@rmdir("$dir$subdir");
-	      }
-	  }
 	}
-    }
-  spip_log("Destruction des $j cache(s)");
-  if (file_exists('inc-invalideur.php3'))
-    {
-      include_local('inc-invalideur.php3');
-      supprime_invalideurs();
-    }
+	return ($ok? "$subdir/" : '');
 }
 
-# elimine les caches obsoletes figurant dans le même rep que la page indiquée
-
-function retire_vieux_caches($cle, $delais)
-{
-  $dir = dir_of_file_cache($cle, $delais);
-  $tous = trouve_caches('retire_cond_cache', $delais, $dir);
-  spip_log("nettoyage de $dir (" . count($tous) . " obsolète(s)");
-  if ($tous)
-    {
-      if (!file_exists('inc-invalideur.php3'))
-	retire_caches($tous);
-      else
-	{
-	  include_local('inc-invalideur.php3');
-	  applique_invalideur($tous);
+
+function purger_repertoire($dir, $age, $regexp = '') {
+	$handle = @opendir($dir);
+	if (!$handle) return;
+
+	$t = time();
+	while (($fichier = @readdir($handle)) != '') {
+		// Eviter ".", "..", ".htaccess", etc.
+		if ($fichier[0] == '.') continue;
+		if ($regexp AND !ereg($regexp, $fichier)) continue;
+		$chemin = "$dir/$fichier";
+		if (is_file($chemin)) {
+			$d = $t - filemtime($chemin);
+			if ($d > $age OR (ereg('\.NEW$', $fichier) AND $d > 60)) {
+				@unlink($chemin);
+				$fichier = ereg_replace('\.NEW$', '', $fichier);
+				$query = "DELETE FROM spip_forum_cache WHERE fichier='$fichier'";
+				spip_query($query);
+			}
+		}
+		else if (is_dir($chemin)) {
+			if ($fichier != 'CVS') purger_repertoire($chemin, $age);
+		}
 	}
-    }
+	closedir($handle);
 }
 
-# trouve dans un répertoire les caches
-# vérifiant un prédicat binaire (donné avec son premier argument)
-
-function trouve_caches($cond, $arg, $rep)
-{
-  if ($handle = opendir($dir))
-     {
-       while (($fichier = readdir($handle)) != '') {
-	 $path = "$dir/$fichier";
-	 if ($cond($arg, $path)) $tous[] = $path;
-       }
-     }
-   return $tous;
+
+// Recuperer les meta donnees du fichier cache
+function meta_donnees_cache ($chemin_cache) {
+	// Lire le debut du fichier cache ; permet de savoir s'il n'a
+	// pas ete invalide par une modif sur une table
+	if ($f = fopen($chemin_cache, "r")) {
+		$l = fgets($f,1024);
+		if (!preg_match("/^<!-- ([^\n]*) -->\n/", $l, $match))
+			return false; // non conforme
+		$meta_donnees = unserialize($match[1]);
+	}
+	return $meta_donnees;
 }
 
-# Teste l'obsolescence d'un cache. 
-# Celle de son include le + bref (indiquée ligne 1) serait + juste
-# mais lors d'un balayage de répertoire, 
-# ouvrir chaque fichier serait couteux, et de gain faible
+// Determination du fichier cache (si besoin)
+function determiner_cache($delais, &$use_cache, &$chemin_cache) {
+	if ($delais == 0) {
+		$use_cache = false;
+		$chemin_cache = '';
+	} else {
+		// Le fichier cache est-il valide ?
+		$use_cache = utiliser_cache($chemin_cache, $delais);
 
-function retire_cond_cache($arg,$path)
-{
-    return (filemtime($path) <  $arg);
-}
+		if ($use_cache) {
+			$meta_donnees = meta_donnees_cache($chemin_cache);
+			if (!is_array($meta_donnees)) {
+				$use_cache = false;
+			} else {
+				// Remplir les globals pour les boutons d'admin
+				if (is_array($meta_donnees['contexte']))
+				foreach ($meta_donnees['contexte'] as $var=>$val)
+					$GLOBALS[$var] = $val;
+			}
+		}
 
-# détruit les caches donnés en arguments.
-# En fait il faudrait poser un verrou sur chaque fichier
-# pour que ramener_cache ne puisse s'exécuter à ce moment-là
-# Trop cher pour une situation peu probable, mais à étudier.
-
-function retire_caches($caches)
-{
-  if ($caches)
-    {
-      $dir = dir_var();
-      foreach ($caches as $path)
-	{ if (is_cache($path, $dir))
-	    @unlink($GLOBALS['flag_ecrire'] ? ('../' . $path) : $path);
-	  else die(_T('info_acces_refuse') . ": '$path'");
+		// S'il faut calculer, poser un lock (et tester MySQL)
+		if (!$use_cache) {
+			// Attendre 20 secondes maxi, que le copain ait
+			// calcule le meme fichier cache ou que
+			// l'invalideur ait fini de supprimer le fichier
+			$ok = spip_get_lock($chemin_cache, 20);
+
+			if (!$ok)
+				$use_cache = @file_exists($chemin_cache);
+
+			// Toujours rien ? La base est morte :-(
+			if (!$use_cache AND !$GLOBALS['db_ok']) {
+				if (!$GLOBALS['flag_preserver']) {
+					include_ecrire('inc_presentation.php3');
+					install_debut_html(_T('info_travaux_titre'));
+					echo "<p>"._T('titre_probleme_technique')."</p>\n";
+					install_fin_html();
+					spip_log("Erreur base de donnees & ".
+					"impossible de creer $chemin_cache");
+				}
+				exit;
+			}
+		}
+
+		// On a le fichier cache et la date
+		if ($use_cache)
+			$lastmodified = filemtime($chemin_cache);
+			###  Si on utilise la fraicheur ce sera inutile
 	}
-    }
+
+	return $lastmodified;
 }
 
 ?>
diff --git a/inc-calcul.php3 b/inc-calcul.php3
index c84fd53f814a51c69708aa97415fb432f4c35a44..b844f4ee7a747807948d21d51c85987474bca5ab 100644
--- a/inc-calcul.php3
+++ b/inc-calcul.php3
@@ -1,10 +1,13 @@
 <?php
+
+
 // Ce fichier ne sera execute qu'une fois
 if (defined("_INC_CALCUL")) return;
 define("_INC_CALCUL", "1");
 
-// ce fichier exécute un squelette.
-
+//
+// Ce fichier calcule une page en executant un squelette.
+//
 
 include_ecrire("inc_index.php3");
 include_ecrire("inc_texte.php3");
@@ -12,51 +15,104 @@ include_ecrire("inc_filtres.php3");
 include_ecrire("inc_lang.php3");
 include_ecrire("inc_documents.php3");
 include_local("inc-calcul_mysql3.php");
-include("inc-calcul_html4.php");
+include_local("inc-calcul_html4.php");
 
 # Ce fichier peut contenir une affectation de $dossier_squelettes  indiquant
-# le répertoire du source des squelettes (les pseudo-html avec <BOUCLE...)
+# le repertoire du source des squelettes (les pseudo-html avec <BOUCLE...)
 
 if (file_exists("mes_fonctions.php3")) 
     include_local ("mes_fonctions.php3");
 
-# Provoque la recherche du squelette $fond d'une $lang donnée,
+
+function charger_squelette ($squelette) {
+	$ext = $GLOBALS['extension_squelette'];
+	$nom = $ext . '_' . md5($squelette);
+	$sourcefile = $squelette . ".$ext";
+
+	if (function_exists($nom)) {
+		#spip_log("Squelette $squelette:\t($nom) deja en memoire");
+		return $nom;
+	}
+	else {
+		$phpfile = 'CACHE/skel_' . $nom . '.php';
+
+		// le squelette est-il a compiler ?
+		if (!file_exists($phpfile) OR $GLOBALS['recalcul'] == 'oui') {
+			include_local("inc-calcul-squel.php3");
+			$f = fopen ($sourcefile, "r") OR die ("Horrible souffrances");
+			$skel = fread($f, filesize($sourcefile));
+			fclose($f);
+			$skel_compile = "<"."?php\n" .
+				calculer_squelette($skel, $nom, $ext)."\n?".">";
+			eval('?'.'>'.$skel_compile);
+			if (function_exists($nom)) {
+				ecrire_fichier_cache ($phpfile, $skel_compile);
+				return $nom;
+			} else {
+				die ("Hoorreeur squelette pas compile !!");
+			}
+		} else {
+			// Charge le squelette compile
+			include($phpfile);
+			if (function_exists($nom))
+				return $nom;
+			else
+				die ("Horreur squelette contient du baratin");
+		}
+	}
+}
+
+
+# Provoque la recherche du squelette $fond d'une $lang donnee,
 # et l'applique sur un $contexte pour un certain $cache.
-# Retourne un tableau de 3 éléments:
-# 'texte' => la page calculée
-# 'process_ins' => 'html' ou 'php' si présence d'un '<?php'
+# Retourne un tableau de 3 elements:
+# 'texte' => la page calculee
+# 'process_ins' => 'html' ou 'php' si presence d'un '<?php'
 # 'invalideurs' => les invalideurs (cf inc-calcul-squel)
 
-# La recherche est assurée par la fonction cherche_squelette
-# définie dans inc-chercher, fichier non chargé s'il existe un fichier
+# La recherche est assuree par la fonction cherche_squelette
+# definie dans inc-chercher, fichier non charge s'il existe un fichier
 # mon-chercher dans $dossier_squelettes ou dans le rep principal de Spip,
-# pour charger une autre définition de cette fonction.
+# pour charger une autre definition de cette fonction.
 
-# L'exécution est précédée du chargement éventuel d'un fichier homonyme
+# L'execution est precedee du chargement eventuel d'un fichier homonyme
 # de celui du squelette mais d'extension .php  pouvant contenir:
 # - des filtres
 # - des fonctions de traduction de balise (cf inc-index-squel)
 
-function cherche_page($cache, $contexte, $fond, $id_rubrique, $lang='') 
-{
-  global $dossier_squelettes;
-
-  $dir = "$dossier_squelettes/mon-chercher.php3";
-  if (file_exists($dir)) include($dir); else include_local("inc-chercher.php3");
-
-  $skel = chercher_squelette($fond,
-			     $id_rubrique,
-			     $dossier_squelettes ? "$dossier_squelettes/" :'',
-			     $lang);
-
-  $dir = "$skel" . '_fonctions.php3';
-  if (file_exists($dir)) include($dir);
-
-  $fonc =  ramener_squelette($skel);
-  $timer_a = explode(" ", microtime());
-  $page =  $fonc(array('cache' =>$cache),
-		 array($contexte),
-		 array(	'articles' => '0',
+function cherche_page ($cache, $contexte, $fond, $id_rubrique, $lang='')  {
+	global $dossier_squelettes;
+
+	/* Bonne idee mais plus tard ?
+	$dir = "$dossier_squelettes/mon-chercher.php3";
+	if (file_exists($dir)) {
+		include($dir);
+	} else { */
+		include_local("inc-chercher.php3");
+	/* }
+	*/
+
+	// Choisir entre $fond-dist.html, $fond=7.html, etc?
+	$skel = chercher_squelette($fond,
+		$id_rubrique,
+		$dossier_squelettes ? "$dossier_squelettes/" :'',
+		$lang
+	);
+
+	/*  Idem
+	$dir = "$skel" . '_fonctions.php3';
+	if (file_exists($dir)) include($dir);
+	*/
+
+	// Charger le squelette demande et recuperer sa fonction main()
+	// (on va le compiler si besoin est)
+	$fonc = charger_squelette($skel);
+
+	// Calculer la page a partir du main() du skel compile
+	$page =  $fonc(array('cache' =>$cache),
+		array($contexte),
+		array(
+			'articles' => '0',
 			'rubriques' => '0',
 			'breves' => '0',
 			'auteurs' => '0',
@@ -65,91 +121,149 @@ function cherche_page($cache, $contexte, $fond, $id_rubrique, $lang='')
 			'mots' => '0',
 			'groupes_mots' => '0',
 			'syndication' => '0',
-			'documents' => '0'));
-
-  if ($GLOBALS['xhtml']) {
-    include_ecrire("inc_tidy.php");
-    $page['texte'] = xhtml($page['texte']);
-  }
-  $timer_b = explode(" ", microtime());
-  $timer = ceil(1000*($timer_b[0] + $timer_b[1] - $timer_a[0] - $timer_a[1]));
-  spip_log("Page $skel: " . strlen($page['texte']) . " octets, $timer ms");
-  return $page;
+			'documents' => '0'
+		)
+	);
+
+	// Nettoyer le resultat si on est fou de XML
+	if ($GLOBALS['xhtml']) {
+		include_ecrire("inc_tidy.php");
+		$page['texte'] = xhtml($page['texte']);
+	}
+
+	// Entrer les invalideurs dans la base
+	include_ecrire('inc_invalideur.php3');
+	maj_invalideurs($cache, $page['invalideurs']);
+
+	// Retourner la structure de la page
+	return $page;
 }
 
-function cherche_page_incluse($cache, $contexte)
-{
-  $contexte_inclus = $contexte['contexte'];
-  return cherche_page($cache,
-		      $contexte_inclus,
-		      $contexte['fond'], 
-		      $contexte_inclus['id_rubrique']);
+// Etablit le contexte initial a partir des globales
+function calculer_contexte() {
+	foreach($GLOBALS['HTTP_GET_VARS'] as $var => $val) {
+		if (!eregi("^(recalcul|submit|var_.*)$", $var))
+			$contexte[$var] = $val;
+	}
+	if ($GLOBALS['date'])
+		$contexte['date'] = $contexte['date_redac'] = date($GLOBALS['date']);
+	else
+		$contexte['date'] = $contexte['date_redac'] = date("Y-m-d H:i:s");
+
+	return $contexte;
 }
 
-function calculer_page_globale($cache, $contexte, $fond, $var_recherche)
- {
-   global $spip_lang;
-  
-   $id_rubrique_fond = 0;
-   $lang = $contexte['lang'];	// si inc-urls veut fixer la langue
-   if ($r = cherche_rubrique_fond($contexte, $lang ? $lang : lire_meta('langue_site')))
-     list($id_rubrique_fond, $lang) = $r;
-
-  $signale_globals = "";
-  foreach(array('id_parent', 'id_rubrique', 'id_article', 'id_auteur',
-		'id_breve', 'id_forum', 'id_secteur', 'id_syndic', 'id_syndic_article', 'id_mot', 'id_groupe', 'id_document') as $val)
-    {
-      if ($contexte[$val])
-	$signale_globals .= '$GLOBALS[\''.$val.'\'] = '.intval($contexte[$val]).";";
-    }
-  if (!$GLOBALS['forcer_lang'])
-    lang_select($lang);
-
-  $page = cherche_page($cache, $contexte, $fond, $id_rubrique_fond, $spip_lang);
-  $texte = $page['texte'];
-
-  if ($var_recherche)
-    {
-      include_ecrire("inc_surligne.php3");
-      $texte = surligner_mots($texte, $var_recherche);
-    } 
-
-  return array('texte' => 
-	       (($page['process_ins'] || (!$signale_globals)) ? $texte :
-		('<'."?php $signale_globals ?".'>'.$texte)),
-	       'process_ins' => $page['process_ins'],
-	       'invalideurs' => $page['invalideurs']);
+function calculer_page_globale($cache, $contexte_local, $fond, $var_recherche) {
+	global $spip_lang;
+
+	// Mise au point des URLs personnalisees
+	if (@file_exists("inc-urls.php3")) { include_local ("inc-urls.php3"); }
+	else { include_local ("inc-urls-dist.php3"); }
+
+	// C'est sale mais historique
+	if (function_exists("recuperer_parametres_url")) {
+		global $contexte;
+		$contexte = $contexte_local;
+		recuperer_parametres_url($fond, nettoyer_uri());
+		if (is_array($contexte))
+			foreach ($contexte as $var=>$val)
+				$GLOBALS[$var] = $val;
+		$contexte_local = $contexte;
+	}
+
+	$id_rubrique_fond = 0;
+
+	// Si inc-urls veut fixer la langue, se baser ici
+	$lang = $contexte_local['lang'];
+
+	// Chercher le fond qui va servir de squelette
+	if ($r = cherche_rubrique_fond($contexte_local,
+	$lang ? $lang : lire_meta('langue_site')))
+		list($id_rubrique_fond, $lang) = $r;
+
+	if (!$GLOBALS['forcer_lang'])
+		lang_select($lang);
+
+	// Go to work !
+	$page = cherche_page($cache, $contexte_local, $fond, $id_rubrique_fond, $spip_lang);
+
+	// Surligne
+	if ($var_recherche) {
+		include_ecrire("inc_surligne.php3");
+		$page['texte'] = surligner_mots($page['texte'], $var_recherche);
+	} 
+
+	$signal = array();
+	foreach(array('id_parent', 'id_rubrique', 'id_article', 'id_auteur',
+	'id_breve', 'id_forum', 'id_secteur', 'id_syndic', 'id_syndic_article',
+	'id_mot', 'id_groupe', 'id_document') as $val) {
+		if ($contexte_local[$val])
+			$signal['contexte'][$val] = intval($contexte_local[$val]);
+	}
+	$signal['process_ins'] = $page['process_ins'];
+
+# ne marchera qu'avec les inclusions 'html' (versus 'php')
+#	$signal['fraicheur'] = $page['fraicheur'];
+
+	$signal = "<!-- ".str_replace("\n", " ", serialize($signal))." -->\n";
+
+	$page['texte'] = $signal.$page['texte'];
+
+	return $page;
 }
 
-function cherche_page_incluante($cache, $contexte)
-{
-    // si le champ chapo commence par '=' c'est une redirection.
-
-  if ($id_article = intval($GLOBALS['id_article'])) {
-    $page = query_chapo($id_article);
-    if ($page) 
-      {
-	$page = $page['chapo'];
-	if (substr($page, 0, 1) == '=') {
-	  include_ecrire('inc_texte.php3');
-	  list(,$page) = extraire_lien(array('','','',substr($page, 1)));
-	  if ($page) // sinon les navigateurs pataugent
-	    {
-	      $page = addslashes($page);
-	      return array('texte' =>
-			   ("<". "?php header(\"Location: $page\"); ?" . ">"),
-			   'process_ins' => 'php');
-	    }
+
+// Cf ramener_page +cherche_page_incluante+ cherche_page_incluse chez ESJ
+function calculer_page($chemin_cache, $elements, $delais, $inclusion=false) {
+	include_local('inc-calcul.php3');
+
+	// Inclusion
+	if ($inclusion) {
+		$contexte_inclus = $elements['contexte'];
+		$page = cherche_page($chemin_cache,
+			$contexte_inclus,
+			$elements['fond'], 
+			$contexte_inclus['id_rubrique']
+		);
+	}
+	else {
+
+		// Page globale
+		// si le champ chapo commence par '=' c'est une redirection.
+		if ($id_article = intval($GLOBALS['id_article'])) {
+			$page = query_chapo($id_article);
+			if ($page) {
+				$page = $page['chapo'];
+				if (substr($page, 0, 1) == '=') {
+					include_ecrire('inc_texte.php3');
+					list(,$page) = extraire_lien(array('','','',
+					substr($page, 1)));
+					if ($page) { // sinon les navigateurs pataugent
+						$page = addslashes($page);
+						return array('texte' =>
+						("<". "?php header(\"Location: $page\"); ?" . ">"),
+						'process_ins' => 'php');
+					}
+				}
+			}
+		}
+		$page = calculer_page_globale($chemin_cache,
+			$elements['contexte'],
+			$elements['fond'],
+			$elements['var_recherche']);
+	}
+
+	// Enregistrer le fichier cache
+	if ($delais>0) {
+		ecrire_fichier_cache($chemin_cache, $page['texte']);
 	}
-      }
-  }
-  return calculer_page_globale( $cache,
-				$contexte['contexte'],
-				$contexte['fond'],
-				$contexte['var_recherche']);
+
+	return $page;
 }
 
-# Fonctions appelées par les squelettes (insertion dans le code trop lourde)
+
+
+# Fonctions appelees par les squelettes (insertion dans le code trop lourde)
 
 tester_variable('espace_logos',3);  // HSPACE=xxx VSPACE=xxx pour les logos (#LOGO_ARTICLE)
 tester_variable('espace_images',3);  // HSPACE=xxx VSPACE=xxx pour les images integrees
diff --git a/inc-calcul_mysql3.php b/inc-calcul_mysql3.php
index 766f4ef71ecfb7e6d257e9b954a6b672f790097c..cedb725da6a8dcdb93fdbc3a2530ed41536ead3d 100644
--- a/inc-calcul_mysql3.php
+++ b/inc-calcul_mysql3.php
@@ -23,8 +23,7 @@
 # En commentaire, le court-circuit de spip_query,
 # avec traitement de table_prefix sans restriction sur son nom
 
-function spip_abstract_select($s, $f, $w, $g, $o, $l, $sous, $cpt, $table, $id)
-{
+function spip_abstract_select($s, $f, $w, $g, $o, $l, $sous, $cpt, $table, $id) {
 # if ($GLOBALS["mysql_rappel_connexion"] AND $DB = $GLOBALS["spip_mysql_db"])
 #        $DB = "`$DB`";
 # $DB .= $GLOBALS["table_prefix"] . '_';
@@ -115,22 +114,6 @@ function calcul_index_forum($id_article, $id_breve, $id_rubrique, $id_syndic)
     'd' . ($id_syndic ? $id_syndic : '0');
 }
 
-# Critere {branche} : recuperer les descendants d'une rubrique
-
-function calcul_mysql_in($val, $valeurs, $tobeornotobe)
-{
-  $s = split(',', $valeurs, 255);
-  if (count($s) < 255)
-    return ("($val $tobeornotobe IN ($valeurs))");
-  else 
-    {
-      $valeurs = array_pop($s);
-      return ("($val $tobeornotobe IN (" . join(',',$s) . "))\n" .
-	      ($tobeornotobe ? "AND\t" : "OR\t") .
-	      calcul_mysql_in($val, $valeurs, $tobeornotobe));
-    }
-}
-  
 function calcul_exposer ($pile, $reference) {
 	static $hierarchie;
 	static $ref_precedente;
@@ -304,5 +287,4 @@ SELECT id_rubrique,lang FROM spip_articles WHERE id_article='$id'"))) {
 }
 
 
-
 ?>
diff --git a/inc-chercher.php3 b/inc-chercher.php3
index 2bc14a7c561bcd18eaa715790370fe60ab61d349..d2e60a0c9a355a389b53d4a6e2aa99ff850f504e 100644
--- a/inc-chercher.php3
+++ b/inc-chercher.php3
@@ -4,43 +4,45 @@
 if (defined("_INC_CHERCHE")) return;
 define("_INC_CHERCHE", "1");
 
-# Ce fichier doit IMPERATIVEMENT contenir la fonction chercher-squelette
-# (cf commentaires dans inc-calcul)
+// Ce fichier doit IMPERATIVEMENT contenir la fonction chercher-squelette
+// (cf commentaires dans inc-calcul)
 
 function chercher_squelette($fond, $id_rubrique, $dossier, $lang) {
-  $e = $GLOBALS['extension_squelette'];
-  if ($lang)
-    {
-	lang_select($lang);
-	$f = "$fond.$lang";
-	if (@file_exists($f . '.' . $e)) $fond = $f;
-    }
-  $d ="$dossier$fond";
-  // On selectionne, dans l'ordre :
-  // fond=10, fond-10 fond-<rubriques parentes> fond fond-dist
-  $f = "$d=$id_rubrique";
-  if (($id_rubrique > 0) AND (@file_exists($f . '.' . $e))) return $f;
-  while ($id_rubrique) {
-    if (file_exists("$d-$id_rubrique.$e")) {
-      return "$d-$id_rubrique";
-    } else {
-      $id_rubrique = query_parent($id_rubrique);
-    }
-  }
-  if (@file_exists("$d.$e")) {
-    return $d;
-  } else if (@file_exists("$fond.$e")) {
-    return $fond;
-  } else if (@file_exists("$fond-dist.$e")) {
-    return "$fond-dist";
-  } else {
-   // erreur webmaster : $fond ne correspond a rien
-    include_ecrire ("inc_presentation.php3");
-    install_debut_html(_T('info_erreur_squelette'));
-    echo "<P>"._T('info_erreur_squelette2', array('fichier'=>"$d"))."</P>";
-    install_fin_html();
-    spip_log ("ERREUR: aucun squelette $d n'est disponible...");
-    exit;
-    }
+	$ext = $GLOBALS['extension_squelette'];
+	if ($lang) {
+		lang_select($lang);
+		$f = "$fond.$lang";
+		if (@file_exists("$f.$ext"))
+			$fond = $f;
+	}
+	$d ="$dossier$fond";
+	// On selectionne, dans l'ordre :
+	// fond=10, fond-10 fond-<rubriques parentes> fond fond-dist
+	$f = "$d=$id_rubrique";
+	if (($id_rubrique > 0) AND (@file_exists("$f.$ext")))
+		return $f;
+
+	while ($id_rubrique) {
+		if (file_exists("$d-$id_rubrique.$ext"))
+			return "$d-$id_rubrique";
+		else
+			$id_rubrique = query_parent($id_rubrique);
+	}
+
+	if (@file_exists("$d.$ext")) {
+		return $d;
+	} else if (@file_exists("$fond.$ext")) {
+		return $fond;
+	} else if (@file_exists("$fond-dist.$ext")) {
+		return "$fond-dist";
+	} else {
+		// erreur webmaster : $fond ne correspond a rien
+		include_ecrire ("inc_presentation.php3");
+		install_debut_html(_T('info_erreur_squelette'));
+		echo "<P>"._T('info_erreur_squelette2', array('fichier'=>"$d"))."</P>";
+		install_fin_html();
+		spip_log ("ERREUR: aucun squelette $d n'est disponible...");
+		exit;
+	}
 }
 ?>
diff --git a/inc-dir.php3 b/inc-dir.php3
deleted file mode 100644
index 263b699aa72cb68d958db82ceb613ab12df8ab1a..0000000000000000000000000000000000000000
--- a/inc-dir.php3
+++ /dev/null
@@ -1,117 +0,0 @@
-<?php
-
-// Ce fichier ne sera execute qu'une fois
-if (defined("_INC_DIR")) return;
-define("_INC_DIR", "1");
-
-# Retourne le re'pertoire accessible en e'criture 
-# et verifie la presence de son .htaccess (sinon le genere)
-# Force le statcache de PHP par la me^me occasion.
-
-# NE PAS REFERENCER CE REPERTOIRE AUTREMENT QUE PAR CET APPEL
-
-function dir_var()
-{
-  $dir = 'CACHE/';
-  if ($flag_ecrire) $dir = '../' . $dir;
-  $file = $dir . '.htaccess';
-  clearstatcache();
-  if (!@file_exists($file)) {
-    if ($hebergeur == 'nexenservices'){
-      echo "<font color=\"#FF0000\">IMPORTANT : </font>";
-      echo "Votre h&eacute;bergeur est Nexen Services.<br />";
-      echo "La protection du r&eacute;pertoire <i>CACHE/</i> doit se faire par l
-'interm&eacute;diaire de ";
-      echo "<a href=\"http://www.nexenservices.com/webmestres/htlocal.php\" targ
-et=\"_blank\">l'espace webmestres</a>.";
-      echo "Veuillez cr&eacute;er manuellement la protection pour ce r&eacute;pe
-rtoire (un couple login/mot de passe est n&eacute;cessaire).<br />";
-    }
-    else{
-      $f = fopen($file, "wb");
-      fputs($f, "deny from all\n");
-      fclose($f);
-    }
-  }
-  return($dir);
-}
-
-# retourne un sous-re'petoire du pre'ce'dent
-# le cre'e avec les bons droits au besoin
-
-function subdir_var($dir, $subdir)
-{
-  $dir .=  $subdir;
-  if (!@is_writable($dir))
-    { 
-      if (!@mkdir ($dir, 0777))
-	{
-	  flock($lock, LOCK_UN);
-	  header("Location: spip_test_dirs.php3");
-	  exit;
-	}
-    }
-  return $dir  . '/';
-}
-
-# retourne le sous-re'pertoire des squelettes. 
-
-function subdir_skel()
-{
-  return subdir_var(dir_var(), 's');
-}
-
-# retourne un sous-sous-re'pertoire de cache.
-
-function subdir_cache($h, $delai)
-{
-  return subdir_var(subdir_var(dir_var(), $h), $delai);
-}
-
-# retourne tous les sous-re'pertoires de cache
-
-function alldir_cache()
-{
-  $listdir = "0123456789abcdef";
-  $dir = dir_var();
-  $tous = array();
-  for($i=0;$i<16;$i++)
-  { 
-    $tous[] = subdir_var($dir,$listdir[$i]);
-  }
-  return $tous;
-}
-
-# Retourne un fichier de cache suppose' e^tre du html
-# Le nom du cache ne doit pas de'passer 64 caracte`res
-# (sinon rede'finir les tables de caches type's et incluants 
-# dans inc_base et inc_auxbase)
-
-function file_cache($cle, $delai)
-{
-  $hache = md5($cle);
-  return subdir_cache($hache[16],$delai) . $hache . '.html';
-}
-
-# retourne le re'pertoire d'un fichier de cache
-
-function dir_of_file_cache($cle, $delai)
-{
-  $hache = md5($cle);
-  return subdir_cache($hache[16],$delai);
-}
-
-# teste si son argument est un ficher du re'pertoire de cache
-
-function is_cache($path, $dir)
-{
-  $n = strlen($dir);
-  return
-    ((strpos($path, $dir) === 0) && 
-     (strpos("abcdef0123456789", $path[$n]) !== false) &&
-     ($path[$n+1] == '/') &&
-     (strpos($path, '../') === false) );
- return $x;
-}
-
-?>
diff --git a/inc-form-squel.php3 b/inc-form-squel.php3
index db9adf79fe09c1d0b23f6d051e034cf84fe92d89..f6eccdf414eb8d05674dd3b192b5a6e03dc7aca4 100644
--- a/inc-form-squel.php3
+++ b/inc-form-squel.php3
@@ -138,9 +138,7 @@ function calculer_champ_PARAMETRES_FORUM($fonctions, $nom_champ, $id_boucle, &$b
 	index_pile($id_boucle,  "accepter_forum", $boucles) . ' != "non"));
 	if ($forums_publics) {
 		if (!($lien = $GLOBALS["HTTP_GET_VARS"]["retour"])) {
-			$lien = $GLOBALS["REQUEST_URI"];
-			$lien = ereg_replace("&recalcul=oui","",
-				substr($lien, strrpos($lien, "/") + 1));
+			$lien = nettoyer_uri();
 		}
 	$lien = rawurlencode($lien); ';
 
@@ -170,8 +168,7 @@ function calculer_champ_PARAMETRES_FORUM($fonctions, $nom_champ, $id_boucle, &$b
 	}
 	$milieu .= "}\n";
 	$code = "(!\$forums_publics) ? '' :
-		($c .\n" . '"&cache=".rawurlencode($Cache[cache]) .' .
-		"\n\"&retour=\$lien\")";
+		($c . \"&retour=\$lien\")";
 
 	list($c,$m) = applique_filtres($fonctions, $code, $id_boucle, $boucles, $id_mere);
 	return array($c,$milieu . $m);
diff --git a/inc-invalideur.php3 b/inc-invalideur.php3
deleted file mode 100644
index c61427b0d05314097f5ed934697961b8f6f7a0b2..0000000000000000000000000000000000000000
--- a/inc-invalideur.php3
+++ /dev/null
@@ -1,132 +0,0 @@
-<?php
-// Ce fichier ne sera execute qu'une fois
-if (defined("_INVALIDEUR")) return;
-define("_INVALIDEUR", "1");
-
-include_ecrire('inc_serialbase.php3');
-include_local('inc-cache.php3');
-include_local('inc-calcul_mysql3.php'); # pour mysql_in
-
-function  supprime_invalideurs()
-{
-  global $tables_principales;
-
-  foreach($tables_principales as $a)
-	{
-	$p = $a['key']["PRIMARY KEY"];
-	if (!strpos($p, ","))
-	  spip_query("
-DELETE FROM spip_" . $p . _SUFFIXE_DES_CACHES
-);
-	}
-  supprime_invalideurs_inclus();
-}
-
-function  supprime_invalideurs_inclus($cond='')
-{
-  spip_query("
-DELETE FROM spip_inclure"  . _SUFFIXE_DES_CACHES . ($cond ? " WHERE $cond" :'')
-);
-}
-
-function maj_invalideurs($hache, $infosurpage)
-{
-  // en attendant de réécrire les 3 scripts dans ecrire
-#  insere_invalideur($infosurpage['id_article'],'id_article', $hache);
-#  insere_invalideur($infosurpage['id_breve'],   'id_breve', $hache);
-#  insere_invalideur($infosurpage['id_rubrique'],'id_rubrique', $hache);
-  insere_invalideur($infosurpage['id_forum'],'id_forum', $hache);
-}
-
-function insere_invalideur($a, $type, $hache) {
-  if (is_array($a))
-    {
-      $values = array();
-      foreach($a as $k => $v)
-	{ $m = "('$hache', '$k')"; $values[] = $m; $l .= " $k";}
-      spip_query("
-INSERT IGNORE INTO spip_" . $type . _SUFFIXE_DES_CACHES . "
-(hache, " . $type . ")
-VALUES " . join(", ", $values));
-      spip_log("Dépendances $type: " . join(", ", $values));
-    }
-}
-
-// Regarde dans une table de nom de caches ceux vérifiant une condition donnée
-// Les retire de cette table et de la table générale des caches
-// Si la condition est vide, c'est une simple purge générale
-
-function suivre_invalideur($cond, $table)
-{
-  $result = spip_query("
-SELECT  DISTINCT hache 
-FROM    $table
-WHERE   $cond
-");
-  $tous = array();
-  while ($row = spip_fetch_array($result)) 
-    { $tous[] = $row['hache'];
-    }
-  spip_log("suivre $cond");
-  applique_invalideur($tous);
-}
-
-function applique_invalideur($depart)
-{
-  global $tables_principales;
-
-  if ($depart)
-    {
-      $tous = join("', '", $depart);
-      $tous = "'$tous'";
-      $niveau = $tous;
-      spip_log("applique $tous");
-      while ($niveau)
-	{
-# le NOT est théoriquement superflu, mais protège des tables endommagées
-	  $result = spip_query("
-SELECT  DISTINCT hache
-FROM    spip_inclure" . _SUFFIXE_DES_CACHES . '
-WHERE	' .
-			       calcul_mysql_in('inclure', $niveau, '') . '
-AND	' .
-			       calcul_mysql_in('hache', $tous, 'NOT')
-);
-	  $niveau = array();
-	  while ($row = spip_fetch_array($result))
-	    { $niveau[] = "'" . $row['hache'] . "'"; 
-	      $depart[] = $row['hache'];
-	      $tous .= ", '" . $row['hache'] . "'";}
-	  $niveau = join(', ', $niveau);
-	}
-      spip_query("
-DELETE FROM spip_inclure"  . _SUFFIXE_DES_CACHES . '
-WHERE	' .
-			       calcul_mysql_in('hache', $tous, 'NOT')
-);
-      
-      foreach($tables_principales as $a)
-	{
- 
-		$p = $a['key']["PRIMARY KEY"];
-		if (!strpos($p, ","))
-	    spip_query("
-DELETE FROM spip_" . $p  . _SUFFIXE_DES_CACHES . '
-WHERE	' .
-			       calcul_mysql_in('hache', $tous, 'NOT')
-);
-	}
-      retire_caches($depart);
-    }
-}
-
-// Une petite fonction de mise au point qui devrait etre dans inc_db_mysql
-
-function spip_query_log($r)
-{
-  $l = spip_query($r); 
-  $e = mysql_info(); # absent de certaines versions de MySQL
-  spip_log($r .  $e);
-  return $l;
-}
-?>
diff --git a/inc-messforum.php3 b/inc-messforum.php3
index a3332b64418e608eefc18ac599c36c8d1e6ba436..329eed2681e03a2275a27cfff213c4abaa1e4385 100644
--- a/inc-messforum.php3
+++ b/inc-messforum.php3
@@ -3,87 +3,90 @@
 include_ecrire('inc_texte.php3');
 include_ecrire('inc_filtres.php3');
 include_ecrire('inc_mail.php3');
+include_local('inc-calcul_mysql3.php');
 
-if (file_exists("inc-urls.php3")) {
-        include_local ("inc-urls.php3");
+if (file_exists("inc-urls.php3")) { include_local ("inc-urls.php3"); }
+else {include_local ("inc-urls-dist.php3"); }
+
+
+// Ce fichier inclus par inc-public a un comportement special
+// Voir commentaires dans celui-ci et dans inc-forum
+
+$retour_forum = rawurldecode($retour);
+$forum_id_article = intval($forum_id_article);
+$forum_id_rubrique = intval($forum_id_rubrique);
+$forum_id_parent = intval($forum_id_parent);
+$forum_id_breve = intval($forum_id_breve);
+$forum_id_syndic = intval($forum_id_syndic);
+$slash_texte = addslashes($texte);
+$slash_titre = addslashes($titre);
+$slash_nom_site_forum = addslashes($nom_site_forum);
+$slash_url_site = addslashes($url_site);
+$id_message = intval($id_message);
+
+// Nature du forum
+if (!$id_auteur)
+	$id_auteur = $GLOBALS['auteur_session']['id_auteur'];
+
+if ($forum_id_article) {
+	if ($s = spip_query("SELECT accepter_forum FROM spip_articles
+	WHERE id_article=$forum_id_article") AND
+	$obj = spip_fetch_object($s))
+		$forums_publics = $obj->accepter_forum;
+	else
+		$forums_publics = lire_meta("forums_publics");
+} else {
+	$forums_publics = substr(lire_meta("forums_publics"),0,3);
 }
-else {
-        include_local ("inc-urls-dist.php3");
+
+if ($forums_publics == "abo") {
+	if ($auteur_session) {
+		$statut = $auteur_session['statut'];
+		if (!$statut OR $statut == '5poubelle') {
+			die ("<h4>"._T('forum_acces_refuse'). "</h4>" . 
+			_T('forum_cliquer_retour', array('retour_forum' => $retour_forum)).
+			"<p>");
+		}
+	}
+	else {
+		die ("<h4>"._T('forum_non_inscrit'). "</h4>" . 
+		_T('forum_cliquer_retour', array('retour_forum' => $retour_forum)).
+		"<p>");
+	}
+
+	// Ne pas autoriser de changement de nom si forum sur abonnement
+	$auteur = $auteur_session['nom'];
+	$email_auteur = $auteur_session['email'];
+} 
+
+$slash_auteur = addslashes($auteur);
+$slash_email_auteur = addslashes($email_auteur);
+
+if ((strlen($slash_texte) + strlen($slash_titre) + strlen($slash_nom_site_forum) + strlen($slash_url_site) + strlen($slash_auteur) + strlen($slash_email_auteur)) > 20 * 1024) {
+	die ("<h4>"._T('forum_message_trop_long')."</h4>\n" .
+	_T('forum_cliquer_retour', array('retour_forum' => $retour_forum)).
+	"<p>");
 }
-// fichier inclus par inc-public.
-// Voir commentaires dans celui-ci et dans inc-forum
 
-  $retour_forum = rawurldecode($retour);
-  $forum_id_article = intval($forum_id_article);
-  $forum_id_rubrique = intval($forum_id_rubrique);
-  $forum_id_parent = intval($forum_id_parent);
-  $forum_id_breve = intval($forum_id_breve);
-  $forum_id_syndic = intval($forum_id_syndic);
-  $slash_texte = addslashes($texte);
-  $slash_titre = addslashes($titre);
-  $slash_nom_site_forum = addslashes($nom_site_forum);
-  $slash_url_site = addslashes($url_site);
-  $id_message = intval($id_message);
-  if (!$id_auteur) $id_auteur = $GLOBALS['auteur_session']['id_auteur'];
-  if ($forum_id_article) {
-    if ($obj = spip_fetch_object(spip_query("
-SELECT accepter_forum
-FROM spip_articles
-WHERE id_article=$forum_id_article")))
-       $forums_publics = $obj->accepter_forum;
-    else $forums_publics = lire_meta("forums_publics"); 
-  } else {
-    $forums_publics = substr(lire_meta("forums_publics"),0,3);	  
-  }
-  
-  if ($forums_publics == "abo") {
-    if ($auteur_session) {
-      $statut = $auteur_session['statut'];
-      
-      if (!$statut OR $statut == '5poubelle') {
-	die ("<h4>"._T('forum_acces_refuse'). "</h4>" . 
-	     _T('forum_cliquer_retour',
-		array('retour_forum' => $retour_forum)). "<p>");
-      }
-    }
-    else {
-      die ("<h4>"._T('forum_non_inscrit'). "</h4>" .
-	   _T('forum_cliquer_retour',
-	      array('retour_forum' => $retour_forum))."<p>");
-    }
-    // Ne pas autoriser de changement de nom si forum sur abonnement
-    $auteur = $auteur_session['nom'];
-    $email_auteur = $auteur_session['email'];
-  } 
-  $slash_auteur = addslashes($auteur);
-  $slash_email_auteur = addslashes($email_auteur);
-
-  if ((strlen($slash_texte) + strlen($slash_titre) + strlen($slash_nom_site_forum) + strlen($slash_url_site) + strlen($slash_auteur) + strlen($slash_email_auteur)) > 20 * 1024) {
-      die ("<h4>"._T('forum_message_trop_long')."</h4>\n" .
-	   _T('forum_cliquer_retour', array('retour_forum' => $retour_forum))."<p>");
+spip_query("DELETE FROM spip_mots_forum WHERE id_forum='$id_message'");
+if ($ajouter_mot) {
+	for (reset($ajouter_mot);$key=key($ajouter_mot);next($ajouter_mot))
+		$les_mots .= ",".join($ajouter_mot[$key],",");
+	$les_mots = explode(",", $les_mots);
+	for ($index = 0; $index < count($les_mots); $index++){
+		$le_mot = $les_mots[$index];
+		if ($le_mot > 0)
+		spip_query("INSERT INTO spip_mots_forum (id_mot, id_forum)
+		VALUES ('$le_mot', '$id_message')");
 	}
+}
 
-  spip_query("DELETE FROM spip_mots_forum WHERE id_forum='$id_message'");
-  if ($ajouter_mot){
-    for (reset($ajouter_mot); $key = key($ajouter_mot); next($ajouter_mot)){
-      $les_mots .= ",".join($ajouter_mot[$key],",");
-    }
-    $les_mots = explode(",", $les_mots);
-    for ($index = 0; $index < count($les_mots); $index++){
-      $le_mot = $les_mots[$index];
-      if ($le_mot > 0)
-	spip_query("INSERT INTO spip_mots_forum (id_mot, id_forum) VALUES ('$le_mot', '$id_message')");
-    }
-  }
-
-  $validation_finale = (strlen($confirmer) > 0 OR
-			($afficher_texte=='non' AND $ajouter_mot));
-  $statut = ((!$validation_finale) ? 'redac' : 
-			(($forums_publics == 'non') ? 'off' :
-			 (($forums_publics == 'pri') ? 'prop' : 'publie')));
-  spip_query("
-UPDATE	spip_forum
-SET	id_parent = $forum_id_parent,
+$validation_finale = (strlen($confirmer) > 0 OR
+	($afficher_texte=='non' AND $ajouter_mot));
+$statut = ((!$validation_finale) ? 'redac' : 
+	(($forums_publics == 'non') ? 'off' :
+	(($forums_publics == 'pri') ? 'prop' : 'publie')));
+spip_query("UPDATE spip_forum SET id_parent = $forum_id_parent,
 	id_rubrique =$forum_id_rubrique,
 	id_article = $forum_id_article,
 	id_breve = $forum_id_breve,
@@ -98,82 +101,78 @@ SET	id_parent = $forum_id_parent,
 	email_auteur = \"$slash_email_auteur\",
 	ip = \"$REMOTE_ADDR\",
 	statut = \"$statut\"
-WHERE	id_forum = '$id_message'
+	WHERE id_forum = '$id_message'
 ");
 
-if ($validation_finale)
- {
-    include_ecrire("inc_admin.php3");
-    if (!(verifier_action_auteur("ajout_forum $forum_id_rubrique $forum_id_parent $forum_id_article $forum_id_breve $forum_id_syndic $alea",
-				 $hash)))
-      {header("Status: 404");exit;}
-    else
-    {
-	// Poser un cookie pour ne pas retaper le nom / email
-	$cookie_user = array('nom' => $auteur, 'email' => $email_auteur);
-	spip_setcookie('spip_forum_user', serialize($cookie_user));
+if ($validation_finale) {
+	include_ecrire("inc_admin.php3");
+	if (!(verifier_action_auteur("ajout_forum $forum_id_rubrique".
+	" $forum_id_parent $forum_id_article $forum_id_breve".
+	" $forum_id_syndic $alea", $hash))) {
+		header("Status: 404");
+		exit;
+	} else {
+		// Poser un cookie pour ne pas retaper le nom / email
+		$cookie_user = array('nom' => $auteur, 'email' => $email_auteur);
+		spip_setcookie('spip_forum_user', serialize($cookie_user));
 
-		// Envoi d'un mail aux auteurs
-	$prevenir_auteurs = lire_meta("prevenir_auteurs");
-	if ($prevenir_auteurs == "oui" AND $afficher_texte != "non") {
-	  if ($id_article = $forum_id_article) {
-	    $url = ereg_replace('^/', '', generer_url_article($id_article));
-	    $adresse_site = lire_meta("adresse_site");
-	    $nom_site_spip = lire_meta("nom_site");
-	    $url = "$adresse_site/$url";
-	    $courr = _T('form_forum_message_auto')."\n\n";
-	    $parauteur = '';
-	    if (strlen($auteur) > 2) {
-	      $parauteur = " "._T('forum_par_auteur', array('auteur' => $auteur));
-	      if ($email_auteur) $parauteur .= " <$email_auteur>";
-	    }
-	    $courr .= _T('forum_poste_par', array('parauteur' => $parauteur))."\n";
-	    $courr .= _T('forum_ne_repondez_pas')."\n";
-	    $courr .= "$url\n";
-	    $courr .= "\n\n".$titre."\n\n".textebrut(propre($texte))."\n\n$nom_site_forum\n$url_site\n";
-	    $sujet = "[$nom_site_spip] ["._T('forum_forum')."] $titre";
-	    $query = "SELECT auteurs.* FROM spip_auteurs AS auteurs, spip_auteurs_articles AS lien ".
-	      "WHERE lien.id_article='$id_article' AND auteurs.id_auteur=lien.id_auteur";
-	    $result = spip_query($query);
-	    
-	    while ($row = spip_fetch_array($result)) {
-	      $email_auteur = trim($row["email"]);
-	      if (strlen($email_auteur) < 3) continue;
-	      envoyer_mail($email_auteur, $sujet, $courr);
-	    }
-	  }
-	}
-	// destruction du formulaire (on pourrait leconserver
-	// car il ne contient rien de spe'cifique (php dynamique)
-	//  mais il est statistiquement peu re'utilise')
-	// destruction de la page ayant de'clenche' le formulaire si non mode're'
-
-	$cache = rawurldecode($cache);
-
-	if (file_exists('inc-invalideur.php3'))
-	  {
-	    include_local('inc-invalideur.php3');
-	    if ($statut != 'publie')
-	      applique_invalideur(array($var_cache));
-	    else {
-	      include_local('inc-calcul_mysql3.php');
-	      suivre_invalideur("id_forum='" .
+		//
+		// INVALIDATION DES CACHES LIES AUX FORUMS
+		//
+		include_ecrire('inc_invalideur.php3');
+		if ($statut == 'publie') {
+			suivre_invalideur ("id_forum='" .
 				calcul_index_forum($forum_id_article,
-						   $forum_id_breve,
-						   $forum_id_rubrique,
-						   $forum_id_syndic) .
+					$forum_id_breve,
+					$forum_id_rubrique,
+					$forum_id_syndic) .
 				"'",
 				'spip_id_forum_caches');
-	    }
-	  }
-	// trou de sécurité si on ne vérifie pas
-	// (code transitoire ne cas d'absence d'invalideur)
-	//	else 
-	//	  {
-	// @unlink($var_cache);
-	// if ($statut == 'publie') @unlink($cache);
-	//  }
-    }
-    $redirect = $retour_forum;
- }
+		}
+
+		$redirect = $retour_forum;
+
+
+		//
+		// Envoi d'un mail aux auteurs
+		//
+		$prevenir_auteurs = lire_meta("prevenir_auteurs");
+		if ($prevenir_auteurs == "oui" AND $afficher_texte != "non") {
+			if ($id_article = $forum_id_article) {
+				$url = ereg_replace('^/', '', generer_url_article($id_article));
+				$adresse_site = lire_meta("adresse_site");
+				$nom_site_spip = lire_meta("nom_site");
+				$url = "$adresse_site/$url";
+				$courr = _T('form_forum_message_auto')."\n\n";
+				$parauteur = '';
+				if (strlen($auteur) > 2) {
+					$parauteur = " "._T('forum_par_auteur',
+					array('auteur' => $auteur));
+					if ($email_auteur)
+						$parauteur .= " <$email_auteur>";
+				}
+				$courr .= _T('forum_poste_par',
+				array('parauteur' => $parauteur))."\n";
+				$courr .= _T('forum_ne_repondez_pas')."\n";
+				$courr .= "$url\n";
+				$courr .= "\n\n".$titre."\n\n".textebrut(propre($texte)).
+				"\n\n$nom_site_forum\n$url_site\n";
+				$sujet = "[$nom_site_spip] ["._T('forum_forum')."] $titre";
+				$query = "SELECT auteurs.* FROM spip_auteurs AS auteurs,
+				spip_auteurs_articles AS lien
+				WHERE lien.id_article='$id_article'
+				AND auteurs.id_auteur=lien.id_auteur";
+				$result = spip_query($query);
+
+				while ($row = spip_fetch_array($result)) {
+					$email_auteur = trim($row["email"]);
+					if (strlen($email_auteur) < 3) continue;
+					envoyer_mail($email_auteur, $sujet, $courr);
+				}
+			}
+		}
+
+	}
+}
+
 ?>
diff --git a/inc-public-global.php3 b/inc-public-global.php3
index 1fa0a8ea24b7ede3c5735b91797943d5b10681b4..276133705a2b4cd0c34711414b2775b9473f7674 100644
--- a/inc-public-global.php3
+++ b/inc-public-global.php3
@@ -4,23 +4,169 @@
 if (defined("_INC_PUBLIC_GLOBAL")) return;
 define("_INC_PUBLIC_GLOBAL", "1");
 
-function inclure_subpage($fond, $delais_inclus, $contexte_inclus, $cache_incluant) {
-	// ce perdant de PHP ne comprend pas f(x)[y]
-	$page = inclure_page($fond, $delais_inclus, $contexte_inclus, $cache_incluant);
-	return $page['texte']; 
+
+//
+// Aller chercher la page dans le cache ou pas
+//
+function obtenir_page ($contexte, $chemin_cache, $delais, $use_cache, $fond, $inclusion=false) {
+	global $lastmodified;
+
+	if (!$use_cache) {
+		include_local('inc-calcul.php3');
+
+		// page globale ? calculer le contexte
+		if (!$contexte)
+			$contexte = calculer_contexte();
+
+		spip_timer();
+		$page = calculer_page($chemin_cache,
+			array('fond' => $fond,
+				'contexte' => $contexte,
+				'var_recherche' => $HTTP_GET_VARS['var_recherche']),
+			$delais,
+			$inclusion);
+		if ($chemin_cache)
+			$lastmodified = filemtime($chemin_cache);
+		spip_log (($inclusion ? 'inclus':'calcul').' ('.spip_timer().
+		"): $chemin_cache");
+	} else {
+		$f = fopen($chemin_cache, "r") OR die ("Fichier cache illisible");
+		$page['texte'] = fread($f, filesize($chemin_cache));
+		fclose ($f);
+		# spip_log ("cache $chemin_cache");
+	}
+
+	// Supprimer la carte d'identite du squelette
+	if (preg_match("/^<!-- ([^\n]*) -->\n/", $page['texte'], $match))
+		$page['texte'] = substr($page['texte'], strlen($match[0]));
+
+	return $page;
+}
+
+
+//
+// Appeler cette fonction pour obtenir la page principale
+//
+function afficher_page_globale ($fond, $delais) {
+	global $flag_preserver, $flag_dynamique, $recalcul, $last_modified;
+	include_local ("inc-cache.php3");
+
+	$chemin_cache = 'CACHE/'.generer_nom_fichier_cache('', $fond);
+	$lastmodified = determiner_cache($delais, $use_cache, $chemin_cache);
+	if ($lastmodified)
+		$gmoddate = gmdate("D, d M Y H:i:s", $lastmodified);
+
+	// Repondre gentiment aux requetes sympas
+	if ($GLOBALS['HTTP_IF_MODIFIED_SINCE'] && ($recalcul != oui)) {
+		$headers_only = (trim(str_replace('GMT', '',
+			ereg_replace(';.*$', '', $GLOBALS['HTTP_IF_MODIFIED_SINCE'])))
+			== $gmoddate);
+		if ($headers_only)
+			http_status(304);
+	}
+	else {
+		$headers_only  = ($GLOBALS['HTTP_SERVER_VARS']['REQUEST_METHOD'] == 'HEAD');
+	}
+
+	if ($headers_only) {
+		@header("Last-Modified: $gmoddate GMT");
+		@header("Connection: close");
+		// Pas de bouton admin pour un HEAD
+		$flag_preserver = true;
+	}
+	else {
+		// Obtenir la page
+		$page = obtenir_page ('', $chemin_cache, $delais, $use_cache,
+		$fond, false);
+
+		//
+		// Entetes
+		//
+
+		// Interdire au client de cacher un login, un admin ou un recalcul
+		if ($flag_dynamique OR ($recalcul == 'oui')
+		OR $GLOBALS['HTTP_COOKIE_VARS']['spip_admin']) {
+			@header("Cache-Control: no-cache,must-revalidate");
+			@header("Pragma: no-cache");
+			$lastmodified = time()+3600;	// ne pas autoriser les
+											// inclus a rejouer ce header
+		} else if ($lastmodified) {
+			$gmoddate = gmdate("D, d M Y H:i:s", $lastmodified);
+			@header("Last-Modified: $gmoddate GMT");
+		}
+
+		if ($xhtml) {
+			// Si Mozilla et tidy actif, passer en "application/xhtml+xml"
+			// extremement risque: Mozilla passe en mode debugueur strict
+			// mais permet d'afficher du MathML directement dans le texte
+			// (et sauf erreur, c'est la bonne facon de declarer du xhtml)
+			include_ecrire("inc_tidy.php");
+			if (version_tidy() > 0) {
+				if (ereg("application/xhtml\+xml", $GLOBALS['HTTP_ACCEPT'])) 
+					@header("Content-Type: application/xhtml+xml; ".
+					"charset=".lire_meta('charset'));
+				else 
+					@header("Content-Type: text/html; ".
+					"charset=".lire_meta('charset'));
+					
+				echo '<'.'?xml version="1.0" encoding="'.
+				lire_meta('charset').'"?'.">\n";
+			} else {
+				@header("Content-Type: text/html; ".
+				"charset=".lire_meta('charset'));
+			}
+		} else {
+			@header("Content-Type: text/html; charset=".lire_meta('charset'));
+		}
+
+		//
+		// Envoyer le body
+		//
+		$texte = admin_page($use_cache, $page['texte']);
+		eval('?' . '>' . $texte);
+	}
+
+	# Toutes les heures, menage d'un cache si le processus n'a rien recalcule.
+	# On nettoie celui de la page retournee car le systeme vient d'y acceder:
+	# il y a de bonnes chances qu'il l'ait toujours dans son cache.
+
+	if ($use_cache && (time() - lire_meta('date_purge_cache') > 3600)) {
+		ecrire_meta('date_purge_cache', time());
+#		retire_vieux_caches($cle, $delais);
+	}
+
+	// Mise a jour des fichiers langues de l'espace public
+	if ($GLOBALS['cache_lang_modifs']) {
+		include_ecrire('inc_lang.php3');
+		ecrire_caches_langues();
+	}
+
+	// Calculs en background
+	if ($use_cache)
+		taches_de_fond();
+
+	// Gestion des statistiques du site public
+	// (a la fin pour ne pas forcer le $db_ok)
+	if (lire_meta("activer_statistiques") != "non") {
+		include_local ("inc-stats.php3");
+		ecrire_stats();
+	}
 }
 
 function inclure_page($fond, $delais_inclus, $contexte_inclus, $cache_incluant='') {
-	global $delais;
-	static $pile_delais = '', $ptr_delais = 0;
+	global $delais, $lastmodified;
+
+/*
+static $pile_delais = '', $ptr_delais = 0;
 	$ptr_delais++;
 	$pile_delais[$ptr_delais] = $delais_inclus;
+*/
 
 	spip_log("Inclusion dans $cache_incluant");
-	$cle = $fond;
-	if ($contexte_inclus)
-		foreach($contexte_inclus as $k=>$v)
-			$cle .= "&$k=$v";
+	$contexte = $contexte_inclus;
+	$contexte['fond'] = $fond;
+
+	$chemin_cache = 'CACHE/'.generer_nom_fichier_cache($contexte, $fond);
 
 	// Si on a inclus sans fixer le critere de lang, de deux choses l'une :
 	// - on est dans la langue du site, et pas besoin d'inclure inc_lang
@@ -32,27 +178,23 @@ function inclure_page($fond, $delais_inclus, $contexte_inclus, $cache_incluant='
 		$lang_select = true; // pour lang_dselect ci-dessous
 	}
 
-	$page = ramener_cache($cle,
-			  'cherche_page_incluse',
-			  array('fond' => $fond, 
-				'cache_incluant' => $cache_incluant,
-				'contexte' => $contexte_inclus),
-			  $pile_delais[$ptr_delais]);
-	
+	// @header ne marchera qu'en output_buffering
+	$lastmod = determiner_cache($delais, $use_cache, $chemin_cache);
+	if ($lastmod > $lastmodified) {
+		$lastmodified = $lastmod;
+		$gmoddate = gmdate("D, d M Y H:i:s", $lastmodified);
+		@header("Last-Modified: $gmoddate GMT");
+	}
+
+	$page = obtenir_page ($contexte_inclus, $chemin_cache, $delais,
+	$use_cache, $fond, true);
+
+	// Et enfin le contenu...
+	eval('?' . '>' . $page['texte']);
+
 	if ($lang_select)
 		lang_dselect();
 
-	// si son de'lai est + court que l'incluant, il pre'domine
-	if ($ptr_delais == 1) {
-		if ($delais > $pile_delais[$ptr_delais])
-			$delais = $pile_delais[$ptr_delais];
-	}
-	else { 
-		if ($pile_delais[$ptr_delais-1] > $pile_delais[$ptr_delais])
-			$pile_delais[$ptr_delais-1] = $pile_delais[$ptr_delais];
-	}
-	$ptr_delais--;
-	return $page;
 }
 
 //
@@ -62,7 +204,7 @@ function admin_page($cached, $texte) {
 	if (!$GLOBALS['flag_preserver']
 	&& ($admin = $GLOBALS['HTTP_COOKIE_VARS']['spip_admin'])) {
 		include_local('inc-admin.php3');
-		$a = afficher_boutons_admin($cached ? ' *' : '');
+		$a = '<'.'?php echo afficher_boutons_admin("'. ($cached ? ' *' : '').'"); ?'.'>';
 
 		// La constante doit etre definie a l'identique dans inc-form-squel
 		// balise #FORMULAIRE_ADMIN ? sinon ajouter en fin de page
@@ -83,7 +225,7 @@ function cherche_image_nommee($nom, $dossier) {
 	}
 }
 
-function taches_de_fond($use_cache) {
+function taches_de_fond() {
 	// Gestion des taches de fond ?  toutes les 5 secondes
 	// (on mettra 30 s quand on aura prevu la preemption par une image-cron)
 	if (!@file_exists('ecrire/data/cron.lock')
@@ -93,16 +235,9 @@ function taches_de_fond($use_cache) {
 		if (!@file_exists('ecrire/data/mysql_out')
 		OR (time() - @filemtime('ecrire/data/mysql_out') > 300)) {
 			include_ecrire('inc_cron.php3');
-			spip_cron($use_cache);
+			spip_cron();
 		}
 	}
-
-	// Gestion des statistiques du site public
-	// (a la fin pour ne pas forcer le $db_ok)
-	if (lire_meta("activer_statistiques") != "non") {
-		include_local ("inc-stats.php3");
-		ecrire_stats();
-	}
 }
 
 ?>
diff --git a/inc-public.php3 b/inc-public.php3
index 3e9199b3a69cc062d1cf44a0f5e1fcc6dda4c5a7..22d1dbf219e31c97235e938654c7d90b097b662d 100644
--- a/inc-public.php3
+++ b/inc-public.php3
@@ -1,192 +1,72 @@
 <?php
 
-if (defined("_INC_PUBLIC")) { // inclusion différée
-	$page = inclure_page($fond, $delais, $contexte_inclus);
-	if ($page['process_ins'])
-    {
-    	eval('?' . '>' .  $page['texte']); 
-    }
-	else
-	{ 
+// Page inclue ?
+if (defined("_INC_PUBLIC")) {
+	$page = inclure_page($fond, $delais, $contexte_inclus, $fichier_inclus);
+
+	/* if ($page['process_ins']) {
+		eval('?' . '>' .  $page['texte']); 
+	} else { 
 		echo $page['texte']; 
-	}
-} else {
-	// premier appel
-	define("_INC_PUBLIC", "1");
-	
+	} */
 
-	# Variable indiquant l'extension du fichier du squelette 
-	# (peut etre changé dans mes_option via inc_version; en 'xml' pour + tard)
-	$GLOBALS['extension_squelette'] = 'html';
-	# Variable indiquant le répertoires des images
-	$GLOBALS['dossier_images'] = 'IMG';
+	eval('?' . '>' .  $page['texte']); 
+}
 
+// Premier appel inc-public
+else {
+	define("_INC_PUBLIC", "1");
 	include ("ecrire/inc_version.php3");
-	if ($INSECURE['fond'] || $INSECURE['delais']) exit;
 
-	if ($HTTP_COOKIE_VARS['spip_session'] OR ($PHP_AUTH_USER AND !$ignore_auth_http)) {
+	//
+	// Initialisations
+	//
+
+	// Regler le $delais par defaut
+	if ($INSECURE['fond'] || $INSECURE['delais'])
+		exit;
+	if (!isset($delais))
+		$delais = 1 * 3600;
+	if ($recherche)
+		$delais = 0;
+
+	// les meta
+	include_ecrire("inc_meta.php3");
+
+	// multilinguisme
+	if ($GLOBALS['HTTP_COOKIE_VARS']['spip_session'] OR
+	($GLOBALS['PHP_AUTH_USER'] AND !$ignore_auth_http)) {
 		include_ecrire ("inc_session.php3");
 		verifier_visiteur();
 	}
- 
-	if ($forcer_lang) {
+ 	if ($GLOBALS['forcer_lang']) {
 		include_ecrire('inc_lang.php3');
 		verifier_lang_url();
 	}
-	if ($lang = $HTTP_GET_VARS['lang']) {
+	if ($lang = $GLOBALS['HTTP_GET_VARS']['lang']) {
 		include_ecrire('inc_lang.php3');
 		lang_select($lang);     
 	}
 
-	include_ecrire("inc_meta.php3");
-
-	// ajout_forum est une HTTP_GET_VAR installée par retour_forum dans inc-forum.
-	// Il s'agit de pirater les HTTP_POST_VARS, afin de mettre en base
-	// les valeurs transmises, avant réaffichage du formulaire avec celles-ci.
-	// En cas de validation finale ça redirige vers l'URL ayant provoqué l'appel
-	// au lieu de laisser l'URL appelée resynthétiser le formulaire.
 
+	// Ajout_forum est une HTTP_GET_VARS installee par retour_forum dans
+	// inc-forum.
+	// Il s'agit de memoriser les HTTP_POST_VARS, afin de mettre en base
+	// les valeurs transmises, avant reaffichage du formulaire avec celles-ci.
+	// En cas de validation finale ca redirige vers l'URL ayant provoque l'appel
+	// au lieu de laisser l'URL appelee resynthetiser le formulaire.
 	if ($ajout_forum) {
 		$redirect = '';
 		include('inc-messforum.php3');
 		if ($redirect) {
-			header("Location: $redirect");exit();
+			@header("Location: $redirect");
+			exit();
 		}
 	}
 
 	include_local ("inc-public-global.php3");
-	include_local ("inc-cache.php3");
-	if (file_exists("inc-urls.php3")) {
-		include_local ("inc-urls.php3");
-		}
-		else {
-		include_local ("inc-urls-dist.php3");
-		}
-
-	if (!isset($delais)) $delais = 1 * 3600;
-
-	$contexte = $GLOBALS['HTTP_GET_VARS'];
-	if ($GLOBALS['date'])
-		$contexte['date'] = $contexte['date_redac'] = date($GLOBALS['date']);
-	else
-		$contexte['date'] = $contexte['date_redac'] = date("Y-m-d H:i:s");
-
-	$cle = eregi_replace('&(submit|valider|PHPSESSID|(var_[^=&]*)|recalcul)=[^&]*',
-			     '',
-			     strtr($GLOBALS['REQUEST_URI'], '?', '&'));
-
-	// Analyser les URLs personnalisees (inc-urls-...)
-	/* attention c'est assez sale : ça affecte la variable globale $contexte */
-	recuperer_parametres_url($fond, $cle);
-
-	$lastmodified = cv_du_cache($cle, $delais);
-	$gmoddate = gmdate("D, d M Y H:i:s", $lastmodified);
-
-	spip_log($HTTP_SERVER_VARS['REQUEST_METHOD'] . " $HTTP_IF_MODIFIED_SINCE $GLOBALS[PHP_SELF]" .  $GLOBALS['recalcul']);
+	afficher_page_globale ($fond, $delais);
 
-	// Code inoperant si le serveur HTTP traite ce champ en amont.
-	if ($HTTP_IF_MODIFIED_SINCE && ($GLOBALS['recalcul'] != oui))
-	{
-		$headers_only = (trim(str_replace('GMT', '', ereg_replace(';.*$', '', $HTTP_IF_MODIFIED_SINCE))) == $gmoddate);
-		if ($headers_only) http_status(304);
-	}
-	else 
-	{
-		$headers_only  = ($HTTP_SERVER_VARS['REQUEST_METHOD'] == 'HEAD');
-	}
-
-	if ($headers_only)
-	{
-		header("Last-Modified: $gmoddate GMT");
-		header("Connection: close");
-		spip_log("Close, lastmodified: $gmoddate");
-	}
-	else
-	{
-		$fraicheur = $delais;
-		$page = ramener_cache(	$cle,
-					'cherche_page_incluante', 
-					array(	'fond' => $fond,
-						'contexte' => $contexte,
-						'var_recherche' => $HTTP_GET_VARS['var_recherche']),
-			$delais);
-		# si la page est neuve, recalculer ces 2 valeurs
-		if (!$page['naissance'])
-		{
-			$lastmodified = cv_du_cache($cle, $fraicheur);
-			$gmoddate = gmdate("D, d M Y H:i:s", $lastmodified);
-		}
-		// interdire au client de cacher un login, un admin ou un recalcul
-		if (!$flag_dynamique && $recalcul != 'oui' && !$HTTP_COOKIE_VARS['spip_admin'])
-		{
-			$expire = gmdate("D, d M Y H:i:s", $lastmodified + $delais)." GMT";
-		}
-		else 
-		{
-			$expire = "0";
-			header("Cache-Control: no-cache,must-revalidate");
-			header("Pragma: no-cache");
-		}
-			
-		header("Last-Modified: $gmoddate GMT");
-
-		if ($xhtml) 
-		{
-			// Si Mozilla et tidy actif, passer en "application/xhtml+xml"
-			// extremement risque: Mozilla passe en mode debugueur strict
-			// mais permet d'afficher du MathML directement dans le texte
-			// (et sauf erreur, c'est la bonne facon de declarer du xhtml)
-			include_ecrire("inc_tidy.php");
-			if (version_tidy() > 0) {		
-				if (ereg("application/xhtml\+xml", $HTTP_ACCEPT)) 
-					@header("Content-Type: application/xhtml+xml; charset=".lire_meta('charset'));
-				else 
-					@header("Content-Type: text/html; charset=".lire_meta('charset'));
-					
-				echo '<'.'?xml version="1.0" encoding="'.lire_meta('charset').'"?'.">\n";
-			} else {
-				@header("Content-Type: text/html; charset=".lire_meta('charset'));
-			}
-		} else {
-			@header("Content-Type: text/html; charset=".lire_meta('charset'));
-		}
-		
-		$texte = admin_page($page['naissance'], $page['texte']);
-		
-		if ($page['process_ins'] == 'php') {
-			eval('?' . '>' . $texte);
-		}
-		else
-		{ 
-			$n = strlen($texte);
-			# L'envoi du content-Length ci-dessous permet d'envoyer d'autres reponses
-			# dans le cadre des connexions persistantes de HTTP1
-			# Elle doit s'accompagner du connection-close sinon
-			# elle retarde l'affichage de certains navigateurs.
-			# On l'a desactivee ici puisqu'il n'y a qu'une seule reponse, 
-			# et que certains serveurs la calculent et maintiennent la connexion
-			# header("Content-Length: " . $n);
-			# header("Connection: close");
-			 echo $texte; 
-			 spip_log("Page 100% HTML (" . $n  . " octets)");
-		}
-   }
-
-	# Toutes les heures, menage d'un cache si le processus n'a rien recalcule.
-	# On nettoie celui de la page retournee car le systeme vient d'y acceder:
-	# il y a de bonnes chances qu'il l'ait toujours dans son cache.
-
-	if ($page['naissance'] && (time() - lire_meta('date_purge_cache') > 3600)) {
-		ecrire_meta('date_purge_cache', time());
-		retire_vieux_caches($cle, $delais);
-	}
-
-	# Mise a jour des fichiers langues de l'espace public
-	if ($cache_lang_modifs) {
-		include_ecrire('inc_lang.php3');
-		ecrire_caches_langues();
-	}
+}
 
-	taches_de_fond($page['naissance']);
-} // fin du defined
 ?>
\ No newline at end of file
diff --git a/inc-spip_cache_mysql3.php b/inc-spip_cache_mysql3.php
deleted file mode 100644
index 6ced322d95969f0f7b98f48848bfd9930c744594..0000000000000000000000000000000000000000
--- a/inc-spip_cache_mysql3.php
+++ /dev/null
@@ -1,48 +0,0 @@
-<?php
-// Ce fichier ne sera execute qu'une fois
-if (defined("_SPIP_CACHE_MYSQL3")) return;
-define("_SPIP_CACHE_MYSQL3", "1");
-
-function changer_statut_forum($id_forum, $statut) {
-
-	$forum_parents = array('id_rubrique', 'id_article', 'id_breve', 'id_syndic');
-
-$result = spip_query("
-SELECT	id_parent, " . join(",", $forum_parents) . "
-FROM	spip_forum 
-WHERE	id_forum=$id_forum
-");
-
- 	if (!($row = spip_fetch_array($result))) return;
-	$id_parent = $row['id_parent'];
-	if (file_exists('inc-invalideur.php3'))
-	  {
-	    include('inc-invalideur.php3');
-	    foreach ($forum_parents as $id)
-	      { if ($id_num = $row[$id])
-		  suivre_invalideur("$id='$id_num'", 
-				    "spip_" . $id . '_caches');
-	      }
-	  }
-
-	// signaler au moteur de recherche qu'il faut reindexer le thread
-	// (en fait on se contente de demander une reindexation du parent)
-	include_ecrire('inc_index.php3');
-	marquer_indexer ('forum', $id_parent);
-
-	// changer le statut de toute l'arborescence dependant de ce message
-	$id_messages = array($id_forum);
-	while ($id_messages) {
-		$id_messages = join(',', $id_messages);
-		$query_forum = "UPDATE spip_forum SET statut='$statut' WHERE id_forum IN ($id_messages)";
-		$result_forum = spip_query($query_forum);
-		$query_forum = "SELECT id_forum FROM spip_forum WHERE id_parent IN ($id_messages)";
-		$result_forum = spip_query($query_forum);
-		unset($id_messages);
-		while ($row = spip_fetch_array($result_forum)) {
-			$id_messages[] = $row['id_forum'];
-		}
-	}
-}
-
-?>
diff --git a/inc-text-squel.php3 b/inc-text-squel.php3
index bfa1b58a19a6e87f67c090df71ed97fc12e3652d..ca166b234ebcb0c8b76c36f44c7b782472a9445e 100644
--- a/inc-text-squel.php3
+++ b/inc-text-squel.php3
@@ -31,7 +31,8 @@ function calculer_inclure($fichier, $params, $id_boucle, &$boucles, $pi) {
 		}
 	}
 	return "\n'<".
-		"?php\n\t\$contexte_inclus = array($criteres);\n" .
+		"?php\n\t\$contexte_inclus = array($criteres);\n\t".
+		"\$fichier_inclus = \'$fichier\';\n" .
 		(($dossier_squelettes) ?
 		("
 			if (@file_exists(\'$dossier_squelettes/$fichier\')){
@@ -39,8 +40,8 @@ function calculer_inclure($fichier, $params, $id_boucle, &$boucles, $pi) {
 			} else {
 				include(\'$fichier\');
 			} " ) :
-		("include(\'$fichier\');")) .
-		"?" . ">'";
+		("\tinclude(\'$fichier\');")) .
+		"\n?'." . "'>'";
 }
 
 // Convertit un texte Spip en une EXPRESSION php 
diff --git a/spip_cache.php3 b/spip_cache.php3
index b0cd2efddd4bc20d465629a4af3d3b98fc4bca2c..dde94966cb8c1c14d7bb33b2d9e4807bc5e5b645 100644
--- a/spip_cache.php3
+++ b/spip_cache.php3
@@ -4,25 +4,63 @@ include ("ecrire/inc_version.php3");
 
 include_ecrire("inc_meta.php3");
 include_ecrire("inc_admin.php3");
-
 include_local("inc-cache.php3");
 
 if ($purger_cache == "oui") {
 	if (verifier_action_auteur("purger_cache", $hash, $id_auteur)) {
-	  retire_caches_pages();
-	  retire_caches_squelette();
+		include_ecrire('inc_invalideur.php3');
+		supprime_invalideurs();
+		purger_repertoire('CACHE', 0);
 	}
 }
 
 if ($purger_squelettes == "oui") {
 	if (verifier_action_auteur("purger_squelettes", $hash, $id_auteur))
-	  retire_caches_squelette();
+		purger_repertoire('CACHE', 0, '^skel_');
+}
+
+
+//
+// Suppression de forums
+//
+function changer_statut_forum($id_forum, $statut) {
+	$forum_parents = array('id_rubrique', 'id_article', 'id_breve', 'id_syndic');
+	$result = spip_query("SELECT id_parent, " . join(",", $forum_parents) .
+	" FROM spip_forum WHERE id_forum=$id_forum");
+
+	if (!($row = spip_fetch_array($result)))
+		return;
+
+	$id_parent = $row['id_parent'];
+	include_ecrire('inc_invalideur.php3');
+	foreach ($forum_parents as $id) {
+		if ($id_num = $row[$id])
+			suivre_invalideur("$id='$id_num'", "spip_" . $id . '_caches');
 	}
 
+	// Signaler au moteur de recherche qu'il faut reindexer le thread
+	include_ecrire('inc_index.php3');
+	marquer_indexer ('forum', $id_parent);
+
+	// changer le statut de toute l'arborescence dependant de ce message
+	$id_messages = array($id_forum);
+	while ($id_messages) {
+		$id_messages = join(',', $id_messages);
+		$query_forum = "UPDATE spip_forum SET statut='$statut'
+		WHERE id_forum IN ($id_messages)";
+		$result_forum = spip_query($query_forum);
+		$query_forum = "SELECT id_forum FROM spip_forum
+		WHERE id_parent IN ($id_messages)";
+		$result_forum = spip_query($query_forum);
+		unset($id_messages);
+		while ($row = spip_fetch_array($result_forum))
+			$id_messages[] = $row['id_forum'];
+	}
+}
+
 if ($supp_forum OR $supp_forum_priv OR $valid_forum) {
 	$verif = $supp_forum ? "supp_forum $supp_forum" : ($supp_forum_priv ? "supp_forum_priv $supp_forum_priv" : "valid_forum $valid_forum");
 	if (verifier_action_auteur($verif, $hash, $id_auteur)) {
-		include_local("inc-spip_cache_mysql3.php");
 		if ($supp_forum) 
 			changer_statut_forum($supp_forum, 'off');
 		else if ($supp_forum_priv)
@@ -30,7 +68,7 @@ if ($supp_forum OR $supp_forum_priv OR $valid_forum) {
 		else if ($valid_forum)
 			changer_statut_forum($valid_forum, 'publie');
 	}
- }
+}
  
 
 @header ("Location: ./ecrire/" . $redirect);