Bug #16419 ยป class.em_index.php

Administrator Admin, 2006-08-01 18:59

 
1
<?php
2
/***************************************************************
3
*  Copyright notice
4
*
5
*  (c) 1999-2005 Kasper Skaarhoj (kasperYYYY@typo3.com)
6
*  (c) 2005-2006 Karsten Dambekalns <karsten@typo3.org>
7
*  All rights reserved
8
*
9
*  This script is part of the TYPO3 project. The TYPO3 project is
10
*  free software; you can redistribute it and/or modify
11
*  it under the terms of the GNU General Public License as published by
12
*  the Free Software Foundation; either version 2 of the License, or
13
*  (at your option) any later version.
14
*
15
*  The GNU General Public License can be found at
16
*  http://www.gnu.org/copyleft/gpl.html.
17
*  A copy is found in the textfile GPL.txt and important notices to the license
18
*  from the author is found in LICENSE.txt distributed with these scripts.
19
*
20
*
21
*  This script is distributed in the hope that it will be useful,
22
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
23
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24
*  GNU General Public License for more details.
25
*
26
*  This copyright notice MUST APPEAR in all copies of the script!
27
***************************************************************/
28
/**
29
 * Module: Extension manager
30
 *
31
 * $Id: class.em_index.php 2057 2007-02-20 20:44:45Z mundaun $
32
 *
33
 * @author	Kasper Skaarhoj <kasperYYYY@typo3.com>
34
 * @author	Karsten Dambekalns <karsten@typo3.org>
35
 */
36
/**
37
 * [CLASS/FUNCTION INDEX of SCRIPT]
38
 *
39
 *
40
 *
41
 *  194: class SC_mod_tools_em_index extends t3lib_SCbase
42
 *
43
 *              SECTION: Standard module initialization
44
 *  337:     function init()
45
 *  417:     function handleExternalFunctionValue($MM_key='function', $MS_value=NULL)
46
 *  431:     function menuConfig()
47
 *  508:     function main()
48
 *  584:     function printContent()
49
 *
50
 *              SECTION: Function Menu Applications
51
 *  609:     function extensionList_loaded()
52
 *  664:     function extensionList_installed()
53
 *  736:     function extensionList_import()
54
 *  903:     function alterSettings()
55
 *
56
 *              SECTION: Command Applications (triggered by GET var)
57
 * 1005:     function importExtInfo($extKey, $version='')
58
 * 1062:     function fetchMetaData($metaType)
59
 * 1125:     function getMirrorURL()
60
 * 1158:     function installExtension($extKey, $version=null, $mode=EM_INSTALL_VERSION_MIN)
61
 * 1279:     function importExtFromRep($extKey,$version,$loc,$uploadFlag=0,$dontDelete=0,$directInput='')
62
 * 1425:     function showExtDetails($extKey)
63
 *
64
 *              SECTION: Application Sub-functions (HTML parts)
65
 * 1737:     function updatesForm($extKey,$extInfo,$notSilent=0,$script='',$addFields='')
66
 * 1768:     function extDumpTables($extKey,$extInfo)
67
 * 1835:     function getFileListOfExtension($extKey,$conf)
68
 * 1889:     function extDelete($extKey,$extInfo)
69
 * 1920:     function extUpdateEMCONF($extKey,$extInfo)
70
 * 1940:     function extBackup($extKey,$extInfo)
71
 * 1987:     function extBackup_dumpDataTablesLine($tablesArray,$extKey)
72
 * 2015:     function extInformationArray($extKey,$extInfo,$remote=0)
73
 * 2097:     function extInformationArray_dbReq($techInfo,$tableHeader=0)
74
 * 2110:     function extInformationArray_dbInst($dbInst,$current)
75
 * 2129:     function getRepositoryUploadForm($extKey,$extInfo)
76
 *
77
 *              SECTION: Extension list rendering
78
 * 2190:     function extensionListRowHeader($trAttrib,$cells,$import=0)
79
 * 2251:     function extensionListRow($extKey,$extInfo,$cells,$bgColorClass='',$inst_list=array(),$import=0,$altLinkUrl='')
80
 *
81
 *              SECTION: Output helper functions
82
 * 2367:     function wrapEmail($str,$email)
83
 * 2380:     function helpCol($key)
84
 * 2396:     function labelInfo($str)
85
 * 2408:     function extensionTitleIconHeader($extKey,$extInfo,$align='top')
86
 * 2423:     function removeButton()
87
 * 2432:     function installButton()
88
 * 2441:     function noImportMsg()
89
 * 2454:     function depToString($dep,$type='depends')
90
 * 2473:     function stringToDep($dep)
91
 *
92
 *              SECTION: Read information about all available extensions
93
 * 2503:     function getInstalledExtensions()
94
 * 2530:     function getInstExtList($path,&$list,&$cat,$type)
95
 * 2561:     function fixEMCONF($emConf)
96
 * 2600:     function splitVersionRange($ver)
97
 * 2616:     function prepareImportExtList()
98
 * 2660:     function setCat(&$cat,$listArrayPart,$extKey)
99
 *
100
 *              SECTION: Extension analyzing (detailed information)
101
 * 2710:     function makeDetailedExtensionAnalysis($extKey,$extInfo,$validity=0)
102
 * 2892:     function getClassIndexLocallangFiles($absPath,$table_class_prefix,$extKey)
103
 * 2962:     function modConfFileAnalysis($confFilePath)
104
 * 2990:     function serverExtensionMD5Array($extKey,$conf)
105
 * 3015:     function findMD5ArrayDiff($current,$past)
106
 *
107
 *              SECTION: File system operations
108
 * 3047:     function createDirsInPath($dirs,$extDirPath)
109
 * 3065:     function removeExtDirectory($removePath,$removeContentOnly=0)
110
 * 3128:     function clearAndMakeExtensionDir($importedData,$type,$dontDelete=0)
111
 * 3182:     function removeCacheFiles()
112
 * 3192:     function extractDirsFromFileList($files)
113
 * 3218:     function getExtPath($extKey,$type)
114
 *
115
 *              SECTION: Writing to "conf.php" and "localconf.php" files
116
 * 3252:     function writeTYPO3_MOD_PATH($confFilePath,$type,$mP)
117
 * 3289:     function writeNewExtensionList($newExtList)
118
 * 3312:     function writeTsStyleConfig($extKey,$arr)
119
 * 3334:     function updateLocalEM_CONF($extKey,$extInfo)
120
 *
121
 *              SECTION: Compiling upload information, emconf-file etc.
122
 * 3376:     function construct_ext_emconf_file($extKey,$EM_CONF)
123
 * 3407:     function arrayToCode($array, $level=0)
124
 * 3433:     function makeUploadArray($extKey,$conf)
125
 * 3502:     function getSerializedLocalLang($file,$content)
126
 *
127
 *              SECTION: Managing dependencies, conflicts, priorities, load order of extension keys
128
 * 3538:     function addExtToList($extKey,$instExtInfo)
129
 * 3569:     function checkDependencies($extKey, $conf, $instExtInfo)
130
 * 3709:     function removeExtFromList($extKey,$instExtInfo)
131
 * 3746:     function removeRequiredExtFromListArr($listArr)
132
 * 3761:     function managesPriorities($listArr,$instExtInfo)
133
 *
134
 *              SECTION: System Update functions (based on extension requirements)
135
 * 3813:     function checkClearCache($extInfo)
136
 * 3840:     function checkUploadFolder($extKey,$extInfo)
137
 * 3925:     function checkDBupdates($extKey,$extInfo,$infoOnly=0)
138
 * 4022:     function forceDBupdates($extKey, $extInfo)
139
 * 4080:     function tsStyleConfigForm($extKey,$extInfo,$output=0,$script='',$addFields='')
140
 *
141
 *              SECTION: Dumping database (MySQL compliant)
142
 * 4175:     function dumpTableAndFieldStructure($arr)
143
 * 4200:     function dumpStaticTables($tableList)
144
 * 4229:     function dumpHeader()
145
 * 4246:     function dumpTableHeader($table,$fieldKeyInfo,$dropTableIfExists=0)
146
 * 4288:     function dumpTableContent($table,$fieldStructure)
147
 * 4323:     function getTableAndFieldStructure($parts)
148
 *
149
 *              SECTION: TER Communication functions
150
 * 4373:     function uploadExtensionToTER($em)
151
 *
152
 *              SECTION: Various helper functions
153
 * 4411:     function listOrderTitle($listOrder,$key)
154
 * 4436:     function makeVersion($v,$mode)
155
 * 4448:     function renderVersion($v,$raise='')
156
 * 4485:     function ulFolder($extKey)
157
 * 4494:     function importAtAll()
158
 * 4505:     function importAsType($type,$lockType='')
159
 * 4527:     function deleteAsType($type)
160
 * 4548:     function versionDifference($v1,$v2,$div=1)
161
 * 4560:     function first_in_array($str,$array,$caseInsensitive=FALSE)
162
 * 4578:     function includeEMCONF($path,$_EXTKEY)
163
 * 4593:     function searchExtension($extKey,$row)
164
 *
165
 * TOTAL FUNCTIONS: 90
166
 * (This index is automatically created/updated by the extension "extdeveval")
167
 *
168
 */
169

    
170
	// Include classes needed:
171
require_once(PATH_t3lib.'class.t3lib_tcemain.php');
172
require_once(PATH_t3lib.'class.t3lib_install.php');
173
require_once(PATH_t3lib.'class.t3lib_tsstyleconfig.php');
174
require_once(PATH_t3lib.'class.t3lib_scbase.php');
175

    
176
require_once('class.em_xmlhandler.php');
177
require_once('class.em_terconnection.php');
178
require_once('class.em_unzip.php');
179

    
180
	// from tx_ter by Robert Lemke
181
define('TX_TER_RESULT_EXTENSIONSUCCESSFULLYUPLOADED', '10504');
182

    
183
define('EM_INSTALL_VERSION_MIN', 1);
184
define('EM_INSTALL_VERSION_MAX', 2);
185
define('EM_INSTALL_VERSION_STRICT', 3);
186

    
187
/**
188
 * Module: Extension manager
189
 *
190
 * @author	Kasper Skaarhoj <kasperYYYY@typo3.com>
191
 * @author	Karsten Dambekalns <karsten@typo3.org>
192
 * @package TYPO3
193
 * @subpackage core
194
 */
195
class SC_mod_tools_em_index extends t3lib_SCbase {
196

    
197
		// Internal, static:
198
	var $versionDiffFactor = 1;		// This means that version difference testing for import is detected for sub-versions only, not dev-versions. Default: 1000
199
	var $systemInstall = 0;				// If "1" then installs in the sysext directory is allowed. Default: 0
200
	var $requiredExt = '';				// List of required extension (from TYPO3_CONF_VARS)
201
	var $maxUploadSize = 31457280;		// Max size in bytes of extension upload to repository
202
	var $kbMax = 500;					// Max size in kilobytes for files to be edited.
203
	var $doPrintContent = true;			// If set (default), the function printContent() will echo the content which was collected in $this->content. You can set this to FALSE in order to echo content from elsewhere, fx. when using outbut buffering
204
	var $listingLimit = 500;		// List that many extension maximally at one time (fixing memory problems)
205
	var $listingLimitAuthor = 250;		// List that many extension maximally at one time (fixing memory problems)
206

    
207
	/**
208
	 * Internal variable loaded with extension categories (for display/listing). Should reflect $categories above
209
	 * Dynamic var.
210
	 */
211
	var $defaultCategories = Array(
212
		'cat' => Array (
213
			'be' => array(),
214
			'module' => array(),
215
			'fe' => array(),
216
			'plugin' => array(),
217
			'misc' => array(),
218
			'services' => array(),
219
			'templates' => array(),
220
			'example' => array(),
221
			'doc' => array()
222
		)
223
	);
224

    
225
	/**
226
	 * Extension Categories (static var)
227
	 * Content must be redundant with the same internal variable as in class.tx_extrep.php!
228
	 */
229
	var $categories = Array(
230
		'be' => 'Backend',
231
		'module' => 'Backend Modules',
232
		'fe' => 'Frontend',
233
		'plugin' => 'Frontend Plugins',
234
		'misc' => 'Miscellaneous',
235
		'services' => 'Services',
236
		'templates' => 'Templates',
237
		'example' => 'Examples',
238
		'doc' => 'Documentation'
239
	);
240

    
241
	/**
242
	 * Extension States
243
	 * Content must be redundant with the same internal variable as in class.tx_extrep.php!
244
	 */
245
	var $states = Array (
246
		'alpha' => 'Alpha',
247
		'beta' => 'Beta',
248
		'stable' => 'Stable',
249
		'experimental' => 'Experimental',
250
		'test' => 'Test',
251
		'obsolete' => 'Obsolete',
252
	);
253

    
254
	/**
255
	 * Colors for extension states
256
	 */
257
	var $stateColors = Array (
258
		'alpha' => '#d12438',
259
		'beta' => '#97b17e',
260
		'stable' => '#3bb65c',
261
		'experimental' => '#007eba',
262
		'test' => '#979797',
263
		'obsolete' => '#000000',
264
	);
265

    
266
	/**
267
	 * "TYPE" information; labels, paths, description etc.
268
	 */
269
	var $typeLabels = Array (
270
		'S' => 'System',
271
		'G' => 'Global',
272
		'L' => 'Local',
273
	);
274
	var $typeDescr = Array (
275
		'S' => 'System extension (typo3/sysext/) - Always distributed with source code (Static).',
276
		'G' => 'Global extensions (typo3/ext/) - Available for shared source on server (Dynamic).',
277
		'L' => 'Local extensions (typo3conf/ext/) - Local for this TYPO3 installation only (Dynamic).',
278
	);
279
	var $typePaths = Array();			// Also static, set in init()
280
	var $typeBackPaths = Array();		// Also static, set in init()
281

    
282
	var $typeRelPaths = Array (
283
		'S' => 'sysext/',
284
		'G' => 'ext/',
285
		'L' => '../typo3conf/ext/',
286
	);
287

    
288
	var $detailCols = Array (
289
		0 => 2,
290
		1 => 5,
291
		2 => 6,
292
		3 => 6,
293
		4 => 4,
294
		5 => 1
295
	);
296

    
297
	var $fe_user = array(
298
		'username' => '',
299
		'password' => '',
300
	);
301

    
302
	var $privacyNotice = 'When you interact with the online repository, server information may be sent and stored in the repository for statistics.';
303
	var $securityHint = '<strong>Found a security problem? Please get in touch with us!</strong><br />If you think you have found a security issue in TYPO3 or an extension, please contact the <a href="http://typo3.org/teams/security/" target="_blank">TYPO3 security team</a>! Thank you!';
304
	var $editTextExtensions = 'html,htm,txt,css,tmpl,inc,php,sql,conf,cnf,pl,pm,sh,xml,ChangeLog';
305
	var $nameSpaceExceptions = 'beuser_tracking,design_components,impexp,static_file_edit,cms,freesite,quickhelp,classic_welcome,indexed_search,sys_action,sys_workflows,sys_todos,sys_messages,direct_mail,sys_stat,tt_address,tt_board,tt_calender,tt_guest,tt_links,tt_news,tt_poll,tt_rating,tt_products,setup,taskcenter,tsconfig_help,context_help,sys_note,tstemplate,lowlevel,install,belog,beuser,phpmyadmin,aboutmodules,imagelist,setup,taskcenter,sys_notepad,viewpage,adodb';
306

    
307

    
308

    
309

    
310

    
311
		// Default variables for backend modules
312
	var $MCONF = array();				// Module configuration
313
	var $MOD_MENU = array();			// Module menu items
314
	var $MOD_SETTINGS = array();		// Module session settings
315
	var $doc;							// Document Template Object
316
	var $content;						// Accumulated content
317

    
318
	var $inst_keys = array();			// Storage of installed extensions
319
	var $gzcompress = 0;				// Is set true, if system support compression.
320

    
321
	var $terConnection;			// instance of TER connection handler
322

    
323
		// GPvars:
324
	var $CMD = array();					// CMD array
325
	var $listRemote;					// If set, connects to remote repository
326
	var $lookUpStr;						// Search string when listing local extensions
327

    
328

    
329

    
330

    
331
	/*********************************
332
	*
333
	* Standard module initialization
334
	*
335
	*********************************/
336

    
337
	/**
338
	 * Standard init function of a module.
339
	 *
340
	 * @return	void
341
	 */
342
	function init()	{
343
		global $BE_USER,$LANG,$BACK_PATH,$TYPO3_CONF_VARS;
344

    
345
			// Setting paths of install scopes:
346
		$this->typePaths = Array (
347
			'S' => TYPO3_mainDir.'sysext/',
348
			'G' => TYPO3_mainDir.'ext/',
349
			'L' => 'typo3conf/ext/'
350
		);
351
		$this->typeBackPaths = Array (
352
			'S' => '../../../',
353
			'G' => '../../../',
354
			'L' => '../../../../'.TYPO3_mainDir
355
		);
356

    
357
		$this->excludeForPackaging = $GLOBALS['TYPO3_CONF_VARS']['EXT']['excludeForPackaging'];
358

    
359
			// Setting module configuration:
360
		$this->MCONF = $GLOBALS['MCONF'];
361

    
362
			// Setting GPvars:
363
		$this->CMD = t3lib_div::_GP('CMD');
364
		$this->lookUpStr = trim(t3lib_div::_GP('_lookUp'));
365
		$this->listRemote = t3lib_div::_GP('ter_connect');
366
		$this->listRemote_search = trim(t3lib_div::_GP('ter_search'));
367

    
368

    
369
			// Configure menu
370
		$this->menuConfig();
371

    
372
			// Setting internal static:
373
		if ($TYPO3_CONF_VARS['EXT']['allowSystemInstall'])	$this->systemInstall = 1;
374
		$this->requiredExt = t3lib_div::trimExplode(',',$TYPO3_CONF_VARS['EXT']['requiredExt'],1);
375

    
376

    
377
			// Initialize helper object
378
		$this->terConnection = t3lib_div::makeInstance('SC_mod_tools_em_terconnection');
379
		$this->terConnection->emObj =& $this;
380
		$this->terConnection->wsdlURL = $TYPO3_CONF_VARS['EXT']['em_wsdlURL'];
381
		$this->xmlhandler = t3lib_div::makeInstance('SC_mod_tools_em_xmlhandler');
382
		$this->xmlhandler->emObj =& $this;
383
		$this->xmlhandler->useUnchecked = $this->MOD_SETTINGS['display_unchecked'];
384
		$this->xmlhandler->useObsolete = $this->MOD_SETTINGS['display_obsolete'];
385

    
386
			// Initialize Document Template object:
387
		$this->doc = t3lib_div::makeInstance('noDoc');
388
		$this->doc->backPath = $BACK_PATH;
389
		$this->doc->docType = 'xhtml_trans';
390

    
391
			// JavaScript
392
		$this->doc->JScode = $this->doc->wrapScriptTags('
393
			script_ended = 0;
394
			function jumpToUrl(URL)	{	//
395
				window.location.href = URL;
396
			}
397
		');
398
		$this->doc->form = '<form action="index.php" method="post" name="pageform">';
399

    
400
		// Descriptions:
401
		$this->descrTable = '_MOD_'.$this->MCONF['name'];
402
		if ($BE_USER->uc['edit_showFieldHelp'])	{
403
			$LANG->loadSingleTableDescription($this->descrTable);
404
		}
405

    
406
		// Setting username/password etc. for upload-user:
407
		$this->fe_user['username'] = $this->MOD_SETTINGS['fe_u'];
408
		$this->fe_user['password'] = $this->MOD_SETTINGS['fe_p'];
409
		parent::init();
410
		$this->handleExternalFunctionValue('singleDetails');
411
	}
412

    
413
	/**
414
	 * This function is a copy of the same function in t3lib_SCbase with one modification:
415
	 * In contrast to t3lib_SCbase::handleExternalFunctionValue() this function merges the $this->extClassConf array
416
	 * instead of overwriting it. That was necessary for including the Kickstarter as a submodule into the 'singleDetails'
417
	 * selectorbox as well as in the main 'function' selectorbox.
418
	 *
419
	 * @param	string		Mod-setting array key
420
	 * @param	string		Mod setting value, overriding the one in the key
421
	 * @return	void
422
	 * @see t3lib_SCbase::handleExternalFunctionValue()
423
	 */
424
	function handleExternalFunctionValue($MM_key='function', $MS_value=NULL)	{
425
		$MS_value = is_null($MS_value) ? $this->MOD_SETTINGS[$MM_key] : $MS_value;
426
		$externalItems = $this->getExternalItemConfig($this->MCONF['name'],$MM_key,$MS_value);
427
		if (is_array($externalItems))	$this->extClassConf = array_merge($externalItems,is_array($this->extClassConf)?$this->extClassConf:array());
428
		if (is_array($this->extClassConf) && $this->extClassConf['path'])	{
429
			$this->include_once[]=$this->extClassConf['path'];
430
		}
431
	}
432

    
433
	/**
434
	 * Configuration of which mod-menu items can be used
435
	 *
436
	 * @return	void
437
	 */
438
	function menuConfig()	{
439
		global $BE_USER, $TYPO3_CONF_VARS;
440

    
441
		// MENU-ITEMS:
442
		$this->MOD_MENU = array(
443
			'function' => array(
444
				0 => 'Loaded extensions',
445
				1 => 'Install extensions',
446
				2 => 'Import extensions',
447
				4 => 'Translation handling',
448
				3 => 'Settings',
449
			),
450
			'listOrder' => array(
451
				'cat' => 'Category',
452
				'author_company' => 'Author',
453
				'state' => 'State',
454
				'type' => 'Type'
455
			),
456
			'display_details' => array(
457
				1 => 'Details',
458
				0 => 'Description',
459
				2 => 'More details',
460

    
461
				3 => 'Technical (takes time!)',
462
				4 => 'Validating (takes time!)',
463
				5 => 'Changed? (takes time!)',
464
			),
465
			'display_shy' => '',
466
			'display_own' => '',
467
			'display_unchecked' => '',
468
			'display_obsolete' => '',
469

    
470
			'singleDetails' => array(
471
				'info' => 'Information',
472
				'edit' => 'Edit files',
473
				'backup' => 'Backup/Delete',
474
				'dump' => 'Dump DB',
475
				'upload' => 'Upload to TER',
476
				'updateModule' => 'UPDATE!',
477
			),
478
			'fe_u' => '',
479
			'fe_p' => '',
480

    
481
			'mirrorListURL' => '',
482
			'rep_url' => '',
483
			'extMirrors' => '',
484
			'selectedMirror' => '',
485

    
486
			'selectedLanguages' => ''
487
		);
488

    
489
		$this->MOD_MENU['singleDetails'] = $this->mergeExternalItems($this->MCONF['name'],'singleDetails',$this->MOD_MENU['singleDetails']);
490

    
491
		// page/be_user TSconfig settings and blinding of menu-items
492
		if (!$BE_USER->getTSConfigVal('mod.'.$this->MCONF['name'].'.allowTVlisting'))	{
493
			unset($this->MOD_MENU['display_details'][3]);
494
			unset($this->MOD_MENU['display_details'][4]);
495
			unset($this->MOD_MENU['display_details'][5]);
496
		}
497

    
498
		// CLEANSE SETTINGS
499
		$this->MOD_SETTINGS = t3lib_BEfunc::getModuleData($this->MOD_MENU, t3lib_div::_GP('SET'), $this->MCONF['name']);
500

    
501
		if ($this->MOD_SETTINGS['function']==2)	{
502
			// If listing from online repository, certain items are removed though:
503
			unset($this->MOD_MENU['listOrder']['type']);
504
			unset($this->MOD_MENU['display_details'][2]);
505
			unset($this->MOD_MENU['display_details'][3]);
506
			unset($this->MOD_MENU['display_details'][4]);
507
			unset($this->MOD_MENU['display_details'][5]);
508
			$this->MOD_SETTINGS = t3lib_BEfunc::getModuleData($this->MOD_MENU, t3lib_div::_GP('SET'), $this->MCONF['name']);
509
		}
510
		parent::menuConfig();
511
	}
512

    
513
	/**
514
	 * Main function for Extension Manager module.
515
	 *
516
	 * @return	void
517
	 */
518
	function main()	{
519
		global $BE_USER,$LANG,$TYPO3_CONF_VARS;
520

    
521
		if (empty($this->MOD_SETTINGS['mirrorListURL'])) $this->MOD_SETTINGS['mirrorListURL'] = $TYPO3_CONF_VARS['EXT']['em_mirrorListURL'];
522

    
523
		// Starting page:
524
		$this->content.=$this->doc->startPage('Extension Manager');
525
		$this->content.=$this->doc->header('Extension Manager');
526
		$this->content.=$this->doc->spacer(5);
527

    
528
		// Commands given which is executed regardless of main menu setting:
529
		if ($this->CMD['showExt'])	{	// Show details for a single extension
530
			$this->showExtDetails($this->CMD['showExt']);
531
		} elseif ($this->CMD['requestInstallExtensions'])	{	// Show details for a single extension
532
				$this->requestInstallExtensions($this->CMD['requestInstallExtensions']);
533
		} elseif ($this->CMD['importExt'] || $this->CMD['uploadExt'])	{	// Imports an extension from online rep.
534
			$err = $this->importExtFromRep($this->CMD['importExt'],$this->CMD['extVersion'],$this->CMD['loc'],$this->CMD['uploadExt']);
535
			if ($err)	{
536
				$this->content.=$this->doc->section('',$GLOBALS['TBE_TEMPLATE']->rfw($err));
537
			}
538
			if(!$err && $this->CMD['importExt']) {
539
				$this->installTranslationsForExtension($this->CMD['importExt'], $this->getMirrorURL());
540
			}
541
		} elseif ($this->CMD['importExtInfo'])	{	// Gets detailed information of an extension from online rep.
542
			$this->importExtInfo($this->CMD['importExtInfo'],$this->CMD['extVersion']);
543
		} else {	// No command - we show what the menu setting tells us:
544

    
545
			$menu = $LANG->sL('LLL:EXT:lang/locallang_core.php:labels.menu').' '.
546
			t3lib_BEfunc::getFuncMenu(0,'SET[function]',$this->MOD_SETTINGS['function'],$this->MOD_MENU['function']);
547

    
548
			if (t3lib_div::inList('0,1,2',$this->MOD_SETTINGS['function']))	{
549
				$menu.='&nbsp;Group by:&nbsp;'.t3lib_BEfunc::getFuncMenu(0,'SET[listOrder]',$this->MOD_SETTINGS['listOrder'],$this->MOD_MENU['listOrder']).
550
				'&nbsp;&nbsp;Show:&nbsp;'.t3lib_BEfunc::getFuncMenu(0,'SET[display_details]',$this->MOD_SETTINGS['display_details'],$this->MOD_MENU['display_details']).'<br />';
551
			}
552
			if (t3lib_div::inList('0,1',$this->MOD_SETTINGS['function']))	{
553
				$menu.='<label for="checkDisplayShy">Display shy extensions:</label>&nbsp;&nbsp;'.t3lib_BEfunc::getFuncCheck(0,'SET[display_shy]',$this->MOD_SETTINGS['display_shy'],'','','id="checkDisplayShy"');
554
			}
555
			if (t3lib_div::inList('2',$this->MOD_SETTINGS['function']) && strlen($this->fe_user['username']))	{
556
				$menu.='<label for="checkDisplayOwn">Only my extensions:</label>&nbsp;&nbsp;'.t3lib_BEfunc::getFuncCheck(0,'SET[display_own]',$this->MOD_SETTINGS['display_own'],'','','id="checkDisplayOwn"');
557
			}
558
			if (t3lib_div::inList('0,1,2',$this->MOD_SETTINGS['function']))	{
559
				$menu.='&nbsp;&nbsp;<label for="checkDisplayObsolete">Show obsolete:</label>&nbsp;&nbsp;'.t3lib_BEfunc::getFuncCheck(0,'SET[display_obsolete]',$this->MOD_SETTINGS['display_obsolete'],'','','id="checkDisplayObsolete"');
560
			}
561

    
562
			$this->content.=$this->doc->section('','<span class="nobr">'.$menu.'</span>');
563
			$this->content.=$this->doc->spacer(10);
564

    
565
			switch((string)$this->MOD_SETTINGS['function'])	{
566
				case '0':
567
					// Lists loaded (installed) extensions
568
					$this->extensionList_loaded();
569
					break;
570
				case '1':
571
					// Lists the installed (available) extensions
572
					$this->extensionList_installed();
573
					break;
574
				case '2':
575
					// Lists the extensions available from online rep.
576
					$this->extensionList_import();
577
					break;
578
				case '3':
579
					// Shows the settings screen
580
					$this->alterSettings();
581
					break;
582
				case '4':
583
					// Allows to set the translation preferences and check the status
584
					$this->translationHandling();
585
					break;
586
				default:
587
					$this->extObjContent();
588
					break;
589
			}
590
		}
591

    
592
		// Shortcuts:
593
		if ($BE_USER->mayMakeShortcut())	{
594
			$this->content.=$this->doc->spacer(20).$this->doc->section('',$this->doc->makeShortcutIcon('CMD','function',$this->MCONF['name']));
595
		}
596
	}
597

    
598
	/**
599
	 * Print module content. Called as last thing in the global scope.
600
	 *
601
	 * @return	void
602
	 */
603
	function printContent()	{
604
		if ($this->doPrintContent) {
605
			$this->content.= $this->doc->endPage();
606
			echo $this->content;
607
		}
608
	}
609

    
610

    
611

    
612

    
613

    
614

    
615

    
616

    
617

    
618

    
619
	/*********************************
620
	*
621
	* Function Menu Applications
622
	*
623
	*********************************/
624

    
625
	/**
626
	 * Listing of loaded (installed) extensions
627
	 *
628
	 * @return	void
629
	 */
630
	function extensionList_loaded()	{
631
		global $TYPO3_LOADED_EXT;
632

    
633
		list($list,$cat) = $this->getInstalledExtensions();
634

    
635
		// Loaded extensions
636
		$content = '';
637
		$lines = array();
638

    
639
		// Available extensions
640
		if (is_array($cat[$this->MOD_SETTINGS['listOrder']]))	{
641
			$content='';
642
			$lines=array();
643
			$lines[] = $this->extensionListRowHeader(' class="bgColor5"',array('<td><img src="clear.gif" width="1" height="1" alt="" /></td>'));
644

    
645
			foreach($cat[$this->MOD_SETTINGS['listOrder']] as $catName => $extEkeys)	{
646
				natcasesort($extEkeys);
647
				reset($extEkeys);
648
				$extensions = array();
649
				while(list($extKey)=each($extEkeys))	{
650
					if (array_key_exists($extKey,$TYPO3_LOADED_EXT) && ($this->MOD_SETTINGS['display_shy'] || !$list[$extKey]['EM_CONF']['shy']) && $this->searchExtension($extKey,$list[$extKey]))	{
651
						if (in_array($extKey, $this->requiredExt))	{
652
							$loadUnloadLink = '<strong>'.$GLOBALS['TBE_TEMPLATE']->rfw('Rq').'</strong>';
653
						} else {
654
							$loadUnloadLink = '<a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[remove]=1').'">'.$this->removeButton().'</a>';
655
						}
656

    
657
						$extensions[] = $this->extensionListRow($extKey,$list[$extKey],array('<td class="bgColor">'.$loadUnloadLink.'</td>'));
658
					}
659
				}
660
				if(count($extensions)) {
661
					$lines[]='<tr><td colspan="'.(3+$this->detailCols[$this->MOD_SETTINGS['display_details']]).'"><br /></td></tr>';
662
					$lines[]='<tr><td colspan="'.(3+$this->detailCols[$this->MOD_SETTINGS['display_details']]).'"><img src="'.$GLOBALS['BACK_PATH'].'gfx/i/sysf.gif" width="18" height="16" align="top" alt="" /><strong>'.$this->listOrderTitle($this->MOD_SETTINGS['listOrder'],$catName).'</strong></td></tr>';
663
					$lines[] = implode(chr(10),$extensions);
664
				}
665
			}
666
		}
667

    
668
		$content.= t3lib_BEfunc::cshItem('_MOD_tools_em', 'loaded', $GLOBALS['BACK_PATH'],'');
669

    
670
		$content.= 'Look up: <input type="text" name="_lookUp" value="'.htmlspecialchars($this->lookUpStr).'" /><input type="submit" value="Search"/><br/><br/>';
671

    
672
		$content.= '
673

    
674
			<!-- Loaded Extensions List -->
675
			<table border="0" cellpadding="2" cellspacing="1">'.implode('',$lines).'</table>';
676

    
677
		$this->content.=$this->doc->section('Loaded Extensions',$content,0,1);
678
	}
679

    
680
	/**
681
	 * Listing of available (installed) extensions
682
	 *
683
	 * @return	void
684
	 */
685
	function extensionList_installed()	{
686
		global $TYPO3_LOADED_EXT;
687

    
688
		list($list,$cat)=$this->getInstalledExtensions();
689

    
690
		// Available extensions
691
		if (is_array($cat[$this->MOD_SETTINGS['listOrder']]))	{
692
			$content='';
693
			$lines=array();
694
			$lines[]=$this->extensionListRowHeader(' class="bgColor5"',array('<td><img src="clear.gif" width="18" height="1" alt="" /></td>'));
695

    
696
			$allKeys=array();
697
			foreach($cat[$this->MOD_SETTINGS['listOrder']] as $catName => $extEkeys)	{
698
				if(!$this->MOD_SETTINGS['display_obsolete'] && $catName=='obsolete') continue;
699

    
700
				$allKeys[]='';
701
				$allKeys[]='TYPE: '.$catName;
702

    
703
				natcasesort($extEkeys);
704
				reset($extEkeys);
705
				$extensions = array();
706
				while(list($extKey)=each($extEkeys))	{
707
					$allKeys[]=$extKey;
708
					if ((!$list[$extKey]['EM_CONF']['shy'] || $this->MOD_SETTINGS['display_shy']) &&
709
							($list[$extKey]['EM_CONF']['state']!='obsolete' || $this->MOD_SETTINGS['display_obsolete'])
710
					 && $this->searchExtension($extKey,$list[$extKey]))	{
711
						$loadUnloadLink = t3lib_extMgm::isLoaded($extKey)?
712
						'<a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[remove]=1&CMD[clrCmd]=1&SET[singleDetails]=info').'">'.$this->removeButton().'</a>':
713
						'<a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[load]=1&CMD[clrCmd]=1&SET[singleDetails]=info').'">'.$this->installButton().'</a>';
714
						if (in_array($extKey,$this->requiredExt))	{
715
							$loadUnloadLink='<strong>'.$GLOBALS['TBE_TEMPLATE']->rfw('Rq').'</strong>';
716
						}
717
						$theRowClass = t3lib_extMgm::isLoaded($extKey)? 'em-listbg1' : 'em-listbg2';
718
						$extensions[]=$this->extensionListRow($extKey,$list[$extKey],array('<td class="bgColor">'.$loadUnloadLink.'</td>'),$theRowClass);
719
					}
720
				}
721
				if(count($extensions)) {
722
					$lines[]='<tr><td colspan="'.(3+$this->detailCols[$this->MOD_SETTINGS['display_details']]).'"><br /></td></tr>';
723
					$lines[]='<tr><td colspan="'.(3+$this->detailCols[$this->MOD_SETTINGS['display_details']]).'"><img src="'.$GLOBALS['BACK_PATH'].'gfx/i/sysf.gif" width="18" height="16" align="top" alt="" /><strong>'.$this->listOrderTitle($this->MOD_SETTINGS['listOrder'],$catName).'</strong></td></tr>';
724
					$lines[] = implode(chr(10),$extensions);
725
				}
726
			}
727

    
728
			$content.='
729

    
730

    
731
<!--
732
EXTENSION KEYS:
733

    
734
'.trim(implode(chr(10),$allKeys)).'
735

    
736
-->
737

    
738
';
739

    
740
			$content.= t3lib_BEfunc::cshItem('_MOD_tools_em', 'avail', $GLOBALS['BACK_PATH'],'|<br/>');
741
			$content.= 'If you want to use an extension in TYPO3, you should simply click the "plus" button '.$this->installButton().' . <br />
742
						Installed extensions can also be removed again - just click the remove button '.$this->removeButton().' .<br /><br />';
743

    
744
			$content.= 'Look up: <input type="text" name="_lookUp" value="'.htmlspecialchars($this->lookUpStr).'" /><input type="submit" value="Search"/><br/><br/>';
745
			$content.= $this->securityHint.'<br /><br />';
746

    
747
			$content.= '<table border="0" cellpadding="2" cellspacing="1">'.implode('',$lines).'</table>';
748

    
749
			$this->content.=$this->doc->section('Available Extensions - Grouped by: '.$this->MOD_MENU['listOrder'][$this->MOD_SETTINGS['listOrder']],$content,0,1);
750
		}
751
	}
752

    
753
	/**
754
	 * Listing remote extensions from online repository
755
	 *
756
	 * @return	void
757
	 */
758
	function extensionList_import()	{
759
		global $TYPO3_LOADED_EXT;
760
		$content='';
761

    
762
			// Listing from online repository:
763
		if ($this->listRemote)	{
764
			list($inst_list,) = $this->getInstalledExtensions();
765
			$this->inst_keys = array_flip(array_keys($inst_list));
766

    
767
			$this->detailCols[1]+=6;
768

    
769
				// see if we have an extensionlist at all
770
			$this->extensionCount = $this->xmlhandler->countExtensions();
771
			if (!$this->extensionCount)	{
772
				$content .= $this->fetchMetaData('extensions');
773
			}
774

    
775
			if($this->MOD_SETTINGS['listOrder']=='author_company') {
776
				$this->listingLimit = $this->listingLimitAuthor;
777
			}
778

    
779
			$this->pointer = intval(t3lib_div::_GP('pointer'));
780
			$offset = $this->listingLimit*$this->pointer;
781

    
782
			if($this->MOD_SETTINGS['display_own'] && strlen($this->fe_user['username'])) {
783
				$this->xmlhandler->searchExtensionsXML($this->listRemote_search, $this->fe_user['username'], $this->MOD_SETTINGS['listOrder']);
784
			} else {
785
				$this->xmlhandler->searchExtensionsXML($this->listRemote_search, '', $this->MOD_SETTINGS['listOrder'], false, false, $offset, $this->listingLimit);
786
			}
787
			if (count($this->xmlhandler->extensionsXML))	{
788
				list($list,$cat) = $this->prepareImportExtList(true);
789

    
790
					// Available extensions
791
				if (is_array($cat[$this->MOD_SETTINGS['listOrder']]))	{
792
					$lines=array();
793
					$lines[]=$this->extensionListRowHeader(' class="bgColor5"',array('<td><img src="clear.gif" width="18" height="1" alt="" /></td>'),1);
794

    
795
					foreach($cat[$this->MOD_SETTINGS['listOrder']] as $catName => $extEkeys)	{
796
						if (count($extEkeys))	{
797
							$lines[]='<tr><td colspan="'.(3+$this->detailCols[$this->MOD_SETTINGS['display_details']]).'"><br /></td></tr>';
798
							$lines[]='<tr><td colspan="'.(3+$this->detailCols[$this->MOD_SETTINGS['display_details']]).'"><img src="'.$GLOBALS['BACK_PATH'].'gfx/i/sysf.gif" width="18" height="16" align="top" alt="" /><strong>'.$this->listOrderTitle($this->MOD_SETTINGS['listOrder'],$catName).'</strong></td></tr>';
799

    
800
							natcasesort($extEkeys);
801
							reset($extEkeys);
802
							while(list($extKey)=each($extEkeys))	{
803
								$version = array_keys($list[$extKey]['versions']);
804
								$version = end($version);
805
								$ext = $list[$extKey]['versions'][$version];
806
								$ext['downloadcounter_all'] = $list[$extKey]['downloadcounter'];
807
								$ext['_ICON'] = $list[$extKey]['_ICON'];
808
								$loadUnloadLink='';
809
								if ($inst_list[$extKey]['type']!='S' && (!isset($inst_list[$extKey]) || $this->versionDifference($version,$inst_list[$extKey]['EM_CONF']['version'],$this->versionDiffFactor)))	{
810
									if (isset($inst_list[$extKey]))	{
811
											// update
812
										$loc= ($inst_list[$extKey]['type']=='G'?'G':'L');
813
										$aUrl = 'index.php?CMD[importExt]='.$extKey.'&CMD[extVersion]='.$version.'&CMD[loc]='.$loc;
814
										$loadUnloadLink.= '<a href="'.htmlspecialchars($aUrl).'"><img src="'.$GLOBALS['BACK_PATH'].'gfx/import_update.gif" width="12" height="12" title="Update the extension in \''.($loc=='G'?'global':'local').'\' from online repository to server" alt="" /></a>';
815
									} else {
816
											// import
817
										$aUrl = 'index.php?CMD[importExt]='.$extKey.'&CMD[extVersion]='.$version.'&CMD[loc]=L';
818
										$loadUnloadLink.= '<a href="'.htmlspecialchars($aUrl).'"><img src="'.$GLOBALS['BACK_PATH'].'gfx/import.gif" width="12" height="12" title="Import this extension to \'local\' dir typo3conf/ext/ from online repository." alt="" /></a>';
819
									}
820
								} else {
821
									$loadUnloadLink = '&nbsp;';
822
								}
823

    
824
								if (isset($inst_list[$extKey]))	{
825
									$theRowClass = t3lib_extMgm::isLoaded($extKey) ? 'em-listbg1' : 'em-listbg2';
826
								} else {
827
									$theRowClass = 'em-listbg3';
828
								}
829

    
830
								$lines[]=$this->extensionListRow($extKey,$ext,array('<td class="bgColor">'.$loadUnloadLink.'</td>'),$theRowClass,$inst_list,1,'index.php?CMD[importExtInfo]='.rawurlencode($extKey));
831
								unset($list[$extKey]);
832
							}
833
						}
834
					}
835
					unset($list);
836

    
837
						// CSH:
838
					$content.= t3lib_BEfunc::cshItem('_MOD_tools_em', 'import_ter', $GLOBALS['BACK_PATH'],'|<br/>');
839
					$onsubmit = "window.location.href='index.php?ter_connect=1&ter_search='+escape(this.elements['_lookUp'].value);return false;";
840
					$content.= '</form><form action="index.php" method="post" onsubmit="'.htmlspecialchars($onsubmit).'">List or look up <strong'.($this->MOD_SETTINGS['display_unchecked']?' style="color:#900;">all':' style="color:#090;">reviewed').'</strong> extensions<br />
841
							<input type="text" name="_lookUp" value="'.htmlspecialchars($this->listRemote_search).'" /> <input type="submit" value="Look up" /><br /><br />';
842

    
843
 					$content .= $this->browseLinks();
844

    
845
					$content.= '
846

    
847
					<!-- TER Extensions list -->
848
					<table border="0" cellpadding="2" cellspacing="1">'.implode(chr(10),$lines).'</table>';
849
 					$content .= '<br />'.$this->browseLinks();
850
					$content.= '<br /><br />'.$this->securityHint;
851
					$content.= '<br /><br /><strong>PRIVACY NOTICE:</strong><br /> '.$this->privacyNotice;
852

    
853
					$this->content.=$this->doc->section('Extensions in TYPO3 Extension Repository (online) - Grouped by: '.$this->MOD_MENU['listOrder'][$this->MOD_SETTINGS['listOrder']],$content,0,1);
854

    
855
						// Plugins which are NOT uploaded to repository but present on this server.
856
					$content='';
857
					$lines=array();
858
					if (count($this->inst_keys))	{
859
						reset($this->inst_keys);
860
						while(list($extKey)=each($this->inst_keys))	{
861
 							$this->xmlhandler->searchExtensionsXML($extKey, '', '', true);
862
							if((strlen($this->listRemote_search) && !stristr($extKey,$this->listRemote_search)) || isset($this->xmlhandler->extensionsXML[$extKey])) continue;
863

    
864
							$loadUnloadLink = t3lib_extMgm::isLoaded($extKey)?
865
							'<a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[remove]=1&CMD[clrCmd]=1&SET[singleDetails]=info').'">'.$this->removeButton().'</a>':
866
							'<a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[load]=1&CMD[clrCmd]=1&SET[singleDetails]=info').'">'.$this->installButton().'</a>';
867
							if (in_array($extKey,$this->requiredExt))	$loadUnloadLink='<strong>'.$GLOBALS['TBE_TEMPLATE']->rfw('Rq').'</strong>';
868
							$lines[]=$this->extensionListRow($extKey,$inst_list[$extKey],array('<td class="bgColor">'.$loadUnloadLink.'</td>'),t3lib_extMgm::isLoaded($extKey)?'em-listbg1':'em-listbg2');
869
						}
870
					}
871
					if(count($lines)) {
872
						$content.= 'This is the list of extensions which are available locally, but not in the repository.<br />They might be user-defined and should be prepended user_ then.<br /><br />';
873
						$content.= '<table border="0" cellpadding="2" cellspacing="1">'.
874
							$this->extensionListRowHeader(' class="bgColor5"',array('<td><img src="clear.gif" width="18" height="1" alt="" /></td>')).
875
							implode('',$lines).'</table>';
876
						$this->content.=$this->doc->spacer(20);
877
						$this->content.=$this->doc->section('Extensions found only on this server',$content,0,1);
878
					}
879
				}
880
			} else {
881
				$content.= t3lib_BEfunc::cshItem('_MOD_tools_em', 'import_ter', $GLOBALS['BACK_PATH'],'|<br/>');
882
				$onsubmit = "window.location.href='index.php?ter_connect=1&ter_search='+escape(this.elements['_lookUp'].value);return false;";
883
				$content.= '</form><form action="index.php" method="post" onsubmit="'.htmlspecialchars($onsubmit).'">List or look up <strong'.($this->MOD_SETTINGS['display_unchecked']?' style="color:#900;">all':' style="color:#090;">reviewed').'</strong> extensions<br />
884
					<input type="text" name="_lookUp" value="'.htmlspecialchars($this->listRemote_search).'" /> <input type="submit" value="Look up" /><br /><br />';
885

    
886
				$content.= '<p><strong>No matching extensions found.</strong></p>';
887

    
888
				$content.= '<br /><br /><strong>PRIVACY NOTICE:</strong><br /> '.$this->privacyNotice;
889
				$this->content.=$this->doc->section('Extensions in TYPO3 Extension Repository (online) - Grouped by: '.$this->MOD_MENU['listOrder'][$this->MOD_SETTINGS['listOrder']],$content,0,1);
890
			}
891
		} else {
892
				// CSH
893
			$content.= t3lib_BEfunc::cshItem('_MOD_tools_em', 'import', $GLOBALS['BACK_PATH'],'|<br/>');
894

    
895
			$onsubmit = "window.location.href='index.php?ter_connect=1&ter_search='+escape(this.elements['_lookUp'].value);return false;";
896
			$content.= '</form><form action="index.php" method="post" onsubmit="'.htmlspecialchars($onsubmit).'">List or look up <strong'.($this->MOD_SETTINGS['display_unchecked']?' style="color:#900;">all':' style="color:#090;">reviewed').'</strong> extensions<br />
897
			<input type="text" name="_lookUp" value="" /> <input type="submit" value="Look up" /><br /><br />';
898

    
899
			if ($this->CMD['fetchMetaData'])	{	// fetches mirror/extension data from online rep.
900
				$content .= $this->fetchMetaData($this->CMD['fetchMetaData']);
901
			} else {
902
				$onCLick = "window.location.href='index.php?CMD[fetchMetaData]=extensions';return false;";
903
				$content.= 'Connect to the current mirror and retrieve the current list of available plugins from the TYPO3 Extension Repository.<br />
904
				<input type="submit" value="Retrieve/Update" onclick="'.htmlspecialchars($onCLick).'" />';
905
				if (is_file(PATH_site.'typo3temp/extensions.xml.gz'))	{
906
					$dateFormat = $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'];
907
					$timeFormat = $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'];
908
					$content.= ' (last update: '.date($dateFormat.' '.$timeFormat,filemtime(PATH_site.'typo3temp/extensions.xml.gz')).')';
909
				}
910
			}
911
			$content.= '<br /><br />'.$this->securityHint;
912
			$content.= '<br /><br /><strong>PRIVACY NOTICE:</strong><br />'.$this->privacyNotice;
913

    
914
			$this->content.=$this->doc->section('Extensions in TYPO3 Extension Repository',$content,0,1);
915
		}
916

    
917
			// Upload:
918
		if ($this->importAtAll())	{
919
			$content= '</form><form action="index.php" enctype="'.$GLOBALS['TYPO3_CONF_VARS']['SYS']['form_enctype'].'" method="post">
920
			Upload extension file (.t3x):<br />
921
				<input type="file" size="60" name="upload_ext_file" /><br />
922
				... to location:<br />
923
				<select name="CMD[loc]">';
924
			if ($this->importAsType('L'))	$content.='<option value="L">Local (../typo3conf/ext/)</option>';
925
			if ($this->importAsType('G'))	$content.='<option value="G">Global (typo3/ext/)</option>';
926
			if ($this->importAsType('S'))	$content.='<option value="S">System (typo3/sysext/)</option>';
927
			$content.='</select><br />
928
	<input type="checkbox" value="1" name="CMD[uploadOverwrite]" id="checkUploadOverwrite" /> <label for="checkUploadOverwrite">Overwrite any existing extension!</label><br />
929
	<input type="submit" name="CMD[uploadExt]" value="Upload extension file" /><br />
930
			';
931
		} else $content=$this->noImportMsg();
932

    
933
		$this->content.=$this->doc->spacer(20);
934
		$this->content.=$this->doc->section('Upload extension file directly (.t3x):',$content,0,1);
935
	}
936

    
937
	/**
938
	 * Generates a link to the next page of extensions
939
	 *
940
	 * @return	void
941
	 */
942
	function browseLinks()	{
943
		$content = '';
944
		if ($this->pointer)	{
945
			$content .= '<a href="'.t3lib_div::linkThisScript(array('pointer' => $this->pointer-1)).'" class="typo3-prevPage"><img'.t3lib_iconWorks::skinImg($GLOBALS['BACK_PATH'],'gfx/pilleft_n.gif','width="14" height="14"').' alt="Prev page" /> Prev page</a>';
946
		}
947
		if ($content) $content .= '&nbsp;&nbsp;&nbsp;';
948
		if (intval($this->xmlhandler->matchingCount/$this->listingLimit)>$this->pointer)	{
949
			$content .= '<a href="'.t3lib_div::linkThisScript(array('pointer' => $this->pointer+1)).'" class="typo3-nextPage"><img'.t3lib_iconWorks::skinImg($GLOBALS['BACK_PATH'],'gfx/pilright_n.gif','width="14" height="14"').' alt="Next page" /> Next page</a>';
950
		}
951
		$upper = (($this->pointer+1)*$this->listingLimit);
952
		if ($upper>$this->xmlhandler->matchingCount)	{
953
			$upper = $this->xmlhandler->matchingCount;
954
		}
955
		if ($content) $content .= '<br /><br />Showing extensions <strong>'.($this->pointer*$this->listingLimit+1).'</strong> to <strong>'.$upper.'</strong>';
956
		if ($content) $content .= '<br /><br />';
957
		return $content;
958
	}
959

    
960
	/**
961
	 * Allows changing of settings
962
	 *
963
	 * @return	void
964
	 */
965
	function alterSettings()	{
966

    
967
			// Prepare the HTML output:
968
		$content.= '
969
			'.t3lib_BEfunc::cshItem('_MOD_tools_em', 'settings', $GLOBALS['BACK_PATH'],'|<br/>').'
970
			<fieldset><legend>Security Settings</legend>
971
			<table border="0" cellpadding="2" cellspacing="2">
972
				<tr class="bgColor4">
973
					<td><label for="display_unchecked">Enable extensions without review (basic security check):</label></td>
974
					<td>'.t3lib_BEfunc::getFuncCheck(0,'SET[display_unchecked]',$this->MOD_SETTINGS['display_unchecked'],'','','id="display_unchecked"').'</td>
975
				</tr>
976
			</table>
977
			<strong>Notice:</strong> Make sure you know what consequences enabling this checkbox might have. Check the <a href="http://typo3.org/extensions/what-are-reviews/" target="_blank">information on typo3.org about security reviewing</a>!
978
			</fieldset>
979
			<br />
980
			<br />
981
			<fieldset><legend>User Settings</legend>
982
			<table border="0" cellpadding="2" cellspacing="2">
983
				<tr class="bgColor4">
984
					<td>Enter repository username:</td>
985
					<td><input type="text" name="SET[fe_u]" value="'.htmlspecialchars($this->MOD_SETTINGS['fe_u']).'" /></td>
986
				</tr>
987
				<tr class="bgColor4">
988
					<td>Enter repository password:</td>
989
					<td><input type="password" name="SET[fe_p]" value="'.htmlspecialchars($this->MOD_SETTINGS['fe_p']).'" /></td>
990
				</tr>
991
			</table>
992
			<strong>Notice:</strong> This is <em>not</em> your password to the TYPO3 backend! This user information is what is needed to log in at typo3.org with your account there!
993
			</fieldset>
994
			<br />
995
			<br />
996
			<fieldset><legend>Mirror selection</legend>
997
			<table border="0" cellpadding="2" cellspacing="2">
998
				<tr class="bgColor4">
999
					<td>Enter mirror list URL:</td>
1000
					<td><input type="text" size="50" name="SET[mirrorListURL]" value="'.htmlspecialchars($this->MOD_SETTINGS['mirrorListURL']).'" /></td>
1001
				</tr>
1002
			</table>
1003
			<br />
1004
			<p>Select a mirror from below. This list is built from the online mirror list retrieved from the URL above.<br /><br /></p>
1005
			<fieldset><legend>Mirror list</legend>';
1006
		if(!empty($this->MOD_SETTINGS['mirrorListURL'])) {
1007
			if ($this->CMD['fetchMetaData'])	{	// fetches mirror/extension data from online rep.
1008
				$content .= $this->fetchMetaData($this->CMD['fetchMetaData']);
1009
			} else {
1010
				$content.= '<a href="index.php?CMD[fetchMetaData]=mirrors">Click here to reload the list.</a>';
1011
			}
1012
		}
1013
		$content .= '<br />
1014
			<table cellspacing="4" style="text-align:left; vertical-alignment:top;">
1015
			<tr><td>Use</td><td>Name</td><td>URL</td><td>Country</td><td>Sponsored by</td></tr>
1016
		';
1017

    
1018
		if (!strlen($this->MOD_SETTINGS['extMirrors'])) $this->fetchMetaData('mirrors');
1019
		$extMirrors = unserialize($this->MOD_SETTINGS['extMirrors']);
1020
		$extMirrors[''] = array('title'=>'Random (recommended!)');
1021
		ksort($extMirrors);
1022
		if(is_array($extMirrors)) {
1023
			foreach($extMirrors as $k => $v) {
1024
				if(isset($v['sponsor'])) {
1025
					$sponsor = '<a href="'.htmlspecialchars($v['sponsor']['link']).'" target="_new"><img src="'.$v['sponsor']['logo'].'" title="'.htmlspecialchars($v['sponsor']['name']).'" alt="'.htmlspecialchars($v['sponsor']['name']).'" /></a>';
1026
				}
1027
				$selected = ($this->MOD_SETTINGS['selectedMirror']==$k) ? 'checked="checked"' : '';
1028
				$content.='<tr class="bgColor4">
1029
			<td><input type="radio" name="SET[selectedMirror]" id="selectedMirror'.$k.'" value="'.$k.'" '.$selected.'/></td><td><label for="selectedMirror'.$k.'">'.htmlspecialchars($v['title']).'</label></td><td>'.htmlspecialchars($v['host'].$v['path']).'</td><td>'.$v['country'].'</td><td>'.$sponsor.'</td></tr>';
1030
			}
1031
		}
1032
		$content.= '
1033
			</table>
1034
			</fieldset>
1035
			<br />
1036
			<table border="0" cellpadding="2" cellspacing="2">
1037
				<tr class="bgColor4">
1038
					<td>Enter repository URL:</td>
1039
					<td><input type="text" size="50" name="SET[rep_url]" value="'.htmlspecialchars($this->MOD_SETTINGS['rep_url']).'" /></td>
1040
				</tr>
1041
			</table>
1042

    
1043
			If you set a repository URL, this overrides the use of a mirror. Use this to select a specific (private) repository.<br />
1044
			</fieldset>
1045
			<br />
1046
			<input type="submit" value="Update" />
1047
		';
1048

    
1049
		$this->content.=$this->doc->section('Repository settings',$content,0,1);
1050
	}
1051

    
1052
	/**
1053
	 * Allows to set the translation preferences and check the status
1054
	 *
1055
	 * @return	void
1056
	 */
1057
	function translationHandling()	{
1058
		global $LANG, $TYPO3_LOADED_EXT;
1059
		$LANG->includeLLFile('EXT:setup/mod/locallang.xml');
1060

    
1061
		$incoming = t3lib_div::_POST('SET');
1062
		if(isset($incoming['selectedLanguages']) && is_array($incoming['selectedLanguages'])) {
1063
			t3lib_BEfunc::getModuleData($this->MOD_MENU, array('selectedLanguages' => serialize($incoming['selectedLanguages'])), $this->MCONF['name'], '', 'selectedLanguages');
1064
			$this->MOD_SETTINGS['selectedLanguages'] = serialize($incoming['selectedLanguages']);
1065
		}
1066

    
1067
		$selectedLanguages = unserialize($this->MOD_SETTINGS['selectedLanguages']);
1068
		if(count($selectedLanguages)==1 && empty($selectedLanguages[0])) $selectedLanguages = array();
1069
		$theLanguages = t3lib_div::trimExplode('|',TYPO3_languages);
1070
		foreach($theLanguages as $val)  {
1071
			if ($val!='default')    {
1072
				$localLabel = '  -  ['.htmlspecialchars($GLOBALS['LOCAL_LANG']['default']['lang_'.$val]).']';
1073
				$selected = (is_array($selectedLanguages) && in_array($val, $selectedLanguages)) ? ' selected="selected"' : '';
1074
				$opt[$GLOBALS['LOCAL_LANG']['default']['lang_'.$val].'--'.$val]='
1075
             <option value="'.$val.'"'.$selected.'>'.$LANG->getLL('lang_'.$val,1).$localLabel.'</option>';
1076
			}
1077
		}
1078
		ksort($opt);
1079

    
1080
			// Prepare the HTML output:
1081
		$content.= '
1082
			'.t3lib_BEfunc::cshItem('_MOD_tools_em', 'translation', $GLOBALS['BACK_PATH'],'|<br/>').'
1083
			<fieldset><legend>Translation Settings</legend>
1084
			<table border="0" cellpadding="2" cellspacing="2">
1085
				<tr class="bgColor4">
1086
					<td>Languages to fetch:</td>
1087
					<td>
1088
					  <select name="SET[selectedLanguages][]" multiple="multiple" size="10">
1089
					  <option></option>'.
1090
            implode('',$opt).'
1091
            </select>
1092
          </td>
1093
				</tr>
1094
			</table>
1095
			<br />
1096
			<p>For the selected languages the EM tries to download and install translation files if available, whenever an extension is installed. (This replaces the <code>csh_*</code> extensions that were used to install core translations before TYPO3 version 4!)<br />
1097
			<br />To request an update/install for already loaded extensions, see below.</p>
1098
			</fieldset>
1099
			<br />
1100
			<input type="submit" value="Save selection" />
1101
			<br />
1102
			</fieldset>';
1103

    
1104
		$this->content.=$this->doc->section('Translation settings',$content,0,1);
1105

    
1106
		if(count($selectedLanguages)>0) {
1107
			$mirrorURL = $this->getMirrorURL();
1108
			$content = '<input type="button" value="Check status against repository" onclick="document.location.href=\''.t3lib_div::linkThisScript(array('l10n'=>'check')).'\'" />&nbsp;<input type="button" value="Update from repository" onclick="document.location.href=\''.t3lib_div::linkThisScript(array('l10n'=>'update')).'\'" />';
1109

    
1110
			if(t3lib_div::_GET('l10n') == 'check') {
1111
				$loadedExtensions = array_keys($TYPO3_LOADED_EXT);
1112
				$loadedExtensions = array_diff($loadedExtensions,array('_CACHEFILE'));
1113

    
1114
					// Override content output - we now do that ourself:
1115
				echo ($this->content . $this->doc->section('Translation status',$content,0,1));
1116
				$this->doPrintContent = FALSE;
1117
				flush();
1118

    
1119
				echo '
1120
				<br />
1121
				<br />
1122
				<p id="progress-message">
1123
					Checking translation status, please wait ...
1124
				</p>
1125
				<br />
1126
				<div style="width:100%; height:20px; border: 1px solid black;">
1127
					<div id="progress-bar" style="float: left; width: 0%; height: 20px; background-color:green;">&nbsp;</div>
1128
					<div id="transparent-bar" style="float: left; width: 100%; height: 20px; background-color:'.$this->doc->bgColor2.';">&nbsp;</div>
1129
				</div>
1130
				<br />
1131
				<br /><p>This table shows the status of the loaded extension\'s translations.</p><br />
1132
				<table border="0" cellpadding="2" cellspacing="2">
1133
					<tr class="bgColor2"><td>Extension key</td>
1134
				';
1135

    
1136
				foreach($selectedLanguages as $lang) {
1137
					echo ('<td>'.$LANG->getLL('lang_'.$lang,1).'</td>');
1138
				}
1139
				echo ('</tr>');
1140

    
1141
				$counter = 1;
1142
				foreach($loadedExtensions as $extKey) {
1143

    
1144
					$percentDone = intval (($counter / count($loadedExtensions)) * 100);
1145
					echo ('
1146
					<script>
1147
						document.getElementById("progress-bar").style.width = "'.$percentDone.'%";
1148
						document.getElementById("transparent-bar").style.width = "'.(100-$percentDone).'%";
1149
						document.getElementById("progress-message").firstChild.data="Checking translation status for extension \"'.$extKey.'\" ...";
1150
					</script>
1151
					');
1152

    
1153
					flush();
1154
					$translationStatusArr = $this->terConnection->fetchTranslationStatus($extKey,$mirrorURL);
1155

    
1156
					echo ('<tr class="bgColor4"><td>'.$extKey.'</td>');
1157
					foreach($selectedLanguages as $lang) {
1158
						// remote unknown -> keine l10n
1159
						if(!isset($translationStatusArr[$lang])) {
1160
							echo ('<td title="No translation available">N/A</td>');
1161
							continue;
1162
						}
1163
							// determine local md5 from zip
1164
						if(is_file(PATH_site.'typo3temp/'.$extKey.'-l10n-'.$lang.'.zip')) {
1165
							$localmd5 = md5_file(PATH_site.'typo3temp/'.$extKey.'-l10n-'.$lang.'.zip');
1166
						} else {
1167
							echo ('<td title="Not installed / Unknown" style="background-color:#ff0">???</td>');
1168
							continue;
1169
						}
1170
							// local!=remote -> needs update
1171
						if($localmd5 != $translationStatusArr[$lang]['md5']) {
1172
							echo ('<td title="Needs update" style="background-color:#ff0">UPD</td>');
1173
							continue;
1174
						}
1175
						echo ('<td title="Is up to date" style="background-color:#69a550">OK</td>');
1176
					}
1177
					echo ('</tr>');
1178

    
1179
					$counter ++;
1180
				}
1181
				echo '</table>
1182
					<script>
1183
						document.getElementById("progress-message").firstChild.data="Check done.";
1184
					</script>
1185
				';
1186
				echo $this->doc->endPage();
1187
				return '';
1188

    
1189
			} elseif(t3lib_div::_GET('l10n') == 'update') {
1190
				$loadedExtensions = array_keys($TYPO3_LOADED_EXT);
1191
				$loadedExtensions = array_diff($loadedExtensions,array('_CACHEFILE'));
1192

    
1193
					// Override content output - we now do that ourself:
1194
				echo ($this->content . $this->doc->section('Translation status',$content,0,1));
1195
				$this->doPrintContent = FALSE;
1196
				flush();
1197

    
1198
				echo ('
1199
				<br />
1200
				<br />
1201
				<p id="progress-message">
1202
					Updating translations, please wait ...
1203
				</p>
1204
				<br />
1205
				<div style="width:100%; height:20px; border: 1px solid black;">
1206
					<div id="progress-bar" style="float: left; width: 0%; height: 20px; background-color:green;">&nbsp;</div>
1207
					<div id="transparent-bar" style="float: left; width: 100%; height: 20px; background-color:'.$this->doc->bgColor2.';">&nbsp;</div>
1208
				</div>
1209
				<br />
1210
				<br /><p>This table shows the update results of the loaded extension\'s translations.<br />
1211
				<em>If you want to force a full check/update, delete the l10n zip-files from the typo3temp folder.</em></p><br />
1212
				<table border="0" cellpadding="2" cellspacing="2">
1213
					<tr class="bgColor2"><td>Extension key</td>
1214
				');
1215

    
1216
				foreach($selectedLanguages as $lang) {
1217
					echo '<td>'.$LANG->getLL('lang_'.$lang,1).'</td>';
1218
				}
1219
				echo '</tr>';
1220

    
1221
				$counter = 1;
1222
				foreach($loadedExtensions as $extKey) {
1223
					$percentDone = intval (($counter / count($loadedExtensions)) * 100);
1224
					echo ('
1225
					<script>
1226
						document.getElementById("progress-bar").style.width = "'.$percentDone.'%";
1227
						document.getElementById("transparent-bar").style.width = "'.(100-$percentDone).'%";
1228
						document.getElementById("progress-message").firstChild.data="Updating translation for extension \"'.$extKey.'\" ...";
1229
					</script>
1230
					');
1231

    
1232
					flush();
1233
					$translationStatusArr = $this->terConnection->fetchTranslationStatus($extKey,$mirrorURL);
1234

    
1235
					echo ('<tr class="bgColor4"><td>'.$extKey.'</td>');
1236
					if(is_array($translationStatusArr)) {
1237
						foreach($selectedLanguages as $lang) {
1238
								// remote unknown -> no l10n available
1239
							if(!isset($translationStatusArr[$lang])) {
1240
								echo ('<td title="No translation available">N/A</td>');
1241
								continue;
1242
							}
1243
								// determine local md5 from zip
1244
							if(is_file(PATH_site.'typo3temp/'.$extKey.'-l10n-'.$lang.'.zip')) {
1245
								$localmd5 = md5_file(PATH_site.'typo3temp/'.$extKey.'-l10n-'.$lang.'.zip');
1246
							} else {
1247
								$localmd5 = 'zzz';
1248
							}
1249
								// local!=remote or not installed -> needs update
1250
							if($localmd5 != $translationStatusArr[$lang]['md5']) {
1251
								$ret = $this->updateTranslation($extKey, $lang, $mirrorURL);
1252
								if($ret === true) {
1253
									echo ('<td title="Has been updated" style="background-color:#69a550">UPD</td>');
1254
								} else {
1255
									echo ('<td title="'.htmlspecialchars($ret).'" style="background-color:#cb3352">ERR</td>');
1256
								}
1257
								continue;
1258
							}
1259
							echo ('<td title="Is up to date" style="background-color:#69a550">OK</td>');
1260
						}
1261
					} else {
1262
						echo ('<td colspan="'.count($selectedLanguages).'" title="Possible reasons: network problems, allow_url_fopen off, curl not enabled in Install tool.">Could not fetch translation status</td>');
1263
					}
1264
					echo ('</tr>');
1265
					$counter++;
1266
				}
1267
				echo '</table>
1268
					<script>
1269
						document.getElementById("progress-message").firstChild.data="Update done.";
1270
					</script>
1271
				';
1272
				echo $this->doc->endPage();
1273
				return '';
1274
			}
1275

    
1276
			$this->content.=$this->doc->section('Translation status',$content,0,1);
1277
		}
1278
	}
1279

    
1280
	/**
1281
	 * Install translations for all selected languages for an extension
1282
	 *
1283
	 * @param string $extKey		The extension key to install the translations for
1284
	 * @param string $lang		Language code of translation to fetch
1285
	 * @param string $mirrorURL		Mirror URL to fetch data from
1286
	 * @return mixed	true on success, error string on fauilure
1287
	 */
1288
	function updateTranslation($extKey, $lang, $mirrorURL) {
1289
		$l10n = $this->terConnection->fetchTranslation($extKey, $lang, $mirrorURL);
1290
		if(is_array($l10n)) {
1291
			$file = PATH_site.'typo3temp/'.$extKey.'-l10n-'.$lang.'.zip';
1292
			$path = 'l10n/'.$lang.'/';
1293
			if(!is_dir(PATH_typo3conf.$path)) t3lib_div::mkdir_deep(PATH_typo3conf,$path);
1294
			t3lib_div::writeFile($file, $l10n[0]);
1295
			if($this->unzip($file, PATH_typo3conf.$path)) {
1296
				return true;
1297
			} else {
1298
				return 'Unpacking the language pack failed!';
1299
			}
1300
		} else {
1301
			return $l10n;
1302
		}
1303
	}
1304

    
1305
	/**
1306
	 * Install translations for all selected languages for an extension
1307
	 *
1308
	 * @param string $extKey		The extension key to install the translations for
1309
	 * @param string $mirrorURL		Mirror URL to fetch data from
1310
	 * @return mixed	true on success, error string on fauilure
1311
	 */
1312
	function installTranslationsForExtension($extKey, $mirrorURL) {
1313
		$selectedLanguages = unserialize($this->MOD_SETTINGS['selectedLanguages']);
1314
		if(!is_array($selectedLanguages)) $selectedLanguages = array();
1315
		foreach($selectedLanguages as $lang) {
1316
			$l10n = $this->terConnection->fetchTranslation($extKey, $lang, $mirrorURL);
1317
			if(is_array($l10n)) {
1318
				$file = PATH_typo3conf.'l10n/'.$extKey.'-l10n-'.$lang.'.zip';
1319
				$path = 'l10n/'.$lang.'/'.$extKey;
1320
				t3lib_div::writeFile($file, $l10n[0]);
1321
				if(!is_dir(PATH_typo3conf.$path)) t3lib_div::mkdir_deep(PATH_typo3conf,$path);
1322
				if($this->unzip($file, PATH_typo3conf.$path)) {
1323
					return true;
1324
				} else {
1325
					return 'Unpacking the language pack failed!';
1326
				}
1327
			} else {
1328
				return $l10n;
1329
			}
1330
		}
1331
	}
1332

    
1333
	/**
1334
	 * Unzips a zip file in the given path.
1335
	 *
1336
	 * Uses unzip binary if available, otherwise a pure PHP unzip is used.
1337
	 *
1338
	 * @param string $file		Full path to zip file
1339
	 * @param string $path		Path to change to before extracting
1340
	 * @return boolean	True on success, false in failure
1341
	 */
1342
	function unzip($file, $path) {
1343
		if(strlen($GLOBALS['TYPO3_CONF_VARS']['BE']['unzip_path'])) {
1344
			chdir($path);
1345
			$cmd = $GLOBALS['TYPO3_CONF_VARS']['BE']['unzip_path'].' -o '.escapeshellarg($file);
1346
			exec($cmd, $list, $ret);
1347
			return ($ret === 0);
1348
		} else {
1349
				// we use a pure PHP unzip
1350
			$unzip = new em_unzip($file);
1351
			$ret = $unzip->extract(array('add_path'=>$path));
1352
			return (is_array($ret));
1353
		}
1354
	}
1355

    
1356

    
1357

    
1358
	/*********************************
1359
	*
1360
	* Command Applications (triggered by GET var)
1361
	*
1362
	*********************************/
1363

    
1364
	/**
1365
	 * Returns detailed info about an extension in the online repository
1366
	 *
1367
	 * @param	string		Extension repository uid + optional "private key": [uid]-[key].
1368
	 * @param	[type]		$version: ...
1369
	 * @return	void
1370
	 */
1371
	function importExtInfo($extKey, $version='')	{
1372

    
1373
			// "Go back" link
1374
		$content = '<a href="index.php" class="typo3-goBack"><img'.t3lib_iconWorks::skinImg($GLOBALS['BACK_PATH'],'gfx/goback.gif','width="14" height="14"').' alt="" /> Go back</a>';
1375
		$this->content.= $this->doc->section('',$content);
1376
		$content = '';
1377

    
1378
			// Fetch remote data:
1379
		$this->xmlhandler->searchExtensionsXML($extKey, '', '', true, true);
1380
		list($fetchData,) = $this->prepareImportExtList(true);
1381

    
1382
		$versions = array_keys($fetchData[$extKey]['versions']);
1383
		$version = ($version == '') ? end($versions) : $version;
1384

    
1385
		$opt = array();
1386
		foreach(array_keys($fetchData[$extKey]['versions']) as $ver)	{
1387
			$opt[]='<option value="'.$ver.'"'.(($version == $ver) ? ' selected="selected"' : '').'>'.$ver.'</option>';
1388
		}
1389

    
1390
			// "Select version" box:
1391
		$onClick = 'window.location.href=\'index.php?CMD[importExtInfo]='.$extKey.'&CMD[extVersion]=\'+document.pageform.extVersion.options[document.pageform.extVersion.selectedIndex].value; return false;';
1392
		$select='<select name="extVersion">'.implode('',$opt).'</select> <input type="submit" value="Load details" onclick="'.htmlspecialchars($onClick).'" /> or<br /><br />';
1393

    
1394
		if ($this->importAtAll())	{
1395
			$onClick = '
1396
					window.location.href=\'index.php?CMD[importExt]='.$extKey.'\'
1397
						+\'&CMD[extVersion]=\'+document.pageform.extVersion.options[document.pageform.extVersion.selectedIndex].value
1398
						+\'&CMD[loc]=\'+document.pageform.loc.options[document.pageform.loc.selectedIndex].value;
1399
						return false;';
1400
			$select.='
1401
				<input type="submit" value="Import/Update" onclick="'.htmlspecialchars($onClick).'"> to:
1402
				<select name="loc">'.
1403
				($this->importAsType('G',$fetchData['emconf_lockType'])?'<option value="G">Global: '.$this->typePaths['G'].$extKey.'/'.(@is_dir(PATH_site.$this->typePaths['G'].$extKey)?' (OVERWRITE)':' (empty)').'</option>':'').
1404
				($this->importAsType('L',$fetchData['emconf_lockType'])?'<option value="L">Local: '.$this->typePaths['L'].$extKey.'/'.(@is_dir(PATH_site.$this->typePaths['L'].$extKey)?' (OVERWRITE)':' (empty)').'</option>':'').
1405
				($this->importAsType('S',$fetchData['emconf_lockType'])?'<option value="S">System: '.$this->typePaths['S'].$extKey.'/'.(@is_dir(PATH_site.$this->typePaths['S'].$extKey)?' (OVERWRITE)':' (empty)').'</option>':'').
1406
				'</select>';
1407
		} else $select.= $this->noImportMsg();
1408
		$content.= $select;
1409
		$this->content.= $this->doc->section('Select command',$content,0,1);
1410

    
1411
			// Details:
1412
		$eInfo = $fetchData[$extKey]['versions'][$version];
1413
		$content='<strong>'.$fetchData[$extKey]['_ICON'].' &nbsp;'.$eInfo['EM_CONF']['title'].' ('.$extKey.', '.$version.')</strong><br /><br />';
1414
		$content.=$this->extInformationArray($extKey,$eInfo,1);
1415
		$this->content.=$this->doc->spacer(10);
1416
		$this->content.=$this->doc->section('Remote Extension Details',$content,0,1);
1417
	}
1418

    
1419
	/**
1420
	 * Fetches metadata and stores it to the corresponding place. This includes the mirror list,
1421
	 * extension XML files.
1422
	 *
1423
	 * @param	string		Type of data to fetch: (mirrors)
1424
	 * @param	boolean		If true the method doesn't produce any output
1425
	 * @return	void
1426
	 */
1427
	function fetchMetaData($metaType)	{
1428
		global $TYPO3_CONF_VARS;
1429

    
1430
		switch($metaType) {
1431
			case 'mirrors':
1432
				$mfile = t3lib_div::tempnam('mirrors');
1433
				$mirrorsFile = t3lib_div::getURL($this->MOD_SETTINGS['mirrorListURL']);
1434
				if($mirrorsFile===false) {
1435
					t3lib_div::unlink_tempfile($mfile);
1436
					$content = '<p>The mirror list was not updated, it could not be fetched from '.$this->MOD_SETTINGS['mirrorListURL'].'. Possible reasons: network problems, allow_url_fopen is off, curl is not enabled in Install tool.</p>';
1437
				} else {
1438
					t3lib_div::writeFile($mfile, $mirrorsFile);
1439
					$mirrors = implode('',gzfile($mfile));
1440
					t3lib_div::unlink_tempfile($mfile);
1441

    
1442
					$mirrors = $this->xmlhandler->parseMirrorsXML($mirrors);
1443
					if(is_array($mirrors) && count($mirrors)) {
1444
						t3lib_BEfunc::getModuleData($this->MOD_MENU, array('extMirrors' => serialize($mirrors)), $this->MCONF['name'], '', 'extMirrors');
1445
						$this->MOD_SETTINGS['extMirrors'] = serialize($mirrors);
1446
						$content = '<p>The mirror list has been updated and now contains '.count($mirrors).' entries.</p>';
1447
					}
1448
					else {
1449
						$content = '<p>'.$mirrors.'<br />The mirror list was not updated as it contained no entries.</p>';
1450
					}
1451
				}
1452
				break;
1453
			case 'extensions':
1454
				$this->fetchMetaData('mirrors'); // if we fetch the extensions anyway, we can as well keep this up-to-date
1455

    
1456
				$mirror = $this->getMirrorURL();
1457
				$extfile = $mirror.'extensions.xml.gz';
1458
				$extmd5 = t3lib_div::getURL($mirror.'extensions.md5');
1459
				if(is_file(PATH_site.'typo3temp/extensions.xml.gz')) $localmd5 = md5_file(PATH_site.'typo3temp/extensions.xml.gz');
1460

    
1461
				if($extmd5 === false) {
1462
					$content .= '<p>Error: The extension MD5 sum could not be fetched from '.$mirror.'extensions.md5. Possible reasons: network problems, allow_url_fopen is off, curl is not enabled in Install tool.</p>';
1463
				} elseif($extmd5 == $localmd5) {
1464
					$content .= '<p>The extension list has not changed remotely, it has thus not been fetched.</p>';
1465
				} else {
1466
					$extXML = t3lib_div::getURL($extfile);
1467
					if($extXML === false) {
1468
						$content .= '<p>Error: The extension list could not be fetched from '.$extfile.'. Possible reasons: network problems, allow_url_fopen is off, curl is not enabled in Install tool.</p>';
1469
					} else {
1470
						t3lib_div::writeFile(PATH_site.'typo3temp/extensions.xml.gz', $extXML);
1471
						$content .= $this->xmlhandler->parseExtensionsXML(PATH_site.'typo3temp/extensions.xml.gz');
1472
					}
1473
				}
1474
				break;
1475
		}
1476

    
1477
		return $content;
1478
	}
1479

    
1480
	/**
1481
	 * Returns the base URL for the slected or a random mirror.
1482
	 *
1483
	 * @return	string		The URL for the selected or a random mirror
1484
	 */
1485
	function getMirrorURL() {
1486
		if(strlen($this->MOD_SETTINGS['rep_url'])) return $this->MOD_SETTINGS['rep_url'];
1487

    
1488
		$mirrors = unserialize($this->MOD_SETTINGS['extMirrors']);
1489
		if(!is_array($mirrors)) {
1490
			$this->fetchMetaData('mirrors');
1491
			$mirrors = unserialize($this->MOD_SETTINGS['extMirrors']);
1492
			if(!is_array($mirrors)) return false;
1493
		}
1494
		if($this->MOD_SETTINGS['selectedMirror']=='') {
1495
			srand((float) microtime() * 10000000); // not needed after PHP 4.2.0...
1496
			$rand = array_rand($mirrors);
1497
			$url = 'http://'.$mirrors[$rand]['host'].$mirrors[$rand]['path'];
1498
		}
1499
		else {
1500
			$url = 'http://'.$mirrors[$this->MOD_SETTINGS['selectedMirror']]['host'].$mirrors[$this->MOD_SETTINGS['selectedMirror']]['path'];
1501
		}
1502

    
1503
		return $url;
1504
	}
1505

    
1506

    
1507

    
1508
	/**
1509
	 * Installs (activates) an extension
1510
	 *
1511
	 * For $mode use the three constants EM_INSTALL_VERSION_MIN, EM_INSTALL_VERSION_MAX, EM_INSTALL_VERSION_STRICT
1512
	 *
1513
	 * If an extension is loaded or imported already and the version requirement is matched, it will not be
1514
	 * fetched from the repository. This means, if you use EM_INSTALL_VERSION_MIN, you will not always get the latest
1515
	 * version of an extension!
1516
	 *
1517
	 * @param	string		$extKey	The extension key to install
1518
	 * @param	string		$version	A version number that should be installed
1519
	 * @param	int		$mode	If a version is requested, this determines if it is the min, max or strict version requested
1520
	 * @return	[type]		...
1521
	 * @todo Make the method able to handle needed interaction somehow (unmatched dependencies)
1522
	 */
1523
	function installExtension($extKey, $version=null, $mode=EM_INSTALL_VERSION_MIN) {
1524
		list($inst_list,) = $this->getInstalledExtensions();
1525

    
1526
			// check if it is already installed and loaded with sufficient version
1527
		if(isset($inst_list[$extKey])) {
1528
			$currentVersion = $inst_list[$extKey]['EM_CONF']['version'];
1529

    
1530
			if(t3lib_extMgm::isLoaded($extKey)) {
1531
				if($version===null) {
1532
					return array(true, 'Extension already installed and loaded.');
1533
				} else {
1534
					switch($mode) {
1535
						case EM_INSTALL_VERSION_STRICT:
1536
							if ($currentVersion == $version)	{
1537
								return array(true, 'Extension already installed and loaded.');
1538
							}
1539
							break;
1540
						case EM_INSTALL_VERSION_MIN:
1541
							if (version_compare($currentVersion, $version, '>='))	{
1542
								return array(true, 'Extension already installed and loaded.');
1543
							}
1544
							break;
1545
						case EM_INSTALL_VERSION_MAX:
1546
							if (version_compare($currentVersion, $version, '<='))	{
1547
								return array(true, 'Extension already installed and loaded.');
1548
							}
1549
							break;
1550
					}
1551
				}
1552
			} else {
1553
				if (!t3lib_extMgm::isLocalconfWritable())	{
1554
					return array(false, 'localconf.php is not writable!');
1555
				}
1556
				$newExtList = -1;
1557
				switch($mode) {
1558
					case EM_INSTALL_VERSION_STRICT:
1559
						if ($currentVersion == $version)	{
1560
							$newExtList = $this->addExtToList($extKey, $inst_list);
1561
						}
1562
						break;
1563
					case EM_INSTALL_VERSION_MIN:
1564
						if (version_compare($currentVersion, $version, '>='))	{
1565
							$newExtList = $this->addExtToList($extKey, $inst_list);
1566
						}
1567
						break;
1568
					case EM_INSTALL_VERSION_MAX:
1569
						if (version_compare($currentVersion, $version, '<='))	{
1570
							$newExtList = $this->addExtToList($extKey, $inst_list);
1571
						}
1572
						break;
1573
				}
1574
				if ($newExtList!=-1)	{
1575
					$this->writeNewExtensionList($newExtList);
1576
					$this->refreshGlobalExtList();
1577
					$this->forceDBupdates($extKey, $inst_list[$extKey]);
1578
					return array(true, 'Extension was already installed, it has been loaded.');
1579
				}
1580
			}
1581
		}
1582

    
1583
			// at this point we know we need to import (a matching version of) the extension from TER2
1584

    
1585
			// see if we have an extensionlist at all
1586
		if (!$this->xmlhandler->countExtensions())	{
1587
			$this->fetchMetaData('extensions');
1588
		}
1589
		$this->xmlhandler->searchExtensionsXML($extKey, '', '', true);
1590

    
1591
			// check if extension can be fetched
1592
		if(isset($this->xmlhandler->extensionsXML[$extKey])) {
1593
			$versions = array_keys($this->xmlhandler->extensionsXML[$extKey]['versions']);
1594
			$latestVersion = end($versions);
1595
			switch($mode) {
1596
				case EM_INSTALL_VERSION_STRICT:
1597
					if(!isset($this->xmlhandler->extensionsXML[$extKey]['versions'][$version])) {
1598
						return array(false, 'Extension not available in matching version');
1599
					}
1600
					break;
1601
				case EM_INSTALL_VERSION_MIN:
1602
					if (version_compare($latestVersion, $version, '>='))	{
1603
						$version = $latestVersion;
1604
					} else {
1605
						return array(false, 'Extension not available in matching version');
1606
					}
1607
					break;
1608
				case EM_INSTALL_VERSION_MAX:
1609
					while (($v = array_pop($versions)) && version_compare($v, $version, '>='))	{
1610
						// Loop until a version is found
1611
					}
1612

    
1613
					if ($v !== null && version_compare($v, $version, '<='))	{
1614
						$version = $v;
1615
					} else {
1616
						return array(false, 'Extension not available in matching version');
1617
					}
1618
					break;
1619
			}
1620
			$this->importExtFromRep($extKey, $version, 'L');
1621
			$newExtList = $this->addExtToList($extKey, $inst_list);
1622
			if ($newExtList!=-1)	{
1623
				$this->writeNewExtensionList($newExtList);
1624
				$this->refreshGlobalExtList();
1625
				$this->forceDBupdates($extKey, $inst_list[$extKey]);
1626
				$this->installTranslationsForExtension($extKey, $this->getMirrorURL());
1627
				return array(true, 'Extension has been imported from repository and loaded.');
1628
			} else {
1629
				return array(false, 'Extension is in repository, but could not be loaded.');
1630
			}
1631
		} else {
1632
			return array(false, 'Extension not available in repository');
1633
		}
1634
	}
1635

    
1636
	function refreshGlobalExtList() {
1637
		global $TYPO3_LOADED_EXT;
1638

    
1639
		$TYPO3_LOADED_EXT = t3lib_extMgm::typo3_loadExtensions();
1640
		if ($TYPO3_LOADED_EXT['_CACHEFILE'])    {
1641
			require(PATH_typo3conf.$TYPO3_LOADED_EXT['_CACHEFILE'].'_ext_localconf.php');
1642
		}
1643
		return;
1644

    
1645
		$GLOBALS['TYPO3_LOADED_EXT'] = t3lib_extMgm::typo3_loadExtensions();
1646
		if ($TYPO3_LOADED_EXT['_CACHEFILE'])    {
1647
			require(PATH_typo3conf.$TYPO3_LOADED_EXT['_CACHEFILE'].'_ext_localconf.php');
1648
		} else {
1649
			$temp_TYPO3_LOADED_EXT = $TYPO3_LOADED_EXT;
1650
			reset($temp_TYPO3_LOADED_EXT);
1651
			while(list($_EXTKEY,$temp_lEDat)=each($temp_TYPO3_LOADED_EXT))  {
1652
				if (is_array($temp_lEDat) && $temp_lEDat['ext_localconf.php'])  {
1653
					$_EXTCONF = $TYPO3_CONF_VARS['EXT']['extConf'][$_EXTKEY];
1654
					require($temp_lEDat['ext_localconf.php']);
1655
				}
1656
			}
1657
		}
1658
	}
1659

    
1660

    
1661
	/**
1662
	 * Imports an extensions from the online repository
1663
	 * NOTICE: in version 4.0 this changed from "importExtFromRep_old($extRepUid,$loc,$uploadFlag=0,$directInput='',$recentTranslations=0,$incManual=0,$dontDelete=0)"
1664
	 *
1665
	 * @param	string		Extension key
1666
	 * @param	string		Version
1667
	 * @param	string		Install scope: "L" or "G" or "S"
1668
	 * @param	boolean		If true, extension is uploaded as file
1669
	 * @param	boolean		If true, extension directory+files will not be deleted before writing the new ones. That way custom files stored in the extension folder will be kept.
1670
	 * @param	array		Direct input array (like from kickstarter)
1671
	 * @return	string		Return false on success, returns error message if error.
1672
	 */
1673
	function importExtFromRep($extKey,$version,$loc,$uploadFlag=0,$dontDelete=0,$directInput='')	{
1674

    
1675
		$uploadSucceed = false;
1676
		$uploadedTempFile = '';
1677
		if (is_array($directInput))	{
1678
			$fetchData = array($directInput,'');
1679
			$loc = ($loc==='G'||$loc==='S') ? $loc : 'L';
1680
		} elseif ($uploadFlag)	{
1681
			if (($uploadedTempFile = $this->CMD['alreadyUploaded']) || $_FILES['upload_ext_file']['tmp_name'])	{
1682

    
1683
					// Read uploaded file:
1684
				if (!$uploadedTempFile)	{
1685
					if (!is_uploaded_file($_FILES['upload_ext_file']['tmp_name'])) {
1686
 						t3lib_div::sysLog('Possible file upload attack: '.$_FILES['upload_ext_file']['tmp_name'], 'Extension Manager', 3);
1687

    
1688
						return 'File was not uploaded?!?';
1689
					}
1690

    
1691
					$uploadedTempFile = t3lib_div::upload_to_tempfile($_FILES['upload_ext_file']['tmp_name']);
1692
				}
1693
				$fileContent = t3lib_div::getUrl($uploadedTempFile);
1694

    
1695
				if (!$fileContent)	return 'File is empty!';
1696

    
1697
					// Decode file data:
1698
				$fetchData = $this->terConnection->decodeExchangeData($fileContent);
1699

    
1700
				if (is_array($fetchData))	{
1701
					$extKey = $fetchData[0]['extKey'];
1702
					if ($extKey)	{
1703
						if (!$this->CMD['uploadOverwrite'])	{
1704
							$loc = ($loc==='G'||$loc==='S') ? $loc : 'L';
1705
							$comingExtPath = PATH_site.$this->typePaths[$loc].$extKey.'/';
1706
							if (@is_dir($comingExtPath))	{
1707
								return 'Extension was already present in "'.$comingExtPath.'" - and the overwrite flag was not set! So nothing done...';
1708
							}	// ... else go on, install...
1709
						}	// ... else go on, install...
1710
					} else return 'No extension key in file. Strange...';
1711
				} else return 'Wrong file format. No data recognized, '.$fetchData;
1712
			} else return 'No file uploaded! Probably the file was too large for PHPs internal limit for uploadable files.';
1713
		} else {
1714
			$this->xmlhandler->searchExtensionsXML($extKey, '', '', true);
1715

    
1716
				// Fetch extension from TER:
1717
			if(!strlen($version)) {
1718
				$versions = array_keys($this->xmlhandler->extensionsXML[$extKey]['versions']);
1719
				$version = end($versions);
1720
			}
1721
			$fetchData = $this->terConnection->fetchExtension($extKey, $version, $this->xmlhandler->extensionsXML[$extKey]['versions'][$version]['t3xfilemd5'], $this->getMirrorURL());
1722
		}
1723

    
1724
		// At this point the extension data should be present; so we want to write it to disc:
1725
		if ($this->importAsType($loc))	{
1726
			if (is_array($fetchData))	{	// There was some data successfully transferred
1727
				if ($fetchData[0]['extKey'] && is_array($fetchData[0]['FILES']))	{
1728
					$extKey = $fetchData[0]['extKey'];
1729
					if(!isset($fetchData[0]['EM_CONF']['constraints'])) $fetchData[0]['EM_CONF']['constraints'] = $this->xmlhandler->extensionsXML[$extKey]['versions'][$version]['dependencies'];
1730
					$EM_CONF = $this->fixEMCONF($fetchData[0]['EM_CONF']);
1731
					if (!$EM_CONF['lockType'] || !strcmp($EM_CONF['lockType'],$loc))	{
1732
							// check dependencies, act accordingly if ext is loaded
1733
						list($instExtInfo,)=$this->getInstalledExtensions();
1734
						$depStatus = $this->checkDependencies($extKey, $EM_CONF, $instExtInfo);
1735
						if(t3lib_extMgm::isLoaded($extKey) && !$depStatus['returnCode']) {
1736
							$this->content .= $depStatus['html'];
1737
							if ($uploadedTempFile)	{
1738
								$this->content .= '<input type="hidden" name="CMD[alreadyUploaded]" value="'.$uploadedTempFile.'" />';
1739
							}
1740
						} else {
1741
							$res = $this->clearAndMakeExtensionDir($fetchData[0],$loc,$dontDelete);
1742
							if (is_array($res))	{
1743
								$extDirPath = trim($res[0]);
1744
								if ($extDirPath && @is_dir($extDirPath) && substr($extDirPath,-1)=='/')	{
1745

    
1746
									$emConfFile = $this->construct_ext_emconf_file($extKey,$EM_CONF);
1747
									$dirs = $this->extractDirsFromFileList(array_keys($fetchData[0]['FILES']));
1748

    
1749
									$res = $this->createDirsInPath($dirs,$extDirPath);
1750
									if (!$res)	{
1751
										$writeFiles = $fetchData[0]['FILES'];
1752
										$writeFiles['ext_emconf.php']['content'] = $emConfFile;
1753
										$writeFiles['ext_emconf.php']['content_md5'] = md5($emConfFile);
1754

    
1755
											// Write files:
1756
										foreach($writeFiles as $theFile => $fileData)	{
1757
											t3lib_div::writeFile($extDirPath.$theFile,$fileData['content']);
1758
											if (!@is_file($extDirPath.$theFile))	{
1759
												$content.='Error: File "'.$extDirPath.$theFile.'" could not be created!!!<br />';
1760
											} elseif (md5(t3lib_div::getUrl($extDirPath.$theFile)) != $fileData['content_md5']) {
1761
												$content.='Error: File "'.$extDirPath.$theFile.'" MD5 was different from the original files MD5 - so the file is corrupted!<br />';
1762
											}
1763
										}
1764

    
1765
											// No content, no errors. Create success output here:
1766
										if (!$content)	{
1767
											$content='SUCCESS: '.$extDirPath.'<br />';
1768

    
1769
											$uploadSucceed = true;
1770

    
1771
												// Fix TYPO3_MOD_PATH for backend modules in extension:
1772
											$modules = t3lib_div::trimExplode(',',$EM_CONF['module'],1);
1773
											if (count($modules))	{
1774
												foreach($modules as $mD)	{
1775
													$confFileName = $extDirPath.$mD.'/conf.php';
1776
													if (@is_file($confFileName))	{
1777
														$content.= $this->writeTYPO3_MOD_PATH($confFileName,$loc,$extKey.'/'.$mD.'/').'<br />';
1778
													} else $content.='Error: Couldn\'t find "'.$confFileName.'"<br />';
1779
												}
1780
											}
1781
												// NOTICE: I used two hours trying to find out why a script, ext_emconf.php, written twice and in between included by PHP did not update correct the second time. Probably something with PHP-A cache and mtime-stamps.
1782
												// But this order of the code works.... (using the empty Array with type, EMCONF and files hereunder).
1783

    
1784
												// Writing to ext_emconf.php:
1785
											$sEMD5A = $this->serverExtensionMD5Array($extKey,array('type' => $loc, 'EM_CONF' => array(), 'files' => array()));
1786
											$EM_CONF['_md5_values_when_last_written'] = serialize($sEMD5A);
1787
											$emConfFile = $this->construct_ext_emconf_file($extKey,$EM_CONF);
1788
											t3lib_div::writeFile($extDirPath.'ext_emconf.php',$emConfFile);
1789

    
1790
											$content.='ext_emconf.php: '.$extDirPath.'ext_emconf.php<br />';
1791
											$content.='Type: '.$loc.'<br />';
1792

    
1793
												// Remove cache files:
1794
											if (t3lib_extMgm::isLoaded($extKey))	{
1795
												if ($this->removeCacheFiles())	{
1796
													$content.='Cache-files are removed and will be re-written upon next hit<br />';
1797
												}
1798

    
1799
												list($new_list)=$this->getInstalledExtensions();
1800
												$content.=$this->updatesForm($extKey,$new_list[$extKey],1,'index.php?CMD[showExt]='.$extKey.'&SET[singleDetails]=info');
1801
											}
1802

    
1803
												// Install / Uninstall:
1804
											if(!$this->CMD['standAlone']) {
1805
												$content = '<a href="index.php" class="typo3-goBack"><img'.t3lib_iconWorks::skinImg($GLOBALS['BACK_PATH'],'gfx/goback.gif','width="14" height="14"').' alt="" /> Go back</a><br />'.$content;
1806
												$content.='<h3>Install / Uninstall Extension:</h3>';
1807
												$content.= $new_list[$extKey] ?
1808
													'<a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[remove]=1&CMD[clrCmd]=1&SET[singleDetails]=info').'">'.$this->removeButton().' Uninstall extension</a>' :
1809
													'<a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[load]=1&CMD[clrCmd]=1&SET[singleDetails]=info').'">'.$this->installButton().' Install extension</a>';
1810
											} else {
1811
												$content = 'Extension has been imported.<br /><br /><a href="javascript:opener.top.content.document.forms[0].submit();window.close();">Close window and recheck dependencies</a>';
1812
											}
1813

    
1814
										}
1815
									} else $content = $res;
1816
								} else $content = 'Error: The extension path "'.$extDirPath.'" was different than expected...';
1817
							} else $content = $res;
1818
						}
1819
					} else $content = 'Error: The extension can only be installed in the path '.$this->typePaths[$EM_CONF['lockType']].' (lockType='.$EM_CONF['lockType'].')';
1820
				} else $content = 'Error: No extension key!!! Why? - nobody knows... (Or no files in the file-array...)';
1821
			}  else $content = 'Error: The datatransfer did not succeed. '.$fetchData;
1822
		}  else $content = 'Error: Installation is not allowed in this path ('.$this->typePaths[$loc].')';
1823

    
1824
		$this->content.=$this->doc->section('Extension import results',$content,0,1);
1825

    
1826
		if ($uploadSucceed && $uploadedTempFile)	{
1827
			t3lib_div::unlink_tempfile($uploadedTempFile);
1828
		}
1829

    
1830
		return false;
1831
	}
1832

    
1833
	/**
1834
	 * Display extensions details.
1835
	 *
1836
	 * @param	string		Extension key
1837
	 * @return	void		Writes content to $this->content
1838
	 */
1839
	function showExtDetails($extKey)	{
1840
		global $TYPO3_LOADED_EXT;
1841

    
1842
		list($list,)=$this->getInstalledExtensions();
1843
		$absPath = $this->getExtPath($extKey,$list[$extKey]['type']);
1844

    
1845
		// Check updateModule:
1846
		if (@is_file($absPath.'class.ext_update.php'))	{
1847
			require_once($absPath.'class.ext_update.php');
1848
			$updateObj = new ext_update;
1849
			if (!$updateObj->access())	{
1850
				unset($this->MOD_MENU['singleDetails']['updateModule']);
1851
			}
1852
		} else {
1853
			unset($this->MOD_MENU['singleDetails']['updateModule']);
1854
		}
1855

    
1856
		if($this->CMD['doDelete']) {
1857
			$this->MOD_MENU['singleDetails'] = array();
1858
		}
1859

    
1860
			// Function menu here:
1861
		if(!$this->CMD['standAlone'] && !t3lib_div::_GP('standAlone')) {
1862
			$content = '
1863
				<table border="0" cellpadding="0" cellspacing="0" width="100%">
1864
					<tr>
1865
						<td nowrap="nowrap">Extension:&nbsp;<strong>'.$this->extensionTitleIconHeader($extKey,$list[$extKey]).'</strong> ('.$extKey.')</td>
1866
						<td align="right" nowrap="nowrap">'.
1867
			t3lib_BEfunc::getFuncMenu(0,'SET[singleDetails]',$this->MOD_SETTINGS['singleDetails'],$this->MOD_MENU['singleDetails'],'','&CMD[showExt]='.$extKey).' &nbsp; &nbsp; '.
1868
			'<a href="index.php" class="typo3-goBack"><img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/goback.gif','width="14" height="14"').' class="absmiddle" alt="" /> Go back</a></td>
1869
					</tr>
1870
				</table>';
1871
			$this->content.=$this->doc->section('',$content);
1872
		}
1873

    
1874
			// Show extension details:
1875
		if ($list[$extKey])	{
1876

    
1877
				// Checking if a command for install/uninstall is executed:
1878
			if (($this->CMD['remove'] || $this->CMD['load']) && !in_array($extKey,$this->requiredExt))	{
1879

    
1880
					// Install / Uninstall extension here:
1881
				if (t3lib_extMgm::isLocalconfWritable())	{
1882
						// Check dependencies:
1883
					$depStatus = $this->checkDependencies($extKey, $list[$extKey]['EM_CONF'], $list);
1884
					if(!$this->CMD['remove'] && !$depStatus['returnCode']) {
1885
						$this->content .= $depStatus['html'];
1886
						$newExtList = -1;
1887
					} elseif ($this->CMD['remove'])	{
1888
						$newExtList = $this->removeExtFromList($extKey,$list);
1889
					} else {
1890
						$newExtList = $this->addExtToList($extKey,$list);
1891
					}
1892

    
1893
					// Success-installation:
1894
					if ($newExtList!=-1)	{
1895
						$updates = '';
1896
						if ($this->CMD['load'])	{
1897
							if($_SERVER['REQUEST_METHOD'] == 'POST') {
1898
								$script = t3lib_div::linkThisScript(array('CMD[showExt]' => $extKey, 'CMD[load]' => 1, 'CMD[clrCmd]' => $this->CMD['clrCmd'], 'SET[singleDetails]' => 'info'));
1899
							} else {
1900
								$script = '';
1901
							}
1902
							$updates = $this->updatesForm($extKey,$list[$extKey],1,$script,'<input type="hidden" name="_do_install" value="1" /><input type="hidden" name="_clrCmd" value="'.$this->CMD['clrCmd'].'" />');
1903
							if ($updates)	{
1904
								$updates = 'Before the extension can be installed the database needs to be updated with new tables or fields. Please select which operations to perform:'.$updates;
1905
								if($this->CMD['standAlone']) $updates .= '<input type="hidden" name="standAlone" value="1" />';
1906
								$depsolver = t3lib_div::_POST('depsolver');
1907
								if(is_array($depsolver['ignore'])) {
1908
									foreach($depsolver['ignore'] as $depK => $depV)	{
1909
										$updates .= '<input type="hidden" name="depsolver[ignore]['.$depK.']" value="1" />';
1910
									}
1911
								}
1912

    
1913
								$this->content.=$this->doc->section('Installing '.$this->extensionTitleIconHeader($extKey,$list[$extKey]).strtoupper(': Database needs to be updated'),$updates,1,1,1,1);
1914
							}
1915
						} elseif ($this->CMD['remove']) {
1916
							$updates.= $this->checkClearCache($list[$extKey]);
1917
							if ($updates)	{
1918
								$updates = '
1919
								</form><form action="'.t3lib_div::linkThisScript().'" method="post">'.$updates.'
1920
								<br /><input type="submit" name="write" value="Remove extension" />
1921
								<input type="hidden" name="_do_install" value="1" />
1922
								<input type="hidden" name="_clrCmd" value="'.$this->CMD['clrCmd'].'" />
1923
								<input type="hidden" name="standAlone" value="'.$this->CMD['standAlone'].'" />
1924
								';
1925
								$this->content.=$this->doc->section('Removing '.$this->extensionTitleIconHeader($extKey,$list[$extKey]).strtoupper(': Database needs to be updated'),$updates,1,1,1,1);
1926
							}
1927
						}
1928
						if (!$updates || t3lib_div::_GP('_do_install')) {
1929
							$this->writeNewExtensionList($newExtList);
1930
							$GLOBALS['BE_USER']->writelog(5,1,0,0,'Extension list has been changed, extension %s has been %s',array($extKey,($this->CMD['load']?'installed':'removed')));
1931
							if ($this->CMD['clrCmd'] || t3lib_div::_GP('_clrCmd'))	{
1932
								$vA = array('CMD'=>'');
1933
							} else {
1934
								$vA = array('CMD'=>Array('showExt'=>$extKey));
1935
							}
1936
							if($this->CMD['standAlone'] || t3lib_div::_GP('standAlone')) {
1937
								$this->content .= 'Extension has been '.($this->CMD['load'] ? 'installed' : 'removed').'.<br /><br /><a href="javascript:opener.top.content.document.forms[0].submit();window.close();">Close window and recheck dependencies</a>';
1938
							} else {
1939
								header('Location: '.t3lib_div::linkThisScript($vA));
1940
							}
1941
						}
1942
					}
1943
				} else {
1944
					$this->content.=$this->doc->section('Installing '.$this->extensionTitleIconHeader($extKey,$list[$extKey]).strtoupper(': Write access error'),'typo3conf/localconf.php seems not to be writable, so the extension cannot be installed automatically!',1,1,2,1);
1945
				}
1946

    
1947
			} elseif ($this->CMD['downloadFile'] && !in_array($extKey,$this->requiredExt))	{
1948

    
1949
				// Link for downloading extension has been clicked - deliver content stream:
1950
				$dlFile = $this->CMD['downloadFile'];
1951
				if (t3lib_div::isFirstPartOfStr($dlFile,PATH_site) && t3lib_div::isFirstPartOfStr($dlFile,$absPath) && @is_file($dlFile))	{
1952
					$mimeType = 'application/octet-stream';
1953
					Header('Content-Type: '.$mimeType);
1954
					Header('Content-Disposition: attachment; filename='.basename($dlFile));
1955
					echo t3lib_div::getUrl($dlFile);
1956
					exit;
1957
				} else die('Error while trying to download extension file...');
1958

    
1959
			} elseif ($this->CMD['editFile'] && !in_array($extKey,$this->requiredExt))	{
1960

    
1961
				// Editing extension file:
1962
				$editFile = $this->CMD['editFile'];
1963
				if (t3lib_div::isFirstPartOfStr($editFile,PATH_site) && t3lib_div::isFirstPartOfStr($editFile,$absPath))	{	// Paranoia...
1964

    
1965
					$fI = t3lib_div::split_fileref($editFile);
1966
					if (@is_file($editFile) && t3lib_div::inList($this->editTextExtensions,($fI['fileext']?$fI['fileext']:$fI['filebody'])))	{
1967
						if (filesize($editFile)<($this->kbMax*1024))	{
1968
							$outCode = '';
1969
							$info = '';
1970
							$submittedContent = t3lib_div::_POST('edit');
1971
							$saveFlag = 0;
1972

    
1973
							if(isset($submittedContent['file']) && !$GLOBALS['TYPO3_CONF_VARS']['EXT']['noEdit'])	{		// Check referer here?
1974
								$oldFileContent = t3lib_div::getUrl($editFile);
1975
								if($oldFileContent != $submittedContent['file']) {
1976
									$oldMD5 = md5(str_replace(chr(13),'',$oldFileContent));
1977
									$info.= 'MD5: <b>'.$oldMD5.'</b> (Previous File)<br />';
1978
									t3lib_div::writeFile($editFile,$submittedContent['file']);
1979
									$saveFlag = 1;
1980
								} else {
1981
									$info .= 'No changes to the file detected!<br />';
1982
								}
1983
							}
1984

    
1985
							$fileContent = t3lib_div::getUrl($editFile);
1986

    
1987
							$outCode.= 'File: <b>'.substr($editFile,strlen($absPath)).'</b> ('.t3lib_div::formatSize(filesize($editFile)).')<br />';
1988
							$fileMD5 = md5(str_replace(chr(13),'',$fileContent));
1989
							$info.= 'MD5: <b>'.$fileMD5.'</b> (Current File)<br />';
1990
							if($saveFlag)	{
1991
								$saveMD5 = md5(str_replace(chr(13),'',$submittedContent['file']));
1992
								$info.= 'MD5: <b>'.$saveMD5.'</b> (Submitted)<br />';
1993
								if($fileMD5!=$saveMD5) $info .= $GLOBALS['TBE_TEMPLATE']->rfw('<br /><strong>Saving failed, the content was not correctly written to disk. Changes have been lost!</strong>').'<br />';
1994
								else $info.= $GLOBALS['TBE_TEMPLATE']->rfw('<br /><strong>File saved.</strong>').'<br />';
1995
							}
1996

    
1997
							$outCode.= '<textarea name="edit[file]" rows="35" wrap="off"'.$this->doc->formWidthText(48,'width:98%;height:70%','off').' class="fixed-font enable-tab">'.t3lib_div::formatForTextarea($fileContent).'</textarea>';
1998
							$outCode.= '<input type="hidden" name="edit[filename]" value="'.$editFile.'" />';
1999
							$outCode.= '<input type="hidden" name="CMD[editFile]" value="'.htmlspecialchars($editFile).'" />';
2000
							$outCode.= '<input type="hidden" name="CMD[showExt]" value="'.$extKey.'" />';
2001
							$outCode.= $info;
2002

    
2003
							if (!$GLOBALS['TYPO3_CONF_VARS']['EXT']['noEdit'])	{
2004
								$outCode.='<br /><input type="submit" name="save_file" value="Save file" />';
2005
							} else $outCode.=$GLOBALS['TBE_TEMPLATE']->rfw('<br />[SAVING IS DISABLED - can be enabled by the $TYPO3_CONF_VARS[\'EXT\'][\'noEdit\']-flag] ');
2006

    
2007
							$onClick = 'window.location.href=\'index.php?CMD[showExt]='.$extKey.'\';return false;';
2008
							$outCode.='<input type="submit" name="cancel" value="Cancel" onclick="'.htmlspecialchars($onClick).'" />';
2009

    
2010
							$theOutput.=$this->doc->spacer(15);
2011
							$theOutput.=$this->doc->section('Edit file:','',0,1);
2012
							$theOutput.=$this->doc->sectionEnd().$outCode;
2013
							$this->content.=$theOutput;
2014
						} else {
2015
							$theOutput.=$this->doc->spacer(15);
2016
							$theOutput.=$this->doc->section('Filesize exceeded '.$this->kbMax.' Kbytes','Files larger than '.$this->kbMax.' KBytes are not allowed to be edited.');
2017
						}
2018
					}
2019
				} else die('Fatal Edit error: File "'.$editFile.'" was not inside the correct path of the TYPO3 Extension!');
2020
			} else {
2021

    
2022
				// MAIN:
2023
				switch((string)$this->MOD_SETTINGS['singleDetails'])	{
2024
					case 'info':
2025
						// Loaded / Not loaded:
2026
						if (!in_array($extKey,$this->requiredExt))	{
2027
							if ($TYPO3_LOADED_EXT[$extKey])	{
2028
								$content = '<strong>The extension is installed (loaded and running)!</strong><br />'.
2029
								'<a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[remove]=1').'">Click here to remove the extension: '.$this->removeButton().'</a>';
2030
							} else {
2031
								$content = 'The extension is <strong>not</strong> installed yet.<br />'.
2032
								'<a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[load]=1').'">Click here to install the extension: '.$this->installButton().'</a>';
2033
							}
2034
						} else {
2035
							$content = 'This extension is entered in the TYPO3_CONF_VARS[SYS][requiredExt] list and is therefore always loaded.';
2036
						}
2037
						$this->content.=$this->doc->spacer(10);
2038
						$this->content.=$this->doc->section('Active status:',$content,0,1);
2039

    
2040
						if (t3lib_extMgm::isLoaded($extKey))	{
2041
							$updates=$this->updatesForm($extKey,$list[$extKey]);
2042
							if ($updates)	{
2043
								$this->content.=$this->doc->spacer(10);
2044
								$this->content.=$this->doc->section('Update needed:',$updates.'<br /><br />Notice: "Static data" may not <em>need</em> to be updated. You will only have to import static data each time you upgrade the extension.',0,1);
2045
							}
2046
						}
2047

    
2048
						// Config:
2049
						if (@is_file($absPath.'ext_conf_template.txt'))	{
2050
							$this->content.=$this->doc->spacer(10);
2051
							$this->content.=$this->doc->section('Configuration:','(<em>Notice: You may need to clear the cache after configuration of the extension. This is required if the extension adds TypoScript depending on these settings.</em>)<br /><br />',0,1);
2052
							$this->tsStyleConfigForm($extKey,$list[$extKey]);
2053
						}
2054

    
2055
						// Show details:
2056
						$content = t3lib_BEfunc::cshItem('_MOD_tools_em', 'info', $GLOBALS['BACK_PATH'],'|<br/>');
2057
						$content.= $this->extInformationArray($extKey,$list[$extKey]);
2058

    
2059
						$this->content.=$this->doc->spacer(10);
2060
						$this->content.=$this->doc->section('Details:',$content,0,1);
2061
						break;
2062
					case 'upload':
2063
						$em = t3lib_div::_POST('em');
2064
						if($em['action'] == 'doUpload') {
2065
							$em['extKey'] = $extKey;
2066
							$em['extInfo'] = $list[$extKey];
2067
							$content = $this->uploadExtensionToTER($em);
2068
							$content .= $this->doc->spacer(10);
2069
								// Must reload this, because EM_CONF information has been updated!
2070
							list($list,)=$this->getInstalledExtensions();
2071
						} else {
2072
								// CSH:
2073
							$content = t3lib_BEfunc::cshItem('_MOD_tools_em', 'upload', $GLOBALS['BACK_PATH'],'|<br/>');
2074

    
2075
								// Upload:
2076
							if (substr($extKey,0,5)!='user_')	{
2077
								$content.= $this->getRepositoryUploadForm($extKey,$list[$extKey]);
2078
								$eC=0;
2079
							} else {
2080
								$content.='The extensions has an extension key prefixed "user_" which indicates that it is a user-defined extension with no official unique identification. Therefore it cannot be uploaded.';
2081
								$eC=2;
2082
							}
2083
							if (!$this->fe_user['username'])	{
2084
								$content.= '<br /><br /><img src="'.$GLOBALS['BACK_PATH'].'gfx/icon_note.gif" width="18" height="16" align="top" alt="" />You have not configured a default username/password yet. <a href="index.php?SET[function]=3">Go to "Settings"</a> if you want to do that.<br />';
2085
							}
2086
						}
2087
						$this->content.=$this->doc->section('Upload extension to repository',$content,0,1,$eC);
2088
						break;
2089
					case 'backup':
2090
						if($this->CMD['doDelete']) {
2091
							$content = $this->extDelete($extKey,$list[$extKey]);
2092
							$this->content.=$this->doc->section('Delete',$content,0,1);
2093
						} else {
2094
							$content = t3lib_BEfunc::cshItem('_MOD_tools_em', 'backup_delete', $GLOBALS['BACK_PATH'],'|<br/>');
2095
							$content.= $this->extBackup($extKey,$list[$extKey]);
2096
							$this->content.=$this->doc->section('Backup',$content,0,1);
2097

    
2098
							$content = $this->extDelete($extKey,$list[$extKey]);
2099
							$this->content.=$this->doc->section('Delete',$content,0,1);
2100

    
2101
							$content = $this->extUpdateEMCONF($extKey,$list[$extKey]);
2102
							$this->content.=$this->doc->section('Update EM_CONF',$content,0,1);
2103
						}
2104
						break;
2105
					case 'dump':
2106
						$this->extDumpTables($extKey,$list[$extKey]);
2107
						break;
2108
					case 'edit':
2109
						$content = t3lib_BEfunc::cshItem('_MOD_tools_em', 'editfiles', $GLOBALS['BACK_PATH'],'|<br/>');
2110
						$content.= $this->getFileListOfExtension($extKey,$list[$extKey]);
2111

    
2112
						$this->content.=$this->doc->section('Extension files',$content,0,1);
2113
						break;
2114
					case 'updateModule':
2115
						$this->content.=$this->doc->section('Update:',is_object($updateObj) ? $updateObj->main() : 'No update object',0,1);
2116
						break;
2117
					default:
2118
						$this->extObjContent();
2119
						break;
2120
				}
2121
			}
2122
		}
2123
	}
2124

    
2125
	/**
2126
	 * Outputs a screen from where you can install multiple extensions in one go
2127
	 * This can be called from external modules with "...index.php?CMD[requestInstallExtensions]=
2128
	 *
2129
	 * @param	string		Comma list of extension keys to install. Renders a screen with checkboxes for all extensions not already imported or installed
2130
	 * @return	void
2131
	 */
2132
	function requestInstallExtensions($extList)	{
2133

    
2134
			// Return URL:
2135
		$returnUrl = t3lib_div::_GP('returnUrl');
2136
		$installOrImportExtension = t3lib_div::_POST('installOrImportExtension');
2137

    
2138
			// Extension List:
2139
		$extArray = explode(',',$extList);
2140
		$outputRow = array();
2141
		$outputRow[] = '
2142
			<tr class="bgColor5 tableheader">
2143
				<td>Install/Import:</td>
2144
				<td>Extension Key:</td>
2145
			</tr>
2146
		';
2147

    
2148
		foreach($extArray as $extKey)	{
2149

    
2150
				// Check for the request:
2151
			if ($installOrImportExtension[$extKey])	{
2152
				$this->installExtension($extKey);
2153
			}
2154

    
2155
				// Display:
2156
			if (!t3lib_extMgm::isLoaded($extKey))	{
2157
				$outputRow[] = '
2158
				<tr class="bgColor4">
2159
					<td><input type="checkbox" name="'.htmlspecialchars('installOrImportExtension['.$extKey.']').'" value="1" checked="checked" id="check_'.$extKey.'" /></td>
2160
					<td><label for="check_'.$extKey.'">'.htmlspecialchars($extKey).'</label></td>
2161
				</tr>
2162
				';
2163
			}
2164
		}
2165

    
2166
		if (count($outputRow)>1 || !$returnUrl)	{
2167
			$content = '
2168
			</form>	<!-- ending page form ... -->
2169
			<form action="'.htmlspecialchars(t3lib_div::getIndpEnv('REQUEST_URI')).'" method="post">
2170
				<table border="0" cellpadding="1" cellspacing="1">'.implode('',$outputRow).'</table>
2171
			<input type="submit" name="_" value="Import and Install selected" />
2172
			</form>
2173
			<form>	<!-- continuing page form... -->';
2174

    
2175
			if ($returnUrl)	{
2176
				$content.= '
2177
				<br/>
2178
				<br/>
2179
				<a href="'.htmlspecialchars($returnUrl).'">Return</a>
2180
				';
2181
			}
2182

    
2183
			$this->content.= $this->doc->section('Import/Install Extensions:',$content,0,1);
2184
		} else {
2185
			header('Location: '.t3lib_div::locationHeaderUrl($returnUrl));
2186
		}
2187
	}
2188

    
2189

    
2190

    
2191

    
2192

    
2193

    
2194

    
2195

    
2196
	/***********************************
2197
	*
2198
	* Application Sub-functions (HTML parts)
2199
	*
2200
	**********************************/
2201

    
2202
	/**
2203
	 * Creates a form for an extension which contains all options for configuration, updates of database, clearing of cache etc.
2204
	 * This form is shown when
2205
	 *
2206
	 * @param	string		Extension key
2207
	 * @param	array		Extension information array
2208
	 * @param	boolean		If set, the form will ONLY show if fields/tables should be updated (suppressing forms like general configuration and cache clearing).
2209
	 * @param	string		Alternative action=""-script
2210
	 * @param	string		HTML: Additional form fields
2211
	 * @return	string		HTML
2212
	 */
2213
	function updatesForm($extKey,$extInfo,$notSilent=0,$script='',$addFields='')	{
2214
		$script = $script ? $script : t3lib_div::linkThisScript();
2215
		$updates.= $this->checkDBupdates($extKey,$extInfo);
2216
		$uCache = $this->checkClearCache($extInfo);
2217
		if ($notSilent)	$updates.= $uCache;
2218
		$updates.= $this->checkUploadFolder($extKey,$extInfo);
2219

    
2220
		$absPath = $this->getExtPath($extKey,$extInfo['type']);
2221
		if ($notSilent && @is_file($absPath.'ext_conf_template.txt'))	{
2222
			$cForm = $this->tsStyleConfigForm($extKey,$extInfo,1,$script,$updates.$addFields.'<br />');
2223
		}
2224

    
2225
		if ($updates || $cForm)	{
2226
			if ($cForm)	{
2227
				$updates = '</form>'.$cForm.'<form>';
2228
			} else {
2229
				$updates = '</form><form action="'.htmlspecialchars($script).'" method="post">'.$updates.$addFields.'
2230
					<br /><input type="submit" name="write" value="Make updates" />
2231
				';
2232
			}
2233
		}
2234
		return $updates;
2235
	}
2236

    
2237
	/**
2238
	 * Creates view for dumping static tables and table/fields structures...
2239
	 *
2240
	 * @param	string		Extension key
2241
	 * @param	array		Extension information array
2242
	 * @return	void
2243
	 */
2244
	function extDumpTables($extKey,$extInfo)	{
2245

    
2246
		// Get dbInfo which holds the structure known from the tables.sql file
2247
		$techInfo = $this->makeDetailedExtensionAnalysis($extKey,$extInfo);
2248
		$absPath = $this->getExtPath($extKey,$extInfo['type']);
2249

    
2250
		// Static tables:
2251
		if (is_array($techInfo['static']))	{
2252
			if ($this->CMD['writeSTATICdump'])	{	// Writing static dump:
2253
				$writeFile = $absPath.'ext_tables_static+adt.sql';
2254
				if (@is_file($writeFile))	{
2255
					$dump_static = $this->dumpStaticTables(implode(',',$techInfo['static']));
2256
					t3lib_div::writeFile($writeFile,$dump_static);
2257
					$this->content.=$this->doc->section('Table and field structure required',t3lib_div::formatSize(strlen($dump_static)).'bytes written to '.substr($writeFile,strlen(PATH_site)),0,1);
2258
				}
2259
			} else {	// Showing info about what tables to dump - and giving the link to execute it.
2260
				$msg = 'Dumping table content for static tables:<br />';
2261
				$msg.= '<br />'.implode('<br />',$techInfo['static']).'<br />';
2262

    
2263
				// ... then feed that to this function which will make new CREATE statements of the same fields but based on the current database content.
2264
				$this->content.=$this->doc->section('Static tables',$msg.'<hr /><strong><a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[writeSTATICdump]=1').'">Write current static table contents to ext_tables_static+adt.sql now!</a></strong>',0,1);
2265
				$this->content.=$this->doc->spacer(20);
2266
			}
2267
		}
2268

    
2269
		// Table and field definitions:
2270
		if (is_array($techInfo['dump_tf']))	{
2271
			$dump_tf_array = $this->getTableAndFieldStructure($techInfo['dump_tf']);
2272
			$dump_tf = $this->dumpTableAndFieldStructure($dump_tf_array);
2273
			if ($this->CMD['writeTFdump'])	{
2274
				$writeFile = $absPath.'ext_tables.sql';
2275
				if (@is_file($writeFile))	{
2276
					t3lib_div::writeFile($writeFile,$dump_tf);
2277
					$this->content.=$this->doc->section('Table and field structure required',t3lib_div::formatSize(strlen($dump_tf)).'bytes written to '.substr($writeFile,strlen(PATH_site)),0,1);
2278
				}
2279
			} else {
2280
				$msg = 'Dumping current database structure for:<br />';
2281
				if (is_array($techInfo['tables']))	{
2282
					$msg.= '<br /><strong>Tables:</strong><br />'.implode('<br />',$techInfo['tables']).'<br />';
2283
				}
2284
				if (is_array($techInfo['fields']))	{
2285
					$msg.= '<br /><strong>Solo-fields:</strong><br />'.implode('<br />',$techInfo['fields']).'<br />';
2286
				}
2287

    
2288
				// ... then feed that to this function which will make new CREATE statements of the same fields but based on the current database content.
2289
				$this->content.=$this->doc->section('Table and field structure required',$msg.'<hr /><strong><a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[writeTFdump]=1').'">Write this dump to ext_tables.sql now!</a></strong><hr />
2290
				<pre>'.htmlspecialchars($dump_tf).'</pre>',0,1);
2291

    
2292

    
2293
				$details = '							This dump is based on two factors:<br />
2294
				<ul>
2295
				<li>1) All tablenames in ext_tables.sql which are <em>not</em> found in the "modify_tables" list in ext_emconf.php are dumped with the current database structure.</li>
2296
				<li>2) For any tablenames which <em>are</em> listed in "modify_tables" all fields and keys found for the table in ext_tables.sql will be re-dumped with the fresh equalents from the database.</li>
2297
				</ul>
2298
				Bottomline is: Whole tables are dumped from database with no regard to which fields and keys are defined in ext_tables.sql. But for tables which are only modified, any NEW fields added to the database must in some form or the other exist in the ext_tables.sql file as well.<br />';
2299
				$this->content.=$this->doc->section('',$details);
2300
			}
2301
		}
2302
	}
2303

    
2304
	/**
2305
	 * Returns file-listing of an extension
2306
	 *
2307
	 * @param	string		Extension key
2308
	 * @param	array		Extension information array
2309
	 * @return	string		HTML table.
2310
	 */
2311
	function getFileListOfExtension($extKey,$conf)	{
2312
		$content = '';
2313
		$extPath = $this->getExtPath($extKey,$conf['type']);
2314

    
2315
		if ($extPath)	{
2316
			// Read files:
2317
			$fileArr = array();
2318
			$fileArr = t3lib_div::getAllFilesAndFoldersInPath($fileArr,$extPath,'',0,99,$this->excludeForPackaging);
2319

    
2320
			// Start table:
2321
			$lines = array();
2322
			$totalSize = 0;
2323

    
2324
			// Header:
2325
			$lines[] = '
2326
				<tr class="bgColor5">
2327
					<td>File:</td>
2328
					<td>Size:</td>
2329
					<td>Edit:</td>
2330
				</tr>';
2331

    
2332
			foreach($fileArr as $file)	{
2333
				$fI = t3lib_div::split_fileref($file);
2334
				$lines[] = '
2335
				<tr class="bgColor4">
2336
					<td><a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[downloadFile]='.rawurlencode($file)).'" title="Download...">'.substr($file,strlen($extPath)).'</a></td>
2337
					<td>'.t3lib_div::formatSize(filesize($file)).'</td>
2338
					<td>'.(!in_array($extKey,$this->requiredExt)&&t3lib_div::inList($this->editTextExtensions,($fI['fileext']?$fI['fileext']:$fI['filebody']))?'<a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[editFile]='.rawurlencode($file)).'">Edit file</a>':'').'</td>
2339
				</tr>';
2340
				$totalSize+=filesize($file);
2341
			}
2342

    
2343
			$lines[] = '
2344
				<tr class="bgColor6">
2345
					<td><strong>Total:</strong></td>
2346
					<td><strong>'.t3lib_div::formatSize($totalSize).'</strong></td>
2347
					<td>&nbsp;</td>
2348
				</tr>';
2349

    
2350
			$content = '
2351
			Path: '.$extPath.'<br /><br />
2352
			<table border="0" cellpadding="1" cellspacing="2">'.implode('',$lines).'</table>';
2353
		}
2354

    
2355
		return $content;
2356
	}
2357

    
2358
	/**
2359
	 * Delete extension from the file system
2360
	 *
2361
	 * @param	string		Extension key
2362
	 * @param	array		Extension info array
2363
	 * @return	string		Returns message string about the status of the operation
2364
	 */
2365
	function extDelete($extKey,$extInfo)	{
2366
		$absPath = $this->getExtPath($extKey,$extInfo['type']);
2367
		if (t3lib_extMgm::isLoaded($extKey))	{
2368
			return 'This extension is currently installed (loaded and active) and so cannot be deleted!';
2369
		} elseif (!$this->deleteAsType($extInfo['type'])) {
2370
			return 'You cannot delete (and install/update) extensions in the '.$this->typeLabels[$extInfo['type']].' scope.';
2371
		} elseif (t3lib_div::inList('G,L',$extInfo['type'])) {
2372
			if ($this->CMD['doDelete'] && !strcmp($absPath,$this->CMD['absPath'])) {
2373
				$res = $this->removeExtDirectory($absPath);
2374
				if ($res) {
2375
					return 'ERROR: Could not remove extension directory "'.$absPath.'". Had the following errors:<br /><br />'.
2376
					nl2br($res);
2377
				} else {
2378
					return 'Removed extension in path "'.$absPath.'"!';
2379
				}
2380
			} else {
2381
				$onClick = "if (confirm('Are you sure you want to delete this extension from the server?')) {window.location.href='index.php?CMD[showExt]=".$extKey.'&CMD[doDelete]=1&CMD[absPath]='.rawurlencode($absPath)."';}";
2382
				$content.= '<a href="#" onclick="'.htmlspecialchars($onClick).' return false;"><strong>DELETE EXTENSION FROM SERVER</strong> (in the "'.$this->typeLabels[$extInfo['type']].'" location "'.substr($absPath,strlen(PATH_site)).'")!</a>';
2383
				$content.= '<br /><br />(Maybe you should make a backup first, see above.)';
2384
				return $content;
2385
			}
2386
		} else return 'Extension is not a global or local extension and cannot be removed.';
2387
	}
2388

    
2389
	/**
2390
	 * Update extension EM_CONF...
2391
	 *
2392
	 * @param	string		Extension key
2393
	 * @param	array		Extension information array
2394
	 * @return	string		HTML content.
2395
	 */
2396
	function extUpdateEMCONF($extKey,$extInfo)	{
2397
		$absPath = $this->getExtPath($extKey,$extInfo['type']);
2398
		if ($this->CMD['doUpdateEMCONF']) {
2399
			return $this->updateLocalEM_CONF($extKey,$extInfo);
2400
		} else {
2401
			$onClick = "if (confirm('Are you sure you want to update EM_CONF?')) {window.location.href='index.php?CMD[showExt]=".$extKey."&CMD[doUpdateEMCONF]=1';}";
2402
			$content.= '<a href="#" onclick="'.htmlspecialchars($onClick).' return false;"><strong>Update extension EM_CONF file</strong> (in the "'.$this->typeLabels[$extInfo['type']].'" location "'.substr($absPath,strlen(PATH_site)).'")!</a>';
2403
			$content.= '<br /><br />If files are changed, added or removed to an extension this is normally detected and displayed so you know that this extension has been locally altered and may need to be uploaded or at least not overridden.<br />
2404
						Updating this file will first of all reset this registration.';
2405
			return $content;
2406
		}
2407
	}
2408

    
2409
	/**
2410
	 * Download extension as file / make backup
2411
	 *
2412
	 * @param	string		Extension key
2413
	 * @param	array		Extension information array
2414
	 * @return	string		HTML content
2415
	 */
2416
	function extBackup($extKey,$extInfo)	{
2417
		$uArr = $this->makeUploadArray($extKey,$extInfo);
2418
		if (is_array($uArr))	{
2419
			$backUpData = $this->terConnection->makeUploadDataFromArray($uArr);
2420
			$filename = 'T3X_'.$extKey.'-'.str_replace('.','_',$extInfo['EM_CONF']['version']).'-z-'.date('YmdHi').'.t3x';
2421
			if (intval($this->CMD['doBackup'])==1)	{
2422
				header("Pragma: public"); // required
2423
				header("Expires: 0");
2424
				header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
2425
				header("Cache-Control: private",false); // required for certain browsers 
2426
				header('Content-Type: application/octet-stream');
2427
				header('Content-Disposition: attachment; filename='.$filename);
2428
				header("Content-Transfer-Encoding: binary");
2429
				echo $backUpData;
2430
				exit;
2431
			} elseif ($this->CMD['dumpTables'])	{
2432
				$filename='T3X_'.$extKey;
2433
				$cTables = count(explode(',',$this->CMD['dumpTables']));
2434
				if ($cTables>1)	{
2435
					$filename.='-'.$cTables.'tables';
2436
				} else {
2437
					$filename.='-'.$this->CMD['dumpTables'];
2438
				}
2439
				$filename.='+adt.sql';
2440

    
2441
				header('Content-Type: application/octet-stream');
2442
				header('Content-Disposition: attachment; filename='.$filename);
2443
				echo $this->dumpStaticTables($this->CMD['dumpTables']);
2444
				exit;
2445
			} else {
2446
				$techInfo = $this->makeDetailedExtensionAnalysis($extKey,$extInfo);
2447
				$lines=array();
2448
				$lines[]='<tr class="bgColor5"><td colspan="2"><strong>Make selection:</strong></td></tr>';
2449
				$lines[]='<tr class="bgColor4"><td><strong>Extension files:</strong></td><td>'.
2450
				'<a href="'.htmlspecialchars('index.php?CMD[doBackup]=1&CMD[showExt]='.$extKey).'">Download extension "'.$extKey.'" as a file</a><br />('.$filename.', '.t3lib_div::formatSize(strlen($backUpData)).', MD5: '.md5($backUpData).')<br /></td></tr>';
2451

    
2452
				if (is_array($techInfo['tables']))	{	$lines[]='<tr class="bgColor4"><td><strong>Data tables:</strong></td><td>'.$this->extBackup_dumpDataTablesLine($techInfo['tables'],$extKey).'</td></tr>';	}
2453
				if (is_array($techInfo['static']))	{	$lines[]='<tr class="bgColor4"><td><strong>Static tables:</strong></td><td>'.$this->extBackup_dumpDataTablesLine($techInfo['static'],$extKey).'</td></tr>';	}
2454

    
2455
				$content = '<table border="0" cellpadding="2" cellspacing="2">'.implode('',$lines).'</table>';
2456
				return $content;
2457
			}
2458
		} else die('Error...');
2459
	}
2460

    
2461
	/**
2462
	 * Link to dump of database tables
2463
	 *
2464
	 * @param	string		Extension key
2465
	 * @param	array		Extension information array
2466
	 * @return	string		HTML
2467
	 */
2468
	function extBackup_dumpDataTablesLine($tablesArray,$extKey)	{
2469
		$tables = array();
2470
		$tablesNA = array();
2471

    
2472
		foreach($tablesArray as $tN)	{
2473
			$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('count(*)', $tN, '');
2474
			if (!$GLOBALS['TYPO3_DB']->sql_error())	{
2475
				$row = $GLOBALS['TYPO3_DB']->sql_fetch_row($res);
2476
				$tables[$tN]='<tr><td>&nbsp;</td><td><a href="'.htmlspecialchars('index.php?CMD[dumpTables]='.rawurlencode($tN).'&CMD[showExt]='.$extKey).'" title="Dump table \''.$tN.'\'">'.$tN.'</a></td><td>&nbsp;&nbsp;&nbsp;</td><td>'.$row[0].' records</td></tr>';
2477
			} else {
2478
				$tablesNA[$tN]='<tr><td>&nbsp;</td><td>'.$tN.'</td><td>&nbsp;</td><td>Did not exist.</td></tr>';
2479
			}
2480
		}
2481
		$label = '<table border="0" cellpadding="0" cellspacing="0">'.implode('',array_merge($tables,$tablesNA)).'</table>';// Candidate for t3lib_div::array_merge() if integer-keys will some day make trouble...
2482
		if (count($tables))	{
2483
			$label = '<a href="'.htmlspecialchars('index.php?CMD[dumpTables]='.rawurlencode(implode(',',array_keys($tables))).'&CMD[showExt]='.$extKey).'" title="Dump all existing tables.">Download all data from:</a><br /><br />'.$label;
2484
		} else $label = 'Nothing to dump...<br /><br />'.$label;
2485
		return $label;
2486
	}
2487

    
2488
	/**
2489
	 * Prints a table with extension information in it.
2490
	 *
2491
	 * @param	string		Extension key
2492
	 * @param	array		Extension information array
2493
	 * @param	boolean		If set, the information array shows information for a remote extension in TER, not a local one.
2494
	 * @return	string		HTML content.
2495
	 */
2496
	function extInformationArray($extKey,$extInfo,$remote=0)	{
2497
		$lines=array();
2498
		$lines[]='<tr class="bgColor5"><td colspan="2"><strong>General information:</strong></td>'.$this->helpCol('').'</tr>';
2499
		$lines[]='<tr class="bgColor4"><td>Title:</td><td>'.$extInfo['EM_CONF']['_icon'].$extInfo['EM_CONF']['title'].'</td>'.$this->helpCol('title').'</tr>';
2500
		$lines[]='<tr class="bgColor4"><td>Description:</td><td>'.nl2br(htmlspecialchars($extInfo['EM_CONF']['description'])).'</td>'.$this->helpCol('description').'</tr>';
2501
		$lines[]='<tr class="bgColor4"><td>Author:</td><td>'.$this->wrapEmail($extInfo['EM_CONF']['author'].($extInfo['EM_CONF']['author_email'] ? ' <'.$extInfo['EM_CONF']['author_email'].'>' : ''),$extInfo['EM_CONF']['author_email']).($extInfo['EM_CONF']['author_company']?', '.$extInfo['EM_CONF']['author_company']:'').
2502
		'</td>'.$this->helpCol('description').'</tr>';
2503

    
2504
		$lines[]='<tr class="bgColor4"><td>Version:</td><td>'.$extInfo['EM_CONF']['version'].'</td>'.$this->helpCol('version').'</tr>';
2505
		$lines[]='<tr class="bgColor4"><td>Category:</td><td>'.$this->categories[$extInfo['EM_CONF']['category']].'</td>'.$this->helpCol('category').'</tr>';
2506
		$lines[]='<tr class="bgColor4"><td>State:</td><td>'.$this->states[$extInfo['EM_CONF']['state']].'</td>'.$this->helpCol('state').'</tr>';
2507
		$lines[]='<tr class="bgColor4"><td>Shy?</td><td>'.($extInfo['EM_CONF']['shy']?'Yes':'').'</td>'.$this->helpCol('shy').'</tr>';
2508
		$lines[]='<tr class="bgColor4"><td>Internal?</td><td>'.($extInfo['EM_CONF']['internal']?'Yes':'').'</td>'.$this->helpCol('internal').'</tr>';
2509

    
2510
		$lines[]='<tr class="bgColor4"><td>Depends on:</td><td>'.$this->depToString($extInfo['EM_CONF']['constraints']).'</td>'.$this->helpCol('dependencies').'</tr>';
2511
		$lines[]='<tr class="bgColor4"><td>Conflicts with:</td><td>'.$this->depToString($extInfo['EM_CONF']['constraints'],'conflicts').'</td>'.$this->helpCol('dependencies').'</tr>';
2512
		$lines[]='<tr class="bgColor4"><td>Suggests:</td><td>'.$this->depToString($extInfo['EM_CONF']['constraints'],'suggests').'</td>'.$this->helpCol('dependencies').'</tr>';
2513
		if (!$remote)	{
2514
			$lines[]='<tr class="bgColor4"><td>Priority:</td><td>'.$extInfo['EM_CONF']['priority'].'</td>'.$this->helpCol('priority').'</tr>';
2515
			$lines[]='<tr class="bgColor4"><td>Clear cache?</td><td>'.($extInfo['EM_CONF']['clearCacheOnLoad']?'Yes':'').'</td>'.$this->helpCol('clearCacheOnLoad').'</tr>';
2516
			$lines[]='<tr class="bgColor4"><td>Includes modules:</td><td>'.$extInfo['EM_CONF']['module'].'</td>'.$this->helpCol('module').'</tr>';
2517
			$lines[]='<tr class="bgColor4"><td>Lock Type?</td><td>'.($extInfo['EM_CONF']['lockType']?$extInfo['EM_CONF']['lockType']:'').'</td>'.$this->helpCol('lockType').'</tr>';
2518
			$lines[]='<tr class="bgColor4"><td>Modifies tables:</td><td>'.$extInfo['EM_CONF']['modify_tables'].'</td>'.$this->helpCol('modify_tables').'</tr>';
2519

    
2520
			// Installation status:
2521
			$techInfo = $this->makeDetailedExtensionAnalysis($extKey,$extInfo,1);
2522
			$lines[]='<tr><td>&nbsp;</td><td></td>'.$this->helpCol('').'</tr>';
2523
			$lines[]='<tr class="bgColor5"><td colspan="2"><strong>Installation status:</strong></td>'.$this->helpCol('').'</tr>';
2524
			$lines[]='<tr class="bgColor4"><td>Type of install:</td><td>'.$this->typeLabels[$extInfo['type']].' - <em>'.$this->typeDescr[$extInfo['type']].'</em></td>'.$this->helpCol('type').'</tr>';
2525
			$lines[]='<tr class="bgColor4"><td>Double installs?</td><td>'.$this->extInformationArray_dbInst($extInfo['doubleInstall'],$extInfo['type']).'</td>'.$this->helpCol('doubleInstall').'</tr>';
2526
			if (is_array($extInfo['files']))	{
2527
				sort($extInfo['files']);
2528
				$lines[]='<tr class="bgColor4"><td>Root files:</td><td>'.implode('<br />',$extInfo['files']).'</td>'.$this->helpCol('rootfiles').'</tr>';
2529
			}
2530

    
2531
			if ($techInfo['tables']||$techInfo['static']||$techInfo['fields'])	{
2532
				if (!$remote && t3lib_extMgm::isLoaded($extKey))	{
2533
					$tableStatus = $GLOBALS['TBE_TEMPLATE']->rfw(($techInfo['tables_error']?'<strong>Table error!</strong><br />Probably one or more required fields/tables are missing in the database!':'').
2534
					($techInfo['static_error']?'<strong>Static table error!</strong><br />The static tables are missing or empty!':''));
2535
				} else {
2536
					$tableStatus = $techInfo['tables_error']||$techInfo['static_error'] ? 'The database will need to be updated when this extension is installed.' : 'All required tables are already in the database!';
2537
				}
2538
			}
2539

    
2540
			$lines[]='<tr class="bgColor4"><td>Database requirements:</td><td>'.$this->extInformationArray_dbReq($techInfo,1).'</td>'.$this->helpCol('dbReq').'</tr>';
2541
			$lines[]='<tr class="bgColor4"><td>Database status:</td><td>'.$tableStatus.'</td>'.$this->helpCol('dbStatus').'</tr>';
2542
			$lines[]='<tr class="bgColor4"><td>Flags:</td><td>'.(is_array($techInfo['flags'])?implode('<br />',$techInfo['flags']):'').'</td>'.$this->helpCol('flags').'</tr>';
2543
			$lines[]='<tr class="bgColor4"><td>Config template?</td><td>'.($techInfo['conf']?'Yes':'').'</td>'.$this->helpCol('conf').'</tr>';
2544
			$lines[]='<tr class="bgColor4"><td>TypoScript files:</td><td>'.(is_array($techInfo['TSfiles'])?implode('<br />',$techInfo['TSfiles']):'').'</td>'.$this->helpCol('TSfiles').'</tr>';
2545
			$lines[]='<tr class="bgColor4"><td>Language files:</td><td>'.(is_array($techInfo['locallang'])?implode('<br />',$techInfo['locallang']):'').'</td>'.$this->helpCol('locallang').'</tr>';
2546
			$lines[]='<tr class="bgColor4"><td>Upload folder:</td><td>'.($techInfo['uploadfolder']?$techInfo['uploadfolder']:'').'</td>'.$this->helpCol('uploadfolder').'</tr>';
2547
			$lines[]='<tr class="bgColor4"><td>Create directories:</td><td>'.(is_array($techInfo['createDirs'])?implode('<br />',$techInfo['createDirs']):'').'</td>'.$this->helpCol('createDirs').'</tr>';
2548
			$lines[]='<tr class="bgColor4"><td>Module names:</td><td>'.(is_array($techInfo['moduleNames'])?implode('<br />',$techInfo['moduleNames']):'').'</td>'.$this->helpCol('moduleNames').'</tr>';
2549
			$lines[]='<tr class="bgColor4"><td>Class names:</td><td>'.(is_array($techInfo['classes'])?implode('<br />',$techInfo['classes']):'').'</td>'.$this->helpCol('classNames').'</tr>';
2550
			$lines[]='<tr class="bgColor4"><td>Code warnings:<br />(developer-relevant)</td><td>'.(is_array($techInfo['errors'])?$GLOBALS['TBE_TEMPLATE']->rfw(implode('<br />',$techInfo['errors'])):'').'</td>'.$this->helpCol('errors').'</tr>';
2551
			$lines[]='<tr class="bgColor4"><td>Naming annoyances:<br />(developer-relevant)</td><td>'.(is_array($techInfo['NSerrors']) ? (!t3lib_div::inList($this->nameSpaceExceptions,$extKey)?t3lib_div::view_array($techInfo['NSerrors']):$GLOBALS['TBE_TEMPLATE']->dfw('[exception]')) : '').'</td>'.$this->helpCol('NSerrors').'</tr>';
2552

    
2553
			$currentMd5Array = $this->serverExtensionMD5Array($extKey,$extInfo);
2554
			$affectedFiles='';
2555

    
2556
			$msgLines=array();
2557
			if (strcmp($extInfo['EM_CONF']['_md5_values_when_last_written'],serialize($currentMd5Array)))	{
2558
				$msgLines[] = $GLOBALS['TBE_TEMPLATE']->rfw('<br /><strong>A difference between the originally installed version and the current was detected!</strong>');
2559
				$affectedFiles = $this->findMD5ArrayDiff($currentMd5Array,unserialize($extInfo['EM_CONF']['_md5_values_when_last_written']));
2560
				if (count($affectedFiles))	$msgLines[] = '<br /><strong>Modified files:</strong><br />'.$GLOBALS['TBE_TEMPLATE']->rfw(implode('<br />',$affectedFiles));
2561
			}
2562
			$lines[]='<tr class="bgColor4"><td>Files changed?</td><td>'.implode('<br />',$msgLines).'</td>'.$this->helpCol('filesChanged').'</tr>';
2563
		}
2564

    
2565
		return '<table border="0" cellpadding="1" cellspacing="2">
2566
					'.implode('
2567
					',$lines).'
2568
				</table>';
2569
	}
2570

    
2571
	/**
2572
	 * Returns HTML with information about database requirements
2573
	 *
2574
	 * @param	array		Technical information array
2575
	 * @param	boolean		Table header displayed
2576
	 * @return	string		HTML content.
2577
	 */
2578
	function extInformationArray_dbReq($techInfo,$tableHeader=0)	{
2579
		return nl2br(trim((is_array($techInfo['tables'])?($tableHeader?"\n\n<strong>Tables:</strong>\n":'').implode(chr(10),$techInfo['tables']):'').
2580
		(is_array($techInfo['static'])?"\n\n<strong>Static tables:</strong>\n".implode(chr(10),$techInfo['static']):'').
2581
		(is_array($techInfo['fields'])?"\n\n<strong>Additional fields:</strong>\n".implode('<hr />',$techInfo['fields']):'')));
2582
	}
2583

    
2584
	/**
2585
	 * Double install warning.
2586
	 *
2587
	 * @param	string		Double-install string, eg. "LG" etc.
2588
	 * @param	string		Current scope, eg. "L" or "G" or "S"
2589
	 * @return	string		Message
2590
	 */
2591
	function extInformationArray_dbInst($dbInst,$current)	{
2592
		if (strlen($dbInst)>1)	{
2593
			$others = array();
2594
			for($a=0;$a<strlen($dbInst);$a++)	{
2595
				if (substr($dbInst,$a,1)!=$current)	{
2596
					$others[]='"'.$this->typeLabels[substr($dbInst,$a,1)].'"';
2597
				}
2598
			}
2599
			return $GLOBALS['TBE_TEMPLATE']->rfw('A '.implode(' and ',$others).' extension with this key is also available on the server, but cannot be loaded because the "'.$this->typeLabels[$current].'" version takes precedence.');
2600
		} else return '';
2601
	}
2602

    
2603
	/**
2604
	 * Prints the upload form for extensions
2605
	 *
2606
	 * @param	string		Extension key
2607
	 * @param	array		Extension information array
2608
	 * @return	string		HTML content.
2609
	 */
2610
	function getRepositoryUploadForm($extKey,$extInfo)	{
2611
		$content.='
2612
			<input type="hidden" name="CMD[showExt]" value="'.$extKey.'" />
2613
			<input type="hidden" name="em[action]" value="doUpload" />
2614
			<table border="0" cellpadding="2" cellspacing="1">
2615
				<tr class="bgColor4">
2616
					<td>Repository Username:</td>
2617
					<td><input'.$this->doc->formWidth(20).' type="text" name="em[user][fe_u]" value="'.$this->fe_user['username'].'" /></td>
2618
				</tr>
2619
				<tr class="bgColor4">
2620
					<td>Repository Password:</td>
2621
					<td><input'.$this->doc->formWidth(20).' type="password" name="em[user][fe_p]" value="'.$this->fe_user['password'].'" /></td>
2622
				</tr>
2623
				<tr class="bgColor4">
2624
					<td>Changelog for upload:</td>
2625
					<td><textarea'.$this->doc->formWidth(30,1).' rows="5" name="em[upload][comment]"></textarea></td>
2626
				</tr>
2627
				<tr class="bgColor4">
2628
					<td>Upload command:</td>
2629
					<td nowrap="nowrap">
2630
						<input type="radio" name="em[upload][mode]" id="new_dev" value="new_dev" checked="checked" /> <label for="new_dev">New development version (latest x.x.<strong>'.$GLOBALS['TBE_TEMPLATE']->rfw('x+1').'</strong>)</label><br />
2631
						<input type="radio" name="em[upload][mode]" id="latest" value="latest" /> <label for="latest">Override <em>this</em> development version ('.$extInfo['EM_CONF']['version'].')</label><br />
2632
						<input type="radio" name="em[upload][mode]" id="new_sub" value="new_sub" /> <label for="new_sub">New sub version (latest x.<strong>'.$GLOBALS['TBE_TEMPLATE']->rfw('x+1').'</strong>.0)</label><br />
2633
						<input type="radio" name="em[upload][mode]" id="new_main" value="new_main" /> <label for="new_main">New main version (latest <strong>'.$GLOBALS['TBE_TEMPLATE']->rfw('x+1').'</strong>.0.0)</label><br />
2634
						<input type="radio" name="em[upload][mode]" id="custom" value="custom" /> <label for="custom">This version: <input type="text" name="em[upload][version]" /></label><br />
2635
					</td>
2636
				</tr>
2637
				<tr class="bgColor4">
2638
					<td>&nbsp;</td>
2639
					<td><input type="submit" name="submit" value="Upload extension" />
2640
					</td>
2641
				</tr>
2642
			</table>
2643
			';
2644

    
2645
		return $content;
2646
	}
2647

    
2648

    
2649

    
2650

    
2651

    
2652

    
2653

    
2654

    
2655

    
2656

    
2657
	/***********************************
2658
	*
2659
	* Extension list rendering
2660
	*
2661
	**********************************/
2662

    
2663
	/**
2664
	 * Prints the header row for the various listings
2665
	 *
2666
	 * @param	string		Attributes for the <tr> tag
2667
	 * @param	array		Preset cells in the beginning of the row. Typically a blank cell with a clear-gif
2668
	 * @param	boolean		If set, the list is coming from remote server.
2669
	 * @return	string		HTML <tr> table row
2670
	 */
2671
	function extensionListRowHeader($trAttrib,$cells,$import=0)	{
2672
		$cells[] = '<td></td>';
2673
		$cells[] = '<td>Title:</td>';
2674

    
2675
		if (!$this->MOD_SETTINGS['display_details'])	{
2676
			$cells[] = '<td>Description:</td>';
2677
			$cells[] = '<td>Author:</td>';
2678
		} elseif ($this->MOD_SETTINGS['display_details']==2)	{
2679
			$cells[] = '<td>Priority:</td>';
2680
			$cells[] = '<td>Mod.Tables:</td>';
2681
			$cells[] = '<td>Modules:</td>';
2682
			$cells[] = '<td>Cl.Cache?</td>';
2683
			$cells[] = '<td>Internal?</td>';
2684
			$cells[] = '<td>Shy?</td>';
2685
		} elseif ($this->MOD_SETTINGS['display_details']==3)	{
2686
			$cells[] = '<td>Tables/Fields:</td>';
2687
			$cells[] = '<td>TS-files:</td>';
2688
			$cells[] = '<td>Affects:</td>';
2689
			$cells[] = '<td>Modules:</td>';
2690
			$cells[] = '<td>Config?</td>';
2691
			$cells[] = '<td>Code warnings:</td>';
2692
		} elseif ($this->MOD_SETTINGS['display_details']==4)	{
2693
			$cells[] = '<td>locallang:</td>';
2694
			$cells[] = '<td>Classes:</td>';
2695
			$cells[] = '<td>Code warnings:</td>';
2696
			$cells[] = '<td>Nameing annoyances:</td>';
2697
		} elseif ($this->MOD_SETTINGS['display_details']==5)	{
2698
			$cells[] = '<td>Changed files:</td>';
2699
		} else {
2700
			$cells[] = '<td>Extension key:</td>';
2701
			$cells[] = '<td>Version:</td>';
2702
			if (!$import) {
2703
				$cells[] = '<td>DL:</td>';
2704
				$cells[] = '<td>Doc:</td>';
2705
				$cells[] = '<td>Type:</td>';
2706
			} else {
2707
				$cells[] = '<td class="bgColor6"'.$this->labelInfo('Current version of the extension on this server. If colored red there is a newer version in repository! Then you should upgrade.').'>Cur. Ver:</td>';
2708
				$cells[] = '<td class="bgColor6"'.$this->labelInfo('Current type of installation of the extension on this server.').'>Cur. Type:</td>';
2709
				$cells[] = '<td'.$this->labelInfo('Number of downloads, all versions/this version').'>DL:</td>';
2710
			}
2711
			$cells[] = '<td>State:</td>';
2712
		}
2713
		return '
2714
			<tr'.$trAttrib.'>
2715
				'.implode('
2716
				',$cells).'
2717
			</tr>';
2718
	}
2719

    
2720
	/**
2721
	 * Prints a row with data for the various extension listings
2722
	 *
2723
	 * @param	string		Extension key
2724
	 * @param	array		Extension information array
2725
	 * @param	array		Preset table cells, eg. install/uninstall icons.
2726
	 * @param	string		<tr> tag class
2727
	 * @param	array		Array with installed extension keys (as keys)
2728
	 * @param	boolean		If set, the list is coming from remote server.
2729
	 * @param	string		Alternative link URL
2730
	 * @return	string		HTML <tr> content
2731
	 */
2732
	function extensionListRow($extKey,$extInfo,$cells,$bgColorClass='',$inst_list=array(),$import=0,$altLinkUrl='')	{
2733

    
2734
			// Icon:
2735
		$imgInfo = @getImageSize($this->getExtPath($extKey,$extInfo['type']).'/ext_icon.gif');
2736
		if (is_array($imgInfo))	{
2737
			$cells[] = '<td><img src="'.$GLOBALS['BACK_PATH'].$this->typeRelPaths[$extInfo['type']].$extKey.'/ext_icon.gif'.'" '.$imgInfo[3].' alt="" /></td>';
2738
		} elseif ($extInfo['_ICON']) {
2739
			$cells[] = '<td>'.$extInfo['_ICON'].'</td>';
2740
		} else {
2741
			$cells[] = '<td><img src="clear.gif" width="1" height="1" alt="" /></td>';
2742
		}
2743

    
2744
			// Extension title:
2745
		$cells[] = '<td nowrap="nowrap"><a href="'.htmlspecialchars($altLinkUrl?$altLinkUrl:'index.php?CMD[showExt]='.$extKey.'&SET[singleDetails]=info').'" title="'.$extKey.'"'/*.($extInfo['EM_CONF']['shy'] ? ' style="color:#666;" ' : '')*/.'>'.t3lib_div::fixed_lgd($extInfo['EM_CONF']['title']?$extInfo['EM_CONF']['title']:'<em>'.$extKey.'</em>',40).'</a></td>';
2746

    
2747
			// Based on which display mode you will see more or less details:
2748
		if (!$this->MOD_SETTINGS['display_details'])	{
2749
			$cells[] = '<td>'.htmlspecialchars(t3lib_div::fixed_lgd($extInfo['EM_CONF']['description'],400)).'<br /><img src="clear.gif" width="300" height="1" alt="" /></td>';
2750
			$cells[] = '<td nowrap="nowrap">'.($extInfo['EM_CONF']['author_email'] ? '<a href="mailto:'.htmlspecialchars($extInfo['EM_CONF']['author_email']).'">' : '').htmlspecialchars($extInfo['EM_CONF']['author']).($extInfo['EM_CONF']['author_email'] ? '</a>' : '').($extInfo['EM_CONF']['author_company'] ? '<br />'.htmlspecialchars($extInfo['EM_CONF']['author_company']) : '').'</td>';
2751
		} elseif ($this->MOD_SETTINGS['display_details']==2)	{
2752
			$cells[] = '<td nowrap="nowrap">'.$extInfo['EM_CONF']['priority'].'</td>';
2753
			$cells[] = '<td nowrap="nowrap">'.implode('<br />',t3lib_div::trimExplode(',',$extInfo['EM_CONF']['modify_tables'],1)).'</td>';
2754
			$cells[] = '<td nowrap="nowrap">'.$extInfo['EM_CONF']['module'].'</td>';
2755
			$cells[] = '<td nowrap="nowrap">'.($extInfo['EM_CONF']['clearCacheOnLoad'] ? 'Yes' : '').'</td>';
2756
			$cells[] = '<td nowrap="nowrap">'.($extInfo['EM_CONF']['internal'] ? 'Yes' : '').'</td>';
2757
			$cells[] = '<td nowrap="nowrap">'.($extInfo['EM_CONF']['shy'] ? 'Yes' : '').'</td>';
2758
		} elseif ($this->MOD_SETTINGS['display_details']==3)	{
2759
			$techInfo = $this->makeDetailedExtensionAnalysis($extKey,$extInfo);
2760

    
2761
			$cells[] = '<td>'.$this->extInformationArray_dbReq($techInfo).
2762
			'</td>';
2763
			$cells[] = '<td nowrap="nowrap">'.(is_array($techInfo['TSfiles']) ? implode('<br />',$techInfo['TSfiles']) : '').'</td>';
2764
			$cells[] = '<td nowrap="nowrap">'.(is_array($techInfo['flags']) ? implode('<br />',$techInfo['flags']) : '').'</td>';
2765
			$cells[] = '<td nowrap="nowrap">'.(is_array($techInfo['moduleNames']) ? implode('<br />',$techInfo['moduleNames']) : '').'</td>';
2766
			$cells[] = '<td nowrap="nowrap">'.($techInfo['conf'] ? 'Yes' : '').'</td>';
2767
			$cells[] = '<td>'.
2768
			$GLOBALS['TBE_TEMPLATE']->rfw((t3lib_extMgm::isLoaded($extKey)&&$techInfo['tables_error']?'<strong>Table error!</strong><br />Probably one or more required fields/tables are missing in the database!':'').
2769
			(t3lib_extMgm::isLoaded($extKey)&&$techInfo['static_error']?'<strong>Static table error!</strong><br />The static tables are missing or empty!':'')).
2770
			'</td>';
2771
		} elseif ($this->MOD_SETTINGS['display_details']==4)	{
2772
			$techInfo=$this->makeDetailedExtensionAnalysis($extKey,$extInfo,1);
2773

    
2774
			$cells[] = '<td>'.(is_array($techInfo['locallang']) ? implode('<br />',$techInfo['locallang']) : '').'</td>';
2775
			$cells[] = '<td>'.(is_array($techInfo['classes']) ? implode('<br />',$techInfo['classes']) : '').'</td>';
2776
			$cells[] = '<td>'.(is_array($techInfo['errors']) ? $GLOBALS['TBE_TEMPLATE']->rfw(implode('<hr />',$techInfo['errors'])) : '').'</td>';
2777
			$cells[] = '<td>'.(is_array($techInfo['NSerrors']) ? (!t3lib_div::inList($this->nameSpaceExceptions,$extKey) ? t3lib_div::view_array($techInfo['NSerrors']) : $GLOBALS['TBE_TEMPLATE']->dfw('[exception]')) :'').'</td>';
2778
		} elseif ($this->MOD_SETTINGS['display_details']==5)	{
2779
			$currentMd5Array = $this->serverExtensionMD5Array($extKey,$extInfo);
2780
			$affectedFiles = '';
2781
			$msgLines = array();
2782
			$msgLines[] = 'Files: '.count($currentMd5Array);
2783
			if (strcmp($extInfo['EM_CONF']['_md5_values_when_last_written'],serialize($currentMd5Array)))	{
2784
				$msgLines[] = $GLOBALS['TBE_TEMPLATE']->rfw('<br /><strong>A difference between the originally installed version and the current was detected!</strong>');
2785
				$affectedFiles = $this->findMD5ArrayDiff($currentMd5Array,unserialize($extInfo['EM_CONF']['_md5_values_when_last_written']));
2786
				if (count($affectedFiles))	$msgLines[] = '<br /><strong>Modified files:</strong><br />'.$GLOBALS['TBE_TEMPLATE']->rfw(implode('<br />',$affectedFiles));
2787
			}
2788
			$cells[] = '<td>'.implode('<br />',$msgLines).'</td>';
2789
		} else {
2790
				// Default view:
2791
			$verDiff = $inst_list[$extKey] && $this->versionDifference($extInfo['EM_CONF']['version'],$inst_list[$extKey]['EM_CONF']['version'],$this->versionDiffFactor);
2792

    
2793
			$cells[] = '<td nowrap="nowrap"><em>'.$extKey.'</em></td>';
2794
			$cells[] = '<td nowrap="nowrap">'.($verDiff ? '<strong>'.$GLOBALS['TBE_TEMPLATE']->rfw(htmlspecialchars($extInfo['EM_CONF']['version'])).'</strong>' : $extInfo['EM_CONF']['version']).'</td>';
2795
			if (!$import) {		// Listing extenson on LOCAL server:
2796
					// Extension Download:
2797
				$cells[] = '<td nowrap="nowrap"><a href="'.htmlspecialchars('index.php?CMD[doBackup]=1&SET[singleDetails]=backup&CMD[showExt]='.$extKey).'"><img src="download.png" width="13" height="12" title="Download" alt="" /></a></td>';
2798

    
2799
					// Manual download
2800
				$fileP = PATH_site.$this->typePaths[$extInfo['type']].$extKey.'/doc/manual.sxw';
2801
				$cells[] = '<td nowrap="nowrap">'.
2802
				($this->typePaths[$extInfo['type']] && @is_file($fileP)?'<a href="'.htmlspecialchars(t3lib_div::resolveBackPath($this->doc->backPath.'../'.$this->typePaths[$extInfo['type']].$extKey.'/doc/manual.sxw')).'" target="_blank"><img src="oodoc.gif" width="13" height="16" title="Local Open Office Manual" alt="" /></a>':'').
2803
				'</td>';
2804
				$cells[] = '<td nowrap="nowrap">'.$this->typeLabels[$extInfo['type']].(strlen($extInfo['doubleInstall'])>1?'<strong> '.$GLOBALS['TBE_TEMPLATE']->rfw($extInfo['doubleInstall']).'</strong>':'').'</td>';
2805
			} else {	// Listing extensions from REMOTE repository:
2806
				$inst_curVer = $inst_list[$extKey]['EM_CONF']['version'];
2807
				if (isset($inst_list[$extKey]))	{
2808
					if ($verDiff)	$inst_curVer = '<strong>'.$GLOBALS['TBE_TEMPLATE']->rfw($inst_curVer).'</strong>';
2809
				}
2810
				$cells[] = '<td nowrap="nowrap">'.$inst_curVer.'</td>';
2811
				$cells[] = '<td nowrap="nowrap">'.$this->typeLabels[$inst_list[$extKey]['type']].(strlen($inst_list[$extKey]['doubleInstall'])>1?'<strong> '.$GLOBALS['TBE_TEMPLATE']->rfw($inst_list[$extKey]['doubleInstall']).'</strong>':'').'</td>';
2812
				$cells[] = '<td nowrap="nowrap">'.($extInfo['downloadcounter_all']?$extInfo['downloadcounter_all']:'&nbsp;&nbsp;').'/'.($extInfo['downloadcounter']?$extInfo['downloadcounter']:'&nbsp;').'</td>';
2813
			}
2814
			$cells[] = '<td nowrap="nowrap" class="extstate" style="background-color:'.$this->stateColors[$extInfo['EM_CONF']['state']].';">'.$this->states[$extInfo['EM_CONF']['state']].'</td>';
2815
		}
2816

    
2817
		if($this->xmlhandler->getReviewState($extKey,$extInfo['EM_CONF']['version'])<1) {
2818
			$bgclass = ' class="unsupported-ext"';
2819
		} else {
2820
			$bgclass = ' class="'.($bgColorClass?$bgColorClass:'bgColor4').'"';
2821
		}
2822

    
2823
		return '
2824
			<tr'.$bgclass.'>
2825
				'.implode('
2826
				',$cells).'
2827
			</tr>';
2828
	}
2829

    
2830

    
2831

    
2832

    
2833

    
2834

    
2835
	/************************************
2836
	*
2837
	* Output helper functions
2838
	*
2839
	************************************/
2840

    
2841
	/**
2842
	 * Wrapping input string in a link tag with link to email address
2843
	 *
2844
	 * @param	string		Input string, being wrapped in <a> tags
2845
	 * @param	string		Email address for use in link.
2846
	 * @return	string		Output
2847
	 */
2848
	function wrapEmail($str,$email)	{
2849
		if ($email)	{
2850
			$str = '<a href="mailto:'.htmlspecialchars($email).'">'.htmlspecialchars($str).'</a>';
2851
		}
2852
		return $str;
2853
	}
2854

    
2855
	/**
2856
	 * Returns help text if applicable.
2857
	 *
2858
	 * @param	string		Help text key
2859
	 * @return	string		HTML table cell
2860
	 */
2861
	function helpCol($key)	{
2862
		global $BE_USER;
2863
		if ($BE_USER->uc['edit_showFieldHelp'])	{
2864
			$hT = trim(t3lib_BEfunc::helpText($this->descrTable,'emconf_'.$key,$this->doc->backPath));
2865
			return '<td>'.($hT?$hT:t3lib_BEfunc::helpTextIcon($this->descrTable,'emconf_'.$key,$this->doc->backPath)).'</td>';
2866
		} else {
2867
			return '';
2868
		}
2869
	}
2870

    
2871
	/**
2872
	 * Returns title and style attribute for mouseover help text.
2873
	 *
2874
	 * @param	string		Help text.
2875
	 * @return	string		title="" attribute prepended with a single space
2876
	 */
2877
	function labelInfo($str)	{
2878
		return ' title="'.htmlspecialchars($str).'" style="cursor:help;"';
2879
	}
2880

    
2881
	/**
2882
	 * Returns a header for an extensions including icon if any
2883
	 *
2884
	 * @param	string		Extension key
2885
	 * @param	array		Extension information array
2886
	 * @param	string		align-attribute value (for <img> tag)
2887
	 * @return	string		HTML; Extension title and image.
2888
	 */
2889
	function extensionTitleIconHeader($extKey,$extInfo,$align='top')	{
2890
		$imgInfo = @getImageSize($this->getExtPath($extKey,$extInfo['type']).'/ext_icon.gif');
2891
		$out = '';
2892
		if (is_array($imgInfo))	{
2893
			$out.= '<img src="'.$GLOBALS['BACK_PATH'].$this->typeRelPaths[$extInfo['type']].$extKey.'/ext_icon.gif" '.$imgInfo[3].' align="'.$align.'" alt="" />';
2894
		}
2895
		$out.= $extInfo['EM_CONF']['title'] ? htmlspecialchars(t3lib_div::fixed_lgd($extInfo['EM_CONF']['title'],40)) : '<em>'.$extKey.'</em>';
2896
		return $out;
2897
	}
2898

    
2899
	/**
2900
	 * Returns image tag for "uninstall"
2901
	 *
2902
	 * @return	string		<img> tag
2903
	 */
2904
	function removeButton()	{
2905
		return '<img src="uninstall.gif" width="16" height="16" title="Remove extension" align="top" alt="" />';
2906
	}
2907

    
2908
	/**
2909
	 * Returns image for "install"
2910
	 *
2911
	 * @return	string		<img> tag
2912
	 */
2913
	function installButton()	{
2914
		return '<img src="install.gif" width="16" height="16" title="Install extension..." align="top" alt="" />';
2915
	}
2916

    
2917
	/**
2918
	 * Warning (<img> + text string) message about the impossibility to import extensions (both local and global locations are disabled...)
2919
	 *
2920
	 * @return	string		<img> + text string.
2921
	 */
2922
	function noImportMsg()	{
2923
		return '<img src="'.$this->doc->backPath.'gfx/icon_warning2.gif" width="18" height="16" align="top" alt="" /><strong>Import to both local and global path is disabled in TYPO3_CONF_VARS!</strong>';
2924
	}
2925

    
2926
	/**
2927
	 * Checks whether the passed dependency is TER2-style (array) and returns a single string for displaying the dependencies.
2928
	 *
2929
	 * It leaves out all version numbers and the "php" and "typo3" dependencies, as they are implicit and of no interest without the version number.
2930
	 *
2931
	 * @param	mixed		$dep Either a string or an array listing dependencies.
2932
	 * @param	string		$type The dependency type to list if $dep is an array
2933
	 * @return	string		A simple dependency list for display
2934
	 */
2935
	function depToString($dep,$type='depends') {
2936
		if(is_array($dep)) {
2937
			unset($dep[$type]['php']);
2938
			unset($dep[$type]['typo3']);
2939
			$s = (count($dep[$type])) ? implode(',', array_keys($dep[$type])) : '';
2940
			return $s;
2941
		}
2942
		return '';
2943
	}
2944

    
2945
	/**
2946
	 * Checks whether the passed dependency is TER-style (string) or TER2-style (array) and returns a single string for displaying the dependencies.
2947
	 *
2948
	 * It leaves out all version numbers and the "php" and "typo3" dependencies, as they are implicit and of no interest without the version number.
2949
	 *
2950
	 * @param	mixed		$dep Either a string or an array listing dependencies.
2951
	 * @param	string		$type The dependency type to list if $dep is an array
2952
	 * @return	string		A simple dependency list for display
2953
	 */
2954
	function stringToDep($dep) {
2955
		$constraint = array();
2956
		if(is_string($dep) && strlen($dep)) {
2957
			$dep = explode(',',$dep);
2958
			foreach($dep as $v) {
2959
				$constraint[$v] = '';
2960
			}
2961
		}
2962
		return $constraint;
2963
	}
2964

    
2965

    
2966

    
2967

    
2968

    
2969

    
2970

    
2971

    
2972
	/********************************
2973
	*
2974
	* Read information about all available extensions
2975
	*
2976
	*******************************/
2977

    
2978
	/**
2979
	 * Returns the list of available (installed) extensions
2980
	 *
2981
	 * @return	array		Array with two arrays, list array (all extensions with info) and category index
2982
	 * @see getInstExtList()
2983
	 */
2984
	function getInstalledExtensions()	{
2985
		$list = array();
2986
		$cat = $this->defaultCategories;
2987

    
2988
		$path = PATH_typo3.'sysext/';
2989
		$this->getInstExtList($path,$list,$cat,'S');
2990

    
2991
		$path = PATH_typo3.'ext/';
2992
		$this->getInstExtList($path,$list,$cat,'G');
2993

    
2994
		$path = PATH_typo3conf.'ext/';
2995
		$this->getInstExtList($path,$list,$cat,'L');
2996

    
2997
		return array($list,$cat);
2998
	}
2999

    
3000
	/**
3001
	 * Gathers all extensions in $path
3002
	 *
3003
	 * @param	string		Absolute path to local, global or system extensions
3004
	 * @param	array		Array with information for each extension key found. Notice: passed by reference
3005
	 * @param	array		Categories index: Contains extension titles grouped by various criteria.
3006
	 * @param	string		Path-type: L, G or S
3007
	 * @return	void		"Returns" content by reference
3008
	 * @access private
3009
	 * @see getInstalledExtensions()
3010
	 */
3011
	function getInstExtList($path,&$list,&$cat,$type)	{
3012

    
3013
		if (@is_dir($path))	{
3014
			$extList = t3lib_div::get_dirs($path);
3015
			if (is_array($extList))	{
3016
				foreach($extList as $extKey)	{
3017
					if (@is_file($path.$extKey.'/ext_emconf.php'))	{
3018
						$emConf = $this->includeEMCONF($path.$extKey.'/ext_emconf.php', $extKey);
3019
						if (is_array($emConf))	{
3020
							if (is_array($list[$extKey]))	{
3021
								$list[$extKey]=array('doubleInstall'=>$list[$extKey]['doubleInstall']);
3022
							}
3023
							$list[$extKey]['doubleInstall'].= $type;
3024
							$list[$extKey]['type'] = $type;
3025
							$list[$extKey]['EM_CONF'] = $emConf;
3026
							$list[$extKey]['files'] = t3lib_div::getFilesInDir($path.$extKey, '', 0, '', $this->excludeForPackaging);
3027

    
3028
							$this->setCat($cat,$list[$extKey], $extKey);
3029
						}
3030
					}
3031
				}
3032
			}
3033
		}
3034
	}
3035

    
3036
	/**
3037
	 * Fixes an old style ext_emconf.php array by adding constraints if needed and removing deprecated keys
3038
	 *
3039
	 * @param	array		$emConf
3040
	 * @return	array
3041
	 */
3042
	function fixEMCONF($emConf) {
3043
		if(!isset($emConf['constraints']) || !isset($emConf['constraints']['depends']) || !isset($emConf['constraints']['conflicts']) || !isset($emConf['constraints']['suggests'])) {
3044
			if(!isset($emConf['constraints']) || !isset($emConf['constraints']['depends'])) {
3045
				$emConf['constraints']['depends'] = $this->stringToDep($emConf['dependencies']);
3046
				if(strlen($emConf['PHP_version'])) {
3047
					$versionRange = $this->splitVersionRange($emConf['PHP_version']);
3048
					if (version_compare($versionRange[0],'3.0.0','<')) $versionRange[0] = '3.0.0';
3049
					if (version_compare($versionRange[1],'3.0.0','<')) $versionRange[1] = '0.0.0';
3050
					$emConf['constraints']['depends']['php'] = implode('-',$versionRange);
3051
				}
3052
				if(strlen($emConf['TYPO3_version'])) {
3053
					$versionRange = $this->splitVersionRange($emConf['TYPO3_version']);
3054
					if (version_compare($versionRange[0],'3.5.0','<')) $versionRange[0] = '3.5.0';
3055
					if (version_compare($versionRange[1],'3.5.0','<')) $versionRange[1] = '0.0.0';
3056
					$emConf['constraints']['depends']['typo3'] = implode('-',$versionRange);
3057
				}
3058
			}
3059
			if(!isset($emConf['constraints']) || !isset($emConf['constraints']['conflicts'])) {
3060
				$emConf['constraints']['conflicts'] = $this->stringToDep($emConf['conflicts']);
3061
			}
3062
			if(!isset($emConf['constraints']) || !isset($emConf['constraints']['suggests'])) {
3063
				$emConf['constraints']['suggests'] = array();
3064
			}
3065
		} elseif (isset($emConf['constraints']) && isset($emConf['dependencies'])) {
3066
			$emConf['suggests'] = isset($emConf['suggests']) ? $emConf['suggests'] : array();
3067
			$emConf['dependencies'] = $this->depToString($emConf['constraints']);
3068
			$emConf['conflicts'] = $this->depToString($emConf['constraints'], 'conflicts');
3069
		}
3070

    
3071
			// sanity check for version numbers, intentionally only checks php and typo3
3072
		if(isset($emConf['constraints']['depends']) && isset($emConf['constraints']['depends']['php'])) {
3073
			$versionRange = $this->splitVersionRange($emConf['constraints']['depends']['php']);
3074
			if (version_compare($versionRange[0],'3.0.0','<')) $versionRange[0] = '3.0.0';
3075
			if (version_compare($versionRange[1],'3.0.0','<')) $versionRange[1] = '0.0.0';
3076
			$emConf['constraints']['depends']['php'] = implode('-',$versionRange);
3077
		}
3078
		if(isset($emConf['constraints']['depends']) && isset($emConf['constraints']['depends']['typo3'])) {
3079
			$versionRange = $this->splitVersionRange($emConf['constraints']['depends']['typo3']);
3080
			if (version_compare($versionRange[0],'3.5.0','<')) $versionRange[0] = '3.5.0';
3081
			if (version_compare($versionRange[1],'3.5.0','<')) $versionRange[1] = '0.0.0';
3082
			$emConf['constraints']['depends']['typo3'] = implode('-',$versionRange);
3083
		}
3084

    
3085
		unset($emConf['private']);
3086
		unset($emConf['download_password']);
3087
		unset($emConf['TYPO3_version']);
3088
		unset($emConf['PHP_version']);
3089

    
3090
		return $emConf;
3091
	}
3092

    
3093
	/**
3094
	 * Splits a version range into an array.
3095
	 *
3096
	 * If a single version number is given, it is considered a minimum value.
3097
	 * If a dash is found, the numbers left and right are considered as minimum and maximum. Empty values are allowed.
3098
	 *
3099
	 * @param	string		$ver A string with a version range.
3100
	 * @return	array
3101
	 */
3102
	function splitVersionRange($ver)	{
3103
		$versionRange = array();
3104
		if (strstr($ver, '-'))	{
3105
			$versionRange = explode('-', $ver, 2);
3106
		} else {
3107
			$versionRange[0] = $ver;
3108
			$versionRange[1] = '';
3109
		}
3110

    
3111
		if (!$versionRange[0])	{ $versionRange[0] = '0.0.0'; }
3112
		if (!$versionRange[1])	{ $versionRange[1] = '0.0.0'; }
3113

    
3114
		return $versionRange;
3115
	}
3116

    
3117
	/**
3118
	 * Maps remote extensions information into $cat/$list arrays for listing
3119
	 *
3120
	 * @param	boolean		If set the info in the internal extensionsXML array will be unset before returning the result.
3121
	 * @return	array		List array and category index as key 0 / 1 in an array.
3122
	 */
3123
	function prepareImportExtList($unsetProc = false)	{
3124
		$list = array();
3125
		$cat = $this->defaultCategories;
3126
		$filepath = $this->getMirrorURL();
3127

    
3128
		reset($this->xmlhandler->extensionsXML);
3129
		while (list($extKey, $data) = each($this->xmlhandler->extensionsXML)) {
3130
			$GLOBALS['LANG']->csConvObj->convArray($data,'utf-8',$GLOBALS['LANG']->charSet); // is there a better place for conversion?
3131
			$list[$extKey]['type'] = '_';
3132
			$version = array_keys($data['versions']);
3133
			$list[$extKey]['_ICON'] = '<img alt="" src="'.$filepath.$extKey{0}.'/'.$extKey{1}.'/'.$extKey.'_'.end($version).'.gif" />';
3134
			$list[$extKey]['downloadcounter'] = $data['downloadcounter'];
3135

    
3136