Blame view

sources/lib/private/app.php 32.6 KB
03e52840d   Kload   Init
1
2
3
4
5
  <?php
  /**
   * ownCloud
   *
   * @author Frank Karlitschek
6d9380f96   Cédric Dupont   Update sources OC...
6
7
   * @copyright 2012 Frank Karlitschek <frank@owncloud.org>
   *
03e52840d   Kload   Init
8
   * @author Jakob Sack
6d9380f96   Cédric Dupont   Update sources OC...
9
10
11
12
   * @copyright 2012 Jakob Sack <mail@jakobsack.de>
   *
   * @author Georg Ehrke
   * @copyright 2014 Georg Ehrke <georg@ownCloud.com>
03e52840d   Kload   Init
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   *
   * This library is free software; you can redistribute it and/or
   * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
   * License as published by the Free Software Foundation; either
   * version 3 of the License, or any later version.
   *
   * This library is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
   *
   * You should have received a copy of the GNU Affero General Public
   * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
   *
   */
  
  /**
   * This class manages the apps. It allows them to register and integrate in the
6d9380f96   Cédric Dupont   Update sources OC...
31
   * ownCloud ecosystem. Furthermore, this class is responsible for installing,
03e52840d   Kload   Init
32
33
   * upgrading and removing apps.
   */
6d9380f96   Cédric Dupont   Update sources OC...
34
  class OC_App {
03e52840d   Kload   Init
35
36
37
38
39
40
41
42
43
44
  	static private $settingsForms = array();
  	static private $adminForms = array();
  	static private $personalForms = array();
  	static private $appInfo = array();
  	static private $appTypes = array();
  	static private $loadedApps = array();
  	static private $checkedApps = array();
  	static private $altLogin = array();
  
  	/**
6d9380f96   Cédric Dupont   Update sources OC...
45
46
  	 * clean the appId
  	 * @param string|boolean $app AppId that needs to be cleaned
03e52840d   Kload   Init
47
48
49
50
51
52
53
  	 * @return string
  	 */
  	public static function cleanAppId($app) {
  		return str_replace(array('\0', '/', '\\', '..'), '', $app);
  	}
  
  	/**
6d9380f96   Cédric Dupont   Update sources OC...
54
  	 * loads all apps
03e52840d   Kload   Init
55
56
57
  	 * @param array $types
  	 * @return bool
  	 *
6d9380f96   Cédric Dupont   Update sources OC...
58
  	 * This function walks through the ownCloud directory and loads all apps
03e52840d   Kload   Init
59
60
61
62
63
  	 * it can find. A directory contains an app if the file /appinfo/app.php
  	 * exists.
  	 *
  	 * if $types is set, only apps of those types will be loaded
  	 */
6d9380f96   Cédric Dupont   Update sources OC...
64
  	public static function loadApps($types = null) {
f7d878ff1   kload   [enh] Update to 7...
65
66
67
  		if (OC_Config::getValue('maintenance', false)) {
  			return false;
  		}
03e52840d   Kload   Init
68
69
70
71
  		// Load the enabled apps here
  		$apps = self::getEnabledApps();
  		// prevent app.php from printing output
  		ob_start();
6d9380f96   Cédric Dupont   Update sources OC...
72
73
  		foreach ($apps as $app) {
  			if ((is_null($types) or self::isType($app, $types)) && !in_array($app, self::$loadedApps)) {
03e52840d   Kload   Init
74
  				self::$loadedApps[] = $app;
6d9380f96   Cédric Dupont   Update sources OC...
75
  				self::loadApp($app);
03e52840d   Kload   Init
76
77
78
  			}
  		}
  		ob_end_clean();
03e52840d   Kload   Init
79
80
81
82
83
  		return true;
  	}
  
  	/**
  	 * load a single app
6d9380f96   Cédric Dupont   Update sources OC...
84
  	 *
03e52840d   Kload   Init
85
  	 * @param string $app
f7d878ff1   kload   [enh] Update to 7...
86
87
  	 * @param bool $checkUpgrade whether an upgrade check should be done
  	 * @throws \OC\NeedsUpdateException
03e52840d   Kload   Init
88
  	 */
f7d878ff1   kload   [enh] Update to 7...
89
  	public static function loadApp($app, $checkUpgrade = true) {
6d9380f96   Cédric Dupont   Update sources OC...
90
  		if (is_file(self::getAppPath($app) . '/appinfo/app.php')) {
f7d878ff1   kload   [enh] Update to 7...
91
92
93
  			if ($checkUpgrade and self::shouldUpgrade($app)) {
  				throw new \OC\NeedsUpdateException();
  			}
6d9380f96   Cédric Dupont   Update sources OC...
94
  			require_once $app . '/appinfo/app.php';
03e52840d   Kload   Init
95
96
97
98
99
  		}
  	}
  
  	/**
  	 * check if an app is of a specific type
6d9380f96   Cédric Dupont   Update sources OC...
100
  	 *
03e52840d   Kload   Init
101
  	 * @param string $app
6d9380f96   Cédric Dupont   Update sources OC...
102
  	 * @param string|array $types
03e52840d   Kload   Init
103
104
105
  	 * @return bool
  	 */
  	public static function isType($app, $types) {
6d9380f96   Cédric Dupont   Update sources OC...
106
107
  		if (is_string($types)) {
  			$types = array($types);
03e52840d   Kload   Init
108
  		}
6d9380f96   Cédric Dupont   Update sources OC...
109
110
111
  		$appTypes = self::getAppTypes($app);
  		foreach ($types as $type) {
  			if (array_search($type, $appTypes) !== false) {
03e52840d   Kload   Init
112
113
114
115
116
117
118
119
  				return true;
  			}
  		}
  		return false;
  	}
  
  	/**
  	 * get the types of an app
6d9380f96   Cédric Dupont   Update sources OC...
120
  	 *
03e52840d   Kload   Init
121
122
123
124
125
  	 * @param string $app
  	 * @return array
  	 */
  	private static function getAppTypes($app) {
  		//load the cache
6d9380f96   Cédric Dupont   Update sources OC...
126
127
  		if (count(self::$appTypes) == 0) {
  			self::$appTypes = OC_Appconfig::getValues(false, 'types');
03e52840d   Kload   Init
128
  		}
6d9380f96   Cédric Dupont   Update sources OC...
129
  		if (isset(self::$appTypes[$app])) {
03e52840d   Kload   Init
130
  			return explode(',', self::$appTypes[$app]);
6d9380f96   Cédric Dupont   Update sources OC...
131
  		} else {
03e52840d   Kload   Init
132
133
134
135
136
137
138
139
  			return array();
  		}
  	}
  
  	/**
  	 * read app types from info.xml and cache them in the database
  	 */
  	public static function setAppTypes($app) {
6d9380f96   Cédric Dupont   Update sources OC...
140
  		$appData = self::getAppInfo($app);
03e52840d   Kload   Init
141

6d9380f96   Cédric Dupont   Update sources OC...
142
143
144
145
  		if (isset($appData['types'])) {
  			$appTypes = implode(',', $appData['types']);
  		} else {
  			$appTypes = '';
03e52840d   Kload   Init
146
147
148
149
150
151
152
  		}
  
  		OC_Appconfig::setValue($app, 'types', $appTypes);
  	}
  
  	/**
  	 * check if app is shipped
6d9380f96   Cédric Dupont   Update sources OC...
153
154
  	 *
  	 * @param string $appId the id of the app to check
03e52840d   Kload   Init
155
156
157
158
  	 * @return bool
  	 *
  	 * Check if an app that is installed is a shipped app or installed from the appstore.
  	 */
6d9380f96   Cédric Dupont   Update sources OC...
159
160
161
  	public static function isShipped($appId) {
  		$info = self::getAppInfo($appId);
  		if (isset($info['shipped']) && $info['shipped'] == 'true') {
03e52840d   Kload   Init
162
163
164
165
166
167
168
169
170
  			return true;
  		} else {
  			return false;
  		}
  	}
  
  	/**
  	 * get all enabled apps
  	 */
6d9380f96   Cédric Dupont   Update sources OC...
171
172
173
174
  	protected static $enabledAppsCache = array();
  
  	public static function getEnabledApps($forceRefresh = false) {
  		if (!OC_Config::getValue('installed', false)) {
03e52840d   Kload   Init
175
176
  			return array();
  		}
6d9380f96   Cédric Dupont   Update sources OC...
177
  		if (!$forceRefresh && !empty(self::$enabledAppsCache)) {
31b7f2792   Kload   Upgrade to ownclo...
178
179
  			return self::$enabledAppsCache;
  		}
f7d878ff1   kload   [enh] Update to 7...
180
  		$apps = array();
6d9380f96   Cédric Dupont   Update sources OC...
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
  		$appConfig = \OC::$server->getAppConfig();
  		$appStatus = $appConfig->getValues(false, 'enabled');
  		$user = \OC_User::getUser();
  		foreach ($appStatus as $app => $enabled) {
  			if ($app === 'files') {
  				continue;
  			}
  			if ($enabled === 'yes') {
  				$apps[] = $app;
  			} else if ($enabled !== 'no') {
  				$groups = json_decode($enabled);
  				if (is_array($groups)) {
  					foreach ($groups as $group) {
  						if (\OC_Group::inGroup($user, $group)) {
  							$apps[] = $app;
  							break;
  						}
  					}
  				}
03e52840d   Kload   Init
200
201
  			}
  		}
6d9380f96   Cédric Dupont   Update sources OC...
202
203
204
205
206
207
208
209
  		sort($apps);
  		array_unshift($apps, 'files');
  		// Only cache the app list, when the user is logged in.
  		// Otherwise we cache the list with disabled apps, although
  		// the apps are enabled for the user after he logged in.
  		if ($user) {
  			self::$enabledAppsCache = $apps;
  		}
03e52840d   Kload   Init
210
211
212
213
  		return $apps;
  	}
  
  	/**
6d9380f96   Cédric Dupont   Update sources OC...
214
  	 * checks whether or not an app is enabled
03e52840d   Kload   Init
215
216
217
218
219
  	 * @param string $app app
  	 * @return bool
  	 *
  	 * This function checks whether or not an app is enabled.
  	 */
6d9380f96   Cédric Dupont   Update sources OC...
220
221
  	public static function isEnabled($app) {
  		if ('files' == $app) {
03e52840d   Kload   Init
222
223
  			return true;
  		}
31b7f2792   Kload   Upgrade to ownclo...
224
225
  		$enabledApps = self::getEnabledApps();
  		return in_array($app, $enabledApps);
03e52840d   Kload   Init
226
227
228
  	}
  
  	/**
6d9380f96   Cédric Dupont   Update sources OC...
229
  	 * enables an app
03e52840d   Kload   Init
230
  	 * @param mixed $app app
6d9380f96   Cédric Dupont   Update sources OC...
231
  	 * @param array $groups (optional) when set, only these groups will have access to the app
31b7f2792   Kload   Upgrade to ownclo...
232
233
  	 * @throws \Exception
  	 * @return void
03e52840d   Kload   Init
234
235
236
  	 *
  	 * This function set an app as enabled in appconfig.
  	 */
6d9380f96   Cédric Dupont   Update sources OC...
237
  	public static function enable($app, $groups = null) {
31b7f2792   Kload   Upgrade to ownclo...
238
  		self::$enabledAppsCache = array(); // flush
6d9380f96   Cédric Dupont   Update sources OC...
239
240
  		if (!OC_Installer::isInstalled($app)) {
  			$app = self::installApp($app);
03e52840d   Kload   Init
241
  		}
6d9380f96   Cédric Dupont   Update sources OC...
242
243
244
  
  		if (!is_null($groups)) {
  			OC_Appconfig::setValue($app, 'enabled', json_encode($groups));
03e52840d   Kload   Init
245
  		}else{
6d9380f96   Cédric Dupont   Update sources OC...
246
  			OC_Appconfig::setValue($app, 'enabled', 'yes');
03e52840d   Kload   Init
247
248
249
250
  		}
  	}
  
  	/**
6d9380f96   Cédric Dupont   Update sources OC...
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
  	 * @param string $app
  	 * @return int
  	 */
  	public static function downloadApp($app) {
  		$appData=OC_OCSClient::getApplication($app);
  		$download=OC_OCSClient::getApplicationDownload($app, 1);
  		if(isset($download['downloadlink']) and $download['downloadlink']!='') {
  			// Replace spaces in download link without encoding entire URL
  			$download['downloadlink'] = str_replace(' ', '%20', $download['downloadlink']);
  			$info = array('source'=>'http', 'href'=>$download['downloadlink'], 'appdata'=>$appData);
  			$app=OC_Installer::installApp($info);
  		}
  		return $app;
  	}
  
  	/**
  	 * @param string $app
03e52840d   Kload   Init
268
  	 * @return bool
6d9380f96   Cédric Dupont   Update sources OC...
269
270
271
272
273
274
275
276
277
278
  	 */
  	public static function removeApp($app) {
  		if (self::isShipped($app)) {
  			return false;
  		}
  
  		return OC_Installer::removeApp($app);
  	}
  
  	/**
03e52840d   Kload   Init
279
  	 * This function set an app as disabled in appconfig.
6d9380f96   Cédric Dupont   Update sources OC...
280
  	 * @param string $app app
03e52840d   Kload   Init
281
  	 */
6d9380f96   Cédric Dupont   Update sources OC...
282
  	public static function disable($app) {
31b7f2792   Kload   Upgrade to ownclo...
283
  		self::$enabledAppsCache = array(); // flush
03e52840d   Kload   Init
284
285
  		// check if app is a shipped app or not. if not delete
  		\OC_Hook::emit('OC_App', 'pre_disable', array('app' => $app));
6d9380f96   Cédric Dupont   Update sources OC...
286
  		OC_Appconfig::setValue($app, 'enabled', 'no' );
03e52840d   Kload   Init
287
288
289
  	}
  
  	/**
6d9380f96   Cédric Dupont   Update sources OC...
290
  	 * adds an entry to the navigation
31b7f2792   Kload   Upgrade to ownclo...
291
  	 * @param array $data array containing the data
03e52840d   Kload   Init
292
293
294
295
296
297
298
299
300
301
302
303
304
305
  	 * @return bool
  	 *
  	 * This function adds a new entry to the navigation visible to users. $data
  	 * is an associative array.
  	 * The following keys are required:
  	 *   - id: unique id for this entry ('addressbook_index')
  	 *   - href: link to the page
  	 *   - name: Human readable name ('Addressbook')
  	 *
  	 * The following keys are optional:
  	 *   - icon: path to the icon of the app
  	 *   - order: integer, that influences the position of your application in
  	 *     the navigation. Lower values come first.
  	 */
6d9380f96   Cédric Dupont   Update sources OC...
306
  	public static function addNavigationEntry($data) {
31b7f2792   Kload   Upgrade to ownclo...
307
  		OC::$server->getNavigationManager()->add($data);
03e52840d   Kload   Init
308
309
310
311
  		return true;
  	}
  
  	/**
6d9380f96   Cédric Dupont   Update sources OC...
312
  	 * marks a navigation entry as active
03e52840d   Kload   Init
313
314
315
316
317
318
319
  	 * @param string $id id of the entry
  	 * @return bool
  	 *
  	 * This function sets a navigation entry as active and removes the 'active'
  	 * property from all other entries. The templates can use this for
  	 * highlighting the current position of the user.
  	 */
6d9380f96   Cédric Dupont   Update sources OC...
320
  	public static function setActiveNavigationEntry($id) {
31b7f2792   Kload   Upgrade to ownclo...
321
  		OC::$server->getNavigationManager()->setActiveEntry($id);
03e52840d   Kload   Init
322
323
324
325
  		return true;
  	}
  
  	/**
6d9380f96   Cédric Dupont   Update sources OC...
326
  	 * Get the navigation entries for the $app
03e52840d   Kload   Init
327
  	 * @param string $app app
6d9380f96   Cédric Dupont   Update sources OC...
328
  	 * @return array an array of the $data added with addNavigationEntry
31b7f2792   Kload   Upgrade to ownclo...
329
330
  	 *
  	 * Warning: destroys the existing entries
03e52840d   Kload   Init
331
332
  	 */
  	public static function getAppNavigationEntries($app) {
6d9380f96   Cédric Dupont   Update sources OC...
333
  		if (is_file(self::getAppPath($app) . '/appinfo/app.php')) {
31b7f2792   Kload   Upgrade to ownclo...
334
  			OC::$server->getNavigationManager()->clear();
6d9380f96   Cédric Dupont   Update sources OC...
335
  			require $app . '/appinfo/app.php';
31b7f2792   Kload   Upgrade to ownclo...
336
  			return OC::$server->getNavigationManager()->getAll();
03e52840d   Kload   Init
337
338
339
340
341
  		}
  		return array();
  	}
  
  	/**
6d9380f96   Cédric Dupont   Update sources OC...
342
  	 * gets the active Menu entry
03e52840d   Kload   Init
343
344
345
346
347
348
  	 * @return string id or empty string
  	 *
  	 * This function returns the id of the active navigation entry (set by
  	 * setActiveNavigationEntry
  	 */
  	public static function getActiveNavigationEntry() {
31b7f2792   Kload   Upgrade to ownclo...
349
  		return OC::$server->getNavigationManager()->getActiveEntry();
03e52840d   Kload   Init
350
351
352
  	}
  
  	/**
6d9380f96   Cédric Dupont   Update sources OC...
353
354
  	 * Returns the Settings Navigation
  	 * @return string
03e52840d   Kload   Init
355
356
357
358
359
  	 *
  	 * This function returns an array containing all settings pages added. The
  	 * entries are sorted by the key 'order' ascending.
  	 */
  	public static function getSettingsNavigation() {
6d9380f96   Cédric Dupont   Update sources OC...
360
  		$l = OC_L10N::get('lib');
03e52840d   Kload   Init
361
362
363
  
  		$settings = array();
  		// by default, settings only contain the help menu
6d9380f96   Cédric Dupont   Update sources OC...
364
365
366
  		if (OC_Util::getEditionString() === '' &&
  			OC_Config::getValue('knowledgebaseenabled', true) == true
  		) {
03e52840d   Kload   Init
367
368
369
370
  			$settings = array(
  				array(
  					"id" => "help",
  					"order" => 1000,
6d9380f96   Cédric Dupont   Update sources OC...
371
  					"href" => OC_Helper::linkToRoute("settings_help"),
03e52840d   Kload   Init
372
  					"name" => $l->t("Help"),
6d9380f96   Cédric Dupont   Update sources OC...
373
  					"icon" => OC_Helper::imagePath("settings", "help.svg")
03e52840d   Kload   Init
374
375
376
377
378
379
380
381
382
383
  				)
  			);
  		}
  
  		// if the user is logged-in
  		if (OC_User::isLoggedIn()) {
  			// personal menu
  			$settings[] = array(
  				"id" => "personal",
  				"order" => 1,
6d9380f96   Cédric Dupont   Update sources OC...
384
  				"href" => OC_Helper::linkToRoute("settings_personal"),
03e52840d   Kload   Init
385
  				"name" => $l->t("Personal"),
6d9380f96   Cédric Dupont   Update sources OC...
386
  				"icon" => OC_Helper::imagePath("settings", "personal.svg")
03e52840d   Kload   Init
387
388
389
  			);
  
  			// if there are some settings forms
6d9380f96   Cédric Dupont   Update sources OC...
390
  			if (!empty(self::$settingsForms)) {
03e52840d   Kload   Init
391
  				// settings menu
6d9380f96   Cédric Dupont   Update sources OC...
392
  				$settings[] = array(
03e52840d   Kload   Init
393
394
  					"id" => "settings",
  					"order" => 1000,
6d9380f96   Cédric Dupont   Update sources OC...
395
  					"href" => OC_Helper::linkToRoute("settings_settings"),
03e52840d   Kload   Init
396
  					"name" => $l->t("Settings"),
6d9380f96   Cédric Dupont   Update sources OC...
397
  					"icon" => OC_Helper::imagePath("settings", "settings.svg")
03e52840d   Kload   Init
398
399
400
401
  				);
  			}
  
  			//SubAdmins are also allowed to access user management
6d9380f96   Cédric Dupont   Update sources OC...
402
  			if (OC_SubAdmin::isSubAdmin(OC_User::getUser())) {
03e52840d   Kload   Init
403
404
405
406
  				// admin users menu
  				$settings[] = array(
  					"id" => "core_users",
  					"order" => 2,
6d9380f96   Cédric Dupont   Update sources OC...
407
  					"href" => OC_Helper::linkToRoute("settings_users"),
03e52840d   Kload   Init
408
  					"name" => $l->t("Users"),
6d9380f96   Cédric Dupont   Update sources OC...
409
  					"icon" => OC_Helper::imagePath("settings", "users.svg")
03e52840d   Kload   Init
410
411
412
413
414
  				);
  			}
  
  
  			// if the user is an admin
6d9380f96   Cédric Dupont   Update sources OC...
415
  			if (OC_User::isAdminUser(OC_User::getUser())) {
31b7f2792   Kload   Upgrade to ownclo...
416
  				// admin settings
6d9380f96   Cédric Dupont   Update sources OC...
417
  				$settings[] = array(
03e52840d   Kload   Init
418
419
  					"id" => "admin",
  					"order" => 1000,
6d9380f96   Cédric Dupont   Update sources OC...
420
  					"href" => OC_Helper::linkToRoute("settings_admin"),
03e52840d   Kload   Init
421
  					"name" => $l->t("Admin"),
6d9380f96   Cédric Dupont   Update sources OC...
422
  					"icon" => OC_Helper::imagePath("settings", "admin.svg")
03e52840d   Kload   Init
423
424
425
426
427
428
429
  				);
  			}
  		}
  
  		$navigation = self::proceedNavigation($settings);
  		return $navigation;
  	}
31b7f2792   Kload   Upgrade to ownclo...
430
  	// This is private as well. It simply works, so don't ask for more details
6d9380f96   Cédric Dupont   Update sources OC...
431
432
433
434
435
436
437
  	private static function proceedNavigation($list) {
  		$activeApp = OC::$server->getNavigationManager()->getActiveEntry();
  		foreach ($list as &$navEntry) {
  			if ($navEntry['id'] == $activeApp) {
  				$navEntry['active'] = true;
  			} else {
  				$navEntry['active'] = false;
03e52840d   Kload   Init
438
  			}
6d9380f96   Cédric Dupont   Update sources OC...
439
440
  		}
  		unset($navEntry);
03e52840d   Kload   Init
441

6d9380f96   Cédric Dupont   Update sources OC...
442
  		usort($list, create_function('$a, $b', 'if( $a["order"] == $b["order"] ) {return 0;}elseif( $a["order"] < $b["order"] ) {return -1;}else{return 1;}'));
03e52840d   Kload   Init
443
444
445
446
447
448
  
  		return $list;
  	}
  
  	/**
  	 * Get the path where to install apps
6d9380f96   Cédric Dupont   Update sources OC...
449
450
  	 *
  	 * @return string
03e52840d   Kload   Init
451
452
  	 */
  	public static function getInstallPath() {
6d9380f96   Cédric Dupont   Update sources OC...
453
  		if (OC_Config::getValue('appstoreenabled', true) == false) {
03e52840d   Kload   Init
454
455
  			return false;
  		}
6d9380f96   Cédric Dupont   Update sources OC...
456
457
  		foreach (OC::$APPSROOTS as $dir) {
  			if (isset($dir['writable']) && $dir['writable'] === true) {
03e52840d   Kload   Init
458
459
460
461
462
463
464
  				return $dir['path'];
  			}
  		}
  
  		OC_Log::write('core', 'No application directories are marked as writable.', OC_Log::ERROR);
  		return null;
  	}
6d9380f96   Cédric Dupont   Update sources OC...
465
466
467
468
469
470
  	/**
  	 * search for an app in all app-directories
  	 * @param $appId
  	 * @return mixed (bool|string)
  	 */
  	protected static function findAppInDirectories($appId) {
03e52840d   Kload   Init
471
  		static $app_dir = array();
6d9380f96   Cédric Dupont   Update sources OC...
472
473
474
  
  		if (isset($app_dir[$appId])) {
  			return $app_dir[$appId];
03e52840d   Kload   Init
475
  		}
6d9380f96   Cédric Dupont   Update sources OC...
476
477
  
  		$possibleApps = array();
03e52840d   Kload   Init
478
  		foreach(OC::$APPSROOTS as $dir) {
6d9380f96   Cédric Dupont   Update sources OC...
479
480
  			if(file_exists($dir['path'] . '/' . $appId)) {
  				$possibleApps[] = $dir;
03e52840d   Kload   Init
481
482
  			}
  		}
6d9380f96   Cédric Dupont   Update sources OC...
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
  
  		if (empty($possibleApps)) {
  			return false;
  		} elseif(count($possibleApps) === 1) {
  			$dir = array_shift($possibleApps);
  			$app_dir[$appId] = $dir;
  			return $dir;
  		} else {
  			$versionToLoad = array();
  			foreach($possibleApps as $possibleApp) {
  				$version = self::getAppVersionByPath($possibleApp['path']);
  				if (empty($versionToLoad) || version_compare($version, $versionToLoad['version'], '>')) {
  					$versionToLoad = array(
  						'dir' => $possibleApp,
  						'version' => $version,
  					);
  				}
  			}
  			$app_dir[$appId] = $versionToLoad['dir'];
  			return $versionToLoad['dir'];
  			//TODO - write test
  		}
03e52840d   Kload   Init
505
  	}
6d9380f96   Cédric Dupont   Update sources OC...
506

03e52840d   Kload   Init
507
  	/**
6d9380f96   Cédric Dupont   Update sources OC...
508
509
510
511
512
513
514
515
516
517
518
519
520
  	 * Get the directory for the given app.
  	 * If the app is defined in multiple directories, the first one is taken. (false if not found)
  	 *
  	 * @param string $appId
  	 * @return string|false
  	 */
  	public static function getAppPath($appId) {
  		if ($appId === null || trim($appId) === '') {
  			return false;
  		}
  
  		if (($dir = self::findAppInDirectories($appId)) != false) {
  			return $dir['path'] . '/' . $appId;
03e52840d   Kload   Init
521
522
523
  		}
  		return false;
  	}
6d9380f96   Cédric Dupont   Update sources OC...
524
525
526
527
528
529
530
531
532
533
534
  
  	/**
  	 * check if an app's directory is writable
  	 *
  	 * @param string $appId
  	 * @return bool
  	 */
  	public static function isAppDirWritable($appId) {
  		$path = self::getAppPath($appId);
  		return ($path !== false) ? is_writable($path) : false;
  	}
03e52840d   Kload   Init
535
  	/**
6d9380f96   Cédric Dupont   Update sources OC...
536
537
538
539
540
541
542
543
544
  	 * Get the path for the given app on the access
  	 * If the app is defined in multiple directories, the first one is taken. (false if not found)
  	 *
  	 * @param string $appId
  	 * @return string|false
  	 */
  	public static function getAppWebPath($appId) {
  		if (($dir = self::findAppInDirectories($appId)) != false) {
  			return OC::$WEBROOT . $dir['url'] . '/' . $appId;
03e52840d   Kload   Init
545
546
547
548
549
550
  		}
  		return false;
  	}
  
  	/**
  	 * get the last version of the app, either from appinfo/version or from appinfo/info.xml
6d9380f96   Cédric Dupont   Update sources OC...
551
552
553
554
555
556
557
558
559
560
561
562
563
  	 *
  	 * @param string $appId
  	 * @return string
  	 */
  	public static function getAppVersion($appId) {
  		$file = self::getAppPath($appId);
  		return ($file !== false) ? self::getAppVersionByPath($file) : '0';
  	}
  
  	/**
  	 * get app's version based on it's path
  	 * @param string $path
  	 * @return string
03e52840d   Kload   Init
564
  	 */
6d9380f96   Cédric Dupont   Update sources OC...
565
566
567
568
569
  	public static function getAppVersionByPath($path) {
  		$versionFile = $path . '/appinfo/version';
  		$infoFile = $path . '/appinfo/info.xml';
  		if(is_file($versionFile)) {
  			return trim(file_get_contents($versionFile));
03e52840d   Kload   Init
570
  		}else{
6d9380f96   Cédric Dupont   Update sources OC...
571
572
  			$appData = self::getAppInfo($infoFile, true);
  			return isset($appData['version']) ? $appData['version'] : '';
03e52840d   Kload   Init
573
574
  		}
  	}
6d9380f96   Cédric Dupont   Update sources OC...
575

03e52840d   Kload   Init
576
  	/**
6d9380f96   Cédric Dupont   Update sources OC...
577
578
579
  	 * Read all app metadata from the info.xml file
  	 *
  	 * @param string $appId id of the app or the path of the info.xml file
03e52840d   Kload   Init
580
  	 * @param boolean $path (optional)
6d9380f96   Cédric Dupont   Update sources OC...
581
  	 * @return array|null
03e52840d   Kload   Init
582
  	 * @note all data is read from info.xml, not just pre-defined fields
6d9380f96   Cédric Dupont   Update sources OC...
583
584
585
586
587
588
589
  	 */
  	public static function getAppInfo($appId, $path = false) {
  		if ($path) {
  			$file = $appId;
  		} else {
  			if (isset(self::$appInfo[$appId])) {
  				return self::$appInfo[$appId];
03e52840d   Kload   Init
590
  			}
6d9380f96   Cédric Dupont   Update sources OC...
591
592
593
594
595
  			$file = self::getAppPath($appId) . '/appinfo/info.xml';
  		}
  		$data = array();
  		if (!file_exists($file)) {
  			return null;
03e52840d   Kload   Init
596
  		}
6d9380f96   Cédric Dupont   Update sources OC...
597
598
  		$content = @file_get_contents($file);
  		if (!$content) {
03e52840d   Kload   Init
599
600
601
  			return null;
  		}
  		$xml = new SimpleXMLElement($content);
6d9380f96   Cédric Dupont   Update sources OC...
602
603
604
605
  		$data['info'] = array();
  		$data['remote'] = array();
  		$data['public'] = array();
  		foreach ($xml->children() as $child) {
03e52840d   Kload   Init
606
607
608
  			/**
  			 * @var $child SimpleXMLElement
  			 */
6d9380f96   Cédric Dupont   Update sources OC...
609
610
  			if ($child->getName() == 'remote') {
  				foreach ($child->children() as $remote) {
03e52840d   Kload   Init
611
612
613
  					/**
  					 * @var $remote SimpleXMLElement
  					 */
6d9380f96   Cédric Dupont   Update sources OC...
614
  					$data['remote'][$remote->getName()] = (string)$remote;
03e52840d   Kload   Init
615
  				}
6d9380f96   Cédric Dupont   Update sources OC...
616
617
  			} elseif ($child->getName() == 'public') {
  				foreach ($child->children() as $public) {
03e52840d   Kload   Init
618
619
620
  					/**
  					 * @var $public SimpleXMLElement
  					 */
6d9380f96   Cédric Dupont   Update sources OC...
621
  					$data['public'][$public->getName()] = (string)$public;
03e52840d   Kload   Init
622
  				}
6d9380f96   Cédric Dupont   Update sources OC...
623
624
625
  			} elseif ($child->getName() == 'types') {
  				$data['types'] = array();
  				foreach ($child->children() as $type) {
03e52840d   Kload   Init
626
627
628
  					/**
  					 * @var $type SimpleXMLElement
  					 */
6d9380f96   Cédric Dupont   Update sources OC...
629
  					$data['types'][] = $type->getName();
03e52840d   Kload   Init
630
  				}
6d9380f96   Cédric Dupont   Update sources OC...
631
632
633
634
635
636
  			} elseif ($child->getName() == 'description') {
  				$xml = (string)$child->asXML();
  				$data[$child->getName()] = substr($xml, 13, -14); //script <description> tags
  			} elseif ($child->getName() == 'documentation') {
  				foreach ($child as $subChild) {
  					$data["documentation"][$subChild->getName()] = (string)$subChild;
a293d369c   Kload   Update sources to...
637
  				}
6d9380f96   Cédric Dupont   Update sources OC...
638
639
  			} else {
  				$data[$child->getName()] = (string)$child;
03e52840d   Kload   Init
640
641
  			}
  		}
6d9380f96   Cédric Dupont   Update sources OC...
642
  		self::$appInfo[$appId] = $data;
03e52840d   Kload   Init
643
644
645
646
647
  
  		return $data;
  	}
  
  	/**
6d9380f96   Cédric Dupont   Update sources OC...
648
  	 * Returns the navigation
03e52840d   Kload   Init
649
650
651
652
653
654
655
656
  	 * @return array
  	 *
  	 * This function returns an array containing all entries added. The
  	 * entries are sorted by the key 'order' ascending. Additional to the keys
  	 * given for each app the following keys exist:
  	 *   - active: boolean, signals if the user is on this navigation entry
  	 */
  	public static function getNavigation() {
31b7f2792   Kload   Upgrade to ownclo...
657
  		$entries = OC::$server->getNavigationManager()->getAll();
6d9380f96   Cédric Dupont   Update sources OC...
658
  		$navigation = self::proceedNavigation($entries);
03e52840d   Kload   Init
659
660
661
662
663
  		return $navigation;
  	}
  
  	/**
  	 * get the id of loaded app
6d9380f96   Cédric Dupont   Update sources OC...
664
  	 *
03e52840d   Kload   Init
665
666
667
  	 * @return string
  	 */
  	public static function getCurrentApp() {
6d9380f96   Cédric Dupont   Update sources OC...
668
669
  		$script = substr(OC_Request::scriptName(), strlen(OC::$WEBROOT) + 1);
  		$topFolder = substr($script, 0, strpos($script, '/'));
03e52840d   Kload   Init
670
671
672
  		if (empty($topFolder)) {
  			$path_info = OC_Request::getPathInfo();
  			if ($path_info) {
6d9380f96   Cédric Dupont   Update sources OC...
673
  				$topFolder = substr($path_info, 1, strpos($path_info, '/', 1) - 1);
03e52840d   Kload   Init
674
675
  			}
  		}
6d9380f96   Cédric Dupont   Update sources OC...
676
677
678
679
  		if ($topFolder == 'apps') {
  			$length = strlen($topFolder);
  			return substr($script, $length + 1, strpos($script, '/', $length + 1) - $length - 1);
  		} else {
03e52840d   Kload   Init
680
681
682
  			return $topFolder;
  		}
  	}
03e52840d   Kload   Init
683
684
685
686
  	/**
  	 * get the forms for either settings, admin or personal
  	 */
  	public static function getForms($type) {
6d9380f96   Cédric Dupont   Update sources OC...
687
688
  		$forms = array();
  		switch ($type) {
03e52840d   Kload   Init
689
  			case 'settings':
6d9380f96   Cédric Dupont   Update sources OC...
690
  				$source = self::$settingsForms;
03e52840d   Kload   Init
691
692
  				break;
  			case 'admin':
6d9380f96   Cédric Dupont   Update sources OC...
693
  				$source = self::$adminForms;
03e52840d   Kload   Init
694
695
  				break;
  			case 'personal':
6d9380f96   Cédric Dupont   Update sources OC...
696
  				$source = self::$personalForms;
03e52840d   Kload   Init
697
698
699
700
  				break;
  			default:
  				return array();
  		}
6d9380f96   Cédric Dupont   Update sources OC...
701
702
  		foreach ($source as $form) {
  			$forms[] = include $form;
03e52840d   Kload   Init
703
704
705
706
707
708
709
710
  		}
  		return $forms;
  	}
  
  	/**
  	 * register a settings form to be shown
  	 */
  	public static function registerSettings($app, $page) {
6d9380f96   Cédric Dupont   Update sources OC...
711
  		self::$settingsForms[] = $app . '/' . $page . '.php';
03e52840d   Kload   Init
712
713
714
715
  	}
  
  	/**
  	 * register an admin form to be shown
6d9380f96   Cédric Dupont   Update sources OC...
716
717
718
  	 *
  	 * @param string $app
  	 * @param string $page
03e52840d   Kload   Init
719
720
  	 */
  	public static function registerAdmin($app, $page) {
6d9380f96   Cédric Dupont   Update sources OC...
721
  		self::$adminForms[] = $app . '/' . $page . '.php';
03e52840d   Kload   Init
722
723
724
725
726
727
  	}
  
  	/**
  	 * register a personal form to be shown
  	 */
  	public static function registerPersonal($app, $page) {
6d9380f96   Cédric Dupont   Update sources OC...
728
  		self::$personalForms[] = $app . '/' . $page . '.php';
03e52840d   Kload   Init
729
730
731
732
733
734
735
736
737
738
739
  	}
  
  	public static function registerLogIn($entry) {
  		self::$altLogin[] = $entry;
  	}
  
  	public static function getAlternativeLogIns() {
  		return self::$altLogin;
  	}
  
  	/**
6d9380f96   Cédric Dupont   Update sources OC...
740
741
  	 * get a list of all apps in the apps folder
  	 * @return array an array of app names (string IDs)
03e52840d   Kload   Init
742
743
744
  	 * @todo: change the name of this method to getInstalledApps, which is more accurate
  	 */
  	public static function getAllApps() {
6d9380f96   Cédric Dupont   Update sources OC...
745
  		$apps = array();
03e52840d   Kload   Init
746

6d9380f96   Cédric Dupont   Update sources OC...
747
748
749
  		foreach (OC::$APPSROOTS as $apps_dir) {
  			if (!is_readable($apps_dir['path'])) {
  				OC_Log::write('core', 'unable to read app folder : ' . $apps_dir['path'], OC_Log::WARN);
03e52840d   Kload   Init
750
751
  				continue;
  			}
6d9380f96   Cédric Dupont   Update sources OC...
752
  			$dh = opendir($apps_dir['path']);
03e52840d   Kload   Init
753

6d9380f96   Cédric Dupont   Update sources OC...
754
  			if (is_resource($dh)) {
03e52840d   Kload   Init
755
  				while (($file = readdir($dh)) !== false) {
6d9380f96   Cédric Dupont   Update sources OC...
756
  					if ($file[0] != '.' and is_file($apps_dir['path'] . '/' . $file . '/appinfo/app.php')) {
03e52840d   Kload   Init
757
758
759
760
761
762
763
764
765
766
767
768
769
770
  
  						$apps[] = $file;
  
  					}
  
  				}
  			}
  
  		}
  
  		return $apps;
  	}
  
  	/**
6d9380f96   Cédric Dupont   Update sources OC...
771
  	 * Lists all apps, this is used in apps.php
03e52840d   Kload   Init
772
773
774
775
776
777
778
  	 * @return array
  	 */
  	public static function listAllApps() {
  		$installedApps = OC_App::getAllApps();
  
  		//TODO which apps do we want to blacklist and how do we integrate
  		// blacklisting with the multi apps folder feature?
6d9380f96   Cédric Dupont   Update sources OC...
779
  		$blacklist = array('files'); //we don't want to show configuration for these
03e52840d   Kload   Init
780
  		$appList = array();
6d9380f96   Cédric Dupont   Update sources OC...
781
782
  		foreach ($installedApps as $app) {
  			if (array_search($app, $blacklist) === false) {
03e52840d   Kload   Init
783

6d9380f96   Cédric Dupont   Update sources OC...
784
  				$info = OC_App::getAppInfo($app);
03e52840d   Kload   Init
785
786
  
  				if (!isset($info['name'])) {
6d9380f96   Cédric Dupont   Update sources OC...
787
  					OC_Log::write('core', 'App id "' . $app . '" has no name in appinfo', OC_Log::ERROR);
03e52840d   Kload   Init
788
789
  					continue;
  				}
6d9380f96   Cédric Dupont   Update sources OC...
790
791
792
  				$enabled = OC_Appconfig::getValue($app, 'enabled', 'no');
  				$info['groups'] = null;
  				if ($enabled === 'yes') {
03e52840d   Kload   Init
793
  					$active = true;
6d9380f96   Cédric Dupont   Update sources OC...
794
  				} else if($enabled === 'no') {
03e52840d   Kload   Init
795
  					$active = false;
6d9380f96   Cédric Dupont   Update sources OC...
796
797
798
  				} else {
  					$active = true;
  					$info['groups'] = $enabled;
03e52840d   Kload   Init
799
800
801
  				}
  
  				$info['active'] = $active;
6d9380f96   Cédric Dupont   Update sources OC...
802
803
804
805
806
  				if(isset($info['shipped']) and ($info['shipped'] == 'true')) {
  					$info['internal'] = true;
  					$info['internallabel'] = 'Internal App';
  					$info['internalclass'] = '';
  					$info['removable'] = false;
03e52840d   Kload   Init
807
  				} else {
6d9380f96   Cédric Dupont   Update sources OC...
808
809
810
811
  					$info['internal'] = false;
  					$info['internallabel'] = '3rd Party';
  					$info['internalclass'] = 'externalapp';
  					$info['removable'] = true;
03e52840d   Kload   Init
812
  				}
6d9380f96   Cédric Dupont   Update sources OC...
813
  				$info['update'] = OC_Installer::isUpdateAvailable($app);
03e52840d   Kload   Init
814
815
816
817
818
819
  				$info['preview'] = OC_Helper::imagePath('settings', 'trans.png');
  				$info['version'] = OC_App::getAppVersion($app);
  				$appList[] = $info;
  			}
  		}
  		$remoteApps = OC_App::getAppstoreApps();
6d9380f96   Cédric Dupont   Update sources OC...
820
  		if ($remoteApps) {
03e52840d   Kload   Init
821
  			// Remove duplicates
6d9380f96   Cédric Dupont   Update sources OC...
822
823
824
  			foreach ($appList as $app) {
  				foreach ($remoteApps AS $key => $remote) {
  					if ($app['name'] === $remote['name'] ||
f7d878ff1   kload   [enh] Update to 7...
825
826
  						(isset($app['ocsid']) &&
  						$app['ocsid'] ===  $remote['id'])) {
6d9380f96   Cédric Dupont   Update sources OC...
827
  						unset($remoteApps[$key]);
03e52840d   Kload   Init
828
829
830
  					}
  				}
  			}
6d9380f96   Cédric Dupont   Update sources OC...
831
  			$combinedApps = array_merge($appList, $remoteApps);
03e52840d   Kload   Init
832
833
834
  		} else {
  			$combinedApps = $appList;
  		}
6d9380f96   Cédric Dupont   Update sources OC...
835
836
  		// bring the apps into the right order with a custom sort function
  		usort($combinedApps, function ($a, $b) {
31b7f2792   Kload   Upgrade to ownclo...
837

6d9380f96   Cédric Dupont   Update sources OC...
838
839
840
841
  			// priority 1: active
  			if ($a['active'] != $b['active']) {
  				return $b['active'] - $a['active'];
  			}
31b7f2792   Kload   Upgrade to ownclo...
842

6d9380f96   Cédric Dupont   Update sources OC...
843
844
845
846
847
848
  			// priority 2: shipped
  			$aShipped = (array_key_exists('shipped', $a) && $a['shipped'] === 'true') ? 1 : 0;
  			$bShipped = (array_key_exists('shipped', $b) && $b['shipped'] === 'true') ? 1 : 0;
  			if ($aShipped !== $bShipped) {
  				return ($bShipped - $aShipped);
  			}
31b7f2792   Kload   Upgrade to ownclo...
849

6d9380f96   Cédric Dupont   Update sources OC...
850
851
852
853
854
855
  			// priority 3: recommended
  			if ($a['internalclass'] != $b['internalclass']) {
  				$aTemp = ($a['internalclass'] == 'recommendedapp' ? 1 : 0);
  				$bTemp = ($b['internalclass'] == 'recommendedapp' ? 1 : 0);
  				return ($bTemp - $aTemp);
  			}
31b7f2792   Kload   Upgrade to ownclo...
856

6d9380f96   Cédric Dupont   Update sources OC...
857
858
  			// priority 4: alphabetical
  			return strcasecmp($a['name'], $b['name']);
31b7f2792   Kload   Upgrade to ownclo...
859

6d9380f96   Cédric Dupont   Update sources OC...
860
  		});
31b7f2792   Kload   Upgrade to ownclo...
861

6d9380f96   Cédric Dupont   Update sources OC...
862
  		return $combinedApps;
31b7f2792   Kload   Upgrade to ownclo...
863
864
865
  	}
  
  	/**
6d9380f96   Cédric Dupont   Update sources OC...
866
  	 * get a list of all apps on apps.owncloud.com
03e52840d   Kload   Init
867
868
869
  	 * @return array, multi-dimensional array of apps.
  	 *     Keys: id, name, type, typename, personid, license, detailpage, preview, changed, description
  	 */
6d9380f96   Cédric Dupont   Update sources OC...
870
  	public static function getAppstoreApps($filter = 'approved') {
03e52840d   Kload   Init
871
  		$categoryNames = OC_OCSClient::getCategories();
6d9380f96   Cédric Dupont   Update sources OC...
872
  		if (is_array($categoryNames)) {
03e52840d   Kload   Init
873
  			// Check that categories of apps were retrieved correctly
6d9380f96   Cédric Dupont   Update sources OC...
874
  			if (!$categories = array_keys($categoryNames)) {
03e52840d   Kload   Init
875
876
877
878
  				return false;
  			}
  
  			$page = 0;
6d9380f96   Cédric Dupont   Update sources OC...
879
  			$remoteApps = OC_OCSClient::getApplications($categories, $page, $filter);
03e52840d   Kload   Init
880
881
  			$app1 = array();
  			$i = 0;
6d9380f96   Cédric Dupont   Update sources OC...
882
  			foreach ($remoteApps as $app) {
03e52840d   Kload   Init
883
884
885
886
887
  				$app1[$i] = $app;
  				$app1[$i]['author'] = $app['personid'];
  				$app1[$i]['ocs_id'] = $app['id'];
  				$app1[$i]['internal'] = $app1[$i]['active'] = 0;
  				$app1[$i]['update'] = false;
6d9380f96   Cédric Dupont   Update sources OC...
888
889
890
  				$app1[$i]['groups'] = false;
  				$app1[$i]['removable'] = false;
  				if ($app['label'] == 'recommended') {
03e52840d   Kload   Init
891
892
  					$app1[$i]['internallabel'] = 'Recommended';
  					$app1[$i]['internalclass'] = 'recommendedapp';
6d9380f96   Cédric Dupont   Update sources OC...
893
  				} else {
03e52840d   Kload   Init
894
895
896
897
898
899
  					$app1[$i]['internallabel'] = '3rd Party';
  					$app1[$i]['internalclass'] = 'externalapp';
  				}
  
  
  				// rating img
6d9380f96   Cédric Dupont   Update sources OC...
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
  				if ($app['score'] < 5) {
  					$img = OC_Helper::imagePath( "core", "rating/s1.png" );
  				} elseif ($app['score'] < 15) {
  					$img = OC_Helper::imagePath( "core", "rating/s2.png" );
  				} elseif($app['score'] < 25) {
  					$img = OC_Helper::imagePath( "core", "rating/s3.png" );
  				} elseif($app['score'] < 35) {
  					$img = OC_Helper::imagePath( "core", "rating/s4.png" );
  				} elseif($app['score'] < 45) {
  					$img = OC_Helper::imagePath( "core", "rating/s5.png" );
  				} elseif($app['score'] < 55) {
  					$img = OC_Helper::imagePath( "core", "rating/s6.png" );
  				} elseif($app['score'] < 65) {
  					$img = OC_Helper::imagePath( "core", "rating/s7.png" );
  				} elseif($app['score'] < 75) {
  					$img = OC_Helper::imagePath( "core", "rating/s8.png" );
  				} elseif($app['score'] < 85) {
  					$img = OC_Helper::imagePath( "core", "rating/s9.png" );
  				} elseif($app['score'] < 95) {
  					$img = OC_Helper::imagePath( "core", "rating/s10.png" );
  				} elseif($app['score'] < 100) {
  					$img = OC_Helper::imagePath( "core", "rating/s11.png" );
  				}
  
  				$app1[$i]['score'] = '<img src="' . $img . '"> Score: ' . $app['score'] . '%';
03e52840d   Kload   Init
925
926
927
  				$i++;
  			}
  		}
6d9380f96   Cédric Dupont   Update sources OC...
928
  		if (empty($app1)) {
03e52840d   Kload   Init
929
930
931
932
933
  			return false;
  		} else {
  			return $app1;
  		}
  	}
6d9380f96   Cédric Dupont   Update sources OC...
934
935
936
937
938
939
940
941
942
943
944
  	public static function shouldUpgrade($app) {
  		$versions = self::getAppVersions();
  		$currentVersion = OC_App::getAppVersion($app);
  		if ($currentVersion) {
  			$installedVersion = $versions[$app];
  			if (version_compare($currentVersion, $installedVersion, '>')) {
  				return true;
  			}
  		}
  		return false;
  	}
03e52840d   Kload   Init
945
  	/**
03e52840d   Kload   Init
946
947
948
949
  	 * check if the current enabled apps are compatible with the current
  	 * ownCloud version. disable them if not.
  	 * This is important if you upgrade ownCloud and have non ported 3rd
  	 * party apps installed.
6d9380f96   Cédric Dupont   Update sources OC...
950
951
952
953
954
  	 *
  	 * @param array $apps optional app id list to check, uses all enabled apps
  	 * when not specified
  	 *
  	 * @return array containing the list of ids of the disabled apps
03e52840d   Kload   Init
955
956
  	 */
  	public static function checkAppsRequirements($apps = array()) {
6d9380f96   Cédric Dupont   Update sources OC...
957
  		$disabledApps = array();
03e52840d   Kload   Init
958
959
960
961
  		if (empty($apps)) {
  			$apps = OC_App::getEnabledApps();
  		}
  		$version = OC_Util::getVersion();
6d9380f96   Cédric Dupont   Update sources OC...
962
  		foreach ($apps as $app) {
03e52840d   Kload   Init
963
964
  			// check if the app is compatible with this version of ownCloud
  			$info = OC_App::getAppInfo($app);
6d9380f96   Cédric Dupont   Update sources OC...
965
  			if(!self::isAppCompatible($version, $info)) {
03e52840d   Kload   Init
966
  				OC_Log::write('core',
6d9380f96   Cédric Dupont   Update sources OC...
967
968
  					'App "' . $info['name'] . '" (' . $app . ') can\'t be used because it is'
  					. ' not compatible with this version of ownCloud',
03e52840d   Kload   Init
969
  					OC_Log::ERROR);
6d9380f96   Cédric Dupont   Update sources OC...
970
971
972
  				OC_App::disable($app);
  				OC_Hook::emit('update', 'success', 'Disabled ' . $info['name'] . ' app because it is not compatible');
  				$disabledApps[] = $app;
03e52840d   Kload   Init
973
974
  			}
  		}
6d9380f96   Cédric Dupont   Update sources OC...
975
  		return $disabledApps;
03e52840d   Kload   Init
976
  	}
6d9380f96   Cédric Dupont   Update sources OC...
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
  	/**
  	 * Adjust the number of version parts of $version1 to match
  	 * the number of version parts of $version2.
  	 *
  	 * @param string $version1 version to adjust
  	 * @param string $version2 version to take the number of parts from
  	 * @return string shortened $version1
  	 */
  	private static function adjustVersionParts($version1, $version2) {
  		$version1 = explode('.', $version1);
  		$version2 = explode('.', $version2);
  		// reduce $version1 to match the number of parts in $version2
  		while (count($version1) > count($version2)) {
  			array_pop($version1);
  		}
  		// if $version1 does not have enough parts, add some
  		while (count($version1) < count($version2)) {
  			$version1[] = '0';
  		}
  		return implode('.', $version1);
  	}
03e52840d   Kload   Init
998
999
  
  	/**
6d9380f96   Cédric Dupont   Update sources OC...
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
  	 * Check whether the current ownCloud version matches the given
  	 * application's version requirements.
  	 *
  	 * The comparison is made based on the number of parts that the
  	 * app info version has. For example for ownCloud 6.0.3 if the
  	 * app info version is expecting version 6.0, the comparison is
  	 * made on the first two parts of the ownCloud version.
  	 * This means that it's possible to specify "requiremin" => 6
  	 * and "requiremax" => 6 and it will still match ownCloud 6.0.3.
  	 *
  	 * @param string $ocVersion ownCloud version to check against
  	 * @param array  $appInfo app info (from xml)
  	 *
03e52840d   Kload   Init
1013
1014
  	 * @return boolean true if compatible, otherwise false
  	 */
6d9380f96   Cédric Dupont   Update sources OC...
1015
1016
1017
1018
1019
1020
1021
1022
  	public static function isAppCompatible($ocVersion, $appInfo){
  		$requireMin = '';
  		$requireMax = '';
  		if (isset($appInfo['requiremin'])) {
  			$requireMin = $appInfo['requiremin'];
  		} else if (isset($appInfo['require'])) {
  			$requireMin = $appInfo['require'];
  		}
03e52840d   Kload   Init
1023

6d9380f96   Cédric Dupont   Update sources OC...
1024
1025
1026
  		if (isset($appInfo['requiremax'])) {
  			$requireMax = $appInfo['requiremax'];
  		}
03e52840d   Kload   Init
1027

6d9380f96   Cédric Dupont   Update sources OC...
1028
1029
1030
  		if (is_array($ocVersion)) {
  			$ocVersion = implode('.', $ocVersion);
  		}
03e52840d   Kload   Init
1031

6d9380f96   Cédric Dupont   Update sources OC...
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
  		if (!empty($requireMin)
  			&& version_compare(self::adjustVersionParts($ocVersion, $requireMin), $requireMin, '<')
  		) {
  
  			return false;
  		}
  
  		if (!empty($requireMax)
  			&& version_compare(self::adjustVersionParts($ocVersion, $requireMax), $requireMax, '>')
  		) {
  
  			return false;
03e52840d   Kload   Init
1044
1045
1046
1047
  		}
  
  		return true;
  	}
03e52840d   Kload   Init
1048
1049
1050
1051
1052
  	/**
  	 * get the installed version of all apps
  	 */
  	public static function getAppVersions() {
  		static $versions;
6d9380f96   Cédric Dupont   Update sources OC...
1053
  		if (isset($versions)) { // simple cache, needs to be fixed
03e52840d   Kload   Init
1054
1055
  			return $versions; // when function is used besides in checkUpgrade
  		}
6d9380f96   Cédric Dupont   Update sources OC...
1056
1057
1058
  		$versions = array();
  		$query = OC_DB::prepare('SELECT `appid`, `configvalue` FROM `*PREFIX*appconfig`'
  			. ' WHERE `configkey` = \'installed_version\'');
03e52840d   Kload   Init
1059
  		$result = $query->execute();
6d9380f96   Cédric Dupont   Update sources OC...
1060
1061
  		while ($row = $result->fetchRow()) {
  			$versions[$row['appid']] = $row['configvalue'];
03e52840d   Kload   Init
1062
1063
1064
  		}
  		return $versions;
  	}
6d9380f96   Cédric Dupont   Update sources OC...
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
  
  	/**
  	 * @param mixed $app
  	 * @return bool
  	 * @throws Exception if app is not compatible with this version of ownCloud
  	 * @throws Exception if no app-name was specified
  	 */
  	public static function installApp($app) {
  		$l = OC_L10N::get('core');
  		$appData=OC_OCSClient::getApplication($app);
  
  		// check if app is a shipped app or not. OCS apps have an integer as id, shipped apps use a string
  		if(!is_numeric($app)) {
  			$shippedVersion=self::getAppVersion($app);
  			if($appData && version_compare($shippedVersion, $appData['version'], '<')) {
  				$app = self::downloadApp($app);
  			} else {
  				$app = OC_Installer::installShippedApp($app);
  			}
  		}else{
  			$app = self::downloadApp($app);
  		}
  
  		if($app!==false) {
  			// check if the app is compatible with this version of ownCloud
  			$info = self::getAppInfo($app);
  			$version=OC_Util::getVersion();
  			if(!self::isAppCompatible($version, $info)) {
  				throw new \Exception(
  					$l->t('App \"%s\" can\'t be installed because it is not compatible with this version of ownCloud.',
  						array($info['name'])
  					)
  				);
  			}else{
  				OC_Appconfig::setValue( $app, 'enabled', 'yes' );
  				if(isset($appData['id'])) {
  					OC_Appconfig::setValue( $app, 'ocsid', $appData['id'] );
  				}
  				\OC_Hook::emit('OC_App', 'post_enable', array('app' => $app));
  			}
  		}else{
  			throw new \Exception($l->t("No app name specified"));
  		}
  
  		return $app;
  	}
03e52840d   Kload   Init
1111
1112
  	/**
  	 * update the database for the app and call the update script
6d9380f96   Cédric Dupont   Update sources OC...
1113
1114
1115
  	 *
  	 * @param string $appId
  	 * @return bool
03e52840d   Kload   Init
1116
  	 */
6d9380f96   Cédric Dupont   Update sources OC...
1117
1118
  	public static function updateApp($appId) {
  		if (file_exists(self::getAppPath($appId) . '/appinfo/preupdate.php')) {
f7d878ff1   kload   [enh] Update to 7...
1119
  			self::loadApp($appId, false);
6d9380f96   Cédric Dupont   Update sources OC...
1120
  			include self::getAppPath($appId) . '/appinfo/preupdate.php';
03e52840d   Kload   Init
1121
  		}
6d9380f96   Cédric Dupont   Update sources OC...
1122
1123
  		if (file_exists(self::getAppPath($appId) . '/appinfo/database.xml')) {
  			OC_DB::updateDbFromStructure(self::getAppPath($appId) . '/appinfo/database.xml');
03e52840d   Kload   Init
1124
  		}
6d9380f96   Cédric Dupont   Update sources OC...
1125
1126
  		if (!self::isEnabled($appId)) {
  			return false;
03e52840d   Kload   Init
1127
  		}
6d9380f96   Cédric Dupont   Update sources OC...
1128
  		if (file_exists(self::getAppPath($appId) . '/appinfo/update.php')) {
f7d878ff1   kload   [enh] Update to 7...
1129
  			self::loadApp($appId, false);
6d9380f96   Cédric Dupont   Update sources OC...
1130
  			include self::getAppPath($appId) . '/appinfo/update.php';
03e52840d   Kload   Init
1131
1132
1133
  		}
  
  		//set remote/public handlers
6d9380f96   Cédric Dupont   Update sources OC...
1134
1135
1136
  		$appData = self::getAppInfo($appId);
  		if (array_key_exists('ocsid', $appData)) {
  			OC_Appconfig::setValue($appId, 'ocsid', $appData['ocsid']);
03e52840d   Kload   Init
1137
  		}
6d9380f96   Cédric Dupont   Update sources OC...
1138
1139
  		foreach ($appData['remote'] as $name => $path) {
  			OCP\CONFIG::setAppValue('core', 'remote_' . $name, $appId . '/' . $path);
03e52840d   Kload   Init
1140
  		}
6d9380f96   Cédric Dupont   Update sources OC...
1141
1142
1143
1144
1145
  		foreach ($appData['public'] as $name => $path) {
  			OCP\CONFIG::setAppValue('core', 'public_' . $name, $appId . '/' . $path);
  		}
  
  		self::setAppTypes($appId);
03e52840d   Kload   Init
1146

f7d878ff1   kload   [enh] Update to 7...
1147
1148
  		$version = \OC_App::getAppVersion($appId);
  		\OC_Appconfig::setValue($appId, 'installed_version', $version);
6d9380f96   Cédric Dupont   Update sources OC...
1149
  		return true;
03e52840d   Kload   Init
1150
1151
1152
  	}
  
  	/**
6d9380f96   Cédric Dupont   Update sources OC...
1153
  	 * @param string $appId
03e52840d   Kload   Init
1154
1155
  	 * @return \OC\Files\View
  	 */
6d9380f96   Cédric Dupont   Update sources OC...
1156
1157
1158
1159
1160
1161
  	public static function getStorage($appId) {
  		if (OC_App::isEnabled($appId)) { //sanity check
  			if (OC_User::isLoggedIn()) {
  				$view = new \OC\Files\View('/' . OC_User::getUser());
  				if (!$view->file_exists($appId)) {
  					$view->mkdir($appId);
03e52840d   Kload   Init
1162
  				}
6d9380f96   Cédric Dupont   Update sources OC...
1163
1164
1165
  				return new \OC\Files\View('/' . OC_User::getUser() . '/' . $appId);
  			} else {
  				OC_Log::write('core', 'Can\'t get app storage, app ' . $appId . ', user not logged in', OC_Log::ERROR);
03e52840d   Kload   Init
1166
1167
  				return false;
  			}
6d9380f96   Cédric Dupont   Update sources OC...
1168
1169
  		} else {
  			OC_Log::write('core', 'Can\'t get app storage, app ' . $appId . ' not enabled', OC_Log::ERROR);
03e52840d   Kload   Init
1170
1171
1172
1173
  			return false;
  		}
  	}
  }