/**************************************************************************
*   Copyright (c) 2006, 2021 Cisco Systems, Inc.
*   All Rights Reserved. Cisco Highly Confidential.
***************************************************************************
*
*   File:   ClientIfcBase.h
*   Author: Chris Fitzgerald
*   Date:   08/2007
*
***************************************************************************
*   Client Interface Base class implementation for the Client API.
***************************************************************************/

// The ClientIfcBase class contains the majority of private methods and members.
// The purpose of this class is to hide all but the necessary methods from
// being exposed.
//

#ifndef _CLIENTIFCBASE_
#define _CLIENTIFCBASE_

#include <list>
#include <vector>
#include <memory>


/*
 * SCRIPTING_SUPPORTED, INTERPROCESS_COMMUNICATION_SUPPORTED macro is a copy of corresponding
 * #define from GenDefs.h. Any change in #define for the macro in GenDefs.h must propogated to
 * this header file too. We duplicate this definition here due to the manner in which we distribute
 * our code to partners; we cannot include GenDefs.h from here.
 */
#if !defined(PLATFORM_APPLE_SSLVPN) && !defined(PLATFORM_ANDROID) && !defined(PLATFORM_WIN_APP)
#define SCRIPTING_SUPPORTED
#endif
#if !defined(PLATFORM_WIN_APP)
#define INTERPROCESS_COMMUNICATION_SUPPORTED
#endif

/*
 * SCEP_CERTIFICATE_ENROLLMENT_SUPPORTED macro is a copy of corresponding #define from GenDefs.h.
 * Any change in #define for the macro in GenDefs.h must propogated to this header file too. We
 * duplicate this definition here due to the manner in which we distribute our code to partners;
 * we cannot include GenDefs.h from here.
 */
#if defined(_WIN32) || defined(_WIN32_WCE) || defined(PLATFORM_DARWIN) || defined(PLATFORM_LINUX) || defined(PLATFORM_ANDROID) || defined(PLATFORM_APPLE_SSLVPN)
#define SCEP_CERTIFICATE_ENROLLMENT_SUPPORTED
#endif

/*
 * HOST_DATA_SUPPORTED macro is a copy of corresponding #define from GenDefs.h. Any change
 * in #define for the macro in GenDefs.h must propogated to this header file too. We duplicate
 * this definition here due to the manner in which we distribute our code to partners;
 * we cannot include GenDefs.h from here.
 */
#if defined(PLATFORM_ANDROID) || defined(PLATFORM_APPLE_SSLVPN) || defined(PLATFORM_CHROMEBOOK)
#define HOST_DATA_SUPPORTED
#endif

/*
 * MANUAL_PKCS12_IMPORT_SUPPORTED macro is a copy of corresponding #define from GenDefs.h.
 * Any change in #define for the macro in GenDefs.h must propogated to this header file too.
 * We duplicate this definition here due to the manner in which we distribute our
 * code to partners; we cannot include GenDefs.h from here.
 */
#if defined(PLATFORM_APPLE_SSLVPN) || defined(PLATFORM_ANDROID) || defined(PRODUCT_TYPE_SSA)
#define MANUAL_PKCS12_IMPORT_SUPPORTED
#endif

/*
 * PROGRAM_DATA_IMPORT_SUPPORTED macro is a copy of corresponding #define from GenDefs.h.
 * Any change in #define for the macro in GenDefs.h must propogated to this header file too.
 * We duplicate this definition here due to the manner in which we distribute our
 * code to partners; we cannot include GenDefs.h from here.
 */
#if defined(PLATFORM_ANDROID)
#define PROGRAM_DATA_IMPORT_SUPPORTED
#endif

/*
 * CREDENTIAL_PREFILL_SUPPORTED macro is a copy of corresponding #define from GenDefs.h.
 * Any change in #define for the macro in GenDefs.h must propogated to this header file too.
 * We duplicate this definition here due to the manner in which we distribute our
 * code to partners; we cannot include GenDefs.h from here.
 */
#if defined(PLATFORM_ANDROID)
#define CREDENTIAL_PREFILL_SUPPORTED
#endif

#if defined(MANUAL_PKCS12_IMPORT_SUPPORTED) && !defined(__GENDEFS_H)
#if defined(HAVE_STDINT_H)
#include <stdint.h>
#else
typedef unsigned char uint8_t;
#endif // HAVE_STDINT_H
#endif // MANUAL_PKCS12_IMPORT_SUPPORTED

#include "api.h"
#include "PreferenceUpdate.h"

#if defined(PLATFORM_WIN_APP)
typedef unsigned char uint8_t;
#endif

#if defined(HOST_DATA_SUPPORTED)
#include "IHostData.h"
#endif

#if defined(ANYCONNECT_USE_SNAK)
#include "Utility/PluginLoader.h"
#include "SNAK_CertPlugin.h"
#include "SNAK_SocketPlugin.h"
#include "SNAK_StoragePlugin.h"
#endif 

class ConnectPromptInfo;
class ConnectMgr;
class MsgWithArg;
class VPNStats;
class AgentIfc;
class ProfileMgr;
class ApiThread;
class EventMgr;
class PreferenceMgr;
class PreferenceInfo;
class UserPreferences;
class CScriptingMgr;
class CManualLock;
class ProxyIfc;
class CIpcMessage;
class SCEPIfc;
class CertObj;
class CExecutionContext;
class HostEntry;
class CAppLog;

#if defined(CREDENTIAL_PREFILL_SUPPORTED)
class CredentialPrefill;
#endif

#if !defined(PLATFORM_APPLE_SSLVPN)
class CStoragePath;
#endif

#ifdef ANYCONNECT_USE_SNAK
class PluginLoader;
class SNAK_StoragePlugin;
class SNAK_CertPlugin;
class SNAK_SocketPlugin;
class SNAK_DeviceInfoPlugin;
class SNAKDeviceInfoPluginCBImpl;
#endif // ANYCONNECT_USE_SNAK

#if defined(ANYCONNECT_USE_SNAK) || defined(PLATFORM_APPLE_SSLVPN)
class ManagedCertificate;
class ManagedCertHandle;
#endif // ANYCONNECT_USE_SNAK || PLATFORM_APPLE_SSLVPN

#if defined(PROGRAM_DATA_IMPORT_SUPPORTED)
class IACImporterAsync;
class IACImporterAsyncCB;
#endif

class VPN_VPNAPI ClientIfcBase : private IPreferenceUpdateCB
{
    friend class EventMgr;

    protected:

        /**
        * Callback used to deliver new statistics related to the VPN
        * connection.
        *
        * When a connection is active, a new set of statistics is
        * delivered each second.
        *
        * @see resetStats(), stopStats() and startStats()
        *
        */
        virtual void StatsCB(VPNStats &stats) = 0;


        /**
        * Callback used to deliver VPN state and state change string.
        * The stateString delivered by this method is localized.
        *
        * See the ::VPNState enum found in api.h for set of valid states.
        */
        virtual void StateCB(const VPNState state,
                             const VPNSubState subState,
                             const tstring stateString) = 0;


        /**
        * If a banner needs to be acknowledged, this CB delivers the banner
        * to the client.
        *
        * NOTE: Connection establishment will block until the method
        * setBannerResponse() is called.
        *
        * In a GUI, a banner would typically be displayed in a modal dialog
        * with an accept or decline button selection.
        *
        * @see setBannerResponse() to set the user response to the banner.
        */
        virtual void BannerCB(const tstring &banner) = 0;

        /**
         * If a pre-connect reminder needs to be acknowledged, this CB delivers
         * the pre-connect reminder to the client. 
         *
         * NOTE: Connection establishment will block until the method
         * setPreConnectReminderResponse() is called.
         *
         * In a GUI, a pre-connect reminder would typically be displayed in a modal
         * dialog with an OK button selection.
         *
         * @see setPreConnectReminderResponse() to set the user acknowledgement to
         * the pre-connect reminder message.
         */  
        virtual void PreConnectReminderCB(const tstring &rtstrPreConnectReminder);

        /**
        * Messages are delivered via the NoticeCB and can come from multiple
        * sources.  There are four message types (error, warning, info and
        * status).  See the ::MessageType enum in api.h for the list.
        *
        * Clients using the API as an embedded application (not
        * user visible) might want to further characterize
        * messages.  One option here is to use the AnyConnect message
        * catalog and assign message codes as the translations for
        * various messages.  An application could then track messages based
        * on its own error code scheme.
        */    
        virtual void NoticeCB(const tstring &notice,
                              const MessageType type,
                              const bool bSensitive = false) = 0;

#if defined(PLATFORM_APPLE_SSLVPN) || defined(PLATFORM_ANDROID) || defined(PLATFORM_CHROMEBOOK)
        virtual void CertBannerCB(const tstring &certBannerSummary,
                                  const uint32_t nCertBannerCertLen,
                                  const uint8_t *pCertBannerCertDer,
                                  const std::list<tstring> &confirmReasons,
                                  const std::list<CertConfirmReason> &confirmReasonEnums,
                                  bool bImportAllowed = true) = 0;
#endif

        /**
        * This CB would likely occur only during a connection when it was
        * detected that the software needed to be upgraded, or when Start
        * Before Logon (SBL) is being used.
        *
        * Unlike the other callback methods, this method provides a default
        * implementation (calling the system's exit() function).
        * If clients of the API wish to override this behavior, they are
        * responsible for ensuring that the current running process exits with
        * the return code specified by returnCode.
        *
        * <b>Caution</b>: IF YOU OVERRIDE THIS METHOD AND DO NOT EXIT WITH
        * THE PROPER CODE SOFTWARE UPDATE FUNCTIONALITY IN YOUR CLIENT WILL
        * BREAK
        */
        virtual void ExitNoticeCB(const tstring &tstrNotice,
                                  const int returnCode);


        /**
        * Under normal operating conditions, this CB is called as soon
        * as the attach method completes.  In case the service (vpn agent)
        * is not ready, this CB is not called until it is.
        *
        * Any API calls made prior to this CB being called will result in a
        * NoticeCB error message.
        */
        virtual void ServiceReadyCB() = 0;



        /**
        * This method supports prompting for single or multiple values.  All
        * prompts are considered mandatory.
        *
        * The ConnectPromptInfo object contains a list of PromptEntry
        * instances.  The labels and their default values (if any) can be
        * found in these instances.  After the data has been collected from the user
        * it can be set into these same instances.  When ready, the client
        * application should call the method UserSubmit() to have the
        * responses read by the API.
        */
        virtual void UserPromptCB(ConnectPromptInfo &ConnectPrompt) = 0;


        /**
        * Use this method to provide Window Manager hints to GUI
        * applications.  To receive these hints, the application must
        * identify itself as a GUI in the attach method.  In addition, this
        * method should be overriden to receive any generated events.
        *
        * Event that can be received include those indicating that a user is
        * starting a second instance of the GUI application.  This information
        * can be used to tell the already running application to un-minimize
        * itself and let the new program know that it should Quit (since a GUI
        * is already running).
        */
        virtual void WMHintCB(const WMHint hint,
                              const WMHintReason reason);


        /**
        * This method is useful when the connection to the secure gateway
        * has been established as part of a web-launch of the VPN tunnel.
        *
        * If the client application wishes to be notified of the secure
        * gateway to which the VPN has been established, this method should
        * be overriden.
        *
        * If the client application is started and a tunnel is already active,
        * this method also delivers the name of the secure gateway host.
        */
        virtual void deliverWebLaunchHostCB(const tstring &activeHost);

        /**
        * This method is called when the preference to block untrusted
        * servers is enabled and the current VPN server being connected
        * to is untrusted. Clients should present an error to the user
        * notifying them that the current connection to rtstrUntrustedServer
        * is being blocked. The client should also provide a way for the
        * user to change the preference to block untrusted servers.
        *
        * The user response must be indicated using setCertBlockedResponse
        */
        virtual void CertBlockedCB(const tstring &rtstrUntrustedServer) = 0;

        /**
        * This method is called when connections to untrusted VPN servers
        * is allowed by policies and the current VPN server being connected
        * to is untrusted. Clients should present a warning to the user
        * notifying them that the current connection to rtstrUntrustedServer
        * is unsafe. The reason the VPN server is untrusted is provided in
        * rltstrCertErrors. The client should provide a way for the user to
        * connect once, connect and always trust or cancel the connection.
        * If bAllowImport is set to false then the always trust option should
        * not be presented to users.
        *
        * The user response must be indicated using setCertWarningResponse
        */
        virtual void CertWarningCB(const tstring &rtstrUntrustedServer,
                                   const std::list<tstring> &rltstrCertErrors,
                                   bool bAllowImport) = 0;

#if defined(PLATFORM_WIN_APP)
        /**
        * Same as above but also passes the Server certificate DER for details display
        */
        virtual void CertWarningCB(const tstring &rtstrUntrustedServer,
                                   const std::list<tstring> &rltstrCertErrors,
                                   const std::vector<uint8_t> &rvServerCertDER,
                                   bool bAllowImport) = 0;
#endif

        /**
        * This method can be overriden if the client application wishes to
        * exercise some control over the delivery of events from the other
        * protected methods in this class.
        *
        * This might be necessary in cases where a GUI is being written and
        * the data from this API needs to be delivered in the GUI or main
        * thread.  In this case, you should override this method and when it
        * is called by the API post an event to your event queue (message
        * pump, etc.).  After this event executes in your GUI or main thread,
        * call the method ClientIfc::ProcessEvents to have events delivered
        * to your client application.
        */
        virtual void EventAvailable();

#ifdef MANUAL_PKCS12_IMPORT_SUPPORTED
        virtual void ImportPKCS12ResultCB(const std::vector<uint8_t> &certHash, const tstring &tstrError);
#endif        
#ifdef PLATFORM_ANDROID
        virtual void ClientCertificateCB(std::vector< std::pair<uint32_t, uint8_t*> > certList) = 0;
        virtual void AgentDetachedCB();
#endif

        AgentIfc &getAgentIfc();

        ClientIfcBase();


    public:

        virtual bool attach(ClientType clientType = ClientType_GUI,
                            bool requestFullCapabilities = true,
                            bool suppressAutoConnect = true);

        virtual void detach();

        virtual void ProcessEvents();

        virtual bool hasFullCapabilities();

        virtual bool isConnected();

        virtual bool isAvailable();

        virtual std::list<tstring> getHostNames();

        virtual std::list<HostEntry> getHostEntries();

        virtual tstring getDefaultHostName();

#if defined(HOST_DATA_SUPPORTED)
        virtual bool connect(const IHostData& hostData);
                
        bool connect(const IHostData& hostData,
                     unsigned int origin);
#else
        virtual bool connect(tstring host);

        bool connect(tstring host,
                     unsigned int origin);
#endif

        virtual bool setNewTunnelGroup(const tstring & group);

        virtual void disconnect();

        virtual void cancel();

        virtual void resetStats();

        virtual void getState();

        VPNState getCurrentState();
        VPNSubState getCurrentSubState();
        VPNSubState getPreviousSubState();

        tstring getStateText();
        static tstring getNoticeTypeText(MessageType msgType);

        static tstring getStateText(VPNState state,
                                    VPNSubState subState = VPNSS_NORMAL,
                                    NETENV_STATE netEnvState = NES_NETWORK_ACCESSIBLE,
                                    const tstring& tstrConnectedHost = tstring());

        void setNetworkStates(NETENV_STATE netEnvState, 
                              NETCTRL_STATE netCtrlState,
                              NETWORK_TYPE netType,
                              bool bACBrowserForCPRemediation,
                              bool bUpdateUI);
        void refreshOperatingModeForCurrentNetStates();
        NETENV_STATE getCurrentNetEnvState();
        NETENV_STATE getPreviousNetEnvState();
        NETCTRL_STATE getCurrentNetCtrlState();
        NETWORK_TYPE getCurrentNetType();
        bool isACBrowserForCPRemediation();

        static tstring getNetCtrlText(NETCTRL_STATE netCtrlState);
        static tstring getNetEnvText(NETENV_STATE netEnvState,
                                     bool bSimple = false);
        static tstring getNetTypeText(NETWORK_TYPE netType);
        static tstring getQuarantinedStatusText();
        static tstring getNetworkStatusSimpleText(const NETENV_STATE netEnvState,
                                                  const NETCTRL_STATE netCtrlState);

        // can't be static due to requiring operating mode information
        tstring getNetworkStatusText(const VPNState state,
                                     const VPNSubState subState,
                                     const NETENV_STATE netEnvState,
                                     const NETCTRL_STATE netCtrlState);

        PreferenceInfo &getPreferences();

        bool savePreferences();

        virtual void startStats();

        virtual void stopStats();

        virtual void UserSubmit();

        void setBanner(const tstring &banner);
        void setBannerResponse(bool bResponse);

        void setPreConnectReminder(const tstring &tstrPreConnectReminder);
        void setPreConnectReminderResponse();

        bool getUserResponse();
        bool isUserResponseSet();

        void setCertBlocked(const tstring &tstrUntrustedServer);
        void setCertWarning(const tstring &rtstrUntrustedServer,
                            const std::list<tstring> &rltstrCertErrors,
                            bool bAllowImport);
#if defined(PLATFORM_WIN_APP)
        void setCertWarning(const tstring &rtstrUntrustedServer,
                            const std::list<tstring> &rltstrCertErrors,
                            const std::vector<uint8_t>& rvServerCertDER,
                            bool bAllowImport);
#endif
        bool getCertImportResponse();

#if defined(PLATFORM_APPLE_SSLVPN) || defined(PLATFORM_ANDROID) || defined(PLATFORM_CHROMEBOOK)
        void setCertBanner(tstring tstrCertBannerSummary,
                           uint32_t nCertBannerCertLen,
                           const uint8_t *pCertBannerCertDer,
                           const std::list<tstring> &confirmReasons,
                           const std::list<CertConfirmReason> &confirmReasonEnums,
                           bool bImportAllowed);

        void setCertBannerResponse(bool bResponse, bool bImportCert);
        void importServerCert(std::vector<uint8_t> certData);
        bool setFipsMode(bool bEnableFips);
#if defined(PLATFORM_ANDROID)
        bool setStrictMode(bool bEnableStrictMode);
        bool setRevocationEnabled(bool bRevocationEnabled);
        bool IsRevocationEnabled();
#endif // currently supported only for android
#endif

        void setUserPrompt(ConnectPromptInfo &ConnectPrompt);

#ifdef PLATFORM_ANDROID
        void setClientCertResponse(std::vector< std::pair<uint32_t, uint8_t*> > &derList);
        void setAgentDetached();
        bool getClientCertificates();
#endif

#if defined(PLATFORM_APPLE_SSLVPN) || defined(PLATFORM_ANDROID)
        void setSCEPEnrollInProgress(bool bInProgress);
        bool isSCEPEnrollInProgress();
#endif // PLATFORM_APPLE_SSLVPN || PLATFORM_ANDROID

#ifdef MANUAL_PKCS12_IMPORT_SUPPORTED
        void setImportPKCS12Result(const std::vector<uint8_t> &certHash, const tstring &tstrError);
        bool requestImportPKCS12(const std::vector<uint8_t> &data);
        std::vector<uint8_t> importPKCS12WithPassword(const std::vector<uint8_t> &data, const tstring &password);
#endif

        void setCertBlockedResponse(bool bUnlock);
        void setCertWarningResponse(bool bConnect, bool bImportCert);

        void insertStateToConnectPrompt(ConnectPromptInfo &ConnectPrompt);

        void ExitNotice(const tstring &tstrNotice, const int code = 0);

        void notice(const tstring &tstrNotice,
                    const MessageType type = MsgType_Info,
                    bool bClearLastMsg = false,
                    bool bForce = false,
                    bool bStateMsg = false,
                    bool bSensitiveMsg = false);

        void notice(MsgWithArg &notice,
                    const MessageType type = MsgType_Info,
                    bool bClearLastMsg = false,
                    bool bForce = false,
                    bool bStateMsg = false,
                    bool bSensitiveMsg = false);

        void getStats(void);

        void setStats(VPNStats &stats);

        void exportStats(const tstring &tstrFilePath);

        void setState(VPNState state,
                      VPNState previousState,
                      VPNSubState subState = VPNSS_NORMAL,
                      bool bUpdateStateMsg = true,
                      bool bOnlyUpdateUI = false);

#ifdef PROGRAM_DATA_IMPORT_SUPPORTED
        IACImporterAsync *createACImporter(IACImporterAsyncCB *pCallback);
#endif

        void setWMHint(WMHint hint,
                       WMHintReason reason);

        bool isLastConnectType (const ConnectPromptType connPromptType);

        bool isOperatingMode(OperatingMode opMode);
        void setOperatingMode(OperatingMode opMode);
        void unsetOperatingMode(OperatingMode opMode);

        bool CanRemediateCaptivePortal();
        bool policyAllowsCaptivePortalRemediation();

        bool isEventShutdown();

        bool isUsingEventModel();

        time_t getLastDisconnectTime();

        ConnectPromptInfo getConnectPromptInfo();
        void resetConnectPromptPasswordData();

        void setStandaloneConnection(bool isStandalone);

        void deliverActiveHost(const tstring &activeHost,
                               ConnectProtocolType vpnProtocol = PROTOCOL_TYPE_UNKNOWN,
                               bool bActiveHostFriendlyName = false);

        bool isVPNServiceReady();

        // reset last disconnect time indicator.
        //
        void resetLastDisconnectTime(time_t time = 1);

        void processMinimize();
        
        // cert enrollment
        void setEnrollClientCert(CertObj* pCert);

        // Show user banner for cert import warning on linux
        // SCEPIfc to ConnectMgr
        void linuxCertImportWarnUser();

        // Response to cert warning on linux
        // ConnectMgr to SCEPIfc
        void linuxCertImportWarnUserResponse(bool bAccept);

        void setDefaultHost(tstring &host);

#if defined(HOST_DATA_SUPPORTED)
        void setDefaultHostProfile(const IHostData &hostProfile);
        IHostData* getDefaultHostData();
#endif // HOST_DATA_SUPPORTED

        void setLastVpnError(VPNError vpnError);
        VPNError getLastVpnError();

#ifdef PLATFORM_ANDROID
        bool requestClientCertificates();
#endif

        bool requestImportLocalization(const tstring tstrLocale,
                                       const std::vector<unsigned char> &MoFileData);

        // Start the Automatic Headend Selection operation
        void startAHS(const unsigned int uiReason, 
                      const ProxyIfc& proxy);
        // statusReturnCode is a long to match the current type of STATUSCODE.
        // It is not using a STATUSCODE directly so that we do not have to
        // expose the header files for STATUSCODEs to ClientIfcBase.h
        void AHSSelectedHost(const unsigned int uiReason,
                             const std::vector<tstring> &headendList,
                             const long statusReturnCode,
                             const tstring& extraInfo);
        std::vector<tstring> getAHSHostList();
        unsigned int getAHSState();
        bool isAHSHasRun();

        bool suppressConnectionErrorPopups();

        tstring getCaptivePortalDetectedMsg();        

        void setProxyAuthPrompts(ProxyIfc* pProxy,
                                 const tstring& promptMsg);

#if defined(INTERPROCESS_COMMUNICATION_SUPPORTED)
        bool handleIpcMessage(CIpcMessage *pIpcMessage);
#endif
        bool IsCsdTokenVerified() const;

#if defined(PLATFORM_APPLE_SSLVPN) || defined(PLATFORM_ANDROID)
        virtual void SCEPEnrollStartCB();
        virtual void SCEPEnrollExitCB();
#endif // PLATFORM_APPLE_SSLVPN || PLATFORM_ANDROID
        
        void activateConnectMgrTunnelInitiationCompletionEvent();
        bool isConnectRequestActive();
#if defined(PLATFORM_ANDROID) || defined(PLATFORM_CHROMEBOOK)
        bool deleteProfileByName(const tstring &profileName);
        tstring getProfileContents(const tstring &profileName);
        bool importProfile(const tstring &profileName, const tstring &profileContents);
#endif // PLATFORM_ANDROID || PLATFORM_CHROMEBOOK

        bool syncProfileChange(const tstring &profileName);

#if defined(CREDENTIAL_PREFILL_SUPPORTED)
        bool hasPrefilledCredentials();
        bool prefillCredentials(ConnectPromptInfo &connectPrompt);
        void setPrefilledCredentials(CredentialPrefill *prefill);
#endif

#if defined(PLATFORM_ANDROID) || defined(PLATFORM_APPLE_SSLVPN)
        std::list<ManagedCertificate *> enumerateCertificates(CertificateType certType);
        bool deleteCertificates(CertificateType certType, const std::list<std::string> &idList);
        bool deleteServerCertificates(const std::list<std::string> &idList);
#endif // ANYCONNECT_USE_SNAK || PLATFORM_APPLE_SSLVPN        

#if defined(ANYCONNECT_USE_SNAK)        
        std::list<ManagedCertificate *> enumerateSNAKCertificates(SNAK_CertType certType);
        SNAK_CertType getSNAKCertType(CertificateType certType);
        bool deleteClientCertificates(const std::list<std::string> &idList);
#endif // ANYCONNECT_USE_SNAK

#if defined(PLATFORM_APPLE_SSLVPN)
        bool canUseBackupServers();
    
#endif //PLATFORM_APPLE_SSLVPN
    
        virtual ~ClientIfcBase();

        tstring getConnectHost();

        tstring getMgmtTunnelHostname();

        VPN_TUNNEL_SCOPE getVpnTunnelScope();

        bool isStandaloneConnection();

        void sendSSoLogoutPrompt(ConnectPromptInfo &cpi);

        void setExternalSSOLogoutUrlFromAgent(const tstring& logoutUrl);

    private:

        //
        // Private Member Data
        //

        CExecutionContext* m_pExecutionContext;
        CExecutionContext* m_pExecutionContextMgr;

        AgentIfc *mo_AgentIfc;

        ConnectMgr *mo_ConnectMgr;

        ApiThread  *mo_ConnectThread;

        EventMgr  *mo_EventMgr;

        PreferenceMgr *mo_PreferenceMgr;

        ConnectPromptInfo *mp_currentConnectPromptInfo;

        PreferenceInfo *mo_EditablePrefs;

#if defined(SCRIPTING_SUPPORTED)
        CScriptingMgr *mo_ScriptingMgr;
#endif // SCRIPTING_SUPPORTED

#if defined(SCEP_CERTIFICATE_ENROLLMENT_SUPPORTED)
        SCEPIfc* m_pSCEPIfc;
        bool m_bInformedAgentOfSCEP;
#endif // SCEP_CERTIFICATE_ENROLLMENT_SUPPORTED
#ifndef PLATFORM_APPLE_SSLVPN
        CStoragePath* m_pStoragePath;
#endif // !PLATFORM_APPLE_SSLVPN

#ifdef ANYCONNECT_USE_SNAK
        PluginLoader *m_pPluginLoader;
        SNAK_CertPlugin *m_pSNAKCert;
        SNAK_SocketPlugin *m_pSNAKSocket;
        SNAK_StoragePlugin *m_pSNAKStorage;
        SNAK_DeviceInfoPlugin *m_pSNAKDeviceInfo;
        SNAKDeviceInfoPluginCBImpl *m_pSNAKDeviceInfoCB;

        bool mb_SNAKInitialized;
#endif

#if  defined(PLATFORM_ANDROID) || defined(PLATFORM_APPLE_SSLVPN)
        bool mb_SCEPEnrollInProgress;
#endif // PLATFORM_ANDROID || PLATFORM_APPLE_SSLVPN

        bool mb_PreferenceMgrCreated;
        bool mb_StandaloneConnection;
        bool mb_UsingEventModel;
        bool mb_UserResponse;
        bool mb_IsUserResponseSet;
        bool mb_PerformedAutoCertEnrollment;
        tstring ms_PostEnrollmentConnectHost;
        bool mb_CaptivePortalMsgDisplayed;
        bool m_bSuppressMinimizeOnConnect;
        bool m_bSuppressConnectionErrorPopups;
        bool m_bLastConnectionAutomatic;
        bool m_bImportCertResp;
		bool m_bPrevMsgWasStateMsg;

        unsigned int mui_OperatingMode;
        NETENV_STATE m_currentNetEnvState;
        NETENV_STATE m_previousNetEnvState;
        NETCTRL_STATE m_currentNetCtrlState;
        NETWORK_TYPE m_currentNetType;
        bool m_bACBrowserForCPRemediation;

        tstring ms_message;

        time_t m_disconnectTime;

        static std::string ms_ThreadName;

        CManualLock* m_pClientIfcStateLock;
        CManualLock* m_pClientIfcLock;
        CManualLock* m_pClientIfcPromptsLock;
        CManualLock* m_pClientIfcOpModeLock;
        CManualLock* m_pClientIfcAHSLock;
        CManualLock* m_pClientIfcConnectModeLock;
        CManualLock* m_pClientIfcInformAgentOfSCEPLock;

        std::vector<tstring> msl_AHSSelectedHosts;
        ApiThread* m_pAHSThread;
        unsigned int m_uiAHSState;
#if defined(CREDENTIAL_PREFILL_SUPPORTED)
        CredentialPrefill* m_pCredentialPrefill;
#endif

        // m_AppLogStatus is a long to match the current type of STATUSCODE. It is not using the
        // type of STATUSCODE directly to not expose the header files for STATUSCODE here.
        long m_AppLogStatus;
        std::unique_ptr<CAppLog> m_upAppLogger;

        VPNError m_lastVpnError;

        static volatile bool mb_deleteFirstPass;

        //
        // Private Member Methods
        //

        ConnectMgr &getConnectMgr();

        ProfileMgr &getProfileMgr();
        UserPreferences &getUserPreferences();

        void displayAgentAttachMessage();

        void setLastDisconnectTime(time_t time);

        void setCurrentStatePrompts(const VPNState state, 
                                    const VPNState prevState,
                                    const VPNSubState subState,
                                    const bool bUpdateStateMsg);
        void setCurrentStateErrorMessage(VPNState state, CONNECT_FAILURE_REASON cfr);
        void getStateMessage(const VPNState state, 
                             const VPNState prevState,
                             const VPNSubState subState,
                             const NETENV_STATE neState,
                             /*out*/ MsgWithArg& stateMessage);

        // IPreferenceUpdateCB methods
        virtual void OnLoadPreferencesComplete();
        virtual bool IsPreferenceOverridable(const PreferenceId ePreferenceId);
        virtual void OverridePreferenceValue(const PreferenceId ePreferenceId,
                                             tstring& rPrefenceValue,
                                             bool& rbOverriden);

        void RefreshPreferences(void);

        void displayAHSPrompt(const bool isComplete);
        void handleAHSPreferences(const unsigned int uiReason);
        void setAHSState(const unsigned int ahsState);

        bool autoConnectIfEnabled(const bool suppressAutoConnect);

        void clearUserSetResponseFlag();

		bool decodeSSOToken();

#if defined(SCEP_CERTIFICATE_ENROLLMENT_SUPPORTED)
        bool processSCEPIpcMessage(CIpcMessage *pIpcMessage);
        bool isSCEPRedirect();
        void processSCEPRedirect();
#endif // SCEP_CERTIFICATE_ENROLLMENT_SUPPORTED

        bool hasConnectCapabilities();
        bool hasMgmtCapabilities();

        ClientIfcBase(const ClientIfcBase& other);
        ClientIfcBase& operator=(const ClientIfcBase& other);

#ifdef ANYCONNECT_USE_SNAK
        bool initializeSNAK(bool bUseExistingInstanceIfAvail);
        void destroySNAK();
        ManagedCertificate *convertSnakToManagedCertificate(const ManagedCertHandle &snakCert);
#endif
};


#endif // _CLIENTIFCBASE_
