1<?php
2/*
3 * Gallery - a web based photo album viewer and editor
4 * Copyright (C) 2000-2008 Bharat Mediratta
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or (at
9 * your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA  02110-1301, USA.
19 */
20
21if (!defined('G2_SUPPORT')) { return; }
22
23/* Commands */
24define('CMD_CHMOD_MODULES_AND_THEMES_DIR', 'chmodModulesAndThemesDir');
25define('CMD_ADVANCED', 'advanced');
26define('CMD_CHMOD_PLUGIN_DIR', 'chmodPluginDir');
27define('CMD_CHMOD_GALLERY_DIR', 'chmodGalleryDir');
28define('CMD_CHMOD_STORAGE_DIR', 'chmodStorageDir');
29define('CMD_CHMOD_LOCALE_DIR', 'chmodLocaleDir');
30/* For get/post input sanitation */
31require_once(dirname(__FILE__) . '/../../modules/core/classes/GalleryUtilities.class');
32
33$DEFAULT_FOLDER_PERMISSIONS = PermissionBits::fromString('555');
34$DEFAULT_FILE_PERMISSIONS = PermissionBits::fromString('444');
35
36$status = array();
37$ret = null;
38
39/* The permission bit sets that we accept / handle. */
40$permissionBitSets = getPermissionSets();
41/* Gather a complete list of plugins in this installation. */
42$plugins = getPluginList();
43
44/* Process inputs and set some variables to default values */
45
46$path = getRequestVariable('path');
47if (empty($path)) {
48    $path = getGalleryStoragePath();
49} else {
50    /*
51     * $path is used in a chmod() call and we output the path in the HTML.
52     * Just do some very basic sanitation.
53     */
54    GalleryUtilities::sanitizeInputValues($path);
55}
56/* Some basic sanitation */
57$path = str_replace('..', '', $path);
58if (!file_exists($path)) {
59    /* TODO: add open_basedir check */
60    $status['error'][] = "Folder or file '$path' does not exist!";
61}
62
63/* Permissions (format e.g. 755644, split after 3 characters to get 755 and 644)*/
64$permissions = (string)getRequestVariable('permissions');
65if (empty($permissions)) {
66    $permissions = $DEFAULT_FOLDER_PERMISSIONS->getAsString() .
67    		   $DEFAULT_FILE_PERMISSIONS->getAsString();
68}
69if (strlen($permissions) != 6) {
70    $status['error'][] =
71	"Unknown permissions '$permissions'! Aborting action and resetting permissions.";
72}
73if (empty($status['error'])) {
74    $folderPermissions = PermissionBits::fromString(substr($permissions, 0, 3));
75    $filePermissions = PermissionBits::fromString(substr($permissions, 3, 3));
76    if (!$folderPermissions->isValid()) {
77	$status['error'][] =
78	    'Invalid folder permissions! Aborting action and resetting permissions.';
79	$folderPermissions = $DEFAULT_FOLDER_PERMISSIONS;
80    }
81    if (!$filePermissions->isValid()) {
82	$status['error'][] = 'Invalid file permissions! Aborting action and resetting permissions.';
83	$filePermissions = $DEFAULT_FILE_PERMISSIONS;
84    }
85} else {
86    $folderPermissions = $DEFAULT_FOLDER_PERMISSIONS;
87    $filePermissions = $DEFAULT_FILE_PERMISSIONS;
88}
89
90/************************************************************
91 * Main program section
92 ************************************************************/
93
94printPageWithoutFooter($plugins, $path, $filePermissions, $folderPermissions, $permissionBitSets);
95
96if (empty($status['error'])) {
97    $command = trim(getRequestVariable('command'));
98    switch ($command) {
99    case CMD_ADVANCED:
100        /* Advanced Options, allow chmod of any folder / file */
101        $ret = chmodRecursively($path, $folderPermissions->getAsInt(),
102		     $filePermissions->getAsInt(), time() - 60);
103	if (!empty($ret)) {
104            $status['error'][] = "Failed to change the filesystem permissions "
105		. "of '$path'.";
106        } else {
107	    $status['message'] = "Successfully changed the filesystem permissions "
108		. "of '$path'.";
109        }
110        break;
111    case CMD_CHMOD_MODULES_AND_THEMES_DIR:
112        /* Chmod the modules/ and themes/ dir writeable or read-only (not recursively) */
113        $mode = getRequestVariable('mode');
114        if (!in_array($mode, array('open', 'secure'))) {
115            $status['error'][] = "Unknown mode '$mode'. Please try again.";
116        } else {
117            $ret = chmodModulesAndThemesDir($mode == 'open');
118            if (!empty($ret)) {
119                $status['error'][] = 'Failed to change the filesystem permissions '
120		    . 'of the modules/ and themes/ folder.';
121            } else {
122            	$status['message'] = 'Successfully changed the filesystem permissions '
123		    . 'of the modules/ and the themes/ folder.';
124            }
125        }
126        break;
127    case CMD_CHMOD_PLUGIN_DIR:
128        /* Chmod a _specific_ plugin (theme or module) writeable or read-only (recursively) */
129        $mode = getRequestVariable('mode');
130
131        /* Check the given plugin path against a white list */
132        $pluginPath = getRequestVariable('pluginId');
133        if (!isset($plugins[$pluginPath])) {
134            $status['error'][] = "Unknown plugin path '$pluginPath'.";
135        } else if (!in_array($mode, array('open', 'secure'))) {
136            $status['error'][] = "Unknown mode '$mode'. Please try again.";
137        } else {
138            $ret = chmodPluginDir($pluginPath, $mode == 'open');
139            if (!empty($ret)) {
140                $status['error'][] = "Failed to change the filesystem permissions "
141		    . "of the '$pluginPath' folder.";
142            } else {
143            	$status['message'] = "Successfully changed the filesystem permissions "
144		    . "of the '$pluginPath' folder.";
145            }
146        }
147
148        break;
149    case CMD_CHMOD_GALLERY_DIR:
150        /* Chmod the whole gallery2 dir writeable or read-only */
151        $mode = getRequestVariable('mode');
152        if (!in_array($mode, array('open', 'secure'))) {
153            $status['error'][] = "Unknown mode '$mode'. Please try again.";
154        } else {
155            $ret = chmodGalleryDirRecursively($mode == 'open');
156            if (!empty($ret)) {
157                $status['error'][] = 'Failed to change the filesystem permissions '
158		    . 'of the Gallery folder.';
159            } else {
160            	$status['message'] = 'Successfully changed the filesystem permissions '
161		    . 'of the Gallery folder.';
162            }
163        }
164        break;
165    case CMD_CHMOD_STORAGE_DIR:
166        /* Chmod the entire storage dir writeable */
167	$ret = chmodStorageDirRecursively();
168	if (!empty($ret)) {
169            $status['error'][] = 'Failed to change the filesystem permissions '
170		. 'of the storage folder.';
171        } else {
172            $status['message'] = 'Successfully changed the filesystem permissions '
173		. 'of the storage folder.';
174        }
175        break;
176    case CMD_CHMOD_LOCALE_DIR:
177        /* Chmod the entire locale dir writeable */
178	$ret = chmodLocaleDirRecursively();
179	if (!empty($ret)) {
180            $status['error'][] = 'Failed to change the filesystem permissions '
181		. 'of the locale folder.';
182        } else {
183            $status['message'] = 'Successfully changed the filesystem permissions '
184		. 'of the locale folder.';
185        }
186        break;
187    default:
188       /* Just redisplay the page. */
189       break;
190    }
191}
192printStatus($status);
193
194printFooter();
195
196/************************************************************
197 * Functions and Classes
198 ************************************************************/
199
200/**
201 * Changes the filesystem permissions of a file or a folder recursively.  Also prints out folder
202 * names online on success / error and prints out filenames on error as well.
203 *
204 * @param string $filename absolute path to folder/file that should be chmod'ed
205 * @param int $folderPermissions (octal) new permissions for folders
206 * @param int $filePermissions (octal) new permissions for files
207 * @param int $start unix timestamp of last webserver/php timeout counter-measure
208 * @return null on success, int <> 0 on error
209 */
210function chmodRecursively($filename, $folderPermissions, $filePermissions, $start) {
211    $filename = rtrim($filename, '\\/');
212    $error = 0;
213    /* Try to prevent timeouts */
214    if (time() - $start > 55) {
215	if (function_exists('apache_reset_timeout')) {
216    	    @apache_reset_timeout();
217    	}
218    	@set_time_limit(600);
219	$start = time();
220    }
221    /*
222     * Have to chmod first before the is_dir check because is_dir does a stat on the
223     * file / dir which fails if the permissions are too tight.
224     * Chmod to filepermissions since the majority of the chmod() calls will be for
225     * files anyway and then change the permissions for folders with a second call.
226     */
227    if (!@chmod($filename, $filePermissions)) {
228    	error("[ERROR]", $filename);
229    	$error = 1;
230    }
231    if (is_dir($filename)) {
232    	/* For folders, we change the permissions to the right ones with a second chmod call. */
233    	if (!$error) {
234            if (!@chmod($filename, $folderPermissions)) {
235    	        error("[ERROR]", $filename);
236    	        $error = 1;
237	    } else {
238	        status("[OK]", $filename);
239    	    }
240        }
241    	/*
242    	 * Recurse into subdirectories: Open all files / sub-dirs and change the
243    	 * permissions recursively.
244    	 */
245	if ($fd = opendir($filename)) {
246	    while (($child = readdir($fd)) !== false) {
247		if ($child == '.' || $child == '..') {
248		    continue;
249		}
250		$fullpath = "$filename/$child";
251		$ret = chmodRecursively($fullpath, $folderPermissions,
252					$filePermissions, $start);
253		$error |= $ret;
254	    }
255	    closedir($fd);
256	} else {
257	    error("Cannot open directory", $filename);
258	    return 1;
259	}
260    }
261
262    if ($error) {
263	return 1;
264    }
265
266    return null;
267}
268
269/**
270 * Returns the predefined / acceptable permission bit sets for folders and files
271 * as strings. Use as-is for HTML output, convert to integer (octdec) for chmod().
272 *
273 * @return array(array(string folder permission) )
274 */
275function getPermissionSets() {
276    $permissionSets = array();
277
278    $permissionSets[] = array(PermissionBits::fromString("777"),
279    			      PermissionBits::fromString("666"));
280    $permissionSets[] = array(PermissionBits::fromString("555"),
281    			      PermissionBits::fromString("444"));
282    $permissionSets[] = array(PermissionBits::fromString("755"),
283    			      PermissionBits::fromString("644"));
284    return $permissionSets;
285}
286
287function getGalleryStoragePath() {
288    $config = GallerySetupUtilities::getGalleryConfig();
289    return $config['data.gallery.base'];
290}
291
292/**
293 * Class to represent a set of filesystem permission bits, eg. 0755 with a few convenience methods.
294 */
295class PermissionBits {
296    /**
297     * Bits in octal integer representation, e.g. 0755
298     */
299    var $_bits;
300
301    /**
302     * Constructor
303     * @param int $bits permission bits in decimal integer representation, eg. octdec(0755)
304     */
305    function PermissionBits($bits) {
306    	$this->_bits = decoct($bits);
307    }
308
309    /**
310     * Returns a new PermissionBits object
311     * @param string $bitsAsString permission set in string representation, e.g. "755"
312     * @return PermissionBits object
313     * @static
314     */
315    function fromString($bitsAsString) {
316    	$bitsAsString = (string)$bitsAsString;
317    	if (strlen($bitsAsString) && $bitsAsString{0} != '0') {
318    	    $bitsAsString = '0' . $bitsAsString;
319    	}
320    	return new PermissionBits(octdec($bitsAsString));
321    }
322
323    function getAsString() {
324    	return (string)$this->_bits;
325    }
326
327    /**
328     * For use with chmod()
329     * @return int the permission set as decimal integer
330     */
331    function getAsInt() {
332    	return octdec($this->_bits);
333    }
334
335    /**
336     * Returns a concise description of this permission set
337     * @XXX rethink the whole concept, maybe just show a owner/group/world vs. r+w+x matrix
338     */
339    function getDescription() {
340    	switch (intval($this->_bits, 8)) {
341    	    case 0777:
342		return 'Read + Write + Execute for Everyone';
343	    case 0555:
344		return 'Read + Execute for Everyone';
345	    case 0666:
346		return 'Read And Write for Everyone';
347	    case 0444:
348		return 'Read Only for Everyone, Including Owner';
349	    case 0755:
350		return 'Read + Execute for Everyone, Plus Write for Owner';
351	    case 0644:
352		return 'Read And Write for Owner, Read for Everyone Else';
353	    default:
354	        /* No description available */
355	        return null;
356    	}
357    }
358
359    function getAsDescriptiveString() {
360    	return $this->getAsString() . ' (' . $this->getDescription() . ' )';
361    }
362
363    function equals($permissionBits) {
364        return $this->getAsInt() == $permissionBits->getAsInt();
365    }
366
367    function isValid() {
368    	$description = $this->getDescription();
369    	return !empty($description);
370    }
371}
372
373/* Functions which control the HTML output of the page. */
374$errorBoxOpen = 0;
375function status($msg, $obj) {
376    openErrorBox();
377    printf("$msg&nbsp;<b>%s</b><br/>", wordwrap($obj, 85, "<br/>&nbsp;&nbsp;&nbsp;", true));
378}
379
380function error($msg, $obj) {
381    openErrorBox();
382    print '<span class="error">';
383    printf("$msg&nbsp;<b>%s</b><br/>", wordwrap($obj, 85, "<br/>&nbsp;&nbsp;&nbsp;", true));
384    print '</span>';
385}
386
387function isModulesOrThemesDirWriteable() {
388    return is_writeable(GallerySetupUtilities::getConfigDir() . '/modules/') &&
389        is_writeable(GallerySetupUtilities::getConfigDir() . '/themes/');
390}
391
392/**
393 * Make the themes/ and modules/ dir writeable or read-only
394 * @param boolean $makeItWriteable true to make the dirs writeable, false to make them read-only
395 * @return null on success, non 0 integer on error
396 */
397function chmodModulesAndThemesDir($makeItWriteable) {
398    $mode = $makeItWriteable ? 0777 : 0555;
399    $ret = null;
400    foreach (array('/modules/', '/themes/') as $dir) {
401    	if (file_exists(GallerySetupUtilities::getConfigDir() . $dir)) {
402    	    /* Try to chmod all dirs, even if one fails */
403	    if (!@chmod(GallerySetupUtilities::getConfigDir() . $dir, $mode)) {
404		error("[ERROR]", GallerySetupUtilities::getConfigDir() . $dir);
405	        $ret = 1;
406	    }
407    	}
408    }
409    return $ret;
410}
411
412function isGalleryDirWriteable() {
413    return is_writeable(GallerySetupUtilities::getConfigDir());
414}
415
416/**
417 * Chmod the whole gallery dir recursively either read-only or writeable
418 * @param boolean $makeItWriteable true to make the dirs writeable, false to make them read-only
419 * @return null on success, non 0 integer on error
420 */
421function chmodGalleryDirRecursively($makeItWriteable) {
422    /* This is just a wrapper function for the general chmod recursively function */
423    $folderMode = $makeItWriteable ? 0777 : 0555;
424    $fileMode = $makeItWriteable ? 0666 : 0444;
425    return chmodRecursively(GallerySetupUtilities::getConfigDir(), $folderMode, $fileMode,
426			    time() - 60);
427}
428
429/* Chmod a specific plugin dir recursively */
430function chmodPluginDir($pluginPath, $makeItWriteable) {
431    /* This is just a wrapper function for the general chmod recursively function */
432    $folderMode = $makeItWriteable ? 0777 : 0555;
433    $fileMode = $makeItWriteable ? 0666 : 0444;
434    return chmodRecursively(GallerySetupUtilities::getConfigDir() . $pluginPath, $folderMode,
435			    $fileMode, time() - 60);
436}
437
438function chmodStorageDirRecursively() {
439    /* This is just a wrapper function for the general chmod recursively function */
440    return chmodRecursively(getGalleryStoragePath(), 0777, 0666, time() - 60);
441}
442
443function chmodLocaleDirRecursively() {
444    /* This is just a wrapper function for the general chmod recursively function */
445    return chmodRecursively(getGalleryStoragePath() . 'locale', 0777, 0666, time() - 60);
446}
447
448/**
449 * @return array (pluginId => boolean writeable, .. )
450 */
451function getPluginList() {
452    /*
453     * We don't want to depend on the G2 API here, so just list the folders in
454     * modules/, themes/ and in plugins/modules/, plugins/themes/.
455     * We prefer being indepdent of the state of G2 over flexibility (e.g. if the
456     * user hacked init.inc to set a different plugins dir name).
457     */
458    $plugins = array();
459    foreach (array('/modules/', '/themes/') as $base) {
460	if (!file_exists(GallerySetupUtilities::getConfigDir() . $base)) {
461	    continue;
462	}
463	$fh = opendir(GallerySetupUtilities::getConfigDir() . $base);
464	if (empty($fh)) {
465	  continue;
466        }
467
468	/* For each folder in the plugin dir, check if it's writeable */
469	while (($folderName = readdir($fh)) !== false) {
470	    if ($folderName == '.' || $folderName == '..' || $folderName == '.svn') {
471		continue;
472	    }
473	    $pluginId = $base . trim($folderName);
474	    if ((int)is_dir(GallerySetupUtilities::getConfigDir() . $base . $folderName)) {
475                $plugins[$pluginId] = (int)is_writeable(
476                	GallerySetupUtilities::getConfigDir() . $base . $folderName);
477            }
478    	}
479	closedir($fh);
480    }
481    ksort($plugins);
482    return $plugins;
483}
484
485function getRequestVariable($varName) {
486    foreach (array($_POST, $_GET) as $requestVars) {
487	if (isset($requestVars[$varName])) {
488	    return $requestVars[$varName];
489	}
490    }
491
492    return null;
493}
494
495/*
496 * Uses JavaScript to print the status / error message at the top of the page
497 * even if the page has already been printed.
498 */
499function printStatus($status) {
500    if (!empty($status['error'])) {
501	printf('<script type="text/javascript">printErrorMessage(\'%s\');</script>',
502	       str_replace(array("\\", "'"), array("\\\\", "\\'"),
503	       		   implode('<br/>', $status['error'])));
504    }
505    if (!empty($status['message'])) {
506	printf('<script type="text/javascript">printStatusMessage(\'%s\');</script>',
507	       str_replace(array("\\", "'"), array("\\\\", "\\'"), $status['message']));
508    }
509}
510
511/************************************************************
512 * HTML - The Page layout / GUI
513 ************************************************************/
514
515/**
516 * Prints the whole page including form but without the footer.
517 * Call this function, then call chmodRecursively() which will output some HTML,
518 * and finally call printFooter();
519 */
520function printPageWithoutFooter($plugins, $path, $filePermissions, $folderPermissions, $permissionBitSets) {
521    global $baseUrl;
522?>
523<html>
524  <head>
525    <title>Gallery Support - Change Filesystem Permissions</title>
526    <link rel="stylesheet" type="text/css" href="<?php print $baseUrl ?>support.css"/>
527    <style type="text/css">
528    </style>
529    <script type="text/javascript">
530      var plugins = new Array();
531      <?php foreach ($plugins as $pluginId => $isOpenForEdit) {
532        print "plugins['$pluginId'] = $isOpenForEdit;
533        ";
534      } ?>
535
536      function setEditOrSecure(pluginId, formObj) {
537        if (pluginId == -1) {
538	  formObj.mode.value='';
539	  formObj.open.disabled = true;
540	  formObj.secure.disabled = true;
541        } else if (plugins[pluginId]) {
542	  formObj.mode.value='secure';
543	  formObj.open.disabled = true;
544	  formObj.secure.disabled = false;
545        } else {
546	  formObj.mode.value='open';
547	  formObj.open.disabled = false;
548	  formObj.secure.disabled = true;
549        }
550      }
551
552      function printStatusMessage(message) {
553        var statusElement = document.getElementById('status');
554        statusElement.innerHTML = message + "<a href=\"#details\">[details]</a>";
555        statusElement.style.display = 'block';
556      }
557
558      function printErrorMessage(message) {
559        var errorElement = document.getElementById('error');
560        errorElement.innerHTML = message +
561          "<br/>Note: Please look at the <a href=\"#details\">[details]</a>. " +
562          "You might be able to change the filesystem permissions of the failed directories " +
563          "successfully yourself with an FTP program or a command line shell."
564        errorElement.style.display = 'block';
565      }
566    </script>
567  </head>
568
569  <body>
570    <div id="content">
571      <div id="title">
572	<a href="../../">Gallery</a> &raquo;
573	<a href="<?php generateUrl('index.php') ?>">Support</a> &raquo;
574	Change Filesystem Permissions
575      </div>
576      <h2>
577        This tool lets you change the filesystem permissions of files and folders owned
578        by the webserver.
579      </h2>
580      <p>
581        All files and folders in your Gallery storage folder are owned by the
582        webserver. If you installed Gallery2 by unpacking a .zip or .tar.gz file, then the
583        gallery2 folder is probably owned by you which means that you can edit the files
584        directly.  However, if you used the preinstaller then your gallery2 directory is
585        also owned by the webserver. For more information, see the <b><a
586        href="http://codex.gallery2.org/Gallery2:Security">Gallery Security Guide</a>.</b>
587      </p>
588
589      <!-- Identifyable placeholders such that we can insert our messages during runtime via JS. -->
590      <div id="error" class="error" style="display: none;">
591        &nbsp;
592      </div>
593
594      <div id="status" class="success" style="display: none;">
595        &nbsp;
596      </div>
597
598      <hr class="faint"/>
599
600      <?php if (!isModulesOrThemesDirWriteable()): ?>
601      <h2>
602	<a href="<?php generateUrl('index.php?chmod&amp;command=' . CMD_CHMOD_MODULES_AND_THEMES_DIR
603	 . '&amp;mode=open') ?>">Make modules &amp; themes directories writeable</a>
604      </h2>
605      <p class="description">
606	Useful when adding a new module or theme.  This makes your modules and
607	themes folders writeable. It only works if you have installed Gallery with the
608	pre-installer. Usually you can change the filesystem permissions with your FTP
609	program or command line shell.
610      </p>
611      <?php else: ?>
612      <h2>
613	<a href="<?php generateUrl('index.php?chmod&amp;command=' . CMD_CHMOD_MODULES_AND_THEMES_DIR
614	 . '&amp;mode=secure') ?>">Make modules &amp; themes directories read-only</a>
615      </h2>
616      <p class="description">
617	Useful when you're not going to be making changes by hand. This makes your
618	modules and themes folders writeable. Only works if you have installed Gallery
619	with the pre-installer. Usually you can change the filesystem permissions with
620	your FTP program or command line shell.
621      </p>
622      <?php endif; ?>
623
624      <hr class="faint"/>
625
626      <?php startForm('index.php?chmod&amp;command=' . CMD_CHMOD_PLUGIN_DIR, 'pluginForm'); ?>
627	<h2 id="themeOrModule">
628	  Make a specific theme or module editable
629	</h2>
630	<p class="description">
631	  If you want to edit a page template file of a specific module or theme and your
632	  Gallery was originally installed with the pre-installer, you might have to make
633	  the corresponding plugin folder writeable first.
634	</p>
635	<p class="description">
636	  <select name="pluginId"
637	    onchange="setEditOrSecure(this.options[this.selectedIndex].value, this.form)">
638	    <option value="-1">&laquo; select a module or theme &raquo;</option>
639	    <?php foreach ($plugins as $pluginId => $writeable): ?>
640	    <option value="<?php print $pluginId ?>"> <?php print $pluginId ?> </option>
641	    <?php endforeach; ?>
642	  </select>
643	  &nbsp;&nbsp;
644	  <input type="hidden" name="mode" value="open"/>
645	  <input type="submit" disabled="disabled" name="open" value="Make it open (read/write)"/> |
646	  <input type="submit" disabled="disabled" name="secure" value="Make it secure (read-only)"/>
647	</p>
648      </form>
649
650      <hr class="faint"/>
651
652      <h2><a href="<?php generateUrl('index.php?chmod&amp;command=' . CMD_CHMOD_STORAGE_DIR)
653      ?>">Make the data folder read/write</a></h2>
654      <p class="description">
655        For some reason, your Gallery data folder might no longer be writeable by Gallery itself
656        and if that happens, Gallery will usually show a ERROR_PLATFORM_FAILURE. In that case the
657        problem might be solved by the above action. If the problem persists, you will have to talk
658        to your webhost to get data folder writeable again.
659      </p>
660
661      <hr class="faint"/>
662
663      <h2><a href="<?php generateUrl('index.php?chmod&amp;command=' . CMD_CHMOD_LOCALE_DIR)
664      ?>">Make the locale folder read/write</a></h2>
665      <p class="description">
666        If you're localizing Gallery, you may see warnings when you compile up your localization
667        since you may not have permissions to copy the the new localized version into your
668        g2data/locale folder.  Making the locale folder read/write should solve this problem.
669      </p>
670
671      <hr class="faint"/>
672
673      <?php if (isGalleryDirWriteable()): ?>
674      <h2><a href="<?php generateUrl('index.php?chmod&amp;command=' . CMD_CHMOD_GALLERY_DIR)
675      ?>&amp;mode=open">Make everything read/write</a></h2>
676      <p class="description">
677        If your Gallery has been installed with the pre-installer, you might have to make the
678        whole Gallery directory structure read/write before you can upgrade or delete your
679        installation.
680      </p>
681      <?php else: ?>
682      <h2><a href="<?php generateUrl('index.php?chmod&amp;command=' . CMD_CHMOD_GALLERY_DIR)
683      ?>&amp;mode=secure">Make everything read-only</a></h2>
684      <p class="description">
685        If your Gallery has been installed with the pre-installer you may want to change
686        all your files back to read-only for a small amount of additional security.
687      </p>
688      <?php endif; ?>
689
690      <hr class="faint"/>
691
692      <h2>Advanced: Choose the path and the permissions manually</h2>
693      <?php startForm('index.php?chmod&amp;command=' . CMD_ADVANCED); ?>
694	<p class="description">
695	  <b> Path to change: </b>
696	  <input type="text" name="path" size="50" value="<?php print $path; ?>"/>
697          <br/>
698	  <span class="subtext">
699	    Gallery folder: <i><?php print GallerySetupUtilities::getConfigDir(); ?></i> <br/>
700            Gallery data folder: <i><?php print getGalleryStoragePath(); ?></i> <br/>
701	  </span>
702          <br/>
703          <b> New permissions: </b>
704	  <?php
705	   foreach ($permissionBitSets as $permissionBitSet):
706	       $checked = $permissionBitSet[1]->equals($filePermissions) ? 'checked="checked"' : '';
707	       $value = $permissionBitSet[0]->getAsString() . $permissionBitSet[1]->getAsString();
708          ?>
709	  <br/>
710	  <input id="set_<?php print $value?>" type="radio" name="permissions" value="<?php print $value ?>" <?php print $checked ?>>
711	    <label for="set_<?php print $value?>">
712	      <span class="hasToolTip" title="Files: <?php print $permissionBitSet[1]->getAsString(); ?>, Folders: <?php print $permissionBitSet[0]->getAsString(); ?>"> <?php print $permissionBitSet[1]->getDescription() ?></span>
713	    </label>
714	  </input>
715	  <?php endforeach; ?>
716	  <br/><br/>
717
718          <input type="submit" value="Change the Permissions now!"/>
719        </p>
720      </form>
721<?php
722} // end function printPageWithoutFooter()
723
724function openErrorBox() {
725    global $errorBoxOpen;
726    if ($errorBoxOpen) {
727      return;
728    }
729    $errorBoxOpen = 1;
730?>
731      <a name="details"></a>
732      <div id="details" class="results">
733        <h2>Details:</h2>
734<?php
735} // end function openErrorBox() {
736
737function closeErrorBox() {
738    global $errorBoxOpen;
739    if (!$errorBoxOpen) {
740        return;
741    }
742?>
743      </div>
744<?php
745} // end function closeErrorBox()
746
747function printFooter() {
748    closeErrorBox();
749?>
750    </div>
751  </body>
752</html>
753<?php
754} // end function printFooter()
755?>
756