1<?php
2/**
3 * EGroupware Setup - Install, update & remove single apps
4 *
5 * @link http://www.egroupware.org
6 * @package setup
7 * @author Miles Lott <milos@groupwhere.org>
8 * @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
9 * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
10 * @version $Id$
11 */
12
13use EGroupware\Api;
14use EGroupware\Api\Framework;
15
16$DEBUG = @$_POST['debug'] || @$_GET['debug'];
17/*
18 TODO: We allow a user to hose their setup here, need to make use
19 of dependencies so they are warned that they are pulling the rug
20 out from under other apps.  e.g. if they select to uninstall the api
21 this will happen without further warning.
22*/
23
24include ('./inc/functions.inc.php');
25
26@set_time_limit(0);
27
28// Check header and authentication
29if (!$GLOBALS['egw_setup']->auth('Config'))
30{
31	Header('Location: index.php');
32	exit;
33}
34// Does not return unless user is authorized
35
36$tpl_root = $GLOBALS['egw_setup']->html->setup_tpl_dir('setup');
37$setup_tpl = new Framework\Template($tpl_root);
38$setup_tpl->set_file(array(
39	'T_head' => 'head.tpl',
40	'T_footer' => 'footer.tpl',
41	'T_alert_msg' => 'msg_alert_msg.tpl',
42	'T_login_main' => 'login_main.tpl',
43	'T_login_stage_header' => 'login_stage_header.tpl',
44	'T_setup_main' => 'applications.tpl'
45));
46$setup_tpl->set_var('hidden_vars', Api\Html::input_hidden('csrf_token', Api\Csrf::token(__FILE__)));
47
48// check CSRF token for POST requests with any content (setup uses empty POST to call it's modules!)
49if ($_SERVER['REQUEST_METHOD'] == 'POST' && $_POST)
50{
51	Api\Csrf::validate($_POST['csrf_token'], __FILE__);
52}
53
54$setup_tpl->set_block('T_login_stage_header','B_multi_domain','V_multi_domain');
55$setup_tpl->set_block('T_login_stage_header','B_single_domain','V_single_domain');
56$setup_tpl->set_block('T_setup_main','header','header');
57$setup_tpl->set_block('T_setup_main','app_header','app_header');
58$setup_tpl->set_block('T_setup_main','apps','apps');
59$setup_tpl->set_block('T_setup_main','detail','detail');
60$setup_tpl->set_block('T_setup_main','table','table');
61$setup_tpl->set_block('T_setup_main','hook','hook');
62$setup_tpl->set_block('T_setup_main','dep','dep');
63$setup_tpl->set_block('T_setup_main','app_footer','app_footer');
64$setup_tpl->set_block('T_setup_main','submit','submit');
65$setup_tpl->set_block('T_setup_main','footer','footer');
66
67$bgcolor = array('#DDDDDD','#EEEEEE');
68
69function parsedep($depends,$main=True)
70{
71	$depstring = '(';
72	foreach($depends as $b)
73	{
74		foreach($b as $c => $d)
75		{
76			if (is_array($d))
77			{
78				$depstring .= $c . ': ' .implode(',',$d) . '; ';
79				$depver[] = $d;
80			}
81			else
82			{
83				$depstring .= $c . ': ' . $d . '; ';
84				$depapp[] = $d;
85			}
86		}
87	}
88	$depstring .= ')';
89	if ($main)
90	{
91		return $depstring;
92	}
93	else
94	{
95		return array($depapp,$depver);
96	}
97}
98
99$GLOBALS['egw_setup']->loaddb();
100$GLOBALS['egw_info']['setup']['stage']['db'] = $GLOBALS['egw_setup']->detection->check_db();
101
102$setup_info = $GLOBALS['egw_setup']->detection->check_depends(
103	$GLOBALS['egw_setup']->detection->compare_versions(
104		$GLOBALS['egw_setup']->detection->get_db_versions(
105			$GLOBALS['egw_setup']->detection->get_versions())));
106
107@ksort($setup_info);
108
109if(@$_POST['cancel'])
110{
111	Header("Location: index.php");
112	exit;
113}
114
115if(@$_POST['submit'])
116{
117	$GLOBALS['egw_setup']->html->show_header(lang('Application Management'),False,'config',$GLOBALS['egw_setup']->ConfigDomain . '(' . $GLOBALS['egw_domain'][$GLOBALS['egw_setup']->ConfigDomain]['db_type'] . ')');
118	$setup_tpl->set_var('description',lang('App install/remove/upgrade') . ':');
119	$setup_tpl->pparse('out','header');
120
121	$appname = $_POST['appname'];
122	$remove  = $_POST['remove'];
123	$install = $_POST['install'];
124	$upgrade = $_POST['upgrade'];
125
126	$register_hooks = false;
127
128	if(!empty($remove) && is_array($remove))
129	{
130		$register_hooks = $GLOBALS['egw_setup']->process->remove(array_keys($remove), $setup_info, $DEBUG) > 0;
131	}
132
133	if(!empty($install) && is_array($install))
134	{
135		foreach($install as $appname => $key)
136		{
137			$app_title = $setup_info[$appname]['title'] ? $setup_info[$appname]['title'] : $setup_info[$appname]['name'];
138			$terror = array();
139			$terror[$appname] = $setup_info[$appname];
140
141			if ($setup_info[$appname]['tables'])
142			{
143				$terror_c = $GLOBALS['egw_setup']->process->current($terror, $DEBUG);
144				$terror = $GLOBALS['egw_setup']->process->default_records($terror_c, $DEBUG);
145				echo '<br />' . $app_title . ' '
146					. lang('tables installed, unless there are errors printed above') . '.';
147			}
148			else
149			{
150				// check default_records for apps without tables, they might need some initial work too
151				$terror = $GLOBALS['egw_setup']->process->default_records($terror,$DEBUG);
152				if ($GLOBALS['egw_setup']->app_registered($setup_info[$appname]['name']))
153				{
154					$GLOBALS['egw_setup']->update_app($setup_info[$appname]['name']);
155				}
156				else
157				{
158					$GLOBALS['egw_setup']->register_app($setup_info[$appname]['name']);
159				}
160				echo '<br />' . $app_title . ' ' . lang('registered') . '.';
161
162				if ($setup_info[$appname]['hooks'])
163				{
164					$register_hooks = true;
165				}
166			}
167		}
168	}
169
170	if(!empty($upgrade) && is_array($upgrade))
171	{
172		foreach($upgrade as $appname => $key)
173		{
174			$app_title = $setup_info[$appname]['title'] ? $setup_info[$appname]['title'] : $setup_info[$appname]['name'];
175			$terror = array();
176			$terror[$appname] = $setup_info[$appname];
177
178			$GLOBALS['egw_setup']->process->upgrade($terror,$DEBUG);
179			if ($setup_info[$appname]['tables'])
180			{
181				echo '<br />' . $app_title . ' ' . lang('tables upgraded') . '.';
182				// The process_upgrade() function also handles registration
183			}
184			else
185			{
186				echo '<br />' . $app_title . ' ' . lang('upgraded') . '.';
187			}
188			$register_hooks = true;
189		}
190	}
191
192	if ($register_hooks)
193	{
194		Api\Hooks::read(true);
195		echo '<br />' . $app_title . ' ' . lang('hooks registered') . '.';
196	}
197
198	//$setup_tpl->set_var('goback',
199	echo '<br /><a href="applications.php?debug='.$DEBUG.'">' . lang('Go back') . '</a>';
200	//$setup_tpl->pparse('out','submit');
201	$setup_tpl->pparse('out','footer');
202	exit;
203}
204else
205{
206	$GLOBALS['egw_setup']->html->show_header(lang('Application Management'),False,'config',$GLOBALS['egw_setup']->ConfigDomain . '(' . $GLOBALS['egw_domain'][$GLOBALS['egw_setup']->ConfigDomain]['db_type'] . ')');
207}
208
209if(@$_GET['hooks'])
210{
211	Api\Cache::flush(Api\Cache::INSTANCE);
212
213	echo lang('Cached cleared') . '<br />';
214}
215$detail = $_GET['detail'];
216$resolve = $_GET['resolve'];
217if(@$detail)
218{
219	@ksort($setup_info[$detail]);
220	$setup_tpl->set_var('description',lang('App details') . ':');
221	$setup_tpl->pparse('out','header');
222
223	$setup_tpl->set_var('name','application');
224	$setup_tpl->set_var('details', lang($setup_info[$detail]['title']));
225	$setup_tpl->pparse('out','detail');
226
227	foreach($setup_info[$detail] as $key => $val)
228	{
229		switch($key)
230		{
231			case 'title':
232				continue 2;
233			case 'tables':
234				$tblcnt = count($setup_info[$detail][$key]);
235				if(is_array($val))
236				{
237					$key = '<a href="sqltoarray.php?appname=' . $detail . '&submit=True&apps=True">' . $key . '(' . $tblcnt . ')</a>' . "\n";
238					$val = implode(',' . "\n",$val);
239				}
240				break;
241			case 'hooks':
242				foreach($val as &$hooks)
243				{
244					$hooks = (array)$hooks;
245				}
246				$val = str_replace('EGroupware\\', '', implode(', ', call_user_func_array('array_merge', $val)));
247				break;
248			case 'depends':
249				foreach($val as &$dep)
250				{
251					$dep = $dep['appname'].': '.implode(', ', $dep['versions']);
252				}
253				$val = implode('; ', $val);
254				break;
255			case 'check_install':
256				$val = array2string($val);
257				break;
258			default:
259				if (is_array($val)) $val = implode(', ', $val);
260				break;
261		}
262		$setup_tpl->set_var('bg_color', $bgcolor[++$i & 1]);
263		$setup_tpl->set_var('name',$key);
264		$setup_tpl->set_var('details',$val);
265		$setup_tpl->pparse('out','detail');
266	}
267
268	echo '<br /><a href="applications.php?debug='.$DEBUG.'">' . lang('Go back') . '</a>';
269	$setup_tpl->pparse('out','footer');
270	exit;
271}
272elseif (@$resolve)
273{
274	$version  = $_GET['version'];
275	$notables = $_GET['notables'];
276	$setup_tpl->set_var('description',lang('Problem resolution'). ':');
277	$setup_tpl->pparse('out','header');
278	$app_title = $setup_info[$resolve]['title'] ? $setup_info[$resolve]['title'] : $setup_info[$resolve]['name'];
279
280	if($_GET['post'])
281	{
282		echo '"' . $app_title . '" ' . lang('may be broken') . ' ';
283		echo lang('because an application it depends upon was upgraded');
284		echo '<br />';
285		echo lang('to a version it does not know about') . '.';
286		echo '<br />';
287		echo lang('However, the application may still work') . '.';
288	}
289	elseif($_GET['badinstall'])
290	{
291		echo '"' . $app_title . '" ' . lang('is broken') . ' ';
292		echo lang('because of a failed upgrade or install') . '.';
293		echo '<br />';
294		echo lang('Some or all of its tables are missing') . '.';
295		echo '<br />';
296		echo lang('You should either uninstall and then reinstall it, or attempt manual repairs') . '.';
297	}
298	elseif($_GET['deleted'])
299	{
300		echo '"' . $app_title . '" ' . lang('is broken') . ' ';
301		echo lang('because its sources are missing') . '!';
302		echo '<br />';
303		echo lang('However the tables are still in the database') . '.';
304		echo '<br />';
305		echo lang('You should either install the sources or uninstall it, to get rid of the tables') . '.';
306	}
307	elseif (!$version)
308	{
309		if($setup_info[$resolve]['enabled'])
310		{
311			echo '"' . $app_title . '" ' . lang('is broken') . ' ';
312		}
313		else
314		{
315			echo '"' . $app_title . '" ' . lang('is disabled') . ' ';
316		}
317
318		if (!$notables)
319		{
320			if($setup_info[$resolve]['status'] == 'D')
321			{
322				echo lang('because it depends upon') . ':<br />' . "\n";
323				list($depapp,$depver) = parsedep($setup_info[$resolve]['depends'],False);
324                            $depapp_count = count($depapp);
325				for ($i=0; $i<$depapp_count; $i++)
326				{
327					echo '<br />' . $depapp[$i] . ': ';
328					$list = '';
329					foreach($depver[$i] as $x => $y)
330					{
331						$list .= $y . ', ';
332					}
333					echo substr($list,0,-2)."\n";
334				}
335				echo '<br /><br />' . lang('The table definition was correct, and the tables were installed') . '.';
336			}
337			else
338			{
339				echo lang('because it was manually disabled') . '.';
340			}
341		}
342		elseif($setup_info[$resolve]['enable'] == 2)
343		{
344			echo lang('because it is not a user application, or access is controlled via acl') . '.';
345		}
346		elseif($setup_info[$resolve]['enable'] == 0)
347		{
348			echo lang('because the enable flag for this app is set to 0, or is undefined') . '.';
349		}
350		else
351		{
352			echo lang('because it requires manual table installation, <br />or the table definition was incorrect') . ".\n"
353				. lang("Please check for sql scripts within the application's directory") . '.';
354		}
355		echo '<br />' . lang('However, the application is otherwise installed') . '.';
356	}
357	else
358	{
359		echo $app_title . ' ' . lang('has a version mismatch') . ' ';
360		echo lang('because of a failed upgrade, or the database is newer than the installed version of this app') . '.';
361		echo '<br />';
362		echo lang('If the application has no defined tables, selecting upgrade should remedy the problem') . '.';
363		echo '<br />' . lang('However, the application is otherwise installed') . '.';
364	}
365
366	echo '<br /><a href="applications.php?debug='.$DEBUG.'">' . lang('Go back') . '</a>';
367	$setup_tpl->pparse('out','footer');
368	exit;
369}
370else
371{
372	$setup_tpl->set_var('description',lang('Select the desired action(s) from the available choices'));
373	$setup_tpl->set_var('action_url','applications.php');
374	$setup_tpl->pparse('out','header');
375
376	$setup_tpl->set_var('appdata',lang('Application Data'));
377	$setup_tpl->set_var('actions',lang('Actions'));
378	$setup_tpl->set_var('app_info',lang('Application Name and Status Information'));
379	$setup_tpl->set_var('app_title',lang('Application Title'));
380	$setup_tpl->set_var('app_currentver',lang('Current Version'));
381	$setup_tpl->set_var('app_version',lang('Available Version'));
382	$setup_tpl->set_var('app_install',lang('Install'));
383	$setup_tpl->set_var('app_remove',lang('Remove'));
384	$setup_tpl->set_var('app_upgrade',lang('Upgrade'));
385	$setup_tpl->set_var('app_resolve',lang('Resolve'));
386	$setup_tpl->set_var('check','check.png');
387	$setup_tpl->set_var('install_all',lang('Install All'));
388	$setup_tpl->set_var('upgrade_all',lang('Upgrade All'));
389	$setup_tpl->set_var('remove_all',lang('Remove All'));
390	$setup_tpl->set_var('lang_debug',lang('enable for extra debug-messages'));
391	$setup_tpl->set_var('debug','<input type="checkbox" name="debug" value="True"' .($DEBUG ? ' checked="checked"' : '') . ' />');
392	$setup_tpl->set_var('bg_color',$bgcolor[0]);
393
394	$setup_tpl->pparse('out','app_header');
395
396	$i = 0;
397	foreach($setup_info as $key => $value)
398	{
399		if(@$value['name'])
400		{
401			$i = ($i ? 0 : 1);
402			$setup_tpl->set_var('apptitle',$value['title']?$value['title']:lang($value['name']));
403			$setup_tpl->set_var('currentver',@$value['currentver']);
404			$setup_tpl->set_var('version',$value['version']);
405			$setup_tpl->set_var('bg_color',$bgcolor[$i]);
406
407			switch($value['status'])
408			{
409				case 'C':
410					$setup_tpl->set_var('remove', $key == 'api' ? '&nbsp;' : '<input type="checkbox" name="remove[' . $value['name'] . ']" />');
411					$setup_tpl->set_var('upgrade','&nbsp;');
412					if (!$GLOBALS['egw_setup']->detection->check_app_tables($value['name']))
413					{
414						// App installed and enabled, but some tables are missing
415						$setup_tpl->set_var('instimg','table.png');
416						$setup_tpl->set_var('bg_color','FFCCAA');
417						$setup_tpl->set_var('instalt',lang('Not Completed'));
418						$setup_tpl->set_var('resolution','<a href="applications.php?resolve=' . $value['name'] . '&badinstall=True">' . lang('Potential Problem') . '</a>');
419						$status = lang('Requires reinstall or manual repair') . ' - ' . $value['status'];
420					}
421					else
422					{
423						$setup_tpl->set_var('instimg','completed.png');
424						$setup_tpl->set_var('instalt',lang('Completed'));
425						$setup_tpl->set_var('install','&nbsp;');
426						if($value['enabled'])
427						{
428							$setup_tpl->set_var('resolution','');
429							$status = lang('OK') . ' - ' . $value['status'];
430						}
431						else
432						{
433							if ($value['tables'][0] != '')
434							{
435								$notables = '&notables=True';
436							}
437							$setup_tpl->set_var('bg_color','CCCCFF');
438							$setup_tpl->set_var('resolution',
439								'<a href="applications.php?resolve=' . $value['name'] .  $notables . '">' . lang('Possible Reasons') . '</a>'
440							);
441							$status = lang('Disabled') . ' - ' . $value['status'];
442						}
443					}
444					break;
445				case 'U':
446					$setup_tpl->set_var('instimg','incomplete.png');
447					$setup_tpl->set_var('instalt',lang('Not Completed'));
448					if (!@$value['currentver'])
449					{
450						if ($value['tables'] && $GLOBALS['egw_setup']->detection->check_app_tables($value['name'],True))
451						{
452							// Some tables missing
453							$setup_tpl->set_var('remove',$key == 'api' ? '&nbsp;' : '<input type="checkbox" name="remove[' . $value['name'] . ']" />');
454							$setup_tpl->set_var('resolution','<a href="applications.php?resolve=' . $value['name'] . '&badinstall=True">' . lang('Potential Problem') . '</a>');
455							$status = lang('Requires reinstall or manual repair') . ' - ' . $value['status'];
456						}
457						else
458						{
459							$setup_tpl->set_var('remove','&nbsp;');
460							$setup_tpl->set_var('resolution','');
461							$status = lang('Requires upgrade') . ' - ' . $value['status'];
462						}
463						// show not installed apps without icon
464						$setup_tpl->set_var('instimg','spacer.png');
465						$setup_tpl->set_var('instalt','');
466						$setup_tpl->set_var('bg_color','CCFFCC');
467						$setup_tpl->set_var('install','<input type="checkbox" name="install[' . $value['name'] . ']" />');
468						$setup_tpl->set_var('upgrade','&nbsp;');
469						$status = lang('Please install') . ' - ' . $value['status'];
470					}
471					else
472					{
473						$setup_tpl->set_var('bg_color','CCCCFF');
474						$setup_tpl->set_var('install','&nbsp;');
475						// TODO display some info about breakage if you mess with this app
476						$setup_tpl->set_var('upgrade','<input type="checkbox" name="upgrade[' . $value['name'] . ']" />');
477						$setup_tpl->set_var('remove',$key == 'api' ? '&nbsp;' : '<input type="checkbox" name="remove[' . $value['name'] . ']" />');
478						$setup_tpl->set_var('resolution','');
479						$status = lang('Requires upgrade') . ' - ' . $value['status'];
480					}
481					break;
482				case 'V':
483					$setup_tpl->set_var('instimg','incomplete.png');
484					$setup_tpl->set_var('instalt',lang('Not Completed'));
485					$setup_tpl->set_var('install','&nbsp;');
486					$setup_tpl->set_var('remove',$key == 'api' ? '&nbsp;' : '<input type="checkbox" name="remove[' . $value['name'] . ']" />');
487					if ($value['version'] == 'deleted')
488					{
489						$setup_tpl->set_var('bg_color','CCAAAA');
490						$setup_tpl->set_var('upgrade','&nbsp;');
491						$setup_tpl->set_var('resolution','<a href="applications.php?resolve=' . $value['name'] . '&deleted=True">' . lang('Possible Solutions') . '</a>');
492						$status = lang('Sources deleted/missing') . ' - ' . $value['status'];
493					}
494					else
495					{
496						$setup_tpl->set_var('upgrade','<input type="checkbox" name="upgrade[' . $value['name'] . ']" />');
497						$setup_tpl->set_var('resolution','<a href="applications.php?resolve=' . $value['name'] . '&version=True">' . lang('Possible Solutions') . '</a>');
498						$status = lang('Version Mismatch') . ' - ' . $value['status'];
499					}
500					break;
501				case 'D':
502					$setup_tpl->set_var('bg_color','FFCCCC');
503					$depstring = parsedep($value['depends']);
504					$depstring .= ')';
505					$setup_tpl->set_var('instimg','dep.png');
506					$setup_tpl->set_var('instalt',lang('Dependency Failure'));
507					$setup_tpl->set_var('install','&nbsp;');
508					if ($values['currentver'])
509					{
510						$setup_tpl->set_var('remove',$key == 'api' ? '&nbsp;' : '<input type="checkbox" name="remove[' . $value['name'] . ']" />');
511						$setup_tpl->set_var('resolution','<a href="applications.php?resolve=' . $value['name'] . '">' . lang('Possible Solutions') . '</a>');
512					}
513					else
514					{
515						$setup_tpl->set_var('remove','&nbsp;');
516						$setup_tpl->set_var('resolution','&nbsp;');
517					}
518					$setup_tpl->set_var('upgrade','&nbsp;');
519					$status = lang('Dependency Failure') . ':' . $depstring . $value['status'];
520					break;
521				case 'P':
522					$setup_tpl->set_var('bg_color','FFCCFF');
523					$depstring = parsedep($value['depends']);
524					$depstring .= ')';
525					$setup_tpl->set_var('instimg','dep.png');
526					$setup_tpl->set_var('instalt',lang('Post-install Dependency Failure'));
527					$setup_tpl->set_var('install','&nbsp;');
528					$setup_tpl->set_var('remove','&nbsp;');
529					$setup_tpl->set_var('upgrade','&nbsp;');
530					$setup_tpl->set_var('resolution','<a href="applications.php?resolve=' . $value['name'] . '&post=True">' . lang('Possible Solutions') . '</a>');
531					$status = lang('Post-install Dependency Failure') . ':' . $depstring . $value['status'];
532					break;
533				default:
534					$setup_tpl->set_var('instimg','incomplete.png');
535					$setup_tpl->set_var('instalt',lang('Not Completed'));
536					$setup_tpl->set_var('install','&nbsp;');
537					$setup_tpl->set_var('remove','&nbsp;');
538					$setup_tpl->set_var('upgrade','&nbsp;');
539					$setup_tpl->set_var('resolution','');
540					$status = '';
541					break;
542			}
543			//$setup_tpl->set_var('appname',$value['name'] . '-' . $status . ',' . $value['filename']);
544			$setup_tpl->set_var('appinfo',$value['name'] . '-' . $status);
545			$setup_tpl->set_var('appname',$value['name']);
546
547			$setup_tpl->pparse('out','apps',True);
548		}
549	}
550
551	$setup_tpl->set_var('submit',lang('Save'));
552	$setup_tpl->set_var('cancel',lang('Cancel'));
553	$setup_tpl->pparse('out','app_footer');
554	$setup_tpl->pparse('out','footer');
555	$GLOBALS['egw_setup']->html->show_footer();
556}
557