/**
 * @addtogroup ssalibrary
 * @{
 */

/**
 * @defgroup ssacapi The SSA VPN C API (CAPI)
 * @{
 *
 * The VPN C API interface to the standard VPN API.
 * These funtions are wrapper functions that allow applications
 * to use standard C-like calls into the VPN API. It's main
 * purpsose is to avoid having to redistribute DDK libraries and
 * headers.
 *
 */
/**-----------------------------------------------------------------
 * @file    vpncapi.h
 * @date    Jan 2011
 * @brief   VPN C API (CAPI)
 *
 * Copyright (c) 2011 by Cisco Systems, Inc.
 * All rights reserved.
 *------------------------------------------------------------------
 */
/**************************************************************************
*   AnyConnect C API
***************************************************************************/
#ifndef _VPNCAPI_
#define _VPNCAPI_

#include "api.h"

#ifndef _WINDOWS
#include "stddef.h"
#endif


/** @cond - Doxygen to ignore the following */

// no vpncapi static lib on Windows
#ifndef _WINDOWS
#ifdef CAPI_EXPORTS
    #define VPN_CAPI __attribute__((visibility("default")))
#else
    #define VPN_CAPI
#endif
#else
#ifdef CAPI_EXPORTS
    #define VPN_CAPI __declspec(dllexport)
#else
    #define VPN_CAPI __declspec(dllimport)
#endif
#endif

/** @endcond */

/**
 * This is equivalent to _HVPNAPI
 */
typedef struct _HVPNAPI HVPNAPI;

/**
 * STRING_LIST - C Wrapper for a list of strings
 */
struct STRING_LIST
{
    const char** ppszStrings; /**< */
    size_t nStrings;          /**< */
};

/**
 * CONNECT_PROMPT_INFO - All the elements of a Connection Prompt
 */
typedef struct CONNECT_PROMPT_INFO
{
    enum ConnectPromptType eType;    /**< */
    const char* pszMessage;          /**< */
    size_t nEntries;                 /**< */
    int hasEnrollmentCA;             /**< */
    int hasAuthenticationError;      /**< */
    struct PROMPT_ENTRY** ppEntries; /**< */
} CONNECT_PROMPT_INFO;

/**
 * PROMPT_ENTRY - Individual elements of the Connection Prompt
 */
typedef struct PROMPT_ENTRY
{
    const char* pszLabel;   /**< */
    const char* pszName;    /**< */
    const char* pszValue;   /**< */
    enum PromptType eType;  /**< */
    int bIsEntryGroup;      /**< */
    int bIsEnabled;         /**< */
    int bIsVisible;         /**< */
    struct STRING_LIST slValueOptions; /**< */

} PROMPT_ENTRY;

/** PROMPT_ENTRY value username */
#define PROMPT_ENTRY_USERNAME     "username"
/** PROMPT_ENTRY value password */
#define PROMPT_ENTRY_PASSWORD     "password"
/** PROMPT_ENTRY value secondary username */
#define PROMPT_ENTRY_SECONDARY_USERNAME "secondary_username"
/** PROMPT_ENTRY value secondary username */
#define PROMPT_ENTRY_SECONDARY_PASSWORD "secondary_password"
/** PROMPT_ENTRY value group list */
#define PROMPT_ENTRY_GROUP_LIST   "group_list"
/** PROMPT_ENTRY value banner */
#define PROMPT_ENTRY_BANNER       "banner"
/** PROMPT_ENTRY value pin */
#define PROMPT_ENTRY_PIN          "pin"
/** PROMPT_ENTRY value verify pin */
#define PROMPT_ENTRY_VERIFY_PIN   "verify_pin"
/** PROMPT_ENTRY value net access */
#define PROMPT_ENTRY_NET_ACCESS   "net_access"


/**
 * PREFERENCE - A Single Preference element in the VPN configuration
 * take name and value of a preference from prompentry member
 */
struct PREFERENCE
{
    enum PreferenceId id;             /**< */
    struct PROMPT_ENTRY promptentry;  /**< */
    int depth;                        /**< */
    size_t nChildren;                 /**< */
    struct PREFERENCE **ppChildren;   /**< */
};

/**
 * PREFERENCE_INFO - A structure for all the user preferences
 */
struct PREFERENCE_INFO
{
    const char* pszHeading;      /**< */
    size_t nPrefs;               /**< */
    struct PREFERENCE **ppPrefs; /**< all user-controllable preferences */
};


// empty string means no value
/**
 * VPN_STATS
 */
struct VPN_STATS
{
    const char* pszState;           /**< Current state of the VPN tunnel. */
    const char* pszTimeConnected;   /**< Time hh:mm:ss the VPN tunnel has
                                       been active. */

    //
    // Data byte/packet counts, does not include encap/encrypt overhead
    //
    const char* pszBytesSent;       /**< Bytes sent to the remote network. */
    const char* pszBytesReceived;   /**< Bytes received from the remote
                                       network. */
    const char* pszPacketsSent;     /**< Packets sent to the remote
                                       network. */
    const char* pszPacketsReceived; /**< Packets received from the remote
                                       network. */

    //
    // Control byte/packet count include size of DPD/Keepalive/etc
    //
    const char* pszControlBytesSent;        /**< Control bytes sent to the
                                               remote gateway. */
    const char* pszControlBytesReceived;    /**< Control bytes received
                                               from the remote gateway. */
    const char* pszControlPacketsSent;      /**< Control packets sent to the
                                               remote gateway. */
    const char* pszControlPacketsReceived;  /**< Control packets received
                                               from the remote gateway. */

    //
    // Encrypted byte counts include both control and data, as well as
    // encryption and encapsulation headers
    //
    const char* pszEncryptedBytesSent;      /**< Encrypted bytes sent to the
                                               remote network. */
    const char* pszEncryptedBytesReceived;  /**< Encrypted bytes received
                                               from the remote network. */
    const char* pszEncryptedPacketsSent;    /**< Encrypted packets sent to the
                                               remote network. */
    const char* pszEncryptedPacketsReceived;/**< Encrypted packets received
                                               from the remote network. */

    //
    // Encrypted byte counts include both control and data (if protocol
    // is TLS), as well as encryption and encapsulation headers
    //
    const char* pszCompressedBytesSent;      /**< Compressed bytes sent
                                                to the remote network. */
    const char* pszCompressedBytesReceived;  /**< Compressed bytes received
                                                from the remote network. */
    const char* pszCompressedPacketsSent;    /**< Compressed packets sent
                                                to the remote network. */
    const char* pszCompressedPacketsReceived;/**< Compressed packets
                                                received from the remote
                                                network. */

    const char* pszInboundDiscarded;    /**< Incoming discarded bytes. */
    const char* pszOutboundDiscarded;   /**< Outgoing discarded bytes. */
    const char* pszInboundBypassed;     /**< Incoming skipped bytes. */
    const char* pszOutboundBypassed;    /**< Outgoing skipped bytes. */

    const char* pszClientAddress;   /**< Client IPv4 address. */
    const char* pszServerAddress;   /**< Remote gateway IP address. */
    const char* pszClientAddressV6; /**< Client IPv6 address. */

    const char* pszServerHostName;  /**< Host name of the remote gateway. */
    const char* pszProxyAddress;    /**< Proxy server IP address. */
    const char* pszProxyHostName;   /**< Proxy server host name. */
    const char* pszProxyPort;       /**< Port used for communicating with
                                       proxy server. */
    const char* pszTunnelingMode;   /**< Mode IPv4 traffic is being passed over
                                       the tunnel.  Values are "Tunnel All Traffic",
                                       "Split Include", "Split Exclude", "Drop All Traffic",
                                       "Bypass All Traffic". */
    const char* pszTunnelingModeV6; /**< Mode IPv6 traffic is being passed over
                                       the tunnel.  Values are "Tunnel All Traffic",
                                       "Split Include", "Split Exclude", "Drop All Traffic",
                                       "Bypass All Traffic". */
    const char* pszDynamicTunnelExclusion; /**< Domain names dynamically excluded from tunneling */
    const char* pszDynamicTunnelInclusion; /**< Domain names dynamically added to tunnel */

    const char* pszEnabled;     /**< */
    const char* pszDisabled;    /**< */

    const char* pszFipsMode;        /**< FIPS mode (Federal security standard).
                                     * Values are "Enabled" or "Disabled" */

    const char* pszTrustedNetworkDetectionMode;  /**< Trusted Network Detection.
                                                  * Values are "Enabled" or
                                                  * "Disabled" */

    const char* pszAlwaysOnMode;    /**< Always On. Values are "Enabled" or
                                       "Disabled" */

    const char* pszNetworkStatus;     /**< Network Status.
                                         Values include are: "No Networks Detected",
                                         "DNS Services Unavailable",
                                         "Web Authentication Required",
                                         "Proxy Authentication Required",
                                         "Access Restricted",
                                         "Access Unrestricted" */

    const char* pszDAPMessage;     /**< DAP message received from gateway.  Used for Quarantine
                                      mode, etc. */

    const char* pszMUSHost;        /**< MUS Host delivered from secure gateway. */
    const char* pszMUSStatus;      /**< MUS Status: Enabled, Disabled. */

    size_t nSecureRoutes;                  /**< */
    struct ROUTE_INFO** ppSecureRoutes;    /**< */
    size_t nNonSecureRoutes;               /**< */
    struct ROUTE_INFO** ppNonSecureRoutes; /**< */
    size_t nProtocolInfo;                  /**< */
    struct PROTOCOL_INFO** ppProtocolInfo; /**< */
    size_t nFirewallInfo;                  /**< */
    struct FIREWALL_INFO** ppFirewallInfo; /**< */
};

/**
 * ROUTE_INFO - A single entry of the route table
 */
struct ROUTE_INFO
{
    const char* pszNetwork; /**< destination addr for this route */
    const char* pszSubnet;  /**< subnet mask for this route */
    const char* pszHostNames; /**< host names associated with the route destination address; 
                                   applicable only to dynamic split tunneling routes*/
};

/**
 * PROTOCOL_INFO - A single entry of the protocol table
 */
struct PROTOCOL_INFO
{
    const char* pszState;        /**< */
    const char* pszProtocol;     /**< */
    const char* pszCipher;       /**< */
    const char* pszCompression;  /**< */
    int bIsActive;               /**< */
};

/**
 * FIREWALL_INFO - A single entry of the firewall table
 */
struct FIREWALL_INFO
{
    const char* pszPermission;   /**< */
    const char* pszProtocol;     /**< */
    const char* pszInterface;    /**< */
    const char* pszSrcPortRange; /**< */
    const char* pszDstPortRange; /**< */
    const char* pszDstAddr;      /**< */
};

/**
 * 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
 * vpnapi_notice_cb() error message.
 */
typedef void (*vpnapi_serviceready_cb) ();

/**
 * 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.
 */
typedef void (*vpnapi_event_available_cb) ();

/**
 * 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.
 *
 * If iSensitive is 1, then the message has some sensitive content in it.
 */
typedef void (*vpnapi_notice_cb) (const char* pszMessage,
                                  enum MessageType eType,
                                  int iSensitive);

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

/**
 * If a pre-connect reminder needs to be acknowledged, this CB delivers
 * pre-connecet response to the client.
 *
 * NOTE: Connection establishment will block until the method
 * vpnapi_set_preconnect_reminder_response() is called.
 *
 * In a GUI, a pre-connect reminder would typically be displayed in a
 * modal dialog with OK button selection.
 *
 * @see vpnapi_set_preconnect_reminder_response() where user ackowledges
 * pre-connect reminder message.
 */
typedef void (*vpnapi_preconnect_reminder_cb) (const char* pszMessage);


/**
 * 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.
 *
 * NOTE: pszMessage is only valid for duration of callback and must
 * be dup if it needs to live outside of the callback
 *
 * @see vpnapi_set_cert_blocked_response to set the user response
*/
typedef void (*vpnapi_cert_blocked_cb) (const char* pszMessage);

/**
 * 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 0 then the always trust option should be hidden
 * in the client.
 *
 * NOTE: pszMessage and strings in certErrors is only valid for
 * duration of callback and must be dup if it needs to live outside
 * of the callback
 *
 * @see vpnapi_set_cert_warning_response the user response
*/
typedef void (*vpnapi_cert_warning_cb) (const char* pszMessage,
                                        const struct STRING_LIST certErrors,
                                        int bAllowImport);

/**
 * 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 vpnapi_user_submit() to have the
 * responses read by the API.
 */
typedef void (*vpnapi_userprompt_cb) (const struct CONNECT_PROMPT_INFO* pPrompt);

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

/**
 * 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.
 */
typedef void (*vpnapi_exit_notice_cb) (const char* pszNotice, const int returnCode);

/**
 * 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.
 */
typedef void (*vpnapi_stats_cb) (const struct VPN_STATS* pStats);

/**
 * 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).
 */
typedef void (*vpnapi_wmhint_cb) (const enum WMHint hint, const enum 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.
 */
typedef void (*vpnapi_deliver_weblaunch_host_cb) (const char* pszActiveHost);

/**
 * VPNAPI_CALLBACKS is a structure that holds all of the user callbacks.
 * These callback will be invoked upon certain VPN API events occurring.
 *
 */
struct VPNAPI_CALLBACKS
{
    /** Called when the VPN service if ready */
    vpnapi_serviceready_cb pServiceReadyCB;

    /** Called when the user prompt changes */
    vpnapi_userprompt_cb pUserPromptCB;

    /** Called when an event is generated */
    vpnapi_event_available_cb pEventAvailableCB;

    /** Called when a log message is available */
    vpnapi_notice_cb pNoticeCB;

    /** Called when the banner message is received */
    vpnapi_banner_cb pBannerCB;

    /** Called when the pre-connect reminder message is received */
    vpnapi_preconnect_reminder_cb pPreConnectReminderCB;

    /** Called when the VPN state changes */
    vpnapi_state_cb pStateCB;

    /** Called when VPN exits (does this happen for SSA?) */
    vpnapi_exit_notice_cb pExitNoticeCB;

    /** Called when stats are ready for reading */
    vpnapi_stats_cb pStatsCB;

    /** Called SOMETIME? */
    vpnapi_wmhint_cb pWMHintCB;

    /** Called SOMETIME? */
    vpnapi_deliver_weblaunch_host_cb pWeblaunchHostCB;

    /** called when server cert error is encountered and preference is to block untrusted servers */
    vpnapi_cert_blocked_cb pCertBlockedCB;

    /** called when server cert error is encountered and preference is to allow untrusted servers */
    vpnapi_cert_warning_cb pCertWarningCB;
};


#ifdef __cplusplus
extern "C"
{
#endif

    /** create new instance of api; callback functors must be set here */
    VPN_CAPI HVPNAPI* vpnapi_create(struct VPNAPI_CALLBACKS* pCallbacks);

    /** create new instance of api; callback functors must be set here */
    VPN_CAPI void vpnapi_delete(HVPNAPI* pHandle);

    /** initialize api, usually called right after create */
    VPN_CAPI int vpnapi_attach(HVPNAPI* pHandle,
                               const enum ClientType clientType,
                               int requestFullCapabilities,
                               int suppressAutoConnect);

    /** call this from main UI loop to receive callbacks */
    VPN_CAPI void vpnapi_process_events(HVPNAPI* pHandle);

    /** connect to ASA */
    VPN_CAPI int vpnapi_connect(HVPNAPI* pHandle, const char* host);

    /** set new tunnel group */
    VPN_CAPI int vpnapi_set_new_tunnel_group(HVPNAPI* pHandle, const char* group);

    /** submit user input; called this after calling vpnapi_set_prompt_value()
     * to set values for appropriate prompt entries
     */
    VPN_CAPI void vpnapi_user_submit(HVPNAPI* pHandle);

    /** submit user response to ASA banner */
    VPN_CAPI void vpnapi_set_banner_response(HVPNAPI* pHandle, int bAccept);

    /** submit value for a prompt entry with name "name" */
    VPN_CAPI int vpnapi_prompt_set_entry_value(HVPNAPI* pHandle, const char* pszEntryName, const char* pszEntryValue);

    /** */
    VPN_CAPI void vpnapi_prompt_set_enrollment_ca(HVPNAPI* pHandle, int bEnroll);

    /** fetch all user controllabe preferences return soft reference that's
     * valid until next call to vpnapi_get_preferences() or
     * vpnapi_save_preferences()
     */
    VPN_CAPI const struct PREFERENCE_INFO* vpnapi_get_preferences(HVPNAPI* pHandle);

    /** set the the value of specified preference. */
    VPN_CAPI int vpnapi_preference_set_value(HVPNAPI* pHandle, const char *pszPreferenceName, const char *pszValue);

    /** use this call to establish the current values in the soft reference (received from vpnapi_get_preferences) as the new preferences. */
    VPN_CAPI int vpnapi_save_preferences(HVPNAPI* pHandle);

    /** retrive a particular preference by string comparison of the name */
    VPN_CAPI const struct PREFERENCE* vpnapi_get_preference_by_name(HVPNAPI* pHandle, const char* pszPreferenceName);

    /** call this to end the current vpn session */
    VPN_CAPI void vpnapi_disconnect(HVPNAPI* pHandle);

    /** call this to detach this vpnapi handle from the agent */
    VPN_CAPI void vpnapi_detach(HVPNAPI* pHandle);

    /** retrieve the current stats associated with the connection */
    VPN_CAPI void vpnapi_get_stats(HVPNAPI* pHandle);

    /** retrieve the current state of the vpn session */
    VPN_CAPI void vpnapi_get_state(HVPNAPI* pHandle);

    /** resets the cumulatively kept statistics */
    VPN_CAPI void vpnapi_reset_stats(HVPNAPI* pHandle);

    /** poll to determine if the state is CONNECTED */
    VPN_CAPI int vpnapi_is_connected(HVPNAPI* pHandle);

    /** used to determine if the vpn agent is enabled */
    VPN_CAPI int vpnapi_is_available(HVPNAPI* pHandle);

    /** used to determine if the vpn agent can be reached and used at this time */
    VPN_CAPI int vpnapi_is_vpn_service_available(HVPNAPI* pHandle);

    /** used to check operating mode bits */
    VPN_CAPI int vpnapi_is_operating_mode(HVPNAPI* pHandle, enum OperatingMode mode);

    /** used to retrieve the default host name as stored in the Api internals */
    VPN_CAPI const char* vpnapi_get_default_hostname(HVPNAPI* pHandle);

    /** get the list of currently known hostnames */
    VPN_CAPI const struct STRING_LIST vpnapi_get_hostnames(HVPNAPI* pHandle);

    /** poll the internal api to check for outstanding event flags */
    VPN_CAPI int vpnapi_is_event_available(HVPNAPI* pHandle);

    /** retrieve a particular prompt entry from the specified prompt info by name */
    VPN_CAPI const PROMPT_ENTRY *vpnapi_get_prompt_entry(const struct CONNECT_PROMPT_INFO *pPromptInfo,
                                                         const char *pPromptName);

    /** vpnapi_prompt_get_entry_names() can only be called after UserPromptCB
     * has been invoked returned object valid until next invocation
     * UserPromptCB()
     */
    VPN_CAPI const struct STRING_LIST vpnapi_prompt_get_entry_names(HVPNAPI* pHandle);

    /** */
    VPN_CAPI void vpnapi_prompt_set_canceled(HVPNAPI* pHandle, int isCanceled);

    /*
     * Call this method after a vpnapi_cert_blocked_cb has been received to
     * indicate the user's response to the blocked untrusted VPN server
     * error message.
     *
     * bUnblock indicates if the user wants to disable the
     * preference to block untrusted servers
    */
    VPN_CAPI void vpnapi_set_cert_blocked_response(HVPNAPI* pHandle, int bUnblock);

    /*
     * Call this method after a vpnapi_cert_warning_cb has been received to
     * indicate the user's response to the server certificate error
     * warning
     *
     * bConnect indicates user wants to connect anyways
     * bImportCert inidicates user wants to permanently trust
     * the VPN server. This would result in no future certificate
     * error warning prompts. bImport is only valid if
     * bConnect is true.
    */
    VPN_CAPI void vpnapi_set_cert_warning_response(HVPNAPI* pHandle, int bConnect, int bImportCert);

    /*
     * Call this method after a vpnapi_preconnect_reminder_cb has been received to display
     * pre-connect reminder message. User must always acknowledge the message.
    */
    VPN_CAPI void vpnapi_set_preconnect_reminder_response(HVPNAPI* pHandle, int bAccept);

#ifdef __cplusplus
}
#endif

#endif // _VPNCAPI_

/** @} */
/** @} */
/** @} */
