From 727a64cee8d1976a47a9fe928f943694e0c454d4 Mon Sep 17 00:00:00 2001
From: "Committo,Ergo:sum" <esj@rezo.net>
Date: Fri, 16 Jul 2004 07:20:03 +0000
Subject: [PATCH] refonte du compilateur et du cache

---
 ecrire/inc_auxbase.php3    |  357 ++++++
 ecrire/inc_base.php3       | 1481 +---------------------
 ecrire/inc_cron.php3       |   96 +-
 ecrire/inc_majbase.php3    |  830 ++++++++++++
 ecrire/inc_serialbase.php3 |  333 +++++
 ecrire/inc_surligne.php3   |  127 +-
 inc-admin.php3             |  105 +-
 inc-arg-squel.php3         |  310 +++++
 inc-bcl-squel.php3         |   52 +
 inc-cache.php3             |  527 +++++---
 inc-calcul-squel.php3      | 2429 ++++++------------------------------
 inc-calcul.php3            |  641 +++-------
 inc-calcul_html4.php       |  143 +++
 inc-calcul_mysql3.php      |  223 ++++
 inc-champ-squel.php3       |  543 +++-----
 inc-chercher.php3          |   46 +
 inc-debug-squel.php3       |   52 +-
 inc-debug.php3             |   12 +-
 inc-dir.php3               |  104 ++
 inc-form-squel.php3        |  200 +++
 inc-formulaires.php3       |    4 +-
 inc-forum.php3             |  712 ++++-------
 inc-html-squel.php3        |  324 +++++
 inc-index-squel.php3       |  144 +++
 inc-invalideur.php3        |  125 ++
 inc-login.php3             |   65 +-
 inc-logo-squel.php3        |  243 ++++
 inc-messforum.php3         |  166 +++
 inc-public-global.php3     |  411 ++----
 inc-public.php3            |  158 ++-
 inc-reqsql-squel.php3      |  139 +++
 inc-stats.php3             |    2 +-
 inc-text-squel.php3        |  109 ++
 inc-vrac-squel.php3        |  286 +++++
 spip_cache.php3            |   14 +-
 spip_image.php3            |   28 +
 36 files changed, 5966 insertions(+), 5575 deletions(-)
 create mode 100644 ecrire/inc_auxbase.php3
 create mode 100644 ecrire/inc_majbase.php3
 create mode 100644 ecrire/inc_serialbase.php3
 create mode 100644 inc-arg-squel.php3
 create mode 100644 inc-bcl-squel.php3
 create mode 100644 inc-calcul_html4.php
 create mode 100644 inc-calcul_mysql3.php
 create mode 100644 inc-chercher.php3
 create mode 100644 inc-dir.php3
 create mode 100644 inc-form-squel.php3
 create mode 100644 inc-html-squel.php3
 create mode 100644 inc-index-squel.php3
 create mode 100644 inc-invalideur.php3
 create mode 100644 inc-logo-squel.php3
 create mode 100644 inc-messforum.php3
 create mode 100644 inc-reqsql-squel.php3
 create mode 100644 inc-text-squel.php3
 create mode 100644 inc-vrac-squel.php3

diff --git a/ecrire/inc_auxbase.php3 b/ecrire/inc_auxbase.php3
new file mode 100644
index 0000000000..988d1bd3eb
--- /dev/null
+++ b/ecrire/inc_auxbase.php3
@@ -0,0 +1,357 @@
+<?php
+
+// Ce fichier ne sera execute qu'une fois
+if (defined("_ECRIRE_INC_AUXBASE")) return;
+define("_ECRIRE_INC_AUXBASE", "1");
+
+$spip_petitions = array(
+		"id_article"	=> "BIGINT (21) DEFAULT '0' NOT NULL",
+		"email_unique"	=> "CHAR (3) NOT NULL",
+		"site_obli"	=> "CHAR (3) NOT NULL",
+		"site_unique"	=> "CHAR (3) NOT NULL",
+		"message"	=> "CHAR (3) NOT NULL",
+		"texte"	=> "LONGBLOB NOT NULL",
+		"maj"	=> "TIMESTAMP");
+
+$spip_petitions_key = array(
+		"PRIMARY KEY"	=> "id_article");
+
+$spip_visites_temp = array(
+		"ip"	=> "INT UNSIGNED NOT NULL",
+		"type"	=> "ENUM ('article', 'rubrique', 'breve', 'autre') NOT NULL",
+		"id_objet"	=> "INT UNSIGNED NOT NULL",
+		"maj"	=> "TIMESTAMP");
+
+$spip_visites_temp_key = array(
+		"PRIMARY KEY"	=> "type, id_objet, ip");
+
+$spip_visites = array(
+		"date"	=> "DATE NOT NULL",
+		"visites"	=> "INT UNSIGNED NOT NULL",
+		"maj"	=> "TIMESTAMP");
+
+$spip_visites_key = array(
+		"PRIMARY KEY"	=> "date");
+
+$spip_visites_articles = array(
+		"date"	=> "DATE NOT NULL",
+		"id_article"	=> "INT UNSIGNED NOT NULL",
+		"visites"	=> "INT UNSIGNED NOT NULL",
+		"maj"	=> "TIMESTAMP");
+
+$spip_visites_articles_key = array(
+		"PRIMARY KEY"	=> "date, id_article");
+
+$spip_referers_temp = array(
+		"ip"	=> "INT UNSIGNED NOT NULL",
+		"referer"	=> "VARCHAR (255) NOT NULL",
+		"referer_md5"	=> "BIGINT UNSIGNED NOT NULL",
+		"type"	=> "ENUM ('article', 'rubrique', 'breve', 'autre') NOT NULL",
+		"id_objet"	=> "INT UNSIGNED NOT NULL",
+		"maj"	=> "TIMESTAMP");
+
+$spip_referers_temp_key = array(
+		"PRIMARY KEY"	=> "type, id_objet, referer_md5, ip");
+
+$spip_referers = array(
+		"referer_md5"	=> "BIGINT UNSIGNED NOT NULL",
+		"date"		=> "DATE NOT NULL",
+		"referer"	=> "VARCHAR (255) NOT NULL",
+		"visites"	=> "INT UNSIGNED NOT NULL",
+		"visites_jour"	=> "INT UNSIGNED NOT NULL",
+		"maj"		=> "TIMESTAMP");
+
+$spip_referers_key = array(
+		"PRIMARY KEY"	=> "referer_md5");
+
+$spip_referers_articles = array(
+		"id_article"	=> "INT UNSIGNED NOT NULL",
+		"referer_md5"	=> "BIGINT UNSIGNED NOT NULL",
+		"date"		=> "DATE NOT NULL",
+		"referer"	=> "VARCHAR (255) NOT NULL",
+		"visites"	=> "INT UNSIGNED NOT NULL",
+		"maj"		=> "TIMESTAMP");
+
+$spip_referers_articles_key = array(
+		"PRIMARY KEY"	=> "id_article, referer_md5",
+		"KEY referer_md5"	=> "referer_md5");
+
+$spip_auteurs_articles = array(
+		"id_auteur"	=> "BIGINT (21) DEFAULT '0' NOT NULL",
+		"id_article"	=> "BIGINT (21) DEFAULT '0' NOT NULL");
+
+$spip_auteurs_articles_key = array(
+		"KEY id_auteur"	=> "id_auteur",
+		"KEY id_article"	=> "id_article");
+
+$spip_auteurs_rubriques = array(
+		"id_auteur"	=> "BIGINT (21) DEFAULT '0' NOT NULL",
+		"id_rubrique"	=> "BIGINT (21) DEFAULT '0' NOT NULL");
+
+$spip_auteurs_rubriques_key = array(
+		"KEY id_auteur"	=> "id_auteur",
+		"KEY id_rubrique"	=> "id_rubrique");
+
+$spip_auteurs_messages = array(
+		"id_auteur"	=> "BIGINT (21) DEFAULT '0' NOT NULL",
+		"id_message"	=> "BIGINT (21) DEFAULT '0' NOT NULL",
+		"vu"		=> "CHAR (3) NOT NULL");
+
+$spip_auteurs_messages_key = array(
+		"KEY id_auteur"	=> "id_auteur",
+		"KEY id_message"	=> "id_message");
+
+
+$spip_documents_articles = array(
+		"id_document"	=> "BIGINT (21) DEFAULT '0' NOT NULL",
+		"id_article"	=> "BIGINT (21) DEFAULT '0' NOT NULL");
+
+$spip_documents_articles_key = array(
+		"KEY id_document"	=> "id_document",
+		"KEY id_article"	=> "id_article");
+
+$spip_documents_rubriques = array(
+		"id_document"	=> "BIGINT (21) DEFAULT '0' NOT NULL",
+		"id_rubrique"	=> "BIGINT (21) DEFAULT '0' NOT NULL");
+
+$spip_documents_rubriques_key = array(
+		"KEY id_document"	=> "id_document",
+		"KEY id_rubrique"	=> "id_rubrique");
+
+$spip_documents_breves = array(
+		"id_document"	=> "BIGINT (21) DEFAULT '0' NOT NULL",
+		"id_breve"	=> "BIGINT (21) DEFAULT '0' NOT NULL");
+
+$spip_documents_breves_key = array(
+		"KEY id_document"	=> "id_document",
+		"KEY id_breve"	=> "id_breve");
+
+$spip_mots_articles = array(
+		"id_mot"	=> "BIGINT (21) DEFAULT '0' NOT NULL",
+		"id_article"	=> "BIGINT (21) DEFAULT '0' NOT NULL");
+
+$spip_mots_articles_key = array(
+		"KEY id_mot"	=> "id_mot",
+		"KEY id_article"	=> "id_article");
+
+$spip_mots_breves = array(
+		"id_mot"	=> "BIGINT (21) DEFAULT '0' NOT NULL",
+		"id_breve"	=> "BIGINT (21) DEFAULT '0' NOT NULL");
+
+$spip_mots_breves_key = array(
+		"KEY id_mot"	=> "id_mot",
+		"KEY id_breve"	=> "id_breve");
+
+$spip_mots_rubriques = array(
+		"id_mot"	=> "BIGINT (21) DEFAULT '0' NOT NULL",
+		"id_rubrique"	=> "BIGINT (21) DEFAULT '0' NOT NULL");
+
+$spip_mots_rubriques_key = array(
+		"KEY id_mot"	=> "id_mot",
+		"KEY id_rubrique"	=> "id_rubrique");
+
+$spip_mots_syndic = array(
+		"id_mot"	=> "BIGINT (21) DEFAULT '0' NOT NULL",
+		"id_syndic"	=> "BIGINT (21) DEFAULT '0' NOT NULL");
+
+$spip_mots_syndic_key = array(
+		"KEY id_mot"	=> "id_mot",
+		"KEY id_syndic"	=> "id_syndic");
+
+$spip_mots_forum = array(
+		"id_mot"	=> "BIGINT (21) DEFAULT '0' NOT NULL",
+		"id_forum"	=> "BIGINT (21) DEFAULT '0' NOT NULL");
+
+$spip_mots_forum_key = array(
+		"KEY id_mot"	=> "id_mot",
+		"KEY id_forum"	=> "id_forum");
+
+$spip_meta = array(
+		"nom"	=> "VARCHAR (255) NOT NULL",
+		"valeur"	=> "VARCHAR (255) DEFAULT ''",
+		"maj"	=> "TIMESTAMP");
+
+$spip_meta_key = array(
+		"PRIMARY KEY"	=> "nom");
+
+$spip_index_articles = array(
+		"`hash`"	=> "BIGINT UNSIGNED NOT NULL",
+		"points"	=> "INT UNSIGNED DEFAULT '0' NOT NULL",
+		"id_article"	=> "INT UNSIGNED NOT NULL");
+
+$spip_index_articles_key = array(
+		"KEY `hash`"	=> "`hash`",
+		"KEY id_article"	=> "id_article");
+
+$spip_index_auteurs = array(
+		"`hash`"	=> "BIGINT UNSIGNED NOT NULL",
+		"points"	=> "INT UNSIGNED DEFAULT '0' NOT NULL",
+		"id_auteur"	=> "INT UNSIGNED NOT NULL");
+
+$spip_index_auteurs_key = array(
+		"KEY `hash`"	=> "`hash`",
+		"KEY id_auteur"	=> "id_auteur");
+
+$spip_index_breves = array(
+		"`hash`"	=> "BIGINT UNSIGNED NOT NULL",
+		"points"	=> "INT UNSIGNED DEFAULT '0' NOT NULL",
+		"id_breve"	=> "INT UNSIGNED NOT NULL");
+
+$spip_index_breves_key = array(
+		"KEY `hash`"	=> "`hash`",
+		"KEY id_breve"	=> "id_breve");
+
+$spip_index_mots = array(
+		"`hash`"	=> "BIGINT UNSIGNED NOT NULL",
+		"points"	=> "INT UNSIGNED DEFAULT '0' NOT NULL",
+		"id_mot"	=> "INT UNSIGNED NOT NULL");
+
+$spip_index_mots_key = array(
+		"KEY `hash`"	=> "`hash`",
+		"KEY id_mot"	=> "id_mot");
+
+$spip_index_rubriques = array(
+		"`hash`"	=> "BIGINT UNSIGNED NOT NULL",
+		"points"	=> "INT UNSIGNED DEFAULT '0' NOT NULL",
+		"id_rubrique"	=> "INT UNSIGNED NOT NULL");
+
+$spip_index_rubriques_key = array(
+		"KEY `hash`"	=> "`hash`",
+		"KEY id_rubrique"	=> "id_rubrique");
+
+$spip_index_syndic = array(
+		"`hash`"	=> "BIGINT UNSIGNED NOT NULL",
+		"points"	=> "INT UNSIGNED DEFAULT '0' NOT NULL",
+		"id_syndic"	=> "INT UNSIGNED NOT NULL");
+
+$spip_index_syndic_key = array(
+		"KEY `hash`"	=> "`hash`",
+		"KEY id_syndic"	=> "id_syndic");
+
+$spip_index_signatures = array(
+		"`hash`"	=> "BIGINT UNSIGNED NOT NULL",
+		"points"	=> "INT UNSIGNED DEFAULT '0' NOT NULL",
+		"id_signature"	=> "INT UNSIGNED NOT NULL");
+
+$spip_index_signatures_key = array(
+		"KEY `hash`"		=> "`hash`",
+		"KEY id_signature"	=> "id_signature");
+
+$spip_index_forum = array(
+		"`hash`"	=> "BIGINT UNSIGNED NOT NULL",
+		"points"	=> "INT UNSIGNED DEFAULT '0' NOT NULL",
+		"id_forum"	=> "INT UNSIGNED NOT NULL");
+
+$spip_index_forum_key = array(
+		"KEY `hash`"	=> "`hash`",
+		"KEY id_forum"	=> "id_forum");
+
+$spip_index_dico = array(
+		"`hash`"	=> "BIGINT UNSIGNED NOT NULL",
+		"dico"		=> "VARCHAR (30) NOT NULL");
+
+$spip_index_dico_key = array(
+		"PRIMARY KEY"	=> "dico");
+
+$spip_inclure_caches = array(
+		"hache"		=> "CHAR (64) NOT NULL",
+		"inclure"	=> "CHAR (64) NOT NULL");
+
+$spip_inclure_caches_key = array(
+				 "KEY"	=> "hache",
+				 "KEY"	=> "inclure");
+
+
+$spip_versions = array (
+		"id_article"	=> "bigint(21) NOT NULL",
+		"id_version"	=> "int unsigned DEFAULT '0' NOT NULL",
+		"date"	=> "datetime DEFAULT '0000-00-00 00:00:00' NOT NULL",
+		"id_auteur"	=> "bigint(21) NOT NULL",
+		"titre_version"	=> "text DEFAULT '' NOT NULL",
+		"permanent"	=> "char(3) NOT NULL",
+		"champs"	=> "text NOT NULL");
+
+$spip_versions_key = array (
+		"PRIMARY KEY"	=> "id_article, id_version",
+		"KEY date"	=> "id_article, date",
+		"KEY id_auteur"	=> "id_auteur");
+
+$spip_versions_fragments = array(
+		"id_fragment"	=> "int unsigned DEFAULT '0' NOT NULL",
+		"version_min"	=> "int unsigned DEFAULT '0' NOT NULL",
+		"version_max"	=> "int unsigned DEFAULT '0' NOT NULL",
+		"id_article"	=> "bigint(21) NOT NULL",
+		"compress"	=> "tinyint NOT NULL",
+		"fragment"	=> "longblob NOT NULL");
+
+$spip_versions_fragments_key = array(
+	     "PRIMARY KEY"	=> "id_article, id_fragment, version_min");
+
+global $tables_auxiliaires;
+
+$tables_auxiliaires  = 
+  array(
+	'petitions' => array('field' => &$spip_petitions,
+			     'key' => &$spip_petitions_key),
+	'visites_temp' => array('field' => &$spip_visites_temp,
+				'key' => &$spip_visites_temp_key),
+	'visites' =>	array('field' => &$spip_visites,
+			      'key' => &$spip_visites_key),
+	'visites_articles' => array('field' => &$spip_visites_articles,
+				    'key' => &$spip_visites_articles_key),
+	'referers_temp' => array('field' => &$spip_referers_temp,
+				 'key' => &$spip_referers_temp_key),
+	'referers' => array('field' => &$spip_referers,
+			    'key' => &$spip_referers_key),
+	'referers_articles' => array('field' => &$spip_referers_articles,
+				     'key' => &$spip_referers_articles_key),
+	'auteurs_articles' => array('field' => &$spip_auteurs_articles,
+				    'key' => &$spip_auteurs_articles_key),
+	'auteurs_rubriques' => array('field' => &$spip_auteurs_rubriques,
+				     'key' => &$spip_auteurs_rubriques_key),
+	'auteurs_messages' => array('field' => &$spip_auteurs_messages,
+				    'key' => &$spip_auteurs_messages_key),
+	'documents_articles' => array('field' => &$spip_documents_articles,
+				      'key' => &$spip_documents_articles_key),
+	'documents_rubriques' => array('field' => &$spip_documents_rubriques,
+				       'key' => &$spip_documents_rubriques_key),
+	'documents_breves' => array('field' => &$spip_documents_breves,
+				    'key' => &$spip_documents_breves_key),
+	'mots_articles' => array('field' => &$spip_mots_articles,
+				 'key' => &$spip_mots_articles_key),
+	'mots_breves' => array('field' => &$spip_mots_breves,
+			       'key' => &$spip_mots_breves_key),
+	'mots_rubriques' => array('field' => &$spip_mots_rubriques,
+				  'key' => &$spip_mots_rubriques_key),
+	'mots_syndic' => array('field' => &$spip_mots_syndic,
+			       'key' => &$spip_mots_syndic_key),
+	'mots_forum' => array('field' => &$spip_mots_forum,
+			      'key' => &$spip_mots_forum_key),
+	'meta' => array('field' => &$spip_meta,
+			'key' => &$spip_meta_key),
+	'index_articles' => array('field' => &$spip_index_articles,
+				  'key' => &$spip_index_articles_key),
+	'index_auteurs' => array('field' => &$spip_index_auteurs,
+				 'key' => &$spip_index_auteurs_key),
+	'index_breves' => array('field' => &$spip_index_breves,
+				'key' => &$spip_index_breves_key),
+	'index_mots' => array('field' => &$spip_index_mots,
+			      'key' => &$spip_index_mots_key),
+	'index_rubriques' => array('field' => &$spip_index_rubriques,
+				   'key' => &$spip_index_rubriques_key),
+	'index_syndic' => array('field' => &$spip_index_syndic,
+				'key' => &$spip_index_syndic_key),
+	'index_signatures' => array('field' => &$spip_index_signatures,
+				    'key' => &$spip_index_signatures_key),
+	'index_forum' => array('field' => &$spip_index_forum,
+			       'key' => &$spip_index_forum_key),
+	'index_dico' => array('field' => &$spip_index_dico,
+			      'key' => &$spip_index_dico_key),
+	'inclure_caches' => array('field' => &$spip_inclure_caches,
+				  'key' => &$spip_inclure_caches_key),
+	'versions'	=> array('field' => &$spip_versions,
+					 'key' => &$spip_versions_key),
+	'versions_fragments'	=> array('field' => &$spip_versions_fragments,
+					 'key' => &$spip_versions_fragments_key)
+	);
+?>
diff --git a/ecrire/inc_base.php3 b/ecrire/inc_base.php3
index 7b2ccb1bb8..c9200a0b80 100644
--- a/ecrire/inc_base.php3
+++ b/ecrire/inc_base.php3
@@ -5,601 +5,64 @@
 if (defined("_ECRIRE_INC_BASE")) return;
 define("_ECRIRE_INC_BASE", "1");
 
-include_ecrire ("inc_acces.php3");
-
-
-function creer_base() {
-
-	global $spip_version;
-
-	//
-	// Elements redactionnels
-	//
-
-	spip_log("creation des tables d'objets");
-	$query = "CREATE TABLE spip_articles (
-		id_article bigint(21) NOT NULL auto_increment,
-		surtitre text NOT NULL,
-		titre text NOT NULL,
-		soustitre text NOT NULL,
-		id_rubrique bigint(21) DEFAULT '0' NOT NULL,
-		descriptif text NOT NULL,
-		chapo mediumtext NOT NULL,
-		texte longblob NOT NULL,
-		ps mediumtext NOT NULL,
-		date datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
-		statut varchar(10) DEFAULT '0' NOT NULL,
-		id_secteur bigint(21) DEFAULT '0' NOT NULL,
-		maj TIMESTAMP,
-		export VARCHAR(10) DEFAULT 'oui',
-		date_redac datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
-		visites INTEGER DEFAULT '0' NOT NULL,
-		referers INTEGER DEFAULT '0' NOT NULL,
-		popularite DOUBLE DEFAULT '0' NOT NULL,
-		accepter_forum CHAR(3) NOT NULL,
-		auteur_modif bigint(21) DEFAULT '0' NOT NULL,
-		date_modif datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
-		lang VARCHAR(10) DEFAULT '' NOT NULL,
-		langue_choisie VARCHAR(3) DEFAULT 'non',
-		id_trad bigint(21) DEFAULT '0' NOT NULL,
-		nom_site tinytext NOT NULL,
-		url_site VARCHAR(255) NOT NULL,
-		extra longblob NULL,
-		idx ENUM('', '1', 'non', 'oui', 'idx') DEFAULT '' NOT NULL,
-		id_version int unsigned DEFAULT '0' NOT NULL,
-		PRIMARY KEY (id_article),
-		KEY id_rubrique (id_rubrique),
-		KEY id_secteur (id_secteur),
-		KEY id_trad (id_trad),
-		KEY lang (lang),
-		KEY statut (statut, date),
-		KEY url_site (url_site),
-		KEY date_modif (date_modif),
-		KEY idx (idx))";
-	$result = spip_query($query);
-
-	$query = "CREATE TABLE spip_auteurs (
-		id_auteur bigint(21) NOT NULL auto_increment,
-		nom text NOT NULL,
-		bio text NOT NULL,
-		email tinytext NOT NULL,
-		nom_site tinytext NOT NULL,
-		url_site text NOT NULL,
-		login VARCHAR(255) BINARY NOT NULL,
-		pass tinytext NOT NULL,
-		low_sec tinytext NOT NULL,
-		statut VARCHAR(255) NOT NULL,
-		maj TIMESTAMP,
-		pgp BLOB NOT NULL,
-		htpass tinyblob NOT NULL,
-		en_ligne datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
-		imessage VARCHAR(3) NOT NULL,
-		messagerie VARCHAR(3) NOT NULL,
-		alea_actuel tinytext NOT NULL,
-		alea_futur tinytext NOT NULL,
-		prefs tinytext NOT NULL,
-		cookie_oubli tinytext NOT NULL,
-		source VARCHAR(10) DEFAULT 'spip' NOT NULL,
-		lang VARCHAR(10) DEFAULT '' NOT NULL,
-		extra longblob NULL,
-		idx ENUM('', '1', 'non', 'oui', 'idx') DEFAULT '' NOT NULL,
-		PRIMARY KEY (id_auteur),
-		KEY login (login),
-		KEY statut (statut),
-		KEY lang (lang),
-		KEY en_ligne (en_ligne),
-		KEY idx (idx))";
-	$result = spip_query($query);
-
-	$query = "CREATE TABLE spip_breves (
-		id_breve bigint(21) NOT NULL auto_increment,
-		date_heure datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
-		titre text NOT NULL,
-		texte longblob NOT NULL,
-		lien_titre text NOT NULL,
-		lien_url text NOT NULL,
-		statut varchar(6) NOT NULL,
-		id_rubrique bigint(21) DEFAULT '0' NOT NULL,
-		lang VARCHAR(10) DEFAULT '' NOT NULL,
-		langue_choisie VARCHAR(3) DEFAULT 'non',
-		maj TIMESTAMP,
-		extra longblob NULL,
-		idx ENUM('', '1', 'non', 'oui', 'idx') DEFAULT '' NOT NULL,
-		PRIMARY KEY (id_breve),
-		KEY id_rubrique (id_rubrique),
-		KEY idx (idx))";
-	$result = spip_query($query);
-
-	$query = "CREATE TABLE spip_messages (
-		id_message bigint(21) NOT NULL auto_increment,
-		titre text NOT NULL,
-		texte longblob NOT NULL,
-		type varchar(6) NOT NULL,
-		date_heure datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
-		date_fin datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
-		rv varchar(3) NOT NULL,
-		statut varchar(6) NOT NULL,
-		id_auteur bigint(21) NOT NULL,
-		maj TIMESTAMP,
-		KEY id_auteur (id_auteur),
-		PRIMARY KEY (id_message))";
-	$result = spip_query($query);
-
-	$query = "CREATE TABLE spip_mots (
-		id_mot bigint(21) NOT NULL auto_increment,
-		type VARCHAR(100) NOT NULL,
-		titre text NOT NULL,
-		descriptif text NOT NULL,
-		texte longblob NOT NULL,
-		id_groupe bigint(21) NOT NULL,
-		extra longblob NULL,
-		idx ENUM('', '1', 'non', 'oui', 'idx') DEFAULT '' NOT NULL,
-		maj TIMESTAMP,
-		PRIMARY KEY (id_mot),
-		KEY type(type),
-		KEY idx (idx))";
-	$result = spip_query($query);
-
-	$query = "CREATE TABLE spip_groupes_mots (
-		id_groupe bigint(21) NOT NULL auto_increment,
-		titre text NOT NULL,
-		unseul varchar(3) NOT NULL,
-		obligatoire varchar(3) NOT NULL,
-		articles varchar(3) NOT NULL,
-		breves varchar(3) NOT NULL,
-		rubriques varchar(3) NOT NULL,
-		syndic varchar(3) NOT NULL,
-		0minirezo varchar(3) NOT NULL,
-		1comite varchar(3) NOT NULL,
-		6forum varchar(3) NOT NULL,
-		maj TIMESTAMP,
-		PRIMARY KEY (id_groupe))";
-	$result = spip_query($query);
-
-	$query = "CREATE TABLE spip_rubriques (
-		id_rubrique bigint(21) NOT NULL auto_increment,
-		id_parent bigint(21) DEFAULT '0' NOT NULL,
-		titre text NOT NULL,
-		descriptif text NOT NULL,
-		texte longblob NOT NULL,
-		id_secteur bigint(21) DEFAULT '0' NOT NULL,
-		maj TIMESTAMP,
-		export VARCHAR(10) DEFAULT 'oui',
-		id_import BIGINT DEFAULT '0',
-		statut VARCHAR(10) NOT NULL,
-		date datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
-		lang VARCHAR(10) DEFAULT '' NOT NULL,
-		langue_choisie VARCHAR(3) DEFAULT 'non',
-		extra longblob NULL,
-		idx ENUM('', '1', 'non', 'oui', 'idx') DEFAULT '' NOT NULL,
-		PRIMARY KEY (id_rubrique),
-		KEY lang (lang),
-		KEY id_parent (id_parent),
-		KEY idx (idx))";
-	$result = spip_query($query);
-
-	$query = "CREATE TABLE spip_documents (
-		id_document bigint(21) NOT NULL auto_increment,
-		id_vignette bigint(21) DEFAULT '0' NOT NULL,
-		id_type bigint(21) DEFAULT '0' NOT NULL,
-		titre text NOT NULL,
-		date datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
-		descriptif text NOT NULL,
-		fichier varchar(255) NOT NULL,
-		taille integer NOT NULL,
-		largeur integer NOT NULL,
-		hauteur integer NOT NULL,
-		mode ENUM('vignette', 'document') NOT NULL,
-		inclus VARCHAR(3) DEFAULT 'non',
-		maj TIMESTAMP,
-		PRIMARY KEY (id_document),
-		KEY id_vignette (id_vignette),
-		KEY mode (mode),
-		KEY id_type (id_type))";
-	$result = spip_query($query);
-
-	$query = "CREATE TABLE spip_types_documents (
-		id_type bigint(21) NOT NULL auto_increment,
-		titre text NOT NULL,
-		descriptif text NOT NULL,
-		extension varchar(10) NOT NULL,
-		mime_type varchar(100) NOT NULL,
-		inclus ENUM('non', 'image', 'embed') NOT NULL DEFAULT 'non',
-		upload ENUM('oui', 'non') NOT NULL DEFAULT 'oui',
-		maj TIMESTAMP,
-		PRIMARY KEY (id_type),
-		UNIQUE extension (extension),
-		KEY inclus (inclus))";
-	$result = spip_query($query);
-
-	$query = "CREATE TABLE spip_syndic (
-		id_syndic bigint(21) NOT NULL auto_increment,
-		id_rubrique bigint(21) DEFAULT '0' NOT NULL,
-		id_secteur bigint(21) DEFAULT '0' NOT NULL,
-		nom_site blob NOT NULL,
-		url_site blob NOT NULL,
-		url_syndic blob NOT NULL,
-		descriptif blob NOT NULL,
-		idx ENUM('', '1', 'non', 'oui', 'idx') DEFAULT '' NOT NULL,
-		maj TIMESTAMP,
-		syndication VARCHAR(3) NOT NULL,
-		statut VARCHAR(10) NOT NULL,
-		date datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
-		date_syndic datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
-		date_index datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
-		moderation VARCHAR(3) NOT NULL,
-		PRIMARY KEY (id_syndic),
-		KEY id_rubrique (id_rubrique),
-		KEY id_secteur (id_secteur),
-		KEY statut (statut, date_syndic),
-		KEY idx (idx))";
-	$result = spip_query($query);
-
-	$query = "CREATE TABLE spip_syndic_articles (
-		id_syndic_article bigint(21) NOT NULL auto_increment,
-		id_syndic bigint(21) DEFAULT '0' NOT NULL,
-		titre text NOT NULL,
-		url VARCHAR(255) NOT NULL,
-		date datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
-		lesauteurs text NOT NULL,
-		maj TIMESTAMP,
-		statut VARCHAR(10) NOT NULL,
-		descriptif blob NOT NULL,
-		PRIMARY KEY (id_syndic_article),
-		KEY id_syndic (id_syndic),
-		KEY statut (statut),
-		KEY url (url))";
-	$result = spip_query($query);
-
-
-	//
-	// Elements interactifs
-	//
-
-	spip_log("creation des tables interactions");
-	$query = "CREATE TABLE spip_forum (
-		id_forum bigint(21) NOT NULL auto_increment,
-		id_parent bigint(21) DEFAULT '0' NOT NULL,
-		id_rubrique bigint(21) DEFAULT '0' NOT NULL,
-		id_article bigint(21) DEFAULT '0' NOT NULL,
-		id_breve bigint(21) DEFAULT '0' NOT NULL,
-		date_heure datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
-		titre text NOT NULL,
-		texte mediumtext NOT NULL,
-		auteur text NOT NULL,
-		email_auteur text NOT NULL,
-		nom_site text NOT NULL,
-		url_site text NOT NULL,
-		statut varchar(8) NOT NULL,
-		idx ENUM('', '1', 'non', 'oui', 'idx') DEFAULT '' NOT NULL,
-		ip varchar(16),
-		maj TIMESTAMP,
-		id_auteur BIGINT DEFAULT '0' NOT NULL,
-		id_message bigint(21) DEFAULT '0' NOT NULL,
-		id_syndic bigint(21) DEFAULT '0' NOT NULL,
-		PRIMARY KEY (id_forum),
-		KEY id_parent (id_parent),
-		KEY id_rubrique (id_rubrique),
-		KEY id_article (id_article),
-		KEY id_breve (id_breve),
-		KEY id_message (id_message),
-		KEY id_syndic (id_syndic),
-		KEY statut (statut, date_heure),
-		KEY idx (idx))";
-	$result = spip_query($query);
-
-	$query = "CREATE TABLE spip_petitions (
-		id_article bigint(21) DEFAULT '0' NOT NULL,
-		email_unique char(3) NOT NULL,
-		site_obli char(3) NOT NULL,
-		site_unique char(3) NOT NULL,
-		message char(3) NOT NULL,
-		texte longblob NOT NULL,
-		maj TIMESTAMP,
-		PRIMARY KEY (id_article))";
-	$result = spip_query($query);
-
-	$query = "CREATE TABLE spip_signatures (
-		id_signature bigint(21) NOT NULL auto_increment,
-		id_article bigint(21) DEFAULT '0' NOT NULL,
-		date_time datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
-		nom_email text NOT NULL,
-		ad_email text NOT NULL,
-		nom_site text NOT NULL,
-		url_site text NOT NULL,
-		message mediumtext NOT NULL,
-		statut varchar(10) NOT NULL,
-		idx ENUM('', '1', 'non', 'oui', 'idx') DEFAULT '' NOT NULL,
-		maj TIMESTAMP,
-		PRIMARY KEY (id_signature),
-		KEY id_article (id_article),
-		KEY statut(statut),
-		KEY idx (idx))";
-	$result = spip_query($query);
-
-	$query = "CREATE TABLE spip_visites_temp (
-		ip INTEGER UNSIGNED NOT NULL,
-		type ENUM('article', 'rubrique', 'breve', 'autre') NOT NULL,
-		id_objet INTEGER UNSIGNED NOT NULL,
-		maj TIMESTAMP,
-		PRIMARY KEY (type, id_objet, ip))";
-	$result = spip_query($query);
-
-	$query = "CREATE TABLE spip_visites (
-		date DATE NOT NULL,
-		visites INTEGER UNSIGNED NOT NULL,
-		maj TIMESTAMP,
-		PRIMARY KEY (date))";
-	$result = spip_query($query);
-
-	$query = "CREATE TABLE spip_visites_articles (
-		date DATE NOT NULL,
-		id_article INTEGER UNSIGNED NOT NULL,
-		visites INTEGER UNSIGNED NOT NULL,
-		maj TIMESTAMP,
-		PRIMARY KEY (date, id_article))";
-	$result = spip_query($query);
-
-	$query = "CREATE TABLE spip_referers_temp (
-		ip INTEGER UNSIGNED NOT NULL,
-		referer VARCHAR(255) NOT NULL,
-		referer_md5 BIGINT UNSIGNED NOT NULL,
-		type ENUM('article', 'rubrique', 'breve', 'autre') NOT NULL,
-		id_objet INTEGER UNSIGNED NOT NULL,
-		maj TIMESTAMP,
-		PRIMARY KEY (type, id_objet, referer_md5, ip))";
-	$result = spip_query($query);
-
-	$query = "CREATE TABLE spip_referers (
-		referer_md5 BIGINT UNSIGNED NOT NULL,
-		date DATE NOT NULL,
-		referer VARCHAR(255) NOT NULL,
-		visites INTEGER UNSIGNED NOT NULL,
-		visites_jour INTEGER UNSIGNED NOT NULL,
-		maj TIMESTAMP,
-		PRIMARY KEY (referer_md5))";
-	$result = spip_query($query);
-
-	$query = "CREATE TABLE spip_referers_articles (
-		id_article INTEGER UNSIGNED NOT NULL,
-		referer_md5 BIGINT UNSIGNED NOT NULL,
-		date DATE NOT NULL,
-		referer VARCHAR(255) NOT NULL,
-		visites INTEGER UNSIGNED NOT NULL,
-		maj TIMESTAMP,
-		PRIMARY KEY (id_article, referer_md5),
-		KEY referer_md5 (referer_md5))";
-	$result = spip_query($query);
-
-
-	//
-	// Relations
-	//
-
-	spip_log("creation des tables relations");
-	$query = "CREATE TABLE spip_auteurs_articles (
-		id_auteur bigint(21) DEFAULT '0' NOT NULL,
-		id_article bigint(21) DEFAULT '0' NOT NULL,
-		KEY id_auteur (id_auteur),
-		KEY id_article (id_article))";
-	$result = spip_query($query);
-
-	$query = "CREATE TABLE spip_auteurs_rubriques (
-		id_auteur bigint(21) DEFAULT '0' NOT NULL,
-		id_rubrique bigint(21) DEFAULT '0' NOT NULL,
-		KEY id_auteur (id_auteur),
-		KEY id_rubrique (id_rubrique))";
-	$result = spip_query($query);
-
-	$query = "CREATE TABLE spip_auteurs_messages (
-		id_auteur bigint(21) DEFAULT '0' NOT NULL,
-		id_message bigint(21) DEFAULT '0' NOT NULL,
-		vu CHAR(3) NOT NULL,
-		KEY id_auteur (id_auteur),
-		KEY id_message (id_message))";
-	$result = spip_query($query);
-
-
-	$query = "CREATE TABLE spip_documents_articles (
-		id_document bigint(21) DEFAULT '0' NOT NULL,
-		id_article bigint(21) DEFAULT '0' NOT NULL,
-		KEY id_document (id_document),
-		KEY id_article (id_article))";
-	$result = spip_query($query);
-
-	$query = "CREATE TABLE spip_documents_rubriques (
-		id_document bigint(21) DEFAULT '0' NOT NULL,
-		id_rubrique bigint(21) DEFAULT '0' NOT NULL,
-		KEY id_document (id_document),
-		KEY id_rubrique (id_rubrique))";
-	$result = spip_query($query);
-
-	$query = "CREATE TABLE spip_documents_breves (
-		id_document bigint(21) DEFAULT '0' NOT NULL,
-		id_breve bigint(21) DEFAULT '0' NOT NULL,
-		KEY id_document (id_document),
-		KEY id_breve (id_breve))";
-	$result = spip_query($query);
-
-	$query = "CREATE TABLE spip_mots_articles (
-		id_mot bigint(21) DEFAULT '0' NOT NULL,
-		id_article bigint(21) DEFAULT '0' NOT NULL,
-		KEY id_mot (id_mot),
-		KEY id_article (id_article))";
-	$result = spip_query($query);
-
-	$query = "CREATE TABLE spip_mots_breves (
-		id_mot bigint(21) DEFAULT '0' NOT NULL,
-		id_breve bigint(21) DEFAULT '0' NOT NULL,
-		KEY id_mot (id_mot),
-		KEY id_breve (id_breve))";
-	$result = spip_query($query);
-
-	$query = "CREATE TABLE spip_mots_rubriques (
-		id_mot bigint(21) DEFAULT '0' NOT NULL,
-		id_rubrique bigint(21) DEFAULT '0' NOT NULL,
-		KEY id_mot (id_mot),
-		KEY id_rubrique (id_rubrique))";
-	$result = spip_query($query);
-
-	$query = "CREATE TABLE spip_mots_syndic (
-		id_mot bigint(21) DEFAULT '0' NOT NULL,
-		id_syndic bigint(21) DEFAULT '0' NOT NULL,
-		KEY id_mot (id_mot),
-		KEY id_syndic (id_syndic))";
-	$result = spip_query($query);
-
-	$query = "CREATE TABLE spip_mots_forum (
-		id_mot bigint(21) DEFAULT '0' NOT NULL,
-		id_forum bigint(21) DEFAULT '0' NOT NULL,
-		KEY id_mot (id_mot),
-		KEY id_forum (id_forum))";
-	$result = spip_query($query);
-
-
-	//
-	// Versionnage des articles
-	//
-
-	spip_log("creation des tables versionnage des articles");
-	$query = "CREATE TABLE spip_versions (
-		id_article bigint(21) NOT NULL,
-		id_version int unsigned DEFAULT '0' NOT NULL,
-		date datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
-		id_auteur bigint(21) NOT NULL,
-		titre_version text DEFAULT '' NOT NULL,
-		permanent char(3) NOT NULL,
-		champs text NOT NULL,
-
-		PRIMARY KEY (id_article, id_version),
-		KEY date (id_article, date),
-		KEY id_auteur (id_auteur))";
-	$result = spip_query($query);
-
-	$query = "CREATE TABLE spip_versions_fragments (
-		id_fragment int unsigned DEFAULT '0' NOT NULL,
-		version_min int unsigned DEFAULT '0' NOT NULL,
-		version_max int unsigned DEFAULT '0' NOT NULL,
-		id_article bigint(21) NOT NULL,
-		compress tinyint NOT NULL,
-		fragment longblob NOT NULL,
-
-		PRIMARY KEY (id_article, id_fragment, version_min))";
-	$result = spip_query($query);
-
-	//
-	// Gestion du site
-	//
-
-	spip_log("creation des tables gestion du site");
-	$query = "CREATE TABLE spip_forum_cache (
-		id_forum bigint(21) DEFAULT '0' NOT NULL,
-		id_rubrique bigint(21) DEFAULT '0' NOT NULL,
-		id_article bigint(21) DEFAULT '0' NOT NULL,
-		id_breve bigint(21) DEFAULT '0' NOT NULL,
-		id_syndic bigint(21) DEFAULT '0' NOT NULL,
-		fichier char(150) binary NOT NULL,
-		maj TIMESTAMP,
-		PRIMARY KEY (fichier, id_forum, id_article, id_rubrique, id_breve, id_syndic),
-		KEY id_forum(id_forum),
-		KEY id_rubrique(id_rubrique),
-		KEY id_article(id_article),
-		KEY id_syndic(id_syndic),
-		KEY id_breve(id_breve))";
-	$result = spip_query($query);
-
-	$query = "CREATE TABLE spip_meta (
-		nom VARCHAR(255) NOT NULL,
-		valeur VARCHAR(255) DEFAULT '',
-		maj TIMESTAMP,
-		PRIMARY KEY (nom))";
-	$result = spip_query($query);
-
-
-	//
-	// Indexation (moteur de recherche)
-	//
-
-	$query = "CREATE TABLE spip_index_articles (
-		hash bigint unsigned NOT NULL,
-		points int unsigned DEFAULT '0' NOT NULL,
-		id_article int unsigned NOT NULL,
-		KEY hash (hash),
-		KEY id_article (id_article))";
-	$result = spip_query($query);
-
-	$query = "CREATE TABLE spip_index_auteurs (
-		hash bigint unsigned NOT NULL,
-		points int unsigned DEFAULT '0' NOT NULL,
-		id_auteur int unsigned NOT NULL,
-		KEY hash (hash),
-		KEY id_auteur (id_auteur))";
-	$result = spip_query($query);
-
-	$query = "CREATE TABLE spip_index_breves (
-		hash bigint unsigned NOT NULL,
-		points int unsigned DEFAULT '0' NOT NULL,
-		id_breve int unsigned NOT NULL,
-		KEY hash (hash),
-		KEY id_breve (id_breve))";
-	$result = spip_query($query);
-
-	$query = "CREATE TABLE spip_index_mots (
-		hash bigint unsigned NOT NULL,
-		points int unsigned DEFAULT '0' NOT NULL,
-		id_mot int unsigned NOT NULL,
-		KEY hash (hash), KEY id_mot (id_mot))";
-	$result = spip_query($query);
-
-	$query = "CREATE TABLE spip_index_rubriques (
-		hash bigint unsigned NOT NULL,
-		points int unsigned DEFAULT '0' NOT NULL,
-		id_rubrique int unsigned NOT NULL,
-		KEY hash (hash),
-		KEY id_rubrique (id_rubrique))";
-	$result = spip_query($query);
-
-	$query = "CREATE TABLE spip_index_syndic (
-		hash bigint unsigned NOT NULL,
-		points int unsigned DEFAULT '0' NOT NULL,
-		id_syndic int unsigned NOT NULL,
-		KEY hash (hash),
-		KEY id_syndic (id_syndic))";
-	$result = spip_query($query);
-
-	$query = "CREATE TABLE spip_index_signatures (
-		hash bigint unsigned NOT NULL,
-		points int unsigned DEFAULT '0' NOT NULL,
-		id_signature int unsigned NOT NULL,
-		KEY hash (hash),
-		KEY id_signature (id_signature))";
-	$result = spip_query($query);
-
-	$query = "CREATE TABLE spip_index_forum (
-		hash bigint unsigned NOT NULL,
-		points int unsigned DEFAULT '0' NOT NULL,
-		id_forum int unsigned NOT NULL,
-		KEY hash (hash),
-		KEY id_forum (id_forum))";
-	$result = spip_query($query);
-
-	$query = "CREATE TABLE spip_index_dico (
-		hash bigint unsigned NOT NULL,
-		dico VARCHAR(30) NOT NULL,
-		PRIMARY KEY (dico))";
-	$result = spip_query($query);
-
-
-	//
-	// Pre-remplissage de la base
-	//
-	spip_log("pre-remplissage de la base");
-	remplir_type_documents();
-
+include_ecrire("inc_acces.php3");
+include_ecrire("inc_serialbase.php3");
+include_ecrire("inc_auxbase.php3");
+include_ecrire("inc_majbase.php3");
+
+// Fonction de cre'ation d'une table SQL nomme'e $nom
+// a` partir de 2 tableaux PHP:
+// champs: champ => type
+// cles: type-de-cle' => champ(s)
+// si $f est vrai, c'est une auto-increment (i.e. serial) sur la Primary Key
+// si en  plus la Primary Key re'fe'rence un champ unique,
+// on cre'e aussi une table des de'pendances de caches selon ce champ.
+// Le nom des caches doit e^tre infe'rieur a` 64 caracte`res
+
+function spip_create($nom, $champs, $cles, $f=false)
+{
+  # en fait c'est table_prefix, pas forcement 'spip_' faudra finaliser
+  $nom = 'spip_' . $nom;
+  $query = ''; $keys = ""; $s = '';
+  foreach($cles as $k => $v)
+    {
+      $keys .= "$s\n\t\t$k ($v)";
+      if ($k == "PRIMARY KEY") $p = $v;
+      $s = ",";
+    }
+  $s = '';
+  foreach($champs as $k => $v)
+    {
+      $query .= "$s\n\t\t$k $v" .
+		(($f && ($p == $k)) ? " auto_increment" : '');
+      $s = ",";
+    }
+  if (!$f)  spip_query ("DROP TABLE IF EXISTS $nom;");
+  $query = "CREATE TABLE IF NOT EXISTS $nom ($query" .
+    	($keys ? ",$keys" : '') .
+    	")\n";
+  spip_query($query);  
+#  spip_log($query);
+  if (($f && !strpos($p, ",")))
+    {
+      $t = "spip_" . $p . _SUFFIXE_DES_CACHES;
+      spip_query("DROP TABLE IF EXISTS $t");
+      spip_log("Create $t");
+      spip_query("
+CREATE TABLE $t (
+hache char (64) NOT NULL, $p char (64) NOT NULL,
+KEY hache (hache),
+KEY $p ($p))
+");
+    }
 }
 
-
-function remplir_type_documents() {
+function creer_base() {
+	global $tables_principales, $tables_auxiliaires;
+	foreach($tables_principales as $k => $v)
+	  {spip_create($k, $v['field'], $v['key'], true);}
+	foreach($tables_auxiliaires as $k => $v)
+	  {spip_create($k, $v['field'], $v['key'], false);}
 	// Images reconnues par PHP
 	$query = "INSERT IGNORE spip_types_documents (id_type, extension, titre, inclus) VALUES ".
 		"(1, 'jpg', 'JPEG', 'image'), ".
@@ -679,836 +142,4 @@ function stripslashes_base($table, $champs) {
 	spip_query($query);
 }
 
-
-function maj_version($version, $test = true) {
-	if ($test) {
-		spip_query("REPLACE spip_meta (nom, valeur) VALUES ('version_installee', '$version')");
-		spip_log("mise a jour de la base vers $version");
-	}
-	else {
-		include_ecrire ('inc_lang.php3');
-		echo _T('alerte_maj_impossible', array('version' => $version));
-		exit;
-	}
-}
-
-
-function maj_base() {
-
-	global $spip_version;
-
-	//
-	// Lecture de la version installee
-	//
-	$version_installee = 0.0;
-	$result = spip_query("SELECT valeur FROM spip_meta WHERE nom='version_installee'");
-	if ($result) if ($row = spip_fetch_array($result)) $version_installee = (double) $row['valeur'];
-
-	//
-	// Si pas de version mentionnee dans spip_meta, c'est qu'il s'agit d'une nouvelle installation
-	//   => ne pas passer par le processus de mise a jour
-	//
-	if (!$version_installee) {
-		$version_installee = $spip_version;
-		maj_version($version_installee);
-		return true;
-	}
-
-	//
-	// Verification des droits de modification sur la base
-	//
-
-	spip_query("DROP TABLE IF EXISTS spip_test");
-	spip_query("CREATE TABLE spip_test (a INT)");
-	spip_query("ALTER TABLE spip_test ADD b INT");
-	spip_query("INSERT INTO spip_test (b) VALUES (1)");
-	$result = spip_query("SELECT b FROM spip_test");
-	spip_query("ALTER TABLE spip_test DROP b");
-	if (!$result) return false;
-
-	//
-	// Selection en fonction de la version
-	//
-	if ($version_installee < 0.98) {
-
-		spip_query("ALTER TABLE spip_articles ADD maj TIMESTAMP");
-		spip_query("ALTER TABLE spip_articles ADD export VARCHAR(10) DEFAULT 'oui'");
-		spip_query("ALTER TABLE spip_articles ADD images TEXT DEFAULT ''");
-		spip_query("ALTER TABLE spip_articles ADD date_redac datetime DEFAULT '0000-00-00 00:00:00' NOT NULL");
-		spip_query("ALTER TABLE spip_articles DROP INDEX id_article");
-		spip_query("ALTER TABLE spip_articles ADD INDEX id_rubrique (id_rubrique)");
-		spip_query("ALTER TABLE spip_articles ADD visites INTEGER DEFAULT '0' NOT NULL");
-		spip_query("ALTER TABLE spip_articles ADD referers BLOB NOT NULL");
-
-		spip_query("ALTER TABLE spip_auteurs ADD maj TIMESTAMP");
-		spip_query("ALTER TABLE spip_auteurs ADD pgp BLOB NOT NULL");
-
-		spip_query("ALTER TABLE spip_auteurs_articles ADD INDEX id_auteur (id_auteur), ADD INDEX id_article (id_article)");
-	
-		spip_query("ALTER TABLE spip_rubriques ADD maj TIMESTAMP");
-		spip_query("ALTER TABLE spip_rubriques ADD export VARCHAR(10) DEFAULT 'oui', ADD id_import BIGINT DEFAULT '0'");
-	
-		spip_query("ALTER TABLE spip_breves ADD maj TIMESTAMP");
-		spip_query("ALTER TABLE spip_breves DROP INDEX id_breve");
-		spip_query("ALTER TABLE spip_breves DROP INDEX id_breve_2");
-		spip_query("ALTER TABLE spip_breves ADD INDEX id_rubrique (id_rubrique)");
-	
-		spip_query("ALTER TABLE spip_forum ADD ip VARCHAR(16)");
-		spip_query("ALTER TABLE spip_forum ADD maj TIMESTAMP");
-		spip_query("ALTER TABLE spip_forum DROP INDEX id_forum");
-		spip_query("ALTER TABLE spip_forum ADD INDEX id_parent (id_parent), ADD INDEX id_rubrique (id_rubrique), ADD INDEX id_article(id_article), ADD INDEX id_breve(id_breve)");
-		maj_version (0.98);
-	}
-
-	if ($version_installee < 0.99) {
-	
-		$query = "SELECT DISTINCT id_article FROM spip_forum WHERE id_article!=0 AND id_parent=0";
-		$result = spip_query($query);
-		while ($row = spip_fetch_array($result)) {
-			unset($forums_article);
-			$id_article = $row['id_article'];
-			$query2 = "SELECT id_forum FROM spip_forum WHERE id_article=$id_article";
-			for (;;) {
-				$result2 = spip_query($query2);
-				unset($forums);
-				while ($row2 = spip_fetch_array($result2)) $forums[] = $row2['id_forum'];
-				if (!$forums) break;
-				$forums = join(',', $forums);
-				$forums_article[] = $forums;
-				$query2 = "SELECT id_forum FROM spip_forum WHERE id_parent IN ($forums)";
-			}
-			$forums_article = join(',', $forums_article);
-			$query3 = "UPDATE spip_forum SET id_article=$id_article WHERE id_forum IN ($forums_article)";
-			spip_query($query3);
-		}
-	
-		$query = "SELECT DISTINCT id_breve FROM spip_forum WHERE id_breve!=0 AND id_parent=0";
-		$result = spip_query($query);
-		while ($row = spip_fetch_array($result)) {
-			unset($forums_breve);
-			$id_breve = $row['id_breve'];
-			$query2 = "SELECT id_forum FROM spip_forum WHERE id_breve=$id_breve";
-			for (;;) {
-				$result2 = spip_query($query2);
-				unset($forums);
-				while ($row2 = spip_fetch_array($result2)) $forums[] = $row2['id_forum'];
-				if (!$forums) break;
-				$forums = join(',', $forums);
-				$forums_breve[] = $forums;
-				$query2 = "SELECT id_forum FROM spip_forum WHERE id_parent IN ($forums)";
-			}
-			$forums_breve = join(',', $forums_breve);
-			$query3 = "UPDATE spip_forum SET id_breve=$id_breve WHERE id_forum IN ($forums_breve)";
-			spip_query($query3);
-		}
-	
-		$query = "SELECT DISTINCT id_rubrique FROM spip_forum WHERE id_rubrique!=0 AND id_parent=0";
-		$result = spip_query($query);
-		while ($row = spip_fetch_array($result)) {
-			unset($forums_rubrique);
-			$id_rubrique = $row['id_rubrique'];
-			$query2 = "SELECT id_forum FROM spip_forum WHERE id_rubrique=$id_rubrique";
-			for (;;) {
-				$result2 = spip_query($query2);
-				unset($forums);
-				while ($row2 = spip_fetch_array($result2)) $forums[] = $row2['id_forum'];
-				if (!$forums) break;
-				$forums = join(',', $forums);
-				$forums_rubrique[] = $forums;
-				$query2 = "SELECT id_forum FROM spip_forum WHERE id_parent IN ($forums)";
-			}
-			$forums_rubrique = join(',', $forums_rubrique);
-			$query3 = "UPDATE spip_forum SET id_rubrique=$id_rubrique WHERE id_forum IN ($forums_rubrique)";
-			spip_query($query3);
-		}
-		maj_version (0.99);
-	}
-
-	if ($version_installee < 0.997) {
-		spip_query("DROP TABLE spip_index");
-		maj_version (0.997);
-	}
-
-	if ($version_installee < 0.999) {
-		global $htsalt;
-		spip_query("ALTER TABLE spip_auteurs CHANGE pass pass tinyblob NOT NULL");
-		spip_query("ALTER TABLE spip_auteurs ADD htpass tinyblob NOT NULL");
-		$query = "SELECT id_auteur, pass FROM spip_auteurs WHERE pass!=''";
-		$result = spip_query($query);
-		while (list($id_auteur, $pass) = spip_fetch_array($result)) {
-			$htpass = generer_htpass($pass);
-			$pass = md5($pass);
-			spip_query("UPDATE spip_auteurs SET pass='$pass', htpass='$htpass' WHERE id_auteur=$id_auteur");
-		}
-		maj_version (0.999);
-	}
-	
-	if ($version_installee < 1.01) {
-		spip_query("UPDATE spip_forum SET statut='publie' WHERE statut=''");
-		maj_version (1.01);
-	}
-	
-	if ($version_installee < 1.02) {
-		spip_query("ALTER TABLE spip_forum ADD id_auteur BIGINT DEFAULT '0' NOT NULL");
-		maj_version (1.02);
-	}
-
-	if ($version_installee < 1.03) {
-		spip_query("DROP TABLE spip_maj");
-		maj_version (1.03);
-	}
-
-	if ($version_installee < 1.04) {
-		spip_query("ALTER TABLE spip_articles ADD accepter_forum VARCHAR(3)");
-		maj_version (1.04);
-	}
-
-	if ($version_installee < 1.05) {
-		spip_query("DROP TABLE spip_petition");
-		spip_query("DROP TABLE spip_signatures_petition");
-		maj_version (1.05);
-	}
-
-	if ($version_installee < 1.1) {
-		spip_query("DROP TABLE spip_petition");
-		spip_query("DROP TABLE spip_signatures_petition");
-		maj_version (1.1);
-	}
-
-	// Correction de l'oubli des modifs creations depuis 1.04
-	if ($version_installee < 1.204) {
-		spip_query("ALTER TABLE spip_articles ADD accepter_forum VARCHAR(3) NOT NULL");
-		spip_query("ALTER TABLE spip_forum ADD id_message bigint(21) NOT NULL");
-		spip_query("ALTER TABLE spip_forum ADD INDEX id_message (id_message)");
-		spip_query("ALTER TABLE spip_auteurs ADD en_ligne datetime DEFAULT '0000-00-00 00:00:00' NOT NULL");
-		spip_query("ALTER TABLE spip_auteurs ADD imessage VARCHAR(3) not null");
-		spip_query("ALTER TABLE spip_auteurs ADD messagerie VARCHAR(3) not null");
-		maj_version (1.204);
-	}
-
-	if ($version_installee < 1.207) {
-		spip_query("ALTER TABLE spip_rubriques DROP INDEX id_rubrique");
-		spip_query("ALTER TABLE spip_rubriques ADD INDEX id_parent (id_parent)");
-		spip_query("ALTER TABLE spip_rubriques ADD statut VARCHAR(10) NOT NULL");
-		// Declencher le calcul des rubriques publiques
-		spip_query("REPLACE spip_meta (nom, valeur) VALUES ('calculer_rubriques', 'oui')");
-		maj_version (1.207);
-	}
-
-	if ($version_installee < 1.208) {
-		spip_query("ALTER TABLE spip_auteurs_messages CHANGE forum vu CHAR(3) NOT NULL");
-		spip_query("UPDATE spip_auteurs_messages SET vu='oui'");
-		spip_query("UPDATE spip_auteurs_messages SET vu='non' WHERE statut='a'");
-
-		spip_query("ALTER TABLE spip_messages ADD id_auteur bigint(21) NOT NULL");
-		spip_query("ALTER TABLE spip_messages ADD INDEX id_auteur (id_auteur)");
-		$result = spip_query("SELECT id_auteur, id_message FROM spip_auteurs_messages WHERE statut='de'");
-		while ($row = spip_fetch_array($result)) {
-			$id_auteur = $row['id_auteur'];
-			$id_message = $row['id_message'];
-			spip_query("UPDATE spip_messages SET id_auteur=$id_auteur WHERE id_message=$id_message");
-		}
-
-		spip_query("ALTER TABLE spip_auteurs_messages DROP statut");
-		maj_version (1.208);
-	}
-
-	if ($version_installee < 1.209) {
-		spip_query("ALTER TABLE spip_syndic ADD maj TIMESTAMP");
-		spip_query("ALTER TABLE spip_syndic_articles ADD maj TIMESTAMP");
-		spip_query("ALTER TABLE spip_messages ADD maj TIMESTAMP");
-		maj_version (1.209);
-	}
-
-	if ($version_installee < 1.210) {
-		spip_query("ALTER TABLE spip_messages DROP page");
-
-		stripslashes_base('spip_articles', array('surtitre', 'titre', 'soustitre', 'descriptif', 'chapo', 'texte', 'ps'));
-		stripslashes_base('spip_auteurs', array('nom', 'bio', 'nom_site'));
-		stripslashes_base('spip_breves', array('titre', 'texte', 'lien_titre'));
-		stripslashes_base('spip_forum', array('titre', 'texte', 'auteur', 'nom_site'));
-		stripslashes_base('spip_messages', array('titre', 'texte'));
-		stripslashes_base('spip_mots', array('type', 'titre', 'descriptif', 'texte'));
-		stripslashes_base('spip_petitions', array('texte'));
-		stripslashes_base('spip_rubriques', array('titre', 'descriptif', 'texte'));
-		stripslashes_base('spip_signatures', array('nom_email', 'nom_site', 'message'));
-		stripslashes_base('spip_syndic', array('nom_site', 'descriptif'));
-		stripslashes_base('spip_syndic_articles', array('titre', 'lesauteurs'));
-		maj_version (1.210);
-	}
-
-	if ($version_installee < 1.3) {
-		// Modifier la syndication (pour liste de sites)
-		spip_query("ALTER TABLE spip_syndic ADD syndication VARCHAR(3) NOT NULL");
-		spip_query("ALTER TABLE spip_syndic ADD statut VARCHAR(10) NOT NULL");
-		spip_query("ALTER TABLE spip_syndic ADD date datetime DEFAULT '0000-00-00 00:00:00' NOT NULL");
-		spip_query("UPDATE spip_syndic SET syndication='oui', statut='publie', date=NOW()");
-
-		// Statut pour articles syndication, pour pouvoir desactiver un article
-		spip_query("ALTER TABLE spip_syndic_articles ADD statut VARCHAR(10) NOT NULL");
-		spip_query("UPDATE spip_syndic_articles SET statut='publie'");
-		maj_version (1.3);
-	}
-
-	if ($version_installee < 1.301) {
-		spip_query("ALTER TABLE spip_forum ADD id_syndic bigint(21) DEFAULT '0' NOT NULL");
-		maj_version (1.301);
-	}
-
-	if ($version_installee < 1.302) {
-		spip_query("ALTER TABLE spip_forum_cache DROP PRIMARY KEY");
-		spip_query("ALTER TABLE spip_forum_cache DROP INDEX fichier");
-		spip_query("ALTER TABLE spip_forum_cache ADD PRIMARY KEY (fichier, id_forum, id_article, id_rubrique, id_breve, id_syndic)");
-		spip_query("ALTER TABLE spip_forum ADD INDEX id_syndic (id_syndic)");
-		maj_version (1.302);
-	}
-
-	if ($version_installee < 1.303) {
-		spip_query("ALTER TABLE spip_rubriques ADD date datetime DEFAULT '0000-00-00 00:00:00' NOT NULL");
-		spip_query("ALTER TABLE spip_syndic ADD date_syndic datetime DEFAULT '0000-00-00 00:00:00' NOT NULL");
-		spip_query("UPDATE spip_syndic SET date_syndic=date");
-		maj_version (1.303);
-	}
-
-	if ($version_installee < 1.306) {
-		spip_query("DROP TABLE spip_index_syndic_articles");
-		spip_query("ALTER TABLE spip_syndic ADD date_index datetime DEFAULT '0000-00-00 00:00:00' NOT NULL");
-		spip_query("ALTER TABLE spip_syndic ADD INDEX date_index (date_index)");
-		maj_version (1.306);
-	}
-
-	if ($version_installee < 1.307) {
-		spip_query("ALTER TABLE spip_syndic_articles ADD descriptif blob NOT NULL");
-		maj_version (1.307);
-	}
-
-	if ($version_installee < 1.404) {
-		spip_query("UPDATE spip_mots SET type='Mots sans groupe...' WHERE type=''");
-
-		$result = spip_query("SELECT * FROM spip_mots GROUP BY type");
-		while($row = spip_fetch_array($result)) {
-				$type = addslashes($row['type']);
-				spip_query("INSERT INTO spip_groupes_mots 
-					(titre, unseul, obligatoire, articles, breves, rubriques, syndic, 0minirezo, 1comite, 6forum)
-					VALUES (\"$type\", 'non', 'non', 'oui', 'oui', 'non', 'oui', 'oui', 'oui', 'non')");
-		}
-		spip_query("DELETE FROM spip_mots WHERE titre='kawax'");
-		maj_version (1.404);
-	}
-
-	if ($version_installee < 1.405) {
-		spip_query("ALTER TABLE spip_mots ADD id_groupe bigint(21) NOT NULL");
-	
-		$result = spip_query("SELECT * FROM spip_groupes_mots");
-		while($row = spip_fetch_array($result)) {
-				$id_groupe = addslashes($row['id_groupe']);
-				$type = addslashes($row['titre']);
-				spip_query("UPDATE spip_mots SET id_groupe = '$id_groupe' WHERE type=\"$type\"");
-		}
-		maj_version (1.405);
-	}
-
-	if ($version_installee < 1.408) {
-		// Images articles passent dans spip_documents
-		$query = "SELECT id_article, images FROM spip_articles WHERE LENGTH(images) > 0";
-		$result = spip_query($query);
-
-		$types = array('jpg' => 1, 'png' => 2, 'gif' => 3);
-
-		while ($row = @spip_fetch_array($result)) {
-			$id_article = $row['id_article'];
-			$images = $row['images'];
-			$images = explode(",", $images);
-			reset($images);
-			$replace = '_orig_';
-			while (list (, $val) = each($images)) {
-				$image = explode("|", $val);
-				$fichier = $image[0];
-				$largeur = $image[1];
-				$hauteur = $image[2];
-				ereg("-([0-9]+)\.(gif|jpg|png)$", $fichier, $match);
-				$id_type = intval($types[$match[2]]);
-				$num_img = $match[1];
-				$fichier = "IMG/$fichier";
-				$taille = @filesize("../$fichier");
-				spip_query("INSERT INTO spip_documents (titre, id_type, fichier, mode, largeur, hauteur, taille) VALUES ".
-					"('image $largeur x $hauteur', $id_type, '$fichier', 'vignette', '$largeur', '$hauteur', '$taille')");
-				$id_document = spip_insert_id();
-				if ($id_document > 0) {
-					spip_query("INSERT INTO spip_documents_articles (id_document, id_article) VALUES ($id_document, $id_article)");
-					$replace = "REPLACE($replace, '<IMG$num_img|', '<IM_$id_document|')";
-				} else {
-					echo _T('texte_erreur_mise_niveau_base', array('fichier' => $fichier, 'id_article' => $id_article));
-					exit;
-				}
-			}
-			$replace = "REPLACE($replace, '<IM_', '<IMG')";
-			$replace_chapo = ereg_replace('_orig_', 'chapo', $replace);
-			$replace_descriptif = ereg_replace('_orig_', 'descriptif', $replace);
-			$replace_texte = ereg_replace('_orig_', 'texte', $replace);
-			$replace_ps = ereg_replace('_orig_', 'ps', $replace);
-			$query = "UPDATE spip_articles ".
-				"SET chapo=$replace_chapo, descriptif=$replace_descriptif, texte=$replace_texte, ps=$replace_ps ".
-				"WHERE id_article=$id_article";
-			spip_query($query);
-		}
-		spip_query("ALTER TABLE spip_articles DROP images");
-		maj_version (1.408);
-	}
-
-	if ($version_installee < 1.414) {
-		// Forum par defaut "en dur" dans les spip_articles
-		// -> non, prio (priori), pos (posteriori), abo (abonnement)
-		include_ecrire ("inc_meta.php3");
-		$accepter_forum = substr(lire_meta("forums_publics"),0,3) ;
-		$query = "ALTER TABLE spip_articles CHANGE accepter_forum accepter_forum CHAR(3) NOT NULL";
-		$result = spip_query($query);
-		$query = "UPDATE spip_articles SET accepter_forum='$accepter_forum' WHERE accepter_forum != 'non'";
-		$result = spip_query($query);
-		maj_version (1.414);
-	}
-
-	/*
-	if ($version_installee == 1.415) {
-		spip_query("ALTER TABLE spip_documents DROP inclus");
-		maj_version (1.415);
-	}
-	*/
-
-	if ($version_installee < 1.417) {
-		spip_query("ALTER TABLE spip_syndic_articles DROP date_index");
-		maj_version (1.417);
-	}
-
-	if ($version_installee < 1.418) {
-		$query = "SELECT * FROM spip_auteurs WHERE statut = '0minirezo' AND email != '' ORDER BY id_auteur LIMIT 0,1";
-		$result = spip_query($query);
-		if ($webmaster = spip_fetch_object($result)) {
-			include_ecrire("inc_meta.php3");
-			ecrire_meta('email_webmaster', $webmaster->email);
-			ecrire_metas();
-		}
-		maj_version (1.418);
-	}
-
-	if ($version_installee < 1.419) {
-		$query = "ALTER TABLE spip_auteurs ADD alea_actuel TINYTEXT DEFAULT ''";
-		spip_query($query);
-		$query = "ALTER TABLE spip_auteurs ADD alea_futur TINYTEXT DEFAULT ''";
-		spip_query($query);
-		$query = "UPDATE spip_auteurs SET alea_futur = FLOOR(32000*RAND())";
-		spip_query($query);
-		maj_version (1.419);
-	}
-
-	if ($version_installee < 1.420) {
-		$query = "UPDATE spip_auteurs SET alea_actuel='' WHERE statut='nouveau'";
-		spip_query($query);
-		maj_version (1.420);
-	}
-	
-	if ($version_installee < 1.421) {
-		$query = "ALTER TABLE spip_articles ADD auteur_modif bigint(21) DEFAULT '0' NOT NULL";
-		spip_query($query);
-		$query = "ALTER TABLE spip_articles ADD date_modif datetime DEFAULT '0000-00-00 00:00:00' NOT NULL";
-		spip_query($query);
-		maj_version (1.421);
-	}
-
-	if ($version_installee < 1.432) {
-		spip_query("ALTER TABLE spip_articles DROP referers");
-		$query = "ALTER TABLE spip_articles ADD referers INTEGER DEFAULT '0' NOT NULL";
-		spip_query($query);
-		$query = "ALTER TABLE spip_articles ADD popularite INTEGER DEFAULT '0' NOT NULL";
-		spip_query($query);
-		maj_version (1.432);
-	}
-
-	if ($version_installee < 1.436) {
-		$query = "ALTER TABLE spip_documents ADD date datetime DEFAULT '0000-00-00 00:00:00' NOT NULL";
-		spip_query($query);
-		maj_version (1.436);
-	}
-
-	if ($version_installee < 1.437) {
-		spip_query("ALTER TABLE spip_visites ADD maj TIMESTAMP");
-		spip_query("ALTER TABLE spip_visites_referers ADD maj TIMESTAMP");
-		maj_version (1.437);
-	}
-
-	if ($version_installee < 1.438) {
-		spip_query("ALTER TABLE spip_articles ADD INDEX id_secteur (id_secteur)");
-		spip_query("ALTER TABLE spip_articles ADD INDEX statut (statut, date)");
-		maj_version (1.438);
-	}
-
-	if ($version_installee < 1.439) {
-		spip_query("ALTER TABLE spip_syndic ADD INDEX statut (statut, date_syndic)");
-		spip_query("ALTER TABLE spip_syndic_articles ADD INDEX statut (statut)");
-		spip_query("ALTER TABLE spip_syndic_articles CHANGE url url VARCHAR(255) NOT NULL");
-		spip_query("ALTER TABLE spip_syndic_articles ADD INDEX url (url)");
-		maj_version (1.439);
-	}
-
-	if ($version_installee < 1.440) {
-		spip_query("ALTER TABLE spip_visites_temp CHANGE ip ip INTEGER UNSIGNED NOT NULL");
-		maj_version (1.440);
-	}
-
-	if ($version_installee < 1.441) {
-		spip_query("ALTER TABLE spip_visites_temp CHANGE date date DATE NOT NULL");
-		spip_query("ALTER TABLE spip_visites CHANGE date date DATE NOT NULL");
-		spip_query("ALTER TABLE spip_visites_referers CHANGE date date DATE NOT NULL");
-		maj_version (1.441);
-	}
-
-	if ($version_installee < 1.442) {
-		$query = "ALTER TABLE spip_auteurs ADD prefs TINYTEXT NOT NULL";
-		spip_query($query);
-		maj_version (1.442);
-	}
-
-	if ($version_installee < 1.443) {
-		spip_query("ALTER TABLE spip_auteurs CHANGE login login VARCHAR(255) BINARY NOT NULL");
-		spip_query("ALTER TABLE spip_auteurs CHANGE statut statut VARCHAR(255) NOT NULL");
-		spip_query("ALTER TABLE spip_auteurs ADD INDEX login (login)");
-		spip_query("ALTER TABLE spip_auteurs ADD INDEX statut (statut)");
-		maj_version (1.443);
-	}
-
-	if ($version_installee < 1.444) {
-		spip_query("ALTER TABLE spip_syndic ADD moderation VARCHAR(3) NOT NULL");
-		maj_version (1.444);
-	}
-
-	if ($version_installee < 1.457) {
-		spip_query("DROP TABLE spip_visites");
-		spip_query("DROP TABLE spip_visites_temp");
-		spip_query("DROP TABLE spip_visites_referers");
-		creer_base(); // crade, a ameliorer :-((
-		maj_version (1.457);
-	}
-
-	if ($version_installee < 1.458) {
-		spip_query("ALTER TABLE spip_auteurs ADD cookie_oubli TINYTEXT NOT NULL");
-		maj_version (1.458);
-	}
-
-	if ($version_installee < 1.459) {
-		$result = spip_query("SELECT type FROM spip_mots GROUP BY type");
-		while ($row = spip_fetch_array($result)) {
-			$type = addslashes($row['type']);
-			$res = spip_query("SELECT * FROM spip_groupes_mots
-				WHERE titre='$type'");
-			if (spip_num_rows($res) == 0) {
-				spip_query("INSERT IGNORE INTO spip_groupes_mots 
-					(titre, unseul, obligatoire, articles, breves, rubriques, syndic, 0minirezo, 1comite, 6forum)
-					VALUES ('$type', 'non', 'non', 'oui', 'oui', 'non', 'oui', 'oui', 'oui', 'non')");
-				if ($id_groupe = spip_insert_id()) 
-					spip_query("UPDATE spip_mots SET id_groupe = '$id_groupe' WHERE type='$type'");
-			}
-		}
-		spip_query("UPDATE spip_articles SET popularite=0");
-		maj_version (1.459);
-	}
-
-	if ($version_installee < 1.460) {
-		// remettre les mots dans les groupes dupliques par erreur
-		// dans la precedente version du paragraphe de maj 1.459
-		// et supprimer ceux-ci
-		$result = spip_query("SELECT * FROM spip_groupes_mots ORDER BY id_groupe");
-		while ($row = spip_fetch_array($result)) {
-			$titre = addslashes($row['titre']);
-			if (! $vu[$titre] ) {
-				$vu[$titre] = true;
-				$id_groupe = $row['id_groupe'];
-				spip_query ("UPDATE spip_mots SET id_groupe=$id_groupe WHERE type='$titre'");
-				spip_query ("DELETE FROM spip_groupes_mots WHERE titre='$titre' AND id_groupe<>$id_groupe");
-			}
-		}
-		maj_version (1.460);
-	}
-
-	if ($version_installee < 1.462) {
-		spip_query("UPDATE spip_types_documents SET inclus='embed' WHERE inclus!='non' AND extension IN ".
-			"('aiff', 'asf', 'avi', 'mid', 'mov', 'mp3', 'mpg', 'ogg', 'qt', 'ra', 'ram', 'rm', 'swf', 'wav', 'wmv')");
-		maj_version (1.462);
-	}
-
-	if ($version_installee < 1.463) {
-		spip_query("ALTER TABLE spip_articles CHANGE popularite popularite DOUBLE");
-		spip_query("ALTER TABLE spip_visites_temp ADD maj TIMESTAMP");
-		spip_query("ALTER TABLE spip_referers_temp ADD maj TIMESTAMP");
-		maj_version (1.463);
-	}
-
-	// l'upgrade < 1.462 ci-dessus etait fausse, d'ou correctif
-	if (($version_installee < 1.464) AND ($version_installee >= 1.462)) {
-		$res = spip_query("SELECT id_type, extension FROM spip_types_documents WHERE id_type NOT IN (1,2,3)");
-		while ($row = spip_fetch_array($res)) {
-			$extension = $row['extension'];
-			$id_type = $row['id_type'];
-			spip_query("UPDATE spip_documents SET id_type=$id_type
-				WHERE fichier like '%.$extension'");
-		}
-		maj_version (1.464);
-	}
-
-	if ($version_installee < 1.465) {
-		spip_query("ALTER TABLE spip_articles CHANGE popularite popularite DOUBLE NOT NULL");
-		maj_version (1.465);
-	}
-
-	if ($version_installee < 1.466) {
-		spip_query("ALTER TABLE spip_auteurs ADD source VARCHAR(10) DEFAULT 'spip' NOT NULL");
-		maj_version (1.466);
-	}
-
-	if ($version_installee < 1.468) {
-		spip_query("ALTER TABLE spip_auteurs ADD INDEX en_ligne (en_ligne)");
-		spip_query("ALTER TABLE spip_forum ADD INDEX statut (statut, date_heure)");
-		maj_version (1.468);
-	}
-
-	if ($version_installee < 1.470) {
-		if ($version_installee >= 1.467) {	// annule les "listes de diff"
-			spip_query("DROP TABLE spip_listes");
-			spip_query("ALTER TABLE spip_auteurs DROP abonne");
-			spip_query("ALTER TABLE spip_auteurs DROP abonne_pass");
-		}
-		maj_version (1.470);
-	}
-
-	if ($version_installee < 1.471) {
-		if ($version_installee >= 1.470) {	// annule les "maj"
-			spip_query("ALTER TABLE spip_auteurs_articles DROP maj TIMESTAMP");
-			spip_query("ALTER TABLE spip_auteurs_rubriques DROP maj TIMESTAMP");
-			spip_query("ALTER TABLE spip_auteurs_messages DROP maj TIMESTAMP");
-			spip_query("ALTER TABLE spip_documents_articles DROP maj TIMESTAMP");
-			spip_query("ALTER TABLE spip_documents_rubriques DROP maj TIMESTAMP");
-			spip_query("ALTER TABLE spip_documents_breves DROP maj TIMESTAMP");
-			spip_query("ALTER TABLE spip_mots_articles DROP maj TIMESTAMP");
-			spip_query("ALTER TABLE spip_mots_breves DROP maj TIMESTAMP");
-			spip_query("ALTER TABLE spip_mots_rubriques DROP maj TIMESTAMP");
-			spip_query("ALTER TABLE spip_mots_syndic DROP maj TIMESTAMP");
-			spip_query("ALTER TABLE spip_mots_forum DROP maj TIMESTAMP");
-		}
-		maj_version (1.471);
-	}
-
-	if ($version_installee < 1.472) {
-		spip_query("ALTER TABLE spip_referers ADD visites_jour INTEGER UNSIGNED NOT NULL");
-		maj_version (1.472);
-	}
-
-	if ($version_installee < 1.473) {
-		spip_query("UPDATE spip_syndic_articles SET url = REPLACE(url, '&amp;', '&')");
-		spip_query("UPDATE spip_syndic SET url_site = REPLACE(url_site, '&amp;', '&')");
-		maj_version (1.473);
-	}
-
-	if ($version_installee < 1.600) {
-		include_ecrire('inc_index.php3');
-		purger_index();
-		creer_liste_indexation();
-		maj_version (1.600);
-	}
-
-	if ($version_installee < 1.601) {
-		spip_query("ALTER TABLE spip_forum ADD INDEX id_syndic (id_syndic)");
-		maj_version (1.601);
-	}
-
-	if ($version_installee < 1.603) {
-		// supprimer les fichiers deplaces
-		@unlink('inc_meta_cache.php3');
-		@unlink('data/engines-list.ini');
-		maj_version (1.603);
-	}
-
-	if ($version_installee < 1.604) {
-		spip_query("ALTER TABLE spip_auteurs ADD lang VARCHAR(10) DEFAULT '' NOT NULL");
-		$u = spip_query("SELECT * FROM spip_auteurs WHERE prefs LIKE '%spip_lang%'");
-		while ($row = spip_fetch_array($u)) {
-			$prefs = unserialize($row['prefs']);
-			$l = $prefs['spip_lang'];
-			unset ($prefs['spip_lang']);
-			spip_query ("UPDATE spip_auteurs SET lang='".addslashes($l)."',
-				prefs='".addslashes(serialize($prefs))."'
-				WHERE id_auteur=".$row['id_auteur']);
-		}
-		maj_version (1.604, spip_query("SELECT lang FROM spip_auteurs"));
-	}
-
-	if ($version_installee < 1.702) {
-		spip_query("ALTER TABLE spip_articles ADD extra longblob NULL");
-		spip_query("ALTER TABLE spip_auteurs ADD extra longblob NULL");
-		spip_query("ALTER TABLE spip_breves ADD extra longblob NULL");
-		spip_query("ALTER TABLE spip_rubriques ADD extra longblob NULL");
-		spip_query("ALTER TABLE spip_mots ADD extra longblob NULL");
-
-		// recuperer les eventuels 'supplement' installes en 1.701
-		if ($version_installee == 1.701) {
-			spip_query ("UPDATE spip_articles SET extra = supplement");
-			spip_query ("ALTER TABLE spip_articles DROP supplement");
-			spip_query ("UPDATE spip_auteurs SET extra = supplement");
-			spip_query ("ALTER TABLE spip_auteurs DROP supplement");
-			spip_query ("UPDATE spip_breves SET extra = supplement");
-			spip_query ("ALTER TABLE spip_breves DROP supplement");
-			spip_query ("UPDATE spip_rubriques SET extra = supplement");
-			spip_query ("ALTER TABLE spip_rubriques DROP supplement");
-			spip_query ("UPDATE spip_mots SET extra = supplement");
-			spip_query ("ALTER TABLE spip_mots DROP supplement");
-		}
-		maj_version (1.702,
-			spip_query("SELECT extra FROM spip_articles")
-			&& spip_query("SELECT extra FROM spip_auteurs")
-			&& spip_query("SELECT extra FROM spip_breves")
-			&& spip_query("SELECT extra FROM spip_rubriques")
-			&& spip_query("SELECT extra FROM spip_mots")
-			);
-	}
-
-	if ($version_installee < 1.703) {
-		spip_query("ALTER TABLE spip_articles ADD lang VARCHAR(10) DEFAULT '' NOT NULL");
-		spip_query("ALTER TABLE spip_rubriques ADD lang VARCHAR(10) DEFAULT '' NOT NULL");
-		maj_version (1.703);
-	}
-
-	if ($version_installee < 1.704) {
-		spip_query("ALTER TABLE spip_articles ADD INDEX lang (lang)");
-		spip_query("ALTER TABLE spip_auteurs ADD INDEX lang (lang)");
-		spip_query("ALTER TABLE spip_rubriques ADD INDEX lang (lang)");
-		maj_version (1.704);
-	}
-
-	if ($version_installee < 1.705) {
-		spip_query("ALTER TABLE spip_articles ADD langue_choisie VARCHAR(3) DEFAULT 'non'");
-		spip_query("ALTER TABLE spip_rubriques ADD langue_choisie VARCHAR(3) DEFAULT 'non'");
-		maj_version (1.705);
-	}
-
-	if ($version_installee < 1.707) {
-		spip_query("UPDATE spip_articles SET langue_choisie='oui' WHERE MID(lang,1,1) != '.' AND lang != ''");
-		spip_query("UPDATE spip_articles SET lang=MID(lang,2,8) WHERE langue_choisie = 'non'");
-		spip_query("UPDATE spip_rubriques SET langue_choisie='oui' WHERE MID(lang,1,1) != '.' AND lang != ''");
-		spip_query("UPDATE spip_rubriques SET lang=MID(lang,2,8) WHERE langue_choisie = 'non'");
-		maj_version (1.707);
-	}
-
-	if ($version_installee < 1.708) {
-		spip_query("ALTER TABLE spip_breves ADD lang VARCHAR(10) DEFAULT '' NOT NULL");
-		spip_query("ALTER TABLE spip_breves ADD langue_choisie VARCHAR(3) DEFAULT 'non'");
-		maj_version (1.708);
-	}
-
-	if ($version_installee < 1.709) {
-		spip_query("ALTER TABLE spip_articles ADD id_trad bigint(21) DEFAULT '0' NOT NULL");
-		spip_query("ALTER TABLE spip_articles ADD INDEX id_trad (id_trad)");
-		maj_version (1.709);
-	}
-
-	if ($version_installee < 1.717) {
-		spip_query("ALTER TABLE spip_articles ADD INDEX date_modif (date_modif)");
-		maj_version (1.717);
-	}
-
-	if ($version_installee < 1.718) {
-		spip_query("ALTER TABLE spip_referers DROP domaine");
-		spip_query("ALTER TABLE spip_referers_articles DROP domaine");
-		spip_query("ALTER TABLE spip_referers_temp DROP domaine");
-		maj_version (1.718);
-	}
-
-	if ($version_installee < 1.722) {
-		spip_query("ALTER TABLE spip_articles ADD nom_site tinytext NOT NULL");
-		spip_query("ALTER TABLE spip_articles ADD url_site VARCHAR(255) NOT NULL");
-		spip_query("ALTER TABLE spip_articles ADD INDEX url_site (url_site)");
-		if ($version_installee >= 1.720) {
-			spip_query("UPDATE spip_articles SET url_site=url_ref");
-			spip_query("ALTER TABLE spip_articles DROP INDEX url_ref");
-			spip_query("ALTER TABLE spip_articles DROP url_ref");
-		}
-		maj_version (1.722);
-	}
-
-	if ($version_installee < 1.723) {
-		if ($version_installee == 1.722) {
-			spip_query("ALTER TABLE spip_articles MODIFY url_site VARCHAR(255) NOT NULL");
-			spip_query("ALTER TABLE spip_articles DROP INDEX url_site;");
-			spip_query("ALTER TABLE spip_articles ADD INDEX url_site (url_site);");
-		}
-		maj_version (1.723);
-	}
-
-	if ($version_installee < 1.724) {
-		spip_query("ALTER TABLE spip_messages ADD date_fin datetime DEFAULT '0000-00-00 00:00:00' NOT NULL");
-		maj_version (1.724);
-	}
-
-	if ($version_installee < 1.726) {
-		spip_query("ALTER TABLE spip_auteurs ADD low_sec tinytext NOT NULL");
-		maj_version (1.726);
-	}
-
-	if ($version_installee < 1.727) {
-		// occitans : oci_xx -> oc_xx
-		spip_query("UPDATE spip_auteurs SET lang=REPLACE(lang,'oci_', 'oc_') WHERE lang LIKE 'oci_%'");
-		spip_query("UPDATE spip_rubriques SET lang=REPLACE(lang,'oci_', 'oc_') WHERE lang LIKE 'oci_%'");
-		spip_query("UPDATE spip_articles SET lang=REPLACE(lang,'oci_', 'oc_') WHERE lang LIKE 'oci_%'");
-		spip_query("UPDATE spip_breves SET lang=REPLACE(lang,'oci_', 'oc_') WHERE lang LIKE 'oci_%'");
-		maj_version (1.727);
-	}
-
-	// Ici version 1.7 officielle
-
-	if ($version_installee < 1.728) {
-		spip_query("ALTER TABLE spip_articles ADD id_version int unsigned DEFAULT '0' NOT NULL");
-		maj_version (1.728);
-	}
-
-	if ($version_installee < 1.730) {
-		spip_query("ALTER TABLE spip_articles ADD idx ENUM('', '1', 'non', 'oui', 'idx') DEFAULT '' NOT NULL");
-		spip_query("ALTER TABLE spip_articles INDEX idx (idx)");
-		spip_query("ALTER TABLE spip_auteurs ADD idx ENUM('', '1', 'non', 'oui', 'idx') DEFAULT '' NOT NULL");
-		spip_query("ALTER TABLE spip_auteurs INDEX idx (idx)");
-		spip_query("ALTER TABLE spip_breves ADD idx ENUM('', '1', 'non', 'oui', 'idx') DEFAULT '' NOT NULL");
-		spip_query("ALTER TABLE spip_breves INDEX idx (idx)");
-		spip_query("ALTER TABLE spip_mots ADD idx ENUM('', '1', 'non', 'oui', 'idx') DEFAULT '' NOT NULL");
-		spip_query("ALTER TABLE spip_mots INDEX idx (idx)");
-		spip_query("ALTER TABLE spip_rubriques ADD idx ENUM('', '1', 'non', 'oui', 'idx') DEFAULT '' NOT NULL");
-		spip_query("ALTER TABLE spip_rubriques INDEX idx (idx)");
-		spip_query("ALTER TABLE spip_syndic ADD idx ENUM('', '1', 'non', 'oui', 'idx') DEFAULT '' NOT NULL");
-		spip_query("ALTER TABLE spip_syndic INDEX idx (idx)");
-		spip_query("ALTER TABLE spip_forum ADD idx ENUM('', '1', 'non', 'oui', 'idx') DEFAULT '' NOT NULL");
-		spip_query("ALTER TABLE spip_forum ADD INDEX idx (idx)");
-		spip_query("ALTER TABLE spip_signatures ADD idx ENUM('', '1', 'non', 'oui', 'idx') DEFAULT '' NOT NULL");
-		spip_query("ALTER TABLE spip_signatures INDEX idx (idx)");
-		maj_version (1.730);
-	}
-
-	if ($version_installee < 1.731) {	// reindexer les docs allemands et vietnamiens
-		spip_query("UPDATE spip_articles SET idx='1' where lang IN ('de','vi')");
-		spip_query("UPDATE spip_rubriques SET idx='1' where lang IN ('de','vi')");
-		spip_query("UPDATE spip_breves SET idx='1' where lang IN ('de','vi')");
-		spip_query("UPDATE spip_auteurs SET idx='1' where lang IN ('de','vi')");
-		maj_version (1.731);
-	}
-
-	if ($version_installee < 1.732) {	// en correction d'un vieux truc qui avait fait sauter le champ inclus sur les bases version 1.415
-		spip_query ("ALTER TABLE spip_documents ADD inclus  VARCHAR(3) DEFAULT 'non'");
-		maj_version (1.732);
-	}
-
-	if ($version_installee < 1.733) {
-		// spip_query("ALTER TABLE spip_articles ADD id_version int unsigned DEFAULT '0' NOT NULL");
-		spip_query("DROP TABLE spip_versions");
-		spip_query("DROP TABLE spip_versions_fragments");
-		creer_base();
-		maj_version(1.733);
-	}
-
-	return true;
-}
-
 ?>
diff --git a/ecrire/inc_cron.php3 b/ecrire/inc_cron.php3
index 61a73d9ff6..3d3cc54efa 100644
--- a/ecrire/inc_cron.php3
+++ b/ecrire/inc_cron.php3
@@ -56,7 +56,7 @@ function cron_archiver_stats($last_date) {
 // La fonction de base qui distribue les taches
 //
 function spip_cron() {
-	global $flag_ecrire, $dir_ecrire, $use_cache, $db_ok;
+	global $flag_ecrire, $dir_ecrire, $db_ok;
 
 	include_ecrire("inc_connect.php3");
 	if (!$db_ok) {
@@ -73,22 +73,45 @@ function spip_cron() {
 
 	//
 	// Envoi du mail quoi de neuf
-	//
-	if (!$flag_ecrire AND (lire_meta('quoi_de_neuf') == 'oui') AND ($jours_neuf = lire_meta('jours_neuf'))
-	AND ($adresse_neuf = lire_meta('adresse_neuf')) AND (time() - ($majnouv = lire_meta('majnouv'))) > 3600 * 24 * $jours_neuf) {
-
-		if (timeout('quoide_neuf')) {
+	
+	$adresse_neuf = lire_meta('adresse_neuf');
+	$jours_neuf = lire_meta('jours_neuf');
+	if (!$flag_ecrire AND 
+	    $adresse_neuf AND 
+	    $jours_neuf AND
+	    (lire_meta('quoi_de_neuf') == 'oui') AND 
+	    (time() - ($majnouv = lire_meta('majnouv'))) > 3600 * 24 * $jours_neuf) {
+
+	  if (timeout('quoide_neuf')) { 
 			ecrire_meta('majnouv', time());
 			ecrire_metas();
 
-			// preparation mail
-			unset ($mail_nouveautes);
-			unset ($sujet_nouveautes);
-			$fond = 'nouveautes';
-			$delais = 0;
-			$contexte_inclus = array('date' => date('Y-m-d H:i:s', $majnouv));
-			include(inclure_fichier($fond, $delais, $contexte_inclus));
-
+			include_local("inc-calcul.php3");
+			$page= cherche_page('nouveautes',
+					    '',
+					    array('date' => date('Y-m-d H:i:s', $majnouv)),
+					    '',
+					    '');
+			$page = $page['texte'];
+			if (substr($page,0,5) == '<?php')
+			  {
+# ancienne version: squelette en PHP avec affections. 1 passe de +
+			    unset ($mail_nouveautes);
+			    unset ($sujet_nouveautes);
+			    eval ('?' . '>' . $page);
+			  }
+			else 
+			  { 
+# nouvelle version: squelette en mode texte, 1ere ligne = sujet
+# il faudrait ge'ne'raliser en produisant les Headers standars SMTP
+# a` passer en 4e argument de mail. Surtout utile pour le charset.
+			    $page = stripslashes($page);
+			    $p = strpos($page,"\n");
+			    $sujet_nouveautes = substr($page,0,$p);
+			    $mail_nouveautes = ereg_replace('\$jours_neuf',
+							    "$jours_neuf",
+							    substr($page,$p+1));
+			  }
 			// envoi
 			if ($mail_nouveautes) {
 				spip_log("envoi mail nouveautes");
@@ -96,9 +119,8 @@ function spip_cron() {
 				envoyer_mail($adresse_neuf, $sujet_nouveautes, $mail_nouveautes);
 			} else
 				spip_log("envoi mail nouveautes : pas de nouveautes");
-		}
-	}
-
+					}
+	  	}
 
 	//
 	// Statistiques
@@ -129,47 +151,13 @@ function spip_cron() {
 	}
 
 
-	//
-	// Faire du menage dans le cache (effacer les fichiers tres anciens ou inutilises)
-	// Se declenche une fois par heure quand le cache n'est pas recalcule
-	//
-	if (!$flag_ecrire AND $use_cache AND @file_exists('CACHE/.purge2')) {
-		if (timeout('purge_cache')) {
-			unlink('CACHE/.purge2');
-			spip_log("purge cache niveau 2");
-			$query = "SELECT fichier FROM spip_forum_cache WHERE maj < DATE_SUB(NOW(), INTERVAL 14 DAY)";
-			$result = spip_query($query);
-			unset($fichiers);
-			while ($row = spip_fetch_array($result)) {
-				$fichier = $row['fichier'];
-				if (!@file_exists("CACHE/$fichier")) $fichiers[] = "'$fichier'";
-			}
-			if ($fichiers) {
-				$query = "DELETE FROM spip_forum_cache WHERE fichier IN (".join(',', $fichiers).")";
-				spip_query($query);
-			}
-		}
-	}
-	if (!$flag_ecrire AND $use_cache AND @file_exists('CACHE/.purge')) {
-		if (timeout('purge_cache')) {
-			$dir = 'CACHE/'.dechex((time() / 3600) & 0xF);
-			unlink('CACHE/.purge');
-			spip_log("purge cache niveau 1: $dir");
-			$f = fopen('CACHE/.purge2', 'w');
-			fclose($f);
-			include_local ("inc-cache.php3");
-			purger_repertoire($dir, 14 * 24 * 3600);
-		}
-	}
-
-
-
 	//
 	// Gerer l'indexation
 	//
 
-	if ($use_cache AND (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();
 		}
@@ -222,4 +210,4 @@ function spip_cron() {
 }
 
 
-?>
\ No newline at end of file
+?>
diff --git a/ecrire/inc_majbase.php3 b/ecrire/inc_majbase.php3
new file mode 100644
index 0000000000..24439b07c4
--- /dev/null
+++ b/ecrire/inc_majbase.php3
@@ -0,0 +1,830 @@
+<?php
+
+//
+// Ce fichier ne sera execute qu'une fois
+if (defined("_ECRIRE_INC_MAJBASE")) return;
+define("_ECRIRE_INC_MAJBASE", "1");
+
+function maj_version ($version, $test = true) {
+	if ($test) {
+		spip_query("REPLACE spip_meta (nom, valeur) VALUES ('version_installee', '$version')");
+		spip_log("mise a jour de la base vers $version");
+	} else {
+		include_ecrire ('inc_lang.php3');
+		echo _T('alerte_maj_impossible', array('version' => $version));
+		exit;
+	}
+}
+function maj_base() {
+
+	global $spip_version;
+
+	//
+	// Lecture de la version installee
+	//
+	$version_installee = 0.0;
+	$result = spip_query("SELECT valeur FROM spip_meta WHERE nom='version_installee'");
+	if ($result) if ($row = spip_fetch_array($result)) $version_installee = (double) $row['valeur'];
+
+	//
+	// Si pas de version mentionnee dans spip_meta, c'est qu'il s'agit d'une nouvelle installation
+	//   => ne pas passer par le processus de mise a jour
+	//
+#	$version_installee = 1.702; quand on a besoin de forcer une MAJ
+	if (!$version_installee) {
+		$version_installee = $spip_version;
+		maj_version($version_installee);
+		return true;
+	}
+
+
+//
+	// Verification des droits de modification sur la base
+	//
+
+	spip_query("DROP TABLE IF EXISTS spip_test");
+	spip_query("CREATE TABLE spip_test (a INT)");
+	spip_query("ALTER TABLE spip_test ADD b INT");
+	spip_query("INSERT INTO spip_test (b) VALUES (1)");
+	$result = spip_query("SELECT b FROM spip_test");
+	spip_query("ALTER TABLE spip_test DROP b");
+#	if (!$result) return false;
+
+	//
+	// Selection en fonction de la version
+	//
+	if ($version_installee < 0.98) {
+
+		spip_query("ALTER TABLE spip_articles ADD maj TIMESTAMP");
+		spip_query("ALTER TABLE spip_articles ADD export VARCHAR(10) DEFAULT 'oui'");
+		spip_query("ALTER TABLE spip_articles ADD images TEXT DEFAULT ''");
+		spip_query("ALTER TABLE spip_articles ADD date_redac datetime DEFAULT '0000-00-00 00:00:00' NOT NULL");
+		spip_query("ALTER TABLE spip_articles DROP INDEX id_article");
+		spip_query("ALTER TABLE spip_articles ADD INDEX id_rubrique (id_rubrique)");
+		spip_query("ALTER TABLE spip_articles ADD visites INTEGER DEFAULT '0' NOT NULL");
+		spip_query("ALTER TABLE spip_articles ADD referers BLOB NOT NULL");
+
+		spip_query("ALTER TABLE spip_auteurs ADD maj TIMESTAMP");
+		spip_query("ALTER TABLE spip_auteurs ADD pgp BLOB NOT NULL");
+
+		spip_query("ALTER TABLE spip_auteurs_articles ADD INDEX id_auteur (id_auteur), ADD INDEX id_article (id_article)");
+	
+		spip_query("ALTER TABLE spip_rubriques ADD maj TIMESTAMP");
+		spip_query("ALTER TABLE spip_rubriques ADD export VARCHAR(10) DEFAULT 'oui', ADD id_import BIGINT DEFAULT '0'");
+	
+		spip_query("ALTER TABLE spip_breves ADD maj TIMESTAMP");
+		spip_query("ALTER TABLE spip_breves DROP INDEX id_breve");
+		spip_query("ALTER TABLE spip_breves DROP INDEX id_breve_2");
+		spip_query("ALTER TABLE spip_breves ADD INDEX id_rubrique (id_rubrique)");
+	
+		spip_query("ALTER TABLE spip_forum ADD ip VARCHAR(16)");
+		spip_query("ALTER TABLE spip_forum ADD maj TIMESTAMP");
+		spip_query("ALTER TABLE spip_forum DROP INDEX id_forum");
+		spip_query("ALTER TABLE spip_forum ADD INDEX id_parent (id_parent), ADD INDEX id_rubrique (id_rubrique), ADD INDEX id_article(id_article), ADD INDEX id_breve(id_breve)");
+		maj_version (0.98);
+	}
+
+	if ($version_installee < 0.99) {
+	
+		$query = "SELECT DISTINCT id_article FROM spip_forum WHERE id_article!=0 AND id_parent=0";
+		$result = spip_query($query);
+		while ($row = spip_fetch_array($result)) {
+			unset($forums_article);
+			$id_article = $row['id_article'];
+			$query2 = "SELECT id_forum FROM spip_forum WHERE id_article=$id_article";
+			for (;;) {
+				$result2 = spip_query($query2);
+				unset($forums);
+				while ($row2 = spip_fetch_array($result2)) $forums[] = $row2['id_forum'];
+				if (!$forums) break;
+				$forums = join(',', $forums);
+				$forums_article[] = $forums;
+				$query2 = "SELECT id_forum FROM spip_forum WHERE id_parent IN ($forums)";
+			}
+			$forums_article = join(',', $forums_article);
+			$query3 = "UPDATE spip_forum SET id_article=$id_article WHERE id_forum IN ($forums_article)";
+			spip_query($query3);
+		}
+	
+		$query = "SELECT DISTINCT id_breve FROM spip_forum WHERE id_breve!=0 AND id_parent=0";
+		$result = spip_query($query);
+		while ($row = spip_fetch_array($result)) {
+			unset($forums_breve);
+			$id_breve = $row['id_breve'];
+			$query2 = "SELECT id_forum FROM spip_forum WHERE id_breve=$id_breve";
+			for (;;) {
+				$result2 = spip_query($query2);
+				unset($forums);
+				while ($row2 = spip_fetch_array($result2)) $forums[] = $row2['id_forum'];
+				if (!$forums) break;
+				$forums = join(',', $forums);
+				$forums_breve[] = $forums;
+				$query2 = "SELECT id_forum FROM spip_forum WHERE id_parent IN ($forums)";
+			}
+			$forums_breve = join(',', $forums_breve);
+			$query3 = "UPDATE spip_forum SET id_breve=$id_breve WHERE id_forum IN ($forums_breve)";
+			spip_query($query3);
+		}
+	
+		$query = "SELECT DISTINCT id_rubrique FROM spip_forum WHERE id_rubrique!=0 AND id_parent=0";
+		$result = spip_query($query);
+		while ($row = spip_fetch_array($result)) {
+			unset($forums_rubrique);
+			$id_rubrique = $row['id_rubrique'];
+			$query2 = "SELECT id_forum FROM spip_forum WHERE id_rubrique=$id_rubrique";
+			for (;;) {
+				$result2 = spip_query($query2);
+				unset($forums);
+				while ($row2 = spip_fetch_array($result2)) $forums[] = $row2['id_forum'];
+				if (!$forums) break;
+				$forums = join(',', $forums);
+				$forums_rubrique[] = $forums;
+				$query2 = "SELECT id_forum FROM spip_forum WHERE id_parent IN ($forums)";
+			}
+			$forums_rubrique = join(',', $forums_rubrique);
+			$query3 = "UPDATE spip_forum SET id_rubrique=$id_rubrique WHERE id_forum IN ($forums_rubrique)";
+			spip_query($query3);
+		}
+		maj_version (0.99);
+	}
+
+	if ($version_installee < 0.997) {
+		spip_query("DROP TABLE spip_index");
+		maj_version (0.997);
+	}
+
+	if ($version_installee < 0.999) {
+		global $htsalt;
+		spip_query("ALTER TABLE spip_auteurs CHANGE pass pass tinyblob NOT NULL");
+		spip_query("ALTER TABLE spip_auteurs ADD htpass tinyblob NOT NULL");
+		$query = "SELECT id_auteur, pass FROM spip_auteurs WHERE pass!=''";
+		$result = spip_query($query);
+		while (list($id_auteur, $pass) = spip_fetch_array($result)) {
+			$htpass = generer_htpass($pass);
+			$pass = md5($pass);
+			spip_query("UPDATE spip_auteurs SET pass='$pass', htpass='$htpass' WHERE id_auteur=$id_auteur");
+		}
+		maj_version (0.999);
+	}
+	
+	if ($version_installee < 1.01) {
+		spip_query("UPDATE spip_forum SET statut='publie' WHERE statut=''");
+		maj_version (1.01);
+	}
+	
+	if ($version_installee < 1.02) {
+		spip_query("ALTER TABLE spip_forum ADD id_auteur BIGINT DEFAULT '0' NOT NULL");
+		maj_version (1.02);
+	}
+
+	if ($version_installee < 1.03) {
+		spip_query("DROP TABLE spip_maj");
+		maj_version (1.03);
+	}
+
+	if ($version_installee < 1.04) {
+		spip_query("ALTER TABLE spip_articles ADD accepter_forum VARCHAR(3)");
+		maj_version (1.04);
+	}
+
+	if ($version_installee < 1.05) {
+		spip_query("DROP TABLE spip_petition");
+		spip_query("DROP TABLE spip_signatures_petition");
+		maj_version (1.05);
+	}
+
+	if ($version_installee < 1.1) {
+		spip_query("DROP TABLE spip_petition");
+		spip_query("DROP TABLE spip_signatures_petition");
+		maj_version (1.1);
+	}
+
+	// Correction de l'oubli des modifs creations depuis 1.04
+	if ($version_installee < 1.204) {
+		spip_query("ALTER TABLE spip_articles ADD accepter_forum VARCHAR(3) NOT NULL");
+		spip_query("ALTER TABLE spip_forum ADD id_message bigint(21) NOT NULL");
+		spip_query("ALTER TABLE spip_forum ADD INDEX id_message (id_message)");
+		spip_query("ALTER TABLE spip_auteurs ADD en_ligne datetime DEFAULT '0000-00-00 00:00:00' NOT NULL");
+		spip_query("ALTER TABLE spip_auteurs ADD imessage VARCHAR(3) not null");
+		spip_query("ALTER TABLE spip_auteurs ADD messagerie VARCHAR(3) not null");
+		maj_version (1.204);
+	}
+
+	if ($version_installee < 1.207) {
+		spip_query("ALTER TABLE spip_rubriques DROP INDEX id_rubrique");
+		spip_query("ALTER TABLE spip_rubriques ADD INDEX id_parent (id_parent)");
+		spip_query("ALTER TABLE spip_rubriques ADD statut VARCHAR(10) NOT NULL");
+		// Declencher le calcul des rubriques publiques
+		spip_query("REPLACE spip_meta (nom, valeur) VALUES ('calculer_rubriques', 'oui')");
+		maj_version (1.207);
+	}
+
+	if ($version_installee < 1.208) {
+		spip_query("ALTER TABLE spip_auteurs_messages CHANGE forum vu CHAR(3) NOT NULL");
+		spip_query("UPDATE spip_auteurs_messages SET vu='oui'");
+		spip_query("UPDATE spip_auteurs_messages SET vu='non' WHERE statut='a'");
+
+		spip_query("ALTER TABLE spip_messages ADD id_auteur bigint(21) NOT NULL");
+		spip_query("ALTER TABLE spip_messages ADD INDEX id_auteur (id_auteur)");
+		$result = spip_query("SELECT id_auteur, id_message FROM spip_auteurs_messages WHERE statut='de'");
+		while ($row = spip_fetch_array($result)) {
+			$id_auteur = $row['id_auteur'];
+			$id_message = $row['id_message'];
+			spip_query("UPDATE spip_messages SET id_auteur=$id_auteur WHERE id_message=$id_message");
+		}
+
+		spip_query("ALTER TABLE spip_auteurs_messages DROP statut");
+		maj_version (1.208);
+	}
+
+	if ($version_installee < 1.209) {
+		spip_query("ALTER TABLE spip_syndic ADD maj TIMESTAMP");
+		spip_query("ALTER TABLE spip_syndic_articles ADD maj TIMESTAMP");
+		spip_query("ALTER TABLE spip_messages ADD maj TIMESTAMP");
+		maj_version (1.209);
+	}
+
+	if ($version_installee < 1.210) {
+		spip_query("ALTER TABLE spip_messages DROP page");
+
+		stripslashes_base('spip_articles', array('surtitre', 'titre', 'soustitre', 'descriptif', 'chapo', 'texte', 'ps'));
+		stripslashes_base('spip_auteurs', array('nom', 'bio', 'nom_site'));
+		stripslashes_base('spip_breves', array('titre', 'texte', 'lien_titre'));
+		stripslashes_base('spip_forum', array('titre', 'texte', 'auteur', 'nom_site'));
+		stripslashes_base('spip_messages', array('titre', 'texte'));
+		stripslashes_base('spip_mots', array('type', 'titre', 'descriptif', 'texte'));
+		stripslashes_base('spip_petitions', array('texte'));
+		stripslashes_base('spip_rubriques', array('titre', 'descriptif', 'texte'));
+		stripslashes_base('spip_signatures', array('nom_email', 'nom_site', 'message'));
+		stripslashes_base('spip_syndic', array('nom_site', 'descriptif'));
+		stripslashes_base('spip_syndic_articles', array('titre', 'lesauteurs'));
+		maj_version (1.210);
+	}
+
+	if ($version_installee < 1.3) {
+		// Modifier la syndication (pour liste de sites)
+		spip_query("ALTER TABLE spip_syndic ADD syndication VARCHAR(3) NOT NULL");
+		spip_query("ALTER TABLE spip_syndic ADD statut VARCHAR(10) NOT NULL");
+		spip_query("ALTER TABLE spip_syndic ADD date datetime DEFAULT '0000-00-00 00:00:00' NOT NULL");
+		spip_query("UPDATE spip_syndic SET syndication='oui', statut='publie', date=NOW()");
+
+		// Statut pour articles syndication, pour pouvoir desactiver un article
+		spip_query("ALTER TABLE spip_syndic_articles ADD statut VARCHAR(10) NOT NULL");
+		spip_query("UPDATE spip_syndic_articles SET statut='publie'");
+		maj_version (1.3);
+	}
+
+	if ($version_installee < 1.301) {
+		spip_query("ALTER TABLE spip_forum ADD id_syndic bigint(21) DEFAULT '0' NOT NULL");
+		maj_version (1.301);
+	}
+
+	if ($version_installee < 1.302) {
+		spip_query("ALTER TABLE spip_forum_cache DROP PRIMARY KEY");
+		spip_query("ALTER TABLE spip_forum_cache DROP INDEX fichier");
+		spip_query("ALTER TABLE spip_forum_cache ADD PRIMARY KEY (fichier, id_forum, id_article, id_rubrique, id_breve, id_syndic)");
+		spip_query("ALTER TABLE spip_forum ADD INDEX id_syndic (id_syndic)");
+		maj_version (1.302);
+	}
+
+	if ($version_installee < 1.303) {
+		spip_query("ALTER TABLE spip_rubriques ADD date datetime DEFAULT '0000-00-00 00:00:00' NOT NULL");
+		spip_query("ALTER TABLE spip_syndic ADD date_syndic datetime DEFAULT '0000-00-00 00:00:00' NOT NULL");
+		spip_query("UPDATE spip_syndic SET date_syndic=date");
+		maj_version (1.303);
+	}
+
+	if ($version_installee < 1.306) {
+		spip_query("DROP TABLE spip_index_syndic_articles");
+		spip_query("ALTER TABLE spip_syndic ADD date_index datetime DEFAULT '0000-00-00 00:00:00' NOT NULL");
+		spip_query("ALTER TABLE spip_syndic ADD INDEX date_index (date_index)");
+		maj_version (1.306);
+	}
+
+	if ($version_installee < 1.307) {
+		spip_query("ALTER TABLE spip_syndic_articles ADD descriptif blob NOT NULL");
+		maj_version (1.307);
+	}
+
+	if ($version_installee < 1.404) {
+		spip_query("UPDATE spip_mots SET type='Mots sans groupe...' WHERE type=''");
+
+		$result = spip_query("SELECT * FROM spip_mots GROUP BY type");
+		while($row = spip_fetch_array($result)) {
+				$type = addslashes($row['type']);
+				spip_query("INSERT INTO spip_groupes_mots 
+					(titre, unseul, obligatoire, articles, breves, rubriques, syndic, 0minirezo, 1comite, 6forum)
+					VALUES (\"$type\", 'non', 'non', 'oui', 'oui', 'non', 'oui', 'oui', 'oui', 'non')");
+		}
+		spip_query("DELETE FROM spip_mots WHERE titre='kawax'");
+		maj_version (1.404);
+	}
+
+	if ($version_installee < 1.405) {
+		spip_query("ALTER TABLE spip_mots ADD id_groupe bigint(21) NOT NULL");
+	
+		$result = spip_query("SELECT * FROM spip_groupes_mots");
+		while($row = spip_fetch_array($result)) {
+				$id_groupe = addslashes($row['id_groupe']);
+				$type = addslashes($row['titre']);
+				spip_query("UPDATE spip_mots SET id_groupe = '$id_groupe' WHERE type=\"$type\"");
+		}
+		maj_version (1.405);
+	}
+
+	if ($version_installee < 1.408) {
+		// Images articles passent dans spip_documents
+		$query = "SELECT id_article, images FROM spip_articles WHERE LENGTH(images) > 0";
+		$result = spip_query($query);
+
+		$types = array('jpg' => 1, 'png' => 2, 'gif' => 3);
+
+		while ($row = @spip_fetch_array($result)) {
+			$id_article = $row['id_article'];
+			$images = $row['images'];
+			$images = explode(",", $images);
+			reset($images);
+			$replace = '_orig_';
+			while (list (, $val) = each($images)) {
+				$image = explode("|", $val);
+				$fichier = $image[0];
+				$largeur = $image[1];
+				$hauteur = $image[2];
+				ereg("-([0-9]+)\.(gif|jpg|png)$", $fichier, $match);
+				$id_type = intval($types[$match[2]]);
+				$num_img = $match[1];
+				$fichier = "IMG/$fichier";
+				$taille = @filesize("../$fichier");
+				spip_query("INSERT INTO spip_documents (titre, id_type, fichier, mode, largeur, hauteur, taille) VALUES ".
+					"('image $largeur x $hauteur', $id_type, '$fichier', 'vignette', '$largeur', '$hauteur', '$taille')");
+				$id_document = spip_insert_id();
+				if ($id_document > 0) {
+					spip_query("INSERT INTO spip_documents_articles (id_document, id_article) VALUES ($id_document, $id_article)");
+					$replace = "REPLACE($replace, '<IMG$num_img|', '<IM_$id_document|')";
+				} else {
+					echo _T('texte_erreur_mise_niveau_base', array('fichier' => $fichier, 'id_article' => $id_article));
+					exit;
+				}
+			}
+			$replace = "REPLACE($replace, '<IM_', '<IMG')";
+			$replace_chapo = ereg_replace('_orig_', 'chapo', $replace);
+			$replace_descriptif = ereg_replace('_orig_', 'descriptif', $replace);
+			$replace_texte = ereg_replace('_orig_', 'texte', $replace);
+			$replace_ps = ereg_replace('_orig_', 'ps', $replace);
+			$query = "UPDATE spip_articles ".
+				"SET chapo=$replace_chapo, descriptif=$replace_descriptif, texte=$replace_texte, ps=$replace_ps ".
+				"WHERE id_article=$id_article";
+			spip_query($query);
+		}
+		spip_query("ALTER TABLE spip_articles DROP images");
+		maj_version (1.408);
+	}
+
+	if ($version_installee < 1.414) {
+		// Forum par defaut "en dur" dans les spip_articles
+		// -> non, prio (priori), pos (posteriori), abo (abonnement)
+		include_ecrire ("inc_meta.php3");
+		$accepter_forum = substr(lire_meta("forums_publics"),0,3) ;
+		$query = "ALTER TABLE spip_articles CHANGE accepter_forum accepter_forum CHAR(3) NOT NULL";
+		$result = spip_query($query);
+		$query = "UPDATE spip_articles SET accepter_forum='$accepter_forum' WHERE accepter_forum != 'non'";
+		$result = spip_query($query);
+		maj_version (1.414);
+	}
+
+	/*
+	if ($version_installee == 1.415) {
+		spip_query("ALTER TABLE spip_documents DROP inclus");
+		maj_version (1.415);
+	}
+	*/
+
+	if ($version_installee < 1.417) {
+		spip_query("ALTER TABLE spip_syndic_articles DROP date_index");
+		maj_version (1.417);
+	}
+
+	if ($version_installee < 1.418) {
+		$query = "SELECT * FROM spip_auteurs WHERE statut = '0minirezo' AND email != '' ORDER BY id_auteur LIMIT 0,1";
+		$result = spip_query($query);
+		if ($webmaster = spip_fetch_object($result)) {
+			include_ecrire("inc_meta.php3");
+			ecrire_meta('email_webmaster', $webmaster->email);
+			ecrire_metas();
+		}
+		maj_version (1.418);
+	}
+
+	if ($version_installee < 1.419) {
+		$query = "ALTER TABLE spip_auteurs ADD alea_actuel TINYTEXT DEFAULT ''";
+		spip_query($query);
+		$query = "ALTER TABLE spip_auteurs ADD alea_futur TINYTEXT DEFAULT ''";
+		spip_query($query);
+		$query = "UPDATE spip_auteurs SET alea_futur = FLOOR(32000*RAND())";
+		spip_query($query);
+		maj_version (1.419);
+	}
+
+	if ($version_installee < 1.420) {
+		$query = "UPDATE spip_auteurs SET alea_actuel='' WHERE statut='nouveau'";
+		spip_query($query);
+		maj_version (1.420);
+	}
+	
+	if ($version_installee < 1.421) {
+		$query = "ALTER TABLE spip_articles ADD auteur_modif bigint(21) DEFAULT '0' NOT NULL";
+		spip_query($query);
+		$query = "ALTER TABLE spip_articles ADD date_modif datetime DEFAULT '0000-00-00 00:00:00' NOT NULL";
+		spip_query($query);
+		maj_version (1.421);
+	}
+
+	if ($version_installee < 1.432) {
+		spip_query("ALTER TABLE spip_articles DROP referers");
+		$query = "ALTER TABLE spip_articles ADD referers INTEGER DEFAULT '0' NOT NULL";
+		spip_query($query);
+		$query = "ALTER TABLE spip_articles ADD popularite INTEGER DEFAULT '0' NOT NULL";
+		spip_query($query);
+		maj_version (1.432);
+	}
+
+	if ($version_installee < 1.436) {
+		$query = "ALTER TABLE spip_documents ADD date datetime DEFAULT '0000-00-00 00:00:00' NOT NULL";
+		spip_query($query);
+		maj_version (1.436);
+	}
+
+	if ($version_installee < 1.437) {
+		spip_query("ALTER TABLE spip_visites ADD maj TIMESTAMP");
+		spip_query("ALTER TABLE spip_visites_referers ADD maj TIMESTAMP");
+		maj_version (1.437);
+	}
+
+	if ($version_installee < 1.438) {
+		spip_query("ALTER TABLE spip_articles ADD INDEX id_secteur (id_secteur)");
+		spip_query("ALTER TABLE spip_articles ADD INDEX statut (statut, date)");
+		maj_version (1.438);
+	}
+
+	if ($version_installee < 1.439) {
+		spip_query("ALTER TABLE spip_syndic ADD INDEX statut (statut, date_syndic)");
+		spip_query("ALTER TABLE spip_syndic_articles ADD INDEX statut (statut)");
+		spip_query("ALTER TABLE spip_syndic_articles CHANGE url url VARCHAR(255) NOT NULL");
+		spip_query("ALTER TABLE spip_syndic_articles ADD INDEX url (url)");
+		maj_version (1.439);
+	}
+
+	if ($version_installee < 1.440) {
+		spip_query("ALTER TABLE spip_visites_temp CHANGE ip ip INTEGER UNSIGNED NOT NULL");
+		maj_version (1.440);
+	}
+
+	if ($version_installee < 1.441) {
+		spip_query("ALTER TABLE spip_visites_temp CHANGE date date DATE NOT NULL");
+		spip_query("ALTER TABLE spip_visites CHANGE date date DATE NOT NULL");
+		spip_query("ALTER TABLE spip_visites_referers CHANGE date date DATE NOT NULL");
+		maj_version (1.441);
+	}
+
+	if ($version_installee < 1.442) {
+		$query = "ALTER TABLE spip_auteurs ADD prefs TINYTEXT NOT NULL";
+		spip_query($query);
+		maj_version (1.442);
+	}
+
+	if ($version_installee < 1.443) {
+		spip_query("ALTER TABLE spip_auteurs CHANGE login login VARCHAR(255) BINARY NOT NULL");
+		spip_query("ALTER TABLE spip_auteurs CHANGE statut statut VARCHAR(255) NOT NULL");
+		spip_query("ALTER TABLE spip_auteurs ADD INDEX login (login)");
+		spip_query("ALTER TABLE spip_auteurs ADD INDEX statut (statut)");
+		maj_version (1.443);
+	}
+
+	if ($version_installee < 1.444) {
+		spip_query("ALTER TABLE spip_syndic ADD moderation VARCHAR(3) NOT NULL");
+		maj_version (1.444);
+	}
+
+	if ($version_installee < 1.457) {
+		spip_query("DROP TABLE spip_visites");
+		spip_query("DROP TABLE spip_visites_temp");
+		spip_query("DROP TABLE spip_visites_referers");
+		creer_base(); // crade, a ameliorer :-((
+		maj_version (1.457);
+	}
+
+	if ($version_installee < 1.458) {
+		spip_query("ALTER TABLE spip_auteurs ADD cookie_oubli TINYTEXT NOT NULL");
+		maj_version (1.458);
+	}
+
+	if ($version_installee < 1.459) {
+		$result = spip_query("SELECT type FROM spip_mots GROUP BY type");
+		while ($row = spip_fetch_array($result)) {
+			$type = addslashes($row['type']);
+			$res = spip_query("SELECT * FROM spip_groupes_mots
+				WHERE titre='$type'");
+			if (spip_num_rows($res) == 0) {
+				spip_query("INSERT IGNORE INTO spip_groupes_mots 
+					(titre, unseul, obligatoire, articles, breves, rubriques, syndic, 0minirezo, 1comite, 6forum)
+					VALUES ('$type', 'non', 'non', 'oui', 'oui', 'non', 'oui', 'oui', 'oui', 'non')");
+				if ($id_groupe = spip_insert_id()) 
+					spip_query("UPDATE spip_mots SET id_groupe = '$id_groupe' WHERE type='$type'");
+			}
+		}
+		spip_query("UPDATE spip_articles SET popularite=0");
+		maj_version (1.459);
+	}
+
+	if ($version_installee < 1.460) {
+		// remettre les mots dans les groupes dupliques par erreur
+		// dans la precedente version du paragraphe de maj 1.459
+		// et supprimer ceux-ci
+		$result = spip_query("SELECT * FROM spip_groupes_mots ORDER BY id_groupe");
+		while ($row = spip_fetch_array($result)) {
+			$titre = addslashes($row['titre']);
+			if (! $vu[$titre] ) {
+				$vu[$titre] = true;
+				$id_groupe = $row['id_groupe'];
+				spip_query ("UPDATE spip_mots SET id_groupe=$id_groupe WHERE type='$titre'");
+				spip_query ("DELETE FROM spip_groupes_mots WHERE titre='$titre' AND id_groupe<>$id_groupe");
+			}
+		}
+		maj_version (1.460);
+	}
+
+	if ($version_installee < 1.462) {
+		spip_query("UPDATE spip_types_documents SET inclus='embed' WHERE inclus!='non' AND extension IN ".
+			"('aiff', 'asf', 'avi', 'mid', 'mov', 'mp3', 'mpg', 'ogg', 'qt', 'ra', 'ram', 'rm', 'swf', 'wav', 'wmv')");
+		maj_version (1.462);
+	}
+
+	if ($version_installee < 1.463) {
+		spip_query("ALTER TABLE spip_articles CHANGE popularite popularite DOUBLE");
+		spip_query("ALTER TABLE spip_visites_temp ADD maj TIMESTAMP");
+		spip_query("ALTER TABLE spip_referers_temp ADD maj TIMESTAMP");
+		maj_version (1.463);
+	}
+
+	// l'upgrade < 1.462 ci-dessus etait fausse, d'ou correctif
+	if (($version_installee < 1.464) AND ($version_installee >= 1.462)) {
+		$res = spip_query("SELECT id_type, extension FROM spip_types_documents WHERE id_type NOT IN (1,2,3)");
+		while ($row = spip_fetch_array($res)) {
+			$extension = $row['extension'];
+			$id_type = $row['id_type'];
+			spip_query("UPDATE spip_documents SET id_type=$id_type
+				WHERE fichier like '%.$extension'");
+		}
+		maj_version (1.464);
+	}
+
+	if ($version_installee < 1.465) {
+		spip_query("ALTER TABLE spip_articles CHANGE popularite popularite DOUBLE NOT NULL");
+		maj_version (1.465);
+	}
+
+	if ($version_installee < 1.466) {
+		spip_query("ALTER TABLE spip_auteurs ADD source VARCHAR(10) DEFAULT 'spip' NOT NULL");
+		maj_version (1.466);
+	}
+
+	if ($version_installee < 1.468) {
+		spip_query("ALTER TABLE spip_auteurs ADD INDEX en_ligne (en_ligne)");
+		spip_query("ALTER TABLE spip_forum ADD INDEX statut (statut, date_heure)");
+		maj_version (1.468);
+	}
+
+	if ($version_installee < 1.470) {
+		if ($version_installee >= 1.467) {	// annule les "listes de diff"
+			spip_query("DROP TABLE spip_listes");
+			spip_query("ALTER TABLE spip_auteurs DROP abonne");
+			spip_query("ALTER TABLE spip_auteurs DROP abonne_pass");
+		}
+		maj_version (1.470);
+	}
+
+	if ($version_installee < 1.471) {
+		if ($version_installee >= 1.470) {	// annule les "maj"
+			spip_query("ALTER TABLE spip_auteurs_articles DROP maj TIMESTAMP");
+			spip_query("ALTER TABLE spip_auteurs_rubriques DROP maj TIMESTAMP");
+			spip_query("ALTER TABLE spip_auteurs_messages DROP maj TIMESTAMP");
+			spip_query("ALTER TABLE spip_documents_articles DROP maj TIMESTAMP");
+			spip_query("ALTER TABLE spip_documents_rubriques DROP maj TIMESTAMP");
+			spip_query("ALTER TABLE spip_documents_breves DROP maj TIMESTAMP");
+			spip_query("ALTER TABLE spip_mots_articles DROP maj TIMESTAMP");
+			spip_query("ALTER TABLE spip_mots_breves DROP maj TIMESTAMP");
+			spip_query("ALTER TABLE spip_mots_rubriques DROP maj TIMESTAMP");
+			spip_query("ALTER TABLE spip_mots_syndic DROP maj TIMESTAMP");
+			spip_query("ALTER TABLE spip_mots_forum DROP maj TIMESTAMP");
+		}
+		maj_version (1.471);
+	}
+
+	if ($version_installee < 1.472) {
+		spip_query("ALTER TABLE spip_referers ADD visites_jour INTEGER UNSIGNED NOT NULL");
+		maj_version (1.472);
+	}
+
+	if ($version_installee < 1.473) {
+		spip_query("UPDATE spip_syndic_articles SET url = REPLACE(url, '&amp;', '&')");
+		spip_query("UPDATE spip_syndic SET url_site = REPLACE(url_site, '&amp;', '&')");
+		maj_version (1.473);
+	}
+
+	if ($version_installee < 1.600) {
+		include_ecrire('inc_index.php3');
+		purger_index();
+		creer_liste_indexation();
+		maj_version (1.600);
+	}
+
+	if ($version_installee < 1.601) {
+		spip_query("ALTER TABLE spip_forum ADD INDEX id_syndic (id_syndic)");
+		maj_version (1.601);
+	}
+
+	if ($version_installee < 1.603) {
+		// supprimer les fichiers deplaces
+		@unlink('inc_meta_cache.php3');
+		@unlink('data/engines-list.ini');
+		maj_version (1.603);
+	}
+
+	if ($version_installee < 1.604) {
+		spip_query("ALTER TABLE spip_auteurs ADD lang VARCHAR(10) DEFAULT '' NOT NULL");
+		$u = spip_query("SELECT * FROM spip_auteurs WHERE prefs LIKE '%spip_lang%'");
+		while ($row = spip_fetch_array($u)) {
+			$prefs = unserialize($row['prefs']);
+			$l = $prefs['spip_lang'];
+			unset ($prefs['spip_lang']);
+			spip_query ("UPDATE spip_auteurs SET lang='".addslashes($l)."',
+				prefs='".addslashes(serialize($prefs))."'
+				WHERE id_auteur=".$row['id_auteur']);
+		}
+		maj_version (1.604, spip_query("SELECT lang FROM spip_auteurs"));
+	}
+
+	if ($version_installee < 1.702) {
+		spip_query("ALTER TABLE spip_articles ADD extra longblob NULL");
+		spip_query("ALTER TABLE spip_auteurs ADD extra longblob NULL");
+		spip_query("ALTER TABLE spip_breves ADD extra longblob NULL");
+		spip_query("ALTER TABLE spip_rubriques ADD extra longblob NULL");
+		spip_query("ALTER TABLE spip_mots ADD extra longblob NULL");
+
+		// recuperer les eventuels 'supplement' installes en 1.701
+		if ($version_installee == 1.701) {
+			spip_query ("UPDATE spip_articles SET extra = supplement");
+			spip_query ("ALTER TABLE spip_articles DROP supplement");
+			spip_query ("UPDATE spip_auteurs SET extra = supplement");
+			spip_query ("ALTER TABLE spip_auteurs DROP supplement");
+			spip_query ("UPDATE spip_breves SET extra = supplement");
+			spip_query ("ALTER TABLE spip_breves DROP supplement");
+			spip_query ("UPDATE spip_rubriques SET extra = supplement");
+			spip_query ("ALTER TABLE spip_rubriques DROP supplement");
+			spip_query ("UPDATE spip_mots SET extra = supplement");
+			spip_query ("ALTER TABLE spip_mots DROP supplement");
+		}
+		maj_version (1.702,
+			spip_query("SELECT extra FROM spip_articles")
+			&& spip_query("SELECT extra FROM spip_auteurs")
+			&& spip_query("SELECT extra FROM spip_breves")
+			&& spip_query("SELECT extra FROM spip_rubriques")
+			&& spip_query("SELECT extra FROM spip_mots")
+			);
+	}
+
+	if ($version_installee < 1.703) {
+		spip_query("ALTER TABLE spip_articles ADD lang VARCHAR(10) DEFAULT '' NOT NULL");
+		spip_query("ALTER TABLE spip_rubriques ADD lang VARCHAR(10) DEFAULT '' NOT NULL");
+		maj_version (1.703);
+	}
+
+	if ($version_installee < 1.704) {
+		spip_query("ALTER TABLE spip_articles ADD INDEX lang (lang)");
+		spip_query("ALTER TABLE spip_auteurs ADD INDEX lang (lang)");
+		spip_query("ALTER TABLE spip_rubriques ADD INDEX lang (lang)");
+		maj_version (1.704);
+	}
+
+	if ($version_installee < 1.705) {
+		spip_query("ALTER TABLE spip_articles ADD langue_choisie VARCHAR(3) DEFAULT 'non'");
+		spip_query("ALTER TABLE spip_rubriques ADD langue_choisie VARCHAR(3) DEFAULT 'non'");
+		maj_version (1.705);
+	}
+
+	if ($version_installee < 1.707) {
+		spip_query("UPDATE spip_articles SET langue_choisie='oui' WHERE MID(lang,1,1) != '.' AND lang != ''");
+		spip_query("UPDATE spip_articles SET lang=MID(lang,2,8) WHERE langue_choisie = 'non'");
+		spip_query("UPDATE spip_rubriques SET langue_choisie='oui' WHERE MID(lang,1,1) != '.' AND lang != ''");
+		spip_query("UPDATE spip_rubriques SET lang=MID(lang,2,8) WHERE langue_choisie = 'non'");
+		maj_version (1.707);
+	}
+
+	if ($version_installee < 1.708) {
+		spip_query("ALTER TABLE spip_breves ADD lang VARCHAR(10) DEFAULT '' NOT NULL");
+		spip_query("ALTER TABLE spip_breves ADD langue_choisie VARCHAR(3) DEFAULT 'non'");
+		maj_version (1.708);
+	}
+
+	if ($version_installee < 1.709) {
+		spip_query("ALTER TABLE spip_articles ADD id_trad bigint(21) DEFAULT '0' NOT NULL");
+		spip_query("ALTER TABLE spip_articles ADD INDEX id_trad (id_trad)");
+		maj_version (1.709);
+	}
+
+	if ($version_installee < 1.717) {
+		spip_query("ALTER TABLE spip_articles ADD INDEX date_modif (date_modif)");
+		maj_version (1.717);
+	}
+
+	if ($version_installee < 1.718) {
+		spip_query("ALTER TABLE spip_referers DROP domaine");
+		spip_query("ALTER TABLE spip_referers_articles DROP domaine");
+		spip_query("ALTER TABLE spip_referers_temp DROP domaine");
+		maj_version (1.718);
+	}
+
+	if ($version_installee < 1.722) {
+		spip_query("ALTER TABLE spip_articles ADD nom_site tinytext NOT NULL");
+		spip_query("ALTER TABLE spip_articles ADD url_site VARCHAR(255) NOT NULL");
+		spip_query("ALTER TABLE spip_articles ADD INDEX url_site (url_site)");
+		if ($version_installee >= 1.720) {
+			spip_query("UPDATE spip_articles SET url_site=url_ref");
+			spip_query("ALTER TABLE spip_articles DROP INDEX url_ref");
+			spip_query("ALTER TABLE spip_articles DROP url_ref");
+		}
+		maj_version (1.722);
+	}
+
+	if ($version_installee < 1.723) {
+		if ($version_installee == 1.722) {
+			spip_query("ALTER TABLE spip_articles MODIFY url_site VARCHAR(255) NOT NULL");
+			spip_query("ALTER TABLE spip_articles DROP INDEX url_site;");
+			spip_query("ALTER TABLE spip_articles ADD INDEX url_site (url_site);");
+		}
+		maj_version (1.723);
+	}
+
+	if ($version_installee < 1.724) {
+		spip_query("ALTER TABLE spip_messages ADD date_fin datetime DEFAULT '0000-00-00 00:00:00' NOT NULL");
+		maj_version (1.724);
+	}
+
+	if ($version_installee < 1.726) {
+		spip_query("ALTER TABLE spip_auteurs ADD low_sec tinytext NOT NULL");
+		maj_version (1.726);
+	}
+
+	if ($version_installee < 1.727) {
+		// occitans : oci_xx -> oc_xx
+		spip_query("UPDATE spip_auteurs SET lang=REPLACE(lang,'oci_', 'oc_') WHERE lang LIKE 'oci_%'");
+		spip_query("UPDATE spip_rubriques SET lang=REPLACE(lang,'oci_', 'oc_') WHERE lang LIKE 'oci_%'");
+		spip_query("UPDATE spip_articles SET lang=REPLACE(lang,'oci_', 'oc_') WHERE lang LIKE 'oci_%'");
+		spip_query("UPDATE spip_breves SET lang=REPLACE(lang,'oci_', 'oc_') WHERE lang LIKE 'oci_%'");
+		maj_version (1.727);
+	}
+
+	// Ici version 1.7 officielle
+
+	if ($version_installee < 1.728) {
+		spip_query("ALTER TABLE spip_articles ADD id_version int unsigned DEFAULT '0' NOT NULL");
+		maj_version (1.728);
+	}
+
+	if ($version_installee < 1.730) {
+		spip_query("ALTER TABLE spip_articles ADD idx ENUM('', '1', 'non', 'oui', 'idx') DEFAULT '' NOT NULL");
+		spip_query("ALTER TABLE spip_articles INDEX idx (idx)");
+		spip_query("ALTER TABLE spip_auteurs ADD idx ENUM('', '1', 'non', 'oui', 'idx') DEFAULT '' NOT NULL");
+		spip_query("ALTER TABLE spip_auteurs INDEX idx (idx)");
+		spip_query("ALTER TABLE spip_breves ADD idx ENUM('', '1', 'non', 'oui', 'idx') DEFAULT '' NOT NULL");
+		spip_query("ALTER TABLE spip_breves INDEX idx (idx)");
+		spip_query("ALTER TABLE spip_mots ADD idx ENUM('', '1', 'non', 'oui', 'idx') DEFAULT '' NOT NULL");
+		spip_query("ALTER TABLE spip_mots INDEX idx (idx)");
+		spip_query("ALTER TABLE spip_rubriques ADD idx ENUM('', '1', 'non', 'oui', 'idx') DEFAULT '' NOT NULL");
+		spip_query("ALTER TABLE spip_rubriques INDEX idx (idx)");
+		spip_query("ALTER TABLE spip_syndic ADD idx ENUM('', '1', 'non', 'oui', 'idx') DEFAULT '' NOT NULL");
+		spip_query("ALTER TABLE spip_syndic INDEX idx (idx)");
+		spip_query("ALTER TABLE spip_forum ADD idx ENUM('', '1', 'non', 'oui', 'idx') DEFAULT '' NOT NULL");
+		spip_query("ALTER TABLE spip_forum ADD INDEX idx (idx)");
+		spip_query("ALTER TABLE spip_signatures ADD idx ENUM('', '1', 'non', 'oui', 'idx') DEFAULT '' NOT NULL");
+		spip_query("ALTER TABLE spip_signatures INDEX idx (idx)");
+		maj_version (1.730);
+	}
+
+	if ($version_installee < 1.731) {	// reindexer les docs allemands et vietnamiens
+		spip_query("UPDATE spip_articles SET idx='1' where lang IN ('de','vi')");
+		spip_query("UPDATE spip_rubriques SET idx='1' where lang IN ('de','vi')");
+		spip_query("UPDATE spip_breves SET idx='1' where lang IN ('de','vi')");
+		spip_query("UPDATE spip_auteurs SET idx='1' where lang IN ('de','vi')");
+		maj_version (1.731);
+	}
+
+	if ($version_installee < 1.732) {	// en correction d'un vieux truc qui avait fait sauter le champ inclus sur les bases version 1.415
+		spip_query ("ALTER TABLE spip_documents ADD inclus  VARCHAR(3) DEFAULT 'non'");
+		maj_version (1.732);
+	}
+
+	return true;
+}
+
+?>
diff --git a/ecrire/inc_serialbase.php3 b/ecrire/inc_serialbase.php3
new file mode 100644
index 0000000000..2896049442
--- /dev/null
+++ b/ecrire/inc_serialbase.php3
@@ -0,0 +1,333 @@
+<?php
+
+// Ce fichier ne sera execute qu'une fois
+if (defined("_ECRIRE_INC_SERIALBASE")) return;
+define("_ECRIRE_INC_SERIALBASE", "1");
+
+define("_SUFFIXE_DES_CACHES", "_caches");
+
+$spip_articles = array(
+		"id_article"	=> "bigint(21) NOT NULL",
+		"surtitre"	=> "text NOT NULL",
+		"titre"	=> "text NOT NULL",
+		"soustitre"	=> "text NOT NULL",
+		"id_rubrique"	=> "bigint(21) DEFAULT '0' NOT NULL",
+		"descriptif"	=> "text NOT NULL",
+		"chapo"	=> "mediumtext NOT NULL",
+		"texte"	=> "longblob NOT NULL",
+		"ps"	=> "mediumtext NOT NULL",
+		"date"	=> "datetime DEFAULT '0000-00-00 00:00:00' NOT NULL",
+		"statut"	=> "varchar(10) DEFAULT '0' NOT NULL",
+		"id_secteur"	=> "bigint(21) DEFAULT '0' NOT NULL",
+		"maj"	=> "TIMESTAMP",
+		"export"	=> "VARCHAR(10) DEFAULT 'oui'",
+		"date_redac"	=> "datetime DEFAULT '0000-00-00 00:00:00' NOT NULL",
+		"visites"	=> "INTEGER DEFAULT '0' NOT NULL",
+		"referers"	=> "INTEGER DEFAULT '0' NOT NULL",
+		"popularite"	=> "DOUBLE DEFAULT '0' NOT NULL",
+		"accepter_forum"	=> "CHAR(3) NOT NULL",
+		"auteur_modif"	=> "bigint(21) DEFAULT '0' NOT NULL",
+		"date_modif"	=> "datetime DEFAULT '0000-00-00 00:00:00' NOT NULL",
+		"lang"		=> "VARCHAR(10) DEFAULT '' NOT NULL",
+		"langue_choisie"	=> "VARCHAR(3) DEFAULT 'non'",
+		"id_trad"	=> "bigint(21) DEFAULT '0' NOT NULL",
+		"extra"		=> "longblob NULL",
+		"idx"		=> "ENUM('', '1', 'non', 'oui', 'idx') DEFAULT '' NOT NULL",
+		"id_version"	=> "int unsigned DEFAULT '0' NOT NULL",
+
+		"nom_site"	=> "tinytext NOT NULL",
+		"url_site"	=> "VARCHAR(255) NOT NULL");
+
+$spip_articles_key = array(
+		"PRIMARY KEY"		=> "id_article",
+		"KEY id_rubrique"	=> "id_rubrique",
+		"KEY id_secteur"	=> "id_secteur",
+		"KEY id_trad"		=> "id_trad",
+		"KEY lang"		=> "lang",
+		"KEY statut"		=> "statut, date",
+		"KEY url_site"		=> "url_site",
+		"KEY date_modif"	=> "date_modif",
+		"KEY idx"		=> "idx");
+
+$spip_auteurs = array(
+		"id_auteur"	=> "bigint(21) NOT NULL",
+		"nom"	=> "text NOT NULL",
+		"bio"	=> "text NOT NULL",
+		"email"	=> "tinytext NOT NULL",
+		"nom_site"	=> "tinytext NOT NULL",
+		"url_site"	=> "text NOT NULL",
+		"login"	=> "VARCHAR(255) BINARY NOT NULL",
+		"pass"	=> "tinytext NOT NULL",
+		"low_sec"	=> "tinytext NOT NULL",
+		"statut"	=> "VARCHAR(255) NOT NULL",
+		"maj"	=> "TIMESTAMP",
+		"pgp"	=> "BLOB NOT NULL",
+		"htpass"	=> "tinyblob NOT NULL",
+		"en_ligne"	=> "datetime DEFAULT '0000-00-00 00:00:00' NOT NULL",
+		"imessage"	=> "VARCHAR(3) NOT NULL",
+		"messagerie"	=> "VARCHAR(3) NOT NULL",
+		"alea_actuel"	=> "tinytext NOT NULL",
+		"alea_futur"	=> "tinytext NOT NULL",
+		"prefs"	=> "tinytext NOT NULL",
+		"cookie_oubli"	=> "tinytext NOT NULL",
+		"source"	=> "VARCHAR(10) DEFAULT 'spip' NOT NULL",
+		"lang"	=> "VARCHAR(10) DEFAULT '' NOT NULL",
+		"idx"		=> "ENUM('', '1', 'non', 'oui', 'idx') DEFAULT '' NOT NULL",
+		"extra"	=> "longblob NULL");
+
+$spip_auteurs_key = array(
+		"PRIMARY KEY"	=> "id_auteur",
+		"KEY login"	=> "login",
+		"KEY statut"	=> "statut",
+		"KEY lang"	=> "lang",
+		"KEY idx"	=> "idx",
+		"KEY en_ligne"	=> "en_ligne");
+
+$spip_breves = array(
+		"id_breve"	=> "bigint(21) NOT NULL",
+		"date_heure"	=> "datetime DEFAULT '0000-00-00 00:00:00' NOT NULL",
+		"titre"	=> "text NOT NULL",
+		"texte"	=> "longblob NOT NULL",
+		"lien_titre"	=> "text NOT NULL",
+		"lien_url"	=> "text NOT NULL",
+		"statut"	=> "varchar(6) NOT NULL",
+		"id_rubrique"	=> "bigint(21) DEFAULT '0' NOT NULL",
+		"lang"	=> "VARCHAR(10) DEFAULT '' NOT NULL",
+		"langue_choisie"	=> "VARCHAR(3) DEFAULT 'non'",
+		"maj"	=> "TIMESTAMP",
+		"idx"		=> "ENUM('', '1', 'non', 'oui', 'idx') DEFAULT '' NOT NULL",
+		"extra"	=> "longblob NULL");
+
+$spip_breves_key = array(
+		"PRIMARY KEY"	=> "id_breve",
+		"KEY idx"	=> "idx",
+		"KEY id_rubrique"	=> "id_rubrique");
+
+$spip_messages = array(
+		"id_message"	=> "bigint(21) NOT NULL",
+		"titre"	=> "text NOT NULL",
+		"texte"	=> "longblob NOT NULL",
+		"type"	=> "varchar(6) NOT NULL",
+		"date_heure"	=> "datetime DEFAULT '0000-00-00 00:00:00' NOT NULL",
+		"date_fin"	=> "datetime DEFAULT '0000-00-00 00:00:00' NOT NULL",
+		"rv"	=> "varchar(3) NOT NULL",
+		"statut"	=> "varchar(6) NOT NULL",
+		"id_auteur"	=> "bigint(21) NOT NULL",
+		"maj"	=> "TIMESTAMP");
+
+$spip_messages_key = array(
+		"PRIMARY KEY"	=> "id_message",
+		"KEY id_auteur"	=> "id_auteur");
+
+$spip_mots = array(
+		"id_mot"	=> "bigint(21) NOT NULL",
+		"type"	=> "VARCHAR(100) NOT NULL",
+		"titre"	=> "text NOT NULL",
+		"descriptif"	=> "text NOT NULL",
+		"texte"	=> "longblob NOT NULL",
+		"id_groupe"	=> "bigint(21) NOT NULL",
+		"extra"	=> "longblob NULL",
+		"idx"		=> "ENUM('', '1', 'non', 'oui', 'idx') DEFAULT '' NOT NULL",
+		"maj"	=> "TIMESTAMP");
+
+$spip_mots_key = array(
+		"PRIMARY KEY"	=> "id_mot",
+		"KEY idx"	=> "idx",
+		"KEY type"	=> "type");
+
+$spip_groupes_mots = array(
+		"id_groupe"	=> "bigint(21) NOT NULL",
+		"titre"	=> "text NOT NULL",
+		"unseul"	=> "varchar(3) NOT NULL",
+		"obligatoire"	=> "varchar(3) NOT NULL",
+		"articles"	=> "varchar(3) NOT NULL",
+		"breves"	=> "varchar(3) NOT NULL",
+		"rubriques"	=> "varchar(3) NOT NULL",
+		"syndic"	=> "varchar(3) NOT NULL",
+		"0minirezo"	=> "varchar(3) NOT NULL",
+		"1comite"	=> "varchar(3) NOT NULL",
+		"6forum"	=> "varchar(3) NOT NULL",
+		"maj"	=> "TIMESTAMP");
+
+$spip_groupes_mots_key = array(
+		"PRIMARY KEY"	=> "id_groupe");
+
+$spip_rubriques = array(
+		"id_rubrique"	=> "bigint(21) NOT NULL",
+		"id_parent"	=> "bigint(21) DEFAULT '0' NOT NULL",
+		"titre"	=> "text NOT NULL",
+		"descriptif"	=> "text NOT NULL",
+		"texte"	=> "longblob NOT NULL",
+		"id_secteur"	=> "bigint(21) DEFAULT '0' NOT NULL",
+		"maj"	=> "TIMESTAMP",
+		"export"	=> "VARCHAR(10) DEFAULT 'oui'",
+		"id_import"	=> "BIGINT DEFAULT '0'",
+		"statut"	=> "VARCHAR(10) NOT NULL",
+		"date"	=> "datetime DEFAULT '0000-00-00 00:00:00' NOT NULL",
+		"lang"	=> "VARCHAR(10) DEFAULT '' NOT NULL",
+		"langue_choisie"	=> "VARCHAR(3) DEFAULT 'non'",
+		"idx"		=> "ENUM('', '1', 'non', 'oui', 'idx') DEFAULT '' NOT NULL",
+		"extra"	=> "longblob NULL");
+
+$spip_rubriques_key = array(
+		"PRIMARY KEY"	=> "id_rubrique",
+		"KEY lang"	=> "lang",
+		"KEY idx"	=> "idx",
+		"KEY id_parent"	=> "id_parent");
+
+$spip_documents = array(
+		"id_document"	=> "bigint(21) NOT NULL",
+		"id_vignette"	=> "bigint(21) DEFAULT '0' NOT NULL",
+		"id_type"	=> "bigint(21) DEFAULT '0' NOT NULL",
+		"titre"	=> "text NOT NULL",
+		"date"	=> "datetime DEFAULT '0000-00-00 00:00:00' NOT NULL",
+		"descriptif"	=> "text NOT NULL",
+		"fichier"	=> "varchar(255) NOT NULL",
+		"taille"	=> "integer NOT NULL",
+		"largeur"	=> "integer NOT NULL",
+		"hauteur"	=> "integer NOT NULL",
+		"mode"	=> "ENUM('vignette', 'document') NOT NULL",
+		"inclus"	=> "VARCHAR(3) DEFAULT 'non'",
+		"maj"	=> "TIMESTAMP");
+
+$spip_documents_key = array(
+		"PRIMARY KEY"	=> "id_document",
+		"KEY id_vignette"	=> "id_vignette",
+		"KEY mode"	=> "mode",
+		"KEY id_type"	=> "id_type");
+
+$spip_types_documents = array(
+		"id_type"	=> "bigint(21) NOT NULL",
+		"titre"	=> "text NOT NULL",
+		"descriptif"	=> "text NOT NULL",
+		"extension"	=> "varchar(10) NOT NULL",
+		"mime_type"	=> "varchar(100) NOT NULL",
+		"inclus"	=> "ENUM('non', 'image', 'embed') NOT NULL DEFAULT 'non'",
+		"upload"	=> "ENUM('oui', 'non') NOT NULL DEFAULT 'oui'",
+		"maj"	=> "TIMESTAMP");
+
+$spip_types_documents_key = array(
+		"PRIMARY KEY"	=> "id_type",
+		"UNIQUE extension"	=> "extension",
+		"KEY inclus"	=> "inclus");
+
+$spip_syndic = array(
+		"id_syndic"	=> "bigint(21) NOT NULL",
+		"id_rubrique"	=> "bigint(21) DEFAULT '0' NOT NULL",
+		"id_secteur"	=> "bigint(21) DEFAULT '0' NOT NULL",
+		"nom_site"	=> "blob NOT NULL",
+		"url_site"	=> "blob NOT NULL",
+		"url_syndic"	=> "blob NOT NULL",
+		"descriptif"	=> "blob NOT NULL",
+		"idx"		=> "ENUM('', '1', 'non', 'oui', 'idx') DEFAULT '' NOT NULL",
+		"maj"	=> "TIMESTAMP",
+		"syndication"	=> "VARCHAR(3) NOT NULL",
+		"statut"	=> "VARCHAR(10) NOT NULL",
+		"date"	=> "datetime DEFAULT '0000-00-00 00:00:00' NOT NULL",
+		"date_syndic"	=> "datetime DEFAULT '0000-00-00 00:00:00' NOT NULL",
+		"date_index"	=> "datetime DEFAULT '0000-00-00 00:00:00' NOT NULL",
+		"moderation"	=> "VARCHAR(3) NOT NULL");
+
+$spip_syndic_key = array(
+		"PRIMARY KEY"	=> "id_syndic",
+		"KEY id_rubrique"	=> "id_rubrique",
+		"KEY id_secteur"	=> "id_secteur",
+		"KEY idx"		=> "idx",
+		"KEY statut"	=> "statut, date_syndic");
+
+$spip_syndic_articles = array(
+		"id_syndic_article"	=> "bigint(21) NOT NULL",
+		"id_syndic"	=> "bigint(21) DEFAULT '0' NOT NULL",
+		"titre"	=> "text NOT NULL",
+		"url"	=> "VARCHAR(255) NOT NULL",
+		"date"	=> "datetime DEFAULT '0000-00-00 00:00:00' NOT NULL",
+		"lesauteurs"	=> "text NOT NULL",
+		"maj"	=> "TIMESTAMP",
+		"statut"	=> "VARCHAR(10) NOT NULL",
+		"descriptif"	=> "blob NOT NULL");
+
+$spip_syndic_articles_key = array(
+		"PRIMARY KEY"	=> "id_syndic_article",
+		"KEY id_syndic"	=> "id_syndic",
+		"KEY statut"	=> "statut",
+		"KEY url"	=> "url");
+
+$spip_forum = array(
+		"id_forum"	=> "bigint(21) NOT NULL",
+		"id_parent"	=> "bigint(21) DEFAULT '0' NOT NULL",
+		"id_rubrique"	=> "bigint(21) DEFAULT '0' NOT NULL",
+		"id_article"	=> "bigint(21) DEFAULT '0' NOT NULL",
+		"id_breve"	=> "bigint(21) DEFAULT '0' NOT NULL",
+		"date_heure"	=> "datetime DEFAULT '0000-00-00 00:00:00' NOT NULL",
+		"titre"	=> "text NOT NULL",
+		"texte"	=> "mediumtext NOT NULL",
+		"auteur"	=> "text NOT NULL",
+		"email_auteur"	=> "text NOT NULL",
+		"nom_site"	=> "text NOT NULL",
+		"url_site"	=> "text NOT NULL",
+		"statut"	=> "varchar(8) NOT NULL",
+		"idx"		=> "ENUM('', '1', 'non', 'oui', 'idx') DEFAULT '' NOT NULL",
+		"ip"	=> "varchar(16)",
+		"maj"	=> "TIMESTAMP",
+		"id_auteur"	=> "BIGINT DEFAULT '0' NOT NULL",
+		"id_message"	=> "bigint(21) DEFAULT '0' NOT NULL",
+		"id_syndic"	=> "bigint(21) DEFAULT '0' NOT NULL");
+
+$spip_forum_key = array(
+		"PRIMARY KEY"	=> "id_forum",
+		"KEY id_parent"	=> "id_parent",
+		"KEY id_rubrique"	=> "id_rubrique",
+		"KEY id_article"	=> "id_article",
+		"KEY id_breve"	=> "id_breve",
+		"KEY id_message"	=> "id_message",
+		"KEY id_syndic"	=> "id_syndic",
+		"KEY idx"	=> "idx",
+		"KEY statut"	=> "statut, date_heure");
+
+$spip_signatures = array(
+		"id_signature"	=> "bigint(21) NOT NULL",
+		"id_article"	=> "bigint(21) DEFAULT '0' NOT NULL",
+		"date_time"	=> "datetime DEFAULT '0000-00-00 00:00:00' NOT NULL",
+		"nom_email"	=> "text NOT NULL",
+		"ad_email"	=> "text NOT NULL",
+		"nom_site"	=> "text NOT NULL",
+		"url_site"	=> "text NOT NULL",
+		"message"	=> "mediumtext NOT NULL",
+		"statut"	=> "varchar(10) NOT NULL",
+		"idx"		=> "ENUM('', '1', 'non', 'oui', 'idx') DEFAULT '' NOT NULL",
+		"maj"	=> "TIMESTAMP");
+
+$spip_signatures_key = array(
+		"PRIMARY KEY"	=> "id_signature",
+		"KEY id_article"	=> "id_article",
+		"KEY idx"		=> "idx",
+		"KEY statut" => "statut");
+
+global $tables_principales;
+
+$tables_principales  = array(
+ 'articles' => array('field' => &$spip_articles, 'key' => &$spip_articles_key),
+ 'auteurs'  => array('field' => &$spip_auteurs, 'key' => &$spip_auteurs_key),
+ 'breves'   => array('field' => &$spip_breves, 'key' => &$spip_breves_key),
+ 'messages' => array('field' => &$spip_messages, 'key' => &$spip_messages_key),
+ 'mots'     => array('field' => &$spip_mots, 'key' => &$spip_mots_key),
+ 'groupes_mots' =>	array('field' => &$spip_groupes_mots,
+				'key' => &$spip_groupes_mots_key),
+ 'rubriques' =>		array('field' => &$spip_rubriques, 
+		      		'key' => &$spip_rubriques_key),
+ 'documents' =>		array('field' => &$spip_documents,
+		      		'key' => &$spip_documents_key),
+ 'types_documents'	=> array('field' => &$spip_types_documents,
+			    	'key' => &$spip_types_documents_key),
+ 'syndic'		=> array('field' => &$spip_syndic,
+		    		 'key' => &$spip_syndic_key),
+ 'syndic_articles'	=> array('field' => &$spip_syndic_articles,
+				 'key' => &$spip_syndic_articles_key),
+ 'forum' 		=> array('field' => &$spip_forum,
+				 'key' => &$spip_forum_key),
+ 'signatures'		=> array('field' => &$spip_signatures,
+				 'key' => &$spip_signatures_key),
+);
+
+
+?>
diff --git a/ecrire/inc_surligne.php3 b/ecrire/inc_surligne.php3
index c2ba2a308f..5a36bb5e14 100644
--- a/ecrire/inc_surligne.php3
+++ b/ecrire/inc_surligne.php3
@@ -6,6 +6,12 @@ if (defined("_ECRIRE_INC_SURLIGNE")) return;
 define("_ECRIRE_INC_SURLIGNE", "1");
 
 
+// Balises qui ne font rien en mode normal
+// mais  vont etre substitue'es en mode recherche
+// voir les champs SURLIGNE dans inc-index-squel
+
+define("MARQUEUR_SURLIGNE", 'span class="spip_surligneconditionnel">');
+define("MARQUEUR_FSURLIGNE", '/' . MARQUEUR_SURLIGNE);
 
 function surligner_sans_accents ($mot) {
 	$accents =
@@ -65,7 +71,7 @@ function surligner_regexp_accents ($mot) {
 	return $mot;
 }
 
-// utilise avec ob_start() et ob_get_contents() pour
+
 // mettre en rouge les mots passes dans $var_recherche
 function surligner_mots($page, $mots) {
 	global $nombre_surligne;
@@ -82,84 +88,53 @@ function surligner_mots($page, $mots) {
 		}
 	}
 
-	if (is_array($mots_surligne))
-		$mots_surligne = join('|', $mots_surligne);
-
-	// ne pas traiter tout ce qui est avant </head> ou <body>
-	$regexp = '/<\/head>|<body[^>]*>/i';
-	if (preg_match($regexp, $page, $exp)) {
-		$debut = substr($page, 0, strpos($page, $exp[0])+strlen($exp[0]));
-		$page = substr($page, strlen($debut));
+	if (!$mots_surligne) return $page;
+
+	$regexp = '/((^|>)([^<]*[^[:alnum:]_<])?)((' .
+	  join('|', $mots_surligne).
+	  ')[[:alnum:]_]*?)/Uis';
+
+	// en cas de surlignement limite' (champs #SURLIGNE), 
+	// le compilateur a inse're' les balises de surlignement
+	// sur toute la zone; reste a` raffiner.
+	// On boucle pour le cas ou` il y a plusieurs zones
+
+	$p = strpos($page, MARQUEUR_SURLIGNE);
+	if ($p) 
+	  {
+	    $debut = '';
+	    while ($p) {
+	      $debut .= substr($page, 0, $p-1);
+	      $page = substr($page, $p+strlen(MARQUEUR_SURLIGNE));
+	      $q = strpos($page,MARQUEUR_FSURLIGNE);
+	      $debut .= trouve_surligne(substr($page, 0, $q-1), $regexp);
+	      $page = substr($page, $q+strlen(MARQUEUR_SURLIGNE)+1);
+	      $p = strpos($page,MARQUEUR_SURLIGNE);
+	    }
+	    return $debut . $page;
+	  } else {
+
+	// pour toute la page: ignorer ce qui est avant </head> ou <body>
+	$re = '/<\/head>|<body[^>]*>/i';
+	if (preg_match($re, $page, $exp)) {
+	  $debut = substr($page, 0, strpos($page, $exp[0])+strlen($exp[0]));
+	  $page = substr($page, strlen($debut));
 	} else
-		$debut = '';
-
-	// Remplacer une occurence de mot maxi par espace inter-tag (max 1 par paragraphe, sauf italiques etc.)
-	// se limiter a 4 remplacements pour ne pas bouffer le CPU ;
-	// traiter <textarea...>....</textarea> comme un tag.
-	if ($mots_surligne) {
-		$page = preg_replace('/(<textarea[^>]*>)([^<>]*)(<\/textarea>)/Uis', '\1<<SPIP\2>>\3', $page);
-		$regexp = '/((^|>)([^<]*[^[:alnum:]_<])?)(('.$mots_surligne.')[[:alnum:]_]*?)/Uis';
-		$page = preg_replace($regexp, '\1<span class="spip_surligne">\4</span>', $page, $nombre_surligne);
-		$page = preg_replace('/(<textarea[^>]*>)<<SPIP([^<>]*)>>(<\/textarea>)/Uis', '\1\2\3', $page);
-	}
-	return $debut.$page;
+	  $debut = '';
+	return $debut . trouve_surligne($page, $regexp);
+	  }
 }
 
-
-// debut et fin, appeles depuis les squelettes
-function debut_surligne($mots, $mode_surligne) {
-	switch ($mode_surligne) {
-		case 'auto' :	// on arrive du debut de la page, on ne touche pas au buffer
-			ob_end_flush();
-			ob_start();
-			$mode_surligne = 'actif';
-			break;
-
-		case 'actif' :	// il y a un buffer a traiter
-			$la_page = surligner_mots(ob_get_contents(), $mots);
-			ob_end_clean();
-			echo $la_page;
-			ob_start();
-			$mode_surligne = 'actif';
-			break;
-
-		case 'inactif' :	// il n'y a pas de buffer
-			ob_start();
-			$mode_surligne = 'actif';
-			break;
-
-		case false :	// conditions pas reunies (flag_preserver, etc.)
-			break;
-	}
-
-	return $mode_surligne;
-}
-
-function fin_surligne($mots, $mode_surligne) {
-	switch ($mode_surligne) {
-		case 'auto' :	// on arrive du debut de la page, on s'occupe du buffer
-			$la_page = surligner_mots(ob_get_contents(), $mots);
-			ob_end_clean();
-			echo $la_page;
-			ob_start();
-			$mode_surligne = 'inactif';
-			break;
-
-		case 'actif' :	// il y a un buffer a traiter
-			$la_page = surligner_mots(ob_get_contents(), $mots);
-			ob_end_clean();
-			echo $la_page;
-			$mode_surligne = 'inactif';
-			break;
-
-		case 'inactif' :	// il n'y a pas de buffer
-			break;
-
-		case false :	// conditions pas reunies (flag_preserver, etc.)
-			break;
-	}
-
-	return $mode_surligne;
+function trouve_surligne($page, $regexp) {
+  // Remplacer une occurrence de mot maxi par espace inter-tag
+  // (max 1 par paragraphe, sauf italiques etc.)
+  // se limiter a 4 remplacements pour ne pas bouffer le CPU ;
+  // traiter <textarea...>....</textarea> comme un tag.
+  global $nombre_surligne;
+  $page = preg_replace('/(<textarea[^>]*>)([^<>]*)(<\/textarea>)/Uis', '\1<<SPIP\2>>\3', $page);
+  $page = preg_replace($regexp, '\1<span class="spip_surligne">\4</span>', $page, $nombre_surligne);
+  $page = preg_replace('/(<textarea[^>]*>)<<SPIP([^<>]*)>>(<\/textarea>)/Uis', '\1\2\3', $page);
+  return $page ;
 }
 
 ?>
diff --git a/inc-admin.php3 b/inc-admin.php3
index 34865e0431..a10a386f7a 100644
--- a/inc-admin.php3
+++ b/inc-admin.php3
@@ -5,67 +5,84 @@
 if (defined("_INC_ADMIN")) return;
 define("_INC_ADMIN", "1");
 
-
-//
 // Afficher un bouton admin
-//
 
-function bouton_admin($titre, $lien) {
-	$link = new Link($lien);
-	$link->delVar('submit');
-	echo $link->getForm('GET');
-	echo "<input type='submit' name='submit' value=\"".attribut_html($titre)."\" class='spip_bouton' />\n";
-	echo "</form>";
+function bouton_admin($titre, $script, $args) {
+  $r = '';
+  if ($args)
+    foreach ($args as $n => $v)
+      $r .= "<input type='hidden' name='$n' value='$v'/>";
+  return "<form action='$script'>$r<input type='submit' value='" .
+    attribut_html($titre) .
+    "' class='spip_bouton' /></form>";
 }
 
-function afficher_boutons_admin() {
-	global $id_article, $id_breve, $id_rubrique, $id_mot, $id_auteur;
+function split_query_string($query_string)
+{
+  $res = array();
+  if ($query_string)
+    foreach(split('&',$query_string) as $v)
+      {
+	ereg("^(.*)=(.*)$", $v, $m);
+	if ($m[1] != 'recalcul')
+	  $res[$m[1]] = $m[2];
+      }
+  return $res;
+}
+
+function afficher_boutons_admin($pop)  {
+ global $id_article, $id_breve, $id_rubrique, $id_mot, $id_auteur;
 	include_ecrire("inc_filtres.php3");
 	include_ecrire("inc_lang.php3");
 
 	// regler les boutons dans la langue de l'admin (sinon tant pis)
 	if ($login = addslashes(ereg_replace('^@','',$GLOBALS['spip_admin']))) {
-		$q = spip_query("SELECT lang FROM spip_auteurs WHERE login='$login'");
-		$row = spip_fetch_array($q);
-		$lang = $row['lang'];
+	  $row = spip_fetch_array(spip_query("SELECT lang FROM spip_auteurs WHERE login='$login'"));
+	  
+	  $lang = $row['lang'];
 	}
 	lang_select($lang);
 
-	echo '<div class="spip-admin" dir="'.lang_dir($lang,'ltr','rtl').'">';
-	if ($id_article) {
-		bouton_admin(_T('admin_modifier_article')." ($id_article)", "./ecrire/articles.php3?id_article=$id_article");
-	}
-	else if ($id_breve) {
-		bouton_admin(_T('admin_modifier_breve')." ($id_breve)", "./ecrire/breves_voir.php3?id_breve=$id_breve");
-	}
-	else if ($id_rubrique) {
-		bouton_admin(_T('admin_modifier_rubrique')." ($id_rubrique)", "./ecrire/naviguer.php3?coll=$id_rubrique");
-	}
-	else if ($id_mot) {
-		bouton_admin(_T('admin_modifier_mot')." ($id_mot)", "./ecrire/mots_edit.php3?id_mot=$id_mot");
-	}
-	else if ($id_auteur) {
-		bouton_admin(_T('admin_modifier_auteur')." ($id_auteur)", "./ecrire/auteurs_edit.php3?id_auteur=$id_auteur");
-	}
-	$link = $GLOBALS['clean_link'];
-	$link->addVar('recalcul', 'oui');
-	$link->delVar('submit');
-	echo $link->getForm('GET');
-	if ($GLOBALS['use_cache']) $pop = " *";
-	else $pop = "";
-	echo "<input type='submit' class='spip_bouton' name='submit' value=\"".attribut_html(_T('admin_recalculer')).$pop."\"></input>";
-	echo "</form>\n";
+	$ret =
+	  (($id_article) ?
+	   (bouton_admin(_T('admin_modifier_article') . " ($id_article)", 
+			 './ecrire/articles.php3',
+			 array('id_article' => $id_article))):
+	   (($id_breve) ?
+	    (bouton_admin(_T('admin_modifier_breve') . " ($id_breve)",
+			  "./ecrire/breves_voir.php3",
+			  array('id_breve' => $id_breve))) :
+	    (($id_rubrique) ?
+	     (bouton_admin(_T('admin_modifier_rubrique') . " ($id_rubrique)",
+			   "./ecrire/naviguer.php3",
+			   array( 'coll' => $id_rubrique))) :
+	     (($id_mot) ?
+	      (bouton_admin(_T('admin_modifier_mot') . " ($id_mot)", 
+			    "./ecrire/mots_edit.php3",
+			    array(  'id_mot' => $id_mot))) :
+	      (($id_auteur) ?
+	       (bouton_admin(_T('admin_modifier_auteur') . " ($id_auteur)",
+			     "./ecrire/auteurs_edit.php3",
+			     array(   'id_auteur' => $id_auteur))) :
+	       '')))));
 
+	$args = split_query_string($GLOBALS['QUERY_STRING']);
+	$args['recalcul'] = 'oui';
+	$ret .= bouton_admin(attribut_html(_T('admin_recalculer') . $pop),
+			     $GLOBALS[PHP_SELF],
+			     $args);
 	if (lire_meta("activer_statistiques") != "non" AND $id_article AND ($GLOBALS['auteur_session']['statut'] == '0minirezo')) {
-		include_local ("inc-stats.php3");
-		afficher_raccourci_stats($id_article);
+	  include_local ("inc-stats.php3");
+	  $ret .= bouton_admin(_T('stats_visites_et_popularite',
+				  afficher_raccourci_stats($id_article)),
+			       "./ecrire/statistiques_visites.php3",
+			       array('id_article' => $id_article));
 	}
 
-	echo "</div>";
-
 	lang_dselect();
 	
+	return "<div class='spip-admin' dir='" .
+	  lang_dir($lang,'ltr','rtl') .
+	  "'>$ret</div>";
 }
-
-
 ?>
diff --git a/inc-arg-squel.php3 b/inc-arg-squel.php3
new file mode 100644
index 0000000000..0d9619741c
--- /dev/null
+++ b/inc-arg-squel.php3
@@ -0,0 +1,310 @@
+<?php
+
+// traduction des arguments d'une boucle par affectation du tableau $boucles
+
+function calculer_params($type, $params, $idb, $boucles)
+{
+ global $tables_relations, $table_primary, $table_des_tables, $table_date;
+ $boucle = &$boucles[$idb];
+ $id_table = $table_des_tables[$type];
+ $id_field = $id_table . "." . $table_primary[$type];
+
+  if (is_array($params)) {
+    reset($params);
+    while (list(, $param) = each($params)) {
+      if ($param == 'exclus') {
+	$boucle->where[] = "$id_field!='\"." .
+	  index_pile($boucles[$idb]->id_parent, $table_primary[$type], &$boucles) .
+	  ".\"'";  }
+      else if ($param == 'unique' OR $param == 'doublons') {
+	$boucle->doublons = true;
+	$boucle->where[] = "$id_field NOT IN (\$doublons)";
+
+      }
+      else if (ereg('^(!)? *lang_select(=(oui|non))?$', $param, $match)) {
+	if (!$lang_select = $match[3]) $lang_select = 'oui';
+	if ($match[1]) $lang_select = ($lang_select=='oui')?'non':'oui';
+	$boucles[$idb]->lang_select = $lang_select;
+      }
+      else if (ereg('^([0-9]+)/([0-9]+)$', $param, $match)) {
+	$boucle->partie = $match[1];
+	$boucle->total_parties = $match[2];
+	$boucle->mode_partie = '/';
+      }
+      else if (ereg('^(([0-9]+)|n)(-([0-9]+))?,(([0-9]+)|n)(-([0-9]+))?$', 
+		    $param, $match)) {
+	if (($match[2]!='') && ($match[6]!=''))
+	  $boucle->limit = $match[2].','.$match[6];
+	else
+	  {
+	    $boucle->partie = 
+	      ($match[1] != 'n') ? $match[1] : ($match[4] ? $match[4] : 0);
+	    $boucle->total_parties = 
+	      ($match[5] != 'n') ? $match[5] : ($match[8] ? $match[8] : 0);
+	    $boucle->mode_partie = ($match[1] == 'n') ? '-' : '+';
+	  }
+      }
+      else if (ereg('^debut([-_a-zA-Z0-9]+),([0-9]*)$', $param, $match)) {
+	$debut_lim = "debut".$match[1];
+	$boucle->limit = '".intval($GLOBALS[\'HTTP_GET_VARS\'][\''.$debut_lim.'\']).",'.$match[2];
+      }
+      else if ($param == 'recherche') {
+	$boucle->from[] = "index_$id_table AS rec";
+	$boucle->select[] = "SUM(rec.points + 100*(rec.hash IN (\$hash_recherche_strict))) AS points";
+	$boucle->where[] = "rec.". $table_primary[$type] . "=$id_field";
+	$boucle->group = "'$id_field'";
+	$boucle->where[] = "rec.hash IN (\$hash_recherche)";
+	$boucles[$idb]->hash = true;
+     }
+
+      // Classement par ordre inverse
+      else if ($param == 'inverse') {
+	if ($boucle->order) 
+	  { $boucle->order = substr($boucle->order,0,strlen($boucle->order)-1).
+	      " DESC'";
+	  }
+      }
+
+      // Gerer les traductions
+      else if ($param == 'traduction') {
+	$req_where[] = "$id_table.id_trad > 0 AND  $id_table.id_trad ='\"." .
+	  index_pile($boucles[$idb]->id_parent, 'id_trad', &$boucles) . ".\"'";
+      }
+      else if ($param == 'origine_traduction') {
+	$req_where[] = "$id_table.id_trad = $id_table.id_article";
+      }
+      
+      // Special rubriques
+      else if ($param == 'meme_parent') {
+	$boucle->where[] = "$id_table.id_parent='\"." .
+	  index_pile($boucles[$idb]->id_parent, 'id_parent', &$boucles) . ".\"'";
+	if ($type == 'forums') {
+	  $boucle->where[] = "$id_table.id_parent > 0";
+	  $boucle->plat = true;
+	}
+      }
+      else if ($param == 'racine') {
+	$boucle->where[] = "$id_table.id_parent='0'";
+      }
+      else if (ereg("^branche *(\??)", $param, $regs)) {
+	$c = "$id_table.id_rubrique IN (\".calcul_branche(" .
+	  index_pile($boucles[$idb]->id_parent, 'id_rubrique', &$boucles) .
+	  ").\")";
+	if (!$regs[1])
+	  $boucle->where[] = $c ;
+	else
+	  $boucle->where[] = "('\$id_rubrique'='' OR $c)";
+      }
+      else if ($type == 'hierarchie')
+	{
+	  // Hack spe'cifique; cf comple'ment dans calculer_boucle
+	  $boucle->tout = index_pile($boucles[$idb]->id_parent,
+				     'id_rubrique',
+				     &$boucles);
+	}
+      // Restriction de valeurs (implicite ou explicite)
+      else if (ereg('^([a-zA-Z_]+) *(\??)((!?)(<=?|>=?|==?) *"?([^<>=!"]*))?"?$', $param, $match)) {
+	// Variable comparee
+	$col = $match[1];
+	$col_table = $id_table;
+	// Valeur de comparaison
+	if ($match[3])
+	  {
+	    $val = calculer_param_dynamique($match[6], &$boucles, $idb);
+	  }
+	else {
+	  $val = $match[1];
+	  // Si id_parent, comparer l'id_parent avec l'id_objet de la boucle superieure
+	  if ($val == 'id_parent')
+	    $val = $table_primary[$type];
+	  // Si id_enfant, comparer l'id_objet avec l'id_parent de la boucle superieure
+	  else if ($val == 'id_enfant')
+	    $val = 'id_parent';
+	  $val = index_pile($boucles[$idb]->id_parent, $val, &$boucles) ;
+	}
+	if (ereg('^\$',$val))
+	  $val = '" . addslashes(' . $val . ') . "';
+	else 
+	  $val = addslashes($val);
+
+	// operateur optionnel {lang?}
+	$ou_rien = ($match[2]) ? "'$val'='' OR " : '';
+
+	// Traitement general des relations externes
+	if ($s = $tables_relations[$type][$col]) {
+	  $col_table = $s;
+	  $boucle->from[] = "$col_table AS $col_table";
+	  $boucle->where[] = "$id_field=$col_table." . $table_primary[$type];
+	  $boucle->group = "'$id_field'";
+	  $boucle->lien = true;
+	}
+	// Cas particulier pour les raccourcis 'type_mot' et 'titre_mot'
+	else if ($type != 'mots' AND ($col == 'type_mot' OR $col == 'titre_mot' OR $col == 'id_groupe')) {
+	  if ($type == 'forums')
+	    $col_lien = "forum";
+	  else if ($type == 'syndication')
+	    $col_lien = "syndic";
+	  else
+	    $col_lien = $type;
+	  $boucle->from[] = "mots_$col_lien AS lien_mot";
+	  $boucle->from[] = 'mots AS mots';
+	  $boucle->where[] = "$id_field=lien_mot." . $table_primary[$type];
+	  $boucle->where[] = 'lien_mot.id_mot=mots.id_mot';
+	  $boucle->group = "'$id_field'";
+	  $col_table = 'mots';
+
+	  $boucle->lien = true;
+	  if ($col == 'type_mot')
+	    $col = 'type';
+	  else if ($col == 'titre_mot')
+	    $col = 'titre';
+	  else if ($col == 'id_groupe')
+	    $col = 'id_groupe';
+	}
+	
+	// Cas particulier : selection des documents selon l'extension
+	if ($type == 'documents' AND $col == 'extension') {
+	  $col_table = 'types_documents';
+	}
+	// HACK : selection des documents selon mode 'image' (a creer en dur dans la base)
+	else if ($type == 'documents' AND $col == 'mode' AND $val == 'image') {
+	  $val = 'vignette';
+	}
+	// Cas particulier : lier les articles syndiques au site correspondant
+	else if ($type == 'syndic_articles' AND !ereg("^(id_syndic_article|titre|url|date|descriptif|lesauteurs)$",$col))
+	  $col_table = 'syndic';
+	
+	// Cas particulier : id_enfant => utiliser la colonne id_objet
+	if ($col == 'id_enfant')
+	  $col = $table_primary[$type];
+	// Cas particulier : id_secteur = id_rubrique pour certaines tables
+	else if (($type == 'breves' OR $type == 'forums') AND $col == 'id_secteur')
+	  $col = 'id_rubrique';
+	
+	// Cas particulier : expressions de date
+	if (ereg("^(date|mois|annee|age|age_relatif|jour_relatif|mois_relatif|annee_relatif)(_redac)?$", $col, $regs)) {
+	  $col = $regs[1];
+	  if ($regs[2]) {
+	    $date_orig = "date_redac";
+	    $date_compare = 'date_redac';
+	  }
+	  else {
+	    $date_orig = $table_date[$type];
+	    $date_compare = 'date';
+	  }
+	  $date_orig = "$id_table.$date_orig"; 
+
+	  if ($col == 'date')
+	    $col = $date_orig;
+	  else if ($col == 'mois') {
+	    $col = "MONTH($date_orig)";
+	    $col_table = '';
+	  }
+	  else if ($col == 'annee') {
+	    $col = "YEAR($date_orig)";
+	    $col_table = '';
+	  }
+	  else if ($col == 'age') {
+	    $col = "(LEAST((UNIX_TIMESTAMP(now())-UNIX_TIMESTAMP($date_orig))/86400, TO_DAYS(now())-TO_DAYS($date_orig), DAYOFMONTH(now())-DAYOFMONTH($date_ orig)+30.4368*(MONTH(now())-MONTH($date_orig))+365.2422*(YEAR(now())-YEAR($date_orig))))";
+	    $col_table = '';
+	  }
+	  else if ($col == 'age_relatif') {
+	    $col = "LEAST((UNIX_TIMESTAMP('\$$date_compare')-UNIX_TIMESTAMP($date_orig))/86400, TO_DAYS('\$$date_compare')-TO_DAYS($date_orig), DAYOFMONTH('\$$date_compare')-DAYOFMONTH($date_orig)+30.4368*(MONTH('\$$date_compare')-MONTH($date_orig))+365.2422*(YEAR('\$$date_compare')-YEAR($date_orig)))";
+	    $col_table = '';
+	  }
+	  else if ($col == 'jour_relatif') {
+	    $col = "LEAST(TO_DAYS('\$$date_compare')-TO_DAYS($date_orig), DAYOFMONTH('\$$date_compare')-DAYOFMONTH($date_orig)+30.4368*(MONTH('\$$date_compare')-MONTH($date_orig))+365.2422*(YEAR('\$$date_compare')-YEAR($date_orig)))";
+	    $col_table = '';
+	  }
+	  else if ($col == 'mois_relatif') {
+	    $col = "(MONTH('\$$date_compare')-MONTH($date_orig)+12*(YEAR('\$$date_compare')-YEAR($date_orig)))";
+	    $col_table = '';
+	  }
+	  else if ($col == 'annee_relatif') {
+	    $col = "YEAR('\$$date_compare')-YEAR($date_orig)";
+	    $col_table = '';
+	  }
+	}
+	
+	if ($type == 'forums' AND ($col == 'id_parent' OR $col == 'id_forum'))
+	  $boucle->plat = true;
+	
+	// Operateur de comparaison
+	$op = $match[5];
+	if (!$op) {
+	  $op = '=';
+	} else {if ($op == '==') $op = 'REGEXP'; }
+	
+	if ($col_table) $col = "$col_table.$col";
+
+	$vu = 0;
+	if (($op == '=') && ($boucle->where))
+	  {
+	    // repe'rer un parame`tre re'pe'te' comme {id_mot=1}{id_mot=2}
+	    //  pour cre'er une sous-requete
+	      foreach ($boucle->where as $k => $v)
+	      {
+		if (ereg(" *$col *(=|IN) *['\(](.*)['\)]",$v, $m)) {
+		  $boucle->where[$k] = "$col IN ($m[2],$val)";
+		  // espe'rons que c'est le meme !
+		  $boucle->sous_requete = $col;
+		  $boucle->compte_requete++;
+		  $vu=1;
+		  break;}
+	      }
+	  }
+	if (!$vu)
+	  {
+	    if ($match[4] == '!')
+	      $boucle->where[] = "NOT ($ou_rien$col $op'$val')";
+	    else
+	      $boucle->where[] = "$ou_rien$col $op'$val'";
+	  }
+      } // fin du if sur les restrictions de valeurs
+      
+      // Selection du classement
+      else if (ereg('^par[[:space:]]+([^}]*)$', $param, $match)) {
+	$tri = trim($match[1]);
+	if ($tri == 'hasard') { // par hasard
+	  $boucle->select[] = "MOD($id_field * UNIX_TIMESTAMP(), 32767) & UNIX_TIMESTAMP() AS alea";
+	  $boucle->order = "'alea'";
+	}
+	else if ($tri == 'titre_mot'){ // par titre_mot
+	  $boucle->order= "'mots.titre'";
+	}
+	else if ($tri == 'type_mot'){ // par type_mot
+	  $boucle->order= "'mots.type'";
+	}
+	else if ($tri == 'points'){ // par points
+	  $boucle->order= "'points'";
+	}
+	else if (ereg("^num[[:space:]]+([^,]*)(,.*)?",$tri, $match2)) { // par num champ
+	  $boucle->select[] = "0+$id_table.".$match2[1]." AS num";
+	  $boucle->order = "'num".$match2[2]."'";
+	}
+	else if (ereg("^[a-z0-9]+$", $tri)) { // par champ
+	  if ($tri == 'date') $tri = $table_date[$type];
+	  $boucle->order = "'$id_table.$tri'";
+	}
+	else { 
+# tris par crite`re dynamique ou bizarres (formule composee, virgules, etc).
+	  $boucle->order = calculer_param_dynamique($tri, &$boucles, $idb);
+	}
+      }
+# pas de else, c~a a du etre e'vacue' lors du phrase'
+
+    }
+  }
+}
+
+function calculer_param_dynamique($val, &$boucles, $idb)
+{
+  if (ereg("^#(.*)$",$val,$m))
+    return index_pile($boucles[$idb]->id_parent, $m[1], &$boucles) ;
+  else
+    {if (ereg('^\$(.*)$',$val,$m))
+	return '$PileRow[0][\''. $m[1] ."']";
+      else return $val;
+    }
+}
+?>
diff --git a/inc-bcl-squel.php3 b/inc-bcl-squel.php3
new file mode 100644
index 0000000000..2b2006b78e
--- /dev/null
+++ b/inc-bcl-squel.php3
@@ -0,0 +1,52 @@
+<?php
+
+// encodage d'une boucle SPIP en un objet PHP
+
+class Boucle {
+	var $type = 'boucle';
+	var $id_boucle, $id_parent;
+	var $avant, $cond_avant, $milieu, $cond_apres, $cond_altern, $apres;
+	var $commande;
+	var $lang_select;
+	var $type_requete;
+	var $param;
+	var $separateur;
+	var $doublons;
+	var $partie, $total_parties,$mode_partie;
+	// champs pour la construction de la requete SQL
+	var $tout = false;
+	var $plat = false;
+	var $select;
+	var $from;
+	var $where;
+	var $limit;
+	var $group = "''";
+	var $order = "''";
+	var $date = "date" ;
+	var $hash = false ;
+	var $lien = false;
+	var $sous_requete = false;
+	var $compte_requete = 1;
+	// champs pour la construction du corps PHP
+	var $return;
+	var $numrows = false; 
+}
+
+class Texte {
+	var $type = 'texte';
+	var $texte;
+}
+
+class Inclure {
+	var $type = 'include';
+	var $fichier;
+	var $params;
+}
+
+class Champ {
+	var $type = 'champ';
+	var $nom_champ;
+	var $cond_avant, $cond_apres; // tableaux d'objets
+	var $fonctions;
+}
+?>
diff --git a/inc-cache.php3 b/inc-cache.php3
index 658ef83bd8..947fca025d 100644
--- a/inc-cache.php3
+++ b/inc-cache.php3
@@ -1,181 +1,400 @@
 <?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");
 
-
-//
-// Calcul du nom du fichier cache
-//
-
-function generer_nom_fichier_cache($fichier_requete) {
-	global $HTTP_POST_VARS;
-
-	$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), -24);
-
-	if (!$fichier_cache)
-		$fichier_cache = 'INDEX-';
-	if (!empty($HTTP_POST_VARS)) $fichier_cache .= '.'.@getmypid();
-	$fichier_cache .= '.'.substr($md_cache, 1, 6);
-
-	$subdir_cache = substr($md_cache, 0, 1);
-
-	if (creer_repertoire('CACHE', $subdir_cache))
-		$fichier_cache = "$subdir_cache/$fichier_cache";
-
-	return $fichier_cache;
+include('inc-dir.php3');
+
+# Ve'rif de pe'remption d'une compil de squelette par rapport a` son source
+# et les fonctions utilisateurs agissant sur le compilateur.
+# Ses fonctions internes sont suppose'es ne changer qu'a` l'installation; 
+# sinon vider explicitement par l'interface prive'e.
+
+function squelette_obsolete($naissance, $source)
+{
+  $e = $GLOBALS['extension_squelette'];
+  $x = (($GLOBALS['recalcul_squelettes'] == '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;
 }
 
-
-//
-// Doit-on recalculer le cache ?
-//
-
-function utiliser_cache($chemin_cache, $delais) {
-	global $HTTP_SERVER_VARS, $HTTP_POST_VARS;
-	global $lastmodified;
-
-	// A priori cache
-	$use_cache = true;
-
-	// Existence du fichier
-	if (!@file_exists($chemin_cache)) {
-		if (@file_exists($chemin_cache.'.NEW')) {
-			// Deuxieme acces : le fichier est marque comme utilise
-			@rename($chemin_cache.'.NEW', $chemin_cache);
+# Retourne la fonction principale d'un squelette compile'.
+# En lance la compilation s'il ne l'e'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) de'ja` en me'moire (INCLURE re'pe'te')");
+      return $nom;
+    }
+# spip_log("demande verrou $squelette"); 
+  if (!$lock = fopen($sourcefile, 'rb'))
+      $r = '';
+  else
+    {
+#      spip_log("obtient verrou $squelette"); 
+# empecher un meme calcul par 2 processus diffe'rents en se re'servant le source
+      while (!flock($lock, LOCK_EX));
+# remplacer la ligne ci-dessus par les 3 suivantes pour de'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) charge'");
+		  flock($lock, LOCK_UN);
+		  return $nom;
 		}
-		// Double verification (cas renommage/suppression entre les deux @file_exists)
-		clearstatcache();
-		$use_cache = @file_exists($chemin_cache);
+	    }
+	  # Cache obsolete ou errone'.
+	  @unlink($phpfile);
 	}
+      include_local("inc-calcul-squel.php3");
+      $timer_a = explode(" ", microtime());
+# si vous n'etes pas sous Windows, vous ame'liorerez les perfs en 
+# de'commentant les 2 lignes suivantes (quant a` 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);
+      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]));
+  $f=fopen($phpfile, "wb"); 
+  fwrite($f,"<?php # $squelette pid: " .  getmypid() ."\n");
+  fwrite($f,$r);
+  fwrite($f,'?>');
+  fclose($f);
+  flock($lock, LOCK_UN);
+  spip_log("Squelette $squelette: ($nom)"  . strlen($r) . " octets, $timer ms");
+  eval($r); # + rapide qu'un include puisqu'on l'a
+  return $nom;
+}
 
-	// Date de creation du fichier
-	if ($use_cache) {
-		$t = filemtime($chemin_cache);
-		$age = time() - $t;
-		$age_ok = (($age < $delais) AND ($age >= 0));
-		if (!$age_ok) {		// fichier cache trop vieux
-			if (timeout(false, false))	// sauf lock hebergeur ou probleme base
-				$use_cache = false;
-		}
-		// Inclusions multiples : derniere modification
-		if ($lastmodified < $t) $lastmodified = $t;
+# 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]));
 	}
-
-	// recalcul obligatoire
-	$use_cache &= ($GLOBALS['recalcul'] != 'oui');
-	$use_cache &= empty($HTTP_POST_VARS);
-
-	// ne jamais recalculer pour les moteurs de recherche, proxies...
-	if ($HTTP_SERVER_VARS['REQUEST_METHOD'] == 'HEAD')
-		$use_cache = true;
-
-	spip_debug (($use_cache ? "cache":"calcul")." ($chemin_cache)". ($age ? " age: $age s (reste ".($delais-$age)." s)":''));
-	return $use_cache;
+    }
+  return true;
 }
 
+# Controle la validite' d'un cache .
+# retourne False ou un tableau de 3 e'le'ments:
+# - texte
+# - date de naissance
+# - pre'sence de php a` re'executer
+# Si pre'sent, on modifie $fraicheur (passe' en re'fe'rence)
+# pour qu'il indique la dure'e de vie restante
+
+function page_perenne($lock, $file, &$fraicheur)
+{
+  $naissance = filemtime($file);
+  $t = time() - $naissance;
+  if ($t > $fraicheur) return false; 
+#  spip_log("Perenne: fraicheur ok");
+# la ligne 1 contient un commentaire comportant successivement
+# - la longe'vite' 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))
+# fichier non conforme, on ignore
+    return false; 
+#  spip_log("Perenne: contenu ok");
+  $t =  $m[1] - $t;
+  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 ame'liorerez les perfs en 
+# de'commentant les 2 lignes suivantes (quant a` 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]);
+}
 
-function ecrire_fichier_cache($fichier, $contenu) {
-	global $flag_flock;
-
-	$fichier_tmp = $fichier.'_tmp';
-	$fichier_new = $fichier.'.NEW';
-
-	// Essayer de poser un verrou pour proteger l'ecriture du fichier
-	if (!spip_get_lock($fichier_tmp, 1)) return $fichier_new;
-	$ok = true;
-	$f = fopen($fichier_tmp, "wb");
-	if (!$f) $ok = false;
-	else {
-		$r = fwrite($f, $contenu);
-		if ($r != strlen($contenu)) $ok = false;
-		if (!fclose($f)) $ok = false;
+# Retourne une page, de'crite par le tableau de 2 ou 3 e'le'ments:
+# 'texte' => la page
+# 'process_ins' => 'html' ou 'php' si pre'sence d'un '<?php'
+# 'naissance' => heure du calcul si de'ja` calcule' (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 re'petoire $fraicheur.
+# Celle-ci est pase'e par re'fe'rence pour e^tre change'e
+# $calcul est soit cherche_page_incluse soit cherche_page_incluante
+# qui appelle toute deux cherche_page, qui construit le tableau a 2 e'le'ments
+
+# Les acce`s concurrents sont ge're's par un verrou ge'ne'ral, 
+# remplace' rapidement par un verrou spe'cifique
+
+function ramener_cache($cle, $calcul, $contexte, &$fraicheur)
+{
+  # pas de mise en cache si:
+  # - recherche (trop couteux de me'moriser une recherche pre'cise)
+  # - valeurs hors URL (i.e. POST) sauf Forum qui les traite a` part
+  
+  if ($GLOBALS['var_recherche']||
+      ($HTTP_POST_VARS && !$GLOBALS['ajout_forum']))
+      {
+	include('inc-calcul.php3');
+	return $calcul('', $contexte);
+      }
+# Bloquer/se faire bloquer par TOUS les cre'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');
+    }
+# Acque'rir le verrou spe'cifique et libe'rer le pre'ce'dent
+# pour permettre d'autres calculs (notamment d'e'ventuels include).
+# Ouvrir par r+ verrouille' pour forcer un 2e processus de me^me intention
+# a` attendre le re'sulat du premier et s'en servir. 
+# Pour voir, de'commenter le sleep ci-dessous,
+# lancer 2 demandes d'une page (surtout a` 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 be'be'; 
+# on se bloque dessus apre`s libe'ration du verrou ge'ne'ral
+      flock($lock, LOCK_UN);
+      $usefile = true;
+      while(!flock($lock2, LOCK_EX));
+    }
+  else
+    flock($lock, LOCK_UN);
+#  spip_log("obtient verrou $cle et libe`re le ge'ne'ral"); 
+  if ((!timeout(false,false)) OR
+      ($usefile && ($r = page_perenne($lock2, $file, &$fraicheur))))
+    {
+#      spip_log("libe`re verrou $cle (page perenne)"); 
+      flock($lock2, LOCK_UN);
+      return $r;
+    }
+  if ($obsolete && (file_exists('inc-invalideur.php3')))
+    {
+      include('inc-invalideur.php3');
+      supprime_invalideurs_inclus("hache='$file'");
+    }
+  include('inc-calcul.php3');
+  if (!function_exists($calcul))
+      {
+	flock($lock2, LOCK_UN);
+	return(array('texte' => 'Compilateur absent'));
+      }
+  $page = $calcul($file, $contexte);
+  $texte = $page['texte'];
+  $n = ($fraicheur ? strlen($texte) : 0);
+  if (!$n)
+    {
+      flock($lock2, LOCK_UN);
+      @unlink($file);
+    }
+  else
+    {
+      spip_log("Ecriture ($cle): $n octets (validite': $fraicheur sec.)");
+      fseek($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('inc-invalideur.php3');
+	  maj_invalideurs($file, $page['invalideurs']);
+	  if ($f = $contexte['cache_incluant'])
+	    insere_invalideur(array($file => true), 'inclure', $f);
 	}
+    }
+  return $page;
+}
 
-	// En cas d'erreur d'ecriture, renvoyer le fichier existant
-	if (!$ok) {
-		spip_release_lock($fichier_tmp);
-		clearstatcache();
-		return @file_exists($fichier_new) ? $fichier_new : $fichier;
-	}
+# 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);
+    }
+}
 
-	// Finaliser
-	@unlink($fichier_new);
-	rename($fichier_tmp, $fichier_new);
-	@unlink($fichier);
-	spip_release_lock($fichier_tmp);
+# de'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)");
+}
 
-	if ($GLOBALS['flag_apc']) {
-		apc_rm($fichier_new);
-		apc_rm($fichier);
+# de'truit toutes les pages cache'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++;}
+		}
+		@rmdir("$dir$subdir");
+	      }
+	  }
 	}
-	return $fichier_new;
+    }
+  spip_log("Destruction des $j cache(s)");
+  if (file_exists('inc-invalideur.php3'))
+    {
+      include('inc-invalideur.php3');
+      supprime_invalideurs();
+    }
 }
 
-
-//
-// 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;
-		}
+# elimine les caches obsoletes figurant dans le me^me rep que la page indique'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) . " obsole`te(s)");
+  if ($tous)
+    {
+      if (!file_exists('inc-invalideur.php3'))
+	retire_caches($tous);
+      else
+	{
+	  include('inc-invalideur.php3');
+	  applique_invalideur($tous);
 	}
-	return ($ok? "$subdir/" : '');
+    }
 }
 
+# trouve dans un re'pertoire les caches
+# ve'rifiant un pre'dicat binaire (donne' 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;
+}
 
-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);
+# Teste l'obsolescence d'un cache. 
+# Celle de son include le + bref (indique'e ligne 1) serait + juste
+# mais lors d'un balayage de re'pertoire, 
+# ouvrir chaque fichier serait couteux, et de gain faible
+
+function retire_cond_cache($arg,$path)
+{
+    return (filemtime($path) <  $arg);
 }
 
+# de'truit les caches donne's en arguments.
+# En fait il faudrait poser un verrou sur chaque fichier
+# pour que ramener_cache ne puisse s'exe'cuter a` ce moment-la`
+# Trop cher pour une situation peu probable, mais a` e'tudier.
+
+function retire_caches($caches)
+{
+  if ($caches)
+    {
+      foreach ($caches as $path)
+	{ @unlink($GLOBALS['flag_ecrire'] ? ('../' . $path) : $path);}
+    }
+}
 ?>
diff --git a/inc-calcul-squel.php3 b/inc-calcul-squel.php3
index 9026088d8b..a939a84af1 100644
--- a/inc-calcul-squel.php3
+++ b/inc-calcul-squel.php3
@@ -1,2127 +1,396 @@
 <?php
-
-//
 // Ce fichier ne sera execute qu'une fois
 if (defined("_INC_CALCUL_SQUEL")) return;
 define("_INC_CALCUL_SQUEL", "1");
 
+# Fichier principal du compilateur de squelettes, incluant tous les autres.
 
+include_local("inc-bcl-squel.php3");
+include_local("inc-arg-squel.php3");
+include_local("inc-reqsql-squel.php3");
 include_local("inc-champ-squel.php3");
+include_local("inc-logo-squel.php3");
+include_local("inc-form-squel.php3");
+include_local("inc-vrac-squel.php3");
+include_local("inc-index-squel.php3");
+include_local("inc-text-squel.php3");
 
+# Produit le corps PHP d'une boucle Spip,
+# essentiellement une boucle while (ou une double en cas de hierarchie)
+# remplissant une variable $t0 retourne'e en valeur
 
-//////////////////////////////////////////////////////////////////////////////
-//
-//              Parsing des squelettes
-//
-//////////////////////////////////////////////////////////////////////////////
-
-
-class Texte {
-	var $type = 'texte';
-	var $texte;
-}
-
-class Champ {
-	var $type = 'champ';
-	var $nom_champ, $id_champ;
-	var $cond_avant, $cond_apres; // tableaux d'objets
-	var $fonctions;
-}
-
-class Boucle {
-	var $type = 'boucle';
-	var $id_boucle, $id_parent;
-	var $avant, $cond_avant, $milieu, $cond_apres, $cond_altern, $apres; // tableaux d'objets
-	var $commande;
-	var $requete;
-	var $type_requete;
-	var $separateur;
-	var $doublons;
-	var $lang_select;
-	var $partie, $total_parties;
-}
-
-
-function parser_boucle($texte, $id_parent) {
-	global $rubriques_publiques;
-	global $recherche;
-	global $tables_relations;
-
-	//
-	// Detecter et parser la boucle
-	//
-
-	$p = strpos($texte, '<BOUCLE');
-	if (!$p && (substr($texte, 0, strlen('<BOUCLE')) != '<BOUCLE')) {
-		$result = new Texte;
-		$result->texte = $texte;
-		return $result;
-	}
-
-	$result = new Boucle;
-
-	$debut = substr($texte, 0, $p);
-	$milieu = substr($texte, $p);
-
-	if (!ereg("^(<BOUCLE([0-9]+|[-_][-_.a-zA-Z0-9]*)[[:space:]]*(\([^)]*\)([[:space:]]*\{[^}]*\})*)[[:space:]]*>)", $milieu, $match)) {
-		include_ecrire ("inc_presentation.php3");
-		install_debut_html(_T('erreur_boucle_syntaxe'));
-		$milieu = entites_html($milieu);
-		echo '<p>'._T('erreur_boucle_syntaxe2', array('milieu' => $milieu));
-		install_fin_html();
-		exit;
-	}
-
-	$commande = $match[1];
-	$id_boucle = $match[2];
-	$suite_commande = $match[3];
-
-	//
-	// Decomposer les structures conditionnelles
-	//
-
-	$s = "<B$id_boucle>";
-
-	$p = strpos($debut, $s);
-	if ($p || (substr($debut, 0, strlen($s)) == $s)) {
-		$cond_avant = substr($debut, $p + strlen($s));
-		$debut = substr($debut, 0, $p);
-	}
-
-	$milieu = substr($milieu, strlen($commande));
-	$s = "</BOUCLE$id_boucle>";
-	$p = strpos($milieu, $s);
-	if ((!$p) && (substr($milieu, 0, strlen($s)) != $s)) {
-		include_ecrire ("inc_presentation.php3");
-		install_debut_html(_T('erreur_boucle_syntaxe'));
-		echo '<p>'._T('erreur_boucle_fermant', array('id'=>$id_boucle));
-		install_fin_html();
-		exit;
-	}
-
-	$fin = substr($milieu, $p + strlen($s));
-	$milieu = substr($milieu, 0, $p);
-
-	$s = "</B$id_boucle>";
-	$p = strpos($fin, $s);
-	if ($p || (substr($fin, 0, strlen($s)) == $s)) {
-		$cond_fin = substr($fin, 0, $p);
-		$fin = substr($fin, $p + strlen($s));
-	}
-
-	$s = "<//B$id_boucle>";
-	$p = strpos($fin, $s);
-	if ($p || (substr($fin, 0, strlen($s)) == $s)) {
-		$cond_altern = substr($fin, 0, $p);
-		$fin = substr($fin, $p + strlen($s));
-	}
-
-	$id_boucle = ereg_replace("-","_",$id_boucle);
-
-	//
-	// Parser la commande de la boucle
-	//
-
-	if (ereg('\(([^)]*)\)', $suite_commande, $regs)) {
-		$_type = $regs[1];
-		$s = "($_type)";
-		$p = strpos($suite_commande, $s);
-
-		// Exploser les parametres
-		$params = substr($suite_commande, $p + strlen($s));
-		if (ereg('^[[:space:]]*\{(.*)\}[[:space:]]*$', $params, $match)) $params = $match[1];
-		$params = split('\}[[:space:]]*\{', $params);
-		$type = strtolower($_type);
-
-		//
-		// Type boucle (recursion)
-		//
-
-		if ($type == 'sites') $type = 'syndication';
-		
-		if (substr($type, 0, 6) == 'boucle') {
-			$requete = substr($_type, 6);
-			$type = 'boucle';
-		}
-		else {
-			//
-			// Initialisation separee par type
-			//
-			
-			switch($type) {
-			case 'articles':
-				$table = "articles";
-				$req_from[] = "spip_articles AS $table";
-				$id_objet = "id_article";
-				break;
-
-			case 'auteurs':
-				$table = "auteurs";
-				$req_from[] = "spip_auteurs AS $table";
-				$id_objet = "id_auteur";
-				break;
-
-			case 'breves':
-				$table = "breves";
-				$req_from[] = "spip_breves AS $table";
-				$id_objet = "id_breve";
-				$col_date = "date_heure";
-				break;
-
-			case 'forums':
-				$table = "forums";
-				$req_from[] = "spip_forum AS $table";
-				$id_objet = "id_forum";
-				$col_date = "date_heure";
-				break;
-
-			case 'signatures':
-				$table = "signatures";
-				$req_from[] = "spip_signatures AS $table";
-				$id_objet = "id_signature";
-				$col_date = "date_time";
-				break;
-
-			case 'documents':
-				$table = "documents";
-				$req_select[] = "$table.*";
-				$req_select[] = "types_d.titre AS type_document";
-				$req_select[] = "types_d.extension AS extension_document";
-				$req_from[] = "spip_documents AS $table";
-				$req_from[] = "spip_types_documents AS types_d";
-				$req_where[] = "$table.id_type = types_d.id_type";
-				$id_objet = "id_document";
-				break;
-
-			case 'types_documents':
-				$table = "types_documents";
-				$req_from[] = "spip_types_documents AS $table";
-				$id_objet = "id_type";
-				break;
-
-			case 'groupes_mots':
-				$table = "groupes_mots";
-				$req_from[] = "spip_groupes_mots AS $table";
-				$id_objet = "id_groupe";
-				break;
-
-			case 'mots':
-				$table = "mots";
-				$req_from[] = "spip_mots AS $table";
-				$id_objet = "id_mot";
-				break;
-
-			case 'rubriques':
-				$table = "rubriques";
-				$req_from[] = "spip_rubriques AS $table";
-				$id_objet = "id_rubrique";
-				break;
-
-			case 'syndication':
-				$table = "syndic";
-				$req_from[] = "spip_syndic AS $table";
-				$req_where[] = "$table.statut='publie'";
-				$id_objet = "id_syndic";
-				break;
-
-			case 'syndic_articles':
-				$table = "articles";
-				$req_from[] = "spip_syndic_articles AS $table";
-				$req_from[] = "spip_syndic AS source";
-				$req_where[] = "$table.id_syndic=source.id_syndic";
-				$req_where[] = "$table.statut='publie'";
-				$req_where[] = "source.statut='publie'";
-				$id_objet = "id_syndic_article";
-				break;
-			}
-			if ($table) {
-				if ($type == 'articles') {
-					$s = "$table.id_article,$table.id_rubrique,$table.id_secteur,".
-						"$table.surtitre,$table.titre,$table.soustitre,$table.date,$table.date_redac,$table.date_modif,".
-						"$table.visites,$table.popularite,$table.statut,$table.accepter_forum,$table.lang,$table.id_trad";
-					if (ereg('\#(TEXTE|INTRODUCTION)', $milieu))
-						$s .= ",$table.texte";
-					if (ereg('\#(CHAPO|INTRODUCTION)', $milieu))
-						$s .= ",$table.chapo";
-					if (ereg('\#(DESCRIPTIF|INTRODUCTION)', $milieu))
-						$s .= ",$table.descriptif";
-					if (ereg('\#(PS)', $milieu))
-						$s .= ",$table.ps";
-					if (ereg('\#(EXTRA)', $milieu))
-						$s .= ",$table.extra";
-					if (ereg("\#(NOM_SITE|URL_SITE)", $milieu))
-						$s .= ",$table.nom_site,$table.url_site";
-					$req_select[] = $s;
-				}
-				else $req_select[] = "$table.*";
-			}
-			if (!$col_date) $col_date = "date";
-
-			//
-			// Parametres : premiere passe
-			//
-			unset($params2);
-			if ($params) {
-				reset($params);
-				while (list(, $param) = each($params)) {
-					$param = trim($param);
-					if ($param == 'exclus') {
-						$req_where[] = "$table.$id_objet!=\$$id_objet";
-					}
-					else if ($param == 'tout' OR $param == 'tous') {
-						$tout = true;
-					}
-					else if ($param == 'plat') {
-						$plat = true;
-					}
-					else if ($param == 'unique' OR $param == 'doublons') {
-						$doublons = 'oui';
-						$req_where[] = "$table.$id_objet NOT IN (\$id_doublons[$type])";
-					}
-					else if (ereg('^(!)? *lang_select(=(oui|non))?$', $param, $match)) {
-						if (!$lang_select = $match[3]) $lang_select = 'oui';
-						if ($match[1]) $lang_select = ($lang_select=='oui')?'non':'oui';
-					}
-					else if (ereg('^ *"([^"]*)" *$', $param, $match)) {
-						$separateur = ereg_replace("'","\'",$match[1]);
-					}
-					else if (ereg('^([0-9]+),([0-9]*)', $param, $match)) {
-						$req_limit = $match[1].','.$match[2];
-					}
-					else if (ereg('^debut([-_a-zA-Z0-9]+),([0-9]*)$', $param, $match)) {
-						$debut_lim = "debut".$match[1];
-						$req_limit = '".intval($GLOBALS[\'HTTP_GET_VARS\'][\''.$debut_lim.'\']).",'.$match[2];
-					}
-					else if (ereg('^([0-9]+)/([0-9]+)$', $param, $match)) {
-						$partie = $match[1];
-						$total_parties = $match[2];
-					}
-					else if ($param == 'recherche') {
-						if ($type == 'syndication') $req_from[] = "spip_index_syndic AS rec";
-						else if ($type == 'forums') $req_from[] = "spip_index_forum AS rec";
-						else $req_from[] = "spip_index_$type AS rec";
-						$req_select[] = "SUM(rec.points + 100*(rec.hash IN (\$hash_recherche_strict))) AS points";
-						$req_where[] = "rec.$id_objet=$table.$id_objet";
-						$req_group = " GROUP BY $table.$id_objet";
-						$req_where[] = "rec.hash IN (\$hash_recherche)";
-					}
-					else $params2[] = $param;
-				}
-			}
-			$params = $params2;
-
-			//
-			// Parametres : deuxieme passe
-			//
-			if ($params) {
-				reset($params);
-				while (list(, $param) = each($params)) {
-
-					// Classement par ordre inverse
-					if ($param == 'inverse') {
-						if ($req_order) $req_order .= ' DESC';
-					}
-					// Gerer les traductions
-					else if ($param == 'traduction') {
-						$req_where[] = "$table.id_trad > 0 AND $table.id_trad = \$id_trad";
-					}
-					else if ($param == 'origine_traduction') {
-						$req_where[] = "$table.id_trad = $table.id_article";
-					}
-
-					// Special rubriques
-					else if ($param == 'meme_parent') {
-						$req_where[] = "$table.id_parent=\$id_parent";
-						if ($type == 'forums') {
-							$req_where[] = "$table.id_parent > 0";
-							$plat = true;
-						}
-					}
-					else if ($param == 'racine') {
-						$req_where[] = "$table.id_parent=0";
-					}
-					else if (ereg("^branche *(\??)", $param, $regs)) {
-						if (!$regs[1])
-							$req_where[] = "$table.id_rubrique IN (\".calcul_branche(\$id_rubrique).\")";
-						else
-							$req_where[] = "('\$id_rubrique'='' OR $table.id_rubrique IN (\".calcul_branche(\$id_rubrique).\"))";
- 					}
-
-					// Restriction de valeurs (implicite ou explicite)
-					else if (ereg('^([a-zA-Z_]+) *(\??) *((!?)(<=?|>=?|==?|\?) *"?([^<>=!"?]*))?"?$', $param, $match)) {
-						// Variable comparee
-						$col = $match[1];
-						$col_table = $table;
-
-						// Valeur de comparaison
-						if ($match[3])
-							$val = $match[6];
-						else {
-							$val = $match[1];
-							// Si id_parent, comparer l'id_parent avec l'id_objet de la boucle superieure
-							if ($val == 'id_parent')
-								$val = $id_objet;
-							// Si id_enfant, comparer l'id_objet avec l'id_parent de la boucle superieure
-							else if ($val == 'id_enfant')
-								$val = 'id_parent';
-							$val = '$'.$val;
-						}
-
-						// operateur optionnel {lang?}
-						$ou_rien = ($match[2]) ? "'$val'='' OR " : '';
-
-						// Traitement general des relations externes
-						if ($s = $tables_relations[$type][$col]) {
-							$col_table = "rel_$type";
-							$req_from[] = "$s AS $col_table";
-							$req_where[] = "$table.$id_objet=$col_table.$id_objet";
-							$req_group = " GROUP BY $table.$id_objet";
-							$flag_lien = true;
-						}
-						// Cas particulier pour les raccourcis 'type_mot' et 'titre_mot'
-						else if ($type != 'mots' AND ($col == 'type_mot' OR $col == 'titre_mot' OR $col == 'id_groupe')) {
-							if ($type == 'forums')
-								$col_lien = "spip_mots_forum";
-							else if ($type == 'syndication')
-								$col_lien = "spip_mots_syndic";
-							else
-								$col_lien = 'spip_mots_'.$type;
-							$req_from[] = "$col_lien AS lien_mot";
-							$req_from[] = 'spip_mots AS mots';
-							$req_where[] = "$table.$id_objet=lien_mot.$id_objet";
-							$req_where[] = "lien_mot.id_mot=mots.id_mot";
-							$req_group = " GROUP BY $table.$id_objet";
-							$col_table = 'mots';
-							$flag_lien = true;
-							if ($col == 'type_mot')
-								$col = 'type';
-							else if ($col == 'titre_mot')
-								$col = 'titre';
-							else if ($col == 'id_groupe')
-								$col = 'id_groupe';
-						}
-
-						// Cas particulier : selection des documents selon l'extension
-						if ($type == 'documents' AND $col == 'extension') {
-							$col_table = 'types_d';
-						}
-						// HACK : selection des documents selon mode 'image' (a creer en dur dans la base)
-						else if ($type == 'documents' AND $col == 'mode' AND $val == 'image') {
-							$val = 'vignette';
-						}
-						// Cas particulier : lier les articles syndiques au site correspondant
-						else if ($type == 'syndic_articles' AND !ereg("^(id_syndic_article|titre|url|date|descriptif|lesauteurs)$",$col))
-							$col_table = 'source';
-
-						// Cas particulier : id_enfant => utiliser la colonne id_objet
-						if ($col == 'id_enfant')
-							$col = $id_objet;
-						// Cas particulier : id_secteur = id_rubrique pour certaines tables
-						else if (($type == 'breves' OR $type == 'forums') AND $col == 'id_secteur')
-							$col = 'id_rubrique';
-
-						// Cas particulier : expressions de date
-						if (ereg("^(date|mois|annee|age|age_relatif|jour_relatif|mois_relatif|annee_relatif)(_redac)?$", $col, $regs)) {
-							$col = $regs[1];
-							if ($regs[2]) {
-								$date_orig = "$table.date_redac";
-								$date_compare = 'date_redac';
-							}
-							else {
-								$date_orig = "$table.$col_date";
-								$date_compare = 'date';
-							}
-
-							if ($col == 'date') {
-								$col = $date_orig;
-								$col_table = '';
-							}
-							else if ($col == 'mois') {
-								$col = "MONTH($date_orig)";
-								$col_table = '';
-							}
-							else if ($col == 'annee') {
-								$col = "YEAR($date_orig)";
-								$col_table = '';
-							}
-							else if ($col == 'age') {
-								$col = "(LEAST((UNIX_TIMESTAMP(now())-UNIX_TIMESTAMP($date_orig))/86400, TO_DAYS(now())-TO_DAYS($date_orig), DAYOFMONTH(now())-DAYOFMONTH($date_orig)+30.4368*(MONTH(now())-MONTH($date_orig))+365.2422*(YEAR(now())-YEAR($date_orig))))";
-								$col_table = '';
-							}
-							else if ($col == 'age_relatif') {
-								$col = "LEAST((UNIX_TIMESTAMP('\$$date_compare')-UNIX_TIMESTAMP($date_orig))/86400, TO_DAYS('\$$date_compare')-TO_DAYS($date_orig), DAYOFMONTH('\$$date_compare')-DAYOFMONTH($date_orig)+30.4368*(MONTH('\$$date_compare')-MONTH($date_orig))+365.2422*(YEAR('\$$date_compare')-YEAR($date_orig)))";
-								$col_table = '';
-							}
-							else if ($col == 'jour_relatif') {
-								$col = "LEAST(TO_DAYS('\$$date_compare')-TO_DAYS($date_orig), DAYOFMONTH('\$$date_compare')-DAYOFMONTH($date_orig)+30.4368*(MONTH('\$$date_compare')-MONTH($date_orig))+365.2422*(YEAR('\$$date_compare')-YEAR($date_orig)))";
-								$col_table = '';
-							}
-							else if ($col == 'mois_relatif') {
-								$col = "(MONTH('\$$date_compare')-MONTH($date_orig)+12*(YEAR('\$$date_compare')-YEAR($date_orig)))";
-								$col_table = '';
-							}
-							else if ($col == 'annee_relatif') {
-								$col = "YEAR('\$$date_compare')-YEAR($date_orig)";
-								$col_table = '';
-							}
-						}
-
-						if ($type == 'forums' AND ($col == 'id_parent' OR $col == 'id_forum'))
-							$plat = true;
-
-						// Operateur de comparaison
-						if ($match[5]) {
-							$op = $match[5];
-							if ($op == '==') $op = ' REGEXP ';
-						}
-						else {
-							$op = '=';
-						}
-
-						if ($col_table) $col_table .= '.';
-						$where = "($ou_rien$col_table$col$op'".addslashes($val)."')";
-
-						if ($match[4] == '!') $where = "NOT ($where)";
-						$req_where[] = $where;
-					}
-
-					// Selection du classement
-					else if (ereg('^par[[:space:]]+([^}]*)$', $param, $match)) {
-						$tri = trim($match[1]);
-						if ($tri == 'hasard') { // par hasard
-							$req_select[] = "MOD($table.$id_objet * UNIX_TIMESTAMP(), 32767) & UNIX_TIMESTAMP() AS alea";
-							$req_order = " ORDER BY alea";
-						}
-						else if ($tri == 'titre_mot'){ // par titre_mot
-							$req_order= " ORDER BY mots.titre";
-						}
-						else if ($tri == 'type_mot'){ // par type_mot
-							$req_order= " ORDER BY mots.type";
-						}
-						else if ($tri == 'points'){ // par points
-							$req_order= " ORDER BY points";
-						}
-						else if (ereg("^num[[:space:]]+([^,]*)(,.*)?",$tri, $match2)) { // par num champ
-							$req_select[] = "0+$table.".$match2[1]." AS num";
-							$req_order = " ORDER BY num".$match2[2];
-						}
-						else if (ereg("^[a-z0-9]+$", $tri)) { // par champ
-							$col = $tri;
-							if ($col == 'date') $col = $col_date;
-							$req_order = " ORDER BY $table.$col";
-						}
-						else { // tris bizarres, par formule composee, virgules, etc.
-							$req_order = " ORDER BY ".$tri;
-						}
-					}
-				}
-			}
-
-			//
-			// Post-traitement separe par type
-			//
-
-			switch($type) {
-			case 'articles':
-				$post_dates = lire_meta("post_dates");
-				if ($post_dates == 'non') $req_where[] = "$table.date<NOW()";
-				$req_where[] = "$table.statut='publie'";
-				break;
-
-			case 'groupes_mots':
-				// pas de restriction sur les groupes de_mots
-				break;
-
-			case 'mots':
-				// pas de restriction sur les mots
-				break;
-
-			case 'breves':
-				$req_where[] = "$table.statut='publie'";
-				break;
-
-			case 'rubriques':
-				if (!$tout) $req_where[] = "$table.statut='publie'";
-				break;
-
-			case 'forums':
-				// Par defaut, selectionner uniquement les forums sans pere
-				if (!$plat) $req_where[] = "$table.id_parent=0";
-				$req_where[] = "$table.statut='publie'";
-				break;
-
-			case 'signatures':
-				$req_from[] = 'spip_petitions AS petitions';
-				$req_from[] = 'spip_articles AS articles';
-				$req_where[] = "petitions.id_article=articles.id_article";
-				$req_where[] = "petitions.id_article=$table.id_article";
-
-				$req_where[] = "$table.statut='publie'";
-				$req_group = " GROUP BY $table.$id_objet";
-				break;
-
-			case 'syndic_articles':
-				$req_select[]='syndic.nom_site AS nom_site';
-				$req_select[]='syndic.url_site AS url_site';
-				$req_from[]='spip_syndic AS syndic';
-				$req_where[] = "syndic.id_syndic=$table.id_syndic";
-				break;
-
-			case 'documents':
-				$req_where[] = "$table.taille > 0";
-				break;
-
-			case 'auteurs':
-				// Si pas de lien avec un article, selectionner
-				// uniquement les auteurs d'un article publie
-				if (!$tout AND !$flag_lien) {
-					$req_from[] = 'spip_auteurs_articles AS lien';
-					$req_from[] = 'spip_articles AS articles';
-					$req_where[] = "lien.id_auteur=$table.id_auteur";
-					$req_where[] = "lien.id_article=articles.id_article";
-					$req_where[] = "articles.statut='publie'";
-					$req_group = " GROUP BY $table.$id_objet";
-				}
-				// pas d'auteurs poubellises
-				$req_where[] = "NOT($table.statut='5poubelle')";
-				break;
-			}
-		}
-
-		//
-		// Construire la requete
-		//
-		if ($type == 'hierarchie')
-			$requete = $req_limit;
-		else if ($req_select) {
-			$requete = 'SELECT '.join(',', $req_select)." FROM ".join(',', $req_from);
-			if ($req_where) $requete .= " WHERE ".join(" AND ", $req_where);
-			$requete .= $req_group;
-			$requete .= $req_order;
-			if ($req_limit) $requete .= " LIMIT ".$req_limit;
-		}
-		$result->type_requete = $type;
-		$result->requete = $requete;
-		$result->doublons = $doublons;
-		$result->lang_select = $lang_select;
-		$result->separateur = $separateur;
-	}
-
-
-	//
-	// Stocker le tout dans le resultat de la fonction
-	//
-
-	$result->id_boucle = $id_boucle;
-	$result->id_parent = $id_parent;
-	$result->commande = $commande;
-	$result->avant = $debut;
-	$result->cond_avant = parser_texte($cond_avant, $id_parent);
-	$result->cond_apres = parser_texte($cond_fin, $id_parent);
-	$result->cond_altern = parser_texte($cond_altern, $id_parent);
-	$result->milieu = parser_texte($milieu, $id_boucle);
-	$result->apres = $fin;
-	$result->partie = $partie;
-	$result->total_parties = $total_parties;
-
-	return $result;
-}
-
-
-
-function parser_champs($texte) {
-	global $champs;
-	global $champs_count;
-	global $champs_valides;
-	global $champs_traitement;
-	global $champs_pretraitement;
-	global $champs_posttraitement;
-
-	$debut = '';
-	$result=Array();
-	while ($texte) {
-		$r = ereg('(#([a-zA-Z_]+)(\*?))', $texte, $regs);
-		if ($r) {
-			unset($champ);
-			$nom_champ = $regs[2];
-			$flag_brut = $regs[3];
-			$s = $regs[1];
-			$p = strpos($texte, $s);
-			if ($champs_valides[$nom_champ]) {
-				$debut .= substr($texte, 0, $p);
-				if ($debut) {
-					$champ = new Texte;
-					$champ->texte = $debut;
-					$result[] = $champ;
-				}
-				$champ = new Champ;
-				$champ->nom_champ = $nom_champ;
-				$champ->fonctions = $champs_pretraitement[$nom_champ];
-				if (!$flag_brut AND $champs_traitement[$nom_champ]) {
-					reset($champs_traitement[$nom_champ]);
-					while (list(, $f) = each($champs_traitement[$nom_champ])) {
-						$champ->fonctions[] = $f;
-					}
-				}
-				if ($champs_posttraitement[$nom_champ]) {
-					reset($champs_posttraitement[$nom_champ]);
-					while (list(, $f) = each($champs_posttraitement[$nom_champ])) {
-						$champ->fonctions[] = $f;
-					}
-				}
-				$champs_count++;
-				$champ->id_champ = $champs_count;
-				$champs[$champs_count] = $champ;
-				$result[] = $champ;
-				$debut = '';
-			}
-			else {
-				$debut .= substr($texte, 0, $p + strlen($s));
-			}
-			$texte = substr($texte, $p + strlen($s));
-		}
-		else {
-			$champ = new Texte;
-			$champ->texte = $debut.$texte;
-			if ($champ->texte) $result[] = $champ;
-			break;
-		}
-	}
-	return $result;
-}
-
-
-function parser_champs_etendus($texte) {
-	global $champs;
-	global $champs_count;
-	global $champs_valides;
-	global $champs_traitement;
-	global $champs_pretraitement;
-	global $champs_posttraitement;
-
-	$debut = '';
-	while ($texte) {
-		$r = ereg('(\[([^\[]*)\(#([a-zA-Z_]+)(\*?)([^])]*)\)([^]]*)\])', $texte, $regs);
-
-		if ($r) {
-			$cond_avant = $regs[2];
-			$nom_champ = $regs[3];
-			$flag_brut = $regs[4];
-			$fonctions = $regs[5];
-			$cond_apres = $regs[6];
-			$s = $regs[1];
-			$p = strpos($texte, $s);
-			if ($champs_valides[$nom_champ]) {
-				$debut .= substr($texte, 0, $p);
-				if ($debut) {
-					$c = parser_champs($debut);
-					reset($c);
-					while (list(, $val) = each($c)) $result[] = $val;
-				}
-				$champ = new Champ;
-				$champ->nom_champ = $nom_champ;
-				$champ->cond_avant = parser_champs($cond_avant);
-				$champ->cond_apres = parser_champs($cond_apres);
-				$champ->fonctions = $champs_pretraitement[$nom_champ];
-				if (!$flag_brut AND $champs_traitement[$nom_champ]) {
-					reset($champs_traitement[$nom_champ]);
-					while (list(, $f) = each($champs_traitement[$nom_champ])) {
-						$champ->fonctions[] = $f;
-					}
-				}
-				if ($fonctions) {
-					$fonctions = explode('|', ereg_replace("^\|", "", $fonctions));
-					reset($fonctions);
-					while (list(, $f) = each($fonctions)) $champ->fonctions[] = $f;
-				}
-				if ($champs_posttraitement[$nom_champ]) {
-					reset($champs_posttraitement[$nom_champ]);
-					while (list(, $f) = each($champs_posttraitement[$nom_champ])) {
-						$champ->fonctions[] = $f;
-					}
-				}
-				$champs_count++;
-				$champ->id_champ = $champs_count;
-				$champs[$champs_count] = $champ;
-				$result[] = $champ;
-				$debut = '';
-			}
-			else {
-				$debut .= substr($texte, 0, $p + strlen($s));
-			}
-			$texte = substr($texte, $p + strlen($s));
-		}
-		else {
-			$c = parser_champs($debut.$texte);
-			reset($c);
-			while (list(, $val) = each($c)) $result[] = $val;
-			break;
-		}
-	}
-	return $result;
-}
-
-function parser_texte($texte, $id_boucle) {
-	global $boucles;
-
-	$i = 0;
-
-	while ($texte) {
-		$boucle = parser_boucle($texte, $id_boucle);
-		if ($boucle->type == 'texte') {
-			if ($c = parser_champs_etendus($boucle->texte)) {
-				reset($c);
-				while (list(, $val) = each($c)) {
-					$result[$i] = $val;
-					$i++;
-				}
-			}
-			$texte = '';
-		}
-		else {
-			if ($c = parser_champs_etendus($boucle->avant)) {
-				reset($c);
-				while (list(, $val) = each($c)) {
-					$result[$i] = $val;
-					$i++;
-				}
-			}
-			$texte = $boucle->apres;
-			$boucle->avant = '';
-			$boucle->apres = '';
-			$result[$i] = $boucle;
-			$i++;
-			if (!$boucles[$boucle->id_boucle])
-				$boucles[$boucle->id_boucle] = $boucle;
-			else {
-				include_ecrire ("inc_presentation.php3");
-				install_debut_html(_T('erreur_boucle_syntaxe'));
-				$id = $boucle->id_boucle;
-				echo '<p>'._T('erreur_boucle_double', array('id'=>$id));
-				install_fin_html();
-				exit;
-			}
-		}
-	}
-
-	return $result;
-}
-
-
-function parser($texte) {
-	global $racine;
-
-	// Parser le texte et retourner le tableau racine
-
-	$racine = parser_texte($texte, '');
-}
-
-
-
-
-//////////////////////////////////////////////////////////////////////////////
-//
-//              Calcul des squelettes
-//
-//////////////////////////////////////////////////////////////////////////////
-
-//
-// appliquer les filtres a un champ
-//
-function applique_filtres ($fonctions, $code) {
-	if ($fonctions) {
-		while (list(, $fonc) = each($fonctions)) {
-			if ($fonc) {
-				$arglist = '';
-				if (ereg('([^\{\}]*)\{(.+)\}$', $fonc, $regs)) {
-					$fonc = $regs[1];
-					if (trim($regs[2]))
-						$arglist = ','.$regs[2];
-				}
-				if (function_exists($fonc))
-					$code = "$fonc($code$arglist)";
-				else
-					$code = "'"._T('erreur_filtre', array('filtre' => $fonc))."'";
-			}
-		}
-	}
-	return $code;
-}
-
-
-//
-// Generer le code PHP correspondant a un champ SPIP
-//
-
-function calculer_champ($id_champ, $id_boucle, $nom_var)
+function calculer_boucle($id_boucle, &$boucles)
 {
-	global $les_notes;
-	global $boucles;
-	global $champs;
-	global $flag_ob;
-	global $flag_pcre;
-
-	$idb = $id_boucle;
-
-	//
-	// Calculer $id_row en prenant la boucle la plus proche
-	// (i.e. la plus profonde) qui autorise le champ demande
-	//
-
-	$offset_boucle = 0;
-	while (strlen($idb)) {
-		// $rows_articles, etc. : tables pregenerees contenant les correspondances
-		// (nom du champ -> numero de colonne mysql) en fonction du type de requete
-		$id_row = $GLOBALS['rows_'.$boucles[$idb]->type_requete][$champs[$id_champ]->nom_champ];
-		if ($id_row) break;
-		$idb = $boucles[$idb]->id_parent;
-		$offset_boucle++;
-	}
-
-	//
-	// Si cas general (le plus simple), generation
-	// du code php effectuant le calcul du champ
-	//
-
-	if ($id_row) {
-		$fonctions = $champs[$id_champ]->fonctions;
-
-		if ($offset_boucle) $code = "\$pile_boucles[\$id_instance-$offset_boucle]->row[$id_row]";
-		else $code = "\$row[$id_row]";
-
-		$code = applique_filtres ($fonctions, $code);
-
-		return "	\$$nom_var = $code;\n";
-	}
-
-
-	//
-	// Ici traitement des cas particuliers
-	//
-
-/*	$milieu = '<blink>#'.$champs[$id_champ]->nom_champ.'</blink>'; // pour debugger les squelettes
-	$milieu = "	\$$nom_var = '$milieu';\n";*/
-
-	$fonctions = $champs[$id_champ]->fonctions;
-	switch($nom_champ = $champs[$id_champ]->nom_champ) {
-
-	//
-	// Les logos (rubriques, articles...)
-	//
-
-	case 'LOGO_ARTICLE':
-	case 'LOGO_ARTICLE_NORMAL':
-	case 'LOGO_ARTICLE_RUBRIQUE':
-	case 'LOGO_ARTICLE_SURVOL':
-	case 'LOGO_AUTEUR':
-	case 'LOGO_AUTEUR_NORMAL':
-	case 'LOGO_AUTEUR_SURVOL':
-	case 'LOGO_SITE':
-	case 'LOGO_BREVE':
-	case 'LOGO_BREVE_RUBRIQUE':
-	case 'LOGO_MOT':
-	case 'LOGO_RUBRIQUE':
-	case 'LOGO_RUBRIQUE_NORMAL':
-	case 'LOGO_RUBRIQUE_SURVOL':
-	case 'LOGO_DOCUMENT':
-		$milieu = '';
-		ereg("^LOGO_(([a-zA-Z]+).*)$", $nom_champ, $regs);
-		$type_logo = $regs[1];
-		$type_objet = strtolower($regs[2]);
-		$filtres = '';
-		if ($fonctions) {
-			while (list(, $nom) = each($fonctions)) {
-				if (ereg('^(left|right|center|top|bottom)$', $nom))
-					$align = $nom;
-				else if ($nom == 'lien') {
-					$flag_lien_auto = 'oui';
-					$flag_stop = true;
-				}
-				else if ($nom == 'fichier') {
-					$flag_fichier = 'oui';
-					$flag_stop = true;
-				}
-				else if ($nom == '')	// double || signifie "on passe aux filtres"
-					$flag_stop = true;
-				else if (!$flag_stop) {
-					$lien = $nom;
-					$flag_stop = true;
-				}
-				else // apres un URL ou || ou |fichier ce sont des filtres (sauf left...lien...fichier)
-					$filtres[] = $nom;
-			}
-			// recuperer les filtres s'il y en a
-			$fonctions = $filtres;
-		}
-		if ($flag_lien_auto && !$lien) {
-			$milieu .= "
-			\$lien = generer_url_$type_objet(\$contexte['id_$type_objet']);
-			";
-		}
-		else {
-			$milieu .= '
-			$lien = transformer_lien_logo($contexte, \''.addslashes($lien).'\');
-			';
-		}
-
-		if ($type_logo == 'RUBRIQUE') {
-			$milieu .= '
-			list($logon, $logoff) = IMG_image(image_rubrique($contexte["id_rubrique"]));
-			';
-		}
-		else if ($type_logo == 'RUBRIQUE_NORMAL') {
-			$milieu .= '
-			list($logon,) = IMG_image(image_rubrique($contexte["id_rubrique"]));
-			$logoff = "";
-			';
-		}
-		else if ($type_logo == 'RUBRIQUE_SURVOL') {
-			$milieu .= '
-			list(,$logon) = IMG_image(image_rubrique($contexte["id_rubrique"]));
-			$logoff = "";
-			';
-		}
-		else if ($type_logo == 'DOCUMENT'){
-			$milieu .= '
-			$logon = integre_image($contexte["id_document"],"","fichier_vignette");
-			$logoff = "";
-			';
-		}
-		else if ($type_logo == 'AUTEUR') {
-			$milieu .= '
-			list($logon, $logoff) = IMG_image(image_auteur($contexte["id_auteur"]));
-			';
-		}
-		else if ($type_logo == 'AUTEUR_NORMAL') {
-			$milieu .= '
-			list($logon,) = IMG_image(image_auteur($contexte["id_auteur"]));
-			$logoff = "";
-			';
-		}
-		else if ($type_logo == 'AUTEUR_SURVOL') {
-			$milieu .= '
-			list(,$logon) = IMG_image(image_auteur($contexte["id_auteur"]));
-			$logoff = "";
-			';
-		}
-		else if ($type_logo == 'BREVE') {
-			$milieu .= '
-			list($logon, $logoff) = IMG_image(image_breve($contexte["id_breve"]));
-			';
-		}
-		else if ($type_logo == 'BREVE_RUBRIQUE') {
-		  $milieu .= '
-			list($logon, $logoff) = IMG_image(image_breve($contexte["id_breve"]));
-			if (!$logon)
-				list($logon, $logoff) = IMG_image(image_rubrique($contexte["id_rubrique"]));
-		  ';
-		}
-		else if ($type_logo == 'SITE') {
-			$milieu .= '
-			list($logon, $logoff) = IMG_image(image_site($contexte["id_syndic"]));
-			';
-		}
-		else if ($type_logo == 'MOT') {
-			$milieu .= '
-			list($logon, $logoff) = IMG_image(image_mot($contexte["id_mot"]));
-			';
-		}
-		else if ($type_logo == 'ARTICLE') {
-			$milieu .= '
-			list($logon, $logoff) = IMG_image(image_article($contexte["id_article"]));
-			';
-		}
-		else if ($type_logo == 'ARTICLE_NORMAL') {
-			$milieu .= '
-			list($logon,) = IMG_image(image_article($contexte["id_article"]));
-			$logoff = "";
-			';
-		}
-		else if ($type_logo == 'ARTICLE_SURVOL') {
-			$milieu .= '
-			list(,$logon) = IMG_image(image_article($contexte["id_article"]));
-			$logoff = "";
-			';
-		}
-		else if ($type_logo == 'ARTICLE_RUBRIQUE') {
-			$milieu .= '
-			list($logon, $logoff) = IMG_image(image_article($contexte["id_article"]));
-			if (!$logon)
-				list($logon, $logoff) = IMG_image(image_rubrique($contexte["id_rubrique"]));
-			';
-		}
-		if ($flag_fichier)
-			$milieu .= "		\$$nom_var = ereg_replace('^/?IMG/','',\$logon);\n"; // compatibilite ascendante : pas de 'IMG/'
-		else
-			$milieu .= "		\$$nom_var = affiche_logos(\$logon, \$logoff, \$lien, '".addslashes($align)."');\n";
-		break;
-
-	//
-	// Liste des auteurs d'un article
-	//
-	
-	case 'LESAUTEURS':
-		$milieu = '
-		if ($i = $contexte["id_article"]) {
-			$query_auteurs = "SELECT auteurs.nom, auteurs.email FROM spip_auteurs AS auteurs, spip_auteurs_articles AS lien WHERE lien.id_article=$i AND auteurs.id_auteur=lien.id_auteur";
-			$result_auteurs = spip_query($query_auteurs);
-			$auteurs = "";
-			while($row_auteur = spip_fetch_array($result_auteurs)) {
-				$nom_auteur = typo($row_auteur["nom"]);
-				$email_auteur = $row_auteur["email"];
-				if ($email_auteur) {
-					$auteurs[] = "<A HREF=\"mailto:$email_auteur\">$nom_auteur</A>";
-				}
-				else {
-					$auteurs[] = "$nom_auteur";
-				}
-			}
-			if ($auteurs) $'.$nom_var.' = join($auteurs, ", ");
-			else $'.$nom_var.' = "";
-		}
-		';
-		break;
-
-	//
-	// Introduction (d'un article, d'une breve ou d'un message de forum)
-	//
-
-	case 'INTRODUCTION':
-		$code = 'calcul_introduction($pile_boucles[$id_instance]->type_requete,
-			$pile_boucles[$id_instance]->row[\'texte\'],
-			$pile_boucles[$id_instance]->row[\'chapo\'],
-			$pile_boucles[$id_instance]->row[\'descriptif\'])';
-		break;
-
-	//
-	// Divers types de champs
-	//
-
-	case 'URL_SITE_SPIP':
-		$code = "lire_meta('adresse_site')";
-		break;
-
-	case 'NOM_SITE_SPIP':
-		$code = "lire_meta('nom_site')";
-		break;
-
-	case 'EMAIL_WEBMASTER':
-		$code = "lire_meta('email_webmaster')";
-		break;
-
-	case 'CHARSET':
-		$code = "lire_meta('charset')";
-		break;
-
-	case 'LANG':
-		$code = "\$GLOBALS['spip_lang']";
-		break;
-
-	case 'LANG_LEFT':
-		$code = "lang_dir(\$GLOBALS['spip_lang'],'left','right')";
-		break;
-
-	case 'LANG_RIGHT':
-		$code = "lang_dir(\$GLOBALS['spip_lang'],'right','left')";
-		break;
-
-	case 'LANG_DIR':
-		$code = "lang_dir(\$GLOBALS['spip_lang'],'ltr','rtl')";
-		break;
-
-	case 'PUCE':
-		$code = '$GLOBALS["puce"]';
-		break;
-
-	case 'DATE':
-		// Uniquement hors-boucles, pour la date passee dans l'URL ou le contexte inclusion
-		$code = "\$contexte['date']";
-		break;
-
-	case 'DATE_NOUVEAUTES':
-		$milieu = "if (lire_meta('quoi_de_neuf') == 'oui' AND lire_meta('majnouv'))
-			\$$nom_var = normaliser_date(lire_meta('majnouv'));
-		else
-			\$$nom_var = \"'0000-00-00'\";
-		";
-		break;
-
-	case 'URL_ARTICLE':
-		$code = "url_var_recherche(generer_url_article(\$contexte['id_article']), \$contexte['activer_url_recherche'])";
-		break;
-
-	case 'URL_RUBRIQUE':
-		$code = "url_var_recherche(generer_url_rubrique(\$contexte['id_rubrique']), \$contexte['activer_url_recherche'])";
-		break;
-
-	case 'URL_BREVE':
-		$code = "url_var_recherche(generer_url_breve(\$contexte['id_breve']), \$contexte['activer_url_recherche'])";
-		break;
-
-	case 'URL_FORUM':
-		$code = "url_var_recherche(generer_url_forum(\$contexte['id_forum']), \$contexte['activer_url_recherche'])";
-		break;
-
-	case 'URL_MOT':
-		$code = "url_var_recherche(generer_url_mot(\$contexte['id_mot']), \$contexte['activer_url_recherche'])";
-		break;
+  global $table_primary, $table_des_tables; 
 
-	case 'URL_AUTEUR':
-		$code = "url_var_recherche(generer_url_auteur(\$contexte['id_auteur']), \$contexte['activer_url_recherche'])";
-		break;
-
-	case 'URL_DOCUMENT':
-		$code = "generer_url_document(\$contexte['id_document'])";
-		break;
-
-	case 'NOTES':
-		$milieu = '$'.$nom_var.' = $GLOBALS["les_notes"];
-			$GLOBALS["les_notes"] = "";
-			$GLOBALS["compt_note"] = 0;
-			$GLOBALS["marqueur_notes"] ++;
-			';
-		break;
-
-	case 'RECHERCHE':
-		$code = 'htmlspecialchars($GLOBALS["recherche"])';
-		break;
-
-	case 'COMPTEUR_BOUCLE':
-		$code = '$pile_boucles[$id_instance]->compteur_boucle';
-		break;
-
-	case 'TOTAL_BOUCLE':
-		$code = '$pile_boucles[$id_instance_cond]->total_boucle';
-		break;
-
-	case 'POPULARITE':
-		$code = 'ceil(min(100, 100 * $pile_boucles[$id_instance]->row[\'popularite\'] / max(1 , 0 + lire_meta(\'popularite_max\'))))';
-		break;
-
-	case 'POPULARITE_ABSOLUE':
-		$code = 'ceil($pile_boucles[$id_instance]->row[\'popularite\'])';
-		break;
-
-	case 'POPULARITE_SITE':
-		$code = 'ceil(lire_meta(\'popularite_total\'))';
-		break;
-
-	case 'POPULARITE_MAX':
-		$code = 'ceil(lire_meta(\'popularite_max\'))';
-		break;
-
-	case 'EXTRA':
-		$code = 'trim($pile_boucles[$id_instance]->row[\'extra\'])';
-		if ($fonctions) {
-			// Gerer la notation [(#EXTRA|isbn)]
-			include_ecrire("inc_extra.php3");
-			reset($fonctions);
-			list($key, $champ_extra) = each($fonctions);
-			$type_extra = $boucles[$id_boucle]->type_requete;
-			if (extra_champ_valide($type_extra, $champ_extra)) {
-				unset($fonctions[$key]);
-				$code = "extra($code, '".addslashes($champ_extra)."')";
-			}
-			// Appliquer les filtres definis par le webmestre
-			$filtres = extra_filtres($type_extra, $champ_extra);
-			if ($filtres) {
-				reset($filtres);
-				while (list(, $f) = each($filtres)) $code = "$f($code)";
-			}
-		}
-		break;
-
-	case 'EXPOSER':
-		$on = 'on';
-		$off='';
-		if ($fonctions) {
-			// Gerer la notation [(#EXPOSER|on,off)]
-			reset($fonctions);
-			list(, $onoff) = each($fonctions);
-			ereg("([^,]*)(,(.*))?", $onoff, $regs);
-			$on = addslashes($regs[1]);
-			$off = addslashes($regs[3]);
-
-			// autres filtres
-			$filtres=Array();
-			while (list(, $nom) = each($fonctions)) {
-				$filtres[] = $nom;
-			}
-			$fonctions = $filtres;
-		}
-		$id_on_off = $GLOBALS['tables_doublons'][$boucles[$id_boucle]->type_requete];
-		if ($id_on_off) 
-			$code = "(\$GLOBALS[contexte_inclus]['$id_on_off'] == \$contexte['$id_on_off']) ? '$on' : '$off'";
-		else 
-			$code = "'$off'";
-		break;
-
-	//
-	// Inserer directement un document dans le squelette
-	//
-	case 'EMBED_DOCUMENT':
-		if ($fonctions) $fonctions = join($fonctions, "|");
-		$milieu = "
-			include_ecrire('inc_documents.php3');
-			\$$nom_var = embed_document(\$contexte['id_document'], '$fonctions', false) ;
-		";
-		$fonctions = "";
-		break;
-
-
-	//
-	// Formulaire de recherche sur le site
-	//
-	case 'FORMULAIRE_RECHERCHE':
-		if ($fonctions) {
-			list(, $lien) = each($fonctions);	// le premier est un url
-			while (list(, $filtre) = each($fonctions)) {
-				$filtres[] = $filtre;			// les suivants sont des filtres
-			}
-			$fonctions = $filtres;
-		}
-		if (!$lien) $lien = 'recherche.php3';
-		$milieu = "
-		if (lire_meta('activer_moteur') != 'oui') {
-			\$$nom_var = '';
-		}
-		else {
-			\$rech = _T('info_rechercher');
-			\$$nom_var = \"
-				<form action='$lien' method='get' name='form_rech'>
-				<input type='text' id='formulaire_recherche' name='recherche' value=\\\"\$rech\\\" size='20' class='formrecherche'\";
-			\$$nom_var .= \"></form>\";
-		}
-		";
-		break;
-
-	//
-	// Formulaire d'inscription comme redacteur
-	// (dans inc-formulaires.php3)
-	case 'FORMULAIRE_INSCRIPTION':
-		$milieu = '
-		$request_uri = $GLOBALS["REQUEST_URI"];
-		$spip_lang = $GLOBALS["spip_lang"];
-		$accepter_inscriptions = lire_meta("accepter_inscriptions");
-		if ($accepter_inscriptions == "oui") {
-			$'.$nom_var.' = "<"."?php
-				include_local(\"inc-formulaires.php3\");
-				lang_select(\"$spip_lang\");
-				formulaire_inscription(\"redac\");
-				lang_dselect(); ?".">";
-		}
-		else {
-			$'.$nom_var.' = "";
-		}
-		';
-
-		break;
-
-	//
-	// Formulaire de changement de langue
-	case 'MENU_LANG':
-		$milieu = '
-		$'.$nom_var.' = "<"."?php
-			include_ecrire(\"inc_lang.php3\");
-			echo menu_langues(\"var_lang\", \$menu_lang);
-			?".">";
-		';
-
-		break;
-
-
-	//
-	// Formulaire de changement de langue / page de login
-	case 'MENU_LANG_ECRIRE':
-		$milieu = '
-		$'.$nom_var.' = "<"."?php
-			include_ecrire(\"inc_lang.php3\");
-			echo menu_langues(\"var_lang_ecrire\", \$menu_lang);
-			?".">";
-		';
-
-		break;
-
-
-	//
-	// Formulaire pour ecrire a l'auteur
-	//
-	case 'FORMULAIRE_ECRIRE_AUTEUR':
-
-		$milieu = '
-		if (email_valide($row[\'email\'])) {
-			$email = trim($row[\'email\']);
-			$spip_lang = $GLOBALS["spip_lang"];
-			$'.$nom_var.' = "<'.'?php
-				include (\'inc-formulaires.php3\');
-				lang_select(\"$spip_lang\");
-				formulaire_ecrire_auteur(".$row[\'id_auteur\'].",\'$email\');
-				lang_dselect();
-			?'.'>";
-		}
-		';
-
-		break;
-
-	//
-	// Formulaire de signature d'une petition
-	//
-	case 'FORMULAIRE_SIGNATURE':
-
-		$milieu = '
-		$spip_lang = $GLOBALS["spip_lang"];
-		$id_petition = $contexte["id_article"];
-
-		$query_petition = "SELECT id_article FROM spip_petitions WHERE id_article=$id_petition";
- 		$result_petition = spip_query($query_petition);
-
-		if ($row_petition = spip_fetch_array($result_petition)) {
-			include_local("inc-formulaires.php3");
-			$texte_formulaire = formulaire_signature($id_petition);
-			$'.$nom_var.' = "<div class=\'formulaire\'><a name=\'sp$id_petition\'></a>\n";
-			$'.$nom_var.' .= "<"."?php
-				if (\$GLOBALS[\'val_confirm\']) {
-					include_local(\'inc-formulaires.php3\');
-					lang_select(\'$spip_lang\');
-					reponse_confirmation($id_petition);
-					lang_dselect();
-				}
-				else if (\$GLOBALS[\'nom_email\'] AND \$GLOBALS[\'adresse_email\']) {
-					include_local(\'inc-formulaires.php3\');
-					lang_select(\'$spip_lang\');
-					reponse_signature($id_petition);
-					lang_dselect();
-				}
-				else {?".">".$texte_formulaire."<"."?php
-				}
-				?".">";
-			$'.$nom_var.' .= "</div>\n";
-		}
-		else {
-			$'.$nom_var.' = "";
-		}
-		';
-
-		break;
-
-	//
-	// Formulaire de referencement d'un site
-	//
-	case 'FORMULAIRE_SITE':
-
-		$milieu = '
-		$request_uri = $GLOBALS["REQUEST_URI"];
-		$proposer_sites = lire_meta("proposer_sites");
-		$spip_lang = $GLOBALS["spip_lang"];
-
-		if ($proposer_sites == "2") {
-			$'.$nom_var.' = "<"."?php
-				include_local(\"inc-formulaires.php3\");
-				lang_select(\"$spip_lang\");
-				formulaire_site($contexte[id_rubrique]);
-				lang_dselect();
-				?".">";
-		}
-		else {
-			$'.$nom_var.' = "";
-		}
-		';
-
-		break;
-
-	//
-	// Champ testant la presence d'une petition
-	//
-	case 'PETITION':
-		$milieu = '
-		$query_petition = "SELECT id_article FROM spip_petitions WHERE id_article=$contexte[id_article]";
-		$result_petition = spip_query($query_petition);
-		if (spip_num_rows($result_petition) > 0) $'.$nom_var.' = " ";
-		else $'.$nom_var.' = "";
-		';
-		break;
-
-	//
-	// Formulaire de reponse a un forum
-	//
-	case 'FORMULAIRE_FORUM':
-		$milieu = '
-		$spip_lang = $GLOBALS["spip_lang"];
-		$'.$nom_var.' = "<"."?php include_local(\'inc-forum.php3\'); lang_select(\'$spip_lang\'); ";
-		$'.$nom_var.' .= "';
-		switch ($boucles[$id_boucle]->type_requete) {
-		case "articles":
-			$milieu .= 'echo retour_forum(0, 0, $contexte[id_article], 0, 0); ';
-			break;
-
-		case "breves":
-			$milieu .= 'echo retour_forum(0, 0, 0, $contexte[id_breve], 0); ';
-			break;
-
-		case "forums":
-			$milieu .= 'echo retour_forum(0, $contexte[id_forum], 0, 0, 0); ';
-			break;
-
-		case "rubriques":
-			$milieu .= 'echo retour_forum($contexte[id_rubrique], 0, 0, 0, 0); ';
-			break;
-
-		case "syndication":
-			$milieu .= 'echo retour_forum(0, 0, 0, 0, $contexte[id_syndic]); ';
-			break;
-
-		default:
-			$milieu .= 'echo retour_forum(\'$contexte[id_rubrique]\', \'$contexte[id_forum]\', \'$contexte[id_article]\', \'$contexte[id_breve]\', \'$contexte[id_syndic]\'); ';
-			break;
-		}
-		$milieu .= '"; $'.$nom_var.' .= "lang_dselect(); ?".">";
-		';
-		break;
-
-	//
-	// Parametres d'appel du formulaire de reponse a un forum
-	//
-	case 'PARAMETRES_FORUM':
-		$milieu = '
-		$request_uri = $GLOBALS["REQUEST_URI"];
-		$http_get_vars = $GLOBALS["HTTP_GET_VARS"];
-		$forums_publics = lire_meta("forums_publics");
-		if (($contexte["accepter_forum"] == "" AND $forums_publics != "non") OR ($contexte["accepter_forum"] != "" AND $contexte["accepter_forum"] != "non")) {
-			$lien = substr($request_uri, strrpos($request_uri, "/") + 1);
-			if (!$lien_retour = $http_get_vars["retour"])
-				$lien_retour = $lien;
-			$lien_retour = rawurlencode($lien_retour);
-
-			switch ($pile_boucles[$id_instance]->type_requete) {
-			case "articles":
-				$'.$nom_var.' = "id_article=$contexte[id_article]";
-				break;
-
-			case "breves":
-				$'.$nom_var.' = "id_breve=$contexte[id_breve]";
-				break;
-
-			case "rubriques":
-				$'.$nom_var.' = "id_rubrique=$contexte[id_rubrique]";
-				break;
-
-			case "syndication":
-				$'.$nom_var.' = "id_syndic=$contexte[id_syndic]";
-				break;
-
-			case "forums":
-			default:
-				$liste_champs = array ("id_article","id_breve","id_rubrique","id_syndic","id_forum");
-				unset($element);
-				while (list(,$champ) = each ($liste_champs)) {
-					if ($contexte[$champ]) $element[] = "$champ=$contexte[$champ]";
-				}
-				if ($element) $'.$nom_var.' = join("&",$element);
-				break;
-
-			}
-			$'.$nom_var.' .= "&retour=$lien_retour";
-		}
-		else {
-			$'.$nom_var.' = "";
-		}
-		';
-		break;
-
-	//
-	// Debut et fin de surlignage auto des mots de la recherche
-	//
-	case 'DEBUT_SURLIGNE':
-		if ($flag_ob AND $flag_pcre) {
-			$milieu = '
-				$'.$nom_var.' = "<"."?php if (\$var_recherche) { \$mode_surligne = debut_surligne(\$var_recherche, \$mode_surligne); } ?".">";
-			';
-		}
-		break;
-	case 'FIN_SURLIGNE':
-		if ($flag_ob AND $flag_pcre) {
-			$milieu = '
-				$'.$nom_var.' = "<"."?php if (\$var_recherche) { \$mode_surligne = fin_surligne(\$var_recherche, \$mode_surligne); } ?".">";
-			';
-		}
-		break;
-
-	//
-	// Formulaires de login
-	//
-	case 'LOGIN_PRIVE':
-		$milieu = '
-			$'.$nom_var.' = "<"."?php include_local (\'inc-login.php3\');
-				login (\'\', \'prive\'); ?".">";
-			';
-		break;
-
-	case 'LOGIN_PUBLIC':
-		$lacible = '\$GLOBALS[\'clean_link\']';
-		if ($fonctions) {
-			$filtres = array();
-			while (list(, $nom) = each($fonctions))
-				$lacible = "new Link('".$nom."')";
-			$fonctions = $filtres;
-		}
-		$milieu = '
-			$'.$nom_var.' = "<"."?php include_local (\'inc-login.php3\');
-				\$cible = ' . $lacible . ';
-				login (\$cible, false); ?".">";
-			';
-		break;
-
-	case 'URL_LOGOUT':
-		if ($fonctions) {
-			$url = "&url=".$fonctions[0];
-			$fonctions = array();
-		} else {
-			$url = '&url=\'.urlencode(\$clean_link->getUrl()).\'';
-		}
-		$milieu = '
-			$'.$nom_var.' = "<"."?php
-				if (\$GLOBALS[\'auteur_session\'][\'login\']) {
-					echo \'spip_cookie.php3?logout_public=\'.\$GLOBALS[\'auteur_session\'][\'login\'].\'' . $url . '\';
-				} ?".">";
-			';
-		break;
-
-
-	//
-	// Boutons d'administration
-	//
-	case 'FORMULAIRE_ADMIN':
-		$milieu = '
-			$'.$nom_var.' = "<"."?php \$GLOBALS[\"flag_boutons_admin\"] = true;
-				if (\$GLOBALS[\"HTTP_COOKIE_VARS\"][\"spip_admin\"]) {
-					include_local(\"inc-admin.php3\");
-					afficher_boutons_admin();
-				} ?".">";
-		';
-		break;
-
-	default:
-		$milieu = '<blink>#'.$champs[$id_champ]->nom_champ.'</blink>'; // pour debugger les squelettes
-		$milieu = "	\$$nom_var = '$milieu';\n";
-		break;
-	} // switch
-
-	if (!$code) $code = "\$$nom_var";
-
-	$code = applique_filtres ($fonctions, $code);
-
-	if ($code != "\$$nom_var") $milieu .= "\t\$$nom_var = $code;\n";
-
-	return $milieu;
-}
-
-
-//
-// Generer le code PHP correspondant a une boucle
-//
-
-function calculer_boucle($id_boucle, $prefix_boucle)
-{
-	global $boucles;
-	global $tables_code_contexte, $tables_doublons;
-
-	$func = $prefix_boucle.$id_boucle;
-	$boucle = $boucles[$id_boucle];
-
-	//
-	// Ecrire le debut de la fonction
-	//
-
-	$texte .= "function $func".'($contexte) {
-	global $pile_boucles, $ptr_pile_boucles, $id_doublons, $rubriques_publiques;
+	$boucle = &$boucles[$id_boucle];
+	$type_boucle = $boucle->type_requete;
 
-	';
+ 	list($return,$corps) = $boucle->return;
 
-	//
-	// Recherche : recuperer les hash a partir de la chaine de recherche
-	//
-	if (strpos($boucle->requete, '$hash_recherche')) {
-		$texte .= '
-		global $recherche, $hash_recherche, $hash_recherche_strict;
-		$contexte[\'activer_url_recherche\'] = true;
-		if (!$hash_recherche)
-			list($hash_recherche, $hash_recherche_strict) = requete_hash($recherche);
-		';
-	} else
-		$texte .= '
-		$contexte[\'activer_url_recherche\'] = false;
-		';
-
-	if (ereg('\$date_redac[^_]', $boucle->requete)) {
-		$texte .= '$contexte[\'date_redac\'] = normaliser_date($contexte[\'date_redac\']);
-		';
-	}
-	if (ereg('\$date[^_]', $boucle->requete)) {
-		$texte .= '$contexte[\'date\'] = normaliser_date($contexte[\'date\']);
-		';
-	}
-
-	//
-	// Recuperation du contexte et creation de l'instance de boucle
-	//
+	// Boucle recursive : simplement appeler la boucle interieure
 
-	$texte .= '
-	if ($contexte) {
-		reset($contexte);
-		while (list($key, $val) = each($contexte)) $$key = addslashes($val);
+	if ($type_boucle == 'boucle')
+	  {
+	    return ("$corps\n\treturn  $return;");
 	}
 
-	$id_instance = $ptr_pile_boucles++;
-	$id_instance_cond = $id_instance;
-
-	$instance = new InstanceBoucle;
-
-	$instance->id_boucle = \''.$boucle->id_boucle.'\';
-	$instance->type_requete = \''.$boucle->type_requete.'\';
-	$instance->partie = \''.$boucle->partie.'\';
-	$instance->total_parties = \''.$boucle->total_parties.'\';
-
-	$instance->id_instance = $id_instance;
-
-	$pile_boucles[$id_instance] = $instance;
-
-	$retour = "";
-	';
-
-	//
-	// Preparation du code de fermeture
-	//
-
-	$code_fin = "
-	\$ptr_pile_boucles--;
-	return \$retour;\n}\n";
-
-	$type_boucle = $boucle->type_requete;
-	$requete = $boucle->requete;
-	$doublons = $boucle->doublons;
-	$partie = $boucle->partie;
-	$total_parties = $boucle->total_parties;
-	$lang_select = (!$GLOBALS['forcer_lang'] && $boucle->lang_select != "non") &&
+	$lang_select = (!$GLOBALS['forcer_lang'] && ($boucle->lang_select != "non")) &&
 		($type_boucle == 'articles' OR $type_boucle == 'rubriques'
 		OR $type_boucle == 'hierarchie' OR $type_boucle == 'breves');
+	
+	$flag_h = ($type_boucle == 'hierarchie');
+	$flag_parties = ($boucle->partie AND $boucle->total_parties);
+	$flag_cpt = $flag_parties || # pas '$compteur' a` cause du cas 0
+	  		strpos($corps,'compteur_boucle') ||
+	  		strpos($return,'compteur_boucle');
+	$primary_key = $table_primary[$type_boucle];
+
+	if ($primary_key) // sinon c'est une boucle hors Spip
+	  {
+	    // invalidation des caches si la boucle n'est pas vide
+	    if ($return == "''")
+	      $invalide = '';
+	    else
+	      {$id_table = $table_des_tables[$type_boucle]; 
+		$boucle->select[] = "$id_table.$primary_key";
+		$invalide = '
+		$Cache["' . $primary_key . '"][$PileRow[$SP]["'  .
+		  $primary_key . '"]]=1;';
+	      }
+	  }
+	$corps =
+	  ((!$flag_cpt) ? "" : "\n\t\t\$compteur_boucle++;") .
+	  ((!$flag_parties) ? "" : '
+		if	($compteur_boucle >= $debut_boucle AND 
+			 $compteur_boucle <= $fin_boucle) {') .
+	  (((!$lang_select)||($return == "''")) ? "" : ('
+		if ($x = $PileRow[$SP]["lang"]) $GLOBALS["spip_lang"] = $x;')) .
+	  $invalide .
+	  ((!$boucle->doublons) ? "" : 
+	   ("\n\t\t\$doublons .= ','. \$PileRow[\$SP]['" .
+	    $primary_key . "'];")).
+	  $corps .
+	  (($return == "''") ? "" :
+	   ((!$boucle->separateur) ? 
+	    ("\n\t\t" . '$t0 .= ' . $return . ";") :
+	    ("\n\t\t" . '$t1 = ' . $return . ";\n\t\t" .
+	     '$t0 .= (($t1 && $t0) ? \'' . $boucle->separateur .
+	     "' : '') . \$t1;"))).
+	  ((!$flag_parties) ? "" : "\t\t}\n");
 
-	//
-	// Boucle recursive : simplement appeler la boucle interieure
-	//
-	if ($type_boucle == 'boucle') {
-		$texte .= calculer_liste(array($boucles[$boucle->requete]), $prefix_boucle, $id_boucle);
-		$texte .= $code_fin;
-		return $texte;
-	}
-
-	//
-	// Boucle 'hierarchie' : preparation de la requete principale
-	//
-	else if ($type_boucle == 'hierarchie') {
-		$texte .= '
-		if ($id_article || $id_syndic) $hierarchie = construire_hierarchie($id_rubrique);
-		else $hierarchie = construire_hierarchie($id_parent);
-		if ($hierarchie) {
-			$hierarchie = explode("-", substr($hierarchie, 0, -1));
-			$hierarchie = join(",", $hierarchie);
-		}
-		else $hierarchie = "0";';
-
-		$deb_class = 0;
-		$fin_class = 10000;
-		if (ereg("([0-9]+),([0-9]*)", $boucle->requete, $match)) {
-			$deb_class = $match[1];
-			if ($match[2]) $fin_class = $match[2];
-		}
-		if ($doublons == "oui")
-			$requete = "SELECT *, FIELD(id_rubrique, \$hierarchie) AS _field FROM spip_rubriques WHERE id_rubrique IN (\$hierarchie) AND id_rubrique NOT IN (\$id_doublons[rubriques])";
-		else
-			$requete = "SELECT *, FIELD(id_rubrique, \$hierarchie) AS _field FROM spip_rubriques WHERE id_rubrique IN (\$hierarchie)";
-		$requete .= " ORDER BY _field LIMIT $deb_class,$fin_class";
-	}
-
-
-	//
-	// Pour les forums, ajouter le code de gestion du cache
-	// et de l'activation / desactivation par article
-	//
-	if ($type_boucle == 'forums') {
-		$texte .= '
-		global $fichier_cache, $requetes_cache;
-		if (!$id_rubrique AND !$id_article AND !$id_breve AND $id_forum)
-			$my_id_forum = $id_forum;
-		else
-			$my_id_forum = 0;
-		if (!$id_article) $id_article = 0;
-		if (!$id_rubrique) $id_rubrique = 0;
-		if (!$id_breve) $id_breve = 0;
-		$valeurs = "$id_article, $id_rubrique, $id_breve, $my_id_forum, \'$fichier_cache\'";
-		if (!$requetes_cache[$valeurs]) {
-			$query_cache = "INSERT IGNORE INTO spip_forum_cache (id_article, id_rubrique, id_breve, id_forum, fichier) VALUES ($valeurs)";
-			spip_query($query_cache);
-			$requetes_cache[$valeurs] = 1;
-		}
-		';
-
-	} // forums
-
-
-
-	//
-	// Ecrire le code d'envoi de la requete, de recuperation du nombre
-	// de resultats et de traitement des boucles par parties (e.g. 1/2)
-	//
-
-	$texte .= '	$query = "'.$requete.'";
-	$result = @spip_query($query);
-	if (!$result) {
-		$GLOBALS["delais"]=0;
-		include_local("inc-debug-squel.php3");
-		return erreur_requete_boucle($query, $instance->id_boucle);
-	}
-	$total_boucle = @spip_num_rows($result);';
+	// Recherche : recuperer les hash a partir de la chaine de recherche
 
-	if ($partie AND $total_parties) {
-		$flag_parties = true;
-		$texte .= '
-		$debut_boucle = floor(($total_boucle * ($instance->partie - 1) + $instance->total_parties - 1) / $instance->total_parties) + 1;
-		$fin_boucle = floor(($total_boucle * ($instance->partie) + $instance->total_parties - 1) / $instance->total_parties);
-		$pile_boucles[$id_instance]->total_boucle = $fin_boucle - $debut_boucle + 1;';
+	if ($boucle->hash) {
+		$texte =  '
+		global $recherche, $hash_recherche, $hash_recherche_strict;
+		list($hash_recherche, $hash_recherche_strict) = requete_hash($recherche);';
 	}
-	else {
-		$flag_parties = false;
-		$texte .= '
-		$pile_boucles[$id_instance]->total_boucle = $total_boucle;';
+	else { $texte = ''; }
+
+	if ($flag_h) {
+	    $texte .= '
+	$hierarchie = ' . ($boucle->tout ?  $boucle->tout : 
+			   // sinon,  parame`tre passe' par include.
+			   // me^me code, mais a` inexe'cutable a` la compilation:
+			   '(($PileRow[0]["id_article"] ||
+	      $PileRow[0]["id_syndic"]) ?
+	    $PileRow[0]["id_rubrique"] :
+	    $PileRow[0]["id_parent"])') .
+	      ';
+	$h0 = "";
+	while ($hierarchie) {';
 	}
 
-	$texte_debut .= '
-	$pile_boucles[$id_instance]->compteur_boucle = 0;
-	$compteur_boucle = 0;';
-
-	//
-	// Ecrire le code de recuperation des resultats
-	//
-
-	if ($lang_select)
-		$texte_debut .= "\n\t\$old_lang = \$GLOBALS['spip_lang'];\n";
-	$texte_debut .= '
-	while ($row = @spip_fetch_array($result)) {';
-
-	if ($flag_parties) {
-		$texte_debut .= '
-		$compteur_boucle++;
-		if ($compteur_boucle >= $debut_boucle AND $compteur_boucle <= $fin_boucle) {';
-	}
-	$texte_debut .= '
-		$pile_boucles[$id_instance]->compteur_boucle++;
-		$pile_boucles[$id_instance]->row = $row;';
-	if ($boucle->separateur)
-		$texte_debut .= '
-		if ($retour) $retour .= \''.$boucle->separateur."';";
-	if ($lang_select)
-		$texte_debut .= '
-		if ($row["lang"]) {
-			$GLOBALS["spip_lang"] = $row["lang"];
-			$contexte["lang"] = $row["lang"];
-		}';
-
-	// Traitement different selon le type de boucle
-	$texte_debut .= $tables_code_contexte[$type_boucle];
-	if ($doublons == "oui")
-		$texte_debut .= "\n\t\t\$id_doublons['$type_boucle'] .= ','.\$row['".$tables_doublons[$type_boucle]."'];";
-
-	// Inclusion du code correspondant a l'interieur de la boucle
-	$texte_liste = calculer_liste($boucle->milieu, $prefix_boucle, $id_boucle);
-
-	// On n'ecrit la boucle "while" que si elle contient du code utile,
-	// sinon on utlise plutot spip_num_rows() pour recuperer le nombre d'iterations
-	if ($texte_liste OR $doublons == 'oui') {
-		$texte .= $texte_debut . $texte_liste;
-
-		if ($flag_parties) {
-			$texte .= "\n\t\t}\n";
-		}
-
-		// Fermeture de la boucle spip_fetch_array et liberation des resultats
-		$texte .= "\n\t}\n\t@spip_free_result(\$result);\n";
-		if ($lang_select)
-			$texte .= '	$GLOBALS["spip_lang"] = $old_lang;'."\n";
-	}
-	else {
-		$texte .= '	$pile_boucles[$id_instance]->compteur_boucle = $pile_boucles[$id_instance]->total_boucle;'."\n";
-	}
-	$texte .= $code_fin;
-	return $texte;
+	if (!($corps || $boucle->numrows))
+	  return 'return "";';
+	else
+	return  ($texte . '
+	$result = ' . calculer_requete(&$boucle) . ';
+	$t0 = "";
+	$SP++;' .
+		 (($flag_parties) ? 
+		  calculer_parties($boucle->partie,
+				   $boucle->mode_partie,
+				   $boucle->total_parties) :
+		  ((!$boucle->numrows) ? '' : '
+	$PileNum[$SP] = @spip_num_rows($result);')) .
+		 ((!$flag_cpt) ? '' : "\n\t\$compteur_boucle = 0;") .
+		 ((!$corps) ? "" :
+		  (
+		   ((!$lang_select) ? "" : '
+	$old_lang = $GLOBALS[\'spip_lang\'];') . '
+	while ($PileRow[$SP] = @spip_fetch_array($result)) {' .
+		((!$flag_h) ? "" : '
+		 $hierarchie = $PileRow[$SP][id_parent];') .
+		$corps .
+		"\n\t}" .
+		((!$lang_select) ? "" : '
+	$GLOBALS["spip_lang"] = $old_lang;'))) . '
+	@spip_free_result($result);' .
+		 (!($flag_h) ? '
+	return $t0;' : ('
+	$h0 = $t0 .' .
+		   ((!$boucle->separateur) ? "" :
+		    ('(($h0 && $t0) ? \'' . $boucle->separateur . "' : '') .")) .
+		   ' $h0;}
+	return $h0;')));
 }
 
 
-//
-// Generer le code PHP correspondant a un texte brut
-//
+// une grosse fonction pour un petit cas
 
-function calculer_texte($texte)
+function calculer_parties($partie, $mode_partie, $total_parties)
 {
-	global $dossier_squelettes;
-	$dossier = ($dossier_squelettes ? $dossier_squelettes.'/' : '');
-	$code = "";
-
-	$texte = ereg_replace("([\\\\'])", "\\\\1", $texte);
-
-	//
-	// Parties textuelles du squelette
-	//
-
-	// bloc multi
-	if (eregi('<multi>', $texte)) {
-		$ouvre_multi = 'extraire_multi(';
-		$ferme_multi = ')';
-	} else {
-		$ouvre_multi = $ferme_multi = '';
-	}
-
-
-	// Reperer les balises de traduction <:toto:>
-	while (eregi("<:(([a-z0-9_]+):)?([a-z0-9_]+)(\|[^>]*)?:>", $texte, $match)) {
-		$chaine = strtolower($match[3]);
-		if (!($module = $match[2]))
-			$module = 'local/public/spip';	// ordre des modules a explorer
-		$remplace = "_T('$module:$chaine')";
-		if ($filtres = $match[4]) {
-			$filtres = explode('|',substr($filtres,1));
-			$remplace = applique_filtres($filtres, $remplace);
-		}
-		$texte = str_replace($match[0], "'$ferme_multi.$remplace.$ouvre_multi'", $texte);
-	}
-
-
-	//
-	// Reperer les directives d'inclusion de squelette <INCLURE>
-	//
-	while (ereg("(<INCLU[DR]E[[:space:]]*\(([-_0-9a-zA-Z./ ]+)\)(([[:space:]]*\{[^}]*\})*)[[:space:]]*>)", $texte, $match)) {
-		$s = $match[0];
-		$p = strpos($texte, $s);
-		$debut = substr($texte, 0, $p);
-		$texte = substr($texte, $p + strlen($s));
-		if ($debut)
-			$code .= "	\$retour .= $ouvre_multi'$debut'$ferme_multi;\n";
-
-		//
-		// Traiter la directive d'inclusion
-		//
-		$fichier = $match[2];
-		ereg('^\\{(.*)\\}$', trim($match[3]), $params);
-		$code .= "	\$retour .= '<"."?php ';\n";
-		$code .= "	\$retour .= '\$contexte_inclus = \'\'; ';\n";
-
-		if ($params) {
-			// Traiter chaque parametre de contexte
-			$params = split("\}[[:space:]]*\{", $params[1]);
-			reset($params);
-			while (list(, $param) = each($params)) {
-				if (ereg("^([_0-9a-zA-Z]+)[[:space:]]*(=[[:space:]]*([^}]+))?$", $param, $args)) {
-					$var = $args[1];
-					$val = $args[3];
-
-					// cas de la langue
-					if ($var == 'lang') {
-						$lang_inclus = "\\'".addslashes($val)."\\'";
-						if (! $val)
-							$val = $lang_inclus = '$GLOBALS[spip_lang]';
-						$code .= "	\$retour .= '\$contexte_inclus[$var] = $val; ';\n";
-					}
-					else if ($val)
-						$code .= "	\$retour .= '\$contexte_inclus[$var] = \'".addslashes($val)."\'; ';\n";
-					else
-						$code .= "	\$retour .= '\$contexte_inclus[$var] = \''.addslashes(\$contexte[$var]).'\'; ';\n";
-				}
-			}
-		}
-
-		if (!$lang_inclus) $lang_inclus = 'lire_meta(\\\'langue_site\\\')';
-		$code .= "	\$retour .= 'include_ecrire(\'inc_lang.php3\'); lang_select($lang_inclus);';\n";
-
-		// inclure en priorite dans le dossier_squelettes
-		if ($dossier_squelettes) {
-			$code .= "	\$retour .= '
-			if (@file_exists(\'$dossier_squelettes/$fichier\')){
-				include(\'$dossier_squelettes/$fichier\');
-			} else {
-				include(\'$fichier\');
-			}';\n";
-		} else
-			$code .= "	\$retour .= 'include(\'$fichier\');';\n";
-
-		$code .= "	\$retour .= 'lang_dselect(); ?".">';\n";
-	}
-
-	if ($texte)
-		$code .= "	\$retour .= $ouvre_multi'$texte'$ferme_multi;\n";
-
-	return $code;
+     return ('
+	$fin_boucle = @spip_num_rows($result);' .
+		 (($mode_partie == '/') ?
+		  ('
+	$debut_boucle = 1+floor(($fin_boucle * ' . 
+		   ($partie - 1) .
+		   ' + ' .
+		   ($total_parties - 1) .
+		   ')/' .
+		   $total_parties .
+		   ");\n\t" .
+		   '$fin_boucle = floor(($fin_boucle * ' .
+		   $partie .
+		   ' + ' .
+		   ($total_parties - 1) .
+		   ')/' .
+		   $total_parties .
+		   ");") :
+		  (($mode_partie == '+') ?
+		   ('
+	$debut_boucle = ' . $partie . ';
+	$fin_boucle -= ' . 
+		   $total_parties) :
+		   ('
+	$debut_boucle = $fin_boucle - ' . $partie . ';
+	$fin_boucle -= ' . 
+		    ($partie - $total_parties)) .
+		   ';'))  . '
+	$PileNum[$SP] = $fin_boucle - $debut_boucle + 1;');
 }
 
 
-//
-// Generer le code PHP correspondant a une liste d'objets syntaxiques
-//
+# Production du code PHP a` partir de la se'quence livre'e par le phraseur
+# $boucles est passe' par re'fe'rence pour affectation par index_pile.
+# Retourne un tableau de 2 e'le'ments: 
+# 1. une expression PHP,
+# 2. une suite d'instructions PHP a` exe'cuter avant d'e'valuer l'expression.
+# si cette suite est vide, on fusionne les se'quences d'expression
+# ce qui doit re'duire la me'moire ne'cessaire au processus
+# En de'coule une combinatoire laborieuse mais sans difficulte'
 
-function calculer_liste($tableau, $prefix_boucle, $id_boucle)
+function calculer_liste($tableau, $prefix, $id_boucle, $niv, $rec, &$boucles, $id_mere)
 {
-	global $boucles;
-	global $champs;
-	global $nb_milieu;
-
+	if (!$tableau) return array("''",'');
 	$texte = '';
-	if (!$tableau) return $texte;
-
+	$exp = "";
+	$process_ins = false;
+	$firstset = true;
+	$t = '$t' . ($niv+1);
 	reset($tableau);
 	while (list(, $objet) = each($tableau)) {
-		$milieu = '';
-		switch($objet->type) {
-
-		/////////////////////
-		// Texte
-		//
-		case 'texte':
-			$texte .= calculer_texte($objet->texte);
-			break;
-
-
-		/////////////////////
-		// Boucle
-		//
-		case 'boucle':
-			$nb_milieu++;
-			$nom_var = "milieu$nb_milieu";
-			$nom_func = $prefix_boucle.$objet->id_boucle;
-			if ($objet->cond_avant || $objet->cond_apres || $objet->cond_altern) {
-				$texte .= "	\$$nom_var = $nom_func(\$contexte);\n";
-				$texte .= "	if (\$$nom_var) {\n";
-				if ($s = $objet->cond_avant) {
-					$texte .= calculer_liste($s, $prefix_boucle, $id_boucle);
-				}
-				$texte .= "	\$retour .= \$$nom_var;\n";
-				if ($s = $objet->cond_apres) {
-					$texte2 = calculer_liste($s, $prefix_boucle, $id_boucle);
-					if (strpos($texte2, '$id_instance_cond')) {
-						$texte .= "	\$id_instance_cond++;\n";
-						$texte .= $texte2;
-						$texte .= "	\$id_instance_cond--;\n";
-					}
-					else $texte .= $texte2;
-				}
-				$texte .= "	}\n";
-				if ($s = $objet->cond_altern) {
-					$texte .= "	else {\n";
-					$texte2 = calculer_liste($s, $prefix_boucle, $id_boucle);
-					if (strpos($texte2, '$id_instance_cond')) {
-						$texte .= "	\$id_instance_cond++;\n";
-						$texte .= $texte2;
-						$texte .= "	\$id_instance_cond--;\n";
-					}
-					else $texte .= $texte2;
-					$texte .= "	}\n";
-				}
-			}
-			else {
-				$texte .= "	\$retour .= $nom_func(\$contexte);\n";
-			}
-			$nb_milieu--;
-
-			break;
-
-
-		/////////////////////
-		// Champ
-		//
-		case 'champ':
-			$nb_milieu++;
-			if ($objet->cond_avant || $objet->cond_apres) {
-				$nom_var = "milieu$nb_milieu";
-				$texte .= calculer_champ($objet->id_champ, $id_boucle, $nom_var);
-
-				$texte .= "	if (\$$nom_var) {\n";
-				if ($s = $objet->cond_avant) {
-					$texte .= calculer_liste($s, $prefix_boucle, $id_boucle);
-				}
-				$texte .= "	\$retour .= \$$nom_var;\n";
-				if ($s = $objet->cond_apres) {
-					$texte .= calculer_liste($s, $prefix_boucle, $id_boucle);
-				}
-				$texte .= "	}\n";
-			}
-			else {
-				$nom_var = "milieu$nb_milieu";
-				$texte2 = calculer_champ($objet->id_champ, $id_boucle, $nom_var);
-				$c = count(explode("\$$nom_var", $texte2));
-				if ($c <= 2) {
-					$texte2 = str_replace("\$$nom_var = ", "\$retour .= ", $texte2);
-					$texte .= $texte2;
-				}
-				else {
-					$texte .= $texte2;
-					$texte .= "	\$retour .= \$$nom_var;\n";
-				}
-			}
-			$nb_milieu--;
-			break;
-
-		} // switch
-
+	  if ($objet->type == 'texte') {
+	    $c = calculer_texte($objet->texte,$id_boucle, &$boucles, $id_mere);
+	    if (!$exp)
+	      $exp = $c;
+	    else 
+	      {if ((substr($exp,-1)=="'") && (substr($c,1,1)=="'")) 
+		  $exp = substr($exp,0,-1) . substr($c,2);
+		else
+		  $exp .= (!$exp ? $c :  (" .\n\t\t$c"));}
+	    if (!(strpos($c,'<?') === false)) $pi = true;
+	  } else {
+	  if ($objet->type == 'include') {
+	    $c = calculer_inclure($objet->fichier,$objet->params,
+				  $id_boucle,
+				  &$boucles,
+				  $pi);
+	    $exp .= (!$exp ? $c : (" .\n\t\t$c"));
+	  } else {
+	    if ($objet->type ==  'boucle') {
+		$nom = $objet->id_boucle;
+		list($bc,$bm) = calculer_liste($objet->cond_avant, $prefix,
+					       $objet->id_boucle, $niv+2,$rec, &$boucles, $id_mere);
+		list($ac,$am) = calculer_liste($objet->cond_apres, $prefix,
+					       $objet->id_boucle, $niv+2,$rec, &$boucles, $id_mere);
+		list($oc,$om) = calculer_liste($objet->cond_altern, $prefix,
+					       $objet->id_boucle, $niv+1,$rec, &$boucles, $id_mere);
+
+	      // on transmet avec & pour e'viter la recopie
+	      // et re'cupe'rer les affectations (Total_boucles & Cache)
+	      
+	      $c = $prefix .
+		ereg_replace("-","_", $nom) .
+		'(&$Cache, &$PileRow, &$PileNum, $SP' .
+		(!($rec || ( $objet->type_requete ==  'boucle')) ? ", true" : ', $inidoublon') . ')';
+	      $m = "";
+	    } else {
+		list($c,$m) = 
+		  calculer_champ($objet->fonctions, 
+				 $objet->nom_champ,
+				 $id_boucle,
+				 &$boucles,
+				 $id_mere);
+		list($bc,$bm) = calculer_liste($objet->cond_avant, $prefix, $id_boucle, $niv+2,false, &$boucles, $id_mere); 
+	      	list($ac,$am) = calculer_liste($objet->cond_apres, $prefix, $id_boucle, $niv+2,false, &$boucles, $id_mere);
+		$oc = "''";
+		$om = "";
+	    }
+	    // traitement commun des champs et boucles.
+	    // Produit:
+	    // m ; if (Tniv+1 = v)
+	    // { bm; Tniv+1 = $bc . Tniv+1; am; Tniv+1 .= $ac }
+	    // else { om; $Tniv+1 = $oc }
+	    // Tniv .= Tniv+1
+	    // Optimisations si une au moins des 4 se'quences $*m  est vide
+
+	    if ($m) {
+	      // il faut achever le traitement de l'exp pre'ce'dente
+	      if ($exp) {
+		  $texte .= "\n\t\t\$t$niv " .
+		    (($firstset) ? "=" : ".=") .
+		    "$exp;$m" ;
+		  $firstset = false;
+		  $exp = "";
+	      } else { $texte .= $m;}
+	    }
+	    if (!($bm || $am || $om)) {
+	      // 3 se'quences vides: 'if' inutile
+	      $a = (($bc == "''") ?  "" : "$bc .") .
+		$t .
+		(($ac == "''") ?  "" : " . $ac");
+	      // s'il y a un avant ou un apre`s ou un alternant, il faut '?'
+	      if (($a != $t) || ($oc != "''"))
+		$c = "(($t = $c) ? ($a) : ($oc))";
+	      $exp .= (!$exp ? $c : (" .\n\t\t$c"));
+	    } else {
+	      // il faut achever le traitement de l'exp pre'ce'dente
+	      if ($exp) {
+		  $texte .= "\n\t\t\$t$niv " .
+		    (($firstset) ? "=" : ".=") .
+		    "$exp;$m" ;
+		  $firstset = false;
+		  $exp = "";
+	      } else { $texte .= $m;}
+	      $texte .= "\n\t\tif ($t = $c) {\n" . $bm;
+	      $texte .= "\n\t\t$t = $bc . $t";
+	      if (!$am) {
+		$texte .= " . $ac";
+	      } else $texte .= "; $am $t .=  $ac";
+	      $texte .= ";}";
+	      if (!$om)
+		{ $texte .= " else {" . $om . "$t =  $oc;}"; }
+	      $exp = $t;
+	    }
+	  }
+	  }
 	} // while
-
-	return $texte;
+	if (!$exp) $exp ="''";
+	return  (!$texte ? array ($exp, "") : 
+		 array('$t'.$niv. ". $exp",$texte));
 }
 
+# Prend en argument le source d'un squelette, sa grammaire et un nom.
+# Retourne une fonction PHP/SQL portant ce nom et calculant une page HTML.
+# Pour appeler la fonction produite, lui fournir 2 tableaux de 1 e'le'ment:
+# -1er: e'le'ment 'cache' => nom (du fichier ou` mettre la page)
+# -2e: e'lement 0 contenant un environnement ('id_article => $id_article, etc)
+# Elle retourne alors un tableau de 3 e'le'ments:
+# - 'texte' => page HTML, application du squelette a` l'environnement;
+# - 'process_ins' => 'html' ou 'php' selon la pre'sence de PHP dynamique
+# - 'invalideurs' =>  de'pendances de cette page, pour invalider son cache.
+# (voir son utilisation, optionnelle, dans invalideur.php)
+
+function calculer_squelette($squelette, $nom, $gram) {
+
+# Phraser le squelette, selon sa grammaire
+# pour le moment: "html" seul connu (HTML+balises BOUCLE)
+  $boucles = '';
+  include_local("inc-$gram-squel.php3");
+  $racine = parser($squelette, '',&$boucles);
+
+  // Traduction des se'quences syntaxique des boucles 
+
+  if ($boucles)
+    {
+      foreach($boucles as $id => $boucle)
+	{ 
+	  if ($boucle->type_requete == 'boucle')
+	    {
+	      $boucles[$id]->return =
+		calculer_liste(array($boucles[$boucle->param]),
+			       $nom,
+			       $boucle->param,
+			       1,
+			       true,
+			       &$boucles,
+			       $id);
+	    }
+	} 
+      foreach($boucles as $id => $boucle)
+	{ 
+	  if ($boucle->type_requete != 'boucle') 
+	    {
+#	  spip_log("calcul_liste $id de type" . $boucle->type_requete);
+	  calculer_params($boucle->type_requete, $boucle->param, $id, &$boucles);
+
+	  $boucles[$id]->return =
+	    calculer_liste($boucle->milieu,
+			   $nom,
+			   $id,
+			   1,
+			   false,
+			   &$boucles,
+			   $id);
+	    }
+	}
+    }
 
-//
-// Calculer le squelette : i.e. generer le fichier PHP correspondant
-//
-
-function calculer_squelette($squelette, $fichier) {
-	global $racine;
-	global $boucles;
-
-	$boucles = '';
-	$racine = '';
+  // idem pour la racine
 
-	$html = join(file("$squelette.html"), "");
-	parser($html);
+  list($return,$corps) =
+    calculer_liste($racine, $nom, '',0, false, &$boucles, '');
 
-	$squelette_nom = ereg_replace("[^a-zA-Z0-9_]", "_", $squelette);
-	$func = 'squelette_'.$squelette_nom.'_executer';
-	$prefix = $func.'_boucle';
-	$define = strtoupper("_SKEL_$squelette_nom");
+  // Corps de toutes les fonctions PHP,
+  // en particulier les requetes SQL et TOTAL_BOUCLE
+  // de'terminables seulement maintenant
+  // Les 3 premiers parame`tres sont passe's par re'fe'rences
+  // (sorte d'environnement a` la Lisp 1.5)
+  // sauf pour la fonction principale qui recoit les initialisations
 
-	// Debut du fichier
-	$texte .= "<"."?php\n\n";
-	$texte .= "\$func_squelette_executer = '$func';\n\n";
-	$texte .= "if (defined(\"$define\")) return;\n";
-	$texte .= "define(\"$define\", \"1\");\n\n\n";
+  $code = '';
 
-	// Calculer le code PHP des boucles
-	if ($boucles) {
-		reset($boucles);
-		while (list($id_boucle, ) = each($boucles)) {
-			$texte .= calculer_boucle($id_boucle, $prefix);
-			$texte .= "\n\n";
-		}
+  if ($boucles)
+    {
+      foreach($boucles as $id => $boucle)
+	{
+	  $boucles[$id]->return = calculer_boucle($id, &$boucles); 
 	}
-
-	// Calculer le code PHP de la racine
-	$texte .= "function $func(\$contexte) {\n";
-	$texte .= " global \$pile_boucles, \$id_instance_cond;\n \$pile_boucles = Array();\n \$id_instance_cond = -1;\n"; // pour #TOTAL_BOUCLE
-	$texte .= calculer_liste($racine, $prefix, '');
-	$texte .= "	return \$retour;\n";
-	$texte .= "}\n\n";
-
-	// Fin du fichier
-	$texte .= '?'.'>';
-
-	$f = fopen($fichier, "wb");
-	fwrite($f, $texte);
-	fclose($f);
+      
+      foreach($boucles as $id => $boucle) 
+	{
+	  $code .= "\n\nfunction $nom" . ereg_replace("-","_",$id) .
+		'(&$Cache, &$PileRow, &$PileNum, $SP, $inidoublon="") {' .
+	    (!$boucle->doublons ? '' : '
+		static $doublons; 
+		if ($inidoublon) $doublons = "0";') . 
+	    $boucle->return .
+	    "\n}\n";
+	}
+    }
+  return $code . '
+function ' . $nom . '($Cache, $PileRow, $PileNum="", $SP=0, $inidoublon="")
+ {
+' .
+    $corps . "\n \$t0 = " . $return . ';
+    $Cache["squelette"]= "' . $nom . '";
+    return array("texte" => $t0,
+	       "process_ins" =>	((strpos($t0,\'<?\')=== false) ? \'html\' : \'php\'),
+	       "invalideurs" => $Cache);' .
+    "\n}\n" ;
 }
-
-
 ?>
diff --git a/inc-calcul.php3 b/inc-calcul.php3
index a6f83aad0d..4586083902 100644
--- a/inc-calcul.php3
+++ b/inc-calcul.php3
@@ -1,532 +1,203 @@
 <?php
-
-//
 // Ce fichier ne sera execute qu'une fois
 if (defined("_INC_CALCUL")) return;
 define("_INC_CALCUL", "1");
 
+// ce fichier exe'cute un squelette.
 
-if (@file_exists("mes_fonctions.php3")) {
-	include_local ("mes_fonctions.php3");
-}
 
 include_ecrire("inc_index.php3");
 include_ecrire("inc_texte.php3");
 include_ecrire("inc_filtres.php3");
 include_ecrire("inc_lang.php3");
 include_ecrire("inc_documents.php3");
-
-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 (<IMG1>)
-
-include_local("inc-forum.php3");
-
-if (@file_exists("inc-urls.php3")) {
+if (file_exists("inc-urls.php3")) {
 	include_local ("inc-urls.php3");
 }
 else {
 	include_local ("inc-urls-dist.php3");
 }
 
+include("inc-calcul_mysql3.php");
+include("inc-calcul_html4.php");
+
+# Ce fichier peut contenir une affectation de $dossier_squelettes  indiquant
+# le re'pertoire 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 donne'e,
+# et l'applique sur un $contexte pour un certain $cache.
+# Retourne un tableau de 3 e'le'ments:
+# 'texte' => la page calcule'e
+# 'process_ins' => 'html' ou 'php' si pre'sence d'un '<?php'
+# 'invalideurs' => les invalideurs (cf inc-calcul-squel)
+
+# La recherche est assure'e par la fonction cherche_squelette
+# de'finie 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 de'finition de cette fonction.
+
+# L'exe'cution est pre'ce'de'e du chargement e'ventuel 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($fond, $cache, $contexte, $id_rubrique, $lang='') 
+{
+  global $dossier_squelettes;
+
+  $dir = "$dossier_squelettes/mon-chercher.php3";
+  include((file_exists($dir) ? $dir : "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));
+  if ($GLOBALS['xhtml']) {
+    include_ecrire("inc_tidy.php");
+    $page = xhtml($page);
+  }
+  $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;
+}
+
+function cherche_page_incluse($cache, $contexte)
+{
+  $contexte_inclus = $contexte['contexte'];
+  return cherche_page($contexte['fond'], 
+		      $cache,
+		      $contexte_inclus,
+		      $contexte_inclus['id_rubrique']);
+}
+
+function calculer_page_globale($cache, $fond, $recherche)
+ {
+   global $spip_lang;
+   $contexte = $GLOBALS['HTTP_GET_VARS'];
+   if ($GLOBALS['date'])
+    $contexte['date'] = $contexte['date_redac'] = normaliser_date($GLOBALS['date']);
+  else
+    $contexte['date'] = $contexte['date_redac'] = date("Y-m-d H:i:s");
+  
+   $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($fond, $cache, $contexte, $id_rubrique_fond, $spip_lang);
+  $texte = $page['texte'];
+
+  if ($recherche)
+    {
+      include_ecrire("inc_surligne.php3");
+      $texte = surligner_mots($texte, $recherche);
+    } 
+
+  return array('texte' => 
+	       (($page['process_ins'] || (!$signale_globals)) ? $texte :
+		('<'."?php $signale_globals ?".'>'.$texte)),
+	       'process_ins' => $page['process_ins'],
+	       'invalideurs' => $page['invalideurs']);
+}
+
+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) return '';
+    $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');
+	}
+    }
+  }
+  return calculer_page_globale($cache,
+			       $contexte['fond'],
+			       $contexte['recherche']);
+}
+
+# Fonctions appele'es par les squelettes (insertion dans le code trop lourde)
 
-
-//
-// Bidouille pour parametrer les liens (peu utilisee)
-//
-
-function transformer_lien_logo($contexte, $lien) {
-	$lien = ereg_replace("#ID_RUBRIQUE", $contexte['id_rubrique'], $lien);
-	$lien = ereg_replace("#ID_ARTICLE", $contexte['id_article'], $lien);
-	$lien = ereg_replace("#ID_SECTEUR", $contexte['id_secteur'], $lien);
-	$lien = ereg_replace("#ID_BREVE", $contexte['id_breve'], $lien);
-	$lien = ereg_replace("#ID_FORUM", $contexte['id_forum'], $lien);
-	$lien = ereg_replace("#ID_DOCUMENT", $contexte['id_document'], $lien);
-	$lien = ereg_replace("#ID_AUTEUR", $contexte['id_auteur'], $lien);
-	$lien = ereg_replace("#URL_ARTICLE", generer_url_article($contexte['id_article']), $lien);
-	$lien = ereg_replace("#URL_RUBRIQUE", generer_url_rubrique($contexte['id_rubrique']), $lien);
-	$lien = ereg_replace("#URL_SITE", $contexte['url_site'], $lien);
-	$lien = ereg_replace("#URL_SECTEUR", generer_url_rubrique($contexte['id_secteur']), $lien);
-	$lien = ereg_replace("#URL_BREVE", generer_url_breve($contexte['id_breve']), $lien);
-	$lien = ereg_replace("#URL_FORUM", generer_url_forum($contexte['id_forum']), $lien);
-	$lien = ereg_replace("#URL_DOCUMENT", generer_url_document($contexte['id_document']), $lien);
-	return $lien;
-}
-
-//
-// Ajouter le &var_recherche=toto dans les boucles de recherche
-//
-function url_var_recherche($url, $activer_url_recherche) {
-	include_ecrire('inc_surligne.php3');
-	if ($activer_url_recherche && $GLOBALS['HTTP_GET_VARS']['recherche'] && !ereg("var_recherche", $url)) {
-		if (ereg("^([^#]*)(#.*)$", $url, $regs)) {
-			$url = $regs[1];
-			$ancre = $regs[2];
-		} else
-			$ancre = '';
-		$url .= strpos($url, '?') ? '&' : '?';
-		$url .= "var_recherche=".urlencode(surligner_sans_accents($GLOBALS['recherche']));
-		$url .= $ancre;
-	}
-	return $url;
-}
+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
 
 //
 // Retrouver le logo d'un objet (et son survol)
 //
 
-function cherche_image_nommee($nom) {
-	$formats = array ('gif', 'jpg', 'png');
-	while (list(, $format) = each($formats))
-		if (@file_exists('IMG/'.$nom.'.'.$format))
-			return ($nom.'.'.$format);
-}
-
-function cherche_image($id_objet, $type_objet) {
+function cherche_image($id_objet, $type_objet, $flag_fichier) {
 	$image = array('', '');
-
+	$dossier = $GLOBALS['dossier_images'] . '/';
 	// cherche l'image liee a l'objet
-	$image[0] = cherche_image_nommee($type_objet.'on'.$id_objet);
+	$image[0] = cherche_image_nommee($type_objet.'on'.$id_objet,$dossier);
 
 	// cherche un survol
 	if ($image[0]) {
-		$image[1] = cherche_image_nommee($type_objet.'off'.$id_objet);
+	  $image[1] = cherche_image_nommee($type_objet.'off'.$id_objet,$dossier);
 	}
-
+	if ($flag_fichier)
+	  { 
+	    $image[0] = ereg_replace("^$dossier", '', $image[0]);
+	    $image[1] = ereg_replace("^$dossier", '', $image[1]);}
 	return $image;
 }
 
-function image_article($id_article){
-	return cherche_image($id_article,'art');
+function image_article($id_article, $dossier){
+  return cherche_image($id_article,'art', $dossier);
 }
 
-function image_auteur($id_auteur){
-	return cherche_image($id_auteur,'aut');
+function image_auteur($id_auteur, $dossier){
+  return cherche_image($id_auteur,'aut', $dossier);
 }
 
-function image_breve($id_breve){
-	return cherche_image($id_breve,'breve');
+function image_breve($id_breve, $dossier){
+  return cherche_image($id_breve,'breve', $dossier);
 }
 
-function image_site($id_syndic){
-	return cherche_image($id_syndic,'site');
+function image_site($id_syndic, $dossier){
+  return cherche_image($id_syndic,'site', $dossier);
 }
 
-function image_mot($id_mot){
-	return cherche_image($id_mot,'mot');
+function image_mot($id_mot, $dossier){
+  return cherche_image($id_mot,'mot', $dossier);
 }
 
-function image_rubrique($id_rubrique) {
+function image_rubrique($id_rubrique, $dossier) {
 	// Recherche recursive vers les rubriques parentes (y compris racine)
-	for (;;) {
-		$image = cherche_image($id_rubrique, 'rub');
-		if ($image[0]) break;
-		$result = spip_query("SELECT id_parent FROM spip_rubriques WHERE id_rubrique='$id_rubrique'");
-		if ($row = spip_fetch_array($result)) {
-			$id_rubrique = $row['id_parent'];
-		}
-		else break;
-	}
-
-	return $image;
-}
-
-function IMG_image($im) {
-	// ajoute les "IMG/" devant les noms des images trouvees
-	if ($im[0])
-		$im[0] = 'IMG/'.$im[0];
-	if ($im[1])
-		$im[1] = 'IMG/'.$im[1];
-	return $im;
-}
-
-
-// Renvoie le code html pour afficher le logo, avec ou sans survol, avec ou sans lien, etc.
-function affiche_logos($arton, $artoff, $lien, $align) {
-	global $num_survol;
-	global $espace_logos;
-
-	$num_survol++;
-	if ($arton) {
-		//$imgsize = @getimagesize("$arton");
-		//$taille_image = ereg_replace("\"","'",$imgsize[3]);
-		if ($align) $align="align='$align' ";
-
-		$milieu = "<img src='$arton' $align".
-			" name='image$num_survol' ".$taille_image." border='0' alt=''".
-			" hspace='$espace_logos' vspace='$espace_logos' class='spip_logos' />";
-
-		if ($artoff) {
-			if ($lien) {
-				$afflien = "<a href='$lien'";
-				$afflien2 = "a>";
-			}
-			else {
-				$afflien = "<div";
-				$afflien2 = "div>";
-			}
-			$milieu = "$afflien onMouseOver=\"image$num_survol.src=".
-				"'$artoff'\" onMouseOut=\"image$num_survol.src=".
-				"'$arton'\">$milieu</$afflien2";
-		}
-		else if ($lien) {
-			$milieu = "<a href='$lien'>$milieu</a>";
-		}
-	} else {
-		$milieu="";
-	}
-	return $milieu;
-}
-
-
-// Retourne la hierarchie d'une rubrique
-function construire_hierarchie($id_rubrique) {
-	$hierarchie = "";
-	$id_rubrique = intval($id_rubrique);
 	while ($id_rubrique) {
-		$hierarchie = $id_rubrique."-".$hierarchie;
-		$query = "SELECT a.id_parent AS ida, b.id_parent AS idb ".
-			"FROM spip_rubriques AS a LEFT JOIN spip_rubriques AS b ON (b.id_rubrique = a.id_parent) ".
-			"WHERE a.id_rubrique = $id_rubrique";
-		$result = spip_query($query);
-		if ($row = spip_fetch_array($result)) {
-			if ($id_parent = $row['ida']) $hierarchie = $id_parent."-".$hierarchie;
-			$id_grand_parent = $row['idb'];
-		}
-		else break;
-		$id_rubrique = $id_grand_parent;
-	}
-	return $hierarchie;
-}
-
-
-//
-// Critere {branche} : recuperer les descendants d'une rubrique
-//
-function calcul_generation ($generation) {
-	$lesfils = array();
-	$result = spip_query("SELECT id_rubrique FROM spip_rubriques WHERE id_parent IN ($generation)");
-	while ($row = spip_fetch_array($result))
-		$lesfils[] = $row['id_rubrique'];
-	return join(",",$lesfils);
-}
-function calcul_branche ($generation) {
-	if ($generation) {
-		$branche[] = $generation;
-		while ($generation = calcul_generation ($generation))
-			$branche[] = $generation;
-		return join(",",$branche);
-	} else
-		return '0';
-}
-
-//
-// fonction standard de calcul de la balise #INTRODUCTION
-// on peut la surcharger en definissant dans mes_fonctions.php3 :
-// function introduction($type,$texte,$descriptif) {...}
-//
-function calcul_introduction ($type, $texte, $chapo='', $descriptif='') {
-	if (function_exists("introduction"))
-		return introduction ($type, $texte, $chapo, $descriptif);
-
-	switch ($type) {
-		case 'articles':
-			if ($descriptif)
-				return propre($descriptif);
-			else if (substr($chapo, 0, 1) == '=')	// article virtuel
-				return '';
-			else
-				return PtoBR(propre(supprimer_tags(couper_intro($chapo."\n\n\n".$texte, 500))));
-			break;
-		case 'breves':
-			return PtoBR(propre(supprimer_tags(couper_intro($texte, 300))));
-			break;
-		case 'forums':
-			return PtoBR(propre(supprimer_tags(couper_intro($texte, 600))));
-			break;
-		case 'rubriques':
-			if ($descriptif)
-				return propre($descriptif);
-			else
-				return PtoBR(propre(supprimer_tags(couper_intro($texte, 600))));
-			break;
-	}
-}
-
-
-//////////////////////////////////////////////////////////////////////////////
-//
-//              Calcul de la page
-//
-//////////////////////////////////////////////////////////////////////////////
-
-
-//
-// Classe utilisee pour l'execution des boucles
-//
-
-class InstanceBoucle {
-	var $id_instance;
-
-	// Proprietes de la boucle
-	var $id_boucle;
-	var $type_requete;
-	var $partie, $total_parties;
-
-	// Stockage des resultats
-	var $row;
-	var $compteur_boucle, $total_boucle;
+	  $image = cherche_image($id_rubrique, 'rub', $dossier);
+	  if ($image[0]) return $image;
+	  $id_rubrique = query_parent($id_rubrique);
+	  }
+	return '';
 }
-
-
-//
-// Executer un squelette dans un contexte donne
-//
-
-function executer_squelette($squelette, $contexte) {
-	global $pile_boucles;
-	global $ptr_pile_boucles;
-	static $fonctions_squelettes = '';
-
-	$pile_boucles = '';
-	$ptr_pile_boucles = 0;
-
-	// Si squelette pas deja inclus, l'inclure
-	if (!$fonctions_squelettes[$squelette]) {
-		$squelette_cache = 'CACHE/skel_'.rawurlencode($squelette).'.php3';
-		$use_cache = false;
-		if (@file_exists($squelette_cache)) {
-			$t = filemtime($squelette_cache);
-			if (filemtime("$squelette.html") < $t
-			AND filemtime("inc-calcul-squel.php3") < $t
-			AND (!@file_exists("mes_fonctions.php3") OR filemtime("mes_fonctions.php3") < $t)
-			AND (!@file_exists("ecrire/mes_options.php3") OR filemtime("ecrire/mes_options.php3") < $t)) {
-				$use_cache = true;
-			}
-		}
-		if ($GLOBALS['recalcul_squelettes'] == 'oui') {
-			$use_cache = false;
-		}
-
-		// Au besoin, recompiler le squelette
-		if (!$use_cache) {
-			include_local ("inc-calcul-squel.php3");
-			calculer_squelette($squelette, $squelette_cache);
-		}
-
-		// L'inclusion du squelette permet de definir les fonctions associees
-		// aux boucles, et de recuperer le nom de la fonction principale
-		include($squelette_cache);
-
-		// Si le squelette compile est vide, pour une raison inconnue
-		// (plantage disque lors du calcul precedent), tenter un recalcul
-		if (!$func_squelette_executer) {
-			@unlink($squelette_cache);
-			spip_log ("ERREUR $squelette_cache est vide");
-			if ($use_cache) {
-				include_local ("inc-calcul-squel.php3");
-				calculer_squelette($squelette, $squelette_cache);
-				include($squelette_cache);
-			}
-		}
-		// fin du plantage squelette compile
-
-		$fonctions_squelettes[$squelette] = $func_squelette_executer;
-		if ($GLOBALS['flag_apc']) {
-			apc_rm($squelette_cache);
-		}
-	}
-
-	// Executer la fonction principale du squelette
-	// (i.e. racine de l'arbre d'execution)
-	$f = $fonctions_squelettes[$squelette];
-	return $f($contexte);
-}
-
-
-//
-// Recherche recursive du squelette
-//
-
-function chercher_squelette_hierarchie($fond, $id_rubrique, $dossier='') {
-	if (!$id_rubrique) {
-		if (@file_exists("$dossier$fond.html")) {
-			return "$dossier$fond";
-		} else if (@file_exists("$fond.html")) {
-			return "$fond";
-		} else if (@file_exists("$fond-dist.html")) {
-			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'=>"$dossier$fond"))."</P>";
-			install_fin_html();
-			spip_log ("ERREUR: aucun squelette $dossier$fond n'est disponible...");
-			exit;
-		}
-	}
-	else {
-		if (@file_exists("$dossier$fond-$id_rubrique.html")) {
-			return "$dossier$fond-$id_rubrique";
-		} else {
-			$query = "SELECT id_parent FROM spip_rubriques WHERE id_rubrique='$id_rubrique'";
-			$result = spip_query($query);
-			while($row = spip_fetch_array($result)) {
-				$id_parent=$row['id_parent'];
-			}
-			return chercher_squelette_hierarchie($fond, $id_parent, $dossier);
-		}
-	}
-}
-
-function chercher_squelette($fond, $id_rubrique, $lang='') {
-	global $dossier_squelettes;
-
-	// prendre en compte le bon repertoire (pas grave si on a deux / dans l'arborescence)
-	$dossier = ($dossier_squelettes ? $dossier_squelettes.'/' : '');
-
-	// On selectionne, dans l'ordre :
-	// fond=10.html, fond-10.html, fond-<rubriques parentes>.html, fond.html puis fond-dist.html
-	if (($id_rubrique > 0) AND (@file_exists("$dossier$fond=$id_rubrique.html"))) {
-		$squel = "$dossier$fond=$id_rubrique";
-	}
-	else {
-		// recursif le long de la hierarchie
-		$squel = chercher_squelette_hierarchie($fond, $id_rubrique, $dossier); 
-	}
-
-
-	// affiner par langue
-	if ($lang == '')
-		$lang = lire_meta('langue_site');
-
-	if (@file_exists("$squel.$lang.html"))
-		$squel = "$squel.$lang";
-
-	return $squel;
-}
-
-
-//
-// Calculer la page courante
-//
-
-function calculer_page($fond, $contexte) {
-	global $id_doublons;
-
-	static $pile_doublons = '';
-	static $n_doublons = 0;
-
-	$pile_doublons[++$n_doublons] = $id_doublons;
-
-	$id_doublons = '';
-	$id_doublons['articles'] = '0';
-	$id_doublons['rubriques'] = '0';
-	$id_doublons['breves'] = '0';
-	$id_doublons['auteurs'] = '0';
-	$id_doublons['forums'] = '0';
-	$id_doublons['signatures'] = '0';
-	$id_doublons['mots'] = '0';
-	$id_doublons['groupes_mots'] = '0';
-	$id_doublons['syndication'] = '0';
-	$id_doublons['documents'] = '0';
-
-	$texte = executer_squelette($fond, $contexte);
-
-	$id_doublons = $pile_doublons[$n_doublons--];
-
-	return $texte;
-}
-
-
-function calculer_page_globale($fond) {
-	global $contexte, $contexte_inclus;
-	global $fichier_requete;
-	global $id_rubrique_fond;
-	global $spip_lang;
-
-	// Generer le contexte
-	$contexte = '';
-	$contexte_defaut = 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');
-	reset($contexte_defaut);
-	while (list(, $val) = each($contexte_defaut)) {
-		if ($GLOBALS[$val]) {
-			$contexte[$val] = intval($GLOBALS[$val]);
-		}
-	}
-	if ($GLOBALS['date'])
-		$contexte['date'] = $contexte['date_redac'] = normaliser_date($GLOBALS['date']);
-	else
-		$contexte['date'] = $contexte['date_redac'] = date("Y-m-d H:i:s");
-
-	if ($GLOBALS['lang'])
-		$contexte['lang'] = $GLOBALS['lang'];
-
-	// Analyser les URLs personnalisees (inc-urls-...)
-	recuperer_parametres_url($fond, $fichier_requete);
-	$contexte_inclus = $contexte; // Par souci d'homogeneite (utile pour #EXPOSER)
-
-	//
-	// Affiner le choix du squelette :
-	// calcul de la rubrique associee a la requete
-	// + selection de la langue
-	//
-	$lang = lire_meta('langue_site');
-	if ($contexte['lang']) {
-		$lang = $contexte['lang'];	// l'URL peut fixer lang=xx, mais inc-urls peut aussi agir sur $contexte[lang]
-	}
-
-	// chercher la langue de l'objet et sa rubrique (pour article=3.html)
-	if ($id_rubrique = $contexte['id_rubrique']) {
-		$id_rubrique_fond = $id_rubrique;
-		if ($row = spip_fetch_array(spip_query("SELECT lang FROM spip_rubriques WHERE id_rubrique='$id_rubrique'")))
-			if ($row['lang']) $lang = $row['lang'];
-	}
-	else if ($id_breve  = $contexte['id_breve']) {
-		if ($row = spip_fetch_array(spip_query("SELECT id_rubrique FROM spip_breves WHERE id_breve='$id_breve'"))) {
-			$id_rubrique_fond = $row['id_rubrique'];
-			if ($row = spip_fetch_array(spip_query("SELECT lang FROM spip_rubriques WHERE id_rubrique='$id_rubrique_fond'")))
-				if ($row['lang']) $lang = $row['lang'];
-		}
-	}
-	else if ($id_syndic = $contexte['id_syndic']) {
-		if ($row = spip_fetch_array(spip_query("SELECT id_rubrique FROM spip_syndic WHERE id_syndic='$id_syndic'"))) {
-			$id_rubrique_fond = $row['id_rubrique'];
-			if ($row = spip_fetch_array(spip_query("SELECT lang FROM spip_rubriques WHERE id_rubrique='$id_rubrique_fond'")))
-				if ($row['lang']) $lang = $row['lang'];
-		}
-	}
-	else if ($id_article = $contexte['id_article']) {
-		if ($row = spip_fetch_array(spip_query("SELECT id_rubrique,lang FROM spip_articles WHERE id_article='$id_article'"))) {
-			$id_rubrique_fond = $row['id_rubrique'];
-			if ($row['lang']) $lang = $row['lang'];
-		}
-	}
-	else {
-		$id_rubrique_fond = 0;
-	}
-
-	if (!$GLOBALS['forcer_lang'])
-		lang_select($lang);
-
-	$fond = chercher_squelette($fond, $id_rubrique_fond, $spip_lang);
-
-
-	//
-	// Special stats et boutons admin
-	//
-	reset($contexte_defaut);
-	while (list($key, $val) = each($contexte_defaut)) {
-		if ($contexte[$val]) {
-			$GLOBALS[$val] = $contexte[$val];
-			$signale_globals .= "\n".'$GLOBALS[\''.$val.'\'] = '.intval($contexte[$val]).";";
-		}
-	}
-	$signale_globals = '<'."?php$signale_globals\n?".'>';
-
-	return $signale_globals.calculer_page($fond, $contexte);
-}
-
 ?>
diff --git a/inc-calcul_html4.php b/inc-calcul_html4.php
new file mode 100644
index 0000000000..6d979c4afb
--- /dev/null
+++ b/inc-calcul_html4.php
@@ -0,0 +1,143 @@
+<?php
+// Ce fichier ne sera execute qu'une fois
+if (defined("_CALCUL_HTML4")) return;
+define("_CALCUL_HTML4", "1");
+
+// Renvoie le code html pour afficher le logo, avec ou sans survol, avec ou sans lien, etc.
+function affiche_logos($arton, $artoff, $lien, $align) {
+	global $num_survol;
+	global $espace_logos;
+
+	$num_survol++;
+	if ($arton) {
+		//$imgsize = @getimagesize("$arton");
+		//$taille_image = ereg_replace("\"","'",$imgsize[3]);
+		if ($align) $align="align='$align' ";
+
+		$milieu = "<img src='$arton' $align".
+			" name='image$num_survol' ".$taille_image." border='0' alt=''".
+			" hspace='$espace_logos' vspace='$espace_logos' class='spip_logos' />";
+
+		if ($artoff) {
+			if ($lien) {
+				$afflien = "<a href='$lien'";
+				$afflien2 = "a>";
+			}
+			else {
+				$afflien = "<div";
+				$afflien2 = "div>";
+			}
+			$milieu = "$afflien onMouseOver=\"image$num_survol.src=".
+				"'$artoff'\" onMouseOut=\"image$num_survol.src=".
+				"'$arton'\">$milieu</$afflien2";
+		}
+		else if ($lien) {
+			$milieu = "<a href='$lien'>$milieu</a>";
+		}
+	} else {
+		$milieu="";
+	}
+	return $milieu;
+}
+
+
+
+//
+// Ajouter le &var_recherche=toto dans les boucles de recherche
+//
+function url_var_recherche($url) {
+	if ($GLOBALS['HTTP_GET_VARS']['recherche'] && !ereg("var_recherche", $url)) {
+		$url .= strpos($url, '?') ? '&' : '?';
+		$url .= "var_recherche=".urlencode($GLOBALS['recherche']);
+	}
+	return $url;
+}
+
+//
+// fonction standard de calcul de la balise #INTRODUCTION
+// on peut la surcharger en definissant dans mes_fonctions.php3 :
+// function introduction($type,$texte,$descriptif) {...}
+//
+function calcul_introduction ($type, $texte, $chapo='', $descriptif='') {
+	if (function_exists("introduction"))
+		return introduction ($type, $texte, $chapo, $descriptif);
+
+	switch ($type) {
+		case 'articles':
+			if ($descriptif)
+				return propre($descriptif);
+			else if (substr($chapo, 0, 1) == '=')	// article virtuel
+				return '';
+			else
+				return PtoBR(propre(supprimer_tags(couper_intro($chapo."\n\n\n".$texte, 500))));
+			break;
+		case 'breves':
+			return PtoBR(propre(supprimer_tags(couper_intro($texte, 300))));
+			break;
+		case 'forums':
+			return PtoBR(propre(supprimer_tags(couper_intro($texte, 600))));
+			break;
+		case 'rubriques':
+			if ($descriptif)
+				return propre($descriptif);
+			else
+				return PtoBR(propre(supprimer_tags(couper_intro($texte, 600))));
+			break;
+	}
+}
+
+function calcul_form_rech($lien)
+{
+  return 
+    "<form action='$lien' method='get'><p>
+	<input  type='text' id='formulaire_recherche' 
+	size='20' class='formrecherche'	name='recherche'
+	value='" . _T('info_rechercher') . "' />
+	</p></form>";
+}
+
+# fonctions pour la balise FORMULAIRE_FORUM
+# $Cache est passe' par re'fe'rence pour e'viter sa recopie mais n'est pas affecte'
+
+function boutons_de_forum($idr, $idf, $ida, $idb, $ids, $titre, $table, $forum, &$Cache)
+{
+  $r = boutons_de_forum_table($idr, $idf, $ida, $idb, $ids, $titre, $table, $forum);
+  if (!$r) return '';
+  list($titre, $table, $forum) = $r;
+  $titre = ('> ' . supprimer_numero(ereg_replace ('^[>[:space:]]*', '',$titre)));
+  $url = $GLOBALS[HTTP_GET_VARS][url];
+  if (!$url) 
+    $url = substr($GLOBALS[PHP_SELF], strrpos($GLOBALS[PHP_SELF], '/')+1) . 
+      substr($GLOBALS[REQUEST_URI], strpos($GLOBALS[REQUEST_URI], '?')); 
+  $retour_forum = $GLOBALS['retour'];
+  if (!$retour_forum)
+    $retour_forum = rawurlencode($url);
+  else $retour_forum = ereg_replace('&recalcul=oui','',$retour_forum);
+
+  $lacible = "
+	include_local('inc-forum.php3');
+	lang_select(\$GLOBALS['spip_lang']);
+	echo retour_forum('$idr','$idf','$ida','$idb','$ids',\"$titre\",'$table', '$forum', '$url', \"
+	<input type=hidden name='retour' value='$retour_forum' />
+	<input type=hidden name='var_cache' value='$Cache[cache]' />
+	<input type=hidden name='ajout_forum' value='oui' />
+	<input type=hidden name='forum_id_rubrique' value='$idr' />
+	<input type=hidden name='forum_id_parent' value='$idf' />
+	<input type=hidden name='forum_id_article' value='$ida' />
+	<input type=hidden name='forum_id_breve' value='$idb' />
+	<input type=hidden name='forum_id_syndic' value='$ids' />
+	" .
+	(($forum != 'pri') ? '' : ((_T('forum_info_modere'). '<p>'))) . 
+	"\");
+	lang_dselect();";
+  return
+	 (($forum != "abo") ? ("<" . "?php" . $lacible . "?" . ">"):
+	   ("<" . "?php " . "if (\$GLOBALS[\"auteur_session\"]) {
+		$lacible}" . 'else
+		{
+		include_local("inc-login.php3"); 
+		login(new Link("' . $url . '"), false, true); }' . 
+	    "?". ">"));
+}
+
+?>
diff --git a/inc-calcul_mysql3.php b/inc-calcul_mysql3.php
new file mode 100644
index 0000000000..cf5c6bfe1e
--- /dev/null
+++ b/inc-calcul_mysql3.php
@@ -0,0 +1,223 @@
+<?php
+    
+# Ce fichier concentre tous les appels SQL lors de l'execution d'un squelette.
+
+# Cette fonction est syste'matiquement appelee par les squelettes
+# pour constuire une requete SQL a` partir de la boucle SPIP originale.
+# Elle construit et exe'cute une reque^te SQL correspondant a` une balise Boucle
+# Elle notifie une erreur SQL dans le flux de sortie et termine le processus.
+# Sinon, retourne la ressource interrogeable par fetch_row ou fetch_array.
+# Elle peut etre re'de'finie pour s'interfacer avec d'autres serveurs SQL
+# Recoit en argument:
+# - le tableau des champs a` ramener
+# - le tableau des tables a` consulter
+# - le tableau des conditions a` remplir
+# - le crite`re de regroupement
+# - le crite`re de classement
+# - le crite`re de limite
+# - une sous-requete e'ventuelle (MySQL > 4.1)
+# - un compteur de sous-requete
+# - le nom de la table
+# - le nom de la boucle (pour le message d'erreur e'ventuel)
+
+# 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)
+{
+# if ($GLOBALS["mysql_rappel_connexion"] AND $DB = $GLOBALS["spip_mysql_db"])
+#        $DB = "`$DB`";
+# $DB .= $GLOBALS["table_prefix"] . '_';
+  $DB = 'spip_';
+ $q = "\nFROM\t$DB".
+    join(",\n\t$DB", $f) .
+    ((!$w) ? "" : ("\nWHERE\t".join("\n AND\t", $w))) .
+    ($g ? "\nGROUP BY $g" : '') .
+    ($o ? "\nORDER BY $o" : '') .
+    ($l ? "\nLIMIT $l" : '');
+  $q = (!$sous ? 
+	("\nSELECT\t". join(",\n\t", $s) . $q) :
+	("\nSELECT\tS_" . join(",\n\tS_", $s) .
+	 "\nFROM ($s,\n\tCOUNT(" . $sous .
+	 ") AS compteur $q)\n AS S_$table\nWHERE compteur= " . 
+	 $cpt));
+#  spip_log("$id: $q");
+# if (!($result = @mysql_query($q)))
+  if (!($result = @spip_query($q)))
+    {
+      include_local("inc-debug-squel.php3");
+      echo erreur_requete_boucle($q, $id, $table);
+      exit;
+    }
+  else return $result;
+}
+
+# toutes les fonctions avec requete SQL, necessaires aux squelettes.
+
+function boutons_de_forum_table($idr, $idf, $ida, $idb, $ids, $titre, $table, $forum)
+{
+  if (($table == 'forums') || !$table)
+    {
+      $forum = spip_fetch_object(spip_query("
+SELECT	accepter_forum
+FROM	spip_articles
+WHERE	id_article='" . ($ida ? $ida : substr(lire_meta("forums_publics"),0,3)) . "'
+")); 
+      $forum = ($forum ? $forum->accepter_forum : substr(lire_meta("forums_publics"),0,3));
+    }
+  if ($forum=="non") return '';
+  // si FORMULAIRE_FORUM a e'te' employe' hors d'une boucle,
+  // on n'a pas pu de'terminer titre et table a` la compil
+  if (!$table)
+    {
+      if ($idf)
+	{
+	  $r = "SELECT titre FROM spip_forum WHERE id_forum = $idf";
+	  $table = "forum";
+	}
+      else if ($idr)
+	{
+	  $r = "SELECT titre FROM spip_rubriques WHERE id_rubrique = $idr";
+	  $table = "rubriques";
+	}
+      else if ($ida)
+	{
+	  $r = "SELECT titre FROM spip_articles WHERE id_article = $ida";
+	  $table = "articles";
+	}
+      else if ($idb)
+	{
+	  $r = "SELECT titre FROM spip_breves WHERE id_breve = $idb";
+	  $table = "breves";
+	}
+      else if ($ids)
+	{
+	  $table = "syndic";
+	  $r = "SELECT nom_site AS titre FROM spip_syndic WHERE id_syndic = $ids";
+	}
+      else
+	{
+	  $r = "SELECT '".addslashes(_T('forum_titre_erreur'))."' AS titre";
+	}
+      $r = spip_fetch_object(spip_query($r));
+      $titre = $r->titre;
+    }
+  return array($titre, $table, $forum);
+}
+
+# Critere {branche} : recuperer les descendants d'une rubrique
+
+function calcul_generation ($generation) {
+	$lesfils = array();
+	$result = spip_query("SELECT id_rubrique FROM spip_rubriques WHERE id_parent IN ($generation)");
+	while ($row = spip_fetch_array($result))
+		$lesfils[] = $row['id_rubrique'];
+	return join(",",$lesfils);
+}
+
+function calcul_branche ($generation) {
+	if ($generation) {
+		$branche[] = $generation;
+		while ($generation = calcul_generation ($generation))
+			$branche[] = $generation;
+		return join(",",$branche);
+	} else
+		return '0';
+}
+
+function query_parent($id_rubrique)
+{
+  $row = spip_fetch_array(spip_query("
+SELECT id_parent FROM spip_rubriques WHERE id_rubrique='$id_rubrique'
+"));
+  return $row['id_parent'];
+}
+
+function query_auteurs($larticle)
+{
+  $auteurs = "";
+  if ($larticle)
+    {
+      $result_auteurs = spip_query("
+SELECT	auteurs.nom, auteurs.email 
+FROM	spip_auteurs AS auteurs,
+	spip_auteurs_articles AS lien
+WHERE	lien.id_article=$larticle
+ AND	auteurs.id_auteur=lien.id_auteur
+");
+
+      while($row_auteur = spip_fetch_array($result_auteurs)) {
+	$nom_auteur = typo($row_auteur["nom"]);
+	$email_auteur = $row_auteur["email"];
+	if ($email_auteur) {
+	  $auteurs[] = "<A HREF=\"mailto:$email_auteur\">$nom_auteur</A>";
+	}
+	else {
+	  $auteurs[] = "$nom_auteur";
+	}
+      }
+    }
+  return (!$auteurs) ? "" : join($auteurs, ", ");
+}
+
+function query_petitions($id_article)
+{
+  return spip_fetch_array(spip_query("
+SELECT	id_article
+FROM	spip_petitions
+WHERE	id_article='$id_article'"));
+    }
+
+# retourne le chapeau d'un article, et seulement s'il est publie
+
+function query_chapo($id_article)
+{
+ return spip_fetch_array(spip_query("
+SELECT	chapo
+FROM	spip_articles
+WHERE	id_article='$id_article' AND statut='publie'
+"));
+}
+
+// Calcul de la rubrique associee a la requete
+// (selection de squelette specifique)
+
+function cherche_rubrique_fond($contexte, $lang)
+{
+  if ($id = $contexte['id_rubrique']) {
+    if ($row = spip_fetch_array(spip_query("SELECT lang FROM spip_rubriques WHERE id_rubrique='$id'")))
+      if ($row['lang']) $lang = $row['lang'];
+    return array($id, $lang);
+  }
+  if ($id  = $contexte['id_breve']) {
+    if ($row = spip_fetch_array(spip_query("
+SELECT id_rubrique FROM spip_breves WHERE id_breve='$id'"))) {
+      $id_rubrique_fond = $row['id_rubrique'];
+      if ($row = spip_fetch_array(spip_query("
+SELECT lang FROM spip_rubriques WHERE id_rubrique='$id_rubrique_fond'")))
+	if ($row['lang']) $lang = $row['lang'];
+    }
+    return array($id_rubrique_fond, $lang);
+  }
+  if ($id = $contexte['id_syndic']) {
+    if ($row = spip_fetch_array(spip_query("
+SELECT id_rubrique FROM spip_syndic WHERE id_syndic='$id'"))) {
+      $id_rubrique_fond = $row['id_rubrique'];
+      if ($row = spip_fetch_array(spip_query("
+SELECT lang FROM spip_rubriques WHERE id_rubrique='$id_rubrique_fond'")))
+	if ($row['lang']) $lang = $row['lang'];
+    }
+    return array($id_rubrique_fond, $lang);
+  }
+  if ($id = $contexte['id_article']) {
+    if ($row = spip_fetch_array(spip_query("
+SELECT id_rubrique,lang FROM spip_articles WHERE id_article='$id'"))) {
+      $id_rubrique_fond = $row['id_rubrique'];
+      if ($row['lang']) $lang = $row['lang'];
+    }
+    return array($id_rubrique_fond, $lang);
+  }
+  return '';
+}
+
+?>
diff --git a/inc-champ-squel.php3 b/inc-champ-squel.php3
index 71e07135e8..2626e6d680 100755
--- a/inc-champ-squel.php3
+++ b/inc-champ-squel.php3
@@ -5,407 +5,186 @@
 if (defined("_INC_CHAMP_SQUEL")) return;
 define("_INC_CHAMP_SQUEL", "1");
 
+global $exceptions_des_tables, $table_des_tables,
+ $champs_traitement, $champs_pretraitement, $champs_posttraitement,
+ $tables_relations,  $table_primary, $table_date
+;
 
-function init_champs_squel() {
-	global $champs_valides;
-	global $champs_traitement, $champs_pretraitement, $champs_posttraitement;
-
-	global $rows_articles;
-	global $rows_signatures;
-	global $rows_syndication;
-	global $rows_syndic_articles;
-	global $rows_documents;
-	global $rows_types_documents;
-	global $rows_rubriques;
-	global $rows_forums;
-	global $rows_breves;
-	global $rows_auteurs;
-	global $rows_hierarchie;
-	global $rows_mots;
-	global $rows_groupes_mots;
-
-	global $tables_relations;
-	global $tables_code_contexte;
-	global $tables_doublons;
-
-	//
-	// Construire un tableau des tables de relations
-	//
-
-	$tables_relations = '';
-
-	$tables_relations['articles']['id_mot'] = 'spip_mots_articles';
-	$tables_relations['articles']['id_auteur'] = 'spip_auteurs_articles';
-	$tables_relations['articles']['id_document'] = 'spip_documents_articles';
-
-	$tables_relations['auteurs']['id_article'] = 'spip_auteurs_articles';
-
-	$tables_relations['breves']['id_mot'] = 'spip_mots_breves';
-	$tables_relations['breves']['id_document'] = 'spip_documents_breves';
-
-	$tables_relations['documents']['id_article'] = 'spip_documents_articles';
-	$tables_relations['documents']['id_rubrique'] = 'spip_documents_rubriques';
-	$tables_relations['documents']['id_breve'] = 'spip_documents_breves';
-
-	$tables_relations['forums']['id_mot'] = 'spip_mots_forum';
-
-	$tables_relations['mots']['id_article'] = 'spip_mots_articles';
-	$tables_relations['mots']['id_breve'] = 'spip_mots_breves';
-	$tables_relations['mots']['id_forum'] = 'spip_mots_forum';
-	$tables_relations['mots']['id_rubrique'] = 'spip_mots_rubriques';
-	$tables_relations['mots']['id_syndic'] = 'spip_mots_syndic';
-
-	$tables_relations['groupes_mots']['id_groupe'] = 'spip_mots';
-
-	$tables_relations['rubriques']['id_mot'] = 'spip_mots_rubriques';
-	$tables_relations['rubriques']['id_document'] = 'spip_documents_rubriques';
-
-	$tables_relations['syndication']['id_mot'] = 'spip_mots_syndic';
-
+//
+// Construire un tableau des tables de relations
+//
 
-	//
-	// Construire un tableau associatif des codes de champ utilisables
-	//
+$tables_relations = '';
 
-	$c = array('NOM_SITE_SPIP', 'URL_SITE_SPIP', 'EMAIL_WEBMASTER',
-		'CHARSET', 'ID_ARTICLE', 'ID_RUBRIQUE', 'ID_BREVE', 'ID_FORUM',
-		'ID_PARENT', 'ID_SECTEUR', 'ID_DOCUMENT', 'ID_TYPE', 'ID_AUTEUR',
-		'ID_MOT', 'ID_SYNDIC_ARTICLE', 'ID_SYNDIC', 'ID_SIGNATURE',
-		'ID_GROUPE', 'ID_VIGNETTE', 'TITRE', 'SURTITRE', 'SOUSTITRE', 'DESCRIPTIF',
-		'CHAPO', 'TEXTE', 'PS', 'NOTES', 'INTRODUCTION', 'MESSAGE', 'DATE',
-		'DATE_REDAC', 'DATE_MODIF', 'DATE_NOUVEAUTES', 'INCLUS', 'LANG',
-		'LANG_LEFT', 'LANG_RIGHT', 'LANG_DIR', 'LESAUTEURS', 'EMAIL',
-		'NOM_SITE', 'LIEN_TITRE', 'URL_SITE', 'LIEN_URL', 'NOM', 'BIO',
-		'TYPE', 'PGP', 'FORMULAIRE_ECRIRE_AUTEUR', 'FORMULAIRE_FORUM',
-		'FORMULAIRE_SITE', 'PARAMETRES_FORUM', 'FORMULAIRE_RECHERCHE',
-		'RECHERCHE', 'FORMULAIRE_INSCRIPTION', 'FORMULAIRE_SIGNATURE',
-		'LOGO_MOT', 'LOGO_RUBRIQUE', 'LOGO_RUBRIQUE_NORMAL',
-		'LOGO_RUBRIQUE_SURVOL', 'LOGO_AUTEUR', 'LOGO_AUTEUR_NORMAL',
-		'LOGO_AUTEUR_SURVOL', 'LOGO_SITE', 'LOGO_BREVE',
-		'LOGO_BREVE_RUBRIQUE', 'LOGO_DOCUMENT', 'LOGO_ARTICLE',
-		'LOGO_ARTICLE_RUBRIQUE', 'LOGO_ARTICLE_NORMAL',
-		'LOGO_ARTICLE_SURVOL', 'URL_ARTICLE', 'URL_RUBRIQUE', 'URL_BREVE',
-		'URL_FORUM', 'URL_SYNDIC', 'URL_MOT', 'URL_DOCUMENT', 'URL_AUTEUR',
-		'EMBED_DOCUMENT', 'IP', 'VISITES', 'POPULARITE',
-		'POPULARITE_ABSOLUE', 'POPULARITE_MAX', 'POPULARITE_SITE', 'POINTS',
-		'COMPTEUR_BOUCLE', 'TOTAL_BOUCLE', 'PETITION', 'LARGEUR', 'HAUTEUR',
-		'TAILLE', 'EXTENSION', 'DEBUT_SURLIGNE', 'FIN_SURLIGNE',
-		'TYPE_DOCUMENT', 'EXTENSION_DOCUMENT', 'FORMULAIRE_ADMIN',
-		'LOGIN_PRIVE', 'LOGIN_PUBLIC', 'URL_LOGOUT', 'PUCE', 'EXTRA',
-		'EXPOSER', 'MENU_LANG', 'MENU_LANG_ECRIRE'
-	);
-	reset($c);
-	while (list(, $val) = each($c)) {
-		unset($champs_traitement[$val]);
-		unset($champs_pretraitement[$val]);
-		unset($champs_posttraitement[$val]);
-		$champs_valides[$val] = $val;
-	}
+$tables_relations['articles']['id_mot'] = 'mots_articles';
+$tables_relations['articles']['id_auteur'] = 'auteurs_articles';
+$tables_relations['articles']['id_document'] = 'documents_articles';
 
+$tables_relations['auteurs']['id_article'] = 'auteurs_articles';
 
-	//
-	// Construire un tableau associatif des pre-traitements de champs
-	//
+$tables_relations['breves']['id_mot'] = 'mots_breves';
+$tables_relations['breves']['id_document'] = 'documents_breves';
 
-	// Textes utilisateur : ajouter la securite anti-script
-	$c = array('NOM_SITE_SPIP', 'URL_SITE_SPIP', 'EMAIL_WEBMASTER', 'CHARSET',
-		'TITRE', 'SURTITRE', 'SOUSTITRE', 'DESCRIPTIF', 'CHAPO', 'TEXTE', 'PS',
-		'NOTES', 'INTRODUCTION', 'MESSAGE', 'LESAUTEURS', 'EMAIL', 'NOM_SITE',
-		'LIEN_TITRE', 'URL_SITE', 'LIEN_URL', 'NOM', 'IP', 'BIO',
-		'TYPE', 'PGP', 'RECHERCHE'
-	);
-	reset($c);
-	while (list(, $val) = each($c)) {
-		$champs_pretraitement[$val][] = 'trim';
-		$champs_posttraitement[$val][] = 'interdire_scripts';
-	}
-	$c = array('EXTRA');
-	reset($c);
-	while (list(, $val) = each($c)) {
-		$champs_posttraitement[$val][] = 'interdire_scripts';
-	}
+$tables_relations['documents']['id_article'] = 'documents_articles';
+$tables_relations['documents']['id_rubrique'] = 'documents_rubriques';
+$tables_relations['documents']['id_breve'] = 'documents_breves';
 
-	// Textes courts : ajouter le traitement typographique
-	$c = array('NOM_SITE_SPIP', 'SURTITRE', 'TITRE', 'SOUSTITRE', 'NOM_SITE', 'LIEN_TITRE', 'NOM', 'TYPE');
-	reset($c);
-	while (list(, $val) = each($c)) {
-		$champs_traitement[$val][] = 'typo';
-	}
+$tables_relations['forums']['id_mot'] = 'mots_forum';
 
-	// Chapo : ne pas l'afficher si article virtuel
-	$c = array('CHAPO');
-	reset($c);
-	while (list(, $val) = each($c)) {
-		$champs_traitement[$val][] = 'nettoyer_chapo';
-	}
+$tables_relations['mots']['id_article'] = 'mots_articles';
+$tables_relations['mots']['id_breve'] = 'mots_breves';
+$tables_relations['mots']['id_forum'] = 'mots_forum';
+$tables_relations['mots']['id_rubrique'] = 'mots_rubriques';
+$tables_relations['mots']['id_syndic'] = 'mots_syndic';
 
-	// Textes longs : ajouter le traitement typographique + mise en forme
-	$c = array('DESCRIPTIF', 'CHAPO', 'TEXTE', 'PS', 'BIO', 'MESSAGE');
-	reset($c);
-	while (list(, $val) = each($c)) {
-		$champs_traitement[$val][] = 'traiter_raccourcis';
-	}
+$tables_relations['groupes_mots']['id_groupe'] = 'mots';
 
-	// Dates : ajouter le vidage des dates egales a 00-00-0000
-	$c = array('DATE', 'DATE_REDAC', 'DATE_MODIF', 'DATE_NOUVEAUTES');
-	reset($c);
-	while (list(, $val) = each($c)) {
-		$champs_traitement[$val][] = 'vider_date';
-	}
+$tables_relations['rubriques']['id_mot'] = 'mots_rubriques';
+$tables_relations['rubriques']['id_document'] = 'documents_rubriques';
 
-	// URL_SITE : vider les url == 'http://'
-	$c = array('URL_SITE_SPIP', 'URL_SITE', 'LIEN_URL');
-	reset($c);
-	while (list(, $val) = each($c)) {
-		$champs_traitement[$val][] = 'vider_url';
-	}
+$tables_relations['syndication']['id_mot'] = 'mots_syndic';
 
-	// URLs : remplacer les & par &amp;
-	$c = array('URL_SITE_SPIP', 'URL_SITE', 'LIEN_URL', 'PARAMETRES_FORUM',
-		'URL_ARTICLE', 'URL_RUBRIQUE', 'URL_BREVE', 'URL_FORUM', 'URL_SYNDIC',
-		'URL_MOT', 'URL_DOCUMENT');
-	reset($c);
-	while (list(, $val) = each($c)) {
-		$champs_traitement[$val][] = 'htmlspecialchars';
-	}
+//
+// Construire un tableau associatif des pre-traitements de champs
+//
 
-	//
-	// Construire un tableau associatif des champs de chaque type
-	// avec l'intitule de la colonne mysql correspondante
-	//
+// Textes utilisateur : ajouter la securite anti-script
+$c = array('NOM_SITE_SPIP', 'URL_SITE_SPIP', 'EMAIL_WEBMASTER', 'CHARSET',
+	'TITRE', 'SURTITRE', 'SOUSTITRE', 'DESCRIPTIF', 'CHAPO', 'TEXTE', 'PS', 'NOTES', 'INTRODUCTION', 'MESSAGE',
+	'LESAUTEURS', 'EMAIL', 'NOM_SITE', 'LIEN_TITRE', 'URL_SITE', 'LIEN_URL', 'NOM', 'IP', 'BIO', 'TYPE', 'PGP',
+	'RECHERCHE'
+);
+reset($c);
+while (list(, $val) = each($c)) {
+	$champs_pretraitement[$val][] = 'trim';
+	$champs_posttraitement[$val][] = 'interdire_scripts';
+}
+$c = array('EXTRA');
+reset($c);
+while (list(, $val) = each($c)) {
+  $champs_posttraitement[$val][] = 'interdire_scripts';
+}
+   
+// Textes courts : ajouter le traitement typographique
+$c = array('NOM_SITE_SPIP', 'SURTITRE', 'TITRE', 'SOUSTITRE', 'NOM_SITE', 'LIEN_TITRE', 'NOM', 'TYPE');
+reset($c);
+while (list(, $val) = each($c)) {
+	$champs_traitement[$val][] = 'typo';
+}
 
-	$rows_articles = array(
-		'ID_ARTICLE' => 'id_article',
-		'ID_RUBRIQUE' => 'id_rubrique',
-		'ID_SECTEUR' => 'id_secteur',
-		'SURTITRE' => 'surtitre',
-		'TITRE' => 'titre',
-		'SOUSTITRE' => 'soustitre',
-		'DESCRIPTIF' => 'descriptif',
-		'CHAPO' => 'chapo',
-		'TEXTE' => 'texte',
-		'PS' => 'ps',
-		'LANG' => 'lang',
-		'DATE' => 'date',
-		'DATE_REDAC' => 'date_redac',
-		'NOM_SITE' => 'nom_site',
-		'URL_SITE' => 'url_site',
-		'DATE_MODIF' => 'date_modif',
-		'VISITES' => 'visites',
-		'POINTS' => 'points'
-	);
-	$rows_auteurs = array(
-		'ID_AUTEUR' => 'id_auteur',
-		'NOM' => 'nom',
-		'BIO' => 'bio',
-		'EMAIL' => 'email',
-		'NOM_SITE' => 'nom_site',
-		'URL_SITE' => 'url_site',
-		'PGP' => 'pgp',
-		'LANG' => 'lang',
-		'POINTS' => 'points'
-	);
-	$rows_breves = array(
-		'ID_BREVE' => 'id_breve',
-		'ID_RUBRIQUE' => 'id_rubrique',
-		'ID_SECTEUR' => 'id_rubrique',
-		'DATE' => 'date_heure',
-		'TITRE' => 'titre',
-		'TEXTE' => 'texte',
-		'LANG' => 'lang',
-		'NOM_SITE' => 'lien_titre',
-		'URL_SITE' => 'lien_url',
-		'LIEN_TITRE' => 'lien_titre',
-		'LIEN_URL' => 'lien_url',
-		'POINTS' => 'points'
-	);
-	$rows_forums = array(
-		'ID_FORUM' => 'id_forum',
-		'ID_PARENT' => 'id_parent',
-		'ID_BREVE' => 'id_breve',
-		'ID_RUBRIQUE' => 'id_rubrique',
-		'ID_ARTICLE' => 'id_article',
-		'TITRE' => 'titre',
-		'TEXTE' => 'texte',
-		'DATE' => 'date_heure',
-		'NOM' => 'auteur',
-		'EMAIL' => 'email_auteur',
-		'NOM_SITE' => 'nom_site',
-		'URL_SITE' => 'url_site',
-		'ID_AUTEUR' => 'id_auteur',
-		'IP' => 'ip'
-	);
-	$rows_documents = array(
-		'ID_DOCUMENT' => 'id_document',
-		'ID_VIGNETTE' => 'id_vignette',
-		'ID_TYPE' => 'id_type',
-		'TITRE' => 'titre',
-		'DESCRIPTIF' => 'descriptif',
-		'DATE' => 'date',
-		'LARGEUR' => 'largeur',
-		'HAUTEUR' => 'hauteur',
-		'TAILLE' => 'taille',
-		'TYPE_DOCUMENT' => 'type_document',
-		'EXTENSION_DOCUMENT' => 'extension_document'
-	);
-	$rows_types_documents = array(
-		'ID_TYPE' => 'id_type',
-		'TITRE' => 'titre',
-		'DESCRIPTIF' => 'descriptif',
-		'EXTENSION' => 'extension'
-	);
-	$rows_mots = array(
-		'ID_MOT' => 'id_mot',
-		'TYPE' => 'type',
-		'TITRE' => 'titre',
-		'DESCRIPTIF' => 'descriptif',
-		'TEXTE' => 'texte',
-		'POINTS' => 'points',
-		'ID_GROUPE' => 'id_groupe'
-	);
-	$rows_groupes_mots = array(
-		'ID_GROUPE' => 'id_groupe',
-		'TITRE' => 'titre'
-	);
-	$rows_rubriques = array(
-		'ID_RUBRIQUE' => 'id_rubrique',
-		'ID_PARENT' => 'id_parent',
-		'ID_SECTEUR' => 'id_secteur',
-		'TITRE' => 'titre',
-		'DESCRIPTIF' => 'descriptif',
-		'TEXTE' => 'texte',
-		'LANG' => 'lang',
-		'DATE' => 'date',
-		'POINTS' => 'points'
-	);
-	$rows_hierarchie = $rows_rubriques;
+// Chapo : ne pas l'afficher si article virtuel
+$c = array('CHAPO');
+reset($c);
+while (list(, $val) = each($c)) {
+	$champs_traitement[$val][] = 'nettoyer_chapo';
+}
 
-	$rows_signatures = array(
-		'ID_SIGNATURE' => 'id_signature',
-		'ID_ARTICLE' => 'id_article',
-		'DATE' => 'date_time',
-		'NOM' => 'nom_email',
-		'EMAIL' => 'ad_email',
-		'NOM_SITE' => 'nom_site',
-		'URL_SITE' => 'url_site',
-		'MESSAGE' => 'message'
-	);
+// Textes longs : ajouter le traitement typographique + mise en forme
+$c = array('DESCRIPTIF', 'CHAPO', 'TEXTE', 'PS', 'BIO', 'MESSAGE');
+reset($c);
+while (list(, $val) = each($c)) {
+	$champs_traitement[$val][] = 'traiter_raccourcis';
+}
 
-	$rows_syndication = array(
-		'ID_SYNDIC' => 'id_syndic',
-		'ID_RUBRIQUE' => 'id_rubrique',
-		'ID_SECTEUR' => 'id_secteur',
-		'NOM_SITE' => 'nom_site',
-		'URL_SITE' => 'url_site',
-		'URL_SYNDIC' => 'url_syndic',
-		'DESCRIPTIF' => 'descriptif',
-		'DATE' => 'date',
-		'POINTS' => 'points'
-	);
-	$rows_syndic_articles = array(
-		'ID_SYNDIC_ARTICLE' => 'id_syndic_article',
-		'ID_SYNDIC' => 'id_syndic',
-		'TITRE' => 'titre',
-		'URL_ARTICLE' => 'url',
-		'DATE' => 'date',
-		'LESAUTEURS' => 'lesauteurs',
-		'DESCRIPTIF' => 'descriptif',
-		'NOM_SITE' => 'nom_site',
-		'URL_SITE' => 'url_site'
-	);
+// Dates : ajouter le vidage des dates egales a 00-00-0000
+$c = array('DATE', 'DATE_REDAC', 'DATE_MODIF', 'DATE_NOUVEAUTES');
+reset($c);
+while (list(, $val) = each($c)) {
+	$champs_traitement[$val][] = 'vider_date';
+}
 
-	$tables_code_contexte = array(
-	'articles' => '
-		$contexte["id_article"] = $row["id_article"];
-		$contexte["id_rubrique"] = $row["id_rubrique"];
-		$contexte["id_secteur"] = $row["id_secteur"];
-		$contexte["date"] = $row["date"];
-		$contexte["date_redac"] = $row["date_redac"];
-		$contexte["accepter_forum"] = $row["accepter_forum"];
-		$contexte["id_trad"] = $row["id_trad"];
-	',
-	'breves' => '
-		$contexte["id_breve"] = $row["id_breve"];
-		$contexte["id_rubrique"] = $row["id_rubrique"];
-		$contexte["id_secteur"] = $row["id_rubrique"];
-		$contexte["date"] = $row["date_heure"];
-	',
-	'rubriques' => '
-		$contexte["id_rubrique"] = $row["id_rubrique"];
-		$contexte["id_parent"] = $row["id_parent"];
-		$contexte["id_secteur"] = $row["id_secteur"];
-		$contexte["date"] = $row["date"];
-	',
-	'hierarchie' => '
-		$contexte["id_rubrique"] = $row["id_rubrique"];
-		$contexte["id_parent"] = $row["id_parent"];
-		$contexte["id_secteur"] = $row["id_secteur"];
-		$contexte["date"] = $row["date"];
-	',
-	'documents' => '
-		$contexte["id_document"] = $row["id_document"];
-		$contexte["id_vignette"] = $row["id_vignette"];
-		$contexte["id_type"] = $row["id_type"];
-	',
-	'types_documents' => '
-		$contexte["id_type"] = $row["id_type"];
-	',
-	'forums' => '
-		$contexte["id_forum"] = $row["id_forum"];
-		$contexte["id_rubrique"] = $row["id_rubrique"];
-		$contexte["id_article"] = $row["id_article"];
-		$contexte["id_breve"] = $row["id_breve"];
-		$contexte["id_syndic"] = $row["id_syndic"];
-		$contexte["id_parent"] = $row["id_parent"];
-		$contexte["id_auteur"] = $row["id_auteur"];
-		$contexte["date"] = $row["date_heure"];
-	',
-	'auteurs' => '
-		$contexte["id_auteur"] = $row["id_auteur"];
-	',
-	'signatures' => '
-		$contexte["id_signature"] = $row["id_signature"];
-		$contexte["date"] = $row["date_time"];
-	',
-	'mots' => '
-		$contexte["id_mot"] = $row["id_mot"];
-		$contexte["type"] = $row["type"];
-		$contexte["id_groupe"] = $row["id_groupe"];
-	',
-	'groupes_mots' => '
-		$contexte["id_groupe"] = $row["id_groupe"];
-	',
-	'syndication' => '
-		$contexte["id_syndic"] = $row["id_syndic"];
-		$contexte["id_rubrique"] = $row["id_rubrique"];
-		$contexte["id_secteur"] = $row["id_secteur"];
-		$contexte["url_site"] = $row["url_site"];
-		$contexte["date"] = $row["date"];
-	',
-	'syndic_articles' => '
-		$contexte["id_syndic"] = $row["id_syndic"];
-		$contexte["id_syndic_article"] = $row["id_syndic_article"];
-		$contexte["date"] = $row["date"];
-	'
-	);
+// URL_SITE : vider les url == 'http://'
+$c = array('URL_SITE_SPIP', 'URL_SITE', 'LIEN_URL');
+reset($c);
+while (list(, $val) = each($c)) {
+	$champs_traitement[$val][] = 'vider_url';
+}
 
-	$tables_doublons = array(
-		'articles' => "id_article",
-		'auteurs' => "id_auteur",
-		'breves' => "id_breve",
-		'documents' => "id_document",
-		'forums' => "id_forum",
-		'groupes_mots'	=> "id_groupe",
-		'hierarchie' => "id_rubrique",
-		'mots'	=> "id_mot",
-		'rubriques' => "id_rubrique",
-		'signatures' => "id_signature",
-		'syndication' => "id_syndic",
-		'syndic_articles' => "syndic_articles",
-		'types_documents' => "id_document"
-	);
+// URLs : remplacer les & par &amp;
+$c = array('URL_SITE_SPIP', 'URL_SITE', 'LIEN_URL', 'PARAMETRES_FORUM',
+	'URL_ARTICLE', 'URL_RUBRIQUE', 'URL_BREVE', 'URL_FORUM', 'URL_SYNDIC', 'URL_MOT', 'URL_DOCUMENT');
+reset($c);
+while (list(, $val) = each($c)) {
+	$champs_traitement[$val][] = 'htmlspecialchars';
 }
 
-init_champs_squel();
+// champ principal des tables SQL
+
+$table_primary = array(
+	'articles' => "id_article",
+	'auteurs' => "id_auteur",
+	'breves' => "id_breve",
+	'documents' => "id_document",
+	'forums' => "id_forum",
+	'groupes_mots'	=> "id_groupe",
+	'hierarchie' => "id_rubrique",
+	'mots'	=> "id_mot",
+	'rubriques' => "id_rubrique",
+	'signatures' => "id_signature",
+	'syndication' => "id_syndic",
+	'syndic_articles' => "id_syndic_article",
+	'types_documents' => "id_document"
+);
+
+
+$table_des_tables = array(
+			  'articles' => 'articles',
+			  'auteurs' => 'auteurs',
+			  'breves' => 'breves',
+			  'forums' => 'forum',
+			  'signatures' => 'signatures',
+			  'documents' => 'documents',
+			  'types_documents' => 'types_documents',
+			  'mots' => 'mots',
+			  'groupes_mots' => 'groupes_mots',
+			  'rubriques' => 'rubriques',
+			  'syndication' => 'syndic',
+			  'syndic_articles' => 'articles',
+			  'hierarchie' => 'rubriques'
+			  );
+
+$exceptions_des_tables = array(
+	      'breves' => array(
+				"id_secteur" => "id_rubrique",
+				"date" => "date_heure",
+				'nom_site' => 'lien_titre',
+				'url_site' => 'lien_url'
+				),
+	      'forums' => array(
+				"date" => "date_heure",
+				'nom' => 'auteur',
+				'email' => 'email_auteur'
+				),
+	      'signatures' => array(
+				    "date" => "date_time",
+				    'nom' => 'nom_email',
+				    'email' => 'ad_email'		    
+				    ),
+	      'documents' => array(
+				   'type_document' => array('types_documents',
+							    'titre'),
+   				   'extension_document' => array('types_documents',
+								 'extension')
+				   ),
+	      'syndic_articles' => array(
+					 'url_article' => 'url',
+					 'lesauteurs' => 'lesauteurs'
+					 )
+);
+
+$table_date = array (
+	'articles' => "date",
+	'auteurs' =>  "date",
+	'breves' =>  "date_heure",
+	'forums' =>  "date_heure",
+	'signatures' => "date_time",
+	'documents' => "date",
+	'types_documents' => "date",
+	'groupes_mots' => "date",
+	'mots' => "date",
+	'rubriques' => "date",
+	'syndication' => "date",
+	'syndic_articles' => "date"
+);
 
 ?>
diff --git a/inc-chercher.php3 b/inc-chercher.php3
new file mode 100644
index 0000000000..2bc14a7c56
--- /dev/null
+++ b/inc-chercher.php3
@@ -0,0 +1,46 @@
+<?php
+
+// Ce fichier ne sera execute qu'une fois
+if (defined("_INC_CHERCHE")) return;
+define("_INC_CHERCHE", "1");
+
+# 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;
+    }
+}
+?>
diff --git a/inc-debug-squel.php3 b/inc-debug-squel.php3
index 8ec8981922..b810e42522 100755
--- a/inc-debug-squel.php3
+++ b/inc-debug-squel.php3
@@ -4,9 +4,10 @@
 // Ce fichier ne sera execute qu'une fois
 if (defined("_INC_DEBUG_SKEL")) return;
 define("_INC_DEBUG_SKEL", "1");
+include_ecrire("inc_presentation.php3");
 
-
-function erreur_requete_boucle($query, $id_boucle) {
+function erreur_requete_boucle($query, $id_boucle, $type) {
+	$GLOBALS["delais"]=0;
 	$erreur = spip_sql_error();
 	$errno = spip_sql_errno();
 	if (eregi('err(no|code):?[[:space:]]*([0-9]+)', $erreur, $regs))
@@ -19,30 +20,37 @@ function erreur_requete_boucle($query, $id_boucle) {
 	// Erreur systeme
 	if ($errsys > 0 AND $errsys < 200) {
 		$retour .= "<tt><br><br><blink>"._T('info_erreur_systeme', array('errsys'=>$errsys))."</blink><br>\n";
-		$retour .= "<" ."?php
-		if (\$GLOBALS['spip_admin']) {
-			echo \""._T('info_erreur_systeme2').
-				"<blink>"._T('info_erreur_systeme', array('errsys'=>$errsys))."</blink>\";
-		}
-		echo \"</tt>\n\";
-		?".">";
+		if ($GLOBALS['spip_admin'])
+		$retour .= 
+			_T('info_erreur_systeme2').
+				"<blink>"._T('info_erreur_systeme', array('errsys'=>$errsys))."</blink>";
 	}
 	// Requete erronee
 	else {
-		$retour .= "<tt><br><br><blink>&lt;BOUCLE".$id_boucle."&gt;</blink><br>\n".
-			"<b>"._T('avis_erreur_mysql')."</b><br>\n".
-			htmlspecialchars($query)."<br><font color='red'><b>$erreur</b></font><br>".
-			"<blink>&lt;/BOUCLE".$id_boucle."&gt;</blink></tt>\n";
-		$retour .= "<" ."?php
-		if (\$GLOBALS['spip_admin']) {
-			include_ecrire ('inc_lang.php3');
-			utiliser_langue_visiteur();
-			include_ecrire('inc_presentation.php3');
-			echo aide('erreur_mysql');
-		} ?".">";
+		$retour .= "<tt><blink>&lt;BOUCLE".
+		  $id_boucle.
+		  "&gt;(".
+		  $type .
+		  ")</blink><br>\n".
+		"<b>"._T('avis_erreur_mysql')."</b><br>\n".
+		  htmlspecialchars($query)."<br><font color='red'><b>$erreur</b></font><br>".
+		  "<blink>&lt;/BOUCLE".$id_boucle."&gt;</blink></tt>\n";
+		if ($GLOBALS['spip_admin']) {
+		  include_ecrire('inc_lang.php3');
+		  utiliser_langue_visiteur();
+		  $retour .= aide('erreur_mysql');
+		}
 	}
-	$retour .= "<br><br>\n"; // debugger les squelettes
-	return $retour;
+	return "<div style='position: fixed; top: 10px; left: 10px; z-index: 10000'>$retour</div>";
 }
 
+function erreur_squelette($message, $fautif, $lieu)
+{
+  install_debut_html($message);
+  if ($fautif)
+    echo ' (<FONT color="#FF000">' . entites_html($fautif) . '</FONT>)';
+  echo '<br /><FONT color="#FF000">' . $lieu . '</FONT>.'; 
+  install_fin_html();
+  exit;
+}
 ?>
diff --git a/inc-debug.php3 b/inc-debug.php3
index ba5d346727..5b632951f4 100644
--- a/inc-debug.php3
+++ b/inc-debug.php3
@@ -65,14 +65,8 @@ function affboucle($val) {
 	echo "\n";
 }
 
-function affboucles() {
-	global $boucles;
-	reset($boucles);
-	while (list($key, $val) = each($boucles)) affboucle($val);
+function affboucles($boucles) {
+  while (list($key, $val) = each($boucles)) affboucle($val);
 }
 
-afftable($GLOBALS['racine']);
-affboucles();
-
-
-?>
\ No newline at end of file
+?>
diff --git a/inc-dir.php3 b/inc-dir.php3
new file mode 100644
index 0000000000..3e67f6a55d
--- /dev/null
+++ b/inc-dir.php3
@@ -0,0 +1,104 @@
+<?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, 0770))
+	{
+	  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);
+}
+
+?>
diff --git a/inc-form-squel.php3 b/inc-form-squel.php3
new file mode 100644
index 0000000000..e7738f8a32
--- /dev/null
+++ b/inc-form-squel.php3
@@ -0,0 +1,200 @@
+<?php
+
+# traduction des champs "formulaire" et "parametres
+
+# Boutons d'administration: 
+# comme c'est soumis a` une condition dynamique (adminitrateur ?)
+# on produit un appel a` une fonction Javascript
+# a chaque utilisation du squelette, on produira la de'finition ad hoc
+
+function calculer_champ_FORMULAIRE_ADMIN($fonctions, $nom_champ, $id_boucle, &$boucles, $id_mere)
+{
+  return array("envoi_script('admin()')",'');
+}
+
+function calculer_champ_FORMULAIRE_RECHERCHE($fonctions, $nom_champ, $id_boucle, &$boucles, $id_mere)
+{
+  if ($fonctions) {
+    list(, $lien) = each($fonctions);	// le premier est un url
+    while (list(, $filtre) = each($fonctions)) {
+      $filtres[] = $filtre;		// les suivants sont des filtres
+    }
+    $fonctions = $filtres;
+  }
+  if (!$lien) $lien = 'recherche.php3';
+  $code = "((lire_meta('activer_moteur') != 'oui') ? '' : calcul_form_rech('$lien'))";
+		
+  return applique_filtres($fonctions, $code, $id_boucle, $boucles, $id_mere);
+}
+
+
+// Formulaire d'inscription comme redacteur (dans inc-formulaires.php3)
+
+function calculer_champ_FORMULAIRE_INSCRIPTION($fonctions, $nom_champ, $id_boucle, &$boucles, $id_mere)
+{
+  $milieu = '
+		$spip_lang = $GLOBALS["spip_lang"];';
+  $code = '(lire_meta("accepter_inscriptions") != "oui") ? "" :
+			("<"."?php include(\'inc-formulaires.php3\'); lang_select(\"$spip_lang\"); formulaire_inscription(\"redac\"); lang_dselect(); ?".">")';
+  list($c,$m) = applique_filtres($fonctions, $code, $id_boucle, $boucles, $id_mere);
+  return array($c,$milieu . $m);
+}
+
+function calculer_champ_FORMULAIRE_ECRIRE_AUTEUR($fonctions, $nom_champ, $id_boucle, &$boucles, $id_mere)
+{
+  $milieu = '
+		$spip_lang = $GLOBALS["spip_lang"];
+		$mailauteur = ' .
+    index_pile($id_boucle,  'email', &$boucles) . ';
+		$nomauteur = ' .
+    index_pile($id_boucle,  'id_auteur', &$boucles) . ';';
+  $code = '(!email_valide($mailauteur) ? "" :
+			("<'.'?php include(\'inc-formulaires.php3\'); lang_select(\"$spip_lang\"); formulaire_ecrire_auteur(\"$nomauteur\", trim(\"$mailauteur\")); lang_dselect();
+			?'.'>"))';
+  list($c,$m) = applique_filtres($fonctions, $code, $id_boucle, $boucles, $id_mere);
+  return array($c,$milieu . $m);  
+}
+
+function calculer_champ_FORMULAIRE_SIGNATURE($fonctions, $nom_champ, $id_boucle, &$boucles, $id_mere)
+{
+  $milieu = '
+		$spip_lang = $GLOBALS["spip_lang"];
+		$lacible = ' . 	index_pile($id_boucle, 'id_article', &$boucles) . ";";
+   $code = '(!query_petitions($lacible) ? "" :
+ 			 ("<"."?php include(\'inc-formulaires.php3\'); lang_select(\"$spip_lang\"); formulaire_signature($lacible); lang_dselect();
+				?".">"))';
+  list($c,$m) = applique_filtres($fonctions, $code, $id_boucle, $boucles, $id_mere);
+  return array($c,$milieu . $m);
+}
+
+	//
+	// Formulaire de referencement d'un site
+	//
+function calculer_champ_FORMULAIRE_SITE($fonctions, $nom_champ, $id_boucle, &$boucles, $id_mere)
+{
+  $milieu = '
+		$spip_lang = $GLOBALS["spip_lang"];
+		$lacible = ' .
+    index_pile($id_boucle,  'id_rubrique', &$boucles) . ';';
+  $code = '(lire_meta("proposer_sites") != "2") ? "" :
+			("<"."?php include(\'inc-formulaires.php3\'); lang_select(\"$spip_lang\"); formulaire_site($lacible); lang_dselect();
+				?".">")';
+  list($c,$m) = applique_filtres($fonctions, $code, $id_boucle, $boucles, $id_mere);
+  return array($c,$milieu . $m);
+}
+
+
+// Formulaire de reponse a un forum
+
+function calculer_champ_FORMULAIRE_FORUM($fonctions, $nom_champ, $id_boucle, &$boucles, $id_mere)
+{
+  $type = $boucles[$id_boucle]->type_requete;
+  $milieu ='';
+  switch ($type) {
+  case 'breves':
+    $code = "
+			boutons_de_forum('', '', ''," .
+      index_pile($id_boucle,  'id_breve', &$boucles) .
+      ", '', " .
+      index_pile($id_boucle,  'titre', &$boucles) .
+      ", '$type', substr(lire_meta('forums_publics'),0,3)), &\$Cache)";
+    break;
+    
+  case 'rubriques':
+    $code = '
+			boutons_de_forum(' .
+      index_pile($id_boucle,  'id_rubrique', &$boucles) .
+      ", '', '', '', ''," .
+      index_pile($id_boucle,  'titre', &$boucles) .
+      ", '$type', substr(lire_meta('forums_publics'),0,3)), &\$Cache)";
+    break;
+    
+  case 'syndication':
+    $code = "
+			boutons_de_forum('', '', '','', " .
+      index_pile($id_boucle, 'id_rubrique', &$boucles) .
+      ", " .
+      index_pile($id_boucle,  'nom_site', &$boucles) .
+      ", '$type', substr(lire_meta('forums_publics'),0,3)), &\$Cache)";
+    break;
+    
+  case 'articles': 
+    $code = "
+			boutons_de_forum('', '', " .
+      index_pile($id_boucle, 'id_article', &$boucles) .
+      ", '','', " .
+      index_pile($id_boucle,  'nom_site', &$boucles) .
+      "'$type', " .
+      index_pile($id_boucle,  'accepter_forum', &$boucles) .
+      ', &$Cache)';
+    break;
+    
+  case 'forums':
+  default:
+    $code = "
+		boutons_de_forum(" .
+      index_pile($id_boucle, 'id_rubrique', &$boucles) . ', ' .
+      index_pile($id_boucle, 'id_forum', &$boucles) . ', ' .
+      index_pile($id_boucle, 'id_article', &$boucles) . ', ' .
+      index_pile($id_boucle, 'id_breve', &$boucles) . ', ' .
+      index_pile($id_boucle, 'id_syndic', &$boucles) . ', ' .
+      index_pile($id_boucle, 'titre', &$boucles) .
+      ", '$type', '', &\$Cache)";
+    break;
+  }
+  list($c,$m) = applique_filtres($fonctions, $code, $id_boucle, $boucles, $id_mere);
+  return array($c,$milieu . $m);
+}
+
+function calculer_champ_PARAMETRES_FORUM($fonctions, $nom_champ, $id_boucle, &$boucles, $id_mere)
+{
+  $milieu = '
+		$forums_publics = ((' .
+    index_pile($id_boucle,  "accepter_forum", &$boucles) . ' == ""
+				AND lire_meta("forums_publics") != "non")
+			OR (' .
+    index_pile($id_boucle,  "accepter_forum", &$boucles) . ' != ""
+				AND ' .
+    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 = rawurlencode($lien); ';
+  switch ($boucles[$id_boucle]->type_requete) {
+  case 'articles':
+    $c = '"id_article=".' .
+      index_pile($id_boucle,  id_article, &$boucles);
+    break;
+  case 'breves':
+    $c = '"id_breve=".' .
+      index_pile($id_boucle,  id_breve, &$boucles);
+    break;
+  case 'rubriques':
+    $c = '"id_rubrique=".' .
+      index_pile($id_boucle,  id_rubrique, &$boucles);
+    break;
+  case 'syndication':
+    $c = '"id_syndic=".' .
+      index_pile($id_boucle,  id_syndic, &$boucles);
+    break;
+  case 'forums':
+  default:
+    $liste_champs = array ("id_article","id_breve","id_rubrique","id_syndic","id_forum");
+    $c="";$s="";
+    while (list(,$champ) = each ($liste_champs)) {
+      $x = index_pile($id_boucle,  $champ, &$boucles);
+      $c .= (($c) ? ".\n" : "") . 
+		        "((!$x) ? '' : ('$s$champ='.$x))";
+      $s="&";}
+    break;
+  }
+  $milieu .= "}\n";
+  $code = "(!\$forums_publics) ? '' :
+ 			($c .\n" . '"&cache=".$Cache[cache] .' . "\n\"&retour=\$lien\")";
+  
+  list($c,$m) = applique_filtres($fonctions, $code, $id_boucle, $boucles, $id_mere);
+  return array($c,$milieu . $m);
+}
+
+?>
diff --git a/inc-formulaires.php3 b/inc-formulaires.php3
index f1aec7931e..40e9a2eb87 100644
--- a/inc-formulaires.php3
+++ b/inc-formulaires.php3
@@ -260,7 +260,7 @@ function reponse_signature($id_article) {
 
 function formulaire_signature($id_article) {
 	include_ecrire("inc_texte.php3");
-
+	include_ecrire("inc_mail.php3");
 	$query_petition = "SELECT * FROM spip_petitions WHERE id_article=$id_article";
 	$result_petition = spip_query($query_petition);
 
@@ -317,6 +317,7 @@ function formulaire_signature($id_article) {
 
 // inscrire les visiteurs dans l'espace public (statut 6forum) ou prive (statut nouveau->1comite)
 function formulaire_inscription($type) {
+  include_ecrire("inc_mail.php3");
 	$request_uri = $GLOBALS["REQUEST_URI"];
 	global $mail_inscription;
 	global $nom_inscription;
@@ -406,6 +407,7 @@ function formulaire_inscription($type) {
 
 
 function formulaire_site($la_rubrique) {
+  include_ecrire("inc_mail.php3");
 	$request_uri = $GLOBALS["REQUEST_URI"];
 	global $nom_site;
 	global $url_site;
diff --git a/inc-forum.php3 b/inc-forum.php3
index 57b8d8b5ba..bf2d813a1a 100644
--- a/inc-forum.php3
+++ b/inc-forum.php3
@@ -5,15 +5,14 @@
 if (defined("_INC_FORUM")) return;
 define("_INC_FORUM", "1");
 
-
-include_ecrire("inc_meta.php3");
-include_ecrire("inc_admin.php3");
-include_ecrire("inc_acces.php3");
-include_ecrire("inc_texte.php3");
-include_ecrire("inc_filtres.php3");
-include_ecrire('inc_lang.php3');	// pour lang_select
-include_ecrire("inc_mail.php3");
-include_ecrire("inc_barre.php3");
+include_ecrire('inc_meta.php3');
+include_ecrire('inc_admin.php3');
+include_ecrire('inc_acces.php3');
+include_ecrire('inc_texte.php3');
+include_ecrire('inc_filtres.php3');
+include_ecrire('inc_lang.php3');
+include_ecrire('inc_mail.php3');
+include_ecrire('inc_barre.php3');
 
 if (@file_exists("inc-urls.php3")) {
 	include_local ("inc-urls.php3");
@@ -22,179 +21,83 @@ else {
 	include_local ("inc-urls-dist.php3");
 }
 
-// dupliquee dans ecrire/articles.php3 ; mais je ne sais pas ou l'installer (Fil)...
-function get_forums_publics($id_article=0) {
-	$forums_publics = lire_meta("forums_publics");
-	if ($id_article) {
-		$query = "SELECT accepter_forum FROM spip_articles WHERE id_article=$id_article";
-		$res = spip_query($query);
-		if ($obj = spip_fetch_object($res))
-			$forums_publics = $obj->accepter_forum;
-	} else {
-		$forums_publics = substr(lire_meta("forums_publics"),0,3);
-	}
-	return $forums_publics;
-}
+// fabrique un bouton d'attribut Name $n, d'attribut Value $v et autres $a
 
-function afficher_petits_logos_mots($id_mot) {
-	$racine = "IMG/moton$id_mot";
-	if (@file_exists("$racine.gif")) {
-		$image = "$racine.gif";
-	} elseif (@file_exists("$racine.jpg")) {
-		$image = "$racine.jpg";
-	} elseif (@file_exists("$racine.png")) {
-		$image = "$racine.png";
-	}
-
-	if ($image) {
-		$taille = getimagesize($image);
-		$largeur = $taille[0];
-		$hauteur = $taille[1];
-		if ($largeur < 100 AND $hauteur < 100)
-			return "<IMG SRC='$image' align='middle' WIDTH='$largeur' HEIGHT='$hauteur' HSPACE='1' VSPACE='1' ALT=' ' BORDER=0 class='spip_image'> ";
-		else return "";
-	} else {
-		return "";
-	}
+function boutonne($a, $n, $v) {
+     return "\n<input $a name='$n' value=\"$v\" />";
 }
 
+// Re'ponse a` un forum 
 
-function decoder_hash_forum($email, $hash) {
-	if (!$email OR !$hash) return false;
-	$query = "SELECT * FROM spip_auteurs WHERE email='$email'";
-	$result = spip_query($query);
-	while ($row = spip_fetch_array($result)) {
-		if (verifier_action_auteur("forum public $email", $hash, $row['id_auteur'])) {
-			$ok = true;
-			break;
-		}
-	}
-	if ($ok) return $row;
-	else return false;
-}
-
-
-function forum_abonnement($retour) {
-	if ($GLOBALS['auteur_session'])
-		return true;	// autoriser le formulaire
-	else {
-		include_local("inc-login.php3");
-
-		$message_login = _T('forum_vous_enregistrer').'<a href="spip_pass.php3" target="spip_pass" onclick="'
-			."javascript:window.open(this.href, 'spip_pass', 'scrollbars=yes, resizable=yes, width=480, height=450'); return false;\">"
-			._T('forum_vous_inscrire')."<br>\n";
-		login('', false, $message_login);
-		return false;
-	}
-}
+function retour_forum($id_rubrique, $id_parent, $id_article, $id_breve, $id_syndic, $titre, $table, $forums_publics, $url, $hidden) {
 
-
-//
-// Afficher le formulaire d'edition de forum en fonction du contexte
-//
-
-function retour_forum($id_rubrique, $id_parent, $id_article, $id_breve, $id_syndic, $titre='') {
-	global $REQUEST_URI, $HTTP_GET_VARS, $PATH_TRANSLATED, $REMOTE_ADDR, $id_message;
-	global $new, $redac, $afficher_groupe, $afficher_texte;
-	global $spip_forum_user;
-
-	$forums_publics = get_forums_publics($id_article);
-	if ($forums_publics == "non") return;
-
-	$lien = substr($REQUEST_URI, strrpos($REQUEST_URI, '/') + 1);
-
-	$retour = $HTTP_GET_VARS['retour'];
-	if (!$retour)
-		$retour = rawurlencode($lien);
-
-	if ($forums_publics == 'abo') {
-		if (!forum_abonnement($retour)) return;
-	}
-
-	$ret .= "\n<a name='formulaire_forum'></a>\n";
-
-	if ($forums_publics == "pri") {
-		$ret.= _T('forum_info_modere')."<p>";
-	}
+	global $REMOTE_ADDR, $id_message, $afficher_texte, $spip_forum_user;
 
 	// Recuperer le message a previsualiser
-	if ($id_message = intval($id_message)) {
-		$query_forum="SELECT * FROM spip_forum WHERE ip=\"$REMOTE_ADDR\" AND id_forum=$id_message";
-		$result_forum=spip_query($query_forum);
-
-		while($row = spip_fetch_array($result_forum)) {
-			$titre=$row['titre'];
-			$texte=$row['texte'];
-			$auteur=$row['auteur'];
-			$email_auteur=$row['email_auteur'];
-			$nom_site_forum=$row['nom_site'];
-			$url_site=$row['url_site'];
-		}
+	if ($id_message = intval($GLOBALS[HTTP_POST_VARS][id_message]))  {
+		$titre = $GLOBALS[HTTP_POST_VARS][titre];
+		$texte = $GLOBALS[HTTP_POST_VARS][texte];
+		$auteur = $GLOBALS[HTTP_POST_VARS][auteur];
+		$email_auteur = $GLOBALS[HTTP_POST_VARS][email_auteur];
+		$nom_site_forum = $GLOBALS[HTTP_POST_VARS][nom_site_forum];
+		$url_site = $GLOBALS[HTTP_POST_VARS][url_site];
 
 		if ($afficher_texte != 'non') {
-			$lien = ereg_replace("\&", "&amp;", $lien);
-
-			$ret .= "\n<form action='$lien' name='formulaire' method='post'>";
-			$ret .= "<div class='spip_encadrer'>";
-			if ($afficher_texte != "non"){
-				$ret .= "<div style='font-size: 120%; font-weigth: bold;'>".typo($titre)."</div>";
-				$ret .= "<p /><b><a href='mailto:".entites_html($email_auteur)."'>".typo($auteur)."</a></b>";
-				$ret .= "<p />".propre($texte)."<p />";
-			}
-
-			$ret .= "<a href='".entites_html($url_site)."'>".typo($nom_site_forum)."</a>";
+			$bouton = 
+			  "<div style='font-size: 120%; font-weigth: bold;'>" .
+			  typo($titre) .
+			  "</div><p /><b><a href='mailto:" .
+			  entites_html($email_auteur) .
+			  "'>" .
+			  typo($auteur) .
+			  "</a></b><p />" .
+			  propre($texte) .
+			  "<p /><a href='" .
+			  entites_html($url_site) .
+			  "'>" .
+			  typo($nom_site_forum) .
+			  "</a>";
 
 			// Verifier mots associes au message
-			$query_mots = "SELECT mots.* FROM spip_mots_forum AS lien, spip_mots AS mots WHERE id_forum='$id_message' AND mots.id_mot = lien.id_mot GROUP BY mots.id_mot";
-			$result_mots = spip_query($query_mots);
-			if (spip_num_rows($result_mots)>0) {
-				$ret .= "<p>"._T('forum_avez_selectionne')."</p>";
-				$ret .= "<ul>";
-				while ($row = spip_fetch_array($result_mots)) {
-					$id_mot = $row['id_mot'];
-					$type_mot = $row['type'];
-					$titre_mot = $row['titre'];
-					$les_mots[$id_mot] = true;
-					$presence_mots = true;
-	
-					$ret.= "<li class='font-size=80%'> $type_mot&nbsp;: <b>$titre_mot</b></li>\n";
-				}
-				$ret .= "</ul>";
-			}
-			
+			$result_mots = spip_query("
+SELECT	mots.id_mot, mots.titre, mots.type
+FROM	spip_mots_forum AS lien,
+	spip_mots AS mots 
+WHERE	id_forum='$id_message'
+    AND mots.id_mot = lien.id_mot 
+GROUP BY mots.id_mot
+");
+			if (spip_num_rows($result_mots)>0) 
+			  {
+			    $bouton .= "<p>".
+			      _T('forum_avez_selectionne') .
+			      "</p><ul>";
+			    while ($row = spip_fetch_array($result_mots)) {
+			      $les_mots[$row['id_mot']] = "checked='checked'";
+			      $presence_mots = true;
+			      $bouton .= "<li class='font-size=80%'> ".
+				$row['type'] .
+				"&nbsp;: <b>" .
+				$row['titre'] . 
+				"</b></li>";
+			    }
+			    $bouton .= '</ul>';
+			  }
+
 			if (strlen($texte) < 10 AND !$presence_mots) {
-				$ret .= "<p align='right' style='color: red;'>"._T('forum_attention_dix_caracteres')."</p>\n";
+				$bouton .= "<p align='right' style='color: red;'>"._T('forum_attention_dix_caracteres')."</p>\n";
 			}
 			else if (strlen($titre) < 3 AND $afficher_texte <> "non") {
-				$ret .= "<p align='right' style='color: red;'><font color=\"red\">"._T('forum_attention_trois_caracteres')."</p>\n";
+				$bouton .= "<p align='right' style='color: red;'>"._T('forum_attention_trois_caracteres')."</p>";
 			}
 			else {
-				$ret .= "\n<div align='right'><input type='submit' name='confirmer' class='spip_bouton' value='"._T('forum_message_definitif')."' /></div>";
+				$bouton .= "<div align='right'><input type='submit' name='confirmer' class='spip_bouton' value='"._T('forum_message_definitif')."' /></div>";
 			}
-			$ret .= "</div>\n<br />";
-		}
-	}
-	else {
-		// Si premiere edition, initialiser le titre et l'auteur
-		if (!$titre) {
-			if ($id_parent)
-				$titre_select = "SELECT titre FROM spip_forum WHERE id_forum = $id_parent AND statut='publie'";
-			else if ($id_rubrique)
-				$titre_select = "SELECT titre FROM spip_rubriques WHERE id_rubrique = $id_rubrique AND statut='publie'";
-			else if ($id_article)
-				$titre_select = "SELECT titre FROM spip_articles WHERE id_article = $id_article AND statut='publie'";
-			else if ($id_breve)
-				$titre_select = "SELECT titre FROM spip_breves WHERE id_breve = $id_breve AND statut='publie'";
-			else if ($id_syndic)
-				$titre_select = "SELECT nom_site AS titre FROM spip_syndic WHERE id_syndic = $id_syndic AND statut='publie'";
-			else
-				$titre_select = "SELECT '".addslashes(_T('forum_titre_erreur'))."' AS titre";
-
-			if ($res = spip_fetch_object(spip_query($titre_select)))
-				$titre = '> ' . supprimer_numero(ereg_replace ('^[>[:space:]]*', '', $res->titre));
-			else
-				$titre = _T('forum_titre_erreur');
+			$bouton = "<div class='spip_encadrer'>$bouton</div>\n<br />";
 		}
+	} else {
+		// Si premiere edition, initialiser l'auteur
+	  	// puis s'accorder une nouvelle entre'e dans la table
 		if ($spip_forum_user && is_array($cookie_user = unserialize($spip_forum_user))) {
 			$auteur = $cookie_user['nom'];
 			$email_auteur = $cookie_user['email'];
@@ -203,348 +106,159 @@ function retour_forum($id_rubrique, $id_parent, $id_article, $id_breve, $id_synd
 			$auteur = $GLOBALS['auteur_session']['nom'];
 			$email_auteur = $GLOBALS['auteur_session']['email'];
 		}
-		$lien = ereg_replace("\&", "&amp;", $lien);
-		$ret .= "\n<form action='$lien' name='formulaire' method='post'>";
-	}
-
-	$ret .= "\n";
-
-	// Generation d'une valeur de securite pour validation
-	$seed = (double) (microtime() + 1) * time() * 1000000;
-	@mt_srand($seed);
-	$alea = @mt_rand();
-	if (!$alea) {
-		srand($seed);
-		$alea = rand();
+		spip_query("
+INSERT INTO spip_forum (date_heure, titre, ip, statut)
+VALUES (NOW(), \"".addslashes($titre)."\", \"$REMOTE_ADDR\", \"redac\")
+");
+		$id_message = spip_insert_id();
 	}
-	$id_rubrique = intval($id_rubrique);
-	$id_parent = intval($id_parent);
-	$id_article = intval($id_article);
-	$id_breve = intval($id_breve);
-	$id_syndic = intval($id_syndic);
-	$hash = calculer_action_auteur("ajout_forum $id_rubrique $id_parent $id_article $id_breve $id_syndic $alea");
 
-	// Afficher le formulaire d'edition
+	        // Generation d'une valeur de securite pour validation
+        $seed = (double) (microtime() + 1) * time() * 1000000;
+        @mt_srand($seed);
+        $alea = @mt_rand();
+        if (!$alea) {srand($seed);$alea = rand();}
+        $forum_id_rubrique = intval($id_rubrique);
+        $forum_id_parent = intval($id_parent);
+        $forum_id_article = intval($id_article);
+        $forum_id_breve = intval($id_breve);
+        $forum_id_syndic = intval($id_syndic);
+        $hash = calculer_action_auteur("ajout_forum $forum_id_rubrique $forum_id_parent $forum_id_article $forum_id_breve $forum_id_syndic $alea");
 	$titre = entites_html($titre);
-	$texte = entites_html($texte);
-
-	if ($afficher_texte == "non"){
-		$ret .= "\n<input type='hidden' name='titre' VALUE=\"$titre\" />";
-	}
-	else {
-		$ret .= "\n<div class='spip_encadrer'><b>"._T('forum_titre')."</b><br />";
-		$ret .= "\n<input type='text' class='forml' name='titre' value=\"$titre\" size='40' /></div>";
-	}
-
-	$ret .= "\n<input type='hidden' name='id_message' value=\"$id_message\" />";
-	$ret .= "\n<input type='hidden' name='ajout_forum' value=\"oui\" />";
-	$ret .= "\n<input type='hidden' name='forum_id_rubrique' value=\"$id_rubrique\" />";
-	$ret .= "\n<input type='hidden' name='forum_id_parent' value=\"$id_parent\" />";
-	$ret .= "\n<input type='hidden' name='forum_id_article' value=\"$id_article\" />";
-	$ret .= "\n<input type='hidden' name='forum_id_breve' value=\"$id_breve\" />";
-	$ret .= "\n<input type='hidden' name='forum_id_syndic' value=\"$id_syndic\" />";
-	$ret .= "\n<input type='hidden' name='alea' value=\"$alea\" />";
-	$ret .= "\n<input type='hidden' name='hash' value=\"$hash\" />";
-	$retour = ereg_replace("\&", "&amp;", $retour);
-	$ret .= "\n<input type='hidden' name='retour_forum' value=\"$retour\" />";
-
-	if ($new != "oui" AND $redac != "oui") $ret .= "\n<input type='hidden' name='new' value=\"oui\" />";
-	if ($new == "oui") $ret .= "\n<input type='hidden' name='redac' value=\"oui\" />";
-
-	if ($afficher_texte != "non"){
-		$ret .= "\n<br /><div class='spip_encadrer'><b>"._T('forum_texte')."</b><br />\n";
-		$ret .= _T('forum_creer_paragraphes');
-		$ret .= "<br />\n";
-		$ret .= afficher_barre('formulaire', 'texte', true);
-		$ret .= "<textarea name='texte' ".afficher_claret()." rows='12' class='forml' cols='40'>";
-		$ret.= $texte;
-		$ret .= "\n</textarea></div>\n";
-	}
-
-
-	// Gestion des mots-cles
-
-	$mots_cles_forums=lire_meta("mots_cles_forums");
-	if ($mots_cles_forums == "oui"){
-		if ($id_rubrique > 0) $table = "rubriques";
-		else if ($id_article > 0) $table = "articles";
-		else if ($id_breve > 0) $table = "breves";
-		else if ($id_syndic > 0) $table = "syndic";
-
-
-		if ($afficher_groupe) {
-			$afficher_groupe = join($afficher_groupe, ",");
-			$selectionner_groupe = "AND id_groupe IN ($afficher_groupe)";
-		}
-		if ($table){
-			$query_groupe = "SELECT * FROM spip_groupes_mots WHERE 6forum = 'oui' AND $table = 'oui' $selectionner_groupe";
-			$result_groupe = spip_query($query_groupe);
-			while ($row_groupe = spip_fetch_array($result_groupe)) {
-				$id_groupe = $row_groupe['id_groupe'];
-				$titre_groupe = propre($row_groupe['titre']);
-				$unseul_groupe = $row_groupe['unseul'];
-
-				$query = "SELECT * FROM spip_mots WHERE id_groupe='$id_groupe'";
-				$result = spip_query($query);
-				$total_rows = spip_num_rows($result);
-
-				if ($total_rows > 0){
-					$ret .= "\n<p /><div class='spip_encadrer' style='font-size: 80%;'>";
-					$ret.= "<b>$titre_groupe&nbsp;:</b>";
-
-					$ret .= "<table cellpadding='0' cellspacing='0' border='0' width='100%'>\n";
-					$ret .= "<tr><td width='47%' valign='top'>";
-					$i = 0;
-
-					while ($row = spip_fetch_array($result)) {
-						$id_mot = $row['id_mot'];
-						$titre_mot = propre($row['titre']);
-						$type_mot = propre($row['type']);
-						$descriptif_mot = propre($row['descriptif']);
-
-						if ($i >= ($total_rows/2) AND $i < $total_rows){
-							$i = $total_rows + 1;
-							$ret .= "</td><td width='6%'>&nbsp;</td><td width='47%' valign='top'>";
-						}
-
-						if ($les_mots[$id_mot]) $checked = "checked='checked'";
-						else $checked = "";
-
-						if ($unseul_groupe == 'oui'){
-							$ret .= "<input type='radio' name='ajouter_mot[$id_groupe][]' value='$id_mot' $checked id='mot$id_mot' /> ";
-						}
-						else {
-							$ret .= "<input type='checkbox' name='ajouter_mot[$id_groupe][]' value='$id_mot' $checked id='mot$id_mot' /> ";
-						}
-
-						$ret .=  afficher_petits_logos_mots($id_mot);
-						$ret .= "<b><label for='mot$id_mot'>$titre_mot</label></b><br />";
-						if (strlen($descriptif_mot) > 0) $ret .= "$descriptif_mot<br />";
-						$i++;
-					}
-
-					$ret .= "</td></tr></table>";
-
-					$ret .= "</div>";
-				}
-			}
-		}
-	}
-
-	// Edition du texte du forum
-	if ($afficher_texte != "non") {
-		$ret .= "\n<br /><div class='spip_encadrer'>"._T('forum_lien_hyper')."<br />\n";
-		$ret .= _T('forum_page_url');
-		$ret .= "<br />\n"._T('forum_titre');
-		$ret .= "<br />\n<input type='text' class='forml' name='nom_site_forum' value=\"".entites_html($nom_site_forum)."\" size='40' /><br />";
-
-		if (!$url_site) $url_site = "http://";
-		$ret .= "\n"._T('forum_url');
-		$ret .= "<br />\n<input type='text' class='forml' name='url_site' value=\"".entites_html($url_site)."\" size='40' /></div>";
-
-		$ret .= "\n<br /><div class='spip_encadrer'>"._T('forum_qui_etes_vous')."<br />";
-
-		if ($forums_publics == "abo")
-			$disabled = ' disabled="disabled"';
-
-		$ret .= "\n"._T('forum_votre_nom');
-		$ret .= "<br />\n<input type='text' class='forml' name='auteur' value=\"".entites_html($auteur)."\" size='40'$disabled /><br />\n";
-
-		$ret .= _T('forum_votre_email');
-		$ret .= "<br />\n<input type='text' class='forml' name='email_auteur' value=\"".entites_html($email_auteur)."\" size='40'$disabled /></div>";
-	}
-
-	// Bouton de validation
-	if ($afficher_texte !="non") $ret .= "\n<br /><div align='right'><input type='submit' name='Valider' class='spip_bouton' value='"._T('forum_voir_avant')."' /></div>";
-	else  $ret .= "\n<br /><div align='right'><input type='submit' name='Valider' class='spip_bouton' value='"._T('forum_valider')."' /></div>";
-
-	$ret .= "</form>";
-
-	return $ret;
+	if (!$url_site) $url_site = "http://";
+	if ($forums_publics == "abo") $disabled = " disabled='disabled'";
+
+	if ((lire_meta("mots_cles_forums") == "oui") && ($table != 'forum'))
+	  $table= table_des_mots($table, $les_mots);
+	else $table = '';
+
+	return ("<form action='$url' method='post'>\n$hidden" .
+		boutonne("type='hidden'", 'id_message', $id_message) .
+		boutonne("type='hidden'", 'alea', $alea) .
+                boutonne("type='hidden'", 'hash', $hash) .
+  		(($afficher_texte == "non") ?
+		 (boutonne("type='hidden'", 'titre', $titre) .
+		  $table .
+		  "\n<br /><div align='right'>" .
+		  boutonne("type='submit' class='spip_bouton'",
+			   'Valider',
+			   _T('forum_valider'). "</div>")) :
+		 ($bouton . "
+	<div class='spip_encadrer'><b>"._T('forum_titre')."</b>\n<br />" .
+		  boutonne("type='text' class='forml' size='40'", 'titre', $titre) . "
+	</div>
+	\n<br /><div class='spip_encadrer'><b>" .
+		  _T('forum_texte') .
+		  "</b>\n<br />" .
+		  _T('forum_creer_paragraphes') .
+		  "\n<br /> " .
+#		  afficher_barre('formulaire', 'texte', true) .
+		  "<textarea name='texte' " .
+		  afficher_claret() .
+		  " rows='12' class='forml' cols='40'>" .
+		  entites_html($texte) .
+		  "</textarea></div>" .
+		  $table  .
+		 "\n<br /><div class='spip_encadrer'>" .
+		  _T('forum_lien_hyper') .
+		  "\n<br />" .
+		  _T('forum_page_url') .
+		  "\n<br />" .
+		  _T('forum_titre') .
+		  "\n<br />" .
+		  boutonne("type='text' class='forml' size='40'",
+			   'nom_site_forum',
+			   entites_html($nom_site_forum)) .
+		  "\n<br />" .
+		  _T('forum_url') .
+		  "\n<br />" .
+		  boutonne("type='text' class='forml'  size='40'", 
+			   'url_site',
+			   entites_html($url_site)) .
+		  "</div>\n<br /><div class='spip_encadrer'>" .
+		  _T('forum_qui_etes_vous') .
+		  "\n<br />" .
+		  _T('forum_votre_nom') .
+		  "\n<br />" .
+		  boutonne("type='text' class='forml' size='40'$disabled",
+			   'auteur',
+			   entites_html($auteur)) .
+		  "\n<br />" .
+		  _T('forum_votre_email') .
+		  "\n<br />" .
+		  boutonne("type='text' class='forml' size='40'$disabled",
+			   'email_auteur',
+			   entites_html($email_auteur)) .
+		  "</div>\n<br /><div align='right'>" .
+		  boutonne("type='submit' class='spip_bouton'",
+			   'Valider',
+			   _T('forum_voir_avant')) . 
+		  "</div>\n</form>")));
 }
 
-
-//
-// Fonction appelee a l'ajout d'un message
-// (previsualisation et validation finale)
-//
-
-function ajout_forum() {
-	global $texte, $titre, $nom_site_forum, $url_site, $auteur, $email_auteur, $retour_forum, $id_message, $confirmer;
-	global $forum_id_rubrique, $forum_id_parent, $forum_id_article, $forum_id_breve, $forum_id_syndic, $alea, $hash;
-	global $auteur_session;
-	global $ajouter_mot, $new;
-	global $REQUEST_URI, $HTTP_COOKIE_VARS, $REMOTE_ADDR;
-	global $afficher_texte;
-
-	if (!$GLOBALS['db_ok']) {
-		die ("<h4>"._T('forum_probleme_database')."</h4>");
-	}
-
-	$texte = addslashes($texte);
-	$titre = addslashes($titre);
-	$nom_site_forum = addslashes($nom_site_forum);
-	$url_site = addslashes($url_site);
-	$auteur = addslashes($auteur);
-	$email_auteur = addslashes($email_auteur);
-	$id_message = intval($id_message);
-	$retour_forum = rawurldecode($retour_forum);
-	$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);
-
-	$forums_publics = get_forums_publics($forum_id_article);
-	$validation_finale = (strlen($confirmer) > 0 OR ($afficher_texte=='non' AND $ajouter_mot));
-
-	// Gestion forums sur abonnement
-	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 le forum est sur abonnement
-		$auteur = $auteur_session['nom'];
-		$email_auteur = $auteur_session['email'];
-	}
-
-	// Verification des donnees et gestion du cache
-	if ($validation_finale) {
-		if (!verifier_action_auteur("ajout_forum $forum_id_rubrique $forum_id_parent $forum_id_article $forum_id_breve $forum_id_syndic $alea", $hash)) {
-			@header("Location: $retour_forum");
-			exit;
-		}
-		if ((strlen($texte) + strlen($titre) + strlen($nom_site_forum) + strlen($url_site) + strlen($auteur) + strlen($email_auteur)) > 20 * 1024) {
-			die ("<h4>"._T('forum_message_trop_long')."</h4>\n" .
-			_T('forum_cliquer_retour', array('retour_forum' => $retour_forum))."<p>");
-		}
-
-		unset($where);
-		if ($forum_id_article) $where[] = "id_article=$forum_id_article";
-		if ($forum_id_rubrique) $where[] = "id_rubrique=$forum_id_rubrique";
-		if ($forum_id_breve) $where[] = "id_breve=$forum_id_breve";
-		if ($forum_id_parent) $where[] = "id_forum=$forum_id_parent";
-		if ($where) {
-			$query = "SELECT fichier FROM spip_forum_cache WHERE ".join(' OR ', $where);
-			$result = spip_query($query);
-			unset($fichiers);
-			while ($row = spip_fetch_array($result)) {
-				$fichier = $row["fichier"];
-				@unlink("CACHE/$fichier");
-				@unlink("CACHE/$fichier.NEW");
-				$fichiers[] = "'".$fichier."'";
-			}
-			if ($fichiers) {
-				$fichiers = join(',', $fichiers);
-				$query = "DELETE FROM spip_forum_cache WHERE fichier IN ($fichiers)";
-				spip_query($query);
-			}
-		}
-	}
-
-	switch ($forums_publics) {
-		case "non":
-			$etat = "off";
-			break;
-		case "pri":
-			$etat = "prop";
-			break;
-		default:
-			$etat = "publie";
-			break;
-	}
-
-	if (!$id_auteur) $id_auteur = $GLOBALS['auteur_session']['id_auteur'];
-
-	if ($new == "oui") {
-		$nouveau_document = true;
-		if ($HTTP_GET_VARS['titre']){
-			$titre = "> ".rawurldecode($HTTP_GET_VARS['titre']);
-		}
-		$query_forum = "INSERT INTO spip_forum (date_heure, titre, ip, statut)
-			VALUES (NOW(), \"".addslashes($titre)."\", \"$REMOTE_ADDR\", \"redac\")";
-		$result_forum = spip_query($query_forum);
-		$id_message = spip_insert_id();
-	}
-
-	// Ajouter les mots-cles
-	$query_mots = "DELETE FROM spip_mots_forum WHERE id_forum='$id_message'";
-	$result_mots = spip_query($query_mots);
-	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')");
-		}
-
+function table_des_mots($table, $les_mots) {
+  global $afficher_groupe;
+
+  $result_groupe = spip_query("
+SELECT * 
+FROM spip_groupes_mots 
+WHERE 6forum = 'oui' 
+AND $table = 'oui' " . ((!$afficher_groupe) ? '' : ("
+AND id_groupe IN (" . join($afficher_groupe, ", ")))
+);
+  
+  $ret = '';
+  while ($row_groupe = spip_fetch_array($result_groupe)) {
+    $id_groupe = $row_groupe['id_groupe'];
+    $titre_groupe = propre($row_groupe['titre']);
+    $unseul = ($row_groupe['unseul']== 'oui') ? 'radio' : 'checkbox';
+    $result =spip_query("SELECT * FROM spip_mots WHERE id_groupe='$id_groupe'");
+    $total_rows = spip_num_rows($result);
+    
+    if ($total_rows > 0){
+      $ret .= "\n<p /><div class='spip_encadrer' style='font-size: 80%;'>";
+      $ret.= "<b>$titre_groupe&nbsp;:</b>";
+      $ret .= "<table cellpadding='0' cellspacing='0' border='0' width='100%'>\n";
+      $ret .= "<tr><td width='47%' valign='top'>";
+      $i = 0;
+      
+      while ($row = spip_fetch_array($result)) {
+	$id_mot = $row['id_mot'];
+	$titre_mot = propre($row['titre']);
+	$descriptif_mot = propre($row['descriptif']);
+	
+	if ($i >= ($total_rows/2) AND $i < $total_rows)
+	  {
+	    $i = $total_rows + 1;
+	    $ret .= "</td><td width='6%'>&nbsp;</td><td width='47%' valign='top'>";
 	}
+	
+	$ret .= boutonne("type='$unseul' id='mot$id_mot' " . $les_mots[$id_mot],
+			 "ajouter_mot[$id_groupe][]", 
+			 $id_mot) .
+	  afficher_petits_logos_mots($id_mot) .
+	  "<b><label for='mot$id_mot'>$titre_mot</label></b><br />";
+	if (strlen($descriptif_mot) > 0) $ret .= "$descriptif_mot<br />";
+	$i++;
+      }
+      
+      $ret .= "</td></tr></table>";
+      $ret .= "</div>";
+    }
+  }
+  return $ret;
+}
 
-	$query_forum = "UPDATE spip_forum
-		SET id_parent = $forum_id_parent, id_rubrique =$forum_id_rubrique, id_article = $forum_id_article, id_breve = $forum_id_breve, id_syndic = \"$forum_id_syndic\",
-			date_heure = NOW(), titre = \"$titre\", texte = \"$texte\", nom_site = \"$nom_site_forum\", url_site = \"$url_site\", auteur = \"$auteur\",
-			email_auteur = \"$email_auteur\",  ip = \"$REMOTE_ADDR\", statut = \"redac\", id_auteur = \"$id_auteur\"
-		WHERE id_forum = '$id_message'";
-	$result_forum = spip_query($query_forum);
-
-	if ($validation_finale) {
-		spip_query("UPDATE spip_forum SET statut=\"$etat\" WHERE id_forum='$id_message'");
-
-		$texte = stripslashes($texte);
-		$titre = stripslashes($titre);
-		$auteur = stripslashes($auteur);
-		$email_auteur = stripslashes($email_auteur);
-
-		// 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);
-				}
-			}
-		}
-
-		@header("Location: $retour_forum");
-		exit;
-	}
+function afficher_petits_logos_mots($id_mot) {
+  $image = cherche_image_nommee("moton$id_mot", $GLOBALS['dossier_images']);
+  if ($image) {
+    $taille = getimagesize($image);
+    $largeur = $taille[0];
+    $hauteur = $taille[1];
+    if ($largeur < 100 AND $hauteur < 100)
+      return "<img src='$image' align='middle' width='$largeur' height='$hauteur' hspace='1' vspace='1' alt=' ' border=0 class='spip_image'> ";
+  }
+  return "";
 }
 
 ?>
diff --git a/inc-html-squel.php3 b/inc-html-squel.php3
new file mode 100644
index 0000000000..baeb1ff33f
--- /dev/null
+++ b/inc-html-squel.php3
@@ -0,0 +1,324 @@
+<?php
+
+// Ce fichier ne sera execute qu'une fois
+if (defined("_INC_HTML_SQUEL")) return;
+define("_INC_HTML_SQUEL", "1");
+
+# Ce fichier doit IMPERATIVEMENT contenir la fonction "parser"
+# qui transforme un squelette en un tableau d'objets de classe Boucle
+# il est charge' par un include calcule' dans inc-calcul-squel
+# pour permettre diffe'rentes syntaxes en entre'e
+
+define(NOM_DE_BOUCLE, "[0-9]+|[-_][-_.a-zA-Z0-9]*");
+define(NOM_DE_CHAMP, "#((" . NOM_DE_BOUCLE . ":)?([A-Z_]+))(\*?)");
+define(CHAMP_ETENDU, '\[([^]\[]*)\(' . NOM_DE_CHAMP . '([^])]*)\)([^]]*)\]');
+define(PARAM_DE_BOUCLE,'\{[^}]*\}');
+define(TYPE_DE_BOUCLE, "[^)]*");
+define(BALISE_DE_BOUCLE,
+       "^<BOUCLE(" .
+       NOM_DE_BOUCLE . 
+       ')[[:space:]]*\((' . 
+       TYPE_DE_BOUCLE .
+       ')\)[[:space:]]*(([[:space:]]*' .
+       PARAM_DE_BOUCLE . 
+       ')*)[[:space:]]*>');
+
+function parser_texte($texte) {
+  while (ereg("<INCLU[DR]E[[:space:]]*\(([-_0-9a-zA-Z./ ]+)\)([^>]*)>", $texte, $match)) {
+    $s = $match[0];
+    $p = strpos($texte, $s);
+    $debut = substr($texte, 0, $p);
+    $texte = substr($texte, $p + strlen($s));
+    if ($debut)
+      {
+	$champ = new Texte;
+	$champ->texte = $debut;
+	$result[] = $champ;
+      }
+    $champ = new Inclure;
+    $champ->fichier = $match[1];
+    $p = trim($match[2]);
+    if (!$p)
+      $champ->params = '';
+    else {
+      if (!(ereg('^\\{(.*)\\}$', $p, $params)))
+	{
+	  include_local("inc-debug-squel.php3");
+	  erreur_squelette(_L("Param&egrave;tres d'inclusion incorrects"), $p,
+				$champ->fichier);
+	}
+      else $champ->params = split("\}[[:space:]]*\{", $params[1]);
+    }
+    $result[] = $champ;
+  }
+  if ($texte)
+    {
+	$champ = new Texte;
+	$champ->texte = $texte;
+	$result[] = $champ;
+    }
+
+  return $result;
+}
+
+function parser_champs($texte) {
+  global $champs_traitement, $champs_pretraitement, $champs_posttraitement;
+
+	$result=Array();
+	while (ereg(NOM_DE_CHAMP . '(.*)$', $texte, $regs))
+	  {
+	    $p = strpos($texte, $regs[0]);
+	    if ($p) 
+	      $result = array_merge($result,
+				    parser_texte(substr($texte, 0, $p)));
+	    $texte = $regs[5];
+	    $nom_champ = $regs[3];
+	    $champ = new Champ;
+	    $champ->nom_champ = $regs[1];
+	    $champ->fonctions = $champs_pretraitement[$nom_champ];
+	    if (!$regs[4] AND $champs_traitement[$nom_champ]) {
+	      reset($champs_traitement[$nom_champ]);
+	      while (list(, $f) = each($champs_traitement[$nom_champ])) {
+		$champ->fonctions[] = $f;
+		}
+	    }
+	    if ($champs_posttraitement[$nom_champ]) {
+	      reset($champs_posttraitement[$nom_champ]);
+	      while (list(, $f) = each($champs_posttraitement[$nom_champ])) {
+		$champ->fonctions[] = $f;
+	      }
+	    }
+	    $result[] = $champ;
+	  }
+	return (!$texte ?
+		$result :
+		array_merge($result, parser_texte($texte)));
+}
+
+
+function parser_champs_etendus($debut)
+{
+  $sep = '##';
+  while (strpos($debut,$sep)!== false) $sep .= '#';
+  return parser_champs_interieurs($debut, $sep, array());
+}
+
+function parser_champs_exterieurs($debut, $sep, $nested)
+{
+  $res = array();
+  foreach (split("%$sep",$debut) as $v)
+    {
+      if (!ereg("^([0-9]+)@(.*)$", $v, $m))
+	$res = array_merge($res, parser_champs($v));
+      else
+	{
+	  if ($m[2] == 'Object')
+	    $res[]= $nested[$m[1]];
+	  else
+	    $res = array_merge($res, parser_champs($m[2]));
+	}
+    }
+  return $res;
+}
+	
+
+function parser_champs_interieurs($texte, $sep, $nested)
+{
+  global $champs_traitement, $champs_pretraitement, $champs_posttraitement;
+  $result = array();
+  if (!$texte) return $result;
+  $i = 0;
+  while (ereg(CHAMP_ETENDU . '(.*)$', $texte, $regs)) {
+	  $nom_champ = $regs[4];
+	  $fonctions = $regs[6];
+	  $champ = new Champ;
+	  $champ->nom_champ = $regs[2];
+	  $champ->cond_avant = parser_champs_exterieurs($regs[1],$sep,$nested);
+
+	  $champ->cond_apres = parser_champs_exterieurs($regs[7],$sep,$nested);
+	  $champ->fonctions = $champs_pretraitement[$nom_champ];
+	  if (!$regs[5] AND $champs_traitement[$nom_champ]) {
+	    reset($champs_traitement[$nom_champ]);
+	    while (list(, $f) = each($champs_traitement[$nom_champ])) {
+	      $champ->fonctions[]= $f;
+	    }
+	  }
+	  if ($fonctions) {
+	    $fonctions = explode('|', ereg_replace("^\|", "", $fonctions));
+	    reset($fonctions);
+	    while (list(, $f) = each($fonctions)) $champ->fonctions[]= $f;
+	  }
+	  if ($champs_posttraitement[$nom_champ]) {
+	    reset($champs_posttraitement[$nom_champ]);
+	    while (list(, $f) = each($champs_posttraitement[$nom_champ])) {
+	      $champ->fonctions[]= $f;
+	    }
+	  }
+	  $p = strpos($texte, $regs[0]);
+	  if ($p) {
+	    $result[$i] = substr($texte, 0, $p);
+	    $i++;
+	  }
+	  $result[$i] = $champ;
+	  $i++;
+	  $texte = $regs[8];
+  }
+  if ($texte) {$result[$i] = $texte;$i++;}
+  $x ='';
+  $j=0;
+  while($j < $i) {$x .= "%#$sep$j@" . $result[$j];$j++;}
+  if (ereg(CHAMP_ETENDU, $x)) 
+    return (parser_champs_interieurs($x, "#$sep", $result));
+  $res2 = array();
+  foreach ($result as $k => $v)
+    {
+      if (is_object($v))
+	$res2[]= $v;
+      else
+	{ $c = parser_champs_exterieurs($v,$sep,$nested);
+	  reset($c);
+	  while (list(, $val) = each($c)) $res2[] = $val;
+	}
+    }
+  return $res2;
+}
+
+function parser_param($params, &$result, $idb) {
+      $params2 = Array();
+      $i = 1;
+      while (ereg('^[[:space:]]*\{[[:space:]]*([^ \}])([^\"\}]*)([\"\}])(.*)$', $params, $args)) {
+	if ($args[3] == "}")
+	  {
+	    $params = $args[4];
+	    ereg("^(.*[^ \t\n])[[:space:]]*$", $args[2], $m);
+	    $param = $args[1] . $m[1];
+	    if ($param == 'tout') {
+	      $result->tout = true;
+	    }
+	    else if ($param == 'plat') {
+	      $result->plat = true;
+	    }
+	    else $params2[] = $param;
+	  }
+	else
+	  { 
+	    if ($args[1] == '"')
+	      {
+		if (!ereg("[[:space:]]*\}(.*)$", $params, $m))
+		  break;
+		else
+		  {
+		    $params = $m[1];
+		    $result->separateur = 
+		      ereg_replace("'","\'",$args[2]);
+		  }
+	      }
+	    else
+	      {
+		if (!ereg("([^\"]*\"[[:space:]]*)\}(.*)$", $args[4], $m))
+		  break;
+		else
+		  {
+		    $params = $m[2];
+		    $params2[] = $args[1] . $args[2] . '"' . $m[1];
+		  }
+	      }
+	  }
+	$i++;
+      }
+      if ($params)
+	{
+	  include_local("inc-debug-squel.php3");
+	  erreur_squelette(_L("Param&egrave;tre $i (ou suivants) incorrect"),
+				$params, $idb);
+	}
+      $result->param = $params2;
+}
+
+function parser($texte, $id_parent, &$boucles) {
+
+  while (($p = strpos($texte, '<BOUCLE')) ||
+	 (substr($texte, 0, strlen('<BOUCLE')) == '<BOUCLE'))
+    {
+
+      $debut = substr($texte, 0, $p);
+      $milieu = substr($texte, $p);
+
+      if (!ereg(BALISE_DE_BOUCLE, $milieu, $match)) {
+	include_local("inc-debug-squel.php3");
+	erreur_squelette((_T('erreur_boucle_syntaxe')), $milieu,'');
+      }
+      $id_boucle = $match[1];
+
+      $result = new Boucle;
+      $result->id_parent = $id_parent;
+      $result->id_boucle = $id_boucle;
+
+      $type = strtolower($match[2]);
+      if (substr($type, 0, 6) == 'boucle') {
+	// Re'cursion: pas de parame`tre, donc presque rien a` faire  
+	$result->type_requete = 'boucle';
+	$result->param = substr($match[2], 6);
+      } else {
+	if ($type == 'sites') $type = 'syndication';
+	$result->type_requete = $type;
+	parser_param($match[3], &$result, $id_boucle);
+      }
+
+	$s = "<B$id_boucle>";
+	$p = strpos($debut, $s);
+	if ($p || (substr($debut, 0, strlen($s)) == $s)) {
+		$result->cond_avant = substr($debut, $p + strlen($s));
+		$debut = substr($debut, 0, $p);
+	}
+
+	$milieu = substr($milieu, strlen($match[0]));
+	$s = "</BOUCLE$id_boucle>";
+	$p = strpos($milieu, $s);
+	if ((!$p) && (substr($milieu, 0, strlen($s)) != $s)) 
+	  {
+	    include_local("inc-debug-squel.php3");
+	    erreur_squelette(_T('erreur_boucle_syntaxe'), '',
+				  _T('erreur_boucle_fermant',
+				     array('id'=>$id_boucle)));
+	    exit;
+	  }
+
+	$texte = substr($milieu, $p + strlen($s));
+	$milieu = substr($milieu, 0, $p);
+
+	$s = "</B$id_boucle>";
+	$p = strpos($texte, $s);
+	if ($p || (substr($texte, 0, strlen($s)) == $s)) {
+		$result->cond_fin = substr($texte, 0, $p);
+		$texte = substr($texte, $p + strlen($s));
+	}
+
+	$s = "<//B$id_boucle>";
+	$p = strpos($texte, $s);
+	if ($p || (substr($texte, 0, strlen($s)) == $s)) {
+		$result->cond_altern = substr($texte, 0, $p);
+		$texte = substr($texte, $p + strlen($s));
+	}
+
+	$result->cond_avant = parser($result->cond_avant, $id_parent,&$boucles);
+	$result->cond_apres = parser($result->cond_fin, $id_parent,&$boucles);
+	$result->cond_altern = parser($result->cond_altern, $id_parent,&$boucles);
+	$result->milieu = parser($milieu, $id_boucle,&$boucles);
+	
+	$all_res = array_merge($all_res, parser_champs_etendus($debut));
+	$all_res[] = $result;
+	if ($boucles[$id_boucle])
+	  {
+	    include_local("inc-debug-squel.php3");
+	    erreur_squelette(_T('erreur_boucle_syntaxe'), '',
+				  _T('erreur_boucle_double',
+				     array('id'=>$id_boucle)));
+	    exit;
+	  }
+	$boucles[$id_boucle] = $result;
+    }
+  return array_merge($all_res, parser_champs_etendus($texte));
+}
+
+?>
diff --git a/inc-index-squel.php3 b/inc-index-squel.php3
new file mode 100644
index 0000000000..f168a41af5
--- /dev/null
+++ b/inc-index-squel.php3
@@ -0,0 +1,144 @@
+<?php
+
+// index_pile retourne la position dans la pile du champ SQL $nom_champ 
+// en prenant la boucle la plus proche du sommet de pile (indique' par $idb).
+// Si on ne trouve rien, on conside`re que c~a doit provenir du contexte 
+// (par l'URL ou l'include) qui a e'te' recopie' dans Pile[0]
+// (un essai d'affinage a de'bouche' sur un bug vicieux)
+// Si c~a re'ference un champ SQL, on le me'morise dans la structure $boucles
+// afin de construire un requete SQL minimale (plutot qu'un brutal 'SELECT *')
+
+include_ecrire('inc_serialbase.php3');
+
+function index_pile($idb, $nom_champ, &$boucles)
+{
+   global $exceptions_des_tables, $table_des_tables, $tables_principales;
+
+  $i = 0;
+  if ($c=strpos($nom_champ, ':'))
+     {
+       $idbs = substr($nom_champ, 0, $c);
+       $nom_champ = substr($nom_champ, $c+1);
+       while (($idb != $idbs) && $idb)
+	 {$i++; $idb = $boucles[$idb]->id_parent;
+#       spip_log("Cherche en amont: $nom_champ '$idbs' '$idb' '$c'");
+	 }
+     }
+
+  $c = strtolower($nom_champ);
+  # attention a` la boucle nomme'e 0 ....
+  while ($idb!== '') {
+#       spip_log("Cherche: $nom_champ '$idb' '$c'");
+    $r = $boucles[$idb]->type_requete;
+    // indirection (pour les rares cas ou` le nom de la table est /= du type)
+    $t = $table_des_tables[$r];
+    if (!$t) $t = $r; // pour les tables non Spip
+    // $t est le nom PHP de cette table 
+    $x = $tables_principales[$t];
+    if (!$x) 
+    {
+      include_local("inc-debug-squel.php3");
+      erreur_syntaxe_boucle("Table SQL absente de \$tables_principales dans inc_serialbase", $r, $idb);
+    }
+
+    $a = $x['field'];
+    $e = $a[$c];
+#    spip_log("	Dans $idb ($t $e): $x");    
+    // $e est le type SQL de l'entre'e (on s'en sert comme boole'en uniquement)
+      if ($e)
+      // entite' SPIP homonyme au champ SQL
+      { $e = $c; }
+    else
+      {
+      // entite' SPIP alias d'un champ SQL
+	$e = $exceptions_des_tables[$r][$c];
+	if (is_array($e))
+      // entite' SPIP dans une table SQL annexe qu'il faut pre'ciser
+	  { $t = $e[0]; $e = $e[1]; } }
+    if ($e)
+      {
+	$boucles[$idb]->select[] = $t . "." . $e;
+	return ('$PileRow[$SP' .
+		($i ? "-$i" : "") . '][' .
+		$e . 
+		"]");
+	    }
+    $idb = $boucles[$idb]->id_parent;
+    $i++;
+  }
+#  spip_log("Pas vu $nom_champ dans les " . count($boucles) . " boucles");
+  # espe'rons qu'il y sera
+  return('$PileRow[0]['.$nom_champ.']');
+}
+
+# calculer_champ genere le code PHP correspondant a la balise Spip $nom_champ
+# Retourne un tableau dont le premier e'le'ment est une EXPRESSION php 
+# et le deuxie`me une suite d'INSTRUCTIONS a` exe'cuter AVANT de calculer
+# l'expression (typiquement: un include ou une affectation d'auxiliaires)
+# Ce tableau est e'galement retourne' par la fonction applique_filtres
+# qui s'occupe de construire l'application 
+# s'il existe une fonction nomme'e "calculer_champ_" suivi du nom du champ,
+# on lui passe la main et elle est cense' retourner le tableau ci-dessus
+# (Essayer de renvoyer une suite vide, c~a diminue les allocations a` l'exec)
+
+function calculer_champ($fonctions, $nom_champ, $id_boucle, &$boucles, $id_mere)
+{
+# regarder s'il existe une fonction spe'cifique a` ce nom
+  $f = 'calculer_champ_' . $nom_champ;
+  if (function_exists($f)) 
+    return $f($fonctions, $nom_champ, $id_boucle, &$boucles, $id_mere);
+  else
+    {
+    # on regarde ensuite s'il y a un champ SQL homonyme,
+      $code = index_pile($id_boucle, $nom_champ, &$boucles);
+      if (($code) && ($code != '$PileRow[0]['.$nom_champ.']'))
+	  return applique_filtres($fonctions, $code, $id_boucle, $boucles, $id_mere);
+      else
+	{
+# si index_pile a ramene' le choix par de'faut, 
+# c~a doit plutot e^tre un champ SPIP non SQL, ou ni l'un ni l'autre
+	  return calculer_champ_divers($fonctions, $nom_champ, $id_boucle, &$boucles, $id_mere);
+	}
+    }
+}
+
+
+// ge'ne`re l'application d'une liste de filtres
+
+function applique_filtres ($fonctions, $code, $id_boucle, $boucles, $id_mere)
+{
+  $milieu = '';
+  if ($fonctions) {
+    while (list(, $fonc) = each($fonctions)) {
+      if ($fonc) {
+	$arglist = '';
+	if (ereg('([^\{\}]*)\{(.+)\}$', $fonc, $regs)) {
+	  $fonc = $regs[1];
+	  $args = $regs[2];
+	  while (ereg('([^,]+),?(.*)$', $args, $regs)) {
+	    $args = $regs[2];
+	    $arg = trim($regs[1]);
+	    if ($arg)
+	      {
+		if ($arg[0] =='#')
+		  {
+		    list($arg,$m) = calculer_champ(array(),substr($arg,1),$id_boucle, &$boucles, $id_mere);
+		    $milieu .= $m;
+		  }
+		else {if ($arg[0] =='$')
+		    $arg = '$PileRow[0][\'' . substr($arg,1) . "']";}
+		$arglist .= ','.$arg;
+	      }
+	  }
+	}
+	if (function_exists($fonc))
+	  $code = "$fonc($code$arglist)";
+	else
+	  $code = "'"._T('erreur_filtre', array('filtre' => $fonc))."'";
+	}
+    }
+  }
+  return array($code,$milieu);
+}
+
+?>
diff --git a/inc-invalideur.php3 b/inc-invalideur.php3
new file mode 100644
index 0000000000..cdf7821fe6
--- /dev/null
+++ b/inc-invalideur.php3
@@ -0,0 +1,125 @@
+<?php
+// Ce fichier ne sera execute qu'une fois
+if (defined("_INVALIDEUR")) return;
+define("_INVALIDEUR", "1");
+
+include($GLOBALS['flag_ecrire'] ? '../inc-cache.php3' : 'inc-cache.php3');
+include($GLOBALS['flag_ecrire'] ? 'inc_serialbase.php3' : 'ecrire/inc_serialbase.php3');
+
+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)
+{
+    // pour l'instant on ne sait traiter que ces infos-la`:
+  insere_invalideur($infosurpage['id_article'],'id_article', $hache);
+  insere_invalideur($infosurpage['id_breve'],   'id_breve', $hache);
+  insere_invalideur($infosurpage['id_rubrique'],'id_rubrique', $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("De'pendances $type: " . join(", ", $values));
+    }
+}
+
+// Regarde dans une table de nom de caches ceux ve'rifiant une condition donne'e
+// Les retire de cette table et de la table ge'ne'rale des caches
+// Si la condition est vide, c'est une simple purge ge'ne'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: " . join(' ' , $tous));
+  applique_invalideur($tous);
+}
+
+function applique_invalideur($depart)
+{
+  global $tables_principales;
+
+  if ($depart)
+    {
+      $tous = join("', '", $depart);
+      $tous = "'$tous'";
+      $niveau = $tous;
+      while ($niveau)
+	{
+# le NOT IN est the'oriquement superflu, mais prote`ge des tables endommage'es
+	  $result = spip_query("
+SELECT  DISTINCT hache
+FROM    spip_inclure" . _SUFFIXE_DES_CACHES . "
+WHERE   inclure IN ($niveau) 
+AND	hache NOT IN ($tous)
+");
+	  $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 hache IN ($tous)
+");
+      
+      foreach($tables_principales as $a)
+	{
+ 
+		$p = $a['key']["PRIMARY KEY"];
+		if (!strpos($p, ","))
+	    spip_query("
+DELETE FROM spip_" . $p  . _SUFFIXE_DES_CACHES ."
+WHERE hache IN ($tous)
+");
+	}
+      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-login.php3 b/inc-login.php3
index 622b494ae5..4ca55e50b8 100644
--- a/inc-login.php3
+++ b/inc-login.php3
@@ -5,7 +5,6 @@
 if (defined("_INC_LOGIN")) return;
 define("_INC_LOGIN", "1");
 
-
 include_ecrire ("inc_meta.php3");
 include_ecrire ("inc_session.php3");
 include_ecrire ("inc_filtres.php3");
@@ -41,7 +40,7 @@ function ouvre_login($titre='') {
 
 	if ($titre) $retour .= "<h3 class='spip'>$titre</h3>";
 
-	$retour .= '<div style="font-family: Verdana,arial,helvetica,sans-serif; font-size: 2;">';
+	$retour .= '<div style="font-family: Verdana,arial,helvetica,sans-serif: font-size: 2">';
 	return $retour;
 }
 
@@ -51,7 +50,11 @@ function ferme_login() {
 	return $retour;
 }
 
-function login($cible = '', $prive = 'prive', $message_login='') {
+function login($cible, $prive = 'prive', $message_login='') {
+
+  $pass_popup ='href="spip_pass.php3" target="spip_pass" onclick="'
+                       . "javascript:window.open('spip_pass.php3', 'spip_pass', 'scrollbars=yes, resizable=yes, width=480, height=450'); return false;\"";
+
 	$login = $GLOBALS['var_login'];
 	$erreur = '';
 	$essai_auth_http = $GLOBALS['var_essai_auth_http'];
@@ -62,7 +65,7 @@ function login($cible = '', $prive = 'prive', $message_login='') {
 	// s'il est la, c'est probablement un bookmark sur bonjour=oui,
 	// et pas un echec cookie.
 	if ($GLOBALS['var_echec_cookie'])
-		$echec_cookie = ($GLOBALS['spip_session'] != 'test_echec_cookie');
+	  $echec_cookie = ($GLOBALS['spip_session'] != 'test_echec_cookie');
 
 	global $auteur_session;
 	global $spip_session, $PHP_AUTH_USER, $ignore_auth_http;
@@ -70,6 +73,7 @@ function login($cible = '', $prive = 'prive', $message_login='') {
 	global $php_module;
 	global $clean_link;
 
+
 	if (!$cible) {
 		if ($GLOBALS['var_url']) $cible = new Link($GLOBALS['var_url']);
 		else if ($prive) $cible = new Link('ecrire/');
@@ -80,12 +84,12 @@ function login($cible = '', $prive = 'prive', $message_login='') {
 	$cible->delVar('var_url');
 	$clean_link->delVar('var_erreur');
 	$clean_link->delVar('var_login');
+	$url = $cible->getUrl();
 
 	include_ecrire("inc_session.php3");
 	verifier_visiteur();
 	if ($auteur_session AND !$logout AND
 	($auteur_session['statut']=='0minirezo' OR $auteur_session['statut']=='1comite')) {
-		$url = $cible->getUrl();
 		if ($url != $GLOBALS['clean_link']->getUrl())
 			@Header("Location: $url");
 		echo "<a href='$url'>"._T('login_par_ici')."</a>\n";
@@ -108,13 +112,14 @@ function login($cible = '', $prive = 'prive', $message_login='') {
 
 	$flag_autres_sources = $GLOBALS['ldap_present'];
 
+	// quels sont les aleas a passer ?
 	if ($login) {
 		$statut_login = 0; // statut inconnu
 		$login = addslashes($login);
 		$query = "SELECT * FROM spip_auteurs WHERE login='$login'";
 		$result = spip_query($query);
 		if ($row = spip_fetch_array($result)) {
-			if ($row['statut'] == '5poubelle' OR ($row['source'] == 'spip' AND $row['pass'] == '')) {
+		  if ($row['statut'] == '5poubelle' OR ($row['source'] == 'spip' AND $row['pass'] == '')) {
 				$statut_login = -1; // refus
 			} else {
 
@@ -143,7 +148,7 @@ function login($cible = '', $prive = 'prive', $message_login='') {
 			@spip_setcookie("spip_admin", "", time() - 3600);
 		}
 	}
-
+	
 	// javascript pour le focus
 	if ($login)
 		$js_focus = 'document.form_login.session_password.focus();';
@@ -157,9 +162,22 @@ function login($cible = '', $prive = 'prive', $message_login='') {
 	}
 	else {
 		echo ouvre_login ();
-		if (strlen($message_login) > 0) echo "<br>$message_login<br>\n";
+		echo 
+		  (!$message_login ? '' :
+		   ("<br>" . 
+		    _T("forum_vous_enregistrer") . 
+		    "<a $pass_popup>" .
+		    _T("forum_vous_inscrire") .
+		    "</a><br><br>\n")) ;
+		   
 	}
 
+	# e'quivalent $clean_link->getUrl() si celui-ci n'e'tait bugge'...
+	$p = strpos($GLOBALS[REQUEST_URI], '?');
+	$action = 
+	  substr($GLOBALS[PHP_SELF], strrpos($GLOBALS[PHP_SELF], '/')+1) . 
+	  ($p ? substr($GLOBALS[REQUEST_URI], $p) : '');
+
 	if ($login) {
 		// Affiche formulaire de login en incluant le javascript MD5
 		$flag_challenge_md5 = ($source_auteur == 'spip');
@@ -178,7 +196,7 @@ function login($cible = '', $prive = 'prive', $message_login='') {
 		if ($flag_challenge_md5) {
 			// si jaja actif, on affiche le login en 'dur', et on le passe en champ hidden
 			echo "<script type=\"text/javascript\"><!--\n" .
-				"document.write('".addslashes(_T('login_login'))." <b>$login</b> <br><font size=\\'2\\'>[<a href=\\'spip_cookie.php3?cookie_admin=non&url=".rawurlencode($clean_link->getUrl())."\\'>".addslashes(_T('login_autre_identifiant'))."</a>]</font>');\n" .
+			  "document.write('".addslashes(_T('login_login'))." <b>$login</b> <br><font size=\\'2\\'>[<a href=\\'spip_cookie.php3?cookie_admin=non&url=".rawurlencode($action)."\\'>"._T('login_autre_identifiant')."</a>]</font>');\n" .
 				"//--></script>\n";
 			echo "<input type='hidden' name='session_login_hidden' value='$login'>";
 
@@ -198,27 +216,23 @@ function login($cible = '', $prive = 'prive', $message_login='') {
 		echo "<br>&nbsp;&nbsp;&nbsp;&nbsp;<input type='checkbox' name='session_remember' value='oui' id='session_remember'$rester_checked> ";
 		echo "<label for='session_remember'>"._T('login_rester_identifie')."</label>";
 
-		$url = $cible->getUrl();
 		echo "<input type='hidden' name='url' value='$url'>\n";
 		echo "<input type='hidden' name='session_password_md5' value=''>\n";
 		echo "<input type='hidden' name='next_session_password_md5' value=''>\n";
-		echo "<div align='right'><input type='submit' class='spip_bouton' name='submit' value='"._T('bouton_valider')."'></div>\n";
+		echo "<div align='right'><input type='submit' class='spip_bouton' value='"._T('bouton_valider')."'></div>\n";
 		echo "</div>";
 		echo "</form>";
 	}
 	else { // demander seulement le login
 
-		$url = $cible->getUrl();
-		$action = $clean_link->getUrl();
-
 		echo "<form name='form_login' action='$action' method='post'>\n";
-		echo "<div class='spip_encadrer'>";
+		echo "<div class='spip_encadrer' style='text-align:".$GLOBALS["spip_lang_left"].";'>";
 		if ($erreur) echo "<span style='color:red;'><b>$erreur</b></span><p />";
 		echo "<label><b>"._T('login_login2')."</b><br></label>";
 		echo "<input type='text' name='var_login' class='forml' value=\"\" size='40' />\n";
 
 		echo "<input type='hidden' name='var_url' value='$url' />\n";
-		echo "<div align='right'><input type='submit' class='spip_bouton' name='submit' value='"._T('bouton_valider')."' /></div>\n";
+		echo "<div align='right'><input type='submit' class='spip_bouton' value='"._T('bouton_valider')."'/></div>\n";
 		echo "</div>";
 		echo "</form>";
 	}
@@ -230,23 +244,19 @@ function login($cible = '', $prive = 'prive', $message_login='') {
 		echo "<form action='spip_cookie.php3' method='get'>";
 		echo "<fieldset>\n<p>";
 		echo _T('login_preferez_refuser')." \n";
-		echo "<input type='hidden' name='essai_auth_http' value='oui' /> ";
-		$url = $cible->getUrl();
-		echo "<input type='hidden' name='url' value='$url' />\n";
-		echo "<div align='right'><input type='submit' name='submit' class='spip_bouton' value='"._T('login_sans_cookiie')."'></div>\n";
+		echo "<input type='hidden' name='essai_auth_http' value='oui'/> ";
+		echo "<input type='hidden' name='url' value='$url'/>\n";
+		echo "<div align='right'><input type='submit' class='spip_bouton' value='"._T('login_sans_cookiie')."'/></div>\n";
 		echo "</fieldset></form>\n";
 	}
 
 	echo "\n<center>"; // debut du pied de login
 
-	// Bouton s'inscrire
 	$inscriptions_ecrire = (lire_meta("accepter_inscriptions") == "oui");
-	if ((!$prive AND (lire_meta('accepter_visiteurs') == 'oui') OR (lire_meta('forums_publics') == 'abo')) OR ($prive AND $inscriptions_ecrire)) {
-		echo '[<a href="spip_pass.php3" target="spip_pass" onclick="'
-			."javascript:window.open(this.href, 'spip_pass', 'scrollbars=yes, resizable=yes, width=480, height=450'); return false;\">"
-			._T('login_sinscrire').'</a>]';
-	}
-	// Bouton oubli de mot de passe
+	if ((!$prive AND (lire_meta('accepter_visiteurs') == 'oui') OR (lire_meta('forums_publics') == 'abo')) OR ($prive AND $inscriptions_ecrire)) 
+		echo " [<a $pass_popup>" . _T('login_sinscrire').'</a>]';
+
+	// bouton oubli de mot de passe
 	include_ecrire ("inc_mail.php3");
 	if (tester_mail()) {
 		echo ' [<a href="spip_pass.php3?oubli_pass=oui" target="spip_pass" onclick="'
@@ -254,6 +264,7 @@ function login($cible = '', $prive = 'prive', $message_login='') {
 			._T('login_motpasseoublie').'</a>]';
 	}
 	// Bouton retour au site public
+
 	if ($prive) echo " [<a href='$url_site'>"._T('login_retoursitepublic')."</a>]";
 
 	echo "</center>\n";
diff --git a/inc-logo-squel.php3 b/inc-logo-squel.php3
new file mode 100644
index 0000000000..898e45f246
--- /dev/null
+++ b/inc-logo-squel.php3
@@ -0,0 +1,243 @@
+<?php
+
+# Fonctions de traitement de champs Spip homonymes de champs SQL
+# mais non e'quivalent
+
+function calculer_champ_EXTRA ($fonctions, $nom_champ, $id_boucle, &$boucles, $id_mere)
+{
+  $code = 'trim(' . index_pile($id_boucle,  "extra", &$boucles) . ')';
+  if ($fonctions) {
+    // Gerer la notation [(#EXTRA|isbn)]
+    include_ecrire("inc_extra.php3");
+    reset($fonctions);
+    list($key, $champ_extra) = each($fonctions);
+    $type_extra = $boucles[$id_boucle]->type_requete;
+    if (extra_champ_valide($type_extra, $champ_extra)) {
+      unset($fonctions[$key]);
+      $code = "extra($code, '".addslashes($champ_extra  )."')";
+    }
+    // Appliquer les filtres definis par le webmestre
+    $filtres = extra_filtres($type_extra, $champ_extra);
+    if ($filtres) {
+      reset($filtres);
+      while (list(, $f) = each($filtres)) $code = "$f($code)";
+    }
+  }
+  return applique_filtres($fonctions, $code, $id_boucle, $boucles, $id_mere);
+}
+
+function calculer_champ_LANG ($fonctions, $nom_champ, $id_boucle, &$boucles, $id_mere)
+ {
+#	$code = "lire_meta('langue_site')"; # 1.7
+   $code = "\$GLOBALS['spip_lang']";   # 1.7.2
+   return applique_filtres($fonctions, $code, $id_boucle, $boucles, $id_mere);
+}
+
+function calculer_champ_LESAUTEURS ($fonctions, $nom_champ, $id_boucle, &$boucles, $id_mere)
+{
+  $code = index_pile($id_boucle,  "lesauteurs", &$boucles);
+  if ((!$code) || ($code == '$PileRow[0][lesauteurs]'))
+    $code = 'query_auteurs(' .
+      index_pile($id_boucle,  "id_article", &$boucles) .
+      ')';    
+   return applique_filtres($fonctions, $code, $id_boucle, $boucles, $id_mere);
+}
+
+function calculer_champ_PETITION ($fonctions, $nom_champ, $id_boucle, &$boucles, $id_mere)
+ {
+   $code = 'query_petitions(' .
+     index_pile($id_boucle,  'id_article', &$boucles)
+     . '")) ? " " : "")';
+  return applique_filtres($fonctions, $code, $id_boucle, $boucles, $id_mere);
+}
+
+function calculer_champ_POPULARITE ($fonctions, $nom_champ, $id_boucle, &$boucles, $id_mere)
+ {
+   $code = 'ceil(min(100, 100 * ' .
+     index_pile($id_boucle,  "popularite", &$boucles) .
+     '/ max(1 , 0 + lire_meta(\'popularite_max\'))))';
+  return applique_filtres($fonctions, $code, $id_boucle, $boucles, $id_mere);
+ }
+
+
+function calculer_champ_DATE ($fonctions, $nom_champ, $id_boucle, &$boucles, $id_mere) {
+# Uniquement hors-boucles, pour date passee dans l'URL ou  contexte_inclus
+  return applique_filtres($fonctions,
+			  index_pile($id_boucle,  'date', &$boucles),
+			  $id_boucle, $boucles, $id_mere);
+}
+
+# Fonction commune aux logos (rubriques, articles...)
+
+function calculer_champ_LOGO($fonctions, $nom_champ, $id_boucle, &$boucles, $id_mere)
+{
+  ereg("^LOGO_(([a-zA-Z]+).*)$", $nom_champ, $regs);
+  $type_logo = $regs[1];
+  $type_objet = strtolower($regs[2]);
+  $flag_fichier = 0;  // compatibilite ascendante
+  $filtres = '';
+  if ($fonctions) {
+    while (list(, $nom) = each($fonctions)) {
+      if (ereg('^(left|right|center|top|bottom)$', $nom))
+	$align = $nom;
+      else if ($nom == 'lien') {
+	$flag_lien_auto = 'oui';
+	$flag_stop = true;
+      }
+      else if ($nom == 'fichier') {
+	$flag_fichier = 1;
+	$flag_stop = true;
+      }
+      else if ($nom == '')	// double || signifie "on passe aux filtres"
+	$flag_stop = true;
+      else if (!$flag_stop) {
+	$lien = $nom;
+	$flag_stop = true;
+      }
+      else // apres un URL ou || ou |fichier ce sont des filtres (sauf left...lien...fichier)
+	{
+	$filtres[] = $nom;
+	}
+    }
+    // recuperer les filtres s'il y en a
+    $fonctions = $filtres;
+  }
+  if ($flag_lien_auto && !$lien) {
+    $milieu .= "
+			\$lien = generer_url_$type_objet(" .
+      index_pile($id_boucle,  'id_$type_objet', &$boucles) . ");
+			";
+  }
+  else
+    {
+      $milieu .= "\n\t\$lien = ";
+      $a = $lien;
+      while (ereg("^([^#]*)#([A-Za-z_]+)(.*)$", $a, $match))
+	{
+	  list($c,$m) = calculer_champ("", $match[2], $id_boucle, &$boucles, $id_mere);
+	  // $m est nul dans les cas pre'vus
+	  $milieu .= ((!$match[1]) ? "" :"'$match[1]' .") . " $c .";
+	  $a = $match[3];
+	}
+      if ($a) $milieu .= "'$lien';"; 
+      else 
+	{
+	  if ($lien) $milieu = substr($milieu,1,-1) .";";
+	  else $milieu .= "'';";
+	}
+    }
+  
+  if ($type_logo == 'RUBRIQUE') {
+    $milieu .= '
+			list($logon, $logoff) = image_rubrique(' .
+      index_pile($id_boucle,  "id_rubrique", &$boucles) . ", $flag_fichier);
+			";
+  }
+  else if ($type_logo == 'RUBRIQUE_NORMAL') {
+    $milieu .= '
+			list($logon,) = image_rubrique(' .
+      index_pile($id_boucle,  "id_rubrique", &$boucles) . ", $flag_fichier); ". '
+			$logoff = "";
+			';
+  }
+  else if ($type_logo == 'RUBRIQUE_SURVOL') {
+    $milieu .= '
+			list(,$logon) = image_rubrique(' .
+      index_pile($id_boucle,  "id_rubrique", &$boucles) . ", $flag_fichier); ". '
+			$logoff = "";
+			';
+  }
+  else if ($type_logo == 'DOCUMENT'){
+    $milieu .= '
+			$logon = integre_image(' .
+      index_pile($id_boucle,  "id_document", &$boucles) . ',"","fichier_vignette");
+			$logoff = "";
+			';
+  }
+  else if ($type_logo == 'AUTEUR') {
+    $milieu .= '
+			list($logon, $logoff) = image_auteur(' .
+      index_pile($id_boucle,  "id_auteur", &$boucles) . ", $flag_fichier);
+			";
+  }
+  else if ($type_logo == 'AUTEUR_NORMAL') {
+    $milieu .= '
+			list($logon,) = image_auteur(' .
+      index_pile($id_boucle,  "id_auteur", &$boucles) . ", $flag_fichier);".'
+			$logoff = "";
+			';
+  }
+  else if ($type_logo == 'AUTEUR_SURVOL') {
+    $milieu .= '
+			list(,$logon) = image_auteur(' .
+      index_pile($id_boucle,  "id_auteur", &$boucles) . ", $flag_fichier);".'
+			$logoff = "";
+			';
+  }
+  else if ($type_logo == 'BREVE') {
+    $milieu .= '
+			list($logon, $logoff) = image_breve(' .
+      index_pile($id_boucle,  "id_breve", &$boucles) . ", $flag_fichier);
+			";
+  }
+  else if ($type_logo == 'BREVE_RUBRIQUE') {
+    $milieu .= '
+			list($logon, $logoff) = image_breve(' .
+      index_pile($id_boucle,  "id_breve", &$boucles) . ", $flag_fichier);".'
+			if (!$logon)
+				list($logon, $logoff) = image_rubrique(' .
+      index_pile($id_boucle,  "id_rubrique", &$boucles) . ", $flag_fichier);
+		  ";
+  }
+  else if ($type_logo == 'SITE') {
+    $milieu .= '
+			list($logon, $logoff) = image_site(' .
+      index_pile($id_boucle,  "id_syndic", &$boucles) . ", $flag_fichier);
+			";
+  }
+  else if ($type_logo == 'MOT') {
+    $milieu .= '
+			list($logon, $logoff) = image_mot(' .
+      index_pile($id_boucle,  "id_mot", &$boucles) . ", $flag_fichier);
+			";
+  }
+  else if ($type_logo == 'ARTICLE') {
+    $milieu .= '
+			list($logon, $logoff) = image_article(' .
+      index_pile($id_boucle,  "id_article", &$boucles) . ", $flag_fichier);
+			";
+  }
+  else if ($type_logo == 'ARTICLE_NORMAL') {
+    $milieu .= '
+			list($logon,) = image_article(' .
+		index_pile($id_boucle,  "id_article", &$boucles) . ", $flag_fichier);".'
+			$logoff = "";
+			';
+  }
+  else if ($type_logo == 'ARTICLE_SURVOL') {
+    $milieu .= '
+			list(,$logon) = image_article(' .
+      index_pile($id_boucle,  "id_article", &$boucles) . ", $flag_fichier);".'
+			$logoff = "";
+			';
+  }
+  else if ($type_logo == 'ARTICLE_RUBRIQUE') {
+    $milieu .= '
+			list($logon, $logoff) = image_article(' .
+      index_pile($id_boucle,  "id_article", &$boucles) . ", $flag_fichier);".'
+			if (!$logon)
+				list($logon, $logoff) = image_rubrique(' .
+      index_pile($id_boucle,  "id_rubrique", &$boucles) . ", $flag_fichier);
+			";
+  }
+  if ($flag_fichier)
+    $code = '$logon';
+  else
+    $code = "affiche_logos(\$logon, \$logoff, \$lien, '".
+      addslashes($align) . "')";
+  
+  list($c,$m) = applique_filtres($fonctions, $code, $id_boucle, $boucles, $id_mere);
+		return array($c,$milieu . $m);
+}
+
+?>
diff --git a/inc-messforum.php3 b/inc-messforum.php3
new file mode 100644
index 0000000000..5f4c384da1
--- /dev/null
+++ b/inc-messforum.php3
@@ -0,0 +1,166 @@
+<?php
+
+include_ecrire('inc_texte.php3');
+include_ecrire('inc_filtres.php3');
+include_ecrire('inc_mail.php3');
+
+if (file_exists("inc-urls.php3")) {
+        include_local ("inc-urls.php3");
+}
+else {
+        include_local ("inc-urls-dist.php3");
+}
+// 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')");
+    }
+  }
+
+  $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,
+	id_syndic = \"$forum_id_syndic\",
+	id_auteur = \"$id_auteur\",
+	date_heure = NOW(),
+	titre = \"$slash_titre\",
+	texte = \"$slash_texte\",
+	nom_site = \"$slash_nom_site_forum\",
+	url_site = \"$slash_url_site\",
+	auteur = \"$slash_auteur\",
+	email_auteur = \"$slash_email_auteur\",
+	ip = \"$REMOTE_ADDR\",
+	statut = \"$statut\"
+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));
+
+		// 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'
+
+	if (file_exists('inc-invalideur.php3'))
+	  {
+	    include('inc-invalideur.php3');
+	    applique_invalideur(($statut == 'publie') ?
+				array($var_cache, $cache) :
+				array($var_cache));
+	      }
+	else // minimum vital 
+	  {
+	    @unlink($var_cache);
+	    if ($statut == 'publie') @unlink($cache);
+	  }
+    }
+    $redirect = $retour_forum;
+ }
+?>
diff --git a/inc-public-global.php3 b/inc-public-global.php3
index 38d63ff8f1..cfffd6f054 100644
--- a/inc-public-global.php3
+++ b/inc-public-global.php3
@@ -1,302 +1,114 @@
 <?php
 
-include ("ecrire/inc_version.php3");
-include_local ("inc-cache.php3");
-
-if ($INSECURE['fond'] || $INSECURE['delais']) exit;
-if (!isset($delais))
-	$delais = 1 * 3600;
-
-/*function t($s = '') {
-	global $t0, $t1;
-	$t1 = explode(" ", microtime());
-	$dt = floor(1000 * ($t1[0] + $t1[1] - $t0[0] - $t0[1])) / 1000;
-	echo "<p>";
-	if ($s) echo "<b>$s :</b> ";
-	echo "$dt secondes</p>\n";
-	$t0 = $t1;
-}*/
-
-
-//
-// Inclusions de squelettes
-//
-
-function inclure_fichier($fond, $delais, $contexte_inclus = "") {
-	global $fichier_cache;
-	$fichier_requete = $fond;
-	if (is_array($contexte_inclus)) {
-		reset($contexte_inclus);
-		while(list($key, $val) = each($contexte_inclus))
-			$fichier_requete .= '&'.$key.'='.$val;
-	}
-	$fichier_cache = generer_nom_fichier_cache($fichier_requete);
-	$chemin_cache = "CACHE/$fichier_cache";
-	$use_cache = utiliser_cache($chemin_cache, $delais);
-
-	if (!$use_cache) {
-		include_local("inc-calcul.php3");
-		$timer_a = explode(" ", microtime());
-
-		$fond = chercher_squelette($fond, $contexte_inclus['id_rubrique'], $contexte_inclus['lang']);
-		$page = calculer_page($fond, $contexte_inclus);
-		$timer_b = explode(" ", microtime());
-		if ($page) {
-			$timer = ceil(1000 * ($timer_b[0] + $timer_b[1] - $timer_a[0] - $timer_a[1]));
-			$taille = ceil(strlen($page) / 1024);
-			spip_log("inclus ($timer ms): $chemin_cache ($taille ko, delai: $delais s)");
-			$chemin_cache = ecrire_fichier_cache($chemin_cache, $page);
-		}
-	}
-	return $chemin_cache;
-}
-
-
-//
-// Authentification
-//
-
-if ($HTTP_COOKIE_VARS['spip_session'] OR ($PHP_AUTH_USER AND !$ignore_auth_http)) {
-	include_ecrire ("inc_session.php3");
-	verifier_visiteur();
-}
-
-
-//
-// Gestion de la langue dans l'URL
-//
-if ($forcer_lang) {
-	include_ecrire('inc_lang.php3');
-	verifier_lang_url();
-}
-if ($lang = $HTTP_GET_VARS['lang']) {
-	include_ecrire('inc_lang.php3');
-	lang_select($lang);	
-}
-
-
-//
-// Gestion du cache et calcul de la page
-//
-
-// Nom du fichier cache
-$fichier_requete = $REQUEST_URI;
-$fichier_requete = strtr($fichier_requete, '?', '&');
-$fichier_requete = eregi_replace('&(submit|valider|PHPSESSID|(var_[^=&]*)|recalcul)=[^&]*', '', $fichier_requete);
-
-$fichier_cache = generer_nom_fichier_cache($fichier_requete);
-$chemin_cache = "CACHE/$fichier_cache";
-
-$use_cache = utiliser_cache($chemin_cache, $delais);
-
-$ecraser_cache = false;
-$cache_supprimes = Array();
-
-if (!$use_cache OR !defined("_ECRIRE_INC_META_CACHE")) {
-	include_ecrire("inc_meta.php3");
-}
-
-
-//
-// Ajouter un forum
-//
-
-if ($ajout_forum) {
-	include_local ("inc-forum.php3");
-	ajout_forum();
-}
-
-if (!$use_cache) {
-	$lastmodified = time();
-	if (($lastmodified - lire_meta('date_purge_cache')) > 3600) {
-		ecrire_meta('date_purge_cache', $lastmodified);
-		$f = fopen('CACHE/.purge', 'w');
-		fclose($f);
-	}
-
-	//
-	// Recalculer le cache
-	//
-
-	$calculer_cache = true;
-
-	// Gestion '=chapo'
-	// + ne pas cacher si l'URL d'un article est demande avant sa publication
-	// (une seule requete, deux usages)
-	if ($id_article = intval($id_article)) {
-		$query = "SELECT chapo FROM spip_articles WHERE id_article='$id_article' AND statut='publie'";
-		$result = spip_query($query);
-		$row = spip_fetch_array($result);
-		if (!$row)
-			$ecraser_cache = true;
-
-		if (substr($row['chapo'], 0, 1) == '=') {
-			include_ecrire('inc_texte.php3');
-
-			$regs = array('','','',substr($row['chapo'], 1));
-			list(,$url) = extraire_lien($regs);
-			$url = addslashes($url);
-			$texte = "<"."?php @header (\"Location: $url\"); ?".">";
-			$calculer_cache = false;
-			spip_log("redirection: $url");
-			$chemin_cache = ecrire_fichier_cache($chemin_cache, $texte);
-		}
-	}
-
-	if ($calculer_cache) {
-		include_local ("inc-calcul.php3");
-		$timer_a = explode(" ", microtime());
-
-		$page = calculer_page_globale($fond);
-		$timer_b = explode(" ", microtime());
-		if ($page) {
-			if ($xhtml) {
-				include_ecrire("inc_tidy.php");
-				$page = xhtml($page);
-			}
-			$timer = ceil(1000 * ($timer_b[0] + $timer_b[1] - $timer_a[0] - $timer_a[1]));
-			$taille = ceil(strlen($page) / 1024);
-			spip_log("calcul ($timer ms): $chemin_cache ($taille ko, delai: $delais s)");
-			$chemin_cache = ecrire_fichier_cache($chemin_cache, $page);
-		}
-	}
-}
-
-//
-// si $var_recherche est positionnee, on met en rouge les mots cherches (php4 uniquement)
-//
-
-if ($var_recherche AND $flag_ob AND $flag_pcre AND !$flag_preserver AND !$mode_surligne) {
-	include_ecrire("inc_surligne.php3");
-	$mode_surligne = 'auto';
-	timeout(false, true, false);	// no lock, action, no mysql
-	ob_start();
-}
-else {
-	unset ($var_recherche);
-	unset ($mode_surligne);
-}
-
-
-
-//
-// Inclusion du cache pour envoyer la page au client
-//
-
-$effacer_cache = !$delais;
-$effacer_cache |= $ecraser_cache;	// ecraser le cache de l'article x s'il n'est pas publie
-
-// Envoyer les entetes
-$headers_only = ($HTTP_SERVER_VARS['REQUEST_METHOD'] == 'HEAD');
-if (!$effacer_cache && !$flag_dynamique && $recalcul != 'oui' && !$HTTP_COOKIE_VARS['spip_admin']) {
-	if ($lastmodified) 
-		$headers_only |= http_last_modified($lastmodified, $lastmodified + $delais);
-	if ($headers_only) exit;
-}
-else {
-	@Header("Expires: 0");
-	@Header("Cache-Control: no-cache,must-revalidate");
-	@Header("Pragma: no-cache");
-}
-$flag_preserver |= $headers_only;	// ne pas se fatiguer a envoyer des donnees
-if (!$flag_preserver) {
-	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");
-		verif_butineur();
-		if (version_tidy() > 0) {		
-			if ($browser_name == "MSIE")
-				@Header("Content-Type: text/html; charset=".lire_meta('charset'));
-			else 
-				@Header("Content-Type: application/xhtml+xml; 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 la page
-if (@file_exists($chemin_cache)) {
-	if (!$headers_only) include($chemin_cache);
-}
-else if (!$flag_preserver) {
-	// Message d'erreur base de donnees
-	include_ecrire('inc_presentation.php3');
-	install_debut_html(_T('info_travaux_titre'));
-	echo "<p>"._T('titre_probleme_technique')."</p>\n";
-	install_fin_html();
-}
-
-
-// suite et fin mots en rouge
-if ($var_recherche)
-	fin_surligne($var_recherche, $mode_surligne);
-
-
-// nettoie
-if ($effacer_cache) @unlink($chemin_cache);
-while (list(, $chemin_cache_supprime) = each($cache_supprimes))
-	@unlink($chemin_cache_supprime);
-
-
-//
-// Verifier la presence du .htaccess dans le cache, sinon le generer
-//
-
-if (!@file_exists("CACHE/.htaccess")) {
-	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\" target=\"_blank\">l'espace webmestres</a>.";
-		echo "Veuillez cr&eacute;er manuellement la protection pour ce r&eacute;pertoire (un couple login/mot de passe est n&eacute;cessaire).<br />";
-	}
-	else{
-		$f = fopen("CACHE/.htaccess", "w");
-		fputs($f, "deny from all\n");
-		fclose($f);
-	}
-}
-
-
-//
-// Fonctionnalites administrateur (declenchees par le cookie admin, authentifie ou non)
-//
-
-if ($HTTP_COOKIE_VARS['spip_admin'] AND !$flag_preserver AND !$flag_boutons_admin) {
-	include_local("inc-admin.php3");
-	afficher_boutons_admin();
-}
-
-
-// envoyer la page si possible
-@flush();
-
-
-// Mise a jour des fichiers langues de l'espace public
-if ($cache_lang_modifs) {
-	include_ecrire('inc_lang.php3');
-	ecrire_caches_langues();
-}
-
-
-// Gestion des taches de fond ?  toutes les 5 secondes (on mettra 30 s quand on aura prevu la preemption par une image-cron)
+// Ce fichier ne sera execute qu'une fois
+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']; 
+  }
+
+function inclure_page($fond, $delais_inclus, $contexte_inclus, $cache_incluant='')
+  {
+    global $delais;
+    static $pile_delais = '', $ptr_delais = 0;
+    $ptr_delais++;
+    $pile_delais[$ptr_delais] = $delais_inclus;
+
+    spip_log("Inclusion ($cache_incluant)");
+    $cle = nom_du_cache($fond, $contexte_inclus);
+    $page = ramener_cache($cle,
+			  'cherche_page_incluse',
+			  array('fond' => $fond, 
+				'cache_incluant' => $cache_incluant,
+				'contexte' => $contexte_inclus),
+			  &$pile_delais[$ptr_delais]);
+    
+   // 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;
+  }
+
+# Le bouton des administrateurs est affiche' par une fonction JavaScript
+# non mise en cache car de'pendant de l'utilisateur (pas d'affichage parfois)
+# Elle est appele'e par le code d'un squelette utilisant FORMULAIRE_ADMIN
+
+function admin_page($cached, $texte)
+{
+  if  ($GLOBALS['flag_preserver'] ||
+       !($admin = $GLOBALS['HTTP_COOKIE_VARS']['spip_admin']))
+    $a = 'function admin(){}';
+  else
+    {
+      include_local('inc-admin.php3');
+      $a = str_replace("/", '\/', addslashes(strtr(afficher_boutons_admin($cached ? ' *' : ''), "\n", ' ')));
+      $a = "var bouton_admin = \"$a\";function admin() 
+ {document.write(bouton_admin); document.close(); bouton_admin='';}";
+    }
+  if (eregi("^[[:space:]]*(<!DOCTYPE[^>]*>[[:space:]]*<html[^>]*>[[:space:]]<head[^>]*>)(.*)$", $texte, $m))
+      return $m[1] . envoi_script($a) . $m[2];
+  else
+    {
+    return envoi_script($a) . $texte;
+    }
+}
+
+function nom_du_cache($fond, $contexte)
+ {
+   // Tenir compte de l'URL, pour le jour ou` on mutualisera Spip 
+   $appel = $GLOBALS['PHP_SELF'];
+   $appel = substr($appel,0, strrpos($appel, '/')+1) . $fond;
+   // Virer les variables internes. 
+   // Faudrait rationnaliser pour ne pas interfe'rer avec contexte_inclus
+   if ($contexte)
+     while(list($k, $v) = each($contexte))
+       {if (!(ereg('((var_*)|recalcul)', $k)))
+	   $appel .= "=$v";
+       }
+   return $appel;
+ }
+
+function envoi_script($code)
+{
+  return
+  "<script type='text/javascript'><!--
+  $code
+--></script>\n";
+}
+
+function cherche_image_nommee($nom, $dossier) {
+  $formats = array ('gif', 'jpg', 'png');
+  while (list(, $format) = each($formats))
+    {
+      $d = "$dossier$nom.$format";
+      if (file_exists($d)) return ($d);
+    }
+}
+
+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')
-	OR (time() - @filemtime('ecrire/data/cron.lock') > 5)) {
-	// Si MySQL est out, laisser souffler
-	if (!@file_exists('ecrire/data/mysql_out')
-		OR (time() - @filemtime('ecrire/data/mysql_out') > 300)) {
-		include_ecrire('inc_cron.php3');
-		spip_cron();
-	}
-}
+        OR (time() - @filemtime('ecrire/data/cron.lock') > 5)) {
+        // Si MySQL est out, laisser souffler
+        if (!@file_exists('ecrire/data/mysql_out')
+                OR (time() - @filemtime('ecrire/data/mysql_out') > 300)) {
+                include_ecrire('inc_cron.php3');
+                spip_cron();
+        }
+ }
 
 //
 // Gestion des statistiques du site public
@@ -304,9 +116,8 @@ if (!@file_exists('ecrire/data/cron.lock')
 //
 
 if (lire_meta("activer_statistiques") != "non") {
-	include_local ("inc-stats.php3");
-	ecrire_stats();
+        include_local ("inc-stats.php3");
+        ecrire_stats();
+ }
 }
-
-
 ?>
diff --git a/inc-public.php3 b/inc-public.php3
index 745a222f12..15b6f827de 100644
--- a/inc-public.php3
+++ b/inc-public.php3
@@ -1,13 +1,153 @@
 <?php
 
-if (!defined("_INC_PUBLIC")) {
- 	define("_INC_PUBLIC", "1");
-	include("inc-public-global.php3");
-}
-else {
-	$cache_inclus = inclure_fichier($fond, $delais, $contexte_inclus);
-	if (!$delais) $cache_supprimes[] = $cache_inclus; // message pour suppression
-	include($cache_inclus);
-}
+if (defined("_INC_PUBLIC")) { // inclusion diffe're'e
+  $page = inclure_page($fond, $delais, $contexte_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 change' dans mes_option via inc_version; en 'xml' pour + tard)
+  $GLOBALS['extension_squelette'] = 'html';
+# Variable indiquant le re'pertoires des images
+  $GLOBALS['dossier_images'] = 'IMG';
+
+  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)) {
+       include_ecrire ("inc_session.php3");
+       verifier_visiteur();
+ }
+ 
+ if ($forcer_lang) {
+       include_ecrire('inc_lang.php3');
+       verifier_lang_url();
+ }
+ if ($lang = $HTTP_GET_VARS['lang']) {
+       include_ecrire('inc_lang.php3');
+       lang_select($lang);     
+    }
+
+include_ecrire("inc_meta.php3");
+
+// ajout_forum est une HTTP_GET_VAR installe'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 re'affichage du formulaire avec celles-ci.
+// En cas de validation finale c~a redirige vers l'URL ayant provoque' l'appel
+// au lieu de laisser l'URL appele'e resynthe'tiser le formulaire.
+
+  if ($ajout_forum) {
+    $redirect = '';
+    include('inc-messforum.php3');
+    if ($redirect) {header("Location: $redirect");exit();}
+  }
+  include_local ("inc-public-global.php3");
+  include_local ("inc-cache.php3");
+  if (!isset($delais)) $delais = 1 * 3600;
+  $cle = nom_du_cache($fond, $HTTP_GET_VARS);
+  $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]");
+
+  // Code inope'rant si le serveur HTTP traite ce champ en amont.
+  if ($HTTP_IF_MODIFIED_SINCE)
+    {
+      $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,
+				 'recherche' => $HTTP_GET_VARS['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("Expires: $expire");
+     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");
+		verif_butineur();
+		if (version_tidy() > 0) {		
+			if ($browser_name == "MSIE")
+				@Header("Content-Type: text/html; charset=".lire_meta('charset'));
+			else 
+				@Header("Content-Type: application/xhtml+xml; 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 re'ponses
+# 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 de'sactive' ici puisqu'il n'y a qu'une seule re'ponse, 
+# 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 retourne'e car le syste`me vient d'y acce'der:
+# 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();
+ } // fin du defined
 ?>
diff --git a/inc-reqsql-squel.php3 b/inc-reqsql-squel.php3
new file mode 100644
index 0000000000..b691de8d30
--- /dev/null
+++ b/inc-reqsql-squel.php3
@@ -0,0 +1,139 @@
+<?php
+
+# Retourne l'appel a` spip_abstract_select de'finie dans inc-calcul,
+# cense'e construire et effecteur la reque^te SQL de'termine'e 
+# par les infos mises dans $boucles.
+# A ce stade, on explicite les conditions exprime'es par les crite`res.
+# L'utilisation de x AS x n'est pas une redondance:
+# spip_abstract_select accolera au premier x la valeur de table_prefix
+# qui n'a pas de raison d'apparai^tre de`s cette e'tape.
+
+function calculer_requete(&$boucle) {
+ global $table_primary, $table_des_tables, $table_date;
+
+ $type = $boucle->type_requete;
+ $id_table = $table_des_tables[$type];
+ $id_field = $id_table . "." . $table_primary[$type];
+  switch($type) {
+  case 'articles':
+    $boucle->from[] =  "articles AS $id_table";
+    if (lire_meta("post_dates") == 'non') {
+      $boucle->where[] = "$id_table.date < NOW()";}
+    $boucle->where[] = "$id_table.statut='publie'";
+    break;
+
+  case 'auteurs':
+    $boucle->from[] =  "auteurs AS $id_table";
+    // Si pas de lien avec un article, selectionner
+    // uniquement les auteurs d'un article publie
+    if (!$boucle->lien AND !$boucle->tout) {
+      $boucle->from[] =  "auteurs_articles AS lien";
+      $boucle->from[] =  "articles AS articles";
+      $boucle->where[] = "lien.id_auteur=$id_table.id_auteur";
+      $boucle->where[] = 'lien.id_article=articles.id_article';
+      $boucle->where[] = "articles.statut='publie'";
+      $boucle->group =  "'$id_field'";
+    }
+    // pas d'auteurs poubellises
+    $boucle->where[] = "NOT($id_table.statut='5poubelle')";
+    break;
+    
+  case 'breves':
+    $boucle->from[] =  "breves AS $id_table";
+    $boucle->where[] = "$id_table.statut='publie'";
+    break;
+    
+  case 'forums':
+    $boucle->from[] =  "forum AS $id_table";
+    // Par defaut, selectionner uniquement les forums sans pere
+    if (!$boucle->tout AND !$boucle->plat) 
+      {
+	$boucle->where[] = "$id_table.id_parent=0";
+      }
+    $boucle->where[] = "$id_table.statut='publie'";
+   break;
+    
+  case 'signatures':
+    $boucle->from[] =  "signatures AS $id_table";
+    $boucle->from[] =  "petitions AS petitions";
+    $boucle->from[] =  "articles articles";
+    $boucle->where[] = "petitions.id_article=articles.id_article";
+    $boucle->where[] = "petitions.id_article=$id_table.id_article";
+    $boucle->where[] = "$id_table.statut='publie'";
+    $boucle->group = "'$id_field'";
+    break;
+    
+  case 'documents':
+    $boucle->from[] =  "documents AS $id_table";
+    $boucle->from[] =  "types_documents AS types_documents";
+    $boucle->where[] = "$id_table.id_type=types_documents.id_type";
+    $boucle->where[] = "$id_table.taille > 0";
+    break;
+    
+  case 'types_documents':
+    $boucle->from[] =  "types_documents AS $id_table";
+    break;
+    
+  case 'groupes_mots':
+    $boucle->from[] =  "groupes_mots AS $id_table";
+    break;
+    
+  case 'mots':
+    $boucle->from[] =  "mots AS $id_table";
+    break;
+    
+  case 'rubriques':
+    $boucle->from[] =  "rubriques AS $id_table";
+    if (!$boucle->tout) $boucle->where[] = "$id_table.statut='publie'";
+    break;
+    
+  case 'hierarchie':
+    $boucle->from[] =  "rubriques AS $id_table";
+    $boucle->where[] = 'rubriques.id_rubrique = $hierarchie';
+    // champ oblige' pour ge'rer le 2e while synthe'tise' dans inc-calcul-squel
+    $boucle->select[] = "rubriques.id_parent";
+    break;
+    
+  case 'syndication':
+    $boucle->from[] =  "syndic AS $id_table";
+    $boucle->where[] = "$id_table.statut='publie'";
+    break;
+    
+  case 'syndic_articles':
+    $boucle->from[] =  "syndic_articles  AS $id_table";
+    $boucle->from[] =  "syndic AS syndic";
+    $boucle->where[] = "$id_table.id_syndic=syndic.id_syndic";
+    $boucle->where[] = "$id_table.statut='publie'";
+    $boucle->where[] = "syndic.statut='publie'";
+    $boucle->select[]='syndic.nom_site AS nom_site'; # de'rogation zarbi
+    $boucle->select[]='syndic.url_site AS url_site'; # idem
+    break;
+
+  default: // table hors Spip, pourquoi pas
+    $boucle->from[] =  "$type AS $type";
+    $id_field = '*'; // utile a` TOTAL_BOUCLE seulement
+  } // fin du switch
+
+# si pas de champ c'est un de'compte on prend la primary pour avoir qqch
+# (le marteau-pilon * est trop couteux, et le COUNT incompatible avec le cas
+# ge'ne'ral)
+    return ('spip_abstract_select(array("'. 
+	    ((!$boucle->select) ? $id_field :
+	     join('", "', array_unique($boucle->select))) .
+	    '"),
+		array("' .
+	    join('","', array_unique($boucle->from)) .
+	    '"),
+		array(' .
+	    (!$boucle->where ? '' : ( '"' . join('","', $boucle->where) . '"')) .
+	    "),
+		$boucle->group,
+		$boucle->order,
+		\"$boucle->limit\",
+ 		'$boucle->sous_requete', 
+		$boucle->compte_requete,
+		'$id_table',
+		'$boucle->id_boucle')") ;
+}
+
+?>
diff --git a/inc-stats.php3 b/inc-stats.php3
index 73ee03a164..98f91eef44 100644
--- a/inc-stats.php3
+++ b/inc-stats.php3
@@ -73,7 +73,7 @@ function afficher_raccourci_stats($id_article) {
 			$visites = $visites + $row['c'];
 		}
 
-		bouton_admin(_T('stats_visites_et_popularite', array('visites' => $visites, 'popularite' => $popularite)), "./ecrire/statistiques_visites.php3?id_article=$id_article");
+		return array('visites' => $visites, 'popularite' => $popularite);
 	}
 }
 
diff --git a/inc-text-squel.php3 b/inc-text-squel.php3
new file mode 100644
index 0000000000..3e88206b39
--- /dev/null
+++ b/inc-text-squel.php3
@@ -0,0 +1,109 @@
+<?php
+
+# Standard: on ge'ne`re une se'quence PHP qui sera re'interpre'te'e a` chaque fois.
+# Avec le compilateur e'tant re'entrant, on peut inclure imme'diatement 
+# en cas de script standard (i.e. les 2 affectations de fond et delais).
+# Teste' & valide', mais mettre c~a en option car l'incidence sur des squelettes
+# avec de'lais configure's pour l'ancienne version peuvent en souffir
+
+function calculer_inclure($fichier, $params, $id_boucle, $boucles, $pi)
+{
+	global $dossier_squelettes;
+	/*	if (!$pi && (preg_match("/\s*<.php\s*.fond\s*=\s*[\"\']([^;]*)[\"\']\s*;\s*.delais\s*=\s*([^;]*);\s*include\s*..inc-public.php3?..;\s*.>/",
+implode('',file((($dossier_squelettes) &&
+					    @file_exists("$dossier_squelettes/$fichier")) ?
+					   "$dossier_squelettes/$fichier" :
+					   $fichier)),
+				$m)))
+	    {
+	      $l  = "";
+	      if ($params) {
+		reset($params);
+		while (list(, $param) = each($params)) {
+		  if (ereg("^([_0-9a-zA-Z]+)[[:space:]]*(=[[:space:]]*([^}]+))?$", $param, $args)) {
+		    $var = $args[1];
+		    $val = $args[3];
+		    $l .= "'$var' =>" .
+		      ($val ?
+		       ("'" . addslashes($val) . "'") :
+		       (index_pile($id_boucle, $var, &$boucles))) .
+		      ",";
+		  }
+		}
+	      }
+
+	      return "inclure_subpage('" . $m[1] . "'," . $m[2] . 
+		", array(" . $l . '), $Cache["cache"])';}
+		else */
+	    { # vieux code du compilateur non re'entrant. 
+	      # reste utile pour les squelettes appele's bizarrement
+	      $l  = "";
+	      if ($params) {
+		reset($params);
+		while (list(, $param) = each($params)) {
+		  if (ereg("^([_0-9a-zA-Z]+)[[:space:]]*(=[[:space:]]*([^}]+))?$", $param, $args)) {
+		    $var = $args[1];
+		    $val = $args[3];
+		    if ($val)
+		      $l[] = "'\'$var\' => " . addslashes($val) . "'";
+		    else
+		      $l[] = "'\'$var\' => \'' . addslashes(" . index_pile($id_boucle, $var, &$boucles) . ") .'\''";
+		  }
+		}
+	      }
+	      return "\n'<".
+		"?php include_ecrire(\'inc_lang.php3\'); lang_select(lire_meta(\'langue_site\')); \$contexte_inclus = array(' ." . 
+		($l ? (join(".', '.\n",$l)) : '""') . ".');" .
+		(($dossier_squelettes) ?
+		 ("
+			if (@file_exists(\'$dossier_squelettes/$fichier\')){
+				include(\'$dossier_squelettes/$fichier\');
+			} else {
+				include(\'$fichier\');
+			} " ) :
+		 ("include(\'$fichier\');")) .
+		"lang_dselect(); ?" . ">'";
+	    }
+}
+
+// Convertit un texte Spip en une EXPRESSION php 
+// donc qqch qui peut e^tre l'argument d'un Return 
+// ou la partie droite d'une affectation
+
+function calculer_texte($texte, $id_boucle, $boucles, $id_mere)
+{
+	$code = ".\n '".ereg_replace("([\\\\'])", "\\\\1", $texte)."'";
+
+        // bloc multi
+        if (eregi('<multi>', $texte)) {
+                $ouvre_multi = 'extraire_multi(';
+                $ferme_multi = ')';
+        } else {
+                $ouvre_multi = $ferme_multi = '';
+        }
+
+	// Reperer les balises de traduction <:toto:>
+
+	while (eregi("<:(([a-z0-9_]+):)?([a-z0-9_]+)(\|[^>]*)?:>", $code, $match)) {
+		//
+		// Traiter la balise de traduction multilingue
+		//
+		$chaine = strtolower($match[3]);
+ 		if (!($module = $match[2]))
+		  // ordre des modules a explorer
+		  $module = 'local/public/spip';
+		// il faudrait traiter un $m non vide
+		list ($c,$m) = applique_filtres(explode('|',
+							substr($match[4],1)),
+						"_T('$module:$chaine')",
+						$id_boucle, 
+						$boucles,
+						$id_mere);
+		$code = str_replace($match[0], 
+				    "'$ferme_multi.$c.$ouvre_multi'",
+				    $code);
+	}
+
+	return (ereg('^\..', $code) ? substr($code,2) : $code);
+}
+?>
diff --git a/inc-vrac-squel.php3 b/inc-vrac-squel.php3
new file mode 100644
index 0000000000..c12ce1fb62
--- /dev/null
+++ b/inc-vrac-squel.php3
@@ -0,0 +1,286 @@
+<?php
+
+# Fonction de traduction des champs Spip basiques
+# A terme, elle devrait etre remplace'e par autant de fonctions que de 'case'
+
+function calculer_champ_divers($fonctions, $nom_champ, $id_boucle, &$boucles, $id_mere)
+{
+  global  $flag_pcre;
+
+  switch($nom_champ) {
+
+	// Introduction (d'un article, d'une breve ou d'un message de forum)
+
+  case 'INTRODUCTION':
+		$code = 'calcul_introduction(\'' .
+		  $boucles[$id_boucle]->type_requete . "',\n" .
+		  index_pile($id_boucle,  "texte", &$boucles) . ",\n" .
+		  index_pile($id_boucle,  "chapo", &$boucles) . ",\n" .
+		  index_pile($id_boucle,  "descriptif", &$boucles) . ")\n"; 
+		break;
+
+  case 'NOM_SITE_SPIP':
+		$code = "lire_meta('nom_site')";
+		break;
+
+  case 'EMAIL_WEBMASTER':
+		$code = "lire_meta('email_webmaster')";
+		break;
+
+  case 'CHARSET':
+		$code = "lire_meta('charset')";
+		break;
+
+
+  case 'LANG_LEFT':
+		$code = "lang_dir(\$GLOBALS['spip_lang'],'left','right')";
+		break;
+
+  case 'LANG_RIGHT':
+		$code = "lang_dir(\$GLOBALS['spip_lang'],'right','left')";
+		break;
+
+  case 'LANG_DIR':
+		$code = "lang_dir(\$GLOBALS['spip_lang'],'ltr','rtl')";
+		break;
+
+  case 'PUCE':
+		$code = "propre('- ')";
+		break;
+
+
+  case 'DATE_NOUVEAUTES':
+		$code = "((lire_meta('quoi_de_neuf') == 'oui' AND lire_meta('majnouv')) ? normaliser_date(lire_meta('majnouv')) : \"'0000-00-00'\")";
+		break;
+
+  case 'URL_SITE_SPIP':
+		$code = "lire_meta('adresse_site')";
+		break;
+
+  case 'URL_ARTICLE':
+		$code = "generer_url_article(" . 
+		  index_pile($id_boucle,  'id_article', &$boucles) . 
+		  ")" ;
+		  if ($boucles[$id_boucle]->hash)
+		    $code = "url_var_recherche(" . $code . ")";
+		break;
+
+  case 'URL_RUBRIQUE':
+		$code = "generer_url_rubrique(" . 
+		  index_pile($id_boucle,  'id_rubrique', &$boucles) . 
+		  ")" ;
+		  if ($boucles[$id_boucle]->hash)
+		    $code = "url_var_recherche(" . $code . ")";
+		break;
+
+  case 'URL_BREVE':
+		$code = "generer_url_breve(" .
+		  index_pile($id_boucle,  'id_breve', &$boucles) . 
+		  ")";
+		  if ($boucles[$id_boucle]->hash)
+		    $code = "url_var_recherche(" . $code . ")";
+		break;
+
+  case 'URL_MOT':
+		$code = "generer_url_mot(" .
+		  index_pile($id_boucle,  'id_mot', &$boucles) .
+		  ")";
+		$code = "url_var_recherche(" . $code . ")";
+		break;
+
+  case 'URL_FORUM':
+		$code = "generer_url_forum(" .
+		  index_pile($id_boucle,  'id_forum', &$boucles) .")";
+		break;
+
+  case 'URL_DOCUMENT':
+		$code = "generer_url_document(" .
+		  index_pile($id_boucle,  'id_document', &$boucles) . ")";
+		break;
+
+  case 'URL_AUTEUR': # 1.7.2
+               $code = "generer_url_auteur(" .
+                 index_pile($id_boucle,  'id_forum', &$boucles) .")";
+               if ($boucles[$id_boucle]->hash)
+                   $code = "url_var_recherche(" . $code . ")";
+               break;
+ 
+  case 'NOTES':
+		$milieu = '$lacible = $GLOBALS["les_notes"];
+			$GLOBALS["les_notes"] = "";
+			$GLOBALS["compt_note"] = 0;
+			$GLOBALS["marqueur_notes"] ++;
+			';
+		$code = '$lacible';
+		break;
+
+  case 'RECHERCHE':
+		$code = 'htmlspecialchars($GLOBALS["recherche"])';
+		break;
+
+  case 'COMPTEUR_BOUCLE':
+		$code = '$compteur_boucle';
+		break;
+
+  case 'TOTAL_BOUCLE':
+	  $n = 0;
+	  $b = $id_boucle;
+	  // si $id_boucle est vide, c'est la racine 
+	  // il faudrait dire a` l'auteur du squelette que ca n'a pas de sens
+	  while ($b != $id_mere)
+	    {
+	      $n++;
+	      $b = $boucles[$b]->id_parent;
+	      // c~a ne devrait pas arriver si id_mere != '',
+	      // mais je ne prends pas le risque
+	      if (!$b) break;
+	    }
+	$code = '$PileNum[$SP' . (($n==0) ? "" : "+$n") . ']';
+	$boucles[$id_boucle]->numrows = true;
+#	spip_log("TOTAL_BOUCLE: $id_boucle dans $id_mere");
+		break;
+
+  case 'POPULARITE_ABSOLUE':
+		$code = 'ceil(' .
+		  index_pile($id_boucle,  "popularite", &$boucles) .
+		  ')';
+		break;
+
+  case 'POPULARITE_SITE':
+                $code = 'ceil(lire_meta(\'popularite_total\'))';
+                break;
+
+  case 'POPULARITE_MAX':
+                $code = 'ceil(lire_meta(\'popularite_max\'))';
+                break;
+
+
+  case 'EXPOSER':
+          break;
+                $on = 'on';
+                $off='';
+                if ($fonctions) {
+                        // Gerer la notation [(#EXPOSER|on,off)]
+                        reset($fonctions);
+                        list(, $onoff) = each($fonctions);
+                        ereg("([^,]*)(,(.*))?", $onoff, $regs);
+                        $on = addslashes($regs[1]);
+                        $off = addslashes($regs[3]);
+
+                        // autres filtres
+                        $filtres=Array();
+                        while (list(, $nom) = each($fonctions)) {
+                                $filtres[] = $nom;
+                        }
+                        $fonctions = $filtres;
+                }
+                $id_on_off = $table_primary[$boucles[$id_boucle]->type_requete];
+                if ($id_on_off) 
+                        $code = "(\$PileRow[0]['$id_on_off'] == \$PileRow[\$SP]['$id_on_off']) ?
+ '$on' : '$off'";
+                else 
+                        $code = "'$off'";
+                break;
+	//
+	// Inserer directement un document dans le squelette
+	//
+	case 'EMBED_DOCUMENT':
+		$milieu = "
+		include_ecrire('inc_documents.php3');";
+		$code = "embed_document(" .
+		  index_pile($id_boucle,  'id_document', &$boucles) . ", '" .
+			($fonctions) ? join($fonctions, "|") : "" .
+			"', false)";
+		$fonctions = "";
+		break;
+
+	// Debut et fin de surlignage auto des mots de la recherche
+	// on inse`re une balise Span avec une classe sans spec:
+	// c'est transparent s'il n'y a pas de recherche,
+	// sinon elles seront remplace'es par les fontions de inc_surligne
+	// flag_pcre est juste une flag signalant que preg_match est dispo.
+
+  case 'DEBUT_SURLIGNE':
+	  $code = ($flag_pcre ? ('\'<span class="spip_surligneconditionnel">\'') : '');
+	  break;
+  case 'FIN_SURLIGNE':
+	  $code = ($flag_pcre ? ('\'</span class="spip_surligneconditionnel">\'') : '');
+	  break;
+
+  case 'MENU_LANG':
+                $code = '"<"."?php
+                        include_ecrire(\"inc_lang.php3\");
+                        echo menu_langues(\"var_lang\", \$menu_lang);
+                        ?".">"';
+                break;
+
+        //
+        // Formulaire de changement de langue / page de login
+  case 'MENU_LANG_ECRIRE':
+                $code = '"<"."?php
+                        include_ecrire(\"inc_lang.php3\");
+                        echo menu_langues(\"var_lang_ecrire\", \$menu_lang);
+                        ?".">"';
+
+                break;
+
+	//
+	// Formulaires de login
+	//
+  case 'LOGIN_PRIVE':
+	  $code = '"<"."?php include(\'inc-login.php3\'); login(\'\', \'prive\'); ?".">"'; 
+		break;
+
+  case 'LOGIN_PUBLIC':
+    $lacible = '\$GLOBALS[\'clean_link\']';
+    if ($fonctions) {
+      $filtres = array();
+      while (list(, $nom) = each($fonctions))
+	$lacible = "new Link('".$nom."')";
+      $fonctions = $filtres;
+    }
+    $code = '"<"."?php include(\'inc-login.php3\'); login(' . $lacible . ', false); ?".">"';
+    break;
+
+  case 'URL_LOGOUT':
+                if ($fonctions) {
+                        $url = "&url=".$fonctions[0];
+                        $fonctions = array();
+                } else {
+                        $url = '&url=\'.urlencode(\$clean_link->getUrl()).\'';
+                }
+                $code = '"<"."?php if (\$GLOBALS[\'auteur_session\'][\'login\'])
+ { echo \'spip_cookie.php3?logout_public=\'.\$GLOBALS[\'auteur_session\'][\'login\'].\'' . $url . '\'; } ?".">"';
+		break;
+
+  case 'LOGO_ARTICLE':
+  case 'LOGO_ARTICLE_NORMAL':
+  case 'LOGO_ARTICLE_RUBRIQUE':
+  case 'LOGO_ARTICLE_SURVOL':
+  case 'LOGO_AUTEUR':
+  case 'LOGO_AUTEUR_NORMAL':
+  case 'LOGO_AUTEUR_SURVOL':
+  case 'LOGO_SITE':
+  case 'LOGO_BREVE':
+  case 'LOGO_BREVE_RUBRIQUE':
+  case 'LOGO_MOT':
+  case 'LOGO_RUBRIQUE':
+  case 'LOGO_RUBRIQUE_NORMAL':
+  case 'LOGO_RUBRIQUE_SURVOL':
+  case 'LOGO_DOCUMENT' :
+    // retour imme'diat: filtres de'rogatoires traite's dans la fonction
+    return calculer_champ_LOGO($fonctions, $nom_champ, $id_boucle, &$boucles, $id_mere);
+    break; 
+
+  default:
+	  // champ inconnu. Il s'auto-de'note.
+	    $code = "'#$nom_champ'";
+	  break;
+	} // switch
+
+  list($c,$m) = applique_filtres($fonctions, $code, $id_boucle, $boucles, $id_mere);
+  return array($c,$milieu . $m);
+}
+
+
+?>
diff --git a/spip_cache.php3 b/spip_cache.php3
index ef93805b49..6660c89286 100644
--- a/spip_cache.php3
+++ b/spip_cache.php3
@@ -9,21 +9,20 @@ include_local("inc-cache.php3");
 
 if ($purger_cache == "oui") {
 	if (verifier_action_auteur("purger_cache", $hash, $id_auteur)) {
-		purger_repertoire('CACHE', 0);
-		spip_query("DELETE FROM spip_forum_cache");
+	  retire_caches_pages();
+	  retire_caches_squelette();
 	}
 }
 
 if ($purger_squelettes == "oui") {
-	if (verifier_action_auteur("purger_squelettes", $hash, $id_auteur)) {
-		purger_repertoire('CACHE', 0, '^skel_');
+	if (verifier_action_auteur("purger_squelettes", $hash, $id_auteur))
+	  retire_caches_squelette();
 	}
-}
 
 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("ecrire/Include/MySQL3/spip_cache.php");
+		include("ecrire/Include/MySQL3/spip_cache_mysql3.php");
 		if ($supp_forum) 
 			changer_statut_forum($supp_forum, 'off');
 		else if ($supp_forum_priv)
@@ -31,7 +30,8 @@ if ($supp_forum OR $supp_forum_priv OR $valid_forum) {
 		else if ($valid_forum)
 			changer_statut_forum($valid_forum, 'publie');
 	}
-}
+ }
+ 
 
 @header ("Location: ./ecrire/" . $redirect);
 
diff --git a/spip_image.php3 b/spip_image.php3
index 856070c996..057e5eef56 100644
--- a/spip_image.php3
+++ b/spip_image.php3
@@ -8,6 +8,34 @@ include_ecrire("inc_meta.php3");
 include_ecrire("inc_admin.php3");
 include_local("inc-cache.php3");
 
+// Retourne true si le sous-repertoire peut etre cree, false sinon
+# issu de l'ancienne version du cache
+
+function creer_repertoire($base, $subdir) {
+	if (file_exists("$base/.plat")) return false;
+	$path = $base.'/'.$subdir;
+	if (file_exists($path)) return true;
+
+	@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;
+		}
+	}
+	return $ok;
+}
+
 $taille_preview = lire_meta("taille_preview");
 if ($taille_preview < 10) $taille_preview = 120;
 
-- 
GitLab