diff --git a/.gitattributes b/.gitattributes
index 992f562b7614a591ead811708accaf5f8478c841..6abf7d286a70c19732c307ed444d84e7d8a3d65d 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -639,19 +639,19 @@ ecrire/lang/spip_cs.php -text
 ecrire/lang/spip_id.php -text
 ecrire/lang/spip_it_fem.php -text
 ecrire/lang/spip_ru.php -text
+ecrire/lib/safehtml/classes/HTMLSax3.php -text
+ecrire/lib/safehtml/classes/HTMLSax3/Decorators.php -text
+ecrire/lib/safehtml/classes/HTMLSax3/States.php -text
+ecrire/lib/safehtml/classes/HTMLSax3/index.php -text
+ecrire/lib/safehtml/classes/index.php -text
+ecrire/lib/safehtml/classes/safehtml.php -text
+ecrire/lib/safehtml/index.php -text
+ecrire/lib/safehtml/license.txt -text
+ecrire/lib/safehtml/readme-SPIP.txt -text
+ecrire/lib/safehtml/readme.txt -text
 ecrire/prive.php -text
 ecrire/public/index.php -text
 ecrire/rien.gif -text
-ecrire/safehtml/classes/HTMLSax3.php -text
-ecrire/safehtml/classes/HTMLSax3/Decorators.php -text
-ecrire/safehtml/classes/HTMLSax3/States.php -text
-ecrire/safehtml/classes/HTMLSax3/index.php -text
-ecrire/safehtml/classes/index.php -text
-ecrire/safehtml/classes/safehtml.php -text
-ecrire/safehtml/index.php -text
-ecrire/safehtml/license.txt -text
-ecrire/safehtml/readme-SPIP.txt -text
-ecrire/safehtml/readme.txt -text
 ecrire/typographie/en.php -text
 ecrire/typographie/fr.php -text
 ecrire/typographie/index.php -text
diff --git a/ecrire/action/charger_plugin.php b/ecrire/action/charger_plugin.php
index 96f36ad9644c3bb43b90e8b51212e062dc189102..fab4ba482a07f1f23b773a39ed28b8e9b878cf09 100644
--- a/ecrire/action/charger_plugin.php
+++ b/ecrire/action/charger_plugin.php
@@ -62,24 +62,14 @@ function action_charger_plugin_dist() {
 	}
 
 	## si ici on n'est pas en POST c'est qu'il y a un loup
-	if (!$_POST) die('pas normal');
-
-	# destination finale des fichiers
-	switch($arg) {
-		case 'lib':
-			$dest = sous_repertoire(_DIR_PLUGINS_AUTO, 'lib');
-			break;
-		case 'auto':
-		default:
-			$dest = _DIR_PLUGINS_AUTO;
-			break;
-	}
+	if (!$_POST) die('pas en POST ?');
+
+	# Si definie a '', le chargeur est interdit ; mais on n'aurait de toutes
+	# facons jamais pu venir ici avec toutes les securisations faites :^)
+	if (!_DIR_PLUGINS_AUTO) die('jamais');
 
 	# si premiere lecture, destination temporaire des fichiers
-	$tmp = _request('extract')
-		? $dest
-		: sous_repertoire(_DIR_CACHE,'chargeur');
-	
+	$tmp = sous_repertoire(_DIR_CACHE, 'chargeur');
 
 	# dispose-t-on du fichier ?
 	$status = null;
@@ -91,7 +81,7 @@ function action_charger_plugin_dist() {
 		if (!$contenu
 		OR !ecrire_fichier($fichier, $contenu)) {
 			spip_log('charger_decompresser impossible de charger '.$zip);
-			$status = 0;
+			$status = -1;
 		}
 	}
 
@@ -99,7 +89,7 @@ function action_charger_plugin_dist() {
 		$status = chargeur_charger_zip(
 			array(
 				'zip' => $zip,
-				'dest' => $dest,
+				'arg' => $arg,
 				'fichier' => $fichier,
 				'tmp' => $tmp,
 				'extract' => _request('extract')
@@ -116,8 +106,31 @@ function action_charger_plugin_dist() {
 	// le fichier .zip est la et bien forme
 	if (is_array($status)) {
 
+		// Reconnaitre un plugin par son plugin.xml
+		if (@file_exists($status['tmpname'].'/plugin.xml')) {
+			$type = 'plugin';
+			$dest = _DIR_PLUGINS_AUTO;
+		} else {
+			$type = 'lib';
+			$dest = 'lib/';
+		}
+
+		// Fixer son emplacement définitif
+		$status['dirname'] = $dest
+			. basename($status['tmpname']) . '/';
+
+		// repertoire parent accessible en ecriture ?
+		if (!@is_dir($dest)
+		OR !@is_writeable($dest)) {
+			$retour = _L("Erreur");
+			$texte = "<p>"._L("Le r&#233;pertoire $dest n'est pas accessible en &#233;criture.")."</p>"
+				. "<p>"._L("Veuillez v&#233;rifier les droits sur ce r&#233;pertoire et recommencer, ou installer les fichiers par FTP.")."</p>";
+		}
+		else
+
 		// C'est un plugin ?
-		if (lire_fichier($xml=$status['tmpname'].'/plugin.xml', $pluginxml)) {
+		if ($type == 'plugin') {
+			lire_fichier($xml=$status['tmpname'].'/plugin.xml', $pluginxml);
 
 			include_spip('inc/xml');
 			$arbre = spip_xml_load($xml);
@@ -143,15 +156,16 @@ function action_charger_plugin_dist() {
 				$texte = '<p>'._L('Le fichier '.$zip.' a &#233;t&#233; t&#233;l&#233;charg&#233;').'</p>';
 				$texte .= liste_fichiers_pclzip($status);
 				$texte .= _L("<h2 style='text-align:center;'>Vous pouvez maintenant l'installer.</h2>");
-				$suite = 'auto';
+				$suite = 'plugins';
 			}
 		}
 
 		// C'est un paquet quelconque
 		else {
 			$retour = _L('Chargement du paquet') . ' '.basename($status['tmpname']);
+
 			if (_request('extract')) {
-				$texte = '<p>'._L('Le fichier '.$zip.' a &#233;t&#233; d&#233;compact&#233; et install&#233; dans le répertoire '.$dest).'</p>';
+				$texte = '<p>'._L('Le fichier '.$zip.' a &#233;t&#233; d&#233;compact&#233; et install&#233; dans le r&#233;pertoire '.$status['dirname']).'</p>';
 			} else {
 				$texte = "<p>"._L("Le fichier ".$zip.' a &#233;t&#233; t&#233;l&#233;charg&#233;.')."</p>\n";
 				$texte .= liste_fichiers_pclzip($status);
@@ -160,18 +174,19 @@ function action_charger_plugin_dist() {
 		}
 	}
 
-	// fichier la mais pas bien dezippe
-	else if ($status < 0) {
+	// fichier absent
+	else if ($status == -1) {
 		$retour = _T('erreur');
-		$texte = _L("echec pclzip : erreur ").$status;
+		$texte = _L('erreur : impossible de charger '.$zip);
 	}
 
-	// fichier absent
-	else if ($status == 0) {
+	// fichier la mais pas bien dezippe
+	else {
 		$retour = _T('erreur');
-		$texte = _L('erreur : impossible de charger '.$zip);
+		$texte = _L("echec pclzip : erreur ").$status;
 	}
 
+
 	include_spip('exec/install'); // pour bouton_suivant()
 
 	$texte = "<div style='text-align:$spip_lang_left;'>$texte</div>\n";
diff --git a/ecrire/inc/charger_plugin.php b/ecrire/inc/charger_plugin.php
index 5aa6836a391ccf5b7b52e654daab49edc4f3023e..0b73133486e7d7dfc00dfc3490c3b86dae19fdc6 100644
--- a/ecrire/inc/charger_plugin.php
+++ b/ecrire/inc/charger_plugin.php
@@ -119,7 +119,7 @@ function interface_plugins_auto($retour) {
 		.  "</div>\n";
 
 	$res = redirige_action_auteur('charger_plugin',
-				'auto', // arg = _DIR_PLUGINS_AUTO
+				'', // arg = 'plugins' / 'lib', a priori
 				'',
 				'',
 				$res,
@@ -145,18 +145,33 @@ function chargeur_charger_zip($quoi = array())
 		$quoi['zip'] = $quoi['depot'] . $quoi['nom'] . '.zip';
 	}
 	foreach (array(	'remove' => 'spip',
-					'dest' => _DIR_RACINE,
+					'arg' => 'lib',
 					'plugin' => null,
 					'cache_cache' => null,
 					'rename' => array(),
 					'edit' => array(),
 					'root_extract' => false, # extraire a la racine de dest ?
-					'tmp' => sous_repertoire(_DIR_TMP, 'chargeur')
+					'tmp' => sous_repertoire(_DIR_CACHE, 'chargeur')
 				)
 				as $opt=>$def) {
 		isset($quoi[$opt]) || ($quoi[$opt] = $def);
 	}
 
+
+	# destination finale des fichiers
+	switch($quoi['arg']) {
+		case 'lib':
+			$quoi['dest'] = 'lib/';
+			break;
+		case 'plugins':
+			$quoi['dest'] = _DIR_PLUGINS_AUTO;
+			break;
+		default:
+			$quoi['dest'] = '';
+			break;
+	}
+
+
 	if (!@file_exists($fichier = $quoi['fichier']))
 		return 0;
 
@@ -194,7 +209,7 @@ function chargeur_charger_zip($quoi = array())
 		? $quoi['dest']
 		: $quoi['dest'] . $nom.'/';
 
-	$tmpname = $quoi['tmp'].$nom;
+	$tmpname = $quoi['tmp'].$nom.'/';
 
 	// On extrait, mais dans tmp/ si on ne veut pas vraiment le faire
 	$ok = $zip->extract(
@@ -210,7 +225,8 @@ function chargeur_charger_zip($quoi = array())
 	if ($zip->error_code < 0) {
 		spip_log('charger_decompresser erreur zip ' . $zip->error_code .
 			' pour paquet: ' . $quoi['zip']);
-		return $zip->error_code;
+		return //$zip->error_code
+			$zip->errorName(true);
 	}
 
 /*
@@ -332,6 +348,7 @@ function chargeur_activer_plugin($plugin)
 // http://doc.spip.org/@liste_fichiers_pclzip
 function liste_fichiers_pclzip($status) {
 	$list = $status['files'];
+
 	$ret = '<b>'._L('Il contient les fichiers suivants ('
 		.taille_en_octets($status['size']).'),<br />pr&#234;ts &#224; installer dans le r&#233;pertoire <code>'.$status['dirname']).'</code></b>';
 
@@ -439,12 +456,13 @@ function afficher_liste_listes_plugins() {
 	return $ret;
 }
 
-function bouton_telechargement_plugin($url) {
-	// pas de chargement auto : on donne l'url du zip
+// Si le chargement auto est autorise, un bouton
+// sinon on donne l'url du zip
+function bouton_telechargement_plugin($url, $rep) {
 	if (_DIR_PLUGINS_AUTO
 	AND @is_dir(_DIR_PLUGINS_AUTO))
 		$bouton = redirige_action_auteur('charger_plugin',
-			'auto', // arg = _DIR_PLUGINS_AUTO, a priori
+			$rep, // arg = 'lib' ou 'plugins'
 			'',
 			'',
 			"<input type='hidden' name='url_zip_plugin' value='$url' />"
diff --git a/ecrire/inc/plugin.php b/ecrire/inc/plugin.php
index 6d5e436b83ffa20e728d1977df45200b24f87818..4dce884a1c1b98dcf3a0984b924b85031e3414a0 100644
--- a/ecrire/inc/plugin.php
+++ b/ecrire/inc/plugin.php
@@ -78,15 +78,15 @@ function erreur_necessite($n, $liste) {
 		}
 
 		// Necessite une librairie ?
-		else if (preg_match(',^LIB:(.*),i', $id, $r)) {
-			$lib = trim($r[1]);
-			if (!find_lib($lib)) {
+		else if (preg_match(',^(lib):(.*),i', $need['id'], $r)) {
+			$lib = trim($r[2]);
+			if (!find_in_path('lib/'.$lib)) {
 				$lien_download = '';
 				if (isset($n[0]['src'])) {
 					$url = $n[0]['src'];
 					include_ecrire('inc/charger_plugin');
 					$lien_download = '<br />'
-						.bouton_telechargement_plugin($url);
+						.bouton_telechargement_plugin($url, strtolower($r[1]));
 				}
 				$msg .= "<li>"
 				._L('Ce plugin n&#233;cessite la librairie '.$lib)
diff --git a/ecrire/inc/safehtml.php b/ecrire/inc/safehtml.php
index c9fae952d52f9d6e59223995e55d0b3c49e08817..e0ac2f0ba9b04ba52a5ad39c6605d6413d2d57b4 100644
--- a/ecrire/inc/safehtml.php
+++ b/ecrire/inc/safehtml.php
@@ -15,40 +15,41 @@ if (!defined("_ECRIRE_INC_VERSION")) return;
 
 // Controle la presence de la lib safehtml et cree la fonction
 // de transformation du texte qui l'exploite
-if (@is_dir(_DIR_RESTREINT.'safehtml')) {
 // http://doc.spip.org/@inc_safehtml_dist
-	function inc_safehtml_dist($t) {
-		static $process, $test;
-
-		if (!$test) {
-			if ($f = include_spip('safehtml/classes/safehtml', false)) {
-				define('XML_HTMLSAX3', dirname($f).'/');
-				include($f);
-				$process = new safehtml();
-				$process->deleteTags[] = 'param'; // sinon bug Firefox
-			} else die('pas de safe');
-			if ($process)
-				$test = 1; # ok
-			else
-				$test = -1; # se rabattre sur interdire_scripts
+function inc_safehtml_dist($t) {
+	static $process, $test;
+
+	if (!$test) {
+		$process = false;
+		if ($f = find_in_path('lib/safehtml/classes')) {
+			define('XML_HTMLSAX3', $f.'/');
+			require_once XML_HTMLSAX3.'safehtml.php';
+			$process = new safehtml();
+			$process->deleteTags[] = 'param'; // sinon bug Firefox
 		}
+		if ($process)
+			$test = 1; # ok
+		else
+			$test = -1; # se rabattre sur une fonction de securite basique
+	}
 
-		if ($test > 0) {
-			# reset ($process->clear() ne vide que _xhtml...),
-			# on doit pouvoir programmer ca plus propremement
-			$process->_counter = array();
-			$process->_stack = array();
-			$process->_dcCounter = array();
-			$process->_dcStack = array();
-			$process->_listScope = 0;
-			$process->_liStack = array();
+	if ($test > 0) {
+		# reset ($process->clear() ne vide que _xhtml...),
+		# on doit pouvoir programmer ca plus propremement
+		$process->_counter = array();
+		$process->_stack = array();
+		$process->_dcCounter = array();
+		$process->_dcStack = array();
+		$process->_listScope = 0;
+		$process->_liStack = array();
 #		$process->parse(''); # cas particulier ?
-			$process->clear();
-			$t = $process->parse($t);
-		}
-
-		return $t;
+		$process->clear();
+		$t = $process->parse($t);
 	}
+	else
+		$t = entites_html($t); // tres laid, en cas d'erreur
+
+	return $t;
 }
 
-?>
\ No newline at end of file
+?>
diff --git a/ecrire/inc/utils.php b/ecrire/inc/utils.php
index 247cb651a13a8ae4359b0188aba6a640dfd122a2..73597fe9c27f1a824b54a372ab8e8b0864c3e577 100644
--- a/ecrire/inc/utils.php
+++ b/ecrire/inc/utils.php
@@ -684,15 +684,7 @@ function creer_chemin() {
 // destine aux plugins qui veulent des lib non spip
 // dans le chemin mais aussi dans _DIR_PLUGINS_AUTO
 function find_lib($lib) {
-	if (!$lib)
-		return null;
-	return (
-		($b = find_in_path($a = 'lib/'.$lib) AND is_dir($b))
-		OR (_DIR_PLUGINS AND @is_dir($b = _DIR_PLUGINS.$a))
-		OR (_DIR_PLUGINS_AUTO AND @is_dir($b = _DIR_PLUGINS_AUTO.$a))
-		)
-			? $b.'/'
-			: false;
+	return find_in_path('lib/'.$lib);
 }
 
 // Cette fonction est appelee une seule fois par hit et par dir du chemin
diff --git a/ecrire/safehtml/classes/HTMLSax3.php b/ecrire/lib/safehtml/classes/HTMLSax3.php
similarity index 100%
rename from ecrire/safehtml/classes/HTMLSax3.php
rename to ecrire/lib/safehtml/classes/HTMLSax3.php
diff --git a/ecrire/safehtml/classes/HTMLSax3/Decorators.php b/ecrire/lib/safehtml/classes/HTMLSax3/Decorators.php
similarity index 100%
rename from ecrire/safehtml/classes/HTMLSax3/Decorators.php
rename to ecrire/lib/safehtml/classes/HTMLSax3/Decorators.php
diff --git a/ecrire/safehtml/classes/HTMLSax3/States.php b/ecrire/lib/safehtml/classes/HTMLSax3/States.php
similarity index 100%
rename from ecrire/safehtml/classes/HTMLSax3/States.php
rename to ecrire/lib/safehtml/classes/HTMLSax3/States.php
diff --git a/ecrire/safehtml/classes/HTMLSax3/index.php b/ecrire/lib/safehtml/classes/HTMLSax3/index.php
similarity index 100%
rename from ecrire/safehtml/classes/HTMLSax3/index.php
rename to ecrire/lib/safehtml/classes/HTMLSax3/index.php
diff --git a/ecrire/safehtml/classes/index.php b/ecrire/lib/safehtml/classes/index.php
similarity index 100%
rename from ecrire/safehtml/classes/index.php
rename to ecrire/lib/safehtml/classes/index.php
diff --git a/ecrire/safehtml/classes/safehtml.php b/ecrire/lib/safehtml/classes/safehtml.php
similarity index 100%
rename from ecrire/safehtml/classes/safehtml.php
rename to ecrire/lib/safehtml/classes/safehtml.php
diff --git a/ecrire/safehtml/index.php b/ecrire/lib/safehtml/index.php
similarity index 100%
rename from ecrire/safehtml/index.php
rename to ecrire/lib/safehtml/index.php
diff --git a/ecrire/safehtml/license.txt b/ecrire/lib/safehtml/license.txt
similarity index 100%
rename from ecrire/safehtml/license.txt
rename to ecrire/lib/safehtml/license.txt
diff --git a/ecrire/safehtml/readme-SPIP.txt b/ecrire/lib/safehtml/readme-SPIP.txt
similarity index 100%
rename from ecrire/safehtml/readme-SPIP.txt
rename to ecrire/lib/safehtml/readme-SPIP.txt
diff --git a/ecrire/safehtml/readme.txt b/ecrire/lib/safehtml/readme.txt
similarity index 100%
rename from ecrire/safehtml/readme.txt
rename to ecrire/lib/safehtml/readme.txt