Index: extensions/Icy_Picture_Modify/CHANGELOG
===================================================================
--- extensions/Icy_Picture_Modify/CHANGELOG	(revision 16494)
+++ extensions/Icy_Picture_Modify/CHANGELOG	(revision 16495)
@@ -1,6 +1,19 @@
+2.0.0 2012-07-09
+
+  - Advance ACL support in local ZAML file
+  - Upload permission can be specified in new ACL
+  - Doesn't require any settings from the plugin `community`
+
 1.1.2 2012-07-04
 
   - Make plugin compatible with Piwigo 2.3.5 and Piwigo 2.4.1
   - Fix minor bugs. Fix caching issue when updating images.
+
+1.2.0 2012-01-07
+
+  - Support advanced ACL in local file <ROOT/local/config/icy_acl.php>
+    + Allow user to edit images in any set of categories
+    + Allow user to (dis)associate image (from)to any categories
+    + Allow user to upload images to any categories
 
 1.1.0 2011-09-02
Index: extensions/Icy_Picture_Modify/README.md
===================================================================
--- extensions/Icy_Picture_Modify/README.md	(revision 16494)
+++ extensions/Icy_Picture_Modify/README.md	(revision 16495)
@@ -1,56 +1,91 @@
-NAME
+# NAME
 
-  icy_picture_modify -- Allow user to modify their pictures
+  `icy_picture_modify` -- Allow user to modify any pictures
 
-DESCRIPTION
+# DESCRIPTION
 
-  A piwigo extension that allows users to modify pictures they uploaded.
-  This extension just works as the 'picture_modify.php' for administrator.
+  A piwigo extension that allows users to edit any set of images.
+  This extension just works as the `picture_modify.php` for administrator.
 
-  The code of this plugin is heavily based on the original source
-  'picture_modify.php' of the Piwigo distribution (version 2.2.3.)
+  The code of this plugin is based on the original source
+  `picture_modify.php` of the Piwigo distribution (version 2.2.3.)
 
-USAGE
+  Advanced ACL is supported since version 1.2.0.
 
-  1. Install and enable the plugin "community" which allows users to
-     upload pictures to some albums. Please configure the plugin before
-     you install "icy_picture_modify".
+# FEATURES
 
-  2. Install and enable this plugin
+  Normal users in Piwigo system can delete image or modify image's metadata
+  (author, date, tags, description, metada, linking/represented categories).
+  They can upload some images to some categories.
 
-  3. When users view a picture they uploaded, they will be provided a link
-     to modify that picture's information.
+  Advanced ACL allows users to work with any set of images / categories.
 
-FEATURES
+# USAGE
 
-  Users can delete image or modify image's properties (author, date, tags,
-  description, metada, associcate/aissociated/represented categories).
+  * Install and enable this plugin and the plugin `community`.
+  * Create and edit ACL file in `local/config/icy_acl.zml` in your Piwigo
+    installation. A sample file can be found in `doc/icy_acl.zml.sample`.
+    You don't have to modify any settings for the plugin `community`.
+    Moverover, any settings of the plugin `community` will be ignored.
+  * If you are using a development of the plugin, please clean up the
+    obsolete files (See `OBSOLETE FILES` below.)
 
-KNOWN PROBLEMS
+# OBSOLETE FILES
 
-  * If an image is replaced by other version (using plugin 'Photo update')
-    the author of (new) image will be owned by administrator, not the
-    current user. Hence the image won't be editable anymore
+  The following files are obsolsete. They need to be ported to new format
+  and/or to be removed
 
+  * `local/config/icy_acl.php`:
+    need to be ported to `local/config/icy_acl.zml`. After your old ACL
+    settings are ported to new format, you can safely delete this file;
+
+  * `_data/icy.log`:
+    if you are using `icy_picture_modify` version 2.0.0 or higher, you
+    can safely remove this file.
+
+# KNOWN PROBLEMS
+
+  * No webUI for ACL editting
+  * If an image is replaced by a new version (using plugin `Photo update`)
+    the new version is owned by administrator, not the current user.
+    Hence the image may not be editable by themself.
   * This plugin doesn't support all known templates
-
-  * This plugin may not work smoothly without the plugin 'community'
-
+  * This plugin may not work smoothly without the plugin `community`.
   * User can delete an image which is associated to some albums to which
     the user doesn't have permission to write/access. This is true as the
     plugin only checks owner of the image.
 
-AUTHOR
+# SUPPORT
 
-  Anh K. Huỳnh (icy)
+  To get support, please create new issue at
+    https://github.com/icy/icy_picture_modify/issues
 
-LICENSE
+# DEVELOPMENT
+
+  The plugin requires a webUI for ACL editting. Unfortunately, the author
+  isn't good at template system used by Piwigo. Feel free to help us to
+  write a webUI :)
+
+# DONATION
+
+  If you know what `donation` is and how it works in Open source develoment,
+  feel free to donate ;) My Paypal email is `xkyanh@gmail.com`.
+
+# AUTHOR
+
+  The author's information
+
+  * Real name: Anh K. Huỳnh
+  * Email: kyanh@viettug.org, xkyanh@gmail.com
+  * Nickname on Piwigo's forum: icy
+
+# LICENSE
 
   GPL2
 
-HOMGEPAGE
+# HOMGEPAGE
 
-  At Github.com:  https://github.com/icy/icy_picture_modify
-  At Piwigo.com:  http://piwigo.org/ext/extension_view.php?eid=563
-  SVN repository: http://piwigo.org/svn/extensions/Icy_Picture_Modify/
-  Forum link:     http://piwigo.org/forum/viewtopic.php?pid=131585#p131585
+  * At Github.com:  https://github.com/icy/icy_picture_modify
+  * At Piwigo.com:  http://piwigo.org/ext/extension_view.php?eid=563
+  * SVN repository: http://piwigo.org/svn/extensions/Icy_Picture_Modify/
+  * Forum link:     http://piwigo.org/forum/viewtopic.php?pid=131585#p131585
Index: extensions/Icy_Picture_Modify/add_photos.php
===================================================================
--- extensions/Icy_Picture_Modify/add_photos.php	(revision 16495)
+++ extensions/Icy_Picture_Modify/add_photos.php	(revision 16495)
@@ -0,0 +1,336 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | Piwigo - a PHP based photo gallery                                    |
+// +-----------------------------------------------------------------------+
+// | Copyright(C) 2008-2011 Piwigo Team                  http://piwigo.org |
+// | Copyright(C) 2003-2008 PhpWebGallery Team    http://phpwebgallery.net |
+// | Copyright(C) 2002-2003 Pierrick LE GALL   http://le-gall.net/pierrick |
+// +-----------------------------------------------------------------------+
+// | This program is free software; you can redistribute it and/or modify  |
+// | it under the terms of the GNU General Public License as published by  |
+// | the Free Software Foundation                                          |
+// |                                                                       |
+// | This program 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      |
+// | General Public License for more details.                              |
+// |                                                                       |
+// | You should have received a copy of the GNU General Public License     |
+// | along with this program; if not, write to the Free Software           |
+// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
+// | USA.                                                                  |
+// +-----------------------------------------------------------------------+
+
+if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
+
+global $template, $conf, $user;
+
+include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
+include_once(PHPWG_ROOT_PATH.'admin/include/functions_upload.inc.php');
+include_once(COMMUNITY_PATH.'include/functions_community.inc.php');
+
+define('PHOTOS_ADD_BASE_URL', make_index_url(array('section' => 'add_photos')));
+
+icy_acl_fix_community(icy_acl_load_configuration());
+
+$user_permissions = community_get_user_permissions($user['id']);
+
+if (count($user_permissions['upload_categories']) == 0 and !$user_permissions ['create_whole_gallery'])
+{
+  redirect(make_index_url());
+}
+
+// +-----------------------------------------------------------------------+
+// |                             process form                              |
+// +-----------------------------------------------------------------------+
+
+$page['errors'] = array();
+$page['infos'] = array();
+
+// this is for "browser uploader", for Flash Uploader the problem is solved
+// with function community_uploadify_privacy_level (see main.inc.php)
+$_POST['level'] = 16;
+
+if (isset($_GET['processed']))
+{
+  $hacking_attempt = false;
+
+  // is the user authorized to upload in this album?
+  if (!in_array($_POST['category'], $user_permissions['upload_categories']))
+  {
+    echo 'Hacking attempt, you have no permission to upload in this album';
+    $hacking_attempt = true;
+  }
+
+  if ($hacking_attempt)
+  {
+    if (isset($_SESSION['uploads'][ $_POST['upload_id'] ]))
+    {
+      delete_elements($_SESSION['uploads'][ $_POST['upload_id'] ], true);
+    }
+    exit();
+  }
+}
+
+include_once(PHPWG_ROOT_PATH.'admin/include/photos_add_direct_process.inc.php');
+
+if (isset($image_ids) and count($image_ids) > 0)
+{
+  // reinitialize the informations to display on the result page
+  $page['infos'] = array();
+
+  if (isset($_POST['set_photo_properties']))
+  {
+    $data = array();
+
+    $data['name'] = $_POST['name'];
+    $data['author'] = $_POST['author'];
+
+    if ($conf['allow_html_descriptions'])
+    {
+      $data['comment'] = @$_POST['description'];
+    }
+    else
+    {
+      $data['comment'] = strip_tags(@$_POST['description']);
+    }
+
+    $updates = array();
+    foreach ($image_ids as $image_id)
+    {
+      $update = $data;
+      $update['id'] = $image_id;
+
+      array_push($updates, $update);
+    }
+
+    mass_updates(
+      IMAGES_TABLE,
+      array(
+        'primary' => array('id'),
+        'update' => array_diff(array_keys($updates[0]), array('id'))
+        ),
+      $updates
+      );
+  }
+
+  // $category_id is set in the photos_add_direct_process.inc.php included script
+  $category_infos = get_cat_info($category_id);
+  $category_name = get_cat_display_name($category_infos['upper_names']);
+
+  array_push(
+    $page['infos'],
+    sprintf(
+      l10n('%d photos uploaded into album "%s"'),
+      count($page['thumbnails']),
+      '<em>'.$category_name.'</em>'
+      )
+    );
+
+  // should the photos be moderated?
+  //
+  // if one of the user community permissions is not moderated on the path
+  // to gallery root, then the upload is not moderated. For example, if the
+  // user is allowed to upload to events/parties with no admin moderation,
+  // then he's not moderated when uploading in
+  // events/parties/happyNewYear2011
+  $moderate = icy_acl("moderate_image");
+  if ($moderate)
+  {
+    $inserts = array();
+
+    $query = '
+SELECT
+    id,
+    date_available
+  FROM '.IMAGES_TABLE.'
+  WHERE id IN ('.implode(',', $image_ids).')
+;';
+    $result = pwg_query($query);
+    while ($row = pwg_db_fetch_assoc($result))
+    {
+      array_push(
+        $inserts,
+        array(
+          'image_id' => $row['id'],
+          'added_on' => $row['date_available'],
+          'state' => 'moderation_pending',
+          )
+        );
+    }
+
+    mass_inserts(
+      COMMUNITY_PENDINGS_TABLE,
+      array_keys($inserts[0]),
+      $inserts
+      );
+
+    // the link on thumbnail must go to the websize photo
+    foreach ($page['thumbnails'] as $idx => $thumbnail)
+    {
+      $page['thumbnails'][$idx]['link'] = str_replace(
+        'thumbnail/'.$conf['prefix_thumbnail'],
+        '',
+        $thumbnail['src']
+        );
+    }
+
+    array_push(
+      $page['infos'],
+      l10n('Your photos are waiting for validation, administrators have been notified')
+      );
+  }
+  else
+  {
+
+    // the level of a user upload photo with no moderation is 0
+    $query = '
+UPDATE '.IMAGES_TABLE.'
+  SET level = 0
+  WHERE id IN ('.implode(',', $image_ids).')
+;';
+    pwg_query($query);
+
+    // the link on thumbnail must go to picture.php
+    foreach ($page['thumbnails'] as $idx => $thumbnail)
+    {
+      if (preg_match('/(image_id=|photo-)(\d+)/', $thumbnail['link'], $matches))
+      {
+        $page['thumbnails'][$idx]['link'] = make_picture_url(
+          array(
+            'image_id' => $matches[2],
+            'image_file' => $thumbnail['file'],
+            'category' => $category_infos,
+            )
+          );
+      }
+    }
+  }
+
+  invalidate_user_cache();
+
+  // let's notify administrators
+  include_once(PHPWG_ROOT_PATH.'include/functions_mail.inc.php');
+
+  $keyargs_content = array(
+    get_l10n_args('Hi administrators,', ''),
+    get_l10n_args('', ''),
+    get_l10n_args('Album: %s', get_cat_display_name($category_infos['upper_names'], null, false)),
+    get_l10n_args('User: %s', $user['username']),
+    get_l10n_args('Email: %s', $user['email']),
+    );
+
+  if ($moderate)
+  {
+    $keyargs_content[] = get_l10n_args('', '');
+
+    array_push(
+      $keyargs_content,
+      get_l10n_args(
+        'Validation page: %s',
+        get_absolute_root_url().'admin.php?page=plugin-community-pendings'
+        )
+      );
+  }
+
+  pwg_mail_notification_admins(
+    get_l10n_args('%d photos uploaded by %s', array(count($image_ids), $user['username'])),
+    $keyargs_content,
+    false
+    );
+}
+
+// +-----------------------------------------------------------------------+
+// |                             prepare form                              |
+// +-----------------------------------------------------------------------+
+
+$template->set_filenames(array('add_photos' =>  dirname(__FILE__).'/../community/add_photos.tpl'));
+
+include_once(PHPWG_ROOT_PATH.'admin/include/photos_add_direct_prepare.inc.php');
+
+// we have to change the list of uploadable albums
+$upload_categories = $user_permissions['upload_categories'];
+if (count($upload_categories) == 0)
+{
+  $upload_categories = array(-1);
+}
+
+$query = '
+SELECT id,name,uppercats,global_rank
+  FROM '.CATEGORIES_TABLE.'
+  WHERE id IN ('.implode(',', $upload_categories).')
+;';
+
+display_select_cat_wrapper(
+  $query,
+  $selected_category,
+  'category_options'
+  );
+
+$create_subcategories = false;
+if ($user_permissions['create_whole_gallery'] or count($user_permissions['create_categories']) > 0)
+{
+  $create_subcategories = true;
+}
+
+$create_categories = $user_permissions['create_categories'];
+if (count($user_permissions['create_categories']) == 0)
+{
+  $create_categories = array(-1);
+}
+
+$query = '
+SELECT id,name,uppercats,global_rank
+  FROM '.CATEGORIES_TABLE.'
+  WHERE id IN ('.implode(',', $create_categories).')
+;';
+
+display_select_cat_wrapper(
+  $query,
+  $selected_category,
+  'category_parent_options'
+  );
+
+$template->assign(
+  array(
+    'create_subcategories' => $create_subcategories,
+    'create_whole_gallery' => $user_permissions['create_whole_gallery'],
+    )
+  );
+
+if (isset($conf['community_ask_for_properties']) and $conf['community_ask_for_properties'])
+{
+  $template->assign(
+    array(
+      'community_ask_for_properties' => true,
+      )
+    );
+}
+
+// +-----------------------------------------------------------------------+
+// |                             display page                              |
+// +-----------------------------------------------------------------------+
+
+if (count($page['errors']) != 0)
+{
+  $template->assign('errors', $page['errors']);
+}
+
+if (count($page['infos']) != 0)
+{
+  $template->assign('infos', $page['infos']);
+}
+
+$title = l10n('Upload Photos');
+$page['body_id'] = 'theUploadPage';
+
+$template->assign_var_from_handle('PLUGIN_INDEX_CONTENT_BEGIN', 'add_photos');
+
+$template->clear_assign(array('U_MODE_POSTED', 'U_MODE_CREATED'));
+
+$template->assign(
+  array(
+    'TITLE' => '<a href="'.get_gallery_home_url().'">'.l10n('Home').'</a>'.$conf['level_separator'].$title,
+    )
+  );
+?>
Index: extensions/Icy_Picture_Modify/doc/icy_acl.zml.sample
===================================================================
--- extensions/Icy_Picture_Modify/doc/icy_acl.zml.sample	(revision 16495)
+++ extensions/Icy_Picture_Modify/doc/icy_acl.zml.sample	(revision 16495)
@@ -0,0 +1,43 @@
+# Default settings for all users (except guest user). These settings are
+# put in the code of the plugin `icy_picture_modify` so you may not have
+# to specify them. All of the following lines mean:
+#   - User can edit their own images (image they uploaded)
+#   - User can't delete any image
+#   - User can upload image to sub categories. Unfortunately, there is no
+#     category specified, so they can't upload images to any category.
+#   - All images are showed on the Piwigo system after they are uploaded;
+#     they will not require any moderation work
+#   - User can create new gallery inside sub categories. As there isn't
+#     any category specified, they can't create any new gallery.
+#   - User can't link an image to any album
+#   - User can't create representation for any album
+
+default:
+  edit_image_of: owner
+  delete_image_of:
+  upload_image_to: sub
+  moderate_image: no
+  create_gallery_to: sub
+  associate_image_to:
+  present_image_to:
+
+# This user can upload image to category whose identity is `34`;
+# He can edit image of his own and of the user `example_user0`;
+# He can link images to any album in Piwigo system;
+# He can create new gallery in the parent category `34` and its sub
+# category; He can also make representation for any album
+# Finally, he can't delete any images.
+
+example_user1:
+  upload_image_to: sub, 34
+  edit_image_of:  example_user0, owner
+  associate_image_to: any
+  create_gallery_to: 34, sub
+  present_image_to: any
+  delete_image_of:
+
+# This user `example_user2` will have all settings of `example_user1`,
+# except he can delete images of `example_user1` and his own
+
+example_user2: @example_user1
+  delete_image_of: owner, example_user1
Index: extensions/Icy_Picture_Modify/doc/zaml.md
===================================================================
--- extensions/Icy_Picture_Modify/doc/zaml.md	(revision 16495)
+++ extensions/Icy_Picture_Modify/doc/zaml.md	(revision 16495)
@@ -0,0 +1,132 @@
+# PURPOSE
+
+  This format is used to describe advance ACL for Piwigo installation.
+  This ACL is supported by the plugin `icy_picture_modify`.
+
+# FORMAT
+
+  Format details
+
+  * Name:     ZAML (not YAML)
+  * Version:  1.0.0
+  * Author:   icy (Anh K. Huynh)
+
+# SYNTAX
+
+  There are only three types of lines in the format. They follows
+  a rule: a late one overwrites any similar mean of the previous lines.
+
+  * user name specification   _(meanful)_
+  * variable assigment        _(meanful)_
+  * all other non-sense lines _(meanless)_
+
+## User name specification
+
+  A user name (as in your Piwigo system) is put on a single line,
+  ended by a colon (:), and optionally followed by `reference`.
+
+  A `reference` is any user name started by `@`. The current user
+  will have all settings of the `reference` user; those settings will
+  be overwritten by other assignment for the current user. If the
+  `reference` user has't any settings at the time it is declared,
+  the reference will be ignored.
+
+  * *Note 1:* The special name `default` is used specially by the format,
+    and you should not use it for any user in your Piwigo system.
+  * *Note 2:* User name must not contain a colon (:)
+
+## Variable assigment
+
+  A variable assigment has two parts: a variable name and its value.
+  On the line, the variable name must be started by two spaces,
+  followed by a colon (:) and its value.
+
+  You can specify any variable name, though most of them are not
+  officialy supported by `icy_picture_modify` (see EXAMPLES).
+
+  To specify variable's value, you can use
+
+  * nothing, or any spaces      _(meaning: `FALSE`)_
+  * `no`, `false`               _(meaning: `FALSE`)_
+  * `yes`, `true`               _(meaning: `TRUE`)_
+  * Any other string. This string will be considered as an array
+    whose its delimiter is any space, semi-colon (`;`), colon (`:`)
+    or colon (`,`), or any combination of them. Each item of array
+    is often a number, a user name, `sub` or `any` or `owner`.
+
+    * number:     specify category identity
+    * user name:  specify any Piwigo user name
+    * `sub`:      action can work on sub categories
+    * `any`:      action can work on any categories
+    * `owner`:    action can work on any image of current user
+
+## Meanless lines
+
+  Any other lines are considered as comment. They are meanless.
+
+# PARSER
+
+  Simple parser can be found in the function `icy_zml_parser` in
+  ```
+    plugins/icy_picture_modify/include/ \
+      functions_icy_picture_modify.inc.php
+  ```
+
+# EXAMPLE
+
+## Default settings
+
+  Default settings for all users (except guest user). These settings are
+  put in the code of the plugin `icy_picture_modify` so you may not have
+  to specify them. All of the following lines mean:
+
+  *  User can edit their own images (image they uploaded)
+  *  User can't delete any image
+  *  User can upload image to sub categories. Unfortunately, there is no
+  *  category specified, so they can't upload images to any category.
+  *  All images are showed on the Piwigo system after they are uploaded;
+  *  they will not require any moderation work
+  *  User can create new gallery inside sub categories. As there isn't
+  *  any category specified, they can't create any new gallery.
+  *  User can't link an image to any album
+  *  User can't create representation for any album
+
+```
+default:
+  edit_image_of: owner
+  delete_image_of:
+  upload_image_to: sub
+  moderate_image: no
+  create_gallery_to: sub
+  associate_image_to:
+  present_image_to:
+```
+
+## A normal user
+
+  This user can upload image to category whose identity is `34`;
+  He can edit image of his own and of the user `example_user0`;
+  He can link images to any album in Piwigo system;
+  He can create new gallery in the parent category `34` and its sub
+  category; He can also make representation for any album
+  Finally, he can't delete any images.
+
+```
+example_user1:
+  upload_image_to: sub, 34
+  edit_image_of:  example_user0, owner
+  associate_image_to: any
+  create_gallery_to: 34, sub
+  present_image_to: any
+  delete_image_of:
+```
+
+## Reference
+
+  This user `example_user2` will have all settings of `example_user1`,
+  except he can delete images of `example_user1` and his own
+
+```
+example_user2: @example_user1
+  delete_image_of: owner, example_user1
+```
Index: extensions/Icy_Picture_Modify/icy_picture_modify.php
===================================================================
--- extensions/Icy_Picture_Modify/icy_picture_modify.php	(revision 16494)
+++ extensions/Icy_Picture_Modify/icy_picture_modify.php	(revision 16495)
@@ -25,40 +25,11 @@
 if (!defined('ICY_PICTURE_MODIFY_PATH')) die('Hacking attempt!');
 
-include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
-include_once(ICY_PICTURE_MODIFY_PATH.'include/functions_icy_picture_modify.inc.php');
-
-global $template, $conf, $user, $page, $lang, $cache;
-
-// <admin.php>
-$page['errors'] = array();
-$page['infos']  = array();
-$page['warnings']  = array();
-// </admin.php>
-
-// +-----------------------------------------------------------------------+
-// |                             check permission                          |
-// +-----------------------------------------------------------------------+
-
-// redirect users to the index page or category page if 'image_id' isn't provided
-if (!isset($_GET['image_id']))
-{
-  if (isset($_GET['cat_id']))
-  {
-    redirect_http(get_root_url().'?/category/'.$_GET['cat_id']);
-  }
-  else
-  {
-    // FIXME: $_SESSION['page_infos'] = array(l10n('Permission denied'));
-    redirect_http(make_index_url());
-  }
-}
-
-check_input_parameter('cat_id', $_GET, false, PATTERN_ID);
-check_input_parameter('image_id', $_GET, false, PATTERN_ID);
-
-// Simplify redirect to administrator page if current user == admin
+require_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
+require_once(ICY_PICTURE_MODIFY_PATH.'include/functions_icy_picture_modify.inc.php');
+
+// <ADMIN_ONLY>
 if (is_admin())
 {
-  if (icy_does_image_exist($_GET['image_id']))
+  if (icy_image_exists($_GET['image_id']))
   {
     $url = get_root_url().'admin.php?page=picture_modify';
@@ -70,8 +41,47 @@
   else
   {
+    // FIXME: language support ^^
     bad_request('invalid picture identifier');
   }
 }
-elseif (!icy_check_image_owner($_GET['image_id'], $user['id']))
+// </ADMIN_ONLY>
+
+global $template, $conf, $user, $page, $lang, $cache, $ICY_ACL;
+
+// <load_from_admin.php>
+$page['errors'] = array();
+$page['infos']  = array();
+$page['warnings']  = array();
+// </load_from_admin.php>
+
+#! icy_log("body from icy_picture_modify.php");
+icy_acl_load_configuration();
+
+// +-----------------------------------------------------------------------+
+// |                             check permission                          |
+// +-----------------------------------------------------------------------+
+
+// <CHECK_IF_IMAGE_ID_IS_VALID>
+// redirect users to the index page or category page if 'image_id' isn't provided
+if (!isset($_GET['image_id']))
+{
+  if (isset($_GET['cat_id']))
+  {
+    redirect_http(get_root_url().'?/category/'.$_GET['cat_id']);
+  }
+  else
+  {
+    // FIXME: $_SESSION['page_infos'] = array(l10n('Permission denied'));
+    redirect_http(make_index_url());
+  }
+}
+// </CHECK_IF_IMAGE_ID_IS_VALID>
+
+// FIXME: check and then !?
+check_input_parameter('cat_id', $_GET, false, PATTERN_ID);
+check_input_parameter('image_id', $_GET, false, PATTERN_ID);
+
+// Return if the image isn't editable
+if (!icy_acl("edit_image_of", $_GET['image_id'], icy_get_user_owner_of_image($_GET['image_id'])))
 {
   $url = make_picture_url(
@@ -86,4 +96,5 @@
 
 // Update the page sessions
+// FIXME: why?
 if (isset($_SESSION['page_infos']))
 {
@@ -93,37 +104,8 @@
 
 // <find writable categories>
-
-// * Purpose: Find all categories that are reachable for the current user.
-// * FIXME:   This query will include all readable categories, included
-//            the ones user can't write to them.
-
 $my_categories = array();
-$my_permissions = null;
-$has_plugin_community = false;
-
-// <community support>
-if (is_file(PHPWG_PLUGINS_PATH.'community/include/functions_community.inc.php'))
-{
-  include_once(PHPWG_PLUGINS_PATH.'community/include/functions_community.inc.php');
-  $has_plugin_community = true;
-
-  $user_permissions = community_get_user_permissions($user['id']);
-  $my_categories = $user_permissions['upload_categories'];
-}
-// </community support>
-
-if (($has_plugin_community == false) or $user_permissions['create_whole_gallery'])
-{
-  $query = '
-  SELECT category_id
-    FROM '.IMAGE_CATEGORY_TABLE.'
-  ;';
-
-  // list of categories to which the user can read
-  $my_categories = array_diff(
-    array_from_query($query, 'category_id'),
-    explode(',',calculate_permissions($user['id'], $user['status'])));
-}
-// </find writable categories>
+// FIXME: delete this line ^^
+$my_categories = array_from_query('SELECT category_id FROM '
+                        .IMAGE_CATEGORY_TABLE.';', 'category_id');
 
 // +-----------------------------------------------------------------------+
@@ -131,5 +113,10 @@
 // +-----------------------------------------------------------------------+
 
-if (isset($_GET['delete']))
+// ACTION => :delete_image
+
+if (isset($_GET['delete'])
+      and icy_acl("delete_image_of",
+            $_GET['image_id'],
+            icy_get_user_owner_of_image($_GET['image_id'])))
 {
   check_pwg_token();
@@ -183,5 +170,10 @@
 // +-----------------------------------------------------------------------+
 
-if (isset($_GET['sync_metadata']))
+// ACTION => synchronize_image_metadata
+// This includes other sub-actions and other permissions
+//  (tag update, timestamp updated, ...)
+
+if (version_compare(PHPWG_VERSION, '2.4.0', '<')
+    and isset($_GET['sync_metadata']))
 {
   $query = '
@@ -246,4 +238,5 @@
   }
 
+  // FIXME: why mass_updates here ? Used with a simple array?
   mass_updates(
     IMAGES_TABLE,
@@ -271,34 +264,43 @@
 // associate the element to other categories than its storage category
 //
+
+// SUB-ACTION => associate_image_to_gallery
+
 if (isset($_POST['associate'])
-    and ($has_plugin_community == true)
     and isset($_POST['cat_dissociated'])
-    and count($_POST['cat_dissociated']) > 0
+    and (count($_POST['cat_dissociated']) > 0)
   )
 {
-  associate_images_to_categories(
-    array($_GET['image_id']),
-    array_intersect($_POST['cat_dissociated'], $my_categories)
-    );
+  $_categories = array_intersect($_POST['cat_dissociated'],
+                    icy_acl_get_categories("associate_image_to"));
+  //! $_categories = array_filter($_categories,
+  //!    create_function('$item', 'return icy_acl("associate_image_to", $item);'));
+
+  associate_images_to_categories(array($_GET['image_id']), $_categories);
   invalidate_user_cache();
 }
 
+// SUB-ACTION => dissociate_image_from_gallery
 
 // dissociate the element from categories (but not from its storage category)
 if (isset($_POST['dissociate'])
-    and ($has_plugin_community == true)
     and isset($_POST['cat_associated'])
     and count($_POST['cat_associated']) > 0
   )
 {
-  $arr_dissociate = array_intersect($_POST['cat_associated'], $my_categories);
+
+  $_categories = array_intersect($_POST['cat_associated'],
+                    icy_acl_get_categories("associate_image_to"));
+  //! $_categories = array_filter($_categories,
+  //!    create_function('$item', 'return icy_acl("associate_image_to", $item);'));
+
   $query = '
 DELETE FROM '.IMAGE_CATEGORY_TABLE.'
   WHERE image_id = '.$_GET['image_id'].'
-    AND category_id IN ('.implode(',', $arr_dissociate).')
+    AND category_id IN (0'.join(',', $_categories).')
 ';
+
   pwg_query($query);
-
-  update_category($arr_dissociate);
+  update_category($_categories);
   invalidate_user_cache();
 }
@@ -308,7 +310,8 @@
 // +-----------------------------------------------------------------------+
 
-// select the element to represent the given categories
+// SUB-ACTION => select the element to represent the given categories
+// FIXME: select or elect?
+
 if (isset($_POST['elect'])
-    and ($has_plugin_community == true)
     and isset($_POST['cat_dismissed'])
     and count($_POST['cat_dismissed']) > 0
@@ -316,5 +319,7 @@
 {
   $datas = array();
-  $arr_dimissed = array_intersect($_POST['cat_dismissed'], $my_categories);
+  $arr_dimissed = array_intersect($_POST['cat_dismissed'],
+                        icy_acl_get_categories("present_image_to"));
+
   if (count($arr_dimissed) > 0)
   {
@@ -332,12 +337,13 @@
 }
 
-// dismiss the element as representant of the given categories
+// SUB-ACTION => dismiss the element as representant of the given categories
+
 if (isset($_POST['dismiss'])
-    and ($has_plugin_community == true)
     and isset($_POST['cat_elected'])
     and count($_POST['cat_elected']) > 0
   )
 {
-  $arr_dismiss = array_intersect($_POST['cat_elected'], $my_categories);
+  $arr_dismiss = array_intersect($_POST['cat_elected'],
+                        icy_acl_get_categories("present_image_to"));
   if (count($arr_dismiss) > 0)
   {
@@ -350,4 +356,6 @@
 // |                             tagging support                           |
 // +-----------------------------------------------------------------------+
+
+// FIXME: tag is always updatable?
 
 if (version_compare(PHPWG_VERSION, '2.2.5', '<')) {
@@ -410,6 +418,4 @@
     'tag_selection' => $tag_selection,
     'tags' => $tags,
-    'U_SYNC' => $admin_url_start.'&amp;sync_metadata=1',
-    'U_DELETE' => $admin_url_start.'&amp;delete=1&amp;pwg_token='.get_pwg_token(),
 
     'PATH'=>$row['path'],
@@ -436,10 +442,21 @@
       htmlspecialchars( isset($_POST['description']) ?
         stripslashes($_POST['description']) : @$row['comment'] ),
-
-    'F_ACTION' =>
-        get_root_url() # .'index.php?/icy_picture_modify'
-        .get_query_string_diff(array('sync_metadata'))
     )
   );
+
+if (version_compare(PHPWG_VERSION, '2.4.0', '<')) {
+  $template->assign(
+    array(
+      'U_SYNC' => $admin_url_start.'&amp;sync_metadata=1',
+      'F_ACTION' => get_root_url() . get_query_string_diff(array('sync_metadata'))
+    )
+  );
+}
+
+if (icy_image_deletable($_GET['image_id'])) {
+  $template->assign(
+    'U_DELETE', $admin_url_start.'&amp;delete=1&amp;pwg_token='.get_pwg_token()
+  );
+}
 
 if (array_key_exists('has_high', $row) and $row['has_high'] == 'true')
@@ -577,5 +594,6 @@
 }
 
-// associate to another category ?
+$_categories = icy_acl_get_categories("associate_image_to");
+// Select list of categories this image is associcated to
 $query = '
 SELECT id,name,uppercats,global_rank
@@ -583,7 +601,7 @@
     INNER JOIN '.IMAGE_CATEGORY_TABLE.' ON id = category_id
   WHERE image_id = '.$_GET['image_id'] . '
-    AND id IN ('. join(",", $my_categories).')';
-// if the image belongs to a physical storage,
-// we simply ignore that storage album
+    AND id IN (0'.join(",",$_categories).')';
+// FIMXE: if the image belongs to a physical storage,
+// FIXME: we simply ignore that storage album
 if (isset($storage_category_id))
 {
@@ -605,25 +623,26 @@
   array_push($associateds, $row['id']);
 }
+  // FIXME: Also display some forbidden presentations
 $query = '
 SELECT id,name,uppercats,global_rank
   FROM '.CATEGORIES_TABLE.'
   WHERE id NOT IN ('.implode(',', $associateds).')
-  AND id IN ('. join(",", $my_categories).')
+  AND id IN (0'.join(",", $_categories).')
 ;';
 display_select_cat_wrapper($query, array(), 'dissociated_options');
 
 // display list of categories for representing
+$_categories = icy_acl_get_categories("present_image_to");
 $query = '
 SELECT id,name,uppercats,global_rank
   FROM '.CATEGORIES_TABLE.'
   WHERE representative_picture_id = '.$_GET['image_id'].'
-    AND id IN ('. join(",", $my_categories).')
+    AND id IN (0'. join(",", $_categories).')
 ;';
 display_select_cat_wrapper($query, array(), 'elected_options');
-
 $query = '
 SELECT id,name,uppercats,global_rank
   FROM '.CATEGORIES_TABLE.'
-  WHERE id IN ('. join(",", $my_categories).')
+  WHERE id IN (0'. join(",", $_categories).')
     AND (representative_picture_id != '.$_GET['image_id'].'
     OR representative_picture_id IS NULL)
Index: extensions/Icy_Picture_Modify/include/functions_icy_picture_modify.inc.php
===================================================================
--- extensions/Icy_Picture_Modify/include/functions_icy_picture_modify.inc.php	(revision 16494)
+++ extensions/Icy_Picture_Modify/include/functions_icy_picture_modify.inc.php	(revision 16495)
@@ -29,25 +29,8 @@
  *
 */
-function icy_check_image_owner($image_id, $user_id = 0)
+function icy_check_image_owner($image_id)
 {
-  if (!preg_match(PATTERN_ID, $image_id))
-  {
-    bad_request('invalid picture identifier');
-  }
-  if (!preg_match(PATTERN_ID, $user_id))
-  {
-    bad_request('invalid category identifier');
-  }
-
-  $query = '
-SELECT COUNT(id)
-  FROM '.IMAGES_TABLE.'
-  WHERE id = '.$image_id.'
-  AND added_by = '.$user_id.'
-;';
-
-  list($count) = pwg_db_fetch_row(pwg_query($query));
-
-  return ($count > 0 ? true: false);
+  global $user;
+  return $user['id'] == icy_get_user_owner_of_image($image_id);
 }
 
@@ -58,5 +41,5 @@
  *
 */
-function icy_does_image_exist($image_id)
+function icy_image_exists($image_id)
 {
   if (!preg_match(PATTERN_ID, $image_id))
@@ -72,3 +55,431 @@
   return ($count > 0 ? true: false);
 }
+
+/*
+ * Check if an image is editable by current user
+ * @icy_acl   access rules (provided by icy module)
+ * @image_id  identity of the image
+ * @return    boolean value
+ * @author    icy
+ */
+function icy_image_editable($image_id) {
+  return icy_acl("edit_image_of", $image_id, icy_get_user_owner_of_image($image_id));
+}
+
+function icy_image_deletable($image_id) {
+  return icy_acl("delete_image_of", $image_id, icy_get_user_owner_of_image($image_id));
+}
+
+
+/*
+ * Return list of visible/uploadable categories
+ * @author  icy
+ */
+function icy_acl_get_data($symbol) {
+  global $user, $ICY_ACL;
+
+  // Load ACL setting for this user
+  $this_user = $user['username'];
+  $my_acl = $ICY_ACL['default'];
+  if (array_key_exists($this_user, $ICY_ACL)) {
+    $my_acl = array_replace($my_acl, $ICY_ACL[$this_user]);
+  }
+
+  // Load ACL setting for the symbol
+  if (!array_key_exists($symbol, $my_acl)) {
+    return NULL;
+  }
+
+  return $my_acl[$symbol];
+}
+
+/*
+ *
+ * visible: upload, assosiate,...
+ * @symbol    must be ended by "_to" or "_from"
+ */
+function icy_acl_get_categories($symbol) {
+  global $user, $conf;
+
+  $all_categories = array();
+  $symbol_categories = array();
+  $symbol_settings = NULL;
+
+  // It's always EMPTY array for any kind of guests
+  if ($user['id'] == $conf['guest_id']) {
+    return $symbol_categories;
+  }
+
+  // check if $symbol is valid
+  if (!preg_match("/_(to|from)$/", $symbol)) {
+    return $symbol_categories;
+  }
+
+  $symbol_settings = icy_acl_get_data($symbol);
+  if (!$symbol_settings) {
+    return $symbol_categories;
+  }
+
+  // all known categories in the system
+  $query = 'SELECT id FROM '.CATEGORIES_TABLE.';';
+  $all_categories = array_unique(array_from_query($query, 'id'));
+  $forbidden_categories = explode(',',calculate_permissions($user['id'], $user['status']));
+
+  // ICY_ACL allows user to access all categories. In this case,
+  // the plugin 'community' plays an empty role (we just supress it)
+  if (icy_acl_symbol_data_wide_open($symbol_settings)) {
+    $symbol_categories = $all_categories;
+  }
+  elseif (is_array($symbol_settings)) {
+    $symbol_categories = array_values(array_intersect($symbol_settings, $all_categories));
+  }
+  else {
+    // not wide-open, not an-array. So waht!?
+    $symbol_settings = array();
+  }
+
+  // Make sure categories are in our sytem
+  // remove all forbidden categories from the list
+  if (in_array('sub', icy_acl_get_data($symbol))) {
+    // FIXME: (get_subcat_ids) requires a 0-based array
+    // FIXME: + array(0) is really a trick :) In Piwigo 2.4, (get_subcat_ids)
+    // FIXME: will generate NOTICE (SQL syntax error) if $symbol_categories is empty.
+    $symbol_categories = array_merge($symbol_categories, get_subcat_ids($symbol_categories + array(0)));
+  }
+  $symbol_categories = array_diff($symbol_categories, $forbidden_categories);
+  return array_values($symbol_categories);
+}
+/*
+ * FIXME: Test if current user is logged in
+ * FIXME: $guestowner must be provided explicitly
+ *
+ * Check if the current user has permission to do something
+ * @symbol     Action to be checked
+ * @guestdata  Object of the action
+ * @guestowner Owner of @guestdata
+ *
+ * There are two cases of @symbol:
+ * - _from/_to: action on an category
+ * - _of      : action on the author
+ * - others   : boolean flag
+ *
+ * There are three cases of symbol data
+ * - Array of categories (' identities)    [_from/_to]
+ *    $guestowner is simply ignored
+ * - Array of usernames (list of authors)  [_of]
+ *    $guestowner must be specified
+ * - Others: {"any", "owner", TRUE, FALSE} [others]
+ */
+ function icy_acl($symbol, $guestdata = NULL, $guestowner = NULL) {
+  global $user, $ICY_ACL, $conf;
+
+  // Load ACL setting for this user
+  $this_user = $user['id'];
+
+  if ($user['id'] == $conf['guest_id']) {
+    return FALSE;
+  }
+  elseif (is_admin()) {
+    return TRUE;
+  }
+
+  $symbol_settings = icy_acl_get_data($symbol);
+
+
+  if (! preg_match("/_(to|from|of)$/", $symbol)) {
+    return is_bool($symbol_settings) ? $symbol_settings: FALSE;
+  }
+
+  if (! is_array($symbol_settings) ) {
+    return FALSE;
+  } elseif (icy_acl_symbol_data_wide_open($symbol_settings)) {
+    return TRUE;
+  }
+
+  if (preg_match("/_(to|from)$/", $symbol)) {
+    return in_array($guestdata, $symbol_settings);
+  }
+  elseif (preg_match("/_of$/", $symbol)) {
+    $guestowner = icy_get_username_of($guestowner);
+    // Replace 'owner' by the $guestowner. For example
+    //  array('owner','ruby', 12) => array($guestowner, 'ruby', 12)
+    array_walk($symbol_settings,
+     create_function('&$val, $key',
+       'if ($val == "owner") {$val = "'.$user['username'].'";}'));
+    return in_array($guestowner, $symbol_settings);
+  }
+}
+
+function icy_acl_symbol_data_wide_open($symbol_data) {
+  return (is_array($symbol_data) and in_array("any", $symbol_data));
+}
+
+/*
+ * Write some logs for debugging
+ * @notes     Data will be written to STDERRR (default)
+ *            or to file `<ROOT>/_data/icy.log`
+ * @author    icy
+ */
+function icy_log($st, $stderr = FALSE) {
+  if ($stderr === TRUE) {
+    $_f_log = "php://stderr";
+  }
+  else {
+    $_f_log = PHPWG_ROOT_PATH.'_data/icy.log';
+  }
+
+  $_f_handle = fopen($_f_log, 'a');
+  if ($_f_handle) {
+    $new_line = "\n";
+    fwrite($_f_handle, "piwigo/icy_picture_modify: $st". $new_line );
+    if ($stderr !== TRUE) {
+      fclose($_f_handle);
+    }
+  }
+}
+
+/*
+ * Get UserId from their UserName
+ * @user_name   username as string
+ * @author      icy
+ */
+function icy_get_user_id_from_name($user_name) {
+  $user_name = pwg_db_real_escape_string($user_name);
+
+  $query = '
+SELECT id
+  FROM '.USERS_TABLE.'
+  WHERE username = "'.$user_name.'"
+  LIMIT 1
+;';
+
+  list($user_id) = pwg_db_fetch_row(pwg_query($query));
+
+  // FIXME: Is this the best way?
+  if ($user_id == NULL) $user_id = 0;
+
+  #! icy_log("icy_get_user_id_from_name: map userid <= username: $user_name <= $user_id");
+  return $user_id;
+}
+
+/*
+ * Rerturn the owner id of an image
+ * @author    icy
+ * @image_id  identity of the image
+ */
+function icy_get_user_owner_of_image($image_id) {
+  // FIXME: Clean this up!!!
+  if (!preg_match(PATTERN_ID, $image_id))
+    bad_request('invalid picture identifier');
+
+  $query = '
+SELECT added_by
+  FROM '.IMAGES_TABLE.'
+  WHERE id = '.$image_id.'
+  LIMIT 1
+;';
+
+  list($owner) = pwg_db_fetch_row(pwg_query($query));
+  #! icy_log("icy_get_user_owner_of_image: image_id, added_by = $image_id, $owner");
+  return $owner ? $owner : 0;
+}
+
+/*
+ * Return the username from user_id
+ */
+function icy_get_username_of($user_id) {
+  if (!preg_match(PATTERN_ID, $user_id))
+    bad_request('invalid user identifier');
+
+  $query = '
+SELECT username
+  FROM '.USERS_TABLE.'
+  WHERE id = '.$user_id.'
+  LIMIT 1
+;';
+
+  list($username) = pwg_db_fetch_row(pwg_query($query));
+  #! icy_log("icy_get_username_of: user_id, user_name = $user_id, $username");
+  return $username;
+}
+
+/*
+ * Check if a plugin is enabled
+ * @plugin_name   name of the plugin
+ * @author        icy
+ */
+function icy_plugin_enabled($plugin_name) {
+  $return = false;
+
+  $query = '
+SELECT count(id)
+  FROM '.PLUGINS_TABLE.'
+  WHERE id = "'.pwg_db_real_escape_string($plugin_name).'"
+  AND state="active"
+  LIMIT 1
+;';
+
+  list($count) = pwg_db_fetch_row(pwg_query($query));
+  $return = ($count == 1 ? true : false);
+
+  // we need the file ^^
+  if ($plugin_name == "community")
+    $return = $return
+                and is_file(PHPWG_PLUGINS_PATH
+                  .'community/include/functions_community.inc.php');
+
+  return $return;
+}
+
+/*
+ * Load ICY_ACL configuration from files
+ * @author   icy
+ */
+function icy_acl_load_configuration($force = FALSE) {
+  global $ICY_ACL;
+  $conf_path = PHPWG_ROOT_PATH.PWG_LOCAL_DIR.'config/icy_acl.zml';
+
+  if (($force == FALSE)
+      and isset($ICY_ACL['default'])
+      and isset($_SESSION['icy_picture_modify_acl_mtime'])
+      and ($_SESSION['icy_picture_modify_acl_mtime'] == filemtime($conf_path))) {
+    #! icy_log("icy_acl_load_configuration: configuration is up-to-date");
+    return FALSE;
+  }
+
+  $ICY_ACL = icy_zml_parser(<<<EOF
+default:
+  edit_image_of: owner
+  delete_image_of:
+  upload_image_to: sub
+  moderate_image: no
+  create_gallery_to: sub
+  associate_image_to:
+  present_image_to: sub
+EOF
+);
+
+  if (file_exists($conf_path)) {
+    #! icy_log("icy_acl_load_configuration: now loading ACL from $conf_path");
+    $ICY_ACL = array_replace($ICY_ACL, icy_zml_parser(file($conf_path)));
+    $_SESSION['icy_picture_modify_acl_mtime'] = filemtime($conf_path);
+  }
+
+  return TRUE;
+}
+
+/*
+ * Return array of variable from a `.zml` array  / string
+ * Syntax of the `.zml` file can be found in `doc/zaml.md`
+ * @author icy
+ */
+function icy_zml_parser($data) {
+  $acl = array();
+  $author = 'default';
+  $acl[$author] = array();
+
+  if (is_string($data)) {
+    $data = preg_split("/[\r\n]/", $data);
+  }
+
+  foreach($data as $line) {
+    # AUTHOR:
+    if (preg_match('/^([^[:space:]:]+):$/', $line, $gs)) {
+      $author = trim($gs[1]);
+      if (! array_key_exists($author, $acl)) {
+        $acl[$author] = array();
+      }
+      continue;
+    }
+
+    # AUTHOR: @REFERENCE
+    if (preg_match('/^([^[:space:]:]+):[[:space:]]+@([^[:space:]:]+)$/', $line, $gs)) {
+      $ref_author = trim($gs[2]);
+      if (!array_key_exists($ref_author, $acl)) {
+        continue;
+      }
+      $author = trim($gs[1]);
+      if (! array_key_exists($author, $acl)) {
+        $acl[$author] = array();
+      }
+      $acl[$author] = array_replace($acl[$ref_author], $acl[$author]);
+    }
+
+    # <two spaces> KEY: [VALUE]
+    if (preg_match('/  ([^:]+):(.*)$/', $line, $gs)) {
+      $key = $gs[1];
+      $val = trim($gs[2]);
+      if (in_array($val, array("","false","no"))) {
+        $val = FALSE;
+      }
+      elseif (in_array($val, array("yes", "true"))) {
+        $val = TRUE;
+      }
+      else {
+        $val = array_unique(preg_split("/[[:space:],:;]+/", $val));
+      }
+      $acl[$author][$key] = $val;
+    }
+
+    # Other line is ignored :)
+  }
+  return $acl;
+}
+
+/*
+ * Overwrite the ACl setings from community plugin
+ * @author: icy
+ */
+function icy_acl_fix_community($force = FALSE) {
+  global $user, $_SESSION;
+
+  if (!icy_plugin_enabled("community")) {
+    return TRUE;
+  }
+
+  require_once(PHPWG_PLUGINS_PATH.'community/include/functions_community.inc.php');
+
+  # <community_support>
+  $cache_key = community_get_cache_key();
+  if (!isset($cache_key))  {
+    $cache_key = community_update_cache_key();
+  }
+
+  if (($force == FALSE)
+      and isset($_SESSION['community_user_permissions'])
+      and isset($_SESSION['community_user_permissions']['icy_acl_fixed'])) {
+    #! icy_log("icy_fix_community_acl: the fix is up-to-date " . print_r($_SESSION['community_user_permissions'], true));
+    return TRUE;
+  }
+
+  # icy_log("WARNING: icy_fix_community_acl: the fix is out-of-date. will fix it again");
+  # </community_support>
+
+  $return = array(
+    'create_categories' => array(),
+    'upload_categories' => array(),
+    'permission_ids' => array(),
+    );
+
+  $return['upload_whole_gallery'] = icy_acl_symbol_data_wide_open(icy_acl_get_data("upload_image_to"));
+  $return['create_whole_gallery'] = icy_acl_symbol_data_wide_open(icy_acl_get_data("create_gallery_to"));
+  $return['upload_categories'] = icy_acl_get_categories("upload_image_to");
+  $return['create_categories'] = icy_acl_get_categories("create_gallery_to");
+  $return['permission_ids'] = array();
+  $return['icy_acl_fixed'] = 1;
+
+  $_SESSION['community_user_permissions'] = $return;
+  $_SESSION['community_cache_key'] = $cache_key;
+  $_SESSION['community_user_id'] = $user['id'];
+}
+
+
+if (!function_exists('array_replace')) {
+  function array_replace() {
+    $array=array();
+    $n=func_num_args();
+    while ($n-- >0) $array+=func_get_arg($n);
+    return $array;
+  }
+}
 ?>
Index: extensions/Icy_Picture_Modify/index.php
===================================================================
--- extensions/Icy_Picture_Modify/index.php	(revision 16494)
+++ extensions/Icy_Picture_Modify/index.php	(revision 16495)
@@ -4,9 +4,4 @@
 // | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
 // | Copyright (C) 2003-2007 PhpWebGallery Team - http://phpwebgallery.net |
-// +-----------------------------------------------------------------------+
-// | file          : $Id: index.php 1912 2007-03-16 06:30:07Z rub $
-// | last update   : $Date: 2007-03-16 07:30:07 +0100 (ven, 16 mar 2007) $
-// | last modifier : $Author: rub $
-// | revision      : $Revision: 1912 $
 // +-----------------------------------------------------------------------+
 // | This program is free software; you can redistribute it and/or modify  |
Index: extensions/Icy_Picture_Modify/main.inc.php
===================================================================
--- extensions/Icy_Picture_Modify/main.inc.php	(revision 16494)
+++ extensions/Icy_Picture_Modify/main.inc.php	(revision 16495)
@@ -2,5 +2,5 @@
 /*
 Plugin Name: Icy Modify Picture
-Version: 1.1.2
+Version: 2.0.0
 Description: Allow users to modify pictures they uploaded
 Plugin URI: http://piwigo.org/ext/extension_view.php?eid=563
@@ -14,15 +14,33 @@
 }
 
-# Should be ./plugins/icy_picture_modify/
 define('ICY_PICTURE_MODIFY_PATH' , PHPWG_PLUGINS_PATH.basename(dirname(__FILE__)).'/');
-include_once(ICY_PICTURE_MODIFY_PATH.'include/functions_icy_picture_modify.inc.php');
+require_once(ICY_PICTURE_MODIFY_PATH.'include/functions_icy_picture_modify.inc.php');
 
-# Hooks declaration
+# Variable declarations ################################################
+
+global $ICY_ACL;
+
+# Hooks declarations ###################################################
 
 add_event_handler('loc_end_section_init', 'icy_picture_modify_section_init');
-add_event_handler('loc_end_index', 'icy_picture_modify_index');
+remove_event_handler('loc_end_index', 'community_index');
+add_event_handler('loc_end_index', 'icy_picture_modify_index', 40);
+
 add_event_handler('loc_begin_picture', 'icy_picture_modify_loc_begin_picture');
+add_event_handler('init','icy_picture_modify_fix_community_acl', 40);
+# add_event_handler('login_success', );
 
-# Hooks definitions
+add_event_handler('blockmanager_apply', 'icy_picture_modify_fix_community_acl', 40);
+add_event_handler('ws_invoke_allowed', 'icy_picture_modify_fix_community_acl', 40);
+add_event_handler('ws_add_methods', 'icy_picture_modify_fix_community_acl', 40);
+add_event_handler('community_ws_categories_getList', 'icy_picture_modify_fix_community_acl', 40);
+add_event_handler('sendResponse', 'icy_picture_modify_fix_community_acl', 40);
+
+# Hooks definitions ####################################################
+
+function icy_picture_modify_fix_community_acl()
+{
+  icy_acl_fix_community(icy_acl_load_configuration());
+}
 
 function icy_picture_modify_section_init()
@@ -40,7 +58,15 @@
   global $page;
 
-  if (isset($page['section']) and $page['section'] == 'icy_picture_modify')
+  if (! isset($page['section'])) {
+    return TRUE;
+  }
+
+  if ($page['section'] == 'icy_picture_modify')
   {
     include(ICY_PICTURE_MODIFY_PATH.'icy_picture_modify.php');
+  }
+  elseif ($page['section'] == 'add_photos') {
+    icy_picture_modify_fix_community_acl(TRUE);
+    include(ICY_PICTURE_MODIFY_PATH.'add_photos.php');
   }
 }
@@ -51,5 +77,8 @@
 {
   global $conf, $template, $page, $user;
-  if ((!is_admin()) and icy_check_image_owner($page['image_id'], $user['id']))
+
+  icy_acl_load_configuration();
+
+  if (icy_image_editable($page['image_id']))
   {
     $url_admin =
Index: extensions/Icy_Picture_Modify/template/icy_picture_modify.tpl
===================================================================
--- extensions/Icy_Picture_Modify/template/icy_picture_modify.tpl	(revision 16494)
+++ extensions/Icy_Picture_Modify/template/icy_picture_modify.tpl	(revision 16495)
@@ -47,7 +47,10 @@
   {/if}
   {if !url_is_remote($PATH)}
+  {if isset($U_SYNC) }
   <li><a href="{$U_SYNC}" title="{'synchronize'|@translate}"><img src="{$ICY_PICTURE_MODIFY_PATH}/template/icon/sync_metadata.png" class="button" alt="{'synchronize'|@translate}"></a></li>
-
+  {/if}
+  {if isset($U_IMAGE_DELETABLE) }
   <li><a href="{$U_DELETE}" title="{'delete photo'|@translate}"><img src="{$ICY_PICTURE_MODIFY_PATH}/template/icon/category_delete.png" class="button" alt="{'delete photo'|@translate}" onclick="return confirm('{'Are you sure?'|@translate|@escape:javascript}');"></a></li>
+  {/if}
   {/if}
 </ul>
