diff --git a/modules/websubmit/lib/websubmit_managedocfiles.py b/modules/websubmit/lib/websubmit_managedocfiles.py
index 45b862334..f4fe7ab17 100644
--- a/modules/websubmit/lib/websubmit_managedocfiles.py
+++ b/modules/websubmit/lib/websubmit_managedocfiles.py
@@ -1,2780 +1,2780 @@
 ## $Id: Revise_Files.py,v 1.37 2009/03/26 15:11:05 jerome Exp $
 
 ## This file is part of Invenio.
 ## Copyright (C) 2010, 2011 CERN.
 ##
 ## Invenio 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; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## Invenio 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 Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 """
 WebSubmit Upload File Interface utils
 =====================================
 
 Tools to help with creation of file management interfaces.
 
 Contains the two main functions `create_file_upload_interface' and
 `move_uploaded_files_to_storage', which must be run one after the
 other:
 
  - create_file_upload_interface: Generates the HTML of an interface to
    revise files of a given record. The actions on the files are
    recorded in a working directory, but not applied to the record.
 
  - move_uploaded_files_to_storage: Applies/executes the modifications
    on files as recorded by the `create_file_upload_interface'
    function.
 
 Theses functions are a complex interplay of HTML, Javascript and HTTP
 requests. They are not meant to be used in any type of scenario, but
 require to be used in extremely specific contexts (Currently in
 WebSubmit Response Elements, WebSubmit functions and the WebSubmit
 File Management interface).
 
 NOTES:
 ======
 
  - Comments are not considered as a property of bibdocfiles, but
    bibdocs: this conflicts with the APIs
 
 FIXME:
 ======
 
  - refactor into smaller components. Eg. form processing in
    create_file_upload_interface could be move outside the function.
 
  - better differentiate between revised file, and added format
    (currently when adding a format, the whole bibdoc is marked as
    updated, and all links are removed)
 
  - After a file has been revised or added, add a 'check' icon
 
  - One issue: if we allow deletion or renaming, we might lose track of
    a bibdoc: someone adds X, renames X->Y, and adds again another file
    with name X: when executing actions, we will add the second X, and
    rename it to Y
    -> need to go back in previous action when renaming... or check
    that name has never been used..
 
 DEPENDENCIES:
 =============
   - jQuery Form plugin U{http://jquery.malsup.com/form/}
 """
 import cPickle
 import os
 import time
 import cgi
 
 from urllib import urlencode
 
 from invenio.config import \
      CFG_SITE_LANG, \
      CFG_SITE_URL, \
      CFG_WEBSUBMIT_STORAGEDIR, \
-     CFG_TMPDIR, \
+     CFG_TMPSHAREDDIR, \
      CFG_SITE_SUPPORT_EMAIL
 from invenio.messages import gettext_set_language
 from invenio.bibdocfilecli import cli_fix_marc
 from invenio.bibdocfile import BibRecDocs, \
      decompose_file, calculate_md5, BibDocFile, \
      InvenioWebSubmitFileError, BibDocMoreInfo
 from invenio.websubmit_functions.Shared_Functions import \
      createRelatedFormats
 from invenio.errorlib import register_exception
 from invenio.dbquery import run_sql
 from invenio.websubmit_icon_creator import \
      create_icon, InvenioWebSubmitIconCreatorError
 from invenio.urlutils import create_html_mailto
 from invenio.websubmit_config import CFG_WEBSUBMIT_DEFAULT_ICON_SUBFORMAT
 
 CFG_ALLOWED_ACTIONS = ['revise', 'delete', 'add', 'addFormat']
 
 def create_file_upload_interface(recid,
                                  form=None,
                                  print_outside_form_tag=True,
                                  print_envelope=True,
                                  include_headers=False,
                                  ln=CFG_SITE_LANG,
                                  minsize='', maxsize='',
                                  doctypes_and_desc=None,
                                  can_delete_doctypes=None,
                                  can_revise_doctypes=None,
                                  can_describe_doctypes=None,
                                  can_comment_doctypes=None,
                                  can_keep_doctypes=None,
                                  can_rename_doctypes=None,
                                  can_add_format_to_doctypes=None,
                                  create_related_formats=True,
                                  can_name_new_files=True,
                                  keep_default=True, show_links=True,
                                  file_label=None, filename_label=None,
                                  description_label=None, comment_label=None,
                                  restrictions_and_desc=None,
                                  can_restrict_doctypes=None,
                                  restriction_label=None,
                                  doctypes_to_default_filename=None,
                                  max_files_for_doctype=None,
                                  sbm_indir=None, sbm_doctype=None, sbm_access=None,
                                  uid=None, sbm_curdir=None,
                                  display_hidden_files=False, protect_hidden_files=True):
     """
     Returns the HTML for the file upload interface.
 
     @param recid: the id of the record to edit files
     @type recid: int or None
 
     @param form: the form sent by the user's browser in response to a
                  user action. This is used to read and record user's
                  actions.
     @param form: as returned by the interface handler.
 
     @param print_outside_form_tag: display encapsulating <form> tag or
                                    not
     @type print_outside_form_tag: boolean
 
     @param print_envelope: (internal parameter) if True, return the
                            encapsulating initial markup, otherwise
                            skip it.
     @type print_envelope: boolean
 
     @param include_headers: include javascript and css headers in the
                             body of the page. If you set this to
                             False, you must take care of including
                             these headers in your page header. Setting
                             this parameter to True is useful if you
                             cannot change the page header.
     @type include_headers: boolean
 
     @param ln: language
     @type ln: string
 
     @param minsize: the minimum size (in bytes) allowed for the
                     uploaded files. Files not big enough are
                     discarded.
     @type minsize: int
 
     @param maxsize: the maximum size (in bytes) allowed for the
                     uploaded files. Files too big are discarded.
     @type maxsize: int
 
     @param doctypes_and_desc: the list of doctypes (like 'Main' or
                               'Additional') and their description that users
                               can choose from when adding new files.
                                 - When no value is provided, users cannot add new
                                   file (they can only revise/delete/add format)
                                 - When a single value is given, it is used as
                                   default doctype for all new documents
 
                               Order is relevant
                               Eg:
                               [('main', 'Main document'), ('additional', 'Figure, schema. etc')]
     @type doctypes_and_desc: list(tuple(string, string))
 
     @param restrictions_and_desc: the list of restrictions (like 'Restricted' or
                          'No Restriction') and their description that
                          users can choose from when adding or revising
                          files. Restrictions can then be configured at
                          the level of WebAccess.
                            - When no value is provided, no restriction is
                              applied
                            - When a single value is given, it is used as
                              default resctriction for all documents.
                            - The first value of the list is used as default
                              restriction if the user if not given the
                              choice of the restriction. Order is relevant
 
                          Eg:
                          [('', 'No restriction'), ('restr', 'Restricted')]
     @type restrictions_and_desc: list(tuple(string, string))
 
     @param can_delete_doctypes: the list of doctypes that users are
                                 allowed to delete.
                                 Eg: ['main', 'additional']
                                 Use ['*'] for "all doctypes"
     @type can_delete_doctypes: list(string)
 
     @param can_revise_doctypes: the list of doctypes that users are
                                 allowed to revise
                                 Eg: ['main', 'additional']
                                 Use ['*'] for "all doctypes"
     @type can_revise_doctypes: list(string)
 
     @param can_describe_doctypes: the list of doctypes that users are
                                   allowed to describe
                                   Eg: ['main', 'additional']
                                   Use ['*'] for "all doctypes"
     @type can_describe_doctypes: list(string)
 
     @param can_comment_doctypes: the list of doctypes that users are
                                  allowed to comment
                                  Eg: ['main', 'additional']
                                  Use ['*'] for "all doctypes"
     @type can_comment_doctypes: list(string)
 
     @param can_keep_doctypes: the list of doctypes for which users can
                          choose to keep previous versions visible when
                          revising a file (i.e. 'Keep previous version'
                          checkbox). See also parameter 'keepDefault'.
                          Note that this parameter is ~ignored when
                          revising the attributes of a file (comment,
                          description) without uploading a new
                          file. See also parameter
                          Move_Uploaded_Files_to_Storage.force_file_revision
                          Eg: ['main', 'additional']
                          Use ['*'] for "all doctypes"
     @type can_keep_doctypes: list(string)
 
 
     @param can_add_format_to_doctypes: the list of doctypes for which users can
                               add new formats. If there is no value,
                               then no 'add format' link nor warning
                               about losing old formats are displayed.
                               Eg: ['main', 'additional']
                               Use ['*'] for "all doctypes"
     @type can_add_format_to_doctypes: list(string)
 
     @param can_restrict_doctypes: the list of doctypes for which users can
                              choose the access restrictions when adding or
                              revising a file. If no value is given:
                                - no restriction is applied if none is defined
                                  in the 'restrictions' parameter.
                                - else the *first* value of the 'restrictions'
                                  parameter is used as default restriction.
 
                              Eg: ['main', 'additional']
                              Use ['*'] for "all doctypes"
     @type can_restrict_doctypes : list(string)
 
     @param can_rename_doctypes: the list of doctypes that users are allowed
                            to rename (when revising)
                            Eg: ['main', 'additional']
                            Use ['*'] for "all doctypes"
     @type can_rename_doctypes: list(string)
 
     @param can_name_new_files: if user can choose the name of the files they
                          upload or not
     @type can_name_new_files: boolean
 
     @param doctypes_to_default_filename: Rename uploaded files to admin-chosen
                                  values. To rename to a value found in a file in curdir,
                                  use 'file:' prefix to specify the file to read from.
                                  Eg:
                                  {'main': 'file:RN', 'additional': 'foo'}
 
                                  If the same doctype is submitted
                                  several times, a"-%i" suffix is added
                                  to the name defined in the file.
 
                                  When using 'file:' prefix, the name
                                  is only resolved at the end of the
                                  submission, when attaching the file.
 
                                  The default filenames are overriden
                                  by user-chosen names if you allow
                                  'can_name_new_files' or
                                  'can_rename_doctypes', excepted if the
                                  name is prefixed with 'file:'.
     @type doctypes_to_default_filename: dict
 
     @param max_files_for_doctype: the maximum number of files that users can
                           upload for each doctype.
                           Eg: {'main': 1, 'additional': 2}
 
                           Do not specify the doctype here to have an
                           unlimited number of files for a given
                           doctype.
     @type max_files_for_doctype: dict
 
     @param create_related_formats: if uploaded files get converted to
                                      whatever format we can or not
     @type create_related_formats: boolean
 
     @param keep_default: the default behaviour for keeping or not previous
                      version of files when users cannot choose (no
                      value in can_keep_doctypes).
                      Note that this parameter is ignored when revising
                      the attributes of a file (comment, description)
                      without uploading a new file. See also parameter
                      Move_Uploaded_Files_to_Storage.force_file_revision
     @type keep_default: boolean
 
     @param show_links: if we display links to files when possible or
                          not
     @type show_links: boolean
 
     @param file_label: the label for the file field
     @type file_label: string
 
     @param filename_label: the label for the file name field
     @type filename_label: string
 
     @param description_label: the label for the description field
     @type description_label: string
 
     @param comment_label: the label for the comments field
     @type comment_label: string
 
     @param restriction_label: the label in front of the restrictions list
     @type restriction_label: string
 
     @param sbm_indir: the submission indir parameter, in case the
                       function is used in a WebSubmit submission
                       context.
                       This value will be used to retrieve where to
                       read the current state of the interface and
                       store uploaded files
     @type sbm_indir : string
 
     @param sbm_doctype: the submission doctype parameter, in case the
                         function is used in a WebSubmit submission
                         context.
                         This value will be used to retrieve where to
                         read the current state of the interface and
                         store uploaded files
     @type sbm_doctype: string
 
     @param sbm_access: the submission access parameter. Must be
                        specified in the context of WebSubmit
                        submission, as well when used in the
                        WebSubmit Admin file management interface.
 
                        This value will be used to retrieve where to
                        read the current state of the interface and
                        store uploaded files
     @type sbm_access: string
 
     @param sbm_curdir: the submission curdir parameter. Must be
                        specified in the context of WebSubmit
                        function Create_Upload_File_Interface.
 
                        This value will be used to retrieve where to
                        read the current state of the interface and
                        store uploaded files.
     @type sbm_curdir: string
 
     @param uid: the user id
     @type uid: int
 
     @param display_hidden_files: if bibdoc containing bibdocfiles
                                  flagged as 'HIDDEN' should be
                                  displayed or not.
     @type display_hidden_files: boolean
 
     @param protect_hidden_files: if bibdoc containing bibdocfiles
                                  flagged as 'HIDDEN' can be edited
                                  (revise, delete, add format) or not.
     @type protect_hidden_files: boolean
 
     @return Tuple (errorcode, html)
     """
     # Clean and set up a few parameters
     _ = gettext_set_language(ln)
     body = ''
     if not file_label:
         file_label = _('Choose a file')
     if not filename_label:
         filename_label = _('Name')
     if not description_label:
         description_label = _('Description')
     if not comment_label:
         comment_label = _('Comment')
     if not restriction_label:
         restriction_label = _('Access')
     if not doctypes_and_desc:
         doctypes_and_desc = []
     if not can_delete_doctypes:
         can_delete_doctypes = []
     if not can_revise_doctypes:
         can_revise_doctypes = []
     if not can_describe_doctypes:
         can_describe_doctypes = []
     if not can_comment_doctypes:
         can_comment_doctypes = []
     if not can_keep_doctypes:
         can_keep_doctypes = []
     if not can_rename_doctypes:
         can_rename_doctypes = []
     if not can_add_format_to_doctypes:
         can_add_format_to_doctypes = []
     if not restrictions_and_desc:
         restrictions_and_desc = []
     if not can_restrict_doctypes:
         can_restrict_doctypes = []
     if not doctypes_to_default_filename:
         doctypes_to_default_filename = {}
     if not max_files_for_doctype:
         max_files_for_doctype = {}
 
     doctypes = [doctype for (doctype, desc) in doctypes_and_desc]
 
     # Retrieve/build a working directory to save uploaded files and
     # states + configuration.
     working_dir = None
     if sbm_indir and sbm_doctype and sbm_access:
         # Write/read configuration to/from working_dir (WebSubmit mode).
         # Retrieve the interface configuration from the current
         # submission directory.
         working_dir = os.path.join(CFG_WEBSUBMIT_STORAGEDIR,
                               sbm_indir,
                               sbm_doctype,
                               sbm_access)
         try:
             assert(working_dir == os.path.abspath(working_dir))
         except AssertionError:
             register_exception(prefix='Cannot create file upload interface: ' + \
                                + 'missing parameter ',
                                alert_admin=True)
             return (1, "Unauthorized parameters")
 
         form_url_params = "?" + urlencode({'access': sbm_access,
                                            'indir': sbm_indir,
                                            'doctype': sbm_doctype})
     elif uid and sbm_access:
         # WebSubmit File Management (admin) interface mode.
-        # Working directory is in CFG_TMPDIR
-        working_dir = os.path.join(CFG_TMPDIR,
+        # Working directory is in CFG_TMPSHAREDDIR
+        working_dir = os.path.join(CFG_TMPSHAREDDIR,
                               'websubmit_upload_interface_config_' + str(uid),
                               sbm_access)
         try:
             assert(working_dir == os.path.abspath(working_dir))
         except AssertionError:
             register_exception(prefix='Some user tried to access ' \
                                + working_dir + \
                                ' which is different than ' + \
                                os.path.abspath(working_dir),
                                alert_admin=True)
             return (1, "Unauthorized parameters")
         if not os.path.exists(working_dir):
             os.makedirs(working_dir)
 
         form_url_params = "?" + urlencode({'access': sbm_access})
     elif sbm_curdir:
         # WebSubmit Create_Upload_File_Interface.py function
         working_dir = sbm_curdir
         form_url_params = None
     else:
         register_exception(prefix='Some user tried to access ' \
                            + working_dir + \
                            ' which is different than ' + \
                            os.path.abspath(working_dir),
                            alert_admin=True)
         return (1, "Unauthorized parameters")
 
     # Save interface configuration, if this is the first time we come
     # here, or else load parameters
     try:
         parameters = _read_file_revision_interface_configuration_from_disk(working_dir)
         (minsize, maxsize, doctypes_and_desc, doctypes,
          can_delete_doctypes, can_revise_doctypes,
          can_describe_doctypes,
          can_comment_doctypes, can_keep_doctypes,
          can_rename_doctypes,
          can_add_format_to_doctypes, create_related_formats,
          can_name_new_files, keep_default, show_links,
          file_label, filename_label, description_label,
          comment_label, restrictions_and_desc,
          can_restrict_doctypes,
          restriction_label, doctypes_to_default_filename,
          max_files_for_doctype, print_outside_form_tag,
          display_hidden_files, protect_hidden_files) = parameters
     except:
         # Initial display of the interface: save configuration to
         # disk for later reuse
         parameters = (minsize, maxsize, doctypes_and_desc, doctypes,
                       can_delete_doctypes, can_revise_doctypes,
                       can_describe_doctypes,
                       can_comment_doctypes, can_keep_doctypes,
                       can_rename_doctypes,
                       can_add_format_to_doctypes, create_related_formats,
                       can_name_new_files, keep_default, show_links,
                       file_label, filename_label, description_label,
                       comment_label, restrictions_and_desc,
                       can_restrict_doctypes,
                       restriction_label, doctypes_to_default_filename,
                       max_files_for_doctype, print_outside_form_tag,
                       display_hidden_files, protect_hidden_files)
         _write_file_revision_interface_configuration_to_disk(working_dir, parameters)
 
     # Get the existing bibdocs as well as the actions performed during
     # the former revise sessions of the user, to build an updated list
     # of documents. We will use it to check if last action performed
     # by user is allowed.
     performed_actions = read_actions_log(working_dir)
     if recid:
         bibrecdocs = BibRecDocs(recid)
         # Create the list of files based on current files and performed
         # actions
         bibdocs = bibrecdocs.list_bibdocs()
     else:
         bibdocs = []
 
     # "merge":
     abstract_bibdocs = build_updated_files_list(bibdocs,
                                                 performed_actions,
                                                 recid or -1,
                                                 display_hidden_files)
 
     # If any, process form submitted by user
     if form:
         ## Get and clean parameters received from user
         (file_action, file_target, file_target_doctype,
          keep_previous_files, file_description, file_comment, file_rename,
          file_doctype, file_restriction, uploaded_filename, uploaded_filepath) = \
          wash_form_parameters(form, abstract_bibdocs, can_keep_doctypes,
          keep_default, can_describe_doctypes, can_comment_doctypes,
          can_rename_doctypes, can_name_new_files, can_restrict_doctypes,
          doctypes_to_default_filename, working_dir)
 
         if protect_hidden_files and \
                (file_action in ['revise', 'addFormat', 'delete']) and \
                is_hidden_for_docname(file_target, abstract_bibdocs):
             # Sanity check. We should not let editing
             file_action = ''
             body += '<script>alert("%s");</script>' % \
                     _("The file you want to edit is protected against modifications. Your action has not been applied")
 
         ## Check the last action performed by user, and log it if
         ## everything is ok
         if uploaded_filepath and \
                ((file_action == 'add' and (file_doctype in doctypes)) or \
                 (file_action == 'revise' and \
                  ((file_target_doctype in can_revise_doctypes) or \
                   '*' in can_revise_doctypes)) or
                 (file_action == 'addFormat' and \
                  ((file_target_doctype in can_add_format_to_doctypes) or \
                   '*' in can_add_format_to_doctypes))):
             # A file has been uploaded (user has revised or added a file,
             # or a format)
             dirname, filename, extension = decompose_file(uploaded_filepath)
             os.unlink("%s/myfile" % working_dir)
             if minsize.isdigit() and os.path.getsize(uploaded_filepath) < int(minsize):
                 os.unlink(uploaded_filepath)
                 body += '<script>alert("%s");</script>' % \
                        (_("The uploaded file is too small (<%i o) and has therefore not been considered") % \
                         int(minsize)).replace('"', '\\"')
             elif maxsize.isdigit() and os.path.getsize(uploaded_filepath) > int(maxsize):
                 os.unlink(uploaded_filepath)
                 body += '<script>alert("%s");</script>' % \
                        (_("The uploaded file is too big (>%i o) and has therefore not been considered") % \
                         int(maxsize)).replace('"', '\\"')
             elif len(filename) + len(extension) + 4 > 255:
                 # Max filename = 256, including extension and version that
                 # will be appended later by BibDoc
                 os.unlink(uploaded_filepath)
                 body += '<script>alert("%s");</script>' % \
                        _("The uploaded file name is too long and has therefore not been considered").replace('"', '\\"')
 
             elif file_action == 'add' and \
                      max_files_for_doctype.has_key(file_doctype) and \
                      max_files_for_doctype[file_doctype] < \
                      (len([bibdoc for bibdoc in abstract_bibdocs \
                            if bibdoc['get_type'] == file_doctype]) + 1):
                 # User has tried to upload more than allowed for this
                 # doctype.  Should never happen, unless the user did some
                 # nasty things
                 os.unlink(uploaded_filepath)
                 body += '<script>alert("%s");</script>' % \
                        _("You have already reached the maximum number of files for this type of document").replace('"', '\\"')
 
             else:
                 # Prepare to move file to
                 # working_dir/files/updated/doctype/bibdocname/
                 folder_doctype = file_doctype or \
                                  bibrecdocs.get_bibdoc(file_target).get_type()
                 folder_bibdocname = file_rename or file_target or filename
                 new_uploaded_filepath = os.path.join(working_dir, 'files', 'updated',
                                             folder_doctype,
                                             folder_bibdocname, uploaded_filename)
 
                 # First check that we do not conflict with an already
                 # existing bibdoc name
                 if file_action == "add" and \
                        ((filename in [bibdoc['get_docname'] for bibdoc \
                                       in abstract_bibdocs] and not file_rename) or \
                         file_rename in [bibdoc['get_docname'] for bibdoc \
                                         in abstract_bibdocs]):
                     # A file with that name already exist. Cancel action
                     # and tell user.
                     os.unlink(uploaded_filepath)
                     body += '<script>alert("%s");</script>' % \
                            (_("A file named %s already exists. Please choose another name.") % \
                             (file_rename or filename)).replace('"', '\\"')
 
                 elif file_action == "revise" and \
                          file_rename != file_target and \
                          file_rename in [bibdoc['get_docname'] for bibdoc \
                                          in abstract_bibdocs]:
                     # A file different from the one to revise already has
                     # the same bibdocname
                     os.unlink(uploaded_filepath)
                     body += '<script>alert("%s");</script>' % \
                            (_("A file named %s already exists. Please choose another name.") % \
                             file_rename).replace('"', '\\"')
 
                 elif file_action == "addFormat" and \
                          (extension in \
                           get_extensions_for_docname(file_target,
                                                      abstract_bibdocs)):
                     # A file with that extension already exists. Cancel
                     # action and tell user.
                     os.unlink(uploaded_filepath)
                     body += '<script>alert("%s");</script>' % \
                            (_("A file with format '%s' already exists. Please upload another format.") % \
                             extension).replace('"', '\\"')
                 elif '.' in file_rename  or '/' in file_rename or "\\" in file_rename or \
                          not os.path.abspath(new_uploaded_filepath).startswith(os.path.join(working_dir, 'files', 'updated')):
                     # We forbid usage of a few characters, for the good of
                     # everybody...
                     os.unlink(uploaded_filepath)
                     body += '<script>alert("%s");</script>' % \
                            _("You are not allowed to use dot '.', slash '/', or backslash '\\\\' in file names. Choose a different name and upload your file again. In particular, note that you should not include the extension in the renaming field.").replace('"', '\\"')
                 else:
                     # No conflict with file name
 
                     # When revising, delete previously uploaded files for
                     # this entry, so that we do not execute the
                     # corresponding action
                     if file_action == "revise":
                         for path_to_delete in \
                                 get_uploaded_files_for_docname(working_dir, file_target):
                             delete_file(working_dir, path_to_delete)
 
                     # Move uploaded file to working_dir/files/updated/doctype/bibdocname/
                     os.renames(uploaded_filepath, new_uploaded_filepath)
 
                     if file_action == "add":
                         # if not bibrecdocs.check_file_exists(new_uploaded_filepath): # No need to check: done before...
                         # Log
                         if file_rename != '':
                             # at this point, bibdocname is specified
                             # name, no need to 'rename'
                             filename = file_rename
                         log_action(working_dir, file_action, filename,
                                    new_uploaded_filepath, file_rename,
                                    file_description, file_comment,
                                    file_doctype, keep_previous_files,
                                    file_restriction)
 
                         # Automatically create additional formats when
                         # possible.
                         additional_formats = []
                         if create_related_formats:
                             additional_formats = createRelatedFormats(new_uploaded_filepath,
                                                                       overwrite=False)
 
                         for additional_format in additional_formats:
                             # Log
                             log_action(working_dir, 'addFormat', filename,
                                        additional_format, file_rename,
                                        file_description, file_comment,
                                        file_doctype, True, file_restriction)
 
                 if file_action == "revise" and file_target != "":
                     # Log
                     log_action(working_dir, file_action, file_target,
                                new_uploaded_filepath, file_rename,
                                file_description, file_comment,
                                file_target_doctype, keep_previous_files,
                                file_restriction)
                     # Automatically create additional formats when
                     # possible.
                     additional_formats = []
                     if create_related_formats:
                         additional_formats = createRelatedFormats(new_uploaded_filepath,
                                                                   overwrite=False)
 
                     for additional_format in additional_formats:
                         # Log
                         log_action(working_dir, 'addFormat',
                                    (file_rename or file_target),
                                    additional_format, file_rename,
                                    file_description, file_comment,
                                    file_target_doctype, True,
                                    file_restriction)
 
                 if file_action == "addFormat" and file_target != "":
                     # We have already checked above that this format does
                     # not already exist.
                     # Log
                     log_action(working_dir, file_action, file_target,
                                new_uploaded_filepath, file_rename,
                                file_description, file_comment,
                                file_target_doctype, keep_previous_files,
                                file_restriction)
 
         elif file_action in ["add", "addFormat"]:
             # No file found, but action involved adding file: ask user to
             # select a file
             body += """<script>
             alert("You did not specify a file. Please choose one before uploading.");
             </script>"""
 
         elif file_action ==  "revise" and file_target != "":
             # User has chosen to revise attributes of a file (comment,
             # name, etc.) without revising the file itself.
             if file_rename != file_target and \
                    file_rename in [bibdoc['get_docname'] for bibdoc \
                                    in abstract_bibdocs]:
                 # A file different from the one to revise already has
                 # the same bibdocname
                 body += '<script>alert("%s");</script>' % \
                        (_("A file named %s already exists. Please choose another name.") % \
                         file_rename).replace('"', '\\"')
             else:
                 # Log
                 log_action(working_dir, file_action, file_target,
                            "", file_rename,
                            file_description, file_comment,
                            file_target_doctype, keep_previous_files,
                            file_restriction)
 
 
         elif file_action == "delete" and file_target != "" and \
                  ((file_target_doctype in can_delete_doctypes) or \
                   '*' in can_delete_doctypes):
             # Delete previously uploaded files for this entry
             for path_to_delete in get_uploaded_files_for_docname(working_dir, file_target):
                 delete_file(working_dir, path_to_delete)
             # Log
             log_action(working_dir, file_action, file_target, "", file_rename,
                        file_description, file_comment, "",
                        keep_previous_files, file_restriction)
 
     ## Display
 
     performed_actions = read_actions_log(working_dir)
     #performed_actions = []
     if recid:
         bibrecdocs = BibRecDocs(recid)
         # Create the list of files based on current files and performed
         # actions
         bibdocs = bibrecdocs.list_bibdocs()
     else:
         bibdocs = []
 
     abstract_bibdocs = build_updated_files_list(bibdocs, performed_actions,
                                                 recid or -1, display_hidden_files)
     abstract_bibdocs.sort(lambda x, y: x['order'] - y['order'])
 
     # Display form and necessary CSS + Javscript
     #body += '<div>'
     #body += css
     js_can_describe_doctypes = repr({}.fromkeys(can_describe_doctypes, ''))
     js_can_comment_doctypes = repr({}.fromkeys(can_comment_doctypes, ''))
     js_can_restrict_doctypes = repr({}.fromkeys(can_restrict_doctypes, ''))
 
     # Prepare to display file revise panel "balloon".  Check if we
     # should display the list of doctypes or if it is not necessary (0
     # or 1 doctype). Also make sure that we do not exceed the maximum
     # number of files specified per doctype. The markup of the list of
     # doctypes is prepared here, and will be passed as parameter to
     # the display_revise_panel function
     cleaned_doctypes = [doctype for doctype in doctypes if
                         not max_files_for_doctype.has_key(doctype) or
                         (max_files_for_doctype[doctype] > \
                         len([bibdoc for bibdoc in abstract_bibdocs \
                              if bibdoc['get_type'] == doctype]))]
     doctypes_list = ""
     if len(cleaned_doctypes) > 1:
         doctypes_list = '<select id="fileDoctype" name="fileDoctype" onchange="var idx=this.selectedIndex;var doctype=this.options[idx].value;updateForm(doctype,'+','.join([js_can_describe_doctypes, js_can_comment_doctypes, js_can_restrict_doctypes])+');">' + \
                         '\n'.join(['<option value="' + doctype + '">' + \
                                    description + '</option>' \
                                    for (doctype, description) \
                                    in doctypes_and_desc if \
                                    doctype in cleaned_doctypes]) + \
                         '</select>'
     elif len(cleaned_doctypes) == 1:
         doctypes_list = '<input id="fileDoctype" name="fileDoctype" type="hidden" value="%s" />' % cleaned_doctypes[0]
 
     # Check if we should display the list of access restrictions or if
     # it is not necessary
     restrictions_list = ""
     if len(restrictions_and_desc) > 1:
         restrictions_list = '<select id="fileRestriction" name="fileRestriction">' + \
                         '\n'.join(['<option value="' + cgi.escape(restriction, True) + '">' + \
                                    cgi.escape(description) + '</option>' \
                                    for (restriction, description) \
                                    in restrictions_and_desc]) + \
                         '</select>'
         restrictions_list = '''<label for="restriction">%(restriction_label)s:</label>&nbsp;%(restrictions_list)s&nbsp;<small>[<a href="" onclick="alert('%(restriction_help)s');return false;">?</a>]</small>''' % \
                             {'restrictions_list': restrictions_list,
                              'restriction_label': restriction_label,
                              'restriction_help': _('Choose how you want to restrict access to this file.').replace("'", "\\'")}
 
     elif len(restrictions_and_desc) == 1:
         restrictions_list = '<select style="display:none" id="fileRestriction" name="fileRestriction"><option value="%(restriction_attr)s">%(restriction)s</option></select>' % {
             'restriction': cgi.escape(restrictions_and_desc[0][0]),
             'restriction_attr': cgi.escape(restrictions_and_desc[0][0], True)
         }
     else:
         restrictions_list = '<select style="display:none" id="fileRestriction" name="fileRestriction"></select>'
 
     # List the files
     body += '''
 <div id="reviseControl">
     <table class="reviseControlBrowser">'''
     i = 0
     for bibdoc in abstract_bibdocs:
         if bibdoc['list_latest_files']:
             i += 1
             body += create_file_row(bibdoc, can_delete_doctypes,
                                     can_rename_doctypes,
                                     can_revise_doctypes,
                                     can_describe_doctypes,
                                     can_comment_doctypes,
                                     can_keep_doctypes,
                                     can_add_format_to_doctypes,
                                     doctypes_list,
                                     show_links,
                                     can_restrict_doctypes,
                                     even=not (i % 2),
                                     ln=ln,
                                     form_url_params=form_url_params,
                                     protect_hidden_files=protect_hidden_files)
     body += '</table>'
     if len(cleaned_doctypes) > 0:
         body += '''<input type="button" onclick="%(display_revise_panel)s;updateForm('%(defaultSelectedDoctype)s', %(can_describe_doctypes)s, %(can_comment_doctypes)s, %(can_restrict_doctypes)s);return false;" value="%(add_new_file)s"/>''' % \
                {'display_revise_panel':javascript_display_revise_panel(action='add', target='', show_doctypes=True, show_keep_previous_versions=False, show_rename=can_name_new_files, show_description=True, show_comment=True, bibdocname='', description='', comment='', show_restrictions=True, restriction=len(restrictions_and_desc) > 0 and restrictions_and_desc[0][0] or '', doctypes=doctypes_list),
                 'defaultSelectedDoctype': cleaned_doctypes[0],
                 'add_new_file': _("Add new file"),
                 'can_describe_doctypes':js_can_describe_doctypes,
                 'can_comment_doctypes': repr({}.fromkeys(can_comment_doctypes, '')),
                 'can_restrict_doctypes': repr({}.fromkeys(can_restrict_doctypes, ''))}
 
     body += '</div>'
 
     if print_envelope:
         # We should print this only if we display for the first time
         body = '<div id="uploadFileInterface">' + body + '</div>'
         if include_headers:
             body = get_upload_file_interface_javascript(form_url_params) + \
                    get_upload_file_interface_css() + \
                    body
 
         # Display markup of the revision panel. This one is also
         # printed only at the beginning, so that it does not need to
         # be returned with each response
         body += revise_balloon % \
            {'CFG_SITE_URL': CFG_SITE_URL,
             'file_label': file_label,
             'filename_label': filename_label,
             'description_label': description_label,
             'comment_label': comment_label,
             'restrictions': restrictions_list,
             'previous_versions_help': _('You can decide to hide or not previous version(s) of this file.').replace("'", "\\'"),
             'revise_format_help': _('When you revise a file, the additional formats that you might have previously uploaded are removed, since they no longer up-to-date with the new file.').replace("'", "\\'"),
             'revise_format_warning': _('Alternative formats uploaded for current version of this file will be removed'),
             'previous_versions_label': _('Keep previous versions'),
             'cancel': _('Cancel'),
             'upload': _('Upload')}
         body += '''
         <input type="hidden" name="recid" value="%(recid)i"/>
         <input type="hidden" name="ln" value="%(ln)s"/>
         ''' % \
         {'recid': recid or -1,
          'ln': ln}
 
     # End submission button
     if sbm_curdir:
         body += '''<br /><div style="font-size:small">
      <input type="button" class="adminbutton" name="Submit" id="applyChanges" value="%(apply_changes)s" onClick="nextStep();"></div>''' % \
      {'apply_changes': _("Apply changes")}
 
         # Display a link to support email in case users have problem
         # revising/adding files
         mailto_link = create_html_mailto(email=CFG_SITE_SUPPORT_EMAIL,
                                          subject=_("Need help revising or adding files to record %(recid)s") % \
                                          {'recid': recid or ''},
                                          body=_("""Dear Support,
 I would need help to revise or add a file to record %(recid)s.
 I have attached the new version to this email.
 Best regards"""))
 
         problem_revising = _('Having a problem revising a file? Send the revised version to %(mailto_link)s.') % {'mailto_link': mailto_link}
         if len(cleaned_doctypes) > 0:
             # We can add files, so change note
             problem_revising = _('Having a problem adding or revising a file? Send the new/revised version to %(mailto_link)s.') % {'mailto_link': mailto_link}
 
         body += '<br />'
         body += problem_revising
 
     if print_envelope and print_outside_form_tag:
         body = '<form method="post" action="/submit/managedocfilesasync" id="uploadFileForm">' + body + '</form>'
 
     return (0, body)
 
 def create_file_row(abstract_bibdoc, can_delete_doctypes,
                     can_rename_doctypes, can_revise_doctypes,
                     can_describe_doctypes, can_comment_doctypes,
                     can_keep_doctypes, can_add_format_to_doctypes,
                     doctypes_list, show_links, can_restrict_doctypes,
                     even=False, ln=CFG_SITE_LANG, form_url_params='',
                     protect_hidden_files=True):
     """
     Creates a row in the files list representing the given abstract_bibdoc
 
     @param abstract_bibdoc: list of "fake" BibDocs: it is a list of dictionaries
                              with keys 'list_latest_files' and 'get_docname' with
                              values corresponding to what you would expect to receive
                              when calling their counterpart function on a real BibDoc
                              object.
 
     @param can_delete_doctypes: list of doctypes for which we allow users to delete
                              documents
 
     @param can_revise_doctypes: the list of doctypes that users are
                              allowed to revise.
 
     @param can_describe_doctypes: the list of doctypes that users are
                              allowed to describe.
 
     @param can_comment_doctypes: the list of doctypes that users are
                              allowed to comment.
 
     @param can_keep_doctypes: the list of doctypes for which users can
                              choose to keep previous versions visible
                              when revising a file (i.e. 'Keep previous
                              version' checkbox).
 
     @param can_rename_doctypes: the list of doctypes that users are
                              allowed to rename (when revising)
 
     @param can_add_format_to_doctypes: the list of doctypes for which users can
                              add new formats
 
     @param show_links: if we display links to files
 
     @param even: if the row is even or odd on the list
     @type even: boolean
 
     @param ln: language
     @type ln: string
 
     @param form_url_params: the
     @type form_url_params: string
 
     @param protect_hidden_files: if bibdoc containing bibdocfiles
                                  flagged as 'HIDDEN' can be edited
                                  (revise, delete, add format) or not.
     @type protect_hidden_files: boolean
 
     @return: an HTML formatted "file" row
     @rtype: string
     """
     _ = gettext_set_language(ln)
 
     # Try to retrieve "main format", to display as link for the
     # file. There is no such concept in BibDoc, but let's just try to
     # get the pdf file if it exists
     main_bibdocfile = [bibdocfile for bibdocfile in abstract_bibdoc['list_latest_files'] \
                        if bibdocfile.get_format().strip('.').lower() == 'pdf']
     if len(main_bibdocfile) > 0:
         main_bibdocfile = main_bibdocfile[0]
     else:
         main_bibdocfile = abstract_bibdoc['list_latest_files'][0]
 
     main_bibdocfile_description = main_bibdocfile.get_description()
     if main_bibdocfile_description is None:
         main_bibdocfile_description = ''
 
     updated = abstract_bibdoc['updated'] # Has BibDoc been updated?
     hidden_p = abstract_bibdoc['hidden_p']
 
     # Main file row
     out = '<tr%s>' % (even and ' class="even"' or '')
     out += '<td class="reviseControlFileColumn"%s>' % (hidden_p and ' style="color:#99F"' or '')
     if not updated and show_links and not hidden_p:
         out += '<a target="_blank" href="' + main_bibdocfile.get_url() \
            + '">'
     out += abstract_bibdoc['get_docname']
     if hidden_p:
         out += ' <span style="font-size:small;font-style:italic;color:#888">(hidden)</span>'
     if not updated and show_links and not hidden_p:
         out += '</a>'
     if main_bibdocfile_description:
         out += ' (<em>' + main_bibdocfile_description + '</em>)'
     out += '</td>'
 
     (description, comment) = get_description_and_comment(abstract_bibdoc['list_latest_files'])
     restriction = abstract_bibdoc['get_status']
 
     # Revise link
     out += '<td class="reviseControlActionColumn">'
     if main_bibdocfile.get_type() in can_revise_doctypes or \
            '*' in can_revise_doctypes and not (hidden_p and protect_hidden_files):
         out += '[<a href="" onclick="%(display_revise_panel)s;return false;">%(revise)s</a>]' % \
                {'display_revise_panel': javascript_display_revise_panel(
             action='revise',
             target=abstract_bibdoc['get_docname'],
             show_doctypes=False,
             show_keep_previous_versions=(main_bibdocfile.get_type() in can_keep_doctypes) or '*' in can_keep_doctypes,
             show_rename=(main_bibdocfile.get_type() in can_rename_doctypes) or '*' in can_rename_doctypes,
             show_description=(main_bibdocfile.get_type() in can_describe_doctypes) or '*' in can_describe_doctypes,
             show_comment=(main_bibdocfile.get_type() in can_comment_doctypes) or '*' in can_comment_doctypes,
             bibdocname=abstract_bibdoc['get_docname'],
             description=description,
             comment=comment,
             show_restrictions=(main_bibdocfile.get_type() in can_restrict_doctypes) or '*' in can_restrict_doctypes,
             restriction=restriction,
             doctypes=doctypes_list),
                 'revise': _("revise")
                 }
 
     # Delete link
     if main_bibdocfile.get_type() in can_delete_doctypes or \
            '*' in can_delete_doctypes and not (hidden_p and protect_hidden_files):
         out += '''[<a href="" onclick="return askDelete('%(bibdocname)s', '%(form_url_params)s')">%(delete)s</a>]
         ''' % {'bibdocname': abstract_bibdoc['get_docname'].replace("'", "\\'").replace('"', '&quot;'),
                'delete': _("delete"),
                'form_url_params': form_url_params or ''}
     out += '''</td>'''
 
     # Format row
     out += '''<tr%s>
     <td class="reviseControlFormatColumn"%s>
         <img src="%s/img/tree_branch.gif" alt="">
     ''' % (even and ' class="even"' or '', hidden_p and ' style="color:#999"' or '', CFG_SITE_URL)
     for bibdocfile in abstract_bibdoc['list_latest_files']:
         if not updated and show_links and not hidden_p:
             out += '<a target="_blank" href="' + bibdocfile.get_url() + '">'
         out += bibdocfile.get_format().strip('.')
         if not updated and show_links and not hidden_p:
             out += '</a>'
         out += ' '
 
     # Add format link
     out += '<td class="reviseControlActionColumn">'
     if main_bibdocfile.get_type() in can_add_format_to_doctypes or \
            '*' in can_add_format_to_doctypes and not (hidden_p and protect_hidden_files):
         out += '[<a href="" onclick="%(display_revise_panel)s;return false;">%(add_format)s</a>]' % \
         {'display_revise_panel':javascript_display_revise_panel(
             action='addFormat',
             target=abstract_bibdoc['get_docname'],
             show_doctypes=False,
             show_keep_previous_versions=False,
             show_rename=False,
             show_description=False,
             show_comment=False,
             bibdocname='',
             description='',
             comment='',
             show_restrictions=False,
             restriction=restriction,
             doctypes=doctypes_list),
          'add_format':_("add format")}
 
     out += '</td></tr>'
 
     return out
 
 def build_updated_files_list(bibdocs, actions, recid, display_hidden_files=False):
     """
     Parses the list of BibDocs and builds an updated version to reflect
     the changes performed by the user of the file
 
     It is necessary to abstract the BibDocs since user wants to
     perform action on the files that are committed only at the end of
     the session.
 
     @param bibdocs: the original list of bibdocs on which we want to
                     build a new updated list
 
     @param actions: the list of actions performed by the user on the
                     files, and that we want to consider to build an
                     updated file list
 
     @param recid: the record ID to which the files belong
 
     @param display_hidden_files: if bibdoc containing bibdocfiles
                                  flagged as 'HIDDEN' should be
                                  displayed or not.
     @type display_hidden_files: boolean
     """
     abstract_bibdocs = {}
     i = 0
     for bibdoc in bibdocs:
         hidden_p = True in [bibdocfile.hidden_p() for bibdocfile in bibdoc.list_latest_files()]
         if not display_hidden_files and hidden_p:
             # Do not consider hidden files
             continue
         i += 1
         status = bibdoc.get_status()
         if status == "DELETED":
             status = ''
 
         abstract_bibdocs[bibdoc.get_docname()] = \
             {'list_latest_files': bibdoc.list_latest_files(),
              'get_docname': bibdoc.get_docname(),
              'updated': False,
              'get_type': bibdoc.get_type(),
              'get_status': status,
              'order': i,
              'hidden_p': hidden_p}
 
     for action, bibdoc_name, file_path, rename, description, \
             comment, doctype, keep_previous_versions, \
             file_restriction in actions:
         dirname, filename, fileformat = decompose_file(file_path)
         i += 1
         if action in ["add", "revise"] and \
                os.path.exists(file_path):
             checksum = calculate_md5(file_path)
             order = i
             if action == "revise" and \
                    abstract_bibdocs.has_key(bibdoc_name):
                 # Keep previous values
                 order = abstract_bibdocs[bibdoc_name]['order']
                 doctype = abstract_bibdocs[bibdoc_name]['get_type']
             if bibdoc_name.strip() == '' and rename.strip() == '':
                 bibdoc_name = os.path.extsep.join(filename.split(os.path.extsep)[:-1])
             elif rename.strip() != '' and \
                      abstract_bibdocs.has_key(bibdoc_name):
                 # Keep previous position
                 del abstract_bibdocs[bibdoc_name]
 
             # First instantiate a fake BibDocMoreInfo object, without any side effect
             more_info = BibDocMoreInfo(1, cPickle.dumps({}))
             if description is not None:
                 more_info.more_info['descriptions'] = {1: {fileformat:description}}
             if comment is not None:
                 more_info.more_info['comments'] = {1: {fileformat:comment}}
             abstract_bibdocs[(rename or bibdoc_name)] = \
                 {'list_latest_files': [BibDocFile(file_path, doctype, version=1,
                                                   name=(rename or bibdoc_name),
                                                   format=fileformat,
                                                   recid=int(recid), docid=-1,
                                                   status=file_restriction,
                                                   checksum=checksum,
                                                   more_info=more_info)],
                  'get_docname': rename or bibdoc_name,
                  'get_type': doctype,
                  'updated': True,
                  'get_status': file_restriction,
                  'order': order,
                  'hidden_p': False}
             abstract_bibdocs[(rename or bibdoc_name)]['updated'] = True
         elif action == "revise" and not file_path:
             # revision of attributes of a file (description, name,
             # comment or restriction) but no new file.
             abstract_bibdocs[bibdoc_name]['get_docname'] = rename or bibdoc_name
             abstract_bibdocs[bibdoc_name]['get_status'] = file_restriction
             set_description_and_comment(abstract_bibdocs[bibdoc_name]['list_latest_files'],
                                         description, comment)
             abstract_bibdocs[bibdoc_name]['updated'] = True
         elif action == "delete":
             if abstract_bibdocs.has_key(bibdoc_name):
                 del abstract_bibdocs[bibdoc_name]
         elif action == "addFormat" and \
                os.path.exists(file_path):
             checksum = calculate_md5(file_path)
             # Preserve type and status
             doctype = abstract_bibdocs[bibdoc_name]['get_type']
             file_restriction = abstract_bibdocs[bibdoc_name]['get_status']
             # First instantiate a fake BibDocMoreInfo object, without any side effect
             more_info = BibDocMoreInfo(1, cPickle.dumps({}))
             if description is not None:
                 more_info.more_info['descriptions'] = {1: {fileformat:description}}
             if comment is not None:
                 more_info.more_info['comments'] = {1: {fileformat:comment}}
             abstract_bibdocs[bibdoc_name]['list_latest_files'].append(\
                 BibDocFile(file_path, doctype, version=1,
                            name=(rename or bibdoc_name), format=fileformat,
                            recid=int(recid), docid=-1, status='',
                            checksum=checksum, more_info=more_info))
             abstract_bibdocs[bibdoc_name]['updated'] = True
 
     return abstract_bibdocs.values()
 
 def _read_file_revision_interface_configuration_from_disk(working_dir):
     """
     Read the configuration of the file revision interface from disk
 
     @param working_dir: the path to the working directory where we can find
                   the configuration file
     """
     input_file = open(os.path.join(working_dir, 'upload_interface.config'), 'rb')
     configuration = cPickle.load(input_file)
     input_file.close()
     return configuration
 
 def _write_file_revision_interface_configuration_to_disk(working_dir, parameters):
     """
     Write the configuration of the file revision interface to disk
 
     @param working_dir: the path to the working directory where we should
                   write the configuration.
 
     @param parameters: the parameters to write to disk
     """
     output = open(os.path.join(working_dir, 'upload_interface.config'), 'wb')
     cPickle.dump(parameters, output)
     output.close()
 
 def log_action(log_dir, action, bibdoc_name, file_path, rename,
                description, comment, doctype, keep_previous_versions,
                file_restriction):
     """
     Logs a new action performed by user on a BibDoc file.
 
     The log file record one action per line, each column being split
     by '<--->' ('---' is escaped from values 'rename', 'description',
     'comment' and 'bibdoc_name'). The original request for this
     format was motivated by the need to have it easily readable by
     other scripts. Not sure it still makes sense nowadays...
 
     Newlines are also reserved, and are escaped from the input values
     (necessary for the 'comment' field, which is the only one allowing
     newlines from the browser)
 
     Each line starts with the time of the action in the following
     format: '2008-06-20 08:02:04 --> '
 
     @param log_dir: directory where to save the log (ie. working_dir)
 
     @param action: the performed action (one of 'revise', 'delete',
                    'add', 'addFormat')
 
     @param bibdoc_name: the name of the bibdoc on which the change is
                         applied
 
     @param file_path: the path to the file that is going to be
                       integrated as bibdoc, if any (should be""
                       in case of action="delete", or action="revise"
                       when revising only attributes of a file)
 
     @param rename: the name used to display the bibdoc, instead of the
                    filename (can be None for no renaming)
 
     @param description: a description associated with the file
 
     @param comment: a comment associated with the file
 
     @param doctype: the category in which the file is going to be
                     integrated
 
     @param keep_previous_versions: if the previous versions of this
                                     file are to be hidden (0) or not (1)
 
     @param file_restriction: the restriction applied to the
                               file. Empty string if no restriction
     """
     log_file = os.path.join(log_dir, 'bibdocactions.log')
     try:
         file_desc = open(log_file, "a+")
         # We must escape new lines from comments in some way:
         comment = str(comment).replace('\\', '\\\\').replace('\r\n', '\\n\\r')
         msg = action                                 + '<--->' + \
               bibdoc_name.replace('---', '___')      + '<--->' + \
               file_path                              + '<--->' + \
               str(rename).replace('---', '___')      + '<--->' + \
               str(description).replace('---', '___') + '<--->' + \
               comment.replace('---', '___')          + '<--->' + \
               doctype                                + '<--->' + \
               str(int(keep_previous_versions))       + '<--->' + \
               file_restriction + '\n'
         file_desc.write("%s --> %s" %(time.strftime("%Y-%m-%d %H:%M:%S"), msg))
         file_desc.close()
     except Exception ,e:
         raise e
 
 def read_actions_log(log_dir):
     """
     Reads the logs of action to be performed on files
 
     See log_action(..) for more information about the structure of the
     log file.
 
     @param log_dir: the path to the directory from which to read the
                     log file
     @type log_dir: string
     """
     actions = []
     log_file = os.path.join(log_dir, 'bibdocactions.log')
     try:
         file_desc = open(log_file, "r")
         for line in file_desc.readlines():
             (timestamp, action) = line.split(' --> ', 1)
             try:
                 (action, bibdoc_name, file_path, rename, description,
                  comment, doctype, keep_previous_versions,
                  file_restriction) = action.rstrip('\n').split('<--->')
             except ValueError, e:
                 # Malformed action log
                 pass
 
             # Clean newline-escaped comment:
             comment = comment.replace('\\n\\r', '\r\n').replace('\\\\', '\\')
 
             # Perform some checking
             if action not in CFG_ALLOWED_ACTIONS:
                 # Malformed action log
                 pass
 
             try:
                 keep_previous_versions = int(keep_previous_versions)
             except:
                 # Malformed action log
                 keep_previous_versions = 1
                 pass
 
             actions.append((action, bibdoc_name, file_path, rename, \
                             description, comment, doctype,
                             keep_previous_versions, file_restriction))
         file_desc.close()
     except:
         pass
 
     return actions
 
 def javascript_display_revise_panel(action, target, show_doctypes, show_keep_previous_versions, show_rename, show_description, show_comment, bibdocname, description, comment, show_restrictions, restriction, doctypes):
     """
     Returns a correctly encoded call to the javascript function to
     display the revision panel.
     """
     def escape_js_string_param(input):
         "Escape string parameter to be used in Javascript function"
         return input.replace('\\', '\\\\').replace('\r', '\\r').replace('\n', '\\n').replace("'", "\\'").replace('"', '&quot;')
 
     return '''display_revise_panel(this, '%(action)s', '%(target)s', %(showDoctypes)s, %(showKeepPreviousVersions)s, %(showRename)s, %(showDescription)s, %(showComment)s, '%(bibdocname)s', '%(description)s', '%(comment)s', %(showRestrictions)s, '%(restriction)s', '%(doctypes)s')''' % \
            {'action': action,
             'showDoctypes': show_doctypes and 'true' or 'false',
             'target': escape_js_string_param(target),
             'bibdocname': escape_js_string_param(bibdocname),
             'showRename': show_rename and 'true' or 'false',
             'showKeepPreviousVersions': show_keep_previous_versions and 'true' or 'false',
             'showComment': show_comment and 'true' or 'false',
             'showDescription': show_description and 'true' or 'false',
             'description': description and escape_js_string_param(description) or '',
             'comment': comment and escape_js_string_param(comment) or '',
             'showRestrictions': show_restrictions and 'true' or 'false',
             'restriction': escape_js_string_param(restriction),
             'doctypes': escape_js_string_param(doctypes)}
 
 def get_uploaded_files_for_docname(log_dir, docname):
     """
     Given a docname, returns the paths to the files uploaded for this
     revision session.
 
     @param log_dir: the path to the directory that should contain the
                     uploaded files.
 
     @param docname: the name of the bibdoc for which we want to
                     retrieve files.
     """
     return [file_path for action, bibdoc_name, file_path, rename, \
             description, comment, doctype, keep_previous_versions , \
             file_restriction in read_actions_log(log_dir) \
             if bibdoc_name == docname and os.path.exists(file_path)]
 
 def get_bibdoc_for_docname(docname, abstract_bibdocs):
     """
     Given a docname, returns the corresponding bibdoc from the
     'abstract' bibdocs.
 
     Return None if not found
 
     @param docname: the name of the bibdoc we want to retrieve
 
     @param abstract_bibdocs: the list of bibdocs from which we want to
                              retrieve the bibdoc
     """
     bibdocs = [bibdoc for bibdoc in abstract_bibdocs \
                if bibdoc['get_docname'] == docname]
     if len(bibdocs) > 0:
         return bibdocs[0]
     else:
         return None
 
 def get_extensions_for_docname(docname, abstract_bibdocs):
     """
     Returns the list of extensions that exists for given bibdoc
     name in the given 'abstract' bibdocs.
 
     @param docname: the name of the bibdoc for wich we want to
                     retrieve the available extensions
 
     @param abstract_bibdocs: the list of bibdocs from which we want to
                              retrieve the bibdoc extensions
     """
 
     bibdocfiles = [bibdoc['list_latest_files'] for bibdoc \
                    in abstract_bibdocs \
                    if bibdoc['get_docname'] == docname]
     if len(bibdocfiles) > 0:
         # There should always be at most 1 matching docname, or 0 if
         # it is a new file
         return [bibdocfile.get_format() for bibdocfile \
                 in bibdocfiles[0]]
     return []
 
 def is_hidden_for_docname(docname, abstract_bibdocs):
     """
     Returns True if the bibdoc with given docname in abstract_bibdocs
     should be hidden. Also return True if docname cannot be found in
     abstract_bibdocs.
 
     @param docname: the name of the bibdoc for wich we want to
                     check if it is hidden or not
 
     @param abstract_bibdocs: the list of bibdocs from which we want to
                              look for the given docname
     """
     bibdocs = [bibdoc for bibdoc in abstract_bibdocs \
                    if bibdoc['get_docname'] == docname]
     if len(bibdocs) > 0:
         return bibdocs[0]['hidden_p']
     return True
 
 def get_description_and_comment(bibdocfiles):
     """
     Returns the first description and comment as tuple (description,
     comment) found in the given list of bibdocfile
 
     description and/or comment can be None.
 
     This function is needed since we do consider that there is one
     comment/description per bibdoc, and not per bibdocfile as APIs
     state.
 
     @param bibdocfiles: the list of files of a given bibdoc for which
                         we want to extract the description and comment.
     """
     description = None
     comment = None
     all_descriptions = [bibdocfile.get_description() for bibdocfile \
                         in bibdocfiles
                         if bibdocfile.get_description() not in ['', None]]
     if len(all_descriptions) > 0:
         description = all_descriptions[0]
 
     all_comments = [bibdocfile.get_comment() for bibdocfile \
                     in bibdocfiles
                     if bibdocfile.get_comment() not in ['', None]]
     if len(all_comments) > 0:
         comment = all_comments[0]
 
     return (description, comment)
 
 def set_description_and_comment(abstract_bibdocfiles, description, comment):
     """
     Set the description and comment to the given (abstract)
     bibdocfiles.
 
     description and/or comment can be None.
 
     This function is needed since we do consider that there is one
     comment/description per bibdoc, and not per bibdocfile as APIs
     state.
 
     @param abstract_bibdocfiles: the list of 'abstract' files of a
                         given bibdoc for which we want to set the
                         description and comment.
 
     @param description: the new description
     @param comment: the new comment
     """
     for bibdocfile in abstract_bibdocfiles:
         bibdocfile.description = description
         bibdocfile.comment = comment
 
 def delete_file(working_dir, file_path):
     """
     Deletes a file at given path from the file.
     In fact, we just move it to working_dir/files/trash
 
     @param working_dir: the path to the working directory
     @param file_path: the path to the file to delete
     """
     if os.path.exists(file_path):
         filename = os.path.split(file_path)[1]
         move_to = os.path.join(working_dir, 'files', 'trash',
                                filename +'_' + str(time.time()))
         os.renames(file_path, move_to)
 
 def wash_form_parameters(form, abstract_bibdocs, can_keep_doctypes,
                          keep_default, can_describe_doctypes,
                          can_comment_doctypes, can_rename_doctypes,
                          can_name_new_files, can_restrict_doctypes,
                          doctypes_to_default_filename, working_dir):
     """
     Washes the (user-defined) form parameters, taking into account the
     current state of the files and the admin defaults.
 
     @param form: the form of the function
 
     @param abstract_bibdocs: a representation of the current state of
                              the files, as returned by
                              build_updated_file_list(..)
 
     @param can_keep_doctypes: the list of doctypes for which we allow
                             users to choose to keep or not the
                             previous versions when revising.
     @type can_keep_doctypes: list
 
     @param keep_default: the admin-defined default for when users
                          cannot choose to keep or not previous version
                          of a revised file
     @type keep_default: boolean
 
     @param can_describe_doctypes: the list of doctypes for which we
                                   let users define descriptions.
     @type can_describe_doctypes: list
 
     @param can_comment_doctypes: the list of doctypes for which we let
                                  users define comments.
     @type can_comment_doctypes: list
 
     @param can_rename_doctypes: the list of doctypes for which we let
                                 users rename bibdoc when revising.
     @type can_rename_doctypes: list
 
     @param can_name_new_files: if we let users choose a name when
                                adding new files.
     @type can_name_new_files: boolean
 
     @param can_restrict_doctypes: the list of doctypes for which we
                                   let users define access
                                   restrictions.
     @type can_restrict_doctypes: list
 
     @param doctypes_to_default_filename: mapping from doctype to
                                          admin-chosen name for
                                          uploaded file.
     @type doctypes_to_default_filename: dict
 
     @param working_dir: the path to the current working directory
     @type working_dir: string
 
     @return: tuple (file_action, file_target, file_target_doctype,
         keep_previous_files, file_description, file_comment,
         file_rename, file_doctype, file_restriction) where::
 
          file_action: *str* the performed action ('add',
                        'revise','addFormat' or 'delete')
 
          file_target: *str* the bibdocname of the file on which the
                       action is performed (empty string when
                       file_action=='add')
 
          file_target_doctype: *str* the doctype of the file we will
                                work on.  Eg: ('main',
                                'additional'). Empty string with
                                file_action=='add'.
 
          keep_previous_files: *bool* if we keep the previous version of
                               the file or not. Only useful when
                               revising files.
 
          file_description: *str* the user-defined description to apply
                            to the file.  Empty string when no
                            description defined or when not applicable
 
          file_comment: *str* the user-defined comment to apply to the
                        file.  Empty string when no comment defined or
                        when not applicable
 
          file_rename: *str* the new name chosen by user for the
                       bibdoc. Empty string when not defined or when not
                       applicable.
 
          file_doctype: *str* the user-chosen doctype for the bibdoc
                        when file_action=='add', or the current doctype
                        of the file_target in other cases (doctype must
                        be preserved).
 
          file_restriction: *str* the user-selected restriction for the
                            file. Emptry string if not defined or when
                            not applicable.
 
          file_name: *str* the original name of the uploaded file. None
                     if no file uploaded
 
          file_path: *str* the full path to the file
 
     @rtype: tuple(string, string, string, boolean, string, string,
                   string, string, string, string, string)
     """
     # Action performed ...
     if form.has_key("fileAction") and \
            form['fileAction'] in CFG_ALLOWED_ACTIONS:
         file_action = str(form['fileAction']) # "add", "revise",
                                               # "addFormat" or "delete"
     else:
         file_action = ""
 
     # ... on file ...
     if form.has_key("fileTarget"):
         file_target = str(form['fileTarget']) # contains bibdocname
         # Also remember its doctype to make sure we do valid actions
         # on it
         corresponding_bibdoc = get_bibdoc_for_docname(file_target,
                                                       abstract_bibdocs)
         if corresponding_bibdoc is not None:
             file_target_doctype = corresponding_bibdoc['get_type']
         else:
             file_target_doctype = ""
     else:
         file_target = ""
         file_target_doctype = ""
 
     # ... with doctype?
     # Only useful when adding file: otherwise fileTarget doctype is
     # preserved
     file_doctype = file_target_doctype
     if form.has_key("fileDoctype") and \
            file_action == 'add':
         file_doctype = str(form['fileDoctype'])
 
     # ... keeping previous version? ...
     if file_target_doctype != '' and \
            not form.has_key("keepPreviousFiles"):
         # no corresponding key. Two possibilities:
         if file_target_doctype in can_keep_doctypes or \
                '*' in can_keep_doctypes:
             # User decided no to keep
             keep_previous_files = 0
         else:
             # No choice for user. Use default admin has chosen
             keep_previous_files = keep_default
     else:
         # Checkbox seems to be checked ...
         if file_target_doctype in can_keep_doctypes or \
                '*' in can_keep_doctypes:
             # ...and this is allowed
             keep_previous_files = 1
         else:
             # ...but this is not allowed
             keep_previous_files = keep_default
 
     # ... and decription? ...
     if form.has_key("description") and \
         (((file_action == 'revise' and \
            (file_target_doctype in can_describe_doctypes)) or \
           (file_action == 'add' and \
            (file_doctype in can_describe_doctypes))) \
          or '*' in can_describe_doctypes):
         file_description = str(form['description'])
     else:
         file_description = ''
 
     # ... and comment? ...
     if form.has_key("comment") and \
         (((file_action == 'revise' and \
            (file_target_doctype in can_comment_doctypes)) or \
           (file_action == 'add' and \
            (file_doctype in can_comment_doctypes))) \
          or '*' in can_comment_doctypes):
         file_comment = str(form['comment'])
     else:
         file_comment = ''
 
     # ... and rename to ? ...
     if form.has_key("rename") and \
         ((file_action == "revise" and \
           ((file_target_doctype in can_rename_doctypes) or \
            '*'  in can_rename_doctypes)) or \
          (file_action == "add" and \
           can_name_new_files)):
         file_rename = str(form['rename']) # contains new bibdocname if applicable
     elif file_action == "add" and \
              doctypes_to_default_filename.has_key(file_doctype):
         # Admin-chosen name.
         file_rename = doctypes_to_default_filename[file_doctype]
         if file_rename.lower().startswith('file:'):
             # We will define name at a later stage, i.e. when
             # submitting the file with bibdocfile. The name will be
             # chosen by reading content of a file in curdir
             file_rename = ''
         else:
             # Ensure name is unique, by appending a suffix
             file_rename = doctypes_to_default_filename[file_doctype]
             file_counter = 2
             while get_bibdoc_for_docname(file_rename, abstract_bibdocs):
                 if file_counter == 2:
                     file_rename += '-2'
                 else:
                     file_rename = file_rename[:-len(str(file_counter))] + \
                                   str(file_counter)
                 file_counter += 1
     else:
         file_rename = ''
 
     # ... and file restriction ? ...
     file_restriction = ''
     if form.has_key("fileRestriction"):
         # We cannot clean that value as it could be a restriction
         # declared in another submission. We keep this value.
         file_restriction = str(form['fileRestriction'])
 
     # ... and the file itself ? ...
     if form.has_key('myfile') and \
            hasattr(form['myfile'], "filename") and \
            form['myfile'].filename:
         dir_to_open = os.path.join(working_dir, 'files', 'myfile')
         if not os.path.exists(dir_to_open):
             try:
                 os.makedirs(dir_to_open)
             except:
                 pass
                 # Shall we continue?
         if os.path.exists(dir_to_open):
             form_field = form['myfile']
             file_name = form_field.filename
             form_file = form_field.file
             ## Before saving the file to disk, wash the filename (in particular
             ## washing away UNIX and Windows (e.g. DFS) paths):
             file_name = os.path.basename(file_name.split('\\')[-1])
             file_name = file_name.strip()
             if file_name != "":
                 # This may be dangerous if the file size is bigger than
                 # the available memory
                 file_path = os.path.join(dir_to_open, file_name)
                 if not os.path.exists(file_path):
                     # If file already exists, it means that it was
                     # handled by WebSubmit
                     fp = file(file_path, "wb")
                     chunk = form_file.read(10240)
                     while chunk:
                         fp.write(chunk)
                         chunk = form_file.read(10240)
                     fp.close()
                     fp = open(os.path.join(working_dir, "lastuploadedfile"), "w")
                     fp.write(file_name)
                     fp.close()
                     fp = open(os.path.join(working_dir, 'myfile'), "w")
                     fp.write(file_name)
                     fp.close()
     else:
         file_name = None
         file_path = None
 
     return (file_action, file_target, file_target_doctype,
             keep_previous_files, file_description, file_comment,
             file_rename, file_doctype, file_restriction, file_name,
             file_path)
 
 
 def move_uploaded_files_to_storage(working_dir, recid, icon_sizes,
                                    create_icon_doctypes,
                                    force_file_revision):
     """
     Apply the modifications on files (add/remove/revise etc.) made by
     users with one of the compatible interfaces (WebSubmit function
     `Create_Upload_Files_Interface.py'; WebSubmit element or WebSubmit
     File management interface using function
     `create_file_upload_interface').
 
     This function needs a "working directory" (working_dir) that contains a
     bibdocactions.log file with the list of actions to perform.
 
     @param working_dir: a path to the working directory containing actions to perform and files to attach
     @type working_dir: string
     @param recid: the recid to modify
     @type recid: int
     @param icon_sizes: the sizes of icons to create, as understood by
                       the websubmit icon creation tool
     @type icon_sizes: list(string)
     @param create_icon_doctypes: a list of doctype for which we want
                                  to create icons
     @type create_icon_doctypes: list(string)
     @param force_file_revision: when revising attributes of a file
                                 (comment, description) without
                                 uploading a new file, force a revision
                                 of the current version (so that old
                                 comment, description, etc. is kept
                                 or not)
     @type force_file_revision: bool
     """
     # We need to remember of some actions that cannot be performed,
     # because files have been deleted or moved after a renaming.
     # Those pending action must be applied when revising the bibdoc
     # with a file that exists (that means that the bibdoc has not been
     # deleted nor renamed by a later action)
     pending_bibdocs = {}
     newly_added_bibdocs = [] # Does not consider new formats/revisions
 
     performed_actions = read_actions_log(working_dir)
     for action, bibdoc_name, file_path, rename, description, \
             comment, doctype, keep_previous_versions, \
             file_restriction in performed_actions:
 
         # FIXME: get this out of the loop once changes to bibrecdocs
         # are immediately visible. For the moment, reload the
         # structure from scratch at each step
         bibrecdocs = BibRecDocs(recid)
 
         if action == 'add':
             new_bibdoc = \
                        add(file_path, bibdoc_name, rename, doctype, description,
                            comment, file_restriction, recid, working_dir, icon_sizes,
                            create_icon_doctypes, pending_bibdocs, bibrecdocs)
             if new_bibdoc:
                 newly_added_bibdocs.append(new_bibdoc)
 
         elif action == 'addFormat':
             add_format(file_path, bibdoc_name, recid, doctype, working_dir,
                        icon_sizes, create_icon_doctypes,
                        pending_bibdocs, bibrecdocs)
 
         elif action == 'revise':
             new_bibdoc = \
                        revise(file_path, bibdoc_name, rename, doctype,
                               description, comment, file_restriction, icon_sizes,
                               create_icon_doctypes, keep_previous_versions,
                               recid, working_dir, pending_bibdocs,
                               bibrecdocs, force_file_revision)
             if new_bibdoc:
                 newly_added_bibdocs.append(new_bibdoc)
 
         elif action == 'delete':
             delete(bibdoc_name, recid, working_dir, pending_bibdocs,
                    bibrecdocs)
 
     # Finally rename bibdocs that should be named according to a file in
     # curdir (eg. naming according to report number). Only consider
     # file that have just been added.
     parameters = _read_file_revision_interface_configuration_from_disk(working_dir)
     new_names = []
     doctypes_to_default_filename = parameters[22]
     for bibdoc_to_rename in newly_added_bibdocs:
         bibdoc_to_rename_doctype = bibdoc_to_rename.doctype
         rename_to = doctypes_to_default_filename.get(bibdoc_to_rename_doctype, '')
         if rename_to.startswith('file:'):
             # This BibDoc must be renamed. Look for name in working dir
             name_at_filepath = os.path.join(working_dir, rename_to[5:])
             if os.path.exists(name_at_filepath) and \
                    os.path.abspath(name_at_filepath).startswith(working_dir):
                 try:
                     rename = file(name_at_filepath).read()
                 except:
                     register_exception(prefix='Move_Uploaded_Files_to_Storage ' \
                                        'could not read file %s in curdir to rename bibdoc' % \
                                        (name_at_filepath,),
                                        alert_admin=True)
                 if rename:
                     file_counter = 2
                     new_filename = rename
                     while bibrecdocs.has_docname_p(new_filename) or (new_filename in new_names):
                         new_filename = rename + '_%i' % file_counter
                         file_counter += 1
                     bibdoc_to_rename.change_name(new_filename)
                     new_names.append(new_filename) # keep track of name, or we have to reload bibrecdoc...
                     _do_log(working_dir, 'Renamed ' + bibdoc_to_rename.get_docname())
 
     # Delete the HB BibFormat cache in the DB, so that the fulltext
     # links do not point to possible dead files
     run_sql("DELETE from bibfmt WHERE format='HB' AND id_bibrec=%s", (recid,))
 
     # Update the MARC
     cli_fix_marc(None, [recid], interactive=False)
 
 
 def add(file_path, bibdoc_name, rename, doctype, description, comment,
         file_restriction, recid, working_dir, icon_sizes, create_icon_doctypes,
         pending_bibdocs, bibrecdocs):
     """
     Adds the file using bibdocfile CLI
 
     Return the bibdoc that has been newly added.
     """
     try:
         if os.path.exists(file_path):
             # Add file
             bibdoc = bibrecdocs.add_new_file(file_path,
                                              doctype,
                                              rename or bibdoc_name,
                                              never_fail=True)
             _do_log(working_dir, 'Added ' + bibdoc.get_docname() + ': ' + \
                     file_path)
 
             # Add icon
             iconpath = ''
             has_added_default_icon_subformat_p = False
             for icon_size in icon_sizes:
                 if doctype in create_icon_doctypes or \
                        '*' in create_icon_doctypes:
                     iconpath = _create_icon(file_path, icon_size)
                     if iconpath is not None:
                         try:
                             if not has_added_default_icon_subformat_p:
                                 bibdoc.add_icon(iconpath)
                                 has_added_default_icon_subformat_p = True
                             else:
                                 icon_suffix = icon_size.replace('>', '').replace('<', '').replace('^', '').replace('!', '')
                                 bibdoc.add_icon(iconpath, subformat=CFG_WEBSUBMIT_DEFAULT_ICON_SUBFORMAT + "-" + icon_suffix)
                             _do_log(working_dir, 'Added icon to ' + \
                                     bibdoc.get_docname() + ': ' + iconpath)
                         except InvenioWebSubmitFileError, e:
                             # Most probably icon already existed.
                             pass
 
             # Add description
             if description:
                 bibdocfiles = bibdoc.list_latest_files()
                 for bibdocfile in bibdocfiles:
                     bibdoc.set_description(description,
                                            bibdocfile.get_format())
                     _do_log(working_dir, 'Described ' + \
                             bibdoc.get_docname() + ': ' + description)
 
             # Add comment
             if comment:
                 bibdocfiles = bibdoc.list_latest_files()
                 for bibdocfile in bibdocfiles:
                     bibdoc.set_comment(comment,
                                        bibdocfile.get_format())
                     _do_log(working_dir, 'Commented ' + \
                             bibdoc.get_docname() + ': ' + comment)
 
             # Set restriction
             bibdoc.set_status(file_restriction)
             _do_log(working_dir, 'Set restriction of ' + \
                     bibdoc.get_docname() + ': ' + \
                     file_restriction or '(no restriction)')
 
             return bibdoc
         else:
             # File has been later renamed or deleted.
             # Remember to add it later if file is found (ie
             # it was renamed)
             pending_bibdocs[bibdoc_name] = (doctype, comment, description, [])
 
     except InvenioWebSubmitFileError, e:
         # Format already existed.  How come? We should
         # have checked this in Create_Upload_Files_Interface.py
         register_exception(prefix='Move_Uploaded_Files_to_Storage ' \
                            'tried to add already existing file %s ' \
                            'with name %s to record %i.' % \
                            (file_path, bibdoc_name, recid),
                            alert_admin=True)
 
 def add_format(file_path, bibdoc_name, recid, doctype, working_dir,
                icon_sizes, create_icon_doctypes, pending_bibdocs,
                bibrecdocs):
     """
     Adds a new format to a bibdoc using bibdocfile CLI
     """
     try:
         if os.path.exists(file_path):
 
             # We must retrieve previous description and comment as
             # adding a file using the APIs reset these values
             prev_desc, prev_comment = None, None
             if bibrecdocs.has_docname_p(bibdoc_name):
                 (prev_desc, prev_comment) = \
                             get_description_and_comment(bibrecdocs.get_bibdoc(bibdoc_name).list_latest_files())
 
             # Add file
             bibdoc = bibrecdocs.add_new_format(file_path,
                                                bibdoc_name,
                                                prev_desc,
                                                prev_comment)
             _do_log(working_dir, 'Added new format to ' + \
                     bibdoc.get_docname() + ': ' + file_path)
 
             # Add icons
             has_added_default_icon_subformat_p = False
             for icon_size in icon_sizes:
                 iconpath = ''
                 if doctype in create_icon_doctypes or \
                        '*' in create_icon_doctypes:
                     iconpath = _create_icon(file_path, icon_size)
                     if iconpath is not None:
                         try:
                             if not has_added_default_icon_subformat_p:
                                 bibdoc.add_icon(iconpath)
                                 has_added_default_icon_subformat_p = True
                             else:
                                 # We have already added the "default" icon subformat
                                 icon_suffix = icon_size.replace('>', '').replace('<', '').replace('^', '').replace('!', '')
 
                                 bibdoc.add_icon(iconpath, subformat=CFG_WEBSUBMIT_DEFAULT_ICON_SUBFORMAT + "-" + icon_suffix)
                             _do_log(working_dir, 'Added icon to ' + \
                                     bibdoc.get_docname() + ': ' + iconpath)
                         except InvenioWebSubmitFileError, e:
                             # Most probably icon already existed.
                             pass
         else:
             # File has been later renamed or deleted.
             # Remember to add it later if file is found
             if pending_bibdocs.has_key(bibdoc_name):
                 pending_bibdocs[bibdoc_name][3].append(file_path)
             # else: we previously added a file by mistake. Do
             # not care, it will be deleted
     except InvenioWebSubmitFileError, e:
         # Format already existed.  How come? We should
         # have checked this in Create_Upload_Files_Interface.py
         register_exception(prefix='Move_Uploaded_Files_to_Storage ' \
                            'tried to add already existing format %s ' \
                            'named %s in record %i.' % \
                            (file_path, bibdoc_name, recid),
                                alert_admin=True)
 
 def revise(file_path, bibdoc_name, rename, doctype, description,
            comment, file_restriction, icon_sizes, create_icon_doctypes,
            keep_previous_versions, recid, working_dir, pending_bibdocs,
            bibrecdocs, force_file_revision):
     """
     Revises the given bibdoc with a new file.
 
     Return the bibdoc that has been newly added. (later: if needed,
     return as tuple the bibdoc that has been revised, or deleted,
     etc.)
     """
     added_bibdoc = None
     try:
         if os.path.exists(file_path) or not file_path:
 
             # Perform pending actions
             if pending_bibdocs.has_key(bibdoc_name):
                 # We have some pending actions to apply before
                 # going further.
                 if description == '':
                     # Last revision did not include a description.
                     # Use the one of the pending actions
                     description = pending_bibdocs[bibdoc_name][2]
                 if comment == '':
                     # Last revision did not include a comment.
                     # Use the one of the pending actions
                     comment = pending_bibdocs[bibdoc_name][1]
                 original_bibdoc_name = pending_bibdocs[bibdoc_name][0]
                 if not bibrecdocs.has_docname_p(original_bibdoc_name) and file_path:
                     # the bibdoc did not originaly exist, so it
                     # must be added first
                     bibdoc = bibrecdocs.add_new_file(file_path,
                                                      pending_bibdocs[bibdoc_name][0],
                                                      bibdoc_name,
                                                      never_fail=True)
                     _do_log(working_dir, 'Added ' + bibdoc.get_docname() + ': ' + \
                             file_path)
                     added_bibdoc = bibdoc
 
                     # Set restriction
                     bibdoc.set_status(file_restriction)
                     _do_log(working_dir, 'Set restriction of ' + \
                             bibdoc.get_docname() + ': ' + \
                             file_restriction or '(no restriction)')
 
                 # We must retrieve previous description and comment as
                 # revising a file using the APIs reset these values
                 prev_desc, prev_comment = None, None
                 if bibrecdocs.has_docname_p(bibdoc_name):
                     (prev_desc, prev_comment) = \
                                 get_description_and_comment(bibrecdocs.get_bibdoc(bibdoc_name).list_latest_files())
 
                 # Do we have additional formats?
                 for additional_format in pending_bibdocs[bibdoc_name][3]:
                     if os.path.exists(additional_format):
                         bibdoc.add_file_new_format(additional_format,
                                                    description=bibdoc.get_description(),
                                                    comment=bibdoc.get_comment())
                         _do_log(working_dir, 'Added new format to' + \
                                 bibdoc.get_docname() + ': ' + file_path)
 
                 # All pending modification have been applied,
                 # so delete
                 del pending_bibdocs[bibdoc_name]
 
             # We must retrieve previous description and comment as
             # revising a file using the APIs reset these values
             prev_desc, prev_comment = None, None
             if bibrecdocs.has_docname_p(bibdoc_name):
                 (prev_desc, prev_comment) = \
                             get_description_and_comment(bibrecdocs.get_bibdoc(bibdoc_name).list_latest_files())
 
             if keep_previous_versions and file_path:
                 # Standard procedure, keep previous version
                 bibdoc = bibrecdocs.add_new_version(file_path,
                                                     bibdoc_name,
                                                     prev_desc,
                                                     prev_comment)
                 _do_log(working_dir, 'Revised ' + bibdoc.get_docname() + \
                         ' with : ' + file_path)
 
             elif file_path:
                 # Soft-delete previous versions, and add new file
                 # (we need to get the doctype before deleting)
                 if bibrecdocs.has_docname_p(bibdoc_name):
                     # Delete only if bibdoc originally
                     # existed
                     bibrecdocs.delete_bibdoc(bibdoc_name)
                     _do_log(working_dir, 'Deleted ' + bibdoc_name)
                 try:
                     bibdoc = bibrecdocs.add_new_file(file_path,
                                                      doctype,
                                                      bibdoc_name,
                                                      never_fail=True,
                                                      description=prev_desc,
                                                      comment=prev_comment)
                     _do_log(working_dir, 'Added ' + bibdoc.get_docname() + ': ' + \
                             file_path)
 
                 except InvenioWebSubmitFileError, e:
                     _do_log(working_dir, str(e))
                     register_exception(prefix='Move_Uploaded_Files_to_Storage ' \
                                        'tried to revise a file %s ' \
                                        'named %s in record %i.' % \
                                        (file_path, bibdoc_name, recid),
                                        alert_admin=True)
             else:
                 # User just wanted to change attribute of the file,
                 # not the file itself
                 bibdoc = bibrecdocs.get_bibdoc(bibdoc_name)
                 (prev_desc, prev_comment) = \
                             get_description_and_comment(bibdoc.list_latest_files())
                 if prev_desc is None:
                     prev_desc = ""
                 if prev_comment is None:
                     prev_comment = ""
                 if force_file_revision and \
                        (description != prev_desc or comment != prev_comment):
                     # FIXME: If we are going to create a new version,
                     # then we should honour the keep_previous_versions
                     # parameter (soft-delete, then add bibdoc, etc)
                     # But it is a bit complex right now...
 
                     # Trick: we revert to current version, which
                     # creates a revision of the BibDoc
                     bibdoc.revert(bibdoc.get_latest_version())
                     bibdoc = bibrecdocs.get_bibdoc(bibdoc_name)
 
             # Rename
             if rename and rename != bibdoc_name:
                 bibdoc.change_name(rename)
                 _do_log(working_dir, 'renamed ' + bibdoc_name +' to '+ rename)
 
             # Add icons
             if file_path:
                 has_added_default_icon_subformat_p = False
                 for icon_size in icon_sizes:
                     iconpath = ''
                     if doctype in create_icon_doctypes or \
                            '*' in create_icon_doctypes:
                         iconpath = _create_icon(file_path, icon_size)
                         if iconpath is not None:
                             try:
                                 if not has_added_default_icon_subformat_p:
                                     bibdoc.add_icon(iconpath)
                                     has_added_default_icon_subformat_p = True
                                 else:
                                     # We have already added the "default" icon subformat
                                     icon_suffix = icon_size.replace('>', '').replace('<', '').replace('^', '').replace('!', '')
                                     bibdoc.add_icon(iconpath, subformat=CFG_WEBSUBMIT_DEFAULT_ICON_SUBFORMAT + "-" + icon_suffix)
                                 _do_log(working_dir, 'Added icon to ' + \
                                         bibdoc.get_docname() + ': ' + iconpath)
                             except InvenioWebSubmitFileError, e:
                                 # Most probably icon already existed.
                                 pass
 
             # Description
             if description:
                 bibdocfiles = bibdoc.list_latest_files()
                 for bibdocfile in bibdocfiles:
                     bibdoc.set_description(description,
                                            bibdocfile.get_format())
                     _do_log(working_dir, 'Described ' + \
                             bibdoc.get_docname() + ': ' + description)
             # Comment
             if comment:
                 bibdocfiles = bibdoc.list_latest_files()
                 for bibdocfile in bibdocfiles:
                     bibdoc.set_comment(comment,
                                        bibdocfile.get_format())
                     _do_log(working_dir, 'Commented ' + \
                             bibdoc.get_docname() + ': ' + comment)
 
             # Set restriction
             bibdoc.set_status(file_restriction)
             _do_log(working_dir, 'Set restriction of ' + \
                     bibdoc.get_docname() + ': ' + \
                     file_restriction or '(no restriction)')
         else:
             # File has been later renamed or deleted.
             # Remember it
             if rename and rename != bibdoc_name:
                 pending_bibdocs[rename] = pending_bibdocs[bibdoc_name]
 
     except InvenioWebSubmitFileError, e:
         # Format already existed.  How come? We should
         # have checked this in Create_Upload_Files_Interface.py
         register_exception(prefix='Move_Uploaded_Files_to_Storage ' \
                            'tried to revise a file %s ' \
                            'named %s in record %i.' % \
                            (file_path, bibdoc_name, recid),
                            alert_admin=True)
 
     return added_bibdoc
 
 def delete(bibdoc_name, recid, working_dir, pending_bibdocs,
            bibrecdocs):
     """
     Deletes the given bibdoc
     """
     try:
         if bibrecdocs.has_docname_p(bibdoc_name):
             bibrecdocs.delete_bibdoc(bibdoc_name)
             _do_log(working_dir, 'Deleted ' + bibdoc_name)
 
         if pending_bibdocs.has_key(bibdoc_name):
             del pending_bibdocs[bibdoc_name]
 
     except InvenioWebSubmitFileError, e:
         # Mmh most probably we deleted two files at the same
         # second. Sleep 1 second and retry...  This might go
         # away one bibdoc improves its way to delete files
         try:
             time.sleep(1)
             bibrecdocs.delete_bibdoc(bibdoc_name)
             _do_log(working_dir, 'Deleted ' + bibdoc_name)
             if pending_bibdocs.has_key(bibdoc_name):
                 del pending_bibdocs[bibdoc_name]
         except InvenioWebSubmitFileError, e:
             _do_log(working_dir, str(e))
             _do_log(working_dir, repr(bibrecdocs.list_bibdocs()))
             register_exception(prefix='Move_Uploaded_Files_to_Storage ' \
                                'tried to delete a file' \
                                'named %s in record %i.' % \
                                (bibdoc_name, recid),
                                alert_admin=True)
 
 def _do_log(log_dir, msg):
     """
     Log what we have done, in case something went wrong.
     Nice to compare with bibdocactions.log
 
     Should be removed when the development is over.
 
     @param log_dir: the path to the working directory
     @type log_dir: string
 
     @param msg: the message to log
     @type msg: string
     """
     log_file = os.path.join(log_dir, 'performed_actions.log')
     file_desc = open(log_file, "a+")
     file_desc.write("%s --> %s\n" %(time.strftime("%Y-%m-%d %H:%M:%S"), msg))
     file_desc.close()
 
 def _create_icon(file_path, icon_size, format='gif', verbosity=9):
     """
     Creates icon of given file.
 
     Returns path to the icon. If creation fails, return None, and
     register exception (send email to admin).
 
 
     @param file_path: full path to icon
     @type file_path: string
 
     @param icon_size: the scaling information to be used for the
                       creation of the new icon.
     @type icon_size: int
 
     @param verbosity: the verbosity level under which the program
                       is to run;
     @type verbosity: int
     """
     icon_path = None
     try:
         filename = os.path.splitext(os.path.basename(file_path))[0]
         (icon_dir, icon_name) = create_icon(
             {'input-file':file_path,
              'icon-name': "icon-%s" % filename,
              'multipage-icon': False,
              'multipage-icon-delay': 0,
              'icon-scale': icon_size,
              'icon-file-format': format,
              'verbosity': verbosity})
         icon_path = icon_dir + os.sep + icon_name
     except InvenioWebSubmitIconCreatorError, e:
         register_exception(prefix='Icon for file %s could not be created: %s' % \
                            (file_path, str(e)),
                            alert_admin=False)
     return icon_path
 
 def get_upload_file_interface_javascript(form_url_params):
     """
     Returns the Javascript code necessary to run the upload file
     interface.
     """
     javascript = '''
 <script type="text/javascript" src="/js/jquery.form.js"></script>
 <script type="text/javascript">
 <!--
 '''
     if form_url_params:
         javascript += '''
 // prepare the form when the DOM is ready
 $(document).ready(function() {
     var options = {
         target: '#uploadFileInterface', // target element(s) to be updated with server response
         success: showResponse, // post-submit callback
         url: '/submit/managedocfilesasync%(form_url_params)s' // override for form's 'action' attribute
     };
 
     // bind form using 'ajaxForm'
     $('form:has(#balloonReviseFileInput)').ajaxForm(options);
 
 });
 
 // post-submit callback
 function showResponse(responseText, statusText)  {
     hide_revise_panel();
 }
     '''  % {'form_url_params': form_url_params} #'
 
     javascript += '''
 /* Record position of the last clicked link that triggered the display
  * of the revise panel
  */
 var last_clicked_link = null;
 
 function display_revise_panel(link, action, target, showDoctypes, showKeepPreviousVersions, showRename, showDescription, showComment, bibdocname, description, comment, showRestrictions, restriction, doctypes){
         var balloon = document.getElementById("balloon");
         var file_input_block = document.getElementById("balloonReviseFileInputBlock");
         var doctype = document.getElementById("fileDoctypesRow");
         var warningFormats = document.getElementById("warningFormats");
         var keepPreviousVersions = document.getElementById("keepPreviousVersions");
         var renameBox = document.getElementById("renameBox");
         var descriptionBox = document.getElementById("descriptionBox");
         var commentBox = document.getElementById("commentBox");
         var restrictionBox = document.getElementById("restrictionBox");
         var apply_button = document.getElementById("applyChanges");
         var mainForm = getMainForm();
         last_clicked_link = link;
         var pos;
 
         /* Show/hide parts of the form */
         if (showDoctypes) {
             doctype.style.display = ''
         } else {
             doctype.style.display = 'none'
         }
         if (action == 'revise' && showKeepPreviousVersions == true){
             warningFormats.style.display = ''
         } else {
             warningFormats.style.display = 'none'
         }
         if ((action == 'revise' || action == 'add') && showRename == true){
             renameBox.style.display = ''
         } else {
             renameBox.style.display = 'none'
         }
         if ((action == 'revise' || action == 'add') && showDescription == true){
             descriptionBox.style.display = ''
         } else {
             descriptionBox.style.display = 'none'
         }
         if ((action == 'revise' || action == 'add') && showComment == true){
             commentBox.style.display = ''
         } else {
             commentBox.style.display = 'none'
         }
         if ((action == 'revise' || action == 'add') && showRestrictions == true){
             restrictionBox.style.display = ''
         } else {
             restrictionBox.style.display = 'none'
         }
         if (action == 'revise' && showKeepPreviousVersions == true) {
             keepPreviousVersions.style.display = ''
         } else {
             keepPreviousVersions.style.display = 'none'
         }
         if (action == 'add') {
             updateForm();
         }
         /* Reset values */
         file_input_block.innerHTML = file_input_block.innerHTML; // Trick to reset input field
         doctype.innerHTML = doctypes;
         mainForm.balloonReviseFileKeep.checked = true;
         mainForm.rename.value = bibdocname;
         mainForm.comment.value = comment;
         mainForm.description.value = description;
         var fileRestrictionFound = false;
         for (var i=0; i < mainForm.fileRestriction.length; i++) {
             if (mainForm.fileRestriction[i].value == restriction) {
                     mainForm.fileRestriction.selectedIndex = i;
                     fileRestrictionFound = true;
                 }
         }
         if (!fileRestrictionFound) {
             var restrictionItem = new Option(restriction, restriction);
             mainForm.fileRestriction.appendChild(restrictionItem);
             var lastIndex = mainForm.fileRestriction.length - 1;
             mainForm.fileRestriction.selectedIndex = lastIndex;
         }
 
         /* Display and move to correct position*/
         pos = findPosition(link)
         balloon.style.display = '';
         balloon.style.position="absolute";
         balloon.style.left = pos[0] + link.offsetWidth +"px";
         balloon.style.top = pos[1] - Math.round(balloon.offsetHeight/2) + 5 + "px";
         balloon.style.zIndex = 1001;
         balloon.style.display = '';
 
         /* Set the correct action and target file*/
         mainForm.fileAction.value = action;
         mainForm.fileTarget.value = target;
 
         /* Disable other controls */
         if (apply_button) {
             apply_button.disabled = true;
         }
         /*gray_out(true);*/
 }
 function hide_revise_panel(){
         var balloon = document.getElementById("balloon");
         var apply_button = document.getElementById("applyChanges");
         balloon.style.display = 'none';
         if (apply_button) {
             apply_button.disabled = false;
         }
         /*gray_out(false);*/
 }
 
 
 /* Intercept ESC key in order to close revise panel */
 document.onkeyup = keycheck;
 function keycheck(e){
         var KeyID = (window.event) ? event.keyCode : e.keyCode;
         if(KeyID==27){
             hide_revise_panel()
         }
 }
 
 function findPosition( oElement ) {
   /*Return the x,y position on page of the given object*/
   if( typeof( oElement.offsetParent ) != 'undefined' ) {
     for( var posX = 0, posY = 0; oElement; oElement = oElement.offsetParent ) {
       posX += oElement.offsetLeft;
       posY += oElement.offsetTop;
     }
     return [ posX, posY ];
   } else {
     return [ oElement.x, oElement.y ];
   }
 }
 
 function getMainForm()
 {
     return $('form:has(#balloonReviseFileInput)')[0];
 }
 
 function nextStep()
 {
       if(confirm("You are about to submit the files and end the upload process."))
       {
           var mainForm = getMainForm();
           mainForm.step.value = 2;
           user_must_confirm_before_leaving_page = false;
           mainForm.submit();
       }
       return true;
 }
 
 function updateForm(doctype, can_describe_doctypes, can_comment_doctypes, can_restrict_doctypes) {
     /* Update the revision panel to hide or not part of the interface
      * based on selected doctype
      *
      * Note: we use a small trick here to use the javascript 'in' operator, which
      * does not work for arrays, but for object => we transform our arrays into
      * objects literal
      */
 
     /* Get the elements we are going to affect */
     var renameBox = document.getElementById("renameBox");
     var descriptionBox = document.getElementById("descriptionBox");
     var commentBox = document.getElementById("commentBox");
     var restrictionBox = document.getElementById("restrictionBox");
 
     if (!can_describe_doctypes) {var can_describe_doctypes = [];}
     if (!can_comment_doctypes)  {var can_comment_doctypes = [];}
     if (!can_restrict_doctypes) {var can_restrict_doctypes = [];}
 
     if ((doctype in can_describe_doctypes) ||
         ('*' in can_describe_doctypes)){
         descriptionBox.style.display = ''
     } else {
         descriptionBox.style.display = 'none'
     }
 
     if ((doctype in can_comment_doctypes) ||
         ('*' in can_comment_doctypes)){
         commentBox.style.display = ''
     } else {
         commentBox.style.display = 'none'
     }
 
     if ((doctype in can_restrict_doctypes) ||
         ('*' in can_restrict_doctypes)){
         restrictionBox.style.display = ''
     } else {
         restrictionBox.style.display = 'none'
     }
 
     /* Move the revise panel accordingly */
     var balloon = document.getElementById("balloon");
     pos = findPosition(last_clicked_link)
     balloon.style.display = '';
     balloon.style.position="absolute";
     balloon.style.left = pos[0] + last_clicked_link.offsetWidth +"px";
     balloon.style.top = pos[1] - Math.round(balloon.offsetHeight/2) + 5 + "px";
     balloon.style.zIndex = 1001;
     balloon.style.display = '';
 }
 
 function askDelete(bibdocname, form_url_params){
     /*
     Ask user if she wants to delete file
     */
     if (confirm('Are you sure you want to delete '+bibdocname+'?'))
     {
         if (form_url_params) {
             var mainForm = getMainForm();
             mainForm.fileTarget.value = bibdocname;
             mainForm.fileAction.value='delete';
             user_must_confirm_before_leaving_page = false;
             var options = {
                 target: '#uploadFileInterface',
                 success: showResponse,
                 url: '/submit/managedocfilesasync' + form_url_params
             };
             $(mainForm).ajaxSubmit(options);
         } else {
             /*WebSubmit function*/
             document.forms[0].fileTarget.value = bibdocname;
             document.forms[0].fileAction.value='delete';
             user_must_confirm_before_leaving_page = false;
             document.forms[0].submit();
         }
     }
     return false;
 }
 
 function gray_out(visible) {
     /* Gray out the screen so that user cannot click anywhere else.
        Based on <http://www.hunlock.com/blogs/Snippets:_Howto_Grey-Out_The_Screen>
      */
     var modalShield = document.getElementById('modalShield');
     if (!modalShield) {
         var tbody = document.getElementsByTagName("body")[0];
         var tnode = document.createElement('div');
         tnode.style.position = 'absolute';
         tnode.style.top = '0px';
         tnode.style.left = '0px';
         tnode.style.overflow = 'hidden';
         tnode.style.display = 'none';
         tnode.id = 'modalShield';
         tbody.appendChild(tnode);
         modalShield = document.getElementById('modalShield');
     }
 
     if (visible){
         // Calculate the page width and height
         var pageWidth = '100%%';
         var pageHeight = '100%%';
         //set the shader to cover the entire page and make it visible.
         modalShield.style.opacity = 0.7;
         modalShield.style.MozOpacity = 0.7;
         modalShield.style.filter = 'alpha(opacity=70)';
         modalShield.style.zIndex = 1000;
         modalShield.style.backgroundColor = '#000000';
         modalShield.style.width = pageWidth;
         modalShield.style.height = pageHeight;
         modalShield.style.display = 'block';
     } else {
         modalShield.style.display = 'none';
     }
 
 }
 -->
 </script>
 '''
     return javascript
 
 def get_upload_file_interface_css():
     """
     Returns the CSS to embed in the page for the upload file interface.
     """
     # The CSS embedded in the page for the revise panel
     css = '''
 <style type="text/css">
 <!--
 #reviseControl{
 overflow:auto;
 width: 600px;
 padding:1px;
 }
 .reviseControlBrowser{
 padding:5px;
 background-color:#fff;
 border-collapse:collapse;
 border-spacing: 0px;
 border: 1px solid #999;
 }
 .reviseControlFileColumn {
 padding-right:60px;
 padding-left:5px;
 text-align: left;
 color:#00f;
 }
 .reviseControlActionColumn,
 .reviseControlFormatColumn{
 font-size:small;
 }
 .reviseControlActionColumn,
 .reviseControlActionColumn a,
 .reviseControlActionColumn a:link,
 .reviseControlActionColumn a:hover
 .reviseControlActionColumn a:visited{
 font-size:small;
 color: #060;
 text-align:right;
 }
 .reviseControlFormatColumn,
 .reviseControlFormatColumn a,
 .reviseControlFormatColumn a:link,
 .reviseControlFormatColumn a:hover
 .reviseControlFormatColumn a:visited{
 font-size:small;
 color: #555;
 text-align:left;
 }
 .optional{
 color: #555;
 font-size:0.9em;
 font-weight:normal
 }
 .even{
 background-color:#ecf3fe;
 }
 /*
 .buttonLikeLink, .buttonLikeLink:visited, .buttonLikeLink:hover{
 background-color:#fff;
 border:2px outset #555;
 color:#000;
 padding: 2px 5px;
 display:inline-block;
 margin:2px;
 text-decoration:none;
 font-size:small;
 cursor: default
 }
 */
 
 #balloon table{
 border-collapse:collapse;
 border-spacing: 0px;
 }
 #balloon table td.topleft{
 background: transparent url(%(CFG_SITE_URL)s/img/balloon_top_left_shadow.png) no-repeat bottom right;
 }
 #balloon table td.bottomleft{
 background: transparent url(%(CFG_SITE_URL)s/img/balloon_bottom_left_shadow.png) no-repeat top right;
 }
 #balloon table td.topright{
 background: transparent url(%(CFG_SITE_URL)s/img/balloon_top_right_shadow.png) no-repeat bottom left;
 }
 #balloon table td.bottomright{
 background: transparent url(%(CFG_SITE_URL)s/img/balloon_bottom_right_shadow.png) no-repeat top left;
 }
 #balloon table td.top{
 background: transparent url(%(CFG_SITE_URL)s/img/balloon_top_shadow.png) repeat-x bottom left;
 }
 #balloon table td.bottom{
 background: transparent url(%(CFG_SITE_URL)s/img/balloon_bottom_shadow.png) repeat-x top left;
 }
 #balloon table td.left{
 background: transparent url(%(CFG_SITE_URL)s/img/balloon_left_shadow.png) repeat-y top right;
 text-align:right;
 padding:0;
 }
 #balloon table td.right{
 background: transparent url(%(CFG_SITE_URL)s/img/balloon_right_shadow.png) repeat-y top left;
 }
 #balloon table td.arrowleft{
 background: transparent url(%(CFG_SITE_URL)s/img/balloon_arrow_left_shadow.png) no-repeat bottom right;
 width:24px;
 height:27px;
 }
 #balloon table td.center{
 background-color:#ffffea;
 }
 #balloon label{
 font-size:small;
 }
 #balloonReviseFile{
 width:220px;
 text-align:left;
 }
 #warningFormats{
 color:#432e11;
 font-size:x-small;
 text-align:center;
 margin: 4px auto 4px auto;
 }
 #fileDoctype {
 margin-bottom:3px;
 }
 #renameBox, #descriptionBox, #commentBox, #keepPreviousVersions{
 margin-top:6px;
 }
 #description, #comment, #rename {
 width:90%%;
 }
 -->
 </style>
 ''' % {'CFG_SITE_URL': CFG_SITE_URL}
     return css
 
 # The HTML markup of the revise panel
 revise_balloon = '''
 <div id="balloon" style="display:none;">
 <input type="hidden" name="fileAction" value="" />
 <input type="hidden" name="fileTarget" value="" />
   <table>
     <tr>
       <td class="topleft">&nbsp;</td>
       <td class="top">&nbsp;</td>
       <td class="topright">&nbsp;</td>
     </tr>
     <tr>
       <td class="left" vertical-align="center" width="24"><img alt=" " src="../img/balloon_arrow_left_shadow.png" /></td>
       <td class="center">
         <table id="balloonReviseFile">
           <tr>
             <td><label for="balloonReviseFileInput">%(file_label)s:</label><br/>
               <div style="display:none" id="fileDoctypesRow"></div>
               <div id="balloonReviseFileInputBlock"><input type="file" name="myfile" id="balloonReviseFileInput" size="20" /></div>
                           <!--  <input type="file" name="myfile" id="balloonReviseFileInput" size="20" onchange="var name=getElementById('rename');var filename=this.value.split('/').pop().split('.')[0];name.value=filename;"/> -->
               <div id="renameBox" style=""><label for="rename">%(filename_label)s:</label><br/><input type="text" name="rename" id="rename" size="20" autocomplete="off"/></div>
               <div id="descriptionBox" style=""><label for="description">%(description_label)s:</label><br/><input type="text" name="description" id="description" size="20" autocomplete="off"/></div>
               <div id="commentBox" style=""><label for="comment">%(comment_label)s:</label><br/><textarea name="comment" id="comment" rows="3"/></textarea></div>
               <div id="restrictionBox" style="display:none">%(restrictions)s</div>
               <div id="keepPreviousVersions" style="display:none"><input type="checkbox" id="balloonReviseFileKeep" name="keepPreviousFiles" checked="checked" /><label for="balloonReviseFileKeep">%(previous_versions_label)s</label>&nbsp;<small>[<a href="" onclick="alert('%(previous_versions_help)s');return false;">?</a>]</small></div>
               <p id="warningFormats" style="display:none"><img src="%(CFG_SITE_URL)s/img/warning.png" alt="Warning"/> %(revise_format_warning)s&nbsp;[<a href="" onclick="alert('%(revise_format_help)s');return false;">?</a>]</p>
               <div style="text-align:right;margin-top:5px"><input type="button" value="%(cancel)s" onclick="javascript:hide_revise_panel();"/> <input type="submit" value="%(upload)s"/></div>
             </td>
           </tr>
         </table>
       </td>
       <td class="right">&nbsp;</td>
     </tr>
     <tr>
       <td class="bottomleft">&nbsp;</td>
       <td class="bottom">&nbsp;</td>
       <td class="bottomright">&nbsp;</td>
     </tr>
   </table>
 </div>
 '''
diff --git a/modules/websubmit/lib/websubmit_webinterface.py b/modules/websubmit/lib/websubmit_webinterface.py
index 76ea64704..c88aca902 100644
--- a/modules/websubmit/lib/websubmit_webinterface.py
+++ b/modules/websubmit/lib/websubmit_webinterface.py
@@ -1,1423 +1,1423 @@
 ## This file is part of Invenio.
 ## Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 CERN.
 ##
 ## Invenio 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; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## Invenio 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 Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 __lastupdated__ = """$Date$"""
 
 __revision__ = "$Id$"
 
 import os
 import time
 import cgi
 import sys
 import shutil
 
 from urllib import urlencode
 
 from invenio.config import \
      CFG_ACCESS_CONTROL_LEVEL_SITE, \
      CFG_SITE_LANG, \
      CFG_SITE_NAME, \
-     CFG_TMPDIR, \
+     CFG_TMPSHAREDDIR, \
      CFG_SITE_NAME_INTL, \
      CFG_SITE_URL, \
      CFG_SITE_SECURE_URL, \
      CFG_WEBSUBMIT_STORAGEDIR, \
      CFG_PREFIX, \
      CFG_CERN_SITE, \
      CFG_SITE_RECORD
 from invenio import webinterface_handler_config as apache
 from invenio.dbquery import run_sql
 from invenio.access_control_config import VIEWRESTRCOLL
 from invenio.access_control_mailcookie import mail_cookie_create_authorize_action
 from invenio.access_control_engine import acc_authorize_action
 from invenio.access_control_admin import acc_is_role
 from invenio.webpage import page, create_error_box, pageheaderonly, \
     pagefooteronly
 from invenio.webuser import getUid, page_not_authorized, collect_user_info, isGuestUser, isUserSuperAdmin
 from invenio.websubmit_config import *
 from invenio import webjournal_utils
 from invenio.webinterface_handler import wash_urlargd, WebInterfaceDirectory
 from invenio.urlutils import make_canonical_urlargd, redirect_to_url
 from invenio.messages import gettext_set_language
 from invenio.search_engine import \
      guess_primary_collection_of_a_record, get_colID, record_exists, \
      create_navtrail_links, check_user_can_view_record, record_empty, \
      is_user_owner_of_record
 from invenio.bibdocfile import BibRecDocs, normalize_format, file_strip_ext, \
     stream_restricted_icon, BibDoc, InvenioWebSubmitFileError, stream_file, \
     decompose_file, propose_next_docname, get_subformat_from_format
 from invenio.errorlib import register_exception
 from invenio.htmlutils import is_html_text_editor_installed
 from invenio.websubmit_icon_creator import create_icon, InvenioWebSubmitIconCreatorError
 from ckeditor_invenio_connector import process_CKEditor_upload, send_response
 import invenio.template
 websubmit_templates = invenio.template.load('websubmit')
 from invenio.websearchadminlib import get_detailed_page_tabs
 from invenio.session import get_session
 from invenio.jsonutils import json, CFG_JSON_AVAILABLE
 import invenio.template
 webstyle_templates = invenio.template.load('webstyle')
 websearch_templates = invenio.template.load('websearch')
 
 from invenio.websubmit_managedocfiles import \
      create_file_upload_interface, \
      get_upload_file_interface_javascript, \
      get_upload_file_interface_css, \
      move_uploaded_files_to_storage
 
 
 class WebInterfaceFilesPages(WebInterfaceDirectory):
 
     def __init__(self,recid):
         self.recid = recid
 
     def _lookup(self, component, path):
         # after /<CFG_SITE_RECORD>/<recid>/files/ every part is used as the file
         # name
         filename = component
 
         def getfile(req, form):
             args = wash_urlargd(form, websubmit_templates.files_default_urlargd)
             ln = args['ln']
 
             _ = gettext_set_language(ln)
 
             uid = getUid(req)
             user_info = collect_user_info(req)
 
             verbose = args['verbose']
             if verbose >= 1 and not isUserSuperAdmin(user_info):
                 # Only SuperUser can see all the details!
                 verbose = 0
 
             if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE > 1:
                 return page_not_authorized(req, "/%s/%s" % (CFG_SITE_RECORD, self.recid),
                                            navmenuid='submit')
 
             if record_exists(self.recid) < 1:
                 msg = "<p>%s</p>" % _("Requested record does not seem to exist.")
                 return warningMsg(msg, req, CFG_SITE_NAME, ln)
 
             if record_empty(self.recid):
                 msg = "<p>%s</p>" % _("Requested record does not seem to have been integrated.")
                 return warningMsg(msg, req, CFG_SITE_NAME, ln)
 
             (auth_code, auth_message) = check_user_can_view_record(user_info, self.recid)
             if auth_code and user_info['email'] == 'guest':
                 if webjournal_utils.is_recid_in_released_issue(self.recid):
                     # We can serve the file
                     pass
                 else:
                     cookie = mail_cookie_create_authorize_action(VIEWRESTRCOLL, {'collection' : guess_primary_collection_of_a_record(self.recid)})
                     target = '/youraccount/login' + \
                              make_canonical_urlargd({'action': cookie, 'ln' : ln, 'referer' : \
                                                      CFG_SITE_SECURE_URL + user_info['uri']}, {})
                     return redirect_to_url(req, target, norobot=True)
             elif auth_code:
                 if webjournal_utils.is_recid_in_released_issue(self.recid):
                     # We can serve the file
                     pass
                 else:
                     return page_not_authorized(req, "../", \
                                                text = auth_message)
 
 
             readonly = CFG_ACCESS_CONTROL_LEVEL_SITE == 1
 
             # From now on: either the user provided a specific file
             # name (and a possible version), or we return a list of
             # all the available files. In no case are the docids
             # visible.
             try:
                 bibarchive = BibRecDocs(self.recid)
             except InvenioWebSubmitFileError, e:
                 register_exception(req=req, alert_admin=True)
                 msg = "<p>%s</p><p>%s</p>" % (
                     _("The system has encountered an error in retrieving the list of files for this document."),
                     _("The error has been logged and will be taken in consideration as soon as possible."))
                 return warningMsg(msg, req, CFG_SITE_NAME, ln)
 
             if bibarchive.deleted_p():
                 return print_warning(req, _("Requested record does not seem to exist."))
 
             docname = ''
             format = ''
             version = ''
             warn = ''
 
             if filename:
                 # We know the complete file name, guess which docid it
                 # refers to
                 ## TODO: Change the extension system according to ext.py from setlink
                 ##       and have a uniform extension mechanism...
                 docname = file_strip_ext(filename)
                 format = filename[len(docname):]
                 if format and format[0] != '.':
                     format = '.' + format
                 if args['subformat']:
                     format += ';%s' % args['subformat']
             else:
                 docname = args['docname']
 
             if not format:
                 format = args['format']
                 if args['subformat']:
                     format += ';%s' % args['subformat']
 
             if not version:
                 version = args['version']
 
             ## Download as attachment
             is_download = False
             if args['download']:
                 is_download = True
 
             # version could be either empty, or all or an integer
             try:
                 int(version)
             except ValueError:
                 if version != 'all':
                     version = ''
 
             display_hidden = isUserSuperAdmin(user_info)
 
             if version != 'all':
                 # search this filename in the complete list of files
                 for doc in bibarchive.list_bibdocs():
                     if docname == doc.get_docname():
                         try:
                             docfile = doc.get_file(format, version)
                             (auth_code, auth_message) = docfile.is_restricted(user_info)
                             if auth_code != 0 and not is_user_owner_of_record(user_info, self.recid):
                                 if CFG_WEBSUBMIT_ICON_SUBFORMAT_RE.match(get_subformat_from_format(format)):
                                     return stream_restricted_icon(req)
                                 if user_info['email'] == 'guest':
                                     cookie = mail_cookie_create_authorize_action('viewrestrdoc', {'status' : docfile.get_status()})
                                     target = '/youraccount/login' + \
                                     make_canonical_urlargd({'action': cookie, 'ln' : ln, 'referer' : \
                                         CFG_SITE_SECURE_URL + user_info['uri']}, {})
                                     redirect_to_url(req, target)
                                 else:
                                     req.status = apache.HTTP_UNAUTHORIZED
                                     warn += print_warning(_("This file is restricted: ") + auth_message)
                                     break
 
                             if not docfile.hidden_p():
                                 if not readonly:
                                     ip = str(req.remote_ip)
                                     res = doc.register_download(ip, version, format, uid)
                                 try:
                                     return docfile.stream(req, download=is_download)
                                 except InvenioWebSubmitFileError, msg:
                                     register_exception(req=req, alert_admin=True)
                                     req.status = apache.HTTP_INTERNAL_SERVER_ERROR
                                     return warningMsg(_("An error has happened in trying to stream the request file."), req, CFG_SITE_NAME, ln)
                             else:
                                 req.status = apache.HTTP_UNAUTHORIZED
                                 warn = print_warning(_("The requested file is hidden and can not be accessed."))
 
                         except InvenioWebSubmitFileError, msg:
                             register_exception(req=req, alert_admin=True)
 
             if docname and format and not warn:
                 req.status = apache.HTTP_NOT_FOUND
                 warn += print_warning(_("Requested file does not seem to exist."))
             filelist = bibarchive.display("", version, ln=ln, verbose=verbose, display_hidden=display_hidden)
 
             t = warn + websubmit_templates.tmpl_filelist(
                 ln=ln,
                 recid=self.recid,
                 docname=args['docname'],
                 version=version,
                 filelist=filelist)
 
             cc = guess_primary_collection_of_a_record(self.recid)
             unordered_tabs = get_detailed_page_tabs(get_colID(cc), self.recid, ln)
             ordered_tabs_id = [(tab_id, values['order']) for (tab_id, values) in unordered_tabs.iteritems()]
             ordered_tabs_id.sort(lambda x,y: cmp(x[1],y[1]))
             link_ln = ''
             if ln != CFG_SITE_LANG:
                 link_ln = '?ln=%s' % ln
             tabs = [(unordered_tabs[tab_id]['label'], \
                      '%s/%s/%s/%s%s' % (CFG_SITE_URL, CFG_SITE_RECORD, self.recid, tab_id, link_ln), \
                      tab_id == 'files',
                      unordered_tabs[tab_id]['enabled']) \
                     for (tab_id, order) in ordered_tabs_id
                     if unordered_tabs[tab_id]['visible'] == True]
             top = webstyle_templates.detailed_record_container_top(self.recid,
                                                                    tabs,
                                                                    args['ln'])
             bottom = webstyle_templates.detailed_record_container_bottom(self.recid,
                                                                          tabs,
                                                                          args['ln'])
             title, description, keywords = websearch_templates.tmpl_record_page_header_content(req, self.recid, args['ln'])
             return pageheaderonly(title=title,
                         navtrail=create_navtrail_links(cc=cc, aas=0, ln=ln) + \
                                         ''' &gt; <a class="navtrail" href="%s/%s/%s">%s</a>
                                         &gt; %s''' % \
                         (CFG_SITE_URL, CFG_SITE_RECORD, self.recid, title, _("Access to Fulltext")),
 
                         description="",
                         keywords="keywords",
                         uid=uid,
                         language=ln,
                         req=req,
                         navmenuid='search',
                         navtrail_append_title_p=0) + \
                         websearch_templates.tmpl_search_pagestart(ln) + \
                         top + t + bottom + \
                         websearch_templates.tmpl_search_pageend(ln) + \
                         pagefooteronly(lastupdated=__lastupdated__, language=ln, req=req)
         return getfile, []
 
     def __call__(self, req, form):
         """Called in case of URLs like /CFG_SITE_RECORD/123/files without
            trailing slash.
         """
         args = wash_urlargd(form, websubmit_templates.files_default_urlargd)
         ln = args['ln']
         link_ln = ''
         if ln != CFG_SITE_LANG:
             link_ln = '?ln=%s' % ln
 
         return redirect_to_url(req, '%s/%s/%s/files/%s' % (CFG_SITE_URL, CFG_SITE_RECORD, self.recid, link_ln))
 
 def websubmit_legacy_getfile(req, form):
     """ Handle legacy /getfile.py URLs """
 
     args = wash_urlargd(form, {
         'recid': (int, 0),
         'docid': (int, 0),
         'version': (str, ''),
         'name': (str, ''),
         'format': (str, ''),
         'ln' : (str, CFG_SITE_LANG)
         })
 
     _ = gettext_set_language(args['ln'])
 
     def _getfile_py(req, recid=0, docid=0, version="", name="", format="", ln=CFG_SITE_LANG):
         if not recid:
             ## Let's obtain the recid from the docid
             if docid:
                 try:
                     bibdoc = BibDoc(docid=docid)
                     recid = bibdoc.get_recid()
                 except InvenioWebSubmitFileError, e:
                     return warningMsg(_("An error has happened in trying to retrieve the requested file."), req, CFG_SITE_NAME, ln)
             else:
                 return warningMsg(_('Not enough information to retrieve the document'), req, CFG_SITE_NAME, ln)
         else:
             if not name and docid:
                 ## Let's obtain the name from the docid
                 try:
                     bibdoc = BibDoc(docid)
                     name = bibdoc.get_docname()
                 except InvenioWebSubmitFileError, e:
                     return warningMsg(_("An error has happened in trying to retrieving the requested file."), req, CFG_SITE_NAME, ln)
 
         format = normalize_format(format)
 
         redirect_to_url(req, '%s/%s/%s/files/%s%s?ln=%s%s' % (CFG_SITE_URL, CFG_SITE_RECORD, recid, name, format, ln, version and 'version=%s' % version or ''), apache.HTTP_MOVED_PERMANENTLY)
 
     return _getfile_py(req, **args)
 
 
 # --------------------------------------------------
 
 from invenio.websubmit_engine import home, action, interface, endaction
 
 class WebInterfaceSubmitPages(WebInterfaceDirectory):
 
     _exports = ['summary', 'sub', 'direct', '', 'attachfile', 'uploadfile', \
                 'getuploadedfile', 'managedocfiles', 'managedocfilesasync', \
                 'upload_video']
 
     def managedocfiles(self, req, form):
         """
         Display admin interface to manage files of a record
         """
         argd = wash_urlargd(form, {
             'ln': (str, ''),
             'access': (str, ''),
             'recid': (int, None),
             'do': (int, 0),
             'cancel': (str, None),
             })
 
         _ = gettext_set_language(argd['ln'])
         uid = getUid(req)
         user_info = collect_user_info(req)
         # Check authorization
         (auth_code, auth_msg) = acc_authorize_action(req,
                                                      'runbibdocfile')
         if auth_code and user_info['email'] == 'guest':
             # Ask to login
             target = '/youraccount/login' + \
                      make_canonical_urlargd({'ln' : argd['ln'],
                                              'referer' : CFG_SITE_SECURE_URL + user_info['uri']}, {})
             return redirect_to_url(req, target)
         elif auth_code:
             return page_not_authorized(req, referer="/submit/managedocfiles",
                                        uid=uid, text=auth_msg,
                                        ln=argd['ln'],
                                        navmenuid="admin")
 
         # Prepare navtrail
         navtrail = '''<a class="navtrail" href="%(CFG_SITE_URL)s/help/admin">Admin Area</a> &gt; %(manage_files)s''' \
         % {'CFG_SITE_URL': CFG_SITE_URL,
            'manage_files': _("Manage Document Files")}
 
         body = ''
         if argd['do'] != 0 and not argd['cancel']:
             # Apply modifications
-            working_dir = os.path.join(CFG_TMPDIR,
+            working_dir = os.path.join(CFG_TMPSHAREDDIR,
                                        'websubmit_upload_interface_config_' + str(uid),
                                        argd['access'])
             move_uploaded_files_to_storage(working_dir=working_dir,
                                            recid=argd['recid'],
                                            icon_sizes=['180>','700>'],
                                            create_icon_doctypes=['*'],
                                            force_file_revision=False)
             # Clean temporary directory
             shutil.rmtree(working_dir)
 
             # Confirm modifications
             body += '<p style="color:#0f0">%s</p>' % \
                     (_('Your modifications to record #%i have been submitted') % argd['recid'])
         elif argd['cancel']:
             # Clean temporary directory
-            working_dir = os.path.join(CFG_TMPDIR,
+            working_dir = os.path.join(CFG_TMPSHAREDDIR,
                                        'websubmit_upload_interface_config_' + str(uid),
                                        argd['access'])
             shutil.rmtree(working_dir)
             body += '<p style="color:#c00">%s</p>' % \
                     (_('Your modifications to record #%i have been cancelled') % argd['recid'])
 
         if not argd['recid'] or argd['do'] != 0:
             body += '''
         <form method="post" action="%(CFG_SITE_URL)s/submit/managedocfiles">
         <label for="recid">%(edit_record)s:</label>
         <input type="text" name="recid" id="recid" />
         <input type="submit" value="%(edit)s" class="adminbutton" />
         </form>
         ''' % {'edit': _('Edit'),
                'edit_record': _('Edit record'),
                'CFG_SITE_URL': CFG_SITE_URL}
 
         access = time.strftime('%Y%m%d_%H%M%S')
         if argd['recid'] and argd['do'] == 0:
             # Displaying interface to manage files
             # Prepare navtrail
             title, description, keywords = websearch_templates.tmpl_record_page_header_content(req, argd['recid'],
                                                                                                argd['ln'])
             navtrail = '''<a class="navtrail" href="%(CFG_SITE_URL)s/help/admin">Admin Area</a> &gt;
         <a class="navtrail" href="%(CFG_SITE_URL)s/submit/managedocfiles">%(manage_files)s</a> &gt;
         %(record)s: %(title)s
         ''' \
             % {'CFG_SITE_URL': CFG_SITE_URL,
                'title': title,
                'manage_files': _("Document File Manager"),
                'record': _("Record #%i") % argd['recid']}
 
             # FIXME: add parameters to `runbibdocfile' in order to
             # configure the file editor based on role, or at least
             # move configuration below to some config file.
             body += create_file_upload_interface(\
                 recid=argd['recid'],
                 ln=argd['ln'],
                 doctypes_and_desc=[('main', 'Main document'),
                                    ('latex', 'LaTeX'),
                                    ('source', 'Source'),
                                    ('additional', 'Additional File'),
                                    ('audio', 'Audio file'),
                                    ('video', 'Video file'),
                                    ('script', 'Script'),
                                    ('data', 'Data'),
                                    ('figure', 'Figure'),
                                    ('schema', 'Schema'),
                                    ('graph', 'Graph'),
                                    ('image', 'Image'),
                                    ('drawing', 'Drawing'),
                                    ('slides', 'Slides')],
                 can_revise_doctypes=['*'],
                 can_comment_doctypes=['*'],
                 can_describe_doctypes=['*'],
                 can_delete_doctypes=['*'],
                 can_keep_doctypes=['*'],
                 can_rename_doctypes=['*'],
                 can_add_format_to_doctypes=['*'],
                 can_restrict_doctypes=['*'],
                 restrictions_and_desc=[('', 'Public'),
                                        ('restricted', 'Restricted')],
                 uid=uid,
                 sbm_access=access,
                 display_hidden_files=True)[1]
 
             body += '''<br />
             <form method="post" action="%(CFG_SITE_URL)s/submit/managedocfiles">
             <input type="hidden" name="recid" value="%(recid)s" />
             <input type="hidden" name="do" value="1" />
             <input type="hidden" name="access" value="%(access)s" />
             <input type="hidden" name="ln" value="%(ln)s" />
             <div style="font-size:small">
     <input type="submit" name="cancel" value="%(cancel_changes)s" />
     <input type="submit" onclick="user_must_confirm_before_leaving_page=false;return true;" class="adminbutton" name="submit" id="applyChanges" value="%(apply_changes)s" />
     </div></form>''' % \
     {'apply_changes': _("Apply changes"),
      'cancel_changes': _("Cancel all changes"),
      'recid': argd['recid'],
      'access': access,
      'ln': argd['ln'],
      'CFG_SITE_URL': CFG_SITE_URL}
 
             body += websubmit_templates.tmpl_page_do_not_leave_submission_js(argd['ln'], enabled=True)
 
         return page(title = _("Document File Manager") + (argd['recid'] and (': ' + _("Record #%i") % argd['recid']) or ''),
                     navtrail=navtrail,
                     navtrail_append_title_p=0,
                     metaheaderadd = get_upload_file_interface_javascript(form_url_params='?access='+access) + \
                                     get_upload_file_interface_css(),
                     body = body,
                     uid = uid,
                     language=argd['ln'],
                     req=req,
                     navmenuid='admin')
 
     def managedocfilesasync(self, req, form):
         "Upload file and returns upload interface"
 
         argd = wash_urlargd(form, {
             'ln': (str, ''),
             'recid': (int, 1),
             'doctype': (str, ''),
             'access': (str, ''),
             'indir': (str, ''),
             })
 
         user_info = collect_user_info(req)
         include_headers = False
         # User submitted either through WebSubmit, or admin interface.
         if form.has_key('doctype') and form.has_key('indir') \
                and form.has_key('access'):
             # Submitted through WebSubmit. Check rights
             include_headers = True
             working_dir = os.path.join(CFG_WEBSUBMIT_STORAGEDIR,
                                   argd['indir'], argd['doctype'],
                                   argd['access'])
             try:
                 assert(working_dir == os.path.abspath(working_dir))
             except AssertionError:
                 raise apache.SERVER_RETURN(apache.HTTP_UNAUTHORIZED)
             try:
                 # Retrieve recid from working_dir, safer.
                 recid_fd = file(os.path.join(working_dir, 'SN'))
                 recid = int(recid_fd.read())
                 recid_fd.close()
             except:
                 recid = ""
             try:
                 act_fd = file(os.path.join(working_dir, 'act'))
                 action = act_fd.read()
                 act_fd.close()
             except:
                 action = ""
 
             # Is user authorized to perform this action?
             (auth_code, auth_msg) = acc_authorize_action(user_info,
                                                          "submit",
                                                          doctype=argd['doctype'],
                                                          act=action)
             if not acc_is_role("submit", doctype=argd['doctype'], act=action):
                 # There is NO authorization plugged. User should have access
                 auth_code = 0
         else:
             # User must be allowed to attach files
             (auth_code, auth_msg) = acc_authorize_action(user_info,
                                                          'runbibdocfile')
             recid = argd['recid']
 
         if auth_code:
             raise apache.SERVER_RETURN(apache.HTTP_UNAUTHORIZED)
 
         return create_file_upload_interface(recid=recid,
                                             ln=argd['ln'],
                                             print_outside_form_tag=False,
                                             print_envelope=False,
                                             form=form,
                                             include_headers=include_headers,
                                             sbm_indir=argd['indir'],
                                             sbm_access=argd['access'],
                                             sbm_doctype=argd['doctype'],
                                             uid=user_info['uid'])[1]
 
     def uploadfile(self, req, form):
         """
         Similar to /submit, but only consider files. Nice for
         asynchronous Javascript uploads. Should be used to upload a
         single file.
 
         Also try to create an icon, and return URL to file(s) + icon(s)
 
         Authentication is performed based on session ID passed as
         parameter instead of cookie-based authentication, due to the
         use of this URL by the Flash plugin (to upload multiple files
         at once), which does not route cookies.
 
         FIXME: consider adding /deletefile and /modifyfile functions +
         parsing of additional parameters to rename files, add
         comments, restrictions, etc.
         """
         argd = wash_urlargd(form, {
             'doctype': (str, ''),
             'access': (str, ''),
             'indir': (str, ''),
             'session_id': (str, ''),
             'rename': (str, ''),
             })
 
         curdir = None
         if not form.has_key("indir") or \
                not form.has_key("doctype") or \
                not form.has_key("access"):
             raise apache.SERVER_RETURN(apache.HTTP_BAD_REQUEST)
         else:
             curdir = os.path.join(CFG_WEBSUBMIT_STORAGEDIR,
                                   argd['indir'],
                                   argd['doctype'],
                                   argd['access'])
 
         user_info = collect_user_info(req)
         if form.has_key("session_id"):
             # Are we uploading using Flash, which does not transmit
             # cookie? The expect to receive session_id as a form
             # parameter.  First check that IP addresses do not
             # mismatch. A ValueError will be raises if there is
             # something wrong
             session = get_session(req=req, sid=argd['session_id'])
             try:
                 session = get_session(req=req, sid=argd['session_id'])
             except ValueError, e:
                 raise apache.SERVER_RETURN(apache.HTTP_BAD_REQUEST)
 
             # Retrieve user information. We cannot rely on the session here.
             res = run_sql("SELECT uid FROM session WHERE session_key=%s", (argd['session_id'],))
             if len(res):
                 uid = res[0][0]
                 user_info = collect_user_info(uid)
                 try:
                     act_fd = file(os.path.join(curdir, 'act'))
                     action = act_fd.read()
                     act_fd.close()
                 except:
                     act = ""
 
         # Is user authorized to perform this action?
         (auth_code, auth_message) = acc_authorize_action(uid, "submit",
                                                      verbose=0,
                                                      doctype=argd['doctype'],
                                                      act=action)
         if acc_is_role("submit", doctype=argd['doctype'], act=action) and auth_code != 0:
             # User cannot submit
             raise apache.SERVER_RETURN(apache.HTTP_UNAUTHORIZED)
         else:
             # Process the upload and get the response
             added_files = {}
             for key, formfields in form.items():
                 filename = key.replace("[]", "")
                 file_to_open = os.path.join(curdir, filename)
                 if hasattr(formfields, "filename") and formfields.filename:
                     dir_to_open = os.path.abspath(os.path.join(curdir,
                                                                'files',
                                                                str(user_info['uid']),
                                                                key))
                     try:
                         assert(dir_to_open.startswith(CFG_WEBSUBMIT_STORAGEDIR))
                     except AssertionError:
                         register_exception(req=req, prefix='curdir="%s", key="%s"' % (curdir, key))
                         raise apache.SERVER_RETURN(apache.HTTP_FORBIDDEN)
 
                     if not os.path.exists(dir_to_open):
                         try:
                             os.makedirs(dir_to_open)
                         except:
                             register_exception(req=req, alert_admin=True)
                             raise apache.SERVER_RETURN(apache.HTTP_FORBIDDEN)
 
                     filename = formfields.filename
                     ## Before saving the file to disc, wash the filename (in particular
                     ## washing away UNIX and Windows (e.g. DFS) paths):
                     filename = os.path.basename(filename.split('\\')[-1])
                     filename = filename.strip()
                     if filename != "":
                         # Check that file does not already exist
                         n = 1
                         while os.path.exists(os.path.join(dir_to_open, filename)):
                             #dirname, basename, extension = decompose_file(new_destination_path)
                             basedir, name, extension = decompose_file(filename)
                             new_name = propose_next_docname(name)
                             filename = new_name + extension
                         # This may be dangerous if the file size is bigger than the available memory
                         fp = open(os.path.join(dir_to_open, filename), "w")
                         fp.write(formfields.file.read())
                         fp.close()
                         fp = open(os.path.join(curdir, "lastuploadedfile"), "w")
                         fp.write(filename)
                         fp.close()
                         fp = open(file_to_open, "w")
                         fp.write(filename)
                         fp.close()
                         try:
                             # Create icon
                             (icon_path, icon_name) = create_icon(
                                 { 'input-file'           : os.path.join(dir_to_open, filename),
                                   'icon-name'            : filename, # extension stripped automatically
                                   'icon-file-format'     : 'gif',
                                   'multipage-icon'       : False,
                                   'multipage-icon-delay' : 100,
                                   'icon-scale'           : "300>", # Resize only if width > 300
                                   'verbosity'            : 0,
                                   })
 
                             icons_dir = os.path.join(os.path.join(curdir,
                                                                   'icons',
                                                                   str(user_info['uid']),
                                                                   key))
                             if not os.path.exists(icons_dir):
                                 # Create uid/icons dir if needed
                                 os.makedirs(icons_dir)
                             os.rename(os.path.join(icon_path, icon_name),
                                       os.path.join(icons_dir, icon_name))
                             added_files[key] = {'name': filename,
                                                 'iconName': icon_name}
                         except InvenioWebSubmitIconCreatorError, e:
                             # We could not create the icon
                             added_files[key] = {'name': filename}
                             continue
                     else:
                         raise apache.SERVER_RETURN(apache.HTTP_BAD_REQUEST)
 
             # Send our response
             if CFG_JSON_AVAILABLE:
                 return json.dumps(added_files)
 
 
     def upload_video(self, req, form):
         """
         A clone of uploadfile but for (large) videos.
         Does not copy the uploaded file to the websubmit directory.
         Instead, the path to the file is stored inside the submission directory.
         """
 
         def gcd(a,b):
             """ the euclidean algorithm """
             while a:
                 a, b = b%a, a
             return b
 
         from invenio.bibencode_extract import extract_frames
         from invenio.bibencode_config import CFG_BIBENCODE_WEBSUBMIT_ASPECT_SAMPLE_DIR, CFG_BIBENCODE_WEBSUBMIT_ASPECT_SAMPLE_FNAME
         from invenio.bibencode_encode import determine_aspect
         from invenio.bibencode_utils import probe
         from invenio.bibencode_metadata import ffprobe_metadata
         from invenio.websubmit_config import CFG_WEBSUBMIT_TMP_VIDEO_PREFIX
 
         argd = wash_urlargd(form, {
             'doctype': (str, ''),
             'access': (str, ''),
             'indir': (str, ''),
             'session_id': (str, ''),
             'rename': (str, ''),
             })
 
         curdir = None
         if not form.has_key("indir") or \
                not form.has_key("doctype") or \
                not form.has_key("access"):
             raise apache.SERVER_RETURN(apache.HTTP_BAD_REQUEST)
         else:
             curdir = os.path.join(CFG_WEBSUBMIT_STORAGEDIR,
                                   argd['indir'],
                                   argd['doctype'],
                                   argd['access'])
 
         user_info = collect_user_info(req)
         if form.has_key("session_id"):
             # Are we uploading using Flash, which does not transmit
             # cookie? The expect to receive session_id as a form
             # parameter.  First check that IP addresses do not
             # mismatch. A ValueError will be raises if there is
             # something wrong
             session = get_session(req=req, sid=argd['session_id'])
             try:
                 session = get_session(req=req, sid=argd['session_id'])
             except ValueError, e:
                 raise apache.SERVER_RETURN(apache.HTTP_BAD_REQUEST)
 
             # Retrieve user information. We cannot rely on the session here.
             res = run_sql("SELECT uid FROM session WHERE session_key=%s", (argd['session_id'],))
             if len(res):
                 uid = res[0][0]
                 user_info = collect_user_info(uid)
                 try:
                     act_fd = file(os.path.join(curdir, 'act'))
                     action = act_fd.read()
                     act_fd.close()
                 except:
                     act = ""
 
         # Is user authorized to perform this action?
         (auth_code, auth_message) = acc_authorize_action(uid, "submit",
                                                      verbose=0,
                                                      doctype=argd['doctype'],
                                                      act=action)
         if acc_is_role("submit", doctype=argd['doctype'], act=action) and auth_code != 0:
             # User cannot submit
             raise apache.SERVER_RETURN(apache.HTTP_UNAUTHORIZED)
         else:
             # Process the upload and get the response
             json_response = {}
             for key, formfields in form.items():
                 filename = key.replace("[]", "")
                 if hasattr(formfields, "filename") and formfields.filename:
                     dir_to_open = os.path.abspath(os.path.join(curdir,
                                                                'files',
                                                                str(user_info['uid']),
                                                                key))
                     try:
                         assert(dir_to_open.startswith(CFG_WEBSUBMIT_STORAGEDIR))
                     except AssertionError:
                         register_exception(req=req, prefix='curdir="%s", key="%s"' % (curdir, key))
                         raise apache.SERVER_RETURN(apache.HTTP_FORBIDDEN)
 
                     if not os.path.exists(dir_to_open):
                         try:
                             os.makedirs(dir_to_open)
                         except:
                             register_exception(req=req, alert_admin=True)
                             raise apache.SERVER_RETURN(apache.HTTP_FORBIDDEN)
 
                     filename = formfields.filename
                     ## Before saving the file to disc, wash the filename (in particular
                     ## washing away UNIX and Windows (e.g. DFS) paths):
                     filename = os.path.basename(filename.split('\\')[-1])
                     filename = filename.strip()
                     if filename != "":
                         # Check that file does not already exist
                         while os.path.exists(os.path.join(dir_to_open, filename)):
                             #dirname, basename, extension = decompose_file(new_destination_path)
                             basedir, name, extension = decompose_file(filename)
                             new_name = propose_next_docname(name)
                             filename = new_name + extension
 
                         #-------------#
                         # VIDEO STUFF #
                         #-------------#
 
                         ## Remove all previous uploads
                         filelist = os.listdir(os.path.split(formfields.file.name)[0])
                         for afile in filelist:
                             if argd['access'] in afile:
                                 os.remove(os.path.join(os.path.split(formfields.file.name)[0], afile))
 
                         ## Check if the file is a readable video
                         ## We must exclude all image and audio formats that are readable by ffprobe
                         if (os.path.splitext(filename)[1] in ['jpg', 'jpeg', 'gif', 'tiff', 'bmp', 'png', 'tga',
                                                               'jp2', 'j2k', 'jpf', 'jpm', 'mj2', 'biff', 'cgm',
                                                               'exif', 'img', 'mng', 'pic', 'pict', 'raw', 'wmf', 'jpe', 'jif',
                                                               'jfif', 'jfi', 'tif', 'webp', 'svg', 'ai', 'ps', 'psd',
                                                               'wav', 'mp3', 'pcm', 'aiff', 'au', 'flac', 'wma', 'm4a', 'wv', 'oga',
                                                               'm4a', 'm4b', 'm4p', 'm4r', 'aac', 'mp4', 'vox', 'amr', 'snd']
                                                               or not probe(formfields.file.name)):
                             formfields.file.close()
                             raise apache.SERVER_RETURN(apache.HTTP_FORBIDDEN)
 
                         ## We have no "delete" attribute in Python 2.4
                         if sys.hexversion < 0x2050000:
                             ## We need to rename first and create a dummy file
                             ## Rename the temporary file for the garbage collector
                             new_tmp_fullpath = os.path.split(formfields.file.name)[0] + "/" + CFG_WEBSUBMIT_TMP_VIDEO_PREFIX + argd['access'] + "_" + os.path.split(formfields.file.name)[1]
                             os.rename(formfields.file.name, new_tmp_fullpath)
                             dummy = open(formfields.file.name, "w")
                             dummy.close()
                             formfields.file.close()
                         else:
                             # Mark the NamedTemporatyFile as not to be deleted
                             formfields.file.delete = False
                             formfields.file.close()
                             ## Rename the temporary file for the garbage collector
                             new_tmp_fullpath = os.path.split(formfields.file.name)[0] + "/" + CFG_WEBSUBMIT_TMP_VIDEO_PREFIX + argd['access'] + "_" + os.path.split(formfields.file.name)[1]
                             os.rename(formfields.file.name, new_tmp_fullpath)
 
                         # Write the path to the temp file to a file in STORAGEDIR
                         fp = open(os.path.join(dir_to_open, "filepath"), "w")
                         fp.write(new_tmp_fullpath)
                         fp.close()
 
                         fp = open(os.path.join(dir_to_open, "filename"), "w")
                         fp.write(filename)
                         fp.close()
 
                         ## We are going to extract some thumbnails for websubmit ##
                         sample_dir = os.path.join(curdir, 'files', str(user_info['uid']), CFG_BIBENCODE_WEBSUBMIT_ASPECT_SAMPLE_DIR)
                         try:
                             ## Remove old thumbnails
                             shutil.rmtree(sample_dir)
                         except OSError:
                             register_exception(req=req, alert_admin=False)
                         try:
                             os.makedirs(os.path.join(curdir, 'files', str(user_info['uid']), sample_dir))
                         except OSError:
                             register_exception(req=req, alert_admin=False)
                         try:
                             extract_frames(input_file=new_tmp_fullpath,
                                         output_file=os.path.join(sample_dir, CFG_BIBENCODE_WEBSUBMIT_ASPECT_SAMPLE_FNAME),
                                         size="600x600",
                                         numberof=5)
                             json_response['frames'] = []
                             for extracted_frame in os.listdir(sample_dir):
                                 json_response['frames'].append(extracted_frame)
                         except:
                             ## If the frame extraction fails, something was bad with the video
                             os.remove(new_tmp_fullpath)
                             register_exception(req=req, alert_admin=False)
                             raise apache.SERVER_RETURN(apache.HTTP_FORBIDDEN)
 
                         ## Try to detect the aspect. if this fails, the video is not readable
                         ## or a wrong file might have been uploaded
                         try:
                             (aspect, width, height) = determine_aspect(new_tmp_fullpath)
                             if aspect:
                                 aspx, aspy = aspect.split(':')
                             else:
                                 the_gcd = gcd(width, height)
                                 aspx = str(width / the_gcd)
                                 aspy = str(height / the_gcd)
                             json_response['aspx'] = aspx
                             json_response['aspy'] = aspy
                         except TypeError:
                             ## If the aspect detection completely fails
                             os.remove(new_tmp_fullpath)
                             register_exception(req=req, alert_admin=False)
                             raise apache.SERVER_RETURN(apache.HTTP_FORBIDDEN)
 
                         ## Try to extract some metadata from the video container
                         metadata = ffprobe_metadata(new_tmp_fullpath)
                         json_response['meta_title'] = metadata['format'].get('TAG:title')
                         json_response['meta_description'] = metadata['format'].get('TAG:description')
                         json_response['meta_year'] = metadata['format'].get('TAG:year')
                         json_response['meta_author'] = metadata['format'].get('TAG:author')
                     ## Empty file name
                     else:
                         raise apache.SERVER_RETURN(apache.HTTP_BAD_REQUEST)
                     ## We found our file, we can break the loop
                     break;
 
             # Send our response
             if CFG_JSON_AVAILABLE:
 
                 dumped_response = json.dumps(json_response)
 
                 # store the response in the websubmit directory
                 # this is needed if the submission is not finished and continued later
                 response_dir = os.path.join(curdir, 'files', str(user_info['uid']), "response")
                 try:
                     os.makedirs(response_dir)
                 except OSError:
                     # register_exception(req=req, alert_admin=False)
                     pass
                 fp = open(os.path.join(response_dir, "response"), "w")
                 fp.write(dumped_response)
                 fp.close()
 
                 return dumped_response
 
     def getuploadedfile(self, req, form):
         """
         Stream uploaded files.
 
         For the moment, restrict to files in ./curdir/files/uid or
         ./curdir/icons/uid directory, so that we are sure we stream
         files only to the user who uploaded them.
         """
         argd = wash_urlargd(form, {'indir': (str, None),
                                    'doctype': (str, None),
                                    'access': (str, None),
                                    'icon': (int, 0),
                                    'key': (str, None),
                                    'filename': (str, None),
                                    'nowait': (int, 0)})
 
         if None in argd.values():
             raise apache.SERVER_RETURN(apache.HTTP_BAD_REQUEST)
 
         uid = getUid(req)
 
         if argd['icon']:
             file_path = os.path.join(CFG_WEBSUBMIT_STORAGEDIR,
                                      argd['indir'],
                                      argd['doctype'],
                                      argd['access'],
                                      'icons',
                                      str(uid),
                                      argd['key'],
                                      argd['filename']
                                      )
         else:
             file_path = os.path.join(CFG_WEBSUBMIT_STORAGEDIR,
                                      argd['indir'],
                                      argd['doctype'],
                                      argd['access'],
                                      'files',
                                      str(uid),
                                      argd['key'],
                                      argd['filename']
                                      )
 
         abs_file_path = os.path.abspath(file_path)
         if abs_file_path.startswith(CFG_WEBSUBMIT_STORAGEDIR):
             # Check if file exist. Note that icon might not yet have
             # been created.
             if not argd['nowait']:
                 for i in range(5):
                     if os.path.exists(abs_file_path):
                         return stream_file(req, abs_file_path)
                     time.sleep(1)
             else:
                 if os.path.exists(abs_file_path):
                         return stream_file(req, abs_file_path)
 
         # Send error 404 in all other cases
         raise apache.SERVER_RETURN(apache.HTTP_NOT_FOUND)
 
     def attachfile(self, req, form):
         """
         Process requests received from CKEditor to upload files.
         If the uploaded file is an image, create an icon version
         """
         if not is_html_text_editor_installed():
             return apache.HTTP_NOT_FOUND
 
         if not form.has_key('type'):
             form['type'] = 'File'
 
         if not form.has_key('upload') or \
                not form['type'] in \
                ['File', 'Image', 'Flash', 'Media']:
             #return apache.HTTP_NOT_FOUND
             pass
         filetype = form['type'].lower()
 
         uid = getUid(req)
 
 
         # URL where the file can be fetched after upload
         user_files_path = '%(CFG_SITE_URL)s/submit/getattachedfile/%(uid)s' % \
                           {'uid': uid,
                            'CFG_SITE_URL': CFG_SITE_URL,
                            'filetype': filetype}
 
         # Path to directory where uploaded files are saved
         user_files_absolute_path = '%(CFG_PREFIX)s/var/tmp/attachfile/%(uid)s/%(filetype)s' % \
                                    {'uid': uid,
                                     'CFG_PREFIX': CFG_PREFIX,
                                     'filetype': filetype}
         try:
             os.makedirs(user_files_absolute_path)
         except:
             pass
 
         user_info = collect_user_info(req)
         (auth_code, auth_message) = acc_authorize_action(user_info, 'attachsubmissionfile')
         msg = ""
         if user_info['email'] == 'guest':
             # User is guest: must login prior to upload
             msg = 'Please login before uploading file.'
         elif auth_code:
             # User cannot submit
             msg = 'Sorry, you are not allowed to submit files.'
         ## elif len(form['upload']) != 1:
         ##     msg = 'Sorry, you must upload one single file'
         else:
             # Process the upload and get the response
             (msg, uploaded_file_path, uploaded_file_name, uploaded_file_url, callback_function) = \
                   process_CKEditor_upload(form, uid, user_files_path, user_files_absolute_path)
 
             if uploaded_file_path:
                 # Create an icon
                 if form.get('type','') == 'Image':
                     try:
                         (icon_path, icon_name) = create_icon(
                             { 'input-file'           : uploaded_file_path,
                               'icon-name'            : os.path.splitext(uploaded_file_name)[0],
                               'icon-file-format'     : os.path.splitext(uploaded_file_name)[1][1:] or 'gif',
                               'multipage-icon'       : False,
                               'multipage-icon-delay' : 100,
                               'icon-scale'           : "300>", # Resize only if width > 300
                               'verbosity'            : 0,
                               })
 
                         # Move original file to /original dir, and replace it with icon file
                         original_user_files_absolute_path = os.path.join(user_files_absolute_path,
                                                                          'original')
                         if not os.path.exists(original_user_files_absolute_path):
                             # Create /original dir if needed
                             os.mkdir(original_user_files_absolute_path)
                         os.rename(uploaded_file_path,
                                   original_user_files_absolute_path + os.sep + uploaded_file_name)
                         os.rename(icon_path + os.sep + icon_name,
                                   uploaded_file_path)
                     except InvenioWebSubmitIconCreatorError, e:
                         pass
 
                 user_files_path += '/' + filetype + '/' + uploaded_file_name
 
             else:
                 user_files_path = ''
                 if not msg:
                     msg = 'No valid file found'
 
         # Send our response
         send_response(req, msg, user_files_path, callback_function)
 
     def _lookup(self, component, path):
         """ This handler is invoked for the dynamic URLs (for getting
         and putting attachments) Eg:
         /submit/getattachedfile/41336978/image/myfigure.png
         /submit/attachfile/41336978/image/myfigure.png
         """
         if component == 'getattachedfile' and len(path) > 2:
 
             uid = path[0] # uid of the submitter
             file_type = path[1] # file, image, flash or media (as
                                 # defined by CKEditor)
 
             if file_type in ['file', 'image', 'flash', 'media']:
                 file_name = '/'.join(path[2:]) # the filename
 
                 def answer_get(req, form):
                     """Accessing files attached to submission."""
                     form['file'] = file_name
                     form['type'] = file_type
                     form['uid'] = uid
                     return self.getattachedfile(req, form)
 
                 return answer_get, []
 
         # All other cases: file not found
         return None, []
 
     def getattachedfile(self, req, form):
         """
         Returns a file uploaded to the submission 'drop box' by the
         CKEditor.
         """
         argd = wash_urlargd(form, {'file': (str, None),
                                    'type': (str, None),
                                    'uid': (int, 0)})
 
         # Can user view this record, i.e. can user access its
         # attachments?
         uid = getUid(req)
         user_info = collect_user_info(req)
 
         if not argd['file'] is None:
             # Prepare path to file on disk. Normalize the path so that
             # ../ and other dangerous components are removed.
             path = os.path.abspath(CFG_PREFIX + '/var/tmp/attachfile/' + \
                                    '/'  + str(argd['uid']) + \
                                    '/' + argd['type'] + '/' + argd['file'])
 
             # Check that we are really accessing attachements
             # directory, for the declared record.
             if path.startswith(CFG_PREFIX + '/var/tmp/attachfile/') and os.path.exists(path):
                 return stream_file(req, path)
 
         # Send error 404 in all other cases
         return(apache.HTTP_NOT_FOUND)
 
     def direct(self, req, form):
         """Directly redirected to an initialized submission."""
         args = wash_urlargd(form, {'sub': (str, ''),
                                    'access' : (str, '')})
 
         sub = args['sub']
         access = args['access']
         ln = args['ln']
 
         _ = gettext_set_language(ln)
 
         uid = getUid(req)
         if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1:
             return page_not_authorized(req, "direct",
                                            navmenuid='submit')
 
         myQuery = req.args
         if not sub:
             return warningMsg(_("Sorry, 'sub' parameter missing..."), req, ln=ln)
         res = run_sql("SELECT docname,actname FROM sbmIMPLEMENT WHERE subname=%s", (sub,))
         if not res:
             return warningMsg(_("Sorry. Cannot analyse parameter"), req, ln=ln)
         else:
             # get document type
             doctype = res[0][0]
             # get action name
             action = res[0][1]
         # retrieve other parameter values
         params = dict(form)
         # find existing access number
         if not access:
             # create 'unique' access number
             pid = os.getpid()
             now = time.time()
             access = "%i_%s" % (now,pid)
         # retrieve 'dir' value
         res = run_sql ("SELECT dir FROM sbmACTION WHERE sactname=%s", (action,))
         dir = res[0][0]
 
         mainmenu = req.headers_in.get('referer')
 
         params['access'] = access
         params['act'] = action
         params['doctype'] = doctype
         params['startPg'] = '1'
         params['mainmenu'] = mainmenu
         params['ln'] = ln
         params['indir'] = dir
 
         url = "%s/submit?%s" % (CFG_SITE_SECURE_URL, urlencode(params))
         redirect_to_url(req, url)
 
     def sub(self, req, form):
         """DEPRECATED: /submit/sub is deprecated now, so raise email to the admin (but allow submission to continue anyway)"""
         args = wash_urlargd(form, {'password': (str, '')})
         uid = getUid(req)
         if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1:
             return page_not_authorized(req, "../sub/",
                                        navmenuid='submit')
         try:
             raise DeprecationWarning, 'submit/sub handler has been used. Please use submit/direct. e.g. "submit/sub?RN=123@SBIFOO" -> "submit/direct?RN=123&sub=SBIFOO"'
         except DeprecationWarning:
             register_exception(req=req, alert_admin=True)
 
         ln = args['ln']
         _ = gettext_set_language(ln)
         #DEMOBOO_RN=DEMO-BOOK-2008-001&ln=en&password=1223993532.26572%40APPDEMOBOO
         params = dict(form)
         password = args['password']
         if password:
             del params['password']
             if "@" in password:
                 params['access'], params['sub'] = password.split('@', 1)
             else:
                 params['sub'] = password
         else:
             args = str(req.args).split('@')
             if len(args) > 1:
                 params = {'sub' : args[-1]}
                 args = '@'.join(args[:-1])
                 params.update(cgi.parse_qs(args))
             else:
                 return warningMsg(_("Sorry, invalid URL..."), req, ln=ln)
         url = "%s/submit/direct?%s" % (CFG_SITE_SECURE_URL, urlencode(params, doseq=True))
         redirect_to_url(req, url)
 
 
     def summary(self, req, form):
         args = wash_urlargd(form, {
             'doctype': (str, ''),
             'act': (str, ''),
             'access': (str, ''),
             'indir': (str, '')})
 
         uid = getUid(req)
         if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1:
             return page_not_authorized(req, "../summary",
                                        navmenuid='submit')
 
         t=""
         curdir  = os.path.join(CFG_WEBSUBMIT_STORAGEDIR, args['indir'], args['doctype'], args['access'])
         try:
             assert(curdir == os.path.abspath(curdir))
         except AssertionError:
             register_exception(req=req, alert_admin=True, prefix='Possible cracking tentative: indir="%s", doctype="%s", access="%s"' % (args['indir'], args['doctype'], args['access']))
             return warningMsg("Invalid parameters", req)
 
         subname = "%s%s" % (args['act'], args['doctype'])
 
         res = run_sql("select sdesc,fidesc,pagenb,level from sbmFIELD where subname=%s "
                       "order by pagenb,fieldnb", (subname,))
         nbFields = 0
 
         values = []
         for arr in res:
             if arr[0] != "":
                 val = {
                        'mandatory' : (arr[3] == 'M'),
                        'value' : '',
                        'page' : arr[2],
                        'name' : arr[0],
                       }
                 if os.path.exists(os.path.join(curdir, curdir,arr[1])):
                     fd = open(os.path.join(curdir, arr[1]),"r")
                     value = fd.read()
                     fd.close()
                     value = value.replace("\n"," ")
                     value = value.replace("Select:","")
                 else:
                     value = ""
                 val['value'] = value
                 values.append(val)
 
         return websubmit_templates.tmpl_submit_summary(
                  ln = args['ln'],
                  values = values,
                )
 
     def index(self, req, form):
 
         args = wash_urlargd(form, {
             'c': (str, CFG_SITE_NAME),
             'doctype': (str, ''),
             'act': (str, ''),
             'startPg': (str, "1"),
             'access': (str, ''),
             'mainmenu': (str, ''),
             'fromdir': (str, ''),
             'nextPg': (str, ''),
             'nbPg': (str, ''),
             'curpage': (str, '1'),
             'step': (str, '0'),
             'mode': (str, 'U'),
             })
 
         ## Strip whitespace from beginning and end of doctype and action:
         args["doctype"] = args["doctype"].strip()
         args["act"] = args["act"].strip()
 
         def _index(req, c, ln, doctype, act, startPg, access,
                    mainmenu, fromdir, nextPg, nbPg, curpage, step,
                    mode):
 
             uid = getUid(req)
             if isGuestUser(uid):
                 return redirect_to_url(req, "%s/youraccount/login%s" % (
                     CFG_SITE_SECURE_URL,
                         make_canonical_urlargd({
                     'referer' : CFG_SITE_SECURE_URL + req.unparsed_uri, 'ln' : args['ln']}, {})), norobot=True)
 
             if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1:
                 return page_not_authorized(req, "../submit",
                                            navmenuid='submit')
             if CFG_CERN_SITE:
                 ## HACK BEGIN: this is a hack for CMS and ATLAS draft
                 from invenio.webuser import collect_user_info
                 user_info = collect_user_info(req)
                 if doctype == 'CMSPUB' and 'cds-admin [CERN]' not in user_info['group'] and not user_info['email'].lower() == 'cds.support@cern.ch':
                     if 'cms-publication-committee-chair [CERN]' not in user_info['group']:
                         return page_not_authorized(req, "../submit", text="In order to access this submission interface you need to be member of the CMS Publication Committee Chair.",
                                         navmenuid='submit')
                 elif doctype == 'ATLPUB' and 'cds-admin [CERN]' not in user_info['group'] and not user_info['email'].lower() == 'cds.support@cern.ch':
                     if 'atlas-gen [CERN]' not in user_info['group']:
                         return page_not_authorized(req, "../submit", text="In order to access this submission interface you need to be member of ATLAS.",
                                         navmenuid='submit')
             ## HACK END
 
             if doctype=="":
                 return home(req,c,ln)
             elif act=="":
                 return action(req,c,ln,doctype)
             elif int(step)==0:
                 return interface(req, c, ln, doctype, act, startPg, access, mainmenu, fromdir, nextPg, nbPg, curpage)
             else:
                 return endaction(req, c, ln, doctype, act, startPg, access,mainmenu, fromdir, nextPg, nbPg, curpage, step, mode)
 
         return _index(req, **args)
 
     # Answer to both /submit/ and /submit
     __call__ = index
 
 def errorMsg(title, req, c=None, ln=CFG_SITE_LANG):
     # load the right message language
     _ = gettext_set_language(ln)
 
     if c is None:
         c = CFG_SITE_NAME_INTL.get(ln, CFG_SITE_NAME)
 
     return page(title = _("Error"),
                 body = create_error_box(req, title=str(title), verbose=0, ln=ln),
                 description="%s - Internal Error" % c,
                 keywords="%s, Internal Error" % c,
                 uid = getUid(req),
                 language=ln,
                 req=req,
                 navmenuid='submit')
 
 def warningMsg(title, req, c=None, ln=CFG_SITE_LANG):
     # load the right message language
     _ = gettext_set_language(ln)
 
     if c is None:
         c = CFG_SITE_NAME_INTL.get(ln, CFG_SITE_NAME)
 
     return page(title = _("Warning"),
                 body = title,
                 description="%s - Internal Error" % c,
                 keywords="%s, Internal Error" % c,
                 uid = getUid(req),
                 language=ln,
                 req=req,
                 navmenuid='submit')
 
 def print_warning(msg, type='', prologue='<br />', epilogue='<br />'):
     """Prints warning message and flushes output."""
     if msg:
         return websubmit_templates.tmpl_print_warning(
                    msg = msg,
                    type = type,
                    prologue = prologue,
                    epilogue = epilogue,
                  )
     else:
         return ''
 
 ## def retrieve_most_recent_attached_file(file_path):
 ##     """
 ##     Retrieve the latest file that has been uploaded with the
 ##     CKEditor. This is the only way to retrieve files that the
 ##     CKEditor has renamed after the upload.
 
 ##     Eg: 'prefix/image.jpg' was uploaded but did already
 ##     exist. CKEditor silently renamed it to 'prefix/image(1).jpg':
 ##     >>> retrieve_most_recent_attached_file('prefix/image.jpg')
 ##     'prefix/image(1).jpg'
 ##     """
 ##     (base_path, filename) = os.path.split(file_path)
 ##     base_name = os.path.splitext(filename)[0]
 ##     file_ext = os.path.splitext(filename)[1][1:]
 ##     most_recent_filename = filename
 ##     i = 0
 ##     while True:
 ##         i += 1
 ##         possible_filename = "%s(%d).%s" % \
 ##                             (base_name, i, file_ext)
 ##         if os.path.exists(base_path + os.sep + possible_filename):
 ##             most_recent_filename = possible_filename
 ##         else:
 ##             break
 
 ##     return os.path.join(base_path, most_recent_filename)