/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is mozilla.org code.
 *
 * The Initial Developer of the Original Code is
 * Netscape Communications Corporation.
 * Portions created by the Initial Developer are Copyright (C) 1998
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *   Bradley Baetz <bbaetz@student.usyd.edu.au>
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

#ifndef __nsFtpState__h_
#define __nsFtpState__h_

#include "ftpCore.h"
#include "nsInt64.h"
#include "nsIThread.h"
#include "nsIRunnable.h"
#include "nsISocketTransportService.h"
#include "nsISocketTransport.h"
#include "nsIServiceManager.h"
#include "nsIStreamListener.h"
#include "nsIURI.h"
#include "prtime.h"
#include "nsString.h"
#include "nsIFTPChannel.h"
#include "nsIProtocolHandler.h"
#include "nsCOMPtr.h"
#include "nsIInputStream.h"
#include "nsIOutputStream.h"
#include "nsAutoLock.h"
#include "nsAutoPtr.h"
#include "nsIEventQueueService.h"
#include "nsIPrompt.h"
#include "nsIAuthPrompt.h"
#include "nsITransport.h"
#include "nsIProxyInfo.h"

#include "nsFtpControlConnection.h"

#include "nsICacheEntryDescriptor.h"

// ftp server types
#define FTP_GENERIC_TYPE     0
#define FTP_UNIX_TYPE        1
#define FTP_VMS_TYPE         8
#define FTP_NT_TYPE          9
#define FTP_OS2_TYPE         11

// ftp states
typedef enum _FTP_STATE {
///////////////////////
//// Internal states
    FTP_COMMAND_CONNECT,
    FTP_READ_BUF,
    FTP_ERROR,
    FTP_COMPLETE,

///////////////////////
//// Command channel connection setup states
    FTP_S_USER, FTP_R_USER,
    FTP_S_PASS, FTP_R_PASS,
    FTP_S_SYST, FTP_R_SYST,
    FTP_S_ACCT, FTP_R_ACCT,
    FTP_S_TYPE, FTP_R_TYPE,
    FTP_S_CWD,  FTP_R_CWD,
    FTP_S_SIZE, FTP_R_SIZE,
    FTP_S_MDTM, FTP_R_MDTM,
    FTP_S_REST, FTP_R_REST,
    FTP_S_RETR, FTP_R_RETR,
    FTP_S_STOR, FTP_R_STOR,
    FTP_S_LIST, FTP_R_LIST,
    FTP_S_PASV, FTP_R_PASV,
    FTP_S_PWD,  FTP_R_PWD
} FTP_STATE;

// higher level ftp actions
typedef enum _FTP_ACTION {GET, PUT} FTP_ACTION;

class DataRequestForwarder;
class nsFTPChannel;

class nsFtpState : public nsIStreamListener,
                   public nsIRequest {
public:
    NS_DECL_ISUPPORTS
    NS_DECL_NSISTREAMLISTENER
    NS_DECL_NSIREQUESTOBSERVER
    NS_DECL_NSIREQUEST

    nsFtpState();
    virtual ~nsFtpState();

    nsresult Init(nsFTPChannel *aChannel, 
                  nsICacheEntryDescriptor* cacheEntry,
                  nsIProxyInfo* proxyInfo,
                  PRUint64 startPos,
                  const nsACString& entity);

    // use this to provide a stream to be written to the server.
    nsresult SetWriteStream(nsIInputStream* aInStream);

    nsresult GetEntityID(nsACString& aEntityID);

    nsresult Connect();

    // lets the data forwarder tell us when the the data pipe has been created
    // and when the data pipe has finished.
    void DataConnectionEstablished();    
    void DataConnectionComplete();
private:
    ///////////////////////////////////
    // BEGIN: STATE METHODS
    nsresult        S_user(); FTP_STATE       R_user();
    nsresult        S_pass(); FTP_STATE       R_pass();
    nsresult        S_syst(); FTP_STATE       R_syst();
    nsresult        S_acct(); FTP_STATE       R_acct();

    nsresult        S_type(); FTP_STATE       R_type();
    nsresult        S_cwd();  FTP_STATE       R_cwd();

    nsresult        S_size(); FTP_STATE       R_size();
    nsresult        S_mdtm(); FTP_STATE       R_mdtm();
    nsresult        S_list(); FTP_STATE       R_list();

    nsresult        S_rest(); FTP_STATE       R_rest();
    nsresult        S_retr(); FTP_STATE       R_retr();
    nsresult        S_stor(); FTP_STATE       R_stor();
    nsresult        S_pasv(); FTP_STATE       R_pasv();
    nsresult        S_pwd();  FTP_STATE       R_pwd();
    // END: STATE METHODS
    ///////////////////////////////////

    // internal methods
    void        MoveToNextState(FTP_STATE nextState);
    nsresult    Process();

    void KillControlConnection();
    nsresult StopProcessing();
    nsresult EstablishControlConnection();
    nsresult SendFTPCommand(nsCString& command);
    void ConvertFilespecToVMS(nsCString& fileSpec);
    void ConvertDirspecToVMS(nsCString& fileSpec);
    void ConvertDirspecFromVMS(nsCString& fileSpec);
    nsresult BuildStreamConverter(nsIStreamListener** convertStreamListener);
    nsresult SetContentType();
    PRBool CanReadEntry();

    ///////////////////////////////////
    // Private members

        // ****** state machine vars
    FTP_STATE           mState;             // the current state
    FTP_STATE           mNextState;         // the next state
    PRPackedBool        mKeepRunning;       // thread event loop boolean
    PRInt32             mResponseCode;      // the last command response code
    nsCAutoString       mResponseMsg;       // the last command response text

        // ****** channel/transport/stream vars 
    nsFtpControlConnection*         mControlConnection;       // cacheable control connection (owns mCPipe)
    PRPackedBool                    mReceivedControlData;  
    PRPackedBool                    mTryingCachedControl;     // retrying the password
    PRPackedBool                    mWaitingForDConn;         // Are we wait for a data connection
    PRPackedBool                    mRETRFailed;              // Did we already try a RETR and it failed?
    nsCOMPtr<nsISocketTransport>    mDPipe;                   // the data transport
    nsCOMPtr<nsIRequest>            mDPipeRequest;
    DataRequestForwarder*           mDRequestForwarder;
    PRUint64                        mFileSize;
    nsCString                       mModTime;

        // ****** consumer vars
    nsRefPtr<nsFTPChannel>          mChannel;         // our owning FTP channel we pass through our events
    nsCOMPtr<nsIProxyInfo>          mProxyInfo;

        // ****** connection cache vars
    PRInt32             mServerType;    // What kind of server are we talking to
    PRPackedBool        mList;          // Use LIST instead of NLST

        // ****** protocol interpretation related state vars
    nsString            mUsername;      // username
    nsString            mPassword;      // password
    FTP_ACTION          mAction;        // the higher level action (GET/PUT)
    PRPackedBool        mAnonymous;     // try connecting anonymous (default)
    PRPackedBool        mRetryPass;     // retrying the password
    nsresult            mInternalError; // represents internal state errors

        // ****** URI vars
    nsCOMPtr<nsIURI>       mURL;        // the uri we're connecting to
    PRInt32                mPort;       // the port to connect to
    nsString               mFilename;   // url filename (if any)
    nsCString              mPath;       // the url's path
    nsCString              mPwd;        // login Path

        // ****** other vars
    PRUint8                mSuspendCount;// number of times we've been suspended.
    PRUint32               mBufferSegmentSize;
    PRUint32               mBufferMaxSize;
    PRLock                 *mLock;
    nsCOMPtr<nsIInputStream> mWriteStream; // This stream is written to the server.
    PRUint32                 mWriteCount;
    PRPackedBool            mAddressChecked;
    PRPackedBool            mServerIsIPv6;
    
    static PRUint32         mSessionStartTime;

    char                    mServerAddress[64];

    // ***** control read gvars
    nsresult                mControlStatus;
    nsCAutoString           mControlReadCarryOverBuf;

    nsCOMPtr<nsICacheEntryDescriptor> mCacheEntry;
    
    nsUint64 mStartPos;
    nsCString mSuppliedEntityID;
    nsCString mEntityID;
};


#endif //__nsFtpState__h_
