Exemplo n.º 1
0
    def resend_create(self, workspace_id):
        #verify email valid and send invitation mail
        if 'email' in request.params:
            if request.params['email'] == '':
                return render('invitation/resend_show.mako')
            user = User.get_by_lower_email(int(workspace_id), request.params['email'])
            if (user):
                # Instantiate a Kcd client.
                invitees = []
                invitee = WorkspaceInvitee()
                invitee.email_address = user.email
                invitee.send_mail = True
                
                invitees.append(invitee)
                message = "click on the link to join the teambox"
                
                kc = KcdClient(get_cached_kcd_external_conf_object())
                #TODO handle kcd errors, render confirmation messages
                kc.invite_users(workspace_id, message, invitees)
                ui_info(message="You have been re-invited to the Teambox, please check you email and follow instructions.")
                return render('invitation/resend_success.mako')

            else:
                #please contact ws owner
                ui_error(message="No invitation to this teambox had been sent to this email address." + \
                              " If you were not invited to this teambox, please contact the teambox owner.")
                return render('invitation/resend_show.mako')
                pass
        else:
            abort(403)
Exemplo n.º 2
0
    def save(self):
        
        kc = KcdClient(get_cached_kcd_external_conf_object())

        # TODO: check for status code from Kcd, and handle errors
        kc.save_notification_policy(self._workspace_id, self._user_id, self._new_notif_policy)
        self._notif_policy = self._new_notif_policy
        pass
Exemplo n.º 3
0
    def _request_common(self, workspace_id):
        # Check that the user is logged.
        if not session['user']:
            log.error("_request_common(): user is not logged.")
            abort(404)

        # Instantiate a Kcd client in the context-global variable.
        c.pubws_kc = KcdClient(get_cached_kcd_external_conf_object())
Exemplo n.º 4
0
    def _request_common(self, workspace_id):
        # Check that the user is logged.
        if not session['user']:
            log.error("_request_common(): user is not logged.")
            abort(404)

        # Instantiate a Kcd client in the context-global variable.
        c.pubws_kc = KcdClient(get_cached_kcd_external_conf_object())
Exemplo n.º 5
0
    def login(self, workspace_id):
        # Get kcd database password.
        from kwmo.lib.config import get_cached_kcd_external_conf_object
        expected_passwd = get_cached_kcd_external_conf_object().db_passwd

        if request.params.has_key('stamp') \
                and re.match(r"^\d+$", request.params['stamp']) \
                and request.params.has_key('hash'):

            # Get the provided parameters.
            stamp = int(request.params['stamp'])
            hex_hash = request.params['hash']

            # Make sure the stamp is in sync with the local server... the hash is good for 5 minutes.
            hash_timeout_secs = 300
            if abs(int(time.time()) - stamp) > hash_timeout_secs:
                log.warning(
                    "teambox_admin.login: Bad time stamp or servers time is out of sync."
                )
                return abort(403)

            # Generate the local hash.
            md5 = hashlib.md5()
            md5.update(str(stamp))
            md5.update(expected_passwd)
            expected_hex_hash = md5.digest().encode('hex')

            # Compare the provided hash and the generated one.
            if hex_hash == expected_hex_hash:

                # Login as user 1 (the workspace creator) in read-only mode.
                user_id = 1
                session_timeout_secs = 1800  # 30 minutes
                session['admin'] = True
                session['expiration_time'] = int(
                    time.time()) + session_timeout_secs
                session['mode'] = MODE_WS
                session['user_id'] = user_id
                session['user'] = User.get_by(workspace_id=workspace_id,
                                              id=user_id).to_dict()
                c.perms.addRole('roadmin')
                session.save()

                # Redirect to teambox.
                redirect_to("teambox_admin", workspace_id=workspace_id)

            else:
                log.debug("teambox_admin.login: Bad admin password.")
                return abort(403)

        else:
            log.debug("teambox_admin.login: Bad parameters.")
            return abort(404)
Exemplo n.º 6
0
    def login(self, workspace_id):
        # Get kcd database password. 
        from kwmo.lib.config import get_cached_kcd_external_conf_object
        expected_passwd = get_cached_kcd_external_conf_object().db_passwd

        if request.params.has_key('stamp') \
                and re.match(r"^\d+$", request.params['stamp']) \
                and request.params.has_key('hash'):

            # Get the provided parameters.
            stamp = int(request.params['stamp'])
            hex_hash = request.params['hash']

            # Make sure the stamp is in sync with the local server... the hash is good for 5 minutes.
            hash_timeout_secs = 300
            if abs(int(time.time()) - stamp) > hash_timeout_secs:
                log.warning("teambox_admin.login: Bad time stamp or servers time is out of sync.")
                return abort(403)

            # Generate the local hash.
            md5 = hashlib.md5()
            md5.update(str(stamp))
            md5.update(expected_passwd)
            expected_hex_hash = md5.digest().encode('hex')

            # Compare the provided hash and the generated one.
            if hex_hash == expected_hex_hash:

                # Login as user 1 (the workspace creator) in read-only mode.
                user_id = 1
                session_timeout_secs = 1800 # 30 minutes
                session['admin'] = True
                session['expiration_time'] = int(time.time()) + session_timeout_secs
                session['mode'] = MODE_WS
                session['user_id'] = user_id
                session['user'] = User.get_by(workspace_id=workspace_id, id=user_id).to_dict()
                c.perms.addRole('roadmin')
                session.save()

                # Redirect to teambox.
                redirect_to("teambox_admin", workspace_id=workspace_id)

            else:
                log.debug("teambox_admin.login: Bad admin password.")
                return abort(403)

        else:
            log.debug("teambox_admin.login: Bad parameters.")
            return abort(404)
Exemplo n.º 7
0
    def get(self, workspace_id, email_id):
        # Return a rendered template
        #return render('/credentials_file.mako')
        # or, return a response
        response.content_type = "application/wsl"

        filename = "kwmo_creds.wsl"
        # Temporarily disabled - need to be debugged.
        if request.params.has_key('interactive') and str(request.params.get('interactive')) == "1":
            filename = c.workspace.name + ".wsl"

        response.headers['Content-disposition'] = 'attachment; filename="%s"' % ( filename.encode('latin1') )
        
        #fix for IE
        response.headers['Pragma'] = 'public'
        response.headers['Cache-Control'] = 'max-age-0'

        errorStr = None
        #ws = Workspace.get_by(id= workspace_id)
        ws = c.workspace
        invitation = Invitation.get_by(email_id = email_id)
        
        if (ws and invitation):
            user = User.get_by(id = invitation.user_id, workspace=ws)
            if(user and ws.id==invitation.kws_id):
                c.invitation = invitation
                c.user = user
                c.workspace = ws
                conf = get_cached_kcd_external_conf_object()
                c.kcd_host = conf.kcd_host
                c.kcd_port = conf.kcd_port
                if ('password' in request.params):
                    c.password = request.params['password']
                    
                if ('user_id' in session):
                    c.password = session['password']
            else:
                errorStr = "User was not invited to this workspace"

        else:
            errorStr = "Invalid email_id or workspace_id"
        
        if errorStr:
            c.errorStr = errorStr
            return render('credentials_file/error.mako')
        else:
            return render('credentials_file/get.mako')
Exemplo n.º 8
0
    def chat_request_result(self, workspace_id, req_id):
        workspace_id = int(workspace_id)
        req_id = int(req_id)
        req_start_time = request.params['req_start_time']

        # Do some checks and initialization.
        self._check_public(workspace_id)
        self._request_common(workspace_id)

        # Get the request.
        req = ChatRequest.get_by(workspace_id=workspace_id, request_id=req_id)

        if req:
            # Check request status.
            if req.accepted:
                # Modify permissions.
                self._set_chat_requests_perms(False)
                self._set_chat_perms(True)

                # Save session.
                session.save()

                log.debug("chat_request_result(): accepted.")
                return {"result": "ok"}

            # Enable when debugging to enable automatic chat acceptation.
            if 0:
                from kanp import KANP_MINOR
                from pylons import config

                kc = KcdClient(get_cached_kcd_external_conf_object())
                # This function has to be rewritten.
                kc.pubws_chat_request_accept(workspace_id, user_id, KANP_MINOR,
                                             req_id)

        else:
            # Bad request ID or kwsfetcher has not yet fetched the request.
            pass

        log.debug("chat_request_result(): pending, chat_req_id='%s', req_start_time='%s'." \
            % ( str(req_id), str(req_start_time) ) )
        return {
            "result": "pending",
            "chat_req_id": req_id,
            'req_start_time': req_start_time
        }
Exemplo n.º 9
0
 def _invite_and_login(self, usr, workspace_id, password):
     invitation = Invitation.get_by(kws_id=workspace_id, inviting_user_id=0, user_id=usr.user_id)
     if invitation:
         email_id = invitation.email_id
     else:
         invitees = []
         invitee = WorkspaceInvitee()
         invitee.email_address = usr.email
         invitee.send_mail = False
         invitees.append(invitee)
         
         kc = KcdClient(get_cached_kcd_external_conf_object())
         #TODO handle kcd errors
         ws_url, invitees_result = kc.invite_users(workspace_id, '', invitees)
         email_id = invitees_result[0].email_id
         
     redirect_to(url('invite_create',workspace_id=workspace_id, email_id=email_id, password=password))
Exemplo n.º 10
0
    def post_message(self, workspace_id):
        workspace_id = int(workspace_id)

        # Get ajax parameters.
        channel_id = int(request.params['channel_id'])
        message = request.params['message']  #.encode('latin1')

        if not c.perms.hasPerm('chat.post.channel.%i' % (channel_id)):
            log.error("Chat post denied: user has not the right permissions.")
            raise KAjaxViewException("Chat post denied.")

        user_id = session['user_id']

        log.debug("Chat post request: workspace_id=%i channel_id=%i user_id=%i" % \
            ( workspace_id, channel_id, user_id ) )

        # Instantiate a Kcd client.
        kc = KcdClient(get_cached_kcd_external_conf_object())

        # Post the message.
        kc.post_chat_msg_request(workspace_id, channel_id, user_id, message)

        if 0:
            # Get first update directly (not finished: need other motifications at client side
            # so the update is not shown twice.
            state_req_id = int(request.params['state_req_id'])
            last_evt_chat_id = int(request.params['last_evt_chat_id'])

            time.sleep(0.5)  # Wait for kwsfetcher to fetch the message.
            flags = (StateRequest.STATE_FORCE_SYNC
                     | StateRequest.STATE_WANT_CHAT)
            params = {
                'req_id': state_req_id,
                'chat_channel_id': channel_id,
                'last_evt_chat_id': last_evt_chat_id
            }
            updater_state_dict = state_request_get(c, session, flags, params)

            return {'updater': updater_state_dict}

        return {}
Exemplo n.º 11
0
    def chat_request_result(self, workspace_id, req_id):
        workspace_id = int(workspace_id)
        req_id = int(req_id)
        req_start_time = request.params['req_start_time']

        # Do some checks and initialization.
        self._check_public(workspace_id)
        self._request_common(workspace_id)

        # Get the request.
        req = ChatRequest.get_by(workspace_id=workspace_id, request_id=req_id)

        if req:
            # Check request status.
            if req.accepted:
                # Modify permissions.
                self._set_chat_requests_perms(False)
                self._set_chat_perms(True)

                # Save session.
                session.save()

                log.debug("chat_request_result(): accepted.")
                return { "result" : "ok" }

            # Enable when debugging to enable automatic chat acceptation.
            if 0:
                from kanp import KANP_MINOR
                from pylons import config

                kc = KcdClient(get_cached_kcd_external_conf_object())
                # This function has to be rewritten.
                kc.pubws_chat_request_accept(workspace_id, user_id, KANP_MINOR, req_id)

        else:
            # Bad request ID or kwsfetcher has not yet fetched the request.
            pass

        log.debug("chat_request_result(): pending, chat_req_id='%s', req_start_time='%s'." \
            % ( str(req_id), str(req_start_time) ) )
        return { "result" : "pending", "chat_req_id" : req_id, 'req_start_time' : req_start_time }
Exemplo n.º 12
0
    def post_message(self, workspace_id):
        workspace_id = int(workspace_id)

        # Get ajax parameters.
        channel_id = int(request.params['channel_id'])
        message = request.params['message'] #.encode('latin1')

        if not c.perms.hasPerm('chat.post.channel.%i' % (channel_id)):
            log.error("Chat post denied: user has not the right permissions.")
            raise KAjaxViewException("Chat post denied.")

        user_id = session['user_id']

        log.debug("Chat post request: workspace_id=%i channel_id=%i user_id=%i" % \
            ( workspace_id, channel_id, user_id ) )

        # Instantiate a Kcd client.
        kc = KcdClient(get_cached_kcd_external_conf_object())

        # Post the message.
        kc.post_chat_msg_request(workspace_id, channel_id, user_id, message)

        if 0:
            # Get first update directly (not finished: need other motifications at client side
            # so the update is not shown twice.
            state_req_id = int(request.params['state_req_id'])
            last_evt_chat_id = int(request.params['last_evt_chat_id'])

            time.sleep(0.5) # Wait for kwsfetcher to fetch the message.
            flags = ( StateRequest.STATE_FORCE_SYNC | StateRequest.STATE_WANT_CHAT )
            params = { 'req_id' : state_req_id, 'chat_channel_id' : channel_id, 'last_evt_chat_id' : last_evt_chat_id }
            updater_state_dict = state_request_get(c, session, flags, params)

            return { 'updater' : updater_state_dict }

        return {}
Exemplo n.º 13
0
    def show(self, workspace_id, email_id):
        workspace_id = int(workspace_id)
        email_id = int(email_id)

        # Set logout url.
        c.logout_url = url('teambox_pubws_logout',
                           workspace_id=workspace_id,
                           email_id=email_id)

        # Check if the workspace is public.
        self._check_public(workspace_id)

        if 'email_id' in session and session['email_id'] != email_id:
            # User is logged but wants to access a different email. Reinit session.
            log.debug("Reinitializing session because user is using another email id: previous='%s', new='%s'." \
                % ( str(session['email_id']), str(email_id) ) )
            init_session(c.workspace, reinit=True)

        notif = request.GET.get('notif', 0)
        if notif:
            # This is the sender (user 1)... [re-]login automatically.
            log.debug(
                "User is accessing a public workspace using a notification link... automatically log user in."
            )
            user = User.get_by(workspace_id=workspace_id, id=1)
            log.debug(
                "Reinitializing session because user is logging as user 1 (notif management)."
            )
            init_session(c.workspace, reinit=True)
            self._login(user)
            c.notif_flag = True
        else:
            if 'user' in session and session['user'] and session['user'][
                    'id'] == 1:
                # Sender is logged (as a sender) but he's using a regular skurl link: logout.
                log.debug(
                    "Reinitializing session because user was logged as user 1 but is using a regular skurl link."
                )
                init_session(c.workspace, reinit=True)

        if not c.perms.hasRole('skurl'):
            # Give skurl role, if not already done.
            c.perms.addRole('skurl')

            # Save session.
            session.save()

        if not 'email_id' in session:
            # Set email information in session.

            # Instantiate a Kcd client.
            kc = KcdClient(get_cached_kcd_external_conf_object())

            # Check that email ID is valid.
            email_info = kc.pubws_get_email_info(workspace_id, email_id)
            if not email_info:
                log.debug("PubWS: invalild email ID: %i" % (email_id))
                abort(404)

            # Get the email sender.
            sender_user = User.get_by(workspace_id=workspace_id, id=1)
            sender = kbase.PropStore()
            sender.name = sender_user.real_name
            sender.email = sender_user.email

            # Get the email recipients (list of PropStores, having name and email keys).
            raw_recipients = kc.pubws_get_eid_recipient_identities(
                workspace_id, email_id)

            # Strip sender email from recipients, if needed.
            recipients = []
            for recipient in raw_recipients:
                if recipient.email != sender.email:
                    recipients.append(recipient)

            # Merge sender and recipients.
            identities = [sender] + recipients

            # Set needed informations in session.
            session['email_id'] = email_id
            session['email_info'] = email_info.to_dict()
            session['identities'] = map(lambda x: x.to_dict(), identities)
            session.save()

        # Get informations that will be published in the template.
        c.dyn_version = 15
        c.email_info = session['email_info']
        c.json_email_info_str = simplejson.dumps(c.email_info)
        c.identities = session['identities']
        c.json_identities_str = simplejson.dumps(c.identities)

        # Check if a chat request was accepted lately (delay is hardcoded in accepted_lately()).
        c.user_id = None
        if 'user_id' in session and session['user_id']:
            c.user_id = session['user_id']
            if ChatRequest.accepted_lately(workspace_id, session['user_id']):
                # Deny chat requests and allow chat since a request was accepted lately.
                self._set_chat_requests_perms(False)
                self._set_chat_perms(True)
            else:
                # Allow chat requests and deny chat since no request was accepted lately.
                self._set_chat_requests_perms(True)
                self._set_chat_perms(False)

            # Allow workspace creation request.
            self._set_ws_creation_requests_perms(True)

            # Save session.
            session.save()

        c.base_url_paths = kurl.get_base_url_paths(
            'teambox_updater', 'teambox_post_chat', 'teambox_download',
            'teambox_upload', 'teambox_pubws_set_identity',
            'teambox_pubws_chat_request', 'teambox_pubws_chat_request_result',
            'teambox_pubws_kfsup_request', 'teambox_pubws_kfsdown_request',
            'teambox_pubws_create_request')

        # Get first update directly.
        flags = (StateRequest.STATE_FORCE_SYNC
                 | StateRequest.STATE_WANT_PERMS
                 | StateRequest.STATE_WANT_MEMBERS
                 | StateRequest.STATE_WANT_KFS
                 | StateRequest.STATE_WANT_PUBWS_INFO)
        params = {}
        if 'user_id' in session and session['user_id']:
            flags |= StateRequest.STATE_WANT_CHAT
            params['chat_channel_id'] = session['user_id']
        updater_state_dict = state_request_get(c, session, flags, params)
        c.updater_state_json = simplejson.dumps(updater_state_dict)

        return render('/teambox/pubwsshow.mako')
Exemplo n.º 14
0
    def pb_set_identity(self, workspace_id):
        import select
        from kcd_lib import WorkspaceInvitee

        workspace_id = int(workspace_id)

        # Get the workspace.
        if not c.workspace.public:
            log.warning("pb_set_identity: Workspace %i is not public." %
                        (workspace_id))
            abort(404)

        # Get POST parameters.
        identity_id = request.params['identity_id']
        identity_id = int(identity_id)

        # Shortcuts
        identity = session['identities'][identity_id]
        log.debug("Recipient: %s" % (str(identity)))

        if identity_id == 0:
            # This is the sender (user 1).
            user = User.get_by(workspace_id=workspace_id, id=1)
            self._login(user)
            log.debug("Found matching user(0): '%s'." % (str(user)))
            return {'result': 'ok', 'user': session['user']}

        # This is a real recipient... try to get the user.
        user = User.get_by(workspace_id=workspace_id, email=identity['email'])
        if user:
            self._login(user)
            log.debug("Found matching user(1): '%s'." % (str(user)))
            return {'result': 'ok', 'user': session['user']}

        # Instantiate a Kcd client.
        kc = KcdClient(get_cached_kcd_external_conf_object())

        # Invite user.
        invitee = WorkspaceInvitee(real_name=identity['name'],
                                   email_address=identity['email'])
        junk_url, invitees = kc.invite_users(workspace_id, "empty message",
                                             [invitee])
        if invitees[0].error:
            log.debug("User could not be invited: '%s'." %
                      (str(invitees[0].error)))
            raise Exception('Internal error.')

        # Get user. If not present, retry a few times, until new user is fetched by kwsfetcher or until timeout.

        wait_seconds = 0.5
        timeout_seconds = 8
        time_started = time.time()
        while 1:
            # Get user, if it exists (fetched by kwsfetcher).
            user = User.get_by(workspace_id=workspace_id,
                               email=identity['email'])
            if user:
                self._login(user)
                log.debug("Found matching user (2): '%s'." % (str(user)))
                return {'result': 'ok', 'user': session['user']}

            # Check for timeout.
            if time.time() > time_started + timeout_seconds: break

            # Wait
            select.select([], [], [], wait_seconds)

        # Reached timeout.
        log.error(
            "Error: reached end of pb_set_identity(). KWSFetcher might be too loaded or down."
        )
        raise Exception('Temporary server error: please try again later.')
Exemplo n.º 15
0
    def _upload(self, workspace_id):
        workspace_id = int(workspace_id)

        # Shortcuts
        share_id = 0
        user_id = session['user']['id']
        user_email = session['user']['email']
        client_random_id = None

        # Permissions verification
        log.debug(str(c.perms.to_dict()))
        if not c.perms.hasPerm('kfs.upload.share.%i' % (share_id)):
            log.error("Upload denied: user has not the right permissions.")
            return abort(403)

        email_id = 0

        parent_inode_id = None
        parent_commit_id = None
        filename = None
        inode_id = None
        commit_id = None
        if c.workspace.public:
            email_id = session['email_id']
            email_date = session['email_info']['date']
            email_subject = session['email_info']['subject']

            kc = KcdClient(get_cached_kcd_external_conf_object())
            kcd_dir = kc.kcd_kfs_create_skurl_directories(
                workspace_id, share_id, user_id, user_email, email_id,
                email_date, email_subject)
            parent_inode_id = kcd_dir.inode
            parent_commit_id = kcd_dir.commit_id

        else:
            inode_id = request.GET.get('inode_id', None)

            client_random_id = request.GET['client_random_id']
            log.debug("about to upload a file with client_random_id %i" %
                      (int(client_random_id)))

            if inode_id:
                # Updating a file.
                inode_id = long(inode_id)
                node = KcdKwsKfsCurrentView.get_by(kws_id=workspace_id,
                                                   share_id=share_id,
                                                   inode=inode_id)
                if not node: raise Exception("File does not exist.")
                filename = node.entry_name
                commit_id = node.commit_id

            else:
                # Get current kfs_dir object from request.
                # (It must be sent in the url AND NOT in the posted data for asynchroneous upload to work.)
                kfs_dir_json = request.GET['kfs_dir']
                kfs_dir_dict = simplejson.loads(kfs_dir_json)
                assert kfs_dir_dict['workspace_id'] == workspace_id
                assert kfs_dir_dict['share_id'] == share_id

                # Get the dir node.
                kcd_dir = KcdKwsKfsCurrentView.get_by(
                    kws_id=workspace_id,
                    share_id=share_id,
                    inode=kfs_dir_dict['inode_id'])
                parent_inode_id = kcd_dir.inode
                parent_commit_id = kcd_dir.commit_id

        # Helper function what will be used later in the asynchronous upload.
        # Get node by name:
        kfs_get_node_by_name = lambda x: KcdKwsKfsCurrentView.query.filter(
            and_(KcdKwsKfsCurrentView.kws_id == workspace_id,
                 KcdKwsKfsCurrentView.share_id == share_id,
                 KcdKwsKfsCurrentView.parent_inode == parent_inode_id,
                 KcdKwsKfsCurrentView.entry_name == x)).first()
        # Set upload failure:
        set_upload_failure = None

        if client_random_id is not None:
            self.upload_status = KfsUploadStatus.create_save(
                workspace_id, share_id, user_id, client_random_id)
            set_upload_failure = lambda e: self.upload_status.update_status_faliure(
                e)

            #TODO: lamda function that should be used to update the progress of the uploaded file(bytes written+status)
            #kfs_update_progess_status = lambda num_bytes_written, status: self.upload_status.update(num_bytes_written, status)

        # Asynchronously upload files to KCD.
        kcd_conf = get_cached_kcd_external_conf_object()

        if c.workspace.public:
            # Virtual skurl file upload limit is 50MB but the only available size is the POST size.
            # POSTs up to 60MB are allowed.
            if 'CONTENT_LENGTH' in request.environ and int(
                    request.environ['CONTENT_LENGTH']) > 60 * 1024 * 1024:
                log.debug("File upload too big: %i bytes." %
                          (int(request.environ['CONTENT_LENGTH'])))
                # Read wsgi.input, otherwise it doesn't work.
                # FIXME: stop connection here and warn user (using Ajax?)
                #        Can we render (reliably) before stdin is read? Seems not, to re-test.
                FieldStorage(fp=request.environ['wsgi.input'],
                             environ=request.environ)
                return simplejson.dumps({
                    "result":
                    "error",
                    "error":
                    "File is too big: limit is 50MB."
                })
        fu = KFSWSGIFilesUpload(kcd_conf, request.environ, workspace_id,
                                email_id, share_id, user_id, parent_inode_id,
                                parent_commit_id, filename, inode_id,
                                commit_id, kfs_get_node_by_name,
                                set_upload_failure)
        fs = fu.run()

        return simplejson.dumps({"result": "ok"})
Exemplo n.º 16
0
    def download(self, workspace_id):
        workspace_id = int(workspace_id)

        # Shortcuts
        share_id = 0
        user_id = session['user']['id']
        kcd_conf = get_cached_kcd_external_conf_object()

        # Permissions verification
        if not c.perms.hasPerm('kfs.download.share.%i' % (share_id)):
            log.error("File download denied: user has not the right permissions.")
            # FIXME download permission error: get rid of 403 error: send an errror file?
            return abort(403)
 
        # Get kfs_file object from request.
        web_kfs_file_json = request.params.get('kfs_file')
        web_kfs_file_dict =  simplejson.loads(web_kfs_file_json)
        web_kfs_file = WebKFSFile().from_dict(web_kfs_file_dict)
        assert web_kfs_file.workspace_id == workspace_id
        assert web_kfs_file.share_id == share_id

        # Get the kfs node associted to it.
        kfs_node = KfsNode.get_by(workspace_id=workspace_id, 
                                    share_id=web_kfs_file.share_id,
                                    inode_id=web_kfs_file.inode_id)

        if c.workspace.public and not c.is_admin:
            # Check that the user has rights to download from this path.
            kfs_dir = kfs_node.parent
            if not kfs_dir:
                raise Exception("Public workspace file download: bad directory(0).") 
            if kfs_dir.name == "Original attachments":
                kfs_dir = kfs_dir.parent
            expected_dir_name = get_kfs_skurl_subject(session['email_info']['date'], session['email_info']['subject'])
            if kfs_dir.name != expected_dir_name:
                raise Exception("Public workspace file download: bad directory(1).")
            kfs_dir_parent = kfs_dir.parent
            if not kfs_dir_parent: 
                raise Exception("Public workspace file download: bad directory(2).")
            if kfs_dir_parent.parent_inode_id != KFS_ROOT_INODE_ID: 
                raise Exception("Public workspace file download: bad directory(3).");
            identities_emails = map(lambda x: x['email'], session['identities'])
            if kfs_dir_parent.name not in identities_emails:
                raise Exception("Public workspace file download: bad directory(4).");

        # Get download mode.
        mode = request.params.get('mode', 'save')
        ctype = None

        if mode == 'open':
            # Guest mime type
            import mimetypes
            ctype, cencoding = mimetypes.guess_type(kfs_node.name, False) # not strict
            #ctype, cencoding = mimetypes.guess_type(kfs_node.name, True) # strict

        if not ctype:
            # Download mime type
            ctype, cencoding = ('application/octet-stream', None)
 
        kfs_files = [kfs_node.to_dict()]

        # Set the content type and the headers.
        response.headers['Content-Type'] = ctype
        #if cencoding:
        #    response.headers['Content-Encoding'] = cencoding
        response.headers['Content-disposition'] = str('attachment; filename="%s"' % ( kfs_node.name.encode('latin1') ))
        response.headers['Content-Transfer-Encoding'] = 'binary'

        # Use a custom header that will be replaced in a middleware (workaround for
        # the Content-Length header being dropped somewhere in pylons).
        response.headers['X-Content-Length'] = str(kfs_node.file_size)

        # These headers are necessary for the download to work on IE.
        response.headers['Cache-Control'] = 'maxage=3600'
        response.headers['Pragma'] = 'public'

        if self.send_notification:
            # Send download notification to KCD.
            pubws_email_id = 0
            if c.workspace.public:
                pubws_email_id = session['email_id']
            kc = KcdClient(kcd_conf)

            try:
                kc.send_download_notification(workspace_id, user_id, kfs_node.share_id, kfs_node.inode_id, 
                    kfs_node.commit_id, pubws_email_id)
                log.debug(("Sent download notification: workspace_id=%i, user_id=%i, share_id=%i" + \
                    ", inode_id=%i, commit_id=%i, pubws_email_id=%i.") % \
                    ( workspace_id, user_id, kfs_node.share_id, kfs_node.inode_id, kfs_node.commit_id, 
                      pubws_email_id ) )
            except Exception, e:
                log.error("Sending download notification failed: '%s'." % ( str(e) ) )