##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""
FTP Request class for FTP server.

The FTP Request does the dirty work of turning an FTP request into something
that ZPublisher can understand.
"""

from ZPublisher.HTTPRequest import HTTPRequest

from cStringIO import StringIO
import os
from base64 import encodestring
import re

class FTPRequest(HTTPRequest):

    def __init__(self, path, command, channel, response, stdin=None,
                 environ=None, globbing=None, recursive=0, size=None):

        # we need to store the globbing information to pass it
        # to the ZPublisher and the manage_FTPlist function
        # (ajung)
        self.globbing = globbing
        self.recursive= recursive

        if stdin is None:
            size = 0
            stdin = StringIO()

        if environ is None:
            environ = self._get_env(path, command, channel, stdin, size)

        self._orig_env=environ
        HTTPRequest.__init__(self, stdin, environ, response, clean=1)

        # support for cookies and cookie authentication
        self.cookies=channel.cookies
        if not self.cookies.has_key('__ac') and channel.userid != 'anonymous':
            self.other['__ac_name']=channel.userid
            self.other['__ac_password']=channel.password
        for k,v in self.cookies.items():
            if not self.other.has_key(k):
                self.other[k]=v


    def retry(self):
        self.retry_count=self.retry_count+1
        r=self.__class__(stdin=self.stdin,
                         environ=self._orig_env,
                         response=self.response.retry(),
                         channel=self, # For my cookies
                         )
        return r

    def _get_env(self, path, command, channel, stdin, size):
        "Returns a CGI style environment"
        env={}
        env['SCRIPT_NAME']='/%s' % channel.module
        env['REQUEST_METHOD']='GET' # XXX what should this be?
        env['SERVER_SOFTWARE']=channel.server.SERVER_IDENT
        if channel.userid != 'anonymous':
            env['HTTP_AUTHORIZATION']='Basic %s' % re.sub('\012','',
                    encodestring('%s:%s' % (channel.userid, channel.password)))
        env['SERVER_NAME']=channel.server.hostname
        env['SERVER_PORT']=str(channel.server.port)
        env['REMOTE_ADDR']=channel.client_addr[0]
        env['GATEWAY_INTERFACE']='CGI/1.1' # that's stretching it ;-)

        # FTP commands
        #
        if type(command)==type(()):
            args=command[1:]
            command=command[0]
        if command in ('LST','CWD','PASS'):
            env['PATH_INFO']=self._join_paths(channel.path,
                                              path, 'manage_FTPlist')
        elif command in ('MDTM','SIZE'):
            env['PATH_INFO']=self._join_paths(channel.path,
                                              path, 'manage_FTPstat')
        elif command=='RETR':
            env['PATH_INFO']=self._join_paths(channel.path,
                                              path, 'manage_FTPget')
        elif command in ('RMD','DELE'):
            env['PATH_INFO']=self._join_paths(channel.path,
                                              path, 'manage_delObjects')
            env['QUERY_STRING']='ids=%s' % args[0]
        elif command=='MKD':
            env['PATH_INFO']=self._join_paths(channel.path,
                                              path, 'manage_addFolder')
            env['QUERY_STRING']='id=%s' % args[0]

        elif command=='RNFR':
            env['PATH_INFO']=self._join_paths(channel.path,
                                              path, 'manage_hasId')
            env['QUERY_STRING']='id=%s' % (args[0])

        elif command=='RNTO':
            env['PATH_INFO']=self._join_paths(channel.path,
                                              path, 'manage_renameObject')
            env['QUERY_STRING']='id=%s&new_id=%s' % (args[0],args[1])

        elif command=='STOR':
            env['PATH_INFO'] = self._join_paths(channel.path, path)
            env['REQUEST_METHOD'] = 'PUT'
            env['CONTENT_LENGTH'] = long(size)

        else:
            env['PATH_INFO']=self._join_paths(channel.path, path, command)

        # Fake in globbing information
        env['GLOBBING'] = self.globbing
        env['FTP_RECURSIVE'] = self.recursive

        return env

    def _join_paths(self,*args):
        path=apply(os.path.join,args)
        path=os.path.normpath(path)
        if os.sep != '/':
            path=path.replace(os.sep,'/')
        return path
