diff --git a/htdocs/admin/modules.php b/htdocs/admin/modules.php
index b61e5a4a86e3275701d9a9782184c8b1468c8a72..e34861450eb663ed51604d3353d1db3aba55669c 100644
--- a/htdocs/admin/modules.php
+++ b/htdocs/admin/modules.php
@@ -29,12 +29,15 @@
 
 require '../main.inc.php';
 require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
-require_once DOL_DOCUMENT_ROOT . '/core/lib/functions2.lib.php';
+require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
+require_once DOL_DOCUMENT_ROOT.'/core/lib/geturl.lib.php';
+require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
 
 $langs->load("errors");
 $langs->load("admin");
 
-$mode=GETPOST('mode', 'alpha')?GETPOST('mode', 'alpha'):0;
+$mode=GETPOST('mode', 'alpha');
+if (empty($mode)) $mode='common';
 $action=GETPOST('action','alpha');
 $value=GETPOST('value', 'alpha');
 $page_y=GETPOST('page_y','int');
@@ -69,13 +72,14 @@ if ($search_status)  $param.='&search_status='.urlencode($search_status);
 if ($search_nature)  $param.='&search_nature='.urlencode($search_nature);
 if ($search_version) $param.='&search_version='.urlencode($search_version);
 
+$dirins=DOL_DOCUMENT_ROOT.'/custom';
+$urldolibarrmodules='https://www.dolistore.com/';
 
 
 /*
  * Actions
  */
 
-
 if (GETPOST('buttonreset'))
 {
     $search_keyword='';
@@ -84,6 +88,103 @@ if (GETPOST('buttonreset'))
     $search_version='';
 }
 
+if ($action=='install')
+{
+    $error=0;
+
+    // $original_file should match format module_modulename-x.y[.z].zip
+    $original_file=basename($_FILES["fileinstall"]["name"]);
+    $newfile=$conf->admin->dir_temp.'/'.$original_file.'/'.$original_file;
+
+    if (! $original_file)
+    {
+        $langs->load("Error");
+        setEventMessages($langs->trans("ErrorModuleFileRequired"), null, 'warnings');
+        $error++;
+    }
+    else
+    {
+        if (! preg_match('/\.zip/i',$original_file))
+        {
+            $langs->load("errors");
+            setEventMessages($langs->trans("ErrorFileMustBeADolibarrPackage",$original_file), null, 'errors');
+            $error++;
+        }
+    }
+
+    if (! $error)
+    {
+        if ($original_file)
+        {
+            @dol_delete_dir_recursive($conf->admin->dir_temp.'/'.$original_file);
+            dol_mkdir($conf->admin->dir_temp.'/'.$original_file);
+        }
+
+        $tmpdir=preg_replace('/\.zip$/','',$original_file).'.dir';
+        if ($tmpdir)
+        {
+            @dol_delete_dir_recursive($conf->admin->dir_temp.'/'.$tmpdir);
+            dol_mkdir($conf->admin->dir_temp.'/'.$tmpdir);
+        }
+
+        $result=dol_move_uploaded_file($_FILES['fileinstall']['tmp_name'],$newfile,1,0,$_FILES['fileinstall']['error']);
+        if ($result > 0)
+        {
+            $result=dol_uncompress($newfile,$conf->admin->dir_temp.'/'.$tmpdir);
+
+            if (! empty($result['error']))
+            {
+                $langs->load("errors");
+                setEventMessages($langs->trans($result['error'],$original_file), null, 'errors');
+                $error++;
+            }
+            else
+            {
+                // Now we move the dir of the module
+                $modulename=preg_replace('/module_/', '', $original_file);
+                $modulename=preg_replace('/\-[\d]+\.[\d]+.*$/', '', $modulename);
+                // Search dir $modulename
+                $modulenamedir=$conf->admin->dir_temp.'/'.$tmpdir.'/'.$modulename;
+                //var_dump($modulenamedir);
+                if (! dol_is_dir($modulenamedir))
+                {
+                    $modulenamedir=$conf->admin->dir_temp.'/'.$tmpdir.'/htdocs/'.$modulename;
+                    //var_dump($modulenamedir);
+                    if (! dol_is_dir($modulenamedir))
+                    {
+                        setEventMessages($langs->trans("ErrorModuleFileSeemsToHaveAWrongFormat"), null, 'errors');
+                        $error++;
+                    }
+                }
+
+                if (! $error)
+                {
+                    //var_dump($dirins);
+                    @dol_delete_dir_recursive($dirins.'/'.$modulename);
+                    dol_syslog("Uncompress of module file is a success. We copy it from ".$modulenamedir." into target dir ".$dirins.'/'.$modulename);
+                    $result=dolCopyDir($modulenamedir, $dirins.'/'.$modulename, '0444', 1);
+                    if ($result <= 0)
+                    {
+                        dol_syslog('Failed to call dolCopyDir result='.$result." with param ".$modulenamedir." and ".$dirins.'/'.$modulename, LOG_WARNING);
+                        $langs->load("errors");
+                        setEventMessages($langs->trans("ErrorFailToCopyDir", $modulenamedir, $dirins.'/'.$modulename), null, 'errors');
+                        $error++;
+                    }
+                }
+            }
+        }
+        else
+        {
+            $error++;
+        }
+    }
+
+    if (! $error)
+    {
+        setEventMessages($langs->trans("SetupIsReadyForUse", DOL_URL_ROOT.'/admin/modules.php?mainmenu=home', $langs->transnoentitiesnoconv("Home").' - '.$langs->transnoentitiesnoconv("Setup").' - '.$langs->transnoentitiesnoconv("Modules")), null, 'warnings');
+    }
+}
+
 if ($action == 'set' && $user->admin)
 {
     $resarray = activateModule($value);
@@ -115,6 +216,13 @@ if ($action == 'reset' && $user->admin)
  * View
  */
 
+// Set dir where external modules are installed
+if (! dol_is_dir($dirins))
+{
+    dol_mkdir($dirins);
+}
+$dirins_ok=(dol_is_dir($dirins));
+
 $form = new Form($db);
 
 $help_url='EN:First_setup|FR:Premiers_paramétrages|ES:Primeras_configuraciones';
@@ -277,33 +385,35 @@ if ($nbofactivatedmodules <= 1) $moreinfo .= ' '.img_warning($langs->trans("YouM
 print load_fiche_titre($langs->trans("ModulesSetup"),$moreinfo,'title_setup');
 
 // Start to show page
-if (empty($mode)) $mode='common';
-if ($mode==='common')      print $langs->trans("ModulesDesc")."<br>\n";
-if ($mode==='marketplace') print $langs->trans("ModulesMarketPlaceDesc")."<br>\n";
-if ($mode==='expdev')      print $langs->trans("ModuleFamilyExperimental")."<br>\n";
+if ($mode=='common')      print $langs->trans("ModulesDesc")."<br>\n";
+if ($mode=='marketplace') print $langs->trans("ModulesMarketPlaceDesc")."<br>\n";
+if ($mode=='deploy')      print $langs->trans("ModulesDeployDesc", $langs->transnoentitiesnoconv("AvailableModules"))."<br>\n";
 
 
 $h = 0;
 
-$categidx='common';    // Main
-$head[$h][0] = DOL_URL_ROOT."/admin/modules.php?mode=".$categidx;
+$head[$h][0] = DOL_URL_ROOT."/admin/modules.php?mode=common";
 $head[$h][1] = $langs->trans("AvailableModules");
 $head[$h][2] = 'common';
 $h++;
 
-$categidx='marketplace';
-$head[$h][0] = DOL_URL_ROOT."/admin/modules.php?mode=".$categidx;
+$head[$h][0] = DOL_URL_ROOT."/admin/modules.php?mode=marketplace";
 $head[$h][1] = $langs->trans("ModulesMarketPlaces");
 $head[$h][2] = 'marketplace';
 $h++;
 
+$head[$h][0] = DOL_URL_ROOT."/admin/modules.php?mode=deploy";
+$head[$h][1] = $langs->trans("AddExtensionThemeModuleOrOther");
+$head[$h][2] = 'deploy';
+$h++;
+
 
 print "<br>\n";
 
 
 $var=true;
 
-if ($mode != 'marketplace')
+if ($mode == 'common')
 {
     
     print '<form method="GET" id="searchFormList" action="'.$_SERVER["PHP_SELF"].'">';
@@ -351,7 +461,6 @@ if ($mode != 'marketplace')
         //print '</div>';
     }
     
-    //dol_fiche_end();
     
     print '<div class="clearboth"></div><br>';
 
@@ -477,163 +586,6 @@ if ($mode != 'marketplace')
             $imginfo="info_black";
         }
         
-        // Define text of description of module
-        /*
-        $text='';
-        
-        if ($objMod->getDescLong()) $text.='<div class="titre">'.$objMod->getDesc().'</div><br>'.$objMod->getDescLong().'<br>';
-        else $text.='<div class="titre">'.$objMod->getDesc().'</div><br>';
-        
-        $text.='<br><strong>'.$langs->trans("Version").':</strong> '.$version;
-        
-        $textexternal='';
-        if ($objMod->isCoreOrExternalModule() == 'external')
-        {
-            $textexternal.='<br><strong>'.$langs->trans("Origin").':</strong> '.$langs->trans("ExternalModule",$dirofmodule);
-            if ($objMod->editor_name != 'dolibarr') $textexternal.='<br><strong>'.$langs->trans("Publisher").':</strong> '.(empty($objMod->editor_name)?$langs->trans("Unknown"):$objMod->editor_name);
-            if (! empty($objMod->editor_url) && ! preg_match('/dolibarr\.org/i',$objMod->editor_url)) $textexternal.='<br><strong>'.$langs->trans("Url").':</strong> '.$objMod->editor_url;
-            $text.=$textexternal;
-            $text.='<br>';
-        }
-        else
-        {
-            $text.='<br><strong>'.$langs->trans("Origin").':</strong> '.$langs->trans("Core").'<br>';
-        }
-        $text.='<br><strong>'.$langs->trans("LastActivationDate").':</strong> ';
-        if (! empty($conf->global->$const_name)) $text.=dol_print_date($objMod->getLastActivationDate(), 'dayhour');
-        else $text.=$langs->trans("Disabled");
-        $text.='<br>';
-        
-        $text.='<br><strong>'.$langs->trans("AddRemoveTabs").':</strong> ';
-        if (isset($objMod->tabs) && is_array($objMod->tabs) && count($objMod->tabs))
-        {
-            $i=0;
-            foreach($objMod->tabs as $val)
-            {
-                $tmp=explode(':',$val,3);
-                $text.=($i?', ':'').$tmp[0].':'.$tmp[1];
-                $i++;
-            }
-        }
-        else $text.=$langs->trans("No");
-        
-        $text.='<br><strong>'.$langs->trans("AddDictionaries").':</strong> ';
-        if (isset($objMod->dictionaries) && isset($objMod->dictionaries['tablib']) && is_array($objMod->dictionaries['tablib']) && count($objMod->dictionaries['tablib']))
-        {
-            $i=0;
-            foreach($objMod->dictionaries['tablib'] as $val)
-            {
-                $text.=($i?', ':'').$val;
-                $i++;
-            }
-        }
-        else $text.=$langs->trans("No");
-        
-        $text.='<br><strong>'.$langs->trans("AddBoxes").':</strong> ';
-        if (isset($objMod->boxes) && is_array($objMod->boxes) && count($objMod->boxes))
-        {
-            $i=0;
-            foreach($objMod->boxes as $val)
-            {
-                $text.=($i?', ':'').($val['file']?$val['file']:$val[0]);
-                $i++;
-            }
-        }
-        else $text.=$langs->trans("No");
-        
-        $text.='<br><strong>'.$langs->trans("AddModels").':</strong> ';
-        if (isset($objMod->module_parts) && isset($objMod->module_parts['models']) && $objMod->module_parts['models'])
-        {
-            $text.=$langs->trans("Yes");
-        }
-        else $text.=$langs->trans("No");
-        
-        $text.='<br><strong>'.$langs->trans("AddSubstitutions").':</strong> ';
-        if (isset($objMod->module_parts) && isset($objMod->module_parts['substitutions']) && $objMod->module_parts['substitutions'])
-        {
-            $text.=$langs->trans("Yes");
-        }
-        else $text.=$langs->trans("No");
-        
-        $text.='<br><strong>'.$langs->trans("AddSheduledJobs").':</strong> ';
-        if (isset($objMod->cronjobs) && is_array($objMod->cronjobs) && count($objMod->cronjobs))
-        {
-            $i=0;
-            foreach($objMod->cronjobs as $val)
-            {
-                $text.=($i?', ':'').($val['label']);
-                $i++;
-            }
-        }
-        else $text.=$langs->trans("No");
-        
-        $text.='<br><strong>'.$langs->trans("AddTriggers").':</strong> ';
-        if (isset($objMod->module_parts) && isset($objMod->module_parts['triggers']) && $objMod->module_parts['triggers'])
-        {
-            $text.=$langs->trans("Yes");
-        }
-        else $text.=$langs->trans("No");
-        
-        $text.='<br><strong>'.$langs->trans("AddHooks").':</strong> ';
-        if (isset($objMod->module_parts) && is_array($objMod->module_parts['hooks']) && count($objMod->module_parts['hooks']))
-        {
-            $i=0;
-            foreach($objMod->module_parts['hooks'] as $val)
-            {
-                $text.=($i?', ':'').($val);
-                $i++;
-            }
-        }
-        else $text.=$langs->trans("No");
-        
-        $text.='<br><strong>'.$langs->trans("AddPermissions").':</strong> ';
-        if (isset($objMod->rights) && is_array($objMod->rights) && count($objMod->rights))
-        {
-            $i=0;
-            foreach($objMod->rights as $val)
-            {
-                $text.=($i?', ':'').($val[1]);
-                $i++;
-            }
-        }
-        else $text.=$langs->trans("No");
-        
-        $text.='<br><strong>'.$langs->trans("AddMenus").':</strong> ';
-        if (isset($objMod->menu) && ! empty($objMod->menu)) // objMod can be an array or just an int 1
-        {
-            $text.=$langs->trans("Yes");
-        }
-        else $text.=$langs->trans("No");
-        
-        $text.='<br><strong>'.$langs->trans("AddExportProfiles").':</strong> ';
-        if (isset($objMod->export_label) && is_array($objMod->export_label) && count($objMod->export_label))
-        {
-            $i=0;
-            foreach($objMod->export_label as $val)
-            {
-                $text.=($i?', ':'').($val);
-                $i++;
-            }
-        }
-        else $text.=$langs->trans("No");
-        
-        $text.='<br><strong>'.$langs->trans("AddImportProfiles").':</strong> ';
-        if (isset($objMod->import_label) && is_array($objMod->import_label) && count($objMod->import_label))
-        {
-            $i=0;
-            foreach($objMod->import_label as $val)
-            {
-                $text.=($i?', ':'').($val);
-                $i++;
-            }
-        }
-        else $text.=$langs->trans("No");
-        
-        $text.='<br><strong>'.$langs->trans("AddOtherPagesOrServices").':</strong> ';
-        $text.=$langs->trans("DetectionNotPossible");
-        */
-        
-        //print "\n<!-- Module ".$objMod->numero." ".$objMod->getName()." found into ".$dirmod[$key]." -->\n";
         print '<tr '.$bc[$var].">\n";
 
         // Picto
@@ -768,8 +720,11 @@ if ($mode != 'marketplace')
     }
     print "</table>\n";
     print '</div>';
+    
+    dol_fiche_end();
 }
-else
+
+if ($mode == 'marketplace')
 {
     dol_fiche_head($head, $mode, '');
     
@@ -799,13 +754,115 @@ else
 
     print "</table>\n";
 
-    //dol_fiche_end();
+    dol_fiche_end();
+}
+
+
+// Install external module
+   
+if ($mode == 'deploy')
+{
+    dol_fiche_head($head, $mode, '');
+
+    
+    $allowonlineinstall=true;
+    $allowfromweb=1;
+    if (dol_is_file($dolibarrdataroot.'/installmodules.lock')) $allowonlineinstall=false;
+    
+    $fullurl='<a href="'.$urldolibarrmodules.'" target="_blank">'.$urldolibarrmodules.'</a>';
+    $message='';
+    if (! empty($allowonlineinstall))
+    {
+        if (! in_array('/custom',explode(',',$dolibarr_main_url_root_alt)))
+        {
+            $message=info_admin($langs->trans("ConfFileMuseContainCustom", DOL_DOCUMENT_ROOT.'/custom', DOL_DOCUMENT_ROOT));
+            $allowfromweb=-1;
+        }
+        else
+        {
+            if ($dirins_ok)
+            {
+                if (! is_writable(dol_osencode($dirins)))
+                {
+                    $langs->load("errors");
+                    $message=info_admin($langs->trans("ErrorFailedToWriteInDir",$dirins));
+                    $allowfromweb=0;
+                }
+            }
+            else
+            {
+    
+                $message=info_admin($langs->trans("NotExistsDirect",$dirins).$langs->trans("InfDirAlt").$langs->trans("InfDirExample"));
+                $allowfromweb=0;
+            }
+        }
+    }
+    else
+    {
+        $message=info_admin($langs->trans("InstallModuleFromWebHasBeenDisabledByFile",$dolibarrdataroot.'/installmodules.lock'));
+        $allowfromweb=0;
+    }
+    
+    if ($allowfromweb < 1)
+    {
+    	print $langs->trans("SomethingMakeInstallFromWebNotPossible");
+    	print $message;
+    	//print $langs->trans("SomethingMakeInstallFromWebNotPossible2");
+    	print '<br>';
+    }
+    
+    
+    if ($allowfromweb >= 0)
+    {
+    	if ($allowfromweb == 1) 
+    	{
+    	    //print $langs->trans("ThisIsProcessToFollow").'<br>';
+    	}
+    	else 
+    	{
+    	    print $langs->trans("ThisIsAlternativeProcessToFollow").'<br>';
+        	print '<b>'.$langs->trans("StepNb",1).'</b>: ';
+        	print $langs->trans("FindPackageFromWebSite",$fullurl).'<br>';
+        	print '<b>'.$langs->trans("StepNb",2).'</b>: ';
+        	print $langs->trans("DownloadPackageFromWebSite",$fullurl).'<br>';
+        	print '<b>'.$langs->trans("StepNb",3).'</b>: ';
+    	}
+    
+    	if ($allowfromweb == 1)
+    	{
+    		print $langs->trans("UnpackPackageInModulesRoot",$dirins).'<br>';
+    		print '<form enctype="multipart/form-data" method="POST" class="noborder" action="'.$_SERVER["PHP_SELF"].'" name="forminstall">';
+    		print '<input type="hidden" name="action" value="install">';
+    		print '<input type="hidden" name="mode" value="deploy">';
+    		print $langs->trans("YouCanSubmitFile").' <input type="file" name="fileinstall"> ';
+    		print '<input type="submit" name="send" value="'.dol_escape_htmltag($langs->trans("Send")).'" class="button">';
+    		print '</form>';
+    	}
+    	else
+    	{
+    		print $langs->trans("UnpackPackageInModulesRoot",$dirins).'<br>';
+    		print '<b>'.$langs->trans("StepNb",4).'</b>: ';
+    		print $langs->trans("SetupIsReadyForUse").'<br>';
+    	}
+    }
+    
+    
+    if (! empty($result['return']))
+    {
+    	print '<br>';
+    
+    	foreach($result['return'] as $value)
+    	{
+    		echo $value.'<br>';
+    	}
+    }
+
+    dol_fiche_end();
 }
 
-dol_fiche_end();
 
 // Show warning about external users
-if ($mode != 'marketplace') print info_admin(showModulesExludedForExternal($modules))."\n";
+if ($mode == 'common') print info_admin(showModulesExludedForExternal($modules))."\n";
 
 
 llxFooter();
diff --git a/htdocs/admin/tools/update.php b/htdocs/admin/tools/update.php
index 912016b498c54a439be6ae2aa3c5c9a55cc91e7d..d8b17ab989bbd263be3b1fd876eb0583ff5716fa 100644
--- a/htdocs/admin/tools/update.php
+++ b/htdocs/admin/tools/update.php
@@ -1,5 +1,5 @@
 <?php
-/* Copyright (C) 2007-2012 Laurent Destailleur  <eldy@users.sourceforge.net>
+/* Copyright (C) 2007-2017 Laurent Destailleur  <eldy@users.sourceforge.net>
  * Copyright (C) 2009-2012 Regis Houssin        <regis.houssin@capnetworks.com>
  * Copyright (C) 2012      Juanjo Menent        <jmenent@2byte.es>
  *
@@ -23,9 +23,9 @@
  */
 
 require '../../main.inc.php';
-include_once DOL_DOCUMENT_ROOT . '/core/lib/admin.lib.php';
-include_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php';
-include_once DOL_DOCUMENT_ROOT . '/core/lib/geturl.lib.php';
+require_once DOL_DOCUMENT_ROOT . '/core/lib/admin.lib.php';
+require_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php';
+require_once DOL_DOCUMENT_ROOT . '/core/lib/geturl.lib.php';
 
 $langs->load("admin");
 $langs->load("other");
@@ -40,111 +40,23 @@ if (GETPOST('msg','alpha')) {
 
 
 $urldolibarr='https://www.dolibarr.org/downloads/';
-$urldolibarrmodules='https://www.dolistore.com/';
-$urldolibarrthemes='https://www.dolistore.com/';
 $dolibarrroot=preg_replace('/([\\/]+)$/i','',DOL_DOCUMENT_ROOT);
 $dolibarrroot=preg_replace('/([^\\/]+)$/i','',$dolibarrroot);
 $dolibarrdataroot=preg_replace('/([\\/]+)$/i','',DOL_DATA_ROOT);
 
-$dirins=DOL_DOCUMENT_ROOT.'/custom';
+$sfurl = '';
+$version='0.0';
 
 
 /*
  *	Actions
  */
 
-if ($action=='install')
+if ($action == 'getlastversion')
 {
-	$error=0;
-
-	// $original_file should match format module_modulename-x.y[.z].zip
-	$original_file=basename($_FILES["fileinstall"]["name"]);
-	$newfile=$conf->admin->dir_temp.'/'.$original_file.'/'.$original_file;
-
-	if (! $original_file)
-	{
-		$langs->load("Error");
-		setEventMessages($langs->trans("ErrorFileRequired"), null, 'warnings');
-		$error++;
-	}
-	else
-	{
-		if (! preg_match('/\.zip/i',$original_file))
-		{
-			$langs->load("errors");
-			setEventMessages($langs->trans("ErrorFileMustBeADolibarrPackage",$original_file), null, 'errors');
-			$error++;
-		}
-	}
-
-	if (! $error)
-	{
-		if ($original_file)
-		{
-			@dol_delete_dir_recursive($conf->admin->dir_temp.'/'.$original_file);
-			dol_mkdir($conf->admin->dir_temp.'/'.$original_file);
-		}
-
-		$tmpdir=preg_replace('/\.zip$/','',$original_file).'.dir';
-		if ($tmpdir)
-		{
-			@dol_delete_dir_recursive($conf->admin->dir_temp.'/'.$tmpdir);
-			dol_mkdir($conf->admin->dir_temp.'/'.$tmpdir);
-		}
-
-		$result=dol_move_uploaded_file($_FILES['fileinstall']['tmp_name'],$newfile,1,0,$_FILES['fileinstall']['error']);
-		if ($result > 0)
-		{
-			$result=dol_uncompress($newfile,$conf->admin->dir_temp.'/'.$tmpdir);
-
-			if (! empty($result['error']))
-			{
-				$langs->load("errors");
-				setEventMessages($langs->trans($result['error'],$original_file), null, 'errors');
-				$error++;
-			}
-			else
-			{
-				// Now we move the dir of the module
-				$modulename=preg_replace('/module_/', '', $original_file);
-				$modulename=preg_replace('/\-[\d]+\.[\d]+.*$/', '', $modulename);
-				// Search dir $modulename
-				$modulenamedir=$conf->admin->dir_temp.'/'.$tmpdir.'/'.$modulename;
-				//var_dump($modulenamedir);
-				if (! dol_is_dir($modulenamedir))
-				{
-					$modulenamedir=$conf->admin->dir_temp.'/'.$tmpdir.'/htdocs/'.$modulename;
-					//var_dump($modulenamedir);
-					if (! dol_is_dir($modulenamedir))
-					{
-						setEventMessages($langs->trans("ErrorModuleFileSeemsToHaveAWrongFormat"), null, 'errors');
-						$error++;
-					}
-				}
-
-				if (! $error)
-				{
-					//var_dump($dirins);
-					@dol_delete_dir_recursive($dirins.'/'.$modulename);
-					$result=dolCopyDir($modulenamedir, $dirins.'/'.$modulename, '0444', 1);
-					if ($result <= 0)
-					{
-						setEventMessages($langs->trans("ErrorFailedToCopy"), null, 'errors');
-						$error++;
-					}
-				}
-			}
-		}
-		else
-		{
-			$error++;
-		}
-	}
-
-	if (! $error)
-	{
-		setEventMessages($langs->trans("SetupIsReadyForUse", DOL_URL_ROOT.'/admin/modules.php?mainmenu=home', $langs->transnoentitiesnoconv("Home").' - '.$langs->transnoentitiesnoconv("Setup").' - '.$langs->transnoentitiesnoconv("Modules")), null, 'warnings');
-	}
+    $result = getURLContent('http://sourceforge.net/projects/dolibarr/rss');
+    //var_dump($result['content']);
+    $sfurl = simplexml_load_string($result['content']);
 }
 
 
@@ -152,15 +64,6 @@ if ($action=='install')
  * View
  */
 
-
-
-// Set dir where external modules are installed
-if (! dol_is_dir($dirins))
-{
-	dol_mkdir($dirins);
-}
-$dirins_ok=(dol_is_dir($dirins));
-
 $wikihelp='EN:Installation_-_Upgrade|FR:Installation_-_Mise_à_jour|ES:Instalación_-_Actualización';
 llxHeader('',$langs->trans("Upgrade"),$wikihelp);
 
@@ -172,36 +75,40 @@ if (function_exists('curl_init'))
 {
     $conf->global->MAIN_USE_RESPONSE_TIMEOUT = 10;
     
-    $result = getURLContent('http://sourceforge.net/projects/dolibarr/rss');
-    //var_dump($result['content']);
-    $sfurl = simplexml_load_string($result['content']);
-    if ($sfurl)
+    if ($action == 'getlastversion')
     {
-        $i=0;
-        $version='0.0';
-        while (! empty($sfurl->channel[0]->item[$i]->title) && $i < 10000)
+        if ($sfurl)
         {
-            $title=$sfurl->channel[0]->item[$i]->title;
-            if (preg_match('/([0-9]+\.([0-9\.]+))/', $title, $reg))
+            $i=0;
+            while (! empty($sfurl->channel[0]->item[$i]->title) && $i < 10000)
             {
-                $newversion=$reg[1];
-                $newversionarray=explode('.',$newversion);
-                $versionarray=explode('.',$version);
-                //var_dump($newversionarray);var_dump($versionarray);
-                if (versioncompare($newversionarray, $versionarray) > 0) $version=$newversion;
+                $title=$sfurl->channel[0]->item[$i]->title;
+                if (preg_match('/([0-9]+\.([0-9\.]+))/', $title, $reg))
+                {
+                    $newversion=$reg[1];
+                    $newversionarray=explode('.',$newversion);
+                    $versionarray=explode('.',$version);
+                    //var_dump($newversionarray);var_dump($versionarray);
+                    if (versioncompare($newversionarray, $versionarray) > 0) $version=$newversion;
+                }
+                $i++;
             }
-            $i++;
+            
+            // Show version
+        	print $langs->trans("LastStableVersion").' : <b>'. (($version != '0.0')?$version:$langs->trans("Unknown")) .'</b><br>';
+        }
+        else
+        {
+            print $langs->trans("LastStableVersion").' : <b>' .$langs->trans("UpdateServerOffline").'</b><br>';
         }
-        
-        // Show version
-    	print $langs->trans("LastStableVersion").' : <b>'. (($version != '0.0')?$version:$langs->trans("Unknown")) .'</b><br>';
     }
     else
     {
-        print $langs->trans("LastStableVersion").' : <b>' .$langs->trans("UpdateServerOffline").'</b><br>';
+        print $langs->trans("LastStableVersion").' : <a href="'.$_SERVER["PHP_SELF"].'?action=getlastversion" class="button">' .$langs->trans("Check").'</a><br>';
     }
 }
 
+print '<br>';
 print '<br>';
 
 // Upgrade
@@ -225,105 +132,14 @@ print '<br>';
 print '<br>';
 
 
-// Install external module
-
-$allowonlineinstall=true;
-$allowfromweb=1;
-if (dol_is_file($dolibarrdataroot.'/installmodules.lock')) $allowonlineinstall=false;
-
-$fullurl='<a href="'.$urldolibarrmodules.'" target="_blank">'.$urldolibarrmodules.'</a>';
-$message='';
-if (! empty($allowonlineinstall))
-{
-	if (! in_array('/custom',explode(',',$dolibarr_main_url_root_alt)))
-	{
-		$message=info_admin($langs->trans("ConfFileMuseContainCustom", DOL_DOCUMENT_ROOT.'/custom', DOL_DOCUMENT_ROOT));
-		$allowfromweb=-1;
-	}
-	else
-	{
-		if ($dirins_ok)
-		{
-			if (! is_writable(dol_osencode($dirins)))
-			{
-				$langs->load("errors");
-				$message=info_admin($langs->trans("ErrorFailedToWriteInDir",$dirins));
-				$allowfromweb=0;
-			}
-		}
-		else
-		{
-
-			$message=info_admin($langs->trans("NotExistsDirect",$dirins).$langs->trans("InfDirAlt").$langs->trans("InfDirExample"));
-			$allowfromweb=0;
-		}
-	}
-}
-else
-{
-	$message=info_admin($langs->trans("InstallModuleFromWebHasBeenDisabledByFile",$dolibarrdataroot.'/installmodules.lock'));
-	$allowfromweb=0;
-}
-
-
 
 
 
 print $langs->trans("AddExtensionThemeModuleOrOther").'<br>';
 print '<hr>';
 
-if ($allowfromweb < 1)
-{
-	print $langs->trans("SomethingMakeInstallFromWebNotPossible");
-	print $message;
-	//print $langs->trans("SomethingMakeInstallFromWebNotPossible2");
-	print '<br>';
-}
-
-
-if ($allowfromweb >= 0)
-{
-	if ($allowfromweb == 1) 
-	{
-	    //print $langs->trans("ThisIsProcessToFollow").'<br>';
-	}
-	else 
-	{
-	    print $langs->trans("ThisIsAlternativeProcessToFollow").'<br>';
-    	print '<b>'.$langs->trans("StepNb",1).'</b>: ';
-    	print $langs->trans("FindPackageFromWebSite",$fullurl).'<br>';
-    	print '<b>'.$langs->trans("StepNb",2).'</b>: ';
-    	print $langs->trans("DownloadPackageFromWebSite",$fullurl).'<br>';
-    	print '<b>'.$langs->trans("StepNb",3).'</b>: ';
-	}
-
-	if ($allowfromweb == 1)
-	{
-		print $langs->trans("UnpackPackageInModulesRoot",$dirins).'<br>';
-		print '<form enctype="multipart/form-data" method="POST" class="noborder" action="'.$_SERVER["PHP_SELF"].'" name="forminstall">';
-		print '<input type="hidden" name="action" value="install">';
-		print $langs->trans("YouCanSubmitFile").' <input type="file" name="fileinstall"> ';
-		print '<input type="submit" name="send" value="'.dol_escape_htmltag($langs->trans("Send")).'" class="button">';
-		print '</form>';
-	}
-	else
-	{
-		print $langs->trans("UnpackPackageInModulesRoot",$dirins).'<br>';
-		print '<b>'.$langs->trans("StepNb",4).'</b>: ';
-		print $langs->trans("SetupIsReadyForUse").'<br>';
-	}
-}
-
+print $langs->trans("GoModuleSetupArea", DOL_URL_ROOT.'/admin/modules.php?mode=deploy', $langs->transnoentities("Home").' - '.$langs->transnoentities("Setup").' - '.$langs->transnoentities("Modules"));
 
-if (! empty($result['return']))
-{
-	print '<br>';
-
-	foreach($result['return'] as $value)
-	{
-		echo $value.'<br>';
-	}
-}
 
 llxFooter();
 
diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang
index 6ee9a1854f481c2a29b2fed4ea5e3724beccfc9f..36d8772dccb60ddcc3a21d700b7d37e255a32937 100644
--- a/htdocs/langs/en_US/admin.lang
+++ b/htdocs/langs/en_US/admin.lang
@@ -191,7 +191,9 @@ BoxesDesc=Widgets are components showing some information that you can add to pe
 OnlyActiveElementsAreShown=Only elements from <a href="%s">enabled modules</a> are shown.
 ModulesDesc=Dolibarr modules define which functionality is enabled in software. Some modules require permissions you must grant to users, after enabling module. Click on button on/off to enable a module/feature.
 ModulesMarketPlaceDesc=You can find more modules to download on external websites on the Internet...
-ModulesMarketPlaces=More modules...
+ModulesDeployDesc=If permissions on your file system allows it, you can use this tool to deploy an external module. The module wil then be visible on the tab <strong>%s</strong>.
+ModulesMarketPlaces=Find external modules...
+GoModuleSetupArea=To deploy/install a new module, go onto the Module setup area at <a href="%s">%s</a>.
 DoliStoreDesc=DoliStore, the official market place for Dolibarr ERP/CRM external modules
 DoliPartnersDesc=List of companies providing custom developed modules or features (Note: anyone experienced in PHP programming can provide custom development for an open source project)
 WebSiteDesc=Reference websites to find more modules...
@@ -283,16 +285,16 @@ MenuHandlers=Menu handlers
 MenuAdmin=Menu editor
 DoNotUseInProduction=Do not use in production
 ThisIsProcessToFollow=This is steps to process:
-ThisIsAlternativeProcessToFollow=This is an alternative setup to process:
+ThisIsAlternativeProcessToFollow=This is an alternative setup to process manually:
 StepNb=Step %s
 FindPackageFromWebSite=Find a package that provides feature you want (for example on official web site %s).
 DownloadPackageFromWebSite=Download package (for example from official web site %s).
-UnpackPackageInDolibarrRoot=Unpack package files into Dolibarr server directory dedicated to Dolibarr: <b>%s</b>
-UnpackPackageInModulesRoot=Unpack package files into Dolibarr server directory dedicated to modules: <b>%s</b>
-oiSetupIsReadyForUse=Module deployement is finished. You must however enable and setup the module in your application by going on the page to setup modules: <a href="%s">%s</a>.
-NotExistsDirect=The alternative root directory is not defined.<br>
-InfDirAlt=Since version 3 it is possible to define an alternative root directory.This allows you to store, same place, plug-ins and custom templates.<br>Just create a directory at the root of Dolibarr (eg: custom).<br>
-InfDirExample=<br>Then declare it in the file conf.php<br> $dolibarr_main_url_root_alt='http://myserver/custom'<br>$dolibarr_main_document_root_alt='/path/of/dolibarr/htdocs/custom'<br>*These lines are commented with "#", to uncomment only remove the character.
+UnpackPackageInDolibarrRoot=Unpack the packaged files into server directory dedicated to Dolibarr: <b>%s</b>
+UnpackPackageInModulesRoot=To deploy/install an external module, unpack the packaged files into the server directory dedicated to modules: <b>%s</b>
+SetupIsReadyForUse=Module deployment is finished. You must however enable and setup the module in your application by going on the page to setup modules: <a href="%s">%s</a>.
+NotExistsDirect=The alternative root directory is not defined to an existing directory.<br>
+InfDirAlt=Since version 3, it is possible to define an alternative root directory. This allows you to store, into a dedicated directory, plug-ins and custom templates.<br>Just create a directory at the root of Dolibarr (eg: custom).<br>
+InfDirExample=<br>Then declare it in the file <strong>conf.php</strong><br> $dolibarr_main_url_root_alt='http://myserver/custom'<br>$dolibarr_main_document_root_alt='/path/of/dolibarr/htdocs/custom'<br>If these lines are commented with "#", to enable them, just uncomment by removing the "#" character.
 YouCanSubmitFile=For this step, you can send package using this tool: Select module file
 CurrentVersion=Dolibarr current version
 CallUpdatePage=Go to the page that updates the database structure and data: %s.
@@ -895,7 +897,7 @@ Offset=Offset
 AlwaysActive=Always active
 Upgrade=Upgrade
 MenuUpgrade=Upgrade / Extend
-AddExtensionThemeModuleOrOther=Add extension (theme, module, ...)
+AddExtensionThemeModuleOrOther=Deploy/install external module
 WebServer=Web server
 DocumentRootServer=Web server's root directory
 DataRootServer=Data files directory
@@ -1582,7 +1584,7 @@ BackupDumpWizard=Wizard to build database backup dump file
 SomethingMakeInstallFromWebNotPossible=Installation of external module is not possible from the web interface for the following reason:
 SomethingMakeInstallFromWebNotPossible2=For this reason, process to upgrade described here is only manual steps a privileged user can do. 
 InstallModuleFromWebHasBeenDisabledByFile=Install of external module from application has been disabled by your administrator. You must ask him to remove the file <strong>%s</strong> to allow this feature.
-ConfFileMuseContainCustom=Installing an external module from application need to save the module files into directory <strong>%s</strong>. To have this directory processed by Dolibarr, you must setup your <strong>conf/conf.php</strong> to have option<br><strong>$dolibarr_main_url_root_alt='/custom';</strong><br><strong>$dolibarr_main_document_root_alt='%s/custom';</strong> 
+ConfFileMuseContainCustom=Installing an external module from application need to save the module files into directory <strong>%s</strong>. To have this directory processed by Dolibarr, you must setup your <strong>conf/conf.php</strong> to add the 2 directive lines:<br><strong>$dolibarr_main_url_root_alt='/custom';</strong><br><strong>$dolibarr_main_document_root_alt='%s/custom';</strong> 
 HighlightLinesOnMouseHover=Highlight table lines when mouse move passes over
 HighlightLinesColor=Highlight color of the line when the mouse passes over (keep empty for no highlight)
 TextTitleColor=Color of page title
diff --git a/htdocs/langs/en_US/errors.lang b/htdocs/langs/en_US/errors.lang
index edbf603e8fc6ee0e7ae66d6332fe8449d3f83d34..e493bc675247c2c49be5687da0d5a02384fd0eb6 100644
--- a/htdocs/langs/en_US/errors.lang
+++ b/htdocs/langs/en_US/errors.lang
@@ -11,6 +11,7 @@ ErrorLoginAlreadyExists=Login %s already exists.
 ErrorGroupAlreadyExists=Group %s already exists.
 ErrorRecordNotFound=Record not found.
 ErrorFailToCopyFile=Failed to copy file '<b>%s</b>' into '<b>%s</b>'.
+ErrorFailToCopyDir=Failed to copy directory '<b>%s</b>' into '<b>%s</b>'.
 ErrorFailToRenameFile=Failed to rename file '<b>%s</b>' into '<b>%s</b>'.
 ErrorFailToDeleteFile=Failed to remove file '<b>%s</b>'.
 ErrorFailToCreateFile=Failed to create file '<b>%s</b>'.
@@ -115,7 +116,7 @@ ErrorNoActivatedBarcode=No barcode type activated
 ErrUnzipFails=Failed to unzip %s with ZipArchive
 ErrNoZipEngine=No engine to unzip %s file in this PHP
 ErrorFileMustBeADolibarrPackage=The file %s must be a Dolibarr zip package
-ErrorFileRequired=It takes a package Dolibarr file
+ErrorModuleFileRequired=You must select a Dolibarr module package file
 ErrorPhpCurlNotInstalled=The PHP CURL is not installed, this is essential to talk with Paypal
 ErrorFailedToAddToMailmanList=Failed to add record %s to Mailman list %s or SPIP base
 ErrorFailedToRemoveToMailmanList=Failed to remove record %s to Mailman list %s or SPIP base