1<?php
2/*
3 * e107 website system
4 *
5 * Copyright (C) 2008-2013 e107 Inc (e107.org)
6 * Released under the terms and conditions of the
7 * GNU General Public License (http://www.gnu.org/licenses/gpl.txt)
8 *
9 */
10
11if (!defined('e107_INIT')) { exit; }
12
13/**
14 *
15 * @package     e107
16 * @category	e107_handlers
17 * @author      e107inc
18 *
19 *	Plugin administration handler
20 */
21
22
23e107::coreLan('plugin', true);
24
25
26// new in v2.1.5 - optimized for speed.
27class e_plugin
28{
29
30
31	protected $_data         = array();
32	protected $_ids          = array();
33	protected $_installed    = array();
34	protected $_addons       = array();
35	protected $_plugdir      = null; // the currently loaded plugin
36
37	const CACHETIME  = 120; // 2 hours
38	const CACHETAG   = "Meta_plugin";
39
40
41	protected $_addon_types = array(
42		'e_admin',
43		'e_bb',
44		'e_cron',
45		'e_notify',
46		'e_linkgen',
47		'e_list',
48
49		'e_meta', // @Deprecated
50		'e_emailprint',
51		'e_print', // new v2.2
52		'e_frontpage',
53		'e_latest', /* @deprecated  - see e_dashboard */
54		'e_status', /* @deprecated  - see e_dashboard */
55		'e_menu',
56		'e_search',
57		'e_shortcode',
58		'e_module',
59		'e_event',
60		'e_comment',
61		'e_sql',
62		'e_dashboard', // Admin Front-Page addon.
63	//	'e_userprofile', @deprecated @see e_user
64		'e_header', // loaded in header prior to javascript manager.
65		'e_footer', // Loaded in footer prior to javascript manager.
66	//	'e_userinfo', @deprecated @see e_user
67		'e_tagwords',
68		'e_url', // simple mod-rewrite.
69		'e_mailout',
70		'e_sitelink', // sitelinks generator.
71		'e_tohtml', /* @deprecated  - use e_parse */
72		'e_featurebox',
73		'e_parse',
74		'e_related',
75		'e_rss',
76		'e_upload',
77		'e_user',
78		'e_library', // For third-party libraries are defined by plugins/themes.
79		'e_gsitemap',
80		'e_output', //hook into all pages at the end (after closing </html>)
81	);
82
83	protected $_core_plugins = array(
84		"_blank","admin_menu","banner","blogcalendar_menu",
85		"chatbox_menu",	"clock_menu","comment_menu",
86		"contact", "download", "featurebox", "forum","gallery",
87		"gsitemap","import", "linkwords", "list_new", "log", "login_menu",
88		"metaweblog", "newforumposts_main", "news", "newsfeed",
89		"newsletter","online", "page", "pm","poll",
90		"rss_menu","search_menu","siteinfo", "social", "tagcloud", "tinymce4",
91		"trackback","tree_menu","user"
92	);
93
94
95
96	private $_accepted_categories = array('settings'=>EPL_ADLAN_147, 'users'=>EPL_ADLAN_148, 'content'=>EPL_ADLAN_149,'tools'=> EPL_ADLAN_150, 'manage'=>EPL_ADLAN_151,'misc'=> EPL_ADLAN_152, 'menu'=>EPL_ADLAN_153, 'about'=> EPL_ADLAN_154);
97
98	function __construct()
99	{
100
101		$this->_init();
102
103		if(empty($this->_ids) )
104		{
105		//	e107::getDebug()->log("Running e_plugin::_initIDs()");
106		//	e107::getDebug()->log(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS));
107			$this->_initIDs();
108		}
109
110	}
111
112		/**
113	 * Load specified plugin data.
114	 * @param string $plugdir
115	 * @return e_plugin
116	 */
117	public function load($plugdir)
118	{
119		$this->_plugdir = (string) $plugdir;
120
121		return $this;
122	}
123
124	public function getCategoryList()
125	{
126		return $this->_accepted_categories;
127	}
128
129	public function getDetected()
130	{
131		return array_keys($this->_data);
132	}
133
134	public function getCorePluginList()
135	{
136		return $this->_core_plugins;
137	}
138
139	public function clearCache()
140	{
141		$this->_installed = array();
142		$this->_addons = array();
143		e107::setRegistry('core/e107/addons/e_url');
144
145		$this->_init(true);
146		$this->_initIDs();
147		return $this;
148	}
149
150	public function getInstalledWysiwygEditors()
151	{
152		$result = array();
153
154		foreach(array_keys($this->_installed) as $k)
155		{
156			$pl = new e_plugin();
157			$pl->load($k);
158			$keys = $pl->getKeywords();
159			// check the keywords
160			if (is_array($keys) && in_array('wysiwyg', $keys['word']))
161			{
162				if (in_array('default', $keys['word']))
163				{
164					// add "default" editor to the beginning of the array
165					$result = array_merge(array($k => $pl->getName()), $result);
166				}
167				else
168				{
169					// add all "wysiwyg" editors to the array
170					$result[$k] = $pl->getName();
171				}
172			}
173
174		}
175		return $result;
176	}
177
178	public function getInstalled()
179	{
180		return $this->_installed;
181	}
182
183	public function getId()
184	{
185		if(empty($this->_plugdir))
186		{
187			e107::getDebug()->log("\$this->_plugdir is empty ".__FILE__." ". __CLASS__ ."::".__METHOD__);
188		}
189
190		if(isset($this->_ids[$this->_plugdir]))
191		{
192			return $this->_ids[$this->_plugdir];
193		}
194
195		return false;
196	}
197
198
199	public function getCompat()
200	{
201
202		if(isset($this->_data[$this->_plugdir]['@attributes']['compatibility']))
203		{
204			return $this->_data[$this->_plugdir]['@attributes']['compatibility'];
205		}
206
207		return false;
208	}
209
210	public function getInstallRequired()
211	{
212
213		if(empty($this->_plugdir))
214		{
215			e107::getDebug()->log("\$this->_plugdir is empty ".__FILE__." ". __CLASS__ ."::".__METHOD__);
216		}
217
218		if(isset($this->_data[$this->_plugdir]['@attributes']['installRequired']))
219		{
220			return ($this->_data[$this->_plugdir]['@attributes']['installRequired'] === 'false') ? false : true;
221		}
222
223		return false;
224	}
225
226
227
228	public function getVersion()
229	{
230		if(empty($this->_plugdir))
231		{
232			e107::getDebug()->log("\$this->_plugdir is empty ".__FILE__." ". __CLASS__ ."::".__METHOD__);
233		}
234
235		if(isset($this->_data[$this->_plugdir]['@attributes']['version']))
236		{
237			return $this->_data[$this->_plugdir]['@attributes']['version'];
238		}
239
240		return false;
241	}
242
243
244
245	public function getDate()
246	{
247		if(isset($this->_data[$this->_plugdir]['@attributes']['date']))
248		{
249			return $this->_data[$this->_plugdir]['@attributes']['date'];
250		}
251
252		return false;
253	}
254
255
256	public function getAuthor($type='name')
257	{
258		if(!isset($this->_data[$this->_plugdir]['author']['@attributes'][$type]))
259		{
260			return false;
261		}
262
263		return $this->_data[$this->_plugdir]['author']['@attributes'][$type];
264
265	}
266
267
268
269	public function getCategory()
270	{
271		if(!isset($this->_data[$this->_plugdir]['category']))
272		{
273			return false;
274		}
275
276		return (string) $this->_data[$this->_plugdir]['category'];
277
278	}
279
280	public function getKeywords()
281	{
282		if(!isset($this->_data[$this->_plugdir]['keywords']))
283		{
284			return false;
285		}
286
287		return $this->_data[$this->_plugdir]['keywords'];
288
289	}
290
291
292	public function getDescription()
293	{
294		if(!isset($this->_data[$this->_plugdir]['description']['@value']))
295		{
296			return false;
297		}
298
299		return $this->_data[$this->_plugdir]['description']['@value'];
300
301	}
302
303
304	public function getIcon($size = 16,$opt='')
305	{
306
307
308
309		$link = $this->_data[$this->_plugdir]['adminLinks']['link'][0]['@attributes'];
310
311		$k = array(16 => 'iconSmall', 24 => 'icon', 32 => 'icon', 128=>'icon128');
312		$def = array(16 => E_16_PLUGIN, 24 => E_24_PLUGIN, 32 => E_32_PLUGIN);
313
314		$key = $k[$size];
315
316		if(empty($link[$key]))
317		{
318			return $def[$size];
319		}
320
321		$caption = $this->getName();
322
323		if($opt === 'path')
324		{
325			return e107::getParser()->createConstants(e_PLUGIN_ABS.$this->_plugdir.'/'.$link[$key]);
326		}
327
328		return "<img src='".e_PLUGIN.$this->_plugdir.'/'.$link[$key] ."' alt=\"".$caption."\"  class='icon S".$size."'  />";
329	}
330
331
332
333	public function getAdminCaption()
334	{
335		$att = $this->_data[$this->_plugdir]['adminLinks']['link'][0]['@attributes'];
336
337		if(empty($att['description']))
338		{
339			return false;
340		}
341
342		return str_replace("'", '', e107::getParser()->toHTML($att['description'], FALSE, 'defs, emotes_off'));
343
344	}
345
346
347
348	public function getAdminUrl()
349	{
350		if(!empty($this->_data[$this->_plugdir]['administration']['configFile']))
351		{
352			return e_PLUGIN_ABS.$this->_plugdir.'/'.$this->_data[$this->_plugdir]['administration']['configFile'];
353		}
354
355		return false;
356
357	}
358
359
360	/**
361	 * Check if the current plugin is a legacy plugin which doesn't use plugin.xml
362	 * @return mixed
363	 */
364	public function isLegacy()
365	{
366		if(empty($this->_plugdir))
367		{
368			e107::getDebug()->log("\$this->_plugdir is empty ".__FILE__." ". __CLASS__ ."::".__METHOD__);
369		}
370
371		return $this->_data[$this->_plugdir]['legacy'];
372	}
373
374
375	/**
376	 * Check if the current plugin has a global lan file
377	 * @return mixed
378	 */
379	public function hasLanGlobal()
380	{
381		if(empty($this->_plugdir))
382		{
383			e107::getDebug()->log("\$this->_plugdir is empty ".__FILE__." ". __CLASS__ ."::".__METHOD__);
384			return null;
385		}
386
387		return isset($this->_data[$this->_plugdir]['lan']) ? $this->_data[$this->_plugdir]['lan'] : false;
388	}
389
390
391	function setInstalled($plug,$version)
392	{
393		$this->_installed[$plug] = $version;
394
395		return $this;
396	}
397
398
399
400
401
402	/**
403	 * Check if the currently loaded plugin is installed
404	 * @return mixed
405	 */
406	public function isInstalled()
407	{
408		if(empty($this->_plugdir))
409		{
410			e107::getDebug()->log("\$this->_plugdir is empty ".__FILE__." ". __CLASS__ ."::".__METHOD__);
411		}
412
413		return in_array($this->_plugdir, array_keys($this->_installed));
414	}
415
416
417	/**
418	 * Check if the currently loaded plugin's addon has errors.
419	 * @param string e_xxxx addon
420	 * @return mixed
421	 */
422	public function getAddonErrors($e_xxx)
423	{
424
425		if(substr($e_xxx, -3) === '.sc')
426		{
427			$filename =  $e_xxx;
428			$sc = true;
429		}
430		else
431		{
432			$filename =   $e_xxx.".php";
433			$sc = false;
434		}
435
436		if (is_readable(e_PLUGIN.$this->_plugdir."/".$filename))
437		{
438			$content = file_get_contents(e_PLUGIN.$this->_plugdir."/".$filename);
439		}
440		else
441		{
442			return 2;
443		}
444
445		if(substr($e_xxx, - 4, 4) == '_sql')
446		{
447
448			if(strpos($content,'INSERT INTO')!==false)
449			{
450				return array('type'=> 'error', 'msg'=>"INSERT sql commands are not permitted here. Use a ".$this->_plugdir."_setup.php file instead.");
451			}
452			else
453			{
454				return 0;
455			}
456		}
457
458		// Generic markup check
459		if ($sc === false && !$this->isValidAddonMarkup($content))
460		{
461			return 1;
462		}
463
464
465		if($e_xxx == 'e_meta' && strpos($content,'<script')!==false)
466		{
467			return array('type'=> 'warning', 'msg'=>"Contains script tags. Use e_header.php with the e107::js() function instead.");
468		}
469
470
471		if($e_xxx == 'e_latest' && strpos($content,'<div')!==false)
472		{
473			return array('type'=> 'warning', 'msg'=>"Using deprecated method. See e_latest.php in the forum plugin for an example.");
474		}
475
476		if($e_xxx == 'e_status' && strpos($content,'<div')!==false)
477		{
478			return array('type'=> 'warning', 'msg'=>"Using deprecated method. See e_status.php in the forum plugin for an example.");
479		}
480
481
482		return 0;
483
484
485	}
486
487	public function isValidAddonMarkup($content='')
488    {
489       if ((substr($content, 0, 5) != '<'.'?php'))
490       {
491            return false;
492       }
493
494      if ((substr($content, -2, 2) != '?'.'>') && (strrpos(substr($content, -20, 20), '?'.'>') !== false))
495      {
496			return false;
497      }
498
499
500      return true;
501
502    }
503
504
505	public function getUpgradableList()
506	{
507		$needed = array();
508
509		foreach($this->_installed as $path=>$curVal)
510		{
511
512			$version = $this->load($path)->getVersion();
513
514			if(version_compare($curVal,$version,"<")) // check pref version against file version.
515			{
516			    e107::getDebug()->log($curVal."  vs  ".$version);
517				$needed[$path] = $version;
518			}
519
520		}
521
522		return !empty($needed) ? $needed : false;
523	}
524
525
526	private function _initIDs()
527	{
528		$sql = e107::getDb();
529		$cfg = e107::getConfig();
530
531		$pref = $cfg->get('plug_installed');
532		$detected = $this->getDetected();
533
534		$toRemove = array();
535
536		$save = false;
537		if ($rows = $sql->retrieve("plugin", "*", "plugin_id != 0 ORDER by plugin_path ", true))
538		{
539
540			foreach($rows as $row)
541			{
542
543				$path = $row['plugin_path'];
544
545				if(!empty($detected) && !in_array($path,$detected))
546				{
547					$toRemove[] = (int) $row['plugin_id'];
548					continue;
549				}
550
551
552				$this->_ids[$path] = (int) $row['plugin_id'];
553
554				if(!empty($row['plugin_installflag']) )
555				{
556					$this->_installed[$path] = $row['plugin_version'];
557
558					if(!isset($pref[$path]))
559					{
560						$cfg->setPref('plug_installed/'.$path, $row['plugin_version']);
561						e107::getAdminLog()->addDebug($path)->save("plug_installed pref updated");
562						$save = true;
563					}
564				}
565
566				$this->_addons[$path] = !empty($row['plugin_addons']) ? explode(',',$row['plugin_addons']) : null;// $path;
567			}
568
569			if($save)
570			{
571				$cfg->save(false,true,false);
572			}
573		}
574
575
576		$runUpdate = false;
577
578		if(!empty($toRemove))
579		{
580			$runUpdate = true;
581			$delList = implode(",", $toRemove);
582
583			if($sql->delete('plugin', "plugin_id IN (".$delList.")"))
584			{
585				e107::getAdminLog()->addDebug("Deleted missing plugins with id(s): ".$delList)->save("Plugin Table Updated");
586				// e107::getDebug()->log("Deleted missing plugins with id(s): ".$delList);
587			}
588		}
589
590
591        if(e_PAGE == 'e107_update.php')
592        {
593            return null;
594        }
595
596
597		foreach($detected as $path) // add a missing plugin to the database table.
598		{
599
600			if(!isset($this->_ids[$path]) && !empty($this->_data[$path]['@attributes']))
601			{
602				$this->load($path);
603				$row = $this->getFields();
604
605//var_dump($row);
606				if(!$id = $sql->insert('plugin',$row))
607				{
608					e107::getDebug()->log("Unable to insert plugin data into table".print_a($row,true));
609					e107::getAdminLog()->addDebug("Unable to insert plugin data into table".print_a($row,true))->save("plug_installed pref updated");
610				}
611				else
612				{
613					$this->_ids[$path] = (int) $id;
614					$this->_addons[$path] = !empty($row['plugin_addons']) ? explode(',',$row['plugin_addons']) : null;
615					$runUpdate = true;
616
617					e107::getDebug()->log("Inserting plugin data into table".print_a($row,true));
618					e107::getAdminLog()->addArray($row)->save("Plugin Table Entry Added");
619
620					if($row['plugin_installflag'] == 1)
621					{
622						e107::getConfig()->setPref('plug_installed/'.$path, $row['plugin_version'])->save(false,true,false);
623					}
624
625				}
626
627			}
628
629		}
630
631		if($runUpdate === true) // clearCache
632		{
633			$this->_init(true);
634
635		}
636
637
638	}
639
640	public function getFields($currentStatus = false)
641	{
642		/*if(!isset($this->_data[$this->_plugdir]['@attributes']['name']))
643		{
644			return false;
645		}*/
646
647
648		$ret = array(
649			 'plugin_name'          => $this->getName('db'),
650			 'plugin_version'       => $this->getVersion(),
651			 'plugin_path'          => $this->_plugdir,
652			 'plugin_installflag'   => ($this->getInstallRequired() === true) ? 0 : 1,
653			 'plugin_addons'        => $this->getAddons(),
654			 'plugin_category'      => $this->getCategory()
655		);
656
657		if($currentStatus)
658		{
659			$ret['plugin_installflag'] = (int) $this->isInstalled();
660			$ret['plugin_id'] = $this->getId();
661		}
662
663		return $ret;
664
665	}
666
667
668	/**
669	 *Returns a list of addons available for the currently loaded plugin.
670	 * @return string  (comma separated)
671	 */
672	public function getAddons()
673	{
674
675		$allFiles = isset($this->_data[$this->_plugdir]) ? $this->_data[$this->_plugdir]['files']: array();
676
677		$addons = array();
678
679		foreach($this->_addon_types as $ad)
680		{
681			$file = $ad.".php";
682
683			if(in_array($file,$allFiles))
684			{
685				$addons[] = $ad;
686			}
687
688		}
689
690		foreach($allFiles as $file)
691		{
692
693			if(substr($file, -8) === "_sql.php")
694			{
695				$addons[] = str_replace(".php", '', $file);
696			}
697
698			if(substr($file, -3) === ".bb")
699			{
700				$addons[] = $file;
701			}
702
703
704			if(substr($file, -3) === ".sc")
705			{
706				$addons[] = $file;
707			}
708
709			if(preg_match('/^bb_(.*)\.php$/',$file))
710			{
711				$addons[] = $file;
712			}
713
714		}
715
716		if(!empty($this->_data[$this->_plugdir]['shortcodes']))
717		{
718			foreach($this->_data[$this->_plugdir]['shortcodes'] as $val)
719			{
720				$addons[] = 'sc_'.$val;
721			}
722
723		}
724
725
726
727		return implode(',', $addons);
728
729
730	}
731
732
733
734	private function _init($force=false)
735	{
736
737		$cacheTag = self::CACHETAG;
738
739		if($force === false && $tmp = e107::getCache()->retrieve($cacheTag, self::CACHETIME, true, true))
740		{
741			$this->_data = e107::unserialize($tmp);
742			return true;
743		}
744
745		$dirs = scandir(e_PLUGIN);
746
747		$arr = array();
748
749		foreach($dirs as $plugName)
750		{
751			$ret = null;
752
753			if((htmlentities($plugName) != $plugName) || empty($plugName) || $plugName === '.' || $plugName === '..' || !is_dir(e_PLUGIN.$plugName))
754			{
755				continue;
756			}
757
758			if (file_exists(e_PLUGIN.$plugName.'/plugin.xml'))
759			{
760				$ret = $this->parse_plugin_xml($plugName);
761			}
762			elseif (file_exists(e_PLUGIN.$plugName.'/plugin.php'))
763			{
764				$ret = $this->parse_plugin_php($plugName);
765			}
766
767			if(!empty($ret['@attributes']['name'])) // make sure it's a valid plugin.
768			{
769				$arr[$plugName] = $ret;
770			}
771		}
772
773		if(empty($arr))
774		{
775			return false;
776		}
777
778		$cacheSet = e107::serialize($arr,'json');
779
780		if(empty($cacheSet))
781		{
782			$error = json_last_error_msg();
783			e107::getMessage()->addDebug("Plugin Cache JSON encoding is failing! (".__METHOD__.") Line: ".__LINE__);
784			e107::getMessage()->addDebug("JSON Error: ".$error);
785		}
786
787		e107::getCache()->set($cacheTag,$cacheSet,true,true,true);
788
789		$this->_data = $arr;
790
791		return null;
792	}
793
794
795	public function getMeta()
796	{
797
798		if(isset($this->_data[$this->_plugdir]))
799		{
800			return $this->_data[$this->_plugdir];
801		}
802
803		return false;
804	}
805
806
807	public function getName($mode=null)
808	{
809		if(!empty($this->_data[$this->_plugdir]['@attributes']['lan']))
810		{
811			if($mode === 'db')
812			{
813				return $this->_data[$this->_plugdir]['@attributes']['lan'];
814			}
815			elseif(defined(	$this->_data[$this->_plugdir]['@attributes']['lan']))
816			{
817				return constant($this->_data[$this->_plugdir]['@attributes']['lan']);
818			}
819		}
820
821		if(isset($this->_data[$this->_plugdir]['@attributes']['name']))
822		{
823			return ($mode === 'db') ? $this->_data[$this->_plugdir]['@attributes']['name'] : e107::getParser()->toHTML($this->_data[$this->_plugdir]['@attributes']['name'],FALSE,"defs, emotes_off");
824		}
825
826		return false;
827
828	}
829
830
831	private function parse_plugin_xml($plugName)
832	{
833		// $tp = e107::getParser();
834		//	loadLanFiles($plugName, 'admin');					// Look for LAN files on default paths
835		$xml = e107::getXml();
836		$mes = e107::getMessage();
837
838
839
840
841		//	$xml->setOptArrayTags('extendedField,userclass,menuLink,commentID'); // always arrays for these tags.
842		//	$xml->setOptStringTags('install,uninstall,upgrade');
843	//	if(null === $where) $where = 'plugin.xml';
844
845		$where = 'plugin.xml';
846		$ret = $xml->loadXMLfile(e_PLUGIN.$plugName.'/'.$where, 'advanced');
847
848		if ($ret === FALSE)
849		{
850			$mes->addError("Error reading {$plugName}/plugin.xml");
851			return FALSE;
852		}
853
854
855
856		$ret['folder'] = $plugName; // remove the need for <folder> tag in plugin.xml.
857		$ret['category'] = (isset($ret['category'])) ? $this->checkCategory($ret['category']) : "misc";
858		$ret['files'] = preg_grep('/^([^.])/', scandir(e_PLUGIN.$plugName,SCANDIR_SORT_ASCENDING));
859		$ret['lan'] = $this->_detectLanGlobal($plugName);
860
861
862		$ret['@attributes']['version'] = $this->_fixVersion($ret['@attributes']['version']);
863		$ret['@attributes']['compatibility'] = $this->_fixCompat($ret['@attributes']['compatibility']);
864
865		if(varset($ret['description']))
866		{
867			if (is_array($ret['description']))
868			{
869				if (isset($ret['description']['@attributes']['lan']) && defined($ret['description']['@attributes']['lan']))
870				{
871					// Pick up the language-specific description if it exists.
872					$ret['description']['@value'] = constant($ret['description']['@attributes']['lan']);
873				}
874			}
875			else
876			{
877				$diz = $ret['description'];
878				unset($ret['description']);
879
880				$ret['description']['@value'] = $diz;
881			}
882		}
883
884
885		 // Very useful debug code.to compare plugin.php vs plugin.xml
886		/*
887		 $testplug = 'forum';
888		 if($plugName == $testplug)
889		 {
890		 $plug_vars1 = $ret;
891		 $this->parse_plugin_php($testplug);
892		 $plug_vars2 = $ret;
893		 ksort($plug_vars2);
894		 ksort($plug_vars1);
895		 echo "<table>
896		 <tr><td><h1>PHP</h1></td><td><h1>XML</h1></td></tr>
897		 <tr><td style='border-right:1px solid black'>";
898		 print_a($plug_vars2);
899		 echo "</td><td>";
900		 print_a($plug_vars1);
901		 echo "</table>";
902		 }
903		*/
904
905
906		// TODO search for $ret['adminLinks']['link'][0]['@attributes']['primary']==true.
907		$ret['administration']['icon'] = varset($ret['adminLinks']['link'][0]['@attributes']['icon']);
908		$ret['administration']['caption'] = varset($ret['adminLinks']['link'][0]['@attributes']['description']);
909		$ret['administration']['iconSmall'] = varset($ret['adminLinks']['link'][0]['@attributes']['iconSmall']);
910		$ret['administration']['configFile'] = varset($ret['adminLinks']['link'][0]['@attributes']['url']);
911		$ret['legacy'] = false;
912
913		if (is_dir(e_PLUGIN.$plugName."/shortcodes/single/"))
914		{
915			$ret['shortcodes'] = preg_grep('/^([^.])/', scandir(e_PLUGIN.$plugName,SCANDIR_SORT_ASCENDING));
916		}
917
918
919		return $ret;
920
921	}
922
923
924	/**
925	 * @param $plugName
926	 * @return array
927	 */
928	private function parse_plugin_php($plugName)
929	{
930		$tp = e107::getParser();
931		$sql = e107::getDb(); // in case it is used inside plugin.php
932
933		$PLUGINS_FOLDER = '{e_PLUGIN}'; // Could be used in plugin.php file.
934
935		$eplug_conffile     = null;
936		$eplug_table_names  = null;
937		$eplug_prefs        = null;
938		$eplug_module       = null;
939		$eplug_userclass    = null;
940		$eplug_status       = null;
941		$eplug_latest       = null;
942		$eplug_icon         = null;
943		$eplug_icon_small   = null;
944		$eplug_compatible   = null;
945		$eplug_version      = null;
946
947
948		ob_start();
949		include(e_PLUGIN.$plugName.'/plugin.php');
950		ob_end_clean();
951		$ret = array();
952
953		unset($sql);
954		unset($PLUGINS_FOLDER);
955
956		$ret['@attributes']['name'] = varset($eplug_name);
957		$ret['@attributes']['lan'] = varset($eplug_name);
958		$ret['@attributes']['version'] =  $this->_fixVersion($eplug_version, true);
959		$ret['@attributes']['date'] = varset($eplug_date);
960		$ret['@attributes']['compatibility'] = $this->_fixCompat($eplug_compatible);
961		$ret['@attributes']['installRequired'] = ($eplug_conffile || is_array($eplug_table_names) || is_array($eplug_prefs) || $eplug_module || $eplug_userclass || $eplug_status || $eplug_latest) ? 'true' : '';
962		$ret['@attributes']['xhtmlcompliant'] = vartrue($eplug_compliant) ? 'true' : '';
963		$ret['folder'] = $plugName; // (varset($eplug_folder)) ? $eplug_folder : $plugName;
964
965		$ret['author']['@attributes']['name'] = varset($eplug_author);
966		$ret['author']['@attributes']['url'] = varset($eplug_url);
967		$ret['author']['@attributes']['email'] = varset($eplug_email);
968		$ret['description']['@value'] = varset($eplug_description);
969		$ret['description']['@attributes']['lan'] = varset($eplug_description);
970
971		$ret['category'] = !empty($eplug_category) ? $this->checkCategory($eplug_category) : "misc";
972		$ret['readme'] = !empty($eplug_readme);
973
974		$ret['menuName'] = varset($eplug_menu_name);
975
976
977		if (!empty($eplug_prefs) && is_array($eplug_prefs))
978		{
979			$c = 0;
980			foreach($eplug_prefs as $name => $value)
981			{
982				$ret['mainPrefs']['pref'][$c]['@attributes']['name'] = $name;
983				$ret['mainPrefs']['pref'][$c]['@value'] = $value;
984				$c++;
985			}
986		}
987
988
989
990		// For BC.
991		$ret['administration']['icon'] = $this->_fixPath($eplug_icon,$plugName);
992		$ret['administration']['caption'] = varset($eplug_caption);
993		$ret['administration']['iconSmall'] = $this->_fixPath($eplug_icon_small,$plugName);
994		$ret['administration']['configFile'] = varset($eplug_conffile);
995
996
997
998		if(isset($eplug_conffile))
999		{
1000			$ret['adminLinks']['link'][0]['@attributes']['url'] = varset($eplug_conffile);
1001			$ret['adminLinks']['link'][0]['@attributes']['description'] = LAN_CONFIGURE;
1002			$ret['adminLinks']['link'][0]['@attributes']['icon'] = $this->_fixPath($eplug_icon,$plugName); // str_replace($plugName."/","",$eplug_icon);
1003			$ret['adminLinks']['link'][0]['@attributes']['iconSmall'] = $this->_fixPath($eplug_icon_small,$plugName);
1004			$ret['adminLinks']['link'][0]['@attributes']['primary'] = 'true';
1005		}
1006		if(!empty($eplug_link) && isset($eplug_link_name) && isset($eplug_link_url))
1007		{
1008			$ret['siteLinks']['link'][0]['@attributes']['url'] = $tp->createConstants($eplug_link_url, 1);
1009			$ret['siteLinks']['link'][0]['@attributes']['perm'] = varset($eplug_link_perms);
1010			$ret['siteLinks']['link'][0]['@value'] = varset($eplug_link_name);
1011		}
1012
1013		if(!empty($eplug_userclass) && !empty($eplug_userclass_description))
1014		{
1015			$ret['userClasses']['class'][0]['@attributes']['name'] = $eplug_userclass;
1016			$ret['userClasses']['class'][0]['@attributes']['description'] = $eplug_userclass_description;
1017		}
1018
1019		$ret['files'] = preg_grep('/^([^.])/', scandir(e_PLUGIN.$plugName,SCANDIR_SORT_ASCENDING));
1020		$ret['lan'] = $this->_detectLanGlobal($plugName);
1021		$ret['legacy'] = true;
1022
1023		return $ret;
1024
1025	}
1026
1027	private function _detectLanGlobal($pluginDir)
1028	{
1029		$path_a = e_PLUGIN.$pluginDir."/languages/English_global.php"; // always check for English so we have a fall-back
1030		$path_b = e_PLUGIN.$pluginDir."/languages/English/English_global.php";
1031
1032		if(file_exists($path_a) || file_exists($path_b))
1033		{
1034			return $pluginDir;
1035		}
1036
1037		return false;
1038	}
1039
1040
1041	private function _fixVersion($ver, $legacy=false)
1042	{
1043
1044		if(empty($ver))
1045		{
1046			return null;
1047		}
1048
1049		$ver = str_replace('e107','',$ver);
1050
1051        $regex = ($legacy === true) ? '/([^\d\.ab])/' : '/([^\d\.])/';
1052
1053		return preg_replace($regex,'',$ver); // eg. 2.0.1b okay for BC plugin.
1054
1055
1056	}
1057
1058	private function _fixCompat($ver)
1059	{
1060		$ver = $this->_fixVersion($ver);
1061		$ver = str_replace('0.8','2.0',$ver);
1062		if($ver == 7 || intval($ver) < 1)
1063		{
1064			$ver = "1.0";
1065		}
1066
1067		return $ver;
1068	}
1069
1070
1071	private function _fixPath($path, $plugName)
1072	{
1073		$pathFilter = array(
1074			e_PLUGIN.$plugName.'/',
1075			$plugName."/"
1076
1077		);
1078
1079		return str_replace($pathFilter,'', $path);
1080	}
1081
1082
1083	private function checkCategory($cat)
1084	{
1085		$okayCats = array_keys($this->_accepted_categories);
1086
1087		if (!empty($cat) && in_array($cat, $okayCats))
1088		{
1089			return $cat;
1090		}
1091		else
1092		{
1093			return 'misc';
1094		}
1095	}
1096
1097
1098
1099	public function buildAddonPrefLists()
1100	{
1101		$core = e107::getConfig('core');
1102
1103		$urlsBefore = $core->get('e_url_list', array()); // get URL settings to be restored after.
1104
1105		foreach ($this->_addon_types as $var) // clear all existing prefs.
1106		{
1107			$core->update($var.'_list', "");
1108		}
1109
1110		// reset
1111		$core->set('bbcode_list', array())
1112			 ->set('shortcode_legacy_list', array())
1113			 ->set('shortcode_list', array())
1114			 ->set('lan_global_list', array());
1115
1116		$paths = $this->getDetected();
1117
1118		/**
1119		 * Prevent this method from wiping out the variable that is tracking
1120		 * the currently loaded plugin by moving the currently loaded plugin to
1121		 * the end of the iterated array.
1122		 * @see https://github.com/e107inc/e107/issues/3531
1123		 * @see https://github.com/e107inc/e107-test/issues/9
1124		 */
1125		$paths = array_diff($paths, [$this->_plugdir]);
1126		$paths[] = $this->_plugdir;
1127
1128		foreach($paths as $path)
1129		{
1130
1131			$this->load($path);
1132
1133			$is_installed = $this->isInstalled();
1134			$tmp = explode(",", $this->getAddons());
1135
1136
1137			if ($is_installed)
1138			{
1139				if($hasLAN = $this->hasLanGlobal())
1140				{
1141					$core->setPref('lan_global_list/'.$hasLAN, $hasLAN);
1142				}
1143
1144				foreach ($tmp as $val)
1145				{
1146					if (strpos($val, 'e_') === 0)
1147					{
1148						$core->setPref($val.'_list/'.$path, $path);
1149					}
1150				}
1151			}
1152
1153				// search for .bb and .sc files.
1154			$scl_array = array();
1155			$sc_array = array();
1156			$bb_array = array();
1157		//	$sql_array = array();
1158
1159			foreach ($tmp as $adds)
1160			{
1161				// legacy shortcodes - plugin root *.sc files
1162				if (substr($adds, -3) === ".sc")
1163				{
1164					$sc_name = substr($adds, 0, -3); // remove the .sc
1165					if ($is_installed)
1166					{
1167						$scl_array[$sc_name] = "0"; // default userclass = e_UC_PUBLIC
1168					}
1169					else
1170					{
1171						$scl_array[$sc_name] = e_UC_NOBODY; // register shortcode, but disable it
1172					}
1173				}
1174				// new shortcodes location - shortcodes/single/*.php
1175				elseif (substr($adds, 0, 3) === "sc_")
1176				{
1177					$sc_name = substr(substr($adds, 3), 0, -4); // remove the sc_ and .php
1178
1179					if ($is_installed)
1180					{
1181						$sc_array[$sc_name] = "0"; // default userclass = e_UC_PUBLIC
1182					}
1183					else
1184					{
1185						$sc_array[$sc_name] = e_UC_NOBODY; // register shortcode, but disable it
1186					}
1187				}
1188
1189				if($is_installed)
1190				{
1191					// simple bbcode
1192					if(substr($adds,-3) == ".bb")
1193					{
1194						$bb_name = substr($adds, 0,-3); // remove the .bb
1195                    	$bb_array[$bb_name] = "0"; // default userclass.
1196					}
1197					// bbcode class
1198					elseif(substr($adds, 0, 3) == "bb_" && substr($adds, -4) == ".php")
1199					{
1200						$bb_name = substr($adds, 0,-4); // remove the .php
1201						$bb_name = substr($bb_name, 3);
1202                    	$bb_array[$bb_name] = "0"; // TODO - instance and getPermissions() method
1203					}
1204				}
1205
1206					if ($is_installed && (substr($adds, -4) == "_sql"))
1207					{
1208						$core->setPref('e_sql_list/'.$path, $adds);
1209					}
1210				}
1211
1212				// Build Bbcode list (will be empty if plugin not installed)
1213				if (count($bb_array) > 0)
1214				{
1215					ksort($bb_array);
1216					$core->setPref('bbcode_list/'.$path, $bb_array);
1217				}
1218
1219				// Build shortcode list - do if uninstalled as well
1220				if (count($scl_array) > 0)
1221				{
1222					ksort($scl_array);
1223					$core->setPref('shortcode_legacy_list/'.$path, $scl_array);
1224				}
1225
1226				if (count($sc_array) > 0)
1227				{
1228					ksort($sc_array);
1229					$core->setPref('shortcode_list/'.$path, $sc_array);
1230				}
1231			}
1232
1233		// Restore e_url settings
1234		$urlsAfter = $core->get('e_url_list', array());
1235		foreach($urlsAfter as $k=>$v)
1236		{
1237			if(isset($urlsBefore[$k]))
1238			{
1239				$core->setPref('e_url_list/'.$k, $urlsBefore[$k]);
1240			}
1241		}
1242
1243
1244		$core->save(false, true, false);
1245
1246	}
1247
1248
1249
1250
1251
1252}
1253
1254
1255
1256/**
1257 * @deprecated in part. To eventually be replaced with e_plugin above.
1258 */
1259class e107plugin
1260{
1261	// Reserved Addon names.
1262	var $plugin_addons = array(
1263		'e_admin',
1264		'e_bb',
1265		'e_cron',
1266		'e_notify',
1267		'e_linkgen',
1268		'e_list',
1269
1270		'e_meta', // @Deprecated
1271		'e_emailprint',
1272		'e_print', // new v2.2
1273		'e_frontpage',
1274		'e_latest', /* @deprecated  - see e_dashboard */
1275		'e_status', /* @deprecated  - see e_dashboard */
1276		'e_menu',
1277		'e_search',
1278		'e_shortcode',
1279		'e_module',
1280		'e_event',
1281		'e_comment',
1282		'e_sql',
1283		'e_dashboard', // Admin Front-Page addon.
1284	//	'e_userprofile', @deprecated @see e_user
1285		'e_header', // loaded in header prior to javascript manager.
1286		'e_footer', // Loaded in footer prior to javascript manager.
1287	//	'e_userinfo', @deprecated @see e_user
1288		'e_tagwords',
1289		'e_url', // simple mod-rewrite.
1290		'e_mailout',
1291		'e_sitelink', // sitelinks generator.
1292		'e_tohtml', /* @deprecated  - use e_parse */
1293		'e_featurebox',
1294		'e_parse',
1295		'e_related',
1296		'e_rss',
1297		'e_upload',
1298		'e_user',
1299		'e_library', // For third-party libraries are defined by plugins/themes.
1300		'e_gsitemap',
1301		'e_output', //hook into all pages at the end (after closing </html>)
1302	);
1303
1304
1305	/** Deprecated or non-v2.x standards */
1306	private $plugin_addons_deprecated = array(
1307		'e_bb',     // @deprecated
1308		'e_list',
1309		'e_meta',   // @deprecated
1310		'e_latest', // @deprecated
1311		'e_status', // @deprecated
1312		'e_tagwords',
1313		'e_sql.php',
1314		'e_linkgen',
1315		'e_frontpage',
1316		'e_tohtml', // @deprecated rename to e_parser ?
1317		'e_sql',
1318		'e_emailprint',
1319	);
1320
1321
1322
1323	private $plugin_addons_diz = array(
1324		'e_admin'       => "Add form elements to existing core admin areas.",
1325		'e_cron'        => "Include your plugin's cron in the 'Scheduled Tasks' admin area.",
1326		'e_notify'      => "Include your plugin's notification to the Notify admin area.",
1327		'e_linkgen'     => "Add link generation into the sitelinks area.",
1328		'e_frontpage'   => "Add your plugin as a frontpage option.",
1329		'e_menu'        => "Gives your plugin's menu(s) configuration options in the Menu Manager.",
1330		'e_featurebox'  => "Allow your plugin to generate content for the featurebox plugin.",
1331		'e_search'      => "Add your plugin to the search page.",
1332		'e_shortcode'   => "Add a global shortcode which can be used site-wide. (use sparingly)",
1333		'e_module'      => "Include a file within class2.php (every page of the site).",
1334		'e_event'       => "Hook into core events and process them with custom functions.",
1335		'e_comment'     => "Override the core commenting system.",
1336		'e_dashboard'   => "Add something to the default admin dashboard panel.", // Admin Front-Page addon.
1337		'e_header'      => "Have your plugin include code in the head of every page of the site. eg. css", // loaded in header prior to javascript manager.
1338		'e_footer'      => "Have your plugin include code in the foot of every page of the site. eg. javascript", // Loaded in footer prior to javascript manager.
1339		'e_url'         => "Give your plugin search-engine-friendly URLs", // simple mod-rewrite.
1340		'e_mailout'     => "Allow the mailing engine to use data from your plugin's database tables.",
1341		'e_sitelink'    => "Create dynamic navigation links for your plugin.", // sitelinks generator.
1342		'e_related'     => "Allow your plugin to be included in the 'related' links.",
1343		'e_rss'         => "Give your plugin an rss feed.",
1344		'e_upload'      => "Use data from your plugin in the user upload form.",
1345		'e_user'        => "Have your plugin include data on the user-profile page.",
1346		'e_library'     => "Include a third-party library",
1347		'e_parse'       => "Hook into e107's text/html parser",
1348		'e_output'      => "Hook into all pages at the end (after closing </html>)"
1349	);
1350
1351
1352	var $disAllowed = array(
1353		'theme',
1354		'core'
1355	);
1356
1357
1358	protected $core_plugins = array(
1359		"_blank","admin_menu","banner","blogcalendar_menu",
1360		"chatbox_menu",	"clock_menu","comment_menu",
1361		"contact", "download", "featurebox", "forum","gallery",
1362		"gsitemap","import", "linkwords", "list_new", "log", "login_menu",
1363		"metaweblog", "newforumposts_main", "news", "newsfeed",
1364		"newsletter","online", "page", "pm","poll",
1365		"rss_menu","search_menu","siteinfo", "social", "tagcloud", "tinymce4",
1366		"trackback","tree_menu","user"
1367	);
1368
1369
1370	// List of all plugin variables which need to be checked - install required if one or more set and non-empty
1371	// Deprecated in 0.8 (used in plugin.php only). Probably delete in 0.9
1372	var $all_eplug_install_variables = array(
1373		'eplug_link_url',
1374		'eplug_link',
1375		'eplug_prefs',
1376		'eplug_array_pref',
1377		'eplug_table_names',
1378		//	'eplug_sc',				// Not used in 0.8 (or later 0.7)
1379		'eplug_userclass',
1380		'eplug_module',
1381		//	'eplug_bb',				// Not used in 0.8 (or later 0.7)
1382		'eplug_latest',
1383		'eplug_status',
1384		'eplug_comment_ids',
1385		'eplug_conffile',
1386		'eplug_menu_name'
1387	);
1388
1389	// List of all plugin variables involved in an update (not used ATM, but worth 'documenting')
1390	// Deprecated in 0.8 (used in plugin.php only). Probably delete in 0.9
1391	var $all_eplug_update_variables = array(
1392		'upgrade_alter_tables',
1393		//	'upgrade_add_eplug_sc',				// Not used in 0.8 (or later 0.7)
1394		//	'upgrade_remove_eplug_sc',			// Not used in 0.8 (or later 0.7)
1395		//	'upgrade_add_eplug_bb',				// Not used in 0.8 (or later 0.7)
1396		//	'upgrade_remove_eplug_bb',			// Not used in 0.8 (or later 0.7)
1397		'upgrade_add_prefs',
1398		'upgrade_remove_prefs',
1399		'upgrade_add_array_pref',
1400		'upgrade_remove_array_pref'
1401	);
1402
1403	// List of all 'editable' DB fields ('plugin_id' is an arbitrary reference which is never edited)
1404	var $all_editable_db_fields = array(
1405		'plugin_name', // Name of the plugin - language dependent
1406		'plugin_version', // Version - arbitrary text field
1407		'plugin_path', // Name of the directory off e_PLUGIN - unique
1408		'plugin_installflag', // '0' = not installed, '1' = installed
1409		'plugin_addons', // List of any extras associated with plugin - bbcodes, e_XXX files...
1410		'plugin_category' // Plugin Category: settings, users, content, management, tools, misc, about
1411		);
1412
1413	var $accepted_categories = array('settings', 'users', 'content', 'tools', 'manage', 'misc', 'menu', 'about');
1414
1415	var $plug_vars;
1416	var $current_plug;
1417	var $parsed_plugin  = array();
1418	var $plugFolder;
1419	var $plugConfigFile;
1420	var $unInstallOpts;
1421	var $module = array();
1422	private $options = array();
1423	private $log = array();
1424
1425
1426
1427
1428
1429
1430	function __construct()
1431	{
1432		//$parsed_plugin = array();
1433	}
1434
1435	/**
1436	 * @deprecated to be removed. Use e_plugin instead.
1437	 * Returns an array containing details of all plugins in the plugin table - should normally use e107plugin::update_plugins_table() first to
1438	 * make sure the table is up to date. (Primarily called from plugin manager to get lists of installed and uninstalled plugins.
1439	 * @return array|bool plugin details
1440	 */
1441	private function getall($flag)
1442	{
1443		$sql = e107::getDb();
1444
1445		if($flag === 'all')
1446		{
1447			$qry = "SELECT * FROM #plugin ORDER BY plugin_path ASC";
1448		}
1449		else
1450		{
1451			$qry = "SELECT * FROM #plugin WHERE plugin_installflag = ".(int) $flag." ORDER BY plugin_path ASC";
1452		}
1453
1454		if ($sql->gen($qry))
1455		{
1456			$ret = $sql->db_getList();
1457			return $ret;
1458		}
1459
1460		return false;
1461	}
1462
1463	/**
1464	* Return a list of core plugins.
1465	*/
1466	public function getCorePlugins()
1467	{
1468		return $this->core_plugins;
1469	}
1470
1471	/**
1472	* Return a list of non-core plugins
1473	*/
1474	public function getOtherPlugins()
1475	{
1476		$allplugs = e107::getFile()->get_dirs(e_PLUGIN);
1477
1478		return array_diff($allplugs,$this->core_plugins);
1479	}
1480
1481
1482	/**
1483	 * Returns an array containing details of all plugins in the plugin table - should normally use e107plugin::update_plugins_table() first to
1484	 * make sure the table is up to date. (Primarily called from plugin manager to get lists of installed and uninstalled plugins.
1485	 * @param string $path
1486	 * @return int
1487	 */
1488	private function getId($path)
1489	{
1490		$sql = e107::getDb();
1491
1492		if ($sql->select("plugin", "plugin_id", "plugin_path = '".(string) $path."' LIMIT 1"))
1493		{
1494			$row = $sql->fetch();
1495			return intval($row['plugin_id']);
1496		}
1497
1498		return false;
1499	}
1500
1501	/**
1502	 * Checks all installed plugins and returns an array of those needing an update.
1503	 * @param string $mode  'boolean' for a quick true/false or null for full array returned.
1504	 * @return mixed
1505	 */
1506	public function updateRequired($mode=null)
1507	{
1508	//	$xml 			= e107::getXml();
1509		$mes 			= e107::getMessage();
1510		$needed 		= array();
1511		$log 			= e107::getAdminLog();
1512
1513		if(!$plugVersions = e107::getConfig('core')->get('plug_installed'))
1514		{
1515			return FALSE;
1516		}
1517
1518		$dbv = e107::getObject('db_verify', null, e_HANDLER."db_verify_class.php");
1519		$plg = e107::getPlug();
1520
1521		foreach($plugVersions as $path=>$version)
1522		{
1523
1524			$data = $plg->load($path)->getMeta();
1525
1526			if($plg->isLegacy() === true)
1527			{
1528				continue;
1529			}
1530
1531			if(!in_array($path, $this->core_plugins)) // check non-core plugins for sql file changes.
1532			{
1533				$dbv->errors = array();
1534				$dbv->compare($path);
1535
1536				if($dbv->errors())
1537				{
1538					$mes->addDebug("Plugin Update(s) Required - db structure change [".$path."]");
1539					$needed[$path] = $data;
1540				}
1541			}
1542
1543			$curVal = $version;
1544			$fileVal = $plg->getVersion();
1545
1546			if($ret = $this->execute_function($path, 'upgrade', 'required', array($this, $curVal, $fileVal))) // Check {plugin}_setup.php and run a 'required' method, if true, then update is required.
1547			{
1548				$mes->addDebug("Plugin Update(s) Required in ".$path."_setup.php [".$path."]");
1549
1550				if($mode === 'boolean')
1551				{
1552					return TRUE;
1553				}
1554
1555				$needed[$path] = $data;
1556			}
1557
1558			if(version_compare($curVal,$fileVal,"<")) // check pref version against file version.
1559			{
1560				$mes->addDebug("Plugin Update(s) Required - different version [".$path."]");
1561
1562				if($mode === 'boolean')
1563				{
1564					return TRUE;
1565				}
1566
1567			//	$mes->addDebug("Plugin: <strong>{$path}</strong> requires an update.");
1568
1569			//	$log->flushMessages();
1570				$needed[$path] = $data;
1571			}
1572
1573		}
1574
1575		// Display debug and log to file.
1576		foreach($needed as $path=>$tmp)
1577		{
1578			$log->addDebug("Plugin: <strong>{$path}</strong> requires an update.");
1579		}
1580
1581
1582		if($mode === 'boolean')
1583		{
1584			return count($needed) ? true : FALSE;
1585		}
1586
1587
1588		return count($needed) ? $needed : FALSE;
1589	}
1590
1591
1592
1593	/**
1594	 * Check for new plugins, create entry in plugin table and remove deleted plugins
1595	 * @deprecated by e_plugin::init() some parts might still need to be integrated into the new method.
1596	 *	@param string $mode = install|upgrade|refresh|uninstall - defines the intent of the call
1597	 *
1598	 *	'upgrade' and 'refresh' are very similar in intent, and often take the same actions:
1599	 *		'upgrade' signals a possible change to the installed list of plugins
1600	 *		'refresh' validates the stored data for existing plugins, recreating any that has gone missing
1601	 */
1602	function update_plugins_table($mode = 'upgrade')
1603	{
1604
1605		$sql 	= e107::getDb();
1606		$sql2 	= e107::getDb('sql2');
1607		$tp 	= e107::getParser();
1608		$fl 	= e107::getFile();
1609		$mes 	= e107::getMessage();
1610
1611		$mes->addDebug("Updating plugins Table");
1612
1613		$log = e107::getAdminLog();
1614
1615		global $mySQLprefix, $menu_pref;
1616		$pref = e107::getPref();
1617
1618
1619		$sp = FALSE;
1620
1621		$pluginDBList = array();
1622		if ($sql->select('plugin', "*")) // Read all the plugin DB info into an array to save lots of accesses
1623
1624		{
1625			while ($row = $sql->fetch())
1626			{
1627				$pluginDBList[$row['plugin_path']] = $row;
1628				$pluginDBList[$row['plugin_path']]['status'] = 'read';
1629				//	echo "Found plugin: ".$row['plugin_path']." in DB<br />";
1630				}
1631		}
1632		e107::getDebug()->logTime('Start Scanning Plugin Files');
1633		$plugList = $fl->get_files(e_PLUGIN, "^plugin\.(php|xml)$", "standard", 1);
1634
1635		foreach ($plugList as $num => $val) // Remove Duplicates caused by having both plugin.php AND plugin.xml.
1636		{
1637			$key = basename($val['path']);
1638			$pluginList[$key] = $val;
1639		}
1640
1641		e107::getDebug()->logTime('After Scanning Plugin Files');
1642		$p_installed = e107::getPref('plug_installed', array()); // load preference;
1643		$mes = e107::getMessage();
1644
1645		foreach ($pluginList as $p)
1646		{
1647			$p['path'] = substr(str_replace(e_PLUGIN, "", $p['path']), 0, -1);
1648			$plugin_path = $p['path'];
1649
1650			if (strpos($plugin_path, 'e107_') !== FALSE)
1651			{
1652				$mes->addWarning("Folder error: <i>{$p['path']}</i>.  'e107_' is not permitted within plugin folder names.");
1653				continue;
1654			}
1655
1656			if(in_array($plugin_path, $this->disAllowed))
1657			{
1658				$mes->addWarning("Folder error: <i>{$p['path']}</i> is not permitted as an acceptable folder name.");
1659				continue;
1660			}
1661
1662
1663			$plug['plug_action'] = 'scan'; // Make sure plugin.php knows what we're up to
1664
1665			if (!$this->parse_plugin($p['path']))
1666			{
1667				//parsing of plugin.php/plugin.xml failed.
1668				$mes->addError("Parsing failed - file format error: {$p['path']}");
1669				continue; // Carry on and do any others that are OK
1670			}
1671
1672			$plug_info = $this->plug_vars;
1673			$eplug_addons = $this->getAddons($plugin_path);
1674
1675			//Ensure the plugin path lives in the same folder as is configured in the plugin.php/plugin.xml - no longer relevant.
1676			if ($plugin_path == $plug_info['folder'])
1677			{
1678				if (array_key_exists($plugin_path, $pluginDBList))
1679				{ // Update the addons needed by the plugin
1680					$pluginDBList[$plugin_path]['status'] = 'exists';
1681
1682						// Check for name (lan) changes
1683					if (vartrue($plug_info['@attributes']['lan']) && $pluginDBList[$plugin_path]['plugin_name'] != $plug_info['@attributes']['lan'])
1684					{
1685						// print_a($plug_info);
1686						$pluginDBList[$plugin_path]['status'] = 'update';
1687						$pluginDBList[$plugin_path]['plugin_name'] = $plug_info['@attributes']['lan'];
1688						$this->plugFolder = $plugin_path;
1689						$this->XmlLanguageFiles('upgrade');
1690					}
1691
1692					if ($mode == 'refresh')
1693					{
1694						if ($this->XmlLanguageFileCheck('_log', 'lan_log_list', 'refresh', $pluginDBList[$plugin_path]['plugin_installflag'], FALSE, $plugin_path)) $sp = TRUE;
1695						if ($this->XmlLanguageFileCheck('_global', 'lan_global_list', 'refresh', $pluginDBList[$plugin_path]['plugin_installflag'], TRUE, $plugin_path)) $sp = TRUE;
1696					}
1697
1698					// Check for missing plugin_category in plugin table.
1699					if ($pluginDBList[$plugin_path]['plugin_category'] == '' || $pluginDBList[$plugin_path]['plugin_category'] != $plug_info['category'])
1700					{
1701						// print_a($plug_info);
1702						$pluginDBList[$plugin_path]['status'] = 'update';
1703						$pluginDBList[$plugin_path]['plugin_category'] = (vartrue($plug_info['category'])) ? $plug_info['category'] : "misc";
1704					}
1705
1706					// If plugin not installed, and version number of files changed, update version as well
1707					if (($pluginDBList[$plugin_path]['plugin_installflag'] == 0) && ($pluginDBList[$plugin_path]['plugin_version'] != $plug_info['@attributes']['version']))
1708					{ // Update stored version
1709						$pluginDBList[$plugin_path]['plugin_version'] = $plug_info['@attributes']['version'];
1710						$pluginDBList[$plugin_path]['status'] = 'update';
1711					}
1712					if ($pluginDBList[$plugin_path]['plugin_addons'] != $eplug_addons)
1713					{ // Update stored addons list
1714						$pluginDBList[$plugin_path]['plugin_addons'] = $eplug_addons;
1715						$pluginDBList[$plugin_path]['status'] = 'update';
1716					}
1717
1718					if ($pluginDBList[$plugin_path]['plugin_installflag'] == 0) // Plugin not installed - make sure $pref not set
1719
1720					{
1721						if (isset($p_installed[$plugin_path]))
1722						{
1723							unset($p_installed[$plugin_path]);
1724							$sp = TRUE;
1725						}
1726					}
1727					else
1728					{ // Plugin installed - make sure $pref is set
1729						if (!isset($p_installed[$plugin_path]) || ($p_installed[$plugin_path] != $pluginDBList[$plugin_path]['plugin_version']))
1730						{ // Update prefs array of installed plugins
1731							$p_installed[$plugin_path] = $pluginDBList[$plugin_path]['plugin_version'];
1732							//				  echo "Add: ".$plugin_path."->".$ep_row['plugin_version']."<br />";
1733							$sp = TRUE;
1734						}
1735					}
1736				}
1737				else // New plugin - not in table yet, so add it. If no install needed, mark it as 'installed'
1738				{
1739					if ($plug_info['@attributes']['name'])
1740					{
1741						$pName = vartrue($plug_info['@attributes']['lan']) ? $plug_info['@attributes']['lan'] : $plug_info['@attributes']['name'] ;
1742
1743						$_installed = ($plug_info['@attributes']['installRequired'] == 'true' || $plug_info['@attributes']['installRequired'] == 1 ? 0 : 1);
1744
1745
1746						$pInsert = array(
1747							'plugin_id' 			=> 0,
1748							'plugin_name'			=> $tp->toDB($pName, true),
1749							'plugin_version'		=> $tp->toDB($plug_info['@attributes']['version'], true),
1750							'plugin_path'			=> $tp->toDB($plugin_path, true),
1751							'plugin_installflag'	=> $_installed,
1752							'plugin_addons'			=> $eplug_addons,
1753							'plugin_category'		=> $this->manage_category($plug_info['category'])
1754						);
1755
1756					//		if (e107::getDb()->db_Insert("plugin", "0, '".$tp->toDB($pName, true)."', '".$tp->toDB($plug_info['@attributes']['version'], true)."', '".$tp->toDB($plugin_path, true)."',{$_installed}, '{$eplug_addons}', '".$this->manage_category($plug_info['category'])."' "))
1757							if (e107::getDb()->insert("plugin", $pInsert))
1758							{
1759								$log->addDebug("Added <b>".$tp->toHTML($pName,false,"defs")."</b> to the plugin table.");
1760							}
1761							else
1762							{
1763								$log->addDebug("Failed to add ".$tp->toHTML($pName,false,"defs")." to the plugin table.");
1764							}
1765
1766							$log->flushMessages("Updated Plugins table");
1767						}
1768					}
1769			}
1770		//	else
1771			{ // May be useful that we ignore what will usually be copies/backups of plugins - but don't normally say anything
1772				//						    echo "Plugin copied to wrong directory. Is in: {$plugin_path} Should be: {$plug_info['folder']}<br /><br />";
1773			}
1774
1775			// print_a($plug_info);
1776		}
1777
1778		// Now scan the table, updating the DB where needed
1779		foreach ($pluginDBList as $plug_path => $plug_info)
1780		{
1781			if ($plug_info['status'] == 'read')
1782			{ // In table, not on server - delete it
1783				$sql->delete('plugin', "`plugin_id`={$plug_info['plugin_id']}");
1784				//			echo "Deleted: ".$plug_path."<br />";
1785				}
1786			if ($plug_info['status'] == 'update')
1787			{
1788				$temp = array();
1789				foreach ($this->all_editable_db_fields as $p_f)
1790				{
1791					$temp[] = "`{$p_f}` = '{$plug_info[$p_f]}'";
1792				}
1793				$sql->update('plugin', implode(", ", $temp)."  WHERE `plugin_id`={$plug_info['plugin_id']}");
1794				//			echo "Updated: ".$plug_path."<br />";
1795				}
1796		}
1797		if ($sp/* && vartrue($p_installed)*/)
1798		{
1799			e107::getConfig('core')->setPref('plug_installed', $p_installed);
1800			$this->rebuildUrlConfig();
1801			e107::getConfig('core')->save(true,false,false);
1802		}
1803
1804		// Triggering system (post) event.
1805		e107::getEvent()->trigger('system_plugins_table_updated', array(
1806			'mode' => $mode,
1807		));
1808	}
1809
1810	private function manage_category($cat)
1811	{
1812		$this->log("Running ".__FUNCTION__);
1813		if (vartrue($cat) && in_array($cat, $this->accepted_categories))
1814		{
1815			return $cat;
1816		}
1817		else
1818		{
1819			return 'misc';
1820		}
1821	}
1822
1823	private function manage_icons($plugin = '', $function = '')
1824	{
1825		$this->log("Running ".__FUNCTION__);
1826		if ($plugin == '')
1827		{
1828			return null;
1829		}
1830
1831		$mes = e107::getMessage();
1832		$sql = e107::getDb();
1833		$tp = e107::getParser();
1834		$med = e107::getMedia();
1835
1836		if ($function == 'install' || $function == 'upgrade')
1837		{
1838			$med->importIcons(e_PLUGIN.$plugin);
1839			return null;
1840		}
1841
1842		if ($function == 'uninstall')
1843		{
1844			if (vartrue($this->unInstallOpts['delete_ipool'], FALSE))
1845			{
1846				$status = ($med->removePath(e_PLUGIN.$plugin, 'icon')) ? E_MESSAGE_SUCCESS : E_MESSAGE_ERROR;
1847				$mes->add(IMALAN_164, $status);
1848				$this->log("Deleted Icons from Media-Manager "); // No LANS
1849			}
1850			return null;
1851		}
1852
1853	}
1854
1855	/**
1856	 * Returns details of a plugin from the plugin table from it's ID
1857	 * @deprecated
1858	 * @param int|string $id
1859	 * @return array plugin info
1860	 */
1861	static function getPluginRecord($id)
1862	{
1863
1864		$path = (!is_numeric($id)) ? $id : false;
1865		$id = (int)$id;
1866
1867		if(!empty($path))
1868		{
1869		//	$bla = e107::getPlug()->load($path);
1870			if($tmp = e107::getPlug()->load($path)->getFields(true))
1871			{
1872				return $tmp;
1873			}
1874		}
1875		else // log all deprecated calls made using an integer so they can be removed in future.
1876		{
1877			$dbgArr = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS,3);
1878			unset($dbgArr[0]);
1879			e107::getLog()->addDebug("Deprecated call to getPluginRecord() using integer.".print_a($dbgArr,true));
1880
1881		}
1882
1883		$sql = e107::getDb();
1884		$getinfo_results = array();
1885
1886
1887		$qry = "plugin_id = " . $id;
1888		$qry .= ($path != false) ? " OR plugin_path = '" . $path . "' " : "";
1889
1890		if ($sql->select('plugin', '*', $qry)) {
1891			$getinfo_results[$id] = $sql->fetch();
1892		}
1893
1894		return $getinfo_results[$id];
1895	}
1896
1897	private function setUe()
1898	{
1899		if (!isset($this->module['ue']))
1900		{
1901			include_once(e_HANDLER.'user_extended_class.php');
1902			$this->module['ue'] = new e107_user_extended;
1903		}
1904	}
1905
1906	/**
1907	 * User field name, based on its type
1908	 * @param string $folder plugin folder
1909	 * @param int $type normalized field type
1910	 * @param string $name field name
1911	 * @return string  field name
1912	 */
1913	private function ue_field_name($folder, $type, $name)
1914	{
1915		if($type == EUF_PREFIELD || $type == EUF_CATEGORY)
1916		{
1917			return $name; // no plugin_plugname_ prefix
1918		}
1919		return 'plugin_'.$folder.'_'.$name;
1920	}
1921
1922	/**
1923	 * Normalize type
1924	 * @param array $attrib parsed from XML user field definitions
1925	 * @return integer type ID
1926	 */
1927	private function ue_field_type($attrib)
1928	{
1929		$field_type = $attrib['type'];
1930		$type = defined($field_type) ? constant($field_type) : $field_type;
1931		if(!is_numeric($type))
1932		{
1933			// normalize further
1934			$this->setUe();
1935			$type = $this->module['ue']->typeArray[$type];
1936		}
1937		return $type;
1938	}
1939
1940	/**
1941	 * Type number to type name
1942	 * @param integer $typeId
1943	 * @return string type name
1944	 */
1945	private function ue_field_type_name($typeId)
1946	{
1947		if(is_numeric($typeId))
1948		{
1949			$this->setUe();
1950			return array_search($typeId, $this->module['ue']->typeArray);
1951		}
1952		return $typeId;
1953	}
1954
1955	/**
1956	 * Field attributes ($field_attrib array) as they have to be defined in plugin.xml:
1957	 * name - REQUIRED string
1958	 * text -  (string|constant name) field label
1959	 * type - REQUIRED (constant name) see EUF_* constants in e107_user_extended class
1960	 * regex - regex validation string
1961	 * required - 0-not requried, don't show on signup; 1 - required, show on signup; 2-not required, show on signup
1962	 * allow_hide (0|1) - allow user to hide this field on profile page
1963	 * read, write, applicable - classes, see e_UC_* defines
1964	 * values - comma separated values (if required)
1965	 * default - default value
1966	 * order - (number)
1967	 * parent - (string) category name for this field
1968	 * system - (0|1) - field wont be shown if it's system, NOTE - default value if system is not set is 1!
1969	 *
1970	 * @param string $action - add|remove
1971	 * @param string $field_name normalized field name (see self::ue_field_name())
1972	 * @param array $field_attrib
1973	 * @param string $field_source used for system user fields
1974	 *
1975	 * @return boolean success
1976	 */
1977	private function manage_extended_field($action, $field_name, $field_attrib, $field_source = '')
1978	{
1979		$this->log("Running ".__FUNCTION__);
1980		$mes = e107::getMessage();
1981		$this->setUe();
1982
1983		$type = $this->ue_field_type($field_attrib);
1984		$type_name = $this->ue_field_type_name($type);
1985
1986		$mes->addDebug("Extended Field: ".$action.": ".$field_name." : ".$type_name);
1987
1988		// predefined
1989		if($type == EUF_PREFIELD)
1990		{
1991
1992			$preList = $this->module['ue']->parse_extended_xml(''); // passed value currently not used at all, could be file path in the near future
1993			if($preList && isset($preList[$field_name]))
1994			{
1995				$preField = $preList[$field_name];
1996				if($preField)
1997				{
1998					$field_attrib = array_merge($preField, $field_attrib); // merge
1999					// predefined type - numeric value, constant or as defined in user_extended_class::typeArray
2000					$field_attrib['type'] = $type = $this->ue_field_type($preField); // override type
2001				}
2002				else
2003				{
2004					return false;
2005				}
2006			}
2007
2008		}
2009		// not allowed for categories
2010		elseif($type == EUF_CATEGORY)
2011		{
2012			$field_attrib['parent'] = 0;
2013		}
2014
2015		if ($action == 'add')
2016		{
2017			// system field
2018			if($field_attrib['system'])
2019			{
2020				return $this->module['ue']->user_extended_add_system($field_name, $type, varset($field_attrib['default'], ''), $field_source);
2021			}
2022
2023			// new - add non-system extended field
2024
2025			// classes
2026			$field_attrib['read'] = varset($field_attrib['read'], 'e_UC_MEMBER');
2027			$field_attrib['write'] = varset($field_attrib['read'], 'e_UC_MEMBER');
2028			$field_attrib['applicable'] = varset($field_attrib['applicable'], 'e_UC_MEMBER');
2029
2030			// manage parent
2031			if(vartrue($field_attrib['parent']))
2032			{
2033				foreach ($this->module['ue']->catDefinitions as $key => $value)
2034				{
2035					if($value['user_extended_struct_name'] == $field_attrib['parent'])
2036					{
2037						$field_attrib['parent'] = $key;
2038						break;
2039					}
2040				}
2041				if(!is_numeric($field_attrib['parent'])) $field_attrib['parent'] = 0;
2042			}
2043			else $field_attrib['parent'] = 0;
2044
2045
2046			// manage required (0, 1, 2)
2047			if(!isset($field_attrib['required']))
2048			{
2049				$field_attrib['required'] = 0;
2050			}
2051
2052			// manage params
2053			$field_attrib['parms'] = '';
2054
2055			// validation and parms
2056			$include = varset($field_attrib['include_text']);
2057			$regex = varset($field_attrib['regex']);
2058			$hide = vartrue($field_attrib['allow_hide']) ? 1 : 0;
2059			$failmsg = '';
2060			if($regex || $hide)
2061			{
2062				// failmsg only when required
2063				if($field_attrib['required'] == 1 || $regex)
2064					$failmsg = vartrue($field_attrib['error']) ? $field_attrib['error'] : 'LAN_UE_FAIL_'.strtoupper($field_name);
2065
2066				$field_attrib['parms'] = $include."^,^".$regex."^,^".$failmsg.'^,^'.$hide;
2067			}
2068
2069			//var_dump($field_attrib, $field_name, $type);
2070			$mes->addDebug("Extended Field: ".print_a($field_attrib,true));
2071
2072			$status = $this->module['ue']->user_extended_add(
2073				$field_name,
2074				varset($field_attrib['text'], "LAN_UE_".strtoupper($field_name)),
2075				$type,
2076				$field_attrib['parms'],
2077				varset($field_attrib['values'], ''),
2078				varset($field_attrib['default'], ''),
2079				$field_attrib['required'],
2080				defset($field_attrib['read'], e_UC_MEMBER),
2081				defset($field_attrib['write'], e_UC_MEMBER),
2082				defset($field_attrib['applicable'], e_UC_MEMBER),
2083				varset($field_attrib['order'], ''),
2084				$field_attrib['parent']
2085			);
2086
2087			// db fields handling
2088			if($status && $type == EUF_DB_FIELD)
2089			{
2090				// handle DB, use original non-modified name value
2091				$status = !$this->manage_extended_field_sql('add', $field_attrib['name']); // reverse logic - sql method do a error check
2092			}
2093
2094			// refresh categories - sadly the best way so far... need improvement (inside ue class)
2095			if($status && $type == EUF_CATEGORY)
2096			{
2097				$cats = $this->module['ue']->user_extended_get_categories(false);
2098				foreach ($cats as $cat)
2099				{
2100					$this->module['ue']->catDefinitions[$cat['user_extended_struct_id']] = $cat;
2101				}
2102			}
2103
2104			return $status;
2105		}
2106
2107		if ($action == 'remove')
2108		{
2109			//var_dump($field_attrib, $field_name, $type);
2110			$status = $this->module['ue']->user_extended_remove($field_name, $field_name);
2111			if($status && $type == EUF_DB_FIELD)
2112			{
2113				$status = $this->manage_extended_field_sql('remove', $field_attrib['name']);
2114			}
2115
2116			return $status;
2117		}
2118
2119		return false;
2120	}
2121
2122	private function manage_extended_field_sql($action, $field_name)
2123	{
2124		$this->log("Running ".__FUNCTION__);
2125		$f = e_CORE.'sql/extended_'.preg_replace('/[^\w]/', '', $field_name).'.php'; // quick security, always good idea
2126
2127		if(!is_readable($f)) return false;
2128
2129		// TODO - taken from user_extended Administration, need to be refined :/
2130		// FIXME - use sql parse handler
2131		$error = FALSE;
2132		$count = 0;
2133
2134		$sql = e107::getDb();
2135
2136
2137		if($action == 'add')
2138		{
2139			$sql_data = file_get_contents($f);
2140
2141			$search[0] = "CREATE TABLE ";	$replace[0] = "CREATE TABLE ".MPREFIX;
2142			$search[1] = "INSERT INTO ";	$replace[1] = "INSERT INTO ".MPREFIX;
2143
2144		    preg_match_all("/create(.*?)myisam;/si", $sql_data, $creation);
2145		    foreach($creation[0] as $tab)
2146		    {
2147				$query = str_replace($search,$replace,$tab);
2148		      	if(!$sql->gen($query))
2149		      	{
2150		        	$error = TRUE;
2151				}
2152				$count++;
2153			}
2154
2155		    preg_match_all("/insert(.*?);/si", $sql_data, $inserts);
2156			foreach($inserts[0] as $ins)
2157			{
2158				$qry = str_replace($search,$replace,$ins);
2159				if(!$sql->gen($qry))
2160				{
2161				  	$error = TRUE;
2162				}
2163				$count++;
2164		    }
2165
2166			if(!$count) $error = TRUE;
2167
2168			return $error;
2169		}
2170
2171		//remove
2172		if($action == 'remove')
2173		{
2174			// executed only if the sql file exists!
2175			return $sql->gen("DROP TABLE ".MPREFIX."user_extended_".$field_name) ? true : false;
2176		}
2177	}
2178
2179	private function manage_userclass($action, $class_name, $class_description='')
2180	{
2181		$this->log("Running ".__FUNCTION__);
2182		$e107 = e107::getInstance();
2183		$tp = e107::getParser();
2184		$sql = e107::getDb();
2185		$mes = e107::getMessage();
2186
2187		$mes->addDebug("Userclass: ".$action.": ".$class_name." : ".$class_description);
2188
2189		if (!$e107->user_class->isAdmin())
2190		{
2191			$e107->user_class = new user_class_admin; // We need the extra methods of the admin extension
2192		}
2193
2194		$class_name = strip_tags(strtoupper($class_name));
2195		if ($action == 'add')
2196		{
2197			if ($e107->user_class->ucGetClassIDFromName($class_name) !== FALSE)
2198			{ // Class already exists.
2199				return TRUE; // That's probably OK
2200			}
2201			$i = $e107->user_class->findNewClassID();
2202			if ($i !== FALSE)
2203			{
2204				$tmp = array();
2205				$tmp['userclass_id'] = $i;
2206				$tmp['userclass_name'] = $class_name;
2207				$tmp['userclass_description'] = $class_description;
2208				$tmp['userclass_editclass'] = e_UC_ADMIN;
2209				$tmp['userclass_visibility'] = e_UC_ADMIN;
2210				$tmp['userclass_type'] = UC_TYPE_STD;
2211				$tmp['userclass_parent'] = e_UC_NOBODY;
2212				$tmp['_FIELD_TYPES']['userclass_editclass'] = 'int';
2213				$tmp['_FIELD_TYPES']['userclass_visibility'] = 'int';
2214				$tmp['_FIELD_TYPES']['userclass_id'] = 'int';
2215				$tmp['_FIELD_TYPES']['_DEFAULT'] = 'todb';
2216				return $e107->user_class->add_new_class($tmp);
2217			}
2218			else
2219			{
2220				return NULL;
2221			}
2222		}
2223		if ($action == 'remove')
2224		{
2225			$classID = $e107->user_class->ucGetClassIDFromName($class_name);
2226			if (($classID !== FALSE) && ($e107->user_class->deleteClassAndUsers($classID) === TRUE))
2227			{
2228				return TRUE;
2229			}
2230			else
2231			{
2232				return FALSE;
2233			}
2234		}
2235
2236		return null;
2237	}
2238
2239	private function manage_link($action, $link_url, $link_name, $link_class = 0, $options=array())
2240	{
2241
2242		$sql = e107::getDb();
2243		$tp = e107::getParser();
2244
2245		if (!is_numeric($link_class))
2246		{
2247			$link_class = strtolower($link_class);
2248			$plug_perm['everyone'] = e_UC_PUBLIC;
2249			$plug_perm['guest'] = e_UC_GUEST;
2250			$plug_perm['member'] = e_UC_MEMBER;
2251			$plug_perm['mainadmin'] = e_UC_MAINADMIN;
2252			$plug_perm['admin'] = e_UC_ADMIN;
2253			$plug_perm['nobody'] = e_UC_NOBODY;
2254			$link_class = ($plug_perm[$link_class]) ? intval($plug_perm[$link_class]) : e_UC_PUBLIC;
2255		}
2256
2257
2258		$link_url = $tp->toDB($link_url, true);
2259		$link_name = $tp->toDB($link_name, true);
2260		$path = str_replace("../", "", $link_url); // This should clean up 'non-standard' links
2261		$path = $tp->createConstants($path); // Add in standard {e_XXXX} directory constants if we can
2262
2263		if ($action == 'add')
2264		{
2265			$link_t = $sql->count('links');
2266			if (!$sql->count('links', '(*)', "WHERE link_url = '{$path}' OR link_name = '{$link_name}'"))
2267			{
2268					$linkData = array(
2269						'link_name'			 => $link_name,
2270						'link_url'			 => $path,
2271						'link_description'	 => vartrue($options['link_desription'],''),
2272						'link_button'		 => vartrue($options['link_icon'],''),
2273						'link_category'		 => '1',
2274						'link_order'		 => $link_t + 1,
2275						'link_parent'		 => '0',
2276						'link_open'			 => '0',
2277						'link_class'		 => vartrue($link_class,'0'),
2278						'link_function'		 => vartrue($options['link_function']),
2279						'link_sefurl'		 => vartrue($options['link_sef']),
2280						'link_owner'		 => vartrue($options['link_owner'])
2281					);
2282					return $sql->insert('links', $linkData);
2283			}
2284			else
2285			{
2286				return null;
2287			}
2288		}
2289		if ($action == 'remove')
2290		{
2291			//v2.x
2292			if(vartrue($options['link_owner']) && $sql->select('links', 'link_id', "link_owner = '".$options['link_owner']."'"))
2293			{
2294				return $sql->delete('links', "link_owner = '".$options['link_owner']."' ");
2295			}
2296
2297			// Look up by URL if we can - should be more reliable. Otherwise try looking up by name (as previously)
2298			if (($path && $sql->select('links', 'link_id,link_order', "link_url = '{$path}'")) || $sql->select('links', 'link_id,link_order', "link_name = '{$link_name}'"))
2299			{
2300					$row = $sql->fetch();
2301					$sql->db_Update('links', "link_order = link_order - 1 WHERE link_order > {$row['link_order']}");
2302					return $sql->delete('links', "link_id = {$row['link_id']}");
2303			}
2304		}
2305	}
2306
2307	// DEPRECATED in 0.8 -
2308	// Update prefs array according to $action
2309	// $prefType specifies the storage type - may be 'pref', 'listPref' or 'arrayPref'
2310	/**
2311	 * @deprecated See XmlPrefs(); Left for BC.
2312	 * @param        $action
2313	 * @param        $var
2314	 * @param string $prefType
2315	 * @param string $path
2316	 * @param bool   $unEscape
2317	 * @return null|void
2318	 */
2319	function manage_prefs($action, $var, $prefType = 'pref', $path = '', $unEscape = FALSE)
2320	{
2321		$this->log("Running ".__FUNCTION__);
2322		global $pref;
2323		if (!is_array($var))
2324			return null;
2325		if (($prefType == 'arrayPref') && ($path == ''))
2326			return null;
2327		foreach ($var as $k => $v)
2328		{
2329			if ($unEscape)
2330			{
2331				$v = str_replace(array('\{', '\}'), array('{', '}'), $v);
2332			}
2333			switch ($prefType)
2334			{
2335				case 'pref':
2336					switch ($action)
2337					{
2338						case 'add':
2339							$pref[$k] = $v;
2340							break;
2341
2342						case 'update' :
2343						case 'upgrade' :
2344						case 'refresh':
2345							// Only update if $pref doesn't exist
2346							if (!isset($pref[$k]))
2347								$pref[$k] = $v;
2348							break;
2349
2350						case 'remove':
2351							if (is_numeric($k))
2352							{ // Sometimes arrays specified with value being the name of the key to delete
2353								unset($pref[$var[$k]]);
2354							}
2355							else
2356							{ // This is how the array should be specified - key is the name of the pref
2357								unset($pref[$k]);
2358							}
2359							break;
2360					}
2361					break;
2362				case 'listPref':
2363					$tmp = array();
2364					if (isset($pref[$k]))
2365						$tmp = explode(',', $pref[$k]);
2366					switch ($action)
2367					{
2368						case 'add':
2369						case 'update' :
2370						case 'upgrade' :
2371						case 'refresh':
2372							if (!in_array($v, $tmp))
2373								$tmp[] = $v;
2374							break;
2375						case 'remove':
2376							if (($tkey = array_search($v, $tmp)) !== FALSE)
2377								unset($tmp[$tkey]);
2378							break;
2379					}
2380					$pref[$k] = implode(',', $tmp); // Leaves an empty element if no values - probably acceptable or even preferable
2381					break;
2382				case 'arrayPref':
2383					switch ($action)
2384					{
2385						case 'add':
2386							$pref[$k][$path] = $v;
2387							break;
2388						case 'update' :
2389						case 'upgrade' :
2390						case 'refresh':
2391							if (!isset($pref[$k][$path]))
2392								$pref[$k][$path] = $v;
2393							break;
2394						case 'remove':
2395							if (isset($pref[$k][$path]))
2396								unset($pref[$k][$path]); // Leaves an empty element if no values - probably acceptable or even preferable
2397							break;
2398					}
2399					break;
2400			}
2401		}
2402
2403		e107::getConfig('core')->setPref($pref)->save(true,false,false);
2404
2405		return null;
2406
2407	}
2408
2409	function manage_comments($action, $comment_id)
2410	{
2411		$this->log("Running ".__FUNCTION__);
2412		$sql = e107::getDb();
2413		$tp = e107::getParser();
2414
2415		$tmp = array();
2416		if ($action == 'remove')
2417		{
2418			foreach ($comment_id as $com)
2419			{
2420				$tmp[] = "comment_type='".$tp->toDB($com, true)."'";
2421			}
2422			$qry = implode(" OR ", $tmp);
2423			//			echo $qry."<br />";
2424			return $sql->delete('comments', $qry);
2425		}
2426	}
2427
2428	// Handle table updates - passed an array of actions.
2429	// $var array:
2430	//   For 'add' - its a query to create the table
2431	//	 For 'upgrade' - its a query to modify the table (not called from the plugin.xml handler)
2432	//	 For 'remove' - its a table name
2433	//  'upgrade' and 'remove' operate on all language variants of the same table
2434	function manage_tables($action, $var)
2435	{
2436		$this->log("Running ".__FUNCTION__);
2437		$sql = e107::getDb();
2438		$mes = e107::getMessage();
2439
2440		if (!is_array($var))
2441			return FALSE; // Return if nothing to do
2442		$error = false;
2443		$error_data = array();
2444		switch ($action)
2445		{
2446			case 'add':
2447				foreach ($var as $tab)
2448				{
2449
2450					$tab = str_replace("TYPE=MyISAM","ENGINE=MyISAM",$tab);
2451					$tab = str_replace("IF NOT EXISTS", "", $tab);
2452
2453					if(!preg_match("/MyISAM.*CHARSET ?= ?utf8/i",$tab))
2454					{
2455						$tab = str_replace("MyISAM", "MyISAM DEFAULT CHARSET=utf8", $tab);
2456					}
2457
2458
2459					$mes->addDebug($tab);
2460					if (false === $sql->db_Query($tab))
2461					{
2462						$error = true;
2463						$error_data[] = $tab;
2464					}
2465				}
2466				break;
2467			case 'upgrade':
2468				foreach ($var as $tab)
2469				{
2470					if (false === $sql->db_Query_all($tab))
2471					{
2472						$error = true;
2473						$error_data[] = $tab;
2474					}
2475				}
2476				break;
2477			case 'remove':
2478				foreach ($var as $tab)
2479				{
2480					$qry = 'DROP TABLE '.MPREFIX.$tab;
2481					if (!$sql->db_Query_all($qry))
2482					{
2483						$error = true;
2484						$error_data[] = $tab;
2485					}
2486				}
2487				break;
2488		}
2489		// doesn't exit the loop now, returns true on success
2490		// or error queries (string)
2491		return (!$error ? true : (!empty($$error_data) ? implode('<br />', $error_data) : false));
2492	}
2493
2494	// DEPRECATED for 0.8 xml files - See XmlPrefs();
2495	// Handle prefs from arrays (mostly 0.7 stuff, possibly apart from the special cases)
2496	function manage_plugin_prefs($action, $prefname, $plugin_folder, $varArray = '')
2497	{ // These prefs are 'cumulative' - several plugins may contribute an array element
2498		//	global $pref;
2499		/*
2500		 if ($prefname == 'plug_sc' || $prefname == 'plug_bb')
2501		 {  // Special cases - shortcodes and bbcodes - each plugin may contribute several elements
2502		 foreach($varArray as $code)
2503		 {
2504		 $prefvals[] = "$code:$plugin_folder";
2505		 }
2506		 }
2507		 else
2508		 {
2509		 */
2510		$pref = e107::getPref();
2511
2512		$prefvals[] = $varArray;
2513		//			$prefvals[] = $plugin_folder;
2514		//		}
2515		$curvals = explode(',', $pref[$prefname]);
2516
2517		if ($action == 'add')
2518		{
2519			$newvals = array_merge($curvals, $prefvals);
2520		}
2521		if ($action == 'remove')
2522		{
2523			foreach ($prefvals as $v)
2524			{
2525				if (($i = array_search($v, $curvals)) !== FALSE)
2526				{
2527					unset($curvals[$i]);
2528				}
2529			}
2530			$newvals = $curvals;
2531		}
2532		$newvals = array_unique($newvals);
2533		$pref[$prefname] = implode(',', $newvals);
2534
2535		if (substr($pref[$prefname], 0, 1) == ",")
2536		{
2537			$pref[$prefname] = substr($pref[$prefname], 1);
2538		}
2539
2540		e107::getConfig('core')->setPref($pref);
2541		e107::getConfig('core')->save(true,false,false);
2542
2543	}
2544
2545	function manage_search($action, $eplug_folder)
2546	{
2547		global $sysprefs;
2548		$sql = e107::getDb();
2549
2550		$search_prefs = e107::getConfig('search')->getPref();
2551
2552		//	$search_prefs = $sysprefs -> getArray('search_prefs');
2553		$default = file_exists(e_PLUGIN.$eplug_folder.'/e_search.php') ? TRUE : FALSE;
2554		$comments = file_exists(e_PLUGIN.$eplug_folder.'/search/search_comments.php') ? TRUE : FALSE;
2555		if ($action == 'add')
2556		{
2557			$install_default = $default ? TRUE : FALSE;
2558			$install_comments = $comments ? TRUE : FALSE;
2559		}
2560		else
2561			if ($action == 'remove')
2562			{
2563				$uninstall_default = isset($search_prefs['plug_handlers'][$eplug_folder]) ? TRUE : FALSE;
2564				$uninstall_comments = isset($search_prefs['comments_handlers'][$eplug_folder]) ? TRUE : FALSE;
2565			}
2566			else
2567				if ($action == 'upgrade')
2568				{
2569					if (isset($search_prefs['plug_handlers'][$eplug_folder]))
2570					{
2571						$uninstall_default = $default ? FALSE : TRUE;
2572					}
2573					else
2574					{
2575						$install_default = $default ? TRUE : FALSE;
2576					}
2577					if (isset($search_prefs['comments_handlers'][$eplug_folder]))
2578					{
2579						$uninstall_comments = $comments ? FALSE : TRUE;
2580					}
2581					else
2582					{
2583						$install_comments = $comments ? TRUE : FALSE;
2584					}
2585				}
2586		if (vartrue($install_default))
2587		{
2588			$search_prefs['plug_handlers'][$eplug_folder] = array('class' => 0, 'pre_title' => 1, 'pre_title_alt' => '', 'chars' => 150, 'results' => 10);
2589		}
2590		else
2591			if (vartrue($uninstall_default))
2592			{
2593				unset($search_prefs['plug_handlers'][$eplug_folder]);
2594			}
2595		if (vartrue($install_comments))
2596		{
2597			$comments_type_id = '';
2598			require_once(e_PLUGIN.$eplug_folder.'/search/search_comments.php');
2599			$search_prefs['comments_handlers'][$eplug_folder] = array('id' => $comments_type_id, 'class' => 0, 'dir' => $eplug_folder);
2600		}
2601		else
2602			if (vartrue($uninstall_comments))
2603			{
2604				unset($search_prefs['comments_handlers'][$eplug_folder]);
2605			}
2606
2607	//	e107::getConfig('search')->setPref($search_prefs)->save(true,false,false);
2608
2609	}
2610
2611	function manage_notify($action, $eplug_folder)
2612	{
2613		$this->log("Running ".__FUNCTION__);
2614		$tp = e107::getParser();
2615		//	$notify_prefs = $sysprefs -> get('notify_prefs');
2616		//	$notify_prefs = $eArrayStorage -> ReadArray($notify_prefs);
2617
2618		$notify_prefs = e107::getConfig('notify');
2619		$e_notify = file_exists(e_PLUGIN.$eplug_folder.'/e_notify.php') ? TRUE : FALSE;
2620		if ($action == 'add')
2621		{
2622			$install_notify = $e_notify ? TRUE : FALSE;
2623		}
2624		else
2625			if ($action == 'remove')
2626			{
2627				$uninstall_notify = $notify_prefs->isData('plugins/'.$eplug_folder); //isset($notify_prefs['plugins'][$eplug_folder]) ? TRUE : FALSE;
2628				}
2629			else
2630				if ($action == 'upgrade')
2631				{
2632					if ($notify_prefs->isData('plugins/'.$eplug_folder))
2633					{
2634						$uninstall_notify = $e_notify ? FALSE : TRUE;
2635					}
2636					else
2637					{
2638						$install_notify = $e_notify ? TRUE : FALSE;
2639					}
2640				}
2641
2642		$config_events = array(); // Notice removal
2643		if (vartrue($install_notify))
2644		{
2645			$notify_prefs->setPref('plugins/'.$eplug_folder, 1); //$notify_prefs['plugins'][$eplug_folder] = TRUE;
2646
2647			require_once(e_PLUGIN.$eplug_folder.'/e_notify.php');
2648			foreach ($config_events as $event_id => $event_text)
2649			{
2650				$notify_prefs->setPref('event/'.$event_id.'/class', e_UC_NOBODY)
2651					->setPref('event/'.$event_id.'/email', '');
2652				//$notify_prefs['event'][$event_id] = array('class' => e_UC_NOBODY, 'email' => '');
2653				}
2654		}
2655		else
2656			if (vartrue($uninstall_notify))
2657			{
2658				$notify_prefs->removePref('plugins/'.$eplug_folder);
2659				//unset($notify_prefs['plugins'][$eplug_folder]);
2660				require_once(e_PLUGIN.$eplug_folder.'/e_notify.php');
2661				foreach ($config_events as $event_id => $event_text)
2662				{
2663					$notify_prefs->removePref('event/'.$event_id);
2664					//unset($notify_prefs['event'][$event_id]);
2665					}
2666			}
2667		//$s_prefs = $tp -> toDB($notify_prefs);
2668		//$s_prefs = e107::getArrayStorage()->WriteArray($s_prefs);
2669		//e107::getDb() -> db_Update("core", "e107_value='".$s_prefs."' WHERE e107_name='notify_prefs'");
2670		$notify_prefs->save(false,false,false);
2671	}
2672
2673	/**
2674	 * Rebuild URL configuration values
2675	 * Note - new core system pref values will be set, but not saved
2676	 * e107::getConfig()->save() is required outside after execution of this method
2677	 * @return void
2678	 */
2679	public function rebuildUrlConfig()
2680	{
2681		$this->log("Running ".__FUNCTION__);
2682		$modules = eRouter::adminReadModules(); // get all available locations, non installed plugins will be ignored
2683		$config = eRouter::adminBuildConfig(e107::getPref('url_config'), $modules); // merge with current config
2684		$locations = eRouter::adminBuildLocations($modules); // rebuild locations pref
2685		$aliases = eRouter::adminSyncAliases(e107::getPref('url_aliases'), $config); // rebuild aliases
2686
2687		// set new values, changes should be saved outside this methods
2688	/*	e107::getConfig()
2689			->set('url_aliases', $aliases)
2690			->set('url_config', $config)
2691			->set('url_modules', $modules)
2692			->set('url_locations', $locations);
2693			*/
2694		eRouter::clearCache();
2695	}
2696
2697	function displayArray(&$array, $msg = '')
2698	{
2699		$txt = ($msg ? $msg.'<br />' : '');
2700		foreach ($array as $_k => $_v)
2701		{
2702			$txt .= "{$_k} -> {$_v}<br />";
2703		}
2704		$txt .= '<br />';
2705		return $txt;
2706	}
2707
2708
2709	private function log($message)
2710	{
2711		$this->log[] = $message;
2712	}
2713
2714	public function getLog()
2715	{
2716		$text = $this->log;
2717
2718		$this->log = array();
2719
2720		return $text;
2721
2722	}
2723
2724	/**
2725	 * Install routine for XML file
2726	 * @param mixed $id (the number of the plugin in the DB) or the path to the plugin folder. eg. 'forum'
2727	 * @param string $function install|upgrade|uninstall|refresh (adds things that are missing, but doesn't change any existing settings)
2728	 * @param array $options [optional] an array of possible options - ATM used only for uninstall:
2729	 * 			'delete_userclasses' - to delete userclasses created
2730	 * 			'delete_tables' - to delete DB tables
2731	 * 			'delete_xfields' - to delete extended fields
2732	 * 			'delete_ipool' - to delete icon pool entry
2733	 * 			+ any defined in <pluginname>_setup.php in the uninstall_options() method.
2734	 * @return bool
2735	 */
2736	function install_plugin_xml($id, $function = '', $options = null)
2737	{
2738
2739		$pref = e107::getPref();
2740		$sql = e107::getDb();
2741		$mes = e107::getMessage();
2742	  	$event = e107::getEvent();
2743
2744	  	$this->log("Running Plugin: ".$function);
2745
2746		$error = array(); // Array of error messages
2747		$canContinue = TRUE; // Clear flag if must abort part way through
2748
2749		if(is_array($id)) // plugin info array
2750		{
2751			$plug = $id;
2752			$id = (int) $plug['plugin_id'];
2753		}
2754		elseif(is_numeric($id)) // plugin database id
2755		{
2756			$id = (int) $id;
2757			$plug = e107plugin::getPluginRecord($id); // Get plugin info from DB
2758		}
2759		else // Plugin Path.
2760		{
2761			$id = $this->getId($id);
2762			$plug = e107plugin::getPluginRecord($id); // Get plugin info from DB
2763		}
2764
2765		$this->current_plug = $plug;
2766
2767		$txt = '';
2768		$path = e_PLUGIN.$plug['plugin_path'].'/';
2769
2770		$this->plugFolder = $plug['plugin_path'];
2771
2772
2773
2774		$this->unInstallOpts = $options;
2775
2776		$addons = explode(',', $plug['plugin_addons']);
2777		$sql_list = array();
2778		foreach ($addons as $addon)
2779		{
2780			if (substr($addon, -4) == '_sql')
2781			{
2782				$sql_list[] = $addon.'.php';
2783			}
2784		}
2785
2786		if (!file_exists($path.'plugin.xml') || $function == '')
2787		{
2788			$error[] = EPL_ADLAN_77;
2789			$this->log("Cannot find plugin.xml"); // Do NOT LAN. Debug Only.
2790			$canContinue = false;
2791		}
2792
2793		if ($canContinue && $this->parse_plugin_xml($plug['plugin_path']))
2794		{
2795			$plug_vars = $this->plug_vars;
2796			$this->log("Vars: ".print_r($plug_vars,true));
2797		}
2798		else
2799		{
2800			$error[] = EPL_ADLAN_76;
2801			$this->log("Error in plugin.xml");
2802			$canContinue = FALSE;
2803		}
2804
2805		// Load install language file and set lan_global pref.
2806		$this->XmlLanguageFiles($function, varset($plug_vars['languageFiles']), 'pre'); // First of all, see if there's a language file specific to install
2807
2808		// Next most important, if installing or upgrading, check that any dependencies are met
2809		if($canContinue && ($function != 'uninstall') && isset($plug_vars['dependencies']))
2810		{
2811			$canContinue = $this->XmlDependencies($plug_vars['dependencies']);
2812		}
2813
2814		if ($canContinue === false)
2815		{
2816			$this->log("Cannot Continue. Line:".__LINE__); // Do NOT LAN. Debug Only.
2817			return false;
2818		}
2819
2820		// All the dependencies are OK - can start the install now
2821
2822		// Run custom {plugin}_setup install/upgrade etc. for INSERT, ALTER etc. etc. etc.
2823		$ret = $this->execute_function($plug['plugin_path'], $function, 'pre');
2824		if (!is_bool($ret))
2825		{
2826			$txt .= $ret;
2827		}
2828
2829		// Handle tables
2830		$this->XmlTables($function, $plug, $options);
2831
2832		if (varset($plug_vars['adminLinks']))
2833		{
2834			$this->XmlAdminLinks($function, $plug_vars['adminLinks']);
2835		}
2836
2837		if (!empty($plug_vars['siteLinks']))
2838		{
2839			$this->XmlSiteLinks($function, $plug_vars);
2840		}
2841
2842		if (varset($plug_vars['mainPrefs'])) //Core pref items <mainPrefs>
2843		{
2844			$this->XmlPrefs('core', $function, $plug_vars['mainPrefs']);
2845		}
2846
2847		if (varset($plug_vars['pluginPrefs'])) //Plugin pref items <pluginPrefs>
2848		{
2849			$this->XmlPrefs($plug['plugin_path'], $function, $plug_vars['pluginPrefs']);
2850		}
2851
2852		if (varset($plug_vars['userClasses']))
2853		{
2854			$this->XmlUserClasses($function, $plug_vars['userClasses']);
2855		}
2856
2857		if (varset($plug_vars['extendedFields']))
2858		{
2859			$this->XmlExtendedFields($function, $plug_vars['extendedFields']);
2860		}
2861
2862		if (varset($plug_vars['languageFiles']))
2863		{
2864			$this->XmlLanguageFiles($function, $plug_vars['languageFiles']);
2865		}
2866
2867		if (varset($plug_vars['bbcodes']))
2868		{
2869			$this->XmlBBcodes($function, $plug_vars);
2870		}
2871
2872		if (varset($plug_vars['mediaCategories']))
2873		{
2874			$this->XmlMediaCategories($function, $plug_vars);
2875		}
2876
2877		$this->XmlMenus($this->plugFolder, $function, $plug_vars['files']);
2878
2879
2880		$this->manage_icons($this->plugFolder, $function);
2881
2882		//FIXME
2883		//If any commentIDs are configured, we need to remove all comments on uninstall
2884		if ($function == 'uninstall' && isset($plug_vars['commentID']))
2885		{
2886			$txt .= 'Removing all plugin comments: ('.implode(', ', $plug_vars['commentID']).')<br />';
2887			$commentArray = array();
2888			$this->manage_comments('remove', $commentArray);
2889		}
2890
2891		$this->manage_search($function, $plug_vars['folder']);
2892		$this->manage_notify($function, $plug_vars['folder']);
2893
2894		$eplug_addons = $this->getAddons($plug['plugin_path']);
2895
2896		$p_installed = e107::getPref('plug_installed', array()); // load preference;
2897
2898		if ($function == 'install' || $function == 'upgrade' || $function == 'refresh')
2899		{
2900			$sql->update('plugin', "plugin_installflag = 1, plugin_addons = '{$eplug_addons}', plugin_version = '{$plug_vars['@attributes']['version']}', plugin_category ='".$this->manage_category($plug_vars['category'])."' WHERE plugin_id = ".$id);
2901			$p_installed[$plug['plugin_path']] = $plug_vars['@attributes']['version'];
2902
2903			e107::getConfig('core')->setPref('plug_installed', $p_installed);
2904			//e107::getConfig('core')->save(); - save triggered below
2905		}
2906
2907		if ($function == 'uninstall')
2908		{
2909			$sql->update('plugin', "plugin_installflag = 0, plugin_addons = '{$eplug_addons}', plugin_version = '{$plug_vars['@attributes']['version']}', plugin_category ='".$this->manage_category($plug_vars['category'])."' WHERE plugin_id = ".$id);
2910			unset($p_installed[$plug['plugin_path']]);
2911
2912			e107::getConfig('core')->setPref('plug_installed', $p_installed);
2913
2914
2915			$this->removeCrons($plug_vars);
2916
2917		}
2918
2919
2920
2921
2922		$this->rebuildUrlConfig();
2923
2924		$this->log("Updated 'plug_installed' core pref. ");
2925
2926		e107::getConfig('core')->save(true, false, false);
2927/*
2928		e107::getPlug()->clearCache()->buildAddonPrefLists();
2929
2930		if($function === 'install')
2931		{
2932			e107::getPlug()->setInstalled($plug_vars['folder'],$plug_vars['@attributes']['version']);
2933		}
2934*/
2935
2936	//	e107::getPlug()->setInstalled($plug_vars['folder'],$plug_vars['@attributes']['version'])->buildAddonPrefLists();
2937
2938	//	e107::getPlug()->clearCache()->setInstalled($plug_vars['folder'],$plug_vars['@attributes']['version'])->buildAddonPrefLists();
2939
2940		$this->save_addon_prefs('update'); // to be replaced with buildAddonPrefLists(); once working correctly.
2941
2942		/*	if($function == 'install')
2943		 {
2944		 if(isset($plug_vars['management']['installDone'][0]))
2945		 {
2946		 $mes->add($plug_vars['management']['installDone'][0], E_MESSAGE_SUCCESS);
2947		 }
2948		 }*/
2949
2950		// Run custom {plugin}_setup install/upgrade etc. for INSERT, ALTER etc. etc. etc.
2951		// Call any custom post functions defined in <plugin>_setup.php or the deprecated <management> section
2952		if (!$this->execute_function($plug['plugin_path'], $function, 'post'))
2953		{
2954			if ($function == 'install')
2955			{
2956				$text = EPL_ADLAN_238;
2957
2958				if ($this->plugConfigFile)
2959				{
2960					$text .= "<br /><a class='btn btn-primary' href='".$this->plugConfigFile."'>".LAN_CONFIGURE."</a>";
2961				}
2962
2963				$mes->addSuccess($text);
2964			}
2965
2966		}
2967
2968		$event->trigger('admin_plugin_'.$function, $plug);
2969
2970
2971		return null;
2972
2973	}
2974
2975
2976	private function removeCrons($plug_vars)
2977	{
2978		$this->log("Running ".__METHOD__);
2979
2980		if(!file_exists(e_PLUGIN. $plug_vars['folder']."/e_cron.php"))
2981		{
2982			return false;
2983		}
2984
2985		if(e107::getDb()->delete('cron', 'cron_function LIKE "'. $plug_vars['folder'] . '::%"'))
2986		{
2987			$this->log($plug_vars['folder']." crons removed successfully."); // no LANs.
2988			e107::getMessage()->addDebug($plug_vars['folder']." crons removed successfully."); // No LAN necessary
2989		}
2990
2991		return false;
2992
2993	}
2994
2995	private function XmlMenus($plug, $function, $files)
2996	{
2997		$this->log("Running ".__FUNCTION__);
2998
2999		$menuFiles = array();
3000
3001
3002
3003		foreach($files as $file)
3004		{
3005			if($file === 'e_menu.php')
3006			{
3007				continue;
3008			}
3009
3010			if(substr($file,-9) === '_menu.php')
3011			{
3012				$menuFiles[] = basename($file, '.php');
3013			}
3014
3015
3016		}
3017
3018		$this->log("Scanning for _menu.php files - ". count($menuFiles)." found."); // Debug info, no LAN
3019
3020
3021		if(empty($menuFiles))
3022		{
3023			return false;
3024		}
3025
3026
3027		switch($function)
3028		{
3029			case "install":
3030			case "refresh":
3031
3032				$this->log("Adding menus to menus table."); // NO LANS - debug info!
3033
3034				foreach($menuFiles as $menu)
3035				{
3036					if(!e107::getMenu()->add($plug, $menu))
3037					{
3038						$this->log("Couldn't add ".$menu." to menus table."); // NO LAN
3039					}
3040				}
3041
3042				break;
3043
3044			case "uninstall":
3045
3046				$this->log("Removing menus from menus table."); // No Lan
3047
3048				if(!e107::getMenu()->remove($plug))
3049				{
3050					$this->log("Couldn't remove menus for plugin: ".$plug); // NO LAN
3051				}
3052
3053				break;
3054
3055		}
3056
3057		return null;
3058	}
3059
3060	/**
3061	 * Parse {plugin}_sql.php file and install/upgrade/uninstall tables.
3062	 * @param $function string install|upgrade|uninstall
3063	 * @param $plug - array of plugin data - mostly $plug['plugin_path']
3064	 * @param array $options
3065	 */
3066	function XmlTables($function, $plug, $options = array())
3067	{
3068		$this->log("Running ".__METHOD__);
3069
3070		$sqlFile = e_PLUGIN.$plug['plugin_path'].'/'.str_replace("_menu","", $plug['plugin_path'])."_sql.php";
3071
3072		if(!file_exists($sqlFile)) // No File, so return;
3073		{
3074			$this->log("No SQL File Found at: ".$sqlFile);
3075			return null;
3076		}
3077
3078		if(!is_readable($sqlFile)) // File Can't be read.
3079		{
3080			e107::getMessage()->addError("Can't read SQL definition: ".$sqlFile);
3081			$this->log("Can't read SQL definition: ".$sqlFile);
3082			return null;
3083		}
3084
3085		$dbv = e107::getSingleton('db_verify', e_HANDLER."db_verify_class.php");
3086	//	require_once(e_HANDLER."db_verify_class.php");
3087	//	$dbv = new db_verify;
3088		$sql = e107::getDb();
3089
3090		// Add or Remove Table --------------
3091		if($function == 'install' || $function == 'uninstall')
3092		{
3093			$contents = file_get_contents($sqlFile);
3094
3095			if(empty($contents))
3096			{
3097				e107::getMessage()->addError("Can't read SQL definition: ".$sqlFile);
3098				$this->log("Can't read SQL definition: ".$sqlFile);
3099				return null;
3100			}
3101
3102			$tableData = $dbv->getSqlFileTables($contents);
3103
3104			$query = '';
3105			foreach($tableData['tables'] as $k=>$v)
3106			{
3107				switch($function)
3108				{
3109					case "install":
3110						$query = "CREATE TABLE  `".MPREFIX.$v."` (\n";
3111						$query .= $tableData['data'][$k];
3112						$query .= "\n) ENGINE=". vartrue($tableData['engine'][$k],"InnoDB")." DEFAULT CHARSET=utf8 ";
3113
3114						$txt = EPL_ADLAN_239." <b>{$v}</b> ";
3115						$status = $sql->db_Query($query) ? E_MESSAGE_SUCCESS : E_MESSAGE_ERROR;
3116						break;
3117
3118					case "uninstall":
3119						if (!empty($options['delete_tables']))
3120						{
3121							$query = "DROP TABLE  `".MPREFIX.$v."`; ";
3122							$txt = EPL_ADLAN_240." <b> {$v} </b><br />";
3123							$status = $sql->db_Query_all($query) ? E_MESSAGE_SUCCESS : E_MESSAGE_ERROR;
3124
3125						}
3126						else
3127						{
3128							$status = E_MESSAGE_SUCCESS;
3129							$txt = "Table {$v} left in place.";
3130						}
3131						break;
3132				}
3133
3134
3135
3136				e107::getMessage()->add($txt, $status);
3137				e107::getMessage()->addDebug($query);
3138			}
3139
3140		}
3141
3142		// Upgrade Table --------------
3143		if($function == 'upgrade')
3144		{
3145			$dbv->errors = array();
3146			$dbv->compare($plug['plugin_path']);
3147			if($dbv->errors())
3148			{
3149				$dbv->compileResults();
3150				$dbv->runFix();
3151			}
3152
3153		}
3154
3155
3156
3157	}
3158
3159
3160	/**
3161	 * Check if plugin is being used by another plugin before uninstalling it.
3162	 *
3163	 * @param array $plugin
3164	 *  Plugin name.
3165	 *
3166	 * @return boolean
3167	 *  TRUE if plugin is used, otherwise FALSE.
3168	 */
3169	function isUsedByAnotherPlugin($plugin)
3170	{
3171		$this->log("Running ".__FUNCTION__);
3172		$db = e107::getDb();
3173		$tp = e107::getParser();
3174		$mes = e107::getMessage();
3175		$xml = e107::getXml();
3176
3177		$pluginIsUsed = false;
3178		$enPlugs = array();
3179		$usedBy = array();
3180
3181		// Get list of enabled plugins.
3182		$db->select("plugin", "*", "plugin_id !='' order by plugin_path ASC");
3183		while($row = $db->fetch())
3184		{
3185			if($row['plugin_installflag'] == 1)
3186			{
3187				$enPlugs[] = $row['plugin_path'];
3188			}
3189		}
3190
3191		foreach($enPlugs as $enPlug)
3192		{
3193			if(!file_exists(e_PLUGIN . $enPlug . '/plugin.xml'))
3194			{
3195				continue;
3196			}
3197
3198			$plugInfo = $xml->loadXMLfile(e_PLUGIN . $enPlug . '/plugin.xml', 'advanced');
3199
3200			if($plugInfo === false)
3201			{
3202				continue;
3203			}
3204
3205			if (!isset($plugInfo['dependencies']))
3206			{
3207				continue;
3208			}
3209
3210			// FIXME too many nested foreach, need refactoring.
3211			foreach($plugInfo['dependencies'] as $dt => $da)
3212			{
3213				foreach($da as $dv)
3214				{
3215					if(isset($dv['@attributes']) && isset($dv['@attributes']['name']))
3216					{
3217						switch($dt)
3218						{
3219							case 'plugin':
3220								if ($dv['@attributes']['name'] == $plugin)
3221								{
3222									$usedBy[] = $enPlug;
3223								}
3224								break;
3225						}
3226					}
3227				}
3228			}
3229		}
3230
3231		if(count($usedBy))
3232		{
3233			$pluginIsUsed = true;
3234			$text = '<b>' . LAN_UNINSTALL_FAIL . '</b><br />';
3235			$text .= $tp->lanVars(LAN_PLUGIN_IS_USED, array('x' => $plugin), true) . ' ';
3236			$text .= implode(', ', $usedBy);
3237			$mes->addError($text);
3238		}
3239
3240		return $pluginIsUsed;
3241	}
3242
3243	/**
3244	 * Process XML Tag <dependencies> (deprecated 'depend' which is a brand of adult diapers)
3245	 *
3246	 * @param array $tags
3247	 *  Tags (in <dependencies> tag) from XML file.
3248	 *
3249	 * @return boolean
3250	 */
3251	function XmlDependencies($tags)
3252	{
3253		$this->log("Running ".__METHOD__);
3254		$db = e107::getDb();
3255		$mes = e107::getMessage();
3256
3257		$canContinue = true;
3258		$enabledPlugins = array();
3259		$error = array();
3260
3261		// Get list of enabled plugins.
3262		$db->select("plugin", "*", "plugin_id !='' order by plugin_path ASC");
3263		while($row = $db->fetch())
3264		{
3265			if($row['plugin_installflag'] == 1)
3266			{
3267				$enabledPlugins[$row['plugin_path']] = $row['plugin_version'];
3268			}
3269		}
3270
3271		// FIXME too many nested foreach, need refactoring.
3272		foreach($tags as $dt => $da)
3273		{
3274			foreach($da as $dv)
3275			{
3276				if(isset($dv['@attributes']) && isset($dv['@attributes']['name']))
3277				{
3278					switch($dt)
3279					{
3280						case 'plugin':
3281							if(!isset($enabledPlugins[$dv['@attributes']['name']]))
3282							{ // Plugin not installed
3283								$canContinue = false;
3284								$error[] = EPL_ADLAN_70 . $dv['@attributes']['name'];
3285							}
3286							elseif(isset($dv['@attributes']['min_version']) && (version_compare($dv['@attributes']['min_version'], $enabledPlugins[$dv['@attributes']['name']], '<=') === false))
3287							{
3288								$error[] = EPL_ADLAN_71 . $dv['@attributes']['name'] . EPL_ADLAN_72 . $dv['@attributes']['min_version'];
3289								$canContinue = false;
3290							}
3291							break;
3292						case 'extension':
3293							if(!extension_loaded($dv['@attributes']['name']))
3294							{
3295								$canContinue = false;
3296								$error[] = EPL_ADLAN_73 . $dv['@attributes']['name'];
3297							}
3298							elseif(isset($dv['@attributes']['min_version']) && (version_compare($dv['@attributes']['min_version'], phpversion($dv['@attributes']['name']), '<=') === false))
3299							{
3300								$error[] = EPL_ADLAN_71 . $dv['@attributes']['name'] . EPL_ADLAN_72 . $dv['@attributes']['min_version'];
3301								$canContinue = false;
3302							}
3303							break;
3304						case 'php': // all should be lowercase
3305							if(isset($dv['@attributes']['min_version']) && (version_compare($dv['@attributes']['min_version'], phpversion(), '<=') === false))
3306							{
3307								$error[] = EPL_ADLAN_74 . $dv['@attributes']['min_version'];
3308								$canContinue = false;
3309							}
3310							break;
3311						case 'mysql': // all should be lowercase
3312							if(isset($dv['@attributes']['min_version']) && (version_compare($dv['@attributes']['min_version'], $db->mySqlServerInfo(), '<=') === false)
3313							)
3314							{
3315								$error[] = EPL_ADLAN_75 . $dv['@attributes']['min_version'];
3316								$canContinue = false;
3317							}
3318							break;
3319						default:
3320							// TODO lan
3321							echo "Unknown dependency: {$dt}<br />";
3322					}
3323				}
3324			}
3325		}
3326
3327		if(count($error))
3328		{
3329			$text = '<b>' . LAN_INSTALL_FAIL . '</b><br />' . implode('<br />', $error);
3330			$mes->addError($text);
3331		}
3332
3333		return $canContinue;
3334	}
3335
3336
3337
3338	/**
3339	 *	Look for a language file in the two acceptable places.
3340	 *	If found, update the appropriate pref
3341	 *
3342	 *	@param string $fileEnd - the suffix of the file name (e.g. '_global')
3343	 *	@param string $prefName - the name of the pref to be updated
3344	 *	@param string $when = install|upgrade|refresh|uninstall ('update' also supported as alias for 'upgrade')
3345	 *	@param string $isInstalled - flag indicates whether plugin installed
3346	 *			- if false, any preference is removed.
3347	 *			- if TRUE, any preference is added
3348	 *			- so set TRUE to add value to pref regardless
3349	 *	@param boolean $justPath
3350	 *		- if TRUE, plugin name is written to pref, as a generic string which requires a search to locate the file.
3351	 *		- if FALSE, a precise path within the plugin folder, which includes '--LAN--' strings to substitute for language, is written
3352	 *	@param string $plugin - name of plugin folder. If empty string, $this->plugFolder is used (may not always exist).
3353	 *
3354	 *	@return boolean TRUE if pref changed
3355	 */
3356	public function XmlLanguageFileCheck($fileEnd, $prefName, $when, $isInstalled, $justPath = FALSE, $plugin = '')
3357	{
3358		$core = e107::getConfig('core');
3359		$mes = e107::getMessage();
3360
3361		if (trim($plugin) == '') $plugin = $this->plugFolder;
3362		if (!$plugin) return FALSE;			// No plugin name - error
3363
3364		if (!$isInstalled) $when = 'uninstall';
3365
3366		$updated = false;
3367
3368		$path_a = e_PLUGIN.$plugin.'/languages/English'.$fileEnd.'.php';  // always check for English so we have a fall-back
3369		$path_b = e_PLUGIN.$plugin.'/languages/English/English'.$fileEnd.'.php';
3370		$pathEntry = '';
3371
3372		if (file_exists($path_a))
3373		{
3374			$pathEntry = $justPath ? $plugin : '--LAN--'.$fileEnd.'.php';
3375		}
3376		elseif (file_exists($path_b))
3377		{
3378			$pathEntry = $justPath ? $plugin : '--LAN--/--LAN--'.$fileEnd.'.php';
3379		}
3380
3381		$currentPref = $core->getPref($prefName.'/'.$plugin);
3382		//echo 'Path: '.$plugin.' Pref: '.$prefName.' Current: '.$currentPref.'  New: '.$pathEntry.'<br />';
3383		switch ($when)
3384		{
3385			case 'install':
3386			case 'upgrade':
3387			case 'update' :
3388			case 'refresh':
3389				if ($currentPref != $pathEntry)
3390				{
3391					$mes->addDebug('Adding '.$plugin.' to '.$prefName);
3392					$core->setPref($prefName.'/'.$plugin, $pathEntry);
3393					$updated = true;
3394				}
3395				break;
3396			case 'uninstall':
3397				if ($currentPref)
3398				{
3399					$mes->addDebug('Removing '.$plugin.' from '.$prefName);
3400					$core->removePref($prefName.'/'.$plugin);
3401					$updated = true;
3402				}
3403			break;
3404		}
3405		return $updated;
3406	}
3407
3408
3409
3410	/**
3411	 * Process XML Tag <LanguageFiles> // Tag is DEPRECATED - using _install _log and _global
3412	 * @param string $function install|uninstall|upgrade|refresh- should $when have been used?
3413	 * @param object $tag (not used?)
3414	 * @param string $when = install|upgrade|refresh|uninstall
3415	 * @return null
3416	 */
3417	function XmlLanguageFiles($function, $tag='', $when = '')
3418	{
3419		$this->log("Running ".__FUNCTION__);
3420		$core = e107::getConfig('core');
3421
3422		$updated = false;
3423
3424		$path_a = e_PLUGIN.$this->plugFolder."/languages/English_install.php"; // always check for English so we have a fall-back
3425		$path_b = e_PLUGIN.$this->plugFolder."/languages/English/English_install.php";
3426
3427		if(file_exists($path_a) || file_exists($path_b))
3428		{
3429			e107::lan($this->plugFolder,'install',true);
3430		}
3431
3432		$path_a = e_PLUGIN.$this->plugFolder."/languages/English_global.php"; // always check for English so we have a fall-back
3433		$path_b = e_PLUGIN.$this->plugFolder."/languages/English/English_global.php";
3434
3435		if(file_exists($path_a) || file_exists($path_b))
3436		{
3437			switch ($function)
3438			{
3439				case 'install':
3440				case 'upgrade':
3441				case 'refresh':
3442					e107::getMessage()->addDebug("Adding ".$this->plugFolder." to lan_global_list");
3443					e107::lan($this->plugFolder,'global',true);
3444					$core->setPref('lan_global_list/'.$this->plugFolder, $this->plugFolder);
3445					$updated = true;
3446					break;
3447				case 'uninstall':
3448					$core->removePref('lan_global_list/'.$this->plugFolder);
3449					$update = true;
3450				break;
3451			}
3452		}
3453
3454
3455		$path_a = e_PLUGIN.$this->plugFolder."/languages/English_log.php";  // always check for English so we have a fall-back
3456		$path_b = e_PLUGIN.$this->plugFolder."/languages/English/English_log.php";
3457
3458		if(file_exists($path_a) || file_exists($path_b))
3459		{
3460			switch ($function)
3461			{
3462				case 'install':
3463				case 'upgrade':
3464				case 'refresh':
3465					$core->setPref('lan_log_list/'.$this->plugFolder, $this->plugFolder);
3466					$updated = true;
3467					break;
3468				case 'uninstall':
3469					$core->removePref('lan_log_list/'.$this->plugFolder);
3470					$updated = true;
3471				break;
3472			}
3473		}
3474
3475
3476		if($updated === true)
3477		{
3478			$this->log("Prefs saved");
3479			$core->save(true,false,false);	//FIXME do this quietly without an s-message
3480		}
3481
3482		return null;
3483	}
3484
3485	/**
3486	 * Process XML Tag <siteLinks>
3487	 * @param string $function install|upgrade|refresh|uninstall
3488	 * @param array $array
3489	 * @return null
3490	 */
3491	function XmlSiteLinks($function, $plug_vars)
3492	{
3493		$this->log("Running ".__FUNCTION__);
3494
3495		$mes = e107::getMessage();
3496
3497		if(vartrue($this->options['nolinks']))
3498		{
3499			return null;
3500		}
3501
3502		if($function == 'refresh')
3503		{
3504			$mes->addDebug("Checking Plugin Site-links");
3505			$mes->addDebug(print_a($plug_vars['siteLinks'],true));
3506		}
3507
3508
3509		$array = $plug_vars['siteLinks'];
3510
3511		foreach ($array['link'] as $link)
3512		{
3513			$attrib 	= $link['@attributes'];
3514			$linkName 	= (defset($link['@value'])) ? constant($link['@value']) : vartrue($link['@value'],'');
3515			$remove 	= (varset($attrib['deprecate']) == 'true') ? TRUE : FALSE;
3516			$url 		= vartrue($attrib['url']);
3517			$perm 		= vartrue($attrib['perm'],'everyone');
3518			$sef		= vartrue($attrib['sef']);
3519
3520			$options 	= array(
3521				'link_function'	=>	!empty($attrib['function']) ? $plug_vars['folder'].'::'.$attrib['function'] : null,
3522				'link_owner'	=> 	vartrue($plug_vars['folder']),
3523				'link_sef'		=> $sef,
3524				'link_icon'     => vartrue($attrib['icon']),
3525				'link_description'  => vartrue($attrib['description'])
3526			);
3527
3528			switch ($function)
3529			{
3530				case 'upgrade':
3531				case 'install':
3532				case 'refresh':
3533
3534					if (!$remove) // Add any non-deprecated link
3535					{
3536
3537						if($function == 'refresh')
3538						{
3539							$perm = 'nobody';
3540
3541						}
3542
3543						$result = $this->manage_link('add', $url, $linkName, $perm, $options);
3544						if($result !== NULL)
3545						{
3546							$status = ($result) ? E_MESSAGE_SUCCESS : E_MESSAGE_ERROR;
3547							$mes->add(EPL_ADLAN_233." {$linkName} URL: [{$url}] ".EPL_ADLAN_252." {$perm} ", $status);
3548						}
3549					}
3550
3551					if ($function == 'upgrade' && $remove) //remove inactive links on upgrade
3552					{
3553						$status = ($this->manage_link('remove', $url, $linkName,false, $options)) ? E_MESSAGE_SUCCESS : E_MESSAGE_ERROR;
3554						$mes->add(EPL_ADLAN_234." {$linkName} URL: [{$url}]", $status);
3555					}
3556					break;
3557
3558
3559				case 'uninstall': //remove all links
3560
3561					$status = ($this->manage_link('remove', $url, $linkName, $perm, $options)) ? E_MESSAGE_SUCCESS : E_MESSAGE_ERROR;
3562					$mes->add(EPL_ADLAN_234." {$linkName} URL: [{$url}]", $status);
3563					break;
3564			}
3565		}
3566
3567		return ($status === E_MESSAGE_SUCCESS) ? true : false;
3568	}
3569
3570	/**
3571	 * Process XML Tag <adminLinks>
3572	 * @return null
3573	 */
3574	function XmlAdminLinks($function, $tag)
3575	{
3576		$this->log("Running ".__FUNCTION__);
3577		foreach ($tag['link'] as $link)
3578		{
3579			$attrib = $link['@attributes'];
3580			$url = e_PLUGIN_ABS.$this->plugFolder."/".$attrib['url'];
3581			if (isset($attrib['primary']) && $attrib['primary'] == 'true')
3582			{
3583				$this->plugConfigFile = $url;
3584			}
3585		}
3586
3587		return null;
3588	}
3589
3590
3591
3592
3593	function getPerm($type, $default = 'member')
3594	{
3595
3596		if(empty($type))
3597		{
3598			$type = $default;
3599		}
3600
3601		$plug_perm = array();
3602		$plug_perm['everyone'] 	= e_UC_PUBLIC;
3603		$plug_perm['guest'] 	= e_UC_GUEST;
3604		$plug_perm['member'] 	= e_UC_MEMBER;
3605		$plug_perm['mainadmin'] = e_UC_MAINADMIN;
3606		$plug_perm['admin'] 	= e_UC_ADMIN;
3607		$plug_perm['nobody'] 	= e_UC_NOBODY;
3608
3609		if(isset($plug_perm[$type]))
3610		{
3611			return $plug_perm[$type];
3612		}
3613
3614		return $plug_perm[$default];
3615	}
3616
3617
3618	// Only 1 category per file-type allowed. ie. 1 for images, 1 for files.
3619	function XmlMediaCategories($function, $tag)
3620	{
3621		$this->log("Running ".__FUNCTION__);
3622		$mes = e107::getMessage();
3623	//	print_a($tag);
3624
3625		$folder = $tag['folder'];
3626		$prevType = "";
3627
3628
3629		//print_a($tag);
3630		switch ($function)
3631		{
3632			case 'install':
3633			case 'refresh':
3634				$c = 1;
3635				$i = array('file'=>1, 'image'=>1, 'video'=>1);
3636
3637				foreach($tag['mediaCategories']['category'] as $v)
3638				{
3639					$type = $v['@attributes']['type'];
3640
3641					if(strpos($type, 'image') !== 0 && strpos($type, 'file') !== 0 && strpos($type, 'video') !== 0)
3642					{
3643						continue;
3644					}
3645
3646					if($c == 4)
3647					{
3648						$mes->addDebug(EPL_ADLAN_244);
3649						break;
3650					}
3651
3652				//	$prevType = $type;
3653
3654					$data['owner'] 		= $folder;
3655					$data['image']		= vartrue($v['@attributes']['image']);
3656					$data['category'] 	= $folder."_".$type;
3657
3658					if($i[$type] > 1)
3659					{
3660						$data['category'] 	.= "_".$i[$type];
3661					}
3662
3663					$data['title'] 		= $v['@value'];
3664					$data['sef'] 		= vartrue($v['@attributes']['sef']);
3665				//	$data['type'] = $v['@attributes']['type']; //TODO
3666					$data['class'] 		= $this->getPerm(varset($v['@attributes']['perm']), 'member');
3667
3668					$status = e107::getMedia()->createCategory($data) ? E_MESSAGE_SUCCESS : E_MESSAGE_ERROR;
3669					$message = e107::getParser()->lanVars(EPL_ADLAN_245,$data['category'],true);
3670				//	$message = str_replace('[x]', $data['category'], EPL_ADLAN_245);
3671					$mes->add($message, $status);
3672					e107::getMedia()->import($data['category'],e_PLUGIN.$folder, false,'min-size=20000');
3673					$c++;
3674					$i[$type]++;
3675				}
3676
3677			break;
3678
3679			case 'uninstall': // Probably best to leave well alone
3680				$status = e107::getMedia()->deleteAllCategories($folder)? E_MESSAGE_SUCCESS : E_MESSAGE_ERROR;
3681			//	$message = str_replace('[x]', $folder, EPL_ADLAN_246);
3682				$message = e107::getParser()->lanVars(EPL_ADLAN_246,$folder,true);
3683				$mes->add($message, $status);
3684			break;
3685
3686
3687		}
3688
3689		return null;
3690	}
3691
3692
3693
3694	/**
3695	 * Process XML Tag <bbcodes>
3696	 * @return null
3697	 */
3698	function XmlBBcodes($function, $tag)
3699	{
3700		$this->log("Running ".__FUNCTION__);
3701
3702		switch ($function)
3703		{
3704			case 'install': // Probably best to leave well alone
3705				if(vartrue($tag['bbcodes']['@attributes']['imgResize']))
3706				{
3707					e107::getConfig('core')->setPref('resize_dimensions/'.$this->plugFolder."-bbcode", array('w'=>300,'h'=>300));
3708					$this->log('Adding imageResize for: '.$this->plugFolder);
3709				}
3710			break;
3711
3712			case 'uninstall': // Probably best to leave well alone
3713				if(vartrue($tag['bbcodes']['@attributes']['imgResize']))
3714				{
3715					//e107::getConfig('core')->removePref('resize_dimensions/'.$this->plugFolder);
3716					//e107::getConfig('core')->removePref('e_imageresize/'.$this->plugFolder);
3717					e107::getConfig('core')->removePref('resize_dimensions/'.$this->plugFolder."-bbcode");
3718					$this->log('Removing imageResize for: '.$this->plugFolder."-bbcode");
3719				}
3720
3721			break;
3722		}
3723
3724
3725		return null;
3726
3727	}
3728
3729	/**
3730	 * Process XML Tag <userClasses>
3731	 * @param string $function install|upgrade|refresh|uninstall
3732	 * @param array $array
3733	 * @return null
3734	 */
3735	function XmlUserClasses($function, $array)
3736	{
3737		$mes = e107::getMessage();
3738		$this->log("Running ".__FUNCTION__);
3739
3740		foreach ($array['class'] as $uclass)
3741		{
3742			$attrib = $uclass['@attributes'];
3743			$name = $attrib['name'];
3744			$description = $attrib['description'];
3745			$remove = (varset($attrib['deprecate']) == 'true') ? TRUE : FALSE;
3746
3747			switch ($function)
3748			{
3749				case 'install':
3750				case 'upgrade':
3751				case 'refresh':
3752
3753					if (!$remove) // Add all active userclasses (code checks for already installed)
3754					{
3755						$result = $this->manage_userclass('add', $name, $description);
3756						if($result !== NULL)
3757						{
3758							$status = ($result) ? E_MESSAGE_SUCCESS : E_MESSAGE_ERROR;
3759							$mes->add('Adding Userclass: '.$name, $status);
3760						}
3761					}
3762
3763					if ($function == 'upgrade' && $remove) //If upgrading, removing any inactive userclass
3764
3765					{
3766						$status = $this->manage_userclass('remove', $name, $description) ? E_MESSAGE_SUCCESS : E_MESSAGE_ERROR;
3767						$mes->add('Removing Userclass: '.$name, $status);
3768					}
3769
3770					break;
3771
3772				case 'uninstall': //If uninstalling, remove all userclasses (active or inactive)
3773
3774					if (vartrue($this->unInstallOpts['delete_userclasses'], FALSE))
3775					{
3776						$status = $this->manage_userclass('remove', $name, $description) ? E_MESSAGE_SUCCESS : E_MESSAGE_ERROR;
3777						$mes->add('Removing Userclass: '.$name, $status);
3778					}
3779					else
3780					{
3781						$mes->add('Userclass: '.$name.' left in place', E_MESSAGE_DEBUG);
3782					}
3783
3784					break;
3785			}
3786		}
3787
3788		return null;
3789	}
3790
3791
3792	/**
3793	 * Process XML Tag <extendedFields>
3794	 * @param string $function install|upgrade|refresh|uninstall
3795	 * @param array $array
3796	 * @return null
3797	 */
3798	function XmlExtendedFields($function, $array)
3799	{
3800		$this->log("Running ".__FUNCTION__);
3801		$mes = e107::getMessage();
3802		$this->setUe();
3803
3804		$ret = array();
3805
3806		foreach ($array['field'] as $efield)
3807		{
3808			$attrib = $efield['@attributes'];
3809			$attrib['default'] = varset($attrib['default']);
3810
3811			$type = $this->ue_field_type($attrib);
3812			$name = $this->ue_field_name($this->plugFolder, $type, $attrib['name']);
3813
3814			//$name = 'plugin_'.$this->plugFolder.'_'.$attrib['name'];
3815			$source = 'plugin_'.$this->plugFolder;
3816			$remove = (varset($attrib['deprecate']) == 'true') ? TRUE : FALSE;
3817
3818			if(!isset($attrib['system']))
3819			{
3820				 $attrib['system'] = true; // default true
3821			}
3822			else
3823			{
3824				$attrib['system'] = ($attrib['system'] === 'true') ? true : false;
3825			}
3826
3827			switch ($function)
3828			{
3829				case 'install': // Add all active extended fields
3830				case 'upgrade':
3831
3832					if (!$remove)
3833					{
3834						//$status = $this->manage_extended_field('add', $name, $type, $attrib['default'], $source) ? E_MESSAGE_SUCCESS : E_MESSAGE_ERROR;
3835
3836						$status = $this->manage_extended_field('add', $name, $attrib, $source) ? E_MESSAGE_SUCCESS : E_MESSAGE_ERROR;
3837						$mes->add(EPL_ADLAN_249 .$name.' ... ', $status);
3838					}
3839
3840					if ($function == 'upgrade' && $remove) //If upgrading, removing any inactive extended fields
3841
3842					{
3843						$status = $this->manage_extended_field('remove', $name, $attrib, $source) ? E_MESSAGE_SUCCESS : E_MESSAGE_ERROR;
3844						$mes->add(EPL_ADLAN_250 .$name.' ... ', $status);
3845					}
3846					break;
3847
3848				case 'uninstall': //If uninstalling, remove all extended fields (active or inactive)
3849
3850					if (vartrue($this->unInstallOpts['delete_xfields'], FALSE))
3851					{
3852						$status = ($this->manage_extended_field('remove', $name, $attrib, $source)) ? E_MESSAGE_SUCCESS : E_MESSAGE_ERROR;
3853						$mes->add(EPL_ADLAN_250 .$name.' ... ', $status);
3854					}
3855					else
3856					{
3857						$mes->add(EPL_ADLAN_251 .$name, E_MESSAGE_SUCCESS);
3858					}
3859					break;
3860
3861				case 'test': // phpunit
3862					$ret[] = array('name' => $name, 'attrib' => $attrib, 'source' => $source);
3863				break;
3864			}
3865		}
3866
3867		if(!empty($ret))
3868		{
3869			return $ret;
3870		}
3871
3872		return null;
3873	}
3874
3875
3876	/**
3877	 * Process XML tags <mainPrefs> and <pluginPrefs>
3878	 * @param string $mode 'core' or the folder name of the plugin.
3879	 * @param string $function install|uninstall|upgrade|refresh
3880	 * @param array $prefArray XML array of prefs. eg. mainPref() or pluginPref();
3881	 * @return null
3882	 */
3883	function XmlPrefs($mode = 'core', $function='', $prefArray=array())
3884	{
3885		$this->log("Running ".__FUNCTION__);
3886
3887		$mes = e107::getMessage();
3888
3889		if(empty($prefArray))
3890		{
3891			return null;
3892		}
3893
3894		$config = ($mode === 'core') ? e107::getConfig('core') : e107::getPlugConfig($mode);
3895
3896		foreach ($prefArray['pref'] as $tag)
3897		{
3898			$key = varset($tag['@attributes']['name']);
3899			$value = varset($tag['@value']);
3900
3901		//	$this->log("&nbsp;   Pref:  ".$key." => ".$value);
3902
3903			if(substr($value,0,5) == "e_UC_") // Convert Userclass constants.
3904			{
3905				$value = constant($value);
3906			}
3907			elseif($tmp = e107::unserialize($value)) // check for array data and convert when required. .
3908			{
3909				$value = $tmp;
3910			}
3911
3912			$remove = (varset($tag['@attributes']['deprecate']) == 'true') ? TRUE : FALSE;
3913
3914			if (varset($tag['@attributes']['value']))
3915			{
3916				$mes->addError("Deprecated plugin.xml spec. found. Use the following format: ".htmlentities("<pref name='name'>value</pref>"));
3917			}
3918
3919			switch ($function)
3920			{
3921				case 'install':
3922				case 'upgrade':
3923					$ret = $config->add($key, $value);
3924					if($ret->data_has_changed == TRUE)
3925					{
3926						$mes->addSuccess(EPL_ADLAN_241, $key);
3927					}
3928					break;
3929
3930
3931				case 'refresh':
3932					if ($remove) // remove active='false' prefs.
3933
3934					{
3935						$config->remove($key);
3936						$mes->addSuccess(EPL_ADLAN_242, $key);
3937					}
3938					else
3939					{
3940						$config->update($key, $value);
3941						$mes->addSuccess(EPL_ADLAN_243, $key);
3942					}
3943
3944					break;
3945
3946				case 'uninstall':
3947					$config->remove($key);
3948					$mes->addSuccess(EPL_ADLAN_242, $key);
3949					$this->log("Removing Pref: ".$key);
3950					break;
3951			}
3952		}
3953
3954		if ($mode != "core") // Do only one core pref save during install/uninstall etc.
3955		{
3956			$config->save(true, false, false);
3957		}
3958
3959		return null;
3960	}
3961
3962	/**
3963	 *
3964	 * @param object $path [unused]
3965	 * @param object $what install|uninstall|upgrade
3966	 * @param object $when pre|post
3967	 * @param array $callbackData callback method arguments
3968	 * @return boolean FALSE
3969	 */
3970	function execute_function($path = null, $what = '', $when = '', $callbackData = null)
3971	{
3972		$mes = e107::getMessage();
3973
3974		if($path == null)
3975		{
3976			$path = $this->plugFolder;
3977		}
3978
3979		$class_name = $path."_setup"; // was using $this->pluginFolder;
3980		$method_name = $what."_".$when;
3981
3982
3983			// {PLUGIN}_setup.php should ALWAYS be the name of the file..
3984
3985
3986	//	if (varset($this->plug_vars['@attributes']['setupFile']))
3987	//	{
3988	//		$setup_file = e_PLUGIN.$this->plugFolder.'/'.$this->plug_vars['@attributes']['setupFile'];
3989	//	}
3990	//	else
3991	//	{
3992			$setup_file = e_PLUGIN.$path.'/'.$path.'_setup.php';
3993	//	}
3994
3995
3996
3997		if(!is_readable($setup_file) && substr($path,-5) == "_menu")
3998		{
3999			$setup_file = e_PLUGIN.$path.'/'.str_replace("_menu","",$path).'_setup.php';
4000		}
4001
4002		if(deftrue('E107_DBG_INCLUDES'))
4003		{
4004			e107::getMessage()->addDebug("Checking for SetUp File: ".$setup_file);
4005		}
4006
4007		if (is_readable($setup_file))
4008		{
4009			if(e_PAGE == 'e107_update.php' && E107_DBG_INCLUDES)
4010			{
4011				$mes->addDebug("Found setup file <b>".$path."_setup.php</b> ");
4012			}
4013
4014			include_once($setup_file);
4015
4016
4017			if (class_exists($class_name))
4018			{
4019				$obj = new $class_name;
4020				$obj->version_from = $this;
4021
4022				if (method_exists($obj, $method_name))
4023				{
4024					if(e_PAGE == 'e107_update.php' && E107_DBG_INCLUDES)
4025					{
4026						$mes->addDebug("Executing setup function <b>".$class_name." :: ".$method_name."()</b>");
4027					}
4028					if(null !== $callbackData) return call_user_func_array(array($obj, $method_name), $callbackData);
4029					return call_user_func(array($obj, $method_name), $this);
4030				}
4031				else
4032				{
4033					if(e_PAGE == 'e107_update.php' && E107_DBG_INCLUDES)
4034					{
4035						$mes->addDebug("Setup function ".$class_name." :: ".$method_name."() NOT found.");
4036					}
4037					return FALSE;
4038				}
4039			}
4040			else
4041			{
4042			//	$mes->add("Setup Class ".$class_name." NOT found.", E_MESSAGE_DEBUG);
4043				return FALSE;
4044			}
4045		}
4046		else
4047		{
4048			//$mes->add("Optional Setup File NOT Found ".$path."_setup.php ", E_MESSAGE_DEBUG);
4049		}
4050
4051		return FALSE; // IMPORTANT.
4052	}
4053
4054/* @deprecated
4055	// @deprecated - See XMLPrefs();
4056	function parse_prefs($pref_array, $mode = 'simple')
4057	{
4058		$ret = array();
4059		if (!isset($pref_array[0]))
4060		{
4061			$pref_array = array($pref_array);
4062		}
4063		if (is_array($pref_array))
4064		{
4065			foreach ($pref_array as $k => $p)
4066			{
4067				$attrib = $p['@attributes'];
4068				if (isset($attrib['type']) && $attrib['type'] == 'array')
4069				{
4070					$name = $attrib['name'];
4071					$tmp = $this->parse_prefs($pref_array[$k]['key']);
4072					$ret['all'][$name] = $tmp['all'];
4073					$ret['active'][$name] = $tmp['active'];
4074					$ret['inactive'][$name] = $tmp['inactive'];
4075				}
4076				else
4077				{
4078					$ret['all'][$attrib['name']] = $attrib['value'];
4079					if (!isset($attrib['active']) || $attrib['active'] == 'true')
4080					{
4081						$ret['active'][$attrib['name']] = $attrib['value'];
4082					}
4083					else
4084					{
4085						$ret['inactive'][$attrib['name']] = $attrib['value'];
4086					}
4087				}
4088			}
4089		}
4090		return $ret;
4091	}
4092
4093*/
4094
4095	function install_plugin_php($id)
4096	{
4097		$function = 'install';
4098		$sql = e107::getDb();
4099		$mes = e107::getMessage();
4100		$mySQLprefix = MPREFIX; // Fix for some plugin.php files.
4101
4102		$this->log("Running Legacy Plugin: ".$function);
4103
4104		if(is_array($id))
4105		{
4106			$plug = $id;
4107			$id = $plug['plugin_id'];
4108		}
4109		else
4110		{
4111			$plug = e107plugin::getPluginRecord($id);
4112		}
4113
4114		$_path = e_PLUGIN.$plug['plugin_path'].'/';
4115
4116		$plug['plug_action'] = 'install';
4117
4118		$this->parse_plugin_php($plug['plugin_path']);
4119		$plug_vars = $this->plug_vars;
4120
4121		$eplug_folder = '';
4122		$text = '';
4123
4124		include($_path.'plugin.php');
4125
4126		$func = $eplug_folder.'_install';
4127		if (function_exists($func))
4128		{
4129			$text .= call_user_func($func);
4130		}
4131
4132		if(!empty($eplug_tables) && is_array($eplug_tables))
4133		{
4134			$result = $this->manage_tables('add', $eplug_tables);
4135			if ($result === true)
4136			{
4137				$text .= EPL_ADLAN_19.'<br />';
4138				$this->log("Tables added");
4139				$mes->addSuccess(EPL_ADLAN_19);
4140			}
4141			else
4142			{
4143				$this->log("Unable to create tables for this plugin."); // NO LANS - debug info!
4144				$mes->addError(EPL_ADLAN_18);
4145
4146			}
4147		}
4148
4149		/*		if (is_array($eplug_prefs))
4150		 {
4151		 $this->manage_prefs('add', $eplug_prefs);
4152		 $text .= EPL_ADLAN_8.'<br />';
4153		 }*/
4154
4155		if (varset($plug_vars['mainPrefs'])) //Core pref items <mainPrefs>
4156		{
4157			$this->XmlPrefs('core', $function, $plug_vars['mainPrefs']);
4158			$this->log("Prefs added");
4159			//$text .= EPL_ADLAN_8.'<br />';
4160		}
4161
4162		if (!empty($eplug_array_pref) && is_array($eplug_array_pref))
4163		{
4164			foreach ($eplug_array_pref as $key => $val)
4165			{
4166				$this->manage_plugin_prefs('add', $key, $eplug_folder, $val);
4167			}
4168			$this->log("Adding Prefs: ". print_r($eplug_array_pref, true));
4169		}
4170
4171		if (varset($plug_vars['siteLinks']))
4172		{
4173			$this->XmlSiteLinks($function, $plug_vars);
4174		}
4175
4176		if (varset($plug_vars['userClasses']))
4177		{
4178			$this->XmlUserClasses($function, $plug_vars['userClasses']);
4179		}
4180
4181		$this->manage_search('add', $eplug_folder);
4182
4183		$this->manage_notify('add', $eplug_folder);
4184
4185		$this->XmlMenus($plug_vars['folder'], $function, $plug_vars['files']);
4186
4187		$eplug_addons = $this->getAddons($eplug_folder);
4188
4189		$sql->update('plugin', "plugin_installflag = 1, plugin_addons = '{$eplug_addons}' WHERE plugin_id = ".(int) $id);
4190
4191		$p_installed = e107::getPref('plug_installed', array()); // load preference;
4192		$p_installed[$plug['plugin_path']] = $plug['plugin_version'];
4193
4194		e107::getConfig('core')->setPref('plug_installed', $p_installed);
4195
4196		$this->rebuildUrlConfig();
4197
4198		e107::getConfig('core')->save();
4199
4200		$this->save_addon_prefs('update');
4201
4202		$text .= (isset($eplug_done) ? "<br />{$eplug_done}" : "<br />".LAN_INSTALL_SUCCESSFUL);
4203
4204		if (!empty($eplug_conffile))
4205		{
4206			$text .= "<br /><a class='btn btn-primary' href='".e_PLUGIN.$eplug_folder."/".$eplug_conffile."'>".LAN_CONFIGURE."</a>";
4207		}
4208
4209		// Event triggering after plugin installation.
4210		$event = e107::getEvent();
4211		$event->trigger('admin_plugin_install', $plug);
4212
4213		return $text;
4214	}
4215
4216	/**
4217	 * BC Alias for install();
4218	 */
4219	public function install_plugin($id)
4220	{
4221		global $sysprefs, $mySQLprefix;
4222		return $this->install($id);
4223
4224	}
4225
4226	/**
4227	 * Refresh Plugin Info, Install flag, e_xxx, ignore existing tables. etc.
4228	 *
4229	 * @param int $dir - plugin folder.
4230	 */
4231	function refresh($dir)
4232	{
4233		if(empty($dir))
4234		{
4235			return null;
4236		}
4237
4238		global $sysprefs, $mySQLprefix;
4239
4240		$ns = e107::getRender();
4241		$sql = e107::getDb();
4242		$tp = e107::getParser();
4243
4244		$plug = e107plugin::getPluginRecord($dir);
4245
4246		$this->options = array('nolinks'=>true);
4247
4248		if(!is_array($plug))
4249		{
4250			return "'{$dir}' is missing from the plugin db table";
4251		}
4252
4253		$_path = e_PLUGIN.$plug['plugin_path'].'/';
4254
4255		if (file_exists($_path.'plugin.xml'))
4256		{
4257			$this->install_plugin_xml($plug, 'refresh');
4258		}
4259		else
4260		{
4261			e107::getMessage()->addDebug("Missing xml file at : ".$_path."plugin.xml");
4262			$text = EPL_ADLAN_21;
4263
4264		}
4265
4266		e107::getMessage()->addDebug("Running Refresh of ".$_path);
4267
4268		$this->save_addon_prefs();
4269
4270		e107::getPlug()->clearCache();
4271
4272		return $text;
4273	}
4274
4275
4276	/**
4277	 * Installs a plugin by ID or folder name
4278	 *
4279	 * @param int $id
4280	 * @param array $options (currently only 'nolinks' - set to true to prevent sitelink creation during install)
4281	 */
4282	function install($id, $options = array())
4283	{
4284		global $sysprefs, $mySQLprefix;
4285		$this->log("Running ".__METHOD__);
4286
4287		$ns = e107::getRender();
4288		$sql = e107::getDb();
4289		$tp = e107::getParser();
4290
4291		$this->options = $options;
4292
4293
4294		$text = '';
4295
4296		e107::getPlug()->clearCache();
4297
4298		// install plugin ...
4299		$plug = e107plugin::getPluginRecord($id);
4300
4301		// XXX: The code below does not actually check if the plugin is in the database table.
4302		if(!is_array($plug))
4303		{
4304			$message = $id." is missing from the plugin db table";
4305			$this->log($message);
4306			return $message;
4307		}
4308		// XXX: The code above does not actually check if the plugin is in the database table.
4309
4310		$plug['plug_action'] = !empty($options['function']) ? $options['function'] : 'install';
4311
4312		if (!vartrue($plug['plugin_installflag']))
4313		{
4314			$_path = e_PLUGIN.$plug['plugin_path'].'/';
4315
4316			$this->log("Installing: ".$plug['plugin_path']);
4317
4318			if (file_exists($_path.'plugin.xml'))
4319			{
4320
4321				$text = $this->install_plugin_xml($plug, 'install');
4322			}
4323			elseif (file_exists($_path.'plugin.php'))
4324			{
4325				$text = $this->install_plugin_php($plug);
4326			}
4327		}
4328		else
4329		{
4330			$text = EPL_ADLAN_21;
4331
4332		}
4333
4334		$this->log("Installation completed"); // no LANs
4335
4336		e107::getPlug()->clearCache();
4337
4338		return $text;
4339	}
4340
4341
4342	public function uninstall($id, $options = array())
4343	{
4344		$pref = e107::getPref();
4345		$admin_log = e107::getAdminLog();
4346		$plugin = e107::getPlugin();
4347		$tp = e107::getParser();
4348
4349		$sql = e107::getDb();
4350		$plug = e107plugin::getPluginRecord($id);
4351
4352		$this->log("Uninstalling :" . $plug['plugin_path'] . " with options: " . print_r($options, true));
4353
4354		$this->log("e107plugin::getPluginRecord() returned: " . print_r($plug, true));
4355
4356		// Check if plugin is being used by another plugin before uninstalling it.
4357		if (isset($plug['plugin_path']))
4358		{
4359			if ($this->isUsedByAnotherPlugin($plug['plugin_path']))
4360			{
4361				$this->action = 'installed'; // Render plugin list.
4362				return false;
4363			}
4364		}
4365
4366		$text = '';
4367		//Uninstall Plugin
4368		$eplug_folder = $plug['plugin_path'];
4369		if ($plug['plugin_installflag'] == true)
4370		{
4371			$this->log("plugin_installflag = true, proceeding to uninstall");
4372
4373			$_path = e_PLUGIN . $plug['plugin_path'] . '/';
4374
4375			if (file_exists($_path . 'plugin.xml'))
4376			{
4377				unset($_POST['uninstall_confirm']);
4378				$this->install_plugin_xml($plug, 'uninstall', $options); //$_POST must be used.
4379			}
4380			else
4381			{    // Deprecated - plugin uses plugin.php
4382				$eplug_table_names = null;
4383				$eplug_prefs = null;
4384				$eplug_comment_ids = null;
4385				$eplug_array_pref = null;
4386				$eplug_menu_name = null;
4387				$eplug_link = null;
4388				$eplug_link_url = null;
4389				$eplug_link_name = null;
4390				$eplug_userclass = null;
4391				$eplug_version = null;
4392
4393				include(e_PLUGIN . $plug['plugin_path'] . '/plugin.php');
4394
4395				$func = $eplug_folder . '_uninstall';
4396				if (function_exists($func))
4397				{
4398					$text .= call_user_func($func);
4399				}
4400
4401				if (!empty($options['delete_tables']))
4402				{
4403
4404					if (is_array($eplug_table_names))
4405					{
4406						$result = $this->manage_tables('remove', $eplug_table_names);
4407						if ($result !== TRUE)
4408						{
4409							$text .= EPL_ADLAN_27 . ' <b>' . MPREFIX . $result . '</b> - ' . EPL_ADLAN_30 . '<br />';
4410							$this->log("Unable to delete table."); // No LANS
4411						}
4412						else
4413						{
4414							$text .= EPL_ADLAN_28 . "<br />";
4415							$this->log("Deleting tables."); // NO LANS
4416						}
4417					}
4418				}
4419				else
4420				{
4421					$text .= EPL_ADLAN_49 . "<br />";
4422					$this->log("Tables left intact by request."); // No LANS
4423				}
4424
4425				if (is_array($eplug_prefs))
4426				{
4427					$this->manage_prefs('remove', $eplug_prefs);
4428					$text .= EPL_ADLAN_29 . "<br />";
4429				}
4430
4431				if (is_array($eplug_comment_ids))
4432				{
4433					$text .= ($this->manage_comments('remove', $eplug_comment_ids)) ? EPL_ADLAN_50 . "<br />" : "";
4434				}
4435
4436				if (is_array($eplug_array_pref))
4437				{
4438					foreach ($eplug_array_pref as $key => $val)
4439					{
4440						$this->manage_plugin_prefs('remove', $key, $eplug_folder, $val);
4441					}
4442				}
4443				/*
4444									if ($eplug_menu_name)
4445									{
4446										$sql->delete('menus', "menu_name='{$eplug_menu_name}' ");
4447									}*/
4448				$folderFiles = scandir(e_PLUGIN . $plug['plugin_path']);
4449				$this->XmlMenus($eplug_folder, 'uninstall', $folderFiles);
4450
4451				if ($eplug_link)
4452				{
4453					$this->manage_link('remove', $eplug_link_url, $eplug_link_name);
4454				}
4455
4456				if ($eplug_userclass)
4457				{
4458					$this->manage_userclass('remove', $eplug_userclass);
4459				}
4460
4461				$sql->update('plugin', "plugin_installflag=0, plugin_version='{$eplug_version}' WHERE plugin_path='{$eplug_folder}' ");
4462				$this->manage_search('remove', $eplug_folder);
4463
4464				$this->manage_notify('remove', $eplug_folder);
4465
4466				// it's done inside install_plugin_xml(), required only here
4467				if (isset($pref['plug_installed'][$plug['plugin_path']]))
4468				{
4469					unset($pref['plug_installed'][$plug['plugin_path']]);
4470				}
4471				e107::getConfig('core')->setPref($pref);
4472				$this->rebuildUrlConfig();
4473				e107::getConfig('core')->save(false, true, false);
4474			}
4475
4476			$logInfo = deftrue($plug['plugin_name'], $plug['plugin_name']) . " v" . $plug['plugin_version'] . " ({e_PLUGIN}" . $plug['plugin_path'] . ")";
4477			e107::getLog()->add('PLUGMAN_03', $logInfo, E_LOG_INFORMATIVE, '');
4478		}
4479		else
4480		{
4481			$this->log("plugin_installflag = false, uninstall skipped.");
4482		}
4483
4484		if (!empty($options['delete_files']) && ($plug['plugin_installflag'] == true))
4485		{
4486			if (!empty($eplug_folder))
4487			{
4488				$result = e107::getFile()->rmtree(e_PLUGIN . $eplug_folder);
4489				e107::getDb()->delete('plugin', "plugin_path='" . $eplug_folder . "'");
4490				$text .= ($result ? '<br />' . EPL_ADLAN_86 . e_PLUGIN . $eplug_folder : '<br />' . EPL_ADLAN_87 . '<br />' . EPL_ADLAN_31 . ' <b>' . e_PLUGIN . $eplug_folder . '</b> ' . EPL_ADLAN_32);
4491			}
4492		}
4493		else
4494		{
4495			$text .= '<br />' . EPL_ADLAN_31 . ' <b>' . e_PLUGIN . $eplug_folder . '</b> ' . EPL_ADLAN_32;
4496		}
4497
4498		e107::getPlug()->clearCache()->buildAddonPrefLists();
4499
4500		//	$this->save_addon_prefs('update');
4501
4502		$this->log("Uninstall completed");
4503
4504
4505		return $text;
4506	}
4507
4508
4509
4510
4511
4512	/**
4513	 *	scan the plugin table and create path-array-prefs for each addon.
4514	 *  @deprecated Replaced by eplug::refreshAddonPrefList()
4515	 *	@param string $mode = install|upgrade|refresh|uninstall - defines the intent of the call
4516	 *
4517	 *	'upgrade' and 'refresh' are very similar in intent, and often take the same actions:
4518	 *		'upgrade' signals a possible change to the installed list of plugins - usually an upgrade
4519	 *		'refresh' validates the stored data for existing plugins, recreating any that has gone missing
4520	 */
4521	function save_addon_prefs($mode = 'upgrade')
4522	{
4523		$this->log('Running save_addon_prefs('.$mode.')');
4524
4525	//	e107::getPlug()->buildAddonPrefLists(); // XXX TODO Breaks plugin installation in most cases.
4526
4527	//	return;
4528
4529		$sql = e107::getDb();
4530		$core = e107::getConfig('core');
4531
4532		foreach ($this->plugin_addons as $var) // clear all existing prefs.
4533
4534		{
4535			$core->update($var.'_list', "");
4536		}
4537
4538		// reset
4539		$core->set('bbcode_list', array())
4540			 ->set('shortcode_legacy_list', array())
4541			 ->set('shortcode_list', array());
4542
4543		$query = "SELECT * FROM #plugin WHERE plugin_addons !='' ORDER BY plugin_path ASC";
4544
4545		if ($sql->gen($query))
4546		{
4547			while ($row = $sql->fetch())
4548			{
4549				$is_installed = ($row['plugin_installflag'] == 1);
4550				$tmp = explode(",", $row['plugin_addons']);
4551				$path = $row['plugin_path'];
4552
4553				if ($is_installed)
4554				{
4555					foreach ($tmp as $val)
4556					{
4557						if (strpos($val, 'e_') === 0)
4558						{
4559							// $addpref[$val."_list"][$path] = $path;
4560							$core->setPref($val.'_list/'.$path, $path);
4561						}
4562					}
4563				}
4564
4565				// search for .bb and .sc files.
4566				$scl_array = array();
4567				$sc_array = array();
4568				$bb_array = array();
4569				$sql_array = array();
4570
4571				foreach ($tmp as $adds)
4572				{
4573					// legacy shortcodes - plugin root *.sc files
4574					if (substr($adds, -3) === ".sc")
4575					{
4576						$sc_name = substr($adds, 0, -3); // remove the .sc
4577						if ($is_installed)
4578						{
4579							$scl_array[$sc_name] = "0"; // default userclass = e_UC_PUBLIC
4580						}
4581						else
4582						{
4583							$scl_array[$sc_name] = e_UC_NOBODY; // register shortcode, but disable it
4584						}
4585					}
4586					// new shortcodes location - shortcodes/single/*.php
4587					elseif (substr($adds, 0, 3) === "sc_")
4588					{
4589						$sc_name = substr(substr($adds, 3), 0, -4); // remove the sc_ and .php
4590
4591						if ($is_installed)
4592						{
4593							$sc_array[$sc_name] = "0"; // default userclass = e_UC_PUBLIC
4594						}
4595						else
4596						{
4597							$sc_array[$sc_name] = e_UC_NOBODY; // register shortcode, but disable it
4598						}
4599					}
4600
4601					if($is_installed)
4602					{
4603						// simple bbcode
4604						if(substr($adds,-3) == ".bb")
4605						{
4606							$bb_name = substr($adds, 0,-3); // remove the .bb
4607	                    	$bb_array[$bb_name] = "0"; // default userclass.
4608						}
4609						// bbcode class
4610						elseif(substr($adds, 0, 3) == "bb_" && substr($adds, -4) == ".php")
4611						{
4612							$bb_name = substr($adds, 0,-4); // remove the .php
4613							$bb_name = substr($bb_name, 3);
4614	                    	$bb_array[$bb_name] = "0"; // TODO - instance and getPermissions() method
4615						}
4616					}
4617
4618					if ($is_installed && (substr($adds, -4) == "_sql"))
4619					{
4620						$core->setPref('e_sql_list/'.$path, $adds);
4621					}
4622				}
4623
4624				// Build Bbcode list (will be empty if plugin not installed)
4625				if (count($bb_array) > 0)
4626				{
4627					ksort($bb_array);
4628					$core->setPref('bbcode_list/'.$path, $bb_array);
4629				}
4630
4631				// Build shortcode list - do if uninstalled as well
4632				if (count($scl_array) > 0)
4633				{
4634					ksort($scl_array);
4635					$core->setPref('shortcode_legacy_list/'.$path, $scl_array);
4636				}
4637
4638				if (count($sc_array) > 0)
4639				{
4640					ksort($sc_array);
4641					$core->setPref('shortcode_list/'.$path, $sc_array);
4642				}
4643			}
4644		}
4645
4646		$core->save(FALSE, false, false);
4647
4648		if ($this->manage_icons())
4649		{
4650			// 	echo 'IT WORKED';
4651			}
4652		else
4653		{
4654			// echo "didn't work!";
4655			}
4656		return null;
4657	}
4658
4659	public function getAddonsList()
4660	{
4661		$list = array_diff($this->plugin_addons,$this->plugin_addons_deprecated);
4662		sort($list);
4663
4664		return $list;
4665	}
4666
4667	public function getAddonsDiz($v)
4668	{
4669		if(!empty($this->plugin_addons_diz[$v]))
4670		{
4671			return $this->plugin_addons_diz[$v];
4672		}
4673
4674		return null;
4675
4676	}
4677
4678
4679	// return a list of available plugin addons for the specified plugin. e_xxx etc.
4680	// $debug = TRUE - prints diagnostics
4681	// $debug = 'check' - checks each file found for php tags - prints 'pass' or 'fail'
4682	function getAddons($plugin_path, $debug = FALSE)
4683	{
4684		$fl = e107::getFile();
4685		$mes = e107::getMessage();
4686
4687		$p_addons = array();
4688
4689
4690		foreach ($this->plugin_addons as $addon) //Find exact matches only.
4691		{
4692			//	if(preg_match("#^(e_.*)\.php$#", $f['fname'], $matches))
4693
4694			$addonPHP = $addon.".php";
4695
4696			if (is_readable(e_PLUGIN.$plugin_path."/".$addonPHP))
4697			{
4698				if ($debug === 'check')
4699				{
4700					$passfail = '';
4701					$file_text = file_get_contents(e_PLUGIN.$plugin_path."/".$addonPHP);
4702					if ((substr($file_text, 0, 5) != '<'.'?php') || ((substr($file_text, -2, 2) != '?'.'>') && (strrpos($file_text, '?'.'>') !== FALSE)))
4703					{
4704						$passfail = '<b>fail</b>';
4705					}
4706					else
4707					{
4708						$passfail = 'pass';
4709					}
4710					echo $plugin_path."/".$addon.".php - ".$passfail."<br />";
4711				}
4712				// $mes->add('Detected addon: <b>'.$addon.'</b>', E_MESSAGE_DEBUG);
4713
4714				$p_addons[] = $addon;
4715			}
4716		}
4717
4718		// Grab List of Shortcodes & BBcodes
4719		$shortcodeLegacyList = $fl->get_files(e_PLUGIN.$plugin_path, '\.sc$', "standard", 1);
4720		$shortcodeList = $fl->get_files(e_PLUGIN.$plugin_path.'/shortcodes/single', '\.php$', "standard", 1);
4721
4722		$bbcodeList		= $fl->get_files(e_PLUGIN.$plugin_path, '\.bb$', "standard", 1);
4723		$bbcodeClassList= $fl->get_files(e_PLUGIN.$plugin_path, '^bb_(.*)\.php$', "standard", 1);
4724		$bbcodeList = array_merge($bbcodeList, $bbcodeClassList);
4725
4726		$sqlList = $fl->get_files(e_PLUGIN.$plugin_path, '_sql\.php$', "standard", 1);
4727
4728		// Search Shortcodes
4729		foreach ($shortcodeLegacyList as $sc)
4730		{
4731			if (is_readable(e_PLUGIN.$plugin_path."/".$sc['fname']))
4732			{
4733				$p_addons[] = $sc['fname'];
4734			}
4735		}
4736		foreach ($shortcodeList as $sc)
4737		{
4738			if (is_readable(e_PLUGIN.$plugin_path."/shortcodes/single/".$sc['fname']))
4739			{
4740				$p_addons[] = 'sc_'.$sc['fname'];
4741			}
4742		}
4743
4744		// Search Bbcodes.
4745		foreach ($bbcodeList as $bb)
4746		{
4747			if (is_readable(e_PLUGIN.$plugin_path."/".$bb['fname']))
4748			{
4749				$p_addons[] = $bb['fname'];
4750			}
4751		}
4752
4753		// Search _sql files.
4754		foreach ($sqlList as $esql)
4755		{
4756			if (is_readable(e_PLUGIN.$plugin_path."/".$esql['fname']))
4757			{
4758				$fname = str_replace(".php", "", $esql['fname']);
4759				if (!in_array($fname, $p_addons))
4760					$p_addons[] = $fname; // Probably already found - avoid duplication
4761				}
4762		}
4763
4764		if ($debug == true)
4765		{
4766			echo $plugin_path." = ".implode(",", $p_addons)."<br />";
4767		}
4768
4769		$this->log("Detected Addons: ".print_r($p_addons,true));
4770
4771		return implode(",", $p_addons);
4772	}
4773
4774
4775	/**
4776	 * Check Plugin Addon for errors.
4777	 * @return array or numeric. 0 = OK, 1 = Fail, 2 = inaccessible
4778	 */
4779	function checkAddon($plugin_path, $e_xxx)
4780	{
4781
4782		if (is_readable(e_PLUGIN.$plugin_path."/".$e_xxx.".php"))
4783		{
4784			$content = file_get_contents(e_PLUGIN.$plugin_path."/".$e_xxx.".php");
4785		}
4786		else
4787		{
4788			return 2;
4789		}
4790
4791		if(substr($e_xxx, - 4, 4) == '_sql')
4792		{
4793
4794			if(strpos($content,'INSERT INTO')!==false)
4795			{
4796				return array('type'=> 'error', 'msg'=>"INSERT sql commands are not permitted here. Use a ".$plugin_path."_setup.php file instead.");
4797			}
4798			else
4799			{
4800				return 0;
4801			}
4802		}
4803
4804		// Generic markup check
4805		if ((substr($content, 0, 5) != '<'.'?php') || ((substr($content, -2, 2) != '?'.'>') && (strrpos($content, '?'.'>') !== FALSE)))
4806		{
4807			return 1;
4808		}
4809
4810
4811		if($e_xxx == 'e_meta' && strpos($content,'<script')!==false)
4812		{
4813			return array('type'=> 'warning', 'msg'=>"Contains script tags. Use e_header.php with the e107::js() function instead.");
4814		}
4815
4816
4817		if($e_xxx == 'e_latest' && strpos($content,'<div')!==false)
4818		{
4819			return array('type'=> 'warning', 'msg'=>"Using deprecated method. See e_latest.php in the forum plugin for an example.");
4820		}
4821
4822		if($e_xxx == 'e_status' && strpos($content,'<div')!==false)
4823		{
4824			return array('type'=> 'warning', 'msg'=>"Using deprecated method. See e_status.php in the forum plugin for an example.");
4825		}
4826
4827
4828		return 0;
4829	}
4830
4831	// Entry point to read plugin configuration data
4832	function parse_plugin($plugName, $force = false)
4833	{
4834		$ret = "";
4835
4836		if (isset($this->parsed_plugin[$plugName]) && $force != true)
4837		{
4838			$this->plug_vars = $this->parsed_plugin[$plugName];
4839			return true;
4840		}
4841		unset($this->parsed_plugin[$plugName]); // In case forced parsing which fails
4842		if (file_exists(e_PLUGIN.$plugName.'/plugin.xml'))
4843		{
4844			$ret = $this->parse_plugin_xml($plugName);
4845		}
4846		elseif (file_exists(e_PLUGIN.$plugName.'/plugin.php'))
4847		{
4848			$ret = $this->parse_plugin_php($plugName);
4849		}
4850		if ($ret == true)
4851		{
4852			$this->parsed_plugin[$plugName] = $this->plug_vars;
4853		}
4854
4855		return $ret;
4856	}
4857
4858	// return the Icon of the
4859	function getIcon($plugName='',$size=32, $defaultOverride=false)
4860	{
4861		if(!$plugName) return false;
4862
4863		$tp = e107::getParser();
4864
4865		if(!isset($this->parsed_plugin[$plugName]))
4866		{
4867			 $this->parse_plugin($plugName,true);
4868
4869		}
4870
4871		$plug_vars = $this->parsed_plugin[$plugName];
4872
4873
4874		//return print_r($plug_vars,TRUE);
4875
4876
4877		$sizeArray = array(32=>'icon', 16=>'iconSmall');
4878		$default = ($size == 32) ? $tp->toGlyph('e-cat_plugins-32') : "<img class='icon S16' src='".E_16_CAT_PLUG."' alt='' />";
4879		$sz = $sizeArray[$size];
4880
4881		$icon_src = e_PLUGIN.$plugName."/".$plug_vars['administration'][$sz];
4882		$plugin_icon = $plug_vars['administration'][$sz] ? "<img src='{$icon_src}' alt='' class='icon S".intval($size)."' />" : $default;
4883
4884     	if($defaultOverride !== false && $default === $plugin_icon)
4885        {
4886            return $defaultOverride;
4887        }
4888
4889
4890		if(!$plugin_icon)
4891		{
4892		//
4893		}
4894
4895     	return $plugin_icon;
4896	}
4897
4898
4899
4900	// Called to parse the (deprecated) plugin.php file
4901	function parse_plugin_php($plugName)
4902	{
4903		$tp = e107::getParser();
4904		$sql = e107::getDb(); // in case it is used inside plugin.php
4905
4906		$PLUGINS_FOLDER = '{e_PLUGIN}'; // Could be used in plugin.php file.
4907
4908		$eplug_conffile     = null;
4909		$eplug_table_names  = null;
4910		$eplug_prefs        = null;
4911		$eplug_module       = null;
4912		$eplug_userclass    = null;
4913		$eplug_status       = null;
4914		$eplug_latest       = null;
4915		$eplug_icon         = null;
4916		$eplug_icon_small   = null;
4917
4918	e107::getDebug()->log("Legacy Plugin Parse (php): ".$plugName);
4919
4920		ob_start();
4921		if (include(e_PLUGIN.$plugName.'/plugin.php'))
4922		{
4923			//$mes->add("Loading ".e_PLUGIN.$plugName.'/plugin.php', E_MESSAGE_DEBUG);
4924		}
4925		ob_end_clean();
4926		$ret = array();
4927
4928		//		$ret['installRequired'] = ($eplug_conffile || is_array($eplug_table_names) || is_array($eplug_prefs) || is_array($eplug_sc) || is_array($eplug_bb) || $eplug_module || $eplug_userclass || $eplug_status || $eplug_latest);
4929
4930		$ret['@attributes']['name'] = varset($eplug_name);
4931		$ret['@attributes']['lang'] = varset($eplug_name);
4932		$ret['@attributes']['version'] = varset($eplug_version);
4933		$ret['@attributes']['date'] = varset($eplug_date);
4934		$ret['@attributes']['compatibility'] = varset($eplug_compatible);
4935		$ret['@attributes']['installRequired'] = ($eplug_conffile || is_array($eplug_table_names) || is_array($eplug_prefs) || $eplug_module || $eplug_userclass || $eplug_status || $eplug_latest) ? 'true' : '';
4936		$ret['@attributes']['xhtmlcompliant'] = vartrue($eplug_compliant) ? 'true' : '';
4937		$ret['folder'] = (varset($eplug_folder)) ? $eplug_folder : $plugName;
4938
4939		$ret['author']['@attributes']['name'] = varset($eplug_author);
4940		$ret['author']['@attributes']['url'] = varset($eplug_url);
4941		$ret['author']['@attributes']['email'] = varset($eplug_email);
4942		$ret['description']['@value'] = varset($eplug_description);
4943		$ret['description']['@attributes']['lang'] = varset($eplug_description);
4944
4945		$ret['category'] = varset($eplug_category) ? $this->manage_category($eplug_category) : "misc";
4946		$ret['readme'] = varset($eplug_readme);
4947
4948		$ret['menuName'] = varset($eplug_menu_name);
4949
4950
4951		if (!empty($eplug_prefs) && is_array($eplug_prefs))
4952		{
4953			$c = 0;
4954			foreach($eplug_prefs as $name => $value)
4955			{
4956				$ret['mainPrefs']['pref'][$c]['@attributes']['name'] = $name;
4957				$ret['mainPrefs']['pref'][$c]['@value'] = $value;
4958				$c++;
4959			}
4960		}
4961
4962		// For BC.
4963		$ret['administration']['icon'] = str_replace($plugName."/","",$eplug_icon);
4964		$ret['administration']['caption'] = varset($eplug_caption);
4965		$ret['administration']['iconSmall'] = str_replace($plugName."/","",$eplug_icon_small);
4966		$ret['administration']['configFile'] = varset($eplug_conffile);
4967
4968		if(varset($eplug_conffile))
4969		{
4970			$ret['adminLinks']['link'][0]['@attributes']['url'] = varset($eplug_conffile);
4971			$ret['adminLinks']['link'][0]['@attributes']['description'] = LAN_CONFIGURE;
4972			$ret['adminLinks']['link'][0]['@attributes']['icon'] = str_replace($plugName."/","",$eplug_icon);
4973			$ret['adminLinks']['link'][0]['@attributes']['iconSmall'] = str_replace($plugName."/","",$eplug_icon_small);
4974			$ret['adminLinks']['link'][0]['@attributes']['primary'] = 'true';
4975		}
4976		if(vartrue($eplug_link) && varset($eplug_link_name) && varset($eplug_link_url))
4977		{
4978			$ret['siteLinks']['link'][0]['@attributes']['url'] = $tp->createConstants($eplug_link_url, 1);
4979			$ret['siteLinks']['link'][0]['@attributes']['perm'] = varset($eplug_link_perms);
4980			$ret['siteLinks']['link'][0]['@value'] = varset($eplug_link_name);
4981		}
4982
4983		if(vartrue($eplug_userclass) && vartrue($eplug_userclass_description))
4984		{
4985			$ret['userClasses']['class'][0]['@attributes']['name'] = $eplug_userclass;
4986			$ret['userClasses']['class'][0]['@attributes']['description'] = $eplug_userclass_description;
4987		}
4988
4989		$ret['files'] = preg_grep('/^([^.])/', scandir(e_PLUGIN.$plugName,SCANDIR_SORT_ASCENDING));
4990
4991
4992		// Set this key so we know the vars came from a plugin.php file
4993		// $ret['plugin_php'] = true; // Should no longer be needed.
4994		$this->plug_vars = $ret;
4995
4996
4997		return true;
4998	}
4999
5000	// Called to parse the plugin.xml file if it exists
5001
5002	/**
5003	 * @deprecated To eventually be replaced by e_plugin::parse_plugin_xml.
5004	 * @param      $plugName
5005	 * @param null $where
5006	 * @return bool
5007	 */
5008	function parse_plugin_xml($plugName, $where = null)
5009	{
5010
5011		$tp = e107::getParser();
5012		//	loadLanFiles($plugName, 'admin');					// Look for LAN files on default paths
5013		$xml = e107::getXml();
5014		$mes = e107::getMessage();
5015
5016		if(E107_DEBUG_LEVEL > 0)
5017		{
5018			$dbgArr = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS,3);
5019			unset($dbgArr[0]);
5020			e107::getDebug()->log("Legacy Plugin Parse (xml): ".$plugName. print_a($dbgArr,true));
5021		}
5022
5023
5024
5025		//	$xml->setOptArrayTags('extendedField,userclass,menuLink,commentID'); // always arrays for these tags.
5026		//	$xml->setOptStringTags('install,uninstall,upgrade');
5027		if(null === $where) $where = 'plugin.xml';
5028
5029		$this->plug_vars = $xml->loadXMLfile(e_PLUGIN.$plugName.'/'.$where, 'advanced');
5030
5031		if ($this->plug_vars === FALSE)
5032		{
5033			$mes->addError("Error reading {$plugName}/plugin.xml");
5034			return FALSE;
5035	}
5036
5037		$this->plug_vars['folder'] = $plugName; // remove the need for <folder> tag in plugin.xml.
5038		$this->plug_vars['category'] = (isset($this->plug_vars['category'])) ? $this->manage_category($this->plug_vars['category']) : "misc";
5039		$this->plug_vars['files'] = preg_grep('/^([^.])/', scandir(e_PLUGIN.$plugName,SCANDIR_SORT_ASCENDING));
5040
5041
5042		if(varset($this->plug_vars['description']))
5043		{
5044			if (is_array($this->plug_vars['description']))
5045			{
5046				if (isset($this->plug_vars['description']['@attributes']['lan']) && defined($this->plug_vars['description']['@attributes']['lan']))
5047				{
5048					// Pick up the language-specific description if it exists.
5049					$this->plug_vars['description']['@value'] = constant($this->plug_vars['description']['@attributes']['lan']);
5050}
5051			}
5052			else
5053			{
5054				$diz = $this->plug_vars['description'];
5055				unset($this->plug_vars['description']);
5056
5057				$this->plug_vars['description']['@value'] = $diz;
5058			}
5059		}
5060
5061
5062		 // Very useful debug code.to compare plugin.php vs plugin.xml
5063		/*
5064		 $testplug = 'forum';
5065		 if($plugName == $testplug)
5066		 {
5067		 $plug_vars1 = $this->plug_vars;
5068		 $this->parse_plugin_php($testplug);
5069		 $plug_vars2 = $this->plug_vars;
5070		 ksort($plug_vars2);
5071		 ksort($plug_vars1);
5072		 echo "<table>
5073		 <tr><td><h1>PHP</h1></td><td><h1>XML</h1></td></tr>
5074		 <tr><td style='border-right:1px solid black'>";
5075		 print_a($plug_vars2);
5076		 echo "</td><td>";
5077		 print_a($plug_vars1);
5078		 echo "</table>";
5079		 }
5080		*/
5081
5082
5083		// TODO search for $this->plug_vars['adminLinks']['link'][0]['@attributes']['primary']==true.
5084		$this->plug_vars['administration']['icon'] = varset($this->plug_vars['adminLinks']['link'][0]['@attributes']['icon']);
5085		$this->plug_vars['administration']['caption'] = varset($this->plug_vars['adminLinks']['link'][0]['@attributes']['description']);
5086		$this->plug_vars['administration']['iconSmall'] = varset($this->plug_vars['adminLinks']['link'][0]['@attributes']['iconSmall']);
5087		$this->plug_vars['administration']['configFile'] = varset($this->plug_vars['adminLinks']['link'][0]['@attributes']['url']);
5088
5089		return TRUE;
5090	}
5091
5092}
5093
5094
5095