#pragma once

/// @file
/// @brief Define VPN API functions
///
/// @copyright Copyright 2019 InfoTeCS.

#include <stdint.h>
#include <stdbool.h>
#include <time.h>

#if ( __GNUC__ >= 4 ) || defined( __clang__ )
#   define VpnApiExport __attribute__( ( visibility( "default" ) ) )
#else
#   define VpnApiExport
#endif

#include "vpn_api_types.h"

/*! \defgroup get_client_param_keys Keys to get parameters using the GetClientParam function
 * @{
 */
/// @brief Key to get the network number
static const char* const paramKeyNetworkNumber = "network.number";
/// @brief Key to get the encryption mode in use
static const char* const paramSecurityEncryptionMode = "node.security.encryption.mode";
/// @brief Key to get the link for accessing the monitoring system over the public network
static const char* const paramSystemNetworkMonitoringOpenUrls = "system.monitoring.openUrls";
/// @brief Key to get the link for accessing the monitoring system over the private network
static const char* const paramSystemNetworkMonitoringVipnetUrls = "system.monitoring.vipnetUrls";

/// @brief Key to get the link for accessing the NVS monitoring system over the public network
static const char* const paramNvsConnectionOpenUrls = "nvs.info/connection.openUrls";
/// @brief Key to get the link for accessing the NVS monitoring system over the private network
static const char* const paramNvsConnectionVipnetUrls = "nvs.info/connection.vipnetUrls";
/// @brief Key to get the logon ID in NVS
static const char* const paramNvsAuthenticationId = "nvs.info/authentication.id";
/// @brief Key to get the logon secret in NVS
static const char* const paramNvsAuthenticationSecret = "nvs.info/authentication.secret";
/// @brief Key to get the unique device ID for data transfer to NVS
static const char* const paramNodeDeviceId = "node.deviceId";

/// @brief Key to get the nvs.info contents
static const char* const paramNvsInfoData = "data/nvs.info";
/// @brief Key to get the itcslic.xml contents
static const char* const paramItcslicXmlData = "data/itcslic.xml";
/*! @} */ // get_client_param_keys

/*! \defgroup set_init_param_keys Keys to configure initialization
 * @{
 */
/// @brief Keys to set the group name, applies to Apple devices only
static const char* const initKeyAppGroupName = "app_group_name";
/// @brief Keys to set the app name, applies to Apple devices only
static const char* const initKeyAppName = "app_name";

/*! @} */ // set_init_param_keys

/*! \defgroup set_extra_param_keys Keys to configure advanced settings, such as logger
 * @{
 */
/// @brief Key to pass the handler that redirects logs to the calling code
static const char* const initKeyLogHandler = "log_handler";
/// @brief Key to pass the event severity level from the calling code
static const char* const initKeyLogHandlerLevel = "log_level";
/// @brief Log handler prototype
/// @param[in] logLevel - event severity level
/// @param[in] message - log
/// @remarks default event severity level is 3
///
typedef void ( *LogEventHandler )( enum LoggerLevel logLevel, const char* message );
/*! @} */ // set_extra_param_keys

/// @brief Get the current ViPNet Client version
/// @param[out] version - version buffer or NULL to get the buffer size
/// @param[in,out] size - buffer size[in], size of the resulting data with '\0' at the end[out]
/// @remarks Version memory must be allocated and released independently
/// @return Command execution result
typedef VpnApiReturnCode ( *GetClientVersion )( char* version, size_t* size );

/// @brief Install the keys
/// @param[in] dstPath - key set path
/// @param[in] psw - key set password
/// @return Command execution result
typedef VpnApiReturnCode ( *InstallKeys )( const char* dstPath, const char* psw );

/// @brief Delete the keys
/// @return Command execution result
typedef VpnApiReturnCode ( *DeleteKeys )();

/// @brief Enable VPN
/// @param[in] psw - key set password
/// @return Command execution result
typedef VpnApiReturnCode ( *StartVpn )( const char* psw );

/// @brief Disable VPN
/// @return Command execution result
typedef VpnApiReturnCode ( *StopVpn )();

/// @brief Get the VPN state
/// @param[out] vpnStatus - current VPN state
/// @return Command execution result
typedef VpnApiReturnCode ( *GetVpnStatus )( VpnStatus* vpnStatus );

/// @brief Get the license expiration date and time in seconds (Unix time)
/// @param[out] time - license expiration date and time in seconds
/// @remarks Returns 0 for perpetual license
/// @return Command execution result
typedef VpnApiReturnCode ( *GetLicenseExpiration )( time_t* time );

/// @brief Get the host details
/// @param[out] nodesInfo - host details
/// @param[out] size - number of hosts
/// @remarks The nodesInfo memory is allocated dynamically and must be released using ReleaseVpnNodeInfo( nodesInfo, size )
/// @return Command execution result
typedef VpnApiReturnCode ( *GetNodesInfo )( VpnNodeInfo** nodesInfo, size_t* size );

/// @brief Get the user details
/// @param[out] usersInfo - user details
/// @param[out] size - number of users
/// @remarks The usersInfo memory is allocated dynamically and must be released using ReleaseVpnUserInfo( usersInfo, size )
/// @return Command execution result
typedef VpnApiReturnCode ( *GetUsersInfo )( VpnUserInfo** usersInfo, size_t* size );

/// @brief Get the host details by the role and host properties mask
/// @param[out] nodesInfo - host details
/// @param[out] size - number of hosts
/// @param[in] tasksMask - bit mask of the roles and host properties from VpnNodeTask to filter the hosts by
/// @remarks The nodesInfo memory is allocated dynamically and must be released using ReleaseVpnNodeInfo( nodesInfo, size )
/// @return Command execution result
typedef VpnApiReturnCode ( *GetNodesInfoByTask )( VpnNodeInfo** nodesInfo, size_t* size, VpnNodeTasksMask tasksMask );

/// @brief List of host IDs
/// @param[out] nodeIds - host ID list
/// @param[out] size - number of hosts
/// @remarks The nodeIds memory is allocated dynamically and must be released using ReleaseVpnNodeIds( nodesIds, size )
/// @return Command execution result
typedef VpnApiReturnCode ( *GetNodesIds )( uint32_t** nodeIds, size_t* size );

/// @brief Get the host details by host ID
/// @param[in] id - host ID
/// @param[out] nodeInfo - host details
/// @remarks The nodeInfo memory is allocated dynamically and must be released using ReleaseVpnNodeInfo( nodeInfo, 1 )
/// @return Command execution result
typedef VpnApiReturnCode ( *GetNodeInfo )( uint32_t id, VpnNodeInfo** nodeInfo );

/// @brief Get the user details by user ID
/// @param[in] id - user ID
/// @param[out] userInfo - user details
/// @remarks The userInfo memory is allocated dynamically and must be released using ReleaseVpnUserInfo( userInfo, 1 )
/// @return Command execution result
typedef VpnApiReturnCode ( *GetUserInfo )( uint32_t id, VpnUserInfo** userInfo );

/// @brief Get IDs of the users registered on this host
/// @param[in] nodeId - host ID
/// @param[out] userIds - user ID list
/// @param[out] size - number of users
/// @remarks The userIds memory is allocated dynamically and must be released using ReleaseVpnUserIds( userIds, size )
/// @return Command execution result
typedef VpnApiReturnCode ( *GetUserIdsForNode )( uint32_t nodeId, uint32_t** userIds, size_t* size );

/// @brief Get your ViPNet host details
/// @param[out] nodeInfo - host details
/// @remarks The nodeInfo memory is allocated dynamically and must be released using ReleaseVpnNodeInfo( nodeInfo, 1 )
/// @return Command execution result
typedef VpnApiReturnCode ( *GetOwnNodeInfo )( VpnNodeInfo** nodeInfo );

/// @brief Get your ViPNet host permission level
/// @param[out] privilege - permission level
/// @return Command execution result
typedef VpnApiReturnCode ( *GetOwnPrivilegeLevel )( enum VpnPrivilege* privilege );

/// @brief Get the ViPNet configuration parameter by a key as strings
/// @param[in] key - key to search for data
/// @param[in] keyLength - key buffer length
/// @param[out] outData - output buffer
/// @param[out] outDataLength - size of the data buffer allocated dynamically
/// @remarks The outData memory is allocated dynamically and must be released using ReleaseClientParamData( outData )
/// @return Command execution result
typedef VpnApiReturnCode ( *GetClientParam )( const char* key,
                                              uint32_t keyLength,
                                              char** outData,
                                              uint32_t* outDataLength );

/// @brief Release memory allocated for the ClientSettings transfer
/// @param[in] data - buffer to be released
typedef void ( *ReleaseClientParamData )( char* data );

/// @brief Release memory allocated to the host details
/// @param[in] nodeInfo - host details memory to be released
/// @param[in] size - number of hosts
typedef void ( *ReleaseVpnNodeInfo )( VpnNodeInfo* nodeInfo, size_t size );

/// @brief Release memory allocated to the user details
/// @param[in] userInfo - user details memory to be released
/// @param[in] size - number of users
typedef void ( *ReleaseVpnUserInfo )( VpnUserInfo* userInfo, size_t size );

/// @brief Release memory allocated to the host list
/// @param[in] nodeIds - host ID array to be released
/// @param[in] size - number of hosts
typedef void ( *ReleaseVpnNodeIds )( uint32_t* nodeIds, size_t size );

/// @brief Release memory allocated to the user list
/// @param[in] userIds - user ID array to be released
/// @param[in] size - number of users
typedef void ( *ReleaseVpnUserIds )( uint32_t* userIds, size_t size );

/// @brief Get ID of the active coordinator
/// @param[out] id - ID of the active coordinator, 0 means error
/// @return Command execution result
typedef VpnApiReturnCode ( *GetActiveCoordinator )( uint32_t* id );

/// @brief Get the current event severity level
/// @param[out] logLevel - event severity level
/// @return Command execution result
typedef VpnApiReturnCode ( *GetLogLevel )( int32_t* logLevel );

/// @brief Set the current event severity level
/// @param[in] logLevel - event severity level
/// @return Command execution result
typedef VpnApiReturnCode ( *SetLogLevel )( int32_t logLevel );

/// @brief Run the routine control
/// @param[in] psw - host administrator password
/// @remarks VPN must be enabled for the command to succeed
/// @return Command execution result
typedef VpnApiReturnCode ( *RegulationsCheck )( const char* psw );

/// @brief Export the log files to the ZIP archive
/// @param[in] path - archive path
/// @return Command execution result
typedef VpnApiReturnCode ( *CollectReport )( const char* path );

/// @brief Export the event log to the ZIP archive
/// @param[in] path - archive path
/// @param[in] psw - host administrator password
/// @param[in] truncate - whether the log should be deleted after export
/// @remarks VPN must be enabled for the command to succeed
/// @return Command execution result
typedef VpnApiReturnCode ( *CollectEventlog )( const char* path, const char* psw, bool truncate );

/// @brief Event handler prototype
/// @param[in] event - VPN event
typedef void ( *VpnEventHandler )( enum VpnEvent event );

/// @brief Subscribe to VPN events
/// @param[in] eventHandler - event handler or NULL to unsubscribe
/// @remarks Only the single handler subscription is supported
/// @remarks Do not unsubscribe within the event handler
/// @return Command execution result
typedef VpnApiReturnCode ( *SubscribeForEvents )( VpnEventHandler eventHandler );

/// @brief Event handler prototype with additional data
/// @param[in] data - pointer to the arbitrary data passed through SubscribeForEventsExt
/// @param[in] event - VPN event
typedef void ( *VpnEventHandlerExt )( void* data, enum VpnEvent event );

/// @brief Subscribe the data object to VPN events
/// @param[in] data - arbitrary non-zero data pointer to be passed to the handler
/// @param[in] eventHandler - event handler
/// @remarks Use UnsubscribeFromEventsExt to unsubscribe from events
/// @remarks Do not unsubscribe within the event handler
/// @return Command execution result
typedef VpnApiReturnCode ( *SubscribeForEventsExt )( void* data, VpnEventHandlerExt eventHandler );

/// @brief Unsubscribe the data object from VPN events
/// @param[in] data - arbitrary non-zero data pointer to unsubscribe
/// @return Command execution result
typedef VpnApiReturnCode ( *UnsubscribeFromEventsExt )( void* data );

/*! \defgroup api_token_operations SDK functions for enhanced logon
 * @{
 */
/// @brief Get the list of tokens connected and supported
/// @param[in] cbk - token descriptor handler; can return non-zero value to interrupt the request
/// @return Command execution result
typedef VpnApiReturnCode ( *CollectTokens )( int ( *cbk )( VpnTokenHandle ) );

/// @brief Set the logon device parameters
/// @param[in] handle - descriptor of the token to be used for loogn
/// @param[in] pin - PIN of the logon device user (unmasked)
/// @remarks handle can be NULL which means using the same device as when installing a DST file or moving a key
/// @remarks pin can be NULL which means using the PIN saved with SetPin
/// @return Command execution result
typedef VpnApiReturnCode ( *SetToken )( VpnTokenHandle handle, const char* pin );

/// @brief Save the logon device PIN
/// @ingroup api_ver6 api_token_operations
/// @param[in] handle - descriptor of the token whose PIN should be saved
/// @param[out] pin - PIN of the logon device user (unmasked)
/// @remarks PIN is masked when saved and gets destroyed on the ReleaseTokenHandle( handle ) execution
/// @return Command execution result
typedef VpnApiReturnCode ( *SetPin )( VpnTokenHandle handle, const char* pin );

/// @brief Get the logon device parameters
/// @param[in] handle - descriptor of the token to get details for
/// @param[out] info - pointer to the structure to copy the information to
/// @remarks VpnTokenInfo contains pointers to the strings; these objects are destroyed on calling ReleaseTokenHandle( handle )
/// @return Command execution result
typedef VpnApiReturnCode ( *GetTokenInfo )( VpnTokenHandle handle, VpnTokenInfo* info );

/// @brief Release memory allocated to descriptor
/// @param[in] handle - token descriptor
/// @remarks Should be called for every descriptor as soon as it is no longer needed (considering the GetTokenInfo note)
/// @return Command execution result
typedef VpnApiReturnCode ( *ReleaseTokenHandle )( VpnTokenHandle handle );

/// @brief Get the pkcs#11 module configuration and usage status
/// @param[in] cbk - data handler that gets utf8-encoded json structure
/// @details Returns the following structure:
/**
* \code{.json}
*{
*    "global": { "paths": "<path1>:<path2>:...:<pathN>" },
*    "token01": {
*        "name": "<name>",
*        "file": "<the pkcs#11 module file>",
*        "type": "<numerical ID of the type>",
*        "check": {
*            "library": "<current path to the pkcs#11 module when found>",
*            "load": "<true/false: whether the pkcs#11 library is loaded to CSP or not>"
*        }
*    },
*    "token02": { ... },
*    ....
*    "tokenNN": { ... }
*}
* \endcode
*/
/// @return Command execution result
typedef VpnApiReturnCode ( *GetTokenConfig )( int ( *cbk )( const char* ) );

/// @brief Move the personal key to a device and change the logon method to an enhanced one (personal key on device)
/// @param[in] handle - descriptor of the token to be used for logon
/// @param[in] pin - PIN of the logon device user (unmasked)
/// @remarks VPN must be enabled for the command to succeed
/// @return Command execution result
typedef VpnApiReturnCode ( *MoveKeysToToken )( VpnTokenHandle handle, const char* pin );
/*! @} */ // api_token_operations

/*! \defgroup api_ver6
    @{
*/
/// @brief Check connection to the active coordinator
/// @param[out] nodeId - active coordinator ID
/// @return Command execution result
typedef VpnApiReturnCode ( *CheckActiveCoordinatorConnection )( uint32_t* nodeId );

/// @brief Check connection to a host
/// @param[in] nodeId - host ID
/// @return Command execution result
typedef VpnApiReturnCode ( *CheckNodeConnection )( uint32_t nodeId );

/// @brief Change the active coordinator
/// @param[in] nodeId - new active coordinator ID
/// @return Command execution result
typedef VpnApiReturnCode ( *SetActiveCoordinatorId )( uint32_t nodeId );

/// @brief Set the exchange directory to configure RPC through TCP/IP (for Windows only)
/// @param[in] folder - exchange directory
/// @return Command execution result
typedef VpnApiReturnCode ( *SetExchangeFolder )( const wchar_t* folder );

/// @brief Get the host details by the host ID
/// @param[in] id - host ID
/// @param[out] nodeInfo - host details
/// @remarks The nodeInfo memory is allocated dynamically and must be released using ReleaseNodeInfoExt( nodeInfo )
/// @return Command execution result
/// @details VpnNodeInfoExt contains data similar to VpnNodeInfo and the tunneled host details, if any
typedef VpnApiReturnCode ( *GetNodeInfoExt )( uint32_t id, VpnNodeInfoExt** nodeInfo );

/// @brief Release memory allocated to the host details
/// @param[in] nodeInfo - host details memory to be released
/// @return Command execution result
typedef VpnApiReturnCode ( *ReleaseNodeInfoExt )( VpnNodeInfoExt* nodeInfo );

/// @brief Set handlers of the vipnetclient events
/// @param[in] consumer - unique subscriber ID (must not contain spaces)
/// @param[in] events - pointers to the handling functions
/// @return Command execution result
/// @details Allows setting separate functions to handle each event and accept the event details (if applicable)
typedef VpnApiReturnCode ( *SetEventHandlers )( const char* consumer, VpnEventHandlers* events );
/// @brief Get the key set details (DST)
/// @param[in] path - DST file path
/// @param[out] info - key set details
/// @return Command execution result
typedef VpnApiReturnCode ( *GetDstInfo )( const char* path, VpnDstInfo* info );
/// @brief Unpack the key set (DST) and configure the ViPNet access service
/// @param[in] path - DST file path
/// @param[in] password - host user password (blank or NULL)
/// @param[out] status - DST verification result and unpack status
/// @return Command execution result
typedef VpnApiReturnCode ( *InstallKeysExt )( const char* path, const char* password, VpnDstStatus* status );
/// @brief Get the vipnetclient status and mode
/// @param[out] status - requested data
/// @return Command execution result
typedef VpnApiReturnCode ( *GetUltimateStatus )( VpnUltimateStatus* status );
/// @brief Diagnose the vipnetclient service
/// @param[out] status - diagnostics result
/// @return Command execution result
typedef VpnApiReturnCode ( *GetHealthStatus )( VpnHealthStatus* status );
/// @brief Turn on autostart on OS user logon
/// @return Command execution result
typedef VpnApiReturnCode ( *SetOptionAutorun )( void );
/// @brief Turn off autostart on OS user logon
/// @return Command execution result
typedef VpnApiReturnCode ( *SetOptionNoAutorun )( void );
/*! @} */ // api_ver6
/*! \defgroup api_ver7 SDK functions for version 7 and higher
    @{
*/
/// @brief Turn on the fault tolerance feature
/// @return Command execution result
/// @remark Option is stored in the memory of the process that uses API; gets lost after restart
/// @remark By default, the fault tolerance system launches on VPN startup
typedef VpnApiReturnCode ( *SetOptionFaultTolerance )( void );
/// @brief Turn off the fault tolerance feature
/// @return Command execution result
/// @remark Option is stored in the memory of the process that uses API; gets lost after restart
/// @remark By default, the fault tolerance system launches on VPN startup
typedef VpnApiReturnCode ( *SetOptionNoFaultTolerance )( void );
/*! @} */
/*! \defgroup api_ver8 SDK functions for version 8 and higher
    @{
*/
/// @brief Get the ViPNet connection ID (for Aurora only; Aurora supports multiple connections)
/// @param[out] conn - ViPNet connection ID
/// @return Command execution result
typedef VpnApiReturnCode ( *GetConnectionId )( int32_t* conn );
/// @brief Get the ViPNet connection ID through DBus-RPC call (Aurora supports multiple connections)
/// @param[out] conn - ViPNet connection ID
/// @return Command execution result
typedef VpnApiReturnCode ( *GetConnectionIdRoutine )( int32_t* conn );
/// @brief Get the current host encryptor details
/// @param[in] id - host ID
/// @param[out] keyType - pointer to the string with utf8-encoded json structure
/// @remarks When used, the result string must be released by calling ReleaseNodeCrypto( keyType )
/// @details Returns the following structure:
/**
* \code{.json}
*{
*  "keyType": "<Key type: Default, Quantum, etc>",
*  "keyStartDate": "<Quantum key effective time (time_t)>"
*}
* \endcode
*/
typedef VpnApiReturnCode ( *GetNodeCrypto )( uint32_t id, char** keyType );
/// @brief Release memory allocated on calling GetNodeCrypto
/// @param[in] keyType - pointer to the string returned by GetNodeCrypto
/// @return Command execution result
typedef VpnApiReturnCode ( *ReleaseNodeCrypto )( char* keyType );
/*! @} */

/*! \defgroup api_ver9 SDK functions for version 9 and higher
    @{
*/
/// @brief Block the user traffic
/// @param[in] status - user traffic block status
/// @return Command execution result
typedef VpnApiReturnCode ( *BlockUserTraffic )( enum VpnUserTrafficBlockStatus status );

/// @brief Get the user traffic block information
/// @param[out] blockInfo - user traffic block information
/// @remarks When used, the blockInfo struct must be released by calling ReleaseUserTrafficBlockInfo( blockInfo )
/// @return Command execution result
typedef VpnApiReturnCode ( *GetUserTrafficBlockInfo )( VpnUserTrafficBlockInfo** blockInfo );

/// @brief Release memory allocated on calling GetUserTrafficBlockInfo
/// @param[in] blockInfo - pointer to the struct returned by GetUserTrafficBlockInfo
/// @return Command execution result
typedef VpnApiReturnCode ( *ReleaseUserTrafficBlockInfo )( VpnUserTrafficBlockInfo* blockInfo );

/// @brief Get the list of available configuration reference books
/// @param[out] refBookList - list of configuration reference books
/// @remarks When used, the refBookList struct must be released by calling ReleaseRefBookList( refBookList )
/// @return Command execution result
typedef VpnApiReturnCode ( *GetAvailableRefBooks )( VpnRefBookListInfo** refBookList );

/// @brief Export configuration reference book to the specified filepath
/// @param[in] refBook - configuration reference book name
/// @param[in] filepath - file export path
/// @return Command execution result
typedef VpnApiReturnCode ( *ExportRefBook )( const char* refBook, const char* filepath );

/// @brief Release memory allocated to the configuration reference book list
/// @param[in] refBookList - pointer to the struct to be released
/// @return Command execution result
typedef VpnApiReturnCode ( *ReleaseRefBookList )( VpnRefBookListInfo* refBookList );
/*! @} */

/// @brief VPN API functions (described above)
typedef struct
{
    InstallKeys installKeys;
    DeleteKeys deleteKeys;
    StartVpn startVpn;
    StopVpn stopVpn;
    RegulationsCheck regulationsCheck;
    CollectReport collectReport;
    CollectEventlog collectEventlog;
    SubscribeForEvents subscribeForEvents;

    GetClientVersion getClientVersion;
    GetVpnStatus getVpnStatus;
    GetLicenseExpiration getLicenseExpiration;
    GetNodesIds getNodesIds;
    GetNodesInfo getNodesInfo;
    GetNodesInfoByTask getNodesInfoByMask;
    GetNodeInfo getNodeInfo;
    GetOwnNodeInfo getOwnNodeInfo;
    GetOwnPrivilegeLevel getOwnPrivilegeLevel;
    ReleaseVpnNodeInfo releaseVpnNodeInfo;
    ReleaseVpnNodeIds releaseVpnNodeIds;
    GetActiveCoordinator getActiveCoordinator;
    GetLogLevel getLogLevel;
    SetLogLevel setLogLevel;

    // API_VERSION_3
    GetUsersInfo getUsersInfo;
    GetUserInfo getUserInfo;
    GetClientParam getClientParam;
    ReleaseVpnUserInfo releaseVpnUserInfo;
    ReleaseClientParamData releaseClientParamData;
    GetUserIdsForNode getUserListForNode;
    ReleaseVpnUserIds releaseVpnUserIds;

    // API_VERSION_4
    CollectTokens collectTokens;
    SetToken setToken;
    GetTokenInfo getTokenInfo;
    ReleaseTokenHandle releaseTokenHandle;
    GetTokenConfig getTokenConfig;
    MoveKeysToToken moveKeysToToken;

    // API_VERSION 5
    SubscribeForEventsExt subscribeForEventsExt;
    UnsubscribeFromEventsExt unsubscribeFromEventsExt;

    // API_VERSION 6
    SetPin setPin;
    GetNodeInfoExt getNodeInfoExt;
    ReleaseNodeInfoExt releaseNodeInfoExt;
    CheckActiveCoordinatorConnection checkActiveCoordinatorConnection;
    SetActiveCoordinatorId changeActiveCoordinator;
    CheckNodeConnection checkNodeConnection;
    SetEventHandlers setEventHandlers;
    GetDstInfo getDstInfo;
    InstallKeysExt installKeysExt;
    GetUltimateStatus getUltimateStatus;
    GetHealthStatus getHealthStatus;
    SetOptionAutorun setOptionAutorun;
    SetOptionNoAutorun setOptionNoAutorun;
    SetExchangeFolder setExchangeFolder;
    // API_VERSION 7
    SetOptionFaultTolerance setOptionFaultTolerance;
    SetOptionNoFaultTolerance setOptionNoFaultTolerance;
    // API_VERSION 8
    GetConnectionId getConnectionId;
    GetConnectionIdRoutine getConnectionIdRoutine;
    GetNodeCrypto getNodeCrypto;
    ReleaseNodeCrypto releaseNodeCrypto;

    // API_VERSION 9
    BlockUserTraffic blockUserTraffic;
    GetUserTrafficBlockInfo getUserTrafficBlockInfo;
    ReleaseUserTrafficBlockInfo releaseUserTrafficBlockInfo;
    GetAvailableRefBooks getAvailableRefBooks;
    ExportRefBook exportRefBook;
    ReleaseRefBookList releaseRefBookList;
} ItcsVpnApi;

#ifdef __cplusplus
extern "C" {
#endif

/// @brief Get the current VPN API version
/// @remarks When updating API, check it for compatibility; otherwise, correct operation is not guaranteed
/// @return Current VPN API version
VpnApiExport uint32_t GetVpnApiVersion();

/// @brief Get the VPN API structure pointer
/// @return The VPN API structure pointer
VpnApiExport ItcsVpnApi* GetVpnApi();

/// @brief Get the VPN API structure pointer
/// @param[in] params - initialization settings
/// @param[in] len -  number of parameters
/// @return The VPN API structure pointer
VpnApiExport ItcsVpnApi* GetVpnApiExt( VpnApiInitData* params, size_t len );

#ifdef __cplusplus
}
#endif
