diff --git a/modules/webbasket/lib/webbasket.py b/modules/webbasket/lib/webbasket.py
index a028fcd7e..bab1051b6 100644
--- a/modules/webbasket/lib/webbasket.py
+++ b/modules/webbasket/lib/webbasket.py
@@ -1,2891 +1,2874 @@
 ## This file is part of Invenio.
 ## Copyright (C) 2003, 2004, 2005, 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.
 
 """Web Baskets features."""
 
 __revision__ = "$Id$"
 
 import sys
 
 
 if sys.hexversion < 0x2040000:
     # pylint: disable=W0622
     from sets import Set as set
     # pylint: enable=W0622
 
 from invenio.intbitset import intbitset
 
 import cgi
+import urllib
 from httplib import urlsplit, HTTPConnection
 #from socket import getdefaulttimeout, setdefaulttimeout
 from zlib import decompress
 import re
 
 from invenio.config import CFG_SITE_LANG, CFG_SITE_URL, \
      CFG_WEBBASKET_MAX_NUMBER_OF_DISPLAYED_BASKETS
 from invenio.messages import gettext_set_language
 from invenio.dateutils import convert_datetext_to_dategui, \
                               convert_datetext_to_datestruct,\
                               convert_datestruct_to_dategui
 from invenio.bibformat import format_record
 from invenio.webbasket_config import CFG_WEBBASKET_SHARE_LEVELS, \
                                      CFG_WEBBASKET_SHARE_LEVELS_ORDERED, \
                                      CFG_WEBBASKET_CATEGORIES, \
                                      InvenioWebBasketWarning
 from invenio.urlutils import get_referer
 from invenio.webuser import isGuestUser, collect_user_info
 from invenio.search_engine import \
      record_exists, \
      check_user_can_view_record, \
      print_records_prologue, \
      print_records_epilogue
 #from invenio.webcomment import check_user_can_attach_file_to_comments
 import invenio.webbasket_dblayer as db
 try:
     import invenio.template
     webbasket_templates = invenio.template.load('webbasket')
 except ImportError:
     pass
 from invenio.websearch_external_collections_utils import get_collection_name_by_id
 from invenio.websearch_external_collections import select_hosted_search_engines
 from invenio.websearch_external_collections_config import CFG_EXTERNAL_COLLECTION_TIMEOUT
 from invenio.websearch_external_collections_getter import HTTPAsyncPageGetter, async_download
 from invenio.errorlib import register_exception
 from invenio.search_engine import search_unit
 from invenio.htmlutils import remove_html_markup
 
 ########################################
 ### Display public baskets and notes ###
 ########################################
 
 def perform_request_display_public(uid,
                                    selected_bskid=0,
                                    selected_recid=0,
                                    optional_params={},
                                    of='hb',
                                    ln=CFG_SITE_LANG):
     """Engine for the display of a public interface. Calls the template and returns HTML.
     @param selected_bskid: The id of the basket to be displayed (optional)
     @param selected_recid: The id of the item to be displayed (optional)
     @param optional_params: optional parameters to be passed, used for notes
     @param of: display format
     @param ln: language"""
 
     _ = gettext_set_language(ln)
 
     warnings_item = []
     warnings_basket = []
 
     (of, of_warnings) = wash_of(of)
     if of_warnings:
         navtrail = create_webbasket_navtrail(uid, ln=ln)
         body = webbasket_templates.tmpl_warnings(of_warnings, ln)
         return (body, of_warnings, navtrail)
 
     basket = db.get_public_basket_info(selected_bskid)
     if not basket:
         if of != 'hb':
             return ("", None, None)
         try:
             raise InvenioWebBasketWarning(_('The selected public basket does not exist or you do not have access to it.'))
         except InvenioWebBasketWarning, exc:
             register_exception(stream='warning')
         warnings_html = webbasket_templates.tmpl_warnings(exc.message, ln)
             #warnings.append(exc.message)
         #warnings = ['WRN_WEBBASKET_INVALID_OR_RESTRICTED_PUBLIC_BASKET']
         (body, navtrail) = perform_request_list_public_baskets(uid)
         try:
             raise InvenioWebBasketWarning(_('Please select a valid public basket from the list of public baskets.'))
         except InvenioWebBasketWarning, exc:
             register_exception(stream='warning')
             #warnings.append(exc.message)
         #warnings.append('WRN_WEBBASKET_SHOW_LIST_PUBLIC_BASKETS')
         warnings_html += webbasket_templates.tmpl_warnings(exc.message, ln)
         body = warnings_html + body
         return (body, None, navtrail)
     else:
         (bskid, basket_name, id_owner, last_update, dummy, nb_items, recids, share_rights) = basket[0]
         if selected_recid:
-            valid_recids = eval(recids + ',')
+            valid_recids = tuple(map(int, recids.split(',')))
             if selected_recid in valid_recids:
                 (content, warnings_item) = __display_public_basket_single_item(bskid,
                                                                           basket_name,
                                                                           selected_recid,
                                                                           nb_items,
                                                                           share_rights,
                                                                           optional_params,
                                                                           of,
                                                                           ln)
             else:
                 try:
                     raise InvenioWebBasketWarning(_('The selected item does not exist or you do not have access to it.'))
                 except InvenioWebBasketWarning, exc:
                     register_exception(stream='warning')
                     warnings_item.append(exc.message)
                 #warnings_item.append('WRN_WEBBASKET_INVALID_OR_RESTRICTED_ITEM')
                 try:
                     raise InvenioWebBasketWarning(_('Returning to the public basket view.'))
                 except InvenioWebBasketWarning, exc:
                     register_exception(stream='warning')
                     warnings_item.append(exc.message)
                 #warnings_item.append('WRN_WEBBASKET_RETURN_TO_PUBLIC_BASKET')
                 selected_recid = 0
         if not selected_recid:
             if uid == id_owner:
                 subscription_status = 0
             else:
                 if db.is_user_subscribed_to_basket(uid,bskid):
                     subscription_status = 1
                 else:
                     subscription_status = -1
             (content, warnings_basket) = __display_public_basket(bskid,
                                                           basket_name,
                                                           last_update,
                                                           nb_items,
                                                           share_rights,
                                                           id_owner,
                                                           subscription_status,
                                                           of,
                                                           ln)
 
     if of == 'hb':
         body = webbasket_templates.tmpl_display(content=content)
         warnings = warnings_item + warnings_basket
         warnings_html = webbasket_templates.tmpl_warnings(warnings, ln)
         body = warnings_html + body
     else:
         body = content
 
     if of == 'hb':
         navtrail = create_webbasket_navtrail(uid,
                                              bskid=selected_bskid,
                                              public_basket=True,
                                              ln=ln)
 
     if of == 'hb':
         return (body, warnings, navtrail)
     else:
         return (body, None, None)
 
 def __display_public_basket(bskid,
                             basket_name,
                             last_update,
                             nb_items,
                             share_rights,
                             id_owner,
                             subscription_status,
                             of='hb',
                             ln=CFG_SITE_LANG):
     """Private function. Display a basket giving its category and topic or group.
     @param share_rights: rights user has on basket
     @param group_sharing_level: None if basket is not shared,
                                 0 if public basket,
                                 > 0 if shared to usergroups but not public.
     @param category: selected category (see webbasket_config.py)
     @param selected_topic: # of selected topic to display baskets
     @param selected_group_id: id of group to display baskets
     @param ln: language"""
 
     _ = gettext_set_language(ln)
 
     warnings = []
 
     nb_total_notes = 0
     last_note = _("N/A")
     records = []
     notes_dates = []
     last_update = convert_datetext_to_dategui(last_update, ln)
 
     items = db.get_basket_content(bskid, of)
     external_recids = []
 
     for (recid, collection_id, nb_notes, last_note, ext_val, int_val, score) in items:
         notes_dates.append(convert_datetext_to_datestruct(last_note))
         last_note = convert_datetext_to_dategui(last_note, ln)
         colid = collection_id and collection_id or collection_id == 0 and -1 or 0
         val = ""
         nb_total_notes += nb_notes
         if recid < 0:
             if ext_val:
                 val = decompress(ext_val)
             else:
                 external_recids.append(recid)
         else:
             if int_val:
                 val = decompress(int_val)
             else:
                 val = format_record(recid, of, on_the_fly=True)
         records.append((recid, colid, nb_notes, last_note, val, score))
 
     if external_recids:
         external_records = format_external_records(external_recids, of)
 
         for external_record in external_records:
             for record in records:
                 if record[0] == -external_record[0]:
                     idx = records.index(record)
                     tuple_to_list = list(records.pop(idx))
                     tuple_to_list[4] = external_record[1]
                     records.insert(idx, tuple(tuple_to_list))
                     break
 
     if notes_dates:
         last_note = convert_datestruct_to_dategui(max(notes_dates), ln)
 
     body = webbasket_templates.tmpl_public_basket(bskid,
                                                   basket_name,
                                                   last_update,
                                                   nb_items,
                                                   (check_sufficient_rights(share_rights, CFG_WEBBASKET_SHARE_LEVELS['READCMT'],),),
                                                   nb_total_notes,
                                                   records,
                                                   id_owner,
                                                   subscription_status,
                                                   of,
                                                   ln)
     return (body, warnings)
 
 def __display_public_basket_single_item(bskid,
                                         basket_name,
                                         recid,
                                         nb_items,
                                         share_rights,
                                         optional_params={},
                                         of='hb',
                                         ln=CFG_SITE_LANG):
     """Private function. Display a basket giving its category and topic or group.
     @param share_rights: rights user has on basket
     @param group_sharing_level: None if basket is not shared,
                                 0 if public basket,
                                 > 0 if shared to usergroups but not public.
     @param category: selected category (see webbasket_config.py)
     @param selected_topic: # of selected topic to display baskets
     @param selected_group_id: id of group to display baskets
     @param ln: language"""
 
     _ = gettext_set_language(ln)
 
     warnings = []
 
     item = db.get_basket_item(bskid, recid, of)
 
     if item:
         (recid, collection_id, nb_notes, last_note, ext_val, int_val, score) = item[0]
         previous_item_recid = item[1]
         next_item_recid = item[2]
         item_index = item[3]
     else:
         # The validity of the recid and hence the item is already checked by the
         # previous function and the appropriate warning is returned.
         # This is just an extra check just in case we missed something.
         # An empty body is returned.
         body = ""
         try:
             raise InvenioWebBasketWarning(_('The selected item does not exist or you do not have access to it.'))
         except InvenioWebBasketWarning, exc:
             register_exception(stream='warning')
             warnings.append(exc.message)
         #warnings.append('WRN_WEBBASKET_INVALID_OR_RESTRICTED_ITEM')
         return (body, warnings)
     last_note = convert_datetext_to_dategui(last_note, ln)
     colid = collection_id and collection_id or collection_id == 0 and -1 or 0
     val = ""
     if recid < 0:
         if ext_val:
             val = decompress(ext_val)
         else:
             external_record = format_external_records([recid], of)
             val = external_record and external_record[0][1] or ""
     else:
         if int_val:
             val = decompress(int_val)
         else:
             val = format_record(recid, of, on_the_fly=True)
     item = (recid, colid, nb_notes, last_note, val, score)
 
     notes = db.get_notes(bskid, recid)
 
     body = webbasket_templates.tmpl_public_basket_single_item(bskid,
                                                               basket_name,
                                                               nb_items,
                                                               (check_sufficient_rights(share_rights, CFG_WEBBASKET_SHARE_LEVELS['READCMT']),
                                                                check_sufficient_rights(share_rights, CFG_WEBBASKET_SHARE_LEVELS['ADDCMT'])),
                                                               item,
                                                               notes,
                                                               previous_item_recid,
                                                               next_item_recid,
                                                               item_index,
                                                               optional_params,
                                                               of,
                                                               ln)
     return (body, warnings)
 
 def perform_request_list_public_baskets(uid,
                                         limit=1,
                                         sort='name',
                                         asc=1,
                                         nb_views_show_p=False,
                                         ln=CFG_SITE_LANG):
 
     """Display list of public baskets.
     @param limit: display baskets from the incrementally numbered 'limit' and on
     @param sort: sort by 'name' or 'views' or 'owner' or 'date' or 'items'
     @param asc: ascending sort or not
     @param ln: language"""
 
     warnings_html = ""
 
     number_of_all_public_baskets = db.count_all_public_baskets()
 
     limit -= 1
     if limit < 0:
         limit = 0
     elif limit >= number_of_all_public_baskets:
         limit = number_of_all_public_baskets - 1
 
     if not nb_views_show_p and sort == 'views':
         # TODO: Add a 'sort by views' restriction warning
         #warnings.append('...')
         #warnings_html += webbasket_templates.tmpl_warnings(warnings, ln)
         sort = "name"
 
     all_public_baskets = db.get_list_public_baskets(limit,
                                                     CFG_WEBBASKET_MAX_NUMBER_OF_DISPLAYED_BASKETS,
                                                     sort,
                                                     asc)
 
     body = webbasket_templates.tmpl_display_list_public_baskets(all_public_baskets,
                                                                 limit,
                                                                 number_of_all_public_baskets,
                                                                 sort,
                                                                 asc,
                                                                 nb_views_show_p,
                                                                 ln)
 
     search_box = __create_search_box(uid=uid,
                                      category=CFG_WEBBASKET_CATEGORIES['ALLPUBLIC'],
                                      ln=ln)
 
     body = webbasket_templates.tmpl_display(content=body, search_box=search_box)
 
     body = warnings_html + body
 
     navtrail = create_webbasket_navtrail(uid,
                                          public_basket=True,
                                          ln=ln)
 
     return (body, navtrail)
 
 def perform_request_write_public_note(uid,
                                       bskid=0,
                                       recid=0,
                                       cmtid=0,
                                       ln=CFG_SITE_LANG):
     """Display a note writing form
     @param uid: user id
     @param bskid: basket id
     @param recid: record id (comments are on a specific record in a specific basket)
     @param cmtid: if provided this comment is a reply to comment cmtid.
     @param category: selected category
     @param topic: selected topic
     @param group_id: selected group id
     @param ln: language
     """
     _ = gettext_set_language(ln)
 
     optional_params = {}
     warnings_rights = []
     warnings_html = ""
 
     if not can_add_notes_to_public_basket_p(bskid):
         try:
             raise InvenioWebBasketWarning(_('You do not have permission to write notes to this item.'))
         except InvenioWebBasketWarning, exc:
             register_exception(stream='warning')
 #            warnings_rights = exc.message
         #warnings_rights = ['WRN_WEBBASKET_RESTRICTED_WRITE_NOTES']
         warnings_html += webbasket_templates.tmpl_warnings(warnings_rights, ln)
     else:
         if cmtid and db.note_belongs_to_item_in_basket_p(cmtid, recid, bskid):
             optional_params["Add note"] = db.get_note(cmtid)
             optional_params["Reply to"] = cmtid
         elif cmtid:
             optional_params["Add note"] = ()
             try:
                 raise InvenioWebBasketWarning(_('The note you are quoting does not exist or you do not have access to it.'))
             except InvenioWebBasketWarning, exc:
                 register_exception(stream='warning')
                 optional_params["Warnings"] = exc.message
         else:
             optional_params["Add note"] = ()
 
     (body, warnings, navtrail) = perform_request_display_public(uid=uid,
                                                                 selected_bskid=bskid,
                                                                 selected_recid=recid,
                                                                 optional_params=optional_params,
                                                                 of='hb',
                                                                 ln=CFG_SITE_LANG)
 
     if not warnings:
         body = warnings_html + body
 #        warnings = warnings_rights
 
     return (body, navtrail)
 
 def perform_request_save_public_note(uid,
                                      bskid=0,
                                      recid=0,
                                      note_title="",
                                      note_body="",
                                      editor_type='textarea',
                                      ln=CFG_SITE_LANG,
                                      reply_to=None):
     """ Save a given comment if able to.
     @param uid: user id (int)
     @param bskid: basket id (int)
     @param recid: record id (int)
     @param title: title of comment (string)
     @param text: comment's body (string)
     @param ln: language (string)
     @param editor_type: the kind of editor/input used for the comment: 'textarea', 'ckeditor'
     @param reply_to: the id of the comment we are replying to
     """
     optional_params = {}
     warnings_rights = []
     warnings_html = ""
     _ = gettext_set_language(ln)
 
     if not can_add_notes_to_public_basket_p(bskid):
         try:
             raise InvenioWebBasketWarning(_('You do not have permission to write notes to this item.'))
         except InvenioWebBasketWarning, exc:
             register_exception(stream='warning')
 #            warnings_rights = exc.message
         #warnings_rights = ['WRN_WEBBASKET_RESTRICTED_WRITE_NOTES']
         warnings_html += webbasket_templates.tmpl_warnings(warnings_rights, ln)
     else:
         if not note_title or not note_body: # FIXME: improve check when ckeditor
             optional_params["Incomplete note"] = (note_title, note_body)
             try:
                 raise InvenioWebBasketWarning(_('You must fill in both the subject and the body of the note.'))
             except InvenioWebBasketWarning, exc:
                 register_exception(stream='warning')
                 optional_params["Warnings"] = exc.message
         else:
             if editor_type == 'ckeditor':
                 # Here we remove the line feeds introduced by CKEditor (they
                 # have no meaning for the user) and replace the HTML line
                 # breaks by linefeeds, so that we are close to an input that
                 # would be done without the CKEditor. That's much better if a
                 # reply to a comment is made with a browser that does not
                 # support CKEditor.
                 note_body = note_body.replace('\n', '').replace('\r', '').replace('<br />', '\n')
             if not(db.save_note(uid, bskid, recid, note_title, note_body, reply_to)):
                 # TODO: The note could not be saved. DB problem?
                 pass
             else:
                 # TODO: inform about successful annotating.
                 pass
 
     (body, warnings, navtrail) = perform_request_display_public(uid=uid,
                                                                 selected_bskid=bskid,
                                                                 selected_recid=recid,
                                                                 optional_params=optional_params,
                                                                 of='hb',
                                                                 ln=CFG_SITE_LANG)
 
     if not warnings:
         body = warnings_html + body
 #        warnings = warnings_rights
 
     return (body, navtrail)
 
 #################################
 ### Display baskets and notes ###
 #################################
 def perform_request_display(uid,
                             selected_category=CFG_WEBBASKET_CATEGORIES['PRIVATE'],
                             selected_topic="",
                             selected_group_id=0,
                             selected_bskid=0,
                             selected_recid=0,
                             optional_params={},
                             of='hb',
                             ln=CFG_SITE_LANG):
     """Display all the baskets of given category, topic or group.
     @param uid: user id
     @param selected_category: selected category (see webbasket_config.py)
     @param selected_topic: # of selected topic to display baskets
     @param selected_group_id: id of group to display baskets
     @param ln: language"""
 
     _ = gettext_set_language(ln)
 
     warnings = []
     warnings_html = ""
 
     valid_category_choice = False
     selected_basket_info = []
     content = ""
     search_box = ""
 
     (of, of_warnings) = wash_of(of)
     if of_warnings:
         navtrail = create_webbasket_navtrail(uid, ln=ln)
         body = webbasket_templates.tmpl_warnings(of_warnings, ln)
         return (body, of_warnings, navtrail)
 
 
     (selected_category, category_warnings) = wash_category(selected_category)
     if not selected_category and category_warnings:
         if of == 'xm':
             return ("", None. None)
         navtrail = create_webbasket_navtrail(uid, ln=ln)
         body = webbasket_templates.tmpl_warnings(category_warnings, ln)
         return (body, category_warnings, navtrail)
 
     if selected_category == CFG_WEBBASKET_CATEGORIES['ALLPUBLIC']:
         if of == 'xm':
             return ("", None. None)
         # TODO: Send the correct title of the page as well.
         return perform_request_list_public_baskets(uid)
 
-    personal_info = db.get_all_personal_basket_ids_and_names_by_topic(uid)
+    personal_info = db.get_all_user_personal_basket_ids_by_topic(uid)
     personal_baskets_info = ()
+
     if personal_info and selected_category == CFG_WEBBASKET_CATEGORIES['PRIVATE']:
+        # Create a dictionary that has the valid topics for keys and the basket
+        # ids in each topic (string, ids separated by commas) as values.
+        personal_info_dict = {}
+        for personal_info_topic_and_bskids in personal_info:
+            personal_info_dict[personal_info_topic_and_bskids[0]] = map(int, personal_info_topic_and_bskids[1].split(','))
         valid_category_choice = True
         if selected_topic:
-            # (A) tuples parsing check
-            valid_topic_names = [personal_info_topic[0] for personal_info_topic in personal_info]
-            if selected_topic in valid_topic_names:
-            # (B) DB check
-            #if db.is_topic_valid(uid, selected_topic):
+            valid_selected_topic_p = False
+            # Validate the topic. Check if the selected topic is one of the keys
+            # in the dictionary. If it is valid then get some more info for that
+            # topic from the DB.
+            if selected_topic in personal_info_dict.keys():
                 personal_baskets_info = db.get_personal_baskets_info_for_topic(uid, selected_topic)
                 valid_selected_topic_p = True
-            else:
+            if not valid_selected_topic_p:
                 try:
                     raise InvenioWebBasketWarning(_('The selected topic does not exist or you do not have access to it.'))
                 except InvenioWebBasketWarning, exc:
                     register_exception(stream='warning')
                     warnings.append(exc.message)
                 #warnings.append('WRN_WEBBASKET_INVALID_OR_RESTRICTED_TOPIC')
                 warnings_html += webbasket_templates.tmpl_warnings(exc.message, ln)
                 valid_selected_topic_p = False
                 selected_topic = ""
         else:
             valid_selected_topic_p = True
+
         if valid_selected_topic_p and selected_bskid:
-            # (A) tuples parsing check
             if selected_topic:
-                valid_baskets = [eval(personal_info_topic[2] + ',') for personal_info_topic in personal_info
-                                 if personal_info_topic[0] == selected_topic]
+                valid_bskids = personal_info_dict[selected_topic]
             else:
-                valid_baskets = [eval(personal_info_topic[2] + ',') for personal_info_topic in personal_info]
-            valid_bskids = []
-            for valid_basket in valid_baskets:
-                valid_bskids.extend([valid_bskid[0] for valid_bskid in valid_basket])
+                valid_bskids = []
+                for valid_bskids_per_topic in personal_info_dict.values():
+                    valid_bskids.extend(valid_bskids_per_topic)
             if selected_bskid in valid_bskids:
-            # (B) DB check
-            #if db.is_personal_basket_valid(uid, selected_bskid):
                 if not selected_topic:
-                    # (A) tuples parsing check
-                    valid_baskets_dict = {}
-                    for personal_info_topic in personal_info:
-                        valid_baskets_dict[personal_info_topic[0]] = eval(personal_info_topic[2] + ',')
-                    for valid_basket in valid_baskets_dict.iteritems():
-                        if selected_bskid in [valid_bskid[0] for valid_bskid in valid_basket[1]]:
-                            selected_topic = valid_basket[0]
+                    for valid_topic in personal_info_dict.iterkeys():
+                        if selected_bskid in personal_info_dict[valid_topic]:
+                            selected_topic = valid_topic
                             break
-                    # (B) DB check
-                    #selected_topic = db.get_basket_topic(uid, selected_bskid)
-                    personal_baskets_info = db.get_personal_baskets_info_for_topic(uid, selected_topic)
+                personal_baskets_info = db.get_personal_baskets_info_for_topic(uid, selected_topic)
                 for personal_basket_info in personal_baskets_info:
                     if personal_basket_info[0] == selected_bskid:
                         selected_basket_info = list(personal_basket_info)
                         selected_basket_info.append(CFG_WEBBASKET_SHARE_LEVELS['MANAGE'])
                         break
             else:
                 try:
                     raise InvenioWebBasketWarning(_('The selected basket does not exist or you do not have access to it.'))
                 except InvenioWebBasketWarning, exc:
                     register_exception(stream='warning')
                     warnings.append(exc.message)
                 #warnings.append('WRN_WEBBASKET_INVALID_OR_RESTRICTED_BASKET')
                 warnings_html += webbasket_templates.tmpl_warnings(exc.message, ln)
                 selected_bskid = 0
         else:
             selected_bskid = 0
 
-    group_info = db.get_all_group_basket_ids_and_names_by_group(uid)
+    group_info = db.get_all_user_group_basket_ids_by_group(uid)
     group_baskets_info = ()
     selected_group_name = ""
+
     if group_info and selected_category == CFG_WEBBASKET_CATEGORIES['GROUP']:
+        # Create a dictionary that has the valid group as keys and the basket
+        # ids in each group (string, ids separated by commas) as values.
+        group_info_dict = {}
+        for group_info_group_and_bskids in group_info:
+            group_info_dict[group_info_group_and_bskids[0]] = (group_info_group_and_bskids[1], \
+                                                               map(int, group_info_group_and_bskids[2].split(',')))
         valid_category_choice = True
         if selected_group_id:
-            # (A) tuples parsing check
-            valid_group_ids = [group_info_group[0] for group_info_group in group_info]
-            if selected_group_id in valid_group_ids:
-            # (B) DB check
-            #if db.is_group_valid(uid, selected_group_id):
+            valid_selected_group_p = False
+            # Validate the group. Check if the selected group is one of the keys
+            # in the dictionary. If it is valid then get some more info for that
+            # group from the DB.
+            if selected_group_id in group_info_dict.keys():
+                selected_group_name = group_info_dict[selected_group_id][0]
                 group_baskets_info = db.get_group_baskets_info_for_group(selected_group_id)
-                # (A) tuples parsing
-                for group_info_group in group_info:
-                    if group_info_group[0] == selected_group_id:
-                        selected_group_name = group_info_group[1]
-                        break
-                # (B) DB
-                #selected_group_name = db.get_group_name(selected_group_id)
-                #if selected_group_name:
-                #    selected_group_name = selected_group_name[0][0]
                 valid_selected_group_p = True
-            else:
+            if not valid_selected_group_p:
                 try:
                     raise InvenioWebBasketWarning(_('The selected topic does not exist or you do not have access to it.'))
                 except InvenioWebBasketWarning, exc:
                     register_exception(stream='warning')
                     warnings.append(exc.message)
                 #warnings.append('WRN_WEBBASKET_INVALID_OR_RESTRICTED_GROUP')
                 warnings_html += webbasket_templates.tmpl_warnings(exc.message, ln)
                 selected_group_id = ""
                 valid_selected_group_p = False
         else:
             valid_selected_group_p = True
+
         if valid_selected_group_p and selected_bskid:
-            # (A) tuples parsing check
             if selected_group_id:
-                valid_baskets = [eval(group_info_group[3] + ',') for group_info_group in group_info
-                                 if group_info_group[0] == selected_group_id]
+                valid_bskids = group_info_dict[selected_group_id][1]
             else:
-                valid_baskets = [eval(group_info_group[3] + ',') for group_info_group in group_info]
-            valid_bskids = []
-            for valid_basket in valid_baskets:
-                valid_bskids.extend([valid_bskid[0] for valid_bskid in valid_basket])
+                valid_bskids = []
+                for group_and_valid_bskids_per_group in group_info_dict.values():
+                    valid_bskids_per_group = group_and_valid_bskids_per_group[1]
+                    valid_bskids.extend(valid_bskids_per_group)
             if selected_bskid in valid_bskids:
-            # (B) DB check
-            #if db.is_group_basket_valid(uid, selected_bskid):
                 if not selected_group_id:
-                    # (A) tuples parsing check
-                    valid_baskets_dict = {}
-                    for group_info_group in group_info:
-                        valid_baskets_dict[group_info_group[0]] = eval(group_info_group[3] + ',')
-                    for valid_basket in valid_baskets_dict.iteritems():
-                        if selected_bskid in [valid_bskid[0] for valid_bskid in valid_basket[1]]:
-                            selected_group_id = valid_basket[0]
+                    for valid_group_id in group_info_dict.iterkeys():
+                        if selected_bskid in group_info_dict[valid_group_id][1]:
+                            selected_group_id = valid_group_id
                             break
-                    # (B) DB check
-                    #selected_group_id = db.get_basket_group(uid, selected_bskid)
-                    # (A) tuples parsing
-                    for group_info_group in group_info:
-                        if group_info_group[0] == selected_group_id:
-                            selected_group_name = group_info_group[1]
-                            break
-                    # (B) DB
-                    #selected_group_name = db.get_group_name(selected_group_id)
-                    #if selected_group_name:
-                    #    selected_group_name = selected_group_name[0][0]
-                    group_baskets_info = db.get_group_baskets_info_for_group(selected_group_id)
+                selected_group_name = group_info_dict[selected_group_id][0]
+                group_baskets_info = db.get_group_baskets_info_for_group(selected_group_id)
                 for group_basket_info in group_baskets_info:
                     if group_basket_info[0] == selected_bskid:
                         selected_basket_info = list(group_basket_info)
                         # INFO: uncomment the two following lines to give MANAGE
                         # rights to the owner of the basket even when through
                         # the group view of the basket.
                         #if group_basket_info[7] == uid:
                         #    selected_basket_info[6] = CFG_WEBBASKET_SHARE_LEVELS['MANAGE']
                         selected_basket_info.pop(7)
                         break
             else:
                 try:
                     raise InvenioWebBasketWarning(_('The selected topic does not exist or you do not have access to it.'))
                 except InvenioWebBasketWarning, exc:
                     register_exception(stream='warning')
                     warnings.append(exc.message)
                 #warnings.append('WRN_WEBBASKET_INVALID_OR_RESTRICTED_BASKET')
                 warnings_html += webbasket_templates.tmpl_warnings(exc.message, ln)
                 selected_bskid = 0
         else:
             selected_bskid = 0
 
     public_info = db.get_all_external_basket_ids_and_names(uid)
     if public_info and selected_category == CFG_WEBBASKET_CATEGORIES['EXTERNAL']:
         valid_category_choice = True
         if selected_bskid:
             valid_bskids = [(valid_basket[0], valid_basket[3]) for valid_basket in public_info]
             if (selected_bskid, 0) in valid_bskids:
                 public_basket_info = db.get_external_basket_info(selected_bskid)
                 if public_basket_info:
                     selected_basket_info = list(public_basket_info[0])
             elif (selected_bskid, None) in valid_bskids:
                 try:
                     raise InvenioWebBasketWarning(_('The selected basket is no longer public.'))
                 except InvenioWebBasketWarning, exc:
                     register_exception(stream='warning')
                     warnings.append(exc.message)
                 #warnings.append('WRN_WEBBASKET_FORMER_PUBLIC_BASKET')
                 warnings_html += webbasket_templates.tmpl_warnings(exc.message, ln)
                 selected_bskid = 0
             else:
                 try:
                     raise InvenioWebBasketWarning(_('The selected basket does not exist or you do not have access to it.'))
                 except InvenioWebBasketWarning, exc:
                     register_exception(stream='warning')
                     warnings.append(exc.message)
                 #warnings.append('WRN_WEBBASKET_INVALID_OR_RESTRICTED_BASKET')
                 warnings_html += webbasket_templates.tmpl_warnings(exc.message, ln)
                 selected_bskid = 0
 
     if not valid_category_choice:
         if personal_info:
             selected_category = CFG_WEBBASKET_CATEGORIES['PRIVATE']
         elif group_info:
             selected_category = CFG_WEBBASKET_CATEGORIES['GROUP']
         elif public_info:
             selected_category = CFG_WEBBASKET_CATEGORIES['EXTERNAL']
         else:
             selected_category = CFG_WEBBASKET_CATEGORIES['ALLPUBLIC']
 
     if not of.startswith('x'):
         directory_box = webbasket_templates.tmpl_create_directory_box(selected_category,
                                                                       selected_topic,
                                                                       (selected_group_id, selected_group_name),
                                                                       selected_bskid,
                                                                       (personal_info, personal_baskets_info),
                                                                       (group_info, group_baskets_info),
                                                                       public_info,
                                                                       ln)
 
     if selected_basket_info:
         if selected_recid:
             (bskid, basket_name, last_update, dummy, nb_items, dummy, share_rights) = selected_basket_info
             (content, bsk_warnings) = __display_basket_single_item(bskid,
                                                                    basket_name,
                                                                    selected_recid,
                                                                    last_update,
                                                                    nb_items,
                                                                    share_rights,
                                                                    selected_category,
                                                                    selected_topic,
                                                                    selected_group_id,
                                                                    optional_params,
                                                                    of,
                                                                    ln)
         else:
             (bskid, basket_name, last_update, dummy, nb_items, dummy, share_rights) = selected_basket_info
             share_level = db.get_basket_share_level(bskid)
             if share_level:
                 share_level = share_level[0][0]
             else:
                 share_level = None
             if share_level == 0:
                 nb_subscribers = db.count_public_basket_subscribers(bskid)
             else:
                 nb_subscribers = None
 
             (content, bsk_warnings) = __display_basket(bskid,
                                                        basket_name,
                                                        last_update,
                                                        nb_items,
                                                        nb_subscribers,
                                                        share_rights,
                                                        share_level,
                                                        selected_category,
                                                        selected_topic,
                                                        selected_group_id,
                                                        of,
                                                        ln)
             warnings.extend(bsk_warnings)
 
         if not of.startswith('x'):
             warnings_html += webbasket_templates.tmpl_warnings(bsk_warnings, ln)
     else:
         if not of.startswith('x'):
             search_box = __create_search_box(uid=uid,
                                              category=selected_category,
                                              topic=selected_topic,
                                              grpid=selected_group_id,
                                              p="",
                                              n=1,
                                              ln=ln)
 
     if not of.startswith('x'):
         body = webbasket_templates.tmpl_display(directory_box, content, search_box)
         body = warnings_html + body
     else:
         body = content
 
     if not of.startswith('x'):
         navtrail = create_webbasket_navtrail(uid,
                                              category=selected_category,
                                              topic=selected_topic,
                                              group=selected_group_id,
                                              bskid=selected_bskid,
                                              ln=ln)
 
     if not of.startswith('x'):
         return (body, warnings, navtrail)
     else:
         return (body, None, None)
 
 def __display_basket(bskid,
                      basket_name,
                      last_update,
                      nb_items,
                      nb_subscribers,
                      share_rights,
                      share_level,
                      selected_category=CFG_WEBBASKET_CATEGORIES['PRIVATE'],
                      selected_topic="",
                      selected_group_id=0,
                      of="hb",
                      ln=CFG_SITE_LANG):
     """Private function. Display a basket giving its category and topic or group.
     @param share_rights: rights user has on basket
     @param share_level: None if basket is not shared,
                                 0 if public basket,
                                 > 0 if shared to usergroups but not public.
     @param selected_category: selected category (see webbasket_config.py)
     @param selected_topic: # of selected topic to display baskets
     @param selected_group_id: id of group to display baskets
     @param ln: language"""
 
     _ = gettext_set_language(ln)
 
     warnings = []
 
     nb_total_notes = 0
     last_note = _("N/A")
     records = []
     notes_dates = []
     #date_modification = convert_datetext_to_dategui(date_modification, ln)
     last_update = convert_datetext_to_dategui(last_update, ln)
 
     items = db.get_basket_content(bskid, of)
     external_recids = []
 
     for (recid, collection_id, nb_notes, last_note, ext_val, int_val, score) in items:
         notes_dates.append(convert_datetext_to_datestruct(last_note))
         last_note = convert_datetext_to_dategui(last_note, ln)
         colid = collection_id and collection_id or collection_id == 0 and -1 or 0
         val = ""
         nb_total_notes += nb_notes
         if recid < 0:
             if ext_val:
                 val = decompress(ext_val)
             else:
                 external_recids.append(recid)
         else:
             if int_val:
                 val = decompress(int_val)
             else:
                 val = format_record(recid, of, on_the_fly=True)
         ## external item (record): colid = positive integet
         ## external item (url): colid = -1
         ## local item (record): colid = 0
         records.append((recid, colid, nb_notes, last_note, val, score))
 
     if external_recids:
         external_records = format_external_records(external_recids, of)
 
         for external_record in external_records:
             for record in records:
                 if record[0] == -external_record[0]:
                     idx = records.index(record)
                     tuple_to_list = list(records.pop(idx))
                     tuple_to_list[4] = external_record[1]
                     records.insert(idx, tuple(tuple_to_list))
                     break
 
     if notes_dates:
         last_note = convert_datestruct_to_dategui(max(notes_dates), ln)
 
     if of == 'hb' or of.startswith('x'):
 
         body = webbasket_templates.tmpl_basket(bskid,
                                                basket_name,
                                                last_update,
                                                nb_items,
                                                nb_subscribers,
                                                (check_sufficient_rights(share_rights, CFG_WEBBASKET_SHARE_LEVELS['READITM']),
                                                 check_sufficient_rights(share_rights, CFG_WEBBASKET_SHARE_LEVELS['MANAGE']),
                                                 check_sufficient_rights(share_rights, CFG_WEBBASKET_SHARE_LEVELS['READCMT']),
                                                 check_sufficient_rights(share_rights, CFG_WEBBASKET_SHARE_LEVELS['ADDCMT']),
                                                 check_sufficient_rights(share_rights, CFG_WEBBASKET_SHARE_LEVELS['ADDITM']),
                                                 check_sufficient_rights(share_rights, CFG_WEBBASKET_SHARE_LEVELS['DELITM'])),
                                                nb_total_notes,
                                                share_level,
                                                selected_category,
                                                selected_topic,
                                                selected_group_id,
                                                records,
                                                of,
                                                ln)
     else:
         body = ""
         for rec in records:
             body +=  rec[4]
     return (body, warnings)
 
 def __display_basket_single_item(bskid,
                                  basket_name,
                                  recid,
                                  last_update,
                                  nb_items,
                                  share_rights,
                                  selected_category=CFG_WEBBASKET_CATEGORIES['PRIVATE'],
                                  selected_topic="",
                                  selected_group_id=0,
                                  optional_params={},
                                  of='hb',
                                  ln=CFG_SITE_LANG):
     """Private function. Display a basket giving its category and topic or group.
     @param share_rights: rights user has on basket
     @param selected_category: selected category (see webbasket_config.py)
     @param selected_topic: # of selected topic to display baskets
     @param selected_group_id: id of group to display baskets
     @param ln: language"""
 
     _ = gettext_set_language(ln)
 
     warnings = []
 
     last_note = _("N/A")
     notes_dates = []
     #date_modification = convert_datetext_to_dategui(date_modification, ln)
     last_update = convert_datetext_to_dategui(last_update, ln)
 
     item = db.get_basket_item(bskid, recid, of)
 
     if item:
         (recid, collection_id, nb_notes, last_note, ext_val, int_val, score) = item[0]
         previous_item_recid = item[1]
         next_item_recid = item[2]
         item_index = item[3]
     else:
         share_level = db.get_basket_share_level(bskid)
         if share_level:
             share_level = share_level[0][0]
         else:
             share_level = None
         if share_level == 0:
             nb_subscribers = db.count_public_basket_subscribers(bskid)
         else:
             nb_subscribers = None
         (content, bsk_warnings) = __display_basket(bskid,
                                                    basket_name,
                                                    last_update,
                                                    nb_items,
                                                    nb_subscribers,
                                                    share_rights,
                                                    share_level,
                                                    selected_category,
                                                    selected_topic,
                                                    selected_group_id,
                                                    of,
                                                    ln)
         try:
             raise InvenioWebBasketWarning(_('The selected item does not exist or you do not have access to it.'))
         except InvenioWebBasketWarning, exc:
             register_exception(stream='warning')
             bsk_warnings.append(exc.message)
         #bsk_warnings.append('WRN_WEBBASKET_INVALID_OR_RESTRICTED_ITEM')
         return (content, bsk_warnings)
 
     notes_dates.append(convert_datetext_to_datestruct(last_note))
     last_note = convert_datetext_to_dategui(last_note, ln)
     colid = collection_id and collection_id or collection_id == 0 and -1 or 0
     val = ""
     if recid < 0:
         if ext_val:
             val = decompress(ext_val)
         else:
             external_record = format_external_records([recid], of)
             val = external_record and external_record[0][1] or ""
     else:
         if int_val:
             val = decompress(int_val)
         else:
             val = format_record(recid, of, on_the_fly=True)
     item = (recid, colid, nb_notes, last_note, val, score)
 
     comments = db.get_notes(bskid, recid)
 
     if notes_dates:
         last_note = convert_datestruct_to_dategui(max(notes_dates), ln)
 
     body = webbasket_templates.tmpl_basket_single_item(bskid,
                                                basket_name,
                                                nb_items,
                                                (check_sufficient_rights(share_rights, CFG_WEBBASKET_SHARE_LEVELS['READITM']),
                                                 check_sufficient_rights(share_rights, CFG_WEBBASKET_SHARE_LEVELS['READCMT']),
                                                 check_sufficient_rights(share_rights, CFG_WEBBASKET_SHARE_LEVELS['ADDCMT']),
                                                 check_sufficient_rights(share_rights, CFG_WEBBASKET_SHARE_LEVELS['DELCMT'])),
                                                selected_category,
                                                selected_topic,
                                                selected_group_id,
                                                item, comments,
                                                previous_item_recid, next_item_recid, item_index,
                                                optional_params,
                                                of,
                                                ln)
     return (body, warnings)
 
 def perform_request_search(uid,
                            selected_category="",
                            selected_topic="",
                            selected_group_id=0,
                            p="",
                            b="",
                            n=0,
                            #format='xm',
                            ln=CFG_SITE_LANG):
     """Search the baskets...
     @param uid: user id
     @param category: selected category (see webbasket_config.py)
     @param selected_topic: # of selected topic to display baskets
     @param selected_group_id: id of group to display baskets
     @param ln: language"""
 
     _ = gettext_set_language(ln)
 
     body = ""
     #warnings = []
     warnings_html = ""
 
     (b_category, b_topic_or_grpid, b_warnings) = wash_b_search(b)
     # we extract the category from the washed b GET variable.
     # if a valid category was returned we use it as the selected category.
     if b_category:
         selected_category = b_category
         if selected_category == CFG_WEBBASKET_CATEGORIES['PRIVATE']:
             selected_topic = b_topic_or_grpid
         elif selected_category == CFG_WEBBASKET_CATEGORIES['GROUP']:
             selected_group_id = b_topic_or_grpid
     # if no category was returned and there were warnings it means there was a
     # bad input, send the warning to the user and return the page.
     elif b_warnings:
         navtrail = create_webbasket_navtrail(uid, search_baskets=True, ln=ln)
         body = webbasket_templates.tmpl_warnings(b_warnings, ln)
         return (body, navtrail)
     # if no category was returned and there were no warnings it means no category
     # was defined in the b GET variable. If the user has not defined a category
     # either using the category GET variable it means there is no category defined
     # whatsoever.
     elif not selected_category:
         selected_category = ""
     # finally, if no category was returned but the user has defined a category
     # using the category GET variable we extract the category after washing the
     # variable.
     else:
         (selected_category, category_warnings) = wash_category(selected_category)
         if not selected_category and category_warnings:
             navtrail = create_webbasket_navtrail(uid, search_baskets=True, ln=ln)
             body = webbasket_templates.tmpl_warnings(category_warnings, ln)
             return (body, navtrail)
 
     if selected_category == CFG_WEBBASKET_CATEGORIES['PRIVATE'] and selected_topic:
         (selected_topic, topic_warnings) = wash_topic(uid, selected_topic)
         if not selected_topic and topic_warnings:
             navtrail = create_webbasket_navtrail(uid, search_baskets=True, ln=ln)
             body = webbasket_templates.tmpl_warnings(topic_warnings, ln)
             return (body, navtrail)
 
     if selected_category == CFG_WEBBASKET_CATEGORIES['GROUP'] and selected_group_id:
         (selected_group_id, group_warnings) = wash_group(uid, selected_group_id)
         if not selected_group_id and group_warnings:
             navtrail = create_webbasket_navtrail(uid, search_baskets=True, ln=ln)
             body = webbasket_templates.tmpl_warnings(group_warnings, ln)
             return (body, navtrail)
 
     # IDEA: in case we pass an "action=search" GET variable we can use the
     # following bit to warn the user he's searching for an empty search pattern.
     #if action == "search" and not p:
     #    warnings_html += webbasket_templates.tmpl_warnings('WRN_WEBBASKET_NO_SEARCH_PATTERN', ln)
     #    perform_search = 0
 
     if p:
         # Let's set some initial values
         personal_search_results = None
         total_no_personal_search_results = 0
         group_search_results = None
         total_no_group_search_results = 0
         public_search_results = None
         total_no_public_search_results = 0
         all_public_search_results = None
         total_no_all_public_search_results = 0
         # Let's precalculate the local search resutls
         # and the pattern for the external search results
         local_search_results = search_unit(p)
 
         # How strict should the pattern be? Look for the exact word
         # (using word boundaries: \b) or is any substring enough?
 
         # not that strict:
         # since we remove the html markup before searching for the pattern we
         # can use a rather simple pattern here.
         # INFO: we choose a not so strict pattern, since there are issues with
         # word bounderies and utf-8 strings (ex. with greek that was tested)
         pattern = re.compile(r'%s' % (re.escape(p),), re.DOTALL + re.MULTILINE + re.IGNORECASE + re.UNICODE)
         #pattern = re.compile(r'%s(?!([^<]+)?>)' % (p,), re.DOTALL + re.MULTILINE + re.IGNORECASE + re.UNICODE)
 
         # strict:
         # since we remove the html markup before searching for the pattern we
         # can use a rather simple pattern here.
         #pattern = re.compile(r'\b%s\b' % (re.escape(p),), re.DOTALL + re.MULTILINE + re.IGNORECASE + re.UNICODE)
         #pattern = re.compile(r'%s\b(?!([^<]+)?>)' % (p,), re.DOTALL + re.MULTILINE + re.IGNORECASE + re.UNICODE)
 
         # TODO: All the external records are now saved automatically first in xml.
         # So, the search should be done on the "xm" formatted records in the database
         # and not the "hb" ones. (That is not the case for their comments though).
         # Records in xml in the database are stored escaped. It's then suggested
         # that the pattern is also escaped before we performed the search for more
         # consistent resutls. We could also use .replace("\n", "") to clean the
         # content (after the removal of html markup) from all the newline characters.
 
         # The search format for external records. This means in which format will
         # the external records be fetched from the database to be searched then.
         format = 'xm'
 
         ### Calculate the search results for the user's personal baskets ###
         if b.startswith("P") or not b:
             personal_search_results = {}
             personal_items = db.get_all_items_in_user_personal_baskets(uid, selected_topic, format)
             personal_local_items = personal_items[0]
             personal_external_items = personal_items[1]
             personal_external_items_xml_records = {}
 
             for local_info_per_basket in personal_local_items:
                 bskid       = local_info_per_basket[0]
                 basket_name = local_info_per_basket[1]
                 topic       = local_info_per_basket[2]
                 recid_list  = local_info_per_basket[3]
                 local_recids_per_basket = intbitset(map(int, recid_list.strip(',').split(',')))
                 intsec = local_search_results.intersection(local_recids_per_basket)
                 if intsec:
                     personal_search_results[bskid] = [basket_name, topic, len(intsec), list(intsec)]
                     total_no_personal_search_results += len(intsec)
 
             for external_info_per_basket in personal_external_items:
                 bskid       = external_info_per_basket[0]
                 basket_name = external_info_per_basket[1]
                 topic       = external_info_per_basket[2]
                 recid       = external_info_per_basket[3]
                 value       = external_info_per_basket[4]
                 xml_record  = decompress(value)
                 personal_external_items_xml_records[recid] = xml_record
                 text = remove_html_markup(xml_record)
                 #text = text.replace('\n', '')
                 result = pattern.search(text)
                 if result:
                     if personal_search_results.has_key(bskid):
                         personal_search_results[bskid][2] += 1
                         personal_search_results[bskid][3].append(recid)
                     else:
                         personal_search_results[bskid] = [basket_name, topic, 1, [recid]]
                     total_no_personal_search_results += 1
 
             if n:
                 personal_items_by_matching_notes = db.get_all_items_in_user_personal_baskets_by_matching_notes(uid, selected_topic, p)
                 for info_per_basket_by_matching_notes in personal_items_by_matching_notes:
                     bskid       = info_per_basket_by_matching_notes[0]
                     basket_name = info_per_basket_by_matching_notes[1]
                     topic       = info_per_basket_by_matching_notes[2]
                     recid_list  = info_per_basket_by_matching_notes[3]
                     recids_per_basket_by_matching_notes = set(map(int, recid_list.strip(',').split(',')))
                     if personal_search_results.has_key(bskid):
                         no_personal_search_results_per_basket_so_far = personal_search_results[bskid][2]
                         personal_search_results[bskid][3] = list(set(personal_search_results[bskid][3]).union(recids_per_basket_by_matching_notes))
                         personal_search_results[bskid][2] = len(personal_search_results[bskid][3])
                         total_no_personal_search_results += ( personal_search_results[bskid][2] - no_personal_search_results_per_basket_so_far )
                     else:
                         personal_search_results[bskid] = [basket_name, topic, len(recids_per_basket_by_matching_notes), list(recids_per_basket_by_matching_notes)]
                         total_no_personal_search_results += len(recids_per_basket_by_matching_notes)
 
             # For every found record: calculate the number of notes
             # and the HTML representation of the record.
             for bskid in personal_search_results.keys():
                 recids = personal_search_results[bskid][3]
                 number_of_notes_per_record = db.get_number_of_notes_per_record_in_basket(bskid, recids)
                 records = []
                 for recid_and_notes in number_of_notes_per_record:
                     recid = recid_and_notes[0]
                     number_of_notes = recid_and_notes[1]
                     if recid < 0:
                         xml_record = personal_external_items_xml_records[recid]
                         record_html = format_record(None, of='hwbsr', xml_record=xml_record)
                         records.append((recid, number_of_notes, record_html))
                     else:
                         record_html = format_record(recid, of='hwbsr', on_the_fly=True)
                         records.append((recid, number_of_notes, record_html))
                 personal_search_results[bskid][3] = records
 
         ### Calculate the search results for the user's group baskets ###
         if b.startswith("G") or not b:
             group_search_results = {}
             group_items = db.get_all_items_in_user_group_baskets(uid, selected_group_id, format)
             group_local_items = group_items[0]
             group_external_items = group_items[1]
             group_external_items_xml_records = {}
 
             for local_info_per_basket in group_local_items:
                 bskid       = local_info_per_basket[0]
                 basket_name = local_info_per_basket[1]
                 grpid       = local_info_per_basket[2]
                 group_name  = local_info_per_basket[3]
                 share_rights = local_info_per_basket[4]
                 recid_list  = local_info_per_basket[5]
                 local_recids_per_basket = intbitset(map(int, recid_list.strip(',').split(',')))
                 intsec = local_search_results.intersection(local_recids_per_basket)
                 if intsec:
                     share_rights_view_notes = check_sufficient_rights(share_rights, CFG_WEBBASKET_SHARE_LEVELS['READCMT'])
                     share_rights_add_notes  = check_sufficient_rights(share_rights, CFG_WEBBASKET_SHARE_LEVELS['ADDCMT'])
                     share_rights_notes = (share_rights_view_notes, share_rights_add_notes)
                     group_search_results[bskid] = [basket_name, grpid, group_name, share_rights_notes, len(intsec), list(intsec)]
                     total_no_group_search_results += len(intsec)
 
             for external_info_per_basket in group_external_items:
                 bskid       = external_info_per_basket[0]
                 basket_name = external_info_per_basket[1]
                 grpid       = external_info_per_basket[2]
                 group_name  = external_info_per_basket[3]
                 share_rights = external_info_per_basket[4]
                 recid       = external_info_per_basket[5]
                 value       = external_info_per_basket[6]
                 xml_record  = decompress(value)
                 group_external_items_xml_records[recid] = xml_record
                 text = remove_html_markup(xml_record)
                 #text = text.replace('\n', '')
                 result = pattern.search(text)
                 if result:
                     if group_search_results.has_key(bskid):
                         group_search_results[bskid][4] += 1
                         group_search_results[bskid][5].append(recid)
                     else:
                         share_rights_view_notes = check_sufficient_rights(share_rights, CFG_WEBBASKET_SHARE_LEVELS['READCMT'])
                         share_rights_add_notes  = check_sufficient_rights(share_rights, CFG_WEBBASKET_SHARE_LEVELS['ADDCMT'])
                         share_rights_notes = (share_rights_view_notes, share_rights_add_notes)
                         group_search_results[bskid] = [basket_name, grpid, group_name, share_rights_notes, 1, [recid]]
                     total_no_group_search_results += 1
 
             if n:
                 group_items_by_matching_notes = db.get_all_items_in_user_group_baskets_by_matching_notes(uid, selected_group_id, p)
                 for info_per_basket_by_matching_notes in group_items_by_matching_notes:
                     bskid       = info_per_basket_by_matching_notes[0]
                     basket_name = info_per_basket_by_matching_notes[1]
                     grpid       = info_per_basket_by_matching_notes[2]
                     group_name  = info_per_basket_by_matching_notes[3]
                     share_rights = info_per_basket_by_matching_notes[4]
                     recid_list  = info_per_basket_by_matching_notes[5]
                     recids_per_basket_by_matching_notes = set(map(int, recid_list.strip(',').split(',')))
                     if group_search_results.has_key(bskid):
                         no_group_search_results_per_basket_so_far = group_search_results[bskid][4]
                         group_search_results[bskid][5] = list(set(group_search_results[bskid][5]).union(recids_per_basket_by_matching_notes))
                         group_search_results[bskid][4] = len(group_search_results[bskid][5])
                         total_no_group_search_results += ( group_search_results[bskid][4] - no_group_search_results_per_basket_so_far )
                     else:
                         share_rights_view_notes = check_sufficient_rights(share_rights, CFG_WEBBASKET_SHARE_LEVELS['READCMT'])
                         share_rights_add_notes  = check_sufficient_rights(share_rights, CFG_WEBBASKET_SHARE_LEVELS['ADDCMT'])
                         share_rights_notes = (share_rights_view_notes, share_rights_add_notes)
                         group_search_results[bskid] = [basket_name, grpid, group_name, share_rights_notes, len(recids_per_basket_by_matching_notes), list(recids_per_basket_by_matching_notes)]
                         total_no_group_search_results += len(recids_per_basket_by_matching_notes)
 
             # For every found record: calculate the number of notes
             # and the HTML representation of the record.
             for bskid in group_search_results.keys():
                 recids = group_search_results[bskid][5]
                 number_of_notes_per_record = db.get_number_of_notes_per_record_in_basket(bskid, recids)
                 records = []
                 for recid_and_notes in number_of_notes_per_record:
                     recid = recid_and_notes[0]
                     number_of_notes = recid_and_notes[1]
                     if recid < 0:
                         xml_record = group_external_items_xml_records[recid]
                         record_html = format_record(None, of='hwbsr', xml_record=xml_record)
                         records.append((recid, number_of_notes, record_html))
                     else:
                         record_html = format_record(recid, of='hwbsr', on_the_fly=True)
                         records.append((recid, number_of_notes, record_html))
                 group_search_results[bskid][5] = records
 
         ### Calculate the search results for the user's public baskets ###
         if b.startswith("E") or not b:
             public_search_results = {}
             public_items = db.get_all_items_in_user_public_baskets(uid, format)
             public_local_items = public_items[0]
             public_external_items = public_items[1]
             public_external_items_xml_records = {}
 
             for local_info_per_basket in public_local_items:
                 bskid       = local_info_per_basket[0]
                 basket_name = local_info_per_basket[1]
                 share_rights = local_info_per_basket[2]
                 recid_list  = local_info_per_basket[3]
                 local_recids_per_basket = intbitset(map(int, recid_list.strip(',').split(',')))
                 intsec = local_search_results.intersection(local_recids_per_basket)
                 if intsec:
                     share_rights_view_notes = check_sufficient_rights(share_rights, CFG_WEBBASKET_SHARE_LEVELS['READCMT'])
                     share_rights_add_notes  = check_sufficient_rights(share_rights, CFG_WEBBASKET_SHARE_LEVELS['ADDCMT'])
                     share_rights_notes = (share_rights_view_notes, share_rights_add_notes)
                     public_search_results[bskid] = [basket_name, share_rights_notes, len(intsec), list(intsec)]
                     total_no_public_search_results += len(intsec)
 
             for external_info_per_basket in public_external_items:
                 bskid       = external_info_per_basket[0]
                 basket_name = external_info_per_basket[1]
                 share_rights = external_info_per_basket[2]
                 recid       = external_info_per_basket[3]
                 value       = external_info_per_basket[4]
                 xml_record  = decompress(value)
                 public_external_items_xml_records[recid] = xml_record
                 text = remove_html_markup(xml_record)
                 #text = text.replace('\n', '')
                 result = pattern.search(text)
                 if result:
                     if public_search_results.has_key(bskid):
                         public_search_results[bskid][2] += 1
                         public_search_results[bskid][3].append(recid)
                     else:
                         share_rights_view_notes = check_sufficient_rights(share_rights, CFG_WEBBASKET_SHARE_LEVELS['READCMT'])
                         share_rights_add_notes  = check_sufficient_rights(share_rights, CFG_WEBBASKET_SHARE_LEVELS['ADDCMT'])
                         share_rights_notes = (share_rights_view_notes, share_rights_add_notes)
                         public_search_results[bskid] = [basket_name, share_rights_notes, 1, [recid]]
                     total_no_public_search_results += 1
 
             if n:
                 public_items_by_matching_notes = db.get_all_items_in_user_public_baskets_by_matching_notes(uid, p)
                 for info_per_basket_by_matching_notes in public_items_by_matching_notes:
                     bskid       = info_per_basket_by_matching_notes[0]
                     basket_name = info_per_basket_by_matching_notes[1]
                     share_rights = info_per_basket_by_matching_notes[2]
                     recid_list  = info_per_basket_by_matching_notes[3]
                     recids_per_basket_by_matching_notes = set(map(int, recid_list.strip(',').split(',')))
                     if public_search_results.has_key(bskid):
                         no_public_search_results_per_basket_so_far = public_search_results[bskid][2]
                         public_search_results[bskid][3] = list(set(public_search_results[bskid][3]).union(recids_per_basket_by_matching_notes))
                         public_search_results[bskid][2] = len(public_search_results[bskid][3])
                         total_no_public_search_results += ( public_search_results[bskid][2] - no_public_search_results_per_basket_so_far )
                     else:
                         share_rights_view_notes = check_sufficient_rights(share_rights, CFG_WEBBASKET_SHARE_LEVELS['READCMT'])
                         share_rights_add_notes  = check_sufficient_rights(share_rights, CFG_WEBBASKET_SHARE_LEVELS['ADDCMT'])
                         share_rights_notes = (share_rights_view_notes, share_rights_add_notes)
                         public_search_results[bskid] = [basket_name, share_rights_notes, len(recids_per_basket_by_matching_notes), list(recids_per_basket_by_matching_notes)]
                         total_no_public_search_results += len(recids_per_basket_by_matching_notes)
 
             # For every found record: calculate the number of notes
             # and the HTML representation of the record.
             for bskid in public_search_results.keys():
                 recids = public_search_results[bskid][3]
                 number_of_notes_per_record = db.get_number_of_notes_per_record_in_basket(bskid, recids)
                 records = []
                 for recid_and_notes in number_of_notes_per_record:
                     recid = recid_and_notes[0]
                     number_of_notes = recid_and_notes[1]
                     if recid < 0:
                         xml_record = public_external_items_xml_records[recid]
                         record_html = format_record(None, of='hwbsr', xml_record=xml_record)
                         records.append((recid, number_of_notes, record_html))
                     else:
                         record_html = format_record(recid, of='hwbsr', on_the_fly=True)
                         records.append((recid, number_of_notes, record_html))
                 public_search_results[bskid][3] = records
 
         ### Calculate the search results for all the public baskets ###
         if b.startswith("A"):
             all_public_search_results = {}
             all_public_items = db.get_all_items_in_all_public_baskets(format)
             all_public_local_items = all_public_items[0]
             all_public_external_items = all_public_items[1]
             all_public_external_items_xml_records = {}
 
             for local_info_per_basket in all_public_local_items:
                 bskid       = local_info_per_basket[0]
                 basket_name = local_info_per_basket[1]
                 share_rights = local_info_per_basket[2]
                 recid_list  = local_info_per_basket[3]
                 local_recids_per_basket = intbitset(map(int, recid_list.strip(',').split(',')))
                 intsec = local_search_results.intersection(local_recids_per_basket)
                 if intsec:
                     share_rights_view_notes = check_sufficient_rights(share_rights, CFG_WEBBASKET_SHARE_LEVELS['READCMT'])
                     share_rights_add_notes  = check_sufficient_rights(share_rights, CFG_WEBBASKET_SHARE_LEVELS['ADDCMT'])
                     share_rights_notes = (share_rights_view_notes, share_rights_add_notes)
                     all_public_search_results[bskid] = [basket_name, share_rights_notes, len(intsec), list(intsec)]
                     total_no_all_public_search_results += len(intsec)
 
             for external_info_per_basket in all_public_external_items:
                 bskid       = external_info_per_basket[0]
                 basket_name = external_info_per_basket[1]
                 share_rights = external_info_per_basket[2]
                 recid       = external_info_per_basket[3]
                 value       = external_info_per_basket[4]
                 xml_record  = decompress(value)
                 all_public_external_items_xml_records[recid] = xml_record
                 text = remove_html_markup(xml_record)
                 #text = text.replace('\n', '')
                 result = pattern.search(text)
                 if result:
                     if all_public_search_results.has_key(bskid):
                         all_public_search_results[bskid][2] += 1
                         all_public_search_results[bskid][3].append(recid)
                     else:
                         share_rights_view_notes = check_sufficient_rights(share_rights, CFG_WEBBASKET_SHARE_LEVELS['READCMT'])
                         share_rights_add_notes  = check_sufficient_rights(share_rights, CFG_WEBBASKET_SHARE_LEVELS['ADDCMT'])
                         share_rights_notes = (share_rights_view_notes, share_rights_add_notes)
                         all_public_search_results[bskid] = [basket_name, share_rights_notes, 1, [recid]]
                     total_no_all_public_search_results += 1
 
             if n:
                 all_public_items_by_matching_notes = db.get_all_items_in_all_public_baskets_by_matching_notes(p)
                 for info_per_basket_by_matching_notes in all_public_items_by_matching_notes:
                     bskid       = info_per_basket_by_matching_notes[0]
                     basket_name = info_per_basket_by_matching_notes[1]
                     share_rights = info_per_basket_by_matching_notes[2]
                     recid_list  = info_per_basket_by_matching_notes[3]
                     recids_per_basket_by_matching_notes = set(map(int, recid_list.strip(',').split(',')))
                     if all_public_search_results.has_key(bskid):
                         no_all_public_search_results_per_basket_so_far = all_public_search_results[bskid][2]
                         all_public_search_results[bskid][3] = list(set(all_public_search_results[bskid][3]).union(recids_per_basket_by_matching_notes))
                         all_public_search_results[bskid][2] = len(all_public_search_results[bskid][3])
                         total_no_all_public_search_results += ( all_public_search_results[bskid][2] - no_all_public_search_results_per_basket_so_far )
                     else:
                         share_rights_view_notes = check_sufficient_rights(share_rights, CFG_WEBBASKET_SHARE_LEVELS['READCMT'])
                         share_rights_add_notes  = check_sufficient_rights(share_rights, CFG_WEBBASKET_SHARE_LEVELS['ADDCMT'])
                         share_rights_notes = (share_rights_view_notes, share_rights_add_notes)
                         all_public_search_results[bskid] = [basket_name, share_rights_notes, len(recids_per_basket_by_matching_notes), list(recids_per_basket_by_matching_notes)]
                         total_no_all_public_search_results += len(recids_per_basket_by_matching_notes)
 
             # For every found record: calculate the number of notes
             # and the HTML representation of the record.
             for bskid in all_public_search_results.keys():
                 recids = all_public_search_results[bskid][3]
                 number_of_notes_per_record = db.get_number_of_notes_per_record_in_basket(bskid, recids)
                 records = []
                 for recid_and_notes in number_of_notes_per_record:
                     recid = recid_and_notes[0]
                     number_of_notes = recid_and_notes[1]
                     if recid < 0:
                         xml_record = all_public_external_items_xml_records[recid]
                         record_html = format_record(None, of='hwbsr', xml_record=xml_record)
                         records.append((recid, number_of_notes, record_html))
                     else:
                         record_html = format_record(recid, of='hwbsr', on_the_fly=True)
                         records.append((recid, number_of_notes, record_html))
                 all_public_search_results[bskid][3] = records
 
         search_results_html = webbasket_templates.tmpl_search_results(personal_search_results,
                                                                       total_no_personal_search_results,
                                                                       group_search_results,
                                                                       total_no_group_search_results,
                                                                       public_search_results,
                                                                       total_no_public_search_results,
                                                                       all_public_search_results,
                                                                       total_no_all_public_search_results,
                                                                       ln)
     else:
         search_results_html = None
 
     search_box = __create_search_box(uid=uid,
                                      category=selected_category,
                                      topic=selected_topic,
                                      grpid=selected_group_id,
                                      p=p,
                                      n=n,
                                      ln=ln)
 
     body = webbasket_templates.tmpl_display(search_box=search_box,
                                             search_results=search_results_html)
     body = warnings_html + body
 
     navtrail = create_webbasket_navtrail(uid,
                                          search_baskets=True,
                                          ln=ln)
 
     return (body, navtrail)
 
 def perform_request_write_note(uid,
                                category=CFG_WEBBASKET_CATEGORIES['PRIVATE'],
                                topic="",
                                group_id=0,
                                bskid=0,
                                recid=0,
                                cmtid=0,
                                ln=CFG_SITE_LANG):
     """Display a note writing form
     @param uid: user id
     @param bskid: basket id
     @param recid: record id (comments are on a specific record in a specific basket)
     @param cmtid: if provided this comment is a reply to comment cmtid.
     @param category: selected category
     @param topic: selected topic
     @param group_id: selected group id
     @param ln: language
     """
     _ = gettext_set_language(ln)
 
     optional_params = {}
     #warnings_rights = []
     warnings_html = ""
 
     if not check_user_can_comment(uid, bskid):
         try:
             raise InvenioWebBasketWarning(_('You do not have permission to write notes to this item.'))
         except InvenioWebBasketWarning, exc:
             register_exception(stream='warning')
         #warnings_rights = ['WRN_WEBBASKET_RESTRICTED_WRITE_NOTES']
         warnings_html += webbasket_templates.tmpl_warnings(exc.message, ln)
     else:
         if cmtid and db.note_belongs_to_item_in_basket_p(cmtid, recid, bskid):
             optional_params["Add note"] = db.get_note(cmtid)
             optional_params["Reply to"] = cmtid
         elif cmtid:
             optional_params["Add note"] = ()
             try:
                 raise InvenioWebBasketWarning(_('The note you are quoting does not exist or you do not have access to it.'))
             except InvenioWebBasketWarning, exc:
                 register_exception(stream='warning')
                 optional_params["Warnings"] = exc.message
         else:
             optional_params["Add note"] = ()
 
     (body, warnings, navtrail) = perform_request_display(uid=uid,
                                                          selected_category=category,
                                                          selected_topic=topic,
                                                          selected_group_id=group_id,
                                                          selected_bskid=bskid,
                                                          selected_recid=recid,
                                                          optional_params=optional_params,
                                                          of='hb',
                                                          ln=CFG_SITE_LANG)
 
     if not warnings:
         body = warnings_html + body
         #warnings = warnings_rights
 
     return (body, navtrail)
 
 def perform_request_save_note(uid,
                               category=CFG_WEBBASKET_CATEGORIES['PRIVATE'],
                               topic="",
                               group_id=0,
                               bskid=0,
                               recid=0,
                               note_title="",
                               note_body="",
                               editor_type='textarea',
                               ln=CFG_SITE_LANG,
                               reply_to=None):
     """ Save a given comment if able to.
     @param uid: user id (int)
     @param bskid: basket id (int)
     @param recid: record id (int)
     @param title: title of comment (string)
     @param text: comment's body (string)
     @param ln: language (string)
     @param editor_type: the kind of editor/input used for the comment: 'textarea', 'ckeditor'
     @param reply_to: the id of the comment we are replying to
     """
     _ = gettext_set_language(ln)
 
     optional_params = {}
     #warnings_rights = []
     warnings_html = ""
 
     if not check_user_can_comment(uid, bskid):
         try:
             raise InvenioWebBasketWarning(_('You do not have permission to write notes to this item.'))
         except InvenioWebBasketWarning, exc:
             register_exception(stream='warning')
             #warnings_rights = exc.message
         #warnings_rights = ['WRN_WEBBASKET_RESTRICTED_WRITE_NOTES']
         warnings_html += webbasket_templates.tmpl_warnings(exc.message, ln)
     else:
         if not note_title or \
            ((not note_body and editor_type != 'ckeditor') or \
             (not remove_html_markup(note_body, '').replace('\n', '').replace('\r', '').strip() and editor_type == 'ckeditor')):
             optional_params["Incomplete note"] = (note_title, note_body)
             try:
                 raise InvenioWebBasketWarning(_('You must fill in both the subject and the body of the note.'))
             except InvenioWebBasketWarning, exc:
                 register_exception(stream='warning')
                 optional_params["Warnings"] = exc.message
         else:
             if editor_type == 'ckeditor':
                 # Here we remove the line feeds introduced by CKEditor (they
                 # have no meaning for the user) and replace the HTML line
                 # breaks by linefeeds, so that we are close to an input that
                 # would be done without the CKEditor. That's much better if a
                 # reply to a comment is made with a browser that does not
                 # support CKEditor.
                 note_body = note_body.replace('\n', '').replace('\r', '').replace('<br />', '\n')
             if not(db.save_note(uid, bskid, recid, note_title, note_body, reply_to)):
                 # TODO: The note could not be saved. DB problem?
                 pass
             else:
                 # TODO: inform about successful annotating.
                 pass
 
     (body, warnings, navtrail) = perform_request_display(uid=uid,
                                                          selected_category=category,
                                                          selected_topic=topic,
                                                          selected_group_id=group_id,
                                                          selected_bskid=bskid,
                                                          selected_recid=recid,
                                                          optional_params=optional_params,
                                                          of='hb',
                                                          ln=CFG_SITE_LANG)
 
     if not warnings:
         body = warnings_html + body
         #warnings = warnings_rights
 
     return (body, navtrail)
 
 def perform_request_delete_note(uid,
                                 category=CFG_WEBBASKET_CATEGORIES['PRIVATE'],
                                 topic="",
                                 group_id=0,
                                 bskid=0,
                                 recid=0,
                                 cmtid=0,
                                 ln=CFG_SITE_LANG):
     """Delete comment cmtid on record recid for basket bskid."""
 
     _ = gettext_set_language(ln)
 
     #warnings_notes = []
     warnings_html = ""
 
     if not __check_user_can_perform_action(uid, bskid, CFG_WEBBASKET_SHARE_LEVELS['DELCMT']):
         try:
             raise InvenioWebBasketWarning(_('You do not have permission to delete this note.'))
         except InvenioWebBasketWarning, exc:
             register_exception(stream='warning')
             #warnings_notes.append(exc.message)
         #warnings_notes.append('WRN_WEBBASKET_RESTRICTED_DELETE_NOTES')
         warnings_html += webbasket_templates.tmpl_warnings(exc.message, ln)
     else:
         if cmtid and db.note_belongs_to_item_in_basket_p(cmtid, recid, bskid):
             db.delete_note(bskid, recid, cmtid)
         else:
             try:
                 raise InvenioWebBasketWarning(_('The note you are deleting does not exist or you do not have access to it.'))
             except InvenioWebBasketWarning, exc:
                 register_exception(stream='warning')
                 #warnings_notes.append(exc.message)
             #warnings_notes.append('WRN_WEBBASKET_DELETE_INVALID_NOTE')
             warnings_html += webbasket_templates.tmpl_warnings(exc.message, ln)
 
     (body, warnings, navtrail) = perform_request_display(uid=uid,
                                                          selected_category=category,
                                                          selected_topic=topic,
                                                          selected_group_id=group_id,
                                                          selected_bskid=bskid,
                                                          selected_recid=recid,
                                                          of='hb',
                                                          ln=CFG_SITE_LANG)
 
     body = warnings_html + body
     #warnings.extend(warnings_notes)
 
     return (body, navtrail)
 
 def perform_request_add(uid,
                         recids=[],
                         category='',
                         bskid=0,
                         colid=0,
                         es_title='',
                         es_desc='',
                         es_url='',
                         note_body='',
                         editor_type='',
                         b='',
                         successful_add=False,
                         copy=False,
                         wait=False,
                         referer='',
                         ln=CFG_SITE_LANG):
     """Add records to baskets
     @param uid: user id
     @param recids: list of records to add
     @param colid: in case of external collections, the id of the collection the records belong to
     @param bskids: list of baskets to add records to. if not provided, will return a
                    page where user can select baskets
     @param es_title: the title of the external source
     @param es_desc: the description of the external source
     @param es_url: the url of the external source
     @param referer: URL of the referring page
     @param ln: language"""
 
     _ = gettext_set_language(ln)
 
     if successful_add:
         body = webbasket_templates.tmpl_add(recids=recids,
                                             category=category,
                                             bskid=bskid,
                                             colid=colid,
                                             successful_add=True,
                                             copy=copy,
                                             referer=referer,
                                             ln=ln)
         #warnings = []
         navtrail = create_webbasket_navtrail(uid,
                                              add_to_basket=True,
                                              ln=ln)
         return (body, navtrail)
 
     #warnings = []
     warnings_html = ""
 
     if type(recids) is not list:
         recids = [recids]
 
     validated_recids = []
 
     if colid == 0:
         # Local records
         for recid in recids:
             recid = int(recid)
             if recid > 0 and record_exists(recid) == 1:
                 validated_recids.append(recid)
             elif recid < 0 and copy:
                 # if we are copying a record, colid will always be 0 but we may
                 # still get negative recids when it comes to external items.
                 # In that case, we just skip the checking and add them directly
                 # to the validated_recids.
                 validated_recids.append(recid)
         user_info = collect_user_info(uid)
         recids_to_remove = []
         for recid in validated_recids:
             (auth_code, dummy) = check_user_can_view_record(user_info, recid)
             if auth_code:
                 # User is not authorized to view record.
                 # We should not remove items from the list while we parse it.
                 # Better store them in another list and in the end remove them.
                 #validated_recids.remove(recid)
                 recids_to_remove.append(recid)
                 try:
                     raise InvenioWebBasketWarning(_('Sorry, you do not have sufficient rights to add record #%i.') % recid)
                 except InvenioWebBasketWarning, exc:
                     register_exception(stream='warning')
                     #warnings.append(exc.message)
                 #warnings.append(('WRN_WEBBASKET_NO_RIGHTS_TO_ADD_THIS_RECORD', recid))
                 try:
                     raise InvenioWebBasketWarning(_('Some of the items were not added due to lack of sufficient rights.'))
                 except InvenioWebBasketWarning, exc:
                     register_exception(stream='warning')
                     warnings_html = webbasket_templates.tmpl_warnings(exc.message, ln)
                     #warnings_html = webbasket_templates.tmpl_warnings('WRN_WEBBASKET_NO_RIGHTS_TO_ADD_RECORDS', ln)
         for recid in recids_to_remove:
             validated_recids.remove(recid)
 
     elif colid > 0:
         # External records, no need to validate.
         validated_recids.extend(recids)
 
     elif colid == -1:
         # External source.
         es_warnings = []
         if not es_title:
             try:
                 raise InvenioWebBasketWarning(_('Please provide a title for the external source.'))
             except InvenioWebBasketWarning, exc:
                 register_exception(stream='warning')
                 es_warnings.append(exc.message)
         if not es_desc:
             try:
                 raise InvenioWebBasketWarning(_('Please provide a description for the external source.'))
             except InvenioWebBasketWarning, exc:
                 register_exception(stream='warning')
                 es_warnings.append(exc.message)
         if not es_url:
             try:
                 raise InvenioWebBasketWarning(_('Please provide a url for the external source.'))
             except InvenioWebBasketWarning, exc:
                 register_exception(stream='warning')
                 es_warnings.append(exc.message)
         else:
             (is_valid, status, dummy) = url_is_valid(es_url)
             if not is_valid:
                 if str(status).startswith('0'):
                     try:
                         raise InvenioWebBasketWarning(_('The url you have provided is not valid.'))
                     except InvenioWebBasketWarning, exc:
                         register_exception(stream='warning')
                         es_warnings.append(exc.message)
                     #es_warnings.append('WRN_WEBBASKET_NO_VALID_URL_0')
                 elif str(status).startswith('4'):
                     try:
                         raise InvenioWebBasketWarning(_('The url you have provided is not valid: The request contains bad syntax or cannot be fulfilled.'))
                     except InvenioWebBasketWarning, exc:
                         register_exception(stream='warning')
                         es_warnings.append(exc.message)
                     #es_warnings.append('WRN_WEBBASKET_NO_VALID_URL_4')
                 elif str(status).startswith('5'):
                     try:
                         raise InvenioWebBasketWarning(_('The url you have provided is not valid: The server failed to fulfil an apparently valid request.'))
                     except InvenioWebBasketWarning, exc:
                         register_exception(stream='warning')
                         es_warnings.append(exc.message)
                     #es_warnings.append('WRN_WEBBASKET_NO_VALID_URL_5')
             elif not (es_url.startswith("http://") or es_url.startswith("https://")):
                 es_url = "http://" + es_url
         if es_warnings:
             #warnings.extend(es_warnings)
             warnings_html += webbasket_templates.tmpl_warnings(es_warnings, ln)
 
     if not validated_recids:
         # in case there are no record ids select assume we want to add an
         # external source.
         colid = -1
 
     # This part of code is under the current circumstances never ran,
     # since if there no validated_recids, colid is set to -1.
     # IDEA: colid should by default (i.e. when not set) be -2 and when local
     # recids are added we should use the 0 value.
     #if not validated_recids and colid >= 0:
     #    warnings.append('WRN_WEBBASKET_NO_RECORD')
     #    body += webbasket_templates.tmpl_warnings(warnings, ln)
     #    if referer and not(referer.find(CFG_SITE_URL) == -1):
     #        body += webbasket_templates.tmpl_back_link(referer, ln)
     #    return (body, warnings)
 
     if b or (category and bskid):
         # if b was not defined we use category and bskid to construct it.
         if not b:
             b = category + "_" + str(bskid)
         # we extract the category and  the bskid from the washed b POST variable
         # or the constracted b variable from category and bskid.
         (category, b_bskid, b_warnings) = wash_b_add(b)
         # if there were warnings it means there was a bad input.
         # Send the warning to the user and return the page.
         if b_warnings:
             #warnings.extend(b_warnings)
             warnings_html += webbasket_templates.tmpl_warnings(b_warnings, ln)
         if not b_warnings:
             (bskid, b_warnings) = wash_bskid(uid, category, b_bskid)
             if b_warnings:
                 #warnings.extend(b_warnings)
                 warnings_html += webbasket_templates.tmpl_warnings(b_warnings, ln)
                 if not b_warnings:
                     if not(__check_user_can_perform_action(uid,
                                                            bskid,
                                                            CFG_WEBBASKET_SHARE_LEVELS['ADDITM'])):
                         try:
                             raise InvenioWebBasketWarning(_('Sorry, you do not have sufficient rights on this basket.'))
                         except InvenioWebBasketWarning, exc:
                             register_exception(stream='warning')
                             #warnings.append(exc.message)
                         #warnings.append('WRN_WEBBASKET_NO_RIGHTS')
                         warnings_html += webbasket_templates.tmpl_warnings(exc.message, ln)
         if not warnings_html:
             if ( colid >= 0 and not validated_recids ) or ( colid == -1 and ( not es_title or not es_desc or not es_url ) ):
                 try:
                     raise InvenioWebBasketWarning(_('No records to add.'))
                 except InvenioWebBasketWarning, exc:
                     register_exception(stream='warning')
                     #warnings.append(exc.message)
             if not warnings_html and not wait:
                 if colid == -1:
                     es_title = es_title
                     es_desc = nl2br(es_desc)
                 added_items = db.add_to_basket(uid, validated_recids, colid, bskid, es_title, es_desc, es_url)
                 if added_items:
                     if (note_body and editor_type != 'ckeditor') or \
                            (editor_type == 'ckeditor' and \
                             remove_html_markup(note_body, '').replace('\n', '').replace('\r', '').strip()):
                         if editor_type == 'ckeditor':
                             # Here we remove the line feeds introduced by CKEditor (they
                             # have no meaning for the user) and replace the HTML line
                             # breaks by linefeeds, so that we are close to an input that
                             # would be done without the CKEditor. That's much better if a
                             # reply to a comment is made with a browser that does not
                             # support CKEditor.
                             note_title = ''
                             note_body = note_body.replace('\n', '').replace('\r', '').replace('<br />', '\n')
                         else:
                             note_title = ''
                         for recid in added_items:
                             if not(db.save_note(uid, bskid, recid, note_title, note_body, reply_to=None)):
                                 # TODO: The note could not be saved. DB problem?
                                 pass
                     if colid > 0:
                         format_external_records(added_items, of="xm")
                     return perform_request_add(uid=uid,
                                                recids=recids,
                                                category=category,
                                                bskid=bskid,
                                                colid=colid,
                                                successful_add=True,
                                                copy=copy,
                                                referer=referer)
                 else:
                     try:
                         raise InvenioWebBasketWarning(_('Cannot add items to the selected basket. Invalid parameters.'))
                     except InvenioWebBasketWarning, exc:
                         register_exception(stream='warning')
                         #warnings.append(exc.message)
                     #warnings.append('WRN_WEBBASKET_INVALID_ADD_TO_PARAMETERS')
                     warnings_html += webbasket_templates.tmpl_warnings(exc.message, ln)
 
-    personal_basket_list = db.get_all_personal_basket_ids_and_names_by_topic_for_add_to_list(uid)
-    group_basket_list = db.get_all_group_basket_ids_and_names_by_group_for_add_to_list(uid)
+    personal_basket_list = db.get_all_user_personal_basket_ids_by_topic(uid)
+    group_basket_list = db.get_all_user_group_basket_ids_by_group_with_add_rights(uid)
     if not personal_basket_list and not group_basket_list:
-        bskid = db.create_basket(uid=uid, basket_name="Untitled basket", topic="Untitled topic")
+        bskid = db.create_basket(uid=uid, basket_name=_('Untitled basket'), topic=_('Untitled topic'))
         try:
             raise InvenioWebBasketWarning(_('A default topic and basket have been automatically created. Edit them to rename them as you see fit.'))
         except InvenioWebBasketWarning, exc:
             register_exception(stream='warning')
             #warnings.append(exc.message)
         #warnings.append('WRN_WEBBASKET_DEFAULT_TOPIC_AND_BASKET')
         warnings_html += webbasket_templates.tmpl_warnings(exc.message, ln)
         if colid >= 0 and validated_recids:
             (body, navtrail) = perform_request_add(uid=uid,
                                                    recids=validated_recids,
                                                    category=CFG_WEBBASKET_CATEGORIES['PRIVATE'],
                                                    bskid=bskid,
                                                    colid=colid,
                                                    referer=referer,
                                                    ln=ln)
             body = warnings_html + body
             return (body, navtrail)
         else:
-            personal_basket_list = db.get_all_personal_basket_ids_and_names_by_topic_for_add_to_list(uid)
+            personal_basket_list = db.get_all_user_personal_basket_ids_by_topic(uid)
 
     body = webbasket_templates.tmpl_add(recids=recids,
                                         category=category,
                                         bskid=bskid,
                                         colid=colid,
                                         es_title=es_title,
                                         es_desc=es_desc,
                                         es_url=es_url,
                                         note_body=note_body,
                                         personal_basket_list=personal_basket_list,
                                         group_basket_list=group_basket_list,
                                         copy=copy,
                                         referer=referer,
                                         ln=ln)
 
     body = warnings_html + body
 
     navtrail = create_webbasket_navtrail(uid,
                                          add_to_basket=True,
                                          ln=ln)
 
     return (body, navtrail)
 
 def perform_request_delete(uid, bskid, confirmed=0,
                            category=CFG_WEBBASKET_CATEGORIES['PRIVATE'],
                            selected_topic="", selected_group_id=0,
                            ln=CFG_SITE_LANG):
     """Delete a given basket.
     @param uid: user id (user has to be owner of this basket)
     @param bskid: basket id
     @param confirmed: if 0 will return a confirmation page; if 1 will delete basket.
     @param category: category currently displayed
     @param selected_topic: topic currently displayed
     @param selected_group_id: if category is group, id of the group currently displayed
     @param ln: language"""
 
     _ = gettext_set_language(ln)
 
     body = ''
     #warnings = []
     if not(db.check_user_owns_baskets(uid, [bskid])):
         try:
             raise InvenioWebBasketWarning(_('Sorry, you do not have sufficient rights on this basket.'))
         except InvenioWebBasketWarning, exc:
             register_exception(stream='warning')
             #warnings.append(exc.message)
         #warnings.append(('WRN_WEBBASKET_NO_RIGHTS',))
         return body
     if confirmed:
         if not db.delete_basket(bskid):
             # TODO: The item was not deleted. DB problem?
             pass
     else:
         body = webbasket_templates.tmpl_confirm_delete(bskid,
                                                        db.count_subscribers(uid, bskid),
                                                        category,
                                                        selected_topic, selected_group_id,
                                                        ln)
     return body
 
 def delete_record(uid, bskid, recid):
     """Delete a given record in a given basket.
     @param uid: user id (user has to have sufficient rights on basket
     @param bskid: basket id
     @param recid: record id
     """
     if __check_user_can_perform_action(uid,
                                        bskid,
                                        CFG_WEBBASKET_SHARE_LEVELS['DELITM']):
         db.delete_item(bskid, recid)
 
 def move_record(uid, bskid, recid, direction):
     """Move a record up or down in a basket (change score).
     @param uid: user id (user has to have manage rights over this basket)
     @param bskid: basket id
     @param recid: record we want to move
     @param direction: CFG_WEBBASKET_ACTIONS['UP'] or CFG_WEBBASKET_ACTIONS['DOWN']
     """
     if __check_user_can_perform_action(uid,
                                        bskid,
                                        CFG_WEBBASKET_SHARE_LEVELS['MANAGE']):
         db.move_item(bskid, recid, direction)
 
 def perform_request_edit(uid, bskid, topic="", new_name='',
                          new_topic = '', new_topic_name='',
                          groups=[], external='',
                          ln=CFG_SITE_LANG):
     """Interface for management of basket. If names, groups or external is
      provided, will save new rights into database, else will provide interface.
     @param uid: user id (user has to have sufficient rights on this basket
     @param bskid: basket id to change rights on
     @param topic: topic currently used (int)
     @param new_name: new name of basket
     @param new_topic: topic in which to move basket (int),
                       new_topic_name must be left blank
     @param new_topic_name: new topic in which to move basket
                            (will overwrite param new_topic)
     @param groups: list of strings formed in this way: group_id + '_' + rights
     @param external: rights for everybody (can be 'NO')
     @param ln: language
     """
     body = ''
     #warnings = []
 
     # TODO: external rights must be washed, it can only be one of the following:
     # NO, READITM, READCMT, ADDCMT
     _ = gettext_set_language(ln)
 
     rights = db.get_max_user_rights_on_basket(uid, bskid)
     if rights != CFG_WEBBASKET_SHARE_LEVELS['MANAGE']:
         try:
             raise InvenioWebBasketWarning(_('Sorry, you do not have sufficient rights on this basket.'))
         except InvenioWebBasketWarning, exc:
             register_exception(stream='warning')
             #warnings.append(exc.message)
         #warnings.append(('WRN_WEBBASKET_NO_RIGHTS',))
         return body
     bsk_name = db.get_basket_name(bskid)
     if not(groups) and not(external) and not(new_name) and not(new_topic) and not(new_topic_name):
         # display interface
         topics = map(lambda x: x[0], db.get_personal_topics_infos(uid))
         groups_rights = db.get_groups_subscribing_to_basket(bskid)
         external_rights = ''
         if groups_rights and groups_rights[0][0] == 0:
             external_rights = groups_rights[0][2]
             groups_rights = groups_rights[1:]
         display_delete = db.check_user_owns_baskets(uid, bskid)
         display_general = display_delete
         if isGuestUser(uid):
             display_sharing = 0
         else:
             display_sharing = 1
         body = webbasket_templates.tmpl_edit(bskid=bskid, bsk_name=bsk_name,
                                              display_general=display_general,
                                              topics=topics, topic=topic,
                                              display_delete=display_delete,
                                              display_sharing=display_sharing,
                                              groups_rights=groups_rights,
                                              external_rights=external_rights,
                                              ln=ln)
     else:
         out_groups = {}
         if len(groups):
             for group in groups:
                 (group_id, group_rights) = group.split('_')
                 out_groups[group_id] = group_rights
         out_groups['0'] = external
         if not(isGuestUser(uid)):
             db.update_rights(bskid, out_groups)
         if new_name != bsk_name:
             db.rename_basket(bskid, new_name)
         if new_topic_name:
             db.move_baskets_to_topic(uid, bskid, new_topic_name)
         elif not (new_topic == "-1" or new_topic == topic):
             if db.check_user_owns_baskets(uid, bskid):
                 topics = map(lambda x: x[0], db.get_personal_topics_infos(uid))
                 if new_topic in topics:
                     new_topic_name = new_topic
                     db.move_baskets_to_topic(uid, bskid, new_topic_name)
                 else:
                     # TODO: inform the admin
                     #errors.append(('ERR_WEBBASKET_DB_ERROR'))
                     pass
             else:
                 topic = ""
             #warnings.append(('ERR_WEBBASKET_NOT_OWNER'))
     return body
 
 def perform_request_edit_topic(uid, topic='', new_name='', ln=CFG_SITE_LANG):
     """Interface for editing of topic.
     @param uid: user id (user has to have sufficient rights on this basket
     @param topic: topic to be edited
     @param new_name: new name of topic
     @param ln: language
     """
     body = ''
     #warnings = []
 
     #rights = db.get_max_user_rights_on_basket(uid, bskid)
     #if rights != CFG_WEBBASKET_SHARE_LEVELS['MANAGE']:
     #    errors.append(('ERR_WEBBASKET_NO_RIGHTS',))
     #    return (body, errors, warnings)
     if not(new_name):
         # display interface
         #display_delete = db.check_user_owns_baskets(uid, bskid)
         #display_general = display_delete
         #if isGuestUser(uid):
             #display_sharing = 0
         #else:
             #display_sharing = 1
         display_general = True
         display_delete = True
         body = webbasket_templates.tmpl_edit_topic(display_general=display_general, topic=topic,
                                                    display_delete=display_delete, ln=ln)
     else:
         if cgi.escape(new_name, True) != cgi.escape(topic, True):
             db.rename_topic(uid, topic, new_name)
     return body
 
 def perform_request_add_group(uid, bskid, topic="", group_id=0, ln=CFG_SITE_LANG):
     """If group id is specified, share basket bskid to this group with
     READITM rights;
     else return a page for selection of a group.
     @param uid: user id (selection only of groups user is member of)
     @param bskid: basket id
     @param topic: topic currently displayed
     @param group_id: id of group to share basket to
     @param ln: language
     """
     if group_id:
         db.share_basket_with_group(bskid,
                                    group_id,
                                    CFG_WEBBASKET_SHARE_LEVELS['READITM'])
     else:
         groups = db.get_groups_user_member_of(uid)
         body = webbasket_templates.tmpl_add_group(bskid, topic, groups, ln)
         return body
 
 def perform_request_create_basket(req, uid,
                                   new_basket_name='',
                                   new_topic_name='', create_in_topic="-1",
                                   topic="-1",
                                   recids=[],
                                   colid=-1,
                                   es_title='',
                                   es_desc='',
                                   es_url='',
                                   ln=CFG_SITE_LANG):
     """if new_basket_name and topic infos are given create a basket and return topic number,
     else return body with warnings of basket creation form.
     @param req: request object for obtaining URL of the referring page
     @param uid: user id (int)
     @param new_basket_name: name of the basket to create (str)
     @param new_topic_name: name of new topic to create new basket in (str)
     @param create_in_topic: identification number of topic to create new basket in (int)
     @param topic: topic to preselect on the creation form.
     @pram ln: language
     """
     warnings = []
     warnings_html = ""
     _ = gettext_set_language(ln)
 
     if new_basket_name and (new_topic_name or create_in_topic != "-1"):
         #topics_infos = map(lambda x: x[0], db.get_personal_topics_infos(uid))
         new_topic_name = new_topic_name.strip()
         if new_topic_name:
             topic = new_topic_name
         else:
             topic = create_in_topic
         bskid = db.create_basket(uid, new_basket_name, topic)
         #topics = map(lambda x: x[0], topics_infos)
         return (bskid, topic)
     else:
         referer = get_referer(req) # URL of the referring page
         url = CFG_SITE_URL + '/yourbaskets/create_basket'
         import string
         if string.find(referer, url) == 0:
             if not new_basket_name:
                 try:
                     raise InvenioWebBasketWarning(_('Please provide a name for the new basket.'))
                 except InvenioWebBasketWarning, exc:
                     register_exception(stream='warning', req=req)
                     warnings.append(exc.message)
             if (not new_topic_name and create_in_topic == "-1"):
                 try:
                     raise InvenioWebBasketWarning(_('Please select an existing topic or create a new one.'))
                 except InvenioWebBasketWarning, exc:
                     register_exception(stream='warning', req=req)
                     warnings.append(exc.message)
 
         topics = map(lambda x: x[0], db.get_personal_topics_infos(uid))
         if topic in topics:
             create_in_topic = topic
         body = webbasket_templates.tmpl_create_basket(new_basket_name,
                                                       new_topic_name,
                                                       create_in_topic,
                                                       topics,
                                                       recids,
                                                       colid,
                                                       es_title,
                                                       es_desc,
                                                       es_url,
                                                       ln)
         if warnings:
             warnings_html += webbasket_templates.tmpl_warnings(warnings, ln)
             body = warnings_html + body
         return body
 
 def perform_request_subscribe(uid,
                               bskid,
                               ln=CFG_SITE_LANG):
     """Subscribes user to the given public basket.
     Returns warnings if there were any."""
     _ = gettext_set_language(ln)
 
     #warnings = []
     warnings_html = ""
 
     if db.is_basket_public(bskid):
         if not db.subscribe(uid, bskid):
             try:
                 raise InvenioWebBasketWarning(_('You cannot subscribe to this basket, you are the either owner or you have already subscribed.'))
             except InvenioWebBasketWarning, exc:
                 register_exception(stream='warning')
                 #warnings.append(exc.message)
             #warnings.append('WRN_WEBBASKET_CAN_NOT_SUBSCRIBE')
             warnings_html += webbasket_templates.tmpl_warnings(exc.message, ln)
     else:
         try:
             raise InvenioWebBasketWarning(_('The selected public basket does not exist or you do not have access to it.'))
         except InvenioWebBasketWarning, exc:
             register_exception(stream='warning')
             #warnings.append(exc.message)
         #warnings.append('WRN_WEBBASKET_INVALID_OR_RESTRICTED_PUBLIC_BASKET')
         warnings_html += webbasket_templates.tmpl_warnings(exc.message, ln)
 
     return warnings_html
 
 def perform_request_unsubscribe(uid,
                                 bskid,
                                 ln=CFG_SITE_LANG):
     """Unsubscribes user from the given public basket.
     Returns warnings if there were any."""
     _ = gettext_set_language(ln)
 
     #warnings = []
     warnings_html = ""
 
     if db.is_basket_public(bskid):
         if not db.unsubscribe(uid, bskid):
             try:
                 raise InvenioWebBasketWarning(_('You cannot unsubscribe from this basket, you are the either owner or you have already unsubscribed.'))
             except InvenioWebBasketWarning, exc:
                 register_exception(stream='warning')
                 #warnings.append(exc.message)
             #warnings.append('WRN_WEBBASKET_CAN_NOT_UNSUBSCRIBE')
             warnings_html += webbasket_templates.tmpl_warnings(exc.message, ln)
     else:
         try:
             raise InvenioWebBasketWarning(_('The selected public basket does not exist or you do not have access to it.'))
         except InvenioWebBasketWarning, exc:
             register_exception(stream='warning')
             #warnings.append(exc.message)
         #warnings.append('WRN_WEBBASKET_INVALID_OR_RESTRICTED_PUBLIC_BASKET')
         warnings_html += webbasket_templates.tmpl_warnings(exc.message, ln)
 
     return warnings_html
 
 def check_user_can_comment(uid, bskid):
     """ Private function. check if a user can comment """
     min_right = CFG_WEBBASKET_SHARE_LEVELS['ADDCMT']
     rights = db.get_max_user_rights_on_basket(uid, bskid)
     if rights:
         if CFG_WEBBASKET_SHARE_LEVELS_ORDERED.index(rights) >= CFG_WEBBASKET_SHARE_LEVELS_ORDERED.index(min_right):
             return 1
     return 0
 
 def __check_user_can_perform_action(uid, bskid, rights):
     """ Private function, check if a user has sufficient rights"""
     min_right = rights
     rights = db.get_max_user_rights_on_basket(uid, bskid)
     if rights:
         if CFG_WEBBASKET_SHARE_LEVELS_ORDERED.index(rights) >= CFG_WEBBASKET_SHARE_LEVELS_ORDERED.index(min_right):
             return 1
     return 0
 
 def check_sufficient_rights(rights_user_has, rights_needed):
     """Private function, check if the rights are sufficient."""
     try:
         out = CFG_WEBBASKET_SHARE_LEVELS_ORDERED.index(rights_user_has) >= \
               CFG_WEBBASKET_SHARE_LEVELS_ORDERED.index(rights_needed)
     except ValueError:
         out = 0
     return out
 
 def can_add_notes_to_public_basket_p(bskid):
     """ Private function. Checks if notes can be added to the given public basket."""
 
     min_right = CFG_WEBBASKET_SHARE_LEVELS['ADDCMT']
     rights = db.get_rights_on_public_basket(bskid)
     if rights:
         if CFG_WEBBASKET_SHARE_LEVELS_ORDERED.index(rights[0][0]) >= CFG_WEBBASKET_SHARE_LEVELS_ORDERED.index(min_right):
             return True
     return False
 
 def create_guest_warning_box(ln=CFG_SITE_LANG):
     """return a warning message about logging into system"""
     return webbasket_templates.tmpl_create_guest_warning_box(ln)
 
 def create_personal_baskets_selection_box(uid,
                                           html_select_box_name='baskets',
                                           selected_bskid=None,
                                           ln=CFG_SITE_LANG):
     """Return HTML box for basket selection. Only for personal baskets.
     @param uid: user id
     @param html_select_box_name: name used in html form
     @param selected_bskid: basket currently selected
     @param ln: language
     """
     baskets = db.get_all_personal_baskets_names(uid)
     return webbasket_templates.tmpl_personal_baskets_selection_box(
                                         baskets,
                                         html_select_box_name,
                                         selected_bskid,
                                         ln)
 
 def create_basket_navtrail(uid,
                            category=CFG_WEBBASKET_CATEGORIES['PRIVATE'],
                            topic="", group=0,
                            bskid=0, ln=CFG_SITE_LANG):
     """display navtrail for basket navigation.
     @param uid: user id (int)
     @param category: selected category (see CFG_WEBBASKET_CATEGORIES)
     @param topic: selected topic if personal baskets
     @param group: selected group id for displaying (int)
     @param bskid: basket id (int)
     @param ln: language"""
     _ = gettext_set_language(ln)
     out = ''
     if category == CFG_WEBBASKET_CATEGORIES['PRIVATE']:
-        out += ' &gt; <a class="navtrail" href="%s/yourbaskets/display?%s">'\
-               '%s</a>'
-        out %= (CFG_SITE_URL,
-                'category=' + category + '&amp;ln=' + ln,
-                _("Personal baskets"))
+        category_html = """ &gt; <a class="navtrail" href="%s/yourbaskets/display?%s">%s</a>""" % \
+                        (CFG_SITE_URL,
+                         'category=' + category + '&amp;ln=' + ln,
+                         _("Personal baskets"))
+        out += category_html
+
         topics = map(lambda x: x[0], db.get_personal_topics_infos(uid))
         if topic in topics:
-            out += ' &gt; '
-            out += '<a class="navtrail" href="%s/yourbaskets/display?%s">'\
-                   '%s</a>'
-            out %= (CFG_SITE_URL,
-                    'category=' + category + '&amp;topic=' + \
-                                  topic + '&amp;ln=' + ln,
-                    cgi.escape(topic))
+            topic_html = """ &gt; <a class="navtrail" href="%s/yourbaskets/display?%s">%s</a>""" % \
+                         (CFG_SITE_URL,
+                          'category=' + category + '&amp;topic=' + \
+                                    urllib.quote(topic) + '&amp;ln=' + ln,
+                          cgi.escape(topic))
+            out += topic_html
+
             if bskid:
                 basket = db.get_public_basket_infos(bskid)
                 if basket:
-                    out += ' &gt; '
-                    out += '<a class="navtrail" href="%s/yourbaskets/display'\
-                           '?%s">%s</a>'
-                    out %= (CFG_SITE_URL,
-                            'category=' + category + '&amp;topic=' + \
-                            topic + '&amp;ln=' + ln + '#bsk' + str(bskid),
-                            cgi.escape(basket[1]))
+                    basket_html = """ &gt; <a class="navtrail" href="%s/yourbaskets/display?%s">%s</a>""" % \
+                                  (CFG_SITE_URL,
+                                   'category=' + category + '&amp;topic=' + \
+                                             urllib.quote(topic) + '&amp;ln=' + ln + '#bsk' + str(bskid),
+                                   cgi.escape(basket[1]))
+                    out += basket_html
 
     elif category == CFG_WEBBASKET_CATEGORIES['GROUP']:
-        out += ' &gt; <a class="navtrail" href="%s/yourbaskets/display?%s">'\
-               '%s</a>'
-        out %= (CFG_SITE_URL, 'category=' + category + '&amp;ln=' + ln, _("Group baskets"))
+        category_html = """ &gt; <a class="navtrail" href="%s/yourbaskets/display?%s">%s</a>""" % \
+                        (CFG_SITE_URL,
+                         'category=' + category + '&amp;ln=' + ln,
+                         _("Group baskets"))
+        out += category_html
+
         groups = db.get_group_infos(uid)
         if group:
             groups = filter(lambda x: x[0] == group, groups)
         if len(groups):
-            out += ' &gt; '
-            out += '<a class="navtrail" href="%s/yourbaskets/display?%s">%s</a>'
-            out %= (CFG_SITE_URL,
-                    'category=' + category + '&amp;group=' + \
-                              str(group) + '&amp;ln=' + ln,
-                    cgi.escape(groups[0][1]))
+            group_html = """ &gt; <a class="navtrail" href="%s/yourbaskets/display?%s">%s</a>""" % \
+                         (CFG_SITE_URL,
+                          'category=' + category + '&amp;group=' + \
+                                    str(group) + '&amp;ln=' + ln,
+                          cgi.escape(groups[0][1]))
+            out += group_html
+
             if bskid:
                 basket = db.get_public_basket_infos(bskid)
                 if basket:
-                    out += ' &gt; '
-                    out += '<a class="navtrail" href="%s/yourbaskets/display?'\
-                           '%s">%s</a>'
-                    out %= (CFG_SITE_URL,
-                            'category=' + category + '&amp;group=' + \
-                            str(group) + '&amp;ln=' + ln + '#bsk' + str(bskid),
-                            cgi.escape(basket[1]))
+                    basket_html = """ &gt; <a class="navtrail" href="%s/yourbaskets/display?%s">%s</a>""" % \
+                                  (CFG_SITE_URL,
+                                   'category=' + category + '&amp;group=' + \
+                                             str(group) + '&amp;ln=' + ln + '#bsk' + str(bskid),
+                                   cgi.escape(basket[1]))
+                    out += basket_html
+
     elif category == CFG_WEBBASKET_CATEGORIES['EXTERNAL']:
-        out += ' &gt; <a class="navtrail" href="%s/yourbaskets/display?%s">'\
-               '%s</a>'
-        out %= (CFG_SITE_URL,
-                'category=' + category + '&amp;ln=' + ln,
-                _("Others' baskets"))
+        category_html = """ &gt; <a class="navtrail" href="%s/yourbaskets/display?%s">%s</a>""" % \
+                        (CFG_SITE_URL,
+                         'category=' + category + '&amp;ln=' + ln,
+                         _("Others' baskets"))
+        out += category_html
         if bskid:
             basket = db.get_public_basket_infos(bskid)
             if basket:
-                out += ' &gt; '
-                out += '<a class="navtrail" href="%s/yourbaskets/display?%s">'\
-                       '%s</a>'
-                out %= (CFG_SITE_URL,
-                        'category=' + category + '&amp;ln=' + ln + \
-                        '#bsk' + str(bskid),
-                        cgi.escape(basket[1]))
+                basket_html = """ &gt; <a class="navtrail" href="%s/yourbaskets/display?%s">""" % \
+                              (CFG_SITE_URL,
+                               'category=' + category + '&amp;ln=' + ln + \
+                                         '#bsk' + str(bskid),
+                               cgi.escape(basket[1]))
+                out += basket_html
+
     return out
 
 def create_webbasket_navtrail(uid,
                               category="",
                               topic="",
                               group=0,
                               bskid=0,
                               public_basket=False,
                               search_baskets=False,
                               add_to_basket=False,
                               ln=CFG_SITE_LANG):
     """Create the navtrail for navigation withing WebBasket.
     @param uid: user id (int)
     @param category: selected category (see CFG_WEBBASKET_CATEGORIES)
     @param topic: selected topic (str)
     @param group: selected group (int)
     @param bskid: selected basket id (int)
     @param ln: language"""
 
     _ = gettext_set_language(ln)
 
     out = """<a class="navtrail" href="%s/youraccount/display?ln=%s">%s</a>""" % \
           (CFG_SITE_URL, ln, _("Your Account"))
     out += " &gt; "
     out += """<a class="navtrail" href="%s/yourbaskets/display?ln=%s">%s</a>""" % \
            (CFG_SITE_URL, ln, _("Your Baskets"))
 
     if public_basket:
         out += " &gt; "
         out += """<a class="navtrail" href="%s/yourbaskets/list_public_baskets?ln=%s">%s</a>""" % \
                (CFG_SITE_URL, ln, _("List of public baskets"))
         if bskid:
             basket = db.get_basket_name(bskid)
             if basket:
                 out += " &gt; "
                 out += """<a class="navtrail" href="%s/yourbaskets/display_public?bskid=%i&amp;ln=%s">%s</a>""" % \
-                       (CFG_SITE_URL, bskid, ln, cgi.escape(basket))
+                       (CFG_SITE_URL, bskid, ln, cgi.escape(basket, True))
 
     elif search_baskets:
         out += " &gt; "
         out += """<a class="navtrail" href="%s/yourbaskets/search?ln=%s">%s</a>""" % \
                (CFG_SITE_URL, ln, _("Search baskets"))
 
     elif add_to_basket:
         out += " &gt; "
         out += """<a class="navtrail" href="%s/yourbaskets/add?ln=%s">%s</a>""" % \
                (CFG_SITE_URL, ln, _("Add to basket"))
 
     else:
         if category == CFG_WEBBASKET_CATEGORIES['PRIVATE']:
             out += " &gt; "
             out += """<a class="navtrail" href="%s/yourbaskets/display?category=%s&amp;ln=%s">%s</a>""" % \
                    (CFG_SITE_URL, CFG_WEBBASKET_CATEGORIES['PRIVATE'], ln, _("Personal baskets"))
             if topic:
                 topic_names = map(lambda x: x[0], db.get_personal_topics_infos(uid))
                 if topic in topic_names:
                     out += " &gt; "
                     out += """<a class="navtrail" href="%s/yourbaskets/display?category=%s&amp;topic=%s&amp;ln=%s">%s</a>""" % \
-                           (CFG_SITE_URL, CFG_WEBBASKET_CATEGORIES['PRIVATE'], cgi.escape(topic), ln, cgi.escape(topic))
+                           (CFG_SITE_URL, CFG_WEBBASKET_CATEGORIES['PRIVATE'], urllib.quote(topic), ln, cgi.escape(topic, True))
                     if bskid:
                         basket = db.get_basket_name(bskid)
                         if basket:
                             out += " &gt; "
                             out += """<a class="navtrail" href="%s/yourbaskets/display?category=%s&amp;topic=%s&amp;bskid=%i&amp;ln=%s">%s</a>""" % \
-                                   (CFG_SITE_URL, CFG_WEBBASKET_CATEGORIES['PRIVATE'], cgi.escape(topic), bskid, ln, cgi.escape(basket))
+                                   (CFG_SITE_URL, CFG_WEBBASKET_CATEGORIES['PRIVATE'], urllib.quote(topic), bskid, ln, cgi.escape(basket, True))
 
         elif category == CFG_WEBBASKET_CATEGORIES['GROUP']:
             out += " &gt; "
             out += """<a class="navtrail" href="%s/yourbaskets/display?category=%s&amp;ln=%s">%s</a>""" % \
                    (CFG_SITE_URL, CFG_WEBBASKET_CATEGORIES['GROUP'], ln, _("Group baskets"))
             if group:
                 group_names = map(lambda x: x[0] == group and x[1], db.get_group_infos(uid))
                 if group_names and group_names[0]:
                     out += " &gt; "
                     out += """<a class="navtrail" href="%s/yourbaskets/display?category=%s&amp;group=%i&amp;ln=%s">%s</a>""" % \
-                           (CFG_SITE_URL, CFG_WEBBASKET_CATEGORIES['GROUP'], group, ln, cgi.escape(group_names[0]))
+                           (CFG_SITE_URL, CFG_WEBBASKET_CATEGORIES['GROUP'], group, ln, cgi.escape(group_names[0], True))
                     if bskid:
                         basket = db.get_basket_name(bskid)
                         if basket:
                             out += " &gt; "
                             out += """<a class="navtrail" href="%s/yourbaskets/display?category=%s&amp;topic=%s&amp;bskid=%i&amp;ln=%s">%s</a>""" % \
-                                   (CFG_SITE_URL, CFG_WEBBASKET_CATEGORIES['GROUP'], group, bskid, ln, cgi.escape(basket))
+                                   (CFG_SITE_URL, CFG_WEBBASKET_CATEGORIES['GROUP'], group, bskid, ln, cgi.escape(basket, True))
 
         elif category == CFG_WEBBASKET_CATEGORIES['EXTERNAL']:
             out += " &gt; "
             out += """<a class="navtrail" href="%s/yourbaskets/display?category=%s&amp;ln=%s">%s</a>""" % \
                    (CFG_SITE_URL, category, ln, _("Public baskets"))
             if bskid:
                 basket = db.get_basket_name(bskid)
                 if basket:
                     out += " &gt; "
                     out += """<a class="navtrail" href="%s/yourbaskets/display?category=%s&amp;topic=%s&amp;bskid=%i&amp;ln=%s">%s</a>""" % \
-                           (CFG_SITE_URL, category, group, bskid, ln, cgi.escape(basket))
+                           (CFG_SITE_URL, category, group, bskid, ln, cgi.escape(basket, True))
 
     return out
 
 def account_list_baskets(uid, ln=CFG_SITE_LANG):
     """Display baskets informations on account page"""
     _ = gettext_set_language(ln)
     (personal, group, external) = db.count_baskets(uid)
     link = '<a href="%s">%s</a>'
     base_url = CFG_SITE_URL + '/yourbaskets/display?category=%s&amp;ln=' + ln
     personal_text = personal
     if personal:
         url = base_url % CFG_WEBBASKET_CATEGORIES['PRIVATE']
         personal_text = link % (url, personal_text)
     group_text = group
     if group:
         url = base_url % CFG_WEBBASKET_CATEGORIES['GROUP']
         group_text = link % (url, group_text)
     external_text = external
     if external:
         url = base_url % CFG_WEBBASKET_CATEGORIES['EXTERNAL']
     else:
         url = CFG_SITE_URL + '/yourbaskets/list_public_baskets?ln=' + ln
     external_text = link % (url, external_text)
     out = _("You have %(x_nb_perso)s personal baskets and are subscribed to %(x_nb_group)s group baskets and %(x_nb_public)s other users public baskets.") %\
         {'x_nb_perso': personal_text,
          'x_nb_group': group_text,
          'x_nb_public': external_text}
     return out
 
 def page_start(req, of='xm'):
     """Set the content type and send the headers for the page."""
 
     if of.startswith('x'):
         req.content_type = "text/xml"
         if of == 'xr':
             req.content_type = "application/rss+xml"
         req.send_http_header()
         req.write("""<?xml version="1.0" encoding="UTF-8"?>\n""")
         print_records_prologue(req, of)
     else: # assuming HTML by default
         req.content_type = "text/html"
         req.send_http_header()
 
 def page_end(req, of='xm'):
     """Print page footer"""
     if of.startswith('x'):
         print_records_epilogue(req, of)
 
 def perform_request_export_xml(body):
     """Export an xml representation of the selected baskets/items."""
     return webbasket_templates.tmpl_export_xml(body)
 
 ################################
 ### External items functions ###
 ################################
 
 def format_external_records(recids, of='hb'):
     """Given a list of external records' recids, this function returns a list of tuples
     with each recid and the actual formatted record using the selected output format.
     It also stores the formatted record in the database for future use."""
 
     # TODO: add a returnp variable to control whether we actually want anything
     # to be returned or not. For example when we just want to store the xml
     # formatted records for newly added items.
     # TODO: take care of external urls. Invent an xml format for them.
 
     # NOTE: this function is meant to format external records from other
     # libraries. It's not meant to handle custom external sources like urls
     # submitted manually by the user. These items are directly formatted and
     # stored by the add_to_basket database function.
 
     formatted_records = []
 
     if type(recids) is not list:
         recids = [recids]
 
     existing_xml_formatted_records = db.get_external_records(recids, "xm")
     for existing_xml_formatted_record in existing_xml_formatted_records:
         xml_record = decompress(existing_xml_formatted_record[2])
         xml_record_id = existing_xml_formatted_record[1]
         xml_record_colid = existing_xml_formatted_record[0]
         recids.remove(-xml_record_id)
         if of == "hb":
             if xml_record_colid > 0:
                 htmlbrief_record = format_record(None, of, xml_record=xml_record)
             formatted_records.append((xml_record_id, htmlbrief_record))
         elif of != "hb":
             #formatted_records.append((xml_record_id, xml_record))
             formatted_records.append((xml_record_id, format_record([], of, xml_record=xml_record, on_the_fly=True)))
 #            formatted_records.append((xml_record_id, repr(xml_record)))
 
     if formatted_records and of == "hb":
         db.store_external_records(formatted_records, of)
 
     records_grouped_by_collection = db.get_external_records_by_collection(recids)
 
     if records_grouped_by_collection:
         for records in records_grouped_by_collection:
             colid = records[2]
             if colid:
                 external_records = fetch_and_store_external_records(records, of)
                 formatted_records.extend(external_records)
 
     return formatted_records
 
 def fetch_and_store_external_records(records, of="hb"):
     """Function that fetches the formatted records for one collection and stores them
     into the database. It also calculates and stores the original external url for each
     record."""
 
     results = []
     formatted_records = []
 
     if of == 'xm':
         re_controlfield = re.compile(r'<controlfield\b[^>]*>.*?</controlfield>', re.DOTALL + re.MULTILINE + re.IGNORECASE)
         re_blankline = re.compile(r'\s*\n', re.DOTALL + re.MULTILINE + re.IGNORECASE)
 
     # the locally saved external ids
     local_ext_ids = records[0].split(",")
     # the locally saved original external ids
     external_ids = records[1].split(",")
     collection_name = get_collection_name_by_id(records[2])
     collection_engine_set = select_hosted_search_engines(collection_name)
     collection_engine = collection_engine_set.pop()
 
     external_ids_urls = collection_engine.build_record_urls(external_ids)
     external_urls = [external_id_url[1] for external_id_url in external_ids_urls]
     #external_urls_dict = {}
     #for (local_id, url) in zip(local_ext_ids, external_urls):
         #external_urls_dict[local_id] = url
     #db.store_external_urls(external_urls_dict)
     db.store_external_urls(zip(local_ext_ids, external_urls))
 
     url = collection_engine.build_search_url(None, req_args=external_ids)
     pagegetters = [HTTPAsyncPageGetter(url)]
 
     def finished(pagegetter, dummy_data, dummy_time):
         """Function to be called when a page has been downloaded."""
         results.append(pagegetter)
 
     finished_list = async_download(pagegetters, finish_function=finished, timeout=CFG_EXTERNAL_COLLECTION_TIMEOUT)
 
     if finished_list[0]:
         collection_engine.parser.parse_and_get_results(results[0].data, feedonly=True)
         (dummy, parsed_results_dict) = collection_engine.parser.parse_and_extract_records(of=of)
         for (local_ext_id, external_id) in zip(local_ext_ids, external_ids):
             formatted_record = parsed_results_dict[external_id]
             if of == 'xm':
                 formatted_record = re_controlfield.sub('', formatted_record)
                 formatted_record = re_blankline.sub('\n', formatted_record)
             formatted_records.append((int(local_ext_id), formatted_record))
         db.store_external_records(formatted_records, of)
     else:
         for (local_ext_id, external_id) in zip(local_ext_ids, external_ids):
             formatted_records.append((int(local_ext_id), "There was a timeout when fetching the record."))
 
     return formatted_records
 
 ###############################
 ### Miscellaneous functions ###
 ###############################
 
 def url_is_valid(url):
     """Returns (True, status, reason) if the url is valid or (False, status, reason) if different."""
 
     common_errors_list = [400, 404, 500]
     url_tuple = urlsplit(url)
     if not url_tuple[0]:
         url = "http://" + url
         url_tuple =  urlsplit(url)
     if not url_tuple[0] and not url_tuple[1]:
         return (False, 000, "Not Valid")
     # HTTPConnection had the timeout parameter introduced in python 2.6
     # for the older versions we have to get and set the default timeout
     # In order to use a custom timeout pass it as an extra argument to this function
     #old_timeout = getdefaulttimeout()
     #setdefaulttimeout(timeout)
     conn = HTTPConnection(url_tuple[1])
     #setdefaulttimeout(old_timeout)
     try:
         conn.request("GET", url_tuple[2])
     except:
         return (False, 000, "Not Valid")
     response = conn.getresponse()
     status = response.status
     reason = response.reason
     if str(status).startswith('1') or str(status).startswith('2') or str(status).startswith('3'):
         return (True, status, reason)
     elif str(status).startswith('4') or str(status).startswith('5'):
         if status in common_errors_list:
             return (False, status, reason)
         else:
             return (True, status, reason)
 
 def nl2br(text):
     """Replace newlines (\n) found in text with line breaks (<br />)."""
 
     return '<br />'.join(text.split('\n'))
 
 def wash_b_search(b):
     """Wash the b GET variable for the search interface."""
     _ = gettext_set_language(CFG_SITE_LANG)
 
     b = b.split('_', 1)
     b_category = b[0].upper()
     valid_categories = CFG_WEBBASKET_CATEGORIES.values()
     valid_categories.append('')
     if b_category not in valid_categories:
         try:
             raise InvenioWebBasketWarning(_('The category you have selected does not exist. Please select a valid category.'))
         except InvenioWebBasketWarning, exc:
             register_exception(stream='warning')
             return ("", "", exc.message)
         #return ("", "", ['WRN_WEBBASKET_INVALID_CATEGORY'])
     if len(b) == 2:
         if b_category == CFG_WEBBASKET_CATEGORIES['PRIVATE'] or b_category == CFG_WEBBASKET_CATEGORIES['GROUP']:
             return (b_category, b[1], None)
         # TODO: send a warning when the user has sent a second argument
         # specifying a category other than PRIVATE or GROUP
         #else:
             #return (b_category, "", ['WRN_WEBBASKET_'])
     return (b_category, "", None)
 
 def wash_b_add(b):
     """Wash the b POST variable for the add interface."""
     _ = gettext_set_language(CFG_SITE_LANG)
 
     b = b.split('_', 1)
     b_category = b[0].upper()
     valid_categories = (CFG_WEBBASKET_CATEGORIES['PRIVATE'], CFG_WEBBASKET_CATEGORIES['GROUP'])
     if b_category not in valid_categories or len(b) != 2 or not b[1]:
         try:
             raise InvenioWebBasketWarning(_('Cannot add items to the selected basket. Invalid parameters.'))
         except InvenioWebBasketWarning, exc:
             register_exception(stream='warning')
             return ("", "", exc.message)
     return (b_category, b[1], None)
 
 def wash_category(category):
     """Wash the category."""
     _ = gettext_set_language(CFG_SITE_LANG)
 
     category = category.upper()
     valid_categories = CFG_WEBBASKET_CATEGORIES.values()
     valid_categories.append('')
     if category not in valid_categories:
         try:
             raise InvenioWebBasketWarning(_('The category you have selected does not exist. Please select a valid category.'))
         except InvenioWebBasketWarning, exc:
             register_exception(stream='warning')
             return ("", "", exc.message)
         #return ("", ['WRN_WEBBASKET_INVALID_CATEGORY'])
     return (category, None)
 
 def wash_topic(uid, topic):
     """Wash the topic."""
     _ = gettext_set_language(CFG_SITE_LANG)
 
     if not db.is_topic_valid(uid, topic):
         try:
             raise InvenioWebBasketWarning(_('The selected topic does not exist or you do not have access to it.'))
         except InvenioWebBasketWarning, exc:
             register_exception(stream='warning')
             return ("", "", exc.message)
         #return ("", ['WRN_WEBBASKET_INVALID_OR_RESTRICTED_TOPIC'])
     return (topic, None)
 
 def wash_group(uid, group):
     """Wash the topic."""
     _ = gettext_set_language(ln=CFG_SITE_LANG)
 
     if not group.isdigit() or not db.is_group_valid(uid, group):
         try:
             raise InvenioWebBasketWarning(_('The selected group does not exist or you do not have access to it.'))
         except InvenioWebBasketWarning, exc:
             register_exception(stream='warning')
             return (0, exc.message)
         #return (0, ['WRN_WEBBASKET_INVALID_OR_RESTRICTED_GROUP'])
     return (int(group), None)
 
 def wash_bskid(uid, category, bskid):
     """Wash the bskid based on its category. This function expectes a washed
     category, either for personal or for group baskets."""
     _ = gettext_set_language(CFG_SITE_LANG)
 
     if not bskid.isdigit():
         try:
             raise InvenioWebBasketWarning(_('The selected basket does not exist or you do not have access to it.'))
         except InvenioWebBasketWarning, exc:
             register_exception(stream='warning')
             return (0, exc.message)
         #return (0, ['WRN_WEBBASKET_INVALID_OR_RESTRICTED_BASKET'])
     bskid = int(bskid)
     if category == CFG_WEBBASKET_CATEGORIES['PRIVATE'] and not db.is_personal_basket_valid(uid, bskid):
         try:
             raise InvenioWebBasketWarning(_('The selected basket does not exist or you do not have access to it.'))
         except InvenioWebBasketWarning, exc:
             register_exception(stream='warning')
             return (0, exc.message)
         #return (0, ['WRN_WEBBASKET_INVALID_OR_RESTRICTED_BASKET'])
     if category == CFG_WEBBASKET_CATEGORIES['GROUP'] and not db.is_group_basket_valid(uid, bskid):
         try:
             raise InvenioWebBasketWarning(_('The selected basket does not exist or you do not have access to it.'))
         except InvenioWebBasketWarning, exc:
             register_exception(stream='warning')
             return (0, exc.message)
         #return (0, ['WRN_WEBBASKET_INVALID_OR_RESTRICTED_BASKET'])
     return (bskid, None)
 
 def wash_of(of):
     """Wash the output format"""
     _ = gettext_set_language(CFG_SITE_LANG)
 
     list_of_accepted_formats = ['hb', 'xm', 'hx', 'xd', 'xe', 'xn', 'xw', 'xr', 'xp']
 
     if of in list_of_accepted_formats:
         return (of, None)
     try:
         raise InvenioWebBasketWarning(_('The selected output format is not available or is invalid.'))
     except InvenioWebBasketWarning, exc:
         register_exception(stream='warning')
     return ('hb', exc.message)
 
 def __create_search_box(uid,
                         category="",
                         topic="",
                         grpid=0,
                         p="",
                         n=0,
                         ln=CFG_SITE_LANG):
     """Private function.
     Creates the search box and returns html code."""
 
     topic_list = db.get_all_user_topics(uid)
     group_list = db.get_all_user_groups(uid)
     number_of_public_baskets = db.count_external_baskets(uid)
 
     search_box = webbasket_templates.tmpl_create_search_box(category,
                                                             topic,
                                                             grpid,
                                                             topic_list,
                                                             group_list,
                                                             number_of_public_baskets,
                                                             p,
                                                             n,
                                                             ln=ln)
 
     return search_box
diff --git a/modules/webbasket/lib/webbasket_config.py b/modules/webbasket/lib/webbasket_config.py
index 341d0524f..01b5dd684 100644
--- a/modules/webbasket/lib/webbasket_config.py
+++ b/modules/webbasket/lib/webbasket_config.py
@@ -1,71 +1,74 @@
 # -*- coding: utf-8 -*-
 ##
 ## 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.
 
 """WebBasket configuration parameters."""
 
 __revision__ = "$Id$"
 
 CFG_WEBBASKET_SHARE_LEVELS = {'READITM': 'RI',
                               'READCMT': 'RC',
                               'ADDCMT': 'AC',
                               'ADDITM': 'AI',
                               'DELCMT': 'DC',
                               'DELITM': 'DI',
                               'MANAGE': 'MA'}
 
 CFG_WEBBASKET_SHARE_LEVELS_ORDERED = [CFG_WEBBASKET_SHARE_LEVELS['READITM'],
                                       CFG_WEBBASKET_SHARE_LEVELS['READCMT'],
                                       CFG_WEBBASKET_SHARE_LEVELS['ADDCMT'],
                                       CFG_WEBBASKET_SHARE_LEVELS['ADDITM'],
                                       CFG_WEBBASKET_SHARE_LEVELS['DELCMT'],
                                       CFG_WEBBASKET_SHARE_LEVELS['DELITM'],
                                       CFG_WEBBASKET_SHARE_LEVELS['MANAGE']]
 
+# Keep in mind that the underscore ('_') is a special character. In case you
+# want to define new categories, don't use the underscore ('_') anywhere in the
+# value! You may use it in the key if you wish.
 CFG_WEBBASKET_CATEGORIES = {'PRIVATE':      'P',
                             'GROUP':        'G',
                             'EXTERNAL':     'E',
                             'ALLPUBLIC':    'A'}
 
 CFG_WEBBASKET_ACTIONS = {'DELETE':  'delete',
                          'UP':      'moveup',
                          'DOWN':    'movedown',
                          'COPY':    'copy'}
 
 # Specify how many levels of indentation discussions can be.  This can
 # be used to ensure that discussions will not go into deep levels of
 # nesting if users don't understand the difference between "reply to
 # comment" and "add comment". When the depth is reached, any "reply to
 # comment" is conceptually converted to a "reply to thread"
 # (i.e. reply to this parent's comment). Use -1 for no limit, 0 for
 # unthreaded (flat) discussions.
 CFG_WEBBASKET_MAX_COMMENT_THREAD_DEPTH = 1
 
 CFG_WEBBASKET_DIRECTORY_BOX_NUMBER_OF_COLUMNS = 3
 
 CFG_WEBBASKET_MAX_NUMBER_OF_NOTES = 100
 
 # Exceptions: warnings
 class InvenioWebBasketWarning(Exception):
     """A generic warning for WebBasket."""
     def __init__(self, message):
         """Initialisation."""
         self.message = message
     def __str__(self):
         """String representation."""
         return repr(self.message)
diff --git a/modules/webbasket/lib/webbasket_dblayer.py b/modules/webbasket/lib/webbasket_dblayer.py
index 92aa90b82..a33784213 100644
--- a/modules/webbasket/lib/webbasket_dblayer.py
+++ b/modules/webbasket/lib/webbasket_dblayer.py
@@ -1,2385 +1,2371 @@
 # -*- coding: utf-8 -*-
 ##
 ## 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.
 
 """ Database related functions for webbasket module """
 
 __revision__ = "$Id$"
 
 from zlib import decompress
 from zlib import compress
 from time import localtime
 from invenio.textutils import encode_for_xml
 
 from invenio.dbquery import run_sql
 from invenio.webcomment import get_reply_order_cache_data
 from invenio.webbasket_config import CFG_WEBBASKET_SHARE_LEVELS, \
                                      CFG_WEBBASKET_ACTIONS, \
                                      CFG_WEBBASKET_SHARE_LEVELS_ORDERED, \
                                      CFG_WEBBASKET_MAX_COMMENT_THREAD_DEPTH
 from invenio.config import CFG_SITE_URL
 from invenio.dateutils import convert_datestruct_to_datetext
 from invenio.websession_config import CFG_WEBSESSION_USERGROUP_STATUS
 from invenio.search_engine import get_fieldvalues
 
 ########################### Table of contents ################################
 #
 # NB. functions preceeded by a star use usergroup table
 #
 # 1. General functions
 #    - count_baskets
 #    - check_user_owns_basket
 #    - get_max_user_rights_on_basket
 #
 # 2. Personal baskets
 #    - get_personal_baskets_info_for_topic
 #    - get_all_personal_basket_ids_and_names_by_topic
 #    - get_all_personal_baskets_names
 #    - get_basket_name
 #    - is_personal_basket_valid
 #    - is_topic_valid
 #    - get_basket_topic
 #    - get_personal_topics_infos
 #    - rename_basket
 #    - rename_topic
 #    - move_baskets_to_topic
 #    - delete_basket
 #    - create_basket
 #
 # 3. Actions on baskets
 #    - get_basket_record
 #    - get_basket_content
 #    - get_basket_item
 #    - get_basket_item_title_and_URL
 #    - share_basket_with_group
 #    - update_rights
 #    - move_item
 #    - delete_item
 #    - add_to_basket
 #    - get_external_records_by_collection
 #    - store_external_records
 #    - store_external_urls
 #    - store_external_source
 #    - get_external_colid_and_url
 #
 # 4. Group baskets
 #    - get_group_basket_infos
 #    - get_group_name
 #    - get_all_group_basket_ids_and_names_by_group
 #    - (*) get_all_group_baskets_names
 #    - is_shared_to
 #
 # 5. External baskets (baskets user has subscribed to)
 #    - get_external_baskets_infos
 #    - get_external_basket_info
 #    - get_all_external_basket_ids_and_names
 #    - count_external_baskets
 #    - get_all_external_baskets_names
 #
 # 6. Public baskets (interface to subscribe to baskets)
 #    - get_public_basket_infos
 #    - get_public_basket_info
 #    - get_basket_general_infos
 #    - get_basket_owner_id
 #    - count_public_baskets
 #    - get_public_baskets_list
 #    - is_basket_public
 #    - subscribe
 #    - unsubscribe
 #    - is_user_subscribed_to_basket
 #    - count_subscribers
 #    - (*) get_groups_subscribing_to_basket
 #    - get_rights_on_public_basket
 #
 # 7. Annotating
 #    - get_notes
 #    - get_note
 #    - save_note
 #    - delete_note
 #    - note_belongs_to_item_in_basket_p
 #
 # 8. Usergroup functions
 #    - (*) get_group_infos
 #    - count_groups_user_member_of
 #    - (*) get_groups_user_member_of
 #
 # 9. auxilliary functions
 #    - __wash_sql_count
 #    - __decompress_last
 #    - create_pseudo_record
 #    - prettify_url
 
 ########################## General functions ##################################
 
 def count_baskets(uid):
     """Return (nb personal baskets, nb group baskets, nb external
     baskets) tuple for given user"""
     query1 = "SELECT COUNT(id) FROM bskBASKET WHERE id_owner=%s"
     res1 = run_sql(query1, (int(uid),))
     personal = __wash_sql_count(res1)
     query2 = """SELECT count(ugbsk.id_bskbasket)
                 FROM usergroup_bskBASKET ugbsk LEFT JOIN user_usergroup uug
                                                ON ugbsk.id_usergroup=uug.id_usergroup
                 WHERE uug.id_user=%s AND uug.user_status!=%s
                 GROUP BY ugbsk.id_usergroup"""
     params = (int(uid), CFG_WEBSESSION_USERGROUP_STATUS['PENDING'])
     res2 = run_sql(query2, params)
     if len(res2):
         groups = reduce(lambda x, y: x + y, map(lambda x: x[0], res2))
     else:
         groups = 0
     external = count_external_baskets(uid)
     return (personal, groups, external)
 
 def check_user_owns_baskets(uid, bskids):
     """ Return 1 if user is owner of every basket in list bskids"""
     if not((type(bskids) is list) or (type(bskids) is tuple)):
         bskids = [bskids]
     query = """SELECT id_owner FROM bskBASKET WHERE %s GROUP BY id_owner"""
     sep = ' OR '
     query %= sep.join(['id=%s'] * len(bskids))
     res = run_sql(query, tuple(bskids))
     if len(res)==1 and int(res[0][0])==uid:
         return 1
     else:
         return 0
 
 def get_max_user_rights_on_basket(uid, bskid):
     """Return the max rights a user has on this basket"""
     query_owner = "SELECT count(id_owner) FROM bskBASKET WHERE id_owner=%s and id=%s"
     params_owner = (int(uid), int(bskid))
     res = run_sql(query_owner, params_owner)
     if res and res[0][0]:
         # if this user is owner of this baskets he can do anything he wants.
         return CFG_WEBBASKET_SHARE_LEVELS['MANAGE']
     # not owner => group member ?
     query_group_baskets = """
     SELECT share_level
     FROM user_usergroup AS ug LEFT JOIN usergroup_bskBASKET AS ub
                               ON ug.id_usergroup=ub.id_usergroup
     WHERE ug.id_user=%s AND ub.id_bskBASKET=%s AND NOT(ub.share_level='NO') AND ug.user_status!=%s
     """
     params_group_baskets = (int(uid), int(bskid), CFG_WEBSESSION_USERGROUP_STATUS['PENDING'])
     res = run_sql(query_group_baskets, params_group_baskets)
     group_index = None
     if res:
         try:
             group_index = CFG_WEBBASKET_SHARE_LEVELS_ORDERED.index(res[0][0])
         except:
             return None
     # public basket ?
     query_public_baskets = """
     SELECT share_level
     FROM usergroup_bskBASKET
     WHERE id_usergroup=0 AND id_bskBASKET=%s
     """
     public_index = None
     res = run_sql(query_public_baskets, (int(bskid),))
     if res:
         try:
             public_index = CFG_WEBBASKET_SHARE_LEVELS_ORDERED.index(res[0][0])
         except:
             return None
     if group_index or public_index:
         if group_index > public_index:
             return CFG_WEBBASKET_SHARE_LEVELS_ORDERED[group_index]
         else:
             return CFG_WEBBASKET_SHARE_LEVELS_ORDERED[public_index]
     return None
 
 ########################### Personal baskets ##################################
 
 def get_personal_baskets_info_for_topic(uid, topic):
     """Return information about every basket that belongs to the given user and topic."""
 
     query = """ SELECT      bsk.id,
                             bsk.name,
                             DATE_FORMAT(bsk.date_modification, '%%Y-%%m-%%d %%H:%%i:%%s'),
                             bsk.nb_views,
                             count(rec.id_bibrec_or_bskEXTREC),
                             DATE_FORMAT(max(rec.date_added), '%%Y-%%m-%%d %%H:%%i:%%s')
                 FROM        user_bskBASKET AS ubsk
                 JOIN        bskBASKET AS bsk
                     ON      bsk.id=ubsk.id_bskBASKET
                     AND     bsk.id_owner=%s
                 LEFT JOIN   bskREC AS rec
                     ON      rec.id_bskBASKET=bsk.id
                 WHERE       ubsk.id_user=%s
                 AND         ubsk.topic=%s
                 GROUP BY    bsk.id
                 ORDER BY    bsk.name"""
 
     params = (uid, uid, topic)
 
     res = run_sql(query, params)
 
     return res
 
-def get_all_personal_basket_ids_and_names_by_topic(uid):
-    """For a given user return all their personal baskets
-    (in tuples: (id, name)) grouped by topic. Note that the
-    basket tuples have to evaluated to be converted to actual
-    tuples."""
+def get_all_user_personal_basket_ids_by_topic(uid):
+    """For a given user return all their personal basket ids grouped by topic."""
 
     query = """ SELECT      ubsk.topic,
-                            count(bsk.id),
-                            GROUP_CONCAT('(', bsk.id, ', \"', bsk.name, '\")'
-                                        ORDER BY bsk.name)
-                FROM        user_bskBASKET AS ubsk
-                JOIN        bskBASKET AS bsk
-                ON          ubsk.id_bskBASKET=bsk.id
-                AND         ubsk.id_user=bsk.id_owner
-                WHERE       bsk.id_owner=%s
-                GROUP BY    ubsk.topic
-                ORDER BY    ubsk.topic"""
-    params = (uid,)
-    res = run_sql(query, params)
-
-    return res
-
-def get_all_personal_basket_ids_and_names_by_topic_for_add_to_list(uid):
-    """For a given user return all their personal baskets
-    (in tuples: (id, name)) grouped by topic. Note that the
-    basket tuples have to evaluated to be converted to actual
-    tuples."""
-
-    query = """ SELECT      ubsk.topic,
-                            GROUP_CONCAT('(', bsk.id, ', \"', bsk.name, '\")'
-                                        ORDER BY bsk.name)
+                            GROUP_CONCAT(bsk.id)
                 FROM        user_bskBASKET AS ubsk
                 JOIN        bskBASKET AS bsk
                 ON          ubsk.id_bskBASKET=bsk.id
                 AND         ubsk.id_user=bsk.id_owner
                 WHERE       bsk.id_owner=%s
                 GROUP BY    ubsk.topic
                 ORDER BY    ubsk.topic"""
     params = (uid,)
     res = run_sql(query, params)
 
     return res
 
 def get_all_personal_baskets_names(uid):
     """ for a given user, returns every basket he is owner of
     returns list of tuples: (bskid, bsk_name, topic)
     """
     query = """
     SELECT bsk.id,
            bsk.name,
            ubsk.topic
     FROM user_bskBASKET ubsk JOIN bskBASKET bsk
                              ON ubsk.id_bskBASKET=bsk.id
                              AND ubsk.id_user=bsk.id_owner
     WHERE bsk.id_owner=%s
     ORDER BY ubsk.topic
     """
     params = (int(uid),)
     return run_sql(query, params)
 
 def get_basket_name(bskid):
     """return the name of a given basket"""
     query = 'SELECT name FROM bskBASKET where id=%s'
     res = run_sql(query, (int(bskid), ))
     if res:
         return res[0][0]
     else:
         return ''
 
 def is_personal_basket_valid(uid, bskid):
     """Check if the basked (bskid) belongs to user (uid) and is valid."""
 
     query = """ SELECT  id
                 FROM    bskBASKET
                 WHERE   id=%s
                 AND     id_owner=%s"""
     params = (bskid, uid)
     res = run_sql(query, params)
 
     return res
 
 def is_topic_valid(uid, topic):
     """Check if the topic defined by user (uid) exists."""
 
     query = """ SELECT  distinct(topic)
                 FROM    user_bskBASKET
                 WHERE   topic=%s
                 AND     id_user=%s"""
     params = (topic, uid)
     res = run_sql(query, params)
 
     return res
 
 def get_basket_topic(uid, bskid):
     """Return the name of the topic this basket (bskid) belongs to."""
 
     query = """ SELECT  topic
                 FROM    user_bskBASKET
                 WHERE   id_bskBASKET=%s
                 AND     id_user=%s"""
     params = (bskid,uid)
     res = run_sql(query, params)
 
     return res
 
 def get_personal_topics_infos(uid):
     """
     Get the list of every topic user has defined,
     and the number of baskets in each topic
     @param uid: user id (int)
     @return: a list of tuples (topic name, nb of baskets)
     """
     query = """SELECT topic, count(b.id)
                FROM   user_bskBASKET ub JOIN bskBASKET b
                                         ON ub.id_bskBASKET=b.id AND
                                            b.id_owner=ub.id_user
                WHERE  ub.id_user=%s
                GROUP BY topic
                ORDER BY topic"""
     uid = int(uid)
     res = run_sql(query, (uid,))
     return res
 
+def get_basket_ids_and_names(bskids, limit=0):
+    """For the given basket ids, return their ids and names,
+    ordered by basket name.
+    If 'limit' is greater than 0, limit the number of results returned."""
+
+    if not((type(bskids) is list) or (type(bskids) is tuple)):
+        bskids = [bskids]
+
+    query = """ SELECT      bsk.id,
+                            bsk.name
+                FROM        bskBASKET AS bsk
+                WHERE       %s
+                ORDER BY    bsk.name
+                %s"""
+    sep = ' OR '
+    query %= (sep.join(['id=%s'] * len(bskids)), limit and 'LIMIT %i' % limit or '')
+
+    params = tuple(bskids)
+
+    res = run_sql(query, params)
+
+    return res
+
 def rename_basket(bskid, new_name):
     """Rename basket to new_name"""
     run_sql("UPDATE bskBASKET SET name=%s WHERE id=%s", (new_name, bskid))
 
 def rename_topic(uid, old_topic, new_topic):
     """Rename topic to new_topic """
     res = run_sql("UPDATE user_bskBASKET SET topic=%s WHERE id_user=%s AND topic=%s",
                   (new_topic, uid, old_topic))
     return res
 
 def move_baskets_to_topic(uid, bskids, new_topic):
     """Move given baskets to another topic"""
     if not((type(bskids) is list) or (type(bskids) is tuple)):
         bskids = [bskids]
     query = "UPDATE user_bskBASKET SET topic=%s WHERE id_user=%s AND ("
     query += ' OR '.join(['id_bskBASKET=%s'] * len(bskids))
     query += ")"
     params = (new_topic, uid) + tuple(bskids)
     res = run_sql(query, params)
     return res
 
 def delete_basket(bskid):
     """Delete given basket."""
 
     # TODO: check if any alerts are automaticly adding items to the given basket.
     bskid = int(bskid)
 
     query1 = "DELETE FROM bskBASKET WHERE id=%s"
     res = run_sql(query1, (bskid,))
 
     query2A = "SELECT id_bibrec_or_bskEXTREC FROM bskREC WHERE id_bskBASKET=%s"
     local_and_external_ids = run_sql(query2A, (bskid,))
     external_ids = [local_and_external_id[0] for local_and_external_id in \
                     local_and_external_ids if local_and_external_id[0]<0]
     for external_id in external_ids:
         delete_item(bskid=bskid, recid=external_id, update_date_modification=False)
 
     query2B = "DELETE FROM bskREC WHERE id_bskBASKET=%s"
     run_sql(query2B, (bskid,))
 
     query3 = "DELETE FROM bskRECORDCOMMENT WHERE id_bskBASKET=%s"
     run_sql(query3, (bskid,))
 
     query4 = "DELETE FROM user_bskBASKET WHERE id_bskBASKET=%s"
     run_sql(query4, (bskid,))
 
     query5 = "DELETE FROM usergroup_bskBASKET WHERE id_bskBASKET=%s"
     run_sql(query5, (bskid,))
 
     query6 = "DELETE FROM user_query_basket WHERE id_basket=%s"
     run_sql(query6, (bskid,))
 
     return int(res)
 
 def create_basket(uid, basket_name, topic):
     """Create new basket for given user in given topic"""
     now = convert_datestruct_to_datetext(localtime())
     id_bsk = run_sql("""INSERT INTO bskBASKET (id_owner, name, date_modification)
                         VALUES                (%s, %s, %s)""",
                      (uid, basket_name, now))
     run_sql("""INSERT INTO user_bskBASKET (id_user, id_bskBASKET, topic)
                VALUES                     (%s, %s, %s)""",
             (uid, id_bsk, topic))
     return id_bsk
 
 def get_all_items_in_user_personal_baskets(uid,
                                            topic="",
                                            format='hb'):
     """For the specified user, return all the items in their personal baskets,
     grouped by basket if local or as a list if external.
     If topic is set, return only that topic's items."""
 
     if topic:
         topic_clause = """AND     ubsk.topic=%s"""
         params_local = (uid, uid, topic)
         params_external = (uid, uid, topic, format)
     else:
         topic_clause = ""
         params_local = (uid, uid)
         params_external = (uid, uid, format)
 
     query_local = """
                 SELECT      rec.id_bskBASKET,
                             bsk.name,
                             ubsk.topic,
                             GROUP_CONCAT(rec.id_bibrec_or_bskEXTREC)
                 FROM        bskREC AS rec
                 JOIN        bskBASKET AS bsk
                     ON      bsk.id=rec.id_bskBASKET
                     AND     bsk.id_owner=%%s
                 JOIN        user_bskBASKET AS ubsk
                     ON      ubsk.id_bskBASKET=rec.id_bskBASKET
                     AND     ubsk.id_user=%%s
                     %s
                 WHERE       rec.id_bibrec_or_bskEXTREC > 0
                 GROUP BY    rec.id_bskBASKET""" % (topic_clause,)
 
     res_local = run_sql(query_local, params_local)
 
     query_external = """
                 SELECT      rec.id_bskBASKET,
                             bsk.name,
                             ubsk.topic,
                             rec.id_bibrec_or_bskEXTREC,
                             ext.value
                 FROM        bskREC AS rec
                 JOIN        bskBASKET AS bsk
                     ON      bsk.id=rec.id_bskBASKET
                     AND     bsk.id_owner=%%s
                 JOIN        user_bskBASKET AS ubsk
                     ON      ubsk.id_bskBASKET=rec.id_bskBASKET
                     AND     ubsk.id_user=%%s
                     %s
                 JOIN        bskEXTFMT AS ext
                     ON      ext.id_bskEXTREC=-rec.id_bibrec_or_bskEXTREC
                     AND     ext.format=%%s
                 WHERE       rec.id_bibrec_or_bskEXTREC < 0
                 ORDER BY    rec.id_bskBASKET""" % (topic_clause,)
 
     res_external = run_sql(query_external, params_external)
 
     return (res_local, res_external)
 
 def get_all_items_in_user_personal_baskets_by_matching_notes(uid,
                                                              topic="",
                                                              p=""):
     """For the specified user, return all the items in their personal baskets
     matching their notes' titles and bodies, grouped by basket.
     If topic is set, return only that topic's items."""
 
     p = p and '%' + p + '%' or '%'
 
     if topic:
         topic_clause = """AND     ubsk.topic=%s"""
         params = (uid, uid, topic, p, p)
     else:
         topic_clause = ""
         params = (uid, uid, p, p)
 
     query = """ SELECT      notes.id_bskBASKET,
                             bsk.name,
                             ubsk.topic,
                             GROUP_CONCAT(DISTINCT(notes.id_bibrec_or_bskEXTREC))
                 FROM        bskRECORDCOMMENT AS notes
                 JOIN        bskBASKET AS bsk
                     ON      bsk.id=notes.id_bskBASKET
                     AND     bsk.id_owner=%%s
                 JOIN        user_bskBASKET AS ubsk
                     ON      ubsk.id_bskBASKET=notes.id_bskBASKET
                     AND     ubsk.id_user=%%s
                     %s
                 WHERE       notes.title like %%s
                 OR          notes.body like %%s
                 GROUP BY    notes.id_bskBASKET""" % (topic_clause,)
 
     res = run_sql(query, params)
 
     return res
 
 def get_all_user_topics(uid):
     """Return a list of the user's topics."""
 
     query = """ SELECT      ubsk.topic
                 FROM        bskBASKET AS bsk
                 JOIN        user_bskBASKET AS ubsk
                     ON      ubsk.id_bskBASKET=bsk.id
                     AND     ubsk.id_user=bsk.id_owner
                 WHERE       bsk.id_owner=%s
                 GROUP BY    ubsk.topic"""
     params = (uid,)
     res = run_sql(query, params)
     return res
 
 ########################## Actions on baskets #################################
 
 def get_basket_record(bskid, recid, format='hb'):
     """get record recid in basket bskid
     """
     if recid < 0:
         rec_table = 'bskEXTREC'
         format_table = 'bskEXTFMT'
         id_field = 'id_bskEXTREC'
         sign = '-'
     else:
         rec_table = 'bibrec'
         format_table = 'bibfmt'
         id_field = 'id_bibrec'
         sign = ''
     query = """
     SELECT DATE_FORMAT(record.creation_date, '%%%%Y-%%%%m-%%%%d %%%%H:%%%%i:%%%%s'),
            DATE_FORMAT(record.modification_date, '%%%%Y-%%%%m-%%%%d %%%%H:%%%%i:%%%%s'),
            DATE_FORMAT(bskREC.date_added, '%%%%Y-%%%%m-%%%%d %%%%H:%%%%i:%%%%s'),
            user.nickname,
            count(cmt.id_bibrec_or_bskEXTREC),
            DATE_FORMAT(max(cmt.date_creation), '%%%%Y-%%%%m-%%%%d %%%%H:%%%%i:%%%%s'),
            fmt.value
 
     FROM bskREC LEFT JOIN user
                 ON bskREC.id_user_who_added_item=user.id
                 LEFT JOIN bskRECORDCOMMENT cmt
                 ON bskREC.id_bibrec_or_bskEXTREC=cmt.id_bibrec_or_bskEXTREC
                 LEFT JOIN %(rec_table)s record
                 ON (%(sign)sbskREC.id_bibrec_or_bskEXTREC=record.id)
                 LEFT JOIN %(format_table)s fmt
                 ON (record.id=fmt.%(id_field)s)
 
     WHERE bskREC.id_bskBASKET=%%s AND
           bskREC.id_bibrec_or_bskEXTREC=%%s AND
           fmt.format=%%s
 
     GROUP BY bskREC.id_bibrec_or_bskEXTREC
     """ % {'rec_table': rec_table,
            'sign': sign,
            'format_table': format_table,
            'id_field':id_field}
     params = (int(bskid), int(recid), format)
     res = run_sql(query, params)
     if res:
         return __decompress_last(res[0])
     return ()
 
 def get_basket_content(bskid, format='hb'):
     """Get all records for a given basket."""
 
     query = """ SELECT      rec.id_bibrec_or_bskEXTREC,
                             extrec.collection_id,
                             count(cmt.id_bibrec_or_bskEXTREC),
                             DATE_FORMAT(max(cmt.date_creation), '%%Y-%%m-%%d %%H:%%i:%%s'),
                             extern.value as ext_val,
                             intern.value as int_val,
                             rec.score
 
                 FROM        bskREC AS rec
 
                 LEFT JOIN   bskRECORDCOMMENT AS cmt
                     ON     (rec.id_bibrec_or_bskEXTREC=cmt.id_bibrec_or_bskEXTREC
                     AND     rec.id_bskBASKET=cmt.id_bskBASKET)
 
                 LEFT JOIN   bskEXTFMT AS extern
                     ON     (-rec.id_bibrec_or_bskEXTREC=extern.id_bskEXTREC
                     AND     extern.format=%s)
 
                 LEFT JOIN   bibfmt AS intern
                     ON     (rec.id_bibrec_or_bskEXTREC=intern.id_bibrec
                     AND     intern.format=%s)
 
                 LEFT JOIN   bskEXTREC AS extrec
                     ON      extrec.id=-rec.id_bibrec_or_bskEXTREC
 
                 WHERE       rec.id_bskBASKET=%s
 
                 GROUP BY    rec.id_bibrec_or_bskEXTREC
 
                 ORDER BY    rec.score"""
 
     params = (format, format, int(bskid))
 
     res = run_sql(query, params)
 
     if res:
         query2 = "UPDATE bskBASKET SET nb_views=nb_views+1 WHERE id=%s"
         run_sql(query2, (int(bskid),))
         return res
     return ()
 
 def get_basket_item(bskid, recid, format='hb'):
     """Get item (recid) for a given basket."""
 
     query = """ SELECT      rec.id_bibrec_or_bskEXTREC,
                             extrec.collection_id,
                             count(cmt.id_bibrec_or_bskEXTREC),
                             DATE_FORMAT(max(cmt.date_creation), '%%Y-%%m-%%d %%H:%%i:%%s'),
                             extern.value as ext_val,
                             intern.value as int_val,
                             rec.score
                 FROM        bskREC rec
                 LEFT JOIN   bskRECORDCOMMENT cmt
                 ON          (rec.id_bibrec_or_bskEXTREC=cmt.id_bibrec_or_bskEXTREC
                              AND
                              rec.id_bskBASKET=cmt.id_bskBASKET)
                 LEFT JOIN   bskEXTFMT extern
                 ON          (-rec.id_bibrec_or_bskEXTREC=extern.id_bskEXTREC
                              AND
                              extern.format=%s)
                 LEFT JOIN   bibfmt intern
                 ON          (rec.id_bibrec_or_bskEXTREC=intern.id_bibrec
                              AND
                              intern.format=%s)
                 LEFT JOIN   bskEXTREC AS extrec
                     ON      extrec.id=-rec.id_bibrec_or_bskEXTREC
                 WHERE       rec.id_bskBASKET=%s
                 AND         rec.id_bibrec_or_bskEXTREC=%s
                 GROUP BY    rec.id_bibrec_or_bskEXTREC
                 ORDER BY    rec.score"""
     params = (format, format, bskid, recid)
     res = run_sql(query, params)
     if res:
         queryU = """UPDATE bskBASKET SET nb_views=nb_views+1 WHERE id=%s"""
         paramsU = (bskid,)
         run_sql(queryU, paramsU)
         score = res[0][6]
         query_previous = """SELECT      id_bibrec_or_bskEXTREC
                             FROM        bskREC
                             WHERE       id_bskBASKET=%s
                             AND         score<%s
                             ORDER BY    score   DESC
                             LIMIT 1"""
         params_previous = (bskid, score)
         res_previous = run_sql(query_previous, params_previous)
         query_next = """SELECT      id_bibrec_or_bskEXTREC
                         FROM        bskREC
                         WHERE       id_bskBASKET=%s
                         AND         score>%s
                         ORDER BY    score   ASC
                         LIMIT 1"""
         params_next = (bskid, score)
         res_next = run_sql(query_next, params_next)
         query_index = """   SELECT      COUNT(id_bibrec_or_bskEXTREC)
                             FROM        bskREC
                             WHERE       id_bskBASKET=%s
                             AND         score<=%s
                             ORDER BY    score"""
         params_index = (bskid, score)
         res_index = run_sql(query_index, params_index)
         res_index = __wash_sql_count(res_index)
         return (res[0], res_previous and res_previous[0][0] or 0, res_next and res_next[0][0] or 0, res_index)
     else:
         return ()
 
 def get_basket_item_title_and_URL(recid):
     """
     Retrieves the title and URL for the specified item in the specified basket.
 
     @param bskid: The basked id
     @type bskid: int
 
     @param recid: The record (item) id
     @type recid: int
 
     @return: A tuple containing the title as a sting and the URL as a string.
     """
 
     if recid > 0:
         # This is a local record, we can easily retrieve the title using the
         # search engine's get_fieldvalues function and the MARC field and tag.
         title_list = get_fieldvalues(recid, '245___')
         # Check if the main title is always the first element in the list
         if title_list:
             title = title_list[0]
         else:
             title = ""
         url = '%s/record/%i' % (CFG_SITE_URL, recid)
     elif recid < 0:
         # This is an external record or item, use 
         title = "This is an external record or item."
         url = '%s' % (CFG_SITE_URL,)
 
         query = """ SELECT  rec.collection_id,
                             rec.original_url,
                             fmt.value
                     FROM    bskEXTREC as rec,
                             bskEXTFMT as fmt
                     WHERE   rec.id=%s
                         AND fmt.id_bskEXTREC=%s
                         AND fmt.format='hb'"""
         params = (-recid, -recid)
         result = run_sql(query, params)
         if result:
             item = __decompress_last(result[0])
             collection = item[0]
             url = item[1]
             hb = item[2]
             if collection == 0:
                 # This is an external item
                 title = hb.split('\n',1)[0]
             elif collection > 0:
                 # This is an external record from a hosted collection
                 title = hb.split('</strong>',1)[0].split('<strong>')[-1]
 
     return (title, url)
 
 def share_basket_with_group(bskid, group_id,
                             share_level=CFG_WEBBASKET_SHARE_LEVELS['READITM']):
     """ Share basket bskid with group group_id with given share_level
     @param share_level:  see CFG_WEBBASKET_SHARE_LEVELS in webbasket_config
     """
     now = convert_datestruct_to_datetext(localtime())
     run_sql("""REPLACE INTO usergroup_bskBASKET
                  (id_usergroup, id_bskBASKET, date_shared, share_level)
                VALUES (%s,%s,%s,%s)""",
             (group_id, bskid, now, str(share_level)))
 
 def update_rights(bskid, group_rights):
     """update rights (permissions) for groups.
     @param bskid: basket id
     @param group_rights: dictionary of {group id: new rights}
     """
     now = convert_datestruct_to_datetext(localtime())
     query1 = """REPLACE INTO usergroup_bskBASKET
                        (id_usergroup, id_bskBASKET, date_shared, share_level)
                 VALUES """ + \
                 ', '.join(["(%s, %s, %s, %s)"] * len(group_rights.items()))
 
     params = ()
     for (group_id, share_level) in group_rights.items():
         params += (int(group_id), int(bskid), now, str(share_level))
 
     run_sql(query1, params)
     query2 = """DELETE FROM usergroup_bskBASKET WHERE share_level='NO'"""
     run_sql(query2)
 
 def move_item(bskid, recid, direction):
     """Change score of an item in a basket"""
     bskid = int(bskid)
     query1 = """SELECT id_bibrec_or_bskEXTREC,
                        score
                 FROM bskREC
                 WHERE id_bskBASKET=%s
                 ORDER BY score, date_added"""
     items = run_sql(query1, (bskid,))
     (recids, scores) = zip(*items)
     (recids, scores) = (list(recids), list(scores))
     if len(recids) and recid in recids:
         current_index = recids.index(recid)
         if direction == CFG_WEBBASKET_ACTIONS['UP']:
             switch_index = 0
             if current_index != 0:
                 switch_index = current_index -1
         else:
             switch_index = len(recids) - 1
             if current_index != len(recids)-1:
                 switch_index = current_index + 1
         query2 = """UPDATE bskREC
                     SET score=%s
                     WHERE id_bskBASKET=%s AND id_bibrec_or_bskEXTREC=%s"""
         res1 = run_sql(query2, (scores[switch_index], bskid, recids[current_index]))
         res2 = run_sql(query2, (scores[current_index], bskid, recids[switch_index]))
         if res1 and res2:
             now = convert_datestruct_to_datetext(localtime())
             query3 = "UPDATE bskBASKET SET date_modification=%s WHERE id=%s"
             params3 = (now, int(bskid))
             run_sql(query3, params3)
 
 def delete_item(bskid, recid, update_date_modification=True):
     """Remove item recid from basket bskid"""
 
     if recid < 0:
         query0A = "select count(id_bskBASKET) from bskREC where id_bibrec_or_bskEXTREC=%s" % (int(recid))
         ncopies = run_sql(query0A)
         if ncopies and ncopies[0][0]<=1:
             # uncomment the following 5 lines and comment the following 2 to delete cached records
             # only for external sources and not for external records
             #query0B = "SELECT collection_id FROM bskEXTREC WHERE id=%s" % (-int(recid))
             #colid = run_sql(query0B)
             #if colid and colid[0][0]==0:
                 #query0C = "DELETE from bskEXTFMT WHERE id_bskEXTREC=%s" % (-int(recid))
                 #run_sql(query0C)
             # the following two lines delete cached external records. We could keep them if we find
             # a way to reuse them in case the external records are added again in the future.
             query0D = "DELETE from bskEXTFMT WHERE id_bskEXTREC=%s" % (-int(recid))
             run_sql(query0D)
             query0E = "DELETE from bskEXTREC WHERE id=%s" % (-int(recid))
             run_sql(query0E)
     query_notes = "DELETE FROM bskRECORDCOMMENT WHERE id_bskBASKET=%s AND id_bibrec_or_bskEXTREC=%s"
     run_sql(query_notes, (bskid, recid,))
     query1 = "DELETE from bskREC WHERE id_bskBASKET=%s AND id_bibrec_or_bskEXTREC=%s"
     params1 = (int(bskid), int(recid))
     res = run_sql(query1, params1)
     if update_date_modification and res:
         now = convert_datestruct_to_datetext(localtime())
         query2 = "UPDATE bskBASKET SET date_modification=%s WHERE id=%s"
         params2 = (now, int(bskid))
         run_sql(query2, params2)
     return res
 
 def add_to_basket(uid,
                   recids=[],
                   colid=0,
                   bskid=0,
                   es_title="",
                   es_desc="",
                   es_url=""):
     """Add items (recids) basket (bskid)."""
 
     if (recids or (colid == -1 and es_title and es_desc and es_url)) and bskid > 0:
         query_max_score = """   SELECT   MAX(score)
                                 FROM     bskREC
                                 WHERE    id_bskBASKET=%s"""
         params_max_score = (bskid,)
         res_max_score = run_sql(query_max_score, params_max_score)
         max_score = __wash_sql_count(res_max_score)
         if not max_score:
             # max_score == None actually means that the basket doesn't exist.
             # Maybe we should return 0 and inform the admin?
             max_score = 1
 
         if colid > 0:
             query_existing = """    SELECT  id,
                                             external_id
                                     FROM    bskEXTREC
                                     WHERE   %s
                                     AND     collection_id=%s"""
             sep_or = ' OR '
             query_existing %= (sep_or.join(['external_id=%s'] * len(recids)), colid)
             params_existing = tuple(recids)
             res_existing = run_sql(query_existing, params_existing)
             existing_recids = [int(external_ids_couple[1]) for external_ids_couple in res_existing]
             existing_ids = [int(ids[0]) for ids in res_existing]
             new_recids = [recid for recid in recids if int(recid) not in existing_recids]
             # sets approach
             #existing_recids = [ids[1] for ids in res_existing]
             #new_recids = list(set(recids)-set(existing_recids))
             if new_recids:
                 query_new = """ INSERT INTO bskEXTREC (external_id,
                                                        collection_id,
                                                        creation_date,
                                                        modification_date)
                                 VALUES """
                 now = convert_datestruct_to_datetext(localtime())
                 records = ["(%s, %s, %s, %s)"] * len(new_recids)
                 query_new += ', '.join(records)
                 params_new = ()
                 for new_recid in new_recids:
                     params_new += (int(new_recid), colid, now, now)
                 res_new = run_sql(query_new, params_new)
                 recids = [-int(recid) for recid in existing_ids]
                 recids.extend(range(-res_new,-(res_new+len(new_recids)),-1))
             else:
                 recids = [-int(recid) for recid in existing_ids]
         elif colid < 0:
             query_external = """INSERT INTO bskEXTREC (collection_id,
                                                        original_url,
                                                        creation_date,
                                                        modification_date)
                                 VALUES      (%s, %s, %s, %s)"""
             now = convert_datestruct_to_datetext(localtime())
             params_external = (colid, es_url, now, now)
             res_external = run_sql(query_external, params_external)
             recids = [-res_external]
             store_external_source(res_external, es_title, es_desc, es_url, 'xm')
             store_external_source(res_external, es_title, es_desc, es_url, 'hb')
 
         query_insert = """  INSERT IGNORE INTO  bskREC
                                                 (id_bibrec_or_bskEXTREC,
                                                  id_bskBASKET,
                                                  id_user_who_added_item,
                                                  date_added,
                                                  score)
                             VALUES """
         if colid == 0 or (colid > 0 and not new_recids):
             now = convert_datestruct_to_datetext(localtime())
         records = ["(%s, %s, %s, %s, %s)"] * len(recids)
         query_insert += ', '.join(records)
         params_insert = ()
         i = 1
         for recid in recids:
             params_insert += (recid, bskid, uid, now, max_score + i)
             i += 1
         run_sql(query_insert, params_insert)
 
         query_update = """  UPDATE  bskBASKET
                             SET     date_modification=%s
                             WHERE   id=%s"""
         params_update = (now, bskid)
         run_sql(query_update, params_update)
         return recids
     return 0
 
 def add_to_many_baskets(uid, recids=[], colid=0, bskids=[], es_title="", es_desc="", es_url=""):
     """Add items recids to every basket in bskids list."""
     if (len(recids) or colid == -1) and len(bskids):
         query1 = """SELECT   id_bskBASKET,
                              max(score)
                     FROM     bskREC
                     WHERE    %s
                     GROUP BY id_bskBASKET"""
         bskids = [bskid for bskid in bskids if int(bskid) >= 0]
         sep_or = ' OR '
         query1 %= sep_or.join(['id_bskBASKET=%s'] * len(bskids))
         bsks = dict.fromkeys(bskids, 0)
         params = tuple(bskids)
         bsks.update(dict(run_sql(query1, params)))
 
         if colid > 0:
             query2A = """SELECT id,
                                 external_id
                          FROM   bskEXTREC
                          WHERE  %s
                          AND    collection_id=%s"""
             query2A %= (sep_or.join(['external_id=%s'] * len(recids)), colid)
             params2A = tuple(recids)
             res2A = run_sql(query2A, params2A)
             existing_recids = [int(external_ids_couple[1]) for external_ids_couple in res2A]
             existing_ids = [int(ids[0]) for ids in res2A]
             new_recids = [recid for recid in recids if int(recid) not in existing_recids]
             # sets approach
             #existing_recids = [ids[1] for ids in res2A]
             #new_recids = list(set(recids)-set(existing_recids))
-            f = open("/tmp/bsk_db", "w")
-            f.write(str(recids) + "\n" + str(existing_recids) + "\n" + str(existing_ids) + "\n" + str(new_recids) + "\n")
-            f.close()
             if new_recids:
                 query2B = """INSERT
                              INTO   bskEXTREC
                                    (external_id,
                                     collection_id,
                                     creation_date,
                                     modification_date)
                              VALUES """
                 now = convert_datestruct_to_datetext(localtime())
                 records = ["(%s, %s, %s, %s)"] * len(new_recids)
                 query2B += ', '.join(records)
                 params2B = ()
                 for new_recid in new_recids:
                     params2B += (int(new_recid), colid, now, now)
                 res = run_sql(query2B, params2B)
                 recids = [-int(recid) for recid in existing_ids]
                 recids.extend(range(-res,-(res+len(new_recids)),-1))
             else:
                 recids = [-int(recid) for recid in existing_ids]
         elif colid < 0:
             query2C = """INSERT
                         INTO bskEXTREC
                             (collection_id,
                             original_url,
                             creation_date,
                             modification_date)
                         VALUES (%s, %s, %s, %s)"""
             now = convert_datestruct_to_datetext(localtime())
             params = (colid, es_url, now, now)
             res = run_sql(query2C, params)
             recids = [-res]
             store_external_source(res, es_title, es_desc, es_url, 'xm')
             store_external_source(res, es_title, es_desc, es_url, 'hb')
 
         query2 = """INSERT IGNORE
                     INTO   bskREC
                            (id_bibrec_or_bskEXTREC,
                             id_bskBASKET,
                             id_user_who_added_item,
                             date_added,
                             score)
                     VALUES """
         if colid == 0 or (colid > 0 and not new_recids):
             now = convert_datestruct_to_datetext(localtime())
         records = ["(%s, %s, %s, %s, %s)"] * (len(recids) * len(bsks.items()))
         query2 += ', '.join(records)
         params = ()
         for (bskid, max_score) in bsks.items():
             i = 1
             for recid in recids:
                 params += (int(recid), int(bskid), int(uid), now, int(max_score) + i)
                 i += 1
         run_sql(query2, params)
 
         query3 = """UPDATE bskBASKET
                     SET    date_modification=%s
                     WHERE """
         query3 += sep_or.join(["id=%s"] * len(bskids))
         params = (now,) + tuple(bskids)
         run_sql(query3, params)
         return len(bskids)
     return 0
 
 def get_external_records_by_collection(recids):
     """Get the selected recids, both local and external, grouped by collection."""
 
     if recids:
         query = """ SELECT      GROUP_CONCAT(id),
                                 GROUP_CONCAT(external_id),
                                 collection_id
                     FROM        bskEXTREC
                     WHERE       %s
                     GROUP BY    collection_id"""
 
         recids = [-recid for recid in recids]
         sep_or = ' OR '
         query %= sep_or.join(['id=%s'] * len(recids))
         params = tuple(recids)
         res = run_sql(query,params)
         return res
     return 0
 
 def get_external_records(recids, of="hb"):
     """Get formatted external records from the database."""
 
     if recids:
         query = """ SELECT  rec.collection_id,
                             fmt.id_bskEXTREC,
                             fmt.value
                     FROM    bskEXTFMT AS fmt
                     JOIN    bskEXTREC AS rec
                         ON  rec.id=fmt.id_bskEXTREC
                     WHERE   format=%%s
                     AND     ( %s )"""
         recids = [-recid for recid in recids]
         sep_or = ' OR '
         query %= sep_or.join(['id_bskEXTREC=%s'] * len(recids))
         params = [of]
         params.extend(recids)
         params = tuple(params)
         res = run_sql(query,params)
         return res
     return ()
 
 def store_external_records(records, of="hb"):
     """Store formatted external records to the database."""
 
     if records:
         query = """INSERT
                     INTO bskEXTFMT
                         (id_bskEXTREC,
                         format,
                         last_updated,
                         value)
                     VALUES """
         now = convert_datestruct_to_datetext(localtime())
         formatted_records = ["(%s, %s, %s, %s)"] * len(records)
         query += ', '.join(formatted_records)
         params = ()
         for record in records:
             params += (record[0], of, now, compress(record[1]))
         run_sql(query,params)
 
 def store_external_urls(ids_urls):
     """Store original urls for external records to the database."""
 
     #for id_url in ids_urls.iteritems():
     for id_url in ids_urls:
         query = """UPDATE
                     bskEXTREC
                     SET original_url=%s
                     WHERE id=%s"""
         params = (id_url[1], id_url[0])
         run_sql(query,params)
 
 def store_external_source(es_id, es_title, es_desc, es_url, of="hb"):
     """Store formatted external sources to the database."""
 
     if es_id and es_title and es_desc:
         query = """INSERT INTO  bskEXTFMT
                                 (id_bskEXTREC,
                                  format,
                                  last_updated,
                                  value)
                     VALUES      (%s, %s, %s, %s)"""
         now = convert_datestruct_to_datetext(localtime())
         value = create_pseudo_record(es_title, es_desc, es_url, of)
         params = (es_id, of, now, compress(value))
         run_sql(query,params)
 
 def get_external_colid_and_url(recid):
     """Get the collection id and original url for an external record."""
 
     if recid:
         query = """SELECT
                     collection_id,
                     original_url
                     FROM bskEXTREC
                     WHERE id=%s"""
         params = (-recid,)
         res = run_sql(query,params)
         if res:
             return res
         else:
             return 0
 
 ############################ Group baskets ####################################
 
 def get_group_baskets_info_for_group(grpid):
     """Return information about every basket that belongs to the given group,
     provided the user is its manager or a member of it."""
 
     if not grpid:
         return ()
 
     query = """ SELECT      bsk.id,
                             bsk.name,
                             DATE_FORMAT(bsk.date_modification, '%%Y-%%m-%%d %%H:%%i:%%s'),
                             bsk.nb_views,
                             COUNT(rec.id_bibrec_or_bskEXTREC),
                             DATE_FORMAT(max(rec.date_added), '%%Y-%%m-%%d %%H:%%i:%%s'),
                             ugbsk.share_level,
                             bsk.id_owner
                 FROM        usergroup_bskBASKET AS ugbsk
                 JOIN        bskBASKET AS bsk
                     ON      bsk.id=ugbsk.id_bskBASKET
                 LEFT JOIN   bskREC AS rec
                     ON      rec.id_bskBASKET=bsk.id
                 WHERE       ugbsk.id_usergroup=%s
                 AND         ugbsk.share_level!='NO'
                 GROUP BY    bsk.id
                 ORDER BY    bsk.name"""
 
     params = (grpid,)
 
     res = run_sql(query, params)
 
     return res
 
 def get_group_name(gid):
     """Given its id return the group's name."""
 
     query = """ SELECT  name
                 FROM    usergroup
                 WHERE   id=%s"""
     params = (gid,)
     res = run_sql(query, params)
 
     return res
 
-def get_all_group_basket_ids_and_names_by_group(uid):
-    """For a given user return all their group baskets
-    (in tuples: (id, name)) grouped by group. Note that the
-    basket tuples have to evaluated to be converted to actual
-    tuples."""
+def get_all_user_group_basket_ids_by_group(uid):
+    """For a given user return all their group basket ids grouped by group."""
 
     query = """ SELECT      ug.id,
                             ug.name,
-                            count(bsk.id),
-                            GROUP_CONCAT('(', ugbsk.id_bskBASKET, ', \"', bsk.name, '\")'
-                                        ORDER BY bsk.name)
+                            GROUP_CONCAT(ugbsk.id_bskBASKET)
                 FROM        usergroup AS ug
                 JOIN        usergroup_bskBASKET AS ugbsk
                     ON      ugbsk.id_usergroup=ug.id
                 JOIN        bskBASKET AS bsk
                     ON      ugbsk.id_bskBASKET=bsk.id
                 JOIN        user_usergroup AS uug
                     ON      ug.id=uug.id_usergroup
                     AND     uug.id_user=%s
                 GROUP BY    ug.name
                 ORDER BY    ug.name"""
     params = (uid,)
     res = run_sql(query, params)
 
     return res
 
-def get_all_group_basket_ids_and_names_by_group_for_add_to_list(uid):
-    """For a given user return all their group baskets
-    (in tuples: (id, name)) grouped by group. Note that the
-    basket tuples have to evaluated to be converted to actual
-    tuples."""
+def get_all_user_group_basket_ids_by_group_with_add_rights(uid):
+    """For a given user return all their group basket ids grouped by group.
+    Return only the basket ids to which it is allowed to add records."""
 
     query = """ SELECT      ug.name,
-                            GROUP_CONCAT('(', ugbsk.id_bskBASKET, ', \"', bsk.name, '\")'
-                                        ORDER BY bsk.name)
+                            GROUP_CONCAT(ugbsk.id_bskBASKET)
                 FROM        usergroup AS ug
                 JOIN        usergroup_bskBASKET AS ugbsk
                     ON      ugbsk.id_usergroup=ug.id
                     AND     ugbsk.share_level!='NO'
                     AND     ugbsk.share_level!='RI'
                     AND     ugbsk.share_level!='RC'
                     AND     ugbsk.share_level!='AC'
                 JOIN        bskBASKET AS bsk
                     ON      ugbsk.id_bskBASKET=bsk.id
                 JOIN        user_usergroup AS uug
                     ON      ug.id=uug.id_usergroup
                     AND     uug.id_user=%s
                 GROUP BY    ug.name
                 ORDER BY    ug.name"""
     params = (uid,)
     res = run_sql(query, params)
 
     return res
 
 def get_all_group_baskets_names(uid,
                                 min_rights=CFG_WEBBASKET_SHARE_LEVELS['ADDCMT']):
     """For a given user returns every group baskets in which he can <min_rights>
     return a list of tuples: (bskid, bsk_name, group_name)."""
 
     # TODO: This function is no longer used. Delete if necessary.
     uid = int(uid)
     try:
         min_rights_num = CFG_WEBBASKET_SHARE_LEVELS_ORDERED.index(min_rights)
     except ValueError:
         return ()
     groups = get_groups_user_member_of(uid)
     if groups:
         where_clause = '('
         where_clause += " OR ".join(["ugbsk.id_usergroup=%s"] * len(groups))
         where_clause += ') AND ('
         where_clause += " OR ".join(["ugbsk.share_level=%s"] * len(CFG_WEBBASKET_SHARE_LEVELS_ORDERED[min_rights_num:]))
         where_clause += ")"
         query = """
         SELECT bsk.id,
                bsk.name,
                ug.name
         FROM usergroup ug JOIN usergroup_bskBASKET ugbsk
                           ON ug.id=ugbsk.id_usergroup
                           JOIN bskBASKET bsk
                           ON bsk.id=ugbsk.id_bskBASKET
         WHERE %s AND NOT(ugbsk.share_level='NO')
         ORDER BY ug.name""" % where_clause
         params = tuple([group_id for (group_id, dummy) in groups])
         params += tuple(CFG_WEBBASKET_SHARE_LEVELS_ORDERED[min_rights_num:])
         return run_sql(query, params)
     return ()
 
 def is_shared_to(bskids):
     """For each bskid in bskids get id of one of its group. Used to
     make distinction between private basket (no group), 'world' basket
     (0) or group basket (any int > 0)
     """
     if not((type(bskids) == list) or (type(bskids) == tuple)):
         bskids = [bskids]
     query = """SELECT b.id,
                       min(u.id_usergroup)
                FROM
                       bskBASKET b LEFT JOIN usergroup_bskBASKET u
                       ON (b.id=u.id_bskBASKET) """
     if len(bskids) != 0:
         query += " WHERE "
         query += " OR ".join(['b.id=%s'] * len(bskids))
     query += " GROUP BY b.id"
     params = tuple(bskids)
     res = run_sql(query, params)
     if res:
         return res
     return ()
 
 def get_basket_share_level(bskid):
     """Get the minimum share level of the basket (bskid).
     Returns:
         None for personal baskets
         positive integet for group baskets
         0 for public baskets
     Will return 0 if the basket is both group and publicly shared."""
 
     query = """ SELECT      MIN(ugbsk.id_usergroup)
                 FROM        bskBASKET AS bsk
                 LEFT JOIN   usergroup_bskBASKET AS ugbsk
                     ON      ugbsk.id_bskBASKET=bsk.id
                 WHERE       bsk.id=%s
                 GROUP BY    bsk.id"""
 
     params = (bskid,)
 
     res = run_sql(query, params)
 
     return res
 
 def get_all_items_in_user_group_baskets(uid,
                                         group=0,
                                         format='hb'):
     """For the specified user, return all the items in their group baskets,
     grouped by basket if local or as a list if external.
     If group is set, return only that group's items."""
 
     if group:
         group_clause = """AND     ugbsk.id_usergroup=%s"""
         params_local = (group, uid)
         params_external = (group, uid, format)
     else:
         group_clause = ""
         params_local = (uid,)
         params_external = (uid, format)
 
     query_local = """
                 SELECT      rec.id_bskBASKET,
                             bsk.name,
                             uug.id_usergroup,
                             ug.name,
                             ugbsk.share_level,
                             GROUP_CONCAT(rec.id_bibrec_or_bskEXTREC)
                 FROM        bskREC AS rec
                 JOIN        bskBASKET AS bsk
                     ON      bsk.id=rec.id_bskBASKET
                 JOIN        usergroup_bskBASKET AS ugbsk
                     ON      ugbsk.id_bskBASKET=rec.id_bskBASKET
                     %s
                 JOIN        user_usergroup AS uug
                     ON      uug.id_usergroup=ugbsk.id_usergroup
                     AND     uug.id_user=%%s
                 JOIN        usergroup AS ug
                     ON      ug.id=uug.id_usergroup
                 WHERE       rec.id_bibrec_or_bskEXTREC > 0
                 GROUP BY    rec.id_bskBASKET""" % (group_clause,)
 
     res_local = run_sql(query_local, params_local)
 
     query_external = """
                 SELECT      rec.id_bskBASKET,
                             bsk.name,
                             uug.id_usergroup,
                             ug.name,
                             ugbsk.share_level,
                             rec.id_bibrec_or_bskEXTREC,
                             ext.value
                 FROM        bskREC AS rec
                 JOIN        bskBASKET AS bsk
                     ON      bsk.id=rec.id_bskBASKET
                 JOIN        usergroup_bskBASKET AS ugbsk
                     ON      ugbsk.id_bskBASKET=rec.id_bskBASKET
                     %s
                 JOIN        user_usergroup AS uug
                     ON      uug.id_usergroup=ugbsk.id_usergroup
                     AND     uug.id_user=%%s
                 JOIN        usergroup AS ug
                     ON      ug.id=uug.id_usergroup
                 JOIN        bskEXTFMT AS ext
                     ON      ext.id_bskEXTREC=-rec.id_bibrec_or_bskEXTREC
                     AND     ext.format=%%s
                 WHERE       rec.id_bibrec_or_bskEXTREC < 0
                 ORDER BY    rec.id_bskBASKET""" % (group_clause,)
 
     res_external = run_sql(query_external, params_external)
 
     return (res_local, res_external)
 
 def get_all_items_in_user_group_baskets_by_matching_notes(uid,
                                                           group=0,
                                                           p=""):
     """For the specified user, return all the items in group personal baskets
     matching their notes' titles and bodies, grouped by basket.
     If topic is set, return only that topic's items."""
 
     p = p and '%' + p + '%' or '%'
 
     if group:
         group_clause = """AND     ugbsk.id_usergroup=%s"""
         params = (group, uid, p, p)
     else:
         group_clause = ""
         params = (uid, p, p)
 
     query = """ SELECT      notes.id_bskBASKET,
                             bsk.name,
                             uug.id_usergroup,
                             ug.name,
                             ugbsk.share_level,
                             GROUP_CONCAT(DISTINCT(notes.id_bibrec_or_bskEXTREC))
                 FROM        bskRECORDCOMMENT AS notes
                 JOIN        bskBASKET AS bsk
                     ON      bsk.id=notes.id_bskBASKET
                 JOIN        usergroup_bskBASKET AS ugbsk
                     ON      ugbsk.id_bskBASKET=notes.id_bskBASKET
                     AND     ugbsk.share_level IS NOT NULL
                     AND     ugbsk.share_level!='NO'
                     AND     ugbsk.share_level!='RI'
                     %s
                 JOIN        user_usergroup AS uug
                     ON      uug.id_usergroup=ugbsk.id_usergroup
                     AND     uug.id_user=%%s
                 JOIN        usergroup AS ug
                     ON      ug.id=uug.id_usergroup
                 WHERE       notes.title like %%s
                 OR          notes.body like %%s
                 GROUP BY    notes.id_bskBASKET""" % (group_clause,)
 
     res = run_sql(query, params)
 
     return res
 
 def is_group_basket_valid(uid, bskid):
     """Check if the basked (bskid) belongs to one of the groups the user (uid)
     is a member of and is valid."""
 
     query = """ SELECT  id
                 FROM    bskBASKET AS bsk
                 JOIN    usergroup_bskBASKET AS ugbsk
                     ON  ugbsk.id_bskBASKET=bsk.id
                 JOIN    user_usergroup AS uug
                     ON  uug.id_usergroup=ugbsk.id_usergroup
                     AND uug.id_user=%s
                 WHERE   id=%s"""
     params = (uid, bskid)
     res = run_sql(query, params)
 
     return res
 
 def is_group_valid(uid, group):
     """Check if the group exists and the user is a member or manager."""
 
     query = """ SELECT  id_usergroup
                 FROM    user_usergroup
                 WHERE   id_usergroup=%s
                 AND     id_user=%s"""
     params = (group, uid)
     res = run_sql(query, params)
 
     return res
 
 def get_all_user_groups(uid):
     """Return a list of the groups the user is a member of or manages."""
 
     query = """ SELECT      ug.id,
                             ug.name
                 FROM        user_usergroup AS uug
                 JOIN        usergroup AS ug
                     ON      ug.id=uug.id_usergroup
                 JOIN        usergroup_bskBASKET AS ugbsk
                     ON      ugbsk.id_usergroup=uug.id_usergroup
                 WHERE       uug.id_user=%s
                 GROUP BY    uug.id_usergroup"""
     params = (uid,)
     res = run_sql(query, params)
     return res
 
 ########################## External baskets ###################################
 
 def get_external_baskets_infos(uid):
     """Get general informations about every external basket user uid has subscribed to."""
     query = """
     SELECT bsk.id,
            bsk.name,
            DATE_FORMAT(bsk.date_modification, '%%Y-%%m-%%d %%H:%%i:%%s'),
            bsk.nb_views,
            count(rec.id_bibrec_or_bskEXTREC),
            DATE_FORMAT(max(rec.date_added), '%%Y-%%m-%%d %%H:%%i:%%s'),
            ugbsk.share_level
     FROM   bskBASKET bsk JOIN user_bskBASKET ubsk
                          ON (bsk.id=ubsk.id_bskBASKET AND ubsk.id_user=%s)
                          LEFT JOIN bskREC rec
                          ON (bsk.id=rec.id_bskBASKET)
                          LEFT JOIN usergroup_bskBASKET ugbsk
                          ON (ugbsk.id_bskBASKET=bsk.id AND ugbsk.id_usergroup=0)
 
     WHERE  bsk.id_owner!=%s
 
     GROUP BY bsk.id
     """
     uid = int(uid)
     params = (uid, uid)
     res = run_sql(query, params)
     if res:
         return res
     return ()
 
 def get_external_basket_info(bskid):
     """"""
 
     query = """ SELECT      bsk.id,
                             bsk.name,
                             DATE_FORMAT(bsk.date_modification, '%%Y-%%m-%%d %%H:%%i:%%s'),
                             bsk.nb_views,
                             count(rec.id_bibrec_or_bskEXTREC),
                             DATE_FORMAT(max(rec.date_added), '%%Y-%%m-%%d %%H:%%i:%%s'),
                             ugbsk.share_level
                 FROM        bskBASKET AS bsk
                 LEFT JOIN   bskREC AS rec
                 ON          bsk.id=rec.id_bskBASKET
                 JOIN        usergroup_bskBASKET AS ugbsk
                 ON          bsk.id=ugbsk.id_bskBASKET
                 AND         ugbsk.id_usergroup=0
                 WHERE       id=%s"""
     params = (bskid,)
     res = run_sql(query, params)
 
     return res
 
 def get_all_external_basket_ids_and_names(uid):
     """For a given user return all their external baskets
     (in tuples: (id, name, number_of_records))."""
 
     query = """ SELECT      bsk.id,
                             bsk.name,
                             count(rec.id_bibrec_or_bskEXTREC),
                             ugbsk.id_usergroup
                 FROM        user_bskBASKET AS ubsk
                 JOIN        bskBASKET AS bsk
                     ON      ubsk.id_bskBASKET=bsk.id
                     AND     ubsk.id_user!=bsk.id_owner
                 LEFT JOIN   bskREC AS rec
                     ON      ubsk.id_bskBASKET=rec.id_bskBASKET
                 LEFT JOIN   usergroup_bskBASKET AS ugbsk
                     ON      ugbsk.id_usergroup=0
                     AND     ugbsk.id_bskBASKET=bsk.id
                 WHERE       ubsk.id_user=%s
                 GROUP BY    bsk.id
                 ORDER BY    bsk.name"""
     params = (uid,)
     res = run_sql(query, params)
 
     return res
 
 def count_external_baskets(uid):
     """Returns the number of external baskets the user is subscribed to."""
 
     query = """ SELECT      COUNT(ubsk.id_bskBASKET)
                 FROM        user_bskBASKET ubsk
                 LEFT JOIN   bskBASKET bsk
                     ON      (bsk.id=ubsk.id_bskBASKET AND ubsk.id_user=%s)
                 WHERE       bsk.id_owner!=%s"""
 
     params = (int(uid), int(uid))
 
     res = run_sql(query, params)
 
     return __wash_sql_count(res)
 
 def get_all_external_baskets_names(uid,
                                    min_rights=CFG_WEBBASKET_SHARE_LEVELS['ADDCMT']):
 
     """ for a given user returns every basket which he has subscribed to and in which
     he can <min_rights>
     return a list of tuples: (bskid, bsk_name)
     """
     uid = int(uid)
     try:
         min_rights_num = CFG_WEBBASKET_SHARE_LEVELS_ORDERED.index(min_rights)
     except ValueError:
         return ()
     where_clause = ' AND ('
     for right in CFG_WEBBASKET_SHARE_LEVELS_ORDERED[min_rights_num:-1]:
         where_clause += "ugbsk.share_level = '%s' OR " % right
     where_clause += "ugbsk.share_level = '%s')" % CFG_WEBBASKET_SHARE_LEVELS_ORDERED[-1]
     query = """
     SELECT bsk.id,
            bsk.name
     FROM bskBASKET bsk JOIN usergroup_bskBASKET ugbsk
                        ON bsk.id=ugbsk.id_bskBASKET
                        JOIN user_bskBASKET ubsk
                        ON ubsk.id_bskBASKET=bsk.id
     WHERE ugbsk.id_usergroup=0 AND
           ubsk.id_user=%s AND
           NOT(bsk.id_owner=%s) AND
           NOT(ugbsk.share_level='NO')
     """ + where_clause
 
     params = (uid, uid)
     return run_sql(query, params)
 
 def get_all_items_in_user_public_baskets(uid,
                                         format='hb'):
     """For the specified user, return all the items in the public baskets they
     are subscribed to, grouped by basket if local or as a list if external."""
 
     query_local = """
                 SELECT      rec.id_bskBASKET,
                             bsk.name,
                             ugbsk.share_level,
                             GROUP_CONCAT(rec.id_bibrec_or_bskEXTREC)
                 FROM        bskREC AS rec
                 JOIN        bskBASKET AS bsk
                     ON      bsk.id=rec.id_bskBASKET
                     AND     bsk.id_owner!=%s
                 JOIN        user_bskBASKET AS ubsk
                     ON      ubsk.id_bskBASKET=rec.id_bskBASKET
                     AND     ubsk.id_user=%s
                 JOIN        usergroup_bskBASKET AS ugbsk
                     ON      ugbsk.id_bskBASKET=rec.id_bskBASKET
                     AND     ugbsk.id_usergroup=0
                 WHERE       rec.id_bibrec_or_bskEXTREC > 0
                 GROUP BY    rec.id_bskBASKET"""
 
     params_local = (uid, uid)
 
     res_local = run_sql(query_local, params_local)
 
     query_external = """
                 SELECT      rec.id_bskBASKET,
                             bsk.name,
                             ugbsk.share_level,
                             rec.id_bibrec_or_bskEXTREC,
                             ext.value
                 FROM        bskREC AS rec
                 JOIN        bskBASKET AS bsk
                     ON      bsk.id=rec.id_bskBASKET
                     AND     bsk.id_owner!=%s
                 JOIN        user_bskBASKET AS ubsk
                     ON      ubsk.id_bskBASKET=rec.id_bskBASKET
                     AND     ubsk.id_user=%s
                 JOIN        usergroup_bskBASKET AS ugbsk
                     ON      ugbsk.id_bskBASKET=rec.id_bskBASKET
                     AND     ugbsk.id_usergroup=0
                 JOIN        bskEXTFMT AS ext
                     ON      ext.id_bskEXTREC=-rec.id_bibrec_or_bskEXTREC
                     AND     ext.format=%s
                 WHERE       rec.id_bibrec_or_bskEXTREC < 0
                 ORDER BY    rec.id_bskBASKET"""
 
     params_external = (uid, uid, format)
 
     res_external = run_sql(query_external, params_external)
 
     return (res_local, res_external)
 
 def get_all_items_in_user_public_baskets_by_matching_notes(uid,
                                                            p=""):
     """For the specified user, return all the items in the public baskets they
     are subscribed to, matching their notes' titles and bodies,
     grouped by basket"""
 
     p = p and '%' + p + '%' or '%'
 
     query = """ SELECT      notes.id_bskBASKET,
                             bsk.name,
                             ugbsk.share_level,
                             GROUP_CONCAT(DISTINCT(notes.id_bibrec_or_bskEXTREC))
                 FROM        bskRECORDCOMMENT AS notes
                 JOIN        bskBASKET AS bsk
                     ON      bsk.id=notes.id_bskBASKET
                     AND     bsk.id_owner!=%s
                 JOIN        user_bskBASKET AS ubsk
                     ON      ubsk.id_bskBASKET=notes.id_bskBASKET
                     AND     ubsk.id_user=%s
                 JOIN        usergroup_bskBASKET AS ugbsk
                     ON      ugbsk.id_bskBASKET=notes.id_bskBASKET
                     AND     ugbsk.id_usergroup=0
                     AND     ugbsk.share_level IS NOT NULL
                     AND     ugbsk.share_level!='NO'
                     AND     ugbsk.share_level!='RI'
                 WHERE       notes.title like %s
                 OR          notes.body like %s
                 GROUP BY    notes.id_bskBASKET"""
 
     params = (uid, uid, p, p)
 
     res = run_sql(query, params)
 
     return res
 
 def get_all_items_in_all_public_baskets(format='hb'):
     """Return all the items in all the public baskets,
     grouped by basket if local or as a list if external."""
 
     query_local = """
                 SELECT      rec.id_bskBASKET,
                             bsk.name,
                             ugbsk.share_level,
                             GROUP_CONCAT(rec.id_bibrec_or_bskEXTREC)
                 FROM        bskREC AS rec
                 JOIN        bskBASKET AS bsk
                     ON      bsk.id=rec.id_bskBASKET
                 JOIN        usergroup_bskBASKET AS ugbsk
                     ON      ugbsk.id_bskBASKET=rec.id_bskBASKET
                     AND     ugbsk.id_usergroup=0
                 WHERE       rec.id_bibrec_or_bskEXTREC > 0
                 GROUP BY    rec.id_bskBASKET"""
 
     res_local = run_sql(query_local)
 
     query_external = """
                 SELECT      rec.id_bskBASKET,
                             bsk.name,
                             ugbsk.share_level,
                             rec.id_bibrec_or_bskEXTREC,
                             ext.value
                 FROM        bskREC AS rec
                 JOIN        bskBASKET AS bsk
                     ON      bsk.id=rec.id_bskBASKET
                 JOIN        usergroup_bskBASKET AS ugbsk
                     ON      ugbsk.id_bskBASKET=rec.id_bskBASKET
                     AND     ugbsk.id_usergroup=0
                 JOIN        bskEXTFMT AS ext
                     ON      ext.id_bskEXTREC=-rec.id_bibrec_or_bskEXTREC
                     AND     ext.format=%s
                 WHERE       rec.id_bibrec_or_bskEXTREC < 0
                 ORDER BY    rec.id_bskBASKET"""
 
     params_external = (format,)
 
     res_external = run_sql(query_external, params_external)
 
     return (res_local, res_external)
 
 def get_all_items_in_all_public_baskets_by_matching_notes(p=""):
     """Return all the items in all the public baskets matching
     their notes' titles and bodies, grouped by basket"""
 
     p = p and '%' + p + '%' or '%'
 
     query = """ SELECT      notes.id_bskBASKET,
                             bsk.name,
                             ugbsk.share_level,
                             GROUP_CONCAT(DISTINCT(notes.id_bibrec_or_bskEXTREC))
                 FROM        bskRECORDCOMMENT AS notes
                 JOIN        bskBASKET AS bsk
                     ON      bsk.id=notes.id_bskBASKET
                 JOIN        usergroup_bskBASKET AS ugbsk
                     ON      ugbsk.id_bskBASKET=notes.id_bskBASKET
                     AND     ugbsk.id_usergroup=0
                     AND     ugbsk.share_level IS NOT NULL
                     AND     ugbsk.share_level!='NO'
                     AND     ugbsk.share_level!='RI'
                 WHERE       notes.title like %s
                 OR          notes.body like %s
                 GROUP BY    notes.id_bskBASKET"""
 
     params = (p, p)
 
     res = run_sql(query, params)
 
     return res
 
 ############################ Public access ####################################
 
 def get_public_basket_infos(bskid):
     """return (id, name, date modification, nb of views, id of owner, nickname of owner, rights for public access)
     for a given basket"""
     basket = []
     query1 = """SELECT bsk.id,
                        bsk.name,
                        DATE_FORMAT(bsk.date_modification, '%%Y-%%m-%%d %%H:%%i:%%s'),
                        bsk.nb_views,
                        bsk.id_owner,
                        user.nickname
                 FROM bskBASKET bsk LEFT JOIN user
                                    ON bsk.id_owner=user.id
                 WHERE bsk.id=%s"""
     res1 = run_sql(query1, (int(bskid),))
     if len(res1):
         basket = list(res1[0])
         query2 = """SELECT share_level
                     FROM usergroup_bskBASKET
                     WHERE id_usergroup=0 and id_bskBASKET=%s"""
         res2 = run_sql(query2, (int(bskid),))
         if res2:
             basket.append(res2[0][0])
         else:
             basket.append(None)
     return basket
 
 def get_public_basket_info(bskid):
     """Return information about a given public basket."""
 
     query = """ SELECT      bsk.id,
                             bsk.name,
                             bsk.id_owner,
                             DATE_FORMAT(bsk.date_modification, '%%Y-%%m-%%d %%H:%%i:%%s'),
                             bsk.nb_views,
                             COUNT(rec.id_bibrec_or_bskEXTREC),
                             GROUP_CONCAT(rec.id_bibrec_or_bskEXTREC),
                             ubsk.share_level
                 FROM        bskBASKET AS bsk
                 LEFT JOIN   bskREC AS rec
                     ON      rec.id_bskBASKET=bsk.id
                 JOIN        usergroup_bskBASKET AS ubsk
                     ON      ubsk.id_bskBASKET=bsk.id
                     AND     ubsk.id_usergroup=0
                 WHERE       bsk.id=%s
                 GROUP BY    bsk.id;"""
 
     params = (bskid,)
 
     res = run_sql(query, params)
 
     return res
 
 def get_basket_general_infos(bskid):
     """return information about a basket, suited for public access.
     @return: a (id, name, date of modification, nb of views, nb of records, id of owner) tuple
     """
     query = """SELECT bsk.id,
                       bsk.name,
                       DATE_FORMAT(bsk.date_modification, '%%Y-%%m-%%d %%H:%%i:%%s'),
                       bsk.nb_views,
                       count(rec.id_bibrec_or_bskEXTREC),
                       bsk.id_owner
 
     FROM   bskBASKET bsk LEFT JOIN bskREC rec
                          ON bsk.id=rec.id_bskBASKET
     WHERE bsk.id=%s
 
     GROUP BY bsk.id"""
     res = run_sql(query, (int(bskid),))
     if res:
         query2 = "UPDATE bskBASKET SET nb_views=nb_views+1 WHERE id=%s"
         run_sql(query2, (int(bskid),))
         return res[0]
     return ()
 
 def get_basket_owner_id(bskid):
     """Return the uid of the owner."""
     query = """SELECT id_owner
                  FROM bskBASKET
                 WHERE id=%s"""
     res = run_sql(query, (bskid, ))
     if res:
         return res[0][0]
     return -1
 
 def count_public_baskets():
     """Returns the number of public baskets."""
 
     query = """ SELECT  COUNT(id_bskBASKET)
                 FROM    usergroup_bskBASKET
                 WHERE   id_usergroup=0"""
 
     res = run_sql(query)
 
     return __wash_sql_count(res)
 
 def get_public_baskets_list(inf_limit, max_number, order=1, asc=1):
     """Return list of public baskets
     @param inf_limit: limit to baskets from number x
     @param max_number: number of baskets to return
     @order: 1: order by name of basket, 2: number of views, 3: owner
     @return:
     [(basket id, basket name, nb of views, uid of owner, nickname of owner)]"""
 
     query = """SELECT bsk.id,
                       bsk.name,
                       bsk.nb_views,
                       u.id,
                       u.nickname
                FROM   bskBASKET bsk LEFT JOIN usergroup_bskBASKET ugbsk
                                     on bsk.id=ugbsk.id_bskBASKET
                                     LEFT JOIN user u
                                     on bsk.id_owner=u.id
                WHERE ugbsk.id_usergroup=0
     """
     if order == 2:
         query += 'ORDER BY bsk.nb_views'
     elif order == 3:
         query += 'ORDER BY u.nickname'
         if asc:
             query += ' ASC'
         else:
             query += ' DESC'
         query += ', u.id'
     else:
         query += 'ORDER BY bsk.name'
     if asc:
         query += ' ASC '
     else:
         query += ' DESC '
     query += "LIMIT %s,%s"
 
     return run_sql(query, (inf_limit, max_number))
 
 def count_all_public_baskets():
     """Return the number of all the public baskets."""
 
     query = """ SELECT  count(id_bskBASKET)
                 FROM    usergroup_bskBASKET
                 WHERE   id_usergroup=0"""
 
     res = run_sql(query)
 
     return __wash_sql_count(res)
 
 def get_list_public_baskets(page, max_number, sort='name', asc=1):
     """Return list of public baskets
     @param page: limit to baskets from number x
     @param max_number: maximum number of baskets to return
     @sort: 1: order by name of basket, 2: number of views, 3: owner
     @return:
     [(basket id, basket name, nb of views, uid of owner, nickname of owner)]"""
 
     query = """ SELECT      bsk.id,
                             bsk.name,
                             bsk.id_owner,
                             u.nickname,
                             DATE_FORMAT(bsk.date_modification, '%%Y-%%m-%%d %%H:%%i:%%s'),
                             COUNT(rec.id_bibrec_or_bskEXTREC) AS items,
                             bsk.nb_views
                 FROM        usergroup_bskBASKET AS ugbsk
                 JOIN        bskBASKET AS bsk
                     ON      bsk.id=ugbsk.id_bskBASKET
                 LEFT JOIN   bskREC AS rec
                     ON      rec.id_bskBASKET=bsk.id
                 LEFT JOIN   user AS u
                     ON      u.id=bsk.id_owner
                 WHERE       ugbsk.id_usergroup=0
                 GROUP BY    bsk.id"""
 
     if sort == 'name':
         query += """
                 ORDER BY bsk.name"""
     elif sort == 'owner':
         query += """
                 ORDER BY u.nickname"""
     elif sort == 'views':
         query += """
                 ORDER BY bsk.nb_views"""
     elif sort == 'date':
         query += """
                 ORDER BY bsk.date_modification"""
     elif sort == 'items':
         query += """
                 ORDER BY items"""
     else:
         query += """
                 ORDER BY bsk.name"""
     if asc:
         query += """ ASC"""
         if sort == """owner""":
             query += """, u.id"""
     else:
         query += """ DESC"""
         if sort == """owner""":
             query += """, u.id"""
 
     query += """
                 LIMIT %s, %s"""
 
     page = max(0, page)
 
     res = run_sql(query, (page, max_number))
 
     return res
 
 def is_basket_public(bskid):
     """Check if the given basket is public.
     Returns ((0,),) if False, ((1,),) if True."""
 
     query = """ SELECT  COUNT(*)
                 FROM    usergroup_bskBASKET
                 WHERE   id_usergroup=0
                 AND     id_bskBASKET=%s"""
 
     params = (bskid,)
 
     res = run_sql(query, params)
 
     return __wash_sql_count(res)
 
 def subscribe(uid, bskid):
     """Subscribe the given user to the given basket."""
 
     query1 = """SELECT  COUNT(*)
                 FROM    user_bskBASKET
                 WHERE   id_user=%s
                 AND     id_bskBASKET=%s"""
 
     params1 = (uid, bskid)
 
     res1 = run_sql(query1, params1)
 
     if res1[0][0]:
         # The user is either the owner of the basket or is already subscribed.
         return False
     else:
         query2 = """INSERT INTO user_bskBASKET (id_user, id_bskBASKET)
                                    VALUES      (%s, %s)"""
 
         params2 = (uid, bskid)
 
         run_sql(query2, params2)
 
         return True
 
 def unsubscribe(uid, bskid):
     """Unsubscribe the given user from the given basket."""
 
     query1 = """SELECT  COUNT(*)
                 FROM    bskBASKET
                 WHERE   id_owner=%s
                 AND     id=%s"""
 
     params1 = (uid, bskid)
 
     res1 = run_sql(query1, params1)
 
     if res1[0][0]:
         # The user is the owner of the basket.
         return False
     else:
         query2 = """DELETE FROM user_bskBASKET
                     WHERE       id_user=%s
                     AND         id_bskBASKET=%s"""
 
         params2 = (uid, bskid)
 
         res2 = run_sql(query2, params2)
 
         if res2:
             return True
         else:
             return False
 
 def is_user_subscribed_to_basket(uid, bskid):
     """Return ((1,),) if the user is subscribed to the given basket
     or ((0,),) if the user is not subscribed or is the owner of the basket."""
 
     query = """ SELECT  COUNT(ubsk.id_bskBASKET)
                 FROM    user_bskBASKET AS ubsk
                 JOIN    bskBASKET AS bsk
                     ON  bsk.id=ubsk.id_bskBASKET
                     AND bsk.id_owner!=ubsk.id_user
                 WHERE   ubsk.id_user=%s
                 AND     ubsk.id_bskBASKET=%s"""
 
     params = (uid, bskid)
 
     res = run_sql(query, params)
 
     return __wash_sql_count(res)
 
 def count_subscribers(uid, bskid):
     """Returns a (number of users, number of groups, number of alerts) tuple
     for the given user (uid) and basket (bskid)."""
 
     uid = int(uid)
     bskid = int(bskid)
 
     query_groups = """  SELECT      count(id_usergroup)
                         FROM        usergroup_bskBASKET
                         WHERE       id_bskBASKET=%s
                         AND         NOT(share_level='NO')
                         GROUP BY    id_bskBASKET"""
     params_groups = (bskid,)
     res_groups = run_sql(query_groups, params_groups)
     nb_groups = __wash_sql_count(res_groups)
 
     query_users = """   SELECT      count(id_user)
                         FROM        user_bskBASKET
                         WHERE       id_bskBASKET=%s
                         AND         id_user!=%s
                         GROUP BY    id_bskBASKET"""
     params_users = (bskid, uid)
     res_users = run_sql(query_users, params_users)
     nb_users = __wash_sql_count(res_users)
 
     query_alerts = """  SELECT      count(id_query)
                         FROM        user_query_basket
                         WHERE       id_basket=%s
                         GROUP BY    id_basket"""
     params_alerts = (bskid,)
     res_alerts = run_sql(query_alerts, params_alerts)
     nb_alerts = __wash_sql_count(res_alerts)
     return (nb_users, nb_groups, nb_alerts)
 
 def get_groups_subscribing_to_basket(bskid):
     """ get list of (group id, group name, rights) tuples for a given basket
     Please note that group 0 is used to mean everybody.
     """
     query = """SELECT ugb.id_usergroup,
                       ug.name,
                       ugb.share_level
                FROM usergroup_bskBASKET ugb LEFT JOIN usergroup ug
                                             ON ugb.id_usergroup=ug.id
                WHERE ugb.id_bskBASKET=%s
                ORDER BY ugb.id_usergroup"""
     return run_sql(query, (int(bskid),))
 
 def get_rights_on_public_basket(bskid):
     """"""
 
     query = """ SELECT  share_level
                 FROM    usergroup_bskBASKET
                 WHERE   id_usergroup=0
                 AND     id_bskBASKET=%s"""
 
     params = (bskid,)
 
     res = run_sql(query, params)
 
     return res
 
 def count_public_basket_subscribers(bskid):
     """Return the number of users subscribed to the given public basket."""
 
     query = """ SELECT  COUNT(ubsk.id_user)
                 FROM    user_bskBASKET AS ubsk
                 JOIN    bskBASKET AS bsk
                     ON  bsk.id=ubsk.id_bskBASKET
                     AND bsk.id_owner!=ubsk.id_user
                 WHERE   ubsk.id_bskBASKET=%s"""
 
     params = (bskid,)
 
     res = run_sql(query, params)
 
     return __wash_sql_count(res)
 
 ################################ Notes ########################################
 
 def get_notes(bskid, recid):
     """Return all comments for record recid in basket bskid."""
 
     query = """
     SELECT user.id,
            user.nickname,
            bskcmt.title,
            bskcmt.body,
            DATE_FORMAT(bskcmt.date_creation, '%%Y-%%m-%%d %%H:%%i:%%s'),
            bskcmt.priority,
            bskcmt.id,
            bskcmt.in_reply_to_id_bskRECORDCOMMENT
 
     FROM   bskRECORDCOMMENT bskcmt LEFT JOIN user
                                    ON (bskcmt.id_user=user.id)
 
     WHERE  bskcmt.id_bskBASKET=%s AND
            bskcmt.id_bibrec_or_bskEXTREC=%s
 
     ORDER BY bskcmt.reply_order_cached_data
     """
     bskid = int(bskid)
     recid = int(recid)
     res = run_sql(query, (bskid, recid))
     if res:
         return res
     else:
         return ()
 
 def get_note(cmtid):
     """Return comment cmtid as a (author's nickname, author's uid, title, body, date of creation, priority) tuple"""
     out = ()
     query = """
     SELECT user.nickname,
            user.id,
            bskcmt.title,
            bskcmt.body,
            DATE_FORMAT(bskcmt.date_creation, '%%Y-%%m-%%d %%H:%%i:%%s'),
            bskcmt.priority
 
     FROM   bskRECORDCOMMENT bskcmt LEFT JOIN user
                                    ON (bskcmt.id_user=user.id)
 
     WHERE  bskcmt.id=%s
     """
     cmtid = int(cmtid)
     res = run_sql(query, (cmtid,))
     if res:
         return res[0]
     return out
 
 def save_note(uid, bskid, recid, title, body, reply_to=None):
     """Save then given note (title, body) on the given item in the given basket."""
     if reply_to and CFG_WEBBASKET_MAX_COMMENT_THREAD_DEPTH >= 0:
         # Check that we have not reached max depth
         note_ancestors = get_note_ancestors(reply_to)
         if len(note_ancestors) >= CFG_WEBBASKET_MAX_COMMENT_THREAD_DEPTH:
             if CFG_WEBBASKET_MAX_COMMENT_THREAD_DEPTH == 0:
                 reply_to = None
             else:
                 reply_to = note_ancestors[CFG_WEBBASKET_MAX_COMMENT_THREAD_DEPTH - 1]
 
     date = convert_datestruct_to_datetext(localtime())
     res = run_sql("""INSERT INTO bskRECORDCOMMENT (id_user, id_bskBASKET,
                        id_bibrec_or_bskEXTREC, title, body, date_creation, in_reply_to_id_bskRECORDCOMMENT)
                      VALUES (%s, %s, %s, %s, %s, %s, %s)""",
                   (int(uid), int(bskid), int(recid), title, body, date, reply_to or 0))
     if res:
         new_comid = int(res)
         parent_reply_order = run_sql("""SELECT reply_order_cached_data from bskRECORDCOMMENT where id=%s""", (reply_to,))
         if not parent_reply_order or parent_reply_order[0][0] is None:
             parent_reply_order = ''
         else:
             parent_reply_order = parent_reply_order[0][0]
         run_sql("""UPDATE bskRECORDCOMMENT SET reply_order_cached_data=%s WHERE id=%s""",
                 (parent_reply_order + get_reply_order_cache_data(new_comid), new_comid))
         return int(res)
     return 0
 
 def delete_note(bskid, recid, cmtid):
     """Delete a comment on an item of a basket"""
 
     query = """ DELETE
                 FROM    bskRECORDCOMMENT
                 WHERE   id_bskBASKET=%s
                 AND     id_bibrec_or_bskEXTREC=%s
                 AND     id=%s"""
 
     params = (int(bskid), int(recid), int(cmtid))
 
     run_sql(query, params)
 
 def get_note_ancestors(cmtid, depth=None):
     """
     Returns the list of ancestors of the given note, ordered from
     oldest to newest ("top-down": direct parent of cmtid is at last position),
     up to given depth
 
     @param cmtid: the ID of the note for which we want to retrieve ancestors
     @type cmtid: int
     @param depth: the maximum of levels up from the given note we
                   want to retrieve ancestors. None for no limit, 1 for
                   direct parent only, etc.
     @type depth: int
     @return the list of ancestors
     @rtype: list
     """
     if depth == 0:
         return []
 
     res = run_sql("SELECT in_reply_to_id_bskRECORDCOMMENT FROM bskRECORDCOMMENT WHERE id=%s", (cmtid,))
     if res:
         parent_cmtid = res[0][0]
         if parent_cmtid == 0:
             return []
         parent_ancestors = []
         if depth:
             depth -= 1
         parent_ancestors = get_note_ancestors(parent_cmtid, depth)
         parent_ancestors.append(parent_cmtid)
         return parent_ancestors
     else:
         return []
 
 def note_belongs_to_item_in_basket_p(cmtid, recid, bskid):
     """Returns 1 (True) if the given note (cmtid) belongs to the given item
     (recid) and the given basket (bskid) or 0 (False)."""
 
     query = """ SELECT  COUNT(*)
                 FROM    bskRECORDCOMMENT
                 WHERE   id=%s
                 AND     id_bibrec_or_bskEXTREC=%s
                 AND     id_bskBASKET=%s"""
 
     params = (cmtid, recid, bskid)
 
     res = run_sql(query, params)
 
     return __wash_sql_count(res)
 
 def get_number_of_notes_per_record_in_basket(bskid, recids):
     """Returns the number of comments per record
     for all the given records in the given basket"""
 
     # We need to convert the list of recids into a string of commma separated
     # numbers (recids), instead of a tuple, to cover the case where we have
     # single element lists of recids. Example:
     # [1] --> '1' instaed of [1] --> (1,)
     # Single element tuples would cause the query to fail due to the syntax.
     query = """ SELECT      rec.id_bibrec_or_bskEXTREC,
                             COUNT(cmt.id_bibrec_or_bskEXTREC)
                 FROM        bskREC as rec
                 LEFT JOIN   bskRECORDCOMMENT as cmt
                     ON      cmt.id_bibrec_or_bskEXTREC = rec.id_bibrec_or_bskEXTREC
                 WHERE       rec.id_bskBASKET=%%s
                     AND     rec.id_bibrec_or_bskEXTREC IN (%s)
                 GROUP BY    id_bibrec_or_bskEXTREC
                 ORDER BY    rec.score""" % (str(map(int, recids))[1:-1],)
 
     params = (bskid,)
 
     result = run_sql(query, params)
 
     return result
 
 ########################## Usergroup functions ################################
 
 def get_group_infos(uid):
     """For each group the user with uid is a member of return the id, name and number of baskets."""
     query = """SELECT g.id,
                       g.name,
                       count(ugb.id_bskBASKET)
                FROM usergroup g LEFT JOIN (user_usergroup ug,
                                            usergroup_bskBASKET ugb)
                                 ON (g.id=ug.id_usergroup
                                             AND
                                     g.id=ugb.id_usergroup)
                WHERE ug.id_user=%s AND NOT(ugb.share_level='NO') AND ug.user_status!=%s
                GROUP BY g.id
                ORDER BY g.name"""
     params = (int(uid), CFG_WEBSESSION_USERGROUP_STATUS['PENDING'])
     res = run_sql(query, params)
     return res
 
 def count_groups_user_member_of(uid):
     """Returns the number of groups the user has joined."""
 
     query = """ SELECT  COUNT(id_usergroup)
                 FROM    user_usergroup
                 WHERE   id_user=%s
                 AND     user_status!=%s"""
 
     params = (int(uid), CFG_WEBSESSION_USERGROUP_STATUS['PENDING'])
 
     res = run_sql(query, params)
 
     return __wash_sql_count(res)
 
 def get_groups_user_member_of(uid):
     """
     Get uids and names of groups user is member of.
     @param uid: user id (int)
     @return: a tuple of (group_id, group_name) tuples
     """
     query = """
     SELECT g.id,
            g.name
     FROM usergroup g JOIN user_usergroup ug
                    ON (g.id=ug.id_usergroup)
     WHERE ug.id_user=%s and ug.user_status!=%s
     ORDER BY g.name
     """
     params = (int(uid), CFG_WEBSESSION_USERGROUP_STATUS['PENDING'])
     res = run_sql(query, params)
     if res:
         return res
     return ()
 
 ########################## auxilliary functions ###############################
 
 def __wash_sql_count(res):
     """Wash the result of SQL COUNT function and return only an integer."""
     if res:
         return res[0][0]
     return 0
 
 def __decompress_last(item):
     """private function, used to shorten code"""
     item = list(item)
     item[-1] = decompress(item[-1])
     return item
 
 def create_pseudo_record(es_title, es_desc, es_url, of="hb"):
     """Return a pseudo record representation given a title and a description."""
 
     if of == 'hb':
         record = '\n'.join([es_title, es_desc, es_url])
     if of == 'xm':
 # In case we want to use the controlfield,
 # the -es_id must be used.
 #<controlfield tag="001">%s</controlfield>
         record = """<record>
   <datafield tag="245" ind1=" " ind2=" ">
     <subfield code="a">%s</subfield>
   </datafield>
   <datafield tag="520" ind1=" " ind2=" ">
     <subfield code="a">%s</subfield>
   </datafield>
   <datafield tag="856" ind1="4" ind2=" ">
     <subfield code="u">%s</subfield>
   </datafield>
 </record>""" % (encode_for_xml(es_title), encode_for_xml(es_desc), encode_for_xml(es_url))
     return record
 
 def prettify_url(url, char_limit=50, nb_dots=3):
     """If the url has more characters than char_limit return a shortened version of it
     keeping the beginning and ending and replacing the rest with dots."""
 
     if len(url) > char_limit:
         # let's set a minimum character limit
         if char_limit < 5:
             char_limit = 5
         # let's set a maximum number of dots in relation to the character limit
         if nb_dots > char_limit/4:
             nb_dots = char_limit/5
         nb_char_url = char_limit - nb_dots
         nb_char_end = nb_char_url/4
         nb_char_beg = nb_char_url - nb_char_end
         return url[:nb_char_beg] + '.'*nb_dots + url[-nb_char_end:]
     else:
         return url
diff --git a/modules/webbasket/lib/webbasket_templates.py b/modules/webbasket/lib/webbasket_templates.py
index 057723b04..0940ca54c 100644
--- a/modules/webbasket/lib/webbasket_templates.py
+++ b/modules/webbasket/lib/webbasket_templates.py
@@ -1,4315 +1,4332 @@
 ## This file is part of Invenio.
 ## Copyright (C) 2005, 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.
 
 """ Templating for webbasket module """
 
 __revision__ = "$Id$"
 
 import cgi
+import urllib
 
 from invenio.messages import gettext_set_language
 from invenio.webbasket_config import \
                        CFG_WEBBASKET_CATEGORIES, \
                        CFG_WEBBASKET_SHARE_LEVELS, \
                        CFG_WEBBASKET_DIRECTORY_BOX_NUMBER_OF_COLUMNS
 from invenio.webmessage_mailutils import email_quoted_txt2html, \
                                          email_quote_txt, \
                                          escape_email_quoted_text
 from invenio.htmlutils import get_html_text_editor
 from invenio.config import \
      CFG_SITE_URL, \
      CFG_SITE_SECURE_URL, \
      CFG_SITE_LANG, \
      CFG_WEBBASKET_MAX_NUMBER_OF_DISPLAYED_BASKETS, \
      CFG_WEBBASKET_USE_RICH_TEXT_EDITOR, \
      CFG_SITE_RECORD
 from invenio.webuser import get_user_info
 from invenio.dateutils import convert_datetext_to_dategui
-from invenio.webbasket_dblayer import get_basket_item_title_and_URL
+from invenio.webbasket_dblayer import get_basket_item_title_and_URL, \
+                                      get_basket_ids_and_names
 from invenio.bibformat import format_record
 
 class Template:
     """Templating class for webbasket module"""
     ######################## General interface ################################
 
     def tmpl_create_directory_box(self,
                                   category, topic,
                                   (grpid, group_name),
                                   bskid,
                                   (personal_info, personal_baskets_info),
                                   (group_info, group_baskets_info),
                                   public_info,
                                   ln):
         """Template for the directory-like menu.
         @param category: the selected category
         @param topic: the selected topic (optional)
         @param (grpid, groupname): the id and name of the selected group (optional)
         @param bskid: the id of the selected basket (optional)
         @param (personal_info, personal_baskets_info): personal baskets data
         @param (group_info, group_baskets_info): group baskets data
         @param public_info: public baskets data
         @param ln: language"""
 
         _ = gettext_set_language(ln)
 
         def __calculate_prettify_name_char_limit(nb_baskets, max_chars=45, nb_dots=3):
             """Private function. Calculates the char_limit to be fed to the
             prettify_name function according to the max_chars limit and the nb_dots."""
 
             # Let's do some initial calculations:
             D = nb_dots
             B = nb_baskets
             M = max_chars
             # some assisting abbreviations
             Y = ( B > 3 and 2 or B - 1 )
             Z = ( B > 3 and 5 or 0 )
             # and the desired result
             X = ( ( M - Z - ( ( 2 + D ) * Y ) - D ) / ( Y + 1 ) )
             return X
 
         if not personal_info and not group_info and not public_info:
             return """
     %(no_baskets_label)s
     <br /><br />
     %(create_basket_label)s""" % \
     {'no_baskets_label': _('You have no personal or group baskets or are subscribed to any public baskets.'),
      'create_basket_label': _('You may want to start by %(x_url_open)screating a new basket%(x_url_close)s.') % \
                              {'x_url_open': '<a href="%s/yourbaskets/create_basket?ln=%s">' % (CFG_SITE_URL, ln),
                               'x_url_close': '</a>'}}
 
         ## Firstly, create the tabs area.
         if personal_info:
             ## If a specific topic is selected display the name of the topic
             ## and the options on it.
             if personal_baskets_info:
                 personalbaskets_link = """<a href="%(url)s/yourbaskets/display?category=%(category)s&amp;ln=%(ln)s">%(label)s</a>""" % \
-                                {'url': CFG_SITE_URL,
-                                 'category': CFG_WEBBASKET_CATEGORIES['PRIVATE'],
-                                 'ln': ln,
-                                 'label': _('Personal baskets')}
+                                       {'url': CFG_SITE_URL,
+                                        'category': CFG_WEBBASKET_CATEGORIES['PRIVATE'],
+                                        'ln': ln,
+                                        'label': _('Personal baskets')}
                 topic_link = """<a href="%(url)s/yourbaskets/display?category=%(category)s&amp;topic=%(topic)s&amp;ln=%(ln)s">%(label)s</a>""" % \
                              {'url': CFG_SITE_URL,
                               'category': CFG_WEBBASKET_CATEGORIES['PRIVATE'],
-                              'topic': topic,
+                              'topic': urllib.quote(topic),
                               'ln': ln,
                               'label': cgi.escape(topic, True)}
                 go_back_link = """<a href="%(url)s/yourbaskets/display?ln=%(ln)s"><img src="%(url)s/img/%(img)s" />%(label)s</a>""" % \
                                {'url': CFG_SITE_URL,
                                 'ln': ln,
                                 'img': 'wb-go-back.png',
                                 'label': _('Back to Your Baskets')}
                 create_basket_link = """<a href="%(url)s/yourbaskets/create_basket?topic=%(topic)s&amp;ln=%(ln)s"><img src="%(url)s/img/%(img)s" />%(label)s</a>""" % \
                                      {'url': CFG_SITE_URL,
-                                      'topic': cgi.escape(topic, True),
+                                      'topic': urllib.quote(topic),
                                       'ln': ln,
                                       'img': 'wb-create-basket.png',
                                       'label': _('Create basket')}
                 edit_topic_link = """<a href="%(url)s/yourbaskets/edit_topic?topic=%(topic)s&amp;ln=%(ln)s"><img src="%(url)s/img/%(img)s" />%(label)s</a>""" % \
                                   {'url': CFG_SITE_URL,
-                                   'topic': cgi.escape(topic, True),
+                                   'topic': urllib.quote(topic),
                                    'ln': ln,
                                    'img': 'wb-edit-topic.png',
                                    'label': _('Edit topic')}
                 personal_tab = """
               <td class="bsk_directory_box_nav_tab_content">
               %(personalbaskets_link)s&nbsp;&gt;&nbsp;%(topic_link)s
               </td>
               <td class="bsk_directory_box_nav_tab_options">
               %(go_back)s
               &nbsp;&nbsp;
               %(create_basket)s
               &nbsp;&nbsp;
               %(edit_topic)s
               </td>""" % {'topic_link': topic_link,
                           'personalbaskets_link': personalbaskets_link,
                           'go_back': go_back_link,
                           'create_basket': create_basket_link,
                           'edit_topic': edit_topic_link}
             ## If no specific topic is selected display the personal baskets tab.
             else:
                 personal_tab = """
               <td class="%(class)s">
               <a href="%(url)s/yourbaskets/display?category=%(category)s&amp;ln=%(ln)s">%(label)s</a>
               </td>""" % {'class': category == CFG_WEBBASKET_CATEGORIES['PRIVATE'] \
                           and "bsk_directory_box_tab_content_selected" \
                           or "bsk_directory_box_tab_content",
                           'url': CFG_SITE_URL,
                           'category': CFG_WEBBASKET_CATEGORIES['PRIVATE'],
                           'ln': ln,
                           'label': _('Personal baskets')}
         else:
             personal_tab = """
               <td class="%(class)s">
               %(label)s
               </td>""" % {'class': 'bsk_directory_box_tab_content_inactive',
                           'label': _('Personal baskets')}
 
         if group_info:
             ## If a specific group is selected display the name of the group
             ## and the options on it.
             if group_baskets_info:
                 groupbaskets_link = """<a href="%(url)s/yourbaskets/display?category=%(category)s&amp;ln=%(ln)s">%(label)s</a>""" % \
                                     {'url': CFG_SITE_URL,
                                      'category': CFG_WEBBASKET_CATEGORIES['GROUP'],
                                      'ln': ln,
                                      'label': _('Group baskets')}
                 group_link = """<a href="%(url)s/yourbaskets/display?category=%(category)s&amp;group=%(grpid)i&amp;ln=%(ln)s">%(label)s</a>""" % \
                              {'url': CFG_SITE_URL,
                               'category': CFG_WEBBASKET_CATEGORIES['GROUP'],
                               'grpid': grpid,
                               'ln': ln,
-                              'label': group_name}
+                              'label': cgi.escape(group_name, True)}
                 go_back_link = """<a href="%(url)s/yourbaskets/display?ln=%(ln)s"><img src="%(url)s/img/%(img)s" />%(label)s</a>""" % \
                                {'url': CFG_SITE_URL,
                                 'ln': ln,
                                 'img': 'wb-go-back.png',
                                 'label': _('Back to Your Baskets')}
                 group_tab = """
               <td class="bsk_directory_box_nav_tab_content">
               %(groupbaskets_link)s&nbsp;&gt;&nbsp;%(group_link)s
               </td>
               <td class="bsk_directory_box_nav_tab_options">
               %(go_back)s
               </td>""" % {'groupbaskets_link': groupbaskets_link,
                           'group_link': group_link,
                           'go_back': go_back_link}
             ## If no specific group is selected display the group baskets tab.
             else:
                 group_tab = """
               <td class="%(class)s">
               <a href="%(url)s/yourbaskets/display?category=%(category)s&amp;ln=%(ln)s">%(label)s</a>
               </td>""" % {'class': category == CFG_WEBBASKET_CATEGORIES['GROUP'] \
                           and "bsk_directory_box_tab_content_selected" \
                           or "bsk_directory_box_tab_content",
                           'url': CFG_SITE_URL,
                           'category': CFG_WEBBASKET_CATEGORIES['GROUP'],
                           'ln': ln,
                           'label': _('Group baskets')}
         else:
             group_tab = """
               <td class="%(class)s">
               %(label)s
               </td>""" % {'class': 'bsk_directory_box_tab_content_inactive',
                           'label': _('Group baskets')}
 
         if public_info:
             ## Display the public baskets tab.
             public_tab = """
               <td class="%(class)s">
               <a href="%(url)s/yourbaskets/display?category=%(category)s&amp;ln=%(ln)s">%(label)s</a>
               </td>""" % {'class': category == CFG_WEBBASKET_CATEGORIES['EXTERNAL'] \
                           and "bsk_directory_box_tab_content_selected" \
                           or "bsk_directory_box_tab_content",
                           'url': CFG_SITE_URL,
                           'category': CFG_WEBBASKET_CATEGORIES['EXTERNAL'],
                           'ln': ln,
                           'label': _('Public baskets')}
         else:
             public_tab = """
               <td class="%(class)s">
               %(label)s
               </td>""" % {'class': 'bsk_directory_box_tab_content_inactive',
                           'label': _('Public baskets')}
 
         ## If a specific topic is selected display the name of the topic
         ## and the options on it.
         if personal_baskets_info:
             tabs = """
           <table cellspacing="0px" cellpadding="0px" class="bsk_directory_box_tabs">
             <tr>%s
             </tr>
           </table>""" % (personal_tab,)
         ## If a specific group is selected display the name of the group
         ## and the options on it.
         elif group_baskets_info:
             tabs = """
           <table cellspacing="0px" cellpadding="0px" class="bsk_directory_box_tabs">
             <tr>
               %s
             </tr>
           </table>""" % (group_tab,)
         ## If only a sepcific category is selected (or eveb none) display
         ## all the available tabs (selected, normal, inactive).
         else:
             tabs = """
           <table cellspacing="0px" cellpadding="0px" class="bsk_directory_box_tabs">
             <tr>
               <td class="bsk_directory_box_tab_separator">
               &nbsp;
               </td>
               %(personal_tab)s
               <td class="bsk_directory_box_tab_separator">
               &nbsp;
               </td>
               %(group_tab)s
               <td class="bsk_directory_box_tab_separator">
               &nbsp;
               </td>
               %(public_tab)s
               <td class="bsk_directory_box_tab_separator_end">
               &nbsp;
               </td>
             </tr>
           </table>""" % {'personal_tab': personal_tab,
                          'group_tab': group_tab,
                          'public_tab': public_tab}
 
         ## Secondly, create the content.
         if personal_info and category==CFG_WEBBASKET_CATEGORIES['PRIVATE']:
             content_list = []
             ## If a specific topic is selected create a list of baskets for that topic.
             if personal_baskets_info:
                 for basket in personal_baskets_info:
                     basket_id = basket[0]
                     basket_name = basket[1]
                     nb_items = basket[4]
                     basket_link = """%(opening_tag)s<a href="%(url)s/yourbaskets/display?category=%(category)s&amp;topic=%(topic)s&amp;bskid=%(bskid)i&amp;ln=%(ln)s" title="%(title_name)s">%(basket_name)s</a>%(closing_tag)s <span class="bsk_directory_box_content_list_number_of">(%(nb_items)i)</span>""" % \
                                  {'opening_tag': basket_id==bskid and "<em>" or "",
                                   'closing_tag': basket_id==bskid and "</em>" or "",
                                   'url': CFG_SITE_URL,
                                   'category': category,
-                                  'topic': cgi.escape(topic, True),
+                                  'topic': urllib.quote(topic),
                                   'bskid': basket_id,
                                   'ln': ln,
                                   'title_name': cgi.escape(basket_name, True),
                                   'basket_name': cgi.escape(prettify_name(basket_name, 27), True),
                                   'nb_items': nb_items}
                     content_list_item = """
                       %(basket_link)s""" % {'basket_link': basket_link}
                     content_list.append(content_list_item)
             ## If no specific topic is selected create a list of topics with a preview of their baskets.
             else:
-                for topic_and_baskets in personal_info:
-                    topic_name = topic_and_baskets[0]
-                    nb_baskets = topic_and_baskets[1]
+                for topic_and_bskids in personal_info:
+                    topic_name = topic_and_bskids[0]
+                    bskids = topic_and_bskids[1].split(',')
+                    nb_baskets = len(bskids)
                     topic_link = """<strong><a href="%(url)s/yourbaskets/display?category=%(category)s&amp;topic=%(topic)s&amp;ln=%(ln)s" title="%(title_name)s">%(topic_name)s</a></strong> <span class="bsk_directory_box_content_list_number_of">(%(nb_baskets)s)</span>""" % \
                                  {'url': CFG_SITE_URL,
                                   'category': category,
-                                  'topic': cgi.escape(topic_name, True),
+                                  'topic': urllib.quote(topic_name),
                                   'ln': ln,
                                   'title_name': cgi.escape(topic_name, True),
                                   'topic_name': cgi.escape(prettify_name(topic_name, 25), True),
                                   'nb_baskets': nb_baskets}
-                    baskets = eval(topic_and_baskets[2] + ',')
                     basket_links = ""
                     basket_links_list = []
-                    for basket in baskets[:3]:
-                        # TODO: adapt the prettify_name char_limit variable according to nb_baskets
+                    #TODO: Not have the number of basket names displayed hardcoded (3 in this case)
+                    bskids_and_names = get_basket_ids_and_names(bskids, 3)
+                    for bskid_and_name in bskids_and_names:
+                        bskid = bskid_and_name[0]
+                        basket_name = bskid_and_name[1]
+                        #TODO: adapt the prettify_name char_limit variable according to nb_baskets
                         basket_link = """<a href="%(url)s/yourbaskets/display?category=%(category)s&amp;topic=%(topic)s&amp;bskid=%(bskid)i&amp;ln=%(ln)s" title="%(title_name)s">%(basket_name)s</a>""" % \
                                       {'url': CFG_SITE_URL,
                                        'category': category,
-                                       'topic': cgi.escape(topic_name, True),
-                                       'bskid': basket[0],
+                                       'topic': urllib.quote(topic_name),
+                                       'bskid': bskid,
                                        'ln': ln,
-                                       'title_name': cgi.escape(basket[1], True),
-                                       'basket_name': cgi.escape(prettify_name(basket[1], __calculate_prettify_name_char_limit(nb_baskets, 135/CFG_WEBBASKET_DIRECTORY_BOX_NUMBER_OF_COLUMNS)), True)}
+                                       'title_name': cgi.escape(basket_name, True),
+                                       'basket_name': cgi.escape(prettify_name(basket_name, __calculate_prettify_name_char_limit(nb_baskets, 135/CFG_WEBBASKET_DIRECTORY_BOX_NUMBER_OF_COLUMNS)), True)}
                         basket_links_list.append(basket_link)
                         basket_links = ', '.join(basket_links_list)
                     if nb_baskets > 3:
                         basket_links += ", ..."
                     content_list_item = """
                       %(topic_link)s
                       <br />
                       <small>%(basket_links)s</small>""" % \
                                      {'topic_link': topic_link,
                                       'basket_links': basket_links}
                     content_list.append(content_list_item)
 
             nb_cells = CFG_WEBBASKET_DIRECTORY_BOX_NUMBER_OF_COLUMNS
             nb_items = len(content_list)
             content_list.reverse()
             content = """
                 <table cellspacing="0px" cellpadding="0px" align="center" width="100%">
                   <tr>"""
             for i in range(nb_cells):
                 content += """
                     <td class="bsk_directory_box_content_list_cell" width="%s%%">""" % \
                               (100/nb_cells,)
                 nb_lines = (nb_items/nb_cells) + ((nb_items%nb_cells) > i and 1 or 0)
                 for j in range(nb_lines):
                     content += content_list.pop()
                     if j < (nb_lines-1):
                         content += personal_baskets_info and "<br />" or "<br /><br />"
                 content += """
                     </td>"""
             content += """
                   </tr>
                 </table>"""
 
         elif group_info and category==CFG_WEBBASKET_CATEGORIES['GROUP']:
             content_list = []
             ## If a specific grpid is selected create a list of baskets for that group.
             if group_baskets_info:
                 for basket in group_baskets_info:
                     basket_id = basket[0]
                     basket_name = basket[1]
                     nb_items = basket[4]
                     basket_link = """%(opening_tag)s<a href="%(url)s/yourbaskets/display?category=%(category)s&amp;group=%(grpid)i&amp;bskid=%(bskid)i&amp;ln=%(ln)s" title="%(title_name)s">%(basket_name)s</a>%(closing_tag)s <span class="bsk_directory_box_content_list_number_of">(%(nb_items)i)</span>""" % \
                                  {'opening_tag': basket_id==bskid and "<em>" or "",
                                   'closing_tag': basket_id==bskid and "</em>" or "",
                                   'url': CFG_SITE_URL,
                                   'category': CFG_WEBBASKET_CATEGORIES['GROUP'],
                                   'grpid': grpid,
                                   'bskid': basket_id,
                                   'ln': ln,
                                   'title_name': cgi.escape(basket_name, True),
                                   'basket_name': cgi.escape(prettify_name(basket_name, 27), True),
                                   'nb_items': nb_items}
                     content_list_item = """
                       %(basket_link)s""" % {'basket_link': basket_link}
                     content_list.append(content_list_item)
             ## If no specific grpid is selected create a list of groups with a preview of their baskets.
             else:
-                for group_and_baskets in group_info:
-                    group_id = group_and_baskets[0]
-                    group_name = group_and_baskets[1]
-                    nb_baskets = group_and_baskets[2]
+                for group_and_bskids in group_info:
+                    group_id = group_and_bskids[0]
+                    group_name = group_and_bskids[1]
+                    bskids = group_and_bskids[2].split(',')
+                    nb_baskets = len(bskids)
                     group_link = """<strong><a href="%(url)s/yourbaskets/display?category=%(category)s&amp;group=%(group)i&amp;ln=%(ln)s" title="%(title_name)s">%(group_name)s</a></strong> <span class="bsk_directory_box_content_list_number_of">(%(nb_baskets)s)</span>""" % \
                                  {'url': CFG_SITE_URL,
                                   'category': category,
                                   'group': group_id,
                                   'ln': ln,
                                   'title_name': cgi.escape(group_name, True),
                                   'group_name': cgi.escape(prettify_name(group_name, 25), True),
                                   'nb_baskets': nb_baskets}
-                    baskets = eval(group_and_baskets[3] + ',')
                     basket_links = ""
                     basket_links_list = []
-                    for basket in baskets[:3]:
+                    #TODO: Not have the number of basket names displayed hardcoded (3 in this case)
+                    bskids_and_names = get_basket_ids_and_names(bskids, 3)
+                    for bskid_and_name in bskids_and_names:
+                        bskid = bskid_and_name[0]
+                        basket_name = bskid_and_name[1]
                         # TODO: adapt the prettify_name char_limit variable according to nb_baskets
                         basket_link = """<a href="%(url)s/yourbaskets/display?category=%(category)s&amp;group=%(group)i&amp;bskid=%(bskid)i&amp;ln=%(ln)s" title="%(title_name)s">%(basket_name)s</a>""" % \
                                       {'url': CFG_SITE_URL,
                                        'category': category,
                                        'group': group_id,
-                                       'bskid': basket[0],
+                                       'bskid': bskid,
                                        'ln': ln,
-                                       'title_name': cgi.escape(basket[1], True),
-                                       'basket_name': cgi.escape(prettify_name(basket[1], __calculate_prettify_name_char_limit(nb_baskets, 135/CFG_WEBBASKET_DIRECTORY_BOX_NUMBER_OF_COLUMNS)), True)}
+                                       'title_name': cgi.escape(basket_name, True),
+                                       'basket_name': cgi.escape(prettify_name(basket_name, __calculate_prettify_name_char_limit(nb_baskets, 135/CFG_WEBBASKET_DIRECTORY_BOX_NUMBER_OF_COLUMNS)), True)}
                         basket_links_list.append(basket_link)
                         basket_links = ', '.join(basket_links_list)
                     if nb_baskets > 3:
                         basket_links += ", ..."
                     content_list_item = """
                       %(group_link)s
                       <br />
                       <small>%(basket_links)s</small>""" % \
                                      {'group_link': group_link,
                                       'basket_links': basket_links}
                     content_list.append(content_list_item)
 
             nb_cells = CFG_WEBBASKET_DIRECTORY_BOX_NUMBER_OF_COLUMNS
             nb_items = len(content_list)
             content_list.reverse()
             content = """
                 <table cellspacing="0px" cellpadding="0px" align="center" width="100%">
                   <tr>"""
             for i in range(nb_cells):
                 content += """
                     <td class="bsk_directory_box_content_list_cell" width="%s%%">""" % \
                               (100/nb_cells,)
                 nb_lines = (nb_items/nb_cells) + ((nb_items%nb_cells) > i and 1 or 0)
                 for j in range(nb_lines):
                     content += content_list.pop()
                     if j < (nb_lines-1):
                         #content += "<br /><br />"
                         content += group_baskets_info and "<br />" or "<br /><br />"
                 content += """
                     </td>"""
             content += """
                   </tr>
                 </table>"""
 
         elif public_info and category==CFG_WEBBASKET_CATEGORIES['EXTERNAL']:
             content_list = []
             for basket in public_info:
                 basket_id = basket[0]
                 basket_name = basket[1]
                 nb_items = basket[2]
                 basket_link = """<a href="%(url)s/yourbaskets/display?category=%(category)s&amp;bskid=%(bskid)i&amp;ln=%(ln)s" title="%(title_name)s">%(basket_name)s</a> <span class="bsk_directory_box_content_list_number_of">(%(nb_items)i)</span>""" % \
                              {'url': CFG_SITE_URL,
                               'category': category,
                               'bskid': basket_id,
                               'ln': ln,
                               'title_name': cgi.escape(basket_name, True),
                               'basket_name': cgi.escape(prettify_name(basket_name, 27), True),
                               'nb_items': nb_items}
                 content_list_item = """
                       %(basket_link)s""" % {'basket_link': basket_link}
                 content_list.append(content_list_item)
 
             nb_cells = CFG_WEBBASKET_DIRECTORY_BOX_NUMBER_OF_COLUMNS
             nb_items = len(content_list)
             content_list.reverse()
             content = """
                 <table cellspacing="0px" cellpadding="0px" align="center" width="100%">
                   <tr>"""
             for i in range(nb_cells):
                 content += """
                     <td class="bsk_directory_box_content_list_cell" width="%s%%">""" % \
                               (100/nb_cells,)
                 nb_lines = (nb_items/nb_cells) + ((nb_items%nb_cells) > i and 1 or 0)
                 for j in range(nb_lines):
                     content += content_list.pop()
                     if j < (nb_lines-1):
                         content += "<br />"
                 content += """
                     </td>"""
             content += """
                   </tr>
                 </table>"""
 
         out = """
     <table cellspacing="0px" cellpadding="0px" class="bsk_directory_box">
       <tr>
         <td width="100%%">
         %(tabs)s
         </td>
       </tr>
       <tr>
         <td width="100%%">
           <table cellspacing="0px" cellpadding="0px" class="bsk_directory_box_content">
             <tr>
               <td class="%(class)s">
               %(content)s
               </td>
             </tr>
           </table>
         </td>
       </tr>
     </table>""" % {'class': ((category == CFG_WEBBASKET_CATEGORIES['PRIVATE'] and topic) or \
                              (category == CFG_WEBBASKET_CATEGORIES['GROUP'] and grpid)) and \
                              "bsk_directory_box_content_list_baskets" or \
                              "bsk_directory_box_content_list_topics_groups",
                    'tabs': tabs,
                    'content': content}
         return out
 
     def tmpl_create_search_box(self,
                                category="",
                                topic="",
                                grpid=0,
                                topic_list=(),
                                group_list=(),
                                number_of_public_baskets=0,
                                p="",
                                n=0,
                                ln=CFG_SITE_LANG):
         """EXPERIMENTAL UI"""
 
         _ = gettext_set_language(ln)
 
         action = """%s/yourbaskets/search""" % (CFG_SITE_URL,)
 
         select_options = create_search_box_select_options(category,
                                                           topic,
                                                           grpid,
                                                           topic_list,
                                                           group_list,
                                                           number_of_public_baskets,
                                                           ln)
 
         out = """
     <table cellspacing="0px" cellpadding="5px" class="bsk_search_box">
     <form name="search_baskets" action="%(action)s" method="get">
       <thead>
         <tr>
           <td colspan="4">
           <small><strong>%(search_for_label)s:</strong><small>
           </td>
         </tr>
       </thead>
       <tbody>
         <tr>
           <td>
           <input name="p" value="%(p)s" type="text" />
           </td>
           <td>
           <small><strong>in</strong><small>
           </td>
           <td>
           <select name="b">%(select_options)s
           </select>
           </td>
           <td>
           <input class="formbutton" type="submit" value="Search" />
           </td>
         </tr>
         <tr>
           <td>
           <input type="checkbox" name="n" value="1"%(notes_checked)s />
           <small>%(notes_label)s</small>
           </td>
         </tr>
       </tbody>
     <input type="hidden" name="ln" value="%(ln)s" />
     </form>
     </table>""" % {'action': action,
                    'search_for_label': _('Search baskets for'),
                    'notes_label': _('Search also in notes (where allowed)'),
                    'notes_checked': n and ' checked="checked"' or '',
                    'p': p,
                    'select_options': select_options,
-                   'ln': cgi.escape(ln, True)}
+                   'ln': ln}
         return out
 
     def tmpl_search_results(self,
                             personal_search_results={},
                             total_no_personal_search_results=0,
                             group_search_results={},
                             total_no_group_search_results=0,
                             public_search_results={},
                             total_no_public_search_results=0,
                             all_public_search_results={},
                             total_no_all_public_search_results=0,
                             ln=CFG_SITE_LANG):
         """Template for the search results."""
 
         _ = gettext_set_language(ln)
 
         out = """
     <table cellspacing="0px" cellpadding="5px">"""
 
         total_no_search_results = total_no_personal_search_results + \
                                total_no_group_search_results + \
                                total_no_public_search_results + \
                                total_no_all_public_search_results
         if total_no_search_results:
             if total_no_search_results != max(total_no_personal_search_results, \
                                               total_no_group_search_results, \
                                               total_no_public_search_results, \
                                               total_no_all_public_search_results):
                 out += """
       <tr>
         <td class="webbasket_search_results_results_overview_cell">
         <strong>%(results_overview_label)s:</strong> %(items_found_label)s
         </td>
       </tr>""" % {'results_overview_label': _('Results overview'),
                   'items_found_label': _('%i matching items') % total_no_search_results}
                 if total_no_personal_search_results:
                     out += """
       <tr>
         <td>
         <a href="#%(personal_baskets_name)s">%(personal_baskets_label)s</a>
         <span class="webbasket_search_results_number_of_items">(%(items_found)i)</span>
         </td>
       </tr>""" % {'personal_baskets_label': _('Personal baskets'),
                   'personal_baskets_name': "P",
                   'items_found': total_no_personal_search_results}
                 if total_no_group_search_results:
                     out += """
       <tr>
         <td>
         <a href="#%(group_baskets_name)s">%(group_baskets_label)s<a/>
         <span class="webbasket_search_results_number_of_items">(%(items_found)s)</span>
         </td>
       </tr>""" % {'group_baskets_label': _('Group baskets'),
                   'group_baskets_name': "G",
                   'items_found': total_no_group_search_results}
                 if total_no_public_search_results:
                     out += """
       <tr>
         <td>
         <a href="#%(public_baskets_name)s">%(public_baskets_label)s</a>
         <span class="webbasket_search_results_number_of_items">(%(items_found)s)</span>
         </td>
       </tr>""" % {'public_baskets_label': _('Public baskets'),
                   'public_baskets_name': "E",
                   'items_found': total_no_public_search_results}
                 if total_no_all_public_search_results:
                     out += """
       <tr>
         <td>
         <a href="#%(all_public_baskets_name)s">%(all_public_baskets_label)s</a>
         <span class="webbasket_search_results_number_of_items">(%(items_found)s)</span>
         </td>
       </tr>""" % {'all_public_baskets_label': _('All public baskets'),
                   'all_public_baskets_name': "A",
                   'items_found': total_no_all_public_search_results}
                 out += """
       <tr>
         <td>
         &nbsp;
         </td>
       </tr>"""
 
         else:
             out += """
       <tr>
         <td>
         %(no_items_found_label)s
         </td>
       </tr>""" % {'no_items_found_label': _('No items found.')}
 
 
         ### Search results from the user's personal baskets ###
         if total_no_personal_search_results:
             # Print out the header for the personal baskets
             out += """
       <tr>
         <td class="webbasket_search_results_results_overview_cell">
         <a name="%(personal_baskets_name)s"></a><strong>%(personal_baskets_label)s:</strong> %(items_found_label)s
         </td>
       </tr>""" % {'personal_baskets_label': _('Personal baskets'),
                   'personal_baskets_name': "P",
                   'items_found_label': _('%i matching items') % total_no_personal_search_results}
 
             # For every basket print a link to the basket and the number of items
             # found in that basket
             for bskid in personal_search_results.keys():
                 basket_link = """<a href="%(url)s/yourbaskets/display?category=%(category)s&amp;topic=%(topic)s&amp;bskid=%(bskid)i&amp;ln=%(ln)s">%(basket_name)s</a>""" % \
                               {'url': CFG_SITE_URL,
                                'category': CFG_WEBBASKET_CATEGORIES['PRIVATE'],
-                               'topic': cgi.escape(personal_search_results[bskid][1], True),
+                               'topic': urllib.quote(personal_search_results[bskid][1]),
                                'bskid': bskid,
                                'ln': ln,
                                'basket_name': cgi.escape(personal_search_results[bskid][0], True)}
                 out += """
       <tr>
         <td>
         %(in_basket_label)s <span class="webbasket_search_results_number_of_items">(%(items_found)i)</span>
         </td>
       </tr>""" % {'in_basket_label': _('In %(x_linked_basket_name)s') % \
                                      {'x_linked_basket_name': basket_link},
                                       'items_found': personal_search_results[bskid][2]}
 
                 # Print the list of records found in that basket
                 out += """
       <tr>
         <td class="webbasket_search_results_basket">
           <ol>"""
                 personal_search_result_records = personal_search_results[bskid][3]
                 for personal_search_result_record in personal_search_result_records:
                     recid = personal_search_result_record[0]
                     number_of_notes = personal_search_result_record[1]
                     record_html = personal_search_result_record[2]
                     # If this a local record print the detailed record link and
                     # the view/add notes link
                     if recid > 0:
                         detailed_record_html = """<a class="moreinfo" href="%(siteurl)s/%(CFG_SITE_RECORD)s/%(recid)i">%(detailed_record_label)s</a>""" % \
                                                {'siteurl': CFG_SITE_URL,
                                                 'CFG_SITE_RECORD': CFG_SITE_RECORD,
                                                 'recid': recid,
                                                 'detailed_record_label': _('Detailed record')}
                         notes_html = """<a class="moreinfo" href="%(siteurl)s/yourbaskets/%(notes_action)s?"""\
                                      """category=P&amp;topic=%(topic)s&amp;bskid=%(bskid)s&amp;recid=%(recid)i"""\
                                      """&amp;ln=%(ln)s%(notes_inline_anchor)s">%(notes_label)s</a>""" % \
                                      {'siteurl': CFG_SITE_URL,
-                                      'topic': personal_search_results[bskid][1],
+                                      'topic': urllib.quote(personal_search_results[bskid][1]),
                                       'bskid' : bskid,
                                       'recid' : recid,
                                       'ln' : ln,
                                       'notes_action': number_of_notes and 'display' or 'write_note',
                                       'notes_inline_anchor': not number_of_notes and '#note' or '',
                                       'notes_label': number_of_notes and _('Notes') + ' (' + str(number_of_notes) + ')' or _('Add a note...')}
                         
                         out += """
                         <li>
                         %(record_html)s
                         <br />
                         %(more_info)s
                         </li>""" % \
                         {'record_html': record_html,
                          'more_info': """<span class="moreinfo">%(detailed_record_html)s - %(notes_html)s</span>""" % \
                                                        {'detailed_record_html': detailed_record_html,
                                                         'notes_html': notes_html}}
                     # If this an external record print only the view/add notes link
                     else:
                         notes_html = """<a class="moreinfo" href="%(siteurl)s/yourbaskets/%(notes_action)s?"""\
                                      """category=P&amp;topic=%(topic)s&amp;bskid=%(bskid)s&amp;recid=%(recid)i"""\
                                      """&amp;ln=%(ln)s%(notes_inline_anchor)s">%(notes_label)s</a>""" % \
                                      {'siteurl': CFG_SITE_URL,
-                                      'topic': personal_search_results[bskid][1],
+                                      'topic': urllib.quote(personal_search_results[bskid][1]),
                                       'bskid' : bskid,
                                       'recid' : recid,
                                       'ln' : ln,
                                       'notes_action': number_of_notes and 'display' or 'write_note',
                                       'notes_inline_anchor': not number_of_notes and '#note' or '',
                                       'notes_label': number_of_notes and _('Notes') + ' (' + str(number_of_notes) + ')' or _('Add a note...')}
                         
                         out += """
                         <li>
                         %(record_html)s
                         <br />
                         %(more_info)s
                         </li>""" % \
                         {'record_html': record_html,
                          'more_info':  notes_html}
                         
                 out += """
           </ol>
         </td>
       </tr>"""
 
             out += """
       <tr>
         <td>
         &nbsp;
         </td>
       </tr>"""
 
         ### Search results from the user's group baskets ###
         if total_no_group_search_results:
             # Print out the header for the group baskets
             out += """
       <tr>
         <td class="webbasket_search_results_results_overview_cell">
         <a name="%(group_baskets_name)s"></a><strong>%(group_baskets_label)s:</strong> %(items_found_label)s
         </td>
       </tr>""" % {'group_baskets_label': _('Group baskets'),
                   'group_baskets_name': "G",
                   'items_found_label': _('%i matching items') % total_no_group_search_results}
 
             # For every basket print a link to the basket and the number of items
             # found in that basket
             for bskid in group_search_results.keys():
                 basket_link = """<a href="%(url)s/yourbaskets/display?category=%(category)s&amp;group=%(grpid)i&amp;bskid=%(bskid)i&amp;ln=%(ln)s">%(basket_name)s</a>""" % \
                               {'url': CFG_SITE_URL,
                                'category': CFG_WEBBASKET_CATEGORIES['GROUP'],
                                'grpid': group_search_results[bskid][1],
                                'bskid': bskid,
                                'ln': ln,
                                'basket_name': cgi.escape(group_search_results[bskid][0], True)}
                 out += """
       <tr>
         <td>
         %(in_basket_label)s <span class="webbasket_search_results_number_of_items">(%(items_found)i)</span>
         </td>
       </tr>""" % {'in_basket_label': _('In %(x_linked_basket_name)s') % \
                                      {'x_linked_basket_name': basket_link},
                                       'items_found': group_search_results[bskid][4]}
 
                 # Print the list of records found in that basket
                 out += """
       <tr>
         <td class="webbasket_search_results_basket">
           <ol>"""
                 group_search_result_records = group_search_results[bskid][5]
                 (share_rights_view_notes, share_rights_add_notes) = group_search_results[bskid][3]
                 for group_search_result_record in group_search_result_records:
                     recid = group_search_result_record[0]
                     number_of_notes = group_search_result_record[1]
                     record_html = group_search_result_record[2]
                     share_rights_notes = bool(share_rights_view_notes and (number_of_notes or share_rights_add_notes))
                     # If this a local record print the detailed record link and
                     # the view/add notes link
                     if recid > 0:
                         detailed_record_html = """<a class="moreinfo" href="%(siteurl)s/%(CFG_SITE_RECORD)s/%(recid)i">%(detailed_record_label)s</a>""" % \
                                                {'siteurl': CFG_SITE_URL,
                                                 'CFG_SITE_RECORD': CFG_SITE_RECORD,
                                                 'recid': recid,
                                                 'detailed_record_label': _('Detailed record')}
                         if share_rights_notes:
                             notes_html = """<a class="moreinfo" href="%(siteurl)s/yourbaskets/%(notes_action)s?"""\
                                          """category=G&amp;group=%(grpid)i&amp;bskid=%(bskid)s&amp;recid=%(recid)i"""\
                                          """&amp;ln=%(ln)s%(notes_inline_anchor)s">%(notes_label)s</a>""" % \
                                          {'siteurl': CFG_SITE_URL,
                                           'grpid': group_search_results[bskid][1],
                                           'bskid' : bskid,
                                           'recid' : recid,
                                           'ln' : ln,
                                           'notes_action': number_of_notes and 'display' or 'write_note',
                                           'notes_inline_anchor': not number_of_notes and '#note' or '',
                                           'notes_label': number_of_notes and _('Notes') + ' (' + str(number_of_notes) + ')' or _('Add a note...')}
                         
                         out += """
                         <li>
                         %(record_html)s
                         <br />
                         %(more_info)s
                         </li>""" % \
                         {'record_html': record_html,
                          'more_info': """<span class="moreinfo">%(detailed_record_html)s%(separator)s%(notes_html)s</span>""" % \
                                                        {'detailed_record_html': detailed_record_html,
                                                         'separator': share_rights_notes and ' - ' or '',
                                                         'notes_html': share_rights_notes and notes_html or ''}}
                     # If this an external record print only the view/add notes link
                     else:
                         if share_rights_notes:
                             notes_html = """<a class="moreinfo" href="%(siteurl)s/yourbaskets/%(notes_action)s?"""\
                                          """category=G&amp;group=%(grpid)i&amp;bskid=%(bskid)s&amp;recid=%(recid)i"""\
                                          """&amp;ln=%(ln)s%(notes_inline_anchor)s">%(notes_label)s</a>""" % \
                                          {'siteurl': CFG_SITE_URL,
                                           'grpid': group_search_results[bskid][1],
                                           'bskid' : bskid,
                                           'recid' : recid,
                                           'ln' : ln,
                                           'notes_action': number_of_notes and 'display' or 'write_note',
                                           'notes_inline_anchor': not number_of_notes and '#note' or '',
                                           'notes_label': number_of_notes and _('Notes') + ' (' + str(number_of_notes) + ')' or _('Add a note...')}
                         
                         out += """
                         <li>
                         %(record_html)s
                         %(more_info)s
                         </li>""" % \
                         {'record_html': record_html,
                          'more_info': share_rights_notes and '<br />' + notes_html or ''}
                         
                 out += """
           </ol>
         </td>
       </tr>"""
 
             out += """
       <tr>
         <td>
         &nbsp;
         </td>
       </tr>"""
 
         ### Search results from the user's public baskets ###
         if total_no_public_search_results:
             out += """
       <tr>
         <td class="webbasket_search_results_results_overview_cell">
         <a name="%(public_baskets_name)s"></a><strong>%(public_baskets_label)s:</strong> %(items_found_label)s
         </td>
       </tr>""" % {'public_baskets_label': _('Public baskets'),
                   'public_baskets_name': "E",
                   'items_found_label': _('%i matching items') % total_no_public_search_results}
 
             for bskid in public_search_results.keys():
                 basket_link = """<a href="%(url)s/yourbaskets/display?category=%(category)s&amp;bskid=%(bskid)i&amp;ln=%(ln)s">%(basket_name)s</a>""" % \
                               {'url': CFG_SITE_URL,
                                'category': CFG_WEBBASKET_CATEGORIES['EXTERNAL'],
                                'bskid': bskid,
                                'ln': ln,
                                'basket_name': cgi.escape(public_search_results[bskid][0], True)}
                 out += """
       <tr>
         <td>
         %(in_basket_label)s <span class="webbasket_search_results_number_of_items">(%(items_found)i)</span>
         </td>
       </tr>""" % {'in_basket_label': _('In %(x_linked_basket_name)s') % \
                                      {'x_linked_basket_name': basket_link},
                   'items_found': public_search_results[bskid][2]}
 
                 # Print the list of records found in that basket
                 out += """
       <tr>
         <td class="webbasket_search_results_basket">
           <ol>"""
                 public_search_result_records = public_search_results[bskid][3]
                 (share_rights_view_notes, share_rights_add_notes) = public_search_results[bskid][1]
                 for public_search_result_record in public_search_result_records:
                     recid = public_search_result_record[0]
                     number_of_notes = public_search_result_record[1]
                     record_html = public_search_result_record[2]
                     share_rights_notes = bool(share_rights_view_notes and (number_of_notes or share_rights_add_notes))
                     # If this a local record print the detailed record link and
                     # the view/add notes link
                     if recid > 0:
                         detailed_record_html = """<a class="moreinfo" href="%(siteurl)s/%(CFG_SITE_RECORD)s/%(recid)i">%(detailed_record_label)s</a>""" % \
                                                {'siteurl': CFG_SITE_URL,
                                                 'CFG_SITE_RECORD': CFG_SITE_RECORD,
                                                 'recid': recid,
                                                 'detailed_record_label': _('Detailed record')}
                         if share_rights_notes:
                             notes_html = """<a class="moreinfo" href="%(siteurl)s/yourbaskets/%(notes_action)s?"""\
                                          """bskid=%(bskid)s&amp;recid=%(recid)i"""\
                                          """&amp;ln=%(ln)s%(notes_inline_anchor)s">%(notes_label)s</a>""" % \
                                          {'siteurl': CFG_SITE_URL,
                                           'bskid' : bskid,
                                           'recid' : recid,
                                           'ln' : ln,
                                           'notes_action': number_of_notes and 'display_public' or 'write_public_note',
                                           'notes_inline_anchor': not number_of_notes and '#note' or '',
                                           'notes_label': number_of_notes and _('Notes') + ' (' + str(number_of_notes) + ')' or _('Add a note...')}
                         
                         out += """
                         <li>
                         %(record_html)s
                         <br />
                         %(more_info)s
                         </li>""" % \
                         {'record_html': record_html,
                          'more_info': """<span class="moreinfo">%(detailed_record_html)s%(separator)s%(notes_html)s</span>""" % \
                                                        {'detailed_record_html': detailed_record_html,
                                                         'separator': share_rights_notes and ' - ' or '',
                                                         'notes_html': share_rights_notes and notes_html or ''}}
                     # If this an external record print only the view/add notes link
                     else:
                         if share_rights_notes:
                             notes_html = """<a class="moreinfo" href="%(siteurl)s/yourbaskets/%(notes_action)s?"""\
                                          """bskid=%(bskid)s&amp;recid=%(recid)i"""\
                                          """&amp;ln=%(ln)s%(notes_inline_anchor)s">%(notes_label)s</a>""" % \
                                          {'siteurl': CFG_SITE_URL,
                                           'bskid' : bskid,
                                           'recid' : recid,
                                           'ln' : ln,
                                           'notes_action': number_of_notes and 'display_public' or 'write_public_note',
                                           'notes_inline_anchor': not number_of_notes and '#note' or '',
                                           'notes_label': number_of_notes and _('Notes') + ' (' + str(number_of_notes) + ')' or _('Add a note...')}
                         
                         out += """
                         <li>
                         %(record_html)s
                         %(more_info)s
                         </li>""" % \
                         {'record_html': record_html,
                          'more_info': share_rights_notes and '<br />' + notes_html or ''}
                         
                 out += """
           </ol>
         </td>
       </tr>"""
 
             out += """
       <tr>
         <td>
         &nbsp;
         </td>
       </tr>"""
 
         ### Search results from all the public baskets ###
         if total_no_all_public_search_results:
             out += """
       <tr>
         <td class="webbasket_search_results_results_overview_cell">
         <a name="%(all_public_baskets_name)s"></a><strong>%(all_public_baskets_label)s:</strong> %(items_found_label)s
         </td>
       </tr>""" % {'all_public_baskets_label': _('All public baskets'),
                   'all_public_baskets_name': "A",
                   'items_found_label': _('%i matching items') % total_no_all_public_search_results}
 
             for bskid in all_public_search_results.keys():
                 basket_link = """<a href="%(url)s/yourbaskets/display_public?bskid=%(bskid)i&amp;ln=%(ln)s">%(basket_name)s</a>""" % \
                               {'url': CFG_SITE_URL,
                                'bskid': bskid,
                                'ln': ln,
                                'basket_name': cgi.escape(all_public_search_results[bskid][0], True)}
                 out += """
       <tr>
         <td>
         %(in_basket_label)s <span class="webbasket_search_results_number_of_items">(%(items_found)i)</span>
         </td>
       </tr>""" % {'in_basket_label': _('In %(x_linked_basket_name)s') % \
                                      {'x_linked_basket_name': basket_link},
                   'items_found': all_public_search_results[bskid][2]}
 
                 # Print the list of records found in that basket
                 out += """
       <tr>
         <td class="webbasket_search_results_basket">
           <ol>"""
                 all_public_search_result_records = all_public_search_results[bskid][3]
                 (share_rights_view_notes, share_rights_add_notes) = all_public_search_results[bskid][1]
                 for all_public_search_result_record in all_public_search_result_records:
                     recid = all_public_search_result_record[0]
                     number_of_notes = all_public_search_result_record[1]
                     record_html = all_public_search_result_record[2]
                     share_rights_notes = bool(share_rights_view_notes and (number_of_notes or share_rights_add_notes))
                     # If this a local record print the detailed record link and
                     # the view/add notes link
                     if recid > 0:
                         detailed_record_html = """<a class="moreinfo" href="%(siteurl)s/%(CFG_SITE_RECORD)s/%(recid)i">%(detailed_record_label)s</a>""" % \
                                                {'siteurl': CFG_SITE_URL,
                                                 'CFG_SITE_RECORD': CFG_SITE_RECORD,
                                                 'recid': recid,
                                                 'detailed_record_label': _('Detailed record')}
                         if share_rights_notes:
                             notes_html = """<a class="moreinfo" href="%(siteurl)s/yourbaskets/%(notes_action)s?"""\
                                          """bskid=%(bskid)s&amp;recid=%(recid)i"""\
                                          """&amp;ln=%(ln)s%(notes_inline_anchor)s">%(notes_label)s</a>""" % \
                                          {'siteurl': CFG_SITE_URL,
                                           'bskid' : bskid,
                                           'recid' : recid,
                                           'ln' : ln,
                                           'notes_action': number_of_notes and 'display_public' or 'write_public_note',
                                           'notes_inline_anchor': not number_of_notes and '#note' or '',
                                           'notes_label': number_of_notes and _('Notes') + ' (' + str(number_of_notes) + ')' or _('Add a note...')}
                         
                         out += """
                         <li>
                         %(record_html)s
                         <br />
                         %(more_info)s
                         </li>""" % \
                         {'record_html': record_html,
                          'more_info': """<span class="moreinfo">%(detailed_record_html)s%(separator)s%(notes_html)s</span>""" % \
                                                        {'detailed_record_html': detailed_record_html,
                                                         'separator': share_rights_notes and ' - ' or '',
                                                         'notes_html': share_rights_notes and notes_html or ''}}
                     # If this an external record print only the view/add notes link
                     else:
                         if share_rights_notes:
                             notes_html = """<a class="moreinfo" href="%(siteurl)s/yourbaskets/%(notes_action)s?"""\
                                          """bskid=%(bskid)s&amp;recid=%(recid)i"""\
                                          """&amp;ln=%(ln)s%(notes_inline_anchor)s">%(notes_label)s</a>""" % \
                                          {'siteurl': CFG_SITE_URL,
                                           'bskid' : bskid,
                                           'recid' : recid,
                                           'ln' : ln,
                                           'notes_action': number_of_notes and 'display_public' or 'write_public_note',
                                           'notes_inline_anchor': not number_of_notes and '#note' or '',
                                           'notes_label': number_of_notes and _('Notes') + ' (' + str(number_of_notes) + ')' or _('Add a note...')}
                         
                         out += """
                         <li>
                         %(record_html)s
                         %(more_info)s
                         </li>""" % \
                         {'record_html': record_html,
                          'more_info': share_rights_notes and '<br />' + notes_html or ''}
                         
                 out += """
           </ol>
         </td>
       </tr>"""
 
             out += """
       <tr>
         <td>
         &nbsp;
         </td>
       </tr>"""
 
         out += """
     </table>"""
 
         return out
 
     def tmpl_display(self,
                      directory='',
                      content='',
                      search_box='',
                      search_results=''):
         """Template for the generic display.
         @param directory: the directory-like menu (optional)
         @param content: content (of a basket) (optional)
         @param search_box: the search form (optional)
         @param search_results: the search results (optional)"""
 
         display_items = []
 
         if directory:
             container_directory = """
   <div id="bskcontainerdirectory">%s
   </div>
 """ % (directory,)
             display_items.append(container_directory)
 
         if content:
             container_content = """
   <div id="bskcontainercontent">%s
   </div>
 """ % (content,)
             display_items.append(container_content)
 
         if search_box:
             container_search_box = """
   <div id="webbasket_container_search_box">%s
   </div>
 """ % (search_box,)
             display_items.append(container_search_box)
 
         if search_results:
             container_search_results = """
   <div id="webbasket_container_search_results">%s
   </div>
 """ % (search_results,)
             display_items.append(container_search_results)
 
         display_separator= """
   <div height="10px">
   &nbsp;
   </div>
 """
 
         display = display_separator.join(display_items)
 
         out = """
 <div id="bskcontainer">
 %s
 </div>""" % (display,)
 
         return out
 
     def tmpl_display_list_public_baskets(self,
                                          all_public_baskets,
                                          limit,
                                          number_of_all_public_baskets,
                                          sort,
                                          asc,
                                          nb_views_show_p=False,
                                          ln=CFG_SITE_LANG):
         """Template for the list of public baskets.
         @param all_public_baskets: tuple
                                    (bskid, basket_name, owner_id, nickname, date_modification, nb_views, nb_items)
         @param limit: display baskets from the incrementally numbered 'limit' and on
         @param number_of_all_public_baskets: the number of all the public baskets
         @param sort: 'name': sort by basket name
                      'views': sort by number of basket views
                      'nickname': sort by user nickname
                      'date': sort by basket modification date
                      'items': sort by number of basket items
         @param asc: ascending sort or not
         @param nb_views_show_p: show the views column or not
         @param ln: language"""
 
         _ = gettext_set_language(ln)
 
         basket_name_label = _("Public basket")
         owner_label = _("Owner")
         date_modification_label = _("Last update")
         nb_items_label = _("Items")
         nb_views_label = _("Views")
 
         if sort == "name":
             if asc:
                 basket_name_sort_img = """<img src="%s/img/wb-sort-asc.gif" />""" % (CFG_SITE_URL,)
             else:
                 basket_name_sort_img = """<img src="%s/img/wb-sort-desc.gif" />""" % (CFG_SITE_URL,)
         else:
             basket_name_sort_img = """<img src="%s/img/wb-sort-none.gif" />""" % (CFG_SITE_URL,)
         if sort == "owner":
             if asc:
                 owner_sort_img = """<img src="%s/img/wb-sort-asc.gif" />""" % (CFG_SITE_URL,)
             else:
                 owner_sort_img = """<img src="%s/img/wb-sort-desc.gif" />""" % (CFG_SITE_URL,)
         else:
             owner_sort_img = """<img src="%s/img/wb-sort-none.gif" />""" % (CFG_SITE_URL,)
         if sort == "date":
             if asc:
                 date_modification_sort_img = """<img src="%s/img/wb-sort-asc.gif" />""" % (CFG_SITE_URL,)
             else:
                 date_modification_sort_img = """<img src="%s/img/wb-sort-desc.gif" />""" % (CFG_SITE_URL,)
         else:
             date_modification_sort_img = """<img src="%s/img/wb-sort-none.gif" />""" % (CFG_SITE_URL,)
         if sort == "items":
             if asc:
                 nb_items_sort_img = """<img src="%s/img/wb-sort-asc.gif" />""" % (CFG_SITE_URL,)
             else:
                 nb_items_sort_img = """<img src="%s/img/wb-sort-desc.gif" />""" % (CFG_SITE_URL,)
         else:
             nb_items_sort_img = """<img src="%s/img/wb-sort-none.gif" />""" % (CFG_SITE_URL,)
         if sort == "views":
             if asc:
                 nb_views_sort_img = """<img src="%s/img/wb-sort-asc.gif" />""" % (CFG_SITE_URL,)
             else:
                 nb_views_sort_img = """<img src="%s/img/wb-sort-desc.gif" />""" % (CFG_SITE_URL,)
         else:
             nb_views_sort_img = """<img src="%s/img/wb-sort-none.gif" />""" % (CFG_SITE_URL,)
 
         basket_name_sort = """<a href="%s/yourbaskets/list_public_baskets?limit=%i&amp;sort=name&amp;asc=%i&amp;ln=%s">%s</a>""" % \
                            (CFG_SITE_URL, limit, not(asc), ln, basket_name_sort_img)
         owner_sort = """<a href="%s/yourbaskets/list_public_baskets?limit=%i&amp;sort=owner&amp;asc=%i&amp;ln=%s">%s</a>""" % \
                      (CFG_SITE_URL, limit, not(asc), ln, owner_sort_img)
         date_modification_sort = """<a href="%s/yourbaskets/list_public_baskets?limit=%i&amp;sort=date&amp;asc=%i&amp;ln=%s">%s</a>""" % \
                                  (CFG_SITE_URL, limit, not(asc), ln, date_modification_sort_img)
         nb_items_sort = """<a href="%s/yourbaskets/list_public_baskets?limit=%i&amp;sort=items&amp;asc=%i&amp;ln=%s">%s</a>""" % \
                         (CFG_SITE_URL, limit, not(asc), ln, nb_items_sort_img)
         nb_views_sort = """<a href="%s/yourbaskets/list_public_baskets?limit=%i&amp;sort=views&amp;asc=%i&amp;ln=%s">%s</a>""" % \
                         (CFG_SITE_URL, limit, not(asc), ln, nb_views_sort_img)
 
         baskets_html = ''
         for (bskid, basket_name, owner_id, nickname, date_modification, nb_items, nb_views) in all_public_baskets:
             if nickname:
                 display = nickname
             else:
                 (owner_id, nickname, display) = get_user_info(owner_id)
             webmessage_link = self.__create_webmessage_link(nickname, display, ln)
 
             basket_link = """<a href="%s/yourbaskets/display_public?category=%s&amp;bskid=%s&amp;ln=%s">%s<a/>""" % \
                           (CFG_SITE_URL, CFG_WEBBASKET_CATEGORIES['EXTERNAL'], bskid, ln, cgi.escape(basket_name, True))
 
             nb_views_td = """<td class="bsk_list_public_baskets_basket_right">%i</td>""" % (nb_views,)
 
             baskets_html += """
     <tr>
       <td class="bsk_list_public_baskets_basket_left">%(basket_link)s</td>
       <td class="bsk_list_public_baskets_basket_left">%(webmessage_link)s</td>
       <td class="bsk_list_public_baskets_basket_left">%(date_modification)s</td>
       <td class="bsk_list_public_baskets_basket_right">%(nb_items)i</td>
       %(nb_views)s
     </tr>""" % {'basket_link': basket_link,
                 'webmessage_link': webmessage_link,
                 'date_modification': date_modification,
                 'nb_items': nb_items,
                 'nb_views': nb_views_show_p and nb_views_td or ''}
 
         if not all_public_baskets:
             baskets_html = """
     <tr>
       <td colspan="%i">
       %s
       </td>
     </tr>""" % (nb_views_show_p and 5 or 4,
                 _("There is currently no publicly accessible basket"))
 
         footer = ''
 
         if limit > CFG_WEBBASKET_MAX_NUMBER_OF_DISPLAYED_BASKETS:
             limit_first = 1
             page_first = """<a href="%s/yourbaskets/list_public_baskets?limit=%i&amp;sort=%s&amp;asc=%i&amp;ln=%s"><img src="%s" /></a>""" % \
                          (CFG_SITE_URL, limit_first, sort, asc, ln, '/img/sb.gif')
             footer += page_first
 
         if limit > 0:
             limit_previous = limit > CFG_WEBBASKET_MAX_NUMBER_OF_DISPLAYED_BASKETS \
                              and limit - CFG_WEBBASKET_MAX_NUMBER_OF_DISPLAYED_BASKETS + 1 \
                              or 1
             page_previous = """<a href="%s/yourbaskets/list_public_baskets?limit=%i&amp;sort=%s&amp;asc=%i&amp;ln=%s"><img src="%s" /></a>""" % \
                             (CFG_SITE_URL, limit_previous, sort, asc, ln, '/img/sp.gif')
             footer += page_previous
 
         display_from = limit + 1
         display_to = limit + CFG_WEBBASKET_MAX_NUMBER_OF_DISPLAYED_BASKETS > number_of_all_public_baskets \
                      and number_of_all_public_baskets \
                      or limit + CFG_WEBBASKET_MAX_NUMBER_OF_DISPLAYED_BASKETS
         footer += _('Displaying public baskets %(x_from)i - %(x_to)i out of %(x_total_public_basket)i public baskets in total.') % \
                {'x_from': display_from, 'x_to': display_to, 'x_total_public_basket': number_of_all_public_baskets}
 
         if limit < number_of_all_public_baskets - CFG_WEBBASKET_MAX_NUMBER_OF_DISPLAYED_BASKETS:
             limit_next = limit + CFG_WEBBASKET_MAX_NUMBER_OF_DISPLAYED_BASKETS + 1
             page_next = """<a href="%s/yourbaskets/list_public_baskets?limit=%i&amp;sort=%s&amp;asc=%i&amp;ln=%s"><img src="%s" /></a>""" % \
                         (CFG_SITE_URL, limit_next, sort, asc, ln, '/img/sn.gif')
             footer += page_next
 
         if limit < number_of_all_public_baskets - ( 2 * CFG_WEBBASKET_MAX_NUMBER_OF_DISPLAYED_BASKETS ):
             limit_last = number_of_all_public_baskets - CFG_WEBBASKET_MAX_NUMBER_OF_DISPLAYED_BASKETS + 1
             page_last = """<a href="%s/yourbaskets/list_public_baskets?limit=%i&amp;sort=%s&amp;asc=%i&amp;ln=%s"><img src="%s" /></a>""" % \
                         (CFG_SITE_URL, limit_last, sort, asc, ln, '/img/se.gif')
             footer += page_last
 
         if nb_views_show_p:
             nb_views_label_td = """<td>%(nb_views_label)s&nbsp;%(nb_views_sort)s</td>""" % \
                                 {'nb_views_label': nb_views_label,
                                  'nb_views_sort': nb_views_sort}
 
         out = """
 <table class="bsk_list_public_baskets" cellpadding="5px">
   <thead class="bsk_list_public_baskets_header">
     <tr>
       <td>%(basket_name_label)s&nbsp;%(basket_name_sort)s</td>
       <td>%(owner_label)s&nbsp;%(owner_sort)s</td>
       <td>%(date_modification_label)s&nbsp;%(date_modification_sort)s</td>
       <td>%(nb_items_label)s&nbsp;%(nb_items_sort)s</td>
       %(nb_views_label_td)s
     </tr>
   </thead>
   <tfoot class="bsk_list_public_baskets_footer">
     <tr>
       <td colspan="%(colspan)s" style="text-align:center">%(footer)s</td>
     </tr>
   </tfoot>
   <tbody>
     %(baskets)s
   </tbody>
 </table>""" % {'basket_name_label': basket_name_label,
                'basket_name_sort': basket_name_sort,
                'owner_label': owner_label,
                'owner_sort': owner_sort,
                'date_modification_label': date_modification_label,
                'date_modification_sort': date_modification_sort,
                'nb_items_label': nb_items_label,
                'nb_items_sort': nb_items_sort,
                'nb_views_label_td': nb_views_show_p and nb_views_label_td or '',
                'colspan': nb_views_show_p and 5 or 4,
                'footer': footer,
                'baskets': baskets_html}
 
         return out
 
     def tmpl_quote_comment_textual(self, title, uid, nickname, date, body, ln=CFG_SITE_LANG):
         """Return a comment in a quoted form (i.e. with '>' signs before each line)
         @param title: title of comment to quote
         @param uid: user id of user who posted comment to quote
         @param nickname: nickname of user who posted comment to quote
         @param date: date of post of comment to quote
         @param body: body of comment to quote
         @param ln: language"""
         _ = gettext_set_language(ln)
         if not(nickname):
             nickname = get_user_info(uid)[2]
 
         if title:
             msg = _("%(x_title)s, by %(x_name)s on %(x_date)s:") % \
                   {'x_title': title, 'x_name': nickname, 'x_date': date}
         else:
             msg = _("%(x_name)s wrote on %(x_date)s:") % {'x_name': nickname, 'x_date': date}
 
         msg += '\n\n'
         msg += body
         return email_quote_txt(msg)
 
     def tmpl_quote_comment_html(self, title, uid, nickname, date, body, ln=CFG_SITE_LANG):
         """Return a comment in a quoted form (i.e. indented using HTML
         table) for HTML output (i.e. in CKEditor).
 
         @param title: title of comment to quote
         @param uid: user id of user who posted comment to quote
         @param nickname: nickname of user who posted comment to quote
         @param date: date of post of comment to quote
         @param body: body of comment to quote
         @param ln: language"""
         _ = gettext_set_language(ln)
         if not(nickname):
             nickname = get_user_info(uid)[2]
 
         if title:
             msg = _("%(x_title)s, by %(x_name)s on %(x_date)s:") % \
                   {'x_title': title, 'x_name': nickname, 'x_date': date}
         else:
             msg = _("%(x_name)s wrote on %(x_date)s:") % {'x_name': nickname, 'x_date': date}
 
         msg += '<br/><br/>'
         msg += body
         msg = email_quote_txt(text=msg)
         msg = email_quoted_txt2html(text=msg)
 
         return '<br/>' + msg + '<br/>'
 
     def __tmpl_basket_box(self, img='', title='&nbsp;', subtitle='&nbsp;', body=''):
         """ private function, display a basket/topic selection box """
         out = """
 <table class="bskbasket">
   <thead class="bskbasketheader">
     <tr>
       <td class="bskactions">
         <img src="%(logo)s" alt="%(label)s" />
       </td>
       <td class="bsktitle">
         <b>%(label)s</b><br />
         %(count)s
       </td>
     </tr>
   </thead>
   <tbody>
     <tr>
       <td colspan="2">
         <table>%(basket_list)s
         </table>
       </td>
     </tr>
   </tbody>
 </table>"""
         out %= {'logo': img,
               'label': title, 'count': subtitle,
               'basket_list': body}
         return out
 
     def tmpl_create_box(self, new_basket_name='', new_topic_name='',
                         topics=[], selected_topic="",
                         ln=CFG_SITE_LANG):
         """Display a HTML box for creation of a new basket
         @param new_basket_name: prefilled value (string)
         @param new_topic_name: prefilled value (string)
         @param topics: list of topics (list of strings)
         @param selected_topic: preselected value for topic selection
         @param ln: language"""
         _ = gettext_set_language(ln)
         topics_html = ''
         #if selected_topic:
         #    try:
         #        selected_topic = topics.index(selected_topic)
         #    except:
         #        selected_topic = None
         if topics:
             topics = zip(topics, topics)
             topics.insert(0, (-1, _("Select topic")))
             topics_html = self.__create_select_menu('create_in_topic', topics, selected_topic)
         create_html = """
 <tr>
   <td style="padding: 10 5 0 5;">%s</td>
   <td style="padding: 10 5 0 0;">%s</td>
 </tr>
 <tr>
   <td style="padding: 10 5 0 5;">%s</td>
   <td style="padding: 10 5 0 0;"><input type="text" name="new_topic_name" value="%s"/></td>
 </tr>
 <tr>
   <td style="padding: 10 5 0 5;">%s</td>
   <td style="padding: 10 5 0 0;">
     <input type="text" name="new_basket_name" value="%s"/>
   </td>
-</tr>""" % (topics_html != '' and _("Choose topic") or '', topics_html,
-            topics_html != '' and _("or create a new one") or _("Create new topic"), new_topic_name,
-            _("Basket name"), new_basket_name,)
+</tr>""" % (topics_html != '' and _("Choose topic") or '',
+            topics_html,
+            topics_html != '' and _("or create a new one") or _("Create new topic"),
+            cgi.escape(new_topic_name, True),
+            _("Basket name"),
+            cgi.escape(new_basket_name, True))
         return self.__tmpl_basket_box(img=CFG_SITE_URL + '/img/webbasket_create.png',
                                       title=_("Create a new basket"),
                                       body=create_html)
 
     def tmpl_create_basket(self,
                            new_basket_name='',
                            new_topic_name='',
                            create_in_topic=None,
                            topics=[],
                            recids=[],
                            colid=-1,
                            es_title='',
                            es_desc='',
                            es_url='',
                            ln=CFG_SITE_LANG):
         """Template for basket creation
         @param new_basket_name: prefilled value (string)
         @param new_topic_name: prefilled value (string)
         @param topics: list of topics (list of strings)
         @param create_in_topic: preselected value for topic selection
         @param ln: language"""
         _ = gettext_set_language(ln)
         out = """
 <form name="create_basket" action="%(action)s" method="post">
   <input type="hidden" name="ln" value="%(ln)s" />
   <div style="padding:10px;">
     %(create_box)s
     %(recids)s
     %(es_title)s
     %(es_desc)s
     %(es_url)s
     <input type="hidden" name="colid" value="%(colid)s" />
     <input type="submit" value="%(label)s" class="formbutton"/>
   </div>
 </form>""" % {'action': CFG_SITE_URL + '/yourbaskets/create_basket',
               'ln': ln,
               'create_box': self.tmpl_create_box(new_basket_name=new_basket_name,
                                                  new_topic_name=new_topic_name,
                                                  topics=topics,
                                                  selected_topic=create_in_topic,
                                                  ln=ln),
               'recids': recids and '\n'.join(['<input type="hidden" name="recid" value="%s" />' % \
                                               recid for recid in recids]) or '',
               'es_title': es_title and \
                 '<input type="hidden" name="es_title" value="%s" />' % \
-                (es_title,) or '',
+                (cgi.escape(es_title, True),) or '',
               'es_desc': es_desc and \
                 '<input type="hidden" name="es_desc" value="%s" />' % \
-                (es_desc,) or '',
+                (cgi.escape(es_desc, True),) or '',
               'es_url': es_url and \
                 '<input type="hidden" name="es_url" value="%s" />' % \
-                (es_url,) or '',
+                (cgi.escape(es_url, True),) or '',
               'colid': colid,
               'label': _("Create new basket")}
         return out
 
     ############################ external sources ###########################
 
     def tmpl_external_source_add_box(self,
                                      title="",
                                      desc="",
                                      url="",
                                      ln=CFG_SITE_LANG):
         """Template for adding external items."""
 
         _ = gettext_set_language(ln)
 
         # Instead of the rich editor we choose to use everytime a simple textarea
         # because a rich text editor may already be used in the add to baskets
         # page to anotate.
         #desc_editor = get_html_text_editor(name="es_desc",
         #                                   content=desc,
         #                                   textual_content=desc,
         #                                   width="640px",
         #                                   height="100px",
         #                                   enabled=CFG_WEBBASKET_USE_RICH_TEXT_EDITOR,
         #                                   toolbar_set="WebComment")
         desc_editor = """<textarea name="es_desc" style="width: 640px; height: 100px;">%(value)s</textarea>""" % \
-                      {'value': desc}
+                      {'value': cgi.escape(desc, True)}
 
         out = """
 <table class="bskbasket" width="100%%">
   <thead>
     <tr>
       <td class="bskbasketheader">
         <table>
           <tr>
             <td class="bskbasketheadertitle">
               <strong>
               %(header_label)s
               </strong>
             </td>
         </table>
       </td>
     </tr>
   </thead>
   <tbody>
     <tr>
       <td style="padding: 10px;">
         %(instructions_label)s:
       </td>
     </tr>
     <tr>
       <td style="padding: 10px;">
         <p align="left">
         <small>%(title_label)s:</small>
         <br />
         <input type="text" name="es_title" size="65" value="%(es_title)s" />
         </p>
         <p align="left">
         <small>%(desc_label)s:</small>
         <br />
         %(desc_editor)s
         </p>
         <p align="left">
         <small>%(url_label)s:</small>
         <br />
         <input type="text" name="es_url" size="65" value="%(es_url)s" />
         <input type="hidden" name="colid" value="-1" />
         </p>
       </td>
     </tr>
   </tbody>
 </table>""" % {'header_label': _('External item'),
                'instructions_label': _('Provide a url for the external item you wish to add and fill in a title and description'),
                'title_label': _('Title'),
-               'es_title': title,
+               'es_title': cgi.escape(title, True),
                'desc_label': _('Description'),
                'desc_editor': desc_editor,
                'url_label': _('URL'),
-               'es_url': url}
+               'es_url': cgi.escape(url, True)}
 
         return out
 
     ########################## functions on baskets #########################
 
     def tmpl_add(self,
                  recids=[],
                  category="",
                  bskid=0,
                  colid=0,
                  es_title="",
                  es_desc="",
                  es_url="",
                  note_body="",
                  personal_basket_list=(),
                  group_basket_list=(),
                  successful_add=False,
                  copy=False,
                  referer='',
                  ln=CFG_SITE_LANG):
         """Template for addding items to baskets."""
 
         _ = gettext_set_language(ln)
 
         if successful_add:
             out = """
 %(success_label)s.
 <br /><br />
 %(proceed_label)s""" % {'success_label': _('%i items have been successfully added to your basket') % (colid == -1 and 1 or len(recids)),
                         'proceed_label': _('Proceed to the %(x_url_open)sbasket%(x_url_close)s') % \
                                          {'x_url_open': '<a href="%s/yourbaskets/display?category=%s&amp;bskid=%i&amp;ln=%s">' % (CFG_SITE_URL, category, bskid, ln),
                                          'x_url_close': "</a>"}}
             if referer:
                 if copy:
                     out +=  _(' or return to your %(x_url_open)sprevious basket%(x_url_close)s') % \
                             {'x_url_open': '<a href="%s">' % referer,
                              'x_url_close': '</a>'}
                 else:
                     out +=  _(' or return to your %(x_url_open)ssearch%(x_url_close)s') % \
                             {'x_url_open': '<a href="%s">' % referer,
                              'x_url_close': '</a>'}
             else:
                 out += "."
 
             return out
 
         out=""
 
         #If no recids were specified the page is asking which external item to add,
         #so we remind to the user to use the search engine for internal items.
         #(having no recids specified is just like having a colid equal -1)
         if len(recids) == 0:
         #if colid == -1:
             out += """
     <table class="bskbasket">
       <thead class="bskbasketheader">
         <tr>
           <td class="bskactions">
             <img src="%(logo)s" alt="%(label)s" />
           </td>
           <td class="bsktitle">
             <b>Adding items to your basket</b><br />
           </td>
         </tr>
       </thead>
       <tbody>
         <tr>
           <td colspan="2">
             <table>
             To add internal items to your basket please select them through the  <a href="%(search_link)s">search page</a>
             and use the "Add to basket" functionality. For any external resource please use the
             "External item" form below.
             </table>
           </td>
         </tr>
       </tbody>
     </table>"""
             out %= {'logo': "%s/img/tick.gif"% (CFG_SITE_URL,),
                   'label':"tick",
                   'search_link':"%s"%(CFG_SITE_URL,) }
 
         note_editor = get_html_text_editor(name="note_body",
                                            content=note_body,
                                            textual_content=note_body,
                                            width="600px",
                                            height="110px",
                                            enabled=CFG_WEBBASKET_USE_RICH_TEXT_EDITOR,
                                            toolbar_set="WebComment")
 
         select_options = create_add_box_select_options(category,
                                                        bskid,
                                                        personal_basket_list,
                                                        group_basket_list,
                                                        ln)
 
         hidden_recids = ""
         for recid in recids:
             hidden_recids += """
         <input type="hidden" name="recid" value="%s" />""" % (recid,)
 
         action = "%s/yourbaskets/add" % (CFG_SITE_URL,)
 
         out += """
 <form name="add_to_basket" action="%(action)s" method="post">""" % {'action': action}
 
         if colid == -1:
             out += self.tmpl_external_source_add_box(es_title, es_desc, es_url, ln)
 
         out += """
 <table class="bskbasket" width="100%%">
   <thead>
     <tr>
       <td class="bskbasketheader">
         <table>
           <tr>
             <td class="bskbasketheadertitle">
               <strong>
               %(header_label)s
               </strong>
             </td>
         </table>
       </td>
     </tr>
   </thead>
   <tbody>
     <tr>
       <td style="padding: 10px;">
       %(create_new_basket)s
         <br />
       </td>
     </tr>
     <tr>
       <td style="padding: 10px;">
         <p align="left">
         <small>%(note_label)s:</small>
         <br />
         %(note_editor)s
         </p>
       </td>
     </tr>
     <tr>
       <td style="padding: 10px;">
         %(hidden_recids)s
         <input type="hidden" name="colid" value="%(colid)s" />
         <input type="hidden" name="copy" value="%(copy)i" />
         <input type="hidden" name="referer" value="%(referer)s" />
         <input type="submit" class="formbutton" value="%(add_label)s" />
         <input type="button" class="nonsubmitbutton" value="%(cancel_label)s" onClick="window.location='/'" />
       </td>
     </tr>
   </tbody>
 </table>""" % {'header_label': _("Adding %i items to your baskets") % (colid == -1 and 1 or len(recids)),
                'create_new_basket': _("Please choose a basket: %(x_basket_selection_box)s %(x_fmt_open)s(or %(x_url_open)screate a new one%(x_url_close)s first)%(x_fmt_close)s") % \
                                     {'x_basket_selection_box': '&nbsp;<select name="b">%s</select>' % select_options,
                                      'x_url_open': colid == -1 and ('''<a href="%s/yourbaskets/create_basket?colid=-1" onClick="this.href+= \
-                                                                        '&es_title=' + encodeURIComponent(document.add_to_basket.es_title.value) + \
-                                                                        '&es_url=' + encodeURIComponent(document.add_to_basket.es_url.value) + \
-                                                                        '&es_desc=' + encodeURIComponent(document.add_to_basket.es_desc.value);">''' % \
+                                                                        '&amp;es_title=' + encodeURIComponent(document.add_to_basket.es_title.value) + \
+                                                                        '&amp;es_url=' + encodeURIComponent(document.add_to_basket.es_url.value) + \
+                                                                        '&amp;es_desc=' + encodeURIComponent(document.add_to_basket.es_desc.value);">''' % \
                                                                     (CFG_SITE_URL,))
-                                                                or ('<a href="%s/yourbaskets/create_basket?colid=%i&recid=%s">' % \
+                                                                or ('<a href="%s/yourbaskets/create_basket?colid=%i&amp;recid=%s">' % \
                                                                     (CFG_SITE_URL,
                                                                      colid,
-                                                                     '&recid='.join(str(recid) for recid in recids))),
+                                                                     '&amp;recid='.join(str(recid) for recid in recids))),
                                      'x_url_close': '</a>',
                                      'x_fmt_open': '<br /><small>',
                                      'x_fmt_close': '</small>'},
                'note_label': len(recids) > 1 and _('Optionally, add a note to each one of these items') \
                or _('Optionally, add a note to this item'),
                'note_editor': note_editor,
                'hidden_recids': hidden_recids,
                'colid': colid,
                'copy': copy and 1 or 0,
                'referer': referer,
                'add_label': _('Add items'),
                'cancel_label': _('Cancel')}
 
         out += """
 </form>"""
 
         return out
 
     def tmpl_confirm_delete(self, bskid,
                             (nb_users, nb_groups, nb_alerts),
                             category=CFG_WEBBASKET_CATEGORIES['PRIVATE'],
                             selected_topic="", selected_group_id=0,
                             ln=CFG_SITE_LANG):
         """
         display a confirm message
         @param bskid: basket id
         @param nb*: nb of users/groups/alerts linked to this basket
         @param category: private, group or external baskets are selected
         @param selected_topic: if private baskets, topic nb
         @param selected_group_id: if group: group to display baskets of
         @param ln: language
         @return: html output
         """
         _ = gettext_set_language(ln)
         message = _("Are you sure you want to delete this basket?")
         if nb_users:
             message += '<p>' + _("%i users are subscribed to this basket.")% nb_users + '</p>'
         if nb_groups:
             message += '<p>' + _("%i user groups are subscribed to this basket.")% nb_groups + '</p>'
         if nb_alerts:
             message += '<p>' + _("You have set %i alerts on this basket.")% nb_alerts + '</p>'
         out = """
 <table class="confirmoperation">
   <tr>
     <td colspan="2" class="confirmmessage">
       %(message)s
     </td>
   </tr>
   <tr>
     <td>
       <form name="validate" action="%(url_ok)s" method="post">
         <input type="hidden" name="confirmed" value="1" />
         <input type="hidden" name="category" value="%(category)s" />
         <input type="hidden" name="group" value="%(group)i" />
         <input type="hidden" name="topic" value="%(topic)s" />
         <input type="hidden" name="ln" value="%(ln)s" />
         <input type="hidden" name="bskid" value="%(bskid)i" />
         <input type="submit" value="%(yes_label)s" class="formbutton" />
       </form>
     </td>
     <td>
       <form name="cancel" action="%(url_cancel)s" method="get">
         <input type="hidden" name="category" value="%(category)s" />
         <input type="hidden" name="group" value="%(group)i" />
         <input type="hidden" name="topic" value="%(topic)s" />
         <input type="hidden" name="ln" value="%(ln)s" />
         <input type="submit" value="%(no_label)s" class="formbutton" />
       </form>
     </td>
   </tr>
-</table>"""% {'message': message,
+</table>"""% {'message': cgi.escape(message, True),
               'bskid': bskid,
               'url_ok': 'delete',
               'url_cancel': 'display',
               'category': category,
-              'topic': selected_topic,
+              'topic': cgi.escape(selected_topic, True),
               'group': selected_group_id,
               'ln':ln,
               'yes_label': _("Yes"),
               'no_label': _("Cancel")}
         return out
 
     def tmpl_edit(self, bskid, bsk_name, topic, topics, groups_rights, external_rights,
                   display_general=0, display_sharing=0, display_delete=0, ln=CFG_SITE_LANG):
         """Display interface for rights management over the given basket
         @param group_rights: list of (group id, name, rights) tuples
         @param external_rights: rights as defined in CFG_WEBBASKET_SHARE_LEVELS for public access.
         @param display_general: display fields name and topic, used with personal baskets
         @param display_sharing: display sharing possibilities
         @param display_delete: display delete basket button
         """
         _ = gettext_set_language(ln)
         general_body = ''
         if display_general:
             general_body = """
 <tr>
   <td class="bskcontentcol">%s</td>
   <td class="bskcontentcol"><input type="text" name="new_name" value="%s"/></td>
-</tr>""" % (_("Basket name"), cgi.escape(bsk_name, 1))
+</tr>""" % (_("Basket name"), cgi.escape(bsk_name, True))
             #topics_selection = zip(range(len(topics)), topics)
             topics_selection = zip(topics, topics)
             topics_selection.insert(0, (-1, _("Choose topic")))
             topics_body = """
 <tr>
   <td style="padding: 10 5 0 5;">%s</td>
   <td style="padding: 10 5 0 0;">%s</td>
 </tr>
 <tr>
   <td style="padding: 0 5 10 5;">%s</td>
   <td style="padding: 0 5 10 0;"><input type="text" name="new_topic_name" />
 </tr>""" %  (_("Choose topic"),
              self.__create_select_menu('new_topic', topics_selection, topic),
              _("or create a new one"))
             general_body += topics_body
         general_box = self.__tmpl_basket_box(img=CFG_SITE_URL + '/img/webbasket_user.png',
                                              title=_("General settings"),
                                              body = general_body)
         groups_body = ''
         if display_sharing:
             for (group_id, name, rights) in groups_rights:
                 groups_body += """
 <tr>
   <td>%s</td>
   <td>%s</td>
 </tr>""" % (name, self.__create_group_rights_selection_menu(group_id, rights, ln))
             groups_body += """
 <tr>
   <td colspan="2">
     <input type="submit" name="add_group" class="nonsubmitbutton" value="%s"/>
   </td>
 </tr>""" % _("Add group")
         else:
             groups_body = '<tr><td colspan="2">%s</td></tr>'
             groups_body %= self.tmpl_create_guest_forbidden_box(ln)
         groups_box = self.__tmpl_basket_box(img=CFG_SITE_URL + '/img/webbasket_usergroup.png',
                                             title=_("Manage group rights"),
                                             body=groups_body)
         if display_sharing:
             external_body = """
 <tr>
   <td>%s</td>
 </tr>""" % self.__create_rights_selection_menu('external', external_rights, ln)
         else:
             external_body = '<tr><td colspan="2">%s</td></tr>'
             external_body %= self.tmpl_create_guest_forbidden_box(ln)
 
         external_box = self.__tmpl_basket_box(img=CFG_SITE_URL + '/img/webbasket_world.png',
                                               title=_("Manage global sharing rights"),
                                               body=external_body)
         delete_button = ''
         if display_delete:
             delete_button = '<input type="submit" class="nonsubmitbutton" name="delete" value="%s" />'
             delete_button %=  _("Delete basket")
         out = """
 <form name="edit" action="%(action)s" method="post">
   <p>%(label)s</p>
   <input type="hidden" name="ln" value="%(ln)s" />
   <input type="hidden" name="bskid" value="%(bskid)i" />
   <input type="hidden" name="topic" value ="%(topic)s" />
   <table>
     <tr>
       <td colspan="3">%(general)s</td>
     </tr>
     <tr>
       <td colspan="3">%(groups)s</td>
     </tr>
     <tr>
       <td colspan="3">%(external)s</td>
     </tr>
     <tr>
       <td><input type="submit" class="formbutton" name="submit" value="%(submit_label)s" /></td>
       <td><input type="submit" class="nonsubmitbutton" name="cancel" value="%(cancel_label)s" /></td>
       <td>%(delete_button)s</td>
     </tr>
   </table>
 
 </form>""" % {'label': _('Editing basket %(x_basket_name)s') % \
-              {'x_basket_name': cgi.escape(bsk_name)},
+              {'x_basket_name': cgi.escape(bsk_name, True)},
               'action': CFG_SITE_URL + '/yourbaskets/edit',
               'ln': ln,
-              'topic': topic,
+              'topic': cgi.escape(topic, True),
               'bskid': bskid,
               'general': general_box,
               'groups': groups_box,
               'external': external_box,
               'submit_label': _("Save changes"),
               'cancel_label': _("Cancel"),
               'delete_button': delete_button}
         return out
 
     def tmpl_edit_topic(self, topic, display_general=0, display_delete=0, ln=CFG_SITE_LANG):
         """Display interface for topic editing.
         @param display_general: display topic name
         @param display_delete: display delete topic button
         """
         _ = gettext_set_language(ln)
         general_body = ''
         if not topic:
             general_body = """<div class="important" style="padding: 10px;">%s</div>"""
             general_body %= ("You must provide a valid topic name.",)
             display_general = False
         if display_general:
             general_body = """
 <tr>
   <td>%s</td>
   <td><input type="text" name="new_name" value="%s"/></td>
 </tr>""" % (_("Topic name"), cgi.escape(topic, True))
   #<td class="bskcontentcol">%s</td>
   #<td class="bskcontentcol"><input type="text" name="new_name" value="%s"/></td>
 
         general_box = self.__tmpl_basket_box(img=CFG_SITE_URL + '/img/webbasket_user.png',
                                              title=_("General settings"),
                                              body = general_body)
 
         delete_button = ''
         display_delete = False
         if display_delete:
             delete_button = '<input type="submit" class="nonsubmitbutton" name="delete" value="%s" />'
             delete_button %=  _("Delete basket")
         out = """
 <form name="edit" action="%(action)s" method="post">
   <p>%(label)s</p>
   <input type="hidden" name="ln" value="%(ln)s" />
   <input type="hidden" name="topic" value ="%(topic)s" />
   <table>
     <tr>
       <td colspan="3">%(general)s</td>
     </tr>
     <tr>
       <td><input type="submit" class="formbutton" name="submit" value="%(submit_label)s" /></td>
       <td><input type="submit" class="nonsubmitbutton" name="cancel" value="%(cancel_label)s" /></td>
       <td>%(delete_button)s</td>
     </tr>
   </table>
 
 </form>""" % {'label': _('Editing topic: %(x_topic_name)s') % {'x_topic_name': cgi.escape(topic, True)},
               'action': CFG_SITE_URL + '/yourbaskets/edit_topic',
               'ln': ln,
               'topic': cgi.escape(topic, True),
               'general': general_box,
               'submit_label': _("Save changes"),
               'cancel_label': _("Cancel"),
               'delete_button': delete_button}
         return out
 
     def __create_rights_selection_menu(self, name, current_rights, ln=CFG_SITE_LANG):
         """Private function. create a drop down menu for selection of rights
         @param name: name of menu (for HTML name attribute)
         @param current_rights: rights as defined in CFG_WEBBASKET_SHARE_LEVELS
         @param ln: language
         """
         _ = gettext_set_language(ln)
         elements = [('NO', _("No rights")),
                     (CFG_WEBBASKET_SHARE_LEVELS['READITM'],
                      _("View records")),
                     (CFG_WEBBASKET_SHARE_LEVELS['READCMT'],
                      '... ' + _("and") + ' ' + _("view comments")),
                     (CFG_WEBBASKET_SHARE_LEVELS['ADDCMT'],
                      '... ' + _("and") + ' ' + _("add comments"))]
         return self.__create_select_menu(name, elements, current_rights)
 
     def __create_group_rights_selection_menu(self, group_id, current_rights, ln=CFG_SITE_LANG):
         """Private function. create a drop down menu for selection of rights
         @param current_rights: rights as defined in CFG_WEBBASKET_SHARE_LEVELS
         @param ln: language
         """
         _ = gettext_set_language(ln)
         elements = [(str(group_id) + '_' + 'NO', _("No rights")),
                     (str(group_id) + '_' + CFG_WEBBASKET_SHARE_LEVELS['READITM'],
                      _("View records")),
                     (str(group_id) + '_' + CFG_WEBBASKET_SHARE_LEVELS['READCMT'],
                      '... ' + _("and") + ' ' + _("view notes")),
                     (str(group_id) + '_' + CFG_WEBBASKET_SHARE_LEVELS['ADDCMT'],
                      '... ' + _("and") + ' ' + _("add notes")),
                     (str(group_id) + '_' + CFG_WEBBASKET_SHARE_LEVELS['ADDITM'],
                      '... ' + _("and") + ' ' + _("add records")),
                     (str(group_id) + '_' + CFG_WEBBASKET_SHARE_LEVELS['DELCMT'],
                      '... ' + _("and") + ' ' + _("delete notes")),
                     (str(group_id) + '_' + CFG_WEBBASKET_SHARE_LEVELS['DELITM'],
                      '... ' + _("and") + ' ' + _("remove records")),
                     (str(group_id) + '_' + CFG_WEBBASKET_SHARE_LEVELS['MANAGE'],
                      '... ' + _("and") + ' ' + _("manage sharing rights"))
                     ]
         return self.__create_select_menu('groups', elements, str(group_id) + '_' + current_rights)
 
     def tmpl_add_group(self, bskid, selected_topic, groups=[], ln=CFG_SITE_LANG):
         """
         return form for selection of groups.
         @param bskid: basket id (int)
         @param selected_topic: topic currently displayed (int)
         @param groups: list of tuples (group id, group name)
         @param ln: language
         """
         _ = gettext_set_language(ln)
         if len(groups):
             groups_body = """
 <tr>
   <td>%s</td>
 </tr>""" % self.__create_select_menu('new_group', groups, selected_key=None)
         else:
             groups_body = """
 <tr>
   <td>%s</td>
 </tr>""" % _("You are not a member of a group.")
         groups_box = self.__tmpl_basket_box(img=CFG_SITE_URL + '/img/webbasket_usergroup.png',
                                             title=_("Add group"),
                                             body=groups_body)
         out = """
 <form name="add_group" action="%(action)s" method="post">
   <p>%(label)s</p>
   <input type="hidden" name="ln" value="%(ln)s" />
   <input type="hidden" name="bskid" value="%(bskid)i" />
   <input type="hidden" name="topic" value ="%(topic)s" />
   <table style="width:100%%;">
     <tr>
       <td style="width:50%%;vertical-align:top;">%(groups)s</td>
       <td style="width:50%%;vertical-align:top;"></td>
     </tr>
     <tr>
       <td colspan="2">
         <input type="submit" class="formbutton" name="group_cancel" value="%(cancel_label)s" />
         <input type="submit" class="formbutton" name="add_group" value="%(submit_label)s" />
       </td>
     </tr>
   </table>
 </form>""" % {'label': _('Sharing basket to a new group'),
               'action': CFG_SITE_URL + '/yourbaskets/edit',
               'ln': ln,
-              'topic': selected_topic,
+              'topic': cgi.escape(selected_topic, True),
               'bskid': bskid,
               'groups': groups_box,
               'cancel_label': _("Cancel"),
               'submit_label': _("Add group")}
         return out
 
     def tmpl_personal_baskets_selection_box(self,
                                             baskets=[],
                                             select_box_name='baskets',
                                             selected_bskid=None,
                                             ln=CFG_SITE_LANG):
         """return an HTML popupmenu
         @param baskets: list of (bskid, bsk_name, bsk_topic) tuples
         @param select_box_name: name that will be used for the control
         @param selected_bskid: id of the selcte basket, use None for no selection
         @param ln: language"""
         _ = gettext_set_language(ln)
         elements = [(0, '- ' + _("no basket") + ' -')]
         for (bskid, bsk_name, bsk_topic) in baskets:
-            elements.append((bskid, bsk_topic + ' > ' + bsk_name))
+            elements.append((bskid, bsk_topic + ' &gt; ' + bsk_name))
         return self.__create_select_menu(select_box_name, elements, selected_bskid)
 
     def tmpl_create_guest_warning_box(self, ln=CFG_SITE_LANG):
         """return html warning box for non registered users"""
         _ = gettext_set_language(ln)
         message = _("You are logged in as a guest user, so your baskets will disappear at the end of the current session.") + ' '
         message += _("If you wish you can %(x_url_open)slogin or register here%(x_url_close)s.") %\
             {'x_url_open': '<a href="' + CFG_SITE_SECURE_URL + '/youraccount/login?ln=' + ln + '">',
              'x_url_close': '</a>'}
         out = """
 <table class="errorbox">
     <tr>
       <th class="errorboxheader">%s</th>
     </tr>
 </table>"""
         return out % message
 
     def tmpl_create_guest_forbidden_box(self, ln=CFG_SITE_LANG):
         """return html warning box for non registered users"""
         _ = gettext_set_language(ln)
         message = _("This functionality is forbidden to guest users.") + ' '
         message += _("If you wish you can %(x_url_open)slogin or register here%(x_url_close)s.") %\
             {'x_url_open': '<a href="' + CFG_SITE_SECURE_URL + '/youraccount/login?ln=' + ln + '">',
              'x_url_close': '</a>'}
         out = """
 <table class="errorbox">
   <thead>
     <tr>
       <th class="errorboxheader">%s</th>
     </tr>
   </thead>
 </table>"""
         return out % message
 
 
     ############################ Utilities ###################################
 
     def __create_select_menu(self, name, elements, selected_key=None):
         """ private function, returns a popup menu
         @param name: name of HTML control
         @param elements: list of (key, value)
         @param selected_key: item that should be selected (key of elements tuple)
         """
         out = '<select name="%s">' % name
         for (key, label) in elements:
             selected = ''
             if key == selected_key:
                 selected = ' selected="selected"'
-            out += '<option value="%s"%s>%s</option>'% (key, selected, cgi.escape(label))
+            out += '<option value="%s"%s>%s</option>'% (cgi.escape(str(key), True), selected, cgi.escape(label, True))
         out += '</select>'
         return out
 
     def tmpl_warnings(self, warnings=[], ln=CFG_SITE_LANG):
         """ returns HTML for warnings """
         if type(warnings) is not list:
             warnings = [warnings]
         warningbox = ""
         if warnings:
             warningbox = "<div class=\"important\">\n"
             for warning in warnings:
                 lines = warning.split("\n")
                 warningbox += "  <p>"
                 for line in lines[0:-1]:
                     warningbox += line + "    <br />\n"
                 warningbox += lines[-1] + "  </p>"
             warningbox += "</div><br />\n"
         return warningbox
 
     def tmpl_back_link(self, link, ln=CFG_SITE_LANG):
         """ returns HTML for a link whose label should be
         'Back to search results'
         """
         _ = gettext_set_language(ln)
         label = _("Back to search results")
         out = '<a href="%s">%s</a>' % (link, label)
         return out
 
     def __create_webmessage_link(self, to, display_name, ln=CFG_SITE_LANG):
         """prints a link to the messaging system"""
         link = "%s/yourmessages/write?msg_to=%s&amp;ln=%s" % (CFG_SITE_URL, to, ln)
         if to:
             return '<a href="%s" class="maillink">%s</a>' % (link, display_name)
         else:
             return display_name
 
     def tmpl_xml_basket(self, items=[]):
         """Template for XML output of basket
         @param items: XML version of each item (list)"""
         items_xml = ''
         for item in items:
             items_xml += '  ' + item + '\n'
         return """<?xml version="1.0" encoding="UTF-8"?>
 <collection>
 %s
 </collection>
 """ % items_xml
 
     ############################ Baskets ###################################
 
     ##################################
     ########### BASKET VIEW ##########
     ##################################
 
     def tmpl_basket(self,
                     bskid,
                     name,
                     date_modification,
                     nb_items,
                     nb_subscribers,
                     (user_can_view_content,
                      user_can_edit_basket,
                      user_can_view_notes,
                      user_can_add_notes,
                      user_can_add_item,
                      user_can_delete_item),
                     nb_comments,
                     share_level,
                     selected_category=CFG_WEBBASKET_CATEGORIES['PRIVATE'],
                     selected_topic="",
                     selected_group=0,
                     items=[],
                     of='hb',
                     ln=CFG_SITE_LANG):
         """Template for basket display."""
 
         if not of.startswith('x'):
             out = """
 <table class="bskbasket" width="100%">"""
         else:
             out = ""
 
         if not of.startswith('x'):
             out += self.tmpl_basket_header(bskid,
                                            name,
                                            nb_items,
                                            nb_subscribers,
                                            date_modification,
                                            (user_can_view_content,
                                             user_can_edit_basket,
                                             user_can_view_notes),
                                            selected_category,
                                            nb_comments,
                                            selected_topic,
                                            share_level,
                                            ln)
 
         if not of.startswith('x'):
             out += self.tmpl_basket_footer(bskid,
                                            nb_items,
                                            (user_can_view_content,
                                             user_can_edit_basket),
                                            selected_category,
                                            selected_topic,
                                            share_level,
                                            ln)
 
         out += self.tmpl_basket_content(bskid,
                                         (user_can_view_content,
                                          user_can_view_notes,
                                          user_can_add_notes,
                                          user_can_add_item,
                                          user_can_delete_item),
                                         selected_category,
                                         selected_topic,
                                         selected_group,
                                         items,
                                         of,
                                         ln)
 
         if not of.startswith('x'):
             out += """
 </table>"""
 
         if not of.startswith('x'):
             out += self.tmpl_create_export_as_list(selected_category,
                                                    selected_topic,
                                                    selected_group,
                                                    bskid,
                                                    None,
                                                    False)
         return out
 
     def tmpl_basket_header(self,
                            bskid,
                            name,
                            nb_items,
                            nb_subscribers,
                            date_modification,
                            (user_can_view_content,
                             user_can_edit_basket,
                             user_can_view_notes),
                            selected_category,
                            nb_comments,
                            selected_topic,
                            share_level,
                            ln=CFG_SITE_LANG):
         """Template for basket header display."""
 
         _ = gettext_set_language(ln)
 
         optional_colspan = nb_items and user_can_view_content and ' colspan="3"' or ''
         records_field = '<br />' + _('%i items') % nb_items
         comments_field = user_can_view_notes and (nb_comments and (', ' + _('%i notes') % nb_comments) or ', ' + _('no notes yet')) or ''
         subscribers_field = selected_category == CFG_WEBBASKET_CATEGORIES['PRIVATE'] and \
                             share_level == 0 and \
                             ', ' + (_('%i subscribers') % nb_subscribers) or \
                             ''
         last_update_field = '<br />' + _('last update') + ': ' + date_modification
         if user_can_edit_basket:
-            add_ext_resource_url = """%s/yourbaskets/add?category=%s&bskid=%i""" % (CFG_SITE_URL,selected_category,bskid,)
+            add_ext_resource_url = """%s/yourbaskets/add?category=%s&amp;bskid=%i""" % (CFG_SITE_URL,selected_category,bskid,)
             add_ext_resource_logo = """<img src="%s/img/wb-create-basket.png" />""" % (CFG_SITE_URL,)
             add_ext_resource = """<a href="%s">%s%s</a>""" % (add_ext_resource_url, add_ext_resource_logo, _("Add item"))
-            edit_basket_url = """%s/yourbaskets/edit?bskid=%i&amp;topic=%s&amp;ln=%s""" % (CFG_SITE_URL, bskid, cgi.escape(selected_topic, True), ln)
+            edit_basket_url = """%s/yourbaskets/edit?bskid=%i&amp;topic=%s&amp;ln=%s""" % (CFG_SITE_URL, bskid, urllib.quote(selected_topic), ln)
             edit_basket_logo = """<img src="%s/img/wb-edit-basket.png" />""" % (CFG_SITE_URL,)
             edit_basket = """<a href="%s">%s%s</a>""" % (edit_basket_url, edit_basket_logo, _("Edit basket"))
-            delete_basket_url = """%s/yourbaskets/edit?bskid=%i&amp;topic=%s&amp;delete=1&amp;ln=%s""" % (CFG_SITE_URL, bskid, cgi.escape(selected_topic, True), ln)
+            delete_basket_url = """%s/yourbaskets/edit?bskid=%i&amp;topic=%s&amp;delete=1&amp;ln=%s""" % (CFG_SITE_URL, bskid, urllib.quote(selected_topic), ln)
             delete_basket_logo = """<img src="%s/img/wb-delete-basket.png" />""" % (CFG_SITE_URL,)
             delete_basket = """<a href="%s">%s%s</a>""" % (delete_basket_url, delete_basket_logo, _("Delete basket"))
         else:
             #edit_basket = """<small>%s</small>""" % (_("You cannot edit this basket"),)
             #delete_basket = """<small>%s</small>""" % (_("You cannot delete this basket"),)
             edit_basket = ""
             delete_basket = ""
             add_ext_resource = ""
         if selected_category==CFG_WEBBASKET_CATEGORIES['EXTERNAL']:
             unsubscribe_url = """%s/yourbaskets/unsubscribe?bskid=%i&amp;ln=%s""" % (CFG_SITE_URL, bskid, ln)
             unsubscribe_logo = """<img src="%s/img/wb-unsubscribe.png" />""" % (CFG_SITE_URL,)
             unsubscribe = """&nbsp;&nbsp;\n<a href="%s">%s%s</a>""" % (unsubscribe_url, unsubscribe_logo, _("Unsubscribe from basket"))
         else:
             unsubscribe = ""
         out = """
   <thead>
     <tr>
       <td class="bskbasketheader"%(optional_colspan)s>
         <table width="100%%">
           <tr>
             <td class="bskbasketheadertitle">
               <strong>
               %(name)s
               </strong>
               <small>
               %(records_field)s%(comments_field)s%(subscribers_field)s
               %(last_update_field)s
               </small>
             </td>
             <td class="bskbasketheaderoptions">
               %(add_ext_resource)s
               &nbsp;&nbsp;
               %(edit_basket)s
               &nbsp;&nbsp;
               %(delete_basket)s
               %(unsubscribe)s
             </td>
         </table>
       </td>
     </tr>
   </thead>"""
 
         out %= {'optional_colspan': optional_colspan,
                 'name': cgi.escape(name, True),
                 'nb_items': nb_items,
                 'records_field': records_field,
                 'comments_field': comments_field,
                 'subscribers_field': subscribers_field,
                 'last_update_field': last_update_field,
                 'add_ext_resource': add_ext_resource,
                 'edit_basket': edit_basket,
                 'delete_basket': delete_basket,
                 'unsubscribe': unsubscribe,
         }
 
         return out
 
     def tmpl_basket_footer(self,
                            bskid,
                            nb_items,
                            (user_can_view_content,
                             user_can_edit_basket),
                            selected_category,
                            selected_topic,
                            share_level=None,
                            ln=CFG_SITE_LANG):
         """Template for basket footer display."""
 
         _ = gettext_set_language(ln)
 
         optional_colspan = nb_items and user_can_view_content and ' colspan="3"' or ''
         if user_can_edit_basket:
-            add_ext_resource_url = """%s/yourbaskets/add?category=%s&bskid=%i""" % (CFG_SITE_URL,selected_category,bskid,)
+            add_ext_resource_url = """%s/yourbaskets/add?category=%s&amp;bskid=%i""" % (CFG_SITE_URL,selected_category,bskid,)
             add_ext_resource_logo = """<img src="%s/img/wb-create-basket.png" />""" % (CFG_SITE_URL,)
             add_ext_resource = """<a href="%s">%s%s</a>""" % (add_ext_resource_url, add_ext_resource_logo, _("Add item"))
-            edit_basket_url = """%s/yourbaskets/edit?bskid=%i&amp;topic=%s&amp;ln=%s""" % (CFG_SITE_URL, bskid, selected_topic, ln)
+            edit_basket_url = """%s/yourbaskets/edit?bskid=%i&amp;topic=%s&amp;ln=%s""" % (CFG_SITE_URL, bskid, urllib.quote(selected_topic), ln)
             edit_basket_logo = """<img src="%s/img/wb-edit-basket.png" />""" % (CFG_SITE_URL,)
             edit_basket = """<a href="%s">%s%s</a>""" % (edit_basket_url, edit_basket_logo, _("Edit basket"))
-            delete_basket_url = """%s/yourbaskets/edit?bskid=%i&amp;topic=%s&amp;delete=1&amp;ln=%s""" % (CFG_SITE_URL, bskid, selected_topic, ln)
+            delete_basket_url = """%s/yourbaskets/edit?bskid=%i&amp;topic=%s&amp;delete=1&amp;ln=%s""" % (CFG_SITE_URL, bskid, urllib.quote(selected_topic), ln)
             delete_basket_logo = """<img src="%s/img/wb-delete-basket.png" />""" % (CFG_SITE_URL,)
             delete_basket = """<a href="%s">%s%s</a>""" % (delete_basket_url, delete_basket_logo, _("Delete basket"))
         else:
             edit_basket = ""
             delete_basket = ""
             add_ext_resource = ""
         if selected_category==CFG_WEBBASKET_CATEGORIES['EXTERNAL']:
             unsubscribe_url = """%s/yourbaskets/unsubscribe?bskid=%i&amp;ln=%s""" % (CFG_SITE_URL, bskid, ln)
             unsubscribe_logo = """<img src="%s/img/wb-unsubscribe.png" />""" % (CFG_SITE_URL,)
             unsubscribe = """&nbsp;&nbsp;\n<a href="%s">%s%s</a>""" % (unsubscribe_url, unsubscribe_logo, _("Unsubscribe from basket"))
         else:
             unsubscribe = ""
         if share_level == 0:
             display_public_url = """%s/yourbaskets/display_public?bskid=%i""" % (CFG_SITE_URL, bskid)
             display_public_text = _("This basket is publicly accessible at the following address:")
             display_public = """%s<br /><a href="%s">%s</a>""" % (display_public_text, display_public_url, display_public_url)
         else:
             display_public = ""
         out = """
   <tfoot>
     <tr>
       <td class="bskbasketfooter"%(optional_colspan)s>
         <table width="100%%">
           <tr>
             <td class="bskbasketfootertitle">
               <small>
               %(display_public)s
               </small>
             </td>
             <td class="bskbasketfooteroptions">
               %(add_ext_resource)s
               &nbsp;&nbsp;
               %(edit_basket)s
               &nbsp;&nbsp;
               %(delete_basket)s
               %(unsubscribe)s
             </td>
           </tr>
         </table>
       </td>
     </tr>
   </tfoot>"""
 
         out %= {'optional_colspan': optional_colspan,
                 'display_public': display_public,
                 'add_ext_resource': add_ext_resource,
                 'edit_basket': edit_basket,
                 'delete_basket': delete_basket,
                 'unsubscribe': unsubscribe}
 
         return out
 
     def tmpl_basket_content(self,
                             bskid,
                             (user_can_view_content,
                              user_can_view_notes,
                              user_can_add_notes,
                              user_can_add_item,
                              user_can_delete_item),
                             selected_category=CFG_WEBBASKET_CATEGORIES['PRIVATE'],
                             selected_topic="",
                             selected_group=0,
                             items=[],
                             of='hb',
                             ln=CFG_SITE_LANG):
         """Template for basket content display."""
 
         if not of.startswith('x'):
             _ = gettext_set_language(ln)
             items_html = """
   <tbody>"""
             if user_can_view_content:
                 if not(items):
                     items_html += """
     <tr>
       <td style="text-align:center; height:100px">
       %s
       </td>
     </tr>""" % _("This basket does not contain any records yet.")
                 else:
                     count = 0
                     for item in items:
                         count += 1
                         copy = 1
                         go_up = go_down = delete = 0
                         if user_can_add_item:
                             go_up = go_down = 1
                             if item == items[0]:
                                 go_up = 0
                             if item == items[-1]:
                                 go_down = 0
                         if user_can_delete_item:
                             delete = 1
                         items_html += self.__tmpl_basket_item(count=count,
                                                               bskid=bskid,
                                                               item=item,
                                                               uparrow=go_up,
                                                               downarrow=go_down,
                                                               copy_item=copy,
                                                               delete_item=delete,
                                                               view_notes=user_can_view_notes,
                                                               add_notes=user_can_add_notes,
                                                               selected_category=selected_category,
                                                               selected_topic=selected_topic,
                                                               selected_group=selected_group,
                                                               ln=ln)
             else:
                 items_html += """
     <tr>
       <td style="text-align:center; height:100px">
       %s
       </td>
     </tr>""" % _("You do not have sufficient rights to view this basket's content.")
             items_html += """
   </tbody>"""
             return items_html
         else:
             items_xml = ""
             for item in items:
                 items_xml += item[4] + "\n"
             return items_xml
 
 
     def __tmpl_basket_item(self,
                            count,
                            bskid,
                            item,
                            uparrow=0,
                            downarrow=0,
                            copy_item=0,
                            delete_item=0,
                            view_notes=0,
                            add_notes=0,
                            selected_category=CFG_WEBBASKET_CATEGORIES['PRIVATE'],
                            selected_topic="",
                            selected_group=0,
                            ln=CFG_SITE_LANG):
         """Template for basket item display within the basket content."""
 
         _ = gettext_set_language(ln)
 
         (recid, colid, nb_cmt, last_cmt, val, dummy) = item
 
         if uparrow:
             moveup_url = "%(siteurl)s/yourbaskets/modify?action=moveup&amp;bskid=%(bskid)i&amp;recid=%(recid)i"\
                          "&amp;category=%(category)s&amp;topic=%(topic)s&amp;group_id=%(group)i&amp;ln=%(ln)s" % \
                          {'siteurl': CFG_SITE_URL,
                           'bskid': bskid,
                           'recid': recid,
                           'category': selected_category,
-                          'topic': selected_topic,
+                          'topic': urllib.quote(selected_topic),
                           'group': selected_group,
                           'ln': ln}
             moveup_img = "%s/img/wb-move-item-up.png" % (CFG_SITE_URL,)
             moveup = """<a href="%s"><img src="%s" alt="%s" /></a>""" % \
                        (moveup_url, moveup_img, _("Move item up"))
         else:
             moveup_img = "%s/img/wb-move-item-up-disabled.png" % (CFG_SITE_URL,)
             moveup = """<img src="%s" alt="%s" />""" % \
                        (moveup_img, _("You cannot move this item up"))
 
         if downarrow:
             movedown_url = "%(siteurl)s/yourbaskets/modify?action=movedown&amp;bskid=%(bskid)i&amp;recid=%(recid)i"\
                          "&amp;category=%(category)s&amp;topic=%(topic)s&amp;group_id=%(group)i&amp;ln=%(ln)s" % \
                          {'siteurl': CFG_SITE_URL,
                           'bskid': bskid,
                           'recid': recid,
                           'category': selected_category,
-                          'topic': selected_topic,
+                          'topic': urllib.quote(selected_topic),
                           'group': selected_group,
                           'ln': ln}
             movedown_img = "%s/img/wb-move-item-down.png" % (CFG_SITE_URL,)
             movedown = """<a href="%s"><img src="%s" alt="%s" /></a>""" % \
                        (movedown_url, movedown_img, _("Move item down"))
         else:
             movedown_img = "%s/img/wb-move-item-down-disabled.png" % (CFG_SITE_URL,)
             movedown = """<img src="%s" alt="%s" />""" % \
                        (movedown_img, _("You cannot move this item down"))
 
         if copy_item:
             copy_url = "%(siteurl)s/yourbaskets/modify?action=copy&amp;bskid=%(bskid)i&amp;recid=%(recid)i"\
                        "&amp;category=%(category)s&amp;topic=%(topic)s&amp;group_id=%(group)i&amp;ln=%(ln)s" % \
                        {'siteurl': CFG_SITE_URL,
                         'bskid': bskid,
                         'recid': recid,
                         'category': selected_category,
-                        'topic': selected_topic,
+                        'topic': urllib.quote(selected_topic),
                         'group': selected_group,
                         'ln': ln}
             copy_img = "%s/img/wb-copy-item.png" % (CFG_SITE_URL,)
             copy = """<a href="%s"><img src="%s" alt="%s" />%s</a>""" % \
                        (copy_url, copy_img, _("Copy item"), _("Copy item"))
         else:
             copy = ""
 
         if delete_item:
             remove_url = "%(siteurl)s/yourbaskets/modify?action=delete&amp;bskid=%(bskid)i&amp;recid=%(recid)i"\
                          "&amp;category=%(category)s&amp;topic=%(topic)s&amp;group=%(group)i&amp;ln=%(ln)s" % \
                          {'siteurl': CFG_SITE_URL,
                           'bskid': bskid,
                           'recid': recid,
                           'category': selected_category,
-                          'topic': selected_topic,
+                          'topic': urllib.quote(selected_topic),
                           'group': selected_group,
                           'ln': ln}
             remove_img = "%s/img/wb-delete-item.png" % (CFG_SITE_URL,)
             remove = """<a href="%s"><img src="%s" alt="%s" />%s</a>""" % \
                        (remove_url, remove_img, _("Remove item"), _("Remove item"))
         else:
             remove = ""
 
         if recid < 0:
             external_item_img = '<img src="%s/img/wb-external-item.png" alt="%s" style="vertical-align: top;" />&nbsp;' % \
                                  (CFG_SITE_URL, _("External item"))
         else:
             external_item_img = ''
 
         out = """
     <tr>
       <td class="webbasket_basket_content_item_cell">
         <table>
           <tr>
             <td class="bskcontentcount">
             %(count)i.
             </td>
             <td class="bskcontentcol" colspan="2">
             %(icon)s%(content)s
             </td>
           </tr>
           <tr>
             <td class="bskcontentoptions">
             %(moveup)s%(movedown)s
             </td>
             <td>
               <span class="moreinfo">"""
 
         if item[0] > 0:
             detailed_record = """<a class="moreinfo" href="%(siteurl)s/%(CFG_SITE_RECORD)s/%(recid)s">%(detailed_record_label)s</a>"""
             out += detailed_record + (view_notes and " - " or "")
             external_url = ""
         else:
             ## Uncomment the following lines if you want the Detailed record link to be
             ## displayed for external records but not for external sources (such as urls)
             #external_colid_and_url = db.get_external_colid_and_url(item[0])
             #if external_colid_and_url and external_colid_and_url[0][0] and external_colid_and_url[0][1]:
             #    detailed_record = '<a class="moreinfo" href="%(external_url)s">%(detailed_record_label)s</a>'
             #    out += detailed_record + (view_notes and " - " or "")
             #    external_url = external_colid_and_url[0][1]
             #else:
             #    external_url = ""
             ## Currently no external items (records or sources) have a Detailed record link
             external_url = ""
 
         # TODO: If a user has the right to view the notes but not to add new ones,
         # and there are no notes for some item an anchor to write notes will be
         # created but with no text, hence invisible. Fix this so that no anchor
         # is created whatsoever.
         if view_notes:
             notes = """\n<a class="moreinfo" href="%(siteurl)s/yourbaskets/%(add_and_view_notes_action)s?"""\
                     """category=%(category)s&amp;topic=%(topic)s&amp;group=%(group)i&amp;"""\
                     """bskid=%(bskid)s&amp;recid=%(recid)i&amp;ln=%(ln)s%(add_and_view_notes_inline_anchor)s">%(add_and_view_notes_label)s</a>"""
             out += notes
 
         out += """
               </span>
             </td>
             <td class="bskbasketheaderoptions">
             %(copy)s
             &nbsp;
             %(remove)s
             </td>
           </tr>
         </table>
       </td>
     </tr>"""
         out = out % {'moveup': moveup,
                      'movedown': movedown,
                      'count': count,
                      'icon': external_item_img,
                      'content': colid >= 0 and val or val and self.tmpl_create_pseudo_item(val) or _("This record does not seem to exist any more"),
                      'add_and_view_notes_action': nb_cmt and 'display' or 'write_note',
                      'add_and_view_notes_inline_anchor': not nb_cmt and '#note' or '',
                      'add_and_view_notes_label': nb_cmt and _('Notes') + ' (' + str(nb_cmt) + ')' or add_notes and _('Add a note...') or '',
                      'last_cmt': last_cmt,
                      'siteurl': CFG_SITE_URL,
                      'CFG_SITE_RECORD': CFG_SITE_RECORD,
                      'bskid': bskid,
                      'recid': recid,
                      'external_url': external_url,
                      'detailed_record_label': _("Detailed record"),
                      'category': selected_category,
-                     'topic': selected_topic,
+                     'topic': urllib.quote(selected_topic),
                      'group': selected_group,
                      'copy': copy,
                      'remove': remove,
                      'ln': ln}
         return out
 
     #############################################
     ########## BASKET SINGLE ITEM VIEW ##########
     #############################################
 
     def tmpl_basket_single_item(self,
                                 bskid,
                                 name,
                                 nb_items,
                                 (user_can_view_content,
                                  user_can_view_notes,
                                  user_can_add_notes,
                                  user_can_delete_notes),
                                 selected_category=CFG_WEBBASKET_CATEGORIES['PRIVATE'],
                                 selected_topic="",
                                 selected_group=0,
                                 item=(),
                                 comments=(),
                                 previous_item_recid=0,
                                 next_item_recid=0,
                                 item_index=0,
                                 optional_params={},
                                 of='hb',
                                 ln=CFG_SITE_LANG):
         """Template for basket's single item display."""
 
         if of != 'xm':
             out = """
 <table class="bskbasket" width="100%">"""
         else:
             out = ""
 
         if of != 'xm':
             out += self.tmpl_basket_single_item_header(bskid,
                                                        name,
                                                        nb_items,
                                                        selected_category,
                                                        selected_topic,
                                                        selected_group,
                                                        previous_item_recid,
                                                        next_item_recid,
                                                        item_index,
                                                        ln)
 
         if of != 'xm':
             out += self.tmpl_basket_single_item_footer(bskid,
                                                        selected_category,
                                                        selected_topic,
                                                        selected_group,
                                                        previous_item_recid,
                                                        next_item_recid,
                                                        ln)
 
         out += self.tmpl_basket_single_item_content(bskid,
                                                     (user_can_view_content,
                                                      user_can_view_notes,
                                                      user_can_add_notes,
                                                      user_can_delete_notes),
                                                     selected_category,
                                                     selected_topic,
                                                     selected_group,
                                                     item,
                                                     comments,
                                                     item_index,
                                                     optional_params,
                                                     of,
                                                     ln)
 
         if of != 'xm':
             out += """
 </table>"""
 
         if of != 'xm':
             out += self.tmpl_create_export_as_list(selected_category,
                                                    selected_topic,
                                                    selected_group,
                                                    bskid,
                                                    item,
                                                    False)
 
         return out
 
     def tmpl_basket_single_item_header(self,
                                        bskid,
                                        name,
                                        nb_items,
                                        selected_category,
                                        selected_topic,
                                        selected_group,
                                        previous_item_recid,
                                        next_item_recid,
                                        item_index,
                                        ln=CFG_SITE_LANG):
         """Template for basket's single item header display."""
 
         _ = gettext_set_language(ln)
 
         records_field = '<br />' + _('Item %(x_item_index)i of %(x_item_total)i') % \
                         {'x_item_index': item_index, 'x_item_total': nb_items}
 
         if previous_item_recid:
             previous_item_url = """%s/yourbaskets/display?category=%s&amp;topic=%s&amp;group=%i&amp;bskid=%i&amp;recid=%s&amp;ln=%s""" % \
                                 (CFG_SITE_URL,
                                  selected_category,
-                                 selected_topic,
+                                 urllib.quote(selected_topic),
                                  selected_group,
                                  bskid,
                                  previous_item_recid,
                                  ln)
             previous_item_logo = """<img src="%s/img/wb-previous-item.png" />""" % (CFG_SITE_URL,)
             previous_item = """<a href="%s">%s%s</a>""" % (previous_item_url, previous_item_logo, _("Previous item"))
         else:
             previous_item_logo = """<img src="%s/img/wb-previous-item-disabled.png" />""" % (CFG_SITE_URL,)
             previous_item = """%s%s""" % (previous_item_logo, _("Previous item"))
 
         if next_item_recid:
             next_item_url = """%s/yourbaskets/display?category=%s&amp;topic=%s&amp;group=%i&amp;bskid=%i&amp;recid=%s&amp;ln=%s""" % \
                             (CFG_SITE_URL,
                              selected_category,
-                             selected_topic,
+                             urllib.quote(selected_topic),
                              selected_group,
                              bskid,
                              next_item_recid,
                              ln)
             next_item_logo = """<img src="%s/img/wb-next-item.png" />""" % (CFG_SITE_URL,)
             next_item = """<a href="%s">%s%s</a>""" % (next_item_url, next_item_logo, _("Next item"))
         else:
             next_item_logo = """<img src="%s/img/wb-next-item-disabled.png" />""" % (CFG_SITE_URL,)
             next_item = """%s%s""" % (next_item_logo, _("Next item"))
 
         go_back_url = """%s/yourbaskets/display?category=%s&amp;topic=%s&amp;group=%i&amp;bskid=%i&amp;ln=%s""" % \
                       (CFG_SITE_URL,
                        selected_category,
-                       selected_topic,
+                       urllib.quote(selected_topic),
                        selected_group,
                        bskid,
                        ln)
         go_back_logo = """<img src="%s/img/wb-go-back.png" />""" % (CFG_SITE_URL,)
         go_back = """<a href="%s">%s%s</a>""" % (go_back_url, go_back_logo, _("Return to basket"))
 
         out = """
   <thead>
     <tr>
       <td class="bskbasketheader">
         <table>
           <tr>
             <td class="bskbasketheadertitle">
               <strong>
               %(name)s
               </strong>
               <small>
               %(records_field)s
               </small>
             </td>
             <td class="bskbasketheaderoptions">
               %(go_back)s
               &nbsp;&nbsp;
               %(previous_item)s
               &nbsp;&nbsp;
               %(next_item)s
             </td>
         </table>
       </td>
     </tr>
   </thead>"""
 
         out %= {'name': name,
                 'records_field': records_field,
                 'go_back': go_back,
                 'previous_item': previous_item,
                 'next_item': next_item,
         }
 
         return out
 
     def tmpl_basket_single_item_footer(self,
                                        bskid,
                                        selected_category,
                                        selected_topic,
                                        selected_group,
                                        previous_item_recid,
                                        next_item_recid,
                                        ln=CFG_SITE_LANG):
         """Template for basket's single item footer display."""
 
         _ = gettext_set_language(ln)
 
         if previous_item_recid:
             previous_item_url = """%s/yourbaskets/display?category=%s&amp;topic=%s&amp;group=%i&amp;bskid=%i&amp;recid=%s&amp;ln=%s""" % \
                                 (CFG_SITE_URL,
                                  selected_category,
-                                 selected_topic,
+                                 urllib.quote(selected_topic),
                                  selected_group,
                                  bskid,
                                  previous_item_recid,
                                  ln)
             previous_item_logo = """<img src="%s/img/wb-previous-item.png" />""" % (CFG_SITE_URL,)
             previous_item = """<a href="%s">%s%s</a>""" % (previous_item_url, previous_item_logo, _("Previous item"))
         else:
             previous_item_logo = """<img src="%s/img/wb-previous-item-disabled.png" />""" % (CFG_SITE_URL,)
             previous_item = """%s%s""" % (previous_item_logo, _("Previous item"))
 
         if next_item_recid:
             next_item_url = """%s/yourbaskets/display?category=%s&amp;topic=%s&amp;group=%i&amp;bskid=%i&amp;recid=%s&amp;ln=%s""" % \
                             (CFG_SITE_URL,
                              selected_category,
-                             selected_topic,
+                             urllib.quote(selected_topic),
                              selected_group,
                              bskid,
                              next_item_recid,
                              ln)
             next_item_logo = """<img src="%s/img/wb-next-item.png" />""" % (CFG_SITE_URL,)
             next_item = """<a href="%s">%s%s</a>""" % (next_item_url, next_item_logo, _("Next item"))
         else:
             next_item_logo = """<img src="%s/img/wb-next-item-disabled.png" />""" % (CFG_SITE_URL,)
             next_item = """%s%s""" % (next_item_logo, _("Next item"))
 
         go_back_url = """%s/yourbaskets/display?category=%s&amp;topic=%s&amp;group=%i&amp;bskid=%i&amp;ln=%s""" % \
                       (CFG_SITE_URL,
                        selected_category,
-                       selected_topic,
+                       urllib.quote(selected_topic),
                        selected_group,
                        bskid,
                        ln)
         go_back_logo = """<img src="%s/img/wb-go-back.png" />""" % (CFG_SITE_URL,)
         go_back = """<a href="%s">%s%s</a>""" % (go_back_url, go_back_logo, _("Return to basket"))
 
         out = """
   <tfoot>
     <tr>
       <td class="bskbasketfooter">
         <table width="100%%">
           <tr>
             <td class="bskbasketfootertitle">
               &nbsp;
             </td>
             <td class="bskbasketfooteroptions">
               %(go_back)s
               &nbsp;&nbsp;
               %(previous_item)s
               &nbsp;&nbsp;
               %(next_item)s
             </td>
         </table>
       </td>
     </tr>
   </tfoot>"""
 
         out %= {'go_back': go_back,
                 'previous_item': previous_item,
                 'next_item': next_item,
         }
 
         return out
 
     def tmpl_basket_single_item_content(self,
                                         bskid,
                                         (user_can_view_content,
                                          user_can_view_notes,
                                          user_can_add_notes,
                                          user_can_delete_notes),
                                         selected_category=CFG_WEBBASKET_CATEGORIES['PRIVATE'],
                                         selected_topic="",
                                         selected_group=0,
                                         item=(),
                                         notes=(),
                                         index_item=0,
                                         optional_params={},
                                         of='hb',
                                         ln=CFG_SITE_LANG):
         """Template for basket's single item content display."""
 
         if of != 'xm':
             _ = gettext_set_language(ln)
 
             item_html = """
   <tbody>"""
 
             if user_can_view_content:
                 if not item:
                     item_html += """
     <tr>
       <td style="text-align: center; height: 100px">
         %s
       </td>
     </tr>""" % _("The item you have selected does not exist.")
 
                 else:
                     (recid, colid, dummy, last_cmt, val, dummy) = item
 
                     if recid < 0:
                         external_item_img = '<img src="%s/img/wb-external-item.png" alt="%s" style="vertical-align: top;" />&nbsp;' % \
                                              (CFG_SITE_URL, _("External item"))
                     else:
                         external_item_img = ''
 
                     if user_can_view_notes:
                         notes_html = self.__tmpl_display_notes(recid,
                                                                bskid,
                                                                (user_can_add_notes,
                                                                 user_can_delete_notes),
                                                                selected_category,
                                                                selected_topic,
                                                                selected_group,
                                                                notes,
                                                                optional_params,
                                                                ln)
                         notes = """
           <tr>
             <td colspan="2" class="bskcontentnotes">%(notes_html)s
             </td>
           </tr>""" % {'notes_html': notes_html}
                     else:
                         notes_msg = _("You do not have sufficient rights to view this item's notes.")
                         notes = """
           <tr>
             <td colspan="2" style="text-align: center; height: 50px">
               %(notes_msg)s
             </td>
           </tr>""" % {'notes_msg': notes_msg}
 
                     item_html += """
     <tr>
       <td style="border-bottom: 1px solid #fc0;">
         <table>
           <tr>
             <td class="bskcontentcount">
             %(count)i.
             </td>
             <td class="bskcontentcol">
             %(icon)s%(content)s
             </td>
           </tr>%(notes)s
         </table>
       </td>
     </tr>""" % {'count': index_item,
                 'icon': external_item_img,
                 'content': colid >=0 and val or val and self.tmpl_create_pseudo_item(val) or _("This record does not seem to exist any more"),
-                'last_cmt': last_cmt,
-                'siteurl': CFG_SITE_URL,
-                'bskid': bskid,
-                'recid': recid,
-                'category': selected_category,
-                'topic': selected_topic,
-                'group': selected_group,
-                'notes': notes,
-                'ln': ln}
+                'notes': notes}
 
             else:
                 item_html += """
     <tr>
       <td style="text-align: center; height: 100px">
         %s
       </td>
     </tr>""" % _("You do not have sufficient rights to view this item.")
 
             item_html += """
   </tbody>"""
 
             return item_html
         else:
             item_xml = item[4]
             return item_xml
 
     def __tmpl_display_notes(self,
                              recid,
                              bskid,
                              (user_can_add_notes,
                               user_can_delete_notes),
                              selected_category,
                              selected_topic,
                              selected_group,
                              notes,
                              optional_params,
                              ln=CFG_SITE_LANG):
         """Template for basket's single item notes display."""
 
         _ = gettext_set_language(ln)
 
         warnings_html = ""
 
         add_note_p = False
         if user_can_add_notes and (optional_params.has_key("Add note") or optional_params.has_key("Incomplete note")):
             add_note_p = True
             if optional_params.has_key("Add note") and optional_params['Add note']:
                 replied_to_note = optional_params['Add note']
                 note_body_html = self.tmpl_quote_comment_html(replied_to_note[2],
                                                               replied_to_note[1],
                                                               replied_to_note[0],
                                                               replied_to_note[4],
                                                               replied_to_note[3],
                                                               ln)
                 note_body_textual = self.tmpl_quote_comment_textual(replied_to_note[2],
                                                                     replied_to_note[1],
                                                                     replied_to_note[0],
                                                                     replied_to_note[4],
                                                                     replied_to_note[3],
                                                                     ln)
                 note_title = "Re: " + replied_to_note[2]
             elif optional_params.has_key("Incomplete note") and optional_params['Incomplete note']:
                 incomplete_note = optional_params['Incomplete note']
                 note_body_html = incomplete_note[1]
                 # TODO: Do we need to format incomplete body correctly as textual
                 # and html as above?
                 note_body_textual = incomplete_note[1]
                 note_title = incomplete_note[0]
                 if optional_params.has_key("Warnings"):
                     warnings = optional_params["Warnings"]
                     warnings_html = self.tmpl_warnings(warnings, ln)
             else:
                 note_body_html = ""
                 note_body_textual = ""
                 note_title = ""
                 if optional_params.has_key("Warnings"):
                     warnings = optional_params["Warnings"]
                     warnings_html = self.tmpl_warnings(warnings, ln)
             # TODO: calculate the url
             file_upload_url = ""
             action = """%s/yourbaskets/save_note?category=%s&amp;topic=%s&amp;group=%i&amp;bskid=%i&amp;recid=%i&amp;ln=%s%s""" % \
-                     (CFG_SITE_URL, selected_category, selected_topic, selected_group, bskid, recid, ln, '#note')
+                     (CFG_SITE_URL, selected_category, urllib.quote(selected_topic), selected_group, bskid, recid, ln, '#note')
             cancel = """%s/yourbaskets/display?category=%s&amp;topic=%s&amp;group=%i&amp;bskid=%i&amp;recid=%i&amp;ln=%s""" % \
-                     (CFG_SITE_URL, selected_category, selected_topic, selected_group, bskid, recid, ln)
+                     (CFG_SITE_URL, selected_category, urllib.quote(selected_topic), selected_group, bskid, recid, ln)
             editor = get_html_text_editor(name="note_body",
                                           content=note_body_html,
                                           textual_content=note_body_textual,
                                           width="99%",
                                           height="160px",
                                           enabled=CFG_WEBBASKET_USE_RICH_TEXT_EDITOR,
                                           file_upload_url=file_upload_url,
                                           toolbar_set="WebComment")
             add_note_html = """
                     <table cellspacing="0" cellpadding="0" class="bsknotescontentaddnote">
                       <tr>
                         <td class="bsknotescontentaddform">
                           <form name="write_note" method="post" action="%(action)s">
                             <a name="note"></a><strong>%(add_a_note_label)s</strong>
                             %(warnings_html)s
                             <p align="left">
                             <small>Subject:</small>
                             <br />
                             <input type="text" name="note_title" size="65" value="%(note_title)s" />
                             </p>
                             <p align="left">
                             <small>Note:</small>
                             <br />
                             %(editor)s
                             </p>
                             <input type="hidden" name="reply_to" value="%(reply_to)s" />
                             <p align="left">
                             <input type="submit" class="formbutton" value="%(submit_label)s" />
                             <input type="button" class="nonsubmitbutton" value="%(cancel_label)s" onClick="window.location='%(cancel)s'" />
                             </p>
                           </form>
                         </td>
                       </tr>
                     </table>""" % {'action': action,
                                    'warnings_html': warnings_html,
                                    'cancel': cancel,
                                    'cancel_label': _('Cancel'),
                                    'note_title': note_title,
                                    'editor': editor,
                                    'add_a_note_label': _('Add a note'),
                                    'submit_label': _('Add note'),
                                    'reply_to': optional_params.get("Reply to")}
 
         notes_icon = '<img src="%s/img/wb-notes.png" style="vertical-align: top;" />&nbsp;' % (CFG_SITE_URL,)
 
         if user_can_add_notes and not add_note_p:
             add_note_url = """%s/yourbaskets/write_note?category=%s&amp;topic=%s&amp;group=%i&amp;bskid=%i&amp;recid=%i&amp;ln=%s%s""" % \
-                           (CFG_SITE_URL, selected_category, selected_topic, selected_group, bskid, recid, ln, '#note')
+                           (CFG_SITE_URL, selected_category, urllib.quote(selected_topic), selected_group, bskid, recid, ln, '#note')
             add_note_logo = """<img src="%s/img/wb-add-note.png" />""" % (CFG_SITE_URL,)
             add_note = """<a href="%s">%s%s</a>""" % (add_note_url, add_note_logo, _("Add a note"))
         else:
             add_note = ""
 
         notes_html = """
               <table>
                 <tr>
                   <td class="bsknotesheadertitle">
                   <br />
                   <strong>%(notes_icon)s%(notes_label)s</strong>
                   <br />
                   <small>%(nb_notes)i notes in total</small>
                   </td>
                   <td class="bsknotesheaderoptions">
                   %(add_note)s
                   </td>
                 </tr>""" % {'notes_label': _('Notes'),
                             'notes_icon': notes_icon,
                             'add_note': (notes and user_can_add_notes and not add_note_p) and add_note or "&nbsp;",
                             'nb_notes': len(notes)}
 
         if notes or add_note or add_note_p:
             notes_html += """
                 <tr>
                   <td colspan="2" class="bsknotescontent">"""
             thread_history = [0]
             for (cmt_uid, cmt_nickname, cmt_title, cmt_body, cmt_date, dummy, cmtid, reply_to) in notes:
                 if reply_to not in thread_history:
                     # Going one level down in the thread
                     thread_history.append(reply_to)
                     depth = thread_history.index(reply_to)
                 else:
                     depth = thread_history.index(reply_to)
                     thread_history = thread_history[:depth + 1]
                 notes_html += '<div style="margin-left:%spx">' % (depth*20)
                 if user_can_add_notes:
                     reply_to_note = """<a href="%s/yourbaskets/write_note?category=%s&amp;topic=%s&amp;group=%i&amp;bskid=%i&amp;recid=%i&amp;cmtid=%i&amp;ln=%s%s">%s</a>""" % \
-                                    (CFG_SITE_URL, selected_category, cgi.escape(selected_topic, True), selected_group, bskid, recid, cmtid, ln, '#note', _('Reply'))
+                                    (CFG_SITE_URL, selected_category, urllib.quote(selected_topic), selected_group, bskid, recid, cmtid, ln, '#note', _('Reply'))
                 else:
                     reply_to_note = ""
                 if user_can_delete_notes:
                     delete_note = """&nbsp;|&nbsp;<a href="%s/yourbaskets/delete_note?category=%s&amp;topic=%s&amp;group=%i&amp;bskid=%i&amp;recid=%i&amp;cmtid=%i&amp;ln=%s">%s</a>""" % \
-                                  (CFG_SITE_URL, selected_category, cgi.escape(selected_topic, True), selected_group, bskid, recid, cmtid, ln, _('Delete'))
+                                  (CFG_SITE_URL, selected_category, urllib.quote(selected_topic), selected_group, bskid, recid, cmtid, ln, _('Delete'))
                 else:
                     delete_note = ""
                 notes_html += """
                     <table cellspacing="0" cellpadding="0" class="bsknotescontentnote">
                       <tr>
                         <td class="bsknotescontenttitle">
                         %(inline_anchor)s<img src="%(CFG_SITE_URL)s/img/user-icon-1-24x24.gif" />%(authorship)s
                         </td>
                       </tr>
                       <tr>
                         <td class="bsknotescontentbody">
                         <blockquote>
                         %(body)s
                         </blockquote>
                         </td>
                       </tr>
                       <tr>
                         <td class="bsknotescontentoptions">
                         %(reply_to_note)s%(delete_note)s
                         </td>
                       </tr>
                     </table>
                     <br />""" % {'inline_anchor': (not add_note_p and notes[-1][-1]==cmtid) and '<a name="note"></a>' or '',
                                  'CFG_SITE_URL': CFG_SITE_URL,
                                  'authorship': _("%(x_title)s, by %(x_name)s on %(x_date)s") % \
                                                {'x_title': '<strong>' + (cmt_title and cgi.escape(cmt_title, True) \
                                                                          or _('Note')) + '</strong>',
                                                 'x_name': '<a href="%(CFG_SITE_URL)s/yourmessages/write?msg_to=%(user)s">%(user_display)s</a>' % \
                                                           {'CFG_SITE_URL': CFG_SITE_URL,
                                                            'user': cmt_nickname or cmt_uid,
                                                            'user_display': cmt_nickname or get_user_info(cmt_uid)[2]},
                                                 'x_date': '<em>' + convert_datetext_to_dategui(cmt_date) + '</em>'},
                                  'body': email_quoted_txt2html(escape_email_quoted_text(cmt_body)),
                                  'reply_to_note': reply_to_note,
                                  'delete_note': delete_note}
                 notes_html += '</div>'
             if add_note_p:
                 notes_html += add_note_html
             notes_html += """
                   </td>
                 </tr>"""
 
         notes_html += """
                 <tr>
                   <td class="bsknotesfootertitle">
                   &nbsp;
                   </td>
                   <td class="bsknotesfooteroptions">
                   %(add_note)s
                   </td>
                 </tr>
               </table>""" % {'add_note': (user_can_add_notes and not add_note_p) and add_note or '&nbsp;'}
 
         return notes_html
 
     ########################################
     ########## PUBLIC BASKET VIEW ##########
     ########################################
 
     def tmpl_public_basket(self,
                            bskid,
                            basket_name,
                            date_modification,
                            nb_items,
                            (user_can_view_comments,),
                            nb_comments,
                            items=[],
                            id_owner=0,
                            subscription_status=0,
                            of='hb',
                            ln=CFG_SITE_LANG):
         """Template for public basket display."""
 
         if of == 'hb':
             out = """
 <table class="bskbasket" width="100%">"""
         else:
             out = ""
 
         if of == 'hb':
             out += self.tmpl_public_basket_header(bskid,
                                                   basket_name,
                                                   nb_items,
                                                   date_modification,
                                                   (user_can_view_comments,),
                                                   nb_comments,
                                                   subscription_status,
                                                   ln)
 
         if of == 'hb':
             out += self.tmpl_public_basket_footer(bskid,
                                                   nb_items,
                                                   id_owner,
                                                   subscription_status,
                                                   ln)
 
         out += self.tmpl_public_basket_content(bskid,
                                                (user_can_view_comments,),
                                                items,
                                                of,
                                                ln)
 
         if of == 'hb':
             out += """
 </table>"""
 
         if of == 'hb':
             out += self.tmpl_create_export_as_list(bskid=bskid,
                                                    item=None,
                                                    public=True)
 
         return out
 
     def tmpl_public_basket_header(self,
                                   bskid,
                                   name,
                                   nb_items,
                                   date_modification,
                                   (user_can_view_comments,),
                                   nb_comments,
                                   subscription_status,
                                   ln=CFG_SITE_LANG):
         """Template for public basket header display."""
 
         _ = gettext_set_language(ln)
 
         optional_colspan = nb_items and ' colspan="3"' or ''
         records_field = '<br />' + _('%i items') % nb_items
         comments_field = user_can_view_comments and \
                          (nb_comments and ', ' + (_('%i notes') % nb_comments) or ', ' + _('no notes yet')) \
                          or ''
         last_update_field = '<br />' + _('last update') + ': ' + date_modification
 
         if subscription_status:
             subscribe_url = """%s/yourbaskets/subscribe?bskid=%i&amp;ln=%s""" % (CFG_SITE_URL, bskid, ln)
             subscribe_logo = """<img src="%s/img/wb-subscribe.png" />""" % (CFG_SITE_URL,)
             subscribe = """<a href="%s">%s%s</a>""" % (subscribe_url, subscribe_logo, _("Subscribe to basket"))
             unsubscribe_url = """%s/yourbaskets/unsubscribe?bskid=%i&amp;ln=%s""" % (CFG_SITE_URL, bskid, ln)
             unsubscribe_logo = """<img src="%s/img/wb-unsubscribe.png" />""" % (CFG_SITE_URL,)
             unsubscribe = """<a href="%s">%s%s</a>""" % (unsubscribe_url, unsubscribe_logo, _("Unsubscribe from basket"))
 
         out = """
   <thead>
     <tr>
       <td class="bskbasketheader"%(optional_colspan)s>
         <table width="100%%">
           <tr>
             <td class="bskbasketheadertitle">
               <strong>
               %(name)s
               </strong>
               <small>
               %(records_field)s%(comments_field)s
               %(last_update_field)s
               </small>
             </td>
             <td class="bskbasketheaderoptions">
               %(subscribe_unsubscribe_basket)s
             </td>
         </table>
       </td>
     </tr>
   </thead>"""
 
         out %= {'optional_colspan': optional_colspan,
                 'name': name,
                 'nb_items': nb_items,
                 'records_field': records_field,
                 'comments_field': comments_field,
                 'last_update_field': last_update_field,
                 'subscribe_unsubscribe_basket': subscription_status > 0 and unsubscribe or subscription_status < 0 and subscribe or not subscription_status and '&nbsp;'}
 
         return out
 
     def tmpl_public_basket_footer(self,
                                   bskid,
                                   nb_items,
                                   id_owner,
                                   subscription_status,
                                   ln=CFG_SITE_LANG):
         """Template for public basket footer display."""
 
         _ = gettext_set_language(ln)
 
         optional_colspan = nb_items and ' colspan="3"' or ''
 
         if subscription_status:
             subscribe_url = """%s/yourbaskets/subscribe?bskid=%i&amp;ln=%s""" % (CFG_SITE_URL, bskid, ln)
             subscribe_logo = """<img src="%s/img/wb-subscribe.png" />""" % (CFG_SITE_URL,)
             subscribe = """<a href="%s">%s%s</a>""" % (subscribe_url, subscribe_logo, _("Subscribe to basket"))
             unsubscribe_url = """%s/yourbaskets/unsubscribe?bskid=%i&amp;ln=%s""" % (CFG_SITE_URL, bskid, ln)
             unsubscribe_logo = """<img src="%s/img/wb-unsubscribe.png" />""" % (CFG_SITE_URL,)
             unsubscribe = """<a href="%s">%s%s</a>""" % (unsubscribe_url, unsubscribe_logo, _("Unsubscribe from basket"))
             (uid, nickname, display_name) = get_user_info(id_owner)
             display_owner_url = """%s/yourmessages/write?msg_to=%s""" % (CFG_SITE_URL, nickname or str(uid))
             display_owner_text = _("This public basket belongs to the user ")
             display_owner = """%s<a href="%s">%s</a>.""" % (display_owner_text, display_owner_url, nickname or display_name)
 
         out = """
   <tfoot>
     <tr>
       <td class="bskbasketfooter"%(optional_colspan)s>
         <table width="100%%">
           <tr>
             <td class="bskbasketfootertitle">
               <small>
               %(display_owner)s
               </small>
             </td>
             <td class="bskbasketfooteroptions">
               %(subscribe_unsubscribe_basket)s
             </td>
           </tr>
         </table>
       </td>
     </tr>
   </tfoot>"""
 
         out %= {'optional_colspan': optional_colspan,
                 'display_owner': subscription_status and display_owner or _('This public basket belongs to you.'),
                 'subscribe_unsubscribe_basket': subscription_status > 0 and unsubscribe or subscription_status < 0 and subscribe or not subscription_status and '&nbsp;'}
 
         return out
 
     def tmpl_public_basket_content(self,
                                    bskid,
                                    (user_can_view_comments,),
                                    items=[],
                                    of='hb',
                                    ln=CFG_SITE_LANG):
         """Template for public basket footer display."""
 
         if of == 'hb':
             _ = gettext_set_language(ln)
             items_html = """
   <tbody>"""
             if not(items):
                 items_html += """
     <tr>
       <td style="text-align:center; height:100px">
       %s
       </td>
     </tr>""" % _("Basket is empty")
             else:
                 count = 0
                 for item in items:
                     count += 1
                     items_html += self.__tmpl_public_basket_item(count=count,
                                                                  bskid=bskid,
                                                                  item=item,
                                                                  view_notes=user_can_view_comments,
                                                                  ln=ln)
 
             items_html += """
   </tbody>"""
             return items_html
         elif of.startswith('x'):
             items_xml = ""
             for item in items:
                 items_xml += item[4] + "\n"
             return items_xml
         else:
             return ""
 
     def __tmpl_public_basket_item(self,
                                   count,
                                   bskid,
                                   item,
                                   view_notes=0,
                                   ln=CFG_SITE_LANG):
         """Template for basket item display within the basket content."""
 
         _ = gettext_set_language(ln)
 
         (recid, colid, nb_cmt, last_cmt, val, dummy) = item
 
         copy_url = "%(siteurl)s/yourbaskets/modify?action=copy&amp;bskid=%(bskid)i&amp;recid=%(recid)i&amp;ln=%(ln)s" % \
                    {'siteurl': CFG_SITE_URL,
                     'bskid': bskid,
                     'recid': recid,
                     'ln': ln}
         copy_img = "%s/img/wb-copy-item.png" % (CFG_SITE_URL,)
         copy = """<a href="%s"><img src="%s" alt="%s" />%s</a>""" % \
                (copy_url, copy_img, _("Copy item"), _("Copy item"))
 
         if recid < 0:
             external_item_img = '<img src="%s/img/wb-external-item.png" alt="%s" style="vertical-align: top;" />&nbsp;' % \
                                  (CFG_SITE_URL, _("External item"))
         else:
             external_item_img = ''
 
         out = """
     <tr>
       <td style="border-bottom: 1px solid #fc0;">
         <table>
           <tr>
             <td class="bskcontentcount">
             %(count)i.
             </td>
             <td class="bskcontentcol" colspan="2">
             %(icon)s%(content)s
             </td>
           </tr>
           <tr>
             <td class="bskcontentoptions">
             &nbsp;
             </td>
             <td>
               <span class="moreinfo">"""
 
         if item[0] > 0:
             detailed_record = """<a class="moreinfo" href="%(siteurl)s/%(CFG_SITE_RECORD)s/%(recid)s">%(detailed_record_label)s</a>"""
             out += detailed_record + (view_notes and " - " or "")
             external_url = ""
         else:
             ## Uncomment the following lines if you want the Detailed record link to be
             ## displayed for external records but not for external sources (such as urls)
             #external_colid_and_url = db.get_external_colid_and_url(item[0])
             #if external_colid_and_url and external_colid_and_url[0][0] and external_colid_and_url[0][1]:
             #    detailed_record = '<a class="moreinfo" href="%(external_url)s">%(detailed_record_label)s</a>'
             #    out += detailed_record + (view_notes and " - " or "")
             #    external_url = external_colid_and_url[0][1]
             #else:
             #    external_url = ""
             ## Currently no external items (records or sources) have a Detailed record link
             external_url = ""
 
         if view_notes:
             notes = """\n<a class="moreinfo" href="%(siteurl)s/yourbaskets/%(add_and_view_notes_action)s?"""\
                     """bskid=%(bskid)s&amp;recid=%(recid)i&amp;ln=%(ln)s%(add_and_view_notes_inline_anchor)s">%(add_and_view_notes_label)s</a>"""
             out += notes
 
         out += """
               </span>
             </td>
             <td class="bskbasketheaderoptions">
             %(copy)s
             </td>
           </tr>
         </table>
       </td>
     </tr>"""
         out = out % {'count': count,
                      'icon': external_item_img,
                      'content': colid >= 0 and val or val and self.tmpl_create_pseudo_item(val) or _("This record does not seem to exist any more"),
                      'add_and_view_notes_action': nb_cmt and 'display_public' or 'write_public_note',
                      'add_and_view_notes_inline_anchor': not nb_cmt and '#note' or '',
                      'add_and_view_notes_label': nb_cmt and _('Notes') + ' (' + str(nb_cmt) + ')' or _('Add a note...'),
                      'last_cmt': last_cmt,
                      'siteurl': CFG_SITE_URL,
                      'CFG_SITE_RECORD': CFG_SITE_RECORD,
                      'bskid': bskid,
                      'recid': recid,
                      'external_url': external_url,
                      'detailed_record_label': _("Detailed record"),
                      'copy': copy,
                      'ln': ln}
         return out
 
     ####################################################
     ########## PUBLIC BASKET SINGLE ITEM VIEW ##########
     ####################################################
 
     def tmpl_public_basket_single_item(self,
                                        bskid,
                                        name,
                                        nb_items,
                                        (user_can_view_notes,
                                         user_can_add_notes),
                                        item=(),
                                        notes=(),
                                        previous_item_recid=0,
                                        next_item_recid=0,
                                        item_index=0,
                                        optional_params={},
                                        of='hb',
                                        ln=CFG_SITE_LANG):
         """Template for public basket's single item display."""
 
         _ = gettext_set_language(ln)
 
         if of == 'hb':
             out = """
 <table class="bskbasket" width="100%">"""
         else:
             out = ""
 
         if of == 'hb':
             out += self.tmpl_public_basket_single_item_header(bskid,
                                                               name,
                                                               nb_items,
                                                               previous_item_recid,
                                                               next_item_recid,
                                                               item_index,
                                                               ln=CFG_SITE_LANG)
 
         if of == 'hb':
             out += self.tmpl_public_basket_single_item_footer(bskid,
                                                               previous_item_recid,
                                                               next_item_recid,
                                                               ln=CFG_SITE_LANG)
 
         out += self.tmpl_public_basket_single_item_content(bskid,
                                                            (user_can_view_notes,
                                                             user_can_add_notes),
                                                            item,
                                                            notes,
                                                            item_index,
                                                            optional_params,
                                                            of,
                                                            ln=CFG_SITE_LANG)
 
         if of == 'hb':
             out += """
 </table>"""
 
         if of == 'hb':
             out += self.tmpl_create_export_as_list(bskid=bskid,
                                                    item=item,
                                                    public=True)
 
         return out
 
     def tmpl_public_basket_single_item_header(self,
                                               bskid,
                                               name,
                                               nb_items,
                                               previous_item_recid,
                                               next_item_recid,
                                               item_index,
                                               ln=CFG_SITE_LANG):
         """Template for public basket's single item header display."""
 
         _ = gettext_set_language(ln)
 
         records_field = '<br />' + _('Item %(x_item_index)i of %(x_item_total)i') % \
                         {'x_item_index': item_index, 'x_item_total': nb_items}
 
         if previous_item_recid:
             previous_item_url = """%s/yourbaskets/display_public?bskid=%i&amp;recid=%s&amp;ln=%s""" % \
                                 (CFG_SITE_URL,
                                  bskid,
                                  previous_item_recid,
                                  ln)
             previous_item_logo = """<img src="%s/img/wb-previous-item.png" />""" % (CFG_SITE_URL,)
             previous_item = """<a href="%s">%s%s</a>""" % (previous_item_url, previous_item_logo, _("Previous item"))
         else:
             previous_item_logo = """<img src="%s/img/wb-previous-item-disabled.png" />""" % (CFG_SITE_URL,)
             previous_item = """%s%s""" % (previous_item_logo, _("Previous item"))
 
         if next_item_recid:
             next_item_url = """%s/yourbaskets/display_public?bskid=%i&amp;recid=%s&amp;ln=%s""" % \
                             (CFG_SITE_URL,
                              bskid,
                              next_item_recid,
                              ln)
             next_item_logo = """<img src="%s/img/wb-next-item.png" />""" % (CFG_SITE_URL,)
             next_item = """<a href="%s">%s%s</a>""" % (next_item_url, next_item_logo, _("Next item"))
         else:
             next_item_logo = """<img src="%s/img/wb-next-item-disabled.png" />""" % (CFG_SITE_URL,)
             next_item = """%s%s""" % (next_item_logo, _("Next item"))
 
         go_back_url = """%s/yourbaskets/display_public?bskid=%i&amp;ln=%s""" % \
                       (CFG_SITE_URL,
                        bskid,
                        ln)
         go_back_logo = """<img src="%s/img/wb-go-back.png" />""" % (CFG_SITE_URL,)
         go_back = """<a href="%s">%s%s</a>""" % (go_back_url, go_back_logo, _("Return to basket"))
 
         out = """
   <thead>
     <tr>
       <td class="bskbasketheader">
         <table>
           <tr>
             <td class="bskbasketheadertitle">
               <strong>
               %(name)s
               </strong>
               <small>
               %(records_field)s
               </small>
             </td>
             <td class="bskbasketheaderoptions">
               %(go_back)s
               &nbsp;&nbsp;
               %(previous_item)s
               &nbsp;&nbsp;
               %(next_item)s
             </td>
         </table>
       </td>
     </tr>
   </thead>"""
 
         out %= {'name': name,
                 'records_field': records_field,
                 'go_back': go_back,
                 'previous_item': previous_item,
                 'next_item': next_item,
         }
 
         return out
 
     def tmpl_public_basket_single_item_footer(self,
                                               bskid,
                                               previous_item_recid,
                                               next_item_recid,
                                               ln=CFG_SITE_LANG):
         """Template for public basket's single item footer display."""
 
         _ = gettext_set_language(ln)
 
         if previous_item_recid:
             previous_item_url = """%s/yourbaskets/display_public?bskid=%i&amp;recid=%s&amp;ln=%s""" % \
                                 (CFG_SITE_URL,
                                  bskid,
                                  previous_item_recid,
                                  ln)
             previous_item_logo = """<img src="%s/img/wb-previous-item.png" />""" % (CFG_SITE_URL,)
             previous_item = """<a href="%s">%s%s</a>""" % (previous_item_url, previous_item_logo, _("Previous item"))
         else:
             previous_item_logo = """<img src="%s/img/wb-previous-item-disabled.png" />""" % (CFG_SITE_URL,)
             previous_item = """%s%s""" % (previous_item_logo, _("Previous item"))
 
         if next_item_recid:
             next_item_url = """%s/yourbaskets/display_public?bskid=%i&amp;recid=%s&amp;ln=%s""" % \
                             (CFG_SITE_URL,
                              bskid,
                              next_item_recid,
                              ln)
             next_item_logo = """<img src="%s/img/wb-next-item.png" />""" % (CFG_SITE_URL,)
             next_item = """<a href="%s">%s%s</a>""" % (next_item_url, next_item_logo, _("Next item"))
         else:
             next_item_logo = """<img src="%s/img/wb-next-item-disabled.png" />""" % (CFG_SITE_URL,)
             next_item = """%s%s""" % (next_item_logo, _("Next item"))
 
         go_back_url = """%s/yourbaskets/display_public?bskid=%i&amp;ln=%s""" % \
                       (CFG_SITE_URL,
                        bskid,
                        ln)
         go_back_logo = """<img src="%s/img/wb-go-back.png" />""" % (CFG_SITE_URL,)
         go_back = """<a href="%s">%s%s</a>""" % (go_back_url, go_back_logo, _("Return to basket"))
 
         out = """
   <tfoot>
     <tr>
       <td class="bskbasketfooter">
         <table width="100%%">
           <tr>
             <td class="bskbasketfootertitle">
               &nbsp;
             </td>
             <td class="bskbasketfooteroptions">
               %(go_back)s
               &nbsp;&nbsp;
               %(previous_item)s
               &nbsp;&nbsp;
               %(next_item)s
             </td>
         </table>
       </td>
     </tr>
   </tfoot>"""
 
         out %= {'go_back': go_back,
                 'previous_item': previous_item,
                 'next_item': next_item,
         }
 
         return out
 
     def tmpl_public_basket_single_item_content(self,
                                                bskid,
                                                (user_can_view_notes,
                                                 user_can_add_notes),
                                                item=(),
                                                notes=(),
                                                index_item=0,
                                                optional_params={},
                                                of='hb',
                                                ln=CFG_SITE_LANG):
         """Template for public basket's single item content display."""
 
         if of == 'hb':
             _ = gettext_set_language(ln)
 
             item_html = """
   <tbody>"""
 
             if not item:
                 item_html += """
     <tr>
       <td style="text-align: center; height: 100px">
         %s
       </td>
     </tr>""" % _("The item you have selected does not exist.")
 
             else:
                 (recid, colid, dummy, dummy, val, dummy) = item
 
                 if recid < 0:
                     external_item_img = '<img src="%s/img/wb-external-item.png" alt="%s" style="vertical-align: top;" />&nbsp;' % \
                                         (CFG_SITE_URL, _("External item"))
                 else:
                     external_item_img = ''
 
                 if user_can_view_notes:
                     notes_html = self.__tmpl_display_public_notes(recid,
                                                                   bskid,
                                                                   (user_can_add_notes,),
                                                                   notes,
                                                                   optional_params,
                                                                   ln)
                     notes = """
           <tr>
             <td colspan="2" class="bskcontentnotes">%(notes_html)s
             </td>
           </tr>""" % {'notes_html': notes_html}
                 else:
                     notes_msg = _("You do not have sufficient rights to view this item's notes.")
                     notes = """
           <tr>
             <td colspan="2" style="text-align: center; height: 50px">
               %(notes_msg)s
             </td>
           </tr>""" % {'notes_msg': notes_msg}
 
                 item_html += """
     <tr>
       <td style="border-bottom: 1px solid #fc0;">
         <table>
           <tr>
             <td class="bskcontentcount">
             %(count)i.
             </td>
             <td class="bskcontentcol">
             %(icon)s%(content)s
             </td>
           </tr>%(notes)s
         </table>
       </td>
     </tr>""" % {'count': index_item,
                 'icon': external_item_img,
                 'content': colid >= 0 and val or val and self.tmpl_create_pseudo_item(val) or _("This record does not seem to exist any more"),
                 'notes': notes,
                 'ln': ln}
 
             item_html += """
   </tbody>"""
 
             return item_html
 
         elif of == 'xm':
             item_xml = item[4]
             return item_xml
 
     def __tmpl_display_public_notes(self,
                                     recid,
                                     bskid,
                                     (user_can_add_notes,),
                                     notes,
                                     optional_params,
                                     ln=CFG_SITE_LANG):
         """Template for public basket's single item notes display."""
 
         _ = gettext_set_language(ln)
 
         warnings_html = ""
 
         add_note_p = False
         if user_can_add_notes and (optional_params.has_key("Add note") or optional_params.has_key("Incomplete note")):
             add_note_p = True
             if optional_params.has_key("Add note") and optional_params['Add note']:
                 replied_to_note = optional_params['Add note']
                 note_body_html = self.tmpl_quote_comment_html(replied_to_note[2],
                                                               replied_to_note[1],
                                                               replied_to_note[0],
                                                               replied_to_note[4],
                                                               replied_to_note[3],
                                                               ln)
                 note_body_textual = self.tmpl_quote_comment_textual(replied_to_note[2],
                                                                     replied_to_note[1],
                                                                     replied_to_note[0],
                                                                     replied_to_note[4],
                                                                     replied_to_note[3],
                                                                     ln)
                 note_title = "Re: " + replied_to_note[2]
             elif optional_params.has_key("Incomplete note") and optional_params['Incomplete note']:
                 incomplete_note = optional_params['Incomplete note']
                 note_body_html = incomplete_note[1]
                 # TODO: Do we need to format incomplete body correctly as textual
                 # and html as above?
                 note_body_textual = incomplete_note[1]
                 note_title = incomplete_note[0]
                 if optional_params.has_key("Warnings"):
                     warnings = optional_params["Warnings"]
                     warnings_html = self.tmpl_warnings(warnings, ln)
             else:
                 note_body_html = ""
                 note_body_textual = ""
                 note_title = ""
                 if optional_params.has_key("Warnings"):
                     warnings = optional_params["Warnings"]
                     warnings_html = self.tmpl_warnings(warnings, ln)
             # TODO: calculate the url
             file_upload_url = ""
             action = """%s/yourbaskets/save_public_note?bskid=%i&amp;recid=%i&amp;ln=%s%s""" % \
                      (CFG_SITE_URL, bskid, recid, ln, '#note')
             cancel = """%s/yourbaskets/display_public?bskid=%i&amp;recid=%i&amp;ln=%s""" % \
                      (CFG_SITE_URL, bskid, recid, ln)
             editor = get_html_text_editor(name="note_body",
                                           content=note_body_html,
                                           textual_content=note_body_textual,
                                           width="100%",
                                           height="200px",
                                           enabled=CFG_WEBBASKET_USE_RICH_TEXT_EDITOR,
                                           file_upload_url=file_upload_url,
                                           toolbar_set="WebComment")
             add_note_html = """
                     <table cellspacing="0" cellpadding="0" class="bsknotescontentaddnote">
                       <tr>
                         <td class="bsknotescontentaddform">
                           <form name="write_note" method="post" action="%(action)s">
                             <a name="note"></a><strong>%(add_a_note_label)s</strong>
                             %(warnings_html)s
                             <p align="left">
                             <small>Subject:</small>
                             <br />
                             <input type="text" name="note_title" size="65" value="%(note_title)s" />
                             </p>
                             <p align="left">
                             <small>Note:</small>
                             <br />
                             %(editor)s
                             </p>
                             <input type="hidden" name="reply_to" value="%(reply_to)s" />
                             <p align="right">
                             <input type="submit" class="formbutton" value="%(submit_label)s" />
                             <input type="button" class="nonsubmitbutton" value="%(cancel_label)s" onClick="window.location='%(cancel)s'" />
                             </p>
                           </form>
                         </td>
                       </tr>
                     </table>""" % {'action': action,
                                    'warnings_html': warnings_html,
                                    'cancel': cancel,
                                    'cancel_label': _('Cancel'),
                                    'note_title': note_title,
                                    'editor': editor,
                                    'add_a_note_label': _('Add a note'),
                                    'submit_label': _('Add note'),
                                    'reply_to': optional_params.get("Reply to")}
 
         notes_icon = '<img src="%s/img/wb-notes.png" style="vertical-align: top;" />&nbsp;' % (CFG_SITE_URL,)
 
         if user_can_add_notes and not add_note_p:
             add_note_url = """%s/yourbaskets/write_public_note?bskid=%i&amp;recid=%i&amp;ln=%s%s""" % \
                            (CFG_SITE_URL, bskid, recid, ln, '#note')
             add_note_logo = """<img src="%s/img/wb-add-note.png" />""" % (CFG_SITE_URL,)
             add_note = """<a href="%s">%s%s</a>""" % (add_note_url, add_note_logo, _("Add a note"))
         else:
             add_note = ""
 
         notes_html = """
               <table>
                 <tr>
                   <td class="bsknotesheadertitle">
                   <br />
                   <strong>%(notes_icon)s%(notes_label)s</strong>
                   <br />
                   <small>%(nb_notes)i notes in total</small>
                   </td>
                   <td class="bsknotesheaderoptions">
                   %(add_note)s
                   </td>
                 </tr>""" % {'notes_label': _('Notes'),
                             'notes_icon': notes_icon,
                             'add_note': (notes and user_can_add_notes and not add_note_p) and add_note or "&nbsp;",
                             'nb_notes': len(notes)}
 
         if notes or add_note or add_note_p:
             notes_html += """
                 <tr>
                   <td colspan="2" class="bsknotescontent">"""
             thread_history = [0]
             for (cmt_uid, cmt_nickname, cmt_title, cmt_body, cmt_date, dummy, cmtid, reply_to) in notes:
                 if reply_to not in thread_history:
                     # Going one level down in the thread
                     thread_history.append(reply_to)
                     depth = thread_history.index(reply_to)
                 else:
                     depth = thread_history.index(reply_to)
                     thread_history = thread_history[:depth + 1]
                 notes_html += '<div style="margin-left:%spx">' % (depth*20)
                 if user_can_add_notes:
                     reply_to_note = """<a href="%s/yourbaskets/write_public_note?bskid=%i&amp;recid=%i&amp;cmtid=%i&amp;ln=%s%s">%s</a>""" % \
                                     (CFG_SITE_URL, bskid, recid, cmtid, ln, '#note', _('Reply'))
                 else:
                     reply_to_note = ""
                 notes_html += """
                     <table cellspacing="0" cellpadding="0" class="bsknotescontentnote">
                       <tr>
                         <td class="bsknotescontenttitle">
                         %(inline_anchor)s<img src="%(CFG_SITE_URL)s/img/user-icon-1-24x24.gif" />%(authorship)s
                         </td>
                       </tr>
                       <tr>
                         <td class="bsknotescontentbody">
                         <blockquote>
                         %(body)s
                         </blockquote>
                         </td>
                       </tr>
                       <tr>
                         <td class="bsknotescontentoptions">
                         %(reply_to_note)s
                         </td>
                       </tr>
                     </table>
                     <br />""" % {'inline_anchor': (not add_note_p and notes[-1][-1]==cmtid) and '<a name="note"></a>' or '',
                                  'CFG_SITE_URL': CFG_SITE_URL,
                                  'authorship': _("%(x_title)s, by %(x_name)s on %(x_date)s") % \
                                                {'x_title': '<strong>' + (cmt_title and cgi.escape(cmt_title, True) \
                                                                          or _('Note')) + '</strong>',
                                                 'x_name': '<a href="%(CFG_SITE_URL)s/yourmessages/write?msg_to=%(user)s">%(user_display)s</a>' % \
                                                           {'CFG_SITE_URL': CFG_SITE_URL,
                                                            'user': cmt_nickname or cmt_uid,
                                                            'user_display': cmt_nickname or get_user_info(cmt_uid)[2]},
                                                 'x_date': '<em>' + convert_datetext_to_dategui(cmt_date) + '</em>'},
 
                                  'body': email_quoted_txt2html(escape_email_quoted_text(cmt_body)),
                                  'reply_to_note': reply_to_note}
                 notes_html += '</div>'
             if add_note_p:
                 notes_html += add_note_html
             notes_html += """
                   </td>
                 </tr>"""
 
         notes_html += """
                 <tr>
                   <td class="bsknotesfootertitle">
                   &nbsp;
                   </td>
                   <td class="bsknotesfooteroptions">
                   %(add_note)s
                   </td>
                 </tr>
               </table>""" % {'add_note': (user_can_add_notes and not add_note_p) and add_note or '&nbsp;'}
 
         return notes_html
 
     def tmpl_create_pseudo_item(self, item, of='hb'):
         """"""
 
         if not item:
             # normally this function should never be run if "item"
             # is empty or does not exist anyway.
             return ""
 
         if of == 'hb':
             (es_title, es_desc, es_url) = tuple(item.split('\n'))
             es_title = cgi.escape(es_title, True)
             es_desc = cgi.escape(es_desc.replace('<br />', '\n'), True).replace('\n', '<br />')
+            es_url_label = cgi.escape(prettify_url(es_url))
+            es_url = cgi.escape(es_url, True)
             out = """<strong>%s</strong>
 <br />
 <small>%s
 <br />
 <strong>URL:</strong> <a class="note" target="_blank" href="%s">%s</a>
 </small>
-""" % (es_title, es_desc, es_url, cgi.escape(prettify_url(es_url)))
+""" % (es_title, es_desc, es_url, es_url_label)
 
         if of == 'xm':
             # TODO: xml output...
             out = ""
 
         return out
 
     def tmpl_export_xml(self, body):
         """Template for the xml represantation for the selected basket/items."""
 
         out = """
 <collection xmlns="http://www.loc.gov/MARC21/slim">
 %s
 </collection>""" % (body,)
 
         return out
 
     def tmpl_create_export_as_list(self,
                                    selected_category=CFG_WEBBASKET_CATEGORIES['PRIVATE'],
                                    selected_topic="",
                                    selected_group=0,
                                    bskid=0,
                                    item=(),
                                    public=False):
         """Tamplate that creates a bullet list of export as formats for a basket or an item."""
 
         list_of_export_as_formats = [('BibTeX','hx'), ('DC','xd'), ('EndNote','xe'), ('MARCXML', 'xm'), ('NLM','xn'), ('RefWorks','xw'), ('RSS','xr')]
 
-        recid = item and "&recid=" + str(item[0]) or ""
+        recid = item and "&amp;recid=" + str(item[0]) or ""
 
         if not public:
-            href = "%s/yourbaskets/display?category=%s&topic=%s&group=%i&bskid=%i%s" % \
+            href = "%s/yourbaskets/display?category=%s&amp;topic=%s&amp;group=%i&amp;bskid=%i%s" % \
                    (CFG_SITE_URL,
                     selected_category,
-                    selected_topic,
+                    urllib.quote(selected_topic),
                     selected_group,
                     bskid,
                     recid)
         else:
             href = "%s/yourbaskets/display_public?bskid=%i%s" % \
                    (CFG_SITE_URL,
                     bskid,
                     recid)
 
         export_as_html = ""
         for format in list_of_export_as_formats:
-            export_as_html += """<a style="text-decoration:underline;font-weight:normal" href="%s&of=%s">%s</a>, """ % \
+            export_as_html += """<a style="text-decoration:underline;font-weight:normal" href="%s&amp;of=%s">%s</a>, """ % \
                               (href, format[1], format[0])
         if export_as_html:
             export_as_html = export_as_html[:-2]
         out = """
 <div style="float:right; text-align:right;">
   <ul class="bsk_export_as_list">
     <li>Export as
       %s
     </li>
   </ul>
 </div>""" % (export_as_html,)
 
         return out
 
 #############################################
 ########## SUPPLEMENTARY FUNCTIONS ##########
 #############################################
 
 def prettify_name(name, char_limit=10, nb_dots=3):
     """If name has more characters than char_limit return a shortened version of it
     keeping the beginning (up to char_limit) and replacing the rest with dots."""
 
     name = unicode(name, 'utf-8')
     if len(name) > char_limit:
         while name[char_limit-1] == ' ':
             char_limit -= 1
         prettified_name = name[:char_limit] + '.'*nb_dots
         return prettified_name.encode('utf-8')
     else:
         return name.encode('utf-8')
 
 def prettify_url(url, char_limit=50, nb_dots=3):
     """If the url has more characters than char_limit return a shortened version of it
     keeping the beginning and ending and replacing the rest with dots."""
 
     if len(url) > char_limit:
         # let's set a minimum character limit
         if char_limit < 5:
             char_limit = 5
         # let's set a maximum number of dots in relation to the character limit
         if nb_dots > char_limit/4:
             nb_dots = char_limit/5
         nb_char_url = char_limit - nb_dots
         nb_char_end = nb_char_url/4
         nb_char_beg = nb_char_url - nb_char_end
         return url[:nb_char_beg] + '.'*nb_dots + url[-nb_char_end:]
     else:
         return url
 
 def create_search_box_select_options(category,
                                      topic,
                                      grpid,
                                      topic_list,
                                      group_list,
                                      number_of_public_baskets,
                                      ln):
     """Returns an html list of options for the select form field of the search box."""
 
     _ = gettext_set_language(ln)
 
     out = ""
 
     if category:
         if topic:
             b = CFG_WEBBASKET_CATEGORIES['PRIVATE'] + '_' + cgi.escape(topic, True)
         elif grpid:
             b = CFG_WEBBASKET_CATEGORIES['GROUP'] + '_' + str(grpid)
         else:
             b = category
     else:
         b = ""
 
     if topic_list or group_list:
         out += """<option value=""%(selected)s>%(label)s</option>""" % \
                {'selected': not b and ' selected="selected"' or '',
                 'label': _("All your baskets")}
     if topic_list:
         out += """<optgroup label="%(label)s">""" % \
                {'label': _("Your personal baskets")}
         if len(topic_list) > 1:
             out += """<option value="%(value)s"%(selected)s>%(label)s</option>""" % \
                    {'value': CFG_WEBBASKET_CATEGORIES['PRIVATE'],
                     'selected': b == CFG_WEBBASKET_CATEGORIES['PRIVATE'] and ' selected="selected"' or '',
                     'label': _("All your topics")}
         for topic_name in topic_list:
             topic_label = cgi.escape(topic_name[0], True)
             topic_value = "P_%s" % (topic_label,)
             out += """<option value="%(value)s"%(selected)s>%(label)s</option>""" % \
                    {'value': topic_value,
                     'selected': b == topic_value and ' selected="selected"' or '',
                     'label': topic_label}
         out += "</optgroup>"
     if group_list:
         out += """<optgroup label="%(label)s">""" % \
                {'label': _("Your group baskets")}
         if len(group_list) > 1:
             out += """<option value="%(value)s"%(selected)s>%(label)s</option>""" % \
                    {'value': CFG_WEBBASKET_CATEGORIES['GROUP'],
                     'selected': b == CFG_WEBBASKET_CATEGORIES['GROUP'] and ' selected="selected"' or '',
                     'label': _("All your groups")}
         for group_id_and_name in group_list:
             group_label = cgi.escape(group_id_and_name[1], True)
             group_value = "G_%i" % (group_id_and_name[0],)
             out += """<option value="%(value)s"%(selected)s>%(label)s</option>""" % \
                    {'value': group_value,
                     'selected': b == group_value and ' selected="selected"' or '',
                     'label': group_label}
         out += "</optgroup>"
     if number_of_public_baskets:
         out += """<optgroup label="%(label)s">""" % \
                {'label': _("Your public baskets")}
         out += """<option value="%(value)s"%(selected)s>%(label)s</option>""" % \
                {'value': CFG_WEBBASKET_CATEGORIES['EXTERNAL'],
                 'selected': b == CFG_WEBBASKET_CATEGORIES['EXTERNAL'] and ' selected="selected"' or '',
                 'label': _("All your public baskets")}
         out += "</optgroup>"
     out += """<option value="%(value)s"%(selected)s>%(label)s</option>""" % \
            {'value': CFG_WEBBASKET_CATEGORIES['ALLPUBLIC'],
             'selected': b == CFG_WEBBASKET_CATEGORIES['ALLPUBLIC'] and ' selected="selected"' or '',
             'label': _("All the public baskets")}
 
     return out
 
 def create_add_box_select_options(category,
                                   bskid,
                                   personal_basket_list,
                                   group_basket_list,
                                   ln):
     """Returns an html list of options for the select form field of the add box."""
 
     _ = gettext_set_language(ln)
 
     out = ""
-    options = []
 
+    # Calculate the selected basket if there is one pre-selected.
     if category and bskid:
         if category == CFG_WEBBASKET_CATEGORIES['PRIVATE']:
             b = CFG_WEBBASKET_CATEGORIES['PRIVATE'] + '_' + str(bskid)
         elif category == CFG_WEBBASKET_CATEGORIES['GROUP']:
             b = CFG_WEBBASKET_CATEGORIES['GROUP'] + '_' + str(bskid)
         elif category == CFG_WEBBASKET_CATEGORIES['EXTERNAL']:
             b = CFG_WEBBASKET_CATEGORIES['EXTERNAL'] + '_' + str(bskid)
         else:
             b = ""
     else:
         b = ""
 
-    #option list format: [ name, value, 1st level: True/False, 2nd level: True/False]
-    #   name: the name of the option, it will be used as its label in the list.
-    #   value: the value of the option that will be sent as a POST variable through
-    #          the select form field
-    #   1st level: bold, no margin, used for categories
-    #   2nd level: bold, small margin, used for topics and groups
-    #   * when both levels are False: normal font, big margin,
-    #     used for actual options *
-
-    # Let's set the default "Choose a basket..." option first.
-    #options= [(_("Choose a basket..."), str(-1), False, False)]
+    # Create the default disabled label option.
     out += """
-            <option style="%(style)s" value="%(value)i">%(label)s</option>""" % \
-                          {'style': "font-weight: normal;",
-                           'value': -1,
-                           'label': _("*** basket name ***")}
-
-    # Then, we parse the personal and group basket lists and dynamically create
-    # the list of options
+            <option disabled="disabled" value="%(value)i"%(selected)s>%(label)s</option>""" % \
+                             {'value': -1,
+                              'selected': not b and ' selected="selected"' or '',
+                              'label': _('Please select a basket...')}
+
+    # Check if there is only one basket to select from. If that is the case,
+    # set the selected basket to its value so that it will automatically be
+    # pre-selected. We want to make it easier for the user if they only have
+    # one basket.
+    if not (personal_basket_list and group_basket_list):
+        if len(personal_basket_list) == 1:
+            bskids = personal_basket_list[0][1].split(',')
+            if len(bskids) == 1:
+               b = CFG_WEBBASKET_CATEGORIES['PRIVATE'] + '_' + bskids[0]
+        elif len(group_basket_list) == 1:
+            bskids = group_basket_list[0][1].split(',')
+            if len(bskids) == 1:
+               b = CFG_WEBBASKET_CATEGORIES['GROUP'] + '_' + bskids[0]
+
+    # Create the <optgroup>s and <option>s for the user personal baskets.
     if personal_basket_list:
-        options.append((_("Your personal baskets"), None, True, False))
-        for personal_topic in personal_basket_list:
-            personal_topic_name = cgi.escape(personal_topic[0], True)
-            personal_baskets = eval(personal_topic[1] + ",")
-            options.append((personal_topic_name, None, False, True))
-            for personal_basket in personal_baskets:
-                personal_basket_name = cgi.escape(personal_basket[1], True)
-                personal_basket_value = CFG_WEBBASKET_CATEGORIES['PRIVATE'] + "_" + str(personal_basket[0])
-                options.append((personal_basket_name, personal_basket_value, False, False))
+        out += """
+            <optgroup label="%s">""" % ('* ' + _('Your personal baskets') + ' *',)
+        for personal_basket_list_topic_and_bskids in personal_basket_list:
+            topic = personal_basket_list_topic_and_bskids[0]
+            bskids = personal_basket_list_topic_and_bskids[1].split(',')
+            out += """
+              <optgroup label="%s">""" % (cgi.escape(topic, True),)
+            bskids_and_names = get_basket_ids_and_names(bskids)
+            for bskid_and_name in bskids_and_names:
+                basket_value = CFG_WEBBASKET_CATEGORIES['PRIVATE'] + '_' + str(bskid_and_name[0])
+                basket_name = bskid_and_name[1]
+                out += """
+                <option value="%(value)s"%(selected)s>%(label)s</option>""" % \
+                              {'value': basket_value,
+                               'selected': basket_value == b and ' selected="selected"' or '',
+                               'label': cgi.escape(basket_name, True)}
+            out += """
+              </optgroup>"""
+        out += """
+            </optgroup>"""
 
+    # Create the <optgroup>s and <option>s for the user group baskets.
     if group_basket_list:
-        options.append((_("Your group baskets"), None, True, False))
-        for group_group in group_basket_list:
-            group_group_name = cgi.escape(group_group[0], True)
-            group_baskets = eval(group_group[1] + ",")
-            options.append((group_group_name, None, False, True))
-            for group_basket in group_baskets:
-                group_basket_name = cgi.escape(group_basket[1], True)
-                group_basket_value = CFG_WEBBASKET_CATEGORIES['GROUP'] + "_" + str(group_basket[0])
-                options.append((group_basket_name, group_basket_value, False, False))
-
-    if len(options) == 3:
-        # In case we only have 1 option, pretend b has the value of that option
-        # so that it is selected by default.
-        b = options[2][1]
-
-    for option in options:
         out += """
-            <option style="%(style)s"%(value)s%(selected)s%(disabled)s>%(label)s</option>""" % \
-                          {'value': not ( option[2] or option[3] ) and ' value="' + option[1] + '"' or '',
-                           'label': option[0],
-                           'selected': option[1] == b and ' selected="selected"' or '',
-                           'disabled': ( option[2] or option[3] ) and ' disabled="disabled"' or '',
-                           'style': option[2] and "font-weight: bold;" or \
-                           option[3] and "font-weight: bold; margin-left: 5px;" or \
-                           "font-weight: normal; margin-left: 10px;"}
+            <optgroup label="%s">""" % ('* ' + _('Your group baskets') + ' *',)
+        for group_basket_list_topic_and_bskids in group_basket_list:
+            group = group_basket_list_topic_and_bskids[0]
+            bskids = group_basket_list_topic_and_bskids[1].split(',')
+            out += """
+              <optgroup label="%s">""" % (cgi.escape(group, True),)
+            bskids_and_names = get_basket_ids_and_names(bskids)
+            for bskid_and_name in bskids_and_names:
+                basket_value = CFG_WEBBASKET_CATEGORIES['GROUP'] + '_' + str(bskid_and_name[0])
+                basket_name = bskid_and_name[1]
+                out += """
+                <option value="%(value)s"%(selected)s>%(label)s</option>""" % \
+                              {'value': basket_value,
+                               'selected': basket_value == b and ' selected="selected"' or '',
+                               'label': cgi.escape(basket_name, True)}
+            out += """
+              </optgroup>"""
+        out += """
+            </optgroup>"""
 
     return out
diff --git a/modules/webbasket/lib/webbasket_webinterface.py b/modules/webbasket/lib/webbasket_webinterface.py
index 151172993..17bfdd1f9 100644
--- a/modules/webbasket/lib/webbasket_webinterface.py
+++ b/modules/webbasket/lib/webbasket_webinterface.py
@@ -1,1614 +1,1619 @@
 ## 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.
 
 """WebBasket Web Interface."""
 
 __revision__ = "$Id$"
 
 __lastupdated__ = """$Date$"""
 from invenio import webinterface_handler_config as apache
 
 import os
 import cgi
+import urllib
 from invenio.config import CFG_SITE_SECURE_URL, \
                            CFG_ACCESS_CONTROL_LEVEL_SITE, \
                            CFG_WEBSESSION_DIFFERENTIATE_BETWEEN_GUESTS, \
                            CFG_SITE_SECURE_URL, CFG_PREFIX, CFG_SITE_LANG
 from invenio.messages import gettext_set_language
 from invenio.webpage import page
 from invenio.webuser import getUid, page_not_authorized, isGuestUser
 from invenio.webbasket import \
      check_user_can_comment, \
      check_sufficient_rights, \
      perform_request_display, \
      perform_request_search, \
      create_guest_warning_box, \
      create_basket_navtrail, \
      perform_request_write_note, \
      perform_request_save_note, \
      perform_request_delete_note, \
      perform_request_add_group, \
      perform_request_edit, \
      perform_request_edit_topic, \
      perform_request_list_public_baskets, \
      perform_request_unsubscribe, \
      perform_request_subscribe, \
      perform_request_display_public, \
      perform_request_write_public_note, \
      perform_request_save_public_note, \
      delete_record, \
      move_record, \
      perform_request_add, \
      perform_request_create_basket, \
      perform_request_delete, \
      wash_topic, \
      wash_group, \
      perform_request_export_xml, \
      page_start, \
      page_end
 from invenio.webbasket_config import CFG_WEBBASKET_CATEGORIES, \
                                      CFG_WEBBASKET_ACTIONS, \
                                      CFG_WEBBASKET_SHARE_LEVELS
 from invenio.webbasket_dblayer import get_basket_name, \
      get_max_user_rights_on_basket
-from invenio.urlutils import get_referer, redirect_to_url, make_canonical_urlargd, quote
+from invenio.urlutils import get_referer, redirect_to_url, make_canonical_urlargd
 from invenio.webinterface_handler import wash_urlargd, WebInterfaceDirectory
 from invenio.webstat import register_customevent
 from invenio.errorlib import register_exception
 from invenio.webuser import collect_user_info
 from invenio.webcomment import check_user_can_attach_file_to_comments
 from invenio.access_control_engine import acc_authorize_action
 from htmlutils import is_html_text_editor_installed
 from ckeditor_invenio_connector import process_CKEditor_upload, send_response
 from invenio.bibdocfile import stream_file
 
 class WebInterfaceBasketCommentsFiles(WebInterfaceDirectory):
     """Handle upload and access to files for comments in WebBasket.
 
        The upload is currently only available through the CKEditor.
     """
 
     def _lookup(self, component, path):
         """ This handler is invoked for the dynamic URLs (for getting
         and putting attachments) Eg:
         /yourbaskets/attachments/get/31/652/5/file/myfile.pdf
         /yourbaskets/attachments/get/31/552/5/image/myfigure.png
                                  bskid/recid/uid/
 
         /yourbaskets/attachments/put/31/550/
                                    bskid/recid
         """
         if component == 'get' and len(path) > 4:
             bskid = path[0] # Basket id
             recid = path[1] # Record id
             uid = path[2]   # uid of the submitter
             file_type = path[3]  # file, image, flash or media (as
                                  # defined by CKEditor)
 
             if file_type in ['file', 'image', 'flash', 'media']:
                 file_name = '/'.join(path[4:]) # the filename
 
                 def answer_get(req, form):
                     """Accessing files attached to comments."""
                     form['file'] = file_name
                     form['type'] = file_type
                     form['uid'] = uid
                     form['recid'] = recid
                     form['bskid'] = bskid
                     return self._get(req, form)
 
                 return answer_get, []
 
         elif component == 'put' and len(path) > 1:
             bskid = path[0] # Basket id
             recid = path[1] # Record id
 
             def answer_put(req, form):
                 """Attaching file to a comment."""
                 form['recid'] = recid
                 form['bskid'] = bskid
                 return self._put(req, form)
 
             return answer_put, []
 
         # All other cases: file not found
         return None, []
 
     def _get(self, req, form):
         """
         Returns a file attached to a comment.
 
         A file is attached to a comment of a record of a basket, by a
         user (who is the author of the comment), and is of a certain
         type (file, image, etc). Therefore these 5 values are part of
         the URL. Eg:
         CFG_SITE_SECURE_URL/yourbaskets/attachments/get/31/91/5/file/myfile.pdf
                                              bskid/recid/uid
         """
         argd = wash_urlargd(form, {'file': (str, None),
                                    'type': (str, None),
                                    'uid': (int, 0),
                                    'bskid': (int, 0),
                                    'recid': (int, 0)})
 
         _ = gettext_set_language(argd['ln'])
 
         # Can user view this basket & record & comment, i.e. can user
         # access its attachments?
         #uid = getUid(req)
         user_info = collect_user_info(req)
         rights = get_max_user_rights_on_basket(argd['uid'], argd['bskid'])
 
         if not user_info['precached_usebaskets']:
             return page_not_authorized(req, "../", \
                                        text = _("You are not authorized to use baskets."))
 
         if 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 not(check_sufficient_rights(rights, CFG_WEBBASKET_SHARE_LEVELS['READITM'])):
             return page_not_authorized(req, "../", \
                                        text = _("You are not authorized to view this attachment"))
 
         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/data/baskets/comments/' + \
                                    str(argd['bskid']) + '/'  + str(argd['recid']) + '/' + \
                                    str(argd['uid']) + '/' + argd['type'] + '/' + \
                                    argd['file'])
 
             # Check that we are really accessing attachements
             # directory, for the declared basket and record.
             if path.startswith(CFG_PREFIX + '/var/data/baskets/comments/' + \
                                str(argd['bskid']) + '/' + str(argd['recid'])) and \
                                os.path.exists(path):
                 return stream_file(req, path)
 
         # Send error 404 in all other cases
         return apache.HTTP_NOT_FOUND
 
     def _put(self, req, form):
         """
         Process requests received from CKEditor to upload files, etc.
 
         URL eg:
         CFG_SITE_SECURE_URL/yourbaskets/attachments/put/31/91/
                                              bskid/recid/
         """
         if not is_html_text_editor_installed():
             return
 
         argd = wash_urlargd(form, {'bskid': (int, 0),
                                    'recid': (int, 0)})
 
         uid = getUid(req)
 
         # URL where the file can be fetched after upload
         user_files_path = '%(CFG_SITE_SECURE_URL)s/yourbaskets/attachments/get/%(bskid)s/%(recid)i/%(uid)s' % \
                           {'uid': uid,
                            'recid': argd['recid'],
                            'bskid': argd['bskid'],
                            'CFG_SITE_SECURE_URL': CFG_SITE_SECURE_URL}
         # Path to directory where uploaded files are saved
         user_files_absolute_path = '%(CFG_PREFIX)s/var/data/baskets/comments/%(bskid)s/%(recid)s/%(uid)s' % \
                                    {'uid': uid,
                                     'recid': argd['recid'],
                                     'bskid': argd['bskid'],
                                     'CFG_PREFIX': CFG_PREFIX}
 
         # Check that user can
         # 1. is logged in
         # 2. comment records of this basket (to simplify, we use
         #    WebComment function to check this, even if it is not
         #    entirely adequate)
         # 3. attach files
 
         user_info = collect_user_info(req)
         (auth_code, dummy) = check_user_can_attach_file_to_comments(user_info, argd['recid'])
 
         fileurl = ''
         callback_function = ''
         if user_info['email'] == 'guest':
             # 1. User is guest: must login prior to upload
             data ='Please login before uploading file.'
         if not user_info['precached_usebaskets']:
             msg = 'Sorry, you are not allowed to use WebBasket'
         elif not check_user_can_comment(uid, argd['bskid']):
             # 2. User cannot edit comment of this basket
             msg = 'Sorry, you are not allowed to submit files'
         elif auth_code:
             # 3. User cannot submit
             msg = 'Sorry, you are not allowed to submit files.'
         else:
             # Process the upload and get the response
             (msg, uploaded_file_path, filename, fileurl, callback_function) = \
                       process_CKEditor_upload(form, uid, user_files_path, user_files_absolute_path,
                                               recid=argd['recid'])
 
         send_response(req, msg, fileurl, callback_function)
 
 
 class WebInterfaceYourBasketsPages(WebInterfaceDirectory):
     """Defines the set of /yourbaskets pages."""
 
     _exports = ['',
                 'display_item',
                 'display',
                 'search',
                 'write_note',
                 'save_note',
                 'delete_note',
                 'add',
                 'delete',
                 'modify',
                 'edit',
                 'edit_topic',
                 'create_basket',
                 'display_public',
                 'list_public_baskets',
                 'subscribe',
                 'unsubscribe',
                 'write_public_note',
                 'save_public_note',
                 'attachments']
 
     attachments = WebInterfaceBasketCommentsFiles()
 
     def index(self, req, dummy):
         """Index page."""
         redirect_to_url(req, '%s/yourbaskets/display?%s' % (CFG_SITE_SECURE_URL, req.args))
 
     def display_item(self, req, dummy):
         """Legacy URL redirection."""
         redirect_to_url(req, '%s/yourbaskets/display?%s' % (CFG_SITE_SECURE_URL, req.args))
 
     def display(self, req, form):
         """Display basket interface."""
         #import rpdb2; rpdb2.start_embedded_debugger('password', fAllowRemote=True)
 
         argd = wash_urlargd(form, {'category':
                                      (str, CFG_WEBBASKET_CATEGORIES['PRIVATE']),
                                    'topic': (str, ""),
                                    'group': (int, 0),
                                    'bskid': (int, 0),
                                    'recid': (int, 0),
                                    'bsk_to_sort': (int, 0),
                                    'sort_by_title': (str, ""),
                                    'sort_by_date': (str, ""),
                                    'of': (str, "hb"),
                                    'ln': (str, CFG_SITE_LANG)})
 
         _ = gettext_set_language(argd['ln'])
 
         uid = getUid(req)
         if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1:
             return page_not_authorized(req, "../yourbaskets/display",
                                        navmenuid = 'yourbaskets')
         if isGuestUser(uid):
             if not CFG_WEBSESSION_DIFFERENTIATE_BETWEEN_GUESTS:
                 return redirect_to_url(req, "%s/youraccount/login%s" % (
                     CFG_SITE_SECURE_URL,
                         make_canonical_urlargd({
                     'referer' : "%s/yourbaskets/display%s" % (
                         CFG_SITE_SECURE_URL,
                         make_canonical_urlargd(argd, {})),
                     "ln" : argd['ln']}, {})))
 
         user_info = collect_user_info(req)
         if not user_info['precached_usebaskets']:
             return page_not_authorized(req, "../", \
                                        text = _("You are not authorized to use baskets."))
 
         (body, dummy, navtrail) = perform_request_display(uid=uid,
                                                    selected_category=argd['category'],
                                                    selected_topic=argd['topic'],
                                                    selected_group_id=argd['group'],
                                                    selected_bskid=argd['bskid'],
                                                    selected_recid=argd['recid'],
                                                    of=argd['of'],
                                                    ln=argd['ln'])
 
         if isGuestUser(uid):
             body = create_guest_warning_box(argd['ln']) + body
 
         # register event in webstat
         if user_info['email']:
             user_str = "%s (%d)" % (user_info['email'], user_info['uid'])
         else:
             user_str = ""
         try:
             register_customevent("baskets", ["display", "", user_str])
         except:
             register_exception(suffix="Do the webstat tables exists? Try with 'webstatadmin --load-config'")
 
         rssurl = CFG_SITE_SECURE_URL + "/rss"
 
         if argd['of'] != 'hb':
             page_start(req, of=argd['of'])
 
             if argd['of'].startswith('x'):
                 req.write(body)
                 page_end(req, of=argd['of'])
                 return
 
         elif argd['bskid']:
-            rssurl = "%s/yourbaskets/display?category=%s&topic=%s&group=%i&bskid=%i&of=xr" % \
+            rssurl = "%s/yourbaskets/display?category=%s&amp;topic=%s&amp;group=%i&amp;bskid=%i&amp;of=xr" % \
                      (CFG_SITE_SECURE_URL,
-                      cgi.escape(argd['category']),
-                      cgi.escape(argd['topic']),
+                      argd['category'],
+                      urllib.quote(argd['topic']),
                       argd['group'],
                       argd['bskid'])
 
         return page(title       = _("Display baskets"),
                     body        = body,
                     navtrail    = navtrail,
                     uid         = uid,
                     lastupdated = __lastupdated__,
                     language    = argd['ln'],
                     req         = req,
                     navmenuid   = 'yourbaskets',
                     of          = argd['of'],
                     navtrail_append_title_p = 0,
                     secure_page_p=1,
                     rssurl=rssurl)
 
     def search(self, req, form):
         """Search baskets interface."""
-
         argd = wash_urlargd(form, {'category': (str, ""),
                                    'topic': (str, ""),
                                    'group': (int, 0),
                                    'p': (str, ""),
                                    'b': (str, ""),
                                    'n': (int, 0),
                                    'of': (str, "hb"),
                                    'verbose': (int, 0),
                                    'ln': (str, CFG_SITE_LANG)})
 
         _ = gettext_set_language(argd['ln'])
 
         uid = getUid(req)
         if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1:
             return page_not_authorized(req, "../yourbaskets/search",
                                        navmenuid = 'yourbaskets')
         if isGuestUser(uid):
             if not CFG_WEBSESSION_DIFFERENTIATE_BETWEEN_GUESTS:
                 return redirect_to_url(req, "%s/youraccount/login%s" % (
                     CFG_SITE_SECURE_URL,
                         make_canonical_urlargd({
                     'referer' : "%s/yourbaskets/search%s" % (
                         CFG_SITE_SECURE_URL,
                         make_canonical_urlargd(argd, {})),
                     "ln" : argd['ln']}, {})))
 
         user_info = collect_user_info(req)
         if not user_info['precached_usebaskets']:
             return page_not_authorized(req, "../", \
                                        text = _("You are not authorized to use baskets."))
 
         (body, navtrail) = perform_request_search(uid=uid,
                                                   selected_category=argd['category'],
                                                   selected_topic=argd['topic'],
                                                   selected_group_id=argd['group'],
                                                   p=argd['p'],
                                                   b=argd['b'],
                                                   n=argd['n'],
 #                                                  format=argd['of'],
                                                   ln=argd['ln'])
 
         # register event in webstat
         if user_info['email']:
             user_str = "%s (%d)" % (user_info['email'], user_info['uid'])
         else:
             user_str = ""
         try:
             register_customevent("baskets", ["search", "", user_str])
         except:
             register_exception(suffix="Do the webstat tables exists? Try with 'webstatadmin --load-config'")
 
         return page(title       = _("Search baskets"),
                     body        = body,
                     navtrail    = navtrail,
                     uid         = uid,
                     lastupdated = __lastupdated__,
                     language    = argd['ln'],
                     req         = req,
                     navmenuid   = 'yourbaskets',
                     of          = argd['of'],
                     navtrail_append_title_p = 0,
                     secure_page_p=1)
 
     def write_note(self, req, form):
         """Write a comment (just interface for writing)"""
 
         argd = wash_urlargd(form, {'category': (str, CFG_WEBBASKET_CATEGORIES['PRIVATE']),
                                    'topic': (str, ""),
                                    'group': (int, 0),
                                    'bskid': (int, 0),
                                    'recid': (int, 0),
                                    'cmtid': (int, 0),
                                    'of'   : (str, ''),
                                    'ln': (str, CFG_SITE_LANG)})
 
         _ = gettext_set_language(argd['ln'])
         uid = getUid(req)
         if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1:
             return page_not_authorized(req, "../yourbaskets/write_note",
                                        navmenuid = 'yourbaskets')
 
         if isGuestUser(uid):
             if not CFG_WEBSESSION_DIFFERENTIATE_BETWEEN_GUESTS:
                 return redirect_to_url(req, "%s/youraccount/login%s" % (
                     CFG_SITE_SECURE_URL,
                         make_canonical_urlargd({
                     'referer' : "%s/yourbaskets/write_note%s" % (
                         CFG_SITE_SECURE_URL,
                         make_canonical_urlargd(argd, {})),
                     "ln" : argd['ln']}, {})))
 
         user_info = collect_user_info(req)
         if not user_info['precached_usebaskets']:
             return page_not_authorized(req, "../", \
                                        text = _("You are not authorized to use baskets."))
 
         (body, navtrail) = perform_request_write_note(uid=uid,
                                                       category=argd['category'],
                                                       topic=argd['topic'],
                                                       group_id=argd['group'],
                                                       bskid=argd['bskid'],
                                                       recid=argd['recid'],
                                                       cmtid=argd['cmtid'],
                                                       ln=argd['ln'])
 
         # register event in webstat
         basket_str = "%s (%d)" % (get_basket_name(argd['bskid']), argd['bskid'])
         if user_info['email']:
             user_str = "%s (%d)" % (user_info['email'], user_info['uid'])
         else:
             user_str = ""
         try:
             register_customevent("baskets", ["write_note", basket_str, user_str])
         except:
             register_exception(suffix="Do the webstat tables exists? Try with 'webstatadmin --load-config'")
 
         return page(title       = _("Add a note"),
                     body        = body,
                     navtrail    = navtrail,
                     uid         = uid,
                     lastupdated = __lastupdated__,
                     language    = argd['ln'],
                     req         = req,
                     navmenuid   = 'yourbaskets',
                     of          = argd['of'],
                     secure_page_p=1)
 
     def save_note(self, req, form):
         """Save comment on record in basket"""
 
         argd = wash_urlargd(form, {'category': (str, CFG_WEBBASKET_CATEGORIES['PRIVATE']),
                                    'topic': (str, ""),
                                    'group': (int, 0),
                                    'bskid': (int, 0),
                                    'recid': (int, 0),
                                    'note_title': (str, ""),
                                    'note_body': (str, ""),
                                    'editor_type': (str, ""),
                                    'of': (str, ''),
                                    'ln': (str, CFG_SITE_LANG),
                                    'reply_to': (int, 0)})
 
         _ = gettext_set_language(argd['ln'])
         uid = getUid(req)
         if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1:
             return page_not_authorized(req, "../yourbaskets/save_note",
                                        navmenuid = 'yourbaskets')
 
         if isGuestUser(uid):
             if not CFG_WEBSESSION_DIFFERENTIATE_BETWEEN_GUESTS:
                 return redirect_to_url(req, "%s/youraccount/login%s" % (
                     CFG_SITE_SECURE_URL,
                         make_canonical_urlargd({
                     'referer' : "%s/yourbaskets/save_note%s" % (
                         CFG_SITE_SECURE_URL,
                         make_canonical_urlargd(argd, {})),
                     "ln" : argd['ln']}, {})))
 
         user_info = collect_user_info(req)
         if not user_info['precached_usebaskets']:
             return page_not_authorized(req, "../", \
                                        text = _("You are not authorized to use baskets."))
 
         (body, navtrail) = perform_request_save_note(uid=uid,
                                                     category=argd['category'],
                                                     topic=argd['topic'],
                                                     group_id=argd['group'],
                                                     bskid=argd['bskid'],
                                                     recid=argd['recid'],
                                                     note_title=argd['note_title'],
                                                     note_body=argd['note_body'],
                                                     editor_type=argd['editor_type'],
                                                     ln=argd['ln'],
                                                     reply_to=argd['reply_to'])
 
         # TODO: do not stat event if save was not succussful
         # register event in webstat
         basket_str = "%s (%d)" % (get_basket_name(argd['bskid']), argd['bskid'])
         if user_info['email']:
             user_str = "%s (%d)" % (user_info['email'], user_info['uid'])
         else:
             user_str = ""
         try:
             register_customevent("baskets", ["save_note", basket_str, user_str])
         except:
             register_exception(suffix="Do the webstat tables exists? Try with 'webstatadmin --load-config'")
 
         return page(title       = _("Display item and notes"),
                     body        = body,
                     navtrail    = navtrail,
                     uid         = uid,
                     lastupdated = __lastupdated__,
                     language    = argd['ln'],
                     req         = req,
                     navmenuid   = 'yourbaskets',
                     of          = argd['of'],
                     navtrail_append_title_p = 0,
                     secure_page_p=1)
 
     def delete_note(self, req, form):
         """Delete a comment
         @param bskid: id of basket (int)
         @param recid: id of record (int)
         @param cmtid: id of comment (int)
         @param category: category (see webbasket_config) (str)
         @param topic: nb of topic currently displayed (int)
         @param group: id of group baskets currently displayed (int)
         @param ln: language"""
 
         argd = wash_urlargd(form, {'category': (str, CFG_WEBBASKET_CATEGORIES['PRIVATE']),
                                    'topic': (str, ""),
                                    'group': (int, 0),
                                    'bskid': (int, 0),
                                    'recid': (int, 0),
                                    'cmtid': (int, 0),
                                    'of'   : (str, ''),
                                    'ln': (str, CFG_SITE_LANG)})
 
         _ = gettext_set_language(argd['ln'])
 
         uid = getUid(req)
         if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1:
             return page_not_authorized(req, "../yourbaskets/delete_note",
                                        navmenuid = 'yourbaskets')
 
         if isGuestUser(uid):
             if not CFG_WEBSESSION_DIFFERENTIATE_BETWEEN_GUESTS:
                 return redirect_to_url(req, "%s/youraccount/delete_note%s" % (
                     CFG_SITE_SECURE_URL,
                         make_canonical_urlargd({
                     'referer' : "%s/yourbaskets/display%s" % (
                         CFG_SITE_SECURE_URL,
                         make_canonical_urlargd(argd, {})),
                     "ln" : argd['ln']}, {})))
 
         user_info = collect_user_info(req)
         if not user_info['precached_usebaskets']:
             return page_not_authorized(req, "../", \
                                        text = _("You are not authorized to use baskets."))
 
         (body, navtrail) = perform_request_delete_note(uid=uid,
                                                        category=argd['category'],
                                                        topic=argd['topic'],
                                                        group_id=argd['group'],
                                                        bskid=argd['bskid'],
                                                        recid=argd['recid'],
                                                        cmtid=argd['cmtid'],
                                                        ln=argd['ln'])
 
         # TODO: do not stat event if delete was not succussful
         # register event in webstat
         basket_str = "%s (%d)" % (get_basket_name(argd['bskid']), argd['bskid'])
         user_info = collect_user_info(req)
         if user_info['email']:
             user_str = "%s (%d)" % (user_info['email'], user_info['uid'])
         else:
             user_str = ""
         try:
             register_customevent("baskets", ["delete_note", basket_str, user_str])
         except:
             register_exception(suffix="Do the webstat tables exists? Try with 'webstatadmin --load-config'")
 
         return page(title       = _("Display item and notes"),
                     body        = body,
                     navtrail    = navtrail,
                     uid         = uid,
                     lastupdated = __lastupdated__,
                     language    = argd['ln'],
                     req         = req,
                     navmenuid   = 'yourbaskets',
                     of          = argd['of'],
                     navtrail_append_title_p = 0,
                     secure_page_p=1)
 
     def add(self, req, form):
         """Add records to baskets.
         @param recid: list of records to add
         @param colid: in case of external collections, the id of the collection the records belong to
         @param bskids: list of baskets to add records to. if not provided,
                        will return a page where user can select baskets
         @param referer: URL of the referring page
         @param new_basket_name: add record to new basket
         @param new_topic_name: new basket goes into new topic
         @param create_in_topic: # of topic to put basket into
         @param ln: language"""
 
         # TODO: apply a maximum limit of items (100) that can be added to a basket
         # at once. Also see the build_search_url function of websearch_..._searcher.py
         # for the "rg" GET variable.
         argd = wash_urlargd(form, {'recid': (list, []),
                                    'category': (str, ""),
                                    'bskid': (int, 0),
                                    'colid': (int, 0),
                                    'es_title': (str, ""),
                                    'es_desc': (str, ""),
                                    'es_url': (str, ""),
                                    'note_body': (str, ""),
                                    'editor_type': (str, ""),
                                    'b': (str, ""),
                                    'copy': (int, 0),
                                    'wait': (int, 0),
                                    'referer': (str, ""),
                                    "of" : (str, ''),
                                    'ln': (str, CFG_SITE_LANG)})
 
         _ = gettext_set_language(argd['ln'])
 
         uid = getUid(req)
         if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1:
             return page_not_authorized(req, "../yourbaskets/add",
                                        navmenuid = 'yourbaskets')
 
         if isGuestUser(uid):
             if not CFG_WEBSESSION_DIFFERENTIATE_BETWEEN_GUESTS:
                 return redirect_to_url(req, "%s/youraccount/login%s" % (
                     CFG_SITE_SECURE_URL,
                         make_canonical_urlargd({
                     'referer' : "%s/yourbaskets/add%s" % (
                         CFG_SITE_SECURE_URL,
                         make_canonical_urlargd(argd, {})),
                     "ln" : argd['ln']}, {})))
 
         user_info = collect_user_info(req)
         if not user_info['precached_usebaskets']:
             return page_not_authorized(req, "../", \
                                        text = _("You are not authorized to use baskets."))
 
         if not argd['referer']:
             argd['referer'] = get_referer(req)
 
         (body, navtrail) = perform_request_add(uid=uid,
                                                recids=argd['recid'],
                                                colid=argd['colid'],
                                                bskid=argd['bskid'],
                                                es_title=argd['es_title'],
                                                es_desc=argd['es_desc'],
                                                es_url=argd['es_url'],
                                                note_body=argd['note_body'],
                                                editor_type=argd['editor_type'],
                                                category=argd['category'],
                                                b=argd['b'],
                                                copy=argd['copy'],
                                                wait=argd['wait'],
                                                referer=argd['referer'],
                                                ln=argd['ln'])
 
         if isGuestUser(uid):
             body = create_guest_warning_box(argd['ln']) + body
 
         # register event in webstat
         bskid = argd['bskid']
         basket_str = "%s (%s)" % (get_basket_name(bskid), bskid)
         if user_info['email']:
             user_str = "%s (%d)" % (user_info['email'], user_info['uid'])
         else:
             user_str = ""
         try:
             register_customevent("baskets", ["add", basket_str, user_str])
         except:
             register_exception(suffix="Do the webstat tables exists? Try with 'webstatadmin --load-config'")
 
         return page(title       = _('Add to basket'),
                     body        = body,
                     navtrail    = navtrail,
                     uid         = uid,
                     lastupdated = __lastupdated__,
                     language    = argd['ln'],
                     req         = req,
                     navmenuid   = 'yourbaskets',
                     of          = argd['of'],
                     navtrail_append_title_p = 0,
                     secure_page_p=1)
 
     def delete(self, req, form):
         """Delete basket interface"""
-        argd = wash_urlargd(form, {'bskid': (int, -1),
-                                   'confirmed': (int, 0),
-                                   'category':
-                                     (str, CFG_WEBBASKET_CATEGORIES['PRIVATE']),
-                                   'topic': (str, ""),
-                                   'group': (int, 0),
-                                   'of'   : (str, ''),
-                                   'ln': (str, CFG_SITE_LANG)})
+        argd = wash_urlargd(form, {'bskid'      : (int, -1),
+                                   'confirmed'  : (int, 0),
+                                   'category'   : (str, CFG_WEBBASKET_CATEGORIES['PRIVATE']),
+                                   'topic'      : (str, ""),
+                                   'group'      : (int, 0),
+                                   'of'         : (str, ''),
+                                   'ln'         : (str, CFG_SITE_LANG)})
 
         _ = gettext_set_language(argd['ln'])
         uid = getUid(req)
         if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1:
             return page_not_authorized(req, "../yourbaskets/delete",
                                        navmenuid = 'yourbaskets')
 
         if isGuestUser(uid):
             if not CFG_WEBSESSION_DIFFERENTIATE_BETWEEN_GUESTS:
                 return redirect_to_url(req, "%s/youraccount/login%s" % (
                     CFG_SITE_SECURE_URL,
                         make_canonical_urlargd({
                     'referer' : "%s/yourbaskets/delete%s" % (
                         CFG_SITE_SECURE_URL,
                         make_canonical_urlargd(argd, {})),
                     "ln" : argd['ln']}, {})))
 
         user_info = collect_user_info(req)
         if not user_info['precached_usebaskets']:
             return page_not_authorized(req, "../", \
                                        text = _("You are not authorized to use baskets."))
 
         body=perform_request_delete(uid=uid,
                                     bskid=argd['bskid'],
                                     confirmed=argd['confirmed'],
                                     category=argd['category'],
                                     selected_topic=argd['topic'],
                                     selected_group_id=argd['group'],
                                     ln=argd['ln'])
         if argd['confirmed']:
             if argd['category'] == CFG_WEBBASKET_CATEGORIES['PRIVATE']:
                 argd['topic'] = wash_topic(uid, argd['topic'])[0]
             elif argd['category'] == CFG_WEBBASKET_CATEGORIES['GROUP']:
                 argd['group'] = wash_group(uid, argd['group'])[0]
             url = """%s/yourbaskets/display?category=%s&topic=%s&group=%i&ln=%s""" % \
-                  (CFG_SITE_SECURE_URL, argd['category'], argd['topic'], argd['group'], argd['ln'])
+                  (CFG_SITE_SECURE_URL,
+                   argd['category'],
+                   urllib.quote(argd['topic']),
+                   argd['group'],
+                   argd['ln'])
             redirect_to_url(req, url)
         else:
             navtrail = '<a class="navtrail" href="%s/youraccount/display?ln=%s">'\
                        '%s</a>'
             navtrail %= (CFG_SITE_SECURE_URL, argd['ln'], _("Your Account"))
             navtrail_end = create_basket_navtrail(uid=uid,
                                                   category=argd['category'],
                                                   topic=argd['topic'],
                                                   group=argd['group'],
                                                   bskid=argd['bskid'],
                                                   ln=argd['ln'])
             if isGuestUser(uid):
                 body = create_guest_warning_box(argd['ln']) + body
 
             # register event in webstat
             basket_str = "%s (%d)" % (get_basket_name(argd['bskid']), argd['bskid'])
             if user_info['email']:
                 user_str = "%s (%d)" % (user_info['email'], user_info['uid'])
             else:
                 user_str = ""
             try:
                 register_customevent("baskets", ["delete", basket_str, user_str])
             except:
                 register_exception(suffix="Do the webstat tables exists? Try with 'webstatadmin --load-config'")
 
             return page(title = _("Delete a basket"),
                         body        = body,
                         navtrail    = navtrail + navtrail_end,
                         uid         = uid,
                         lastupdated = __lastupdated__,
                         language    = argd['ln'],
                         req         = req,
                         navmenuid   = 'yourbaskets',
                         of          = argd['of'],
                         secure_page_p=1)
 
     def modify(self, req, form):
         """Modify basket content interface (reorder, suppress record, etc.)"""
 
         argd = wash_urlargd(form, {'action': (str, ""),
                                    'bskid': (int, -1),
                                    'recid': (int, 0),
                                    'category': (str, CFG_WEBBASKET_CATEGORIES['PRIVATE']),
                                    'topic': (str, ""),
                                    'group': (int, 0),
                                    'of'   : (str, ''),
                                    'ln': (str, CFG_SITE_LANG)})
 
         _ = gettext_set_language(argd['ln'])
 
         uid = getUid(req)
         if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1:
             return page_not_authorized(req, "../yourbaskets/modify",
                                        navmenuid = 'yourbaskets')
 
         if isGuestUser(uid):
             if not CFG_WEBSESSION_DIFFERENTIATE_BETWEEN_GUESTS:
                 return redirect_to_url(req, "%s/youraccount/login%s" % (
                     CFG_SITE_SECURE_URL,
                         make_canonical_urlargd({
                     'referer' : "%s/yourbaskets/modify%s" % (
                         CFG_SITE_SECURE_URL,
                         make_canonical_urlargd(argd, {})),
                     "ln" : argd['ln']}, {})))
 
         user_info = collect_user_info(req)
         if not user_info['precached_usebaskets']:
             return page_not_authorized(req, "../", \
                                        text = _("You are not authorized to use baskets."))
 
         url = CFG_SITE_SECURE_URL
-        url += '/yourbaskets/display?category=%s&amp;topic=%s&amp;group=%i&amp;bskid=%i&amp;ln=%s' % \
-               (argd['category'], argd['topic'], argd['group'], argd['bskid'], argd['ln'])
+        url += '/yourbaskets/display?category=%s&topic=%s&group=%i&bskid=%i&ln=%s' % \
+               (argd['category'], urllib.quote(argd['topic']), argd['group'], argd['bskid'], argd['ln'])
         if argd['action'] == CFG_WEBBASKET_ACTIONS['DELETE']:
             delete_record(uid, argd['bskid'], argd['recid'])
             redirect_to_url(req, url)
         elif argd['action'] == CFG_WEBBASKET_ACTIONS['UP']:
             move_record(uid, argd['bskid'], argd['recid'], argd['action'])
             redirect_to_url(req, url)
         elif argd['action'] == CFG_WEBBASKET_ACTIONS['DOWN']:
             move_record(uid, argd['bskid'], argd['recid'], argd['action'])
             redirect_to_url(req, url)
         elif argd['action'] == CFG_WEBBASKET_ACTIONS['COPY']:
             title = _("Copy record to basket")
             referer = get_referer(req)
             (body, navtrail) = perform_request_add(uid=uid,
                                                    recids=argd['recid'],
                                                    copy=True,
                                                    referer=referer,
                                                    ln=argd['ln'])
             if isGuestUser(uid):
                 body = create_guest_warning_box(argd['ln']) + body
         else:
             title = ''
             body = ''
 #            warnings = [('WRN_WEBBASKET_UNDEFINED_ACTION',)]
         navtrail = '<a class="navtrail" href="%s/youraccount/display?ln=%s">'\
                    '%s</a>'
         navtrail %= (CFG_SITE_SECURE_URL, argd['ln'], _("Your Account"))
         navtrail_end = create_basket_navtrail(uid=uid,
                                               category=argd['category'],
                                               topic=argd['topic'],
                                               group=argd['group'],
                                               bskid=argd['bskid'],
                                               ln=argd['ln'])
 
         # register event in webstat
         basket_str = "%s (%d)" % (get_basket_name(argd['bskid']), argd['bskid'])
         if user_info['email']:
             user_str = "%s (%d)" % (user_info['email'], user_info['uid'])
         else:
             user_str = ""
         try:
             register_customevent("baskets", ["modify", basket_str, user_str])
         except:
             register_exception(suffix="Do the webstat tables exists? Try with 'webstatadmin --load-config'")
 
         return page(title = title,
                     body        = body,
                     navtrail    = navtrail + navtrail_end,
                     uid         = uid,
                     lastupdated = __lastupdated__,
                     language    = argd['ln'],
                     req         = req,
                     navmenuid   = 'yourbaskets',
                     of          = argd['of'],
                     secure_page_p=1)
 
     def edit(self, req, form):
         """Edit basket interface"""
         argd = wash_urlargd(form, {'bskid': (int, 0),
                                    'groups': (list, []),
                                    'topic': (str, ""),
                                    'add_group': (str, ""),
                                    'group_cancel': (str, ""),
                                    'submit': (str, ""),
                                    'cancel': (str, ""),
                                    'delete': (str, ""),
                                    'new_name': (str, ""),
                                    'new_topic': (str, ""),
                                    'new_topic_name': (str, ""),
                                    'new_group': (str, ""),
                                    'external': (str, ""),
                                    'of'      : (str, ''),
                                    'ln': (str, CFG_SITE_LANG)})
 
         uid = getUid(req)
         if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1:
             return page_not_authorized(req, "../yourbaskets/edit",
                                        navmenuid = 'yourbaskets')
 
         if isGuestUser(uid):
             if not CFG_WEBSESSION_DIFFERENTIATE_BETWEEN_GUESTS:
                 return redirect_to_url(req, "%s/youraccount/login%s" % (
                     CFG_SITE_SECURE_URL,
                         make_canonical_urlargd({
                     'referer' : "%s/yourbaskets/edit%s" % (
                         CFG_SITE_SECURE_URL,
                         make_canonical_urlargd(argd, {})),
                     "ln" : argd['ln']}, {})))
 
         _ = gettext_set_language(argd['ln'])
         user_info = collect_user_info(req)
         if not user_info['precached_usebaskets']:
             return page_not_authorized(req, "../", \
                                        text = _("You are not authorized to use baskets."))
 
         if argd['cancel']:
             url = CFG_SITE_SECURE_URL + '/yourbaskets/display?category=%s&topic=%s&ln=%s'
-            url %= (CFG_WEBBASKET_CATEGORIES['PRIVATE'], argd['topic'],
+            url %= (CFG_WEBBASKET_CATEGORIES['PRIVATE'],
+                    urllib.quote(argd['topic']),
                     argd['ln'])
             redirect_to_url(req, url)
         elif argd['delete']:
             url = CFG_SITE_SECURE_URL
             url += '/yourbaskets/delete?bskid=%i&category=%s&topic=%s&ln=%s' % \
-                   (argd['bskid'], CFG_WEBBASKET_CATEGORIES['PRIVATE'],
-                   argd['topic'], argd['ln'])
+                   (argd['bskid'],
+                    CFG_WEBBASKET_CATEGORIES['PRIVATE'],
+                    urllib.quote(argd['topic']),
+                    argd['ln'])
             redirect_to_url(req, url)
         elif argd['add_group'] and not(argd['new_group']):
             body = perform_request_add_group(uid=uid,
                                              bskid=argd['bskid'],
                                              topic=argd['topic'],
                                              ln=argd['ln'])
 #            warnings = []
         elif (argd['add_group'] and argd['new_group']) or argd['group_cancel']:
             if argd['add_group']:
                 perform_request_add_group(uid=uid,
                                           bskid=argd['bskid'],
                                           topic=argd['topic'],
                                           group_id=argd['new_group'],
                                           ln=argd['ln'])
             body = perform_request_edit(uid=uid,
                                         bskid=argd['bskid'],
                                         topic=argd['topic'],
                                         ln=argd['ln'])
         elif argd['submit']:
             body = perform_request_edit(uid=uid,
                                         bskid=argd['bskid'],
                                         topic=argd['topic'],
                                         new_name=argd['new_name'],
                                         new_topic=argd['new_topic'],
                                         new_topic_name=argd['new_topic_name'],
                                         groups=argd['groups'],
                                         external=argd['external'],
                                         ln=argd['ln'])
             if argd['new_topic'] != "-1":
                 argd['topic'] = argd['new_topic']
             url = CFG_SITE_SECURE_URL + '/yourbaskets/display?category=%s&topic=%s&ln=%s' % \
                   (CFG_WEBBASKET_CATEGORIES['PRIVATE'],
-                   argd['topic'], argd['ln'])
+                   urllib.quote(argd['topic']),
+                   argd['ln'])
             redirect_to_url(req, url)
         else:
             body = perform_request_edit(uid=uid,
-                                                    bskid=argd['bskid'],
-                                                    topic=argd['topic'],
-                                                    ln=argd['ln'])
+                                        bskid=argd['bskid'],
+                                        topic=argd['topic'],
+                                        ln=argd['ln'])
 
         navtrail = '<a class="navtrail" href="%s/youraccount/display?ln=%s">'\
                    '%s</a>'
         navtrail %= (CFG_SITE_SECURE_URL, argd['ln'], _("Your Account"))
         navtrail_end = create_basket_navtrail(
                             uid=uid,
                             category=CFG_WEBBASKET_CATEGORIES['PRIVATE'],
                             topic=argd['topic'],
                             group=0,
                             bskid=argd['bskid'],
                             ln=argd['ln'])
         if isGuestUser(uid):
             body = create_guest_warning_box(argd['ln']) + body
 
         # register event in webstat
         basket_str = "%s (%d)" % (get_basket_name(argd['bskid']), argd['bskid'])
         if user_info['email']:
             user_str = "%s (%d)" % (user_info['email'], user_info['uid'])
         else:
             user_str = ""
         try:
             register_customevent("baskets", ["edit", basket_str, user_str])
         except:
             register_exception(suffix="Do the webstat tables exists? Try with 'webstatadmin --load-config'")
 
         return page(title = _("Edit basket"),
                     body        = body,
                     navtrail    = navtrail + navtrail_end,
                     uid         = uid,
                     lastupdated = __lastupdated__,
                     language    = argd['ln'],
                     req         = req,
                     navmenuid   = 'yourbaskets',
                     of          = argd['of'],
                     secure_page_p=1)
 
     def edit_topic(self, req, form):
         """Edit topic interface"""
         argd = wash_urlargd(form, {'topic': (str, ""),
                                    'submit': (str, ""),
                                    'cancel': (str, ""),
                                    'delete': (str, ""),
                                    'new_name': (str, ""),
                                    'of'      : (str, ''),
                                    'ln': (str, CFG_SITE_LANG)})
 
         uid = getUid(req)
         if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1:
             return page_not_authorized(req, "../yourbaskets/edit",
                                        navmenuid = 'yourbaskets')
 
         if isGuestUser(uid):
             if not CFG_WEBSESSION_DIFFERENTIATE_BETWEEN_GUESTS:
                 return redirect_to_url(req, "%s/youraccount/login%s" % (
                     CFG_SITE_SECURE_URL,
                         make_canonical_urlargd({
                     'referer' : "%s/yourbaskets/edit_topic%s" % (
                         CFG_SITE_SECURE_URL,
                         make_canonical_urlargd(argd, {})),
                     "ln" : argd['ln']}, {})))
 
         _ = gettext_set_language(argd['ln'])
         user_info = collect_user_info(req)
         if not user_info['precached_usebaskets']:
             return page_not_authorized(req, "../", \
                                        text = _("You are not authorized to use baskets."))
 
         if argd['cancel']:
             url = CFG_SITE_SECURE_URL + '/yourbaskets/display?category=%s&ln=%s'
             url %= (CFG_WEBBASKET_CATEGORIES['PRIVATE'], argd['ln'])
-            #url = CFG_SITE_SECURE_URL + '/yourbaskets/display?category=%s&topic=%s&ln=%s'
-            #url %= (CFG_WEBBASKET_CATEGORIES['PRIVATE'], argd['topic'],
-            #        argd['ln'])
             redirect_to_url(req, url)
         elif argd['delete']:
             url = CFG_SITE_SECURE_URL
             url += '/yourbaskets/delete?bskid=%i&category=%s&topic=%s&ln=%s' % \
-                   (argd['bskid'], CFG_WEBBASKET_CATEGORIES['PRIVATE'],
-                   argd['topic'], argd['ln'])
+                   (argd['bskid'],
+                    CFG_WEBBASKET_CATEGORIES['PRIVATE'],
+                    urllib.quote(argd['topic']),
+                    argd['ln'])
             redirect_to_url(req, url)
         elif argd['submit']:
             body = perform_request_edit_topic(uid=uid,
                                               topic=argd['topic'],
                                               new_name=argd['new_name'],
                                               ln=argd['ln'])
-            #url = CFG_SITE_SECURE_URL + '/yourbaskets/display?category=%s&topic=%s&ln=%s' % \
-            #      (CFG_WEBBASKET_CATEGORIES['PRIVATE'],
-            #       argd['topic'], argd['ln'])
             url = CFG_SITE_SECURE_URL + '/yourbaskets/display?category=%s&ln=%s' % \
                   (CFG_WEBBASKET_CATEGORIES['PRIVATE'], argd['ln'])
             redirect_to_url(req, url)
         else:
             body = perform_request_edit_topic(uid=uid,
                                               topic=argd['topic'],
                                               ln=argd['ln'])
 
         navtrail = '<a class="navtrail" href="%s/youraccount/display?ln=%s">'\
                    '%s</a>'
         navtrail %= (CFG_SITE_SECURE_URL, argd['ln'], _("Your Account"))
         navtrail_end = ""
         #navtrail_end = create_basket_navtrail(
         #                    uid=uid,
         #                    category=CFG_WEBBASKET_CATEGORIES['PRIVATE'],
         #                    topic=argd['topic'],
         #                    group=0,
         #                    ln=argd['ln'])
         if isGuestUser(uid):
             body = create_guest_warning_box(argd['ln']) + body
 
         # register event in webstat
         #basket_str = "%s (%d)" % (get_basket_name(argd['bskid']), argd['bskid'])
         #if user_info['email']:
         #    user_str = "%s (%d)" % (user_info['email'], user_info['uid'])
         #else:
         #    user_str = ""
         #try:
         #    register_customevent("baskets", ["edit", basket_str, user_str])
         #except:
         #    register_exception(suffix="Do the webstat tables exists? Try with 'webstatadmin --load-config'")
 
-        return page(title = _("Edit topic"),
+        return page(title       = _("Edit topic"),
                     body        = body,
                     navtrail    = navtrail + navtrail_end,
                     uid         = uid,
                     lastupdated = __lastupdated__,
                     language    = argd['ln'],
                     req         = req,
                     navmenuid   = 'yourbaskets',
                     of          = argd['of'],
                     secure_page_p=1)
 
     def create_basket(self, req, form):
         """Create basket interface"""
 
         argd = wash_urlargd(form, {'new_basket_name': (str, ""),
                                    'new_topic_name' : (str, ""),
                                    'create_in_topic': (str, "-1"),
                                    'topic'          : (str, ""),
                                    'recid'          : (list, []),
                                    'colid'          : (int, -1),
                                    'es_title'       : (str, ''),
                                    'es_desc'        : (str, ''),
                                    'es_url'         : (str, ''),
                                    'of'             : (str, ''),
                                    'ln'             : (str, CFG_SITE_LANG)})
 
         uid = getUid(req)
         if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1:
             return page_not_authorized(req, "../yourbaskets/create_basket",
                                        navmenuid = 'yourbaskets')
 
         if isGuestUser(uid):
             if not CFG_WEBSESSION_DIFFERENTIATE_BETWEEN_GUESTS:
                 return redirect_to_url(req, "%s/youraccount/login%s" % (
                     CFG_SITE_SECURE_URL,
                         make_canonical_urlargd({
                     'referer' : "%s/yourbaskets/create_basket%s" % (
                         CFG_SITE_SECURE_URL,
                         make_canonical_urlargd(argd, {})),
                     "ln" : argd['ln']}, {})))
 
         user_info = collect_user_info(req)
         _ = gettext_set_language(argd['ln'])
         if not user_info['precached_usebaskets']:
             return page_not_authorized(req, "../", \
                                        text = _("You are not authorized to use baskets."))
 
         if argd['new_basket_name'] and \
                 (argd['new_topic_name'] or argd['create_in_topic'] != "-1"):
             (bskid, topic) = perform_request_create_basket(
                                 req,
                                 uid=uid,
                                 new_basket_name=argd['new_basket_name'],
                                 new_topic_name=argd['new_topic_name'],
                                 create_in_topic=argd['create_in_topic'],
                                 recids=argd['recid'],
                                 colid=argd['colid'],
                                 es_title=argd['es_title'],
                                 es_desc=argd['es_desc'],
                                 es_url=argd['es_url'],
                                 ln=argd['ln'])
 
             # register event in webstat
             basket_str = "%s ()" % argd['new_basket_name']
             if user_info['email']:
                 user_str = "%s (%d)" % (user_info['email'], user_info['uid'])
             else:
                 user_str = ""
             try:
                 register_customevent("baskets", ["create_basket", basket_str, user_str])
             except:
                 register_exception(suffix="Do the webstat tables exists? Try with 'webstatadmin --load-config'")
 
             if ( argd['recid'] and argd['colid'] >= 0 ):
                 url = CFG_SITE_SECURE_URL + '/yourbaskets/add?category=%s&bskid=%i&colid=%i&recid=%s&wait=1&ln=%s'
                 url %= (CFG_WEBBASKET_CATEGORIES['PRIVATE'],
                         bskid,
                         argd['colid'],
                         '&recid='.join(str(recid) for recid in argd['recid']),
                         argd['ln'])
             elif ( argd['es_title'] and argd['es_desc'] and argd['es_url'] and argd['colid'] == -1 ):
                 url = CFG_SITE_SECURE_URL + '/yourbaskets/add?category=%s&bskid=%i&colid=%i&es_title=%s&es_desc=%s&es_url=%s&wait=1&ln=%s'
                 url %= (CFG_WEBBASKET_CATEGORIES['PRIVATE'],
                         bskid,
                         argd['colid'],
-                        quote(argd['es_title']),
-                        quote(argd['es_desc']),
-                        quote(argd['es_url']),
+                        urllib.quote(argd['es_title']),
+                        urllib.quote(argd['es_desc']),
+                        urllib.quote(argd['es_url']),
                         argd['ln'])
             else:
                 url = CFG_SITE_SECURE_URL + '/yourbaskets/display?category=%s&topic=%s&ln=%s'
-                url %= (CFG_WEBBASKET_CATEGORIES['PRIVATE'], topic, argd['ln'])
+                url %= (CFG_WEBBASKET_CATEGORIES['PRIVATE'],
+                        urllib.quote(topic),
+                        argd['ln'])
             redirect_to_url(req, url)
         else:
             body = perform_request_create_basket(req,
                                                  uid=uid,
                                                  new_basket_name=argd['new_basket_name'],
                                                  new_topic_name=argd['new_topic_name'],
                                                  create_in_topic=argd['create_in_topic'],
                                                  topic=argd['topic'],
                                                  recids=argd['recid'],
                                                  colid=argd['colid'],
                                                  es_title=argd['es_title'],
                                                  es_desc=argd['es_desc'],
                                                  es_url=argd['es_url'],
                                                  ln=argd['ln'])
             navtrail = '<a class="navtrail" href="%s/youraccount/'\
                        'display?ln=%s">%s</a>'
             navtrail %= (CFG_SITE_SECURE_URL, argd['ln'], _("Your Account"))
             if isGuestUser(uid):
                 body = create_guest_warning_box(argd['ln']) + body
             return page(title = _("Create basket"),
                         body        = body,
                         navtrail    = navtrail,
                         uid         = uid,
                         lastupdated = __lastupdated__,
                         language    = argd['ln'],
                         req         = req,
                         navmenuid   = 'yourbaskets',
                         of          = argd['of'],
                         secure_page_p=1)
 
     def display_public(self, req, form):
         """Display a public basket"""
 
         argd = wash_urlargd(form, {'bskid': (int, 0),
                                    'recid': (int, 0),
                                    'of': (str, "hb"),
                                    'ln': (str, CFG_SITE_LANG)})
 
         _ = gettext_set_language(argd['ln'])
 
         uid = getUid(req)
         if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1:
             return page_not_authorized(req, "../yourbaskets/display",
                                        navmenuid = 'yourbaskets')
 
         user_info = collect_user_info(req)
 
         if not argd['bskid']:
             (body, navtrail) = perform_request_list_public_baskets(uid)
             title = _('List of public baskets')
 
             # register event in webstat
             if user_info['email']:
                 user_str = "%s (%d)" % (user_info['email'], user_info['uid'])
             else:
                 user_str = ""
             try:
                 register_customevent("baskets", ["list_public_baskets", "", user_str])
             except:
                 register_exception(suffix="Do the webstat tables exists? Try with 'webstatadmin --load-config'")
 
         else:
             (body, dummy, navtrail) = perform_request_display_public(uid=uid,
                                                                   selected_bskid=argd['bskid'],
                                                                   selected_recid=argd['recid'],
                                                                   of=argd['of'],
                                                                   ln=argd['ln'])
             title = _('Public basket')
 
             # register event in webstat
             basket_str = "%s (%d)" % (get_basket_name(argd['bskid']), argd['bskid'])
             if user_info['email']:
                 user_str = "%s (%d)" % (user_info['email'], user_info['uid'])
             else:
                 user_str = ""
             try:
                 register_customevent("baskets", ["display_public", basket_str, user_str])
             except:
                 register_exception(suffix="Do the webstat tables exists? Try with 'webstatadmin --load-config'")
 
         rssurl = CFG_SITE_SECURE_URL + "/rss"
 
         if argd['of'] != 'hb':
             page_start(req, of=argd['of'])
 
             if argd['of'].startswith('x'):
                 req.write(body)
                 page_end(req, of=argd['of'])
                 return
         elif argd['bskid']:
-            rssurl = "%s/yourbaskets/display_public?&bskid=%i&of=xr" % \
+            rssurl = "%s/yourbaskets/display_public?&amp;bskid=%i&amp;of=xr" % \
                      (CFG_SITE_SECURE_URL,
                       argd['bskid'])
 
         return page(title       = title,
                     body        = body,
                     navtrail    = navtrail,
                     uid         = uid,
                     lastupdated = __lastupdated__,
                     language    = argd['ln'],
                     req         = req,
                     navmenuid   = 'yourbaskets',
                     of          = argd['of'],
                     navtrail_append_title_p = 0,
                     secure_page_p=1,
                     rssurl=rssurl)
 
     def list_public_baskets(self, req, form):
         """List of public baskets interface."""
 
         argd = wash_urlargd(form, {'limit': (int, 1),
                                    'sort': (str, 'name'),
                                    'asc': (int, 1),
                                    'of': (str, ''),
                                    'ln': (str, CFG_SITE_LANG)})
 
         _ = gettext_set_language(argd['ln'])
 
         uid = getUid(req)
         if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE == 2:
             return page_not_authorized(req, "../yourbaskets/list_public_baskets",
                                        navmenuid = 'yourbaskets')
 
         user_info = collect_user_info(req)
         nb_views_show = acc_authorize_action(user_info, 'runwebstatadmin')
         nb_views_show_p = not(nb_views_show[0])
 
         (body, navtrail) = perform_request_list_public_baskets(uid,
                                                                argd['limit'],
                                                                argd['sort'],
                                                                argd['asc'],
                                                                nb_views_show_p,
                                                                argd['ln'])
 
         return page(title = _("List of public baskets"),
                     body        = body,
                     navtrail    = navtrail,
                     uid         = uid,
                     lastupdated = __lastupdated__,
                     language    = argd['ln'],
                     req         = req,
                     navmenuid   = 'yourbaskets',
                     of          = argd['of'],
                     navtrail_append_title_p = 0,
                     secure_page_p=1)
 
     def subscribe(self, req, form):
         """Subscribe to a basket pseudo-interface."""
 
         argd = wash_urlargd(form, {'bskid': (int, 0),
                                    'of': (str, 'hb'),
                                    'ln': (str, CFG_SITE_LANG)})
 
         _ = gettext_set_language(argd['ln'])
 
         uid = getUid(req)
         if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE == 2:
             return page_not_authorized(req, "../yourbaskets/subscribe",
                                        navmenuid = 'yourbaskets')
 
         if isGuestUser(uid):
             if not CFG_WEBSESSION_DIFFERENTIATE_BETWEEN_GUESTS:
                 return redirect_to_url(req, "%s/youraccount/login%s" % (
                     CFG_SITE_SECURE_URL,
                         make_canonical_urlargd({
                     'referer' : "%s/yourbaskets/subscribe%s" % (
                         CFG_SITE_SECURE_URL,
                         make_canonical_urlargd(argd, {})),
                     "ln" : argd['ln']}, {})))
 
         user_info = collect_user_info(req)
         if not user_info['precached_usebaskets']:
             return page_not_authorized(req, "../", \
                                        text = _("You are not authorized to use baskets."))
 
         if not argd['bskid']:
             (body, navtrail) = perform_request_list_public_baskets(uid)
             title = _('List of public baskets')
 
         else:
             # TODO: Take care of XML output as shown below
             #req.content_type = "text/xml"
             #req.send_http_header()
             #return perform_request_display_public(bskid=argd['bskid'], of=argd['of'], ln=argd['ln'])
             subscribe_warnings_html = perform_request_subscribe(uid, argd['bskid'], argd['ln'])
             (body, dummy, navtrail) = perform_request_display_public(uid=uid,
                                                                selected_bskid=argd['bskid'],
                                                                selected_recid=0,
                                                                of=argd['of'],
                                                                ln=argd['ln'])
             #warnings.extend(subscribe_warnings)
             body = subscribe_warnings_html + body
             title = _('Public basket')
 
         return page(title       = title,
                     body        = body,
                     navtrail    = navtrail,
                     uid         = uid,
                     lastupdated = __lastupdated__,
                     language    = argd['ln'],
                     req         = req,
                     navmenuid   = 'yourbaskets',
                     of          = argd['of'],
                     navtrail_append_title_p = 0,
                     secure_page_p=1)
 
     def unsubscribe(self, req, form):
         """Unsubscribe from basket pseudo-interface."""
 
         argd = wash_urlargd(form, {'bskid': (int, 0),
                                    'of': (str, 'hb'),
                                    'ln': (str, CFG_SITE_LANG)})
 
         _ = gettext_set_language(argd['ln'])
 
         uid = getUid(req)
         if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE == 2:
             return page_not_authorized(req, "../yourbaskets/unsubscribe",
                                        navmenuid = 'yourbaskets')
 
         if isGuestUser(uid):
             if not CFG_WEBSESSION_DIFFERENTIATE_BETWEEN_GUESTS:
                 return redirect_to_url(req, "%s/youraccount/login%s" % (
                     CFG_SITE_SECURE_URL,
                         make_canonical_urlargd({
                     'referer' : "%s/yourbaskets/unsubscribe%s" % (
                         CFG_SITE_SECURE_URL,
                         make_canonical_urlargd(argd, {})),
                     "ln" : argd['ln']}, {})))
 
         user_info = collect_user_info(req)
         if not user_info['precached_usebaskets']:
             return page_not_authorized(req, "../", \
                                        text = _("You are not authorized to use baskets."))
 
         if not argd['bskid']:
             (body, navtrail) = perform_request_list_public_baskets(uid)
             title = _('List of public baskets')
 
         else:
             # TODO: Take care of XML output as shown below
             #req.content_type = "text/xml"
             #req.send_http_header()
             #return perform_request_display_public(bskid=argd['bskid'], of=argd['of'], ln=argd['ln'])
             unsubscribe_warnings_html = perform_request_unsubscribe(uid, argd['bskid'], argd['ln'])
             (body, dummy, navtrail) = perform_request_display_public(uid=uid,
                                                               selected_bskid=argd['bskid'],
                                                               selected_recid=0,
                                                               of=argd['of'],
                                                               ln=argd['ln'])
            # warnings.extend(unsubscribe_warnings)
             body = unsubscribe_warnings_html + body
             title = _('Public basket')
 
         return page(title       = title,
                     body        = body,
                     navtrail    = navtrail,
                     uid         = uid,
                     lastupdated = __lastupdated__,
                     language    = argd['ln'],
                     req         = req,
                     navmenuid   = 'yourbaskets',
                     of          = argd['of'],
                     navtrail_append_title_p = 0,
                     secure_page_p=1)
 
     def write_public_note(self, req, form):
         """Write a comment (just interface for writing)"""
 
         argd = wash_urlargd(form, {'bskid': (int, 0),
                                    'recid': (int, 0),
                                    'cmtid': (int, 0),
                                    'of'   : (str, ''),
                                    'ln'   : (str, CFG_SITE_LANG)})
 
         _ = gettext_set_language(argd['ln'])
 
         uid = getUid(req)
         if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1:
             return page_not_authorized(req, "../yourbaskets/write_public_note",
                                        navmenuid = 'yourbaskets')
 
         if isGuestUser(uid):
             if not CFG_WEBSESSION_DIFFERENTIATE_BETWEEN_GUESTS:
                 return redirect_to_url(req, "%s/youraccount/login%s" % (
                     CFG_SITE_SECURE_URL,
                         make_canonical_urlargd({
                     'referer' : "%s/yourbaskets/write_public_note%s" % (
                         CFG_SITE_SECURE_URL,
                         make_canonical_urlargd(argd, {})),
                     "ln" : argd['ln']}, {})))
 
         user_info = collect_user_info(req)
         if not user_info['precached_usebaskets']:
             return page_not_authorized(req, "../", \
                                        text = _("You are not authorized to use baskets."))
 
         (body, navtrail) = perform_request_write_public_note(uid=uid,
                                                             bskid=argd['bskid'],
                                                             recid=argd['recid'],
                                                             cmtid=argd['cmtid'],
                                                             ln=argd['ln'])
 
         # register event in webstat
         basket_str = "%s (%d)" % (get_basket_name(argd['bskid']), argd['bskid'])
         if user_info['email']:
             user_str = "%s (%d)" % (user_info['email'], user_info['uid'])
         else:
             user_str = ""
         try:
             register_customevent("baskets", ["write_public_note", basket_str, user_str])
         except:
             register_exception(suffix="Do the webstat tables exists? Try with 'webstatadmin --load-config'")
 
         return page(title       = _("Add a note"),
                     body        = body,
                     navtrail    = navtrail,
                     uid         = uid,
                     lastupdated = __lastupdated__,
                     language    = argd['ln'],
                     req         = req,
                     navmenuid   = 'yourbaskets',
                     of          = argd['of'],
                     secure_page_p=1)
 
     def save_public_note(self, req, form):
         """Save comment on record in basket"""
 
         argd = wash_urlargd(form, {'bskid': (int, 0),
                                    'recid': (int, 0),
                                    'note_title': (str, ""),
                                    'note_body': (str, ""),
                                    'editor_type': (str, ""),
                                    'of': (str, ''),
                                    'ln': (str, CFG_SITE_LANG),
                                    'reply_to': (str, 0)})
 
         _ = gettext_set_language(argd['ln'])
 
         uid = getUid(req)
         if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1:
             return page_not_authorized(req, "../yourbaskets/save_public_note",
                                        navmenuid = 'yourbaskets')
 
         if isGuestUser(uid):
             if not CFG_WEBSESSION_DIFFERENTIATE_BETWEEN_GUESTS:
                 return redirect_to_url(req, "%s/youraccount/login%s" % (
                     CFG_SITE_SECURE_URL,
                         make_canonical_urlargd({
                     'referer' : "%s/yourbaskets/save_public_note%s" % (
                         CFG_SITE_SECURE_URL,
                         make_canonical_urlargd(argd, {})),
                     "ln" : argd['ln']}, {})))
 
         user_info = collect_user_info(req)
         if not user_info['precached_usebaskets']:
             return page_not_authorized(req, "../", \
                                        text = _("You are not authorized to use baskets."))
 
         (body, navtrail) = perform_request_save_public_note(uid=uid,
                                                                       bskid=argd['bskid'],
                                                                       recid=argd['recid'],
                                                                       note_title=argd['note_title'],
                                                                       note_body=argd['note_body'],
                                                                       editor_type=argd['editor_type'],
                                                                       ln=argd['ln'],
                                                                       reply_to=argd['reply_to'])
 
         # TODO: do not stat event if save was not succussful
         # register event in webstat
         basket_str = "%s (%d)" % (get_basket_name(argd['bskid']), argd['bskid'])
         if user_info['email']:
             user_str = "%s (%d)" % (user_info['email'], user_info['uid'])
         else:
             user_str = ""
         try:
             register_customevent("baskets", ["save_public_note", basket_str, user_str])
         except:
             register_exception(suffix="Do the webstat tables exists? Try with 'webstatadmin --load-config'")
 
         return page(title       = _("Display item and notes"),
                     body        = body,
                     navtrail    = navtrail,
                     uid         = uid,
                     lastupdated = __lastupdated__,
                     language    = argd['ln'],
                     req         = req,
                     navmenuid   = 'yourbaskets',
                     of          = argd['of'],
                     navtrail_append_title_p = 0,
                     secure_page_p=1)